Skip to content

Commit 1e2e903

Browse files
authored
[CIR] Add VTableAddrPointOp (#148730)
This change adds the definition of VTableAddrPointOp and the related AddressPointAttr to the CIR dialect, along with tests for the parsing and verification of these elements. Code to generate this operation will be added in a later change.
1 parent 740f690 commit 1e2e903

File tree

6 files changed

+129
-0
lines changed

6 files changed

+129
-0
lines changed

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,4 +516,36 @@ def CIR_BitfieldInfoAttr : CIR_Attr<"BitfieldInfo", "bitfield_info"> {
516516
];
517517
}
518518

519+
//===----------------------------------------------------------------------===//
520+
// AddressPointAttr
521+
//===----------------------------------------------------------------------===//
522+
523+
def CIR_AddressPointAttr : CIR_Attr<"AddressPoint", "address_point"> {
524+
let summary = "Address point attribute";
525+
526+
let description = [{
527+
Attribute specifying the address point within a C++ virtual table (vtable).
528+
529+
The `index` (vtable index) parameter identifies which vtable to use within a
530+
vtable group, while the `offset` (address point index) specifies the offset
531+
within that vtable where the address begins.
532+
533+
Example:
534+
```mlir
535+
cir.global linkonce_odr @_ZTV1B = ...
536+
...
537+
%3 = cir.vtable.address_point(@_ZTV1B,
538+
address_point = <index = 0, offset = 2>)
539+
: !cir.vptr
540+
```
541+
}];
542+
543+
let parameters = (ins "int32_t":$index,
544+
"int32_t":$offset);
545+
546+
let assemblyFormat = [{
547+
`<` struct($index, $offset) `>`
548+
}];
549+
}
550+
519551
#endif // CLANG_CIR_DIALECT_IR_CIRATTRS_TD

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,6 +1691,49 @@ def CIR_GetGlobalOp : CIR_Op<"get_global", [
16911691
}];
16921692
}
16931693

1694+
//===----------------------------------------------------------------------===//
1695+
// VTableAddrPointOp
1696+
//===----------------------------------------------------------------------===//
1697+
1698+
def CIR_VTableAddrPointOp : CIR_Op<"vtable.address_point", [
1699+
Pure, DeclareOpInterfaceMethods<SymbolUserOpInterface>
1700+
]> {
1701+
let summary = "Get the vtable (global variable) address point";
1702+
let description = [{
1703+
The `vtable.address_point` operation retrieves the "effective" address
1704+
(address point) of a C++ virtual table. An object internal `__vptr`
1705+
gets initializated on top of the value returned by this operation.
1706+
1707+
`address_point.index` (vtable index) provides the appropriate vtable within
1708+
the vtable group (as specified by Itanium ABI), and `address_point.offset`
1709+
(address point index) the actual address point within that vtable.
1710+
1711+
The return type is always `!cir.vptr`.
1712+
1713+
Example:
1714+
```mlir
1715+
cir.global linkonce_odr @_ZTV1B = ...
1716+
...
1717+
%3 = cir.vtable.address_point(@_ZTV1B,
1718+
address_point = <index = 0, offset = 2>) : !cir.vptr
1719+
```
1720+
}];
1721+
1722+
let arguments = (ins
1723+
FlatSymbolRefAttr:$name,
1724+
CIR_AddressPointAttr:$address_point
1725+
);
1726+
1727+
let results = (outs Res<CIR_VPtrType, "", []>:$addr);
1728+
1729+
let assemblyFormat = [{
1730+
`(`
1731+
$name `,` `address_point` `=` $address_point
1732+
`)`
1733+
`:` qualified(type($addr)) attr-dict
1734+
}];
1735+
}
1736+
16941737
//===----------------------------------------------------------------------===//
16951738
// SetBitfieldOp
16961739
//===----------------------------------------------------------------------===//

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ struct MissingFeatures {
253253
static bool thunks() { return false; }
254254
static bool tryEmitAsConstant() { return false; }
255255
static bool typeChecks() { return false; }
256+
static bool vtableInitializer() { return false; }
256257
static bool weakRefReference() { return false; }
257258
static bool writebacks() { return false; }
258259
static bool appleKext() { return false; }

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,6 +1443,27 @@ cir::GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
14431443
return success();
14441444
}
14451445

1446+
//===----------------------------------------------------------------------===//
1447+
// VTableAddrPointOp
1448+
//===----------------------------------------------------------------------===//
1449+
1450+
LogicalResult
1451+
cir::VTableAddrPointOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1452+
StringRef name = getName();
1453+
1454+
// Verify that the result type underlying pointer type matches the type of
1455+
// the referenced cir.global or cir.func op.
1456+
auto op = symbolTable.lookupNearestSymbolFrom<GlobalOp>(*this, getNameAttr());
1457+
if (!op)
1458+
return emitOpError("'")
1459+
<< name << "' does not reference a valid cir.global";
1460+
std::optional<mlir::Attribute> init = op.getInitialValue();
1461+
if (!init)
1462+
return success();
1463+
assert(!cir::MissingFeatures::vtableInitializer());
1464+
return success();
1465+
}
1466+
14461467
//===----------------------------------------------------------------------===//
14471468
// FuncOp
14481469
//===----------------------------------------------------------------------===//

clang/test/CIR/IR/invalid-vtable.cir

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: cir-opt %s -verify-diagnostics
2+
3+
!s8i = !cir.int<s, 8>
4+
!u32i = !cir.int<u, 32>
5+
cir.func @reference_unknown_vtable() {
6+
// expected-error @below {{'cir.vtable.address_point' op 'some_vtable' does not reference a valid cir.global}}
7+
%0 = cir.vtable.address_point(@some_vtable, address_point = <index = 0, offset = 2>) : !cir.vptr
8+
cir.return
9+
}

clang/test/CIR/IR/vtable-addrpt.cir

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: cir-opt %s | FileCheck %s
2+
3+
// Test the parsing and printing of a constructor that uses a vtable addess_point op.
4+
5+
!u32i = !cir.int<u, 32>
6+
!u8i = !cir.int<u, 8>
7+
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}>
8+
!rec_S = !cir.record<struct "S" {!cir.vptr}>
9+
10+
module {
11+
cir.global "private" external @_ZTV1S : !rec_anon_struct {alignment = 8 : i64}
12+
cir.func @_ZN1SC2Ev(%arg0: !cir.ptr<!rec_S>) {
13+
%0 = cir.alloca !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>, ["this", init] {alignment = 8 : i64}
14+
cir.store %arg0, %0 : !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>
15+
%1 = cir.load %0 : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
16+
%2 = cir.vtable.address_point(@_ZTV1S, address_point = <index = 0, offset = 2>) : !cir.vptr
17+
%3 = cir.cast(bitcast, %1 : !cir.ptr<!rec_S>), !cir.ptr<!cir.vptr>
18+
cir.store align(8) %2, %3 : !cir.vptr, !cir.ptr<!cir.vptr>
19+
cir.return
20+
}
21+
}
22+
23+
// CHECK: cir.vtable.address_point(@_ZTV1S, address_point = <index = 0, offset = 2>) : !cir.vptr

0 commit comments

Comments
 (0)