11f5207b7SJohn Levon /*
21f5207b7SJohn Levon * sparse/compile-i386.c
31f5207b7SJohn Levon *
41f5207b7SJohn Levon * Copyright (C) 2003 Transmeta Corp.
51f5207b7SJohn Levon * 2003 Linus Torvalds
61f5207b7SJohn Levon * Copyright 2003 Jeff Garzik
71f5207b7SJohn Levon *
81f5207b7SJohn Levon * Permission is hereby granted, free of charge, to any person obtaining a copy
91f5207b7SJohn Levon * of this software and associated documentation files (the "Software"), to deal
101f5207b7SJohn Levon * in the Software without restriction, including without limitation the rights
111f5207b7SJohn Levon * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
121f5207b7SJohn Levon * copies of the Software, and to permit persons to whom the Software is
131f5207b7SJohn Levon * furnished to do so, subject to the following conditions:
141f5207b7SJohn Levon *
151f5207b7SJohn Levon * The above copyright notice and this permission notice shall be included in
161f5207b7SJohn Levon * all copies or substantial portions of the Software.
171f5207b7SJohn Levon *
181f5207b7SJohn Levon * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
191f5207b7SJohn Levon * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
201f5207b7SJohn Levon * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
211f5207b7SJohn Levon * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
221f5207b7SJohn Levon * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
231f5207b7SJohn Levon * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
241f5207b7SJohn Levon * THE SOFTWARE.
251f5207b7SJohn Levon *
261f5207b7SJohn Levon * x86 backend
271f5207b7SJohn Levon *
281f5207b7SJohn Levon * TODO list:
291f5207b7SJohn Levon * in general, any non-32bit SYM_BASETYPE is unlikely to work.
301f5207b7SJohn Levon * complex initializers
311f5207b7SJohn Levon * bitfields
321f5207b7SJohn Levon * global struct/union variables
331f5207b7SJohn Levon * addressing structures, and members of structures (as opposed to
341f5207b7SJohn Levon * scalars) on the stack. Requires smarter stack frame allocation.
351f5207b7SJohn Levon * labels / goto
361f5207b7SJohn Levon * any function argument that isn't 32 bits (or promoted to such)
371f5207b7SJohn Levon * inline asm
381f5207b7SJohn Levon * floating point
391f5207b7SJohn Levon *
401f5207b7SJohn Levon */
411f5207b7SJohn Levon #include <stdarg.h>
421f5207b7SJohn Levon #include <stdlib.h>
431f5207b7SJohn Levon #include <stdio.h>
441f5207b7SJohn Levon #include <string.h>
451f5207b7SJohn Levon #include <ctype.h>
461f5207b7SJohn Levon #include <unistd.h>
471f5207b7SJohn Levon #include <fcntl.h>
481f5207b7SJohn Levon #include <assert.h>
491f5207b7SJohn Levon
501f5207b7SJohn Levon #include "lib.h"
511f5207b7SJohn Levon #include "allocate.h"
521f5207b7SJohn Levon #include "token.h"
531f5207b7SJohn Levon #include "parse.h"
541f5207b7SJohn Levon #include "symbol.h"
551f5207b7SJohn Levon #include "scope.h"
561f5207b7SJohn Levon #include "expression.h"
571f5207b7SJohn Levon #include "target.h"
581f5207b7SJohn Levon #include "compile.h"
591f5207b7SJohn Levon #include "bitmap.h"
601f5207b7SJohn Levon #include "version.h"
611f5207b7SJohn Levon
621f5207b7SJohn Levon struct textbuf {
631f5207b7SJohn Levon unsigned int len; /* does NOT include terminating null */
641f5207b7SJohn Levon char *text;
651f5207b7SJohn Levon struct textbuf *next;
661f5207b7SJohn Levon struct textbuf *prev;
671f5207b7SJohn Levon };
681f5207b7SJohn Levon
691f5207b7SJohn Levon struct loop_stack {
701f5207b7SJohn Levon int continue_lbl;
711f5207b7SJohn Levon int loop_bottom_lbl;
721f5207b7SJohn Levon struct loop_stack *next;
731f5207b7SJohn Levon };
741f5207b7SJohn Levon
751f5207b7SJohn Levon struct atom;
761f5207b7SJohn Levon struct storage;
771f5207b7SJohn Levon DECLARE_PTR_LIST(str_list, struct atom);
781f5207b7SJohn Levon DECLARE_PTR_LIST(atom_list, struct atom);
791f5207b7SJohn Levon DECLARE_PTR_LIST(storage_list, struct storage);
801f5207b7SJohn Levon
811f5207b7SJohn Levon struct function {
821f5207b7SJohn Levon int stack_size;
831f5207b7SJohn Levon int pseudo_nr;
841f5207b7SJohn Levon struct storage_list *pseudo_list;
851f5207b7SJohn Levon struct atom_list *atom_list;
861f5207b7SJohn Levon struct str_list *str_list;
871f5207b7SJohn Levon struct loop_stack *loop_stack;
881f5207b7SJohn Levon struct symbol **argv;
891f5207b7SJohn Levon unsigned int argc;
901f5207b7SJohn Levon int ret_target;
911f5207b7SJohn Levon };
921f5207b7SJohn Levon
931f5207b7SJohn Levon enum storage_type {
941f5207b7SJohn Levon STOR_PSEUDO, /* variable stored on the stack */
951f5207b7SJohn Levon STOR_ARG, /* function argument */
961f5207b7SJohn Levon STOR_SYM, /* a symbol we can directly ref in the asm */
971f5207b7SJohn Levon STOR_REG, /* scratch register */
981f5207b7SJohn Levon STOR_VALUE, /* integer constant */
991f5207b7SJohn Levon STOR_LABEL, /* label / jump target */
1001f5207b7SJohn Levon STOR_LABELSYM, /* label generated from symbol's pointer value */
1011f5207b7SJohn Levon };
1021f5207b7SJohn Levon
1031f5207b7SJohn Levon struct reg_info {
1041f5207b7SJohn Levon const char *name;
1051f5207b7SJohn Levon struct storage *contains;
1061f5207b7SJohn Levon const unsigned char aliases[12];
1071f5207b7SJohn Levon #define own_regno aliases[0]
1081f5207b7SJohn Levon };
1091f5207b7SJohn Levon
1101f5207b7SJohn Levon struct storage {
1111f5207b7SJohn Levon enum storage_type type;
1121f5207b7SJohn Levon unsigned long flags;
1131f5207b7SJohn Levon
1141f5207b7SJohn Levon /* STOR_REG */
1151f5207b7SJohn Levon struct reg_info *reg;
1161f5207b7SJohn Levon struct symbol *ctype;
1171f5207b7SJohn Levon
1181f5207b7SJohn Levon union {
1191f5207b7SJohn Levon /* STOR_PSEUDO */
1201f5207b7SJohn Levon struct {
1211f5207b7SJohn Levon int pseudo;
1221f5207b7SJohn Levon int offset;
1231f5207b7SJohn Levon int size;
1241f5207b7SJohn Levon };
1251f5207b7SJohn Levon /* STOR_ARG */
1261f5207b7SJohn Levon struct {
1271f5207b7SJohn Levon int idx;
1281f5207b7SJohn Levon };
1291f5207b7SJohn Levon /* STOR_SYM */
1301f5207b7SJohn Levon struct {
1311f5207b7SJohn Levon struct symbol *sym;
1321f5207b7SJohn Levon };
1331f5207b7SJohn Levon /* STOR_VALUE */
1341f5207b7SJohn Levon struct {
1351f5207b7SJohn Levon long long value;
1361f5207b7SJohn Levon };
1371f5207b7SJohn Levon /* STOR_LABEL */
1381f5207b7SJohn Levon struct {
1391f5207b7SJohn Levon int label;
1401f5207b7SJohn Levon };
1411f5207b7SJohn Levon /* STOR_LABELSYM */
1421f5207b7SJohn Levon struct {
1431f5207b7SJohn Levon struct symbol *labelsym;
1441f5207b7SJohn Levon };
1451f5207b7SJohn Levon };
1461f5207b7SJohn Levon };
1471f5207b7SJohn Levon
1481f5207b7SJohn Levon enum {
1491f5207b7SJohn Levon STOR_LABEL_VAL = (1 << 0),
1501f5207b7SJohn Levon STOR_WANTS_FREE = (1 << 1),
1511f5207b7SJohn Levon };
1521f5207b7SJohn Levon
1531f5207b7SJohn Levon struct symbol_private {
1541f5207b7SJohn Levon struct storage *addr;
1551f5207b7SJohn Levon };
1561f5207b7SJohn Levon
1571f5207b7SJohn Levon enum atom_type {
1581f5207b7SJohn Levon ATOM_TEXT,
1591f5207b7SJohn Levon ATOM_INSN,
1601f5207b7SJohn Levon ATOM_CSTR,
1611f5207b7SJohn Levon };
1621f5207b7SJohn Levon
1631f5207b7SJohn Levon struct atom {
1641f5207b7SJohn Levon enum atom_type type;
1651f5207b7SJohn Levon union {
1661f5207b7SJohn Levon /* stuff for text */
1671f5207b7SJohn Levon struct {
1681f5207b7SJohn Levon char *text;
1691f5207b7SJohn Levon unsigned int text_len; /* w/o terminating null */
1701f5207b7SJohn Levon };
1711f5207b7SJohn Levon
1721f5207b7SJohn Levon /* stuff for insns */
1731f5207b7SJohn Levon struct {
1741f5207b7SJohn Levon char insn[32];
1751f5207b7SJohn Levon char comment[40];
1761f5207b7SJohn Levon struct storage *op1;
1771f5207b7SJohn Levon struct storage *op2;
1781f5207b7SJohn Levon };
1791f5207b7SJohn Levon
1801f5207b7SJohn Levon /* stuff for C strings */
1811f5207b7SJohn Levon struct {
1821f5207b7SJohn Levon struct string *string;
1831f5207b7SJohn Levon int label;
1841f5207b7SJohn Levon };
1851f5207b7SJohn Levon };
1861f5207b7SJohn Levon };
1871f5207b7SJohn Levon
1881f5207b7SJohn Levon
1891f5207b7SJohn Levon static struct function *current_func = NULL;
1901f5207b7SJohn Levon static struct textbuf *unit_post_text = NULL;
1911f5207b7SJohn Levon static const char *current_section;
1921f5207b7SJohn Levon
1931f5207b7SJohn Levon static void emit_comment(const char * fmt, ...) FORMAT_ATTR(1);
1941f5207b7SJohn Levon static void emit_move(struct storage *src, struct storage *dest,
1951f5207b7SJohn Levon struct symbol *ctype, const char *comment);
1961f5207b7SJohn Levon static struct storage *x86_address_gen(struct expression *expr);
1971f5207b7SJohn Levon static struct storage *x86_symbol_expr(struct symbol *sym);
1981f5207b7SJohn Levon static void x86_symbol(struct symbol *sym);
1991f5207b7SJohn Levon static struct storage *x86_statement(struct statement *stmt);
2001f5207b7SJohn Levon static struct storage *x86_expression(struct expression *expr);
2011f5207b7SJohn Levon
2021f5207b7SJohn Levon enum registers {
2031f5207b7SJohn Levon NOREG,
2041f5207b7SJohn Levon AL, DL, CL, BL, AH, DH, CH, BH, // 8-bit
2051f5207b7SJohn Levon AX, DX, CX, BX, SI, DI, BP, SP, // 16-bit
2061f5207b7SJohn Levon EAX, EDX, ECX, EBX, ESI, EDI, EBP, ESP, // 32-bit
2071f5207b7SJohn Levon EAX_EDX, ECX_EBX, ESI_EDI, // 64-bit
2081f5207b7SJohn Levon };
2091f5207b7SJohn Levon
2101f5207b7SJohn Levon /* This works on regno's, reg_info's and hardreg_storage's */
2111f5207b7SJohn Levon #define byte_reg(reg) ((reg) - 16)
2121f5207b7SJohn Levon #define highbyte_reg(reg) ((reg)-12)
2131f5207b7SJohn Levon #define word_reg(reg) ((reg)-8)
2141f5207b7SJohn Levon
2151f5207b7SJohn Levon #define REGINFO(nr, str, conflicts...) [nr] = { .name = str, .aliases = { nr , conflicts } }
2161f5207b7SJohn Levon
2171f5207b7SJohn Levon static struct reg_info reg_info_table[] = {
2181f5207b7SJohn Levon REGINFO( AL, "%al", AX, EAX, EAX_EDX),
2191f5207b7SJohn Levon REGINFO( DL, "%dl", DX, EDX, EAX_EDX),
2201f5207b7SJohn Levon REGINFO( CL, "%cl", CX, ECX, ECX_EBX),
2211f5207b7SJohn Levon REGINFO( BL, "%bl", BX, EBX, ECX_EBX),
2221f5207b7SJohn Levon REGINFO( AH, "%ah", AX, EAX, EAX_EDX),
2231f5207b7SJohn Levon REGINFO( DH, "%dh", DX, EDX, EAX_EDX),
2241f5207b7SJohn Levon REGINFO( CH, "%ch", CX, ECX, ECX_EBX),
2251f5207b7SJohn Levon REGINFO( BH, "%bh", BX, EBX, ECX_EBX),
2261f5207b7SJohn Levon REGINFO( AX, "%ax", AL, AH, EAX, EAX_EDX),
2271f5207b7SJohn Levon REGINFO( DX, "%dx", DL, DH, EDX, EAX_EDX),
2281f5207b7SJohn Levon REGINFO( CX, "%cx", CL, CH, ECX, ECX_EBX),
2291f5207b7SJohn Levon REGINFO( BX, "%bx", BL, BH, EBX, ECX_EBX),
2301f5207b7SJohn Levon REGINFO( SI, "%si", ESI, ESI_EDI),
2311f5207b7SJohn Levon REGINFO( DI, "%di", EDI, ESI_EDI),
2321f5207b7SJohn Levon REGINFO( BP, "%bp", EBP),
2331f5207b7SJohn Levon REGINFO( SP, "%sp", ESP),
2341f5207b7SJohn Levon REGINFO(EAX, "%eax", AL, AH, AX, EAX_EDX),
2351f5207b7SJohn Levon REGINFO(EDX, "%edx", DL, DH, DX, EAX_EDX),
2361f5207b7SJohn Levon REGINFO(ECX, "%ecx", CL, CH, CX, ECX_EBX),
2371f5207b7SJohn Levon REGINFO(EBX, "%ebx", BL, BH, BX, ECX_EBX),
2381f5207b7SJohn Levon REGINFO(ESI, "%esi", SI, ESI_EDI),
2391f5207b7SJohn Levon REGINFO(EDI, "%edi", DI, ESI_EDI),
2401f5207b7SJohn Levon REGINFO(EBP, "%ebp", BP),
2411f5207b7SJohn Levon REGINFO(ESP, "%esp", SP),
2421f5207b7SJohn Levon REGINFO(EAX_EDX, "%eax:%edx", AL, AH, AX, EAX, DL, DH, DX, EDX),
2431f5207b7SJohn Levon REGINFO(ECX_EBX, "%ecx:%ebx", CL, CH, CX, ECX, BL, BH, BX, EBX),
2441f5207b7SJohn Levon REGINFO(ESI_EDI, "%esi:%edi", SI, ESI, DI, EDI),
2451f5207b7SJohn Levon };
2461f5207b7SJohn Levon
2471f5207b7SJohn Levon #define REGSTORAGE(nr) [nr] = { .type = STOR_REG, .reg = reg_info_table + (nr) }
2481f5207b7SJohn Levon
2491f5207b7SJohn Levon static struct storage hardreg_storage_table[] = {
2501f5207b7SJohn Levon REGSTORAGE(AL), REGSTORAGE(DL), REGSTORAGE(CL), REGSTORAGE(BL),
2511f5207b7SJohn Levon REGSTORAGE(AH), REGSTORAGE(DH), REGSTORAGE(CH), REGSTORAGE(BH),
2521f5207b7SJohn Levon REGSTORAGE(AX), REGSTORAGE(DX), REGSTORAGE(CX), REGSTORAGE(BX),
2531f5207b7SJohn Levon REGSTORAGE(SI), REGSTORAGE(DI), REGSTORAGE(BP), REGSTORAGE(SP),
2541f5207b7SJohn Levon REGSTORAGE(EAX), REGSTORAGE(EDX), REGSTORAGE(ECX), REGSTORAGE(EBX),
2551f5207b7SJohn Levon REGSTORAGE(ESI), REGSTORAGE(EDI), REGSTORAGE(EBP), REGSTORAGE(ESP),
2561f5207b7SJohn Levon REGSTORAGE(EAX_EDX), REGSTORAGE(ECX_EBX), REGSTORAGE(ESI_EDI),
2571f5207b7SJohn Levon };
2581f5207b7SJohn Levon
2591f5207b7SJohn Levon #define REG_EAX (&hardreg_storage_table[EAX])
2601f5207b7SJohn Levon #define REG_ECX (&hardreg_storage_table[ECX])
2611f5207b7SJohn Levon #define REG_EDX (&hardreg_storage_table[EDX])
2621f5207b7SJohn Levon #define REG_ESP (&hardreg_storage_table[ESP])
2631f5207b7SJohn Levon #define REG_DL (&hardreg_storage_table[DL])
2641f5207b7SJohn Levon #define REG_DX (&hardreg_storage_table[DX])
2651f5207b7SJohn Levon #define REG_AL (&hardreg_storage_table[AL])
2661f5207b7SJohn Levon #define REG_AX (&hardreg_storage_table[AX])
2671f5207b7SJohn Levon
2681f5207b7SJohn Levon static DECLARE_BITMAP(regs_in_use, 256);
2691f5207b7SJohn Levon
reginfo_reg(struct reg_info * info)2701f5207b7SJohn Levon static inline struct storage * reginfo_reg(struct reg_info *info)
2711f5207b7SJohn Levon {
2721f5207b7SJohn Levon return hardreg_storage_table + info->own_regno;
2731f5207b7SJohn Levon }
2741f5207b7SJohn Levon
get_hardreg(struct storage * reg,int clear)2751f5207b7SJohn Levon static struct storage * get_hardreg(struct storage *reg, int clear)
2761f5207b7SJohn Levon {
2771f5207b7SJohn Levon struct reg_info *info = reg->reg;
2781f5207b7SJohn Levon const unsigned char *aliases;
2791f5207b7SJohn Levon int regno;
2801f5207b7SJohn Levon
2811f5207b7SJohn Levon aliases = info->aliases;
2821f5207b7SJohn Levon while ((regno = *aliases++) != NOREG) {
2831f5207b7SJohn Levon if (test_bit(regno, regs_in_use))
2841f5207b7SJohn Levon goto busy;
2851f5207b7SJohn Levon if (clear)
2861f5207b7SJohn Levon reg_info_table[regno].contains = NULL;
2871f5207b7SJohn Levon }
2881f5207b7SJohn Levon set_bit(info->own_regno, regs_in_use);
2891f5207b7SJohn Levon return reg;
2901f5207b7SJohn Levon busy:
2911f5207b7SJohn Levon fprintf(stderr, "register %s is busy\n", info->name);
2921f5207b7SJohn Levon if (regno + reg_info_table != info)
2931f5207b7SJohn Levon fprintf(stderr, " conflicts with %s\n", reg_info_table[regno].name);
2941f5207b7SJohn Levon exit(1);
2951f5207b7SJohn Levon }
2961f5207b7SJohn Levon
put_reg(struct storage * reg)2971f5207b7SJohn Levon static void put_reg(struct storage *reg)
2981f5207b7SJohn Levon {
2991f5207b7SJohn Levon struct reg_info *info = reg->reg;
3001f5207b7SJohn Levon int regno = info->own_regno;
3011f5207b7SJohn Levon
3021f5207b7SJohn Levon if (test_and_clear_bit(regno, regs_in_use))
3031f5207b7SJohn Levon return;
3041f5207b7SJohn Levon fprintf(stderr, "freeing already free'd register %s\n", reg_info_table[regno].name);
3051f5207b7SJohn Levon }
3061f5207b7SJohn Levon
3071f5207b7SJohn Levon struct regclass {
3081f5207b7SJohn Levon const char *name;
3091f5207b7SJohn Levon const unsigned char regs[30];
3101f5207b7SJohn Levon };
3111f5207b7SJohn Levon
3121f5207b7SJohn Levon static struct regclass regclass_8 = { "8-bit", { AL, DL, CL, BL, AH, DH, CH, BH }};
3131f5207b7SJohn Levon static struct regclass regclass_16 = { "16-bit", { AX, DX, CX, BX, SI, DI, BP }};
3141f5207b7SJohn Levon static struct regclass regclass_32 = { "32-bit", { EAX, EDX, ECX, EBX, ESI, EDI, EBP }};
3151f5207b7SJohn Levon static struct regclass regclass_64 = { "64-bit", { EAX_EDX, ECX_EBX, ESI_EDI }};
3161f5207b7SJohn Levon
3171f5207b7SJohn Levon static struct regclass regclass_32_8 = { "32-bit bytes", { EAX, EDX, ECX, EBX }};
3181f5207b7SJohn Levon
get_regclass_bits(int bits)3191f5207b7SJohn Levon static struct regclass *get_regclass_bits(int bits)
3201f5207b7SJohn Levon {
3211f5207b7SJohn Levon switch (bits) {
3221f5207b7SJohn Levon case 8: return ®class_8;
3231f5207b7SJohn Levon case 16: return ®class_16;
3241f5207b7SJohn Levon case 64: return ®class_64;
3251f5207b7SJohn Levon default: return ®class_32;
3261f5207b7SJohn Levon }
3271f5207b7SJohn Levon }
3281f5207b7SJohn Levon
get_regclass(struct expression * expr)3291f5207b7SJohn Levon static struct regclass *get_regclass(struct expression *expr)
3301f5207b7SJohn Levon {
3311f5207b7SJohn Levon return get_regclass_bits(expr->ctype->bit_size);
3321f5207b7SJohn Levon }
3331f5207b7SJohn Levon
register_busy(int regno)3341f5207b7SJohn Levon static int register_busy(int regno)
3351f5207b7SJohn Levon {
3361f5207b7SJohn Levon if (!test_bit(regno, regs_in_use)) {
3371f5207b7SJohn Levon struct reg_info *info = reg_info_table + regno;
3381f5207b7SJohn Levon const unsigned char *regs = info->aliases+1;
3391f5207b7SJohn Levon
3401f5207b7SJohn Levon while ((regno = *regs) != NOREG) {
3411f5207b7SJohn Levon regs++;
3421f5207b7SJohn Levon if (test_bit(regno, regs_in_use))
3431f5207b7SJohn Levon goto busy;
3441f5207b7SJohn Levon }
3451f5207b7SJohn Levon return 0;
3461f5207b7SJohn Levon }
3471f5207b7SJohn Levon busy:
3481f5207b7SJohn Levon return 1;
3491f5207b7SJohn Levon }
3501f5207b7SJohn Levon
get_reg(struct regclass * class)3511f5207b7SJohn Levon static struct storage *get_reg(struct regclass *class)
3521f5207b7SJohn Levon {
3531f5207b7SJohn Levon const unsigned char *regs = class->regs;
3541f5207b7SJohn Levon int regno;
3551f5207b7SJohn Levon
3561f5207b7SJohn Levon while ((regno = *regs) != NOREG) {
3571f5207b7SJohn Levon regs++;
3581f5207b7SJohn Levon if (register_busy(regno))
3591f5207b7SJohn Levon continue;
3601f5207b7SJohn Levon return get_hardreg(hardreg_storage_table + regno, 1);
3611f5207b7SJohn Levon }
3621f5207b7SJohn Levon fprintf(stderr, "Ran out of %s registers\n", class->name);
3631f5207b7SJohn Levon exit(1);
3641f5207b7SJohn Levon }
3651f5207b7SJohn Levon
get_reg_value(struct storage * value,struct regclass * class)3661f5207b7SJohn Levon static struct storage *get_reg_value(struct storage *value, struct regclass *class)
3671f5207b7SJohn Levon {
3681f5207b7SJohn Levon struct reg_info *info;
3691f5207b7SJohn Levon struct storage *reg;
3701f5207b7SJohn Levon
3711f5207b7SJohn Levon /* Do we already have it somewhere */
3721f5207b7SJohn Levon info = value->reg;
3731f5207b7SJohn Levon if (info && info->contains == value) {
3741f5207b7SJohn Levon emit_comment("already have register %s", info->name);
3751f5207b7SJohn Levon return get_hardreg(hardreg_storage_table + info->own_regno, 0);
3761f5207b7SJohn Levon }
3771f5207b7SJohn Levon
3781f5207b7SJohn Levon reg = get_reg(class);
3791f5207b7SJohn Levon emit_move(value, reg, value->ctype, "reload register");
3801f5207b7SJohn Levon info = reg->reg;
3811f5207b7SJohn Levon info->contains = value;
3821f5207b7SJohn Levon value->reg = info;
3831f5207b7SJohn Levon return reg;
3841f5207b7SJohn Levon }
3851f5207b7SJohn Levon
temp_from_bits(unsigned int bit_size)3861f5207b7SJohn Levon static struct storage *temp_from_bits(unsigned int bit_size)
3871f5207b7SJohn Levon {
3881f5207b7SJohn Levon return get_reg(get_regclass_bits(bit_size));
3891f5207b7SJohn Levon }
3901f5207b7SJohn Levon
pseudo_offset(struct storage * s)3911f5207b7SJohn Levon static inline unsigned int pseudo_offset(struct storage *s)
3921f5207b7SJohn Levon {
3931f5207b7SJohn Levon if (s->type != STOR_PSEUDO)
3941f5207b7SJohn Levon return 123456; /* intentionally bogus value */
3951f5207b7SJohn Levon
3961f5207b7SJohn Levon return s->offset;
3971f5207b7SJohn Levon }
3981f5207b7SJohn Levon
arg_offset(struct storage * s)3991f5207b7SJohn Levon static inline unsigned int arg_offset(struct storage *s)
4001f5207b7SJohn Levon {
4011f5207b7SJohn Levon if (s->type != STOR_ARG)
4021f5207b7SJohn Levon return 123456; /* intentionally bogus value */
4031f5207b7SJohn Levon
4041f5207b7SJohn Levon /* FIXME: this is wrong wrong wrong */
4051f5207b7SJohn Levon return current_func->stack_size + ((1 + s->idx) * 4);
4061f5207b7SJohn Levon }
4071f5207b7SJohn Levon
pretty_offset(int ofs)4081f5207b7SJohn Levon static const char *pretty_offset(int ofs)
4091f5207b7SJohn Levon {
4101f5207b7SJohn Levon static char esp_buf[64];
4111f5207b7SJohn Levon
4121f5207b7SJohn Levon if (ofs)
4131f5207b7SJohn Levon sprintf(esp_buf, "%d(%%esp)", ofs);
4141f5207b7SJohn Levon else
4151f5207b7SJohn Levon strcpy(esp_buf, "(%esp)");
4161f5207b7SJohn Levon
4171f5207b7SJohn Levon return esp_buf;
4181f5207b7SJohn Levon }
4191f5207b7SJohn Levon
stor_sym_init(struct symbol * sym)4201f5207b7SJohn Levon static void stor_sym_init(struct symbol *sym)
4211f5207b7SJohn Levon {
4221f5207b7SJohn Levon struct storage *stor;
4231f5207b7SJohn Levon struct symbol_private *priv;
4241f5207b7SJohn Levon
4251f5207b7SJohn Levon priv = calloc(1, sizeof(*priv) + sizeof(*stor));
4261f5207b7SJohn Levon if (!priv)
4271f5207b7SJohn Levon die("OOM in stor_sym_init");
4281f5207b7SJohn Levon
4291f5207b7SJohn Levon stor = (struct storage *) (priv + 1);
4301f5207b7SJohn Levon
4311f5207b7SJohn Levon priv->addr = stor;
4321f5207b7SJohn Levon stor->type = STOR_SYM;
4331f5207b7SJohn Levon stor->sym = sym;
4341f5207b7SJohn Levon }
4351f5207b7SJohn Levon
stor_op_name(struct storage * s)4361f5207b7SJohn Levon static const char *stor_op_name(struct storage *s)
4371f5207b7SJohn Levon {
4381f5207b7SJohn Levon static char name[32];
4391f5207b7SJohn Levon
4401f5207b7SJohn Levon switch (s->type) {
4411f5207b7SJohn Levon case STOR_PSEUDO:
4421f5207b7SJohn Levon strcpy(name, pretty_offset((int) pseudo_offset(s)));
4431f5207b7SJohn Levon break;
4441f5207b7SJohn Levon case STOR_ARG:
4451f5207b7SJohn Levon strcpy(name, pretty_offset((int) arg_offset(s)));
4461f5207b7SJohn Levon break;
4471f5207b7SJohn Levon case STOR_SYM:
4481f5207b7SJohn Levon strcpy(name, show_ident(s->sym->ident));
4491f5207b7SJohn Levon break;
4501f5207b7SJohn Levon case STOR_REG:
4511f5207b7SJohn Levon strcpy(name, s->reg->name);
4521f5207b7SJohn Levon break;
4531f5207b7SJohn Levon case STOR_VALUE:
454*c85f09ccSJohn Levon sprintf(name, "$%lld", s->value);
4551f5207b7SJohn Levon break;
4561f5207b7SJohn Levon case STOR_LABEL:
4571f5207b7SJohn Levon sprintf(name, "%s.L%d", s->flags & STOR_LABEL_VAL ? "$" : "",
4581f5207b7SJohn Levon s->label);
4591f5207b7SJohn Levon break;
4601f5207b7SJohn Levon case STOR_LABELSYM:
4611f5207b7SJohn Levon sprintf(name, "%s.LS%p", s->flags & STOR_LABEL_VAL ? "$" : "",
4621f5207b7SJohn Levon s->labelsym);
4631f5207b7SJohn Levon break;
4641f5207b7SJohn Levon }
4651f5207b7SJohn Levon
4661f5207b7SJohn Levon return name;
4671f5207b7SJohn Levon }
4681f5207b7SJohn Levon
new_atom(enum atom_type type)4691f5207b7SJohn Levon static struct atom *new_atom(enum atom_type type)
4701f5207b7SJohn Levon {
4711f5207b7SJohn Levon struct atom *atom;
4721f5207b7SJohn Levon
4731f5207b7SJohn Levon atom = calloc(1, sizeof(*atom)); /* TODO: chunked alloc */
4741f5207b7SJohn Levon if (!atom)
4751f5207b7SJohn Levon die("nuclear OOM");
4761f5207b7SJohn Levon
4771f5207b7SJohn Levon atom->type = type;
4781f5207b7SJohn Levon
4791f5207b7SJohn Levon return atom;
4801f5207b7SJohn Levon }
4811f5207b7SJohn Levon
push_cstring(struct function * f,struct string * str,int label)4821f5207b7SJohn Levon static inline void push_cstring(struct function *f, struct string *str,
4831f5207b7SJohn Levon int label)
4841f5207b7SJohn Levon {
4851f5207b7SJohn Levon struct atom *atom;
4861f5207b7SJohn Levon
4871f5207b7SJohn Levon atom = new_atom(ATOM_CSTR);
4881f5207b7SJohn Levon atom->string = str;
4891f5207b7SJohn Levon atom->label = label;
4901f5207b7SJohn Levon
4911f5207b7SJohn Levon add_ptr_list(&f->str_list, atom); /* note: _not_ atom_list */
4921f5207b7SJohn Levon }
4931f5207b7SJohn Levon
push_atom(struct function * f,struct atom * atom)4941f5207b7SJohn Levon static inline void push_atom(struct function *f, struct atom *atom)
4951f5207b7SJohn Levon {
4961f5207b7SJohn Levon add_ptr_list(&f->atom_list, atom);
4971f5207b7SJohn Levon }
4981f5207b7SJohn Levon
push_text_atom(struct function * f,const char * text)4991f5207b7SJohn Levon static void push_text_atom(struct function *f, const char *text)
5001f5207b7SJohn Levon {
5011f5207b7SJohn Levon struct atom *atom = new_atom(ATOM_TEXT);
5021f5207b7SJohn Levon
5031f5207b7SJohn Levon atom->text = strdup(text);
5041f5207b7SJohn Levon atom->text_len = strlen(text);
5051f5207b7SJohn Levon
5061f5207b7SJohn Levon push_atom(f, atom);
5071f5207b7SJohn Levon }
5081f5207b7SJohn Levon
new_storage(enum storage_type type)5091f5207b7SJohn Levon static struct storage *new_storage(enum storage_type type)
5101f5207b7SJohn Levon {
5111f5207b7SJohn Levon struct storage *stor;
5121f5207b7SJohn Levon
5131f5207b7SJohn Levon stor = calloc(1, sizeof(*stor));
5141f5207b7SJohn Levon if (!stor)
5151f5207b7SJohn Levon die("OOM in new_storage");
5161f5207b7SJohn Levon
5171f5207b7SJohn Levon stor->type = type;
5181f5207b7SJohn Levon
5191f5207b7SJohn Levon return stor;
5201f5207b7SJohn Levon }
5211f5207b7SJohn Levon
stack_alloc(int n_bytes)5221f5207b7SJohn Levon static struct storage *stack_alloc(int n_bytes)
5231f5207b7SJohn Levon {
5241f5207b7SJohn Levon struct function *f = current_func;
5251f5207b7SJohn Levon struct storage *stor;
5261f5207b7SJohn Levon
5271f5207b7SJohn Levon assert(f != NULL);
5281f5207b7SJohn Levon
5291f5207b7SJohn Levon stor = new_storage(STOR_PSEUDO);
5301f5207b7SJohn Levon stor->type = STOR_PSEUDO;
5311f5207b7SJohn Levon stor->pseudo = f->pseudo_nr;
5321f5207b7SJohn Levon stor->offset = f->stack_size; /* FIXME: stack req. natural align */
5331f5207b7SJohn Levon stor->size = n_bytes;
5341f5207b7SJohn Levon f->stack_size += n_bytes;
5351f5207b7SJohn Levon f->pseudo_nr++;
5361f5207b7SJohn Levon
5371f5207b7SJohn Levon add_ptr_list(&f->pseudo_list, stor);
5381f5207b7SJohn Levon
5391f5207b7SJohn Levon return stor;
5401f5207b7SJohn Levon }
5411f5207b7SJohn Levon
new_labelsym(struct symbol * sym)5421f5207b7SJohn Levon static struct storage *new_labelsym(struct symbol *sym)
5431f5207b7SJohn Levon {
5441f5207b7SJohn Levon struct storage *stor;
5451f5207b7SJohn Levon
5461f5207b7SJohn Levon stor = new_storage(STOR_LABELSYM);
5471f5207b7SJohn Levon
5481f5207b7SJohn Levon if (stor) {
5491f5207b7SJohn Levon stor->flags |= STOR_WANTS_FREE;
5501f5207b7SJohn Levon stor->labelsym = sym;
5511f5207b7SJohn Levon }
5521f5207b7SJohn Levon
5531f5207b7SJohn Levon return stor;
5541f5207b7SJohn Levon }
5551f5207b7SJohn Levon
new_val(long long value)5561f5207b7SJohn Levon static struct storage *new_val(long long value)
5571f5207b7SJohn Levon {
5581f5207b7SJohn Levon struct storage *stor;
5591f5207b7SJohn Levon
5601f5207b7SJohn Levon stor = new_storage(STOR_VALUE);
5611f5207b7SJohn Levon
5621f5207b7SJohn Levon if (stor) {
5631f5207b7SJohn Levon stor->flags |= STOR_WANTS_FREE;
5641f5207b7SJohn Levon stor->value = value;
5651f5207b7SJohn Levon }
5661f5207b7SJohn Levon
5671f5207b7SJohn Levon return stor;
5681f5207b7SJohn Levon }
5691f5207b7SJohn Levon
new_label(void)5701f5207b7SJohn Levon static int new_label(void)
5711f5207b7SJohn Levon {
5721f5207b7SJohn Levon static int label = 0;
5731f5207b7SJohn Levon return ++label;
5741f5207b7SJohn Levon }
5751f5207b7SJohn Levon
textbuf_push(struct textbuf ** buf_p,const char * text)5761f5207b7SJohn Levon static void textbuf_push(struct textbuf **buf_p, const char *text)
5771f5207b7SJohn Levon {
5781f5207b7SJohn Levon struct textbuf *tmp, *list = *buf_p;
5791f5207b7SJohn Levon unsigned int text_len = strlen(text);
5801f5207b7SJohn Levon unsigned int alloc_len = text_len + 1 + sizeof(*list);
5811f5207b7SJohn Levon
5821f5207b7SJohn Levon tmp = calloc(1, alloc_len);
5831f5207b7SJohn Levon if (!tmp)
5841f5207b7SJohn Levon die("OOM on textbuf alloc");
5851f5207b7SJohn Levon
5861f5207b7SJohn Levon tmp->text = ((void *) tmp) + sizeof(*tmp);
5871f5207b7SJohn Levon memcpy(tmp->text, text, text_len + 1);
5881f5207b7SJohn Levon tmp->len = text_len;
5891f5207b7SJohn Levon
5901f5207b7SJohn Levon /* add to end of list */
5911f5207b7SJohn Levon if (!list) {
5921f5207b7SJohn Levon list = tmp;
5931f5207b7SJohn Levon tmp->prev = tmp;
5941f5207b7SJohn Levon } else {
5951f5207b7SJohn Levon tmp->prev = list->prev;
5961f5207b7SJohn Levon tmp->prev->next = tmp;
5971f5207b7SJohn Levon list->prev = tmp;
5981f5207b7SJohn Levon }
5991f5207b7SJohn Levon tmp->next = list;
6001f5207b7SJohn Levon
6011f5207b7SJohn Levon *buf_p = list;
6021f5207b7SJohn Levon }
6031f5207b7SJohn Levon
textbuf_emit(struct textbuf ** buf_p)6041f5207b7SJohn Levon static void textbuf_emit(struct textbuf **buf_p)
6051f5207b7SJohn Levon {
6061f5207b7SJohn Levon struct textbuf *tmp, *list = *buf_p;
6071f5207b7SJohn Levon
6081f5207b7SJohn Levon while (list) {
6091f5207b7SJohn Levon tmp = list;
6101f5207b7SJohn Levon if (tmp->next == tmp)
6111f5207b7SJohn Levon list = NULL;
6121f5207b7SJohn Levon else {
6131f5207b7SJohn Levon tmp->prev->next = tmp->next;
6141f5207b7SJohn Levon tmp->next->prev = tmp->prev;
6151f5207b7SJohn Levon list = tmp->next;
6161f5207b7SJohn Levon }
6171f5207b7SJohn Levon
6181f5207b7SJohn Levon fputs(tmp->text, stdout);
6191f5207b7SJohn Levon
6201f5207b7SJohn Levon free(tmp);
6211f5207b7SJohn Levon }
6221f5207b7SJohn Levon
6231f5207b7SJohn Levon *buf_p = list;
6241f5207b7SJohn Levon }
6251f5207b7SJohn Levon
insn(const char * insn,struct storage * op1,struct storage * op2,const char * comment_in)6261f5207b7SJohn Levon static void insn(const char *insn, struct storage *op1, struct storage *op2,
6271f5207b7SJohn Levon const char *comment_in)
6281f5207b7SJohn Levon {
6291f5207b7SJohn Levon struct function *f = current_func;
6301f5207b7SJohn Levon struct atom *atom = new_atom(ATOM_INSN);
6311f5207b7SJohn Levon
6321f5207b7SJohn Levon assert(insn != NULL);
6331f5207b7SJohn Levon
6341f5207b7SJohn Levon strcpy(atom->insn, insn);
6351f5207b7SJohn Levon if (comment_in && (*comment_in))
6361f5207b7SJohn Levon strncpy(atom->comment, comment_in,
6371f5207b7SJohn Levon sizeof(atom->comment) - 1);
6381f5207b7SJohn Levon
6391f5207b7SJohn Levon atom->op1 = op1;
6401f5207b7SJohn Levon atom->op2 = op2;
6411f5207b7SJohn Levon
6421f5207b7SJohn Levon push_atom(f, atom);
6431f5207b7SJohn Levon }
6441f5207b7SJohn Levon
emit_comment(const char * fmt,...)6451f5207b7SJohn Levon static void emit_comment(const char *fmt, ...)
6461f5207b7SJohn Levon {
6471f5207b7SJohn Levon struct function *f = current_func;
6481f5207b7SJohn Levon static char tmpbuf[100] = "\t# ";
6491f5207b7SJohn Levon va_list args;
6501f5207b7SJohn Levon int i;
6511f5207b7SJohn Levon
6521f5207b7SJohn Levon va_start(args, fmt);
6531f5207b7SJohn Levon i = vsnprintf(tmpbuf+3, sizeof(tmpbuf)-4, fmt, args);
6541f5207b7SJohn Levon va_end(args);
6551f5207b7SJohn Levon tmpbuf[i+3] = '\n';
6561f5207b7SJohn Levon tmpbuf[i+4] = '\0';
6571f5207b7SJohn Levon push_text_atom(f, tmpbuf);
6581f5207b7SJohn Levon }
6591f5207b7SJohn Levon
emit_label(int label,const char * comment)6601f5207b7SJohn Levon static void emit_label (int label, const char *comment)
6611f5207b7SJohn Levon {
6621f5207b7SJohn Levon struct function *f = current_func;
6631f5207b7SJohn Levon char s[64];
6641f5207b7SJohn Levon
6651f5207b7SJohn Levon if (!comment)
6661f5207b7SJohn Levon sprintf(s, ".L%d:\n", label);
6671f5207b7SJohn Levon else
6681f5207b7SJohn Levon sprintf(s, ".L%d:\t\t\t\t\t# %s\n", label, comment);
6691f5207b7SJohn Levon
6701f5207b7SJohn Levon push_text_atom(f, s);
6711f5207b7SJohn Levon }
6721f5207b7SJohn Levon
emit_labelsym(struct symbol * sym,const char * comment)6731f5207b7SJohn Levon static void emit_labelsym (struct symbol *sym, const char *comment)
6741f5207b7SJohn Levon {
6751f5207b7SJohn Levon struct function *f = current_func;
6761f5207b7SJohn Levon char s[64];
6771f5207b7SJohn Levon
6781f5207b7SJohn Levon if (!comment)
6791f5207b7SJohn Levon sprintf(s, ".LS%p:\n", sym);
6801f5207b7SJohn Levon else
6811f5207b7SJohn Levon sprintf(s, ".LS%p:\t\t\t\t# %s\n", sym, comment);
6821f5207b7SJohn Levon
6831f5207b7SJohn Levon push_text_atom(f, s);
6841f5207b7SJohn Levon }
6851f5207b7SJohn Levon
emit_unit_begin(const char * basename)6861f5207b7SJohn Levon void emit_unit_begin(const char *basename)
6871f5207b7SJohn Levon {
6881f5207b7SJohn Levon printf("\t.file\t\"%s\"\n", basename);
6891f5207b7SJohn Levon }
6901f5207b7SJohn Levon
emit_unit_end(void)6911f5207b7SJohn Levon void emit_unit_end(void)
6921f5207b7SJohn Levon {
6931f5207b7SJohn Levon textbuf_emit(&unit_post_text);
6941f5207b7SJohn Levon printf("\t.ident\t\"sparse silly x86 backend (version %s)\"\n", SPARSE_VERSION);
6951f5207b7SJohn Levon }
6961f5207b7SJohn Levon
6971f5207b7SJohn Levon /* conditionally switch sections */
emit_section(const char * s)6981f5207b7SJohn Levon static void emit_section(const char *s)
6991f5207b7SJohn Levon {
7001f5207b7SJohn Levon if (s == current_section)
7011f5207b7SJohn Levon return;
7021f5207b7SJohn Levon if (current_section && (!strcmp(s, current_section)))
7031f5207b7SJohn Levon return;
7041f5207b7SJohn Levon
7051f5207b7SJohn Levon printf("\t%s\n", s);
7061f5207b7SJohn Levon current_section = s;
7071f5207b7SJohn Levon }
7081f5207b7SJohn Levon
emit_insn_atom(struct function * f,struct atom * atom)7091f5207b7SJohn Levon static void emit_insn_atom(struct function *f, struct atom *atom)
7101f5207b7SJohn Levon {
7111f5207b7SJohn Levon char s[128];
7121f5207b7SJohn Levon char comment[64];
7131f5207b7SJohn Levon struct storage *op1 = atom->op1;
7141f5207b7SJohn Levon struct storage *op2 = atom->op2;
7151f5207b7SJohn Levon
7161f5207b7SJohn Levon if (atom->comment[0])
7171f5207b7SJohn Levon sprintf(comment, "\t\t# %s", atom->comment);
7181f5207b7SJohn Levon else
7191f5207b7SJohn Levon comment[0] = 0;
7201f5207b7SJohn Levon
7211f5207b7SJohn Levon if (atom->op2) {
7221f5207b7SJohn Levon char tmp[16];
7231f5207b7SJohn Levon strcpy(tmp, stor_op_name(op1));
7241f5207b7SJohn Levon sprintf(s, "\t%s\t%s, %s%s\n",
7251f5207b7SJohn Levon atom->insn, tmp, stor_op_name(op2), comment);
7261f5207b7SJohn Levon } else if (atom->op1)
7271f5207b7SJohn Levon sprintf(s, "\t%s\t%s%s%s\n",
7281f5207b7SJohn Levon atom->insn, stor_op_name(op1),
7291f5207b7SJohn Levon comment[0] ? "\t" : "", comment);
7301f5207b7SJohn Levon else
7311f5207b7SJohn Levon sprintf(s, "\t%s\t%s%s\n",
7321f5207b7SJohn Levon atom->insn,
7331f5207b7SJohn Levon comment[0] ? "\t\t" : "", comment);
7341f5207b7SJohn Levon
7351f5207b7SJohn Levon if (write(STDOUT_FILENO, s, strlen(s)) < 0)
7361f5207b7SJohn Levon die("can't write to stdout");
7371f5207b7SJohn Levon }
7381f5207b7SJohn Levon
emit_atom_list(struct function * f)7391f5207b7SJohn Levon static void emit_atom_list(struct function *f)
7401f5207b7SJohn Levon {
7411f5207b7SJohn Levon struct atom *atom;
7421f5207b7SJohn Levon
7431f5207b7SJohn Levon FOR_EACH_PTR(f->atom_list, atom) {
7441f5207b7SJohn Levon switch (atom->type) {
7451f5207b7SJohn Levon case ATOM_TEXT: {
7461f5207b7SJohn Levon if (write(STDOUT_FILENO, atom->text, atom->text_len) < 0)
7471f5207b7SJohn Levon die("can't write to stdout");
7481f5207b7SJohn Levon break;
7491f5207b7SJohn Levon }
7501f5207b7SJohn Levon case ATOM_INSN:
7511f5207b7SJohn Levon emit_insn_atom(f, atom);
7521f5207b7SJohn Levon break;
7531f5207b7SJohn Levon case ATOM_CSTR:
7541f5207b7SJohn Levon assert(0);
7551f5207b7SJohn Levon break;
7561f5207b7SJohn Levon }
7571f5207b7SJohn Levon } END_FOR_EACH_PTR(atom);
7581f5207b7SJohn Levon }
7591f5207b7SJohn Levon
emit_string_list(struct function * f)7601f5207b7SJohn Levon static void emit_string_list(struct function *f)
7611f5207b7SJohn Levon {
7621f5207b7SJohn Levon struct atom *atom;
7631f5207b7SJohn Levon
7641f5207b7SJohn Levon emit_section(".section\t.rodata");
7651f5207b7SJohn Levon
7661f5207b7SJohn Levon FOR_EACH_PTR(f->str_list, atom) {
7671f5207b7SJohn Levon /* FIXME: escape " in string */
7681f5207b7SJohn Levon printf(".L%d:\n", atom->label);
7691f5207b7SJohn Levon printf("\t.string\t%s\n", show_string(atom->string));
7701f5207b7SJohn Levon
7711f5207b7SJohn Levon free(atom);
7721f5207b7SJohn Levon } END_FOR_EACH_PTR(atom);
7731f5207b7SJohn Levon }
7741f5207b7SJohn Levon
func_cleanup(struct function * f)7751f5207b7SJohn Levon static void func_cleanup(struct function *f)
7761f5207b7SJohn Levon {
7771f5207b7SJohn Levon struct storage *stor;
7781f5207b7SJohn Levon struct atom *atom;
7791f5207b7SJohn Levon
7801f5207b7SJohn Levon FOR_EACH_PTR(f->atom_list, atom) {
7811f5207b7SJohn Levon if ((atom->type == ATOM_TEXT) && (atom->text))
7821f5207b7SJohn Levon free(atom->text);
7831f5207b7SJohn Levon if (atom->op1 && (atom->op1->flags & STOR_WANTS_FREE))
7841f5207b7SJohn Levon free(atom->op1);
7851f5207b7SJohn Levon if (atom->op2 && (atom->op2->flags & STOR_WANTS_FREE))
7861f5207b7SJohn Levon free(atom->op2);
7871f5207b7SJohn Levon free(atom);
7881f5207b7SJohn Levon } END_FOR_EACH_PTR(atom);
7891f5207b7SJohn Levon
7901f5207b7SJohn Levon FOR_EACH_PTR(f->pseudo_list, stor) {
7911f5207b7SJohn Levon free(stor);
7921f5207b7SJohn Levon } END_FOR_EACH_PTR(stor);
7931f5207b7SJohn Levon
7941f5207b7SJohn Levon free_ptr_list(&f->pseudo_list);
7951f5207b7SJohn Levon free(f);
7961f5207b7SJohn Levon }
7971f5207b7SJohn Levon
7981f5207b7SJohn Levon /* function prologue */
emit_func_pre(struct symbol * sym)7991f5207b7SJohn Levon static void emit_func_pre(struct symbol *sym)
8001f5207b7SJohn Levon {
8011f5207b7SJohn Levon struct function *f;
8021f5207b7SJohn Levon struct symbol *arg;
8031f5207b7SJohn Levon unsigned int i, argc = 0, alloc_len;
8041f5207b7SJohn Levon unsigned char *mem;
8051f5207b7SJohn Levon struct symbol_private *privbase;
8061f5207b7SJohn Levon struct storage *storage_base;
8071f5207b7SJohn Levon struct symbol *base_type = sym->ctype.base_type;
8081f5207b7SJohn Levon
8091f5207b7SJohn Levon FOR_EACH_PTR(base_type->arguments, arg) {
8101f5207b7SJohn Levon argc++;
8111f5207b7SJohn Levon } END_FOR_EACH_PTR(arg);
8121f5207b7SJohn Levon
8131f5207b7SJohn Levon alloc_len =
8141f5207b7SJohn Levon sizeof(*f) +
8151f5207b7SJohn Levon (argc * sizeof(struct symbol *)) +
8161f5207b7SJohn Levon (argc * sizeof(struct symbol_private)) +
8171f5207b7SJohn Levon (argc * sizeof(struct storage));
8181f5207b7SJohn Levon mem = calloc(1, alloc_len);
8191f5207b7SJohn Levon if (!mem)
8201f5207b7SJohn Levon die("OOM on func info");
8211f5207b7SJohn Levon
8221f5207b7SJohn Levon f = (struct function *) mem;
8231f5207b7SJohn Levon mem += sizeof(*f);
8241f5207b7SJohn Levon f->argv = (struct symbol **) mem;
8251f5207b7SJohn Levon mem += (argc * sizeof(struct symbol *));
8261f5207b7SJohn Levon privbase = (struct symbol_private *) mem;
8271f5207b7SJohn Levon mem += (argc * sizeof(struct symbol_private));
8281f5207b7SJohn Levon storage_base = (struct storage *) mem;
8291f5207b7SJohn Levon
8301f5207b7SJohn Levon f->argc = argc;
8311f5207b7SJohn Levon f->ret_target = new_label();
8321f5207b7SJohn Levon
8331f5207b7SJohn Levon i = 0;
8341f5207b7SJohn Levon FOR_EACH_PTR(base_type->arguments, arg) {
8351f5207b7SJohn Levon f->argv[i] = arg;
8361f5207b7SJohn Levon arg->aux = &privbase[i];
8371f5207b7SJohn Levon storage_base[i].type = STOR_ARG;
8381f5207b7SJohn Levon storage_base[i].idx = i;
8391f5207b7SJohn Levon privbase[i].addr = &storage_base[i];
8401f5207b7SJohn Levon i++;
8411f5207b7SJohn Levon } END_FOR_EACH_PTR(arg);
8421f5207b7SJohn Levon
8431f5207b7SJohn Levon assert(current_func == NULL);
8441f5207b7SJohn Levon current_func = f;
8451f5207b7SJohn Levon }
8461f5207b7SJohn Levon
8471f5207b7SJohn Levon /* function epilogue */
emit_func_post(struct symbol * sym)8481f5207b7SJohn Levon static void emit_func_post(struct symbol *sym)
8491f5207b7SJohn Levon {
8501f5207b7SJohn Levon const char *name = show_ident(sym->ident);
8511f5207b7SJohn Levon struct function *f = current_func;
8521f5207b7SJohn Levon int stack_size = f->stack_size;
8531f5207b7SJohn Levon
8541f5207b7SJohn Levon if (f->str_list)
8551f5207b7SJohn Levon emit_string_list(f);
8561f5207b7SJohn Levon
8571f5207b7SJohn Levon /* function prologue */
8581f5207b7SJohn Levon emit_section(".text");
8591f5207b7SJohn Levon if ((sym->ctype.modifiers & MOD_STATIC) == 0)
8601f5207b7SJohn Levon printf(".globl %s\n", name);
8611f5207b7SJohn Levon printf("\t.type\t%s, @function\n", name);
8621f5207b7SJohn Levon printf("%s:\n", name);
8631f5207b7SJohn Levon
8641f5207b7SJohn Levon if (stack_size) {
8651f5207b7SJohn Levon char pseudo_const[16];
8661f5207b7SJohn Levon
8671f5207b7SJohn Levon sprintf(pseudo_const, "$%d", stack_size);
8681f5207b7SJohn Levon printf("\tsubl\t%s, %%esp\n", pseudo_const);
8691f5207b7SJohn Levon }
8701f5207b7SJohn Levon
8711f5207b7SJohn Levon /* function epilogue */
8721f5207b7SJohn Levon
8731f5207b7SJohn Levon /* jump target for 'return' statements */
8741f5207b7SJohn Levon emit_label(f->ret_target, NULL);
8751f5207b7SJohn Levon
8761f5207b7SJohn Levon if (stack_size) {
8771f5207b7SJohn Levon struct storage *val;
8781f5207b7SJohn Levon
8791f5207b7SJohn Levon val = new_storage(STOR_VALUE);
8801f5207b7SJohn Levon val->value = (long long) (stack_size);
8811f5207b7SJohn Levon val->flags = STOR_WANTS_FREE;
8821f5207b7SJohn Levon
8831f5207b7SJohn Levon insn("addl", val, REG_ESP, NULL);
8841f5207b7SJohn Levon }
8851f5207b7SJohn Levon
8861f5207b7SJohn Levon insn("ret", NULL, NULL, NULL);
8871f5207b7SJohn Levon
8881f5207b7SJohn Levon /* output everything to stdout */
8891f5207b7SJohn Levon fflush(stdout); /* paranoia; needed? */
8901f5207b7SJohn Levon emit_atom_list(f);
8911f5207b7SJohn Levon
8921f5207b7SJohn Levon /* function footer */
8931f5207b7SJohn Levon name = show_ident(sym->ident);
8941f5207b7SJohn Levon printf("\t.size\t%s, .-%s\n", name, name);
8951f5207b7SJohn Levon
8961f5207b7SJohn Levon func_cleanup(f);
8971f5207b7SJohn Levon current_func = NULL;
8981f5207b7SJohn Levon }
8991f5207b7SJohn Levon
9001f5207b7SJohn Levon /* emit object (a.k.a. variable, a.k.a. data) prologue */
emit_object_pre(const char * name,unsigned long modifiers,unsigned long alignment,unsigned int byte_size)9011f5207b7SJohn Levon static void emit_object_pre(const char *name, unsigned long modifiers,
9021f5207b7SJohn Levon unsigned long alignment, unsigned int byte_size)
9031f5207b7SJohn Levon {
9041f5207b7SJohn Levon if ((modifiers & MOD_STATIC) == 0)
9051f5207b7SJohn Levon printf(".globl %s\n", name);
9061f5207b7SJohn Levon emit_section(".data");
9071f5207b7SJohn Levon if (alignment)
9081f5207b7SJohn Levon printf("\t.align %lu\n", alignment);
9091f5207b7SJohn Levon printf("\t.type\t%s, @object\n", name);
9101f5207b7SJohn Levon printf("\t.size\t%s, %d\n", name, byte_size);
9111f5207b7SJohn Levon printf("%s:\n", name);
9121f5207b7SJohn Levon }
9131f5207b7SJohn Levon
9141f5207b7SJohn Levon /* emit value (only) for an initializer scalar */
emit_scalar(struct expression * expr,unsigned int bit_size)9151f5207b7SJohn Levon static void emit_scalar(struct expression *expr, unsigned int bit_size)
9161f5207b7SJohn Levon {
9171f5207b7SJohn Levon const char *type;
9181f5207b7SJohn Levon long long ll;
9191f5207b7SJohn Levon
9201f5207b7SJohn Levon assert(expr->type == EXPR_VALUE);
9211f5207b7SJohn Levon
9221f5207b7SJohn Levon if (expr->value == 0ULL) {
9231f5207b7SJohn Levon printf("\t.zero\t%d\n", bit_size / 8);
9241f5207b7SJohn Levon return;
9251f5207b7SJohn Levon }
9261f5207b7SJohn Levon
9271f5207b7SJohn Levon ll = (long long) expr->value;
9281f5207b7SJohn Levon
9291f5207b7SJohn Levon switch (bit_size) {
9301f5207b7SJohn Levon case 8: type = "byte"; ll = (char) ll; break;
9311f5207b7SJohn Levon case 16: type = "value"; ll = (short) ll; break;
9321f5207b7SJohn Levon case 32: type = "long"; ll = (int) ll; break;
9331f5207b7SJohn Levon case 64: type = "quad"; break;
9341f5207b7SJohn Levon default: type = NULL; break;
9351f5207b7SJohn Levon }
9361f5207b7SJohn Levon
9371f5207b7SJohn Levon assert(type != NULL);
9381f5207b7SJohn Levon
939*c85f09ccSJohn Levon printf("\t.%s\t%lld\n", type, ll);
9401f5207b7SJohn Levon }
9411f5207b7SJohn Levon
emit_global_noinit(const char * name,unsigned long modifiers,unsigned long alignment,unsigned int byte_size)9421f5207b7SJohn Levon static void emit_global_noinit(const char *name, unsigned long modifiers,
9431f5207b7SJohn Levon unsigned long alignment, unsigned int byte_size)
9441f5207b7SJohn Levon {
9451f5207b7SJohn Levon char s[64];
9461f5207b7SJohn Levon
9471f5207b7SJohn Levon if (modifiers & MOD_STATIC) {
9481f5207b7SJohn Levon sprintf(s, "\t.local\t%s\n", name);
9491f5207b7SJohn Levon textbuf_push(&unit_post_text, s);
9501f5207b7SJohn Levon }
9511f5207b7SJohn Levon if (alignment)
9521f5207b7SJohn Levon sprintf(s, "\t.comm\t%s,%d,%lu\n", name, byte_size, alignment);
9531f5207b7SJohn Levon else
9541f5207b7SJohn Levon sprintf(s, "\t.comm\t%s,%d\n", name, byte_size);
9551f5207b7SJohn Levon textbuf_push(&unit_post_text, s);
9561f5207b7SJohn Levon }
9571f5207b7SJohn Levon
9581f5207b7SJohn Levon static int ea_current, ea_last;
9591f5207b7SJohn Levon
emit_initializer(struct symbol * sym,struct expression * expr)9601f5207b7SJohn Levon static void emit_initializer(struct symbol *sym,
9611f5207b7SJohn Levon struct expression *expr)
9621f5207b7SJohn Levon {
9631f5207b7SJohn Levon int distance = ea_current - ea_last - 1;
9641f5207b7SJohn Levon
9651f5207b7SJohn Levon if (distance > 0)
9661f5207b7SJohn Levon printf("\t.zero\t%d\n", (sym->bit_size / 8) * distance);
9671f5207b7SJohn Levon
9681f5207b7SJohn Levon if (expr->type == EXPR_VALUE) {
9691f5207b7SJohn Levon struct symbol *base_type = sym->ctype.base_type;
9701f5207b7SJohn Levon assert(base_type != NULL);
9711f5207b7SJohn Levon
9721f5207b7SJohn Levon emit_scalar(expr, sym->bit_size / get_expression_value(base_type->array_size));
9731f5207b7SJohn Levon return;
9741f5207b7SJohn Levon }
9751f5207b7SJohn Levon if (expr->type != EXPR_INITIALIZER)
9761f5207b7SJohn Levon return;
9771f5207b7SJohn Levon
9781f5207b7SJohn Levon assert(0); /* FIXME */
9791f5207b7SJohn Levon }
9801f5207b7SJohn Levon
sort_array_cmp(const struct expression * a,const struct expression * b)9811f5207b7SJohn Levon static int sort_array_cmp(const struct expression *a,
9821f5207b7SJohn Levon const struct expression *b)
9831f5207b7SJohn Levon {
9841f5207b7SJohn Levon int a_ofs = 0, b_ofs = 0;
9851f5207b7SJohn Levon
9861f5207b7SJohn Levon if (a->type == EXPR_POS)
9871f5207b7SJohn Levon a_ofs = (int) a->init_offset;
9881f5207b7SJohn Levon if (b->type == EXPR_POS)
9891f5207b7SJohn Levon b_ofs = (int) b->init_offset;
9901f5207b7SJohn Levon
9911f5207b7SJohn Levon return a_ofs - b_ofs;
9921f5207b7SJohn Levon }
9931f5207b7SJohn Levon
9941f5207b7SJohn Levon /* move to front-end? */
sort_array(struct expression * expr)9951f5207b7SJohn Levon static void sort_array(struct expression *expr)
9961f5207b7SJohn Levon {
9971f5207b7SJohn Levon struct expression *entry, **list;
9981f5207b7SJohn Levon unsigned int elem, sorted, i;
9991f5207b7SJohn Levon
10001f5207b7SJohn Levon elem = expression_list_size(expr->expr_list);
10011f5207b7SJohn Levon if (!elem)
10021f5207b7SJohn Levon return;
10031f5207b7SJohn Levon
10041f5207b7SJohn Levon list = malloc(sizeof(entry) * elem);
10051f5207b7SJohn Levon if (!list)
10061f5207b7SJohn Levon die("OOM in sort_array");
10071f5207b7SJohn Levon
10081f5207b7SJohn Levon /* this code is no doubt evil and ignores EXPR_INDEX possibly
10091f5207b7SJohn Levon * to its detriment and other nasty things. improvements
10101f5207b7SJohn Levon * welcome.
10111f5207b7SJohn Levon */
10121f5207b7SJohn Levon i = 0;
10131f5207b7SJohn Levon sorted = 0;
10141f5207b7SJohn Levon FOR_EACH_PTR(expr->expr_list, entry) {
10151f5207b7SJohn Levon if ((entry->type == EXPR_POS) || (entry->type == EXPR_VALUE)) {
10161f5207b7SJohn Levon /* add entry to list[], in sorted order */
10171f5207b7SJohn Levon if (sorted == 0) {
10181f5207b7SJohn Levon list[0] = entry;
10191f5207b7SJohn Levon sorted = 1;
10201f5207b7SJohn Levon } else {
10211f5207b7SJohn Levon for (i = 0; i < sorted; i++)
10221f5207b7SJohn Levon if (sort_array_cmp(entry, list[i]) <= 0)
10231f5207b7SJohn Levon break;
10241f5207b7SJohn Levon
10251f5207b7SJohn Levon /* If inserting into the middle of list[]
10261f5207b7SJohn Levon * instead of appending, we memmove.
10271f5207b7SJohn Levon * This is ugly, but thankfully
10281f5207b7SJohn Levon * uncommon. Input data with tons of
10291f5207b7SJohn Levon * entries very rarely have explicit
10301f5207b7SJohn Levon * offsets. convert to qsort eventually...
10311f5207b7SJohn Levon */
10321f5207b7SJohn Levon if (i != sorted)
10331f5207b7SJohn Levon memmove(&list[i + 1], &list[i],
10341f5207b7SJohn Levon (sorted - i) * sizeof(entry));
10351f5207b7SJohn Levon list[i] = entry;
10361f5207b7SJohn Levon sorted++;
10371f5207b7SJohn Levon }
10381f5207b7SJohn Levon }
10391f5207b7SJohn Levon } END_FOR_EACH_PTR(entry);
10401f5207b7SJohn Levon
10411f5207b7SJohn Levon i = 0;
10421f5207b7SJohn Levon FOR_EACH_PTR(expr->expr_list, entry) {
10431f5207b7SJohn Levon if ((entry->type == EXPR_POS) || (entry->type == EXPR_VALUE))
10441f5207b7SJohn Levon *THIS_ADDRESS(entry) = list[i++];
10451f5207b7SJohn Levon } END_FOR_EACH_PTR(entry);
10461f5207b7SJohn Levon
10471f5207b7SJohn Levon free(list);
10481f5207b7SJohn Levon }
10491f5207b7SJohn Levon
emit_array(struct symbol * sym)10501f5207b7SJohn Levon static void emit_array(struct symbol *sym)
10511f5207b7SJohn Levon {
10521f5207b7SJohn Levon struct symbol *base_type = sym->ctype.base_type;
10531f5207b7SJohn Levon struct expression *expr = sym->initializer;
10541f5207b7SJohn Levon struct expression *entry;
10551f5207b7SJohn Levon
10561f5207b7SJohn Levon assert(base_type != NULL);
10571f5207b7SJohn Levon
10581f5207b7SJohn Levon stor_sym_init(sym);
10591f5207b7SJohn Levon
10601f5207b7SJohn Levon ea_last = -1;
10611f5207b7SJohn Levon
10621f5207b7SJohn Levon emit_object_pre(show_ident(sym->ident), sym->ctype.modifiers,
10631f5207b7SJohn Levon sym->ctype.alignment,
10641f5207b7SJohn Levon sym->bit_size / 8);
10651f5207b7SJohn Levon
10661f5207b7SJohn Levon sort_array(expr);
10671f5207b7SJohn Levon
10681f5207b7SJohn Levon FOR_EACH_PTR(expr->expr_list, entry) {
10691f5207b7SJohn Levon if (entry->type == EXPR_VALUE) {
10701f5207b7SJohn Levon ea_current = 0;
10711f5207b7SJohn Levon emit_initializer(sym, entry);
10721f5207b7SJohn Levon ea_last = ea_current;
10731f5207b7SJohn Levon } else if (entry->type == EXPR_POS) {
10741f5207b7SJohn Levon ea_current =
10751f5207b7SJohn Levon entry->init_offset / (base_type->bit_size / 8);
10761f5207b7SJohn Levon emit_initializer(sym, entry->init_expr);
10771f5207b7SJohn Levon ea_last = ea_current;
10781f5207b7SJohn Levon }
10791f5207b7SJohn Levon } END_FOR_EACH_PTR(entry);
10801f5207b7SJohn Levon }
10811f5207b7SJohn Levon
emit_one_symbol(struct symbol * sym)10821f5207b7SJohn Levon void emit_one_symbol(struct symbol *sym)
10831f5207b7SJohn Levon {
10841f5207b7SJohn Levon x86_symbol(sym);
10851f5207b7SJohn Levon }
10861f5207b7SJohn Levon
emit_copy(struct storage * dest,struct storage * src,struct symbol * ctype)10871f5207b7SJohn Levon static void emit_copy(struct storage *dest, struct storage *src,
10881f5207b7SJohn Levon struct symbol *ctype)
10891f5207b7SJohn Levon {
10901f5207b7SJohn Levon struct storage *reg = NULL;
10911f5207b7SJohn Levon unsigned int bit_size;
10921f5207b7SJohn Levon
10931f5207b7SJohn Levon /* FIXME: Bitfield copy! */
10941f5207b7SJohn Levon
10951f5207b7SJohn Levon bit_size = src->size * 8;
10961f5207b7SJohn Levon if (!bit_size)
10971f5207b7SJohn Levon bit_size = 32;
10981f5207b7SJohn Levon if ((src->type == STOR_ARG) && (bit_size < 32))
10991f5207b7SJohn Levon bit_size = 32;
11001f5207b7SJohn Levon
11011f5207b7SJohn Levon reg = temp_from_bits(bit_size);
11021f5207b7SJohn Levon emit_move(src, reg, ctype, "begin copy ..");
11031f5207b7SJohn Levon
11041f5207b7SJohn Levon bit_size = dest->size * 8;
11051f5207b7SJohn Levon if (!bit_size)
11061f5207b7SJohn Levon bit_size = 32;
11071f5207b7SJohn Levon if ((dest->type == STOR_ARG) && (bit_size < 32))
11081f5207b7SJohn Levon bit_size = 32;
11091f5207b7SJohn Levon
11101f5207b7SJohn Levon emit_move(reg, dest, ctype, ".... end copy");
11111f5207b7SJohn Levon put_reg(reg);
11121f5207b7SJohn Levon }
11131f5207b7SJohn Levon
emit_store(struct expression * dest_expr,struct storage * dest,struct storage * src,int bits)11141f5207b7SJohn Levon static void emit_store(struct expression *dest_expr, struct storage *dest,
11151f5207b7SJohn Levon struct storage *src, int bits)
11161f5207b7SJohn Levon {
11171f5207b7SJohn Levon /* FIXME: Bitfield store! */
11181f5207b7SJohn Levon printf("\tst.%d\t\tv%d,[v%d]\n", bits, src->pseudo, dest->pseudo);
11191f5207b7SJohn Levon }
11201f5207b7SJohn Levon
emit_scalar_noinit(struct symbol * sym)11211f5207b7SJohn Levon static void emit_scalar_noinit(struct symbol *sym)
11221f5207b7SJohn Levon {
11231f5207b7SJohn Levon emit_global_noinit(show_ident(sym->ident),
11241f5207b7SJohn Levon sym->ctype.modifiers, sym->ctype.alignment,
11251f5207b7SJohn Levon sym->bit_size / 8);
11261f5207b7SJohn Levon stor_sym_init(sym);
11271f5207b7SJohn Levon }
11281f5207b7SJohn Levon
emit_array_noinit(struct symbol * sym)11291f5207b7SJohn Levon static void emit_array_noinit(struct symbol *sym)
11301f5207b7SJohn Levon {
11311f5207b7SJohn Levon emit_global_noinit(show_ident(sym->ident),
11321f5207b7SJohn Levon sym->ctype.modifiers, sym->ctype.alignment,
11331f5207b7SJohn Levon get_expression_value(sym->array_size) * (sym->bit_size / 8));
11341f5207b7SJohn Levon stor_sym_init(sym);
11351f5207b7SJohn Levon }
11361f5207b7SJohn Levon
opbits(const char * insn,unsigned int bits)11371f5207b7SJohn Levon static const char *opbits(const char *insn, unsigned int bits)
11381f5207b7SJohn Levon {
11391f5207b7SJohn Levon static char opbits_str[32];
11401f5207b7SJohn Levon char c;
11411f5207b7SJohn Levon
11421f5207b7SJohn Levon switch (bits) {
11431f5207b7SJohn Levon case 8: c = 'b'; break;
11441f5207b7SJohn Levon case 16: c = 'w'; break;
11451f5207b7SJohn Levon case 32: c = 'l'; break;
11461f5207b7SJohn Levon case 64: c = 'q'; break;
11471f5207b7SJohn Levon default: abort(); break;
11481f5207b7SJohn Levon }
11491f5207b7SJohn Levon
11501f5207b7SJohn Levon sprintf(opbits_str, "%s%c", insn, c);
11511f5207b7SJohn Levon
11521f5207b7SJohn Levon return opbits_str;
11531f5207b7SJohn Levon }
11541f5207b7SJohn Levon
emit_move(struct storage * src,struct storage * dest,struct symbol * ctype,const char * comment)11551f5207b7SJohn Levon static void emit_move(struct storage *src, struct storage *dest,
11561f5207b7SJohn Levon struct symbol *ctype, const char *comment)
11571f5207b7SJohn Levon {
11581f5207b7SJohn Levon unsigned int bits;
11591f5207b7SJohn Levon unsigned int is_signed;
11601f5207b7SJohn Levon unsigned int is_dest = (src->type == STOR_REG);
11611f5207b7SJohn Levon const char *opname;
11621f5207b7SJohn Levon
11631f5207b7SJohn Levon if (ctype) {
11641f5207b7SJohn Levon bits = ctype->bit_size;
1165*c85f09ccSJohn Levon is_signed = is_signed_type(ctype);
11661f5207b7SJohn Levon } else {
11671f5207b7SJohn Levon bits = 32;
11681f5207b7SJohn Levon is_signed = 0;
11691f5207b7SJohn Levon }
11701f5207b7SJohn Levon
11711f5207b7SJohn Levon /*
11721f5207b7SJohn Levon * Are we moving from a register to a register?
11731f5207b7SJohn Levon * Make the new reg to be the "cache".
11741f5207b7SJohn Levon */
11751f5207b7SJohn Levon if ((dest->type == STOR_REG) && (src->type == STOR_REG)) {
11761f5207b7SJohn Levon struct storage *backing;
11771f5207b7SJohn Levon
11781f5207b7SJohn Levon reg_reg_move:
11791f5207b7SJohn Levon if (dest == src)
11801f5207b7SJohn Levon return;
11811f5207b7SJohn Levon
11821f5207b7SJohn Levon backing = src->reg->contains;
11831f5207b7SJohn Levon if (backing) {
11841f5207b7SJohn Levon /* Is it still valid? */
11851f5207b7SJohn Levon if (backing->reg != src->reg)
11861f5207b7SJohn Levon backing = NULL;
11871f5207b7SJohn Levon else
11881f5207b7SJohn Levon backing->reg = dest->reg;
11891f5207b7SJohn Levon }
11901f5207b7SJohn Levon dest->reg->contains = backing;
11911f5207b7SJohn Levon insn("mov", src, dest, NULL);
11921f5207b7SJohn Levon return;
11931f5207b7SJohn Levon }
11941f5207b7SJohn Levon
11951f5207b7SJohn Levon /*
11961f5207b7SJohn Levon * Are we moving to a register from a non-reg?
11971f5207b7SJohn Levon *
11981f5207b7SJohn Levon * See if we have the non-reg source already cached
11991f5207b7SJohn Levon * in a register..
12001f5207b7SJohn Levon */
12011f5207b7SJohn Levon if (dest->type == STOR_REG) {
12021f5207b7SJohn Levon if (src->reg) {
12031f5207b7SJohn Levon struct reg_info *info = src->reg;
12041f5207b7SJohn Levon if (info->contains == src) {
12051f5207b7SJohn Levon src = reginfo_reg(info);
12061f5207b7SJohn Levon goto reg_reg_move;
12071f5207b7SJohn Levon }
12081f5207b7SJohn Levon }
12091f5207b7SJohn Levon dest->reg->contains = src;
12101f5207b7SJohn Levon src->reg = dest->reg;
12111f5207b7SJohn Levon }
12121f5207b7SJohn Levon
12131f5207b7SJohn Levon if (src->type == STOR_REG) {
12141f5207b7SJohn Levon /* We could just mark the register dirty here and do lazy store.. */
12151f5207b7SJohn Levon src->reg->contains = dest;
12161f5207b7SJohn Levon dest->reg = src->reg;
12171f5207b7SJohn Levon }
12181f5207b7SJohn Levon
12191f5207b7SJohn Levon if ((bits == 8) || (bits == 16)) {
12201f5207b7SJohn Levon if (is_dest)
12211f5207b7SJohn Levon opname = "mov";
12221f5207b7SJohn Levon else
12231f5207b7SJohn Levon opname = is_signed ? "movsx" : "movzx";
12241f5207b7SJohn Levon } else
12251f5207b7SJohn Levon opname = "mov";
12261f5207b7SJohn Levon
12271f5207b7SJohn Levon insn(opbits(opname, bits), src, dest, comment);
12281f5207b7SJohn Levon }
12291f5207b7SJohn Levon
emit_compare(struct expression * expr)12301f5207b7SJohn Levon static struct storage *emit_compare(struct expression *expr)
12311f5207b7SJohn Levon {
12321f5207b7SJohn Levon struct storage *left = x86_expression(expr->left);
12331f5207b7SJohn Levon struct storage *right = x86_expression(expr->right);
12341f5207b7SJohn Levon struct storage *reg1, *reg2;
12351f5207b7SJohn Levon struct storage *new, *val;
12361f5207b7SJohn Levon const char *opname = NULL;
12371f5207b7SJohn Levon unsigned int right_bits = expr->right->ctype->bit_size;
12381f5207b7SJohn Levon
12391f5207b7SJohn Levon switch(expr->op) {
12401f5207b7SJohn Levon case '<': opname = "setl"; break;
12411f5207b7SJohn Levon case '>': opname = "setg"; break;
12421f5207b7SJohn Levon case SPECIAL_LTE:
12431f5207b7SJohn Levon opname = "setle"; break;
12441f5207b7SJohn Levon case SPECIAL_GTE:
12451f5207b7SJohn Levon opname = "setge"; break;
12461f5207b7SJohn Levon case SPECIAL_EQUAL: opname = "sete"; break;
12471f5207b7SJohn Levon case SPECIAL_NOTEQUAL: opname = "setne"; break;
12481f5207b7SJohn Levon case SPECIAL_UNSIGNED_LT:
12491f5207b7SJohn Levon opname = "setb"; break;
12501f5207b7SJohn Levon case SPECIAL_UNSIGNED_GT:
12511f5207b7SJohn Levon opname = "seta"; break;
12521f5207b7SJohn Levon case SPECIAL_UNSIGNED_LTE:
12531f5207b7SJohn Levon opname = "setb"; break;
12541f5207b7SJohn Levon case SPECIAL_UNSIGNED_GTE:
12551f5207b7SJohn Levon opname = "setae"; break;
12561f5207b7SJohn Levon default:
12571f5207b7SJohn Levon assert(0);
12581f5207b7SJohn Levon break;
12591f5207b7SJohn Levon }
12601f5207b7SJohn Levon
12611f5207b7SJohn Levon /* init EDX to 0 */
12621f5207b7SJohn Levon val = new_storage(STOR_VALUE);
12631f5207b7SJohn Levon val->flags = STOR_WANTS_FREE;
12641f5207b7SJohn Levon
12651f5207b7SJohn Levon reg1 = get_reg(®class_32_8);
12661f5207b7SJohn Levon emit_move(val, reg1, NULL, NULL);
12671f5207b7SJohn Levon
12681f5207b7SJohn Levon /* move op1 into EAX */
12691f5207b7SJohn Levon reg2 = get_reg_value(left, get_regclass(expr->left));
12701f5207b7SJohn Levon
12711f5207b7SJohn Levon /* perform comparison, RHS (op1, right) and LHS (op2, EAX) */
12721f5207b7SJohn Levon insn(opbits("cmp", right_bits), right, reg2, NULL);
12731f5207b7SJohn Levon put_reg(reg2);
12741f5207b7SJohn Levon
12751f5207b7SJohn Levon /* store result of operation, 0 or 1, in DL using SETcc */
12761f5207b7SJohn Levon insn(opname, byte_reg(reg1), NULL, NULL);
12771f5207b7SJohn Levon
12781f5207b7SJohn Levon /* finally, store the result (DL) in a new pseudo / stack slot */
12791f5207b7SJohn Levon new = stack_alloc(4);
12801f5207b7SJohn Levon emit_move(reg1, new, NULL, "end EXPR_COMPARE");
12811f5207b7SJohn Levon put_reg(reg1);
12821f5207b7SJohn Levon
12831f5207b7SJohn Levon return new;
12841f5207b7SJohn Levon }
12851f5207b7SJohn Levon
emit_value(struct expression * expr)12861f5207b7SJohn Levon static struct storage *emit_value(struct expression *expr)
12871f5207b7SJohn Levon {
12881f5207b7SJohn Levon #if 0 /* old and slow way */
12891f5207b7SJohn Levon struct storage *new = stack_alloc(4);
12901f5207b7SJohn Levon struct storage *val;
12911f5207b7SJohn Levon
12921f5207b7SJohn Levon val = new_storage(STOR_VALUE);
12931f5207b7SJohn Levon val->value = (long long) expr->value;
12941f5207b7SJohn Levon val->flags = STOR_WANTS_FREE;
12951f5207b7SJohn Levon insn("movl", val, new, NULL);
12961f5207b7SJohn Levon
12971f5207b7SJohn Levon return new;
12981f5207b7SJohn Levon #else
12991f5207b7SJohn Levon struct storage *val;
13001f5207b7SJohn Levon
13011f5207b7SJohn Levon val = new_storage(STOR_VALUE);
13021f5207b7SJohn Levon val->value = (long long) expr->value;
13031f5207b7SJohn Levon
13041f5207b7SJohn Levon return val; /* FIXME: memory leak */
13051f5207b7SJohn Levon #endif
13061f5207b7SJohn Levon }
13071f5207b7SJohn Levon
emit_divide(struct expression * expr,struct storage * left,struct storage * right)13081f5207b7SJohn Levon static struct storage *emit_divide(struct expression *expr, struct storage *left, struct storage *right)
13091f5207b7SJohn Levon {
13101f5207b7SJohn Levon struct storage *eax_edx;
13111f5207b7SJohn Levon struct storage *reg, *new;
13121f5207b7SJohn Levon struct storage *val = new_storage(STOR_VALUE);
13131f5207b7SJohn Levon
13141f5207b7SJohn Levon emit_comment("begin DIVIDE");
13151f5207b7SJohn Levon eax_edx = get_hardreg(hardreg_storage_table + EAX_EDX, 1);
13161f5207b7SJohn Levon
13171f5207b7SJohn Levon /* init EDX to 0 */
13181f5207b7SJohn Levon val->flags = STOR_WANTS_FREE;
13191f5207b7SJohn Levon emit_move(val, REG_EDX, NULL, NULL);
13201f5207b7SJohn Levon
13211f5207b7SJohn Levon new = stack_alloc(expr->ctype->bit_size / 8);
13221f5207b7SJohn Levon
13231f5207b7SJohn Levon /* EAX is dividend */
13241f5207b7SJohn Levon emit_move(left, REG_EAX, NULL, NULL);
13251f5207b7SJohn Levon
13261f5207b7SJohn Levon reg = get_reg_value(right, ®class_32);
13271f5207b7SJohn Levon
13281f5207b7SJohn Levon /* perform binop */
13291f5207b7SJohn Levon insn("div", reg, REG_EAX, NULL);
13301f5207b7SJohn Levon put_reg(reg);
13311f5207b7SJohn Levon
13321f5207b7SJohn Levon reg = REG_EAX;
13331f5207b7SJohn Levon if (expr->op == '%')
13341f5207b7SJohn Levon reg = REG_EDX;
13351f5207b7SJohn Levon emit_move(reg, new, NULL, NULL);
13361f5207b7SJohn Levon
13371f5207b7SJohn Levon put_reg(eax_edx);
13381f5207b7SJohn Levon emit_comment("end DIVIDE");
13391f5207b7SJohn Levon return new;
13401f5207b7SJohn Levon }
13411f5207b7SJohn Levon
emit_binop(struct expression * expr)13421f5207b7SJohn Levon static struct storage *emit_binop(struct expression *expr)
13431f5207b7SJohn Levon {
13441f5207b7SJohn Levon struct storage *left = x86_expression(expr->left);
13451f5207b7SJohn Levon struct storage *right = x86_expression(expr->right);
13461f5207b7SJohn Levon struct storage *new;
13471f5207b7SJohn Levon struct storage *dest, *src;
13481f5207b7SJohn Levon const char *opname = NULL;
13491f5207b7SJohn Levon const char *suffix = NULL;
13501f5207b7SJohn Levon char opstr[16];
13511f5207b7SJohn Levon int is_signed;
13521f5207b7SJohn Levon
13531f5207b7SJohn Levon /* Divides have special register constraints */
13541f5207b7SJohn Levon if ((expr->op == '/') || (expr->op == '%'))
13551f5207b7SJohn Levon return emit_divide(expr, left, right);
13561f5207b7SJohn Levon
1357*c85f09ccSJohn Levon is_signed = is_signed_type(expr->ctype);
13581f5207b7SJohn Levon
13591f5207b7SJohn Levon switch (expr->op) {
13601f5207b7SJohn Levon case '+':
13611f5207b7SJohn Levon opname = "add";
13621f5207b7SJohn Levon break;
13631f5207b7SJohn Levon case '-':
13641f5207b7SJohn Levon opname = "sub";
13651f5207b7SJohn Levon break;
13661f5207b7SJohn Levon case '&':
13671f5207b7SJohn Levon opname = "and";
13681f5207b7SJohn Levon break;
13691f5207b7SJohn Levon case '|':
13701f5207b7SJohn Levon opname = "or";
13711f5207b7SJohn Levon break;
13721f5207b7SJohn Levon case '^':
13731f5207b7SJohn Levon opname = "xor";
13741f5207b7SJohn Levon break;
13751f5207b7SJohn Levon case SPECIAL_LEFTSHIFT:
13761f5207b7SJohn Levon opname = "shl";
13771f5207b7SJohn Levon break;
13781f5207b7SJohn Levon case SPECIAL_RIGHTSHIFT:
13791f5207b7SJohn Levon if (is_signed)
13801f5207b7SJohn Levon opname = "sar";
13811f5207b7SJohn Levon else
13821f5207b7SJohn Levon opname = "shr";
13831f5207b7SJohn Levon break;
13841f5207b7SJohn Levon case '*':
13851f5207b7SJohn Levon if (is_signed)
13861f5207b7SJohn Levon opname = "imul";
13871f5207b7SJohn Levon else
13881f5207b7SJohn Levon opname = "mul";
13891f5207b7SJohn Levon break;
13901f5207b7SJohn Levon case SPECIAL_LOGICAL_AND:
13911f5207b7SJohn Levon warning(expr->pos, "bogus bitwise and for logical op (should use '2*setne + and' or something)");
13921f5207b7SJohn Levon opname = "and";
13931f5207b7SJohn Levon break;
13941f5207b7SJohn Levon case SPECIAL_LOGICAL_OR:
13951f5207b7SJohn Levon warning(expr->pos, "bogus bitwise or for logical op (should use 'or + setne' or something)");
13961f5207b7SJohn Levon opname = "or";
13971f5207b7SJohn Levon break;
13981f5207b7SJohn Levon default:
13991f5207b7SJohn Levon error_die(expr->pos, "unhandled binop '%s'\n", show_special(expr->op));
14001f5207b7SJohn Levon break;
14011f5207b7SJohn Levon }
14021f5207b7SJohn Levon
14031f5207b7SJohn Levon dest = get_reg_value(right, ®class_32);
14041f5207b7SJohn Levon src = get_reg_value(left, ®class_32);
14051f5207b7SJohn Levon switch (expr->ctype->bit_size) {
14061f5207b7SJohn Levon case 8:
14071f5207b7SJohn Levon suffix = "b";
14081f5207b7SJohn Levon break;
14091f5207b7SJohn Levon case 16:
14101f5207b7SJohn Levon suffix = "w";
14111f5207b7SJohn Levon break;
14121f5207b7SJohn Levon case 32:
14131f5207b7SJohn Levon suffix = "l";
14141f5207b7SJohn Levon break;
14151f5207b7SJohn Levon case 64:
14161f5207b7SJohn Levon suffix = "q"; /* FIXME */
14171f5207b7SJohn Levon break;
14181f5207b7SJohn Levon default:
14191f5207b7SJohn Levon assert(0);
14201f5207b7SJohn Levon break;
14211f5207b7SJohn Levon }
14221f5207b7SJohn Levon
14231f5207b7SJohn Levon snprintf(opstr, sizeof(opstr), "%s%s", opname, suffix);
14241f5207b7SJohn Levon
14251f5207b7SJohn Levon /* perform binop */
14261f5207b7SJohn Levon insn(opstr, src, dest, NULL);
14271f5207b7SJohn Levon put_reg(src);
14281f5207b7SJohn Levon
14291f5207b7SJohn Levon /* store result in new pseudo / stack slot */
14301f5207b7SJohn Levon new = stack_alloc(expr->ctype->bit_size / 8);
14311f5207b7SJohn Levon emit_move(dest, new, NULL, "end EXPR_BINOP");
14321f5207b7SJohn Levon
14331f5207b7SJohn Levon put_reg(dest);
14341f5207b7SJohn Levon
14351f5207b7SJohn Levon return new;
14361f5207b7SJohn Levon }
14371f5207b7SJohn Levon
emit_conditional_test(struct storage * val)14381f5207b7SJohn Levon static int emit_conditional_test(struct storage *val)
14391f5207b7SJohn Levon {
14401f5207b7SJohn Levon struct storage *reg;
14411f5207b7SJohn Levon struct storage *target_val;
14421f5207b7SJohn Levon int target_false;
14431f5207b7SJohn Levon
14441f5207b7SJohn Levon /* load result into EAX */
14451f5207b7SJohn Levon emit_comment("begin if/conditional");
14461f5207b7SJohn Levon reg = get_reg_value(val, ®class_32);
14471f5207b7SJohn Levon
14481f5207b7SJohn Levon /* compare result with zero */
14491f5207b7SJohn Levon insn("test", reg, reg, NULL);
14501f5207b7SJohn Levon put_reg(reg);
14511f5207b7SJohn Levon
14521f5207b7SJohn Levon /* create conditional-failed label to jump to */
14531f5207b7SJohn Levon target_false = new_label();
14541f5207b7SJohn Levon target_val = new_storage(STOR_LABEL);
14551f5207b7SJohn Levon target_val->label = target_false;
14561f5207b7SJohn Levon target_val->flags = STOR_WANTS_FREE;
14571f5207b7SJohn Levon insn("jz", target_val, NULL, NULL);
14581f5207b7SJohn Levon
14591f5207b7SJohn Levon return target_false;
14601f5207b7SJohn Levon }
14611f5207b7SJohn Levon
emit_conditional_end(int target_false)14621f5207b7SJohn Levon static int emit_conditional_end(int target_false)
14631f5207b7SJohn Levon {
14641f5207b7SJohn Levon struct storage *cond_end_st;
14651f5207b7SJohn Levon int cond_end;
14661f5207b7SJohn Levon
14671f5207b7SJohn Levon /* finished generating code for if-true statement.
14681f5207b7SJohn Levon * add a jump-to-end jump to avoid falling through
14691f5207b7SJohn Levon * to the if-false statement code.
14701f5207b7SJohn Levon */
14711f5207b7SJohn Levon cond_end = new_label();
14721f5207b7SJohn Levon cond_end_st = new_storage(STOR_LABEL);
14731f5207b7SJohn Levon cond_end_st->label = cond_end;
14741f5207b7SJohn Levon cond_end_st->flags = STOR_WANTS_FREE;
14751f5207b7SJohn Levon insn("jmp", cond_end_st, NULL, NULL);
14761f5207b7SJohn Levon
14771f5207b7SJohn Levon /* if we have both if-true and if-false statements,
14781f5207b7SJohn Levon * the failed-conditional case will fall through to here
14791f5207b7SJohn Levon */
14801f5207b7SJohn Levon emit_label(target_false, NULL);
14811f5207b7SJohn Levon
14821f5207b7SJohn Levon return cond_end;
14831f5207b7SJohn Levon }
14841f5207b7SJohn Levon
emit_if_conditional(struct statement * stmt)14851f5207b7SJohn Levon static void emit_if_conditional(struct statement *stmt)
14861f5207b7SJohn Levon {
14871f5207b7SJohn Levon struct storage *val;
14881f5207b7SJohn Levon int cond_end;
14891f5207b7SJohn Levon
14901f5207b7SJohn Levon /* emit test portion of conditional */
14911f5207b7SJohn Levon val = x86_expression(stmt->if_conditional);
14921f5207b7SJohn Levon cond_end = emit_conditional_test(val);
14931f5207b7SJohn Levon
14941f5207b7SJohn Levon /* emit if-true statement */
14951f5207b7SJohn Levon x86_statement(stmt->if_true);
14961f5207b7SJohn Levon
14971f5207b7SJohn Levon /* emit if-false statement, if present */
14981f5207b7SJohn Levon if (stmt->if_false) {
14991f5207b7SJohn Levon cond_end = emit_conditional_end(cond_end);
15001f5207b7SJohn Levon x86_statement(stmt->if_false);
15011f5207b7SJohn Levon }
15021f5207b7SJohn Levon
15031f5207b7SJohn Levon /* end of conditional; jump target for if-true branch */
15041f5207b7SJohn Levon emit_label(cond_end, "end if");
15051f5207b7SJohn Levon }
15061f5207b7SJohn Levon
emit_inc_dec(struct expression * expr,int postop)15071f5207b7SJohn Levon static struct storage *emit_inc_dec(struct expression *expr, int postop)
15081f5207b7SJohn Levon {
15091f5207b7SJohn Levon struct storage *addr = x86_address_gen(expr->unop);
15101f5207b7SJohn Levon struct storage *retval;
15111f5207b7SJohn Levon char opname[16];
15121f5207b7SJohn Levon
15131f5207b7SJohn Levon strcpy(opname, opbits(expr->op == SPECIAL_INCREMENT ? "inc" : "dec",
15141f5207b7SJohn Levon expr->ctype->bit_size));
15151f5207b7SJohn Levon
15161f5207b7SJohn Levon if (postop) {
15171f5207b7SJohn Levon struct storage *new = stack_alloc(4);
15181f5207b7SJohn Levon
15191f5207b7SJohn Levon emit_copy(new, addr, expr->unop->ctype);
15201f5207b7SJohn Levon
15211f5207b7SJohn Levon retval = new;
15221f5207b7SJohn Levon } else
15231f5207b7SJohn Levon retval = addr;
15241f5207b7SJohn Levon
15251f5207b7SJohn Levon insn(opname, addr, NULL, NULL);
15261f5207b7SJohn Levon
15271f5207b7SJohn Levon return retval;
15281f5207b7SJohn Levon }
15291f5207b7SJohn Levon
emit_postop(struct expression * expr)15301f5207b7SJohn Levon static struct storage *emit_postop(struct expression *expr)
15311f5207b7SJohn Levon {
15321f5207b7SJohn Levon return emit_inc_dec(expr, 1);
15331f5207b7SJohn Levon }
15341f5207b7SJohn Levon
emit_return_stmt(struct statement * stmt)15351f5207b7SJohn Levon static struct storage *emit_return_stmt(struct statement *stmt)
15361f5207b7SJohn Levon {
15371f5207b7SJohn Levon struct function *f = current_func;
15381f5207b7SJohn Levon struct expression *expr = stmt->ret_value;
15391f5207b7SJohn Levon struct storage *val = NULL, *jmplbl;
15401f5207b7SJohn Levon
15411f5207b7SJohn Levon if (expr && expr->ctype) {
15421f5207b7SJohn Levon val = x86_expression(expr);
15431f5207b7SJohn Levon assert(val != NULL);
15441f5207b7SJohn Levon emit_move(val, REG_EAX, expr->ctype, "return");
15451f5207b7SJohn Levon }
15461f5207b7SJohn Levon
15471f5207b7SJohn Levon jmplbl = new_storage(STOR_LABEL);
15481f5207b7SJohn Levon jmplbl->flags |= STOR_WANTS_FREE;
15491f5207b7SJohn Levon jmplbl->label = f->ret_target;
15501f5207b7SJohn Levon insn("jmp", jmplbl, NULL, NULL);
15511f5207b7SJohn Levon
15521f5207b7SJohn Levon return val;
15531f5207b7SJohn Levon }
15541f5207b7SJohn Levon
emit_conditional_expr(struct expression * expr)15551f5207b7SJohn Levon static struct storage *emit_conditional_expr(struct expression *expr)
15561f5207b7SJohn Levon {
1557*c85f09ccSJohn Levon struct storage *cond, *stot = NULL, *stof = NULL;
15581f5207b7SJohn Levon struct storage *new = stack_alloc(expr->ctype->bit_size / 8);
15591f5207b7SJohn Levon int target_false, cond_end;
15601f5207b7SJohn Levon
15611f5207b7SJohn Levon /* evaluate conditional */
15621f5207b7SJohn Levon cond = x86_expression(expr->conditional);
15631f5207b7SJohn Levon target_false = emit_conditional_test(cond);
15641f5207b7SJohn Levon
15651f5207b7SJohn Levon /* handle if-true part of the expression */
1566*c85f09ccSJohn Levon stot = x86_expression(expr->cond_true);
15671f5207b7SJohn Levon
1568*c85f09ccSJohn Levon emit_copy(new, stot, expr->ctype);
15691f5207b7SJohn Levon
15701f5207b7SJohn Levon cond_end = emit_conditional_end(target_false);
15711f5207b7SJohn Levon
15721f5207b7SJohn Levon /* handle if-false part of the expression */
1573*c85f09ccSJohn Levon stof = x86_expression(expr->cond_false);
15741f5207b7SJohn Levon
1575*c85f09ccSJohn Levon emit_copy(new, stof, expr->ctype);
15761f5207b7SJohn Levon
15771f5207b7SJohn Levon /* end of conditional; jump target for if-true branch */
15781f5207b7SJohn Levon emit_label(cond_end, "end conditional");
15791f5207b7SJohn Levon
15801f5207b7SJohn Levon return new;
15811f5207b7SJohn Levon }
15821f5207b7SJohn Levon
emit_select_expr(struct expression * expr)15831f5207b7SJohn Levon static struct storage *emit_select_expr(struct expression *expr)
15841f5207b7SJohn Levon {
15851f5207b7SJohn Levon struct storage *cond = x86_expression(expr->conditional);
1586*c85f09ccSJohn Levon struct storage *stot = x86_expression(expr->cond_true);
1587*c85f09ccSJohn Levon struct storage *stof = x86_expression(expr->cond_false);
15881f5207b7SJohn Levon struct storage *reg_cond, *reg_true, *reg_false;
15891f5207b7SJohn Levon struct storage *new = stack_alloc(4);
15901f5207b7SJohn Levon
15911f5207b7SJohn Levon emit_comment("begin SELECT");
15921f5207b7SJohn Levon reg_cond = get_reg_value(cond, get_regclass(expr->conditional));
1593*c85f09ccSJohn Levon reg_true = get_reg_value(stot, get_regclass(expr));
1594*c85f09ccSJohn Levon reg_false = get_reg_value(stof, get_regclass(expr));
15951f5207b7SJohn Levon
15961f5207b7SJohn Levon /*
15971f5207b7SJohn Levon * Do the actual select: check the conditional for zero,
15981f5207b7SJohn Levon * move false over true if zero
15991f5207b7SJohn Levon */
16001f5207b7SJohn Levon insn("test", reg_cond, reg_cond, NULL);
16011f5207b7SJohn Levon insn("cmovz", reg_false, reg_true, NULL);
16021f5207b7SJohn Levon
16031f5207b7SJohn Levon /* Store it back */
16041f5207b7SJohn Levon emit_move(reg_true, new, expr->ctype, NULL);
16051f5207b7SJohn Levon put_reg(reg_cond);
16061f5207b7SJohn Levon put_reg(reg_true);
16071f5207b7SJohn Levon put_reg(reg_false);
16081f5207b7SJohn Levon emit_comment("end SELECT");
16091f5207b7SJohn Levon return new;
16101f5207b7SJohn Levon }
16111f5207b7SJohn Levon
emit_symbol_expr_init(struct symbol * sym)16121f5207b7SJohn Levon static struct storage *emit_symbol_expr_init(struct symbol *sym)
16131f5207b7SJohn Levon {
16141f5207b7SJohn Levon struct expression *expr = sym->initializer;
16151f5207b7SJohn Levon struct symbol_private *priv = sym->aux;
16161f5207b7SJohn Levon
16171f5207b7SJohn Levon if (priv == NULL) {
16181f5207b7SJohn Levon priv = calloc(1, sizeof(*priv));
16191f5207b7SJohn Levon sym->aux = priv;
16201f5207b7SJohn Levon
16211f5207b7SJohn Levon if (expr == NULL) {
16221f5207b7SJohn Levon struct storage *new = stack_alloc(4);
16231f5207b7SJohn Levon fprintf(stderr, "FIXME! no value for symbol %s. creating pseudo %d (stack offset %d)\n",
16241f5207b7SJohn Levon show_ident(sym->ident),
16251f5207b7SJohn Levon new->pseudo, new->pseudo * 4);
16261f5207b7SJohn Levon priv->addr = new;
16271f5207b7SJohn Levon } else {
16281f5207b7SJohn Levon priv->addr = x86_expression(expr);
16291f5207b7SJohn Levon }
16301f5207b7SJohn Levon }
16311f5207b7SJohn Levon
16321f5207b7SJohn Levon return priv->addr;
16331f5207b7SJohn Levon }
16341f5207b7SJohn Levon
emit_string_expr(struct expression * expr)16351f5207b7SJohn Levon static struct storage *emit_string_expr(struct expression *expr)
16361f5207b7SJohn Levon {
16371f5207b7SJohn Levon struct function *f = current_func;
16381f5207b7SJohn Levon int label = new_label();
16391f5207b7SJohn Levon struct storage *new;
16401f5207b7SJohn Levon
16411f5207b7SJohn Levon push_cstring(f, expr->string, label);
16421f5207b7SJohn Levon
16431f5207b7SJohn Levon new = new_storage(STOR_LABEL);
16441f5207b7SJohn Levon new->label = label;
16451f5207b7SJohn Levon new->flags = STOR_LABEL_VAL | STOR_WANTS_FREE;
16461f5207b7SJohn Levon return new;
16471f5207b7SJohn Levon }
16481f5207b7SJohn Levon
emit_cast_expr(struct expression * expr)16491f5207b7SJohn Levon static struct storage *emit_cast_expr(struct expression *expr)
16501f5207b7SJohn Levon {
16511f5207b7SJohn Levon struct symbol *old_type, *new_type;
16521f5207b7SJohn Levon struct storage *op = x86_expression(expr->cast_expression);
16531f5207b7SJohn Levon int oldbits, newbits;
16541f5207b7SJohn Levon struct storage *new;
16551f5207b7SJohn Levon
16561f5207b7SJohn Levon old_type = expr->cast_expression->ctype;
16571f5207b7SJohn Levon new_type = expr->cast_type;
16581f5207b7SJohn Levon
16591f5207b7SJohn Levon oldbits = old_type->bit_size;
16601f5207b7SJohn Levon newbits = new_type->bit_size;
16611f5207b7SJohn Levon if (oldbits >= newbits)
16621f5207b7SJohn Levon return op;
16631f5207b7SJohn Levon
16641f5207b7SJohn Levon emit_move(op, REG_EAX, old_type, "begin cast ..");
16651f5207b7SJohn Levon
16661f5207b7SJohn Levon new = stack_alloc(newbits / 8);
16671f5207b7SJohn Levon emit_move(REG_EAX, new, new_type, ".... end cast");
16681f5207b7SJohn Levon
16691f5207b7SJohn Levon return new;
16701f5207b7SJohn Levon }
16711f5207b7SJohn Levon
emit_regular_preop(struct expression * expr)16721f5207b7SJohn Levon static struct storage *emit_regular_preop(struct expression *expr)
16731f5207b7SJohn Levon {
16741f5207b7SJohn Levon struct storage *target = x86_expression(expr->unop);
16751f5207b7SJohn Levon struct storage *val, *new = stack_alloc(4);
16761f5207b7SJohn Levon const char *opname = NULL;
16771f5207b7SJohn Levon
16781f5207b7SJohn Levon switch (expr->op) {
16791f5207b7SJohn Levon case '!':
16801f5207b7SJohn Levon val = new_storage(STOR_VALUE);
16811f5207b7SJohn Levon val->flags = STOR_WANTS_FREE;
16821f5207b7SJohn Levon emit_move(val, REG_EDX, NULL, NULL);
16831f5207b7SJohn Levon emit_move(target, REG_EAX, expr->unop->ctype, NULL);
16841f5207b7SJohn Levon insn("test", REG_EAX, REG_EAX, NULL);
16851f5207b7SJohn Levon insn("setz", REG_DL, NULL, NULL);
16861f5207b7SJohn Levon emit_move(REG_EDX, new, expr->unop->ctype, NULL);
16871f5207b7SJohn Levon
16881f5207b7SJohn Levon break;
16891f5207b7SJohn Levon case '~':
16901f5207b7SJohn Levon opname = "not";
16911f5207b7SJohn Levon case '-':
16921f5207b7SJohn Levon if (!opname)
16931f5207b7SJohn Levon opname = "neg";
16941f5207b7SJohn Levon emit_move(target, REG_EAX, expr->unop->ctype, NULL);
16951f5207b7SJohn Levon insn(opname, REG_EAX, NULL, NULL);
16961f5207b7SJohn Levon emit_move(REG_EAX, new, expr->unop->ctype, NULL);
16971f5207b7SJohn Levon break;
16981f5207b7SJohn Levon default:
16991f5207b7SJohn Levon assert(0);
17001f5207b7SJohn Levon break;
17011f5207b7SJohn Levon }
17021f5207b7SJohn Levon
17031f5207b7SJohn Levon return new;
17041f5207b7SJohn Levon }
17051f5207b7SJohn Levon
emit_case_statement(struct statement * stmt)17061f5207b7SJohn Levon static void emit_case_statement(struct statement *stmt)
17071f5207b7SJohn Levon {
17081f5207b7SJohn Levon emit_labelsym(stmt->case_label, NULL);
17091f5207b7SJohn Levon x86_statement(stmt->case_statement);
17101f5207b7SJohn Levon }
17111f5207b7SJohn Levon
emit_switch_statement(struct statement * stmt)17121f5207b7SJohn Levon static void emit_switch_statement(struct statement *stmt)
17131f5207b7SJohn Levon {
17141f5207b7SJohn Levon struct storage *val = x86_expression(stmt->switch_expression);
17151f5207b7SJohn Levon struct symbol *sym, *default_sym = NULL;
17161f5207b7SJohn Levon struct storage *labelsym, *label;
17171f5207b7SJohn Levon int switch_end = 0;
17181f5207b7SJohn Levon
17191f5207b7SJohn Levon emit_move(val, REG_EAX, stmt->switch_expression->ctype, "begin case");
17201f5207b7SJohn Levon
17211f5207b7SJohn Levon /*
17221f5207b7SJohn Levon * This is where a _real_ back-end would go through the
17231f5207b7SJohn Levon * cases to decide whether to use a lookup table or a
17241f5207b7SJohn Levon * series of comparisons etc
17251f5207b7SJohn Levon */
17261f5207b7SJohn Levon FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) {
17271f5207b7SJohn Levon struct statement *case_stmt = sym->stmt;
17281f5207b7SJohn Levon struct expression *expr = case_stmt->case_expression;
17291f5207b7SJohn Levon struct expression *to = case_stmt->case_to;
17301f5207b7SJohn Levon
17311f5207b7SJohn Levon /* default: */
17321f5207b7SJohn Levon if (!expr)
17331f5207b7SJohn Levon default_sym = sym;
17341f5207b7SJohn Levon
17351f5207b7SJohn Levon /* case NNN: */
17361f5207b7SJohn Levon else {
17371f5207b7SJohn Levon struct storage *case_val = new_val(expr->value);
17381f5207b7SJohn Levon
17391f5207b7SJohn Levon assert (expr->type == EXPR_VALUE);
17401f5207b7SJohn Levon
17411f5207b7SJohn Levon insn("cmpl", case_val, REG_EAX, NULL);
17421f5207b7SJohn Levon
17431f5207b7SJohn Levon if (!to) {
17441f5207b7SJohn Levon labelsym = new_labelsym(sym);
17451f5207b7SJohn Levon insn("je", labelsym, NULL, NULL);
17461f5207b7SJohn Levon } else {
17471f5207b7SJohn Levon int next_test;
17481f5207b7SJohn Levon
17491f5207b7SJohn Levon label = new_storage(STOR_LABEL);
17501f5207b7SJohn Levon label->flags |= STOR_WANTS_FREE;
17511f5207b7SJohn Levon label->label = next_test = new_label();
17521f5207b7SJohn Levon
17531f5207b7SJohn Levon /* FIXME: signed/unsigned */
17541f5207b7SJohn Levon insn("jl", label, NULL, NULL);
17551f5207b7SJohn Levon
17561f5207b7SJohn Levon case_val = new_val(to->value);
17571f5207b7SJohn Levon insn("cmpl", case_val, REG_EAX, NULL);
17581f5207b7SJohn Levon
17591f5207b7SJohn Levon /* TODO: implement and use refcounting... */
17601f5207b7SJohn Levon label = new_storage(STOR_LABEL);
17611f5207b7SJohn Levon label->flags |= STOR_WANTS_FREE;
17621f5207b7SJohn Levon label->label = next_test;
17631f5207b7SJohn Levon
17641f5207b7SJohn Levon /* FIXME: signed/unsigned */
17651f5207b7SJohn Levon insn("jg", label, NULL, NULL);
17661f5207b7SJohn Levon
17671f5207b7SJohn Levon labelsym = new_labelsym(sym);
17681f5207b7SJohn Levon insn("jmp", labelsym, NULL, NULL);
17691f5207b7SJohn Levon
17701f5207b7SJohn Levon emit_label(next_test, NULL);
17711f5207b7SJohn Levon }
17721f5207b7SJohn Levon }
17731f5207b7SJohn Levon } END_FOR_EACH_PTR(sym);
17741f5207b7SJohn Levon
17751f5207b7SJohn Levon if (default_sym) {
17761f5207b7SJohn Levon labelsym = new_labelsym(default_sym);
17771f5207b7SJohn Levon insn("jmp", labelsym, NULL, "default");
17781f5207b7SJohn Levon } else {
17791f5207b7SJohn Levon label = new_storage(STOR_LABEL);
17801f5207b7SJohn Levon label->flags |= STOR_WANTS_FREE;
17811f5207b7SJohn Levon label->label = switch_end = new_label();
17821f5207b7SJohn Levon insn("jmp", label, NULL, "goto end of switch");
17831f5207b7SJohn Levon }
17841f5207b7SJohn Levon
17851f5207b7SJohn Levon x86_statement(stmt->switch_statement);
17861f5207b7SJohn Levon
17871f5207b7SJohn Levon if (stmt->switch_break->used)
17881f5207b7SJohn Levon emit_labelsym(stmt->switch_break, NULL);
17891f5207b7SJohn Levon
17901f5207b7SJohn Levon if (switch_end)
17911f5207b7SJohn Levon emit_label(switch_end, NULL);
17921f5207b7SJohn Levon }
17931f5207b7SJohn Levon
x86_struct_member(struct symbol * sym)17941f5207b7SJohn Levon static void x86_struct_member(struct symbol *sym)
17951f5207b7SJohn Levon {
17961f5207b7SJohn Levon printf("\t%s:%d:%ld at offset %ld.%d", show_ident(sym->ident), sym->bit_size, sym->ctype.alignment, sym->offset, sym->bit_offset);
17971f5207b7SJohn Levon printf("\n");
17981f5207b7SJohn Levon }
17991f5207b7SJohn Levon
x86_symbol(struct symbol * sym)18001f5207b7SJohn Levon static void x86_symbol(struct symbol *sym)
18011f5207b7SJohn Levon {
18021f5207b7SJohn Levon struct symbol *type;
18031f5207b7SJohn Levon
18041f5207b7SJohn Levon if (!sym)
18051f5207b7SJohn Levon return;
18061f5207b7SJohn Levon
18071f5207b7SJohn Levon type = sym->ctype.base_type;
18081f5207b7SJohn Levon if (!type)
18091f5207b7SJohn Levon return;
18101f5207b7SJohn Levon
18111f5207b7SJohn Levon /*
18121f5207b7SJohn Levon * Show actual implementation information
18131f5207b7SJohn Levon */
18141f5207b7SJohn Levon switch (type->type) {
18151f5207b7SJohn Levon
18161f5207b7SJohn Levon case SYM_ARRAY:
18171f5207b7SJohn Levon if (sym->initializer)
18181f5207b7SJohn Levon emit_array(sym);
18191f5207b7SJohn Levon else
18201f5207b7SJohn Levon emit_array_noinit(sym);
18211f5207b7SJohn Levon break;
18221f5207b7SJohn Levon
18231f5207b7SJohn Levon case SYM_BASETYPE:
18241f5207b7SJohn Levon if (sym->initializer) {
18251f5207b7SJohn Levon emit_object_pre(show_ident(sym->ident),
18261f5207b7SJohn Levon sym->ctype.modifiers,
18271f5207b7SJohn Levon sym->ctype.alignment,
18281f5207b7SJohn Levon sym->bit_size / 8);
18291f5207b7SJohn Levon emit_scalar(sym->initializer, sym->bit_size);
18301f5207b7SJohn Levon stor_sym_init(sym);
18311f5207b7SJohn Levon } else
18321f5207b7SJohn Levon emit_scalar_noinit(sym);
18331f5207b7SJohn Levon break;
18341f5207b7SJohn Levon
18351f5207b7SJohn Levon case SYM_STRUCT:
18361f5207b7SJohn Levon case SYM_UNION: {
18371f5207b7SJohn Levon struct symbol *member;
18381f5207b7SJohn Levon
18391f5207b7SJohn Levon printf(" {\n");
18401f5207b7SJohn Levon FOR_EACH_PTR(type->symbol_list, member) {
18411f5207b7SJohn Levon x86_struct_member(member);
18421f5207b7SJohn Levon } END_FOR_EACH_PTR(member);
18431f5207b7SJohn Levon printf("}\n");
18441f5207b7SJohn Levon break;
18451f5207b7SJohn Levon }
18461f5207b7SJohn Levon
18471f5207b7SJohn Levon case SYM_FN: {
18481f5207b7SJohn Levon struct statement *stmt = type->stmt;
18491f5207b7SJohn Levon if (stmt) {
18501f5207b7SJohn Levon emit_func_pre(sym);
18511f5207b7SJohn Levon x86_statement(stmt);
18521f5207b7SJohn Levon emit_func_post(sym);
18531f5207b7SJohn Levon }
18541f5207b7SJohn Levon break;
18551f5207b7SJohn Levon }
18561f5207b7SJohn Levon
18571f5207b7SJohn Levon default:
18581f5207b7SJohn Levon break;
18591f5207b7SJohn Levon }
18601f5207b7SJohn Levon
18611f5207b7SJohn Levon if (sym->initializer && (type->type != SYM_BASETYPE) &&
18621f5207b7SJohn Levon (type->type != SYM_ARRAY)) {
18631f5207b7SJohn Levon printf(" = \n");
18641f5207b7SJohn Levon x86_expression(sym->initializer);
18651f5207b7SJohn Levon }
18661f5207b7SJohn Levon }
18671f5207b7SJohn Levon
18681f5207b7SJohn Levon static void x86_symbol_init(struct symbol *sym);
18691f5207b7SJohn Levon
x86_symbol_decl(struct symbol_list * syms)18701f5207b7SJohn Levon static void x86_symbol_decl(struct symbol_list *syms)
18711f5207b7SJohn Levon {
18721f5207b7SJohn Levon struct symbol *sym;
18731f5207b7SJohn Levon FOR_EACH_PTR(syms, sym) {
18741f5207b7SJohn Levon x86_symbol_init(sym);
18751f5207b7SJohn Levon } END_FOR_EACH_PTR(sym);
18761f5207b7SJohn Levon }
18771f5207b7SJohn Levon
loopstk_push(int cont_lbl,int loop_bottom_lbl)18781f5207b7SJohn Levon static void loopstk_push(int cont_lbl, int loop_bottom_lbl)
18791f5207b7SJohn Levon {
18801f5207b7SJohn Levon struct function *f = current_func;
18811f5207b7SJohn Levon struct loop_stack *ls;
18821f5207b7SJohn Levon
18831f5207b7SJohn Levon ls = malloc(sizeof(*ls));
18841f5207b7SJohn Levon ls->continue_lbl = cont_lbl;
18851f5207b7SJohn Levon ls->loop_bottom_lbl = loop_bottom_lbl;
18861f5207b7SJohn Levon ls->next = f->loop_stack;
18871f5207b7SJohn Levon f->loop_stack = ls;
18881f5207b7SJohn Levon }
18891f5207b7SJohn Levon
loopstk_pop(void)18901f5207b7SJohn Levon static void loopstk_pop(void)
18911f5207b7SJohn Levon {
18921f5207b7SJohn Levon struct function *f = current_func;
18931f5207b7SJohn Levon struct loop_stack *ls;
18941f5207b7SJohn Levon
18951f5207b7SJohn Levon assert(f->loop_stack != NULL);
18961f5207b7SJohn Levon ls = f->loop_stack;
18971f5207b7SJohn Levon f->loop_stack = f->loop_stack->next;
18981f5207b7SJohn Levon free(ls);
18991f5207b7SJohn Levon }
19001f5207b7SJohn Levon
loopstk_break(void)19011f5207b7SJohn Levon static int loopstk_break(void)
19021f5207b7SJohn Levon {
19031f5207b7SJohn Levon return current_func->loop_stack->loop_bottom_lbl;
19041f5207b7SJohn Levon }
19051f5207b7SJohn Levon
loopstk_continue(void)19061f5207b7SJohn Levon static int loopstk_continue(void)
19071f5207b7SJohn Levon {
19081f5207b7SJohn Levon return current_func->loop_stack->continue_lbl;
19091f5207b7SJohn Levon }
19101f5207b7SJohn Levon
emit_loop(struct statement * stmt)19111f5207b7SJohn Levon static void emit_loop(struct statement *stmt)
19121f5207b7SJohn Levon {
19131f5207b7SJohn Levon struct statement *pre_statement = stmt->iterator_pre_statement;
19141f5207b7SJohn Levon struct expression *pre_condition = stmt->iterator_pre_condition;
19151f5207b7SJohn Levon struct statement *statement = stmt->iterator_statement;
19161f5207b7SJohn Levon struct statement *post_statement = stmt->iterator_post_statement;
19171f5207b7SJohn Levon struct expression *post_condition = stmt->iterator_post_condition;
19181f5207b7SJohn Levon int loop_top = 0, loop_bottom, loop_continue;
19191f5207b7SJohn Levon int have_bottom = 0;
19201f5207b7SJohn Levon struct storage *val;
19211f5207b7SJohn Levon
19221f5207b7SJohn Levon loop_bottom = new_label();
19231f5207b7SJohn Levon loop_continue = new_label();
19241f5207b7SJohn Levon loopstk_push(loop_continue, loop_bottom);
19251f5207b7SJohn Levon
19261f5207b7SJohn Levon x86_symbol_decl(stmt->iterator_syms);
19271f5207b7SJohn Levon x86_statement(pre_statement);
19281f5207b7SJohn Levon if (!post_condition || post_condition->type != EXPR_VALUE || post_condition->value) {
19291f5207b7SJohn Levon loop_top = new_label();
19301f5207b7SJohn Levon emit_label(loop_top, "loop top");
19311f5207b7SJohn Levon }
19321f5207b7SJohn Levon if (pre_condition) {
19331f5207b7SJohn Levon if (pre_condition->type == EXPR_VALUE) {
19341f5207b7SJohn Levon if (!pre_condition->value) {
19351f5207b7SJohn Levon struct storage *lbv;
19361f5207b7SJohn Levon lbv = new_storage(STOR_LABEL);
19371f5207b7SJohn Levon lbv->label = loop_bottom;
19381f5207b7SJohn Levon lbv->flags = STOR_WANTS_FREE;
19391f5207b7SJohn Levon insn("jmp", lbv, NULL, "go to loop bottom");
19401f5207b7SJohn Levon have_bottom = 1;
19411f5207b7SJohn Levon }
19421f5207b7SJohn Levon } else {
19431f5207b7SJohn Levon struct storage *lbv = new_storage(STOR_LABEL);
19441f5207b7SJohn Levon lbv->label = loop_bottom;
19451f5207b7SJohn Levon lbv->flags = STOR_WANTS_FREE;
19461f5207b7SJohn Levon have_bottom = 1;
19471f5207b7SJohn Levon
19481f5207b7SJohn Levon val = x86_expression(pre_condition);
19491f5207b7SJohn Levon
19501f5207b7SJohn Levon emit_move(val, REG_EAX, NULL, "loop pre condition");
19511f5207b7SJohn Levon insn("test", REG_EAX, REG_EAX, NULL);
19521f5207b7SJohn Levon insn("jz", lbv, NULL, NULL);
19531f5207b7SJohn Levon }
19541f5207b7SJohn Levon }
19551f5207b7SJohn Levon x86_statement(statement);
19561f5207b7SJohn Levon if (stmt->iterator_continue->used)
19571f5207b7SJohn Levon emit_label(loop_continue, "'continue' iterator");
19581f5207b7SJohn Levon x86_statement(post_statement);
19591f5207b7SJohn Levon if (!post_condition) {
19601f5207b7SJohn Levon struct storage *lbv = new_storage(STOR_LABEL);
19611f5207b7SJohn Levon lbv->label = loop_top;
19621f5207b7SJohn Levon lbv->flags = STOR_WANTS_FREE;
19631f5207b7SJohn Levon insn("jmp", lbv, NULL, "go to loop top");
19641f5207b7SJohn Levon } else if (post_condition->type == EXPR_VALUE) {
19651f5207b7SJohn Levon if (post_condition->value) {
19661f5207b7SJohn Levon struct storage *lbv = new_storage(STOR_LABEL);
19671f5207b7SJohn Levon lbv->label = loop_top;
19681f5207b7SJohn Levon lbv->flags = STOR_WANTS_FREE;
19691f5207b7SJohn Levon insn("jmp", lbv, NULL, "go to loop top");
19701f5207b7SJohn Levon }
19711f5207b7SJohn Levon } else {
19721f5207b7SJohn Levon struct storage *lbv = new_storage(STOR_LABEL);
19731f5207b7SJohn Levon lbv->label = loop_top;
19741f5207b7SJohn Levon lbv->flags = STOR_WANTS_FREE;
19751f5207b7SJohn Levon
19761f5207b7SJohn Levon val = x86_expression(post_condition);
19771f5207b7SJohn Levon
19781f5207b7SJohn Levon emit_move(val, REG_EAX, NULL, "loop post condition");
19791f5207b7SJohn Levon insn("test", REG_EAX, REG_EAX, NULL);
19801f5207b7SJohn Levon insn("jnz", lbv, NULL, NULL);
19811f5207b7SJohn Levon }
19821f5207b7SJohn Levon if (have_bottom || stmt->iterator_break->used)
19831f5207b7SJohn Levon emit_label(loop_bottom, "loop bottom");
19841f5207b7SJohn Levon
19851f5207b7SJohn Levon loopstk_pop();
19861f5207b7SJohn Levon }
19871f5207b7SJohn Levon
19881f5207b7SJohn Levon /*
19891f5207b7SJohn Levon * Print out a statement
19901f5207b7SJohn Levon */
x86_statement(struct statement * stmt)19911f5207b7SJohn Levon static struct storage *x86_statement(struct statement *stmt)
19921f5207b7SJohn Levon {
19931f5207b7SJohn Levon if (!stmt)
19941f5207b7SJohn Levon return NULL;
19951f5207b7SJohn Levon switch (stmt->type) {
19961f5207b7SJohn Levon default:
19971f5207b7SJohn Levon return NULL;
19981f5207b7SJohn Levon case STMT_RETURN:
19991f5207b7SJohn Levon return emit_return_stmt(stmt);
20001f5207b7SJohn Levon case STMT_DECLARATION:
20011f5207b7SJohn Levon x86_symbol_decl(stmt->declaration);
20021f5207b7SJohn Levon break;
20031f5207b7SJohn Levon case STMT_COMPOUND: {
20041f5207b7SJohn Levon struct statement *s;
20051f5207b7SJohn Levon struct storage *last = NULL;
20061f5207b7SJohn Levon
20071f5207b7SJohn Levon FOR_EACH_PTR(stmt->stmts, s) {
20081f5207b7SJohn Levon last = x86_statement(s);
20091f5207b7SJohn Levon } END_FOR_EACH_PTR(s);
20101f5207b7SJohn Levon
20111f5207b7SJohn Levon return last;
20121f5207b7SJohn Levon }
20131f5207b7SJohn Levon
20141f5207b7SJohn Levon case STMT_EXPRESSION:
20151f5207b7SJohn Levon return x86_expression(stmt->expression);
20161f5207b7SJohn Levon case STMT_IF:
20171f5207b7SJohn Levon emit_if_conditional(stmt);
20181f5207b7SJohn Levon return NULL;
20191f5207b7SJohn Levon
20201f5207b7SJohn Levon case STMT_CASE:
20211f5207b7SJohn Levon emit_case_statement(stmt);
20221f5207b7SJohn Levon break;
20231f5207b7SJohn Levon case STMT_SWITCH:
20241f5207b7SJohn Levon emit_switch_statement(stmt);
20251f5207b7SJohn Levon break;
20261f5207b7SJohn Levon
20271f5207b7SJohn Levon case STMT_ITERATOR:
20281f5207b7SJohn Levon emit_loop(stmt);
20291f5207b7SJohn Levon break;
20301f5207b7SJohn Levon
20311f5207b7SJohn Levon case STMT_NONE:
20321f5207b7SJohn Levon break;
20331f5207b7SJohn Levon
20341f5207b7SJohn Levon case STMT_LABEL:
20351f5207b7SJohn Levon printf(".L%p:\n", stmt->label_identifier);
20361f5207b7SJohn Levon x86_statement(stmt->label_statement);
20371f5207b7SJohn Levon break;
20381f5207b7SJohn Levon
20391f5207b7SJohn Levon case STMT_GOTO:
20401f5207b7SJohn Levon if (stmt->goto_expression) {
20411f5207b7SJohn Levon struct storage *val = x86_expression(stmt->goto_expression);
20421f5207b7SJohn Levon printf("\tgoto *v%d\n", val->pseudo);
20431f5207b7SJohn Levon } else if (!strcmp("break", show_ident(stmt->goto_label->ident))) {
20441f5207b7SJohn Levon struct storage *lbv = new_storage(STOR_LABEL);
20451f5207b7SJohn Levon lbv->label = loopstk_break();
20461f5207b7SJohn Levon lbv->flags = STOR_WANTS_FREE;
20471f5207b7SJohn Levon insn("jmp", lbv, NULL, "'break'; go to loop bottom");
20481f5207b7SJohn Levon } else if (!strcmp("continue", show_ident(stmt->goto_label->ident))) {
20491f5207b7SJohn Levon struct storage *lbv = new_storage(STOR_LABEL);
20501f5207b7SJohn Levon lbv->label = loopstk_continue();
20511f5207b7SJohn Levon lbv->flags = STOR_WANTS_FREE;
20521f5207b7SJohn Levon insn("jmp", lbv, NULL, "'continue'; go to loop top");
20531f5207b7SJohn Levon } else {
20541f5207b7SJohn Levon struct storage *labelsym = new_labelsym(stmt->goto_label);
20551f5207b7SJohn Levon insn("jmp", labelsym, NULL, NULL);
20561f5207b7SJohn Levon }
20571f5207b7SJohn Levon break;
20581f5207b7SJohn Levon case STMT_ASM:
20591f5207b7SJohn Levon printf("\tasm( .... )\n");
20601f5207b7SJohn Levon break;
20611f5207b7SJohn Levon }
20621f5207b7SJohn Levon return NULL;
20631f5207b7SJohn Levon }
20641f5207b7SJohn Levon
x86_call_expression(struct expression * expr)20651f5207b7SJohn Levon static struct storage *x86_call_expression(struct expression *expr)
20661f5207b7SJohn Levon {
20671f5207b7SJohn Levon struct function *f = current_func;
20681f5207b7SJohn Levon struct symbol *direct;
20691f5207b7SJohn Levon struct expression *arg, *fn;
20701f5207b7SJohn Levon struct storage *retval, *fncall;
20711f5207b7SJohn Levon int framesize;
20721f5207b7SJohn Levon char s[64];
20731f5207b7SJohn Levon
20741f5207b7SJohn Levon if (!expr->ctype) {
20751f5207b7SJohn Levon warning(expr->pos, "\tcall with no type!");
20761f5207b7SJohn Levon return NULL;
20771f5207b7SJohn Levon }
20781f5207b7SJohn Levon
20791f5207b7SJohn Levon framesize = 0;
20801f5207b7SJohn Levon FOR_EACH_PTR_REVERSE(expr->args, arg) {
20811f5207b7SJohn Levon struct storage *new = x86_expression(arg);
20821f5207b7SJohn Levon int size = arg->ctype->bit_size;
20831f5207b7SJohn Levon
20841f5207b7SJohn Levon /*
20851f5207b7SJohn Levon * FIXME: i386 SysV ABI dictates that values
20861f5207b7SJohn Levon * smaller than 32 bits should be placed onto
20871f5207b7SJohn Levon * the stack as 32-bit objects. We should not
20881f5207b7SJohn Levon * blindly do a 32-bit push on objects smaller
20891f5207b7SJohn Levon * than 32 bits.
20901f5207b7SJohn Levon */
20911f5207b7SJohn Levon if (size < 32)
20921f5207b7SJohn Levon size = 32;
20931f5207b7SJohn Levon insn("pushl", new, NULL,
20941f5207b7SJohn Levon !framesize ? "begin function call" : NULL);
20951f5207b7SJohn Levon
20961f5207b7SJohn Levon framesize += bits_to_bytes(size);
20971f5207b7SJohn Levon } END_FOR_EACH_PTR_REVERSE(arg);
20981f5207b7SJohn Levon
20991f5207b7SJohn Levon fn = expr->fn;
21001f5207b7SJohn Levon
21011f5207b7SJohn Levon /* Remove dereference, if any */
21021f5207b7SJohn Levon direct = NULL;
21031f5207b7SJohn Levon if (fn->type == EXPR_PREOP) {
21041f5207b7SJohn Levon if (fn->unop->type == EXPR_SYMBOL) {
21051f5207b7SJohn Levon struct symbol *sym = fn->unop->symbol;
21061f5207b7SJohn Levon if (sym->ctype.base_type->type == SYM_FN)
21071f5207b7SJohn Levon direct = sym;
21081f5207b7SJohn Levon }
21091f5207b7SJohn Levon }
21101f5207b7SJohn Levon if (direct) {
21111f5207b7SJohn Levon struct storage *direct_stor = new_storage(STOR_SYM);
21121f5207b7SJohn Levon direct_stor->flags |= STOR_WANTS_FREE;
21131f5207b7SJohn Levon direct_stor->sym = direct;
21141f5207b7SJohn Levon insn("call", direct_stor, NULL, NULL);
21151f5207b7SJohn Levon } else {
21161f5207b7SJohn Levon fncall = x86_expression(fn);
21171f5207b7SJohn Levon emit_move(fncall, REG_EAX, fn->ctype, NULL);
21181f5207b7SJohn Levon
21191f5207b7SJohn Levon strcpy(s, "\tcall\t*%eax\n");
21201f5207b7SJohn Levon push_text_atom(f, s);
21211f5207b7SJohn Levon }
21221f5207b7SJohn Levon
21231f5207b7SJohn Levon /* FIXME: pay attention to BITS_IN_POINTER */
21241f5207b7SJohn Levon if (framesize) {
21251f5207b7SJohn Levon struct storage *val = new_storage(STOR_VALUE);
21261f5207b7SJohn Levon val->value = (long long) framesize;
21271f5207b7SJohn Levon val->flags = STOR_WANTS_FREE;
21281f5207b7SJohn Levon insn("addl", val, REG_ESP, NULL);
21291f5207b7SJohn Levon }
21301f5207b7SJohn Levon
21311f5207b7SJohn Levon retval = stack_alloc(4);
21321f5207b7SJohn Levon emit_move(REG_EAX, retval, NULL, "end function call");
21331f5207b7SJohn Levon
21341f5207b7SJohn Levon return retval;
21351f5207b7SJohn Levon }
21361f5207b7SJohn Levon
x86_address_gen(struct expression * expr)21371f5207b7SJohn Levon static struct storage *x86_address_gen(struct expression *expr)
21381f5207b7SJohn Levon {
21391f5207b7SJohn Levon struct function *f = current_func;
21401f5207b7SJohn Levon struct storage *addr;
21411f5207b7SJohn Levon struct storage *new;
21421f5207b7SJohn Levon char s[32];
21431f5207b7SJohn Levon
21441f5207b7SJohn Levon addr = x86_expression(expr->unop);
21451f5207b7SJohn Levon if (expr->unop->type == EXPR_SYMBOL)
21461f5207b7SJohn Levon return addr;
21471f5207b7SJohn Levon
21481f5207b7SJohn Levon emit_move(addr, REG_EAX, NULL, "begin deref ..");
21491f5207b7SJohn Levon
21501f5207b7SJohn Levon /* FIXME: operand size */
21511f5207b7SJohn Levon strcpy(s, "\tmovl\t(%eax), %ecx\n");
21521f5207b7SJohn Levon push_text_atom(f, s);
21531f5207b7SJohn Levon
21541f5207b7SJohn Levon new = stack_alloc(4);
21551f5207b7SJohn Levon emit_move(REG_ECX, new, NULL, ".... end deref");
21561f5207b7SJohn Levon
21571f5207b7SJohn Levon return new;
21581f5207b7SJohn Levon }
21591f5207b7SJohn Levon
x86_assignment(struct expression * expr)21601f5207b7SJohn Levon static struct storage *x86_assignment(struct expression *expr)
21611f5207b7SJohn Levon {
21621f5207b7SJohn Levon struct expression *target = expr->left;
21631f5207b7SJohn Levon struct storage *val, *addr;
21641f5207b7SJohn Levon
21651f5207b7SJohn Levon if (!expr->ctype)
21661f5207b7SJohn Levon return NULL;
21671f5207b7SJohn Levon
21681f5207b7SJohn Levon val = x86_expression(expr->right);
21691f5207b7SJohn Levon addr = x86_address_gen(target);
21701f5207b7SJohn Levon
21711f5207b7SJohn Levon switch (val->type) {
21721f5207b7SJohn Levon /* copy, where both operands are memory */
21731f5207b7SJohn Levon case STOR_PSEUDO:
21741f5207b7SJohn Levon case STOR_ARG:
21751f5207b7SJohn Levon emit_copy(addr, val, expr->ctype);
21761f5207b7SJohn Levon break;
21771f5207b7SJohn Levon
21781f5207b7SJohn Levon /* copy, one or zero operands are memory */
21791f5207b7SJohn Levon case STOR_REG:
21801f5207b7SJohn Levon case STOR_SYM:
21811f5207b7SJohn Levon case STOR_VALUE:
21821f5207b7SJohn Levon case STOR_LABEL:
21831f5207b7SJohn Levon emit_move(val, addr, expr->left->ctype, NULL);
21841f5207b7SJohn Levon break;
21851f5207b7SJohn Levon
21861f5207b7SJohn Levon case STOR_LABELSYM:
21871f5207b7SJohn Levon assert(0);
21881f5207b7SJohn Levon break;
21891f5207b7SJohn Levon }
21901f5207b7SJohn Levon return val;
21911f5207b7SJohn Levon }
21921f5207b7SJohn Levon
x86_initialization(struct symbol * sym,struct expression * expr)21931f5207b7SJohn Levon static int x86_initialization(struct symbol *sym, struct expression *expr)
21941f5207b7SJohn Levon {
21951f5207b7SJohn Levon struct storage *val, *addr;
21961f5207b7SJohn Levon int bits;
21971f5207b7SJohn Levon
21981f5207b7SJohn Levon if (!expr->ctype)
21991f5207b7SJohn Levon return 0;
22001f5207b7SJohn Levon
22011f5207b7SJohn Levon bits = expr->ctype->bit_size;
22021f5207b7SJohn Levon val = x86_expression(expr);
22031f5207b7SJohn Levon addr = x86_symbol_expr(sym);
22041f5207b7SJohn Levon // FIXME! The "target" expression is for bitfield store information.
22051f5207b7SJohn Levon // Leave it NULL, which works fine.
22061f5207b7SJohn Levon emit_store(NULL, addr, val, bits);
22071f5207b7SJohn Levon return 0;
22081f5207b7SJohn Levon }
22091f5207b7SJohn Levon
x86_access(struct expression * expr)22101f5207b7SJohn Levon static struct storage *x86_access(struct expression *expr)
22111f5207b7SJohn Levon {
22121f5207b7SJohn Levon return x86_address_gen(expr);
22131f5207b7SJohn Levon }
22141f5207b7SJohn Levon
x86_preop(struct expression * expr)22151f5207b7SJohn Levon static struct storage *x86_preop(struct expression *expr)
22161f5207b7SJohn Levon {
22171f5207b7SJohn Levon /*
22181f5207b7SJohn Levon * '*' is an lvalue access, and is fundamentally different
22191f5207b7SJohn Levon * from an arithmetic operation. Maybe it should have an
22201f5207b7SJohn Levon * expression type of its own..
22211f5207b7SJohn Levon */
22221f5207b7SJohn Levon if (expr->op == '*')
22231f5207b7SJohn Levon return x86_access(expr);
22241f5207b7SJohn Levon if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
22251f5207b7SJohn Levon return emit_inc_dec(expr, 0);
22261f5207b7SJohn Levon return emit_regular_preop(expr);
22271f5207b7SJohn Levon }
22281f5207b7SJohn Levon
x86_symbol_expr(struct symbol * sym)22291f5207b7SJohn Levon static struct storage *x86_symbol_expr(struct symbol *sym)
22301f5207b7SJohn Levon {
22311f5207b7SJohn Levon struct storage *new = stack_alloc(4);
22321f5207b7SJohn Levon
22331f5207b7SJohn Levon if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_EXTERN | MOD_STATIC)) {
22341f5207b7SJohn Levon printf("\tmovi.%d\t\tv%d,$%s\n", bits_in_pointer, new->pseudo, show_ident(sym->ident));
22351f5207b7SJohn Levon return new;
22361f5207b7SJohn Levon }
22371f5207b7SJohn Levon if (sym->ctype.modifiers & MOD_ADDRESSABLE) {
2238*c85f09ccSJohn Levon printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new->pseudo, 0LL);
22391f5207b7SJohn Levon return new;
22401f5207b7SJohn Levon }
22411f5207b7SJohn Levon printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", bits_in_pointer, new->pseudo, show_ident(sym->ident), sym);
22421f5207b7SJohn Levon return new;
22431f5207b7SJohn Levon }
22441f5207b7SJohn Levon
x86_symbol_init(struct symbol * sym)22451f5207b7SJohn Levon static void x86_symbol_init(struct symbol *sym)
22461f5207b7SJohn Levon {
22471f5207b7SJohn Levon struct symbol_private *priv = sym->aux;
22481f5207b7SJohn Levon struct expression *expr = sym->initializer;
22491f5207b7SJohn Levon struct storage *new;
22501f5207b7SJohn Levon
22511f5207b7SJohn Levon if (expr)
22521f5207b7SJohn Levon new = x86_expression(expr);
22531f5207b7SJohn Levon else
22541f5207b7SJohn Levon new = stack_alloc(sym->bit_size / 8);
22551f5207b7SJohn Levon
22561f5207b7SJohn Levon if (!priv) {
22571f5207b7SJohn Levon priv = calloc(1, sizeof(*priv));
22581f5207b7SJohn Levon sym->aux = priv;
22591f5207b7SJohn Levon /* FIXME: leak! we don't free... */
22601f5207b7SJohn Levon /* (well, we don't free symbols either) */
22611f5207b7SJohn Levon }
22621f5207b7SJohn Levon
22631f5207b7SJohn Levon priv->addr = new;
22641f5207b7SJohn Levon }
22651f5207b7SJohn Levon
x86_label_expr(struct expression * expr)22661f5207b7SJohn Levon static struct storage *x86_label_expr(struct expression *expr)
22671f5207b7SJohn Levon {
22681f5207b7SJohn Levon struct storage *new = stack_alloc(4);
22691f5207b7SJohn Levon printf("\tmovi.%d\t\tv%d,.L%p\n", bits_in_pointer, new->pseudo, expr->label_symbol);
22701f5207b7SJohn Levon return new;
22711f5207b7SJohn Levon }
22721f5207b7SJohn Levon
x86_statement_expr(struct expression * expr)22731f5207b7SJohn Levon static struct storage *x86_statement_expr(struct expression *expr)
22741f5207b7SJohn Levon {
22751f5207b7SJohn Levon return x86_statement(expr->statement);
22761f5207b7SJohn Levon }
22771f5207b7SJohn Levon
x86_position_expr(struct expression * expr,struct symbol * base)22781f5207b7SJohn Levon static int x86_position_expr(struct expression *expr, struct symbol *base)
22791f5207b7SJohn Levon {
22801f5207b7SJohn Levon struct storage *new = x86_expression(expr->init_expr);
22811f5207b7SJohn Levon struct symbol *ctype = expr->init_expr->ctype;
22821f5207b7SJohn Levon
22831f5207b7SJohn Levon printf("\tinsert v%d at [%d:%d] of %s\n", new->pseudo,
22841f5207b7SJohn Levon expr->init_offset, ctype->bit_offset,
22851f5207b7SJohn Levon show_ident(base->ident));
22861f5207b7SJohn Levon return 0;
22871f5207b7SJohn Levon }
22881f5207b7SJohn Levon
x86_initializer_expr(struct expression * expr,struct symbol * ctype)22891f5207b7SJohn Levon static void x86_initializer_expr(struct expression *expr, struct symbol *ctype)
22901f5207b7SJohn Levon {
22911f5207b7SJohn Levon struct expression *entry;
22921f5207b7SJohn Levon
22931f5207b7SJohn Levon FOR_EACH_PTR(expr->expr_list, entry) {
22941f5207b7SJohn Levon // Nested initializers have their positions already
22951f5207b7SJohn Levon // recursively calculated - just output them too
22961f5207b7SJohn Levon if (entry->type == EXPR_INITIALIZER) {
22971f5207b7SJohn Levon x86_initializer_expr(entry, ctype);
22981f5207b7SJohn Levon continue;
22991f5207b7SJohn Levon }
23001f5207b7SJohn Levon
23011f5207b7SJohn Levon // Ignore initializer indexes and identifiers - the
23021f5207b7SJohn Levon // evaluator has taken them into account
23031f5207b7SJohn Levon if (entry->type == EXPR_IDENTIFIER || entry->type == EXPR_INDEX)
23041f5207b7SJohn Levon continue;
23051f5207b7SJohn Levon if (entry->type == EXPR_POS) {
23061f5207b7SJohn Levon x86_position_expr(entry, ctype);
23071f5207b7SJohn Levon continue;
23081f5207b7SJohn Levon }
23091f5207b7SJohn Levon x86_initialization(ctype, entry);
23101f5207b7SJohn Levon } END_FOR_EACH_PTR(entry);
23111f5207b7SJohn Levon }
23121f5207b7SJohn Levon
23131f5207b7SJohn Levon /*
23141f5207b7SJohn Levon * Print out an expression. Return the pseudo that contains the
23151f5207b7SJohn Levon * variable.
23161f5207b7SJohn Levon */
x86_expression(struct expression * expr)23171f5207b7SJohn Levon static struct storage *x86_expression(struct expression *expr)
23181f5207b7SJohn Levon {
23191f5207b7SJohn Levon if (!expr)
23201f5207b7SJohn Levon return NULL;
23211f5207b7SJohn Levon
23221f5207b7SJohn Levon if (!expr->ctype) {
23231f5207b7SJohn Levon struct position *pos = &expr->pos;
23241f5207b7SJohn Levon printf("\tno type at %s:%d:%d\n",
23251f5207b7SJohn Levon stream_name(pos->stream),
23261f5207b7SJohn Levon pos->line, pos->pos);
23271f5207b7SJohn Levon return NULL;
23281f5207b7SJohn Levon }
23291f5207b7SJohn Levon
23301f5207b7SJohn Levon switch (expr->type) {
23311f5207b7SJohn Levon default:
23321f5207b7SJohn Levon return NULL;
23331f5207b7SJohn Levon case EXPR_CALL:
23341f5207b7SJohn Levon return x86_call_expression(expr);
23351f5207b7SJohn Levon
23361f5207b7SJohn Levon case EXPR_ASSIGNMENT:
23371f5207b7SJohn Levon return x86_assignment(expr);
23381f5207b7SJohn Levon
23391f5207b7SJohn Levon case EXPR_COMPARE:
23401f5207b7SJohn Levon return emit_compare(expr);
23411f5207b7SJohn Levon case EXPR_BINOP:
23421f5207b7SJohn Levon case EXPR_COMMA:
23431f5207b7SJohn Levon case EXPR_LOGICAL:
23441f5207b7SJohn Levon return emit_binop(expr);
23451f5207b7SJohn Levon case EXPR_PREOP:
23461f5207b7SJohn Levon return x86_preop(expr);
23471f5207b7SJohn Levon case EXPR_POSTOP:
23481f5207b7SJohn Levon return emit_postop(expr);
23491f5207b7SJohn Levon case EXPR_SYMBOL:
23501f5207b7SJohn Levon return emit_symbol_expr_init(expr->symbol);
23511f5207b7SJohn Levon case EXPR_DEREF:
23521f5207b7SJohn Levon case EXPR_SIZEOF:
23531f5207b7SJohn Levon case EXPR_ALIGNOF:
23541f5207b7SJohn Levon warning(expr->pos, "invalid expression after evaluation");
23551f5207b7SJohn Levon return NULL;
23561f5207b7SJohn Levon case EXPR_CAST:
23571f5207b7SJohn Levon case EXPR_FORCE_CAST:
23581f5207b7SJohn Levon case EXPR_IMPLIED_CAST:
23591f5207b7SJohn Levon return emit_cast_expr(expr);
23601f5207b7SJohn Levon case EXPR_VALUE:
23611f5207b7SJohn Levon return emit_value(expr);
23621f5207b7SJohn Levon case EXPR_STRING:
23631f5207b7SJohn Levon return emit_string_expr(expr);
23641f5207b7SJohn Levon case EXPR_INITIALIZER:
23651f5207b7SJohn Levon x86_initializer_expr(expr, expr->ctype);
23661f5207b7SJohn Levon return NULL;
23671f5207b7SJohn Levon case EXPR_SELECT:
23681f5207b7SJohn Levon return emit_select_expr(expr);
23691f5207b7SJohn Levon case EXPR_CONDITIONAL:
23701f5207b7SJohn Levon return emit_conditional_expr(expr);
23711f5207b7SJohn Levon case EXPR_STATEMENT:
23721f5207b7SJohn Levon return x86_statement_expr(expr);
23731f5207b7SJohn Levon case EXPR_LABEL:
23741f5207b7SJohn Levon return x86_label_expr(expr);
23751f5207b7SJohn Levon
23761f5207b7SJohn Levon // None of these should exist as direct expressions: they are only
23771f5207b7SJohn Levon // valid as sub-expressions of initializers.
23781f5207b7SJohn Levon case EXPR_POS:
23791f5207b7SJohn Levon warning(expr->pos, "unable to show plain initializer position expression");
23801f5207b7SJohn Levon return NULL;
23811f5207b7SJohn Levon case EXPR_IDENTIFIER:
23821f5207b7SJohn Levon warning(expr->pos, "unable to show identifier expression");
23831f5207b7SJohn Levon return NULL;
23841f5207b7SJohn Levon case EXPR_INDEX:
23851f5207b7SJohn Levon warning(expr->pos, "unable to show index expression");
23861f5207b7SJohn Levon return NULL;
23871f5207b7SJohn Levon case EXPR_TYPE:
23881f5207b7SJohn Levon warning(expr->pos, "unable to show type expression");
23891f5207b7SJohn Levon return NULL;
23901f5207b7SJohn Levon case EXPR_FVALUE:
23911f5207b7SJohn Levon warning(expr->pos, "floating point support is not implemented");
23921f5207b7SJohn Levon return NULL;
23931f5207b7SJohn Levon }
23941f5207b7SJohn Levon return NULL;
23951f5207b7SJohn Levon }
2396