1 // SPDX-License-Identifier: MIT 2 3 #include "ir.h" 4 #include "linearize.h" 5 #include <stdlib.h> 6 #include <assert.h> 7 8 9 static int nbr_phi_operands(struct instruction *insn) 10 { 11 pseudo_t p; 12 int nbr = 0; 13 14 if (!insn->phi_list) 15 return 0; 16 17 FOR_EACH_PTR(insn->phi_list, p) { 18 if (p == VOID) 19 continue; 20 nbr++; 21 } END_FOR_EACH_PTR(p); 22 23 return nbr; 24 } 25 26 static int check_phi_node(struct instruction *insn) 27 { 28 struct basic_block *par; 29 pseudo_t phi; 30 int err = 0; 31 32 if (!has_users(insn->target)) 33 return err; 34 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; 41 } 42 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++; 55 } 56 NEXT_PTR_LIST(par); 57 } END_FOR_EACH_PTR(phi); 58 FINISH_PTR_LIST(par); 59 return err; 60 } 61 62 static int check_user(struct instruction *insn, pseudo_t pseudo) 63 { 64 struct instruction *def; 65 66 if (!pseudo) { 67 show_entry(insn->bb->ep); 68 sparse_error(insn->pos, "null pseudo in %s", show_instruction(insn)); 69 return 1; 70 } 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; 81 82 default: 83 break; 84 } 85 return 0; 86 } 87 88 static int check_branch(struct entrypoint *ep, struct instruction *insn, struct basic_block *bb) 89 { 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; 94 } 95 96 static int check_switch(struct entrypoint *ep, struct instruction *insn) 97 { 98 struct multijmp *jmp; 99 int err = 0; 100 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); 106 107 return err; 108 } 109 110 static int check_return(struct instruction *insn) 111 { 112 struct symbol *ctype = insn->type; 113 114 if (ctype && ctype->bit_size > 0 && insn->src == VOID) { 115 sparse_error(insn->pos, "return without value"); 116 return 1; 117 } 118 return 0; 119 } 120 121 static int validate_insn(struct entrypoint *ep, struct instruction *insn) 122 { 123 int err = 0; 124 125 switch (insn->opcode) { 126 case OP_SEL: 127 case OP_RANGE: 128 err += check_user(insn, insn->src3); 129 /* fall through */ 130 131 case OP_BINARY ... OP_BINCMP_END: 132 err += check_user(insn, insn->src2); 133 /* fall through */ 134 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; 141 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; 149 150 case OP_PHI: 151 err += check_phi_node(insn); 152 break; 153 154 case OP_CALL: 155 // FIXME: ignore for now 156 break; 157 158 case OP_STORE: 159 err += check_user(insn, insn->target); 160 /* fall through */ 161 162 case OP_LOAD: 163 err += check_user(insn, insn->src); 164 break; 165 166 case OP_RET: 167 err += check_return(insn); 168 break; 169 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; 176 177 case OP_ENTRY: 178 case OP_SETVAL: 179 default: 180 break; 181 } 182 183 return err; 184 } 185 186 int ir_validate(struct entrypoint *ep) 187 { 188 struct basic_block *bb; 189 int err = 0; 190 191 if (!dbg_ir || has_error) 192 return 0; 193 194 FOR_EACH_PTR(ep->bbs, bb) { 195 struct instruction *insn; 196 FOR_EACH_PTR(bb->insns, insn) { 197 if (!insn->bb) 198 continue; 199 err += validate_insn(ep, insn); 200 } END_FOR_EACH_PTR(insn); 201 } END_FOR_EACH_PTR(bb); 202 203 if (err) 204 abort(); 205 return err; 206 } 207