Repository: llvm/clangir
Pull request #1508: [CIR] Add `AddressPointAttr`
Author: login: el-ev
Created: 2025-03-20T15:40:49Z | Merged: 2025-03-25T00:43:03Z

Part of #258 .

1. Added `AddressPointAttr`
2. Change all occurrences of `VTableAddrPointOp` into using the attribute
3. Update tests


Diff:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 68c15fb8a403..0ae6e1c4c5de 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -1407,6 +1407,36 @@ def GlobalAnnotationValuesAttr : CIR_Attr<"GlobalAnnotationValues",
   let genVerifyDecl = 1;
 }
 
+//===----------------------------------------------------------------------===//
+// AddressPointAttr
+//===----------------------------------------------------------------------===//
+
+def 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.ptr<!cir.ptr<() -> i32>>
+  ```
+  }];
+
+  let parameters = (ins "int32_t":$index,
+                        "int32_t":$offset);
+
+  let assemblyFormat = [{
+    `<` struct($index, $offset) `>`
+  }];
+}
+
 include "clang/CIR/Dialect/IR/CIRTBAAAttrs.td"
 
 include "clang/CIR/Dialect/IR/CIROpenCLAttrs.td"
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index e8a929f7a12e..979041f9c114 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2575,8 +2575,8 @@ def VTableAddrPointOp : CIR_Op<"vtable.address_point",
     (address point) of a C++ virtual table. An object internal `__vptr`
     gets initializated on top of the value returned by this operation.
 
-    `vtable_index` provides the appropriate vtable within the vtable group
-    (as specified by Itanium ABI), and `addr_point_index` the actual address
+    `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>>`.
@@ -2585,14 +2585,13 @@ def VTableAddrPointOp : CIR_Op<"vtable.address_point",
     ```mlir
     cir.global linkonce_odr @_ZTV1B = ...
     ...
-    %3 = cir.vtable.address_point(@_ZTV1B, vtable_index = 0, address_point_index = 2) : !cir.ptr<!cir.ptr<() -> i32>>
+    %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,
-                       I32Attr:$vtable_index,
-                       I32Attr:$address_point_index);
+                       AddressPointAttr:$address_point);
   let results = (outs Res<CIR_PointerType, "", []>:$addr);
 
   let assemblyFormat = [{
@@ -2600,8 +2599,7 @@ def VTableAddrPointOp : CIR_Op<"vtable.address_point",
       ($name^)?
       ($sym_addr^ `:` type($sym_addr))?
       `,`
-        `vtable_index` `=` $vtable_index `,`
-        `address_point_index` `=` $address_point_index
+        `address_point` `=` $address_point
     `)`
     `:` qualified(type($addr)) attr-dict
   }];
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 2e887647ef8a..bb342648a9af 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -950,7 +950,8 @@ CIRGenCallee CIRGenItaniumCXXABI::getVirtualFunctionPointer(
       auto VTableSlotPtr = CGF.getBuilder().create<cir::VTableAddrPointOp>(
           loc, CGF.getBuilder().getPointerTo(TyPtr),
           ::mlir::FlatSymbolRefAttr{}, VTable,
-          /*vtable_index=*/0, VTableIndex);
+          cir::AddressPointAttr::get(CGF.getBuilder().getContext(), 0,
+                                     VTableIndex));
       VFuncLoad = CGF.getBuilder().createAlignedLoad(loc, TyPtr, VTableSlotPtr,
                                                      CGF.getPointerAlign());
     }
