12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396 |
- /*
- * sparse/compile-i386.c
- *
- * Copyright (C) 2003 Transmeta Corp.
- * 2003 Linus Torvalds
- * Copyright 2003 Jeff Garzik
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * x86 backend
- *
- * TODO list:
- * in general, any non-32bit SYM_BASETYPE is unlikely to work.
- * complex initializers
- * bitfields
- * global struct/union variables
- * addressing structures, and members of structures (as opposed to
- * scalars) on the stack. Requires smarter stack frame allocation.
- * labels / goto
- * any function argument that isn't 32 bits (or promoted to such)
- * inline asm
- * floating point
- *
- */
- #include <stdarg.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <assert.h>
- #include "lib.h"
- #include "allocate.h"
- #include "token.h"
- #include "parse.h"
- #include "symbol.h"
- #include "scope.h"
- #include "expression.h"
- #include "target.h"
- #include "compile.h"
- #include "bitmap.h"
- #include "version.h"
- struct textbuf {
- unsigned int len; /* does NOT include terminating null */
- char *text;
- struct textbuf *next;
- struct textbuf *prev;
- };
- struct loop_stack {
- int continue_lbl;
- int loop_bottom_lbl;
- struct loop_stack *next;
- };
- struct atom;
- struct storage;
- DECLARE_PTR_LIST(str_list, struct atom);
- DECLARE_PTR_LIST(atom_list, struct atom);
- DECLARE_PTR_LIST(storage_list, struct storage);
- struct function {
- int stack_size;
- int pseudo_nr;
- struct storage_list *pseudo_list;
- struct atom_list *atom_list;
- struct str_list *str_list;
- struct loop_stack *loop_stack;
- struct symbol **argv;
- unsigned int argc;
- int ret_target;
- };
- enum storage_type {
- STOR_PSEUDO, /* variable stored on the stack */
- STOR_ARG, /* function argument */
- STOR_SYM, /* a symbol we can directly ref in the asm */
- STOR_REG, /* scratch register */
- STOR_VALUE, /* integer constant */
- STOR_LABEL, /* label / jump target */
- STOR_LABELSYM, /* label generated from symbol's pointer value */
- };
- struct reg_info {
- const char *name;
- struct storage *contains;
- const unsigned char aliases[12];
- #define own_regno aliases[0]
- };
- struct storage {
- enum storage_type type;
- unsigned long flags;
- /* STOR_REG */
- struct reg_info *reg;
- struct symbol *ctype;
- union {
- /* STOR_PSEUDO */
- struct {
- int pseudo;
- int offset;
- int size;
- };
- /* STOR_ARG */
- struct {
- int idx;
- };
- /* STOR_SYM */
- struct {
- struct symbol *sym;
- };
- /* STOR_VALUE */
- struct {
- long long value;
- };
- /* STOR_LABEL */
- struct {
- int label;
- };
- /* STOR_LABELSYM */
- struct {
- struct symbol *labelsym;
- };
- };
- };
- enum {
- STOR_LABEL_VAL = (1 << 0),
- STOR_WANTS_FREE = (1 << 1),
- };
- struct symbol_private {
- struct storage *addr;
- };
- enum atom_type {
- ATOM_TEXT,
- ATOM_INSN,
- ATOM_CSTR,
- };
- struct atom {
- enum atom_type type;
- union {
- /* stuff for text */
- struct {
- char *text;
- unsigned int text_len; /* w/o terminating null */
- };
- /* stuff for insns */
- struct {
- char insn[32];
- char comment[40];
- struct storage *op1;
- struct storage *op2;
- };
- /* stuff for C strings */
- struct {
- struct string *string;
- int label;
- };
- };
- };
- static struct function *current_func = NULL;
- static struct textbuf *unit_post_text = NULL;
- static const char *current_section;
- static void emit_comment(const char * fmt, ...) FORMAT_ATTR(1);
- static void emit_move(struct storage *src, struct storage *dest,
- struct symbol *ctype, const char *comment);
- static struct storage *x86_address_gen(struct expression *expr);
- static struct storage *x86_symbol_expr(struct symbol *sym);
- static void x86_symbol(struct symbol *sym);
- static struct storage *x86_statement(struct statement *stmt);
- static struct storage *x86_expression(struct expression *expr);
- enum registers {
- NOREG,
- AL, DL, CL, BL, AH, DH, CH, BH, // 8-bit
- AX, DX, CX, BX, SI, DI, BP, SP, // 16-bit
- EAX, EDX, ECX, EBX, ESI, EDI, EBP, ESP, // 32-bit
- EAX_EDX, ECX_EBX, ESI_EDI, // 64-bit
- };
- /* This works on regno's, reg_info's and hardreg_storage's */
- #define byte_reg(reg) ((reg) - 16)
- #define highbyte_reg(reg) ((reg)-12)
- #define word_reg(reg) ((reg)-8)
- #define REGINFO(nr, str, conflicts...) [nr] = { .name = str, .aliases = { nr , conflicts } }
- static struct reg_info reg_info_table[] = {
- REGINFO( AL, "%al", AX, EAX, EAX_EDX),
- REGINFO( DL, "%dl", DX, EDX, EAX_EDX),
- REGINFO( CL, "%cl", CX, ECX, ECX_EBX),
- REGINFO( BL, "%bl", BX, EBX, ECX_EBX),
- REGINFO( AH, "%ah", AX, EAX, EAX_EDX),
- REGINFO( DH, "%dh", DX, EDX, EAX_EDX),
- REGINFO( CH, "%ch", CX, ECX, ECX_EBX),
- REGINFO( BH, "%bh", BX, EBX, ECX_EBX),
- REGINFO( AX, "%ax", AL, AH, EAX, EAX_EDX),
- REGINFO( DX, "%dx", DL, DH, EDX, EAX_EDX),
- REGINFO( CX, "%cx", CL, CH, ECX, ECX_EBX),
- REGINFO( BX, "%bx", BL, BH, EBX, ECX_EBX),
- REGINFO( SI, "%si", ESI, ESI_EDI),
- REGINFO( DI, "%di", EDI, ESI_EDI),
- REGINFO( BP, "%bp", EBP),
- REGINFO( SP, "%sp", ESP),
- REGINFO(EAX, "%eax", AL, AH, AX, EAX_EDX),
- REGINFO(EDX, "%edx", DL, DH, DX, EAX_EDX),
- REGINFO(ECX, "%ecx", CL, CH, CX, ECX_EBX),
- REGINFO(EBX, "%ebx", BL, BH, BX, ECX_EBX),
- REGINFO(ESI, "%esi", SI, ESI_EDI),
- REGINFO(EDI, "%edi", DI, ESI_EDI),
- REGINFO(EBP, "%ebp", BP),
- REGINFO(ESP, "%esp", SP),
- REGINFO(EAX_EDX, "%eax:%edx", AL, AH, AX, EAX, DL, DH, DX, EDX),
- REGINFO(ECX_EBX, "%ecx:%ebx", CL, CH, CX, ECX, BL, BH, BX, EBX),
- REGINFO(ESI_EDI, "%esi:%edi", SI, ESI, DI, EDI),
- };
- #define REGSTORAGE(nr) [nr] = { .type = STOR_REG, .reg = reg_info_table + (nr) }
- static struct storage hardreg_storage_table[] = {
- REGSTORAGE(AL), REGSTORAGE(DL), REGSTORAGE(CL), REGSTORAGE(BL),
- REGSTORAGE(AH), REGSTORAGE(DH), REGSTORAGE(CH), REGSTORAGE(BH),
- REGSTORAGE(AX), REGSTORAGE(DX), REGSTORAGE(CX), REGSTORAGE(BX),
- REGSTORAGE(SI), REGSTORAGE(DI), REGSTORAGE(BP), REGSTORAGE(SP),
- REGSTORAGE(EAX), REGSTORAGE(EDX), REGSTORAGE(ECX), REGSTORAGE(EBX),
- REGSTORAGE(ESI), REGSTORAGE(EDI), REGSTORAGE(EBP), REGSTORAGE(ESP),
- REGSTORAGE(EAX_EDX), REGSTORAGE(ECX_EBX), REGSTORAGE(ESI_EDI),
- };
- #define REG_EAX (&hardreg_storage_table[EAX])
- #define REG_ECX (&hardreg_storage_table[ECX])
- #define REG_EDX (&hardreg_storage_table[EDX])
- #define REG_ESP (&hardreg_storage_table[ESP])
- #define REG_DL (&hardreg_storage_table[DL])
- #define REG_DX (&hardreg_storage_table[DX])
- #define REG_AL (&hardreg_storage_table[AL])
- #define REG_AX (&hardreg_storage_table[AX])
- static DECLARE_BITMAP(regs_in_use, 256);
- static inline struct storage * reginfo_reg(struct reg_info *info)
- {
- return hardreg_storage_table + info->own_regno;
- }
- static struct storage * get_hardreg(struct storage *reg, int clear)
- {
- struct reg_info *info = reg->reg;
- const unsigned char *aliases;
- int regno;
- aliases = info->aliases;
- while ((regno = *aliases++) != NOREG) {
- if (test_bit(regno, regs_in_use))
- goto busy;
- if (clear)
- reg_info_table[regno].contains = NULL;
- }
- set_bit(info->own_regno, regs_in_use);
- return reg;
- busy:
- fprintf(stderr, "register %s is busy\n", info->name);
- if (regno + reg_info_table != info)
- fprintf(stderr, " conflicts with %s\n", reg_info_table[regno].name);
- exit(1);
- }
- static void put_reg(struct storage *reg)
- {
- struct reg_info *info = reg->reg;
- int regno = info->own_regno;
- if (test_and_clear_bit(regno, regs_in_use))
- return;
- fprintf(stderr, "freeing already free'd register %s\n", reg_info_table[regno].name);
- }
- struct regclass {
- const char *name;
- const unsigned char regs[30];
- };
- static struct regclass regclass_8 = { "8-bit", { AL, DL, CL, BL, AH, DH, CH, BH }};
- static struct regclass regclass_16 = { "16-bit", { AX, DX, CX, BX, SI, DI, BP }};
- static struct regclass regclass_32 = { "32-bit", { EAX, EDX, ECX, EBX, ESI, EDI, EBP }};
- static struct regclass regclass_64 = { "64-bit", { EAX_EDX, ECX_EBX, ESI_EDI }};
- static struct regclass regclass_32_8 = { "32-bit bytes", { EAX, EDX, ECX, EBX }};
- static struct regclass *get_regclass_bits(int bits)
- {
- switch (bits) {
- case 8: return ®class_8;
- case 16: return ®class_16;
- case 64: return ®class_64;
- default: return ®class_32;
- }
- }
- static struct regclass *get_regclass(struct expression *expr)
- {
- return get_regclass_bits(expr->ctype->bit_size);
- }
- static int register_busy(int regno)
- {
- if (!test_bit(regno, regs_in_use)) {
- struct reg_info *info = reg_info_table + regno;
- const unsigned char *regs = info->aliases+1;
- while ((regno = *regs) != NOREG) {
- regs++;
- if (test_bit(regno, regs_in_use))
- goto busy;
- }
- return 0;
- }
- busy:
- return 1;
- }
- static struct storage *get_reg(struct regclass *class)
- {
- const unsigned char *regs = class->regs;
- int regno;
- while ((regno = *regs) != NOREG) {
- regs++;
- if (register_busy(regno))
- continue;
- return get_hardreg(hardreg_storage_table + regno, 1);
- }
- fprintf(stderr, "Ran out of %s registers\n", class->name);
- exit(1);
- }
- static struct storage *get_reg_value(struct storage *value, struct regclass *class)
- {
- struct reg_info *info;
- struct storage *reg;
- /* Do we already have it somewhere */
- info = value->reg;
- if (info && info->contains == value) {
- emit_comment("already have register %s", info->name);
- return get_hardreg(hardreg_storage_table + info->own_regno, 0);
- }
- reg = get_reg(class);
- emit_move(value, reg, value->ctype, "reload register");
- info = reg->reg;
- info->contains = value;
- value->reg = info;
- return reg;
- }
- static struct storage *temp_from_bits(unsigned int bit_size)
- {
- return get_reg(get_regclass_bits(bit_size));
- }
- static inline unsigned int pseudo_offset(struct storage *s)
- {
- if (s->type != STOR_PSEUDO)
- return 123456; /* intentionally bogus value */
- return s->offset;
- }
- static inline unsigned int arg_offset(struct storage *s)
- {
- if (s->type != STOR_ARG)
- return 123456; /* intentionally bogus value */
- /* FIXME: this is wrong wrong wrong */
- return current_func->stack_size + ((1 + s->idx) * 4);
- }
- static const char *pretty_offset(int ofs)
- {
- static char esp_buf[64];
- if (ofs)
- sprintf(esp_buf, "%d(%%esp)", ofs);
- else
- strcpy(esp_buf, "(%esp)");
- return esp_buf;
- }
- static void stor_sym_init(struct symbol *sym)
- {
- struct storage *stor;
- struct symbol_private *priv;
- priv = calloc(1, sizeof(*priv) + sizeof(*stor));
- if (!priv)
- die("OOM in stor_sym_init");
- stor = (struct storage *) (priv + 1);
- priv->addr = stor;
- stor->type = STOR_SYM;
- stor->sym = sym;
- }
- static const char *stor_op_name(struct storage *s)
- {
- static char name[32];
- switch (s->type) {
- case STOR_PSEUDO:
- strcpy(name, pretty_offset((int) pseudo_offset(s)));
- break;
- case STOR_ARG:
- strcpy(name, pretty_offset((int) arg_offset(s)));
- break;
- case STOR_SYM:
- strcpy(name, show_ident(s->sym->ident));
- break;
- case STOR_REG:
- strcpy(name, s->reg->name);
- break;
- case STOR_VALUE:
- sprintf(name, "$%lld", s->value);
- break;
- case STOR_LABEL:
- sprintf(name, "%s.L%d", s->flags & STOR_LABEL_VAL ? "$" : "",
- s->label);
- break;
- case STOR_LABELSYM:
- sprintf(name, "%s.LS%p", s->flags & STOR_LABEL_VAL ? "$" : "",
- s->labelsym);
- break;
- }
- return name;
- }
- static struct atom *new_atom(enum atom_type type)
- {
- struct atom *atom;
- atom = calloc(1, sizeof(*atom)); /* TODO: chunked alloc */
- if (!atom)
- die("nuclear OOM");
- atom->type = type;
- return atom;
- }
- static inline void push_cstring(struct function *f, struct string *str,
- int label)
- {
- struct atom *atom;
- atom = new_atom(ATOM_CSTR);
- atom->string = str;
- atom->label = label;
- add_ptr_list(&f->str_list, atom); /* note: _not_ atom_list */
- }
- static inline void push_atom(struct function *f, struct atom *atom)
- {
- add_ptr_list(&f->atom_list, atom);
- }
- static void push_text_atom(struct function *f, const char *text)
- {
- struct atom *atom = new_atom(ATOM_TEXT);
- atom->text = strdup(text);
- atom->text_len = strlen(text);
- push_atom(f, atom);
- }
- static struct storage *new_storage(enum storage_type type)
- {
- struct storage *stor;
- stor = calloc(1, sizeof(*stor));
- if (!stor)
- die("OOM in new_storage");
- stor->type = type;
- return stor;
- }
- static struct storage *stack_alloc(int n_bytes)
- {
- struct function *f = current_func;
- struct storage *stor;
- assert(f != NULL);
- stor = new_storage(STOR_PSEUDO);
- stor->type = STOR_PSEUDO;
- stor->pseudo = f->pseudo_nr;
- stor->offset = f->stack_size; /* FIXME: stack req. natural align */
- stor->size = n_bytes;
- f->stack_size += n_bytes;
- f->pseudo_nr++;
- add_ptr_list(&f->pseudo_list, stor);
- return stor;
- }
- static struct storage *new_labelsym(struct symbol *sym)
- {
- struct storage *stor;
- stor = new_storage(STOR_LABELSYM);
- if (stor) {
- stor->flags |= STOR_WANTS_FREE;
- stor->labelsym = sym;
- }
- return stor;
- }
- static struct storage *new_val(long long value)
- {
- struct storage *stor;
- stor = new_storage(STOR_VALUE);
- if (stor) {
- stor->flags |= STOR_WANTS_FREE;
- stor->value = value;
- }
- return stor;
- }
- static int new_label(void)
- {
- static int label = 0;
- return ++label;
- }
- static void textbuf_push(struct textbuf **buf_p, const char *text)
- {
- struct textbuf *tmp, *list = *buf_p;
- unsigned int text_len = strlen(text);
- unsigned int alloc_len = text_len + 1 + sizeof(*list);
- tmp = calloc(1, alloc_len);
- if (!tmp)
- die("OOM on textbuf alloc");
- tmp->text = ((void *) tmp) + sizeof(*tmp);
- memcpy(tmp->text, text, text_len + 1);
- tmp->len = text_len;
- /* add to end of list */
- if (!list) {
- list = tmp;
- tmp->prev = tmp;
- } else {
- tmp->prev = list->prev;
- tmp->prev->next = tmp;
- list->prev = tmp;
- }
- tmp->next = list;
- *buf_p = list;
- }
- static void textbuf_emit(struct textbuf **buf_p)
- {
- struct textbuf *tmp, *list = *buf_p;
- while (list) {
- tmp = list;
- if (tmp->next == tmp)
- list = NULL;
- else {
- tmp->prev->next = tmp->next;
- tmp->next->prev = tmp->prev;
- list = tmp->next;
- }
- fputs(tmp->text, stdout);
- free(tmp);
- }
- *buf_p = list;
- }
- static void insn(const char *insn, struct storage *op1, struct storage *op2,
- const char *comment_in)
- {
- struct function *f = current_func;
- struct atom *atom = new_atom(ATOM_INSN);
- assert(insn != NULL);
- strcpy(atom->insn, insn);
- if (comment_in && (*comment_in))
- strncpy(atom->comment, comment_in,
- sizeof(atom->comment) - 1);
- atom->op1 = op1;
- atom->op2 = op2;
- push_atom(f, atom);
- }
- static void emit_comment(const char *fmt, ...)
- {
- struct function *f = current_func;
- static char tmpbuf[100] = "\t# ";
- va_list args;
- int i;
- va_start(args, fmt);
- i = vsnprintf(tmpbuf+3, sizeof(tmpbuf)-4, fmt, args);
- va_end(args);
- tmpbuf[i+3] = '\n';
- tmpbuf[i+4] = '\0';
- push_text_atom(f, tmpbuf);
- }
- static void emit_label (int label, const char *comment)
- {
- struct function *f = current_func;
- char s[64];
- if (!comment)
- sprintf(s, ".L%d:\n", label);
- else
- sprintf(s, ".L%d:\t\t\t\t\t# %s\n", label, comment);
- push_text_atom(f, s);
- }
- static void emit_labelsym (struct symbol *sym, const char *comment)
- {
- struct function *f = current_func;
- char s[64];
- if (!comment)
- sprintf(s, ".LS%p:\n", sym);
- else
- sprintf(s, ".LS%p:\t\t\t\t# %s\n", sym, comment);
- push_text_atom(f, s);
- }
- void emit_unit_begin(const char *basename)
- {
- printf("\t.file\t\"%s\"\n", basename);
- }
- void emit_unit_end(void)
- {
- textbuf_emit(&unit_post_text);
- printf("\t.ident\t\"sparse silly x86 backend (version %s)\"\n", SPARSE_VERSION);
- }
- /* conditionally switch sections */
- static void emit_section(const char *s)
- {
- if (s == current_section)
- return;
- if (current_section && (!strcmp(s, current_section)))
- return;
- printf("\t%s\n", s);
- current_section = s;
- }
- static void emit_insn_atom(struct function *f, struct atom *atom)
- {
- char s[128];
- char comment[64];
- struct storage *op1 = atom->op1;
- struct storage *op2 = atom->op2;
- if (atom->comment[0])
- sprintf(comment, "\t\t# %s", atom->comment);
- else
- comment[0] = 0;
- if (atom->op2) {
- char tmp[16];
- strcpy(tmp, stor_op_name(op1));
- sprintf(s, "\t%s\t%s, %s%s\n",
- atom->insn, tmp, stor_op_name(op2), comment);
- } else if (atom->op1)
- sprintf(s, "\t%s\t%s%s%s\n",
- atom->insn, stor_op_name(op1),
- comment[0] ? "\t" : "", comment);
- else
- sprintf(s, "\t%s\t%s%s\n",
- atom->insn,
- comment[0] ? "\t\t" : "", comment);
- if (write(STDOUT_FILENO, s, strlen(s)) < 0)
- die("can't write to stdout");
- }
- static void emit_atom_list(struct function *f)
- {
- struct atom *atom;
- FOR_EACH_PTR(f->atom_list, atom) {
- switch (atom->type) {
- case ATOM_TEXT: {
- if (write(STDOUT_FILENO, atom->text, atom->text_len) < 0)
- die("can't write to stdout");
- break;
- }
- case ATOM_INSN:
- emit_insn_atom(f, atom);
- break;
- case ATOM_CSTR:
- assert(0);
- break;
- }
- } END_FOR_EACH_PTR(atom);
- }
- static void emit_string_list(struct function *f)
- {
- struct atom *atom;
- emit_section(".section\t.rodata");
- FOR_EACH_PTR(f->str_list, atom) {
- /* FIXME: escape " in string */
- printf(".L%d:\n", atom->label);
- printf("\t.string\t%s\n", show_string(atom->string));
- free(atom);
- } END_FOR_EACH_PTR(atom);
- }
- static void func_cleanup(struct function *f)
- {
- struct storage *stor;
- struct atom *atom;
- FOR_EACH_PTR(f->atom_list, atom) {
- if ((atom->type == ATOM_TEXT) && (atom->text))
- free(atom->text);
- if (atom->op1 && (atom->op1->flags & STOR_WANTS_FREE))
- free(atom->op1);
- if (atom->op2 && (atom->op2->flags & STOR_WANTS_FREE))
- free(atom->op2);
- free(atom);
- } END_FOR_EACH_PTR(atom);
- FOR_EACH_PTR(f->pseudo_list, stor) {
- free(stor);
- } END_FOR_EACH_PTR(stor);
- free_ptr_list(&f->pseudo_list);
- free(f);
- }
- /* function prologue */
- static void emit_func_pre(struct symbol *sym)
- {
- struct function *f;
- struct symbol *arg;
- unsigned int i, argc = 0, alloc_len;
- unsigned char *mem;
- struct symbol_private *privbase;
- struct storage *storage_base;
- struct symbol *base_type = sym->ctype.base_type;
- FOR_EACH_PTR(base_type->arguments, arg) {
- argc++;
- } END_FOR_EACH_PTR(arg);
- alloc_len =
- sizeof(*f) +
- (argc * sizeof(struct symbol *)) +
- (argc * sizeof(struct symbol_private)) +
- (argc * sizeof(struct storage));
- mem = calloc(1, alloc_len);
- if (!mem)
- die("OOM on func info");
- f = (struct function *) mem;
- mem += sizeof(*f);
- f->argv = (struct symbol **) mem;
- mem += (argc * sizeof(struct symbol *));
- privbase = (struct symbol_private *) mem;
- mem += (argc * sizeof(struct symbol_private));
- storage_base = (struct storage *) mem;
- f->argc = argc;
- f->ret_target = new_label();
- i = 0;
- FOR_EACH_PTR(base_type->arguments, arg) {
- f->argv[i] = arg;
- arg->aux = &privbase[i];
- storage_base[i].type = STOR_ARG;
- storage_base[i].idx = i;
- privbase[i].addr = &storage_base[i];
- i++;
- } END_FOR_EACH_PTR(arg);
- assert(current_func == NULL);
- current_func = f;
- }
- /* function epilogue */
- static void emit_func_post(struct symbol *sym)
- {
- const char *name = show_ident(sym->ident);
- struct function *f = current_func;
- int stack_size = f->stack_size;
- if (f->str_list)
- emit_string_list(f);
- /* function prologue */
- emit_section(".text");
- if ((sym->ctype.modifiers & MOD_STATIC) == 0)
- printf(".globl %s\n", name);
- printf("\t.type\t%s, @function\n", name);
- printf("%s:\n", name);
- if (stack_size) {
- char pseudo_const[16];
- sprintf(pseudo_const, "$%d", stack_size);
- printf("\tsubl\t%s, %%esp\n", pseudo_const);
- }
- /* function epilogue */
- /* jump target for 'return' statements */
- emit_label(f->ret_target, NULL);
- if (stack_size) {
- struct storage *val;
- val = new_storage(STOR_VALUE);
- val->value = (long long) (stack_size);
- val->flags = STOR_WANTS_FREE;
- insn("addl", val, REG_ESP, NULL);
- }
- insn("ret", NULL, NULL, NULL);
- /* output everything to stdout */
- fflush(stdout); /* paranoia; needed? */
- emit_atom_list(f);
- /* function footer */
- name = show_ident(sym->ident);
- printf("\t.size\t%s, .-%s\n", name, name);
- func_cleanup(f);
- current_func = NULL;
- }
- /* emit object (a.k.a. variable, a.k.a. data) prologue */
- static void emit_object_pre(const char *name, unsigned long modifiers,
- unsigned long alignment, unsigned int byte_size)
- {
- if ((modifiers & MOD_STATIC) == 0)
- printf(".globl %s\n", name);
- emit_section(".data");
- if (alignment)
- printf("\t.align %lu\n", alignment);
- printf("\t.type\t%s, @object\n", name);
- printf("\t.size\t%s, %d\n", name, byte_size);
- printf("%s:\n", name);
- }
- /* emit value (only) for an initializer scalar */
- static void emit_scalar(struct expression *expr, unsigned int bit_size)
- {
- const char *type;
- long long ll;
- assert(expr->type == EXPR_VALUE);
- if (expr->value == 0ULL) {
- printf("\t.zero\t%d\n", bit_size / 8);
- return;
- }
- ll = (long long) expr->value;
- switch (bit_size) {
- case 8: type = "byte"; ll = (char) ll; break;
- case 16: type = "value"; ll = (short) ll; break;
- case 32: type = "long"; ll = (int) ll; break;
- case 64: type = "quad"; break;
- default: type = NULL; break;
- }
- assert(type != NULL);
- printf("\t.%s\t%lld\n", type, ll);
- }
- static void emit_global_noinit(const char *name, unsigned long modifiers,
- unsigned long alignment, unsigned int byte_size)
- {
- char s[64];
- if (modifiers & MOD_STATIC) {
- sprintf(s, "\t.local\t%s\n", name);
- textbuf_push(&unit_post_text, s);
- }
- if (alignment)
- sprintf(s, "\t.comm\t%s,%d,%lu\n", name, byte_size, alignment);
- else
- sprintf(s, "\t.comm\t%s,%d\n", name, byte_size);
- textbuf_push(&unit_post_text, s);
- }
- static int ea_current, ea_last;
- static void emit_initializer(struct symbol *sym,
- struct expression *expr)
- {
- int distance = ea_current - ea_last - 1;
- if (distance > 0)
- printf("\t.zero\t%d\n", (sym->bit_size / 8) * distance);
- if (expr->type == EXPR_VALUE) {
- struct symbol *base_type = sym->ctype.base_type;
- assert(base_type != NULL);
- emit_scalar(expr, sym->bit_size / get_expression_value(base_type->array_size));
- return;
- }
- if (expr->type != EXPR_INITIALIZER)
- return;
- assert(0); /* FIXME */
- }
- static int sort_array_cmp(const struct expression *a,
- const struct expression *b)
- {
- int a_ofs = 0, b_ofs = 0;
- if (a->type == EXPR_POS)
- a_ofs = (int) a->init_offset;
- if (b->type == EXPR_POS)
- b_ofs = (int) b->init_offset;
- return a_ofs - b_ofs;
- }
- /* move to front-end? */
- static void sort_array(struct expression *expr)
- {
- struct expression *entry, **list;
- unsigned int elem, sorted, i;
- elem = expression_list_size(expr->expr_list);
- if (!elem)
- return;
- list = malloc(sizeof(entry) * elem);
- if (!list)
- die("OOM in sort_array");
- /* this code is no doubt evil and ignores EXPR_INDEX possibly
- * to its detriment and other nasty things. improvements
- * welcome.
- */
- i = 0;
- sorted = 0;
- FOR_EACH_PTR(expr->expr_list, entry) {
- if ((entry->type == EXPR_POS) || (entry->type == EXPR_VALUE)) {
- /* add entry to list[], in sorted order */
- if (sorted == 0) {
- list[0] = entry;
- sorted = 1;
- } else {
- for (i = 0; i < sorted; i++)
- if (sort_array_cmp(entry, list[i]) <= 0)
- break;
- /* If inserting into the middle of list[]
- * instead of appending, we memmove.
- * This is ugly, but thankfully
- * uncommon. Input data with tons of
- * entries very rarely have explicit
- * offsets. convert to qsort eventually...
- */
- if (i != sorted)
- memmove(&list[i + 1], &list[i],
- (sorted - i) * sizeof(entry));
- list[i] = entry;
- sorted++;
- }
- }
- } END_FOR_EACH_PTR(entry);
- i = 0;
- FOR_EACH_PTR(expr->expr_list, entry) {
- if ((entry->type == EXPR_POS) || (entry->type == EXPR_VALUE))
- *THIS_ADDRESS(entry) = list[i++];
- } END_FOR_EACH_PTR(entry);
- free(list);
- }
- static void emit_array(struct symbol *sym)
- {
- struct symbol *base_type = sym->ctype.base_type;
- struct expression *expr = sym->initializer;
- struct expression *entry;
- assert(base_type != NULL);
- stor_sym_init(sym);
- ea_last = -1;
- emit_object_pre(show_ident(sym->ident), sym->ctype.modifiers,
- sym->ctype.alignment,
- sym->bit_size / 8);
- sort_array(expr);
- FOR_EACH_PTR(expr->expr_list, entry) {
- if (entry->type == EXPR_VALUE) {
- ea_current = 0;
- emit_initializer(sym, entry);
- ea_last = ea_current;
- } else if (entry->type == EXPR_POS) {
- ea_current =
- entry->init_offset / (base_type->bit_size / 8);
- emit_initializer(sym, entry->init_expr);
- ea_last = ea_current;
- }
- } END_FOR_EACH_PTR(entry);
- }
- void emit_one_symbol(struct symbol *sym)
- {
- x86_symbol(sym);
- }
- static void emit_copy(struct storage *dest, struct storage *src,
- struct symbol *ctype)
- {
- struct storage *reg = NULL;
- unsigned int bit_size;
- /* FIXME: Bitfield copy! */
- bit_size = src->size * 8;
- if (!bit_size)
- bit_size = 32;
- if ((src->type == STOR_ARG) && (bit_size < 32))
- bit_size = 32;
- reg = temp_from_bits(bit_size);
- emit_move(src, reg, ctype, "begin copy ..");
- bit_size = dest->size * 8;
- if (!bit_size)
- bit_size = 32;
- if ((dest->type == STOR_ARG) && (bit_size < 32))
- bit_size = 32;
- emit_move(reg, dest, ctype, ".... end copy");
- put_reg(reg);
- }
- static void emit_store(struct expression *dest_expr, struct storage *dest,
- struct storage *src, int bits)
- {
- /* FIXME: Bitfield store! */
- printf("\tst.%d\t\tv%d,[v%d]\n", bits, src->pseudo, dest->pseudo);
- }
- static void emit_scalar_noinit(struct symbol *sym)
- {
- emit_global_noinit(show_ident(sym->ident),
- sym->ctype.modifiers, sym->ctype.alignment,
- sym->bit_size / 8);
- stor_sym_init(sym);
- }
- static void emit_array_noinit(struct symbol *sym)
- {
- emit_global_noinit(show_ident(sym->ident),
- sym->ctype.modifiers, sym->ctype.alignment,
- get_expression_value(sym->array_size) * (sym->bit_size / 8));
- stor_sym_init(sym);
- }
- static const char *opbits(const char *insn, unsigned int bits)
- {
- static char opbits_str[32];
- char c;
- switch (bits) {
- case 8: c = 'b'; break;
- case 16: c = 'w'; break;
- case 32: c = 'l'; break;
- case 64: c = 'q'; break;
- default: abort(); break;
- }
- sprintf(opbits_str, "%s%c", insn, c);
- return opbits_str;
- }
- static void emit_move(struct storage *src, struct storage *dest,
- struct symbol *ctype, const char *comment)
- {
- unsigned int bits;
- unsigned int is_signed;
- unsigned int is_dest = (src->type == STOR_REG);
- const char *opname;
- if (ctype) {
- bits = ctype->bit_size;
- is_signed = is_signed_type(ctype);
- } else {
- bits = 32;
- is_signed = 0;
- }
- /*
- * Are we moving from a register to a register?
- * Make the new reg to be the "cache".
- */
- if ((dest->type == STOR_REG) && (src->type == STOR_REG)) {
- struct storage *backing;
- reg_reg_move:
- if (dest == src)
- return;
- backing = src->reg->contains;
- if (backing) {
- /* Is it still valid? */
- if (backing->reg != src->reg)
- backing = NULL;
- else
- backing->reg = dest->reg;
- }
- dest->reg->contains = backing;
- insn("mov", src, dest, NULL);
- return;
- }
- /*
- * Are we moving to a register from a non-reg?
- *
- * See if we have the non-reg source already cached
- * in a register..
- */
- if (dest->type == STOR_REG) {
- if (src->reg) {
- struct reg_info *info = src->reg;
- if (info->contains == src) {
- src = reginfo_reg(info);
- goto reg_reg_move;
- }
- }
- dest->reg->contains = src;
- src->reg = dest->reg;
- }
- if (src->type == STOR_REG) {
- /* We could just mark the register dirty here and do lazy store.. */
- src->reg->contains = dest;
- dest->reg = src->reg;
- }
- if ((bits == 8) || (bits == 16)) {
- if (is_dest)
- opname = "mov";
- else
- opname = is_signed ? "movsx" : "movzx";
- } else
- opname = "mov";
- insn(opbits(opname, bits), src, dest, comment);
- }
- static struct storage *emit_compare(struct expression *expr)
- {
- struct storage *left = x86_expression(expr->left);
- struct storage *right = x86_expression(expr->right);
- struct storage *reg1, *reg2;
- struct storage *new, *val;
- const char *opname = NULL;
- unsigned int right_bits = expr->right->ctype->bit_size;
- switch(expr->op) {
- case '<': opname = "setl"; break;
- case '>': opname = "setg"; break;
- case SPECIAL_LTE:
- opname = "setle"; break;
- case SPECIAL_GTE:
- opname = "setge"; break;
- case SPECIAL_EQUAL: opname = "sete"; break;
- case SPECIAL_NOTEQUAL: opname = "setne"; break;
- case SPECIAL_UNSIGNED_LT:
- opname = "setb"; break;
- case SPECIAL_UNSIGNED_GT:
- opname = "seta"; break;
- case SPECIAL_UNSIGNED_LTE:
- opname = "setb"; break;
- case SPECIAL_UNSIGNED_GTE:
- opname = "setae"; break;
- default:
- assert(0);
- break;
- }
- /* init EDX to 0 */
- val = new_storage(STOR_VALUE);
- val->flags = STOR_WANTS_FREE;
- reg1 = get_reg(®class_32_8);
- emit_move(val, reg1, NULL, NULL);
- /* move op1 into EAX */
- reg2 = get_reg_value(left, get_regclass(expr->left));
- /* perform comparison, RHS (op1, right) and LHS (op2, EAX) */
- insn(opbits("cmp", right_bits), right, reg2, NULL);
- put_reg(reg2);
- /* store result of operation, 0 or 1, in DL using SETcc */
- insn(opname, byte_reg(reg1), NULL, NULL);
- /* finally, store the result (DL) in a new pseudo / stack slot */
- new = stack_alloc(4);
- emit_move(reg1, new, NULL, "end EXPR_COMPARE");
- put_reg(reg1);
- return new;
- }
- static struct storage *emit_value(struct expression *expr)
- {
- #if 0 /* old and slow way */
- struct storage *new = stack_alloc(4);
- struct storage *val;
- val = new_storage(STOR_VALUE);
- val->value = (long long) expr->value;
- val->flags = STOR_WANTS_FREE;
- insn("movl", val, new, NULL);
- return new;
- #else
- struct storage *val;
- val = new_storage(STOR_VALUE);
- val->value = (long long) expr->value;
- return val; /* FIXME: memory leak */
- #endif
- }
- static struct storage *emit_divide(struct expression *expr, struct storage *left, struct storage *right)
- {
- struct storage *eax_edx;
- struct storage *reg, *new;
- struct storage *val = new_storage(STOR_VALUE);
- emit_comment("begin DIVIDE");
- eax_edx = get_hardreg(hardreg_storage_table + EAX_EDX, 1);
- /* init EDX to 0 */
- val->flags = STOR_WANTS_FREE;
- emit_move(val, REG_EDX, NULL, NULL);
- new = stack_alloc(expr->ctype->bit_size / 8);
- /* EAX is dividend */
- emit_move(left, REG_EAX, NULL, NULL);
- reg = get_reg_value(right, ®class_32);
- /* perform binop */
- insn("div", reg, REG_EAX, NULL);
- put_reg(reg);
- reg = REG_EAX;
- if (expr->op == '%')
- reg = REG_EDX;
- emit_move(reg, new, NULL, NULL);
- put_reg(eax_edx);
- emit_comment("end DIVIDE");
- return new;
- }
- static struct storage *emit_binop(struct expression *expr)
- {
- struct storage *left = x86_expression(expr->left);
- struct storage *right = x86_expression(expr->right);
- struct storage *new;
- struct storage *dest, *src;
- const char *opname = NULL;
- const char *suffix = NULL;
- char opstr[16];
- int is_signed;
- /* Divides have special register constraints */
- if ((expr->op == '/') || (expr->op == '%'))
- return emit_divide(expr, left, right);
- is_signed = is_signed_type(expr->ctype);
- switch (expr->op) {
- case '+':
- opname = "add";
- break;
- case '-':
- opname = "sub";
- break;
- case '&':
- opname = "and";
- break;
- case '|':
- opname = "or";
- break;
- case '^':
- opname = "xor";
- break;
- case SPECIAL_LEFTSHIFT:
- opname = "shl";
- break;
- case SPECIAL_RIGHTSHIFT:
- if (is_signed)
- opname = "sar";
- else
- opname = "shr";
- break;
- case '*':
- if (is_signed)
- opname = "imul";
- else
- opname = "mul";
- break;
- case SPECIAL_LOGICAL_AND:
- warning(expr->pos, "bogus bitwise and for logical op (should use '2*setne + and' or something)");
- opname = "and";
- break;
- case SPECIAL_LOGICAL_OR:
- warning(expr->pos, "bogus bitwise or for logical op (should use 'or + setne' or something)");
- opname = "or";
- break;
- default:
- error_die(expr->pos, "unhandled binop '%s'\n", show_special(expr->op));
- break;
- }
- dest = get_reg_value(right, ®class_32);
- src = get_reg_value(left, ®class_32);
- switch (expr->ctype->bit_size) {
- case 8:
- suffix = "b";
- break;
- case 16:
- suffix = "w";
- break;
- case 32:
- suffix = "l";
- break;
- case 64:
- suffix = "q"; /* FIXME */
- break;
- default:
- assert(0);
- break;
- }
- snprintf(opstr, sizeof(opstr), "%s%s", opname, suffix);
- /* perform binop */
- insn(opstr, src, dest, NULL);
- put_reg(src);
- /* store result in new pseudo / stack slot */
- new = stack_alloc(expr->ctype->bit_size / 8);
- emit_move(dest, new, NULL, "end EXPR_BINOP");
- put_reg(dest);
- return new;
- }
- static int emit_conditional_test(struct storage *val)
- {
- struct storage *reg;
- struct storage *target_val;
- int target_false;
- /* load result into EAX */
- emit_comment("begin if/conditional");
- reg = get_reg_value(val, ®class_32);
- /* compare result with zero */
- insn("test", reg, reg, NULL);
- put_reg(reg);
- /* create conditional-failed label to jump to */
- target_false = new_label();
- target_val = new_storage(STOR_LABEL);
- target_val->label = target_false;
- target_val->flags = STOR_WANTS_FREE;
- insn("jz", target_val, NULL, NULL);
- return target_false;
- }
- static int emit_conditional_end(int target_false)
- {
- struct storage *cond_end_st;
- int cond_end;
- /* finished generating code for if-true statement.
- * add a jump-to-end jump to avoid falling through
- * to the if-false statement code.
- */
- cond_end = new_label();
- cond_end_st = new_storage(STOR_LABEL);
- cond_end_st->label = cond_end;
- cond_end_st->flags = STOR_WANTS_FREE;
- insn("jmp", cond_end_st, NULL, NULL);
- /* if we have both if-true and if-false statements,
- * the failed-conditional case will fall through to here
- */
- emit_label(target_false, NULL);
- return cond_end;
- }
- static void emit_if_conditional(struct statement *stmt)
- {
- struct storage *val;
- int cond_end;
- /* emit test portion of conditional */
- val = x86_expression(stmt->if_conditional);
- cond_end = emit_conditional_test(val);
- /* emit if-true statement */
- x86_statement(stmt->if_true);
- /* emit if-false statement, if present */
- if (stmt->if_false) {
- cond_end = emit_conditional_end(cond_end);
- x86_statement(stmt->if_false);
- }
- /* end of conditional; jump target for if-true branch */
- emit_label(cond_end, "end if");
- }
- static struct storage *emit_inc_dec(struct expression *expr, int postop)
- {
- struct storage *addr = x86_address_gen(expr->unop);
- struct storage *retval;
- char opname[16];
- strcpy(opname, opbits(expr->op == SPECIAL_INCREMENT ? "inc" : "dec",
- expr->ctype->bit_size));
- if (postop) {
- struct storage *new = stack_alloc(4);
- emit_copy(new, addr, expr->unop->ctype);
- retval = new;
- } else
- retval = addr;
- insn(opname, addr, NULL, NULL);
- return retval;
- }
- static struct storage *emit_postop(struct expression *expr)
- {
- return emit_inc_dec(expr, 1);
- }
- static struct storage *emit_return_stmt(struct statement *stmt)
- {
- struct function *f = current_func;
- struct expression *expr = stmt->ret_value;
- struct storage *val = NULL, *jmplbl;
- if (expr && expr->ctype) {
- val = x86_expression(expr);
- assert(val != NULL);
- emit_move(val, REG_EAX, expr->ctype, "return");
- }
- jmplbl = new_storage(STOR_LABEL);
- jmplbl->flags |= STOR_WANTS_FREE;
- jmplbl->label = f->ret_target;
- insn("jmp", jmplbl, NULL, NULL);
- return val;
- }
- static struct storage *emit_conditional_expr(struct expression *expr)
- {
- struct storage *cond, *stot = NULL, *stof = NULL;
- struct storage *new = stack_alloc(expr->ctype->bit_size / 8);
- int target_false, cond_end;
- /* evaluate conditional */
- cond = x86_expression(expr->conditional);
- target_false = emit_conditional_test(cond);
- /* handle if-true part of the expression */
- stot = x86_expression(expr->cond_true);
- emit_copy(new, stot, expr->ctype);
- cond_end = emit_conditional_end(target_false);
- /* handle if-false part of the expression */
- stof = x86_expression(expr->cond_false);
- emit_copy(new, stof, expr->ctype);
- /* end of conditional; jump target for if-true branch */
- emit_label(cond_end, "end conditional");
- return new;
- }
- static struct storage *emit_select_expr(struct expression *expr)
- {
- struct storage *cond = x86_expression(expr->conditional);
- struct storage *stot = x86_expression(expr->cond_true);
- struct storage *stof = x86_expression(expr->cond_false);
- struct storage *reg_cond, *reg_true, *reg_false;
- struct storage *new = stack_alloc(4);
- emit_comment("begin SELECT");
- reg_cond = get_reg_value(cond, get_regclass(expr->conditional));
- reg_true = get_reg_value(stot, get_regclass(expr));
- reg_false = get_reg_value(stof, get_regclass(expr));
- /*
- * Do the actual select: check the conditional for zero,
- * move false over true if zero
- */
- insn("test", reg_cond, reg_cond, NULL);
- insn("cmovz", reg_false, reg_true, NULL);
- /* Store it back */
- emit_move(reg_true, new, expr->ctype, NULL);
- put_reg(reg_cond);
- put_reg(reg_true);
- put_reg(reg_false);
- emit_comment("end SELECT");
- return new;
- }
- static struct storage *emit_symbol_expr_init(struct symbol *sym)
- {
- struct expression *expr = sym->initializer;
- struct symbol_private *priv = sym->aux;
- if (priv == NULL) {
- priv = calloc(1, sizeof(*priv));
- sym->aux = priv;
- if (expr == NULL) {
- struct storage *new = stack_alloc(4);
- fprintf(stderr, "FIXME! no value for symbol %s. creating pseudo %d (stack offset %d)\n",
- show_ident(sym->ident),
- new->pseudo, new->pseudo * 4);
- priv->addr = new;
- } else {
- priv->addr = x86_expression(expr);
- }
- }
- return priv->addr;
- }
- static struct storage *emit_string_expr(struct expression *expr)
- {
- struct function *f = current_func;
- int label = new_label();
- struct storage *new;
- push_cstring(f, expr->string, label);
- new = new_storage(STOR_LABEL);
- new->label = label;
- new->flags = STOR_LABEL_VAL | STOR_WANTS_FREE;
- return new;
- }
- static struct storage *emit_cast_expr(struct expression *expr)
- {
- struct symbol *old_type, *new_type;
- struct storage *op = x86_expression(expr->cast_expression);
- int oldbits, newbits;
- struct storage *new;
- old_type = expr->cast_expression->ctype;
- new_type = expr->cast_type;
- oldbits = old_type->bit_size;
- newbits = new_type->bit_size;
- if (oldbits >= newbits)
- return op;
- emit_move(op, REG_EAX, old_type, "begin cast ..");
- new = stack_alloc(newbits / 8);
- emit_move(REG_EAX, new, new_type, ".... end cast");
- return new;
- }
- static struct storage *emit_regular_preop(struct expression *expr)
- {
- struct storage *target = x86_expression(expr->unop);
- struct storage *val, *new = stack_alloc(4);
- const char *opname = NULL;
- switch (expr->op) {
- case '!':
- val = new_storage(STOR_VALUE);
- val->flags = STOR_WANTS_FREE;
- emit_move(val, REG_EDX, NULL, NULL);
- emit_move(target, REG_EAX, expr->unop->ctype, NULL);
- insn("test", REG_EAX, REG_EAX, NULL);
- insn("setz", REG_DL, NULL, NULL);
- emit_move(REG_EDX, new, expr->unop->ctype, NULL);
- break;
- case '~':
- opname = "not";
- case '-':
- if (!opname)
- opname = "neg";
- emit_move(target, REG_EAX, expr->unop->ctype, NULL);
- insn(opname, REG_EAX, NULL, NULL);
- emit_move(REG_EAX, new, expr->unop->ctype, NULL);
- break;
- default:
- assert(0);
- break;
- }
- return new;
- }
- static void emit_case_statement(struct statement *stmt)
- {
- emit_labelsym(stmt->case_label, NULL);
- x86_statement(stmt->case_statement);
- }
- static void emit_switch_statement(struct statement *stmt)
- {
- struct storage *val = x86_expression(stmt->switch_expression);
- struct symbol *sym, *default_sym = NULL;
- struct storage *labelsym, *label;
- int switch_end = 0;
- emit_move(val, REG_EAX, stmt->switch_expression->ctype, "begin case");
- /*
- * This is where a _real_ back-end would go through the
- * cases to decide whether to use a lookup table or a
- * series of comparisons etc
- */
- FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) {
- struct statement *case_stmt = sym->stmt;
- struct expression *expr = case_stmt->case_expression;
- struct expression *to = case_stmt->case_to;
- /* default: */
- if (!expr)
- default_sym = sym;
- /* case NNN: */
- else {
- struct storage *case_val = new_val(expr->value);
- assert (expr->type == EXPR_VALUE);
- insn("cmpl", case_val, REG_EAX, NULL);
- if (!to) {
- labelsym = new_labelsym(sym);
- insn("je", labelsym, NULL, NULL);
- } else {
- int next_test;
- label = new_storage(STOR_LABEL);
- label->flags |= STOR_WANTS_FREE;
- label->label = next_test = new_label();
- /* FIXME: signed/unsigned */
- insn("jl", label, NULL, NULL);
- case_val = new_val(to->value);
- insn("cmpl", case_val, REG_EAX, NULL);
- /* TODO: implement and use refcounting... */
- label = new_storage(STOR_LABEL);
- label->flags |= STOR_WANTS_FREE;
- label->label = next_test;
- /* FIXME: signed/unsigned */
- insn("jg", label, NULL, NULL);
- labelsym = new_labelsym(sym);
- insn("jmp", labelsym, NULL, NULL);
- emit_label(next_test, NULL);
- }
- }
- } END_FOR_EACH_PTR(sym);
- if (default_sym) {
- labelsym = new_labelsym(default_sym);
- insn("jmp", labelsym, NULL, "default");
- } else {
- label = new_storage(STOR_LABEL);
- label->flags |= STOR_WANTS_FREE;
- label->label = switch_end = new_label();
- insn("jmp", label, NULL, "goto end of switch");
- }
- x86_statement(stmt->switch_statement);
- if (stmt->switch_break->used)
- emit_labelsym(stmt->switch_break, NULL);
- if (switch_end)
- emit_label(switch_end, NULL);
- }
- static void x86_struct_member(struct symbol *sym)
- {
- printf("\t%s:%d:%ld at offset %ld.%d", show_ident(sym->ident), sym->bit_size, sym->ctype.alignment, sym->offset, sym->bit_offset);
- printf("\n");
- }
- static void x86_symbol(struct symbol *sym)
- {
- struct symbol *type;
- if (!sym)
- return;
- type = sym->ctype.base_type;
- if (!type)
- return;
- /*
- * Show actual implementation information
- */
- switch (type->type) {
- case SYM_ARRAY:
- if (sym->initializer)
- emit_array(sym);
- else
- emit_array_noinit(sym);
- break;
- case SYM_BASETYPE:
- if (sym->initializer) {
- emit_object_pre(show_ident(sym->ident),
- sym->ctype.modifiers,
- sym->ctype.alignment,
- sym->bit_size / 8);
- emit_scalar(sym->initializer, sym->bit_size);
- stor_sym_init(sym);
- } else
- emit_scalar_noinit(sym);
- break;
- case SYM_STRUCT:
- case SYM_UNION: {
- struct symbol *member;
- printf(" {\n");
- FOR_EACH_PTR(type->symbol_list, member) {
- x86_struct_member(member);
- } END_FOR_EACH_PTR(member);
- printf("}\n");
- break;
- }
- case SYM_FN: {
- struct statement *stmt = type->stmt;
- if (stmt) {
- emit_func_pre(sym);
- x86_statement(stmt);
- emit_func_post(sym);
- }
- break;
- }
- default:
- break;
- }
- if (sym->initializer && (type->type != SYM_BASETYPE) &&
- (type->type != SYM_ARRAY)) {
- printf(" = \n");
- x86_expression(sym->initializer);
- }
- }
- static void x86_symbol_init(struct symbol *sym);
- static void x86_symbol_decl(struct symbol_list *syms)
- {
- struct symbol *sym;
- FOR_EACH_PTR(syms, sym) {
- x86_symbol_init(sym);
- } END_FOR_EACH_PTR(sym);
- }
- static void loopstk_push(int cont_lbl, int loop_bottom_lbl)
- {
- struct function *f = current_func;
- struct loop_stack *ls;
- ls = malloc(sizeof(*ls));
- ls->continue_lbl = cont_lbl;
- ls->loop_bottom_lbl = loop_bottom_lbl;
- ls->next = f->loop_stack;
- f->loop_stack = ls;
- }
- static void loopstk_pop(void)
- {
- struct function *f = current_func;
- struct loop_stack *ls;
- assert(f->loop_stack != NULL);
- ls = f->loop_stack;
- f->loop_stack = f->loop_stack->next;
- free(ls);
- }
- static int loopstk_break(void)
- {
- return current_func->loop_stack->loop_bottom_lbl;
- }
- static int loopstk_continue(void)
- {
- return current_func->loop_stack->continue_lbl;
- }
- static void emit_loop(struct statement *stmt)
- {
- struct statement *pre_statement = stmt->iterator_pre_statement;
- struct expression *pre_condition = stmt->iterator_pre_condition;
- struct statement *statement = stmt->iterator_statement;
- struct statement *post_statement = stmt->iterator_post_statement;
- struct expression *post_condition = stmt->iterator_post_condition;
- int loop_top = 0, loop_bottom, loop_continue;
- int have_bottom = 0;
- struct storage *val;
- loop_bottom = new_label();
- loop_continue = new_label();
- loopstk_push(loop_continue, loop_bottom);
- x86_symbol_decl(stmt->iterator_syms);
- x86_statement(pre_statement);
- if (!post_condition || post_condition->type != EXPR_VALUE || post_condition->value) {
- loop_top = new_label();
- emit_label(loop_top, "loop top");
- }
- if (pre_condition) {
- if (pre_condition->type == EXPR_VALUE) {
- if (!pre_condition->value) {
- struct storage *lbv;
- lbv = new_storage(STOR_LABEL);
- lbv->label = loop_bottom;
- lbv->flags = STOR_WANTS_FREE;
- insn("jmp", lbv, NULL, "go to loop bottom");
- have_bottom = 1;
- }
- } else {
- struct storage *lbv = new_storage(STOR_LABEL);
- lbv->label = loop_bottom;
- lbv->flags = STOR_WANTS_FREE;
- have_bottom = 1;
- val = x86_expression(pre_condition);
- emit_move(val, REG_EAX, NULL, "loop pre condition");
- insn("test", REG_EAX, REG_EAX, NULL);
- insn("jz", lbv, NULL, NULL);
- }
- }
- x86_statement(statement);
- if (stmt->iterator_continue->used)
- emit_label(loop_continue, "'continue' iterator");
- x86_statement(post_statement);
- if (!post_condition) {
- struct storage *lbv = new_storage(STOR_LABEL);
- lbv->label = loop_top;
- lbv->flags = STOR_WANTS_FREE;
- insn("jmp", lbv, NULL, "go to loop top");
- } else if (post_condition->type == EXPR_VALUE) {
- if (post_condition->value) {
- struct storage *lbv = new_storage(STOR_LABEL);
- lbv->label = loop_top;
- lbv->flags = STOR_WANTS_FREE;
- insn("jmp", lbv, NULL, "go to loop top");
- }
- } else {
- struct storage *lbv = new_storage(STOR_LABEL);
- lbv->label = loop_top;
- lbv->flags = STOR_WANTS_FREE;
- val = x86_expression(post_condition);
- emit_move(val, REG_EAX, NULL, "loop post condition");
- insn("test", REG_EAX, REG_EAX, NULL);
- insn("jnz", lbv, NULL, NULL);
- }
- if (have_bottom || stmt->iterator_break->used)
- emit_label(loop_bottom, "loop bottom");
- loopstk_pop();
- }
- /*
- * Print out a statement
- */
- static struct storage *x86_statement(struct statement *stmt)
- {
- if (!stmt)
- return NULL;
- switch (stmt->type) {
- default:
- return NULL;
- case STMT_RETURN:
- return emit_return_stmt(stmt);
- case STMT_DECLARATION:
- x86_symbol_decl(stmt->declaration);
- break;
- case STMT_COMPOUND: {
- struct statement *s;
- struct storage *last = NULL;
- FOR_EACH_PTR(stmt->stmts, s) {
- last = x86_statement(s);
- } END_FOR_EACH_PTR(s);
- return last;
- }
- case STMT_EXPRESSION:
- return x86_expression(stmt->expression);
- case STMT_IF:
- emit_if_conditional(stmt);
- return NULL;
- case STMT_CASE:
- emit_case_statement(stmt);
- break;
- case STMT_SWITCH:
- emit_switch_statement(stmt);
- break;
- case STMT_ITERATOR:
- emit_loop(stmt);
- break;
- case STMT_NONE:
- break;
- case STMT_LABEL:
- printf(".L%p:\n", stmt->label_identifier);
- x86_statement(stmt->label_statement);
- break;
- case STMT_GOTO:
- if (stmt->goto_expression) {
- struct storage *val = x86_expression(stmt->goto_expression);
- printf("\tgoto *v%d\n", val->pseudo);
- } else if (!strcmp("break", show_ident(stmt->goto_label->ident))) {
- struct storage *lbv = new_storage(STOR_LABEL);
- lbv->label = loopstk_break();
- lbv->flags = STOR_WANTS_FREE;
- insn("jmp", lbv, NULL, "'break'; go to loop bottom");
- } else if (!strcmp("continue", show_ident(stmt->goto_label->ident))) {
- struct storage *lbv = new_storage(STOR_LABEL);
- lbv->label = loopstk_continue();
- lbv->flags = STOR_WANTS_FREE;
- insn("jmp", lbv, NULL, "'continue'; go to loop top");
- } else {
- struct storage *labelsym = new_labelsym(stmt->goto_label);
- insn("jmp", labelsym, NULL, NULL);
- }
- break;
- case STMT_ASM:
- printf("\tasm( .... )\n");
- break;
- }
- return NULL;
- }
- static struct storage *x86_call_expression(struct expression *expr)
- {
- struct function *f = current_func;
- struct symbol *direct;
- struct expression *arg, *fn;
- struct storage *retval, *fncall;
- int framesize;
- char s[64];
- if (!expr->ctype) {
- warning(expr->pos, "\tcall with no type!");
- return NULL;
- }
- framesize = 0;
- FOR_EACH_PTR_REVERSE(expr->args, arg) {
- struct storage *new = x86_expression(arg);
- int size = arg->ctype->bit_size;
- /*
- * FIXME: i386 SysV ABI dictates that values
- * smaller than 32 bits should be placed onto
- * the stack as 32-bit objects. We should not
- * blindly do a 32-bit push on objects smaller
- * than 32 bits.
- */
- if (size < 32)
- size = 32;
- insn("pushl", new, NULL,
- !framesize ? "begin function call" : NULL);
- framesize += bits_to_bytes(size);
- } END_FOR_EACH_PTR_REVERSE(arg);
- fn = expr->fn;
- /* Remove dereference, if any */
- direct = NULL;
- if (fn->type == EXPR_PREOP) {
- if (fn->unop->type == EXPR_SYMBOL) {
- struct symbol *sym = fn->unop->symbol;
- if (sym->ctype.base_type->type == SYM_FN)
- direct = sym;
- }
- }
- if (direct) {
- struct storage *direct_stor = new_storage(STOR_SYM);
- direct_stor->flags |= STOR_WANTS_FREE;
- direct_stor->sym = direct;
- insn("call", direct_stor, NULL, NULL);
- } else {
- fncall = x86_expression(fn);
- emit_move(fncall, REG_EAX, fn->ctype, NULL);
- strcpy(s, "\tcall\t*%eax\n");
- push_text_atom(f, s);
- }
- /* FIXME: pay attention to BITS_IN_POINTER */
- if (framesize) {
- struct storage *val = new_storage(STOR_VALUE);
- val->value = (long long) framesize;
- val->flags = STOR_WANTS_FREE;
- insn("addl", val, REG_ESP, NULL);
- }
- retval = stack_alloc(4);
- emit_move(REG_EAX, retval, NULL, "end function call");
- return retval;
- }
- static struct storage *x86_address_gen(struct expression *expr)
- {
- struct function *f = current_func;
- struct storage *addr;
- struct storage *new;
- char s[32];
- addr = x86_expression(expr->unop);
- if (expr->unop->type == EXPR_SYMBOL)
- return addr;
- emit_move(addr, REG_EAX, NULL, "begin deref ..");
- /* FIXME: operand size */
- strcpy(s, "\tmovl\t(%eax), %ecx\n");
- push_text_atom(f, s);
- new = stack_alloc(4);
- emit_move(REG_ECX, new, NULL, ".... end deref");
- return new;
- }
- static struct storage *x86_assignment(struct expression *expr)
- {
- struct expression *target = expr->left;
- struct storage *val, *addr;
- if (!expr->ctype)
- return NULL;
- val = x86_expression(expr->right);
- addr = x86_address_gen(target);
- switch (val->type) {
- /* copy, where both operands are memory */
- case STOR_PSEUDO:
- case STOR_ARG:
- emit_copy(addr, val, expr->ctype);
- break;
- /* copy, one or zero operands are memory */
- case STOR_REG:
- case STOR_SYM:
- case STOR_VALUE:
- case STOR_LABEL:
- emit_move(val, addr, expr->left->ctype, NULL);
- break;
- case STOR_LABELSYM:
- assert(0);
- break;
- }
- return val;
- }
- static int x86_initialization(struct symbol *sym, struct expression *expr)
- {
- struct storage *val, *addr;
- int bits;
- if (!expr->ctype)
- return 0;
- bits = expr->ctype->bit_size;
- val = x86_expression(expr);
- addr = x86_symbol_expr(sym);
- // FIXME! The "target" expression is for bitfield store information.
- // Leave it NULL, which works fine.
- emit_store(NULL, addr, val, bits);
- return 0;
- }
- static struct storage *x86_access(struct expression *expr)
- {
- return x86_address_gen(expr);
- }
- static struct storage *x86_preop(struct expression *expr)
- {
- /*
- * '*' is an lvalue access, and is fundamentally different
- * from an arithmetic operation. Maybe it should have an
- * expression type of its own..
- */
- if (expr->op == '*')
- return x86_access(expr);
- if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
- return emit_inc_dec(expr, 0);
- return emit_regular_preop(expr);
- }
- static struct storage *x86_symbol_expr(struct symbol *sym)
- {
- struct storage *new = stack_alloc(4);
- if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_EXTERN | MOD_STATIC)) {
- printf("\tmovi.%d\t\tv%d,$%s\n", bits_in_pointer, new->pseudo, show_ident(sym->ident));
- return new;
- }
- if (sym->ctype.modifiers & MOD_ADDRESSABLE) {
- printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new->pseudo, 0LL);
- return new;
- }
- printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", bits_in_pointer, new->pseudo, show_ident(sym->ident), sym);
- return new;
- }
- static void x86_symbol_init(struct symbol *sym)
- {
- struct symbol_private *priv = sym->aux;
- struct expression *expr = sym->initializer;
- struct storage *new;
- if (expr)
- new = x86_expression(expr);
- else
- new = stack_alloc(sym->bit_size / 8);
- if (!priv) {
- priv = calloc(1, sizeof(*priv));
- sym->aux = priv;
- /* FIXME: leak! we don't free... */
- /* (well, we don't free symbols either) */
- }
- priv->addr = new;
- }
- static struct storage *x86_label_expr(struct expression *expr)
- {
- struct storage *new = stack_alloc(4);
- printf("\tmovi.%d\t\tv%d,.L%p\n", bits_in_pointer, new->pseudo, expr->label_symbol);
- return new;
- }
- static struct storage *x86_statement_expr(struct expression *expr)
- {
- return x86_statement(expr->statement);
- }
- static int x86_position_expr(struct expression *expr, struct symbol *base)
- {
- struct storage *new = x86_expression(expr->init_expr);
- struct symbol *ctype = expr->init_expr->ctype;
- printf("\tinsert v%d at [%d:%d] of %s\n", new->pseudo,
- expr->init_offset, ctype->bit_offset,
- show_ident(base->ident));
- return 0;
- }
- static void x86_initializer_expr(struct expression *expr, struct symbol *ctype)
- {
- struct expression *entry;
- FOR_EACH_PTR(expr->expr_list, entry) {
- // Nested initializers have their positions already
- // recursively calculated - just output them too
- if (entry->type == EXPR_INITIALIZER) {
- x86_initializer_expr(entry, ctype);
- continue;
- }
- // Ignore initializer indexes and identifiers - the
- // evaluator has taken them into account
- if (entry->type == EXPR_IDENTIFIER || entry->type == EXPR_INDEX)
- continue;
- if (entry->type == EXPR_POS) {
- x86_position_expr(entry, ctype);
- continue;
- }
- x86_initialization(ctype, entry);
- } END_FOR_EACH_PTR(entry);
- }
- /*
- * Print out an expression. Return the pseudo that contains the
- * variable.
- */
- static struct storage *x86_expression(struct expression *expr)
- {
- if (!expr)
- return NULL;
- if (!expr->ctype) {
- struct position *pos = &expr->pos;
- printf("\tno type at %s:%d:%d\n",
- stream_name(pos->stream),
- pos->line, pos->pos);
- return NULL;
- }
- switch (expr->type) {
- default:
- return NULL;
- case EXPR_CALL:
- return x86_call_expression(expr);
- case EXPR_ASSIGNMENT:
- return x86_assignment(expr);
- case EXPR_COMPARE:
- return emit_compare(expr);
- case EXPR_BINOP:
- case EXPR_COMMA:
- case EXPR_LOGICAL:
- return emit_binop(expr);
- case EXPR_PREOP:
- return x86_preop(expr);
- case EXPR_POSTOP:
- return emit_postop(expr);
- case EXPR_SYMBOL:
- return emit_symbol_expr_init(expr->symbol);
- case EXPR_DEREF:
- case EXPR_SIZEOF:
- case EXPR_ALIGNOF:
- warning(expr->pos, "invalid expression after evaluation");
- return NULL;
- case EXPR_CAST:
- case EXPR_FORCE_CAST:
- case EXPR_IMPLIED_CAST:
- return emit_cast_expr(expr);
- case EXPR_VALUE:
- return emit_value(expr);
- case EXPR_STRING:
- return emit_string_expr(expr);
- case EXPR_INITIALIZER:
- x86_initializer_expr(expr, expr->ctype);
- return NULL;
- case EXPR_SELECT:
- return emit_select_expr(expr);
- case EXPR_CONDITIONAL:
- return emit_conditional_expr(expr);
- case EXPR_STATEMENT:
- return x86_statement_expr(expr);
- case EXPR_LABEL:
- return x86_label_expr(expr);
- // None of these should exist as direct expressions: they are only
- // valid as sub-expressions of initializers.
- case EXPR_POS:
- warning(expr->pos, "unable to show plain initializer position expression");
- return NULL;
- case EXPR_IDENTIFIER:
- warning(expr->pos, "unable to show identifier expression");
- return NULL;
- case EXPR_INDEX:
- warning(expr->pos, "unable to show index expression");
- return NULL;
- case EXPR_TYPE:
- warning(expr->pos, "unable to show type expression");
- return NULL;
- case EXPR_FVALUE:
- warning(expr->pos, "floating point support is not implemented");
- return NULL;
- }
- return NULL;
- }
|