Skip to content

Commit 3b96648

Browse files
authored
[CIR] Implement__builtin_va_arg (llvm#153834)
Part of llvm#153286. Depends on llvm#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.
1 parent 93189ec commit 3b96648

File tree

8 files changed

+244
-52
lines changed

8 files changed

+244
-52
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3696,4 +3696,45 @@ def CIR_VAEndOp : CIR_Op<"va_end"> {
36963696
}];
36973697
}
36983698

3699+
def CIR_VAArgOp : CIR_Op<"va_arg"> {
3700+
let summary = "Fetches next variadic element as a given type";
3701+
let description = [{
3702+
The `cir.va_arg` operation models the C/C++ `va_arg` macro by reading the
3703+
next argument from an active variable argument list and producing it as a
3704+
value of a specified result type.
3705+
3706+
The operand must be a pointer to the target's `va_list` representation.
3707+
The operation advances the `va_list` state as a side effect and returns
3708+
the fetched value as the result, whose type is chosen by the user of the
3709+
operation.
3710+
3711+
A `cir.va_arg` must only be used on a `va_list` that has been initialized
3712+
with `cir.va.start` and not yet finalized by `cir.va.end`. The semantics
3713+
(including alignment and promotion rules) follow the platform ABI; the
3714+
frontend is responsible for providing a `va_list` pointer that matches the
3715+
target representation.
3716+
3717+
Example:
3718+
```mlir
3719+
// %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
3720+
%p = cir.cast(array_to_ptrdecay, %args
3721+
: !cir.ptr<!cir.array<!rec___va_list_tag x 1>>),
3722+
!cir.ptr<!rec___va_list_tag>
3723+
cir.va.start %p : !cir.ptr<!rec___va_list_tag>
3724+
3725+
// Fetch an `int` from the vararg list.
3726+
%v = cir.va_arg %p : (!cir.ptr<!rec___va_list_tag>) -> !s32i
3727+
3728+
cir.va.end %p : !cir.ptr<!rec___va_list_tag>
3729+
```
3730+
}];
3731+
3732+
let arguments = (ins CIR_PointerType:$arg_list);
3733+
let results = (outs CIR_AnyType:$result);
3734+
3735+
let assemblyFormat = [{
3736+
$arg_list attr-dict `:` functional-type(operands, $result)
3737+
}];
3738+
}
3739+
36993740
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ struct MissingFeatures {
279279
static bool vtableInitialization() { return false; }
280280
static bool vtableRelativeLayout() { return false; }
281281
static bool msvcBuiltins() { return false; }
282+
static bool vaArgABILowering() { return false; }
282283
static bool vlas() { return false; }
283284

284285
// Missing types

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,3 +401,15 @@ void CIRGenFunction::emitVAStart(mlir::Value vaList, mlir::Value count) {
401401
void CIRGenFunction::emitVAEnd(mlir::Value vaList) {
402402
cir::VAEndOp::create(builder, vaList.getLoc(), vaList);
403403
}
404+
405+
// FIXME(cir): This completely abstracts away the ABI with a generic CIR Op. By
406+
// default this lowers to llvm.va_arg which is incomplete and not ABI-compliant
407+
// on most targets so cir.va_arg will need some ABI handling in LoweringPrepare
408+
mlir::Value CIRGenFunction::emitVAArg(VAArgExpr *ve) {
409+
assert(!cir::MissingFeatures::msabi());
410+
assert(!cir::MissingFeatures::vlas());
411+
mlir::Location loc = cgm.getLoc(ve->getExprLoc());
412+
mlir::Type type = convertType(ve->getType());
413+
mlir::Value vaList = emitVAListRef(ve->getSubExpr()).getPointer();
414+
return cir::VAArgOp::create(builder, loc, type, vaList);
415+
}

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,17 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
399399
return Visit(e->getReplacement());
400400
}
401401

402+
mlir::Value VisitVAArgExpr(VAArgExpr *ve) {
403+
QualType ty = ve->getType();
404+
405+
if (ty->isVariablyModifiedType()) {
406+
cgf.cgm.errorNYI(ve->getSourceRange(),
407+
"variably modified types in varargs");
408+
}
409+
410+
return cgf.emitVAArg(ve);
411+
}
412+
402413
mlir::Value VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *e);
403414
mlir::Value
404415
VisitAbstractConditionalOperator(const AbstractConditionalOperator *e);

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,6 +1504,17 @@ class CIRGenFunction : public CIRGenTypeCache {
15041504
/// \c emitVAListRef or \c emitMSVAListRef.
15051505
void emitVAEnd(mlir::Value vaList);
15061506

1507+
/// Generate code to get an argument from the passed in pointer
1508+
/// and update it accordingly.
1509+
///
1510+
/// \param ve The \c VAArgExpr for which to generate code.
1511+
///
1512+
/// \param vaListAddr Receives a reference to the \c va_list as emitted by
1513+
/// either \c emitVAListRef or \c emitMSVAListRef.
1514+
///
1515+
/// \returns SSA value with the argument.
1516+
mlir::Value emitVAArg(VAArgExpr *ve);
1517+
15071518
/// ----------------------
15081519
/// CIR build helpers
15091520
/// -----------------

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2400,6 +2400,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
24002400
CIRToLLVMTrapOpLowering,
24012401
CIRToLLVMUnaryOpLowering,
24022402
CIRToLLVMUnreachableOpLowering,
2403+
CIRToLLVMVAArgOpLowering,
24032404
CIRToLLVMVAEndOpLowering,
24042405
CIRToLLVMVAStartOpLowering,
24052406
CIRToLLVMVecCmpOpLowering,
@@ -3148,6 +3149,23 @@ mlir::LogicalResult CIRToLLVMVAEndOpLowering::matchAndRewrite(
31483149
return mlir::success();
31493150
}
31503151

3152+
mlir::LogicalResult CIRToLLVMVAArgOpLowering::matchAndRewrite(
3153+
cir::VAArgOp op, OpAdaptor adaptor,
3154+
mlir::ConversionPatternRewriter &rewriter) const {
3155+
assert(!cir::MissingFeatures::vaArgABILowering());
3156+
auto opaquePtr = mlir::LLVM::LLVMPointerType::get(getContext());
3157+
auto vaList = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), opaquePtr,
3158+
adaptor.getArgList());
3159+
3160+
mlir::Type llvmType =
3161+
getTypeConverter()->convertType(op->getResultTypes().front());
3162+
if (!llvmType)
3163+
return mlir::failure();
3164+
3165+
rewriter.replaceOpWithNewOp<mlir::LLVM::VaArgOp>(op, llvmType, vaList);
3166+
return mlir::success();
3167+
}
3168+
31513169
std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
31523170
return std::make_unique<ConvertCIRToLLVMPass>();
31533171
}

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,16 @@ class CIRToLLVMVAEndOpLowering
745745
mlir::ConversionPatternRewriter &) const override;
746746
};
747747

