https://github.com/adams381 updated 
https://github.com/llvm/llvm-project/pull/172551

>From 2325611a24206a99940b29f67102dcff0e04ff7a Mon Sep 17 00:00:00 2001
From: Adam Smith <[email protected]>
Date: Tue, 16 Dec 2025 12:45:42 -0800
Subject: [PATCH 1/2] [CIR] Implement AggExprEmitter::VisitVAArgExpr

This PR implements support for aggregate va_arg expressions in CIR codegen.
The implementation:
- Modifies emitVAArg to return a pointer type for aggregate types
- Implements VisitVAArgExpr to handle aggregate va_arg by creating an Address
  and LValue, then copying to the destination
- Adds comprehensive tests with CIR, LLVM, and OGCG checks
---
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       |  8 +++-
 clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 15 +++++-
 clang/test/CIR/CodeGen/var-arg-aggregate.c    | 48 +++++++++++++++++++
 3 files changed, 69 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/var-arg-aggregate.c

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index b4f02c97f539a..93c2c0fca1276 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -1519,7 +1519,13 @@ mlir::Value CIRGenFunction::emitVAArg(VAArgExpr *ve) {
   assert(!cir::MissingFeatures::msabi());
   assert(!cir::MissingFeatures::vlas());
   mlir::Location loc = cgm.getLoc(ve->getExprLoc());
-  mlir::Type type = convertType(ve->getType());
+  QualType qualType = ve->getType();
+  mlir::Type type = convertType(qualType);
+
+  // For aggregate types, va_arg returns a pointer to the aggregate.
+  if (qualType->isAggregateType())
+    type = cir::PointerType::get(type.getContext(), type);
+
   mlir::Value vaList = emitVAListRef(ve->getSubExpr()).getPointer();
   return cir::VAArgOp::create(builder, loc, type, vaList);
 }
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 367c56f07f734..b0383a8dd533f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -375,7 +375,20 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
   }
 
   void VisitVAArgExpr(VAArgExpr *e) {
-    cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitVAArgExpr");
+    // For aggregate va_arg, emitVAArg returns a pointer to the aggregate.
+    mlir::Value vaArgPtr = cgf.emitVAArg(e);
+
+    // Get alignment for the aggregate type.
+    CharUnits align = cgf.getContext().getTypeAlignInChars(e->getType());
+
+    // Create an Address from the pointer value.
+    Address vaArgAddr(vaArgPtr, align);
+
+    // Create an LValue from the Address.
+    LValue vaArgLValue = cgf.makeAddrLValue(vaArgAddr, e->getType());
+
+    // Copy the aggregate value from va_arg location to destination.
+    emitFinalDestCopy(e->getType(), vaArgLValue);
   }
 
   void VisitCXXThrowExpr(const CXXThrowExpr *e) {
diff --git a/clang/test/CIR/CodeGen/var-arg-aggregate.c 
b/clang/test/CIR/CodeGen/var-arg-aggregate.c
new file mode 100644
index 0000000000000..e7858a06e5bdf
--- /dev/null
+++ b/clang/test/CIR/CodeGen/var-arg-aggregate.c
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value 
-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 -Wno-unused-value 
-fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value 
-emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+struct Bar {
+  float f1;
+  float f2;
+  unsigned u;
+};
+
+struct Bar varargs_aggregate(int count, ...) {
+  __builtin_va_list args;
+  __builtin_va_start(args, count);
+  struct Bar res = __builtin_va_arg(args, struct Bar);
+  __builtin_va_end(args);
+  return res;
+}
+
+// CIR-LABEL: cir.func {{.*}} @varargs_aggregate(
+// CIR:   %[[COUNT_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", 
init]
+// CIR:   %[[RET_ADDR:.+]] = cir.alloca !rec_Bar, !cir.ptr<!rec_Bar>, 
["__retval", init]
+// CIR:   %[[VAAREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"]
+// CIR:   cir.store %arg0, %[[COUNT_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR:   %[[VA_PTR0:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR:   %[[COUNT_VAL:.+]] = cir.load{{.*}} %[[COUNT_ADDR]] : 
!cir.ptr<!s32i>, !s32i
+// CIR:   cir.va_start %[[VA_PTR0]] %[[COUNT_VAL]] : 
!cir.ptr<!rec___va_list_tag>, !s32i
+// CIR:   %[[VA_PTR1:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR:   %[[VA_ARG:.+]] = cir.va_arg %[[VA_PTR1]] : 
(!cir.ptr<!rec___va_list_tag>) -> !cir.ptr<!rec_Bar>
+// CIR:   cir.copy %[[VA_ARG]] to %[[RET_ADDR]] : !cir.ptr<!rec_Bar>
+// CIR:   %[[VA_PTR2:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR:   cir.va_end %[[VA_PTR2]] : !cir.ptr<!rec___va_list_tag>
+// CIR:   %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!rec_Bar>, 
!rec_Bar
+// CIR:   cir.return %[[RETVAL]] : !rec_Bar
+
+// LLVM-LABEL: define dso_local %struct.Bar @varargs_aggregate(
+// LLVM:   call void @llvm.va_start.p0(ptr %{{.*}})
+// LLVM:   %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %{{.*}}, 
i32 0
+// LLVM:   %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], ptr
+// LLVM:   call void @llvm.memcpy.p0.p0.i32(ptr %{{.*}}, ptr %[[VA_ARG]], i32 
12, i1 false)
+
+// OGCG-LABEL: define dso_local { <2 x float>, i32 } @varargs_aggregate
+// OGCG:   call void @llvm.va_start.p0(ptr %{{.*}})
+// OGCG:   %[[VAARG_ADDR:.+]] = phi ptr [ %{{.*}}, %vaarg.in_reg ], [ %{{.*}}, 
%vaarg.in_mem ]
+// OGCG:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.*}}, ptr align 4 
%[[VAARG_ADDR]], i64 12, i1 false)
+

