Author: Andy Kaylor
Date: 2025-11-26T22:49:17Z
New Revision: 20d95c807092755114fdc8cc3dba49e3f6820eb2

URL: 
https://github.com/llvm/llvm-project/commit/20d95c807092755114fdc8cc3dba49e3f6820eb2
DIFF: 
https://github.com/llvm/llvm-project/commit/20d95c807092755114fdc8cc3dba49e3f6820eb2.diff

LOG: [CIR] Add undef handling to enable global lambdas (#169721)

This change adds undef handling that was needed to enable global
lambdas. There was no lambda-specific code needed, but the global lambda
handling needed to initialize a global with an undef value.

[CIR] Handle undef init of struct

This adds handling for a case where Clang initializes a struct to undef
with a constant copy. This required adding support for undef constants
and lowering undef attributes to LLVM IR.

Added: 
    

Modified: 
    clang/lib/CIR/Dialect/IR/CIRDialect.cpp
    clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
    clang/test/CIR/CodeGen/lambda.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 6bf543cf794b7..f1bacff7fc691 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -330,6 +330,12 @@ static LogicalResult checkConstantTypes(mlir::Operation 
*op, mlir::Type opType,
         "zero expects struct, array, vector, or complex type");
   }
 
+  if (mlir::isa<cir::UndefAttr>(attrType)) {
+    if (!mlir::isa<cir::VoidType>(opType))
+      return success();
+    return op->emitOpError("undef expects non-void type");
+  }
+
   if (mlir::isa<cir::BoolAttr>(attrType)) {
     if (!mlir::isa<cir::BoolType>(opType))
       return op->emitOpError("result type (")

diff  --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index cd923a15af132..0c34d87734c3e 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -240,7 +240,7 @@ class CIRAttrToValue {
         .Case<cir::IntAttr, cir::FPAttr, cir::ConstComplexAttr,
               cir::ConstArrayAttr, cir::ConstRecordAttr, cir::ConstVectorAttr,
               cir::ConstPtrAttr, cir::GlobalViewAttr, cir::TypeInfoAttr,
-              cir::VTableAttr, cir::ZeroAttr>(
+              cir::UndefAttr, cir::VTableAttr, cir::ZeroAttr>(
             [&](auto attrT) { return visitCirAttr(attrT); })
         .Default([&](auto attrT) { return mlir::Value(); });
   }
@@ -254,6 +254,7 @@ class CIRAttrToValue {
   mlir::Value visitCirAttr(cir::ConstVectorAttr attr);
   mlir::Value visitCirAttr(cir::GlobalViewAttr attr);
   mlir::Value visitCirAttr(cir::TypeInfoAttr attr);
+  mlir::Value visitCirAttr(cir::UndefAttr attr);
   mlir::Value visitCirAttr(cir::VTableAttr attr);
   mlir::Value visitCirAttr(cir::ZeroAttr attr);
 
@@ -591,6 +592,13 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::TypeInfoAttr 
typeInfoAttr) {
   return result;
 }
 
+/// UndefAttr visitor.
+mlir::Value CIRAttrToValue::visitCirAttr(cir::UndefAttr undefAttr) {
+  mlir::Location loc = parentOp->getLoc();
+  return mlir::LLVM::UndefOp::create(
+      rewriter, loc, converter->convertType(undefAttr.getType()));
+}
+
 // VTableAttr visitor.
 mlir::Value CIRAttrToValue::visitCirAttr(cir::VTableAttr vtableArr) {
   mlir::Type llvmTy = converter->convertType(vtableArr.getType());
@@ -2046,9 +2054,11 @@ 
CIRToLLVMGlobalOpLowering::matchAndRewriteRegionInitializedGlobal(
     cir::GlobalOp op, mlir::Attribute init,
     mlir::ConversionPatternRewriter &rewriter) const {
   // TODO: Generalize this handling when more types are needed here.
-  assert((isa<cir::ConstArrayAttr, cir::ConstRecordAttr, cir::ConstVectorAttr,
-              cir::ConstPtrAttr, cir::ConstComplexAttr, cir::GlobalViewAttr,
-              cir::TypeInfoAttr, cir::VTableAttr, cir::ZeroAttr>(init)));
+  assert(
+      (isa<cir::ConstArrayAttr, cir::ConstRecordAttr, cir::ConstVectorAttr,
+           cir::ConstPtrAttr, cir::ConstComplexAttr, cir::GlobalViewAttr,
+           cir::TypeInfoAttr, cir::UndefAttr, cir::VTableAttr, cir::ZeroAttr>(
+          init)));
 
   // TODO(cir): once LLVM's dialect has proper equivalent attributes this
   // should be updated. For now, we use a custom op to initialize globals
@@ -2106,8 +2116,8 @@ mlir::LogicalResult 
CIRToLLVMGlobalOpLowering::matchAndRewrite(
     } else if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr,
                          cir::ConstRecordAttr, cir::ConstPtrAttr,
                          cir::ConstComplexAttr, cir::GlobalViewAttr,
-                         cir::TypeInfoAttr, cir::VTableAttr, cir::ZeroAttr>(
-                   init.value())) {
+                         cir::TypeInfoAttr, cir::UndefAttr, cir::VTableAttr,
+                         cir::ZeroAttr>(init.value())) {
       // TODO(cir): once LLVM's dialect has proper equivalent attributes this
       // should be updated. For now, we use a custom op to initialize globals
       // to the appropriate value.

diff  --git a/clang/test/CIR/CodeGen/lambda.cpp 
b/clang/test/CIR/CodeGen/lambda.cpp
index 91380b9bea296..1d06496a85530 100644
--- a/clang/test/CIR/CodeGen/lambda.cpp
+++ b/clang/test/CIR/CodeGen/lambda.cpp
@@ -8,6 +8,39 @@
 // We declare anonymous record types to represent lambdas. Rather than trying 
to
 // to match the declarations, we establish variables for these when they are 
used.
 
+auto global_lambda = [](){};
+void use_global_lambda() {
+  global_lambda();
+}
+
+// CIR: cir.global "private" internal dso_local @global_lambda = #cir.undef : 
![[REC_LAM_GLOBAL_LAMBDA:.*]] {alignment = 1 : i64}
+// CIR: cir.func lambda internal private dso_local 
@_ZNK3$_0clEv(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_GLOBAL_LAMBDA]]> {{.*}})
+// CIR:   %[[THIS:.*]] = cir.alloca !cir.ptr<![[REC_LAM_GLOBAL_LAMBDA]]>, 
!cir.ptr<!cir.ptr<![[REC_LAM_GLOBAL_LAMBDA]]>>, ["this", init]
+// CIR:   cir.store %[[THIS_ARG]], %[[THIS]]
+// CIR:   cir.load %[[THIS]]
+//
+// CIR: cir.func {{.*}} @_Z17use_global_lambdav()
+// CIR:   %[[LAMBDA:.*]] = cir.get_global @global_lambda : 
!cir.ptr<![[REC_LAM_GLOBAL_LAMBDA]]>
+// CIR:   cir.call @_ZNK3$_0clEv(%[[LAMBDA]]) : 
(!cir.ptr<![[REC_LAM_GLOBAL_LAMBDA]]>) -> ()
+
+// LLVM: @global_lambda = internal global %[[REC_LAM_GLOBAL_LAMBDA:.*]] undef, 
align 1
+// LLVM: define internal void @"_ZNK3$_0clEv"(ptr %[[THIS_ARG:.*]])
+// LLVM:   %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM:   store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM:   %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+//
+// LLVM: define dso_local void @_Z17use_global_lambdav()
+// LLVM:   call void @"_ZNK3$_0clEv"(ptr @global_lambda)
+
+// OGCG: @global_lambda = internal global %[[REC_LAM_GLOBAL_LAMBDA:.*]] undef, 
align 1
+// OGCG: define dso_local void @_Z17use_global_lambdav()
+// OGCG:   call void @"_ZNK3$_0clEv"(ptr noundef nonnull align 1 
dereferenceable(1) @global_lambda)
+//
+// OGCG: define internal void @"_ZNK3$_0clEv"(ptr {{.*}} %[[THIS_ARG:.*]])
+// OGCG:   %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG:   store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG:   %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+
 void fn() {
   auto a = [](){};
   a();


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

Reply via email to