Skip to content

Commit 4c21e46

Browse files
authored
[CIR] Add support for runtime data member pointer access (#171510)
This adds support for a CIR operation to represent runtime data member access.
1 parent e4c83b7 commit 4c21e46

File tree

12 files changed

+374
-8
lines changed

12 files changed

+374
-8
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3559,6 +3559,63 @@ def CIR_ArrayDtor : CIR_ArrayInitDestroy<"array.dtor"> {
35593559
}];
35603560
}
35613561

3562+
//===----------------------------------------------------------------------===//
3563+
// GetRuntimeMemberOp
3564+
//===----------------------------------------------------------------------===//
3565+
3566+
def CIR_GetRuntimeMemberOp : CIR_Op<"get_runtime_member"> {
3567+
let summary = "Get the address of a member of a record";
3568+
let description = [{
3569+
The `cir.get_runtime_member` operation gets the address of a member from
3570+
the input record. The target member is given by a value of type
3571+
`!cir.data_member` (i.e. a pointer-to-data-member value).
3572+
3573+
This operation differs from `cir.get_member` in when the target member can
3574+
be determined. For the `cir.get_member` operation, the target member is
3575+
specified as a constant index so the member it returns access to is known
3576+
when the operation is constructed. For the `cir.get_runtime_member`
3577+
operation, the target member is given through a pointer-to-data-member
3578+
value which is unknown until the program being compiled is executed. In
3579+
other words, `cir.get_member` represents a normal member access through the
3580+
`.` operator in C/C++:
3581+
3582+
```cpp
3583+
struct Foo { int x; };
3584+
Foo f;
3585+
(void)f.x; // cir.get_member
3586+
```
3587+
3588+
And `cir.get_runtime_member` represents a member access through the `.*` or
3589+
the `->*` operator in C++:
3590+
3591+
```cpp
3592+
struct Foo { int x; }
3593+
Foo f;
3594+
Foo *p;
3595+
int Foo::*member;
3596+
3597+
(void)f.*member; // cir.get_runtime_member
3598+
(void)p->*member; // cir.get_runtime_member
3599+
```
3600+
3601+
This operation expects a pointer to the base record as well as the pointer
3602+
to the target member.
3603+
}];
3604+
3605+
let arguments = (ins
3606+
Arg<CIR_PtrToRecordType, "address of the record object", [MemRead]>:$addr,
3607+
Arg<CIR_DataMemberType, "pointer to the target member">:$member);
3608+
3609+
let results = (outs Res<CIR_PointerType, "">:$result);
3610+
3611+
let assemblyFormat = [{
3612+
$addr `[` $member `:` qualified(type($member)) `]` attr-dict
3613+
`:` qualified(type($addr)) `->` qualified(type($result))
3614+
}];
3615+
3616+
let hasVerifier = 1;
3617+
}
3618+
35623619
//===----------------------------------------------------------------------===//
35633620
// VecCreate
35643621
//===----------------------------------------------------------------------===//

clang/lib/CIR/CodeGen/CIRGenBuilder.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,19 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
529529
addr.getAlignment()};
530530
}
531531

532+
cir::GetRuntimeMemberOp createGetIndirectMember(mlir::Location loc,
533+
mlir::Value objectPtr,
534+
mlir::Value memberPtr) {
535+
auto memberPtrTy = mlir::cast<cir::DataMemberType>(memberPtr.getType());
536+
537+
// TODO(cir): consider address space.
538+
assert(!cir::MissingFeatures::addressSpace());
539+
cir::PointerType resultTy = getPointerTo(memberPtrTy.getMemberTy());
540+
541+
return cir::GetRuntimeMemberOp::create(*this, loc, resultTy, objectPtr,
542+
memberPtr);
543+
}
544+
532545
/// Create a cir.ptr_stride operation to get access to an array element.
533546
/// \p idx is the index of the element to access, \p shouldDecay is true if
534547
/// the result should decay to a pointer to the element type.

clang/lib/CIR/CodeGen/CIRGenClass.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,25 @@ void CIRGenFunction::emitInitializerForField(FieldDecl *field, LValue lhs,
584584
assert(!cir::MissingFeatures::requiresCleanups());
585585
}
586586

