Author: Andy Kaylor Date: 2025-12-11T10:19:00-08:00 New Revision: 4c21e460ed39925bf5bc2e24ed90de004241b8e3
URL: https://github.com/llvm/llvm-project/commit/4c21e460ed39925bf5bc2e24ed90de004241b8e3 DIFF: https://github.com/llvm/llvm-project/commit/4c21e460ed39925bf5bc2e24ed90de004241b8e3.diff LOG: [CIR] Add support for runtime data member pointer access (#171510) This adds support for a CIR operation to represent runtime data member access. Added: Modified: clang/include/clang/CIR/Dialect/IR/CIROps.td clang/lib/CIR/CodeGen/CIRGenBuilder.h clang/lib/CIR/CodeGen/CIRGenClass.cpp clang/lib/CIR/CodeGen/CIRGenExpr.cpp clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp clang/lib/CIR/CodeGen/CIRGenFunction.h clang/lib/CIR/Dialect/IR/CIRDialect.cpp clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp clang/test/CIR/CodeGen/pointer-to-data-member.cpp clang/test/CIR/IR/invalid-data-member.cir Removed: ################################################################################ diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index c6ef95a28c586..4922f83df0efb 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3559,6 +3559,63 @@ def CIR_ArrayDtor : CIR_ArrayInitDestroy<"array.dtor"> { }]; } +//===----------------------------------------------------------------------===// +// GetRuntimeMemberOp +//===----------------------------------------------------------------------===// + +def CIR_GetRuntimeMemberOp : CIR_Op<"get_runtime_member"> { + let summary = "Get the address of a member of a record"; + let description = [{ + The `cir.get_runtime_member` operation gets the address of a member from + the input record. The target member is given by a value of type + `!cir.data_member` (i.e. a pointer-to-data-member value). + + This operation diff ers from `cir.get_member` in when the target member can + be determined. For the `cir.get_member` operation, the target member is + specified as a constant index so the member it returns access to is known + when the operation is constructed. For the `cir.get_runtime_member` + operation, the target member is given through a pointer-to-data-member + value which is unknown until the program being compiled is executed. In + other words, `cir.get_member` represents a normal member access through the + `.` operator in C/C++: + + ```cpp + struct Foo { int x; }; + Foo f; + (void)f.x; // cir.get_member + ``` + + And `cir.get_runtime_member` represents a member access through the `.*` or + the `->*` operator in C++: + + ```cpp + struct Foo { int x; } + Foo f; + Foo *p; + int Foo::*member; + + (void)f.*member; // cir.get_runtime_member + (void)p->*member; // cir.get_runtime_member + ``` + + This operation expects a pointer to the base record as well as the pointer + to the target member. + }]; + + let arguments = (ins + Arg<CIR_PtrToRecordType, "address of the record object", [MemRead]>:$addr, + Arg<CIR_DataMemberType, "pointer to the target member">:$member); + + let results = (outs Res<CIR_PointerType, "">:$result); + + let assemblyFormat = [{ + $addr `[` $member `:` qualified(type($member)) `]` attr-dict + `:` qualified(type($addr)) `->` qualified(type($result)) + }]; + + let hasVerifier = 1; +} + //===----------------------------------------------------------------------===// // VecCreate //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index a9f7fe1386fa0..5b10bddd054ea 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -529,6 +529,19 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { addr.getAlignment()}; } + cir::GetRuntimeMemberOp createGetIndirectMember(mlir::Location loc, + mlir::Value objectPtr, + mlir::Value memberPtr) { + auto memberPtrTy = mlir::cast<cir::DataMemberType>(memberPtr.getType()); + + // TODO(cir): consider address space. + assert(!cir::MissingFeatures::addressSpace()); + cir::PointerType resultTy = getPointerTo(memberPtrTy.getMemberTy()); + + return cir::GetRuntimeMemberOp::create(*this, loc, resultTy, objectPtr, + memberPtr); + } + /// Create a cir.ptr_stride operation to get access to an array element. /// \p idx is the index of the element to access, \p shouldDecay is true if /// the result should decay to a pointer to the element type. diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index 2a26e38bb214d..3ab3be3706205 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -584,6 +584,25 @@ void CIRGenFunction::emitInitializerForField(FieldDecl *field, LValue lhs, assert(!cir::MissingFeatures::requiresCleanups()); } +Address CIRGenFunction::emitCXXMemberDataPointerAddress( + const Expr *e, Address base, mlir::Value memberPtr, + const MemberPointerType *memberPtrType, LValueBaseInfo *baseInfo) { + assert(!cir::MissingFeatures::cxxABI()); + + cir::GetRuntimeMemberOp op = builder.createGetIndirectMember( + getLoc(e->getSourceRange()), base.getPointer(), memberPtr); + + QualType memberType = memberPtrType->getPointeeType(); + assert(!cir::MissingFeatures::opTBAA()); + CharUnits memberAlign = cgm.getNaturalTypeAlignment(memberType, baseInfo); + memberAlign = cgm.getDynamicOffsetAlignment( + base.getAlignment(), memberPtrType->getMostRecentCXXRecordDecl(), + memberAlign); + + return Address(op, convertTypeForMem(memberPtrType->getPointeeType()), + memberAlign); +} + CharUnits CIRGenModule::getDynamicOffsetAlignment(CharUnits actualBaseAlign, const CXXRecordDecl *baseDecl, diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index cac046c41e30d..1d386f43fc8f4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -683,6 +683,29 @@ RValue CIRGenFunction::emitLoadOfExtVectorElementLValue(LValue lv) { return RValue::get(resultVec); } +LValue +CIRGenFunction::emitPointerToDataMemberBinaryExpr(const BinaryOperator *e) { + assert((e->getOpcode() == BO_PtrMemD || e->getOpcode() == BO_PtrMemI) && + "unexpected binary operator opcode"); + + Address baseAddr = Address::invalid(); + if (e->getOpcode() == BO_PtrMemD) + baseAddr = emitLValue(e->getLHS()).getAddress(); + else + baseAddr = emitPointerWithAlignment(e->getLHS()); + + const auto *memberPtrTy = e->getRHS()->getType()->castAs<MemberPointerType>(); + + mlir::Value memberPtr = emitScalarExpr(e->getRHS()); + + LValueBaseInfo baseInfo; + assert(!cir::MissingFeatures::opTBAA()); + Address memberAddr = emitCXXMemberDataPointerAddress(e, baseAddr, memberPtr, + memberPtrTy, &baseInfo); + + return makeAddrLValue(memberAddr, memberPtrTy->getPointeeType(), baseInfo); +} + /// Generates lvalue for partial ext_vector access. Address CIRGenFunction::emitExtVectorElementLValue(LValue lv, mlir::Location loc) { @@ -1762,10 +1785,8 @@ LValue CIRGenFunction::emitBinaryOperatorLValue(const BinaryOperator *e) { return emitLValue(e->getRHS()); } - if (e->getOpcode() == BO_PtrMemD || e->getOpcode() == BO_PtrMemI) { - cgm.errorNYI(e->getSourceRange(), "member pointers"); - return {}; - } + if (e->getOpcode() == BO_PtrMemD || e->getOpcode() == BO_PtrMemI) + return emitPointerToDataMemberBinaryExpr(e); assert(e->getOpcode() == BO_Assign && "unexpected binary l-value"); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 3887433e5e181..3b5ed225a58d6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1338,13 +1338,11 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> { } mlir::Value VisitBinPtrMemD(const BinaryOperator *e) { - cgf.cgm.errorNYI(e->getSourceRange(), "ScalarExprEmitter: ptr mem d"); - return {}; + return emitLoadOfLValue(e); } mlir::Value VisitBinPtrMemI(const BinaryOperator *e) { - cgf.cgm.errorNYI(e->getSourceRange(), "ScalarExprEmitter: ptr mem i"); - return {}; + return emitLoadOfLValue(e); } // Other Operators. diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index efe0fe5fcc979..90a3c6233d892 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1514,6 +1514,10 @@ class CIRGenFunction : public CIRGenTypeCache { RValue emitCXXMemberCallExpr(const clang::CXXMemberCallExpr *e, ReturnValueSlot returnValue); + Address emitCXXMemberDataPointerAddress( + const Expr *e, Address base, mlir::Value memberPtr, + const MemberPointerType *memberPtrType, LValueBaseInfo *baseInfo); + RValue emitCXXMemberOrOperatorCall( const clang::CXXMethodDecl *md, const CIRGenCallee &callee, ReturnValueSlot returnValue, mlir::Value thisPtr, @@ -1696,6 +1700,8 @@ class CIRGenFunction : public CIRGenTypeCache { mlir::Value emitOpOnBoolExpr(mlir::Location loc, const clang::Expr *cond); + LValue emitPointerToDataMemberBinaryExpr(const BinaryOperator *e); + mlir::LogicalResult emitLabel(const clang::LabelDecl &d); mlir::LogicalResult emitLabelStmt(const clang::LabelStmt &s); diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index d888fdcf081e7..ffe93c5b4124b 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2485,6 +2485,21 @@ LogicalResult cir::CopyOp::verify() { return mlir::success(); } +//===----------------------------------------------------------------------===// +// GetRuntimeMemberOp Definitions +//===----------------------------------------------------------------------===// + +LogicalResult cir::GetRuntimeMemberOp::verify() { + auto recordTy = mlir::cast<RecordType>(getAddr().getType().getPointee()); + cir::DataMemberType memberPtrTy = getMember().getType(); + + if (recordTy != memberPtrTy.getClassTy()) + return emitError() << "record type does not match the member pointer type"; + if (getType().getPointee() != memberPtrTy.getMemberTy()) + return emitError() << "result type does not match the member pointer type"; + return mlir::success(); +} + //===----------------------------------------------------------------------===// // GetMemberOp Definitions //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h index 003cd78eb3f26..90f0ac3478f9d 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h @@ -15,6 +15,7 @@ #define CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_CIRCXXABI_H #include "mlir/Transforms/DialectConversion.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" namespace cir { @@ -45,6 +46,13 @@ class CIRCXXABI { lowerDataMemberConstant(cir::DataMemberAttr attr, const mlir::DataLayout &layout, const mlir::TypeConverter &typeConverter) const = 0; + + /// Lower the given cir.get_runtime_member op to a sequence of more + /// "primitive" CIR operations that act on the ABI types. + virtual mlir::Operation * + lowerGetRuntimeMember(cir::GetRuntimeMemberOp op, mlir::Type loweredResultTy, + mlir::Value loweredAddr, mlir::Value loweredMember, + mlir::OpBuilder &builder) const = 0; }; /// Creates an Itanium-family ABI. diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp index 7089990343dc0..ce4b0c7e92d09 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp @@ -42,6 +42,11 @@ class LowerItaniumCXXABI : public CIRCXXABI { mlir::TypedAttr lowerDataMemberConstant( cir::DataMemberAttr attr, const mlir::DataLayout &layout, const mlir::TypeConverter &typeConverter) const override; + + mlir::Operation * + lowerGetRuntimeMember(cir::GetRuntimeMemberOp op, mlir::Type loweredResultTy, + mlir::Value loweredAddr, mlir::Value loweredMember, + mlir::OpBuilder &builder) const override; }; } // namespace @@ -87,4 +92,20 @@ mlir::TypedAttr LowerItaniumCXXABI::lowerDataMemberConstant( return cir::IntAttr::get(abiTy, memberOffset); } +mlir::Operation *LowerItaniumCXXABI::lowerGetRuntimeMember( + cir::GetRuntimeMemberOp op, mlir::Type loweredResultTy, + mlir::Value loweredAddr, mlir::Value loweredMember, + mlir::OpBuilder &builder) const { + auto byteTy = cir::IntType::get(op.getContext(), 8, true); + auto bytePtrTy = cir::PointerType::get( + byteTy, + mlir::cast<cir::PointerType>(op.getAddr().getType()).getAddrSpace()); + auto objectBytesPtr = cir::CastOp::create( + builder, op.getLoc(), bytePtrTy, cir::CastKind::bitcast, op.getAddr()); + auto memberBytesPtr = cir::PtrStrideOp::create( + builder, op.getLoc(), bytePtrTy, objectBytesPtr, loweredMember); + return cir::CastOp::create(builder, op.getLoc(), op.getType(), + cir::CastKind::bitcast, memberBytesPtr); +} + } // namespace cir diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index f9d0b2c73abea..00307df62ce5a 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -3231,6 +3231,17 @@ 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 b116d21f01170..14d1befeed67f 100644 --- a/clang/test/CIR/CodeGen/pointer-to-data-member.cpp +++ b/clang/test/CIR/CodeGen/pointer-to-data-member.cpp @@ -30,3 +30,169 @@ auto test1() -> int Point::* { // OGCG: define {{.*}} i64 @_Z5test1v() // OGCG: ret i64 4 + +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]] + +// LLVM: define {{.*}} i32 @_Z5test2RK5PointMS_i(ptr %[[PT_ARG:.*]], i64 %[[MEMBER_ARG:.*]]) +// LLVM: %[[PT_ADDR:.*]] = alloca ptr +// LLVM: %[[MEMBER_ADDR:.*]] = alloca i64 +// LLVM: %[[RETVAL_ADDR:.*]] = alloca i32 +// LLVM: store ptr %[[PT_ARG]], ptr %[[PT_ADDR]] +// LLVM: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]] +// LLVM: %[[PT:.*]] = load ptr, ptr %[[PT_ADDR]] +// LLVM: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]] +// LLVM: %[[RT_MEMBER:.*]] = getelementptr i8, ptr %[[PT]], i64 %[[MEMBER]] +// LLVM: %[[VAL:.*]] = load i32, ptr %[[RT_MEMBER]] +// LLVM: store i32 %[[VAL]], ptr %[[RETVAL_ADDR]] +// LLVM: %[[RET:.*]] = load i32, ptr %[[RETVAL_ADDR]] +// LLVM: ret i32 %[[RET]] + +// OGCG: define {{.*}} i32 @_Z5test2RK5PointMS_i(ptr {{.*}} %[[PT_ARG:.*]], i64 %[[MEMBER_ARG:.*]]) +// OGCG: %[[PT_ADDR:.*]] = alloca ptr +// OGCG: %[[MEMBER_ADDR:.*]] = alloca i64 +// OGCG: store ptr %[[PT_ARG]], ptr %[[PT_ADDR]] +// OGCG: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]] +// OGCG: %[[PT:.*]] = load ptr, ptr %[[PT_ADDR]] +// OGCG: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]] +// OGCG: %[[RT_MEMBER:.*]] = getelementptr inbounds i8, ptr %[[PT]], i64 %[[MEMBER]] +// OGCG: %[[RET:.*]] = load i32, ptr %[[RT_MEMBER]] +// OGCG: ret i32 %[[RET]] + +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]] + +// LLVM: define {{.*}} i32 @_Z5test3PK5PointMS_i(ptr %[[PT_ARG:.*]], i64 %[[MEMBER_ARG:.*]]) +// LLVM: %[[PT_ADDR:.*]] = alloca ptr +// LLVM: %[[MEMBER_ADDR:.*]] = alloca i64 +// LLVM: %[[RETVAL_ADDR:.*]] = alloca i32 +// LLVM: store ptr %[[PT_ARG]], ptr %[[PT_ADDR]] +// LLVM: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]] +// LLVM: %[[PT:.*]] = load ptr, ptr %[[PT_ADDR]] +// LLVM: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]] +// LLVM: %[[RT_MEMBER:.*]] = getelementptr i8, ptr %[[PT]], i64 %[[MEMBER]] +// LLVM: %[[VAL:.*]] = load i32, ptr %[[RT_MEMBER]] +// LLVM: store i32 %[[VAL]], ptr %[[RETVAL_ADDR]] +// LLVM: %[[RET:.*]] = load i32, ptr %[[RETVAL_ADDR]] +// LLVM: ret i32 %[[RET]] + +// OGCG: define {{.*}} i32 @_Z5test3PK5PointMS_i(ptr {{.*}} %[[PT_ARG:.*]], i64 %[[MEMBER_ARG:.*]]) +// OGCG: %[[PT_ADDR:.*]] = alloca ptr +// OGCG: %[[MEMBER_ADDR:.*]] = alloca i64 +// OGCG: store ptr %[[PT_ARG]], ptr %[[PT_ADDR]] +// OGCG: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]] +// OGCG: %[[PT:.*]] = load ptr, ptr %[[PT_ADDR]] +// OGCG: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]] +// OGCG: %[[RT_MEMBER:.*]] = getelementptr inbounds i8, ptr %[[PT]], i64 %[[MEMBER]] +// OGCG: %[[RET:.*]] = load i32, ptr %[[RT_MEMBER]] +// OGCG: ret i32 %[[RET]] + +struct Incomplete; + +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]] + +// LLVM: define {{.*}} i64 @_Z5test4M10Incompletei(i64 %[[MEMBER_ARG:.*]]) +// LLVM: %[[MEMBER_ADDR:.*]] = alloca i64 +// LLVM: %[[RETVAL_ADDR:.*]] = alloca i64 +// LLVM: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]] +// LLVM: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]] +// LLVM: store i64 %[[MEMBER]], ptr %[[RETVAL_ADDR]] +// LLVM: %[[RET:.*]] = load i64, ptr %[[RETVAL_ADDR]] +// LLVM: ret i64 %[[RET]] + +// OGCG: define {{.*}} i64 @_Z5test4M10Incompletei(i64 %[[MEMBER_ARG:.*]]) +// OGCG: %[[MEMBER_ADDR:.*]] = alloca i64 +// OGCG: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]] +// OGCG: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]] +// OGCG: ret i64 %[[MEMBER]] + +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]] + +// LLVM: define {{.*}} i32 @_Z5test5P10IncompleteMS_i(ptr %[[IC_ARG:.*]], i64 %[[MEMBER_ARG:.*]]) +// LLVM: %[[IC_ADDR:.*]] = alloca ptr +// LLVM: %[[MEMBER_ADDR:.*]] = alloca i64 +// LLVM: %[[RETVAL_ADDR:.*]] = alloca i32 +// LLVM: store ptr %[[IC_ARG]], ptr %[[IC_ADDR]] +// LLVM: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]] +// LLVM: %[[IC:.*]] = load ptr, ptr %[[IC_ADDR]] +// LLVM: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]] +// LLVM: %[[RT_MEMBER:.*]] = getelementptr i8, ptr %[[IC]], i64 %[[MEMBER]] +// LLVM: %[[VAL:.*]] = load i32, ptr %[[RT_MEMBER]] +// LLVM: store i32 %[[VAL]], ptr %[[RETVAL_ADDR]] +// LLVM: %[[RET:.*]] = load i32, ptr %[[RETVAL_ADDR]] +// LLVM: ret i32 %[[RET]] + +// OGCG: define {{.*}} i32 @_Z5test5P10IncompleteMS_i(ptr {{.*}} %[[IC_ARG:.*]], i64 %[[MEMBER_ARG:.*]]) +// OGCG: %[[IC_ADDR:.*]] = alloca ptr +// OGCG: %[[MEMBER_ADDR:.*]] = alloca i64 +// OGCG: store ptr %[[IC_ARG]], ptr %[[IC_ADDR]] +// OGCG: store i64 %[[MEMBER_ARG]], ptr %[[MEMBER_ADDR]] +// OGCG: %[[IC:.*]] = load ptr, ptr %[[IC_ADDR]] +// OGCG: %[[MEMBER:.*]] = load i64, ptr %[[MEMBER_ADDR]] +// OGCG: %[[RT_MEMBER:.*]] = getelementptr inbounds i8, ptr %[[IC]], i64 %[[MEMBER]] +// OGCG: %[[RET:.*]] = load i32, ptr %[[RT_MEMBER]] +// OGCG: ret i32 %[[RET]] diff --git a/clang/test/CIR/IR/invalid-data-member.cir b/clang/test/CIR/IR/invalid-data-member.cir index 2941777404973..a8be435931a8f 100644 --- a/clang/test/CIR/IR/invalid-data-member.cir +++ b/clang/test/CIR/IR/invalid-data-member.cir @@ -25,3 +25,34 @@ // expected-error@+1 {{member index of a #cir.data_member attribute is out of range}} #invalid_member_ty = #cir.data_member<2> : !cir.data_member<!u32i in !struct1> + +// ----- + +!u16i = !cir.int<u, 16> +!u32i = !cir.int<u, 32> +!struct1 = !cir.record<struct "Struct1" {!u16i, !u32i}> +!struct2 = !cir.record<struct "Struct2" {!u16i, !u32i}> + +module { + cir.func @invalid_base_type(%arg0 : !cir.data_member<!u32i in !struct1>) { + %0 = cir.alloca !struct2, !cir.ptr<!struct2>, ["tmp"] {alignment = 4 : i64} + // expected-error@+1 {{record type does not match the member pointer type}} + %1 = cir.get_runtime_member %0[%arg0 : !cir.data_member<!u32i in !struct1>] : !cir.ptr<!struct2> -> !cir.ptr<!u32i> + cir.return + } +} + +// ----- + +!u16i = !cir.int<u, 16> +!u32i = !cir.int<u, 32> +!struct1 = !cir.record<struct "Struct1" {!u16i, !u32i}> + +module { + cir.func @invalid_base_type(%arg0 : !cir.data_member<!u32i in !struct1>) { + %0 = cir.alloca !struct1, !cir.ptr<!struct1>, ["tmp"] {alignment = 4 : i64} + // expected-error@+1 {{result type does not match the member pointer type}} + %1 = cir.get_runtime_member %0[%arg0 : !cir.data_member<!u32i in !struct1>] : !cir.ptr<!struct1> -> !cir.ptr<!u16i> + cir.return + } +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
