ir.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. // SPDX-License-Identifier: MIT
  2. #include "ir.h"
  3. #include "linearize.h"
  4. #include <stdlib.h>
  5. #include <assert.h>
  6. static int nbr_phi_operands(struct instruction *insn)
  7. {
  8. pseudo_t p;
  9. int nbr = 0;
  10. if (!insn->phi_list)
  11. return 0;
  12. FOR_EACH_PTR(insn->phi_list, p) {
  13. if (p == VOID)
  14. continue;
  15. nbr++;
  16. } END_FOR_EACH_PTR(p);
  17. return nbr;
  18. }
  19. static int check_phi_node(struct instruction *insn)
  20. {
  21. struct basic_block *par;
  22. pseudo_t phi;
  23. int err = 0;
  24. if (!has_users(insn->target))
  25. return err;
  26. if (bb_list_size(insn->bb->parents) != nbr_phi_operands(insn)) {
  27. sparse_error(insn->pos, "bad number of phi operands in:\n\t%s",
  28. show_instruction(insn));
  29. info(insn->pos, "parents: %d", bb_list_size(insn->bb->parents));
  30. info(insn->pos, "phisrcs: %d", nbr_phi_operands(insn));
  31. return 1;
  32. }
  33. PREPARE_PTR_LIST(insn->bb->parents, par);
  34. FOR_EACH_PTR(insn->phi_list, phi) {
  35. struct instruction *src;
  36. if (phi == VOID)
  37. continue;
  38. assert(phi->type == PSEUDO_PHI);
  39. src = phi->def;
  40. if (src->bb != par) {
  41. sparse_error(src->pos, "wrong BB for %s:", show_instruction(src));
  42. info(src->pos, "expected: %s", show_label(par));
  43. info(src->pos, " got: %s", show_label(src->bb));
  44. err++;
  45. }
  46. NEXT_PTR_LIST(par);
  47. } END_FOR_EACH_PTR(phi);
  48. FINISH_PTR_LIST(par);
  49. return err;
  50. }
  51. static int check_user(struct instruction *insn, pseudo_t pseudo)
  52. {
  53. struct instruction *def;
  54. if (!pseudo) {
  55. show_entry(insn->bb->ep);
  56. sparse_error(insn->pos, "null pseudo in %s", show_instruction(insn));
  57. return 1;
  58. }
  59. switch (pseudo->type) {
  60. case PSEUDO_PHI:
  61. case PSEUDO_REG:
  62. def = pseudo->def;
  63. if (def && def->bb)
  64. break;
  65. show_entry(insn->bb->ep);
  66. sparse_error(insn->pos, "wrong usage for %s in %s", show_pseudo(pseudo),
  67. show_instruction(insn));
  68. return 1;
  69. default:
  70. break;
  71. }
  72. return 0;
  73. }
  74. static int check_branch(struct entrypoint *ep, struct instruction *insn, struct basic_block *bb)
  75. {
  76. if (bb->ep && lookup_bb(ep->bbs, bb))
  77. return 0;
  78. sparse_error(insn->pos, "branch to dead BB: %s", show_instruction(insn));
  79. return 1;
  80. }
  81. static int check_switch(struct entrypoint *ep, struct instruction *insn)
  82. {
  83. struct multijmp *jmp;
  84. int err = 0;
  85. FOR_EACH_PTR(insn->multijmp_list, jmp) {
  86. err = check_branch(ep, insn, jmp->target);
  87. if (err)
  88. return err;
  89. } END_FOR_EACH_PTR(jmp);
  90. return err;
  91. }
  92. static int check_return(struct instruction *insn)
  93. {
  94. struct symbol *ctype = insn->type;
  95. if (ctype && ctype->bit_size > 0 && insn->src == VOID) {
  96. sparse_error(insn->pos, "return without value");
  97. return 1;
  98. }
  99. return 0;
  100. }
  101. static int validate_insn(struct entrypoint *ep, struct instruction *insn)
  102. {
  103. int err = 0;
  104. switch (insn->opcode) {
  105. case OP_SEL:
  106. case OP_RANGE:
  107. err += check_user(insn, insn->src3);
  108. /* fall through */
  109. case OP_BINARY ... OP_BINCMP_END:
  110. err += check_user(insn, insn->src2);
  111. /* fall through */
  112. case OP_UNOP ... OP_UNOP_END:
  113. case OP_SLICE:
  114. case OP_SYMADDR:
  115. case OP_PHISOURCE:
  116. err += check_user(insn, insn->src1);
  117. break;
  118. case OP_CBR:
  119. err += check_branch(ep, insn, insn->bb_true);
  120. err += check_branch(ep, insn, insn->bb_false);
  121. /* fall through */
  122. case OP_COMPUTEDGOTO:
  123. err += check_user(insn, insn->cond);
  124. break;
  125. case OP_PHI:
  126. err += check_phi_node(insn);
  127. break;
  128. case OP_CALL:
  129. // FIXME: ignore for now
  130. break;
  131. case OP_STORE:
  132. err += check_user(insn, insn->target);
  133. /* fall through */
  134. case OP_LOAD:
  135. err += check_user(insn, insn->src);
  136. break;
  137. case OP_RET:
  138. err += check_return(insn);
  139. break;
  140. case OP_BR:
  141. err += check_branch(ep, insn, insn->bb_true);
  142. break;
  143. case OP_SWITCH:
  144. err += check_switch(ep, insn);
  145. break;
  146. case OP_ENTRY:
  147. case OP_SETVAL:
  148. default:
  149. break;
  150. }
  151. return err;
  152. }
  153. int ir_validate(struct entrypoint *ep)
  154. {
  155. struct basic_block *bb;
  156. int err = 0;
  157. if (!dbg_ir || has_error)
  158. return 0;
  159. FOR_EACH_PTR(ep->bbs, bb) {
  160. struct instruction *insn;
  161. FOR_EACH_PTR(bb->insns, insn) {
  162. if (!insn->bb)
  163. continue;
  164. err += validate_insn(ep, insn);
  165. } END_FOR_EACH_PTR(insn);
  166. } END_FOR_EACH_PTR(bb);
  167. if (err)
  168. abort();
  169. return err;
  170. }