1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * Example of how to write a compiler with sparse
3f08c3bdfSopenharmony_ci */
4f08c3bdfSopenharmony_ci#include <stdio.h>
5f08c3bdfSopenharmony_ci#include <stdlib.h>
6f08c3bdfSopenharmony_ci#include <stdarg.h>
7f08c3bdfSopenharmony_ci#include <string.h>
8f08c3bdfSopenharmony_ci#include <assert.h>
9f08c3bdfSopenharmony_ci
10f08c3bdfSopenharmony_ci#include "symbol.h"
11f08c3bdfSopenharmony_ci#include "expression.h"
12f08c3bdfSopenharmony_ci#include "linearize.h"
13f08c3bdfSopenharmony_ci#include "flow.h"
14f08c3bdfSopenharmony_ci#include "storage.h"
15f08c3bdfSopenharmony_ci#include "target.h"
16f08c3bdfSopenharmony_ci
17f08c3bdfSopenharmony_cistatic const char *opcodes[] = {
18f08c3bdfSopenharmony_ci	[OP_BADOP] = "bad_op",
19f08c3bdfSopenharmony_ci
20f08c3bdfSopenharmony_ci	/* Fn entrypoint */
21f08c3bdfSopenharmony_ci	[OP_ENTRY] = "<entry-point>",
22f08c3bdfSopenharmony_ci
23f08c3bdfSopenharmony_ci	/* Terminator */
24f08c3bdfSopenharmony_ci	[OP_RET] = "ret",
25f08c3bdfSopenharmony_ci	[OP_BR] = "br",
26f08c3bdfSopenharmony_ci	[OP_CBR] = "cbr",
27f08c3bdfSopenharmony_ci	[OP_SWITCH] = "switch",
28f08c3bdfSopenharmony_ci	[OP_COMPUTEDGOTO] = "jmp *",
29f08c3bdfSopenharmony_ci
30f08c3bdfSopenharmony_ci	/* Binary */
31f08c3bdfSopenharmony_ci	[OP_ADD] = "add",
32f08c3bdfSopenharmony_ci	[OP_SUB] = "sub",
33f08c3bdfSopenharmony_ci	[OP_MUL] = "mul",
34f08c3bdfSopenharmony_ci	[OP_DIVU] = "divu",
35f08c3bdfSopenharmony_ci	[OP_DIVS] = "divs",
36f08c3bdfSopenharmony_ci	[OP_MODU] = "modu",
37f08c3bdfSopenharmony_ci	[OP_MODS] = "mods",
38f08c3bdfSopenharmony_ci	[OP_SHL] = "shl",
39f08c3bdfSopenharmony_ci	[OP_LSR] = "lsr",
40f08c3bdfSopenharmony_ci	[OP_ASR] = "asr",
41f08c3bdfSopenharmony_ci
42f08c3bdfSopenharmony_ci	/* Logical */
43f08c3bdfSopenharmony_ci	[OP_AND] = "and",
44f08c3bdfSopenharmony_ci	[OP_OR] = "or",
45f08c3bdfSopenharmony_ci	[OP_XOR] = "xor",
46f08c3bdfSopenharmony_ci
47f08c3bdfSopenharmony_ci	/* Binary comparison */
48f08c3bdfSopenharmony_ci	[OP_SET_EQ] = "seteq",
49f08c3bdfSopenharmony_ci	[OP_SET_NE] = "setne",
50f08c3bdfSopenharmony_ci	[OP_SET_LE] = "setle",
51f08c3bdfSopenharmony_ci	[OP_SET_GE] = "setge",
52f08c3bdfSopenharmony_ci	[OP_SET_LT] = "setlt",
53f08c3bdfSopenharmony_ci	[OP_SET_GT] = "setgt",
54f08c3bdfSopenharmony_ci	[OP_SET_B] = "setb",
55f08c3bdfSopenharmony_ci	[OP_SET_A] = "seta",
56f08c3bdfSopenharmony_ci	[OP_SET_BE] = "setbe",
57f08c3bdfSopenharmony_ci	[OP_SET_AE] = "setae",
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_ci	/* Uni */
60f08c3bdfSopenharmony_ci	[OP_NOT] = "not",
61f08c3bdfSopenharmony_ci	[OP_NEG] = "neg",
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_ci	/* Special three-input */
64f08c3bdfSopenharmony_ci	[OP_SEL] = "select",
65f08c3bdfSopenharmony_ci
66f08c3bdfSopenharmony_ci	/* Memory */
67f08c3bdfSopenharmony_ci	[OP_LOAD] = "load",
68f08c3bdfSopenharmony_ci	[OP_STORE] = "store",
69f08c3bdfSopenharmony_ci	[OP_LABEL] = "label",
70f08c3bdfSopenharmony_ci	[OP_SETVAL] = "set",
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_ci	/* Other */
73f08c3bdfSopenharmony_ci	[OP_PHI] = "phi",
74f08c3bdfSopenharmony_ci	[OP_PHISOURCE] = "phisrc",
75f08c3bdfSopenharmony_ci	[OP_COPY] = "copy",
76f08c3bdfSopenharmony_ci	[OP_SEXT] = "sext",
77f08c3bdfSopenharmony_ci	[OP_ZEXT] = "zext",
78f08c3bdfSopenharmony_ci	[OP_TRUNC] = "trunc",
79f08c3bdfSopenharmony_ci	[OP_FCVTU] = "fcvtu",
80f08c3bdfSopenharmony_ci	[OP_FCVTS] = "fcvts",
81f08c3bdfSopenharmony_ci	[OP_UCVTF] = "ucvtf",
82f08c3bdfSopenharmony_ci	[OP_SCVTF] = "scvtf",
83f08c3bdfSopenharmony_ci	[OP_FCVTF] = "fcvtf",
84f08c3bdfSopenharmony_ci	[OP_UTPTR] = "utptr",
85f08c3bdfSopenharmony_ci	[OP_PTRTU] = "utptr",
86f08c3bdfSopenharmony_ci	[OP_PTRCAST] = "ptrcast",
87f08c3bdfSopenharmony_ci	[OP_CALL] = "call",
88f08c3bdfSopenharmony_ci	[OP_SLICE] = "slice",
89f08c3bdfSopenharmony_ci	[OP_NOP] = "nop",
90f08c3bdfSopenharmony_ci	[OP_DEATHNOTE] = "dead",
91f08c3bdfSopenharmony_ci	[OP_ASM] = "asm",
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_ci	/* Sparse tagging (line numbers, context, whatever) */
94f08c3bdfSopenharmony_ci	[OP_CONTEXT] = "context",
95f08c3bdfSopenharmony_ci};
96f08c3bdfSopenharmony_ci
97f08c3bdfSopenharmony_cistatic int last_reg, stack_offset;
98f08c3bdfSopenharmony_ci
99f08c3bdfSopenharmony_cistruct hardreg {
100f08c3bdfSopenharmony_ci	const char *name;
101f08c3bdfSopenharmony_ci	struct pseudo_list *contains;
102f08c3bdfSopenharmony_ci	unsigned busy:16,
103f08c3bdfSopenharmony_ci		 dead:8,
104f08c3bdfSopenharmony_ci		 used:1;
105f08c3bdfSopenharmony_ci};
106f08c3bdfSopenharmony_ci
107f08c3bdfSopenharmony_ci#define TAG_DEAD 1
108f08c3bdfSopenharmony_ci#define TAG_DIRTY 2
109f08c3bdfSopenharmony_ci
110f08c3bdfSopenharmony_ci/* Our "switch" generation is very very stupid. */
111f08c3bdfSopenharmony_ci#define SWITCH_REG (1)
112f08c3bdfSopenharmony_ci
113f08c3bdfSopenharmony_cistatic void output_bb(struct basic_block *bb, unsigned long generation);
114f08c3bdfSopenharmony_ci
115f08c3bdfSopenharmony_ci/*
116f08c3bdfSopenharmony_ci * We only know about the caller-clobbered registers
117f08c3bdfSopenharmony_ci * right now.
118f08c3bdfSopenharmony_ci */
119f08c3bdfSopenharmony_cistatic struct hardreg hardregs[] = {
120f08c3bdfSopenharmony_ci	{ .name = "%eax" },
121f08c3bdfSopenharmony_ci	{ .name = "%edx" },
122f08c3bdfSopenharmony_ci	{ .name = "%ecx" },
123f08c3bdfSopenharmony_ci	{ .name = "%ebx" },
124f08c3bdfSopenharmony_ci	{ .name = "%esi" },
125f08c3bdfSopenharmony_ci	{ .name = "%edi" },
126f08c3bdfSopenharmony_ci
127f08c3bdfSopenharmony_ci	{ .name = "%ebp" },
128f08c3bdfSopenharmony_ci	{ .name = "%esp" },
129f08c3bdfSopenharmony_ci};
130f08c3bdfSopenharmony_ci#define REGNO 6
131f08c3bdfSopenharmony_ci#define REG_EBP 6
132f08c3bdfSopenharmony_ci#define REG_ESP 7
133f08c3bdfSopenharmony_ci
134f08c3bdfSopenharmony_cistruct bb_state {
135f08c3bdfSopenharmony_ci	struct position pos;
136f08c3bdfSopenharmony_ci	struct storage_hash_list *inputs;
137f08c3bdfSopenharmony_ci	struct storage_hash_list *outputs;
138f08c3bdfSopenharmony_ci	struct storage_hash_list *internal;
139f08c3bdfSopenharmony_ci
140f08c3bdfSopenharmony_ci	/* CC cache.. */
141f08c3bdfSopenharmony_ci	int cc_opcode, cc_dead;
142f08c3bdfSopenharmony_ci	pseudo_t cc_target;
143f08c3bdfSopenharmony_ci};
144f08c3bdfSopenharmony_ci
145f08c3bdfSopenharmony_cienum optype {
146f08c3bdfSopenharmony_ci	OP_UNDEF,
147f08c3bdfSopenharmony_ci	OP_REG,
148f08c3bdfSopenharmony_ci	OP_VAL,
149f08c3bdfSopenharmony_ci	OP_MEM,
150f08c3bdfSopenharmony_ci	OP_ADDR,
151f08c3bdfSopenharmony_ci};
152f08c3bdfSopenharmony_ci
153f08c3bdfSopenharmony_cistruct operand {
154f08c3bdfSopenharmony_ci	enum optype type;
155f08c3bdfSopenharmony_ci	int size;
156f08c3bdfSopenharmony_ci	union {
157f08c3bdfSopenharmony_ci		struct hardreg *reg;
158f08c3bdfSopenharmony_ci		long long value;
159f08c3bdfSopenharmony_ci		struct /* OP_MEM and OP_ADDR */ {
160f08c3bdfSopenharmony_ci			unsigned int offset;
161f08c3bdfSopenharmony_ci			unsigned int scale;
162f08c3bdfSopenharmony_ci			struct symbol *sym;
163f08c3bdfSopenharmony_ci			struct hardreg *base;
164f08c3bdfSopenharmony_ci			struct hardreg *index;
165f08c3bdfSopenharmony_ci		};
166f08c3bdfSopenharmony_ci	};
167f08c3bdfSopenharmony_ci};
168f08c3bdfSopenharmony_ci
169f08c3bdfSopenharmony_cistatic const char *show_op(struct bb_state *state, struct operand *op)
170f08c3bdfSopenharmony_ci{
171f08c3bdfSopenharmony_ci	static char buf[256][4];
172f08c3bdfSopenharmony_ci	static int bufnr;
173f08c3bdfSopenharmony_ci	char *p, *ret;
174f08c3bdfSopenharmony_ci	int nr;
175f08c3bdfSopenharmony_ci
176f08c3bdfSopenharmony_ci	nr = (bufnr + 1) & 3;
177f08c3bdfSopenharmony_ci	bufnr = nr;
178f08c3bdfSopenharmony_ci	ret = p = buf[nr];
179f08c3bdfSopenharmony_ci
180f08c3bdfSopenharmony_ci	switch (op->type) {
181f08c3bdfSopenharmony_ci	case OP_UNDEF:
182f08c3bdfSopenharmony_ci		return "undef";
183f08c3bdfSopenharmony_ci	case OP_REG:
184f08c3bdfSopenharmony_ci		return op->reg->name;
185f08c3bdfSopenharmony_ci	case OP_VAL:
186f08c3bdfSopenharmony_ci		sprintf(p, "$%lld", op->value);
187f08c3bdfSopenharmony_ci		break;
188f08c3bdfSopenharmony_ci	case OP_MEM:
189f08c3bdfSopenharmony_ci	case OP_ADDR:
190f08c3bdfSopenharmony_ci		if (op->offset)
191f08c3bdfSopenharmony_ci			p += sprintf(p, "%d", op->offset);
192f08c3bdfSopenharmony_ci		if (op->sym)
193f08c3bdfSopenharmony_ci			p += sprintf(p, "%s%s",
194f08c3bdfSopenharmony_ci				op->offset ? "+" : "",
195f08c3bdfSopenharmony_ci				show_ident(op->sym->ident));
196f08c3bdfSopenharmony_ci		if (op->base || op->index) {
197f08c3bdfSopenharmony_ci			p += sprintf(p, "(%s%s%s",
198f08c3bdfSopenharmony_ci				op->base ? op->base->name : "",
199f08c3bdfSopenharmony_ci				(op->base && op->index) ? "," : "",
200f08c3bdfSopenharmony_ci				op->index ? op->index->name : "");
201f08c3bdfSopenharmony_ci			if (op->scale > 1)
202f08c3bdfSopenharmony_ci				p += sprintf(p, ",%d", op->scale);
203f08c3bdfSopenharmony_ci			*p++ = ')';
204f08c3bdfSopenharmony_ci			*p = '\0';
205f08c3bdfSopenharmony_ci		}
206f08c3bdfSopenharmony_ci		break;
207f08c3bdfSopenharmony_ci	}
208f08c3bdfSopenharmony_ci	return ret;
209f08c3bdfSopenharmony_ci}
210f08c3bdfSopenharmony_ci
211f08c3bdfSopenharmony_cistatic struct storage_hash *find_storage_hash(pseudo_t pseudo, struct storage_hash_list *list)
212f08c3bdfSopenharmony_ci{
213f08c3bdfSopenharmony_ci	struct storage_hash *entry;
214f08c3bdfSopenharmony_ci	FOR_EACH_PTR(list, entry) {
215f08c3bdfSopenharmony_ci		if (entry->pseudo == pseudo)
216f08c3bdfSopenharmony_ci			return entry;
217f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(entry);
218f08c3bdfSopenharmony_ci	return NULL;
219f08c3bdfSopenharmony_ci}
220f08c3bdfSopenharmony_ci
221f08c3bdfSopenharmony_cistatic struct storage_hash *find_or_create_hash(pseudo_t pseudo, struct storage_hash_list **listp)
222f08c3bdfSopenharmony_ci{
223f08c3bdfSopenharmony_ci	struct storage_hash *entry;
224f08c3bdfSopenharmony_ci
225f08c3bdfSopenharmony_ci	entry = find_storage_hash(pseudo, *listp);
226f08c3bdfSopenharmony_ci	if (!entry) {
227f08c3bdfSopenharmony_ci		entry = alloc_storage_hash(alloc_storage());
228f08c3bdfSopenharmony_ci		entry->pseudo = pseudo;
229f08c3bdfSopenharmony_ci		add_ptr_list(listp, entry);
230f08c3bdfSopenharmony_ci	}
231f08c3bdfSopenharmony_ci	return entry;
232f08c3bdfSopenharmony_ci}
233f08c3bdfSopenharmony_ci
234f08c3bdfSopenharmony_ci/* Eventually we should just build it up in memory */
235f08c3bdfSopenharmony_cistatic void FORMAT_ATTR(2) output_line(struct bb_state *state, const char *fmt, ...)
236f08c3bdfSopenharmony_ci{
237f08c3bdfSopenharmony_ci	va_list args;
238f08c3bdfSopenharmony_ci
239f08c3bdfSopenharmony_ci	va_start(args, fmt);
240f08c3bdfSopenharmony_ci	vprintf(fmt, args);
241f08c3bdfSopenharmony_ci	va_end(args);
242f08c3bdfSopenharmony_ci}
243f08c3bdfSopenharmony_ci
244f08c3bdfSopenharmony_cistatic void FORMAT_ATTR(2) output_label(struct bb_state *state, const char *fmt, ...)
245f08c3bdfSopenharmony_ci{
246f08c3bdfSopenharmony_ci	static char buffer[512];
247f08c3bdfSopenharmony_ci	va_list args;
248f08c3bdfSopenharmony_ci
249f08c3bdfSopenharmony_ci	va_start(args, fmt);
250f08c3bdfSopenharmony_ci	vsnprintf(buffer, sizeof(buffer), fmt, args);
251f08c3bdfSopenharmony_ci	va_end(args);
252f08c3bdfSopenharmony_ci
253f08c3bdfSopenharmony_ci	output_line(state, "%s:\n", buffer);
254f08c3bdfSopenharmony_ci}
255f08c3bdfSopenharmony_ci
256f08c3bdfSopenharmony_cistatic void FORMAT_ATTR(2) output_insn(struct bb_state *state, const char *fmt, ...)
257f08c3bdfSopenharmony_ci{
258f08c3bdfSopenharmony_ci	static char buffer[512];
259f08c3bdfSopenharmony_ci	va_list args;
260f08c3bdfSopenharmony_ci
261f08c3bdfSopenharmony_ci	va_start(args, fmt);
262f08c3bdfSopenharmony_ci	vsnprintf(buffer, sizeof(buffer), fmt, args);
263f08c3bdfSopenharmony_ci	va_end(args);
264f08c3bdfSopenharmony_ci
265f08c3bdfSopenharmony_ci	output_line(state, "\t%s\n", buffer);
266f08c3bdfSopenharmony_ci}
267f08c3bdfSopenharmony_ci
268f08c3bdfSopenharmony_ci#define output_insn(state, fmt, arg...) \
269f08c3bdfSopenharmony_ci	output_insn(state, fmt "\t\t# %s" , ## arg , __FUNCTION__)
270f08c3bdfSopenharmony_ci
271f08c3bdfSopenharmony_cistatic void FORMAT_ATTR(2) output_comment(struct bb_state *state, const char *fmt, ...)
272f08c3bdfSopenharmony_ci{
273f08c3bdfSopenharmony_ci	static char buffer[512];
274f08c3bdfSopenharmony_ci	va_list args;
275f08c3bdfSopenharmony_ci
276f08c3bdfSopenharmony_ci	if (!verbose)
277f08c3bdfSopenharmony_ci		return;
278f08c3bdfSopenharmony_ci	va_start(args, fmt);
279f08c3bdfSopenharmony_ci	vsnprintf(buffer, sizeof(buffer), fmt, args);
280f08c3bdfSopenharmony_ci	va_end(args);
281f08c3bdfSopenharmony_ci
282f08c3bdfSopenharmony_ci	output_line(state, "\t# %s\n", buffer);
283f08c3bdfSopenharmony_ci}
284f08c3bdfSopenharmony_ci
285f08c3bdfSopenharmony_cistatic const char *show_memop(struct storage *storage)
286f08c3bdfSopenharmony_ci{
287f08c3bdfSopenharmony_ci	static char buffer[1000];
288f08c3bdfSopenharmony_ci
289f08c3bdfSopenharmony_ci	if (!storage)
290f08c3bdfSopenharmony_ci		return "undef";
291f08c3bdfSopenharmony_ci	switch (storage->type) {
292f08c3bdfSopenharmony_ci	case REG_FRAME:
293f08c3bdfSopenharmony_ci		sprintf(buffer, "%d(FP)", storage->offset);
294f08c3bdfSopenharmony_ci		break;
295f08c3bdfSopenharmony_ci	case REG_STACK:
296f08c3bdfSopenharmony_ci		sprintf(buffer, "%d(SP)", storage->offset);
297f08c3bdfSopenharmony_ci		break;
298f08c3bdfSopenharmony_ci	case REG_REG:
299f08c3bdfSopenharmony_ci		return hardregs[storage->regno].name;
300f08c3bdfSopenharmony_ci	default:
301f08c3bdfSopenharmony_ci		return show_storage(storage);
302f08c3bdfSopenharmony_ci	}
303f08c3bdfSopenharmony_ci	return buffer;
304f08c3bdfSopenharmony_ci}
305f08c3bdfSopenharmony_ci
306f08c3bdfSopenharmony_cistatic int alloc_stack_offset(int size)
307f08c3bdfSopenharmony_ci{
308f08c3bdfSopenharmony_ci	int ret = stack_offset;
309f08c3bdfSopenharmony_ci	stack_offset = ret + size;
310f08c3bdfSopenharmony_ci	return ret;
311f08c3bdfSopenharmony_ci}
312f08c3bdfSopenharmony_ci
313f08c3bdfSopenharmony_cistatic void alloc_stack(struct bb_state *state, struct storage *storage)
314f08c3bdfSopenharmony_ci{
315f08c3bdfSopenharmony_ci	storage->type = REG_STACK;
316f08c3bdfSopenharmony_ci	storage->offset = alloc_stack_offset(4);
317f08c3bdfSopenharmony_ci}
318f08c3bdfSopenharmony_ci
319f08c3bdfSopenharmony_ci/*
320f08c3bdfSopenharmony_ci * Can we re-generate the pseudo, so that we don't need to
321f08c3bdfSopenharmony_ci * flush it to memory? We can regenerate:
322f08c3bdfSopenharmony_ci *  - immediates and symbol addresses
323f08c3bdfSopenharmony_ci *  - pseudos we got as input in non-registers
324f08c3bdfSopenharmony_ci *  - pseudos we've already saved off earlier..
325f08c3bdfSopenharmony_ci */
326f08c3bdfSopenharmony_cistatic int can_regenerate(struct bb_state *state, pseudo_t pseudo)
327f08c3bdfSopenharmony_ci{
328f08c3bdfSopenharmony_ci	struct storage_hash *in;
329f08c3bdfSopenharmony_ci
330f08c3bdfSopenharmony_ci	switch (pseudo->type) {
331f08c3bdfSopenharmony_ci	case PSEUDO_VAL:
332f08c3bdfSopenharmony_ci	case PSEUDO_SYM:
333f08c3bdfSopenharmony_ci		return 1;
334f08c3bdfSopenharmony_ci
335f08c3bdfSopenharmony_ci	default:
336f08c3bdfSopenharmony_ci		in = find_storage_hash(pseudo, state->inputs);
337f08c3bdfSopenharmony_ci		if (in && in->storage->type != REG_REG)
338f08c3bdfSopenharmony_ci			return 1;
339f08c3bdfSopenharmony_ci		in = find_storage_hash(pseudo, state->internal);
340f08c3bdfSopenharmony_ci		if (in)
341f08c3bdfSopenharmony_ci			return 1;
342f08c3bdfSopenharmony_ci	}
343f08c3bdfSopenharmony_ci	return 0;
344f08c3bdfSopenharmony_ci}
345f08c3bdfSopenharmony_ci
346f08c3bdfSopenharmony_cistatic void flush_one_pseudo(struct bb_state *state, struct hardreg *hardreg, pseudo_t pseudo)
347f08c3bdfSopenharmony_ci{
348f08c3bdfSopenharmony_ci	struct storage_hash *out;
349f08c3bdfSopenharmony_ci	struct storage *storage;
350f08c3bdfSopenharmony_ci
351f08c3bdfSopenharmony_ci	if (can_regenerate(state, pseudo))
352f08c3bdfSopenharmony_ci		return;
353f08c3bdfSopenharmony_ci
354f08c3bdfSopenharmony_ci	output_comment(state, "flushing %s from %s", show_pseudo(pseudo), hardreg->name);
355f08c3bdfSopenharmony_ci	out = find_storage_hash(pseudo, state->internal);
356f08c3bdfSopenharmony_ci	if (!out) {
357f08c3bdfSopenharmony_ci		out = find_storage_hash(pseudo, state->outputs);
358f08c3bdfSopenharmony_ci		if (!out)
359f08c3bdfSopenharmony_ci			out = find_or_create_hash(pseudo, &state->internal);
360f08c3bdfSopenharmony_ci	}
361f08c3bdfSopenharmony_ci	storage = out->storage;
362f08c3bdfSopenharmony_ci	switch (storage->type) {
363f08c3bdfSopenharmony_ci	default:
364f08c3bdfSopenharmony_ci		/*
365f08c3bdfSopenharmony_ci		 * Aieee - the next user wants it in a register, but we
366f08c3bdfSopenharmony_ci		 * need to flush it to memory in between. Which means that
367f08c3bdfSopenharmony_ci		 * we need to allocate an internal one, dammit..
368f08c3bdfSopenharmony_ci		 */
369f08c3bdfSopenharmony_ci		out = find_or_create_hash(pseudo, &state->internal);
370f08c3bdfSopenharmony_ci		storage = out->storage;
371f08c3bdfSopenharmony_ci		/* Fall through */
372f08c3bdfSopenharmony_ci	case REG_UDEF:
373f08c3bdfSopenharmony_ci		alloc_stack(state, storage);
374f08c3bdfSopenharmony_ci		/* Fall through */
375f08c3bdfSopenharmony_ci	case REG_STACK:
376f08c3bdfSopenharmony_ci		output_insn(state, "movl %s,%s", hardreg->name, show_memop(storage));
377f08c3bdfSopenharmony_ci		break;
378f08c3bdfSopenharmony_ci	}
379f08c3bdfSopenharmony_ci}
380f08c3bdfSopenharmony_ci
381f08c3bdfSopenharmony_ci/* Flush a hardreg out to the storage it has.. */
382f08c3bdfSopenharmony_cistatic void flush_reg(struct bb_state *state, struct hardreg *reg)
383f08c3bdfSopenharmony_ci{
384f08c3bdfSopenharmony_ci	pseudo_t pseudo;
385f08c3bdfSopenharmony_ci
386f08c3bdfSopenharmony_ci	if (reg->busy)
387f08c3bdfSopenharmony_ci		output_comment(state, "reg %s flushed while busy is %d!", reg->name, reg->busy);
388f08c3bdfSopenharmony_ci	if (!reg->contains)
389f08c3bdfSopenharmony_ci		return;
390f08c3bdfSopenharmony_ci	reg->dead = 0;
391f08c3bdfSopenharmony_ci	reg->used = 1;
392f08c3bdfSopenharmony_ci	FOR_EACH_PTR_TAG(reg->contains, pseudo) {
393f08c3bdfSopenharmony_ci		if (CURRENT_TAG(pseudo) & TAG_DEAD)
394f08c3bdfSopenharmony_ci			continue;
395f08c3bdfSopenharmony_ci		if (!(CURRENT_TAG(pseudo) & TAG_DIRTY))
396f08c3bdfSopenharmony_ci			continue;
397f08c3bdfSopenharmony_ci		flush_one_pseudo(state, reg, pseudo);
398f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(pseudo);
399f08c3bdfSopenharmony_ci	free_ptr_list(&reg->contains);
400f08c3bdfSopenharmony_ci}
401f08c3bdfSopenharmony_ci
402f08c3bdfSopenharmony_cistatic struct storage_hash *find_pseudo_storage(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
403f08c3bdfSopenharmony_ci{
404f08c3bdfSopenharmony_ci	struct storage_hash *src;
405f08c3bdfSopenharmony_ci
406f08c3bdfSopenharmony_ci	src = find_storage_hash(pseudo, state->internal);
407f08c3bdfSopenharmony_ci	if (!src) {
408f08c3bdfSopenharmony_ci		src = find_storage_hash(pseudo, state->inputs);
409f08c3bdfSopenharmony_ci		if (!src) {
410f08c3bdfSopenharmony_ci			src = find_storage_hash(pseudo, state->outputs);
411f08c3bdfSopenharmony_ci			/* Undefined? Screw it! */
412f08c3bdfSopenharmony_ci			if (!src)
413f08c3bdfSopenharmony_ci				return NULL;
414f08c3bdfSopenharmony_ci
415f08c3bdfSopenharmony_ci			/*
416f08c3bdfSopenharmony_ci			 * If we found output storage, it had better be local stack
417f08c3bdfSopenharmony_ci			 * that we flushed to earlier..
418f08c3bdfSopenharmony_ci			 */
419f08c3bdfSopenharmony_ci			if (src->storage->type != REG_STACK)
420f08c3bdfSopenharmony_ci				return NULL;
421f08c3bdfSopenharmony_ci		}
422f08c3bdfSopenharmony_ci	}
423f08c3bdfSopenharmony_ci
424f08c3bdfSopenharmony_ci	/*
425f08c3bdfSopenharmony_ci	 * Incoming pseudo with out any pre-set storage allocation?
426f08c3bdfSopenharmony_ci	 * We can make up our own, and obviously prefer to get it
427f08c3bdfSopenharmony_ci	 * in the register we already selected (if it hasn't been
428f08c3bdfSopenharmony_ci	 * used yet).
429f08c3bdfSopenharmony_ci	 */
430f08c3bdfSopenharmony_ci	if (src->storage->type == REG_UDEF) {
431f08c3bdfSopenharmony_ci		if (reg && !reg->used) {
432f08c3bdfSopenharmony_ci			src->storage->type = REG_REG;
433f08c3bdfSopenharmony_ci			src->storage->regno = reg - hardregs;
434f08c3bdfSopenharmony_ci			return NULL;
435f08c3bdfSopenharmony_ci		}
436f08c3bdfSopenharmony_ci		alloc_stack(state, src->storage);
437f08c3bdfSopenharmony_ci	}
438f08c3bdfSopenharmony_ci	return src;
439f08c3bdfSopenharmony_ci}
440f08c3bdfSopenharmony_ci
441f08c3bdfSopenharmony_cistatic void mark_reg_dead(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
442f08c3bdfSopenharmony_ci{
443f08c3bdfSopenharmony_ci	pseudo_t p;
444f08c3bdfSopenharmony_ci
445f08c3bdfSopenharmony_ci	FOR_EACH_PTR_TAG(reg->contains, p) {
446f08c3bdfSopenharmony_ci		if (p != pseudo)
447f08c3bdfSopenharmony_ci			continue;
448f08c3bdfSopenharmony_ci		if (CURRENT_TAG(p) & TAG_DEAD)
449f08c3bdfSopenharmony_ci			continue;
450f08c3bdfSopenharmony_ci		output_comment(state, "marking pseudo %s in reg %s dead", show_pseudo(pseudo), reg->name);
451f08c3bdfSopenharmony_ci		TAG_CURRENT(p, TAG_DEAD);
452f08c3bdfSopenharmony_ci		reg->dead++;
453f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(p);
454f08c3bdfSopenharmony_ci}
455f08c3bdfSopenharmony_ci
456f08c3bdfSopenharmony_cistatic void add_pseudo_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
457f08c3bdfSopenharmony_ci{
458f08c3bdfSopenharmony_ci	output_comment(state, "added pseudo %s to reg %s", show_pseudo(pseudo), reg->name);
459f08c3bdfSopenharmony_ci	add_ptr_list_tag(&reg->contains, pseudo, TAG_DIRTY);
460f08c3bdfSopenharmony_ci}
461f08c3bdfSopenharmony_ci
462f08c3bdfSopenharmony_cistatic struct hardreg *preferred_reg(struct bb_state *state, pseudo_t target)
463f08c3bdfSopenharmony_ci{
464f08c3bdfSopenharmony_ci	struct storage_hash *dst;
465f08c3bdfSopenharmony_ci
466f08c3bdfSopenharmony_ci	dst = find_storage_hash(target, state->outputs);
467f08c3bdfSopenharmony_ci	if (dst) {
468f08c3bdfSopenharmony_ci		struct storage *storage = dst->storage;
469f08c3bdfSopenharmony_ci		if (storage->type == REG_REG)
470f08c3bdfSopenharmony_ci			return hardregs + storage->regno;
471f08c3bdfSopenharmony_ci	}
472f08c3bdfSopenharmony_ci	return NULL;
473f08c3bdfSopenharmony_ci}
474f08c3bdfSopenharmony_ci
475f08c3bdfSopenharmony_cistatic struct hardreg *empty_reg(struct bb_state *state)
476f08c3bdfSopenharmony_ci{
477f08c3bdfSopenharmony_ci	int i;
478f08c3bdfSopenharmony_ci	struct hardreg *reg = hardregs;
479f08c3bdfSopenharmony_ci
480f08c3bdfSopenharmony_ci	for (i = 0; i < REGNO; i++, reg++) {
481f08c3bdfSopenharmony_ci		if (!reg->contains)
482f08c3bdfSopenharmony_ci			return reg;
483f08c3bdfSopenharmony_ci	}
484f08c3bdfSopenharmony_ci	return NULL;
485f08c3bdfSopenharmony_ci}
486f08c3bdfSopenharmony_ci
487f08c3bdfSopenharmony_cistatic struct hardreg *target_reg(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
488f08c3bdfSopenharmony_ci{
489f08c3bdfSopenharmony_ci	int i;
490f08c3bdfSopenharmony_ci	int unable_to_find_reg = 0;
491f08c3bdfSopenharmony_ci	struct hardreg *reg;
492f08c3bdfSopenharmony_ci
493f08c3bdfSopenharmony_ci	/* First, see if we have a preferred target register.. */
494f08c3bdfSopenharmony_ci	reg = preferred_reg(state, target);
495f08c3bdfSopenharmony_ci	if (reg && !reg->contains)
496f08c3bdfSopenharmony_ci		goto found;
497f08c3bdfSopenharmony_ci
498f08c3bdfSopenharmony_ci	reg = empty_reg(state);
499f08c3bdfSopenharmony_ci	if (reg)
500f08c3bdfSopenharmony_ci		goto found;
501f08c3bdfSopenharmony_ci
502f08c3bdfSopenharmony_ci	i = last_reg;
503f08c3bdfSopenharmony_ci	do {
504f08c3bdfSopenharmony_ci		i++;
505f08c3bdfSopenharmony_ci		if (i >= REGNO)
506f08c3bdfSopenharmony_ci			i = 0;
507f08c3bdfSopenharmony_ci		reg = hardregs + i;
508f08c3bdfSopenharmony_ci		if (!reg->busy) {
509f08c3bdfSopenharmony_ci			flush_reg(state, reg);
510f08c3bdfSopenharmony_ci			last_reg = i;
511f08c3bdfSopenharmony_ci			goto found;
512f08c3bdfSopenharmony_ci		}
513f08c3bdfSopenharmony_ci	} while (i != last_reg);
514f08c3bdfSopenharmony_ci	assert(unable_to_find_reg);
515f08c3bdfSopenharmony_ci
516f08c3bdfSopenharmony_cifound:
517f08c3bdfSopenharmony_ci	add_pseudo_reg(state, pseudo, reg);
518f08c3bdfSopenharmony_ci	return reg;
519f08c3bdfSopenharmony_ci}
520f08c3bdfSopenharmony_ci
521f08c3bdfSopenharmony_cistatic struct hardreg *find_in_reg(struct bb_state *state, pseudo_t pseudo)
522f08c3bdfSopenharmony_ci{
523f08c3bdfSopenharmony_ci	int i;
524f08c3bdfSopenharmony_ci	struct hardreg *reg;
525f08c3bdfSopenharmony_ci
526f08c3bdfSopenharmony_ci	for (i = 0; i < REGNO; i++) {
527f08c3bdfSopenharmony_ci		pseudo_t p;
528f08c3bdfSopenharmony_ci
529f08c3bdfSopenharmony_ci		reg = hardregs + i;
530f08c3bdfSopenharmony_ci		FOR_EACH_PTR_TAG(reg->contains, p) {
531f08c3bdfSopenharmony_ci			if (p == pseudo) {
532f08c3bdfSopenharmony_ci				last_reg = i;
533f08c3bdfSopenharmony_ci				output_comment(state, "found pseudo %s in reg %s (busy=%d)", show_pseudo(pseudo), reg->name, reg->busy);
534f08c3bdfSopenharmony_ci				return reg;
535f08c3bdfSopenharmony_ci			}
536f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(p);
537f08c3bdfSopenharmony_ci	}
538f08c3bdfSopenharmony_ci	return NULL;
539f08c3bdfSopenharmony_ci}
540f08c3bdfSopenharmony_ci
541f08c3bdfSopenharmony_cistatic void flush_pseudo(struct bb_state *state, pseudo_t pseudo, struct storage *storage)
542f08c3bdfSopenharmony_ci{
543f08c3bdfSopenharmony_ci	struct hardreg *reg = find_in_reg(state, pseudo);
544f08c3bdfSopenharmony_ci
545f08c3bdfSopenharmony_ci	if (reg)
546f08c3bdfSopenharmony_ci		flush_reg(state, reg);
547f08c3bdfSopenharmony_ci}
548f08c3bdfSopenharmony_ci
549f08c3bdfSopenharmony_cistatic void flush_cc_cache_to_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
550f08c3bdfSopenharmony_ci{
551f08c3bdfSopenharmony_ci	int opcode = state->cc_opcode;
552f08c3bdfSopenharmony_ci
553f08c3bdfSopenharmony_ci	state->cc_opcode = 0;
554f08c3bdfSopenharmony_ci	state->cc_target = NULL;
555f08c3bdfSopenharmony_ci	output_insn(state, "%s %s", opcodes[opcode], reg->name);
556f08c3bdfSopenharmony_ci}
557f08c3bdfSopenharmony_ci
558f08c3bdfSopenharmony_cistatic void flush_cc_cache(struct bb_state *state)
559f08c3bdfSopenharmony_ci{
560f08c3bdfSopenharmony_ci	pseudo_t pseudo = state->cc_target;
561f08c3bdfSopenharmony_ci
562f08c3bdfSopenharmony_ci	if (pseudo) {
563f08c3bdfSopenharmony_ci		struct hardreg *dst;
564f08c3bdfSopenharmony_ci
565f08c3bdfSopenharmony_ci		state->cc_target = NULL;
566f08c3bdfSopenharmony_ci
567f08c3bdfSopenharmony_ci		if (!state->cc_dead) {
568f08c3bdfSopenharmony_ci			dst = target_reg(state, pseudo, pseudo);
569f08c3bdfSopenharmony_ci			flush_cc_cache_to_reg(state, pseudo, dst);
570f08c3bdfSopenharmony_ci		}
571f08c3bdfSopenharmony_ci	}
572f08c3bdfSopenharmony_ci}
573f08c3bdfSopenharmony_ci
574f08c3bdfSopenharmony_cistatic void add_cc_cache(struct bb_state *state, int opcode, pseudo_t pseudo)
575f08c3bdfSopenharmony_ci{
576f08c3bdfSopenharmony_ci	assert(!state->cc_target);
577f08c3bdfSopenharmony_ci	state->cc_target = pseudo;
578f08c3bdfSopenharmony_ci	state->cc_opcode = opcode;
579f08c3bdfSopenharmony_ci	state->cc_dead = 0;
580f08c3bdfSopenharmony_ci	output_comment(state, "caching %s", opcodes[opcode]);
581f08c3bdfSopenharmony_ci}
582f08c3bdfSopenharmony_ci
583f08c3bdfSopenharmony_ci/* Fill a hardreg with the pseudo it has */
584f08c3bdfSopenharmony_cistatic struct hardreg *fill_reg(struct bb_state *state, struct hardreg *hardreg, pseudo_t pseudo)
585f08c3bdfSopenharmony_ci{
586f08c3bdfSopenharmony_ci	struct storage_hash *src;
587f08c3bdfSopenharmony_ci	struct instruction *def;
588f08c3bdfSopenharmony_ci
589f08c3bdfSopenharmony_ci	if (state->cc_target == pseudo) {
590f08c3bdfSopenharmony_ci		flush_cc_cache_to_reg(state, pseudo, hardreg);
591f08c3bdfSopenharmony_ci		return hardreg;
592f08c3bdfSopenharmony_ci	}
593f08c3bdfSopenharmony_ci
594f08c3bdfSopenharmony_ci	switch (pseudo->type) {
595f08c3bdfSopenharmony_ci	case PSEUDO_VAL:
596f08c3bdfSopenharmony_ci		output_insn(state, "movl $%lld,%s", pseudo->value, hardreg->name);
597f08c3bdfSopenharmony_ci		break;
598f08c3bdfSopenharmony_ci	case PSEUDO_SYM:
599f08c3bdfSopenharmony_ci		src = find_pseudo_storage(state, pseudo, NULL);
600f08c3bdfSopenharmony_ci		/* Static thing? */
601f08c3bdfSopenharmony_ci		if (!src) {
602f08c3bdfSopenharmony_ci			output_insn(state, "movl $<%s>,%s", show_pseudo(pseudo), hardreg->name);
603f08c3bdfSopenharmony_ci			break;
604f08c3bdfSopenharmony_ci		}
605f08c3bdfSopenharmony_ci		switch (src->storage->type) {
606f08c3bdfSopenharmony_ci		case REG_REG:
607f08c3bdfSopenharmony_ci			/* Aiaiaiaiaii! Need to flush it to temporary memory */
608f08c3bdfSopenharmony_ci			src = find_or_create_hash(pseudo, &state->internal);
609f08c3bdfSopenharmony_ci			/* Fall through */
610f08c3bdfSopenharmony_ci		default:
611f08c3bdfSopenharmony_ci			alloc_stack(state, src->storage);
612f08c3bdfSopenharmony_ci			/* Fall through */
613f08c3bdfSopenharmony_ci		case REG_STACK:
614f08c3bdfSopenharmony_ci		case REG_FRAME:
615f08c3bdfSopenharmony_ci			flush_pseudo(state, pseudo, src->storage);
616f08c3bdfSopenharmony_ci			output_insn(state, "leal %s,%s", show_memop(src->storage), hardreg->name);
617f08c3bdfSopenharmony_ci			break;
618f08c3bdfSopenharmony_ci		}
619f08c3bdfSopenharmony_ci		break;
620f08c3bdfSopenharmony_ci	case PSEUDO_ARG:
621f08c3bdfSopenharmony_ci	case PSEUDO_REG:
622f08c3bdfSopenharmony_ci		def = pseudo->def;
623f08c3bdfSopenharmony_ci		if (def && (def->opcode == OP_SETVAL || def->opcode == OP_LABEL)) {
624f08c3bdfSopenharmony_ci			output_insn(state, "movl $<%s>,%s", show_pseudo(def->target), hardreg->name);
625f08c3bdfSopenharmony_ci			break;
626f08c3bdfSopenharmony_ci		}
627f08c3bdfSopenharmony_ci		src = find_pseudo_storage(state, pseudo, hardreg);
628f08c3bdfSopenharmony_ci		if (!src)
629f08c3bdfSopenharmony_ci			break;
630f08c3bdfSopenharmony_ci		if (src->flags & TAG_DEAD)
631f08c3bdfSopenharmony_ci			mark_reg_dead(state, pseudo, hardreg);
632f08c3bdfSopenharmony_ci		output_insn(state, "mov.%d %s,%s", 32, show_memop(src->storage), hardreg->name);
633f08c3bdfSopenharmony_ci		break;
634f08c3bdfSopenharmony_ci	default:
635f08c3bdfSopenharmony_ci		output_insn(state, "reload %s from %s", hardreg->name, show_pseudo(pseudo));
636f08c3bdfSopenharmony_ci		break;
637f08c3bdfSopenharmony_ci	}
638f08c3bdfSopenharmony_ci	return hardreg;
639f08c3bdfSopenharmony_ci}
640f08c3bdfSopenharmony_ci
641f08c3bdfSopenharmony_cistatic struct hardreg *getreg(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
642f08c3bdfSopenharmony_ci{
643f08c3bdfSopenharmony_ci	struct hardreg *reg;
644f08c3bdfSopenharmony_ci
645f08c3bdfSopenharmony_ci	reg = find_in_reg(state, pseudo);
646f08c3bdfSopenharmony_ci	if (reg)
647f08c3bdfSopenharmony_ci		return reg;
648f08c3bdfSopenharmony_ci	reg = target_reg(state, pseudo, target);
649f08c3bdfSopenharmony_ci	return fill_reg(state, reg, pseudo);
650f08c3bdfSopenharmony_ci}
651f08c3bdfSopenharmony_ci
652f08c3bdfSopenharmony_cistatic void move_reg(struct bb_state *state, struct hardreg *src, struct hardreg *dst)
653f08c3bdfSopenharmony_ci{
654f08c3bdfSopenharmony_ci	output_insn(state, "movl %s,%s", src->name, dst->name);
655f08c3bdfSopenharmony_ci}
656f08c3bdfSopenharmony_ci
657f08c3bdfSopenharmony_cistatic struct hardreg *copy_reg(struct bb_state *state, struct hardreg *src, pseudo_t target)
658f08c3bdfSopenharmony_ci{
659f08c3bdfSopenharmony_ci	int i;
660f08c3bdfSopenharmony_ci	struct hardreg *reg;
661f08c3bdfSopenharmony_ci
662f08c3bdfSopenharmony_ci	/* If the container has been killed off, just re-use it */
663f08c3bdfSopenharmony_ci	if (!src->contains)
664f08c3bdfSopenharmony_ci		return src;
665f08c3bdfSopenharmony_ci
666f08c3bdfSopenharmony_ci	/* If "src" only has one user, and the contents are dead, we can re-use it */
667f08c3bdfSopenharmony_ci	if (src->busy == 1 && src->dead == 1)
668f08c3bdfSopenharmony_ci		return src;
669f08c3bdfSopenharmony_ci
670f08c3bdfSopenharmony_ci	reg = preferred_reg(state, target);
671f08c3bdfSopenharmony_ci	if (reg && !reg->contains) {
672f08c3bdfSopenharmony_ci		output_comment(state, "copying %s to preferred target %s", show_pseudo(target), reg->name);
673f08c3bdfSopenharmony_ci		move_reg(state, src, reg);
674f08c3bdfSopenharmony_ci		return reg;
675f08c3bdfSopenharmony_ci	}
676f08c3bdfSopenharmony_ci
677f08c3bdfSopenharmony_ci	for (i = 0; i < REGNO; i++) {
678f08c3bdfSopenharmony_ci		reg = hardregs + i;
679f08c3bdfSopenharmony_ci		if (!reg->contains) {
680f08c3bdfSopenharmony_ci			output_comment(state, "copying %s to %s", show_pseudo(target), reg->name);
681f08c3bdfSopenharmony_ci			output_insn(state, "movl %s,%s", src->name, reg->name);
682f08c3bdfSopenharmony_ci			return reg;
683f08c3bdfSopenharmony_ci		}
684f08c3bdfSopenharmony_ci	}
685f08c3bdfSopenharmony_ci
686f08c3bdfSopenharmony_ci	flush_reg(state, src);
687f08c3bdfSopenharmony_ci	return src;
688f08c3bdfSopenharmony_ci}
689f08c3bdfSopenharmony_ci
690f08c3bdfSopenharmony_cistatic void put_operand(struct bb_state *state, struct operand *op)
691f08c3bdfSopenharmony_ci{
692f08c3bdfSopenharmony_ci	switch (op->type) {
693f08c3bdfSopenharmony_ci	case OP_REG:
694f08c3bdfSopenharmony_ci		op->reg->busy--;
695f08c3bdfSopenharmony_ci		break;
696f08c3bdfSopenharmony_ci	case OP_ADDR:
697f08c3bdfSopenharmony_ci	case OP_MEM:
698f08c3bdfSopenharmony_ci		if (op->base)
699f08c3bdfSopenharmony_ci			op->base->busy--;
700f08c3bdfSopenharmony_ci		if (op->index)
701f08c3bdfSopenharmony_ci			op->index->busy--;
702f08c3bdfSopenharmony_ci		break;
703f08c3bdfSopenharmony_ci	default:
704f08c3bdfSopenharmony_ci		break;
705f08c3bdfSopenharmony_ci	}
706f08c3bdfSopenharmony_ci}
707f08c3bdfSopenharmony_ci
708f08c3bdfSopenharmony_cistatic struct operand *alloc_op(void)
709f08c3bdfSopenharmony_ci{
710f08c3bdfSopenharmony_ci	struct operand *op = malloc(sizeof(*op));
711f08c3bdfSopenharmony_ci	memset(op, 0, sizeof(*op));
712f08c3bdfSopenharmony_ci	return op;
713f08c3bdfSopenharmony_ci}
714f08c3bdfSopenharmony_ci
715f08c3bdfSopenharmony_cistatic struct operand *get_register_operand(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
716f08c3bdfSopenharmony_ci{
717f08c3bdfSopenharmony_ci	struct operand *op = alloc_op();
718f08c3bdfSopenharmony_ci	op->type = OP_REG;
719f08c3bdfSopenharmony_ci	op->reg = getreg(state, pseudo, target);
720f08c3bdfSopenharmony_ci	op->reg->busy++;
721f08c3bdfSopenharmony_ci	return op;
722f08c3bdfSopenharmony_ci}
723f08c3bdfSopenharmony_ci
724f08c3bdfSopenharmony_cistatic int get_sym_frame_offset(struct bb_state *state, pseudo_t pseudo)
725f08c3bdfSopenharmony_ci{
726f08c3bdfSopenharmony_ci	int offset = pseudo->nr;
727f08c3bdfSopenharmony_ci	if (offset < 0) {
728f08c3bdfSopenharmony_ci		offset = alloc_stack_offset(4);
729f08c3bdfSopenharmony_ci		pseudo->nr = offset;
730f08c3bdfSopenharmony_ci	}
731f08c3bdfSopenharmony_ci	return offset;
732f08c3bdfSopenharmony_ci}
733f08c3bdfSopenharmony_ci
734f08c3bdfSopenharmony_cistatic struct operand *get_generic_operand(struct bb_state *state, pseudo_t pseudo)
735f08c3bdfSopenharmony_ci{
736f08c3bdfSopenharmony_ci	struct hardreg *reg;
737f08c3bdfSopenharmony_ci	struct storage *src;
738f08c3bdfSopenharmony_ci	struct storage_hash *hash;
739f08c3bdfSopenharmony_ci	struct operand *op = malloc(sizeof(*op));
740f08c3bdfSopenharmony_ci
741f08c3bdfSopenharmony_ci	memset(op, 0, sizeof(*op));
742f08c3bdfSopenharmony_ci	switch (pseudo->type) {
743f08c3bdfSopenharmony_ci	case PSEUDO_VAL:
744f08c3bdfSopenharmony_ci		op->type = OP_VAL;
745f08c3bdfSopenharmony_ci		op->value = pseudo->value;
746f08c3bdfSopenharmony_ci		break;
747f08c3bdfSopenharmony_ci
748f08c3bdfSopenharmony_ci	case PSEUDO_SYM: {
749f08c3bdfSopenharmony_ci		struct symbol *sym = pseudo->sym;
750f08c3bdfSopenharmony_ci		op->type = OP_ADDR;
751f08c3bdfSopenharmony_ci		if (sym->ctype.modifiers & MOD_NONLOCAL) {
752f08c3bdfSopenharmony_ci			op->sym = sym;
753f08c3bdfSopenharmony_ci			break;
754f08c3bdfSopenharmony_ci		}
755f08c3bdfSopenharmony_ci		op->base = hardregs + REG_EBP;
756f08c3bdfSopenharmony_ci		op->offset = get_sym_frame_offset(state, pseudo);
757f08c3bdfSopenharmony_ci		break;
758f08c3bdfSopenharmony_ci	}
759f08c3bdfSopenharmony_ci
760f08c3bdfSopenharmony_ci	default:
761f08c3bdfSopenharmony_ci		reg = find_in_reg(state, pseudo);
762f08c3bdfSopenharmony_ci		if (reg) {
763f08c3bdfSopenharmony_ci			op->type = OP_REG;
764f08c3bdfSopenharmony_ci			op->reg = reg;
765f08c3bdfSopenharmony_ci			reg->busy++;
766f08c3bdfSopenharmony_ci			break;
767f08c3bdfSopenharmony_ci		}
768f08c3bdfSopenharmony_ci		hash = find_pseudo_storage(state, pseudo, NULL);
769f08c3bdfSopenharmony_ci		if (!hash)
770f08c3bdfSopenharmony_ci			break;
771f08c3bdfSopenharmony_ci		src = hash->storage;
772f08c3bdfSopenharmony_ci		switch (src->type) {
773f08c3bdfSopenharmony_ci		case REG_REG:
774f08c3bdfSopenharmony_ci			op->type = OP_REG;
775f08c3bdfSopenharmony_ci			op->reg = hardregs + src->regno;
776f08c3bdfSopenharmony_ci			op->reg->busy++;
777f08c3bdfSopenharmony_ci			break;
778f08c3bdfSopenharmony_ci		case REG_FRAME:
779f08c3bdfSopenharmony_ci			op->type = OP_MEM;
780f08c3bdfSopenharmony_ci			op->offset = src->offset;
781f08c3bdfSopenharmony_ci			op->base = hardregs + REG_EBP;
782f08c3bdfSopenharmony_ci			break;
783f08c3bdfSopenharmony_ci		case REG_STACK:
784f08c3bdfSopenharmony_ci			op->type = OP_MEM;
785f08c3bdfSopenharmony_ci			op->offset = src->offset;
786f08c3bdfSopenharmony_ci			op->base = hardregs + REG_ESP;
787f08c3bdfSopenharmony_ci			break;
788f08c3bdfSopenharmony_ci		default:
789f08c3bdfSopenharmony_ci			break;
790f08c3bdfSopenharmony_ci		}
791f08c3bdfSopenharmony_ci	}
792f08c3bdfSopenharmony_ci	return op;
793f08c3bdfSopenharmony_ci}
794f08c3bdfSopenharmony_ci
795f08c3bdfSopenharmony_ci/* Callers should be made to use the proper "operand" formats */
796f08c3bdfSopenharmony_cistatic const char *generic(struct bb_state *state, pseudo_t pseudo)
797f08c3bdfSopenharmony_ci{
798f08c3bdfSopenharmony_ci	struct hardreg *reg;
799f08c3bdfSopenharmony_ci	struct operand *op = get_generic_operand(state, pseudo);
800f08c3bdfSopenharmony_ci	static char buf[100];
801f08c3bdfSopenharmony_ci	const char *str;
802f08c3bdfSopenharmony_ci
803f08c3bdfSopenharmony_ci	switch (op->type) {
804f08c3bdfSopenharmony_ci	case OP_ADDR:
805f08c3bdfSopenharmony_ci		if (!op->offset && op->base && !op->sym)
806f08c3bdfSopenharmony_ci			return op->base->name;
807f08c3bdfSopenharmony_ci		if (op->sym && !op->base) {
808f08c3bdfSopenharmony_ci			int len = sprintf(buf, "$ %s", show_op(state, op));
809f08c3bdfSopenharmony_ci			if (op->offset)
810f08c3bdfSopenharmony_ci				sprintf(buf + len, " + %d", op->offset);
811f08c3bdfSopenharmony_ci			return buf;
812f08c3bdfSopenharmony_ci		}
813f08c3bdfSopenharmony_ci		str = show_op(state, op);
814f08c3bdfSopenharmony_ci		put_operand(state, op);
815f08c3bdfSopenharmony_ci		reg = target_reg(state, pseudo, NULL);
816f08c3bdfSopenharmony_ci		output_insn(state, "lea %s,%s", show_op(state, op), reg->name);
817f08c3bdfSopenharmony_ci		return reg->name;
818f08c3bdfSopenharmony_ci
819f08c3bdfSopenharmony_ci	default:
820f08c3bdfSopenharmony_ci		str = show_op(state, op);
821f08c3bdfSopenharmony_ci	}
822f08c3bdfSopenharmony_ci	put_operand(state, op);
823f08c3bdfSopenharmony_ci	return str;
824f08c3bdfSopenharmony_ci}
825f08c3bdfSopenharmony_ci
826f08c3bdfSopenharmony_cistatic struct operand *get_address_operand(struct bb_state *state, struct instruction *memop)
827f08c3bdfSopenharmony_ci{
828f08c3bdfSopenharmony_ci	struct hardreg *base;
829f08c3bdfSopenharmony_ci	struct operand *op = get_generic_operand(state, memop->src);
830f08c3bdfSopenharmony_ci
831f08c3bdfSopenharmony_ci	switch (op->type) {
832f08c3bdfSopenharmony_ci	case OP_ADDR:
833f08c3bdfSopenharmony_ci		op->offset += memop->offset;
834f08c3bdfSopenharmony_ci		break;
835f08c3bdfSopenharmony_ci	default:
836f08c3bdfSopenharmony_ci		put_operand(state, op);
837f08c3bdfSopenharmony_ci		base = getreg(state, memop->src, NULL);
838f08c3bdfSopenharmony_ci		op->type = OP_ADDR;
839f08c3bdfSopenharmony_ci		op->base = base;
840f08c3bdfSopenharmony_ci		base->busy++;
841f08c3bdfSopenharmony_ci		op->offset = memop->offset;
842f08c3bdfSopenharmony_ci		op->sym = NULL;
843f08c3bdfSopenharmony_ci	}
844f08c3bdfSopenharmony_ci	return op;
845f08c3bdfSopenharmony_ci}
846f08c3bdfSopenharmony_ci
847f08c3bdfSopenharmony_cistatic const char *address(struct bb_state *state, struct instruction *memop)
848f08c3bdfSopenharmony_ci{
849f08c3bdfSopenharmony_ci	struct operand *op = get_address_operand(state, memop);
850f08c3bdfSopenharmony_ci	const char *str = show_op(state, op);
851f08c3bdfSopenharmony_ci	put_operand(state, op);
852f08c3bdfSopenharmony_ci	return str;
853f08c3bdfSopenharmony_ci}
854f08c3bdfSopenharmony_ci
855f08c3bdfSopenharmony_cistatic const char *reg_or_imm(struct bb_state *state, pseudo_t pseudo)
856f08c3bdfSopenharmony_ci{
857f08c3bdfSopenharmony_ci	switch(pseudo->type) {
858f08c3bdfSopenharmony_ci	case PSEUDO_VAL:
859f08c3bdfSopenharmony_ci		return show_pseudo(pseudo);
860f08c3bdfSopenharmony_ci	default:
861f08c3bdfSopenharmony_ci		return getreg(state, pseudo, NULL)->name;
862f08c3bdfSopenharmony_ci	}
863f08c3bdfSopenharmony_ci}
864f08c3bdfSopenharmony_ci
865f08c3bdfSopenharmony_cistatic void kill_dead_reg(struct hardreg *reg)
866f08c3bdfSopenharmony_ci{
867f08c3bdfSopenharmony_ci	if (reg->dead) {
868f08c3bdfSopenharmony_ci		pseudo_t p;
869f08c3bdfSopenharmony_ci
870f08c3bdfSopenharmony_ci		FOR_EACH_PTR_TAG(reg->contains, p) {
871f08c3bdfSopenharmony_ci			if (CURRENT_TAG(p) & TAG_DEAD) {
872f08c3bdfSopenharmony_ci				DELETE_CURRENT_PTR(p);
873f08c3bdfSopenharmony_ci				reg->dead--;
874f08c3bdfSopenharmony_ci			}
875f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(p);
876f08c3bdfSopenharmony_ci		PACK_PTR_LIST(&reg->contains);
877f08c3bdfSopenharmony_ci		assert(!reg->dead);
878f08c3bdfSopenharmony_ci	}
879f08c3bdfSopenharmony_ci}
880f08c3bdfSopenharmony_ci
881f08c3bdfSopenharmony_cistatic struct hardreg *target_copy_reg(struct bb_state *state, struct hardreg *src, pseudo_t target)
882f08c3bdfSopenharmony_ci{
883f08c3bdfSopenharmony_ci	kill_dead_reg(src);
884f08c3bdfSopenharmony_ci	return copy_reg(state, src, target);
885f08c3bdfSopenharmony_ci}
886f08c3bdfSopenharmony_ci
887f08c3bdfSopenharmony_cistatic void do_binop(struct bb_state *state, struct instruction *insn, pseudo_t val1, pseudo_t val2)
888f08c3bdfSopenharmony_ci{
889f08c3bdfSopenharmony_ci	const char *op = opcodes[insn->opcode];
890f08c3bdfSopenharmony_ci	struct operand *src = get_register_operand(state, val1, insn->target);
891f08c3bdfSopenharmony_ci	struct operand *src2 = get_generic_operand(state, val2);
892f08c3bdfSopenharmony_ci	struct hardreg *dst;
893f08c3bdfSopenharmony_ci
894f08c3bdfSopenharmony_ci	dst = target_copy_reg(state, src->reg, insn->target);
895f08c3bdfSopenharmony_ci	output_insn(state, "%s.%d %s,%s", op, insn->size, show_op(state, src2), dst->name);
896f08c3bdfSopenharmony_ci	put_operand(state, src);
897f08c3bdfSopenharmony_ci	put_operand(state, src2);
898f08c3bdfSopenharmony_ci	add_pseudo_reg(state, insn->target, dst);
899f08c3bdfSopenharmony_ci}
900f08c3bdfSopenharmony_ci
901f08c3bdfSopenharmony_cistatic void generate_binop(struct bb_state *state, struct instruction *insn)
902f08c3bdfSopenharmony_ci{
903f08c3bdfSopenharmony_ci	flush_cc_cache(state);
904f08c3bdfSopenharmony_ci	do_binop(state, insn, insn->src1, insn->src2);
905f08c3bdfSopenharmony_ci}
906f08c3bdfSopenharmony_ci
907f08c3bdfSopenharmony_cistatic int is_dead_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
908f08c3bdfSopenharmony_ci{
909f08c3bdfSopenharmony_ci	pseudo_t p;
910f08c3bdfSopenharmony_ci	FOR_EACH_PTR_TAG(reg->contains, p) {
911f08c3bdfSopenharmony_ci		if (p == pseudo)
912f08c3bdfSopenharmony_ci			return CURRENT_TAG(p) & TAG_DEAD;
913f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(p);
914f08c3bdfSopenharmony_ci	return 0;
915f08c3bdfSopenharmony_ci}
916f08c3bdfSopenharmony_ci
917f08c3bdfSopenharmony_ci/*
918f08c3bdfSopenharmony_ci * Commutative binops are much more flexible, since we can switch the
919f08c3bdfSopenharmony_ci * sources around to satisfy the target register, or to avoid having
920f08c3bdfSopenharmony_ci * to load one of them into a register..
921f08c3bdfSopenharmony_ci */
922f08c3bdfSopenharmony_cistatic void generate_commutative_binop(struct bb_state *state, struct instruction *insn)
923f08c3bdfSopenharmony_ci{
924f08c3bdfSopenharmony_ci	pseudo_t src1, src2;
925f08c3bdfSopenharmony_ci	struct hardreg *reg1, *reg2;
926f08c3bdfSopenharmony_ci
927f08c3bdfSopenharmony_ci	flush_cc_cache(state);
928f08c3bdfSopenharmony_ci	src1 = insn->src1;
929f08c3bdfSopenharmony_ci	src2 = insn->src2;
930f08c3bdfSopenharmony_ci	reg2 = find_in_reg(state, src2);
931f08c3bdfSopenharmony_ci	if (!reg2)
932f08c3bdfSopenharmony_ci		goto dont_switch;
933f08c3bdfSopenharmony_ci	reg1 = find_in_reg(state, src1);
934f08c3bdfSopenharmony_ci	if (!reg1)
935f08c3bdfSopenharmony_ci		goto do_switch;
936f08c3bdfSopenharmony_ci	if (!is_dead_reg(state, src2, reg2))
937f08c3bdfSopenharmony_ci		goto dont_switch;
938f08c3bdfSopenharmony_ci	if (!is_dead_reg(state, src1, reg1))
939f08c3bdfSopenharmony_ci		goto do_switch;
940f08c3bdfSopenharmony_ci
941f08c3bdfSopenharmony_ci	/* Both are dead. Is one preferable? */
942f08c3bdfSopenharmony_ci	if (reg2 != preferred_reg(state, insn->target))
943f08c3bdfSopenharmony_ci		goto dont_switch;
944f08c3bdfSopenharmony_ci
945f08c3bdfSopenharmony_cido_switch:
946f08c3bdfSopenharmony_ci	src1 = src2;
947f08c3bdfSopenharmony_ci	src2 = insn->src1;
948f08c3bdfSopenharmony_cidont_switch:
949f08c3bdfSopenharmony_ci	do_binop(state, insn, src1, src2);
950f08c3bdfSopenharmony_ci}
951f08c3bdfSopenharmony_ci
952f08c3bdfSopenharmony_ci/*
953f08c3bdfSopenharmony_ci * This marks a pseudo dead. It still stays on the hardreg list (the hardreg
954f08c3bdfSopenharmony_ci * still has its value), but it's scheduled to be killed after the next
955f08c3bdfSopenharmony_ci * "sequence point" when we call "kill_read_pseudos()"
956f08c3bdfSopenharmony_ci */
957f08c3bdfSopenharmony_cistatic void mark_pseudo_dead(struct bb_state *state, pseudo_t pseudo)
958f08c3bdfSopenharmony_ci{
959f08c3bdfSopenharmony_ci	int i;
960f08c3bdfSopenharmony_ci	struct storage_hash *src;
961f08c3bdfSopenharmony_ci
962f08c3bdfSopenharmony_ci	if (state->cc_target == pseudo)
963f08c3bdfSopenharmony_ci		state->cc_dead = 1;
964f08c3bdfSopenharmony_ci	src = find_pseudo_storage(state, pseudo, NULL);
965f08c3bdfSopenharmony_ci	if (src)
966f08c3bdfSopenharmony_ci		src->flags |= TAG_DEAD;
967f08c3bdfSopenharmony_ci	for (i = 0; i < REGNO; i++)
968f08c3bdfSopenharmony_ci		mark_reg_dead(state, pseudo, hardregs + i);
969f08c3bdfSopenharmony_ci}
970f08c3bdfSopenharmony_ci
971f08c3bdfSopenharmony_cistatic void kill_dead_pseudos(struct bb_state *state)
972f08c3bdfSopenharmony_ci{
973f08c3bdfSopenharmony_ci	int i;
974f08c3bdfSopenharmony_ci
975f08c3bdfSopenharmony_ci	for (i = 0; i < REGNO; i++) {
976f08c3bdfSopenharmony_ci		kill_dead_reg(hardregs + i);
977f08c3bdfSopenharmony_ci	}
978f08c3bdfSopenharmony_ci}
979f08c3bdfSopenharmony_ci
980f08c3bdfSopenharmony_cistatic void generate_store(struct instruction *insn, struct bb_state *state)
981f08c3bdfSopenharmony_ci{
982f08c3bdfSopenharmony_ci	output_insn(state, "mov.%d %s,%s", insn->size, reg_or_imm(state, insn->target), address(state, insn));
983f08c3bdfSopenharmony_ci}
984f08c3bdfSopenharmony_ci
985f08c3bdfSopenharmony_cistatic void generate_load(struct instruction *insn, struct bb_state *state)
986f08c3bdfSopenharmony_ci{
987f08c3bdfSopenharmony_ci	const char *input = address(state, insn);
988f08c3bdfSopenharmony_ci	struct hardreg *dst;
989f08c3bdfSopenharmony_ci
990f08c3bdfSopenharmony_ci	kill_dead_pseudos(state);
991f08c3bdfSopenharmony_ci	dst = target_reg(state, insn->target, NULL);
992f08c3bdfSopenharmony_ci	output_insn(state, "mov.%d %s,%s", insn->size, input, dst->name);
993f08c3bdfSopenharmony_ci}
994f08c3bdfSopenharmony_ci
995f08c3bdfSopenharmony_cistatic void kill_pseudo(struct bb_state *state, pseudo_t pseudo)
996f08c3bdfSopenharmony_ci{
997f08c3bdfSopenharmony_ci	int i;
998f08c3bdfSopenharmony_ci	struct hardreg *reg;
999f08c3bdfSopenharmony_ci
1000f08c3bdfSopenharmony_ci	output_comment(state, "killing pseudo %s", show_pseudo(pseudo));
1001f08c3bdfSopenharmony_ci	for (i = 0; i < REGNO; i++) {
1002f08c3bdfSopenharmony_ci		pseudo_t p;
1003f08c3bdfSopenharmony_ci
1004f08c3bdfSopenharmony_ci		reg = hardregs + i;
1005f08c3bdfSopenharmony_ci		FOR_EACH_PTR_TAG(reg->contains, p) {
1006f08c3bdfSopenharmony_ci			if (p != pseudo)
1007f08c3bdfSopenharmony_ci				continue;
1008f08c3bdfSopenharmony_ci			if (CURRENT_TAG(p) & TAG_DEAD)
1009f08c3bdfSopenharmony_ci				reg->dead--;
1010f08c3bdfSopenharmony_ci			output_comment(state, "removing pseudo %s from reg %s",
1011f08c3bdfSopenharmony_ci				show_pseudo(pseudo), reg->name);
1012f08c3bdfSopenharmony_ci			DELETE_CURRENT_PTR(p);
1013f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(p);
1014f08c3bdfSopenharmony_ci		PACK_PTR_LIST(&reg->contains);
1015f08c3bdfSopenharmony_ci	}
1016f08c3bdfSopenharmony_ci}
1017f08c3bdfSopenharmony_ci
1018f08c3bdfSopenharmony_cistatic void generate_copy(struct bb_state *state, struct instruction *insn)
1019f08c3bdfSopenharmony_ci{
1020f08c3bdfSopenharmony_ci	struct hardreg *src = getreg(state, insn->src, insn->target);
1021f08c3bdfSopenharmony_ci	kill_pseudo(state, insn->target);
1022f08c3bdfSopenharmony_ci	add_pseudo_reg(state, insn->target, src);
1023f08c3bdfSopenharmony_ci}
1024f08c3bdfSopenharmony_ci
1025f08c3bdfSopenharmony_cistatic void generate_cast(struct bb_state *state, struct instruction *insn)
1026f08c3bdfSopenharmony_ci{
1027f08c3bdfSopenharmony_ci	struct hardreg *src = getreg(state, insn->src, insn->target);
1028f08c3bdfSopenharmony_ci	struct hardreg *dst;
1029f08c3bdfSopenharmony_ci	unsigned int old = insn->orig_type ? insn->orig_type->bit_size : 0;
1030f08c3bdfSopenharmony_ci	unsigned int new = insn->size;
1031f08c3bdfSopenharmony_ci
1032f08c3bdfSopenharmony_ci	/*
1033f08c3bdfSopenharmony_ci	 * Cast to smaller type? Ignore the high bits, we
1034f08c3bdfSopenharmony_ci	 * just keep both pseudos in the same register.
1035f08c3bdfSopenharmony_ci	 */
1036f08c3bdfSopenharmony_ci	if (old >= new) {
1037f08c3bdfSopenharmony_ci		add_pseudo_reg(state, insn->target, src);
1038f08c3bdfSopenharmony_ci		return;
1039f08c3bdfSopenharmony_ci	}
1040f08c3bdfSopenharmony_ci
1041f08c3bdfSopenharmony_ci	dst = target_copy_reg(state, src, insn->target);
1042f08c3bdfSopenharmony_ci
1043f08c3bdfSopenharmony_ci	if (insn->orig_type && (insn->orig_type->ctype.modifiers & MOD_SIGNED)) {
1044f08c3bdfSopenharmony_ci		output_insn(state, "sext.%d.%d %s", old, new, dst->name);
1045f08c3bdfSopenharmony_ci	} else {
1046f08c3bdfSopenharmony_ci		unsigned long long mask;
1047f08c3bdfSopenharmony_ci		mask = ~(~0ULL << old);
1048f08c3bdfSopenharmony_ci		mask &= ~(~0ULL << new);
1049f08c3bdfSopenharmony_ci		output_insn(state, "andl.%d $%#llx,%s", insn->size, mask, dst->name);
1050f08c3bdfSopenharmony_ci	}
1051f08c3bdfSopenharmony_ci	add_pseudo_reg(state, insn->target, dst);
1052f08c3bdfSopenharmony_ci}
1053f08c3bdfSopenharmony_ci
1054f08c3bdfSopenharmony_cistatic void generate_output_storage(struct bb_state *state);
1055f08c3bdfSopenharmony_ci
1056f08c3bdfSopenharmony_cistatic const char *conditional[] = {
1057f08c3bdfSopenharmony_ci	[OP_SET_EQ] = "e",
1058f08c3bdfSopenharmony_ci	[OP_SET_NE] = "ne",
1059f08c3bdfSopenharmony_ci	[OP_SET_LE] = "le",
1060f08c3bdfSopenharmony_ci	[OP_SET_GE] = "ge",
1061f08c3bdfSopenharmony_ci	[OP_SET_LT] = "lt",
1062f08c3bdfSopenharmony_ci	[OP_SET_GT] = "gt",
1063f08c3bdfSopenharmony_ci	[OP_SET_B] = "b",
1064f08c3bdfSopenharmony_ci	[OP_SET_A] = "a",
1065f08c3bdfSopenharmony_ci	[OP_SET_BE] = "be",
1066f08c3bdfSopenharmony_ci	[OP_SET_AE] = "ae"
1067f08c3bdfSopenharmony_ci};
1068f08c3bdfSopenharmony_ci
1069f08c3bdfSopenharmony_ci
1070f08c3bdfSopenharmony_cistatic void generate_branch(struct bb_state *state, struct instruction *br)
1071f08c3bdfSopenharmony_ci{
1072f08c3bdfSopenharmony_ci	const char *cond = "XXX";
1073f08c3bdfSopenharmony_ci	struct basic_block *target;
1074f08c3bdfSopenharmony_ci
1075f08c3bdfSopenharmony_ci	if (br->cond) {
1076f08c3bdfSopenharmony_ci		if (state->cc_target == br->cond) {
1077f08c3bdfSopenharmony_ci			cond = conditional[state->cc_opcode];
1078f08c3bdfSopenharmony_ci		} else {
1079f08c3bdfSopenharmony_ci			struct hardreg *reg = getreg(state, br->cond, NULL);
1080f08c3bdfSopenharmony_ci			output_insn(state, "testl %s,%s", reg->name, reg->name);
1081f08c3bdfSopenharmony_ci			cond = "ne";
1082f08c3bdfSopenharmony_ci		}
1083f08c3bdfSopenharmony_ci	}
1084f08c3bdfSopenharmony_ci	generate_output_storage(state);
1085f08c3bdfSopenharmony_ci	target = br->bb_true;
1086f08c3bdfSopenharmony_ci	if (br->cond) {
1087f08c3bdfSopenharmony_ci		output_insn(state, "j%s .L%p", cond, target);
1088f08c3bdfSopenharmony_ci		target = br->bb_false;
1089f08c3bdfSopenharmony_ci	}
1090f08c3bdfSopenharmony_ci	output_insn(state, "jmp .L%p", target);
1091f08c3bdfSopenharmony_ci}
1092f08c3bdfSopenharmony_ci
1093f08c3bdfSopenharmony_ci/* We've made sure that there is a dummy reg live for the output */
1094f08c3bdfSopenharmony_cistatic void generate_switch(struct bb_state *state, struct instruction *insn)
1095f08c3bdfSopenharmony_ci{
1096f08c3bdfSopenharmony_ci	struct hardreg *reg = hardregs + SWITCH_REG;
1097f08c3bdfSopenharmony_ci
1098f08c3bdfSopenharmony_ci	generate_output_storage(state);
1099f08c3bdfSopenharmony_ci	output_insn(state, "switch on %s", reg->name);
1100f08c3bdfSopenharmony_ci	output_insn(state, "unimplemented: %s", show_instruction(insn));
1101f08c3bdfSopenharmony_ci}
1102f08c3bdfSopenharmony_ci
1103f08c3bdfSopenharmony_cistatic void generate_ret(struct bb_state *state, struct instruction *ret)
1104f08c3bdfSopenharmony_ci{
1105f08c3bdfSopenharmony_ci	if (ret->src && ret->src != VOID) {
1106f08c3bdfSopenharmony_ci		struct hardreg *wants = hardregs+0;
1107f08c3bdfSopenharmony_ci		struct hardreg *reg = getreg(state, ret->src, NULL);
1108f08c3bdfSopenharmony_ci		if (reg != wants)
1109f08c3bdfSopenharmony_ci			output_insn(state, "movl %s,%s", reg->name, wants->name);
1110f08c3bdfSopenharmony_ci	}
1111f08c3bdfSopenharmony_ci	output_insn(state, "ret");
1112f08c3bdfSopenharmony_ci}
1113f08c3bdfSopenharmony_ci
1114f08c3bdfSopenharmony_ci/*
1115f08c3bdfSopenharmony_ci * Fake "call" linearization just as a taster..
1116f08c3bdfSopenharmony_ci */
1117f08c3bdfSopenharmony_cistatic void generate_call(struct bb_state *state, struct instruction *insn)
1118f08c3bdfSopenharmony_ci{
1119f08c3bdfSopenharmony_ci	int offset = 0;
1120f08c3bdfSopenharmony_ci	pseudo_t arg;
1121f08c3bdfSopenharmony_ci
1122f08c3bdfSopenharmony_ci	FOR_EACH_PTR(insn->arguments, arg) {
1123f08c3bdfSopenharmony_ci		output_insn(state, "pushl %s", generic(state, arg));
1124f08c3bdfSopenharmony_ci		offset += 4;
1125f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(arg);
1126f08c3bdfSopenharmony_ci	flush_reg(state, hardregs+0);
1127f08c3bdfSopenharmony_ci	flush_reg(state, hardregs+1);
1128f08c3bdfSopenharmony_ci	flush_reg(state, hardregs+2);
1129f08c3bdfSopenharmony_ci	output_insn(state, "call %s", show_pseudo(insn->func));
1130f08c3bdfSopenharmony_ci	if (offset)
1131f08c3bdfSopenharmony_ci		output_insn(state, "addl $%d,%%esp", offset);
1132f08c3bdfSopenharmony_ci	if (insn->target && insn->target != VOID)
1133f08c3bdfSopenharmony_ci		add_pseudo_reg(state, insn->target, hardregs+0);
1134f08c3bdfSopenharmony_ci}
1135f08c3bdfSopenharmony_ci
1136f08c3bdfSopenharmony_cistatic void generate_select(struct bb_state *state, struct instruction *insn)
1137f08c3bdfSopenharmony_ci{
1138f08c3bdfSopenharmony_ci	const char *cond;
1139f08c3bdfSopenharmony_ci	struct hardreg *src1, *src2, *dst;
1140f08c3bdfSopenharmony_ci
1141f08c3bdfSopenharmony_ci	src1 = getreg(state, insn->src2, NULL);
1142f08c3bdfSopenharmony_ci	dst = copy_reg(state, src1, insn->target);
1143f08c3bdfSopenharmony_ci	add_pseudo_reg(state, insn->target, dst);
1144f08c3bdfSopenharmony_ci	src2 = getreg(state, insn->src3, insn->target);
1145f08c3bdfSopenharmony_ci
1146f08c3bdfSopenharmony_ci	if (state->cc_target == insn->src1) {
1147f08c3bdfSopenharmony_ci		cond = conditional[state->cc_opcode];
1148f08c3bdfSopenharmony_ci	} else {
1149f08c3bdfSopenharmony_ci		struct hardreg *reg = getreg(state, insn->src1, NULL);
1150f08c3bdfSopenharmony_ci		output_insn(state, "testl %s,%s", reg->name, reg->name);
1151f08c3bdfSopenharmony_ci		cond = "ne";
1152f08c3bdfSopenharmony_ci	}
1153f08c3bdfSopenharmony_ci
1154f08c3bdfSopenharmony_ci	output_insn(state, "sel%s %s,%s", cond, src2->name, dst->name);
1155f08c3bdfSopenharmony_ci}
1156f08c3bdfSopenharmony_ci
1157f08c3bdfSopenharmony_cistruct asm_arg {
1158f08c3bdfSopenharmony_ci	const struct ident *name;
1159f08c3bdfSopenharmony_ci	const char *value;
1160f08c3bdfSopenharmony_ci	pseudo_t pseudo;
1161f08c3bdfSopenharmony_ci	struct hardreg *reg;
1162f08c3bdfSopenharmony_ci};
1163f08c3bdfSopenharmony_ci
1164f08c3bdfSopenharmony_cistatic void replace_asm_arg(char **dst_p, struct asm_arg *arg)
1165f08c3bdfSopenharmony_ci{
1166f08c3bdfSopenharmony_ci	char *dst = *dst_p;
1167f08c3bdfSopenharmony_ci	int len = strlen(arg->value);
1168f08c3bdfSopenharmony_ci
1169f08c3bdfSopenharmony_ci	memcpy(dst, arg->value, len);
1170f08c3bdfSopenharmony_ci	*dst_p = dst + len;
1171f08c3bdfSopenharmony_ci}
1172f08c3bdfSopenharmony_ci
1173f08c3bdfSopenharmony_cistatic void replace_asm_percent(const char **src_p, char **dst_p, struct asm_arg *args, int nr)
1174f08c3bdfSopenharmony_ci{
1175f08c3bdfSopenharmony_ci	const char *src = *src_p;
1176f08c3bdfSopenharmony_ci	char c;
1177f08c3bdfSopenharmony_ci	int index;
1178f08c3bdfSopenharmony_ci
1179f08c3bdfSopenharmony_ci	c = *src++;
1180f08c3bdfSopenharmony_ci	switch (c) {
1181f08c3bdfSopenharmony_ci	case '0' ... '9':
1182f08c3bdfSopenharmony_ci		index = c - '0';
1183f08c3bdfSopenharmony_ci		if (index < nr)
1184f08c3bdfSopenharmony_ci			replace_asm_arg(dst_p, args+index);
1185f08c3bdfSopenharmony_ci		break;
1186f08c3bdfSopenharmony_ci	}
1187f08c3bdfSopenharmony_ci	*src_p = src;
1188f08c3bdfSopenharmony_ci	return;
1189f08c3bdfSopenharmony_ci}
1190f08c3bdfSopenharmony_ci
1191f08c3bdfSopenharmony_cistatic void replace_asm_named(const char **src_p, char **dst_p, struct asm_arg *args, int nr)
1192f08c3bdfSopenharmony_ci{
1193f08c3bdfSopenharmony_ci	const char *src = *src_p;
1194f08c3bdfSopenharmony_ci	const char *end = src;
1195f08c3bdfSopenharmony_ci
1196f08c3bdfSopenharmony_ci	for(;;) {
1197f08c3bdfSopenharmony_ci		char c = *end++;
1198f08c3bdfSopenharmony_ci		if (!c)
1199f08c3bdfSopenharmony_ci			return;
1200f08c3bdfSopenharmony_ci		if (c == ']') {
1201f08c3bdfSopenharmony_ci			int i;
1202f08c3bdfSopenharmony_ci
1203f08c3bdfSopenharmony_ci			*src_p = end;
1204f08c3bdfSopenharmony_ci			for (i = 0; i < nr; i++) {
1205f08c3bdfSopenharmony_ci				const struct ident *ident = args[i].name;
1206f08c3bdfSopenharmony_ci				int len;
1207f08c3bdfSopenharmony_ci				if (!ident)
1208f08c3bdfSopenharmony_ci					continue;
1209f08c3bdfSopenharmony_ci				len = ident->len;
1210f08c3bdfSopenharmony_ci				if (memcmp(src, ident->name, len))
1211f08c3bdfSopenharmony_ci					continue;
1212f08c3bdfSopenharmony_ci				replace_asm_arg(dst_p, args+i);
1213f08c3bdfSopenharmony_ci				return;
1214f08c3bdfSopenharmony_ci			}
1215f08c3bdfSopenharmony_ci		}
1216f08c3bdfSopenharmony_ci	}
1217f08c3bdfSopenharmony_ci}
1218f08c3bdfSopenharmony_ci
1219f08c3bdfSopenharmony_cistatic const char *replace_asm_args(const char *str, struct asm_arg *args, int nr)
1220f08c3bdfSopenharmony_ci{
1221f08c3bdfSopenharmony_ci	static char buffer[1000];
1222f08c3bdfSopenharmony_ci	char *p = buffer;
1223f08c3bdfSopenharmony_ci
1224f08c3bdfSopenharmony_ci	for (;;) {
1225f08c3bdfSopenharmony_ci		char c = *str;
1226f08c3bdfSopenharmony_ci		*p = c;
1227f08c3bdfSopenharmony_ci		if (!c)
1228f08c3bdfSopenharmony_ci			return buffer;
1229f08c3bdfSopenharmony_ci		str++;
1230f08c3bdfSopenharmony_ci		switch (c) {
1231f08c3bdfSopenharmony_ci		case '%':
1232f08c3bdfSopenharmony_ci			if (*str == '%') {
1233f08c3bdfSopenharmony_ci				str++;
1234f08c3bdfSopenharmony_ci				p++;
1235f08c3bdfSopenharmony_ci				continue;
1236f08c3bdfSopenharmony_ci			}
1237f08c3bdfSopenharmony_ci			replace_asm_percent(&str, &p, args, nr);
1238f08c3bdfSopenharmony_ci			continue;
1239f08c3bdfSopenharmony_ci		case '[':
1240f08c3bdfSopenharmony_ci			replace_asm_named(&str, &p, args, nr);
1241f08c3bdfSopenharmony_ci			continue;
1242f08c3bdfSopenharmony_ci		default:
1243f08c3bdfSopenharmony_ci			break;
1244f08c3bdfSopenharmony_ci		}
1245f08c3bdfSopenharmony_ci		p++;
1246f08c3bdfSopenharmony_ci	}
1247f08c3bdfSopenharmony_ci}
1248f08c3bdfSopenharmony_ci
1249f08c3bdfSopenharmony_ci#define MAX_ASM_ARG (50)
1250f08c3bdfSopenharmony_cistatic struct asm_arg asm_arguments[MAX_ASM_ARG];
1251f08c3bdfSopenharmony_ci
1252f08c3bdfSopenharmony_cistatic struct asm_arg *generate_asm_inputs(struct bb_state *state, struct asm_constraint_list *list, struct asm_arg *arg)
1253f08c3bdfSopenharmony_ci{
1254f08c3bdfSopenharmony_ci	struct asm_constraint *entry;
1255f08c3bdfSopenharmony_ci
1256f08c3bdfSopenharmony_ci	FOR_EACH_PTR(list, entry) {
1257f08c3bdfSopenharmony_ci		const char *constraint = entry->constraint;
1258f08c3bdfSopenharmony_ci		pseudo_t pseudo = entry->pseudo;
1259f08c3bdfSopenharmony_ci		struct hardreg *reg, *orig;
1260f08c3bdfSopenharmony_ci		const char *string;
1261f08c3bdfSopenharmony_ci		int index;
1262f08c3bdfSopenharmony_ci
1263f08c3bdfSopenharmony_ci		string = "undef";
1264f08c3bdfSopenharmony_ci		switch (*constraint) {
1265f08c3bdfSopenharmony_ci		case 'r':
1266f08c3bdfSopenharmony_ci			string = getreg(state, pseudo, NULL)->name;
1267f08c3bdfSopenharmony_ci			break;
1268f08c3bdfSopenharmony_ci		case '0' ... '9':
1269f08c3bdfSopenharmony_ci			index = *constraint - '0';
1270f08c3bdfSopenharmony_ci			reg = asm_arguments[index].reg;
1271f08c3bdfSopenharmony_ci			orig = find_in_reg(state, pseudo);
1272f08c3bdfSopenharmony_ci			if (orig)
1273f08c3bdfSopenharmony_ci				move_reg(state, orig, reg);
1274f08c3bdfSopenharmony_ci			else
1275f08c3bdfSopenharmony_ci				fill_reg(state, reg, pseudo);
1276f08c3bdfSopenharmony_ci			string = reg->name;
1277f08c3bdfSopenharmony_ci			break;
1278f08c3bdfSopenharmony_ci		default:
1279f08c3bdfSopenharmony_ci			string = generic(state, pseudo);
1280f08c3bdfSopenharmony_ci			break;
1281f08c3bdfSopenharmony_ci		}
1282f08c3bdfSopenharmony_ci
1283f08c3bdfSopenharmony_ci		output_insn(state, "# asm input \"%s\": %s : %s", constraint, show_pseudo(pseudo), string);
1284f08c3bdfSopenharmony_ci
1285f08c3bdfSopenharmony_ci		arg->name = entry->ident;
1286f08c3bdfSopenharmony_ci		arg->value = string;
1287f08c3bdfSopenharmony_ci		arg->pseudo = NULL;
1288f08c3bdfSopenharmony_ci		arg->reg = NULL;
1289f08c3bdfSopenharmony_ci		arg++;
1290f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(entry);
1291f08c3bdfSopenharmony_ci	return arg;
1292f08c3bdfSopenharmony_ci}
1293f08c3bdfSopenharmony_ci
1294f08c3bdfSopenharmony_cistatic struct asm_arg *generate_asm_outputs(struct bb_state *state, struct asm_constraint_list *list, struct asm_arg *arg)
1295f08c3bdfSopenharmony_ci{
1296f08c3bdfSopenharmony_ci	struct asm_constraint *entry;
1297f08c3bdfSopenharmony_ci
1298f08c3bdfSopenharmony_ci	FOR_EACH_PTR(list, entry) {
1299f08c3bdfSopenharmony_ci		const char *constraint = entry->constraint;
1300f08c3bdfSopenharmony_ci		pseudo_t pseudo = entry->pseudo;
1301f08c3bdfSopenharmony_ci		struct hardreg *reg;
1302f08c3bdfSopenharmony_ci		const char *string;
1303f08c3bdfSopenharmony_ci
1304f08c3bdfSopenharmony_ci		while (*constraint == '=' || *constraint == '+')
1305f08c3bdfSopenharmony_ci			constraint++;
1306f08c3bdfSopenharmony_ci
1307f08c3bdfSopenharmony_ci		string = "undef";
1308f08c3bdfSopenharmony_ci		switch (*constraint) {
1309f08c3bdfSopenharmony_ci		case 'r':
1310f08c3bdfSopenharmony_ci		default:
1311f08c3bdfSopenharmony_ci			reg = target_reg(state, pseudo, NULL);
1312f08c3bdfSopenharmony_ci			arg->pseudo = pseudo;
1313f08c3bdfSopenharmony_ci			arg->reg = reg;
1314f08c3bdfSopenharmony_ci			string = reg->name;
1315f08c3bdfSopenharmony_ci			break;
1316f08c3bdfSopenharmony_ci		}
1317f08c3bdfSopenharmony_ci
1318f08c3bdfSopenharmony_ci		output_insn(state, "# asm output \"%s\": %s : %s", constraint, show_pseudo(pseudo), string);
1319f08c3bdfSopenharmony_ci
1320f08c3bdfSopenharmony_ci		arg->name = entry->ident;
1321f08c3bdfSopenharmony_ci		arg->value = string;
1322f08c3bdfSopenharmony_ci		arg++;
1323f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(entry);
1324f08c3bdfSopenharmony_ci	return arg;
1325f08c3bdfSopenharmony_ci}
1326f08c3bdfSopenharmony_ci
1327f08c3bdfSopenharmony_cistatic void generate_asm(struct bb_state *state, struct instruction *insn)
1328f08c3bdfSopenharmony_ci{
1329f08c3bdfSopenharmony_ci	const char *str = insn->string;
1330f08c3bdfSopenharmony_ci
1331f08c3bdfSopenharmony_ci	if (insn->asm_rules->outputs || insn->asm_rules->inputs) {
1332f08c3bdfSopenharmony_ci		struct asm_arg *arg;
1333f08c3bdfSopenharmony_ci
1334f08c3bdfSopenharmony_ci		arg = generate_asm_outputs(state, insn->asm_rules->outputs, asm_arguments);
1335f08c3bdfSopenharmony_ci		arg = generate_asm_inputs(state, insn->asm_rules->inputs, arg);
1336f08c3bdfSopenharmony_ci		str = replace_asm_args(str, asm_arguments, arg - asm_arguments);
1337f08c3bdfSopenharmony_ci	}
1338f08c3bdfSopenharmony_ci	output_insn(state, "%s", str);
1339f08c3bdfSopenharmony_ci}
1340f08c3bdfSopenharmony_ci
1341f08c3bdfSopenharmony_cistatic void generate_compare(struct bb_state *state, struct instruction *insn)
1342f08c3bdfSopenharmony_ci{
1343f08c3bdfSopenharmony_ci	struct hardreg *src;
1344f08c3bdfSopenharmony_ci	const char *src2;
1345f08c3bdfSopenharmony_ci	int opcode;
1346f08c3bdfSopenharmony_ci
1347f08c3bdfSopenharmony_ci	flush_cc_cache(state);
1348f08c3bdfSopenharmony_ci	opcode = insn->opcode;
1349f08c3bdfSopenharmony_ci
1350f08c3bdfSopenharmony_ci	/*
1351f08c3bdfSopenharmony_ci	 * We should try to switch these around if necessary,
1352f08c3bdfSopenharmony_ci	 * and update the opcode to match..
1353f08c3bdfSopenharmony_ci	 */
1354f08c3bdfSopenharmony_ci	src = getreg(state, insn->src1, insn->target);
1355f08c3bdfSopenharmony_ci	src2 = generic(state, insn->src2);
1356f08c3bdfSopenharmony_ci
1357f08c3bdfSopenharmony_ci	output_insn(state, "cmp.%d %s,%s", insn->size, src2, src->name);
1358f08c3bdfSopenharmony_ci
1359f08c3bdfSopenharmony_ci	add_cc_cache(state, opcode, insn->target);
1360f08c3bdfSopenharmony_ci}
1361f08c3bdfSopenharmony_ci
1362f08c3bdfSopenharmony_cistatic void generate_one_insn(struct instruction *insn, struct bb_state *state)
1363f08c3bdfSopenharmony_ci{
1364f08c3bdfSopenharmony_ci	if (verbose)
1365f08c3bdfSopenharmony_ci		output_comment(state, "%s", show_instruction(insn));
1366f08c3bdfSopenharmony_ci
1367f08c3bdfSopenharmony_ci	switch (insn->opcode) {
1368f08c3bdfSopenharmony_ci	case OP_ENTRY: {
1369f08c3bdfSopenharmony_ci		struct symbol *sym = insn->bb->ep->name;
1370f08c3bdfSopenharmony_ci		const char *name = show_ident(sym->ident);
1371f08c3bdfSopenharmony_ci		if (sym->ctype.modifiers & MOD_STATIC)
1372f08c3bdfSopenharmony_ci			printf("\n\n%s:\n", name);
1373f08c3bdfSopenharmony_ci		else
1374f08c3bdfSopenharmony_ci			printf("\n\n.globl %s\n%s:\n", name, name);
1375f08c3bdfSopenharmony_ci		break;
1376f08c3bdfSopenharmony_ci	}
1377f08c3bdfSopenharmony_ci
1378f08c3bdfSopenharmony_ci	/*
1379f08c3bdfSopenharmony_ci	 * OP_LABEL & OP_SETVAL likewise doesn't actually generate any
1380f08c3bdfSopenharmony_ci	 * code. On use, the "def" of the pseudo will be
1381f08c3bdfSopenharmony_ci	 * looked up.
1382f08c3bdfSopenharmony_ci	 */
1383f08c3bdfSopenharmony_ci	case OP_LABEL:
1384f08c3bdfSopenharmony_ci	case OP_SETVAL:
1385f08c3bdfSopenharmony_ci		break;
1386f08c3bdfSopenharmony_ci
1387f08c3bdfSopenharmony_ci	case OP_STORE:
1388f08c3bdfSopenharmony_ci		generate_store(insn, state);
1389f08c3bdfSopenharmony_ci		break;
1390f08c3bdfSopenharmony_ci
1391f08c3bdfSopenharmony_ci	case OP_LOAD:
1392f08c3bdfSopenharmony_ci		generate_load(insn, state);
1393f08c3bdfSopenharmony_ci		break;
1394f08c3bdfSopenharmony_ci
1395f08c3bdfSopenharmony_ci	case OP_DEATHNOTE:
1396f08c3bdfSopenharmony_ci		mark_pseudo_dead(state, insn->target);
1397f08c3bdfSopenharmony_ci		return;
1398f08c3bdfSopenharmony_ci
1399f08c3bdfSopenharmony_ci	case OP_COPY:
1400f08c3bdfSopenharmony_ci		generate_copy(state, insn);
1401f08c3bdfSopenharmony_ci		break;
1402f08c3bdfSopenharmony_ci
1403f08c3bdfSopenharmony_ci	case OP_ADD: case OP_MUL:
1404f08c3bdfSopenharmony_ci	case OP_AND: case OP_OR: case OP_XOR:
1405f08c3bdfSopenharmony_ci		generate_commutative_binop(state, insn);
1406f08c3bdfSopenharmony_ci		break;
1407f08c3bdfSopenharmony_ci
1408f08c3bdfSopenharmony_ci	case OP_SUB: case OP_DIVU: case OP_DIVS:
1409f08c3bdfSopenharmony_ci	case OP_MODU: case OP_MODS:
1410f08c3bdfSopenharmony_ci	case OP_SHL: case OP_LSR: case OP_ASR:
1411f08c3bdfSopenharmony_ci 		generate_binop(state, insn);
1412f08c3bdfSopenharmony_ci		break;
1413f08c3bdfSopenharmony_ci
1414f08c3bdfSopenharmony_ci	case OP_BINCMP ... OP_BINCMP_END:
1415f08c3bdfSopenharmony_ci		generate_compare(state, insn);
1416f08c3bdfSopenharmony_ci		break;
1417f08c3bdfSopenharmony_ci
1418f08c3bdfSopenharmony_ci	case OP_SEXT: case OP_ZEXT:
1419f08c3bdfSopenharmony_ci	case OP_TRUNC:
1420f08c3bdfSopenharmony_ci	case OP_PTRCAST:
1421f08c3bdfSopenharmony_ci	case OP_UTPTR:
1422f08c3bdfSopenharmony_ci	case OP_PTRTU:
1423f08c3bdfSopenharmony_ci	case OP_FCVTU: case OP_FCVTS:
1424f08c3bdfSopenharmony_ci	case OP_UCVTF: case OP_SCVTF:
1425f08c3bdfSopenharmony_ci	case OP_FCVTF:
1426f08c3bdfSopenharmony_ci		generate_cast(state, insn);
1427f08c3bdfSopenharmony_ci		break;
1428f08c3bdfSopenharmony_ci
1429f08c3bdfSopenharmony_ci	case OP_SEL:
1430f08c3bdfSopenharmony_ci		generate_select(state, insn);
1431f08c3bdfSopenharmony_ci		break;
1432f08c3bdfSopenharmony_ci
1433f08c3bdfSopenharmony_ci	case OP_BR:
1434f08c3bdfSopenharmony_ci	case OP_CBR:
1435f08c3bdfSopenharmony_ci		generate_branch(state, insn);
1436f08c3bdfSopenharmony_ci		break;
1437f08c3bdfSopenharmony_ci
1438f08c3bdfSopenharmony_ci	case OP_SWITCH:
1439f08c3bdfSopenharmony_ci		generate_switch(state, insn);
1440f08c3bdfSopenharmony_ci		break;
1441f08c3bdfSopenharmony_ci
1442f08c3bdfSopenharmony_ci	case OP_CALL:
1443f08c3bdfSopenharmony_ci		generate_call(state, insn);
1444f08c3bdfSopenharmony_ci		break;
1445f08c3bdfSopenharmony_ci
1446f08c3bdfSopenharmony_ci	case OP_RET:
1447f08c3bdfSopenharmony_ci		generate_ret(state, insn);
1448f08c3bdfSopenharmony_ci		break;
1449f08c3bdfSopenharmony_ci
1450f08c3bdfSopenharmony_ci	case OP_ASM:
1451f08c3bdfSopenharmony_ci		generate_asm(state, insn);
1452f08c3bdfSopenharmony_ci		break;
1453f08c3bdfSopenharmony_ci
1454f08c3bdfSopenharmony_ci	case OP_PHI:
1455f08c3bdfSopenharmony_ci	case OP_PHISOURCE:
1456f08c3bdfSopenharmony_ci	default:
1457f08c3bdfSopenharmony_ci		output_insn(state, "unimplemented: %s", show_instruction(insn));
1458f08c3bdfSopenharmony_ci		break;
1459f08c3bdfSopenharmony_ci	}
1460f08c3bdfSopenharmony_ci	kill_dead_pseudos(state);
1461f08c3bdfSopenharmony_ci}
1462f08c3bdfSopenharmony_ci
1463f08c3bdfSopenharmony_ci#define VERY_BUSY 1000
1464f08c3bdfSopenharmony_ci#define REG_FIXED 2000
1465f08c3bdfSopenharmony_ci
1466f08c3bdfSopenharmony_cistatic void write_reg_to_storage(struct bb_state *state, struct hardreg *reg, pseudo_t pseudo, struct storage *storage)
1467f08c3bdfSopenharmony_ci{
1468f08c3bdfSopenharmony_ci	int i;
1469f08c3bdfSopenharmony_ci	struct hardreg *out;
1470f08c3bdfSopenharmony_ci
1471f08c3bdfSopenharmony_ci	switch (storage->type) {
1472f08c3bdfSopenharmony_ci	case REG_REG:
1473f08c3bdfSopenharmony_ci		out = hardregs + storage->regno;
1474f08c3bdfSopenharmony_ci		if (reg == out)
1475f08c3bdfSopenharmony_ci			return;
1476f08c3bdfSopenharmony_ci		output_insn(state, "movl %s,%s", reg->name, out->name);
1477f08c3bdfSopenharmony_ci		return;
1478f08c3bdfSopenharmony_ci	case REG_UDEF:
1479f08c3bdfSopenharmony_ci		if (reg->busy < VERY_BUSY) {
1480f08c3bdfSopenharmony_ci			storage->type = REG_REG;
1481f08c3bdfSopenharmony_ci			storage->regno = reg - hardregs;
1482f08c3bdfSopenharmony_ci			reg->busy = REG_FIXED;
1483f08c3bdfSopenharmony_ci			return;
1484f08c3bdfSopenharmony_ci		}
1485f08c3bdfSopenharmony_ci
1486f08c3bdfSopenharmony_ci		/* Try to find a non-busy register.. */
1487f08c3bdfSopenharmony_ci		for (i = 0; i < REGNO; i++) {
1488f08c3bdfSopenharmony_ci			out = hardregs + i;
1489f08c3bdfSopenharmony_ci			if (out->contains)
1490f08c3bdfSopenharmony_ci				continue;
1491f08c3bdfSopenharmony_ci			output_insn(state, "movl %s,%s", reg->name, out->name);
1492f08c3bdfSopenharmony_ci			storage->type = REG_REG;
1493f08c3bdfSopenharmony_ci			storage->regno = i;
1494f08c3bdfSopenharmony_ci			out->busy = REG_FIXED;
1495f08c3bdfSopenharmony_ci			return;
1496f08c3bdfSopenharmony_ci		}
1497f08c3bdfSopenharmony_ci
1498f08c3bdfSopenharmony_ci		/* Fall back on stack allocation ... */
1499f08c3bdfSopenharmony_ci		alloc_stack(state, storage);
1500f08c3bdfSopenharmony_ci		/* Fall through */
1501f08c3bdfSopenharmony_ci	default:
1502f08c3bdfSopenharmony_ci		output_insn(state, "movl %s,%s", reg->name, show_memop(storage));
1503f08c3bdfSopenharmony_ci		return;
1504f08c3bdfSopenharmony_ci	}
1505f08c3bdfSopenharmony_ci}
1506f08c3bdfSopenharmony_ci
1507f08c3bdfSopenharmony_cistatic void write_val_to_storage(struct bb_state *state, pseudo_t src, struct storage *storage)
1508f08c3bdfSopenharmony_ci{
1509f08c3bdfSopenharmony_ci	struct hardreg *out;
1510f08c3bdfSopenharmony_ci
1511f08c3bdfSopenharmony_ci	switch (storage->type) {
1512f08c3bdfSopenharmony_ci	case REG_UDEF:
1513f08c3bdfSopenharmony_ci		alloc_stack(state, storage);
1514f08c3bdfSopenharmony_ci	default:
1515f08c3bdfSopenharmony_ci		output_insn(state, "movl %s,%s", show_pseudo(src), show_memop(storage));
1516f08c3bdfSopenharmony_ci		break;
1517f08c3bdfSopenharmony_ci	case REG_REG:
1518f08c3bdfSopenharmony_ci		out = hardregs + storage->regno;
1519f08c3bdfSopenharmony_ci		output_insn(state, "movl %s,%s", show_pseudo(src), out->name);
1520f08c3bdfSopenharmony_ci	}
1521f08c3bdfSopenharmony_ci}
1522f08c3bdfSopenharmony_ci
1523f08c3bdfSopenharmony_cistatic void fill_output(struct bb_state *state, pseudo_t pseudo, struct storage *out)
1524f08c3bdfSopenharmony_ci{
1525f08c3bdfSopenharmony_ci	int i;
1526f08c3bdfSopenharmony_ci	struct storage_hash *in;
1527f08c3bdfSopenharmony_ci	struct instruction *def;
1528f08c3bdfSopenharmony_ci
1529f08c3bdfSopenharmony_ci	/* Is that pseudo a constant value? */
1530f08c3bdfSopenharmony_ci	switch (pseudo->type) {
1531f08c3bdfSopenharmony_ci	case PSEUDO_VAL:
1532f08c3bdfSopenharmony_ci		write_val_to_storage(state, pseudo, out);
1533f08c3bdfSopenharmony_ci		return;
1534f08c3bdfSopenharmony_ci	case PSEUDO_REG:
1535f08c3bdfSopenharmony_ci		def = pseudo->def;
1536f08c3bdfSopenharmony_ci		if (def && (def->opcode == OP_SETVAL || def->opcode == OP_LABEL)) {
1537f08c3bdfSopenharmony_ci			write_val_to_storage(state, pseudo, out);
1538f08c3bdfSopenharmony_ci			return;
1539f08c3bdfSopenharmony_ci		}
1540f08c3bdfSopenharmony_ci	default:
1541f08c3bdfSopenharmony_ci		break;
1542f08c3bdfSopenharmony_ci	}
1543f08c3bdfSopenharmony_ci
1544f08c3bdfSopenharmony_ci	/* See if we have that pseudo in a register.. */
1545f08c3bdfSopenharmony_ci	for (i = 0; i < REGNO; i++) {
1546f08c3bdfSopenharmony_ci		struct hardreg *reg = hardregs + i;
1547f08c3bdfSopenharmony_ci		pseudo_t p;
1548f08c3bdfSopenharmony_ci
1549f08c3bdfSopenharmony_ci		FOR_EACH_PTR_TAG(reg->contains, p) {
1550f08c3bdfSopenharmony_ci			if (p == pseudo) {
1551f08c3bdfSopenharmony_ci				write_reg_to_storage(state, reg, pseudo, out);
1552f08c3bdfSopenharmony_ci				return;
1553f08c3bdfSopenharmony_ci			}
1554f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(p);
1555f08c3bdfSopenharmony_ci	}
1556f08c3bdfSopenharmony_ci
1557f08c3bdfSopenharmony_ci	/* Do we have it in another storage? */
1558f08c3bdfSopenharmony_ci	in = find_storage_hash(pseudo, state->internal);
1559f08c3bdfSopenharmony_ci	if (!in) {
1560f08c3bdfSopenharmony_ci		in = find_storage_hash(pseudo, state->inputs);
1561f08c3bdfSopenharmony_ci		/* Undefined? */
1562f08c3bdfSopenharmony_ci		if (!in)
1563f08c3bdfSopenharmony_ci			return;
1564f08c3bdfSopenharmony_ci	}
1565f08c3bdfSopenharmony_ci	switch (out->type) {
1566f08c3bdfSopenharmony_ci	case REG_UDEF:
1567f08c3bdfSopenharmony_ci		*out = *in->storage;
1568f08c3bdfSopenharmony_ci		break;
1569f08c3bdfSopenharmony_ci	case REG_REG:
1570f08c3bdfSopenharmony_ci		output_insn(state, "movl %s,%s", show_memop(in->storage), hardregs[out->regno].name);
1571f08c3bdfSopenharmony_ci		break;
1572f08c3bdfSopenharmony_ci	default:
1573f08c3bdfSopenharmony_ci		if (out == in->storage)
1574f08c3bdfSopenharmony_ci			break;
1575f08c3bdfSopenharmony_ci		if ((out->type == in->storage->type) && (out->regno == in->storage->regno))
1576f08c3bdfSopenharmony_ci			break;
1577f08c3bdfSopenharmony_ci		output_insn(state, "movl %s,%s", show_memop(in->storage), show_memop(out));
1578f08c3bdfSopenharmony_ci		break;
1579f08c3bdfSopenharmony_ci	}
1580f08c3bdfSopenharmony_ci	return;
1581f08c3bdfSopenharmony_ci}
1582f08c3bdfSopenharmony_ci
1583f08c3bdfSopenharmony_cistatic int final_pseudo_flush(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
1584f08c3bdfSopenharmony_ci{
1585f08c3bdfSopenharmony_ci	struct storage_hash *hash;
1586f08c3bdfSopenharmony_ci	struct storage *out;
1587f08c3bdfSopenharmony_ci	struct hardreg *dst;
1588f08c3bdfSopenharmony_ci
1589f08c3bdfSopenharmony_ci	/*
1590f08c3bdfSopenharmony_ci	 * Since this pseudo is live at exit, we'd better have output
1591f08c3bdfSopenharmony_ci	 * storage for it..
1592f08c3bdfSopenharmony_ci	 */
1593f08c3bdfSopenharmony_ci	hash = find_storage_hash(pseudo, state->outputs);
1594f08c3bdfSopenharmony_ci	if (!hash)
1595f08c3bdfSopenharmony_ci		return 1;
1596f08c3bdfSopenharmony_ci	out = hash->storage;
1597f08c3bdfSopenharmony_ci
1598f08c3bdfSopenharmony_ci	/* If the output is in a register, try to get it there.. */
1599f08c3bdfSopenharmony_ci	if (out->type == REG_REG) {
1600f08c3bdfSopenharmony_ci		dst = hardregs + out->regno;
1601f08c3bdfSopenharmony_ci		/*
1602f08c3bdfSopenharmony_ci		 * Two good cases: nobody is using the right register,
1603f08c3bdfSopenharmony_ci		 * or we've already set it aside for output..
1604f08c3bdfSopenharmony_ci		 */
1605f08c3bdfSopenharmony_ci		if (!dst->contains || dst->busy > VERY_BUSY)
1606f08c3bdfSopenharmony_ci			goto copy_to_dst;
1607f08c3bdfSopenharmony_ci
1608f08c3bdfSopenharmony_ci		/* Aiee. Try to keep it in a register.. */
1609f08c3bdfSopenharmony_ci		dst = empty_reg(state);
1610f08c3bdfSopenharmony_ci		if (dst)
1611f08c3bdfSopenharmony_ci			goto copy_to_dst;
1612f08c3bdfSopenharmony_ci
1613f08c3bdfSopenharmony_ci		return 0;
1614f08c3bdfSopenharmony_ci	}
1615f08c3bdfSopenharmony_ci
1616f08c3bdfSopenharmony_ci	/* If the output is undefined, let's see if we can put it in a register.. */
1617f08c3bdfSopenharmony_ci	if (out->type == REG_UDEF) {
1618f08c3bdfSopenharmony_ci		dst = empty_reg(state);
1619f08c3bdfSopenharmony_ci		if (dst) {
1620f08c3bdfSopenharmony_ci			out->type = REG_REG;
1621f08c3bdfSopenharmony_ci			out->regno = dst - hardregs;
1622f08c3bdfSopenharmony_ci			goto copy_to_dst;
1623f08c3bdfSopenharmony_ci		}
1624f08c3bdfSopenharmony_ci		/* Uhhuh. Not so good. No empty registers right now */
1625f08c3bdfSopenharmony_ci		return 0;
1626f08c3bdfSopenharmony_ci	}
1627f08c3bdfSopenharmony_ci
1628f08c3bdfSopenharmony_ci	/* If we know we need to flush it, just do so already .. */
1629f08c3bdfSopenharmony_ci	output_insn(state, "movl %s,%s", reg->name, show_memop(out));
1630f08c3bdfSopenharmony_ci	return 1;
1631f08c3bdfSopenharmony_ci
1632f08c3bdfSopenharmony_cicopy_to_dst:
1633f08c3bdfSopenharmony_ci	if (reg == dst)
1634f08c3bdfSopenharmony_ci		return 1;
1635f08c3bdfSopenharmony_ci	output_insn(state, "movl %s,%s", reg->name, dst->name);
1636f08c3bdfSopenharmony_ci	add_pseudo_reg(state, pseudo, dst);
1637f08c3bdfSopenharmony_ci	return 1;
1638f08c3bdfSopenharmony_ci}
1639f08c3bdfSopenharmony_ci
1640f08c3bdfSopenharmony_ci/*
1641f08c3bdfSopenharmony_ci * This tries to make sure that we put all the pseudos that are
1642f08c3bdfSopenharmony_ci * live on exit into the proper storage
1643f08c3bdfSopenharmony_ci */
1644f08c3bdfSopenharmony_cistatic void generate_output_storage(struct bb_state *state)
1645f08c3bdfSopenharmony_ci{
1646f08c3bdfSopenharmony_ci	struct storage_hash *entry;
1647f08c3bdfSopenharmony_ci
1648f08c3bdfSopenharmony_ci	/* Go through the fixed outputs, making sure we have those regs free */
1649f08c3bdfSopenharmony_ci	FOR_EACH_PTR(state->outputs, entry) {
1650f08c3bdfSopenharmony_ci		struct storage *out = entry->storage;
1651f08c3bdfSopenharmony_ci		if (out->type == REG_REG) {
1652f08c3bdfSopenharmony_ci			struct hardreg *reg = hardregs + out->regno;
1653f08c3bdfSopenharmony_ci			pseudo_t p;
1654f08c3bdfSopenharmony_ci			int flushme = 0;
1655f08c3bdfSopenharmony_ci
1656f08c3bdfSopenharmony_ci			reg->busy = REG_FIXED;
1657f08c3bdfSopenharmony_ci			FOR_EACH_PTR_TAG(reg->contains, p) {
1658f08c3bdfSopenharmony_ci				if (p == entry->pseudo) {
1659f08c3bdfSopenharmony_ci					flushme = -100;
1660f08c3bdfSopenharmony_ci					continue;
1661f08c3bdfSopenharmony_ci				}
1662f08c3bdfSopenharmony_ci				if (CURRENT_TAG(p) & TAG_DEAD)
1663f08c3bdfSopenharmony_ci					continue;
1664f08c3bdfSopenharmony_ci
1665f08c3bdfSopenharmony_ci				/* Try to write back the pseudo to where it should go ... */
1666f08c3bdfSopenharmony_ci				if (final_pseudo_flush(state, p, reg)) {
1667f08c3bdfSopenharmony_ci					DELETE_CURRENT_PTR(p);
1668f08c3bdfSopenharmony_ci					continue;
1669f08c3bdfSopenharmony_ci				}
1670f08c3bdfSopenharmony_ci				flushme++;
1671f08c3bdfSopenharmony_ci			} END_FOR_EACH_PTR(p);
1672f08c3bdfSopenharmony_ci			PACK_PTR_LIST(&reg->contains);
1673f08c3bdfSopenharmony_ci			if (flushme > 0)
1674f08c3bdfSopenharmony_ci				flush_reg(state, reg);
1675f08c3bdfSopenharmony_ci		}
1676f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(entry);
1677f08c3bdfSopenharmony_ci
1678f08c3bdfSopenharmony_ci	FOR_EACH_PTR(state->outputs, entry) {
1679f08c3bdfSopenharmony_ci		fill_output(state, entry->pseudo, entry->storage);
1680f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(entry);
1681f08c3bdfSopenharmony_ci}
1682f08c3bdfSopenharmony_ci
1683f08c3bdfSopenharmony_cistatic void generate(struct basic_block *bb, struct bb_state *state)
1684f08c3bdfSopenharmony_ci{
1685f08c3bdfSopenharmony_ci	int i;
1686f08c3bdfSopenharmony_ci	struct storage_hash *entry;
1687f08c3bdfSopenharmony_ci	struct instruction *insn;
1688f08c3bdfSopenharmony_ci
1689f08c3bdfSopenharmony_ci	for (i = 0; i < REGNO; i++) {
1690f08c3bdfSopenharmony_ci		free_ptr_list(&hardregs[i].contains);
1691f08c3bdfSopenharmony_ci		hardregs[i].busy = 0;
1692f08c3bdfSopenharmony_ci		hardregs[i].dead = 0;
1693f08c3bdfSopenharmony_ci		hardregs[i].used = 0;
1694f08c3bdfSopenharmony_ci	}
1695f08c3bdfSopenharmony_ci
1696f08c3bdfSopenharmony_ci	FOR_EACH_PTR(state->inputs, entry) {
1697f08c3bdfSopenharmony_ci		struct storage *storage = entry->storage;
1698f08c3bdfSopenharmony_ci		const char *name = show_storage(storage);
1699f08c3bdfSopenharmony_ci		output_comment(state, "incoming %s in %s", show_pseudo(entry->pseudo), name);
1700f08c3bdfSopenharmony_ci		if (storage->type == REG_REG) {
1701f08c3bdfSopenharmony_ci			int regno = storage->regno;
1702f08c3bdfSopenharmony_ci			add_pseudo_reg(state, entry->pseudo, hardregs + regno);
1703f08c3bdfSopenharmony_ci			name = hardregs[regno].name;
1704f08c3bdfSopenharmony_ci		}
1705f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(entry);
1706f08c3bdfSopenharmony_ci
1707f08c3bdfSopenharmony_ci	output_label(state, ".L%p", bb);
1708f08c3bdfSopenharmony_ci	FOR_EACH_PTR(bb->insns, insn) {
1709f08c3bdfSopenharmony_ci		if (!insn->bb)
1710f08c3bdfSopenharmony_ci			continue;
1711f08c3bdfSopenharmony_ci		generate_one_insn(insn, state);
1712f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(insn);
1713f08c3bdfSopenharmony_ci
1714f08c3bdfSopenharmony_ci	if (verbose) {
1715f08c3bdfSopenharmony_ci		output_comment(state, "--- in ---");
1716f08c3bdfSopenharmony_ci		FOR_EACH_PTR(state->inputs, entry) {
1717f08c3bdfSopenharmony_ci			output_comment(state, "%s <- %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
1718f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(entry);
1719f08c3bdfSopenharmony_ci		output_comment(state, "--- spill ---");
1720f08c3bdfSopenharmony_ci		FOR_EACH_PTR(state->internal, entry) {
1721f08c3bdfSopenharmony_ci			output_comment(state, "%s <-> %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
1722f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(entry);
1723f08c3bdfSopenharmony_ci		output_comment(state, "--- out ---");
1724f08c3bdfSopenharmony_ci		FOR_EACH_PTR(state->outputs, entry) {
1725f08c3bdfSopenharmony_ci			output_comment(state, "%s -> %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
1726f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(entry);
1727f08c3bdfSopenharmony_ci	}
1728f08c3bdfSopenharmony_ci	printf("\n");
1729f08c3bdfSopenharmony_ci}
1730f08c3bdfSopenharmony_ci
1731f08c3bdfSopenharmony_cistatic void generate_list(struct basic_block_list *list, unsigned long generation)
1732f08c3bdfSopenharmony_ci{
1733f08c3bdfSopenharmony_ci	struct basic_block *bb;
1734f08c3bdfSopenharmony_ci	FOR_EACH_PTR(list, bb) {
1735f08c3bdfSopenharmony_ci		if (bb->generation == generation)
1736f08c3bdfSopenharmony_ci			continue;
1737f08c3bdfSopenharmony_ci		output_bb(bb, generation);
1738f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(bb);
1739f08c3bdfSopenharmony_ci}
1740f08c3bdfSopenharmony_ci
1741f08c3bdfSopenharmony_ci/*
1742f08c3bdfSopenharmony_ci * Mark all the output registers of all the parents
1743f08c3bdfSopenharmony_ci * as being "used" - this does not mean that we cannot
1744f08c3bdfSopenharmony_ci * re-use them, but it means that we cannot ask the
1745f08c3bdfSopenharmony_ci * parents to pass in another pseudo in one of those
1746f08c3bdfSopenharmony_ci * registers that it already uses for another child.
1747f08c3bdfSopenharmony_ci */
1748f08c3bdfSopenharmony_cistatic void mark_used_registers(struct basic_block *bb, struct bb_state *state)
1749f08c3bdfSopenharmony_ci{
1750f08c3bdfSopenharmony_ci	struct basic_block *parent;
1751f08c3bdfSopenharmony_ci
1752f08c3bdfSopenharmony_ci	FOR_EACH_PTR(bb->parents, parent) {
1753f08c3bdfSopenharmony_ci		struct storage_hash_list *outputs = gather_storage(parent, STOR_OUT);
1754f08c3bdfSopenharmony_ci		struct storage_hash *entry;
1755f08c3bdfSopenharmony_ci
1756f08c3bdfSopenharmony_ci		FOR_EACH_PTR(outputs, entry) {
1757f08c3bdfSopenharmony_ci			struct storage *s = entry->storage;
1758f08c3bdfSopenharmony_ci			if (s->type == REG_REG) {
1759f08c3bdfSopenharmony_ci				struct hardreg *reg = hardregs + s->regno;
1760f08c3bdfSopenharmony_ci				reg->used = 1;
1761f08c3bdfSopenharmony_ci			}
1762f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(entry);
1763f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(parent);
1764f08c3bdfSopenharmony_ci}
1765f08c3bdfSopenharmony_ci
1766f08c3bdfSopenharmony_cistatic void output_bb(struct basic_block *bb, unsigned long generation)
1767f08c3bdfSopenharmony_ci{
1768f08c3bdfSopenharmony_ci	struct bb_state state;
1769f08c3bdfSopenharmony_ci
1770f08c3bdfSopenharmony_ci	bb->generation = generation;
1771f08c3bdfSopenharmony_ci
1772f08c3bdfSopenharmony_ci	/* Make sure all parents have been generated first */
1773f08c3bdfSopenharmony_ci	generate_list(bb->parents, generation);
1774f08c3bdfSopenharmony_ci
1775f08c3bdfSopenharmony_ci	state.pos = bb->pos;
1776f08c3bdfSopenharmony_ci	state.inputs = gather_storage(bb, STOR_IN);
1777f08c3bdfSopenharmony_ci	state.outputs = gather_storage(bb, STOR_OUT);
1778f08c3bdfSopenharmony_ci	state.internal = NULL;
1779f08c3bdfSopenharmony_ci	state.cc_opcode = 0;
1780f08c3bdfSopenharmony_ci	state.cc_target = NULL;
1781f08c3bdfSopenharmony_ci
1782f08c3bdfSopenharmony_ci	/* Mark incoming registers used */
1783f08c3bdfSopenharmony_ci	mark_used_registers(bb, &state);
1784f08c3bdfSopenharmony_ci
1785f08c3bdfSopenharmony_ci	generate(bb, &state);
1786f08c3bdfSopenharmony_ci
1787f08c3bdfSopenharmony_ci	free_ptr_list(&state.inputs);
1788f08c3bdfSopenharmony_ci	free_ptr_list(&state.outputs);
1789f08c3bdfSopenharmony_ci
1790f08c3bdfSopenharmony_ci	/* Generate all children... */
1791f08c3bdfSopenharmony_ci	generate_list(bb->children, generation);
1792f08c3bdfSopenharmony_ci}
1793f08c3bdfSopenharmony_ci
1794f08c3bdfSopenharmony_ci/*
1795f08c3bdfSopenharmony_ci * We should set up argument sources here..
1796f08c3bdfSopenharmony_ci *
1797f08c3bdfSopenharmony_ci * Things like "first three arguments in registers" etc
1798f08c3bdfSopenharmony_ci * are all for this place.
1799f08c3bdfSopenharmony_ci *
1800f08c3bdfSopenharmony_ci * On x86, we default to stack, unless it's a static
1801f08c3bdfSopenharmony_ci * function that doesn't have its address taken.
1802f08c3bdfSopenharmony_ci *
1803f08c3bdfSopenharmony_ci * I should implement the -mregparm=X cmd line option.
1804f08c3bdfSopenharmony_ci */
1805f08c3bdfSopenharmony_cistatic void set_up_arch_entry(struct entrypoint *ep, struct instruction *entry)
1806f08c3bdfSopenharmony_ci{
1807f08c3bdfSopenharmony_ci	pseudo_t arg;
1808f08c3bdfSopenharmony_ci	struct symbol *sym, *argtype;
1809f08c3bdfSopenharmony_ci	int i, offset, regparm;
1810f08c3bdfSopenharmony_ci
1811f08c3bdfSopenharmony_ci	sym = ep->name;
1812f08c3bdfSopenharmony_ci	regparm = 0;
1813f08c3bdfSopenharmony_ci	if (!(sym->ctype.modifiers & MOD_ADDRESSABLE))
1814f08c3bdfSopenharmony_ci		regparm = 3;
1815f08c3bdfSopenharmony_ci	sym = sym->ctype.base_type;
1816f08c3bdfSopenharmony_ci	i = 0;
1817f08c3bdfSopenharmony_ci	offset = 0;
1818f08c3bdfSopenharmony_ci	PREPARE_PTR_LIST(sym->arguments, argtype);
1819f08c3bdfSopenharmony_ci	FOR_EACH_PTR(entry->arg_list, arg) {
1820f08c3bdfSopenharmony_ci		struct storage *in = lookup_storage(entry->bb, arg, STOR_IN);
1821f08c3bdfSopenharmony_ci		if (!in) {
1822f08c3bdfSopenharmony_ci			in = alloc_storage();
1823f08c3bdfSopenharmony_ci			add_storage(in, entry->bb, arg, STOR_IN);
1824f08c3bdfSopenharmony_ci		}
1825f08c3bdfSopenharmony_ci		if (i < regparm) {
1826f08c3bdfSopenharmony_ci			in->type = REG_REG;
1827f08c3bdfSopenharmony_ci			in->regno = i;
1828f08c3bdfSopenharmony_ci		} else {
1829f08c3bdfSopenharmony_ci			int bits = argtype ? argtype->bit_size : 0;
1830f08c3bdfSopenharmony_ci
1831f08c3bdfSopenharmony_ci			if (bits < bits_in_int)
1832f08c3bdfSopenharmony_ci				bits = bits_in_int;
1833f08c3bdfSopenharmony_ci
1834f08c3bdfSopenharmony_ci			in->type = REG_FRAME;
1835f08c3bdfSopenharmony_ci			in->offset = offset;
1836f08c3bdfSopenharmony_ci
1837f08c3bdfSopenharmony_ci			offset += bits_to_bytes(bits);
1838f08c3bdfSopenharmony_ci		}
1839f08c3bdfSopenharmony_ci		i++;
1840f08c3bdfSopenharmony_ci		NEXT_PTR_LIST(argtype);
1841f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(arg);
1842f08c3bdfSopenharmony_ci	FINISH_PTR_LIST(argtype);
1843f08c3bdfSopenharmony_ci}
1844f08c3bdfSopenharmony_ci
1845f08c3bdfSopenharmony_ci/*
1846f08c3bdfSopenharmony_ci * Set up storage information for "return"
1847f08c3bdfSopenharmony_ci *
1848f08c3bdfSopenharmony_ci * Not strictly necessary, since the code generator will
1849f08c3bdfSopenharmony_ci * certainly move the return value to the right register,
1850f08c3bdfSopenharmony_ci * but it can help register allocation if the allocator
1851f08c3bdfSopenharmony_ci * sees that the target register is going to return in %eax.
1852f08c3bdfSopenharmony_ci */
1853f08c3bdfSopenharmony_cistatic void set_up_arch_exit(struct basic_block *bb, struct instruction *ret)
1854f08c3bdfSopenharmony_ci{
1855f08c3bdfSopenharmony_ci	pseudo_t pseudo = ret->src;
1856f08c3bdfSopenharmony_ci
1857f08c3bdfSopenharmony_ci	if (pseudo && pseudo != VOID) {
1858f08c3bdfSopenharmony_ci		struct storage *out = lookup_storage(bb, pseudo, STOR_OUT);
1859f08c3bdfSopenharmony_ci		if (!out) {
1860f08c3bdfSopenharmony_ci			out = alloc_storage();
1861f08c3bdfSopenharmony_ci			add_storage(out, bb, pseudo, STOR_OUT);
1862f08c3bdfSopenharmony_ci		}
1863f08c3bdfSopenharmony_ci		out->type = REG_REG;
1864f08c3bdfSopenharmony_ci		out->regno = 0;
1865f08c3bdfSopenharmony_ci	}
1866f08c3bdfSopenharmony_ci}
1867f08c3bdfSopenharmony_ci
1868f08c3bdfSopenharmony_ci/*
1869f08c3bdfSopenharmony_ci * Set up dummy/silly output storage information for a switch
1870f08c3bdfSopenharmony_ci * instruction. We need to make sure that a register is available
1871f08c3bdfSopenharmony_ci * when we generate code for switch, so force that by creating
1872f08c3bdfSopenharmony_ci * a dummy output rule.
1873f08c3bdfSopenharmony_ci */
1874f08c3bdfSopenharmony_cistatic void set_up_arch_switch(struct basic_block *bb, struct instruction *insn)
1875f08c3bdfSopenharmony_ci{
1876f08c3bdfSopenharmony_ci	pseudo_t pseudo = insn->cond;
1877f08c3bdfSopenharmony_ci	struct storage *out = lookup_storage(bb, pseudo, STOR_OUT);
1878f08c3bdfSopenharmony_ci	if (!out) {
1879f08c3bdfSopenharmony_ci		out = alloc_storage();
1880f08c3bdfSopenharmony_ci		add_storage(out, bb, pseudo, STOR_OUT);
1881f08c3bdfSopenharmony_ci	}
1882f08c3bdfSopenharmony_ci	out->type = REG_REG;
1883f08c3bdfSopenharmony_ci	out->regno = SWITCH_REG;
1884f08c3bdfSopenharmony_ci}
1885f08c3bdfSopenharmony_ci
1886f08c3bdfSopenharmony_cistatic void arch_set_up_storage(struct entrypoint *ep)
1887f08c3bdfSopenharmony_ci{
1888f08c3bdfSopenharmony_ci	struct basic_block *bb;
1889f08c3bdfSopenharmony_ci
1890f08c3bdfSopenharmony_ci	/* Argument storage etc.. */
1891f08c3bdfSopenharmony_ci	set_up_arch_entry(ep, ep->entry);
1892f08c3bdfSopenharmony_ci
1893f08c3bdfSopenharmony_ci	FOR_EACH_PTR(ep->bbs, bb) {
1894f08c3bdfSopenharmony_ci		struct instruction *insn = last_instruction(bb->insns);
1895f08c3bdfSopenharmony_ci		if (!insn)
1896f08c3bdfSopenharmony_ci			continue;
1897f08c3bdfSopenharmony_ci		switch (insn->opcode) {
1898f08c3bdfSopenharmony_ci		case OP_RET:
1899f08c3bdfSopenharmony_ci			set_up_arch_exit(bb, insn);
1900f08c3bdfSopenharmony_ci			break;
1901f08c3bdfSopenharmony_ci		case OP_SWITCH:
1902f08c3bdfSopenharmony_ci			set_up_arch_switch(bb, insn);
1903f08c3bdfSopenharmony_ci			break;
1904f08c3bdfSopenharmony_ci		default:
1905f08c3bdfSopenharmony_ci			/* nothing */;
1906f08c3bdfSopenharmony_ci		}
1907f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(bb);
1908f08c3bdfSopenharmony_ci}
1909f08c3bdfSopenharmony_ci
1910f08c3bdfSopenharmony_cistatic void output(struct entrypoint *ep)
1911f08c3bdfSopenharmony_ci{
1912f08c3bdfSopenharmony_ci	unsigned long generation = ++bb_generation;
1913f08c3bdfSopenharmony_ci
1914f08c3bdfSopenharmony_ci	last_reg = -1;
1915f08c3bdfSopenharmony_ci	stack_offset = 0;
1916f08c3bdfSopenharmony_ci
1917f08c3bdfSopenharmony_ci	/* Get rid of SSA form (phinodes etc) */
1918f08c3bdfSopenharmony_ci	unssa(ep);
1919f08c3bdfSopenharmony_ci
1920f08c3bdfSopenharmony_ci	/* Set up initial inter-bb storage links */
1921f08c3bdfSopenharmony_ci	set_up_storage(ep);
1922f08c3bdfSopenharmony_ci
1923f08c3bdfSopenharmony_ci	/* Architecture-specific storage rules.. */
1924f08c3bdfSopenharmony_ci	arch_set_up_storage(ep);
1925f08c3bdfSopenharmony_ci
1926f08c3bdfSopenharmony_ci	/* Show the results ... */
1927f08c3bdfSopenharmony_ci	output_bb(ep->entry->bb, generation);
1928f08c3bdfSopenharmony_ci
1929f08c3bdfSopenharmony_ci	/* Clear the storage hashes for the next function.. */
1930f08c3bdfSopenharmony_ci	free_storage();
1931f08c3bdfSopenharmony_ci}
1932f08c3bdfSopenharmony_ci
1933f08c3bdfSopenharmony_cistatic int compile(struct symbol_list *list)
1934f08c3bdfSopenharmony_ci{
1935f08c3bdfSopenharmony_ci	struct symbol *sym;
1936f08c3bdfSopenharmony_ci	FOR_EACH_PTR(list, sym) {
1937f08c3bdfSopenharmony_ci		struct entrypoint *ep;
1938f08c3bdfSopenharmony_ci		expand_symbol(sym);
1939f08c3bdfSopenharmony_ci		ep = linearize_symbol(sym);
1940f08c3bdfSopenharmony_ci		if (ep)
1941f08c3bdfSopenharmony_ci			output(ep);
1942f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(sym);
1943f08c3bdfSopenharmony_ci
1944f08c3bdfSopenharmony_ci	return 0;
1945f08c3bdfSopenharmony_ci}
1946f08c3bdfSopenharmony_ci
1947f08c3bdfSopenharmony_ciint main(int argc, char **argv)
1948f08c3bdfSopenharmony_ci{
1949f08c3bdfSopenharmony_ci	struct string_list *filelist = NULL;
1950f08c3bdfSopenharmony_ci	char *file;
1951f08c3bdfSopenharmony_ci
1952f08c3bdfSopenharmony_ci	compile(sparse_initialize(argc, argv, &filelist));
1953f08c3bdfSopenharmony_ci	dbg_dead = 1;
1954f08c3bdfSopenharmony_ci	FOR_EACH_PTR(filelist, file) {
1955f08c3bdfSopenharmony_ci		compile(sparse(file));
1956f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(file);
1957f08c3bdfSopenharmony_ci	return 0;
1958f08c3bdfSopenharmony_ci}
1959f08c3bdfSopenharmony_ci
1960