-
Notifications
You must be signed in to change notification settings - Fork 0
/
validate.c
182 lines (157 loc) · 4.38 KB
/
validate.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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#include "validate.h"
#include "../util.h"
#include "ir.h"
struct validate_op_order_metadata {
struct ir_op *consumer;
};
static void validate_op_order(struct ir_op **ir, void *metadata) {
struct validate_op_order_metadata *data = metadata;
struct ir_op *consumer = data->consumer;
if (consumer->ty == IR_OP_TY_PHI || (consumer->flags & IR_OP_FLAG_PHI_MOV)) {
// these can work across time
return;
}
struct ir_op *op = *ir;
if (op->id > consumer->id) {
BUG("op %zu uses op %zu which is ahead of it", consumer->id, op->id);
}
}
static void ir_validate_op(UNUSED struct ir_func *func, struct ir_op *op) {
struct validate_op_order_metadata metadata = {.consumer = op};
walk_op_uses(op, validate_op_order, &metadata);
switch (op->ty) {
case IR_OP_TY_UNKNOWN:
BUG("should not have unknown ops");
case IR_OP_TY_PHI:
break;
case IR_OP_TY_UNDF:
break;
case IR_OP_TY_MOV:
break;
case IR_OP_TY_CNST:
break;
case IR_OP_TY_BINARY_OP:
break;
case IR_OP_TY_UNARY_OP:
break;
case IR_OP_TY_CAST_OP:
break;
case IR_OP_TY_LOAD:
invariant_assert(!op->lcl, "op %zu: loads should not have locals", op->id);
switch (op->load.ty) {
case IR_OP_LOAD_TY_LCL:
invariant_assert(op->load.lcl, "op %zu: load ty lcl must have lcl",
op->id);
break;
case IR_OP_LOAD_TY_GLB:
invariant_assert(op->load.glb, "op %zu: load ty glb must have glb",
op->id);
break;
case IR_OP_LOAD_TY_ADDR:
invariant_assert(op->load.addr, "op %zu: load ty addr must have addr",
op->id);
break;
}
break;
case IR_OP_TY_STORE:
invariant_assert(op->var_ty.ty == IR_VAR_TY_TY_NONE,
"op %zu: store ops should not have a var ty", op->id);
switch (op->store.ty) {
case IR_OP_STORE_TY_LCL:
invariant_assert(op->store.lcl, "op %zu: store ty lcl must have lcl",
op->id);
break;
case IR_OP_STORE_TY_GLB:
invariant_assert(op->store.glb, "op %zu: store ty glb must have glb",
op->id);
break;
case IR_OP_STORE_TY_ADDR:
invariant_assert(op->store.addr, "op %zu: store ty addr must have addr",
op->id);
break;
}
invariant_assert(!op->lcl, "op %zu: stores should not have locals", op->id);
break;
case IR_OP_TY_STORE_BITFIELD:
break;
case IR_OP_TY_LOAD_BITFIELD:
break;
case IR_OP_TY_ADDR:
break;
case IR_OP_TY_BR:
break;
case IR_OP_TY_BR_COND:
break;
case IR_OP_TY_BR_SWITCH:
break;
case IR_OP_TY_RET:
break;
case IR_OP_TY_CALL:
break;
case IR_OP_TY_CUSTOM:
break;
case IR_OP_TY_BITFIELD_EXTRACT:
break;
case IR_OP_TY_BITFIELD_INSERT:
break;
case IR_OP_TY_MEM_SET:
break;
case IR_OP_TY_ADDR_OFFSET:
invariant_assert(popcntl(op->addr_offset.scale) == 1, "op %zu: scale must be power of 2",
op->id);
break;
}
}
static void ir_validate_stmt(struct ir_func *func, struct ir_stmt *stmt) {
struct ir_op *op = stmt->first;
while (op) {
ir_validate_op(func, op);
op = op->succ;
}
}
static void ir_validate_basicblock(struct ir_func *func,
struct ir_basicblock *basicblock) {
struct ir_stmt *stmt = basicblock->first;
while (stmt) {
ir_validate_stmt(func, stmt);
stmt = stmt->succ;
}
}
static void ir_validate_data(struct ir_unit *iru, struct ir_glb *glb) {}
static void ir_validate_func(struct ir_unit *iru, struct ir_glb *glb) {
switch (glb->def_ty) {
case IR_GLB_DEF_TY_DEFINED:
if (!glb->func) {
BUG("defined global should have func");
}
break;
case IR_GLB_DEF_TY_UNDEFINED:
if (glb->func) {
BUG("undefined global should not have func");
}
return;
case IR_GLB_DEF_TY_TENTATIVE:
BUG("should not have tentative defs by now");
}
struct ir_func *func = glb->func;
struct ir_basicblock *basicblock = func->first;
rebuild_ids(func);
while (basicblock) {
ir_validate_basicblock(func, basicblock);
basicblock = basicblock->succ;
}
}
void ir_validate(struct ir_unit *iru) {
struct ir_glb *glb = iru->first_global;
while (glb) {
switch (glb->ty) {
case IR_GLB_TY_DATA:
ir_validate_data(iru, glb);
break;
case IR_GLB_TY_FUNC:
ir_validate_func(iru, glb);
break;
}
glb = glb->succ;
}
}