1*1f5207b7SJohn Levon /*
2*1f5207b7SJohn Levon  * sparse/compile-i386.c
3*1f5207b7SJohn Levon  *
4*1f5207b7SJohn Levon  * Copyright (C) 2003 Transmeta Corp.
5*1f5207b7SJohn Levon  *               2003 Linus Torvalds
6*1f5207b7SJohn Levon  * Copyright 2003 Jeff Garzik
7*1f5207b7SJohn Levon  *
8*1f5207b7SJohn Levon  * Permission is hereby granted, free of charge, to any person obtaining a copy
9*1f5207b7SJohn Levon  * of this software and associated documentation files (the "Software"), to deal
10*1f5207b7SJohn Levon  * in the Software without restriction, including without limitation the rights
11*1f5207b7SJohn Levon  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12*1f5207b7SJohn Levon  * copies of the Software, and to permit persons to whom the Software is
13*1f5207b7SJohn Levon  * furnished to do so, subject to the following conditions:
14*1f5207b7SJohn Levon  *
15*1f5207b7SJohn Levon  * The above copyright notice and this permission notice shall be included in
16*1f5207b7SJohn Levon  * all copies or substantial portions of the Software.
17*1f5207b7SJohn Levon  *
18*1f5207b7SJohn Levon  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19*1f5207b7SJohn Levon  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20*1f5207b7SJohn Levon  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21*1f5207b7SJohn Levon  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22*1f5207b7SJohn Levon  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23*1f5207b7SJohn Levon  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24*1f5207b7SJohn Levon  * THE SOFTWARE.
25*1f5207b7SJohn Levon  *
26*1f5207b7SJohn Levon  * x86 backend
27*1f5207b7SJohn Levon  *
28*1f5207b7SJohn Levon  * TODO list:
29*1f5207b7SJohn Levon  * in general, any non-32bit SYM_BASETYPE is unlikely to work.
30*1f5207b7SJohn Levon  * complex initializers
31*1f5207b7SJohn Levon  * bitfields
32*1f5207b7SJohn Levon  * global struct/union variables
33*1f5207b7SJohn Levon  * addressing structures, and members of structures (as opposed to
34*1f5207b7SJohn Levon  *     scalars) on the stack.  Requires smarter stack frame allocation.
35*1f5207b7SJohn Levon  * labels / goto
36*1f5207b7SJohn Levon  * any function argument that isn't 32 bits (or promoted to such)
37*1f5207b7SJohn Levon  * inline asm
38*1f5207b7SJohn Levon  * floating point
39*1f5207b7SJohn Levon  *
40*1f5207b7SJohn Levon  */
41*1f5207b7SJohn Levon #include <stdarg.h>
42*1f5207b7SJohn Levon #include <stdlib.h>
43*1f5207b7SJohn Levon #include <stdio.h>
44*1f5207b7SJohn Levon #include <string.h>
45*1f5207b7SJohn Levon #include <ctype.h>
46*1f5207b7SJohn Levon #include <unistd.h>
47*1f5207b7SJohn Levon #include <fcntl.h>
48*1f5207b7SJohn Levon #include <assert.h>
49*1f5207b7SJohn Levon 
50*1f5207b7SJohn Levon #include "lib.h"
51*1f5207b7SJohn Levon #include "allocate.h"
52*1f5207b7SJohn Levon #include "token.h"
53*1f5207b7SJohn Levon #include "parse.h"
54*1f5207b7SJohn Levon #include "symbol.h"
55*1f5207b7SJohn Levon #include "scope.h"
56*1f5207b7SJohn Levon #include "expression.h"
57*1f5207b7SJohn Levon #include "target.h"
58*1f5207b7SJohn Levon #include "compile.h"
59*1f5207b7SJohn Levon #include "bitmap.h"
60*1f5207b7SJohn Levon #include "version.h"
61*1f5207b7SJohn Levon 
62*1f5207b7SJohn Levon struct textbuf {
63*1f5207b7SJohn Levon 	unsigned int	len;	/* does NOT include terminating null */
64*1f5207b7SJohn Levon 	char		*text;
65*1f5207b7SJohn Levon 	struct textbuf	*next;
66*1f5207b7SJohn Levon 	struct textbuf	*prev;
67*1f5207b7SJohn Levon };
68*1f5207b7SJohn Levon 
69*1f5207b7SJohn Levon struct loop_stack {
70*1f5207b7SJohn Levon 	int		continue_lbl;
71*1f5207b7SJohn Levon 	int		loop_bottom_lbl;
72*1f5207b7SJohn Levon 	struct loop_stack *next;
73*1f5207b7SJohn Levon };
74*1f5207b7SJohn Levon 
75*1f5207b7SJohn Levon struct atom;
76*1f5207b7SJohn Levon struct storage;
77*1f5207b7SJohn Levon DECLARE_PTR_LIST(str_list, struct atom);
78*1f5207b7SJohn Levon DECLARE_PTR_LIST(atom_list, struct atom);
79*1f5207b7SJohn Levon DECLARE_PTR_LIST(storage_list, struct storage);
80*1f5207b7SJohn Levon 
81*1f5207b7SJohn Levon struct function {
82*1f5207b7SJohn Levon 	int stack_size;
83*1f5207b7SJohn Levon 	int pseudo_nr;
84*1f5207b7SJohn Levon 	struct storage_list *pseudo_list;
85*1f5207b7SJohn Levon 	struct atom_list *atom_list;
86*1f5207b7SJohn Levon 	struct str_list *str_list;
87*1f5207b7SJohn Levon 	struct loop_stack *loop_stack;
88*1f5207b7SJohn Levon 	struct symbol **argv;
89*1f5207b7SJohn Levon 	unsigned int argc;
90*1f5207b7SJohn Levon 	int ret_target;
91*1f5207b7SJohn Levon };
92*1f5207b7SJohn Levon 
93*1f5207b7SJohn Levon enum storage_type {
94*1f5207b7SJohn Levon 	STOR_PSEUDO,	/* variable stored on the stack */
95*1f5207b7SJohn Levon 	STOR_ARG,	/* function argument */
96*1f5207b7SJohn Levon 	STOR_SYM,	/* a symbol we can directly ref in the asm */
97*1f5207b7SJohn Levon 	STOR_REG,	/* scratch register */
98*1f5207b7SJohn Levon 	STOR_VALUE,	/* integer constant */
99*1f5207b7SJohn Levon 	STOR_LABEL,	/* label / jump target */
100*1f5207b7SJohn Levon 	STOR_LABELSYM,	/* label generated from symbol's pointer value */
101*1f5207b7SJohn Levon };
102*1f5207b7SJohn Levon 
103*1f5207b7SJohn Levon struct reg_info {
104*1f5207b7SJohn Levon 	const char	*name;
105*1f5207b7SJohn Levon 	struct storage	*contains;
106*1f5207b7SJohn Levon 	const unsigned char aliases[12];
107*1f5207b7SJohn Levon #define own_regno aliases[0]
108*1f5207b7SJohn Levon };
109*1f5207b7SJohn Levon 
110*1f5207b7SJohn Levon struct storage {
111*1f5207b7SJohn Levon 	enum storage_type type;
112*1f5207b7SJohn Levon 	unsigned long flags;
113*1f5207b7SJohn Levon 
114*1f5207b7SJohn Levon 	/* STOR_REG */
115*1f5207b7SJohn Levon 	struct reg_info *reg;
116*1f5207b7SJohn Levon 	struct symbol *ctype;
117*1f5207b7SJohn Levon 
118*1f5207b7SJohn Levon 	union {
119*1f5207b7SJohn Levon 		/* STOR_PSEUDO */
120*1f5207b7SJohn Levon 		struct {
121*1f5207b7SJohn Levon 			int pseudo;
122*1f5207b7SJohn Levon 			int offset;
123*1f5207b7SJohn Levon 			int size;
124*1f5207b7SJohn Levon 		};
125*1f5207b7SJohn Levon 		/* STOR_ARG */
126*1f5207b7SJohn Levon 		struct {
127*1f5207b7SJohn Levon 			int idx;
128*1f5207b7SJohn Levon 		};
129*1f5207b7SJohn Levon 		/* STOR_SYM */
130*1f5207b7SJohn Levon 		struct {
131*1f5207b7SJohn Levon 			struct symbol *sym;
132*1f5207b7SJohn Levon 		};
133*1f5207b7SJohn Levon 		/* STOR_VALUE */
134*1f5207b7SJohn Levon 		struct {
135*1f5207b7SJohn Levon 			long long value;
136*1f5207b7SJohn Levon 		};
137*1f5207b7SJohn Levon 		/* STOR_LABEL */
138*1f5207b7SJohn Levon 		struct {
139*1f5207b7SJohn Levon 			int label;
140*1f5207b7SJohn Levon 		};
141*1f5207b7SJohn Levon 		/* STOR_LABELSYM */
142*1f5207b7SJohn Levon 		struct {
143*1f5207b7SJohn Levon 			struct symbol *labelsym;
144*1f5207b7SJohn Levon 		};
145*1f5207b7SJohn Levon 	};
146*1f5207b7SJohn Levon };
147*1f5207b7SJohn Levon 
148*1f5207b7SJohn Levon enum {
149*1f5207b7SJohn Levon 	STOR_LABEL_VAL	= (1 << 0),
150*1f5207b7SJohn Levon 	STOR_WANTS_FREE	= (1 << 1),
151*1f5207b7SJohn Levon };
152*1f5207b7SJohn Levon 
153*1f5207b7SJohn Levon struct symbol_private {
154*1f5207b7SJohn Levon 	struct storage *addr;
155*1f5207b7SJohn Levon };
156*1f5207b7SJohn Levon 
157*1f5207b7SJohn Levon enum atom_type {
158*1f5207b7SJohn Levon 	ATOM_TEXT,
159*1f5207b7SJohn Levon 	ATOM_INSN,
160*1f5207b7SJohn Levon 	ATOM_CSTR,
161*1f5207b7SJohn Levon };
162*1f5207b7SJohn Levon 
163*1f5207b7SJohn Levon struct atom {
164*1f5207b7SJohn Levon 	enum atom_type type;
165*1f5207b7SJohn Levon 	union {
166*1f5207b7SJohn Levon 		/* stuff for text */
167*1f5207b7SJohn Levon 		struct {
168*1f5207b7SJohn Levon 			char *text;
169*1f5207b7SJohn Levon 			unsigned int text_len;  /* w/o terminating null */
170*1f5207b7SJohn Levon 		};
171*1f5207b7SJohn Levon 
172*1f5207b7SJohn Levon 		/* stuff for insns */
173*1f5207b7SJohn Levon 		struct {
174*1f5207b7SJohn Levon 			char insn[32];
175*1f5207b7SJohn Levon 			char comment[40];
176*1f5207b7SJohn Levon 			struct storage *op1;
177*1f5207b7SJohn Levon 			struct storage *op2;
178*1f5207b7SJohn Levon 		};
179*1f5207b7SJohn Levon 
180*1f5207b7SJohn Levon 		/* stuff for C strings */
181*1f5207b7SJohn Levon 		struct {
182*1f5207b7SJohn Levon 			struct string *string;
183*1f5207b7SJohn Levon 			int label;
184*1f5207b7SJohn Levon 		};
185*1f5207b7SJohn Levon 	};
186*1f5207b7SJohn Levon };
187*1f5207b7SJohn Levon 
188*1f5207b7SJohn Levon 
189*1f5207b7SJohn Levon static struct function *current_func = NULL;
190*1f5207b7SJohn Levon static struct textbuf *unit_post_text = NULL;
191*1f5207b7SJohn Levon static const char *current_section;
192*1f5207b7SJohn Levon 
193*1f5207b7SJohn Levon static void emit_comment(const char * fmt, ...) FORMAT_ATTR(1);
194*1f5207b7SJohn Levon static void emit_move(struct storage *src, struct storage *dest,
195*1f5207b7SJohn Levon 		      struct symbol *ctype, const char *comment);
196*1f5207b7SJohn Levon static int type_is_signed(struct symbol *sym);
197*1f5207b7SJohn Levon static struct storage *x86_address_gen(struct expression *expr);
198*1f5207b7SJohn Levon static struct storage *x86_symbol_expr(struct symbol *sym);
199*1f5207b7SJohn Levon static void x86_symbol(struct symbol *sym);
200*1f5207b7SJohn Levon static struct storage *x86_statement(struct statement *stmt);
201*1f5207b7SJohn Levon static struct storage *x86_expression(struct expression *expr);
202*1f5207b7SJohn Levon 
203*1f5207b7SJohn Levon enum registers {
204*1f5207b7SJohn Levon 	NOREG,
205*1f5207b7SJohn Levon 	 AL,  DL,  CL,  BL,  AH,  DH,  CH,  BH,	// 8-bit
206*1f5207b7SJohn Levon 	 AX,  DX,  CX,  BX,  SI,  DI,  BP,  SP,	// 16-bit
207*1f5207b7SJohn Levon 	EAX, EDX, ECX, EBX, ESI, EDI, EBP, ESP,	// 32-bit
208*1f5207b7SJohn Levon 	EAX_EDX, ECX_EBX, ESI_EDI,		// 64-bit
209*1f5207b7SJohn Levon };
210*1f5207b7SJohn Levon 
211*1f5207b7SJohn Levon /* This works on regno's, reg_info's and hardreg_storage's */
212*1f5207b7SJohn Levon #define byte_reg(reg) ((reg) - 16)
213*1f5207b7SJohn Levon #define highbyte_reg(reg) ((reg)-12)
214*1f5207b7SJohn Levon #define word_reg(reg) ((reg)-8)
215*1f5207b7SJohn Levon 
216*1f5207b7SJohn Levon #define REGINFO(nr, str, conflicts...)	[nr] = { .name = str, .aliases = { nr , conflicts } }
217*1f5207b7SJohn Levon 
218*1f5207b7SJohn Levon static struct reg_info reg_info_table[] = {
219*1f5207b7SJohn Levon 	REGINFO( AL,  "%al", AX, EAX, EAX_EDX),
220*1f5207b7SJohn Levon 	REGINFO( DL,  "%dl", DX, EDX, EAX_EDX),
221*1f5207b7SJohn Levon 	REGINFO( CL,  "%cl", CX, ECX, ECX_EBX),
222*1f5207b7SJohn Levon 	REGINFO( BL,  "%bl", BX, EBX, ECX_EBX),
223*1f5207b7SJohn Levon 	REGINFO( AH,  "%ah", AX, EAX, EAX_EDX),
224*1f5207b7SJohn Levon 	REGINFO( DH,  "%dh", DX, EDX, EAX_EDX),
225*1f5207b7SJohn Levon 	REGINFO( CH,  "%ch", CX, ECX, ECX_EBX),
226*1f5207b7SJohn Levon 	REGINFO( BH,  "%bh", BX, EBX, ECX_EBX),
227*1f5207b7SJohn Levon 	REGINFO( AX,  "%ax", AL, AH, EAX, EAX_EDX),
228*1f5207b7SJohn Levon 	REGINFO( DX,  "%dx", DL, DH, EDX, EAX_EDX),
229*1f5207b7SJohn Levon 	REGINFO( CX,  "%cx", CL, CH, ECX, ECX_EBX),
230*1f5207b7SJohn Levon 	REGINFO( BX,  "%bx", BL, BH, EBX, ECX_EBX),
231*1f5207b7SJohn Levon 	REGINFO( SI,  "%si", ESI, ESI_EDI),
232*1f5207b7SJohn Levon 	REGINFO( DI,  "%di", EDI, ESI_EDI),
233*1f5207b7SJohn Levon 	REGINFO( BP,  "%bp", EBP),
234*1f5207b7SJohn Levon 	REGINFO( SP,  "%sp", ESP),
235*1f5207b7SJohn Levon 	REGINFO(EAX, "%eax", AL, AH, AX, EAX_EDX),
236*1f5207b7SJohn Levon 	REGINFO(EDX, "%edx", DL, DH, DX, EAX_EDX),
237*1f5207b7SJohn Levon 	REGINFO(ECX, "%ecx", CL, CH, CX, ECX_EBX),
238*1f5207b7SJohn Levon 	REGINFO(EBX, "%ebx", BL, BH, BX, ECX_EBX),
239*1f5207b7SJohn Levon 	REGINFO(ESI, "%esi", SI, ESI_EDI),
240*1f5207b7SJohn Levon 	REGINFO(EDI, "%edi", DI, ESI_EDI),
241*1f5207b7SJohn Levon 	REGINFO(EBP, "%ebp", BP),
242*1f5207b7SJohn Levon 	REGINFO(ESP, "%esp", SP),
243*1f5207b7SJohn Levon 	REGINFO(EAX_EDX, "%eax:%edx", AL, AH, AX, EAX, DL, DH, DX, EDX),
244*1f5207b7SJohn Levon 	REGINFO(ECX_EBX, "%ecx:%ebx", CL, CH, CX, ECX, BL, BH, BX, EBX),
245*1f5207b7SJohn Levon 	REGINFO(ESI_EDI, "%esi:%edi", SI, ESI, DI, EDI),
246*1f5207b7SJohn Levon };
247*1f5207b7SJohn Levon 
248*1f5207b7SJohn Levon #define REGSTORAGE(nr) [nr] = { .type = STOR_REG, .reg = reg_info_table + (nr) }
249*1f5207b7SJohn Levon 
250*1f5207b7SJohn Levon static struct storage hardreg_storage_table[] = {
251*1f5207b7SJohn Levon 	REGSTORAGE(AL), REGSTORAGE(DL), REGSTORAGE(CL), REGSTORAGE(BL),
252*1f5207b7SJohn Levon 	REGSTORAGE(AH), REGSTORAGE(DH), REGSTORAGE(CH), REGSTORAGE(BH),
253*1f5207b7SJohn Levon 	REGSTORAGE(AX), REGSTORAGE(DX), REGSTORAGE(CX), REGSTORAGE(BX),
254*1f5207b7SJohn Levon 	REGSTORAGE(SI), REGSTORAGE(DI), REGSTORAGE(BP), REGSTORAGE(SP),
255*1f5207b7SJohn Levon 	REGSTORAGE(EAX), REGSTORAGE(EDX), REGSTORAGE(ECX), REGSTORAGE(EBX),
256*1f5207b7SJohn Levon 	REGSTORAGE(ESI), REGSTORAGE(EDI), REGSTORAGE(EBP), REGSTORAGE(ESP),
257*1f5207b7SJohn Levon 	REGSTORAGE(EAX_EDX), REGSTORAGE(ECX_EBX), REGSTORAGE(ESI_EDI),
258*1f5207b7SJohn Levon };
259*1f5207b7SJohn Levon 
260*1f5207b7SJohn Levon #define REG_EAX (&hardreg_storage_table[EAX])
261*1f5207b7SJohn Levon #define REG_ECX (&hardreg_storage_table[ECX])
262*1f5207b7SJohn Levon #define REG_EDX (&hardreg_storage_table[EDX])
263*1f5207b7SJohn Levon #define REG_ESP (&hardreg_storage_table[ESP])
264*1f5207b7SJohn Levon #define REG_DL	(&hardreg_storage_table[DL])
265*1f5207b7SJohn Levon #define REG_DX	(&hardreg_storage_table[DX])
266*1f5207b7SJohn Levon #define REG_AL	(&hardreg_storage_table[AL])
267*1f5207b7SJohn Levon #define REG_AX	(&hardreg_storage_table[AX])
268*1f5207b7SJohn Levon 
269*1f5207b7SJohn Levon static DECLARE_BITMAP(regs_in_use, 256);
270*1f5207b7SJohn Levon 
271*1f5207b7SJohn Levon static inline struct storage * reginfo_reg(struct reg_info *info)
272*1f5207b7SJohn Levon {
273*1f5207b7SJohn Levon 	return hardreg_storage_table + info->own_regno;
274*1f5207b7SJohn Levon }
275*1f5207b7SJohn Levon 
276*1f5207b7SJohn Levon static struct storage * get_hardreg(struct storage *reg, int clear)
277*1f5207b7SJohn Levon {
278*1f5207b7SJohn Levon 	struct reg_info *info = reg->reg;
279*1f5207b7SJohn Levon 	const unsigned char *aliases;
280*1f5207b7SJohn Levon 	int regno;
281*1f5207b7SJohn Levon 
282*1f5207b7SJohn Levon 	aliases = info->aliases;
283*1f5207b7SJohn Levon 	while ((regno = *aliases++) != NOREG) {
284*1f5207b7SJohn Levon 		if (test_bit(regno, regs_in_use))
285*1f5207b7SJohn Levon 			goto busy;
286*1f5207b7SJohn Levon 		if (clear)
287*1f5207b7SJohn Levon 			reg_info_table[regno].contains = NULL;
288*1f5207b7SJohn Levon 	}
289*1f5207b7SJohn Levon 	set_bit(info->own_regno, regs_in_use);
290*1f5207b7SJohn Levon 	return reg;
291*1f5207b7SJohn Levon busy:
292*1f5207b7SJohn Levon 	fprintf(stderr, "register %s is busy\n", info->name);
293*1f5207b7SJohn Levon 	if (regno + reg_info_table != info)
294*1f5207b7SJohn Levon 		fprintf(stderr, "  conflicts with %s\n", reg_info_table[regno].name);
295*1f5207b7SJohn Levon 	exit(1);
296*1f5207b7SJohn Levon }
297*1f5207b7SJohn Levon 
298*1f5207b7SJohn Levon static void put_reg(struct storage *reg)
299*1f5207b7SJohn Levon {
300*1f5207b7SJohn Levon 	struct reg_info *info = reg->reg;
301*1f5207b7SJohn Levon 	int regno = info->own_regno;
302*1f5207b7SJohn Levon 
303*1f5207b7SJohn Levon 	if (test_and_clear_bit(regno, regs_in_use))
304*1f5207b7SJohn Levon 		return;
305*1f5207b7SJohn Levon 	fprintf(stderr, "freeing already free'd register %s\n", reg_info_table[regno].name);
306*1f5207b7SJohn Levon }
307*1f5207b7SJohn Levon 
308*1f5207b7SJohn Levon struct regclass {
309*1f5207b7SJohn Levon 	const char *name;
310*1f5207b7SJohn Levon 	const unsigned char regs[30];
311*1f5207b7SJohn Levon };
312*1f5207b7SJohn Levon 
313*1f5207b7SJohn Levon static struct regclass regclass_8 = { "8-bit", { AL, DL, CL, BL, AH, DH, CH, BH }};
314*1f5207b7SJohn Levon static struct regclass regclass_16 = { "16-bit", { AX, DX, CX, BX, SI, DI, BP }};
315*1f5207b7SJohn Levon static struct regclass regclass_32 = { "32-bit", { EAX, EDX, ECX, EBX, ESI, EDI, EBP }};
316*1f5207b7SJohn Levon static struct regclass regclass_64 = { "64-bit", { EAX_EDX, ECX_EBX, ESI_EDI }};
317*1f5207b7SJohn Levon 
318*1f5207b7SJohn Levon static struct regclass regclass_32_8 = { "32-bit bytes", { EAX, EDX, ECX, EBX }};
319*1f5207b7SJohn Levon 
320*1f5207b7SJohn Levon static struct regclass *get_regclass_bits(int bits)
321*1f5207b7SJohn Levon {
322*1f5207b7SJohn Levon 	switch (bits) {
323*1f5207b7SJohn Levon 	case 8: return &regclass_8;
324*1f5207b7SJohn Levon 	case 16: return &regclass_16;
325*1f5207b7SJohn Levon 	case 64: return &regclass_64;
326*1f5207b7SJohn Levon 	default: return &regclass_32;
327*1f5207b7SJohn Levon 	}
328*1f5207b7SJohn Levon }
329*1f5207b7SJohn Levon 
330*1f5207b7SJohn Levon static struct regclass *get_regclass(struct expression *expr)
331*1f5207b7SJohn Levon {
332*1f5207b7SJohn Levon 	return get_regclass_bits(expr->ctype->bit_size);
333*1f5207b7SJohn Levon }
334*1f5207b7SJohn Levon 
335*1f5207b7SJohn Levon static int register_busy(int regno)
336*1f5207b7SJohn Levon {
337*1f5207b7SJohn Levon 	if (!test_bit(regno, regs_in_use)) {
338*1f5207b7SJohn Levon 		struct reg_info *info = reg_info_table + regno;
339*1f5207b7SJohn Levon 		const unsigned char *regs = info->aliases+1;
340*1f5207b7SJohn Levon 
341*1f5207b7SJohn Levon 		while ((regno = *regs) != NOREG) {
342*1f5207b7SJohn Levon 			regs++;
343*1f5207b7SJohn Levon 			if (test_bit(regno, regs_in_use))
344*1f5207b7SJohn Levon 				goto busy;
345*1f5207b7SJohn Levon 		}
346*1f5207b7SJohn Levon 		return 0;
347*1f5207b7SJohn Levon 	}
348*1f5207b7SJohn Levon busy:
349*1f5207b7SJohn Levon 	return 1;
350*1f5207b7SJohn Levon }
351*1f5207b7SJohn Levon 
352*1f5207b7SJohn Levon static struct storage *get_reg(struct regclass *class)
353*1f5207b7SJohn Levon {
354*1f5207b7SJohn Levon 	const unsigned char *regs = class->regs;
355*1f5207b7SJohn Levon 	int regno;
356*1f5207b7SJohn Levon 
357*1f5207b7SJohn Levon 	while ((regno = *regs) != NOREG) {
358*1f5207b7SJohn Levon 		regs++;
359*1f5207b7SJohn Levon 		if (register_busy(regno))
360*1f5207b7SJohn Levon 			continue;
361*1f5207b7SJohn Levon 		return get_hardreg(hardreg_storage_table + regno, 1);
362*1f5207b7SJohn Levon 	}
363*1f5207b7SJohn Levon 	fprintf(stderr, "Ran out of %s registers\n", class->name);
364*1f5207b7SJohn Levon 	exit(1);
365*1f5207b7SJohn Levon }
366*1f5207b7SJohn Levon 
367*1f5207b7SJohn Levon static struct storage *get_reg_value(struct storage *value, struct regclass *class)
368*1f5207b7SJohn Levon {
369*1f5207b7SJohn Levon 	struct reg_info *info;
370*1f5207b7SJohn Levon 	struct storage *reg;
371*1f5207b7SJohn Levon 
372*1f5207b7SJohn Levon 	/* Do we already have it somewhere */
373*1f5207b7SJohn Levon 	info = value->reg;
374*1f5207b7SJohn Levon 	if (info && info->contains == value) {
375*1f5207b7SJohn Levon 		emit_comment("already have register %s", info->name);
376*1f5207b7SJohn Levon 		return get_hardreg(hardreg_storage_table + info->own_regno, 0);
377*1f5207b7SJohn Levon 	}
378*1f5207b7SJohn Levon 
379*1f5207b7SJohn Levon 	reg = get_reg(class);
380*1f5207b7SJohn Levon 	emit_move(value, reg, value->ctype, "reload register");
381*1f5207b7SJohn Levon 	info = reg->reg;
382*1f5207b7SJohn Levon 	info->contains = value;
383*1f5207b7SJohn Levon 	value->reg = info;
384*1f5207b7SJohn Levon 	return reg;
385*1f5207b7SJohn Levon }
386*1f5207b7SJohn Levon 
387*1f5207b7SJohn Levon static struct storage *temp_from_bits(unsigned int bit_size)
388*1f5207b7SJohn Levon {
389*1f5207b7SJohn Levon 	return get_reg(get_regclass_bits(bit_size));
390*1f5207b7SJohn Levon }
391*1f5207b7SJohn Levon 
392*1f5207b7SJohn Levon static inline unsigned int pseudo_offset(struct storage *s)
393*1f5207b7SJohn Levon {
394*1f5207b7SJohn Levon 	if (s->type != STOR_PSEUDO)
395*1f5207b7SJohn Levon 		return 123456;	/* intentionally bogus value */
396*1f5207b7SJohn Levon 
397*1f5207b7SJohn Levon 	return s->offset;
398*1f5207b7SJohn Levon }
399*1f5207b7SJohn Levon 
400*1f5207b7SJohn Levon static inline unsigned int arg_offset(struct storage *s)
401*1f5207b7SJohn Levon {
402*1f5207b7SJohn Levon 	if (s->type != STOR_ARG)
403*1f5207b7SJohn Levon 		return 123456;	/* intentionally bogus value */
404*1f5207b7SJohn Levon 
405*1f5207b7SJohn Levon 	/* FIXME: this is wrong wrong wrong */
406*1f5207b7SJohn Levon 	return current_func->stack_size + ((1 + s->idx) * 4);
407*1f5207b7SJohn Levon }
408*1f5207b7SJohn Levon 
409*1f5207b7SJohn Levon static const char *pretty_offset(int ofs)
410*1f5207b7SJohn Levon {
411*1f5207b7SJohn Levon 	static char esp_buf[64];
412*1f5207b7SJohn Levon 
413*1f5207b7SJohn Levon 	if (ofs)
414*1f5207b7SJohn Levon 		sprintf(esp_buf, "%d(%%esp)", ofs);
415*1f5207b7SJohn Levon 	else
416*1f5207b7SJohn Levon 		strcpy(esp_buf, "(%esp)");
417*1f5207b7SJohn Levon 
418*1f5207b7SJohn Levon 	return esp_buf;
419*1f5207b7SJohn Levon }
420*1f5207b7SJohn Levon 
421*1f5207b7SJohn Levon static void stor_sym_init(struct symbol *sym)
422*1f5207b7SJohn Levon {
423*1f5207b7SJohn Levon 	struct storage *stor;
424*1f5207b7SJohn Levon 	struct symbol_private *priv;
425*1f5207b7SJohn Levon 
426*1f5207b7SJohn Levon 	priv = calloc(1, sizeof(*priv) + sizeof(*stor));
427*1f5207b7SJohn Levon 	if (!priv)
428*1f5207b7SJohn Levon 		die("OOM in stor_sym_init");
429*1f5207b7SJohn Levon 
430*1f5207b7SJohn Levon 	stor = (struct storage *) (priv + 1);
431*1f5207b7SJohn Levon 
432*1f5207b7SJohn Levon 	priv->addr = stor;
433*1f5207b7SJohn Levon 	stor->type = STOR_SYM;
434*1f5207b7SJohn Levon 	stor->sym = sym;
435*1f5207b7SJohn Levon }
436*1f5207b7SJohn Levon 
437*1f5207b7SJohn Levon static const char *stor_op_name(struct storage *s)
438*1f5207b7SJohn Levon {
439*1f5207b7SJohn Levon 	static char name[32];
440*1f5207b7SJohn Levon 
441*1f5207b7SJohn Levon 	switch (s->type) {
442*1f5207b7SJohn Levon 	case STOR_PSEUDO:
443*1f5207b7SJohn Levon 		strcpy(name, pretty_offset((int) pseudo_offset(s)));
444*1f5207b7SJohn Levon 		break;
445*1f5207b7SJohn Levon 	case STOR_ARG:
446*1f5207b7SJohn Levon 		strcpy(name, pretty_offset((int) arg_offset(s)));
447*1f5207b7SJohn Levon 		break;
448*1f5207b7SJohn Levon 	case STOR_SYM:
449*1f5207b7SJohn Levon 		strcpy(name, show_ident(s->sym->ident));
450*1f5207b7SJohn Levon 		break;
451*1f5207b7SJohn Levon 	case STOR_REG:
452*1f5207b7SJohn Levon 		strcpy(name, s->reg->name);
453*1f5207b7SJohn Levon 		break;
454*1f5207b7SJohn Levon 	case STOR_VALUE:
455*1f5207b7SJohn Levon 		sprintf(name, "$%Ld", s->value);
456*1f5207b7SJohn Levon 		break;
457*1f5207b7SJohn Levon 	case STOR_LABEL:
458*1f5207b7SJohn Levon 		sprintf(name, "%s.L%d", s->flags & STOR_LABEL_VAL ? "$" : "",
459*1f5207b7SJohn Levon 			s->label);
460*1f5207b7SJohn Levon 		break;
461*1f5207b7SJohn Levon 	case STOR_LABELSYM:
462*1f5207b7SJohn Levon 		sprintf(name, "%s.LS%p", s->flags & STOR_LABEL_VAL ? "$" : "",
463*1f5207b7SJohn Levon 			s->labelsym);
464*1f5207b7SJohn Levon 		break;
465*1f5207b7SJohn Levon 	}
466*1f5207b7SJohn Levon 
467*1f5207b7SJohn Levon 	return name;
468*1f5207b7SJohn Levon }
469*1f5207b7SJohn Levon 
470*1f5207b7SJohn Levon static struct atom *new_atom(enum atom_type type)
471*1f5207b7SJohn Levon {
472*1f5207b7SJohn Levon 	struct atom *atom;
473*1f5207b7SJohn Levon 
474*1f5207b7SJohn Levon 	atom = calloc(1, sizeof(*atom));	/* TODO: chunked alloc */
475*1f5207b7SJohn Levon 	if (!atom)
476*1f5207b7SJohn Levon 		die("nuclear OOM");
477*1f5207b7SJohn Levon 
478*1f5207b7SJohn Levon 	atom->type = type;
479*1f5207b7SJohn Levon 
480*1f5207b7SJohn Levon 	return atom;
481*1f5207b7SJohn Levon }
482*1f5207b7SJohn Levon 
483*1f5207b7SJohn Levon static inline void push_cstring(struct function *f, struct string *str,
484*1f5207b7SJohn Levon 				int label)
485*1f5207b7SJohn Levon {
486*1f5207b7SJohn Levon 	struct atom *atom;
487*1f5207b7SJohn Levon 
488*1f5207b7SJohn Levon 	atom = new_atom(ATOM_CSTR);
489*1f5207b7SJohn Levon 	atom->string = str;
490*1f5207b7SJohn Levon 	atom->label = label;
491*1f5207b7SJohn Levon 
492*1f5207b7SJohn Levon 	add_ptr_list(&f->str_list, atom);	/* note: _not_ atom_list */
493*1f5207b7SJohn Levon }
494*1f5207b7SJohn Levon 
495*1f5207b7SJohn Levon static inline void push_atom(struct function *f, struct atom *atom)
496*1f5207b7SJohn Levon {
497*1f5207b7SJohn Levon 	add_ptr_list(&f->atom_list, atom);
498*1f5207b7SJohn Levon }
499*1f5207b7SJohn Levon 
500*1f5207b7SJohn Levon static void push_text_atom(struct function *f, const char *text)
501*1f5207b7SJohn Levon {
502*1f5207b7SJohn Levon 	struct atom *atom = new_atom(ATOM_TEXT);
503*1f5207b7SJohn Levon 
504*1f5207b7SJohn Levon 	atom->text = strdup(text);
505*1f5207b7SJohn Levon 	atom->text_len = strlen(text);
506*1f5207b7SJohn Levon 
507*1f5207b7SJohn Levon 	push_atom(f, atom);
508*1f5207b7SJohn Levon }
509*1f5207b7SJohn Levon 
510*1f5207b7SJohn Levon static struct storage *new_storage(enum storage_type type)
511*1f5207b7SJohn Levon {
512*1f5207b7SJohn Levon 	struct storage *stor;
513*1f5207b7SJohn Levon 
514*1f5207b7SJohn Levon 	stor = calloc(1, sizeof(*stor));
515*1f5207b7SJohn Levon 	if (!stor)
516*1f5207b7SJohn Levon 		die("OOM in new_storage");
517*1f5207b7SJohn Levon 
518*1f5207b7SJohn Levon 	stor->type = type;
519*1f5207b7SJohn Levon 
520*1f5207b7SJohn Levon 	return stor;
521*1f5207b7SJohn Levon }
522*1f5207b7SJohn Levon 
523*1f5207b7SJohn Levon static struct storage *stack_alloc(int n_bytes)
524*1f5207b7SJohn Levon {
525*1f5207b7SJohn Levon 	struct function *f = current_func;
526*1f5207b7SJohn Levon 	struct storage *stor;
527*1f5207b7SJohn Levon 
528*1f5207b7SJohn Levon 	assert(f != NULL);
529*1f5207b7SJohn Levon 
530*1f5207b7SJohn Levon 	stor = new_storage(STOR_PSEUDO);
531*1f5207b7SJohn Levon 	stor->type = STOR_PSEUDO;
532*1f5207b7SJohn Levon 	stor->pseudo = f->pseudo_nr;
533*1f5207b7SJohn Levon 	stor->offset = f->stack_size; /* FIXME: stack req. natural align */
534*1f5207b7SJohn Levon 	stor->size = n_bytes;
535*1f5207b7SJohn Levon 	f->stack_size += n_bytes;
536*1f5207b7SJohn Levon 	f->pseudo_nr++;
537*1f5207b7SJohn Levon 
538*1f5207b7SJohn Levon 	add_ptr_list(&f->pseudo_list, stor);
539*1f5207b7SJohn Levon 
540*1f5207b7SJohn Levon 	return stor;
541*1f5207b7SJohn Levon }
542*1f5207b7SJohn Levon 
543*1f5207b7SJohn Levon static struct storage *new_labelsym(struct symbol *sym)
544*1f5207b7SJohn Levon {
545*1f5207b7SJohn Levon 	struct storage *stor;
546*1f5207b7SJohn Levon 
547*1f5207b7SJohn Levon 	stor = new_storage(STOR_LABELSYM);
548*1f5207b7SJohn Levon 
549*1f5207b7SJohn Levon 	if (stor) {
550*1f5207b7SJohn Levon 		stor->flags |= STOR_WANTS_FREE;
551*1f5207b7SJohn Levon 		stor->labelsym = sym;
552*1f5207b7SJohn Levon 	}
553*1f5207b7SJohn Levon 
554*1f5207b7SJohn Levon 	return stor;
555*1f5207b7SJohn Levon }
556*1f5207b7SJohn Levon 
557*1f5207b7SJohn Levon static struct storage *new_val(long long value)
558*1f5207b7SJohn Levon {
559*1f5207b7SJohn Levon 	struct storage *stor;
560*1f5207b7SJohn Levon 
561*1f5207b7SJohn Levon 	stor = new_storage(STOR_VALUE);
562*1f5207b7SJohn Levon 
563*1f5207b7SJohn Levon 	if (stor) {
564*1f5207b7SJohn Levon 		stor->flags |= STOR_WANTS_FREE;
565*1f5207b7SJohn Levon 		stor->value = value;
566*1f5207b7SJohn Levon 	}
567*1f5207b7SJohn Levon 
568*1f5207b7SJohn Levon 	return stor;
569*1f5207b7SJohn Levon }
570*1f5207b7SJohn Levon 
571*1f5207b7SJohn Levon static int new_label(void)
572*1f5207b7SJohn Levon {
573*1f5207b7SJohn Levon 	static int label = 0;
574*1f5207b7SJohn Levon 	return ++label;
575*1f5207b7SJohn Levon }
576*1f5207b7SJohn Levon 
577*1f5207b7SJohn Levon static void textbuf_push(struct textbuf **buf_p, const char *text)
578*1f5207b7SJohn Levon {
579*1f5207b7SJohn Levon 	struct textbuf *tmp, *list = *buf_p;
580*1f5207b7SJohn Levon 	unsigned int text_len = strlen(text);
581*1f5207b7SJohn Levon 	unsigned int alloc_len = text_len + 1 + sizeof(*list);
582*1f5207b7SJohn Levon 
583*1f5207b7SJohn Levon 	tmp = calloc(1, alloc_len);
584*1f5207b7SJohn Levon 	if (!tmp)
585*1f5207b7SJohn Levon 		die("OOM on textbuf alloc");
586*1f5207b7SJohn Levon 
587*1f5207b7SJohn Levon 	tmp->text = ((void *) tmp) + sizeof(*tmp);
588*1f5207b7SJohn Levon 	memcpy(tmp->text, text, text_len + 1);
589*1f5207b7SJohn Levon 	tmp->len = text_len;
590*1f5207b7SJohn Levon 
591*1f5207b7SJohn Levon 	/* add to end of list */
592*1f5207b7SJohn Levon 	if (!list) {
593*1f5207b7SJohn Levon 		list = tmp;
594*1f5207b7SJohn Levon 		tmp->prev = tmp;
595*1f5207b7SJohn Levon 	} else {
596*1f5207b7SJohn Levon 		tmp->prev = list->prev;
597*1f5207b7SJohn Levon 		tmp->prev->next = tmp;
598*1f5207b7SJohn Levon 		list->prev = tmp;
599*1f5207b7SJohn Levon 	}
600*1f5207b7SJohn Levon 	tmp->next = list;
601*1f5207b7SJohn Levon 
602*1f5207b7SJohn Levon 	*buf_p = list;
603*1f5207b7SJohn Levon }
604*1f5207b7SJohn Levon 
605*1f5207b7SJohn Levon static void textbuf_emit(struct textbuf **buf_p)
606*1f5207b7SJohn Levon {
607*1f5207b7SJohn Levon 	struct textbuf *tmp, *list = *buf_p;
608*1f5207b7SJohn Levon 
609*1f5207b7SJohn Levon 	while (list) {
610*1f5207b7SJohn Levon 		tmp = list;
611*1f5207b7SJohn Levon 		if (tmp->next == tmp)
612*1f5207b7SJohn Levon 			list = NULL;
613*1f5207b7SJohn Levon 		else {
614*1f5207b7SJohn Levon 			tmp->prev->next = tmp->next;
615*1f5207b7SJohn Levon 			tmp->next->prev = tmp->prev;
616*1f5207b7SJohn Levon 			list = tmp->next;
617*1f5207b7SJohn Levon 		}
618*1f5207b7SJohn Levon 
619*1f5207b7SJohn Levon 		fputs(tmp->text, stdout);
620*1f5207b7SJohn Levon 
621*1f5207b7SJohn Levon 		free(tmp);
622*1f5207b7SJohn Levon 	}
623*1f5207b7SJohn Levon 
624*1f5207b7SJohn Levon 	*buf_p = list;
625*1f5207b7SJohn Levon }
626*1f5207b7SJohn Levon 
627*1f5207b7SJohn Levon static void insn(const char *insn, struct storage *op1, struct storage *op2,
628*1f5207b7SJohn Levon 		 const char *comment_in)
629*1f5207b7SJohn Levon {
630*1f5207b7SJohn Levon 	struct function *f = current_func;
631*1f5207b7SJohn Levon 	struct atom *atom = new_atom(ATOM_INSN);
632*1f5207b7SJohn Levon 
633*1f5207b7SJohn Levon 	assert(insn != NULL);
634*1f5207b7SJohn Levon 
635*1f5207b7SJohn Levon 	strcpy(atom->insn, insn);
636*1f5207b7SJohn Levon 	if (comment_in && (*comment_in))
637*1f5207b7SJohn Levon 		strncpy(atom->comment, comment_in,
638*1f5207b7SJohn Levon 			sizeof(atom->comment) - 1);
639*1f5207b7SJohn Levon 
640*1f5207b7SJohn Levon 	atom->op1 = op1;
641*1f5207b7SJohn Levon 	atom->op2 = op2;
642*1f5207b7SJohn Levon 
643*1f5207b7SJohn Levon 	push_atom(f, atom);
644*1f5207b7SJohn Levon }
645*1f5207b7SJohn Levon 
646*1f5207b7SJohn Levon static void emit_comment(const char *fmt, ...)
647*1f5207b7SJohn Levon {
648*1f5207b7SJohn Levon 	struct function *f = current_func;
649*1f5207b7SJohn Levon 	static char tmpbuf[100] = "\t# ";
650*1f5207b7SJohn Levon 	va_list args;
651*1f5207b7SJohn Levon 	int i;
652*1f5207b7SJohn Levon 
653*1f5207b7SJohn Levon 	va_start(args, fmt);
654*1f5207b7SJohn Levon 	i = vsnprintf(tmpbuf+3, sizeof(tmpbuf)-4, fmt, args);
655*1f5207b7SJohn Levon 	va_end(args);
656*1f5207b7SJohn Levon 	tmpbuf[i+3] = '\n';
657*1f5207b7SJohn Levon 	tmpbuf[i+4] = '\0';
658*1f5207b7SJohn Levon 	push_text_atom(f, tmpbuf);
659*1f5207b7SJohn Levon }
660*1f5207b7SJohn Levon 
661*1f5207b7SJohn Levon static void emit_label (int label, const char *comment)
662*1f5207b7SJohn Levon {
663*1f5207b7SJohn Levon 	struct function *f = current_func;
664*1f5207b7SJohn Levon 	char s[64];
665*1f5207b7SJohn Levon 
666*1f5207b7SJohn Levon 	if (!comment)
667*1f5207b7SJohn Levon 		sprintf(s, ".L%d:\n", label);
668*1f5207b7SJohn Levon 	else
669*1f5207b7SJohn Levon 		sprintf(s, ".L%d:\t\t\t\t\t# %s\n", label, comment);
670*1f5207b7SJohn Levon 
671*1f5207b7SJohn Levon 	push_text_atom(f, s);
672*1f5207b7SJohn Levon }
673*1f5207b7SJohn Levon 
674*1f5207b7SJohn Levon static void emit_labelsym (struct symbol *sym, const char *comment)
675*1f5207b7SJohn Levon {
676*1f5207b7SJohn Levon 	struct function *f = current_func;
677*1f5207b7SJohn Levon 	char s[64];
678*1f5207b7SJohn Levon 
679*1f5207b7SJohn Levon 	if (!comment)
680*1f5207b7SJohn Levon 		sprintf(s, ".LS%p:\n", sym);
681*1f5207b7SJohn Levon 	else
682*1f5207b7SJohn Levon 		sprintf(s, ".LS%p:\t\t\t\t# %s\n", sym, comment);
683*1f5207b7SJohn Levon 
684*1f5207b7SJohn Levon 	push_text_atom(f, s);
685*1f5207b7SJohn Levon }
686*1f5207b7SJohn Levon 
687*1f5207b7SJohn Levon void emit_unit_begin(const char *basename)
688*1f5207b7SJohn Levon {
689*1f5207b7SJohn Levon 	printf("\t.file\t\"%s\"\n", basename);
690*1f5207b7SJohn Levon }
691*1f5207b7SJohn Levon 
692*1f5207b7SJohn Levon void emit_unit_end(void)
693*1f5207b7SJohn Levon {
694*1f5207b7SJohn Levon 	textbuf_emit(&unit_post_text);
695*1f5207b7SJohn Levon 	printf("\t.ident\t\"sparse silly x86 backend (version %s)\"\n", SPARSE_VERSION);
696*1f5207b7SJohn Levon }
697*1f5207b7SJohn Levon 
698*1f5207b7SJohn Levon /* conditionally switch sections */
699*1f5207b7SJohn Levon static void emit_section(const char *s)
700*1f5207b7SJohn Levon {
701*1f5207b7SJohn Levon 	if (s == current_section)
702*1f5207b7SJohn Levon 		return;
703*1f5207b7SJohn Levon 	if (current_section && (!strcmp(s, current_section)))
704*1f5207b7SJohn Levon 		return;
705*1f5207b7SJohn Levon 
706*1f5207b7SJohn Levon 	printf("\t%s\n", s);
707*1f5207b7SJohn Levon 	current_section = s;
708*1f5207b7SJohn Levon }
709*1f5207b7SJohn Levon 
710*1f5207b7SJohn Levon static void emit_insn_atom(struct function *f, struct atom *atom)
711*1f5207b7SJohn Levon {
712*1f5207b7SJohn Levon 	char s[128];
713*1f5207b7SJohn Levon 	char comment[64];
714*1f5207b7SJohn Levon 	struct storage *op1 = atom->op1;
715*1f5207b7SJohn Levon 	struct storage *op2 = atom->op2;
716*1f5207b7SJohn Levon 
717*1f5207b7SJohn Levon 	if (atom->comment[0])
718*1f5207b7SJohn Levon 		sprintf(comment, "\t\t# %s", atom->comment);
719*1f5207b7SJohn Levon 	else
720*1f5207b7SJohn Levon 		comment[0] = 0;
721*1f5207b7SJohn Levon 
722*1f5207b7SJohn Levon 	if (atom->op2) {
723*1f5207b7SJohn Levon 		char tmp[16];
724*1f5207b7SJohn Levon 		strcpy(tmp, stor_op_name(op1));
725*1f5207b7SJohn Levon 		sprintf(s, "\t%s\t%s, %s%s\n",
726*1f5207b7SJohn Levon 			atom->insn, tmp, stor_op_name(op2), comment);
727*1f5207b7SJohn Levon 	} else if (atom->op1)
728*1f5207b7SJohn Levon 		sprintf(s, "\t%s\t%s%s%s\n",
729*1f5207b7SJohn Levon 			atom->insn, stor_op_name(op1),
730*1f5207b7SJohn Levon 			comment[0] ? "\t" : "", comment);
731*1f5207b7SJohn Levon 	else
732*1f5207b7SJohn Levon 		sprintf(s, "\t%s\t%s%s\n",
733*1f5207b7SJohn Levon 			atom->insn,
734*1f5207b7SJohn Levon 			comment[0] ? "\t\t" : "", comment);
735*1f5207b7SJohn Levon 
736*1f5207b7SJohn Levon 	if (write(STDOUT_FILENO, s, strlen(s)) < 0)
737*1f5207b7SJohn Levon 		die("can't write to stdout");
738*1f5207b7SJohn Levon }
739*1f5207b7SJohn Levon 
740*1f5207b7SJohn Levon static void emit_atom_list(struct function *f)
741*1f5207b7SJohn Levon {
742*1f5207b7SJohn Levon 	struct atom *atom;
743*1f5207b7SJohn Levon 
744*1f5207b7SJohn Levon 	FOR_EACH_PTR(f->atom_list, atom) {
745*1f5207b7SJohn Levon 		switch (atom->type) {
746*1f5207b7SJohn Levon 		case ATOM_TEXT: {
747*1f5207b7SJohn Levon 			if (write(STDOUT_FILENO, atom->text, atom->text_len) < 0)
748*1f5207b7SJohn Levon 				die("can't write to stdout");
749*1f5207b7SJohn Levon 			break;
750*1f5207b7SJohn Levon 		}
751*1f5207b7SJohn Levon 		case ATOM_INSN:
752*1f5207b7SJohn Levon 			emit_insn_atom(f, atom);
753*1f5207b7SJohn Levon 			break;
754*1f5207b7SJohn Levon 		case ATOM_CSTR:
755*1f5207b7SJohn Levon 			assert(0);
756*1f5207b7SJohn Levon 			break;
757*1f5207b7SJohn Levon 		}
758*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(atom);
759*1f5207b7SJohn Levon }
760*1f5207b7SJohn Levon 
761*1f5207b7SJohn Levon static void emit_string_list(struct function *f)
762*1f5207b7SJohn Levon {
763*1f5207b7SJohn Levon 	struct atom *atom;
764*1f5207b7SJohn Levon 
765*1f5207b7SJohn Levon 	emit_section(".section\t.rodata");
766*1f5207b7SJohn Levon 
767*1f5207b7SJohn Levon 	FOR_EACH_PTR(f->str_list, atom) {
768*1f5207b7SJohn Levon 		/* FIXME: escape " in string */
769*1f5207b7SJohn Levon 		printf(".L%d:\n", atom->label);
770*1f5207b7SJohn Levon 		printf("\t.string\t%s\n", show_string(atom->string));
771*1f5207b7SJohn Levon 
772*1f5207b7SJohn Levon 		free(atom);
773*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(atom);
774*1f5207b7SJohn Levon }
775*1f5207b7SJohn Levon 
776*1f5207b7SJohn Levon static void func_cleanup(struct function *f)
777*1f5207b7SJohn Levon {
778*1f5207b7SJohn Levon 	struct storage *stor;
779*1f5207b7SJohn Levon 	struct atom *atom;
780*1f5207b7SJohn Levon 
781*1f5207b7SJohn Levon 	FOR_EACH_PTR(f->atom_list, atom) {
782*1f5207b7SJohn Levon 		if ((atom->type == ATOM_TEXT) && (atom->text))
783*1f5207b7SJohn Levon 			free(atom->text);
784*1f5207b7SJohn Levon 		if (atom->op1 && (atom->op1->flags & STOR_WANTS_FREE))
785*1f5207b7SJohn Levon 			free(atom->op1);
786*1f5207b7SJohn Levon 		if (atom->op2 && (atom->op2->flags & STOR_WANTS_FREE))
787*1f5207b7SJohn Levon 			free(atom->op2);
788*1f5207b7SJohn Levon 		free(atom);
789*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(atom);
790*1f5207b7SJohn Levon 
791*1f5207b7SJohn Levon 	FOR_EACH_PTR(f->pseudo_list, stor) {
792*1f5207b7SJohn Levon 		free(stor);
793*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(stor);
794*1f5207b7SJohn Levon 
795*1f5207b7SJohn Levon 	free_ptr_list(&f->pseudo_list);
796*1f5207b7SJohn Levon 	free(f);
797*1f5207b7SJohn Levon }
798*1f5207b7SJohn Levon 
799*1f5207b7SJohn Levon /* function prologue */
800*1f5207b7SJohn Levon static void emit_func_pre(struct symbol *sym)
801*1f5207b7SJohn Levon {
802*1f5207b7SJohn Levon 	struct function *f;
803*1f5207b7SJohn Levon 	struct symbol *arg;
804*1f5207b7SJohn Levon 	unsigned int i, argc = 0, alloc_len;
805*1f5207b7SJohn Levon 	unsigned char *mem;
806*1f5207b7SJohn Levon 	struct symbol_private *privbase;
807*1f5207b7SJohn Levon 	struct storage *storage_base;
808*1f5207b7SJohn Levon 	struct symbol *base_type = sym->ctype.base_type;
809*1f5207b7SJohn Levon 
810*1f5207b7SJohn Levon 	FOR_EACH_PTR(base_type->arguments, arg) {
811*1f5207b7SJohn Levon 		argc++;
812*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
813*1f5207b7SJohn Levon 
814*1f5207b7SJohn Levon 	alloc_len =
815*1f5207b7SJohn Levon 		sizeof(*f) +
816*1f5207b7SJohn Levon 		(argc * sizeof(struct symbol *)) +
817*1f5207b7SJohn Levon 		(argc * sizeof(struct symbol_private)) +
818*1f5207b7SJohn Levon 		(argc * sizeof(struct storage));
819*1f5207b7SJohn Levon 	mem = calloc(1, alloc_len);
820*1f5207b7SJohn Levon 	if (!mem)
821*1f5207b7SJohn Levon 		die("OOM on func info");
822*1f5207b7SJohn Levon 
823*1f5207b7SJohn Levon 	f		=  (struct function *) mem;
824*1f5207b7SJohn Levon 	mem		+= sizeof(*f);
825*1f5207b7SJohn Levon 	f->argv		=  (struct symbol **) mem;
826*1f5207b7SJohn Levon 	mem		+= (argc * sizeof(struct symbol *));
827*1f5207b7SJohn Levon 	privbase	=  (struct symbol_private *) mem;
828*1f5207b7SJohn Levon 	mem		+= (argc * sizeof(struct symbol_private));
829*1f5207b7SJohn Levon 	storage_base	=  (struct storage *) mem;
830*1f5207b7SJohn Levon 
831*1f5207b7SJohn Levon 	f->argc = argc;
832*1f5207b7SJohn Levon 	f->ret_target = new_label();
833*1f5207b7SJohn Levon 
834*1f5207b7SJohn Levon 	i = 0;
835*1f5207b7SJohn Levon 	FOR_EACH_PTR(base_type->arguments, arg) {
836*1f5207b7SJohn Levon 		f->argv[i] = arg;
837*1f5207b7SJohn Levon 		arg->aux = &privbase[i];
838*1f5207b7SJohn Levon 		storage_base[i].type = STOR_ARG;
839*1f5207b7SJohn Levon 		storage_base[i].idx = i;
840*1f5207b7SJohn Levon 		privbase[i].addr = &storage_base[i];
841*1f5207b7SJohn Levon 		i++;
842*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
843*1f5207b7SJohn Levon 
844*1f5207b7SJohn Levon 	assert(current_func == NULL);
845*1f5207b7SJohn Levon 	current_func = f;
846*1f5207b7SJohn Levon }
847*1f5207b7SJohn Levon 
848*1f5207b7SJohn Levon /* function epilogue */
849*1f5207b7SJohn Levon static void emit_func_post(struct symbol *sym)
850*1f5207b7SJohn Levon {
851*1f5207b7SJohn Levon 	const char *name = show_ident(sym->ident);
852*1f5207b7SJohn Levon 	struct function *f = current_func;
853*1f5207b7SJohn Levon 	int stack_size = f->stack_size;
854*1f5207b7SJohn Levon 
855*1f5207b7SJohn Levon 	if (f->str_list)
856*1f5207b7SJohn Levon 		emit_string_list(f);
857*1f5207b7SJohn Levon 
858*1f5207b7SJohn Levon 	/* function prologue */
859*1f5207b7SJohn Levon 	emit_section(".text");
860*1f5207b7SJohn Levon 	if ((sym->ctype.modifiers & MOD_STATIC) == 0)
861*1f5207b7SJohn Levon 		printf(".globl %s\n", name);
862*1f5207b7SJohn Levon 	printf("\t.type\t%s, @function\n", name);
863*1f5207b7SJohn Levon 	printf("%s:\n", name);
864*1f5207b7SJohn Levon 
865*1f5207b7SJohn Levon 	if (stack_size) {
866*1f5207b7SJohn Levon 		char pseudo_const[16];
867*1f5207b7SJohn Levon 
868*1f5207b7SJohn Levon 		sprintf(pseudo_const, "$%d", stack_size);
869*1f5207b7SJohn Levon 		printf("\tsubl\t%s, %%esp\n", pseudo_const);
870*1f5207b7SJohn Levon 	}
871*1f5207b7SJohn Levon 
872*1f5207b7SJohn Levon 	/* function epilogue */
873*1f5207b7SJohn Levon 
874*1f5207b7SJohn Levon 	/* jump target for 'return' statements */
875*1f5207b7SJohn Levon 	emit_label(f->ret_target, NULL);
876*1f5207b7SJohn Levon 
877*1f5207b7SJohn Levon 	if (stack_size) {
878*1f5207b7SJohn Levon 		struct storage *val;
879*1f5207b7SJohn Levon 
880*1f5207b7SJohn Levon 		val = new_storage(STOR_VALUE);
881*1f5207b7SJohn Levon 		val->value = (long long) (stack_size);
882*1f5207b7SJohn Levon 		val->flags = STOR_WANTS_FREE;
883*1f5207b7SJohn Levon 
884*1f5207b7SJohn Levon 		insn("addl", val, REG_ESP, NULL);
885*1f5207b7SJohn Levon 	}
886*1f5207b7SJohn Levon 
887*1f5207b7SJohn Levon 	insn("ret", NULL, NULL, NULL);
888*1f5207b7SJohn Levon 
889*1f5207b7SJohn Levon 	/* output everything to stdout */
890*1f5207b7SJohn Levon 	fflush(stdout);		/* paranoia; needed? */
891*1f5207b7SJohn Levon 	emit_atom_list(f);
892*1f5207b7SJohn Levon 
893*1f5207b7SJohn Levon 	/* function footer */
894*1f5207b7SJohn Levon 	name = show_ident(sym->ident);
895*1f5207b7SJohn Levon 	printf("\t.size\t%s, .-%s\n", name, name);
896*1f5207b7SJohn Levon 
897*1f5207b7SJohn Levon 	func_cleanup(f);
898*1f5207b7SJohn Levon 	current_func = NULL;
899*1f5207b7SJohn Levon }
900*1f5207b7SJohn Levon 
901*1f5207b7SJohn Levon /* emit object (a.k.a. variable, a.k.a. data) prologue */
902*1f5207b7SJohn Levon static void emit_object_pre(const char *name, unsigned long modifiers,
903*1f5207b7SJohn Levon 			    unsigned long alignment, unsigned int byte_size)
904*1f5207b7SJohn Levon {
905*1f5207b7SJohn Levon 	if ((modifiers & MOD_STATIC) == 0)
906*1f5207b7SJohn Levon 		printf(".globl %s\n", name);
907*1f5207b7SJohn Levon 	emit_section(".data");
908*1f5207b7SJohn Levon 	if (alignment)
909*1f5207b7SJohn Levon 		printf("\t.align %lu\n", alignment);
910*1f5207b7SJohn Levon 	printf("\t.type\t%s, @object\n", name);
911*1f5207b7SJohn Levon 	printf("\t.size\t%s, %d\n", name, byte_size);
912*1f5207b7SJohn Levon 	printf("%s:\n", name);
913*1f5207b7SJohn Levon }
914*1f5207b7SJohn Levon 
915*1f5207b7SJohn Levon /* emit value (only) for an initializer scalar */
916*1f5207b7SJohn Levon static void emit_scalar(struct expression *expr, unsigned int bit_size)
917*1f5207b7SJohn Levon {
918*1f5207b7SJohn Levon 	const char *type;
919*1f5207b7SJohn Levon 	long long ll;
920*1f5207b7SJohn Levon 
921*1f5207b7SJohn Levon 	assert(expr->type == EXPR_VALUE);
922*1f5207b7SJohn Levon 
923*1f5207b7SJohn Levon 	if (expr->value == 0ULL) {
924*1f5207b7SJohn Levon 		printf("\t.zero\t%d\n", bit_size / 8);
925*1f5207b7SJohn Levon 		return;
926*1f5207b7SJohn Levon 	}
927*1f5207b7SJohn Levon 
928*1f5207b7SJohn Levon 	ll = (long long) expr->value;
929*1f5207b7SJohn Levon 
930*1f5207b7SJohn Levon 	switch (bit_size) {
931*1f5207b7SJohn Levon 	case 8:		type = "byte";	ll = (char) ll; break;
932*1f5207b7SJohn Levon 	case 16:	type = "value";	ll = (short) ll; break;
933*1f5207b7SJohn Levon 	case 32:	type = "long";	ll = (int) ll; break;
934*1f5207b7SJohn Levon 	case 64:	type = "quad";	break;
935*1f5207b7SJohn Levon 	default:	type = NULL;	break;
936*1f5207b7SJohn Levon 	}
937*1f5207b7SJohn Levon 
938*1f5207b7SJohn Levon 	assert(type != NULL);
939*1f5207b7SJohn Levon 
940*1f5207b7SJohn Levon 	printf("\t.%s\t%Ld\n", type, ll);
941*1f5207b7SJohn Levon }
942*1f5207b7SJohn Levon 
943*1f5207b7SJohn Levon static void emit_global_noinit(const char *name, unsigned long modifiers,
944*1f5207b7SJohn Levon 			       unsigned long alignment, unsigned int byte_size)
945*1f5207b7SJohn Levon {
946*1f5207b7SJohn Levon 	char s[64];
947*1f5207b7SJohn Levon 
948*1f5207b7SJohn Levon 	if (modifiers & MOD_STATIC) {
949*1f5207b7SJohn Levon 		sprintf(s, "\t.local\t%s\n", name);
950*1f5207b7SJohn Levon 		textbuf_push(&unit_post_text, s);
951*1f5207b7SJohn Levon 	}
952*1f5207b7SJohn Levon 	if (alignment)
953*1f5207b7SJohn Levon 		sprintf(s, "\t.comm\t%s,%d,%lu\n", name, byte_size, alignment);
954*1f5207b7SJohn Levon 	else
955*1f5207b7SJohn Levon 		sprintf(s, "\t.comm\t%s,%d\n", name, byte_size);
956*1f5207b7SJohn Levon 	textbuf_push(&unit_post_text, s);
957*1f5207b7SJohn Levon }
958*1f5207b7SJohn Levon 
959*1f5207b7SJohn Levon static int ea_current, ea_last;
960*1f5207b7SJohn Levon 
961*1f5207b7SJohn Levon static void emit_initializer(struct symbol *sym,
962*1f5207b7SJohn Levon 			     struct expression *expr)
963*1f5207b7SJohn Levon {
964*1f5207b7SJohn Levon 	int distance = ea_current - ea_last - 1;
965*1f5207b7SJohn Levon 
966*1f5207b7SJohn Levon 	if (distance > 0)
967*1f5207b7SJohn Levon 		printf("\t.zero\t%d\n", (sym->bit_size / 8) * distance);
968*1f5207b7SJohn Levon 
969*1f5207b7SJohn Levon 	if (expr->type == EXPR_VALUE) {
970*1f5207b7SJohn Levon 		struct symbol *base_type = sym->ctype.base_type;
971*1f5207b7SJohn Levon 		assert(base_type != NULL);
972*1f5207b7SJohn Levon 
973*1f5207b7SJohn Levon 		emit_scalar(expr, sym->bit_size / get_expression_value(base_type->array_size));
974*1f5207b7SJohn Levon 		return;
975*1f5207b7SJohn Levon 	}
976*1f5207b7SJohn Levon 	if (expr->type != EXPR_INITIALIZER)
977*1f5207b7SJohn Levon 		return;
978*1f5207b7SJohn Levon 
979*1f5207b7SJohn Levon 	assert(0); /* FIXME */
980*1f5207b7SJohn Levon }
981*1f5207b7SJohn Levon 
982*1f5207b7SJohn Levon static int sort_array_cmp(const struct expression *a,
983*1f5207b7SJohn Levon 			  const struct expression *b)
984*1f5207b7SJohn Levon {
985*1f5207b7SJohn Levon 	int a_ofs = 0, b_ofs = 0;
986*1f5207b7SJohn Levon 
987*1f5207b7SJohn Levon 	if (a->type == EXPR_POS)
988*1f5207b7SJohn Levon 		a_ofs = (int) a->init_offset;
989*1f5207b7SJohn Levon 	if (b->type == EXPR_POS)
990*1f5207b7SJohn Levon 		b_ofs = (int) b->init_offset;
991*1f5207b7SJohn Levon 
992*1f5207b7SJohn Levon 	return a_ofs - b_ofs;
993*1f5207b7SJohn Levon }
994*1f5207b7SJohn Levon 
995*1f5207b7SJohn Levon /* move to front-end? */
996*1f5207b7SJohn Levon static void sort_array(struct expression *expr)
997*1f5207b7SJohn Levon {
998*1f5207b7SJohn Levon 	struct expression *entry, **list;
999*1f5207b7SJohn Levon 	unsigned int elem, sorted, i;
1000*1f5207b7SJohn Levon 
1001*1f5207b7SJohn Levon 	elem = expression_list_size(expr->expr_list);
1002*1f5207b7SJohn Levon 	if (!elem)
1003*1f5207b7SJohn Levon 		return;
1004*1f5207b7SJohn Levon 
1005*1f5207b7SJohn Levon 	list = malloc(sizeof(entry) * elem);
1006*1f5207b7SJohn Levon 	if (!list)
1007*1f5207b7SJohn Levon 		die("OOM in sort_array");
1008*1f5207b7SJohn Levon 
1009*1f5207b7SJohn Levon 	/* this code is no doubt evil and ignores EXPR_INDEX possibly
1010*1f5207b7SJohn Levon 	 * to its detriment and other nasty things.  improvements
1011*1f5207b7SJohn Levon 	 * welcome.
1012*1f5207b7SJohn Levon 	 */
1013*1f5207b7SJohn Levon 	i = 0;
1014*1f5207b7SJohn Levon 	sorted = 0;
1015*1f5207b7SJohn Levon 	FOR_EACH_PTR(expr->expr_list, entry) {
1016*1f5207b7SJohn Levon 		if ((entry->type == EXPR_POS) || (entry->type == EXPR_VALUE)) {
1017*1f5207b7SJohn Levon 			/* add entry to list[], in sorted order */
1018*1f5207b7SJohn Levon 			if (sorted == 0) {
1019*1f5207b7SJohn Levon 				list[0] = entry;
1020*1f5207b7SJohn Levon 				sorted = 1;
1021*1f5207b7SJohn Levon 			} else {
1022*1f5207b7SJohn Levon 				for (i = 0; i < sorted; i++)
1023*1f5207b7SJohn Levon 					if (sort_array_cmp(entry, list[i]) <= 0)
1024*1f5207b7SJohn Levon 						break;
1025*1f5207b7SJohn Levon 
1026*1f5207b7SJohn Levon 				/* If inserting into the middle of list[]
1027*1f5207b7SJohn Levon 				 * instead of appending, we memmove.
1028*1f5207b7SJohn Levon 				 * This is ugly, but thankfully
1029*1f5207b7SJohn Levon 				 * uncommon.  Input data with tons of
1030*1f5207b7SJohn Levon 				 * entries very rarely have explicit
1031*1f5207b7SJohn Levon 				 * offsets.  convert to qsort eventually...
1032*1f5207b7SJohn Levon 				 */
1033*1f5207b7SJohn Levon 				if (i != sorted)
1034*1f5207b7SJohn Levon 					memmove(&list[i + 1], &list[i],
1035*1f5207b7SJohn Levon 						(sorted - i) * sizeof(entry));
1036*1f5207b7SJohn Levon 				list[i] = entry;
1037*1f5207b7SJohn Levon 				sorted++;
1038*1f5207b7SJohn Levon 			}
1039*1f5207b7SJohn Levon 		}
1040*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(entry);
1041*1f5207b7SJohn Levon 
1042*1f5207b7SJohn Levon 	i = 0;
1043*1f5207b7SJohn Levon 	FOR_EACH_PTR(expr->expr_list, entry) {
1044*1f5207b7SJohn Levon 		if ((entry->type == EXPR_POS) || (entry->type == EXPR_VALUE))
1045*1f5207b7SJohn Levon 			*THIS_ADDRESS(entry) = list[i++];
1046*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(entry);
1047*1f5207b7SJohn Levon 
1048*1f5207b7SJohn Levon 	free(list);
1049*1f5207b7SJohn Levon }
1050*1f5207b7SJohn Levon 
1051*1f5207b7SJohn Levon static void emit_array(struct symbol *sym)
1052*1f5207b7SJohn Levon {
1053*1f5207b7SJohn Levon 	struct symbol *base_type = sym->ctype.base_type;
1054*1f5207b7SJohn Levon 	struct expression *expr = sym->initializer;
1055*1f5207b7SJohn Levon 	struct expression *entry;
1056*1f5207b7SJohn Levon 
1057*1f5207b7SJohn Levon 	assert(base_type != NULL);
1058*1f5207b7SJohn Levon 
1059*1f5207b7SJohn Levon 	stor_sym_init(sym);
1060*1f5207b7SJohn Levon 
1061*1f5207b7SJohn Levon 	ea_last = -1;
1062*1f5207b7SJohn Levon 
1063*1f5207b7SJohn Levon 	emit_object_pre(show_ident(sym->ident), sym->ctype.modifiers,
1064*1f5207b7SJohn Levon 		        sym->ctype.alignment,
1065*1f5207b7SJohn Levon 			sym->bit_size / 8);
1066*1f5207b7SJohn Levon 
1067*1f5207b7SJohn Levon 	sort_array(expr);
1068*1f5207b7SJohn Levon 
1069*1f5207b7SJohn Levon 	FOR_EACH_PTR(expr->expr_list, entry) {
1070*1f5207b7SJohn Levon 		if (entry->type == EXPR_VALUE) {
1071*1f5207b7SJohn Levon 			ea_current = 0;
1072*1f5207b7SJohn Levon 			emit_initializer(sym, entry);
1073*1f5207b7SJohn Levon 			ea_last = ea_current;
1074*1f5207b7SJohn Levon 		} else if (entry->type == EXPR_POS) {
1075*1f5207b7SJohn Levon 			ea_current =
1076*1f5207b7SJohn Levon 			    entry->init_offset / (base_type->bit_size / 8);
1077*1f5207b7SJohn Levon 			emit_initializer(sym, entry->init_expr);
1078*1f5207b7SJohn Levon 			ea_last = ea_current;
1079*1f5207b7SJohn Levon 		}
1080*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(entry);
1081*1f5207b7SJohn Levon }
1082*1f5207b7SJohn Levon 
1083*1f5207b7SJohn Levon void emit_one_symbol(struct symbol *sym)
1084*1f5207b7SJohn Levon {
1085*1f5207b7SJohn Levon 	x86_symbol(sym);
1086*1f5207b7SJohn Levon }
1087*1f5207b7SJohn Levon 
1088*1f5207b7SJohn Levon static void emit_copy(struct storage *dest, struct storage *src,
1089*1f5207b7SJohn Levon 		      struct symbol *ctype)
1090*1f5207b7SJohn Levon {
1091*1f5207b7SJohn Levon 	struct storage *reg = NULL;
1092*1f5207b7SJohn Levon 	unsigned int bit_size;
1093*1f5207b7SJohn Levon 
1094*1f5207b7SJohn Levon 	/* FIXME: Bitfield copy! */
1095*1f5207b7SJohn Levon 
1096*1f5207b7SJohn Levon 	bit_size = src->size * 8;
1097*1f5207b7SJohn Levon 	if (!bit_size)
1098*1f5207b7SJohn Levon 		bit_size = 32;
1099*1f5207b7SJohn Levon 	if ((src->type == STOR_ARG) && (bit_size < 32))
1100*1f5207b7SJohn Levon 		bit_size = 32;
1101*1f5207b7SJohn Levon 
1102*1f5207b7SJohn Levon 	reg = temp_from_bits(bit_size);
1103*1f5207b7SJohn Levon 	emit_move(src, reg, ctype, "begin copy ..");
1104*1f5207b7SJohn Levon 
1105*1f5207b7SJohn Levon 	bit_size = dest->size * 8;
1106*1f5207b7SJohn Levon 	if (!bit_size)
1107*1f5207b7SJohn Levon 		bit_size = 32;
1108*1f5207b7SJohn Levon 	if ((dest->type == STOR_ARG) && (bit_size < 32))
1109*1f5207b7SJohn Levon 		bit_size = 32;
1110*1f5207b7SJohn Levon 
1111*1f5207b7SJohn Levon 	emit_move(reg, dest, ctype, ".... end copy");
1112*1f5207b7SJohn Levon 	put_reg(reg);
1113*1f5207b7SJohn Levon }
1114*1f5207b7SJohn Levon 
1115*1f5207b7SJohn Levon static void emit_store(struct expression *dest_expr, struct storage *dest,
1116*1f5207b7SJohn Levon 		       struct storage *src, int bits)
1117*1f5207b7SJohn Levon {
1118*1f5207b7SJohn Levon 	/* FIXME: Bitfield store! */
1119*1f5207b7SJohn Levon 	printf("\tst.%d\t\tv%d,[v%d]\n", bits, src->pseudo, dest->pseudo);
1120*1f5207b7SJohn Levon }
1121*1f5207b7SJohn Levon 
1122*1f5207b7SJohn Levon static void emit_scalar_noinit(struct symbol *sym)
1123*1f5207b7SJohn Levon {
1124*1f5207b7SJohn Levon 	emit_global_noinit(show_ident(sym->ident),
1125*1f5207b7SJohn Levon 			   sym->ctype.modifiers, sym->ctype.alignment,
1126*1f5207b7SJohn Levon 			   sym->bit_size / 8);
1127*1f5207b7SJohn Levon 	stor_sym_init(sym);
1128*1f5207b7SJohn Levon }
1129*1f5207b7SJohn Levon 
1130*1f5207b7SJohn Levon static void emit_array_noinit(struct symbol *sym)
1131*1f5207b7SJohn Levon {
1132*1f5207b7SJohn Levon 	emit_global_noinit(show_ident(sym->ident),
1133*1f5207b7SJohn Levon 			   sym->ctype.modifiers, sym->ctype.alignment,
1134*1f5207b7SJohn Levon 			   get_expression_value(sym->array_size) * (sym->bit_size / 8));
1135*1f5207b7SJohn Levon 	stor_sym_init(sym);
1136*1f5207b7SJohn Levon }
1137*1f5207b7SJohn Levon 
1138*1f5207b7SJohn Levon static const char *opbits(const char *insn, unsigned int bits)
1139*1f5207b7SJohn Levon {
1140*1f5207b7SJohn Levon 	static char opbits_str[32];
1141*1f5207b7SJohn Levon 	char c;
1142*1f5207b7SJohn Levon 
1143*1f5207b7SJohn Levon 	switch (bits) {
1144*1f5207b7SJohn Levon 	case 8:	 c = 'b'; break;
1145*1f5207b7SJohn Levon 	case 16: c = 'w'; break;
1146*1f5207b7SJohn Levon 	case 32: c = 'l'; break;
1147*1f5207b7SJohn Levon 	case 64: c = 'q'; break;
1148*1f5207b7SJohn Levon 	default: abort(); break;
1149*1f5207b7SJohn Levon 	}
1150*1f5207b7SJohn Levon 
1151*1f5207b7SJohn Levon 	sprintf(opbits_str, "%s%c", insn, c);
1152*1f5207b7SJohn Levon 
1153*1f5207b7SJohn Levon 	return opbits_str;
1154*1f5207b7SJohn Levon }
1155*1f5207b7SJohn Levon 
1156*1f5207b7SJohn Levon static void emit_move(struct storage *src, struct storage *dest,
1157*1f5207b7SJohn Levon 		      struct symbol *ctype, const char *comment)
1158*1f5207b7SJohn Levon {
1159*1f5207b7SJohn Levon 	unsigned int bits;
1160*1f5207b7SJohn Levon 	unsigned int is_signed;
1161*1f5207b7SJohn Levon 	unsigned int is_dest = (src->type == STOR_REG);
1162*1f5207b7SJohn Levon 	const char *opname;
1163*1f5207b7SJohn Levon 
1164*1f5207b7SJohn Levon 	if (ctype) {
1165*1f5207b7SJohn Levon 		bits = ctype->bit_size;
1166*1f5207b7SJohn Levon 		is_signed = type_is_signed(ctype);
1167*1f5207b7SJohn Levon 	} else {
1168*1f5207b7SJohn Levon 		bits = 32;
1169*1f5207b7SJohn Levon 		is_signed = 0;
1170*1f5207b7SJohn Levon 	}
1171*1f5207b7SJohn Levon 
1172*1f5207b7SJohn Levon 	/*
1173*1f5207b7SJohn Levon 	 * Are we moving from a register to a register?
1174*1f5207b7SJohn Levon 	 * Make the new reg to be the "cache".
1175*1f5207b7SJohn Levon 	 */
1176*1f5207b7SJohn Levon 	if ((dest->type == STOR_REG) && (src->type == STOR_REG)) {
1177*1f5207b7SJohn Levon 		struct storage *backing;
1178*1f5207b7SJohn Levon 
1179*1f5207b7SJohn Levon reg_reg_move:
1180*1f5207b7SJohn Levon 		if (dest == src)
1181*1f5207b7SJohn Levon 			return;
1182*1f5207b7SJohn Levon 
1183*1f5207b7SJohn Levon 		backing = src->reg->contains;
1184*1f5207b7SJohn Levon 		if (backing) {
1185*1f5207b7SJohn Levon 			/* Is it still valid? */
1186*1f5207b7SJohn Levon 			if (backing->reg != src->reg)
1187*1f5207b7SJohn Levon 				backing = NULL;
1188*1f5207b7SJohn Levon 			else
1189*1f5207b7SJohn Levon 				backing->reg = dest->reg;
1190*1f5207b7SJohn Levon 		}
1191*1f5207b7SJohn Levon 		dest->reg->contains = backing;
1192*1f5207b7SJohn Levon 		insn("mov", src, dest, NULL);
1193*1f5207b7SJohn Levon 		return;
1194*1f5207b7SJohn Levon 	}
1195*1f5207b7SJohn Levon 
1196*1f5207b7SJohn Levon 	/*
1197*1f5207b7SJohn Levon 	 * Are we moving to a register from a non-reg?
1198*1f5207b7SJohn Levon 	 *
1199*1f5207b7SJohn Levon 	 * See if we have the non-reg source already cached
1200*1f5207b7SJohn Levon 	 * in a register..
1201*1f5207b7SJohn Levon 	 */
1202*1f5207b7SJohn Levon 	if (dest->type == STOR_REG) {
1203*1f5207b7SJohn Levon 		if (src->reg) {
1204*1f5207b7SJohn Levon 			struct reg_info *info = src->reg;
1205*1f5207b7SJohn Levon 			if (info->contains == src) {
1206*1f5207b7SJohn Levon 				src = reginfo_reg(info);
1207*1f5207b7SJohn Levon 				goto reg_reg_move;
1208*1f5207b7SJohn Levon 			}
1209*1f5207b7SJohn Levon 		}
1210*1f5207b7SJohn Levon 		dest->reg->contains = src;
1211*1f5207b7SJohn Levon 		src->reg = dest->reg;
1212*1f5207b7SJohn Levon 	}
1213*1f5207b7SJohn Levon 
1214*1f5207b7SJohn Levon 	if (src->type == STOR_REG) {
1215*1f5207b7SJohn Levon 		/* We could just mark the register dirty here and do lazy store.. */
1216*1f5207b7SJohn Levon 		src->reg->contains = dest;
1217*1f5207b7SJohn Levon 		dest->reg = src->reg;
1218*1f5207b7SJohn Levon 	}
1219*1f5207b7SJohn Levon 
1220*1f5207b7SJohn Levon 	if ((bits == 8) || (bits == 16)) {
1221*1f5207b7SJohn Levon 		if (is_dest)
1222*1f5207b7SJohn Levon 			opname = "mov";
1223*1f5207b7SJohn Levon 		else
1224*1f5207b7SJohn Levon 			opname = is_signed ? "movsx" : "movzx";
1225*1f5207b7SJohn Levon 	} else
1226*1f5207b7SJohn Levon 		opname = "mov";
1227*1f5207b7SJohn Levon 
1228*1f5207b7SJohn Levon 	insn(opbits(opname, bits), src, dest, comment);
1229*1f5207b7SJohn Levon }
1230*1f5207b7SJohn Levon 
1231*1f5207b7SJohn Levon static struct storage *emit_compare(struct expression *expr)
1232*1f5207b7SJohn Levon {
1233*1f5207b7SJohn Levon 	struct storage *left = x86_expression(expr->left);
1234*1f5207b7SJohn Levon 	struct storage *right = x86_expression(expr->right);
1235*1f5207b7SJohn Levon 	struct storage *reg1, *reg2;
1236*1f5207b7SJohn Levon 	struct storage *new, *val;
1237*1f5207b7SJohn Levon 	const char *opname = NULL;
1238*1f5207b7SJohn Levon 	unsigned int right_bits = expr->right->ctype->bit_size;
1239*1f5207b7SJohn Levon 
1240*1f5207b7SJohn Levon 	switch(expr->op) {
1241*1f5207b7SJohn Levon 	case '<': 		opname = "setl";	break;
1242*1f5207b7SJohn Levon 	case '>':		opname = "setg";	break;
1243*1f5207b7SJohn Levon 	case SPECIAL_LTE:
1244*1f5207b7SJohn Levon 				opname = "setle";	break;
1245*1f5207b7SJohn Levon 	case SPECIAL_GTE:
1246*1f5207b7SJohn Levon 				opname = "setge";	break;
1247*1f5207b7SJohn Levon 	case SPECIAL_EQUAL:	opname = "sete";	break;
1248*1f5207b7SJohn Levon 	case SPECIAL_NOTEQUAL:	opname = "setne";	break;
1249*1f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_LT:
1250*1f5207b7SJohn Levon 				opname = "setb";	break;
1251*1f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_GT:
1252*1f5207b7SJohn Levon 				opname = "seta";	break;
1253*1f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_LTE:
1254*1f5207b7SJohn Levon 				opname = "setb";	break;
1255*1f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_GTE:
1256*1f5207b7SJohn Levon 				opname = "setae";	break;
1257*1f5207b7SJohn Levon 	default:
1258*1f5207b7SJohn Levon 		assert(0);
1259*1f5207b7SJohn Levon 		break;
1260*1f5207b7SJohn Levon 	}
1261*1f5207b7SJohn Levon 
1262*1f5207b7SJohn Levon 	/* init EDX to 0 */
1263*1f5207b7SJohn Levon 	val = new_storage(STOR_VALUE);
1264*1f5207b7SJohn Levon 	val->flags = STOR_WANTS_FREE;
1265*1f5207b7SJohn Levon 
1266*1f5207b7SJohn Levon 	reg1 = get_reg(&regclass_32_8);
1267*1f5207b7SJohn Levon 	emit_move(val, reg1, NULL, NULL);
1268*1f5207b7SJohn Levon 
1269*1f5207b7SJohn Levon 	/* move op1 into EAX */
1270*1f5207b7SJohn Levon 	reg2 = get_reg_value(left, get_regclass(expr->left));
1271*1f5207b7SJohn Levon 
1272*1f5207b7SJohn Levon 	/* perform comparison, RHS (op1, right) and LHS (op2, EAX) */
1273*1f5207b7SJohn Levon 	insn(opbits("cmp", right_bits), right, reg2, NULL);
1274*1f5207b7SJohn Levon 	put_reg(reg2);
1275*1f5207b7SJohn Levon 
1276*1f5207b7SJohn Levon 	/* store result of operation, 0 or 1, in DL using SETcc */
1277*1f5207b7SJohn Levon 	insn(opname, byte_reg(reg1), NULL, NULL);
1278*1f5207b7SJohn Levon 
1279*1f5207b7SJohn Levon 	/* finally, store the result (DL) in a new pseudo / stack slot */
1280*1f5207b7SJohn Levon 	new = stack_alloc(4);
1281*1f5207b7SJohn Levon 	emit_move(reg1, new, NULL, "end EXPR_COMPARE");
1282*1f5207b7SJohn Levon 	put_reg(reg1);
1283*1f5207b7SJohn Levon 
1284*1f5207b7SJohn Levon 	return new;
1285*1f5207b7SJohn Levon }
1286*1f5207b7SJohn Levon 
1287*1f5207b7SJohn Levon static struct storage *emit_value(struct expression *expr)
1288*1f5207b7SJohn Levon {
1289*1f5207b7SJohn Levon #if 0 /* old and slow way */
1290*1f5207b7SJohn Levon 	struct storage *new = stack_alloc(4);
1291*1f5207b7SJohn Levon 	struct storage *val;
1292*1f5207b7SJohn Levon 
1293*1f5207b7SJohn Levon 	val = new_storage(STOR_VALUE);
1294*1f5207b7SJohn Levon 	val->value = (long long) expr->value;
1295*1f5207b7SJohn Levon 	val->flags = STOR_WANTS_FREE;
1296*1f5207b7SJohn Levon 	insn("movl", val, new, NULL);
1297*1f5207b7SJohn Levon 
1298*1f5207b7SJohn Levon 	return new;
1299*1f5207b7SJohn Levon #else
1300*1f5207b7SJohn Levon 	struct storage *val;
1301*1f5207b7SJohn Levon 
1302*1f5207b7SJohn Levon 	val = new_storage(STOR_VALUE);
1303*1f5207b7SJohn Levon 	val->value = (long long) expr->value;
1304*1f5207b7SJohn Levon 
1305*1f5207b7SJohn Levon 	return val;	/* FIXME: memory leak */
1306*1f5207b7SJohn Levon #endif
1307*1f5207b7SJohn Levon }
1308*1f5207b7SJohn Levon 
1309*1f5207b7SJohn Levon static struct storage *emit_divide(struct expression *expr, struct storage *left, struct storage *right)
1310*1f5207b7SJohn Levon {
1311*1f5207b7SJohn Levon 	struct storage *eax_edx;
1312*1f5207b7SJohn Levon 	struct storage *reg, *new;
1313*1f5207b7SJohn Levon 	struct storage *val = new_storage(STOR_VALUE);
1314*1f5207b7SJohn Levon 
1315*1f5207b7SJohn Levon 	emit_comment("begin DIVIDE");
1316*1f5207b7SJohn Levon 	eax_edx = get_hardreg(hardreg_storage_table + EAX_EDX, 1);
1317*1f5207b7SJohn Levon 
1318*1f5207b7SJohn Levon 	/* init EDX to 0 */
1319*1f5207b7SJohn Levon 	val->flags = STOR_WANTS_FREE;
1320*1f5207b7SJohn Levon 	emit_move(val, REG_EDX, NULL, NULL);
1321*1f5207b7SJohn Levon 
1322*1f5207b7SJohn Levon 	new = stack_alloc(expr->ctype->bit_size / 8);
1323*1f5207b7SJohn Levon 
1324*1f5207b7SJohn Levon 	/* EAX is dividend */
1325*1f5207b7SJohn Levon 	emit_move(left, REG_EAX, NULL, NULL);
1326*1f5207b7SJohn Levon 
1327*1f5207b7SJohn Levon 	reg = get_reg_value(right, &regclass_32);
1328*1f5207b7SJohn Levon 
1329*1f5207b7SJohn Levon 	/* perform binop */
1330*1f5207b7SJohn Levon 	insn("div", reg, REG_EAX, NULL);
1331*1f5207b7SJohn Levon 	put_reg(reg);
1332*1f5207b7SJohn Levon 
1333*1f5207b7SJohn Levon 	reg = REG_EAX;
1334*1f5207b7SJohn Levon 	if (expr->op == '%')
1335*1f5207b7SJohn Levon 		reg = REG_EDX;
1336*1f5207b7SJohn Levon 	emit_move(reg, new, NULL, NULL);
1337*1f5207b7SJohn Levon 
1338*1f5207b7SJohn Levon 	put_reg(eax_edx);
1339*1f5207b7SJohn Levon 	emit_comment("end DIVIDE");
1340*1f5207b7SJohn Levon 	return new;
1341*1f5207b7SJohn Levon }
1342*1f5207b7SJohn Levon 
1343*1f5207b7SJohn Levon static struct storage *emit_binop(struct expression *expr)
1344*1f5207b7SJohn Levon {
1345*1f5207b7SJohn Levon 	struct storage *left = x86_expression(expr->left);
1346*1f5207b7SJohn Levon 	struct storage *right = x86_expression(expr->right);
1347*1f5207b7SJohn Levon 	struct storage *new;
1348*1f5207b7SJohn Levon 	struct storage *dest, *src;
1349*1f5207b7SJohn Levon 	const char *opname = NULL;
1350*1f5207b7SJohn Levon 	const char *suffix = NULL;
1351*1f5207b7SJohn Levon 	char opstr[16];
1352*1f5207b7SJohn Levon 	int is_signed;
1353*1f5207b7SJohn Levon 
1354*1f5207b7SJohn Levon 	/* Divides have special register constraints */
1355*1f5207b7SJohn Levon 	if ((expr->op == '/') || (expr->op == '%'))
1356*1f5207b7SJohn Levon 		return emit_divide(expr, left, right);
1357*1f5207b7SJohn Levon 
1358*1f5207b7SJohn Levon 	is_signed = type_is_signed(expr->ctype);
1359*1f5207b7SJohn Levon 
1360*1f5207b7SJohn Levon 	switch (expr->op) {
1361*1f5207b7SJohn Levon 	case '+':
1362*1f5207b7SJohn Levon 		opname = "add";
1363*1f5207b7SJohn Levon 		break;
1364*1f5207b7SJohn Levon 	case '-':
1365*1f5207b7SJohn Levon 		opname = "sub";
1366*1f5207b7SJohn Levon 		break;
1367*1f5207b7SJohn Levon 	case '&':
1368*1f5207b7SJohn Levon 		opname = "and";
1369*1f5207b7SJohn Levon 		break;
1370*1f5207b7SJohn Levon 	case '|':
1371*1f5207b7SJohn Levon 		opname = "or";
1372*1f5207b7SJohn Levon 		break;
1373*1f5207b7SJohn Levon 	case '^':
1374*1f5207b7SJohn Levon 		opname = "xor";
1375*1f5207b7SJohn Levon 		break;
1376*1f5207b7SJohn Levon 	case SPECIAL_LEFTSHIFT:
1377*1f5207b7SJohn Levon 		opname = "shl";
1378*1f5207b7SJohn Levon 		break;
1379*1f5207b7SJohn Levon 	case SPECIAL_RIGHTSHIFT:
1380*1f5207b7SJohn Levon 		if (is_signed)
1381*1f5207b7SJohn Levon 			opname = "sar";
1382*1f5207b7SJohn Levon 		else
1383*1f5207b7SJohn Levon 			opname = "shr";
1384*1f5207b7SJohn Levon 		break;
1385*1f5207b7SJohn Levon 	case '*':
1386*1f5207b7SJohn Levon 		if (is_signed)
1387*1f5207b7SJohn Levon 			opname = "imul";
1388*1f5207b7SJohn Levon 		else
1389*1f5207b7SJohn Levon 			opname = "mul";
1390*1f5207b7SJohn Levon 		break;
1391*1f5207b7SJohn Levon 	case SPECIAL_LOGICAL_AND:
1392*1f5207b7SJohn Levon 		warning(expr->pos, "bogus bitwise and for logical op (should use '2*setne + and' or something)");
1393*1f5207b7SJohn Levon 		opname = "and";
1394*1f5207b7SJohn Levon 		break;
1395*1f5207b7SJohn Levon 	case SPECIAL_LOGICAL_OR:
1396*1f5207b7SJohn Levon 		warning(expr->pos, "bogus bitwise or for logical op (should use 'or + setne' or something)");
1397*1f5207b7SJohn Levon 		opname = "or";
1398*1f5207b7SJohn Levon 		break;
1399*1f5207b7SJohn Levon 	default:
1400*1f5207b7SJohn Levon 		error_die(expr->pos, "unhandled binop '%s'\n", show_special(expr->op));
1401*1f5207b7SJohn Levon 		break;
1402*1f5207b7SJohn Levon 	}
1403*1f5207b7SJohn Levon 
1404*1f5207b7SJohn Levon 	dest = get_reg_value(right, &regclass_32);
1405*1f5207b7SJohn Levon 	src = get_reg_value(left, &regclass_32);
1406*1f5207b7SJohn Levon 	switch (expr->ctype->bit_size) {
1407*1f5207b7SJohn Levon 	case 8:
1408*1f5207b7SJohn Levon 		suffix = "b";
1409*1f5207b7SJohn Levon 		break;
1410*1f5207b7SJohn Levon 	case 16:
1411*1f5207b7SJohn Levon 		suffix = "w";
1412*1f5207b7SJohn Levon 		break;
1413*1f5207b7SJohn Levon 	case 32:
1414*1f5207b7SJohn Levon 		suffix = "l";
1415*1f5207b7SJohn Levon 		break;
1416*1f5207b7SJohn Levon 	case 64:
1417*1f5207b7SJohn Levon 		suffix = "q";		/* FIXME */
1418*1f5207b7SJohn Levon 		break;
1419*1f5207b7SJohn Levon 	default:
1420*1f5207b7SJohn Levon 		assert(0);
1421*1f5207b7SJohn Levon 		break;
1422*1f5207b7SJohn Levon 	}
1423*1f5207b7SJohn Levon 
1424*1f5207b7SJohn Levon 	snprintf(opstr, sizeof(opstr), "%s%s", opname, suffix);
1425*1f5207b7SJohn Levon 
1426*1f5207b7SJohn Levon 	/* perform binop */
1427*1f5207b7SJohn Levon 	insn(opstr, src, dest, NULL);
1428*1f5207b7SJohn Levon 	put_reg(src);
1429*1f5207b7SJohn Levon 
1430*1f5207b7SJohn Levon 	/* store result in new pseudo / stack slot */
1431*1f5207b7SJohn Levon 	new = stack_alloc(expr->ctype->bit_size / 8);
1432*1f5207b7SJohn Levon 	emit_move(dest, new, NULL, "end EXPR_BINOP");
1433*1f5207b7SJohn Levon 
1434*1f5207b7SJohn Levon 	put_reg(dest);
1435*1f5207b7SJohn Levon 
1436*1f5207b7SJohn Levon 	return new;
1437*1f5207b7SJohn Levon }
1438*1f5207b7SJohn Levon 
1439*1f5207b7SJohn Levon static int emit_conditional_test(struct storage *val)
1440*1f5207b7SJohn Levon {
1441*1f5207b7SJohn Levon 	struct storage *reg;
1442*1f5207b7SJohn Levon 	struct storage *target_val;
1443*1f5207b7SJohn Levon 	int target_false;
1444*1f5207b7SJohn Levon 
1445*1f5207b7SJohn Levon 	/* load result into EAX */
1446*1f5207b7SJohn Levon 	emit_comment("begin if/conditional");
1447*1f5207b7SJohn Levon 	reg = get_reg_value(val, &regclass_32);
1448*1f5207b7SJohn Levon 
1449*1f5207b7SJohn Levon 	/* compare result with zero */
1450*1f5207b7SJohn Levon 	insn("test", reg, reg, NULL);
1451*1f5207b7SJohn Levon 	put_reg(reg);
1452*1f5207b7SJohn Levon 
1453*1f5207b7SJohn Levon 	/* create conditional-failed label to jump to */
1454*1f5207b7SJohn Levon 	target_false = new_label();
1455*1f5207b7SJohn Levon 	target_val = new_storage(STOR_LABEL);
1456*1f5207b7SJohn Levon 	target_val->label = target_false;
1457*1f5207b7SJohn Levon 	target_val->flags = STOR_WANTS_FREE;
1458*1f5207b7SJohn Levon 	insn("jz", target_val, NULL, NULL);
1459*1f5207b7SJohn Levon 
1460*1f5207b7SJohn Levon 	return target_false;
1461*1f5207b7SJohn Levon }
1462*1f5207b7SJohn Levon 
1463*1f5207b7SJohn Levon static int emit_conditional_end(int target_false)
1464*1f5207b7SJohn Levon {
1465*1f5207b7SJohn Levon 	struct storage *cond_end_st;
1466*1f5207b7SJohn Levon 	int cond_end;
1467*1f5207b7SJohn Levon 
1468*1f5207b7SJohn Levon 	/* finished generating code for if-true statement.
1469*1f5207b7SJohn Levon 	 * add a jump-to-end jump to avoid falling through
1470*1f5207b7SJohn Levon 	 * to the if-false statement code.
1471*1f5207b7SJohn Levon 	 */
1472*1f5207b7SJohn Levon 	cond_end = new_label();
1473*1f5207b7SJohn Levon 	cond_end_st = new_storage(STOR_LABEL);
1474*1f5207b7SJohn Levon 	cond_end_st->label = cond_end;
1475*1f5207b7SJohn Levon 	cond_end_st->flags = STOR_WANTS_FREE;
1476*1f5207b7SJohn Levon 	insn("jmp", cond_end_st, NULL, NULL);
1477*1f5207b7SJohn Levon 
1478*1f5207b7SJohn Levon 	/* if we have both if-true and if-false statements,
1479*1f5207b7SJohn Levon 	 * the failed-conditional case will fall through to here
1480*1f5207b7SJohn Levon 	 */
1481*1f5207b7SJohn Levon 	emit_label(target_false, NULL);
1482*1f5207b7SJohn Levon 
1483*1f5207b7SJohn Levon 	return cond_end;
1484*1f5207b7SJohn Levon }
1485*1f5207b7SJohn Levon 
1486*1f5207b7SJohn Levon static void emit_if_conditional(struct statement *stmt)
1487*1f5207b7SJohn Levon {
1488*1f5207b7SJohn Levon 	struct storage *val;
1489*1f5207b7SJohn Levon 	int cond_end;
1490*1f5207b7SJohn Levon 
1491*1f5207b7SJohn Levon 	/* emit test portion of conditional */
1492*1f5207b7SJohn Levon 	val = x86_expression(stmt->if_conditional);
1493*1f5207b7SJohn Levon 	cond_end = emit_conditional_test(val);
1494*1f5207b7SJohn Levon 
1495*1f5207b7SJohn Levon 	/* emit if-true statement */
1496*1f5207b7SJohn Levon 	x86_statement(stmt->if_true);
1497*1f5207b7SJohn Levon 
1498*1f5207b7SJohn Levon 	/* emit if-false statement, if present */
1499*1f5207b7SJohn Levon 	if (stmt->if_false) {
1500*1f5207b7SJohn Levon 		cond_end = emit_conditional_end(cond_end);
1501*1f5207b7SJohn Levon 		x86_statement(stmt->if_false);
1502*1f5207b7SJohn Levon 	}
1503*1f5207b7SJohn Levon 
1504*1f5207b7SJohn Levon 	/* end of conditional; jump target for if-true branch */
1505*1f5207b7SJohn Levon 	emit_label(cond_end, "end if");
1506*1f5207b7SJohn Levon }
1507*1f5207b7SJohn Levon 
1508*1f5207b7SJohn Levon static struct storage *emit_inc_dec(struct expression *expr, int postop)
1509*1f5207b7SJohn Levon {
1510*1f5207b7SJohn Levon 	struct storage *addr = x86_address_gen(expr->unop);
1511*1f5207b7SJohn Levon 	struct storage *retval;
1512*1f5207b7SJohn Levon 	char opname[16];
1513*1f5207b7SJohn Levon 
1514*1f5207b7SJohn Levon 	strcpy(opname, opbits(expr->op == SPECIAL_INCREMENT ? "inc" : "dec",
1515*1f5207b7SJohn Levon 			      expr->ctype->bit_size));
1516*1f5207b7SJohn Levon 
1517*1f5207b7SJohn Levon 	if (postop) {
1518*1f5207b7SJohn Levon 		struct storage *new = stack_alloc(4);
1519*1f5207b7SJohn Levon 
1520*1f5207b7SJohn Levon 		emit_copy(new, addr, expr->unop->ctype);
1521*1f5207b7SJohn Levon 
1522*1f5207b7SJohn Levon 		retval = new;
1523*1f5207b7SJohn Levon 	} else
1524*1f5207b7SJohn Levon 		retval = addr;
1525*1f5207b7SJohn Levon 
1526*1f5207b7SJohn Levon 	insn(opname, addr, NULL, NULL);
1527*1f5207b7SJohn Levon 
1528*1f5207b7SJohn Levon 	return retval;
1529*1f5207b7SJohn Levon }
1530*1f5207b7SJohn Levon 
1531*1f5207b7SJohn Levon static struct storage *emit_postop(struct expression *expr)
1532*1f5207b7SJohn Levon {
1533*1f5207b7SJohn Levon 	return emit_inc_dec(expr, 1);
1534*1f5207b7SJohn Levon }
1535*1f5207b7SJohn Levon 
1536*1f5207b7SJohn Levon static struct storage *emit_return_stmt(struct statement *stmt)
1537*1f5207b7SJohn Levon {
1538*1f5207b7SJohn Levon 	struct function *f = current_func;
1539*1f5207b7SJohn Levon 	struct expression *expr = stmt->ret_value;
1540*1f5207b7SJohn Levon 	struct storage *val = NULL, *jmplbl;
1541*1f5207b7SJohn Levon 
1542*1f5207b7SJohn Levon 	if (expr && expr->ctype) {
1543*1f5207b7SJohn Levon 		val = x86_expression(expr);
1544*1f5207b7SJohn Levon 		assert(val != NULL);
1545*1f5207b7SJohn Levon 		emit_move(val, REG_EAX, expr->ctype, "return");
1546*1f5207b7SJohn Levon 	}
1547*1f5207b7SJohn Levon 
1548*1f5207b7SJohn Levon 	jmplbl = new_storage(STOR_LABEL);
1549*1f5207b7SJohn Levon 	jmplbl->flags |= STOR_WANTS_FREE;
1550*1f5207b7SJohn Levon 	jmplbl->label = f->ret_target;
1551*1f5207b7SJohn Levon 	insn("jmp", jmplbl, NULL, NULL);
1552*1f5207b7SJohn Levon 
1553*1f5207b7SJohn Levon 	return val;
1554*1f5207b7SJohn Levon }
1555*1f5207b7SJohn Levon 
1556*1f5207b7SJohn Levon static struct storage *emit_conditional_expr(struct expression *expr)
1557*1f5207b7SJohn Levon {
1558*1f5207b7SJohn Levon 	struct storage *cond, *true = NULL, *false = NULL;
1559*1f5207b7SJohn Levon 	struct storage *new = stack_alloc(expr->ctype->bit_size / 8);
1560*1f5207b7SJohn Levon 	int target_false, cond_end;
1561*1f5207b7SJohn Levon 
1562*1f5207b7SJohn Levon 	/* evaluate conditional */
1563*1f5207b7SJohn Levon 	cond = x86_expression(expr->conditional);
1564*1f5207b7SJohn Levon 	target_false = emit_conditional_test(cond);
1565*1f5207b7SJohn Levon 
1566*1f5207b7SJohn Levon 	/* handle if-true part of the expression */
1567*1f5207b7SJohn Levon 	true = x86_expression(expr->cond_true);
1568*1f5207b7SJohn Levon 
1569*1f5207b7SJohn Levon 	emit_copy(new, true, expr->ctype);
1570*1f5207b7SJohn Levon 
1571*1f5207b7SJohn Levon 	cond_end = emit_conditional_end(target_false);
1572*1f5207b7SJohn Levon 
1573*1f5207b7SJohn Levon 	/* handle if-false part of the expression */
1574*1f5207b7SJohn Levon 	false = x86_expression(expr->cond_false);
1575*1f5207b7SJohn Levon 
1576*1f5207b7SJohn Levon 	emit_copy(new, false, expr->ctype);
1577*1f5207b7SJohn Levon 
1578*1f5207b7SJohn Levon 	/* end of conditional; jump target for if-true branch */
1579*1f5207b7SJohn Levon 	emit_label(cond_end, "end conditional");
1580*1f5207b7SJohn Levon 
1581*1f5207b7SJohn Levon 	return new;
1582*1f5207b7SJohn Levon }
1583*1f5207b7SJohn Levon 
1584*1f5207b7SJohn Levon static struct storage *emit_select_expr(struct expression *expr)
1585*1f5207b7SJohn Levon {
1586*1f5207b7SJohn Levon 	struct storage *cond = x86_expression(expr->conditional);
1587*1f5207b7SJohn Levon 	struct storage *true = x86_expression(expr->cond_true);
1588*1f5207b7SJohn Levon 	struct storage *false = x86_expression(expr->cond_false);
1589*1f5207b7SJohn Levon 	struct storage *reg_cond, *reg_true, *reg_false;
1590*1f5207b7SJohn Levon 	struct storage *new = stack_alloc(4);
1591*1f5207b7SJohn Levon 
1592*1f5207b7SJohn Levon 	emit_comment("begin SELECT");
1593*1f5207b7SJohn Levon 	reg_cond = get_reg_value(cond, get_regclass(expr->conditional));
1594*1f5207b7SJohn Levon 	reg_true = get_reg_value(true, get_regclass(expr));
1595*1f5207b7SJohn Levon 	reg_false = get_reg_value(false, get_regclass(expr));
1596*1f5207b7SJohn Levon 
1597*1f5207b7SJohn Levon 	/*
1598*1f5207b7SJohn Levon 	 * Do the actual select: check the conditional for zero,
1599*1f5207b7SJohn Levon 	 * move false over true if zero
1600*1f5207b7SJohn Levon 	 */
1601*1f5207b7SJohn Levon 	insn("test", reg_cond, reg_cond, NULL);
1602*1f5207b7SJohn Levon 	insn("cmovz", reg_false, reg_true, NULL);
1603*1f5207b7SJohn Levon 
1604*1f5207b7SJohn Levon 	/* Store it back */
1605*1f5207b7SJohn Levon 	emit_move(reg_true, new, expr->ctype, NULL);
1606*1f5207b7SJohn Levon 	put_reg(reg_cond);
1607*1f5207b7SJohn Levon 	put_reg(reg_true);
1608*1f5207b7SJohn Levon 	put_reg(reg_false);
1609*1f5207b7SJohn Levon 	emit_comment("end SELECT");
1610*1f5207b7SJohn Levon 	return new;
1611*1f5207b7SJohn Levon }
1612*1f5207b7SJohn Levon 
1613*1f5207b7SJohn Levon static struct storage *emit_symbol_expr_init(struct symbol *sym)
1614*1f5207b7SJohn Levon {
1615*1f5207b7SJohn Levon 	struct expression *expr = sym->initializer;
1616*1f5207b7SJohn Levon 	struct symbol_private *priv = sym->aux;
1617*1f5207b7SJohn Levon 
1618*1f5207b7SJohn Levon 	if (priv == NULL) {
1619*1f5207b7SJohn Levon 		priv = calloc(1, sizeof(*priv));
1620*1f5207b7SJohn Levon 		sym->aux = priv;
1621*1f5207b7SJohn Levon 
1622*1f5207b7SJohn Levon 		if (expr == NULL) {
1623*1f5207b7SJohn Levon 			struct storage *new = stack_alloc(4);
1624*1f5207b7SJohn Levon 			fprintf(stderr, "FIXME! no value for symbol %s.  creating pseudo %d (stack offset %d)\n",
1625*1f5207b7SJohn Levon 				show_ident(sym->ident),
1626*1f5207b7SJohn Levon 				new->pseudo, new->pseudo * 4);
1627*1f5207b7SJohn Levon 			priv->addr = new;
1628*1f5207b7SJohn Levon 		} else {
1629*1f5207b7SJohn Levon 			priv->addr = x86_expression(expr);
1630*1f5207b7SJohn Levon 		}
1631*1f5207b7SJohn Levon 	}
1632*1f5207b7SJohn Levon 
1633*1f5207b7SJohn Levon 	return priv->addr;
1634*1f5207b7SJohn Levon }
1635*1f5207b7SJohn Levon 
1636*1f5207b7SJohn Levon static struct storage *emit_string_expr(struct expression *expr)
1637*1f5207b7SJohn Levon {
1638*1f5207b7SJohn Levon 	struct function *f = current_func;
1639*1f5207b7SJohn Levon 	int label = new_label();
1640*1f5207b7SJohn Levon 	struct storage *new;
1641*1f5207b7SJohn Levon 
1642*1f5207b7SJohn Levon 	push_cstring(f, expr->string, label);
1643*1f5207b7SJohn Levon 
1644*1f5207b7SJohn Levon 	new = new_storage(STOR_LABEL);
1645*1f5207b7SJohn Levon 	new->label = label;
1646*1f5207b7SJohn Levon 	new->flags = STOR_LABEL_VAL | STOR_WANTS_FREE;
1647*1f5207b7SJohn Levon 	return new;
1648*1f5207b7SJohn Levon }
1649*1f5207b7SJohn Levon 
1650*1f5207b7SJohn Levon static struct storage *emit_cast_expr(struct expression *expr)
1651*1f5207b7SJohn Levon {
1652*1f5207b7SJohn Levon 	struct symbol *old_type, *new_type;
1653*1f5207b7SJohn Levon 	struct storage *op = x86_expression(expr->cast_expression);
1654*1f5207b7SJohn Levon 	int oldbits, newbits;
1655*1f5207b7SJohn Levon 	struct storage *new;
1656*1f5207b7SJohn Levon 
1657*1f5207b7SJohn Levon 	old_type = expr->cast_expression->ctype;
1658*1f5207b7SJohn Levon 	new_type = expr->cast_type;
1659*1f5207b7SJohn Levon 
1660*1f5207b7SJohn Levon 	oldbits = old_type->bit_size;
1661*1f5207b7SJohn Levon 	newbits = new_type->bit_size;
1662*1f5207b7SJohn Levon 	if (oldbits >= newbits)
1663*1f5207b7SJohn Levon 		return op;
1664*1f5207b7SJohn Levon 
1665*1f5207b7SJohn Levon 	emit_move(op, REG_EAX, old_type, "begin cast ..");
1666*1f5207b7SJohn Levon 
1667*1f5207b7SJohn Levon 	new = stack_alloc(newbits / 8);
1668*1f5207b7SJohn Levon 	emit_move(REG_EAX, new, new_type, ".... end cast");
1669*1f5207b7SJohn Levon 
1670*1f5207b7SJohn Levon 	return new;
1671*1f5207b7SJohn Levon }
1672*1f5207b7SJohn Levon 
1673*1f5207b7SJohn Levon static struct storage *emit_regular_preop(struct expression *expr)
1674*1f5207b7SJohn Levon {
1675*1f5207b7SJohn Levon 	struct storage *target = x86_expression(expr->unop);
1676*1f5207b7SJohn Levon 	struct storage *val, *new = stack_alloc(4);
1677*1f5207b7SJohn Levon 	const char *opname = NULL;
1678*1f5207b7SJohn Levon 
1679*1f5207b7SJohn Levon 	switch (expr->op) {
1680*1f5207b7SJohn Levon 	case '!':
1681*1f5207b7SJohn Levon 		val = new_storage(STOR_VALUE);
1682*1f5207b7SJohn Levon 		val->flags = STOR_WANTS_FREE;
1683*1f5207b7SJohn Levon 		emit_move(val, REG_EDX, NULL, NULL);
1684*1f5207b7SJohn Levon 		emit_move(target, REG_EAX, expr->unop->ctype, NULL);
1685*1f5207b7SJohn Levon 		insn("test", REG_EAX, REG_EAX, NULL);
1686*1f5207b7SJohn Levon 		insn("setz", REG_DL, NULL, NULL);
1687*1f5207b7SJohn Levon 		emit_move(REG_EDX, new, expr->unop->ctype, NULL);
1688*1f5207b7SJohn Levon 
1689*1f5207b7SJohn Levon 		break;
1690*1f5207b7SJohn Levon 	case '~':
1691*1f5207b7SJohn Levon 		opname = "not";
1692*1f5207b7SJohn Levon 	case '-':
1693*1f5207b7SJohn Levon 		if (!opname)
1694*1f5207b7SJohn Levon 			opname = "neg";
1695*1f5207b7SJohn Levon 		emit_move(target, REG_EAX, expr->unop->ctype, NULL);
1696*1f5207b7SJohn Levon 		insn(opname, REG_EAX, NULL, NULL);
1697*1f5207b7SJohn Levon 		emit_move(REG_EAX, new, expr->unop->ctype, NULL);
1698*1f5207b7SJohn Levon 		break;
1699*1f5207b7SJohn Levon 	default:
1700*1f5207b7SJohn Levon 		assert(0);
1701*1f5207b7SJohn Levon 		break;
1702*1f5207b7SJohn Levon 	}
1703*1f5207b7SJohn Levon 
1704*1f5207b7SJohn Levon 	return new;
1705*1f5207b7SJohn Levon }
1706*1f5207b7SJohn Levon 
1707*1f5207b7SJohn Levon static void emit_case_statement(struct statement *stmt)
1708*1f5207b7SJohn Levon {
1709*1f5207b7SJohn Levon 	emit_labelsym(stmt->case_label, NULL);
1710*1f5207b7SJohn Levon 	x86_statement(stmt->case_statement);
1711*1f5207b7SJohn Levon }
1712*1f5207b7SJohn Levon 
1713*1f5207b7SJohn Levon static void emit_switch_statement(struct statement *stmt)
1714*1f5207b7SJohn Levon {
1715*1f5207b7SJohn Levon 	struct storage *val = x86_expression(stmt->switch_expression);
1716*1f5207b7SJohn Levon 	struct symbol *sym, *default_sym = NULL;
1717*1f5207b7SJohn Levon 	struct storage *labelsym, *label;
1718*1f5207b7SJohn Levon 	int switch_end = 0;
1719*1f5207b7SJohn Levon 
1720*1f5207b7SJohn Levon 	emit_move(val, REG_EAX, stmt->switch_expression->ctype, "begin case");
1721*1f5207b7SJohn Levon 
1722*1f5207b7SJohn Levon 	/*
1723*1f5207b7SJohn Levon 	 * This is where a _real_ back-end would go through the
1724*1f5207b7SJohn Levon 	 * cases to decide whether to use a lookup table or a
1725*1f5207b7SJohn Levon 	 * series of comparisons etc
1726*1f5207b7SJohn Levon 	 */
1727*1f5207b7SJohn Levon 	FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) {
1728*1f5207b7SJohn Levon 		struct statement *case_stmt = sym->stmt;
1729*1f5207b7SJohn Levon 		struct expression *expr = case_stmt->case_expression;
1730*1f5207b7SJohn Levon 		struct expression *to = case_stmt->case_to;
1731*1f5207b7SJohn Levon 
1732*1f5207b7SJohn Levon 		/* default: */
1733*1f5207b7SJohn Levon 		if (!expr)
1734*1f5207b7SJohn Levon 			default_sym = sym;
1735*1f5207b7SJohn Levon 
1736*1f5207b7SJohn Levon 		/* case NNN: */
1737*1f5207b7SJohn Levon 		else {
1738*1f5207b7SJohn Levon 			struct storage *case_val = new_val(expr->value);
1739*1f5207b7SJohn Levon 
1740*1f5207b7SJohn Levon 			assert (expr->type == EXPR_VALUE);
1741*1f5207b7SJohn Levon 
1742*1f5207b7SJohn Levon 			insn("cmpl", case_val, REG_EAX, NULL);
1743*1f5207b7SJohn Levon 
1744*1f5207b7SJohn Levon 			if (!to) {
1745*1f5207b7SJohn Levon 				labelsym = new_labelsym(sym);
1746*1f5207b7SJohn Levon 				insn("je", labelsym, NULL, NULL);
1747*1f5207b7SJohn Levon 			} else {
1748*1f5207b7SJohn Levon 				int next_test;
1749*1f5207b7SJohn Levon 
1750*1f5207b7SJohn Levon 				label = new_storage(STOR_LABEL);
1751*1f5207b7SJohn Levon 				label->flags |= STOR_WANTS_FREE;
1752*1f5207b7SJohn Levon 				label->label = next_test = new_label();
1753*1f5207b7SJohn Levon 
1754*1f5207b7SJohn Levon 				/* FIXME: signed/unsigned */
1755*1f5207b7SJohn Levon 				insn("jl", label, NULL, NULL);
1756*1f5207b7SJohn Levon 
1757*1f5207b7SJohn Levon 				case_val = new_val(to->value);
1758*1f5207b7SJohn Levon 				insn("cmpl", case_val, REG_EAX, NULL);
1759*1f5207b7SJohn Levon 
1760*1f5207b7SJohn Levon 				/* TODO: implement and use refcounting... */
1761*1f5207b7SJohn Levon 				label = new_storage(STOR_LABEL);
1762*1f5207b7SJohn Levon 				label->flags |= STOR_WANTS_FREE;
1763*1f5207b7SJohn Levon 				label->label = next_test;
1764*1f5207b7SJohn Levon 
1765*1f5207b7SJohn Levon 				/* FIXME: signed/unsigned */
1766*1f5207b7SJohn Levon 				insn("jg", label, NULL, NULL);
1767*1f5207b7SJohn Levon 
1768*1f5207b7SJohn Levon 				labelsym = new_labelsym(sym);
1769*1f5207b7SJohn Levon 				insn("jmp", labelsym, NULL, NULL);
1770*1f5207b7SJohn Levon 
1771*1f5207b7SJohn Levon 				emit_label(next_test, NULL);
1772*1f5207b7SJohn Levon 			}
1773*1f5207b7SJohn Levon 		}
1774*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sym);
1775*1f5207b7SJohn Levon 
1776*1f5207b7SJohn Levon 	if (default_sym) {
1777*1f5207b7SJohn Levon 		labelsym = new_labelsym(default_sym);
1778*1f5207b7SJohn Levon 		insn("jmp", labelsym, NULL, "default");
1779*1f5207b7SJohn Levon 	} else {
1780*1f5207b7SJohn Levon 		label = new_storage(STOR_LABEL);
1781*1f5207b7SJohn Levon 		label->flags |= STOR_WANTS_FREE;
1782*1f5207b7SJohn Levon 		label->label = switch_end = new_label();
1783*1f5207b7SJohn Levon 		insn("jmp", label, NULL, "goto end of switch");
1784*1f5207b7SJohn Levon 	}
1785*1f5207b7SJohn Levon 
1786*1f5207b7SJohn Levon 	x86_statement(stmt->switch_statement);
1787*1f5207b7SJohn Levon 
1788*1f5207b7SJohn Levon 	if (stmt->switch_break->used)
1789*1f5207b7SJohn Levon 		emit_labelsym(stmt->switch_break, NULL);
1790*1f5207b7SJohn Levon 
1791*1f5207b7SJohn Levon 	if (switch_end)
1792*1f5207b7SJohn Levon 		emit_label(switch_end, NULL);
1793*1f5207b7SJohn Levon }
1794*1f5207b7SJohn Levon 
1795*1f5207b7SJohn Levon static void x86_struct_member(struct symbol *sym)
1796*1f5207b7SJohn Levon {
1797*1f5207b7SJohn 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);
1798*1f5207b7SJohn Levon 	printf("\n");
1799*1f5207b7SJohn Levon }
1800*1f5207b7SJohn Levon 
1801*1f5207b7SJohn Levon static void x86_symbol(struct symbol *sym)
1802*1f5207b7SJohn Levon {
1803*1f5207b7SJohn Levon 	struct symbol *type;
1804*1f5207b7SJohn Levon 
1805*1f5207b7SJohn Levon 	if (!sym)
1806*1f5207b7SJohn Levon 		return;
1807*1f5207b7SJohn Levon 
1808*1f5207b7SJohn Levon 	type = sym->ctype.base_type;
1809*1f5207b7SJohn Levon 	if (!type)
1810*1f5207b7SJohn Levon 		return;
1811*1f5207b7SJohn Levon 
1812*1f5207b7SJohn Levon 	/*
1813*1f5207b7SJohn Levon 	 * Show actual implementation information
1814*1f5207b7SJohn Levon 	 */
1815*1f5207b7SJohn Levon 	switch (type->type) {
1816*1f5207b7SJohn Levon 
1817*1f5207b7SJohn Levon 	case SYM_ARRAY:
1818*1f5207b7SJohn Levon 		if (sym->initializer)
1819*1f5207b7SJohn Levon 			emit_array(sym);
1820*1f5207b7SJohn Levon 		else
1821*1f5207b7SJohn Levon 			emit_array_noinit(sym);
1822*1f5207b7SJohn Levon 		break;
1823*1f5207b7SJohn Levon 
1824*1f5207b7SJohn Levon 	case SYM_BASETYPE:
1825*1f5207b7SJohn Levon 		if (sym->initializer) {
1826*1f5207b7SJohn Levon 			emit_object_pre(show_ident(sym->ident),
1827*1f5207b7SJohn Levon 					sym->ctype.modifiers,
1828*1f5207b7SJohn Levon 				        sym->ctype.alignment,
1829*1f5207b7SJohn Levon 					sym->bit_size / 8);
1830*1f5207b7SJohn Levon 			emit_scalar(sym->initializer, sym->bit_size);
1831*1f5207b7SJohn Levon 			stor_sym_init(sym);
1832*1f5207b7SJohn Levon 		} else
1833*1f5207b7SJohn Levon 			emit_scalar_noinit(sym);
1834*1f5207b7SJohn Levon 		break;
1835*1f5207b7SJohn Levon 
1836*1f5207b7SJohn Levon 	case SYM_STRUCT:
1837*1f5207b7SJohn Levon 	case SYM_UNION: {
1838*1f5207b7SJohn Levon 		struct symbol *member;
1839*1f5207b7SJohn Levon 
1840*1f5207b7SJohn Levon 		printf(" {\n");
1841*1f5207b7SJohn Levon 		FOR_EACH_PTR(type->symbol_list, member) {
1842*1f5207b7SJohn Levon 			x86_struct_member(member);
1843*1f5207b7SJohn Levon 		} END_FOR_EACH_PTR(member);
1844*1f5207b7SJohn Levon 		printf("}\n");
1845*1f5207b7SJohn Levon 		break;
1846*1f5207b7SJohn Levon 	}
1847*1f5207b7SJohn Levon 
1848*1f5207b7SJohn Levon 	case SYM_FN: {
1849*1f5207b7SJohn Levon 		struct statement *stmt = type->stmt;
1850*1f5207b7SJohn Levon 		if (stmt) {
1851*1f5207b7SJohn Levon 			emit_func_pre(sym);
1852*1f5207b7SJohn Levon 			x86_statement(stmt);
1853*1f5207b7SJohn Levon 			emit_func_post(sym);
1854*1f5207b7SJohn Levon 		}
1855*1f5207b7SJohn Levon 		break;
1856*1f5207b7SJohn Levon 	}
1857*1f5207b7SJohn Levon 
1858*1f5207b7SJohn Levon 	default:
1859*1f5207b7SJohn Levon 		break;
1860*1f5207b7SJohn Levon 	}
1861*1f5207b7SJohn Levon 
1862*1f5207b7SJohn Levon 	if (sym->initializer && (type->type != SYM_BASETYPE) &&
1863*1f5207b7SJohn Levon 	    (type->type != SYM_ARRAY)) {
1864*1f5207b7SJohn Levon 		printf(" = \n");
1865*1f5207b7SJohn Levon 		x86_expression(sym->initializer);
1866*1f5207b7SJohn Levon 	}
1867*1f5207b7SJohn Levon }
1868*1f5207b7SJohn Levon 
1869*1f5207b7SJohn Levon static void x86_symbol_init(struct symbol *sym);
1870*1f5207b7SJohn Levon 
1871*1f5207b7SJohn Levon static void x86_symbol_decl(struct symbol_list *syms)
1872*1f5207b7SJohn Levon {
1873*1f5207b7SJohn Levon 	struct symbol *sym;
1874*1f5207b7SJohn Levon 	FOR_EACH_PTR(syms, sym) {
1875*1f5207b7SJohn Levon 		x86_symbol_init(sym);
1876*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sym);
1877*1f5207b7SJohn Levon }
1878*1f5207b7SJohn Levon 
1879*1f5207b7SJohn Levon static void loopstk_push(int cont_lbl, int loop_bottom_lbl)
1880*1f5207b7SJohn Levon {
1881*1f5207b7SJohn Levon 	struct function *f = current_func;
1882*1f5207b7SJohn Levon 	struct loop_stack *ls;
1883*1f5207b7SJohn Levon 
1884*1f5207b7SJohn Levon 	ls = malloc(sizeof(*ls));
1885*1f5207b7SJohn Levon 	ls->continue_lbl = cont_lbl;
1886*1f5207b7SJohn Levon 	ls->loop_bottom_lbl = loop_bottom_lbl;
1887*1f5207b7SJohn Levon 	ls->next = f->loop_stack;
1888*1f5207b7SJohn Levon 	f->loop_stack = ls;
1889*1f5207b7SJohn Levon }
1890*1f5207b7SJohn Levon 
1891*1f5207b7SJohn Levon static void loopstk_pop(void)
1892*1f5207b7SJohn Levon {
1893*1f5207b7SJohn Levon 	struct function *f = current_func;
1894*1f5207b7SJohn Levon 	struct loop_stack *ls;
1895*1f5207b7SJohn Levon 
1896*1f5207b7SJohn Levon 	assert(f->loop_stack != NULL);
1897*1f5207b7SJohn Levon 	ls = f->loop_stack;
1898*1f5207b7SJohn Levon 	f->loop_stack = f->loop_stack->next;
1899*1f5207b7SJohn Levon 	free(ls);
1900*1f5207b7SJohn Levon }
1901*1f5207b7SJohn Levon 
1902*1f5207b7SJohn Levon static int loopstk_break(void)
1903*1f5207b7SJohn Levon {
1904*1f5207b7SJohn Levon 	return current_func->loop_stack->loop_bottom_lbl;
1905*1f5207b7SJohn Levon }
1906*1f5207b7SJohn Levon 
1907*1f5207b7SJohn Levon static int loopstk_continue(void)
1908*1f5207b7SJohn Levon {
1909*1f5207b7SJohn Levon 	return current_func->loop_stack->continue_lbl;
1910*1f5207b7SJohn Levon }
1911*1f5207b7SJohn Levon 
1912*1f5207b7SJohn Levon static void emit_loop(struct statement *stmt)
1913*1f5207b7SJohn Levon {
1914*1f5207b7SJohn Levon 	struct statement  *pre_statement = stmt->iterator_pre_statement;
1915*1f5207b7SJohn Levon 	struct expression *pre_condition = stmt->iterator_pre_condition;
1916*1f5207b7SJohn Levon 	struct statement  *statement = stmt->iterator_statement;
1917*1f5207b7SJohn Levon 	struct statement  *post_statement = stmt->iterator_post_statement;
1918*1f5207b7SJohn Levon 	struct expression *post_condition = stmt->iterator_post_condition;
1919*1f5207b7SJohn Levon 	int loop_top = 0, loop_bottom, loop_continue;
1920*1f5207b7SJohn Levon 	int have_bottom = 0;
1921*1f5207b7SJohn Levon 	struct storage *val;
1922*1f5207b7SJohn Levon 
1923*1f5207b7SJohn Levon 	loop_bottom = new_label();
1924*1f5207b7SJohn Levon 	loop_continue = new_label();
1925*1f5207b7SJohn Levon 	loopstk_push(loop_continue, loop_bottom);
1926*1f5207b7SJohn Levon 
1927*1f5207b7SJohn Levon 	x86_symbol_decl(stmt->iterator_syms);
1928*1f5207b7SJohn Levon 	x86_statement(pre_statement);
1929*1f5207b7SJohn Levon 	if (!post_condition || post_condition->type != EXPR_VALUE || post_condition->value) {
1930*1f5207b7SJohn Levon 		loop_top = new_label();
1931*1f5207b7SJohn Levon 		emit_label(loop_top, "loop top");
1932*1f5207b7SJohn Levon 	}
1933*1f5207b7SJohn Levon 	if (pre_condition) {
1934*1f5207b7SJohn Levon 		if (pre_condition->type == EXPR_VALUE) {
1935*1f5207b7SJohn Levon 			if (!pre_condition->value) {
1936*1f5207b7SJohn Levon 				struct storage *lbv;
1937*1f5207b7SJohn Levon 				lbv = new_storage(STOR_LABEL);
1938*1f5207b7SJohn Levon 				lbv->label = loop_bottom;
1939*1f5207b7SJohn Levon 				lbv->flags = STOR_WANTS_FREE;
1940*1f5207b7SJohn Levon 				insn("jmp", lbv, NULL, "go to loop bottom");
1941*1f5207b7SJohn Levon 				have_bottom = 1;
1942*1f5207b7SJohn Levon 			}
1943*1f5207b7SJohn Levon 		} else {
1944*1f5207b7SJohn Levon 			struct storage *lbv = new_storage(STOR_LABEL);
1945*1f5207b7SJohn Levon 			lbv->label = loop_bottom;
1946*1f5207b7SJohn Levon 			lbv->flags = STOR_WANTS_FREE;
1947*1f5207b7SJohn Levon 			have_bottom = 1;
1948*1f5207b7SJohn Levon 
1949*1f5207b7SJohn Levon 			val = x86_expression(pre_condition);
1950*1f5207b7SJohn Levon 
1951*1f5207b7SJohn Levon 			emit_move(val, REG_EAX, NULL, "loop pre condition");
1952*1f5207b7SJohn Levon 			insn("test", REG_EAX, REG_EAX, NULL);
1953*1f5207b7SJohn Levon 			insn("jz", lbv, NULL, NULL);
1954*1f5207b7SJohn Levon 		}
1955*1f5207b7SJohn Levon 	}
1956*1f5207b7SJohn Levon 	x86_statement(statement);
1957*1f5207b7SJohn Levon 	if (stmt->iterator_continue->used)
1958*1f5207b7SJohn Levon 		emit_label(loop_continue, "'continue' iterator");
1959*1f5207b7SJohn Levon 	x86_statement(post_statement);
1960*1f5207b7SJohn Levon 	if (!post_condition) {
1961*1f5207b7SJohn Levon 		struct storage *lbv = new_storage(STOR_LABEL);
1962*1f5207b7SJohn Levon 		lbv->label = loop_top;
1963*1f5207b7SJohn Levon 		lbv->flags = STOR_WANTS_FREE;
1964*1f5207b7SJohn Levon 		insn("jmp", lbv, NULL, "go to loop top");
1965*1f5207b7SJohn Levon 	} else if (post_condition->type == EXPR_VALUE) {
1966*1f5207b7SJohn Levon 		if (post_condition->value) {
1967*1f5207b7SJohn Levon 			struct storage *lbv = new_storage(STOR_LABEL);
1968*1f5207b7SJohn Levon 			lbv->label = loop_top;
1969*1f5207b7SJohn Levon 			lbv->flags = STOR_WANTS_FREE;
1970*1f5207b7SJohn Levon 			insn("jmp", lbv, NULL, "go to loop top");
1971*1f5207b7SJohn Levon 		}
1972*1f5207b7SJohn Levon 	} else {
1973*1f5207b7SJohn Levon 		struct storage *lbv = new_storage(STOR_LABEL);
1974*1f5207b7SJohn Levon 		lbv->label = loop_top;
1975*1f5207b7SJohn Levon 		lbv->flags = STOR_WANTS_FREE;
1976*1f5207b7SJohn Levon 
1977*1f5207b7SJohn Levon 		val = x86_expression(post_condition);
1978*1f5207b7SJohn Levon 
1979*1f5207b7SJohn Levon 		emit_move(val, REG_EAX, NULL, "loop post condition");
1980*1f5207b7SJohn Levon 		insn("test", REG_EAX, REG_EAX, NULL);
1981*1f5207b7SJohn Levon 		insn("jnz", lbv, NULL, NULL);
1982*1f5207b7SJohn Levon 	}
1983*1f5207b7SJohn Levon 	if (have_bottom || stmt->iterator_break->used)
1984*1f5207b7SJohn Levon 		emit_label(loop_bottom, "loop bottom");
1985*1f5207b7SJohn Levon 
1986*1f5207b7SJohn Levon 	loopstk_pop();
1987*1f5207b7SJohn Levon }
1988*1f5207b7SJohn Levon 
1989*1f5207b7SJohn Levon /*
1990*1f5207b7SJohn Levon  * Print out a statement
1991*1f5207b7SJohn Levon  */
1992*1f5207b7SJohn Levon static struct storage *x86_statement(struct statement *stmt)
1993*1f5207b7SJohn Levon {
1994*1f5207b7SJohn Levon 	if (!stmt)
1995*1f5207b7SJohn Levon 		return NULL;
1996*1f5207b7SJohn Levon 	switch (stmt->type) {
1997*1f5207b7SJohn Levon 	default:
1998*1f5207b7SJohn Levon 		return NULL;
1999*1f5207b7SJohn Levon 	case STMT_RETURN:
2000*1f5207b7SJohn Levon 		return emit_return_stmt(stmt);
2001*1f5207b7SJohn Levon 	case STMT_DECLARATION:
2002*1f5207b7SJohn Levon 		x86_symbol_decl(stmt->declaration);
2003*1f5207b7SJohn Levon 		break;
2004*1f5207b7SJohn Levon 	case STMT_COMPOUND: {
2005*1f5207b7SJohn Levon 		struct statement *s;
2006*1f5207b7SJohn Levon 		struct storage *last = NULL;
2007*1f5207b7SJohn Levon 
2008*1f5207b7SJohn Levon 		FOR_EACH_PTR(stmt->stmts, s) {
2009*1f5207b7SJohn Levon 			last = x86_statement(s);
2010*1f5207b7SJohn Levon 		} END_FOR_EACH_PTR(s);
2011*1f5207b7SJohn Levon 
2012*1f5207b7SJohn Levon 		return last;
2013*1f5207b7SJohn Levon 	}
2014*1f5207b7SJohn Levon 
2015*1f5207b7SJohn Levon 	case STMT_EXPRESSION:
2016*1f5207b7SJohn Levon 		return x86_expression(stmt->expression);
2017*1f5207b7SJohn Levon 	case STMT_IF:
2018*1f5207b7SJohn Levon 		emit_if_conditional(stmt);
2019*1f5207b7SJohn Levon 		return NULL;
2020*1f5207b7SJohn Levon 
2021*1f5207b7SJohn Levon 	case STMT_CASE:
2022*1f5207b7SJohn Levon 		emit_case_statement(stmt);
2023*1f5207b7SJohn Levon 		break;
2024*1f5207b7SJohn Levon 	case STMT_SWITCH:
2025*1f5207b7SJohn Levon 		emit_switch_statement(stmt);
2026*1f5207b7SJohn Levon 		break;
2027*1f5207b7SJohn Levon 
2028*1f5207b7SJohn Levon 	case STMT_ITERATOR:
2029*1f5207b7SJohn Levon 		emit_loop(stmt);
2030*1f5207b7SJohn Levon 		break;
2031*1f5207b7SJohn Levon 
2032*1f5207b7SJohn Levon 	case STMT_NONE:
2033*1f5207b7SJohn Levon 		break;
2034*1f5207b7SJohn Levon 
2035*1f5207b7SJohn Levon 	case STMT_LABEL:
2036*1f5207b7SJohn Levon 		printf(".L%p:\n", stmt->label_identifier);
2037*1f5207b7SJohn Levon 		x86_statement(stmt->label_statement);
2038*1f5207b7SJohn Levon 		break;
2039*1f5207b7SJohn Levon 
2040*1f5207b7SJohn Levon 	case STMT_GOTO:
2041*1f5207b7SJohn Levon 		if (stmt->goto_expression) {
2042*1f5207b7SJohn Levon 			struct storage *val = x86_expression(stmt->goto_expression);
2043*1f5207b7SJohn Levon 			printf("\tgoto *v%d\n", val->pseudo);
2044*1f5207b7SJohn Levon 		} else if (!strcmp("break", show_ident(stmt->goto_label->ident))) {
2045*1f5207b7SJohn Levon 			struct storage *lbv = new_storage(STOR_LABEL);
2046*1f5207b7SJohn Levon 			lbv->label = loopstk_break();
2047*1f5207b7SJohn Levon 			lbv->flags = STOR_WANTS_FREE;
2048*1f5207b7SJohn Levon 			insn("jmp", lbv, NULL, "'break'; go to loop bottom");
2049*1f5207b7SJohn Levon 		} else if (!strcmp("continue", show_ident(stmt->goto_label->ident))) {
2050*1f5207b7SJohn Levon 			struct storage *lbv = new_storage(STOR_LABEL);
2051*1f5207b7SJohn Levon 			lbv->label = loopstk_continue();
2052*1f5207b7SJohn Levon 			lbv->flags = STOR_WANTS_FREE;
2053*1f5207b7SJohn Levon 			insn("jmp", lbv, NULL, "'continue'; go to loop top");
2054*1f5207b7SJohn Levon 		} else {
2055*1f5207b7SJohn Levon 			struct storage *labelsym = new_labelsym(stmt->goto_label);
2056*1f5207b7SJohn Levon 			insn("jmp", labelsym, NULL, NULL);
2057*1f5207b7SJohn Levon 		}
2058*1f5207b7SJohn Levon 		break;
2059*1f5207b7SJohn Levon 	case STMT_ASM:
2060*1f5207b7SJohn Levon 		printf("\tasm( .... )\n");
2061*1f5207b7SJohn Levon 		break;
2062*1f5207b7SJohn Levon 	}
2063*1f5207b7SJohn Levon 	return NULL;
2064*1f5207b7SJohn Levon }
2065*1f5207b7SJohn Levon 
2066*1f5207b7SJohn Levon static struct storage *x86_call_expression(struct expression *expr)
2067*1f5207b7SJohn Levon {
2068*1f5207b7SJohn Levon 	struct function *f = current_func;
2069*1f5207b7SJohn Levon 	struct symbol *direct;
2070*1f5207b7SJohn Levon 	struct expression *arg, *fn;
2071*1f5207b7SJohn Levon 	struct storage *retval, *fncall;
2072*1f5207b7SJohn Levon 	int framesize;
2073*1f5207b7SJohn Levon 	char s[64];
2074*1f5207b7SJohn Levon 
2075*1f5207b7SJohn Levon 	if (!expr->ctype) {
2076*1f5207b7SJohn Levon 		warning(expr->pos, "\tcall with no type!");
2077*1f5207b7SJohn Levon 		return NULL;
2078*1f5207b7SJohn Levon 	}
2079*1f5207b7SJohn Levon 
2080*1f5207b7SJohn Levon 	framesize = 0;
2081*1f5207b7SJohn Levon 	FOR_EACH_PTR_REVERSE(expr->args, arg) {
2082*1f5207b7SJohn Levon 		struct storage *new = x86_expression(arg);
2083*1f5207b7SJohn Levon 		int size = arg->ctype->bit_size;
2084*1f5207b7SJohn Levon 
2085*1f5207b7SJohn Levon 		/*
2086*1f5207b7SJohn Levon 		 * FIXME: i386 SysV ABI dictates that values
2087*1f5207b7SJohn Levon 		 * smaller than 32 bits should be placed onto
2088*1f5207b7SJohn Levon 		 * the stack as 32-bit objects.  We should not
2089*1f5207b7SJohn Levon 		 * blindly do a 32-bit push on objects smaller
2090*1f5207b7SJohn Levon 		 * than 32 bits.
2091*1f5207b7SJohn Levon 		 */
2092*1f5207b7SJohn Levon 		if (size < 32)
2093*1f5207b7SJohn Levon 			size = 32;
2094*1f5207b7SJohn Levon 		insn("pushl", new, NULL,
2095*1f5207b7SJohn Levon 		     !framesize ? "begin function call" : NULL);
2096*1f5207b7SJohn Levon 
2097*1f5207b7SJohn Levon 		framesize += bits_to_bytes(size);
2098*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR_REVERSE(arg);
2099*1f5207b7SJohn Levon 
2100*1f5207b7SJohn Levon 	fn = expr->fn;
2101*1f5207b7SJohn Levon 
2102*1f5207b7SJohn Levon 	/* Remove dereference, if any */
2103*1f5207b7SJohn Levon 	direct = NULL;
2104*1f5207b7SJohn Levon 	if (fn->type == EXPR_PREOP) {
2105*1f5207b7SJohn Levon 		if (fn->unop->type == EXPR_SYMBOL) {
2106*1f5207b7SJohn Levon 			struct symbol *sym = fn->unop->symbol;
2107*1f5207b7SJohn Levon 			if (sym->ctype.base_type->type == SYM_FN)
2108*1f5207b7SJohn Levon 				direct = sym;
2109*1f5207b7SJohn Levon 		}
2110*1f5207b7SJohn Levon 	}
2111*1f5207b7SJohn Levon 	if (direct) {
2112*1f5207b7SJohn Levon 		struct storage *direct_stor = new_storage(STOR_SYM);
2113*1f5207b7SJohn Levon 		direct_stor->flags |= STOR_WANTS_FREE;
2114*1f5207b7SJohn Levon 		direct_stor->sym = direct;
2115*1f5207b7SJohn Levon 		insn("call", direct_stor, NULL, NULL);
2116*1f5207b7SJohn Levon 	} else {
2117*1f5207b7SJohn Levon 		fncall = x86_expression(fn);
2118*1f5207b7SJohn Levon 		emit_move(fncall, REG_EAX, fn->ctype, NULL);
2119*1f5207b7SJohn Levon 
2120*1f5207b7SJohn Levon 		strcpy(s, "\tcall\t*%eax\n");
2121*1f5207b7SJohn Levon 		push_text_atom(f, s);
2122*1f5207b7SJohn Levon 	}
2123*1f5207b7SJohn Levon 
2124*1f5207b7SJohn Levon 	/* FIXME: pay attention to BITS_IN_POINTER */
2125*1f5207b7SJohn Levon 	if (framesize) {
2126*1f5207b7SJohn Levon 		struct storage *val = new_storage(STOR_VALUE);
2127*1f5207b7SJohn Levon 		val->value = (long long) framesize;
2128*1f5207b7SJohn Levon 		val->flags = STOR_WANTS_FREE;
2129*1f5207b7SJohn Levon 		insn("addl", val, REG_ESP, NULL);
2130*1f5207b7SJohn Levon 	}
2131*1f5207b7SJohn Levon 
2132*1f5207b7SJohn Levon 	retval = stack_alloc(4);
2133*1f5207b7SJohn Levon 	emit_move(REG_EAX, retval, NULL, "end function call");
2134*1f5207b7SJohn Levon 
2135*1f5207b7SJohn Levon 	return retval;
2136*1f5207b7SJohn Levon }
2137*1f5207b7SJohn Levon 
2138*1f5207b7SJohn Levon static struct storage *x86_address_gen(struct expression *expr)
2139*1f5207b7SJohn Levon {
2140*1f5207b7SJohn Levon 	struct function *f = current_func;
2141*1f5207b7SJohn Levon 	struct storage *addr;
2142*1f5207b7SJohn Levon 	struct storage *new;
2143*1f5207b7SJohn Levon 	char s[32];
2144*1f5207b7SJohn Levon 
2145*1f5207b7SJohn Levon 	addr = x86_expression(expr->unop);
2146*1f5207b7SJohn Levon 	if (expr->unop->type == EXPR_SYMBOL)
2147*1f5207b7SJohn Levon 		return addr;
2148*1f5207b7SJohn Levon 
2149*1f5207b7SJohn Levon 	emit_move(addr, REG_EAX, NULL, "begin deref ..");
2150*1f5207b7SJohn Levon 
2151*1f5207b7SJohn Levon 	/* FIXME: operand size */
2152*1f5207b7SJohn Levon 	strcpy(s, "\tmovl\t(%eax), %ecx\n");
2153*1f5207b7SJohn Levon 	push_text_atom(f, s);
2154*1f5207b7SJohn Levon 
2155*1f5207b7SJohn Levon 	new = stack_alloc(4);
2156*1f5207b7SJohn Levon 	emit_move(REG_ECX, new, NULL, ".... end deref");
2157*1f5207b7SJohn Levon 
2158*1f5207b7SJohn Levon 	return new;
2159*1f5207b7SJohn Levon }
2160*1f5207b7SJohn Levon 
2161*1f5207b7SJohn Levon static struct storage *x86_assignment(struct expression *expr)
2162*1f5207b7SJohn Levon {
2163*1f5207b7SJohn Levon 	struct expression *target = expr->left;
2164*1f5207b7SJohn Levon 	struct storage *val, *addr;
2165*1f5207b7SJohn Levon 
2166*1f5207b7SJohn Levon 	if (!expr->ctype)
2167*1f5207b7SJohn Levon 		return NULL;
2168*1f5207b7SJohn Levon 
2169*1f5207b7SJohn Levon 	val = x86_expression(expr->right);
2170*1f5207b7SJohn Levon 	addr = x86_address_gen(target);
2171*1f5207b7SJohn Levon 
2172*1f5207b7SJohn Levon 	switch (val->type) {
2173*1f5207b7SJohn Levon 	/* copy, where both operands are memory */
2174*1f5207b7SJohn Levon 	case STOR_PSEUDO:
2175*1f5207b7SJohn Levon 	case STOR_ARG:
2176*1f5207b7SJohn Levon 		emit_copy(addr, val, expr->ctype);
2177*1f5207b7SJohn Levon 		break;
2178*1f5207b7SJohn Levon 
2179*1f5207b7SJohn Levon 	/* copy, one or zero operands are memory */
2180*1f5207b7SJohn Levon 	case STOR_REG:
2181*1f5207b7SJohn Levon 	case STOR_SYM:
2182*1f5207b7SJohn Levon 	case STOR_VALUE:
2183*1f5207b7SJohn Levon 	case STOR_LABEL:
2184*1f5207b7SJohn Levon 		emit_move(val, addr, expr->left->ctype, NULL);
2185*1f5207b7SJohn Levon 		break;
2186*1f5207b7SJohn Levon 
2187*1f5207b7SJohn Levon 	case STOR_LABELSYM:
2188*1f5207b7SJohn Levon 		assert(0);
2189*1f5207b7SJohn Levon 		break;
2190*1f5207b7SJohn Levon 	}
2191*1f5207b7SJohn Levon 	return val;
2192*1f5207b7SJohn Levon }
2193*1f5207b7SJohn Levon 
2194*1f5207b7SJohn Levon static int x86_initialization(struct symbol *sym, struct expression *expr)
2195*1f5207b7SJohn Levon {
2196*1f5207b7SJohn Levon 	struct storage *val, *addr;
2197*1f5207b7SJohn Levon 	int bits;
2198*1f5207b7SJohn Levon 
2199*1f5207b7SJohn Levon 	if (!expr->ctype)
2200*1f5207b7SJohn Levon 		return 0;
2201*1f5207b7SJohn Levon 
2202*1f5207b7SJohn Levon 	bits = expr->ctype->bit_size;
2203*1f5207b7SJohn Levon 	val = x86_expression(expr);
2204*1f5207b7SJohn Levon 	addr = x86_symbol_expr(sym);
2205*1f5207b7SJohn Levon 	// FIXME! The "target" expression is for bitfield store information.
2206*1f5207b7SJohn Levon 	// Leave it NULL, which works fine.
2207*1f5207b7SJohn Levon 	emit_store(NULL, addr, val, bits);
2208*1f5207b7SJohn Levon 	return 0;
2209*1f5207b7SJohn Levon }
2210*1f5207b7SJohn Levon 
2211*1f5207b7SJohn Levon static struct storage *x86_access(struct expression *expr)
2212*1f5207b7SJohn Levon {
2213*1f5207b7SJohn Levon 	return x86_address_gen(expr);
2214*1f5207b7SJohn Levon }
2215*1f5207b7SJohn Levon 
2216*1f5207b7SJohn Levon static struct storage *x86_preop(struct expression *expr)
2217*1f5207b7SJohn Levon {
2218*1f5207b7SJohn Levon 	/*
2219*1f5207b7SJohn Levon 	 * '*' is an lvalue access, and is fundamentally different
2220*1f5207b7SJohn Levon 	 * from an arithmetic operation. Maybe it should have an
2221*1f5207b7SJohn Levon 	 * expression type of its own..
2222*1f5207b7SJohn Levon 	 */
2223*1f5207b7SJohn Levon 	if (expr->op == '*')
2224*1f5207b7SJohn Levon 		return x86_access(expr);
2225*1f5207b7SJohn Levon 	if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
2226*1f5207b7SJohn Levon 		return emit_inc_dec(expr, 0);
2227*1f5207b7SJohn Levon 	return emit_regular_preop(expr);
2228*1f5207b7SJohn Levon }
2229*1f5207b7SJohn Levon 
2230*1f5207b7SJohn Levon static struct storage *x86_symbol_expr(struct symbol *sym)
2231*1f5207b7SJohn Levon {
2232*1f5207b7SJohn Levon 	struct storage *new = stack_alloc(4);
2233*1f5207b7SJohn Levon 
2234*1f5207b7SJohn Levon 	if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_EXTERN | MOD_STATIC)) {
2235*1f5207b7SJohn Levon 		printf("\tmovi.%d\t\tv%d,$%s\n", bits_in_pointer, new->pseudo, show_ident(sym->ident));
2236*1f5207b7SJohn Levon 		return new;
2237*1f5207b7SJohn Levon 	}
2238*1f5207b7SJohn Levon 	if (sym->ctype.modifiers & MOD_ADDRESSABLE) {
2239*1f5207b7SJohn Levon 		printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new->pseudo, sym->value);
2240*1f5207b7SJohn Levon 		return new;
2241*1f5207b7SJohn Levon 	}
2242*1f5207b7SJohn Levon 	printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", bits_in_pointer, new->pseudo, show_ident(sym->ident), sym);
2243*1f5207b7SJohn Levon 	return new;
2244*1f5207b7SJohn Levon }
2245*1f5207b7SJohn Levon 
2246*1f5207b7SJohn Levon static void x86_symbol_init(struct symbol *sym)
2247*1f5207b7SJohn Levon {
2248*1f5207b7SJohn Levon 	struct symbol_private *priv = sym->aux;
2249*1f5207b7SJohn Levon 	struct expression *expr = sym->initializer;
2250*1f5207b7SJohn Levon 	struct storage *new;
2251*1f5207b7SJohn Levon 
2252*1f5207b7SJohn Levon 	if (expr)
2253*1f5207b7SJohn Levon 		new = x86_expression(expr);
2254*1f5207b7SJohn Levon 	else
2255*1f5207b7SJohn Levon 		new = stack_alloc(sym->bit_size / 8);
2256*1f5207b7SJohn Levon 
2257*1f5207b7SJohn Levon 	if (!priv) {
2258*1f5207b7SJohn Levon 		priv = calloc(1, sizeof(*priv));
2259*1f5207b7SJohn Levon 		sym->aux = priv;
2260*1f5207b7SJohn Levon 		/* FIXME: leak! we don't free... */
2261*1f5207b7SJohn Levon 		/* (well, we don't free symbols either) */
2262*1f5207b7SJohn Levon 	}
2263*1f5207b7SJohn Levon 
2264*1f5207b7SJohn Levon 	priv->addr = new;
2265*1f5207b7SJohn Levon }
2266*1f5207b7SJohn Levon 
2267*1f5207b7SJohn Levon static int type_is_signed(struct symbol *sym)
2268*1f5207b7SJohn Levon {
2269*1f5207b7SJohn Levon 	if (sym->type == SYM_NODE)
2270*1f5207b7SJohn Levon 		sym = sym->ctype.base_type;
2271*1f5207b7SJohn Levon 	if (sym->type == SYM_PTR)
2272*1f5207b7SJohn Levon 		return 0;
2273*1f5207b7SJohn Levon 	return !(sym->ctype.modifiers & MOD_UNSIGNED);
2274*1f5207b7SJohn Levon }
2275*1f5207b7SJohn Levon 
2276*1f5207b7SJohn Levon static struct storage *x86_label_expr(struct expression *expr)
2277*1f5207b7SJohn Levon {
2278*1f5207b7SJohn Levon 	struct storage *new = stack_alloc(4);
2279*1f5207b7SJohn Levon 	printf("\tmovi.%d\t\tv%d,.L%p\n", bits_in_pointer, new->pseudo, expr->label_symbol);
2280*1f5207b7SJohn Levon 	return new;
2281*1f5207b7SJohn Levon }
2282*1f5207b7SJohn Levon 
2283*1f5207b7SJohn Levon static struct storage *x86_statement_expr(struct expression *expr)
2284*1f5207b7SJohn Levon {
2285*1f5207b7SJohn Levon 	return x86_statement(expr->statement);
2286*1f5207b7SJohn Levon }
2287*1f5207b7SJohn Levon 
2288*1f5207b7SJohn Levon static int x86_position_expr(struct expression *expr, struct symbol *base)
2289*1f5207b7SJohn Levon {
2290*1f5207b7SJohn Levon 	struct storage *new = x86_expression(expr->init_expr);
2291*1f5207b7SJohn Levon 	struct symbol *ctype = expr->init_expr->ctype;
2292*1f5207b7SJohn Levon 
2293*1f5207b7SJohn Levon 	printf("\tinsert v%d at [%d:%d] of %s\n", new->pseudo,
2294*1f5207b7SJohn Levon 		expr->init_offset, ctype->bit_offset,
2295*1f5207b7SJohn Levon 		show_ident(base->ident));
2296*1f5207b7SJohn Levon 	return 0;
2297*1f5207b7SJohn Levon }
2298*1f5207b7SJohn Levon 
2299*1f5207b7SJohn Levon static void x86_initializer_expr(struct expression *expr, struct symbol *ctype)
2300*1f5207b7SJohn Levon {
2301*1f5207b7SJohn Levon 	struct expression *entry;
2302*1f5207b7SJohn Levon 
2303*1f5207b7SJohn Levon 	FOR_EACH_PTR(expr->expr_list, entry) {
2304*1f5207b7SJohn Levon 		// Nested initializers have their positions already
2305*1f5207b7SJohn Levon 		// recursively calculated - just output them too
2306*1f5207b7SJohn Levon 		if (entry->type == EXPR_INITIALIZER) {
2307*1f5207b7SJohn Levon 			x86_initializer_expr(entry, ctype);
2308*1f5207b7SJohn Levon 			continue;
2309*1f5207b7SJohn Levon 		}
2310*1f5207b7SJohn Levon 
2311*1f5207b7SJohn Levon 		// Ignore initializer indexes and identifiers - the
2312*1f5207b7SJohn Levon 		// evaluator has taken them into account
2313*1f5207b7SJohn Levon 		if (entry->type == EXPR_IDENTIFIER || entry->type == EXPR_INDEX)
2314*1f5207b7SJohn Levon 			continue;
2315*1f5207b7SJohn Levon 		if (entry->type == EXPR_POS) {
2316*1f5207b7SJohn Levon 			x86_position_expr(entry, ctype);
2317*1f5207b7SJohn Levon 			continue;
2318*1f5207b7SJohn Levon 		}
2319*1f5207b7SJohn Levon 		x86_initialization(ctype, entry);
2320*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(entry);
2321*1f5207b7SJohn Levon }
2322*1f5207b7SJohn Levon 
2323*1f5207b7SJohn Levon /*
2324*1f5207b7SJohn Levon  * Print out an expression. Return the pseudo that contains the
2325*1f5207b7SJohn Levon  * variable.
2326*1f5207b7SJohn Levon  */
2327*1f5207b7SJohn Levon static struct storage *x86_expression(struct expression *expr)
2328*1f5207b7SJohn Levon {
2329*1f5207b7SJohn Levon 	if (!expr)
2330*1f5207b7SJohn Levon 		return NULL;
2331*1f5207b7SJohn Levon 
2332*1f5207b7SJohn Levon 	if (!expr->ctype) {
2333*1f5207b7SJohn Levon 		struct position *pos = &expr->pos;
2334*1f5207b7SJohn Levon 		printf("\tno type at %s:%d:%d\n",
2335*1f5207b7SJohn Levon 			stream_name(pos->stream),
2336*1f5207b7SJohn Levon 			pos->line, pos->pos);
2337*1f5207b7SJohn Levon 		return NULL;
2338*1f5207b7SJohn Levon 	}
2339*1f5207b7SJohn Levon 
2340*1f5207b7SJohn Levon 	switch (expr->type) {
2341*1f5207b7SJohn Levon 	default:
2342*1f5207b7SJohn Levon 		return NULL;
2343*1f5207b7SJohn Levon 	case EXPR_CALL:
2344*1f5207b7SJohn Levon 		return x86_call_expression(expr);
2345*1f5207b7SJohn Levon 
2346*1f5207b7SJohn Levon 	case EXPR_ASSIGNMENT:
2347*1f5207b7SJohn Levon 		return x86_assignment(expr);
2348*1f5207b7SJohn Levon 
2349*1f5207b7SJohn Levon 	case EXPR_COMPARE:
2350*1f5207b7SJohn Levon 		return emit_compare(expr);
2351*1f5207b7SJohn Levon 	case EXPR_BINOP:
2352*1f5207b7SJohn Levon 	case EXPR_COMMA:
2353*1f5207b7SJohn Levon 	case EXPR_LOGICAL:
2354*1f5207b7SJohn Levon 		return emit_binop(expr);
2355*1f5207b7SJohn Levon 	case EXPR_PREOP:
2356*1f5207b7SJohn Levon 		return x86_preop(expr);
2357*1f5207b7SJohn Levon 	case EXPR_POSTOP:
2358*1f5207b7SJohn Levon 		return emit_postop(expr);
2359*1f5207b7SJohn Levon 	case EXPR_SYMBOL:
2360*1f5207b7SJohn Levon 		return emit_symbol_expr_init(expr->symbol);
2361*1f5207b7SJohn Levon 	case EXPR_DEREF:
2362*1f5207b7SJohn Levon 	case EXPR_SIZEOF:
2363*1f5207b7SJohn Levon 	case EXPR_ALIGNOF:
2364*1f5207b7SJohn Levon 		warning(expr->pos, "invalid expression after evaluation");
2365*1f5207b7SJohn Levon 		return NULL;
2366*1f5207b7SJohn Levon 	case EXPR_CAST:
2367*1f5207b7SJohn Levon 	case EXPR_FORCE_CAST:
2368*1f5207b7SJohn Levon 	case EXPR_IMPLIED_CAST:
2369*1f5207b7SJohn Levon 		return emit_cast_expr(expr);
2370*1f5207b7SJohn Levon 	case EXPR_VALUE:
2371*1f5207b7SJohn Levon 		return emit_value(expr);
2372*1f5207b7SJohn Levon 	case EXPR_STRING:
2373*1f5207b7SJohn Levon 		return emit_string_expr(expr);
2374*1f5207b7SJohn Levon 	case EXPR_INITIALIZER:
2375*1f5207b7SJohn Levon 		x86_initializer_expr(expr, expr->ctype);
2376*1f5207b7SJohn Levon 		return NULL;
2377*1f5207b7SJohn Levon 	case EXPR_SELECT:
2378*1f5207b7SJohn Levon 		return emit_select_expr(expr);
2379*1f5207b7SJohn Levon 	case EXPR_CONDITIONAL:
2380*1f5207b7SJohn Levon 		return emit_conditional_expr(expr);
2381*1f5207b7SJohn Levon 	case EXPR_STATEMENT:
2382*1f5207b7SJohn Levon 		return x86_statement_expr(expr);
2383*1f5207b7SJohn Levon 	case EXPR_LABEL:
2384*1f5207b7SJohn Levon 		return x86_label_expr(expr);
2385*1f5207b7SJohn Levon 
2386*1f5207b7SJohn Levon 	// None of these should exist as direct expressions: they are only
2387*1f5207b7SJohn Levon 	// valid as sub-expressions of initializers.
2388*1f5207b7SJohn Levon 	case EXPR_POS:
2389*1f5207b7SJohn Levon 		warning(expr->pos, "unable to show plain initializer position expression");
2390*1f5207b7SJohn Levon 		return NULL;
2391*1f5207b7SJohn Levon 	case EXPR_IDENTIFIER:
2392*1f5207b7SJohn Levon 		warning(expr->pos, "unable to show identifier expression");
2393*1f5207b7SJohn Levon 		return NULL;
2394*1f5207b7SJohn Levon 	case EXPR_INDEX:
2395*1f5207b7SJohn Levon 		warning(expr->pos, "unable to show index expression");
2396*1f5207b7SJohn Levon 		return NULL;
2397*1f5207b7SJohn Levon 	case EXPR_TYPE:
2398*1f5207b7SJohn Levon 		warning(expr->pos, "unable to show type expression");
2399*1f5207b7SJohn Levon 		return NULL;
2400*1f5207b7SJohn Levon 	case EXPR_FVALUE:
2401*1f5207b7SJohn Levon 		warning(expr->pos, "floating point support is not implemented");
2402*1f5207b7SJohn Levon 		return NULL;
2403*1f5207b7SJohn Levon 	}
2404*1f5207b7SJohn Levon 	return NULL;
2405*1f5207b7SJohn Levon }
2406