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