[CIR] Add CIR vtable attribute (#154415)
This adds the #cir.vtable attribute definition and verification. Generation of the vtable will be implemented in a later change.
This commit is contained in:
parent
761125f267
commit
c5466c64d4
@ -535,6 +535,72 @@ def CIR_GlobalViewAttr : CIR_Attr<"GlobalView", "global_view", [
|
||||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// VTableAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", [TypedAttrInterface]> {
|
||||
let summary = "Represents a C++ vtable";
|
||||
let description = [{
|
||||
Wraps a #cir.const_record containing one or more vtable arrays.
|
||||
|
||||
In most cases, the anonymous record type wrapped by this attribute will
|
||||
contain a single array corresponding to the vtable for one class. However,
|
||||
in the case of multiple inheritence, the anonymous structure may contain
|
||||
multiple arrays, each of which is a vtable.
|
||||
|
||||
Example 1 (single vtable):
|
||||
```mlir
|
||||
cir.global linkonce_odr @_ZTV6Mother =
|
||||
#cir.vtable<{
|
||||
#cir.const_array<[
|
||||
#cir.ptr<null> : !cir.ptr<!u8i>,
|
||||
#cir.global_view<@_ZTI6Mother> : !cir.ptr<!u8i>,
|
||||
#cir.global_view<@_ZN6Mother9MotherFooEv> : !cir.ptr<!u8i>,
|
||||
#cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr<!u8i>
|
||||
]> : !cir.array<!cir.ptr<!u8i> x 4>
|
||||
}> : !rec_anon_struct1
|
||||
```
|
||||
|
||||
Example 2 (multiple vtables):
|
||||
```mlir
|
||||
cir.global linkonce_odr @_ZTV5Child =
|
||||
#cir.vtable<{
|
||||
#cir.const_array<[
|
||||
#cir.ptr<null> : !cir.ptr<!u8i>,
|
||||
#cir.global_view<@_ZTI5Child> : !cir.ptr<!u8i>,
|
||||
#cir.global_view<@_ZN5Child9MotherFooEv> : !cir.ptr<!u8i>,
|
||||
#cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr<!u8i>
|
||||
]> : !cir.array<!cir.ptr<!u8i> x 4>,
|
||||
#cir.const_array<[
|
||||
#cir.ptr<-8 : i64> : !cir.ptr<!u8i>,
|
||||
#cir.global_view<@_ZTI5Child> : !cir.ptr<!u8i>,
|
||||
#cir.global_view<@_ZN6Father9FatherFooEv> : !cir.ptr<!u8i>
|
||||
]> : !cir.array<!cir.ptr<!u8i> x 3>
|
||||
}> : !rec_anon_struct2
|
||||
```
|
||||
}];
|
||||
|
||||
// `data` is a const record with one element, containing an array of
|
||||
// vtable information.
|
||||
let parameters = (ins
|
||||
AttributeSelfTypeParameter<"">:$type,
|
||||
"mlir::ArrayAttr":$data
|
||||
);
|
||||
|
||||
let builders = [
|
||||
AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
|
||||
"mlir::ArrayAttr":$data), [{
|
||||
return $_get(type.getContext(), type, data);
|
||||
}]>
|
||||
];
|
||||
|
||||
let genVerifyDecl = 1;
|
||||
let assemblyFormat = [{
|
||||
`<` custom<RecordMembers>($data) `>`
|
||||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ConstComplexAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -424,6 +424,44 @@ cir::ConstVectorAttr::verify(function_ref<InFlightDiagnostic()> emitError,
|
||||
return elementTypeCheck;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CIR VTableAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
LogicalResult cir::VTableAttr::verify(
|
||||
llvm::function_ref<mlir::InFlightDiagnostic()> emitError, mlir::Type type,
|
||||
mlir::ArrayAttr data) {
|
||||
auto sTy = mlir::dyn_cast_if_present<cir::RecordType>(type);
|
||||
if (!sTy)
|
||||
return emitError() << "expected !cir.record type result";
|
||||
if (sTy.getMembers().empty() || data.empty())
|
||||
return emitError() << "expected record type with one or more subtype";
|
||||
|
||||
if (cir::ConstRecordAttr::verify(emitError, type, data).failed())
|
||||
return failure();
|
||||
|
||||
for (const auto &element : data.getAsRange<mlir::Attribute>()) {
|
||||
const auto &constArrayAttr = mlir::dyn_cast<cir::ConstArrayAttr>(element);
|
||||
if (!constArrayAttr)
|
||||
return emitError() << "expected constant array subtype";
|
||||
|
||||
LogicalResult eltTypeCheck = success();
|
||||
auto arrayElts = mlir::cast<ArrayAttr>(constArrayAttr.getElts());
|
||||
arrayElts.walkImmediateSubElements(
|
||||
[&](mlir::Attribute attr) {
|
||||
if (mlir::isa<ConstPtrAttr, GlobalViewAttr>(attr))
|
||||
return;
|
||||
|
||||
eltTypeCheck = emitError()
|
||||
<< "expected GlobalViewAttr or ConstPtrAttr";
|
||||
},
|
||||
[&](mlir::Type type) {});
|
||||
if (eltTypeCheck.failed())
|
||||
return eltTypeCheck;
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CIR Dialect
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -342,7 +342,8 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType,
|
||||
|
||||
if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr,
|
||||
cir::ConstComplexAttr, cir::ConstRecordAttr,
|
||||
cir::GlobalViewAttr, cir::PoisonAttr>(attrType))
|
||||
cir::GlobalViewAttr, cir::PoisonAttr, cir::VTableAttr>(
|
||||
attrType))
|
||||
return success();
|
||||
|
||||
assert(isa<TypedAttr>(attrType) && "What else could we be looking at here?");
|
||||
|
@ -1,4 +1,4 @@
|
||||
// RUN: cir-opt %s -verify-diagnostics
|
||||
// RUN: cir-opt %s -verify-diagnostics -split-input-file
|
||||
|
||||
!s8i = !cir.int<s, 8>
|
||||
!u32i = !cir.int<u, 32>
|
||||
@ -7,3 +7,67 @@ cir.func @reference_unknown_vtable() {
|
||||
%0 = cir.vtable.address_point(@some_vtable, address_point = <index = 0, offset = 2>) : !cir.vptr
|
||||
cir.return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
!rec_S = !cir.record<struct "S" {!cir.vptr}>
|
||||
!u8i = !cir.int<u, 8>
|
||||
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}>
|
||||
module {
|
||||
// expected-error @below {{expected !cir.record type result}}
|
||||
cir.global external @_ZTV1S = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>}> : !cir.ptr<!rec_anon_struct>
|
||||
cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
|
||||
cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
!rec_S = !cir.record<struct "S" {!cir.vptr}>
|
||||
!u8i = !cir.int<u, 8>
|
||||
!rec_anon_struct = !cir.record<struct {}>
|
||||
module {
|
||||
// expected-error @below {{expected record type with one or more subtype}}
|
||||
cir.global external @_ZTV1S = #cir.vtable<{}> : !rec_anon_struct {alignment = 8 : i64}
|
||||
cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
|
||||
cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
!rec_S = !cir.record<struct "S" {!cir.vptr}>
|
||||
!u8i = !cir.int<u, 8>
|
||||
!rec_anon_struct = !cir.record<struct {!cir.ptr<!u8i>}>
|
||||
module {
|
||||
// expected-error @below {{expected constant array subtype}}
|
||||
cir.global external @_ZTV1S = #cir.vtable<{#cir.ptr<null> : !cir.ptr<!u8i>}> : !rec_anon_struct {alignment = 8 : i64}
|
||||
cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
|
||||
cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
!rec_S = !cir.record<struct "S" {!cir.vptr}>
|
||||
!u64i = !cir.int<u, 64>
|
||||
!rec_anon_struct = !cir.record<struct {!cir.array<!u64i x 4>}>
|
||||
module {
|
||||
// expected-error @below {{expected GlobalViewAttr or ConstPtrAttr}}
|
||||
cir.global external @_ZTV1S = #cir.vtable<{#cir.const_array<[#cir.int<1> : !u64i, #cir.int<1> : !u64i, #cir.int<3> : !u64i, #cir.int<4> : !u64i]> : !cir.array<!u64i x 4>}> : !rec_anon_struct {alignment = 8 : i64}
|
||||
cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
|
||||
cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
!rec_Q = !cir.record<struct "Q" {!cir.vptr}>
|
||||
!rec_S = !cir.record<struct "S" {!cir.vptr}>
|
||||
!rec_S2 = !cir.record<struct "S2" {!rec_Q, !rec_S}>
|
||||
!u8i = !cir.int<u, 8>
|
||||
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>, !cir.ptr<!u8i>}>
|
||||
module {
|
||||
// expected-error @below {{expected constant array subtype}}
|
||||
cir.global external @_ZTV2S2 = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>, #cir.ptr<null> : !cir.ptr<!u8i>}> : !rec_anon_struct {alignment = 8 : i64}
|
||||
|
||||
cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
|
||||
cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
|
||||
cir.func private dso_local @_ZN2S23keyEv(%arg0: !cir.ptr<!rec_S2>)
|
||||
}
|
||||
|
19
clang/test/CIR/IR/vtable-attr.cir
Normal file
19
clang/test/CIR/IR/vtable-attr.cir
Normal file
@ -0,0 +1,19 @@
|
||||
// RUN: cir-opt %s | FileCheck %s
|
||||
|
||||
!rec_Q = !cir.record<struct "Q" {!cir.vptr}>
|
||||
!rec_S = !cir.record<struct "S" {!cir.vptr}>
|
||||
!rec_S2 = !cir.record<struct "S2" {!rec_Q, !rec_S}>
|
||||
!u8i = !cir.int<u, 8>
|
||||
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}>
|
||||
!rec_anon_struct1 = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>, !cir.array<!cir.ptr<!u8i> x 3>}>
|
||||
module {
|
||||
cir.global external @_ZTV1S = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>}> : !rec_anon_struct {alignment = 8 : i64}
|
||||
// CHECK: cir.global external @_ZTV1S = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>}> : !rec_anon_struct {alignment = 8 : i64}
|
||||
|
||||
cir.global external @_ZTV2S2 = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>, #cir.const_array<[#cir.ptr<-8 : i64> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN2S23keyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 3>}> : !rec_anon_struct1 {alignment = 8 : i64}
|
||||
// CHECK: cir.global external @_ZTV2S2 = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>, #cir.const_array<[#cir.ptr<-8 : i64> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN2S23keyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 3>}> : !rec_anon_struct1 {alignment = 8 : i64}
|
||||
|
||||
cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
|
||||
cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
|
||||
cir.func private dso_local @_ZN2S23keyEv(%arg0: !cir.ptr<!rec_S2>)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user