Author: Erich Keane
Date: 2026-02-03T12:54:28-08:00
New Revision: 3db2fd8bf0f3f0726bf8a32fe59e6b131f2e1b8e

URL: 
https://github.com/llvm/llvm-project/commit/3db2fd8bf0f3f0726bf8a32fe59e6b131f2e1b8e
DIFF: 
https://github.com/llvm/llvm-project/commit/3db2fd8bf0f3f0726bf8a32fe59e6b131f2e1b8e.diff

LOG: [CIR] Implement 'allocsize' function/call attribute lowering (#179342)

The alloc_size attribute takes the argument number(normalized to the
    index!) of the element size and count, for things like 'malloc' or
'calloc'.

This ends up being slightly more complicated than others, as this has
data that we have to decide on a format for. LLVM chooses to pack both
of these 32 bit values into a single i64, but unpacks it for the purpose
of input/output. The second value, the number of elements, is optional.

This patch uses a DenseI32ArrayAttr to store them for the LLVMIR
dialect, which gets us the packed nature, but doesn't require us doing
any work to unpack it.

Added: 
    clang/test/CIR/CodeGen/alloc-size.c

Modified: 
    clang/include/clang/CIR/Dialect/IR/CIRDialect.td
    clang/lib/CIR/CodeGen/CIRGenCall.cpp
    clang/test/CIR/CodeGen/coro-task.cpp
    clang/test/CIR/CodeGen/new.cpp
    clang/test/CIR/CodeGenBuiltins/builtin_new_delete.cpp
    mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
    mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
    mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
    mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
    mlir/lib/Target/LLVMIR/ModuleImport.cpp
    mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
    mlir/test/Dialect/LLVMIR/func.mlir
    mlir/test/Dialect/LLVMIR/roundtrip.mlir
    mlir/test/Target/LLVMIR/Import/function-attributes.ll
    mlir/test/Target/LLVMIR/Import/instructions.ll
    mlir/test/Target/LLVMIR/llvmir.mlir

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td 
b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index bbd9831e73a50..c06807efbb83a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -53,6 +53,7 @@ def CIR_Dialect : Dialect {
     static llvm::StringRef getOperandSegmentSizesAttrName() { return 
"operandSegmentSizes"; }
     static llvm::StringRef getNoCallerSavedRegsAttrName() { return 
"no_caller_saved_registers"; }
     static llvm::StringRef getNoCallbackAttrName() { return "nocallback"; }
+    static llvm::StringRef getAllocSizeAttrName() { return "allocsize"; }
     // Note: we have to name this with the underscore instead of the dash like
     // traditional LLVM-IR does, because the LLVM-IR-Dialect doesn't have a way
     // of forming names with a dash instead of underscore in its auto-generated

diff  --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 7a1efb2ace010..abc4dd9b3c160 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -246,11 +246,20 @@ void CIRGenModule::constructAttributeList(llvm::StringRef 
name,
 
     // TODO(cir): Detecting 'OptimizeNone' is done here in classic codegen, 
when
     // we figure out when to do that, we should do it here.
-    // TODO(cir): AllocSize attr should be done here, but it has some 
additional
-    // work with forming the correct value for it.  Typically this calls into
-    // LLVM to set it correctly, which flattens the elem size and num-elems 
into
-    // a single value.  CIR should probably represent these as two values and
-    // handle the combination during lowering by calling into LLVM.
+
+    if (auto *allocSizeAttr = targetDecl->getAttr<AllocSizeAttr>()) {
+      unsigned size = allocSizeAttr->getElemSizeParam().getLLVMIndex();
+
+      if (allocSizeAttr->getNumElemsParam().isValid()) {
+        unsigned numElts = allocSizeAttr->getNumElemsParam().getLLVMIndex();
+        attrs.set(cir::CIRDialect::getAllocSizeAttrName(),
+                  builder.getDenseI32ArrayAttr(
+                      {static_cast<int>(size), static_cast<int>(numElts)}));
+      } else {
+        attrs.set(cir::CIRDialect::getAllocSizeAttrName(),
+                  builder.getDenseI32ArrayAttr({static_cast<int>(size)}));
+      }
+    }
 
     // TODO(cir): Quite a few CUDA and OpenCL attributes are added here, like
     // uniform-work-group-size.

diff  --git a/clang/test/CIR/CodeGen/alloc-size.c 
b/clang/test/CIR/CodeGen/alloc-size.c
new file mode 100644
index 0000000000000..17b548c369217
--- /dev/null
+++ b/clang/test/CIR/CodeGen/alloc-size.c
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+
+#define NULL ((void *)0)
+
+typedef unsigned long size_t;
+
+// CIR: cir.func{{.*}}@my_malloc(!s32i){{.*}} attributes {allocsize = 
array<i32: 0>}
+extern void *my_malloc(int) __attribute__((alloc_size(1)));
+// CIR: cir.func{{.*}}@my_calloc(!s32i, !s32i){{.*}} attributes {allocsize = 
array<i32: 0, 1>}
+extern void *my_calloc(int, int) __attribute__((alloc_size(1, 2)));
+
+// CIR-LABEL: @call_direct
+// LLVM-LABEL: @call_direct
+void call_direct(void) {
+  my_malloc(50);
+  // CIR: cir.call @my_malloc(%{{.*}}) {allocsize = array<i32: 0>}
+  // LLVM: call ptr @my_malloc(i32{{.*}} 50) [[DIRECT_MALLOC_ATTR:#[0-9]+]]
+  my_calloc(1, 16);
+  // CIR: cir.call @my_calloc(%{{.*}}) {allocsize = array<i32: 0, 1>}
+  // LLVM: call ptr @my_calloc(i32{{.*}} 1, i32{{.*}} 16) 
[[DIRECT_CALLOC_ATTR:#[0-9]+]]
+}
+
+extern void *(*malloc_function_pointer)(void *, 
int)__attribute__((alloc_size(2)));
+extern void *(*calloc_function_pointer)(void *, int, 
int)__attribute__((alloc_size(2, 3)));
+
+// CIR-LABEL: @call_function_pointer
+// LLVM-LABEL: @call_function_pointer
+void call_function_pointer(void) {
+  malloc_function_pointer(NULL, 100);
+  // CIR: %[[MALLOC_FN_PTR_GLOBAL:.*]] = cir.get_global 
@malloc_function_pointer
+  // CIR: %[[MALLOC_FN_PTR:.+]] = cir.load{{.*}}%[[MALLOC_FN_PTR_GLOBAL]]
+  // CIR: cir.call %[[MALLOC_FN_PTR]]({{.*}}) {allocsize = array<i32: 1>}
+  //
+  // LLVM: %[[MALLOC_FN_PTR:.+]] = load ptr, ptr @malloc_function_pointer, 
align 8
+  // LLVM: call ptr %[[MALLOC_FN_PTR]](ptr{{.*}} null, i32{{.*}} 100) 
[[INDIRECT_MALLOC_ATTR:#[0-9]+]]
+  calloc_function_pointer(NULL, 2, 4);
+  // CIR: %[[CALLOC_FN_PTR_GLOBAL:.*]] = cir.get_global 
@calloc_function_pointer
+  // CIR: %[[CALLOC_FN_PTR:.+]] = cir.load{{.*}}%[[CALLOC_FN_PTR_GLOBAL]]
+  // CIR: cir.call %[[CALLOC_FN_PTR]]({{.*}}) {allocsize = array<i32: 1, 2>}
+  //
+  // LLVM: %[[CALLOC_FN_PTR:.+]] = load ptr, ptr @calloc_function_pointer, 
align 8
+  // LLVM: call ptr %[[CALLOC_FN_PTR]](ptr{{.*}} null, i32{{.*}} 2, i32{{.*}} 
4) [[INDIRECT_CALLOC_ATTR:#[0-9]+]]
+}
+
+typedef void *(__attribute__((alloc_size(3))) * 
my_malloc_fn_pointer_type)(void *, void *, int);
+typedef void *(__attribute__((alloc_size(3, 4))) * 
my_calloc_fn_pointer_type)(void *, void *, int, int);
+extern my_malloc_fn_pointer_type malloc_function_pointer_with_typedef;
+extern my_calloc_fn_pointer_type calloc_function_pointer_with_typedef;
+
+// CIR-LABEL: @call_function_pointer_typedef
+// LLVM-LABEL: @call_function_pointer_typedef
+void call_function_pointer_typedef(void) {
+  malloc_function_pointer_with_typedef(NULL, NULL, 200);
+  // CIR: %[[INDIRECT_TYPEDEF_MALLOC_FN_PTR_GLOBAL:.*]] = cir.get_global 
@malloc_function_pointer_with_typedef
+  // CIR: %[[INDIRECT_TYPEDEF_MALLOC_FN_PTR:.+]] = 
cir.load{{.*}}%[[INDIRECT_TYPEDEF_MALLOC_FN_PTR_GLOBAL]]
+  // CIR: cir.call %[[INDIRECT_TYPEDEF_MALLOC_FN_PTR]]({{.*}}) {allocsize = 
array<i32: 2>}
+  //
+  // LLVM: %[[INDIRECT_TYPEDEF_MALLOC_FN_PTR:.+]] = load ptr, ptr 
@malloc_function_pointer_with_typedef, align 8
+  // LLVM: call ptr %[[INDIRECT_TYPEDEF_MALLOC_FN_PTR]](ptr{{.*}} null, 
ptr{{.*}} null, i32{{.*}} 200) [[INDIRECT_TYPEDEF_MALLOC_ATTR:#[0-9]+]]
+  calloc_function_pointer_with_typedef(NULL, NULL, 8, 4);
+  // CIR: %[[INDIRECT_TYPEDEF_CALLOC_FN_PTR_GLOBAL:.*]] = cir.get_global 
@calloc_function_pointer_with_typedef
+  // CIR: %[[INDIRECT_TYPEDEF_CALLOC_FN_PTR:.+]] = 
cir.load{{.*}}%[[INDIRECT_TYPEDEF_CALLOC_FN_PTR_GLOBAL]]
+  // CIR: cir.call %[[INDIRECT_TYPEDEF_CALLOC_FN_PTR]]({{.*}}) {allocsize = 
array<i32: 2, 3>}
+  //
+  // LLVM: %[[INDIRECT_TYPEDEF_CALLOC_FN_PTR:.+]] = load ptr, ptr 
@calloc_function_pointer_with_typedef, align 8
+  // LLVM: call ptr %[[INDIRECT_TYPEDEF_CALLOC_FN_PTR]](ptr{{.*}} null, 
ptr{{.*}} null, i32{{.*}} 8, i32{{.*}} 4) 
[[INDIRECT_TYPEDEF_CALLOC_ATTR:#[0-9]+]]
+}
+
+// LLVM: attributes [[DIRECT_MALLOC_ATTR]] = { allocsize(0) }
+// LLVM: attributes [[DIRECT_CALLOC_ATTR]] = { allocsize(0,1) }
+// LLVM: attributes [[INDIRECT_MALLOC_ATTR]] = { allocsize(1) }
+// LLVM: attributes [[INDIRECT_CALLOC_ATTR]] = { allocsize(1,2) }
+// LLVM: attributes [[INDIRECT_TYPEDEF_MALLOC_ATTR]] = { allocsize(2) }
+// LLVM: attributes [[INDIRECT_TYPEDEF_CALLOC_ATTR]] = { allocsize(2,3) }

diff  --git a/clang/test/CIR/CodeGen/coro-task.cpp 
b/clang/test/CIR/CodeGen/coro-task.cpp
index c7072daa051e5..0a2b49345e628 100644
--- a/clang/test/CIR/CodeGen/coro-task.cpp
+++ b/clang/test/CIR/CodeGen/coro-task.cpp
@@ -173,7 +173,7 @@ VoidTask silly_task() {
 // CIR: cir.store{{.*}} %[[NullPtr]], %[[SavedFrameAddr]] : !cir.ptr<!void>, 
!cir.ptr<!cir.ptr<!void>>
 // CIR: cir.if %[[ShouldAlloc]] {
 // CIR:   %[[CoroSize:.*]] = cir.call @__builtin_coro_size() : () -> !u64i
-// CIR:   %[[AllocAddr:.*]] = cir.call @_Znwm(%[[CoroSize]]) : (!u64i) -> 
!cir.ptr<!void>
+// CIR:   %[[AllocAddr:.*]] = cir.call @_Znwm(%[[CoroSize]]) {allocsize = 
array<i32: 0>} : (!u64i) -> !cir.ptr<!void>
 // CIR:   cir.store{{.*}} %[[AllocAddr]], %[[SavedFrameAddr]] : 
!cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
 // CIR: }
 // CIR: %[[Load0:.*]] = cir.load{{.*}} %[[SavedFrameAddr]] : 
!cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>

diff  --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp
index 9f454770e3960..ed6f5b6450fb2 100644
--- a/clang/test/CIR/CodeGen/new.cpp
+++ b/clang/test/CIR/CodeGen/new.cpp
@@ -160,7 +160,7 @@ void test_new_with_complex_type() {
 // CHECK: cir.func{{.*}} @_Z26test_new_with_complex_typev
 // CHECK:   %[[A_ADDR:.*]] = cir.alloca !cir.ptr<!cir.complex<!cir.float>>, 
!cir.ptr<!cir.ptr<!cir.complex<!cir.float>>>, ["a", init]
 // CHECK:   %[[COMPLEX_SIZE:.*]] = cir.const #cir.int<8> : !u64i
-// CHECK:   %[[NEW_COMPLEX:.*]] = cir.call @_Znwm(%[[COMPLEX_SIZE]]) : (!u64i) 
-> !cir.ptr<!void>
+// CHECK:   %[[NEW_COMPLEX:.*]] = cir.call @_Znwm(%[[COMPLEX_SIZE]]) 
{allocsize = array<i32: 0>} : (!u64i) -> !cir.ptr<!void>
 // CHECK:   %[[COMPLEX_PTR:.*]] = cir.cast bitcast %[[NEW_COMPLEX]] : 
!cir.ptr<!void> -> !cir.ptr<!cir.complex<!cir.float>>
 // CHECK:   %[[COMPLEX_VAL:.*]] = cir.const 
#cir.const_complex<#cir.fp<1.000000e+00> : !cir.float, #cir.fp<2.000000e+00> : 
!cir.float> : !cir.complex<!cir.float>
 // CHECK:   cir.store{{.*}} %[[COMPLEX_VAL]], %[[COMPLEX_PTR]] : 
!cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
@@ -188,7 +188,7 @@ void t_new_constant_size() {
 // CHECK:   cir.func{{.*}} @_Z19t_new_constant_sizev()
 // CHECK:    %[[P_ADDR:.*]] = cir.alloca !cir.ptr<!cir.double>, 
!cir.ptr<!cir.ptr<!cir.double>>, ["p", init] {alignment = 8 : i64}
 // CHECK:    %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<128> : !u64i
-// CHECK:    %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) 
-> !cir.ptr<!void>
+// CHECK:    %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) 
{allocsize = array<i32: 0>} : (!u64i) -> !cir.ptr<!void>
 // CHECK:    %[[TYPED_PTR:.*]] = cir.cast bitcast %[[RAW_PTR]] : 
!cir.ptr<!void> -> !cir.ptr<!cir.double>
 // CHECK:    cir.store align(8) %[[TYPED_PTR]], %[[P_ADDR]] : 
!cir.ptr<!cir.double>, !cir.ptr<!cir.ptr<!cir.double>>
 // CHECK:    cir.return
@@ -217,7 +217,7 @@ void t_constant_size_nontrivial() {
 // CHECK:    %[[P_ADDR:.*]] = cir.alloca !cir.ptr<!rec_C>, 
!cir.ptr<!cir.ptr<!rec_C>>, ["p", init] {alignment = 8 : i64}
 // CHECK:    %[[NUM_ELEMENTS:.*]] = cir.const #cir.int<3> : !u64i
 // CHECK:    %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<11> : !u64i
-// CHECK:    %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) 
-> !cir.ptr<!void>
+// CHECK:    %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) 
{allocsize = array<i32: 0>} : (!u64i) -> !cir.ptr<!void>
 // CHECK:    %[[COOKIE_PTR_BASE:.*]] = cir.cast bitcast %[[RAW_PTR]] : 
!cir.ptr<!void> -> !cir.ptr<!cir.ptr<!u8i>>
 // CHECK:    %[[COOKIE_PTR:.*]] = cir.cast bitcast %[[COOKIE_PTR_BASE]] : 
!cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!u64i>
 // CHECK:    cir.store align(8) %[[NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, 
!cir.ptr<!u64i>
@@ -257,7 +257,7 @@ void t_constant_size_nontrivial2() {
 // CHECK:    %[[P_ADDR:.*]] = cir.alloca !cir.ptr<!rec_D>, 
!cir.ptr<!cir.ptr<!rec_D>>, ["p", init] {alignment = 8 : i64}
 // CHECK:    %[[NUM_ELEMENTS:.*]] = cir.const #cir.int<3> : !u64i
 // CHECK:    %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<20> : !u64i
-// CHECK:    %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) 
-> !cir.ptr<!void>
+// CHECK:    %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) 
{allocsize = array<i32: 0>} : (!u64i) -> !cir.ptr<!void>
 // CHECK:    %[[COOKIE_PTR_BASE:.*]] = cir.cast bitcast %[[RAW_PTR]] : 
!cir.ptr<!void> -> !cir.ptr<!cir.ptr<!u8i>>
 // CHECK:    %[[COOKIE_PTR:.*]] = cir.cast bitcast %[[COOKIE_PTR_BASE]] : 
!cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!u64i>
 // CHECK:    cir.store align(8) %[[NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, 
!cir.ptr<!u64i>
@@ -289,7 +289,7 @@ void t_align16_nontrivial() {
 // CHECK:    %[[P_ADDR:.*]] = cir.alloca !cir.ptr<!rec_E>, 
!cir.ptr<!cir.ptr<!rec_E>>, ["p", init] {alignment = 8 : i64}
 // CHECK:    %[[NUM_ELEMENTS:.*]] = cir.const #cir.int<2> : !u64i
 // CHECK:    %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<48> : !u64i
-// CHECK:    %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) 
-> !cir.ptr<!void>
+// CHECK:    %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) 
{allocsize = array<i32: 0>} : (!u64i) -> !cir.ptr<!void>
 // CHECK:    %[[COOKIE_PTR_BASE:.*]] = cir.cast bitcast %[[RAW_PTR]] : 
!cir.ptr<!void> -> !cir.ptr<!cir.ptr<!u8i>>
 // CHECK:    %[[COOKIE_OFFSET:.*]] = cir.const #cir.int<8> : !s32i
 // CHECK:    %[[COOKIE_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], 
%[[COOKIE_OFFSET]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> 
!cir.ptr<!cir.ptr<!u8i>>
@@ -327,7 +327,7 @@ void t_new_multidim_constant_size() {
 // CHECK:  cir.func{{.*}} @_Z28t_new_multidim_constant_sizev()
 // CHECK:    %[[P_ADDR:.*]] = cir.alloca 
!cir.ptr<!cir.array<!cir.array<!cir.double x 4> x 3>>, 
!cir.ptr<!cir.ptr<!cir.array<!cir.array<!cir.double x 4> x 3>>>, ["p", init] 
{alignment = 8 : i64}
 // CHECK:    %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<192> : !u64i
-// CHECK:    %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) 
-> !cir.ptr<!void>
+// CHECK:    %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) 
{allocsize = array<i32: 0>} : (!u64i) -> !cir.ptr<!void>
 // CHECK:    %[[TYPED_PTR:.*]] = cir.cast bitcast %[[RAW_PTR]] : 
!cir.ptr<!void> -> !cir.ptr<!cir.array<!cir.array<!cir.double x 4> x 3>>
 // CHECK:    cir.store align(8) %[[TYPED_PTR]], %[[P_ADDR]] : 
!cir.ptr<!cir.array<!cir.array<!cir.double x 4> x 3>>, 
!cir.ptr<!cir.ptr<!cir.array<!cir.array<!cir.double x 4> x 3>>>
 // CHECK:  }
@@ -348,7 +348,7 @@ void t_constant_size_memset_init() {
 
 // CHECK:  cir.func {{.*}} @_Z27t_constant_size_memset_initv()
 // CHECK:    %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<64> : !u64i
-// CHECK:    %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : 
(!u64i) -> !cir.ptr<!void>
+// CHECK:    %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) 
{allocsize = array<i32: 0>} : (!u64i) -> !cir.ptr<!void>
 // CHECK:    %[[ELEM_PTR:.*]] = cir.cast bitcast %[[ALLOC_PTR]] : 
!cir.ptr<!void> -> !cir.ptr<!s32i>
 // CHECK:    %[[VOID_PTR:.*]] = cir.cast bitcast %[[ELEM_PTR]] : 
!cir.ptr<!s32i> -> !cir.ptr<!void>
 // CHECK:    %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i

diff  --git a/clang/test/CIR/CodeGenBuiltins/builtin_new_delete.cpp 
b/clang/test/CIR/CodeGenBuiltins/builtin_new_delete.cpp
index d540bfcf8a36d..52f1599a75e94 100644
--- a/clang/test/CIR/CodeGenBuiltins/builtin_new_delete.cpp
+++ b/clang/test/CIR/CodeGenBuiltins/builtin_new_delete.cpp
@@ -9,7 +9,7 @@
 void test_builtins_basic() {
   __builtin_operator_delete(__builtin_operator_new(4));
   // CIR-LABEL: test_builtins_basic
-  // CIR: [[P:%.*]] = cir.call @_Znwm({{%.*}}) : (!u64i) -> !cir.ptr<!void>
+  // CIR: [[P:%.*]] = cir.call @_Znwm({{%.*}}) {allocsize = array<i32: 0>} : 
(!u64i) -> !cir.ptr<!void>
   // CIR: cir.call @_ZdlPv([[P]]) {{.*}}: (!cir.ptr<!void>) -> ()
   // CIR: cir.return
 
@@ -28,7 +28,7 @@ void test_sized_delete() {
   __builtin_operator_delete(__builtin_operator_new(4), 4);
 
   // CIR-LABEL: test_sized_delete
-  // CIR: [[P:%.*]] = cir.call @_Znwm({{%.*}}) : (!u64i) -> !cir.ptr<!void>
+  // CIR: [[P:%.*]] = cir.call @_Znwm({{%.*}}) {allocsize = array<i32: 0>} : 
(!u64i) -> !cir.ptr<!void>
   // CIR: cir.call @_ZdlPvm([[P]], {{%.*}}) {{.*}}: (!cir.ptr<!void>, !u64i) 
-> ()
   // CIR: cir.return
 

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td 
b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index e2358dcf1ed4c..a03a933eed370 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -800,6 +800,7 @@ def LLVM_CallOp
       UnitAttr:$no_caller_saved_registers, UnitAttr:$nocallback,
       OptionalAttr<StrAttr>:$modular_format,
       OptionalAttr<ArrayAttr>:$nobuiltins,
+      OptionalAttr<DenseI32ArrayAttr>:$allocsize,
       VariadicOfVariadic<LLVM_Type, "op_bundle_sizes">:$op_bundle_operands,
       DenseI32ArrayAttr:$op_bundle_sizes,
       OptionalAttr<ArrayAttr>:$op_bundle_tags,
@@ -2007,6 +2008,7 @@ def LLVM_LLVMFuncOp : LLVM_Op<"func", [
     OptionalAttr<UnitAttr>:$nocallback,
     OptionalAttr<StrAttr>:$modular_format,
     OptionalAttr<ArrayAttr>:$nobuiltins,
+    OptionalAttr<DenseI32ArrayAttr>:$allocsize,
     OptionalAttr<LLVM_VecTypeHintAttr>:$vec_type_hint,
     OptionalAttr<DenseI32ArrayAttr>:$work_group_size_hint,
     OptionalAttr<DenseI32ArrayAttr>:$reqd_work_group_size,

diff  --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h 
b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
index a9b6a58b30e10..349c0f8810a47 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -370,6 +370,8 @@ class ModuleTranslation {
     }
   }
 
+  llvm::Attribute convertAllocsizeAttr(DenseI32ArrayAttr allocsizeAttr);
+
 private:
   ModuleTranslation(Operation *module,
                     std::unique_ptr<llvm::Module> llvmModule);

diff  --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp 
b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 34d0de078e553..d4573060eca25 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -999,6 +999,7 @@ void CallOp::build(OpBuilder &builder, OperationState 
&state, TypeRange results,
         /*cold=*/nullptr, /*noduplicate=*/nullptr,
         /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr,
         /*modular_format=*/nullptr, /*nobuiltins=*/nullptr,
+        /*alloc_size=*/nullptr,
         /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
         /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
         /*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
@@ -1034,6 +1035,7 @@ void CallOp::build(OpBuilder &builder, OperationState 
&state,
         /*cold=*/nullptr, /*noduplicate=*/nullptr,
         /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr,
         /*modular_format=*/nullptr, /*nobuiltins=*/nullptr,
+        /*alloc_size=*/nullptr,
         /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
         /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
         /*access_groups=*/nullptr,
@@ -1055,6 +1057,7 @@ void CallOp::build(OpBuilder &builder, OperationState 
&state,
         /*cold=*/nullptr, /*noduplicate=*/nullptr,
         /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr,
         /*modular_format=*/nullptr, /*nobuiltins=*/nullptr,
+        /*alloc_size=*/nullptr,
         /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
         /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
         /*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
@@ -1076,6 +1079,7 @@ void CallOp::build(OpBuilder &builder, OperationState 
&state, LLVMFuncOp func,
         /*cold=*/nullptr, /*noduplicate=*/nullptr,
         /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr,
         /*modular_format=*/nullptr, /*nobuiltins=*/nullptr,
+        /*alloc_size=*/nullptr,
         /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
         /*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
         /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,

diff  --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp 
b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
index 68c634538d92b..93a8e00d40e35 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -456,6 +456,11 @@ convertOperationImpl(Operation &opInst, 
llvm::IRBuilderBase &builder,
           noBuiltins, call, ModuleTranslation::convertNoBuiltin);
     }
 
+    if (llvm::Attribute attr =
+            moduleTranslation.convertAllocsizeAttr(callOp.getAllocsizeAttr());
+        attr.isValid())
+      call->addFnAttr(attr);
+
     if (failed(moduleTranslation.convertArgAndResultAttrs(callOp, call)))
       return failure();
 

diff  --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp 
b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index feb5011a5cc91..2c1613c890923 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -2659,6 +2659,7 @@ static constexpr std::array kExplicitLLVMFuncOpAttributes{
     StringLiteral("aarch64_pstate_sm_body"),
     StringLiteral("aarch64_pstate_sm_compatible"),
     StringLiteral("aarch64_pstate_sm_enabled"),
+    StringLiteral("allocsize"),
     StringLiteral("alwaysinline"),
     StringLiteral("cold"),
     StringLiteral("convergent"),
@@ -2725,6 +2726,24 @@ static void convertNoBuiltinAttrs(MLIRContext *ctx,
     target.setNobuiltinsAttr(ArrayAttr::get(ctx, nbAttrs.getArrayRef()));
 }
 
+template <typename OpTy>
+static void convertAllocsizeAttr(MLIRContext *ctx,
+                                 const llvm::AttributeSet &attrs, OpTy target) 
{
+  llvm::Attribute attr = attrs.getAttribute(llvm::Attribute::AllocSize);
+  if (!attr.isValid())
+    return;
+
+  auto [elemSize, numElems] = attr.getAllocSizeArgs();
+  if (numElems) {
+    target.setAllocsizeAttr(
+        DenseI32ArrayAttr::get(ctx, {static_cast<int32_t>(elemSize),
+                                     static_cast<int32_t>(*numElems)}));
+  } else {
+    target.setAllocsizeAttr(
+        DenseI32ArrayAttr::get(ctx, {static_cast<int32_t>(elemSize)}));
+  }
+}
+
 /// Converts LLVM attributes from `func` into MLIR attributes and adds them
 /// to `funcOp` as passthrough attributes, skipping those listed in
 /// `kExplicitLLVMFuncAttributes`.
@@ -2794,6 +2813,7 @@ void 
ModuleImport::processFunctionAttributes(llvm::Function *func,
     funcOp.setArmPreservesZa(true);
 
   convertNoBuiltinAttrs(context, func->getAttributes().getFnAttrs(), funcOp);
+  convertAllocsizeAttr(context, func->getAttributes().getFnAttrs(), funcOp);
 
   llvm::Attribute attr = func->getFnAttribute(llvm::Attribute::VScaleRange);
   if (attr.isValid()) {
@@ -3036,6 +3056,7 @@ LogicalResult 
ModuleImport::convertCallAttributes(llvm::CallInst *inst,
     op.setMemoryEffectsAttr(memAttr);
 
   convertNoBuiltinAttrs(op.getContext(), callAttrs.getFnAttrs(), op);
+  convertAllocsizeAttr(op.getContext(), callAttrs.getFnAttrs(), op);
 
   return convertCallBaseAttributes(inst, op);
 }

diff  --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp 
b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index e87b4a6502359..6ee9b0cc1cee7 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -1659,6 +1659,20 @@ static void convertFunctionMemoryAttributes(LLVMFuncOp 
func,
   llvmFunc->setMemoryEffects(newMemEffects);
 }
 
+llvm::Attribute
+ModuleTranslation::convertAllocsizeAttr(DenseI32ArrayAttr allocSizeAttr) {
+  if (!allocSizeAttr || allocSizeAttr.empty())
+    return llvm::Attribute{};
+
+  unsigned elemSize = static_cast<unsigned>(allocSizeAttr[0]);
+  std::optional<unsigned> numElems;
+  if (allocSizeAttr.size() > 1)
+    numElems = static_cast<unsigned>(allocSizeAttr[1]);
+
+  return llvm::Attribute::getWithAllocSizeArgs(getLLVMContext(), elemSize,
+                                               numElems);
+}
+
 /// Converts function attributes from `func` and attaches them to `llvmFunc`.
 static void convertFunctionAttributes(ModuleTranslation &mod, LLVMFuncOp func,
                                       llvm::Function *llvmFunc) {
@@ -1709,6 +1723,10 @@ static void convertFunctionAttributes(ModuleTranslation 
&mod, LLVMFuncOp func,
                                  ModuleTranslation::convertNoBuiltin);
   }
 
+  if (llvm::Attribute attr = mod.convertAllocsizeAttr(func.getAllocsizeAttr());
+      attr.isValid())
+    llvmFunc->addFnAttr(attr);
+
   convertFunctionMemoryAttributes(func, llvmFunc);
 }
 

diff  --git a/mlir/test/Dialect/LLVMIR/func.mlir 
b/mlir/test/Dialect/LLVMIR/func.mlir
index 2f1bd0eb96910..8dc7f1ddab11c 100644
--- a/mlir/test/Dialect/LLVMIR/func.mlir
+++ b/mlir/test/Dialect/LLVMIR/func.mlir
@@ -384,6 +384,18 @@ module {
     llvm.return
   }
 
+  llvm.func @alloc_size_one(%arg: i32, %arg2: i32, %arg3: i32, %args4: i32) 
attributes { allocsize = array<i32: 3>} {
+    // CHECK: @alloc_size_one
+    // CHECK-SAME: attributes {allocsize = array<i32: 3>}
+    llvm.return
+  }
+
+  llvm.func @alloc_size_two(%arg: i32, %arg2: i32, %arg3: i32, %args4: i32) 
attributes { allocsize = array<i32:3, 1> } {
+    // CHECK: @alloc_size_two
+    // CHECK-SAME: attributes {allocsize = array<i32: 3, 1>}
+    llvm.return
+  }
+
 }
 
 // -----

diff  --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir 
b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index 2d1a383274e97..a39a4e9e18a56 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -1,4 +1,4 @@
-// RUN: mlir-opt -verify-roundtrip %s
+// RUN: mlir-opt -verify-roundtrip %s | FileCheck %s
 
 
 // CHECK-LABEL: func @baz
@@ -155,6 +155,12 @@ func.func @ops(%arg0: i32, %arg1: f32,
 // CHECK: llvm.call @baz() {nobuiltins = ["asdf", "defg"]} : () -> ()
   llvm.call @baz() {nobuiltins = ["asdf", "defg"]} : () -> ()
 
+// CHECK: llvm.call @baz() {allocsize = array<i32: 5>} : () -> ()
+  llvm.call @baz() {allocsize = array<i32: 5>} : () -> ()
+
+// CHECK: llvm.call @baz() {allocsize = array<i32: 3, 5>} : () -> ()
+  llvm.call @baz() {allocsize = array<i32: 3, 5>} : () -> ()
+
 // Terminator operations and their successors.
 //
 // CHECK: llvm.br ^[[BB1:.*]]

diff  --git a/mlir/test/Target/LLVMIR/Import/function-attributes.ll 
b/mlir/test/Target/LLVMIR/Import/function-attributes.ll
index f4a060280a95c..6348511935e0c 100644
--- a/mlir/test/Target/LLVMIR/Import/function-attributes.ll
+++ b/mlir/test/Target/LLVMIR/Import/function-attributes.ll
@@ -471,5 +471,17 @@ declare void @no_builtins_2() "no-builtin-asdf" 
"no-builtin-defg"
 
 // -----
 
+; CHECK-LABEL: @alloc_size_1
+; CHECK-SAME: attributes {allocsize = array<i32: 0>}
+declare void @alloc_size_1(i32) allocsize(0)
+
+// -----
+
+; CHECK-LABEL: @alloc_size_2
+; CHECK-SAME: attributes {allocsize = array<i32: 0, 1>}
+declare void @alloc_size_2(i32, i32) allocsize(0, 1)
+
+// -----
+
 ; expected-warning @unknown {{'preallocated' attribute is invalid on current 
operation, skipping it}}
 declare void @test() preallocated(i32)

diff  --git a/mlir/test/Target/LLVMIR/Import/instructions.ll 
b/mlir/test/Target/LLVMIR/Import/instructions.ll
index cf3962a92c46c..a72227f01716c 100644
--- a/mlir/test/Target/LLVMIR/Import/instructions.ll
+++ b/mlir/test/Target/LLVMIR/Import/instructions.ll
@@ -817,6 +817,30 @@ define void @call_nobuiltins_2() {
   ret void
 }
 
+
+; // -----
+
+; CHECK: llvm.func @f(i32, i32)
+declare void @f(i32, i32)
+
+; CHECK-LABEL: @call_alloc_size_1
+define void @call_alloc_size_1() {
+; CHECK: llvm.call @f({{.*}}) {allocsize = array<i32: 0>}
+  call void @f(i32 0, i32 0) allocsize(0)
+  ret void
+}
+; // -----
+
+; CHECK: llvm.func @f(i32, i32)
+declare void @f(i32, i32)
+
+; CHECK-LABEL: @call_alloc_size_2
+define void @call_alloc_size_2() {
+; CHECK: llvm.call @f({{.*}}) {allocsize = array<i32: 1, 0>}
+  call void @f(i32 0, i32 0) allocsize(1, 0)
+  ret void
+}
+
 ; // -----
 
 ; CHECK: llvm.func @f()

diff  --git a/mlir/test/Target/LLVMIR/llvmir.mlir 
b/mlir/test/Target/LLVMIR/llvmir.mlir
index ba566e7931359..f88cbda459e80 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -2771,6 +2771,58 @@ llvm.func @no_builtins_call_2() {
 
 // -----
 
+// CHECK-LABEL: @allocsize_1
+// CHECK-SAME: #[[ATTRS:[0-9]+]]
+llvm.func @allocsize_1(%arg: i32, %arg2: i32) attributes { allocsize = 
array<i32: 1> } {
+  llvm.return
+}
+
+// CHECK: #[[ATTRS]]
+// CHECK-SAME: allocsize(1)
+
+// -----
+
+// CHECK-LABEL: @allocsize_2
+// CHECK-SAME: #[[ATTRS:[0-9]+]]
+llvm.func @allocsize_2(%arg: i32, %arg2: i32) attributes { allocsize = 
array<i32:0, 1> } {
+  llvm.return
+}
+
+// CHECK: #[[ATTRS]]
+// CHECK-SAME: allocsize(0,1)
+
+// -----
+
+llvm.func @f(i32, i32)
+
+// CHECK-LABEL: @allocsize_call_1
+// CHECK: call void @f({{.*}}) #[[ATTRS:[0-9]+]]
+llvm.func @allocsize_call_1() {
+  %0 = llvm.mlir.constant(0 : i32) : i32
+  llvm.call @f(%0, %0) {allocsize = array<i32: 1> } : (i32, i32) -> ()
+  llvm.return
+}
+
+// CHECK: #[[ATTRS]]
+// CHECK-SAME: allocsize(1)
+
+// -----
+
+llvm.func @f(i32, i32)
+
+// CHECK-LABEL: @allocsize_call_2
+// CHECK: call void @f({{.*}}) #[[ATTRS:[0-9]+]]
+llvm.func @allocsize_call_2() {
+  %0 = llvm.mlir.constant(0 : i32) : i32
+  llvm.call @f(%0, %0) {allocsize = array<i32: 1, 0> } : (i32, i32) -> ()
+  llvm.return
+}
+
+// CHECK: #[[ATTRS]]
+// CHECK-SAME: allocsize(1,0)
+
+// -----
+
 llvm.func @f()
 
 // CHECK-LABEL: @convergent_call


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to