Skip to content

Commit c301b4a

Browse files
authored
[CIR] LLVM lowering support for pointers to member functions (#1292)
This PR adds support for LLVM lowering of pointers to member functions. The lowering is ABI-specific and this patch only considers Itanium ABI. Itanium ABI lowers pointers to member functions to a struct with two fields of type `ptrdiff_t`. To extract fields from such aggregate values, this PR includes a new operation `cir.extract_member` to accomplish this.
1 parent b6796c4 commit c301b4a

File tree

10 files changed

+530
-13
lines changed

10 files changed

+530
-13
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,16 @@ def MethodAttr : CIR_Attr<"Method", "method", [TypedAttrInterface]> {
573573
let hasCustomAssemblyFormat = 1;
574574

575575
let genVerifyDecl = 1;
576+
577+
let extraClassDeclaration = [{
578+
bool isNull() const {
579+
return !getSymbol().has_value() && !getVtableOffset().has_value();
580+
}
581+
582+
bool isVirtual() const {
583+
return getVtableOffset().has_value();
584+
}
585+
}];
576586
}
577587

578588
//===----------------------------------------------------------------------===//

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

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2850,6 +2850,64 @@ def GetMemberOp : CIR_Op<"get_member"> {
28502850
let hasVerifier = 1;
28512851
}
28522852

2853+
//===----------------------------------------------------------------------===//
2854+
// ExtractMemberOp
2855+
//===----------------------------------------------------------------------===//
2856+
2857+
def ExtractMemberOp : CIR_Op<"extract_member", [Pure]> {
2858+
let summary = "Extract the value of a member of a struct value";
2859+
let description = [{
2860+
The `cir.extract_member` operation extracts the value of a particular member
2861+
from the input record. Unlike `cir.get_member` which derives pointers, this
2862+
operation operates on values. It takes a value of record type, and extract
2863+
the value of the specified record member from the input record value.
2864+
2865+
Currently `cir.extract_member` does not work on unions.
2866+
2867+
Example:
2868+
2869+
```mlir
2870+
// Suppose we have a struct with multiple members.
2871+
!s32i = !cir.int<s, 32>
2872+
!s8i = !cir.int<s, 32>
2873+
!struct_ty = !cir.struct<"struct.Bar" {!s32i, !s8i}>
2874+
2875+
// And suppose we have a value of the struct type.
2876+
%0 = cir.const #cir.const_struct<{#cir.int<1> : !s32i, #cir.int<2> : !s8i}> : !struct_ty
2877+
2878+
// Extract the value of the second member of the struct.
2879+
%1 = cir.extract_member %0[1] : !struct_ty -> !s8i
2880+
```
2881+
}];
2882+
2883+
let arguments = (ins CIR_StructType:$record, IndexAttr:$index_attr);
2884+
let results = (outs CIR_AnyType:$result);
2885+
2886+
let assemblyFormat = [{
2887+
$record `[` $index_attr `]` attr-dict
2888+
`:` qualified(type($record)) `->` qualified(type($result))
2889+
}];
2890+
2891+
let builders = [
2892+
OpBuilder<(ins "mlir::Type":$type, "mlir::Value":$record, "uint64_t":$index), [{
2893+
mlir::APInt fieldIdx(64, index);
2894+
build($_builder, $_state, type, record, fieldIdx);
2895+
}]>,
2896+
OpBuilder<(ins "mlir::Value":$record, "uint64_t":$index), [{
2897+
auto recordTy = mlir::cast<cir::StructType>(record.getType());
2898+
mlir::Type memberTy = recordTy.getMembers()[index];
2899+
build($_builder, $_state, memberTy, record, index);
2900+
}]>
2901+
];
2902+
2903+
let extraClassDeclaration = [{
2904+
/// Get the index of the struct member being accessed.
2905+
uint64_t getIndex() { return getIndexAttr().getZExtValue(); }
2906+
}];
2907+
2908+
let hasVerifier = 1;
2909+
}
2910+
28532911
//===----------------------------------------------------------------------===//
28542912
// GetRuntimeMemberOp
28552913
//===----------------------------------------------------------------------===//

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ struct MissingFeatures {
7070
static bool tbaaPointer() { return false; }
7171
static bool emitNullabilityCheck() { return false; }
7272
static bool ptrAuth() { return false; }
73+
static bool emitCFICheck() { return false; }
74+
static bool emitVFEInfo() { return false; }
75+
static bool emitWPDInfo() { return false; }
7376

7477
// GNU vectors are done, but other kinds of vectors haven't been implemented.
7578
static bool scalableVectors() { return false; }

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3577,6 +3577,22 @@ LogicalResult cir::GetMemberOp::verify() {
35773577
return mlir::success();
35783578
}
35793579

3580+
//===----------------------------------------------------------------------===//
3581+
// ExtractMemberOp Definitions
3582+
//===----------------------------------------------------------------------===//
3583+
3584+
LogicalResult cir::ExtractMemberOp::verify() {
3585+
auto recordTy = mlir::cast<cir::StructType>(getRecord().getType());
3586+
if (recordTy.getKind() == cir::StructType::Union)
3587+
return emitError()
3588+
<< "cir.extract_member currently does not work on unions";
3589+
if (recordTy.getMembers().size() <= getIndex())
3590+
return emitError() << "member index out of bounds";
3591+
if (recordTy.getMembers()[getIndex()] != getType())
3592+
return emitError() << "member type mismatch";
3593+
return mlir::success();
3594+
}
3595+
35803596
//===----------------------------------------------------------------------===//
35813597
// GetRuntimeMemberOp Definitions
35823598
//===----------------------------------------------------------------------===//

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,20 +72,40 @@ class CIRCXXABI {
7272
lowerDataMemberType(cir::DataMemberType type,
7373
const mlir::TypeConverter &typeConverter) const = 0;
7474

75+
/// Lower the given member function pointer type to its ABI type. The returned
76+
/// type is also a CIR type.
77+
virtual mlir::Type
78+
lowerMethodType(cir::MethodType type,
79+
const mlir::TypeConverter &typeConverter) const = 0;
80+
7581
/// Lower the given data member pointer constant to a constant of the ABI
7682
/// type. The returned constant is represented as an attribute as well.
7783
virtual mlir::TypedAttr
7884
lowerDataMemberConstant(cir::DataMemberAttr attr,
7985
const mlir::DataLayout &layout,
8086
const mlir::TypeConverter &typeConverter) const = 0;
8187

88+
/// Lower the given member function pointer constant to a constant of the ABI
89+
/// type. The returned constant is represented as an attribute as well.
90+
virtual mlir::TypedAttr
91+
lowerMethodConstant(cir::MethodAttr attr, const mlir::DataLayout &layout,
92+
const mlir::TypeConverter &typeConverter) const = 0;
93+
8294
/// Lower the given cir.get_runtime_member op to a sequence of more
8395
/// "primitive" CIR operations that act on the ABI types.
8496
virtual mlir::Operation *
8597
lowerGetRuntimeMember(cir::GetRuntimeMemberOp op, mlir::Type loweredResultTy,
8698
mlir::Value loweredAddr, mlir::Value loweredMember,
8799
mlir::OpBuilder &builder) const = 0;
88100

101+
/// Lower the given cir.get_method op to a sequence of more "primitive" CIR
102+
/// operations that act on the ABI types. The lowered result values will be
103+
/// stored in the given loweredResults array.
104+
virtual void
105+
lowerGetMethod(cir::GetMethodOp op, mlir::Value (&loweredResults)[2],
106+
mlir::Value loweredMethod, mlir::Value loweredObjectPtr,
107+
mlir::ConversionPatternRewriter &rewriter) const = 0;
108+
89109
/// Lower the given cir.base_data_member op to a sequence of more "primitive"
90110
/// CIR operations that act on the ABI types.
91111
virtual mlir::Value lowerBaseDataMember(cir::BaseDataMemberOp op,

0 commit comments

Comments
 (0)