https://github.com/andykaylor created https://github.com/llvm/llvm-project/pull/178004
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 <[email protected]> >From 1fc2a334e5f01e279aba6bee6bffe3487353ff8a Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Mon, 26 Jan 2026 09:55:57 -0800 Subject: [PATCH] [CIR] Upstream support for pointer-to-method casts 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. --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 121 +++++++++++++++ clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 7 +- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 28 ++++ .../CIR/Dialect/Transforms/CXXABILowering.cpp | 23 ++- .../Transforms/TargetLowering/CIRCXXABI.h | 12 ++ .../TargetLowering/LowerItaniumCXXABI.cpp | 45 ++++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 18 +++ .../CodeGen/pointer-to-member-func-cast.cpp | 140 ++++++++++++++++++ clang/test/CIR/IR/invalid-struct.cir | 47 ++++++ 9 files changed, 436 insertions(+), 5 deletions(-) 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 + +// OGCG: define {{.*}} { i64, i64 } @_Z15base_to_derivedM5Base2FviE +// OGCG: %[[ARG:.*]] = load { i64, i64 }, ptr %{{.*}} +// OGCG: store { i64, i64 } %[[ARG]], ptr %[[ARG_ADDR:.*]] +// OGCG: %[[ARG1:.*]] = load { i64, i64 }, ptr %[[ARG_ADDR]] +// OGCG: %[[ADJ:.*]] = extractvalue { i64, i64 } %[[ARG1]], 1 +// OGCG: %[[ADJ_ADJ:.*]] = add nsw i64 %[[ADJ]], 16 +// OGCG: %{{.*}} = insertvalue { i64, i64 } %[[ARG1]], i64 %[[ADJ_ADJ]], 1 + +Base1MemFunc derived_to_base_zero_offset(DerivedMemFunc ptr) { + return static_cast<Base1MemFunc>(ptr); +} + +// CIR-BEFORE: cir.func {{.*}} @_Z27derived_to_base_zero_offsetM7DerivedFviE +// CIR-BEFORE: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.method<!cir.func<(!s32i)> in !rec_Derived>>, !cir.method<!cir.func<(!s32i)> in !rec_Derived> +// CIR-BEFORE: %{{.*}} = cir.base_method %[[PTR]][0] : !cir.method<!cir.func<(!s32i)> in !rec_Derived> -> !cir.method<!cir.func<(!s32i)> in !rec_Base1> + +// CIR-AFTER: cir.func {{.*}} @_Z27derived_to_base_zero_offsetM7DerivedFviE +// 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 } @_Z27derived_to_base_zero_offsetM7DerivedFviE +// 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 } @_Z27derived_to_base_zero_offsetM7DerivedFviE +// 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]] + +Base2MemFunc derived_to_base(DerivedMemFunc ptr) { + return static_cast<Base2MemFunc>(ptr); +} + +// CIR-BEFORE: cir.func {{.*}} @_Z15derived_to_baseM7DerivedFviE +// CIR-BEFORE: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.method<!cir.func<(!s32i)> in !rec_Derived>>, !cir.method<!cir.func<(!s32i)> in !rec_Derived> +// CIR-BEFORE: %{{.*}} = cir.base_method %[[PTR]][16] : !cir.method<!cir.func<(!s32i)> in !rec_Derived> -> !cir.method<!cir.func<(!s32i)> in !rec_Base2> + +// CIR-AFTER: cir.func {{.*}} @_Z15derived_to_baseM7DerivedFviE +// 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(sub, %[[OFFSET]], %[[OFFSET_ADJ]]) nsw : !s64i +// CIR-AFTER: %{{.*}} = cir.insert_member %[[PTR]][1], %[[BINOP_KIND]] : !rec_anon_struct, !s64i + +// LLVM: define {{.*}} { i64, i64 } @_Z15derived_to_baseM7DerivedFviE +// LLVM: %[[ARG:.*]] = load { i64, i64 }, ptr %{{.*}} +// LLVM: %[[ADJ:.*]] = extractvalue { i64, i64 } %[[ARG]], 1 +// LLVM: %[[ADJ_ADJ:.*]] = sub nsw i64 %[[ADJ]], 16 +// LLVM: %{{.*}} = insertvalue { i64, i64 } %[[ARG]], i64 %[[ADJ_ADJ]], 1 + +// OGCG: define {{.*}} { i64, i64 } @_Z15derived_to_baseM7DerivedFviE +// OGCG: %[[ARG:.*]] = load { i64, i64 }, ptr %{{.*}} +// OGCG: store { i64, i64 } %[[ARG]], ptr %[[ARG_ADDR:.*]] +// OGCG: %[[ARG1:.*]] = load { i64, i64 }, ptr %[[ARG_ADDR]] +// OGCG: %[[ADJ:.*]] = extractvalue { i64, i64 } %[[ARG1]], 1 +// OGCG: %[[ADJ_ADJ:.*]] = sub nsw i64 %[[ADJ]], 16 +// OGCG: %{{.*}} = insertvalue { i64, i64 } %[[ARG1]], i64 %[[ADJ_ADJ]], 1 diff --git a/clang/test/CIR/IR/invalid-struct.cir b/clang/test/CIR/IR/invalid-struct.cir index 99a3969df9982..63260cf3584e0 100644 --- a/clang/test/CIR/IR/invalid-struct.cir +++ b/clang/test/CIR/IR/invalid-struct.cir @@ -41,3 +41,50 @@ module { cir.return } } + +// ----- + +!u8i = !cir.int<u, 8> +!u32i = !cir.int<u, 32> +!rec_S = !cir.record<struct "S" {!u8i, !u32i}> + +module { + cir.func @struct_insert_member_invalid_element_type() { + %0 = cir.const #cir.const_record<{#cir.int<1> : !u8i, #cir.int<3> : !u32i}> : !rec_S + %1 = cir.const #cir.int<3> : !u8i + // expected-error @below {{member type mismatch}} + %2 = cir.insert_member %0[1], %1 : !rec_S, !u8i + cir.return + } +} + +// ----- + +!u8i = !cir.int<u, 8> +!u32i = !cir.int<u, 32> +!rec_S = !cir.record<struct "S" {!u8i, !u32i}> + +module { + cir.func @struct_extract_member_invalid_index_value() { + %0 = cir.const #cir.const_record<{#cir.int<1> : !u8i, #cir.int<3> : !u32i}> : !rec_S + %1 = cir.const #cir.int<3> : !u8i + // expected-error @below {{member index out of bounds}} + %2 = cir.insert_member %0[2], %1 : !rec_S, !u8i + cir.return + } +} + +// ----- + +!u32i = !cir.int<u, 32> +!rec_U = !cir.record<union "U" {!u32i}> + +module { + cir.func @extract_member_invalid_for_union() { + %0 = cir.const #cir.const_record<{#cir.int<1> : !u32i}> : !rec_U + %1 = cir.const #cir.int<3> : !u32i + // expected-error @below {{cir.insert_member currently does not support unions}} + %2 = cir.insert_member %0[1], %1 : !rec_U, !u32i + cir.return + } +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
