[clang] [CIR] Implement AggExprEmitter::VisitVAArgExpr (PR #172551)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Dec 16 12:48:14 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: None (adams381)
<details>
<summary>Changes</summary>
This PR implements support for aggregate va_arg expressions in CIR codegen.
## Changes
- **CIRGenBuiltin.cpp**: Modified `emitVAArg` to return a pointer type for aggregate types. For aggregate types, `va_arg` returns a pointer to the aggregate rather than the aggregate value itself.
- **CIRGenExprAggregate.cpp**: Implemented `AggExprEmitter::VisitVAArgExpr` to handle aggregate va_arg expressions by:
- Getting the va_arg pointer from `emitVAArg()`
- Creating an `Address` from the pointer with proper alignment
- Creating an `LValue` from the `Address`
- Copying the aggregate value to the destination using `emitFinalDestCopy()`
- **Test**: Added comprehensive test `var-arg-aggregate.c` with CIR, LLVM, and OGCG checks to verify the implementation matches original codegen behavior.
## Testing
All tests pass:
- `check-clang-cir-codegen`: 180/181 passed (99.45%)
- `check-clang-cir`: 423/424 passed (99.76%)
---
Full diff: https://github.com/llvm/llvm-project/pull/172551.diff
3 Files Affected:
- (modified) clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp (+7-1)
- (modified) clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp (+14-1)
- (added) clang/test/CIR/CodeGen/var-arg-aggregate.c (+48)
``````````diff
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)
+
``````````
</details>
https://github.com/llvm/llvm-project/pull/172551
More information about the cfe-commits
mailing list