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
