Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -3489,6 +3489,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 differs 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
//===----------------------------------------------------------------------===//
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,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.
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
29 changes: 25 additions & 4 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,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) {
Expand Down Expand Up @@ -1763,10 +1786,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");

Expand Down
6 changes: 2 additions & 4 deletions clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1333,13 +1333,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.
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1508,6 +1508,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,
Expand Down Expand Up @@ -1690,6 +1694,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);

Expand Down
15 changes: 15 additions & 0 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2501,6 +2501,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
//===----------------------------------------------------------------------===//
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
11 changes: 11 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3223,6 +3223,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 {
Expand Down
Loading
Loading