@@ -1011,7 +1012,9 @@ CIRGenItaniumCXXABI::getVTableAddressPoint(BaseSubobject Base,
   return builder.create<cir::VTableAddrPointOp>(
       CGM.getLoc(VTableClass->getSourceRange()), vtablePtrTy,
       mlir::FlatSymbolRefAttr::get(vtable.getSymNameAttr()), mlir::Value{},
-      AddressPoint.VTableIndex, AddressPoint.AddressPointIndex);
+      cir::AddressPointAttr::get(CGM.getBuilder().getContext(),
+                                 AddressPoint.VTableIndex,
+                                 AddressPoint.AddressPointIndex));
 }
 
 mlir::Value CIRGenItaniumCXXABI::getVTableAddressPointInStructor(
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareItaniumCXXABI.cpp
index bba759494e3b..abd3bcd00d98 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareItaniumCXXABI.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareItaniumCXXABI.cpp
@@ -120,7 +120,7 @@ buildDynamicCastToVoidAfterNullCheck(CIRBaseBuilderTy &builder,
   auto vtablePtr = builder.createLoad(loc, vtablePtrPtr);
   auto offsetToTopSlotPtr = builder.create<cir::VTableAddrPointOp>(
       loc, vtablePtrTy, mlir::FlatSymbolRefAttr{}, vtablePtr,
-      /*vtable_index=*/0, -2ULL);
+      cir::AddressPointAttr::get(builder.getContext(), 0, -2));
   auto offsetToTop =
       builder.createAlignedLoad(loc, offsetToTopSlotPtr, vtableElemAlign);
 
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index c014bab10d3e..d840c7ea4067 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -3661,13 +3661,15 @@ mlir::LogicalResult CIRToLLVMVTableAddrPointOpLowering::matchAndRewrite(
   if (!symAddr) {
     symAddr = getValueForVTableSymbol(op, rewriter, getTypeConverter(),
                                       op.getNameAttr(), eltType);
-    offsets = llvm::SmallVector<mlir::LLVM::GEPArg>{0, op.getVtableIndex(),
-                                                    op.getAddressPointIndex()};
+    offsets = llvm::SmallVector<mlir::LLVM::GEPArg>{
+        0, op.getAddressPointAttr().getIndex(),
+        op.getAddressPointAttr().getOffset()};
   } else {
     // Get indirect vtable address point retrieval
     symAddr = adaptor.getSymAddr();
     eltType = converter->convertType(symAddr.getType());
-    offsets = llvm::SmallVector<mlir::LLVM::GEPArg>{op.getAddressPointIndex()};
+    offsets = llvm::SmallVector<mlir::LLVM::GEPArg>{
+        op.getAddressPointAttr().getOffset()};
   }
 
   assert(eltType && "Shouldn't ever be missing an eltType here");
diff --git a/clang/test/CIR/CodeGen/derived-to-base.cpp b/clang/test/CIR/CodeGen/derived-to-base.cpp
index c6dc92d3ac7b..5ba1dd264cbc 100644
--- a/clang/test/CIR/CodeGen/derived-to-base.cpp
+++ b/clang/test/CIR/CodeGen/derived-to-base.cpp
@@ -120,7 +120,7 @@ void vcall(C1 &c1) {
 // CHECK:   %6 = cir.load %3 : !cir.ptr<!ty_buffy>, !ty_buffy
 // CHECK:   %7 = cir.cast(bitcast, %4 : !cir.ptr<!ty_C1_>), !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>>>
 // CHECK:   %8 = cir.load %7 : !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>>>, !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>>
-// CHECK:   %9 = cir.vtable.address_point( %8 : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>>, vtable_index = 0, address_point_index = 2) : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>>
+// CHECK:   %9 = cir.vtable.address_point( %8 : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>>, address_point = <index = 0, offset = 2>) : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>>
 // CHECK:   %10 = cir.load align(8) %9 : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>>, !cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>
 // CHECK:   %11 = cir.call %10(%4, %5, %6) : (!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>, !cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i
 // CHECK:   cir.return
diff --git a/clang/test/CIR/CodeGen/dynamic-cast-exact.cpp b/clang/test/CIR/CodeGen/dynamic-cast-exact.cpp
index cb962ea437ee..df2533501faf 100644
--- a/clang/test/CIR/CodeGen/dynamic-cast-exact.cpp
+++ b/clang/test/CIR/CodeGen/dynamic-cast-exact.cpp
@@ -16,7 +16,7 @@ struct Derived final : Base1 {};
 Derived *ptr_cast(Base1 *ptr) {
   return dynamic_cast<Derived *>(ptr);
   //      CHECK: %[[#SRC:]] = cir.load %{{.+}} : !cir.ptr<!cir.ptr<!ty_Base1_>>, !cir.ptr<!ty_Base1_>
-  // CHECK-NEXT: %[[#EXPECTED_VPTR:]] = cir.vtable.address_point(@_ZTV7Derived, vtable_index = 0, address_point_index = 2) : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>
+  // CHECK-NEXT: %[[#EXPECTED_VPTR:]] = cir.vtable.address_point(@_ZTV7Derived, address_point = <index = 0, offset = 2>) : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>
   // CHECK-NEXT: %[[#SRC_VPTR_PTR:]] = cir.cast(bitcast, %[[#SRC]] : !cir.ptr<!ty_Base1_>), !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>>
   // CHECK-NEXT: %[[#SRC_VPTR:]] = cir.load %[[#SRC_VPTR_PTR]] : !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>>, !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>
   // CHECK-NEXT: %[[#SUCCESS:]] = cir.cmp(eq, %[[#SRC_VPTR]], %[[#EXPECTED_VPTR]]) : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>, !cir.bool
@@ -39,7 +39,7 @@ Derived *ptr_cast(Base1 *ptr) {
 Derived &ref_cast(Base1 &ref) {
   return dynamic_cast<Derived &>(ref);
   //      CHECK: %[[#SRC:]] = cir.load %{{.+}} : !cir.ptr<!cir.ptr<!ty_Base1_>>, !cir.ptr<!ty_Base1_>
-  // CHECK-NEXT: %[[#EXPECTED_VPTR:]] = cir.vtable.address_point(@_ZTV7Derived, vtable_index = 0, address_point_index = 2) : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>
+  // CHECK-NEXT: %[[#EXPECTED_VPTR:]] = cir.vtable.address_point(@_ZTV7Derived, address_point = <index = 0, offset = 2>) : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>
   // CHECK-NEXT: %[[#SRC_VPTR_PTR:]] = cir.cast(bitcast, %[[#SRC]] : !cir.ptr<!ty_Base1_>), !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>>
   // CHECK-NEXT: %[[#SRC_VPTR:]] = cir.load %[[#SRC_VPTR_PTR]] : !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>>, !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>
   // CHECK-NEXT: %[[#SUCCESS:]] = cir.cmp(eq, %[[#SRC_VPTR]], %[[#EXPECTED_VPTR]]) : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>, !cir.bool
diff --git a/clang/test/CIR/CodeGen/dynamic-cast-relative-layout.cpp b/clang/test/CIR/CodeGen/dynamic-cast-relative-layout.cpp
index 27cff8b2d172..c50d03fa68ed 100644
--- a/clang/test/CIR/CodeGen/dynamic-cast-relative-layout.cpp
+++ b/clang/test/CIR/CodeGen/dynamic-cast-relative-layout.cpp
@@ -21,7 +21,7 @@ void *ptr_cast_to_complete(Base *ptr) {
 // AFTER-NEXT:   %{{.+}} = cir.ternary(%[[#SRC_IS_NOT_NULL]], true {
 // AFTER-NEXT:     %[[#VPTR_PTR:]] = cir.cast(bitcast, %[[#SRC]] : !cir.ptr<!ty_Base>), !cir.ptr<!cir.ptr<!s32i>>
 // AFTER-NEXT:     %[[#VPTR:]] = cir.load %[[#VPTR_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
-// AFTER-NEXT:     %[[#OFFSET_TO_TOP_PTR:]] = cir.vtable.address_point( %[[#VPTR]] : !cir.ptr<!s32i>, vtable_index = 0, address_point_index = -2) : !cir.ptr<!s32i>
+// AFTER-NEXT:     %[[#OFFSET_TO_TOP_PTR:]] = cir.vtable.address_point( %[[#VPTR]] : !cir.ptr<!s32i>,  address_point = <index = 0, offset = -2>) : !cir.ptr<!s32i>
 // AFTER-NEXT:     %[[#OFFSET_TO_TOP:]] = cir.load align(4) %[[#OFFSET_TO_TOP_PTR]] : !cir.ptr<!s32i>, !s32i
 // AFTER-NEXT:     %[[#SRC_BYTES_PTR:]] = cir.cast(bitcast, %[[#SRC]] : !cir.ptr<!ty_Base>), !cir.ptr<!u8i>
 // AFTER-NEXT:     %[[#DST_BYTES_PTR:]] = cir.ptr_stride(%[[#SRC_BYTES_PTR]] : !cir.ptr<!u8i>, %[[#OFFSET_TO_TOP]] : !s32i), !cir.ptr<!u8i>
diff --git a/clang/test/CIR/CodeGen/dynamic-cast.cpp b/clang/test/CIR/CodeGen/dynamic-cast.cpp
index 2d1393b4a582..ba3208b907b7 100644
--- a/clang/test/CIR/CodeGen/dynamic-cast.cpp
+++ b/clang/test/CIR/CodeGen/dynamic-cast.cpp
@@ -73,7 +73,7 @@ void *ptr_cast_to_complete(Base *ptr) {
 // AFTER-NEXT:   %{{.+}} = cir.ternary(%[[#SRC_IS_NOT_NULL]], true {
 // AFTER-NEXT:     %[[#VPTR_PTR:]] = cir.cast(bitcast, %[[#SRC]] : !cir.ptr<!ty_Base>), !cir.ptr<!cir.ptr<!s64i>>
 // AFTER-NEXT:     %[[#VPTR:]] = cir.load %[[#VPTR_PTR]] : !cir.ptr<!cir.ptr<!s64i>>, !cir.ptr<!s64i>
-// AFTER-NEXT:     %[[#BASE_OFFSET_PTR:]] = cir.vtable.address_point( %[[#VPTR]] : !cir.ptr<!s64i>, vtable_index = 0, address_point_index = -2) : !cir.ptr<!s64i>
+// AFTER-NEXT:     %[[#BASE_OFFSET_PTR:]] = cir.vtable.address_point( %[[#VPTR]] : !cir.ptr<!s64i>, address_point = <index = 0, offset = -2>) : !cir.ptr<!s64i>
 // AFTER-NEXT:     %[[#BASE_OFFSET:]] = cir.load align(8) %[[#BASE_OFFSET_PTR]] : !cir.ptr<!s64i>, !s64i
 // AFTER-NEXT:     %[[#SRC_BYTES_PTR:]] = cir.cast(bitcast, %[[#SRC]] : !cir.ptr<!ty_Base>), !cir.ptr<!u8i>
 // AFTER-NEXT:     %[[#DST_BYTES_PTR:]] = cir.ptr_stride(%[[#SRC_BYTES_PTR]] : !cir.ptr<!u8i>, %[[#BASE_OFFSET]] : !s64i), !cir.ptr<!u8i>
diff --git a/clang/test/CIR/CodeGen/vtable-rtti.cpp b/clang/test/CIR/CodeGen/vtable-rtti.cpp
index 3c8a5253c526..b9857a58b38c 100644
--- a/clang/test/CIR/CodeGen/vtable-rtti.cpp
+++ b/clang/test/CIR/CodeGen/vtable-rtti.cpp
@@ -45,7 +45,7 @@ class B : public A
 // CHECK:   %1 = cir.load %0 : !cir.ptr<!cir.ptr<![[ClassB]]>>, !cir.ptr<![[ClassB]]>
 // CHECK:   %2 = cir.base_class_addr(%1 : !cir.ptr<![[ClassB]]> nonnull) [0] -> !cir.ptr<![[ClassA]]>
 // CHECK:   cir.call @_ZN1AC2Ev(%2) : (!cir.ptr<![[ClassA]]>) -> ()
-// CHECK:   %3 = cir.vtable.address_point(@_ZTV1B, vtable_index = 0, address_point_index = 2) : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>
+// CHECK:   %3 = cir.vtable.address_point(@_ZTV1B, address_point = <index = 0, offset = 2>) : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>
 // CHECK:   %4 = cir.cast(bitcast, %1 : !cir.ptr<![[ClassB]]>), !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>>
 // CHECK:   cir.store %3, %4 : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>, !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>>
 // CHECK:   cir.return
@@ -73,7 +73,7 @@ class B : public A
 // CHECK:    %0 = cir.alloca !cir.ptr<![[ClassA]]>, !cir.ptr<!cir.ptr<![[ClassA]]>>, ["this", init] {alignment = 8 : i64}
 // CHECK:    cir.store %arg0, %0 : !cir.ptr<![[ClassA]]>, !cir.ptr<!cir.ptr<![[ClassA]]>>
 // CHECK:    %1 = cir.load %0 : !cir.ptr<!cir.ptr<![[ClassA]]>>, !cir.ptr<![[ClassA]]>
-// CHECK:    %2 = cir.vtable.address_point(@_ZTV1A, vtable_index = 0, address_point_index = 2) : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>
+// CHECK:    %2 = cir.vtable.address_point(@_ZTV1A, address_point = <index = 0, offset = 2>) : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>
 // CHECK:    %3 = cir.cast(bitcast, %1 : !cir.ptr<![[ClassA]]>), !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>>
 // CHECK:    cir.store %2, %3 : !cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>, !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>>
 // CHECK:    cir.return


Reviews:
user: login: bcardosolopes
body: LGTM after minor nits (also please rebase to eliminate the unrelated errors)
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-20T21:14:53Z
user: login: bcardosolopes
body: Same comment from your other PR, you likely need some rebasing
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-24T18:09:55Z
user: login: bcardosolopes
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-25T00:42:58Z

Review comments:
diff_hunk: @@ -1407,6 +1407,36 @@ def GlobalAnnotationValuesAttr : CIR_Attr<"GlobalAnnotationValues",
   let genVerifyDecl = 1;
 }
 
+//===----------------------------------------------------------------------===//
+// AddressPointAttr
+//===----------------------------------------------------------------------===//
+
+def 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 `vtable_index` parameter identifies which vtable to use within a vtable
+  group, while the `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 = (0, 2)) : !cir.ptr<!cir.ptr<() -> i32>>
+  ```
+  }];
+
+  let parameters = (ins "int32_t":$vtable_index,
+                        "int32_t":$address_point_index);
+
+  let assemblyFormat = [{
+    `(` $vtable_index `,` $address_point_index `)`
path: clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
user: login: bcardosolopes
body: Please use: "\`<\` struct($vtable_index, $address_point_index) \`>\`"
created_at: 2025-03-20T21:09:15Z
author_association: MEMBER
diff_hunk: @@ -1407,6 +1407,36 @@ def GlobalAnnotationValuesAttr : CIR_Attr<"GlobalAnnotationValues",
   let genVerifyDecl = 1;
 }
 
+//===----------------------------------------------------------------------===//
+// AddressPointAttr
+//===----------------------------------------------------------------------===//
+
+def 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 `vtable_index` parameter identifies which vtable to use within a vtable
+  group, while the `address_point_index` specifies the offset within
+  that vtable where the address begins.
path: clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
user: login: bcardosolopes
body: Because the attribute name contains "address point", let's rename the operands a bit, how about:
- vtable_index -> `index`
- address_point_index -> `offset`
You can keep the original names in the desc, example: "The \`index`\ (vtable index) parameter identifies ...", same for the other one.
created_at: 2025-03-20T21:14:12Z
author_association: MEMBER

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-20T16:28:33Z
body: <!--LLVM CODE FORMAT COMMENT: {clang-format}-->

:white_check_mark: With the latest revision this PR passed the C/C++ code formatter.
author_association: NONE
user: login: bcardosolopes
created_at: 2025-03-20T21:15:12Z
body: clang-format issues need to be addressed too!
author_association: MEMBER
user: login: el-ev
created_at: 2025-03-24T03:03:40Z
body: @bcardosolopes  It seems `GlobalViewAttr` isn't exactly using two indices. Should we create a new attribute for it?
author_association: MEMBER
user: login: bcardosolopes
created_at: 2025-03-24T18:11:10Z
body: > @bcardosolopes It seems `GlobalViewAttr` isn't exactly using two indices. Should we create a new attribute for it?

global view is able to more/less work like a GEP, so they are more generic than address points abstraction
author_association: MEMBER