[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
|
// ConstComplexAttr
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -424,6 +424,44 @@ cir::ConstVectorAttr::verify(function_ref<InFlightDiagnostic()> emitError,
|
|||||||
return elementTypeCheck;
|
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
|
// CIR Dialect
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -342,7 +342,8 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType,
|
|||||||
|
|
||||||
if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr,
|
if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr,
|
||||||
cir::ConstComplexAttr, cir::ConstRecordAttr,
|
cir::ConstComplexAttr, cir::ConstRecordAttr,
|
||||||
cir::GlobalViewAttr, cir::PoisonAttr>(attrType))
|
cir::GlobalViewAttr, cir::PoisonAttr, cir::VTableAttr>(
|
||||||
|
attrType))
|
||||||
return success();
|
return success();
|
||||||
|
|
||||||
assert(isa<TypedAttr>(attrType) && "What else could we be looking at here?");
|
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>
|
!s8i = !cir.int<s, 8>
|
||||||
!u32i = !cir.int<u, 32>
|
!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
|
%0 = cir.vtable.address_point(@some_vtable, address_point = <index = 0, offset = 2>) : !cir.vptr
|
||||||
cir.return
|
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