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++;
8111f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
8121f5207b7SJohn Levon 
8131f5207b7SJohn Levon 	alloc_len =
8141f5207b7SJohn Levon 		sizeof(*f) +
8151f5207b7SJohn Levon 		(argc * sizeof(struct symbol *)) +
8161f5207b7SJohn Levon 		(argc * sizeof(struct symbol_private)) +
8171f5207b7SJohn Levon 		(argc * sizeof(struct storage));
8181f5207b7SJohn Levon 	mem = calloc(1, alloc_len);
8191f5207b7SJohn Levon 	if (!mem)
8201f5207b7SJohn Levon 		die("OOM on func info");
8211f5207b7SJohn Levon 
8221f5207b7SJohn Levon 	f		=  (struct function *) mem;
8231f5207b7SJohn Levon 	mem		+= sizeof(*f);
8241f5207b7SJohn Levon 	f->argv		=  (struct symbol **) mem;
8251f5207b7SJohn Levon 	mem		+= (argc * sizeof(struct symbol *));
8261f5207b7SJohn Levon 	privbase	=  (struct symbol_private *) mem;
8271f5207b7SJohn Levon 	mem		+= (argc * sizeof(struct symbol_private));
8281f5207b7SJohn Levon 	storage_base	=  (struct storage *) mem;
8291f5207b7SJohn Levon 
8301f5207b7SJohn Levon 	f->argc = argc;
8311f5207b7SJohn Levon 	f->ret_target = new_label();
8321f5207b7SJohn Levon 
8331f5207b7SJohn Levon 	i = 0;
8341f5207b7SJohn Levon 	FOR_EACH_PTR(base_type->arguments, arg) {
8351f5207b7SJohn Levon 		f->argv[i] = arg;
8361f5207b7SJohn Levon 		arg->aux = &privbase[i];
8371f5207b7SJohn Levon 		storage_base[i].type = STOR_ARG;
8381f5207b7SJohn Levon 		storage_base[i].idx = i;
8391f5207b7SJohn Levon 		privbase[i].addr = &storage_base[i];
8401f5207b7SJohn Levon 		i++;
8411f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
8421f5207b7SJohn Levon 
8431f5207b7SJohn Levon 	assert(current_func == NULL);
8441f5207b7SJohn Levon 	current_func = f;
8451f5207b7SJohn Levon }
8461f5207b7SJohn Levon 
8471f5207b7SJohn Levon /* function epilogue */
emit_func_post(struct symbol * sym)8481f5207b7SJohn Levon static void emit_func_post(struct symbol *sym)
8491f5207b7SJohn Levon {
8501f5207b7SJohn Levon 	const char *name = show_ident(sym->ident);
8511f5207b7SJohn Levon 	struct function *f = current_func;
8521f5207b7SJohn Levon 	int stack_size = f->stack_size;
8531f5207b7SJohn Levon 
8541f5207b7SJohn Levon 	if (f->str_list)
8551f5207b7SJohn Levon 		emit_string_list(f);
8561f5207b7SJohn Levon 
8571f5207b7SJohn Levon 	/* function prologue */
8581f5207b7SJohn Levon 	emit_section(".text");
8591f5207b7SJohn Levon 	if ((sym->ctype.modifiers & MOD_STATIC) == 0)
8601f5207b7SJohn Levon 		printf(".globl %s\n", name);
8611f5207b7SJohn Levon 	printf("\t.type\t%s, @function\n", name);
8621f5207b7SJohn Levon 	printf("%s:\n", name);
8631f5207b7SJohn Levon 
8641f5207b7SJohn Levon 	if (stack_size) {
8651f5207b7SJohn Levon 		char pseudo_const[16];
8661f5207b7SJohn Levon 
8671f5207b7SJohn Levon 		sprintf(pseudo_const, "$%d", stack_size);
8681f5207b7SJohn Levon 		printf("\tsubl\t%s, %%esp\n", pseudo_const);
8691f5207b7SJohn Levon 	}
8701f5207b7SJohn Levon 
8711f5207b7SJohn Levon 	/* function epilogue */
8721f5207b7SJohn Levon 
8731f5207b7SJohn Levon 	/* jump target for 'return' statements */
8741f5207b7SJohn Levon 	emit_label(f->ret_target, NULL);
8751f5207b7SJohn Levon 
8761f5207b7SJohn Levon 	if (stack_size) {
8771f5207b7SJohn Levon 		struct storage *val;
8781f5207b7SJohn Levon 
8791f5207b7SJohn Levon 		val = new_storage(STOR_VALUE);
8801f5207b7SJohn Levon 		val->value = (long long) (stack_size);
8811f5207b7SJohn Levon 		val->flags = STOR_WANTS_FREE;
8821f5207b7SJohn Levon 
8831f5207b7SJohn Levon 		insn("addl", val, REG_ESP, NULL);
8841f5207b7SJohn Levon 	}
8851f5207b7SJohn Levon 
8861f5207b7SJohn Levon 	insn("ret", NULL, NULL, NULL);
8871f5207b7SJohn Levon 
8881f5207b7SJohn Levon 	/* output everything to stdout */
8891f5207b7SJohn Levon 	fflush(stdout);		/* paranoia; needed? */
8901f5207b7SJohn Levon 	emit_atom_list(f);
8911f5207b7SJohn Levon 
8921f5207b7SJohn Levon 	/* function footer */
8931f5207b7SJohn Levon 	name = show_ident(sym->ident);
8941f5207b7SJohn Levon 	printf("\t.size\t%s, .-%s\n", name, name);
8951f5207b7SJohn Levon 
8961f5207b7SJohn Levon 	func_cleanup(f);
8971f5207b7SJohn Levon 	current_func = NULL;
8981f5207b7SJohn Levon }
8991f5207b7SJohn Levon 
9001f5207b7SJohn Levon /* emit object (a.k.a. variable, a.k.a. data) prologue */
emit_object_pre(const char * name,unsigned long modifiers,unsigned long alignment,unsigned int byte_size)9011f5207b7SJohn Levon static void emit_object_pre(const char *name, unsigned long modifiers,
9021f5207b7SJohn Levon 			    unsigned long alignment, unsigned int byte_size)
9031f5207b7SJohn Levon {
9041f5207b7SJohn Levon 	if ((modifiers & MOD_STATIC) == 0)
9051f5207b7SJohn Levon 		printf(".globl %s\n", name);
9061f5207b7SJohn Levon 	emit_section(".data");
9071f5207b7SJohn Levon 	if (alignment)
9081f5207b7SJohn Levon 		printf("\t.align %lu\n", alignment);
9091f5207b7SJohn Levon 	printf("\t.type\t%s, @object\n", name);
9101f5207b7SJohn Levon 	printf("\t.size\t%s, %d\n", name, byte_size);
9111f5207b7SJohn Levon 	printf("%s:\n", name);
9121f5207b7SJohn Levon }
9131f5207b7SJohn Levon 
9141f5207b7SJohn Levon /* emit value (only) for an initializer scalar */
emit_scalar(struct expression * expr,unsigned int bit_size)9151f5207b7SJohn Levon static void emit_scalar(struct expression *expr, unsigned int bit_size)
9161f5207b7SJohn Levon {
9171f5207b7SJohn Levon 	const char *type;
9181f5207b7SJohn Levon 	long long ll;
9191f5207b7SJohn Levon 
9201f5207b7SJohn Levon 	assert(expr->type == EXPR_VALUE);
9211f5207b7SJohn Levon 
9221f5207b7SJohn Levon 	if (expr->value == 0ULL) {
9231f5207b7SJohn Levon 		printf("\t.zero\t%d\n", bit_size / 8);
9241f5207b7SJohn Levon 		return;
9251f5207b7SJohn Levon 	}
9261f5207b7SJohn Levon 
9271f5207b7SJohn Levon 	ll = (long long) expr->value;
9281f5207b7SJohn Levon 
9291f5207b7SJohn Levon 	switch (bit_size) {
9301f5207b7SJohn Levon 	case 8:		type = "byte";	ll = (char) ll; break;
9311f5207b7SJohn Levon 	case 16:	type = "value";	ll = (short) ll; break;
9321f5207b7SJohn Levon 	case 32:	type = "long";	ll = (int) ll; break;
9331f5207b7SJohn Levon 	case 64:	type = "quad";	break;
9341f5207b7SJohn Levon 	default:	type = NULL;	break;
9351f5207b7SJohn Levon 	}
9361f5207b7SJohn Levon 
9371f5207b7SJohn Levon 	assert(type != NULL);
9381f5207b7SJohn Levon 
939*c85f09ccSJohn Levon 	printf("\t.%s\t%lld\n", type, ll);
9401f5207b7SJohn Levon }
9411f5207b7SJohn Levon 
emit_global_noinit(const char * name,unsigned long modifiers,unsigned long alignment,unsigned int byte_size)9421f5207b7SJohn Levon static void emit_global_noinit(const char *name, unsigned long modifiers,
9431f5207b7SJohn Levon 			       unsigned long alignment, unsigned int byte_size)
9441f5207b7SJohn Levon {
9451f5207b7SJohn Levon 	char s[64];
9461f5207b7SJohn Levon 
9471f5207b7SJohn Levon 	if (modifiers & MOD_STATIC) {
9481f5207b7SJohn Levon 		sprintf(s, "\t.local\t%s\n", name);
9491f5207b7SJohn Levon 		textbuf_push(&unit_post_text, s);
9501f5207b7SJohn Levon 	}
9511f5207b7SJohn Levon 	if (alignment)
9521f5207b7SJohn Levon 		sprintf(s, "\t.comm\t%s,%d,%lu\n", name, byte_size, alignment);
9531f5207b7SJohn Levon 	else
9541f5207b7SJohn Levon 		sprintf(s, "\t.comm\t%s,%d\n", name, byte_size);
9551f5207b7SJohn Levon 	textbuf_push(&unit_post_text, s);
9561f5207b7SJohn Levon }
9571f5207b7SJohn Levon 
9581f5207b7SJohn Levon static int ea_current, ea_last;
9591f5207b7SJohn Levon 
emit_initializer(struct symbol * sym,struct expression * expr)9601f5207b7SJohn Levon static void emit_initializer(struct symbol *sym,
9611f5207b7SJohn Levon 			     struct expression *expr)
9621f5207b7SJohn Levon {
9631f5207b7SJohn Levon 	int distance = ea_current - ea_last - 1;
9641f5207b7SJohn Levon 
9651f5207b7SJohn Levon 	if (distance > 0)
9661f5207b7SJohn Levon 		printf("\t.zero\t%d\n", (sym->bit_size / 8) * distance);
9671f5207b7SJohn Levon 
9681f5207b7SJohn Levon 	if (expr->type == EXPR_VALUE) {
9691f5207b7SJohn Levon 		struct symbol *base_type = sym->ctype.base_type;
9701f5207b7SJohn Levon 		assert(base_type != NULL);
9711f5207b7SJohn Levon 
9721f5207b7SJohn Levon 		emit_scalar(expr, sym->bit_size / get_expression_value(base_type->array_size));
9731f5207b7SJohn Levon 		return;
9741f5207b7SJohn Levon 	}
9751f5207b7SJohn Levon 	if (expr->type != EXPR_INITIALIZER)
9761f5207b7SJohn Levon 		return;
9771f5207b7SJohn Levon 
9781f5207b7SJohn Levon 	assert(0); /* FIXME */
9791f5207b7SJohn Levon }
9801f5207b7SJohn Levon 
sort_array_cmp(const struct expression * a,const struct expression * b)9811f5207b7SJohn Levon static int sort_array_cmp(const struct expression *a,
9821f5207b7SJohn Levon 			  const struct expression *b)
9831f5207b7SJohn Levon {
9841f5207b7SJohn Levon 	int a_ofs = 0, b_ofs = 0;
9851f5207b7SJohn Levon 
9861f5207b7SJohn Levon 	if (a->type == EXPR_POS)
9871f5207b7SJohn Levon 		a_ofs = (int) a->init_offset;
9881f5207b7SJohn Levon 	if (b->type == EXPR_POS)
9891f5207b7SJohn Levon 		b_ofs = (int) b->init_offset;
9901f5207b7SJohn Levon 
9911f5207b7SJohn Levon 	return a_ofs - b_ofs;
9921f5207b7SJohn Levon }
9931f5207b7SJohn Levon 
9941f5207b7SJohn Levon /* move to front-end? */
sort_array(struct expression * expr)9951f5207b7SJohn Levon static void sort_array(struct expression *expr)
9961f5207b7SJohn Levon {
9971f5207b7SJohn Levon 	struct expression *entry, **list;
9981f5207b7SJohn Levon 	unsigned int elem, sorted, i;
9991f5207b7SJohn Levon 
10001f5207b7SJohn Levon 	elem = expression_list_size(expr->expr_list);
10011f5207b7SJohn Levon 	if (!elem)
10021f5207b7SJohn Levon 		return;
10031f5207b7SJohn Levon 
10041f5207b7SJohn Levon 	list = malloc(sizeof(entry) * elem);
10051f5207b7SJohn Levon 	if (!list)
10061f5207b7SJohn Levon 		die("OOM in sort_array");
10071f5207b7SJohn Levon 
10081f5207b7SJohn Levon 	/* this code is no doubt evil and ignores EXPR_INDEX possibly
10091f5207b7SJohn Levon 	 * to its detriment and other nasty things.  improvements
10101f5207b7SJohn Levon 	 * welcome.
10111f5207b7SJohn Levon 	 */
10121f5207b7SJohn Levon 	i = 0;
10131f5207b7SJohn Levon 	sorted = 0;
10141f5207b7SJohn Levon 	FOR_EACH_PTR(expr->expr_list, entry) {
10151f5207b7SJohn Levon 		if ((entry->type == EXPR_POS) || (entry->type == EXPR_VALUE)) {
10161f5207b7SJohn Levon 			/* add entry to list[], in sorted order */
10171f5207b7SJohn Levon 			if (sorted == 0) {
10181f5207b7SJohn Levon 				list[0] = entry;
10191f5207b7SJohn Levon 				sorted = 1;
10201f5207b7SJohn Levon 			} else {
10211f5207b7SJohn Levon 				for (i = 0; i < sorted; i++)
10221f5207b7SJohn Levon 					if (sort_array_cmp(entry, list[i]) <= 0)
10231f5207b7SJohn Levon 						break;
10241f5207b7SJohn Levon 
10251f5207b7SJohn Levon 				/* If inserting into the middle of list[]
10261f5207b7SJohn Levon 				 * instead of appending, we memmove.
10271f5207b7SJohn Levon 				 * This is ugly, but thankfully
10281f5207b7SJohn Levon 				 * uncommon.  Input data with tons of
10291f5207b7SJohn Levon 				 * entries very rarely have explicit
10301f5207b7SJohn Levon 				 * offsets.  convert to qsort eventually...
10311f5207b7SJohn Levon 				 */
10321f5207b7SJohn Levon 				if (i != sorted)
10331f5207b7SJohn Levon 					memmove(&list[i + 1], &list[i],
10341f5207b7SJohn Levon 						(sorted - i) * sizeof(entry));
10351f5207b7SJohn Levon 				list[i] = entry;
10361f5207b7SJohn Levon 				sorted++;
10371f5207b7SJohn Levon 			}
10381f5207b7SJohn Levon 		}
10391f5207b7SJohn Levon 	} END_FOR_EACH_PTR(entry);
10401f5207b7SJohn Levon 
10411f5207b7SJohn Levon 	i = 0;
10421f5207b7SJohn Levon 	FOR_EACH_PTR(expr->expr_list, entry) {
10431f5207b7SJohn Levon 		if ((entry->type == EXPR_POS) || (entry->type == EXPR_VALUE))
10441f5207b7SJohn Levon 			*THIS_ADDRESS(entry) = list[i++];
10451f5207b7SJohn Levon 	} END_FOR_EACH_PTR(entry);
10461f5207b7SJohn Levon 
10471f5207b7SJohn Levon 	free(list);
10481f5207b7SJohn Levon }
10491f5207b7SJohn Levon 
emit_array(struct symbol * sym)10501f5207b7SJohn Levon static void emit_array(struct symbol *sym)
10511f5207b7SJohn Levon {
10521f5207b7SJohn Levon 	struct symbol *base_type = sym->ctype.base_type;
10531f5207b7SJohn Levon 	struct expression *expr = sym->initializer;
10541f5207b7SJohn Levon 	struct expression *entry;
10551f5207b7SJohn Levon 
10561f5207b7SJohn Levon 	assert(base_type != NULL);
10571f5207b7SJohn Levon 
10581f5207b7SJohn Levon 	stor_sym_init(sym);
10591f5207b7SJohn Levon 
10601f5207b7SJohn Levon 	ea_last = -1;
10611f5207b7SJohn Levon 
10621f5207b7SJohn Levon 	emit_object_pre(show_ident(sym->ident), sym->ctype.modifiers,
10631f5207b7SJohn Levon 		        sym->ctype.alignment,
10641f5207b7SJohn Levon 			sym->bit_size / 8);
10651f5207b7SJohn Levon 
10661f5207b7SJohn Levon 	sort_array(expr);
10671f5207b7SJohn Levon 
10681f5207b7SJohn Levon 	FOR_EACH_PTR(expr->expr_list, entry) {
10691f5207b7SJohn Levon 		if (entry->type == EXPR_VALUE) {
10701f5207b7SJohn Levon 			ea_current = 0;
10711f5207b7SJohn Levon 			emit_initializer(sym, entry);
10721f5207b7SJohn Levon 			ea_last = ea_current;
10731f5207b7SJohn Levon 		} else if (entry->type == EXPR_POS) {
10741f5207b7SJohn Levon 			ea_current =
10751f5207b7SJohn Levon 			    entry->init_offset / (base_type->bit_size / 8);
10761f5207b7SJohn Levon 			emit_initializer(sym, entry->init_expr);
10771f5207b7SJohn Levon 			ea_last = ea_current;
10781f5207b7SJohn Levon 		}
10791f5207b7SJohn Levon 	} END_FOR_EACH_PTR(entry);
10801f5207b7SJohn Levon }
10811f5207b7SJohn Levon 
emit_one_symbol(struct symbol * sym)10821f5207b7SJohn Levon void emit_one_symbol(struct symbol *sym)
10831f5207b7SJohn Levon {
10841f5207b7SJohn Levon 	x86_symbol(sym);
10851f5207b7SJohn Levon }
10861f5207b7SJohn Levon 
emit_copy(struct storage * dest,struct storage * src,struct symbol * ctype)10871f5207b7SJohn Levon static void emit_copy(struct storage *dest, struct storage *src,
10881f5207b7SJohn Levon 		      struct symbol *ctype)
10891f5207b7SJohn Levon {
10901f5207b7SJohn Levon 	struct storage *reg = NULL;
10911f5207b7SJohn Levon 	unsigned int bit_size;
10921f5207b7SJohn Levon 
10931f5207b7SJohn Levon 	/* FIXME: Bitfield copy! */
10941f5207b7SJohn Levon 
10951f5207b7SJohn Levon 	bit_size = src->size * 8;
10961f5207b7SJohn Levon 	if (!bit_size)
10971f5207b7SJohn Levon 		bit_size = 32;
10981f5207b7SJohn Levon 	if ((src->type == STOR_ARG) && (bit_size < 32))
10991f5207b7SJohn Levon 		bit_size = 32;
11001f5207b7SJohn Levon 
11011f5207b7SJohn Levon 	reg = temp_from_bits(bit_size);
11021f5207b7SJohn Levon 	emit_move(src, reg, ctype, "begin copy ..");
11031f5207b7SJohn Levon 
11041f5207b7SJohn Levon 	bit_size = dest->size * 8;
11051f5207b7SJohn Levon 	if (!bit_size)
11061f5207b7SJohn Levon 		bit_size = 32;
11071f5207b7SJohn Levon 	if ((dest->type == STOR_ARG) && (bit_size < 32))
11081f5207b7SJohn Levon 		bit_size = 32;
11091f5207b7SJohn Levon 
11101f5207b7SJohn Levon 	emit_move(reg, dest, ctype, ".... end copy");
11111f5207b7SJohn Levon 	put_reg(reg);
11121f5207b7SJohn Levon }
11131f5207b7SJohn Levon 
emit_store(struct expression * dest_expr,struct storage * dest,struct storage * src,int bits)11141f5207b7SJohn Levon static void emit_store(struct expression *dest_expr, struct storage *dest,
11151f5207b7SJohn Levon 		       struct storage *src, int bits)
11161f5207b7SJohn Levon {
11171f5207b7SJohn Levon 	/* FIXME: Bitfield store! */
11181f5207b7SJohn Levon 	printf("\tst.%d\t\tv%d,[v%d]\n", bits, src->pseudo, dest->pseudo);
11191f5207b7SJohn Levon }
11201f5207b7SJohn Levon 
emit_scalar_noinit(struct symbol * sym)11211f5207b7SJohn Levon static void emit_scalar_noinit(struct symbol *sym)
11221f5207b7SJohn Levon {
11231f5207b7SJohn Levon 	emit_global_noinit(show_ident(sym->ident),
11241f5207b7SJohn Levon 			   sym->ctype.modifiers, sym->ctype.alignment,
11251f5207b7SJohn Levon 			   sym->bit_size / 8);
11261f5207b7SJohn Levon 	stor_sym_init(sym);
11271f5207b7SJohn Levon }
11281f5207b7SJohn Levon 
emit_array_noinit(struct symbol * sym)11291f5207b7SJohn Levon static void emit_array_noinit(struct symbol *sym)
11301f5207b7SJohn Levon {
11311f5207b7SJohn Levon 	emit_global_noinit(show_ident(sym->ident),
11321f5207b7SJohn Levon 			   sym->ctype.modifiers, sym->ctype.alignment,
11331f5207b7SJohn Levon 			   get_expression_value(sym->array_size) * (sym->bit_size / 8));
11341f5207b7SJohn Levon 	stor_sym_init(sym);
11351f5207b7SJohn Levon }
11361f5207b7SJohn Levon 
opbits(const char * insn,unsigned int bits)11371f5207b7SJohn Levon static const char *opbits(const char *insn, unsigned int bits)
11381f5207b7SJohn Levon {
11391f5207b7SJohn Levon 	static char opbits_str[32];
11401f5207b7SJohn Levon 	char c;
11411f5207b7SJohn Levon 
11421f5207b7SJohn Levon 	switch (bits) {
11431f5207b7SJohn Levon 	case 8:	 c = 'b'; break;
11441f5207b7SJohn Levon 	case 16: c = 'w'; break;
11451f5207b7SJohn Levon 	case 32: c = 'l'; break;
11461f5207b7SJohn Levon 	case 64: c = 'q'; break;
11471f5207b7SJohn Levon 	default: abort(); break;
11481f5207b7SJohn Levon 	}
11491f5207b7SJohn Levon 
11501f5207b7SJohn Levon 	sprintf(opbits_str, "%s%c", insn, c);
11511f5207b7SJohn Levon 
11521f5207b7SJohn Levon 	return opbits_str;
11531f5207b7SJohn Levon }
11541f5207b7SJohn Levon 
emit_move(struct storage * src,struct storage * dest,struct symbol * ctype,const char * comment)11551f5207b7SJohn Levon static void emit_move(struct storage *src, struct storage *dest,
11561f5207b7SJohn Levon 		      struct symbol *ctype, const char *comment)
11571f5207b7SJohn Levon {
11581f5207b7SJohn Levon 	unsigned int bits;
11591f5207b7SJohn Levon 	unsigned int is_signed;
11601f5207b7SJohn Levon 	unsigned int is_dest = (src->type == STOR_REG);
11611f5207b7SJohn Levon 	const char *opname;
11621f5207b7SJohn Levon 
11631f5207b7SJohn Levon 	if (ctype) {
11641f5207b7SJohn Levon 		bits = ctype->bit_size;
1165*c85f09ccSJohn Levon 		is_signed = is_signed_type(ctype);
11661f5207b7SJohn Levon 	} else {
11671f5207b7SJohn Levon 		bits = 32;
11681f5207b7SJohn Levon 		is_signed = 0;
11691f5207b7SJohn Levon 	}
11701f5207b7SJohn Levon 
11711f5207b7SJohn Levon 	/*
11721f5207b7SJohn Levon 	 * Are we moving from a register to a register?
11731f5207b7SJohn Levon 	 * Make the new reg to be the "cache".
11741f5207b7SJohn Levon 	 */
11751f5207b7SJohn Levon 	if ((dest->type == STOR_REG) && (src->type == STOR_REG)) {
11761f5207b7SJohn Levon 		struct storage *backing;
11771f5207b7SJohn Levon 
11781f5207b7SJohn Levon reg_reg_move:
11791f5207b7SJohn Levon 		if (dest == src)
11801f5207b7SJohn Levon 			return;
11811f5207b7SJohn Levon 
11821f5207b7SJohn Levon 		backing = src->reg->contains;
11831f5207b7SJohn Levon 		if (backing) {
11841f5207b7SJohn Levon 			/* Is it still valid? */
11851f5207b7SJohn Levon 			if (backing->reg != src->reg)
11861f5207b7SJohn Levon 				backing = NULL;
11871f5207b7SJohn Levon 			else
11881f5207b7SJohn Levon 				backing->reg = dest->reg;
11891f5207b7SJohn Levon 		}
11901f5207b7SJohn Levon 		dest->reg->contains = backing;
11911f5207b7SJohn Levon 		insn("mov", src, dest, NULL);
11921f5207b7SJohn Levon 		return;
11931f5207b7SJohn Levon 	}
11941f5207b7SJohn Levon 
11951f5207b7SJohn Levon 	/*
11961f5207b7SJohn Levon 	 * Are we moving to a register from a non-reg?
11971f5207b7SJohn Levon 	 *
11981f5207b7SJohn Levon 	 * See if we have the non-reg source already cached
11991f5207b7SJohn Levon 	 * in a register..
12001f5207b7SJohn Levon 	 */
12011f5207b7SJohn Levon 	if (dest->type == STOR_REG) {
12021f5207b7SJohn Levon 		if (src->reg) {
12031f5207b7SJohn Levon 			struct reg_info *info = src->reg;
12041f5207b7SJohn Levon 			if (info->contains == src) {
12051f5207b7SJohn Levon 				src = reginfo_reg(info);
12061f5207b7SJohn Levon 				goto reg_reg_move;
12071f5207b7SJohn Levon 			}
12081f5207b7SJohn Levon 		}
12091f5207b7SJohn Levon 		dest->reg->contains = src;
12101f5207b7SJohn Levon 		src->reg = dest->reg;
12111f5207b7SJohn Levon 	}
12121f5207b7SJohn Levon 
12131f5207b7SJohn Levon 	if (src->type == STOR_REG) {
12141f5207b7SJohn Levon 		/* We could just mark the register dirty here and do lazy store.. */
12151f5207b7SJohn Levon 		src->reg->contains = dest;
12161f5207b7SJohn Levon 		dest->reg = src->reg;
12171f5207b7SJohn Levon 	}
12181f5207b7SJohn Levon 
12191f5207b7SJohn Levon 	if ((bits == 8) || (bits == 16)) {
12201f5207b7SJohn Levon 		if (is_dest)
12211f5207b7SJohn Levon 			opname = "mov";
12221f5207b7SJohn Levon 		else
12231f5207b7SJohn Levon 			opname = is_signed ? "movsx" : "movzx";
12241f5207b7SJohn Levon 	} else
12251f5207b7SJohn Levon 		opname = "mov";
12261f5207b7SJohn Levon 
12271f5207b7SJohn Levon 	insn(opbits(opname, bits), src, dest, comment);
12281f5207b7SJohn Levon }
12291f5207b7SJohn Levon 
emit_compare(struct expression * expr)12301f5207b7SJohn Levon static struct storage *emit_compare(struct expression *expr)
12311f5207b7SJohn Levon {
12321f5207b7SJohn Levon 	struct storage *left = x86_expression(expr->left);
12331f5207b7SJohn Levon 	struct storage *right = x86_expression(expr->right);
12341f5207b7SJohn Levon 	struct storage *reg1, *reg2;
12351f5207b7SJohn Levon 	struct storage *new, *val;
12361f5207b7SJohn Levon 	const char *opname = NULL;
12371f5207b7SJohn Levon 	unsigned int right_bits = expr->right->ctype->bit_size;
12381f5207b7SJohn Levon 
12391f5207b7SJohn Levon 	switch(expr->op) {
12401f5207b7SJohn Levon 	case '<': 		opname = "setl";	break;
12411f5207b7SJohn Levon 	case '>':		opname = "setg";	break;
12421f5207b7SJohn Levon 	case SPECIAL_LTE:
12431f5207b7SJohn Levon 				opname = "setle";	break;
12441f5207b7SJohn Levon 	case SPECIAL_GTE:
12451f5207b7SJohn Levon 				opname = "setge";	break;
12461f5207b7SJohn Levon 	case SPECIAL_EQUAL:	opname = "sete";	break;
12471f5207b7SJohn Levon 	case SPECIAL_NOTEQUAL:	opname = "setne";	break;
12481f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_LT:
12491f5207b7SJohn Levon 				opname = "setb";	break;
12501f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_GT:
12511f5207b7SJohn Levon 				opname = "seta";	break;
12521f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_LTE:
12531f5207b7SJohn Levon 				opname = "setb";	break;
12541f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_GTE:
12551f5207b7SJohn Levon 				opname = "setae";	break;
12561f5207b7SJohn Levon 	default:
12571f5207b7SJohn Levon 		assert(0);
12581f5207b7SJohn Levon 		break;
12591f5207b7SJohn Levon 	}
12601f5207b7SJohn Levon 
12611f5207b7SJohn Levon 	/* init EDX to 0 */
12621f5207b7SJohn Levon 	val = new_storage(STOR_VALUE);
12631f5207b7SJohn Levon 	val->flags = STOR_WANTS_FREE;
12641f5207b7SJohn Levon 
12651f5207b7SJohn Levon 	reg1 = get_reg(&regclass_32_8);
12661f5207b7SJohn Levon 	emit_move(val, reg1, NULL, NULL);
12671f5207b7SJohn Levon 
12681f5207b7SJohn Levon 	/* move op1 into EAX */
12691f5207b7SJohn Levon 	reg2 = get_reg_value(left, get_regclass(expr->left));
12701f5207b7SJohn Levon 
12711f5207b7SJohn Levon 	/* perform comparison, RHS (op1, right) and LHS (op2, EAX) */
12721f5207b7SJohn Levon 	insn(opbits("cmp", right_bits), right, reg2, NULL);
12731f5207b7SJohn Levon 	put_reg(reg2);
12741f5207b7SJohn Levon 
12751f5207b7SJohn Levon 	/* store result of operation, 0 or 1, in DL using SETcc */
12761f5207b7SJohn Levon 	insn(opname, byte_reg(reg1), NULL, NULL);
12771f5207b7SJohn Levon 
12781f5207b7SJohn Levon 	/* finally, store the result (DL) in a new pseudo / stack slot */
12791f5207b7SJohn Levon 	new = stack_alloc(4);
12801f5207b7SJohn Levon 	emit_move(reg1, new, NULL, "end EXPR_COMPARE");
12811f5207b7SJohn Levon 	put_reg(reg1);
12821f5207b7SJohn Levon 
12831f5207b7SJohn Levon 	return new;
12841f5207b7SJohn Levon }
12851f5207b7SJohn Levon 
emit_value(struct expression * expr)12861f5207b7SJohn Levon static struct storage *emit_value(struct expression *expr)
12871f5207b7SJohn Levon {
12881f5207b7SJohn Levon #if 0 /* old and slow way */
12891f5207b7SJohn Levon 	struct storage *new = stack_alloc(4);
12901f5207b7SJohn Levon 	struct storage *val;
12911f5207b7SJohn Levon 
12921f5207b7SJohn Levon 	val = new_storage(STOR_VALUE);
12931f5207b7SJohn Levon 	val->value = (long long) expr->value;
12941f5207b7SJohn Levon 	val->flags = STOR_WANTS_FREE;
12951f5207b7SJohn Levon 	insn("movl", val, new, NULL);
12961f5207b7SJohn Levon 
12971f5207b7SJohn Levon 	return new;
12981f5207b7SJohn Levon #else
12991f5207b7SJohn Levon 	struct storage *val;
13001f5207b7SJohn Levon 
13011f5207b7SJohn Levon 	val = new_storage(STOR_VALUE);
13021f5207b7SJohn Levon 	val->value = (long long) expr->value;
13031f5207b7SJohn Levon 
13041f5207b7SJohn Levon 	return val;	/* FIXME: memory leak */
13051f5207b7SJohn Levon #endif
13061f5207b7SJohn Levon }
13071f5207b7SJohn Levon 
emit_divide(struct expression * expr,struct storage * left,struct storage * right)13081f5207b7SJohn Levon static struct storage *emit_divide(struct expression *expr, struct storage *left, struct storage *right)
13091f5207b7SJohn Levon {
13101f5207b7SJohn Levon 	struct storage *eax_edx;
13111f5207b7SJohn Levon 	struct storage *reg, *new;
13121f5207b7SJohn Levon 	struct storage *val = new_storage(STOR_VALUE);
13131f5207b7SJohn Levon 
13141f5207b7SJohn Levon 	emit_comment("begin DIVIDE");
13151f5207b7SJohn Levon 	eax_edx = get_hardreg(hardreg_storage_table + EAX_EDX, 1);
13161f5207b7SJohn Levon 
13171f5207b7SJohn Levon 	/* init EDX to 0 */
13181f5207b7SJohn Levon 	val->flags = STOR_WANTS_FREE;
13191f5207b7SJohn Levon 	emit_move(val, REG_EDX, NULL, NULL);
13201f5207b7SJohn Levon 
13211f5207b7SJohn Levon 	new = stack_alloc(expr->ctype->bit_size / 8);
13221f5207b7SJohn Levon 
13231f5207b7SJohn Levon 	/* EAX is dividend */
13241f5207b7SJohn Levon 	emit_move(left, REG_EAX, NULL, NULL);
13251f5207b7SJohn Levon 
13261f5207b7SJohn Levon 	reg = get_reg_value(right, &regclass_32);
13271f5207b7SJohn Levon 
13281f5207b7SJohn Levon 	/* perform binop */
13291f5207b7SJohn Levon 	insn("div", reg, REG_EAX, NULL);
13301f5207b7SJohn Levon 	put_reg(reg);
13311f5207b7SJohn Levon 
13321f5207b7SJohn Levon 	reg = REG_EAX;
13331f5207b7SJohn Levon 	if (expr->op == '%')
13341f5207b7SJohn Levon 		reg = REG_EDX;
13351f5207b7SJohn Levon 	emit_move(reg, new, NULL, NULL);
13361f5207b7SJohn Levon 
13371f5207b7SJohn Levon 	put_reg(eax_edx);
13381f5207b7SJohn Levon 	emit_comment("end DIVIDE");
13391f5207b7SJohn Levon 	return new;
13401f5207b7SJohn Levon }
13411f5207b7SJohn Levon 
emit_binop(struct expression * expr)13421f5207b7SJohn Levon static struct storage *emit_binop(struct expression *expr)
13431f5207b7SJohn Levon {
13441f5207b7SJohn Levon 	struct storage *left = x86_expression(expr->left);
13451f5207b7SJohn Levon 	struct storage *right = x86_expression(expr->right);
13461f5207b7SJohn Levon 	struct storage *new;
13471f5207b7SJohn Levon 	struct storage *dest, *src;
13481f5207b7SJohn Levon 	const char *opname = NULL;
13491f5207b7SJohn Levon 	const char *suffix = NULL;
13501f5207b7SJohn Levon 	char opstr[16];
13511f5207b7SJohn Levon 	int is_signed;
13521f5207b7SJohn Levon 
13531f5207b7SJohn Levon 	/* Divides have special register constraints */
13541f5207b7SJohn Levon 	if ((expr->op == '/') || (expr->op == '%'))
13551f5207b7SJohn Levon 		return emit_divide(expr, left, right);
13561f5207b7SJohn Levon 
1357*c85f09ccSJohn Levon 	is_signed = is_signed_type(expr->ctype);
13581f5207b7SJohn Levon 
13591f5207b7SJohn Levon 	switch (expr->op) {
13601f5207b7SJohn Levon 	case '+':
13611f5207b7SJohn Levon 		opname = "add";
13621f5207b7SJohn Levon 		break;
13631f5207b7SJohn Levon 	case '-':
13641f5207b7SJohn Levon 		opname = "sub";
13651f5207b7SJohn Levon 		break;
13661f5207b7SJohn Levon 	case '&':
13671f5207b7SJohn Levon 		opname = "and";
13681f5207b7SJohn Levon 		break;
13691f5207b7SJohn Levon 	case '|':
13701f5207b7SJohn Levon 		opname = "or";
13711f5207b7SJohn Levon 		break;
13721f5207b7SJohn Levon 	case '^':
13731f5207b7SJohn Levon 		opname = "xor";
13741f5207b7SJohn Levon 		break;
13751f5207b7SJohn Levon 	case SPECIAL_LEFTSHIFT:
13761f5207b7SJohn Levon 		opname = "shl";
13771f5207b7SJohn Levon 		break;
13781f5207b7SJohn Levon 	case SPECIAL_RIGHTSHIFT:
13791f5207b7SJohn Levon 		if (is_signed)
13801f5207b7SJohn Levon 			opname = "sar";
13811f5207b7SJohn Levon 		else
13821f5207b7SJohn Levon 			opname = "shr";
13831f5207b7SJohn Levon 		break;
13841f5207b7SJohn Levon 	case '*':
13851f5207b7SJohn Levon 		if (is_signed)
13861f5207b7SJohn Levon 			opname = "imul";
13871f5207b7SJohn Levon 		else
13881f5207b7SJohn Levon 			opname = "mul";
13891f5207b7SJohn Levon 		break;
13901f5207b7SJohn Levon 	case SPECIAL_LOGICAL_AND:
13911f5207b7SJohn Levon 		warning(expr->pos, "bogus bitwise and for logical op (should use '2*setne + and' or something)");
13921f5207b7SJohn Levon 		opname = "and";
13931f5207b7SJohn Levon 		break;
13941f5207b7SJohn Levon 	case SPECIAL_LOGICAL_OR:
13951f5207b7SJohn Levon 		warning(expr->pos, "bogus bitwise or for logical op (should use 'or + setne' or something)");
13961f5207b7SJohn Levon 		opname = "or";
13971f5207b7SJohn Levon 		break;
13981f5207b7SJohn Levon 	default:
13991f5207b7SJohn Levon 		error_die(expr->pos, "unhandled binop '%s'\n", show_special(expr->op));
14001f5207b7SJohn Levon 		break;
14011f5207b7SJohn Levon 	}
14021f5207b7SJohn Levon 
14031f5207b7SJohn Levon 	dest = get_reg_value(right, &regclass_32);
14041f5207b7SJohn Levon 	src = get_reg_value(left, &regclass_32);
14051f5207b7SJohn Levon 	switch (expr->ctype->bit_size) {
14061f5207b7SJohn Levon 	case 8:
14071f5207b7SJohn Levon 		suffix = "b";
14081f5207b7SJohn Levon 		break;
14091f5207b7SJohn Levon 	case 16:
14101f5207b7SJohn Levon 		suffix = "w";
14111f5207b7SJohn Levon 		break;
14121f5207b7SJohn Levon 	case 32:
14131f5207b7SJohn Levon 		suffix = "l";
14141f5207b7SJohn Levon 		break;
14151f5207b7SJohn Levon 	case 64:
14161f5207b7SJohn Levon 		suffix = "q";		/* FIXME */
14171f5207b7SJohn Levon 		break;
14181f5207b7SJohn Levon 	default:
14191f5207b7SJohn Levon 		assert(0);
14201f5207b7SJohn Levon 		break;
14211f5207b7SJohn Levon 	}
14221f5207b7SJohn Levon 
14231f5207b7SJohn Levon 	snprintf(opstr, sizeof(opstr), "%s%s", opname, suffix);
14241f5207b7SJohn Levon 
14251f5207b7SJohn Levon 	/* perform binop */
14261f5207b7SJohn Levon 	insn(opstr, src, dest, NULL);
14271f5207b7SJohn Levon 	put_reg(src);
14281f5207b7SJohn Levon 
14291f5207b7SJohn Levon 	/* store result in new pseudo / stack slot */
14301f5207b7SJohn Levon 	new = stack_alloc(expr->ctype->bit_size / 8);
14311f5207b7SJohn Levon 	emit_move(dest, new, NULL, "end EXPR_BINOP");
14321f5207b7SJohn Levon 
14331f5207b7SJohn Levon 	put_reg(dest);
14341f5207b7SJohn Levon 
14351f5207b7SJohn Levon 	return new;
14361f5207b7SJohn Levon }
14371f5207b7SJohn Levon 
emit_conditional_test(struct storage * val)14381f5207b7SJohn Levon static int emit_conditional_test(struct storage *val)
14391f5207b7SJohn Levon {
14401f5207b7SJohn Levon 	struct storage *reg;
14411f5207b7SJohn Levon 	struct storage *target_val;
14421f5207b7SJohn Levon 	int target_false;
14431f5207b7SJohn Levon 
14441f5207b7SJohn Levon 	/* load result into EAX */
14451f5207b7SJohn Levon 	emit_comment("begin if/conditional");
14461f5207b7SJohn Levon 	reg = get_reg_value(val, &regclass_32);
14471f5207b7SJohn Levon 
14481f5207b7SJohn Levon 	/* compare result with zero */
14491f5207b7SJohn Levon 	insn("test", reg, reg, NULL);
14501f5207b7SJohn Levon 	put_reg(reg);
14511f5207b7SJohn Levon 
14521f5207b7SJohn Levon 	/* create conditional-failed label to jump to */
14531f5207b7SJohn Levon 	target_false = new_label();
14541f5207b7SJohn Levon 	target_val = new_storage(STOR_LABEL);
14551f5207b7SJohn Levon 	target_val->label = target_false;
14561f5207b7SJohn Levon 	target_val->flags = STOR_WANTS_FREE;
14571f5207b7SJohn Levon 	insn("jz", target_val, NULL, NULL);
14581f5207b7SJohn Levon 
14591f5207b7SJohn Levon 	return target_false;
14601f5207b7SJohn Levon }
14611f5207b7SJohn Levon 
emit_conditional_end(int target_false)14621f5207b7SJohn Levon static int emit_conditional_end(int target_false)
14631f5207b7SJohn Levon {
14641f5207b7SJohn Levon 	struct storage *cond_end_st;
14651f5207b7SJohn Levon 	int cond_end;
14661f5207b7SJohn Levon 
14671f5207b7SJohn Levon 	/* finished generating code for if-true statement.
14681f5207b7SJohn Levon 	 * add a jump-to-end jump to avoid falling through
14691f5207b7SJohn Levon 	 * to the if-false statement code.
14701f5207b7SJohn Levon 	 */
14711f5207b7SJohn Levon 	cond_end = new_label();
14721f5207b7SJohn Levon 	cond_end_st = new_storage(STOR_LABEL);
14731f5207b7SJohn Levon 	cond_end_st->label = cond_end;
14741f5207b7SJohn Levon 	cond_end_st->flags = STOR_WANTS_FREE;
14751f5207b7SJohn Levon 	insn("jmp", cond_end_st, NULL, NULL);
14761f5207b7SJohn Levon 
14771f5207b7SJohn Levon 	/* if we have both if-true and if-false statements,
14781f5207b7SJohn Levon 	 * the failed-conditional case will fall through to here
14791f5207b7SJohn Levon 	 */
14801f5207b7SJohn Levon 	emit_label(target_false, NULL);
14811f5207b7SJohn Levon 
14821f5207b7SJohn Levon 	return cond_end;
14831f5207b7SJohn Levon }
14841f5207b7SJohn Levon 
emit_if_conditional(struct statement * stmt)14851f5207b7SJohn Levon static void emit_if_conditional(struct statement *stmt)
14861f5207b7SJohn Levon {
14871f5207b7SJohn Levon 	struct storage *val;
14881f5207b7SJohn Levon 	int cond_end;
14891f5207b7SJohn Levon 
14901f5207b7SJohn Levon 	/* emit test portion of conditional */
14911f5207b7SJohn Levon 	val = x86_expression(stmt->if_conditional);
14921f5207b7SJohn Levon 	cond_end = emit_conditional_test(val);
14931f5207b7SJohn Levon 
14941f5207b7SJohn Levon 	/* emit if-true statement */
14951f5207b7SJohn Levon 	x86_statement(stmt->if_true);
14961f5207b7SJohn Levon 
14971f5207b7SJohn Levon 	/* emit if-false statement, if present */
14981f5207b7SJohn Levon 	if (stmt->if_false) {
14991f5207b7SJohn Levon 		cond_end = emit_conditional_end(cond_end);
15001f5207b7SJohn Levon 		x86_statement(stmt->if_false);
15011f5207b7SJohn Levon 	}
15021f5207b7SJohn Levon 
15031f5207b7SJohn Levon 	/* end of conditional; jump target for if-true branch */
15041f5207b7SJohn Levon 	emit_label(cond_end, "end if");
15051f5207b7SJohn Levon }
15061f5207b7SJohn Levon 
emit_inc_dec(struct expression * expr,int postop)15071f5207b7SJohn Levon static struct storage *emit_inc_dec(struct expression *expr, int postop)
15081f5207b7SJohn Levon {
15091f5207b7SJohn Levon 	struct storage *addr = x86_address_gen(expr->unop);
15101f5207b7SJohn Levon 	struct storage *retval;
15111f5207b7SJohn Levon 	char opname[16];
15121f5207b7SJohn Levon 
15131f5207b7SJohn Levon 	strcpy(opname, opbits(expr->op == SPECIAL_INCREMENT ? "inc" : "dec",
15141f5207b7SJohn Levon 			      expr->ctype->bit_size));
15151f5207b7SJohn Levon 
15161f5207b7SJohn Levon 	if (postop) {
15171f5207b7SJohn Levon 		struct storage *new = stack_alloc(4);
15181f5207b7SJohn Levon 
15191f5207b7SJohn Levon 		emit_copy(new, addr, expr->unop->ctype);
15201f5207b7SJohn Levon 
15211f5207b7SJohn Levon 		retval = new;
15221f5207b7SJohn Levon 	} else
15231f5207b7SJohn Levon 		retval = addr;
15241f5207b7SJohn Levon 
15251f5207b7SJohn Levon 	insn(opname, addr, NULL, NULL);
15261f5207b7SJohn Levon 
15271f5207b7SJohn Levon 	return retval;
15281f5207b7SJohn Levon }
15291f5207b7SJohn Levon 
emit_postop(struct expression * expr)15301f5207b7SJohn Levon static struct storage *emit_postop(struct expression *expr)
15311f5207b7SJohn Levon {
15321f5207b7SJohn Levon 	return emit_inc_dec(expr, 1);
15331f5207b7SJohn Levon }
15341f5207b7SJohn Levon 
emit_return_stmt(struct statement * stmt)15351f5207b7SJohn Levon static struct storage *emit_return_stmt(struct statement *stmt)
15361f5207b7SJohn Levon {
15371f5207b7SJohn Levon 	struct function *f = current_func;
15381f5207b7SJohn Levon 	struct expression *expr = stmt->ret_value;
15391f5207b7SJohn Levon 	struct storage *val = NULL, *jmplbl;
15401f5207b7SJohn Levon 
15411f5207b7SJohn Levon 	if (expr && expr->ctype) {
15421f5207b7SJohn Levon 		val = x86_expression(expr);
15431f5207b7SJohn Levon 		assert(val != NULL);
15441f5207b7SJohn Levon 		emit_move(val, REG_EAX, expr->ctype, "return");
15451f5207b7SJohn Levon 	}
15461f5207b7SJohn Levon 
15471f5207b7SJohn Levon 	jmplbl = new_storage(STOR_LABEL);
15481f5207b7SJohn Levon 	jmplbl->flags |= STOR_WANTS_FREE;
15491f5207b7SJohn Levon 	jmplbl->label = f->ret_target;
15501f5207b7SJohn Levon 	insn("jmp", jmplbl, NULL, NULL);
15511f5207b7SJohn Levon 
15521f5207b7SJohn Levon 	return val;
15531f5207b7SJohn Levon }
15541f5207b7SJohn Levon 
emit_conditional_expr(struct expression * expr)15551f5207b7SJohn Levon static struct storage *emit_conditional_expr(struct expression *expr)
15561f5207b7SJohn Levon {
1557*c85f09ccSJohn Levon 	struct storage *cond, *stot = NULL, *stof = NULL;
15581f5207b7SJohn Levon 	struct storage *new = stack_alloc(expr->ctype->bit_size / 8);
15591f5207b7SJohn Levon 	int target_false, cond_end;
15601f5207b7SJohn Levon 
15611f5207b7SJohn Levon 	/* evaluate conditional */
15621f5207b7SJohn Levon 	cond = x86_expression(expr->conditional);
15631f5207b7SJohn Levon 	target_false = emit_conditional_test(cond);
15641f5207b7SJohn Levon 
15651f5207b7SJohn Levon 	/* handle if-true part of the expression */
1566*c85f09ccSJohn Levon 	stot = x86_expression(expr->cond_true);
15671f5207b7SJohn Levon 
1568*c85f09ccSJohn Levon 	emit_copy(new, stot, expr->ctype);
15691f5207b7SJohn Levon 
15701f5207b7SJohn Levon 	cond_end = emit_conditional_end(target_false);
15711f5207b7SJohn Levon 
15721f5207b7SJohn Levon 	/* handle if-false part of the expression */
1573*c85f09ccSJohn Levon 	stof = x86_expression(expr->cond_false);
15741f5207b7SJohn Levon 
1575*c85f09ccSJohn Levon 	emit_copy(new, stof, expr->ctype);
15761f5207b7SJohn Levon 
15771f5207b7SJohn Levon 	/* end of conditional; jump target for if-true branch */
15781f5207b7SJohn Levon 	emit_label(cond_end, "end conditional");
15791f5207b7SJohn Levon 
15801f5207b7SJohn Levon 	return new;
15811f5207b7SJohn Levon }
15821f5207b7SJohn Levon 
emit_select_expr(struct expression * expr)15831f5207b7SJohn Levon static struct storage *emit_select_expr(struct expression *expr)
15841f5207b7SJohn Levon {
15851f5207b7SJohn Levon 	struct storage *cond = x86_expression(expr->conditional);
1586*c85f09ccSJohn Levon 	struct storage *stot = x86_expression(expr->cond_true);
1587*c85f09ccSJohn Levon 	struct storage *stof = x86_expression(expr->cond_false);
15881f5207b7SJohn Levon 	struct storage *reg_cond, *reg_true, *reg_false;
15891f5207b7SJohn Levon 	struct storage *new = stack_alloc(4);
15901f5207b7SJohn Levon 
15911f5207b7SJohn Levon 	emit_comment("begin SELECT");
15921f5207b7SJohn Levon 	reg_cond = get_reg_value(cond, get_regclass(expr->conditional));
1593*c85f09ccSJohn Levon 	reg_true = get_reg_value(stot, get_regclass(expr));
1594*c85f09ccSJohn Levon 	reg_false = get_reg_value(stof, get_regclass(expr));
15951f5207b7SJohn Levon 
15961f5207b7SJohn Levon 	/*
15971f5207b7SJohn Levon 	 * Do the actual select: check the conditional for zero,
15981f5207b7SJohn Levon 	 * move false over true if zero
15991f5207b7SJohn Levon 	 */
16001f5207b7SJohn Levon 	insn("test", reg_cond, reg_cond, NULL);
16011f5207b7SJohn Levon 	insn("cmovz", reg_false, reg_true, NULL);
16021f5207b7SJohn Levon 
16031f5207b7SJohn Levon 	/* Store it back */
16041f5207b7SJohn Levon 	emit_move(reg_true, new, expr->ctype, NULL);
16051f5207b7SJohn Levon 	put_reg(reg_cond);
16061f5207b7SJohn Levon 	put_reg(reg_true);
16071f5207b7SJohn Levon 	put_reg(reg_false);
16081f5207b7SJohn Levon 	emit_comment("end SELECT");
16091f5207b7SJohn Levon 	return new;
16101f5207b7SJohn Levon }
16111f5207b7SJohn Levon 
emit_symbol_expr_init(struct symbol * sym)16121f5207b7SJohn Levon static struct storage *emit_symbol_expr_init(struct symbol *sym)
16131f5207b7SJohn Levon {
16141f5207b7SJohn Levon 	struct expression *expr = sym->initializer;
16151f5207b7SJohn Levon 	struct symbol_private *priv = sym->aux;
16161f5207b7SJohn Levon 
16171f5207b7SJohn Levon 	if (priv == NULL) {
16181f5207b7SJohn Levon 		priv = calloc(1, sizeof(*priv));
16191f5207b7SJohn Levon 		sym->aux = priv;
16201f5207b7SJohn Levon 
16211f5207b7SJohn Levon 		if (expr == NULL) {
16221f5207b7SJohn Levon 			struct storage *new = stack_alloc(4);
16231f5207b7SJohn Levon 			fprintf(stderr, "FIXME! no value for symbol %s.  creating pseudo %d (stack offset %d)\n",
16241f5207b7SJohn Levon 				show_ident(sym->ident),
16251f5207b7SJohn Levon 				new->pseudo, new->pseudo * 4);
16261f5207b7SJohn Levon 			priv->addr = new;
16271f5207b7SJohn Levon 		} else {
16281f5207b7SJohn Levon 			priv->addr = x86_expression(expr);
16291f5207b7SJohn Levon 		}
16301f5207b7SJohn Levon 	}
16311f5207b7SJohn Levon 
16321f5207b7SJohn Levon 	return priv->addr;
16331f5207b7SJohn Levon }
16341f5207b7SJohn Levon 
emit_string_expr(struct expression * expr)16351f5207b7SJohn Levon static struct storage *emit_string_expr(struct expression *expr)
16361f5207b7SJohn Levon {
16371f5207b7SJohn Levon 	struct function *f = current_func;
16381f5207b7SJohn Levon 	int label = new_label();
16391f5207b7SJohn Levon 	struct storage *new;
16401f5207b7SJohn Levon 
16411f5207b7SJohn Levon 	push_cstring(f, expr->string, label);
16421f5207b7SJohn Levon 
16431f5207b7SJohn Levon 	new = new_storage(STOR_LABEL);
16441f5207b7SJohn Levon 	new->label = label;
16451f5207b7SJohn Levon 	new->flags = STOR_LABEL_VAL | STOR_WANTS_FREE;
16461f5207b7SJohn Levon 	return new;
16471f5207b7SJohn Levon }
16481f5207b7SJohn Levon 
emit_cast_expr(struct expression * expr)16491f5207b7SJohn Levon static struct storage *emit_cast_expr(struct expression *expr)
16501f5207b7SJohn Levon {
16511f5207b7SJohn Levon 	struct symbol *old_type, *new_type;
16521f5207b7SJohn Levon 	struct storage *op = x86_expression(expr->cast_expression);
16531f5207b7SJohn Levon 	int oldbits, newbits;
16541f5207b7SJohn Levon 	struct storage *new;
16551f5207b7SJohn Levon 
16561f5207b7SJohn Levon 	old_type = expr->cast_expression->ctype;
16571f5207b7SJohn Levon 	new_type = expr->cast_type;
16581f5207b7SJohn Levon 
16591f5207b7SJohn Levon 	oldbits = old_type->bit_size;
16601f5207b7SJohn Levon 	newbits = new_type->bit_size;
16611f5207b7SJohn Levon 	if (oldbits >= newbits)
16621f5207b7SJohn Levon 		return op;
16631f5207b7SJohn Levon 
16641f5207b7SJohn Levon 	emit_move(op, REG_EAX, old_type, "begin cast ..");
16651f5207b7SJohn Levon 
16661f5207b7SJohn Levon 	new = stack_alloc(newbits / 8);
16671f5207b7SJohn Levon 	emit_move(REG_EAX, new, new_type, ".... end cast");
16681f5207b7SJohn Levon 
16691f5207b7SJohn Levon 	return new;
16701f5207b7SJohn Levon }
16711f5207b7SJohn Levon 
emit_regular_preop(struct expression * expr)16721f5207b7SJohn Levon static struct storage *emit_regular_preop(struct expression *expr)
16731f5207b7SJohn Levon {
16741f5207b7SJohn Levon 	struct storage *target = x86_expression(expr->unop);
16751f5207b7SJohn Levon 	struct storage *val, *new = stack_alloc(4);
16761f5207b7SJohn Levon 	const char *opname = NULL;
16771f5207b7SJohn Levon 
16781f5207b7SJohn Levon 	switch (expr->op) {
16791f5207b7SJohn Levon 	case '!':
16801f5207b7SJohn Levon 		val = new_storage(STOR_VALUE);
16811f5207b7SJohn Levon 		val->flags = STOR_WANTS_FREE;
16821f5207b7SJohn Levon 		emit_move(val, REG_EDX, NULL, NULL);
16831f5207b7SJohn Levon 		emit_move(target, REG_EAX, expr->unop->ctype, NULL);
16841f5207b7SJohn Levon 		insn("test", REG_EAX, REG_EAX, NULL);
16851f5207b7SJohn Levon 		insn("setz", REG_DL, NULL, NULL);
16861f5207b7SJohn Levon 		emit_move(REG_EDX, new, expr->unop->ctype, NULL);
16871f5207b7SJohn Levon 
16881f5207b7SJohn Levon 		break;
16891f5207b7SJohn Levon 	case '~':
16901f5207b7SJohn Levon 		opname = "not";
16911f5207b7SJohn Levon 	case '-':
16921f5207b7SJohn Levon 		if (!opname)
16931f5207b7SJohn Levon 			opname = "neg";
16941f5207b7SJohn Levon 		emit_move(target, REG_EAX, expr->unop->ctype, NULL);
16951f5207b7SJohn Levon 		insn(opname, REG_EAX, NULL, NULL);
16961f5207b7SJohn Levon 		emit_move(REG_EAX, new, expr->unop->ctype, NULL);
16971f5207b7SJohn Levon 		break;
16981f5207b7SJohn Levon 	default:
16991f5207b7SJohn Levon 		assert(0);
17001f5207b7SJohn Levon 		break;
17011f5207b7SJohn Levon 	}
17021f5207b7SJohn Levon 
17031f5207b7SJohn Levon 	return new;
17041f5207b7SJohn Levon }
17051f5207b7SJohn Levon 
emit_case_statement(struct statement * stmt)17061f5207b7SJohn Levon static void emit_case_statement(struct statement *stmt)
17071f5207b7SJohn Levon {
17081f5207b7SJohn Levon 	emit_labelsym(stmt->case_label, NULL);
17091f5207b7SJohn Levon 	x86_statement(stmt->case_statement);
17101f5207b7SJohn Levon }
17111f5207b7SJohn Levon 
emit_switch_statement(struct statement * stmt)17121f5207b7SJohn Levon static void emit_switch_statement(struct statement *stmt)
17131f5207b7SJohn Levon {
17141f5207b7SJohn Levon 	struct storage *val = x86_expression(stmt->switch_expression);
17151f5207b7SJohn Levon 	struct symbol *sym, *default_sym = NULL;
17161f5207b7SJohn Levon 	struct storage *labelsym, *label;
17171f5207b7SJohn Levon 	int switch_end = 0;
17181f5207b7SJohn Levon 
17191f5207b7SJohn Levon 	emit_move(val, REG_EAX, stmt->switch_expression->ctype, "begin case");
17201f5207b7SJohn Levon 
17211f5207b7SJohn Levon 	/*
17221f5207b7SJohn Levon 	 * This is where a _real_ back-end would go through the
17231f5207b7SJohn Levon 	 * cases to decide whether to use a lookup table or a
17241f5207b7SJohn Levon 	 * series of comparisons etc
17251f5207b7SJohn Levon 	 */
17261f5207b7SJohn Levon 	FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) {
17271f5207b7SJohn Levon 		struct statement *case_stmt = sym->stmt;
17281f5207b7SJohn Levon 		struct expression *expr = case_stmt->case_expression;
17291f5207b7SJohn Levon 		struct expression *to = case_stmt->case_to;
17301f5207b7SJohn Levon 
17311f5207b7SJohn Levon 		/* default: */
17321f5207b7SJohn Levon 		if (!expr)
17331f5207b7SJohn Levon 			default_sym = sym;
17341f5207b7SJohn Levon 
17351f5207b7SJohn Levon 		/* case NNN: */
17361f5207b7SJohn Levon 		else {
17371f5207b7SJohn Levon 			struct storage *case_val = new_val(expr->value);
17381f5207b7SJohn Levon 
17391f5207b7SJohn Levon 			assert (expr->type == EXPR_VALUE);
17401f5207b7SJohn Levon 
17411f5207b7SJohn Levon 			insn("cmpl", case_val, REG_EAX, NULL);
17421f5207b7SJohn Levon 
17431f5207b7SJohn Levon 			if (!to) {
17441f5207b7SJohn Levon 				labelsym = new_labelsym(sym);
17451f5207b7SJohn Levon 				insn("je", labelsym, NULL, NULL);
17461f5207b7SJohn Levon 			} else {
17471f5207b7SJohn Levon 				int next_test;
17481f5207b7SJohn Levon 
17491f5207b7SJohn Levon 				label = new_storage(STOR_LABEL);
17501f5207b7SJohn Levon 				label->flags |= STOR_WANTS_FREE;
17511f5207b7SJohn Levon 				label->label = next_test = new_label();
17521f5207b7SJohn Levon 
17531f5207b7SJohn Levon 				/* FIXME: signed/unsigned */
17541f5207b7SJohn Levon 				insn("jl", label, NULL, NULL);
17551f5207b7SJohn Levon 
17561f5207b7SJohn Levon 				case_val = new_val(to->value);
17571f5207b7SJohn Levon 				insn("cmpl", case_val, REG_EAX, NULL);
17581f5207b7SJohn Levon 
17591f5207b7SJohn Levon 				/* TODO: implement and use refcounting... */
17601f5207b7SJohn Levon 				label = new_storage(STOR_LABEL);
17611f5207b7SJohn Levon 				label->flags |= STOR_WANTS_FREE;
17621f5207b7SJohn Levon 				label->label = next_test;
17631f5207b7SJohn Levon 
17641f5207b7SJohn Levon 				/* FIXME: signed/unsigned */
17651f5207b7SJohn Levon 				insn("jg", label, NULL, NULL);
17661f5207b7SJohn Levon 
17671f5207b7SJohn Levon 				labelsym = new_labelsym(sym);
17681f5207b7SJohn Levon 				insn("jmp", labelsym, NULL, NULL);
17691f5207b7SJohn Levon 
17701f5207b7SJohn Levon 				emit_label(next_test, NULL);
17711f5207b7SJohn Levon 			}
17721f5207b7SJohn Levon 		}
17731f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sym);
17741f5207b7SJohn Levon 
17751f5207b7SJohn Levon 	if (default_sym) {
17761f5207b7SJohn Levon 		labelsym = new_labelsym(default_sym);
17771f5207b7SJohn Levon 		insn("jmp", labelsym, NULL, "default");
17781f5207b7SJohn Levon 	} else {
17791f5207b7SJohn Levon 		label = new_storage(STOR_LABEL);
17801f5207b7SJohn Levon 		label->flags |= STOR_WANTS_FREE;
17811f5207b7SJohn Levon 		label->label = switch_end = new_label();
17821f5207b7SJohn Levon 		insn("jmp", label, NULL, "goto end of switch");
17831f5207b7SJohn Levon 	}
17841f5207b7SJohn Levon 
17851f5207b7SJohn Levon 	x86_statement(stmt->switch_statement);
17861f5207b7SJohn Levon 
17871f5207b7SJohn Levon 	if (stmt->switch_break->used)
17881f5207b7SJohn Levon 		emit_labelsym(stmt->switch_break, NULL);
17891f5207b7SJohn Levon 
17901f5207b7SJohn Levon 	if (switch_end)
17911f5207b7SJohn Levon 		emit_label(switch_end, NULL);
17921f5207b7SJohn Levon }
17931f5207b7SJohn Levon 
x86_struct_member(struct symbol * sym)17941f5207b7SJohn Levon static void x86_struct_member(struct symbol *sym)
17951f5207b7SJohn Levon {
17961f5207b7SJohn Levon 	printf("\t%s:%d:%ld at offset %ld.%d", show_ident(sym->ident), sym->bit_size, sym->ctype.alignment, sym->offset, sym->bit_offset);
17971f5207b7SJohn Levon 	printf("\n");
17981f5207b7SJohn Levon }
17991f5207b7SJohn Levon 
x86_symbol(struct symbol * sym)18001f5207b7SJohn Levon static void x86_symbol(struct symbol *sym)
18011f5207b7SJohn Levon {
18021f5207b7SJohn Levon 	struct symbol *type;
18031f5207b7SJohn Levon 
18041f5207b7SJohn Levon 	if (!sym)
18051f5207b7SJohn Levon 		return;
18061f5207b7SJohn Levon 
18071f5207b7SJohn Levon 	type = sym->ctype.base_type;
18081f5207b7SJohn Levon 	if (!type)
18091f5207b7SJohn Levon 		return;
18101f5207b7SJohn Levon 
18111f5207b7SJohn Levon 	/*
18121f5207b7SJohn Levon 	 * Show actual implementation information
18131f5207b7SJohn Levon 	 */
18141f5207b7SJohn Levon 	switch (type->type) {
18151f5207b7SJohn Levon 
18161f5207b7SJohn Levon 	case SYM_ARRAY:
18171f5207b7SJohn Levon 		if (sym->initializer)
18181f5207b7SJohn Levon 			emit_array(sym);
18191f5207b7SJohn Levon 		else
18201f5207b7SJohn Levon 			emit_array_noinit(sym);
18211f5207b7SJohn Levon 		break;
18221f5207b7SJohn Levon 
18231f5207b7SJohn Levon 	case SYM_BASETYPE:
18241f5207b7SJohn Levon 		if (sym->initializer) {
18251f5207b7SJohn Levon 			emit_object_pre(show_ident(sym->ident),
18261f5207b7SJohn Levon 					sym->ctype.modifiers,
18271f5207b7SJohn Levon 				        sym->ctype.alignment,
18281f5207b7SJohn Levon 					sym->bit_size / 8);
18291f5207b7SJohn Levon 			emit_scalar(sym->initializer, sym->bit_size);
18301f5207b7SJohn Levon 			stor_sym_init(sym);
18311f5207b7SJohn Levon 		} else
18321f5207b7SJohn Levon 			emit_scalar_noinit(sym);
18331f5207b7SJohn Levon 		break;
18341f5207b7SJohn Levon 
18351f5207b7SJohn Levon 	case SYM_STRUCT:
18361f5207b7SJohn Levon 	case SYM_UNION: {
18371f5207b7SJohn Levon 		struct symbol *member;
18381f5207b7SJohn Levon 
18391f5207b7SJohn Levon 		printf(" {\n");
18401f5207b7SJohn Levon 		FOR_EACH_PTR(type->symbol_list, member) {
18411f5207b7SJohn Levon 			x86_struct_member(member);
18421f5207b7SJohn Levon 		} END_FOR_EACH_PTR(member);
18431f5207b7SJohn Levon 		printf("}\n");
18441f5207b7SJohn Levon 		break;
18451f5207b7SJohn Levon 	}
18461f5207b7SJohn Levon 
18471f5207b7SJohn Levon 	case SYM_FN: {
18481f5207b7SJohn Levon 		struct statement *stmt = type->stmt;
18491f5207b7SJohn Levon 		if (stmt) {
18501f5207b7SJohn Levon 			emit_func_pre(sym);
18511f5207b7SJohn Levon 			x86_statement(stmt);
18521f5207b7SJohn Levon 			emit_func_post(sym);
18531f5207b7SJohn Levon 		}
18541f5207b7SJohn Levon 		break;
18551f5207b7SJohn Levon 	}
18561f5207b7SJohn Levon 
18571f5207b7SJohn Levon 	default:
18581f5207b7SJohn Levon 		break;
18591f5207b7SJohn Levon 	}
18601f5207b7SJohn Levon 
18611f5207b7SJohn Levon 	if (sym->initializer && (type->type != SYM_BASETYPE) &&
18621f5207b7SJohn Levon 	    (type->type != SYM_ARRAY)) {
18631f5207b7SJohn Levon 		printf(" = \n");
18641f5207b7SJohn Levon 		x86_expression(sym->initializer);
18651f5207b7SJohn Levon 	}
18661f5207b7SJohn Levon }
18671f5207b7SJohn Levon 
18681f5207b7SJohn Levon static void x86_symbol_init(struct symbol *sym);
18691f5207b7SJohn Levon 
x86_symbol_decl(struct symbol_list * syms)18701f5207b7SJohn Levon static void x86_symbol_decl(struct symbol_list *syms)
18711f5207b7SJohn Levon {
18721f5207b7SJohn Levon 	struct symbol *sym;
18731f5207b7SJohn Levon 	FOR_EACH_PTR(syms, sym) {
18741f5207b7SJohn Levon 		x86_symbol_init(sym);
18751f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sym);
18761f5207b7SJohn Levon }
18771f5207b7SJohn Levon 
loopstk_push(int cont_lbl,int loop_bottom_lbl)18781f5207b7SJohn Levon static void loopstk_push(int cont_lbl, int loop_bottom_lbl)
18791f5207b7SJohn Levon {
18801f5207b7SJohn Levon 	struct function *f = current_func;
18811f5207b7SJohn Levon 	struct loop_stack *ls;
18821f5207b7SJohn Levon 
18831f5207b7SJohn Levon 	ls = malloc(sizeof(*ls));
18841f5207b7SJohn Levon 	ls->continue_lbl = cont_lbl;
18851f5207b7SJohn Levon 	ls->loop_bottom_lbl = loop_bottom_lbl;
18861f5207b7SJohn Levon 	ls->next = f->loop_stack;
18871f5207b7SJohn Levon 	f->loop_stack = ls;
18881f5207b7SJohn Levon }
18891f5207b7SJohn Levon 
loopstk_pop(void)18901f5207b7SJohn Levon static void loopstk_pop(void)
18911f5207b7SJohn Levon {
18921f5207b7SJohn Levon 	struct function *f = current_func;
18931f5207b7SJohn Levon 	struct loop_stack *ls;
18941f5207b7SJohn Levon 
18951f5207b7SJohn Levon 	assert(f->loop_stack != NULL);
18961f5207b7SJohn Levon 	ls = f->loop_stack;
18971f5207b7SJohn Levon 	f->loop_stack = f->loop_stack->next;
18981f5207b7SJohn Levon 	free(ls);
18991f5207b7SJohn Levon }
19001f5207b7SJohn Levon 
loopstk_break(void)19011f5207b7SJohn Levon static int loopstk_break(void)
19021f5207b7SJohn Levon {
19031f5207b7SJohn Levon 	return current_func->loop_stack->loop_bottom_lbl;
19041f5207b7SJohn Levon }
19051f5207b7SJohn Levon 
loopstk_continue(void)19061f5207b7SJohn Levon static int loopstk_continue(void)
19071f5207b7SJohn Levon {
19081f5207b7SJohn Levon 	return current_func->loop_stack->continue_lbl;
19091f5207b7SJohn Levon }
19101f5207b7SJohn Levon 
emit_loop(struct statement * stmt)19111f5207b7SJohn Levon static void emit_loop(struct statement *stmt)
19121f5207b7SJohn Levon {
19131f5207b7SJohn Levon 	struct statement  *pre_statement = stmt->iterator_pre_statement;
19141f5207b7SJohn Levon 	struct expression *pre_condition = stmt->iterator_pre_condition;
19151f5207b7SJohn Levon 	struct statement  *statement = stmt->iterator_statement;
19161f5207b7SJohn Levon 	struct statement  *post_statement = stmt->iterator_post_statement;
19171f5207b7SJohn Levon 	struct expression *post_condition = stmt->iterator_post_condition;
19181f5207b7SJohn Levon 	int loop_top = 0, loop_bottom, loop_continue;
19191f5207b7SJohn Levon 	int have_bottom = 0;
19201f5207b7SJohn Levon 	struct storage *val;
19211f5207b7SJohn Levon 
19221f5207b7SJohn Levon 	loop_bottom = new_label();
19231f5207b7SJohn Levon 	loop_continue = new_label();
19241f5207b7SJohn Levon 	loopstk_push(loop_continue, loop_bottom);
19251f5207b7SJohn Levon 
19261f5207b7SJohn Levon 	x86_symbol_decl(stmt->iterator_syms);
19271f5207b7SJohn Levon 	x86_statement(pre_statement);
19281f5207b7SJohn Levon 	if (!post_condition || post_condition->type != EXPR_VALUE || post_condition->value) {
19291f5207b7SJohn Levon 		loop_top = new_label();
19301f5207b7SJohn Levon 		emit_label(loop_top, "loop top");
19311f5207b7SJohn Levon 	}
19321f5207b7SJohn Levon 	if (pre_condition) {
19331f5207b7SJohn Levon 		if (pre_condition->type == EXPR_VALUE) {
19341f5207b7SJohn Levon 			if (!pre_condition->value) {
19351f5207b7SJohn Levon 				struct storage *lbv;
19361f5207b7SJohn Levon 				lbv = new_storage(STOR_LABEL);
19371f5207b7SJohn Levon 				lbv->label = loop_bottom;
19381f5207b7SJohn Levon 				lbv->flags = STOR_WANTS_FREE;
19391f5207b7SJohn Levon 				insn("jmp", lbv, NULL, "go to loop bottom");
19401f5207b7SJohn Levon 				have_bottom = 1;
19411f5207b7SJohn Levon 			}
19421f5207b7SJohn Levon 		} else {
19431f5207b7SJohn Levon 			struct storage *lbv = new_storage(STOR_LABEL);
19441f5207b7SJohn Levon 			lbv->label = loop_bottom;
19451f5207b7SJohn Levon 			lbv->flags = STOR_WANTS_FREE;
19461f5207b7SJohn Levon 			have_bottom = 1;
19471f5207b7SJohn Levon 
19481f5207b7SJohn Levon 			val = x86_expression(pre_condition);
19491f5207b7SJohn Levon 
19501f5207b7SJohn Levon 			emit_move(val, REG_EAX, NULL, "loop pre condition");
19511f5207b7SJohn Levon 			insn("test", REG_EAX, REG_EAX, NULL);
19521f5207b7SJohn Levon 			insn("jz", lbv, NULL, NULL);
19531f5207b7SJohn Levon 		}
19541f5207b7SJohn Levon 	}
19551f5207b7SJohn Levon 	x86_statement(statement);
19561f5207b7SJohn Levon 	if (stmt->iterator_continue->used)
19571f5207b7SJohn Levon 		emit_label(loop_continue, "'continue' iterator");
19581f5207b7SJohn Levon 	x86_statement(post_statement);
19591f5207b7SJohn Levon 	if (!post_condition) {
19601f5207b7SJohn Levon 		struct storage *lbv = new_storage(STOR_LABEL);
19611f5207b7SJohn Levon 		lbv->label = loop_top;
19621f5207b7SJohn Levon 		lbv->flags = STOR_WANTS_FREE;
19631f5207b7SJohn Levon 		insn("jmp", lbv, NULL, "go to loop top");
19641f5207b7SJohn Levon 	} else if (post_condition->type == EXPR_VALUE) {
19651f5207b7SJohn Levon 		if (post_condition->value) {
19661f5207b7SJohn Levon 			struct storage *lbv = new_storage(STOR_LABEL);
19671f5207b7SJohn Levon 			lbv->label = loop_top;
19681f5207b7SJohn Levon 			lbv->flags = STOR_WANTS_FREE;
19691f5207b7SJohn Levon 			insn("jmp", lbv, NULL, "go to loop top");
19701f5207b7SJohn Levon 		}
19711f5207b7SJohn Levon 	} else {
19721f5207b7SJohn Levon 		struct storage *lbv = new_storage(STOR_LABEL);
19731f5207b7SJohn Levon 		lbv->label = loop_top;
19741f5207b7SJohn Levon 		lbv->flags = STOR_WANTS_FREE;
19751f5207b7SJohn Levon 
19761f5207b7SJohn Levon 		val = x86_expression(post_condition);
19771f5207b7SJohn Levon 
19781f5207b7SJohn Levon 		emit_move(val, REG_EAX, NULL, "loop post condition");
19791f5207b7SJohn Levon 		insn("test", REG_EAX, REG_EAX, NULL);
19801f5207b7SJohn Levon 		insn("jnz", lbv, NULL, NULL);
19811f5207b7SJohn Levon 	}
19821f5207b7SJohn Levon 	if (have_bottom || stmt->iterator_break->used)
19831f5207b7SJohn Levon 		emit_label(loop_bottom, "loop bottom");
19841f5207b7SJohn Levon 
19851f5207b7SJohn Levon 	loopstk_pop();
19861f5207b7SJohn Levon }
19871f5207b7SJohn Levon 
19881f5207b7SJohn Levon /*
19891f5207b7SJohn Levon  * Print out a statement
19901f5207b7SJohn Levon  */
x86_statement(struct statement * stmt)19911f5207b7SJohn Levon static struct storage *x86_statement(struct statement *stmt)
19921f5207b7SJohn Levon {
19931f5207b7SJohn Levon 	if (!stmt)
19941f5207b7SJohn Levon 		return NULL;
19951f5207b7SJohn Levon 	switch (stmt->type) {
19961f5207b7SJohn Levon 	default:
19971f5207b7SJohn Levon 		return NULL;
19981f5207b7SJohn Levon 	case STMT_RETURN:
19991f5207b7SJohn Levon 		return emit_return_stmt(stmt);
20001f5207b7SJohn Levon 	case STMT_DECLARATION:
20011f5207b7SJohn Levon 		x86_symbol_decl(stmt->declaration);
20021f5207b7SJohn Levon 		break;
20031f5207b7SJohn Levon 	case STMT_COMPOUND: {
20041f5207b7SJohn Levon 		struct statement *s;
20051f5207b7SJohn Levon 		struct storage *last = NULL;
20061f5207b7SJohn Levon 
20071f5207b7SJohn Levon 		FOR_EACH_PTR(stmt->stmts, s) {
20081f5207b7SJohn Levon 			last = x86_statement(s);
20091f5207b7SJohn Levon 		} END_FOR_EACH_PTR(s);
20101f5207b7SJohn Levon 
20111f5207b7SJohn Levon 		return last;
20121f5207b7SJohn Levon 	}
20131f5207b7SJohn Levon 
20141f5207b7SJohn Levon 	case STMT_EXPRESSION:
20151f5207b7SJohn Levon 		return x86_expression(stmt->expression);
20161f5207b7SJohn Levon 	case STMT_IF:
20171f5207b7SJohn Levon 		emit_if_conditional(stmt);
20181f5207b7SJohn Levon 		return NULL;
20191f5207b7SJohn Levon 
20201f5207b7SJohn Levon 	case STMT_CASE:
20211f5207b7SJohn Levon 		emit_case_statement(stmt);
20221f5207b7SJohn Levon 		break;
20231f5207b7SJohn Levon 	case STMT_SWITCH:
20241f5207b7SJohn Levon 		emit_switch_statement(stmt);
20251f5207b7SJohn Levon 		break;
20261f5207b7SJohn Levon 
20271f5207b7SJohn Levon 	case STMT_ITERATOR:
20281f5207b7SJohn Levon 		emit_loop(stmt);
20291f5207b7SJohn Levon 		break;
20301f5207b7SJohn Levon 
20311f5207b7SJohn Levon 	case STMT_NONE:
20321f5207b7SJohn Levon 		break;
20331f5207b7SJohn Levon 
20341f5207b7SJohn Levon 	case STMT_LABEL:
20351f5207b7SJohn Levon 		printf(".L%p:\n", stmt->label_identifier);
20361f5207b7SJohn Levon 		x86_statement(stmt->label_statement);
20371f5207b7SJohn Levon 		break;
20381f5207b7SJohn Levon 
20391f5207b7SJohn Levon 	case STMT_GOTO:
20401f5207b7SJohn Levon 		if (stmt->goto_expression) {
20411f5207b7SJohn Levon 			struct storage *val = x86_expression(stmt->goto_expression);
20421f5207b7SJohn Levon 			printf("\tgoto *v%d\n", val->pseudo);
20431f5207b7SJohn Levon 		} else if (!strcmp("break", show_ident(stmt->goto_label->ident))) {
20441f5207b7SJohn Levon 			struct storage *lbv = new_storage(STOR_LABEL);
20451f5207b7SJohn Levon 			lbv->label = loopstk_break();
20461f5207b7SJohn Levon 			lbv->flags = STOR_WANTS_FREE;
20471f5207b7SJohn Levon 			insn("jmp", lbv, NULL, "'break'; go to loop bottom");
20481f5207b7SJohn Levon 		} else if (!strcmp("continue", show_ident(stmt->goto_label->ident))) {
20491f5207b7SJohn Levon 			struct storage *lbv = new_storage(STOR_LABEL);
20501f5207b7SJohn Levon 			lbv->label = loopstk_continue();
20511f5207b7SJohn Levon 			lbv->flags = STOR_WANTS_FREE;
20521f5207b7SJohn Levon 			insn("jmp", lbv, NULL, "'continue'; go to loop top");
20531f5207b7SJohn Levon 		} else {
20541f5207b7SJohn Levon 			struct storage *labelsym = new_labelsym(stmt->goto_label);
20551f5207b7SJohn Levon 			insn("jmp", labelsym, NULL, NULL);
20561f5207b7SJohn Levon 		}
20571f5207b7SJohn Levon 		break;
20581f5207b7SJohn Levon 	case STMT_ASM:
20591f5207b7SJohn Levon 		printf("\tasm( .... )\n");
20601f5207b7SJohn Levon 		break;
20611f5207b7SJohn Levon 	}
20621f5207b7SJohn Levon 	return NULL;
20631f5207b7SJohn Levon }
20641f5207b7SJohn Levon 
x86_call_expression(struct expression * expr)20651f5207b7SJohn Levon static struct storage *x86_call_expression(struct expression *expr)
20661f5207b7SJohn Levon {
20671f5207b7SJohn Levon 	struct function *f = current_func;
20681f5207b7SJohn Levon 	struct symbol *direct;
20691f5207b7SJohn Levon 	struct expression *arg, *fn;
20701f5207b7SJohn Levon 	struct storage *retval, *fncall;
20711f5207b7SJohn Levon 	int framesize;
20721f5207b7SJohn Levon 	char s[64];
20731f5207b7SJohn Levon 
20741f5207b7SJohn Levon 	if (!expr->ctype) {
20751f5207b7SJohn Levon 		warning(expr->pos, "\tcall with no type!");
20761f5207b7SJohn Levon 		return NULL;
20771f5207b7SJohn Levon 	}
20781f5207b7SJohn Levon 
20791f5207b7SJohn Levon 	framesize = 0;
20801f5207b7SJohn Levon 	FOR_EACH_PTR_REVERSE(expr->args, arg) {
20811f5207b7SJohn Levon 		struct storage *new = x86_expression(arg);
20821f5207b7SJohn Levon 		int size = arg->ctype->bit_size;
20831f5207b7SJohn Levon 
20841f5207b7SJohn Levon 		/*
20851f5207b7SJohn Levon 		 * FIXME: i386 SysV ABI dictates that values
20861f5207b7SJohn Levon 		 * smaller than 32 bits should be placed onto
20871f5207b7SJohn Levon 		 * the stack as 32-bit objects.  We should not
20881f5207b7SJohn Levon 		 * blindly do a 32-bit push on objects smaller
20891f5207b7SJohn Levon 		 * than 32 bits.
20901f5207b7SJohn Levon 		 */
20911f5207b7SJohn Levon 		if (size < 32)
20921f5207b7SJohn Levon 			size = 32;
20931f5207b7SJohn Levon 		insn("pushl", new, NULL,
20941f5207b7SJohn Levon 		     !framesize ? "begin function call" : NULL);
20951f5207b7SJohn Levon 
20961f5207b7SJohn Levon 		framesize += bits_to_bytes(size);
20971f5207b7SJohn Levon 	} END_FOR_EACH_PTR_REVERSE(arg);
20981f5207b7SJohn Levon 
20991f5207b7SJohn Levon 	fn = expr->fn;
21001f5207b7SJohn Levon 
21011f5207b7SJohn Levon 	/* Remove dereference, if any */
21021f5207b7SJohn Levon 	direct = NULL;
21031f5207b7SJohn Levon 	if (fn->type == EXPR_PREOP) {
21041f5207b7SJohn Levon 		if (fn->unop->type == EXPR_SYMBOL) {
21051f5207b7SJohn Levon 			struct symbol *sym = fn->unop->symbol;
21061f5207b7SJohn Levon 			if (sym->ctype.base_type->type == SYM_FN)
21071f5207b7SJohn Levon 				direct = sym;
21081f5207b7SJohn Levon 		}
21091f5207b7SJohn Levon 	}
21101f5207b7SJohn Levon 	if (direct) {
21111f5207b7SJohn Levon 		struct storage *direct_stor = new_storage(STOR_SYM);
21121f5207b7SJohn Levon 		direct_stor->flags |= STOR_WANTS_FREE;
21131f5207b7SJohn Levon 		direct_stor->sym = direct;
21141f5207b7SJohn Levon 		insn("call", direct_stor, NULL, NULL);
21151f5207b7SJohn Levon 	} else {
21161f5207b7SJohn Levon 		fncall = x86_expression(fn);
21171f5207b7SJohn Levon 		emit_move(fncall, REG_EAX, fn->ctype, NULL);
21181f5207b7SJohn Levon 
21191f5207b7SJohn Levon 		strcpy(s, "\tcall\t*%eax\n");
21201f5207b7SJohn Levon 		push_text_atom(f, s);
21211f5207b7SJohn Levon 	}
21221f5207b7SJohn Levon 
21231f5207b7SJohn Levon 	/* FIXME: pay attention to BITS_IN_POINTER */
21241f5207b7SJohn Levon 	if (framesize) {
21251f5207b7SJohn Levon 		struct storage *val = new_storage(STOR_VALUE);
21261f5207b7SJohn Levon 		val->value = (long long) framesize;
21271f5207b7SJohn Levon 		val->flags = STOR_WANTS_FREE;
21281f5207b7SJohn Levon 		insn("addl", val, REG_ESP, NULL);
21291f5207b7SJohn Levon 	}
21301f5207b7SJohn Levon 
21311f5207b7SJohn Levon 	retval = stack_alloc(4);
21321f5207b7SJohn Levon 	emit_move(REG_EAX, retval, NULL, "end function call");
21331f5207b7SJohn Levon 
21341f5207b7SJohn Levon 	return retval;
21351f5207b7SJohn Levon }
21361f5207b7SJohn Levon 
x86_address_gen(struct expression * expr)21371f5207b7SJohn Levon static struct storage *x86_address_gen(struct expression *expr)
21381f5207b7SJohn Levon {
21391f5207b7SJohn Levon 	struct function *f = current_func;
21401f5207b7SJohn Levon 	struct storage *addr;
21411f5207b7SJohn Levon 	struct storage *new;
21421f5207b7SJohn Levon 	char s[32];
21431f5207b7SJohn Levon 
21441f5207b7SJohn Levon 	addr = x86_expression(expr->unop);
21451f5207b7SJohn Levon 	if (expr->unop->type == EXPR_SYMBOL)
21461f5207b7SJohn Levon 		return addr;
21471f5207b7SJohn Levon 
21481f5207b7SJohn Levon 	emit_move(addr, REG_EAX, NULL, "begin deref ..");
21491f5207b7SJohn Levon 
21501f5207b7SJohn Levon 	/* FIXME: operand size */
21511f5207b7SJohn Levon 	strcpy(s, "\tmovl\t(%eax), %ecx\n");
21521f5207b7SJohn Levon 	push_text_atom(f, s);
21531f5207b7SJohn Levon 
21541f5207b7SJohn Levon 	new = stack_alloc(4);
21551f5207b7SJohn Levon 	emit_move(REG_ECX, new, NULL, ".... end deref");
21561f5207b7SJohn Levon 
21571f5207b7SJohn Levon 	return new;
21581f5207b7SJohn Levon }
21591f5207b7SJohn Levon 
x86_assignment(struct expression * expr)21601f5207b7SJohn Levon static struct storage *x86_assignment(struct expression *expr)
21611f5207b7SJohn Levon {
21621f5207b7SJohn Levon 	struct expression *target = expr->left;
21631f5207b7SJohn Levon 	struct storage *val, *addr;
21641f5207b7SJohn Levon 
21651f5207b7SJohn Levon 	if (!expr->ctype)
21661f5207b7SJohn Levon 		return NULL;
21671f5207b7SJohn Levon 
21681f5207b7SJohn Levon 	val = x86_expression(expr->right);
21691f5207b7SJohn Levon 	addr = x86_address_gen(target);
21701f5207b7SJohn Levon 
21711f5207b7SJohn Levon 	switch (val->type) {
21721f5207b7SJohn Levon 	/* copy, where both operands are memory */
21731f5207b7SJohn Levon 	case STOR_PSEUDO:
21741f5207b7SJohn Levon 	case STOR_ARG:
21751f5207b7SJohn Levon 		emit_copy(addr, val, expr->ctype);
21761f5207b7SJohn Levon 		break;
21771f5207b7SJohn Levon 
21781f5207b7SJohn Levon 	/* copy, one or zero operands are memory */
21791f5207b7SJohn Levon 	case STOR_REG:
21801f5207b7SJohn Levon 	case STOR_SYM:
21811f5207b7SJohn Levon 	case STOR_VALUE:
21821f5207b7SJohn Levon 	case STOR_LABEL:
21831f5207b7SJohn Levon 		emit_move(val, addr, expr->left->ctype, NULL);
21841f5207b7SJohn Levon 		break;
21851f5207b7SJohn Levon 
21861f5207b7SJohn Levon 	case STOR_LABELSYM:
21871f5207b7SJohn Levon 		assert(0);
21881f5207b7SJohn Levon 		break;
21891f5207b7SJohn Levon 	}
21901f5207b7SJohn Levon 	return val;
21911f5207b7SJohn Levon }
21921f5207b7SJohn Levon 
x86_initialization(struct symbol * sym,struct expression * expr)21931f5207b7SJohn Levon static int x86_initialization(struct symbol *sym, struct expression *expr)
21941f5207b7SJohn Levon {
21951f5207b7SJohn Levon 	struct storage *val, *addr;
21961f5207b7SJohn Levon 	int bits;
21971f5207b7SJohn Levon 
21981f5207b7SJohn Levon 	if (!expr->ctype)
21991f5207b7SJohn Levon 		return 0;
22001f5207b7SJohn Levon 
22011f5207b7SJohn Levon 	bits = expr->ctype->bit_size;
22021f5207b7SJohn Levon 	val = x86_expression(expr);
22031f5207b7SJohn Levon 	addr = x86_symbol_expr(sym);
22041f5207b7SJohn Levon 	// FIXME! The "target" expression is for bitfield store information.
22051f5207b7SJohn Levon 	// Leave it NULL, which works fine.
22061f5207b7SJohn Levon 	emit_store(NULL, addr, val, bits);
22071f5207b7SJohn Levon 	return 0;
22081f5207b7SJohn Levon }
22091f5207b7SJohn Levon 
x86_access(struct expression * expr)22101f5207b7SJohn Levon static struct storage *x86_access(struct expression *expr)
22111f5207b7SJohn Levon {
22121f5207b7SJohn Levon 	return x86_address_gen(expr);
22131f5207b7SJohn Levon }
22141f5207b7SJohn Levon 
x86_preop(struct expression * expr)22151f5207b7SJohn Levon static struct storage *x86_preop(struct expression *expr)
22161f5207b7SJohn Levon {
22171f5207b7SJohn Levon 	/*
22181f5207b7SJohn Levon 	 * '*' is an lvalue access, and is fundamentally different
22191f5207b7SJohn Levon 	 * from an arithmetic operation. Maybe it should have an
22201f5207b7SJohn Levon 	 * expression type of its own..
22211f5207b7SJohn Levon 	 */
22221f5207b7SJohn Levon 	if (expr->op == '*')
22231f5207b7SJohn Levon 		return x86_access(expr);
22241f5207b7SJohn Levon 	if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
22251f5207b7SJohn Levon 		return emit_inc_dec(expr, 0);
22261f5207b7SJohn Levon 	return emit_regular_preop(expr);
22271f5207b7SJohn Levon }
22281f5207b7SJohn Levon 
x86_symbol_expr(struct symbol * sym)22291f5207b7SJohn Levon static struct storage *x86_symbol_expr(struct symbol *sym)
22301f5207b7SJohn Levon {
22311f5207b7SJohn Levon 	struct storage *new = stack_alloc(4);
22321f5207b7SJohn Levon 
22331f5207b7SJohn Levon 	if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_EXTERN | MOD_STATIC)) {
22341f5207b7SJohn Levon 		printf("\tmovi.%d\t\tv%d,$%s\n", bits_in_pointer, new->pseudo, show_ident(sym->ident));
22351f5207b7SJohn Levon 		return new;
22361f5207b7SJohn Levon 	}
22371f5207b7SJohn Levon 	if (sym->ctype.modifiers & MOD_ADDRESSABLE) {
2238*c85f09ccSJohn Levon 		printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new->pseudo, 0LL);
22391f5207b7SJohn Levon 		return new;
22401f5207b7SJohn Levon 	}
22411f5207b7SJohn Levon 	printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", bits_in_pointer, new->pseudo, show_ident(sym->ident), sym);
22421f5207b7SJohn Levon 	return new;
22431f5207b7SJohn Levon }
22441f5207b7SJohn Levon 
x86_symbol_init(struct symbol * sym)22451f5207b7SJohn Levon static void x86_symbol_init(struct symbol *sym)
22461f5207b7SJohn Levon {
22471f5207b7SJohn Levon 	struct symbol_private *priv = sym->aux;
22481f5207b7SJohn Levon 	struct expression *expr = sym->initializer;
22491f5207b7SJohn Levon 	struct storage *new;
22501f5207b7SJohn Levon 
22511f5207b7SJohn Levon 	if (expr)
22521f5207b7SJohn Levon 		new = x86_expression(expr);
22531f5207b7SJohn Levon 	else
22541f5207b7SJohn Levon 		new = stack_alloc(sym->bit_size / 8);
22551f5207b7SJohn Levon 
22561f5207b7SJohn Levon 	if (!priv) {
22571f5207b7SJohn Levon 		priv = calloc(1, sizeof(*priv));
22581f5207b7SJohn Levon 		sym->aux = priv;
22591f5207b7SJohn Levon 		/* FIXME: leak! we don't free... */
22601f5207b7SJohn Levon 		/* (well, we don't free symbols either) */
22611f5207b7SJohn Levon 	}
22621f5207b7SJohn Levon 
22631f5207b7SJohn Levon 	priv->addr = new;
22641f5207b7SJohn Levon }
22651f5207b7SJohn Levon 
x86_label_expr(struct expression * expr)22661f5207b7SJohn Levon static struct storage *x86_label_expr(struct expression *expr)
22671f5207b7SJohn Levon {
22681f5207b7SJohn Levon 	struct storage *new = stack_alloc(4);
22691f5207b7SJohn Levon 	printf("\tmovi.%d\t\tv%d,.L%p\n", bits_in_pointer, new->pseudo, expr->label_symbol);
22701f5207b7SJohn Levon 	return new;
22711f5207b7SJohn Levon }
22721f5207b7SJohn Levon 
x86_statement_expr(struct expression * expr)22731f5207b7SJohn Levon static struct storage *x86_statement_expr(struct expression *expr)
22741f5207b7SJohn Levon {
22751f5207b7SJohn Levon 	return x86_statement(expr->statement);
22761f5207b7SJohn Levon }
22771f5207b7SJohn Levon 
x86_position_expr(struct expression * expr,struct symbol * base)22781f5207b7SJohn Levon static int x86_position_expr(struct expression *expr, struct symbol *base)
22791f5207b7SJohn Levon {
22801f5207b7SJohn Levon 	struct storage *new = x86_expression(expr->init_expr);
22811f5207b7SJohn Levon 	struct symbol *ctype = expr->init_expr->ctype;
22821f5207b7SJohn Levon 
22831f5207b7SJohn Levon 	printf("\tinsert v%d at [%d:%d] of %s\n", new->pseudo,
22841f5207b7SJohn Levon 		expr->init_offset, ctype->bit_offset,
22851f5207b7SJohn Levon 		show_ident(base->ident));
22861f5207b7SJohn Levon 	return 0;
22871f5207b7SJohn Levon }
22881f5207b7SJohn Levon 
x86_initializer_expr(struct expression * expr,struct symbol * ctype)22891f5207b7SJohn Levon static void x86_initializer_expr(struct expression *expr, struct symbol *ctype)
22901f5207b7SJohn Levon {
22911f5207b7SJohn Levon 	struct expression *entry;
22921f5207b7SJohn Levon 
22931f5207b7SJohn Levon 	FOR_EACH_PTR(expr->expr_list, entry) {
22941f5207b7SJohn Levon 		// Nested initializers have their positions already
22951f5207b7SJohn Levon 		// recursively calculated - just output them too
22961f5207b7SJohn Levon 		if (entry->type == EXPR_INITIALIZER) {
22971f5207b7SJohn Levon 			x86_initializer_expr(entry, ctype);
22981f5207b7SJohn Levon 			continue;
22991f5207b7SJohn Levon 		}
23001f5207b7SJohn Levon 
23011f5207b7SJohn Levon 		// Ignore initializer indexes and identifiers - the
23021f5207b7SJohn Levon 		// evaluator has taken them into account
23031f5207b7SJohn Levon 		if (entry->type == EXPR_IDENTIFIER || entry->type == EXPR_INDEX)
23041f5207b7SJohn Levon 			continue;
23051f5207b7SJohn Levon 		if (entry->type == EXPR_POS) {
23061f5207b7SJohn Levon 			x86_position_expr(entry, ctype);
23071f5207b7SJohn Levon 			continue;
23081f5207b7SJohn Levon 		}
23091f5207b7SJohn Levon 		x86_initialization(ctype, entry);
23101f5207b7SJohn Levon 	} END_FOR_EACH_PTR(entry);
23111f5207b7SJohn Levon }
23121f5207b7SJohn Levon 
23131f5207b7SJohn Levon /*
23141f5207b7SJohn Levon  * Print out an expression. Return the pseudo that contains the
23151f5207b7SJohn Levon  * variable.
23161f5207b7SJohn Levon  */
x86_expression(struct expression * expr)23171f5207b7SJohn Levon static struct storage *x86_expression(struct expression *expr)
23181f5207b7SJohn Levon {
23191f5207b7SJohn Levon 	if (!expr)
23201f5207b7SJohn Levon 		return NULL;
23211f5207b7SJohn Levon 
23221f5207b7SJohn Levon 	if (!expr->ctype) {
23231f5207b7SJohn Levon 		struct position *pos = &expr->pos;
23241f5207b7SJohn Levon 		printf("\tno type at %s:%d:%d\n",
23251f5207b7SJohn Levon 			stream_name(pos->stream),
23261f5207b7SJohn Levon 			pos->line, pos->pos);
23271f5207b7SJohn Levon 		return NULL;
23281f5207b7SJohn Levon 	}
23291f5207b7SJohn Levon 
23301f5207b7SJohn Levon 	switch (expr->type) {
23311f5207b7SJohn Levon 	default:
23321f5207b7SJohn Levon 		return NULL;
23331f5207b7SJohn Levon 	case EXPR_CALL:
23341f5207b7SJohn Levon 		return x86_call_expression(expr);
23351f5207b7SJohn Levon 
23361f5207b7SJohn Levon 	case EXPR_ASSIGNMENT:
23371f5207b7SJohn Levon 		return x86_assignment(expr);
23381f5207b7SJohn Levon 
23391f5207b7SJohn Levon 	case EXPR_COMPARE:
23401f5207b7SJohn Levon 		return emit_compare(expr);
23411f5207b7SJohn Levon 	case EXPR_BINOP:
23421f5207b7SJohn Levon 	case EXPR_COMMA:
23431f5207b7SJohn Levon 	case EXPR_LOGICAL:
23441f5207b7SJohn Levon 		return emit_binop(expr);
23451f5207b7SJohn Levon 	case EXPR_PREOP:
23461f5207b7SJohn Levon 		return x86_preop(expr);
23471f5207b7SJohn Levon 	case EXPR_POSTOP:
23481f5207b7SJohn Levon 		return emit_postop(expr);
23491f5207b7SJohn Levon 	case EXPR_SYMBOL:
23501f5207b7SJohn Levon 		return emit_symbol_expr_init(expr->symbol);
23511f5207b7SJohn Levon 	case EXPR_DEREF:
23521f5207b7SJohn Levon 	case EXPR_SIZEOF:
23531f5207b7SJohn Levon 	case EXPR_ALIGNOF:
23541f5207b7SJohn Levon 		warning(expr->pos, "invalid expression after evaluation");
23551f5207b7SJohn Levon 		return NULL;
23561f5207b7SJohn Levon 	case EXPR_CAST:
23571f5207b7SJohn Levon 	case EXPR_FORCE_CAST:
23581f5207b7SJohn Levon 	case EXPR_IMPLIED_CAST:
23591f5207b7SJohn Levon 		return emit_cast_expr(expr);
23601f5207b7SJohn Levon 	case EXPR_VALUE:
23611f5207b7SJohn Levon 		return emit_value(expr);
23621f5207b7SJohn Levon 	case EXPR_STRING:
23631f5207b7SJohn Levon 		return emit_string_expr(expr);
23641f5207b7SJohn Levon 	case EXPR_INITIALIZER:
23651f5207b7SJohn Levon 		x86_initializer_expr(expr, expr->ctype);
23661f5207b7SJohn Levon 		return NULL;
23671f5207b7SJohn Levon 	case EXPR_SELECT:
23681f5207b7SJohn Levon 		return emit_select_expr(expr);
23691f5207b7SJohn Levon 	case EXPR_CONDITIONAL:
23701f5207b7SJohn Levon 		return emit_conditional_expr(expr);
23711f5207b7SJohn Levon 	case EXPR_STATEMENT:
23721f5207b7SJohn Levon 		return x86_statement_expr(expr);
23731f5207b7SJohn Levon 	case EXPR_LABEL:
23741f5207b7SJohn Levon 		return x86_label_expr(expr);
23751f5207b7SJohn Levon 
23761f5207b7SJohn Levon 	// None of these should exist as direct expressions: they are only
23771f5207b7SJohn Levon 	// valid as sub-expressions of initializers.
23781f5207b7SJohn Levon 	case EXPR_POS:
23791f5207b7SJohn Levon 		warning(expr->pos, "unable to show plain initializer position expression");
23801f5207b7SJohn Levon 		return NULL;
23811f5207b7SJohn Levon 	case EXPR_IDENTIFIER:
23821f5207b7SJohn Levon 		warning(expr->pos, "unable to show identifier expression");
23831f5207b7SJohn Levon 		return NULL;
23841f5207b7SJohn Levon 	case EXPR_INDEX:
23851f5207b7SJohn Levon 		warning(expr->pos, "unable to show index expression");
23861f5207b7SJohn Levon 		return NULL;
23871f5207b7SJohn Levon 	case EXPR_TYPE:
23881f5207b7SJohn Levon 		warning(expr->pos, "unable to show type expression");
23891f5207b7SJohn Levon 		return NULL;
23901f5207b7SJohn Levon 	case EXPR_FVALUE:
23911f5207b7SJohn Levon 		warning(expr->pos, "floating point support is not implemented");
23921f5207b7SJohn Levon 		return NULL;
23931f5207b7SJohn Levon 	}
23941f5207b7SJohn Levon 	return NULL;
23951f5207b7SJohn Levon }
2396