https://github.com/mmha updated https://github.com/llvm/llvm-project/pull/157116

>From 4121aecbda6be80161eb8fe22c351fadd5bbe62a Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhaf...@nvidia.com>
Date: Fri, 5 Sep 2025 16:27:28 +0200
Subject: [PATCH 1/2] [CIR] Add support for __builtin_alloca

This patch adds support for the alloca builtin and extends AllocaOp with a 
dynamic size argument.
---
 .../CIR/Dialect/Builder/CIRBaseBuilder.h      | 16 ++++++
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 21 +++++++-
 clang/include/clang/CIR/MissingFeatures.h     |  1 -
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       | 51 +++++++++++++++++++
 .../CIR/Dialect/Transforms/HoistAllocas.cpp   |  3 +-
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  9 ++--
 clang/test/CIR/CodeGen/builtin_call.cpp       | 10 ++++
 clang/test/CIR/IR/alloca.cir                  | 32 ++++++++++++
 8 files changed, 137 insertions(+), 6 deletions(-)
 create mode 100644 clang/test/CIR/IR/alloca.cir

diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h 
b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 8dc4ca2f9c4e1..a3f167e3cde2c 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -221,6 +221,22 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
     return cir::ConstPtrAttr::get(type, getI64IntegerAttr(value));
   }
 
