Skip to content

Commit 5ea5c5c

Browse files
committed
[CIR] LLVM lowering support for pointers to member functions
This patch 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 patch includes a new operation `cir.extract_member` to accomplish this.
1 parent f8821e8 commit 5ea5c5c

File tree

9 files changed

+526
-13
lines changed

9 files changed

+526
-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
@@ -572,6 +572,16 @@ def MethodAttr : CIR_Attr<"Method", "method", [TypedAttrInterface]> {
572572
let hasCustomAssemblyFormat = 1;
573573

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

577587
//===----------------------------------------------------------------------===//

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/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3575,6 +3575,26 @@ LogicalResult cir::GetMemberOp::verify() {
35753575
return mlir::success();
35763576
}
35773577

3578+
//===----------------------------------------------------------------------===//
3579+
// ExtractMemberOp Definitions
3580+
//===----------------------------------------------------------------------===//
3581+
3582+
LogicalResult cir::ExtractMemberOp::verify() {
3583+
auto recordTy = mlir::cast<cir::StructType>(getRecord().getType());
3584+
if (recordTy.getKind() == cir::StructType::Union)
3585+
return emitError()
3586+
<< "cir.extract_member currently does not work on unions";
3587+
if (recordTy.getMembers().size() <= getIndex())
3588+
return emitError() << "member index out of bounds";
3589+
3590+
// FIXME(cir): member type check is disabled for classes as the codegen for
3591+
// these still need to be patched.
3592+
if (!recordTy.isClass() && recordTy.getMembers()[getIndex()] != getType())
3593+
return emitError() << "member type mismatch";
3594+
3595+
return mlir::success();
3596+
}
3597+
35783598
//===----------------------------------------------------------------------===//
35793599
// GetRuntimeMemberOp Definitions
35803600
//===----------------------------------------------------------------------===//

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)