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

Reply via email to