-
Notifications
You must be signed in to change notification settings - Fork 5
/
tree.c
168 lines (157 loc) · 4 KB
/
tree.c
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <assert.h>
#include "cc.h"
#define WRN_EXPR_RESULT_NOT_USED "expression result not used"
static struct tree *root1(struct tree *p, int warn)
{
switch (OPKIND(p->op)) {
case RIGHT:
if (p->kids[1] == NULL)
return root1(p->kids[0], warn);
if (p->kids[0] &&
p->kids[0]->op == RIGHT &&
p->kids[0]->kids[0] == p->kids[1])
// postfix increment
return p->kids[0]->kids[1];
if (p->kids[0] &&
opid(p->kids[0]->op) == CALL+S &&
p->kids[1] &&
opid(p->kids[1]->op) == INDIR+S)
// funcall
return p->kids[0];
p = ast_expr(RIGHT, p->type,
root1(p->kids[0], warn),
root1(p->kids[1], warn));
return p->kids[0] || p->kids[1] ? p : NULL;
case COND:
{
struct tree *r = p->kids[1];
assert(OPKIND(r->op) == RIGHT);
if (p->s.sym && OPKIND(r->kids[0]->op) == ASGN)
r->kids[0] = root1(r->kids[0]->kids[1], warn+1);
else
r->kids[0] = root1(r->kids[0], warn+1);
if (p->s.sym && OPKIND(r->kids[1]->op) == ASGN)
r->kids[1] = root1(r->kids[1]->kids[1], warn+1);
else
r->kids[1] = root1(r->kids[1], warn+1);
// discard the result
if (p->s.sym)
deuse(p->s.sym);
p->s.sym = NULL;
if (r->kids[0] == NULL && r->kids[1] == NULL)
return root1(p->kids[0], warn);
else
return p;
}
case AND:
case OR:
if (root1(p->kids[1], warn) == NULL)
return root1(p->kids[0], warn+1);
else
return p;
// binary
case ADD:
case SUB:
case MUL:
case DIV:
case MOD:
case SHL:
case SHR:
case BAND:
case BOR:
case XOR:
case EQ:
case NE:
case GT:
case GE:
case LT:
case LE:
if (warn++ == 0)
warning(WRN_EXPR_RESULT_NOT_USED);
p = ast_expr(RIGHT, p->type,
root1(p->kids[0], warn),
root1(p->kids[1], warn));
return p->kids[0] || p->kids[1] ? p : NULL;
case INDIR:
if (iscpliteral(p))
// TODO: compound literal
return p;
// fall through
case BFIELD:
// unary
case NEG:
case BNOT:
// conv
if (warn++ == 0)
warning(WRN_EXPR_RESULT_NOT_USED);
case CVI:
case CVU:
case CVF:
case CVP:
return root1(p->kids[0], warn);
case CNST:
case ADDRG:
case ADDRP:
case ADDRL:
return NULL;
case CALL:
case ASGN:
return p;
default:
CC_UNAVAILABLE();
}
}
// remove expressions with no side-effect.
// expr may be NULL.
struct tree *root(struct tree *expr)
{
if (expr)
return root1(expr, 0);
else
return NULL;
}
// get the address of an expr returning struct/union
struct tree *addrof(struct tree *expr)
{
struct tree *p = expr;
while (1) {
switch (OPKIND(p->op)) {
case RIGHT:
assert(p->kids[1] || p->kids[0]);
p = p->kids[1] ? p->kids[1] : p->kids[0];
continue;
case COND:
p = mkref(p->s.sym);
// fall through
case INDIR:
case ASGN:
if (p == expr)
return p->kids[0];
p = p->kids[0];
return ast_expr(RIGHT, p->type, root(expr), p);
default:
CC_UNAVAILABLE();
}
}
}
// get the right-most kid of a RIGHT tree
struct tree *rightkid(struct tree *expr)
{
while (expr && expr->op == RIGHT) {
if (expr->kids[1])
expr = expr->kids[1];
else if (expr->kids[0])
expr = expr->kids[0];
else
assert(0 && "empty RIGHT tree");
}
return expr;
}
void gencode(struct symbol *s)
{
IR->gen(s);
}
void emitcode(struct symbol *s)
{
IR->emit(s);
}