-
Notifications
You must be signed in to change notification settings - Fork 14.5k
[CIR] Add VTableAddrPointOp #148730
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[CIR] Add VTableAddrPointOp #148730
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -515,5 +515,35 @@ def BitfieldInfoAttr : CIR_Attr<"BitfieldInfo", "bitfield_info"> { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//===----------------------------------------------------------------------===// | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// AddressPointAttr | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//===----------------------------------------------------------------------===// | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def AddressPointAttr : CIR_Attr<"AddressPoint", "address_point"> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any reason to have this as a special attribute and not just two I scanned through incubator codebase and all uses I found it is always accessed directly to index or offset, e.g. Therefore, I believe we can remove the attribute entirely and use just This can clean up address point op assembly as well to something like:
^ This just my suggestion removing also some parenthesis and adding There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are other places that use address point in the incubator but are not using the attribute just yet (e.g. emitVTTDefinition). The idea was to unify those references so they are easy to understand (versus reading random integers in tables). It's possible we need more work to make them adequate to use though, so it's possible we don't need this until we can also cover relative layouts and understand all we really need. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let summary = "Address point attribute"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let description = [{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Attribute specifying the address point within a C++ virtual table (vtable). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The `index` (vtable index) parameter identifies which vtable to use within a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
vtable group, while the `offset` (address point index) specifies the offset | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
within that vtable where the address begins. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Example: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
```mlir | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cir.global linkonce_odr @_ZTV1B = ... | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
... | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
%3 = cir.vtable.address_point(@_ZTV1B, address_point = <index = 0, offset = 2>) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
: !cir.ptr<!cir.ptr<() -> i32>> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+526
to
+538
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let parameters = (ins "int32_t":$index, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"int32_t":$offset); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let assemblyFormat = [{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
`<` struct($index, $offset) `>` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#endif // LLVM_CLANG_CIR_DIALECT_IR_CIRATTRS_TD |
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -1669,6 +1669,51 @@ def GetGlobalOp : CIR_Op<"get_global", | |||||||||||||||||
}]; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
//===----------------------------------------------------------------------===// | ||||||||||||||||||
// VTableAddrPointOp | ||||||||||||||||||
//===----------------------------------------------------------------------===// | ||||||||||||||||||
|
||||||||||||||||||
def VTableAddrPointOp : CIR_Op<"vtable.address_point", | ||||||||||||||||||
[Pure, DeclareOpInterfaceMethods<SymbolUserOpInterface>]> { | ||||||||||||||||||
Comment on lines
+1676
to
+1677
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
let summary = "Get the vtable (global variable) address point"; | ||||||||||||||||||
let description = [{ | ||||||||||||||||||
The `vtable.address_point` operation retrieves the effective address | ||||||||||||||||||
(address point) of a C++ virtual table. An object internal `__vptr` | ||||||||||||||||||
gets initializated on top of the value returned by this operation. | ||||||||||||||||||
|
||||||||||||||||||
`address_point.index` (vtable index) provides the appropriate vtable within | ||||||||||||||||||
the vtable group (as specified by Itanium ABI), and `address_point.offset` | ||||||||||||||||||
(address point index) the actual address point within that vtable. | ||||||||||||||||||
|
||||||||||||||||||
The return type is always a `!cir.ptr<!cir.ptr<() -> i32>>`. | ||||||||||||||||||
|
||||||||||||||||||
Example: | ||||||||||||||||||
```mlir | ||||||||||||||||||
cir.global linkonce_odr @_ZTV1B = ... | ||||||||||||||||||
... | ||||||||||||||||||
%3 = cir.vtable.address_point(@_ZTV1B, address_point = <index = 0, | ||||||||||||||||||
offset = 2>) : !cir.ptr<!cir.ptr<() -> i32>> | ||||||||||||||||||
``` | ||||||||||||||||||
}]; | ||||||||||||||||||
|
||||||||||||||||||
let arguments = (ins OptionalAttr<FlatSymbolRefAttr>:$name, | ||||||||||||||||||
Optional<CIR_AnyType>:$sym_addr, | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this should not be CIR_AnyType; should it be CIR_PtrTo<CIR_AnyFuncType> instead? However, neither the description nor the example clarifies what is expected for sym_addr. It would be helpful to include that in the documentation as well. |
||||||||||||||||||
AddressPointAttr:$address_point); | ||||||||||||||||||
Comment on lines
+1699
to
+1701
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
let results = (outs Res<CIR_PointerType, "", []>:$addr); | ||||||||||||||||||
|
||||||||||||||||||
let assemblyFormat = [{ | ||||||||||||||||||
`(` | ||||||||||||||||||
($name^)? | ||||||||||||||||||
($sym_addr^ `:` type($sym_addr))? | ||||||||||||||||||
`,` | ||||||||||||||||||
`address_point` `=` $address_point | ||||||||||||||||||
`)` | ||||||||||||||||||
`:` qualified(type($addr)) attr-dict | ||||||||||||||||||
}]; | ||||||||||||||||||
|
||||||||||||||||||
let hasVerifier = 1; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
//===----------------------------------------------------------------------===// | ||||||||||||||||||
// SetBitfieldOp | ||||||||||||||||||
//===----------------------------------------------------------------------===// | ||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1338,6 +1338,52 @@ cir::GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) { | |
return success(); | ||
} | ||
|
||
//===----------------------------------------------------------------------===// | ||
// VTableAddrPointOp | ||
//===----------------------------------------------------------------------===// | ||
|
||
LogicalResult | ||
cir::VTableAddrPointOp::verifySymbolUses(SymbolTableCollection &symbolTable) { | ||
// vtable ptr is not coming from a symbol. | ||
if (!getName()) | ||
return success(); | ||
StringRef name = *getName(); | ||
|
||
// Verify that the result type underlying pointer type matches the type of | ||
// the referenced cir.global or cir.func op. | ||
auto op = dyn_cast_or_null<GlobalOp>( | ||
symbolTable.lookupNearestSymbolFrom(*this, getNameAttr())); | ||
if (!op) | ||
return emitOpError("'") | ||
<< name << "' does not reference a valid cir.global"; | ||
std::optional<mlir::Attribute> init = op.getInitialValue(); | ||
if (!init) | ||
return success(); | ||
assert(!cir::MissingFeatures::vtableInitializer()); | ||
return success(); | ||
} | ||
|
||
LogicalResult cir::VTableAddrPointOp::verify() { | ||
// The operation uses either a symbol or a value to operate, but not both | ||
if (getName() && getSymAddr()) | ||
return emitOpError("should use either a symbol or value, but not both"); | ||
|
||
// If not a symbol, stick with the concrete type used for getSymAddr. | ||
if (getSymAddr()) | ||
return success(); | ||
|
||
mlir::Type resultType = getAddr().getType(); | ||
auto intTy = cir::IntType::get(getContext(), 32, /*isSigned=*/false); | ||
auto fnTy = cir::FuncType::get({}, intTy); | ||
|
||
auto resTy = cir::PointerType::get(cir::PointerType::get(fnTy)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As far as I can tell, this is completely arbitrary. In the incubator, |
||
|
||
if (resultType != resTy) | ||
return emitOpError("result type must be ") | ||
<< resTy << ", but provided result type is " << resultType << ""; | ||
return success(); | ||
} | ||
|
||
//===----------------------------------------------------------------------===// | ||
// FuncOp | ||
//===----------------------------------------------------------------------===// | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// RUN: cir-opt %s -verify-diagnostics -split-input-file | ||
|
||
!s8i = !cir.int<s, 8> | ||
!u32i = !cir.int<u, 32> | ||
cir.func @reference_unknown_vtable() { | ||
// expected-error @below {{'cir.vtable.address_point' op 'some_vtable' does not reference a valid cir.global}} | ||
%0 = cir.vtable.address_point(@some_vtable, address_point = <index = 0, offset = 2>) : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>> | ||
cir.return | ||
} | ||
|
||
// ----- | ||
|
||
!s8i = !cir.int<s, 8> | ||
!u8i = !cir.int<u, 8> | ||
!u64i = !cir.int<u, 64> | ||
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}> | ||
cir.global "private" external @_ZTV1S : !rec_anon_struct {alignment = 8 : i64} | ||
cir.func @incorrect_type() { | ||
// expected-error @below {{'cir.vtable.address_point' op result type must be '!cir.ptr<!cir.ptr<!cir.func<() -> !cir.int<u, 32>>>>', but provided result type is '!cir.ptr<!cir.ptr<!cir.func<() -> !cir.int<u, 64>>>>'}} | ||
%0 = cir.vtable.address_point(@_ZTV1S, address_point = <index = 0, offset = 2>) : !cir.ptr<!cir.ptr<!cir.func<() -> !u64i>>> | ||
cir.return | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// RUN: cir-opt %s | FileCheck %s | ||
|
||
// Test the parsing and printing of a constructor that uses a vtable addess_point op. | ||
|
||
!u32i = !cir.int<u, 32> | ||
!u8i = !cir.int<u, 8> | ||
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}> | ||
!rec_S = !cir.record<struct "S" {!cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>}> | ||
|
||
module { | ||
cir.global "private" external @_ZTV1S : !rec_anon_struct {alignment = 8 : i64} | ||
cir.func @_ZN1SC2Ev(%arg0: !cir.ptr<!rec_S>) { | ||
%0 = cir.alloca !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>, ["this", init] {alignment = 8 : i64} | ||
cir.store %arg0, %0 : !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>> | ||
%1 = cir.load %0 : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S> | ||
%2 = cir.vtable.address_point(@_ZTV1S, address_point = <index = 0, offset = 2>) : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>> | ||
%3 = cir.cast(bitcast, %1 : !cir.ptr<!rec_S>), !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>> | ||
cir.store align(8) %2, %3 : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>, !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>> | ||
cir.return | ||
} | ||
} | ||
|
||
// CHECK: cir.vtable.address_point(@_ZTV1S, address_point = <index = 0, offset = 2>) : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.