[clang] [CIR] Upstream support for pointer-to-method casts (PR #178004)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 26 10:00:16 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir
Author: Andy Kaylor (andykaylor)
<details>
<summary>Changes</summary>
This adds support in CIR for handling based-to-derived and derived-to-base casts of pointer-to-member values that point to member functions.
Co-authored-by: Sirui Mu <msrlancern@<!-- -->gmail.com>
---
Patch is 25.67 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/178004.diff
9 Files Affected:
- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+121)
- (modified) clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp (+4-3)
- (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+28)
- (modified) clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp (+21-2)
- (modified) clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h (+12)
- (modified) clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp (+45)
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+18)
- (modified) clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp (+140)
- (modified) clang/test/CIR/IR/invalid-struct.cir (+47)
``````````diff
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index fe35ab305f4ba..fe6e8f76cddb7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2797,6 +2797,55 @@ def CIR_ExtractMemberOp : CIR_Op<"extract_member", [Pure]> {
let hasVerifier = 1;
}
+//===----------------------------------------------------------------------===//
+// InsertMemberOp
+//===----------------------------------------------------------------------===//
+
+def CIR_InsertMemberOp : CIR_Op<"insert_member", [
+ Pure, AllTypesMatch<["record", "result"]>
+]> {
+ let summary = "Overwrite the value of a member of a record value";
+ let description = [{
+ The `cir.insert_member` operation overwrites the value of a particular
+ member in the input record value, and returns the modified record value. The
+ result of this operation is equal to the input record value, except for the
+ member specified by `index_attr` whose value is equal to the given value.
+
+ This operation is named after the LLVM instruction `insertvalue`.
+
+ Currently `cir.insert_member` does not work on unions.
+
+ Example:
+
+ ```mlir
+ // Suppose we have a record with multiple members.
+ !s32i = !cir.int<s, 32>
+ !s8i = !cir.int<s, 32>
+ !record_ty = !cir.record<"struct.Bar" {!s32i, !s8i}>
+
+ // And suppose we have a value of the record type.
+ %0 = cir.const #cir.const_record<{#cir.int<1> : !s32i, #cir.int<2> : !s8i}> : !record_ty
+ // %0 is {1, 2}
+
+ // Overwrite the second member of the record value.
+ %1 = cir.const #cir.int<3> : !s8i
+ %2 = cir.insert_member %0[1], %1 : !record_ty, !s8i
+ // %2 is {1, 3}
+ ```
+ }];
+
+ let arguments = (ins CIRRecordType:$record, I64Attr:$index,
+ CIR_AnyType:$value);
+ let results = (outs CIRRecordType:$result);
+
+ let assemblyFormat = [{
+ $record `[` $index `]` `,` $value attr-dict
+ `:` qualified(type($record)) `,` qualified(type($value))
+ }];
+
+ let hasVerifier = 1;
+}
+
//===----------------------------------------------------------------------===//
// GetElementOp
//===----------------------------------------------------------------------===//
@@ -4353,6 +4402,78 @@ def CIR_DerivedDataMemberOp : CIR_Op<"derived_data_member", [Pure]> {
let hasCXXABILowering = true;
}
+//===----------------------------------------------------------------------===//
+// BaseMethodOp & DerivedMethodOp
+//===----------------------------------------------------------------------===//
+
+def CIR_BaseMethodOp : CIR_Op<"base_method", [Pure]> {
+ let summary = [{
+ Cast a derived class pointer-to-member-function to a base class
+ pointer-to-member-function
+ }];
+ let description = [{
+ The `cir.base_method` operation casts a pointer-to-member-function of type
+ `Ret (Derived::*)(Args)` to a pointer-to-member-function of type
+ `Ret (Base::*)(Args)`, where `Base` is a non-virtual base class of
+ `Derived`.
+
+ The `offset` parameter gives the offset in bytes of the `Base` base class
+ subobject within a `Derived` object.
+
+ Example:
+
+ ```mlir
+ %1 = cir.base_method %0 [16] : !cir.method<!cir.func<(!s32i)> in !rec_Derived> -> !cir.method<!cir.func<(!s32i)> in !rec_Base>
+ ```
+ }];
+
+ let arguments = (ins CIR_MethodType:$src, IndexAttr:$offset);
+ let results = (outs CIR_MethodType:$result);
+
+ let assemblyFormat = [{
+ $src `[` $offset `]` `:` qualified(type($src))
+ `->` qualified(type($result)) attr-dict
+ }];
+
+ let hasVerifier = 1;
+ let hasLLVMLowering = false;
+ let hasCXXABILowering = true;
+}
+
+def CIR_DerivedMethodOp : CIR_Op<"derived_method", [Pure]> {
+ let summary = [{
+ Cast a base class pointer-to-member-function to a derived class
+ pointer-to-member-function
+ }];
+ let description = [{
+ The `cir.derived_method` operation casts a pointer-to-member-function of
+ type `Ret (Base::*)(Args)` to a pointer-to-member-function of type
+ `Ret (Derived::*)(Args)`, where `Base` is a non-virtual base class of
+ `Derived`.
+
+ The `offset` parameter gives the offset in bytes of the `Base` base class
+ subobject within a `Derived` object.
+
+ Example:
+
+ ```mlir
+ %1 = cir.derived_method %0 [16] : !cir.method<!cir.func<(!s32i)> in !rec_Base> -> !cir.method<!cir.func<(!s32i)> in !rec_Derived>
+ ```
+ }];
+
+ let arguments = (ins CIR_MethodType:$src, IndexAttr:$offset);
+ let results = (outs CIR_MethodType:$result);
+
+ let assemblyFormat = [{
+ $src `[` $offset `]` `:` qualified(type($src))
+ `->` qualified(type($result)) attr-dict
+ }];
+
+ let hasVerifier = 1;
+ let hasLLVMLowering = false;
+ let hasCXXABILowering = true;
+}
+
//===----------------------------------------------------------------------===//
// ComplexCreateOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index a7fc36bbb5bfb..940a0cb616b27 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -2281,9 +2281,10 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
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::DerivedMethodOp::create(builder, loc, resultTy, src,
+ offsetAttr);
+ return cir::BaseMethodOp::create(builder, loc, resultTy, src, offsetAttr);
}
if (kind == CK_BaseToDerivedMemberPointer)
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 7b9fc83403f71..c1461ebda53de 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2613,6 +2613,18 @@ LogicalResult cir::DerivedDataMemberOp::verify() {
return verifyMemberPtrCast(getOperation(), getSrc(), getType());
}
+//===----------------------------------------------------------------------===//
+// BaseMethodOp & DerivedMethodOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::BaseMethodOp::verify() {
+ return verifyMemberPtrCast(getOperation(), getSrc(), getType());
+}
+
+LogicalResult cir::DerivedMethodOp::verify() {
+ return verifyMemberPtrCast(getOperation(), getSrc(), getType());
+}
+
//===----------------------------------------------------------------------===//
// AwaitOp
//===----------------------------------------------------------------------===//
@@ -2791,6 +2803,22 @@ LogicalResult cir::ExtractMemberOp::verify() {
return mlir::success();
}
+//===----------------------------------------------------------------------===//
+// InsertMemberOp Definitions
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::InsertMemberOp::verify() {
+ auto recordTy = mlir::cast<cir::RecordType>(getRecord().getType());
+ if (recordTy.getKind() == cir::RecordType::Union)
+ return emitError() << "cir.insert_member currently does not support unions";
+ if (recordTy.getMembers().size() <= getIndex())
+ return emitError() << "member index out of bounds";
+ if (recordTy.getMembers()[getIndex()] != getValue().getType())
+ return emitError() << "member type mismatch";
+ // The op trait already checks that the types of $result and $record match.
+ return mlir::success();
+}
+
//===----------------------------------------------------------------------===//
// VecCreateOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
index c8e06fed50cf9..fbd2403c8a2b9 100644
--- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -57,8 +57,9 @@ 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::BaseDataMemberOp, cir::CastOp, cir::CmpOp,
- cir::ConstantOp, cir::DerivedDataMemberOp, cir::FuncOp,
+ if (llvm::isa<cir::AllocaOp, cir::BaseDataMemberOp, cir::BaseMethodOp,
+ cir::CastOp, cir::CmpOp, cir::ConstantOp,
+ cir::DerivedDataMemberOp, cir::DerivedMethodOp, cir::FuncOp,
cir::GetMethodOp, cir::GetRuntimeMemberOp, cir::GlobalOp>(op))
return mlir::failure();
@@ -285,6 +286,15 @@ mlir::LogicalResult CIRBaseDataMemberOpABILowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRBaseMethodOpABILowering::matchAndRewrite(
+ cir::BaseMethodOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Value loweredResult =
+ lowerModule->getCXXABI().lowerBaseMethod(op, adaptor.getSrc(), rewriter);
+ rewriter.replaceOp(op, loweredResult);
+ return mlir::success();
+}
+
mlir::LogicalResult CIRDerivedDataMemberOpABILowering::matchAndRewrite(
cir::DerivedDataMemberOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -294,6 +304,15 @@ mlir::LogicalResult CIRDerivedDataMemberOpABILowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRDerivedMethodOpABILowering::matchAndRewrite(
+ cir::DerivedMethodOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Value loweredResult = lowerModule->getCXXABI().lowerDerivedMethod(
+ op, adaptor.getSrc(), rewriter);
+ rewriter.replaceOp(op, loweredResult);
+ return mlir::success();
+}
+
mlir::LogicalResult CIRDynamicCastOpABILowering::matchAndRewrite(
cir::DynamicCastOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
index 108e56a107738..5be66b4bff40f 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
@@ -86,6 +86,18 @@ class CIRCXXABI {
lowerDerivedDataMember(cir::DerivedDataMemberOp op, mlir::Value loweredSrc,
mlir::OpBuilder &builder) const = 0;
+ /// Lower the given cir.base_method op to a sequence of more "primitive" CIR
+ /// operations that act on the ABI types.
+ virtual mlir::Value lowerBaseMethod(cir::BaseMethodOp op,
+ mlir::Value loweredSrc,
+ mlir::OpBuilder &builder) const = 0;
+
+ /// Lower the given cir.derived_method op to a sequence of more "primitive"
+ /// CIR operations that act on the ABI types.
+ virtual mlir::Value lowerDerivedMethod(cir::DerivedMethodOp op,
+ mlir::Value loweredSrc,
+ mlir::OpBuilder &builder) const = 0;
+
virtual mlir::Value lowerDataMemberCmp(cir::CmpOp op, mlir::Value loweredLhs,
mlir::Value loweredRhs,
mlir::OpBuilder &builder) const = 0;
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
index 10996e6b5fe29..50c481192f16b 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
@@ -74,6 +74,13 @@ class LowerItaniumCXXABI : public CIRCXXABI {
mlir::Value loweredSrc,
mlir::OpBuilder &builder) const override;
+ mlir::Value lowerBaseMethod(cir::BaseMethodOp op, mlir::Value loweredSrc,
+ mlir::OpBuilder &builder) const override;
+
+ mlir::Value lowerDerivedMethod(cir::DerivedMethodOp op,
+ mlir::Value loweredSrc,
+ mlir::OpBuilder &builder) const override;
+
mlir::Value lowerDataMemberCmp(cir::CmpOp op, mlir::Value loweredLhs,
mlir::Value loweredRhs,
mlir::OpBuilder &builder) const override;
@@ -435,6 +442,44 @@ LowerItaniumCXXABI::lowerDerivedDataMember(cir::DerivedDataMemberOp op,
/*isDerivedToBase=*/false, builder);
}
+static mlir::Value lowerMethodCast(mlir::Operation *op, mlir::Value loweredSrc,
+ std::int64_t offset, bool isDerivedToBase,
+ LowerModule &lowerMod,
+ mlir::OpBuilder &builder) {
+ if (offset == 0)
+ return loweredSrc;
+
+ cir::IntType ptrdiffCIRTy = getPtrDiffCIRTy(lowerMod);
+ auto adjField = cir::ExtractMemberOp::create(builder, op->getLoc(),
+ ptrdiffCIRTy, loweredSrc, 1);
+
+ auto offsetValue = cir::ConstantOp::create(
+ builder, op->getLoc(), cir::IntAttr::get(ptrdiffCIRTy, offset));
+ auto binOpKind = isDerivedToBase ? cir::BinOpKind::Sub : cir::BinOpKind::Add;
+ auto adjustedAdjField = cir::BinOp::create(
+ builder, op->getLoc(), ptrdiffCIRTy, binOpKind, adjField, offsetValue);
+ adjustedAdjField.setNoSignedWrap(true);
+
+ return cir::InsertMemberOp::create(builder, op->getLoc(), loweredSrc, 1,
+ adjustedAdjField);
+}
+
+mlir::Value
+LowerItaniumCXXABI::lowerBaseMethod(cir::BaseMethodOp op,
+ mlir::Value loweredSrc,
+ mlir::OpBuilder &builder) const {
+ return lowerMethodCast(op, loweredSrc, op.getOffset().getSExtValue(),
+ /*isDerivedToBase=*/true, lm, builder);
+}
+
+mlir::Value
+LowerItaniumCXXABI::lowerDerivedMethod(cir::DerivedMethodOp op,
+ mlir::Value loweredSrc,
+ mlir::OpBuilder &builder) const {
+ return lowerMethodCast(op, loweredSrc, op.getOffset().getSExtValue(),
+ /*isDerivedToBase=*/false, lm, builder);
+}
+
mlir::Value
LowerItaniumCXXABI::lowerDataMemberCmp(cir::CmpOp op, mlir::Value loweredLhs,
mlir::Value loweredRhs,
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index a774b0dcc6ba8..7ec6fce934530 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -3335,6 +3335,24 @@ mlir::LogicalResult CIRToLLVMExtractMemberOpLowering::matchAndRewrite(
llvm_unreachable("Unexpected record kind");
}
+mlir::LogicalResult CIRToLLVMInsertMemberOpLowering::matchAndRewrite(
+ cir::InsertMemberOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ std::int64_t indecies[1] = {static_cast<std::int64_t>(op.getIndex())};
+ mlir::Type recordTy = op.getRecord().getType();
+
+ if (auto cirRecordTy = mlir::dyn_cast<cir::RecordType>(recordTy)) {
+ if (cirRecordTy.getKind() == cir::RecordType::Union) {
+ op.emitError("cir.update_member cannot update member of a union");
+ return mlir::failure();
+ }
+ }
+
+ rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
+ op, adaptor.getRecord(), adaptor.getValue(), indecies);
+ 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-member-func-cast.cpp b/clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp
index 4f18a6a6a9540..1abb5241f8af9 100644
--- a/clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp
+++ b/clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp
@@ -69,3 +69,143 @@ auto memfunc_reinterpret(void (Foo::*func)(int)) -> void (Bar::*)() {
// OGCG: store { i64, i64 } %[[FUNC]], ptr %[[RET_ADDR:.*]]
// OGCG: %[[RET:.*]] = load { i64, i64 }, ptr %[[RET_ADDR]]
// OGCG: ret { i64, i64 } %[[RET]]
+
+struct Base1 {
+ int x;
+ virtual void m1(int);
+};
+
+struct Base2 {
+ int y;
+ virtual void m2(int);
+};
+
+struct Derived : Base1, Base2 {
+ virtual void m3(int);
+};
+
+using Base1MemFunc = void (Base1::*)(int);
+using Base2MemFunc = void (Base2::*)(int);
+using DerivedMemFunc = void (Derived::*)(int);
+
+DerivedMemFunc base_to_derived_zero_offset(Base1MemFunc ptr) {
+ return static_cast<DerivedMemFunc>(ptr);
+}
+
+// CIR-BEFORE: cir.func {{.*}} @_Z27base_to_derived_zero_offsetM5Base1FviE
+// CIR-BEFORE: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.method<!cir.func<(!s32i)> in !rec_Base1>>, !cir.method<!cir.func<(!s32i)> in !rec_Base1>
+// CIR-BEFORE: %{{.*}} = cir.derived_method %[[PTR]][0] : !cir.method<!cir.func<(!s32i)> in !rec_Base1> -> !cir.method<!cir.func<(!s32i)> in !rec_Derived>
+
+// CIR-AFTER: cir.func {{.*}} @_Z27base_to_derived_zero_offsetM5Base1FviE
+// CIR-AFTER: %[[PTR:.*]] = cir.alloca !rec_anon_struct, !cir.ptr<!rec_anon_struct>, ["ptr", init]
+// CIR-AFTER: %[[RET:.*]] = cir.alloca !rec_anon_struct, !cir.ptr<!rec_anon_struct>, ["__retval"]
+// CIR-AFTER: cir.store %{{.*}}, %[[PTR]] : !rec_anon_struct, !cir.ptr<!rec_anon_struct>
+// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %[[PTR]] : !cir.ptr<!rec_anon_struct>, !rec_anon_struct
+// CIR-AFTER: cir.store %[[TMP]], %[[RET]] : !rec_anon_struct, !cir.ptr<!rec_anon_struct>
+// CIR-AFTER: %[[RET_VAL:.*]] = cir.load %[[RET]] : !cir.ptr<!rec_anon_struct>, !rec_anon_struct
+// CIR-AFTER: cir.return %[[RET_VAL]] : !rec_anon_struct
+
+// LLVM: define {{.*}} { i64, i64 } @_Z27base_to_derived_zero_offsetM5Base1FviE
+// LLVM: %[[ARG_ADDR:.*]] = alloca { i64, i64 }
+// LLVM: %[[RET_ADDR:.*]] = alloca { i64, i64 }
+// LLVM: store { i64, i64 } %{{.*}}, ptr %[[ARG_ADDR]]
+// LLVM: %[[TMP:.*]] = load { i64, i64 }, ptr %[[ARG_ADDR]]
+// LLVM: store { i64, i64 } %[[TMP]], ptr %[[RET_ADDR]]
+// LLVM: %[[RET:.*]] = load { i64, i64 }, ptr %[[RET_ADDR]]
+// LLVM: ret { i64, i64 } %[[RET]]
+
+// OGCG: define {{.*}} { i64, i64 } @_Z27base_to_derived_zero_offsetM5Base1FviE
+// OGCG: %[[ARG_ADDR:.*]] = alloca { i64, i64 }
+// OGCG: store { i64, i64 } %{{.*}}, ptr %[[ARG_ADDR]]
+// OGCG: %[[RET:.*]] = load { i64, i64 }, ptr %[[ARG_ADDR]]
+// OGCG: ret { i64, i64 } %[[RET]]
+
+DerivedMemFunc base_to_derived(Base2MemFunc ptr) {
+ return static_cast<DerivedMemFunc>(ptr);
+}
+
+// CIR-BEFORE: cir.func {{.*}} @_Z15base_to_derivedM5Base2FviE
+// CIR-BEFORE: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.method<!cir.func<(!s32i)> in !rec_Base2>>, !cir.method<!cir.func<(!s32i)> in !rec_Base2>
+// CIR-BEFORE: %{{.*}} = cir.derived_method %[[PTR]][16] : !cir.method<!cir.func<(!s32i)> in !rec_Base2> -> !cir.method<!cir.func<(!s32i)> in !rec_Derived>
+
+// CIR-AFTER: cir.func {{.*}} @_Z15base_to_derivedM5Base2FviE
+// CIR-AFTER: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!rec_anon_struct>, !rec_anon_struct
+// CIR-AFTER: %[[OFFSET:.*]] = cir.extract_member %[[PTR]][1] : !rec_anon_struct -> !s64i
+// CIR-AFTER: %[[OFFSET_ADJ:.*]] = cir.const #cir.int<16> : !s64i
+// CIR-AFTER: %[[BINOP_KIND:.*]] = cir.binop(add, %[[OFFSET]], %[[OFFSET_ADJ]]) nsw : !s64i
+// CIR-AFTER: %{{.*}} = cir.insert_member %[[PTR]][1], %[[BINOP_KIND]] : !rec_anon_struct, !s64i
+
+// LLVM: define {{.*}} { i64, i64 } @_Z15base_to_derivedM5Base2FviE
+// LLVM: %[[ARG:.*]] = load { i64, i64 }, ptr %{{.*}}
+// LLVM: %[[ADJ:.*]] = extractvalue { i64, i64 } %[[ARG]], 1
+// LLVM: %[[ADJ_ADJ:.*]] = add nsw i64 %[[ADJ]], 16
+// LLVM: %{{.*}} = insertvalue { i64, i64 } %[[ARG]], i64 %[[ADJ_ADJ]], 1
+
+// ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/178004
More information about the cfe-commits
mailing list