748+
class CIRToLLVMVAArgOpLowering
749+
: public mlir::OpConversionPattern<cir::VAArgOp> {
750+
public:
751+
using mlir::OpConversionPattern<cir::VAArgOp>::OpConversionPattern;
752+
753+
mlir::LogicalResult
754+
matchAndRewrite(cir::VAArgOp op, OpAdaptor,
755+
mlir::ConversionPatternRewriter &) const override;
756+
};
757+
748758
} // namespace direct
749759
} // namespace cir
750760

clang/test/CIR/CodeGen/var_arg.c

Lines changed: 140 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -9,70 +9,158 @@
99
// LLVM: %struct.__va_list_tag = type { i32, i32, ptr, ptr }
1010
// OGCG: %struct.__va_list_tag = type { i32, i32, ptr, ptr }
1111

12-
void varargs(int count, ...) {
12+
int varargs(int count, ...) {
1313
__builtin_va_list args;
14-
__builtin_va_start(args, 12345);
14+
__builtin_va_start(args, count);
15+
int res = __builtin_va_arg(args, int);
1516
__builtin_va_end(args);
17+
return res;
1618
}
1719

18-
// CIR-LABEL: cir.func dso_local @varargs
19-
// CIR-SAME: (%[[COUNT:.+]]: !s32i{{.*}}, ...)
20+
// CIR-LABEL: cir.func dso_local @varargs(
2021
// CIR: %[[COUNT_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", init]
21-
// CIR: %[[ARGS:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"]
22-
// CIR: cir.store %[[COUNT]], %[[COUNT_ADDR]] : !s32i, !cir.ptr<!s32i>
23-
// CIR: %[[APTR:.+]] = cir.cast(array_to_ptrdecay, %[[ARGS]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag>
24-
// CIR: %[[C12345:.+]] = cir.const #cir.int<12345> : !s32i
25-
// CIR: cir.va_start %[[APTR]] %[[C12345]] : !cir.ptr<!rec___va_list_tag>, !s32i
26-
// CIR: %[[APTR2:.+]] = cir.cast(array_to_ptrdecay, %[[ARGS]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag>
27-
// CIR: cir.va_end %[[APTR2]] : !cir.ptr<!rec___va_list_tag>
28-
// CIR: cir.return
22+
// CIR: %[[RET_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
23+
// CIR: %[[VAAREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"]
24+
// CIR: %[[RES_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["res", init]
25+
// CIR: cir.store %arg0, %[[COUNT_ADDR]] : !s32i, !cir.ptr<!s32i>
26+
// 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>
27+
// CIR: %[[COUNT_VAL:.+]] = cir.load{{.*}} %[[COUNT_ADDR]] : !cir.ptr<!s32i>, !s32i
28+
// CIR: cir.va_start %[[VA_PTR0]] %[[COUNT_VAL]] : !cir.ptr<!rec___va_list_tag>, !s32i
29+
// 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>
30+
// CIR: %[[VA_ARG:.+]] = cir.va_arg %[[VA_PTR1]] : (!cir.ptr<!rec___va_list_tag>) -> !s32i
31+
// CIR: cir.store{{.*}} %[[VA_ARG]], %[[RES_ADDR]] : !s32i, !cir.ptr<!s32i>
32+
// 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>
33+
// CIR: cir.va_end %[[VA_PTR2]] : !cir.ptr<!rec___va_list_tag>
34+
// CIR: %[[RESULT:.+]] = cir.load{{.*}} %[[RES_ADDR]] : !cir.ptr<!s32i>, !s32i
35+
// CIR: cir.store %[[RESULT]], %[[RET_ADDR]] : !s32i, !cir.ptr<!s32i>
36+
// CIR: %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i
37+
// CIR: cir.return %[[RETVAL]] : !s32i
2938

30-
// LLVM: define dso_local void @varargs(
31-
// LLVM: %[[ARGS:.+]] = alloca [1 x %struct.__va_list_tag], i64 1, align 16
32-
// LLVM: %[[ARGS_PTR:.+]] = getelementptr %struct.__va_list_tag, ptr %[[ARGS]], i32 0
33-
// LLVM: call void @llvm.va_start.p0(ptr %[[ARGS_PTR]])
34-
// LLVM: %[[ARGS_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[ARGS]], i32 0
35-
// LLVM: call void @llvm.va_end.p0(ptr %[[ARGS_PTR2]])
36-
// LLVM: ret void
39+
// LLVM-LABEL: define dso_local i32 @varargs(
40+
// LLVM: %[[COUNT_ADDR:.+]] = alloca i32{{.*}}
41+
// LLVM: %[[RET_ADDR:.+]] = alloca i32{{.*}}
42+
// LLVM: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
43+
// LLVM: %[[RES_ADDR:.+]] = alloca i32{{.*}}
44+
// LLVM: %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
45+
// LLVM: call void @llvm.va_start.p0(ptr %[[VA_PTR0]])
46+
// LLVM: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
47+
// LLVM: %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], i32
48+
// LLVM: store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}}
49+
// LLVM: %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
50+
// LLVM: call void @llvm.va_end.p0(ptr %[[VA_PTR2]])
51+
// LLVM: %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}}
52+
// LLVM: store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}}
53+
// LLVM: %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}}
54+
// LLVM: ret i32 %[[RETVAL]]
3755

38-
// OGCG: define dso_local void @varargs(
39-
// OGCG: %[[ARGS:.+]] = alloca [1 x %struct.__va_list_tag], align 16
40-
// OGCG: %[[ARGS_PTR:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[ARGS]], i64 0, i64 0
41-
// OGCG: call void @llvm.va_start.p0(ptr %[[ARGS_PTR]])
42-
// OGCG: %[[ARGS_PTR2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[ARGS]], i64 0, i64 0
43-
// OGCG: call void @llvm.va_end.p0(ptr %[[ARGS_PTR2]])
44-
// OGCG: ret void
56+
// OGCG-LABEL: define dso_local i32 @varargs
57+
// OGCG: %[[COUNT_ADDR:.+]] = alloca i32
58+
// OGCG: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
59+
// OGCG: %[[RES_ADDR:.+]] = alloca i32
60+
// OGCG: %[[DECAY:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]]
61+
// OGCG: call void @llvm.va_start.p0(ptr %[[DECAY]])
62+
// OGCG: %[[DECAY1:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]]
63+
// OGCG: %[[GPOFFSET_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 0
64+
// OGCG: %[[GPOFFSET:.+]] = load i32, ptr %[[GPOFFSET_PTR]]
65+
// OGCG: %[[COND:.+]] = icmp ule i32 %[[GPOFFSET]], 40
66+
// OGCG: br i1 %[[COND]], label %vaarg.in_reg, label %vaarg.in_mem
67+
//
68+
// OGCG: vaarg.in_reg:
69+
// OGCG: %[[REGSAVE_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 3
70+
// OGCG: %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]]
71+
// OGCG: %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 %[[GPOFFSET]]
72+
// OGCG: br label %vaarg.end
73+
//
74+
// OGCG: vaarg.in_mem:
75+
// OGCG: %[[OVERFLOW_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 2
76+
// OGCG: %[[OVERFLOW:.+]] = load ptr, ptr %[[OVERFLOW_PTR]]
77+
// OGCG: br label %vaarg.end
78+
//
79+
// OGCG: vaarg.end:
80+
// OGCG: %[[PHI:.+]] = phi ptr [ %[[VAADDR1]], %vaarg.in_reg ], [ %[[OVERFLOW]], %vaarg.in_mem ]
81+
// OGCG: %[[LOADED:.+]] = load i32, ptr %[[PHI]]
82+
// OGCG: store i32 %[[LOADED]], ptr %[[RES_ADDR]]
83+
// OGCG: %[[DECAY2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]]
84+
// OGCG: call void @llvm.va_end.p0(ptr %[[DECAY2]])
85+
// OGCG: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
86+
// OGCG: ret i32 %[[VAL]]
4587

46-
void stdarg_start(int count, ...) {
88+
int stdarg_start(int count, ...) {
4789
__builtin_va_list args;
4890
__builtin_stdarg_start(args, 12345);
91+
int res = __builtin_va_arg(args, int);
4992
__builtin_va_end(args);
93+
return res;
5094
}
5195

52-
// CIR-LABEL: cir.func dso_local @stdarg_start
53-
// CIR-SAME: (%[[COUNT2:.+]]: !s32i{{.*}}, ...)
54-
// CIR: %[[COUNT2_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", init]
55-
// CIR: %[[ARGS2:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"]
56-
// CIR: cir.store %[[COUNT2]], %[[COUNT2_ADDR]] : !s32i, !cir.ptr<!s32i>
57-
// CIR: %[[APTR3:.+]] = cir.cast(array_to_ptrdecay, %[[ARGS2]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag>
58-
// CIR: %[[C12345_2:.+]] = cir.const #cir.int<12345> : !s32i
59-
// CIR: cir.va_start %[[APTR3]] %[[C12345_2]] : !cir.ptr<!rec___va_list_tag>, !s32i
60-
// CIR: %[[APTR4:.+]] = cir.cast(array_to_ptrdecay, %[[ARGS2]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag>
61-
// CIR: cir.va_end %[[APTR4]] : !cir.ptr<!rec___va_list_tag>
62-
// CIR: cir.return
96+
// CIR-LABEL: cir.func dso_local @stdarg_start(
97+
// CIR: %[[COUNT_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", init]
98+
// CIR: %[[RET_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
99+
// CIR: %[[VAAREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"]
100+
// CIR: %[[RES_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["res", init]
101+
// CIR: cir.store %arg0, %[[COUNT_ADDR]] : !s32i, !cir.ptr<!s32i>
102+
// 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>
103+
// CIR: %[[C12345:.+]] = cir.const #cir.int<12345> : !s32i
104+
// CIR: cir.va_start %[[VA_PTR0]] %[[C12345]] : !cir.ptr<!rec___va_list_tag>, !s32i
105+
// 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>
106+
// CIR: %[[VA_ARG:.+]] = cir.va_arg %[[VA_PTR1]] : (!cir.ptr<!rec___va_list_tag>) -> !s32i
107+
// CIR: cir.store{{.*}} %[[VA_ARG]], %[[RES_ADDR]] : !s32i, !cir.ptr<!s32i>
108+
// 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>
109+
// CIR: cir.va_end %[[VA_PTR2]] : !cir.ptr<!rec___va_list_tag>
110+
// CIR: %[[RESULT:.+]] = cir.load{{.*}} %[[RES_ADDR]] : !cir.ptr<!s32i>, !s32i
111+
// CIR: cir.store %[[RESULT]], %[[RET_ADDR]] : !s32i, !cir.ptr<!s32i>
112+
// CIR: %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i
113+
// CIR: cir.return %[[RETVAL]] : !s32i
63114

64-
// LLVM: define dso_local void @stdarg_start(
65-
// LLVM: %[[ARGS:.+]] = alloca [1 x %struct.__va_list_tag], i64 1, align 16
66-
// LLVM: %[[ARGS_PTR:.+]] = getelementptr %struct.__va_list_tag, ptr %[[ARGS]], i32 0
67-
// LLVM: call void @llvm.va_start.p0(ptr %[[ARGS_PTR]])
68-
// LLVM: %[[ARGS_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[ARGS]], i32 0
69-
// LLVM: call void @llvm.va_end.p0(ptr %[[ARGS_PTR2]])
70-
// LLVM: ret void
115+
// LLVM-LABEL: define dso_local i32 @stdarg_start(
116+
// LLVM: %[[COUNT_ADDR:.+]] = alloca i32{{.*}}
117+
// LLVM: %[[RET_ADDR:.+]] = alloca i32{{.*}}
118+
// LLVM: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
119+
// LLVM: %[[RES_ADDR:.+]] = alloca i32{{.*}}
120+
// LLVM: %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
121+
// LLVM: call void @llvm.va_start.p0(ptr %[[VA_PTR0]])
122+
// LLVM: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
123+
// LLVM: %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], i32
124+
// LLVM: store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}}
125+
// LLVM: %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
126+
// LLVM: call void @llvm.va_end.p0(ptr %[[VA_PTR2]])
127+
// LLVM: %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}}
128+
// LLVM: store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}}
129+
// LLVM: %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}}
130+
// LLVM: ret i32 %[[RETVAL]]
71131

72-
// OGCG: define dso_local void @stdarg_start(
73-
// OGCG: %[[ARGS:.+]] = alloca [1 x %struct.__va_list_tag], align 16
74-
// OGCG: %[[ARGS_PTR:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[ARGS]], i64 0, i64 0
75-
// OGCG: call void @llvm.va_start.p0(ptr %[[ARGS_PTR]])
76-
// OGCG: %[[ARGS_PTR2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[ARGS]], i64 0, i64 0
77-
// OGCG: call void @llvm.va_end.p0(ptr %[[ARGS_PTR2]])
78-
// OGCG: ret void
132+
// OGCG-LABEL: define dso_local i32 @stdarg_start
133+
// OGCG: %[[COUNT_ADDR:.+]] = alloca i32
134+
// OGCG: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
135+
// OGCG: %[[RES_ADDR:.+]] = alloca i32
136+
// OGCG: %[[DECAY:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0
137+
// OGCG: call void @llvm.va_start.p0(ptr %[[DECAY]])
138+
// OGCG: %[[DECAY1:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0
139+
// OGCG: %[[GPOFFSET_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 0
140+
// OGCG: %[[GPOFFSET:.+]] = load i32, ptr %[[GPOFFSET_PTR]]
141+
// OGCG: %[[COND:.+]] = icmp ule i32 %[[GPOFFSET]], 40
142+
// OGCG: br i1 %[[COND]], label %vaarg.in_reg, label %vaarg.in_mem
143+
//
144+
// OGCG: vaarg.in_reg:
145+
// OGCG: %[[REGSAVE_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 3
146+
// OGCG: %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]]
147+
// OGCG: %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 %[[GPOFFSET]]
148+
// OGCG: %[[NEXT_GPOFFSET:.+]] = add i32 %[[GPOFFSET]], 8
149+
// OGCG: store i32 %[[NEXT_GPOFFSET]], ptr %[[GPOFFSET_PTR]]
150+
// OGCG: br label %vaarg.end
151+
//
152+
// OGCG: vaarg.in_mem:
153+
// OGCG: %[[OVERFLOW_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 2
154+
// OGCG: %[[OVERFLOW:.+]] = load ptr, ptr %[[OVERFLOW_PTR]]
155+
// OGCG: %[[OVERFLOW_NEXT:.+]] = getelementptr i8, ptr %[[OVERFLOW]], i32 8
156+
// OGCG: store ptr %[[OVERFLOW_NEXT]], ptr %[[OVERFLOW_PTR]]
157+
// OGCG: br label %vaarg.end
158+
//
159+
// OGCG: vaarg.end:
160+
// OGCG: %[[PHI:.+]] = phi ptr [ %[[VAADDR1]], %vaarg.in_reg ], [ %[[OVERFLOW]], %vaarg.in_mem ]
161+
// OGCG: %[[LOADED:.+]] = load i32, ptr %[[PHI]]
162+
// OGCG: store i32 %[[LOADED]], ptr %[[RES_ADDR]]
163+
// OGCG: %[[DECAY2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0
164+
// OGCG: call void @llvm.va_end.p0(ptr %[[DECAY2]])
165+
// OGCG: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
166+
// OGCG: ret i32 %[[VAL]]

0 commit comments

Comments
 (0)