aboutsummaryrefslogtreecommitdiff
path: root/ifopt.c
blob: 3e45f52ce178c4ea35a15f7c1eda3e42e425d0a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include "all.h"

enum {
	MaxIns = 2,
	MaxPhis = 2,
};

static int
okbranch(Blk *b)
{
	Ins *i;
	int n;

	n = 0;
	for (i=b->ins; i<&b->ins[b->nins]; i++)
		if (i->op != Odbgloc) {
			if (pinned(i))
				return 0;
			if (i->op != Onop)
				n++;
		}
	return n <= MaxIns;
}

static int
okjoin(Blk *b)
{
	Phi *p;
	int n;

	n = 0;
	for (p=b->phi; p; p=p->link) {
		if (KBASE(p->cls) != 0)
			return 0;
		n++;
	}
	return n <= MaxPhis;
}

static int
okgraph(Blk *ifb, Blk *thenb, Blk *elseb, Blk *joinb)
{
	if (joinb->npred != 2 || !okjoin(joinb))
		return 0;
	assert(thenb != elseb);
	if (thenb != ifb && !okbranch(thenb))
		return 0;
	if (elseb != ifb && !okbranch(elseb))
		return 0;
	return 1;
}

static void
convert(Blk *ifb, Blk *thenb, Blk *elseb, Blk *joinb)
{
	Ins *ins, sel;
	Phi *p;
	uint nins;

	ins = vnew(0, sizeof ins[0], PHeap);
	nins = 0;
	addbins(&ins, &nins, ifb);
	if (thenb != ifb)
		addbins(&ins, &nins, thenb);
	if (elseb != ifb)
		addbins(&ins, &nins, elseb);
	assert(joinb->npred == 2);
	if (joinb->phi) {
		sel = (Ins){
			.op = Osel0, .cls = Kw,
			.arg = {ifb->jmp.arg},
		};
		addins(&ins, &nins, &sel);
	}
	sel = (Ins){.op = Osel1};
	for (p=joinb->phi; p; p=p->link) {
		sel.to = p->to;
		sel.cls = p->cls;
		sel.arg[0] = phiarg(p, thenb);
		sel.arg[1] = phiarg(p, elseb);
		addins(&ins, &nins, &sel);
	}
	idup(ifb, ins, nins);
	ifb->jmp.type = Jjmp;
	ifb->jmp.arg = R;
	ifb->s1 = joinb;
	ifb->s2 = 0;
	joinb->npred = 1;
	joinb->pred[0] = ifb;
	joinb->phi = 0;
	vfree(ins);
}

/* eliminate if-then[-else] graphlets
 * using sel instructions
 * needs rpo pred use; breaks cfg use
 */
void
ifconvert(Fn *fn)
{
	Blk *ifb, *thenb, *elseb, *joinb;

	if (debug['K'])
		fputs("\n> If-conversion:\n", stderr);

	for (ifb=fn->start; ifb; ifb=ifb->link)
		if (ifgraph(ifb, &thenb, &elseb, &joinb))
		if (okgraph(ifb, thenb, elseb, joinb)) {
			if (debug['K'])
				fprintf(stderr,
					"    @%s -> @%s, @%s -> @%s\n",
					ifb->name, thenb->name, elseb->name,
					joinb->name);
			convert(ifb, thenb, elseb, joinb);
		}

	if (debug['K']) {
		fprintf(stderr, "\n> After if-conversion:\n");
		printfn(fn, stderr);
	}
}