xref: /illumos-gate/usr/src/tools/smatch/src/example.c (revision c85f09cc)
11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Example of how to write a compiler with sparse
31f5207b7SJohn Levon  */
41f5207b7SJohn Levon #include <stdio.h>
51f5207b7SJohn Levon #include <stdlib.h>
61f5207b7SJohn Levon #include <stdarg.h>
71f5207b7SJohn Levon #include <string.h>
81f5207b7SJohn Levon #include <assert.h>
91f5207b7SJohn Levon 
101f5207b7SJohn Levon #include "symbol.h"
111f5207b7SJohn Levon #include "expression.h"
121f5207b7SJohn Levon #include "linearize.h"
131f5207b7SJohn Levon #include "flow.h"
141f5207b7SJohn Levon #include "storage.h"
151f5207b7SJohn Levon #include "target.h"
161f5207b7SJohn Levon 
171f5207b7SJohn Levon static const char *opcodes[] = {
181f5207b7SJohn Levon 	[OP_BADOP] = "bad_op",
191f5207b7SJohn Levon 
201f5207b7SJohn Levon 	/* Fn entrypoint */
211f5207b7SJohn Levon 	[OP_ENTRY] = "<entry-point>",
221f5207b7SJohn Levon 
231f5207b7SJohn Levon 	/* Terminator */
241f5207b7SJohn Levon 	[OP_RET] = "ret",
251f5207b7SJohn Levon 	[OP_BR] = "br",
261f5207b7SJohn Levon 	[OP_CBR] = "cbr",
271f5207b7SJohn Levon 	[OP_SWITCH] = "switch",
281f5207b7SJohn Levon 	[OP_COMPUTEDGOTO] = "jmp *",
291f5207b7SJohn Levon 
301f5207b7SJohn Levon 	/* Binary */
311f5207b7SJohn Levon 	[OP_ADD] = "add",
321f5207b7SJohn Levon 	[OP_SUB] = "sub",
33*c85f09ccSJohn Levon 	[OP_MUL] = "mul",
341f5207b7SJohn Levon 	[OP_DIVU] = "divu",
351f5207b7SJohn Levon 	[OP_DIVS] = "divs",
361f5207b7SJohn Levon 	[OP_MODU] = "modu",
371f5207b7SJohn Levon 	[OP_MODS] = "mods",
381f5207b7SJohn Levon 	[OP_SHL] = "shl",
391f5207b7SJohn Levon 	[OP_LSR] = "lsr",
401f5207b7SJohn Levon 	[OP_ASR] = "asr",
411f5207b7SJohn Levon 
421f5207b7SJohn Levon 	/* Logical */
431f5207b7SJohn Levon 	[OP_AND] = "and",
441f5207b7SJohn Levon 	[OP_OR] = "or",
451f5207b7SJohn Levon 	[OP_XOR] = "xor",
461f5207b7SJohn Levon 
471f5207b7SJohn Levon 	/* Binary comparison */
481f5207b7SJohn Levon 	[OP_SET_EQ] = "seteq",
491f5207b7SJohn Levon 	[OP_SET_NE] = "setne",
501f5207b7SJohn Levon 	[OP_SET_LE] = "setle",
511f5207b7SJohn Levon 	[OP_SET_GE] = "setge",
521f5207b7SJohn Levon 	[OP_SET_LT] = "setlt",
531f5207b7SJohn Levon 	[OP_SET_GT] = "setgt",
541f5207b7SJohn Levon 	[OP_SET_B] = "setb",
551f5207b7SJohn Levon 	[OP_SET_A] = "seta",
561f5207b7SJohn Levon 	[OP_SET_BE] = "setbe",
571f5207b7SJohn Levon 	[OP_SET_AE] = "setae",
581f5207b7SJohn Levon 
591f5207b7SJohn Levon 	/* Uni */
601f5207b7SJohn Levon 	[OP_NOT] = "not",
611f5207b7SJohn Levon 	[OP_NEG] = "neg",
621f5207b7SJohn Levon 
631f5207b7SJohn Levon 	/* Special three-input */
641f5207b7SJohn Levon 	[OP_SEL] = "select",
651f5207b7SJohn Levon 
661f5207b7SJohn Levon 	/* Memory */
671f5207b7SJohn Levon 	[OP_LOAD] = "load",
681f5207b7SJohn Levon 	[OP_STORE] = "store",
691f5207b7SJohn Levon 	[OP_SETVAL] = "set",
701f5207b7SJohn Levon 
711f5207b7SJohn Levon 	/* Other */
721f5207b7SJohn Levon 	[OP_PHI] = "phi",
731f5207b7SJohn Levon 	[OP_PHISOURCE] = "phisrc",
741f5207b7SJohn Levon 	[OP_COPY] = "copy",
75*c85f09ccSJohn Levon 	[OP_SEXT] = "sext",
76*c85f09ccSJohn Levon 	[OP_ZEXT] = "zext",
77*c85f09ccSJohn Levon 	[OP_TRUNC] = "trunc",
78*c85f09ccSJohn Levon 	[OP_FCVTU] = "fcvtu",
79*c85f09ccSJohn Levon 	[OP_FCVTS] = "fcvts",
80*c85f09ccSJohn Levon 	[OP_UCVTF] = "ucvtf",
81*c85f09ccSJohn Levon 	[OP_SCVTF] = "scvtf",
82*c85f09ccSJohn Levon 	[OP_FCVTF] = "fcvtf",
83*c85f09ccSJohn Levon 	[OP_UTPTR] = "utptr",
84*c85f09ccSJohn Levon 	[OP_PTRTU] = "utptr",
851f5207b7SJohn Levon 	[OP_PTRCAST] = "ptrcast",
861f5207b7SJohn Levon 	[OP_CALL] = "call",
871f5207b7SJohn Levon 	[OP_SLICE] = "slice",
881f5207b7SJohn Levon 	[OP_NOP] = "nop",
891f5207b7SJohn Levon 	[OP_DEATHNOTE] = "dead",
901f5207b7SJohn Levon 	[OP_ASM] = "asm",
911f5207b7SJohn Levon 
921f5207b7SJohn Levon 	/* Sparse tagging (line numbers, context, whatever) */
931f5207b7SJohn Levon 	[OP_CONTEXT] = "context",
941f5207b7SJohn Levon };
951f5207b7SJohn Levon 
961f5207b7SJohn Levon static int last_reg, stack_offset;
971f5207b7SJohn Levon 
981f5207b7SJohn Levon struct hardreg {
991f5207b7SJohn Levon 	const char *name;
1001f5207b7SJohn Levon 	struct pseudo_list *contains;
1011f5207b7SJohn Levon 	unsigned busy:16,
1021f5207b7SJohn Levon 		 dead:8,
1031f5207b7SJohn Levon 		 used:1;
1041f5207b7SJohn Levon };
1051f5207b7SJohn Levon 
1061f5207b7SJohn Levon #define TAG_DEAD 1
1071f5207b7SJohn Levon #define TAG_DIRTY 2
1081f5207b7SJohn Levon 
1091f5207b7SJohn Levon /* Our "switch" generation is very very stupid. */
1101f5207b7SJohn Levon #define SWITCH_REG (1)
1111f5207b7SJohn Levon 
1121f5207b7SJohn Levon static void output_bb(struct basic_block *bb, unsigned long generation);
1131f5207b7SJohn Levon 
1141f5207b7SJohn Levon /*
1151f5207b7SJohn Levon  * We only know about the caller-clobbered registers
1161f5207b7SJohn Levon  * right now.
1171f5207b7SJohn Levon  */
1181f5207b7SJohn Levon static struct hardreg hardregs[] = {
1191f5207b7SJohn Levon 	{ .name = "%eax" },
1201f5207b7SJohn Levon 	{ .name = "%edx" },
1211f5207b7SJohn Levon 	{ .name = "%ecx" },
1221f5207b7SJohn Levon 	{ .name = "%ebx" },
1231f5207b7SJohn Levon 	{ .name = "%esi" },
1241f5207b7SJohn Levon 	{ .name = "%edi" },
1251f5207b7SJohn Levon 
1261f5207b7SJohn Levon 	{ .name = "%ebp" },
1271f5207b7SJohn Levon 	{ .name = "%esp" },
1281f5207b7SJohn Levon };
1291f5207b7SJohn Levon #define REGNO 6
1301f5207b7SJohn Levon #define REG_EBP 6
1311f5207b7SJohn Levon #define REG_ESP 7
1321f5207b7SJohn Levon 
1331f5207b7SJohn Levon struct bb_state {
1341f5207b7SJohn Levon 	struct position pos;
1351f5207b7SJohn Levon 	struct storage_hash_list *inputs;
1361f5207b7SJohn Levon 	struct storage_hash_list *outputs;
1371f5207b7SJohn Levon 	struct storage_hash_list *internal;
1381f5207b7SJohn Levon 
1391f5207b7SJohn Levon 	/* CC cache.. */
1401f5207b7SJohn Levon 	int cc_opcode, cc_dead;
1411f5207b7SJohn Levon 	pseudo_t cc_target;
1421f5207b7SJohn Levon };
1431f5207b7SJohn Levon 
1441f5207b7SJohn Levon enum optype {
1451f5207b7SJohn Levon 	OP_UNDEF,
1461f5207b7SJohn Levon 	OP_REG,
1471f5207b7SJohn Levon 	OP_VAL,
1481f5207b7SJohn Levon 	OP_MEM,
1491f5207b7SJohn Levon 	OP_ADDR,
1501f5207b7SJohn Levon };
1511f5207b7SJohn Levon 
1521f5207b7SJohn Levon struct operand {
1531f5207b7SJohn Levon 	enum optype type;
1541f5207b7SJohn Levon 	int size;
1551f5207b7SJohn Levon 	union {
1561f5207b7SJohn Levon 		struct hardreg *reg;
1571f5207b7SJohn Levon 		long long value;
1581f5207b7SJohn Levon 		struct /* OP_MEM and OP_ADDR */ {
1591f5207b7SJohn Levon 			unsigned int offset;
1601f5207b7SJohn Levon 			unsigned int scale;
1611f5207b7SJohn Levon 			struct symbol *sym;
1621f5207b7SJohn Levon 			struct hardreg *base;
1631f5207b7SJohn Levon 			struct hardreg *index;
1641f5207b7SJohn Levon 		};
1651f5207b7SJohn Levon 	};
1661f5207b7SJohn Levon };
1671f5207b7SJohn Levon 
show_op(struct bb_state * state,struct operand * op)1681f5207b7SJohn Levon static const char *show_op(struct bb_state *state, struct operand *op)
1691f5207b7SJohn Levon {
1701f5207b7SJohn Levon 	static char buf[256][4];
1711f5207b7SJohn Levon 	static int bufnr;
1721f5207b7SJohn Levon 	char *p, *ret;
1731f5207b7SJohn Levon 	int nr;
1741f5207b7SJohn Levon 
1751f5207b7SJohn Levon 	nr = (bufnr + 1) & 3;
1761f5207b7SJohn Levon 	bufnr = nr;
1771f5207b7SJohn Levon 	ret = p = buf[nr];
1781f5207b7SJohn Levon 
1791f5207b7SJohn Levon 	switch (op->type) {
1801f5207b7SJohn Levon 	case OP_UNDEF:
1811f5207b7SJohn Levon 		return "undef";
1821f5207b7SJohn Levon 	case OP_REG:
1831f5207b7SJohn Levon 		return op->reg->name;
1841f5207b7SJohn Levon 	case OP_VAL:
1851f5207b7SJohn Levon 		sprintf(p, "$%lld", op->value);
1861f5207b7SJohn Levon 		break;
1871f5207b7SJohn Levon 	case OP_MEM:
1881f5207b7SJohn Levon 	case OP_ADDR:
1891f5207b7SJohn Levon 		if (op->offset)
1901f5207b7SJohn Levon 			p += sprintf(p, "%d", op->offset);
1911f5207b7SJohn Levon 		if (op->sym)
1921f5207b7SJohn Levon 			p += sprintf(p, "%s%s",
1931f5207b7SJohn Levon 				op->offset ? "+" : "",
1941f5207b7SJohn Levon 				show_ident(op->sym->ident));
1951f5207b7SJohn Levon 		if (op->base || op->index) {
1961f5207b7SJohn Levon 			p += sprintf(p, "(%s%s%s",
1971f5207b7SJohn Levon 				op->base ? op->base->name : "",
1981f5207b7SJohn Levon 				(op->base && op->index) ? "," : "",
1991f5207b7SJohn Levon 				op->index ? op->index->name : "");
2001f5207b7SJohn Levon 			if (op->scale > 1)
2011f5207b7SJohn Levon 				p += sprintf(p, ",%d", op->scale);
2021f5207b7SJohn Levon 			*p++ = ')';
2031f5207b7SJohn Levon 			*p = '\0';
2041f5207b7SJohn Levon 		}
2051f5207b7SJohn Levon 		break;
2061f5207b7SJohn Levon 	}
2071f5207b7SJohn Levon 	return ret;
2081f5207b7SJohn Levon }
2091f5207b7SJohn Levon 
find_storage_hash(pseudo_t pseudo,struct storage_hash_list * list)2101f5207b7SJohn Levon static struct storage_hash *find_storage_hash(pseudo_t pseudo, struct storage_hash_list *list)
2111f5207b7SJohn Levon {
2121f5207b7SJohn Levon 	struct storage_hash *entry;
2131f5207b7SJohn Levon 	FOR_EACH_PTR(list, entry) {
2141f5207b7SJohn Levon 		if (entry->pseudo == pseudo)
2151f5207b7SJohn Levon 			return entry;
2161f5207b7SJohn Levon 	} END_FOR_EACH_PTR(entry);
2171f5207b7SJohn Levon 	return NULL;
2181f5207b7SJohn Levon }
2191f5207b7SJohn Levon 
find_or_create_hash(pseudo_t pseudo,struct storage_hash_list ** listp)2201f5207b7SJohn Levon static struct storage_hash *find_or_create_hash(pseudo_t pseudo, struct storage_hash_list **listp)
2211f5207b7SJohn Levon {
2221f5207b7SJohn Levon 	struct storage_hash *entry;
2231f5207b7SJohn Levon 
2241f5207b7SJohn Levon 	entry = find_storage_hash(pseudo, *listp);
2251f5207b7SJohn Levon 	if (!entry) {
2261f5207b7SJohn Levon 		entry = alloc_storage_hash(alloc_storage());
2271f5207b7SJohn Levon 		entry->pseudo = pseudo;
2281f5207b7SJohn Levon 		add_ptr_list(listp, entry);
2291f5207b7SJohn Levon 	}
2301f5207b7SJohn Levon 	return entry;
2311f5207b7SJohn Levon }
2321f5207b7SJohn Levon 
2331f5207b7SJohn Levon /* Eventually we should just build it up in memory */
output_line(struct bb_state * state,const char * fmt,...)2341f5207b7SJohn Levon static void FORMAT_ATTR(2) output_line(struct bb_state *state, const char *fmt, ...)
2351f5207b7SJohn Levon {
2361f5207b7SJohn Levon 	va_list args;
2371f5207b7SJohn Levon 
2381f5207b7SJohn Levon 	va_start(args, fmt);
2391f5207b7SJohn Levon 	vprintf(fmt, args);
2401f5207b7SJohn Levon 	va_end(args);
2411f5207b7SJohn Levon }
2421f5207b7SJohn Levon 
output_label(struct bb_state * state,const char * fmt,...)2431f5207b7SJohn Levon static void FORMAT_ATTR(2) output_label(struct bb_state *state, const char *fmt, ...)
2441f5207b7SJohn Levon {
2451f5207b7SJohn Levon 	static char buffer[512];
2461f5207b7SJohn Levon 	va_list args;
2471f5207b7SJohn Levon 
2481f5207b7SJohn Levon 	va_start(args, fmt);
2491f5207b7SJohn Levon 	vsnprintf(buffer, sizeof(buffer), fmt, args);
2501f5207b7SJohn Levon 	va_end(args);
2511f5207b7SJohn Levon 
2521f5207b7SJohn Levon 	output_line(state, "%s:\n", buffer);
2531f5207b7SJohn Levon }
2541f5207b7SJohn Levon 
output_insn(struct bb_state * state,const char * fmt,...)2551f5207b7SJohn Levon static void FORMAT_ATTR(2) output_insn(struct bb_state *state, const char *fmt, ...)
2561f5207b7SJohn Levon {
2571f5207b7SJohn Levon 	static char buffer[512];
2581f5207b7SJohn Levon 	va_list args;
2591f5207b7SJohn Levon 
2601f5207b7SJohn Levon 	va_start(args, fmt);
2611f5207b7SJohn Levon 	vsnprintf(buffer, sizeof(buffer), fmt, args);
2621f5207b7SJohn Levon 	va_end(args);
2631f5207b7SJohn Levon 
2641f5207b7SJohn Levon 	output_line(state, "\t%s\n", buffer);
2651f5207b7SJohn Levon }
2661f5207b7SJohn Levon 
2671f5207b7SJohn Levon #define output_insn(state, fmt, arg...) \
2681f5207b7SJohn Levon 	output_insn(state, fmt "\t\t# %s" , ## arg , __FUNCTION__)
2691f5207b7SJohn Levon 
output_comment(struct bb_state * state,const char * fmt,...)2701f5207b7SJohn Levon static void FORMAT_ATTR(2) output_comment(struct bb_state *state, const char *fmt, ...)
2711f5207b7SJohn Levon {
2721f5207b7SJohn Levon 	static char buffer[512];
2731f5207b7SJohn Levon 	va_list args;
2741f5207b7SJohn Levon 
2751f5207b7SJohn Levon 	if (!verbose)
2761f5207b7SJohn Levon 		return;
2771f5207b7SJohn Levon 	va_start(args, fmt);
2781f5207b7SJohn Levon 	vsnprintf(buffer, sizeof(buffer), fmt, args);
2791f5207b7SJohn Levon 	va_end(args);
2801f5207b7SJohn Levon 
2811f5207b7SJohn Levon 	output_line(state, "\t# %s\n", buffer);
2821f5207b7SJohn Levon }
2831f5207b7SJohn Levon 
show_memop(struct storage * storage)2841f5207b7SJohn Levon static const char *show_memop(struct storage *storage)
2851f5207b7SJohn Levon {
2861f5207b7SJohn Levon 	static char buffer[1000];
2871f5207b7SJohn Levon 
2881f5207b7SJohn Levon 	if (!storage)
2891f5207b7SJohn Levon 		return "undef";
2901f5207b7SJohn Levon 	switch (storage->type) {
2911f5207b7SJohn Levon 	case REG_FRAME:
2921f5207b7SJohn Levon 		sprintf(buffer, "%d(FP)", storage->offset);
2931f5207b7SJohn Levon 		break;
2941f5207b7SJohn Levon 	case REG_STACK:
2951f5207b7SJohn Levon 		sprintf(buffer, "%d(SP)", storage->offset);
2961f5207b7SJohn Levon 		break;
2971f5207b7SJohn Levon 	case REG_REG:
2981f5207b7SJohn Levon 		return hardregs[storage->regno].name;
2991f5207b7SJohn Levon 	default:
3001f5207b7SJohn Levon 		return show_storage(storage);
3011f5207b7SJohn Levon 	}
3021f5207b7SJohn Levon 	return buffer;
3031f5207b7SJohn Levon }
3041f5207b7SJohn Levon 
alloc_stack_offset(int size)3051f5207b7SJohn Levon static int alloc_stack_offset(int size)
3061f5207b7SJohn Levon {
3071f5207b7SJohn Levon 	int ret = stack_offset;
3081f5207b7SJohn Levon 	stack_offset = ret + size;
3091f5207b7SJohn Levon 	return ret;
3101f5207b7SJohn Levon }
3111f5207b7SJohn Levon 
alloc_stack(struct bb_state * state,struct storage * storage)3121f5207b7SJohn Levon static void alloc_stack(struct bb_state *state, struct storage *storage)
3131f5207b7SJohn Levon {
3141f5207b7SJohn Levon 	storage->type = REG_STACK;
3151f5207b7SJohn Levon 	storage->offset = alloc_stack_offset(4);
3161f5207b7SJohn Levon }
3171f5207b7SJohn Levon 
3181f5207b7SJohn Levon /*
3191f5207b7SJohn Levon  * Can we re-generate the pseudo, so that we don't need to
3201f5207b7SJohn Levon  * flush it to memory? We can regenerate:
3211f5207b7SJohn Levon  *  - immediates and symbol addresses
3221f5207b7SJohn Levon  *  - pseudos we got as input in non-registers
3231f5207b7SJohn Levon  *  - pseudos we've already saved off earlier..
3241f5207b7SJohn Levon  */
can_regenerate(struct bb_state * state,pseudo_t pseudo)3251f5207b7SJohn Levon static int can_regenerate(struct bb_state *state, pseudo_t pseudo)
3261f5207b7SJohn Levon {
3271f5207b7SJohn Levon 	struct storage_hash *in;
3281f5207b7SJohn Levon 
3291f5207b7SJohn Levon 	switch (pseudo->type) {
3301f5207b7SJohn Levon 	case PSEUDO_VAL:
3311f5207b7SJohn Levon 	case PSEUDO_SYM:
3321f5207b7SJohn Levon 		return 1;
3331f5207b7SJohn Levon 
3341f5207b7SJohn Levon 	default:
3351f5207b7SJohn Levon 		in = find_storage_hash(pseudo, state->inputs);
3361f5207b7SJohn Levon 		if (in && in->storage->type != REG_REG)
3371f5207b7SJohn Levon 			return 1;
3381f5207b7SJohn Levon 		in = find_storage_hash(pseudo, state->internal);
3391f5207b7SJohn Levon 		if (in)
3401f5207b7SJohn Levon 			return 1;
3411f5207b7SJohn Levon 	}
3421f5207b7SJohn Levon 	return 0;
3431f5207b7SJohn Levon }
3441f5207b7SJohn Levon 
flush_one_pseudo(struct bb_state * state,struct hardreg * hardreg,pseudo_t pseudo)3451f5207b7SJohn Levon static void flush_one_pseudo(struct bb_state *state, struct hardreg *hardreg, pseudo_t pseudo)
3461f5207b7SJohn Levon {
3471f5207b7SJohn Levon 	struct storage_hash *out;
3481f5207b7SJohn Levon 	struct storage *storage;
3491f5207b7SJohn Levon 
3501f5207b7SJohn Levon 	if (can_regenerate(state, pseudo))
3511f5207b7SJohn Levon 		return;
3521f5207b7SJohn Levon 
3531f5207b7SJohn Levon 	output_comment(state, "flushing %s from %s", show_pseudo(pseudo), hardreg->name);
3541f5207b7SJohn Levon 	out = find_storage_hash(pseudo, state->internal);
3551f5207b7SJohn Levon 	if (!out) {
3561f5207b7SJohn Levon 		out = find_storage_hash(pseudo, state->outputs);
3571f5207b7SJohn Levon 		if (!out)
3581f5207b7SJohn Levon 			out = find_or_create_hash(pseudo, &state->internal);
3591f5207b7SJohn Levon 	}
3601f5207b7SJohn Levon 	storage = out->storage;
3611f5207b7SJohn Levon 	switch (storage->type) {
3621f5207b7SJohn Levon 	default:
3631f5207b7SJohn Levon 		/*
3641f5207b7SJohn Levon 		 * Aieee - the next user wants it in a register, but we
3651f5207b7SJohn Levon 		 * need to flush it to memory in between. Which means that
3661f5207b7SJohn Levon 		 * we need to allocate an internal one, dammit..
3671f5207b7SJohn Levon 		 */
3681f5207b7SJohn Levon 		out = find_or_create_hash(pseudo, &state->internal);
3691f5207b7SJohn Levon 		storage = out->storage;
3701f5207b7SJohn Levon 		/* Fall through */
3711f5207b7SJohn Levon 	case REG_UDEF:
3721f5207b7SJohn Levon 		alloc_stack(state, storage);
3731f5207b7SJohn Levon 		/* Fall through */
3741f5207b7SJohn Levon 	case REG_STACK:
3751f5207b7SJohn Levon 		output_insn(state, "movl %s,%s", hardreg->name, show_memop(storage));
3761f5207b7SJohn Levon 		break;
3771f5207b7SJohn Levon 	}
3781f5207b7SJohn Levon }
3791f5207b7SJohn Levon 
3801f5207b7SJohn Levon /* Flush a hardreg out to the storage it has.. */
flush_reg(struct bb_state * state,struct hardreg * reg)3811f5207b7SJohn Levon static void flush_reg(struct bb_state *state, struct hardreg *reg)
3821f5207b7SJohn Levon {
3831f5207b7SJohn Levon 	pseudo_t pseudo;
3841f5207b7SJohn Levon 
3851f5207b7SJohn Levon 	if (reg->busy)
3861f5207b7SJohn Levon 		output_comment(state, "reg %s flushed while busy is %d!", reg->name, reg->busy);
3871f5207b7SJohn Levon 	if (!reg->contains)
3881f5207b7SJohn Levon 		return;
3891f5207b7SJohn Levon 	reg->dead = 0;
3901f5207b7SJohn Levon 	reg->used = 1;
391*c85f09ccSJohn Levon 	FOR_EACH_PTR_TAG(reg->contains, pseudo) {
3921f5207b7SJohn Levon 		if (CURRENT_TAG(pseudo) & TAG_DEAD)
3931f5207b7SJohn Levon 			continue;
3941f5207b7SJohn Levon 		if (!(CURRENT_TAG(pseudo) & TAG_DIRTY))
3951f5207b7SJohn Levon 			continue;
3961f5207b7SJohn Levon 		flush_one_pseudo(state, reg, pseudo);
3971f5207b7SJohn Levon 	} END_FOR_EACH_PTR(pseudo);
3981f5207b7SJohn Levon 	free_ptr_list(&reg->contains);
3991f5207b7SJohn Levon }
4001f5207b7SJohn Levon 
find_pseudo_storage(struct bb_state * state,pseudo_t pseudo,struct hardreg * reg)4011f5207b7SJohn Levon static struct storage_hash *find_pseudo_storage(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
4021f5207b7SJohn Levon {
4031f5207b7SJohn Levon 	struct storage_hash *src;
4041f5207b7SJohn Levon 
4051f5207b7SJohn Levon 	src = find_storage_hash(pseudo, state->internal);
4061f5207b7SJohn Levon 	if (!src) {
4071f5207b7SJohn Levon 		src = find_storage_hash(pseudo, state->inputs);
4081f5207b7SJohn Levon 		if (!src) {
4091f5207b7SJohn Levon 			src = find_storage_hash(pseudo, state->outputs);
4101f5207b7SJohn Levon 			/* Undefined? Screw it! */
4111f5207b7SJohn Levon 			if (!src)
4121f5207b7SJohn Levon 				return NULL;
4131f5207b7SJohn Levon 
4141f5207b7SJohn Levon 			/*
4151f5207b7SJohn Levon 			 * If we found output storage, it had better be local stack
4161f5207b7SJohn Levon 			 * that we flushed to earlier..
4171f5207b7SJohn Levon 			 */
4181f5207b7SJohn Levon 			if (src->storage->type != REG_STACK)
4191f5207b7SJohn Levon 				return NULL;
4201f5207b7SJohn Levon 		}
4211f5207b7SJohn Levon 	}
4221f5207b7SJohn Levon 
4231f5207b7SJohn Levon 	/*
4241f5207b7SJohn Levon 	 * Incoming pseudo with out any pre-set storage allocation?
4251f5207b7SJohn Levon 	 * We can make up our own, and obviously prefer to get it
4261f5207b7SJohn Levon 	 * in the register we already selected (if it hasn't been
4271f5207b7SJohn Levon 	 * used yet).
4281f5207b7SJohn Levon 	 */
4291f5207b7SJohn Levon 	if (src->storage->type == REG_UDEF) {
4301f5207b7SJohn Levon 		if (reg && !reg->used) {
4311f5207b7SJohn Levon 			src->storage->type = REG_REG;
4321f5207b7SJohn Levon 			src->storage->regno = reg - hardregs;
4331f5207b7SJohn Levon 			return NULL;
4341f5207b7SJohn Levon 		}
4351f5207b7SJohn Levon 		alloc_stack(state, src->storage);
4361f5207b7SJohn Levon 	}
4371f5207b7SJohn Levon 	return src;
4381f5207b7SJohn Levon }
4391f5207b7SJohn Levon 
mark_reg_dead(struct bb_state * state,pseudo_t pseudo,struct hardreg * reg)4401f5207b7SJohn Levon static void mark_reg_dead(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
4411f5207b7SJohn Levon {
4421f5207b7SJohn Levon 	pseudo_t p;
4431f5207b7SJohn Levon 
444*c85f09ccSJohn Levon 	FOR_EACH_PTR_TAG(reg->contains, p) {
4451f5207b7SJohn Levon 		if (p != pseudo)
4461f5207b7SJohn Levon 			continue;
4471f5207b7SJohn Levon 		if (CURRENT_TAG(p) & TAG_DEAD)
4481f5207b7SJohn Levon 			continue;
4491f5207b7SJohn Levon 		output_comment(state, "marking pseudo %s in reg %s dead", show_pseudo(pseudo), reg->name);
4501f5207b7SJohn Levon 		TAG_CURRENT(p, TAG_DEAD);
4511f5207b7SJohn Levon 		reg->dead++;
4521f5207b7SJohn Levon 	} END_FOR_EACH_PTR(p);
4531f5207b7SJohn Levon }
4541f5207b7SJohn Levon 
add_pseudo_reg(struct bb_state * state,pseudo_t pseudo,struct hardreg * reg)4551f5207b7SJohn Levon static void add_pseudo_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
4561f5207b7SJohn Levon {
4571f5207b7SJohn Levon 	output_comment(state, "added pseudo %s to reg %s", show_pseudo(pseudo), reg->name);
4581f5207b7SJohn Levon 	add_ptr_list_tag(&reg->contains, pseudo, TAG_DIRTY);
4591f5207b7SJohn Levon }
4601f5207b7SJohn Levon 
preferred_reg(struct bb_state * state,pseudo_t target)4611f5207b7SJohn Levon static struct hardreg *preferred_reg(struct bb_state *state, pseudo_t target)
4621f5207b7SJohn Levon {
4631f5207b7SJohn Levon 	struct storage_hash *dst;
4641f5207b7SJohn Levon 
4651f5207b7SJohn Levon 	dst = find_storage_hash(target, state->outputs);
4661f5207b7SJohn Levon 	if (dst) {
4671f5207b7SJohn Levon 		struct storage *storage = dst->storage;
4681f5207b7SJohn Levon 		if (storage->type == REG_REG)
4691f5207b7SJohn Levon 			return hardregs + storage->regno;
4701f5207b7SJohn Levon 	}
4711f5207b7SJohn Levon 	return NULL;
4721f5207b7SJohn Levon }
4731f5207b7SJohn Levon 
empty_reg(struct bb_state * state)4741f5207b7SJohn Levon static struct hardreg *empty_reg(struct bb_state *state)
4751f5207b7SJohn Levon {
4761f5207b7SJohn Levon 	int i;
4771f5207b7SJohn Levon 	struct hardreg *reg = hardregs;
4781f5207b7SJohn Levon 
4791f5207b7SJohn Levon 	for (i = 0; i < REGNO; i++, reg++) {
4801f5207b7SJohn Levon 		if (!reg->contains)
4811f5207b7SJohn Levon 			return reg;
4821f5207b7SJohn Levon 	}
4831f5207b7SJohn Levon 	return NULL;
4841f5207b7SJohn Levon }
4851f5207b7SJohn Levon 
target_reg(struct bb_state * state,pseudo_t pseudo,pseudo_t target)4861f5207b7SJohn Levon static struct hardreg *target_reg(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
4871f5207b7SJohn Levon {
4881f5207b7SJohn Levon 	int i;
4891f5207b7SJohn Levon 	int unable_to_find_reg = 0;
4901f5207b7SJohn Levon 	struct hardreg *reg;
4911f5207b7SJohn Levon 
4921f5207b7SJohn Levon 	/* First, see if we have a preferred target register.. */
4931f5207b7SJohn Levon 	reg = preferred_reg(state, target);
4941f5207b7SJohn Levon 	if (reg && !reg->contains)
4951f5207b7SJohn Levon 		goto found;
4961f5207b7SJohn Levon 
4971f5207b7SJohn Levon 	reg = empty_reg(state);
4981f5207b7SJohn Levon 	if (reg)
4991f5207b7SJohn Levon 		goto found;
5001f5207b7SJohn Levon 
5011f5207b7SJohn Levon 	i = last_reg;
5021f5207b7SJohn Levon 	do {
5031f5207b7SJohn Levon 		i++;
5041f5207b7SJohn Levon 		if (i >= REGNO)
5051f5207b7SJohn Levon 			i = 0;
5061f5207b7SJohn Levon 		reg = hardregs + i;
5071f5207b7SJohn Levon 		if (!reg->busy) {
5081f5207b7SJohn Levon 			flush_reg(state, reg);
5091f5207b7SJohn Levon 			last_reg = i;
5101f5207b7SJohn Levon 			goto found;
5111f5207b7SJohn Levon 		}
5121f5207b7SJohn Levon 	} while (i != last_reg);
5131f5207b7SJohn Levon 	assert(unable_to_find_reg);
5141f5207b7SJohn Levon 
5151f5207b7SJohn Levon found:
5161f5207b7SJohn Levon 	add_pseudo_reg(state, pseudo, reg);
5171f5207b7SJohn Levon 	return reg;
5181f5207b7SJohn Levon }
5191f5207b7SJohn Levon 
find_in_reg(struct bb_state * state,pseudo_t pseudo)5201f5207b7SJohn Levon static struct hardreg *find_in_reg(struct bb_state *state, pseudo_t pseudo)
5211f5207b7SJohn Levon {
5221f5207b7SJohn Levon 	int i;
5231f5207b7SJohn Levon 	struct hardreg *reg;
5241f5207b7SJohn Levon 
5251f5207b7SJohn Levon 	for (i = 0; i < REGNO; i++) {
5261f5207b7SJohn Levon 		pseudo_t p;
5271f5207b7SJohn Levon 
5281f5207b7SJohn Levon 		reg = hardregs + i;
529*c85f09ccSJohn Levon 		FOR_EACH_PTR_TAG(reg->contains, p) {
5301f5207b7SJohn Levon 			if (p == pseudo) {
5311f5207b7SJohn Levon 				last_reg = i;
5321f5207b7SJohn Levon 				output_comment(state, "found pseudo %s in reg %s (busy=%d)", show_pseudo(pseudo), reg->name, reg->busy);
5331f5207b7SJohn Levon 				return reg;
5341f5207b7SJohn Levon 			}
5351f5207b7SJohn Levon 		} END_FOR_EACH_PTR(p);
5361f5207b7SJohn Levon 	}
5371f5207b7SJohn Levon 	return NULL;
5381f5207b7SJohn Levon }
5391f5207b7SJohn Levon 
flush_pseudo(struct bb_state * state,pseudo_t pseudo,struct storage * storage)5401f5207b7SJohn Levon static void flush_pseudo(struct bb_state *state, pseudo_t pseudo, struct storage *storage)
5411f5207b7SJohn Levon {
5421f5207b7SJohn Levon 	struct hardreg *reg = find_in_reg(state, pseudo);
5431f5207b7SJohn Levon 
5441f5207b7SJohn Levon 	if (reg)
5451f5207b7SJohn Levon 		flush_reg(state, reg);
5461f5207b7SJohn Levon }
5471f5207b7SJohn Levon 
flush_cc_cache_to_reg(struct bb_state * state,pseudo_t pseudo,struct hardreg * reg)5481f5207b7SJohn Levon static void flush_cc_cache_to_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
5491f5207b7SJohn Levon {
5501f5207b7SJohn Levon 	int opcode = state->cc_opcode;
5511f5207b7SJohn Levon 
5521f5207b7SJohn Levon 	state->cc_opcode = 0;
5531f5207b7SJohn Levon 	state->cc_target = NULL;
5541f5207b7SJohn Levon 	output_insn(state, "%s %s", opcodes[opcode], reg->name);
5551f5207b7SJohn Levon }
5561f5207b7SJohn Levon 
flush_cc_cache(struct bb_state * state)5571f5207b7SJohn Levon static void flush_cc_cache(struct bb_state *state)
5581f5207b7SJohn Levon {
5591f5207b7SJohn Levon 	pseudo_t pseudo = state->cc_target;
5601f5207b7SJohn Levon 
5611f5207b7SJohn Levon 	if (pseudo) {
5621f5207b7SJohn Levon 		struct hardreg *dst;
5631f5207b7SJohn Levon 
5641f5207b7SJohn Levon 		state->cc_target = NULL;
5651f5207b7SJohn Levon 
5661f5207b7SJohn Levon 		if (!state->cc_dead) {
5671f5207b7SJohn Levon 			dst = target_reg(state, pseudo, pseudo);
5681f5207b7SJohn Levon 			flush_cc_cache_to_reg(state, pseudo, dst);
5691f5207b7SJohn Levon 		}
5701f5207b7SJohn Levon 	}
5711f5207b7SJohn Levon }
5721f5207b7SJohn Levon 
add_cc_cache(struct bb_state * state,int opcode,pseudo_t pseudo)5731f5207b7SJohn Levon static void add_cc_cache(struct bb_state *state, int opcode, pseudo_t pseudo)
5741f5207b7SJohn Levon {
5751f5207b7SJohn Levon 	assert(!state->cc_target);
5761f5207b7SJohn Levon 	state->cc_target = pseudo;
5771f5207b7SJohn Levon 	state->cc_opcode = opcode;
5781f5207b7SJohn Levon 	state->cc_dead = 0;
5791f5207b7SJohn Levon 	output_comment(state, "caching %s", opcodes[opcode]);
5801f5207b7SJohn Levon }
5811f5207b7SJohn Levon 
5821f5207b7SJohn Levon /* Fill a hardreg with the pseudo it has */
fill_reg(struct bb_state * state,struct hardreg * hardreg,pseudo_t pseudo)5831f5207b7SJohn Levon static struct hardreg *fill_reg(struct bb_state *state, struct hardreg *hardreg, pseudo_t pseudo)
5841f5207b7SJohn Levon {
5851f5207b7SJohn Levon 	struct storage_hash *src;
5861f5207b7SJohn Levon 	struct instruction *def;
5871f5207b7SJohn Levon 
5881f5207b7SJohn Levon 	if (state->cc_target == pseudo) {
5891f5207b7SJohn Levon 		flush_cc_cache_to_reg(state, pseudo, hardreg);
5901f5207b7SJohn Levon 		return hardreg;
5911f5207b7SJohn Levon 	}
5921f5207b7SJohn Levon 
5931f5207b7SJohn Levon 	switch (pseudo->type) {
5941f5207b7SJohn Levon 	case PSEUDO_VAL:
5951f5207b7SJohn Levon 		output_insn(state, "movl $%lld,%s", pseudo->value, hardreg->name);
5961f5207b7SJohn Levon 		break;
5971f5207b7SJohn Levon 	case PSEUDO_SYM:
5981f5207b7SJohn Levon 		src = find_pseudo_storage(state, pseudo, NULL);
5991f5207b7SJohn Levon 		/* Static thing? */
6001f5207b7SJohn Levon 		if (!src) {
6011f5207b7SJohn Levon 			output_insn(state, "movl $<%s>,%s", show_pseudo(pseudo), hardreg->name);
6021f5207b7SJohn Levon 			break;
6031f5207b7SJohn Levon 		}
6041f5207b7SJohn Levon 		switch (src->storage->type) {
6051f5207b7SJohn Levon 		case REG_REG:
6061f5207b7SJohn Levon 			/* Aiaiaiaiaii! Need to flush it to temporary memory */
6071f5207b7SJohn Levon 			src = find_or_create_hash(pseudo, &state->internal);
6081f5207b7SJohn Levon 			/* Fall through */
6091f5207b7SJohn Levon 		default:
6101f5207b7SJohn Levon 			alloc_stack(state, src->storage);
6111f5207b7SJohn Levon 			/* Fall through */
6121f5207b7SJohn Levon 		case REG_STACK:
6131f5207b7SJohn Levon 		case REG_FRAME:
6141f5207b7SJohn Levon 			flush_pseudo(state, pseudo, src->storage);
6151f5207b7SJohn Levon 			output_insn(state, "leal %s,%s", show_memop(src->storage), hardreg->name);
6161f5207b7SJohn Levon 			break;
6171f5207b7SJohn Levon 		}
6181f5207b7SJohn Levon 		break;
6191f5207b7SJohn Levon 	case PSEUDO_ARG:
6201f5207b7SJohn Levon 	case PSEUDO_REG:
6211f5207b7SJohn Levon 		def = pseudo->def;
6221f5207b7SJohn Levon 		if (def && def->opcode == OP_SETVAL) {
6231f5207b7SJohn Levon 			output_insn(state, "movl $<%s>,%s", show_pseudo(def->target), hardreg->name);
6241f5207b7SJohn Levon 			break;
6251f5207b7SJohn Levon 		}
6261f5207b7SJohn Levon 		src = find_pseudo_storage(state, pseudo, hardreg);
6271f5207b7SJohn Levon 		if (!src)
6281f5207b7SJohn Levon 			break;
6291f5207b7SJohn Levon 		if (src->flags & TAG_DEAD)
6301f5207b7SJohn Levon 			mark_reg_dead(state, pseudo, hardreg);
6311f5207b7SJohn Levon 		output_insn(state, "mov.%d %s,%s", 32, show_memop(src->storage), hardreg->name);
6321f5207b7SJohn Levon 		break;
6331f5207b7SJohn Levon 	default:
6341f5207b7SJohn Levon 		output_insn(state, "reload %s from %s", hardreg->name, show_pseudo(pseudo));
6351f5207b7SJohn Levon 		break;
6361f5207b7SJohn Levon 	}
6371f5207b7SJohn Levon 	return hardreg;
6381f5207b7SJohn Levon }
6391f5207b7SJohn Levon 
getreg(struct bb_state * state,pseudo_t pseudo,pseudo_t target)6401f5207b7SJohn Levon static struct hardreg *getreg(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
6411f5207b7SJohn Levon {
6421f5207b7SJohn Levon 	struct hardreg *reg;
6431f5207b7SJohn Levon 
6441f5207b7SJohn Levon 	reg = find_in_reg(state, pseudo);
6451f5207b7SJohn Levon 	if (reg)
6461f5207b7SJohn Levon 		return reg;
6471f5207b7SJohn Levon 	reg = target_reg(state, pseudo, target);
6481f5207b7SJohn Levon 	return fill_reg(state, reg, pseudo);
6491f5207b7SJohn Levon }
6501f5207b7SJohn Levon 
move_reg(struct bb_state * state,struct hardreg * src,struct hardreg * dst)6511f5207b7SJohn Levon static void move_reg(struct bb_state *state, struct hardreg *src, struct hardreg *dst)
6521f5207b7SJohn Levon {
6531f5207b7SJohn Levon 	output_insn(state, "movl %s,%s", src->name, dst->name);
6541f5207b7SJohn Levon }
6551f5207b7SJohn Levon 
copy_reg(struct bb_state * state,struct hardreg * src,pseudo_t target)6561f5207b7SJohn Levon static struct hardreg *copy_reg(struct bb_state *state, struct hardreg *src, pseudo_t target)
6571f5207b7SJohn Levon {
6581f5207b7SJohn Levon 	int i;
6591f5207b7SJohn Levon 	struct hardreg *reg;
6601f5207b7SJohn Levon 
6611f5207b7SJohn Levon 	/* If the container has been killed off, just re-use it */
6621f5207b7SJohn Levon 	if (!src->contains)
6631f5207b7SJohn Levon 		return src;
6641f5207b7SJohn Levon 
6651f5207b7SJohn Levon 	/* If "src" only has one user, and the contents are dead, we can re-use it */
6661f5207b7SJohn Levon 	if (src->busy == 1 && src->dead == 1)
6671f5207b7SJohn Levon 		return src;
6681f5207b7SJohn Levon 
6691f5207b7SJohn Levon 	reg = preferred_reg(state, target);
6701f5207b7SJohn Levon 	if (reg && !reg->contains) {
6711f5207b7SJohn Levon 		output_comment(state, "copying %s to preferred target %s", show_pseudo(target), reg->name);
6721f5207b7SJohn Levon 		move_reg(state, src, reg);
6731f5207b7SJohn Levon 		return reg;
6741f5207b7SJohn Levon 	}
6751f5207b7SJohn Levon 
6761f5207b7SJohn Levon 	for (i = 0; i < REGNO; i++) {
6771f5207b7SJohn Levon 		reg = hardregs + i;
6781f5207b7SJohn Levon 		if (!reg->contains) {
6791f5207b7SJohn Levon 			output_comment(state, "copying %s to %s", show_pseudo(target), reg->name);
6801f5207b7SJohn Levon 			output_insn(state, "movl %s,%s", src->name, reg->name);
6811f5207b7SJohn Levon 			return reg;
6821f5207b7SJohn Levon 		}
6831f5207b7SJohn Levon 	}
6841f5207b7SJohn Levon 
6851f5207b7SJohn Levon 	flush_reg(state, src);
6861f5207b7SJohn Levon 	return src;
6871f5207b7SJohn Levon }
6881f5207b7SJohn Levon 
put_operand(struct bb_state * state,struct operand * op)6891f5207b7SJohn Levon static void put_operand(struct bb_state *state, struct operand *op)
6901f5207b7SJohn Levon {
6911f5207b7SJohn Levon 	switch (op->type) {
6921f5207b7SJohn Levon 	case OP_REG:
6931f5207b7SJohn Levon 		op->reg->busy--;
6941f5207b7SJohn Levon 		break;
6951f5207b7SJohn Levon 	case OP_ADDR:
6961f5207b7SJohn Levon 	case OP_MEM:
6971f5207b7SJohn Levon 		if (op->base)
6981f5207b7SJohn Levon 			op->base->busy--;
6991f5207b7SJohn Levon 		if (op->index)
7001f5207b7SJohn Levon 			op->index->busy--;
7011f5207b7SJohn Levon 		break;
7021f5207b7SJohn Levon 	default:
7031f5207b7SJohn Levon 		break;
7041f5207b7SJohn Levon 	}
7051f5207b7SJohn Levon }
7061f5207b7SJohn Levon 
alloc_op(void)7071f5207b7SJohn Levon static struct operand *alloc_op(void)
7081f5207b7SJohn Levon {
7091f5207b7SJohn Levon 	struct operand *op = malloc(sizeof(*op));
7101f5207b7SJohn Levon 	memset(op, 0, sizeof(*op));
7111f5207b7SJohn Levon 	return op;
7121f5207b7SJohn Levon }
7131f5207b7SJohn Levon 
get_register_operand(struct bb_state * state,pseudo_t pseudo,pseudo_t target)7141f5207b7SJohn Levon static struct operand *get_register_operand(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
7151f5207b7SJohn Levon {
7161f5207b7SJohn Levon 	struct operand *op = alloc_op();
7171f5207b7SJohn Levon 	op->type = OP_REG;
7181f5207b7SJohn Levon 	op->reg = getreg(state, pseudo, target);
7191f5207b7SJohn Levon 	op->reg->busy++;
7201f5207b7SJohn Levon 	return op;
7211f5207b7SJohn Levon }
7221f5207b7SJohn Levon 
get_sym_frame_offset(struct bb_state * state,pseudo_t pseudo)7231f5207b7SJohn Levon static int get_sym_frame_offset(struct bb_state *state, pseudo_t pseudo)
7241f5207b7SJohn Levon {
7251f5207b7SJohn Levon 	int offset = pseudo->nr;
7261f5207b7SJohn Levon 	if (offset < 0) {
7271f5207b7SJohn Levon 		offset = alloc_stack_offset(4);
7281f5207b7SJohn Levon 		pseudo->nr = offset;
7291f5207b7SJohn Levon 	}
7301f5207b7SJohn Levon 	return offset;
7311f5207b7SJohn Levon }
7321f5207b7SJohn Levon 
get_generic_operand(struct bb_state * state,pseudo_t pseudo)7331f5207b7SJohn Levon static struct operand *get_generic_operand(struct bb_state *state, pseudo_t pseudo)
7341f5207b7SJohn Levon {
7351f5207b7SJohn Levon 	struct hardreg *reg;
7361f5207b7SJohn Levon 	struct storage *src;
7371f5207b7SJohn Levon 	struct storage_hash *hash;
7381f5207b7SJohn Levon 	struct operand *op = malloc(sizeof(*op));
7391f5207b7SJohn Levon 
7401f5207b7SJohn Levon 	memset(op, 0, sizeof(*op));
7411f5207b7SJohn Levon 	switch (pseudo->type) {
7421f5207b7SJohn Levon 	case PSEUDO_VAL:
7431f5207b7SJohn Levon 		op->type = OP_VAL;
7441f5207b7SJohn Levon 		op->value = pseudo->value;
7451f5207b7SJohn Levon 		break;
7461f5207b7SJohn Levon 
7471f5207b7SJohn Levon 	case PSEUDO_SYM: {
7481f5207b7SJohn Levon 		struct symbol *sym = pseudo->sym;
7491f5207b7SJohn Levon 		op->type = OP_ADDR;
7501f5207b7SJohn Levon 		if (sym->ctype.modifiers & MOD_NONLOCAL) {
7511f5207b7SJohn Levon 			op->sym = sym;
7521f5207b7SJohn Levon 			break;
7531f5207b7SJohn Levon 		}
7541f5207b7SJohn Levon 		op->base = hardregs + REG_EBP;
7551f5207b7SJohn Levon 		op->offset = get_sym_frame_offset(state, pseudo);
7561f5207b7SJohn Levon 		break;
7571f5207b7SJohn Levon 	}
7581f5207b7SJohn Levon 
7591f5207b7SJohn Levon 	default:
7601f5207b7SJohn Levon 		reg = find_in_reg(state, pseudo);
7611f5207b7SJohn Levon 		if (reg) {
7621f5207b7SJohn Levon 			op->type = OP_REG;
7631f5207b7SJohn Levon 			op->reg = reg;
7641f5207b7SJohn Levon 			reg->busy++;
7651f5207b7SJohn Levon 			break;
7661f5207b7SJohn Levon 		}
7671f5207b7SJohn Levon 		hash = find_pseudo_storage(state, pseudo, NULL);
7681f5207b7SJohn Levon 		if (!hash)
7691f5207b7SJohn Levon 			break;
7701f5207b7SJohn Levon 		src = hash->storage;
7711f5207b7SJohn Levon 		switch (src->type) {
7721f5207b7SJohn Levon 		case REG_REG:
7731f5207b7SJohn Levon 			op->type = OP_REG;
7741f5207b7SJohn Levon 			op->reg = hardregs + src->regno;
7751f5207b7SJohn Levon 			op->reg->busy++;
7761f5207b7SJohn Levon 			break;
7771f5207b7SJohn Levon 		case REG_FRAME:
7781f5207b7SJohn Levon 			op->type = OP_MEM;
7791f5207b7SJohn Levon 			op->offset = src->offset;
7801f5207b7SJohn Levon 			op->base = hardregs + REG_EBP;
7811f5207b7SJohn Levon 			break;
7821f5207b7SJohn Levon 		case REG_STACK:
7831f5207b7SJohn Levon 			op->type = OP_MEM;
7841f5207b7SJohn Levon 			op->offset = src->offset;
7851f5207b7SJohn Levon 			op->base = hardregs + REG_ESP;
7861f5207b7SJohn Levon 			break;
7871f5207b7SJohn Levon 		default:
7881f5207b7SJohn Levon 			break;
7891f5207b7SJohn Levon 		}
7901f5207b7SJohn Levon 	}
7911f5207b7SJohn Levon 	return op;
7921f5207b7SJohn Levon }
7931f5207b7SJohn Levon 
7941f5207b7SJohn Levon /* Callers should be made to use the proper "operand" formats */
generic(struct bb_state * state,pseudo_t pseudo)7951f5207b7SJohn Levon static const char *generic(struct bb_state *state, pseudo_t pseudo)
7961f5207b7SJohn Levon {
7971f5207b7SJohn Levon 	struct hardreg *reg;
7981f5207b7SJohn Levon 	struct operand *op = get_generic_operand(state, pseudo);
7991f5207b7SJohn Levon 	static char buf[100];
8001f5207b7SJohn Levon 	const char *str;
8011f5207b7SJohn Levon 
8021f5207b7SJohn Levon 	switch (op->type) {
8031f5207b7SJohn Levon 	case OP_ADDR:
8041f5207b7SJohn Levon 		if (!op->offset && op->base && !op->sym)
8051f5207b7SJohn Levon 			return op->base->name;
8061f5207b7SJohn Levon 		if (op->sym && !op->base) {
8071f5207b7SJohn Levon 			int len = sprintf(buf, "$ %s", show_op(state, op));
8081f5207b7SJohn Levon 			if (op->offset)
8091f5207b7SJohn Levon 				sprintf(buf + len, " + %d", op->offset);
8101f5207b7SJohn Levon 			return buf;
8111f5207b7SJohn Levon 		}
8121f5207b7SJohn Levon 		str = show_op(state, op);
8131f5207b7SJohn Levon 		put_operand(state, op);
8141f5207b7SJohn Levon 		reg = target_reg(state, pseudo, NULL);
8151f5207b7SJohn Levon 		output_insn(state, "lea %s,%s", show_op(state, op), reg->name);
8161f5207b7SJohn Levon 		return reg->name;
8171f5207b7SJohn Levon 
8181f5207b7SJohn Levon 	default:
8191f5207b7SJohn Levon 		str = show_op(state, op);
8201f5207b7SJohn Levon 	}
8211f5207b7SJohn Levon 	put_operand(state, op);
8221f5207b7SJohn Levon 	return str;
8231f5207b7SJohn Levon }
8241f5207b7SJohn Levon 
get_address_operand(struct bb_state * state,struct instruction * memop)8251f5207b7SJohn Levon static struct operand *get_address_operand(struct bb_state *state, struct instruction *memop)
8261f5207b7SJohn Levon {
8271f5207b7SJohn Levon 	struct hardreg *base;
8281f5207b7SJohn Levon 	struct operand *op = get_generic_operand(state, memop->src);
8291f5207b7SJohn Levon 
8301f5207b7SJohn Levon 	switch (op->type) {
8311f5207b7SJohn Levon 	case OP_ADDR:
8321f5207b7SJohn Levon 		op->offset += memop->offset;
8331f5207b7SJohn Levon 		break;
8341f5207b7SJohn Levon 	default:
8351f5207b7SJohn Levon 		put_operand(state, op);
8361f5207b7SJohn Levon 		base = getreg(state, memop->src, NULL);
8371f5207b7SJohn Levon 		op->type = OP_ADDR;
8381f5207b7SJohn Levon 		op->base = base;
8391f5207b7SJohn Levon 		base->busy++;
8401f5207b7SJohn Levon 		op->offset = memop->offset;
8411f5207b7SJohn Levon 		op->sym = NULL;
8421f5207b7SJohn Levon 	}
8431f5207b7SJohn Levon 	return op;
8441f5207b7SJohn Levon }
8451f5207b7SJohn Levon 
address(struct bb_state * state,struct instruction * memop)8461f5207b7SJohn Levon static const char *address(struct bb_state *state, struct instruction *memop)
8471f5207b7SJohn Levon {
8481f5207b7SJohn Levon 	struct operand *op = get_address_operand(state, memop);
8491f5207b7SJohn Levon 	const char *str = show_op(state, op);
8501f5207b7SJohn Levon 	put_operand(state, op);
8511f5207b7SJohn Levon 	return str;
8521f5207b7SJohn Levon }
8531f5207b7SJohn Levon 
reg_or_imm(struct bb_state * state,pseudo_t pseudo)8541f5207b7SJohn Levon static const char *reg_or_imm(struct bb_state *state, pseudo_t pseudo)
8551f5207b7SJohn Levon {
8561f5207b7SJohn Levon 	switch(pseudo->type) {
8571f5207b7SJohn Levon 	case PSEUDO_VAL:
8581f5207b7SJohn Levon 		return show_pseudo(pseudo);
8591f5207b7SJohn Levon 	default:
8601f5207b7SJohn Levon 		return getreg(state, pseudo, NULL)->name;
8611f5207b7SJohn Levon 	}
8621f5207b7SJohn Levon }
8631f5207b7SJohn Levon 
kill_dead_reg(struct hardreg * reg)8641f5207b7SJohn Levon static void kill_dead_reg(struct hardreg *reg)
8651f5207b7SJohn Levon {
8661f5207b7SJohn Levon 	if (reg->dead) {
8671f5207b7SJohn Levon 		pseudo_t p;
8681f5207b7SJohn Levon 
869*c85f09ccSJohn Levon 		FOR_EACH_PTR_TAG(reg->contains, p) {
8701f5207b7SJohn Levon 			if (CURRENT_TAG(p) & TAG_DEAD) {
8711f5207b7SJohn Levon 				DELETE_CURRENT_PTR(p);
8721f5207b7SJohn Levon 				reg->dead--;
8731f5207b7SJohn Levon 			}
8741f5207b7SJohn Levon 		} END_FOR_EACH_PTR(p);
8751f5207b7SJohn Levon 		PACK_PTR_LIST(&reg->contains);
8761f5207b7SJohn Levon 		assert(!reg->dead);
8771f5207b7SJohn Levon 	}
8781f5207b7SJohn Levon }
8791f5207b7SJohn Levon 
target_copy_reg(struct bb_state * state,struct hardreg * src,pseudo_t target)8801f5207b7SJohn Levon static struct hardreg *target_copy_reg(struct bb_state *state, struct hardreg *src, pseudo_t target)
8811f5207b7SJohn Levon {
8821f5207b7SJohn Levon 	kill_dead_reg(src);
8831f5207b7SJohn Levon 	return copy_reg(state, src, target);
8841f5207b7SJohn Levon }
8851f5207b7SJohn Levon 
do_binop(struct bb_state * state,struct instruction * insn,pseudo_t val1,pseudo_t val2)8861f5207b7SJohn Levon static void do_binop(struct bb_state *state, struct instruction *insn, pseudo_t val1, pseudo_t val2)
8871f5207b7SJohn Levon {
8881f5207b7SJohn Levon 	const char *op = opcodes[insn->opcode];
8891f5207b7SJohn Levon 	struct operand *src = get_register_operand(state, val1, insn->target);
8901f5207b7SJohn Levon 	struct operand *src2 = get_generic_operand(state, val2);
8911f5207b7SJohn Levon 	struct hardreg *dst;
8921f5207b7SJohn Levon 
8931f5207b7SJohn Levon 	dst = target_copy_reg(state, src->reg, insn->target);
8941f5207b7SJohn Levon 	output_insn(state, "%s.%d %s,%s", op, insn->size, show_op(state, src2), dst->name);
8951f5207b7SJohn Levon 	put_operand(state, src);
8961f5207b7SJohn Levon 	put_operand(state, src2);
8971f5207b7SJohn Levon 	add_pseudo_reg(state, insn->target, dst);
8981f5207b7SJohn Levon }
8991f5207b7SJohn Levon 
generate_binop(struct bb_state * state,struct instruction * insn)9001f5207b7SJohn Levon static void generate_binop(struct bb_state *state, struct instruction *insn)
9011f5207b7SJohn Levon {
9021f5207b7SJohn Levon 	flush_cc_cache(state);
9031f5207b7SJohn Levon 	do_binop(state, insn, insn->src1, insn->src2);
9041f5207b7SJohn Levon }
9051f5207b7SJohn Levon 
is_dead_reg(struct bb_state * state,pseudo_t pseudo,struct hardreg * reg)9061f5207b7SJohn Levon static int is_dead_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
9071f5207b7SJohn Levon {
9081f5207b7SJohn Levon 	pseudo_t p;
909*c85f09ccSJohn Levon 	FOR_EACH_PTR_TAG(reg->contains, p) {
9101f5207b7SJohn Levon 		if (p == pseudo)
9111f5207b7SJohn Levon 			return CURRENT_TAG(p) & TAG_DEAD;
9121f5207b7SJohn Levon 	} END_FOR_EACH_PTR(p);
9131f5207b7SJohn Levon 	return 0;
9141f5207b7SJohn Levon }
9151f5207b7SJohn Levon 
9161f5207b7SJohn Levon /*
9171f5207b7SJohn Levon  * Commutative binops are much more flexible, since we can switch the
9181f5207b7SJohn Levon  * sources around to satisfy the target register, or to avoid having
9191f5207b7SJohn Levon  * to load one of them into a register..
9201f5207b7SJohn Levon  */
generate_commutative_binop(struct bb_state * state,struct instruction * insn)9211f5207b7SJohn Levon static void generate_commutative_binop(struct bb_state *state, struct instruction *insn)
9221f5207b7SJohn Levon {
9231f5207b7SJohn Levon 	pseudo_t src1, src2;
9241f5207b7SJohn Levon 	struct hardreg *reg1, *reg2;
9251f5207b7SJohn Levon 
9261f5207b7SJohn Levon 	flush_cc_cache(state);
9271f5207b7SJohn Levon 	src1 = insn->src1;
9281f5207b7SJohn Levon 	src2 = insn->src2;
9291f5207b7SJohn Levon 	reg2 = find_in_reg(state, src2);
9301f5207b7SJohn Levon 	if (!reg2)
9311f5207b7SJohn Levon 		goto dont_switch;
9321f5207b7SJohn Levon 	reg1 = find_in_reg(state, src1);
9331f5207b7SJohn Levon 	if (!reg1)
9341f5207b7SJohn Levon 		goto do_switch;
9351f5207b7SJohn Levon 	if (!is_dead_reg(state, src2, reg2))
9361f5207b7SJohn Levon 		goto dont_switch;
9371f5207b7SJohn Levon 	if (!is_dead_reg(state, src1, reg1))
9381f5207b7SJohn Levon 		goto do_switch;
9391f5207b7SJohn Levon 
9401f5207b7SJohn Levon 	/* Both are dead. Is one preferable? */
9411f5207b7SJohn Levon 	if (reg2 != preferred_reg(state, insn->target))
9421f5207b7SJohn Levon 		goto dont_switch;
9431f5207b7SJohn Levon 
9441f5207b7SJohn Levon do_switch:
9451f5207b7SJohn Levon 	src1 = src2;
9461f5207b7SJohn Levon 	src2 = insn->src1;
9471f5207b7SJohn Levon dont_switch:
9481f5207b7SJohn Levon 	do_binop(state, insn, src1, src2);
9491f5207b7SJohn Levon }
9501f5207b7SJohn Levon 
9511f5207b7SJohn Levon /*
9521f5207b7SJohn Levon  * This marks a pseudo dead. It still stays on the hardreg list (the hardreg
9531f5207b7SJohn Levon  * still has its value), but it's scheduled to be killed after the next
9541f5207b7SJohn Levon  * "sequence point" when we call "kill_read_pseudos()"
9551f5207b7SJohn Levon  */
mark_pseudo_dead(struct bb_state * state,pseudo_t pseudo)9561f5207b7SJohn Levon static void mark_pseudo_dead(struct bb_state *state, pseudo_t pseudo)
9571f5207b7SJohn Levon {
9581f5207b7SJohn Levon 	int i;
9591f5207b7SJohn Levon 	struct storage_hash *src;
9601f5207b7SJohn Levon 
9611f5207b7SJohn Levon 	if (state->cc_target == pseudo)
9621f5207b7SJohn Levon 		state->cc_dead = 1;
9631f5207b7SJohn Levon 	src = find_pseudo_storage(state, pseudo, NULL);
9641f5207b7SJohn Levon 	if (src)
9651f5207b7SJohn Levon 		src->flags |= TAG_DEAD;
9661f5207b7SJohn Levon 	for (i = 0; i < REGNO; i++)
9671f5207b7SJohn Levon 		mark_reg_dead(state, pseudo, hardregs + i);
9681f5207b7SJohn Levon }
9691f5207b7SJohn Levon 
kill_dead_pseudos(struct bb_state * state)9701f5207b7SJohn Levon static void kill_dead_pseudos(struct bb_state *state)
9711f5207b7SJohn Levon {
9721f5207b7SJohn Levon 	int i;
9731f5207b7SJohn Levon 
9741f5207b7SJohn Levon 	for (i = 0; i < REGNO; i++) {
9751f5207b7SJohn Levon 		kill_dead_reg(hardregs + i);
9761f5207b7SJohn Levon 	}
9771f5207b7SJohn Levon }
9781f5207b7SJohn Levon 
generate_store(struct instruction * insn,struct bb_state * state)9791f5207b7SJohn Levon static void generate_store(struct instruction *insn, struct bb_state *state)
9801f5207b7SJohn Levon {
9811f5207b7SJohn Levon 	output_insn(state, "mov.%d %s,%s", insn->size, reg_or_imm(state, insn->target), address(state, insn));
9821f5207b7SJohn Levon }
9831f5207b7SJohn Levon 
generate_load(struct instruction * insn,struct bb_state * state)9841f5207b7SJohn Levon static void generate_load(struct instruction *insn, struct bb_state *state)
9851f5207b7SJohn Levon {
9861f5207b7SJohn Levon 	const char *input = address(state, insn);
9871f5207b7SJohn Levon 	struct hardreg *dst;
9881f5207b7SJohn Levon 
9891f5207b7SJohn Levon 	kill_dead_pseudos(state);
9901f5207b7SJohn Levon 	dst = target_reg(state, insn->target, NULL);
9911f5207b7SJohn Levon 	output_insn(state, "mov.%d %s,%s", insn->size, input, dst->name);
9921f5207b7SJohn Levon }
9931f5207b7SJohn Levon 
kill_pseudo(struct bb_state * state,pseudo_t pseudo)9941f5207b7SJohn Levon static void kill_pseudo(struct bb_state *state, pseudo_t pseudo)
9951f5207b7SJohn Levon {
9961f5207b7SJohn Levon 	int i;
9971f5207b7SJohn Levon 	struct hardreg *reg;
9981f5207b7SJohn Levon 
9991f5207b7SJohn Levon 	output_comment(state, "killing pseudo %s", show_pseudo(pseudo));
10001f5207b7SJohn Levon 	for (i = 0; i < REGNO; i++) {
10011f5207b7SJohn Levon 		pseudo_t p;
10021f5207b7SJohn Levon 
10031f5207b7SJohn Levon 		reg = hardregs + i;
1004*c85f09ccSJohn Levon 		FOR_EACH_PTR_TAG(reg->contains, p) {
10051f5207b7SJohn Levon 			if (p != pseudo)
10061f5207b7SJohn Levon 				continue;
10071f5207b7SJohn Levon 			if (CURRENT_TAG(p) & TAG_DEAD)
10081f5207b7SJohn Levon 				reg->dead--;
10091f5207b7SJohn Levon 			output_comment(state, "removing pseudo %s from reg %s",
10101f5207b7SJohn Levon 				show_pseudo(pseudo), reg->name);
10111f5207b7SJohn Levon 			DELETE_CURRENT_PTR(p);
10121f5207b7SJohn Levon 		} END_FOR_EACH_PTR(p);
10131f5207b7SJohn Levon 		PACK_PTR_LIST(&reg->contains);
10141f5207b7SJohn Levon 	}
10151f5207b7SJohn Levon }
10161f5207b7SJohn Levon 
generate_copy(struct bb_state * state,struct instruction * insn)10171f5207b7SJohn Levon static void generate_copy(struct bb_state *state, struct instruction *insn)
10181f5207b7SJohn Levon {
10191f5207b7SJohn Levon 	struct hardreg *src = getreg(state, insn->src, insn->target);
10201f5207b7SJohn Levon 	kill_pseudo(state, insn->target);
10211f5207b7SJohn Levon 	add_pseudo_reg(state, insn->target, src);
10221f5207b7SJohn Levon }
10231f5207b7SJohn Levon 
generate_cast(struct bb_state * state,struct instruction * insn)10241f5207b7SJohn Levon static void generate_cast(struct bb_state *state, struct instruction *insn)
10251f5207b7SJohn Levon {
10261f5207b7SJohn Levon 	struct hardreg *src = getreg(state, insn->src, insn->target);
10271f5207b7SJohn Levon 	struct hardreg *dst;
10281f5207b7SJohn Levon 	unsigned int old = insn->orig_type ? insn->orig_type->bit_size : 0;
10291f5207b7SJohn Levon 	unsigned int new = insn->size;
10301f5207b7SJohn Levon 
10311f5207b7SJohn Levon 	/*
10321f5207b7SJohn Levon 	 * Cast to smaller type? Ignore the high bits, we
10331f5207b7SJohn Levon 	 * just keep both pseudos in the same register.
10341f5207b7SJohn Levon 	 */
10351f5207b7SJohn Levon 	if (old >= new) {
10361f5207b7SJohn Levon 		add_pseudo_reg(state, insn->target, src);
10371f5207b7SJohn Levon 		return;
10381f5207b7SJohn Levon 	}
10391f5207b7SJohn Levon 
10401f5207b7SJohn Levon 	dst = target_copy_reg(state, src, insn->target);
10411f5207b7SJohn Levon 
10421f5207b7SJohn Levon 	if (insn->orig_type && (insn->orig_type->ctype.modifiers & MOD_SIGNED)) {
10431f5207b7SJohn Levon 		output_insn(state, "sext.%d.%d %s", old, new, dst->name);
10441f5207b7SJohn Levon 	} else {
10451f5207b7SJohn Levon 		unsigned long long mask;
10461f5207b7SJohn Levon 		mask = ~(~0ULL << old);
10471f5207b7SJohn Levon 		mask &= ~(~0ULL << new);
10481f5207b7SJohn Levon 		output_insn(state, "andl.%d $%#llx,%s", insn->size, mask, dst->name);
10491f5207b7SJohn Levon 	}
10501f5207b7SJohn Levon 	add_pseudo_reg(state, insn->target, dst);
10511f5207b7SJohn Levon }
10521f5207b7SJohn Levon 
10531f5207b7SJohn Levon static void generate_output_storage(struct bb_state *state);
10541f5207b7SJohn Levon 
10551f5207b7SJohn Levon static const char *conditional[] = {
10561f5207b7SJohn Levon 	[OP_SET_EQ] = "e",
10571f5207b7SJohn Levon 	[OP_SET_NE] = "ne",
10581f5207b7SJohn Levon 	[OP_SET_LE] = "le",
10591f5207b7SJohn Levon 	[OP_SET_GE] = "ge",
10601f5207b7SJohn Levon 	[OP_SET_LT] = "lt",
10611f5207b7SJohn Levon 	[OP_SET_GT] = "gt",
10621f5207b7SJohn Levon 	[OP_SET_B] = "b",
10631f5207b7SJohn Levon 	[OP_SET_A] = "a",
10641f5207b7SJohn Levon 	[OP_SET_BE] = "be",
10651f5207b7SJohn Levon 	[OP_SET_AE] = "ae"
10661f5207b7SJohn Levon };
10671f5207b7SJohn Levon 
10681f5207b7SJohn Levon 
generate_branch(struct bb_state * state,struct instruction * br)10691f5207b7SJohn Levon static void generate_branch(struct bb_state *state, struct instruction *br)
10701f5207b7SJohn Levon {
10711f5207b7SJohn Levon 	const char *cond = "XXX";
10721f5207b7SJohn Levon 	struct basic_block *target;
10731f5207b7SJohn Levon 
10741f5207b7SJohn Levon 	if (br->cond) {
10751f5207b7SJohn Levon 		if (state->cc_target == br->cond) {
10761f5207b7SJohn Levon 			cond = conditional[state->cc_opcode];
10771f5207b7SJohn Levon 		} else {
10781f5207b7SJohn Levon 			struct hardreg *reg = getreg(state, br->cond, NULL);
10791f5207b7SJohn Levon 			output_insn(state, "testl %s,%s", reg->name, reg->name);
10801f5207b7SJohn Levon 			cond = "ne";
10811f5207b7SJohn Levon 		}
10821f5207b7SJohn Levon 	}
10831f5207b7SJohn Levon 	generate_output_storage(state);
10841f5207b7SJohn Levon 	target = br->bb_true;
10851f5207b7SJohn Levon 	if (br->cond) {
10861f5207b7SJohn Levon 		output_insn(state, "j%s .L%p", cond, target);
10871f5207b7SJohn Levon 		target = br->bb_false;
10881f5207b7SJohn Levon 	}
10891f5207b7SJohn Levon 	output_insn(state, "jmp .L%p", target);
10901f5207b7SJohn Levon }
10911f5207b7SJohn Levon 
10921f5207b7SJohn Levon /* We've made sure that there is a dummy reg live for the output */
generate_switch(struct bb_state * state,struct instruction * insn)10931f5207b7SJohn Levon static void generate_switch(struct bb_state *state, struct instruction *insn)
10941f5207b7SJohn Levon {
10951f5207b7SJohn Levon 	struct hardreg *reg = hardregs + SWITCH_REG;
10961f5207b7SJohn Levon 
10971f5207b7SJohn Levon 	generate_output_storage(state);
10981f5207b7SJohn Levon 	output_insn(state, "switch on %s", reg->name);
10991f5207b7SJohn Levon 	output_insn(state, "unimplemented: %s", show_instruction(insn));
11001f5207b7SJohn Levon }
11011f5207b7SJohn Levon 
generate_ret(struct bb_state * state,struct instruction * ret)11021f5207b7SJohn Levon static void generate_ret(struct bb_state *state, struct instruction *ret)
11031f5207b7SJohn Levon {
11041f5207b7SJohn Levon 	if (ret->src && ret->src != VOID) {
11051f5207b7SJohn Levon 		struct hardreg *wants = hardregs+0;
11061f5207b7SJohn Levon 		struct hardreg *reg = getreg(state, ret->src, NULL);
11071f5207b7SJohn Levon 		if (reg != wants)
11081f5207b7SJohn Levon 			output_insn(state, "movl %s,%s", reg->name, wants->name);
11091f5207b7SJohn Levon 	}
11101f5207b7SJohn Levon 	output_insn(state, "ret");
11111f5207b7SJohn Levon }
11121f5207b7SJohn Levon 
11131f5207b7SJohn Levon /*
11141f5207b7SJohn Levon  * Fake "call" linearization just as a taster..
11151f5207b7SJohn Levon  */
generate_call(struct bb_state * state,struct instruction * insn)11161f5207b7SJohn Levon static void generate_call(struct bb_state *state, struct instruction *insn)
11171f5207b7SJohn Levon {
11181f5207b7SJohn Levon 	int offset = 0;
11191f5207b7SJohn Levon 	pseudo_t arg;
11201f5207b7SJohn Levon 
11211f5207b7SJohn Levon 	FOR_EACH_PTR(insn->arguments, arg) {
11221f5207b7SJohn Levon 		output_insn(state, "pushl %s", generic(state, arg));
11231f5207b7SJohn Levon 		offset += 4;
11241f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
11251f5207b7SJohn Levon 	flush_reg(state, hardregs+0);
11261f5207b7SJohn Levon 	flush_reg(state, hardregs+1);
11271f5207b7SJohn Levon 	flush_reg(state, hardregs+2);
11281f5207b7SJohn Levon 	output_insn(state, "call %s", show_pseudo(insn->func));
11291f5207b7SJohn Levon 	if (offset)
11301f5207b7SJohn Levon 		output_insn(state, "addl $%d,%%esp", offset);
11311f5207b7SJohn Levon 	if (insn->target && insn->target != VOID)
11321f5207b7SJohn Levon 		add_pseudo_reg(state, insn->target, hardregs+0);
11331f5207b7SJohn Levon }
11341f5207b7SJohn Levon 
generate_select(struct bb_state * state,struct instruction * insn)11351f5207b7SJohn Levon static void generate_select(struct bb_state *state, struct instruction *insn)
11361f5207b7SJohn Levon {
11371f5207b7SJohn Levon 	const char *cond;
11381f5207b7SJohn Levon 	struct hardreg *src1, *src2, *dst;
11391f5207b7SJohn Levon 
11401f5207b7SJohn Levon 	src1 = getreg(state, insn->src2, NULL);
11411f5207b7SJohn Levon 	dst = copy_reg(state, src1, insn->target);
11421f5207b7SJohn Levon 	add_pseudo_reg(state, insn->target, dst);
11431f5207b7SJohn Levon 	src2 = getreg(state, insn->src3, insn->target);
11441f5207b7SJohn Levon 
11451f5207b7SJohn Levon 	if (state->cc_target == insn->src1) {
11461f5207b7SJohn Levon 		cond = conditional[state->cc_opcode];
11471f5207b7SJohn Levon 	} else {
11481f5207b7SJohn Levon 		struct hardreg *reg = getreg(state, insn->src1, NULL);
11491f5207b7SJohn Levon 		output_insn(state, "testl %s,%s", reg->name, reg->name);
11501f5207b7SJohn Levon 		cond = "ne";
11511f5207b7SJohn Levon 	}
11521f5207b7SJohn Levon 
11531f5207b7SJohn Levon 	output_insn(state, "sel%s %s,%s", cond, src2->name, dst->name);
11541f5207b7SJohn Levon }
11551f5207b7SJohn Levon 
11561f5207b7SJohn Levon struct asm_arg {
11571f5207b7SJohn Levon 	const struct ident *name;
11581f5207b7SJohn Levon 	const char *value;
11591f5207b7SJohn Levon 	pseudo_t pseudo;
11601f5207b7SJohn Levon 	struct hardreg *reg;
11611f5207b7SJohn Levon };
11621f5207b7SJohn Levon 
replace_asm_arg(char ** dst_p,struct asm_arg * arg)11631f5207b7SJohn Levon static void replace_asm_arg(char **dst_p, struct asm_arg *arg)
11641f5207b7SJohn Levon {
11651f5207b7SJohn Levon 	char *dst = *dst_p;
11661f5207b7SJohn Levon 	int len = strlen(arg->value);
11671f5207b7SJohn Levon 
11681f5207b7SJohn Levon 	memcpy(dst, arg->value, len);
11691f5207b7SJohn Levon 	*dst_p = dst + len;
11701f5207b7SJohn Levon }
11711f5207b7SJohn Levon 
replace_asm_percent(const char ** src_p,char ** dst_p,struct asm_arg * args,int nr)11721f5207b7SJohn Levon static void replace_asm_percent(const char **src_p, char **dst_p, struct asm_arg *args, int nr)
11731f5207b7SJohn Levon {
11741f5207b7SJohn Levon 	const char *src = *src_p;
11751f5207b7SJohn Levon 	char c;
11761f5207b7SJohn Levon 	int index;
11771f5207b7SJohn Levon 
11781f5207b7SJohn Levon 	c = *src++;
11791f5207b7SJohn Levon 	switch (c) {
11801f5207b7SJohn Levon 	case '0' ... '9':
11811f5207b7SJohn Levon 		index = c - '0';
11821f5207b7SJohn Levon 		if (index < nr)
11831f5207b7SJohn Levon 			replace_asm_arg(dst_p, args+index);
11841f5207b7SJohn Levon 		break;
11851f5207b7SJohn Levon 	}
11861f5207b7SJohn Levon 	*src_p = src;
11871f5207b7SJohn Levon 	return;
11881f5207b7SJohn Levon }
11891f5207b7SJohn Levon 
replace_asm_named(const char ** src_p,char ** dst_p,struct asm_arg * args,int nr)11901f5207b7SJohn Levon static void replace_asm_named(const char **src_p, char **dst_p, struct asm_arg *args, int nr)
11911f5207b7SJohn Levon {
11921f5207b7SJohn Levon 	const char *src = *src_p;
11931f5207b7SJohn Levon 	const char *end = src;
11941f5207b7SJohn Levon 
11951f5207b7SJohn Levon 	for(;;) {
11961f5207b7SJohn Levon 		char c = *end++;
11971f5207b7SJohn Levon 		if (!c)
11981f5207b7SJohn Levon 			return;
11991f5207b7SJohn Levon 		if (c == ']') {
12001f5207b7SJohn Levon 			int i;
12011f5207b7SJohn Levon 
12021f5207b7SJohn Levon 			*src_p = end;
12031f5207b7SJohn Levon 			for (i = 0; i < nr; i++) {
12041f5207b7SJohn Levon 				const struct ident *ident = args[i].name;
12051f5207b7SJohn Levon 				int len;
12061f5207b7SJohn Levon 				if (!ident)
12071f5207b7SJohn Levon 					continue;
12081f5207b7SJohn Levon 				len = ident->len;
12091f5207b7SJohn Levon 				if (memcmp(src, ident->name, len))
12101f5207b7SJohn Levon 					continue;
12111f5207b7SJohn Levon 				replace_asm_arg(dst_p, args+i);
12121f5207b7SJohn Levon 				return;
12131f5207b7SJohn Levon 			}
12141f5207b7SJohn Levon 		}
12151f5207b7SJohn Levon 	}
12161f5207b7SJohn Levon }
12171f5207b7SJohn Levon 
replace_asm_args(const char * str,struct asm_arg * args,int nr)12181f5207b7SJohn Levon static const char *replace_asm_args(const char *str, struct asm_arg *args, int nr)
12191f5207b7SJohn Levon {
12201f5207b7SJohn Levon 	static char buffer[1000];
12211f5207b7SJohn Levon 	char *p = buffer;
12221f5207b7SJohn Levon 
12231f5207b7SJohn Levon 	for (;;) {
12241f5207b7SJohn Levon 		char c = *str;
12251f5207b7SJohn Levon 		*p = c;
12261f5207b7SJohn Levon 		if (!c)
12271f5207b7SJohn Levon 			return buffer;
12281f5207b7SJohn Levon 		str++;
12291f5207b7SJohn Levon 		switch (c) {
12301f5207b7SJohn Levon 		case '%':
12311f5207b7SJohn Levon 			if (*str == '%') {
12321f5207b7SJohn Levon 				str++;
12331f5207b7SJohn Levon 				p++;
12341f5207b7SJohn Levon 				continue;
12351f5207b7SJohn Levon 			}
12361f5207b7SJohn Levon 			replace_asm_percent(&str, &p, args, nr);
12371f5207b7SJohn Levon 			continue;
12381f5207b7SJohn Levon 		case '[':
12391f5207b7SJohn Levon 			replace_asm_named(&str, &p, args, nr);
12401f5207b7SJohn Levon 			continue;
12411f5207b7SJohn Levon 		default:
12421f5207b7SJohn Levon 			break;
12431f5207b7SJohn Levon 		}
12441f5207b7SJohn Levon 		p++;
12451f5207b7SJohn Levon 	}
12461f5207b7SJohn Levon }
12471f5207b7SJohn Levon 
12481f5207b7SJohn Levon #define MAX_ASM_ARG (50)
12491f5207b7SJohn Levon static struct asm_arg asm_arguments[MAX_ASM_ARG];
12501f5207b7SJohn Levon 
generate_asm_inputs(struct bb_state * state,struct asm_constraint_list * list,struct asm_arg * arg)12511f5207b7SJohn Levon static struct asm_arg *generate_asm_inputs(struct bb_state *state, struct asm_constraint_list *list, struct asm_arg *arg)
12521f5207b7SJohn Levon {
12531f5207b7SJohn Levon 	struct asm_constraint *entry;
12541f5207b7SJohn Levon 
12551f5207b7SJohn Levon 	FOR_EACH_PTR(list, entry) {
12561f5207b7SJohn Levon 		const char *constraint = entry->constraint;
12571f5207b7SJohn Levon 		pseudo_t pseudo = entry->pseudo;
12581f5207b7SJohn Levon 		struct hardreg *reg, *orig;
12591f5207b7SJohn Levon 		const char *string;
12601f5207b7SJohn Levon 		int index;
12611f5207b7SJohn Levon 
12621f5207b7SJohn Levon 		string = "undef";
12631f5207b7SJohn Levon 		switch (*constraint) {
12641f5207b7SJohn Levon 		case 'r':
12651f5207b7SJohn Levon 			string = getreg(state, pseudo, NULL)->name;
12661f5207b7SJohn Levon 			break;
12671f5207b7SJohn Levon 		case '0' ... '9':
12681f5207b7SJohn Levon 			index = *constraint - '0';
12691f5207b7SJohn Levon 			reg = asm_arguments[index].reg;
12701f5207b7SJohn Levon 			orig = find_in_reg(state, pseudo);
12711f5207b7SJohn Levon 			if (orig)
12721f5207b7SJohn Levon 				move_reg(state, orig, reg);
12731f5207b7SJohn Levon 			else
12741f5207b7SJohn Levon 				fill_reg(state, reg, pseudo);
12751f5207b7SJohn Levon 			string = reg->name;
12761f5207b7SJohn Levon 			break;
12771f5207b7SJohn Levon 		default:
12781f5207b7SJohn Levon 			string = generic(state, pseudo);
12791f5207b7SJohn Levon 			break;
12801f5207b7SJohn Levon 		}
12811f5207b7SJohn Levon 
12821f5207b7SJohn Levon 		output_insn(state, "# asm input \"%s\": %s : %s", constraint, show_pseudo(pseudo), string);
12831f5207b7SJohn Levon 
12841f5207b7SJohn Levon 		arg->name = entry->ident;
12851f5207b7SJohn Levon 		arg->value = string;
12861f5207b7SJohn Levon 		arg->pseudo = NULL;
12871f5207b7SJohn Levon 		arg->reg = NULL;
12881f5207b7SJohn Levon 		arg++;
12891f5207b7SJohn Levon 	} END_FOR_EACH_PTR(entry);
12901f5207b7SJohn Levon 	return arg;
12911f5207b7SJohn Levon }
12921f5207b7SJohn Levon 
generate_asm_outputs(struct bb_state * state,struct asm_constraint_list * list,struct asm_arg * arg)12931f5207b7SJohn Levon static struct asm_arg *generate_asm_outputs(struct bb_state *state, struct asm_constraint_list *list, struct asm_arg *arg)
12941f5207b7SJohn Levon {
12951f5207b7SJohn Levon 	struct asm_constraint *entry;
12961f5207b7SJohn Levon 
12971f5207b7SJohn Levon 	FOR_EACH_PTR(list, entry) {
12981f5207b7SJohn Levon 		const char *constraint = entry->constraint;
12991f5207b7SJohn Levon 		pseudo_t pseudo = entry->pseudo;
13001f5207b7SJohn Levon 		struct hardreg *reg;
13011f5207b7SJohn Levon 		const char *string;
13021f5207b7SJohn Levon 
13031f5207b7SJohn Levon 		while (*constraint == '=' || *constraint == '+')
13041f5207b7SJohn Levon 			constraint++;
13051f5207b7SJohn Levon 
13061f5207b7SJohn Levon 		string = "undef";
13071f5207b7SJohn Levon 		switch (*constraint) {
13081f5207b7SJohn Levon 		case 'r':
13091f5207b7SJohn Levon 		default:
13101f5207b7SJohn Levon 			reg = target_reg(state, pseudo, NULL);
13111f5207b7SJohn Levon 			arg->pseudo = pseudo;
13121f5207b7SJohn Levon 			arg->reg = reg;
13131f5207b7SJohn Levon 			string = reg->name;
13141f5207b7SJohn Levon 			break;
13151f5207b7SJohn Levon 		}
13161f5207b7SJohn Levon 
13171f5207b7SJohn Levon 		output_insn(state, "# asm output \"%s\": %s : %s", constraint, show_pseudo(pseudo), string);
13181f5207b7SJohn Levon 
13191f5207b7SJohn Levon 		arg->name = entry->ident;
13201f5207b7SJohn Levon 		arg->value = string;
13211f5207b7SJohn Levon 		arg++;
13221f5207b7SJohn Levon 	} END_FOR_EACH_PTR(entry);
13231f5207b7SJohn Levon 	return arg;
13241f5207b7SJohn Levon }
13251f5207b7SJohn Levon 
generate_asm(struct bb_state * state,struct instruction * insn)13261f5207b7SJohn Levon static void generate_asm(struct bb_state *state, struct instruction *insn)
13271f5207b7SJohn Levon {
13281f5207b7SJohn Levon 	const char *str = insn->string;
13291f5207b7SJohn Levon 
13301f5207b7SJohn Levon 	if (insn->asm_rules->outputs || insn->asm_rules->inputs) {
13311f5207b7SJohn Levon 		struct asm_arg *arg;
13321f5207b7SJohn Levon 
13331f5207b7SJohn Levon 		arg = generate_asm_outputs(state, insn->asm_rules->outputs, asm_arguments);
13341f5207b7SJohn Levon 		arg = generate_asm_inputs(state, insn->asm_rules->inputs, arg);
13351f5207b7SJohn Levon 		str = replace_asm_args(str, asm_arguments, arg - asm_arguments);
13361f5207b7SJohn Levon 	}
13371f5207b7SJohn Levon 	output_insn(state, "%s", str);
13381f5207b7SJohn Levon }
13391f5207b7SJohn Levon 
generate_compare(struct bb_state * state,struct instruction * insn)13401f5207b7SJohn Levon static void generate_compare(struct bb_state *state, struct instruction *insn)
13411f5207b7SJohn Levon {
13421f5207b7SJohn Levon 	struct hardreg *src;
13431f5207b7SJohn Levon 	const char *src2;
13441f5207b7SJohn Levon 	int opcode;
13451f5207b7SJohn Levon 
13461f5207b7SJohn Levon 	flush_cc_cache(state);
13471f5207b7SJohn Levon 	opcode = insn->opcode;
13481f5207b7SJohn Levon 
13491f5207b7SJohn Levon 	/*
13501f5207b7SJohn Levon 	 * We should try to switch these around if necessary,
13511f5207b7SJohn Levon 	 * and update the opcode to match..
13521f5207b7SJohn Levon 	 */
13531f5207b7SJohn Levon 	src = getreg(state, insn->src1, insn->target);
13541f5207b7SJohn Levon 	src2 = generic(state, insn->src2);
13551f5207b7SJohn Levon 
13561f5207b7SJohn Levon 	output_insn(state, "cmp.%d %s,%s", insn->size, src2, src->name);
13571f5207b7SJohn Levon 
13581f5207b7SJohn Levon 	add_cc_cache(state, opcode, insn->target);
13591f5207b7SJohn Levon }
13601f5207b7SJohn Levon 
generate_one_insn(struct instruction * insn,struct bb_state * state)13611f5207b7SJohn Levon static void generate_one_insn(struct instruction *insn, struct bb_state *state)
13621f5207b7SJohn Levon {
13631f5207b7SJohn Levon 	if (verbose)
13641f5207b7SJohn Levon 		output_comment(state, "%s", show_instruction(insn));
13651f5207b7SJohn Levon 
13661f5207b7SJohn Levon 	switch (insn->opcode) {
13671f5207b7SJohn Levon 	case OP_ENTRY: {
13681f5207b7SJohn Levon 		struct symbol *sym = insn->bb->ep->name;
13691f5207b7SJohn Levon 		const char *name = show_ident(sym->ident);
13701f5207b7SJohn Levon 		if (sym->ctype.modifiers & MOD_STATIC)
13711f5207b7SJohn Levon 			printf("\n\n%s:\n", name);
13721f5207b7SJohn Levon 		else
13731f5207b7SJohn Levon 			printf("\n\n.globl %s\n%s:\n", name, name);
13741f5207b7SJohn Levon 		break;
13751f5207b7SJohn Levon 	}
13761f5207b7SJohn Levon 
13771f5207b7SJohn Levon 	/*
13781f5207b7SJohn Levon 	 * OP_SETVAL likewise doesn't actually generate any
13791f5207b7SJohn Levon 	 * code. On use, the "def" of the pseudo will be
13801f5207b7SJohn Levon 	 * looked up.
13811f5207b7SJohn Levon 	 */
13821f5207b7SJohn Levon 	case OP_SETVAL:
13831f5207b7SJohn Levon 		break;
13841f5207b7SJohn Levon 
13851f5207b7SJohn Levon 	case OP_STORE:
13861f5207b7SJohn Levon 		generate_store(insn, state);
13871f5207b7SJohn Levon 		break;
13881f5207b7SJohn Levon 
13891f5207b7SJohn Levon 	case OP_LOAD:
13901f5207b7SJohn Levon 		generate_load(insn, state);
13911f5207b7SJohn Levon 		break;
13921f5207b7SJohn Levon 
13931f5207b7SJohn Levon 	case OP_DEATHNOTE:
13941f5207b7SJohn Levon 		mark_pseudo_dead(state, insn->target);
13951f5207b7SJohn Levon 		return;
13961f5207b7SJohn Levon 
13971f5207b7SJohn Levon 	case OP_COPY:
13981f5207b7SJohn Levon 		generate_copy(state, insn);
13991f5207b7SJohn Levon 		break;
14001f5207b7SJohn Levon 
1401*c85f09ccSJohn Levon 	case OP_ADD: case OP_MUL:
14021f5207b7SJohn Levon 	case OP_AND: case OP_OR: case OP_XOR:
14031f5207b7SJohn Levon 		generate_commutative_binop(state, insn);
14041f5207b7SJohn Levon 		break;
14051f5207b7SJohn Levon 
14061f5207b7SJohn Levon 	case OP_SUB: case OP_DIVU: case OP_DIVS:
14071f5207b7SJohn Levon 	case OP_MODU: case OP_MODS:
14081f5207b7SJohn Levon 	case OP_SHL: case OP_LSR: case OP_ASR:
14091f5207b7SJohn Levon  		generate_binop(state, insn);
14101f5207b7SJohn Levon 		break;
14111f5207b7SJohn Levon 
14121f5207b7SJohn Levon 	case OP_BINCMP ... OP_BINCMP_END:
14131f5207b7SJohn Levon 		generate_compare(state, insn);
14141f5207b7SJohn Levon 		break;
14151f5207b7SJohn Levon 
1416*c85f09ccSJohn Levon 	case OP_SEXT: case OP_ZEXT:
1417*c85f09ccSJohn Levon 	case OP_TRUNC:
1418*c85f09ccSJohn Levon 	case OP_PTRCAST:
1419*c85f09ccSJohn Levon 	case OP_UTPTR:
1420*c85f09ccSJohn Levon 	case OP_PTRTU:
1421*c85f09ccSJohn Levon 	case OP_FCVTU: case OP_FCVTS:
1422*c85f09ccSJohn Levon 	case OP_UCVTF: case OP_SCVTF:
1423*c85f09ccSJohn Levon 	case OP_FCVTF:
14241f5207b7SJohn Levon 		generate_cast(state, insn);
14251f5207b7SJohn Levon 		break;
14261f5207b7SJohn Levon 
14271f5207b7SJohn Levon 	case OP_SEL:
14281f5207b7SJohn Levon 		generate_select(state, insn);
14291f5207b7SJohn Levon 		break;
14301f5207b7SJohn Levon 
14311f5207b7SJohn Levon 	case OP_BR:
14321f5207b7SJohn Levon 	case OP_CBR:
14331f5207b7SJohn Levon 		generate_branch(state, insn);
14341f5207b7SJohn Levon 		break;
14351f5207b7SJohn Levon 
14361f5207b7SJohn Levon 	case OP_SWITCH:
14371f5207b7SJohn Levon 		generate_switch(state, insn);
14381f5207b7SJohn Levon 		break;
14391f5207b7SJohn Levon 
14401f5207b7SJohn Levon 	case OP_CALL:
14411f5207b7SJohn Levon 		generate_call(state, insn);
14421f5207b7SJohn Levon 		break;
14431f5207b7SJohn Levon 
14441f5207b7SJohn Levon 	case OP_RET:
14451f5207b7SJohn Levon 		generate_ret(state, insn);
14461f5207b7SJohn Levon 		break;
14471f5207b7SJohn Levon 
14481f5207b7SJohn Levon 	case OP_ASM:
14491f5207b7SJohn Levon 		generate_asm(state, insn);
14501f5207b7SJohn Levon 		break;
14511f5207b7SJohn Levon 
14521f5207b7SJohn Levon 	case OP_PHI:
14531f5207b7SJohn Levon 	case OP_PHISOURCE:
14541f5207b7SJohn Levon 	default:
14551f5207b7SJohn Levon 		output_insn(state, "unimplemented: %s", show_instruction(insn));
14561f5207b7SJohn Levon 		break;
14571f5207b7SJohn Levon 	}
14581f5207b7SJohn Levon 	kill_dead_pseudos(state);
14591f5207b7SJohn Levon }
14601f5207b7SJohn Levon 
14611f5207b7SJohn Levon #define VERY_BUSY 1000
14621f5207b7SJohn Levon #define REG_FIXED 2000
14631f5207b7SJohn Levon 
write_reg_to_storage(struct bb_state * state,struct hardreg * reg,pseudo_t pseudo,struct storage * storage)14641f5207b7SJohn Levon static void write_reg_to_storage(struct bb_state *state, struct hardreg *reg, pseudo_t pseudo, struct storage *storage)
14651f5207b7SJohn Levon {
14661f5207b7SJohn Levon 	int i;
14671f5207b7SJohn Levon 	struct hardreg *out;
14681f5207b7SJohn Levon 
14691f5207b7SJohn Levon 	switch (storage->type) {
14701f5207b7SJohn Levon 	case REG_REG:
14711f5207b7SJohn Levon 		out = hardregs + storage->regno;
14721f5207b7SJohn Levon 		if (reg == out)
14731f5207b7SJohn Levon 			return;
14741f5207b7SJohn Levon 		output_insn(state, "movl %s,%s", reg->name, out->name);
14751f5207b7SJohn Levon 		return;
14761f5207b7SJohn Levon 	case REG_UDEF:
14771f5207b7SJohn Levon 		if (reg->busy < VERY_BUSY) {
14781f5207b7SJohn Levon 			storage->type = REG_REG;
14791f5207b7SJohn Levon 			storage->regno = reg - hardregs;
14801f5207b7SJohn Levon 			reg->busy = REG_FIXED;
14811f5207b7SJohn Levon 			return;
14821f5207b7SJohn Levon 		}
14831f5207b7SJohn Levon 
14841f5207b7SJohn Levon 		/* Try to find a non-busy register.. */
14851f5207b7SJohn Levon 		for (i = 0; i < REGNO; i++) {
14861f5207b7SJohn Levon 			out = hardregs + i;
14871f5207b7SJohn Levon 			if (out->contains)
14881f5207b7SJohn Levon 				continue;
14891f5207b7SJohn Levon 			output_insn(state, "movl %s,%s", reg->name, out->name);
14901f5207b7SJohn Levon 			storage->type = REG_REG;
14911f5207b7SJohn Levon 			storage->regno = i;
14921f5207b7SJohn Levon 			out->busy = REG_FIXED;
14931f5207b7SJohn Levon 			return;
14941f5207b7SJohn Levon 		}
14951f5207b7SJohn Levon 
14961f5207b7SJohn Levon 		/* Fall back on stack allocation ... */
14971f5207b7SJohn Levon 		alloc_stack(state, storage);
14981f5207b7SJohn Levon 		/* Fall through */
14991f5207b7SJohn Levon 	default:
15001f5207b7SJohn Levon 		output_insn(state, "movl %s,%s", reg->name, show_memop(storage));
15011f5207b7SJohn Levon 		return;
15021f5207b7SJohn Levon 	}
15031f5207b7SJohn Levon }
15041f5207b7SJohn Levon 
write_val_to_storage(struct bb_state * state,pseudo_t src,struct storage * storage)15051f5207b7SJohn Levon static void write_val_to_storage(struct bb_state *state, pseudo_t src, struct storage *storage)
15061f5207b7SJohn Levon {
15071f5207b7SJohn Levon 	struct hardreg *out;
15081f5207b7SJohn Levon 
15091f5207b7SJohn Levon 	switch (storage->type) {
15101f5207b7SJohn Levon 	case REG_UDEF:
15111f5207b7SJohn Levon 		alloc_stack(state, storage);
15121f5207b7SJohn Levon 	default:
15131f5207b7SJohn Levon 		output_insn(state, "movl %s,%s", show_pseudo(src), show_memop(storage));
15141f5207b7SJohn Levon 		break;
15151f5207b7SJohn Levon 	case REG_REG:
15161f5207b7SJohn Levon 		out = hardregs + storage->regno;
15171f5207b7SJohn Levon 		output_insn(state, "movl %s,%s", show_pseudo(src), out->name);
15181f5207b7SJohn Levon 	}
15191f5207b7SJohn Levon }
15201f5207b7SJohn Levon 
fill_output(struct bb_state * state,pseudo_t pseudo,struct storage * out)15211f5207b7SJohn Levon static void fill_output(struct bb_state *state, pseudo_t pseudo, struct storage *out)
15221f5207b7SJohn Levon {
15231f5207b7SJohn Levon 	int i;
15241f5207b7SJohn Levon 	struct storage_hash *in;
15251f5207b7SJohn Levon 	struct instruction *def;
15261f5207b7SJohn Levon 
15271f5207b7SJohn Levon 	/* Is that pseudo a constant value? */
15281f5207b7SJohn Levon 	switch (pseudo->type) {
15291f5207b7SJohn Levon 	case PSEUDO_VAL:
15301f5207b7SJohn Levon 		write_val_to_storage(state, pseudo, out);
15311f5207b7SJohn Levon 		return;
15321f5207b7SJohn Levon 	case PSEUDO_REG:
15331f5207b7SJohn Levon 		def = pseudo->def;
15341f5207b7SJohn Levon 		if (def && def->opcode == OP_SETVAL) {
15351f5207b7SJohn Levon 			write_val_to_storage(state, pseudo, out);
15361f5207b7SJohn Levon 			return;
15371f5207b7SJohn Levon 		}
15381f5207b7SJohn Levon 	default:
15391f5207b7SJohn Levon 		break;
15401f5207b7SJohn Levon 	}
15411f5207b7SJohn Levon 
15421f5207b7SJohn Levon 	/* See if we have that pseudo in a register.. */
15431f5207b7SJohn Levon 	for (i = 0; i < REGNO; i++) {
15441f5207b7SJohn Levon 		struct hardreg *reg = hardregs + i;
15451f5207b7SJohn Levon 		pseudo_t p;
15461f5207b7SJohn Levon 
1547*c85f09ccSJohn Levon 		FOR_EACH_PTR_TAG(reg->contains, p) {
15481f5207b7SJohn Levon 			if (p == pseudo) {
15491f5207b7SJohn Levon 				write_reg_to_storage(state, reg, pseudo, out);
15501f5207b7SJohn Levon 				return;
15511f5207b7SJohn Levon 			}
15521f5207b7SJohn Levon 		} END_FOR_EACH_PTR(p);
15531f5207b7SJohn Levon 	}
15541f5207b7SJohn Levon 
15551f5207b7SJohn Levon 	/* Do we have it in another storage? */
15561f5207b7SJohn Levon 	in = find_storage_hash(pseudo, state->internal);
15571f5207b7SJohn Levon 	if (!in) {
15581f5207b7SJohn Levon 		in = find_storage_hash(pseudo, state->inputs);
15591f5207b7SJohn Levon 		/* Undefined? */
15601f5207b7SJohn Levon 		if (!in)
15611f5207b7SJohn Levon 			return;
15621f5207b7SJohn Levon 	}
15631f5207b7SJohn Levon 	switch (out->type) {
15641f5207b7SJohn Levon 	case REG_UDEF:
15651f5207b7SJohn Levon 		*out = *in->storage;
15661f5207b7SJohn Levon 		break;
15671f5207b7SJohn Levon 	case REG_REG:
15681f5207b7SJohn Levon 		output_insn(state, "movl %s,%s", show_memop(in->storage), hardregs[out->regno].name);
15691f5207b7SJohn Levon 		break;
15701f5207b7SJohn Levon 	default:
15711f5207b7SJohn Levon 		if (out == in->storage)
15721f5207b7SJohn Levon 			break;
15731f5207b7SJohn Levon 		if ((out->type == in->storage->type) && (out->regno == in->storage->regno))
15741f5207b7SJohn Levon 			break;
15751f5207b7SJohn Levon 		output_insn(state, "movl %s,%s", show_memop(in->storage), show_memop(out));
15761f5207b7SJohn Levon 		break;
15771f5207b7SJohn Levon 	}
15781f5207b7SJohn Levon 	return;
15791f5207b7SJohn Levon }
15801f5207b7SJohn Levon 
final_pseudo_flush(struct bb_state * state,pseudo_t pseudo,struct hardreg * reg)15811f5207b7SJohn Levon static int final_pseudo_flush(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
15821f5207b7SJohn Levon {
15831f5207b7SJohn Levon 	struct storage_hash *hash;
15841f5207b7SJohn Levon 	struct storage *out;
15851f5207b7SJohn Levon 	struct hardreg *dst;
15861f5207b7SJohn Levon 
15871f5207b7SJohn Levon 	/*
15881f5207b7SJohn Levon 	 * Since this pseudo is live at exit, we'd better have output
15891f5207b7SJohn Levon 	 * storage for it..
15901f5207b7SJohn Levon 	 */
15911f5207b7SJohn Levon 	hash = find_storage_hash(pseudo, state->outputs);
15921f5207b7SJohn Levon 	if (!hash)
15931f5207b7SJohn Levon 		return 1;
15941f5207b7SJohn Levon 	out = hash->storage;
15951f5207b7SJohn Levon 
15961f5207b7SJohn Levon 	/* If the output is in a register, try to get it there.. */
15971f5207b7SJohn Levon 	if (out->type == REG_REG) {
15981f5207b7SJohn Levon 		dst = hardregs + out->regno;
15991f5207b7SJohn Levon 		/*
16001f5207b7SJohn Levon 		 * Two good cases: nobody is using the right register,
16011f5207b7SJohn Levon 		 * or we've already set it aside for output..
16021f5207b7SJohn Levon 		 */
16031f5207b7SJohn Levon 		if (!dst->contains || dst->busy > VERY_BUSY)
16041f5207b7SJohn Levon 			goto copy_to_dst;
16051f5207b7SJohn Levon 
16061f5207b7SJohn Levon 		/* Aiee. Try to keep it in a register.. */
16071f5207b7SJohn Levon 		dst = empty_reg(state);
16081f5207b7SJohn Levon 		if (dst)
16091f5207b7SJohn Levon 			goto copy_to_dst;
16101f5207b7SJohn Levon 
16111f5207b7SJohn Levon 		return 0;
16121f5207b7SJohn Levon 	}
16131f5207b7SJohn Levon 
16141f5207b7SJohn Levon 	/* If the output is undefined, let's see if we can put it in a register.. */
16151f5207b7SJohn Levon 	if (out->type == REG_UDEF) {
16161f5207b7SJohn Levon 		dst = empty_reg(state);
16171f5207b7SJohn Levon 		if (dst) {
16181f5207b7SJohn Levon 			out->type = REG_REG;
16191f5207b7SJohn Levon 			out->regno = dst - hardregs;
16201f5207b7SJohn Levon 			goto copy_to_dst;
16211f5207b7SJohn Levon 		}
16221f5207b7SJohn Levon 		/* Uhhuh. Not so good. No empty registers right now */
16231f5207b7SJohn Levon 		return 0;
16241f5207b7SJohn Levon 	}
16251f5207b7SJohn Levon 
16261f5207b7SJohn Levon 	/* If we know we need to flush it, just do so already .. */
16271f5207b7SJohn Levon 	output_insn(state, "movl %s,%s", reg->name, show_memop(out));
16281f5207b7SJohn Levon 	return 1;
16291f5207b7SJohn Levon 
16301f5207b7SJohn Levon copy_to_dst:
16311f5207b7SJohn Levon 	if (reg == dst)
16321f5207b7SJohn Levon 		return 1;
16331f5207b7SJohn Levon 	output_insn(state, "movl %s,%s", reg->name, dst->name);
16341f5207b7SJohn Levon 	add_pseudo_reg(state, pseudo, dst);
16351f5207b7SJohn Levon 	return 1;
16361f5207b7SJohn Levon }
16371f5207b7SJohn Levon 
16381f5207b7SJohn Levon /*
16391f5207b7SJohn Levon  * This tries to make sure that we put all the pseudos that are
16401f5207b7SJohn Levon  * live on exit into the proper storage
16411f5207b7SJohn Levon  */
generate_output_storage(struct bb_state * state)16421f5207b7SJohn Levon static void generate_output_storage(struct bb_state *state)
16431f5207b7SJohn Levon {
16441f5207b7SJohn Levon 	struct storage_hash *entry;
16451f5207b7SJohn Levon 
16461f5207b7SJohn Levon 	/* Go through the fixed outputs, making sure we have those regs free */
16471f5207b7SJohn Levon 	FOR_EACH_PTR(state->outputs, entry) {
16481f5207b7SJohn Levon 		struct storage *out = entry->storage;
16491f5207b7SJohn Levon 		if (out->type == REG_REG) {
16501f5207b7SJohn Levon 			struct hardreg *reg = hardregs + out->regno;
16511f5207b7SJohn Levon 			pseudo_t p;
16521f5207b7SJohn Levon 			int flushme = 0;
16531f5207b7SJohn Levon 
16541f5207b7SJohn Levon 			reg->busy = REG_FIXED;
1655*c85f09ccSJohn Levon 			FOR_EACH_PTR_TAG(reg->contains, p) {
16561f5207b7SJohn Levon 				if (p == entry->pseudo) {
16571f5207b7SJohn Levon 					flushme = -100;
16581f5207b7SJohn Levon 					continue;
16591f5207b7SJohn Levon 				}
16601f5207b7SJohn Levon 				if (CURRENT_TAG(p) & TAG_DEAD)
16611f5207b7SJohn Levon 					continue;
16621f5207b7SJohn Levon 
16631f5207b7SJohn Levon 				/* Try to write back the pseudo to where it should go ... */
16641f5207b7SJohn Levon 				if (final_pseudo_flush(state, p, reg)) {
16651f5207b7SJohn Levon 					DELETE_CURRENT_PTR(p);
16661f5207b7SJohn Levon 					continue;
16671f5207b7SJohn Levon 				}
16681f5207b7SJohn Levon 				flushme++;
16691f5207b7SJohn Levon 			} END_FOR_EACH_PTR(p);
16701f5207b7SJohn Levon 			PACK_PTR_LIST(&reg->contains);
16711f5207b7SJohn Levon 			if (flushme > 0)
16721f5207b7SJohn Levon 				flush_reg(state, reg);
16731f5207b7SJohn Levon 		}
16741f5207b7SJohn Levon 	} END_FOR_EACH_PTR(entry);
16751f5207b7SJohn Levon 
16761f5207b7SJohn Levon 	FOR_EACH_PTR(state->outputs, entry) {
16771f5207b7SJohn Levon 		fill_output(state, entry->pseudo, entry->storage);
16781f5207b7SJohn Levon 	} END_FOR_EACH_PTR(entry);
16791f5207b7SJohn Levon }
16801f5207b7SJohn Levon 
generate(struct basic_block * bb,struct bb_state * state)16811f5207b7SJohn Levon static void generate(struct basic_block *bb, struct bb_state *state)
16821f5207b7SJohn Levon {
16831f5207b7SJohn Levon 	int i;
16841f5207b7SJohn Levon 	struct storage_hash *entry;
16851f5207b7SJohn Levon 	struct instruction *insn;
16861f5207b7SJohn Levon 
16871f5207b7SJohn Levon 	for (i = 0; i < REGNO; i++) {
16881f5207b7SJohn Levon 		free_ptr_list(&hardregs[i].contains);
16891f5207b7SJohn Levon 		hardregs[i].busy = 0;
16901f5207b7SJohn Levon 		hardregs[i].dead = 0;
16911f5207b7SJohn Levon 		hardregs[i].used = 0;
16921f5207b7SJohn Levon 	}
16931f5207b7SJohn Levon 
16941f5207b7SJohn Levon 	FOR_EACH_PTR(state->inputs, entry) {
16951f5207b7SJohn Levon 		struct storage *storage = entry->storage;
16961f5207b7SJohn Levon 		const char *name = show_storage(storage);
16971f5207b7SJohn Levon 		output_comment(state, "incoming %s in %s", show_pseudo(entry->pseudo), name);
16981f5207b7SJohn Levon 		if (storage->type == REG_REG) {
16991f5207b7SJohn Levon 			int regno = storage->regno;
17001f5207b7SJohn Levon 			add_pseudo_reg(state, entry->pseudo, hardregs + regno);
17011f5207b7SJohn Levon 			name = hardregs[regno].name;
17021f5207b7SJohn Levon 		}
17031f5207b7SJohn Levon 	} END_FOR_EACH_PTR(entry);
17041f5207b7SJohn Levon 
17051f5207b7SJohn Levon 	output_label(state, ".L%p", bb);
17061f5207b7SJohn Levon 	FOR_EACH_PTR(bb->insns, insn) {
17071f5207b7SJohn Levon 		if (!insn->bb)
17081f5207b7SJohn Levon 			continue;
17091f5207b7SJohn Levon 		generate_one_insn(insn, state);
17101f5207b7SJohn Levon 	} END_FOR_EACH_PTR(insn);
17111f5207b7SJohn Levon 
17121f5207b7SJohn Levon 	if (verbose) {
17131f5207b7SJohn Levon 		output_comment(state, "--- in ---");
17141f5207b7SJohn Levon 		FOR_EACH_PTR(state->inputs, entry) {
17151f5207b7SJohn Levon 			output_comment(state, "%s <- %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
17161f5207b7SJohn Levon 		} END_FOR_EACH_PTR(entry);
17171f5207b7SJohn Levon 		output_comment(state, "--- spill ---");
17181f5207b7SJohn Levon 		FOR_EACH_PTR(state->internal, entry) {
17191f5207b7SJohn Levon 			output_comment(state, "%s <-> %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
17201f5207b7SJohn Levon 		} END_FOR_EACH_PTR(entry);
17211f5207b7SJohn Levon 		output_comment(state, "--- out ---");
17221f5207b7SJohn Levon 		FOR_EACH_PTR(state->outputs, entry) {
17231f5207b7SJohn Levon 			output_comment(state, "%s -> %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
17241f5207b7SJohn Levon 		} END_FOR_EACH_PTR(entry);
17251f5207b7SJohn Levon 	}
17261f5207b7SJohn Levon 	printf("\n");
17271f5207b7SJohn Levon }
17281f5207b7SJohn Levon 
generate_list(struct basic_block_list * list,unsigned long generation)17291f5207b7SJohn Levon static void generate_list(struct basic_block_list *list, unsigned long generation)
17301f5207b7SJohn Levon {
17311f5207b7SJohn Levon 	struct basic_block *bb;
17321f5207b7SJohn Levon 	FOR_EACH_PTR(list, bb) {
17331f5207b7SJohn Levon 		if (bb->generation == generation)
17341f5207b7SJohn Levon 			continue;
17351f5207b7SJohn Levon 		output_bb(bb, generation);
17361f5207b7SJohn Levon 	} END_FOR_EACH_PTR(bb);
17371f5207b7SJohn Levon }
17381f5207b7SJohn Levon 
17391f5207b7SJohn Levon /*
17401f5207b7SJohn Levon  * Mark all the output registers of all the parents
17411f5207b7SJohn Levon  * as being "used" - this does not mean that we cannot
17421f5207b7SJohn Levon  * re-use them, but it means that we cannot ask the
17431f5207b7SJohn Levon  * parents to pass in another pseudo in one of those
17441f5207b7SJohn Levon  * registers that it already uses for another child.
17451f5207b7SJohn Levon  */
mark_used_registers(struct basic_block * bb,struct bb_state * state)17461f5207b7SJohn Levon static void mark_used_registers(struct basic_block *bb, struct bb_state *state)
17471f5207b7SJohn Levon {
17481f5207b7SJohn Levon 	struct basic_block *parent;
17491f5207b7SJohn Levon 
17501f5207b7SJohn Levon 	FOR_EACH_PTR(bb->parents, parent) {
17511f5207b7SJohn Levon 		struct storage_hash_list *outputs = gather_storage(parent, STOR_OUT);
17521f5207b7SJohn Levon 		struct storage_hash *entry;
17531f5207b7SJohn Levon 
17541f5207b7SJohn Levon 		FOR_EACH_PTR(outputs, entry) {
17551f5207b7SJohn Levon 			struct storage *s = entry->storage;
17561f5207b7SJohn Levon 			if (s->type == REG_REG) {
17571f5207b7SJohn Levon 				struct hardreg *reg = hardregs + s->regno;
17581f5207b7SJohn Levon 				reg->used = 1;
17591f5207b7SJohn Levon 			}
17601f5207b7SJohn Levon 		} END_FOR_EACH_PTR(entry);
17611f5207b7SJohn Levon 	} END_FOR_EACH_PTR(parent);
17621f5207b7SJohn Levon }
17631f5207b7SJohn Levon 
output_bb(struct basic_block * bb,unsigned long generation)17641f5207b7SJohn Levon static void output_bb(struct basic_block *bb, unsigned long generation)
17651f5207b7SJohn Levon {
17661f5207b7SJohn Levon 	struct bb_state state;
17671f5207b7SJohn Levon 
17681f5207b7SJohn Levon 	bb->generation = generation;
17691f5207b7SJohn Levon 
17701f5207b7SJohn Levon 	/* Make sure all parents have been generated first */
17711f5207b7SJohn Levon 	generate_list(bb->parents, generation);
17721f5207b7SJohn Levon 
17731f5207b7SJohn Levon 	state.pos = bb->pos;
17741f5207b7SJohn Levon 	state.inputs = gather_storage(bb, STOR_IN);
17751f5207b7SJohn Levon 	state.outputs = gather_storage(bb, STOR_OUT);
17761f5207b7SJohn Levon 	state.internal = NULL;
17771f5207b7SJohn Levon 	state.cc_opcode = 0;
17781f5207b7SJohn Levon 	state.cc_target = NULL;
17791f5207b7SJohn Levon 
17801f5207b7SJohn Levon 	/* Mark incoming registers used */
17811f5207b7SJohn Levon 	mark_used_registers(bb, &state);
17821f5207b7SJohn Levon 
17831f5207b7SJohn Levon 	generate(bb, &state);
17841f5207b7SJohn Levon 
17851f5207b7SJohn Levon 	free_ptr_list(&state.inputs);
17861f5207b7SJohn Levon 	free_ptr_list(&state.outputs);
17871f5207b7SJohn Levon 
17881f5207b7SJohn Levon 	/* Generate all children... */
17891f5207b7SJohn Levon 	generate_list(bb->children, generation);
17901f5207b7SJohn Levon }
17911f5207b7SJohn Levon 
17921f5207b7SJohn Levon /*
17931f5207b7SJohn Levon  * We should set up argument sources here..
17941f5207b7SJohn Levon  *
17951f5207b7SJohn Levon  * Things like "first three arguments in registers" etc
17961f5207b7SJohn Levon  * are all for this place.
17971f5207b7SJohn Levon  *
17981f5207b7SJohn Levon  * On x86, we default to stack, unless it's a static
17991f5207b7SJohn Levon  * function that doesn't have its address taken.
18001f5207b7SJohn Levon  *
18011f5207b7SJohn Levon  * I should implement the -mregparm=X cmd line option.
18021f5207b7SJohn Levon  */
set_up_arch_entry(struct entrypoint * ep,struct instruction * entry)18031f5207b7SJohn Levon static void set_up_arch_entry(struct entrypoint *ep, struct instruction *entry)
18041f5207b7SJohn Levon {
18051f5207b7SJohn Levon 	pseudo_t arg;
18061f5207b7SJohn Levon 	struct symbol *sym, *argtype;
18071f5207b7SJohn Levon 	int i, offset, regparm;
18081f5207b7SJohn Levon 
18091f5207b7SJohn Levon 	sym = ep->name;
18101f5207b7SJohn Levon 	regparm = 0;
18111f5207b7SJohn Levon 	if (!(sym->ctype.modifiers & MOD_ADDRESSABLE))
18121f5207b7SJohn Levon 		regparm = 3;
18131f5207b7SJohn Levon 	sym = sym->ctype.base_type;
18141f5207b7SJohn Levon 	i = 0;
18151f5207b7SJohn Levon 	offset = 0;
18161f5207b7SJohn Levon 	PREPARE_PTR_LIST(sym->arguments, argtype);
18171f5207b7SJohn Levon 	FOR_EACH_PTR(entry->arg_list, arg) {
18181f5207b7SJohn Levon 		struct storage *in = lookup_storage(entry->bb, arg, STOR_IN);
18191f5207b7SJohn Levon 		if (!in) {
18201f5207b7SJohn Levon 			in = alloc_storage();
18211f5207b7SJohn Levon 			add_storage(in, entry->bb, arg, STOR_IN);
18221f5207b7SJohn Levon 		}
18231f5207b7SJohn Levon 		if (i < regparm) {
18241f5207b7SJohn Levon 			in->type = REG_REG;
18251f5207b7SJohn Levon 			in->regno = i;
18261f5207b7SJohn Levon 		} else {
18271f5207b7SJohn Levon 			int bits = argtype ? argtype->bit_size : 0;
18281f5207b7SJohn Levon 
18291f5207b7SJohn Levon 			if (bits < bits_in_int)
18301f5207b7SJohn Levon 				bits = bits_in_int;
18311f5207b7SJohn Levon 
18321f5207b7SJohn Levon 			in->type = REG_FRAME;
18331f5207b7SJohn Levon 			in->offset = offset;
18341f5207b7SJohn Levon 
18351f5207b7SJohn Levon 			offset += bits_to_bytes(bits);
18361f5207b7SJohn Levon 		}
18371f5207b7SJohn Levon 		i++;
18381f5207b7SJohn Levon 		NEXT_PTR_LIST(argtype);
18391f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
18401f5207b7SJohn Levon 	FINISH_PTR_LIST(argtype);
18411f5207b7SJohn Levon }
18421f5207b7SJohn Levon 
18431f5207b7SJohn Levon /*
18441f5207b7SJohn Levon  * Set up storage information for "return"
18451f5207b7SJohn Levon  *
18461f5207b7SJohn Levon  * Not strictly necessary, since the code generator will
18471f5207b7SJohn Levon  * certainly move the return value to the right register,
18481f5207b7SJohn Levon  * but it can help register allocation if the allocator
18491f5207b7SJohn Levon  * sees that the target register is going to return in %eax.
18501f5207b7SJohn Levon  */
set_up_arch_exit(struct basic_block * bb,struct instruction * ret)18511f5207b7SJohn Levon static void set_up_arch_exit(struct basic_block *bb, struct instruction *ret)
18521f5207b7SJohn Levon {
18531f5207b7SJohn Levon 	pseudo_t pseudo = ret->src;
18541f5207b7SJohn Levon 
18551f5207b7SJohn Levon 	if (pseudo && pseudo != VOID) {
18561f5207b7SJohn Levon 		struct storage *out = lookup_storage(bb, pseudo, STOR_OUT);
18571f5207b7SJohn Levon 		if (!out) {
18581f5207b7SJohn Levon 			out = alloc_storage();
18591f5207b7SJohn Levon 			add_storage(out, bb, pseudo, STOR_OUT);
18601f5207b7SJohn Levon 		}
18611f5207b7SJohn Levon 		out->type = REG_REG;
18621f5207b7SJohn Levon 		out->regno = 0;
18631f5207b7SJohn Levon 	}
18641f5207b7SJohn Levon }
18651f5207b7SJohn Levon 
18661f5207b7SJohn Levon /*
18671f5207b7SJohn Levon  * Set up dummy/silly output storage information for a switch
18681f5207b7SJohn Levon  * instruction. We need to make sure that a register is available
18691f5207b7SJohn Levon  * when we generate code for switch, so force that by creating
18701f5207b7SJohn Levon  * a dummy output rule.
18711f5207b7SJohn Levon  */
set_up_arch_switch(struct basic_block * bb,struct instruction * insn)18721f5207b7SJohn Levon static void set_up_arch_switch(struct basic_block *bb, struct instruction *insn)
18731f5207b7SJohn Levon {
18741f5207b7SJohn Levon 	pseudo_t pseudo = insn->cond;
18751f5207b7SJohn Levon 	struct storage *out = lookup_storage(bb, pseudo, STOR_OUT);
18761f5207b7SJohn Levon 	if (!out) {
18771f5207b7SJohn Levon 		out = alloc_storage();
18781f5207b7SJohn Levon 		add_storage(out, bb, pseudo, STOR_OUT);
18791f5207b7SJohn Levon 	}
18801f5207b7SJohn Levon 	out->type = REG_REG;
18811f5207b7SJohn Levon 	out->regno = SWITCH_REG;
18821f5207b7SJohn Levon }
18831f5207b7SJohn Levon 
arch_set_up_storage(struct entrypoint * ep)18841f5207b7SJohn Levon static void arch_set_up_storage(struct entrypoint *ep)
18851f5207b7SJohn Levon {
18861f5207b7SJohn Levon 	struct basic_block *bb;
18871f5207b7SJohn Levon 
18881f5207b7SJohn Levon 	/* Argument storage etc.. */
18891f5207b7SJohn Levon 	set_up_arch_entry(ep, ep->entry);
18901f5207b7SJohn Levon 
18911f5207b7SJohn Levon 	FOR_EACH_PTR(ep->bbs, bb) {
18921f5207b7SJohn Levon 		struct instruction *insn = last_instruction(bb->insns);
18931f5207b7SJohn Levon 		if (!insn)
18941f5207b7SJohn Levon 			continue;
18951f5207b7SJohn Levon 		switch (insn->opcode) {
18961f5207b7SJohn Levon 		case OP_RET:
18971f5207b7SJohn Levon 			set_up_arch_exit(bb, insn);
18981f5207b7SJohn Levon 			break;
18991f5207b7SJohn Levon 		case OP_SWITCH:
19001f5207b7SJohn Levon 			set_up_arch_switch(bb, insn);
19011f5207b7SJohn Levon 			break;
19021f5207b7SJohn Levon 		default:
19031f5207b7SJohn Levon 			/* nothing */;
19041f5207b7SJohn Levon 		}
19051f5207b7SJohn Levon 	} END_FOR_EACH_PTR(bb);
19061f5207b7SJohn Levon }
19071f5207b7SJohn Levon 
output(struct entrypoint * ep)19081f5207b7SJohn Levon static void output(struct entrypoint *ep)
19091f5207b7SJohn Levon {
19101f5207b7SJohn Levon 	unsigned long generation = ++bb_generation;
19111f5207b7SJohn Levon 
19121f5207b7SJohn Levon 	last_reg = -1;
19131f5207b7SJohn Levon 	stack_offset = 0;
19141f5207b7SJohn Levon 
19151f5207b7SJohn Levon 	/* Get rid of SSA form (phinodes etc) */
19161f5207b7SJohn Levon 	unssa(ep);
19171f5207b7SJohn Levon 
19181f5207b7SJohn Levon 	/* Set up initial inter-bb storage links */
19191f5207b7SJohn Levon 	set_up_storage(ep);
19201f5207b7SJohn Levon 
19211f5207b7SJohn Levon 	/* Architecture-specific storage rules.. */
19221f5207b7SJohn Levon 	arch_set_up_storage(ep);
19231f5207b7SJohn Levon 
19241f5207b7SJohn Levon 	/* Show the results ... */
19251f5207b7SJohn Levon 	output_bb(ep->entry->bb, generation);
19261f5207b7SJohn Levon 
19271f5207b7SJohn Levon 	/* Clear the storage hashes for the next function.. */
19281f5207b7SJohn Levon 	free_storage();
19291f5207b7SJohn Levon }
19301f5207b7SJohn Levon 
compile(struct symbol_list * list)19311f5207b7SJohn Levon static int compile(struct symbol_list *list)
19321f5207b7SJohn Levon {
19331f5207b7SJohn Levon 	struct symbol *sym;
19341f5207b7SJohn Levon 	FOR_EACH_PTR(list, sym) {
19351f5207b7SJohn Levon 		struct entrypoint *ep;
19361f5207b7SJohn Levon 		expand_symbol(sym);
19371f5207b7SJohn Levon 		ep = linearize_symbol(sym);
19381f5207b7SJohn Levon 		if (ep)
19391f5207b7SJohn Levon 			output(ep);
19401f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sym);
19411f5207b7SJohn Levon 
19421f5207b7SJohn Levon 	return 0;
19431f5207b7SJohn Levon }
19441f5207b7SJohn Levon 
main(int argc,char ** argv)19451f5207b7SJohn Levon int main(int argc, char **argv)
19461f5207b7SJohn Levon {
19471f5207b7SJohn Levon 	struct string_list *filelist = NULL;
19481f5207b7SJohn Levon 	char *file;
19491f5207b7SJohn Levon 
19501f5207b7SJohn Levon 	compile(sparse_initialize(argc, argv, &filelist));
19511f5207b7SJohn Levon 	dbg_dead = 1;
1952*c85f09ccSJohn Levon 	FOR_EACH_PTR(filelist, file) {
19531f5207b7SJohn Levon 		compile(sparse(file));
1954*c85f09ccSJohn Levon 	} END_FOR_EACH_PTR(file);
19551f5207b7SJohn Levon 	return 0;
19561f5207b7SJohn Levon }
19571f5207b7SJohn Levon 
1958