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