Skip to content

Commit 86bcec7

Browse files
lucvoosparsecli
authored andcommitted
split OP_BR between unconditional & conditional: OP_CBR
OP_BR instructions exist in two flavours, relatively much differentiated: conditional & non-conditional. One has an operand (and thus its usage need to be cared for, must be handled in liveness analysis, ..) the other has not; one has two BB target, the other only one. There is essentially no places in the code where both flavours are handled the same. Sometimes they both must be handled but each with their specificities but in most cases only one of them is concerned and we need to filter out the other one. In both cases it means that we need to check what kind we're dealing with. There is already a problem with this because there is several ways to test which kind an OP_BR is and they are not exactly equivalent: 1) testing if insn->cond is NULL 2) testing if one of insn->bb_true or ->bb_false is NULL. There exist also an helper (is_branch_goto()) which does the second tests but which is never used. It appears that the first test should not be used because in some cases an conditional OP_BR is changed into a non-conditional one by (amongst others things) setting it's ->cond to VOID. We should thus always use the seconds test (which need two compares with NULL). This could be corrected in several ways (like changing all the places wheer the first test is used, use the helper everywhere or never set ->cond to VOID) but the simplest is to simply split them in two separated instructions: OP_BR & OP_CBR, especailly given the fact that in most cases the OP_BR was first selected by a switch (opcode). Signed-off-by: Luc Van Oostenryck <[email protected]> Signed-off-by: Christopher Li <[email protected]>
1 parent 522773d commit 86bcec7

File tree

8 files changed

+179
-34
lines changed

8 files changed

+179
-34
lines changed