>From 75004cb68c472aa2d8d1a979a2bf2ba44afd5556 Mon Sep 17 00:00:00 2001
From: Adam Smith <[email protected]>
Date: Wed, 17 Dec 2025 10:56:06 -0800
Subject: [PATCH 2/2] [CIR] Address review: Keep emitVAArg ABI-agnostic for
 aggregates

Addresses review comment that aggregate pointer handling is ABI-specific
and should be handled in LoweringPrepare, not at CIR generation level.

- Revert emitVAArg to return aggregate type directly (remove pointer wrapping)
- Update AggExprEmitter::VisitVAArgExpr to handle aggregate value by:
  - Creating temporary alloca to hold the aggregate value
  - Storing va_arg result in temporary using emitAggregateStore
  - Creating LValue from temporary and copying to destination
- Update test to match new behavior (va_arg returns !rec_Bar, not pointer)
---
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       |  8 +------
 clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 22 ++++++++++---------
 clang/test/CIR/CodeGen/var-arg-aggregate.c    | 11 ++++++----
 3 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 93c2c0fca1276..b4f02c97f539a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -1519,13 +1519,7 @@ mlir::Value CIRGenFunction::emitVAArg(VAArgExpr *ve) {
   assert(!cir::MissingFeatures::msabi());
   assert(!cir::MissingFeatures::vlas());
   mlir::Location loc = cgm.getLoc(ve->getExprLoc());
-  QualType qualType = ve->getType();
-  mlir::Type type = convertType(qualType);
-
-  // For aggregate types, va_arg returns a pointer to the aggregate.
-  if (qualType->isAggregateType())
-    type = cir::PointerType::get(type.getContext(), type);
-
+  mlir::Type type = convertType(ve->getType());
   mlir::Value vaList = emitVAListRef(ve->getSubExpr()).getPointer();
   return cir::VAArgOp::create(builder, loc, type, vaList);
 }
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index b0383a8dd533f..3eef284405ad0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -375,20 +375,22 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> 
{
   }
 
   void VisitVAArgExpr(VAArgExpr *e) {
-    // For aggregate va_arg, emitVAArg returns a pointer to the aggregate.
-    mlir::Value vaArgPtr = cgf.emitVAArg(e);
+    // emitVAArg returns an aggregate value (not a pointer) at the CIR level.
+    // ABI-specific pointer handling will be done later in LoweringPrepare.
+    mlir::Value vaArgValue = cgf.emitVAArg(e);
 
-    // Get alignment for the aggregate type.
-    CharUnits align = cgf.getContext().getTypeAlignInChars(e->getType());
+    // Create a temporary alloca to hold the aggregate value.
+    mlir::Location loc = cgf.getLoc(e->getSourceRange());
+    Address tmpAddr = cgf.createMemTemp(e->getType(), loc, "vaarg.tmp");
 
-    // Create an Address from the pointer value.
-    Address vaArgAddr(vaArgPtr, align);
+    // Store the va_arg result into the temporary.
+    cgf.emitAggregateStore(vaArgValue, tmpAddr);
 
-    // Create an LValue from the Address.
-    LValue vaArgLValue = cgf.makeAddrLValue(vaArgAddr, e->getType());
+    // Create an LValue from the temporary address.
+    LValue tmpLValue = cgf.makeAddrLValue(tmpAddr, e->getType());
 
-    // Copy the aggregate value from va_arg location to destination.
-    emitFinalDestCopy(e->getType(), vaArgLValue);
+    // Copy the aggregate value from temporary to destination.
+    emitFinalDestCopy(e->getType(), tmpLValue);
   }
 
   void VisitCXXThrowExpr(const CXXThrowExpr *e) {
diff --git a/clang/test/CIR/CodeGen/var-arg-aggregate.c 
b/clang/test/CIR/CodeGen/var-arg-aggregate.c
index e7858a06e5bdf..5897bc41a116b 100644
--- a/clang/test/CIR/CodeGen/var-arg-aggregate.c
+++ b/clang/test/CIR/CodeGen/var-arg-aggregate.c
@@ -23,13 +23,15 @@ struct Bar varargs_aggregate(int count, ...) {
 // CIR:   %[[COUNT_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", 
init]
 // CIR:   %[[RET_ADDR:.+]] = cir.alloca !rec_Bar, !cir.ptr<!rec_Bar>, 
["__retval", init]
 // CIR:   %[[VAAREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"]
+// CIR:   %[[TMP_ADDR:.+]] = cir.alloca !rec_Bar, !cir.ptr<!rec_Bar>, 
["vaarg.tmp"]
 // CIR:   cir.store %arg0, %[[COUNT_ADDR]] : !s32i, !cir.ptr<!s32i>
 // CIR:   %[[VA_PTR0:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
 // CIR:   %[[COUNT_VAL:.+]] = cir.load{{.*}} %[[COUNT_ADDR]] : 
!cir.ptr<!s32i>, !s32i
 // CIR:   cir.va_start %[[VA_PTR0]] %[[COUNT_VAL]] : 
!cir.ptr<!rec___va_list_tag>, !s32i
 // CIR:   %[[VA_PTR1:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
-// CIR:   %[[VA_ARG:.+]] = cir.va_arg %[[VA_PTR1]] : 
(!cir.ptr<!rec___va_list_tag>) -> !cir.ptr<!rec_Bar>
-// CIR:   cir.copy %[[VA_ARG]] to %[[RET_ADDR]] : !cir.ptr<!rec_Bar>
+// CIR:   %[[VA_ARG:.+]] = cir.va_arg %[[VA_PTR1]] : 
(!cir.ptr<!rec___va_list_tag>) -> !rec_Bar
+// CIR:   cir.store{{.*}} %[[VA_ARG]], %[[TMP_ADDR]] : !rec_Bar, 
!cir.ptr<!rec_Bar>
+// CIR:   cir.copy %[[TMP_ADDR]] to %[[RET_ADDR]] : !cir.ptr<!rec_Bar>
 // CIR:   %[[VA_PTR2:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
 // CIR:   cir.va_end %[[VA_PTR2]] : !cir.ptr<!rec___va_list_tag>
 // CIR:   %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!rec_Bar>, 
!rec_Bar
@@ -38,8 +40,9 @@ struct Bar varargs_aggregate(int count, ...) {
 // LLVM-LABEL: define dso_local %struct.Bar @varargs_aggregate(
 // LLVM:   call void @llvm.va_start.p0(ptr %{{.*}})
 // LLVM:   %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %{{.*}}, 
i32 0
-// LLVM:   %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], ptr
-// LLVM:   call void @llvm.memcpy.p0.p0.i32(ptr %{{.*}}, ptr %[[VA_ARG]], i32 
12, i1 false)
+// LLVM:   %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], %struct.Bar
+// LLVM:   store %struct.Bar %[[VA_ARG]], ptr %{{.*}}
+// LLVM:   call void @llvm.memcpy.p0.p0.i32(ptr %{{.*}}, ptr %{{.*}}, i32 12, 
i1 false)
 
 // OGCG-LABEL: define dso_local { <2 x float>, i32 } @varargs_aggregate
 // OGCG:   call void @llvm.va_start.p0(ptr %{{.*}})

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

Reply via email to