xref: /illumos-gate/usr/src/tools/smatch/src/ir.c (revision c85f09cc)
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