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