+  mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
+                           mlir::Type type, llvm::StringRef name,
+                           mlir::IntegerAttr alignment,
+                           mlir::Value dynAllocSize) {
+    return cir::AllocaOp::create(*this, loc, addrType, type, name, alignment,
+                                 dynAllocSize);
+  }
+
+  mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
+                           mlir::Type type, llvm::StringRef name,
+                           clang::CharUnits alignment,
+                           mlir::Value dynAllocSize) {
+    mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment);
+    return createAlloca(loc, addrType, type, name, alignmentAttr, 
dynAllocSize);
+  }
+
   mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
                            mlir::Type type, llvm::StringRef name,
                            mlir::IntegerAttr alignment) {
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 4592078af966b..63aea2c404b54 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -341,6 +341,11 @@ def CIR_AllocaOp : CIR_Op<"alloca", [
     The presence of the `const` attribute indicates that the local variable is
     declared with C/C++ `const` keyword.
 
+    The `dynAllocSize` specifies the size to dynamically allocate on the stack
+    and ignores the allocation size based on the original type. This is useful
+    when handling VLAs or the `alloca` builtin and is omitted when declaring
+    regular local variables.
+
     The result type is a pointer to the input's type.
 
     Example:
@@ -356,6 +361,7 @@ def CIR_AllocaOp : CIR_Op<"alloca", [
   }];
 
   let arguments = (ins
+    Optional<CIR_AnyFundamentalIntType>:$dynAllocSize,
     TypeAttr:$allocaType,
     StrAttr:$name,
     UnitAttr:$init,
@@ -372,16 +378,29 @@ def CIR_AllocaOp : CIR_Op<"alloca", [
     OpBuilder<(ins "mlir::Type":$addr,
                    "mlir::Type":$allocaType,
                    "llvm::StringRef":$name,
-                   "mlir::IntegerAttr":$alignment)>
+                   "mlir::IntegerAttr":$alignment)>,
+
+    OpBuilder<(ins "mlir::Type":$addr,
+                   "mlir::Type":$allocaType,
+                   "llvm::StringRef":$name,
+                   "mlir::IntegerAttr":$alignment,
+                   "mlir::Value":$dynAllocSize),
+    [{
+      if (dynAllocSize)
+        $_state.addOperands(dynAllocSize);
+      build($_builder, $_state, addr, allocaType, name, alignment);
+    }]>
   ];
 
   let extraClassDeclaration = [{
     // Whether the alloca input type is a pointer.
     bool isPointerType() { return 
::mlir::isa<::cir::PointerType>(getAllocaType()); }
+    bool isDynamic() { return (bool)getDynAllocSize(); }
   }];
 
   let assemblyFormat = [{
     $allocaType `,` qualified(type($addr)) `,`
+    ($dynAllocSize^ `:` type($dynAllocSize) `,`)?
     `[` $name
        (`,` `init` $init^)?
        (`,` `const` $constant^)?
diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 948e3feca2bb5..1e64278d118b5 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -62,7 +62,6 @@ struct MissingFeatures {
   static bool opAllocaEscapeByReference() { return false; }
   static bool opAllocaReference() { return false; }
   static bool opAllocaAnnotations() { return false; }
-  static bool opAllocaDynAllocSize() { return false; }
   static bool opAllocaCaptureByInit() { return false; }
 
   // FuncOp handling
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index b68e91f64dc84..ddd95466dc1d0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -149,6 +149,57 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
     emitVAEnd(emitVAListRef(e->getArg(0)).getPointer());
     return {};
 
+  case Builtin::BIalloca:
+  case Builtin::BI_alloca:
+  case Builtin::BI__builtin_alloca_uninitialized:
+  case Builtin::BI__builtin_alloca: {
+    // Get alloca size input
+    mlir::Value size = emitScalarExpr(e->getArg(0));
+
+    // The alignment of the alloca should correspond to __BIGGEST_ALIGNMENT__.
+    const TargetInfo &TI = getContext().getTargetInfo();
+    const CharUnits SuitableAlignmentInBytes =
+        getContext().toCharUnitsFromBits(TI.getSuitableAlign());
+
+    // Emit the alloca op with type `u8 *` to match the semantics of
+    // `llvm.alloca`. We later bitcast the type to `void *` to match the
+    // semantics of C/C++
+    // FIXME(cir): It may make sense to allow AllocaOp of type `u8` to return a
+    // pointer of type `void *`. This will require a change to the allocaOp
+    // verifier.
+    auto allocaAddr = builder.createAlloca(
+        getLoc(e->getSourceRange()), builder.getUInt8PtrTy(),
+        builder.getUInt8Ty(), "bi_alloca", SuitableAlignmentInBytes, size);
+
+    // Initialize the allocated buffer if required.
+    if (builtinID != Builtin::BI__builtin_alloca_uninitialized) {
+      // Initialize the alloca with the given size and alignment according to
+      // the lang opts. Only the trivial non-initialization is supported for
+      // now.
+
+      switch (getLangOpts().getTrivialAutoVarInit()) {
+      case LangOptions::TrivialAutoVarInitKind::Uninitialized:
+        // Nothing to initialize.
+        break;
+      case LangOptions::TrivialAutoVarInitKind::Zero:
+      case LangOptions::TrivialAutoVarInitKind::Pattern:
+        cgm.errorNYI("trivial auto var init");
+        break;
+      }
+    }
+
+    // An alloca will always return a pointer to the alloca (stack) address
+    // space. This address space need not be the same as the AST / Language
+    // default (e.g. in C / C++ auto vars are in the generic address space). At
+    // the AST level this is handled within CreateTempAlloca et al., but for 
the
+    // builtin / dynamic alloca we have to handle it here.
+    assert(!cir::MissingFeatures::addressSpace());
+
+    // Bitcast the alloca to the expected type.
+    return RValue::get(
+        builder.createBitcast(allocaAddr, builder.getVoidPtrTy()));
+  }
+
   case Builtin::BIfabs:
   case Builtin::BIfabsf:
   case Builtin::BIfabsl:
diff --git a/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp 
b/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
index 4e0a041d26ce1..72bbf08c79b16 100644
--- a/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
@@ -42,7 +42,8 @@ static void process(mlir::ModuleOp mod, cir::FuncOp func) {
     if (alloca->getBlock() == &entryBlock)
       return;
     // Don't hoist allocas with dynamic alloca size.
-    assert(!cir::MissingFeatures::opAllocaDynAllocSize());
+    if (alloca.getDynAllocSize())
+      return;
 
     // Hoist allocas into the entry block.
 
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index ee9f58c829ca9..8e8cd2a63dcd5 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1053,9 +1053,12 @@ mlir::LogicalResult 
CIRToLLVMBaseClassAddrOpLowering::matchAndRewrite(
 mlir::LogicalResult CIRToLLVMAllocaOpLowering::matchAndRewrite(
     cir::AllocaOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
-  assert(!cir::MissingFeatures::opAllocaDynAllocSize());
-  mlir::Value size = rewriter.create<mlir::LLVM::ConstantOp>(
-      op.getLoc(), typeConverter->convertType(rewriter.getIndexType()), 1);
+  mlir::Value size =
+      op.isDynamic() ? adaptor.getDynAllocSize()
+                     : rewriter.create<mlir::LLVM::ConstantOp>(
+                           op.getLoc(),
+                           typeConverter->convertType(rewriter.getIndexType()),
+                           rewriter.getIntegerAttr(rewriter.getIndexType(), 
1));
   mlir::Type elementTy =
       convertTypeForMemory(*getTypeConverter(), dataLayout, 
op.getAllocaType());
   mlir::Type resultTy =
diff --git a/clang/test/CIR/CodeGen/builtin_call.cpp 
b/clang/test/CIR/CodeGen/builtin_call.cpp
index 09be7937a4330..d416841c5d6fe 100644
--- a/clang/test/CIR/CodeGen/builtin_call.cpp
+++ b/clang/test/CIR/CodeGen/builtin_call.cpp
@@ -258,3 +258,13 @@ void trap2() {
 // LLVM:       {{.+}}:
 // LLVM-NEXT:    call void @_Z2f1v()
 // LLVM:       }
+
+void *test_alloca(unsigned long n) {
+  return __builtin_alloca(n);
+}
+
+// CIR-LABEL: @_Z11test_allocam(
+// CIR:         %{{.+}} = cir.alloca !u8i, !cir.ptr<!u8i>, %{{.+}} : !u64i, 
["bi_alloca"]
+
+// LLVM-LABEL: @_Z11test_allocam(
+// LLVM:         alloca i8, i64 %{{.+}}
diff --git a/clang/test/CIR/IR/alloca.cir b/clang/test/CIR/IR/alloca.cir
new file mode 100644
index 0000000000000..12f7e6ac6a914
--- /dev/null
+++ b/clang/test/CIR/IR/alloca.cir
@@ -0,0 +1,32 @@
+
+// RUN: cir-opt %s | FileCheck %s
+
+!u64i = !cir.int<u, 64>
+!u8i = !cir.int<u, 8>
+!void = !cir.void
+module {
+  cir.func dso_local @_Z11test_allocam(%arg0: !u64i) -> !cir.ptr<!void> {
+    %0 = cir.alloca !u64i, !cir.ptr<!u64i>, ["n", init] {alignment = 8 : i64}
+    %1 = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["__retval"] 
{alignment = 8 : i64}
+    cir.store %arg0, %0 : !u64i, !cir.ptr<!u64i>
+    %2 = cir.load align(8) %0 : !cir.ptr<!u64i>, !u64i
+    // Dynamically sized alloca
+    %3 = cir.alloca !u8i, !cir.ptr<!u8i>, %2 : !u64i, ["bi_alloca"] {alignment 
= 16 : i64}
+    %4 = cir.cast(bitcast, %3 : !cir.ptr<!u8i>), !cir.ptr<!void>
+    cir.store %4, %1 : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
+    %5 = cir.load %1 : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+    cir.return %5 : !cir.ptr<!void>
+  }
+
+  // CHECK: cir.func dso_local @_Z11test_allocam(%arg0: !u64i) -> 
!cir.ptr<!void> {
+  // CHECK:   %0 = cir.alloca !u64i, !cir.ptr<!u64i>, ["n", init] {alignment = 
8 : i64}
+  // CHECK:   %1 = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, 
["__retval"] {alignment = 8 : i64}
+  // CHECK:   cir.store %arg0, %0 : !u64i, !cir.ptr<!u64i>
+  // CHECK:   %2 = cir.load align(8) %0 : !cir.ptr<!u64i>, !u64i
+  // CHECK:   %3 = cir.alloca !u8i, !cir.ptr<!u8i>, %2 : !u64i, ["bi_alloca"] 
{alignment = 16 : i64}
+  // CHECK:   %4 = cir.cast(bitcast, %3 : !cir.ptr<!u8i>), !cir.ptr<!void>
+  // CHECK:   cir.store %4, %1 : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
+  // CHECK:   %5 = cir.load %1 : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+  // CHECK:   cir.return %5 : !cir.ptr<!void>
+  // CHECK: }
+}

>From 073ace995467000014769e2ba1da77c6ce6dffe8 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhaf...@nvidia.com>
Date: Mon, 8 Sep 2025 17:37:05 +0200
Subject: [PATCH 2/2] Address review feedback

---
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       | 10 ++---
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 10 ++---
 clang/test/CIR/CodeGen/builtin_call.cpp       | 38 +++++++++++++++++++
 3 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index ddd95466dc1d0..7d410dbf07a01 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -157,9 +157,9 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
     mlir::Value size = emitScalarExpr(e->getArg(0));
 
     // The alignment of the alloca should correspond to __BIGGEST_ALIGNMENT__.
-    const TargetInfo &TI = getContext().getTargetInfo();
-    const CharUnits SuitableAlignmentInBytes =
-        getContext().toCharUnitsFromBits(TI.getSuitableAlign());
+    const TargetInfo &ti = getContext().getTargetInfo();
+    const CharUnits suitableAlignmentInBytes =
+        getContext().toCharUnitsFromBits(ti.getSuitableAlign());
 
     // Emit the alloca op with type `u8 *` to match the semantics of
     // `llvm.alloca`. We later bitcast the type to `void *` to match the
@@ -167,9 +167,9 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
     // FIXME(cir): It may make sense to allow AllocaOp of type `u8` to return a
     // pointer of type `void *`. This will require a change to the allocaOp
     // verifier.
-    auto allocaAddr = builder.createAlloca(
+    mlir::Value allocaAddr = builder.createAlloca(
         getLoc(e->getSourceRange()), builder.getUInt8PtrTy(),
-        builder.getUInt8Ty(), "bi_alloca", SuitableAlignmentInBytes, size);
+        builder.getUInt8Ty(), "bi_alloca", suitableAlignmentInBytes, size);
 
     // Initialize the allocated buffer if required.
     if (builtinID != Builtin::BI__builtin_alloca_uninitialized) {
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 8e8cd2a63dcd5..ba2a7f4075351 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1054,11 +1054,11 @@ mlir::LogicalResult 
CIRToLLVMAllocaOpLowering::matchAndRewrite(
     cir::AllocaOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
   mlir::Value size =
-      op.isDynamic() ? adaptor.getDynAllocSize()
-                     : rewriter.create<mlir::LLVM::ConstantOp>(
-                           op.getLoc(),
-                           typeConverter->convertType(rewriter.getIndexType()),
-                           rewriter.getIntegerAttr(rewriter.getIndexType(), 
1));
+      op.isDynamic()
+          ? adaptor.getDynAllocSize()
+          : rewriter.create<mlir::LLVM::ConstantOp>(
+                op.getLoc(),
+                typeConverter->convertType(rewriter.getIndexType()), 1);
   mlir::Type elementTy =
       convertTypeForMemory(*getTypeConverter(), dataLayout, 
op.getAllocaType());
   mlir::Type resultTy =
diff --git a/clang/test/CIR/CodeGen/builtin_call.cpp 
b/clang/test/CIR/CodeGen/builtin_call.cpp
index d416841c5d6fe..853d894a3311b 100644
--- a/clang/test/CIR/CodeGen/builtin_call.cpp
+++ b/clang/test/CIR/CodeGen/builtin_call.cpp
@@ -211,6 +211,10 @@ void unreachable() {
 // LLVM:         unreachable
 // LLVM:       }
 
+// OGCG-LABEL: @_Z11unreachablev
+// OGCG:         unreachable
+// OGCG:       }
+
 void f1();
 void unreachable2() {
   __builtin_unreachable();
@@ -229,6 +233,9 @@ void unreachable2() {
 // LLVM-NEXT:    call void @_Z2f1v()
 // LLVM:       }
 
+// OGCG-LABEL: @_Z12unreachable2v
+// OGCG:         unreachable
+
 void trap() {
   __builtin_trap();
 }
@@ -241,6 +248,10 @@ void trap() {
 // LLVM:         call void @llvm.trap()
 // LLVM:       }
 
+// OGCG-LABEL: @_Z4trapv
+// OGCG:         call void @llvm.trap()
+// OGCG:       }
+
 void trap2() {
   __builtin_trap();
   f1();
@@ -259,6 +270,12 @@ void trap2() {
 // LLVM-NEXT:    call void @_Z2f1v()
 // LLVM:       }
 
+// OGCG-LABEL: define{{.*}} void @_Z5trap2v
+// OGCG:         call void @llvm.trap()
+// OGCG-NEXT:    call void @_Z2f1v()
+// OGCG:         ret void
+// OGCG:       }
+
 void *test_alloca(unsigned long n) {
   return __builtin_alloca(n);
 }
@@ -268,3 +285,24 @@ void *test_alloca(unsigned long n) {
 
 // LLVM-LABEL: @_Z11test_allocam(
 // LLVM:         alloca i8, i64 %{{.+}}
+
+// OGCG-LABEL: @_Z11test_allocam(
+// OGCG:         alloca i8, i64 %{{.+}}
+
+bool test_multiple_allocas(unsigned long n) {
+  void *a = __builtin_alloca(n);
+  void *b = __builtin_alloca(n);
+  return a != b;
+}
+
+// CIR-LABEL: @_Z21test_multiple_allocasm(
+// CIR:         %{{.+}} = cir.alloca !u8i, !cir.ptr<!u8i>, %{{.+}} : !u64i, 
["bi_alloca"]
+// CIR:         %{{.+}} = cir.alloca !u8i, !cir.ptr<!u8i>, %{{.+}} : !u64i, 
["bi_alloca"]
+
+// LLVM-LABEL: @_Z21test_multiple_allocasm(
+// LLVM:         alloca i8, i64 %{{.+}}
+// LLVM:         alloca i8, i64 %{{.+}}
+
+// OGCG-LABEL: @_Z21test_multiple_allocasm(
+// OGCG:         alloca i8, i64 %{{.+}}
+// OGCG:         alloca i8, i64 %{{.+}}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to