example.c

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ static const char *opcodes[] = {
2323
/* Terminator */
2424
[OP_RET] = "ret",
2525
[OP_BR] = "br",
26+
[OP_CBR] = "cbr",
2627
[OP_SWITCH] = "switch",
2728
[OP_INVOKE] = "invoke",
2829
[OP_COMPUTEDGOTO] = "jmp *",
@@ -1428,6 +1429,7 @@ static void generate_one_insn(struct instruction *insn, struct bb_state *state)
14281429
break;
14291430

14301431
case OP_BR:
1432+
case OP_CBR:
14311433
generate_branch(state, insn);
14321434
break;
14331435

flow.c

+11-6
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ static int try_to_simplify_bb(struct basic_block *bb, struct instruction *first,
111111
br = last_instruction(source->insns);
112112
if (!br)
113113
continue;
114-
if (br->opcode != OP_BR)
114+
if (br->opcode != OP_CBR && br->opcode != OP_BR)
115115
continue;
116116
true = pseudo_truth_value(pseudo);
117117
if (true < 0)
@@ -176,7 +176,7 @@ static int simplify_branch_branch(struct basic_block *bb, struct instruction *br
176176
if (target == bb)
177177
return 0;
178178
insn = last_instruction(target->insns);
179-
if (!insn || insn->opcode != OP_BR || insn->cond != br->cond)
179+
if (!insn || insn->opcode != OP_CBR || insn->cond != br->cond)
180180
return 0;
181181
/*
182182
* Ahhah! We've found a branch to a branch on the same conditional!
@@ -218,7 +218,7 @@ static int simplify_branch_nodes(struct entrypoint *ep)
218218
FOR_EACH_PTR(ep->bbs, bb) {
219219
struct instruction *br = last_instruction(bb->insns);
220220

221-
if (!br || br->opcode != OP_BR || !br->bb_false)
221+
if (!br || br->opcode != OP_CBR)
222222
continue;
223223
changed |= simplify_one_branch(bb, br);
224224
} END_FOR_EACH_PTR(bb);
@@ -811,9 +811,11 @@ static int rewrite_parent_branch(struct basic_block *bb, struct basic_block *old
811811
return 0;
812812

813813
switch (insn->opcode) {
814+
case OP_CBR:
815+
changed |= rewrite_branch(bb, &insn->bb_false, old, new);
816+
/* fall through */
814817
case OP_BR:
815818
changed |= rewrite_branch(bb, &insn->bb_true, old, new);
816-
changed |= rewrite_branch(bb, &insn->bb_false, old, new);
817819
assert(changed);
818820
return changed;
819821
case OP_SWITCH: {
@@ -835,7 +837,7 @@ static struct basic_block * rewrite_branch_bb(struct basic_block *bb, struct ins
835837
struct basic_block *target = br->bb_true;
836838
struct basic_block *false = br->bb_false;
837839

838-
if (target && false) {
840+
if (br->opcode == OP_CBR) {
839841
pseudo_t cond = br->cond;
840842
if (cond->type != PSEUDO_VAL)
841843
return NULL;
@@ -886,9 +888,11 @@ static void vrfy_children(struct basic_block *bb)
886888
}
887889
switch (br->opcode) {
888890
struct multijmp *jmp;
891+
case OP_CBR:
892+
vrfy_bb_in_list(br->bb_false, bb->children);
893+
/* fall through */
889894
case OP_BR:
890895
vrfy_bb_in_list(br->bb_true, bb->children);
891-
vrfy_bb_in_list(br->bb_false, bb->children);
892896
break;
893897
case OP_SWITCH:
894898
case OP_COMPUTEDGOTO:
@@ -945,6 +949,7 @@ void pack_basic_blocks(struct entrypoint *ep)
945949
switch (first->opcode) {
946950
case OP_NOP: case OP_LNOP: case OP_SNOP:
947951
continue;
952+
case OP_CBR:
948953
case OP_BR: {
949954
struct basic_block *replace;
950955
replace = rewrite_branch_bb(bb, first);

linearize.c

+8-6
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ static const char *opcodes[] = {
170170
/* Terminator */
171171
[OP_RET] = "ret",
172172
[OP_BR] = "br",
173+
[OP_CBR] = "cbr",
173174
[OP_SWITCH] = "switch",
174175
[OP_INVOKE] = "invoke",
175176
[OP_COMPUTEDGOTO] = "jmp *",
@@ -304,12 +305,13 @@ const char *show_instruction(struct instruction *insn)
304305
if (insn->src && insn->src != VOID)
305306
buf += sprintf(buf, "%s", show_pseudo(insn->src));
306307
break;
308+
309+
case OP_CBR:
310+
buf += sprintf(buf, "%s, .L%u, .L%u", show_pseudo(insn->cond), insn->bb_true->nr, insn->bb_false->nr);
311+
break;
312+
307313
case OP_BR:
308-
if (insn->bb_true && insn->bb_false) {
309-
buf += sprintf(buf, "%s, .L%u, .L%u", show_pseudo(insn->cond), insn->bb_true->nr, insn->bb_false->nr);
310-
break;
311-
}
312-
buf += sprintf(buf, ".L%u", insn->bb_true ? insn->bb_true->nr : insn->bb_false->nr);
314+
buf += sprintf(buf, ".L%u", insn->bb_true->nr);
313315
break;
314316

315317
case OP_SYMADDR: {
@@ -724,7 +726,7 @@ static void add_branch(struct entrypoint *ep, struct expression *expr, pseudo_t
724726
struct instruction *br;
725727

726728
if (bb_reachable(bb)) {
727-
br = alloc_instruction(OP_BR, 0);
729+
br = alloc_instruction(OP_CBR, 0);
728730
use_pseudo(br, cond, &br->cond);
729731
br->bb_true = bb_true;
730732
br->bb_false = bb_false;

linearize.h

+1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ enum opcode {
137137
OP_TERMINATOR,
138138
OP_RET = OP_TERMINATOR,
139139
OP_BR,
140+
OP_CBR,
140141
OP_SWITCH,
141142
OP_INVOKE,
142143
OP_COMPUTEDGOTO,

liveness.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ static void track_instruction_usage(struct basic_block *bb, struct instruction *
5656
USES(src);
5757
break;
5858

59-
case OP_BR: case OP_SWITCH:
59+
case OP_CBR:
60+
case OP_SWITCH:
6061
USES(cond);
6162
break;
6263

simplify.c

+5-10
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ static int if_convert_phi(struct instruction *insn)
6767
* stuff. Verify that here.
6868
*/
6969
br = last_instruction(source->insns);
70-
if (!br || br->opcode != OP_BR)
70+
if (!br || br->opcode != OP_CBR)
7171
return 0;
7272

7373
assert(br->cond);
@@ -227,11 +227,7 @@ void kill_insn(struct instruction *insn, int force)
227227
repeat_phase |= REPEAT_SYMBOL_CLEANUP;
228228
break;
229229

230-
case OP_BR:
231-
if (!insn->bb_true || !insn->bb_false)
232-
break;
233-
/* fall through */
234-
230+
case OP_CBR:
235231
case OP_COMPUTEDGOTO:
236232
kill_use(&insn->cond);
237233
break;
@@ -266,6 +262,7 @@ void kill_insn(struct instruction *insn, int force)
266262
/* ignore */
267263
return;
268264

265+
case OP_BR:
269266
default:
270267
break;
271268
}
@@ -1035,9 +1032,6 @@ static int simplify_branch(struct instruction *insn)
10351032
{
10361033
pseudo_t cond = insn->cond;
10371034

1038-
if (!cond)
1039-
return 0;
1040-
10411035
/* Constant conditional */
10421036
if (constant(cond)) {
10431037
insert_branch(insn->bb, insn, cond->value ? insn->bb_true : insn->bb_false);
@@ -1053,6 +1047,7 @@ static int simplify_branch(struct instruction *insn)
10531047
insn->bb_false = NULL;
10541048
kill_use(&insn->cond);
10551049
insn->cond = NULL;
1050+
insn->opcode = OP_BR;
10561051
return REPEAT_CSE;
10571052
}
10581053

@@ -1182,7 +1177,7 @@ int simplify_instruction(struct instruction *insn)
11821177
break;
11831178
case OP_SEL:
11841179
return simplify_select(insn);
1185-
case OP_BR:
1180+
case OP_CBR:
11861181
return simplify_branch(insn);
11871182
case OP_SWITCH:
11881183
return simplify_switch(insn);

sparse-llvm.c

+14-11
Original file line numberDiff line numberDiff line change
@@ -642,19 +642,19 @@ static LLVMValueRef bool_value(struct function *fn, LLVMValueRef value)
642642
return value;
643643
}
644644

645-
static void output_op_br(struct function *fn, struct instruction *br)
645+
static void output_op_cbr(struct function *fn, struct instruction *br)
646646
{
647-
if (br->cond) {
648-
LLVMValueRef cond = bool_value(fn,
649-
pseudo_to_value(fn, br, br->cond));
647+
LLVMValueRef cond = bool_value(fn,
648+
pseudo_to_value(fn, br, br->cond));
650649

651-
LLVMBuildCondBr(fn->builder, cond,
652-
br->bb_true->priv,
653-
br->bb_false->priv);
654-
} else
655-
LLVMBuildBr(fn->builder,
656-
br->bb_true ? br->bb_true->priv :
657-
br->bb_false->priv);
650+
LLVMBuildCondBr(fn->builder, cond,
651+
br->bb_true->priv,
652+
br->bb_false->priv);
653+
}
654+
655+
static void output_op_br(struct function *fn, struct instruction *br)
656+
{
657+
LLVMBuildBr(fn->builder, br->bb_true->priv);
658658
}
659659

660660
static void output_op_sel(struct function *fn, struct instruction *insn)
@@ -810,6 +810,9 @@ static void output_insn(struct function *fn, struct instruction *insn)
810810
case OP_BR:
811811
output_op_br(fn, insn);
812812
break;
813+
case OP_CBR:
814+
output_op_cbr(fn, insn);
815+
break;
813816
case OP_SYMADDR:
814817
assert(0);
815818
break;

validation/loop-linearization.c

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
extern int p(int);
2+
3+
static int ffor(void)
4+
{
5+
int i;
6+
for (int i = 0; i < 10; i++) {
7+
if (!p(i))
8+
return 0;
9+
}
10+
return 1;
11+
}
12+
13+
static int fwhile(void)
14+
{
15+
int i = 0;
16+
while (i < 10) {
17+
if (!p(i))
18+
return 0;
19+
i++;
20+
}
21+
return 1;
22+
}
23+
24+
static int fdo(void)
25+
{
26+
int i = 0;
27+
do {
28+
if (!p(i))
29+
return 0;
30+
} while (i++ < 10);
31+
return 1;
32+
}
33+
34+
/*
35+
* check-name: loop-linearization
36+
* check-command: test-linearize $file
37+
*
38+
* check-output-start
39+
ffor:
40+
.L0:
41+
<entry-point>
42+
phisrc.32 %phi5(i) <- $0
43+
br .L4
44+
45+
.L4:
46+
phi.32 %r1(i) <- %phi5(i), %phi6(i)
47+
setlt.32 %r2 <- %r1(i), $10
48+
cbr %r2, .L1, .L3
49+
50+
.L1:
51+
call.32 %r4 <- p, %r1(i)
52+
cbr %r4, .L2, .L5
53+
54+
.L5:
55+
phisrc.32 %phi1(return) <- $0
56+
br .L7
57+
58+
.L2:
59+
add.32 %r7 <- %r1(i), $1
60+
phisrc.32 %phi6(i) <- %r7
61+
br .L4
62+
63+
.L3:
64+
phisrc.32 %phi2(return) <- $1
65+
br .L7
66+
67+
.L7:
68+
phi.32 %r5 <- %phi1(return), %phi2(return)
69+
ret.32 %r5
70+
71+
72+
fwhile:
73+
.L8:
74+
<entry-point>
75+
phisrc.32 %phi11(i) <- $0
76+
br .L12
77+
78+
.L12:
79+
phi.32 %r8(i) <- %phi11(i), %phi12(i)
80+
setlt.32 %r9 <- %r8(i), $10
81+
cbr %r9, .L9, .L11
82+
83+
.L9:
84+
call.32 %r11 <- p, %r8(i)
85+
cbr %r11, .L14, .L13
86+
87+
.L13:
88+
phisrc.32 %phi7(return) <- $0
89+
br .L15
90+
91+
.L14:
92+
add.32 %r14 <- %r8(i), $1
93+
phisrc.32 %phi12(i) <- %r14
94+
br .L12
95+
96+
.L11:
97+
phisrc.32 %phi8(return) <- $1
98+
br .L15
99+
100+
.L15:
101+
phi.32 %r12 <- %phi7(return), %phi8(return)
102+
ret.32 %r12
103+
104+
105+
fdo:
106+
.L16:
107+
<entry-point>
108+
phisrc.32 %phi16(i) <- $0
109+
br .L17
110+
111+
.L17:
112+
phi.32 %r15(i) <- %phi16(i), %phi17(i)
113+
call.32 %r16 <- p, %r15(i)
114+
cbr %r16, .L18, .L20
115+
116+
.L20:
117+
phisrc.32 %phi13(return) <- $0
118+
br .L22
119+
120+
.L18:
121+
add.32 %r19 <- %r15(i), $1
122+
setlt.32 %r20 <- %r15(i), $10
123+
phisrc.32 %phi17(i) <- %r19
124+
cbr %r20, .L17, .L19
125+
126+
.L19:
127+
phisrc.32 %phi14(return) <- $1
128+
br .L22
129+
130+
.L22:
131+
phi.32 %r17 <- %phi13(return), %phi14(return)
132+
ret.32 %r17
133+
134+
135+
* check-output-end
136+
*/

0 commit comments

Comments
 (0)