11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * sparse/compile-i386.c
31f5207b7SJohn Levon  *
41f5207b7SJohn Levon  * Copyright (C) 2003 Transmeta Corp.
51f5207b7SJohn Levon  *               2003 Linus Torvalds
61f5207b7SJohn Levon  * Copyright 2003 Jeff Garzik
71f5207b7SJohn Levon  *
81f5207b7SJohn Levon  * Permission is hereby granted, free of charge, to any person obtaining a copy
91f5207b7SJohn Levon  * of this software and associated documentation files (the "Software"), to deal
101f5207b7SJohn Levon  * in the Software without restriction, including without limitation the rights
111f5207b7SJohn Levon  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
121f5207b7SJohn Levon  * copies of the Software, and to permit persons to whom the Software is
131f5207b7SJohn Levon  * furnished to do so, subject to the following conditions:
141f5207b7SJohn Levon  *
151f5207b7SJohn Levon  * The above copyright notice and this permission notice shall be included in
161f5207b7SJohn Levon  * all copies or substantial portions of the Software.
171f5207b7SJohn Levon  *
181f5207b7SJohn Levon  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
191f5207b7SJohn Levon  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
201f5207b7SJohn Levon  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
211f5207b7SJohn Levon  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
221f5207b7SJohn Levon  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
231f5207b7SJohn Levon  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
241f5207b7SJohn Levon  * THE SOFTWARE.
251f5207b7SJohn Levon  *
261f5207b7SJohn Levon  * x86 backend
271f5207b7SJohn Levon  *
281f5207b7SJohn Levon  * TODO list:
291f5207b7SJohn Levon  * in general, any non-32bit SYM_BASETYPE is unlikely to work.
301f5207b7SJohn Levon  * complex initializers
311f5207b7SJohn Levon  * bitfields
321f5207b7SJohn Levon  * global struct/union variables
331f5207b7SJohn Levon  * addressing structures, and members of structures (as opposed to
341f5207b7SJohn Levon  *     scalars) on the stack.  Requires smarter stack frame allocation.
351f5207b7SJohn Levon  * labels / goto
361f5207b7SJohn Levon  * any function argument that isn't 32 bits (or promoted to such)
371f5207b7SJohn Levon  * inline asm
381f5207b7SJohn Levon  * floating point
391f5207b7SJohn Levon  *
401f5207b7SJohn Levon  */
411f5207b7SJohn Levon #include <stdarg.h>
421f5207b7SJohn Levon #include <stdlib.h>
431f5207b7SJohn Levon #include <stdio.h>
441f5207b7SJohn Levon #include <string.h>
451f5207b7SJohn Levon #include <ctype.h>
461f5207b7SJohn Levon #include <unistd.h>
471f5207b7SJohn Levon #include <fcntl.h>
481f5207b7SJohn Levon #include <assert.h>
491f5207b7SJohn Levon 
501f5207b7SJohn Levon #include "lib.h"
511f5207b7SJohn Levon #include "allocate.h"
521f5207b7SJohn Levon #include "token.h"
531f5207b7SJohn Levon #include "parse.h"
541f5207b7SJohn Levon #include "symbol.h"
551f5207b7SJohn Levon #include "scope.h"
561f5207b7SJohn Levon #include "expression.h"
571f5207b7SJohn Levon #include "target.h"
581f5207b7SJohn Levon #include "compile.h"
591f5207b7SJohn Levon #include "bitmap.h"
601f5207b7SJohn Levon #include "version.h"
611f5207b7SJohn Levon 
621f5207b7SJohn Levon struct textbuf {
631f5207b7SJohn Levon 	unsigned int	len;	/* does NOT include terminating null */
641f5207b7SJohn Levon 	char		*text;
651f5207b7SJohn Levon 	struct textbuf	*next;
661f5207b7SJohn Levon 	struct textbuf	*prev;
671f5207b7SJohn Levon };
681f5207b7SJohn Levon 
691f5207b7SJohn Levon struct loop_stack {
701f5207b7SJohn Levon 	int		continue_lbl;
711f5207b7SJohn Levon 	int		loop_bottom_lbl;
721f5207b7SJohn Levon 	struct loop_stack *next;
731f5207b7SJohn Levon };
741f5207b7SJohn Levon 
751f5207b7SJohn Levon struct atom;
761f5207b7SJohn Levon struct storage;
771f5207b7SJohn Levon DECLARE_PTR_LIST(str_list, struct atom);
781f5207b7SJohn Levon DECLARE_PTR_LIST(atom_list, struct atom);
791f5207b7SJohn Levon DECLARE_PTR_LIST(storage_list, struct storage);
801f5207b7SJohn Levon 
811f5207b7SJohn Levon struct function {
821f5207b7SJohn Levon 	int stack_size;
831f5207b7SJohn Levon 	int pseudo_nr;
841f5207b7SJohn Levon 	struct storage_list *pseudo_list;
851f5207b7SJohn Levon 	struct atom_list *atom_list;
861f5207b7SJohn Levon 	struct str_list *str_list;
871f5207b7SJohn Levon 	struct loop_stack *loop_stack;
881f5207b7SJohn Levon 	struct symbol **argv;
891f5207b7SJohn Levon 	unsigned int argc;
901f5207b7SJohn Levon 	int ret_target;
911f5207b7SJohn Levon };
921f5207b7SJohn Levon 
931f5207b7SJohn Levon enum storage_type {
941f5207b7SJohn Levon 	STOR_PSEUDO,	/* variable stored on the stack */
951f5207b7SJohn Levon 	STOR_ARG,	/* function argument */
961f5207b7SJohn Levon 	STOR_SYM,	/* a symbol we can directly ref in the asm */
971f5207b7SJohn Levon 	STOR_REG,	/* scratch register */
981f5207b7SJohn Levon 	STOR_VALUE,	/* integer constant */
991f5207b7SJohn Levon 	STOR_LABEL,	/* label / jump target */
1001f5207b7SJohn Levon 	STOR_LABELSYM,	/* label generated from symbol's pointer value */
1011f5207b7SJohn Levon };
1021f5207b7SJohn Levon 
1031f5207b7SJohn Levon struct reg_info {
1041f5207b7SJohn Levon 	const char	*name;
1051f5207b7SJohn Levon 	struct storage	*contains;
1061f5207b7SJohn Levon 	const unsigned char aliases[12];
1071f5207b7SJohn Levon #define own_regno aliases[0]
1081f5207b7SJohn Levon };
1091f5207b7SJohn Levon 
1101f5207b7SJohn Levon struct storage {
1111f5207b7SJohn Levon 	enum storage_type type;
1121f5207b7SJohn Levon 	unsigned long flags;
1131f5207b7SJohn Levon 
1141f5207b7SJohn Levon 	/* STOR_REG */
1151f5207b7SJohn Levon 	struct reg_info *reg;
1161f5207b7SJohn Levon 	struct symbol *ctype;
1171f5207b7SJohn Levon 
1181f5207b7SJohn Levon 	union {
1191f5207b7SJohn Levon 		/* STOR_PSEUDO */
1201f5207b7SJohn Levon 		struct {
1211f5207b7SJohn Levon 			int pseudo;
1221f5207b7SJohn Levon 			int offset;
1231f5207b7SJohn Levon 			int size;
1241f5207b7SJohn Levon 		};
1251f5207b7SJohn Levon 		/* STOR_ARG */
1261f5207b7SJohn Levon 		struct {
1271f5207b7SJohn Levon 			int idx;
1281f5207b7SJohn Levon 		};
1291f5207b7SJohn Levon 		/* STOR_SYM */
1301f5207b7SJohn Levon 		struct {
1311f5207b7SJohn Levon 			struct symbol *sym;
1321f5207b7SJohn Levon 		};
1331f5207b7SJohn Levon 		/* STOR_VALUE */
1341f5207b7SJohn Levon 		struct {
1351f5207b7SJohn Levon 			long long value;
1361f5207b7SJohn Levon 		};
1371f5207b7SJohn Levon 		/* STOR_LABEL */
1381f5207b7SJohn Levon 		struct {
1391f5207b7SJohn Levon 			int label;
1401f5207b7SJohn Levon 		};
1411f5207b7SJohn Levon 		/* STOR_LABELSYM */
1421f5207b7SJohn Levon 		struct {
1431f5207b7SJohn Levon 			struct symbol *labelsym;
1441f5207b7SJohn Levon 		};
1451f5207b7SJohn Levon 	};
1461f5207b7SJohn Levon };
1471f5207b7SJohn Levon 
1481f5207b7SJohn Levon enum {
1491f5207b7SJohn Levon 	STOR_LABEL_VAL	= (1 << 0),
1501f5207b7SJohn Levon 	STOR_WANTS_FREE	= (1 << 1),
1511f5207b7SJohn Levon };
1521f5207b7SJohn Levon 
1531f5207b7SJohn Levon struct symbol_private {
1541f5207b7SJohn Levon 	struct storage *addr;
1551f5207b7SJohn Levon };
1561f5207b7SJohn Levon 
1571f5207b7SJohn Levon enum atom_type {
1581f5207b7SJohn Levon 	ATOM_TEXT,
1591f5207b7SJohn Levon 	ATOM_INSN,
1601f5207b7SJohn Levon 	ATOM_CSTR,
1611f5207b7SJohn Levon };
1621f5207b7SJohn Levon 
1631f5207b7SJohn Levon struct atom {
1641f5207b7SJohn Levon 	enum atom_type type;
1651f5207b7SJohn Levon 	union {
1661f5207b7SJohn Levon 		/* stuff for text */
1671f5207b7SJohn Levon 		struct {
1681f5207b7SJohn Levon 			char *text;
1691f5207b7SJohn Levon 			unsigned int text_len;  /* w/o terminating null */
1701f5207b7SJohn Levon 		};
1711f5207b7SJohn Levon 
1721f5207b7SJohn Levon 		/* stuff for insns */
1731f5207b7SJohn Levon 		struct {
1741f5207b7SJohn Levon 			char insn[32];
1751f5207b7SJohn Levon 			char comment[40];
1761f5207b7SJohn Levon 			struct storage *op1;
1771f5207b7SJohn Levon 			struct storage *op2;
1781f5207b7SJohn Levon 		};
1791f5207b7SJohn Levon 
1801f5207b7SJohn Levon 		/* stuff for C strings */
1811f5207b7SJohn Levon 		struct {
1821f5207b7SJohn Levon 			struct string *string;
1831f5207b7SJohn Levon 			int label;
1841f5207b7SJohn Levon 		};
1851f5207b7SJohn Levon 	};
1861f5207b7SJohn Levon };
1871f5207b7SJohn Levon 
1881f5207b7SJohn Levon 
1891f5207b7SJohn Levon static struct function *current_func = NULL;
1901f5207b7SJohn Levon static struct textbuf *unit_post_text = NULL;
1911f5207b7SJohn Levon static const char *current_section;
1921f5207b7SJohn Levon 
1931f5207b7SJohn Levon static void emit_comment(const char * fmt, ...) FORMAT_ATTR(1);
1941f5207b7SJohn Levon static void emit_move(struct storage *src, struct storage *dest,
1951f5207b7SJohn Levon 		      struct symbol *ctype, const char *comment);
1961f5207b7SJohn Levon static struct storage *x86_address_gen(struct expression *expr);
1971f5207b7SJohn Levon static struct storage *x86_symbol_expr(struct symbol *sym);
1981f5207b7SJohn Levon static void x86_symbol(struct symbol *sym);
1991f5207b7SJohn Levon static struct storage *x86_statement(struct statement *stmt);
2001f5207b7SJohn Levon static struct storage *x86_expression(struct expression *expr);
2011f5207b7SJohn Levon 
2021f5207b7SJohn Levon enum registers {
2031f5207b7SJohn Levon 	NOREG,
2041f5207b7SJohn Levon 	 AL,  DL,  CL,  BL,  AH,  DH,  CH,  BH,	// 8-bit
2051f5207b7SJohn Levon 	 AX,  DX,  CX,  BX,  SI,  DI,  BP,  SP,	// 16-bit
2061f5207b7SJohn Levon 	EAX, EDX, ECX, EBX, ESI, EDI, EBP, ESP,	// 32-bit
2071f5207b7SJohn Levon 	EAX_EDX, ECX_EBX, ESI_EDI,		// 64-bit
2081f5207b7SJohn Levon };
2091f5207b7SJohn Levon 
2101f5207b7SJohn Levon /* This works on regno's, reg_info's and hardreg_storage's */
2111f5207b7SJohn Levon #define byte_reg(reg) ((reg) - 16)
2121f5207b7SJohn Levon #define highbyte_reg(reg) ((reg)-12)
2131f5207b7SJohn Levon #define word_reg(reg) ((reg)-8)
2141f5207b7SJohn Levon 
2151f5207b7SJohn Levon #define REGINFO(nr, str, conflicts...)	[nr] = { .name = str, .aliases = { nr , conflicts } }
2161f5207b7SJohn Levon 
2171f5207b7SJohn Levon static struct reg_info reg_info_table[] = {
2181f5207b7SJohn Levon 	REGINFO( AL,  "%al", AX, EAX, EAX_EDX),
2191f5207b7SJohn Levon 	REGINFO( DL,  "%dl", DX, EDX, EAX_EDX),
2201f5207b7SJohn Levon 	REGINFO( CL,  "%cl", CX, ECX, ECX_EBX),
2211f5207b7SJohn Levon 	REGINFO( BL,  "%bl", BX, EBX, ECX_EBX),
2221f5207b7SJohn Levon 	REGINFO( AH,  "%ah", AX, EAX, EAX_EDX),
2231f5207b7SJohn Levon 	REGINFO( DH,  "%dh", DX, EDX, EAX_EDX),
2241f5207b7SJohn Levon 	REGINFO( CH,  "%ch", CX, ECX, ECX_EBX),
2251f5207b7SJohn Levon 	REGINFO( BH,  "%bh", BX, EBX, ECX_EBX),
2261f5207b7SJohn Levon 	REGINFO( AX,  "%ax", AL, AH, EAX, EAX_EDX),
2271f5207b7SJohn Levon 	REGINFO( DX,  "%dx", DL, DH, EDX, EAX_EDX),
2281f5207b7SJohn Levon 	REGINFO( CX,  "%cx", CL, CH, ECX, ECX_EBX),
2291f5207b7SJohn Levon 	REGINFO( BX,  "%bx", BL, BH, EBX, ECX_EBX),
2301f5207b7SJohn Levon 	REGINFO( SI,  "%si", ESI, ESI_EDI),
2311f5207b7SJohn Levon 	REGINFO( DI,  "%di", EDI, ESI_EDI),
2321f5207b7SJohn Levon 	REGINFO( BP,  "%bp", EBP),
2331f5207b7SJohn Levon 	REGINFO( SP,  "%sp", ESP),
2341f5207b7SJohn Levon 	REGINFO(EAX, "%eax", AL, AH, AX, EAX_EDX),
2351f5207b7SJohn Levon 	REGINFO(EDX, "%edx", DL, DH, DX, EAX_EDX),
2361f5207b7SJohn Levon 	REGINFO(ECX, "%ecx", CL, CH, CX, ECX_EBX),
2371f5207b7SJohn Levon 	REGINFO(EBX, "%ebx", BL, BH, BX, ECX_EBX),
2381f5207b7SJohn Levon 	REGINFO(ESI, "%esi", SI, ESI_EDI),
2391f5207b7SJohn Levon 	REGINFO(EDI, "%edi", DI, ESI_EDI),
2401f5207b7SJohn Levon 	REGINFO(EBP, "%ebp", BP),
2411f5207b7SJohn Levon 	REGINFO(ESP, "%esp", SP),
2421f5207b7SJohn Levon 	REGINFO(EAX_EDX, "%eax:%edx", AL, AH, AX, EAX, DL, DH, DX, EDX),
2431f5207b7SJohn Levon 	REGINFO(ECX_EBX, "%ecx:%ebx", CL, CH, CX, ECX, BL, BH, BX, EBX),
2441f5207b7SJohn Levon 	REGINFO(ESI_EDI, "%esi:%edi", SI, ESI, DI, EDI),
2451f5207b7SJohn Levon };
2461f5207b7SJohn Levon 
2471f5207b7SJohn Levon #define REGSTORAGE(nr) [nr] = { .type = STOR_REG, .reg = reg_info_table + (nr) }
2481f5207b7SJohn Levon 
2491f5207b7SJohn Levon static struct storage hardreg_storage_table[] = {
2501f5207b7SJohn Levon 	REGSTORAGE(AL), REGSTORAGE(DL), REGSTORAGE(CL), REGSTORAGE(BL),
2511f5207b7SJohn Levon 	REGSTORAGE(AH), REGSTORAGE(DH), REGSTORAGE(CH), REGSTORAGE(BH),
2521f5207b7SJohn Levon 	REGSTORAGE(AX), REGSTORAGE(DX), REGSTORAGE(CX), REGSTORAGE(BX),
2531f5207b7SJohn Levon 	REGSTORAGE(SI), REGSTORAGE(DI), REGSTORAGE(BP), REGSTORAGE(SP),
2541f5207b7SJohn Levon 	REGSTORAGE(EAX), REGSTORAGE(EDX), REGSTORAGE(ECX), REGSTORAGE(EBX),
2551f5207b7SJohn Levon 	REGSTORAGE(ESI), REGSTORAGE(EDI), REGSTORAGE(EBP), REGSTORAGE(ESP),
2561f5207b7SJohn Levon 	REGSTORAGE(EAX_EDX), REGSTORAGE(ECX_EBX), REGSTORAGE(ESI_EDI),
2571f5207b7SJohn Levon };
2581f5207b7SJohn Levon 
2591f5207b7SJohn Levon #define REG_EAX (&hardreg_storage_table[EAX])
2601f5207b7SJohn Levon #define REG_ECX (&hardreg_storage_table[ECX])
2611f5207b7SJohn Levon #define REG_EDX (&hardreg_storage_table[EDX])
2621f5207b7SJohn Levon #define REG_ESP (&hardreg_storage_table[ESP])
2631f5207b7SJohn Levon #define REG_DL	(&hardreg_storage_table[DL])
2641f5207b7SJohn Levon #define REG_DX	(&hardreg_storage_table[DX])
2651f5207b7SJohn Levon #define REG_AL	(&hardreg_storage_table[AL])
2661f5207b7SJohn Levon #define REG_AX	(&hardreg_storage_table[AX])
2671f5207b7SJohn Levon 
2681f5207b7SJohn Levon static DECLARE_BITMAP(regs_in_use, 256);
2691f5207b7SJohn Levon 
reginfo_reg(struct reg_info * info)2701f5207b7SJohn Levon static inline struct storage * reginfo_reg(struct reg_info *info)
2711f5207b7SJohn Levon {
2721f5207b7SJohn Levon 	return hardreg_storage_table + info->own_regno;
2731f5207b7SJohn Levon }
2741f5207b7SJohn Levon 
get_hardreg(struct storage * reg,int clear)2751f5207b7SJohn Levon static struct storage * get_hardreg(struct storage *reg, int clear)
2761f5207b7SJohn Levon {
2771f5207b7SJohn Levon 	struct reg_info *info = reg->reg;
2781f5207b7SJohn Levon 	const unsigned char *aliases;
2791f5207b7SJohn Levon 	int regno;
2801f5207b7SJohn Levon 
2811f5207b7SJohn Levon 	aliases = info->aliases;
2821f5207b7SJohn Levon 	while ((regno = *aliases++) != NOREG) {
2831f5207b7SJohn Levon 		if (test_bit(regno, regs_in_use))
2841f5207b7SJohn Levon 			goto busy;
2851f5207b7SJohn Levon 		if (clear)
2861f5207b7SJohn Levon 			reg_info_table[regno].contains = NULL;
2871f5207b7SJohn Levon 	}
2881f5207b7SJohn Levon 	set_bit(info->own_regno, regs_in_use);
2891f5207b7SJohn Levon 	return reg;
2901f5207b7SJohn Levon busy:
2911f5207b7SJohn Levon 	fprintf(stderr, "register %s is busy\n", info->name);
2921f5207b7SJohn Levon 	if (regno + reg_info_table != info)
2931f5207b7SJohn Levon 		fprintf(stderr, "  conflicts with %s\n", reg_info_table[regno].name);
2941f5207b7SJohn Levon 	exit(1);
2951f5207b7SJohn Levon }
2961f5207b7SJohn Levon 
put_reg(struct storage * reg)2971f5207b7SJohn Levon static void put_reg(struct storage *reg)
2981f5207b7SJohn Levon {
2991f5207b7SJohn Levon 	struct reg_info *info = reg->reg;
3001f5207b7SJohn Levon 	int regno = info->own_regno;
3011f5207b7SJohn Levon 
3021f5207b7SJohn Levon 	if (test_and_clear_bit(regno, regs_in_use))
3031f5207b7SJohn Levon 		return;
3041f5207b7SJohn Levon 	fprintf(stderr, "freeing already free'd register %s\n", reg_info_table[regno].name);
3051f5207b7SJohn Levon }
3061f5207b7SJohn Levon 
3071f5207b7SJohn Levon struct regclass {
3081f5207b7SJohn Levon 	const char *name;
3091f5207b7SJohn Levon 	const unsigned char regs[30];
3101f5207b7SJohn Levon };
3111f5207b7SJohn Levon 
3121f5207b7SJohn Levon static struct regclass regclass_8 = { "8-bit", { AL, DL, CL, BL, AH, DH, CH, BH }};
3131f5207b7SJohn Levon static struct regclass regclass_16 = { "16-bit", { AX, DX, CX, BX, SI, DI, BP }};
3141f5207b7SJohn Levon static struct regclass regclass_32 = { "32-bit", { EAX, EDX, ECX, EBX, ESI, EDI, EBP }};
3151f5207b7SJohn Levon static struct regclass regclass_64 = { "64-bit", { EAX_EDX, ECX_EBX, ESI_EDI }};
3161f5207b7SJohn Levon 
3171f5207b7SJohn Levon static struct regclass regclass_32_8 = { "32-bit bytes", { EAX, EDX, ECX, EBX }};
3181f5207b7SJohn Levon 
get_regclass_bits(int bits)3191f5207b7SJohn Levon static struct regclass *get_regclass_bits(int bits)
3201f5207b7SJohn Levon {
3211f5207b7SJohn Levon 	switch (bits) {
3221f5207b7SJohn Levon 	case 8: return &regclass_8;
3231f5207b7SJohn Levon 	case 16: return &regclass_16;
3241f5207b7SJohn Levon 	case 64: return &regclass_64;
3251f5207b7SJohn Levon 	default: return &regclass_32;
3261f5207b7SJohn Levon 	}
3271f5207b7SJohn Levon }
3281f5207b7SJohn Levon 
get_regclass(struct expression * expr)3291f5207b7SJohn Levon static struct regclass *get_regclass(struct expression *expr)
3301f5207b7SJohn Levon {
3311f5207b7SJohn Levon 	return get_regclass_bits(expr->ctype->bit_size);
3321f5207b7SJohn Levon }
3331f5207b7SJohn Levon 
register_busy(int regno)3341f5207b7SJohn Levon static int register_busy(int regno)
3351f5207b7SJohn Levon {
3361f5207b7SJohn Levon 	if (!test_bit(regno, regs_in_use)) {
3371f5207b7SJohn Levon 		struct reg_info *info = reg_info_table + regno;
3381f5207b7SJohn Levon 		const unsigned char *regs = info->aliases+1;
3391f5207b7SJohn Levon 
3401f5207b7SJohn Levon 		while ((regno = *regs) != NOREG) {
3411f5207b7SJohn Levon 			regs++;
3421f5207b7SJohn Levon 			if (test_bit(regno, regs_in_use))
3431f5207b7SJohn Levon 				goto busy;
3441f5207b7SJohn Levon 		}
3451f5207b7SJohn Levon 		return 0;
3461f5207b7SJohn Levon 	}
3471f5207b7SJohn Levon busy:
3481f5207b7SJohn Levon 	return 1;
3491f5207b7SJohn Levon }
3501f5207b7SJohn Levon 
get_reg(struct regclass * class)3511f5207b7SJohn Levon static struct storage *get_reg(struct regclass *class)
3521f5207b7SJohn Levon {
3531f5207b7SJohn Levon 	const unsigned char *regs = class->regs;
3541f5207b7SJohn Levon 	int regno;
3551f5207b7SJohn Levon 
3561f5207b7SJohn Levon 	while ((regno = *regs) != NOREG) {
3571f5207b7SJohn Levon 		regs++;
3581f5207b7SJohn Levon 		if (register_busy(regno))
3591f5207b7SJohn Levon 			continue;
3601f5207b7SJohn Levon 		return get_hardreg(hardreg_storage_table + regno, 1);
3611f5207b7SJohn Levon 	}
3621f5207b7SJohn Levon 	fprintf(stderr, "Ran out of %s registers\n", class->name);
3631f5207b7SJohn Levon 	exit(1);
3641f5207b7SJohn Levon }
3651f5207b7SJohn Levon 
get_reg_value(struct storage * value,struct regclass * class)3661f5207b7SJohn Levon static struct storage *get_reg_value(struct storage *value, struct regclass *class)
3671f5207b7SJohn Levon {
3681f5207b7SJohn Levon 	struct reg_info *info;
3691f5207b7SJohn Levon 	struct storage *reg;
3701f5207b7SJohn Levon 
3711f5207b7SJohn Levon 	/* Do we already have it somewhere */
3721f5207b7SJohn Levon 	info = value->reg;
3731f5207b7SJohn Levon 	if (info && info->contains == value) {
3741f5207b7SJohn Levon 		emit_comment("already have register %s", info->name);
3751f5207b7SJohn Levon 		return get_hardreg(hardreg_storage_table + info->own_regno, 0);
3761f5207b7SJohn Levon 	}
3771f5207b7SJohn Levon 
3781f5207b7SJohn Levon 	reg = get_reg(class);
3791f5207b7SJohn Levon 	emit_move(value, reg, value->ctype, "reload register");
3801f5207b7SJohn Levon 	info = reg->reg;
3811f5207b7SJohn Levon 	info->contains = value;
3821f5207b7SJohn Levon 	value->reg = info;
3831f5207b7SJohn Levon 	return reg;
3841f5207b7SJohn Levon }
3851f5207b7SJohn Levon 
temp_from_bits(unsigned int bit_size)3861f5207b7SJohn Levon static struct storage *temp_from_bits(unsigned int bit_size)
3871f5207b7SJohn Levon {
3881f5207b7SJohn Levon 	return get_reg(get_regclass_bits(bit_size));
3891f5207b7SJohn Levon }
3901f5207b7SJohn Levon 
pseudo_offset(struct storage * s)3911f5207b7SJohn Levon static inline unsigned int pseudo_offset(struct storage *s)
3921f5207b7SJohn Levon {
3931f5207b7SJohn Levon 	if (s->type != STOR_PSEUDO)
3941f5207b7SJohn Levon 		return 123456;	/* intentionally bogus value */
3951f5207b7SJohn Levon 
3961f5207b7SJohn Levon 	return s->offset;
3971f5207b7SJohn Levon }
3981f5207b7SJohn Levon 
arg_offset(struct storage * s)3991f5207b7SJohn Levon static inline unsigned int arg_offset(struct storage *s)
4001f5207b7SJohn Levon {
4011f5207b7SJohn Levon 	if (s->type != STOR_ARG)
4021f5207b7SJohn Levon 		return 123456;	/* intentionally bogus value */
4031f5207b7SJohn Levon 
4041f5207b7SJohn Levon 	/* FIXME: this is wrong wrong wrong */
4051f5207b7SJohn Levon 	return current_func->stack_size + ((1 + s->idx) * 4);
4061f5207b7SJohn Levon }
4071f5207b7SJohn Levon 
pretty_offset(int ofs)4081f5207b7SJohn Levon static const char *pretty_offset(int ofs)
4091f5207b7SJohn Levon {
4101f5207b7SJohn Levon 	static char esp_buf[64];
4111f5207b7SJohn Levon 
4121f5207b7SJohn Levon 	if (ofs)
4131f5207b7SJohn Levon 		sprintf(esp_buf, "%d(%%esp)", ofs);
4141f5207b7SJohn Levon 	else
4151f5207b7SJohn Levon 		strcpy(esp_buf, "(%esp)");
4161f5207b7SJohn Levon 
4171f5207b7SJohn Levon 	return esp_buf;
4181f5207b7SJohn Levon }
4191f5207b7SJohn Levon 
stor_sym_init(struct symbol * sym)4201f5207b7SJohn Levon static void stor_sym_init(struct symbol *sym)
4211f5207b7SJohn Levon {
4221f5207b7SJohn Levon 	struct storage *stor;
4231f5207b7SJohn Levon 	struct symbol_private *priv;
4241f5207b7SJohn Levon 
4251f5207b7SJohn Levon 	priv = calloc(1, sizeof(*priv) + sizeof(*stor));
4261f5207b7SJohn Levon 	if (!priv)
4271f5207b7SJohn Levon 		die("OOM in stor_sym_init");
4281f5207b7SJohn Levon 
4291f5207b7SJohn Levon 	stor = (struct storage *) (priv + 1);
4301f5207b7SJohn Levon 
4311f5207b7SJohn Levon 	priv->addr = stor;
4321f5207b7SJohn Levon 	stor->type = STOR_SYM;
4331f5207b7SJohn Levon 	stor->sym = sym;
4341f5207b7SJohn Levon }
4351f5207b7SJohn Levon 
stor_op_name(struct storage * s)4361f5207b7SJohn Levon static const char *stor_op_name(struct storage *s)
4371f5207b7SJohn Levon {
4381f5207b7SJohn Levon 	static char name[32];
4391f5207b7SJohn Levon 
4401f5207b7SJohn Levon 	switch (s->type) {
4411f5207b7SJohn Levon 	case STOR_PSEUDO:
4421f5207b7SJohn Levon 		strcpy(name, pretty_offset((int) pseudo_offset(s)));
4431f5207b7SJohn Levon 		break;
4441f5207b7SJohn Levon 	case STOR_ARG:
4451f5207b7SJohn Levon 		strcpy(name, pretty_offset((int) arg_offset(s)));
4461f5207b7SJohn Levon 		break;
4471f5207b7SJohn Levon 	case STOR_SYM:
4481f5207b7SJohn Levon 		strcpy(name, show_ident(s->sym->ident));
4491f5207b7SJohn Levon 		break;
4501f5207b7SJohn Levon 	case STOR_REG:
4511f5207b7SJohn Levon 		strcpy(name, s->reg->name);
4521f5207b7SJohn Levon 		break;
4531f5207b7SJohn Levon 	case STOR_VALUE:
454*c85f09ccSJohn Levon 		sprintf(name, "$%lld", s->value);
4551f5207b7SJohn Levon 		break;
4561f5207b7SJohn Levon 	case STOR_LABEL:
4571f5207b7SJohn Levon 		sprintf(name, "%s.L%d", s->flags & STOR_LABEL_VAL ? "$" : "",
4581f5207b7SJohn Levon 			s->label);
4591f5207b7SJohn Levon 		break;
4601f5207b7SJohn Levon 	case STOR_LABELSYM:
4611f5207b7SJohn Levon 		sprintf(name, "%s.LS%p", s->flags & STOR_LABEL_VAL ? "$" : "",
4621f5207b7SJohn Levon 			s->labelsym);
4631f5207b7SJohn Levon 		break;
4641f5207b7SJohn Levon 	}
4651f5207b7SJohn Levon 
4661f5207b7SJohn Levon 	return name;
4671f5207b7SJohn Levon }
4681f5207b7SJohn Levon 
new_atom(enum atom_type type)4691f5207b7SJohn Levon static struct atom *new_atom(enum atom_type type)
4701f5207b7SJohn Levon {
4711f5207b7SJohn Levon 	struct atom *atom;
4721f5207b7SJohn Levon 
4731f5207b7SJohn Levon 	atom = calloc(1, sizeof(*atom));	/* TODO: chunked alloc */
4741f5207b7SJohn Levon 	if (!atom)
4751f5207b7SJohn Levon 		die("nuclear OOM");
4761f5207b7SJohn Levon 
4771f5207b7SJohn Levon 	atom->type = type;
4781f5207b7SJohn Levon 
4791f5207b7SJohn Levon 	return atom;
4801f5207b7SJohn Levon }
4811f5207b7SJohn Levon 
push_cstring(struct function * f,struct string * str,int label)4821f5207b7SJohn Levon static inline void push_cstring(struct function *f, struct string *str,
4831f5207b7SJohn Levon 				int label)
4841f5207b7SJohn Levon {
4851f5207b7SJohn Levon 	struct atom *atom;
4861f5207b7SJohn Levon 
4871f5207b7SJohn Levon 	atom = new_atom(ATOM_CSTR);
4881f5207b7SJohn Levon 	atom->string = str;
4891f5207b7SJohn Levon 	atom->label = label;
4901f5207b7SJohn Levon 
4911f5207b7SJohn Levon 	add_ptr_list(&f->str_list, atom);	/* note: _not_ atom_list */
4921f5207b7SJohn Levon }
4931f5207b7SJohn Levon 
push_atom(struct function * f,struct atom * atom)4941f5207b7SJohn Levon static inline void push_atom(struct function *f, struct atom *atom)
4951f5207b7SJohn Levon {
4961f5207b7SJohn Levon 	add_ptr_list(&f->atom_list, atom);
4971f5207b7SJohn Levon }
4981f5207b7SJohn Levon 
push_text_atom(struct function * f,const char * text)4991f5207b7SJohn Levon static void push_text_atom(struct function *f, const char *text)
5001f5207b7SJohn Levon {
5011f5207b7SJohn Levon 	struct atom *atom = new_atom(ATOM_TEXT);
5021f5207b7SJohn Levon 
5031f5207b7SJohn Levon 	atom->text = strdup(text);
5041f5207b7SJohn Levon 	atom->text_len = strlen(text);
5051f5207b7SJohn Levon 
5061f5207b7SJohn Levon 	push_atom(f, atom);
5071f5207b7SJohn Levon }
5081f5207b7SJohn Levon 
new_storage(enum storage_type type)5091f5207b7SJohn Levon static struct storage *new_storage(enum storage_type type)
5101f5207b7SJohn Levon {
5111f5207b7SJohn Levon 	struct storage *stor;
5121f5207b7SJohn Levon 
5131f5207b7SJohn Levon 	stor = calloc(1, sizeof(*stor));
5141f5207b7SJohn Levon 	if (!stor)
5151f5207b7SJohn Levon 		die("OOM in new_storage");
5161f5207b7SJohn Levon 
5171f5207b7SJohn Levon 	stor->type = type;
5181f5207b7SJohn Levon 
5191f5207b7SJohn Levon 	return stor;
5201f5207b7SJohn Levon }
5211f5207b7SJohn Levon 
stack_alloc(int n_bytes)5221f5207b7SJohn Levon static struct storage *stack_alloc(int n_bytes)
5231f5207b7SJohn Levon {
5241f5207b7SJohn Levon 	struct function *f = current_func;
5251f5207b7SJohn Levon 	struct storage *stor;
5261f5207b7SJohn Levon 
5271f5207b7SJohn Levon 	assert(f != NULL);
5281f5207b7SJohn Levon 
5291f5207b7SJohn Levon 	stor = new_storage(STOR_PSEUDO);
5301f5207b7SJohn Levon 	stor->type = STOR_PSEUDO;
5311f5207b7SJohn Levon 	stor->pseudo = f->pseudo_nr;
5321f5207b7SJohn Levon 	stor->offset = f->stack_size; /* FIXME: stack req. natural align */
5331f5207b7SJohn Levon 	stor->size = n_bytes;
5341f5207b7SJohn Levon 	f->stack_size += n_bytes;
5351f5207b7SJohn Levon 	f->pseudo_nr++;
5361f5207b7SJohn Levon 
5371f5207b7SJohn Levon 	add_ptr_list(&f->pseudo_list, stor);
5381f5207b7SJohn Levon 
5391f5207b7SJohn Levon 	return stor;
5401f5207b7SJohn Levon }
5411f5207b7SJohn Levon 
new_labelsym(struct symbol * sym)5421f5207b7SJohn Levon static struct storage *new_labelsym(struct symbol *sym)
5431f5207b7SJohn Levon {
5441f5207b7SJohn Levon 	struct storage *stor;
5451f5207b7SJohn Levon 
5461f5207b7SJohn Levon 	stor = new_storage(STOR_LABELSYM);
5471f5207b7SJohn Levon 
5481f5207b7SJohn Levon 	if (stor) {
5491f5207b7SJohn Levon 		stor->flags |= STOR_WANTS_FREE;
5501f5207b7SJohn Levon 		stor->labelsym = sym;
5511f5207b7SJohn Levon 	}
5521f5207b7SJohn Levon 
5531f5207b7SJohn Levon 	return stor;
5541f5207b7SJohn Levon }
5551f5207b7SJohn Levon 
new_val(long long value)5561f5207b7SJohn Levon static struct storage *new_val(long long value)
5571f5207b7SJohn Levon {
5581f5207b7SJohn Levon 	struct storage *stor;
5591f5207b7SJohn Levon 
5601f5207b7SJohn Levon 	stor = new_storage(STOR_VALUE);
5611f5207b7SJohn Levon 
5621f5207b7SJohn Levon 	if (stor) {
5631f5207b7SJohn Levon 		stor->flags |= STOR_WANTS_FREE;
5641f5207b7SJohn Levon 		stor->value = value;
5651f5207b7SJohn Levon 	}
5661f5207b7SJohn Levon 
5671f5207b7SJohn Levon 	return stor;
5681f5207b7SJohn Levon }
5691f5207b7SJohn Levon 
new_label(void)5701f5207b7SJohn Levon static int new_label(void)
5711f5207b7SJohn Levon {
5721f5207b7SJohn Levon 	static int label = 0;
5731f5207b7SJohn Levon 	return ++label;
5741f5207b7SJohn Levon }
5751f5207b7SJohn Levon 
textbuf_push(struct textbuf ** buf_p,const char * text)5761f5207b7SJohn Levon static void textbuf_push(struct textbuf **buf_p, const char *text)
5771f5207b7SJohn Levon {
5781f5207b7SJohn Levon 	struct textbuf *tmp, *list = *buf_p;
5791f5207b7SJohn Levon 	unsigned int text_len = strlen(text);
5801f5207b7SJohn Levon 	unsigned int alloc_len = text_len + 1 + sizeof(*list);
5811f5207b7SJohn Levon 
5821f5207b7SJohn Levon 	tmp = calloc(1, alloc_len);
5831f5207b7SJohn Levon 	if (!tmp)
5841f5207b7SJohn Levon 		die("OOM on textbuf alloc");
5851f5207b7SJohn Levon 
5861f5207b7SJohn Levon 	tmp->text = ((void *) tmp) + sizeof(*tmp);
5871f5207b7SJohn Levon 	memcpy(tmp->text, text, text_len + 1);
5881f5207b7SJohn Levon 	tmp->len = text_len;
5891f5207b7SJohn Levon 
5901f5207b7SJohn Levon 	/* add to end of list */
5911f5207b7SJohn Levon 	if (!list) {
5921f5207b7SJohn Levon 		list = tmp;
5931f5207b7SJohn Levon 		tmp->prev = tmp;
5941f5207b7SJohn Levon 	} else {
5951f5207b7SJohn Levon 		tmp->prev = list->prev;
5961f5207b7SJohn Levon 		tmp->prev->next = tmp;
5971f5207b7SJohn Levon 		list->prev = tmp;
5981f5207b7SJohn Levon 	}
5991f5207b7SJohn Levon 	tmp->next = list;
6001f5207b7SJohn Levon 
6011f5207b7SJohn Levon 	*buf_p = list;
6021f5207b7SJohn Levon }
6031f5207b7SJohn Levon 
textbuf_emit(struct textbuf ** buf_p)6041f5207b7SJohn Levon static void textbuf_emit(struct textbuf **buf_p)
6051f5207b7SJohn Levon {
6061f5207b7SJohn Levon 	struct textbuf *tmp, *list = *buf_p;
6071f5207b7SJohn Levon 
6081f5207b7SJohn Levon 	while (list) {
6091f5207b7SJohn Levon 		tmp = list;
6101f5207b7SJohn Levon 		if (tmp->next == tmp)
6111f5207b7SJohn Levon 			list = NULL;
6121f5207b7SJohn Levon 		else {
6131f5207b7SJohn Levon 			tmp->prev->next = tmp->next;
6141f5207b7SJohn Levon 			tmp->next->prev = tmp->prev;
6151f5207b7SJohn Levon 			list = tmp->next;
6161f5207b7SJohn Levon 		}
6171f5207b7SJohn Levon 
6181f5207b7SJohn Levon 		fputs(tmp->text, stdout);
6191f5207b7SJohn Levon 
6201f5207b7SJohn Levon 		free(tmp);
6211f5207b7SJohn Levon 	}
6221f5207b7SJohn Levon 
6231f5207b7SJohn Levon 	*buf_p = list;
6241f5207b7SJohn Levon }
6251f5207b7SJohn Levon 
insn(const char * insn,struct storage * op1,struct storage * op2,const char * comment_in)6261f5207b7SJohn Levon static void insn(const char *insn, struct storage *op1, struct storage *op2,
6271f5207b7SJohn Levon 		 const char *comment_in)
6281f5207b7SJohn Levon {
6291f5207b7SJohn Levon 	struct function *f = current_func;
6301f5207b7SJohn Levon 	struct atom *atom = new_atom(ATOM_INSN);
6311f5207b7SJohn Levon 
6321f5207b7SJohn Levon 	assert(insn != NULL);
6331f5207b7SJohn Levon 
6341f5207b7SJohn Levon 	strcpy(atom->insn, insn);
6351f5207b7SJohn Levon 	if (comment_in && (*comment_in))
6361f5207b7SJohn Levon 		strncpy(atom->comment, comment_in,
6371f5207b7SJohn Levon 			sizeof(atom->comment) - 1);
6381f5207b7SJohn Levon 
6391f5207b7SJohn Levon 	atom->op1 = op1;
6401f5207b7SJohn Levon 	atom->op2 = op2;
6411f5207b7SJohn Levon 
6421f5207b7SJohn Levon 	push_atom(f, atom);
6431f5207b7SJohn Levon }
6441f5207b7SJohn Levon 
emit_comment(const char * fmt,...)6451f5207b7SJohn Levon static void emit_comment(const char *fmt, ...)
6461f5207b7SJohn Levon {
6471f5207b7SJohn Levon 	struct function *f = current_func;
6481f5207b7SJohn Levon 	static char tmpbuf[100] = "\t# ";
6491f5207b7SJohn Levon 	va_list args;
6501f5207b7SJohn Levon 	int i;
6511f5207b7SJohn Levon 
6521f5207b7SJohn Levon 	va_start(args, fmt);
6531f5207b7SJohn Levon 	i = vsnprintf(tmpbuf+3, sizeof(tmpbuf)-4, fmt, args);
6541f5207b7SJohn Levon 	va_end(args);
6551f5207b7SJohn Levon 	tmpbuf[i+3] = '\n';
6561f5207b7SJohn Levon 	tmpbuf[i+4] = '\0';
6571f5207b7SJohn Levon 	push_text_atom(f, tmpbuf);
6581f5207b7SJohn Levon }
6591f5207b7SJohn Levon 
emit_label(int label,const char * comment)6601f5207b7SJohn Levon static void emit_label (int label, const char *comment)
6611f5207b7SJohn Levon {
6621f5207b7SJohn Levon 	struct function *f = current_func;
6631f5207b7SJohn Levon 	char s[64];
6641f5207b7SJohn Levon 
6651f5207b7SJohn Levon 	if (!comment)
6661f5207b7SJohn Levon 		sprintf(s, ".L%d:\n", label);
6671f5207b7SJohn Levon 	else
6681f5207b7SJohn Levon 		sprintf(s, ".L%d:\t\t\t\t\t# %s\n", label, comment);
6691f5207b7SJohn Levon 
6701f5207b7SJohn Levon 	push_text_atom(f, s);
6711f5207b7SJohn Levon }
6721f5207b7SJohn Levon 
emit_labelsym(struct symbol * sym,const char * comment)6731f5207b7SJohn Levon static void emit_labelsym (struct symbol *sym, const char *comment)
6741f5207b7SJohn Levon {
6751f5207b7SJohn Levon 	struct function *f = current_func;
6761f5207b7SJohn Levon 	char s[64];
6771f5207b7SJohn Levon 
6781f5207b7SJohn Levon 	if (!comment)
6791f5207b7SJohn Levon 		sprintf(s, ".LS%p:\n", sym);
6801f5207b7SJohn Levon 	else
6811f5207b7SJohn Levon 		sprintf(s, ".LS%p:\t\t\t\t# %s\n", sym, comment);
6821f5207b7SJohn Levon 
6831f5207b7SJohn Levon 	push_text_atom(f, s);
6841f5207b7SJohn Levon }
6851f5207b7SJohn Levon 
emit_unit_begin(const char * basename)6861f5207b7SJohn Levon void emit_unit_begin(const char *basename)
6871f5207b7SJohn Levon {
6881f5207b7SJohn Levon 	printf("\t.file\t\"%s\"\n", basename);
6891f5207b7SJohn Levon }
6901f5207b7SJohn Levon 
emit_unit_end(void)6911f5207b7SJohn Levon void emit_unit_end(void)
6921f5207b7SJohn Levon {
6931f5207b7SJohn Levon 	textbuf_emit(&unit_post_text);
6941f5207b7SJohn Levon 	printf("\t.ident\t\"sparse silly x86 backend (version %s)\"\n", SPARSE_VERSION);
6951f5207b7SJohn Levon }
6961f5207b7SJohn Levon 
6971f5207b7SJohn Levon /* conditionally switch sections */
emit_section(const char * s)6981f5207b7SJohn Levon static void emit_section(const char *s)
6991f5207b7SJohn Levon {
7001f5207b7SJohn Levon 	if (s == current_section)
7011f5207b7SJohn Levon 		return;
7021f5207b7SJohn Levon 	if (current_section && (!strcmp(s, current_section)))
7031f5207b7SJohn Levon 		return;
7041f5207b7SJohn Levon 
7051f5207b7SJohn Levon 	printf("\t%s\n", s);
7061f5207b7SJohn Levon 	current_section = s;
7071f5207b7SJohn Levon }
7081f5207b7SJohn Levon 
emit_insn_atom(struct function * f,struct atom * atom)7091f5207b7SJohn Levon static void emit_insn_atom(struct function *f, struct atom *atom)
7101f5207b7SJohn Levon {
7111f5207b7SJohn Levon 	char s[128];
7121f5207b7SJohn Levon 	char comment[64];
7131f5207b7SJohn Levon 	struct storage *op1 = atom->op1;
7141f5207b7SJohn Levon 	struct storage *op2 = atom->op2;
7151f5207b7SJohn Levon 
7161f5207b7SJohn Levon 	if (atom->comment[0])
7171f5207b7SJohn Levon 		sprintf(comment, "\t\t# %s", atom->comment);
7181f5207b7SJohn Levon 	else
7191f5207b7SJohn Levon 		comment[0] = 0;
7201f5207b7SJohn Levon 
7211f5207b7SJohn Levon 	if (atom->op2) {
7221f5207b7SJohn Levon 		char tmp[16];
7231f5207b7SJohn Levon 		strcpy(tmp, stor_op_name(op1));
7241f5207b7SJohn Levon 		sprintf(s, "\t%s\t%s, %s%s\n",
7251f5207b7SJohn Levon 			atom->insn, tmp, stor_op_name(op2), comment);
7261f5207b7SJohn Levon 	} else if (atom->op1)
7271f5207b7SJohn Levon 		sprintf(s, "\t%s\t%s%s%s\n",
7281f5207b7SJohn Levon 			atom->insn, stor_op_name(op1),
7291f5207b7SJohn Levon 			comment[0] ? "\t" : "", comment);
7301f5207b7SJohn Levon 	else
7311f5207b7SJohn Levon 		sprintf(s, "\t%s\t%s%s\n",
7321f5207b7SJohn Levon 			atom->insn,
7331f5207b7SJohn Levon 			comment[0] ? "\t\t" : "", comment);
7341f5207b7SJohn Levon 
7351f5207b7SJohn Levon 	if (write(STDOUT_FILENO, s, strlen(s)) < 0)
7361f5207b7SJohn Levon 		die("can't write to stdout");
7371f5207b7SJohn Levon }
7381f5207b7SJohn Levon 
emit_atom_list(struct function * f)7391f5207b7SJohn Levon static void emit_atom_list(struct function *f)
7401f5207b7SJohn Levon {
7411f5207b7SJohn Levon 	struct atom *atom;
7421f5207b7SJohn Levon 
7431f5207b7SJohn Levon 	FOR_EACH_PTR(f->atom_list, atom) {
7441f5207b7SJohn Levon 		switch (atom->type) {
7451f5207b7SJohn Levon 		case ATOM_TEXT: {
7461f5207b7SJohn Levon 			if (write(STDOUT_FILENO, atom->text, atom->text_len) < 0)
7471f5207b7SJohn Levon 				die("can't write to stdout");
7481f5207b7SJohn Levon 			break;
7491f5207b7SJohn Levon 		}
7501f5207b7SJohn Levon 		case ATOM_INSN:
7511f5207b7SJohn Levon 			emit_insn_atom(f, atom);
7521f5207b7SJohn Levon 			break;
7531f5207b7SJohn Levon 		case ATOM_CSTR:
7541f5207b7SJohn Levon 			assert(0);
7551f5207b7SJohn Levon 			break;
7561f5207b7SJohn Levon 		}
7571f5207b7SJohn Levon 	} END_FOR_EACH_PTR(atom);
7581f5207b7SJohn Levon }
7591f5207b7SJohn Levon 
emit_string_list(struct function * f)7601f5207b7SJohn Levon static void emit_string_list(struct function *f)
7611f5207b7SJohn Levon {
7621f5207b7SJohn Levon 	struct atom *atom;
7631f5207b7SJohn Levon 
7641f5207b7SJohn Levon 	emit_section(".section\t.rodata");
7651f5207b7SJohn Levon 
7661f5207b7SJohn Levon 	FOR_EACH_PTR(f->str_list, atom) {
7671f5207b7SJohn Levon 		/* FIXME: escape " in string */
7681f5207b7SJohn Levon 		printf(".L%d:\n", atom->label);
7691f5207b7SJohn Levon 		printf("\t.string\t%s\n", show_string(atom->string));
7701f5207b7SJohn Levon 
7711f5207b7SJohn Levon 		free(atom);
7721f5207b7SJohn Levon 	} END_FOR_EACH_PTR(atom);
7731f5207b7SJohn Levon }
7741f5207b7SJohn Levon 
func_cleanup(struct function * f)7751f5207b7SJohn Levon static void func_cleanup(struct function *f)
7761f5207b7SJohn Levon {
7771f5207b7SJohn Levon 	struct storage *stor;
7781f5207b7SJohn Levon 	struct atom *atom;
7791f5207b7SJohn Levon 
7801f5207b7SJohn Levon 	FOR_EACH_PTR(f->atom_list, atom) {
7811f5207b7SJohn Levon 		if ((atom->type == ATOM_TEXT) && (atom->text))
7821f5207b7SJohn Levon 			free(atom->text);
7831f5207b7SJohn Levon 		if (atom->op1 && (atom->op1->flags & STOR_WANTS_FREE))
7841f5207b7SJohn Levon 			free(atom->op1);
7851f5207b7SJohn Levon 		if (atom->op2 && (atom->op2->flags & STOR_WANTS_FREE))
7861f5207b7SJohn Levon 			free(atom->op2);
7871f5207b7SJohn Levon 		free(atom);
7881f5207b7SJohn Levon 	} END_FOR_EACH_PTR(atom);
7891f5207b7SJohn Levon 
7901f5207b7SJohn Levon 	FOR_EACH_PTR(f->pseudo_list, stor) {
7911f5207b7SJohn Levon 		free(stor);
7921f5207b7SJohn Levon 	} END_FOR_EACH_PTR(stor);
7931f5207b7SJohn Levon 
7941f5207b7SJohn Levon 	free_ptr_list(&f->pseudo_list);
7951f5207b7SJohn Levon 	free(f);
7961f5207b7SJohn Levon }
7971f5207b7SJohn Levon 
7981f5207b7SJohn Levon /* function prologue */
emit_func_pre(struct symbol * sym)7991f5207b7SJohn Levon static void emit_func_pre(struct symbol *sym)
8001f5207b7SJohn Levon {
8011f5207b7SJohn Levon 	struct function *f;
8021f5207b7SJohn Levon 	struct symbol *arg;
8031f5207b7SJohn Levon 	unsigned int i, argc = 0, alloc_len;
8041f5207b7SJohn Levon 	unsigned char *mem;
8051f5207b7SJohn Levon 	struct symbol_private *privbase;
8061f5207b7SJohn Levon 	struct storage *storage_base;
8071f5207b7SJohn Levon 	struct symbol *base_type = sym->ctype.base_type;
8081f5207b7SJohn Levon 
8091f5207b7SJohn Levon 	FOR_EACH_PTR(base_type->arguments, arg) {
8101f5207b7SJohn Levon 		argc++;
811