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  *
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[] = {
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++;