diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 588fb0d74a509..3d34d77184a4d 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -516,4 +516,36 @@ def CIR_BitfieldInfoAttr : CIR_Attr<"BitfieldInfo", "bitfield_info"> { ]; } +//===----------------------------------------------------------------------===// +// AddressPointAttr +//===----------------------------------------------------------------------===// + +def CIR_AddressPointAttr : CIR_Attr<"AddressPoint", "address_point"> { + 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 = ) + : !cir.vptr + ``` + }]; + + let parameters = (ins "int32_t":$index, + "int32_t":$offset); + + let assemblyFormat = [{ + `<` struct($index, $offset) `>` + }]; +} + #endif // CLANG_CIR_DIALECT_IR_CIRATTRS_TD diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 72841a1c08441..32813c1a4f43a 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1691,6 +1691,49 @@ def CIR_GetGlobalOp : CIR_Op<"get_global", [ }]; } +//===----------------------------------------------------------------------===// +// VTableAddrPointOp +//===----------------------------------------------------------------------===// + +def CIR_VTableAddrPointOp : CIR_Op<"vtable.address_point", [ + Pure, DeclareOpInterfaceMethods +]> { + 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 `!cir.vptr`. + + Example: + ```mlir + cir.global linkonce_odr @_ZTV1B = ... + ... + %3 = cir.vtable.address_point(@_ZTV1B, + address_point = ) : !cir.vptr + ``` + }]; + + let arguments = (ins + FlatSymbolRefAttr:$name, + CIR_AddressPointAttr:$address_point + ); + + let results = (outs Res:$addr); + + let assemblyFormat = [{ + `(` + $name `,` `address_point` `=` $address_point + `)` + `:` qualified(type($addr)) attr-dict + }]; +} + //===----------------------------------------------------------------------===// // SetBitfieldOp //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 27dd181f2fb37..adf3f08269268 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -253,6 +253,7 @@ struct MissingFeatures { static bool thunks() { return false; } static bool tryEmitAsConstant() { return false; } static bool typeChecks() { return false; } + static bool vtableInitializer() { return false; } static bool weakRefReference() { return false; } static bool writebacks() { return false; } static bool appleKext() { return false; } diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index d3fcac1edeb5a..53ab04eb85385 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -1443,6 +1443,27 @@ cir::GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) { return success(); } +//===----------------------------------------------------------------------===// +// VTableAddrPointOp +//===----------------------------------------------------------------------===// + +LogicalResult +cir::VTableAddrPointOp::verifySymbolUses(SymbolTableCollection &symbolTable) { + 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 = symbolTable.lookupNearestSymbolFrom(*this, getNameAttr()); + if (!op) + return emitOpError("'") + << name << "' does not reference a valid cir.global"; + std::optional init = op.getInitialValue(); + if (!init) + return success(); + assert(!cir::MissingFeatures::vtableInitializer()); + return success(); +} + //===----------------------------------------------------------------------===// // FuncOp //===----------------------------------------------------------------------===// diff --git a/clang/test/CIR/IR/invalid-vtable.cir b/clang/test/CIR/IR/invalid-vtable.cir new file mode 100644 index 0000000000000..b3afb581b2048 --- /dev/null +++ b/clang/test/CIR/IR/invalid-vtable.cir @@ -0,0 +1,9 @@ +// RUN: cir-opt %s -verify-diagnostics + +!s8i = !cir.int +!u32i = !cir.int +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 = ) : !cir.vptr + cir.return +} diff --git a/clang/test/CIR/IR/vtable-addrpt.cir b/clang/test/CIR/IR/vtable-addrpt.cir new file mode 100644 index 0000000000000..0b809cc2506e6 --- /dev/null +++ b/clang/test/CIR/IR/vtable-addrpt.cir @@ -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 +!u8i = !cir.int +!rec_anon_struct = !cir.record x 4>}> +!rec_S = !cir.record + +module { + cir.global "private" external @_ZTV1S : !rec_anon_struct {alignment = 8 : i64} + cir.func @_ZN1SC2Ev(%arg0: !cir.ptr) { + %0 = cir.alloca !cir.ptr, !cir.ptr>, ["this", init] {alignment = 8 : i64} + cir.store %arg0, %0 : !cir.ptr, !cir.ptr> + %1 = cir.load %0 : !cir.ptr>, !cir.ptr + %2 = cir.vtable.address_point(@_ZTV1S, address_point = ) : !cir.vptr + %3 = cir.cast(bitcast, %1 : !cir.ptr), !cir.ptr + cir.store align(8) %2, %3 : !cir.vptr, !cir.ptr + cir.return + } +} + +// CHECK: cir.vtable.address_point(@_ZTV1S, address_point = ) : !cir.vptr