Skip to content

Commit 0b9f59e

Browse files
ghehglanza
authored andcommitted
[CIR][LowerToLLVM][CXXABI] Fix basic block ordering issue. (#676)
When loweringPrepare cg.var_arg for AArch64, we create multiple basic blocks, but didn't really get ordering of the blocks in the blocklist of the parent region right. That is, we didn't make sure the last of the block list is the naturally last block (exit) of the region. This PR fixes this problem. If we don't fix this problem, FlattenCFGPass will fail verification because CIRScopeOpFlattening in this pass is onlyy expecting to see cir.yield op in the last block of the region's block list.
1 parent 9138336 commit 0b9f59e

File tree

4 files changed

+172
-58
lines changed

4 files changed

+172
-58
lines changed

clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareAArch64CXXABI.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,16 @@ mlir::Value LoweringPrepareAArch64CXXABI::lowerAAPCSVAArg(
168168
maybeRegBlock);
169169

170170
auto contBlock = currentBlock->splitBlock(op);
171+
// now contBlock should be the block after onStackBlock in CFG.
172+
// This is essential, considering the case where originally currentBlock
173+
// was the only block in the region. By splitting the block, and added
174+
// above blocks, really the rear block in the region should be contBlock,
175+
// not onStackBlock, but splitBlock would just insert contBlock after
176+
// currentBlock, so we need to move it.
177+
auto contBlockIter = contBlock->getIterator();
178+
contBlock->getParent()->getBlocks().remove(contBlockIter);
179+
onStackBlock->getParent()->getBlocks().insertAfter(
180+
mlir::Region::iterator(onStackBlock), contBlock);
171181

172182
// Otherwise, at least some kind of argument could go in these registers, the
173183
// question is whether this particular type is too big.

clang/test/CIR/CodeGen/var-arg-float.c

+26-28
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,12 @@ double f1(int n, ...) {
3939
// AFTER: [[CMP0:%.*]] = cir.cmp(ge, [[VR_OFFS]], [[ZERO]]) : !s32i, !cir.bool
4040
// AFTER-NEXT: cir.brcond [[CMP0]] [[BB_ON_STACK:\^bb.*]], [[BB_MAY_REG:\^bb.*]]
4141

42-
43-
// AFTER-NEXT: [[BB_END:\^bb.*]]([[BLK_ARG:%.*]]: !cir.ptr<!void>): // 2 preds: [[BB_IN_REG:\^bb.*]], [[BB_ON_STACK]]
44-
// AFTER-NEXT: [[TMP0:%.*]] = cir.cast(bitcast, [[BLK_ARG]] : !cir.ptr<!void>), !cir.ptr<!cir.double>
45-
// AFTER-NEXT: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr<!cir.double>, !cir.double
46-
// AFTER: cir.store [[TMP1]], [[RESP]] : !cir.double, !cir.ptr<!cir.double>
47-
// AFTER: cir.va.end [[VARLIST]] : !cir.ptr<!ty_22__va_list22>
48-
// AFTER: [[RES:%.*]] = cir.load [[RESP]] : !cir.ptr<!cir.double>, !cir.double
49-
// AFTER: cir.store [[RES]], [[RETP]] : !cir.double, !cir.ptr<!cir.double>
50-
// AFTER: [[RETV:%.*]] = cir.load [[RETP]] : !cir.ptr<!cir.double>, !cir.double
51-
// AFTER: cir.return [[RETV]] : !cir.double
52-
53-
5442
// AFTER: [[BB_MAY_REG]]:
5543
// AFTER-NEXT: [[SIXTEEN:%.*]] = cir.const #cir.int<16> : !s32i
5644
// AFTER-NEXT: [[NEW_REG_OFFS:%.*]] = cir.binop(add, [[VR_OFFS]], [[SIXTEEN]]) : !s32i
5745
// AFTER-NEXT: cir.store [[NEW_REG_OFFS]], [[VR_OFFS_P]] : !s32i, !cir.ptr<!s32i>
5846
// AFTER-NEXT: [[CMP1:%.*]] = cir.cmp(le, [[NEW_REG_OFFS]], [[ZERO]]) : !s32i, !cir.bool
59-
// AFTER-NEXT: cir.brcond [[CMP1]] [[BB_IN_REG]], [[BB_ON_STACK]]
47+
// AFTER-NEXT: cir.brcond [[CMP1]] [[BB_IN_REG:\^bb.*]], [[BB_ON_STACK]]
6048

6149

6250
// AFTER: [[BB_IN_REG]]:
@@ -65,7 +53,7 @@ double f1(int n, ...) {
6553
// AFTER-NEXT: [[TMP2:%.*]] = cir.cast(bitcast, [[VR_TOP]] : !cir.ptr<!void>), !cir.ptr<i8>
6654
// AFTER-NEXT: [[TMP3:%.*]] = cir.ptr_stride([[TMP2]] : !cir.ptr<i8>, [[VR_OFFS]] : !s32i), !cir.ptr<i8>
6755
// AFTER-NEXT: [[IN_REG_OUTPUT:%.*]] = cir.cast(bitcast, [[TMP3]] : !cir.ptr<i8>), !cir.ptr<!void>
68-
// AFTER-NEXT: cir.br [[BB_END]]([[IN_REG_OUTPUT]] : !cir.ptr<!void>)
56+
// AFTER-NEXT: cir.br [[BB_END:\^bb.*]]([[IN_REG_OUTPUT]] : !cir.ptr<!void>)
6957

7058

7159
// AFTER: [[BB_ON_STACK]]:
@@ -78,6 +66,16 @@ double f1(int n, ...) {
7866
// AFTER-NEXT: cir.store [[NEW_STACK_V]], [[STACK_P]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
7967
// AFTER-NEXT: cir.br [[BB_END]]([[STACK_V]] : !cir.ptr<!void>)
8068

69+
// AFTER-NEXT: [[BB_END]]([[BLK_ARG:%.*]]: !cir.ptr<!void>): // 2 preds: [[BB_IN_REG]], [[BB_ON_STACK]]
70+
// AFTER-NEXT: [[TMP0:%.*]] = cir.cast(bitcast, [[BLK_ARG]] : !cir.ptr<!void>), !cir.ptr<!cir.double>
71+
// AFTER-NEXT: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr<!cir.double>, !cir.double
72+
// AFTER: cir.store [[TMP1]], [[RESP]] : !cir.double, !cir.ptr<!cir.double>
73+
// AFTER: cir.va.end [[VARLIST]] : !cir.ptr<!ty_22__va_list22>
74+
// AFTER: [[RES:%.*]] = cir.load [[RESP]] : !cir.ptr<!cir.double>, !cir.double
75+
// AFTER: cir.store [[RES]], [[RETP]] : !cir.double, !cir.ptr<!cir.double>
76+
// AFTER: [[RETV:%.*]] = cir.load [[RETP]] : !cir.ptr<!cir.double>, !cir.double
77+
// AFTER: cir.return [[RETV]] : !cir.double
78+
8179
// beginning block llvm code
8280
// LLVM: %struct.__va_list = type { ptr, ptr, ptr, i32, i32 }
8381
// LLVM: define double @f1(i32 %0, ...)
@@ -90,32 +88,32 @@ double f1(int n, ...) {
9088
// LLVM-NEXT: [[CMP0:%.*]] = icmp sge i32 [[VR_OFFS]], 0,
9189
// LLVM-NEXT: br i1 [[CMP0]], label %[[BB_ON_STACK:.*]], label %[[BB_MAY_REG:.*]],
9290

93-
// LLVM: [[BB_END:.*]]: ; preds = %[[BB_ON_STACK]], %[[BB_IN_REG:.*]]
94-
// LLVM-NEXT: [[PHIP:%.*]] = phi ptr [ [[IN_REG_OUTPUT:%.*]], %[[BB_IN_REG]] ], [ [[STACK_V:%.*]], %[[BB_ON_STACK]] ]
95-
// LLVM-NEXT: [[PHIV:%.*]] = load double, ptr [[PHIP]], align 8,
96-
// LLVM-NEXT: store double [[PHIV]], ptr [[RESP]], align 8,
97-
// LLVM: call void @llvm.va_end.p0(ptr [[VARLIST]]),
98-
// LLVM: [[RES:%.*]] = load double, ptr [[RESP]], align 8,
99-
// LLVM: store double [[RES]], ptr [[RETP]], align 8,
100-
// LLVM: [[RETV:%.*]] = load double, ptr [[RETP]], align 8,
101-
// LLVM-NEXT: ret double [[RETV]],
102-
10391
// LLVM: [[BB_MAY_REG]]: ;
10492
// LLVM-NEXT: [[NEW_REG_OFFS:%.*]] = add i32 [[VR_OFFS]], 16,
10593
// LLVM-NEXT: store i32 [[NEW_REG_OFFS]], ptr [[VR_OFFS_P]], align 4,
10694
// LLVM-NEXT: [[CMP1:%.*]] = icmp sle i32 [[NEW_REG_OFFS]], 0,
107-
// LLVM-NEXT: br i1 [[CMP1]], label %[[BB_IN_REG]], label %[[BB_ON_STACK]],
95+
// LLVM-NEXT: br i1 [[CMP1]], label %[[BB_IN_REG:.*]], label %[[BB_ON_STACK]],
10896

10997
// LLVM: [[BB_IN_REG]]: ;
11098
// LLVM-NEXT: [[VR_TOP_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 2,
11199
// LLVM-NEXT: [[VR_TOP:%.*]] = load ptr, ptr [[VR_TOP_P]], align 8,
112100
// LLVM-NEXT: [[EXT64_VR_OFFS:%.*]] = sext i32 [[VR_OFFS]] to i64,
113-
// LLVM-NEXT: [[IN_REG_OUTPUT]] = getelementptr i8, ptr [[VR_TOP]], i64 [[EXT64_VR_OFFS]],
114-
// LLVM-NEXT: br label %[[BB_END]],
101+
// LLVM-NEXT: [[IN_REG_OUTPUT:%.*]] = getelementptr i8, ptr [[VR_TOP]], i64 [[EXT64_VR_OFFS]],
102+
// LLVM-NEXT: br label %[[BB_END:.*]],
115103

116104
// LLVM: [[BB_ON_STACK]]: ;
117105
// LLVM-NEXT: [[STACK_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 0,
118-
// LLVM-NEXT: [[STACK_V]] = load ptr, ptr [[STACK_P]], align 8,
106+
// LLVM-NEXT: [[STACK_V:%.*]] = load ptr, ptr [[STACK_P]], align 8,
119107
// LLVM-NEXT: [[NEW_STACK_V:%.*]] = getelementptr i8, ptr [[STACK_V]], i32 8,
120108
// LLVM-NEXT: store ptr [[NEW_STACK_V]], ptr [[STACK_P]], align 8,
121109
// LLVM-NEXT: br label %[[BB_END]],
110+
111+
// LLVM: [[BB_END]]: ; preds = %[[BB_ON_STACK]], %[[BB_IN_REG]]
112+
// LLVM-NEXT: [[PHIP:%.*]] = phi ptr [ [[IN_REG_OUTPUT]], %[[BB_IN_REG]] ], [ [[STACK_V]], %[[BB_ON_STACK]] ]
113+
// LLVM-NEXT: [[PHIV:%.*]] = load double, ptr [[PHIP]], align 8,
114+
// LLVM-NEXT: store double [[PHIV]], ptr [[RESP]], align 8,
115+
// LLVM: call void @llvm.va_end.p0(ptr [[VARLIST]]),
116+
// LLVM: [[RES:%.*]] = load double, ptr [[RESP]], align 8,
117+
// LLVM: store double [[RES]], ptr [[RETP]], align 8,
118+
// LLVM: [[RETV:%.*]] = load double, ptr [[RETP]], align 8,
119+
// LLVM-NEXT: ret double [[RETV]],
+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=BEFORE
2+
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=AFTER
3+
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-llvm %s -o %t.ll
4+
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
5+
// XFAIL: *
6+
7+
void f1(__builtin_va_list c) {
8+
{ __builtin_va_arg(c, void *); }
9+
}
10+
11+
// BEFORE: cir.func @f1(%arg0: !ty_22__va_list22) attributes
12+
// BEFORE: [[VAR_LIST:%.*]] = cir.alloca !ty_22__va_list22, !cir.ptr<!ty_22__va_list22>, ["c", init] {alignment = 8 : i64}
13+
// BEFORE: cir.store %arg0, [[VAR_LIST]] : !ty_22__va_list22, !cir.ptr<!ty_22__va_list22>
14+
// BEFORE: cir.scope {
15+
// BEFORE-NEXT: [[TMP:%.*]] = cir.va.arg [[VAR_LIST]] : (!cir.ptr<!ty_22__va_list22>) -> !cir.ptr<!void>
16+
// BEFORE-NEXT: }
17+
// BEFORE-NEXT: cir.return
18+
19+
// AFTER: cir.func @f1(%arg0: !ty_22__va_list22) attributes
20+
// AFTER: [[VARLIST:%.*]] = cir.alloca !ty_22__va_list22, !cir.ptr<!ty_22__va_list22>, ["c", init] {alignment = 8 : i64}
21+
// AFTER: cir.store %arg0, [[VARLIST]] : !ty_22__va_list22, !cir.ptr<!ty_22__va_list22>
22+
// AFTER: cir.scope {
23+
//
24+
// AFTER-NEXT: [[GR_OFFS_P:%.*]] = cir.get_member [[VARLIST]][3] {name = "gr_offs"} : !cir.ptr<!ty_22__va_list22> -> !cir.ptr<!s32i>
25+
// AFTER-NEXT: [[GR_OFFS:%.*]] = cir.load [[GR_OFFS_P]] : !cir.ptr<!s32i>
26+
// AFTER: [[ZERO:%.*]] = cir.const #cir.int<0> : !s32i
27+
// AFTER: [[CMP0:%.*]] = cir.cmp(ge, [[GR_OFFS]], [[ZERO]]) : !s32i, !cir.bool
28+
// AFTER-NEXT: cir.brcond [[CMP0]] [[BB_ON_STACK:\^bb.*]], [[BB_MAY_REG:\^bb.*]]
29+
30+
// This BB calculates to see if it is possible to pass arg in register.
31+
// AFTER: [[BB_MAY_REG]]:
32+
// AFTER-NEXT: [[EIGHT:%.*]] = cir.const #cir.int<8> : !s32i
33+
// AFTER-NEXT: [[NEW_REG_OFFS:%.*]] = cir.binop(add, [[GR_OFFS]], [[EIGHT]]) : !s32i
34+
// AFTER-NEXT: cir.store [[NEW_REG_OFFS]], [[GR_OFFS_P]] : !s32i, !cir.ptr<!s32i>
35+
// AFTER-NEXT: [[CMP1:%.*]] = cir.cmp(le, [[NEW_REG_OFFS]], [[ZERO]]) : !s32i, !cir.bool
36+
// AFTER-NEXT: cir.brcond [[CMP1]] [[BB_IN_REG:\^bb.*]], [[BB_ON_STACK]]
37+
38+
// arg is passed in register.
39+
// AFTER: [[BB_IN_REG]]:
40+
// AFTER-NEXT: [[GR_TOP_P:%.*]] = cir.get_member [[VARLIST]][1] {name = "gr_top"} : !cir.ptr<!ty_22__va_list22> -> !cir.ptr<!cir.ptr<!void>>
41+
// AFTER-NEXT: [[GR_TOP:%.*]] = cir.load [[GR_TOP_P]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
42+
// AFTER-NEXT: [[TMP2:%.*]] = cir.cast(bitcast, [[GR_TOP]] : !cir.ptr<!void>), !cir.ptr<i8>
43+
// AFTER-NEXT: [[TMP3:%.*]] = cir.ptr_stride([[TMP2]] : !cir.ptr<i8>, [[GR_OFFS]] : !s32i), !cir.ptr<i8>
44+
// AFTER-NEXT: [[IN_REG_OUTPUT:%.*]] = cir.cast(bitcast, [[TMP3]] : !cir.ptr<i8>), !cir.ptr<!void>
45+
// AFTER-NEXT: cir.br [[BB_END:\^bb.*]]([[IN_REG_OUTPUT]] : !cir.ptr<!void>)
46+
47+
// arg is passed in stack.
48+
// AFTER: [[BB_ON_STACK]]:
49+
// AFTER-NEXT: [[STACK_P:%.*]] = cir.get_member [[VARLIST]][0] {name = "stack"} : !cir.ptr<!ty_22__va_list22> -> !cir.ptr<!cir.ptr<!void>>
50+
// AFTER-NEXT: [[STACK_V:%.*]] = cir.load [[STACK_P]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
51+
// AFTER-NEXT: [[EIGHT_IN_PTR_ARITH:%.*]] = cir.const #cir.int<8> : !u64i
52+
// AFTER-NEXT: [[TMP4:%.*]] = cir.cast(bitcast, [[STACK_V]] : !cir.ptr<!void>), !cir.ptr<i8>
53+
// AFTER-NEXT: [[TMP5:%.*]] = cir.ptr_stride([[TMP4]] : !cir.ptr<i8>, [[EIGHT_IN_PTR_ARITH]] : !u64i), !cir.ptr<i8>
54+
// AFTER-NEXT: [[NEW_STACK_V:%.*]] = cir.cast(bitcast, [[TMP5]] : !cir.ptr<i8>), !cir.ptr<!void>
55+
// AFTER-NEXT: cir.store [[NEW_STACK_V]], [[STACK_P]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
56+
// AFTER-NEXT: cir.br [[BB_END]]([[STACK_V]] : !cir.ptr<!void>)
57+
58+
// This BB is where different path converges. BLK_ARG is the arg addr which
59+
// could come from IN_REG block where arg is passed in register, and saved in callee
60+
// stack's argument saving area.
61+
// Or from ON_STACK block which means arg is passed in from caller's stack area.
62+
// AFTER-NEXT: [[BB_END]]([[BLK_ARG:%.*]]: !cir.ptr<!void>): // 2 preds: [[BB_IN_REG]], [[BB_ON_STACK]]
63+
// AFTER-NEXT: [[TMP0:%.*]] = cir.cast(bitcast, [[BLK_ARG]] : !cir.ptr<!void>), !cir.ptr<!cir.ptr<!void>>
64+
// AFTER-NEXT: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
65+
// AFTER-NEXT: cir.yield
66+
// AFTER-NEXT: }
67+
// AFTER-NEXT: cir.return
68+
69+
// LLVM: %struct.__va_list = type { ptr, ptr, ptr, i32, i32 }
70+
// LLVM: define void @f1(%struct.__va_list %0)
71+
// LLVM: [[VARLIST:%.*]] = alloca %struct.__va_list, i64 1, align 8,
72+
// LLVM: br label %[[SCOPE_FRONT:.*]],
73+
74+
// LLVM: [[SCOPE_FRONT]]: ; preds = %1
75+
// LLVM: [[GR_OFFS_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 3
76+
// LLVM: [[GR_OFFS:%.*]] = load i32, ptr [[GR_OFFS_P]], align 4,
77+
// LLVM-NEXT: [[CMP0:%.*]] = icmp sge i32 [[GR_OFFS]], 0,
78+
// LLVM-NEXT: br i1 [[CMP0]], label %[[BB_ON_STACK:.*]], label %[[BB_MAY_REG:.*]],
79+
80+
// LLVM: [[BB_MAY_REG]]: ;
81+
// LLVM: [[NEW_REG_OFFS:%.*]] = add i32 [[GR_OFFS]], 8,
82+
// LLVM: store i32 [[NEW_REG_OFFS]], ptr [[GR_OFFS_P]], align 4,
83+
// LLVM-NEXT: [[CMP1:%.*]] = icmp sle i32 [[NEW_REG_OFFS]], 0,
84+
// LLVM-NEXT: br i1 [[CMP1]], label %[[BB_IN_REG:.*]], label %[[BB_ON_STACK]],
85+
86+
// LLVM: [[BB_IN_REG]]: ;
87+
// LLVM-NEXT: [[GR_TOP_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 1,
88+
// LLVM-NEXT: [[GR_TOP:%.*]] = load ptr, ptr [[GR_TOP_P]], align 8,
89+
// LLVM-NEXT: [[EXT64_GR_OFFS:%.*]] = sext i32 [[GR_OFFS]] to i64,
90+
// LLVM-NEXT: [[IN_REG_OUTPUT:%.*]] = getelementptr i8, ptr [[GR_TOP]], i64 [[EXT64_GR_OFFS]],
91+
// LLVM-NEXT: br label %[[BB_END:.*]],
92+
93+
// LLVM: [[BB_ON_STACK]]: ;
94+
// LLVM-NEXT: [[STACK_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 0,
95+
// LLVM-NEXT: [[STACK_V:%.*]] = load ptr, ptr [[STACK_P]], align 8,
96+
// LLVM-NEXT: [[NEW_STACK_V:%.*]] = getelementptr i8, ptr [[STACK_V]], i32 8,
97+
// LLVM-NEXT: store ptr [[NEW_STACK_V]], ptr [[STACK_P]], align 8,
98+
// LLVM-NEXT: br label %[[BB_END]],
99+
100+
// LLVM: [[BB_END]]: ; preds = %[[BB_ON_STACK]], %[[BB_IN_REG]]
101+
// LLVM-NEXT: [[PHIP:%.*]] = phi ptr [ [[IN_REG_OUTPUT]], %[[BB_IN_REG]] ], [ [[STACK_V]], %[[BB_ON_STACK]] ]
102+
// LLVM-NEXT: [[PHIV:%.*]] = load ptr, ptr [[PHIP]], align 8,
103+
// LLVM-NEXT: br label %[[OUT_SCOPE:.*]],
104+
105+
// LLVM: [[OUT_SCOPE]]: ; preds = %[[BB_END]]
106+
// LLVM-NEXT: ret void,

clang/test/CIR/CodeGen/var-arg.c

+30-30
Original file line numberDiff line numberDiff line change
@@ -38,27 +38,13 @@ int f1(int n, ...) {
3838
// AFTER: [[CMP0:%.*]] = cir.cmp(ge, [[GR_OFFS]], [[ZERO]]) : !s32i, !cir.bool
3939
// AFTER-NEXT: cir.brcond [[CMP0]] [[BB_ON_STACK:\^bb.*]], [[BB_MAY_REG:\^bb.*]]
4040

41-
// This BB is where different path converges. BLK_ARG is the arg addr which
42-
// could come from IN_REG block where arg is passed in register, and saved in callee
43-
// stack's argument saving area.
44-
// Or from ON_STACK block which means arg is passed in from caller's stack area.
45-
// AFTER-NEXT: [[BB_END:\^bb.*]]([[BLK_ARG:%.*]]: !cir.ptr<!void>): // 2 preds: [[BB_IN_REG:\^bb.*]], [[BB_ON_STACK]]
46-
// AFTER-NEXT: [[TMP0:%.*]] = cir.cast(bitcast, [[BLK_ARG]] : !cir.ptr<!void>), !cir.ptr<!s32i>
47-
// AFTER-NEXT: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr<!s32i>, !s32i
48-
// AFTER: cir.store [[TMP1]], [[RESP]] : !s32i, !cir.ptr<!s32i>
49-
// AFTER: cir.va.end [[VARLIST]] : !cir.ptr<!ty_22__va_list22>
50-
// AFTER: [[RES:%.*]] = cir.load [[RESP]] : !cir.ptr<!s32i>, !s32i
51-
// AFTER: cir.store [[RES]], [[RETP]] : !s32i, !cir.ptr<!s32i>
52-
// AFTER: [[RETV:%.*]] = cir.load [[RETP]] : !cir.ptr<!s32i>, !s32i
53-
// AFTER: cir.return [[RETV]] : !s32i
54-
5541
// This BB calculates to see if it is possible to pass arg in register.
5642
// AFTER: [[BB_MAY_REG]]:
5743
// AFTER-NEXT: [[EIGHT:%.*]] = cir.const #cir.int<8> : !s32i
5844
// AFTER-NEXT: [[NEW_REG_OFFS:%.*]] = cir.binop(add, [[GR_OFFS]], [[EIGHT]]) : !s32i
5945
// AFTER-NEXT: cir.store [[NEW_REG_OFFS]], [[GR_OFFS_P]] : !s32i, !cir.ptr<!s32i>
6046
// AFTER-NEXT: [[CMP1:%.*]] = cir.cmp(le, [[NEW_REG_OFFS]], [[ZERO]]) : !s32i, !cir.bool
61-
// AFTER-NEXT: cir.brcond [[CMP1]] [[BB_IN_REG]], [[BB_ON_STACK]]
47+
// AFTER-NEXT: cir.brcond [[CMP1]] [[BB_IN_REG:\^bb.*]], [[BB_ON_STACK]]
6248

6349
// arg is passed in register.
6450
// AFTER: [[BB_IN_REG]]:
@@ -67,7 +53,7 @@ int f1(int n, ...) {
6753
// AFTER-NEXT: [[TMP2:%.*]] = cir.cast(bitcast, [[GR_TOP]] : !cir.ptr<!void>), !cir.ptr<i8>
6854
// AFTER-NEXT: [[TMP3:%.*]] = cir.ptr_stride([[TMP2]] : !cir.ptr<i8>, [[GR_OFFS]] : !s32i), !cir.ptr<i8>
6955
// AFTER-NEXT: [[IN_REG_OUTPUT:%.*]] = cir.cast(bitcast, [[TMP3]] : !cir.ptr<i8>), !cir.ptr<!void>
70-
// AFTER-NEXT: cir.br [[BB_END]]([[IN_REG_OUTPUT]] : !cir.ptr<!void>)
56+
// AFTER-NEXT: cir.br [[BB_END:\^bb.*]]([[IN_REG_OUTPUT]] : !cir.ptr<!void>)
7157

7258
// arg is passed in stack.
7359
// AFTER: [[BB_ON_STACK]]:
@@ -80,6 +66,20 @@ int f1(int n, ...) {
8066
// AFTER-NEXT: cir.store [[NEW_STACK_V]], [[STACK_P]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
8167
// AFTER-NEXT: cir.br [[BB_END]]([[STACK_V]] : !cir.ptr<!void>)
8268

69+
// This BB is where different path converges. BLK_ARG is the arg addr which
70+
// could come from IN_REG block where arg is passed in register, and saved in callee
71+
// stack's argument saving area.
72+
// Or from ON_STACK block which means arg is passed in from caller's stack area.
73+
// AFTER-NEXT: [[BB_END]]([[BLK_ARG:%.*]]: !cir.ptr<!void>): // 2 preds: [[BB_IN_REG]], [[BB_ON_STACK]]
74+
// AFTER-NEXT: [[TMP0:%.*]] = cir.cast(bitcast, [[BLK_ARG]] : !cir.ptr<!void>), !cir.ptr<!s32i>
75+
// AFTER-NEXT: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr<!s32i>, !s32i
76+
// AFTER: cir.store [[TMP1]], [[RESP]] : !s32i, !cir.ptr<!s32i>
77+
// AFTER: cir.va.end [[VARLIST]] : !cir.ptr<!ty_22__va_list22>
78+
// AFTER: [[RES:%.*]] = cir.load [[RESP]] : !cir.ptr<!s32i>, !s32i
79+
// AFTER: cir.store [[RES]], [[RETP]] : !s32i, !cir.ptr<!s32i>
80+
// AFTER: [[RETV:%.*]] = cir.load [[RETP]] : !cir.ptr<!s32i>, !s32i
81+
// AFTER: cir.return [[RETV]] : !s32i
82+
8383
// LLVM: %struct.__va_list = type { ptr, ptr, ptr, i32, i32 }
8484
// LLVM: define i32 @f1(i32 %0, ...)
8585
// LLVM: [[ARGN:%.*]] = alloca i32, i64 1, align 4,
@@ -91,32 +91,32 @@ int f1(int n, ...) {
9191
// LLVM-NEXT: [[CMP0:%.*]] = icmp sge i32 [[GR_OFFS]], 0,
9292
// LLVM-NEXT: br i1 [[CMP0]], label %[[BB_ON_STACK:.*]], label %[[BB_MAY_REG:.*]],
9393

94-
// LLVM: [[BB_END:.*]]: ; preds = %[[BB_ON_STACK]], %[[BB_IN_REG:.*]]
95-
// LLVM-NEXT: [[PHIP:%.*]] = phi ptr [ [[IN_REG_OUTPUT:%.*]], %[[BB_IN_REG]] ], [ [[STACK_V:%.*]], %[[BB_ON_STACK]] ]
96-
// LLVM-NEXT: [[PHIV:%.*]] = load i32, ptr [[PHIP]], align 4,
97-
// LLVM-NEXT: store i32 [[PHIV]], ptr [[RESP]], align 4,
98-
// LLVM: call void @llvm.va_end.p0(ptr [[VARLIST]]),
99-
// LLVM: [[RES:%.*]] = load i32, ptr [[RESP]], align 4,
100-
// LLVM: store i32 [[RES]], ptr [[RETP]], align 4,
101-
// LLVM: [[RETV:%.*]] = load i32, ptr [[RETP]], align 4,
102-
// LLVM-NEXT: ret i32 [[RETV]],
103-
10494
// LLVM: [[BB_MAY_REG]]: ;
10595
// LLVM: [[NEW_REG_OFFS:%.*]] = add i32 [[GR_OFFS]], 8,
10696
// LLVM: store i32 [[NEW_REG_OFFS]], ptr [[GR_OFFS_P]], align 4,
10797
// LLVM-NEXT: [[CMP1:%.*]] = icmp sle i32 [[NEW_REG_OFFS]], 0,
108-
// LLVM-NEXT: br i1 [[CMP1]], label %[[BB_IN_REG]], label %[[BB_ON_STACK]],
98+
// LLVM-NEXT: br i1 [[CMP1]], label %[[BB_IN_REG:.*]], label %[[BB_ON_STACK]],
10999

110100
// LLVM: [[BB_IN_REG]]: ;
111101
// LLVM-NEXT: [[GR_TOP_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 1,
112102
// LLVM-NEXT: [[GR_TOP:%.*]] = load ptr, ptr [[GR_TOP_P]], align 8,
113103
// LLVM-NEXT: [[EXT64_GR_OFFS:%.*]] = sext i32 [[GR_OFFS]] to i64,
114-
// LLVM-NEXT: [[IN_REG_OUTPUT]] = getelementptr i8, ptr [[GR_TOP]], i64 [[EXT64_GR_OFFS]],
115-
// LLVM-NEXT: br label %[[BB_END]],
104+
// LLVM-NEXT: [[IN_REG_OUTPUT:%.*]] = getelementptr i8, ptr [[GR_TOP]], i64 [[EXT64_GR_OFFS]],
105+
// LLVM-NEXT: br label %[[BB_END:.*]],
116106

117107
// LLVM: [[BB_ON_STACK]]: ;
118108
// LLVM-NEXT: [[STACK_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 0,
119-
// LLVM-NEXT: [[STACK_V]] = load ptr, ptr [[STACK_P]], align 8,
109+
// LLVM-NEXT: [[STACK_V:%.*]] = load ptr, ptr [[STACK_P]], align 8,
120110
// LLVM-NEXT: [[NEW_STACK_V:%.*]] = getelementptr i8, ptr [[STACK_V]], i32 8,
121111
// LLVM-NEXT: store ptr [[NEW_STACK_V]], ptr [[STACK_P]], align 8,
122112
// LLVM-NEXT: br label %[[BB_END]],
113+
114+
// LLVM: [[BB_END]]: ; preds = %[[BB_ON_STACK]], %[[BB_IN_REG]]
115+
// LLVM-NEXT: [[PHIP:%.*]] = phi ptr [ [[IN_REG_OUTPUT]], %[[BB_IN_REG]] ], [ [[STACK_V]], %[[BB_ON_STACK]] ]
116+
// LLVM-NEXT: [[PHIV:%.*]] = load i32, ptr [[PHIP]], align 4,
117+
// LLVM-NEXT: store i32 [[PHIV]], ptr [[RESP]], align 4,
118+
// LLVM: call void @llvm.va_end.p0(ptr [[VARLIST]]),
119+
// LLVM: [[RES:%.*]] = load i32, ptr [[RESP]], align 4,
120+
// LLVM: store i32 [[RES]], ptr [[RETP]], align 4,
121+
// LLVM: [[RETV:%.*]] = load i32, ptr [[RETP]], align 4,
122+
// LLVM-NEXT: ret i32 [[RETV]],

0 commit comments

Comments
 (0)