1 // SPDX-License-Identifier: MIT
9 static int nbr_phi_operands(struct instruction
*insn
)
17 FOR_EACH_PTR(insn
->phi_list
, p
) {
21 } END_FOR_EACH_PTR(p
);
26 static int check_phi_node(struct instruction
*insn
)
28 struct basic_block
*par
;
32 if (!has_users(insn
->target
))
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
));
43 PREPARE_PTR_LIST(insn
->bb
->parents
, par
);
44 FOR_EACH_PTR(insn
->phi_list
, phi
) {
45 struct instruction
*src
;
48 assert(phi
->type
== PSEUDO_PHI
);
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
));
57 } END_FOR_EACH_PTR(phi
);
62 static int check_user(struct instruction
*insn
, pseudo_t pseudo
)
64 struct instruction
*def
;
67 show_entry(insn
->bb
->ep
);
68 sparse_error(insn
->pos
, "null pseudo in %s", show_instruction(insn
));
71 switch (pseudo
->type
) {
77 show_entry(insn
->bb
->ep
);
78 sparse_error(insn
->pos
, "wrong usage for %s in %s", show_pseudo(pseudo
),
79 show_instruction(insn
));
88 static int check_branch(struct entrypoint
*ep
, struct instruction
*insn
, struct basic_block
*bb
)
90 if (bb
->ep
&& lookup_bb(ep
->bbs
, bb
))
92 sparse_error(insn
->pos
, "branch to dead BB: %s", show_instruction(insn
));
96 static int check_switch(struct entrypoint
*ep
, struct instruction
*insn
)
101 FOR_EACH_PTR(insn
->multijmp_list
, jmp
) {
102 err
= check_branch(ep
, insn
, jmp
->target
);
105 } END_FOR_EACH_PTR(jmp
);
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");
121 static int validate_insn(struct entrypoint
*ep
, struct instruction
*insn
)
125 switch (insn
->opcode
) {
128 err
+= check_user(insn
, insn
->src3
);
131 case OP_BINARY
... OP_BINCMP_END
:
132 err
+= check_user(insn
, insn
->src2
);
135 case OP_UNOP
... OP_UNOP_END
:
139 err
+= check_user(insn
, insn
->src1
);
143 err
+= check_branch(ep
, insn
, insn
->bb_true
);
144 err
+= check_branch(ep
, insn
, insn
->bb_false
);
146 case OP_COMPUTEDGOTO
:
147 err
+= check_user(insn
, insn
->cond
);
151 err
+= check_phi_node(insn
);
155 // FIXME: ignore for now
159 err
+= check_user(insn
, insn
->target
);
163 err
+= check_user(insn
, insn
->src
);
167 err
+= check_return(insn
);
171 err
+= check_branch(ep
, insn
, insn
->bb_true
);
174 err
+= check_switch(ep
, insn
);
186 int ir_validate(struct entrypoint
*ep
)
188 struct basic_block
*bb
;
191 if (!dbg_ir
|| has_error
)
194 FOR_EACH_PTR(ep
->bbs
, bb
) {
195 struct instruction
*insn
;
196 FOR_EACH_PTR(bb
->insns
, insn
) {
199 err
+= validate_insn(ep
, insn
);
200 } END_FOR_EACH_PTR(insn
);
201 } END_FOR_EACH_PTR(bb
);