Skip to content

Commit 1c0064b

Browse files
authored
[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 9720c61 commit 1c0064b

File tree

4 files changed

+171
-58
lines changed

4 files changed

+171
-58
lines changed

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

Lines changed: 10 additions & 0 deletions
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

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

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

5947

6048
// AFTER: [[BB_IN_REG]]:
@@ -63,7 +51,7 @@ double f1(int n, ...) {
6351
// AFTER-NEXT: [[TMP2:%.*]] = cir.cast(bitcast, [[VR_TOP]] : !cir.ptr<!void>), !cir.ptr<i8>
6452
// AFTER-NEXT: [[TMP3:%.*]] = cir.ptr_stride([[TMP2]] : !cir.ptr<i8>, [[VR_OFFS]] : !s32i), !cir.ptr<i8>
6553
// AFTER-NEXT: [[IN_REG_OUTPUT:%.*]] = cir.cast(bitcast, [[TMP3]] : !cir.ptr<i8>), !cir.ptr<!void>
66-
// AFTER-NEXT: cir.br [[BB_END]]([[IN_REG_OUTPUT]] : !cir.ptr<!void>)
54+
// AFTER-NEXT: cir.br [[BB_END:\^bb.*]]([[IN_REG_OUTPUT]] : !cir.ptr<!void>)
6755

6856

6957
// AFTER: [[BB_ON_STACK]]:
@@ -76,6 +64,16 @@ double f1(int n, ...) {
7664
// AFTER-NEXT: cir.store [[NEW_STACK_V]], [[STACK_P]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
7765
// AFTER-NEXT: cir.br [[BB_END]]([[STACK_V]] : !cir.ptr<!void>)
7866

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

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

10795
// LLVM: [[BB_IN_REG]]: ;
10896
// LLVM-NEXT: [[VR_TOP_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 2,
10997
// LLVM-NEXT: [[VR_TOP:%.*]] = load ptr, ptr [[VR_TOP_P]], align 8,
11098
// LLVM-NEXT: [[EXT64_VR_OFFS:%.*]] = sext i32 [[VR_OFFS]] to i64,
111-
// LLVM-NEXT: [[IN_REG_OUTPUT]] = getelementptr i8, ptr [[VR_TOP]], i64 [[EXT64_VR_OFFS]],
112-
// LLVM-NEXT: br label %[[BB_END]],
99+
// LLVM-NEXT: [[IN_REG_OUTPUT:%.*]] = getelementptr i8, ptr [[VR_TOP]], i64 [[EXT64_VR_OFFS]],
100+
// LLVM-NEXT: br label %[[BB_END:.*]],
113101

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

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

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

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

6147
// arg is passed in register.
6248
// AFTER: [[BB_IN_REG]]:
@@ -65,7 +51,7 @@ int f1(int n, ...) {
6551
// AFTER-NEXT: [[TMP2:%.*]] = cir.cast(bitcast, [[GR_TOP]] : !cir.ptr<!void>), !cir.ptr<i8>
6652
// AFTER-NEXT: [[TMP3:%.*]] = cir.ptr_stride([[TMP2]] : !cir.ptr<i8>, [[GR_OFFS]] : !s32i), !cir.ptr<i8>
6753
// 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>)
54+
// AFTER-NEXT: cir.br [[BB_END:\^bb.*]]([[IN_REG_OUTPUT]] : !cir.ptr<!void>)
6955

7056
// arg is passed in stack.
7157
// AFTER: [[BB_ON_STACK]]:
@@ -78,6 +64,20 @@ int f1(int n, ...) {
7864
// AFTER-NEXT: cir.store [[NEW_STACK_V]], [[STACK_P]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
7965
// AFTER-NEXT: cir.br [[BB_END]]([[STACK_V]] : !cir.ptr<!void>)
8066

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

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

10898
// LLVM: [[BB_IN_REG]]: ;
10999
// LLVM-NEXT: [[GR_TOP_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 1,
110100
// LLVM-NEXT: [[GR_TOP:%.*]] = load ptr, ptr [[GR_TOP_P]], align 8,
111101
// LLVM-NEXT: [[EXT64_GR_OFFS:%.*]] = sext i32 [[GR_OFFS]] to i64,
112-
// LLVM-NEXT: [[IN_REG_OUTPUT]] = getelementptr i8, ptr [[GR_TOP]], i64 [[EXT64_GR_OFFS]],
113-
// LLVM-NEXT: br label %[[BB_END]],
102+
// LLVM-NEXT: [[IN_REG_OUTPUT:%.*]] = getelementptr i8, ptr [[GR_TOP]], i64 [[EXT64_GR_OFFS]],
103+
// LLVM-NEXT: br label %[[BB_END:.*]],
114104

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

0 commit comments

Comments
 (0)