1*c85f09ccSJohn Levon // SPDX-License-Identifier: MIT
2*c85f09ccSJohn Levon
3*c85f09ccSJohn Levon #include "ir.h"
4*c85f09ccSJohn Levon #include "linearize.h"
5*c85f09ccSJohn Levon #include <stdlib.h>
6*c85f09ccSJohn Levon #include <assert.h>
7*c85f09ccSJohn Levon
8*c85f09ccSJohn Levon
nbr_phi_operands(struct instruction * insn)9*c85f09ccSJohn Levon static int nbr_phi_operands(struct instruction *insn)
10*c85f09ccSJohn Levon {
11*c85f09ccSJohn Levon pseudo_t p;
12*c85f09ccSJohn Levon int nbr = 0;
13*c85f09ccSJohn Levon
14*c85f09ccSJohn Levon if (!insn->phi_list)
15*c85f09ccSJohn Levon return 0;
16*c85f09ccSJohn Levon
17*c85f09ccSJohn Levon FOR_EACH_PTR(insn->phi_list, p) {
18*c85f09ccSJohn Levon if (p == VOID)
19*c85f09ccSJohn Levon continue;
20*c85f09ccSJohn Levon nbr++;
21*c85f09ccSJohn Levon } END_FOR_EACH_PTR(p);
22*c85f09ccSJohn Levon
23*c85f09ccSJohn Levon return nbr;
24*c85f09ccSJohn Levon }
25*c85f09ccSJohn Levon
check_phi_node(struct instruction * insn)26*c85f09ccSJohn Levon static int check_phi_node(struct instruction *insn)
27*c85f09ccSJohn Levon {
28*c85f09ccSJohn Levon struct basic_block *par;
29*c85f09ccSJohn Levon pseudo_t phi;
30*c85f09ccSJohn Levon int err = 0;
31*c85f09ccSJohn Levon
32*c85f09ccSJohn Levon if (!has_users(insn->target))
33*c85f09ccSJohn Levon return err;
34*c85f09ccSJohn Levon
35*c85f09ccSJohn Levon if (bb_list_size(insn->bb->parents) != nbr_phi_operands(insn)) {
36*c85f09ccSJohn Levon sparse_error(insn->pos, "bad number of phi operands in:\n\t%s",
37*c85f09ccSJohn Levon show_instruction(insn));
38*c85f09ccSJohn Levon info(insn->pos, "parents: %d", bb_list_size(insn->bb->parents));
39*c85f09ccSJohn Levon info(insn->pos, "phisrcs: %d", nbr_phi_operands(insn));
40*c85f09ccSJohn Levon return 1;
41*c85f09ccSJohn Levon }
42*c85f09ccSJohn Levon
43*c85f09ccSJohn Levon PREPARE_PTR_LIST(insn->bb->parents, par);
44*c85f09ccSJohn Levon FOR_EACH_PTR(insn->phi_list, phi) {
45*c85f09ccSJohn Levon struct instruction *src;
46*c85f09ccSJohn Levon if (phi == VOID)
47*c85f09ccSJohn Levon continue;
48*c85f09ccSJohn Levon assert(phi->type == PSEUDO_PHI);
49*c85f09ccSJohn Levon src = phi->def;
50*c85f09ccSJohn Levon if (src->bb != par) {
51*c85f09ccSJohn Levon sparse_error(src->pos, "wrong BB for %s:", show_instruction(src));
52*c85f09ccSJohn Levon info(src->pos, "expected: %s", show_label(par));
53*c85f09ccSJohn Levon info(src->pos, " got: %s", show_label(src->bb));
54*c85f09ccSJohn Levon err++;
55*c85f09ccSJohn Levon }
56*c85f09ccSJohn Levon NEXT_PTR_LIST(par);
57*c85f09ccSJohn Levon } END_FOR_EACH_PTR(phi);
58*c85f09ccSJohn Levon FINISH_PTR_LIST(par);
59*c85f09ccSJohn Levon return err;
60*c85f09ccSJohn Levon }
61*c85f09ccSJohn Levon
check_user(struct instruction * insn,pseudo_t pseudo)62*c85f09ccSJohn Levon static int check_user(struct instruction *insn, pseudo_t pseudo)
63*c85f09ccSJohn Levon {
64*c85f09ccSJohn Levon struct instruction *def;
65*c85f09ccSJohn Levon
66*c85f09ccSJohn Levon if (!pseudo) {
67*c85f09ccSJohn Levon show_entry(insn->bb->ep);
68*c85f09ccSJohn Levon sparse_error(insn->pos, "null pseudo in %s", show_instruction(insn));
69*c85f09ccSJohn Levon return 1;
70*c85f09ccSJohn Levon }
71*c85f09ccSJohn Levon switch (pseudo->type) {
72*c85f09ccSJohn Levon case PSEUDO_PHI:
73*c85f09ccSJohn Levon case PSEUDO_REG:
74*c85f09ccSJohn Levon def = pseudo->def;
75*c85f09ccSJohn Levon if (def && def->bb)
76*c85f09ccSJohn Levon break;
77*c85f09ccSJohn Levon show_entry(insn->bb->ep);
78*c85f09ccSJohn Levon sparse_error(insn->pos, "wrong usage for %s in %s", show_pseudo(pseudo),
79*c85f09ccSJohn Levon show_instruction(insn));
80*c85f09ccSJohn Levon return 1;
81*c85f09ccSJohn Levon
82*c85f09ccSJohn Levon default:
83*c85f09ccSJohn Levon break;
84*c85f09ccSJohn Levon }
85*c85f09ccSJohn Levon return 0;
86*c85f09ccSJohn Levon }
87*c85f09ccSJohn Levon
check_branch(struct entrypoint * ep,struct instruction * insn,struct basic_block * bb)88*c85f09ccSJohn Levon static int check_branch(struct entrypoint *ep, struct instruction *insn, struct basic_block *bb)
89*c85f09ccSJohn Levon {
90*c85f09ccSJohn Levon if (bb->ep && lookup_bb(ep->bbs, bb))
91*c85f09ccSJohn Levon return 0;
92*c85f09ccSJohn Levon sparse_error(insn->pos, "branch to dead BB: %s", show_instruction(insn));
93*c85f09ccSJohn Levon return 1;
94*c85f09ccSJohn Levon }
95*c85f09ccSJohn Levon
check_switch(struct entrypoint * ep,struct instruction * insn)96*c85f09ccSJohn Levon static int check_switch(struct entrypoint *ep, struct instruction *insn)
97*c85f09ccSJohn Levon {
98*c85f09ccSJohn Levon struct multijmp *jmp;
99*c85f09ccSJohn Levon int err = 0;
100*c85f09ccSJohn Levon
101*c85f09ccSJohn Levon FOR_EACH_PTR(insn->multijmp_list, jmp) {
102*c85f09ccSJohn Levon err = check_branch(ep, insn, jmp->target);
103*c85f09ccSJohn Levon if (err)
104*c85f09ccSJohn Levon return err;
105*c85f09ccSJohn Levon } END_FOR_EACH_PTR(jmp);
106*c85f09ccSJohn Levon
107*c85f09ccSJohn Levon return err;
108*c85f09ccSJohn Levon }
109*c85f09ccSJohn Levon
check_return(struct instruction * insn)110*c85f09ccSJohn Levon static int check_return(struct instruction *insn)
111*c85f09ccSJohn Levon {
112*c85f09ccSJohn Levon struct symbol *ctype = insn->type;
113*c85f09ccSJohn Levon
114*c85f09ccSJohn Levon if (ctype && ctype->bit_size > 0 && insn->src == VOID) {
115*c85f09ccSJohn Levon sparse_error(insn->pos, "return without value");
116*c85f09ccSJohn Levon return 1;
117*c85f09ccSJohn Levon }
118*c85f09ccSJohn Levon return 0;
119*c85f09ccSJohn Levon }
120*c85f09ccSJohn Levon
validate_insn(struct entrypoint * ep,struct instruction * insn)121*c85f09ccSJohn Levon static int validate_insn(struct entrypoint *ep, struct instruction *insn)
122*c85f09ccSJohn Levon {
123*c85f09ccSJohn Levon int err = 0;
124*c85f09ccSJohn Levon
125*c85f09ccSJohn Levon switch (insn->opcode) {
126*c85f09ccSJohn Levon case OP_SEL:
127*c85f09ccSJohn Levon case OP_RANGE:
128*c85f09ccSJohn Levon err += check_user(insn, insn->src3);
129*c85f09ccSJohn Levon /* fall through */
130*c85f09ccSJohn Levon
131*c85f09ccSJohn Levon case OP_BINARY ... OP_BINCMP_END:
132*c85f09ccSJohn Levon err += check_user(insn, insn->src2);
133*c85f09ccSJohn Levon /* fall through */
134*c85f09ccSJohn Levon
135*c85f09ccSJohn Levon case OP_UNOP ... OP_UNOP_END:
136*c85f09ccSJohn Levon case OP_SLICE:
137*c85f09ccSJohn Levon case OP_SYMADDR:
138*c85f09ccSJohn Levon case OP_PHISOURCE:
139*c85f09ccSJohn Levon err += check_user(insn, insn->src1);
140*c85f09ccSJohn Levon break;
141*c85f09ccSJohn Levon
142*c85f09ccSJohn Levon case OP_CBR:
143*c85f09ccSJohn Levon err += check_branch(ep, insn, insn->bb_true);
144*c85f09ccSJohn Levon err += check_branch(ep, insn, insn->bb_false);
145*c85f09ccSJohn Levon /* fall through */
146*c85f09ccSJohn Levon case OP_COMPUTEDGOTO:
147*c85f09ccSJohn Levon err += check_user(insn, insn->cond);
148*c85f09ccSJohn Levon break;
149*c85f09ccSJohn Levon
150*c85f09ccSJohn Levon case OP_PHI:
151*c85f09ccSJohn Levon err += check_phi_node(insn);
152*c85f09ccSJohn Levon break;
153*c85f09ccSJohn Levon
154*c85f09ccSJohn Levon case OP_CALL:
155*c85f09ccSJohn Levon // FIXME: ignore for now
156*c85f09ccSJohn Levon break;
157*c85f09ccSJohn Levon
158*c85f09ccSJohn Levon case OP_STORE:
159*c85f09ccSJohn Levon err += check_user(insn, insn->target);
160*c85f09ccSJohn Levon /* fall through */
161*c85f09ccSJohn Levon
162*c85f09ccSJohn Levon case OP_LOAD:
163*c85f09ccSJohn Levon err += check_user(insn, insn->src);
164*c85f09ccSJohn Levon break;
165*c85f09ccSJohn Levon
166*c85f09ccSJohn Levon case OP_RET:
167*c85f09ccSJohn Levon err += check_return(insn);
168*c85f09ccSJohn Levon break;
169*c85f09ccSJohn Levon
170*c85f09ccSJohn Levon case OP_BR:
171*c85f09ccSJohn Levon err += check_branch(ep, insn, insn->bb_true);
172*c85f09ccSJohn Levon break;
173*c85f09ccSJohn Levon case OP_SWITCH:
174*c85f09ccSJohn Levon err += check_switch(ep, insn);
175*c85f09ccSJohn Levon break;
176*c85f09ccSJohn Levon
177*c85f09ccSJohn Levon case OP_ENTRY:
178*c85f09ccSJohn Levon case OP_SETVAL:
179*c85f09ccSJohn Levon default:
180*c85f09ccSJohn Levon break;
181*c85f09ccSJohn Levon }
182*c85f09ccSJohn Levon
183*c85f09ccSJohn Levon return err;
184*c85f09ccSJohn Levon }
185*c85f09ccSJohn Levon
ir_validate(struct entrypoint * ep)186*c85f09ccSJohn Levon int ir_validate(struct entrypoint *ep)
187*c85f09ccSJohn Levon {
188*c85f09ccSJohn Levon struct basic_block *bb;
189*c85f09ccSJohn Levon int err = 0;
190*c85f09ccSJohn Levon
191*c85f09ccSJohn Levon if (!dbg_ir || has_error)
192*c85f09ccSJohn Levon return 0;
193*c85f09ccSJohn Levon
194*c85f09ccSJohn Levon FOR_EACH_PTR(ep->bbs, bb) {
195*c85f09ccSJohn Levon struct instruction *insn;
196*c85f09ccSJohn Levon FOR_EACH_PTR(bb->insns, insn) {
197*c85f09ccSJohn Levon if (!insn->bb)
198*c85f09ccSJohn Levon continue;
199*c85f09ccSJohn Levon err += validate_insn(ep, insn);
200*c85f09ccSJohn Levon } END_FOR_EACH_PTR(insn);
201*c85f09ccSJohn Levon } END_FOR_EACH_PTR(bb);
202*c85f09ccSJohn Levon
203*c85f09ccSJohn Levon if (err)
204*c85f09ccSJohn Levon abort();
205*c85f09ccSJohn Levon return err;
206*c85f09ccSJohn Levon }
207