587+
Address CIRGenFunction::emitCXXMemberDataPointerAddress(
588+
const Expr *e, Address base, mlir::Value memberPtr,
589+
const MemberPointerType *memberPtrType, LValueBaseInfo *baseInfo) {
590+
assert(!cir::MissingFeatures::cxxABI());
591+
592+
cir::GetRuntimeMemberOp op = builder.createGetIndirectMember(
593+
getLoc(e->getSourceRange()), base.getPointer(), memberPtr);
594+
595+
QualType memberType = memberPtrType->getPointeeType();
596+
assert(!cir::MissingFeatures::opTBAA());
597+
CharUnits memberAlign = cgm.getNaturalTypeAlignment(memberType, baseInfo);
598+
memberAlign = cgm.getDynamicOffsetAlignment(
599+
base.getAlignment(), memberPtrType->getMostRecentCXXRecordDecl(),
600+
memberAlign);
601+
602+
return Address(op, convertTypeForMem(memberPtrType->getPointeeType()),
603+
memberAlign);
604+
}
605+
587606
CharUnits
588607
CIRGenModule::getDynamicOffsetAlignment(CharUnits actualBaseAlign,
589608
const CXXRecordDecl *baseDecl,

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,29 @@ RValue CIRGenFunction::emitLoadOfExtVectorElementLValue(LValue lv) {
683683
return RValue::get(resultVec);
684684
}
685685

686+
LValue
687+
CIRGenFunction::emitPointerToDataMemberBinaryExpr(const BinaryOperator *e) {
688+
assert((e->getOpcode() == BO_PtrMemD || e->getOpcode() == BO_PtrMemI) &&
689+
"unexpected binary operator opcode");
690+
691+
Address baseAddr = Address::invalid();
692+
if (e->getOpcode() == BO_PtrMemD)
693+
baseAddr = emitLValue(e->getLHS()).getAddress();
694+
else
695+
baseAddr = emitPointerWithAlignment(e->getLHS());
696+
697+
const auto *memberPtrTy = e->getRHS()->getType()->castAs<MemberPointerType>();
698+
699+
mlir::Value memberPtr = emitScalarExpr(e->getRHS());
700+
701+
LValueBaseInfo baseInfo;
702+
assert(!cir::MissingFeatures::opTBAA());
703+
Address memberAddr = emitCXXMemberDataPointerAddress(e, baseAddr, memberPtr,
704+
memberPtrTy, &baseInfo);
705+
706+
return makeAddrLValue(memberAddr, memberPtrTy->getPointeeType(), baseInfo);
707+
}
708+
686709
/// Generates lvalue for partial ext_vector access.
687710
Address CIRGenFunction::emitExtVectorElementLValue(LValue lv,
688711
mlir::Location loc) {
@@ -1762,10 +1785,8 @@ LValue CIRGenFunction::emitBinaryOperatorLValue(const BinaryOperator *e) {
17621785
return emitLValue(e->getRHS());
17631786
}
17641787

1765-
if (e->getOpcode() == BO_PtrMemD || e->getOpcode() == BO_PtrMemI) {
1766-
cgm.errorNYI(e->getSourceRange(), "member pointers");
1767-
return {};
1768-
}
1788+
if (e->getOpcode() == BO_PtrMemD || e->getOpcode() == BO_PtrMemI)
1789+
return emitPointerToDataMemberBinaryExpr(e);
17691790

17701791
assert(e->getOpcode() == BO_Assign && "unexpected binary l-value");
17711792

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,13 +1338,11 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
13381338
}
13391339

13401340
mlir::Value VisitBinPtrMemD(const BinaryOperator *e) {
1341-
cgf.cgm.errorNYI(e->getSourceRange(), "ScalarExprEmitter: ptr mem d");
1342-
return {};
1341+
return emitLoadOfLValue(e);
13431342
}
13441343

13451344
mlir::Value VisitBinPtrMemI(const BinaryOperator *e) {
1346-
cgf.cgm.errorNYI(e->getSourceRange(), "ScalarExprEmitter: ptr mem i");
1347-
return {};
1345+
return emitLoadOfLValue(e);
13481346
}
13491347

13501348
// Other Operators.

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,10 @@ class CIRGenFunction : public CIRGenTypeCache {
15141514
RValue emitCXXMemberCallExpr(const clang::CXXMemberCallExpr *e,
15151515
ReturnValueSlot returnValue);
15161516

1517+
Address emitCXXMemberDataPointerAddress(
1518+
const Expr *e, Address base, mlir::Value memberPtr,
1519+
const MemberPointerType *memberPtrType, LValueBaseInfo *baseInfo);
1520+
15171521
RValue emitCXXMemberOrOperatorCall(
15181522
const clang::CXXMethodDecl *md, const CIRGenCallee &callee,
15191523
ReturnValueSlot returnValue, mlir::Value thisPtr,
@@ -1696,6 +1700,8 @@ class CIRGenFunction : public CIRGenTypeCache {
16961700

16971701
mlir::Value emitOpOnBoolExpr(mlir::Location loc, const clang::Expr *cond);
16981702

1703+
LValue emitPointerToDataMemberBinaryExpr(const BinaryOperator *e);
1704+
16991705
mlir::LogicalResult emitLabel(const clang::LabelDecl &d);
17001706
mlir::LogicalResult emitLabelStmt(const clang::LabelStmt &s);
17011707

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2485,6 +2485,21 @@ LogicalResult cir::CopyOp::verify() {
24852485
return mlir::success();
24862486
}
24872487

2488+
//===----------------------------------------------------------------------===//
2489+
// GetRuntimeMemberOp Definitions
2490+
//===----------------------------------------------------------------------===//
2491+
2492+
LogicalResult cir::GetRuntimeMemberOp::verify() {
2493+
auto recordTy = mlir::cast<RecordType>(getAddr().getType().getPointee());
2494+
cir::DataMemberType memberPtrTy = getMember().getType();
2495+
2496+
if (recordTy != memberPtrTy.getClassTy())
2497+
return emitError() << "record type does not match the member pointer type";
2498+
if (getType().getPointee() != memberPtrTy.getMemberTy())
2499+
return emitError() << "result type does not match the member pointer type";
2500+
return mlir::success();
2501+
}
2502+
24882503
//===----------------------------------------------------------------------===//
24892504
// GetMemberOp Definitions
24902505
//===----------------------------------------------------------------------===//

clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_CIRCXXABI_H
1616

1717
#include "mlir/Transforms/DialectConversion.h"
18+
#include "clang/CIR/Dialect/IR/CIRDialect.h"
1819
#include "clang/CIR/Dialect/IR/CIRTypes.h"
1920

2021
namespace cir {
@@ -45,6 +46,13 @@ class CIRCXXABI {
4546
lowerDataMemberConstant(cir::DataMemberAttr attr,
4647
const mlir::DataLayout &layout,
4748
const mlir::TypeConverter &typeConverter) const = 0;
49+
50+
/// Lower the given cir.get_runtime_member op to a sequence of more
51+
/// "primitive" CIR operations that act on the ABI types.
52+
virtual mlir::Operation *
53+
lowerGetRuntimeMember(cir::GetRuntimeMemberOp op, mlir::Type loweredResultTy,
54+
mlir::Value loweredAddr, mlir::Value loweredMember,
55+
mlir::OpBuilder &builder) const = 0;
4856
};
4957

5058
/// Creates an Itanium-family ABI.

clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ class LowerItaniumCXXABI : public CIRCXXABI {
4242
mlir::TypedAttr lowerDataMemberConstant(
4343
cir::DataMemberAttr attr, const mlir::DataLayout &layout,
4444
const mlir::TypeConverter &typeConverter) const override;
45+
46+
mlir::Operation *
47+
lowerGetRuntimeMember(cir::GetRuntimeMemberOp op, mlir::Type loweredResultTy,
48+
mlir::Value loweredAddr, mlir::Value loweredMember,
49+
mlir::OpBuilder &builder) const override;
4550
};
4651

4752
} // namespace
@@ -87,4 +92,20 @@ mlir::TypedAttr LowerItaniumCXXABI::lowerDataMemberConstant(
8792
return cir::IntAttr::get(abiTy, memberOffset);
8893
}
8994

95+
mlir::Operation *LowerItaniumCXXABI::lowerGetRuntimeMember(
96+
cir::GetRuntimeMemberOp op, mlir::Type loweredResultTy,
97+
mlir::Value loweredAddr, mlir::Value loweredMember,
98+
mlir::OpBuilder &builder) const {
99+
auto byteTy = cir::IntType::get(op.getContext(), 8, true);
100+
auto bytePtrTy = cir::PointerType::get(
101+
byteTy,
102+
mlir::cast<cir::PointerType>(op.getAddr().getType()).getAddrSpace());
103+
auto objectBytesPtr = cir::CastOp::create(
104+
builder, op.getLoc(), bytePtrTy, cir::CastKind::bitcast, op.getAddr());
105+
auto memberBytesPtr = cir::PtrStrideOp::create(
106+
builder, op.getLoc(), bytePtrTy, objectBytesPtr, loweredMember);
107+
return cir::CastOp::create(builder, op.getLoc(), op.getType(),
108+
cir::CastKind::bitcast, memberBytesPtr);
109+
}
110+
90111
} // namespace cir

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3231,6 +3231,17 @@ mlir::LogicalResult CIRToLLVMGetMemberOpLowering::matchAndRewrite(
32313231
}
32323232
}
32333233

3234+
mlir::LogicalResult CIRToLLVMGetRuntimeMemberOpLowering::matchAndRewrite(
3235+
cir::GetRuntimeMemberOp op, OpAdaptor adaptor,
3236+
mlir::ConversionPatternRewriter &rewriter) const {
3237+
assert(lowerMod && "lowering module is not available");
3238+
mlir::Type llvmResTy = getTypeConverter()->convertType(op.getType());
3239+
mlir::Operation *llvmOp = lowerMod->getCXXABI().lowerGetRuntimeMember(
3240+
op, llvmResTy, adaptor.getAddr(), adaptor.getMember(), rewriter);
3241+
rewriter.replaceOp(op, llvmOp);
3242+
return mlir::success();
3243+
}
3244+
32343245
mlir::LogicalResult CIRToLLVMUnreachableOpLowering::matchAndRewrite(
32353246
cir::UnreachableOp op, OpAdaptor adaptor,
32363247
mlir::ConversionPatternRewriter &rewriter) const {

0 commit comments

Comments
 (0)