Author: Andy Kaylor Date: 2025-08-07T11:25:40-07:00 New Revision: 1e2e903684719a0bdf559af261ffff9f551f4ebb
URL: https://github.com/llvm/llvm-project/commit/1e2e903684719a0bdf559af261ffff9f551f4ebb DIFF: https://github.com/llvm/llvm-project/commit/1e2e903684719a0bdf559af261ffff9f551f4ebb.diff LOG: [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. Added: clang/test/CIR/IR/invalid-vtable.cir clang/test/CIR/IR/vtable-addrpt.cir Modified: clang/include/clang/CIR/Dialect/IR/CIRAttrs.td clang/include/clang/CIR/Dialect/IR/CIROps.td clang/include/clang/CIR/MissingFeatures.h clang/lib/CIR/Dialect/IR/CIRDialect.cpp Removed: ################################################################################ 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 = <index = 0, offset = 2>) + : !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<SymbolUserOpInterface> +]> { + 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 = <index = 0, offset = 2>) : !cir.vptr + ``` + }]; + + let arguments = (ins + FlatSymbolRefAttr:$name, + CIR_AddressPointAttr:$address_point + ); + + let results = (outs Res<CIR_VPtrType, "", []>:$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<GlobalOp>(*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(); +} + //===----------------------------------------------------------------------===// // 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<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.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<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.vptr}> + +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.vptr + %3 = cir.cast(bitcast, %1 : !cir.ptr<!rec_S>), !cir.ptr<!cir.vptr> + cir.store align(8) %2, %3 : !cir.vptr, !cir.ptr<!cir.vptr> + cir.return + } +} + +// CHECK: cir.vtable.address_point(@_ZTV1S, address_point = <index = 0, offset = 2>) : !cir.vptr _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits