llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Andy Kaylor (andykaylor) <details> <summary>Changes</summary> This moves the code that handles CXXABI-specific lowering in ConvertCIRToLLVMPass into a standlone CIR-to-CIR transform pass. The handling of these operations was already performing a CIR-to-CIR transformation, with the CIR operations being further lowered to the LLVM dialect. This change makes that transformation a separate pass. The LowerModule object in ConvertCIRToLLVMPass will be unused after this change, but removal of that object is being deferred to a follow-up PR to keep this change isolated to a single purpose. --------- --- Patch is 40.70 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/172133.diff 8 Files Affected: - (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+2) - (modified) clang/include/clang/CIR/Dialect/Passes.h (+1) - (modified) clang/include/clang/CIR/Dialect/Passes.td (+11) - (modified) clang/lib/CIR/Dialect/Transforms/CMakeLists.txt (+1) - (added) clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp (+346) - (modified) clang/lib/CIR/Lowering/CIRPasses.cpp (+1) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+11-46) - (modified) clang/test/CIR/CodeGen/pointer-to-data-member.cpp (+136-63) ``````````diff diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 4922f83df0efb..ddb5bfc5a23cd 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3614,6 +3614,8 @@ def CIR_GetRuntimeMemberOp : CIR_Op<"get_runtime_member"> { }]; let hasVerifier = 1; + + let hasLLVMLowering = false; } //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/Passes.h b/clang/include/clang/CIR/Dialect/Passes.h index 32c3e27d07dfb..98eaf884347ed 100644 --- a/clang/include/clang/CIR/Dialect/Passes.h +++ b/clang/include/clang/CIR/Dialect/Passes.h @@ -23,6 +23,7 @@ namespace mlir { std::unique_ptr<Pass> createCIRCanonicalizePass(); std::unique_ptr<Pass> createCIRFlattenCFGPass(); std::unique_ptr<Pass> createCIRSimplifyPass(); +std::unique_ptr<Pass> createCXXABILoweringPass(); std::unique_ptr<Pass> createHoistAllocasPass(); std::unique_ptr<Pass> createLoweringPreparePass(); std::unique_ptr<Pass> createLoweringPreparePass(clang::ASTContext *astCtx); diff --git a/clang/include/clang/CIR/Dialect/Passes.td b/clang/include/clang/CIR/Dialect/Passes.td index 0f5783945f8ae..55007adf6ffb3 100644 --- a/clang/include/clang/CIR/Dialect/Passes.td +++ b/clang/include/clang/CIR/Dialect/Passes.td @@ -82,6 +82,17 @@ def GotoSolver : Pass<"cir-goto-solver"> { let dependentDialects = ["cir::CIRDialect"]; } +def CXXABILowering : Pass<"cir-cxxabi-lowering"> { + let summary = "Lower abstract C++ operations to target-specific ABI form"; + let description = [{ + This pass lowers high-level operations that represent C++ constructs in a + target-independent way to concrete, target specific operations. + }]; + let constructor = "mlir::createCXXABILoweringPass()"; + let dependentDialects = ["cir::CIRDialect"]; +} + + def LoweringPrepare : Pass<"cir-lowering-prepare"> { let summary = "Lower to more fine-grained CIR operations before lowering to " "other dialects"; diff --git a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt index e3b7106c1d6b9..2a0d791edd22c 100644 --- a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt +++ b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(TargetLowering) add_clang_library(MLIRCIRTransforms CIRCanonicalize.cpp CIRSimplify.cpp + CXXABILowering.cpp FlattenCFG.cpp HoistAllocas.cpp LoweringPrepare.cpp diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp new file mode 100644 index 0000000000000..c81e69ff334da --- /dev/null +++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp @@ -0,0 +1,346 @@ +//==- CXXABILowering.cpp - lower C++ operations to target-specific ABI form -=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PassDetail.h" +#include "TargetLowering/LowerModule.h" + +#include "mlir/IR/PatternMatch.h" +#include "mlir/Interfaces/DataLayoutInterfaces.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Transforms/DialectConversion.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h" +#include "clang/CIR/Dialect/IR/CIRAttrs.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Dialect/IR/CIROpsEnums.h" +#include "clang/CIR/Dialect/Passes.h" +#include "clang/CIR/MissingFeatures.h" + +using namespace mlir; +using namespace cir; + +namespace mlir { +#define GEN_PASS_DEF_CXXABILOWERING +#include "clang/CIR/Dialect/Passes.h.inc" +} // namespace mlir + +namespace { + +template <typename Op> +class CIROpCXXABILoweringPattern : public mlir::OpConversionPattern<Op> { +protected: + mlir::DataLayout *dataLayout; + cir::LowerModule *lowerModule; + +public: + CIROpCXXABILoweringPattern(mlir::MLIRContext *context, + const mlir::TypeConverter &typeConverter, + mlir::DataLayout &dataLayout, + cir::LowerModule &lowerModule) + : mlir::OpConversionPattern<Op>(typeConverter, context), + dataLayout(&dataLayout), lowerModule(&lowerModule) {} +}; + +#define CIR_CXXABI_LOWERING_PATTERN(name, operation) \ + struct name : CIROpCXXABILoweringPattern<operation> { \ + using CIROpCXXABILoweringPattern<operation>::CIROpCXXABILoweringPattern; \ + \ + mlir::LogicalResult \ + matchAndRewrite(operation op, OpAdaptor adaptor, \ + mlir::ConversionPatternRewriter &rewriter) const override; \ + } + +CIR_CXXABI_LOWERING_PATTERN(CIRAllocaOpABILowering, cir::AllocaOp); +CIR_CXXABI_LOWERING_PATTERN(CIRConstantOpABILowering, cir::ConstantOp); +CIR_CXXABI_LOWERING_PATTERN(CIRFuncOpABILowering, cir::FuncOp); +CIR_CXXABI_LOWERING_PATTERN(CIRGetRuntimeMemberOpABILowering, + cir::GetRuntimeMemberOp); +CIR_CXXABI_LOWERING_PATTERN(CIRGlobalOpABILowering, cir::GlobalOp); +#undef CIR_CXXABI_LOWERING_PATTERN + +struct CXXABILoweringPass + : public impl::CXXABILoweringBase<CXXABILoweringPass> { + CXXABILoweringPass() = default; + void runOnOperation() override; +}; + +/// A generic ABI lowering rewrite pattern. This conversion pattern matches any +/// CIR dialect operations with at least one operand or result of an +/// ABI-dependent type. This conversion pattern rewrites the matched operation +/// by replacing all its ABI-dependent operands and results with their +/// lowered counterparts. +class CIRGenericCXXABILoweringPattern : public mlir::ConversionPattern { +public: + CIRGenericCXXABILoweringPattern(mlir::MLIRContext *context, + const mlir::TypeConverter &typeConverter) + : mlir::ConversionPattern(typeConverter, MatchAnyOpTypeTag(), + /*benefit=*/1, context) {} + + mlir::LogicalResult + matchAndRewrite(mlir::Operation *op, llvm::ArrayRef<mlir::Value> operands, + mlir::ConversionPatternRewriter &rewriter) const override { + // Do not match on operations that have dedicated ABI lowering rewrite rules + if (llvm::isa<cir::AllocaOp, cir::ConstantOp, cir::FuncOp, + cir::GetRuntimeMemberOp, cir::GlobalOp>(op)) + return mlir::failure(); + + const mlir::TypeConverter *typeConverter = getTypeConverter(); + assert(typeConverter && + "CIRGenericCXXABILoweringPattern requires a type converter"); + if (typeConverter->isLegal(op)) { + // The operation does not have any CXXABI-dependent operands or results, + // the match fails. + return mlir::failure(); + } + + assert(op->getNumRegions() == 0 && "CIRGenericCXXABILoweringPattern cannot " + "deal with operations with regions"); + + mlir::OperationState loweredOpState(op->getLoc(), op->getName()); + loweredOpState.addOperands(operands); + loweredOpState.addAttributes(op->getAttrs()); + loweredOpState.addSuccessors(op->getSuccessors()); + + // Lower all result types + llvm::SmallVector<mlir::Type> loweredResultTypes; + loweredResultTypes.reserve(op->getNumResults()); + for (mlir::Type result : op->getResultTypes()) + loweredResultTypes.push_back(typeConverter->convertType(result)); + loweredOpState.addTypes(loweredResultTypes); + + // Clone the operation with lowered operand types and result types + mlir::Operation *loweredOp = rewriter.create(loweredOpState); + + rewriter.replaceOp(op, loweredOp); + return mlir::success(); + } +}; + +} // namespace + +mlir::LogicalResult CIRAllocaOpABILowering::matchAndRewrite( + cir::AllocaOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Type allocaPtrTy = op.getType(); + mlir::Type allocaTy = op.getAllocaType(); + mlir::Type loweredAllocaPtrTy = getTypeConverter()->convertType(allocaPtrTy); + mlir::Type loweredAllocaTy = getTypeConverter()->convertType(allocaTy); + + cir::AllocaOp loweredOp = cir::AllocaOp::create( + rewriter, op.getLoc(), loweredAllocaPtrTy, loweredAllocaTy, op.getName(), + op.getAlignmentAttr(), /*dynAllocSize=*/adaptor.getDynAllocSize()); + loweredOp.setInit(op.getInit()); + loweredOp.setConstant(op.getConstant()); + loweredOp.setAnnotationsAttr(op.getAnnotationsAttr()); + + rewriter.replaceOp(op, loweredOp); + return mlir::success(); +} + +mlir::LogicalResult CIRConstantOpABILowering::matchAndRewrite( + cir::ConstantOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + + if (mlir::isa<cir::DataMemberType>(op.getType())) { + auto dataMember = mlir::cast<cir::DataMemberAttr>(op.getValue()); + mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>()); + mlir::TypedAttr abiValue = lowerModule->getCXXABI().lowerDataMemberConstant( + dataMember, layout, *getTypeConverter()); + rewriter.replaceOpWithNewOp<ConstantOp>(op, abiValue); + return mlir::success(); + } + + llvm_unreachable("constant operand is not an CXXABI-dependent type"); +} + +mlir::LogicalResult CIRFuncOpABILowering::matchAndRewrite( + cir::FuncOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + cir::FuncType opFuncType = op.getFunctionType(); + mlir::TypeConverter::SignatureConversion signatureConversion( + opFuncType.getNumInputs()); + + for (const auto &[i, argType] : llvm::enumerate(opFuncType.getInputs())) { + mlir::Type loweredArgType = getTypeConverter()->convertType(argType); + if (!loweredArgType) + return mlir::failure(); + signatureConversion.addInputs(i, loweredArgType); + } + + mlir::Type loweredResultType = + getTypeConverter()->convertType(opFuncType.getReturnType()); + if (!loweredResultType) + return mlir::failure(); + + auto loweredFuncType = + cir::FuncType::get(signatureConversion.getConvertedTypes(), + loweredResultType, /*isVarArg=*/opFuncType.isVarArg()); + + // Create a new cir.func operation for the CXXABI-lowered function. + cir::FuncOp loweredFuncOp = rewriter.cloneWithoutRegions(op); + loweredFuncOp.setFunctionType(loweredFuncType); + rewriter.inlineRegionBefore(op.getBody(), loweredFuncOp.getBody(), + loweredFuncOp.end()); + if (mlir::failed(rewriter.convertRegionTypes( + &loweredFuncOp.getBody(), *getTypeConverter(), &signatureConversion))) + return mlir::failure(); + + rewriter.eraseOp(op); + return mlir::success(); +} + +mlir::LogicalResult CIRGlobalOpABILowering::matchAndRewrite( + cir::GlobalOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Type ty = op.getSymType(); + mlir::Type loweredTy = getTypeConverter()->convertType(ty); + if (!loweredTy) + return mlir::failure(); + + mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>()); + + mlir::Attribute loweredInit; + if (mlir::isa<cir::DataMemberType>(ty)) { + cir::DataMemberAttr init = + mlir::cast_if_present<cir::DataMemberAttr>(op.getInitialValueAttr()); + loweredInit = lowerModule->getCXXABI().lowerDataMemberConstant( + init, layout, *getTypeConverter()); + } else { + llvm_unreachable( + "inputs to cir.global in ABI lowering must be data member or method"); + } + + auto newOp = mlir::cast<cir::GlobalOp>(rewriter.clone(*op.getOperation())); + newOp.setInitialValueAttr(loweredInit); + newOp.setSymType(loweredTy); + rewriter.replaceOp(op, newOp); + return mlir::success(); +} + +mlir::LogicalResult CIRGetRuntimeMemberOpABILowering::matchAndRewrite( + cir::GetRuntimeMemberOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Type resTy = getTypeConverter()->convertType(op.getType()); + mlir::Operation *newOp = lowerModule->getCXXABI().lowerGetRuntimeMember( + op, resTy, adaptor.getAddr(), adaptor.getMember(), rewriter); + rewriter.replaceOp(op, newOp); + return mlir::success(); +} + +// Prepare the type converter for the CXXABI lowering pass. +// Even though this is a CIR-to-CIR pass, we are eliminating some CIR types. +static void prepareCXXABITypeConverter(mlir::TypeConverter &converter, + mlir::DataLayout &dataLayout, + cir::LowerModule &lowerModule) { + converter.addConversion([&](mlir::Type type) -> mlir::Type { return type; }); + // This is necessary in order to convert CIR pointer types that are pointing + // to CIR types that we are lowering in this pass. + converter.addConversion([&](cir::PointerType type) -> mlir::Type { + mlir::Type loweredPointeeType = converter.convertType(type.getPointee()); + if (!loweredPointeeType) + return {}; + return cir::PointerType::get(type.getContext(), loweredPointeeType, + type.getAddrSpace()); + }); + converter.addConversion([&](cir::DataMemberType type) -> mlir::Type { + mlir::Type abiType = + lowerModule.getCXXABI().lowerDataMemberType(type, converter); + return converter.convertType(abiType); + }); + // This is necessary in order to convert CIR function types that have argument + // or return types that use CIR types that we are lowering in this pass. + converter.addConversion([&](cir::FuncType type) -> mlir::Type { + llvm::SmallVector<mlir::Type> loweredInputTypes; + loweredInputTypes.reserve(type.getNumInputs()); + if (mlir::failed( + converter.convertTypes(type.getInputs(), loweredInputTypes))) + return {}; + + mlir::Type loweredReturnType = converter.convertType(type.getReturnType()); + if (!loweredReturnType) + return {}; + + return cir::FuncType::get(loweredInputTypes, loweredReturnType, + /*isVarArg=*/type.getVarArg()); + }); +} + +static void +populateCXXABIConversionTarget(mlir::ConversionTarget &target, + const mlir::TypeConverter &typeConverter) { + target.addLegalOp<mlir::ModuleOp>(); + + // The ABI lowering pass is interested in CIR operations with operands or + // results of CXXABI-dependent types, or CIR operations with regions whose + // block arguments are of CXXABI-dependent types. + target.addDynamicallyLegalDialect<cir::CIRDialect>( + [&typeConverter](mlir::Operation *op) { + if (!typeConverter.isLegal(op)) + return false; + return std::all_of(op->getRegions().begin(), op->getRegions().end(), + [&typeConverter](mlir::Region ®ion) { + return typeConverter.isLegal(®ion); + }); + }); + + // Some CIR ops needs special checking for legality + target.addDynamicallyLegalOp<cir::FuncOp>([&typeConverter](cir::FuncOp op) { + return typeConverter.isLegal(op.getFunctionType()); + }); + target.addDynamicallyLegalOp<cir::GlobalOp>( + [&typeConverter](cir::GlobalOp op) { + return typeConverter.isLegal(op.getSymType()); + }); +} + +//===----------------------------------------------------------------------===// +// The Pass +//===----------------------------------------------------------------------===// + +void CXXABILoweringPass::runOnOperation() { + auto module = mlir::cast<mlir::ModuleOp>(getOperation()); + mlir::MLIRContext *ctx = module.getContext(); + + // If the triple is not present, e.g. CIR modules parsed from text, we + // cannot init LowerModule properly. + assert(!cir::MissingFeatures::makeTripleAlwaysPresent()); + // If no target triple is available, skip the ABI lowering pass. + if (!module->hasAttr(cir::CIRDialect::getTripleAttrName())) + return; + + mlir::PatternRewriter rewriter(ctx); + std::unique_ptr<cir::LowerModule> lowerModule = + cir::createLowerModule(module, rewriter); + + mlir::DataLayout dataLayout(module); + mlir::TypeConverter typeConverter; + prepareCXXABITypeConverter(typeConverter, dataLayout, *lowerModule); + + mlir::RewritePatternSet patterns(ctx); + patterns.add<CIRGenericCXXABILoweringPattern>(patterns.getContext(), + typeConverter); + patterns.add< + // clang-format off + CIRAllocaOpABILowering, + CIRConstantOpABILowering, + CIRFuncOpABILowering, + CIRGetRuntimeMemberOpABILowering, + CIRGlobalOpABILowering + // clang-format on + >(patterns.getContext(), typeConverter, dataLayout, *lowerModule); + + mlir::ConversionTarget target(*ctx); + populateCXXABIConversionTarget(target, typeConverter); + + if (failed(mlir::applyPartialConversion(module, target, std::move(patterns)))) + signalPassFailure(); +} + +std::unique_ptr<Pass> mlir::createCXXABILoweringPass() { + return std::make_unique<CXXABILoweringPass>(); +} diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp b/clang/lib/CIR/Lowering/CIRPasses.cpp index ccc838717e421..72348ff6287b4 100644 --- a/clang/lib/CIR/Lowering/CIRPasses.cpp +++ b/clang/lib/CIR/Lowering/CIRPasses.cpp @@ -31,6 +31,7 @@ mlir::LogicalResult runCIRToCIRPasses(mlir::ModuleOp theModule, if (enableCIRSimplify) pm.addPass(mlir::createCIRSimplifyPass()); + pm.addPass(mlir::createCXXABILoweringPass()); pm.addPass(mlir::createLoweringPreparePass(&astContext)); pm.enableVerifier(enableVerifier); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index c01b2c1487709..507c5596471ad 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -258,9 +258,9 @@ class CIRAttrToValue { return llvm::TypeSwitch<mlir::Attribute, mlir::Value>(attr) .Case<cir::IntAttr, cir::FPAttr, cir::ConstComplexAttr, cir::ConstArrayAttr, cir::ConstRecordAttr, cir::ConstVectorAttr, - cir::ConstPtrAttr, cir::DataMemberAttr, cir::GlobalViewAttr, - cir::TypeInfoAttr, cir::UndefAttr, cir::VTableAttr, - cir::ZeroAttr>([&](auto attrT) { return visitCirAttr(attrT); }) + cir::ConstPtrAttr, cir::GlobalViewAttr, cir::TypeInfoAttr, + cir::UndefAttr, cir::VTableAttr, cir::ZeroAttr>( + [&](auto attrT) { return visitCirAttr(attrT); }) .Default([&](auto attrT) { return mlir::Value(); }); } @@ -271,7 +271,6 @@ class CIRAttrToValue { mlir::Value visitCirAttr(cir::ConstArrayAttr attr); mlir::Value visitCirAttr(cir::ConstRecordAttr attr); mlir::Value visitCirAttr(cir::ConstVectorAttr attr); - mlir::Value visitCirAttr(cir::DataMemberAttr attr); mlir::Value visitCirAttr(cir::GlobalViewAttr attr); mlir::Value visitCirAttr(cir::TypeInfoAttr attr); mlir::Value visitCirAttr(cir::UndefAttr attr); @@ -526,15 +525,6 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstVectorAttr attr) { mlirValues)); } -mlir::Value CIRAttrToValue::visitCirAttr(cir::DataMemberAttr attr) { - assert(lowerMod && "lower module is not available"); - mlir::DataLayout layout(parentOp->getParentOfType<mlir::ModuleOp>()); - mlir::TypedAttr init = - lowerMod->getCXXABI().lowerDataMemberConstant(attr, layout, *converter); - // Recursively lower the CIR attribute produced by the C++ ABI. - return visit(init); -} - // GlobalViewAttr visitor. mlir::Value CIRAttrToValue::visitCirAttr(cir::GlobalViewAttr globalAttr) { auto moduleOp = parentOp->getParentOfType<mlir::ModuleOp>(); @@ -1776,14 +1766,6 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite( return mlir::success(); } attr = op.getValue(); - } else if (mlir::isa<cir::DataMemberType>(op.getType())) { - assert(lowerMod && "lower module is not available"); - auto dataMember = mlir::cast<cir::DataMemberAttr>(op.getValue()); - mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>()); - mlir::TypedAttr abiValue = lowerMod->getCXXABI().lowerDataMemberConstant( - dataMember,... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/172133 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
