Author: Morris Hafner Date: 2025-08-20T12:52:11+02:00 New Revision: 3b9664840bc59c1a5230d222f7eedb2668697ccc
URL: https://github.com/llvm/llvm-project/commit/3b9664840bc59c1a5230d222f7eedb2668697ccc DIFF: https://github.com/llvm/llvm-project/commit/3b9664840bc59c1a5230d222f7eedb2668697ccc.diff LOG: [CIR] Implement__builtin_va_arg (#153834) Part of https://github.com/llvm/llvm-project/issues/153286. Depends on https://github.com/llvm/llvm-project/pull/153819. This patch adds support for __builtin_va_arg by adding the cir.va.arg operator. Unlike the incubator it doesn't depend on any target specific lowering (yet) but maps to llvm.va_arg. Added: Modified: clang/include/clang/CIR/Dialect/IR/CIROps.td clang/include/clang/CIR/MissingFeatures.h clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp clang/lib/CIR/CodeGen/CIRGenFunction.h clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h clang/test/CIR/CodeGen/var_arg.c Removed: ################################################################################ diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 369bcb1ddb1bb..0f7abe1748f5e 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3696,4 +3696,45 @@ def CIR_VAEndOp : CIR_Op<"va_end"> { }]; } +def CIR_VAArgOp : CIR_Op<"va_arg"> { + let summary = "Fetches next variadic element as a given type"; + let description = [{ + The `cir.va_arg` operation models the C/C++ `va_arg` macro by reading the + next argument from an active variable argument list and producing it as a + value of a specified result type. + + The operand must be a pointer to the target's `va_list` representation. + The operation advances the `va_list` state as a side effect and returns + the fetched value as the result, whose type is chosen by the user of the + operation. + + A `cir.va_arg` must only be used on a `va_list` that has been initialized + with `cir.va.start` and not yet finalized by `cir.va.end`. The semantics + (including alignment and promotion rules) follow the platform ABI; the + frontend is responsible for providing a `va_list` pointer that matches the + target representation. + + 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> + + // Fetch an `int` from the vararg list. + %v = cir.va_arg %p : (!cir.ptr<!rec___va_list_tag>) -> !s32i + + cir.va.end %p : !cir.ptr<!rec___va_list_tag> + ``` + }]; + + let arguments = (ins CIR_PointerType:$arg_list); + let results = (outs CIR_AnyType:$result); + + let assemblyFormat = [{ + $arg_list attr-dict `:` functional-type(operands, $result) + }]; +} + #endif // CLANG_CIR_DIALECT_IR_CIROPS_TD diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 8626ed920b678..4c084d9a92cdd 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -279,6 +279,7 @@ struct MissingFeatures { static bool vtableInitialization() { return false; } static bool vtableRelativeLayout() { return false; } static bool msvcBuiltins() { return false; } + static bool vaArgABILowering() { return false; } static bool vlas() { return false; } // Missing types diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 084fc5ccb19f8..b6a6299667308 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -401,3 +401,15 @@ void CIRGenFunction::emitVAStart(mlir::Value vaList, mlir::Value count) { void CIRGenFunction::emitVAEnd(mlir::Value vaList) { cir::VAEndOp::create(builder, vaList.getLoc(), vaList); } + +// FIXME(cir): This completely abstracts away the ABI with a generic CIR Op. By +// default this lowers to llvm.va_arg which is incomplete and not ABI-compliant +// on most targets so cir.va_arg will need some ABI handling in LoweringPrepare +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()); + mlir::Value vaList = emitVAListRef(ve->getSubExpr()).getPointer(); + return cir::VAArgOp::create(builder, loc, type, vaList); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index a23bdfc02ad2d..f6b2c88f2cfb4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -399,6 +399,17 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> { return Visit(e->getReplacement()); } + mlir::Value VisitVAArgExpr(VAArgExpr *ve) { + QualType ty = ve->getType(); + + if (ty->isVariablyModifiedType()) { + cgf.cgm.errorNYI(ve->getSourceRange(), + "variably modified types in varargs"); + } + + return cgf.emitVAArg(ve); + } + mlir::Value VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *e); mlir::Value VisitAbstractConditionalOperator(const AbstractConditionalOperator *e); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 0f1af4dcb801f..86ccb04f960ed 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1504,6 +1504,17 @@ class CIRGenFunction : public CIRGenTypeCache { /// \c emitVAListRef or \c emitMSVAListRef. void emitVAEnd(mlir::Value vaList); + /// Generate code to get an argument from the passed in pointer + /// and update it accordingly. + /// + /// \param ve The \c VAArgExpr for which to generate code. + /// + /// \param vaListAddr Receives a reference to the \c va_list as emitted by + /// either \c emitVAListRef or \c emitMSVAListRef. + /// + /// \returns SSA value with the argument. + mlir::Value emitVAArg(VAArgExpr *ve); + /// ---------------------- /// CIR build helpers /// ----------------- diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index badd6de814bd7..d394cdf96e639 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2400,6 +2400,7 @@ void ConvertCIRToLLVMPass::runOnOperation() { CIRToLLVMTrapOpLowering, CIRToLLVMUnaryOpLowering, CIRToLLVMUnreachableOpLowering, + CIRToLLVMVAArgOpLowering, CIRToLLVMVAEndOpLowering, CIRToLLVMVAStartOpLowering, CIRToLLVMVecCmpOpLowering, @@ -3148,6 +3149,23 @@ mlir::LogicalResult CIRToLLVMVAEndOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMVAArgOpLowering::matchAndRewrite( + cir::VAArgOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + assert(!cir::MissingFeatures::vaArgABILowering()); + auto opaquePtr = mlir::LLVM::LLVMPointerType::get(getContext()); + auto vaList = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), opaquePtr, + adaptor.getArgList()); + + mlir::Type llvmType = + getTypeConverter()->convertType(op->getResultTypes().front()); + if (!llvmType) + return mlir::failure(); + + rewriter.replaceOpWithNewOp<mlir::LLVM::VaArgOp>(op, llvmType, 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 7356e93bf700c..7b109c5cef9d3 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -745,6 +745,16 @@ class CIRToLLVMVAEndOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMVAArgOpLowering + : public mlir::OpConversionPattern<cir::VAArgOp> { +public: + using mlir::OpConversionPattern<cir::VAArgOp>::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::VAArgOp 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 index 4c0492004e785..e9c4acb15d009 100644 --- a/clang/test/CIR/CodeGen/var_arg.c +++ b/clang/test/CIR/CodeGen/var_arg.c @@ -9,70 +9,158 @@ // LLVM: %struct.__va_list_tag = type { i32, i32, ptr, ptr } // OGCG: %struct.__va_list_tag = type { i32, i32, ptr, ptr } -void varargs(int count, ...) { +int varargs(int count, ...) { __builtin_va_list args; - __builtin_va_start(args, 12345); + __builtin_va_start(args, count); + int res = __builtin_va_arg(args, int); __builtin_va_end(args); + return res; } -// CIR-LABEL: cir.func dso_local @varargs -// CIR-SAME: (%[[COUNT:.+]]: !s32i{{.*}}, ...) +// CIR-LABEL: cir.func dso_local @varargs( // 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 +// CIR: %[[RET_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] +// CIR: %[[VAAREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"] +// CIR: %[[RES_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["res", init] +// 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>) -> !s32i +// CIR: cir.store{{.*}} %[[VA_ARG]], %[[RES_ADDR]] : !s32i, !cir.ptr<!s32i> +// 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: %[[RESULT:.+]] = cir.load{{.*}} %[[RES_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.store %[[RESULT]], %[[RET_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.return %[[RETVAL]] : !s32i -// 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 +// LLVM-LABEL: define dso_local i32 @varargs( +// LLVM: %[[COUNT_ADDR:.+]] = alloca i32{{.*}} +// LLVM: %[[RET_ADDR:.+]] = alloca i32{{.*}} +// LLVM: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}} +// LLVM: %[[RES_ADDR:.+]] = alloca i32{{.*}} +// LLVM: %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0 +// LLVM: call void @llvm.va_start.p0(ptr %[[VA_PTR0]]) +// LLVM: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0 +// LLVM: %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], i32 +// LLVM: store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}} +// LLVM: %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0 +// LLVM: call void @llvm.va_end.p0(ptr %[[VA_PTR2]]) +// LLVM: %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}} +// LLVM: store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}} +// LLVM: %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}} +// LLVM: ret i32 %[[RETVAL]] -// 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 +// OGCG-LABEL: define dso_local i32 @varargs +// OGCG: %[[COUNT_ADDR:.+]] = alloca i32 +// OGCG: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag] +// OGCG: %[[RES_ADDR:.+]] = alloca i32 +// OGCG: %[[DECAY:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]] +// OGCG: call void @llvm.va_start.p0(ptr %[[DECAY]]) +// OGCG: %[[DECAY1:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]] +// OGCG: %[[GPOFFSET_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 0 +// OGCG: %[[GPOFFSET:.+]] = load i32, ptr %[[GPOFFSET_PTR]] +// OGCG: %[[COND:.+]] = icmp ule i32 %[[GPOFFSET]], 40 +// OGCG: br i1 %[[COND]], label %vaarg.in_reg, label %vaarg.in_mem +// +// OGCG: vaarg.in_reg: +// OGCG: %[[REGSAVE_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 3 +// OGCG: %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]] +// OGCG: %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 %[[GPOFFSET]] +// OGCG: br label %vaarg.end +// +// OGCG: vaarg.in_mem: +// OGCG: %[[OVERFLOW_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 2 +// OGCG: %[[OVERFLOW:.+]] = load ptr, ptr %[[OVERFLOW_PTR]] +// OGCG: br label %vaarg.end +// +// OGCG: vaarg.end: +// OGCG: %[[PHI:.+]] = phi ptr [ %[[VAADDR1]], %vaarg.in_reg ], [ %[[OVERFLOW]], %vaarg.in_mem ] +// OGCG: %[[LOADED:.+]] = load i32, ptr %[[PHI]] +// OGCG: store i32 %[[LOADED]], ptr %[[RES_ADDR]] +// OGCG: %[[DECAY2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]] +// OGCG: call void @llvm.va_end.p0(ptr %[[DECAY2]]) +// OGCG: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]] +// OGCG: ret i32 %[[VAL]] -void stdarg_start(int count, ...) { +int stdarg_start(int count, ...) { __builtin_va_list args; __builtin_stdarg_start(args, 12345); + int res = __builtin_va_arg(args, int); __builtin_va_end(args); + return res; } -// CIR-LABEL: cir.func dso_local @stdarg_start -// CIR-SAME: (%[[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 +// CIR-LABEL: cir.func dso_local @stdarg_start( +// CIR: %[[COUNT_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", init] +// CIR: %[[RET_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] +// CIR: %[[VAAREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"] +// CIR: %[[RES_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["res", init] +// 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: %[[C12345:.+]] = cir.const #cir.int<12345> : !s32i +// CIR: cir.va_start %[[VA_PTR0]] %[[C12345]] : !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>) -> !s32i +// CIR: cir.store{{.*}} %[[VA_ARG]], %[[RES_ADDR]] : !s32i, !cir.ptr<!s32i> +// 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: %[[RESULT:.+]] = cir.load{{.*}} %[[RES_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.store %[[RESULT]], %[[RET_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.return %[[RETVAL]] : !s32i -// 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 +// LLVM-LABEL: define dso_local i32 @stdarg_start( +// LLVM: %[[COUNT_ADDR:.+]] = alloca i32{{.*}} +// LLVM: %[[RET_ADDR:.+]] = alloca i32{{.*}} +// LLVM: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}} +// LLVM: %[[RES_ADDR:.+]] = alloca i32{{.*}} +// LLVM: %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0 +// LLVM: call void @llvm.va_start.p0(ptr %[[VA_PTR0]]) +// LLVM: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0 +// LLVM: %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], i32 +// LLVM: store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}} +// LLVM: %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0 +// LLVM: call void @llvm.va_end.p0(ptr %[[VA_PTR2]]) +// LLVM: %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}} +// LLVM: store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}} +// LLVM: %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}} +// LLVM: ret i32 %[[RETVAL]] -// 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 +// OGCG-LABEL: define dso_local i32 @stdarg_start +// OGCG: %[[COUNT_ADDR:.+]] = alloca i32 +// OGCG: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag] +// OGCG: %[[RES_ADDR:.+]] = alloca i32 +// OGCG: %[[DECAY:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0 +// OGCG: call void @llvm.va_start.p0(ptr %[[DECAY]]) +// OGCG: %[[DECAY1:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0 +// OGCG: %[[GPOFFSET_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 0 +// OGCG: %[[GPOFFSET:.+]] = load i32, ptr %[[GPOFFSET_PTR]] +// OGCG: %[[COND:.+]] = icmp ule i32 %[[GPOFFSET]], 40 +// OGCG: br i1 %[[COND]], label %vaarg.in_reg, label %vaarg.in_mem +// +// OGCG: vaarg.in_reg: +// OGCG: %[[REGSAVE_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 3 +// OGCG: %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]] +// OGCG: %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 %[[GPOFFSET]] +// OGCG: %[[NEXT_GPOFFSET:.+]] = add i32 %[[GPOFFSET]], 8 +// OGCG: store i32 %[[NEXT_GPOFFSET]], ptr %[[GPOFFSET_PTR]] +// OGCG: br label %vaarg.end +// +// OGCG: vaarg.in_mem: +// OGCG: %[[OVERFLOW_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 2 +// OGCG: %[[OVERFLOW:.+]] = load ptr, ptr %[[OVERFLOW_PTR]] +// OGCG: %[[OVERFLOW_NEXT:.+]] = getelementptr i8, ptr %[[OVERFLOW]], i32 8 +// OGCG: store ptr %[[OVERFLOW_NEXT]], ptr %[[OVERFLOW_PTR]] +// OGCG: br label %vaarg.end +// +// OGCG: vaarg.end: +// OGCG: %[[PHI:.+]] = phi ptr [ %[[VAADDR1]], %vaarg.in_reg ], [ %[[OVERFLOW]], %vaarg.in_mem ] +// OGCG: %[[LOADED:.+]] = load i32, ptr %[[PHI]] +// OGCG: store i32 %[[LOADED]], ptr %[[RES_ADDR]] +// OGCG: %[[DECAY2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0 +// OGCG: call void @llvm.va_end.p0(ptr %[[DECAY2]]) +// OGCG: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]] +// OGCG: ret i32 %[[VAL]] _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits