[clang] 58cf128 - [CIR] Move CIR CXXABI lowering to a standlone pass (#172133)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Dec 18 14:36:21 PST 2025
Author: Andy Kaylor
Date: 2025-12-18T22:36:17Z
New Revision: 58cf128e50fe759373798c4512830c177ed9ecdb
URL: https://github.com/llvm/llvm-project/commit/58cf128e50fe759373798c4512830c177ed9ecdb
DIFF: https://github.com/llvm/llvm-project/commit/58cf128e50fe759373798c4512830c177ed9ecdb.diff
LOG: [CIR] Move CIR CXXABI lowering to a standlone pass (#172133)
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.
---------
Co-authored-by: Sirui Mu <msrlancern at gmail.com>
---------
Co-authored-by: Sirui Mu <msrlancern at gmail.com>
Added:
clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
Modified:
clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
clang/include/clang/CIR/Dialect/IR/CIROps.td
clang/include/clang/CIR/Dialect/Passes.h
clang/include/clang/CIR/Dialect/Passes.td
clang/lib/CIR/CodeGen/CIRGenTypes.cpp
clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
clang/lib/CIR/Lowering/CIRPasses.cpp
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
clang/test/CIR/CodeGen/pointer-to-data-member.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 899a475bc4ac8..cc28941aaa079 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -97,6 +97,10 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return getConstPtrAttr(t, 0);
}
+ mlir::TypedAttr getNullDataMemberAttr(cir::DataMemberType ty) {
+ return cir::DataMemberAttr::get(ty);
+ }
+
mlir::TypedAttr getZeroInitAttr(mlir::Type ty) {
if (mlir::isa<cir::IntType>(ty))
return cir::IntAttr::get(ty, 0);
@@ -112,6 +116,8 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return getConstNullPtrAttr(ptrTy);
if (auto recordTy = mlir::dyn_cast<cir::RecordType>(ty))
return cir::ZeroAttr::get(recordTy);
+ if (auto dataMemberTy = mlir::dyn_cast<cir::DataMemberType>(ty))
+ return getNullDataMemberAttr(dataMemberTy);
if (mlir::isa<cir::BoolType>(ty)) {
return getFalseAttr();
}
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index f965b8a5b7cff..630d357f40db7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3651,6 +3651,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..48c409fa83cee 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", "mlir::ModuleOp"> {
+ 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/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index 2e0193ac71e49..5264357448271 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -34,8 +34,10 @@ mlir::MLIRContext &CIRGenTypes::getMLIRContext() const {
/// expanding the type because we're in a recursive context.
bool CIRGenTypes::isFuncParamTypeConvertible(clang::QualType type) {
// Some ABIs cannot have their member pointers represented in LLVM IR unless
- // certain circumstances have been reached.
- assert(!type->getAs<MemberPointerType>() && "NYI");
+ // certain circumstances have been reached, but in CIR we represent member
+ // pointer types abstractly at this point so they are always convertible.
+ if (type->getAs<MemberPointerType>())
+ return true;
// If this isn't a tag type, we can convert it.
const TagType *tagType = type->getAs<TagType>();
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..bcd9147b130e5
--- /dev/null
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -0,0 +1,362 @@
+//==- 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) {}
+};
+
+// TODO(cir): Use TableGen to generate these patterns.
+#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");
+ bool operandsAndResultsLegal = typeConverter->isLegal(op);
+ bool regionsLegal =
+ std::all_of(op->getRegions().begin(), op->getRegions().end(),
+ [typeConverter](mlir::Region ®ion) {
+ return typeConverter->isLegal(®ion);
+ });
+ if (operandsAndResultsLegal && regionsLegal) {
+ // 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);
+
+ // Lower all regions
+ for (mlir::Region ®ion : op->getRegions()) {
+ mlir::Region *loweredRegion = loweredOpState.addRegion();
+ rewriter.inlineRegionBefore(region, *loweredRegion, loweredRegion->end());
+ if (mlir::failed(
+ rewriter.convertRegionTypes(loweredRegion, *getTypeConverter())))
+ return mlir::failure();
+ }
+
+ // 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 9a2815031970a..611850e7ae44b 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);
@@ -282,7 +281,7 @@ class CIRAttrToValue {
mlir::Operation *parentOp;
mlir::ConversionPatternRewriter &rewriter;
const mlir::TypeConverter *converter;
- cir::LowerModule *lowerMod;
+ [[maybe_unused]] cir::LowerModule *lowerMod;
};
/// Switches on the type of attribute and calls the appropriate conversion.
@@ -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, layout, *typeConverter);
- rewriter.replaceOpWithNewOp<ConstantOp>(op, abiValue);
- return mlir::success();
} else if (const auto arrTy = mlir::dyn_cast<cir::ArrayType>(op.getType())) {
const auto constArr = mlir::dyn_cast<cir::ConstArrayAttr>(op.getValue());
if (!constArr && !isa<cir::ZeroAttr, cir::UndefAttr>(op.getValue()))
@@ -2128,10 +2110,11 @@ CIRToLLVMGlobalOpLowering::matchAndRewriteRegionInitializedGlobal(
cir::GlobalOp op, mlir::Attribute init,
mlir::ConversionPatternRewriter &rewriter) const {
// TODO: Generalize this handling when more types are needed here.
- assert((isa<cir::ConstArrayAttr, cir::ConstRecordAttr, cir::ConstVectorAttr,
- cir::ConstPtrAttr, cir::ConstComplexAttr, cir::DataMemberAttr,
- cir::GlobalViewAttr, cir::TypeInfoAttr, cir::UndefAttr,
- cir::VTableAttr, cir::ZeroAttr>(init)));
+ assert(
+ (isa<cir::ConstArrayAttr, cir::ConstRecordAttr, cir::ConstVectorAttr,
+ cir::ConstPtrAttr, cir::ConstComplexAttr, cir::GlobalViewAttr,
+ cir::TypeInfoAttr, cir::UndefAttr, cir::VTableAttr, cir::ZeroAttr>(
+ init)));
// TODO(cir): once LLVM's dialect has proper equivalent attributes this
// should be updated. For now, we use a custom op to initialize globals
@@ -2187,9 +2170,9 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
}
} else if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr,
cir::ConstRecordAttr, cir::ConstPtrAttr,
- cir::ConstComplexAttr, cir::DataMemberAttr,
- cir::GlobalViewAttr, cir::TypeInfoAttr, cir::UndefAttr,
- cir::VTableAttr, cir::ZeroAttr>(init.value())) {
+ cir::ConstComplexAttr, cir::GlobalViewAttr,
+ cir::TypeInfoAttr, cir::UndefAttr, cir::VTableAttr,
+ cir::ZeroAttr>(init.value())) {
// TODO(cir): once LLVM's dialect has proper equivalent attributes this
// should be updated. For now, we use a custom op to initialize globals
// to the appropriate value.
@@ -2896,13 +2879,6 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
assert(!cir::MissingFeatures::addressSpace());
return mlir::LLVM::LLVMPointerType::get(type.getContext());
});
- converter.addConversion(
- [&, lowerModule](cir::DataMemberType type) -> mlir::Type {
- assert(lowerModule && "CXXABI is not available");
- mlir::Type abiType =
- lowerModule->getCXXABI().lowerDataMemberType(type, converter);
- return converter.convertType(abiType);
- });
converter.addConversion([&](cir::ArrayType type) -> mlir::Type {
mlir::Type ty =
convertTypeForMemory(converter, dataLayout, type.getElementType());
@@ -3249,17 +3225,6 @@ mlir::LogicalResult CIRToLLVMGetMemberOpLowering::matchAndRewrite(
}
}
-mlir::LogicalResult CIRToLLVMGetRuntimeMemberOpLowering::matchAndRewrite(
- cir::GetRuntimeMemberOp op, OpAdaptor adaptor,
- mlir::ConversionPatternRewriter &rewriter) const {
- assert(lowerMod && "lowering module is not available");
- mlir::Type llvmResTy = getTypeConverter()->convertType(op.getType());
- mlir::Operation *llvmOp = lowerMod->getCXXABI().lowerGetRuntimeMember(
- op, llvmResTy, adaptor.getAddr(), adaptor.getMember(), rewriter);
- rewriter.replaceOp(op, llvmOp);
- return mlir::success();
-}
-
mlir::LogicalResult CIRToLLVMUnreachableOpLowering::matchAndRewrite(
cir::UnreachableOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/test/CIR/CodeGen/pointer-to-data-member.cpp b/clang/test/CIR/CodeGen/pointer-to-data-member.cpp
index bee6562e59b8e..818cb75624a66 100644
--- a/clang/test/CIR/CodeGen/pointer-to-data-member.cpp
+++ b/clang/test/CIR/CodeGen/pointer-to-data-member.cpp
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -Wno-unused-value -emit-cir %s -o %t.cir
-// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -Wno-unused-value -emit-cir -mmlir -mlir-print-ir-before=cir-cxxabi-lowering %s -o %t.cir 2> %t-before.cir
+// RUN: FileCheck --check-prefix=CIR-BEFORE --input-file=%t-before.cir %s
+// RUN: FileCheck --check-prefix=CIR-AFTER --input-file=%t.cir %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -Wno-unused-value -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -Wno-unused-value -emit-llvm %s -o %t.ll
@@ -12,7 +13,8 @@ struct Point {
};
int Point::*pt_member = &Point::z;
-// CIR: cir.global external @pt_member = #cir.data_member<2> : !cir.data_member<!s32i in !rec_Point>
+// CIR-BEFORE: cir.global external @pt_member = #cir.data_member<2> : !cir.data_member<!s32i in !rec_Point>
+// CIR-AFTER: cir.global external @pt_member = #cir.int<8> : !s64i
// LLVM: @pt_member = global i64 8
// OGCG: @pt_member = global i64 8
@@ -20,12 +22,43 @@ auto test1() -> int Point::* {
return &Point::y;
}
-// CIR: cir.func {{.*}} @_Z5test1v() -> !cir.data_member<!s32i in !rec_Point> {
-// CIR: %[[RETVAL:.*]] = cir.alloca !cir.data_member<!s32i in !rec_Point>, !cir.ptr<!cir.data_member<!s32i in !rec_Point>>, ["__retval"]
-// CIR: %[[MEMBER:.*]] = cir.const #cir.data_member<1> : !cir.data_member<!s32i in !rec_Point>
-// CIR: cir.store %[[MEMBER]], %[[RETVAL]] : !cir.data_member<!s32i in !rec_Point>, !cir.ptr<!cir.data_member<!s32i in !rec_Point>>
-// CIR: %[[RET:.*]] = cir.load %[[RETVAL]] : !cir.ptr<!cir.data_member<!s32i in !rec_Point>>, !cir.data_member<!s32i in !rec_Point>
-// CIR: cir.return %[[RET]] : !cir.data_member<!s32i in !rec_Point>
+int Point::*pt_member_nested_region = test1();
+
+// CIR-BEFORE: cir.global external @pt_member_nested_region = ctor : !cir.data_member<!s32i in !rec_Point> {
+// CIR-BEFORE: %[[MEMBER_PTR_ADDR:.*]] = cir.get_global @pt_member_nested_region : !cir.ptr<!cir.data_member<!s32i in !rec_Point>>
+// CIR-BEFORE: %[[MEMBER_PTR:.*]] = cir.call @_Z5test1v() : () -> !cir.data_member<!s32i in !rec_Point>
+// CIR-BEFORE: cir.store{{.*}} %[[MEMBER_PTR]], %[[MEMBER_PTR_ADDR]] : !cir.data_member<!s32i in !rec_Point>, !cir.ptr<!cir.data_member<!s32i in !rec_Point>>
+// CIR-BEFORE: }
+
+// CIR-AFTER: cir.global external @pt_member_nested_region = #cir.int<-1> : !s64i
+// CIR-AFTER: cir.func internal private @__cxx_global_var_init()
+// CIR-AFTER: %[[MEMBER_PTR_ADDR:.*]] = cir.get_global @pt_member_nested_region : !cir.ptr<!s64i>
+// CIR-AFTER: %[[MEMBER_PTR:.*]] = cir.call @_Z5test1v() : () -> !s64i
+// CIR-AFTER: cir.store align(8) %[[MEMBER_PTR]], %[[MEMBER_PTR_ADDR]] : !s64i, !cir.ptr<!s64i>
+
+// LLVM: @pt_member_nested_region = global i64 -1, align 8
+// LLVM: define internal void @__cxx_global_var_init()
+// LLVM: %[[MEMBER_PTR:.*]] = call i64 @_Z5test1v()
+// LLVM: store i64 %[[MEMBER_PTR]], ptr @pt_member_nested_region, align 8
+
+// OGCG: @pt_member_nested_region = global i64 -1, align 8
+// OGCG emits __cxx_global_var_init between test1() and test2(). See checks below.
+
+// Checks for test1()
+
+// CIR-BEFORE: cir.func {{.*}} @_Z5test1v() -> !cir.data_member<!s32i in !rec_Point> {
+// CIR-BEFORE: %[[RETVAL:.*]] = cir.alloca !cir.data_member<!s32i in !rec_Point>, !cir.ptr<!cir.data_member<!s32i in !rec_Point>>, ["__retval"]
+// CIR-BEFORE: %[[MEMBER:.*]] = cir.const #cir.data_member<1> : !cir.data_member<!s32i in !rec_Point>
+// CIR-BEFORE: cir.store %[[MEMBER]], %[[RETVAL]] : !cir.data_member<!s32i in !rec_Point>, !cir.ptr<!cir.data_member<!s32i in !rec_Point>>
+// CIR-BEFORE: %[[RET:.*]] = cir.load %[[RETVAL]] : !cir.ptr<!cir.data_member<!s32i in !rec_Point>>, !cir.data_member<!s32i in !rec_Point>
+// CIR-BEFORE: cir.return %[[RET]] : !cir.data_member<!s32i in !rec_Point>
+
+// CIR-AFTER: cir.func {{.*}} @_Z5test1v() -> !s64i {
+// CIR-AFTER: %[[RETVAL:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["__retval"]
+// CIR-AFTER: %[[OFFSET:.*]] = cir.const #cir.int<4> : !s64i
+// CIR-AFTER: cir.store %[[OFFSET]], %[[RETVAL]] : !s64i, !cir.ptr<!s64i>
+// CIR-AFTER: %[[RET:.*]] = cir.load %[[RETVAL]] : !cir.ptr<!s64i>, !s64i
+// CIR-AFTER: cir.return %[[RET]] : !s64i
// LLVM: define {{.*}} i64 @_Z5test1v()
// LLVM: %[[RETVAL:.*]] = alloca i64
@@ -36,25 +69,48 @@ auto test1() -> int Point::* {
// OGCG: define {{.*}} i64 @_Z5test1v()
// OGCG: ret i64 4
+// OGCG: define internal void @__cxx_global_var_init()
+// OGCG: %[[MEMBER_PTR:.*]] = call i64 @_Z5test1v()
+// OGCG: store i64 %[[MEMBER_PTR]], ptr @pt_member_nested_region
+
+
int test2(const Point &pt, int Point::*member) {
return pt.*member;
}
-// CIR: cir.func {{.*}} @_Z5test2RK5PointMS_i(
-// CIR-SAME: %[[PT_ARG:.*]]: !cir.ptr<!rec_Point>
-// CIR-SAME: %[[MEMBER_ARG:.*]]: !cir.data_member<!s32i in !rec_Point>
-// CIR: %[[PT_ADDR:.*]] = cir.alloca {{.*}} ["pt", init, const]
-// CIR: %[[MEMBER_ADDR:.*]] = cir.alloca {{.*}} ["member", init]
-// CIR: %[[RETVAL_ADDR:.*]] = cir.alloca {{.*}} ["__retval"]
-// CIR: cir.store %[[PT_ARG]], %[[PT_ADDR]]
-// CIR: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]]
-// CIR: %[[PT:.*]] = cir.load %[[PT_ADDR]]
-// CIR: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]]
-// CIR: %[[RT_MEMBER:.*]] = cir.get_runtime_member %[[PT]][%[[MEMBER]] : !cir.data_member<!s32i in !rec_Point>] : !cir.ptr<!rec_Point> -> !cir.ptr<!s32i>
-// CIR: %[[VAL:.*]] = cir.load{{.*}} %[[RT_MEMBER]]
-// CIR: cir.store %[[VAL]], %[[RETVAL_ADDR]]
-// CIR: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]]
-// CIR: cir.return %[[RET]]
+// CIR-BEFORE: cir.func {{.*}} @_Z5test2RK5PointMS_i(
+// CIR-BEFORE-SAME: %[[PT_ARG:.*]]: !cir.ptr<!rec_Point>
+// CIR-BEFORE-SAME: %[[MEMBER_ARG:.*]]: !cir.data_member<!s32i in !rec_Point>
+// CIR-BEFORE: %[[PT_ADDR:.*]] = cir.alloca {{.*}} ["pt", init, const]
+// CIR-BEFORE: %[[MEMBER_ADDR:.*]] = cir.alloca {{.*}} ["member", init]
+// CIR-BEFORE: %[[RETVAL_ADDR:.*]] = cir.alloca {{.*}} ["__retval"]
+// CIR-BEFORE: cir.store %[[PT_ARG]], %[[PT_ADDR]]
+// CIR-BEFORE: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]]
+// CIR-BEFORE: %[[PT:.*]] = cir.load %[[PT_ADDR]]
+// CIR-BEFORE: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]]
+// CIR-BEFORE: %[[RT_MEMBER:.*]] = cir.get_runtime_member %[[PT]][%[[MEMBER]] : !cir.data_member<!s32i in !rec_Point>] : !cir.ptr<!rec_Point> -> !cir.ptr<!s32i>
+// CIR-BEFORE: %[[VAL:.*]] = cir.load{{.*}} %[[RT_MEMBER]]
+// CIR-BEFORE: cir.store %[[VAL]], %[[RETVAL_ADDR]]
+// CIR-BEFORE: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]]
+// CIR-BEFORE: cir.return %[[RET]]
+
+// CIR-AFTER: cir.func {{.*}} @_Z5test2RK5PointMS_i(
+// CIR-AFTER-SAME: %[[PT_ARG:.*]]: !cir.ptr<!rec_Point>
+// CIR-AFTER-SAME: %[[MEMBER_ARG:.*]]: !s64i
+// CIR-AFTER: %[[PT_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Point>, !cir.ptr<!cir.ptr<!rec_Point>>, ["pt", init, const]
+// CIR-AFTER: %[[MEMBER_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["member", init]
+// CIR-AFTER: %[[RETVAL_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
+// CIR-AFTER: cir.store %[[PT_ARG]], %[[PT_ADDR]] : !cir.ptr<!rec_Point>, !cir.ptr<!cir.ptr<!rec_Point>>
+// CIR-AFTER: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]] : !s64i, !cir.ptr<!s64i>
+// CIR-AFTER: %[[PT:.*]] = cir.load %[[PT_ADDR]] : !cir.ptr<!cir.ptr<!rec_Point>>, !cir.ptr<!rec_Point>
+// CIR-AFTER: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]] : !cir.ptr<!s64i>, !s64i
+// CIR-AFTER: %[[BYTE_PTR:.*]] = cir.cast bitcast %[[PT]] : !cir.ptr<!rec_Point> -> !cir.ptr<!s8i>
+// CIR-AFTER: %[[BYTE_PTR_STRIDE:.*]] = cir.ptr_stride %[[BYTE_PTR]], %[[MEMBER]] : (!cir.ptr<!s8i>, !s64i) -> !cir.ptr<!s8i>
+// CIR-AFTER: %[[VAL_ADDR:.*]] = cir.cast bitcast %[[BYTE_PTR_STRIDE]] : !cir.ptr<!s8i> -> !cir.ptr<!s32i>
+// CIR-AFTER: %[[VAL:.*]] = cir.load{{.*}} %[[VAL_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR-AFTER: cir.store %[[VAL]], %[[RETVAL_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR-AFTER: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR-AFTER: cir.return %[[RET]] : !s32i
// LLVM: define {{.*}} i32 @_Z5test2RK5PointMS_i(ptr %[[PT_ARG:.*]], i64 %[[MEMBER_ARG:.*]])
// LLVM: %[[PT_ADDR:.*]] = alloca ptr
@@ -85,21 +141,39 @@ int test3(const Point *pt, int Point::*member) {
return pt->*member;
}
-// CIR: cir.func {{.*}} @_Z5test3PK5PointMS_i(
-// CIR-SAME: %[[PT_ARG:.*]]: !cir.ptr<!rec_Point>
-// CIR-SAME: %[[MEMBER_ARG:.*]]: !cir.data_member<!s32i in !rec_Point>
-// CIR: %[[PT_ADDR:.*]] = cir.alloca {{.*}} ["pt", init]
-// CIR: %[[MEMBER_ADDR:.*]] = cir.alloca {{.*}} ["member", init]
-// CIR: %[[RETVAL_ADDR:.*]] = cir.alloca {{.*}} ["__retval"]
-// CIR: cir.store %[[PT_ARG]], %[[PT_ADDR]]
-// CIR: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]]
-// CIR: %[[PT:.*]] = cir.load{{.*}} %[[PT_ADDR]]
-// CIR: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]]
-// CIR: %[[RT_MEMBER:.*]] = cir.get_runtime_member %[[PT]][%[[MEMBER]] : !cir.data_member<!s32i in !rec_Point>] : !cir.ptr<!rec_Point> -> !cir.ptr<!s32i>
-// CIR: %[[VAL:.*]] = cir.load{{.*}} %[[RT_MEMBER]]
-// CIR: cir.store %[[VAL]], %[[RETVAL_ADDR]]
-// CIR: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]]
-// CIR: cir.return %[[RET]]
+// CIR-BEFORE: cir.func {{.*}} @_Z5test3PK5PointMS_i(
+// CIR-BEFORE-SAME: %[[PT_ARG:.*]]: !cir.ptr<!rec_Point>
+// CIR-BEFORE-SAME: %[[MEMBER_ARG:.*]]: !cir.data_member<!s32i in !rec_Point>
+// CIR-BEFORE: %[[PT_ADDR:.*]] = cir.alloca {{.*}} ["pt", init]
+// CIR-BEFORE: %[[MEMBER_ADDR:.*]] = cir.alloca {{.*}} ["member", init]
+// CIR-BEFORE: %[[RETVAL_ADDR:.*]] = cir.alloca {{.*}} ["__retval"]
+// CIR-BEFORE: cir.store %[[PT_ARG]], %[[PT_ADDR]]
+// CIR-BEFORE: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]]
+// CIR-BEFORE: %[[PT:.*]] = cir.load{{.*}} %[[PT_ADDR]]
+// CIR-BEFORE: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]]
+// CIR-BEFORE: %[[RT_MEMBER:.*]] = cir.get_runtime_member %[[PT]][%[[MEMBER]] : !cir.data_member<!s32i in !rec_Point>] : !cir.ptr<!rec_Point> -> !cir.ptr<!s32i>
+// CIR-BEFORE: %[[VAL:.*]] = cir.load{{.*}} %[[RT_MEMBER]]
+// CIR-BEFORE: cir.store %[[VAL]], %[[RETVAL_ADDR]]
+// CIR-BEFORE: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]]
+// CIR-BEFORE: cir.return %[[RET]]
+
+// CIR-AFTER: cir.func {{.*}} @_Z5test3PK5PointMS_i(
+// CIR-AFTER-SAME: %[[PT_ARG:.*]]: !cir.ptr<!rec_Point>
+// CIR-AFTER-SAME: %[[MEMBER_ARG:.*]]: !s64i
+// CIR-AFTER: %[[PT_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Point>, !cir.ptr<!cir.ptr<!rec_Point>>, ["pt", init]
+// CIR-AFTER: %[[MEMBER_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["member", init]
+// CIR-AFTER: %[[RETVAL_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
+// CIR-AFTER: cir.store %[[PT_ARG]], %[[PT_ADDR]] : !cir.ptr<!rec_Point>, !cir.ptr<!cir.ptr<!rec_Point>>
+// CIR-AFTER: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]] : !s64i, !cir.ptr<!s64i>
+// CIR-AFTER: %[[PT:.*]] = cir.load{{.*}} %[[PT_ADDR]] : !cir.ptr<!cir.ptr<!rec_Point>>, !cir.ptr<!rec_Point>
+// CIR-AFTER: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]] : !cir.ptr<!s64i>, !s64i
+// CIR-AFTER: %[[BYTE_PTR:.*]] = cir.cast bitcast %[[PT]] : !cir.ptr<!rec_Point> -> !cir.ptr<!s8i>
+// CIR-AFTER: %[[BYTE_PTR_STRIDE:.*]] = cir.ptr_stride %[[BYTE_PTR]], %[[MEMBER]] : (!cir.ptr<!s8i>, !s64i) -> !cir.ptr<!s8i>
+// CIR-AFTER: %[[VAL_ADDR:.*]] = cir.cast bitcast %[[BYTE_PTR_STRIDE]] : !cir.ptr<!s8i> -> !cir.ptr<!s32i>
+// CIR-AFTER: %[[VAL:.*]] = cir.load{{.*}} %[[VAL_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR-AFTER: cir.store %[[VAL]], %[[RETVAL_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR-AFTER: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR-AFTER: cir.return %[[RET]] : !s32i
// LLVM: define {{.*}} i32 @_Z5test3PK5PointMS_i(ptr %[[PT_ARG:.*]], i64 %[[MEMBER_ARG:.*]])
// LLVM: %[[PT_ADDR:.*]] = alloca ptr
@@ -132,15 +206,25 @@ auto test4(int Incomplete::*member) -> int Incomplete::* {
return member;
}
-// CIR: cir.func {{.*}} @_Z5test4M10Incompletei(
-// CIR-SAME: %[[MEMBER_ARG:.*]]: !cir.data_member<!s32i in !rec_Incomplete>
-// CIR: %[[MEMBER_ADDR:.*]] = cir.alloca {{.*}} ["member", init]
-// CIR: %[[RETVAL_ADDR:.*]] = cir.alloca {{.*}} ["__retval"]
-// CIR: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]]
-// CIR: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]]
-// CIR: cir.store %[[MEMBER]], %[[RETVAL_ADDR]]
-// CIR: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]]
-// CIR: cir.return %[[RET]]
+// CIR-BEFORE: cir.func {{.*}} @_Z5test4M10Incompletei(
+// CIR-BEFORE-SAME: %[[MEMBER_ARG:.*]]: !cir.data_member<!s32i in !rec_Incomplete>
+// CIR-BEFORE: %[[MEMBER_ADDR:.*]] = cir.alloca {{.*}} ["member", init]
+// CIR-BEFORE: %[[RETVAL_ADDR:.*]] = cir.alloca {{.*}} ["__retval"]
+// CIR-BEFORE: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]]
+// CIR-BEFORE: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]]
+// CIR-BEFORE: cir.store %[[MEMBER]], %[[RETVAL_ADDR]]
+// CIR-BEFORE: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]]
+// CIR-BEFORE: cir.return %[[RET]]
+
+// CIR-AFTER: cir.func {{.*}} @_Z5test4M10Incompletei(
+// CIR-AFTER-SAME: %[[MEMBER_ARG:.*]]: !s64i
+// CIR-AFTER: %[[MEMBER_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["member", init]
+// CIR-AFTER: %[[RETVAL_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["__retval"]
+// CIR-AFTER: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]] : !s64i, !cir.ptr<!s64i>
+// CIR-AFTER: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]] : !cir.ptr<!s64i>, !s64i
+// CIR-AFTER: cir.store %[[MEMBER]], %[[RETVAL_ADDR]] : !s64i, !cir.ptr<!s64i>
+// CIR-AFTER: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]] : !cir.ptr<!s64i>, !s64i
+// CIR-AFTER: cir.return %[[RET]] : !s64i
// LLVM: define {{.*}} i64 @_Z5test4M10Incompletei(i64 %[[MEMBER_ARG:.*]])
// LLVM: %[[MEMBER_ADDR:.*]] = alloca i64
@@ -161,21 +245,39 @@ int test5(Incomplete *ic, int Incomplete::*member) {
return ic->*member;
}
-// CIR: cir.func {{.*}} @_Z5test5P10IncompleteMS_i(
-// CIR-SAME: %[[IC_ARG:.*]]: !cir.ptr<!rec_Incomplete>
-// CIR-SAME: %[[MEMBER_ARG:.*]]: !cir.data_member<!s32i in !rec_Incomplete>
-// CIR: %[[IC_ADDR:.*]] = cir.alloca {{.*}} ["ic", init]
-// CIR: %[[MEMBER_ADDR:.*]] = cir.alloca {{.*}} ["member", init]
-// CIR: %[[RETVAL_ADDR:.*]] = cir.alloca {{.*}} ["__retval"]
-// CIR: cir.store %[[IC_ARG]], %[[IC_ADDR]]
-// CIR: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]]
-// CIR: %[[IC:.*]] = cir.load{{.*}} %[[IC_ADDR]]
-// CIR: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]]
-// CIR: %[[RT_MEMBER:.*]] = cir.get_runtime_member %[[IC]][%[[MEMBER]] : !cir.data_member<!s32i in !rec_Incomplete>] : !cir.ptr<!rec_Incomplete> -> !cir.ptr<!s32i>
-// CIR: %[[VAL:.*]] = cir.load{{.*}} %[[RT_MEMBER]]
-// CIR: cir.store %[[VAL]], %[[RETVAL_ADDR]]
-// CIR: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]]
-// CIR: cir.return %[[RET]]
+// CIR-BEFORE: cir.func {{.*}} @_Z5test5P10IncompleteMS_i(
+// CIR-BEFORE-SAME: %[[IC_ARG:.*]]: !cir.ptr<!rec_Incomplete>
+// CIR-BEFORE-SAME: %[[MEMBER_ARG:.*]]: !cir.data_member<!s32i in !rec_Incomplete>
+// CIR-BEFORE: %[[IC_ADDR:.*]] = cir.alloca {{.*}} ["ic", init]
+// CIR-BEFORE: %[[MEMBER_ADDR:.*]] = cir.alloca {{.*}} ["member", init]
+// CIR-BEFORE: %[[RETVAL_ADDR:.*]] = cir.alloca {{.*}} ["__retval"]
+// CIR-BEFORE: cir.store %[[IC_ARG]], %[[IC_ADDR]]
+// CIR-BEFORE: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]]
+// CIR-BEFORE: %[[IC:.*]] = cir.load{{.*}} %[[IC_ADDR]]
+// CIR-BEFORE: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]]
+// CIR-BEFORE: %[[RT_MEMBER:.*]] = cir.get_runtime_member %[[IC]][%[[MEMBER]] : !cir.data_member<!s32i in !rec_Incomplete>] : !cir.ptr<!rec_Incomplete> -> !cir.ptr<!s32i>
+// CIR-BEFORE: %[[VAL:.*]] = cir.load{{.*}} %[[RT_MEMBER]]
+// CIR-BEFORE: cir.store %[[VAL]], %[[RETVAL_ADDR]]
+// CIR-BEFORE: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]]
+// CIR-BEFORE: cir.return %[[RET]]
+
+// CIR-AFTER: cir.func {{.*}} @_Z5test5P10IncompleteMS_i(
+// CIR-AFTER-SAME: %[[IC_ARG:.*]]: !cir.ptr<!rec_Incomplete>
+// CIR-AFTER-SAME: %[[MEMBER_ARG:.*]]: !s64i
+// CIR-AFTER: %[[IC_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Incomplete>, !cir.ptr<!cir.ptr<!rec_Incomplete>>, ["ic", init]
+// CIR-AFTER: %[[MEMBER_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["member", init]
+// CIR-AFTER: %[[RETVAL_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
+// CIR-AFTER: cir.store %[[IC_ARG]], %[[IC_ADDR]] : !cir.ptr<!rec_Incomplete>, !cir.ptr<!cir.ptr<!rec_Incomplete>>
+// CIR-AFTER: cir.store %[[MEMBER_ARG]], %[[MEMBER_ADDR]] : !s64i, !cir.ptr<!s64i>
+// CIR-AFTER: %[[IC:.*]] = cir.load{{.*}} %[[IC_ADDR]] : !cir.ptr<!cir.ptr<!rec_Incomplete>>, !cir.ptr<!rec_Incomplete>
+// CIR-AFTER: %[[MEMBER:.*]] = cir.load{{.*}} %[[MEMBER_ADDR]] : !cir.ptr<!s64i>, !s64i
+// CIR-AFTER: %[[BYTE_PTR:.*]] = cir.cast bitcast %[[IC]] : !cir.ptr<!rec_Incomplete> -> !cir.ptr<!s8i>
+// CIR-AFTER: %[[BYTE_PTR_STRIDE:.*]] = cir.ptr_stride %[[BYTE_PTR]], %[[MEMBER]] : (!cir.ptr<!s8i>, !s64i) -> !cir.ptr<!s8i>
+// CIR-AFTER: %[[VAL_ADDR:.*]] = cir.cast bitcast %[[BYTE_PTR_STRIDE]] : !cir.ptr<!s8i> -> !cir.ptr<!s32i>
+// CIR-AFTER: %[[VAL:.*]] = cir.load{{.*}} %[[VAL_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR-AFTER: cir.store %[[VAL]], %[[RETVAL_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR-AFTER: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR-AFTER: cir.return %[[RET]] : !s32i
// LLVM: define {{.*}} i32 @_Z5test5P10IncompleteMS_i(ptr %[[IC_ARG:.*]], i64 %[[MEMBER_ARG:.*]])
// LLVM: %[[IC_ADDR:.*]] = alloca ptr
More information about the cfe-commits
mailing list