https://github.com/mmha updated https://github.com/llvm/llvm-project/pull/153819
>From dae7b978b994f5d160fae784fcd32bb3734f3208 Mon Sep 17 00:00:00 2001 From: Morris Hafner <mhaf...@nvidia.com> Date: Fri, 15 Aug 2025 17:18:19 +0200 Subject: [PATCH 1/2] [CIR] Upstream __builtin_va_start and __builtin_va_end --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 77 +++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 21 +++++ clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 7 +- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 6 ++ clang/lib/CIR/CodeGen/CIRGenFunction.h | 13 ++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 22 ++++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 20 +++++ clang/test/CIR/CodeGen/var_arg.c | 48 ++++++++++++ 8 files changed, 209 insertions(+), 5 deletions(-) create mode 100644 clang/test/CIR/CodeGen/var_arg.c diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index a77e9199cdc96..86c8b59bf36f0 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3415,4 +3415,81 @@ def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp"> { }]; } +//===----------------------------------------------------------------------===// +// Variadic Operations +//===----------------------------------------------------------------------===// + +def CIR_VAStartOp : CIR_Op<"va.start"> { + let summary = "Starts a variable argument list"; + let description = [{ + The cir.va.start operation models the C/C++ va_start macro by + initializing a variable argument list at the given va_list storage + location. + + The operand must be a pointer to the target's `va_list` representation. + This operation has no results and produces its effect by mutating the + storage referenced by the pointer operand. + + Each `cir.va.start` must be paired with a corresponding `cir.va.end` + on the same logical `va_list` object along all control-flow paths. After + `cir.va.end`, the `va_list` must not be accessed unless reinitialized + with another `cir.va.start`. + + Lowering typically maps this to the LLVM intrinsic `llvm.va_start`, + passing the appropriately decayed pointer to the underlying `va_list` + storage. + + Example: + + ```mlir + // %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> + %p = cir.cast(array_to_ptrdecay, %args + : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), + !cir.ptr<!rec___va_list_tag> + cir.va.start %p : !cir.ptr<!rec___va_list_tag> + ``` + }]; + let arguments = (ins CIR_PointerType:$arg_list); + + let assemblyFormat = [{ + $arg_list attr-dict `:` type(operands) + }]; +} + +def CIR_VAEndOp : CIR_Op<"va.end"> { + let summary = "Ends a variable argument list"; + let description = [{ + The `cir.va.end` operation models the C/C++ va_end macro by finalizing + and cleaning up a variable argument list previously initialized with + `cir.va.start`. + + The operand must be a pointer to the target's `va_list` representation. + This operation has no results and produces its effect by mutating the + storage referenced by the pointer operand. + + `cir.va.end` must only be called after a matching `cir.va.start` on the + same `va_list` along all control-flow paths. After `cir.va.end`, the + `va_list` is invalid and must not be accessed unless reinitialized. + + Lowering typically maps this to the LLVM intrinsic `llvm.va_end`, + passing the appropriately decayed pointer to the underlying `va_list` + storage. + + Example: + ```mlir + // %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> + %p = cir.cast(array_to_ptrdecay, %args + : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), + !cir.ptr<!rec___va_list_tag> + cir.va.end %p : !cir.ptr<!rec___va_list_tag> + ``` + }]; + + let arguments = (ins CIR_PointerType:$arg_list); + + let assemblyFormat = [{ + $arg_list attr-dict `:` type(operands) + }]; +} + #endif // CLANG_CIR_DIALECT_IR_CIROPS_TD diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 36aea4c1d39ce..25ca10e801194 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -125,6 +125,18 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, default: break; + // C stdarg builtins. + case Builtin::BI__builtin_stdarg_start: + case Builtin::BI__builtin_va_start: + case Builtin::BI__va_start: + case Builtin::BI__builtin_va_end: { + emitVAStartEnd(builtinID == Builtin::BI__va_start + ? emitScalarExpr(e->getArg(0)) + : emitVAListRef(e->getArg(0)).getPointer(), + builtinID != Builtin::BI__builtin_va_end); + return {}; + } + case Builtin::BIfabs: case Builtin::BIfabsf: case Builtin::BIfabsl: @@ -361,3 +373,12 @@ mlir::Value CIRGenFunction::emitCheckedArgForAssume(const Expr *e) { "emitCheckedArgForAssume: sanitizers are NYI"); return {}; } + +void CIRGenFunction::emitVAStartEnd(mlir::Value argValue, bool isStart) { + // LLVM codegen casts to *i8, no real gain on doing this for CIRGen this + // early, defer to LLVM lowering. + if (isStart) + cir::VAStartOp::create(builder, argValue.getLoc(), argValue); + else + cir::VAEndOp::create(builder, argValue.getLoc(), argValue); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 8bcca6f5d1803..00f2a64281b8c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -90,11 +90,8 @@ Address CIRGenFunction::emitPointerWithAlignment(const Expr *expr, } break; // Array-to-pointer decay. TODO(cir): BaseInfo and TBAAInfo. - case CK_ArrayToPointerDecay: { - cgm.errorNYI(expr->getSourceRange(), - "emitPointerWithAlignment: array-to-pointer decay"); - return Address::invalid(); - } + case CK_ArrayToPointerDecay: + return emitArrayToPointerDecay(ce->getSubExpr()); case CK_UncheckedDerivedToBase: case CK_DerivedToBase: { diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index d6a0792292604..917afa8e78021 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -1080,4 +1080,10 @@ void CIRGenFunction::emitVariablyModifiedType(QualType type) { } while (type->isVariablyModifiedType()); } +Address CIRGenFunction::emitVAListRef(const Expr *e) { + if (getContext().getBuiltinVaListType()->isArrayType()) + return emitPointerWithAlignment(e); + return emitLValue(e).getAddress(); +} + } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 9a887ec047f86..1c89c2c9d57d3 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1411,6 +1411,19 @@ class CIRGenFunction : public CIRGenTypeCache { const clang::Stmt *thenS, const clang::Stmt *elseS); + /// Build a "reference" to a va_list; this is either the address or the value + /// of the expression, depending on how va_list is defined. + Address emitVAListRef(const Expr *e); + + /// Emits a CIR variable-argument operation, either + /// \c cir.va.start or \c cir.va.end. + /// + /// \param argValue A reference to the \c va_list as emitted by either + /// \c emitVAListRef or \c emitMSVAListRef. + /// + /// \param isStart If \c true, emits \c cir.va.start, otherwise \c cir.va.end. + void emitVAStartEnd(mlir::Value argValue, bool isStart); + /// ---------------------- /// CIR build helpers /// ----------------- diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 1ea296a6887ef..e51fbc9eadaf0 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2336,6 +2336,8 @@ void ConvertCIRToLLVMPass::runOnOperation() { CIRToLLVMTrapOpLowering, CIRToLLVMUnaryOpLowering, CIRToLLVMUnreachableOpLowering, + CIRToLLVMVAEndOpLowering, + CIRToLLVMVAStartOpLowering, CIRToLLVMVecCmpOpLowering, CIRToLLVMVecCreateOpLowering, CIRToLLVMVecExtractOpLowering, @@ -3035,6 +3037,26 @@ mlir::LogicalResult CIRToLLVMInlineAsmOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMVAStartOpLowering::matchAndRewrite( + cir::VAStartOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + auto opaquePtr = mlir::LLVM::LLVMPointerType::get(getContext()); + auto vaList = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), opaquePtr, + adaptor.getArgList()); + rewriter.replaceOpWithNewOp<mlir::LLVM::VaStartOp>(op, vaList); + return mlir::success(); +} + +mlir::LogicalResult CIRToLLVMVAEndOpLowering::matchAndRewrite( + cir::VAEndOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + auto opaquePtr = mlir::LLVM::LLVMPointerType::get(getContext()); + auto vaList = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), opaquePtr, + adaptor.getArgList()); + rewriter.replaceOpWithNewOp<mlir::LLVM::VaEndOp>(op, vaList); + return mlir::success(); +} + std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() { return std::make_unique<ConvertCIRToLLVMPass>(); } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index e32bf2d1bae0c..72315ac127e1b 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -684,6 +684,26 @@ class CIRToLLVMInlineAsmOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMVAStartOpLowering + : public mlir::OpConversionPattern<cir::VAStartOp> { +public: + using mlir::OpConversionPattern<cir::VAStartOp>::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::VAStartOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + +class CIRToLLVMVAEndOpLowering + : public mlir::OpConversionPattern<cir::VAEndOp> { +public: + using mlir::OpConversionPattern<cir::VAEndOp>::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::VAEndOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + } // namespace direct } // namespace cir diff --git a/clang/test/CIR/CodeGen/var_arg.c b/clang/test/CIR/CodeGen/var_arg.c new file mode 100644 index 0000000000000..7cd10e1ca42d2 --- /dev/null +++ b/clang/test/CIR/CodeGen/var_arg.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 + +void varargs(int count, ...) { + __builtin_va_list args; + __builtin_va_start(args, 12345); + __builtin_va_end(args); +} + +// CIR: !rec___va_list_tag = !cir.record<struct "__va_list_tag" {!u32i, !u32i, !cir.ptr<!void>, !cir.ptr<!void>} + +// CIR: cir.func dso_local @varargs(%[[COUNT_ARG:.+]]: !s32i {{.*}}, ...) {{.*}} +// CIR: %[[COUNT:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", init] +// CIR: %[[ARGS:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"] +// CIR: cir.store %[[COUNT_ARG]], %[[COUNT]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[ARGS_DECAY1:.+]] = cir.cast(array_to_ptrdecay, %[[ARGS]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> +// CIR: cir.va.start %[[ARGS_DECAY1]] : !cir.ptr<!rec___va_list_tag> +// CIR: %[[ARGS_DECAY2:.+]] = cir.cast(array_to_ptrdecay, %[[ARGS]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> +// CIR: cir.va.end %[[ARGS_DECAY2]] : !cir.ptr<!rec___va_list_tag> +// CIR: cir.return + +// LLVM: %struct.__va_list_tag = type { i32, i32, ptr, ptr } + +// LLVM: define dso_local void @varargs(i32 %[[ARG0:.+]], ...) +// LLVM: %[[COUNT_ADDR:.+]] = alloca i32, i64 1 +// LLVM: %[[ARGS:.+]] = alloca [1 x %struct.__va_list_tag], i64 1 +// LLVM: store i32 %[[ARG0]], ptr %[[COUNT_ADDR]] +// LLVM: %[[GEP1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[ARGS]], i32 0 +// LLVM: call void @llvm.va_start.p0(ptr %[[GEP1]]) +// LLVM: %[[GEP2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[ARGS]], i32 0 +// LLVM: call void @llvm.va_end.p0(ptr %[[GEP2]]) +// LLVM: ret void + +// OGCG: %struct.__va_list_tag = type { i32, i32, ptr, ptr } + +// OGCG: define dso_local void @varargs(i32 noundef %[[COUNT:.+]], ...) +// OGCG: %[[COUNT_ADDR:.+]] = alloca i32 +// OGCG: %[[ARGS:.+]] = alloca [1 x %struct.__va_list_tag] +// OGCG: store i32 %[[COUNT]], ptr %[[COUNT_ADDR]] +// OGCG: %[[ARRDECAY1:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[ARGS]], i64 0, i64 0 +// OGCG: call void @llvm.va_start.p0(ptr %[[ARRDECAY1]]) +// OGCG: %[[ARRDECAY2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[ARGS]], i64 0, i64 0 +// OGCG: call void @llvm.va_end.p0(ptr %[[ARRDECAY2]]) +// OGCG: ret void >From df15b9b98aecd996482e260c735dacf6ab8b4568 Mon Sep 17 00:00:00 2001 From: Morris Hafner <mhaf...@nvidia.com> Date: Mon, 18 Aug 2025 14:00:20 +0200 Subject: [PATCH 2/2] cir.va.start/end -> cir.va_start/end Retain count parameter add baseInfo arg and add tbaa missing feature Add test --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 45 +++++----- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 26 +++--- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 6 +- clang/lib/CIR/CodeGen/CIRGenFunction.h | 18 ++-- clang/test/CIR/CodeGen/var_arg.c | 86 +++++++++++++------- 5 files changed, 113 insertions(+), 68 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 86c8b59bf36f0..1109c6f93ac45 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3419,25 +3419,26 @@ def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp"> { // Variadic Operations //===----------------------------------------------------------------------===// -def CIR_VAStartOp : CIR_Op<"va.start"> { +def CIR_VAStartOp : CIR_Op<"va_start"> { let summary = "Starts a variable argument list"; let description = [{ - The cir.va.start operation models the C/C++ va_start macro by + The cir.va_start operation models the C/C++ va_start macro by initializing a variable argument list at the given va_list storage location. - The operand must be a pointer to the target's `va_list` representation. - This operation has no results and produces its effect by mutating the - storage referenced by the pointer operand. + The first operand must be a pointer to the target's `va_list` + representation. This operation has no results and produces its effect by + mutating the storage referenced by the pointer operand. The second operand + must be an integer value that contains the expected number of arguments in + that list. - Each `cir.va.start` must be paired with a corresponding `cir.va.end` + Each `cir.va_start` must be paired with a corresponding `cir.va_end` on the same logical `va_list` object along all control-flow paths. After - `cir.va.end`, the `va_list` must not be accessed unless reinitialized - with another `cir.va.start`. + `cir.va_end`, the `va_list` must not be accessed unless reinitialized + with another `cir.va_start`. - Lowering typically maps this to the LLVM intrinsic `llvm.va_start`, - passing the appropriately decayed pointer to the underlying `va_list` - storage. + Lowering maps this to the LLVM intrinsic `llvm.va_start`, passing the + appropriately decayed pointer to the underlying `va_list` storage. Example: @@ -3446,29 +3447,33 @@ def CIR_VAStartOp : CIR_Op<"va.start"> { %p = cir.cast(array_to_ptrdecay, %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> - cir.va.start %p : !cir.ptr<!rec___va_list_tag> + %count = cir.load %0 : !cir.ptr<!s32i>, !s32i + cir.va_start %p %count : !cir.ptr<!rec___va_list_tag>, !s32i ``` }]; - let arguments = (ins CIR_PointerType:$arg_list); + let arguments = (ins + CIR_PointerType:$arg_list, + CIR_AnyFundamentalIntType:$count + ); let assemblyFormat = [{ - $arg_list attr-dict `:` type(operands) + $arg_list $count attr-dict `:` type(operands) }]; } -def CIR_VAEndOp : CIR_Op<"va.end"> { +def CIR_VAEndOp : CIR_Op<"va_end"> { let summary = "Ends a variable argument list"; let description = [{ - The `cir.va.end` operation models the C/C++ va_end macro by finalizing + The `cir.va_end` operation models the C/C++ va_end macro by finalizing and cleaning up a variable argument list previously initialized with - `cir.va.start`. + `cir.va_start`. The operand must be a pointer to the target's `va_list` representation. This operation has no results and produces its effect by mutating the storage referenced by the pointer operand. - `cir.va.end` must only be called after a matching `cir.va.start` on the - same `va_list` along all control-flow paths. After `cir.va.end`, the + `cir.va_end` must only be called after a matching `cir.va_start` on the + same `va_list` along all control-flow paths. After `cir.va_end`, the `va_list` is invalid and must not be accessed unless reinitialized. Lowering typically maps this to the LLVM intrinsic `llvm.va_end`, @@ -3481,7 +3486,7 @@ def CIR_VAEndOp : CIR_Op<"va.end"> { %p = cir.cast(array_to_ptrdecay, %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> - cir.va.end %p : !cir.ptr<!rec___va_list_tag> + cir.va_end %p : !cir.ptr<!rec___va_list_tag> ``` }]; diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 25ca10e801194..28dc6c1de480d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -128,15 +128,18 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, // C stdarg builtins. case Builtin::BI__builtin_stdarg_start: case Builtin::BI__builtin_va_start: - case Builtin::BI__va_start: - case Builtin::BI__builtin_va_end: { - emitVAStartEnd(builtinID == Builtin::BI__va_start - ? emitScalarExpr(e->getArg(0)) - : emitVAListRef(e->getArg(0)).getPointer(), - builtinID != Builtin::BI__builtin_va_end); + case Builtin::BI__va_start: { + emitVAStart(builtinID == Builtin::BI__va_start + ? emitScalarExpr(e->getArg(0)) + : emitVAListRef(e->getArg(0)).getPointer(), + emitScalarExpr(e->getArg(1))); return {}; } + case Builtin::BI__builtin_va_end: + emitVAEnd(emitVAListRef(e->getArg(0)).getPointer()); + return {}; + case Builtin::BIfabs: case Builtin::BIfabsf: case Builtin::BIfabsl: @@ -374,11 +377,12 @@ mlir::Value CIRGenFunction::emitCheckedArgForAssume(const Expr *e) { return {}; } -void CIRGenFunction::emitVAStartEnd(mlir::Value argValue, bool isStart) { +void CIRGenFunction::emitVAStart(mlir::Value vaList, mlir::Value count) { // LLVM codegen casts to *i8, no real gain on doing this for CIRGen this // early, defer to LLVM lowering. - if (isStart) - cir::VAStartOp::create(builder, argValue.getLoc(), argValue); - else - cir::VAEndOp::create(builder, argValue.getLoc(), argValue); + cir::VAStartOp::create(builder, vaList.getLoc(), vaList, count); +} + +void CIRGenFunction::emitVAEnd(mlir::Value vaList) { + cir::VAEndOp::create(builder, vaList.getLoc(), vaList); } diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 00f2a64281b8c..ffbdcd4e1d8de 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -91,7 +91,7 @@ Address CIRGenFunction::emitPointerWithAlignment(const Expr *expr, // Array-to-pointer decay. TODO(cir): BaseInfo and TBAAInfo. case CK_ArrayToPointerDecay: - return emitArrayToPointerDecay(ce->getSubExpr()); + return emitArrayToPointerDecay(ce->getSubExpr(), baseInfo); case CK_UncheckedDerivedToBase: case CK_DerivedToBase: { @@ -1623,7 +1623,9 @@ void CIRGenFunction::emitIgnoredExpr(const Expr *e) { emitLValue(e); } -Address CIRGenFunction::emitArrayToPointerDecay(const Expr *e) { +Address CIRGenFunction::emitArrayToPointerDecay(const Expr *e, + LValueBaseInfo *baseInfo) { + assert(!cir::MissingFeatures::opTBAA()); assert(e->getType()->isArrayType() && "Array to pointer decay must have array source type!"); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 1c89c2c9d57d3..17061127eedbf 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -947,7 +947,8 @@ class CIRGenFunction : public CIRGenTypeCache { QualType &baseType, Address &addr); LValue emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e); - Address emitArrayToPointerDecay(const Expr *array); + Address emitArrayToPointerDecay(const Expr *e, + LValueBaseInfo *baseInfo = nullptr); RValue emitAtomicExpr(AtomicExpr *e); void emitAtomicInit(Expr *init, LValue dest); @@ -1415,14 +1416,19 @@ class CIRGenFunction : public CIRGenTypeCache { /// of the expression, depending on how va_list is defined. Address emitVAListRef(const Expr *e); - /// Emits a CIR variable-argument operation, either - /// \c cir.va.start or \c cir.va.end. + /// Emits the start of a CIR variable-argument operation (`cir.va_start`) /// - /// \param argValue A reference to the \c va_list as emitted by either + /// \param vaList A reference to the \c va_list as emitted by either /// \c emitVAListRef or \c emitMSVAListRef. /// - /// \param isStart If \c true, emits \c cir.va.start, otherwise \c cir.va.end. - void emitVAStartEnd(mlir::Value argValue, bool isStart); + /// \param count The number of arguments in \c vaList + void emitVAStart(mlir::Value vaList, mlir::Value count); + + /// Emits the end of a CIR variable-argument operation (`cir.va_start`) + /// + /// \param vaList A reference to the \c va_list as emitted by either + /// \c emitVAListRef or \c emitMSVAListRef. + void emitVAEnd(mlir::Value vaList); /// ---------------------- /// CIR build helpers diff --git a/clang/test/CIR/CodeGen/var_arg.c b/clang/test/CIR/CodeGen/var_arg.c index 7cd10e1ca42d2..e79d87f542d9e 100644 --- a/clang/test/CIR/CodeGen/var_arg.c +++ b/clang/test/CIR/CodeGen/var_arg.c @@ -5,44 +5,72 @@ // 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 +// CIR: !rec___va_list_tag = !cir.record<struct "__va_list_tag" {!u32i, !u32i, !cir.ptr<!void>, !cir.ptr<!void>} +// LLVM: %struct.__va_list_tag = type { i32, i32, ptr, ptr } +// OGCG: %struct.__va_list_tag = type { i32, i32, ptr, ptr } + void varargs(int count, ...) { __builtin_va_list args; __builtin_va_start(args, 12345); __builtin_va_end(args); } -// CIR: !rec___va_list_tag = !cir.record<struct "__va_list_tag" {!u32i, !u32i, !cir.ptr<!void>, !cir.ptr<!void>} - -// CIR: cir.func dso_local @varargs(%[[COUNT_ARG:.+]]: !s32i {{.*}}, ...) {{.*}} -// CIR: %[[COUNT:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", init] -// CIR: %[[ARGS:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"] -// CIR: cir.store %[[COUNT_ARG]], %[[COUNT]] : !s32i, !cir.ptr<!s32i> -// CIR: %[[ARGS_DECAY1:.+]] = cir.cast(array_to_ptrdecay, %[[ARGS]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> -// CIR: cir.va.start %[[ARGS_DECAY1]] : !cir.ptr<!rec___va_list_tag> -// CIR: %[[ARGS_DECAY2:.+]] = cir.cast(array_to_ptrdecay, %[[ARGS]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> -// CIR: cir.va.end %[[ARGS_DECAY2]] : !cir.ptr<!rec___va_list_tag> +// CIR: cir.func dso_local @varargs(%[[COUNT:.+]]: !s32i{{.*}}, ...) +// CIR: %[[COUNT_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", init] +// CIR: %[[ARGS:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"] +// CIR: cir.store %[[COUNT]], %[[COUNT_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[APTR:.+]] = cir.cast(array_to_ptrdecay, %[[ARGS]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> +// CIR: %[[C12345:.+]] = cir.const #cir.int<12345> : !s32i +// CIR: cir.va_start %[[APTR]] %[[C12345]] : !cir.ptr<!rec___va_list_tag>, !s32i +// CIR: %[[APTR2:.+]] = cir.cast(array_to_ptrdecay, %[[ARGS]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> +// CIR: cir.va_end %[[APTR2]] : !cir.ptr<!rec___va_list_tag> // CIR: cir.return -// LLVM: %struct.__va_list_tag = type { i32, i32, ptr, ptr } - -// LLVM: define dso_local void @varargs(i32 %[[ARG0:.+]], ...) -// LLVM: %[[COUNT_ADDR:.+]] = alloca i32, i64 1 -// LLVM: %[[ARGS:.+]] = alloca [1 x %struct.__va_list_tag], i64 1 -// LLVM: store i32 %[[ARG0]], ptr %[[COUNT_ADDR]] -// LLVM: %[[GEP1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[ARGS]], i32 0 -// LLVM: call void @llvm.va_start.p0(ptr %[[GEP1]]) -// LLVM: %[[GEP2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[ARGS]], i32 0 -// LLVM: call void @llvm.va_end.p0(ptr %[[GEP2]]) +// LLVM: define dso_local void @varargs( +// LLVM: %[[ARGS:.+]] = alloca [1 x %struct.__va_list_tag], i64 1, align 16 +// LLVM: %[[ARGS_PTR:.+]] = getelementptr %struct.__va_list_tag, ptr %[[ARGS]], i32 0 +// LLVM: call void @llvm.va_start.p0(ptr %[[ARGS_PTR]]) +// LLVM: %[[ARGS_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[ARGS]], i32 0 +// LLVM: call void @llvm.va_end.p0(ptr %[[ARGS_PTR2]]) // LLVM: ret void -// OGCG: %struct.__va_list_tag = type { i32, i32, ptr, ptr } +// OGCG: define dso_local void @varargs( +// OGCG: %[[ARGS:.+]] = alloca [1 x %struct.__va_list_tag], align 16 +// OGCG: %[[ARGS_PTR:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[ARGS]], i64 0, i64 0 +// OGCG: call void @llvm.va_start.p0(ptr %[[ARGS_PTR]]) +// OGCG: %[[ARGS_PTR2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[ARGS]], i64 0, i64 0 +// OGCG: call void @llvm.va_end.p0(ptr %[[ARGS_PTR2]]) +// OGCG: ret void + +void stdarg_start(int count, ...) { + __builtin_va_list args; + __builtin_stdarg_start(args, 12345); + __builtin_va_end(args); +} + +// CIR: cir.func dso_local @stdarg_start(%[[COUNT2:.+]]: !s32i{{.*}}, ...) +// CIR: %[[COUNT2_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", init] +// CIR: %[[ARGS2:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"] +// CIR: cir.store %[[COUNT2]], %[[COUNT2_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[APTR3:.+]] = cir.cast(array_to_ptrdecay, %[[ARGS2]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> +// CIR: %[[C12345_2:.+]] = cir.const #cir.int<12345> : !s32i +// CIR: cir.va_start %[[APTR3]] %[[C12345_2]] : !cir.ptr<!rec___va_list_tag>, !s32i +// CIR: %[[APTR4:.+]] = cir.cast(array_to_ptrdecay, %[[ARGS2]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> +// CIR: cir.va_end %[[APTR4]] : !cir.ptr<!rec___va_list_tag> +// CIR: cir.return + +// LLVM: define dso_local void @stdarg_start( +// LLVM: %[[ARGS:.+]] = alloca [1 x %struct.__va_list_tag], i64 1, align 16 +// LLVM: %[[ARGS_PTR:.+]] = getelementptr %struct.__va_list_tag, ptr %[[ARGS]], i32 0 +// LLVM: call void @llvm.va_start.p0(ptr %[[ARGS_PTR]]) +// LLVM: %[[ARGS_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[ARGS]], i32 0 +// LLVM: call void @llvm.va_end.p0(ptr %[[ARGS_PTR2]]) +// LLVM: ret void -// OGCG: define dso_local void @varargs(i32 noundef %[[COUNT:.+]], ...) -// OGCG: %[[COUNT_ADDR:.+]] = alloca i32 -// OGCG: %[[ARGS:.+]] = alloca [1 x %struct.__va_list_tag] -// OGCG: store i32 %[[COUNT]], ptr %[[COUNT_ADDR]] -// OGCG: %[[ARRDECAY1:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[ARGS]], i64 0, i64 0 -// OGCG: call void @llvm.va_start.p0(ptr %[[ARRDECAY1]]) -// OGCG: %[[ARRDECAY2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[ARGS]], i64 0, i64 0 -// OGCG: call void @llvm.va_end.p0(ptr %[[ARRDECAY2]]) +// OGCG: define dso_local void @stdarg_start( +// OGCG: %[[ARGS:.+]] = alloca [1 x %struct.__va_list_tag], align 16 +// OGCG: %[[ARGS_PTR:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[ARGS]], i64 0, i64 0 +// OGCG: call void @llvm.va_start.p0(ptr %[[ARGS_PTR]]) +// OGCG: %[[ARGS_PTR2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[ARGS]], i64 0, i64 0 +// OGCG: call void @llvm.va_end.p0(ptr %[[ARGS_PTR2]]) // OGCG: ret void _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits