123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- // SPDX-License-Identifier: MIT
- #include "ir.h"
- #include "linearize.h"
- #include <stdlib.h>
- #include <assert.h>
- static int nbr_phi_operands(struct instruction *insn)
- {
- pseudo_t p;
- int nbr = 0;
- if (!insn->phi_list)
- return 0;
- FOR_EACH_PTR(insn->phi_list, p) {
- if (p == VOID)
- continue;
- nbr++;
- } END_FOR_EACH_PTR(p);
- return nbr;
- }
- static int check_phi_node(struct instruction *insn)
- {
- struct basic_block *par;
- pseudo_t phi;
- int err = 0;
- if (!has_users(insn->target))
- return err;
- if (bb_list_size(insn->bb->parents) != nbr_phi_operands(insn)) {
- sparse_error(insn->pos, "bad number of phi operands in:\n\t%s",
- show_instruction(insn));
- info(insn->pos, "parents: %d", bb_list_size(insn->bb->parents));
- info(insn->pos, "phisrcs: %d", nbr_phi_operands(insn));
- return 1;
- }
- PREPARE_PTR_LIST(insn->bb->parents, par);
- FOR_EACH_PTR(insn->phi_list, phi) {
- struct instruction *src;
- if (phi == VOID)
- continue;
- assert(phi->type == PSEUDO_PHI);
- src = phi->def;
- if (src->bb != par) {
- sparse_error(src->pos, "wrong BB for %s:", show_instruction(src));
- info(src->pos, "expected: %s", show_label(par));
- info(src->pos, " got: %s", show_label(src->bb));
- err++;
- }
- NEXT_PTR_LIST(par);
- } END_FOR_EACH_PTR(phi);
- FINISH_PTR_LIST(par);
- return err;
- }
- static int check_user(struct instruction *insn, pseudo_t pseudo)
- {
- struct instruction *def;
- if (!pseudo) {
- show_entry(insn->bb->ep);
- sparse_error(insn->pos, "null pseudo in %s", show_instruction(insn));
- return 1;
- }
- switch (pseudo->type) {
- case PSEUDO_PHI:
- case PSEUDO_REG:
- def = pseudo->def;
- if (def && def->bb)
- break;
- show_entry(insn->bb->ep);
- sparse_error(insn->pos, "wrong usage for %s in %s", show_pseudo(pseudo),
- show_instruction(insn));
- return 1;
- default:
- break;
- }
- return 0;
- }
- static int check_branch(struct entrypoint *ep, struct instruction *insn, struct basic_block *bb)
- {
- if (bb->ep && lookup_bb(ep->bbs, bb))
- return 0;
- sparse_error(insn->pos, "branch to dead BB: %s", show_instruction(insn));
- return 1;
- }
- static int check_switch(struct entrypoint *ep, struct instruction *insn)
- {
- struct multijmp *jmp;
- int err = 0;
- FOR_EACH_PTR(insn->multijmp_list, jmp) {
- err = check_branch(ep, insn, jmp->target);
- if (err)
- return err;
- } END_FOR_EACH_PTR(jmp);
- return err;
- }
- static int check_return(struct instruction *insn)
- {
- struct symbol *ctype = insn->type;
- if (ctype && ctype->bit_size > 0 && insn->src == VOID) {
- sparse_error(insn->pos, "return without value");
- return 1;
- }
- return 0;
- }
- static int validate_insn(struct entrypoint *ep, struct instruction *insn)
- {
- int err = 0;
- switch (insn->opcode) {
- case OP_SEL:
- case OP_RANGE:
- err += check_user(insn, insn->src3);
- /* fall through */
- case OP_BINARY ... OP_BINCMP_END:
- err += check_user(insn, insn->src2);
- /* fall through */
- case OP_UNOP ... OP_UNOP_END:
- case OP_SLICE:
- case OP_SYMADDR:
- case OP_PHISOURCE:
- err += check_user(insn, insn->src1);
- break;
- case OP_CBR:
- err += check_branch(ep, insn, insn->bb_true);
- err += check_branch(ep, insn, insn->bb_false);
- /* fall through */
- case OP_COMPUTEDGOTO:
- err += check_user(insn, insn->cond);
- break;
- case OP_PHI:
- err += check_phi_node(insn);
- break;
- case OP_CALL:
- // FIXME: ignore for now
- break;
- case OP_STORE:
- err += check_user(insn, insn->target);
- /* fall through */
- case OP_LOAD:
- err += check_user(insn, insn->src);
- break;
- case OP_RET:
- err += check_return(insn);
- break;
- case OP_BR:
- err += check_branch(ep, insn, insn->bb_true);
- break;
- case OP_SWITCH:
- err += check_switch(ep, insn);
- break;
- case OP_ENTRY:
- case OP_SETVAL:
- default:
- break;
- }
- return err;
- }
- int ir_validate(struct entrypoint *ep)
- {
- struct basic_block *bb;
- int err = 0;
- if (!dbg_ir || has_error)
- return 0;
- FOR_EACH_PTR(ep->bbs, bb) {
- struct instruction *insn;
- FOR_EACH_PTR(bb->insns, insn) {
- if (!insn->bb)
- continue;
- err += validate_insn(ep, insn);
- } END_FOR_EACH_PTR(insn);
- } END_FOR_EACH_PTR(bb);
- if (err)
- abort();
- return err;
- }
|