https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/171950
>From 29c637b8e3bd672afdd0beab5facda1e6afe4a80 Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Tue, 9 Dec 2025 15:46:54 -0800 Subject: [PATCH 1/4] [CIR] Upstream handling for data member pointer casts This adds the CIR basic handling for casts of data member pointers. Cast to bool and null, as well as member function pointer casts will be handled in followup PRs. --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 52 +++++++++ clang/include/clang/CIR/MissingFeatures.h | 2 + clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 34 ++++++ clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 32 +++++ .../Transforms/TargetLowering/CIRCXXABI.h | 12 ++ .../Transforms/TargetLowering/CMakeLists.txt | 1 + .../TargetLowering/LowerItaniumCXXABI.cpp | 51 ++++++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 18 +++ .../CodeGen/pointer-to-data-member-cast.cpp | 110 ++++++++++++++++++ 9 files changed, 312 insertions(+) create mode 100644 clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 7e7424fd71878..81d526e6da985 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4056,6 +4056,58 @@ def CIR_DerivedClassAddrOp : CIR_Op<"derived_class_addr"> { }]; } +//===----------------------------------------------------------------------===// +// BaseDataMemberOp & DerivedDataMemberOp +//===----------------------------------------------------------------------===// + +def CIR_BaseDataMemberOp : CIR_Op<"base_data_member", [Pure]> { + let summary = + "Cast a derived class data member pointer to a base class data member " + "pointer"; + let description = [{ + The `cir.base_data_member` operation casts a data member pointer of type + `T Derived::*` to a data member pointer of type `T Base::*`, where `Base` + is an accessible non-ambiguous non-virtual base class of `Derived`. + + The `offset` parameter gives the offset in bytes of the `Base` base class + subobject within a `Derived` object. + }]; + + let arguments = (ins CIR_DataMemberType:$src, IndexAttr:$offset); + let results = (outs CIR_DataMemberType:$result); + + let assemblyFormat = [{ + $src `:` qualified(type($src)) + ` ` `[` $offset `]` `->` qualified(type($result)) attr-dict + }]; + + let hasVerifier = 1; +} + +def CIR_DerivedDataMemberOp : CIR_Op<"derived_data_member", [Pure]> { + let summary = + "Cast a base class data member pointer to a derived class data member " + "pointer"; + let description = [{ + The `cir.derived_data_member` operation casts a data member pointer of type + `T Base::*` to a data member pointer of type `T Derived::*`, where `Base` + is an accessible non-ambiguous non-virtual base class of `Derived`. + + The `offset` parameter gives the offset in bytes of the `Base` base class + subobject within a `Derived` object. + }]; + + let arguments = (ins CIR_DataMemberType:$src, IndexAttr:$offset); + let results = (outs CIR_DataMemberType:$result); + + let assemblyFormat = [{ + $src `:` qualified(type($src)) + ` ` `[` $offset `]` `->` qualified(type($result)) attr-dict + }]; + + let hasVerifier = 1; +} + //===----------------------------------------------------------------------===// // ComplexCreateOp //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index acfc937a11993..51c8de3c98a23 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -302,6 +302,8 @@ struct MissingFeatures { static bool makeTripleAlwaysPresent() { return false; } static bool maybeHandleStaticInExternC() { return false; } static bool mergeAllConstants() { return false; } + static bool memberFuncPtrAuthInfo() { return false; } + static bool memberFuncPtrCast() { return false; } static bool metaDataNode() { return false; } static bool moduleNameHash() { return false; } static bool msabi() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 60884aefbfb1f..7aeb7f75078d2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -2210,6 +2210,40 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) { return builder.getNullPtr(ty, cgf.getLoc(subExpr->getExprLoc())); } + case CK_BaseToDerivedMemberPointer: + case CK_DerivedToBaseMemberPointer: { + mlir::Value src = Visit(subExpr); + + assert(!cir::MissingFeatures::memberFuncPtrAuthInfo()); + + QualType derivedTy = + kind == CK_DerivedToBaseMemberPointer ? subExpr->getType() : destTy; + const auto *mpType = derivedTy->castAs<MemberPointerType>(); + NestedNameSpecifier qualifier = mpType->getQualifier(); + assert(qualifier && "member pointer without class qualifier"); + const Type *qualifierType = qualifier.getAsType(); + assert(qualifierType && "member pointer qualifier is not a type"); + const CXXRecordDecl *derivedClass = qualifierType->getAsCXXRecordDecl(); + CharUnits offset = cgf.cgm.computeNonVirtualBaseClassOffset( + derivedClass, ce->path()); + + mlir::Location loc = cgf.getLoc(subExpr->getExprLoc()); + mlir::Type resultTy = cgf.convertType(destTy); + mlir::IntegerAttr offsetAttr = builder.getIndexAttr(offset.getQuantity()); + + if (subExpr->getType()->isMemberFunctionPointerType()) { + cgf.cgm.errorNYI(subExpr->getSourceRange(), + "VisitCastExpr: member function pointer"); + return {}; + } + + if (kind == CK_BaseToDerivedMemberPointer) + return cir::DerivedDataMemberOp::create(builder, loc, resultTy, src, + offsetAttr); + return cir::BaseDataMemberOp::create(builder, loc, resultTy, src, + offsetAttr); + } + case CK_LValueToRValue: assert(cgf.getContext().hasSameUnqualifiedType(subExpr->getType(), destTy)); assert(subExpr->isGLValue() && "lvalue-to-rvalue applied to r-value!"); diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 95fc3afffb156..ee164f09a035c 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2433,6 +2433,38 @@ OpFoldResult cir::UnaryOp::fold(FoldAdaptor adaptor) { return {}; } + +//===----------------------------------------------------------------------===// +// BaseDataMemberOp & DerivedDataMemberOp +//===----------------------------------------------------------------------===// + +static LogicalResult verifyMemberPtrCast(Operation *op, mlir::Value src, + mlir::Type resultTy) { + // Let the operand type be T1 C1::*, let the result type be T2 C2::*. + // Verify that T1 and T2 are the same type. + mlir::Type inputMemberTy; + mlir::Type resultMemberTy; + if (mlir::isa<cir::DataMemberType>(src.getType())) { + inputMemberTy = + mlir::cast<cir::DataMemberType>(src.getType()).getMemberTy(); + resultMemberTy = mlir::cast<cir::DataMemberType>(resultTy).getMemberTy(); + } + assert(!cir::MissingFeatures::memberFuncPtrCast()); + if (inputMemberTy != resultMemberTy) + return op->emitOpError() + << "member types of the operand and the result do not match"; + + return mlir::success(); +} + +LogicalResult cir::BaseDataMemberOp::verify() { + return verifyMemberPtrCast(getOperation(), getSrc(), getType()); +} + +LogicalResult cir::DerivedDataMemberOp::verify() { + return verifyMemberPtrCast(getOperation(), getSrc(), getType()); +} + //===----------------------------------------------------------------------===// // AwaitOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h index 90f0ac3478f9d..94472af27ea3f 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h @@ -53,6 +53,18 @@ class CIRCXXABI { lowerGetRuntimeMember(cir::GetRuntimeMemberOp op, mlir::Type loweredResultTy, mlir::Value loweredAddr, mlir::Value loweredMember, mlir::OpBuilder &builder) const = 0; + + /// Lower the given cir.base_data_member op to a sequence of more "primitive" + /// CIR operations that act on the ABI types. + virtual mlir::Value lowerBaseDataMember(cir::BaseDataMemberOp op, + mlir::Value loweredSrc, + mlir::OpBuilder &builder) const = 0; + + /// Lower the given cir.derived_data_member op to a sequence of more + /// "primitive" CIR operations that act on the ABI types. + virtual mlir::Value + lowerDerivedDataMember(cir::DerivedDataMemberOp op, mlir::Value loweredSrc, + mlir::OpBuilder &builder) const = 0; }; /// Creates an Itanium-family ABI. diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CMakeLists.txt b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CMakeLists.txt index 158c42e729536..3a1ab34cea4d9 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CMakeLists.txt +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CMakeLists.txt @@ -17,4 +17,5 @@ add_clang_library(MLIRCIRTargetLowering MLIRDLTIDialect MLIRCIR MLIRCIRInterfaces + MLIRLLVMDialect ) diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp index ce4b0c7e92d09..1d28107ba248b 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp @@ -47,6 +47,14 @@ class LowerItaniumCXXABI : public CIRCXXABI { lowerGetRuntimeMember(cir::GetRuntimeMemberOp op, mlir::Type loweredResultTy, mlir::Value loweredAddr, mlir::Value loweredMember, mlir::OpBuilder &builder) const override; + + mlir::Value lowerBaseDataMember(cir::BaseDataMemberOp op, + mlir::Value loweredSrc, + mlir::OpBuilder &builder) const override; + + mlir::Value lowerDerivedDataMember(cir::DerivedDataMemberOp op, + mlir::Value loweredSrc, + mlir::OpBuilder &builder) const override; }; } // namespace @@ -108,4 +116,47 @@ mlir::Operation *LowerItaniumCXXABI::lowerGetRuntimeMember( cir::CastKind::bitcast, memberBytesPtr); } +static mlir::Value lowerDataMemberCast(mlir::Operation *op, + mlir::Value loweredSrc, + std::int64_t offset, + bool isDerivedToBase, + mlir::OpBuilder &builder) { + if (offset == 0) + return loweredSrc; + mlir::Location loc = op->getLoc(); + mlir::Type ty = loweredSrc.getType(); + + auto nullValue = mlir::LLVM::ConstantOp::create( + builder, loc, ty, mlir::IntegerAttr::get(ty, -1)); + + auto isNull = mlir::LLVM::ICmpOp::create( + builder, loc, mlir::LLVM::ICmpPredicate::eq, loweredSrc, nullValue); + + auto offsetValue = mlir::LLVM::ConstantOp::create( + builder, loc, ty, mlir::IntegerAttr::get(ty, offset)); + mlir::Value adjustedPtr; + if (isDerivedToBase) + adjustedPtr = mlir::LLVM::SubOp::create(builder, loc, loweredSrc, offsetValue, mlir::LLVM::IntegerOverflowFlags::nsw); + else + adjustedPtr = mlir::LLVM::AddOp::create(builder, loc, loweredSrc, offsetValue, mlir::LLVM::IntegerOverflowFlags::nsw); + + return mlir::LLVM::SelectOp::create(builder, loc, isNull, loweredSrc, adjustedPtr); +} + +mlir::Value +LowerItaniumCXXABI::lowerBaseDataMember(cir::BaseDataMemberOp op, + mlir::Value loweredSrc, + mlir::OpBuilder &builder) const { + return lowerDataMemberCast(op, loweredSrc, op.getOffset().getSExtValue(), + /*isDerivedToBase=*/true, builder); +} + +mlir::Value +LowerItaniumCXXABI::lowerDerivedDataMember(cir::DerivedDataMemberOp op, + mlir::Value loweredSrc, + mlir::OpBuilder &builder) const { + return lowerDataMemberCast(op, loweredSrc, op.getOffset().getSExtValue(), + /*isDerivedToBase=*/false, builder); +} + } // namespace cir diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 6d01964ebac41..52e7cfa0f6f90 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1472,6 +1472,24 @@ mlir::LogicalResult CIRToLLVMDerivedClassAddrOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMBaseDataMemberOpLowering::matchAndRewrite( + cir::BaseDataMemberOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Value loweredResult = + lowerMod->getCXXABI().lowerBaseDataMember(op, adaptor.getSrc(), rewriter); + rewriter.replaceOp(op, loweredResult); + return mlir::success(); +} + +mlir::LogicalResult CIRToLLVMDerivedDataMemberOpLowering::matchAndRewrite( + cir::DerivedDataMemberOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Value loweredResult = lowerMod->getCXXABI().lowerDerivedDataMember( + op, adaptor.getSrc(), rewriter); + rewriter.replaceOp(op, loweredResult); + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMATanOpLowering::matchAndRewrite( cir::ATanOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp b/clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp new file mode 100644 index 0000000000000..e5c673d031a2e --- /dev/null +++ b/clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp @@ -0,0 +1,110 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir --check-prefix=CIR %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll --check-prefix=LLVM %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll --check-prefix=OGCG %s + +struct Base1 { + int base1_data; +}; + +struct Base2 { + int base2_data; +}; + +struct Derived : Base1, Base2 { + int derived_data; +}; + +auto base_to_derived(int Base2::*ptr) -> int Derived::* { + return ptr; +} + +// CIR: cir.func {{.*}} @_Z15base_to_derivedM5Base2i +// CIR: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} +// CIR: %[[RET:.*]] = cir.derived_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Base2> [4] -> !cir.data_member<!s32i in !rec_Derived> + +// LLVM: define {{.*}} i64 @_Z15base_to_derivedM5Base2i +// LLVM: %[[PTR:.*]] = load i64, ptr %{{.*}} +// LLVM: %[[IS_NULL:.*]] = icmp eq i64 %[[PTR]], -1 +// LLVM: %[[DERIVED:.*]] = add nsw i64 %[[PTR]], 4 +// LLVM: %[[RET:.*]] = select i1 %[[IS_NULL]], i64 %[[PTR]], i64 %[[DERIVED]] + +// OGCG: define {{.*}} i64 @_Z15base_to_derivedM5Base2i +// OGCG: %[[PTR:.*]] = load i64, ptr %{{.*}} +// OGCG: %[[DERIVED:.*]] = add nsw i64 %[[PTR]], 4 +// OGCG: %[[IS_NULL:.*]] = icmp eq i64 %[[PTR]], -1 +// OGCG: %[[RET:.*]] = select i1 %[[IS_NULL]], i64 %[[PTR]], i64 %[[DERIVED]] + +auto derived_to_base(int Derived::*ptr) -> int Base2::* { + return static_cast<int Base2::*>(ptr); +} + +// CIR: cir.func {{.*}} @_Z15derived_to_baseM7Derivedi +// CIR: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} +// CIR: %[[RET:.*]] = cir.base_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Derived> [4] -> !cir.data_member<!s32i in !rec_Base2> + +// LLVM: define {{.*}} i64 @_Z15derived_to_baseM7Derivedi +// LLVM: %[[PTR:.*]] = load i64, ptr %{{.*}} +// LLVM: %[[IS_NULL:.*]] = icmp eq i64 %[[PTR]], -1 +// LLVM: %[[BASE:.*]] = sub nsw i64 %[[PTR]], 4 +// LLVM: %[[RET:.*]] = select i1 %[[IS_NULL]], i64 %[[PTR]], i64 %[[BASE]] + +// OGCG: define {{.*}} i64 @_Z15derived_to_baseM7Derivedi +// OGCG: %[[PTR:.*]] = load i64, ptr %{{.*}} +// OGCG: %[[BASE:.*]] = sub nsw i64 %[[PTR]], 4 +// OGCG: %[[IS_NULL:.*]] = icmp eq i64 %[[PTR]], -1 +// OGCG: %[[RET:.*]] = select i1 %[[IS_NULL]], i64 %[[PTR]], i64 %[[BASE]] + +auto base_to_derived_zero_offset(int Base1::*ptr) -> int Derived::* { + return ptr; +} + +// CIR: cir.func {{.*}} @_Z27base_to_derived_zero_offsetM5Base1i +// CIR: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} +// CIR: %[[RET:.*]] = cir.derived_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Base1> [0] -> !cir.data_member<!s32i in !rec_Derived> + +// No LLVM instructions emitted for performing a zero-offset cast. + +// LLVM: define {{.*}} i64 @_Z27base_to_derived_zero_offsetM5Base1i +// LLVM-NEXT: %[[PTR_ADDR:.*]] = alloca i64 +// LLVM-NEXT: %[[RETVAL:.*]] = alloca i64 +// LLVM-NEXT: store i64 %{{.*}}, ptr %[[PTR_ADDR]] +// LLVM-NEXT: %[[TEMP:.*]] = load i64, ptr %[[PTR_ADDR]] +// LLVM-NEXT: store i64 %[[TEMP]], ptr %[[RETVAL]] +// LLVM-NEXT: %[[RET:.*]] = load i64, ptr %[[RETVAL]] +// LLVM-NEXT: ret i64 %[[RET]] + +// OGCG: define {{.*}} i64 @_Z27base_to_derived_zero_offsetM5Base1i +// OGCG-NEXT: entry: +// OGCG-NEXT: %[[PTR_ADDR:.*]] = alloca i64 +// OGCG-NEXT: store i64 %{{.*}}, ptr %[[PTR_ADDR]] +// OGCG-NEXT: %[[RET:.*]] = load i64, ptr %[[PTR_ADDR]] +// OGCG-NEXT: ret i64 %[[RET]] + +auto derived_to_base_zero_offset(int Derived::*ptr) -> int Base1::* { + return static_cast<int Base1::*>(ptr); +} + +// CIR: cir.func {{.*}} @_Z27derived_to_base_zero_offsetM7Derivedi +// CIR: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} +// CIR: %[[RET:.*]] = cir.base_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Derived> [0] -> !cir.data_member<!s32i in !rec_Base1> + +// No LLVM instructions emitted for performing a zero-offset cast. + +// LLVM: define {{.*}} i64 @_Z27derived_to_base_zero_offsetM7Derivedi +// LLVM-NEXT: %[[PTR_ADDR:.*]] = alloca i64 +// LLVM-NEXT: %[[RETVAL:.*]] = alloca i64 +// LLVM-NEXT: store i64 %{{.*}}, ptr %[[PTR_ADDR]] +// LLVM-NEXT: %[[TEMP:.*]] = load i64, ptr %[[PTR_ADDR]] +// LLVM-NEXT: store i64 %[[TEMP]], ptr %[[RETVAL]] +// LLVM-NEXT: %[[RET:.*]] = load i64, ptr %[[RETVAL]] +// LLVM-NEXT: ret i64 %[[RET]] + +// OGCG: define {{.*}} i64 @_Z27derived_to_base_zero_offsetM7Derivedi +// OGCG-NEXT: entry: +// OGCG-NEXT: %[[PTR_ADDR:.*]] = alloca i64 +// OGCG-NEXT: store i64 %{{.*}}, ptr %[[PTR_ADDR]] +// OGCG-NEXT: %[[RET:.*]] = load i64, ptr %[[PTR_ADDR]] +// OGCG-NEXT: ret i64 %[[RET]] >From 4facfe9a3971c3b75e65dc7b8c27651c1ffef296 Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Fri, 12 Dec 2025 09:20:22 -0800 Subject: [PATCH 2/4] Fix formatting --- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 4 ++-- .../Transforms/TargetLowering/LowerItaniumCXXABI.cpp | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 7aeb7f75078d2..40c6782e3e945 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -2224,8 +2224,8 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) { const Type *qualifierType = qualifier.getAsType(); assert(qualifierType && "member pointer qualifier is not a type"); const CXXRecordDecl *derivedClass = qualifierType->getAsCXXRecordDecl(); - CharUnits offset = cgf.cgm.computeNonVirtualBaseClassOffset( - derivedClass, ce->path()); + CharUnits offset = + cgf.cgm.computeNonVirtualBaseClassOffset(derivedClass, ce->path()); mlir::Location loc = cgf.getLoc(subExpr->getExprLoc()); mlir::Type resultTy = cgf.convertType(destTy); diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp index 1d28107ba248b..8028beea76e8e 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp @@ -136,11 +136,16 @@ static mlir::Value lowerDataMemberCast(mlir::Operation *op, builder, loc, ty, mlir::IntegerAttr::get(ty, offset)); mlir::Value adjustedPtr; if (isDerivedToBase) - adjustedPtr = mlir::LLVM::SubOp::create(builder, loc, loweredSrc, offsetValue, mlir::LLVM::IntegerOverflowFlags::nsw); + adjustedPtr = + mlir::LLVM::SubOp::create(builder, loc, loweredSrc, offsetValue, + mlir::LLVM::IntegerOverflowFlags::nsw); else - adjustedPtr = mlir::LLVM::AddOp::create(builder, loc, loweredSrc, offsetValue, mlir::LLVM::IntegerOverflowFlags::nsw); + adjustedPtr = + mlir::LLVM::AddOp::create(builder, loc, loweredSrc, offsetValue, + mlir::LLVM::IntegerOverflowFlags::nsw); - return mlir::LLVM::SelectOp::create(builder, loc, isNull, loweredSrc, adjustedPtr); + return mlir::LLVM::SelectOp::create(builder, loc, isNull, loweredSrc, + adjustedPtr); } mlir::Value >From d3297cf663973fc803ddd69a583bf44c0fa09e38 Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Thu, 18 Dec 2025 16:13:14 -0800 Subject: [PATCH 3/4] Move lowering to cxxabi lowering pass --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 2 + .../CIR/Dialect/Transforms/CXXABILowering.cpp | 27 +++++++++- .../TargetLowering/LowerItaniumCXXABI.cpp | 36 ++++++------- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 18 ------- .../CodeGen/pointer-to-data-member-cast.cpp | 53 ++++++++++++++----- 5 files changed, 83 insertions(+), 53 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 81d526e6da985..a28413f327e3a 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4082,6 +4082,7 @@ def CIR_BaseDataMemberOp : CIR_Op<"base_data_member", [Pure]> { }]; let hasVerifier = 1; + let hasLLVMLowering = false; } def CIR_DerivedDataMemberOp : CIR_Op<"derived_data_member", [Pure]> { @@ -4106,6 +4107,7 @@ def CIR_DerivedDataMemberOp : CIR_Op<"derived_data_member", [Pure]> { }]; let hasVerifier = 1; + let hasLLVMLowering = false; } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp index bcd9147b130e5..4434e235f0fc8 100644 --- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp @@ -57,7 +57,11 @@ class CIROpCXXABILoweringPattern : public mlir::OpConversionPattern<Op> { } CIR_CXXABI_LOWERING_PATTERN(CIRAllocaOpABILowering, cir::AllocaOp); +CIR_CXXABI_LOWERING_PATTERN(CIRBaseDataMemberOpABILowering, + cir::BaseDataMemberOp); CIR_CXXABI_LOWERING_PATTERN(CIRConstantOpABILowering, cir::ConstantOp); +CIR_CXXABI_LOWERING_PATTERN(CIRDerivedDataMemberOpABILowering, + cir::DerivedDataMemberOp); CIR_CXXABI_LOWERING_PATTERN(CIRFuncOpABILowering, cir::FuncOp); CIR_CXXABI_LOWERING_PATTERN(CIRGetRuntimeMemberOpABILowering, cir::GetRuntimeMemberOp); @@ -86,7 +90,8 @@ class CIRGenericCXXABILoweringPattern : public mlir::ConversionPattern { 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, + if (llvm::isa<cir::AllocaOp, cir::BaseDataMemberOp, cir::ConstantOp, + cir::DerivedDataMemberOp, cir::FuncOp, cir::GetRuntimeMemberOp, cir::GlobalOp>(op)) return mlir::failure(); @@ -238,6 +243,24 @@ mlir::LogicalResult CIRGlobalOpABILowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRBaseDataMemberOpABILowering::matchAndRewrite( + cir::BaseDataMemberOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Value loweredResult = lowerModule->getCXXABI().lowerBaseDataMember( + op, adaptor.getSrc(), rewriter); + rewriter.replaceOp(op, loweredResult); + return mlir::success(); +} + +mlir::LogicalResult CIRDerivedDataMemberOpABILowering::matchAndRewrite( + cir::DerivedDataMemberOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Value loweredResult = lowerModule->getCXXABI().lowerDerivedDataMember( + op, adaptor.getSrc(), rewriter); + rewriter.replaceOp(op, loweredResult); + return mlir::success(); +} + mlir::LogicalResult CIRGetRuntimeMemberOpABILowering::matchAndRewrite( cir::GetRuntimeMemberOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -343,7 +366,9 @@ void CXXABILoweringPass::runOnOperation() { patterns.add< // clang-format off CIRAllocaOpABILowering, + CIRBaseDataMemberOpABILowering, CIRConstantOpABILowering, + CIRDerivedDataMemberOpABILowering, CIRFuncOpABILowering, CIRGetRuntimeMemberOpABILowering, CIRGlobalOpABILowering diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp index 8028beea76e8e..c20a8f10819aa 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp @@ -126,26 +126,22 @@ static mlir::Value lowerDataMemberCast(mlir::Operation *op, mlir::Location loc = op->getLoc(); mlir::Type ty = loweredSrc.getType(); - auto nullValue = mlir::LLVM::ConstantOp::create( - builder, loc, ty, mlir::IntegerAttr::get(ty, -1)); - - auto isNull = mlir::LLVM::ICmpOp::create( - builder, loc, mlir::LLVM::ICmpPredicate::eq, loweredSrc, nullValue); - - auto offsetValue = mlir::LLVM::ConstantOp::create( - builder, loc, ty, mlir::IntegerAttr::get(ty, offset)); - mlir::Value adjustedPtr; - if (isDerivedToBase) - adjustedPtr = - mlir::LLVM::SubOp::create(builder, loc, loweredSrc, offsetValue, - mlir::LLVM::IntegerOverflowFlags::nsw); - else - adjustedPtr = - mlir::LLVM::AddOp::create(builder, loc, loweredSrc, offsetValue, - mlir::LLVM::IntegerOverflowFlags::nsw); - - return mlir::LLVM::SelectOp::create(builder, loc, isNull, loweredSrc, - adjustedPtr); + auto getConstantInt = [&](int64_t value) -> cir::ConstantOp { + return cir::ConstantOp::create(builder, loc, cir::IntAttr::get(ty, value)); + }; + + cir::ConstantOp nullValue = getConstantInt(-1); + auto isNull = cir::CmpOp::create(builder, loc, cir::CmpOpKind::eq, loweredSrc, + nullValue); + + cir::ConstantOp offsetValue = getConstantInt(offset); + auto binOpKind = isDerivedToBase ? cir::BinOpKind::Sub : cir::BinOpKind::Add; + cir::BinOp adjustedPtr = + cir::BinOp::create(builder, loc, ty, binOpKind, loweredSrc, offsetValue); + adjustedPtr.setNoSignedWrap(true); + + return cir::SelectOp::create(builder, loc, ty, isNull, loweredSrc, + adjustedPtr); } mlir::Value diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 52e7cfa0f6f90..6d01964ebac41 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1472,24 +1472,6 @@ mlir::LogicalResult CIRToLLVMDerivedClassAddrOpLowering::matchAndRewrite( return mlir::success(); } -mlir::LogicalResult CIRToLLVMBaseDataMemberOpLowering::matchAndRewrite( - cir::BaseDataMemberOp op, OpAdaptor adaptor, - mlir::ConversionPatternRewriter &rewriter) const { - mlir::Value loweredResult = - lowerMod->getCXXABI().lowerBaseDataMember(op, adaptor.getSrc(), rewriter); - rewriter.replaceOp(op, loweredResult); - return mlir::success(); -} - -mlir::LogicalResult CIRToLLVMDerivedDataMemberOpLowering::matchAndRewrite( - cir::DerivedDataMemberOp op, OpAdaptor adaptor, - mlir::ConversionPatternRewriter &rewriter) const { - mlir::Value loweredResult = lowerMod->getCXXABI().lowerDerivedDataMember( - op, adaptor.getSrc(), rewriter); - rewriter.replaceOp(op, loweredResult); - return mlir::success(); -} - mlir::LogicalResult CIRToLLVMATanOpLowering::matchAndRewrite( cir::ATanOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp b/clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp index e5c673d031a2e..db0012e51d2f9 100644 --- a/clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp +++ b/clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir --check-prefix=CIR %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -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 -emit-llvm %s -o %t-cir.ll // RUN: FileCheck --input-file=%t-cir.ll --check-prefix=LLVM %s // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -emit-llvm %s -o %t.ll @@ -21,9 +22,17 @@ auto base_to_derived(int Base2::*ptr) -> int Derived::* { return ptr; } -// CIR: cir.func {{.*}} @_Z15base_to_derivedM5Base2i -// CIR: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} -// CIR: %[[RET:.*]] = cir.derived_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Base2> [4] -> !cir.data_member<!s32i in !rec_Derived> +// CIR-BEFORE: cir.func {{.*}} @_Z15base_to_derivedM5Base2i +// CIR-BEFORE: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} +// CIR-BEFORE: %[[RET:.*]] = cir.derived_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Base2> [4] -> !cir.data_member<!s32i in !rec_Derived> + +// CIR-AFTER: cir.func {{.*}} @_Z15base_to_derivedM5Base2i +// CIR-AFTER: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s64i>, !s64i +// CIR-AFTER: %[[NULL_VALUE:.*]] = cir.const #cir.int<-1> : !s64i +// CIR-AFTER: %[[IS_NULL:.*]] = cir.cmp(eq, %[[PTR]], %[[NULL_VALUE]]) +// CIR-AFTER: %[[OFFSET_VALUE:.*]] = cir.const #cir.int<4> : !s64i +// CIR-AFTER: %[[BINOP_KIND:.*]] = cir.binop(add, %[[PTR]], %[[OFFSET_VALUE]]) nsw : !s64i +// CIR-AFTER: %[[SELECT:.*]] = cir.select if %[[IS_NULL]] then %[[PTR]] else %[[BINOP_KIND]] // LLVM: define {{.*}} i64 @_Z15base_to_derivedM5Base2i // LLVM: %[[PTR:.*]] = load i64, ptr %{{.*}} @@ -41,9 +50,17 @@ auto derived_to_base(int Derived::*ptr) -> int Base2::* { return static_cast<int Base2::*>(ptr); } -// CIR: cir.func {{.*}} @_Z15derived_to_baseM7Derivedi -// CIR: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} -// CIR: %[[RET:.*]] = cir.base_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Derived> [4] -> !cir.data_member<!s32i in !rec_Base2> +// CIR-BEFORE: cir.func {{.*}} @_Z15derived_to_baseM7Derivedi +// CIR-BEFORE: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} +// CIR-BEFORE: %[[RET:.*]] = cir.base_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Derived> [4] -> !cir.data_member<!s32i in !rec_Base2> + +// CIR-AFTER: cir.func {{.*}} @_Z15derived_to_baseM7Derivedi +// CIR-AFTER: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s64i>, !s64i +// CIR-AFTER: %[[NULL_VALUE:.*]] = cir.const #cir.int<-1> : !s64i +// CIR-AFTER: %[[IS_NULL:.*]] = cir.cmp(eq, %[[PTR]], %[[NULL_VALUE]]) +// CIR-AFTER: %[[OFFSET_VALUE:.*]] = cir.const #cir.int<4> : !s64i +// CIR-AFTER: %[[BINOP_KIND:.*]] = cir.binop(sub, %[[PTR]], %[[OFFSET_VALUE]]) nsw : !s64i +// CIR-AFTER: %[[SELECT:.*]] = cir.select if %[[IS_NULL]] then %[[PTR]] else %[[BINOP_KIND]] // LLVM: define {{.*}} i64 @_Z15derived_to_baseM7Derivedi // LLVM: %[[PTR:.*]] = load i64, ptr %{{.*}} @@ -61,9 +78,13 @@ auto base_to_derived_zero_offset(int Base1::*ptr) -> int Derived::* { return ptr; } -// CIR: cir.func {{.*}} @_Z27base_to_derived_zero_offsetM5Base1i -// CIR: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} -// CIR: %[[RET:.*]] = cir.derived_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Base1> [0] -> !cir.data_member<!s32i in !rec_Derived> +// CIR-BEFORE: cir.func {{.*}} @_Z27base_to_derived_zero_offsetM5Base1i +// CIR-BEFORE: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} +// CIR-BEFORE: %[[RET:.*]] = cir.derived_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Base1> [0] -> !cir.data_member<!s32i in !rec_Derived> + +// CIR-AFTER: cir.func {{.*}} @_Z27base_to_derived_zero_offsetM5Base1i +// CIR-AFTER: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s64i>, !s64i +// CIR-AFTER: cir.store %[[PTR]], %{{.*}} : !s64i, !cir.ptr<!s64i> // No LLVM instructions emitted for performing a zero-offset cast. @@ -87,9 +108,13 @@ auto derived_to_base_zero_offset(int Derived::*ptr) -> int Base1::* { return static_cast<int Base1::*>(ptr); } -// CIR: cir.func {{.*}} @_Z27derived_to_base_zero_offsetM7Derivedi -// CIR: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} -// CIR: %[[RET:.*]] = cir.base_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Derived> [0] -> !cir.data_member<!s32i in !rec_Base1> +// CIR-BEFORE: cir.func {{.*}} @_Z27derived_to_base_zero_offsetM7Derivedi +// CIR-BEFORE: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} +// CIR-BEFORE: %[[RET:.*]] = cir.base_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Derived> [0] -> !cir.data_member<!s32i in !rec_Base1> + +// CIR-AFTER: cir.func {{.*}} @_Z27derived_to_base_zero_offsetM7Derivedi +// CIR-AFTER: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s64i>, !s64i +// CIR-AFTER: cir.store %[[PTR]], %{{.*}} : !s64i, !cir.ptr<!s64i> // No LLVM instructions emitted for performing a zero-offset cast. >From c77f87934826bb383f67a476925f4eddc6265467 Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Tue, 6 Jan 2026 12:22:35 -0800 Subject: [PATCH 4/4] Update assembly format --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 6 ++---- clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index a28413f327e3a..b373a89545d31 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4077,8 +4077,7 @@ def CIR_BaseDataMemberOp : CIR_Op<"base_data_member", [Pure]> { let results = (outs CIR_DataMemberType:$result); let assemblyFormat = [{ - $src `:` qualified(type($src)) - ` ` `[` $offset `]` `->` qualified(type($result)) attr-dict + $src `[` $offset `]` `:` qualified(type($src)) `->` qualified(type($result)) attr-dict }]; let hasVerifier = 1; @@ -4102,8 +4101,7 @@ def CIR_DerivedDataMemberOp : CIR_Op<"derived_data_member", [Pure]> { let results = (outs CIR_DataMemberType:$result); let assemblyFormat = [{ - $src `:` qualified(type($src)) - ` ` `[` $offset `]` `->` qualified(type($result)) attr-dict + $src `[` $offset `]` `:` qualified(type($src)) `->` qualified(type($result)) attr-dict }]; let hasVerifier = 1; diff --git a/clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp b/clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp index db0012e51d2f9..91cf4b1ae5386 100644 --- a/clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp +++ b/clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp @@ -24,7 +24,7 @@ auto base_to_derived(int Base2::*ptr) -> int Derived::* { // CIR-BEFORE: cir.func {{.*}} @_Z15base_to_derivedM5Base2i // CIR-BEFORE: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} -// CIR-BEFORE: %[[RET:.*]] = cir.derived_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Base2> [4] -> !cir.data_member<!s32i in !rec_Derived> +// CIR-BEFORE: %[[RET:.*]] = cir.derived_data_member %[[PTR]][4] : !cir.data_member<!s32i in !rec_Base2> -> !cir.data_member<!s32i in !rec_Derived> // CIR-AFTER: cir.func {{.*}} @_Z15base_to_derivedM5Base2i // CIR-AFTER: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s64i>, !s64i @@ -52,7 +52,7 @@ auto derived_to_base(int Derived::*ptr) -> int Base2::* { // CIR-BEFORE: cir.func {{.*}} @_Z15derived_to_baseM7Derivedi // CIR-BEFORE: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} -// CIR-BEFORE: %[[RET:.*]] = cir.base_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Derived> [4] -> !cir.data_member<!s32i in !rec_Base2> +// CIR-BEFORE: %[[RET:.*]] = cir.base_data_member %[[PTR]][4] : !cir.data_member<!s32i in !rec_Derived> -> !cir.data_member<!s32i in !rec_Base2> // CIR-AFTER: cir.func {{.*}} @_Z15derived_to_baseM7Derivedi // CIR-AFTER: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s64i>, !s64i @@ -80,7 +80,7 @@ auto base_to_derived_zero_offset(int Base1::*ptr) -> int Derived::* { // CIR-BEFORE: cir.func {{.*}} @_Z27base_to_derived_zero_offsetM5Base1i // CIR-BEFORE: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} -// CIR-BEFORE: %[[RET:.*]] = cir.derived_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Base1> [0] -> !cir.data_member<!s32i in !rec_Derived> +// CIR-BEFORE: %[[RET:.*]] = cir.derived_data_member %[[PTR]][0] : !cir.data_member<!s32i in !rec_Base1> -> !cir.data_member<!s32i in !rec_Derived> // CIR-AFTER: cir.func {{.*}} @_Z27base_to_derived_zero_offsetM5Base1i // CIR-AFTER: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s64i>, !s64i @@ -110,7 +110,7 @@ auto derived_to_base_zero_offset(int Derived::*ptr) -> int Base1::* { // CIR-BEFORE: cir.func {{.*}} @_Z27derived_to_base_zero_offsetM7Derivedi // CIR-BEFORE: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} -// CIR-BEFORE: %[[RET:.*]] = cir.base_data_member %[[PTR]] : !cir.data_member<!s32i in !rec_Derived> [0] -> !cir.data_member<!s32i in !rec_Base1> +// CIR-BEFORE: %[[RET:.*]] = cir.base_data_member %[[PTR]][0] : !cir.data_member<!s32i in !rec_Derived> -> !cir.data_member<!s32i in !rec_Base1> // CIR-AFTER: cir.func {{.*}} @_Z27derived_to_base_zero_offsetM7Derivedi // CIR-AFTER: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s64i>, !s64i _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
