aboutsummaryrefslogtreecommitdiffstats
path: root/lcc/src
diff options
context:
space:
mode:
Diffstat (limited to 'lcc/src')
-rwxr-xr-xlcc/src/2html.c555
-rwxr-xr-xlcc/src/alloc.c94
-rwxr-xr-xlcc/src/alpha.md1192
-rwxr-xr-xlcc/src/asdl.c399
-rwxr-xr-xlcc/src/bind.c23
-rwxr-xr-xlcc/src/bytecode.c365
-rwxr-xr-xlcc/src/c.h723
-rwxr-xr-xlcc/src/config.h102
-rwxr-xr-xlcc/src/dag.c735
-rwxr-xr-xlcc/src/dagcheck.md210
-rwxr-xr-xlcc/src/decl.c1160
-rwxr-xr-xlcc/src/enode.c543
-rwxr-xr-xlcc/src/error.c137
-rwxr-xr-xlcc/src/event.c28
-rwxr-xr-xlcc/src/expr.c709
-rwxr-xr-xlcc/src/gen.c830
-rwxr-xr-xlcc/src/init.c318
-rwxr-xr-xlcc/src/inits.c8
-rwxr-xr-xlcc/src/input.c134
-rwxr-xr-xlcc/src/lex.c922
-rwxr-xr-xlcc/src/list.c56
-rwxr-xr-xlcc/src/main.c225
-rwxr-xr-xlcc/src/mips.md1120
-rwxr-xr-xlcc/src/null.c74
-rwxr-xr-xlcc/src/output.c134
-rwxr-xr-xlcc/src/pass2.c665
-rwxr-xr-xlcc/src/prof.c227
-rwxr-xr-xlcc/src/profio.c276
-rwxr-xr-xlcc/src/rcc.asdl70
-rwxr-xr-xlcc/src/run.sh51
-rwxr-xr-xlcc/src/simp.c587
-rwxr-xr-xlcc/src/sparc.md1163
-rwxr-xr-xlcc/src/stab.c330
-rwxr-xr-xlcc/src/stab.h113
-rwxr-xr-xlcc/src/stmt.c697
-rwxr-xr-xlcc/src/string.c122
-rwxr-xr-xlcc/src/sym.c315
-rwxr-xr-xlcc/src/symbolic.c494
-rwxr-xr-xlcc/src/token.h133
-rwxr-xr-xlcc/src/trace.c180
-rwxr-xr-xlcc/src/tree.c223
-rwxr-xr-xlcc/src/types.c748
-rwxr-xr-xlcc/src/x86.md998
-rwxr-xr-xlcc/src/x86linux.md1081
44 files changed, 19269 insertions, 0 deletions
diff --git a/lcc/src/2html.c b/lcc/src/2html.c
new file mode 100755
index 0000000..3c9b146
--- /dev/null
+++ b/lcc/src/2html.c
@@ -0,0 +1,555 @@
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "c.h"
+#include "rcc.h"
+#if WIN32
+#include <fcntl.h>
+#include <io.h>
+#endif
+
+
+static void do_int(int x) {
+ printf("%d", x);
+}
+
+static void do_scope(int x) {
+#define xx(c) if (x == c) { printf(#c); return; }
+ xx(CONSTANTS)
+ xx(LABELS)
+ xx(GLOBAL)
+ xx(PARAM)
+ xx(LOCAL)
+#undef xx
+ if (x > LOCAL)
+ printf("LOCAL+%d", x-LOCAL);
+ else
+ do_int(x);
+}
+
+static void do_sclass(int x) {
+#define xx(c) if (x == c) { printf(#c); return; }
+ xx(REGISTER)
+ xx(AUTO)
+ xx(EXTERN)
+ xx(STATIC)
+ xx(TYPEDEF)
+#undef xx
+ do_int(x);
+}
+
+static void do_flags(int x) {
+ char *bar = "";
+#define xx(f,n) if ((x>>n)&1) { printf("%s" #f, bar); bar = "|"; }
+ xx(structarg,0)
+ xx(addressed,1)
+ xx(computed,2)
+ xx(temporary,3)
+ xx(generated,4)
+#undef xx
+ if (*bar == '\0')
+ do_int(x);
+}
+
+static void do_seg(int x) {
+#define xx(s) if (x == s) { printf(#s); return; }
+ xx(CODE)
+ xx(BSS)
+ xx(DATA)
+ xx(LIT)
+#undef xx
+ do_int(x);
+}
+
+#define xx(ptr,field,type) do { printf("<li>" #field " = "); do_##type(ptr->field); printf("</li>\n"); } while (0)
+
+static void do_op(int x) {
+ static char *opnames[] = {
+ "",
+ "CNST",
+ "ARG",
+ "ASGN",
+ "INDIR",
+ "CVC",
+ "CVD",
+ "CVF",
+ "CVI",
+ "CVP",
+ "CVS",
+ "CVU",
+ "NEG",
+ "CALL",
+ "*LOAD*",
+ "RET",
+ "ADDRG",
+ "ADDRF",
+ "ADDRL",
+ "ADD",
+ "SUB",
+ "LSH",
+ "MOD",
+ "RSH",
+ "BAND",
+ "BCOM",
+ "BOR",
+ "BXOR",
+ "DIV",
+ "MUL",
+ "EQ",
+ "GE",
+ "GT",
+ "LE",
+ "LT",
+ "NE",
+ "JUMP",
+ "LABEL",
+ "AND",
+ "NOT",
+ "OR",
+ "COND",
+ "RIGHT",
+ "FIELD"
+ };
+ int op = opindex(x);
+ if (op < 1 || op >= sizeof opnames/sizeof opnames[0])
+ printf("%d", x);
+ else
+ printf("%s", opnames[op]);
+}
+
+static void do_define_uid(int x) {
+ printf("<strong id=uid%d>%d</strong>", x, x);
+}
+
+static void do_define_label(int x) {
+ printf("<strong id=ll%d>%d</strong>", x, x);
+}
+
+static void do_uid(int x) {
+ printf("<a href='#%d'>%d</a>", x, x, x);
+}
+
+static void do_label(int x) {
+ printf("<a href='#L%d'>%d</a>", x, x, x);
+}
+
+static int nextid;
+
+static void do_list(list_ty x, void do_one(void *), char *type, char *listhtml, char *separator) {
+ int count = Seq_length(x);
+
+ if (count == 0)
+ printf("<em>empty %s list</em>\n", type);
+ else {
+ int i;
+ printf("<em>%s list</em>", type);
+ if (listhtml != NULL)
+ printf("<%s>\n", listhtml);
+ for (i = 0; i < count; i++) {
+ if (listhtml != NULL)
+ printf("<li>");
+ printf(separator);
+ do_one(Seq_get(x, i));
+ if (listhtml != NULL)
+ printf("</li>\n");
+ }
+ if (listhtml != NULL)
+ printf("</%s>\n", listhtml);
+ }
+}
+
+static void do_uid_list(list_ty x) {
+ int i, count = Seq_length(x);
+
+ if (count == 0)
+ printf("<em>empty int list</em>\n");
+ else {
+ int i;
+ printf("<em>int list</em>");
+ for (i= 0; i < count; i++) {
+ printf(" ");
+ do_uid(*(int *)Seq_get(x, i));
+ }
+ }
+}
+
+static void do_identifier(const char *x) {
+ printf("%s", x);
+}
+
+static void do_real(rcc_real_ty x) {
+ double d;
+ unsigned *p = (unsigned *)&d;
+ static union { int x; char endian; } little = { 1 };
+
+ p[1-little.endian] = x->msb;
+ p[little.endian] = x->lsb;
+ printf("(%#X,%#X) = %g", x->msb, x->lsb, d);
+}
+
+static void do_suffix(int x) {
+ static char suffixes[] = "0F234IUPVB";
+
+ if (x < 0 || x >= (sizeof suffixes/sizeof suffixes[0]) - 1)
+ printf("%d", x);
+ else
+ printf("%c", suffixes[x]);
+}
+
+static void do_enum(void *x) {
+ rcc_enum__ty e = x;
+
+ do_identifier(e->id);
+ printf("=");
+ do_int(e->value);
+}
+
+static void do_enum_list(list_ty x) {
+ do_list(x, do_enum, "enum", NULL, " ");
+}
+
+static void do_field(void *x) {
+ rcc_field_ty f = x;
+
+ printf("<em>field</em><ul>\n");
+ xx(f,id,identifier);
+ xx(f,type,uid);
+ xx(f,offset,int);
+ xx(f,bitsize,int);
+ xx(f,lsb,int);
+ printf("</ul>\n");
+}
+
+static void do_field_list(list_ty x) {
+ do_list(x, do_field, "field", "ol", "");
+}
+
+static void do_symbol(rcc_symbol_ty x) {
+ printf("<em>symbol</em><ul>\n");
+ xx(x,id,identifier);
+ xx(x,type,uid);
+ xx(x,scope,scope);
+ xx(x,sclass,sclass);
+ xx(x,ref,int);
+ xx(x,flags,flags);
+ printf("</ul>\n");
+}
+
+#define caselabel(kind) case rcc_##kind##_enum: \
+ printf("<strong>" #kind "</strong> : <em>%s</em>", typename); \
+ printf("<ul>\n"); attributes
+#define yy(kind,field,type) xx((&x->v.rcc_##kind),field,type)
+
+static void do_type(rcc_type_ty x) {
+#define attributes xx(x,size,int); xx(x,align,int)
+ switch (x->kind) {
+ static char *typename = "type";
+ caselabel(INT); break;
+ caselabel(UNSIGNED); break;
+ caselabel(FLOAT); break;
+ caselabel(VOID); break;
+ caselabel(POINTER);
+ yy(POINTER,type,uid);
+ break;
+ caselabel(ENUM);
+ yy(ENUM,tag,identifier);
+ yy(ENUM,ids,enum_list);
+ break;
+ caselabel(STRUCT);
+ yy(STRUCT,tag,identifier);
+ yy(STRUCT,fields,field_list);
+ break;
+ caselabel(UNION);
+ yy(UNION,tag,identifier);
+ yy(UNION,fields,field_list);
+ break;
+ caselabel(ARRAY);
+ yy(ARRAY,type,uid);
+ break;
+ caselabel(FUNCTION);
+ yy(FUNCTION,type,uid);
+ yy(FUNCTION,formals,uid_list);
+ break;
+ caselabel(CONST);
+ yy(CONST,type,uid);
+ break;
+ caselabel(VOLATILE);
+ yy(VOLATILE,type,uid);
+ break;
+ default: assert(0);
+ }
+#undef attributes
+ printf("</ul>\n");
+}
+
+static void do_item(rcc_item_ty x) {
+ printf("<a name='%d'>", x->uid);
+#define attributes xx(x,uid,define_uid)
+ printf("</a>");
+ switch (x->kind) {
+ static char *typename = "item";
+ caselabel(Symbol);
+ yy(Symbol,symbol,symbol);
+ break;
+ caselabel(Type);
+ yy(Type,type,type);
+ break;
+ default: assert(0);
+ }
+#undef attributes
+ printf("</ul>\n");
+}
+
+static void do_item_list(list_ty x) {
+ int count = Seq_length(x);
+
+ if (count == 0)
+ printf("<em>empty item list</em>\n");
+ else {
+ int i;
+ printf("<em>item list</em>");
+ printf("<ol>\n");
+ for (i = 0; i < count; i++) {
+ rcc_item_ty item = Seq_get(x, i);
+ printf("<li value=%d>", item->uid);
+ do_item(item);
+ printf("</li>\n");
+ }
+ printf("</ol>\n");
+ }
+}
+
+static void do_string(string_ty x) {
+ printf("%d,<code>'%s'</code>", x.len, x.str);
+}
+
+static void do_generic_string(void *x) {
+ do_string(*(string_ty *)x);
+}
+
+static void do_string_list(list_ty x) {
+ do_list(x, do_generic_string, "string", "ol", "");
+}
+
+static void do_node(void *y) {
+ rcc_node_ty x = y;
+
+ if (x->kind == rcc_LABEL_enum)
+ printf("<a name='L%d'></a>", x->v.rcc_LABEL.label);
+#define attributes xx(x,suffix,suffix); xx(x,size,int)
+ switch (x->kind) {
+ static char *typename = "node";
+ caselabel(CNST);
+ yy(CNST,value,int);
+ break;
+ caselabel(CNSTF);
+ yy(CNSTF,value,real);
+ break;
+ caselabel(ARG);
+ yy(ARG,left,node);
+ yy(ARG,len,int);
+ yy(ARG,align,int);
+ break;
+ caselabel(ASGN);
+ yy(ASGN,left,node);
+ yy(ASGN,right,node);
+ yy(ASGN,len,int);
+ yy(ASGN,align,int);
+ break;
+ caselabel(CVT);
+ yy(CVT,op,op);
+ yy(CVT,left,node);
+ yy(CVT,fromsize,int);
+ break;
+ caselabel(CALL);
+ yy(CALL,left,node);
+ yy(CALL,type,uid);
+ break;
+ caselabel(CALLB);
+ yy(CALLB,left,node);
+ yy(CALLB,right,node);
+ yy(CALLB,type,uid);
+ break;
+ caselabel(RET); break;
+ caselabel(ADDRG);
+ yy(ADDRG,uid,uid);
+ break;
+ caselabel(ADDRL);
+ yy(ADDRL,uid,uid);
+ break;
+ caselabel(ADDRF);
+ yy(ADDRF,uid,uid);
+ break;
+ caselabel(Unary);
+ yy(Unary,op,op);
+ yy(Unary,left,node);
+ break;
+ caselabel(Binary);
+ yy(Binary,op,op);
+ yy(Binary,left,node);
+ yy(Binary,right,node);
+ break;
+ caselabel(Compare);
+ yy(Compare,op,op);
+ yy(Compare,left,node);
+ yy(Compare,right,node);
+ yy(Compare,label,label);
+ break;
+ caselabel(LABEL);
+ yy(LABEL,label,define_label);
+ break;
+ caselabel(BRANCH);
+ yy(BRANCH,label,label);
+ break;
+ caselabel(CSE);
+ yy(CSE,uid,uid);
+ yy(CSE,node,node);
+ break;
+ default: assert(0);
+ }
+#undef attributes
+ printf("</ul>");
+}
+
+static void do_node_list(list_ty x) {
+ do_list(x, do_node, "node", "ol", "");
+}
+
+static void do_interface(void *);
+
+static void do_interface_list(list_ty x) {
+ do_list(x, do_interface, "interface", "ol", "");
+}
+
+static void do_interface(void *y) {
+ rcc_interface_ty x = y;
+
+ if (x->kind == rcc_Address_enum)
+ printf("<a name='%d'></a>", x->v.rcc_Address.uid);
+ else if (x->kind == rcc_Local_enum)
+ printf("<a name='%d'></a>", x->v.rcc_Local.uid);
+#define attributes
+ switch (x->kind) {
+ static char *typename = "interface";
+ caselabel(Export);
+ yy(Export,p,uid);
+ break;
+ caselabel(Import);
+ yy(Import,p,uid);
+ break;
+ caselabel(Global);
+ yy(Global,p,uid);
+ yy(Global,seg,seg);
+ break;
+ caselabel(Local);
+ yy(Local,uid,define_uid);
+ yy(Local,p,symbol);
+ break;
+ caselabel(Address);
+ yy(Address,uid,define_uid);
+ yy(Address,q,symbol);
+ yy(Address,p,uid);
+ yy(Address,n,int);
+ break;
+ caselabel(Segment);
+ yy(Segment,seg,seg);
+ break;
+ caselabel(Defaddress);
+ yy(Defaddress,p,uid);
+ break;
+ caselabel(Deflabel);
+ yy(Deflabel,label,label);
+ break;
+ caselabel(Defconst);
+ yy(Defconst,suffix,suffix);
+ yy(Defconst,size,int);
+ yy(Defconst,value,int);
+ break;
+ caselabel(Defconstf);
+ yy(Defconstf,size,int);
+ yy(Defconstf,value,real);
+ break;
+ caselabel(Defstring);
+ yy(Defstring,s,string);
+ break;
+ caselabel(Space);
+ yy(Space,n,int);
+ break;
+ caselabel(Function);
+ yy(Function,f,uid);
+ yy(Function,caller,uid_list);
+ yy(Function,callee,uid_list);
+ yy(Function,ncalls,int);
+ yy(Function,codelist,interface_list);
+ break;
+ caselabel(Forest);
+ yy(Forest,nodes,node_list);
+ break;
+ case rcc_Blockbeg_enum: printf("<strong>Blockbeg</strong> : <em>%s</em>", typename); return;
+ case rcc_Blockend_enum: printf("<strong>Blockend</strong> : <em>%s</em>", typename); return;
+ default: assert(0);
+ }
+#undef attributes
+ printf("</ul>\n");
+}
+
+static void do_program(rcc_program_ty x) {
+ printf("<ul>\n");
+ xx(x,nuids,int);
+ xx(x,nlabels,int);
+ xx(x,items,item_list);
+ xx(x,interfaces,interface_list);
+ xx(x,argc,int);
+ xx(x,argv,string_list);
+ printf("</ul>\n");
+}
+
+int main(int argc, char *argv[]) {
+ int i, version;
+ float stamp = (assert(strstr(rcsid, ",v")), strtod(strstr(rcsid, ",v")+2, NULL))
+;
+ char *infile = NULL, *outfile = NULL;
+ rcc_program_ty pickle;
+
+ for (i = 1; i < argc; i++)
+ if (*argv[i] != '-' || strcmp(argv[i], "-") == 0) {
+ if (infile == NULL)
+ infile = argv[i];
+ else if (outfile == NULL)
+ outfile = argv[i];
+ }
+ if (infile != NULL && strcmp(infile, "-") != 0
+ && freopen(infile, "rb", stdin) == NULL) {
+ fprintf(stderr, "%s: can't read `%s'\n", argv[0], infile);
+ exit(EXIT_FAILURE);
+ }
+ if (infile == NULL || strcmp(infile, "-") == 0)
+ infile = "Standard Input";
+#if WIN32
+ else
+ _setmode(_fileno(stdin), _O_BINARY);
+#endif
+ if (outfile != NULL && strcmp(outfile, "-") != 0
+ && freopen(outfile, "w", stdout) == NULL) {
+ fprintf(stderr, "%s: can't write `%s'\n", argv[0], outfile);
+ exit(EXIT_FAILURE);
+ }
+ version = read_int(stdin);
+ assert(version/100 == (int)stamp);
+ pickle = rcc_read_program(stdin);
+ printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\"\n");
+ printf("<html><head><title>%s</title>\n"
+ "<link rev=made href=\"mailto:drh@microsoft.com\">\n"
+ "</head><body>\n<h1>%s</h1>\n", infile, infile);
+ printf("<p>version = %d.%d</p>", version/100, version%100);
+ do_program(pickle);
+ {
+ time_t t;
+ time(&t);
+ printf("<hr><address>%s</address>\n", ctime(&t));
+ }
+ printf("</body></html>\n");
+ return EXIT_SUCCESS;
+}
diff --git a/lcc/src/alloc.c b/lcc/src/alloc.c
new file mode 100755
index 0000000..698da4f
--- /dev/null
+++ b/lcc/src/alloc.c
@@ -0,0 +1,94 @@
+#include "c.h"
+struct block {
+ struct block *next;
+ char *limit;
+ char *avail;
+};
+union align {
+ long l;
+ char *p;
+ double d;
+ int (*f)(void);
+};
+union header {
+ struct block b;
+ union align a;
+};
+#ifdef PURIFY
+union header *arena[3];
+
+void *allocate(unsigned long n, unsigned a) {
+ union header *new = malloc(sizeof *new + n);
+
+ assert(a < NELEMS(arena));
+ if (new == NULL) {
+ error("insufficient memory\n");
+ exit(1);
+ }
+ new->b.next = (void *)arena[a];
+ arena[a] = new;
+ return new + 1;
+}
+
+void deallocate(unsigned a) {
+ union header *p, *q;
+
+ assert(a < NELEMS(arena));
+ for (p = arena[a]; p; p = q) {
+ q = (void *)p->b.next;
+ free(p);
+ }
+ arena[a] = NULL;
+}
+
+void *newarray(unsigned long m, unsigned long n, unsigned a) {
+ return allocate(m*n, a);
+}
+#else
+static struct block
+ first[] = { { NULL }, { NULL }, { NULL } },
+ *arena[] = { &first[0], &first[1], &first[2] };
+static struct block *freeblocks;
+
+void *allocate(unsigned long n, unsigned a) {
+ struct block *ap;
+
+ assert(a < NELEMS(arena));
+ assert(n > 0);
+ ap = arena[a];
+ n = roundup(n, sizeof (union align));
+ while (n > ap->limit - ap->avail) {
+ if ((ap->next = freeblocks) != NULL) {
+ freeblocks = freeblocks->next;
+ ap = ap->next;
+ } else
+ {
+ unsigned m = sizeof (union header) + n + roundup(10*1024, sizeof (union align));
+ ap->next = malloc(m);
+ ap = ap->next;
+ if (ap == NULL) {
+ error("insufficient memory\n");
+ exit(1);
+ }
+ ap->limit = (char *)ap + m;
+ }
+ ap->avail = (char *)((union header *)ap + 1);
+ ap->next = NULL;
+ arena[a] = ap;
+
+ }
+ ap->avail += n;
+ return ap->avail - n;
+}
+
+void *newarray(unsigned long m, unsigned long n, unsigned a) {
+ return allocate(m*n, a);
+}
+void deallocate(unsigned a) {
+ assert(a < NELEMS(arena));
+ arena[a]->next = freeblocks;
+ freeblocks = first[a].next;
+ first[a].next = NULL;
+ arena[a] = &first[a];
+}
+#endif
diff --git a/lcc/src/alpha.md b/lcc/src/alpha.md
new file mode 100755
index 0000000..fe7140a
--- /dev/null
+++ b/lcc/src/alpha.md
@@ -0,0 +1,1192 @@
+%{
+#define INTTMP ((0xff<<1)|(1<<22)|(1<<25)|(1<<27))
+#define INTVAR (0x3f<<9)
+#define FLTTMP ((0x3f<<10)|(0x1ff<<22))
+#define FLTVAR (0xff<<2)
+
+#define INTRET 0x00000001
+#define FLTRET 0x00000003
+
+#define readsreg(p) \
+ (generic((p)->op)==INDIR && (p)->kids[0]->op==VREG+P)
+#define setsrc(d) ((d) && (d)->x.regnode && \
+ (d)->x.regnode->set == src->x.regnode->set && \
+ (d)->x.regnode->mask&src->x.regnode->mask)
+
+#define relink(a, b) ((b)->x.prev = (a), (a)->x.next = (b))
+
+#include "c.h"
+#define NODEPTR_TYPE Node
+#define OP_LABEL(p) ((p)->op)
+#define LEFT_CHILD(p) ((p)->kids[0])
+#define RIGHT_CHILD(p) ((p)->kids[1])
+#define STATE_LABEL(p) ((p)->x.state)
+static void address(Symbol, Symbol, long);
+static void blkfetch(int, int, int, int);
+static void blkloop(int, int, int, int, int, int[]);
+static void blkstore(int, int, int, int);
+static void defaddress(Symbol);
+static void defconst(int, int, Value);
+static void defstring(int, char *);
+static void defsymbol(Symbol);
+static void doarg(Node);
+static void emit2(Node);
+static void export(Symbol);
+static void clobber(Node);
+static void function(Symbol, Symbol [], Symbol [], int);
+static void global(Symbol);
+static void import(Symbol);
+static void local(Symbol);
+static void progbeg(int, char **);
+static void progend(void);
+static void segment(int);
+static void space(int);
+static void target(Node);
+static Symbol ireg[32], freg[32];
+static Symbol iregw, fregw;
+
+static int tmpregs[] = {4, 2, 3};
+static Symbol blkreg;
+
+static int cseg;
+
+static char *currentfile;
+
+%}
+%start stmt
+%term CNSTF4=4113
+%term CNSTF8=8209
+%term CNSTF16=16401
+%term CNSTI1=1045
+%term CNSTI2=2069
+%term CNSTI4=4117
+%term CNSTI8=8213
+%term CNSTP4=4119
+%term CNSTP8=8215
+%term CNSTU1=1046
+%term CNSTU2=2070
+%term CNSTU4=4118
+%term CNSTU8=8214
+
+%term ARGB=41
+%term ARGF4=4129
+%term ARGF8=8225
+%term ARGF16=16417
+%term ARGI4=4133
+%term ARGI8=8229
+%term ARGP4=4135
+%term ARGP8=8231
+%term ARGU4=4134
+%term ARGU8=8230
+
+%term ASGNB=57
+%term ASGNF4=4145
+%term ASGNF8=8241
+%term ASGNF16=16433
+%term ASGNI1=1077
+%term ASGNI2=2101
+%term ASGNI4=4149
+%term ASGNI8=8245
+%term ASGNP4=4151
+%term ASGNP8=8247
+%term ASGNU1=1078
+%term ASGNU2=2102
+%term ASGNU4=4150
+%term ASGNU8=8246
+
+%term INDIRB=73
+%term INDIRF4=4161
+%term INDIRF8=8257
+%term INDIRF16=16449
+%term INDIRI1=1093
+%term INDIRI2=2117
+%term INDIRI4=4165
+%term INDIRI8=8261
+%term INDIRP4=4167
+%term INDIRP8=8263
+%term INDIRU1=1094
+%term INDIRU2=2118
+%term INDIRU4=4166
+%term INDIRU8=8262
+
+%term CVFF4=4209
+%term CVFF8=8305
+%term CVFF16=16497
+%term CVFI4=4213
+%term CVFI8=8309
+
+%term CVIF4=4225
+%term CVIF8=8321
+%term CVIF16=16513
+%term CVII1=1157
+%term CVII2=2181
+%term CVII4=4229
+%term CVII8=8325
+%term CVIU1=1158
+%term CVIU2=2182
+%term CVIU4=4230
+%term CVIU8=8326
+
+%term CVPP4=4247
+%term CVPP8=8343
+%term CVPP16=16535
+%term CVPU4=4246
+%term CVPU8=8342
+
+%term CVUI1=1205
+%term CVUI2=2229
+%term CVUI4=4277
+%term CVUI8=8373
+%term CVUP4=4279
+%term CVUP8=8375
+%term CVUP16=16567
+%term CVUU1=1206
+%term CVUU2=2230
+%term CVUU4=4278
+%term CVUU8=8374
+
+%term NEGF4=4289
+%term NEGF8=8385
+%term NEGF16=16577
+%term NEGI4=4293
+%term NEGI8=8389
+
+%term CALLB=217
+%term CALLF4=4305
+%term CALLF8=8401
+%term CALLF16=16593
+%term CALLI4=4309
+%term CALLI8=8405
+%term CALLP4=4311
+%term CALLP8=8407
+%term CALLU4=4310
+%term CALLU8=8406
+%term CALLV=216
+
+%term RETF4=4337
+%term RETF8=8433
+%term RETF16=16625
+%term RETI4=4341
+%term RETI8=8437
+%term RETP4=4343
+%term RETP8=8439
+%term RETU4=4342
+%term RETU8=8438
+%term RETV=248
+
+%term ADDRGP4=4359
+%term ADDRGP8=8455
+
+%term ADDRFP4=4375
+%term ADDRFP8=8471
+
+%term ADDRLP4=4391
+%term ADDRLP8=8487
+
+%term ADDF4=4401
+%term ADDF8=8497
+%term ADDF16=16689
+%term ADDI4=4405
+%term ADDI8=8501
+%term ADDP4=4407
+%term ADDP8=8503
+%term ADDU4=4406
+%term ADDU8=8502
+
+%term SUBF4=4417
+%term SUBF8=8513
+%term SUBF16=16705
+%term SUBI4=4421
+%term SUBI8=8517
+%term SUBP4=4423
+%term SUBP8=8519
+%term SUBU4=4422
+%term SUBU8=8518
+
+%term LSHI4=4437
+%term LSHI8=8533
+%term LSHU4=4438
+%term LSHU8=8534
+
+%term MODI4=4453
+%term MODI8=8549
+%term MODU4=4454
+%term MODU8=8550
+
+%term RSHI4=4469
+%term RSHI8=8565
+%term RSHU4=4470
+%term RSHU8=8566
+
+%term BANDI4=4485
+%term BANDI8=8581
+%term BANDU4=4486
+%term BANDU8=8582
+
+%term BCOMI4=4501
+%term BCOMI8=8597
+%term BCOMU4=4502
+%term BCOMU8=8598
+
+%term BORI4=4517
+%term BORI8=8613
+%term BORU4=4518
+%term BORU8=8614
+
+%term BXORI4=4533
+%term BXORI8=8629
+%term BXORU4=4534
+%term BXORU8=8630
+
+%term DIVF4=4545
+%term DIVF8=8641
+%term DIVF16=16833
+%term DIVI4=4549
+%term DIVI8=8645
+%term DIVU4=4550
+%term DIVU8=8646
+
+%term MULF4=4561
+%term MULF8=8657
+%term MULF16=16849
+%term MULI4=4565
+%term MULI8=8661
+%term MULU4=4566
+%term MULU8=8662
+
+%term EQF4=4577
+%term EQF8=8673
+%term EQF16=16865
+%term EQI4=4581
+%term EQI8=8677
+%term EQU4=4582
+%term EQU8=8678
+
+%term GEF4=4593
+%term GEF8=8689
+%term GEI4=4597
+%term GEI8=8693
+%term GEI16=16885
+%term GEU4=4598
+%term GEU8=8694
+
+%term GTF4=4609
+%term GTF8=8705
+%term GTF16=16897
+%term GTI4=4613
+%term GTI8=8709
+%term GTU4=4614
+%term GTU8=8710
+
+%term LEF4=4625
+%term LEF8=8721
+%term LEF16=16913
+%term LEI4=4629
+%term LEI8=8725
+%term LEU4=4630
+%term LEU8=8726
+
+%term LTF4=4641
+%term LTF8=8737
+%term LTF16=16929
+%term LTI4=4645
+%term LTI8=8741
+%term LTU4=4646
+%term LTU8=8742
+
+%term NEF4=4657
+%term NEF8=8753
+%term NEF16=16945
+%term NEI4=4661
+%term NEI8=8757
+%term NEU4=4662
+%term NEU8=8758
+
+%term JUMPV=584
+
+%term LABELV=600
+
+%term LOADB=233
+%term LOADF4=4321
+%term LOADF8=8417
+%term LOADF16=16609
+%term LOADI1=1253
+%term LOADI2=2277
+%term LOADI4=4325
+%term LOADI8=8421
+%term LOADP4=4327
+%term LOADP8=8423
+%term LOADU1=1254
+%term LOADU2=2278
+%term LOADU4=4326
+%term LOADU8=8422
+
+%term VREGP=711
+%%
+reg: INDIRI1(VREGP) "# read register\n"
+reg: INDIRU1(VREGP) "# read register\n"
+
+reg: INDIRI2(VREGP) "# read register\n"
+reg: INDIRU2(VREGP) "# read register\n"
+
+reg: INDIRF4(VREGP) "# read register\n"
+reg: INDIRI4(VREGP) "# read register\n"
+reg: INDIRP4(VREGP) "# read register\n"
+reg: INDIRU4(VREGP) "# read register\n"
+
+reg: INDIRF8(VREGP) "# read register\n"
+reg: INDIRI8(VREGP) "# read register\n"
+reg: INDIRP8(VREGP) "# read register\n"
+reg: INDIRU8(VREGP) "# read register\n"
+
+stmt: ASGNI1(VREGP,reg) "# write register\n"
+stmt: ASGNU1(VREGP,reg) "# write register\n"
+
+stmt: ASGNI2(VREGP,reg) "# write register\n"
+stmt: ASGNU2(VREGP,reg) "# write register\n"
+
+stmt: ASGNF4(VREGP,reg) "# write register\n"
+stmt: ASGNI4(VREGP,reg) "# write register\n"
+stmt: ASGNP4(VREGP,reg) "# write register\n"
+stmt: ASGNU4(VREGP,reg) "# write register\n"
+
+stmt: ASGNF8(VREGP,reg) "# write register\n"
+stmt: ASGNI8(VREGP,reg) "# write register\n"
+stmt: ASGNP8(VREGP,reg) "# write register\n"
+stmt: ASGNU8(VREGP,reg) "# write register\n"
+con: CNSTI1 "%a"
+con: CNSTU1 "%a"
+
+con: CNSTI2 "%a"
+con: CNSTU2 "%a"
+
+con: CNSTI4 "%a"
+con: CNSTU4 "%a"
+con: CNSTP4 "%a"
+
+con: CNSTI8 "%a"
+con: CNSTU8 "%a"
+con: CNSTP8 "%a"
+stmt: reg ""
+acon: con "%0"
+acon: ADDRGP8 "%a"
+
+addr: ADDI4(reg,acon) "%1($%0)"
+addr: ADDI8(reg,acon) "%1($%0)"
+addr: ADDU8(reg,acon) "%1($%0)"
+addr: ADDP8(reg,acon) "%1($%0)"
+
+addr: acon "%0"
+addr: reg "($%0)"
+
+addr: ADDRFP8 "%a+%F($sp)"
+addr: ADDRLP8 "%a+%F($sp)"
+
+reg: addr "lda $%c,%0\n" 1
+
+reg: CNSTI1 "# reg\n" range(a, 0, 0)
+reg: CNSTI2 "# reg\n" range(a, 0, 0)
+reg: CNSTI4 "# reg\n" range(a, 0, 0)
+reg: CNSTI8 "# reg\n" range(a, 0, 0)
+reg: CNSTU1 "# reg\n" range(a, 0, 0)
+reg: CNSTU2 "# reg\n" range(a, 0, 0)
+reg: CNSTU4 "# reg\n" range(a, 0, 0)
+reg: CNSTU8 "# reg\n" range(a, 0, 0)
+reg: CNSTP8 "# reg\n" range(a, 0, 0)
+
+stmt: ASGNI1(addr,reg) "stb $%1,%0\n" 1
+stmt: ASGNU1(addr,reg) "stb $%1,%0\n" 1
+stmt: ASGNI2(addr,reg) "stw $%1,%0\n" 1
+stmt: ASGNU2(addr,reg) "stw $%1,%0\n" 1
+
+stmt: ASGNI4(addr,reg) "stl $%1,%0\n" 1
+stmt: ASGNU4(addr,reg) "stl $%1,%0\n" 1
+stmt: ASGNI8(addr,reg) "stq $%1,%0\n" 1
+stmt: ASGNU8(addr,reg) "stq $%1,%0\n" 1
+stmt: ASGNP8(addr,reg) "stq $%1,%0\n" 1
+
+reg: INDIRI1(reg) "ldb $%c,($%0)\n" 1
+reg: INDIRI2(reg) "ldw $%c,($%0)\n" 1
+reg: INDIRI4(addr) "ldl $%c,%0\n" 1
+reg: INDIRI8(addr) "ldq $%c,%0\n" 1
+reg: INDIRP8(addr) "ldq $%c,%0\n" 1
+reg: INDIRU1(reg) "ldbu $%c,($%0)\n" 1
+reg: INDIRU2(reg) "ldwu $%c,($%0)\n" 1
+reg: INDIRU4(addr) "ldl $%c,%0\nzap $%c,240,$%c\n" 2
+reg: INDIRU8(addr) "ldq $%c,%0\n" 1
+
+reg: CVII4(INDIRI1(reg)) "ldb $%c,($%0)\n" 1
+reg: CVII8(INDIRI1(reg)) "ldb $%c,($%0)\n" 1
+reg: CVII4(INDIRI2(reg)) "ldw $%c,($%0)\n" 1
+reg: CVII8(INDIRI2(reg)) "ldw $%c,($%0)\n" 1
+reg: CVII8(INDIRI4(addr)) "ldl $%c,%0\n" 1
+
+reg: CVUU4(INDIRU1(reg)) "ldbu $%c,($%0)\n" 1
+reg: CVUU8(INDIRU1(reg)) "ldbu $%c,($%0)\n" 1
+reg: CVUU4(INDIRU2(reg)) "ldwu $%c,($%0)\n" 1
+reg: CVUU8(INDIRU2(reg)) "ldwu $%c,($%0)\n" 1
+reg: CVUU8(INDIRU4(addr)) "ldl $%c,%0\nzap $%c,240,$%c\n" 2
+
+reg: CVUI4(INDIRU1(reg)) "ldbu $%c,($%0)\n" 1
+reg: CVUI8(INDIRU1(reg)) "ldbu $%c,($%0)\n" 1
+reg: CVUI4(INDIRU2(reg)) "ldwu $%c,($%0)\n" 1
+reg: CVUI8(INDIRU2(reg)) "ldwu $%c,($%0)\n" 1
+reg: CVUI8(INDIRU4(addr)) "ldl $%c,%0\nzap $%c,240,$%c\n" 2
+
+reg: CVIU8(reg) "mov $%0,$%c\n" move(a)
+
+reg: INDIRF4(addr) "lds $f%c,%0\n" 1
+reg: INDIRF8(addr) "ldt $f%c,%0\n" 1
+stmt: ASGNF4(addr,reg) "sts $f%1,%0\n" 1
+stmt: ASGNF8(addr,reg) "stt $f%1,%0\n" 1
+
+reg: MULI4(reg,rc) "mull $%0,%1,$%c\n" 1
+reg: MULI8(reg,rc) "mulq $%0,%1,$%c\n" 1
+reg: MULU4(reg,rc) "mull $%0,%1,$%c\nzap $%c,240,$%c\n" 2
+reg: MULU8(reg,rc) "mulq $%0,%1,$%c\n" 1
+
+reg: DIVI4(reg,rc) "divl $%0,%1,$%c\n" 1
+reg: DIVI8(reg,rc) "divq $%0,%1,$%c\n" 1
+reg: DIVU4(reg,rc) "divlu $%0,%1,$%c\n" 1
+reg: DIVU8(reg,rc) "divqu $%0,%1,$%c\n" 1
+reg: MODI4(reg,rc) "reml $%0,%1,$%c\n" 1
+reg: MODI8(reg,rc) "remq $%0,%1,$%c\n" 1
+reg: MODU4(reg,rc) "remlu $%0,%1,$%c\n" 1
+reg: MODU8(reg,rc) "remqu $%0,%1,$%c\n" 1
+
+rc: con "%0"
+rc: reg "$%0"
+
+reg: ADDI4(reg,rc) "addl $%0,%1,$%c\n" 1
+reg: ADDI8(reg,rc) "addq $%0,%1,$%c\n" 1
+reg: ADDP8(reg,rc) "addq $%0,%1,$%c\n" 1
+reg: ADDU4(reg,rc) "addl $%0,%1,$%c\nzap $%c,240,$%c\n" 2
+reg: ADDU8(reg,rc) "addq $%0,%1,$%c\n" 1
+reg: SUBI4(reg,rc) "subl $%0,%1,$%c\n" 1
+reg: SUBI8(reg,rc) "subq $%0,%1,$%c\n" 1
+reg: SUBP8(reg,rc) "subq $%0,%1,$%c\n" 1
+reg: SUBU4(reg,rc) "subl $%0,%1,$%c\nzap $%c,240,$%c\n" 2
+reg: SUBU8(reg,rc) "subq $%0,%1,$%c\n" 1
+
+reg: BANDI4(reg,rc) "and $%0,%1,$%c\naddl $%c,0,$%c\n" 2
+reg: BANDI8(reg,rc) "and $%0,%1,$%c\n" 1
+reg: BANDU4(reg,rc) "and $%0,%1,$%c\n" 1
+reg: BANDU8(reg,rc) "and $%0,%1,$%c\n" 1
+reg: BORI4(reg,rc) "or $%0,%1,$%c\naddl $%c,0,$%c\n" 2
+reg: BORI8(reg,rc) "or $%0,%1,$%c\n" 1
+reg: BORU4(reg,rc) "or $%0,%1,$%c\n" 1
+reg: BORU8(reg,rc) "or $%0,%1,$%c\n" 1
+reg: BXORI4(reg,rc) "xor $%0,%1,$%c\naddl $%c,0,$%c\n" 2
+reg: BXORI8(reg,rc) "xor $%0,%1,$%c\n" 1
+reg: BXORU4(reg,rc) "xor $%0,%1,$%c\n" 1
+reg: BXORU8(reg,rc) "xor $%0,%1,$%c\n" 1
+
+rc6: CNSTI4 "%a" range(a,0,63)
+rc6: CNSTI8 "%a" range(a,0,63)
+rc6: reg "$%0"
+
+reg: LSHI4(reg,rc6) "sll $%0,%1,$%c\naddl $%c,0,$%c\n" 2
+reg: LSHI8(reg,rc6) "sll $%0,%1,$%c\n" 1
+reg: LSHU4(reg,rc6) "sll $%0,%1,$%c\nzap $%c,240,$%c\n" 2
+reg: LSHU8(reg,rc6) "sll $%0,%1,$%c\n" 1
+reg: RSHI4(reg,rc6) "sra $%0,%1,$%c\naddl $%c,0,$%c\n" 2
+reg: RSHI8(reg,rc6) "sra $%0,%1,$%c\n" 1
+reg: RSHU4(reg,rc6) "srl $%0,%1,$%c\n" 1
+reg: RSHU8(reg,rc6) "srl $%0,%1,$%c\n" 1
+
+reg: BCOMI4(reg) "not $%0,$%c\naddl $%c,0,$%c\n" 2
+reg: BCOMU4(reg) "not $%0,$%c\nzap $%c,240,$%c\n" 2
+reg: BCOMI8(reg) "not $%0,$%c\n" 1
+reg: BCOMU8(reg) "not $%0,$%c\n" 1
+reg: NEGI4(reg) "negl $%0,$%c\n" 1
+reg: NEGI8(reg) "negq $%0,$%c\n" 1
+reg: LOADI1(reg) "mov $%0,$%c\n" move(a)
+reg: LOADI2(reg) "mov $%0,$%c\n" move(a)
+reg: LOADI4(reg) "mov $%0,$%c\n" move(a)
+reg: LOADI8(reg) "mov $%0,$%c\n" move(a)
+reg: LOADP8(reg) "mov $%0,$%c\n" move(a)
+reg: LOADU1(reg) "mov $%0,$%c\n" move(a)
+reg: LOADU2(reg) "mov $%0,$%c\n" move(a)
+reg: LOADU4(reg) "mov $%0,$%c\n" move(a)
+reg: LOADU8(reg) "mov $%0,$%c\n" move(a)
+
+reg: ADDF4(reg,reg) "adds $f%0,$f%1,$f%c\n" 1
+reg: ADDF8(reg,reg) "addt $f%0,$f%1,$f%c\n" 1
+reg: DIVF4(reg,reg) "divs $f%0,$f%1,$f%c\n" 1
+reg: DIVF8(reg,reg) "divt $f%0,$f%1,$f%c\n" 1
+reg: MULF4(reg,reg) "muls $f%0,$f%1,$f%c\n" 1
+reg: MULF8(reg,reg) "mult $f%0,$f%1,$f%c\n" 1
+reg: SUBF4(reg,reg) "subs $f%0,$f%1,$f%c\n" 1
+reg: SUBF8(reg,reg) "subt $f%0,$f%1,$f%c\n" 1
+reg: LOADF4(reg) "fmov $f%0,$f%c\n" move(a)
+reg: LOADF8(reg) "fmov $f%0,$f%c\n" move(a)
+reg: NEGF4(reg) "negs $f%0,$f%c\n" 1
+reg: NEGF8(reg) "negt $f%0,$f%c\n" 1
+reg: CVII4(reg) "sll $%0,8*(8-%a),$%c\nsra $%c,8*(8-%a),$%c\n" 2
+reg: CVII8(reg) "sll $%0,8*(8-%a),$%c\nsra $%c,8*(8-%a),$%c\n" 2
+reg: CVUI4(reg) "and $%0,(1<<(8*%a))-1,$%c\n" 1
+reg: CVUI8(reg) "and $%0,(1<<(8*%a))-1,$%c\n" 1
+reg: CVUU4(reg) "and $%0,(1<<(8*%a))-1,$%c\n" 1
+reg: CVUU8(reg) "and $%0,(1<<(8*%a))-1,$%c\n" 1
+
+reg: CVUP8(reg) "and $%0,(1<<(8*%a))-1,$%c\n" 1
+
+reg: CVFF4(reg) "cvtts $f%0,$f%c\n" 1
+reg: CVFF8(reg) "cvtst $f%0,$f%c\n" 1
+
+reg: CVIF4(reg) "stq $%0,-56+%F($sp)\nldt $%f%c,-56+%F($sp)\ncvtqs $f%c,$f%c\n" 3
+reg: CVIF8(reg) "stq $%0,-56+%F($sp)\nldt $%f%c,-56+%F($sp)\ncvtqt $f%c,$f%c\n" 3
+reg: CVIF4(INDIRI4(addr)) "lds $f%c,%0\ncvtlq $f%c,$f%c\ncvtqs $f%c,$f%c\n" 3
+reg: CVIF4(INDIRI8(addr)) "ldt $f%c,%0\ncvtqs $f%c,$f%c\n" 2
+reg: CVIF8(INDIRI4(addr)) "lds $f%c,%0\ncvtlq $f%c,$f%c\ncvtqt $f%c,$f%c\n" 3
+reg: CVIF8(INDIRI8(addr)) "ldt $f%c,%0\ncvtqt $f%c,$f%c\n" 2
+
+reg: CVFI4(reg) "cvttqc $f%0,$f1\ncvtql $f1,$f1\nsts $f1,-56+%F($sp)\nldl $%c,-56+%F($sp)\n" 4
+reg: CVFI8(reg) "cvttqc $f%0,$f1\nstt $f1,-56+%F($sp)\nldq $%c,-56+%F($sp)\n" 3
+
+stmt: LABELV "%a:\n"
+
+stmt: JUMPV(acon) "br %0\n" 1
+stmt: JUMPV(reg) "jmp ($%0)\n" 1
+
+stmt: EQI4(reg,rc6) "cmpeq $%0,%1,$23\nbne $23,%a\n" 2
+stmt: EQU4(reg,rc6) "cmpeq $%0,%1,$23\nbne $23,%a\n" 2
+stmt: EQI8(reg,rc6) "cmpeq $%0,%1,$23\nbne $23,%a\n" 2
+stmt: EQU8(reg,rc6) "cmpeq $%0,%1,$23\nbne $23,%a\n" 2
+stmt: NEI4(reg,rc6) "cmpeq $%0,%1,$23\nbeq $23,%a\n" 2
+stmt: NEU4(reg,rc6) "cmpeq $%0,%1,$23\nbeq $23,%a\n" 2
+stmt: NEI8(reg,rc6) "cmpeq $%0,%1,$23\nbeq $23,%a\n" 2
+stmt: NEU8(reg,rc6) "cmpeq $%0,%1,$23\nbeq $23,%a\n" 2
+stmt: GEI4(reg,rc6) "cmplt $%0,%1,$23\nbeq $23,%a\n" 2
+stmt: GEI8(reg,rc6) "cmplt $%0,%1,$23\nbeq $23,%a\n" 2
+stmt: GEU4(reg,rc6) "cmpult $%0,%1,$23\nbeq $23,%a\n" 1
+stmt: GEU8(reg,rc6) "cmpult $%0,%1,$23\nbeq $23,%a\n" 1
+stmt: GTI4(reg,rc6) "cmple $%0,%1,$23\nbeq $23,%a\n" 2
+stmt: GTI8(reg,rc6) "cmple $%0,%1,$23\nbeq $23,%a\n" 2
+stmt: GTU4(reg,rc6) "cmpule $%0,%1,$23\nbeq $23,%a\n" 1
+stmt: GTU8(reg,rc6) "cmpule $%0,%1,$23\nbeq $23,%a\n" 1
+stmt: LEI4(reg,rc6) "cmple $%0,%1,$23\nbne $23,%a\n" 2
+stmt: LEI8(reg,rc6) "cmple $%0,%1,$23\nbne $23,%a\n" 2
+stmt: LEU4(reg,rc6) "cmpule $%0,%1,$23\nbne $23,%a\n" 2
+stmt: LEU8(reg,rc6) "cmpule $%0,%1,$23\nbne $23,%a\n" 2
+stmt: LTI4(reg,rc6) "cmplt $%0,%1,$23\nbne $23,%a\n" 2
+stmt: LTI8(reg,rc6) "cmplt $%0,%1,$23\nbne $23,%a\n" 2
+stmt: LTU4(reg,rc6) "cmpult $%0,%1,$23\nbne $23,%a\n" 2
+stmt: LTU8(reg,rc6) "cmpult $%0,%1,$23\nbne $23,%a\n" 2
+
+stmt: EQF4(reg,reg) "cmpteq $f%0,$f%1,$f1\nfbne $f1,%a\n" 2
+stmt: EQF8(reg,reg) "cmpteq $f%0,$f%1,$f1\nfbne $f1,%a\n" 2
+stmt: LEF4(reg,reg) "cmptle $f%0,$f%1,$f1\nfbne $f1,%a\n" 2
+stmt: LEF8(reg,reg) "cmptle $f%0,$f%1,$f1\nfbne $f1,%a\n" 2
+stmt: LTF4(reg,reg) "cmptlt $f%0,$f%1,$f1\nfbne $f1,%a\n" 2
+stmt: LTF8(reg,reg) "cmptlt $f%0,$f%1,$f1\nfbne $f1,%a\n" 2
+
+stmt: NEF4(reg,reg) "cmpteq $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2
+stmt: NEF8(reg,reg) "cmpteq $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2
+stmt: GEF4(reg,reg) "cmptlt $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2
+stmt: GEF8(reg,reg) "cmptlt $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2
+stmt: GTF4(reg,reg) "cmptle $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2
+stmt: GTF8(reg,reg) "cmptle $f%0,$f%1,$f1\nfbeq $f1,%a\n" 2
+
+ar: ADDRGP8 "%a"
+ar: reg "($%0)"
+
+reg: CALLF4(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2
+reg: CALLF8(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2
+reg: CALLI4(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2
+reg: CALLI8(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2
+reg: CALLP8(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2
+reg: CALLU4(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2
+reg: CALLU8(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2
+stmt: CALLV(ar) "jsr $26,%0\nldgp $gp,0($26)\n" 2
+
+stmt: RETF4(reg) "# ret\n" 1
+stmt: RETF8(reg) "# ret\n" 1
+stmt: RETI4(reg) "# ret\n" 1
+stmt: RETU4(reg) "# ret\n" 1
+stmt: RETI8(reg) "# ret\n" 1
+stmt: RETU8(reg) "# ret\n" 1
+stmt: RETP8(reg) "# ret\n" 1
+stmt: RETV(reg) "# ret\n" 1
+
+stmt: ARGF4(reg) "# arg\n" 1
+stmt: ARGF8(reg) "# arg\n" 1
+stmt: ARGI4(reg) "# arg\n" 1
+stmt: ARGI8(reg) "# arg\n" 1
+stmt: ARGP8(reg) "# arg\n" 1
+stmt: ARGU4(reg) "# arg\n" 1
+stmt: ARGU8(reg) "# arg\n" 1
+
+stmt: ARGB(INDIRB(reg)) "# argb %0\n" 1
+stmt: ASGNB(reg,INDIRB(reg)) "# asgnb %0 %1\n" 1
+
+%%
+static void progend(void){}
+
+static void progbeg(int argc, char *argv[]) {
+ int i;
+
+ {
+ union {
+ char c;
+ int i;
+ } u;
+ u.i = 0;
+ u.c = 1;
+ swap = ((int)(u.i == 1)) != IR->little_endian;
+ }
+ parseflags(argc, argv);
+
+ for (i = 0; i < 32; i++)
+ freg[i] = mkreg("%d", i, 1, FREG);
+ for (i = 0; i < 32; i++)
+ ireg[i] = mkreg("%d", i, 1, IREG);
+ ireg[29]->x.name = "gp";
+ ireg[30]->x.name = "sp";
+ fregw = mkwildcard(freg);
+ iregw = mkwildcard(ireg);
+
+ tmask[IREG] = INTTMP; tmask[FREG] = FLTTMP;
+ vmask[IREG] = INTVAR; vmask[FREG] = FLTVAR;
+
+ blkreg = mkreg("1", 1, 0xf, IREG);
+
+}
+
+static Symbol rmap(int opk) {
+ switch (optype(opk)) {
+ case I: case U: case P: case B:
+ return iregw;
+ case F:
+ return fregw;
+ default:
+ return 0;
+ }
+}
+
+static Symbol argreg(int offset, int ty) {
+ if (offset >= 48)
+ return NULL;
+ else if (ty == F)
+ return freg[(offset/8) + 16];
+ else
+ return ireg[(offset/8) + 16];
+}
+
+static void target(Node p) {
+ assert(p);
+ switch (specific(p->op)) {
+ case CNST+I: case CNST+U: case CNST+P:
+ if (range(p, 0, 0) == 0) {
+ setreg(p, ireg[31]);
+ p->x.registered = 1;
+ }
+ break;
+ case CNST+F:
+ if (p->syms[0]->u.c.v.d == 0) {
+ setreg(p, freg[31]);
+ p->x.registered = 1;
+ }
+ break;
+
+ case CALL+V:
+ rtarget(p, 0, ireg[27]);
+ break;
+ case CALL+F:
+ rtarget(p, 0, ireg[27]);
+ setreg(p, freg[0]);
+ break;
+ case CALL+I: case CALL+P: case CALL+U:
+ rtarget(p, 0, ireg[27]);
+ setreg(p, ireg[0]);
+ break;
+ case RET+F:
+ rtarget(p, 0, freg[0]);
+ break;
+ case RET+I: case RET+U: case RET+P:
+ rtarget(p, 0, ireg[0]);
+ break;
+
+ case ARG+F: case ARG+I: case ARG+P: case ARG+U: {
+ Symbol q = argreg(p->syms[2]->u.c.v.i, optype(p->op));
+ if (q)
+ rtarget(p, 0, q);
+ break;
+ }
+
+
+ case ASGN+B: rtarget(p->kids[1], 0, blkreg); break;
+ case ARG+B: rtarget(p->kids[0], 0, blkreg); break;
+
+ }
+}
+
+static void clobber(Node p) {
+ assert(p);
+ switch (specific(p->op)) {
+ case ASGN+I: case ASGN+U:
+ if (opsize(p->op) <= 2)
+ spill(1<<24, IREG, p);
+ break;
+
+ case DIV+I: case DIV+U: case MOD+I: case MOD+U:
+ spill(((1<<27)|(3<<24))&~p->syms[RX]->x.regnode->mask, IREG, p);
+ break;
+
+ case CALL+F:
+ spill(INTTMP | INTRET, IREG, p);
+ spill(FLTTMP, FREG, p);
+ break;
+ case CALL+I: case CALL+P: case CALL+U:
+ spill(INTTMP, IREG, p);
+ spill(FLTTMP | FLTRET, FREG, p);
+ break;
+ case CALL+V:
+ spill(INTTMP | INTRET, IREG, p);
+ spill(FLTTMP | FLTRET, FREG, p);
+ break;
+
+ }
+}
+
+static void emit2(Node p) {
+ int dst, n, src, sz, ty;
+ static int ty0;
+ Symbol q;
+
+ switch (specific(p->op)) {
+ case ARG+F: case ARG+I: case ARG+P: case ARG+U:
+ ty = optype(p->op);
+ sz = opsize(p->op);
+ q = argreg(p->syms[2]->u.c.v.i, ty);
+ src = getregnum(p->x.kids[0]);
+ if (q)
+ break;
+ else if (ty == F && sz == 4)
+ print("sts $f%d,%d($sp)\n", src, p->syms[2]->u.c.v.i - 48);
+ else if (ty == F && sz == 8)
+ print("stt $f%d,%d($sp)\n", src, p->syms[2]->u.c.v.i - 48);
+ else if (sz == 4)
+ print("stq $%d,%d($sp)\n", src, p->syms[2]->u.c.v.i - 48);
+ else if (sz == 8)
+ print("stq $%d,%d($sp)\n", src, p->syms[2]->u.c.v.i - 48);
+ else
+ assert(0);
+ break;
+
+ case ASGN+B:
+ dalign = salign = p->syms[1]->u.c.v.i;
+ blkcopy(getregnum(p->x.kids[0]), 0,
+ getregnum(p->x.kids[1]), 0,
+ p->syms[0]->u.c.v.i, tmpregs);
+ break;
+
+
+ case ARG+B: {
+ int doff = p->syms[2]->u.c.v.i, soff = 0, sreg = getregnum(p->x.kids[0]);
+ dalign = 8;
+ salign = p->syms[1]->u.c.v.i;
+ n = p->syms[0]->u.c.v.i;
+ for ( ; doff <= 40 && n > 0; doff += 8) {
+ print("uldq $%d,%d($%d)\n", (doff/8)+16, soff, sreg);
+ soff += 8;
+ n -= 8;
+ }
+ if (n > 0)
+ blkcopy(30, doff - 48, sreg, soff, n, tmpregs);
+ break;
+ }
+
+ }
+}
+
+static void doarg(Node p) {
+ p->syms[2] = intconst(mkactual(8, roundup(p->syms[0]->u.c.v.i,8)));
+}
+
+static void local(Symbol p) {
+ if (askregvar(p, rmap(ttob(p->type))) == 0)
+ mkauto(p);
+}
+
+static int bitcount(unsigned mask) {
+ unsigned i, n = 0;
+
+ for (i = 1; i; i <<= 1)
+ if (mask&i)
+ n++;
+ return n;
+}
+
+static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
+ int i, sizeargs, saved, sizefsave, sizeisave, varargs;
+ Symbol r, argregs[6];
+
+ usedmask[0] = usedmask[1] = 0;
+ freemask[0] = freemask[1] = ~(unsigned)0;
+ maxargoffset = offset = maxoffset = 0;
+
+ for (i = 0; callee[i]; i++)
+ ;
+ varargs = variadic(f->type)
+ || i > 0 && strcmp(callee[i-1]->name, "va_alist") == 0;
+ if (varargs)
+ sizeargs = 2*48;
+ else
+ sizeargs = 48;
+
+ for (i = 0; callee[i]; i++) {
+ Symbol p = callee[i];
+ Symbol q = caller[i];
+ assert(q);
+ if (isfloat(p->type) && varargs) {
+ p->x.offset = q->x.offset = offset - 2*48;
+ p->x.name = q->x.name = stringd(offset - 2*48);
+ } else {
+ p->x.offset = q->x.offset = offset - 48;
+ p->x.name = q->x.name = stringd(offset - 48);
+ }
+ offset = roundup(offset, q->type->align);
+ r = argreg(offset, optype(ttob(q->type)));
+ if (i < 6)
+ argregs[i] = r;
+ offset = roundup(offset + q->type->size, 8);
+ if (varargs)
+ p->sclass = AUTO;
+ else if (r && ncalls == 0 && !isstruct(q->type) && !p->addressed
+) {
+ p->sclass = q->sclass = REGISTER;
+ askregvar(p, r);
+ assert(p->x.regnode && p->x.regnode->vbl == p);
+ q->x = p->x;
+ q->type = p->type;
+ } else if (askregvar(p, rmap(ttob(p->type)))
+ && r != NULL /*
+ && (isint(p->type) || p->type == q->type) */
+) {
+ assert(q->sclass != REGISTER);
+ p->sclass = q->sclass = REGISTER;
+ q->type = p->type;
+ }
+
+ }
+ assert(!caller[i]);
+
+ offset = sizeargs + 8;
+ gencode(caller, callee);
+ usedmask[IREG] &= ~(INTTMP|(0x3f<<16)|INTRET);
+ usedmask[FREG] &= ~(FLTTMP|(0x3f<<16)|FLTRET);
+ if (ncalls || usedmask[IREG] || usedmask[FREG])
+ usedmask[IREG] |= 1<<26;
+ sizefsave = 8*bitcount(usedmask[FREG]);
+ sizeisave = 8*bitcount(usedmask[IREG]);
+ if (maxargoffset > 48)
+ maxargoffset -= 48;
+ else
+ maxargoffset = 0;
+ if (maxoffset < sizeargs)
+ maxoffset = sizeargs;
+ framesize = roundup(maxargoffset + sizefsave + sizeisave + maxoffset, 16);
+ segment(CODE);
+ print(".ent %s\n", f->x.name);
+ print("%s:\n", f->x.name);
+ print("ldgp $gp,0($27)\n");
+ i = maxargoffset + sizefsave - framesize;
+ if (framesize > 0)
+ print("lda $sp,%d($sp)\n", -framesize);
+ if (usedmask[FREG])
+ print(".fmask 0x%x,%d\n", usedmask[FREG], i - 8);
+ if (usedmask[IREG])
+ print(".mask 0x%x,%d\n", usedmask[IREG], i + sizeisave - 8);
+ print(".frame $sp,%d,$26,%d\n", framesize, sizeargs);
+
+ saved = maxargoffset;
+ for (i = 2; i <= 9; i++)
+ if (usedmask[FREG]&(1<<i)) {
+ print("stt $f%d,%d($sp)\n", i, saved);
+ saved += 8;
+ }
+
+ for (i = 9; i <= 26; i++)
+ if (usedmask[IREG]&(1<<i)) {
+ print("stq $%d,%d($sp)\n", i, saved);
+ saved += 8;
+ }
+ for (i = 0; i < 6 && callee[i]; i++) {
+ r = argregs[i];
+ if (r && r->x.regnode != callee[i]->x.regnode) {
+ Symbol out = callee[i];
+ Symbol in = caller[i];
+ int rn = r->x.regnode->number;
+ int rs = r->x.regnode->set;
+ int tyin = ttob(in->type);
+
+ assert(out && in && r && r->x.regnode);
+ assert(out->sclass != REGISTER || out->x.regnode);
+ if (out->sclass == REGISTER) {
+ if (rs == FREG)
+ print("fmov $f%d,$f%d\n", rn, out->x.regnode->number);
+ else
+ print("mov $%d,$%d\n", rn, out->x.regnode->number);
+
+ } else {
+ int off = in->x.offset + framesize;
+ if (rs == FREG && tyin == F+sizeop(8))
+ print("stt $f%d,%d($sp)\n", rn, off);
+ else if (rs == FREG && tyin == F+sizeop(4))
+ print("sts $f%d,%d($sp)\n", rn, off);
+ else {
+ int i, n = (in->type->size + 7)/8;
+ for (i = rn; i < rn+n && i <= 21; i++)
+ print("stq $%d,%d($sp)\n", i, off + (i-rn)*8);
+ }
+
+ }
+
+ }
+ }
+ if (varargs && callee[i-1]) {
+ i = callee[i-1]->x.offset + roundup(callee[i-1]->type->size, 8);
+ for (i = (48+i)/8; i < 6; i++) {
+ print("stq $%d,%d($sp)\n", i + 16, framesize - 48 + 8*i);
+ print("stt $f%d,%d($sp)\n", i + 16, framesize - 2*48 + 8*i);
+ }
+ }
+ print(".prologue 1\n");
+
+ emitcode();
+ saved = maxargoffset;
+ for (i = 2; i <= 9; i++)
+ if (usedmask[FREG]&(1<<i)) {
+ print("ldt $f%d,%d($sp)\n", i, saved);
+ saved += 8;
+ }
+ for (i = 9; i <= 26; i++)
+ if (usedmask[IREG]&(1<<i)) {
+ print("ldq $%d,%d($sp)\n", i, saved);
+ saved += 8;
+ }
+ if (framesize > 0)
+ print("lda $sp,%d($sp)\n", framesize);
+ print("ret\n");
+ print(".end %s\n", f->x.name);
+
+}
+
+static void defconst(int suffix, int size, Value v) {
+ if (suffix == F && size == 4) {
+ float f = v.d;
+ print(".long 0x%x\n", *(unsigned *)&f);
+ } else if (suffix == F && size == 8) {
+ double d = v.d;
+ unsigned *p = (unsigned *)&d;
+ print(".long 0x%x\n.long 0x%x\n", p[swap], p[!swap]);
+ } else if (suffix == P)
+ print(".quad 0x%X\n", v.p);
+ else if (size == 1)
+ print(".byte 0x%x\n", suffix == I ? v.i : v.u);
+ else if (size == 2)
+ print(".word 0x%x\n", suffix == I ? v.i&0xFFFF : v.u&0xFFFF);
+ else if (size == 4)
+ print(".long 0x%x\n", suffix == I ? v.i : v.u);
+ else if (size == 8)
+ print(".quad 0x%X\n", suffix == I ? v.i : v.u);
+
+}
+
+static void defaddress(Symbol p) {
+ print(".quad %s\n", p->x.name);
+}
+
+static void defstring(int n, char *str) {
+ char *s;
+
+ for (s = str; s < str + n; s++)
+ print(".byte %d\n", (*s)&0377);
+}
+
+static void export(Symbol p) {
+ print(".globl %s\n", p->x.name);
+}
+
+static void import(Symbol p) {
+ if (!isfunc(p->type))
+ print(".extern %s %d\n", p->name, p->type->size);
+}
+
+static void defsymbol(Symbol p) {
+ if (p->scope >= LOCAL && p->sclass == STATIC)
+ p->x.name = stringf("L.%d", genlabel(1));
+ else if (p->generated)
+ p->x.name = stringf("L.%s", p->name);
+ else
+ assert(p->scope != CONSTANTS || isint(p->type) || isptr(p->type)),
+ p->x.name = p->name;
+}
+
+static void address(Symbol q, Symbol p, long n) {
+ if (p->scope == GLOBAL
+ || p->sclass == STATIC || p->sclass == EXTERN)
+ q->x.name = stringf("%s%s%D", p->x.name,
+ n >= 0 ? "+" : "", n);
+ else {
+ assert(n <= INT_MAX && n >= INT_MIN);
+ q->x.offset = p->x.offset + n;
+ q->x.name = stringd(q->x.offset);
+ }
+}
+
+static void global(Symbol p) {
+ if (p->u.seg == DATA || p->u.seg == LIT) {
+ assert(p->type->align <= 8);
+ print(".align %c\n", ".01.2...3"[p->type->align]);
+ print("%s:\n", p->x.name);
+ } else if (p->sclass == STATIC || Aflag >= 2)
+ print(".lcomm %s,%d\n", p->x.name, p->type->size);
+ else
+ print( ".comm %s,%d\n", p->x.name, p->type->size);
+}
+
+static void segment(int n) {
+ cseg = n;
+ switch (n) {
+ case DATA: print(".sdata\n"); break;
+ case CODE: print(".text\n"); break;
+ case LIT: print(".rdata\n"); break;
+ }
+}
+
+static void space(int n) {
+ if (cseg != BSS)
+ print(".space %d\n", n);
+}
+
+static void blkloop(int dreg, int doff, int sreg, int soff, int size, int tmps[]) {
+ int lab = genlabel(1);
+
+ print("addq $%d,%d,$%d\n", sreg, size&~7, sreg);
+ print("addq $%d,%d,$%d\n", dreg, size&~7, tmps[2]);
+ blkcopy(tmps[2], doff, sreg, soff, size&7, tmps);
+ print("L.%d:\n", lab);
+ print("addq $%d,%d,$%d\n", sreg, -8, sreg);
+ print("addq $%d,%d,$%d\n", tmps[2], -8, tmps[2]);
+ blkcopy(tmps[2], doff, sreg, soff, 8, tmps);
+ print("cmpult $%d,$%d,$23\nbne $23,L.%d\n", dreg, tmps[2], lab);
+}
+
+static void blkfetch(int size, int off, int reg, int tmp) {
+ assert(size == 1 || size == 2 || size == 4 || size == 8);
+ if (size == 1)
+ print("ldb $%d,%d($%d)\n", tmp, off, reg);
+ else if (size == 2)
+ print("ldw $%d,%d($%d)\n", tmp, off, reg);
+ else if (salign >= size && size == 4)
+ print("ldl $%d,%d($%d)\n", tmp, off, reg);
+ else if (salign >= size && size == 8)
+ print("ldq $%d,%d($%d)\n", tmp, off, reg);
+ else if (size == 4)
+ print("uldl $%d,%d($%d)\n", tmp, off, reg);
+ else
+ print("uldq $%d,%d($%d)\n", tmp, off, reg);
+}
+
+static void blkstore(int size, int off, int reg, int tmp) {
+ assert(size == 1 || size == 2 || size == 4 || size == 8);
+ if (size == 1)
+ print("stb $%d,%d($%d)\n", tmp, off, reg);
+ else if (size == 2)
+ print("stw $%d,%d($%d)\n", tmp, off, reg);
+ else if (dalign >= size && size == 4)
+ print("stl $%d,%d($%d)\n", tmp, off, reg);
+ else if (dalign >= size && size == 8)
+ print("stq $%d,%d($%d)\n", tmp, off, reg);
+ else if (size == 4)
+ print("ustl $%d,%d($%d)\n", tmp, off, reg);
+ else
+ print("ustq $%d,%d($%d)\n", tmp, off, reg);
+}
+
+/* stabinit - initialize stab output */
+static void stabinit(char *file, int argc, char *argv[]) {
+ if (file) {
+ print(".file 2,\"%s\"\n", file);
+ currentfile = file;
+ }
+}
+
+/* stabline - emit stab entry for source coordinate *cp */
+static void stabline(Coordinate *cp) {
+ if (cp->file && cp->file != currentfile) {
+ print(".file 2,\"%s\"\n", cp->file);
+ currentfile = cp->file;
+ }
+ print(".loc 2,%d\n", cp->y);
+}
+
+/* stabsym - output a stab entry for symbol p */
+static void stabsym(Symbol p) {
+ if (p == cfunc && IR->stabline)
+ (*IR->stabline)(&p->src);
+}
+Interface alphaIR = {
+ 1, 1, 0, /* char */
+ 2, 2, 0, /* short */
+ 4, 4, 0, /* int */
+ 8, 8, 0, /* long */
+ 8, 8, 0, /* long long */
+ 4, 4, 1, /* float */
+ 8, 8, 1, /* double */
+ 8, 8, 1, /* long double */
+ 8, 8, 0, /* T * */
+ 0, 1, 0, /* struct */
+
+ 1, /* little_endian */
+ 0, /* mulops_calls */
+ 0, /* wants_callb */
+ 1, /* wants_argb */
+ 1, /* left_to_right */
+ 0, /* wants_dag */
+ 0, /* unsigned_char */
+ address,
+ blockbeg,
+ blockend,
+ defaddress,
+ defconst,
+ defstring,
+ defsymbol,
+ emit,
+ export,
+ function,
+ gen,
+ global,
+ import,
+ local,
+ progbeg,
+ progend,
+ segment,
+ space,
+ 0, 0, 0, stabinit, stabline, stabsym, 0,
+ {
+ 1, /* max_unaligned_load */
+ rmap,
+ blkfetch, blkstore, blkloop,
+ _label,
+ _rule,
+ _nts,
+ _kids,
+ _string,
+ _templates,
+ _isinstruction,
+ _ntname,
+ emit2,
+ doarg,
+ target,
+ clobber,
+
+ }
+
+};
+
+
+static char rcsid[] = "$Id: alpha.md 145 2001-10-17 21:53:10Z timo $";
+
diff --git a/lcc/src/asdl.c b/lcc/src/asdl.c
new file mode 100755
index 0000000..1c01c0c
--- /dev/null
+++ b/lcc/src/asdl.c
@@ -0,0 +1,399 @@
+#include "c.h"
+#include "rcc.h"
+#if WIN32
+#include <fcntl.h>
+#include <io.h>
+#endif
+
+
+static list_ty interfaces;
+static rcc_program_ty pickle;
+
+char *string(const char *str) {
+ return (char *)Atom_string(str);
+}
+
+char *stringd(long n) {
+ return (char *)Atom_int(n);
+}
+
+char *stringn(const char *str, int len) {
+ return (char *)Atom_new(str, len);
+}
+
+static void put(rcc_interface_ty node) {
+ Seq_addhi(interfaces, node);
+}
+
+static int typeuid(Type ty) {
+ rcc_type_ty type;
+
+ assert(ty);
+ if (ty->x.typeno != 0)
+ return ty->x.typeno;
+ ty->x.typeno = pickle->nuids++;
+ switch (ty->op) {
+#define xx(op) case op: type = rcc_##op(ty->size, ty->align); break
+ xx(INT);
+ xx(UNSIGNED);
+ xx(FLOAT);
+ xx(VOID);
+#undef xx
+#define xx(op) case op: type = rcc_##op(ty->size, ty->align, typeuid(ty->type)); break
+ xx(POINTER);
+ xx(ARRAY);
+ xx(CONST);
+ xx(VOLATILE);
+#undef xx
+ case CONST+VOLATILE:
+ type = rcc_CONST(ty->size, ty->align, typeuid(ty->type));
+ break;
+ case ENUM: {
+ list_ty ids = Seq_new(0);
+ int i;
+ for (i = 0; ty->u.sym->u.idlist[i] != NULL; i++)
+ Seq_addhi(ids, rcc_enum_(ty->u.sym->u.idlist[i]->name,
+ ty->u.sym->u.idlist[i]->u.value));
+ assert(i > 0);
+ type = rcc_ENUM(ty->size, ty->align, ty->u.sym->name, ids);
+ break;
+ }
+ case STRUCT: case UNION: {
+ list_ty fields = Seq_new(0);
+ Field p = fieldlist(ty);
+ for ( ; p != NULL; p = p->link)
+ Seq_addhi(fields, rcc_field(p->name, typeuid(p->type), p->offset, p->bitsize, p->lsb));
+ if (ty->op == STRUCT)
+ type = rcc_STRUCT(ty->size, ty->align, ty->u.sym->name, fields);
+ else
+ type = rcc_UNION (ty->size, ty->align, ty->u.sym->name, fields);
+ break;
+ }
+ case FUNCTION: {
+ list_ty formals = Seq_new(0);
+ if (ty->u.f.proto != NULL && ty->u.f.proto[0] != NULL) {
+ int i;
+ for (i = 0; ty->u.f.proto[i] != NULL; i++)
+ Seq_addhi(formals, to_generic_int(typeuid(ty->u.f.proto[i])));
+ } else if (ty->u.f.proto != NULL && ty->u.f.proto[0] == NULL)
+ Seq_addhi(formals, to_generic_int(typeuid(voidtype)));
+ type = rcc_FUNCTION(ty->size, ty->align, typeuid(ty->type), formals);
+ break;
+ }
+ default: assert(0);
+ }
+ Seq_addhi(pickle->items, rcc_Type(ty->x.typeno, type));
+ return ty->x.typeno;
+}
+
+static int symboluid(Symbol p) {
+ assert(p);
+ assert(p->scope != CONSTANTS && p->scope != LABELS);
+ if (p->x.offset == 0)
+ p->x.offset = pickle->nuids++;
+ return p->x.offset;
+}
+
+static rcc_symbol_ty mk_symbol(Symbol p) {
+ int flags = 0, ref = 10000*p->ref;
+
+ if (p->ref > 0 && ref == 0)
+ ref++;
+#define xx(f,n) flags |= p->f<<n;
+ xx(structarg,0)
+ xx(addressed,1)
+ xx(computed,2)
+ xx(temporary,3)
+ xx(generated,4)
+#undef xx
+ return rcc_symbol(p->name, typeuid(p->type), p->scope, p->sclass, ref, flags);
+}
+
+static rcc_real_ty mk_real(int size, Value v) {
+ unsigned *p = (unsigned *)&v.d;
+ return rcc_real(p[swap], p[1-swap]);
+}
+
+static void asdl_segment(int n) {
+ static int cseg;
+
+ if (cseg != n)
+ put(rcc_Segment(cseg = n));
+}
+
+static void asdl_address(Symbol q, Symbol p, long n) {
+ assert(q->x.offset == 0);
+ put(rcc_Address(symboluid(q), mk_symbol(q), symboluid(p), n));
+}
+
+static void asdl_blockbeg(Env *e) {
+ put(rcc_Blockbeg());
+}
+
+static void asdl_blockend(Env *e) {
+ put(rcc_Blockend());
+}
+
+static void asdl_defaddress(Symbol p) {
+ if (p->scope == LABELS)
+ put(rcc_Deflabel(p->u.l.label));
+ else
+ put(rcc_Defaddress(symboluid(p)));
+}
+
+static void asdl_defconst(int suffix, int size, Value v) {
+ switch (suffix) {
+ case I: put(rcc_Defconst(suffix, size, v.i)); return;
+ case U: put(rcc_Defconst(suffix, size, v.u)); return;
+ case P: put(rcc_Defconst(suffix, size, (unsigned long)v.p)); return; /* FIXME */
+ case F: put(rcc_Defconstf(size, mk_real(size, v))); return;
+ assert(0);
+ }
+}
+
+static void asdl_defstring(int len, char *str) {
+ put(rcc_Defstring(Text_box(stringn(str, len), len)));
+}
+
+static void asdl_defsymbol(Symbol p) {
+ if (p->scope >= GLOBAL)
+ symboluid(p);
+}
+
+static Symbol temps;
+
+static rcc_node_ty visit(Node p) {
+ Symbol q;
+ rcc_node_ty left = NULL, right = NULL;
+ int suffix = optype(p->op), size = opsize(p->op);
+
+ assert(p);
+ for (q = temps; q; q = q->u.t.next)
+ if (q->u.t.cse == p) {
+ q->u.t.cse = NULL;
+ return rcc_CSE(0, 0, symboluid(q), visit(p));
+ }
+ if (p->kids[0] != NULL)
+ left = visit(p->kids[0]);
+ if (p->kids[1] != NULL)
+ right = visit(p->kids[1]);
+ switch (specific(p->op)) {
+ case CNST+F:
+ assert(p->syms[0]);
+ return rcc_CNSTF(suffix, size, mk_real(size, p->syms[0]->u.c.v));
+ case CALL+B:
+ assert(p->syms[0]);
+ assert(p->syms[0]->type);
+ return rcc_CALLB(suffix, size, left, right, typeuid(p->syms[0]->type));
+ case RET+V:
+ return rcc_RET(suffix, size);
+ case LABEL+V:
+ assert(p->syms[0]);
+ return rcc_LABEL(suffix, size, p->syms[0]->u.l.label);
+ }
+ switch (generic(p->op)) {
+ case CNST:
+ assert(p->syms[0]);
+ return rcc_CNST(suffix, size, p->syms[0]->u.c.v.i); /* FIXME */
+ case ARG:
+ assert(p->syms[0]);
+ return rcc_ARG(suffix, size, left, p->syms[0]->u.c.v.i, p->syms[1]->u.c.v.i);
+ case ASGN:
+ assert(p->syms[0]);
+ assert(p->syms[1]);
+ return rcc_ASGN(suffix, size, left, right, p->syms[0]->u.c.v.i, p->syms[1]->u.c.v.i);
+ case CVF: case CVI: case CVP: case CVU:
+ assert(p->syms[0]);
+ return rcc_CVT(suffix, size, generic(p->op), left, p->syms[0]->u.c.v.i);
+ case CALL:
+ assert(p->syms[0]);
+ assert(p->syms[0]->type);
+ return rcc_CALL(suffix, size, left, typeuid(p->syms[0]->type));
+#define xx(op) case op: return rcc_##op(suffix, size, symboluid(p->syms[0]))
+ xx(ADDRG);
+ xx(ADDRF);
+#undef xx
+ case ADDRL:
+ if (!p->syms[0]->defined)
+ (*IR->local)(p->syms[0]);
+ p->syms[0]->defined = 1;
+ return rcc_ADDRL(suffix, size, symboluid(p->syms[0]));
+ case JUMP:
+ if (p->syms[0] != NULL)
+ return rcc_BRANCH(suffix, size, p->syms[0]->u.l.label);
+ return rcc_Unary(suffix, size, generic(p->op), left);
+ case INDIR: case RET: case NEG: case BCOM:
+ return rcc_Unary(suffix, size, generic(p->op), left);
+ case BOR: case BAND: case BXOR: case RSH: case LSH:
+ case ADD: case SUB: case DIV: case MUL: case MOD:
+ return rcc_Binary(suffix, size, generic(p->op), left, right);
+ case EQ: case NE: case GT: case GE: case LE: case LT:
+ assert(p->syms[0]);
+ return rcc_Compare(suffix, size, generic(p->op), left, right, p->syms[0]->u.l.label);
+ }
+ assert(0);
+ return NULL;
+}
+
+static void asdl_emit(Node p) {}
+
+static void asdl_local(Symbol p) {
+ assert(p->x.offset == 0);
+ put(rcc_Local(symboluid(p), mk_symbol(p)));
+ if (p->temporary && p->u.t.cse) {
+ p->u.t.next = temps;
+ temps = p;
+ }
+}
+
+static Symbol pending = NULL;
+
+static void dopending(Symbol p) {
+ if (pending != NULL) {
+ int uid = symboluid(pending);
+ rcc_symbol_ty symbol = mk_symbol(pending);
+ Seq_addhi(pickle->items, rcc_Symbol(uid, symbol));
+ }
+ pending = p;
+}
+
+
+static void asdl_export(Symbol p) {
+ put(rcc_Export(symboluid(p)));
+}
+
+static void asdl_function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
+ list_ty codelist = Seq_new(0), save, calleelist = Seq_new(0), callerlist = Seq_new(0);
+ int i;
+
+ dopending(f);
+ for (i = 0; caller[i] != NULL; i++) {
+ asdl_local(caller[i]);
+ Seq_addhi(callerlist, to_generic_int(symboluid(caller[i])));
+ }
+ for (i = 0; callee[i] != NULL; i++) {
+ asdl_local(callee[i]);
+ Seq_addhi(calleelist, to_generic_int(symboluid(callee[i])));
+ }
+ save = interfaces;
+ interfaces = codelist;
+ gencode(caller, callee);
+ asdl_segment(CODE);
+ emitcode();
+ interfaces = save;
+ put(rcc_Function(symboluid(f), callerlist, calleelist, ncalls, codelist));
+}
+
+static Node asdl_gen(Node p) {
+ Node q;
+ list_ty forest = Seq_new(0);
+
+ for (q = p; p != NULL; p = p->link)
+ if (specific(p->op) == JUMP+V && specific(p->kids[0]->op) == ADDRG+P
+ && p->kids[0]->syms[0]->scope == LABELS) {
+ p->syms[0] = p->kids[0]->syms[0];
+ p->kids[0] = NULL;
+ }
+ for (p = q; p != NULL; p = p->link)
+ Seq_addhi(forest, visit(p));
+ put(rcc_Forest(forest));
+ temps = NULL;
+ return q;
+}
+
+static void asdl_global(Symbol p) {
+ dopending(p);
+ put(rcc_Global(symboluid(p), p->u.seg));
+}
+
+static void asdl_import(Symbol p) {
+ dopending(p);
+ put(rcc_Import(symboluid(p)));
+}
+
+static void asdl_progbeg(int argc, char *argv[]) {
+ int i;
+
+#if WIN32
+ _setmode(_fileno(stdout), _O_BINARY);
+#endif
+ pickle = rcc_program(1, 0, Seq_new(0), Seq_new(0), argc, Seq_new(0));
+ for (i = 0; i < argc; i++)
+ Seq_addhi(pickle->argv, to_generic_string(Text_box(argv[i], strlen(argv[i]) + 1)));
+ interfaces = pickle->interfaces;
+}
+
+static int checkuid(list_ty list) {
+ int i, n = 0, count = Seq_length(list);
+
+ for (i = 0; i < count; i++) {
+ rcc_interface_ty in = Seq_get(list, i);
+ if (in->kind == rcc_Local_enum
+ || in->kind == rcc_Address_enum)
+ n++;
+ else if (in->kind == rcc_Function_enum)
+ n += checkuid(in->v.rcc_Function.codelist);
+ }
+ return n;
+}
+
+static void asdl_progend(void) {
+ dopending(NULL);
+ {
+ int n = checkuid(pickle->interfaces) + Seq_length(pickle->items);
+ if (n != pickle->nuids - 1)
+ fprintf(stderr, "?bogus uid count: have %d should have %d\n",
+ n, pickle->nuids-1);
+ }
+ pickle->nlabels = genlabel(0);
+ write_int((int)(100*(assert(strstr(rcsid, ",v")), strtod(strstr(rcsid, ",v")+2, NULL))
+), stdout);
+ rcc_write_program(pickle, stdout);
+}
+static void asdl_space(int n) {
+ put(rcc_Space(n));
+}
+
+void asdl_init(int argc, char *argv[]) {
+ int i;
+ static int inited;
+
+ if (inited)
+ return;
+ inited = 1;
+ for (i = 1; i < argc; i++)
+ if (strcmp(argv[i], "-asdl") == 0) {
+#define xx(f) IR->f = asdl_##f
+ xx(address);
+ xx(blockbeg);
+ xx(blockend);
+ xx(defaddress);
+ xx(defconst);
+ xx(defstring);
+ xx(defsymbol);
+ xx(emit);
+ xx(export);
+ xx(function);
+ xx(gen);
+ xx(global);
+ xx(import);
+ xx(local);
+ xx(progbeg);
+ xx(progend);
+ xx(segment);
+ xx(space);
+#undef xx
+#define xx(f) IR->f = 0
+ xx(stabblock);
+ xx(stabend);
+ xx(stabfend);
+ xx(stabinit);
+ xx(stabline);
+ xx(stabsym);
+ xx(stabtype);
+#undef xx
+ IR->wants_dag = 0;
+ prunetemps = 0; /* pass2 prunes useless temps */
+ assignargs = 0; /* pass2 generates caller to callee assignments */
+ }
+}
diff --git a/lcc/src/bind.c b/lcc/src/bind.c
new file mode 100755
index 0000000..3723e37
--- /dev/null
+++ b/lcc/src/bind.c
@@ -0,0 +1,23 @@
+#include "c.h"
+extern Interface alphaIR;
+extern Interface mipsebIR, mipselIR;
+extern Interface sparcIR, solarisIR;
+extern Interface x86IR, x86linuxIR;
+extern Interface symbolicIR, symbolic64IR;
+extern Interface nullIR;
+extern Interface bytecodeIR;
+Binding bindings[] = {
+ "alpha/osf", &alphaIR,
+ "mips/irix", &mipsebIR,
+ "mips/ultrix", &mipselIR,
+ "sparc/sun", &sparcIR,
+ "sparc/solaris", &solarisIR,
+ "x86/win32", &x86IR,
+ "x86/linux", &x86linuxIR,
+ "symbolic/osf", &symbolic64IR,
+ "symbolic/irix", &symbolicIR,
+ "symbolic", &symbolicIR,
+ "null", &nullIR,
+ "bytecode", &bytecodeIR,
+ NULL, NULL
+};
diff --git a/lcc/src/bytecode.c b/lcc/src/bytecode.c
new file mode 100755
index 0000000..f32a04f
--- /dev/null
+++ b/lcc/src/bytecode.c
@@ -0,0 +1,365 @@
+#include "c.h"
+#define I(f) b_##f
+
+
+static void I(segment)(int n) {
+ static int cseg;
+
+ if (cseg != n)
+ switch (cseg = n) {
+ case CODE: print("code\n"); return;
+ case DATA: print("data\n"); return;
+ case BSS: print("bss\n"); return;
+ case LIT: print("lit\n"); return;
+ default: assert(0);
+ }
+}
+
+static void I(address)(Symbol q, Symbol p, long n) {
+ q->x.name = stringf("%s%s%D", p->x.name, n > 0 ? "+" : "", n);
+}
+
+static void I(defaddress)(Symbol p) {
+ print("address %s\n", p->x.name);
+}
+
+static void I(defconst)(int suffix, int size, Value v) {
+ switch (suffix) {
+ case I:
+ if (size > sizeof (int))
+ print("byte %d %D\n", size, v.i);
+ else
+ print("byte %d %d\n", size, v.i);
+ return;
+ case U:
+ if (size > sizeof (unsigned))
+ print("byte %d %U\n", size, v.u);
+ else
+ print("byte %d %u\n", size, v.u);
+ return;
+ case P: print("byte %d %U\n", size, (unsigned long)v.p); return;
+ case F:
+ if (size == 4) {
+ float f = v.d;
+ print("byte 4 %u\n", *(unsigned *)&f);
+ } else {
+ unsigned *p = (unsigned *)&v.d;
+ print("byte 4 %u\n", p[swap]);
+ print("byte 4 %u\n", p[1 - swap]);
+ }
+ return;
+ }
+ assert(0);
+}
+
+static void I(defstring)(int len, char *str) {
+ char *s;
+
+ for (s = str; s < str + len; s++)
+ print("byte 1 %d\n", (*s)&0377);
+}
+
+static void I(defsymbol)(Symbol p) {
+ if (p->scope == CONSTANTS)
+ switch (optype(ttob(p->type))) {
+ case I: p->x.name = stringf("%D", p->u.c.v.i); break;
+ case U: p->x.name = stringf("%U", p->u.c.v.u); break;
+ case P: p->x.name = stringf("%U", p->u.c.v.p); break;
+ case F:
+ { // JDC: added this to get inline floats
+ unsigned temp;
+
+ *(float *)&temp = p->u.c.v.d;
+ p->x.name = stringf("%U", temp );
+ }
+ break;// JDC: added this
+ default: assert(0);
+ }
+ else if (p->scope >= LOCAL && p->sclass == STATIC)
+ p->x.name = stringf("$%d", genlabel(1));
+ else if (p->scope == LABELS || p->generated)
+ p->x.name = stringf("$%s", p->name);
+ else
+ p->x.name = p->name;
+}
+
+static void dumptree(Node p) {
+ switch (specific(p->op)) {
+ case ASGN+B:
+ assert(p->kids[0]);
+ assert(p->kids[1]);
+ assert(p->syms[0]);
+ dumptree(p->kids[0]);
+ dumptree(p->kids[1]);
+ print("%s %d\n", opname(p->op), p->syms[0]->u.c.v.u);
+ return;
+ case RET+V:
+ assert(!p->kids[0]);
+ assert(!p->kids[1]);
+ print("%s\n", opname(p->op));
+ return;
+ }
+ switch (generic(p->op)) {
+ case CNST: case ADDRG: case ADDRF: case ADDRL: case LABEL:
+ assert(!p->kids[0]);
+ assert(!p->kids[1]);
+ assert(p->syms[0] && p->syms[0]->x.name);
+ print("%s %s\n", opname(p->op), p->syms[0]->x.name);
+ return;
+ case CVF: case CVI: case CVP: case CVU:
+ assert(p->kids[0]);
+ assert(!p->kids[1]);
+ assert(p->syms[0]);
+ dumptree(p->kids[0]);
+ print("%s %d\n", opname(p->op), p->syms[0]->u.c.v.i);
+ return;
+ case ARG: case BCOM: case NEG: case INDIR: case JUMP: case RET:
+ assert(p->kids[0]);
+ assert(!p->kids[1]);
+ dumptree(p->kids[0]);
+ print("%s\n", opname(p->op));
+ return;
+ case CALL:
+ assert(p->kids[0]);
+ assert(!p->kids[1]);
+ assert(optype(p->op) != B);
+ dumptree(p->kids[0]);
+ print("%s\n", opname(p->op));
+ if ( !p->count ) { printf("pop\n"); }; // JDC
+ return;
+ case ASGN: case BOR: case BAND: case BXOR: case RSH: case LSH:
+ case ADD: case SUB: case DIV: case MUL: case MOD:
+ assert(p->kids[0]);
+ assert(p->kids[1]);
+ dumptree(p->kids[0]);
+ dumptree(p->kids[1]);
+ print("%s\n", opname(p->op));
+ return;
+ case EQ: case NE: case GT: case GE: case LE: case LT:
+ assert(p->kids[0]);
+ assert(p->kids[1]);
+ assert(p->syms[0]);
+ assert(p->syms[0]->x.name);
+ dumptree(p->kids[0]);
+ dumptree(p->kids[1]);
+ print("%s %s\n", opname(p->op), p->syms[0]->x.name);
+ return;
+ }
+ assert(0);
+}
+
+static void I(emit)(Node p) {
+ for (; p; p = p->link)
+ dumptree(p);
+}
+
+static void I(export)(Symbol p) {
+ print("export %s\n", p->x.name);
+}
+
+static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
+ int i;
+
+ (*IR->segment)(CODE);
+ offset = 0;
+ for (i = 0; caller[i] && callee[i]; i++) {
+ offset = roundup(offset, caller[i]->type->align);
+ caller[i]->x.name = callee[i]->x.name = stringf("%d", offset);
+ caller[i]->x.offset = callee[i]->x.offset = offset;
+ offset += caller[i]->type->size;
+ }
+ maxargoffset = maxoffset = argoffset = offset = 0;
+ gencode(caller, callee);
+ print("proc %s %d %d\n", f->x.name, maxoffset, maxargoffset);
+ emitcode();
+ print("endproc %s %d %d\n", f->x.name, maxoffset, maxargoffset);
+
+}
+
+static void gen02(Node p) {
+ assert(p);
+ if (generic(p->op) == ARG) {
+ assert(p->syms[0]);
+ argoffset += (p->syms[0]->u.c.v.i < 4 ? 4 : p->syms[0]->u.c.v.i);
+ } else if (generic(p->op) == CALL) {
+ maxargoffset = (argoffset > maxargoffset ? argoffset : maxargoffset);
+ argoffset = 0;
+ }
+}
+
+static void gen01(Node p) {
+ if (p) {
+ gen01(p->kids[0]);
+ gen01(p->kids[1]);
+ gen02(p);
+ }
+}
+
+static Node I(gen)(Node p) {
+ Node q;
+
+ assert(p);
+ for (q = p; q; q = q->link)
+ gen01(q);
+ return p;
+}
+
+static void I(global)(Symbol p) {
+ print("align %d\n", p->type->align > 4 ? 4 : p->type->align);
+ print("LABELV %s\n", p->x.name);
+}
+
+static void I(import)(Symbol p) {
+ print("import %s\n", p->x.name);
+}
+
+static void I(local)(Symbol p) {
+ offset = roundup(offset, p->type->align);
+ p->x.name = stringf("%d", offset);
+ p->x.offset = offset;
+ offset += p->type->size;
+}
+
+static void I(progbeg)(int argc, char *argv[]) {}
+
+static void I(progend)(void) {}
+
+static void I(space)(int n) {
+ print("skip %d\n", n);
+}
+
+//========================================================
+
+// JDC: hacked up to get interleaved source lines in asm code
+static char *sourceFile;
+static char *sourcePtr;
+static int sourceLine;
+
+static int filelength( FILE *f ) {
+ int pos;
+ int end;
+
+ pos = ftell (f);
+ fseek (f, 0, SEEK_END);
+ end = ftell (f);
+ fseek (f, pos, SEEK_SET);
+
+ return end;
+}
+
+static void LoadSourceFile( const char *filename ) {
+ FILE *f;
+ int length;
+
+ f = fopen( filename, "r" );
+ if ( !f ) {
+ print( ";couldn't open %s\n", filename );
+ sourceFile = NULL;
+ return;
+ }
+ length = filelength( f );
+ sourceFile = malloc( length + 1 );
+ if ( sourceFile ) {
+ fread( sourceFile, length, 1, f );
+ sourceFile[length] = 0;
+ }
+
+ fclose( f );
+ sourceLine = 1;
+ sourcePtr = sourceFile;
+}
+
+static void PrintToSourceLine( int line ) {
+ int c;
+
+ if ( !sourceFile ) {
+ return;
+ }
+ while ( sourceLine <= line ) {
+ int i;
+
+ for ( i = 0 ; sourcePtr[i] && sourcePtr[i] != '\n' ; i++ ) {
+ }
+ c = sourcePtr[i];
+ if ( c == '\n' ) {
+ sourcePtr[i] = 0;
+ }
+ print( ";%d:%s\n", sourceLine, sourcePtr );
+ if ( c == 0 ) {
+ sourcePtr += i; // end of file
+ } else {
+ sourcePtr += i+1;
+ }
+ sourceLine++;
+ }
+}
+
+static void I(stabline)(Coordinate *cp) {
+ static char *prevfile;
+ static int prevline;
+
+ if (cp->file && (prevfile == NULL || strcmp(prevfile, cp->file) != 0)) {
+ print("file \"%s\"\n", prevfile = cp->file);
+ prevline = 0;
+ if ( sourceFile ) {
+ free( sourceFile );
+ sourceFile = NULL;
+ }
+ // load the new source file
+ LoadSourceFile( cp->file );
+ }
+ if (cp->y != prevline) {
+ print("line %d\n", prevline = cp->y);
+ PrintToSourceLine( cp->y );
+ }
+}
+
+//========================================================
+
+#define b_blockbeg blockbeg
+#define b_blockend blockend
+
+Interface bytecodeIR = {
+ 1, 1, 0, /* char */
+ 2, 2, 0, /* short */
+ 4, 4, 0, /* int */
+ 4, 4, 0, /* long */
+ 4, 4, 0, /* long long */
+ 4, 4, 0, /* float */ // JDC: use inline floats
+ 4, 4, 0, /* double */ // JDC: don't ever emit 8 byte double code
+ 4, 4, 0, /* long double */ // JDC: don't ever emit 8 byte double code
+ 4, 4, 0, /* T* */
+ 0, 4, 0, /* struct */
+ 0, /* little_endian */
+ 0, /* mulops_calls */
+ 0, /* wants_callb */
+ 0, /* wants_argb */
+ 1, /* left_to_right */
+ 0, /* wants_dag */
+ 0, /* unsigned_char */
+ I(address),
+ I(blockbeg),
+ I(blockend),
+ I(defaddress),
+ I(defconst),
+ I(defstring),
+ I(defsymbol),
+ I(emit),
+ I(export),
+ I(function),
+ I(gen),
+ I(global),
+ I(import),
+ I(local),
+ I(progbeg),
+ I(progend),
+ I(segment),
+ I(space),
+ 0, /* I(stabblock) */
+ 0, /* I(stabend) */
+ 0, /* I(stabfend) */
+ 0, /* I(stabinit) */
+ I(stabline),
+ 0, /* I(stabsym) */
+ 0, /* I(stabtype) */
+};
diff --git a/lcc/src/c.h b/lcc/src/c.h
new file mode 100755
index 0000000..e21419d
--- /dev/null
+++ b/lcc/src/c.h
@@ -0,0 +1,723 @@
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+
+#define NEW(p,a) ((p) = allocate(sizeof *(p), (a)))
+#define NEW0(p,a) memset(NEW((p),(a)), 0, sizeof *(p))
+#define isaddrop(op) (specific(op)==ADDRG+P || specific(op)==ADDRL+P \
+ || specific(op)==ADDRF+P)
+
+#define MAXLINE 512
+#define BUFSIZE 4096
+
+#define istypename(t,tsym) (kind[t] == CHAR \
+ || t == ID && tsym && tsym->sclass == TYPEDEF)
+#define sizeop(n) ((n)<<10)
+#define generic(op) ((op)&0x3F0)
+#define specific(op) ((op)&0x3FF)
+#define opindex(op) (((op)>>4)&0x3F)
+#define opkind(op) ((op)&~0x3F0)
+#define opsize(op) ((op)>>10)
+#define optype(op) ((op)&0xF)
+#ifdef __LCC__
+#ifndef __STDC__
+#define __STDC__
+#endif
+#endif
+#define NELEMS(a) ((int)(sizeof (a)/sizeof ((a)[0])))
+#undef roundup
+#define roundup(x,n) (((x)+((n)-1))&(~((n)-1)))
+#define mkop(op,ty) (specific((op) + ttob(ty)))
+
+#define extend(x,ty) ((x)&(1<<(8*(ty)->size-1)) ? (x)|((~0UL)<<(8*(ty)->size-1)) : (x)&ones(8*(ty)->size))
+#define ones(n) ((n)>=8*sizeof (unsigned long) ? ~0UL : ~((~0UL)<<(n)))
+
+#define isqual(t) ((t)->op >= CONST)
+#define unqual(t) (isqual(t) ? (t)->type : (t))
+
+#define isvolatile(t) ((t)->op == VOLATILE \
+ || (t)->op == CONST+VOLATILE)
+#define isconst(t) ((t)->op == CONST \
+ || (t)->op == CONST+VOLATILE)
+#define isarray(t) (unqual(t)->op == ARRAY)
+#define isstruct(t) (unqual(t)->op == STRUCT \
+ || unqual(t)->op == UNION)
+#define isunion(t) (unqual(t)->op == UNION)
+#define isfunc(t) (unqual(t)->op == FUNCTION)
+#define isptr(t) (unqual(t)->op == POINTER)
+#define ischar(t) ((t)->size == 1 && isint(t))
+#define isint(t) (unqual(t)->op == INT \
+ || unqual(t)->op == UNSIGNED)
+#define isfloat(t) (unqual(t)->op == FLOAT)
+#define isarith(t) (unqual(t)->op <= UNSIGNED)
+#define isunsigned(t) (unqual(t)->op == UNSIGNED)
+#define isscalar(t) (unqual(t)->op <= POINTER \
+ || unqual(t)->op == ENUM)
+#define isenum(t) (unqual(t)->op == ENUM)
+#define fieldsize(p) (p)->bitsize
+#define fieldright(p) ((p)->lsb - 1)
+#define fieldleft(p) (8*(p)->type->size - \
+ fieldsize(p) - fieldright(p))
+#define fieldmask(p) (~(~(unsigned)0<<fieldsize(p)))
+typedef struct node *Node;
+
+typedef struct list *List;
+
+typedef struct code *Code;
+
+typedef struct swtch *Swtch;
+
+typedef struct symbol *Symbol;
+
+typedef struct coord {
+ char *file;
+ unsigned x, y;
+} Coordinate;
+typedef struct table *Table;
+
+typedef union value {
+ long i;
+ unsigned long u;
+ long double d;
+ void *p;
+ void (*g)(void);
+} Value;
+typedef struct tree *Tree;
+
+typedef struct type *Type;
+
+typedef struct field *Field;
+
+typedef struct {
+ unsigned printed:1;
+ unsigned marked;
+ unsigned short typeno;
+ void *xt;
+} Xtype;
+
+#include "config.h"
+typedef struct metrics {
+ unsigned char size, align, outofline;
+} Metrics;
+typedef struct interface {
+ Metrics charmetric;
+ Metrics shortmetric;
+ Metrics intmetric;
+ Metrics longmetric;
+ Metrics longlongmetric;
+ Metrics floatmetric;
+ Metrics doublemetric;
+ Metrics longdoublemetric;
+ Metrics ptrmetric;
+ Metrics structmetric;
+ unsigned little_endian:1;
+ unsigned mulops_calls:1;
+ unsigned wants_callb:1;
+ unsigned wants_argb:1;
+ unsigned left_to_right:1;
+ unsigned wants_dag:1;
+ unsigned unsigned_char:1;
+void (*address)(Symbol p, Symbol q, long n);
+void (*blockbeg)(Env *);
+void (*blockend)(Env *);
+void (*defaddress)(Symbol);
+void (*defconst) (int suffix, int size, Value v);
+void (*defstring)(int n, char *s);
+void (*defsymbol)(Symbol);
+void (*emit) (Node);
+void (*export)(Symbol);
+void (*function)(Symbol, Symbol[], Symbol[], int);
+Node (*gen) (Node);
+void (*global)(Symbol);
+void (*import)(Symbol);
+void (*local)(Symbol);
+void (*progbeg)(int argc, char *argv[]);
+void (*progend)(void);
+void (*segment)(int);
+void (*space)(int);
+void (*stabblock)(int, int, Symbol*);
+void (*stabend) (Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *);
+void (*stabfend) (Symbol, int);
+void (*stabinit) (char *, int, char *[]);
+void (*stabline) (Coordinate *);
+void (*stabsym) (Symbol);
+void (*stabtype) (Symbol);
+ Xinterface x;
+} Interface;
+typedef struct binding {
+ char *name;
+ Interface *ir;
+} Binding;
+
+extern Binding bindings[];
+extern Interface *IR;
+typedef struct {
+ List blockentry;
+ List blockexit;
+ List entry;
+ List exit;
+ List returns;
+ List points;
+ List calls;
+ List end;
+} Events;
+
+enum {
+#define xx(a,b,c,d,e,f,g) a=b,
+#define yy(a,b,c,d,e,f,g)
+#include "token.h"
+ LAST
+};
+struct node {
+ short op;
+ short count;
+ Symbol syms[3];
+ Node kids[2];
+ Node link;
+ Xnode x;
+};
+enum {
+ F=FLOAT,
+ I=INT,
+ U=UNSIGNED,
+ P=POINTER,
+ V=VOID,
+ B=STRUCT
+};
+#define gop(name,value) name=value<<4,
+#define op(name,type,sizes)
+
+enum { gop(CNST,1)
+ op(CNST,F,fdx)
+ op(CNST,I,csilh)
+ op(CNST,P,p)
+ op(CNST,U,csilh)
+ gop(ARG,2)
+ op(ARG,B,-)
+ op(ARG,F,fdx)
+ op(ARG,I,ilh)
+ op(ARG,P,p)
+ op(ARG,U,ilh)
+ gop(ASGN,3)
+ op(ASGN,B,-)
+ op(ASGN,F,fdx)
+ op(ASGN,I,csilh)
+ op(ASGN,P,p)
+ op(ASGN,U,csilh)
+ gop(INDIR,4)
+ op(INDIR,B,-)
+ op(INDIR,F,fdx)
+ op(INDIR,I,csilh)
+ op(INDIR,P,p)
+ op(INDIR,U,csilh)
+ gop(CVF,7)
+ op(CVF,F,fdx)
+ op(CVF,I,ilh)
+ gop(CVI,8)
+ op(CVI,F,fdx)
+ op(CVI,I,csilh)
+ op(CVI,U,csilhp)
+ gop(CVP,9)
+ op(CVP,U,p)
+ gop(CVU,11)
+ op(CVU,I,csilh)
+ op(CVU,P,p)
+ op(CVU,U,csilh)
+ gop(NEG,12)
+ op(NEG,F,fdx)
+ op(NEG,I,ilh)
+ gop(CALL,13)
+ op(CALL,B,-)
+ op(CALL,F,fdx)
+ op(CALL,I,ilh)
+ op(CALL,P,p)
+ op(CALL,U,ilh)
+ op(CALL,V,-)
+ gop(RET,15)
+ op(RET,F,fdx)
+ op(RET,I,ilh)
+ op(RET,P,p)
+ op(RET,U,ilh)
+ op(RET,V,-)
+ gop(ADDRG,16)
+ op(ADDRG,P,p)
+ gop(ADDRF,17)
+ op(ADDRF,P,p)
+ gop(ADDRL,18)
+ op(ADDRL,P,p)
+ gop(ADD,19)
+ op(ADD,F,fdx)
+ op(ADD,I,ilh)
+ op(ADD,P,p)
+ op(ADD,U,ilhp)
+ gop(SUB,20)
+ op(SUB,F,fdx)
+ op(SUB,I,ilh)
+ op(SUB,P,p)
+ op(SUB,U,ilhp)
+ gop(LSH,21)
+ op(LSH,I,ilh)
+ op(LSH,U,ilh)
+ gop(MOD,22)
+ op(MOD,I,ilh)
+ op(MOD,U,ilh)
+ gop(RSH,23)
+ op(RSH,I,ilh)
+ op(RSH,U,ilh)
+ gop(BAND,24)
+ op(BAND,I,ilh)
+ op(BAND,U,ilh)
+ gop(BCOM,25)
+ op(BCOM,I,ilh)
+ op(BCOM,U,ilh)
+ gop(BOR,26)
+ op(BOR,I,ilh)
+ op(BOR,U,ilh)
+ gop(BXOR,27)
+ op(BXOR,I,ilh)
+ op(BXOR,U,ilh)
+ gop(DIV,28)
+ op(DIV,F,fdx)
+ op(DIV,I,ilh)
+ op(DIV,U,ilh)
+ gop(MUL,29)
+ op(MUL,F,fdx)
+ op(MUL,I,ilh)
+ op(MUL,U,ilh)
+ gop(EQ,30)
+ op(EQ,F,fdx)
+ op(EQ,I,ilh)
+ op(EQ,U,ilhp)
+ gop(GE,31)
+ op(GE,F,fdx)
+ op(GE,I,ilh)
+ op(GE,U,ilhp)
+ gop(GT,32)
+ op(GT,F,fdx)
+ op(GT,I,ilh)
+ op(GT,U,ilhp)
+ gop(LE,33)
+ op(LE,F,fdx)
+ op(LE,I,ilh)
+ op(LE,U,ilhp)
+ gop(LT,34)
+ op(LT,F,fdx)
+ op(LT,I,ilh)
+ op(LT,U,ilhp)
+ gop(NE,35)
+ op(NE,F,fdx)
+ op(NE,I,ilh)
+ op(NE,U,ilhp)
+ gop(JUMP,36)
+ op(JUMP,V,-)
+ gop(LABEL,37)
+ op(LABEL,V,-)
+ gop(LOAD,14)
+ op(LOAD,B,-)
+ op(LOAD,F,fdx)
+ op(LOAD,I,csilh)
+ op(LOAD,P,p)
+ op(LOAD,U,csilhp) LASTOP };
+
+#undef gop
+#undef op
+enum { CODE=1, BSS, DATA, LIT };
+enum { PERM=0, FUNC, STMT };
+struct list {
+ void *x;
+ List link;
+};
+
+struct code {
+ enum { Blockbeg, Blockend, Local, Address, Defpoint,
+ Label, Start, Gen, Jump, Switch
+ } kind;
+ Code prev, next;
+ union {
+ struct {
+ int level;
+ Symbol *locals;
+ Table identifiers, types;
+ Env x;
+ } block;
+ Code begin;
+ Symbol var;
+
+ struct {
+ Symbol sym;
+ Symbol base;
+ long offset;
+ } addr;
+ struct {
+ Coordinate src;
+ int point;
+ } point;
+ Node forest;
+ struct {
+ Symbol sym;
+ Symbol table;
+ Symbol deflab;
+ int size;
+ long *values;
+ Symbol *labels;
+ } swtch;
+
+ } u;
+};
+struct swtch {
+ Symbol sym;
+ int lab;
+ Symbol deflab;
+ int ncases;
+ int size;
+ long *values;
+ Symbol *labels;
+};
+struct symbol {
+ char *name;
+ int scope;
+ Coordinate src;
+ Symbol up;
+ List uses;
+ int sclass;
+ unsigned structarg:1;
+
+ unsigned addressed:1;
+ unsigned computed:1;
+ unsigned temporary:1;
+ unsigned generated:1;
+ unsigned defined:1;
+ Type type;
+ float ref;
+ union {
+ struct {
+ int label;
+ Symbol equatedto;
+ } l;
+ struct {
+ unsigned cfields:1;
+ unsigned vfields:1;
+ Table ftab; /* omit */
+ Field flist;
+ } s;
+ int value;
+ Symbol *idlist;
+ struct {
+ Value min, max;
+ } limits;
+ struct {
+ Value v;
+ Symbol loc;
+ } c;
+ struct {
+ Coordinate pt;
+ int label;
+ int ncalls;
+ Symbol *callee;
+ } f;
+ int seg;
+ Symbol alias;
+ struct {
+ Node cse;
+ int replace;
+ Symbol next;
+ } t;
+ } u;
+ Xsymbol x;
+};
+enum { CONSTANTS=1, LABELS, GLOBAL, PARAM, LOCAL };
+struct tree {
+ int op;
+ Type type;
+ Tree kids[2];
+ Node node;
+ union {
+ Value v;
+ Symbol sym;
+
+ Field field;
+ } u;
+};
+enum {
+ AND=38<<4,
+ NOT=39<<4,
+ OR=40<<4,
+ COND=41<<4,
+ RIGHT=42<<4,
+ FIELD=43<<4
+};
+struct type {
+ int op;
+ Type type;
+ int align;
+ int size;
+ union {
+ Symbol sym;
+ struct {
+ unsigned oldstyle:1;
+ Type *proto;
+ } f;
+ } u;
+ Xtype x;
+};
+struct field {
+ char *name;
+ Type type;
+ int offset;
+ short bitsize;
+ short lsb;
+ Field link;
+};
+extern int assignargs;
+extern int prunetemps;
+extern int nodecount;
+extern Symbol cfunc;
+extern Symbol retv;
+extern Tree (*optree[])(int, Tree, Tree);
+
+extern char kind[];
+extern int errcnt;
+extern int errlimit;
+extern int wflag;
+extern Events events;
+extern float refinc;
+
+extern unsigned char *cp;
+extern unsigned char *limit;
+extern char *firstfile;
+extern char *file;
+extern char *line;
+extern int lineno;
+extern int t;
+extern char *token;
+extern Symbol tsym;
+extern Coordinate src;
+extern int Aflag;
+extern int Pflag;
+extern Symbol YYnull;
+extern Symbol YYcheck;
+extern int glevel;
+extern int xref;
+
+extern int ncalled;
+extern int npoints;
+
+extern int needconst;
+extern int explicitCast;
+extern struct code codehead;
+extern Code codelist;
+extern Table stmtlabs;
+extern float density;
+extern Table constants;
+extern Table externals;
+extern Table globals;
+extern Table identifiers;
+extern Table labels;
+extern Table types;
+extern int level;
+
+extern List loci, symbols;
+
+extern List symbols;
+
+extern int where;
+extern Type chartype;
+extern Type doubletype;
+extern Type floattype;
+extern Type inttype;
+extern Type longdouble;
+extern Type longtype;
+extern Type longlong;
+extern Type shorttype;
+extern Type signedchar;
+extern Type unsignedchar;
+extern Type unsignedlonglong;
+extern Type unsignedlong;
+extern Type unsignedshort;
+extern Type unsignedtype;
+extern Type charptype;
+extern Type funcptype;
+extern Type voidptype;
+extern Type voidtype;
+extern Type unsignedptr;
+extern Type signedptr;
+extern Type widechar;
+extern void *allocate(unsigned long n, unsigned a);
+extern void deallocate(unsigned a);
+extern void *newarray(unsigned long m, unsigned long n, unsigned a);
+extern void walk(Tree e, int tlab, int flab);
+extern Node listnodes(Tree e, int tlab, int flab);
+extern Node newnode(int op, Node left, Node right, Symbol p);
+extern Tree cvtconst(Tree);
+extern void printdag(Node, int);
+extern void compound(int, Swtch, int);
+extern void defglobal(Symbol, int);
+extern void finalize(void);
+extern void program(void);
+
+extern Tree vcall(Symbol func, Type ty, ...);
+extern Tree addrof(Tree);
+extern Tree asgn(Symbol, Tree);
+extern Tree asgntree(int, Tree, Tree);
+extern Type assign(Type, Tree);
+extern Tree bittree(int, Tree, Tree);
+extern Tree call(Tree, Type, Coordinate);
+extern Tree calltree(Tree, Type, Tree, Symbol);
+extern Tree condtree(Tree, Tree, Tree);
+extern Tree cnsttree(Type, ...);
+extern Tree consttree(unsigned int, Type);
+extern Tree eqtree(int, Tree, Tree);
+extern int iscallb(Tree);
+extern Tree shtree(int, Tree, Tree);
+extern void typeerror(int, Tree, Tree);
+
+extern void test(int tok, char set[]);
+extern void expect(int tok);
+extern void skipto(int tok, char set[]);
+extern void error(const char *, ...);
+extern int fatal(const char *, const char *, int);
+extern void warning(const char *, ...);
+
+typedef void (*Apply)(void *, void *, void *);
+extern void attach(Apply, void *, List *);
+extern void apply(List event, void *arg1, void *arg2);
+extern Tree retype(Tree p, Type ty);
+extern Tree rightkid(Tree p);
+extern int hascall(Tree p);
+extern Type binary(Type, Type);
+extern Tree cast(Tree, Type);
+extern Tree cond(Tree);
+extern Tree expr0(int);
+extern Tree expr(int);
+extern Tree expr1(int);
+extern Tree field(Tree, const char *);
+extern char *funcname(Tree);
+extern Tree idtree(Symbol);
+extern Tree incr(int, Tree, Tree);
+extern Tree lvalue(Tree);
+extern Tree nullcall(Type, Symbol, Tree, Tree);
+extern Tree pointer(Tree);
+extern Tree rvalue(Tree);
+extern Tree value(Tree);
+
+extern void defpointer(Symbol);
+extern Type initializer(Type, int);
+extern void swtoseg(int);
+
+extern void input_init(int, char *[]);
+extern void fillbuf(void);
+extern void nextline(void);
+
+extern int getchr(void);
+extern int gettok(void);
+
+extern void emitcode(void);
+extern void gencode (Symbol[], Symbol[]);
+extern void fprint(FILE *f, const char *fmt, ...);
+extern char *stringf(const char *, ...);
+extern void check(Node);
+extern void print(const char *, ...);
+
+extern List append(void *x, List list);
+extern int length(List list);
+extern void *ltov (List *list, unsigned a);
+extern void init(int, char *[]);
+
+extern Type typename(void);
+extern void checklab(Symbol p, void *cl);
+extern Type enumdcl(void);
+extern void main_init(int, char *[]);
+extern int main(int, char *[]);
+
+extern void vfprint(FILE *, char *, const char *, va_list);
+
+extern int process(char *);
+extern int findfunc(char *, char *);
+extern int findcount(char *, int, int);
+
+extern Tree constexpr(int);
+extern int intexpr(int, int);
+extern Tree simplify(int, Type, Tree, Tree);
+extern int ispow2(unsigned long u);
+
+extern int reachable(int);
+
+extern void addlocal(Symbol);
+extern void branch(int);
+extern Code code(int);
+extern void definelab(int);
+extern void definept(Coordinate *);
+extern void equatelab(Symbol, Symbol);
+extern Node jump(int);
+extern void retcode(Tree);
+extern void statement(int, Swtch, int);
+extern void swcode(Swtch, int *, int, int);
+extern void swgen(Swtch);
+
+extern char * string(const char *str);
+extern char *stringn(const char *str, int len);
+extern char *stringd(long n);
+extern Symbol relocate(const char *name, Table src, Table dst);
+extern void use(Symbol p, Coordinate src);
+extern void locus(Table tp, Coordinate *cp);
+extern Symbol allsymbols(Table);
+
+extern Symbol constant(Type, Value);
+extern void enterscope(void);
+extern void exitscope(void);
+extern Symbol findlabel(int);
+extern Symbol findtype(Type);
+extern void foreach(Table, int, void (*)(Symbol, void *), void *);
+extern Symbol genident(int, Type, int);
+extern int genlabel(int);
+extern Symbol install(const char *, Table *, int, int);
+extern Symbol intconst(int);
+extern Symbol lookup(const char *, Table);
+extern Symbol mkstr(char *);
+extern Symbol mksymbol(int, const char *, Type);
+extern Symbol newtemp(int, int, int);
+extern Table table(Table, int);
+extern Symbol temporary(int, Type);
+extern char *vtoa(Type, Value);
+
+extern int nodeid(Tree);
+extern char *opname(int);
+extern int *printed(int);
+extern void printtree(Tree, int);
+extern Tree root(Tree);
+extern Tree texpr(Tree (*)(int), int, int);
+extern Tree tree(int, Type, Tree, Tree);
+
+extern void type_init(int, char *[]);
+
+extern Type signedint(Type);
+
+extern int hasproto(Type);
+extern void outtype(Type, FILE *);
+extern void printdecl (Symbol p, Type ty);
+extern void printproto(Symbol p, Symbol args[]);
+extern char *typestring(Type ty, char *id);
+extern Field fieldref(const char *name, Type ty);
+extern Type array(Type, int, int);
+extern Type atop(Type);
+extern Type btot(int, int);
+extern Type compose(Type, Type);
+extern Type deref(Type);
+extern int eqtype(Type, Type, int);
+extern Field fieldlist(Type);
+extern Type freturn(Type);
+extern Type ftype(Type, Type);
+extern Type func(Type, Type *, int);
+extern Field newfield(char *, Type, Type);
+extern Type newstruct(int, char *);
+extern void printtype(Type, int);
+extern Type promote(Type);
+extern Type ptr(Type);
+extern Type qual(int, Type);
+extern void rmtypes(int);
+extern int ttob(Type);
+extern int variadic(Type);
+
diff --git a/lcc/src/config.h b/lcc/src/config.h
new file mode 100755
index 0000000..20d115c
--- /dev/null
+++ b/lcc/src/config.h
@@ -0,0 +1,102 @@
+typedef struct {
+ unsigned char max_unaligned_load;
+ Symbol (*rmap)(int);
+
+ void (*blkfetch)(int size, int off, int reg, int tmp);
+ void (*blkstore)(int size, int off, int reg, int tmp);
+ void (*blkloop)(int dreg, int doff,
+ int sreg, int soff,
+ int size, int tmps[]);
+ void (*_label)(Node);
+ int (*_rule)(void*, int);
+ short **_nts;
+ void (*_kids)(Node, int, Node*);
+ char **_string;
+ char **_templates;
+ char *_isinstruction;
+ char **_ntname;
+ void (*emit2)(Node);
+ void (*doarg)(Node);
+ void (*target)(Node);
+ void (*clobber)(Node);
+} Xinterface;
+extern int askregvar(Symbol, Symbol);
+extern void blkcopy(int, int, int, int, int, int[]);
+extern int getregnum(Node);
+extern int mayrecalc(Node);
+extern int mkactual(int, int);
+extern void mkauto(Symbol);
+extern Symbol mkreg(char *, int, int, int);
+extern Symbol mkwildcard(Symbol *);
+extern int move(Node);
+extern int notarget(Node);
+extern void parseflags(int, char **);
+extern int range(Node, int, int);
+extern unsigned regloc(Symbol); /* omit */
+extern void rtarget(Node, int, Symbol);
+extern void setreg(Node, Symbol);
+extern void spill(unsigned, int, Node);
+extern int widens(Node);
+
+extern int argoffset, maxargoffset;
+extern int bflag, dflag;
+extern int dalign, salign;
+extern int framesize;
+extern unsigned freemask[], usedmask[];
+extern int offset, maxoffset;
+extern int swap;
+extern unsigned tmask[], vmask[];
+typedef struct {
+ unsigned listed:1;
+ unsigned registered:1;
+ unsigned emitted:1;
+ unsigned copy:1;
+ unsigned equatable:1;
+ unsigned spills:1;
+ unsigned mayrecalc:1;
+ void *state;
+ short inst;
+ Node kids[3];
+ Node prev, next;
+ Node prevuse;
+ short argno;
+} Xnode;
+typedef struct {
+ Symbol vbl;
+ short set;
+ short number;
+ unsigned mask;
+} *Regnode;
+enum { IREG=0, FREG=1 };
+typedef struct {
+ char *name;
+ unsigned int eaddr; /* omit */
+ int offset;
+ Node lastuse;
+ int usecount;
+ Regnode regnode;
+ Symbol *wildcard;
+} Xsymbol;
+enum { RX=2 };
+typedef struct {
+ int offset;
+ unsigned freemask[2];
+} Env;
+
+#define LBURG_MAX SHRT_MAX
+
+enum { VREG=(44<<4) };
+
+/* Exported for the front end */
+extern void blockbeg(Env *);
+extern void blockend(Env *);
+extern void emit(Node);
+extern Node gen(Node);
+
+extern unsigned emitbin(Node, int);
+
+#ifdef NDEBUG
+#define debug(x) (void)0
+#else
+#define debug(x) (void)(dflag&&((x),0))
+#endif
diff --git a/lcc/src/dag.c b/lcc/src/dag.c
new file mode 100755
index 0000000..6e931ae
--- /dev/null
+++ b/lcc/src/dag.c
@@ -0,0 +1,735 @@
+#include "c.h"
+
+
+#define iscall(op) (generic(op) == CALL \
+ || IR->mulops_calls \
+ && (generic(op)==DIV||generic(op)==MOD||generic(op)==MUL) \
+ && ( optype(op)==U || optype(op)==I))
+static Node forest;
+static struct dag {
+ struct node node;
+ struct dag *hlink;
+} *buckets[16];
+int nodecount;
+static Tree firstarg;
+int assignargs = 1;
+int prunetemps = -1;
+static Node *tail;
+
+static int depth = 0;
+static Node replace(Node);
+static Node prune(Node);
+static Node asgnnode(Symbol, Node);
+static struct dag *dagnode(int, Node, Node, Symbol);
+static Symbol equated(Symbol);
+static void fixup(Node);
+static void labelnode(int);
+static void list(Node);
+static void kill(Symbol);
+static Node node(int, Node, Node, Symbol);
+static void printdag1(Node, int, int);
+static void printnode(Node, int, int);
+static void reset(void);
+static Node tmpnode(Node);
+static void typestab(Symbol, void *);
+static Node undag(Node);
+static Node visit(Node, int);
+static void unlist(void);
+void walk(Tree tp, int tlab, int flab) {
+ listnodes(tp, tlab, flab);
+ if (forest) {
+ Node list = forest->link;
+ forest->link = NULL;
+ if (!IR->wants_dag)
+ list = undag(list);
+ code(Gen)->u.forest = list;
+ forest = NULL;
+ }
+ reset();
+ deallocate(STMT);
+}
+
+static Node node(int op, Node l, Node r, Symbol sym) {
+ int i;
+ struct dag *p;
+
+ i = (opindex(op)^((unsigned long)sym>>2))&(NELEMS(buckets)-1);
+ for (p = buckets[i]; p; p = p->hlink)
+ if (p->node.op == op && p->node.syms[0] == sym
+ && p->node.kids[0] == l && p->node.kids[1] == r)
+ return &p->node;
+ p = dagnode(op, l, r, sym);
+ p->hlink = buckets[i];
+ buckets[i] = p;
+ ++nodecount;
+ return &p->node;
+}
+static struct dag *dagnode(int op, Node l, Node r, Symbol sym) {
+ struct dag *p;
+
+ NEW0(p, FUNC);
+ p->node.op = op;
+ if ((p->node.kids[0] = l) != NULL)
+ ++l->count;
+ if ((p->node.kids[1] = r) != NULL)
+ ++r->count;
+ p->node.syms[0] = sym;
+ return p;
+}
+Node newnode(int op, Node l, Node r, Symbol sym) {
+ return &dagnode(op, l, r, sym)->node;
+}
+static void kill(Symbol p) {
+ int i;
+ struct dag **q;
+
+ for (i = 0; i < NELEMS(buckets); i++)
+ for (q = &buckets[i]; *q; )
+ if (generic((*q)->node.op) == INDIR &&
+ (!isaddrop((*q)->node.kids[0]->op)
+ || (*q)->node.kids[0]->syms[0] == p)) {
+ *q = (*q)->hlink;
+ --nodecount;
+ } else
+ q = &(*q)->hlink;
+}
+static void reset(void) {
+ if (nodecount > 0)
+ memset(buckets, 0, sizeof buckets);
+ nodecount = 0;
+}
+Node listnodes(Tree tp, int tlab, int flab) {
+ Node p = NULL, l, r;
+ int op;
+
+ assert(tlab || flab || tlab == 0 && flab == 0);
+ if (tp == NULL)
+ return NULL;
+ if (tp->node)
+ return tp->node;
+ op = tp->op + sizeop(tp->type->size);
+ switch (generic(tp->op)) {
+ case AND: { if (depth++ == 0) reset();
+ if (flab) {
+ listnodes(tp->kids[0], 0, flab);
+ listnodes(tp->kids[1], 0, flab);
+ } else {
+ listnodes(tp->kids[0], 0, flab = genlabel(1));
+ listnodes(tp->kids[1], tlab, 0);
+ labelnode(flab);
+ }
+ depth--; } break;
+ case OR: { if (depth++ == 0)
+ reset();
+ if (tlab) {
+ listnodes(tp->kids[0], tlab, 0);
+ listnodes(tp->kids[1], tlab, 0);
+ } else {
+ tlab = genlabel(1);
+ listnodes(tp->kids[0], tlab, 0);
+ listnodes(tp->kids[1], 0, flab);
+ labelnode(tlab);
+ }
+ depth--;
+ } break;
+ case NOT: { return listnodes(tp->kids[0], flab, tlab); }
+ case COND: { Tree q = tp->kids[1];
+ assert(tlab == 0 && flab == 0);
+ if (tp->u.sym)
+ addlocal(tp->u.sym);
+ flab = genlabel(2);
+ listnodes(tp->kids[0], 0, flab);
+ assert(q && q->op == RIGHT);
+ reset();
+ listnodes(q->kids[0], 0, 0);
+ if (forest->op == LABEL+V) {
+ equatelab(forest->syms[0], findlabel(flab + 1));
+ unlist();
+ }
+ list(jump(flab + 1));
+ labelnode(flab);
+ listnodes(q->kids[1], 0, 0);
+ if (forest->op == LABEL+V) {
+ equatelab(forest->syms[0], findlabel(flab + 1));
+ unlist();
+ }
+ labelnode(flab + 1);
+
+ if (tp->u.sym)
+ p = listnodes(idtree(tp->u.sym), 0, 0); } break;
+ case CNST: { Type ty = unqual(tp->type);
+ assert(ty->u.sym);
+ if (tlab || flab) {
+ assert(ty == inttype);
+ if (tlab && tp->u.v.i != 0)
+ list(jump(tlab));
+ else if (flab && tp->u.v.i == 0)
+ list(jump(flab));
+ }
+ else if (ty->u.sym->addressed)
+ p = listnodes(cvtconst(tp), 0, 0);
+ else
+ p = node(op, NULL, NULL, constant(ty, tp->u.v)); } break;
+ case RIGHT: { if ( tp->kids[0] && tp->kids[1]
+ && generic(tp->kids[1]->op) == ASGN
+ && (generic(tp->kids[0]->op) == INDIR
+ && tp->kids[0]->kids[0] == tp->kids[1]->kids[0]
+ || (tp->kids[0]->op == FIELD
+ && tp->kids[0] == tp->kids[1]->kids[0]))) {
+ assert(tlab == 0 && flab == 0);
+ if (generic(tp->kids[0]->op) == INDIR) {
+ p = listnodes(tp->kids[0], 0, 0);
+ list(p);
+ listnodes(tp->kids[1], 0, 0);
+ }
+ else {
+ assert(generic(tp->kids[0]->kids[0]->op) == INDIR);
+ list(listnodes(tp->kids[0]->kids[0], 0, 0));
+ p = listnodes(tp->kids[0], 0, 0);
+ listnodes(tp->kids[1], 0, 0);
+ }
+ } else if (tp->kids[1]) {
+ listnodes(tp->kids[0], 0, 0);
+ p = listnodes(tp->kids[1], tlab, flab);
+ } else
+ p = listnodes(tp->kids[0], tlab, flab); } break;
+ case JUMP: { assert(tlab == 0 && flab == 0);
+ assert(tp->u.sym == 0);
+ assert(tp->kids[0]);
+ l = listnodes(tp->kids[0], 0, 0);
+ list(newnode(JUMP+V, l, NULL, NULL));
+ reset(); } break;
+ case CALL: { Tree save = firstarg;
+ firstarg = NULL;
+ assert(tlab == 0 && flab == 0);
+ if (tp->op == CALL+B && !IR->wants_callb) {
+ Tree arg0 = tree(ARG+P, tp->kids[1]->type,
+ tp->kids[1], NULL);
+ if (IR->left_to_right)
+ firstarg = arg0;
+ l = listnodes(tp->kids[0], 0, 0);
+ if (!IR->left_to_right || firstarg) {
+ firstarg = NULL;
+ listnodes(arg0, 0, 0);
+ }
+ p = newnode(CALL+V, l, NULL, NULL);
+ } else {
+ l = listnodes(tp->kids[0], 0, 0);
+ r = listnodes(tp->kids[1], 0, 0);
+ p = newnode(tp->op == CALL+B ? tp->op : op, l, r, NULL);
+ }
+ NEW0(p->syms[0], FUNC);
+ assert(isptr(tp->kids[0]->type));
+ assert(isfunc(tp->kids[0]->type->type));
+ p->syms[0]->type = tp->kids[0]->type->type;
+ list(p);
+ reset();
+ cfunc->u.f.ncalls++;
+ firstarg = save;
+ } break;
+ case ARG: { assert(tlab == 0 && flab == 0);
+ if (IR->left_to_right)
+ listnodes(tp->kids[1], 0, 0);
+ if (firstarg) {
+ Tree arg = firstarg;
+ firstarg = NULL;
+ listnodes(arg, 0, 0);
+ }
+ l = listnodes(tp->kids[0], 0, 0);
+ list(newnode(tp->op == ARG+B ? tp->op : op, l, NULL, NULL));
+ forest->syms[0] = intconst(tp->type->size);
+ forest->syms[1] = intconst(tp->type->align);
+ if (!IR->left_to_right)
+ listnodes(tp->kids[1], 0, 0); } break;
+ case EQ: case NE: case GT: case GE: case LE:
+ case LT: { assert(tp->u.sym == 0);
+ assert(errcnt || tlab || flab);
+ l = listnodes(tp->kids[0], 0, 0);
+ r = listnodes(tp->kids[1], 0, 0);
+ assert(errcnt || opkind(l->op) == opkind(r->op));
+ assert(errcnt || optype(op) == optype(l->op));
+ if (tlab)
+ assert(flab == 0),
+ list(newnode(generic(tp->op) + opkind(l->op), l, r, findlabel(tlab)));
+ else if (flab) {
+ switch (generic(tp->op)) {
+ case EQ: op = NE; break;
+ case NE: op = EQ; break;
+ case GT: op = LE; break;
+ case LT: op = GE; break;
+ case GE: op = LT; break;
+ case LE: op = GT; break;
+ default: assert(0);
+ }
+ list(newnode(op + opkind(l->op), l, r, findlabel(flab)));
+ }
+ if (forest && forest->syms[0])
+ forest->syms[0]->ref++; } break;
+ case ASGN: { assert(tlab == 0 && flab == 0);
+ if (tp->kids[0]->op == FIELD) {
+ Tree x = tp->kids[0]->kids[0];
+ Field f = tp->kids[0]->u.field;
+ assert(generic(x->op) == INDIR);
+ reset();
+ l = listnodes(lvalue(x), 0, 0);
+ if (fieldsize(f) < 8*f->type->size) {
+ unsigned int fmask = fieldmask(f);
+ unsigned int mask = fmask<<fieldright(f);
+ Tree q = tp->kids[1];
+ if (q->op == CNST+I && q->u.v.i == 0
+ || q->op == CNST+U && q->u.v.u == 0)
+ q = bittree(BAND, x, cnsttree(unsignedtype, (unsigned long)~mask));
+ else if (q->op == CNST+I && (q->u.v.i&fmask) == fmask
+ || q->op == CNST+U && (q->u.v.u&fmask) == fmask)
+ q = bittree(BOR, x, cnsttree(unsignedtype, (unsigned long)mask));
+ else {
+ listnodes(q, 0, 0);
+ q = bittree(BOR,
+ bittree(BAND, rvalue(lvalue(x)),
+ cnsttree(unsignedtype, (unsigned long)~mask)),
+ bittree(BAND, shtree(LSH, cast(q, unsignedtype),
+ cnsttree(unsignedtype, (unsigned long)fieldright(f))),
+ cnsttree(unsignedtype, (unsigned long)mask)));
+ }
+ r = listnodes(q, 0, 0);
+ op = ASGN + ttob(q->type);
+ } else {
+ r = listnodes(tp->kids[1], 0, 0);
+ op = ASGN + ttob(tp->kids[1]->type);
+ }
+ } else {
+ l = listnodes(tp->kids[0], 0, 0);
+ r = listnodes(tp->kids[1], 0, 0);
+ }
+ list(newnode(tp->op == ASGN+B ? tp->op : op, l, r, NULL));
+ forest->syms[0] = intconst(tp->kids[1]->type->size);
+ forest->syms[1] = intconst(tp->kids[1]->type->align);
+ if (isaddrop(tp->kids[0]->op)
+ && !tp->kids[0]->u.sym->computed)
+ kill(tp->kids[0]->u.sym);
+ else
+ reset();
+ p = listnodes(tp->kids[1], 0, 0); } break;
+ case BOR: case BAND: case BXOR:
+ case ADD: case SUB: case RSH:
+ case LSH: { assert(tlab == 0 && flab == 0);
+ l = listnodes(tp->kids[0], 0, 0);
+ r = listnodes(tp->kids[1], 0, 0);
+ p = node(op, l, r, NULL); } break;
+ case DIV: case MUL:
+ case MOD: { assert(tlab == 0 && flab == 0);
+ l = listnodes(tp->kids[0], 0, 0);
+ r = listnodes(tp->kids[1], 0, 0);
+ p = node(op, l, r, NULL);
+ if (IR->mulops_calls && isint(tp->type)) {
+ list(p);
+ cfunc->u.f.ncalls++;
+ } } break;
+ case RET: { assert(tlab == 0 && flab == 0);
+ l = listnodes(tp->kids[0], 0, 0);
+ list(newnode(op, l, NULL, NULL)); } break;
+ case CVF: case CVI: case CVP:
+ case CVU: { assert(tlab == 0 && flab == 0);
+ assert(optype(tp->kids[0]->op) != optype(tp->op) || tp->kids[0]->type->size != tp->type->size);
+ l = listnodes(tp->kids[0], 0, 0);
+ p = node(op, l, NULL, intconst(tp->kids[0]->type->size));
+ } break;
+ case BCOM:
+ case NEG: { assert(tlab == 0 && flab == 0);
+ l = listnodes(tp->kids[0], 0, 0);
+ p = node(op, l, NULL, NULL); } break;
+ case INDIR: { Type ty = tp->kids[0]->type;
+ assert(tlab == 0 && flab == 0);
+ l = listnodes(tp->kids[0], 0, 0);
+ if (isptr(ty))
+ ty = unqual(ty)->type;
+ if (isvolatile(ty)
+ || (isstruct(ty) && unqual(ty)->u.sym->u.s.vfields))
+ p = newnode(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL);
+ else
+ p = node(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL); } break;
+ case FIELD: { Tree q = tp->kids[0];
+ if (tp->type == inttype) {
+ long n = fieldleft(tp->u.field);
+ q = shtree(RSH,
+ shtree(LSH, q, cnsttree(inttype, n)),
+ cnsttree(inttype, n + fieldright(tp->u.field)));
+ } else if (fieldsize(tp->u.field) < 8*tp->u.field->type->size)
+ q = bittree(BAND,
+ shtree(RSH, q, cnsttree(inttype, (long)fieldright(tp->u.field))),
+ cnsttree(unsignedtype, (unsigned long)fieldmask(tp->u.field)));
+ assert(tlab == 0 && flab == 0);
+ p = listnodes(q, 0, 0); } break;
+ case ADDRG:
+ case ADDRF: { assert(tlab == 0 && flab == 0);
+ p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym);
+ } break;
+ case ADDRL: { assert(tlab == 0 && flab == 0);
+ if (tp->u.sym->temporary)
+ addlocal(tp->u.sym);
+ p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym); } break;
+ default:assert(0);
+ }
+ tp->node = p;
+ return p;
+}
+static void list(Node p) {
+ if (p && p->link == NULL) {
+ if (forest) {
+ p->link = forest->link;
+ forest->link = p;
+ } else
+ p->link = p;
+ forest = p;
+ }
+}
+static void labelnode(int lab) {
+ assert(lab);
+ if (forest && forest->op == LABEL+V)
+ equatelab(findlabel(lab), forest->syms[0]);
+ else
+ list(newnode(LABEL+V, NULL, NULL, findlabel(lab)));
+ reset();
+}
+static void unlist(void) {
+ Node p;
+
+ assert(forest);
+ assert(forest != forest->link);
+ p = forest->link;
+ while (p->link != forest)
+ p = p->link;
+ p->link = forest->link;
+ forest = p;
+}
+Tree cvtconst(Tree p) {
+ Symbol q = constant(p->type, p->u.v);
+ Tree e;
+
+ if (q->u.c.loc == NULL)
+ q->u.c.loc = genident(STATIC, p->type, GLOBAL);
+ if (isarray(p->type)) {
+ e = simplify(ADDRG, atop(p->type), NULL, NULL);
+ e->u.sym = q->u.c.loc;
+ } else
+ e = idtree(q->u.c.loc);
+ return e;
+}
+void gencode(Symbol caller[], Symbol callee[]) {
+ Code cp;
+ Coordinate save;
+
+ if (prunetemps == -1)
+ prunetemps = !IR->wants_dag;
+ save = src;
+ if (assignargs) {
+ int i;
+ Symbol p, q;
+ cp = codehead.next->next;
+ codelist = codehead.next;
+ for (i = 0; (p = callee[i]) != NULL
+ && (q = caller[i]) != NULL; i++)
+ if (p->sclass != q->sclass || p->type != q->type)
+ walk(asgn(p, idtree(q)), 0, 0);
+ codelist->next = cp;
+ cp->prev = codelist;
+ }
+ if (glevel && IR->stabsym) {
+ int i;
+ Symbol p, q;
+ for (i = 0; (p = callee[i]) != NULL
+ && (q = caller[i]) != NULL; i++) {
+ (*IR->stabsym)(p);
+ if (p->sclass != q->sclass || p->type != q->type)
+ (*IR->stabsym)(q);
+ }
+ swtoseg(CODE);
+ }
+ cp = codehead.next;
+ for ( ; errcnt <= 0 && cp; cp = cp->next)
+ switch (cp->kind) {
+ case Address: (*IR->address)(cp->u.addr.sym, cp->u.addr.base,
+ cp->u.addr.offset); break;
+ case Blockbeg: {
+ Symbol *p = cp->u.block.locals;
+ (*IR->blockbeg)(&cp->u.block.x);
+ for ( ; *p; p++)
+ if ((*p)->ref != 0.0)
+ (*IR->local)(*p);
+ else if (glevel) (*IR->local)(*p);
+ }
+ break;
+ case Blockend: (*IR->blockend)(&cp->u.begin->u.block.x); break;
+ case Defpoint: src = cp->u.point.src; break;
+ case Gen: case Jump:
+ case Label: if (prunetemps)
+ cp->u.forest = prune(cp->u.forest);
+ fixup(cp->u.forest);
+ cp->u.forest = (*IR->gen)(cp->u.forest); break;
+ case Local: (*IR->local)(cp->u.var); break;
+ case Switch: break;
+ default: assert(0);
+ }
+ src = save;
+}
+static void fixup(Node p) {
+ for ( ; p; p = p->link)
+ switch (generic(p->op)) {
+ case JUMP:
+ if (specific(p->kids[0]->op) == ADDRG+P)
+ p->kids[0]->syms[0] =
+ equated(p->kids[0]->syms[0]);
+ break;
+ case LABEL: assert(p->syms[0] == equated(p->syms[0])); break;
+ case EQ: case GE: case GT: case LE: case LT: case NE:
+ assert(p->syms[0]);
+ p->syms[0] = equated(p->syms[0]);
+ }
+}
+static Symbol equated(Symbol p) {
+ { Symbol q; for (q = p->u.l.equatedto; q; q = q->u.l.equatedto) assert(p != q); }
+ while (p->u.l.equatedto)
+ p = p->u.l.equatedto;
+ return p;
+}
+void emitcode(void) {
+ Code cp;
+ Coordinate save;
+
+ save = src;
+ cp = codehead.next;
+ for ( ; errcnt <= 0 && cp; cp = cp->next)
+ switch (cp->kind) {
+ case Address: break;
+ case Blockbeg: if (glevel && IR->stabblock) {
+ (*IR->stabblock)('{', cp->u.block.level - LOCAL, cp->u.block.locals);
+ swtoseg(CODE);
+ }
+ break;
+ case Blockend: if (glevel && IR->stabblock) {
+ Code bp = cp->u.begin;
+ foreach(bp->u.block.identifiers, bp->u.block.level, typestab, NULL);
+ foreach(bp->u.block.types, bp->u.block.level, typestab, NULL);
+ (*IR->stabblock)('}', bp->u.block.level - LOCAL, bp->u.block.locals);
+ swtoseg(CODE);
+ }
+ break;
+ case Defpoint: src = cp->u.point.src;
+ if (glevel > 0 && IR->stabline) {
+ (*IR->stabline)(&cp->u.point.src); swtoseg(CODE); } break;
+ case Gen: case Jump:
+ case Label: if (cp->u.forest)
+ (*IR->emit)(cp->u.forest); break;
+ case Local: if (glevel && IR->stabsym) {
+ (*IR->stabsym)(cp->u.var);
+ swtoseg(CODE);
+ } break;
+ case Switch: { int i;
+ defglobal(cp->u.swtch.table, LIT);
+ (*IR->defaddress)(equated(cp->u.swtch.labels[0]));
+ for (i = 1; i < cp->u.swtch.size; i++) {
+ long k = cp->u.swtch.values[i-1];
+ while (++k < cp->u.swtch.values[i])
+ assert(k < LONG_MAX),
+ (*IR->defaddress)(equated(cp->u.swtch.deflab));
+ (*IR->defaddress)(equated(cp->u.swtch.labels[i]));
+ }
+ swtoseg(CODE);
+ } break;
+ default: assert(0);
+ }
+ src = save;
+}
+
+static Node undag(Node forest) {
+ Node p;
+
+ tail = &forest;
+ for (p = forest; p; p = p->link)
+ if (generic(p->op) == INDIR) {
+ assert(p->count >= 1);
+ visit(p, 1);
+ if (p->syms[2]) {
+ assert(p->syms[2]->u.t.cse);
+ p->syms[2]->u.t.cse = NULL;
+ addlocal(p->syms[2]);
+ }
+ } else if (iscall(p->op) && p->count >= 1)
+ visit(p, 1);
+ else {
+ assert(p->count == 0),
+ visit(p, 1);
+ *tail = p;
+ tail = &p->link;
+ }
+ *tail = NULL;
+ return forest;
+}
+static Node replace(Node p) {
+ if (p && ( generic(p->op) == INDIR
+ && generic(p->kids[0]->op) == ADDRL
+ && p->kids[0]->syms[0]->temporary
+ && p->kids[0]->syms[0]->u.t.replace)) {
+ p = p->kids[0]->syms[0]->u.t.cse;
+ if (generic(p->op) == INDIR && isaddrop(p->kids[0]->op))
+ p = newnode(p->op, newnode(p->kids[0]->op, NULL, NULL,
+ p->kids[0]->syms[0]), NULL, NULL);
+ else if (generic(p->op) == ADDRG)
+ p = newnode(p->op, NULL, NULL, p->syms[0]);
+ else
+ assert(0);
+ p->count = 1;
+ } else if (p) {
+ p->kids[0] = replace(p->kids[0]);
+ p->kids[1] = replace(p->kids[1]);
+ }
+ return p;
+}
+static Node prune(Node forest) {
+ Node p, *tail = &forest;
+ int count = 0;
+
+ for (p = forest; p; p = p->link) {
+ if (count > 0) {
+ p->kids[0] = replace(p->kids[0]);
+ p->kids[1] = replace(p->kids[1]);
+ }
+ if (( generic(p->op) == ASGN
+ && generic(p->kids[0]->op) == ADDRL
+ && p->kids[0]->syms[0]->temporary
+ && p->kids[0]->syms[0]->u.t.cse == p->kids[1])) {
+ Symbol tmp = p->kids[0]->syms[0];
+ if (!tmp->defined)
+ (*IR->local)(tmp);
+ tmp->defined = 1;
+ if (( generic(p->kids[1]->op) == INDIR
+ && isaddrop(p->kids[1]->kids[0]->op)
+ && p->kids[1]->kids[0]->syms[0]->sclass == REGISTER)
+ || (( generic(p->kids[1]->op) == INDIR
+ && isaddrop(p->kids[1]->kids[0]->op)) && tmp->sclass == AUTO)
+ || (generic(p->kids[1]->op) == ADDRG && tmp->sclass == AUTO)) {
+ tmp->u.t.replace = 1;
+ count++;
+ continue; /* and omit the assignment */
+ }
+ }
+ /* keep the assignment and other roots */
+ *tail = p;
+ tail = &(*tail)->link;
+ }
+ assert(*tail == NULL);
+ return forest;
+}
+static Node visit(Node p, int listed) {
+ if (p)
+ if (p->syms[2])
+ p = tmpnode(p);
+ else if (p->count <= 1 && !iscall(p->op)
+ || p->count == 0 && iscall(p->op)) {
+ p->kids[0] = visit(p->kids[0], 0);
+ p->kids[1] = visit(p->kids[1], 0);
+ }
+
+ else if (specific(p->op) == ADDRL+P || specific(p->op) == ADDRF+P) {
+ assert(!listed);
+ p = newnode(p->op, NULL, NULL, p->syms[0]);
+ p->count = 1;
+ }
+ else if (p->op == INDIR+B) {
+ p = newnode(p->op, p->kids[0], NULL, NULL);
+ p->count = 1;
+ p->kids[0] = visit(p->kids[0], 0);
+ p->kids[1] = visit(p->kids[1], 0);
+ }
+ else {
+ p->kids[0] = visit(p->kids[0], 0);
+ p->kids[1] = visit(p->kids[1], 0);
+ p->syms[2] = temporary(REGISTER, btot(p->op, opsize(p->op)));
+ assert(!p->syms[2]->defined);
+ p->syms[2]->ref = 1;
+ p->syms[2]->u.t.cse = p;
+
+ *tail = asgnnode(p->syms[2], p);
+ tail = &(*tail)->link;
+ if (!listed)
+ p = tmpnode(p);
+ };
+ return p;
+}
+static Node tmpnode(Node p) {
+ Symbol tmp = p->syms[2];
+
+ assert(tmp);
+ if (--p->count == 0)
+ p->syms[2] = NULL;
+ p = newnode(INDIR + ttob(tmp->type),
+ newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), NULL, NULL);
+ p->count = 1;
+ return p;
+}
+static Node asgnnode(Symbol tmp, Node p) {
+ p = newnode(ASGN + ttob(tmp->type),
+ newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), p, NULL);
+ p->syms[0] = intconst(tmp->type->size);
+ p->syms[1] = intconst(tmp->type->align);
+ return p;
+}
+/* printdag - print dag p on fd, or the node list if p == 0 */
+void printdag(Node p, int fd) {
+ FILE *f = fd == 1 ? stdout : stderr;
+
+ printed(0);
+ if (p == 0) {
+ if ((p = forest) != NULL)
+ do {
+ p = p->link;
+ printdag1(p, fd, 0);
+ } while (p != forest);
+ } else if (*printed(nodeid((Tree)p)))
+ fprint(f, "node'%d printed above\n", nodeid((Tree)p));
+ else
+ printdag1(p, fd, 0);
+}
+
+/* printdag1 - recursively print dag p */
+static void printdag1(Node p, int fd, int lev) {
+ int id, i;
+
+ if (p == 0 || *printed(id = nodeid((Tree)p)))
+ return;
+ *printed(id) = 1;
+ for (i = 0; i < NELEMS(p->kids); i++)
+ printdag1(p->kids[i], fd, lev + 1);
+ printnode(p, fd, lev);
+}
+
+/* printnode - print fields of dag p */
+static void printnode(Node p, int fd, int lev) {
+ if (p) {
+ FILE *f = fd == 1 ? stdout : stderr;
+ int i, id = nodeid((Tree)p);
+ fprint(f, "%c%d%s", lev == 0 ? '\'' : '#', id,
+ &" "[id < 10 ? 0 : id < 100 ? 1 : 2]);
+ fprint(f, "%s count=%d", opname(p->op), p->count);
+ for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++)
+ fprint(f, " #%d", nodeid((Tree)p->kids[i]));
+ if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type)
+ fprint(f, " {%t}", p->syms[0]->type);
+ else
+ for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++)
+ if (p->syms[i]->name)
+ fprint(f, " %s", p->syms[i]->name);
+ else
+ fprint(f, " %p", p->syms[i]);
+ fprint(f, "\n");
+ }
+}
+
+/* typestab - emit stab entries for p */
+static void typestab(Symbol p, void *cl) {
+ if (!isfunc(p->type) && (p->sclass == EXTERN || p->sclass == STATIC) && IR->stabsym)
+ (*IR->stabsym)(p);
+ else if ((p->sclass == TYPEDEF || p->sclass == 0) && IR->stabtype)
+ (*IR->stabtype)(p);
+}
+
diff --git a/lcc/src/dagcheck.md b/lcc/src/dagcheck.md
new file mode 100755
index 0000000..5deec0d
--- /dev/null
+++ b/lcc/src/dagcheck.md
@@ -0,0 +1,210 @@
+%{
+#include "c.h"
+typedef Node NODEPTR_TYPE;
+#define OP_LABEL(p) (specific((p)->op))
+#define LEFT_CHILD(p) ((p)->kids[0])
+#define RIGHT_CHILD(p) ((p)->kids[1])
+#define STATE_LABEL(p) ((p)->x.state)
+#define PANIC error
+%}
+%term CNSTF=17 CNSTI=21 CNSTP=23 CNSTU=22
+%term ARGB=41 ARGF=33 ARGI=37 ARGP=39 ARGU=38
+%term ASGNB=57 ASGNF=49 ASGNI=53 ASGNP=55 ASGNU=54
+%term INDIRB=73 INDIRF=65 INDIRI=69 INDIRP=71 INDIRU=70
+%term CVFF=113 CVFI=117
+%term CVIF=129 CVII=133 CVIU=134
+%term CVPP=151 CVPU=150
+%term CVUI=181 CVUP=183 CVUU=182
+%term NEGF=193 NEGI=197
+%term CALLB=217 CALLF=209 CALLI=213 CALLP=215 CALLU=214 CALLV=216
+%term RETF=241 RETI=245 RETP=247 RETU=246 RETV=248
+%term ADDRGP=263
+%term ADDRFP=279
+%term ADDRLP=295
+%term ADDF=305 ADDI=309 ADDP=311 ADDU=310
+%term SUBF=321 SUBI=325 SUBP=327 SUBU=326
+%term LSHI=341 LSHU=342
+%term MODI=357 MODU=358
+%term RSHI=373 RSHU=374
+%term BANDI=389 BANDU=390
+%term BCOMI=405 BCOMU=406
+%term BORI=421 BORU=422
+%term BXORI=437 BXORU=438
+%term DIVF=449 DIVI=453 DIVU=454
+%term MULF=465 MULI=469 MULU=470
+%term EQF=481 EQI=485 EQU=486
+%term GEF=497 GEI=501 GEU=502
+%term GTF=513 GTI=517 GTU=518
+%term LEF=529 LEI=533 LEU=534
+%term LTF=545 LTI=549 LTU=550
+%term NEF=561 NEI=565 NEU=566
+%term JUMPV=584
+%term LABELV=600
+%%
+stmt: INDIRB(P) ""
+stmt: INDIRF(P) ""
+stmt: INDIRI(P) ""
+stmt: INDIRU(P) ""
+stmt: INDIRP(P) ""
+stmt: CALLF(P) ""
+stmt: CALLI(P) ""
+stmt: CALLU(P) ""
+stmt: CALLP(P) ""
+stmt: V ""
+bogus: I "" 1
+bogus: U "" 1
+bogus: P "" 1
+bogus: F "" 1
+bogus: B "" 1
+bogus: V "" 1
+I: bogus "" 1
+U: bogus "" 1
+P: bogus "" 1
+F: bogus "" 1
+B: bogus "" 1
+V: bogus "" 1
+F: CNSTF ""
+I: CNSTI ""
+P: CNSTP ""
+U: CNSTU ""
+V: ARGB(B) ""
+V: ARGF(F) ""
+V: ARGI(I) ""
+V: ARGU(U) ""
+V: ARGP(P) ""
+V: ASGNB(P,B) ""
+V: ASGNF(P,F) ""
+V: ASGNI(P,I) ""
+V: ASGNU(P,U) ""
+V: ASGNP(P,P) ""
+B: INDIRB(P) ""
+F: INDIRF(P) ""
+I: INDIRI(P) ""
+U: INDIRU(P) ""
+P: INDIRP(P) ""
+I: CVII(I) ""
+I: CVUI(U) ""
+I: CVFI(F) ""
+U: CVIU(I) ""
+U: CVUU(U) ""
+U: CVPU(P) ""
+F: CVIF(I) ""
+F: CVFF(F) ""
+P: CVUP(U) ""
+P: CVPP(P) ""
+F: NEGF(F) ""
+I: NEGI(I) ""
+V: CALLB(P,P) ""
+F: CALLF(P) ""
+I: CALLI(P) ""
+U: CALLU(P) ""
+P: CALLP(P) ""
+V: CALLV(P) ""
+V: RETF(F) ""
+V: RETI(I) ""
+V: RETU(U) ""
+V: RETP(P) ""
+V: RETV ""
+P: ADDRGP ""
+P: ADDRFP ""
+P: ADDRLP ""
+F: ADDF(F,F) ""
+I: ADDI(I,I) ""
+P: ADDP(P,I) ""
+P: ADDP(I,P) ""
+P: ADDP(U,P) ""
+P: ADDP(P,U) ""
+U: ADDU(U,U) ""
+F: SUBF(F,F) ""
+I: SUBI(I,I) ""
+P: SUBP(P,I) ""
+P: SUBP(P,U) ""
+U: SUBU(U,U) ""
+I: LSHI(I,I) ""
+U: LSHU(U,I) ""
+I: MODI(I,I) ""
+U: MODU(U,U) ""
+I: RSHI(I,I) ""
+U: RSHU(U,I) ""
+U: BANDU(U,U) ""
+I: BANDI(I,I) ""
+U: BCOMU(U) ""
+I: BCOMI(I) ""
+I: BORI(I,I) ""
+U: BORU(U,U) ""
+U: BXORU(U,U) ""
+I: BXORI(I,I) ""
+F: DIVF(F,F) ""
+I: DIVI(I,I) ""
+U: DIVU(U,U) ""
+F: MULF(F,F) ""
+I: MULI(I,I) ""
+U: MULU(U,U) ""
+V: EQF(F,F) ""
+V: EQI(I,I) ""
+V: EQU(U,U) ""
+V: GEF(F,F) ""
+V: GEI(I,I) ""
+V: GEU(U,U) ""
+V: GTF(F,F) ""
+V: GTI(I,I) ""
+V: GTU(U,U) ""
+V: LEF(F,F) ""
+V: LEI(I,I) ""
+V: LEU(U,U) ""
+V: LTF(F,F) ""
+V: LTI(I,I) ""
+V: LTU(U,U) ""
+V: NEF(F,F) ""
+V: NEI(I,I) ""
+V: NEU(U,U) ""
+V: JUMPV(P) ""
+V: LABELV ""
+%%
+
+static void reduce(NODEPTR_TYPE p, int goalnt) {
+ int i, sz = opsize(p->op), rulenumber = _rule(p->x.state, goalnt);
+ short *nts = _nts[rulenumber];
+ NODEPTR_TYPE kids[10];
+
+ assert(rulenumber);
+ _kids(p, rulenumber, kids);
+ for (i = 0; nts[i]; i++)
+ reduce(kids[i], nts[i]);
+ switch (optype(p->op)) {
+#define xx(ty) if (sz == ty->size) return
+ case I:
+ case U:
+ xx(chartype);
+ xx(shorttype);
+ xx(inttype);
+ xx(longtype);
+ xx(longlong);
+ break;
+ case F:
+ xx(floattype);
+ xx(doubletype);
+ xx(longdouble);
+ break;
+ case P:
+ xx(voidptype);
+ xx(funcptype);
+ break;
+ case V:
+ case B: if (sz == 0) return;
+#undef xx
+ }
+ printdag(p, 2);
+ assert(0);
+}
+
+void check(Node p) {
+ struct _state { short cost[1]; };
+
+ _label(p);
+ if (((struct _state *)p->x.state)->cost[1] > 0) {
+ printdag(p, 2);
+ assert(0);
+ }
+ reduce(p, 1);
+}
diff --git a/lcc/src/decl.c b/lcc/src/decl.c
new file mode 100755
index 0000000..59e0850
--- /dev/null
+++ b/lcc/src/decl.c
@@ -0,0 +1,1160 @@
+#include "c.h"
+
+
+#define add(x,n) (x > inttype->u.sym->u.limits.max.i-(n) ? (overflow=1,x) : x+(n))
+#define chkoverflow(x,n) ((void)add(x,n))
+#define bits2bytes(n) (((n) + 7)/8)
+static int regcount;
+
+static List autos, registers;
+Symbol cfunc; /* current function */
+Symbol retv; /* return value location for structs */
+
+static void checkref(Symbol, void *);
+static Symbol dclglobal(int, char *, Type, Coordinate *);
+static Symbol dcllocal(int, char *, Type, Coordinate *);
+static Symbol dclparam(int, char *, Type, Coordinate *);
+static Type dclr(Type, char **, Symbol **, int);
+static Type dclr1(char **, Symbol **, int);
+static void decl(Symbol (*)(int, char *, Type, Coordinate *));
+extern void doconst(Symbol, void *);
+static void doglobal(Symbol, void *);
+static void doextern(Symbol, void *);
+static void exitparams(Symbol []);
+static void fields(Type);
+static void funcdefn(int, char *, Type, Symbol [], Coordinate);
+static void initglobal(Symbol, int);
+static void oldparam(Symbol, void *);
+static Symbol *parameters(Type);
+static Type specifier(int *);
+static Type structdcl(int);
+static Type tnode(int, Type);
+void program(void) {
+ int n;
+
+ level = GLOBAL;
+ for (n = 0; t != EOI; n++)
+ if (kind[t] == CHAR || kind[t] == STATIC
+ || t == ID || t == '*' || t == '(') {
+ decl(dclglobal);
+ deallocate(STMT);
+ if (!(glevel >= 3 || xref))
+ deallocate(FUNC);
+ } else if (t == ';') {
+ warning("empty declaration\n");
+ t = gettok();
+ } else {
+ error("unrecognized declaration\n");
+ t = gettok();
+ }
+ if (n == 0)
+ warning("empty input file\n");
+}
+static Type specifier(int *sclass) {
+ int cls, cons, sign, size, type, vol;
+ Type ty = NULL;
+
+ cls = vol = cons = sign = size = type = 0;
+ if (sclass == NULL)
+ cls = AUTO;
+ for (;;) {
+ int *p, tt = t;
+ switch (t) {
+ case AUTO:
+ case REGISTER: if (level <= GLOBAL && cls == 0)
+ error("invalid use of `%k'\n", t);
+ p = &cls; t = gettok(); break;
+ case STATIC: case EXTERN:
+ case TYPEDEF: p = &cls; t = gettok(); break;
+ case CONST: p = &cons; t = gettok(); break;
+ case VOLATILE: p = &vol; t = gettok(); break;
+ case SIGNED:
+ case UNSIGNED: p = &sign; t = gettok(); break;
+ case LONG: if (size == LONG) {
+ size = 0;
+ tt = LONG+LONG;
+ }
+ p = &size; t = gettok(); break;
+ case SHORT: p = &size; t = gettok(); break;
+ case VOID: case CHAR: case INT: case FLOAT:
+ case DOUBLE: p = &type; ty = tsym->type;
+ t = gettok(); break;
+ case ENUM: p = &type; ty = enumdcl(); break;
+ case STRUCT:
+ case UNION: p = &type; ty = structdcl(t); break;
+ case ID:
+ if (istypename(t, tsym) && type == 0
+ && sign == 0 && size == 0) {
+ use(tsym, src);
+ ty = tsym->type;
+ if (isqual(ty)
+ && ty->size != ty->type->size) {
+ ty = unqual(ty);
+ if (isconst(tsym->type))
+ ty = qual(CONST, ty);
+ if (isvolatile(tsym->type))
+ ty = qual(VOLATILE, ty);
+ tsym->type = ty;
+ }
+ p = &type;
+ t = gettok();
+ } else
+ p = NULL;
+ break;
+ default: p = NULL;
+ }
+ if (p == NULL)
+ break;
+ if (*p)
+ error("invalid use of `%k'\n", tt);
+ *p = tt;
+ }
+ if (sclass)
+ *sclass = cls;
+ if (type == 0) {
+ type = INT;
+ ty = inttype;
+ }
+ if (size == SHORT && type != INT
+ || size == LONG+LONG && type != INT
+ || size == LONG && type != INT && type != DOUBLE
+ || sign && type != INT && type != CHAR)
+ error("invalid type specification\n");
+ if (type == CHAR && sign)
+ ty = sign == UNSIGNED ? unsignedchar : signedchar;
+ else if (size == SHORT)
+ ty = sign == UNSIGNED ? unsignedshort : shorttype;
+ else if (size == LONG && type == DOUBLE)
+ ty = longdouble;
+ else if (size == LONG+LONG) {
+ ty = sign == UNSIGNED ? unsignedlonglong : longlong;
+ if (Aflag >= 1)
+ warning("`%t' is a non-ANSI type\n", ty);
+ } else if (size == LONG)
+ ty = sign == UNSIGNED ? unsignedlong : longtype;
+ else if (sign == UNSIGNED && type == INT)
+ ty = unsignedtype;
+ if (cons == CONST)
+ ty = qual(CONST, ty);
+ if (vol == VOLATILE)
+ ty = qual(VOLATILE, ty);
+ return ty;
+}
+static void decl(Symbol (*dcl)(int, char *, Type, Coordinate *)) {
+ int sclass;
+ Type ty, ty1;
+ static char stop[] = { CHAR, STATIC, ID, 0 };
+
+ ty = specifier(&sclass);
+ if (t == ID || t == '*' || t == '(' || t == '[') {
+ char *id;
+ Coordinate pos;
+ id = NULL;
+ pos = src;
+ if (level == GLOBAL) {
+ Symbol *params = NULL;
+ ty1 = dclr(ty, &id, &params, 0);
+ if (params && id && isfunc(ty1)
+ && (t == '{' || istypename(t, tsym)
+ || (kind[t] == STATIC && t != TYPEDEF))) {
+ if (sclass == TYPEDEF) {
+ error("invalid use of `typedef'\n");
+ sclass = EXTERN;
+ }
+ if (ty1->u.f.oldstyle)
+ exitscope();
+ funcdefn(sclass, id, ty1, params, pos);
+ return;
+ } else if (params)
+ exitparams(params);
+ } else
+ ty1 = dclr(ty, &id, NULL, 0);
+ for (;;) {
+ if (Aflag >= 1 && !hasproto(ty1))
+ warning("missing prototype\n");
+ if (id == NULL)
+ error("missing identifier\n");
+ else if (sclass == TYPEDEF)
+ {
+ Symbol p = lookup(id, identifiers);
+ if (p && p->scope == level)
+ error("redeclaration of `%s'\n", id);
+ p = install(id, &identifiers, level,
+ level < LOCAL ? PERM : FUNC);
+ p->type = ty1;
+ p->sclass = TYPEDEF;
+ p->src = pos;
+ }
+ else
+ (void)(*dcl)(sclass, id, ty1, &pos);
+ if (t != ',')
+ break;
+ t = gettok();
+ id = NULL;
+ pos = src;
+ ty1 = dclr(ty, &id, NULL, 0);
+ }
+ } else if (ty == NULL
+ || !(isenum(ty) ||
+ isstruct(ty) && (*unqual(ty)->u.sym->name < '1' || *unqual(ty)->u.sym->name > '9')))
+ error("empty declaration\n");
+ test(';', stop);
+}
+static Symbol dclglobal(int sclass, char *id, Type ty, Coordinate *pos) {
+ Symbol p;
+
+ if (sclass == 0)
+ sclass = AUTO;
+ else if (sclass != EXTERN && sclass != STATIC) {
+ error("invalid storage class `%k' for `%t %s'\n",
+ sclass, ty, id);
+ sclass = AUTO;
+ }
+ p = lookup(id, identifiers);
+ if (p && p->scope == GLOBAL) {
+ if (p->sclass != TYPEDEF && eqtype(ty, p->type, 1))
+ ty = compose(ty, p->type);
+ else
+ error("redeclaration of `%s' previously declared at %w\n", p->name, &p->src);
+
+ if (!isfunc(ty) && p->defined && t == '=')
+ error("redefinition of `%s' previously defined at %w\n", p->name, &p->src);
+
+ if (p->sclass == EXTERN && sclass == STATIC
+ || p->sclass == STATIC && sclass == AUTO
+ || p->sclass == AUTO && sclass == STATIC)
+ warning("inconsistent linkage for `%s' previously declared at %w\n", p->name, &p->src);
+
+ }
+ if (p == NULL || p->scope != GLOBAL) {
+ Symbol q = lookup(id, externals);
+ if (q) {
+ if (sclass == STATIC || !eqtype(ty, q->type, 1))
+ warning("declaration of `%s' does not match previous declaration at %w\n", id, &q->src);
+
+ p = relocate(id, externals, globals);
+ p->sclass = sclass;
+ } else {
+ p = install(id, &globals, GLOBAL, PERM);
+ p->sclass = sclass;
+ (*IR->defsymbol)(p);
+ }
+ if (p->sclass != STATIC) {
+ static int nglobals;
+ nglobals++;
+ if (Aflag >= 2 && nglobals == 512)
+ warning("more than 511 external identifiers\n");
+ }
+ } else if (p->sclass == EXTERN)
+ p->sclass = sclass;
+ p->type = ty;
+ p->src = *pos;
+ if (t == '=' && isfunc(p->type)) {
+ error("illegal initialization for `%s'\n", p->name);
+ t = gettok();
+ initializer(p->type, 0);
+ } else if (t == '=') {
+ initglobal(p, 0);
+ if (glevel > 0 && IR->stabsym) {
+ (*IR->stabsym)(p); swtoseg(p->u.seg); }
+ } else if (p->sclass == STATIC && !isfunc(p->type)
+ && p->type->size == 0)
+ error("undefined size for `%t %s'\n", p->type, p->name);
+ return p;
+}
+static void initglobal(Symbol p, int flag) {
+ Type ty;
+
+ if (t == '=' || flag) {
+ if (p->sclass == STATIC) {
+ for (ty = p->type; isarray(ty); ty = ty->type)
+ ;
+ defglobal(p, isconst(ty) ? LIT : DATA);
+ } else
+ defglobal(p, DATA);
+ if (t == '=')
+ t = gettok();
+ ty = initializer(p->type, 0);
+ if (isarray(p->type) && p->type->size == 0)
+ p->type = ty;
+ if (p->sclass == EXTERN)
+ p->sclass = AUTO;
+ }
+}
+void defglobal(Symbol p, int seg) {
+ p->u.seg = seg;
+ swtoseg(p->u.seg);
+ if (p->sclass != STATIC)
+ (*IR->export)(p);
+ (*IR->global)(p);
+ p->defined = 1;
+}
+
+static Type dclr(Type basety, char **id, Symbol **params, int abstract) {
+ Type ty = dclr1(id, params, abstract);
+
+ for ( ; ty; ty = ty->type)
+ switch (ty->op) {
+ case POINTER:
+ basety = ptr(basety);
+ break;
+ case FUNCTION:
+ basety = func(basety, ty->u.f.proto,
+ ty->u.f.oldstyle);
+ break;
+ case ARRAY:
+ basety = array(basety, ty->size, 0);
+ break;
+ case CONST: case VOLATILE:
+ basety = qual(ty->op, basety);
+ break;
+ default: assert(0);
+ }
+ if (Aflag >= 2 && basety->size > 32767)
+ warning("more than 32767 bytes in `%t'\n", basety);
+ return basety;
+}
+static Type tnode(int op, Type type) {
+ Type ty;
+
+ NEW0(ty, STMT);
+ ty->op = op;
+ ty->type = type;
+ return ty;
+}
+static Type dclr1(char **id, Symbol **params, int abstract) {
+ Type ty = NULL;
+
+ switch (t) {
+ case ID: if (id)
+ *id = token;
+ else
+ error("extraneous identifier `%s'\n", token);
+ t = gettok(); break;
+ case '*': t = gettok(); if (t == CONST || t == VOLATILE) {
+ Type ty1;
+ ty1 = ty = tnode(t, NULL);
+ while ((t = gettok()) == CONST || t == VOLATILE)
+ ty1 = tnode(t, ty1);
+ ty->type = dclr1(id, params, abstract);
+ ty = ty1;
+ } else
+ ty = dclr1(id, params, abstract);
+ ty = tnode(POINTER, ty); break;
+ case '(': t = gettok(); if (abstract
+ && (t == REGISTER || istypename(t, tsym) || t == ')')) {
+ Symbol *args;
+ ty = tnode(FUNCTION, ty);
+ enterscope();
+ if (level > PARAM)
+ enterscope();
+ args = parameters(ty);
+ exitparams(args);
+ } else {
+ ty = dclr1(id, params, abstract);
+ expect(')');
+ if (abstract && ty == NULL
+ && (id == NULL || *id == NULL))
+ return tnode(FUNCTION, NULL);
+ } break;
+ case '[': break;
+ default: return ty;
+ }
+ while (t == '(' || t == '[')
+ switch (t) {
+ case '(': t = gettok(); { Symbol *args;
+ ty = tnode(FUNCTION, ty);
+ enterscope();
+ if (level > PARAM)
+ enterscope();
+ args = parameters(ty);
+ if (params && *params == NULL)
+ *params = args;
+ else
+ exitparams(args);
+ }
+ break;
+ case '[': t = gettok(); { int n = 0;
+ if (kind[t] == ID) {
+ n = intexpr(']', 1);
+ if (n <= 0) {
+ error("`%d' is an illegal array size\n", n);
+ n = 1;
+ }
+ } else
+ expect(']');
+ ty = tnode(ARRAY, ty);
+ ty->size = n; } break;
+ default: assert(0);
+ }
+ return ty;
+}
+static Symbol *parameters(Type fty) {
+ List list = NULL;
+ Symbol *params;
+
+ if (kind[t] == STATIC || istypename(t, tsym)) {
+ int n = 0;
+ Type ty1 = NULL;
+ for (;;) {
+ Type ty;
+ int sclass = 0;
+ char *id = NULL;
+ if (ty1 && t == ELLIPSIS) {
+ static struct symbol sentinel;
+ if (sentinel.type == NULL) {
+ sentinel.type = voidtype;
+ sentinel.defined = 1;
+ }
+ if (ty1 == voidtype)
+ error("illegal formal parameter types\n");
+ list = append(&sentinel, list);
+ t = gettok();
+ break;
+ }
+ if (!istypename(t, tsym) && t != REGISTER)
+ error("missing parameter type\n");
+ n++;
+ ty = dclr(specifier(&sclass), &id, NULL, 1);
+ if ( ty == voidtype && (ty1 || id)
+ || ty1 == voidtype)
+ error("illegal formal parameter types\n");
+ if (id == NULL)
+ id = stringd(n);
+ if (ty != voidtype)
+ list = append(dclparam(sclass, id, ty, &src), list);
+ if (Aflag >= 1 && !hasproto(ty))
+ warning("missing prototype\n");
+ if (ty1 == NULL)
+ ty1 = ty;
+ if (t != ',')
+ break;
+ t = gettok();
+ }
+ fty->u.f.proto = newarray(length(list) + 1,
+ sizeof (Type *), PERM);
+ params = ltov(&list, FUNC);
+ for (n = 0; params[n]; n++)
+ fty->u.f.proto[n] = params[n]->type;
+ fty->u.f.proto[n] = NULL;
+ fty->u.f.oldstyle = 0;
+ } else {
+ if (t == ID)
+ for (;;) {
+ Symbol p;
+ if (t != ID) {
+ error("expecting an identifier\n");
+ break;
+ }
+ p = dclparam(0, token, inttype, &src);
+ p->defined = 0;
+ list = append(p, list);
+ t = gettok();
+ if (t != ',')
+ break;
+ t = gettok();
+ }
+ params = ltov(&list, FUNC);
+ fty->u.f.proto = NULL;
+ fty->u.f.oldstyle = 1;
+ }
+ if (t != ')') {
+ static char stop[] = { CHAR, STATIC, IF, ')', 0 };
+ expect(')');
+ skipto('{', stop);
+ }
+ if (t == ')')
+ t = gettok();
+ return params;
+}
+static void exitparams(Symbol params[]) {
+ assert(params);
+ if (params[0] && !params[0]->defined)
+ error("extraneous old-style parameter list\n");
+ if (level > PARAM)
+ exitscope();
+ exitscope();
+}
+
+static Symbol dclparam(int sclass, char *id, Type ty, Coordinate *pos) {
+ Symbol p;
+
+ if (isfunc(ty))
+ ty = ptr(ty);
+ else if (isarray(ty))
+ ty = atop(ty);
+ if (sclass == 0)
+ sclass = AUTO;
+ else if (sclass != REGISTER) {
+ error("invalid storage class `%k' for `%t%s\n",
+ sclass, ty, stringf(id ? " %s'" : "' parameter", id));
+ sclass = AUTO;
+ } else if (isvolatile(ty) || isstruct(ty)) {
+ warning("register declaration ignored for `%t%s\n",
+ ty, stringf(id ? " %s'" : "' parameter", id));
+ sclass = AUTO;
+ }
+
+ p = lookup(id, identifiers);
+ if (p && p->scope == level)
+ error("duplicate declaration for `%s' previously declared at %w\n", id, &p->src);
+
+ else
+ p = install(id, &identifiers, level, FUNC);
+ p->sclass = sclass;
+ p->src = *pos;
+ p->type = ty;
+ p->defined = 1;
+ if (t == '=') {
+ error("illegal initialization for parameter `%s'\n", id);
+ t = gettok();
+ (void)expr1(0);
+ }
+ return p;
+}
+static Type structdcl(int op) {
+ char *tag;
+ Type ty;
+ Symbol p;
+ Coordinate pos;
+
+ t = gettok();
+ pos = src;
+ if (t == ID) {
+ tag = token;
+ t = gettok();
+ } else
+ tag = "";
+ if (t == '{') {
+ static char stop[] = { IF, ',', 0 };
+ ty = newstruct(op, tag);
+ ty->u.sym->src = pos;
+ ty->u.sym->defined = 1;
+ t = gettok();
+ if (istypename(t, tsym))
+ fields(ty);
+ else
+ error("invalid %k field declarations\n", op);
+ test('}', stop);
+ }
+ else if (*tag && (p = lookup(tag, types)) != NULL
+ && p->type->op == op) {
+ ty = p->type;
+ if (t == ';' && p->scope < level)
+ ty = newstruct(op, tag);
+ }
+ else {
+ if (*tag == 0)
+ error("missing %k tag\n", op);
+ ty = newstruct(op, tag);
+ }
+ if (*tag && xref)
+ use(ty->u.sym, pos);
+ return ty;
+}
+static void fields(Type ty) {
+ { int n = 0;
+ while (istypename(t, tsym)) {
+ static char stop[] = { IF, CHAR, '}', 0 };
+ Type ty1 = specifier(NULL);
+ for (;;) {
+ Field p;
+ char *id = NULL;
+ Type fty = dclr(ty1, &id, NULL, 0);
+ p = newfield(id, ty, fty);
+ if (Aflag >= 1 && !hasproto(p->type))
+ warning("missing prototype\n");
+ if (t == ':') {
+ if (unqual(p->type) != inttype
+ && unqual(p->type) != unsignedtype) {
+ error("`%t' is an illegal bit-field type\n",
+ p->type);
+ p->type = inttype;
+ }
+ t = gettok();
+ p->bitsize = intexpr(0, 0);
+ if (p->bitsize > 8*inttype->size || p->bitsize < 0) {
+ error("`%d' is an illegal bit-field size\n",
+ p->bitsize);
+ p->bitsize = 8*inttype->size;
+ } else if (p->bitsize == 0 && id) {
+ warning("extraneous 0-width bit field `%t %s' ignored\n", p->type, id);
+
+ p->name = stringd(genlabel(1));
+ }
+ p->lsb = 1;
+ }
+ else {
+ if (id == NULL)
+ error("field name missing\n");
+ else if (isfunc(p->type))
+ error("`%t' is an illegal field type\n", p->type);
+ else if (p->type->size == 0)
+ error("undefined size for field `%t %s'\n",
+ p->type, id);
+ }
+ if (isconst(p->type))
+ ty->u.sym->u.s.cfields = 1;
+ if (isvolatile(p->type))
+ ty->u.sym->u.s.vfields = 1;
+ n++;
+ if (Aflag >= 2 && n == 128)
+ warning("more than 127 fields in `%t'\n", ty);
+ if (t != ',')
+ break;
+ t = gettok();
+ }
+ test(';', stop);
+ } }
+ { int bits = 0, off = 0, overflow = 0;
+ Field p, *q = &ty->u.sym->u.s.flist;
+ ty->align = IR->structmetric.align;
+ for (p = *q; p; p = p->link) {
+ int a = p->type->align ? p->type->align : 1;
+ if (p->lsb)
+ a = unsignedtype->align;
+ if (ty->op == UNION)
+ off = bits = 0;
+ else if (p->bitsize == 0 || bits == 0
+ || bits - 1 + p->bitsize > 8*unsignedtype->size) {
+ off = add(off, bits2bytes(bits-1));
+ bits = 0;
+ chkoverflow(off, a - 1);
+ off = roundup(off, a);
+ }
+ if (a > ty->align)
+ ty->align = a;
+ p->offset = off;
+
+ if (p->lsb) {
+ if (bits == 0)
+ bits = 1;
+ if (IR->little_endian)
+ p->lsb = bits;
+ else
+ p->lsb = 8*unsignedtype->size - bits + 1
+ - p->bitsize + 1;
+ bits += p->bitsize;
+ } else
+ off = add(off, p->type->size);
+ if (off + bits2bytes(bits-1) > ty->size)
+ ty->size = off + bits2bytes(bits-1);
+ if (p->name == NULL
+ || !('1' <= *p->name && *p->name <= '9')) {
+ *q = p;
+ q = &p->link;
+ }
+ }
+ *q = NULL;
+ chkoverflow(ty->size, ty->align - 1);
+ ty->size = roundup(ty->size, ty->align);
+ if (overflow) {
+ error("size of `%t' exceeds %d bytes\n", ty, inttype->u.sym->u.limits.max.i);
+ ty->size = inttype->u.sym->u.limits.max.i&(~(ty->align - 1));
+ } }
+}
+static void funcdefn(int sclass, char *id, Type ty, Symbol params[], Coordinate pt) {
+ int i, n;
+ Symbol *callee, *caller, p;
+ Type rty = freturn(ty);
+
+ if (isstruct(rty) && rty->size == 0)
+ error("illegal use of incomplete type `%t'\n", rty);
+ for (n = 0; params[n]; n++)
+ ;
+ if (n > 0 && params[n-1]->name == NULL)
+ params[--n] = NULL;
+ if (Aflag >= 2 && n > 31)
+ warning("more than 31 parameters in function `%s'\n", id);
+ if (ty->u.f.oldstyle) {
+ if (Aflag >= 1)
+ warning("old-style function definition for `%s'\n", id);
+ caller = params;
+ callee = newarray(n + 1, sizeof *callee, FUNC);
+ memcpy(callee, caller, (n+1)*sizeof *callee);
+ enterscope();
+ assert(level == PARAM);
+ while (kind[t] == STATIC || istypename(t, tsym))
+ decl(dclparam);
+ foreach(identifiers, PARAM, oldparam, callee);
+
+ for (i = 0; (p = callee[i]) != NULL; i++) {
+ if (!p->defined)
+ callee[i] = dclparam(0, p->name, inttype, &p->src);
+ *caller[i] = *p;
+ caller[i]->sclass = AUTO;
+ caller[i]->type = promote(p->type);
+ }
+ p = lookup(id, identifiers);
+ if (p && p->scope == GLOBAL && isfunc(p->type)
+ && p->type->u.f.proto) {
+ Type *proto = p->type->u.f.proto;
+ for (i = 0; caller[i] && proto[i]; i++) {
+ Type ty = unqual(proto[i]);
+ if (eqtype(isenum(ty) ? ty->type : ty,
+ unqual(caller[i]->type), 1) == 0)
+ break;
+ else if (isenum(ty) && !isenum(unqual(caller[i]->type)))
+ warning("compatibility of `%t' and `%t' is compiler dependent\n",
+ proto[i], caller[i]->type);
+ }
+ if (proto[i] || caller[i])
+ error("conflicting argument declarations for function `%s'\n", id);
+
+ }
+ else {
+ Type *proto = newarray(n + 1, sizeof *proto, PERM);
+ if (Aflag >= 1)
+ warning("missing prototype for `%s'\n", id);
+ for (i = 0; i < n; i++)
+ proto[i] = caller[i]->type;
+ proto[i] = NULL;
+ ty = func(rty, proto, 1);
+ }
+ } else {
+ callee = params;
+ caller = newarray(n + 1, sizeof *caller, FUNC);
+ for (i = 0; (p = callee[i]) != NULL && p->name; i++) {
+ NEW(caller[i], FUNC);
+ *caller[i] = *p;
+ if (isint(p->type))
+ caller[i]->type = promote(p->type);
+ caller[i]->sclass = AUTO;
+ if ('1' <= *p->name && *p->name <= '9')
+ error("missing name for parameter %d to function `%s'\n", i + 1, id);
+
+ }
+ caller[i] = NULL;
+ }
+ for (i = 0; (p = callee[i]) != NULL; i++)
+ if (p->type->size == 0) {
+ error("undefined size for parameter `%t %s'\n",
+ p->type, p->name);
+ caller[i]->type = p->type = inttype;
+ }
+ if (Aflag >= 2 && sclass != STATIC && strcmp(id, "main") == 0) {
+ if (ty->u.f.oldstyle)
+ warning("`%t %s()' is a non-ANSI definition\n", rty, id);
+ else if (!(rty == inttype
+ && (n == 0 && callee[0] == NULL
+ || n == 2 && callee[0]->type == inttype
+ && isptr(callee[1]->type) && callee[1]->type->type == charptype
+ && !variadic(ty))))
+ warning("`%s' is a non-ANSI definition\n", typestring(ty, id));
+ }
+ p = lookup(id, identifiers);
+ if (p && isfunc(p->type) && p->defined)
+ error("redefinition of `%s' previously defined at %w\n",
+ p->name, &p->src);
+ cfunc = dclglobal(sclass, id, ty, &pt);
+ cfunc->u.f.label = genlabel(1);
+ cfunc->u.f.callee = callee;
+ cfunc->u.f.pt = src;
+ cfunc->defined = 1;
+ if (xref)
+ use(cfunc, cfunc->src);
+ if (Pflag)
+ printproto(cfunc, cfunc->u.f.callee);
+ if (ncalled >= 0)
+ ncalled = findfunc(cfunc->name, pt.file);
+ labels = table(NULL, LABELS);
+ stmtlabs = table(NULL, LABELS);
+ refinc = 1.0;
+ regcount = 0;
+ codelist = &codehead;
+ codelist->next = NULL;
+ if (!IR->wants_callb && isstruct(rty))
+ retv = genident(AUTO, ptr(rty), PARAM);
+ compound(0, NULL, 0);
+
+ {
+ Code cp;
+ for (cp = codelist; cp->kind < Label; cp = cp->prev)
+ ;
+ if (cp->kind != Jump) {
+ if (rty != voidtype) {
+ warning("missing return value\n");
+ retcode(cnsttree(inttype, 0L));
+ } else
+ retcode(NULL);
+ }
+ }
+ definelab(cfunc->u.f.label);
+ if (events.exit)
+ apply(events.exit, cfunc, NULL);
+ walk(NULL, 0, 0);
+ exitscope();
+ assert(level == PARAM);
+ foreach(identifiers, level, checkref, NULL);
+ if (!IR->wants_callb && isstruct(rty)) {
+ Symbol *a;
+ a = newarray(n + 2, sizeof *a, FUNC);
+ a[0] = retv;
+ memcpy(&a[1], callee, (n+1)*sizeof *callee);
+ callee = a;
+ a = newarray(n + 2, sizeof *a, FUNC);
+ NEW(a[0], FUNC);
+ *a[0] = *retv;
+ memcpy(&a[1], caller, (n+1)*sizeof *callee);
+ caller = a;
+ }
+ if (!IR->wants_argb)
+ for (i = 0; caller[i]; i++)
+ if (isstruct(caller[i]->type)) {
+ caller[i]->type = ptr(caller[i]->type);
+ callee[i]->type = ptr(callee[i]->type);
+ caller[i]->structarg = callee[i]->structarg = 1;
+ }
+ if (glevel > 1) for (i = 0; callee[i]; i++) callee[i]->sclass = AUTO;
+ if (cfunc->sclass != STATIC)
+ (*IR->export)(cfunc);
+ if (glevel && IR->stabsym) {
+ swtoseg(CODE); (*IR->stabsym)(cfunc); }
+ swtoseg(CODE);
+ (*IR->function)(cfunc, caller, callee, cfunc->u.f.ncalls);
+ if (glevel && IR->stabfend)
+ (*IR->stabfend)(cfunc, lineno);
+ foreach(stmtlabs, LABELS, checklab, NULL);
+ exitscope();
+ expect('}');
+ labels = stmtlabs = NULL;
+ retv = NULL;
+ cfunc = NULL;
+}
+static void oldparam(Symbol p, void *cl) {
+ int i;
+ Symbol *callee = cl;
+
+ for (i = 0; callee[i]; i++)
+ if (p->name == callee[i]->name) {
+ callee[i] = p;
+ return;
+ }
+ error("declared parameter `%s' is missing\n", p->name);
+}
+void compound(int loop, struct swtch *swp, int lev) {
+ Code cp;
+ int nregs;
+
+ walk(NULL, 0, 0);
+ cp = code(Blockbeg);
+ enterscope();
+ assert(level >= LOCAL);
+ if (level == LOCAL && events.entry)
+ apply(events.entry, cfunc, NULL);
+ definept(NULL);
+ expect('{');
+ autos = registers = NULL;
+ if (level == LOCAL && IR->wants_callb
+ && isstruct(freturn(cfunc->type))) {
+ retv = genident(AUTO, ptr(freturn(cfunc->type)), level);
+ retv->defined = 1;
+ retv->ref = 1;
+ registers = append(retv, registers);
+ }
+ while (kind[t] == CHAR || kind[t] == STATIC
+ || istypename(t, tsym) && getchr() != ':')
+ decl(dcllocal);
+ {
+ int i;
+ Symbol *a = ltov(&autos, STMT);
+ nregs = length(registers);
+ for (i = 0; a[i]; i++)
+ registers = append(a[i], registers);
+ cp->u.block.locals = ltov(&registers, FUNC);
+ }
+ if (events.blockentry)
+ apply(events.blockentry, cp->u.block.locals, NULL);
+ while (kind[t] == IF || kind[t] == ID)
+ statement(loop, swp, lev);
+ walk(NULL, 0, 0);
+ foreach(identifiers, level, checkref, NULL);
+ {
+ int i = nregs, j;
+ Symbol p;
+ for ( ; (p = cp->u.block.locals[i]) != NULL; i++) {
+ for (j = i; j > nregs
+ && cp->u.block.locals[j-1]->ref < p->ref; j--)
+ cp->u.block.locals[j] = cp->u.block.locals[j-1];
+ cp->u.block.locals[j] = p;
+ }
+ }
+ if (events.blockexit)
+ apply(events.blockexit, cp->u.block.locals, NULL);
+ cp->u.block.level = level;
+ cp->u.block.identifiers = identifiers;
+ cp->u.block.types = types;
+ code(Blockend)->u.begin = cp;
+ if (reachable(Gen))
+ definept(NULL);
+ if (level > LOCAL) {
+ exitscope();
+ expect('}');
+ }
+}
+static void checkref(Symbol p, void *cl) {
+ if (p->scope >= PARAM
+ && (isvolatile(p->type) || isfunc(p->type)))
+ p->addressed = 1;
+ if (Aflag >= 2 && p->defined && p->ref == 0) {
+ if (p->sclass == STATIC)
+ warning("static `%t %s' is not referenced\n",
+ p->type, p->name);
+ else if (p->scope == PARAM)
+ warning("parameter `%t %s' is not referenced\n",
+ p->type, p->name);
+ else if (p->scope >= LOCAL && p->sclass != EXTERN)
+ warning("local `%t %s' is not referenced\n",
+ p->type, p->name);
+ }
+ if (p->sclass == AUTO
+ && (p->scope == PARAM && regcount == 0
+ || p->scope >= LOCAL)
+ && !p->addressed && isscalar(p->type) && p->ref >= 3.0)
+ p->sclass = REGISTER;
+ if (level == GLOBAL && p->sclass == STATIC && !p->defined
+ && isfunc(p->type) && p->ref)
+ error("undefined static `%t %s'\n", p->type, p->name);
+ assert(!(level == GLOBAL && p->sclass == STATIC && !p->defined && !isfunc(p->type)));
+}
+static Symbol dcllocal(int sclass, char *id, Type ty, Coordinate *pos) {
+ Symbol p, q;
+
+ if (sclass == 0)
+ sclass = isfunc(ty) ? EXTERN : AUTO;
+ else if (isfunc(ty) && sclass != EXTERN) {
+ error("invalid storage class `%k' for `%t %s'\n",
+ sclass, ty, id);
+ sclass = EXTERN;
+ } else if (sclass == REGISTER
+ && (isvolatile(ty) || isstruct(ty) || isarray(ty))) {
+ warning("register declaration ignored for `%t %s'\n",
+ ty, id);
+ sclass = AUTO;
+ }
+ q = lookup(id, identifiers);
+ if (q && q->scope >= level
+ || q && q->scope == PARAM && level == LOCAL)
+ if (sclass == EXTERN && q->sclass == EXTERN
+ && eqtype(q->type, ty, 1))
+ ty = compose(ty, q->type);
+ else
+ error("redeclaration of `%s' previously declared at %w\n", q->name, &q->src);
+
+ assert(level >= LOCAL);
+ p = install(id, &identifiers, level, sclass == STATIC || sclass == EXTERN ? PERM : FUNC);
+ p->type = ty;
+ p->sclass = sclass;
+ p->src = *pos;
+ switch (sclass) {
+ case EXTERN: q = lookup(id, globals);
+ if (q == NULL || q->sclass == TYPEDEF || q->sclass == ENUM) {
+ q = lookup(id, externals);
+ if (q == NULL) {
+ q = install(p->name, &externals, GLOBAL, PERM);
+ q->type = p->type;
+ q->sclass = EXTERN;
+ q->src = src;
+ (*IR->defsymbol)(q);
+ }
+ }
+ if (!eqtype(p->type, q->type, 1))
+ warning("declaration of `%s' does not match previous declaration at %w\n", q->name, &q->src);
+
+ p->u.alias = q; break;
+ case STATIC: (*IR->defsymbol)(p);
+ initglobal(p, 0);
+ if (!p->defined)
+ if (p->type->size > 0) {
+ defglobal(p, BSS);
+ (*IR->space)(p->type->size);
+ } else
+ error("undefined size for `%t %s'\n",
+ p->type, p->name);
+ p->defined = 1; break;
+ case REGISTER: registers = append(p, registers);
+ regcount++;
+ p->defined = 1;
+ break;
+ case AUTO: autos = append(p, autos);
+ p->defined = 1; break;
+ default: assert(0);
+ }
+ if (t == '=') {
+ Tree e;
+ if (sclass == EXTERN)
+ error("illegal initialization of `extern %s'\n", id);
+ t = gettok();
+ definept(NULL);
+ if (isscalar(p->type)
+ || isstruct(p->type) && t != '{') {
+ if (t == '{') {
+ t = gettok();
+ e = expr1(0);
+ expect('}');
+ } else
+ e = expr1(0);
+ } else {
+ Symbol t1;
+ Type ty = p->type, ty1 = ty;
+ while (isarray(ty1))
+ ty1 = ty1->type;
+ if (!isconst(ty) && (!isarray(ty) || !isconst(ty1)))
+ ty = qual(CONST, ty);
+ t1 = genident(STATIC, ty, GLOBAL);
+ initglobal(t1, 1);
+ if (isarray(p->type) && p->type->size == 0
+ && t1->type->size > 0)
+ p->type = array(p->type->type,
+ t1->type->size/t1->type->type->size, 0);
+ e = idtree(t1);
+ }
+ walk(root(asgn(p, e)), 0, 0);
+ p->ref = 1;
+ }
+ if (!isfunc(p->type) && p->defined && p->type->size <= 0)
+ error("undefined size for `%t %s'\n", p->type, id);
+ return p;
+}
+void finalize(void) {
+ foreach(externals, GLOBAL, doextern, NULL);
+ foreach(identifiers, GLOBAL, doglobal, NULL);
+ foreach(identifiers, GLOBAL, checkref, NULL);
+ foreach(constants, CONSTANTS, doconst, NULL);
+}
+static void doextern(Symbol p, void *cl) {
+ (*IR->import)(p);
+}
+static void doglobal(Symbol p, void *cl) {
+ if (!p->defined && (p->sclass == EXTERN
+ || isfunc(p->type) && p->sclass == AUTO))
+ (*IR->import)(p);
+ else if (!p->defined && !isfunc(p->type)
+ && (p->sclass == AUTO || p->sclass == STATIC)) {
+ if (isarray(p->type)
+ && p->type->size == 0 && p->type->type->size > 0)
+ p->type = array(p->type->type, 1, 0);
+ if (p->type->size > 0) {
+ defglobal(p, BSS);
+ (*IR->space)(p->type->size);
+ if (glevel > 0 && IR->stabsym)
+ (*IR->stabsym)(p);
+ } else
+ error("undefined size for `%t %s'\n",
+ p->type, p->name);
+ p->defined = 1;
+ }
+ if (Pflag
+ && !isfunc(p->type)
+ && !p->generated && p->sclass != EXTERN)
+ printdecl(p, p->type);
+}
+void doconst(Symbol p, void *cl) {
+ if (p->u.c.loc) {
+ assert(p->u.c.loc->u.seg == 0);
+ defglobal(p->u.c.loc, LIT);
+ if (isarray(p->type) && p->type->type == widechar) {
+ unsigned int *s = p->u.c.v.p;
+ int n = p->type->size/widechar->size;
+ while (n-- > 0) {
+ Value v;
+ v.u = *s++;
+ (*IR->defconst)(widechar->op, widechar->size, v);
+ }
+ } else if (isarray(p->type))
+ (*IR->defstring)(p->type->size, p->u.c.v.p);
+ else
+ (*IR->defconst)(p->type->op, p->type->size, p->u.c.v);
+ p->u.c.loc = NULL;
+ }
+}
+void checklab(Symbol p, void *cl) {
+ if (!p->defined)
+ error("undefined label `%s'\n", p->name);
+ p->defined = 1;
+}
+
+Type enumdcl(void) {
+ char *tag;
+ Type ty;
+ Symbol p;
+ Coordinate pos;
+
+ t = gettok();
+ pos = src;
+ if (t == ID) {
+ tag = token;
+ t = gettok();
+ } else
+ tag = "";
+ if (t == '{') {
+ static char follow[] = { IF, 0 };
+ int n = 0;
+ long k = -1;
+ List idlist = 0;
+ ty = newstruct(ENUM, tag);
+ t = gettok();
+ if (t != ID)
+ error("expecting an enumerator identifier\n");
+ while (t == ID) {
+ char *id = token;
+ Coordinate s;
+ if (tsym && tsym->scope == level)
+ error("redeclaration of `%s' previously declared at %w\n",
+ token, &tsym->src);
+ s = src;
+ t = gettok();
+ if (t == '=') {
+ t = gettok();
+ k = intexpr(0, 0);
+ } else {
+ if (k == inttype->u.sym->u.limits.max.i)
+ error("overflow in value for enumeration constant `%s'\n", id);
+ k++;
+ }
+ p = install(id, &identifiers, level, level < LOCAL ? PERM : FUNC);
+ p->src = s;
+ p->type = ty;
+ p->sclass = ENUM;
+ p->u.value = k;
+ idlist = append(p, idlist);
+ n++;
+ if (Aflag >= 2 && n == 128)
+ warning("more than 127 enumeration constants in `%t'\n", ty);
+ if (t != ',')
+ break;
+ t = gettok();
+ if (Aflag >= 2 && t == '}')
+ warning("non-ANSI trailing comma in enumerator list\n");
+ }
+ test('}', follow);
+ ty->type = inttype;
+ ty->size = ty->type->size;
+ ty->align = ty->type->align;
+ ty->u.sym->u.idlist = ltov(&idlist, PERM);
+ ty->u.sym->defined = 1;
+ } else if ((p = lookup(tag, types)) != NULL && p->type->op == ENUM) {
+ ty = p->type;
+ if (t == ';')
+ error("empty declaration\n");
+ } else {
+ error("unknown enumeration `%s'\n", tag);
+ ty = newstruct(ENUM, tag);
+ ty->type = inttype;
+ }
+ if (*tag && xref)
+ use(p, pos);
+ return ty;
+}
+
+Type typename(void) {
+ Type ty = specifier(NULL);
+
+ if (t == '*' || t == '(' || t == '[') {
+ ty = dclr(ty, NULL, NULL, 1);
+ if (Aflag >= 1 && !hasproto(ty))
+ warning("missing prototype\n");
+ }
+ return ty;
+}
+
diff --git a/lcc/src/enode.c b/lcc/src/enode.c
new file mode 100755
index 0000000..a81c632
--- /dev/null
+++ b/lcc/src/enode.c
@@ -0,0 +1,543 @@
+#include "c.h"
+
+
+static Tree addtree(int, Tree, Tree);
+static Tree andtree(int, Tree, Tree);
+static Tree cmptree(int, Tree, Tree);
+static int compatible(Type, Type);
+static int isnullptr(Tree e);
+static Tree multree(int, Tree, Tree);
+static Tree subtree(int, Tree, Tree);
+#define isvoidptr(ty) \
+ (isptr(ty) && unqual(ty->type) == voidtype)
+
+Tree (*optree[])(int, Tree, Tree) = {
+#define xx(a,b,c,d,e,f,g) e,
+#define yy(a,b,c,d,e,f,g) e,
+#include "token.h"
+};
+Tree call(Tree f, Type fty, Coordinate src) {
+ int n = 0;
+ Tree args = NULL, r = NULL, e;
+ Type *proto, rty = unqual(freturn(fty));
+ Symbol t3 = NULL;
+
+ if (fty->u.f.oldstyle)
+ proto = NULL;
+ else
+ proto = fty->u.f.proto;
+ if (hascall(f))
+ r = f;
+ if (isstruct(rty))
+ {
+ t3 = temporary(AUTO, unqual(rty));
+ if (rty->size == 0)
+ error("illegal use of incomplete type `%t'\n", rty);
+ }
+ if (t != ')')
+ for (;;) {
+ Tree q = pointer(expr1(0));
+ if (proto && *proto && *proto != voidtype)
+ {
+ Type aty;
+ q = value(q);
+ aty = assign(*proto, q);
+ if (aty)
+ q = cast(q, aty);
+ else
+ error("type error in argument %d to %s; found `%t' expected `%t'\n", n + 1, funcname(f),
+
+ q->type, *proto);
+ if ((isint(q->type) || isenum(q->type))
+ && q->type->size != inttype->size)
+ q = cast(q, promote(q->type));
+ ++proto;
+ }
+ else
+ {
+ if (!fty->u.f.oldstyle && *proto == NULL)
+ error("too many arguments to %s\n", funcname(f));
+ q = value(q);
+ if (isarray(q->type) || q->type->size == 0)
+ error("type error in argument %d to %s; `%t' is illegal\n", n + 1, funcname(f), q->type);
+
+ else
+ q = cast(q, promote(q->type));
+ }
+ if (!IR->wants_argb && isstruct(q->type))
+ if (iscallb(q))
+ q = addrof(q);
+ else {
+ Symbol t1 = temporary(AUTO, unqual(q->type));
+ q = asgn(t1, q);
+ q = tree(RIGHT, ptr(t1->type),
+ root(q), lvalue(idtree(t1)));
+ }
+ if (q->type->size == 0)
+ q->type = inttype;
+ if (hascall(q))
+ r = r ? tree(RIGHT, voidtype, r, q) : q;
+ args = tree(mkop(ARG, q->type), q->type, q, args);
+ n++;
+ if (Aflag >= 2 && n == 32)
+ warning("more than 31 arguments in a call to %s\n",
+ funcname(f));
+ if (t != ',')
+ break;
+ t = gettok();
+ }
+ expect(')');
+ if (proto && *proto && *proto != voidtype)
+ error("insufficient number of arguments to %s\n",
+ funcname(f));
+ if (r)
+ args = tree(RIGHT, voidtype, r, args);
+ e = calltree(f, rty, args, t3);
+ if (events.calls)
+ apply(events.calls, &src, &e);
+ return e;
+}
+Tree calltree(Tree f, Type ty, Tree args, Symbol t3) {
+ Tree p;
+
+ if (args)
+ f = tree(RIGHT, f->type, args, f);
+ if (isstruct(ty))
+ assert(t3),
+ p = tree(RIGHT, ty,
+ tree(CALL+B, ty, f, addrof(idtree(t3))),
+ idtree(t3));
+ else {
+ Type rty = ty;
+ if (isenum(ty))
+ rty = unqual(ty)->type;
+ if (!isfloat(rty))
+ rty = promote(rty);
+ p = tree(mkop(CALL, rty), rty, f, NULL);
+ if (isptr(ty) || p->type->size > ty->size)
+ p = cast(p, ty);
+ }
+ return p;
+}
+Tree vcall(Symbol func, Type ty, ...) {
+ va_list ap;
+ Tree args = NULL, e, f = pointer(idtree(func)), r = NULL;
+
+ assert(isfunc(func->type));
+ if (ty == NULL)
+ ty = freturn(func->type);
+ va_start(ap, ty);
+ while ((e = va_arg(ap, Tree)) != NULL) {
+ if (hascall(e))
+ r = r == NULL ? e : tree(RIGHT, voidtype, r, e);
+ args = tree(mkop(ARG, e->type), e->type, e, args);
+ }
+ va_end(ap);
+ if (r != NULL)
+ args = tree(RIGHT, voidtype, r, args);
+ return calltree(f, ty, args, NULL);
+}
+int iscallb(Tree e) {
+ return e->op == RIGHT && e->kids[0] && e->kids[1]
+ && e->kids[0]->op == CALL+B
+ && e->kids[1]->op == INDIR+B
+ && isaddrop(e->kids[1]->kids[0]->op)
+ && e->kids[1]->kids[0]->u.sym->temporary;
+}
+
+static Tree addtree(int op, Tree l, Tree r) {
+ Type ty = inttype;
+
+ if (isarith(l->type) && isarith(r->type)) {
+ ty = binary(l->type, r->type);
+ l = cast(l, ty);
+ r = cast(r, ty);
+ } else if (isptr(l->type) && isint(r->type))
+ return addtree(ADD, r, l);
+ else if ( isptr(r->type) && isint(l->type)
+ && !isfunc(r->type->type))
+ {
+ long n;
+ ty = unqual(r->type);
+ n = unqual(ty->type)->size;
+ if (n == 0)
+ error("unknown size for type `%t'\n", ty->type);
+ l = cast(l, promote(l->type));
+ if (n > 1)
+ l = multree(MUL, cnsttree(signedptr, n), l);
+ if (YYcheck && !isaddrop(r->op)) /* omit */
+ return nullcall(ty, YYcheck, r, l); /* omit */
+ return simplify(ADD, ty, l, r);
+ }
+
+ else
+ typeerror(op, l, r);
+ return simplify(op, ty, l, r);
+}
+
+Tree cnsttree(Type ty, ...) {
+ Tree p = tree(mkop(CNST,ty), ty, NULL, NULL);
+ va_list ap;
+
+ va_start(ap, ty);
+ switch (ty->op) {
+ case INT: p->u.v.i = va_arg(ap, long); break;
+ case UNSIGNED:p->u.v.u = va_arg(ap, unsigned long)&ones(8*ty->size); break;
+ case FLOAT: p->u.v.d = va_arg(ap, long double); break;
+ case POINTER: p->u.v.p = va_arg(ap, void *); break;
+ default: assert(0);
+ }
+ va_end(ap);
+ return p;
+}
+
+Tree consttree(unsigned n, Type ty) {
+ if (isarray(ty))
+ ty = atop(ty);
+ else assert(isint(ty));
+ return cnsttree(ty, (unsigned long)n);
+}
+static Tree cmptree(int op, Tree l, Tree r) {
+ Type ty;
+
+ if (isarith(l->type) && isarith(r->type)) {
+ ty = binary(l->type, r->type);
+ l = cast(l, ty);
+ r = cast(r, ty);
+ } else if (compatible(l->type, r->type)) {
+ ty = unsignedptr;
+ l = cast(l, ty);
+ r = cast(r, ty);
+ } else {
+ ty = unsignedtype;
+ typeerror(op, l, r);
+ }
+ return simplify(mkop(op,ty), inttype, l, r);
+}
+static int compatible(Type ty1, Type ty2) {
+ return isptr(ty1) && !isfunc(ty1->type)
+ && isptr(ty2) && !isfunc(ty2->type)
+ && eqtype(unqual(ty1->type), unqual(ty2->type), 0);
+}
+static int isnullptr(Tree e) {
+ Type ty = unqual(e->type);
+
+ return generic(e->op) == CNST
+ && (ty->op == INT && e->u.v.i == 0
+ || ty->op == UNSIGNED && e->u.v.u == 0
+ || isvoidptr(ty) && e->u.v.p == NULL);
+}
+Tree eqtree(int op, Tree l, Tree r) {
+ Type xty = l->type, yty = r->type;
+
+ if (isptr(xty) && isnullptr(r)
+ || isptr(xty) && !isfunc(xty->type) && isvoidptr(yty)
+ || (isptr(xty) && isptr(yty)
+ && eqtype(unqual(xty->type), unqual(yty->type), 1))) {
+ Type ty = unsignedptr;
+ l = cast(l, ty);
+ r = cast(r, ty);
+ return simplify(mkop(op,ty), inttype, l, r);
+ }
+ if (isptr(yty) && isnullptr(l)
+ || isptr(yty) && !isfunc(yty->type) && isvoidptr(xty))
+ return eqtree(op, r, l);
+ return cmptree(op, l, r);
+}
+
+Type assign(Type xty, Tree e) {
+ Type yty = unqual(e->type);
+
+ xty = unqual(xty);
+ if (isenum(xty))
+ xty = xty->type;
+ if (xty->size == 0 || yty->size == 0)
+ return NULL;
+ if ( isarith(xty) && isarith(yty)
+ || isstruct(xty) && xty == yty)
+ return xty;
+ if (isptr(xty) && isnullptr(e))
+ return xty;
+ if ((isvoidptr(xty) && isptr(yty)
+ || isptr(xty) && isvoidptr(yty))
+ && ( (isconst(xty->type) || !isconst(yty->type))
+ && (isvolatile(xty->type) || !isvolatile(yty->type))))
+ return xty;
+
+ if ((isptr(xty) && isptr(yty)
+ && eqtype(unqual(xty->type), unqual(yty->type), 1))
+ && ( (isconst(xty->type) || !isconst(yty->type))
+ && (isvolatile(xty->type) || !isvolatile(yty->type))))
+ return xty;
+ if (isptr(xty) && isptr(yty)
+ && ( (isconst(xty->type) || !isconst(yty->type))
+ && (isvolatile(xty->type) || !isvolatile(yty->type)))) {
+ Type lty = unqual(xty->type), rty = unqual(yty->type);
+ if (isenum(lty) && rty == inttype
+ || isenum(rty) && lty == inttype) {
+ if (Aflag >= 1)
+ warning("assignment between `%t' and `%t' is compiler-dependent\n",
+ xty, yty);
+ return xty;
+ }
+ }
+ return NULL;
+}
+Tree asgntree(int op, Tree l, Tree r) {
+ Type aty, ty;
+
+ r = pointer(r);
+ ty = assign(l->type, r);
+ if (ty)
+ r = cast(r, ty);
+ else {
+ typeerror(ASGN, l, r);
+ if (r->type == voidtype)
+ r = retype(r, inttype);
+ ty = r->type;
+ }
+ if (l->op != FIELD)
+ l = lvalue(l);
+ aty = l->type;
+ if (isptr(aty))
+ aty = unqual(aty)->type;
+ if ( isconst(aty)
+ || isstruct(aty) && unqual(aty)->u.sym->u.s.cfields)
+ if (isaddrop(l->op)
+ && !l->u.sym->computed && !l->u.sym->generated)
+ error("assignment to const identifier `%s'\n",
+ l->u.sym->name);
+ else
+ error("assignment to const location\n");
+ if (l->op == FIELD) {
+ long n = 8*l->u.field->type->size - fieldsize(l->u.field);
+ if (n > 0 && isunsigned(l->u.field->type))
+ r = bittree(BAND, r,
+ cnsttree(r->type, (unsigned long)fieldmask(l->u.field)));
+ else if (n > 0) {
+ if (r->op == CNST+I) {
+ n = r->u.v.i;
+ if (n&(1<<(fieldsize(l->u.field)-1)))
+ n |= ~0UL<<fieldsize(l->u.field);
+ r = cnsttree(r->type, n);
+ } else
+ r = shtree(RSH,
+ shtree(LSH, r, cnsttree(inttype, n)),
+ cnsttree(inttype, n));
+ }
+ }
+ if (isstruct(ty) && isaddrop(l->op) && iscallb(r))
+ return tree(RIGHT, ty,
+ tree(CALL+B, ty, r->kids[0]->kids[0], l),
+ idtree(l->u.sym));
+ return tree(mkop(op,ty), ty, l, r);
+}
+Tree condtree(Tree e, Tree l, Tree r) {
+ Symbol t1;
+ Type ty, xty = l->type, yty = r->type;
+ Tree p;
+
+ if (isarith(xty) && isarith(yty))
+ ty = binary(xty, yty);
+ else if (eqtype(xty, yty, 1))
+ ty = unqual(xty);
+ else if (isptr(xty) && isnullptr(r))
+ ty = xty;
+ else if (isnullptr(l) && isptr(yty))
+ ty = yty;
+ else if (isptr(xty) && !isfunc(xty->type) && isvoidptr(yty)
+ || isptr(yty) && !isfunc(yty->type) && isvoidptr(xty))
+ ty = voidptype;
+ else if ((isptr(xty) && isptr(yty)
+ && eqtype(unqual(xty->type), unqual(yty->type), 1)))
+ ty = xty;
+ else {
+ typeerror(COND, l, r);
+ return consttree(0, inttype);
+ }
+ if (isptr(ty)) {
+ ty = unqual(unqual(ty)->type);
+ if (isptr(xty) && isconst(unqual(xty)->type)
+ || isptr(yty) && isconst(unqual(yty)->type))
+ ty = qual(CONST, ty);
+ if (isptr(xty) && isvolatile(unqual(xty)->type)
+ || isptr(yty) && isvolatile(unqual(yty)->type))
+ ty = qual(VOLATILE, ty);
+ ty = ptr(ty);
+ }
+ switch (e->op) {
+ case CNST+I: return cast(e->u.v.i != 0 ? l : r, ty);
+ case CNST+U: return cast(e->u.v.u != 0 ? l : r, ty);
+ case CNST+P: return cast(e->u.v.p != 0 ? l : r, ty);
+ case CNST+F: return cast(e->u.v.d != 0.0 ? l : r, ty);
+ }
+ if (ty != voidtype && ty->size > 0) {
+ t1 = genident(REGISTER, unqual(ty), level);
+ /* t1 = temporary(REGISTER, unqual(ty)); */
+ l = asgn(t1, l);
+ r = asgn(t1, r);
+ } else
+ t1 = NULL;
+ p = tree(COND, ty, cond(e),
+ tree(RIGHT, ty, root(l), root(r)));
+ p->u.sym = t1;
+ return p;
+}
+/* addrof - address of p */
+Tree addrof(Tree p) {
+ Tree q = p;
+
+ for (;;)
+ switch (generic(q->op)) {
+ case RIGHT:
+ assert(q->kids[0] || q->kids[1]);
+ q = q->kids[1] ? q->kids[1] : q->kids[0];
+ continue;
+ case ASGN:
+ q = q->kids[1];
+ continue;
+ case COND: {
+ Symbol t1 = q->u.sym;
+ q->u.sym = 0;
+ q = idtree(t1);
+ /* fall thru */
+ }
+ case INDIR:
+ if (p == q)
+ return q->kids[0];
+ q = q->kids[0];
+ return tree(RIGHT, q->type, root(p), q);
+ default:
+ error("addressable object required\n");
+ return value(p);
+ }
+}
+
+/* andtree - construct tree for l [&& ||] r */
+static Tree andtree(int op, Tree l, Tree r) {
+ if (!isscalar(l->type) || !isscalar(r->type))
+ typeerror(op, l, r);
+ return simplify(op, inttype, cond(l), cond(r));
+}
+
+/* asgn - generate tree for assignment of expr e to symbol p sans qualifiers */
+Tree asgn(Symbol p, Tree e) {
+ if (isarray(p->type))
+ e = tree(ASGN+B, p->type, idtree(p),
+ tree(INDIR+B, e->type, e, NULL));
+ else {
+ Type ty = p->type;
+ p->type = unqual(p->type);
+ if (isstruct(p->type) && p->type->u.sym->u.s.cfields) {
+ p->type->u.sym->u.s.cfields = 0;
+ e = asgntree(ASGN, idtree(p), e);
+ p->type->u.sym->u.s.cfields = 1;
+ } else
+ e = asgntree(ASGN, idtree(p), e);
+ p->type = ty;
+ }
+ return e;
+}
+
+/* bittree - construct tree for l [& | ^ %] r */
+Tree bittree(int op, Tree l, Tree r) {
+ Type ty = inttype;
+
+ if (isint(l->type) && isint(r->type)) {
+ ty = binary(l->type, r->type);
+ l = cast(l, ty);
+ r = cast(r, ty);
+ } else
+ typeerror(op, l, r);
+ return simplify(op, ty, l, r);
+}
+
+/* multree - construct tree for l [* /] r */
+static Tree multree(int op, Tree l, Tree r) {
+ Type ty = inttype;
+
+ if (isarith(l->type) && isarith(r->type)) {
+ ty = binary(l->type, r->type);
+ l = cast(l, ty);
+ r = cast(r, ty);
+ } else
+ typeerror(op, l, r);
+ return simplify(op, ty, l, r);
+}
+
+/* shtree - construct tree for l [>> <<] r */
+Tree shtree(int op, Tree l, Tree r) {
+ Type ty = inttype;
+
+ if (isint(l->type) && isint(r->type)) {
+ ty = promote(l->type);
+ l = cast(l, ty);
+ r = cast(r, inttype);
+ } else
+ typeerror(op, l, r);
+ return simplify(op, ty, l, r);
+}
+
+/* subtree - construct tree for l - r */
+static Tree subtree(int op, Tree l, Tree r) {
+ long n;
+ Type ty = inttype;
+
+ if (isarith(l->type) && isarith(r->type)) {
+ ty = binary(l->type, r->type);
+ l = cast(l, ty);
+ r = cast(r, ty);
+ } else if (isptr(l->type) && !isfunc(l->type->type) && isint(r->type)) {
+ ty = unqual(l->type);
+ n = unqual(ty->type)->size;
+ if (n == 0)
+ error("unknown size for type `%t'\n", ty->type);
+ r = cast(r, promote(r->type));
+ if (n > 1)
+ r = multree(MUL, cnsttree(signedptr, n), r);
+ if (isunsigned(r->type))
+ r = cast(r, unsignedptr);
+ else
+ r = cast(r, signedptr);
+ return simplify(SUB+P, ty, l, r);
+ } else if (compatible(l->type, r->type)) {
+ ty = unqual(l->type);
+ n = unqual(ty->type)->size;
+ if (n == 0)
+ error("unknown size for type `%t'\n", ty->type);
+ l = simplify(SUB+U, unsignedptr,
+ cast(l, unsignedptr), cast(r, unsignedptr));
+ return simplify(DIV+I, longtype,
+ cast(l, longtype), cnsttree(longtype, n));
+ } else
+ typeerror(op, l, r);
+ return simplify(op, ty, l, r);
+}
+
+/* typeerror - issue "operands of op have illegal types `l' and `r'" */
+void typeerror(int op, Tree l, Tree r) {
+ int i;
+ static struct { int op; char *name; } ops[] = {
+ ASGN, "=", INDIR, "*", NEG, "-",
+ ADD, "+", SUB, "-", LSH, "<<",
+ MOD, "%", RSH, ">>", BAND, "&",
+ BCOM, "~", BOR, "|", BXOR, "^",
+ DIV, "/", MUL, "*", EQ, "==",
+ GE, ">=", GT, ">", LE, "<=",
+ LT, "<", NE, "!=", AND, "&&",
+ NOT, "!", OR, "||", COND, "?:",
+ 0, 0
+ };
+
+ op = generic(op);
+ for (i = 0; ops[i].op; i++)
+ if (op == ops[i].op)
+ break;
+ assert(ops[i].name);
+ if (r)
+ error("operands of %s have illegal types `%t' and `%t'\n",
+ ops[i].name, l->type, r->type);
+ else
+ error("operand of unary %s has illegal type `%t'\n", ops[i].name,
+ l->type);
+}
diff --git a/lcc/src/error.c b/lcc/src/error.c
new file mode 100755
index 0000000..56d164c
--- /dev/null
+++ b/lcc/src/error.c
@@ -0,0 +1,137 @@
+#include "c.h"
+
+
+static void printtoken(void);
+int errcnt = 0;
+int errlimit = 20;
+char kind[] = {
+#define xx(a,b,c,d,e,f,g) f,
+#define yy(a,b,c,d,e,f,g) f,
+#include "token.h"
+};
+int wflag; /* != 0 to suppress warning messages */
+
+void test(int tok, char set[]) {
+ if (t == tok)
+ t = gettok();
+ else {
+ expect(tok);
+ skipto(tok, set);
+ if (t == tok)
+ t = gettok();
+ }
+}
+void expect(int tok) {
+ if (t == tok)
+ t = gettok();
+ else {
+ error("syntax error; found");
+ printtoken();
+ fprint(stderr, " expecting `%k'\n", tok);
+ }
+}
+void error(const char *fmt, ...) {
+ va_list ap;
+
+ if (errcnt++ >= errlimit) {
+ errcnt = -1;
+ error("too many errors\n");
+ exit(1);
+ }
+ va_start(ap, fmt);
+ if (firstfile != file && firstfile && *firstfile)
+ fprint(stderr, "%s: ", firstfile);
+ fprint(stderr, "%w: ", &src);
+ vfprint(stderr, NULL, fmt, ap);
+ va_end(ap);
+}
+
+void skipto(int tok, char set[]) {
+ int n;
+ char *s;
+
+ assert(set);
+ for (n = 0; t != EOI && t != tok; t = gettok()) {
+ for (s = set; *s && kind[t] != *s; s++)
+ ;
+ if (kind[t] == *s)
+ break;
+ if (n++ == 0)
+ error("skipping");
+ if (n <= 8)
+ printtoken();
+ else if (n == 9)
+ fprint(stderr, " ...");
+ }
+ if (n > 8) {
+ fprint(stderr, " up to");
+ printtoken();
+ }
+ if (n > 0)
+ fprint(stderr, "\n");
+}
+/* fatal - issue fatal error message and exit */
+int fatal(const char *name, const char *fmt, int n) {
+ print("\n");
+ errcnt = -1;
+ error("compiler error in %s--", name);
+ fprint(stderr, fmt, n);
+ exit(EXIT_FAILURE);
+ return 0;
+}
+
+/* printtoken - print current token preceeded by a space */
+static void printtoken(void) {
+ switch (t) {
+ case ID: fprint(stderr, " `%s'", token); break;
+ case ICON:
+ fprint(stderr, " `%s'", vtoa(tsym->type, tsym->u.c.v));
+ break;
+ case SCON: {
+ int i, n;
+ if (ischar(tsym->type->type)) {
+ char *s = tsym->u.c.v.p;
+ n = tsym->type->size;
+ fprint(stderr, " \"");
+ for (i = 0; i < 20 && i < n && *s; s++, i++)
+ if (*s < ' ' || *s >= 0177)
+ fprint(stderr, "\\%o", *s);
+ else
+ fprint(stderr, "%c", *s);
+ } else { /* wchar_t string */
+ unsigned int *s = tsym->u.c.v.p;
+ assert(tsym->type->type->size == widechar->size);
+ n = tsym->type->size/widechar->size;
+ fprint(stderr, " L\"");
+ for (i = 0; i < 20 && i < n && *s; s++, i++)
+ if (*s < ' ' || *s >= 0177)
+ fprint(stderr, "\\x%x", *s);
+ else
+ fprint(stderr, "%c", *s);
+ }
+ if (i < n)
+ fprint(stderr, " ...");
+ else
+ fprint(stderr, "\"");
+ break;
+ }
+ case FCON:
+ fprint(stderr, " `%S'", token, (char*)cp - token);
+ break;
+ case '`': case '\'': fprint(stderr, " \"%k\"", t); break;
+ default: fprint(stderr, " `%k'", t);
+ }
+}
+
+/* warning - issue warning error message */
+void warning(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (wflag == 0) {
+ errcnt--;
+ error("warning: ");
+ vfprint(stderr, NULL, fmt, ap);
+ }
+ va_end(ap);
+}
diff --git a/lcc/src/event.c b/lcc/src/event.c
new file mode 100755
index 0000000..12f409f
--- /dev/null
+++ b/lcc/src/event.c
@@ -0,0 +1,28 @@
+#include "c.h"
+
+
+struct entry {
+ Apply func;
+ void *cl;
+};
+
+Events events;
+void attach(Apply func, void *cl, List *list) {
+ struct entry *p;
+
+ NEW(p, PERM);
+ p->func = func;
+ p->cl = cl;
+ *list = append(p, *list);
+}
+void apply(List event, void *arg1, void *arg2) {
+ if (event) {
+ List lp = event;
+ do {
+ struct entry *p = lp->x;
+ (*p->func)(p->cl, arg1, arg2);
+ lp = lp->link;
+ } while (lp != event);
+ }
+}
+
diff --git a/lcc/src/expr.c b/lcc/src/expr.c
new file mode 100755
index 0000000..30b79cc
--- /dev/null
+++ b/lcc/src/expr.c
@@ -0,0 +1,709 @@
+#include "c.h"
+
+
+static char prec[] = {
+#define xx(a,b,c,d,e,f,g) c,
+#define yy(a,b,c,d,e,f,g) c,
+#include "token.h"
+};
+static int oper[] = {
+#define xx(a,b,c,d,e,f,g) d,
+#define yy(a,b,c,d,e,f,g) d,
+#include "token.h"
+};
+float refinc = 1.0;
+static Tree expr2(void);
+static Tree expr3(int);
+static Tree nullcheck(Tree);
+static Tree postfix(Tree);
+static Tree unary(void);
+static Tree primary(void);
+static Type super(Type ty);
+
+static Type super(Type ty) {
+ switch (ty->op) {
+ case INT:
+ if (ty->size < inttype->size)
+ return inttype;
+ break;
+ case UNSIGNED:
+ if (ty->size < unsignedtype->size)
+ return unsignedtype;
+ break;
+ case POINTER:
+ return unsignedptr;
+ }
+ return ty;
+}
+Tree expr(int tok) {
+ static char stop[] = { IF, ID, '}', 0 };
+ Tree p = expr1(0);
+
+ while (t == ',') {
+ Tree q;
+ t = gettok();
+ q = pointer(expr1(0));
+ p = tree(RIGHT, q->type, root(value(p)), q);
+ }
+ if (tok)
+ test(tok, stop);
+ return p;
+}
+Tree expr0(int tok) {
+ return root(expr(tok));
+}
+Tree expr1(int tok) {
+ static char stop[] = { IF, ID, 0 };
+ Tree p = expr2();
+
+ if (t == '='
+ || (prec[t] >= 6 && prec[t] <= 8)
+ || (prec[t] >= 11 && prec[t] <= 13)) {
+ int op = t;
+ t = gettok();
+ if (oper[op] == ASGN)
+ p = asgntree(ASGN, p, value(expr1(0)));
+ else
+ {
+ expect('=');
+ p = incr(op, p, expr1(0));
+ }
+ }
+ if (tok)
+ test(tok, stop);
+ return p;
+}
+Tree incr(int op, Tree v, Tree e) {
+ return asgntree(ASGN, v, (*optree[op])(oper[op], v, e));
+}
+static Tree expr2(void) {
+ Tree p = expr3(4);
+
+ if (t == '?') {
+ Tree l, r;
+ Coordinate pts[2];
+ if (Aflag > 1 && isfunc(p->type))
+ warning("%s used in a conditional expression\n",
+ funcname(p));
+ p = pointer(p);
+ t = gettok();
+ pts[0] = src;
+ l = pointer(expr(':'));
+ pts[1] = src;
+ r = pointer(expr2());
+ if (events.points)
+ {
+ apply(events.points, &pts[0], &l);
+ apply(events.points, &pts[1], &r);
+ }
+ p = condtree(p, l, r);
+ }
+ return p;
+}
+Tree value(Tree p) {
+ int op = generic(rightkid(p)->op);
+
+ if (p->type != voidtype
+ && (op==AND || op==OR || op==NOT || op==EQ || op==NE
+ || op== LE || op==LT || op== GE || op==GT))
+ p = condtree(p, consttree(1, inttype),
+ consttree(0, inttype));
+ return p;
+}
+static Tree expr3(int k) {
+ int k1;
+ Tree p = unary();
+
+ for (k1 = prec[t]; k1 >= k; k1--)
+ while (prec[t] == k1 && *cp != '=') {
+ Tree r;
+ Coordinate pt;
+ int op = t;
+ t = gettok();
+ pt = src;
+ p = pointer(p);
+ if (op == ANDAND || op == OROR) {
+ r = pointer(expr3(k1));
+ if (events.points)
+ apply(events.points, &pt, &r);
+ } else
+ r = pointer(expr3(k1 + 1));
+ p = (*optree[op])(oper[op], p, r);
+ }
+ return p;
+}
+static Tree unary(void) {
+ Tree p;
+
+ switch (t) {
+ case '*': t = gettok(); p = unary(); p = pointer(p);
+ if (isptr(p->type)
+ && (isfunc(p->type->type) || isarray(p->type->type)))
+ p = retype(p, p->type->type);
+ else {
+ if (YYnull)
+ p = nullcheck(p);
+ p = rvalue(p);
+ } break;
+ case '&': t = gettok(); p = unary(); if (isarray(p->type) || isfunc(p->type))
+ p = retype(p, ptr(p->type));
+ else
+ p = lvalue(p);
+ if (isaddrop(p->op) && p->u.sym->sclass == REGISTER)
+ error("invalid operand of unary &; `%s' is declared register\n", p->u.sym->name);
+
+ else if (isaddrop(p->op))
+ p->u.sym->addressed = 1;
+ break;
+ case '+': t = gettok(); p = unary(); p = pointer(p);
+ if (isarith(p->type))
+ p = cast(p, promote(p->type));
+ else
+ typeerror(ADD, p, NULL); break;
+ case '-': t = gettok(); p = unary(); p = pointer(p);
+ if (isarith(p->type)) {
+ Type ty = promote(p->type);
+ p = cast(p, ty);
+ if (isunsigned(ty)) {
+ warning("unsigned operand of unary -\n");
+ p = simplify(ADD, ty, simplify(BCOM, ty, p, NULL), cnsttree(ty, 1UL));
+ } else
+ p = simplify(NEG, ty, p, NULL);
+ } else
+ typeerror(SUB, p, NULL); break;
+ case '~': t = gettok(); p = unary(); p = pointer(p);
+ if (isint(p->type)) {
+ Type ty = promote(p->type);
+ p = simplify(BCOM, ty, cast(p, ty), NULL);
+ } else
+ typeerror(BCOM, p, NULL); break;
+ case '!': t = gettok(); p = unary(); p = pointer(p);
+ if (isscalar(p->type))
+ p = simplify(NOT, inttype, cond(p), NULL);
+ else
+ typeerror(NOT, p, NULL); break;
+ case INCR: t = gettok(); p = unary(); p = incr(INCR, pointer(p), consttree(1, inttype)); break;
+ case DECR: t = gettok(); p = unary(); p = incr(DECR, pointer(p), consttree(1, inttype)); break;
+ case TYPECODE: case SIZEOF: { int op = t;
+ Type ty;
+ p = NULL;
+ t = gettok();
+ if (t == '(') {
+ t = gettok();
+ if (istypename(t, tsym)) {
+ ty = typename();
+ expect(')');
+ } else {
+ p = postfix(expr(')'));
+ ty = p->type;
+ }
+ } else {
+ p = unary();
+ ty = p->type;
+ }
+ assert(ty);
+ if (op == TYPECODE)
+ p = cnsttree(inttype, (long)ty->op);
+ else {
+ if (isfunc(ty) || ty->size == 0)
+ error("invalid type argument `%t' to `sizeof'\n", ty);
+ else if (p && rightkid(p)->op == FIELD)
+ error("`sizeof' applied to a bit field\n");
+ p = cnsttree(unsignedlong, (unsigned long)ty->size);
+ } } break;
+ case '(':
+ t = gettok();
+ if (istypename(t, tsym)) {
+ Type ty, ty1 = typename(), pty;
+ expect(')');
+ ty = unqual(ty1);
+ if (isenum(ty)) {
+ Type ty2 = ty->type;
+ if (isconst(ty1))
+ ty2 = qual(CONST, ty2);
+ if (isvolatile(ty1))
+ ty2 = qual(VOLATILE, ty2);
+ ty1 = ty2;
+ ty = ty->type;
+ }
+ p = pointer(unary());
+ pty = p->type;
+ if (isenum(pty))
+ pty = pty->type;
+ if (isarith(pty) && isarith(ty)
+ || isptr(pty) && isptr(ty)) {
+ explicitCast++;
+ p = cast(p, ty);
+ explicitCast--;
+ } else if (isptr(pty) && isint(ty)
+ || isint(pty) && isptr(ty)) {
+ if (Aflag >= 1 && ty->size < pty->size)
+ warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, ty);
+
+ p = cast(p, ty);
+ } else if (ty != voidtype) {
+ error("cast from `%t' to `%t' is illegal\n",
+ p->type, ty1);
+ ty1 = inttype;
+ }
+ if (generic(p->op) == INDIR || ty->size == 0)
+ p = tree(RIGHT, ty1, NULL, p);
+ else
+ p = retype(p, ty1);
+ } else
+ p = postfix(expr(')'));
+ break;
+ default:
+ p = postfix(primary());
+ }
+ return p;
+}
+
+static Tree postfix(Tree p) {
+ for (;;)
+ switch (t) {
+ case INCR: p = tree(RIGHT, p->type,
+ tree(RIGHT, p->type,
+ p,
+ incr(t, p, consttree(1, inttype))),
+ p);
+ t = gettok(); break;
+ case DECR: p = tree(RIGHT, p->type,
+ tree(RIGHT, p->type,
+ p,
+ incr(t, p, consttree(1, inttype))),
+ p);
+ t = gettok(); break;
+ case '[': {
+ Tree q;
+ t = gettok();
+ q = expr(']');
+ if (YYnull)
+ if (isptr(p->type))
+ p = nullcheck(p);
+ else if (isptr(q->type))
+ q = nullcheck(q);
+ p = (*optree['+'])(ADD, pointer(p), pointer(q));
+ if (isptr(p->type) && isarray(p->type->type))
+ p = retype(p, p->type->type);
+ else
+ p = rvalue(p);
+ } break;
+ case '(': {
+ Type ty;
+ Coordinate pt;
+ p = pointer(p);
+ if (isptr(p->type) && isfunc(p->type->type))
+ ty = p->type->type;
+ else {
+ error("found `%t' expected a function\n", p->type);
+ ty = func(voidtype, NULL, 1);
+ p = retype(p, ptr(ty));
+ }
+ pt = src;
+ t = gettok();
+ p = call(p, ty, pt);
+ } break;
+ case '.': t = gettok();
+ if (t == ID) {
+ if (isstruct(p->type)) {
+ Tree q = addrof(p);
+ p = field(q, token);
+ q = rightkid(q);
+ if (isaddrop(q->op) && q->u.sym->temporary)
+ p = tree(RIGHT, p->type, p, NULL);
+ } else
+ error("left operand of . has incompatible type `%t'\n",
+ p->type);
+ t = gettok();
+ } else
+ error("field name expected\n"); break;
+ case DEREF: t = gettok();
+ p = pointer(p);
+ if (t == ID) {
+ if (isptr(p->type) && isstruct(p->type->type)) {
+ if (YYnull)
+ p = nullcheck(p);
+ p = field(p, token);
+ } else
+ error("left operand of -> has incompatible type `%t'\n", p->type);
+
+ t = gettok();
+ } else
+ error("field name expected\n"); break;
+ default:
+ return p;
+ }
+}
+static Tree primary(void) {
+ Tree p;
+
+ assert(t != '(');
+ switch (t) {
+ case ICON:
+ case FCON: p = tree(mkop(CNST,tsym->type), tsym->type, NULL, NULL);
+ p->u.v = tsym->u.c.v;
+ break;
+ case SCON: if (ischar(tsym->type->type))
+ tsym->u.c.v.p = stringn(tsym->u.c.v.p, tsym->type->size);
+ else
+ tsym->u.c.v.p = memcpy(allocate(tsym->type->size, PERM), tsym->u.c.v.p, tsym->type->size);
+ tsym = constant(tsym->type, tsym->u.c.v);
+ if (tsym->u.c.loc == NULL)
+ tsym->u.c.loc = genident(STATIC, tsym->type, GLOBAL);
+ p = idtree(tsym->u.c.loc); break;
+ case ID: if (tsym == NULL)
+ {
+ Symbol p = install(token, &identifiers, level, FUNC);
+ p->src = src;
+ if (getchr() == '(') {
+ Symbol q = lookup(token, externals);
+ p->type = func(inttype, NULL, 1);
+ p->sclass = EXTERN;
+ if (Aflag >= 1)
+ warning("missing prototype\n");
+ if (q && !eqtype(q->type, p->type, 1))
+ warning("implicit declaration of `%s' does not match previous declaration at %w\n", q->name, &q->src);
+
+ if (q == NULL) {
+ q = install(p->name, &externals, GLOBAL, PERM);
+ q->type = p->type;
+ q->sclass = EXTERN;
+ q->src = src;
+ (*IR->defsymbol)(q);
+ }
+ p->u.alias = q;
+ } else {
+ error("undeclared identifier `%s'\n", p->name);
+ p->sclass = AUTO;
+ p->type = inttype;
+ if (p->scope == GLOBAL)
+ (*IR->defsymbol)(p);
+ else
+ addlocal(p);
+ }
+ t = gettok();
+ if (xref)
+ use(p, src);
+ return idtree(p);
+ }
+ if (xref)
+ use(tsym, src);
+ if (tsym->sclass == ENUM)
+ p = consttree(tsym->u.value, inttype);
+ else {
+ if (tsym->sclass == TYPEDEF)
+ error("illegal use of type name `%s'\n", tsym->name);
+ p = idtree(tsym);
+ } break;
+ case FIRSTARG:
+ if (level > PARAM && cfunc && cfunc->u.f.callee[0])
+ p = idtree(cfunc->u.f.callee[0]);
+ else {
+ error("illegal use of `%k'\n", FIRSTARG);
+ p = cnsttree(inttype, 0L);
+ }
+ break;
+ default:
+ error("illegal expression\n");
+ p = cnsttree(inttype, 0L);
+ }
+ t = gettok();
+ return p;
+}
+Tree idtree(Symbol p) {
+ int op;
+ Tree e;
+ Type ty = p->type ? unqual(p->type) : voidptype;
+
+ if (p->scope == GLOBAL || p->sclass == STATIC)
+ op = ADDRG;
+ else if (p->scope == PARAM) {
+ op = ADDRF;
+ if (isstruct(p->type) && !IR->wants_argb)
+ {
+ e = tree(mkop(op,voidptype), ptr(ptr(p->type)), NULL, NULL);
+ e->u.sym = p;
+ return rvalue(rvalue(e));
+ }
+ } else if (p->sclass == EXTERN) {
+ assert(p->u.alias);
+ p = p->u.alias;
+ op = ADDRG;
+ } else
+ op = ADDRL;
+ p->ref += refinc;
+ if (isarray(ty))
+ e = tree(mkop(op,voidptype), p->type, NULL, NULL);
+ else if (isfunc(ty))
+ e = tree(mkop(op,funcptype), p->type, NULL, NULL);
+ else
+ e = tree(mkop(op,voidptype), ptr(p->type), NULL, NULL);
+ e->u.sym = p;
+ if (isptr(e->type))
+ e = rvalue(e);
+ return e;
+}
+
+Tree rvalue(Tree p) {
+ Type ty = deref(p->type);
+
+ ty = unqual(ty);
+ return tree(mkop(INDIR,ty), ty, p, NULL);
+}
+Tree lvalue(Tree p) {
+ if (generic(p->op) != INDIR) {
+ error("lvalue required\n");
+ return value(p);
+ } else if (unqual(p->type) == voidtype)
+ warning("`%t' used as an lvalue\n", p->type);
+ return p->kids[0];
+}
+Tree retype(Tree p, Type ty) {
+ Tree q;
+
+ if (p->type == ty)
+ return p;
+ q = tree(p->op, ty, p->kids[0], p->kids[1]);
+ q->node = p->node;
+ q->u = p->u;
+ return q;
+}
+Tree rightkid(Tree p) {
+ while (p && p->op == RIGHT)
+ if (p->kids[1])
+ p = p->kids[1];
+ else if (p->kids[0])
+ p = p->kids[0];
+ else
+ assert(0);
+ assert(p);
+ return p;
+}
+int hascall(Tree p) {
+ if (p == 0)
+ return 0;
+ if (generic(p->op) == CALL || (IR->mulops_calls &&
+ (p->op == DIV+I || p->op == MOD+I || p->op == MUL+I
+ || p->op == DIV+U || p->op == MOD+U || p->op == MUL+U)))
+ return 1;
+ return hascall(p->kids[0]) || hascall(p->kids[1]);
+}
+Type binary(Type xty, Type yty) {
+#define xx(t) if (xty == t || yty == t) return t
+ xx(longdouble);
+ xx(doubletype);
+ xx(floattype);
+ xx(unsignedlonglong);
+ xx(longlong);
+ xx(unsignedlong);
+ if (xty == longtype && yty == unsignedtype
+ || xty == unsignedtype && yty == longtype)
+ if (longtype->size > unsignedtype->size)
+ return longtype;
+ else
+ return unsignedlong;
+ xx(longtype);
+ xx(unsignedtype);
+ return inttype;
+#undef xx
+}
+Tree pointer(Tree p) {
+ if (isarray(p->type))
+ /* assert(p->op != RIGHT || p->u.sym == NULL), */
+ p = retype(p, atop(p->type));
+ else if (isfunc(p->type))
+ p = retype(p, ptr(p->type));
+ return p;
+}
+Tree cond(Tree p) {
+ int op = generic(rightkid(p)->op);
+
+ if (op == AND || op == OR || op == NOT
+ || op == EQ || op == NE
+ || op == LE || op == LT || op == GE || op == GT)
+ return p;
+ p = pointer(p);
+ return (*optree[NEQ])(NE, p, consttree(0, inttype));
+}
+Tree cast(Tree p, Type type) {
+ Type src, dst;
+
+ p = value(p);
+ if (p->type == type)
+ return p;
+ dst = unqual(type);
+ src = unqual(p->type);
+ if (src->op != dst->op || src->size != dst->size) {
+ switch (src->op) {
+ case INT:
+ if (src->size < inttype->size)
+ p = simplify(CVI, inttype, p, NULL);
+ break;
+ case UNSIGNED:
+ if (src->size < inttype->size)
+ p = simplify(CVU, inttype, p, NULL);
+ else if (src->size < unsignedtype->size)
+ p = simplify(CVU, unsignedtype, p, NULL);
+ break;
+ case ENUM:
+ p = retype(p, inttype);
+ break;
+ case POINTER:
+ if (isint(dst) && src->size > dst->size)
+ warning("conversion from `%t' to `%t' is undefined\n", p->type, type);
+ p = simplify(CVP, super(src), p, NULL);
+ break;
+ case FLOAT:
+ break;
+ default: assert(0);
+ }
+ {
+ src = unqual(p->type);
+ dst = super(dst);
+ if (src->op != dst->op)
+ switch (src->op) {
+ case INT:
+ p = simplify(CVI, dst, p, NULL);
+ break;
+ case UNSIGNED:
+ if (isfloat(dst)) {
+ Type ssrc = signedint(src);
+ Tree two = cnsttree(longdouble, (long double)2.0);
+ p = (*optree['+'])(ADD,
+ (*optree['*'])(MUL,
+ two,
+ simplify(CVU, ssrc,
+ simplify(RSH, src,
+ p, consttree(1, inttype)), NULL)),
+ simplify(CVU, ssrc,
+ simplify(BAND, src,
+ p, consttree(1, unsignedtype)), NULL));
+ } else
+ p = simplify(CVU, dst, p, NULL);
+ break;
+ case FLOAT:
+ if (isunsigned(dst)) {
+ Type sdst = signedint(dst);
+ Tree c = cast(cnsttree(longdouble, (long double)sdst->u.sym->u.limits.max.i + 1), src);
+ p = condtree(
+ simplify(GE, src, p, c),
+ (*optree['+'])(ADD,
+ cast(cast(simplify(SUB, src, p, c), sdst), dst),
+ cast(cnsttree(unsignedlong, (unsigned long)sdst->u.sym->u.limits.max.i + 1), dst)),
+ simplify(CVF, sdst, p, NULL));
+ } else
+ p = simplify(CVF, dst, p, NULL);
+ break;
+ default: assert(0);
+ }
+ dst = unqual(type);
+ }
+ }
+ src = unqual(p->type);
+ switch (src->op) {
+ case INT:
+ if (src->op != dst->op || src->size != dst->size)
+ p = simplify(CVI, dst, p, NULL);
+ break;
+ case UNSIGNED:
+ if (src->op != dst->op || src->size != dst->size)
+ p = simplify(CVU, dst, p, NULL);
+ break;
+ case FLOAT:
+ if (src->op != dst->op || src->size != dst->size)
+ p = simplify(CVF, dst, p, NULL);
+ break;
+ case POINTER:
+ if (src->op != dst->op)
+ p = simplify(CVP, dst, p, NULL);
+ else {
+ if (isfunc(src->type) && !isfunc(dst->type)
+ || !isfunc(src->type) && isfunc(dst->type))
+ warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, type);
+
+ if (src->size != dst->size)
+ p = simplify(CVP, dst, p, NULL);
+ }
+ break;
+ default: assert(0);
+ }
+ return retype(p, type);
+}
+Tree field(Tree p, const char *name) {
+ Field q;
+ Type ty1, ty = p->type;
+
+ if (isptr(ty))
+ ty = deref(ty);
+ ty1 = ty;
+ ty = unqual(ty);
+ if ((q = fieldref(name, ty)) != NULL) {
+ if (isarray(q->type)) {
+ ty = q->type->type;
+ if (isconst(ty1) && !isconst(ty))
+ ty = qual(CONST, ty);
+ if (isvolatile(ty1) && !isvolatile(ty))
+ ty = qual(VOLATILE, ty);
+ ty = array(ty, q->type->size/ty->size, q->type->align);
+ } else {
+ ty = q->type;
+ if (isconst(ty1) && !isconst(ty))
+ ty = qual(CONST, ty);
+ if (isvolatile(ty1) && !isvolatile(ty))
+ ty = qual(VOLATILE, ty);
+ ty = ptr(ty);
+ }
+ if (YYcheck && !isaddrop(p->op) && q->offset > 0) /* omit */
+ p = nullcall(ty, YYcheck, p, consttree(q->offset, inttype)); /* omit */
+ else /* omit */
+ p = simplify(ADD+P, ty, p, consttree(q->offset, inttype));
+
+ if (q->lsb) {
+ p = tree(FIELD, ty->type, rvalue(p), NULL);
+ p->u.field = q;
+ } else if (!isarray(q->type))
+ p = rvalue(p);
+
+ } else {
+ error("unknown field `%s' of `%t'\n", name, ty);
+ p = rvalue(retype(p, ptr(inttype)));
+ }
+ return p;
+}
+/* funcname - return name of function f or a function' */
+char *funcname(Tree f) {
+ if (isaddrop(f->op))
+ return stringf("`%s'", f->u.sym->name);
+ return "a function";
+}
+static Tree nullcheck(Tree p) {
+ if (!needconst && YYnull && isptr(p->type)) {
+ p = value(p);
+ if (strcmp(YYnull->name, "_YYnull") == 0) {
+ Symbol t1 = temporary(REGISTER, voidptype);
+ p = tree(RIGHT, p->type,
+ tree(OR, voidtype,
+ cond(asgn(t1, cast(p, voidptype))),
+ vcall(YYnull, voidtype, (file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno) , NULL)),
+ idtree(t1));
+ }
+
+ else
+ p = nullcall(p->type, YYnull, p, cnsttree(inttype, 0L));
+
+ }
+ return p;
+}
+Tree nullcall(Type pty, Symbol f, Tree p, Tree e) {
+ Type ty;
+
+ if (isarray(pty))
+ return retype(nullcall(atop(pty), f, p, e), pty);
+ ty = unqual(unqual(p->type)->type);
+ return vcall(f, pty,
+ p, e,
+ cnsttree(inttype, (long)ty->size),
+ cnsttree(inttype, (long)ty->align),
+ (file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno) , NULL);
+}
diff --git a/lcc/src/gen.c b/lcc/src/gen.c
new file mode 100755
index 0000000..ab8506a
--- /dev/null
+++ b/lcc/src/gen.c
@@ -0,0 +1,830 @@
+#include "c.h"
+
+
+#define readsreg(p) \
+ (generic((p)->op)==INDIR && (p)->kids[0]->op==VREG+P)
+#define setsrc(d) ((d) && (d)->x.regnode && \
+ (d)->x.regnode->set == src->x.regnode->set && \
+ (d)->x.regnode->mask&src->x.regnode->mask)
+
+#define relink(a, b) ((b)->x.prev = (a), (a)->x.next = (b))
+
+static Symbol askfixedreg(Symbol);
+static Symbol askreg(Symbol, unsigned*);
+static void blkunroll(int, int, int, int, int, int, int[]);
+static void docall(Node);
+static void dumpcover(Node, int, int);
+static void dumpregs(char *, char *, char *);
+static void dumprule(int);
+static void dumptree(Node);
+static unsigned emitasm(Node, int);
+static void genreload(Node, Symbol, int);
+static void genspill(Symbol, Node, Symbol);
+static Symbol getreg(Symbol, unsigned*, Node);
+static int getrule(Node, int);
+static void linearize(Node, Node);
+static int moveself(Node);
+static void prelabel(Node);
+static Node* prune(Node, Node*);
+static void putreg(Symbol);
+static void ralloc(Node);
+static void reduce(Node, int);
+static int reprune(Node*, int, int, Node);
+static int requate(Node);
+static Node reuse(Node, int);
+static void rewrite(Node);
+static Symbol spillee(Symbol, unsigned mask[], Node);
+static void spillr(Symbol, Node);
+static int uses(Node, Regnode);
+
+int offset;
+
+int maxoffset;
+
+int framesize;
+int argoffset;
+
+int maxargoffset;
+
+int dalign, salign;
+int bflag = 0; /* omit */
+int dflag = 0;
+
+int swap;
+
+unsigned (*emitter)(Node, int) = emitasm;
+static char NeedsReg[] = {
+ 0, /* unused */
+ 1, /* CNST */
+ 0, 0, /* ARG ASGN */
+ 1, /* INDIR */
+ 0, 0, 1, 1, /* - - CVF CVI */
+ 1, 0, 1, 1, /* CVP - CVU NEG */
+ 1, /* CALL */
+ 1, /* LOAD */
+ 0, /* RET */
+ 1, 1, 1, /* ADDRG ADDRF ADDRL */
+ 1, 1, 1, 1, 1, /* ADD SUB LSH MOD RSH */
+ 1, 1, 1, 1, /* BAND BCOM BOR BXOR */
+ 1, 1, /* DIV MUL */
+ 0, 0, 0, 0, 0, 0, /* EQ GE GT LE LT NE */
+ 0, 0 /* JUMP LABEL */
+};
+Node head;
+
+unsigned freemask[2];
+unsigned usedmask[2];
+unsigned tmask[2];
+unsigned vmask[2];
+Symbol mkreg(char *fmt, int n, int mask, int set) {
+ Symbol p;
+
+ NEW0(p, PERM);
+ p->name = p->x.name = stringf(fmt, n);
+ NEW0(p->x.regnode, PERM);
+ p->x.regnode->number = n;
+ p->x.regnode->mask = mask<<n;
+ p->x.regnode->set = set;
+ return p;
+}
+Symbol mkwildcard(Symbol *syms) {
+ Symbol p;
+
+ NEW0(p, PERM);
+ p->name = p->x.name = "wildcard";
+ p->x.wildcard = syms;
+ return p;
+}
+void mkauto(Symbol p) {
+ assert(p->sclass == AUTO);
+ offset = roundup(offset + p->type->size, p->type->align);
+ p->x.offset = -offset;
+ p->x.name = stringd(-offset);
+}
+void blockbeg(Env *e) {
+ e->offset = offset;
+ e->freemask[IREG] = freemask[IREG];
+ e->freemask[FREG] = freemask[FREG];
+}
+void blockend(Env *e) {
+ if (offset > maxoffset)
+ maxoffset = offset;
+ offset = e->offset;
+ freemask[IREG] = e->freemask[IREG];
+ freemask[FREG] = e->freemask[FREG];
+}
+int mkactual(int align, int size) {
+ int n = roundup(argoffset, align);
+
+ argoffset = n + size;
+ return n;
+}
+static void docall(Node p) {
+ p->syms[1] = p->syms[0];
+ p->syms[0] = intconst(argoffset);
+ if (argoffset > maxargoffset)
+ maxargoffset = argoffset;
+ argoffset = 0;
+}
+void blkcopy(int dreg, int doff, int sreg, int soff, int size, int tmp[]) {
+ assert(size >= 0);
+ if (size == 0)
+ return;
+ else if (size <= 2)
+ blkunroll(size, dreg, doff, sreg, soff, size, tmp);
+ else if (size == 3) {
+ blkunroll(2, dreg, doff, sreg, soff, 2, tmp);
+ blkunroll(1, dreg, doff+2, sreg, soff+2, 1, tmp);
+ }
+ else if (size <= 16) {
+ blkunroll(4, dreg, doff, sreg, soff, size&~3, tmp);
+ blkcopy(dreg, doff+(size&~3),
+ sreg, soff+(size&~3), size&3, tmp);
+ }
+ else
+ (*IR->x.blkloop)(dreg, doff, sreg, soff, size, tmp);
+}
+static void blkunroll(int k, int dreg, int doff, int sreg, int soff, int size, int tmp[]) {
+ int i;
+
+ assert(IR->x.max_unaligned_load);
+ if (k > IR->x.max_unaligned_load
+ && (k > salign || k > dalign))
+ k = IR->x.max_unaligned_load;
+ for (i = 0; i+k < size; i += 2*k) {
+ (*IR->x.blkfetch)(k, soff+i, sreg, tmp[0]);
+ (*IR->x.blkfetch)(k, soff+i+k, sreg, tmp[1]);
+ (*IR->x.blkstore)(k, doff+i, dreg, tmp[0]);
+ (*IR->x.blkstore)(k, doff+i+k, dreg, tmp[1]);
+ }
+ if (i < size) {
+ (*IR->x.blkfetch)(k, i+soff, sreg, tmp[0]);
+ (*IR->x.blkstore)(k, i+doff, dreg, tmp[0]);
+ }
+}
+void parseflags(int argc, char *argv[]) {
+ int i;
+
+ for (i = 0; i < argc; i++)
+ if (strcmp(argv[i], "-d") == 0)
+ dflag = 1;
+ else if (strcmp(argv[i], "-b") == 0) /* omit */
+ bflag = 1; /* omit */
+}
+static int getrule(Node p, int nt) {
+ int rulenum;
+
+ assert(p);
+ rulenum = (*IR->x._rule)(p->x.state, nt);
+ if (!rulenum) {
+ fprint(stderr, "(%x->op=%s at %w is corrupt.)\n", p, opname(p->op), &src);
+ assert(0);
+ }
+ return rulenum;
+}
+static void reduce(Node p, int nt) {
+ int rulenum, i;
+ short *nts;
+ Node kids[10];
+
+ p = reuse(p, nt);
+ rulenum = getrule(p, nt);
+ nts = IR->x._nts[rulenum];
+ (*IR->x._kids)(p, rulenum, kids);
+ for (i = 0; nts[i]; i++)
+ reduce(kids[i], nts[i]);
+ if (IR->x._isinstruction[rulenum]) {
+ assert(p->x.inst == 0 || p->x.inst == nt);
+ p->x.inst = nt;
+ if (p->syms[RX] && p->syms[RX]->temporary) {
+ debug(fprint(stderr, "(using %s)\n", p->syms[RX]->name));
+ p->syms[RX]->x.usecount++;
+ }
+ }
+}
+static Node reuse(Node p, int nt) {
+ struct _state {
+ short cost[1];
+ };
+ Symbol r = p->syms[RX];
+
+ if (generic(p->op) == INDIR && p->kids[0]->op == VREG+P
+ && r->u.t.cse && p->x.mayrecalc
+ && ((struct _state*)r->u.t.cse->x.state)->cost[nt] == 0)
+ return r->u.t.cse;
+ else
+ return p;
+}
+
+int mayrecalc(Node p) {
+ int op;
+
+ assert(p && p->syms[RX]);
+ if (p->syms[RX]->u.t.cse == NULL)
+ return 0;
+ op = generic(p->syms[RX]->u.t.cse->op);
+ if (op == CNST || op == ADDRF || op == ADDRG || op == ADDRL) {
+ p->x.mayrecalc = 1;
+ return 1;
+ } else
+ return 0;
+}
+static Node *prune(Node p, Node pp[]) {
+ if (p == NULL)
+ return pp;
+ p->x.kids[0] = p->x.kids[1] = p->x.kids[2] = NULL;
+ if (p->x.inst == 0)
+ return prune(p->kids[1], prune(p->kids[0], pp));
+ else if (p->syms[RX] && p->syms[RX]->temporary
+ && p->syms[RX]->x.usecount < 2) {
+ p->x.inst = 0;
+ debug(fprint(stderr, "(clobbering %s)\n", p->syms[RX]->name));
+ return prune(p->kids[1], prune(p->kids[0], pp));
+ }
+ else {
+ prune(p->kids[1], prune(p->kids[0], &p->x.kids[0]));
+ *pp = p;
+ return pp + 1;
+ }
+}
+
+#define ck(i) return (i) ? 0 : LBURG_MAX
+
+int range(Node p, int lo, int hi) {
+ Symbol s = p->syms[0];
+
+ switch (specific(p->op)) {
+ case ADDRF+P:
+ case ADDRL+P: ck(s->x.offset >= lo && s->x.offset <= hi);
+ case CNST+I: ck(s->u.c.v.i >= lo && s->u.c.v.i <= hi);
+ case CNST+U: ck(s->u.c.v.u >= lo && s->u.c.v.u <= hi);
+ case CNST+P: ck(s->u.c.v.p == 0 && lo <= 0 && hi >= 0);
+ }
+ return LBURG_MAX;
+}
+static void dumptree(Node p) {
+ if (p->op == VREG+P && p->syms[0]) {
+ fprint(stderr, "VREGP(%s)", p->syms[0]->name);
+ return;
+ } else if (generic(p->op) == LOAD) {
+ fprint(stderr, "LOAD(");
+ dumptree(p->kids[0]);
+ fprint(stderr, ")");
+ return;
+ }
+ fprint(stderr, "%s(", opname(p->op));
+ switch (generic(p->op)) {
+ case CNST: case LABEL:
+ case ADDRG: case ADDRF: case ADDRL:
+ if (p->syms[0])
+ fprint(stderr, "%s", p->syms[0]->name);
+ break;
+ case RET:
+ if (p->kids[0])
+ dumptree(p->kids[0]);
+ break;
+ case CVF: case CVI: case CVP: case CVU: case JUMP:
+ case ARG: case BCOM: case NEG: case INDIR:
+ dumptree(p->kids[0]);
+ break;
+ case CALL:
+ if (optype(p->op) != B) {
+ dumptree(p->kids[0]);
+ break;
+ }
+ /* else fall thru */
+ case EQ: case NE: case GT: case GE: case LE: case LT:
+ case ASGN: case BOR: case BAND: case BXOR: case RSH: case LSH:
+ case ADD: case SUB: case DIV: case MUL: case MOD:
+ dumptree(p->kids[0]);
+ fprint(stderr, ", ");
+ dumptree(p->kids[1]);
+ break;
+ default: assert(0);
+ }
+ fprint(stderr, ")");
+}
+static void dumpcover(Node p, int nt, int in) {
+ int rulenum, i;
+ short *nts;
+ Node kids[10];
+
+ p = reuse(p, nt);
+ rulenum = getrule(p, nt);
+ nts = IR->x._nts[rulenum];
+ fprint(stderr, "dumpcover(%x) = ", p);
+ for (i = 0; i < in; i++)
+ fprint(stderr, " ");
+ dumprule(rulenum);
+ (*IR->x._kids)(p, rulenum, kids);
+ for (i = 0; nts[i]; i++)
+ dumpcover(kids[i], nts[i], in+1);
+}
+
+static void dumprule(int rulenum) {
+ assert(rulenum);
+ fprint(stderr, "%s / %s", IR->x._string[rulenum],
+ IR->x._templates[rulenum]);
+ if (!IR->x._isinstruction[rulenum])
+ fprint(stderr, "\n");
+}
+static unsigned emitasm(Node p, int nt) {
+ int rulenum;
+ short *nts;
+ char *fmt;
+ Node kids[10];
+
+ p = reuse(p, nt);
+ rulenum = getrule(p, nt);
+ nts = IR->x._nts[rulenum];
+ fmt = IR->x._templates[rulenum];
+ assert(fmt);
+ if (IR->x._isinstruction[rulenum] && p->x.emitted)
+ print("%s", p->syms[RX]->x.name);
+ else if (*fmt == '#')
+ (*IR->x.emit2)(p);
+ else {
+ if (*fmt == '?') {
+ fmt++;
+ assert(p->kids[0]);
+ if (p->syms[RX] == p->x.kids[0]->syms[RX])
+ while (*fmt++ != '\n')
+ ;
+ }
+ for ((*IR->x._kids)(p, rulenum, kids); *fmt; fmt++)
+ if (*fmt != '%')
+ (void)putchar(*fmt);
+ else if (*++fmt == 'F')
+ print("%d", framesize);
+ else if (*fmt >= '0' && *fmt <= '9')
+ emitasm(kids[*fmt - '0'], nts[*fmt - '0']);
+ else if (*fmt >= 'a' && *fmt < 'a' + NELEMS(p->syms))
+ fputs(p->syms[*fmt - 'a']->x.name, stdout);
+ else
+ (void)putchar(*fmt);
+ }
+ return 0;
+}
+void emit(Node p) {
+ for (; p; p = p->x.next) {
+ assert(p->x.registered);
+ if (p->x.equatable && requate(p) || moveself(p))
+ ;
+ else
+ (*emitter)(p, p->x.inst);
+ p->x.emitted = 1;
+ }
+}
+static int moveself(Node p) {
+ return p->x.copy
+ && p->syms[RX]->x.name == p->x.kids[0]->syms[RX]->x.name;
+}
+int move(Node p) {
+ p->x.copy = 1;
+ return 1;
+}
+static int requate(Node q) {
+ Symbol src = q->x.kids[0]->syms[RX];
+ Symbol tmp = q->syms[RX];
+ Node p;
+ int n = 0;
+
+ debug(fprint(stderr, "(requate(%x): tmp=%s src=%s)\n", q, tmp->x.name, src->x.name));
+ for (p = q->x.next; p; p = p->x.next)
+ if (p->x.copy && p->syms[RX] == src
+ && p->x.kids[0]->syms[RX] == tmp)
+ debug(fprint(stderr, "(requate arm 0 at %x)\n", p)),
+ p->syms[RX] = tmp;
+ else if (setsrc(p->syms[RX]) && !moveself(p) && !readsreg(p))
+ return 0;
+ else if (p->x.spills)
+ return 0;
+ else if (generic(p->op) == CALL && p->x.next)
+ return 0;
+ else if (p->op == LABEL+V && p->x.next)
+ return 0;
+ else if (p->syms[RX] == tmp && readsreg(p))
+ debug(fprint(stderr, "(requate arm 5 at %x)\n", p)),
+ n++;
+ else if (p->syms[RX] == tmp)
+ break;
+ debug(fprint(stderr, "(requate arm 7 at %x)\n", p));
+ assert(n > 0);
+ for (p = q->x.next; p; p = p->x.next)
+ if (p->syms[RX] == tmp && readsreg(p)) {
+ p->syms[RX] = src;
+ if (--n <= 0)
+ break;
+ }
+ return 1;
+}
+static void prelabel(Node p) {
+ if (p == NULL)
+ return;
+ prelabel(p->kids[0]);
+ prelabel(p->kids[1]);
+ if (NeedsReg[opindex(p->op)])
+ setreg(p, (*IR->x.rmap)(opkind(p->op)));
+ switch (generic(p->op)) {
+ case ADDRF: case ADDRL:
+ if (p->syms[0]->sclass == REGISTER)
+ p->op = VREG+P;
+ break;
+ case INDIR:
+ if (p->kids[0]->op == VREG+P)
+ setreg(p, p->kids[0]->syms[0]);
+ break;
+ case ASGN:
+ if (p->kids[0]->op == VREG+P)
+ rtarget(p, 1, p->kids[0]->syms[0]);
+ break;
+ case CVI: case CVU: case CVP:
+ if (optype(p->op) != F
+ && opsize(p->op) <= p->syms[0]->u.c.v.i)
+ p->op = LOAD + opkind(p->op);
+ break;
+ }
+ (IR->x.target)(p);
+}
+void setreg(Node p, Symbol r) {
+ p->syms[RX] = r;
+}
+void rtarget(Node p, int n, Symbol r) {
+ Node q = p->kids[n];
+
+ assert(q);
+ assert(r);
+ assert(r->sclass == REGISTER || !r->x.wildcard);
+ assert(q->syms[RX]);
+ if (r != q->syms[RX] && !q->syms[RX]->x.wildcard) {
+ q = newnode(LOAD + opkind(q->op),
+ q, NULL, q->syms[0]);
+ if (r->u.t.cse == p->kids[n])
+ r->u.t.cse = q;
+ p->kids[n] = p->x.kids[n] = q;
+ q->x.kids[0] = q->kids[0];
+ }
+ setreg(q, r);
+ debug(fprint(stderr, "(targeting %x->x.kids[%d]=%x to %s)\n", p, n, p->kids[n], r->x.name));
+}
+static void rewrite(Node p) {
+ assert(p->x.inst == 0);
+ prelabel(p);
+ debug(dumptree(p));
+ debug(fprint(stderr, "\n"));
+ (*IR->x._label)(p);
+ debug(dumpcover(p, 1, 0));
+ reduce(p, 1);
+}
+Node gen(Node forest) {
+ int i;
+ struct node sentinel;
+ Node dummy, p;
+
+ head = forest;
+ for (p = forest; p; p = p->link) {
+ assert(p->count == 0);
+ if (generic(p->op) == CALL)
+ docall(p);
+ else if ( generic(p->op) == ASGN
+ && generic(p->kids[1]->op) == CALL)
+ docall(p->kids[1]);
+ else if (generic(p->op) == ARG)
+ (*IR->x.doarg)(p);
+ rewrite(p);
+ p->x.listed = 1;
+ }
+ for (p = forest; p; p = p->link)
+ prune(p, &dummy);
+ relink(&sentinel, &sentinel);
+ for (p = forest; p; p = p->link)
+ linearize(p, &sentinel);
+ forest = sentinel.x.next;
+ assert(forest);
+ sentinel.x.next->x.prev = NULL;
+ sentinel.x.prev->x.next = NULL;
+ for (p = forest; p; p = p->x.next)
+ for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) {
+ assert(p->x.kids[i]->syms[RX]);
+ if (p->x.kids[i]->syms[RX]->temporary) {
+ p->x.kids[i]->x.prevuse =
+ p->x.kids[i]->syms[RX]->x.lastuse;
+ p->x.kids[i]->syms[RX]->x.lastuse = p->x.kids[i];
+ }
+ }
+ for (p = forest; p; p = p->x.next) {
+ ralloc(p);
+ if (p->x.listed && NeedsReg[opindex(p->op)]
+ && (*IR->x.rmap)(opkind(p->op))) {
+ assert(generic(p->op) == CALL || generic(p->op) == LOAD);
+ putreg(p->syms[RX]);
+ }
+ }
+ return forest;
+}
+int notarget(Node p) {
+ return p->syms[RX]->x.wildcard ? 0 : LBURG_MAX;
+}
+static void putreg(Symbol r) {
+ assert(r && r->x.regnode);
+ freemask[r->x.regnode->set] |= r->x.regnode->mask;
+ debug(dumpregs("(freeing %s)\n", r->x.name, NULL));
+}
+static Symbol askfixedreg(Symbol s) {
+ Regnode r = s->x.regnode;
+ int n = r->set;
+
+ if (r->mask&~freemask[n])
+ return NULL;
+ else {
+ freemask[n] &= ~r->mask;
+ usedmask[n] |= r->mask;
+ return s;
+ }
+}
+static Symbol askreg(Symbol rs, unsigned rmask[]) {
+ int i;
+
+ if (rs->x.wildcard == NULL)
+ return askfixedreg(rs);
+ for (i = 31; i >= 0; i--) {
+ Symbol r = rs->x.wildcard[i];
+ if (r != NULL
+ && !(r->x.regnode->mask&~rmask[r->x.regnode->set])
+ && askfixedreg(r))
+ return r;
+ }
+ return NULL;
+}
+
+static Symbol getreg(Symbol s, unsigned mask[], Node p) {
+ Symbol r = askreg(s, mask);
+ if (r == NULL) {
+ r = spillee(s, mask, p);
+ assert(r && r->x.regnode);
+ spill(r->x.regnode->mask, r->x.regnode->set, p);
+ r = askreg(s, mask);
+ }
+ assert(r && r->x.regnode);
+ r->x.regnode->vbl = NULL;
+ return r;
+}
+int askregvar(Symbol p, Symbol regs) {
+ Symbol r;
+
+ assert(p);
+ if (p->sclass != REGISTER)
+ return 0;
+ else if (!isscalar(p->type)) {
+ p->sclass = AUTO;
+ return 0;
+ }
+ else if (p->temporary) {
+ p->x.name = "?";
+ return 1;
+ }
+ else if ((r = askreg(regs, vmask)) != NULL) {
+ p->x.regnode = r->x.regnode;
+ p->x.regnode->vbl = p;
+ p->x.name = r->x.name;
+ debug(dumpregs("(allocating %s to symbol %s)\n", p->x.name, p->name));
+ return 1;
+ }
+ else {
+ p->sclass = AUTO;
+ return 0;
+ }
+}
+static void linearize(Node p, Node next) {
+ int i;
+
+ for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++)
+ linearize(p->x.kids[i], next);
+ relink(next->x.prev, p);
+ relink(p, next);
+ debug(fprint(stderr, "(listing %x)\n", p));
+}
+static void ralloc(Node p) {
+ int i;
+ unsigned mask[2];
+
+ mask[0] = tmask[0];
+ mask[1] = tmask[1];
+ assert(p);
+ debug(fprint(stderr, "(rallocing %x)\n", p));
+ for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) {
+ Node kid = p->x.kids[i];
+ Symbol r = kid->syms[RX];
+ assert(r && kid->x.registered);
+ if (r->sclass != REGISTER && r->x.lastuse == kid)
+ putreg(r);
+ }
+ if (!p->x.registered && NeedsReg[opindex(p->op)]
+ && (*IR->x.rmap)(opkind(p->op))) {
+ Symbol sym = p->syms[RX], set = sym;
+ assert(sym);
+ if (sym->temporary)
+ set = (*IR->x.rmap)(opkind(p->op));
+ assert(set);
+ if (set->sclass != REGISTER) {
+ Symbol r;
+ if (*IR->x._templates[getrule(p, p->x.inst)] == '?')
+ for (i = 1; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) {
+ Symbol r = p->x.kids[i]->syms[RX];
+ assert(p->x.kids[i]->x.registered);
+ assert(r && r->x.regnode);
+ assert(sym->x.wildcard || sym != r);
+ mask[r->x.regnode->set] &= ~r->x.regnode->mask;
+ }
+ r = getreg(set, mask, p);
+ if (sym->temporary) {
+ Node q;
+ r->x.lastuse = sym->x.lastuse;
+ for (q = sym->x.lastuse; q; q = q->x.prevuse) {
+ q->syms[RX] = r;
+ q->x.registered = 1;
+ if (sym->u.t.cse && q->x.copy)
+ q->x.equatable = 1;
+ }
+ } else {
+ p->syms[RX] = r;
+ r->x.lastuse = p;
+ }
+ debug(dumpregs("(allocating %s to node %x)\n", r->x.name, (char *) p));
+ }
+ }
+ p->x.registered = 1;
+ (*IR->x.clobber)(p);
+}
+static Symbol spillee(Symbol set, unsigned mask[], Node here) {
+ Symbol bestreg = NULL;
+ int bestdist = -1, i;
+
+ assert(set);
+ if (!set->x.wildcard)
+ bestreg = set;
+ else {
+ for (i = 31; i >= 0; i--) {
+ Symbol ri = set->x.wildcard[i];
+ if (
+ ri != NULL &&
+ ri->x.lastuse &&
+ (ri->x.regnode->mask&tmask[ri->x.regnode->set]&mask[ri->x.regnode->set])
+ ) {
+ Regnode rn = ri->x.regnode;
+ Node q = here;
+ int dist = 0;
+ for (; q && !uses(q, rn); q = q->x.next)
+ dist++;
+ if (q && dist > bestdist) {
+ bestdist = dist;
+ bestreg = ri;
+ }
+ }
+ }
+ }
+ assert(bestreg); /* Must be able to spill something. Reconfigure the register allocator
+ to ensure that we can allocate a register for all nodes without spilling
+ the node's necessary input regs. */
+ assert(bestreg->x.regnode->vbl == NULL); /* Can't spill register variables because
+ the reload site might be in other blocks. Reconfigure the register allocator
+ to ensure that this register is never allocated to a variable. */
+ return bestreg;
+}
+static int uses(Node p, Regnode rn) {
+ int i;
+
+ for (i = 0; i < NELEMS(p->x.kids); i++)
+ if (
+ p->x.kids[i] &&
+ p->x.kids[i]->x.registered &&
+ rn->set == p->x.kids[i]->syms[RX]->x.regnode->set &&
+ (rn->mask&p->x.kids[i]->syms[RX]->x.regnode->mask)
+ )
+ return 1;
+ return 0;
+}
+static void spillr(Symbol r, Node here) {
+ int i;
+ Symbol tmp;
+ Node p = r->x.lastuse;
+ assert(p);
+ while (p->x.prevuse)
+ assert(r == p->syms[RX]),
+ p = p->x.prevuse;
+ assert(p->x.registered && !readsreg(p));
+ tmp = newtemp(AUTO, optype(p->op), opsize(p->op));
+ genspill(r, p, tmp);
+ for (p = here->x.next; p; p = p->x.next)
+ for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) {
+ Node k = p->x.kids[i];
+ if (k->x.registered && k->syms[RX] == r)
+ genreload(p, tmp, i);
+ }
+ putreg(r);
+}
+static void genspill(Symbol r, Node last, Symbol tmp) {
+ Node p, q;
+ Symbol s;
+ unsigned ty;
+
+ debug(fprint(stderr, "(spilling %s to local %s)\n", r->x.name, tmp->x.name));
+ debug(fprint(stderr, "(genspill: "));
+ debug(dumptree(last));
+ debug(fprint(stderr, ")\n"));
+ ty = opkind(last->op);
+ NEW0(s, FUNC);
+ s->sclass = REGISTER;
+ s->name = s->x.name = r->x.name;
+ s->x.regnode = r->x.regnode;
+ q = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, s);
+ q = newnode(INDIR + ty, q, NULL, NULL);
+ p = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, tmp);
+ p = newnode(ASGN + ty, p, q, NULL);
+ p->x.spills = 1;
+ rewrite(p);
+ prune(p, &q);
+ q = last->x.next;
+ linearize(p, q);
+ for (p = last->x.next; p != q; p = p->x.next) {
+ ralloc(p);
+ assert(!p->x.listed || !NeedsReg[opindex(p->op)] || !(*IR->x.rmap)(opkind(p->op)));
+ }
+}
+
+static void genreload(Node p, Symbol tmp, int i) {
+ Node q;
+ int ty;
+
+ debug(fprint(stderr, "(replacing %x with a reload from %s)\n", p->x.kids[i], tmp->x.name));
+ debug(fprint(stderr, "(genreload: "));
+ debug(dumptree(p->x.kids[i]));
+ debug(fprint(stderr, ")\n"));
+ ty = opkind(p->x.kids[i]->op);
+ q = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, tmp);
+ p->x.kids[i] = newnode(INDIR + ty, q, NULL, NULL);
+ rewrite(p->x.kids[i]);
+ prune(p->x.kids[i], &q);
+ reprune(&p->kids[1], reprune(&p->kids[0], 0, i, p), i, p);
+ prune(p, &q);
+ linearize(p->x.kids[i], p);
+}
+static int reprune(Node *pp, int k, int n, Node p) {
+ struct node x, *q = *pp;
+
+ if (q == NULL || k > n)
+ return k;
+ else if (q->x.inst == 0)
+ return reprune(&q->kids[1],
+ reprune(&q->kids[0], k, n, p), n, p);
+ if (k == n) {
+ debug(fprint(stderr, "(reprune changes %x from %x to %x)\n", pp, *pp, p->x.kids[n]));
+ *pp = p->x.kids[n];
+ x = *p;
+ (IR->x.target)(&x);
+ }
+ return k + 1;
+}
+void spill(unsigned mask, int n, Node here) {
+ int i;
+ Node p;
+
+ here->x.spills = 1;
+ usedmask[n] |= mask;
+ if (mask&~freemask[n]) {
+
+ assert( /* It makes no sense for a node to clobber() its target. */
+ here->x.registered == 0 || /* call isn't coming through clobber() */
+ here->syms[RX] == NULL ||
+ here->syms[RX]->x.regnode == NULL ||
+ here->syms[RX]->x.regnode->set != n ||
+ (here->syms[RX]->x.regnode->mask&mask) == 0
+ );
+
+ for (p = here; p; p = p->x.next)
+ for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) {
+ Symbol r = p->x.kids[i]->syms[RX];
+ assert(r);
+ if (p->x.kids[i]->x.registered && r->x.regnode->set == n
+ && r->x.regnode->mask&mask)
+ spillr(r, here);
+ }
+ }
+}
+static void dumpregs(char *msg, char *a, char *b) {
+ fprint(stderr, msg, a, b);
+ fprint(stderr, "(free[0]=%x)\n", freemask[0]);
+ fprint(stderr, "(free[1]=%x)\n", freemask[1]);
+}
+
+int getregnum(Node p) {
+ assert(p && p->syms[RX] && p->syms[RX]->x.regnode);
+ return p->syms[RX]->x.regnode->number;
+}
+
+
+unsigned regloc(Symbol p) {
+ assert(p && p->sclass == REGISTER && p->sclass == REGISTER && p->x.regnode);
+ return p->x.regnode->set<<8 | p->x.regnode->number;
+}
+
diff --git a/lcc/src/init.c b/lcc/src/init.c
new file mode 100755
index 0000000..67bcc69
--- /dev/null
+++ b/lcc/src/init.c
@@ -0,0 +1,318 @@
+#include "c.h"
+
+
+static int curseg; /* current segment */
+
+/* defpointer - initialize a pointer to p or to 0 if p==0 */
+void defpointer(Symbol p) {
+ if (p) {
+ (*IR->defaddress)(p);
+ p->ref++;
+ } else {
+ static Value v;
+ (*IR->defconst)(P, voidptype->size, v);
+ }
+}
+
+/* genconst - generate/check constant expression e; return size */
+static int genconst(Tree e, int def) {
+ for (;;)
+ switch (generic(e->op)) {
+ case ADDRG:
+ if (def)
+ (*IR->defaddress)(e->u.sym);
+ return e->type->size;
+ case CNST:
+ if (e->op == CNST+P && isarray(e->type)) {
+ e = cvtconst(e);
+ continue;
+ }
+ if (def)
+ (*IR->defconst)(e->type->op, e->type->size, e->u.v);
+ return e->type->size;
+ case RIGHT:
+ assert(e->kids[0] || e->kids[1]);
+ if (e->kids[1] && e->kids[0])
+ error("initializer must be constant\n");
+ e = e->kids[1] ? e->kids[1] : e->kids[0];
+ continue;
+ case CVP:
+ if (isarith(e->type))
+ error("cast from `%t' to `%t' is illegal in constant expressions\n",
+ e->kids[0]->type, e->type);
+ /* fall thru */
+ case CVI: case CVU: case CVF:
+ e = e->kids[0];
+ continue;
+ default:
+ error("initializer must be constant\n");
+ if (def)
+ genconst(consttree(0, inttype), def);
+ return inttype->size;
+ }
+}
+
+/* initvalue - evaluate a constant expression for a value of integer type ty */
+static Tree initvalue(Type ty) {
+ Type aty;
+ Tree e;
+
+ needconst++;
+ e = expr1(0);
+ if ((aty = assign(ty, e)) != NULL)
+ e = cast(e, aty);
+ else {
+ error("invalid initialization type; found `%t' expected `%t'\n",
+ e->type, ty);
+ e = retype(consttree(0, inttype), ty);
+ }
+ needconst--;
+ if (generic(e->op) != CNST) {
+ error("initializer must be constant\n");
+ e = retype(consttree(0, inttype), ty);
+ }
+ return e;
+}
+
+/* initarray - initialize array of ty of <= len bytes; if len == 0, go to } */
+static int initarray(int len, Type ty, int lev) {
+ int n = 0;
+
+ do {
+ initializer(ty, lev);
+ n += ty->size;
+ if (len > 0 && n >= len || t != ',')
+ break;
+ t = gettok();
+ } while (t != '}');
+ return n;
+}
+
+/* initchar - initialize array of <= len ty characters; if len == 0, go to } */
+static int initchar(int len, Type ty) {
+ int n = 0;
+ char buf[16], *s = buf;
+
+ do {
+ *s++ = initvalue(ty)->u.v.i;
+ if (++n%inttype->size == 0) {
+ (*IR->defstring)(inttype->size, buf);
+ s = buf;
+ }
+ if (len > 0 && n >= len || t != ',')
+ break;
+ t = gettok();
+ } while (t != '}');
+ if (s > buf)
+ (*IR->defstring)(s - buf, buf);
+ return n;
+}
+
+/* initend - finish off an initialization at level lev; accepts trailing comma */
+static void initend(int lev, char follow[]) {
+ if (lev == 0 && t == ',')
+ t = gettok();
+ test('}', follow);
+}
+
+/* initfields - initialize <= an unsigned's worth of bit fields in fields p to q */
+static int initfields(Field p, Field q) {
+ unsigned int bits = 0;
+ int i, n = 0;
+
+ do {
+ i = initvalue(inttype)->u.v.i;
+ if (fieldsize(p) < 8*p->type->size) {
+ if (p->type == inttype &&
+ (i < -(int)(fieldmask(p)>>1)-1 || i > (int)(fieldmask(p)>>1))
+ || p->type == unsignedtype && (i&~fieldmask(p)) != 0)
+ warning("initializer exceeds bit-field width\n");
+ i &= fieldmask(p);
+ }
+ bits |= i<<fieldright(p);
+ if (IR->little_endian) {
+ if (fieldsize(p) + fieldright(p) > n)
+ n = fieldsize(p) + fieldright(p);
+ } else {
+ if (fieldsize(p) + fieldleft(p) > n)
+ n = fieldsize(p) + fieldleft(p);
+ }
+ if (p->link == q)
+ break;
+ p = p->link;
+ } while (t == ',' && (t = gettok()) != 0);
+ n = (n + 7)/8;
+ for (i = 0; i < n; i++) {
+ Value v;
+ if (IR->little_endian) {
+ v.u = (unsigned char)bits;
+ bits >>= 8;
+ } else { /* a big endian */
+ v.u = (unsigned char)(bits>>(8*(unsignedtype->size - 1)));
+ bits <<= 8;
+ }
+ (*IR->defconst)(U, unsignedchar->size, v);
+ }
+ return n;
+}
+
+/* initstruct - initialize a struct ty of <= len bytes; if len == 0, go to } */
+static int initstruct(int len, Type ty, int lev) {
+ int a, n = 0;
+ Field p = ty->u.sym->u.s.flist;
+
+ do {
+ if (p->offset > n) {
+ (*IR->space)(p->offset - n);
+ n += p->offset - n;
+ }
+ if (p->lsb) {
+ Field q = p;
+ while (q->link && q->link->offset == p->offset)
+ q = q->link;
+ n += initfields(p, q->link);
+ p = q;
+ } else {
+ initializer(p->type, lev);
+ n += p->type->size;
+ }
+ if (p->link) {
+ p = p->link;
+ a = p->type->align;
+ } else
+ a = ty->align;
+ if (a && n%a) {
+ (*IR->space)(a - n%a);
+ n = roundup(n, a);
+ }
+ if (len > 0 && n >= len || t != ',')
+ break;
+ t = gettok();
+ } while (t != '}');
+ return n;
+}
+
+/* initializer - constexpr | { constexpr ( , constexpr )* [ , ] } */
+Type initializer(Type ty, int lev) {
+ int n = 0;
+ Tree e;
+ Type aty = NULL;
+ static char follow[] = { IF, CHAR, STATIC, 0 };
+
+ ty = unqual(ty);
+ if (isscalar(ty)) {
+ needconst++;
+ if (t == '{') {
+ t = gettok();
+ e = expr1(0);
+ initend(lev, follow);
+ } else
+ e = expr1(0);
+ e = pointer(e);
+ if ((aty = assign(ty, e)) != NULL)
+ e = cast(e, aty);
+ else
+ error("invalid initialization type; found `%t' expected `%t'\n",
+ e->type, ty);
+ n = genconst(e, 1);
+ deallocate(STMT);
+ needconst--;
+ }
+ if ((isunion(ty) || isstruct(ty)) && ty->size == 0) {
+ static char follow[] = { CHAR, STATIC, 0 };
+ error("cannot initialize undefined `%t'\n", ty);
+ skipto(';', follow);
+ return ty;
+ } else if (isunion(ty)) {
+ if (t == '{') {
+ t = gettok();
+ n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1);
+ initend(lev, follow);
+ } else {
+ if (lev == 0)
+ error("missing { in initialization of `%t'\n", ty);
+ n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1);
+ }
+ } else if (isstruct(ty)) {
+ if (t == '{') {
+ t = gettok();
+ n = initstruct(0, ty, lev + 1);
+ test('}', follow);
+ } else if (lev > 0)
+ n = initstruct(ty->size, ty, lev + 1);
+ else {
+ error("missing { in initialization of `%t'\n", ty);
+ n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1);
+ }
+ }
+ if (isarray(ty))
+ aty = unqual(ty->type);
+ if (isarray(ty) && ischar(aty)) {
+ if (t == SCON) {
+ if (ty->size > 0 && ty->size == tsym->type->size - 1)
+ tsym->type = array(chartype, ty->size, 0);
+ n = tsym->type->size;
+ (*IR->defstring)(tsym->type->size, tsym->u.c.v.p);
+ t = gettok();
+ } else if (t == '{') {
+ t = gettok();
+ if (t == SCON) {
+ ty = initializer(ty, lev + 1);
+ initend(lev, follow);
+ return ty;
+ }
+ n = initchar(0, aty);
+ test('}', follow);
+ } else if (lev > 0 && ty->size > 0)
+ n = initchar(ty->size, aty);
+ else { /* eg, char c[] = 0; */
+ error("missing { in initialization of `%t'\n", ty);
+ n = initchar(1, aty);
+ }
+ } else if (isarray(ty)) {
+ if (t == SCON && aty == widechar) {
+ int i;
+ unsigned int *s = tsym->u.c.v.p;
+ if (ty->size > 0 && ty->size == tsym->type->size - widechar->size)
+ tsym->type = array(widechar, ty->size/widechar->size, 0);
+ n = tsym->type->size;
+ for (i = 0; i < n; i += widechar->size) {
+ Value v;
+ v.u = *s++;
+ (*IR->defconst)(widechar->op, widechar->size, v);
+ }
+ t = gettok();
+ } else if (t == '{') {
+ t = gettok();
+ if (t == SCON && aty == widechar) {
+ ty = initializer(ty, lev + 1);
+ initend(lev, follow);
+ return ty;
+ }
+ n = initarray(0, aty, lev + 1);
+ test('}', follow);
+ } else if (lev > 0 && ty->size > 0)
+ n = initarray(ty->size, aty, lev + 1);
+ else {
+ error("missing { in initialization of `%t'\n", ty);
+ n = initarray(aty->size, aty, lev + 1);
+ }
+ }
+ if (ty->size) {
+ if (n > ty->size)
+ error("too many initializers\n");
+ else if (n < ty->size)
+ (*IR->space)(ty->size - n);
+ } else if (isarray(ty) && ty->type->size > 0)
+ ty = array(ty->type, n/ty->type->size, 0);
+ else
+ ty->size = n;
+ return ty;
+}
+
+/* swtoseg - switch to segment seg, if necessary */
+void swtoseg(int seg) {
+ if (curseg != seg)
+ (*IR->segment)(seg);
+ curseg = seg;
+}
diff --git a/lcc/src/inits.c b/lcc/src/inits.c
new file mode 100755
index 0000000..d4d49df
--- /dev/null
+++ b/lcc/src/inits.c
@@ -0,0 +1,8 @@
+void init(int argc, char *argv[]) {
+ {extern void input_init(int, char *[]); input_init(argc, argv);}
+ {extern void main_init(int, char *[]); main_init(argc, argv);}
+ {extern void prof_init(int, char *[]); prof_init(argc, argv);}
+ {extern void trace_init(int, char *[]); trace_init(argc, argv);}
+ {extern void type_init(int, char *[]); type_init(argc, argv);}
+ {extern void x86linux_init(int, char *[]); x86linux_init(argc, argv);}
+}
diff --git a/lcc/src/input.c b/lcc/src/input.c
new file mode 100755
index 0000000..2f34420
--- /dev/null
+++ b/lcc/src/input.c
@@ -0,0 +1,134 @@
+#include "c.h"
+
+
+static void pragma(void);
+static void resynch(void);
+
+static int bsize;
+static unsigned char buffer[MAXLINE+1 + BUFSIZE+1];
+unsigned char *cp; /* current input character */
+char *file; /* current input file name */
+char *firstfile; /* first input file */
+unsigned char *limit; /* points to last character + 1 */
+char *line; /* current line */
+int lineno; /* line number of current line */
+
+void nextline(void) {
+ do {
+ if (cp >= limit) {
+ fillbuf();
+ if (cp >= limit)
+ cp = limit;
+ if (cp == limit)
+ return;
+ } else {
+ lineno++;
+ for (line = (char *)cp; *cp==' ' || *cp=='\t'; cp++)
+ ;
+ if (*cp == '#') {
+ resynch();
+ nextline();
+ }
+ }
+ } while (*cp == '\n' && cp == limit);
+}
+void fillbuf(void) {
+ if (bsize == 0)
+ return;
+ if (cp >= limit)
+ cp = &buffer[MAXLINE+1];
+ else
+ {
+ int n = limit - cp;
+ unsigned char *s = &buffer[MAXLINE+1] - n;
+ assert(s >= buffer);
+ line = (char *)s - ((char *)cp - line);
+ while (cp < limit)
+ *s++ = *cp++;
+ cp = &buffer[MAXLINE+1] - n;
+ }
+ if (feof(stdin))
+ bsize = 0;
+ else
+ bsize = fread(&buffer[MAXLINE+1], 1, BUFSIZE, stdin);
+ if (bsize < 0) {
+ error("read error\n");
+ exit(EXIT_FAILURE);
+ }
+ limit = &buffer[MAXLINE+1+bsize];
+ *limit = '\n';
+}
+void input_init(int argc, char *argv[]) {
+ static int inited;
+
+ if (inited)
+ return;
+ inited = 1;
+ main_init(argc, argv);
+ limit = cp = &buffer[MAXLINE+1];
+ bsize = -1;
+ lineno = 0;
+ file = NULL;
+ fillbuf();
+ if (cp >= limit)
+ cp = limit;
+ nextline();
+}
+
+/* pragma - handle #pragma ref id... */
+static void pragma(void) {
+ if ((t = gettok()) == ID && strcmp(token, "ref") == 0)
+ for (;;) {
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (*cp == '\n' || *cp == 0)
+ break;
+ if ((t = gettok()) == ID && tsym) {
+ tsym->ref++;
+ use(tsym, src);
+ }
+ }
+}
+
+/* resynch - set line number/file name in # n [ "file" ] and #pragma ... */
+static void resynch(void) {
+ for (cp++; *cp == ' ' || *cp == '\t'; )
+ cp++;
+ if (limit - cp < MAXLINE)
+ fillbuf();
+ if (strncmp((char *)cp, "pragma", 6) == 0) {
+ cp += 6;
+ pragma();
+ } else if (*cp >= '0' && *cp <= '9') {
+ line: for (lineno = 0; *cp >= '0' && *cp <= '9'; )
+ lineno = 10*lineno + *cp++ - '0';
+ lineno--;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (*cp == '"') {
+ file = (char *)++cp;
+ while (*cp && *cp != '"' && *cp != '\n')
+ cp++;
+ file = stringn(file, (char *)cp - file);
+ if (*cp == '\n')
+ warning("missing \" in preprocessor line\n");
+ if (firstfile == 0)
+ firstfile = file;
+ }
+ } else if (strncmp((char *)cp, "line", 4) == 0) {
+ for (cp += 4; *cp == ' ' || *cp == '\t'; )
+ cp++;
+ if (*cp >= '0' && *cp <= '9')
+ goto line;
+ if (Aflag >= 2)
+ warning("unrecognized control line\n");
+ } else if (Aflag >= 2 && *cp != '\n')
+ warning("unrecognized control line\n");
+ while (*cp)
+ if (*cp++ == '\n')
+ if (cp == limit + 1)
+ nextline();
+ else
+ break;
+}
+
diff --git a/lcc/src/lex.c b/lcc/src/lex.c
new file mode 100755
index 0000000..09c50f3
--- /dev/null
+++ b/lcc/src/lex.c
@@ -0,0 +1,922 @@
+#include "c.h"
+#include <float.h>
+#include <errno.h>
+
+
+#define MAXTOKEN 32
+
+enum { BLANK=01, NEWLINE=02, LETTER=04,
+ DIGIT=010, HEX=020, OTHER=040 };
+
+static unsigned char map[256] = { /* 000 nul */ 0,
+ /* 001 soh */ 0,
+ /* 002 stx */ 0,
+ /* 003 etx */ 0,
+ /* 004 eot */ 0,
+ /* 005 enq */ 0,
+ /* 006 ack */ 0,
+ /* 007 bel */ 0,
+ /* 010 bs */ 0,
+ /* 011 ht */ BLANK,
+ /* 012 nl */ NEWLINE,
+ /* 013 vt */ BLANK,
+ /* 014 ff */ BLANK,
+ /* 015 cr */ 0,
+ /* 016 so */ 0,
+ /* 017 si */ 0,
+ /* 020 dle */ 0,
+ /* 021 dc1 */ 0,
+ /* 022 dc2 */ 0,
+ /* 023 dc3 */ 0,
+ /* 024 dc4 */ 0,
+ /* 025 nak */ 0,
+ /* 026 syn */ 0,
+ /* 027 etb */ 0,
+ /* 030 can */ 0,
+ /* 031 em */ 0,
+ /* 032 sub */ 0,
+ /* 033 esc */ 0,
+ /* 034 fs */ 0,
+ /* 035 gs */ 0,
+ /* 036 rs */ 0,
+ /* 037 us */ 0,
+ /* 040 sp */ BLANK,
+ /* 041 ! */ OTHER,
+ /* 042 " */ OTHER,
+ /* 043 # */ OTHER,
+ /* 044 $ */ 0,
+ /* 045 % */ OTHER,
+ /* 046 & */ OTHER,
+ /* 047 ' */ OTHER,
+ /* 050 ( */ OTHER,
+ /* 051 ) */ OTHER,
+ /* 052 * */ OTHER,
+ /* 053 + */ OTHER,
+ /* 054 , */ OTHER,
+ /* 055 - */ OTHER,
+ /* 056 . */ OTHER,
+ /* 057 / */ OTHER,
+ /* 060 0 */ DIGIT,
+ /* 061 1 */ DIGIT,
+ /* 062 2 */ DIGIT,
+ /* 063 3 */ DIGIT,
+ /* 064 4 */ DIGIT,
+ /* 065 5 */ DIGIT,
+ /* 066 6 */ DIGIT,
+ /* 067 7 */ DIGIT,
+ /* 070 8 */ DIGIT,
+ /* 071 9 */ DIGIT,
+ /* 072 : */ OTHER,
+ /* 073 ; */ OTHER,
+ /* 074 < */ OTHER,
+ /* 075 = */ OTHER,
+ /* 076 > */ OTHER,
+ /* 077 ? */ OTHER,
+ /* 100 @ */ 0,
+ /* 101 A */ LETTER|HEX,
+ /* 102 B */ LETTER|HEX,
+ /* 103 C */ LETTER|HEX,
+ /* 104 D */ LETTER|HEX,
+ /* 105 E */ LETTER|HEX,
+ /* 106 F */ LETTER|HEX,
+ /* 107 G */ LETTER,
+ /* 110 H */ LETTER,
+ /* 111 I */ LETTER,
+ /* 112 J */ LETTER,
+ /* 113 K */ LETTER,
+ /* 114 L */ LETTER,
+ /* 115 M */ LETTER,
+ /* 116 N */ LETTER,
+ /* 117 O */ LETTER,
+ /* 120 P */ LETTER,
+ /* 121 Q */ LETTER,
+ /* 122 R */ LETTER,
+ /* 123 S */ LETTER,
+ /* 124 T */ LETTER,
+ /* 125 U */ LETTER,
+ /* 126 V */ LETTER,
+ /* 127 W */ LETTER,
+ /* 130 X */ LETTER,
+ /* 131 Y */ LETTER,
+ /* 132 Z */ LETTER,
+ /* 133 [ */ OTHER,
+ /* 134 \ */ OTHER,
+ /* 135 ] */ OTHER,
+ /* 136 ^ */ OTHER,
+ /* 137 _ */ LETTER,
+ /* 140 ` */ 0,
+ /* 141 a */ LETTER|HEX,
+ /* 142 b */ LETTER|HEX,
+ /* 143 c */ LETTER|HEX,
+ /* 144 d */ LETTER|HEX,
+ /* 145 e */ LETTER|HEX,
+ /* 146 f */ LETTER|HEX,
+ /* 147 g */ LETTER,
+ /* 150 h */ LETTER,
+ /* 151 i */ LETTER,
+ /* 152 j */ LETTER,
+ /* 153 k */ LETTER,
+ /* 154 l */ LETTER,
+ /* 155 m */ LETTER,
+ /* 156 n */ LETTER,
+ /* 157 o */ LETTER,
+ /* 160 p */ LETTER,
+ /* 161 q */ LETTER,
+ /* 162 r */ LETTER,
+ /* 163 s */ LETTER,
+ /* 164 t */ LETTER,
+ /* 165 u */ LETTER,
+ /* 166 v */ LETTER,
+ /* 167 w */ LETTER,
+ /* 170 x */ LETTER,
+ /* 171 y */ LETTER,
+ /* 172 z */ LETTER,
+ /* 173 { */ OTHER,
+ /* 174 | */ OTHER,
+ /* 175 } */ OTHER,
+ /* 176 ~ */ OTHER, };
+static struct symbol tval;
+static char cbuf[BUFSIZE+1];
+static unsigned int wcbuf[BUFSIZE+1];
+
+Coordinate src; /* current source coordinate */
+int t;
+char *token; /* current token */
+Symbol tsym; /* symbol table entry for current token */
+
+static void *cput(int c, void *cl);
+static void *wcput(int c, void *cl);
+static void *scon(int q, void *put(int c, void *cl), void *cl);
+static int backslash(int q);
+static Symbol fcon(void);
+static Symbol icon(unsigned long, int, int);
+static void ppnumber(char *);
+
+int gettok(void) {
+ for (;;) {
+ register unsigned char *rcp = cp;
+ while (map[*rcp]&BLANK)
+ rcp++;
+ if (limit - rcp < MAXTOKEN) {
+ cp = rcp;
+ fillbuf();
+ rcp = cp;
+ }
+ src.file = file;
+ src.x = (char *)rcp - line;
+ src.y = lineno;
+ cp = rcp + 1;
+ switch (*rcp++) {
+ case '/': if (*rcp == '*') {
+ int c = 0;
+ for (rcp++; *rcp != '/' || c != '*'; )
+ if (map[*rcp]&NEWLINE) {
+ if (rcp < limit)
+ c = *rcp;
+ cp = rcp + 1;
+ nextline();
+ rcp = cp;
+ if (rcp == limit)
+ break;
+ } else
+ c = *rcp++;
+ if (rcp < limit)
+ rcp++;
+ else
+ error("unclosed comment\n");
+ cp = rcp;
+ continue;
+ }
+ return '/';
+ case '<':
+ if (*rcp == '=') return cp++, LEQ;
+ if (*rcp == '<') return cp++, LSHIFT;
+ return '<';
+ case '>':
+ if (*rcp == '=') return cp++, GEQ;
+ if (*rcp == '>') return cp++, RSHIFT;
+ return '>';
+ case '-':
+ if (*rcp == '>') return cp++, DEREF;
+ if (*rcp == '-') return cp++, DECR;
+ return '-';
+ case '=': return *rcp == '=' ? cp++, EQL : '=';
+ case '!': return *rcp == '=' ? cp++, NEQ : '!';
+ case '|': return *rcp == '|' ? cp++, OROR : '|';
+ case '&': return *rcp == '&' ? cp++, ANDAND : '&';
+ case '+': return *rcp == '+' ? cp++, INCR : '+';
+ case ';': case ',': case ':':
+ case '*': case '~': case '%': case '^': case '?':
+ case '[': case ']': case '{': case '}': case '(': case ')':
+ return rcp[-1];
+ case '\n': case '\v': case '\r': case '\f':
+ nextline();
+ if (cp == limit) {
+ tsym = NULL;
+ return EOI;
+ }
+ continue;
+
+ case 'i':
+ if (rcp[0] == 'f'
+ && !(map[rcp[1]]&(DIGIT|LETTER))) {
+ cp = rcp + 1;
+ return IF;
+ }
+ if (rcp[0] == 'n'
+ && rcp[1] == 't'
+ && !(map[rcp[2]]&(DIGIT|LETTER))) {
+ cp = rcp + 2;
+ tsym = inttype->u.sym;
+ return INT;
+ }
+ goto id;
+ case 'h': case 'j': case 'k': case 'm': case 'n': case 'o':
+ case 'p': case 'q': case 'x': case 'y': case 'z':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ case 'G': case 'H': case 'I': case 'J': case 'K':
+ case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+ case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+ case 'Y': case 'Z':
+ id:
+ if (limit - rcp < MAXLINE) {
+ cp = rcp - 1;
+ fillbuf();
+ rcp = ++cp;
+ }
+ assert(cp == rcp);
+ token = (char *)rcp - 1;
+ while (map[*rcp]&(DIGIT|LETTER))
+ rcp++;
+ token = stringn(token, (char *)rcp - token);
+ tsym = lookup(token, identifiers);
+ cp = rcp;
+ return ID;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9': {
+ unsigned long n = 0;
+ if (limit - rcp < MAXLINE) {
+ cp = rcp - 1;
+ fillbuf();
+ rcp = ++cp;
+ }
+ assert(cp == rcp);
+ token = (char *)rcp - 1;
+ if (*token == '0' && (*rcp == 'x' || *rcp == 'X')) {
+ int d, overflow = 0;
+ while (*++rcp) {
+ if (map[*rcp]&DIGIT)
+ d = *rcp - '0';
+ else if (*rcp >= 'a' && *rcp <= 'f')
+ d = *rcp - 'a' + 10;
+ else if (*rcp >= 'A' && *rcp <= 'F')
+ d = *rcp - 'A' + 10;
+ else
+ break;
+ if (n&~(~0UL >> 4))
+ overflow = 1;
+ else
+ n = (n<<4) + d;
+ }
+ if ((char *)rcp - token <= 2)
+ error("invalid hexadecimal constant `%S'\n", token, (char *)rcp-token);
+ cp = rcp;
+ tsym = icon(n, overflow, 16);
+ } else if (*token == '0') {
+ int err = 0, overflow = 0;
+ for ( ; map[*rcp]&DIGIT; rcp++) {
+ if (*rcp == '8' || *rcp == '9')
+ err = 1;
+ if (n&~(~0UL >> 3))
+ overflow = 1;
+ else
+ n = (n<<3) + (*rcp - '0');
+ }
+ if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') {
+ cp = rcp;
+ tsym = fcon();
+ return FCON;
+ }
+ cp = rcp;
+ tsym = icon(n, overflow, 8);
+ if (err)
+ error("invalid octal constant `%S'\n", token, (char*)cp-token);
+ } else {
+ int overflow = 0;
+ for (n = *token - '0'; map[*rcp]&DIGIT; ) {
+ int d = *rcp++ - '0';
+ if (n > (ULONG_MAX - d)/10)
+ overflow = 1;
+ else
+ n = 10*n + d;
+ }
+ if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') {
+ cp = rcp;
+ tsym = fcon();
+ return FCON;
+ }
+ cp = rcp;
+ tsym = icon(n, overflow, 10);
+ }
+ return ICON;
+ }
+ case '.':
+ if (rcp[0] == '.' && rcp[1] == '.') {
+ cp += 2;
+ return ELLIPSIS;
+ }
+ if ((map[*rcp]&DIGIT) == 0)
+ return '.';
+ if (limit - rcp < MAXLINE) {
+ cp = rcp - 1;
+ fillbuf();
+ rcp = ++cp;
+ }
+ assert(cp == rcp);
+ cp = rcp - 1;
+ token = (char *)cp;
+ tsym = fcon();
+ return FCON;
+ case 'L':
+ if (*rcp == '\'') {
+ unsigned int *s = scon(*cp, wcput, wcbuf);
+ if (s - wcbuf > 2)
+ warning("excess characters in wide-character literal ignored\n");
+ tval.type = widechar;
+ tval.u.c.v.u = wcbuf[0];
+ tsym = &tval;
+ return ICON;
+ } else if (*rcp == '"') {
+ unsigned int *s = scon(*cp, wcput, wcbuf);
+ tval.type = array(widechar, s - wcbuf, 0);
+ tval.u.c.v.p = wcbuf;
+ tsym = &tval;
+ return SCON;
+ } else
+ goto id;
+ case '\'': {
+ char *s = scon(*--cp, cput, cbuf);
+ if (s - cbuf > 2)
+ warning("excess characters in multibyte character literal ignored\n");
+ tval.type = inttype;
+ if (chartype->op == INT)
+ tval.u.c.v.i = extend(cbuf[0], chartype);
+ else
+ tval.u.c.v.i = cbuf[0]&0xFF;
+ tsym = &tval;
+ return ICON;
+ }
+ case '"': {
+ char *s = scon(*--cp, cput, cbuf);
+ tval.type = array(chartype, s - cbuf, 0);
+ tval.u.c.v.p = cbuf;
+ tsym = &tval;
+ return SCON;
+ }
+ case 'a':
+ if (rcp[0] == 'u'
+ && rcp[1] == 't'
+ && rcp[2] == 'o'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ return AUTO;
+ }
+ goto id;
+ case 'b':
+ if (rcp[0] == 'r'
+ && rcp[1] == 'e'
+ && rcp[2] == 'a'
+ && rcp[3] == 'k'
+ && !(map[rcp[4]]&(DIGIT|LETTER))) {
+ cp = rcp + 4;
+ return BREAK;
+ }
+ goto id;
+ case 'c':
+ if (rcp[0] == 'a'
+ && rcp[1] == 's'
+ && rcp[2] == 'e'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ return CASE;
+ }
+ if (rcp[0] == 'h'
+ && rcp[1] == 'a'
+ && rcp[2] == 'r'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ tsym = chartype->u.sym;
+ return CHAR;
+ }
+ if (rcp[0] == 'o'
+ && rcp[1] == 'n'
+ && rcp[2] == 's'
+ && rcp[3] == 't'
+ && !(map[rcp[4]]&(DIGIT|LETTER))) {
+ cp = rcp + 4;
+ return CONST;
+ }
+ if (rcp[0] == 'o'
+ && rcp[1] == 'n'
+ && rcp[2] == 't'
+ && rcp[3] == 'i'
+ && rcp[4] == 'n'
+ && rcp[5] == 'u'
+ && rcp[6] == 'e'
+ && !(map[rcp[7]]&(DIGIT|LETTER))) {
+ cp = rcp + 7;
+ return CONTINUE;
+ }
+ goto id;
+ case 'd':
+ if (rcp[0] == 'e'
+ && rcp[1] == 'f'
+ && rcp[2] == 'a'
+ && rcp[3] == 'u'
+ && rcp[4] == 'l'
+ && rcp[5] == 't'
+ && !(map[rcp[6]]&(DIGIT|LETTER))) {
+ cp = rcp + 6;
+ return DEFAULT;
+ }
+ if (rcp[0] == 'o'
+ && rcp[1] == 'u'
+ && rcp[2] == 'b'
+ && rcp[3] == 'l'
+ && rcp[4] == 'e'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ tsym = doubletype->u.sym;
+ return DOUBLE;
+ }
+ if (rcp[0] == 'o'
+ && !(map[rcp[1]]&(DIGIT|LETTER))) {
+ cp = rcp + 1;
+ return DO;
+ }
+ goto id;
+ case 'e':
+ if (rcp[0] == 'l'
+ && rcp[1] == 's'
+ && rcp[2] == 'e'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ return ELSE;
+ }
+ if (rcp[0] == 'n'
+ && rcp[1] == 'u'
+ && rcp[2] == 'm'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ return ENUM;
+ }
+ if (rcp[0] == 'x'
+ && rcp[1] == 't'
+ && rcp[2] == 'e'
+ && rcp[3] == 'r'
+ && rcp[4] == 'n'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ return EXTERN;
+ }
+ goto id;
+ case 'f':
+ if (rcp[0] == 'l'
+ && rcp[1] == 'o'
+ && rcp[2] == 'a'
+ && rcp[3] == 't'
+ && !(map[rcp[4]]&(DIGIT|LETTER))) {
+ cp = rcp + 4;
+ tsym = floattype->u.sym;
+ return FLOAT;
+ }
+ if (rcp[0] == 'o'
+ && rcp[1] == 'r'
+ && !(map[rcp[2]]&(DIGIT|LETTER))) {
+ cp = rcp + 2;
+ return FOR;
+ }
+ goto id;
+ case 'g':
+ if (rcp[0] == 'o'
+ && rcp[1] == 't'
+ && rcp[2] == 'o'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ return GOTO;
+ }
+ goto id;
+ case 'l':
+ if (rcp[0] == 'o'
+ && rcp[1] == 'n'
+ && rcp[2] == 'g'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ return LONG;
+ }
+ goto id;
+ case 'r':
+ if (rcp[0] == 'e'
+ && rcp[1] == 'g'
+ && rcp[2] == 'i'
+ && rcp[3] == 's'
+ && rcp[4] == 't'
+ && rcp[5] == 'e'
+ && rcp[6] == 'r'
+ && !(map[rcp[7]]&(DIGIT|LETTER))) {
+ cp = rcp + 7;
+ return REGISTER;
+ }
+ if (rcp[0] == 'e'
+ && rcp[1] == 't'
+ && rcp[2] == 'u'
+ && rcp[3] == 'r'
+ && rcp[4] == 'n'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ return RETURN;
+ }
+ goto id;
+ case 's':
+ if (rcp[0] == 'h'
+ && rcp[1] == 'o'
+ && rcp[2] == 'r'
+ && rcp[3] == 't'
+ && !(map[rcp[4]]&(DIGIT|LETTER))) {
+ cp = rcp + 4;
+ return SHORT;
+ }
+ if (rcp[0] == 'i'
+ && rcp[1] == 'g'
+ && rcp[2] == 'n'
+ && rcp[3] == 'e'
+ && rcp[4] == 'd'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ return SIGNED;
+ }
+ if (rcp[0] == 'i'
+ && rcp[1] == 'z'
+ && rcp[2] == 'e'
+ && rcp[3] == 'o'
+ && rcp[4] == 'f'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ return SIZEOF;
+ }
+ if (rcp[0] == 't'
+ && rcp[1] == 'a'
+ && rcp[2] == 't'
+ && rcp[3] == 'i'
+ && rcp[4] == 'c'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ return STATIC;
+ }
+ if (rcp[0] == 't'
+ && rcp[1] == 'r'
+ && rcp[2] == 'u'
+ && rcp[3] == 'c'
+ && rcp[4] == 't'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ return STRUCT;
+ }
+ if (rcp[0] == 'w'
+ && rcp[1] == 'i'
+ && rcp[2] == 't'
+ && rcp[3] == 'c'
+ && rcp[4] == 'h'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ return SWITCH;
+ }
+ goto id;
+ case 't':
+ if (rcp[0] == 'y'
+ && rcp[1] == 'p'
+ && rcp[2] == 'e'
+ && rcp[3] == 'd'
+ && rcp[4] == 'e'
+ && rcp[5] == 'f'
+ && !(map[rcp[6]]&(DIGIT|LETTER))) {
+ cp = rcp + 6;
+ return TYPEDEF;
+ }
+ goto id;
+ case 'u':
+ if (rcp[0] == 'n'
+ && rcp[1] == 'i'
+ && rcp[2] == 'o'
+ && rcp[3] == 'n'
+ && !(map[rcp[4]]&(DIGIT|LETTER))) {
+ cp = rcp + 4;
+ return UNION;
+ }
+ if (rcp[0] == 'n'
+ && rcp[1] == 's'
+ && rcp[2] == 'i'
+ && rcp[3] == 'g'
+ && rcp[4] == 'n'
+ && rcp[5] == 'e'
+ && rcp[6] == 'd'
+ && !(map[rcp[7]]&(DIGIT|LETTER))) {
+ cp = rcp + 7;
+ return UNSIGNED;
+ }
+ goto id;
+ case 'v':
+ if (rcp[0] == 'o'
+ && rcp[1] == 'i'
+ && rcp[2] == 'd'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ tsym = voidtype->u.sym;
+ return VOID;
+ }
+ if (rcp[0] == 'o'
+ && rcp[1] == 'l'
+ && rcp[2] == 'a'
+ && rcp[3] == 't'
+ && rcp[4] == 'i'
+ && rcp[5] == 'l'
+ && rcp[6] == 'e'
+ && !(map[rcp[7]]&(DIGIT|LETTER))) {
+ cp = rcp + 7;
+ return VOLATILE;
+ }
+ goto id;
+ case 'w':
+ if (rcp[0] == 'h'
+ && rcp[1] == 'i'
+ && rcp[2] == 'l'
+ && rcp[3] == 'e'
+ && !(map[rcp[4]]&(DIGIT|LETTER))) {
+ cp = rcp + 4;
+ return WHILE;
+ }
+ goto id;
+ case '_':
+ if (rcp[0] == '_'
+ && rcp[1] == 't'
+ && rcp[2] == 'y'
+ && rcp[3] == 'p'
+ && rcp[4] == 'e'
+ && rcp[5] == 'c'
+ && rcp[6] == 'o'
+ && rcp[7] == 'd'
+ && rcp[8] == 'e'
+ && !(map[rcp[9]]&(DIGIT|LETTER))) {
+ cp = rcp + 9;
+ return TYPECODE;
+ }
+ if (rcp[0] == '_'
+ && rcp[1] == 'f'
+ && rcp[2] == 'i'
+ && rcp[3] == 'r'
+ && rcp[4] == 's'
+ && rcp[5] == 't'
+ && rcp[6] == 'a'
+ && rcp[7] == 'r'
+ && rcp[8] == 'g'
+ && !(map[rcp[9]]&(DIGIT|LETTER))) {
+ cp = rcp + 9;
+ return FIRSTARG;
+ }
+ goto id;
+ default:
+ if ((map[cp[-1]]&BLANK) == 0)
+ if (cp[-1] < ' ' || cp[-1] >= 0177)
+ error("illegal character `\\0%o'\n", cp[-1]);
+ else
+ error("illegal character `%c'\n", cp[-1]);
+ }
+ }
+}
+static Symbol icon(unsigned long n, int overflow, int base) {
+ if ((*cp=='u'||*cp=='U') && (cp[1]=='l'||cp[1]=='L')
+ || (*cp=='l'||*cp=='L') && (cp[1]=='u'||cp[1]=='U')) {
+ tval.type = unsignedlong;
+ cp += 2;
+ } else if (*cp == 'u' || *cp == 'U') {
+ if (overflow || n > unsignedtype->u.sym->u.limits.max.i)
+ tval.type = unsignedlong;
+ else
+ tval.type = unsignedtype;
+ cp += 1;
+ } else if (*cp == 'l' || *cp == 'L') {
+ if (overflow || n > longtype->u.sym->u.limits.max.i)
+ tval.type = unsignedlong;
+ else
+ tval.type = longtype;
+ cp += 1;
+ } else if (overflow || n > longtype->u.sym->u.limits.max.i)
+ tval.type = unsignedlong;
+ else if (n > inttype->u.sym->u.limits.max.i)
+ tval.type = longtype;
+ else if (base != 10 && n > inttype->u.sym->u.limits.max.i)
+ tval.type = unsignedtype;
+ else
+ tval.type = inttype;
+ switch (tval.type->op) {
+ case INT:
+ if (overflow || n > tval.type->u.sym->u.limits.max.i) {
+ warning("overflow in constant `%S'\n", token,
+ (char*)cp - token);
+ tval.u.c.v.i = tval.type->u.sym->u.limits.max.i;
+ } else
+ tval.u.c.v.i = n;
+ break;
+ case UNSIGNED:
+ if (overflow || n > tval.type->u.sym->u.limits.max.u) {
+ warning("overflow in constant `%S'\n", token,
+ (char*)cp - token);
+ tval.u.c.v.u = tval.type->u.sym->u.limits.max.u;
+ } else
+ tval.u.c.v.u = n;
+ break;
+ default: assert(0);
+ }
+ ppnumber("integer");
+ return &tval;
+}
+static void ppnumber(char *which) {
+ unsigned char *rcp = cp--;
+
+ for ( ; (map[*cp]&(DIGIT|LETTER)) || *cp == '.'; cp++)
+ if ((cp[0] == 'E' || cp[0] == 'e')
+ && (cp[1] == '-' || cp[1] == '+'))
+ cp++;
+ if (cp > rcp)
+ error("`%S' is a preprocessing number but an invalid %s constant\n", token,
+
+ (char*)cp-token, which);
+}
+static Symbol fcon(void) {
+ if (*cp == '.')
+ do
+ cp++;
+ while (map[*cp]&DIGIT);
+ if (*cp == 'e' || *cp == 'E') {
+ if (*++cp == '-' || *cp == '+')
+ cp++;
+ if (map[*cp]&DIGIT)
+ do
+ cp++;
+ while (map[*cp]&DIGIT);
+ else
+ error("invalid floating constant `%S'\n", token,
+ (char*)cp - token);
+ }
+
+ errno = 0;
+ tval.u.c.v.d = strtod(token, NULL);
+ if (errno == ERANGE)
+ warning("overflow in floating constant `%S'\n", token,
+ (char*)cp - token);
+ if (*cp == 'f' || *cp == 'F') {
+ ++cp;
+ if (tval.u.c.v.d > floattype->u.sym->u.limits.max.d)
+ warning("overflow in floating constant `%S'\n", token,
+ (char*)cp - token);
+ tval.type = floattype;
+ } else if (*cp == 'l' || *cp == 'L') {
+ cp++;
+ tval.type = longdouble;
+ } else {
+ if (tval.u.c.v.d > doubletype->u.sym->u.limits.max.d)
+ warning("overflow in floating constant `%S'\n", token,
+ (char*)cp - token);
+ tval.type = doubletype;
+ }
+ ppnumber("floating");
+ return &tval;
+}
+
+static void *cput(int c, void *cl) {
+ char *s = cl;
+
+ if (c < 0 || c > 255)
+ warning("overflow in escape sequence with resulting value `%d'\n", c);
+ *s++ = c;
+ return s;
+}
+
+static void *wcput(int c, void *cl) {
+ unsigned int *s = cl;
+
+ *s++ = c;
+ return s;
+}
+
+static void *scon(int q, void *put(int c, void *cl), void *cl) {
+ int n = 0, nbad = 0;
+
+ do {
+ cp++;
+ while (*cp != q) {
+ int c;
+ if (map[*cp]&NEWLINE) {
+ if (cp < limit)
+ break;
+ cp++;
+ nextline();
+ if (cp == limit)
+ break;
+ continue;
+ }
+ c = *cp++;
+ if (c == '\\') {
+ if (map[*cp]&NEWLINE) {
+ if (cp < limit)
+ break;
+ cp++;
+ nextline();
+ }
+ if (limit - cp < MAXTOKEN)
+ fillbuf();
+ c = backslash(q);
+ } else if (c < 0 || c > 255 || map[c] == 0)
+ nbad++;
+ if (n++ < BUFSIZE)
+ cl = put(c, cl);
+ }
+ if (*cp == q)
+ cp++;
+ else
+ error("missing %c\n", q);
+ } while (q == '"' && getchr() == '"');
+ cl = put(0, cl);
+ if (n >= BUFSIZE)
+ error("%s literal too long\n", q == '"' ? "string" : "character");
+ if (Aflag >= 2 && q == '"' && n > 509)
+ warning("more than 509 characters in a string literal\n");
+ if (Aflag >= 2 && nbad > 0)
+ warning("%s literal contains non-portable characters\n",
+ q == '"' ? "string" : "character");
+ return cl;
+}
+int getchr(void) {
+ for (;;) {
+ while (map[*cp]&BLANK)
+ cp++;
+ if (!(map[*cp]&NEWLINE))
+ return *cp;
+ cp++;
+ nextline();
+ if (cp == limit)
+ return EOI;
+ }
+}
+static int backslash(int q) {
+ unsigned int c;
+
+ switch (*cp++) {
+ case 'a': return 7;
+ case 'b': return '\b';
+ case 'f': return '\f';
+ case 'n': return '\n';
+ case 'r': return '\r';
+ case 't': return '\t';
+ case 'v': return '\v';
+ case '\'': case '"': case '\\': case '\?': break;
+ case 'x': {
+ int overflow = 0;
+ if ((map[*cp]&(DIGIT|HEX)) == 0) {
+ if (*cp < ' ' || *cp == 0177)
+ error("ill-formed hexadecimal escape sequence\n");
+ else
+ error("ill-formed hexadecimal escape sequence `\\x%c'\n", *cp);
+ if (*cp != q)
+ cp++;
+ return 0;
+ }
+ for (c = 0; map[*cp]&(DIGIT|HEX); cp++) {
+ if (c >> (8*widechar->size - 4))
+ overflow = 1;
+ if (map[*cp]&DIGIT)
+ c = (c<<4) + *cp - '0';
+ else
+ c = (c<<4) + (*cp&~040) - 'A' + 10;
+ }
+ if (overflow)
+ warning("overflow in hexadecimal escape sequence\n");
+ return c&ones(8*widechar->size);
+ }
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c = *(cp-1) - '0';
+ if (*cp >= '0' && *cp <= '7') {
+ c = (c<<3) + *cp++ - '0';
+ if (*cp >= '0' && *cp <= '7')
+ c = (c<<3) + *cp++ - '0';
+ }
+ return c;
+ default:
+ if (cp[-1] < ' ' || cp[-1] >= 0177)
+ warning("unrecognized character escape sequence\n");
+ else
+ warning("unrecognized character escape sequence `\\%c'\n", cp[-1]);
+ }
+ return cp[-1];
+}
diff --git a/lcc/src/list.c b/lcc/src/list.c
new file mode 100755
index 0000000..dbd63ed
--- /dev/null
+++ b/lcc/src/list.c
@@ -0,0 +1,56 @@
+#include "c.h"
+
+
+static List freenodes; /* free list nodes */
+
+/* append - append x to list, return new list */
+List append(void *x, List list) {
+ List new;
+
+ if ((new = freenodes) != NULL)
+ freenodes = freenodes->link;
+ else
+ NEW(new, PERM);
+ if (list) {
+ new->link = list->link;
+ list->link = new;
+ } else
+ new->link = new;
+ new->x = x;
+ return new;
+}
+
+/* length - # elements in list */
+int length(List list) {
+ int n = 0;
+
+ if (list) {
+ List lp = list;
+ do
+ n++;
+ while ((lp = lp->link) != list);
+ }
+ return n;
+}
+
+/* ltov - convert list to an NULL-terminated vector allocated in arena */
+void *ltov(List *list, unsigned arena) {
+ int i = 0;
+ void **array = newarray(length(*list) + 1, sizeof array[0], arena);
+
+ if (*list) {
+ List lp = *list;
+ do {
+ lp = lp->link;
+ array[i++] = lp->x;
+ } while (lp != *list);
+#ifndef PURIFY
+ lp = (*list)->link;
+ (*list)->link = freenodes;
+ freenodes = lp;
+#endif
+ }
+ *list = NULL;
+ array[i] = NULL;
+ return array;
+}
diff --git a/lcc/src/main.c b/lcc/src/main.c
new file mode 100755
index 0000000..1367fa0
--- /dev/null
+++ b/lcc/src/main.c
@@ -0,0 +1,225 @@
+#include "c.h"
+
+static char rcsid[] = "main.c - faked rcsid";
+
+static void typestab(Symbol, void *);
+
+static void stabline(Coordinate *);
+static void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *);
+Interface *IR = NULL;
+
+int Aflag; /* >= 0 if -A specified */
+int Pflag; /* != 0 if -P specified */
+int glevel; /* == [0-9] if -g[0-9] specified */
+int xref; /* != 0 for cross-reference data */
+Symbol YYnull; /* _YYnull symbol if -n or -nvalidate specified */
+Symbol YYcheck; /* _YYcheck symbol if -nvalidate,check specified */
+
+static char *comment;
+static Interface stabIR;
+static char *currentfile; /* current file name */
+static int currentline; /* current line number */
+static FILE *srcfp; /* stream for current file, if non-NULL */
+static int srcpos; /* position of srcfp, if srcfp is non-NULL */
+int main(int argc, char *argv[]) {
+ int i, j;
+ for (i = argc - 1; i > 0; i--)
+ if (strncmp(argv[i], "-target=", 8) == 0)
+ break;
+ if (i > 0) {
+ char *s = strchr(argv[i], '\\');
+ if (s != NULL)
+ *s = '/';
+ for (j = 0; bindings[j].name && bindings[j].ir; j++)
+ if (strcmp(&argv[i][8], bindings[j].name) == 0) {
+ IR = bindings[j].ir;
+ break;
+ }
+ if (s != NULL)
+ *s = '\\';
+ }
+ if (!IR) {
+ fprint(stderr, "%s: unknown target", argv[0]);
+ if (i > 0)
+ fprint(stderr, " `%s'", &argv[i][8]);
+ fprint(stderr, "; must specify one of\n");
+ for (i = 0; bindings[i].name; i++)
+ fprint(stderr, "\t-target=%s\n", bindings[i].name);
+ exit(EXIT_FAILURE);
+ }
+ init(argc, argv);
+ t = gettok();
+ (*IR->progbeg)(argc, argv);
+ if (glevel && IR->stabinit)
+ (*IR->stabinit)(firstfile, argc, argv);
+ program();
+ if (events.end)
+ apply(events.end, NULL, NULL);
+ memset(&events, 0, sizeof events);
+ if (glevel || xref) {
+ Symbol symroot = NULL;
+ Coordinate src;
+ foreach(types, GLOBAL, typestab, &symroot);
+ foreach(identifiers, GLOBAL, typestab, &symroot);
+ src.file = firstfile;
+ src.x = 0;
+ src.y = lineno;
+ if ((glevel > 2 || xref) && IR->stabend)
+ (*IR->stabend)(&src, symroot,
+ ltov(&loci, PERM),
+ ltov(&symbols, PERM), NULL);
+ else if (IR->stabend)
+ (*IR->stabend)(&src, NULL, NULL, NULL, NULL);
+ }
+ finalize();
+ (*IR->progend)();
+ deallocate(PERM);
+ return errcnt > 0;
+}
+/* main_init - process program arguments */
+void main_init(int argc, char *argv[]) {
+ char *infile = NULL, *outfile = NULL;
+ int i;
+ static int inited;
+
+ if (inited)
+ return;
+ inited = 1;
+ type_init(argc, argv);
+ for (i = 1; i < argc; i++)
+ if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "-g2") == 0)
+ glevel = 2;
+ else if (strncmp(argv[i], "-g", 2) == 0) { /* -gn[,x] */
+ char *p = strchr(argv[i], ',');
+ glevel = atoi(argv[i]+2);
+ if (p) {
+ comment = p + 1;
+ if (glevel == 0)
+ glevel = 1;
+ if (stabIR.stabline == NULL) {
+ stabIR.stabline = IR->stabline;
+ stabIR.stabend = IR->stabend;
+ IR->stabline = stabline;
+ IR->stabend = stabend;
+ }
+ }
+ } else if (strcmp(argv[i], "-x") == 0)
+ xref++;
+ else if (strcmp(argv[i], "-A") == 0) {
+ ++Aflag;
+ } else if (strcmp(argv[i], "-P") == 0)
+ Pflag++;
+ else if (strcmp(argv[i], "-w") == 0)
+ wflag++;
+ else if (strcmp(argv[i], "-n") == 0) {
+ if (!YYnull) {
+ YYnull = install(string("_YYnull"), &globals, GLOBAL, PERM);
+ YYnull->type = func(voidptype, NULL, 1);
+ YYnull->sclass = EXTERN;
+ (*IR->defsymbol)(YYnull);
+ }
+ } else if (strncmp(argv[i], "-n", 2) == 0) { /* -nvalid[,check] */
+ char *p = strchr(argv[i], ',');
+ if (p) {
+ YYcheck = install(string(p+1), &globals, GLOBAL, PERM);
+ YYcheck->type = func(voidptype, NULL, 1);
+ YYcheck->sclass = EXTERN;
+ (*IR->defsymbol)(YYcheck);
+ p = stringn(argv[i]+2, p - (argv[i]+2));
+ } else
+ p = string(argv[i]+2);
+ YYnull = install(p, &globals, GLOBAL, PERM);
+ YYnull->type = func(voidptype, NULL, 1);
+ YYnull->sclass = EXTERN;
+ (*IR->defsymbol)(YYnull);
+ } else if (strcmp(argv[i], "-v") == 0)
+ fprint(stderr, "%s %s\n", argv[0], rcsid);
+ else if (strncmp(argv[i], "-s", 2) == 0)
+ density = strtod(&argv[i][2], NULL);
+ else if (strncmp(argv[i], "-errout=", 8) == 0) {
+ FILE *f = fopen(argv[i]+8, "w");
+ if (f == NULL) {
+ fprint(stderr, "%s: can't write errors to `%s'\n", argv[0], argv[i]+8);
+ exit(EXIT_FAILURE);
+ }
+ fclose(f);
+ f = freopen(argv[i]+8, "w", stderr);
+ assert(f);
+ } else if (strncmp(argv[i], "-e", 2) == 0) {
+ int x;
+ if ((x = strtol(&argv[i][2], NULL, 0)) > 0)
+ errlimit = x;
+ } else if (strncmp(argv[i], "-little_endian=", 15) == 0)
+ IR->little_endian = argv[i][15] - '0';
+ else if (strncmp(argv[i], "-mulops_calls=", 18) == 0)
+ IR->mulops_calls = argv[i][18] - '0';
+ else if (strncmp(argv[i], "-wants_callb=", 13) == 0)
+ IR->wants_callb = argv[i][13] - '0';
+ else if (strncmp(argv[i], "-wants_argb=", 12) == 0)
+ IR->wants_argb = argv[i][12] - '0';
+ else if (strncmp(argv[i], "-left_to_right=", 15) == 0)
+ IR->left_to_right = argv[i][15] - '0';
+ else if (strncmp(argv[i], "-wants_dag=", 11) == 0)
+ IR->wants_dag = argv[i][11] - '0';
+ else if (*argv[i] != '-' || strcmp(argv[i], "-") == 0) {
+ if (infile == NULL)
+ infile = argv[i];
+ else if (outfile == NULL)
+ outfile = argv[i];
+ }
+
+ if (infile != NULL && strcmp(infile, "-") != 0
+ && freopen(infile, "r", stdin) == NULL) {
+ fprint(stderr, "%s: can't read `%s'\n", argv[0], infile);
+ exit(EXIT_FAILURE);
+ }
+ if (outfile != NULL && strcmp(outfile, "-") != 0
+ && freopen(outfile, "w", stdout) == NULL) {
+ fprint(stderr, "%s: can't write `%s'\n", argv[0], outfile);
+ exit(EXIT_FAILURE);
+ }
+}
+/* typestab - emit stab entries for p */
+static void typestab(Symbol p, void *cl) {
+ if (*(Symbol *)cl == 0 && p->sclass && p->sclass != TYPEDEF)
+ *(Symbol *)cl = p;
+ if ((p->sclass == TYPEDEF || p->sclass == 0) && IR->stabtype)
+ (*IR->stabtype)(p);
+}
+
+/* stabline - emit source code for source coordinate *cp */
+static void stabline(Coordinate *cp) {
+ if (cp->file && cp->file != currentfile) {
+ if (srcfp)
+ fclose(srcfp);
+ currentfile = cp->file;
+ srcfp = fopen(currentfile, "r");
+ srcpos = 0;
+ currentline = 0;
+ }
+ if (currentline != cp->y && srcfp) {
+ char buf[512];
+ if (srcpos > cp->y) {
+ rewind(srcfp);
+ srcpos = 0;
+ }
+ for ( ; srcpos < cp->y; srcpos++)
+ if (fgets(buf, sizeof buf, srcfp) == NULL) {
+ fclose(srcfp);
+ srcfp = NULL;
+ break;
+ }
+ if (srcfp && srcpos == cp->y)
+ print("%s%s", comment, buf);
+ }
+ currentline = cp->y;
+ if (stabIR.stabline)
+ (*stabIR.stabline)(cp);
+}
+
+static void stabend(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {
+ if (stabIR.stabend)
+ (*stabIR.stabend)(cp, p, cpp, sp, stab);
+ if (srcfp)
+ fclose(srcfp);
+}
diff --git a/lcc/src/mips.md b/lcc/src/mips.md
new file mode 100755
index 0000000..7e643fb
--- /dev/null
+++ b/lcc/src/mips.md
@@ -0,0 +1,1120 @@
+%{
+#define INTTMP 0x0100ff00
+#define INTVAR 0x40ff0000
+#define FLTTMP 0x000f0ff0
+#define FLTVAR 0xfff00000
+
+#define INTRET 0x00000004
+#define FLTRET 0x00000003
+
+#define readsreg(p) \
+ (generic((p)->op)==INDIR && (p)->kids[0]->op==VREG+P)
+#define setsrc(d) ((d) && (d)->x.regnode && \
+ (d)->x.regnode->set == src->x.regnode->set && \
+ (d)->x.regnode->mask&src->x.regnode->mask)
+
+#define relink(a, b) ((b)->x.prev = (a), (a)->x.next = (b))
+
+#include "c.h"
+#define NODEPTR_TYPE Node
+#define OP_LABEL(p) ((p)->op)
+#define LEFT_CHILD(p) ((p)->kids[0])
+#define RIGHT_CHILD(p) ((p)->kids[1])
+#define STATE_LABEL(p) ((p)->x.state)
+static void address(Symbol, Symbol, long);
+static void blkfetch(int, int, int, int);
+static void blkloop(int, int, int, int, int, int[]);
+static void blkstore(int, int, int, int);
+static void defaddress(Symbol);
+static void defconst(int, int, Value);
+static void defstring(int, char *);
+static void defsymbol(Symbol);
+static void doarg(Node);
+static void emit2(Node);
+static void export(Symbol);
+static void clobber(Node);
+static void function(Symbol, Symbol [], Symbol [], int);
+static void global(Symbol);
+static void import(Symbol);
+static void local(Symbol);
+static void progbeg(int, char **);
+static void progend(void);
+static void segment(int);
+static void space(int);
+static void target(Node);
+static int bitcount (unsigned);
+static Symbol argreg (int, int, int, int, int);
+
+static Symbol ireg[32], freg2[32], d6;
+static Symbol iregw, freg2w;
+static int tmpregs[] = {3, 9, 10};
+static Symbol blkreg;
+
+static int gnum = 8;
+static int pic;
+
+static int cseg;
+%}
+%start stmt
+%term CNSTF4=4113
+%term CNSTF8=8209
+%term CNSTF16=16401
+%term CNSTI1=1045
+%term CNSTI2=2069
+%term CNSTI4=4117
+%term CNSTI8=8213
+%term CNSTP4=4119
+%term CNSTP8=8215
+%term CNSTU1=1046
+%term CNSTU2=2070
+%term CNSTU4=4118
+%term CNSTU8=8214
+
+%term ARGB=41
+%term ARGF4=4129
+%term ARGF8=8225
+%term ARGF16=16417
+%term ARGI4=4133
+%term ARGI8=8229
+%term ARGP4=4135
+%term ARGP8=8231
+%term ARGU4=4134
+%term ARGU8=8230
+
+%term ASGNB=57
+%term ASGNF4=4145
+%term ASGNF8=8241
+%term ASGNF16=16433
+%term ASGNI1=1077
+%term ASGNI2=2101
+%term ASGNI4=4149
+%term ASGNI8=8245
+%term ASGNP4=4151
+%term ASGNP8=8247
+%term ASGNU1=1078
+%term ASGNU2=2102
+%term ASGNU4=4150
+%term ASGNU8=8246
+
+%term INDIRB=73
+%term INDIRF4=4161
+%term INDIRF8=8257
+%term INDIRF16=16449
+%term INDIRI1=1093
+%term INDIRI2=2117
+%term INDIRI4=4165
+%term INDIRI8=8261
+%term INDIRP4=4167
+%term INDIRP8=8263
+%term INDIRU1=1094
+%term INDIRU2=2118
+%term INDIRU4=4166
+%term INDIRU8=8262
+
+%term CVFF4=4209
+%term CVFF8=8305
+%term CVFF16=16497
+%term CVFI4=4213
+%term CVFI8=8309
+
+%term CVIF4=4225
+%term CVIF8=8321
+%term CVIF16=16513
+%term CVII1=1157
+%term CVII2=2181
+%term CVII4=4229
+%term CVII8=8325
+%term CVIU1=1158
+%term CVIU2=2182
+%term CVIU4=4230
+%term CVIU8=8326
+
+%term CVPP4=4247
+%term CVPP8=8343
+%term CVPP16=16535
+%term CVPU4=4246
+%term CVPU8=8342
+
+%term CVUI1=1205
+%term CVUI2=2229
+%term CVUI4=4277
+%term CVUI8=8373
+%term CVUP4=4279
+%term CVUP8=8375
+%term CVUP16=16567
+%term CVUU1=1206
+%term CVUU2=2230
+%term CVUU4=4278
+%term CVUU8=8374
+
+%term NEGF4=4289
+%term NEGF8=8385
+%term NEGF16=16577
+%term NEGI4=4293
+%term NEGI8=8389
+
+%term CALLB=217
+%term CALLF4=4305
+%term CALLF8=8401
+%term CALLF16=16593
+%term CALLI4=4309
+%term CALLI8=8405
+%term CALLP4=4311
+%term CALLP8=8407
+%term CALLU4=4310
+%term CALLU8=8406
+%term CALLV=216
+
+%term RETF4=4337
+%term RETF8=8433
+%term RETF16=16625
+%term RETI4=4341
+%term RETI8=8437
+%term RETP4=4343
+%term RETP8=8439
+%term RETU4=4342
+%term RETU8=8438
+%term RETV=248
+
+%term ADDRGP4=4359
+%term ADDRGP8=8455
+
+%term ADDRFP4=4375
+%term ADDRFP8=8471
+
+%term ADDRLP4=4391
+%term ADDRLP8=8487
+
+%term ADDF4=4401
+%term ADDF8=8497
+%term ADDF16=16689
+%term ADDI4=4405
+%term ADDI8=8501
+%term ADDP4=4407
+%term ADDP8=8503
+%term ADDU4=4406
+%term ADDU8=8502
+
+%term SUBF4=4417
+%term SUBF8=8513
+%term SUBF16=16705
+%term SUBI4=4421
+%term SUBI8=8517
+%term SUBP4=4423
+%term SUBP8=8519
+%term SUBU4=4422
+%term SUBU8=8518
+
+%term LSHI4=4437
+%term LSHI8=8533
+%term LSHU4=4438
+%term LSHU8=8534
+
+%term MODI4=4453
+%term MODI8=8549
+%term MODU4=4454
+%term MODU8=8550
+
+%term RSHI4=4469
+%term RSHI8=8565
+%term RSHU4=4470
+%term RSHU8=8566
+
+%term BANDI4=4485
+%term BANDI8=8581
+%term BANDU4=4486
+%term BANDU8=8582
+
+%term BCOMI4=4501
+%term BCOMI8=8597
+%term BCOMU4=4502
+%term BCOMU8=8598
+
+%term BORI4=4517
+%term BORI8=8613
+%term BORU4=4518
+%term BORU8=8614
+
+%term BXORI4=4533
+%term BXORI8=8629
+%term BXORU4=4534
+%term BXORU8=8630
+
+%term DIVF4=4545
+%term DIVF8=8641
+%term DIVF16=16833
+%term DIVI4=4549
+%term DIVI8=8645
+%term DIVU4=4550
+%term DIVU8=8646
+
+%term MULF4=4561
+%term MULF8=8657
+%term MULF16=16849
+%term MULI4=4565
+%term MULI8=8661
+%term MULU4=4566
+%term MULU8=8662
+
+%term EQF4=4577
+%term EQF8=8673
+%term EQF16=16865
+%term EQI4=4581
+%term EQI8=8677
+%term EQU4=4582
+%term EQU8=8678
+
+%term GEF4=4593
+%term GEF8=8689
+%term GEI4=4597
+%term GEI8=8693
+%term GEI16=16885
+%term GEU4=4598
+%term GEU8=8694
+
+%term GTF4=4609
+%term GTF8=8705
+%term GTF16=16897
+%term GTI4=4613
+%term GTI8=8709
+%term GTU4=4614
+%term GTU8=8710
+
+%term LEF4=4625
+%term LEF8=8721
+%term LEF16=16913
+%term LEI4=4629
+%term LEI8=8725
+%term LEU4=4630
+%term LEU8=8726
+
+%term LTF4=4641
+%term LTF8=8737
+%term LTF16=16929
+%term LTI4=4645
+%term LTI8=8741
+%term LTU4=4646
+%term LTU8=8742
+
+%term NEF4=4657
+%term NEF8=8753
+%term NEF16=16945
+%term NEI4=4661
+%term NEI8=8757
+%term NEU4=4662
+%term NEU8=8758
+
+%term JUMPV=584
+
+%term LABELV=600
+
+%term LOADB=233
+%term LOADF4=4321
+%term LOADF8=8417
+%term LOADF16=16609
+%term LOADI1=1253
+%term LOADI2=2277
+%term LOADI4=4325
+%term LOADI8=8421
+%term LOADP4=4327
+%term LOADP8=8423
+%term LOADU1=1254
+%term LOADU2=2278
+%term LOADU4=4326
+%term LOADU8=8422
+
+%term VREGP=711
+%%
+reg: INDIRI1(VREGP) "# read register\n"
+reg: INDIRU1(VREGP) "# read register\n"
+
+reg: INDIRI2(VREGP) "# read register\n"
+reg: INDIRU2(VREGP) "# read register\n"
+
+reg: INDIRF4(VREGP) "# read register\n"
+reg: INDIRI4(VREGP) "# read register\n"
+reg: INDIRP4(VREGP) "# read register\n"
+reg: INDIRU4(VREGP) "# read register\n"
+
+reg: INDIRF8(VREGP) "# read register\n"
+reg: INDIRI8(VREGP) "# read register\n"
+reg: INDIRP8(VREGP) "# read register\n"
+reg: INDIRU8(VREGP) "# read register\n"
+
+stmt: ASGNI1(VREGP,reg) "# write register\n"
+stmt: ASGNU1(VREGP,reg) "# write register\n"
+
+stmt: ASGNI2(VREGP,reg) "# write register\n"
+stmt: ASGNU2(VREGP,reg) "# write register\n"
+
+stmt: ASGNF4(VREGP,reg) "# write register\n"
+stmt: ASGNI4(VREGP,reg) "# write register\n"
+stmt: ASGNP4(VREGP,reg) "# write register\n"
+stmt: ASGNU4(VREGP,reg) "# write register\n"
+
+stmt: ASGNF8(VREGP,reg) "# write register\n"
+stmt: ASGNI8(VREGP,reg) "# write register\n"
+stmt: ASGNP8(VREGP,reg) "# write register\n"
+stmt: ASGNU8(VREGP,reg) "# write register\n"
+con: CNSTI1 "%a"
+con: CNSTU1 "%a"
+
+con: CNSTI2 "%a"
+con: CNSTU2 "%a"
+
+con: CNSTI4 "%a"
+con: CNSTU4 "%a"
+con: CNSTP4 "%a"
+
+con: CNSTI8 "%a"
+con: CNSTU8 "%a"
+con: CNSTP8 "%a"
+stmt: reg ""
+acon: con "%0"
+acon: ADDRGP4 "%a"
+addr: ADDI4(reg,acon) "%1($%0)"
+addr: ADDU4(reg,acon) "%1($%0)"
+addr: ADDP4(reg,acon) "%1($%0)"
+addr: acon "%0"
+addr: reg "($%0)"
+addr: ADDRFP4 "%a+%F($sp)"
+addr: ADDRLP4 "%a+%F($sp)"
+reg: addr "la $%c,%0\n" 1
+reg: CNSTI1 "# reg\n" range(a, 0, 0)
+reg: CNSTI2 "# reg\n" range(a, 0, 0)
+reg: CNSTI4 "# reg\n" range(a, 0, 0)
+reg: CNSTU1 "# reg\n" range(a, 0, 0)
+reg: CNSTU2 "# reg\n" range(a, 0, 0)
+reg: CNSTU4 "# reg\n" range(a, 0, 0)
+reg: CNSTP4 "# reg\n" range(a, 0, 0)
+stmt: ASGNI1(addr,reg) "sb $%1,%0\n" 1
+stmt: ASGNU1(addr,reg) "sb $%1,%0\n" 1
+stmt: ASGNI2(addr,reg) "sh $%1,%0\n" 1
+stmt: ASGNU2(addr,reg) "sh $%1,%0\n" 1
+stmt: ASGNI4(addr,reg) "sw $%1,%0\n" 1
+stmt: ASGNU4(addr,reg) "sw $%1,%0\n" 1
+stmt: ASGNP4(addr,reg) "sw $%1,%0\n" 1
+reg: INDIRI1(addr) "lb $%c,%0\n" 1
+reg: INDIRU1(addr) "lbu $%c,%0\n" 1
+reg: INDIRI2(addr) "lh $%c,%0\n" 1
+reg: INDIRU2(addr) "lhu $%c,%0\n" 1
+reg: INDIRI4(addr) "lw $%c,%0\n" 1
+reg: INDIRU4(addr) "lw $%c,%0\n" 1
+reg: INDIRP4(addr) "lw $%c,%0\n" 1
+
+reg: CVII4(INDIRI1(addr)) "lb $%c,%0\n" 1
+reg: CVII4(INDIRI2(addr)) "lh $%c,%0\n" 1
+reg: CVUU4(INDIRU1(addr)) "lbu $%c,%0\n" 1
+reg: CVUU4(INDIRU2(addr)) "lhu $%c,%0\n" 1
+reg: CVUI4(INDIRU1(addr)) "lbu $%c,%0\n" 1
+reg: CVUI4(INDIRU2(addr)) "lhu $%c,%0\n" 1
+reg: INDIRF4(addr) "l.s $f%c,%0\n" 1
+reg: INDIRF8(addr) "l.d $f%c,%0\n" 1
+stmt: ASGNF4(addr,reg) "s.s $f%1,%0\n" 1
+stmt: ASGNF8(addr,reg) "s.d $f%1,%0\n" 1
+reg: DIVI4(reg,reg) "div $%c,$%0,$%1\n" 1
+reg: DIVU4(reg,reg) "divu $%c,$%0,$%1\n" 1
+reg: MODI4(reg,reg) "rem $%c,$%0,$%1\n" 1
+reg: MODU4(reg,reg) "remu $%c,$%0,$%1\n" 1
+reg: MULI4(reg,reg) "mul $%c,$%0,$%1\n" 1
+reg: MULU4(reg,reg) "mul $%c,$%0,$%1\n" 1
+rc: con "%0"
+rc: reg "$%0"
+
+reg: ADDI4(reg,rc) "addu $%c,$%0,%1\n" 1
+reg: ADDP4(reg,rc) "addu $%c,$%0,%1\n" 1
+reg: ADDU4(reg,rc) "addu $%c,$%0,%1\n" 1
+reg: BANDI4(reg,rc) "and $%c,$%0,%1\n" 1
+reg: BORI4(reg,rc) "or $%c,$%0,%1\n" 1
+reg: BXORI4(reg,rc) "xor $%c,$%0,%1\n" 1
+reg: BANDU4(reg,rc) "and $%c,$%0,%1\n" 1
+reg: BORU4(reg,rc) "or $%c,$%0,%1\n" 1
+reg: BXORU4(reg,rc) "xor $%c,$%0,%1\n" 1
+reg: SUBI4(reg,rc) "subu $%c,$%0,%1\n" 1
+reg: SUBP4(reg,rc) "subu $%c,$%0,%1\n" 1
+reg: SUBU4(reg,rc) "subu $%c,$%0,%1\n" 1
+rc5: CNSTI4 "%a" range(a,0,31)
+rc5: reg "$%0"
+
+reg: LSHI4(reg,rc5) "sll $%c,$%0,%1\n" 1
+reg: LSHU4(reg,rc5) "sll $%c,$%0,%1\n" 1
+reg: RSHI4(reg,rc5) "sra $%c,$%0,%1\n" 1
+reg: RSHU4(reg,rc5) "srl $%c,$%0,%1\n" 1
+reg: BCOMI4(reg) "not $%c,$%0\n" 1
+reg: BCOMU4(reg) "not $%c,$%0\n" 1
+reg: NEGI4(reg) "negu $%c,$%0\n" 1
+reg: LOADI1(reg) "move $%c,$%0\n" move(a)
+reg: LOADU1(reg) "move $%c,$%0\n" move(a)
+reg: LOADI2(reg) "move $%c,$%0\n" move(a)
+reg: LOADU2(reg) "move $%c,$%0\n" move(a)
+reg: LOADI4(reg) "move $%c,$%0\n" move(a)
+reg: LOADP4(reg) "move $%c,$%0\n" move(a)
+reg: LOADU4(reg) "move $%c,$%0\n" move(a)
+reg: ADDF4(reg,reg) "add.s $f%c,$f%0,$f%1\n" 1
+reg: ADDF8(reg,reg) "add.d $f%c,$f%0,$f%1\n" 1
+reg: DIVF4(reg,reg) "div.s $f%c,$f%0,$f%1\n" 1
+reg: DIVF8(reg,reg) "div.d $f%c,$f%0,$f%1\n" 1
+reg: MULF4(reg,reg) "mul.s $f%c,$f%0,$f%1\n" 1
+reg: MULF8(reg,reg) "mul.d $f%c,$f%0,$f%1\n" 1
+reg: SUBF4(reg,reg) "sub.s $f%c,$f%0,$f%1\n" 1
+reg: SUBF8(reg,reg) "sub.d $f%c,$f%0,$f%1\n" 1
+reg: LOADF4(reg) "mov.s $f%c,$f%0\n" move(a)
+reg: LOADF8(reg) "mov.d $f%c,$f%0\n" move(a)
+reg: NEGF4(reg) "neg.s $f%c,$f%0\n" 1
+reg: NEGF8(reg) "neg.d $f%c,$f%0\n" 1
+reg: CVII4(reg) "sll $%c,$%0,8*(4-%a); sra $%c,$%c,8*(4-%a)\n" 2
+reg: CVUI4(reg) "and $%c,$%0,(1<<(8*%a))-1\n" 1
+reg: CVUU4(reg) "and $%c,$%0,(1<<(8*%a))-1\n" 1
+reg: CVFF4(reg) "cvt.s.d $f%c,$f%0\n" 1
+reg: CVFF8(reg) "cvt.d.s $f%c,$f%0\n" 1
+reg: CVIF4(reg) "mtc1 $%0,$f%c; cvt.s.w $f%c,$f%c\n" 2
+reg: CVIF8(reg) "mtc1 $%0,$f%c; cvt.d.w $f%c,$f%c\n" 2
+reg: CVFI4(reg) "trunc.w.s $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i==4?2:LBURG_MAX)
+reg: CVFI4(reg) "trunc.w.d $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i==8?2:LBURG_MAX)
+stmt: LABELV "%a:\n"
+stmt: JUMPV(acon) "b %0\n" 1
+stmt: JUMPV(reg) ".cpadd $%0\nj $%0\n" !pic
+stmt: JUMPV(reg) "j $%0\n" pic
+stmt: EQI4(reg,reg) "beq $%0,$%1,%a\n" 1
+stmt: EQU4(reg,reg) "beq $%0,$%1,%a\n" 1
+stmt: GEI4(reg,reg) "bge $%0,$%1,%a\n" 1
+stmt: GEU4(reg,reg) "bgeu $%0,$%1,%a\n" 1
+stmt: GTI4(reg,reg) "bgt $%0,$%1,%a\n" 1
+stmt: GTU4(reg,reg) "bgtu $%0,$%1,%a\n" 1
+stmt: LEI4(reg,reg) "ble $%0,$%1,%a\n" 1
+stmt: LEU4(reg,reg) "bleu $%0,$%1,%a\n" 1
+stmt: LTI4(reg,reg) "blt $%0,$%1,%a\n" 1
+stmt: LTU4(reg,reg) "bltu $%0,$%1,%a\n" 1
+stmt: NEI4(reg,reg) "bne $%0,$%1,%a\n" 1
+stmt: NEU4(reg,reg) "bne $%0,$%1,%a\n" 1
+stmt: EQF4(reg,reg) "c.eq.s $f%0,$f%1; bc1t %a\n" 2
+stmt: EQF8(reg,reg) "c.eq.d $f%0,$f%1; bc1t %a\n" 2
+stmt: LEF4(reg,reg) "c.le.s $f%0,$f%1; bc1t %a\n" 2
+stmt: LEF8(reg,reg) "c.le.d $f%0,$f%1; bc1t %a\n" 2
+stmt: LTF4(reg,reg) "c.lt.s $f%0,$f%1; bc1t %a\n" 2
+stmt: LTF8(reg,reg) "c.lt.d $f%0,$f%1; bc1t %a\n" 2
+stmt: GEF4(reg,reg) "c.lt.s $f%0,$f%1; bc1f %a\n" 2
+stmt: GEF8(reg,reg) "c.lt.d $f%0,$f%1; bc1f %a\n" 2
+stmt: GTF4(reg,reg) "c.le.s $f%0,$f%1; bc1f %a\n" 2
+stmt: GTF8(reg,reg) "c.le.d $f%0,$f%1; bc1f %a\n" 2
+stmt: NEF4(reg,reg) "c.eq.s $f%0,$f%1; bc1f %a\n" 2
+stmt: NEF8(reg,reg) "c.eq.d $f%0,$f%1; bc1f %a\n" 2
+ar: ADDRGP4 "%a"
+
+reg: CALLF4(ar) "jal %0\n" 1
+reg: CALLF8(ar) "jal %0\n" 1
+reg: CALLI4(ar) "jal %0\n" 1
+reg: CALLP4(ar) "jal %0\n" 1
+reg: CALLU4(ar) "jal %0\n" 1
+stmt: CALLV(ar) "jal %0\n" 1
+ar: reg "$%0"
+ar: CNSTP4 "%a" range(a, 0, 0x0fffffff)
+stmt: RETF4(reg) "# ret\n" 1
+stmt: RETF8(reg) "# ret\n" 1
+stmt: RETI4(reg) "# ret\n" 1
+stmt: RETU4(reg) "# ret\n" 1
+stmt: RETP4(reg) "# ret\n" 1
+stmt: RETV(reg) "# ret\n" 1
+stmt: ARGF4(reg) "# arg\n" 1
+stmt: ARGF8(reg) "# arg\n" 1
+stmt: ARGI4(reg) "# arg\n" 1
+stmt: ARGP4(reg) "# arg\n" 1
+stmt: ARGU4(reg) "# arg\n" 1
+
+stmt: ARGB(INDIRB(reg)) "# argb %0\n" 1
+stmt: ASGNB(reg,INDIRB(reg)) "# asgnb %0 %1\n" 1
+%%
+static void progend(void){}
+static void progbeg(int argc, char *argv[]) {
+ int i;
+
+ {
+ union {
+ char c;
+ int i;
+ } u;
+ u.i = 0;
+ u.c = 1;
+ swap = ((int)(u.i == 1)) != IR->little_endian;
+ }
+ print(".set reorder\n");
+ pic = !IR->little_endian;
+ parseflags(argc, argv);
+ for (i = 0; i < argc; i++)
+ if (strncmp(argv[i], "-G", 2) == 0)
+ gnum = atoi(argv[i] + 2);
+ else if (strcmp(argv[i], "-pic=1") == 0
+ || strcmp(argv[i], "-pic=0") == 0)
+ pic = argv[i][5]-'0';
+ for (i = 0; i < 31; i += 2)
+ freg2[i] = mkreg("%d", i, 3, FREG);
+ for (i = 0; i < 32; i++)
+ ireg[i] = mkreg("%d", i, 1, IREG);
+ ireg[29]->x.name = "sp";
+ d6 = mkreg("6", 6, 3, IREG);
+ freg2w = mkwildcard(freg2);
+ iregw = mkwildcard(ireg);
+ tmask[IREG] = INTTMP; tmask[FREG] = FLTTMP;
+ vmask[IREG] = INTVAR; vmask[FREG] = FLTVAR;
+ blkreg = mkreg("8", 8, 7, IREG);
+}
+static Symbol rmap(int opk) {
+ switch (optype(opk)) {
+ case I: case U: case P: case B:
+ return iregw;
+ case F:
+ return freg2w;
+ default:
+ return 0;
+ }
+}
+static void target(Node p) {
+ assert(p);
+ switch (specific(p->op)) {
+ case CNST+I: case CNST+U: case CNST+P:
+ if (range(p, 0, 0) == 0) {
+ setreg(p, ireg[0]);
+ p->x.registered = 1;
+ }
+ break;
+ case CALL+V:
+ rtarget(p, 0, ireg[25]);
+ break;
+ case CALL+F:
+ rtarget(p, 0, ireg[25]);
+ setreg(p, freg2[0]);
+ break;
+ case CALL+I: case CALL+P: case CALL+U:
+ rtarget(p, 0, ireg[25]);
+ setreg(p, ireg[2]);
+ break;
+ case RET+F:
+ rtarget(p, 0, freg2[0]);
+ break;
+ case RET+I: case RET+U: case RET+P:
+ rtarget(p, 0, ireg[2]);
+ break;
+ case ARG+F: case ARG+I: case ARG+P: case ARG+U: {
+ static int ty0;
+ int ty = optype(p->op);
+ Symbol q;
+
+ q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, opsize(p->op), ty0);
+ if (p->x.argno == 0)
+ ty0 = ty;
+ if (q &&
+ !(ty == F && q->x.regnode->set == IREG))
+ rtarget(p, 0, q);
+ break;
+ }
+ case ASGN+B: rtarget(p->kids[1], 0, blkreg); break;
+ case ARG+B: rtarget(p->kids[0], 0, blkreg); break;
+ }
+}
+static void clobber(Node p) {
+ assert(p);
+ switch (specific(p->op)) {
+ case CALL+F:
+ spill(INTTMP | INTRET, IREG, p);
+ spill(FLTTMP, FREG, p);
+ break;
+ case CALL+I: case CALL+P: case CALL+U:
+ spill(INTTMP, IREG, p);
+ spill(FLTTMP | FLTRET, FREG, p);
+ break;
+ case CALL+V:
+ spill(INTTMP | INTRET, IREG, p);
+ spill(FLTTMP | FLTRET, FREG, p);
+ break;
+ }
+}
+static void emit2(Node p) {
+ int dst, n, src, sz, ty;
+ static int ty0;
+ Symbol q;
+
+ switch (specific(p->op)) {
+ case ARG+F: case ARG+I: case ARG+P: case ARG+U:
+ ty = optype(p->op);
+ sz = opsize(p->op);
+ if (p->x.argno == 0)
+ ty0 = ty;
+ q = argreg(p->x.argno, p->syms[2]->u.c.v.i, ty, sz, ty0);
+ src = getregnum(p->x.kids[0]);
+ if (q == NULL && ty == F && sz == 4)
+ print("s.s $f%d,%d($sp)\n", src, p->syms[2]->u.c.v.i);
+ else if (q == NULL && ty == F)
+ print("s.d $f%d,%d($sp)\n", src, p->syms[2]->u.c.v.i);
+ else if (q == NULL)
+ print("sw $%d,%d($sp)\n", src, p->syms[2]->u.c.v.i);
+ else if (ty == F && sz == 4 && q->x.regnode->set == IREG)
+ print("mfc1 $%d,$f%d\n", q->x.regnode->number, src);
+ else if (ty == F && q->x.regnode->set == IREG)
+ print("mfc1.d $%d,$f%d\n", q->x.regnode->number, src);
+ break;
+ case ASGN+B:
+ dalign = salign = p->syms[1]->u.c.v.i;
+ blkcopy(getregnum(p->x.kids[0]), 0,
+ getregnum(p->x.kids[1]), 0,
+ p->syms[0]->u.c.v.i, tmpregs);
+ break;
+ case ARG+B:
+ dalign = 4;
+ salign = p->syms[1]->u.c.v.i;
+ blkcopy(29, p->syms[2]->u.c.v.i,
+ getregnum(p->x.kids[0]), 0,
+ p->syms[0]->u.c.v.i, tmpregs);
+ n = p->syms[2]->u.c.v.i + p->syms[0]->u.c.v.i;
+ dst = p->syms[2]->u.c.v.i;
+ for ( ; dst <= 12 && dst < n; dst += 4)
+ print("lw $%d,%d($sp)\n", (dst/4)+4, dst);
+ break;
+ }
+}
+static Symbol argreg(int argno, int offset, int ty, int sz, int ty0) {
+ assert((offset&3) == 0);
+ if (offset > 12)
+ return NULL;
+ else if (argno == 0 && ty == F)
+ return freg2[12];
+ else if (argno == 1 && ty == F && ty0 == F)
+ return freg2[14];
+ else if (argno == 1 && ty == F && sz == 8)
+ return d6; /* Pair! */
+ else
+ return ireg[(offset/4) + 4];
+}
+static void doarg(Node p) {
+ static int argno;
+ int align;
+
+ if (argoffset == 0)
+ argno = 0;
+ p->x.argno = argno++;
+ align = p->syms[1]->u.c.v.i < 4 ? 4 : p->syms[1]->u.c.v.i;
+ p->syms[2] = intconst(mkactual(align,
+ p->syms[0]->u.c.v.i));
+}
+static void local(Symbol p) {
+ if (askregvar(p, rmap(ttob(p->type))) == 0)
+ mkauto(p);
+}
+static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
+ int i, saved, sizefsave, sizeisave, varargs;
+ Symbol r, argregs[4];
+
+ usedmask[0] = usedmask[1] = 0;
+ freemask[0] = freemask[1] = ~(unsigned)0;
+ offset = maxoffset = maxargoffset = 0;
+ for (i = 0; callee[i]; i++)
+ ;
+ varargs = variadic(f->type)
+ || i > 0 && strcmp(callee[i-1]->name, "va_alist") == 0;
+ for (i = 0; callee[i]; i++) {
+ Symbol p = callee[i];
+ Symbol q = caller[i];
+ assert(q);
+ offset = roundup(offset, q->type->align);
+ p->x.offset = q->x.offset = offset;
+ p->x.name = q->x.name = stringd(offset);
+ r = argreg(i, offset, optype(ttob(q->type)), q->type->size, optype(ttob(caller[0]->type)));
+ if (i < 4)
+ argregs[i] = r;
+ offset = roundup(offset + q->type->size, 4);
+ if (varargs)
+ p->sclass = AUTO;
+ else if (r && ncalls == 0 &&
+ !isstruct(q->type) && !p->addressed &&
+ !(isfloat(q->type) && r->x.regnode->set == IREG)
+) {
+ p->sclass = q->sclass = REGISTER;
+ askregvar(p, r);
+ assert(p->x.regnode && p->x.regnode->vbl == p);
+ q->x = p->x;
+ q->type = p->type;
+ }
+ else if (askregvar(p, rmap(ttob(p->type)))
+ && r != NULL
+ && (isint(p->type) || p->type == q->type)) {
+ assert(q->sclass != REGISTER);
+ p->sclass = q->sclass = REGISTER;
+ q->type = p->type;
+ }
+ }
+ assert(!caller[i]);
+ offset = 0;
+ gencode(caller, callee);
+ if (ncalls)
+ usedmask[IREG] |= ((unsigned)1)<<31;
+ usedmask[IREG] &= 0xc0ff0000;
+ usedmask[FREG] &= 0xfff00000;
+ if (pic && ncalls)
+ usedmask[IREG] |= 1<<25;
+ maxargoffset = roundup(maxargoffset, usedmask[FREG] ? 8 : 4);
+ if (ncalls && maxargoffset < 16)
+ maxargoffset = 16;
+ sizefsave = 4*bitcount(usedmask[FREG]);
+ sizeisave = 4*bitcount(usedmask[IREG]);
+ framesize = roundup(maxargoffset + sizefsave
+ + sizeisave + maxoffset, 8);
+ segment(CODE);
+ print(".align 2\n");
+ print(".ent %s\n", f->x.name);
+ print("%s:\n", f->x.name);
+ i = maxargoffset + sizefsave - framesize;
+ print(".frame $sp,%d,$31\n", framesize);
+ if (pic)
+ print(".set noreorder\n.cpload $25\n.set reorder\n");
+ if (framesize > 0)
+ print("addu $sp,$sp,%d\n", -framesize);
+ if (usedmask[FREG])
+ print(".fmask 0x%x,%d\n", usedmask[FREG], i - 8);
+ if (usedmask[IREG])
+ print(".mask 0x%x,%d\n", usedmask[IREG],
+ i + sizeisave - 4);
+ saved = maxargoffset;
+ for (i = 20; i <= 30; i += 2)
+ if (usedmask[FREG]&(3<<i)) {
+ print("s.d $f%d,%d($sp)\n", i, saved);
+ saved += 8;
+ }
+
+ for (i = 16; i <= 31; i++)
+ if (usedmask[IREG]&(1<<i)) {
+ if (i == 25)
+ print(".cprestore %d\n", saved);
+ else
+ print("sw $%d,%d($sp)\n", i, saved);
+ saved += 4;
+ }
+ for (i = 0; i < 4 && callee[i]; i++) {
+ r = argregs[i];
+ if (r && r->x.regnode != callee[i]->x.regnode) {
+ Symbol out = callee[i];
+ Symbol in = caller[i];
+ int rn = r->x.regnode->number;
+ int rs = r->x.regnode->set;
+ int tyin = ttob(in->type);
+
+ assert(out && in && r && r->x.regnode);
+ assert(out->sclass != REGISTER || out->x.regnode);
+ if (out->sclass == REGISTER
+ && (isint(out->type) || out->type == in->type)) {
+ int outn = out->x.regnode->number;
+ if (rs == FREG && tyin == F+sizeop(8))
+ print("mov.d $f%d,$f%d\n", outn, rn);
+ else if (rs == FREG && tyin == F+sizeop(4))
+ print("mov.s $f%d,$f%d\n", outn, rn);
+ else if (rs == IREG && tyin == F+sizeop(8))
+ print("mtc1.d $%d,$f%d\n", rn, outn);
+ else if (rs == IREG && tyin == F+sizeop(4))
+ print("mtc1 $%d,$f%d\n", rn, outn);
+ else
+ print("move $%d,$%d\n", outn, rn);
+ } else {
+ int off = in->x.offset + framesize;
+ if (rs == FREG && tyin == F+sizeop(8))
+ print("s.d $f%d,%d($sp)\n", rn, off);
+ else if (rs == FREG && tyin == F+sizeop(4))
+ print("s.s $f%d,%d($sp)\n", rn, off);
+ else {
+ int i, n = (in->type->size + 3)/4;
+ for (i = rn; i < rn+n && i <= 7; i++)
+ print("sw $%d,%d($sp)\n", i, off + (i-rn)*4);
+ }
+ }
+ }
+ }
+ if (varargs && callee[i-1]) {
+ i = callee[i-1]->x.offset + callee[i-1]->type->size;
+ for (i = roundup(i, 4)/4; i <= 3; i++)
+ print("sw $%d,%d($sp)\n", i + 4, framesize + 4*i);
+ }
+ emitcode();
+ saved = maxargoffset;
+ for (i = 20; i <= 30; i += 2)
+ if (usedmask[FREG]&(3<<i)) {
+ print("l.d $f%d,%d($sp)\n", i, saved);
+ saved += 8;
+ }
+ for (i = 16; i <= 31; i++)
+ if (usedmask[IREG]&(1<<i)) {
+ print("lw $%d,%d($sp)\n", i, saved);
+ saved += 4;
+ }
+ if (framesize > 0)
+ print("addu $sp,$sp,%d\n", framesize);
+ print("j $31\n");
+ print(".end %s\n", f->x.name);
+}
+static void defconst(int suffix, int size, Value v) {
+ if (suffix == F && size == 4) {
+ float f = v.d;
+ print(".word 0x%x\n", *(unsigned *)&f);
+ }
+ else if (suffix == F && size == 8) {
+ double d = v.d;
+ unsigned *p = (unsigned *)&d;
+ print(".word 0x%x\n.word 0x%x\n", p[swap], p[!swap]);
+ }
+ else if (suffix == P)
+ print(".word 0x%x\n", v.p);
+ else if (size == 1)
+ print(".byte 0x%x\n", suffix == I ? v.i : v.u);
+ else if (size == 2)
+ print(".half 0x%x\n", suffix == I ? v.i : v.u);
+ else if (size == 4)
+ print(".word 0x%x\n", suffix == I ? v.i : v.u);
+}
+static void defaddress(Symbol p) {
+ if (pic && p->scope == LABELS)
+ print(".gpword %s\n", p->x.name);
+ else
+ print(".word %s\n", p->x.name);
+}
+static void defstring(int n, char *str) {
+ char *s;
+
+ for (s = str; s < str + n; s++)
+ print(".byte %d\n", (*s)&0377);
+}
+static void export(Symbol p) {
+ print(".globl %s\n", p->x.name);
+}
+static void import(Symbol p) {
+ if (!isfunc(p->type))
+ print(".extern %s %d\n", p->name, p->type->size);
+}
+static void defsymbol(Symbol p) {
+ if (p->scope >= LOCAL && p->sclass == STATIC)
+ p->x.name = stringf("L.%d", genlabel(1));
+ else if (p->generated)
+ p->x.name = stringf("L.%s", p->name);
+ else
+ assert(p->scope != CONSTANTS || isint(p->type) || isptr(p->type)),
+ p->x.name = p->name;
+}
+static void address(Symbol q, Symbol p, long n) {
+ if (p->scope == GLOBAL
+ || p->sclass == STATIC || p->sclass == EXTERN)
+ q->x.name = stringf("%s%s%D", p->x.name,
+ n >= 0 ? "+" : "", n);
+ else {
+ assert(n <= INT_MAX && n >= INT_MIN);
+ q->x.offset = p->x.offset + n;
+ q->x.name = stringd(q->x.offset);
+ }
+}
+static void global(Symbol p) {
+ if (p->u.seg == BSS) {
+ if (p->sclass == STATIC || Aflag >= 2)
+ print(".lcomm %s,%d\n", p->x.name, p->type->size);
+ else
+ print( ".comm %s,%d\n", p->x.name, p->type->size);
+ } else {
+ if (p->u.seg == DATA
+ && (p->type->size == 0 || p->type->size > gnum))
+ print(".data\n");
+ else if (p->u.seg == DATA)
+ print(".sdata\n");
+ print(".align %c\n", ".01.2...3"[p->type->align]);
+ print("%s:\n", p->x.name);
+ }
+}
+static void segment(int n) {
+ cseg = n;
+ switch (n) {
+ case CODE: print(".text\n"); break;
+ case LIT: print(".rdata\n"); break;
+ }
+}
+static void space(int n) {
+ if (cseg != BSS)
+ print(".space %d\n", n);
+}
+static void blkloop(int dreg, int doff, int sreg, int soff, int size, int tmps[]) {
+ int lab = genlabel(1);
+
+ print("addu $%d,$%d,%d\n", sreg, sreg, size&~7);
+ print("addu $%d,$%d,%d\n", tmps[2], dreg, size&~7);
+ blkcopy(tmps[2], doff, sreg, soff, size&7, tmps);
+ print("L.%d:\n", lab);
+ print("addu $%d,$%d,%d\n", sreg, sreg, -8);
+ print("addu $%d,$%d,%d\n", tmps[2], tmps[2], -8);
+ blkcopy(tmps[2], doff, sreg, soff, 8, tmps);
+ print("bltu $%d,$%d,L.%d\n", dreg, tmps[2], lab);
+}
+static void blkfetch(int size, int off, int reg, int tmp) {
+ assert(size == 1 || size == 2 || size == 4);
+ if (size == 1)
+ print("lbu $%d,%d($%d)\n", tmp, off, reg);
+ else if (salign >= size && size == 2)
+ print("lhu $%d,%d($%d)\n", tmp, off, reg);
+ else if (salign >= size)
+ print("lw $%d,%d($%d)\n", tmp, off, reg);
+ else if (size == 2)
+ print("ulhu $%d,%d($%d)\n", tmp, off, reg);
+ else
+ print("ulw $%d,%d($%d)\n", tmp, off, reg);
+}
+static void blkstore(int size, int off, int reg, int tmp) {
+ if (size == 1)
+ print("sb $%d,%d($%d)\n", tmp, off, reg);
+ else if (dalign >= size && size == 2)
+ print("sh $%d,%d($%d)\n", tmp, off, reg);
+ else if (dalign >= size)
+ print("sw $%d,%d($%d)\n", tmp, off, reg);
+ else if (size == 2)
+ print("ush $%d,%d($%d)\n", tmp, off, reg);
+ else
+ print("usw $%d,%d($%d)\n", tmp, off, reg);
+}
+static void stabinit(char *, int, char *[]);
+static void stabline(Coordinate *);
+static void stabsym(Symbol);
+
+static char *currentfile;
+
+static int bitcount(unsigned mask) {
+ unsigned i, n = 0;
+
+ for (i = 1; i; i <<= 1)
+ if (mask&i)
+ n++;
+ return n;
+}
+
+/* stabinit - initialize stab output */
+static void stabinit(char *file, int argc, char *argv[]) {
+ if (file) {
+ print(".file 2,\"%s\"\n", file);
+ currentfile = file;
+ }
+}
+
+/* stabline - emit stab entry for source coordinate *cp */
+static void stabline(Coordinate *cp) {
+ if (cp->file && cp->file != currentfile) {
+ print(".file 2,\"%s\"\n", cp->file);
+ currentfile = cp->file;
+ }
+ print(".loc 2,%d\n", cp->y);
+}
+
+/* stabsym - output a stab entry for symbol p */
+static void stabsym(Symbol p) {
+ if (p == cfunc && IR->stabline)
+ (*IR->stabline)(&p->src);
+}
+Interface mipsebIR = {
+ 1, 1, 0, /* char */
+ 2, 2, 0, /* short */
+ 4, 4, 0, /* int */
+ 4, 4, 0, /* long */
+ 4, 4, 0, /* long long */
+ 4, 4, 1, /* float */
+ 8, 8, 1, /* double */
+ 8, 8, 1, /* long double */
+ 4, 4, 0, /* T * */
+ 0, 1, 0, /* struct */
+ 0, /* little_endian */
+ 0, /* mulops_calls */
+ 0, /* wants_callb */
+ 1, /* wants_argb */
+ 1, /* left_to_right */
+ 0, /* wants_dag */
+ 0, /* unsigned_char */
+ address,
+ blockbeg,
+ blockend,
+ defaddress,
+ defconst,
+ defstring,
+ defsymbol,
+ emit,
+ export,
+ function,
+ gen,
+ global,
+ import,
+ local,
+ progbeg,
+ progend,
+ segment,
+ space,
+ 0, 0, 0, stabinit, stabline, stabsym, 0,
+ {
+ 4, /* max_unaligned_load */
+ rmap,
+ blkfetch, blkstore, blkloop,
+ _label,
+ _rule,
+ _nts,
+ _kids,
+ _string,
+ _templates,
+ _isinstruction,
+ _ntname,
+ emit2,
+ doarg,
+ target,
+ clobber,
+
+ }
+}, mipselIR = {
+ 1, 1, 0, /* char */
+ 2, 2, 0, /* short */
+ 4, 4, 0, /* int */
+ 4, 4, 0, /* long */
+ 4, 4, 0, /* long long */
+ 4, 4, 1, /* float */
+ 8, 8, 1, /* double */
+ 8, 8, 1, /* long double */
+ 4, 4, 0, /* T * */
+ 0, 1, 0, /* struct */
+ 1, /* little_endian */
+ 0, /* mulops_calls */
+ 0, /* wants_callb */
+ 1, /* wants_argb */
+ 1, /* left_to_right */
+ 0, /* wants_dag */
+ 0, /* unsigned_char */
+ address,
+ blockbeg,
+ blockend,
+ defaddress,
+ defconst,
+ defstring,
+ defsymbol,
+ emit,
+ export,
+ function,
+ gen,
+ global,
+ import,
+ local,
+ progbeg,
+ progend,
+ segment,
+ space,
+ 0, 0, 0, stabinit, stabline, stabsym, 0,
+ {
+ 4, /* max_unaligned_load */
+ rmap,
+ blkfetch, blkstore, blkloop,
+ _label,
+ _rule,
+ _nts,
+ _kids,
+ _string,
+ _templates,
+ _isinstruction,
+ _ntname,
+ emit2,
+ doarg,
+ target,
+ clobber,
+
+ }
+};
+static char rcsid[] = "$Id: mips.md 145 2001-10-17 21:53:10Z timo $";
diff --git a/lcc/src/null.c b/lcc/src/null.c
new file mode 100755
index 0000000..52129fc
--- /dev/null
+++ b/lcc/src/null.c
@@ -0,0 +1,74 @@
+#include "c.h"
+#define I(f) null_##f
+
+static Node I(gen)(Node p) { return p; }
+static void I(address)(Symbol q, Symbol p, long n) {}
+static void I(blockbeg)(Env *e) {}
+static void I(blockend)(Env *e) {}
+static void I(defaddress)(Symbol p) {}
+static void I(defconst)(int suffix, int size, Value v) {}
+static void I(defstring)(int len, char *s) {}
+static void I(defsymbol)(Symbol p) {}
+static void I(emit)(Node p) {}
+static void I(export)(Symbol p) {}
+static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {}
+static void I(global)(Symbol p) {}
+static void I(import)(Symbol p) {}
+static void I(local)(Symbol p) {}
+static void I(progbeg)(int argc, char *argv[]) {}
+static void I(progend)(void) {}
+static void I(segment)(int s) {}
+static void I(space)(int n) {}
+static void I(stabblock)(int brace, int lev, Symbol *p) {}
+static void I(stabend)(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {}
+static void I(stabfend)(Symbol p, int lineno) {}
+static void I(stabinit)(char *file, int argc, char *argv[]) {}
+static void I(stabline)(Coordinate *cp) {}
+static void I(stabsym)(Symbol p) {}
+static void I(stabtype)(Symbol p) {}
+
+
+Interface nullIR = {
+ 1, 1, 0, /* char */
+ 2, 2, 0, /* short */
+ 4, 4, 0, /* int */
+ 8, 8, 1, /* long */
+ 8 ,8, 1, /* long long */
+ 4, 4, 1, /* float */
+ 8, 8, 1, /* double */
+ 16,16,1, /* long double */
+ 4, 4, 0, /* T* */
+ 0, 4, 0, /* struct */
+ 1, /* little_endian */
+ 0, /* mulops_calls */
+ 0, /* wants_callb */
+ 0, /* wants_argb */
+ 1, /* left_to_right */
+ 0, /* wants_dag */
+ 0, /* unsigned_char */
+ I(address),
+ I(blockbeg),
+ I(blockend),
+ I(defaddress),
+ I(defconst),
+ I(defstring),
+ I(defsymbol),
+ I(emit),
+ I(export),
+ I(function),
+ I(gen),
+ I(global),
+ I(import),
+ I(local),
+ I(progbeg),
+ I(progend),
+ I(segment),
+ I(space),
+ I(stabblock),
+ I(stabend),
+ I(stabfend),
+ I(stabinit),
+ I(stabline),
+ I(stabsym),
+ I(stabtype)
+};
diff --git a/lcc/src/output.c b/lcc/src/output.c
new file mode 100755
index 0000000..e8fe6f5
--- /dev/null
+++ b/lcc/src/output.c
@@ -0,0 +1,134 @@
+#include "c.h"
+
+
+static char *outs(const char *str, FILE *f, char *bp) {
+ if (f)
+ fputs(str, f);
+ else
+ while (*bp = *str++)
+ bp++;
+ return bp;
+}
+
+static char *outd(long n, FILE *f, char *bp) {
+ unsigned long m;
+ char buf[25], *s = buf + sizeof buf;
+
+ *--s = '\0';
+ if (n < 0)
+ m = -n;
+ else
+ m = n;
+ do
+ *--s = m%10 + '0';
+ while ((m /= 10) != 0);
+ if (n < 0)
+ *--s = '-';
+ return outs(s, f, bp);
+}
+
+static char *outu(unsigned long n, int base, FILE *f, char *bp) {
+ char buf[25], *s = buf + sizeof buf;
+
+ *--s = '\0';
+ do
+ *--s = "0123456789abcdef"[n%base];
+ while ((n /= base) != 0);
+ return outs(s, f, bp);
+}
+void print(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprint(stdout, NULL, fmt, ap);
+ va_end(ap);
+}
+/* fprint - formatted output to f */
+void fprint(FILE *f, const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprint(f, NULL, fmt, ap);
+ va_end(ap);
+}
+
+/* stringf - formatted output to a saved string */
+char *stringf(const char *fmt, ...) {
+ char buf[1024];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprint(NULL, buf, fmt, ap);
+ va_end(ap);
+ return string(buf);
+}
+
+/* vfprint - formatted output to f or string bp */
+void vfprint(FILE *f, char *bp, const char *fmt, va_list ap) {
+ for (; *fmt; fmt++)
+ if (*fmt == '%')
+ switch (*++fmt) {
+ case 'd': bp = outd(va_arg(ap, int), f, bp); break;
+ case 'D': bp = outd(va_arg(ap, long), f, bp); break;
+ case 'U': bp = outu(va_arg(ap, unsigned long), 10, f, bp); break;
+ case 'u': bp = outu(va_arg(ap, unsigned), 10, f, bp); break;
+ case 'o': bp = outu(va_arg(ap, unsigned), 8, f, bp); break;
+ case 'X': bp = outu(va_arg(ap, unsigned long), 16, f, bp); break;
+ case 'x': bp = outu(va_arg(ap, unsigned), 16, f, bp); break;
+ case 'f': case 'e':
+ case 'g': {
+ static char format[] = "%f";
+ char buf[128];
+ format[1] = *fmt;
+ sprintf(buf, format, va_arg(ap, double));
+ bp = outs(buf, f, bp);
+ }
+; break;
+ case 's': bp = outs(va_arg(ap, char *), f, bp); break;
+ case 'p': {
+ void *p = va_arg(ap, void *);
+ if (p)
+ bp = outs("0x", f, bp);
+ bp = outu((unsigned long)p, 16, f, bp);
+ break;
+ }
+ case 'c': if (f) fputc(va_arg(ap, int), f); else *bp++ = va_arg(ap, int); break;
+ case 'S': { char *s = va_arg(ap, char *);
+ int n = va_arg(ap, int);
+ if (s)
+ for ( ; n-- > 0; s++)
+ if (f) (void)putc(*s, f); else *bp++ = *s;
+ } break;
+ case 'k': { int t = va_arg(ap, int);
+ static char *tokens[] = {
+#define xx(a,b,c,d,e,f,g) g,
+#define yy(a,b,c,d,e,f,g) g,
+#include "token.h"
+ };
+ assert(tokens[t&0177]);
+ bp = outs(tokens[t&0177], f, bp);
+ } break;
+ case 't': { Type ty = va_arg(ap, Type);
+ assert(f);
+ outtype(ty ? ty : voidtype, f);
+ } break;
+ case 'w': { Coordinate *p = va_arg(ap, Coordinate *);
+ if (p->file && *p->file) {
+ bp = outs(p->file, f, bp);
+ bp = outs(":", f, bp);
+ }
+ bp = outd(p->y, f, bp);
+ } break;
+ case 'I': { int n = va_arg(ap, int);
+ while (--n >= 0)
+ if (f) (void)putc(' ', f); else *bp++ = ' ';
+ } break;
+ default: if (f) (void)putc(*fmt, f); else *bp++ = *fmt; break;
+ }
+ else if (f)
+ (void)putc(*fmt, f);
+ else
+ *bp++ = *fmt;
+ if (!f)
+ *bp = '\0';
+}
diff --git a/lcc/src/pass2.c b/lcc/src/pass2.c
new file mode 100755
index 0000000..f9e41cf
--- /dev/null
+++ b/lcc/src/pass2.c
@@ -0,0 +1,665 @@
+#include "c.h"
+#include "rcc.h"
+#if WIN32
+#include <fcntl.h>
+#include <io.h>
+#endif
+
+
+Interface *IR = NULL;
+int Aflag; /* >= 0 if -A specified */
+int Pflag; /* != 0 if -P specified */
+int glevel; /* == [0-9] if -g[0-9] specified */
+int xref; /* != 0 for cross-reference data */
+Symbol YYnull; /* _YYnull symbol if -n or -nvalidate specified */
+Symbol YYcheck; /* _YYcheck symbol if -nvalidate,check specified */
+
+static int verbose = 1;
+#define VERBOSE(n,arg) (verbose >= n ? (void)(arg):(void)0)
+static int nuids;
+static rcc_item_ty *items;
+static void **itemmap;
+
+static void *uid2type(int uid) {
+ assert(uid >= 0 && uid < nuids);
+ if (itemmap[uid] == NULL) {
+ Type ty;
+ rcc_type_ty type = (void *)items[uid];
+ assert(items[uid]);
+ assert(items[uid]->uid == uid);
+ assert(items[uid]->kind == rcc_Type_enum);
+ type = items[uid]->v.rcc_Type.type;
+ assert(type);
+ switch (type->kind) {
+ case rcc_INT_enum:
+ ty = btot(INT, type->size);
+ assert(ty->align == type->align);
+ break;
+ case rcc_UNSIGNED_enum:
+ ty = btot(UNSIGNED, type->size);
+ assert(ty->align == type->align);
+ break;
+ case rcc_FLOAT_enum:
+ ty = btot(FLOAT, type->size);
+ assert(ty->align == type->align);
+ break;
+ case rcc_VOID_enum:
+ ty = voidtype;
+ break;
+ case rcc_POINTER_enum:
+ ty = ptr(uid2type(type->v.rcc_POINTER.type));
+ break;
+ case rcc_ARRAY_enum:
+ ty = uid2type(type->v.rcc_ARRAY.type);
+ assert(ty->size > 0);
+ ty = array(ty, type->size/ty->size, 0);
+ break;
+ case rcc_CONST_enum:
+ ty = qual(CONST, uid2type(type->v.rcc_CONST.type));
+ break;
+ case rcc_VOLATILE_enum:
+ ty = qual(VOLATILE, uid2type(type->v.rcc_VOLATILE.type));
+ break;
+ case rcc_ENUM_enum: {
+ int i, n = Seq_length(type->v.rcc_ENUM.ids);
+ ty = newstruct(ENUM, string(type->v.rcc_ENUM.tag));
+ ty->type = inttype;
+ ty->size = ty->type->size;
+ ty->align = ty->type->align;
+ ty->u.sym->u.idlist = newarray(n + 1, sizeof *ty->u.sym->u.idlist, PERM);
+ for (i = 0; i < n; i++) {
+ rcc_enum__ty e = Seq_remlo(type->v.rcc_ENUM.ids);
+ Symbol p = install(e->id, &identifiers, GLOBAL, PERM);
+ p->type = ty;
+ p->sclass = ENUM;
+ p->u.value = e->value;
+ ty->u.sym->u.idlist[i] = p;
+ free(e);
+ }
+ ty->u.sym->u.idlist[i] = NULL;
+ Seq_free(&type->v.rcc_ENUM.ids);
+ break;
+ }
+ case rcc_STRUCT_enum: case rcc_UNION_enum: {
+ int i, n;
+ Field *tail;
+ list_ty fields;
+ if (type->kind == rcc_STRUCT_enum) {
+ ty = newstruct(STRUCT, string(type->v.rcc_STRUCT.tag));
+ fields = type->v.rcc_STRUCT.fields;
+ } else {
+ ty = newstruct(UNION, string(type->v.rcc_UNION.tag));
+ fields = type->v.rcc_UNION.fields;
+ }
+ itemmap[uid] = ty; /* recursive types */
+ ty->size = type->size;
+ ty->align = type->align;
+ tail = &ty->u.sym->u.s.flist;
+ n = Seq_length(fields);
+ for (i = 0; i < n; i++) {
+ rcc_field_ty field = Seq_remlo(fields);
+ NEW0(*tail, PERM);
+ (*tail)->name = (char *)field->id;
+ (*tail)->type = uid2type(field->type);
+ (*tail)->offset = field->offset;
+ (*tail)->bitsize = field->bitsize;
+ (*tail)->lsb = field->lsb;
+ if (isconst((*tail)->type))
+ ty->u.sym->u.s.cfields = 1;
+ if (isvolatile((*tail)->type))
+ ty->u.sym->u.s.vfields = 1;
+ tail = &(*tail)->link;
+ free(field);
+ }
+ Seq_free(&fields);
+ break;
+ }
+ case rcc_FUNCTION_enum: {
+ int n = Seq_length(type->v.rcc_FUNCTION.formals);
+ if (n > 0) {
+ int i;
+ Type *proto = newarray(n + 1, sizeof *proto, PERM);
+ for (i = 0; i < n; i++) {
+ int *formal = Seq_remlo(type->v.rcc_FUNCTION.formals);
+ proto[i] = uid2type(*formal);
+ free(formal);
+ }
+ proto[i] = NULL;
+ ty = func(uid2type(type->v.rcc_FUNCTION.type), proto, 0);
+ } else
+ ty = func(uid2type(type->v.rcc_FUNCTION.type), NULL, 1);
+ Seq_free(&type->v.rcc_FUNCTION.formals);
+ break;
+ }
+ default: assert(0);
+ }
+ if (itemmap[uid] == NULL) {
+ itemmap[uid] = ty;
+ free(type);
+ free(items[uid]);
+ items[uid] = NULL;
+ } else
+ assert(itemmap[uid] == ty);
+ }
+ return itemmap[uid];
+}
+
+static Symbol uid2symbol(int uid) {
+ assert(uid >= 0 && uid < nuids);
+ if (itemmap[uid] == NULL) {
+ Symbol p;
+ rcc_symbol_ty symbol;
+ assert(items[uid]);
+ assert(items[uid]->uid == uid);
+ assert(items[uid]->kind == rcc_Symbol_enum);
+ symbol = items[uid]->v.rcc_Symbol.symbol;
+ assert(symbol);
+ NEW0(p, PERM);
+ p->name = (char *)symbol->id;
+ p->scope = symbol->scope;
+ p->sclass = symbol->sclass;
+ p->type = uid2type(symbol->type);
+#define xx(f,n) p->f = symbol->flags>>n;
+ xx(structarg,0)
+ xx(addressed,1)
+ xx(computed,2)
+ xx(temporary,3)
+ xx(generated,4)
+#undef xx
+ p->ref = symbol->ref/10000.0;
+ assert(p->scope != CONSTANTS && p->scope != LABELS);
+ if (p->scope == GLOBAL || p->sclass == STATIC || p->sclass == EXTERN)
+ (*IR->defsymbol)(p);
+ itemmap[uid] = p;
+ free(symbol);
+ free(items[uid]);
+ items[uid] = NULL;
+ }
+ return itemmap[uid];
+}
+
+#define xx(s) static void do##s(rcc_interface_ty);
+xx(Export)
+xx(Import)
+xx(Global)
+xx(Local)
+xx(Address)
+xx(Segment)
+xx(Defaddress)
+xx(Deflabel)
+xx(Defconst)
+xx(Defconstf)
+xx(Defstring)
+xx(Space)
+xx(Function)
+xx(Blockbeg)
+xx(Blockend)
+xx(Forest)
+#undef xx
+static void (*doX[])(rcc_interface_ty in) = {
+#define xx(s) 0,
+xx(Export)
+xx(Import)
+xx(Global)
+xx(Local)
+xx(Address)
+xx(Segment)
+xx(Defaddress)
+xx(Deflabel)
+xx(Defconst)
+xx(Defconstf)
+xx(Defstring)
+xx(Space)
+xx(Function)
+xx(Blockbeg)
+xx(Blockend)
+xx(Forest)
+ 0
+#undef xx
+};
+
+static void interface(rcc_interface_ty in) {
+ assert(in);
+ (*doX[in->kind])(in);
+ free(in);
+}
+
+static void doExport(rcc_interface_ty in) {
+ (*IR->export)(uid2symbol(in->v.rcc_Export.p));
+}
+
+static void doImport(rcc_interface_ty in) {
+ Symbol p = uid2symbol(in->v.rcc_Export.p);
+
+ (*IR->import)(p);
+ p->defined = 1;
+}
+
+static void doGlobal(rcc_interface_ty in) {
+ Symbol p = uid2symbol(in->v.rcc_Global.p);
+
+ p->u.seg = in->v.rcc_Global.seg;
+ (*IR->global)(p);
+ p->defined = 1;
+}
+
+static void doLocal(rcc_interface_ty in) {
+ int uid = in->v.rcc_Local.uid;
+
+ assert(uid >= 0 && uid < nuids);
+ assert(items[uid] == NULL);
+ items[uid] = rcc_Symbol(uid, in->v.rcc_Local.p);
+ if (in->v.rcc_Local.p->scope >= LOCAL)
+ addlocal(uid2symbol(uid));
+}
+
+static void doAddress(rcc_interface_ty in) {
+ int uid = in->v.rcc_Address.uid;
+ Symbol p = uid2symbol(in->v.rcc_Address.p);
+
+ assert(uid >= 0 && uid < nuids);
+ assert(items[uid] == NULL);
+ items[uid] = rcc_Symbol(uid, in->v.rcc_Address.q);
+ if (p->scope == GLOBAL || p->sclass == STATIC || p->sclass == EXTERN)
+ (*IR->address)(uid2symbol(uid), p, in->v.rcc_Address.n);
+ else {
+ Code cp = code(Address);
+ cp->u.addr.sym = uid2symbol(uid);
+ cp->u.addr.base = p;
+ cp->u.addr.offset = in->v.rcc_Address.n;
+ }
+}
+
+static void doSegment(rcc_interface_ty in) {
+ (*IR->segment)(in->v.rcc_Segment.seg);
+}
+
+static void doDefaddress(rcc_interface_ty in) {
+ (*IR->defaddress)(uid2symbol(in->v.rcc_Defaddress.p));
+}
+
+static void doDeflabel(rcc_interface_ty in) {
+ (*IR->defaddress)(findlabel(in->v.rcc_Deflabel.label));
+}
+
+static void doDefconst(rcc_interface_ty in) {
+ Value v;
+
+ v.i = in->v.rcc_Defconst.value;
+ (*IR->defconst)(in->v.rcc_Defconst.suffix, in->v.rcc_Defconst.size, v);
+}
+
+static void doDefconstf(rcc_interface_ty in) {
+ Value v;
+ unsigned *p = (unsigned *)&v.d;
+
+ p[swap] = in->v.rcc_Defconstf.value->msb;
+ p[1-swap] = in->v.rcc_Defconstf.value->lsb;
+ (*IR->defconst)(F, in->v.rcc_Defconstf.size, v);
+ free(in->v.rcc_Defconstf.value);
+}
+
+static void doDefstring(rcc_interface_ty in) {
+ (*IR->defstring)(in->v.rcc_Defstring.s.len, (char *)in->v.rcc_Defstring.s.str);
+ free((char *)in->v.rcc_Defstring.s.str);
+}
+
+static void doSpace(rcc_interface_ty in) {
+ (*IR->space)(in->v.rcc_Space.n);
+}
+
+static void doFunction(rcc_interface_ty in) {
+ int i, n;
+ Symbol *caller, *callee;
+
+ /*
+ Initialize:
+ define the function symbol,
+ initialize callee and caller arrays.
+ */
+ cfunc = uid2symbol(in->v.rcc_Function.f);
+ labels = table(NULL, LABELS);
+ enterscope();
+ n = Seq_length(in->v.rcc_Function.caller);
+ caller = newarray(n + 1, sizeof *caller, FUNC);
+ for (i = 0; i < n; i++) {
+ int *uid = Seq_remlo(in->v.rcc_Function.caller);
+ caller[i] = uid2symbol(*uid);
+ free(uid);
+ }
+ caller[i] = NULL;
+ Seq_free(&in->v.rcc_Function.caller);
+ callee = newarray(n + 1, sizeof *callee, FUNC);
+ for (i = 0; i < n; i++) {
+ int *uid = Seq_remlo(in->v.rcc_Function.callee);
+ callee[i] = uid2symbol(*uid);
+ free(uid);
+ }
+ callee[i] = NULL;
+ Seq_free(&in->v.rcc_Function.callee);
+ cfunc->u.f.callee = callee;
+ cfunc->defined = 1;
+ /*
+ Initialize the code list,
+ traverse the interfaces inside the function;
+ each call appends code list entries.
+ */
+ codelist = &codehead;
+ codelist->next = NULL;
+ n = Seq_length(in->v.rcc_Function.codelist);
+ for (i = 0; i < n; i++)
+ interface(Seq_remlo(in->v.rcc_Function.codelist));
+ Seq_free(&in->v.rcc_Function.codelist);
+ /*
+ Call the back end,
+ Wrap-up.
+ */
+ exitscope();
+ (*IR->function)(cfunc, caller, callee, in->v.rcc_Function.ncalls);
+ cfunc = NULL;
+ labels = NULL;
+}
+
+static struct block {
+ Code begin;
+ struct block *prev;
+} *blockstack = NULL;
+
+static void doBlockbeg(rcc_interface_ty in) {
+ struct block *b;
+ Code cp = code(Blockbeg);
+
+ enterscope();
+ cp->u.block.level = level;
+ cp->u.block.locals = newarray(1, sizeof *cp->u.block.locals, FUNC);
+ cp->u.block.locals[0] = NULL;
+ cp->u.block.identifiers = NULL;
+ cp->u.block.types = NULL;
+ NEW(b, FUNC);
+ b->begin = cp;
+ b->prev = blockstack;
+ blockstack = b;
+}
+
+static void doBlockend(rcc_interface_ty in) {
+ assert(blockstack);
+ code(Blockend)->u.begin = blockstack->begin;
+ blockstack = blockstack->prev;
+ exitscope();
+}
+
+static Node visit(rcc_node_ty node) {
+ int op;
+ Node left = NULL, right = NULL, p = NULL;
+ Symbol sym = NULL;
+
+ switch (node->kind) {
+#define T(x) rcc_##x##_enum
+ case T(CSE): {
+ Symbol q = uid2symbol(node->v.rcc_CSE.uid);
+ assert(q->temporary);
+ q->u.t.cse = p = visit(node->v.rcc_CSE.node);
+ break;
+ }
+ case T(CNST): {
+ Value v;
+ v.i = node->v.rcc_CNST.value;
+ sym = constant(btot(node->suffix, node->size), v);
+ op = CNST;
+ break;
+ }
+ case T(CNSTF): {
+ Value v;
+ unsigned *p = (unsigned *)&v.d;
+ p[swap] = node->v.rcc_CNSTF.value->msb;
+ p[1-swap] = node->v.rcc_CNSTF.value->lsb;
+ sym = constant(btot(node->suffix, node->size), v);
+ free(node->v.rcc_CNSTF.value);
+ op = CNST;
+ break;
+ }
+ case T(ARG):
+ p = newnode(ARG + node->suffix + sizeop(node->size),
+ visit(node->v.rcc_ARG.left), NULL,
+ intconst(node->v.rcc_ARG.len));
+ p->syms[1] = intconst(node->v.rcc_ARG.align);
+ break;
+ case T(ASGN):
+ p = newnode(ASGN + node->suffix + sizeop(node->size),
+ visit(node->v.rcc_ASGN.left), visit(node->v.rcc_ASGN.right),
+ intconst(node->v.rcc_ASGN.len));
+ p->syms[1] = intconst(node->v.rcc_ASGN.align);
+ break;
+ case T(CVT):
+ op = node->v.rcc_CVT.op;
+ left = visit(node->v.rcc_CVT.left);
+ sym = intconst(node->v.rcc_CVT.fromsize);
+ break;
+ case T(CALL):
+ op = CALL;
+ left = visit(node->v.rcc_CALL.left);
+ NEW0(sym, FUNC);
+ sym->type = uid2type(node->v.rcc_CALL.type);
+ break;
+ case T(CALLB):
+ op = CALL;
+ left = visit(node->v.rcc_CALLB.left);
+ right = visit(node->v.rcc_CALLB.right);
+ NEW0(sym, FUNC);
+ sym->type = uid2type(node->v.rcc_CALLB.type);
+ break;
+ case T(RET):
+ op = RET;
+ break;
+ case T(ADDRG):
+ op = ADDRG;
+ sym = uid2symbol(node->v.rcc_ADDRG.uid);
+ break;
+ case T(ADDRL):
+ op = ADDRL;
+ sym = uid2symbol(node->v.rcc_ADDRG.uid);
+ break;
+ case T(ADDRF):
+ op = ADDRF;
+ sym = uid2symbol(node->v.rcc_ADDRG.uid);
+ break;
+ case T(Unary):
+ op = node->v.rcc_Unary.op;
+ left = visit(node->v.rcc_Unary.left);
+ break;
+ case T(Binary):
+ op = node->v.rcc_Binary.op;
+ left = visit(node->v.rcc_Binary.left);
+ right = visit(node->v.rcc_Binary.right);
+ break;
+ case T(Compare):
+ op = node->v.rcc_Compare.op;
+ left = visit(node->v.rcc_Compare.left);
+ right = visit(node->v.rcc_Compare.right);
+ sym = findlabel(node->v.rcc_Compare.label);
+ break;
+ case T(LABEL):
+ op = LABEL;
+ sym = findlabel(node->v.rcc_LABEL.label);
+ break;
+ case T(BRANCH):
+ op = JUMP;
+ left = newnode(ADDRG+P+sizeop(voidptype->size), NULL, NULL, findlabel(node->v.rcc_BRANCH.label));
+ break;
+#undef T
+ default: assert(0);
+ }
+ if (p == NULL)
+ p = newnode(op + node->suffix + sizeop(node->size), left, right, sym);
+ free(node);
+ return p;
+}
+
+static void doForest(rcc_interface_ty in) {
+ Node *tail = &code(Gen)->u.forest;
+ int i, n = Seq_length(in->v.rcc_Forest.nodes);
+
+ for (i = 0; i < n; i++) {
+ *tail = visit(Seq_remlo(in->v.rcc_Forest.nodes));
+ assert(*tail);
+ tail = &(*tail)->link;
+ }
+ *tail = NULL;
+ Seq_free(&in->v.rcc_Forest.nodes);
+}
+
+int main(int argc, char *argv[]) {
+ int i, version;
+ float stamp = (assert(strstr(rcsid, ",v")), strtod(strstr(rcsid, ",v")+2, NULL))
+;
+ char *infile = NULL, *outfile = NULL;
+ rcc_program_ty pickle;
+
+ for (i = 1; i < argc; i++)
+ if (*argv[i] != '-' || strcmp(argv[i], "-") == 0) {
+ if (infile == NULL)
+ infile = argv[i];
+ else if (outfile == NULL)
+ outfile = argv[i];
+ }
+ if (infile != NULL && strcmp(infile, "-") != 0
+ && freopen(infile, "rb", stdin) == NULL) {
+ fprint(stderr, "%s: can't read `%s'\n", argv[0], infile);
+ exit(EXIT_FAILURE);
+ }
+#if WIN32
+ else
+ _setmode(_fileno(stdin), _O_BINARY);
+#endif
+ if (outfile != NULL && strcmp(outfile, "-") != 0
+ && freopen(outfile, "w", stdout) == NULL) {
+ fprint(stderr, "%s: can't write `%s'\n", argv[0], outfile);
+ exit(EXIT_FAILURE);
+ }
+ version = read_int(stdin);
+ assert(version/100 == (int)stamp);
+ pickle = rcc_read_program(stdin);
+ argc = pickle->argc;
+ argv = newarray(argc + 1, sizeof *argv, PERM);
+ {
+ for (i = 0; i < argc; i++) {
+ string_ty *arg = Seq_remlo(pickle->argv);
+ argv[i] = (char *)arg->str;
+ free(arg);
+ }
+ argv[i] = NULL;
+ assert(i == argc);
+ Seq_free(&pickle->argv);
+ }
+ for (i = argc - 1; i > 0; i--)
+ if (strncmp(argv[i], "-target=", 8) == 0)
+ break;
+ if (i > 0) {
+ int j;
+ for (j = 0; bindings[j].name && bindings[j].ir; j++)
+ if (strcmp(&argv[i][8], bindings[j].name) == 0) {
+ IR = bindings[j].ir;
+ break;
+ }
+ }
+ if (!IR) {
+ fprint(stderr, "%s: unknown target", argv[0]);
+ if (i > 0)
+ fprint(stderr, " `%s'", &argv[i][8]);
+ fprint(stderr, "; must specify one of\n");
+ for (i = 0; bindings[i].name; i++)
+ fprint(stderr, "\t-target=%s\n", bindings[i].name);
+ exit(EXIT_FAILURE);
+ }
+ IR->wants_dag = 0; /* pickle's hold trees */
+ init(argc, argv);
+ genlabel(pickle->nlabels);
+ level = GLOBAL;
+ {
+ int i, count;
+ nuids = pickle->nuids;
+ items = newarray(nuids, sizeof *items, PERM);
+ itemmap = newarray(nuids, sizeof *items, PERM);
+ for (i = 0; i < nuids; i++) {
+ itemmap[i] = NULL;
+ items[i] = NULL;
+ }
+ (*IR->progbeg)(argc, argv);
+ count = Seq_length(pickle->items);
+ for (i = 0; i < count; i++) {
+ rcc_item_ty item = Seq_remlo(pickle->items);
+ int uid = item->uid;
+ assert(uid >= 0 && uid < nuids);
+ assert(items[uid] == NULL);
+ items[uid] = item;
+ }
+ Seq_free(&pickle->items);
+#define xx(s) assert(rcc_##s##_enum < sizeof doX/sizeof doX[0] && doX[rcc_##s##_enum]==0); \
+ doX[rcc_##s##_enum] = do##s;
+ xx(Export)
+ xx(Import)
+ xx(Global)
+ xx(Local)
+ xx(Address)
+ xx(Segment)
+ xx(Defaddress)
+ xx(Deflabel)
+ xx(Defconst)
+ xx(Defconstf)
+ xx(Defstring)
+ xx(Space)
+ xx(Function)
+ xx(Blockbeg)
+ xx(Blockend)
+ xx(Forest)
+#undef xx
+ count = Seq_length(pickle->interfaces);
+ for (i = 0; i < count; i++)
+ interface(Seq_remlo(pickle->interfaces));
+ Seq_free(&pickle->interfaces);
+ free(pickle);
+ (*IR->progend)();
+ }
+ deallocate(PERM);
+ return errcnt > 0;
+}
+
+/* main_init - process program arguments */
+void main_init(int argc, char *argv[]) {
+ int i;
+ static int inited;
+
+ if (inited)
+ return;
+ inited = 1;
+ for (i = 1; i < argc; i++)
+ if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "-g2") == 0)
+ glevel = 2;
+ else if (strcmp(argv[i], "-w") == 0)
+ wflag++;
+ else if (strcmp(argv[i], "-v") == 0) {
+ fprint(stderr, "%s %s\n", argv[0], rcsid);
+ verbose++;
+ } else if (strncmp(argv[i], "-errout=", 8) == 0) {
+ FILE *f = fopen(argv[i]+8, "w");
+ if (f == NULL) {
+ fprint(stderr, "%s: can't write errors to `%s'\n", argv[0], argv[i]+8);
+ exit(EXIT_FAILURE);
+ }
+ fclose(f);
+ f = freopen(argv[i]+8, "w", stderr);
+ assert(f);
+ } else if (strncmp(argv[i], "-e", 2) == 0) {
+ int x;
+ if ((x = strtol(&argv[i][2], NULL, 0)) > 0)
+ errlimit = x;
+ }
+}
+
+void init(int argc, char *argv[]) {
+ {extern void main_init(int, char *[]); main_init(argc, argv);}
+ {extern void prof_init(int, char *[]); prof_init(argc, argv);}
+ {extern void trace_init(int, char *[]); trace_init(argc, argv);}
+ {extern void type_init(int, char *[]); type_init(argc, argv);}
+ {extern void x86linux_init(int, char *[]); x86linux_init(argc, argv);}
+}
diff --git a/lcc/src/prof.c b/lcc/src/prof.c
new file mode 100755
index 0000000..59ce879
--- /dev/null
+++ b/lcc/src/prof.c
@@ -0,0 +1,227 @@
+#include "c.h"
+
+
+struct callsite {
+ char *file, *name;
+ union coordinate {
+ unsigned int coord;
+ struct { unsigned int y:16,x:10,index:6; } le;
+ struct { unsigned int index:6,x:10,y:16; } be;
+ } u;
+};
+struct func {
+ struct func *link;
+ struct caller *callers;
+ char *name;
+ union coordinate src;
+};
+struct map { /* source code map; 200 coordinates/map */
+ int size;
+ union coordinate u[200];
+};
+
+int npoints; /* # of execution points if -b specified */
+int ncalled = -1; /* #times prof.out says current function was called */
+static Symbol YYlink; /* symbol for file's struct _bbdata */
+static Symbol YYcounts; /* symbol for _YYcounts if -b specified */
+static List maplist; /* list of struct map *'s */
+static List filelist; /* list of file names */
+static Symbol funclist; /* list of struct func *'s */
+static Symbol afunc; /* current function's struct func */
+
+/* bbcall - build tree to set _callsite at call site *cp, emit call site data */
+static void bbcall(Symbol yycounts, Coordinate *cp, Tree *e) {
+ static Symbol caller;
+ Value v;
+ union coordinate u;
+ Symbol p = genident(STATIC, array(voidptype, 0, 0), GLOBAL);
+ Tree t = *e;
+
+ defglobal(p, LIT);
+ defpointer(cp->file ? mkstr(cp->file)->u.c.loc : (Symbol)0);
+ defpointer(mkstr(cfunc->name)->u.c.loc);
+ if (IR->little_endian) {
+ u.le.x = cp->x;
+ u.le.y = cp->y;
+ } else {
+ u.be.x = cp->x;
+ u.be.y = cp->y;
+ }
+ (*IR->defconst)(U, unsignedtype->size, (v.u = u.coord, v));
+ if (caller == 0) {
+ caller = mksymbol(EXTERN, "_caller", ptr(voidptype));
+ caller->defined = 0;
+ }
+ if (generic((*e)->op) != CALL)
+ t = (*e)->kids[0];
+ assert(generic(t->op) == CALL);
+ t = tree(t->op, t->type,
+ tree(RIGHT, t->kids[0]->type,
+ t->kids[0],
+ tree(RIGHT, t->kids[0]->type, asgn(caller, idtree(p)), t->kids[0])),
+ t->kids[1]);
+ if (generic((*e)->op) != CALL)
+ t = tree((*e)->op, (*e)->type, t, (*e)->kids[1]);
+ *e = t;
+}
+
+/* bbentry - return tree for _prologue(&afunc, &YYlink)' */
+static void bbentry(Symbol yylink, Symbol f) {
+ static Symbol prologue;
+
+ afunc = genident(STATIC, array(voidptype, 4, 0), GLOBAL);
+ if (prologue == 0) {
+ prologue = mksymbol(EXTERN, "_prologue", ftype(inttype, voidptype));
+ prologue->defined = 0;
+ }
+ walk(vcall(prologue, voidtype, pointer(idtree(afunc)), pointer(idtree(yylink)), NULL), 0, 0);
+
+}
+
+/* bbexit - return tree for _epilogue(&afunc)' */
+static void bbexit(Symbol yylink, Symbol f, Tree e) {
+ static Symbol epilogue;
+
+ if (epilogue == 0) {
+ epilogue = mksymbol(EXTERN, "_epilogue", ftype(inttype, voidptype));
+ epilogue->defined = 0;
+ }
+ walk(vcall(epilogue, voidtype, pointer(idtree(afunc)), NULL), 0, 0);
+}
+
+/* bbfile - add file to list of file names, return its index */
+static int bbfile(char *file) {
+ if (file) {
+ List lp;
+ int i = 1;
+ if ((lp = filelist) != NULL)
+ do {
+ lp = lp->link;
+ if (((Symbol)lp->x)->u.c.v.p == file)
+ return i;
+ i++;
+ } while (lp != filelist);
+ filelist = append(mkstr(file), filelist);
+ return i;
+ }
+ return 0;
+}
+
+/* bbfunc - emit function name and src coordinates */
+static void bbfunc(Symbol yylink, Symbol f) {
+ Value v;
+ union coordinate u;
+
+ defglobal(afunc, DATA);
+ defpointer(funclist);
+ defpointer(NULL);
+ defpointer(mkstr(f->name)->u.c.loc);
+ if (IR->little_endian) {
+ u.le.x = f->u.f.pt.x;
+ u.le.y = f->u.f.pt.y;
+ u.le.index = bbfile(f->u.f.pt.file);
+ } else {
+ u.be.x = f->u.f.pt.x;
+ u.be.y = f->u.f.pt.y;
+ u.be.index = bbfile(f->u.f.pt.file);
+ }
+ (*IR->defconst)(U, unsignedtype->size, (v.u = u.coord, v));
+ funclist = afunc;
+}
+
+/* bbincr - build tree to increment execution point at *cp */
+static void bbincr(Symbol yycounts, Coordinate *cp, Tree *e) {
+ struct map *mp = maplist->x;
+ Tree t;
+
+ /* append *cp to source map */
+ if (mp->size >= NELEMS(mp->u)) {
+ NEW(mp, PERM);
+ mp->size = 0;
+ maplist = append(mp, maplist);
+ }
+ if (IR->little_endian) {
+ mp->u[mp->size].le.x = cp->x;
+ mp->u[mp->size].le.y = cp->y;
+ mp->u[mp->size++].le.index = bbfile(cp->file);
+ } else {
+ mp->u[mp->size].be.x = cp->x;
+ mp->u[mp->size].be.y = cp->y;
+ mp->u[mp->size++].be.index = bbfile(cp->file);
+ }
+ t = incr('+', rvalue((*optree['+'])(ADD, pointer(idtree(yycounts)),
+ consttree(npoints++, inttype))), consttree(1, inttype));
+ if (*e)
+ *e = tree(RIGHT, (*e)->type, t, *e);
+ else
+ *e = t;
+}
+
+/* bbvars - emit definition for basic block counting data */
+static void bbvars(Symbol yylink) {
+ int i, j, n = npoints;
+ Value v;
+ struct map **mp;
+ Symbol coords, files, *p;
+
+ if (!YYcounts && !yylink)
+ return;
+ if (YYcounts) {
+ if (n <= 0)
+ n = 1;
+ YYcounts->type = array(unsignedtype, n, 0);
+ defglobal(YYcounts, BSS);
+ }
+ files = genident(STATIC, array(charptype, 1, 0), GLOBAL);
+ defglobal(files, LIT);
+ for (p = ltov(&filelist, PERM); *p; p++)
+ defpointer((*p)->u.c.loc);
+ defpointer(NULL);
+ coords = genident(STATIC, array(unsignedtype, n, 0), GLOBAL);
+ defglobal(coords, LIT);
+ for (i = n, mp = ltov(&maplist, PERM); *mp; i -= (*mp)->size, mp++)
+ for (j = 0; j < (*mp)->size; j++)
+ (*IR->defconst)(U, unsignedtype->size, (v.u = (*mp)->u[j].coord, v));
+ if (i > 0)
+ (*IR->space)(i*coords->type->type->size);
+ defpointer(NULL);
+ defglobal(yylink, DATA);
+ defpointer(NULL);
+ (*IR->defconst)(U, unsignedtype->size, (v.u = n, v));
+ defpointer(YYcounts);
+ defpointer(coords);
+ defpointer(files);
+ defpointer(funclist);
+}
+
+/* profInit - initialize basic block profiling options */
+void prof_init(int argc, char *argv[]) {
+ int i;
+ static int inited;
+
+ if (inited)
+ return;
+ inited = 1;
+ type_init(argc, argv);
+ if (IR)
+ for (i = 1; i < argc; i++)
+ if (strncmp(argv[i], "-a", 2) == 0) {
+ if (ncalled == -1
+ && process(argv[i][2] ? &argv[i][2] : "prof.out") > 0)
+ ncalled = 0;
+ } else if ((strcmp(argv[i], "-b") == 0
+ || strcmp(argv[i], "-C") == 0) && YYlink == 0) {
+ YYlink = genident(STATIC, array(unsignedtype, 0, 0), GLOBAL);
+ attach((Apply)bbentry, YYlink, &events.entry);
+ attach((Apply)bbexit, YYlink, &events.returns);
+ attach((Apply)bbfunc, YYlink, &events.exit);
+ attach((Apply)bbvars, YYlink, &events.end);
+ if (strcmp(argv[i], "-b") == 0) {
+ YYcounts = genident(STATIC, array(unsignedtype, 0, 0), GLOBAL);
+ maplist = append(allocate(sizeof (struct map), PERM), maplist);
+ ((struct map *)maplist->x)->size = 0;
+ attach((Apply)bbcall, YYcounts, &events.calls);
+ attach((Apply)bbincr, YYcounts, &events.points);
+ }
+ }
+}
diff --git a/lcc/src/profio.c b/lcc/src/profio.c
new file mode 100755
index 0000000..3e74770
--- /dev/null
+++ b/lcc/src/profio.c
@@ -0,0 +1,276 @@
+/* C compiler: prof.out input
+
+prof.out format:
+#files
+ name
+ ... (#files-1 times)
+#functions
+ name file# x y count caller file x y
+ ... (#functions-1 times)
+#points
+ file# x y count
+ ... (#points-1 times)
+*/
+#include "c.h"
+
+
+struct count { /* count data: */
+ int x, y; /* source coordinate */
+ int count; /* associated execution count */
+};
+
+#define MAXTOKEN 64
+
+struct file { /* per-file prof.out data: */
+ struct file *link; /* link to next file */
+ char *name; /* file name */
+ int size; /* size of counts[] */
+ int count; /* counts[0..count-1] hold valid data */
+ struct count *counts; /* count data */
+ struct func { /* function data: */
+ struct func *link; /* link to next function */
+ char *name; /* function name */
+ struct count count; /* total number of calls */
+ struct caller { /* caller data: */
+ struct caller *link; /* link to next caller */
+ char *name; /* caller's name */
+ char *file; /* call site: file, x, y */
+ int x, y;
+ int count; /* number of calls from this site */
+ } *callers;
+ } *funcs; /* list of functions */
+} *filelist;
+FILE *fp;
+
+/* acaller - add caller and site (file,x,y) to callee's callers list */
+static void acaller(char *caller, char *file, int x, int y, int count, struct func *callee) {
+ struct caller *q;
+
+ assert(callee);
+ for (q = callee->callers; q && (caller != q->name
+ || file != q->file || x != q->x || y != q->y); q = q->link)
+ ;
+ if (!q) {
+ struct caller **r;
+ NEW(q, PERM);
+ q->name = caller;
+ q->file = file;
+ q->x = x;
+ q->y = y;
+ q->count = 0;
+ for (r = &callee->callers; *r && (strcmp(q->name, (*r)->name) > 0
+ || strcmp(q->file, (*r)->file) > 0 || q->y > (*r)->y || q->y > (*r)->y); r = &(*r)->link)
+ ;
+ q->link = *r;
+ *r = q;
+ }
+ q->count += count;
+}
+
+/* compare - return <0, 0, >0 if a<b, a==b, a>b, resp. */
+static int compare(struct count *a, struct count *b) {
+ if (a->y == b->y)
+ return a->x - b->x;
+ return a->y - b->y;
+}
+
+/* findfile - return file name's file list entry, or 0 */
+static struct file *findfile(char *name) {
+ struct file *p;
+
+ for (p = filelist; p; p = p->link)
+ if (p->name == name)
+ return p;
+ return 0;
+}
+
+/* afunction - add function name and its data to file's function list */
+static struct func *afunction(char *name, char *file, int x, int y, int count) {
+ struct file *p = findfile(file);
+ struct func *q;
+
+ assert(p);
+ for (q = p->funcs; q && name != q->name; q = q->link)
+ ;
+ if (!q) {
+ struct func **r;
+ NEW(q, PERM);
+ q->name = name;
+ q->count.x = x;
+ q->count.y = y;
+ q->count.count = 0;
+ q->callers = 0;
+ for (r = &p->funcs; *r && compare(&q->count, &(*r)->count) > 0; r = &(*r)->link)
+ ;
+ q->link = *r;
+ *r = q;
+ }
+ q->count.count += count;
+ return q;
+}
+
+/* apoint - append execution point i to file's data */
+static void apoint(int i, char *file, int x, int y, int count) {
+ struct file *p = findfile(file);
+
+ assert(p);
+ if (i >= p->size) {
+ int j;
+ if (p->size == 0) {
+ p->size = i >= 200 ? 2*i : 200;
+ p->counts = newarray(p->size, sizeof *p->counts, PERM);
+ } else {
+ struct count *new;
+ p->size = 2*i;
+ new = newarray(p->size, sizeof *new, PERM);
+ for (j = 0; j < p->count; j++)
+ new[j] = p->counts[j];
+ p->counts = new;
+ }
+ for (j = p->count; j < p->size; j++) {
+ static struct count z;
+ p->counts[j] = z;
+ }
+ }
+ p->counts[i].x = x;
+ p->counts[i].y = y;
+ p->counts[i].count += count;
+ if (i >= p->count)
+ p->count = i + 1;
+}
+
+/* findcount - return count associated with (file,x,y) or -1 */
+int findcount(char *file, int x, int y) {
+ static struct file *cursor;
+
+ if (cursor == 0 || cursor->name != file)
+ cursor = findfile(file);
+ if (cursor) {
+ int l, u;
+ struct count *c = cursor->counts;
+ for (l = 0, u = cursor->count - 1; l <= u; ) {
+ int k = (l + u)/2;
+ if (c[k].y > y || c[k].y == y && c[k].x > x)
+ u = k - 1;
+ else if (c[k].y < y || c[k].y == y && c[k].x < x)
+ l = k + 1;
+ else
+ return c[k].count;
+ }
+ }
+ return -1;
+}
+
+/* findfunc - return count associated with function name in file or -1 */
+int findfunc(char *name, char *file) {
+ static struct file *cursor;
+
+ if (cursor == 0 || cursor->name != file)
+ cursor = findfile(file);
+ if (cursor) {
+ struct func *p;
+ for (p = cursor->funcs; p; p = p->link)
+ if (p->name == name)
+ return p->count.count;
+ }
+ return -1;
+}
+
+/* getd - read a nonnegative number */
+static int getd(void) {
+ int c, n = 0;
+
+ while ((c = getc(fp)) != EOF && (c == ' ' || c == '\n' || c == '\t'))
+ ;
+ if (c >= '0' && c <= '9') {
+ do
+ n = 10*n + (c - '0');
+ while ((c = getc(fp)) >= '0' && c <= '9');
+ return n;
+ }
+ return -1;
+}
+
+/* getstr - read a string */
+static char *getstr(void) {
+ int c;
+ char buf[MAXTOKEN], *s = buf;
+
+ while ((c = getc(fp)) != EOF && c != ' ' && c != '\n' && c != '\t')
+ if (s - buf < (int)sizeof buf - 2)
+ *s++ = c;
+ *s = 0;
+ return s == buf ? (char *)0 : string(buf);
+}
+
+/* gather - read prof.out data from fd */
+static int gather(void) {
+ int i, nfiles, nfuncs, npoints;
+ char *files[64];
+
+ if ((nfiles = getd()) < 0)
+ return 0;
+ assert(nfiles < NELEMS(files));
+ for (i = 0; i < nfiles; i++) {
+ if ((files[i] = getstr()) == 0)
+ return -1;
+ if (!findfile(files[i])) {
+ struct file *new;
+ NEW(new, PERM);
+ new->name = files[i];
+ new->size = new->count = 0;
+ new->counts = 0;
+ new->funcs = 0;
+ new->link = filelist;
+ filelist = new;
+ }
+ }
+ if ((nfuncs = getd()) < 0)
+ return -1;
+ for (i = 0; i < nfuncs; i++) {
+ struct func *q;
+ char *name, *file;
+ int f, x, y, count;
+ if ((name = getstr()) == 0 || (f = getd()) <= 0
+ || (x = getd()) < 0 || (y = getd()) < 0 || (count = getd()) < 0)
+ return -1;
+ q = afunction(name, files[f-1], x, y, count);
+ if ((name = getstr()) == 0 || (file = getstr()) == 0
+ || (x = getd()) < 0 || (y = getd()) < 0)
+ return -1;
+ if (*name != '?')
+ acaller(name, file, x, y, count, q);
+ }
+ if ((npoints = getd()) < 0)
+ return -1;
+ for (i = 0; i < npoints; i++) {
+ int f, x, y, count;
+ if ((f = getd()) < 0 || (x = getd()) < 0 || (y = getd()) < 0
+ || (count = getd()) < 0)
+ return -1;
+ if (f)
+ apoint(i, files[f-1], x, y, count);
+ }
+ return 1;
+}
+
+/* process - read prof.out data from file */
+int process(char *file) {
+ int more;
+
+ if ((fp = fopen(file, "r")) != NULL) {
+ struct file *p;
+ while ((more = gather()) > 0)
+ ;
+ fclose(fp);
+ if (more < 0)
+ return more;
+ for (p = filelist; p; p = p->link)
+ qsort(p->counts, p->count, sizeof *p->counts,
+ (int (*)(const void *, const void *))
+ compare);
+
+ return 1;
+ }
+ return 0;
+}
diff --git a/lcc/src/rcc.asdl b/lcc/src/rcc.asdl
new file mode 100755
index 0000000..833478e
--- /dev/null
+++ b/lcc/src/rcc.asdl
@@ -0,0 +1,70 @@
+-- lcc IR
+-- $Id: rcc.asdl 145 2001-10-17 21:53:10Z timo $
+module rcc {
+
+-- Pickles start with an int version number, followed by rcc.program
+
+program = (int nuids,int nlabels,item* items,interface* interfaces,int argc,string *argv)
+
+real = (int msb,int lsb)
+
+item = Symbol(symbol symbol)
+ | Type(type type)
+ attributes(int uid)
+
+symbol = (identifier id,int type,int scope,int sclass,int ref,int flags)
+
+field = (identifier id,int type,int offset,int bitsize,int lsb)
+
+enum = (identifier id,int value)
+
+type = INT
+ | UNSIGNED
+ | FLOAT
+ | VOID
+ | POINTER(int type)
+ | ENUM(identifier tag,enum* ids)
+ | STRUCT(identifier tag,field* fields)
+ | UNION(identifier tag,field* fields)
+ | ARRAY(int type)
+ | FUNCTION(int type,int* formals)
+ | CONST(int type)
+ | VOLATILE(int type)
+ attributes(int size,int align)
+
+interface = Export(int p)
+ | Import(int p)
+ | Global(int p,int seg)
+ | Local(int uid,symbol p) -- includes formals
+ | Address(int uid,symbol q,int p,int n)
+ | Segment(int seg)
+ | Defaddress(int p)
+ | Deflabel(int label)
+ | Defconst(int suffix,int size,int value)
+ | Defconstf(int size,real value)
+ | Defstring(string s)
+ | Space(int n)
+ | Function(int f,int* caller,int* callee,int ncalls,interface* codelist)
+ | Blockbeg
+ | Blockend
+ | Forest(node* nodes)
+
+node = CNST(int value)
+ | CNSTF(real value)
+ | ARG(node left,int len,int align)
+ | ASGN(node left,node right,int len,int align)
+ | CVT(int op,node left,int fromsize)
+ | CALL(node left,int type)
+ | CALLB(node left,node right,int type)
+ | RET
+ | ADDRG(int uid)
+ | ADDRL(int uid)
+ | ADDRF(int uid)
+ | Unary(int op,node left) -- INDIR RET JUMP NEG BCOM
+ | Binary(int op,node left,node right) -- ADD SUB DIV MUL MOD BOR BAND BXOR RSH LSH
+ | Compare(int op,node left,node right,int label) -- EQ NE GT GE LE LT
+ | LABEL(int label)
+ | BRANCH(int label)
+ | CSE(int uid,node node)
+ attributes(int suffix,int size)
+}
diff --git a/lcc/src/run.sh b/lcc/src/run.sh
new file mode 100755
index 0000000..432872e
--- /dev/null
+++ b/lcc/src/run.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# run .../target/os/tst/foo.s [ remotehost ]
+
+# set -x
+target=`echo $1 | awk -F/ '{ print $(NF-3) }'`
+os=`echo $1 | awk -F/ '{ print $(NF-2) }'`
+dir=$target/$os
+
+case "$1" in
+*symbolic/irix*) idir=include/mips/irix; remotehost=noexecute ;;
+*symbolic/osf*) idir=include/alpha/osf; remotehost=noexecute ;;
+*) idir=include/$dir; remotehost=${2-$REMOTEHOST} ;;
+esac
+
+if [ ! -d "$target/$os" -o ! -d "$idir" ]; then
+ echo 2>&1 $0: unknown combination '"'$target/$os'"'
+ exit 1
+fi
+
+C=`basename $1 .s`
+BUILDDIR=${BUILDDIR-.} LCC="${LCC-${BUILDDIR}/lcc} -Wo-lccdir=$BUILDDIR"
+TSTDIR=${TSTDIR-${BUILDDIR}/$dir/tst}
+if [ ! -d $TSTDIR ]; then mkdir -p $TSTDIR; fi
+
+echo ${BUILDDIR}/rcc$EXE -target=$target/$os $1: 1>&2
+$LCC -S -I$idir -Ualpha -Usun -Uvax -Umips -Ux86 \
+ -Wf-errout=$TSTDIR/$C.2 -D$target -Wf-g0 \
+ -Wf-target=$target/$os -o $1 tst/$C.c
+if [ $? != 0 ]; then remotehost=noexecute; fi
+if [ -r $dir/tst/$C.2bk ]; then
+ diff $dir/tst/$C.2bk $TSTDIR/$C.2
+fi
+if [ -r $dir/tst/$C.sbk ]; then
+ if diff $dir/tst/$C.sbk $TSTDIR/$C.s; then exit 0; fi
+fi
+
+case "$remotehost" in
+noexecute) exit 0 ;;
+""|"-") $LCC -o $TSTDIR/$C$EXE $1; $TSTDIR/$C$EXE <tst/$C.0 >$TSTDIR/$C.1 ;;
+*) rcp $1 $remotehost:
+ if expr "$remotehost" : '.*@' >/dev/null ; then
+ remotehost="`expr $remotehost : '.*@\(.*\)'` -l `expr $remotehost : '\(.*\)@'`"
+ fi
+ rsh $remotehost "cc -o $C$EXE $C.s -lm;./$C$EXE;rm -f $C$EXE $C.[so]" <tst/$C.0 >$TSTDIR/$C.1
+ ;;
+esac
+if [ -r $dir/tst/$C.1bk ]; then
+ diff $dir/tst/$C.1bk $TSTDIR/$C.1
+ exit $?
+fi
+exit 0
diff --git a/lcc/src/simp.c b/lcc/src/simp.c
new file mode 100755
index 0000000..04699bb
--- /dev/null
+++ b/lcc/src/simp.c
@@ -0,0 +1,587 @@
+#include "c.h"
+#include <float.h>
+
+
+#define foldcnst(TYPE,VAR,OP) \
+ if (l->op == CNST+TYPE && r->op == CNST+TYPE) \
+ return cnsttree(ty, l->u.v.VAR OP r->u.v.VAR)
+#define commute(L,R) \
+ if (generic(R->op) == CNST && generic(L->op) != CNST) \
+ do { Tree t = L; L = R; R = t; } while(0)
+#define xfoldcnst(TYPE,VAR,OP,FUNC)\
+ if (l->op == CNST+TYPE && r->op == CNST+TYPE\
+ && FUNC(l->u.v.VAR,r->u.v.VAR,\
+ ty->u.sym->u.limits.min.VAR,\
+ ty->u.sym->u.limits.max.VAR, needconst)) \
+ return cnsttree(ty, l->u.v.VAR OP r->u.v.VAR)
+#define xcvtcnst(FTYPE,SRC,DST,VAR,EXPR) \
+ if (l->op == CNST+FTYPE) do {\
+ if (!explicitCast\
+ && ((SRC) < DST->u.sym->u.limits.min.VAR || (SRC) > DST->u.sym->u.limits.max.VAR))\
+ warning("overflow in converting constant expression from `%t' to `%t'\n", l->type, DST);\
+ if (needconst\
+ || !((SRC) < DST->u.sym->u.limits.min.VAR || (SRC) > DST->u.sym->u.limits.max.VAR))\
+ return cnsttree(ty, (EXPR)); } while(0)
+#define identity(X,Y,TYPE,VAR,VAL) \
+ if (X->op == CNST+TYPE && X->u.v.VAR == VAL) return Y
+#define zerofield(OP,TYPE,VAR) \
+ if (l->op == FIELD \
+ && r->op == CNST+TYPE && r->u.v.VAR == 0)\
+ return eqtree(OP, bittree(BAND, l->kids[0],\
+ cnsttree(unsignedtype, \
+ (unsigned long)fieldmask(l->u.field)<<fieldright(l->u.field))), r)
+#define cfoldcnst(TYPE,VAR,OP) \
+ if (l->op == CNST+TYPE && r->op == CNST+TYPE) \
+ return cnsttree(inttype, (long)(l->u.v.VAR OP r->u.v.VAR))
+#define foldaddp(L,R,RTYPE,VAR) \
+ if (L->op == CNST+P && R->op == CNST+RTYPE) { \
+ Tree e = tree(CNST+P, ty, NULL, NULL);\
+ e->u.v.p = (char *)L->u.v.p + R->u.v.VAR;\
+ return e; }
+#define ufoldcnst(TYPE,EXP) if (l->op == CNST+TYPE) return EXP
+#define sfoldcnst(OP) \
+ if (l->op == CNST+U && r->op == CNST+I \
+ && r->u.v.i >= 0 && r->u.v.i < 8*l->type->size) \
+ return cnsttree(ty, (unsigned long)(l->u.v.u OP r->u.v.i))
+#define geu(L,R,V) \
+ if (R->op == CNST+U && R->u.v.u == 0) do { \
+ warning("result of unsigned comparison is constant\n"); \
+ return tree(RIGHT, inttype, root(L), cnsttree(inttype, (long)(V))); } while(0)
+#define idempotent(OP) if (l->op == OP) return l->kids[0]
+
+int needconst;
+int explicitCast;
+static int addi(long x, long y, long min, long max, int needconst) {
+ int cond = x == 0 || y == 0
+ || x < 0 && y < 0 && x >= min - y
+ || x < 0 && y > 0
+ || x > 0 && y < 0
+ || x > 0 && y > 0 && x <= max - y;
+ if (!cond && needconst) {
+ warning("overflow in constant expression\n");
+ cond = 1;
+ }
+ return cond;
+
+
+}
+
+static int addd(double x, double y, double min, double max, int needconst) {
+ int cond = x == 0 || y == 0
+ || x < 0 && y < 0 && x >= min - y
+ || x < 0 && y > 0
+ || x > 0 && y < 0
+ || x > 0 && y > 0 && x <= max - y;
+ if (!cond && needconst) {
+ warning("overflow in constant expression\n");
+ cond = 1;
+ }
+ return cond;
+
+
+}
+
+static Tree addrtree(Tree e, long n, Type ty) {
+ Symbol p = e->u.sym, q;
+
+ if (p->scope == GLOBAL
+ || p->sclass == STATIC || p->sclass == EXTERN)
+ NEW0(q, PERM);
+ else
+ NEW0(q, FUNC);
+ q->name = stringd(genlabel(1));
+ q->sclass = p->sclass;
+ q->scope = p->scope;
+ assert(isptr(ty) || isarray(ty));
+ q->type = isptr(ty) ? ty->type : ty;
+ q->temporary = p->temporary;
+ q->generated = p->generated;
+ q->addressed = p->addressed;
+ q->computed = 1;
+ q->defined = 1;
+ q->ref = 1;
+ if (p->scope == GLOBAL
+ || p->sclass == STATIC || p->sclass == EXTERN) {
+ if (p->sclass == AUTO)
+ q->sclass = STATIC;
+ (*IR->address)(q, p, n);
+ } else {
+ Code cp;
+ addlocal(p);
+ cp = code(Address);
+ cp->u.addr.sym = q;
+ cp->u.addr.base = p;
+ cp->u.addr.offset = n;
+ }
+ e = tree(e->op, ty, NULL, NULL);
+ e->u.sym = q;
+ return e;
+}
+
+/* div[id] - return 1 if min <= x/y <= max, 0 otherwise */
+static int divi(long x, long y, long min, long max, int needconst) {
+ int cond = y != 0 && !(x == min && y == -1);
+ if (!cond && needconst) {
+ warning("overflow in constant expression\n");
+ cond = 1;
+ }
+ return cond;
+
+
+}
+
+static int divd(double x, double y, double min, double max, int needconst) {
+ int cond;
+
+ if (x < 0) x = -x;
+ if (y < 0) y = -y;
+ cond = y != 0 && !(y < 1 && x > max*y);
+ if (!cond && needconst) {
+ warning("overflow in constant expression\n");
+ cond = 1;
+ }
+ return cond;
+
+}
+
+/* mul[id] - return 1 if min <= x*y <= max, 0 otherwise */
+static int muli(long x, long y, long min, long max, int needconst) {
+ int cond = x > -1 && x <= 1 || y > -1 && y <= 1
+ || x < 0 && y < 0 && -x <= max/-y
+ || x < 0 && y > 0 && x >= min/y
+ || x > 0 && y < 0 && y >= min/x
+ || x > 0 && y > 0 && x <= max/y;
+ if (!cond && needconst) {
+ warning("overflow in constant expression\n");
+ cond = 1;
+ }
+ return cond;
+
+
+}
+
+static int muld(double x, double y, double min, double max, int needconst) {
+ int cond = x >= -1 && x <= 1 || y >= -1 && y <= 1
+ || x < 0 && y < 0 && -x <= max/-y
+ || x < 0 && y > 0 && x >= min/y
+ || x > 0 && y < 0 && y >= min/x
+ || x > 0 && y > 0 && x <= max/y;
+ if (!cond && needconst) {
+ warning("overflow in constant expression\n");
+ cond = 1;
+ }
+ return cond;
+
+
+}
+/* sub[id] - return 1 if min <= x-y <= max, 0 otherwise */
+static int subi(long x, long y, long min, long max, int needconst) {
+ return addi(x, -y, min, max, needconst);
+}
+
+static int subd(double x, double y, double min, double max, int needconst) {
+ return addd(x, -y, min, max, needconst);
+}
+Tree constexpr(int tok) {
+ Tree p;
+
+ needconst++;
+ p = expr1(tok);
+ needconst--;
+ return p;
+}
+
+int intexpr(int tok, int n) {
+ Tree p = constexpr(tok);
+
+ needconst++;
+ if (p->op == CNST+I || p->op == CNST+U)
+ n = cast(p, inttype)->u.v.i;
+ else
+ error("integer expression must be constant\n");
+ needconst--;
+ return n;
+}
+Tree simplify(int op, Type ty, Tree l, Tree r) {
+ int n;
+ Tree p;
+
+ if (optype(op) == 0)
+ op = mkop(op, ty);
+ switch (op) {
+ case ADD+U:
+ foldcnst(U,u,+);
+ commute(r,l);
+ identity(r,l,U,u,0);
+ break;
+ case ADD+I:
+ xfoldcnst(I,i,+,addi);
+ commute(r,l);
+ identity(r,l,I,i,0);
+ break;
+ case CVI+I:
+ xcvtcnst(I,l->u.v.i,ty,i,(long)extend(l->u.v.i,ty));
+ break;
+ case CVU+I:
+ if (l->op == CNST+U) {
+ if (!explicitCast && l->u.v.u > ty->u.sym->u.limits.max.i)
+ warning("overflow in converting constant expression from `%t' to `%t'\n", l->type, ty);
+ if (needconst || !(l->u.v.u > ty->u.sym->u.limits.max.i))
+ return cnsttree(ty, (long)extend(l->u.v.u,ty));
+ }
+ break;
+ case CVP+U:
+ xcvtcnst(P,(unsigned long)l->u.v.p,ty,u,(unsigned long)l->u.v.p);
+ break;
+ case CVU+P:
+ xcvtcnst(U,(void*)l->u.v.u,ty,p,(void*)l->u.v.u);
+ break;
+ case CVP+P:
+ xcvtcnst(P,l->u.v.p,ty,p,l->u.v.p);
+ break;
+ case CVI+U:
+ xcvtcnst(I,l->u.v.i,ty,u,((unsigned long)l->u.v.i)&ones(8*ty->size));
+ break;
+ case CVU+U:
+ xcvtcnst(U,l->u.v.u,ty,u,l->u.v.u&ones(8*ty->size));
+ break;
+
+ case CVI+F:
+ xcvtcnst(I,l->u.v.i,ty,d,(long double)l->u.v.i);
+ case CVU+F:
+ xcvtcnst(U,l->u.v.u,ty,d,(long double)l->u.v.u);
+ break;
+ case CVF+I:
+ xcvtcnst(F,l->u.v.d,ty,i,(long)l->u.v.d);
+ break;
+ case CVF+F: {
+ float d;
+ if (l->op == CNST+F)
+ if (l->u.v.d < ty->u.sym->u.limits.min.d)
+ d = ty->u.sym->u.limits.min.d;
+ else if (l->u.v.d > ty->u.sym->u.limits.max.d)
+ d = ty->u.sym->u.limits.max.d;
+ else
+ d = l->u.v.d;
+ xcvtcnst(F,l->u.v.d,ty,d,(long double)d);
+ break;
+ }
+ case BAND+U:
+ foldcnst(U,u,&);
+ commute(r,l);
+ identity(r,l,U,u,ones(8*ty->size));
+ if (r->op == CNST+U && r->u.v.u == 0)
+ return tree(RIGHT, ty, root(l), cnsttree(ty, 0UL));
+ break;
+ case BAND+I:
+ foldcnst(I,i,&);
+ commute(r,l);
+ identity(r,l,I,i,ones(8*ty->size));
+ if (r->op == CNST+I && r->u.v.u == 0)
+ return tree(RIGHT, ty, root(l), cnsttree(ty, 0L));
+ break;
+
+ case MUL+U:
+ commute(l,r);
+ if (l->op == CNST+U && (n = ispow2(l->u.v.u)) != 0)
+ return simplify(LSH, ty, r, cnsttree(inttype, (long)n));
+ foldcnst(U,u,*);
+ identity(r,l,U,u,1);
+ break;
+ case NE+I:
+ cfoldcnst(I,i,!=);
+ commute(r,l);
+ zerofield(NE,I,i);
+ break;
+
+ case EQ+I:
+ cfoldcnst(I,i,==);
+ commute(r,l);
+ zerofield(EQ,I,i);
+ break;
+ case ADD+P:
+ foldaddp(l,r,I,i);
+ foldaddp(l,r,U,u);
+ foldaddp(r,l,I,i);
+ foldaddp(r,l,U,u);
+ commute(r,l);
+ identity(r,retype(l,ty),I,i,0);
+ identity(r,retype(l,ty),U,u,0);
+ if (isaddrop(l->op)
+ && (r->op == CNST+I && r->u.v.i <= longtype->u.sym->u.limits.max.i
+ && r->u.v.i >= longtype->u.sym->u.limits.min.i
+ || r->op == CNST+U && r->u.v.u <= longtype->u.sym->u.limits.max.i))
+ return addrtree(l, cast(r, longtype)->u.v.i, ty);
+ if (l->op == ADD+P && isaddrop(l->kids[1]->op)
+ && (r->op == CNST+I && r->u.v.i <= longtype->u.sym->u.limits.max.i
+ && r->u.v.i >= longtype->u.sym->u.limits.min.i
+ || r->op == CNST+U && r->u.v.u <= longtype->u.sym->u.limits.max.i))
+ return simplify(ADD+P, ty, l->kids[0],
+ addrtree(l->kids[1], cast(r, longtype)->u.v.i, ty));
+ if ((l->op == ADD+I || l->op == SUB+I)
+ && l->kids[1]->op == CNST+I && isaddrop(r->op))
+ return simplify(ADD+P, ty, l->kids[0],
+ simplify(generic(l->op)+P, ty, r, l->kids[1]));
+ if (l->op == ADD+P && generic(l->kids[1]->op) == CNST
+ && generic(r->op) == CNST)
+ return simplify(ADD+P, ty, l->kids[0],
+ simplify(ADD, l->kids[1]->type, l->kids[1], r));
+ if (l->op == ADD+I && generic(l->kids[1]->op) == CNST
+ && r->op == ADD+P && generic(r->kids[1]->op) == CNST)
+ return simplify(ADD+P, ty, l->kids[0],
+ simplify(ADD+P, ty, r->kids[0],
+ simplify(ADD, r->kids[1]->type, l->kids[1], r->kids[1])));
+ if (l->op == RIGHT && l->kids[1])
+ return tree(RIGHT, ty, l->kids[0],
+ simplify(ADD+P, ty, l->kids[1], r));
+ else if (l->op == RIGHT && l->kids[0])
+ return tree(RIGHT, ty,
+ simplify(ADD+P, ty, l->kids[0], r), NULL);
+ break;
+
+ case ADD+F:
+ xfoldcnst(F,d,+,addd);
+ commute(r,l);
+ break;
+ case AND+I:
+ op = AND;
+ ufoldcnst(I,l->u.v.i ? cond(r) : l); /* 0&&r => 0, 1&&r => r */
+ break;
+ case OR+I:
+ op = OR;
+ /* 0||r => r, 1||r => 1 */
+ ufoldcnst(I,l->u.v.i ? cnsttree(ty, 1L) : cond(r));
+ break;
+ case BCOM+I:
+ ufoldcnst(I,cnsttree(ty, (long)extend((~l->u.v.i)&ones(8*ty->size), ty)));
+ idempotent(BCOM+U);
+ break;
+ case BCOM+U:
+ ufoldcnst(U,cnsttree(ty, (unsigned long)((~l->u.v.u)&ones(8*ty->size))));
+ idempotent(BCOM+U);
+ break;
+ case BOR+U:
+ foldcnst(U,u,|);
+ commute(r,l);
+ identity(r,l,U,u,0);
+ break;
+ case BOR+I:
+ foldcnst(I,i,|);
+ commute(r,l);
+ identity(r,l,I,i,0);
+ break;
+ case BXOR+U:
+ foldcnst(U,u,^);
+ commute(r,l);
+ identity(r,l,U,u,0);
+ break;
+ case BXOR+I:
+ foldcnst(I,i,^);
+ commute(r,l);
+ identity(r,l,I,i,0);
+ break;
+ case DIV+F:
+ xfoldcnst(F,d,/,divd);
+ break;
+ case DIV+I:
+ identity(r,l,I,i,1);
+ if (r->op == CNST+I && r->u.v.i == 0
+ || l->op == CNST+I && l->u.v.i == ty->u.sym->u.limits.min.i
+ && r->op == CNST+I && r->u.v.i == -1)
+ break;
+ xfoldcnst(I,i,/,divi);
+ break;
+ case DIV+U:
+ identity(r,l,U,u,1);
+ if (r->op == CNST+U && r->u.v.u == 0)
+ break;
+ if (r->op == CNST+U && (n = ispow2(r->u.v.u)) != 0)
+ return simplify(RSH, ty, l, cnsttree(inttype, (long)n));
+ foldcnst(U,u,/);
+ break;
+ case EQ+F:
+ cfoldcnst(F,d,==);
+ commute(r,l);
+ break;
+ case EQ+U:
+ cfoldcnst(U,u,==);
+ commute(r,l);
+ zerofield(EQ,U,u);
+ break;
+ case GE+F: cfoldcnst(F,d,>=); break;
+ case GE+I: cfoldcnst(I,i,>=); break;
+ case GE+U:
+ geu(l,r,1); /* l >= 0 => (l,1) */
+ cfoldcnst(U,u,>=);
+ if (l->op == CNST+U && l->u.v.u == 0) /* 0 >= r => r == 0 */
+ return eqtree(EQ, r, l);
+ break;
+ case GT+F: cfoldcnst(F,d, >); break;
+ case GT+I: cfoldcnst(I,i, >); break;
+ case GT+U:
+ geu(r,l,0); /* 0 > r => (r,0) */
+ cfoldcnst(U,u, >);
+ if (r->op == CNST+U && r->u.v.u == 0) /* l > 0 => l != 0 */
+ return eqtree(NE, l, r);
+ break;
+ case LE+F: cfoldcnst(F,d,<=); break;
+ case LE+I: cfoldcnst(I,i,<=); break;
+ case LE+U:
+ geu(r,l,1); /* 0 <= r => (r,1) */
+ cfoldcnst(U,u,<=);
+ if (r->op == CNST+U && r->u.v.u == 0) /* l <= 0 => l == 0 */
+ return eqtree(EQ, l, r);
+ break;
+ case LSH+I:
+ identity(r,l,I,i,0);
+ if (l->op == CNST+I && r->op == CNST+I
+ && r->u.v.i >= 0 && r->u.v.i < 8*l->type->size
+ && muli(l->u.v.i, 1<<r->u.v.i, ty->u.sym->u.limits.min.i, ty->u.sym->u.limits.max.i, needconst))
+ return cnsttree(ty, (long)(l->u.v.i<<r->u.v.i));
+ if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
+ warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
+ break;
+ }
+
+ break;
+ case LSH+U:
+ identity(r,l,I,i,0);
+ sfoldcnst(<<);
+ if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
+ warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
+ break;
+ }
+
+ break;
+
+ case LT+F: cfoldcnst(F,d, <); break;
+ case LT+I: cfoldcnst(I,i, <); break;
+ case LT+U:
+ geu(l,r,0); /* l < 0 => (l,0) */
+ cfoldcnst(U,u, <);
+ if (l->op == CNST+U && l->u.v.u == 0) /* 0 < r => r != 0 */
+ return eqtree(NE, r, l);
+ break;
+ case MOD+I:
+ if (r->op == CNST+I && r->u.v.i == 1) /* l%1 => (l,0) */
+ return tree(RIGHT, ty, root(l), cnsttree(ty, 0L));
+ if (r->op == CNST+I && r->u.v.i == 0
+ || l->op == CNST+I && l->u.v.i == ty->u.sym->u.limits.min.i
+ && r->op == CNST+I && r->u.v.i == -1)
+ break;
+ xfoldcnst(I,i,%,divi);
+ break;
+ case MOD+U:
+ if (r->op == CNST+U && ispow2(r->u.v.u)) /* l%2^n => l&(2^n-1) */
+ return bittree(BAND, l, cnsttree(ty, r->u.v.u - 1));
+ if (r->op == CNST+U && r->u.v.u == 0)
+ break;
+ foldcnst(U,u,%);
+ break;
+ case MUL+F:
+ xfoldcnst(F,d,*,muld);
+ commute(l,r);
+ break;
+ case MUL+I:
+ commute(l,r);
+ xfoldcnst(I,i,*,muli);
+ if (l->op == CNST+I && r->op == ADD+I && r->kids[1]->op == CNST+I)
+ /* c1*(x + c2) => c1*x + c1*c2 */
+ return simplify(ADD, ty, simplify(MUL, ty, l, r->kids[0]),
+ simplify(MUL, ty, l, r->kids[1]));
+ if (l->op == CNST+I && r->op == SUB+I && r->kids[1]->op == CNST+I)
+ /* c1*(x - c2) => c1*x - c1*c2 */
+ return simplify(SUB, ty, simplify(MUL, ty, l, r->kids[0]),
+ simplify(MUL, ty, l, r->kids[1]));
+ if (l->op == CNST+I && l->u.v.i > 0 && (n = ispow2(l->u.v.i)) != 0)
+ /* 2^n * r => r<<n */
+ return simplify(LSH, ty, r, cnsttree(inttype, (long)n));
+ identity(r,l,I,i,1);
+ break;
+ case NE+F:
+ cfoldcnst(F,d,!=);
+ commute(r,l);
+ break;
+ case NE+U:
+ cfoldcnst(U,u,!=);
+ commute(r,l);
+ zerofield(NE,U,u);
+ break;
+ case NEG+F:
+ ufoldcnst(F,cnsttree(ty, -l->u.v.d));
+ idempotent(NEG+F);
+ break;
+ case NEG+I:
+ if (l->op == CNST+I) {
+ if (needconst && l->u.v.i == ty->u.sym->u.limits.min.i)
+ warning("overflow in constant expression\n");
+ if (needconst || l->u.v.i != ty->u.sym->u.limits.min.i)
+ return cnsttree(ty, -l->u.v.i);
+ }
+ idempotent(NEG+I);
+ break;
+ case NOT+I:
+ op = NOT;
+ ufoldcnst(I,cnsttree(ty, !l->u.v.i));
+ break;
+ case RSH+I:
+ identity(r,l,I,i,0);
+ if (l->op == CNST+I && r->op == CNST+I
+ && r->u.v.i >= 0 && r->u.v.i < 8*l->type->size) {
+ long n = l->u.v.i>>r->u.v.i;
+ if (l->u.v.i < 0)
+ n |= ~0UL<<(8*l->type->size - r->u.v.i);
+ return cnsttree(ty, n);
+ }
+ if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
+ warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
+ break;
+ }
+
+ break;
+ case RSH+U:
+ identity(r,l,I,i,0);
+ sfoldcnst(>>);
+ if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
+ warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
+ break;
+ }
+
+ break;
+ case SUB+F:
+ xfoldcnst(F,d,-,subd);
+ break;
+ case SUB+I:
+ xfoldcnst(I,i,-,subi);
+ identity(r,l,I,i,0);
+ break;
+ case SUB+U:
+ foldcnst(U,u,-);
+ identity(r,l,U,u,0);
+ break;
+ case SUB+P:
+ if (l->op == CNST+P && r->op == CNST+P)
+ return cnsttree(ty, (long)((char *)l->u.v.p - (char *)r->u.v.p));
+ if (r->op == CNST+I || r->op == CNST+U)
+ return simplify(ADD, ty, l,
+ cnsttree(inttype, r->op == CNST+I ? -r->u.v.i : -(long)r->u.v.u));
+ if (isaddrop(l->op) && r->op == ADD+I && r->kids[1]->op == CNST+I)
+ /* l - (x + c) => l-c - x */
+ return simplify(SUB, ty,
+ simplify(SUB, ty, l, r->kids[1]), r->kids[0]);
+ break;
+ default:assert(0);
+ }
+ return tree(op, ty, l, r);
+}
+/* ispow2 - if u > 1 && u == 2^n, return n, otherwise return 0 */
+int ispow2(unsigned long u) {
+ int n;
+
+ if (u > 1 && (u&(u-1)) == 0)
+ for (n = 0; u; u >>= 1, n++)
+ if (u&1)
+ return n;
+ return 0;
+}
+
diff --git a/lcc/src/sparc.md b/lcc/src/sparc.md
new file mode 100755
index 0000000..0171492
--- /dev/null
+++ b/lcc/src/sparc.md
@@ -0,0 +1,1163 @@
+%{
+#include "c.h"
+#define NODEPTR_TYPE Node
+#define OP_LABEL(p) ((p)->op)
+#define LEFT_CHILD(p) ((p)->kids[0])
+#define RIGHT_CHILD(p) ((p)->kids[1])
+#define STATE_LABEL(p) ((p)->x.state)
+static void address(Symbol, Symbol, long);
+static void blkfetch(int, int, int, int);
+static void blkloop(int, int, int, int, int, int[]);
+static void blkstore(int, int, int, int);
+static void defaddress(Symbol);
+static void defconst(int, int, Value);
+static void defstring(int, char *);
+static void defsymbol(Symbol);
+static void doarg(Node);
+static void emit2(Node);
+static void export(Symbol);
+static void clobber(Node);
+static void function(Symbol, Symbol [], Symbol [], int);
+static void global(Symbol);
+static void import(Symbol);
+static void local(Symbol);
+static void progbeg(int, char **);
+static void progend(void);
+static void segment(int);
+static void space(int);
+static void target(Node);
+static int imm(Node);
+static void renameregs(void);
+extern Interface sparcIR, solarisIR;
+static void defsymbol2(Symbol);
+static void export2(Symbol);
+static void globalend(void);
+static void global2(Symbol);
+static void segment2(int);
+static void progend2(void);
+
+extern char *stabprefix;
+extern void stabblock(int, int, Symbol*);
+extern void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *);
+extern void stabfend(Symbol, int);
+extern void stabinit(char *, int, char *[]);
+extern void stabline(Coordinate *);
+extern void stabsym(Symbol);
+extern void stabtype(Symbol);
+static Symbol greg[32], gregw;
+static Symbol *oreg = &greg[8], *ireg = &greg[24];
+static Symbol freg[32], freg2[32];
+static Symbol fregw, freg2w;
+
+static int regvars;
+static int retstruct;
+
+static int pflag = 0;
+
+static int cseg;
+
+%}
+%start stmt
+%term CNSTF4=4113
+%term CNSTF8=8209
+%term CNSTF16=16401
+%term CNSTI1=1045
+%term CNSTI2=2069
+%term CNSTI4=4117
+%term CNSTI8=8213
+%term CNSTP4=4119
+%term CNSTP8=8215
+%term CNSTU1=1046
+%term CNSTU2=2070
+%term CNSTU4=4118
+%term CNSTU8=8214
+
+%term ARGB=41
+%term ARGF4=4129
+%term ARGF8=8225
+%term ARGF16=16417
+%term ARGI4=4133
+%term ARGI8=8229
+%term ARGP4=4135
+%term ARGP8=8231
+%term ARGU4=4134
+%term ARGU8=8230
+
+%term ASGNB=57
+%term ASGNF4=4145
+%term ASGNF8=8241
+%term ASGNF16=16433
+%term ASGNI1=1077
+%term ASGNI2=2101
+%term ASGNI4=4149
+%term ASGNI8=8245
+%term ASGNP4=4151
+%term ASGNP8=8247
+%term ASGNU1=1078
+%term ASGNU2=2102
+%term ASGNU4=4150
+%term ASGNU8=8246
+
+%term INDIRB=73
+%term INDIRF4=4161
+%term INDIRF8=8257
+%term INDIRF16=16449
+%term INDIRI1=1093
+%term INDIRI2=2117
+%term INDIRI4=4165
+%term INDIRI8=8261
+%term INDIRP4=4167
+%term INDIRP8=8263
+%term INDIRU1=1094
+%term INDIRU2=2118
+%term INDIRU4=4166
+%term INDIRU8=8262
+
+%term CVFF4=4209
+%term CVFF8=8305
+%term CVFF16=16497
+%term CVFI4=4213
+%term CVFI8=8309
+
+%term CVIF4=4225
+%term CVIF8=8321
+%term CVIF16=16513
+%term CVII1=1157
+%term CVII2=2181
+%term CVII4=4229
+%term CVII8=8325
+%term CVIU1=1158
+%term CVIU2=2182
+%term CVIU4=4230
+%term CVIU8=8326
+
+%term CVPP4=4247
+%term CVPP8=8343
+%term CVPP16=16535
+%term CVPU4=4246
+%term CVPU8=8342
+
+%term CVUI1=1205
+%term CVUI2=2229
+%term CVUI4=4277
+%term CVUI8=8373
+%term CVUP4=4279
+%term CVUP8=8375
+%term CVUP16=16567
+%term CVUU1=1206
+%term CVUU2=2230
+%term CVUU4=4278
+%term CVUU8=8374
+
+%term NEGF4=4289
+%term NEGF8=8385
+%term NEGF16=16577
+%term NEGI4=4293
+%term NEGI8=8389
+
+%term CALLB=217
+%term CALLF4=4305
+%term CALLF8=8401
+%term CALLF16=16593
+%term CALLI4=4309
+%term CALLI8=8405
+%term CALLP4=4311
+%term CALLP8=8407
+%term CALLU4=4310
+%term CALLU8=8406
+%term CALLV=216
+
+%term RETF4=4337
+%term RETF8=8433
+%term RETF16=16625
+%term RETI4=4341
+%term RETI8=8437
+%term RETP4=4343
+%term RETP8=8439
+%term RETU4=4342
+%term RETU8=8438
+%term RETV=248
+
+%term ADDRGP4=4359
+%term ADDRGP8=8455
+
+%term ADDRFP4=4375
+%term ADDRFP8=8471
+
+%term ADDRLP4=4391
+%term ADDRLP8=8487
+
+%term ADDF4=4401
+%term ADDF8=8497
+%term ADDF16=16689
+%term ADDI4=4405
+%term ADDI8=8501
+%term ADDP4=4407
+%term ADDP8=8503
+%term ADDU4=4406
+%term ADDU8=8502
+
+%term SUBF4=4417
+%term SUBF8=8513
+%term SUBF16=16705
+%term SUBI4=4421
+%term SUBI8=8517
+%term SUBP4=4423
+%term SUBP8=8519
+%term SUBU4=4422
+%term SUBU8=8518
+
+%term LSHI4=4437
+%term LSHI8=8533
+%term LSHU4=4438
+%term LSHU8=8534
+
+%term MODI4=4453
+%term MODI8=8549
+%term MODU4=4454
+%term MODU8=8550
+
+%term RSHI4=4469
+%term RSHI8=8565
+%term RSHU4=4470
+%term RSHU8=8566
+
+%term BANDI4=4485
+%term BANDI8=8581
+%term BANDU4=4486
+%term BANDU8=8582
+
+%term BCOMI4=4501
+%term BCOMI8=8597
+%term BCOMU4=4502
+%term BCOMU8=8598
+
+%term BORI4=4517
+%term BORI8=8613
+%term BORU4=4518
+%term BORU8=8614
+
+%term BXORI4=4533
+%term BXORI8=8629
+%term BXORU4=4534
+%term BXORU8=8630
+
+%term DIVF4=4545
+%term DIVF8=8641
+%term DIVF16=16833
+%term DIVI4=4549
+%term DIVI8=8645
+%term DIVU4=4550
+%term DIVU8=8646
+
+%term MULF4=4561
+%term MULF8=8657
+%term MULF16=16849
+%term MULI4=4565
+%term MULI8=8661
+%term MULU4=4566
+%term MULU8=8662
+
+%term EQF4=4577
+%term EQF8=8673
+%term EQF16=16865
+%term EQI4=4581
+%term EQI8=8677
+%term EQU4=4582
+%term EQU8=8678
+
+%term GEF4=4593
+%term GEF8=8689
+%term GEI4=4597
+%term GEI8=8693
+%term GEI16=16885
+%term GEU4=4598
+%term GEU8=8694
+
+%term GTF4=4609
+%term GTF8=8705
+%term GTF16=16897
+%term GTI4=4613
+%term GTI8=8709
+%term GTU4=4614
+%term GTU8=8710
+
+%term LEF4=4625
+%term LEF8=8721
+%term LEF16=16913
+%term LEI4=4629
+%term LEI8=8725
+%term LEU4=4630
+%term LEU8=8726
+
+%term LTF4=4641
+%term LTF8=8737
+%term LTF16=16929
+%term LTI4=4645
+%term LTI8=8741
+%term LTU4=4646
+%term LTU8=8742
+
+%term NEF4=4657
+%term NEF8=8753
+%term NEF16=16945
+%term NEI4=4661
+%term NEI8=8757
+%term NEU4=4662
+%term NEU8=8758
+
+%term JUMPV=584
+
+%term LABELV=600
+
+%term LOADB=233
+%term LOADF4=4321
+%term LOADF8=8417
+%term LOADF16=16609
+%term LOADI1=1253
+%term LOADI2=2277
+%term LOADI4=4325
+%term LOADI8=8421
+%term LOADP4=4327
+%term LOADP8=8423
+%term LOADU1=1254
+%term LOADU2=2278
+%term LOADU4=4326
+%term LOADU8=8422
+
+%term VREGP=711
+%%
+reg: INDIRI1(VREGP) "# read register\n"
+reg: INDIRU1(VREGP) "# read register\n"
+
+reg: INDIRI2(VREGP) "# read register\n"
+reg: INDIRU2(VREGP) "# read register\n"
+
+reg: INDIRF4(VREGP) "# read register\n"
+reg: INDIRI4(VREGP) "# read register\n"
+reg: INDIRP4(VREGP) "# read register\n"
+reg: INDIRU4(VREGP) "# read register\n"
+
+reg: INDIRF8(VREGP) "# read register\n"
+reg: INDIRI8(VREGP) "# read register\n"
+reg: INDIRP8(VREGP) "# read register\n"
+reg: INDIRU8(VREGP) "# read register\n"
+
+stmt: ASGNI1(VREGP,reg) "# write register\n"
+stmt: ASGNU1(VREGP,reg) "# write register\n"
+
+stmt: ASGNI2(VREGP,reg) "# write register\n"
+stmt: ASGNU2(VREGP,reg) "# write register\n"
+
+stmt: ASGNF4(VREGP,reg) "# write register\n"
+stmt: ASGNI4(VREGP,reg) "# write register\n"
+stmt: ASGNP4(VREGP,reg) "# write register\n"
+stmt: ASGNU4(VREGP,reg) "# write register\n"
+
+stmt: ASGNF8(VREGP,reg) "# write register\n"
+stmt: ASGNI8(VREGP,reg) "# write register\n"
+stmt: ASGNP8(VREGP,reg) "# write register\n"
+stmt: ASGNU8(VREGP,reg) "# write register\n"
+con: CNSTI1 "%a"
+con: CNSTU1 "%a"
+
+con: CNSTI2 "%a"
+con: CNSTU2 "%a"
+
+con: CNSTI4 "%a"
+con: CNSTU4 "%a"
+con: CNSTP4 "%a"
+
+con: CNSTI8 "%a"
+con: CNSTU8 "%a"
+con: CNSTP8 "%a"
+stmt: reg ""
+reg: ADDRGP4 "set %a,%%%c\n" 1
+stk13: ADDRFP4 "%a" imm(a)
+stk13: ADDRLP4 "%a" imm(a)
+reg: stk13 "add %0,%%fp,%%%c\n" 1
+stk: ADDRFP4 "set %a,%%%c\n" 2
+stk: ADDRLP4 "set %a,%%%c\n" 2
+reg: ADDRFP4 "set %a,%%%c\nadd %%%c,%%fp,%%%c\n" 3
+reg: ADDRLP4 "set %a,%%%c\nadd %%%c,%%fp,%%%c\n" 3
+con13: CNSTI1 "%a" imm(a)
+con13: CNSTI2 "%a" imm(a)
+con13: CNSTI4 "%a" imm(a)
+con13: CNSTU1 "%a" imm(a)
+con13: CNSTU2 "%a" imm(a)
+con13: CNSTU4 "%a" imm(a)
+con13: CNSTP4 "%a" imm(a)
+base: ADDI4(reg,con13) "%%%0+%1"
+base: ADDP4(reg,con13) "%%%0+%1"
+base: ADDU4(reg,con13) "%%%0+%1"
+base: reg "%%%0"
+base: con13 "%0"
+base: stk13 "%%fp+%0"
+addr: base "%0"
+addr: ADDI4(reg,reg) "%%%0+%%%1"
+addr: ADDP4(reg,reg) "%%%0+%%%1"
+addr: ADDU4(reg,reg) "%%%0+%%%1"
+addr: stk "%%fp+%%%0"
+reg: INDIRI1(addr) "ldsb [%0],%%%c\n" 1
+reg: INDIRI2(addr) "ldsh [%0],%%%c\n" 1
+reg: INDIRI4(addr) "ld [%0],%%%c\n" 1
+reg: INDIRU1(addr) "ldub [%0],%%%c\n" 1
+reg: INDIRU2(addr) "lduh [%0],%%%c\n" 1
+reg: INDIRU4(addr) "ld [%0],%%%c\n" 1
+reg: INDIRP4(addr) "ld [%0],%%%c\n" 1
+reg: INDIRF4(addr) "ld [%0],%%f%c\n" 1
+stmt: ASGNI1(addr,reg) "stb %%%1,[%0]\n" 1
+stmt: ASGNI2(addr,reg) "sth %%%1,[%0]\n" 1
+stmt: ASGNI4(addr,reg) "st %%%1,[%0]\n" 1
+stmt: ASGNU1(addr,reg) "stb %%%1,[%0]\n" 1
+stmt: ASGNU2(addr,reg) "sth %%%1,[%0]\n" 1
+stmt: ASGNU4(addr,reg) "st %%%1,[%0]\n" 1
+stmt: ASGNP4(addr,reg) "st %%%1,[%0]\n" 1
+stmt: ASGNF4(addr,reg) "st %%f%1,[%0]\n" 1
+addrl: ADDRLP4 "%%%fp+%a" imm(a)
+
+reg: INDIRF8(addrl) "ldd [%0],%%f%c\n" 1
+stmt: ASGNF8(addrl,reg) "std %%f%1,[%0]\n" 1
+reg: INDIRF8(base) "ld2 [%0],%%f%c\n" 2
+stmt: ASGNF8(base,reg) "st2 %%f%1,[%0]\n" 2
+spill: ADDRLP4 "%a" !imm(a)
+
+stmt: ASGNI1(spill,reg) "set %0,%%g1\nstb %%%1,[%%fp+%%g1]\n"
+stmt: ASGNI2(spill,reg) "set %0,%%g1\nsth %%%1,[%%fp+%%g1]\n"
+stmt: ASGNI4(spill,reg) "set %0,%%g1\nst %%%1,[%%fp+%%g1]\n"
+stmt: ASGNU1(spill,reg) "set %0,%%g1\nstb %%%1,[%%fp+%%g1]\n"
+stmt: ASGNU2(spill,reg) "set %0,%%g1\nsth %%%1,[%%fp+%%g1]\n"
+stmt: ASGNU4(spill,reg) "set %0,%%g1\nst %%%1,[%%fp+%%g1]\n"
+stmt: ASGNP4(spill,reg) "set %0,%%g1\nst %%%1,[%%fp+%%g1]\n"
+stmt: ASGNF4(spill,reg) "set %0,%%g1\nst %%f%1,[%%fp+%%g1]\n"
+stmt: ASGNF8(spill,reg) "set %0,%%g1\nstd %%f%1,[%%fp+%%g1]\n"
+reg: CVII4(INDIRI1(addr)) "ldsb [%0],%%%c\n" 1
+reg: CVII4(INDIRI2(addr)) "ldsh [%0],%%%c\n" 1
+reg: CVUU4(INDIRU1(addr)) "ldub [%0],%%%c\n" 1
+reg: CVUU4(INDIRU2(addr)) "lduh [%0],%%%c\n" 1
+reg: CVUI4(INDIRU1(addr)) "ldub [%0],%%%c\n" 1
+reg: CVUI4(INDIRU2(addr)) "lduh [%0],%%%c\n" 1
+reg: LOADI1(reg) "mov %%%0,%%%c\n" move(a)
+reg: LOADI2(reg) "mov %%%0,%%%c\n" move(a)
+reg: LOADI4(reg) "mov %%%0,%%%c\n" move(a)
+reg: LOADP4(reg) "mov %%%0,%%%c\n" move(a)
+reg: LOADU1(reg) "mov %%%0,%%%c\n" move(a)
+reg: LOADU2(reg) "mov %%%0,%%%c\n" move(a)
+reg: LOADU4(reg) "mov %%%0,%%%c\n" move(a)
+reg: CNSTI1 "# reg\n" range(a, 0, 0)
+reg: CNSTI2 "# reg\n" range(a, 0, 0)
+reg: CNSTI4 "# reg\n" range(a, 0, 0)
+reg: CNSTP4 "# reg\n" range(a, 0, 0)
+reg: CNSTU1 "# reg\n" range(a, 0, 0)
+reg: CNSTU2 "# reg\n" range(a, 0, 0)
+reg: CNSTU4 "# reg\n" range(a, 0, 0)
+reg: con "set %0,%%%c\n" 1
+rc: con13 "%0"
+rc: reg "%%%0"
+reg: ADDI4(reg,rc) "add %%%0,%1,%%%c\n" 1
+reg: ADDP4(reg,rc) "add %%%0,%1,%%%c\n" 1
+reg: ADDU4(reg,rc) "add %%%0,%1,%%%c\n" 1
+reg: BANDI4(reg,rc) "and %%%0,%1,%%%c\n" 1
+reg: BORI4(reg,rc) "or %%%0,%1,%%%c\n" 1
+reg: BXORI4(reg,rc) "xor %%%0,%1,%%%c\n" 1
+reg: BANDU4(reg,rc) "and %%%0,%1,%%%c\n" 1
+reg: BORU4(reg,rc) "or %%%0,%1,%%%c\n" 1
+reg: BXORU4(reg,rc) "xor %%%0,%1,%%%c\n" 1
+reg: SUBI4(reg,rc) "sub %%%0,%1,%%%c\n" 1
+reg: SUBP4(reg,rc) "sub %%%0,%1,%%%c\n" 1
+reg: SUBU4(reg,rc) "sub %%%0,%1,%%%c\n" 1
+rc5: CNSTI4 "%a" range(a, 0, 31)
+rc5: reg "%%%0"
+reg: LSHI4(reg,rc5) "sll %%%0,%1,%%%c\n" 1
+reg: LSHU4(reg,rc5) "sll %%%0,%1,%%%c\n" 1
+reg: RSHI4(reg,rc5) "sra %%%0,%1,%%%c\n" 1
+reg: RSHU4(reg,rc5) "srl %%%0,%1,%%%c\n" 1
+reg: BANDI4(reg,BCOMI4(rc)) "andn %%%0,%1,%%%c\n" 1
+reg: BORI4(reg,BCOMI4(rc)) "orn %%%0,%1,%%%c\n" 1
+reg: BXORI4(reg,BCOMI4(rc)) "xnor %%%0,%1,%%%c\n" 1
+reg: BANDU4(reg,BCOMU4(rc)) "andn %%%0,%1,%%%c\n" 1
+reg: BORU4(reg,BCOMU4(rc)) "orn %%%0,%1,%%%c\n" 1
+reg: BXORU4(reg,BCOMU4(rc)) "xnor %%%0,%1,%%%c\n" 1
+reg: NEGI4(reg) "neg %%%0,%%%c\n" 1
+reg: BCOMI4(reg) "not %%%0,%%%c\n" 1
+reg: BCOMU4(reg) "not %%%0,%%%c\n" 1
+reg: CVII4(reg) "sll %%%0,8*(4-%a),%%%c; sra %%%c,8*(4-%a),%%%c\n" 2
+reg: CVUU4(reg) "sll %%%0,8*(4-%a),%%%c; srl %%%c,8*(4-%a),%%%c\n" 2
+reg: CVUU4(reg) "and %%%0,0xff,%%%c\n" (a->syms[0]->u.c.v.i == 1 ? 1 : LBURG_MAX)
+reg: CVUU4(reg) "set 0xffff,%%g1; and %%%0,%%g1,%%%c\n" 2
+reg: CVUI4(reg) "and %%%0,0xff,%%%c\n" (a->syms[0]->u.c.v.i == 1 ? 1 : LBURG_MAX)
+reg: CVUI4(reg) "set 0xffff,%%g1; and %%%0,%%g1,%%%c\n" 2
+addrg: ADDRGP4 "%a"
+stmt: JUMPV(addrg) "ba %0; nop\n" 2
+stmt: JUMPV(addr) "jmp %0; nop\n" 2
+stmt: LABELV "%a:\n"
+stmt: EQI4(reg,rc) "cmp %%%0,%1; be %a; nop\n" 3
+stmt: EQU4(reg,rc) "cmp %%%0,%1; be %a; nop\n" 3
+stmt: GEI4(reg,rc) "cmp %%%0,%1; bge %a; nop\n" 3
+stmt: GEU4(reg,rc) "cmp %%%0,%1; bgeu %a; nop\n" 3
+stmt: GTI4(reg,rc) "cmp %%%0,%1; bg %a; nop\n" 3
+stmt: GTU4(reg,rc) "cmp %%%0,%1; bgu %a; nop\n" 3
+stmt: LEI4(reg,rc) "cmp %%%0,%1; ble %a; nop\n" 3
+stmt: LEU4(reg,rc) "cmp %%%0,%1; bleu %a; nop\n" 3
+stmt: LTI4(reg,rc) "cmp %%%0,%1; bl %a; nop\n" 3
+stmt: LTU4(reg,rc) "cmp %%%0,%1; blu %a; nop\n" 3
+stmt: NEI4(reg,rc) "cmp %%%0,%1; bne %a; nop\n" 3
+stmt: NEU4(reg,rc) "cmp %%%0,%1; bne %a; nop\n" 3
+call: ADDRGP4 "%a"
+call: addr "%0"
+reg: CALLF8(call) "call %0; nop\n" 2
+reg: CALLF4(call) "call %0; nop\n" 2
+reg: CALLI4(call) "call %0; nop\n" 2
+reg: CALLP4(call) "call %0; nop\n" 2
+reg: CALLU4(call) "call %0; nop\n" 2
+stmt: CALLV(call) "call %0; nop\n" 2
+stmt: CALLB(call,reg) "call %0; st %%%1,[%%sp+64]; unimp %b&0xfff\n" 3
+
+stmt: RETF8(reg) "# ret\n" 1
+stmt: RETF4(reg) "# ret\n" 1
+stmt: RETI4(reg) "# ret\n" 1
+stmt: RETU4(reg) "# ret\n" 1
+stmt: RETP4(reg) "# ret\n" 1
+stmt: ARGI4(reg) "st %%%0,[%%sp+4*%c+68]\n" 1
+stmt: ARGU4(reg) "st %%%0,[%%sp+4*%c+68]\n" 1
+stmt: ARGP4(reg) "st %%%0,[%%sp+4*%c+68]\n" 1
+stmt: ARGF4(reg) "# ARGF4\n" 1
+stmt: ARGF8(reg) "# ARGF8\n" 1
+
+reg: DIVI4(reg,rc) "sra %%%0,31,%%g1; wr %%g0,%%g1,%%y; nop; nop; nop; sdiv %%%0,%1,%%%c\n" 6
+
+reg: DIVU4(reg,rc) "wr %%g0,%%g0,%%y; nop; nop; nop; udiv %%%0,%1,%%%c\n" 5
+
+reg: MODI4(reg,rc) "sra %%%0,31,%%g1; wr %%g0,%%g1,%%y; nop; nop; nop; sdiv %%%0,%1,%%g1\n; smul %%g1,%1,%%g1; sub %%%0,%%g1,%%%c\n" 8
+
+
+reg: MODU4(reg,rc) "wr %%g0,%%g0,%%y; nop; nop; nop; udiv %%%0,%1,%%g1\n; umul %%g1,%1,%%g1; sub %%%0,%%g1,%%%c\n" 7
+
+
+reg: MULI4(rc,reg) "smul %%%1,%0,%%%c\n" 1
+reg: MULU4(rc,reg) "umul %%%1,%0,%%%c\n" 1
+reg: ADDF8(reg,reg) "faddd %%f%0,%%f%1,%%f%c\n" 1
+reg: ADDF4(reg,reg) "fadds %%f%0,%%f%1,%%f%c\n" 1
+reg: DIVF8(reg,reg) "fdivd %%f%0,%%f%1,%%f%c\n" 1
+reg: DIVF4(reg,reg) "fdivs %%f%0,%%f%1,%%f%c\n" 1
+reg: MULF8(reg,reg) "fmuld %%f%0,%%f%1,%%f%c\n" 1
+reg: MULF4(reg,reg) "fmuls %%f%0,%%f%1,%%f%c\n" 1
+reg: SUBF8(reg,reg) "fsubd %%f%0,%%f%1,%%f%c\n" 1
+reg: SUBF4(reg,reg) "fsubs %%f%0,%%f%1,%%f%c\n" 1
+reg: NEGF4(reg) "fnegs %%f%0,%%f%c\n" 1
+reg: LOADF4(reg) "fmovs %%f%0,%%f%c\n" 1
+reg: CVFF4(reg) "fdtos %%f%0,%%f%c\n" 1
+reg: CVFF8(reg) "fstod %%f%0,%%f%c\n" 1
+reg: CVFI4(reg) "fstoi %%f%0,%%f0; st %%f0,[%%sp+64]; ld [%%sp+64],%%%c\n" (a->syms[0]->u.c.v.i==4?3:LBURG_MAX)
+
+reg: CVFI4(reg) "fdtoi %%f%0,%%f0; st %%f0,[%%sp+64]; ld [%%sp+64],%%%c\n" (a->syms[0]->u.c.v.i==8?3:LBURG_MAX)
+
+reg: CVIF4(reg) "st %%%0,[%%sp+64]; ld [%%sp+64],%%f%c; fitos %%f%c,%%f%c\n" 3
+
+reg: CVIF8(reg) "st %%%0,[%%sp+64]; ld [%%sp+64],%%f%c; fitod %%f%c,%%f%c\n" 3
+
+rel: EQF8(reg,reg) "fcmped %%f%0,%%f%1; nop; fbue"
+rel: EQF4(reg,reg) "fcmpes %%f%0,%%f%1; nop; fbue"
+rel: GEF8(reg,reg) "fcmped %%f%0,%%f%1; nop; fbuge"
+rel: GEF4(reg,reg) "fcmpes %%f%0,%%f%1; nop; fbuge"
+rel: GTF8(reg,reg) "fcmped %%f%0,%%f%1; nop; fbug"
+rel: GTF4(reg,reg) "fcmpes %%f%0,%%f%1; nop; fbug"
+rel: LEF8(reg,reg) "fcmped %%f%0,%%f%1; nop; fbule"
+rel: LEF4(reg,reg) "fcmpes %%f%0,%%f%1; nop; fbule"
+rel: LTF8(reg,reg) "fcmped %%f%0,%%f%1; nop; fbul"
+rel: LTF4(reg,reg) "fcmpes %%f%0,%%f%1; nop; fbul"
+rel: NEF8(reg,reg) "fcmped %%f%0,%%f%1; nop; fbne"
+rel: NEF4(reg,reg) "fcmpes %%f%0,%%f%1; nop; fbne"
+
+stmt: rel "%0 %a; nop\n" 4
+reg: LOADF8(reg) "# LOADD\n" 2
+
+reg: NEGF8(reg) "# NEGD\n" 2
+
+stmt: ASGNB(reg,INDIRB(reg)) "# ASGNB\n"
+
+%%
+static void progend(void){}
+static void progbeg(int argc, char *argv[]) {
+ int i;
+
+ {
+ union {
+ char c;
+ int i;
+ } u;
+ u.i = 0;
+ u.c = 1;
+ swap = ((int)(u.i == 1)) != IR->little_endian;
+ }
+ parseflags(argc, argv);
+ for (i = 0; i < argc; i++)
+ if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "-pg") == 0)
+ pflag = 1;
+ if (IR == &solarisIR)
+ stabprefix = ".LL";
+ else
+ stabprefix = "L";
+ for (i = 0; i < 8; i++) {
+ greg[i + 0] = mkreg(stringf("g%d", i), i + 0, 1, IREG);
+ greg[i + 8] = mkreg(stringf("o%d", i), i + 8, 1, IREG);
+ greg[i + 16] = mkreg(stringf("l%d", i), i + 16, 1, IREG);
+ greg[i + 24] = mkreg(stringf("i%d", i), i + 24, 1, IREG);
+ }
+ gregw = mkwildcard(greg);
+ for (i = 0; i < 32; i++)
+ freg[i] = mkreg("%d", i, 1, FREG);
+ for (i = 0; i < 31; i += 2)
+ freg2[i] = mkreg("%d", i, 3, FREG);
+ fregw = mkwildcard(freg);
+ freg2w = mkwildcard(freg2);
+ tmask[IREG] = 0x3fff3e00;
+ vmask[IREG] = 0x3ff00000;
+ tmask[FREG] = ~(unsigned)0;
+ vmask[FREG] = 0;
+}
+static Symbol rmap(int opk) {
+ switch (optype(opk)) {
+ case I: case U: case P: case B:
+ return gregw;
+ case F:
+ return opsize(opk) == 4 ? fregw : freg2w;
+ default:
+ return 0;
+ }
+}
+static void target(Node p) {
+ assert(p);
+ switch (specific(p->op)) {
+ case CNST+I: case CNST+U: case CNST+P:
+ if (range(p, 0, 0) == 0) {
+ setreg(p, greg[0]);
+ p->x.registered = 1;
+ }
+ break;
+ case CALL+B:
+ assert(p->syms[1] && p->syms[1]->type && isfunc(p->syms[1]->type));
+ p->syms[1] = intconst(freturn(p->syms[1]->type)->size);
+ break;
+ case CALL+F: setreg(p, opsize(p->op)==4?freg[0]:freg2[0]); break;
+ case CALL+I: case CALL+P: case CALL+U:
+ case CALL+V: setreg(p, oreg[0]); break;
+ case RET+F: rtarget(p, 0, opsize(p->op)==4?freg[0]:freg2[0]); break;
+ case RET+I: case RET+P: case RET+U:
+ rtarget(p, 0, ireg[0]);
+ p->kids[0]->x.registered = 1;
+ break;
+ case ARG+I: case ARG+P: case ARG+U:
+ if (p->syms[RX]->u.c.v.i < 6) {
+ rtarget(p, 0, oreg[p->syms[RX]->u.c.v.i]);
+ p->op = LOAD+opkind(p->op);
+ setreg(p, oreg[p->syms[RX]->u.c.v.i]);
+ }
+ break;
+ }
+}
+static void clobber(Node p) {
+ assert(p);
+ switch (specific(p->op)) {
+ case CALL+B: case CALL+F: case CALL+I:
+ spill(~(unsigned)3, FREG, p);
+ break;
+ case CALL+V:
+ spill(oreg[0]->x.regnode->mask, IREG, p);
+ spill(~(unsigned)3, FREG, p);
+ break;
+ case ARG+F:
+ if (opsize(p->op) == 4 && p->syms[2]->u.c.v.i <= 6)
+ spill((1<<(p->syms[2]->u.c.v.i + 8)), IREG, p);
+ else if (opsize(p->op) == 8 && p->syms[2]->u.c.v.i <= 5)
+ spill((3<<(p->syms[2]->u.c.v.i + 8))&0xff00, IREG, p);
+ break;
+ }
+}
+static int imm(Node p) {
+ return range(p, -4096, 4091);
+}
+static void doarg(Node p) {
+ assert(p && p->syms[0] && p->op != ARG+B);
+ p->syms[RX] = intconst(mkactual(4,
+ p->syms[0]->u.c.v.i)/4);
+}
+static void emit2(Node p) {
+ switch (p->op) {
+ case ARG+F+sizeop(4): {
+ int n = p->syms[RX]->u.c.v.i;
+ print("st %%f%d,[%%sp+4*%d+68]\n",
+ getregnum(p->x.kids[0]), n);
+ if (n <= 5)
+ print("ld [%%sp+4*%d+68],%%o%d\n", n, n);
+ break;
+ }
+ case ARG+F+sizeop(8): {
+ int n = p->syms[RX]->u.c.v.i;
+ int src = getregnum(p->x.kids[0]);
+ print("st %%f%d,[%%sp+4*%d+68]\n", src, n);
+ print("st %%f%d,[%%sp+4*%d+68]\n", src+1, n+1);
+ if (n <= 5)
+ print("ld [%%sp+4*%d+68],%%o%d\n", n, n);
+ if (n <= 4)
+ print("ld [%%sp+4*%d+68],%%o%d\n", n+1, n+1);
+ break;
+ }
+ case LOAD+F+sizeop(8): {
+ int dst = getregnum(p);
+ int src = getregnum(p->x.kids[0]);
+ print("fmovs %%f%d,%%f%d; ", src, dst);
+ print("fmovs %%f%d,%%f%d\n", src+1, dst+1);
+ break;
+ }
+ case NEG+F+sizeop(8): {
+ int dst = getregnum(p);
+ int src = getregnum(p->x.kids[0]);
+ print("fnegs %%f%d,%%f%d; ", src, dst);
+ print("fmovs %%f%d,%%f%d\n", src+1, dst+1);
+ break;
+ }
+ case ASGN+B: {
+ static int tmpregs[] = { 1, 2, 3 };
+ dalign = salign = p->syms[1]->u.c.v.i;
+ blkcopy(getregnum(p->x.kids[0]), 0,
+ getregnum(p->x.kids[1]), 0,
+ p->syms[0]->u.c.v.i, tmpregs);
+ break;
+ }
+ }
+}
+static void local(Symbol p) {
+ if (retstruct) {
+ assert(p == retv);
+ p->x.name = stringd(4*16);
+ p->x.offset = 4*16;
+ p->sclass = AUTO;
+ retstruct = 0;
+ return;
+ }
+ if (isscalar(p->type) && !p->addressed && !isfloat(p->type))
+ p->sclass = REGISTER;
+ if (askregvar(p, rmap(ttob(p->type))) == 0)
+ mkauto(p);
+ else if (p->scope > LOCAL)
+ regvars++;
+}
+static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
+ int autos = 0, i, leaf, reg, varargs;
+
+ if (IR == &solarisIR)
+ globalend();
+ regvars = 0;
+ for (i = 0; callee[i]; i++)
+ ;
+ varargs = variadic(f->type)
+ || i > 0 && strcmp(callee[i-1]->name,
+ "__builtin_va_alist") == 0;
+ usedmask[0] = usedmask[1] = 0;
+ freemask[0] = freemask[1] = ~(unsigned)0;
+ for (i = 0; i < 8; i++)
+ ireg[i]->x.regnode->vbl = NULL;
+ offset = 68;
+ maxargoffset = 24;
+ reg = 0;
+ for (i = 0; callee[i]; i++) {
+ Symbol p = callee[i], q = caller[i];
+ int size = roundup(q->type->size, 4);
+ assert(q);
+ if (isfloat(p->type) || reg >= 6) {
+ p->x.offset = q->x.offset = offset;
+ p->x.name = q->x.name = stringd(offset);
+ p->sclass = q->sclass = AUTO;
+ autos++;
+ }
+ else if (p->addressed || varargs) {
+ p->x.offset = offset;
+ p->x.name = stringd(p->x.offset);
+ p->sclass = AUTO;
+ q->sclass = REGISTER;
+ askregvar(q, ireg[reg]);
+ assert(q->x.regnode);
+ autos++;
+ }
+ else {
+ p->sclass = q->sclass = REGISTER;
+ askregvar(p, ireg[reg]);
+ assert(p->x.regnode);
+ q->x.name = p->x.name;
+ }
+ offset += size;
+ reg += isstruct(p->type) ? 1 : size/4;
+ }
+ assert(caller[i] == 0);
+ offset = maxoffset = 0;
+ retstruct = isstruct(freturn(f->type));
+ gencode(caller, callee);
+ maxargoffset = roundup(maxargoffset, 4);
+ framesize = roundup(maxoffset + maxargoffset + 4*(16+1), 8);
+ assert(!varargs || autos);
+ leaf = (!ncalls
+ && !maxoffset && !autos && !regvars
+ && !isstruct(freturn(f->type))
+ && !(usedmask[IREG]&0x00ffff01)
+ && !(usedmask[FREG]&~(unsigned)3)
+ && !pflag && !glevel);
+ print(".align 4\n%s:\n", f->x.name);
+ if (leaf) {
+ for (i = 0; caller[i] && callee[i]; i++) {
+ Symbol p = caller[i], q = callee[i];
+ if (p->sclass == REGISTER && q->sclass == REGISTER) {
+ assert(q->x.regnode);
+ assert(q->x.regnode->set == IREG);
+ assert(q->x.regnode->number >= 24);
+ assert(q->x.regnode->number <= 31);
+ p->x.name = greg[q->x.regnode->number - 16]->x.name;
+ }
+ }
+ renameregs();
+ } else if (framesize <= 4095)
+ print("save %%sp,%d,%%sp\n", -framesize);
+ else
+ print("set %d,%%g1; save %%sp,%%g1,%%sp\n", -framesize);
+ if (varargs)
+ for (; reg < 6; reg++)
+ print("st %%i%d,[%%fp+%d]\n", reg, 4*reg + 68);
+ else {
+ offset = 4*(16 + 1);
+ reg = 0;
+ for (i = 0; caller[i]; i++) {
+ Symbol p = caller[i];
+ if (isfloat(p->type) && p->type->size == 8 && reg <= 4) {
+ print("st %%r%d,[%%fp+%d]\n",
+ ireg[reg++]->x.regnode->number, offset);
+ print("st %%r%d,[%%fp+%d]\n",
+ ireg[reg++]->x.regnode->number, offset + 4);
+ } else if (isfloat(p->type) && p->type->size == 4 && reg <= 5)
+ print("st %%r%d,[%%fp+%d]\n",
+ ireg[reg++]->x.regnode->number, offset);
+ else
+ reg++;
+ offset += roundup(p->type->size, 4);
+ }
+ }
+ if (pflag) {
+ int lab = genlabel(1);
+ print("set L%d,%%o0; call mcount; nop\n", lab);
+ print(".seg \"data\"\n.align 4; L%d:.word 0\n.seg \"text\"\n", lab);
+ }
+ emitcode();
+ if (isstruct(freturn(f->type)))
+ print("jmp %%i7+12; restore\n");
+ else if (!leaf)
+ print("ret; restore\n");
+ else {
+ renameregs();
+ print("retl; nop\n");
+ }
+ if (IR == &solarisIR) {
+ print(".type %s,#function\n", f->x.name);
+ print(".size %s,.-%s\n", f->x.name, f->x.name);
+ }
+}
+#define exch(x, y, t) (((t) = x), ((x) = (y)), ((y) = (t)))
+
+static void renameregs(void) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ char *ptmp;
+ int itmp;
+ if (ireg[i]->x.regnode->vbl)
+ ireg[i]->x.regnode->vbl->x.name = oreg[i]->x.name;
+ exch(ireg[i]->x.name, oreg[i]->x.name, ptmp);
+ exch(ireg[i]->x.regnode->number,
+ oreg[i]->x.regnode->number, itmp);
+ }
+}
+static void defconst(int suffix, int size, Value v) {
+ if (suffix == F && size == 4) {
+ float f = v.d;
+ print(".word 0x%x\n", *(unsigned *)&f);
+ } else if (suffix == F && size == 8) {
+ double d = v.d;
+ unsigned *p = (unsigned *)&d;
+ print(".word 0x%x\n.word 0x%x\n", p[swap], p[!swap]);
+ } else if (suffix == P)
+ print(".word 0x%x\n", v.p);
+ else if (size == 1)
+ print(".byte 0x%x\n", suffix == I ? v.i : v.u);
+ else if (size == 2)
+ print(".half 0x%x\n", suffix == I ? v.i : v.u);
+ else if (size == 4)
+ print(".word 0x%x\n", suffix == I ? v.i : v.u);
+ else assert(0);
+}
+
+static void defaddress(Symbol p) {
+ print(".word %s\n", p->x.name);
+}
+
+static void defstring(int n, char *str) {
+ char *s;
+
+ for (s = str; s < str + n; s++)
+ print(".byte %d\n", (*s)&0377);
+}
+
+static void address(Symbol q, Symbol p, long n) {
+ if (p->scope == GLOBAL || p->sclass == STATIC || p->sclass == EXTERN)
+ q->x.name = stringf("%s%s%D", p->x.name, n >= 0 ? "+" : "", n);
+ else {
+ assert(n <= INT_MAX && n >= INT_MIN);
+ q->x.offset = p->x.offset + n;
+ q->x.name = stringd(q->x.offset);
+ }
+}
+static void export(Symbol p) {
+ print(".global %s\n", p->x.name);
+}
+static void import(Symbol p) {}
+static void defsymbol(Symbol p) {
+ if (p->scope >= LOCAL && p->sclass == STATIC)
+ p->x.name = stringf("%d", genlabel(1));
+ else
+ assert(p->scope != CONSTANTS || isint(p->type) || isptr(p->type)),
+ p->x.name = p->name;
+ if (p->scope >= LABELS)
+ p->x.name = stringf(p->generated ? "L%s" : "_%s",
+ p->x.name);
+}
+static void segment(int n) {
+ cseg = n;
+ switch (n) {
+ case CODE: print(".seg \"text\"\n"); break;
+ case BSS: print(".seg \"bss\"\n"); break;
+ case DATA: print(".seg \"data\"\n"); break;
+ case LIT: print(".seg \"text\"\n"); break;
+ }
+}
+static void space(int n) {
+ if (cseg != BSS)
+ print(".skip %d\n", n);
+}
+static void global(Symbol p) {
+ print(".align %d\n", p->type->align);
+ assert(p->u.seg);
+ if (p->u.seg == BSS
+ && (p->sclass == STATIC || Aflag >= 2))
+ print(".reserve %s,%d\n", p->x.name, p->type->size);
+ else if (p->u.seg == BSS)
+ print(".common %s,%d\n", p->x.name, p->type->size);
+ else
+ print("%s:\n", p->x.name);
+}
+static void blkfetch(int k, int off, int reg, int tmp) {
+ assert(k == 1 || k == 2 || k == 4);
+ assert(salign >= k);
+ if (k == 1)
+ print("ldub [%%r%d+%d],%%r%d\n", reg, off, tmp);
+ else if (k == 2)
+ print("lduh [%%r%d+%d],%%r%d\n", reg, off, tmp);
+ else
+ print("ld [%%r%d+%d],%%r%d\n", reg, off, tmp);
+}
+static void blkstore(int k, int off, int reg, int tmp) {
+ assert(k == 1 || k == 2 || k == 4);
+ assert(dalign >= k);
+ if (k == 1)
+ print("stb %%r%d,[%%r%d+%d]\n", tmp, reg, off);
+ else if (k == 2)
+ print("sth %%r%d,[%%r%d+%d]\n", tmp, reg, off);
+ else
+ print("st %%r%d,[%%r%d+%d]\n", tmp, reg, off);
+}
+static void blkloop(int dreg, int doff, int sreg, int soff, int size, int tmps[]) {
+ if ((size&~7) < 4096) {
+ print("add %%r%d,%d,%%r%d\n", sreg, size&~7, sreg);
+ print("add %%r%d,%d,%%r%d\n", dreg, size&~7, tmps[2]);
+ } else {
+ print("set %d,%%r%d\n", size&~7, tmps[2]);
+ print("add %%r%d,%%r%d,%%r%d\n", sreg, tmps[2], sreg);
+ print("add %%r%d,%%r%d,%%r%d\n", dreg, tmps[2], tmps[2]);
+ }
+ blkcopy(tmps[2], doff, sreg, soff, size&7, tmps);
+ print("1: dec 8,%%r%d\n", tmps[2]);
+ blkcopy(tmps[2], doff, sreg, soff - 8, 8, tmps);
+ print("cmp %%r%d,%%r%d; ", tmps[2], dreg);
+ print("bgt 1b; ");
+ print("dec 8,%%r%d\n", sreg);
+}
+static void defsymbol2(Symbol p) {
+ if (p->scope >= LOCAL && p->sclass == STATIC)
+ p->x.name = stringf(".%d", genlabel(1));
+ else
+ assert(p->scope != CONSTANTS || isint(p->type) || isptr(p->type)),
+ p->x.name = p->name;
+ if (p->scope >= LABELS)
+ p->x.name = stringf(p->generated ? ".L%s" : "%s",
+ p->x.name);
+}
+
+static Symbol prevg;
+
+static void globalend(void) {
+ if (prevg && prevg->type->size > 0)
+ print(".size %s,%d\n", prevg->x.name, prevg->type->size);
+ prevg = NULL;
+}
+
+static void export2(Symbol p) {
+ globalend();
+ print(".global %s\n", p->x.name);
+}
+
+static void progend2(void) {
+ globalend();
+}
+
+static void global2(Symbol p) {
+ globalend();
+ assert(p->u.seg);
+ if (!p->generated) {
+ print(".type %s,#%s\n", p->x.name,
+ isfunc(p->type) ? "function" : "object");
+ if (p->type->size > 0)
+ print(".size %s,%d\n", p->x.name, p->type->size);
+ else
+ prevg = p;
+ }
+ if (p->u.seg == BSS && p->sclass == STATIC)
+ print(".local %s\n.common %s,%d,%d\n", p->x.name, p->x.name,
+ p->type->size, p->type->align);
+ else if (p->u.seg == BSS && Aflag >= 2)
+ print(".align %d\n%s:.skip %d\n", p->type->align, p->x.name,
+ p->type->size);
+ else if (p->u.seg == BSS)
+ print(".common %s,%d,%d\n", p->x.name, p->type->size, p->type->align);
+ else
+ print(".align %d\n%s:\n", p->type->align, p->x.name);
+}
+
+static void segment2(int n) {
+ cseg = n;
+ switch (n) {
+ case CODE: print(".section \".text\"\n"); break;
+ case BSS: print(".section \".bss\"\n"); break;
+ case DATA: print(".section \".data\"\n"); break;
+ case LIT: print(".section \".rodata\"\n"); break;
+ }
+}
+Interface sparcIR = {
+ 1, 1, 0, /* char */
+ 2, 2, 0, /* short */
+ 4, 4, 0, /* int */
+ 4, 4, 0, /* long */
+ 4, 4, 0, /* long long */
+ 4, 4, 1, /* float */
+ 8, 8, 1, /* double */
+ 8, 8, 1, /* long double */
+ 4, 4, 0, /* T * */
+ 0, 1, 0, /* struct */
+ 0, /* little_endian */
+ 0, /* mulops_calls */
+ 1, /* wants_callb */
+ 0, /* wants_argb */
+ 1, /* left_to_right */
+ 0, /* wants_dag */
+ 0, /* unsigned_char */
+ address,
+ blockbeg,
+ blockend,
+ defaddress,
+ defconst,
+ defstring,
+ defsymbol,
+ emit,
+ export,
+ function,
+ gen,
+ global,
+ import,
+ local,
+ progbeg,
+ progend,
+ segment,
+ space,
+ stabblock, 0, 0, stabinit, stabline, stabsym, stabtype,
+ {
+ 1, /* max_unaligned_load */
+ rmap,
+ blkfetch, blkstore, blkloop,
+ _label,
+ _rule,
+ _nts,
+ _kids,
+ _string,
+ _templates,
+ _isinstruction,
+ _ntname,
+ emit2,
+ doarg,
+ target,
+ clobber,
+
+ }
+};
+
+Interface solarisIR = {
+ 1, 1, 0, /* char */
+ 2, 2, 0, /* short */
+ 4, 4, 0, /* int */
+ 4, 4, 0, /* long */
+ 4, 4, 0, /* long long */
+ 4, 4, 1, /* float */
+ 8, 8, 1, /* double */
+ 8, 8, 1, /* long double */
+ 4, 4, 0, /* T * */
+ 0, 1, 0, /* struct */
+ 0, /* little_endian */
+ 0, /* mulops_calls */
+ 1, /* wants_callb */
+ 0, /* wants_argb */
+ 1, /* left_to_right */
+ 0, /* wants_dag */
+ 0, /* unsigned_char */
+ address,
+ blockbeg,
+ blockend,
+ defaddress,
+ defconst,
+ defstring,
+ defsymbol2,
+ emit,
+ export2,
+ function,
+ gen,
+ global2,
+ import,
+ local,
+ progbeg,
+ progend2,
+ segment2,
+ space,
+ stabblock, 0, 0, stabinit, stabline, stabsym, stabtype,
+ {
+ 1, /* max_unaligned_load */
+ rmap,
+ blkfetch, blkstore, blkloop,
+ _label,
+ _rule,
+ _nts,
+ _kids,
+ _string,
+ _templates,
+ _isinstruction,
+ _ntname,
+ emit2,
+ doarg,
+ target,
+ clobber,
+
+ }
+};
+static char rcsid[] = "$Id: sparc.md 145 2001-10-17 21:53:10Z timo $";
diff --git a/lcc/src/stab.c b/lcc/src/stab.c
new file mode 100755
index 0000000..152b778
--- /dev/null
+++ b/lcc/src/stab.c
@@ -0,0 +1,330 @@
+#include <string.h>
+#include <stdlib.h>
+#include "c.h"
+#include "stab.h"
+
+
+static char *currentfile; /* current file name */
+static int ntypes;
+
+extern Interface sparcIR;
+
+char *stabprefix = "L";
+
+extern char *stabprefix;
+extern void stabblock(int, int, Symbol*);
+extern void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *);
+extern void stabfend(Symbol, int);
+extern void stabinit(char *, int, char *[]);
+extern void stabline(Coordinate *);
+extern void stabsym(Symbol);
+extern void stabtype(Symbol);
+
+static void asgncode(Type, int);
+static void dbxout(Type);
+static int dbxtype(Type);
+static int emittype(Type, int, int);
+
+/* asgncode - assign type code to ty */
+static void asgncode(Type ty, int lev) {
+ if (ty->x.marked || ty->x.typeno)
+ return;
+ ty->x.marked = 1;
+ switch (ty->op) {
+ case VOLATILE: case CONST: case VOLATILE+CONST:
+ asgncode(ty->type, lev);
+ ty->x.typeno = ty->type->x.typeno;
+ break;
+ case POINTER: case FUNCTION: case ARRAY:
+ asgncode(ty->type, lev + 1);
+ /* fall thru */
+ case VOID: case INT: case UNSIGNED: case FLOAT:
+ break;
+ case STRUCT: case UNION: {
+ Field p;
+ for (p = fieldlist(ty); p; p = p->link)
+ asgncode(p->type, lev + 1);
+ /* fall thru */
+ case ENUM:
+ if (ty->x.typeno == 0)
+ ty->x.typeno = ++ntypes;
+ if (lev > 0 && (*ty->u.sym->name < '0' || *ty->u.sym->name > '9'))
+ dbxout(ty);
+ break;
+ }
+ default:
+ assert(0);
+ }
+}
+
+/* dbxout - output .stabs entry for type ty */
+static void dbxout(Type ty) {
+ ty = unqual(ty);
+ if (!ty->x.printed) {
+ int col = 0;
+ print(".stabs \""), col += 8;
+ if (ty->u.sym && !(isfunc(ty) || isarray(ty) || isptr(ty)))
+ print("%s", ty->u.sym->name), col += strlen(ty->u.sym->name);
+ print(":%c", isstruct(ty) || isenum(ty) ? 'T' : 't'), col += 2;
+ emittype(ty, 0, col);
+ print("\",%d,0,0,0\n", N_LSYM);
+ }
+}
+
+/* dbxtype - emit a stabs entry for type ty, return type code */
+static int dbxtype(Type ty) {
+ asgncode(ty, 0);
+ dbxout(ty);
+ return ty->x.typeno;
+}
+
+/*
+ * emittype - emit ty's type number, emitting its definition if necessary.
+ * Returns the output column number after emission; col is the approximate
+ * output column before emission and is used to emit continuation lines for long
+ * struct, union, and enum types. Continuations are not emitted for other types,
+ * even if the definition is long. lev is the depth of calls to emittype.
+ */
+static int emittype(Type ty, int lev, int col) {
+ int tc = ty->x.typeno;
+
+ if (isconst(ty) || isvolatile(ty)) {
+ col = emittype(ty->type, lev, col);
+ ty->x.typeno = ty->type->x.typeno;
+ ty->x.printed = 1;
+ return col;
+ }
+ if (tc == 0) {
+ ty->x.typeno = tc = ++ntypes;
+/* fprint(2,"`%t'=%d\n", ty, tc); */
+ }
+ print("%d", tc), col += 3;
+ if (ty->x.printed)
+ return col;
+ ty->x.printed = 1;
+ switch (ty->op) {
+ case VOID: /* void is defined as itself */
+ print("=%d", tc), col += 1+3;
+ break;
+ case INT:
+ if (ty == chartype) /* plain char is a subrange of itself */
+ print("=r%d;%d;%d;", tc, ty->u.sym->u.limits.min.i, ty->u.sym->u.limits.max.i),
+ col += 2+3+2*2.408*ty->size+2;
+ else /* other signed ints are subranges of int */
+ print("=r1;%D;%D;", ty->u.sym->u.limits.min.i, ty->u.sym->u.limits.max.i),
+ col += 4+2*2.408*ty->size+2;
+ break;
+ case UNSIGNED:
+ if (ty == chartype) /* plain char is a subrange of itself */
+ print("=r%d;0;%u;", tc, ty->u.sym->u.limits.max.i),
+ col += 2+3+2+2.408*ty->size+1;
+ else /* other signed ints are subranges of int */
+ print("=r1;0;%U;", ty->u.sym->u.limits.max.i),
+ col += 4+2.408*ty->size+1;
+ break;
+ case FLOAT: /* float, double, long double get sizes, not ranges */
+ print("=r1;%d;0;", ty->size), col += 4+1+3;
+ break;
+ case POINTER:
+ print("=*"), col += 2;
+ col = emittype(ty->type, lev + 1, col);
+ break;
+ case FUNCTION:
+ print("=f"), col += 2;
+ col = emittype(ty->type, lev + 1, col);
+ break;
+ case ARRAY: /* array includes subscript as an int range */
+ if (ty->size && ty->type->size)
+ print("=ar1;0;%d;", ty->size/ty->type->size - 1), col += 7+3+1;
+ else
+ print("=ar1;0;-1;"), col += 10;
+ col = emittype(ty->type, lev + 1, col);
+ break;
+ case STRUCT: case UNION: {
+ Field p;
+ if (!ty->u.sym->defined) {
+ print("=x%c%s:", ty->op == STRUCT ? 's' : 'u', ty->u.sym->name);
+ col += 2+1+strlen(ty->u.sym->name)+1;
+ break;
+ }
+ if (lev > 0 && (*ty->u.sym->name < '0' || *ty->u.sym->name > '9')) {
+ ty->x.printed = 0;
+ break;
+ }
+ print("=%c%d", ty->op == STRUCT ? 's' : 'u', ty->size), col += 1+1+3;
+ for (p = fieldlist(ty); p; p = p->link) {
+ if (p->name)
+ print("%s:", p->name), col += strlen(p->name)+1;
+ else
+ print(":"), col += 1;
+ col = emittype(p->type, lev + 1, col);
+ if (p->lsb)
+ print(",%d,%d;", 8*p->offset +
+ (IR->little_endian ? fieldright(p) : fieldleft(p)),
+ fieldsize(p));
+ else
+ print(",%d,%d;", 8*p->offset, 8*p->type->size);
+ col += 1+3+1+3+1; /* accounts for ,%d,%d; */
+ if (col >= 80 && p->link) {
+ print("\\\\\",%d,0,0,0\n.stabs \"", N_LSYM);
+ col = 8;
+ }
+ }
+ print(";"), col += 1;
+ break;
+ }
+ case ENUM: {
+ Symbol *p;
+ if (lev > 0 && (*ty->u.sym->name < '0' || *ty->u.sym->name > '9')) {
+ ty->x.printed = 0;
+ break;
+ }
+ print("=e"), col += 2;
+ for (p = ty->u.sym->u.idlist; *p; p++) {
+ print("%s:%d,", (*p)->name, (*p)->u.value), col += strlen((*p)->name)+3;
+ if (col >= 80 && p[1]) {
+ print("\\\\\",%d,0,0,0\n.stabs \"", N_LSYM);
+ col = 8;
+ }
+ }
+ print(";"), col += 1;
+ break;
+ }
+ default:
+ assert(0);
+ }
+ return col;
+}
+
+/* stabblock - output a stab entry for '{' or '}' at level lev */
+void stabblock(int brace, int lev, Symbol *p) {
+ if (brace == '{')
+ while (*p)
+ stabsym(*p++);
+ if (IR == &sparcIR)
+ print(".stabd 0x%x,0,%d\n", brace == '{' ? N_LBRAC : N_RBRAC, lev);
+ else {
+ int lab = genlabel(1);
+ print(".stabn 0x%x,0,%d,%s%d-%s\n", brace == '{' ? N_LBRAC : N_RBRAC, lev,
+ stabprefix, lab, cfunc->x.name);
+ print("%s%d:\n", stabprefix, lab);
+ }
+}
+
+/* stabinit - initialize stab output */
+void stabinit(char *file, int argc, char *argv[]) {
+ typedef void (*Closure)(Symbol, void *);
+ extern char *getcwd(char *, size_t);
+
+ print(".stabs \"lcc4_compiled.\",0x%x,0,0,0\n", N_OPT);
+ if (file && *file) {
+ char buf[1024], *cwd = getcwd(buf, sizeof buf);
+ if (cwd)
+ print(".stabs \"%s/\",0x%x,0,3,%stext0\n", cwd, N_SO, stabprefix);
+ print(".stabs \"%s\",0x%x,0,3,%stext0\n", file, N_SO, stabprefix);
+ (*IR->segment)(CODE);
+ print("%stext0:\n", stabprefix, N_SO);
+ currentfile = file;
+ }
+ dbxtype(inttype);
+ dbxtype(chartype);
+ dbxtype(doubletype);
+ dbxtype(floattype);
+ dbxtype(longdouble);
+ dbxtype(longtype);
+ dbxtype(longlong);
+ dbxtype(shorttype);
+ dbxtype(signedchar);
+ dbxtype(unsignedchar);
+ dbxtype(unsignedlong);
+ dbxtype(unsignedlonglong);
+ dbxtype(unsignedshort);
+ dbxtype(unsignedtype);
+ dbxtype(voidtype);
+ foreach(types, GLOBAL, (Closure)stabtype, NULL);
+}
+
+/* stabline - emit stab entry for source coordinate *cp */
+void stabline(Coordinate *cp) {
+ if (cp->file && cp->file != currentfile) {
+ int lab = genlabel(1);
+ print(".stabs \"%s\",0x%x,0,0,%s%d\n", cp->file, N_SOL, stabprefix, lab);
+ print("%s%d:\n", stabprefix, lab);
+ currentfile = cp->file;
+ }
+ if (IR == &sparcIR)
+ print(".stabd 0x%x,0,%d\n", N_SLINE, cp->y);
+ else {
+ int lab = genlabel(1);
+ print(".stabn 0x%x,0,%d,%s%d-%s\n", N_SLINE, cp->y,
+ stabprefix, lab, cfunc->x.name);
+ print("%s%d:\n", stabprefix, lab);
+ }
+}
+
+/* stabsym - output a stab entry for symbol p */
+void stabsym(Symbol p) {
+ int code, tc, sz = p->type->size;
+
+ if (p->generated || p->computed)
+ return;
+ if (isfunc(p->type)) {
+ print(".stabs \"%s:%c%d\",%d,0,0,%s\n", p->name,
+ p->sclass == STATIC ? 'f' : 'F', dbxtype(freturn(p->type)),
+ N_FUN, p->x.name);
+ return;
+ }
+ if (!IR->wants_argb && p->scope == PARAM && p->structarg) {
+ assert(isptr(p->type) && isstruct(p->type->type));
+ tc = dbxtype(p->type->type);
+ sz = p->type->type->size;
+ } else
+ tc = dbxtype(p->type);
+ if (p->sclass == AUTO && p->scope == GLOBAL || p->sclass == EXTERN) {
+ print(".stabs \"%s:G", p->name);
+ code = N_GSYM;
+ } else if (p->sclass == STATIC) {
+ print(".stabs \"%s:%c%d\",%d,0,0,%s\n", p->name, p->scope == GLOBAL ? 'S' : 'V',
+ tc, p->u.seg == BSS ? N_LCSYM : N_STSYM, p->x.name);
+ return;
+ } else if (p->sclass == REGISTER) {
+ if (p->x.regnode) {
+ int r = p->x.regnode->number;
+ if (p->x.regnode->set == FREG)
+ r += 32; /* floating point */
+ print(".stabs \"%s:%c%d\",%d,0,", p->name,
+ p->scope == PARAM ? 'P' : 'r', tc, N_RSYM);
+ print("%d,%d\n", sz, r);
+ }
+ return;
+ } else if (p->scope == PARAM) {
+ print(".stabs \"%s:p", p->name);
+ code = N_PSYM;
+ } else if (p->scope >= LOCAL) {
+ print(".stabs \"%s:", p->name);
+ code = N_LSYM;
+ } else
+ assert(0);
+ print("%d\",%d,0,0,%s\n", tc, code,
+ p->scope >= PARAM && p->sclass != EXTERN ? p->x.name : "0");
+}
+
+/* stabtype - output a stab entry for type *p */
+void stabtype(Symbol p) {
+ if (p->type) {
+ if (p->sclass == 0)
+ dbxtype(p->type);
+ else if (p->sclass == TYPEDEF)
+ print(".stabs \"%s:t%d\",%d,0,0,0\n", p->name, dbxtype(p->type), N_LSYM);
+ }
+}
+
+/* stabend - finalize a function */
+void stabfend(Symbol p, int lineno) {}
+
+/* stabend - finalize stab output */
+void stabend(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {
+ (*IR->segment)(CODE);
+ print(".stabs \"\", %d, 0, 0,%setext\n", N_SO, stabprefix);
+ print("%setext:\n", stabprefix);
+}
diff --git a/lcc/src/stab.h b/lcc/src/stab.h
new file mode 100755
index 0000000..bfb7ebf
--- /dev/null
+++ b/lcc/src/stab.h
@@ -0,0 +1,113 @@
+/* @(#)stab.h 1.11 92/05/11 SMI */
+/*
+ * Copyright (c) 1990 by Sun Microsystems, Inc.
+ */
+
+/*
+ * This file gives definitions supplementing <a.out.h>
+ * for permanent symbol table entries.
+ * These must have one of the N_STAB bits on,
+ * and are subject to relocation according to the masks in <a.out.h>.
+ */
+
+#ifndef _STAB_H
+#define _STAB_H
+
+
+#if !defined(_a_out_h) && !defined(_A_OUT_H)
+/* this file contains fragments of a.out.h and stab.h relevant to
+ * support of stabX processing within ELF files - see the
+ * Format of a symbol table entry
+ */
+struct nlist {
+ union {
+ char *n_name; /* for use when in-core */
+ long n_strx; /* index into file string table */
+ } n_un;
+ unsigned char n_type; /* type flag (N_TEXT,..) */
+ char n_other; /* unused */
+ short n_desc; /* see <stab.h> */
+ unsigned long n_value; /* value of symbol (or sdb offset) */
+};
+
+/*
+ * Simple values for n_type.
+ */
+#define N_UNDF 0x0 /* undefined */
+#define N_ABS 0x2 /* absolute */
+#define N_TEXT 0x4 /* text */
+#define N_DATA 0x6 /* data */
+#define N_BSS 0x8 /* bss */
+#define N_COMM 0x12 /* common (internal to ld) */
+#define N_FN 0x1f /* file name symbol */
+
+#define N_EXT 01 /* external bit, or'ed in */
+#define N_TYPE 0x1e /* mask for all the type bits */
+
+#endif
+
+/*
+ * for symbolic debugger, sdb(1):
+ */
+#define N_GSYM 0x20 /* global symbol: name,,0,type,0 */
+#define N_FNAME 0x22 /* procedure name (f77 kludge): name,,0 */
+#define N_FUN 0x24 /* procedure: name,,0,linenumber,address */
+#define N_STSYM 0x26 /* static symbol: name,,0,type,address */
+#define N_LCSYM 0x28 /* .lcomm symbol: name,,0,type,address */
+#define N_MAIN 0x2a /* name of main routine : name,,0,0,0 */
+#define N_ROSYM 0x2c /* ro_data objects */
+#define N_OBJ 0x38 /* object file path or name */
+#define N_OPT 0x3c /* compiler options */
+#define N_RSYM 0x40 /* register sym: name,,0,type,register */
+#define N_SLINE 0x44 /* src line: 0,,0,linenumber,address */
+#define N_FLINE 0x4c /* function start.end */
+#define N_SSYM 0x60 /* structure elt: name,,0,type,struct_offset */
+#define N_ENDM 0x62 /* last stab emitted for module */
+#define N_SO 0x64 /* source file name: name,,0,0,address */
+#define N_LSYM 0x80 /* local sym: name,,0,type,offset */
+#define N_BINCL 0x82 /* header file: name,,0,0,0 */
+#define N_SOL 0x84 /* #included file name: name,,0,0,address */
+#define N_PSYM 0xa0 /* parameter: name,,0,type,offset */
+#define N_EINCL 0xa2 /* end of include file */
+#define N_ENTRY 0xa4 /* alternate entry: name,linenumber,address */
+#define N_LBRAC 0xc0 /* left bracket: 0,,0,nesting level,address */
+#define N_EXCL 0xc2 /* excluded include file */
+#define N_RBRAC 0xe0 /* right bracket: 0,,0,nesting level,address */
+#define N_BCOMM 0xe2 /* begin common: name,, */
+#define N_ECOMM 0xe4 /* end common: name,, */
+#define N_ECOML 0xe8 /* end common (local name): ,,address */
+#define N_LENG 0xfe /* second stab entry with length information */
+
+/*
+ * for the berkeley pascal compiler, pc(1):
+ */
+#define N_PC 0x30 /* global pascal symbol: name,,0,subtype,line */
+#define N_WITH 0xea /* pascal with statement: type,,0,0,offset */
+
+/*
+ * for code browser only
+ */
+#define N_BROWS 0x48 /* path to associated .cb file */
+
+/*
+ * Optional langauge designations for N_SO
+ */
+#define N_SO_AS 1 /* Assembler */
+#define N_SO_C 2 /* C */
+#define N_SO_ANSI_C 3 /* ANSI C */
+#define N_SO_CC 4 /* C++ */
+#define N_SO_FORTRAN 5 /* Fortran 77 */
+#define N_SO_PASCAL 6 /* Pascal */
+
+/*
+ * Floating point type values
+ */
+#define NF_NONE 0 /* Undefined type */
+#define NF_SINGLE 1 /* IEEE 32 bit float */
+#define NF_DOUBLE 2 /* IEEE 64 bit float */
+#define NF_COMPLEX 3 /* Fortran complex */
+#define NF_COMPLEX16 4 /* Fortran double complex */
+#define NF_COMPLEX32 5 /* Fortran complex*16 */
+#define NF_LDOUBLE 6 /* Long double */
+
+#endif
diff --git a/lcc/src/stmt.c b/lcc/src/stmt.c
new file mode 100755
index 0000000..b742a32
--- /dev/null
+++ b/lcc/src/stmt.c
@@ -0,0 +1,697 @@
+#include "c.h"
+
+
+#define SWSIZE 512
+
+#define den(i,j) ((j-buckets[i]+1.0)/(v[j]-v[buckets[i]]+1))
+
+struct code codehead = { Start };
+Code codelist = &codehead;
+float density = 0.5;
+Table stmtlabs;
+
+static int foldcond(Tree e1, Tree e2);
+static void caselabel(Swtch, long, int);
+static void cmp(int, Symbol, long, int);
+static Tree conditional(int);
+static void dostmt(int, Swtch, int);
+static int equal(Symbol, Symbol);
+static void forstmt(int, Swtch, int);
+static void ifstmt(int, int, Swtch, int);
+static Symbol localaddr(Tree);
+static void stmtlabel(void);
+static void swstmt(int, int, int);
+static void whilestmt(int, Swtch, int);
+Code code(int kind) {
+ Code cp;
+
+ if (!reachable(kind))
+ warning("unreachable code\n");
+
+ NEW(cp, FUNC);
+ cp->kind = kind;
+ cp->prev = codelist;
+ cp->next = NULL;
+ codelist->next = cp;
+ codelist = cp;
+ return cp;
+}
+int reachable(int kind) {
+ Code cp;
+
+ if (kind > Start) {
+ Code cp;
+ for (cp = codelist; cp->kind < Label; )
+ cp = cp->prev;
+ if (cp->kind == Jump || cp->kind == Switch)
+ return 0;
+ }
+ return 1;
+}
+void addlocal(Symbol p) {
+ if (!p->defined) {
+ code(Local)->u.var = p;
+ p->defined = 1;
+ p->scope = level;
+ }
+}
+void definept(Coordinate *p) {
+ Code cp = code(Defpoint);
+
+ cp->u.point.src = p ? *p : src;
+ cp->u.point.point = npoints;
+ if (ncalled > 0) {
+ int n = findcount(cp->u.point.src.file,
+ cp->u.point.src.x, cp->u.point.src.y);
+ if (n > 0)
+ refinc = (float)n/ncalled;
+ }
+ if (glevel > 2) locus(identifiers, &cp->u.point.src);
+ if (events.points && reachable(Gen))
+ {
+ Tree e = NULL;
+ apply(events.points, &cp->u.point.src, &e);
+ if (e)
+ listnodes(e, 0, 0);
+ }
+}
+void statement(int loop, Swtch swp, int lev) {
+ float ref = refinc;
+
+ if (Aflag >= 2 && lev == 15)
+ warning("more than 15 levels of nested statements\n");
+ switch (t) {
+ case IF: ifstmt(genlabel(2), loop, swp, lev + 1);
+ break;
+ case WHILE: whilestmt(genlabel(3), swp, lev + 1); break;
+ case DO: dostmt(genlabel(3), swp, lev + 1); expect(';');
+ break;
+
+ case FOR: forstmt(genlabel(4), swp, lev + 1);
+ break;
+ case BREAK: walk(NULL, 0, 0);
+ definept(NULL);
+ if (swp && swp->lab > loop)
+ branch(swp->lab + 1);
+ else if (loop)
+ branch(loop + 2);
+ else
+ error("illegal break statement\n");
+ t = gettok(); expect(';');
+ break;
+
+ case CONTINUE: walk(NULL, 0, 0);
+ definept(NULL);
+ if (loop)
+ branch(loop + 1);
+ else
+ error("illegal continue statement\n");
+ t = gettok(); expect(';');
+ break;
+
+ case SWITCH: swstmt(loop, genlabel(2), lev + 1);
+ break;
+ case CASE: {
+ int lab = genlabel(1);
+ if (swp == NULL)
+ error("illegal case label\n");
+ definelab(lab);
+ while (t == CASE) {
+ static char stop[] = { IF, ID, 0 };
+ Tree p;
+ t = gettok();
+ p = constexpr(0);
+ if (generic(p->op) == CNST && isint(p->type)) {
+ if (swp) {
+ needconst++;
+ p = cast(p, swp->sym->type);
+ if (p->type->op == UNSIGNED)
+ p->u.v.i = extend(p->u.v.u, p->type);
+ needconst--;
+ caselabel(swp, p->u.v.i, lab);
+ }
+ } else
+ error("case label must be a constant integer expression\n");
+
+ test(':', stop);
+ }
+ statement(loop, swp, lev);
+ } break;
+ case DEFAULT: if (swp == NULL)
+ error("illegal default label\n");
+ else if (swp->deflab)
+ error("extra default label\n");
+ else {
+ swp->deflab = findlabel(swp->lab);
+ definelab(swp->deflab->u.l.label);
+ }
+ t = gettok();
+ expect(':');
+ statement(loop, swp, lev); break;
+ case RETURN: {
+ Type rty = freturn(cfunc->type);
+ t = gettok();
+ definept(NULL);
+ if (t != ';')
+ if (rty == voidtype) {
+ error("extraneous return value\n");
+ expr(0);
+ retcode(NULL);
+ } else
+ retcode(expr(0));
+ else {
+ if (rty != voidtype)
+ warning("missing return value\n");
+ retcode(NULL);
+ }
+ branch(cfunc->u.f.label);
+ } expect(';');
+ break;
+
+ case '{': compound(loop, swp, lev + 1); break;
+ case ';': definept(NULL); t = gettok(); break;
+ case GOTO: walk(NULL, 0, 0);
+ definept(NULL);
+ t = gettok();
+ if (t == ID) {
+ Symbol p = lookup(token, stmtlabs);
+ if (p == NULL) {
+ p = install(token, &stmtlabs, 0, FUNC);
+ p->scope = LABELS;
+ p->u.l.label = genlabel(1);
+ p->src = src;
+ }
+ use(p, src);
+ branch(p->u.l.label);
+ t = gettok();
+ } else
+ error("missing label in goto\n"); expect(';');
+ break;
+
+ case ID: if (getchr() == ':') {
+ stmtlabel();
+ statement(loop, swp, lev);
+ break;
+ }
+ default: definept(NULL);
+ if (kind[t] != ID) {
+ error("unrecognized statement\n");
+ t = gettok();
+ } else {
+ Tree e = expr0(0);
+ listnodes(e, 0, 0);
+ if (nodecount == 0 || nodecount > 200)
+ walk(NULL, 0, 0);
+ else if (glevel) walk(NULL, 0, 0);
+ deallocate(STMT);
+ } expect(';');
+ break;
+
+ }
+ if (kind[t] != IF && kind[t] != ID
+ && t != '}' && t != EOI) {
+ static char stop[] = { IF, ID, '}', 0 };
+ error("illegal statement termination\n");
+ skipto(0, stop);
+ }
+ refinc = ref;
+}
+
+static void ifstmt(int lab, int loop, Swtch swp, int lev) {
+ t = gettok();
+ expect('(');
+ definept(NULL);
+ walk(conditional(')'), 0, lab);
+ refinc /= 2.0;
+ statement(loop, swp, lev);
+ if (t == ELSE) {
+ branch(lab + 1);
+ t = gettok();
+ definelab(lab);
+ statement(loop, swp, lev);
+ if (findlabel(lab + 1)->ref)
+ definelab(lab + 1);
+ } else
+ definelab(lab);
+}
+static Tree conditional(int tok) {
+ Tree p = expr(tok);
+
+ if (Aflag > 1 && isfunc(p->type))
+ warning("%s used in a conditional expression\n",
+ funcname(p));
+ return cond(p);
+}
+static void stmtlabel(void) {
+ Symbol p = lookup(token, stmtlabs);
+
+ if (p == NULL) {
+ p = install(token, &stmtlabs, 0, FUNC);
+ p->scope = LABELS;
+ p->u.l.label = genlabel(1);
+ p->src = src;
+ }
+ if (p->defined)
+ error("redefinition of label `%s' previously defined at %w\n", p->name, &p->src);
+
+ p->defined = 1;
+ definelab(p->u.l.label);
+ t = gettok();
+ expect(':');
+}
+static void forstmt(int lab, Swtch swp, int lev) {
+ int once = 0;
+ Tree e1 = NULL, e2 = NULL, e3 = NULL;
+ Coordinate pt2, pt3;
+
+ t = gettok();
+ expect('(');
+ definept(NULL);
+ if (kind[t] == ID)
+ e1 = texpr(expr0, ';', FUNC);
+ else
+ expect(';');
+ walk(e1, 0, 0);
+ pt2 = src;
+ refinc *= 10.0;
+ if (kind[t] == ID)
+ e2 = texpr(conditional, ';', FUNC);
+ else
+ expect(';');
+ pt3 = src;
+ if (kind[t] == ID)
+ e3 = texpr(expr0, ')', FUNC);
+ else {
+ static char stop[] = { IF, ID, '}', 0 };
+ test(')', stop);
+ }
+ if (e2) {
+ once = foldcond(e1, e2);
+ if (!once)
+ branch(lab + 3);
+ }
+ definelab(lab);
+ statement(lab, swp, lev);
+ definelab(lab + 1);
+ definept(&pt3);
+ if (e3)
+ walk(e3, 0, 0);
+ if (e2) {
+ if (!once)
+ definelab(lab + 3);
+ definept(&pt2);
+ walk(e2, lab, 0);
+ } else {
+ definept(&pt2);
+ branch(lab);
+ }
+ if (findlabel(lab + 2)->ref)
+ definelab(lab + 2);
+}
+static void swstmt(int loop, int lab, int lev) {
+ Tree e;
+ struct swtch sw;
+ Code head, tail;
+
+ t = gettok();
+ expect('(');
+ definept(NULL);
+ e = expr(')');
+ if (!isint(e->type)) {
+ error("illegal type `%t' in switch expression\n",
+ e->type);
+ e = retype(e, inttype);
+ }
+ e = cast(e, promote(e->type));
+ if (generic(e->op) == INDIR && isaddrop(e->kids[0]->op)
+ && e->kids[0]->u.sym->type == e->type
+ && !isvolatile(e->kids[0]->u.sym->type)) {
+ sw.sym = e->kids[0]->u.sym;
+ walk(NULL, 0, 0);
+ } else {
+ sw.sym = genident(REGISTER, e->type, level);
+ addlocal(sw.sym);
+ walk(asgn(sw.sym, e), 0, 0);
+ }
+ head = code(Switch);
+ sw.lab = lab;
+ sw.deflab = NULL;
+ sw.ncases = 0;
+ sw.size = SWSIZE;
+ sw.values = newarray(SWSIZE, sizeof *sw.values, FUNC);
+ sw.labels = newarray(SWSIZE, sizeof *sw.labels, FUNC);
+ refinc /= 10.0;
+ statement(loop, &sw, lev);
+ if (sw.deflab == NULL) {
+ sw.deflab = findlabel(lab);
+ definelab(lab);
+ if (sw.ncases == 0)
+ warning("switch statement with no cases\n");
+ }
+ if (findlabel(lab + 1)->ref)
+ definelab(lab + 1);
+ tail = codelist;
+ codelist = head->prev;
+ codelist->next = head->prev = NULL;
+ if (sw.ncases > 0)
+ swgen(&sw);
+ branch(lab);
+ head->next->prev = codelist;
+ codelist->next = head->next;
+ codelist = tail;
+}
+static void caselabel(Swtch swp, long val, int lab) {
+ int k;
+
+ if (swp->ncases >= swp->size)
+ {
+ long *vals = swp->values;
+ Symbol *labs = swp->labels;
+ swp->size *= 2;
+ swp->values = newarray(swp->size, sizeof *swp->values, FUNC);
+ swp->labels = newarray(swp->size, sizeof *swp->labels, FUNC);
+ for (k = 0; k < swp->ncases; k++) {
+ swp->values[k] = vals[k];
+ swp->labels[k] = labs[k];
+ }
+ }
+ k = swp->ncases;
+ for ( ; k > 0 && swp->values[k-1] >= val; k--) {
+ swp->values[k] = swp->values[k-1];
+ swp->labels[k] = swp->labels[k-1];
+ }
+ if (k < swp->ncases && swp->values[k] == val)
+ error("duplicate case label `%d'\n", val);
+ swp->values[k] = val;
+ swp->labels[k] = findlabel(lab);
+ ++swp->ncases;
+ if (Aflag >= 2 && swp->ncases == 258)
+ warning("more than 257 cases in a switch\n");
+}
+void swgen(Swtch swp) {
+ int *buckets, k, n;
+ long *v = swp->values;
+
+ buckets = newarray(swp->ncases + 1,
+ sizeof *buckets, FUNC);
+ for (n = k = 0; k < swp->ncases; k++, n++) {
+ buckets[n] = k;
+ while (n > 0 && den(n-1, k) >= density)
+ n--;
+ }
+ buckets[n] = swp->ncases;
+ swcode(swp, buckets, 0, n - 1);
+}
+void swcode(Swtch swp, int b[], int lb, int ub) {
+ int hilab, lolab, l, u, k = (lb + ub)/2;
+ long *v = swp->values;
+
+ if (k > lb && k < ub) {
+ lolab = genlabel(1);
+ hilab = genlabel(1);
+ } else if (k > lb) {
+ lolab = genlabel(1);
+ hilab = swp->deflab->u.l.label;
+ } else if (k < ub) {
+ lolab = swp->deflab->u.l.label;
+ hilab = genlabel(1);
+ } else
+ lolab = hilab = swp->deflab->u.l.label;
+ l = b[k];
+ u = b[k+1] - 1;
+ if (u - l + 1 <= 3)
+ {
+ int i;
+ for (i = l; i <= u; i++)
+ cmp(EQ, swp->sym, v[i], swp->labels[i]->u.l.label);
+ if (k > lb && k < ub)
+ cmp(GT, swp->sym, v[u], hilab);
+ else if (k > lb)
+ cmp(GT, swp->sym, v[u], hilab);
+ else if (k < ub)
+ cmp(LT, swp->sym, v[l], lolab);
+ else
+ assert(lolab == hilab),
+ branch(lolab);
+ walk(NULL, 0, 0);
+ }
+ else {
+ Tree e;
+ Type ty = signedint(swp->sym->type);
+ Symbol table = genident(STATIC,
+ array(voidptype, u - l + 1, 0), GLOBAL);
+ (*IR->defsymbol)(table);
+ if (!isunsigned(swp->sym->type) || v[l] != 0)
+ cmp(LT, swp->sym, v[l], lolab);
+ cmp(GT, swp->sym, v[u], hilab);
+ e = (*optree['-'])(SUB, cast(idtree(swp->sym), ty), cnsttree(ty, v[l]));
+ if (e->type->size < unsignedptr->size)
+ e = cast(e, unsignedlong);
+ walk(tree(JUMP, voidtype,
+ rvalue((*optree['+'])(ADD, pointer(idtree(table)), e)), NULL),
+ 0, 0);
+ code(Switch);
+ codelist->u.swtch.table = table;
+ codelist->u.swtch.sym = swp->sym;
+ codelist->u.swtch.deflab = swp->deflab;
+ codelist->u.swtch.size = u - l + 1;
+ codelist->u.swtch.values = &v[l];
+ codelist->u.swtch.labels = &swp->labels[l];
+ if (v[u] - v[l] + 1 >= 10000)
+ warning("switch generates a huge table\n");
+ }
+ if (k > lb) {
+ assert(lolab != swp->deflab->u.l.label);
+ definelab(lolab);
+ swcode(swp, b, lb, k - 1);
+ }
+ if (k < ub) {
+ assert(hilab != swp->deflab->u.l.label);
+ definelab(hilab);
+ swcode(swp, b, k + 1, ub);
+ }
+}
+static void cmp(int op, Symbol p, long n, int lab) {
+ Type ty = signedint(p->type);
+
+ listnodes(eqtree(op,
+ cast(idtree(p), ty),
+ cnsttree(ty, n)),
+ lab, 0);
+}
+void retcode(Tree p) {
+ Type ty;
+
+ if (p == NULL) {
+ if (events.returns)
+ apply(events.returns, cfunc, NULL);
+ return;
+ }
+ p = pointer(p);
+ ty = assign(freturn(cfunc->type), p);
+ if (ty == NULL) {
+ error("illegal return type; found `%t' expected `%t'\n",
+ p->type, freturn(cfunc->type));
+ return;
+ }
+ p = cast(p, ty);
+ if (retv)
+ {
+ if (iscallb(p))
+ p = tree(RIGHT, p->type,
+ tree(CALL+B, p->type,
+ p->kids[0]->kids[0], idtree(retv)),
+ rvalue(idtree(retv)));
+ else
+ p = asgntree(ASGN, rvalue(idtree(retv)), p);
+ walk(p, 0, 0);
+ if (events.returns)
+ apply(events.returns, cfunc, rvalue(idtree(retv)));
+ return;
+ }
+ if (events.returns)
+ {
+ Symbol t1 = genident(AUTO, p->type, level);
+ addlocal(t1);
+ walk(asgn(t1, p), 0, 0);
+ apply(events.returns, cfunc, idtree(t1));
+ p = idtree(t1);
+ }
+ if (!isfloat(p->type))
+ p = cast(p, promote(p->type));
+ if (isptr(p->type))
+ {
+ Symbol q = localaddr(p);
+ if (q && (q->computed || q->generated))
+ warning("pointer to a %s is an illegal return value\n",
+ q->scope == PARAM ? "parameter" : "local");
+ else if (q)
+ warning("pointer to %s `%s' is an illegal return value\n",
+ q->scope == PARAM ? "parameter" : "local", q->name);
+ }
+ walk(tree(mkop(RET,p->type), p->type, p, NULL), 0, 0);
+}
+void definelab(int lab) {
+ Code cp;
+ Symbol p = findlabel(lab);
+
+ assert(lab);
+ walk(NULL, 0, 0);
+ code(Label)->u.forest = newnode(LABEL+V, NULL, NULL, p);
+ for (cp = codelist->prev; cp->kind <= Label; )
+ cp = cp->prev;
+ while ( cp->kind == Jump
+ && cp->u.forest->kids[0]
+ && specific(cp->u.forest->kids[0]->op) == ADDRG+P
+ && cp->u.forest->kids[0]->syms[0] == p) {
+ assert(cp->u.forest->kids[0]->syms[0]->u.l.label == lab);
+ p->ref--;
+ assert(cp->next);
+ assert(cp->prev);
+ cp->prev->next = cp->next;
+ cp->next->prev = cp->prev;
+ cp = cp->prev;
+ while (cp->kind <= Label)
+ cp = cp->prev;
+ }
+}
+Node jump(int lab) {
+ Symbol p = findlabel(lab);
+
+ p->ref++;
+ return newnode(JUMP+V, newnode(ADDRG+ttob(voidptype), NULL, NULL, p),
+ NULL, NULL);
+}
+void branch(int lab) {
+ Code cp;
+ Symbol p = findlabel(lab);
+
+ assert(lab);
+ walk(NULL, 0, 0);
+ code(Label)->u.forest = jump(lab);
+ for (cp = codelist->prev; cp->kind < Label; )
+ cp = cp->prev;
+ while ( cp->kind == Label
+ && cp->u.forest->op == LABEL+V
+ && !equal(cp->u.forest->syms[0], p)) {
+ equatelab(cp->u.forest->syms[0], p);
+ assert(cp->next);
+ assert(cp->prev);
+ cp->prev->next = cp->next;
+ cp->next->prev = cp->prev;
+ cp = cp->prev;
+ while (cp->kind < Label)
+ cp = cp->prev;
+ }
+ if (cp->kind == Jump || cp->kind == Switch) {
+ p->ref--;
+ codelist->prev->next = NULL;
+ codelist = codelist->prev;
+ } else {
+ codelist->kind = Jump;
+ if (cp->kind == Label
+ && cp->u.forest->op == LABEL+V
+ && equal(cp->u.forest->syms[0], p))
+ warning("source code specifies an infinite loop");
+ }
+}
+void equatelab(Symbol old, Symbol new) {
+ assert(old->u.l.equatedto == NULL);
+ old->u.l.equatedto = new;
+ new->ref++;
+}
+static int equal(Symbol lprime, Symbol dst) {
+ assert(dst && lprime);
+ for ( ; dst; dst = dst->u.l.equatedto)
+ if (lprime == dst)
+ return 1;
+ return 0;
+}
+/* dostmt - do statement while ( expression ) */
+static void dostmt(int lab, Swtch swp, int lev) {
+ refinc *= 10.0;
+ t = gettok();
+ definelab(lab);
+ statement(lab, swp, lev);
+ definelab(lab + 1);
+ expect(WHILE);
+ expect('(');
+ definept(NULL);
+ walk(conditional(')'), lab, 0);
+ if (findlabel(lab + 2)->ref)
+ definelab(lab + 2);
+}
+
+/* foldcond - check if initial test in for(e1;e2;e3) S is necessary */
+static int foldcond(Tree e1, Tree e2) {
+ int op = generic(e2->op);
+ Symbol v;
+
+ if (e1 == 0 || e2 == 0)
+ return 0;
+ if (generic(e1->op) == ASGN && isaddrop(e1->kids[0]->op)
+ && generic(e1->kids[1]->op) == CNST) {
+ v = e1->kids[0]->u.sym;
+ e1 = e1->kids[1];
+ } else
+ return 0;
+ if ((op==LE || op==LT || op==EQ || op==NE || op==GT || op==GE)
+ && generic(e2->kids[0]->op) == INDIR
+ && e2->kids[0]->kids[0]->u.sym == v
+ && e2->kids[1]->op == e1->op) {
+ e1 = simplify(op, e2->type, e1, e2->kids[1]);
+ if (e1->op == CNST+I)
+ return e1->u.v.i;
+ }
+ return 0;
+}
+
+/* localaddr - returns q if p yields the address of local/parameter q; otherwise returns 0 */
+static Symbol localaddr(Tree p) {
+ if (p == NULL)
+ return NULL;
+ switch (generic(p->op)) {
+ case INDIR: case CALL: case ARG:
+ return NULL;
+ case ADDRL: case ADDRF:
+ return p->u.sym;
+ case RIGHT: case ASGN:
+ if (p->kids[1])
+ return localaddr(p->kids[1]);
+ return localaddr(p->kids[0]);
+ case COND: {
+ Symbol q;
+ assert(p->kids[1] && p->kids[1]->op == RIGHT);
+ if ((q = localaddr(p->kids[1]->kids[0])) != NULL)
+ return q;
+ return localaddr(p->kids[1]->kids[1]);
+ }
+ default: {
+ Symbol q;
+ if (p->kids[0] && (q = localaddr(p->kids[0])) != NULL)
+ return q;
+ return localaddr(p->kids[1]);
+ }
+ }
+}
+
+/* whilestmt - while ( expression ) statement */
+static void whilestmt(int lab, Swtch swp, int lev) {
+ Coordinate pt;
+ Tree e;
+
+ refinc *= 10.0;
+ t = gettok();
+ expect('(');
+ walk(NULL, 0, 0);
+ pt = src;
+ e = texpr(conditional, ')', FUNC);
+ branch(lab + 1);
+ definelab(lab);
+ statement(lab, swp, lev);
+ definelab(lab + 1);
+ definept(&pt);
+ walk(e, lab, 0);
+ if (findlabel(lab + 2)->ref)
+ definelab(lab + 2);
+}
diff --git a/lcc/src/string.c b/lcc/src/string.c
new file mode 100755
index 0000000..4fee2c9
--- /dev/null
+++ b/lcc/src/string.c
@@ -0,0 +1,122 @@
+#include "c.h"
+
+
+static struct string {
+ char *str;
+ int len;
+ struct string *link;
+} *buckets[1024];
+static int scatter[] = { /* map characters to random values */
+ 2078917053, 143302914, 1027100827, 1953210302, 755253631,
+ 2002600785, 1405390230, 45248011, 1099951567, 433832350,
+ 2018585307, 438263339, 813528929, 1703199216, 618906479,
+ 573714703, 766270699, 275680090, 1510320440, 1583583926,
+ 1723401032, 1965443329, 1098183682, 1636505764, 980071615,
+ 1011597961, 643279273, 1315461275, 157584038, 1069844923,
+ 471560540, 89017443, 1213147837, 1498661368, 2042227746,
+ 1968401469, 1353778505, 1300134328, 2013649480, 306246424,
+ 1733966678, 1884751139, 744509763, 400011959, 1440466707,
+ 1363416242, 973726663, 59253759, 1639096332, 336563455,
+ 1642837685, 1215013716, 154523136, 593537720, 704035832,
+ 1134594751, 1605135681, 1347315106, 302572379, 1762719719,
+ 269676381, 774132919, 1851737163, 1482824219, 125310639,
+ 1746481261, 1303742040, 1479089144, 899131941, 1169907872,
+ 1785335569, 485614972, 907175364, 382361684, 885626931,
+ 200158423, 1745777927, 1859353594, 259412182, 1237390611,
+ 48433401, 1902249868, 304920680, 202956538, 348303940,
+ 1008956512, 1337551289, 1953439621, 208787970, 1640123668,
+ 1568675693, 478464352, 266772940, 1272929208, 1961288571,
+ 392083579, 871926821, 1117546963, 1871172724, 1771058762,
+ 139971187, 1509024645, 109190086, 1047146551, 1891386329,
+ 994817018, 1247304975, 1489680608, 706686964, 1506717157,
+ 579587572, 755120366, 1261483377, 884508252, 958076904,
+ 1609787317, 1893464764, 148144545, 1415743291, 2102252735,
+ 1788268214, 836935336, 433233439, 2055041154, 2109864544,
+ 247038362, 299641085, 834307717, 1364585325, 23330161,
+ 457882831, 1504556512, 1532354806, 567072918, 404219416,
+ 1276257488, 1561889936, 1651524391, 618454448, 121093252,
+ 1010757900, 1198042020, 876213618, 124757630, 2082550272,
+ 1834290522, 1734544947, 1828531389, 1982435068, 1002804590,
+ 1783300476, 1623219634, 1839739926, 69050267, 1530777140,
+ 1802120822, 316088629, 1830418225, 488944891, 1680673954,
+ 1853748387, 946827723, 1037746818, 1238619545, 1513900641,
+ 1441966234, 367393385, 928306929, 946006977, 985847834,
+ 1049400181, 1956764878, 36406206, 1925613800, 2081522508,
+ 2118956479, 1612420674, 1668583807, 1800004220, 1447372094,
+ 523904750, 1435821048, 923108080, 216161028, 1504871315,
+ 306401572, 2018281851, 1820959944, 2136819798, 359743094,
+ 1354150250, 1843084537, 1306570817, 244413420, 934220434,
+ 672987810, 1686379655, 1301613820, 1601294739, 484902984,
+ 139978006, 503211273, 294184214, 176384212, 281341425,
+ 228223074, 147857043, 1893762099, 1896806882, 1947861263,
+ 1193650546, 273227984, 1236198663, 2116758626, 489389012,
+ 593586330, 275676551, 360187215, 267062626, 265012701,
+ 719930310, 1621212876, 2108097238, 2026501127, 1865626297,
+ 894834024, 552005290, 1404522304, 48964196, 5816381,
+ 1889425288, 188942202, 509027654, 36125855, 365326415,
+ 790369079, 264348929, 513183458, 536647531, 13672163,
+ 313561074, 1730298077, 286900147, 1549759737, 1699573055,
+ 776289160, 2143346068, 1975249606, 1136476375, 262925046,
+ 92778659, 1856406685, 1884137923, 53392249, 1735424165,
+ 1602280572
+};
+char *string(const char *str) {
+ const char *s;
+
+ for (s = str; *s; s++)
+ ;
+ return stringn(str, s - str);
+}
+char *stringd(long n) {
+ char str[25], *s = str + sizeof (str);
+ unsigned long m;
+
+ if (n == LONG_MIN)
+ m = (unsigned long)LONG_MAX + 1;
+ else if (n < 0)
+ m = -n;
+ else
+ m = n;
+ do
+ *--s = m%10 + '0';
+ while ((m /= 10) != 0);
+ if (n < 0)
+ *--s = '-';
+ return stringn(s, str + sizeof (str) - s);
+}
+char *stringn(const char *str, int len) {
+ int i;
+ unsigned int h;
+ const char *end;
+ struct string *p;
+
+ assert(str);
+ for (h = 0, i = len, end = str; i > 0; i--)
+ h = (h<<1) + scatter[*(unsigned char *)end++];
+ h &= NELEMS(buckets)-1;
+ for (p = buckets[h]; p; p = p->link)
+ if (len == p->len) {
+ const char *s1 = str;
+ char *s2 = p->str;
+ do {
+ if (s1 == end)
+ return p->str;
+ } while (*s1++ == *s2++);
+ }
+ {
+ static char *next, *strlimit;
+ if (len + 1 >= strlimit - next) {
+ int n = len + 4*1024;
+ next = allocate(n, PERM);
+ strlimit = next + n;
+ }
+ NEW(p, PERM);
+ p->len = len;
+ for (p->str = next; str < end; )
+ *next++ = *str++;
+ *next++ = 0;
+ p->link = buckets[h];
+ buckets[h] = p;
+ return p->str;
+ }
+}
diff --git a/lcc/src/sym.c b/lcc/src/sym.c
new file mode 100755
index 0000000..1d754d4
--- /dev/null
+++ b/lcc/src/sym.c
@@ -0,0 +1,315 @@
+#include "c.h"
+#include <stdio.h>
+
+
+#define equalp(x) v.x == p->sym.u.c.v.x
+
+struct table {
+ int level;
+ Table previous;
+ struct entry {
+ struct symbol sym;
+ struct entry *link;
+ } *buckets[256];
+ Symbol all;
+};
+#define HASHSIZE NELEMS(((Table)0)->buckets)
+static struct table
+ cns = { CONSTANTS },
+ ext = { GLOBAL },
+ ids = { GLOBAL },
+ tys = { GLOBAL };
+Table constants = &cns;
+Table externals = &ext;
+Table identifiers = &ids;
+Table globals = &ids;
+Table types = &tys;
+Table labels;
+int level = GLOBAL;
+static int tempid;
+List loci, symbols;
+
+Table table(Table tp, int level) {
+ Table new;
+
+ NEW0(new, FUNC);
+ new->previous = tp;
+ new->level = level;
+ if (tp)
+ new->all = tp->all;
+ return new;
+}
+void foreach(Table tp, int lev, void (*apply)(Symbol, void *), void *cl) {
+ assert(tp);
+ while (tp && tp->level > lev)
+ tp = tp->previous;
+ if (tp && tp->level == lev) {
+ Symbol p;
+ Coordinate sav;
+ sav = src;
+ for (p = tp->all; p && p->scope == lev; p = p->up) {
+ src = p->src;
+ (*apply)(p, cl);
+ }
+ src = sav;
+ }
+}
+void enterscope(void) {
+ if (++level == LOCAL)
+ tempid = 0;
+}
+void exitscope(void) {
+ rmtypes(level);
+ if (types->level == level)
+ types = types->previous;
+ if (identifiers->level == level) {
+ if (Aflag >= 2) {
+ int n = 0;
+ Symbol p;
+ for (p = identifiers->all; p && p->scope == level; p = p->up)
+ if (++n > 127) {
+ warning("more than 127 identifiers declared in a block\n");
+ break;
+ }
+ }
+ identifiers = identifiers->previous;
+ }
+ assert(level >= GLOBAL);
+ --level;
+}
+Symbol install(const char *name, Table *tpp, int level, int arena) {
+ Table tp = *tpp;
+ struct entry *p;
+ unsigned h = (unsigned long)name&(HASHSIZE-1);
+
+ assert(level == 0 || level >= tp->level);
+ if (level > 0 && tp->level < level)
+ tp = *tpp = table(tp, level);
+ NEW0(p, arena);
+ p->sym.name = (char *)name;
+ p->sym.scope = level;
+ p->sym.up = tp->all;
+ tp->all = &p->sym;
+ p->link = tp->buckets[h];
+ tp->buckets[h] = p;
+ return &p->sym;
+}
+Symbol relocate(const char *name, Table src, Table dst) {
+ struct entry *p, **q;
+ Symbol *r;
+ unsigned h = (unsigned long)name&(HASHSIZE-1);
+
+ for (q = &src->buckets[h]; *q; q = &(*q)->link)
+ if (name == (*q)->sym.name)
+ break;
+ assert(*q);
+ /*
+ Remove the entry from src's hash chain
+ and from its list of all symbols.
+ */
+ p = *q;
+ *q = (*q)->link;
+ for (r = &src->all; *r && *r != &p->sym; r = &(*r)->up)
+ ;
+ assert(*r == &p->sym);
+ *r = p->sym.up;
+ /*
+ Insert the entry into dst's hash chain
+ and into its list of all symbols.
+ Return the symbol-table entry.
+ */
+ p->link = dst->buckets[h];
+ dst->buckets[h] = p;
+ p->sym.up = dst->all;
+ dst->all = &p->sym;
+ return &p->sym;
+}
+Symbol lookup(const char *name, Table tp) {
+ struct entry *p;
+ unsigned h = (unsigned long)name&(HASHSIZE-1);
+
+ assert(tp);
+ do
+ for (p = tp->buckets[h]; p; p = p->link)
+ if (name == p->sym.name)
+ return &p->sym;
+ while ((tp = tp->previous) != NULL);
+ return NULL;
+}
+int genlabel(int n) {
+ static int label = 1;
+
+ label += n;
+ return label - n;
+}
+Symbol findlabel(int lab) {
+ struct entry *p;
+ unsigned h = lab&(HASHSIZE-1);
+
+ for (p = labels->buckets[h]; p; p = p->link)
+ if (lab == p->sym.u.l.label)
+ return &p->sym;
+ NEW0(p, FUNC);
+ p->sym.name = stringd(lab);
+ p->sym.scope = LABELS;
+ p->sym.up = labels->all;
+ labels->all = &p->sym;
+ p->link = labels->buckets[h];
+ labels->buckets[h] = p;
+ p->sym.generated = 1;
+ p->sym.u.l.label = lab;
+ (*IR->defsymbol)(&p->sym);
+ return &p->sym;
+}
+Symbol constant(Type ty, Value v) {
+ struct entry *p;
+ unsigned h = v.u&(HASHSIZE-1);
+
+ ty = unqual(ty);
+ for (p = constants->buckets[h]; p; p = p->link)
+ if (eqtype(ty, p->sym.type, 1))
+ switch (ty->op) {
+ case INT: if (equalp(i)) return &p->sym; break;
+ case UNSIGNED: if (equalp(u)) return &p->sym; break;
+ case FLOAT: if (equalp(d)) return &p->sym; break;
+ case FUNCTION: if (equalp(g)) return &p->sym; break;
+ case ARRAY:
+ case POINTER: if (equalp(p)) return &p->sym; break;
+ default: assert(0);
+ }
+ NEW0(p, PERM);
+ p->sym.name = vtoa(ty, v);
+ p->sym.scope = CONSTANTS;
+ p->sym.type = ty;
+ p->sym.sclass = STATIC;
+ p->sym.u.c.v = v;
+ p->link = constants->buckets[h];
+ p->sym.up = constants->all;
+ constants->all = &p->sym;
+ constants->buckets[h] = p;
+ if (ty->u.sym && !ty->u.sym->addressed)
+ (*IR->defsymbol)(&p->sym);
+ p->sym.defined = 1;
+ return &p->sym;
+}
+Symbol intconst(int n) {
+ Value v;
+
+ v.i = n;
+ return constant(inttype, v);
+}
+Symbol genident(int scls, Type ty, int lev) {
+ Symbol p;
+
+ NEW0(p, lev >= LOCAL ? FUNC : PERM);
+ p->name = stringd(genlabel(1));
+ p->scope = lev;
+ p->sclass = scls;
+ p->type = ty;
+ p->generated = 1;
+ if (lev == GLOBAL)
+ (*IR->defsymbol)(p);
+ return p;
+}
+
+Symbol temporary(int scls, Type ty) {
+ Symbol p;
+
+ NEW0(p, FUNC);
+ p->name = stringd(++tempid);
+ p->scope = level < LOCAL ? LOCAL : level;
+ p->sclass = scls;
+ p->type = ty;
+ p->temporary = 1;
+ p->generated = 1;
+ return p;
+}
+Symbol newtemp(int sclass, int tc, int size) {
+ Symbol p = temporary(sclass, btot(tc, size));
+
+ (*IR->local)(p);
+ p->defined = 1;
+ return p;
+}
+
+Symbol allsymbols(Table tp) {
+ return tp->all;
+}
+
+void locus(Table tp, Coordinate *cp) {
+ loci = append(cp, loci);
+ symbols = append(allsymbols(tp), symbols);
+}
+
+void use(Symbol p, Coordinate src) {
+ Coordinate *cp;
+
+ NEW(cp, PERM);
+ *cp = src;
+ p->uses = append(cp, p->uses);
+}
+/* findtype - find type ty in identifiers */
+Symbol findtype(Type ty) {
+ Table tp = identifiers;
+ int i;
+ struct entry *p;
+
+ assert(tp);
+ do
+ for (i = 0; i < HASHSIZE; i++)
+ for (p = tp->buckets[i]; p; p = p->link)
+ if (p->sym.type == ty && p->sym.sclass == TYPEDEF)
+ return &p->sym;
+ while ((tp = tp->previous) != NULL);
+ return NULL;
+}
+
+/* mkstr - make a string constant */
+Symbol mkstr(char *str) {
+ Value v;
+ Symbol p;
+
+ v.p = str;
+ p = constant(array(chartype, strlen(v.p) + 1, 0), v);
+ if (p->u.c.loc == NULL)
+ p->u.c.loc = genident(STATIC, p->type, GLOBAL);
+ return p;
+}
+
+/* mksymbol - make a symbol for name, install in &globals if sclass==EXTERN */
+Symbol mksymbol(int sclass, const char *name, Type ty) {
+ Symbol p;
+
+ if (sclass == EXTERN)
+ p = install(string(name), &globals, GLOBAL, PERM);
+ else {
+ NEW0(p, PERM);
+ p->name = string(name);
+ p->scope = GLOBAL;
+ }
+ p->sclass = sclass;
+ p->type = ty;
+ (*IR->defsymbol)(p);
+ p->defined = 1;
+ return p;
+}
+
+/* vtoa - return string for the constant v of type ty */
+char *vtoa(Type ty, Value v) {
+ char buf[50];
+
+ ty = unqual(ty);
+ switch (ty->op) {
+ case INT: return stringd(v.i);
+ case UNSIGNED: return stringf((v.u&~0x7FFF) ? "0x%X" : "%U", v.u);
+ case FLOAT: return stringf("%g", (double)v.d);
+ case ARRAY:
+ if (ty->type == chartype || ty->type == signedchar
+ || ty->type == unsignedchar)
+ return v.p;
+ return stringf("%p", v.p);
+ case POINTER: return stringf("%p", v.p);
+ case FUNCTION: return stringf("%p", v.g);
+ }
+ assert(0); return NULL;
+}
diff --git a/lcc/src/symbolic.c b/lcc/src/symbolic.c
new file mode 100755
index 0000000..35ff55c
--- /dev/null
+++ b/lcc/src/symbolic.c
@@ -0,0 +1,494 @@
+#include <time.h>
+#include <ctype.h>
+#include "c.h"
+
+#define I(f) s_##f
+
+static Node *tail;
+static int off, maxoff, uid = 0, verbose = 0, html = 0;
+
+static const char *yyBEGIN(const char *tag) {
+ if (html)
+ print("<%s>", tag);
+ return tag;
+}
+
+static void yyEND(const char *tag) {
+ if (html)
+ print("</%s>", tag);
+ if (isupper(*tag))
+ print("\n");
+}
+
+#define BEGIN(tag) do { const char *yytag=yyBEGIN(#tag);
+#define END yyEND(yytag); } while (0)
+#define ITEM BEGIN(li)
+#define START BEGIN(LI)
+#define ANCHOR(attr,code) do { const char *yytag="a"; if (html) { printf("<a " #attr "=\""); code; print("\">"); }
+#define NEWLINE print(html ? "<br>\n" : "\n")
+
+static void emitCoord(Coordinate src) {
+ if (src.file && *src.file) {
+ ANCHOR(href,print("%s", src.file)); print("%s", src.file); END;
+ print(":");
+ }
+ print("%d.%d", src.y, src.x);
+}
+
+static void emitString(int len, const char *s) {
+ for ( ; len-- > 0; s++)
+ if (*s == '&' && html)
+ print("&amp;");
+ else if (*s == '<' && html)
+ print("&lt;");
+ else if (*s == '>' && html)
+ print("&lt;");
+ else if (*s == '"' || *s == '\\')
+ print("\\%c", *s);
+ else if (*s >= ' ' && *s < 0177)
+ print("%c", *s);
+ else
+ print("\\%d%d%d", (*s>>6)&3, (*s>>3)&7, *s&7);
+}
+
+static void emitSymRef(Symbol p) {
+ (*IR->defsymbol)(p);
+ ANCHOR(href,print("#%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END;
+}
+
+static void emitSymbol(Symbol p) {
+ (*IR->defsymbol)(p);
+ ANCHOR(name,print("%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END;
+ BEGIN(ul);
+#define xx(field,code) ITEM; if (!html) print(" "); print(#field "="); code; END
+ if (verbose && (src.y || src.x))
+ xx(src,emitCoord(p->src));
+ xx(type,print("%t", p->type));
+ xx(sclass,print("%k", p->sclass));
+ switch (p->scope) {
+ case CONSTANTS: xx(scope,print("CONSTANTS")); break;
+ case LABELS: xx(scope,print("LABELS")); break;
+ case GLOBAL: xx(scope,print("GLOBAL")); break;
+ case PARAM: xx(scope,print("PARAM")); break;
+ case LOCAL: xx(scope,print("LOCAL")); break;
+ default:
+ if (p->scope > LOCAL)
+ xx(scope,print("LOCAL+%d", p->scope-LOCAL));
+ else
+ xx(scope,print("%d", p->scope));
+ }
+ if (p->scope >= PARAM && p->sclass != STATIC)
+ xx(offset,print("%d", p->x.offset));
+ xx(ref,print("%f", p->ref));
+ if (p->temporary && p->u.t.cse)
+ xx(u.t.cse,print("%p", p->u.t.cse));
+ END;
+#undef xx
+}
+
+/* address - initialize q for addressing expression p+n */
+static void I(address)(Symbol q, Symbol p, long n) {
+ q->name = stringf("%s%s%D", p->name, n > 0 ? "+" : "", n);
+ (*IR->defsymbol)(q);
+ START; print("address "); emitSymbol(q); END;
+}
+
+/* blockbeg - start a block */
+static void I(blockbeg)(Env *e) {
+ e->offset = off;
+ START; print("blockbeg off=%d", off); END;
+}
+
+/* blockend - start a block */
+static void I(blockend)(Env *e) {
+ if (off > maxoff)
+ maxoff = off;
+ START; print("blockend off=%d", off); END;
+ off = e->offset;
+}
+
+/* defaddress - initialize an address */
+static void I(defaddress)(Symbol p){
+ START; print("defaddress "); emitSymRef(p); END;
+}
+
+/* defconst - define a constant */
+static void I(defconst)(int suffix, int size, Value v) {
+ START;
+ print("defconst ");
+ switch (suffix) {
+ case I:
+ print("int.%d ", size);
+ BEGIN(code);
+ if (size > sizeof (int))
+ print("%D", v.i);
+ else
+ print("%d", (int)v.i);
+ END;
+ break;
+ case U:
+ print("unsigned.%d ", size);
+ BEGIN(code);
+ if (size > sizeof (unsigned))
+ print("%U", v.u);
+ else
+ print("%u", (unsigned)v.u);
+ END;
+ break;
+ case P: print("void*.%d ", size); BEGIN(code); print("%p", v.p); END; break;
+ case F: print("float.%d ", size); BEGIN(code); print("%g", (double)v.d); END; break;
+ default: assert(0);
+ }
+ END;
+}
+
+/* defstring - emit a string constant */
+static void I(defstring)(int len, char *s) {
+ START; print("defstring ");
+ BEGIN(code); print("\""); emitString(len, s); print("\""); END;
+ END;
+}
+
+/* defsymbol - define a symbol: initialize p->x */
+static void I(defsymbol)(Symbol p) {
+ if (p->x.name == NULL)
+ p->x.name = stringd(++uid);
+}
+
+/* emit - emit the dags on list p */
+static void I(emit)(Node p){
+ ITEM;
+ if (!html)
+ print(" ");
+ for (; p; p = p->x.next) {
+ if (p->op == LABEL+V) {
+ assert(p->syms[0]);
+ ANCHOR(name,print("%s", p->syms[0]->x.name));
+ BEGIN(code); print("%s", p->syms[0]->name); END;
+ END;
+ print(":");
+ } else {
+ int i;
+ if (p->x.listed) {
+ BEGIN(strong); print("%d", p->x.inst); END; print("'");
+ print(" %s", opname(p->op));
+ } else
+ print("%d. %s", p->x.inst, opname(p->op));
+ if (p->count > 1)
+ print(" count=%d", p->count);
+ for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++)
+ print(" #%d", p->kids[i]->x.inst);
+ if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type)
+ print(" {%t}", p->syms[0]->type);
+ else
+ for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++) {
+ print(" ");
+ if (p->syms[i]->scope == CONSTANTS)
+ print(p->syms[i]->name);
+ else
+ emitSymRef(p->syms[i]);
+ }
+ }
+ NEWLINE;
+ }
+ END;
+}
+
+/* export - announce p as exported */
+static void I(export)(Symbol p) {
+ START; print("export "); emitSymRef(p); END;
+}
+
+/* function - generate code for a function */
+static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
+ int i;
+
+ (*IR->defsymbol)(f);
+ off = 0;
+ for (i = 0; caller[i] && callee[i]; i++) {
+ off = roundup(off, caller[i]->type->align);
+ caller[i]->x.offset = callee[i]->x.offset = off;
+ off += caller[i]->type->size;
+ }
+ if (!html) {
+ print("function ");
+ emitSymbol(f);
+ print(" ncalls=%d\n", ncalls);
+ for (i = 0; caller[i]; i++)
+ START; print("caller "); emitSymbol(caller[i]); END;
+ for (i = 0; callee[i]; i++)
+ START; print("callee "); emitSymbol(callee[i]); END;
+ } else {
+ START;
+ print("function");
+ BEGIN(UL);
+#define xx(field,code) ITEM; print(#field "="); code; END
+ xx(f,emitSymbol(f));
+ xx(ncalls,print("%d", ncalls));
+ if (caller[0]) {
+ ITEM; print("caller"); BEGIN(OL);
+ for (i = 0; caller[i]; i++)
+ ITEM; emitSymbol(caller[i]); END;
+ END; END;
+ ITEM; print("callee"); BEGIN(OL);
+ for (i = 0; callee[i]; i++)
+ ITEM; emitSymbol(callee[i]); END;
+ END; END;
+ } else {
+ xx(caller,BEGIN(em); print("empty"); END);
+ xx(callee,BEGIN(em); print("empty"); END);
+ }
+ END;
+ END;
+ }
+ maxoff = off = 0;
+ gencode(caller, callee);
+ if (html)
+ START; print("emitcode"); BEGIN(ul); emitcode(); END; END;
+ else
+ emitcode();
+ START; print("maxoff=%d", maxoff); END;
+#undef xx
+}
+
+/* visit - generate code for *p */
+static int visit(Node p, int n) {
+ if (p && p->x.inst == 0) {
+ p->x.inst = ++n;
+ n = visit(p->kids[0], n);
+ n = visit(p->kids[1], n);
+ *tail = p;
+ tail = &p->x.next;
+ }
+ return n;
+}
+
+/* gen0 - generate code for the dags on list p */
+static Node I(gen)(Node p) {
+ int n;
+ Node nodelist;
+
+ tail = &nodelist;
+ for (n = 0; p; p = p->link) {
+ switch (generic(p->op)) { /* check for valid forest */
+ case CALL:
+ assert(IR->wants_dag || p->count == 0);
+ break;
+ case ARG:
+ case ASGN: case JUMP: case LABEL: case RET:
+ case EQ: case GE: case GT: case LE: case LT: case NE:
+ assert(p->count == 0);
+ break;
+ case INDIR:
+ assert(IR->wants_dag && p->count > 0);
+ break;
+ default:
+ assert(0);
+ }
+ check(p);
+ p->x.listed = 1;
+ n = visit(p, n);
+ }
+ *tail = 0;
+ return nodelist;
+}
+
+/* global - announce a global */
+static void I(global)(Symbol p) {
+ START; print("global "); emitSymbol(p); END;
+}
+
+/* import - import a symbol */
+static void I(import)(Symbol p) {
+ START; print("import "); emitSymRef(p); END;
+}
+
+/* local - local variable */
+static void I(local)(Symbol p) {
+ if (p->temporary)
+ p->name = stringf("t%s", p->name);
+ (*IR->defsymbol)(p);
+ off = roundup(off, p->type->align);
+ p->x.offset = off;
+ off += p->type->size;
+ START; print(p->temporary ? "temporary " : "local "); emitSymbol(p); END;
+}
+
+/* progbeg - beginning of program */
+static void I(progbeg)(int argc, char *argv[]) {
+ int i;
+
+ for (i = 1; i < argc; i++)
+ if (strcmp(argv[i], "-v") == 0)
+ verbose++;
+ else if (strcmp(argv[i], "-html") == 0)
+ html++;
+ if (html) {
+ print("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n");
+ print("<html>");
+ BEGIN(head);
+ if (firstfile && *firstfile)
+ BEGIN(title); emitString(strlen(firstfile), firstfile); END;
+ print("<link rev=made href=\"mailto:drh@microsoft.com\">\n");
+ END;
+ print("<body>\n");
+ if (firstfile && *firstfile)
+ BEGIN(h1); emitString(strlen(firstfile), firstfile); END;
+ BEGIN(P); BEGIN(em);
+ print("Links lead from uses of identifiers and labels to their definitions.");
+ END; END;
+ print("<ul>\n");
+ START;
+ print("progbeg");
+ BEGIN(ol);
+ for (i = 1; i < argc; i++) {
+ ITEM;
+ BEGIN(code); print("\""); emitString(strlen(argv[i]), argv[i]); print("\""); END;
+ END;
+ }
+ END;
+ END;
+ }
+}
+
+/* progend - end of program */
+static void I(progend)(void) {
+ START; print("progend"); END;
+ if (html) {
+ time_t t;
+ print("</ul>\n");
+ time(&t);
+ print("<hr><address>%s</address>\n", ctime(&t));
+ print("</body></html>\n");
+ }
+}
+
+/* segment - switch to segment s */
+static void I(segment)(int s) {
+ START; print("segment %s", &"text\0bss\0.data\0lit\0.sym\0."[5*s-5]); END;
+}
+
+/* space - initialize n bytes of space */
+static void I(space)(int n) {
+ START; print("space %d", n); END;
+}
+
+static void I(stabblock)(int brace, int lev, Symbol *p) {}
+
+/* stabend - finalize stab output */
+static void I(stabend)(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {
+ int i;
+
+ if (p)
+ emitSymRef(p);
+ print("\n");
+ if (cpp && sp)
+ for (i = 0; cpp[i] && sp[i]; i++) {
+ print("%w.%d: ", cpp[i], cpp[i]->x);
+ emitSymRef(sp[i]);
+ print("\n");
+ }
+}
+
+static void I(stabfend)(Symbol p, int lineno) {}
+static void I(stabinit)(char *file, int argc, char *argv[]) {}
+
+/* stabline - emit line number information for source coordinate *cp */
+static void I(stabline)(Coordinate *cp) {
+ if (cp->file)
+ print("%s:", cp->file);
+ print("%d.%d:\n", cp->y, cp->x);
+}
+
+static void I(stabsym)(Symbol p) {}
+static void I(stabtype)(Symbol p) {}
+
+Interface symbolicIR = {
+ 1, 1, 0, /* char */
+ 2, 2, 0, /* short */
+ 4, 4, 0, /* int */
+ 4, 4, 0, /* long */
+ 4, 4, 0, /* long long */
+ 4, 4, 1, /* float */
+ 8, 8, 1, /* double */
+ 8, 8, 1, /* long double */
+ 4, 4, 0, /* T* */
+ 0, 4, 0, /* struct */
+ 0, /* little_endian */
+ 0, /* mulops_calls */
+ 0, /* wants_callb */
+ 1, /* wants_argb */
+ 1, /* left_to_right */
+ 1, /* wants_dag */
+ 0, /* unsigned_char */
+ I(address),
+ I(blockbeg),
+ I(blockend),
+ I(defaddress),
+ I(defconst),
+ I(defstring),
+ I(defsymbol),
+ I(emit),
+ I(export),
+ I(function),
+ I(gen),
+ I(global),
+ I(import),
+ I(local),
+ I(progbeg),
+ I(progend),
+ I(segment),
+ I(space),
+ I(stabblock),
+ I(stabend),
+ I(stabfend),
+ I(stabinit),
+ I(stabline),
+ I(stabsym),
+ I(stabtype)
+};
+
+Interface symbolic64IR = {
+ 1, 1, 0, /* char */
+ 2, 2, 0, /* short */
+ 4, 4, 0, /* int */
+ 8, 8, 0, /* long */
+ 8, 8, 0, /* long long */
+ 4, 4, 1, /* float */
+ 8, 8, 1, /* double */
+ 8, 8, 1, /* long double */
+ 8, 8, 0, /* T* */
+ 0, 1, 0, /* struct */
+ 1, /* little_endian */
+ 0, /* mulops_calls */
+ 0, /* wants_callb */
+ 1, /* wants_argb */
+ 1, /* left_to_right */
+ 1, /* wants_dag */
+ 0, /* unsigned_char */
+ I(address),
+ I(blockbeg),
+ I(blockend),
+ I(defaddress),
+ I(defconst),
+ I(defstring),
+ I(defsymbol),
+ I(emit),
+ I(export),
+ I(function),
+ I(gen),
+ I(global),
+ I(import),
+ I(local),
+ I(progbeg),
+ I(progend),
+ I(segment),
+ I(space),
+ I(stabblock),
+ I(stabend),
+ I(stabfend),
+ I(stabinit),
+ I(stabline),
+ I(stabsym),
+ I(stabtype)
+};
diff --git a/lcc/src/token.h b/lcc/src/token.h
new file mode 100755
index 0000000..f92bf6a
--- /dev/null
+++ b/lcc/src/token.h
@@ -0,0 +1,133 @@
+/*
+xx(symbol, value, prec, op, optree, kind, string)
+*/
+yy(0, 0, 0, 0, 0, 0, 0)
+xx(FLOAT, 1, 0, 0, 0, CHAR, "float")
+xx(DOUBLE, 2, 0, 0, 0, CHAR, "double")
+xx(CHAR, 3, 0, 0, 0, CHAR, "char")
+xx(SHORT, 4, 0, 0, 0, CHAR, "short")
+xx(INT, 5, 0, 0, 0, CHAR, "int")
+xx(UNSIGNED, 6, 0, 0, 0, CHAR, "unsigned")
+xx(POINTER, 7, 0, 0, 0, 0, "pointer")
+xx(VOID, 8, 0, 0, 0, CHAR, "void")
+xx(STRUCT, 9, 0, 0, 0, CHAR, "struct")
+xx(UNION, 10, 0, 0, 0, CHAR, "union")
+xx(FUNCTION, 11, 0, 0, 0, 0, "function")
+xx(ARRAY, 12, 0, 0, 0, 0, "array")
+xx(ENUM, 13, 0, 0, 0, CHAR, "enum")
+xx(LONG, 14, 0, 0, 0, CHAR, "long")
+xx(CONST, 15, 0, 0, 0, CHAR, "const")
+xx(VOLATILE, 16, 0, 0, 0, CHAR, "volatile")
+yy(0, 17, 0, 0, 0, 0, 0)
+yy(0, 18, 0, 0, 0, 0, 0)
+yy(0, 19, 0, 0, 0, 0, 0)
+yy(0, 20, 0, 0, 0, 0, 0)
+yy(0, 21, 0, 0, 0, 0, 0)
+yy(0, 22, 0, 0, 0, 0, 0)
+yy(0, 23, 0, 0, 0, 0, 0)
+yy(0, 24, 0, 0, 0, 0, 0)
+yy(0, 25, 0, 0, 0, 0, 0)
+yy(0, 26, 0, 0, 0, 0, 0)
+yy(0, 27, 0, 0, 0, 0, 0)
+yy(0, 28, 0, 0, 0, 0, "long long")
+yy(0, 29, 0, 0, 0, 0, 0)
+yy(0, 30, 0, 0, 0, 0, 0)
+yy(0, 31, 0, 0, 0, 0, "const volatile")
+xx(ID, 32, 0, 0, 0, ID, "identifier")
+yy(0, 33, 0, 0, 0, ID, "!")
+xx(FCON, 34, 0, 0, 0, ID, "floating constant")
+xx(ICON, 35, 0, 0, 0, ID, "integer constant")
+xx(SCON, 36, 0, 0, 0, ID, "string constant")
+yy(0, 37, 13, MOD, bittree,'%', "%")
+yy(0, 38, 8, BAND, bittree,ID, "&")
+xx(INCR, 39, 0, ADD, addtree,ID, "++")
+yy(0, 40, 0, 0, 0, ID, "(")
+yy(0, 41, 0, 0, 0, ')', ")")
+yy(0, 42, 13, MUL, multree,ID, "*")
+yy(0, 43, 12, ADD, addtree,ID, "+")
+yy(0, 44, 1, 0, 0, ',', ",")
+yy(0, 45, 12, SUB, subtree,ID, "-")
+yy(0, 46, 0, 0, 0, '.', ".")
+yy(0, 47, 13, DIV, multree,'/', "/")
+xx(DECR, 48, 0, SUB, subtree,ID, "--")
+xx(DEREF, 49, 0, 0, 0, DEREF, "->")
+xx(ANDAND, 50, 5, AND, andtree,ANDAND, "&&")
+xx(OROR, 51, 4, OR, andtree,OROR, "||")
+xx(LEQ, 52, 10, LE, cmptree,LEQ, "<=")
+xx(EQL, 53, 9, EQ, eqtree, EQL, "==")
+xx(NEQ, 54, 9, NE, eqtree, NEQ, "!=")
+xx(GEQ, 55, 10, GE, cmptree,GEQ, ">=")
+xx(RSHIFT, 56, 11, RSH, shtree, RSHIFT, ">>")
+xx(LSHIFT, 57, 11, LSH, shtree, LSHIFT, "<<")
+yy(0, 58, 0, 0, 0, ':', ":")
+yy(0, 59, 0, 0, 0, IF, ";")
+yy(0, 60, 10, LT, cmptree,'<', "<")
+yy(0, 61, 2, ASGN, asgntree,'=', "=")
+yy(0, 62, 10, GT, cmptree,'>', ">")
+yy(0, 63, 0, 0, 0, '?', "?")
+xx(ELLIPSIS, 64, 0, 0, 0, ELLIPSIS,"...")
+xx(SIZEOF, 65, 0, 0, 0, ID, "sizeof")
+yy(0, 66, 0, 0, 0, 0, 0)
+xx(AUTO, 67, 0, 0, 0, STATIC, "auto")
+xx(BREAK, 68, 0, 0, 0, IF, "break")
+xx(CASE, 69, 0, 0, 0, IF, "case")
+xx(CONTINUE, 70, 0, 0, 0, IF, "continue")
+xx(DEFAULT, 71, 0, 0, 0, IF, "default")
+xx(DO, 72, 0, 0, 0, IF, "do")
+xx(ELSE, 73, 0, 0, 0, IF, "else")
+xx(EXTERN, 74, 0, 0, 0, STATIC, "extern")
+xx(FOR, 75, 0, 0, 0, IF, "for")
+xx(GOTO, 76, 0, 0, 0, IF, "goto")
+xx(IF, 77, 0, 0, 0, IF, "if")
+xx(REGISTER, 78, 0, 0, 0, STATIC, "register")
+xx(RETURN, 79, 0, 0, 0, IF, "return")
+xx(SIGNED, 80, 0, 0, 0, CHAR, "signed")
+xx(STATIC, 81, 0, 0, 0, STATIC, "static")
+xx(SWITCH, 82, 0, 0, 0, IF, "switch")
+xx(TYPEDEF, 83, 0, 0, 0, STATIC, "typedef")
+xx(WHILE, 84, 0, 0, 0, IF, "while")
+xx(TYPECODE, 85, 0, 0, 0, ID, "__typecode")
+xx(FIRSTARG, 86, 0, 0, 0, ID, "__firstarg")
+yy(0, 87, 0, 0, 0, 0, 0)
+yy(0, 88, 0, 0, 0, 0, 0)
+yy(0, 89, 0, 0, 0, 0, 0)
+yy(0, 90, 0, 0, 0, 0, 0)
+yy(0, 91, 0, 0, 0, '[', "[")
+yy(0, 92, 0, 0, 0, 0, 0)
+yy(0, 93, 0, 0, 0, ']', "]")
+yy(0, 94, 7, BXOR, bittree,'^', "^")
+yy(0, 95, 0, 0, 0, 0, 0)
+yy(0, 96, 0, 0, 0, 0, 0)
+yy(0, 97, 0, 0, 0, 0, 0)
+yy(0, 98, 0, 0, 0, 0, 0)
+yy(0, 99, 0, 0, 0, 0, 0)
+yy(0, 100, 0, 0, 0, 0, 0)
+yy(0, 101, 0, 0, 0, 0, 0)
+yy(0, 102, 0, 0, 0, 0, 0)
+yy(0, 103, 0, 0, 0, 0, 0)
+yy(0, 104, 0, 0, 0, 0, 0)
+yy(0, 105, 0, 0, 0, 0, 0)
+yy(0, 106, 0, 0, 0, 0, 0)
+yy(0, 107, 0, 0, 0, 0, 0)
+yy(0, 108, 0, 0, 0, 0, 0)
+yy(0, 109, 0, 0, 0, 0, 0)
+yy(0, 110, 0, 0, 0, 0, 0)
+yy(0, 111, 0, 0, 0, 0, 0)
+yy(0, 112, 0, 0, 0, 0, 0)
+yy(0, 113, 0, 0, 0, 0, 0)
+yy(0, 114, 0, 0, 0, 0, 0)
+yy(0, 115, 0, 0, 0, 0, 0)
+yy(0, 116, 0, 0, 0, 0, 0)
+yy(0, 117, 0, 0, 0, 0, 0)
+yy(0, 118, 0, 0, 0, 0, 0)
+yy(0, 119, 0, 0, 0, 0, 0)
+yy(0, 120, 0, 0, 0, 0, 0)
+yy(0, 121, 0, 0, 0, 0, 0)
+yy(0, 122, 0, 0, 0, 0, 0)
+yy(0, 123, 0, 0, 0, IF, "{")
+yy(0, 124, 6, BOR, bittree,'|', "|")
+yy(0, 125, 0, 0, 0, '}', "}")
+yy(0, 126, 0, BCOM, 0, ID, "~")
+xx(EOI, 127, 0, 0, 0, EOI, "end of input")
+#undef xx
+#undef yy
diff --git a/lcc/src/trace.c b/lcc/src/trace.c
new file mode 100755
index 0000000..55b18a1
--- /dev/null
+++ b/lcc/src/trace.c
@@ -0,0 +1,180 @@
+#include "c.h"
+
+
+static char *fmt, *fp, *fmtend; /* format string, current & limit pointer */
+static Tree args; /* printf arguments */
+static Symbol frameno; /* local holding frame number */
+
+/* appendstr - append str to the evolving format string, expanding it if necessary */
+static void appendstr(char *str) {
+ do
+ if (fp == fmtend)
+ if (fp) {
+ char *s = allocate(2*(fmtend - fmt), FUNC);
+ strncpy(s, fmt, fmtend - fmt);
+ fp = s + (fmtend - fmt);
+ fmtend = s + 2*(fmtend - fmt);
+ fmt = s;
+ } else {
+ fp = fmt = allocate(80, FUNC);
+ fmtend = fmt + 80;
+ }
+ while ((*fp++ = *str++) != 0);
+ fp--;
+}
+
+/* tracevalue - append format and argument to print the value of e */
+static void tracevalue(Tree e, int lev) {
+ Type ty = unqual(e->type);
+
+ switch (ty->op) {
+ case INT:
+ if (ty == chartype || ty == signedchar)
+ appendstr("'\\x%02x'");
+ else if (ty == longtype)
+ appendstr("0x%ld");
+ else
+ appendstr("0x%d");
+ break;
+ case UNSIGNED:
+ if (ty == chartype || ty == unsignedchar)
+ appendstr("'\\x%02x'");
+ else if (ty == unsignedlong)
+ appendstr("0x%lx");
+ else
+ appendstr("0x%x");
+ break;
+ case FLOAT:
+ if (ty == longdouble)
+ appendstr("%Lg");
+ else
+ appendstr("%g");
+ break;
+ case POINTER:
+ if (unqual(ty->type) == chartype
+ || unqual(ty->type) == signedchar
+ || unqual(ty->type) == unsignedchar) {
+ static Symbol null;
+ if (null == NULL)
+ null = mkstr("(null)");
+ tracevalue(cast(e, unsignedtype), lev + 1);
+ appendstr(" \"%.30s\"");
+ e = condtree(e, e, pointer(idtree(null->u.c.loc)));
+ } else {
+ appendstr("("); appendstr(typestring(ty, "")); appendstr(")0x%x");
+ }
+ break;
+ case STRUCT: {
+ Field q;
+ appendstr("("); appendstr(typestring(ty, "")); appendstr("){");
+ for (q = ty->u.sym->u.s.flist; q; q = q->link) {
+ appendstr(q->name); appendstr("=");
+ tracevalue(field(addrof(e), q->name), lev + 1);
+ if (q->link)
+ appendstr(",");
+ }
+ appendstr("}");
+ return;
+ }
+ case UNION:
+ appendstr("("); appendstr(typestring(ty, "")); appendstr("){...}");
+ return;
+ case ARRAY:
+ if (lev && ty->type->size > 0) {
+ int i;
+ e = pointer(e);
+ appendstr("{");
+ for (i = 0; i < ty->size/ty->type->size; i++) {
+ Tree p = (*optree['+'])(ADD, e, consttree(i, inttype));
+ if (isptr(p->type) && isarray(p->type->type))
+ p = retype(p, p->type->type);
+ else
+ p = rvalue(p);
+ if (i)
+ appendstr(",");
+ tracevalue(p, lev + 1);
+ }
+ appendstr("}");
+ } else
+ appendstr(typestring(ty, ""));
+ return;
+ default:
+ assert(0);
+ }
+ e = cast(e, promote(ty));
+ args = tree(mkop(ARG,e->type), e->type, e, args);
+}
+
+/* tracefinis - complete & generate the trace call to print */
+static void tracefinis(Symbol printer) {
+ Tree *ap;
+ Symbol p;
+
+ *fp = 0;
+ p = mkstr(string(fmt));
+ for (ap = &args; *ap; ap = &(*ap)->kids[1])
+ ;
+ *ap = tree(ARG+P, charptype, pointer(idtree(p->u.c.loc)), 0);
+ walk(calltree(pointer(idtree(printer)), freturn(printer->type), args, NULL), 0, 0);
+ args = 0;
+ fp = fmtend = 0;
+}
+
+/* tracecall - generate code to trace entry to f */
+static void tracecall(Symbol printer, Symbol f) {
+ int i;
+ Symbol counter = genident(STATIC, inttype, GLOBAL);
+
+ defglobal(counter, BSS);
+ (*IR->space)(counter->type->size);
+ frameno = genident(AUTO, inttype, level);
+ addlocal(frameno);
+ appendstr(f->name); appendstr("#");
+ tracevalue(asgn(frameno, incr(INCR, idtree(counter), consttree(1, inttype))), 0);
+ appendstr("(");
+ for (i = 0; f->u.f.callee[i]; i++) {
+ if (i)
+ appendstr(",");
+ appendstr(f->u.f.callee[i]->name); appendstr("=");
+ tracevalue(idtree(f->u.f.callee[i]), 0);
+ }
+ if (variadic(f->type))
+ appendstr(",...");
+ appendstr(") called\n");
+ tracefinis(printer);
+}
+
+/* tracereturn - generate code to trace return e */
+static void tracereturn(Symbol printer, Symbol f, Tree e) {
+ appendstr(f->name); appendstr("#");
+ tracevalue(idtree(frameno), 0);
+ appendstr(" returned");
+ if (freturn(f->type) != voidtype && e) {
+ appendstr(" ");
+ tracevalue(e, 0);
+ }
+ appendstr("\n");
+ tracefinis(printer);
+}
+
+/* trace_init - initialize for tracing */
+void trace_init(int argc, char *argv[]) {
+ int i;
+ static int inited;
+
+ if (inited)
+ return;
+ inited = 1;
+ type_init(argc, argv);
+ if (IR)
+ for (i = 1; i < argc; i++)
+ if (strncmp(argv[i], "-t", 2) == 0 && strchr(argv[i], '=') == NULL) {
+ Symbol printer = mksymbol(EXTERN,
+ argv[i][2] ? &argv[i][2] : "printf",
+ ftype(inttype, ptr(qual(CONST, chartype))));
+ printer->defined = 0;
+ attach((Apply)tracecall, printer, &events.entry);
+ attach((Apply)tracereturn, printer, &events.returns);
+ break;
+ }
+}
diff --git a/lcc/src/tree.c b/lcc/src/tree.c
new file mode 100755
index 0000000..1f5b49c
--- /dev/null
+++ b/lcc/src/tree.c
@@ -0,0 +1,223 @@
+#include "c.h"
+
+
+int where = STMT;
+static int warn;
+static int nid = 1; /* identifies trees & nodes in debugging output */
+static struct nodeid {
+ int printed;
+ Tree node;
+} ids[500]; /* if ids[i].node == p, then p's id is i */
+
+static void printtree1(Tree, int, int);
+
+Tree tree(int op, Type type, Tree left, Tree right) {
+ Tree p;
+
+ NEW0(p, where);
+ p->op = op;
+ p->type = type;
+ p->kids[0] = left;
+ p->kids[1] = right;
+ return p;
+}
+
+Tree texpr(Tree (*f)(int), int tok, int a) {
+ int save = where;
+ Tree p;
+
+ where = a;
+ p = (*f)(tok);
+ where = save;
+ return p;
+}
+static Tree root1(Tree p) {
+ if (p == NULL)
+ return p;
+ if (p->type == voidtype)
+ warn++;
+ switch (generic(p->op)) {
+ case COND: {
+ Tree q = p->kids[1];
+ assert(q && q->op == RIGHT);
+ if (p->u.sym && q->kids[0] && generic(q->kids[0]->op) == ASGN)
+ q->kids[0] = root1(q->kids[0]->kids[1]);
+ else
+ q->kids[0] = root1(q->kids[0]);
+ if (p->u.sym && q->kids[1] && generic(q->kids[1]->op) == ASGN)
+ q->kids[1] = root1(q->kids[1]->kids[1]);
+ else
+ q->kids[1] = root1(q->kids[1]);
+ p->u.sym = 0;
+ if (q->kids[0] == 0 && q->kids[1] == 0)
+ p = root1(p->kids[0]);
+ }
+ break;
+ case AND: case OR:
+ if ((p->kids[1] = root1(p->kids[1])) == 0)
+ p = root1(p->kids[0]);
+ break;
+ case NOT:
+ if (warn++ == 0)
+ warning("expression with no effect elided\n");
+ return root1(p->kids[0]);
+ case RIGHT:
+ if (p->kids[1] == 0)
+ return root1(p->kids[0]);
+ if (p->kids[0] && p->kids[0]->op == CALL+B
+ && p->kids[1] && p->kids[1]->op == INDIR+B)
+ /* avoid premature release of the CALL+B temporary */
+ return p->kids[0];
+ if (p->kids[0] && p->kids[0]->op == RIGHT
+ && p->kids[1] == p->kids[0]->kids[0])
+ /* de-construct e++ construction */
+ return p->kids[0]->kids[1];
+ p = tree(RIGHT, p->type, root1(p->kids[0]), root1(p->kids[1]));
+ return p->kids[0] || p->kids[1] ? p : (Tree)0;
+ case EQ: case NE: case GT: case GE: case LE: case LT:
+ case ADD: case SUB: case MUL: case DIV: case MOD:
+ case LSH: case RSH: case BAND: case BOR: case BXOR:
+ if (warn++ == 0)
+ warning("expression with no effect elided\n");
+ p = tree(RIGHT, p->type, root1(p->kids[0]), root1(p->kids[1]));
+ return p->kids[0] || p->kids[1] ? p : (Tree)0;
+ case INDIR:
+ if (p->type->size == 0 && unqual(p->type) != voidtype)
+ warning("reference to `%t' elided\n", p->type);
+ if (isptr(p->kids[0]->type) && isvolatile(p->kids[0]->type->type))
+ warning("reference to `volatile %t' elided\n", p->type);
+ /* fall thru */
+ case CVI: case CVF: case CVU: case CVP:
+ case NEG: case BCOM: case FIELD:
+ if (warn++ == 0)
+ warning("expression with no effect elided\n");
+ return root1(p->kids[0]);
+ case ADDRL: case ADDRG: case ADDRF: case CNST:
+ if (needconst)
+ return p;
+ if (warn++ == 0)
+ warning("expression with no effect elided\n");
+ return NULL;
+ case ARG: case ASGN: case CALL: case JUMP: case LABEL:
+ break;
+ default: assert(0);
+ }
+ return p;
+}
+
+Tree root(Tree p) {
+ warn = 0;
+ return root1(p);
+}
+
+char *opname(int op) {
+ static char *opnames[] = {
+ "",
+ "CNST",
+ "ARG",
+ "ASGN",
+ "INDIR",
+ "CVC",
+ "CVD",
+ "CVF",
+ "CVI",
+ "CVP",
+ "CVS",
+ "CVU",
+ "NEG",
+ "CALL",
+ "*LOAD*",
+ "RET",
+ "ADDRG",
+ "ADDRF",
+ "ADDRL",
+ "ADD",
+ "SUB",
+ "LSH",
+ "MOD",
+ "RSH",
+ "BAND",
+ "BCOM",
+ "BOR",
+ "BXOR",
+ "DIV",
+ "MUL",
+ "EQ",
+ "GE",
+ "GT",
+ "LE",
+ "LT",
+ "NE",
+ "JUMP",
+ "LABEL",
+ "AND",
+ "NOT",
+ "OR",
+ "COND",
+ "RIGHT",
+ "FIELD"
+ }, *suffixes[] = {
+ "0", "F", "D", "C", "S", "I", "U", "P", "V", "B",
+ "10","11","12","13","14","15"
+ };
+
+ if (generic(op) >= AND && generic(op) <= FIELD && opsize(op) == 0)
+ return opnames[opindex(op)];
+ return stringf("%s%s%s",
+ opindex(op) > 0 && opindex(op) < NELEMS(opnames) ?
+ opnames[opindex(op)] : stringd(opindex(op)),
+ suffixes[optype(op)], opsize(op) > 0 ? stringd(opsize(op)) : "");
+}
+
+int nodeid(Tree p) {
+ int i = 1;
+
+ ids[nid].node = p;
+ while (ids[i].node != p)
+ i++;
+ if (i == nid)
+ ids[nid++].printed = 0;
+ return i;
+}
+
+/* printed - return pointer to ids[id].printed */
+int *printed(int id) {
+ if (id)
+ return &ids[id].printed;
+ nid = 1;
+ return 0;
+}
+
+/* printtree - print tree p on fd */
+void printtree(Tree p, int fd) {
+ (void)printed(0);
+ printtree1(p, fd, 1);
+}
+
+/* printtree1 - recursively print tree p */
+static void printtree1(Tree p, int fd, int lev) {
+ FILE *f = fd == 1 ? stdout : stderr;
+ int i;
+ static char blanks[] = " ";
+
+ if (p == 0 || *printed(i = nodeid(p)))
+ return;
+ fprint(f, "#%d%S%S", i, blanks, i < 10 ? 2 : i < 100 ? 1 : 0, blanks, lev);
+ fprint(f, "%s %t", opname(p->op), p->type);
+ *printed(i) = 1;
+ for (i = 0; i < NELEMS(p->kids); i++)
+ if (p->kids[i])
+ fprint(f, " #%d", nodeid(p->kids[i]));
+ if (p->op == FIELD && p->u.field)
+ fprint(f, " %s %d..%d", p->u.field->name,
+ fieldsize(p->u.field) + fieldright(p->u.field), fieldright(p->u.field));
+ else if (generic(p->op) == CNST)
+ fprint(f, " %s", vtoa(p->type, p->u.v));
+ else if (p->u.sym)
+ fprint(f, " %s", p->u.sym->name);
+ if (p->node)
+ fprint(f, " node=%p", p->node);
+ fprint(f, "\n");
+ for (i = 0; i < NELEMS(p->kids); i++)
+ printtree1(p->kids[i], fd, lev + 1);
+}
diff --git a/lcc/src/types.c b/lcc/src/types.c
new file mode 100755
index 0000000..eead3e1
--- /dev/null
+++ b/lcc/src/types.c
@@ -0,0 +1,748 @@
+#include "c.h"
+#include <float.h>
+
+
+static Field isfield(const char *, Field);
+static Type type(int, Type, int, int, void *);
+
+static struct entry {
+ struct type type;
+ struct entry *link;
+} *typetable[128];
+static int maxlevel;
+
+static Symbol pointersym;
+
+Type chartype; /* char */
+Type doubletype; /* double */
+Type floattype; /* float */
+Type inttype; /* signed int */
+Type longdouble; /* long double */
+Type longtype; /* long */
+Type longlong; /* long long */
+Type shorttype; /* signed short int */
+Type signedchar; /* signed char */
+Type unsignedchar; /* unsigned char */
+Type unsignedlong; /* unsigned long int */
+Type unsignedlonglong; /* unsigned long long int */
+Type unsignedshort; /* unsigned short int */
+Type unsignedtype; /* unsigned int */
+Type funcptype; /* void (*)() */
+Type charptype; /* char* */
+Type voidptype; /* void* */
+Type voidtype; /* basic types: void */
+Type unsignedptr; /* unsigned type to hold void* */
+Type signedptr; /* signed type to hold void* */
+Type widechar; /* unsigned type that represents wchar_t */
+
+static Type xxinit(int op, char *name, Metrics m) {
+ Symbol p = install(string(name), &types, GLOBAL, PERM);
+ Type ty = type(op, 0, m.size, m.align, p);
+
+ assert(ty->align == 0 || ty->size%ty->align == 0);
+ p->type = ty;
+ p->addressed = m.outofline;
+ switch (ty->op) {
+ case INT:
+ p->u.limits.max.i = ones(8*ty->size)>>1;
+ p->u.limits.min.i = -p->u.limits.max.i - 1;
+ break;
+ case UNSIGNED:
+ p->u.limits.max.u = ones(8*ty->size);
+ p->u.limits.min.u = 0;
+ break;
+ case FLOAT:
+ if (ty->size == sizeof (float))
+ p->u.limits.max.d = FLT_MAX;
+ else if (ty->size == sizeof (double))
+ p->u.limits.max.d = DBL_MAX;
+ else
+ p->u.limits.max.d = LDBL_MAX;
+ p->u.limits.min.d = -p->u.limits.max.d;
+ break;
+ default: assert(0);
+ }
+ return ty;
+}
+static Type type(int op, Type ty, int size, int align, void *sym) {
+ unsigned h = (op^((unsigned long)ty>>3))
+&(NELEMS(typetable)-1);
+ struct entry *tn;
+
+ if (op != FUNCTION && (op != ARRAY || size > 0))
+ for (tn = typetable[h]; tn; tn = tn->link)
+ if (tn->type.op == op && tn->type.type == ty
+ && tn->type.size == size && tn->type.align == align
+ && tn->type.u.sym == sym)
+ return &tn->type;
+ NEW0(tn, PERM);
+ tn->type.op = op;
+ tn->type.type = ty;
+ tn->type.size = size;
+ tn->type.align = align;
+ tn->type.u.sym = sym;
+ tn->link = typetable[h];
+ typetable[h] = tn;
+ return &tn->type;
+}
+void type_init(int argc, char *argv[]) {
+ static int inited;
+ int i;
+
+ if (inited)
+ return;
+ inited = 1;
+ if (!IR)
+ return;
+ for (i = 1; i < argc; i++) {
+ int size, align, outofline;
+ if (strncmp(argv[i], "-unsigned_char=", 15) == 0)
+ IR->unsigned_char = argv[i][15] - '0';
+#define xx(name) \
+ else if (sscanf(argv[i], "-" #name "=%d,%d,%d", &size, &align, &outofline) == 3) { \
+ IR->name.size = size; IR->name.align = align; \
+ IR->name.outofline = outofline; }
+ xx(charmetric)
+ xx(shortmetric)
+ xx(intmetric)
+ xx(longmetric)
+ xx(longlongmetric)
+ xx(floatmetric)
+ xx(doublemetric)
+ xx(longdoublemetric)
+ xx(ptrmetric)
+ xx(structmetric)
+#undef xx
+ }
+#define xx(v,name,op,metrics) v=xxinit(op,name,IR->metrics)
+ xx(chartype, "char", IR->unsigned_char ? UNSIGNED : INT,charmetric);
+ xx(doubletype, "double", FLOAT, doublemetric);
+ xx(floattype, "float", FLOAT, floatmetric);
+ xx(inttype, "int", INT, intmetric);
+ xx(longdouble, "long double", FLOAT, longdoublemetric);
+ xx(longtype, "long int", INT, longmetric);
+ xx(longlong, "long long int", INT, longlongmetric);
+ xx(shorttype, "short", INT, shortmetric);
+ xx(signedchar, "signed char", INT, charmetric);
+ xx(unsignedchar, "unsigned char", UNSIGNED,charmetric);
+ xx(unsignedlong, "unsigned long", UNSIGNED,longmetric);
+ xx(unsignedshort, "unsigned short", UNSIGNED,shortmetric);
+ xx(unsignedtype, "unsigned int", UNSIGNED,intmetric);
+ xx(unsignedlonglong,"unsigned long long",UNSIGNED,longlongmetric);
+#undef xx
+ {
+ Symbol p;
+ p = install(string("void"), &types, GLOBAL, PERM);
+ voidtype = type(VOID, NULL, 0, 0, p);
+ p->type = voidtype;
+ }
+ pointersym = install(string("T*"), &types, GLOBAL, PERM);
+ pointersym->addressed = IR->ptrmetric.outofline;
+ pointersym->u.limits.max.p = (void*)ones(8*IR->ptrmetric.size);
+ pointersym->u.limits.min.p = 0;
+ voidptype = ptr(voidtype);
+ funcptype = ptr(func(voidtype, NULL, 1));
+ charptype = ptr(chartype);
+#define xx(v,t) if (v==NULL && t->size==voidptype->size && t->align==voidptype->align) v=t
+ xx(unsignedptr,unsignedshort);
+ xx(unsignedptr,unsignedtype);
+ xx(unsignedptr,unsignedlong);
+ xx(unsignedptr,unsignedlonglong);
+ if (unsignedptr == NULL)
+ unsignedptr = type(UNSIGNED, NULL, voidptype->size, voidptype->align, voidptype->u.sym);
+ xx(signedptr,shorttype);
+ xx(signedptr,inttype);
+ xx(signedptr,longtype);
+ xx(signedptr,longlong);
+ if (signedptr == NULL)
+ signedptr = type(INT, NULL, voidptype->size, voidptype->align, voidptype->u.sym);
+#undef xx
+ widechar = unsignedshort;
+ for (i = 0; i < argc; i++) {
+#define xx(name,type) \
+ if (strcmp(argv[i], "-wchar_t=" #name) == 0) \
+ widechar = type;
+ xx(unsigned_char,unsignedchar)
+ xx(unsigned_int,unsignedtype)
+ xx(unsigned_short,unsignedshort)
+ }
+#undef xx
+}
+void rmtypes(int lev) {
+ if (maxlevel >= lev) {
+ int i;
+ maxlevel = 0;
+ for (i = 0; i < NELEMS(typetable); i++) {
+ struct entry *tn, **tq = &typetable[i];
+ while ((tn = *tq) != NULL)
+ if (tn->type.op == FUNCTION)
+ tq = &tn->link;
+ else if (tn->type.u.sym && tn->type.u.sym->scope >= lev)
+ *tq = tn->link;
+ else {
+ if (tn->type.u.sym && tn->type.u.sym->scope > maxlevel)
+ maxlevel = tn->type.u.sym->scope;
+ tq = &tn->link;
+ }
+
+ }
+ }
+}
+Type ptr(Type ty) {
+ return type(POINTER, ty, IR->ptrmetric.size,
+ IR->ptrmetric.align, pointersym);
+}
+Type deref(Type ty) {
+ if (isptr(ty))
+ ty = ty->type;
+ else
+ error("type error: %s\n", "pointer expected");
+ return isenum(ty) ? unqual(ty)->type : ty;
+}
+Type array(Type ty, int n, int a) {
+ assert(ty);
+ if (isfunc(ty)) {
+ error("illegal type `array of %t'\n", ty);
+ return array(inttype, n, 0);
+ }
+ if (isarray(ty) && ty->size == 0)
+ error("missing array size\n");
+ if (ty->size == 0) {
+ if (unqual(ty) == voidtype)
+ error("illegal type `array of %t'\n", ty);
+ else if (Aflag >= 2)
+ warning("declaring type array of %t' is undefined\n", ty);
+
+ } else if (n > INT_MAX/ty->size) {
+ error("size of `array of %t' exceeds %d bytes\n",
+ ty, INT_MAX);
+ n = 1;
+ }
+ return type(ARRAY, ty, n*ty->size,
+ a ? a : ty->align, NULL);
+}
+Type atop(Type ty) {
+ if (isarray(ty))
+ return ptr(ty->type);
+ error("type error: %s\n", "array expected");
+ return ptr(ty);
+}
+Type qual(int op, Type ty) {
+ if (isarray(ty))
+ ty = type(ARRAY, qual(op, ty->type), ty->size,
+ ty->align, NULL);
+ else if (isfunc(ty))
+ warning("qualified function type ignored\n");
+ else if (isconst(ty) && op == CONST
+ || isvolatile(ty) && op == VOLATILE)
+ error("illegal type `%k %t'\n", op, ty);
+ else {
+ if (isqual(ty)) {
+ op += ty->op;
+ ty = ty->type;
+ }
+ ty = type(op, ty, ty->size, ty->align, NULL);
+ }
+ return ty;
+}
+Type func(Type ty, Type *proto, int style) {
+ if (ty && (isarray(ty) || isfunc(ty)))
+ error("illegal return type `%t'\n", ty);
+ ty = type(FUNCTION, ty, 0, 0, NULL);
+ ty->u.f.proto = proto;
+ ty->u.f.oldstyle = style;
+ return ty;
+}
+Type freturn(Type ty) {
+ if (isfunc(ty))
+ return ty->type;
+ error("type error: %s\n", "function expected");
+ return inttype;
+}
+int variadic(Type ty) {
+ if (isfunc(ty) && ty->u.f.proto) {
+ int i;
+ for (i = 0; ty->u.f.proto[i]; i++)
+ ;
+ return i > 1 && ty->u.f.proto[i-1] == voidtype;
+ }
+ return 0;
+}
+Type newstruct(int op, char *tag) {
+ Symbol p;
+
+ assert(tag);
+ if (*tag == 0)
+ tag = stringd(genlabel(1));
+ else
+ if ((p = lookup(tag, types)) != NULL && (p->scope == level
+ || p->scope == PARAM && level == PARAM+1)) {
+ if (p->type->op == op && !p->defined)
+ return p->type;
+ error("redefinition of `%s' previously defined at %w\n",
+ p->name, &p->src);
+ }
+ p = install(tag, &types, level, PERM);
+ p->type = type(op, NULL, 0, 0, p);
+ if (p->scope > maxlevel)
+ maxlevel = p->scope;
+ p->src = src;
+ return p->type;
+}
+Field newfield(char *name, Type ty, Type fty) {
+ Field p, *q = &ty->u.sym->u.s.flist;
+
+ if (name == NULL)
+ name = stringd(genlabel(1));
+ for (p = *q; p; q = &p->link, p = *q)
+ if (p->name == name)
+ error("duplicate field name `%s' in `%t'\n",
+ name, ty);
+ NEW0(p, PERM);
+ *q = p;
+ p->name = name;
+ p->type = fty;
+ if (xref) { /* omit */
+ if (ty->u.sym->u.s.ftab == NULL) /* omit */
+ ty->u.sym->u.s.ftab = table(NULL, level); /* omit */
+ install(name, &ty->u.sym->u.s.ftab, 0, PERM)->src = src;/* omit */
+ } /* omit */
+ return p;
+}
+int eqtype(Type ty1, Type ty2, int ret) {
+ if (ty1 == ty2)
+ return 1;
+ if (ty1->op != ty2->op)
+ return 0;
+ switch (ty1->op) {
+ case ENUM: case UNION: case STRUCT:
+ case UNSIGNED: case INT: case FLOAT:
+ return 0;
+ case POINTER: return eqtype(ty1->type, ty2->type, 1);
+ case VOLATILE: case CONST+VOLATILE:
+ case CONST: return eqtype(ty1->type, ty2->type, 1);
+ case ARRAY: if (eqtype(ty1->type, ty2->type, 1)) {
+ if (ty1->size == ty2->size)
+ return 1;
+ if (ty1->size == 0 || ty2->size == 0)
+ return ret;
+ }
+ return 0;
+ case FUNCTION: if (eqtype(ty1->type, ty2->type, 1)) {
+ Type *p1 = ty1->u.f.proto, *p2 = ty2->u.f.proto;
+ if (p1 == p2)
+ return 1;
+ if (p1 && p2) {
+ for ( ; *p1 && *p2; p1++, p2++)
+ if (eqtype(unqual(*p1), unqual(*p2), 1) == 0)
+ return 0;
+ if (*p1 == NULL && *p2 == NULL)
+ return 1;
+ } else {
+ if (variadic(p1 ? ty1 : ty2))
+ return 0;
+ if (p1 == NULL)
+ p1 = p2;
+ for ( ; *p1; p1++) {
+ Type ty = unqual(*p1);
+ if (promote(ty) != (isenum(ty) ? ty->type : ty))
+ return 0;
+ }
+ return 1;
+ }
+ }
+ return 0;
+ }
+ assert(0); return 0;
+}
+Type promote(Type ty) {
+ ty = unqual(ty);
+ switch (ty->op) {
+ case ENUM:
+ return inttype;
+ case INT:
+ if (ty->size < inttype->size)
+ return inttype;
+ break;
+ case UNSIGNED:
+ if (ty->size < inttype->size)
+ return inttype;
+ if (ty->size < unsignedtype->size)
+ return unsignedtype;
+ break;
+ case FLOAT:
+ if (ty->size < doubletype->size)
+ return doubletype;
+ }
+ return ty;
+}
+Type signedint(Type ty) {
+ if (ty->op == INT)
+ return ty;
+ assert(ty->op == UNSIGNED);
+#define xx(t) if (ty->size == t->size) return t
+ xx(inttype);
+ xx(longtype);
+ xx(longlong);
+#undef xx
+ assert(0); return NULL;
+}
+Type compose(Type ty1, Type ty2) {
+ if (ty1 == ty2)
+ return ty1;
+ assert(ty1->op == ty2->op);
+ switch (ty1->op) {
+ case POINTER:
+ return ptr(compose(ty1->type, ty2->type));
+ case CONST+VOLATILE:
+ return qual(CONST, qual(VOLATILE,
+ compose(ty1->type, ty2->type)));
+ case CONST: case VOLATILE:
+ return qual(ty1->op, compose(ty1->type, ty2->type));
+ case ARRAY: { Type ty = compose(ty1->type, ty2->type);
+ if (ty1->size && (ty1->type->size && ty2->size == 0 || ty1->size == ty2->size))
+ return array(ty, ty1->size/ty1->type->size, ty1->align);
+ if (ty2->size && ty2->type->size && ty1->size == 0)
+ return array(ty, ty2->size/ty2->type->size, ty2->align);
+ return array(ty, 0, 0); }
+ case FUNCTION: { Type *p1 = ty1->u.f.proto, *p2 = ty2->u.f.proto;
+ Type ty = compose(ty1->type, ty2->type);
+ List tlist = NULL;
+ if (p1 == NULL && p2 == NULL)
+ return func(ty, NULL, 1);
+ if (p1 && p2 == NULL)
+ return func(ty, p1, ty1->u.f.oldstyle);
+ if (p2 && p1 == NULL)
+ return func(ty, p2, ty2->u.f.oldstyle);
+ for ( ; *p1 && *p2; p1++, p2++) {
+ Type ty = compose(unqual(*p1), unqual(*p2));
+ if (isconst(*p1) || isconst(*p2))
+ ty = qual(CONST, ty);
+ if (isvolatile(*p1) || isvolatile(*p2))
+ ty = qual(VOLATILE, ty);
+ tlist = append(ty, tlist);
+ }
+ assert(*p1 == NULL && *p2 == NULL);
+ return func(ty, ltov(&tlist, PERM), 0); }
+ }
+ assert(0); return NULL;
+}
+int ttob(Type ty) {
+ switch (ty->op) {
+ case CONST: case VOLATILE: case CONST+VOLATILE:
+ return ttob(ty->type);
+ case VOID: case INT: case UNSIGNED: case FLOAT:
+ return ty->op + sizeop(ty->size);
+ case POINTER:
+ return POINTER + sizeop(voidptype->size);
+ case FUNCTION:
+ return POINTER + sizeop(funcptype->size);
+ case ARRAY: case STRUCT: case UNION:
+ return STRUCT;
+ case ENUM:
+ return INT + sizeop(inttype->size);
+ }
+ assert(0); return INT;
+}
+Type btot(int op, int size) {
+#define xx(ty) if (size == (ty)->size) return ty;
+ switch (optype(op)) {
+ case F:
+ xx(floattype);
+ xx(doubletype);
+ xx(longdouble);
+ assert(0); return 0;
+ case I:
+ if (chartype->op == INT)
+ xx(chartype);
+ xx(signedchar);
+ xx(shorttype);
+ xx(inttype);
+ xx(longtype);
+ xx(longlong);
+ assert(0); return 0;
+ case U:
+ if (chartype->op == UNSIGNED)
+ xx(chartype);
+ xx(unsignedchar);
+ xx(unsignedshort);
+ xx(unsignedtype);
+ xx(unsignedlong);
+ xx(unsignedlonglong);
+ assert(0); return 0;
+ case P:
+ xx(voidptype);
+ xx(funcptype);
+ assert(0); return 0;
+ }
+#undef xx
+ assert(0); return 0;
+}
+int hasproto(Type ty) {
+ if (ty == 0)
+ return 1;
+ switch (ty->op) {
+ case CONST: case VOLATILE: case CONST+VOLATILE: case POINTER:
+ case ARRAY:
+ return hasproto(ty->type);
+ case FUNCTION:
+ return hasproto(ty->type) && ty->u.f.proto;
+ case STRUCT: case UNION:
+ case VOID: case FLOAT: case ENUM: case INT: case UNSIGNED:
+ return 1;
+ }
+ assert(0); return 0;
+}
+/* fieldlist - construct a flat list of fields in type ty */
+Field fieldlist(Type ty) {
+ return ty->u.sym->u.s.flist;
+}
+
+/* fieldref - find field name of type ty, return entry */
+Field fieldref(const char *name, Type ty) {
+ Field p = isfield(name, unqual(ty)->u.sym->u.s.flist);
+
+ if (p && xref) {
+ Symbol q;
+ assert(unqual(ty)->u.sym->u.s.ftab);
+ q = lookup(name, unqual(ty)->u.sym->u.s.ftab);
+ assert(q);
+ use(q, src);
+ }
+ return p;
+}
+
+/* ftype - return a function type for rty function (ty,...)' */
+Type ftype(Type rty, Type ty) {
+ List list = append(ty, NULL);
+
+ list = append(voidtype, list);
+ return func(rty, ltov(&list, PERM), 0);
+}
+
+/* isfield - if name is a field in flist, return pointer to the field structure */
+static Field isfield(const char *name, Field flist) {
+ for ( ; flist; flist = flist->link)
+ if (flist->name == name)
+ break;
+ return flist;
+}
+
+/* outtype - output type ty */
+void outtype(Type ty, FILE *f) {
+ switch (ty->op) {
+ case CONST+VOLATILE: case CONST: case VOLATILE:
+ fprint(f, "%k %t", ty->op, ty->type);
+ break;
+ case STRUCT: case UNION: case ENUM:
+ assert(ty->u.sym);
+ if (ty->size == 0)
+ fprint(f, "incomplete ");
+ assert(ty->u.sym->name);
+ if (*ty->u.sym->name >= '1' && *ty->u.sym->name <= '9') {
+ Symbol p = findtype(ty);
+ if (p == 0)
+ fprint(f, "%k defined at %w", ty->op, &ty->u.sym->src);
+ else
+ fprint(f, p->name);
+ } else {
+ fprint(f, "%k %s", ty->op, ty->u.sym->name);
+ if (ty->size == 0)
+ fprint(f, " defined at %w", &ty->u.sym->src);
+ }
+ break;
+ case VOID: case FLOAT: case INT: case UNSIGNED:
+ fprint(f, ty->u.sym->name);
+ break;
+ case POINTER:
+ fprint(f, "pointer to %t", ty->type);
+ break;
+ case FUNCTION:
+ fprint(f, "%t function", ty->type);
+ if (ty->u.f.proto && ty->u.f.proto[0]) {
+ int i;
+ fprint(f, "(%t", ty->u.f.proto[0]);
+ for (i = 1; ty->u.f.proto[i]; i++)
+ if (ty->u.f.proto[i] == voidtype)
+ fprint(f, ",...");
+ else
+ fprint(f, ",%t", ty->u.f.proto[i]);
+ fprint(f, ")");
+ } else if (ty->u.f.proto && ty->u.f.proto[0] == 0)
+ fprint(f, "(void)");
+
+ break;
+ case ARRAY:
+ if (ty->size > 0 && ty->type && ty->type->size > 0) {
+ fprint(f, "array %d", ty->size/ty->type->size);
+ while (ty->type && isarray(ty->type) && ty->type->type->size > 0) {
+ ty = ty->type;
+ fprint(f, ",%d", ty->size/ty->type->size);
+ }
+ } else
+ fprint(f, "incomplete array");
+ if (ty->type)
+ fprint(f, " of %t", ty->type);
+ break;
+ default: assert(0);
+ }
+}
+
+/* printdecl - output a C declaration for symbol p of type ty */
+void printdecl(Symbol p, Type ty) {
+ switch (p->sclass) {
+ case AUTO:
+ fprint(stderr, "%s;\n", typestring(ty, p->name));
+ break;
+ case STATIC: case EXTERN:
+ fprint(stderr, "%k %s;\n", p->sclass, typestring(ty, p->name));
+ break;
+ case TYPEDEF: case ENUM:
+ break;
+ default: assert(0);
+ }
+}
+
+/* printproto - output a prototype declaration for function p */
+void printproto(Symbol p, Symbol callee[]) {
+ if (p->type->u.f.proto)
+ printdecl(p, p->type);
+ else {
+ int i;
+ List list = 0;
+ if (callee[0] == 0)
+ list = append(voidtype, list);
+ else
+ for (i = 0; callee[i]; i++)
+ list = append(callee[i]->type, list);
+ printdecl(p, func(freturn(p->type), ltov(&list, PERM), 0));
+ }
+}
+
+/* prtype - print details of type ty on f with given indent */
+static void prtype(Type ty, FILE *f, int indent, unsigned mark) {
+ switch (ty->op) {
+ default:
+ fprint(f, "(%d %d %d [%p])", ty->op, ty->size, ty->align, ty->u.sym);
+ break;
+ case FLOAT: case INT: case UNSIGNED: case VOID:
+ fprint(f, "(%k %d %d [\"%s\"])", ty->op, ty->size, ty->align, ty->u.sym->name);
+ break;
+ case CONST+VOLATILE: case CONST: case VOLATILE: case POINTER: case ARRAY:
+ fprint(f, "(%k %d %d ", ty->op, ty->size, ty->align);
+ prtype(ty->type, f, indent+1, mark);
+ fprint(f, ")");
+ break;
+ case STRUCT: case UNION:
+ fprint(f, "(%k %d %d [\"%s\"]", ty->op, ty->size, ty->align, ty->u.sym->name);
+ if (ty->x.marked != mark) {
+ Field p;
+ ty->x.marked = mark;
+ for (p = ty->u.sym->u.s.flist; p; p = p->link) {
+ fprint(f, "\n%I", indent+1);
+ prtype(p->type, f, indent+1, mark);
+ fprint(f, " %s@%d", p->name, p->offset);
+ if (p->lsb)
+ fprint(f, ":%d..%d",
+ fieldsize(p) + fieldright(p), fieldright(p));
+ }
+ fprint(f, "\n%I", indent);
+ }
+ fprint(f, ")");
+ break;
+ case ENUM:
+ fprint(f, "(%k %d %d [\"%s\"]", ty->op, ty->size, ty->align, ty->u.sym->name);
+ if (ty->x.marked != mark) {
+ int i;
+ Symbol *p = ty->u.sym->u.idlist;
+ ty->x.marked = mark;
+ for (i = 0; p[i] != NULL; i++)
+ fprint(f, "%I%s=%d\n", indent+1, p[i]->name, p[i]->u.value);
+ }
+ fprint(f, ")");
+ break;
+ case FUNCTION:
+ fprint(f, "(%k %d %d ", ty->op, ty->size, ty->align);
+ prtype(ty->type, f, indent+1, mark);
+ if (ty->u.f.proto) {
+ int i;
+ fprint(f, "\n%I{", indent+1);
+ for (i = 0; ty->u.f.proto[i]; i++) {
+ if (i > 0)
+ fprint(f, "%I", indent+2);
+ prtype(ty->u.f.proto[i], f, indent+2, mark);
+ fprint(f, "\n");
+ }
+ fprint(f, "%I}", indent+1);
+ }
+ fprint(f, ")");
+ break;
+ }
+}
+
+/* printtype - print details of type ty on fd */
+void printtype(Type ty, int fd) {
+ static unsigned mark;
+ prtype(ty, fd == 1 ? stdout : stderr, 0, ++mark);
+ fprint(fd == 1 ? stdout : stderr, "\n");
+}
+
+/* typestring - return ty as C declaration for str, which may be "" */
+char *typestring(Type ty, char *str) {
+ for ( ; ty; ty = ty->type) {
+ Symbol p;
+ switch (ty->op) {
+ case CONST+VOLATILE: case CONST: case VOLATILE:
+ if (isptr(ty->type))
+ str = stringf("%k %s", ty->op, str);
+ else
+ return stringf("%k %s", ty->op, typestring(ty->type, str));
+ break;
+ case STRUCT: case UNION: case ENUM:
+ assert(ty->u.sym);
+ if ((p = findtype(ty)) != NULL)
+ return *str ? stringf("%s %s", p->name, str) : p->name;
+ if (*ty->u.sym->name >= '1' && *ty->u.sym->name <= '9')
+ warning("unnamed %k in prototype\n", ty->op);
+ if (*str)
+ return stringf("%k %s %s", ty->op, ty->u.sym->name, str);
+ else
+ return stringf("%k %s", ty->op, ty->u.sym->name);
+ case VOID: case FLOAT: case INT: case UNSIGNED:
+ return *str ? stringf("%s %s", ty->u.sym->name, str) : ty->u.sym->name;
+ case POINTER:
+ if (!ischar(ty->type) && (p = findtype(ty)) != NULL)
+ return *str ? stringf("%s %s", p->name, str) : p->name;
+ str = stringf(isarray(ty->type) || isfunc(ty->type) ? "(*%s)" : "*%s", str);
+ break;
+ case FUNCTION:
+ if ((p = findtype(ty)) != NULL)
+ return *str ? stringf("%s %s", p->name, str) : p->name;
+ if (ty->u.f.proto == 0)
+ str = stringf("%s()", str);
+ else if (ty->u.f.proto[0]) {
+ int i;
+ str = stringf("%s(%s", str, typestring(ty->u.f.proto[0], ""));
+ for (i = 1; ty->u.f.proto[i]; i++)
+ if (ty->u.f.proto[i] == voidtype)
+ str = stringf("%s, ...", str);
+ else
+ str = stringf("%s, %s", str, typestring(ty->u.f.proto[i], ""));
+ str = stringf("%s)", str);
+ } else
+ str = stringf("%s(void)", str);
+ break;
+ case ARRAY:
+ if ((p = findtype(ty)) != NULL)
+ return *str ? stringf("%s %s", p->name, str) : p->name;
+ if (ty->type && ty->type->size > 0)
+ str = stringf("%s[%d]", str, ty->size/ty->type->size);
+ else
+ str = stringf("%s[]", str);
+ break;
+ default: assert(0);
+ }
+ }
+ assert(0); return 0;
+}
+
diff --git a/lcc/src/x86.md b/lcc/src/x86.md
new file mode 100755
index 0000000..7e8b84f
--- /dev/null
+++ b/lcc/src/x86.md
@@ -0,0 +1,998 @@
+%{
+enum { EAX=0, ECX=1, EDX=2, EBX=3, ESI=6, EDI=7 };
+#include "c.h"
+#define NODEPTR_TYPE Node
+#define OP_LABEL(p) ((p)->op)
+#define LEFT_CHILD(p) ((p)->kids[0])
+#define RIGHT_CHILD(p) ((p)->kids[1])
+#define STATE_LABEL(p) ((p)->x.state)
+static void address(Symbol, Symbol, long);
+static void blkfetch(int, int, int, int);
+static void blkloop(int, int, int, int, int, int[]);
+static void blkstore(int, int, int, int);
+static void defaddress(Symbol);
+static void defconst(int, int, Value);
+static void defstring(int, char *);
+static void defsymbol(Symbol);
+static void doarg(Node);
+static void emit2(Node);
+static void export(Symbol);
+static void clobber(Node);
+static void function(Symbol, Symbol [], Symbol [], int);
+static void global(Symbol);
+static void import(Symbol);
+static void local(Symbol);
+static void progbeg(int, char **);
+static void progend(void);
+static void segment(int);
+static void space(int);
+static void target(Node);
+extern int ckstack(Node, int);
+extern int memop(Node);
+extern int sametree(Node, Node);
+static Symbol charreg[32], shortreg[32], intreg[32];
+static Symbol fltreg[32];
+
+static Symbol charregw, shortregw, intregw, fltregw;
+
+static int cseg;
+
+static Symbol quo, rem;
+
+%}
+%start stmt
+%term CNSTF4=4113
+%term CNSTF8=8209
+%term CNSTF16=16401
+%term CNSTI1=1045
+%term CNSTI2=2069
+%term CNSTI4=4117
+%term CNSTI8=8213
+%term CNSTP4=4119
+%term CNSTP8=8215
+%term CNSTU1=1046
+%term CNSTU2=2070
+%term CNSTU4=4118
+%term CNSTU8=8214
+
+%term ARGB=41
+%term ARGF4=4129
+%term ARGF8=8225
+%term ARGF16=16417
+%term ARGI4=4133
+%term ARGI8=8229
+%term ARGP4=4135
+%term ARGP8=8231
+%term ARGU4=4134
+%term ARGU8=8230
+
+%term ASGNB=57
+%term ASGNF4=4145
+%term ASGNF8=8241
+%term ASGNF16=16433
+%term ASGNI1=1077
+%term ASGNI2=2101
+%term ASGNI4=4149
+%term ASGNI8=8245
+%term ASGNP4=4151
+%term ASGNP8=8247
+%term ASGNU1=1078
+%term ASGNU2=2102
+%term ASGNU4=4150
+%term ASGNU8=8246
+
+%term INDIRB=73
+%term INDIRF4=4161
+%term INDIRF8=8257
+%term INDIRF16=16449
+%term INDIRI1=1093
+%term INDIRI2=2117
+%term INDIRI4=4165
+%term INDIRI8=8261
+%term INDIRP4=4167
+%term INDIRP8=8263
+%term INDIRU1=1094
+%term INDIRU2=2118
+%term INDIRU4=4166
+%term INDIRU8=8262
+
+%term CVFF4=4209
+%term CVFF8=8305
+%term CVFF16=16497
+%term CVFI4=4213
+%term CVFI8=8309
+
+%term CVIF4=4225
+%term CVIF8=8321
+%term CVIF16=16513
+%term CVII1=1157
+%term CVII2=2181
+%term CVII4=4229
+%term CVII8=8325
+%term CVIU1=1158
+%term CVIU2=2182
+%term CVIU4=4230
+%term CVIU8=8326
+
+%term CVPP4=4247
+%term CVPP8=8343
+%term CVPP16=16535
+%term CVPU4=4246
+%term CVPU8=8342
+
+%term CVUI1=1205
+%term CVUI2=2229
+%term CVUI4=4277
+%term CVUI8=8373
+%term CVUP4=4279
+%term CVUP8=8375
+%term CVUP16=16567
+%term CVUU1=1206
+%term CVUU2=2230
+%term CVUU4=4278
+%term CVUU8=8374
+
+%term NEGF4=4289
+%term NEGF8=8385
+%term NEGF16=16577
+%term NEGI4=4293
+%term NEGI8=8389
+
+%term CALLB=217
+%term CALLF4=4305
+%term CALLF8=8401
+%term CALLF16=16593
+%term CALLI4=4309
+%term CALLI8=8405
+%term CALLP4=4311
+%term CALLP8=8407
+%term CALLU4=4310
+%term CALLU8=8406
+%term CALLV=216
+
+%term RETF4=4337
+%term RETF8=8433
+%term RETF16=16625
+%term RETI4=4341
+%term RETI8=8437
+%term RETP4=4343
+%term RETP8=8439
+%term RETU4=4342
+%term RETU8=8438
+%term RETV=248
+
+%term ADDRGP4=4359
+%term ADDRGP8=8455
+
+%term ADDRFP4=4375
+%term ADDRFP8=8471
+
+%term ADDRLP4=4391
+%term ADDRLP8=8487
+
+%term ADDF4=4401
+%term ADDF8=8497
+%term ADDF16=16689
+%term ADDI4=4405
+%term ADDI8=8501
+%term ADDP4=4407
+%term ADDP8=8503
+%term ADDU4=4406
+%term ADDU8=8502
+
+%term SUBF4=4417
+%term SUBF8=8513
+%term SUBF16=16705
+%term SUBI4=4421
+%term SUBI8=8517
+%term SUBP4=4423
+%term SUBP8=8519
+%term SUBU4=4422
+%term SUBU8=8518
+
+%term LSHI4=4437
+%term LSHI8=8533
+%term LSHU4=4438
+%term LSHU8=8534
+
+%term MODI4=4453
+%term MODI8=8549
+%term MODU4=4454
+%term MODU8=8550
+
+%term RSHI4=4469
+%term RSHI8=8565
+%term RSHU4=4470
+%term RSHU8=8566
+
+%term BANDI4=4485
+%term BANDI8=8581
+%term BANDU4=4486
+%term BANDU8=8582
+
+%term BCOMI4=4501
+%term BCOMI8=8597
+%term BCOMU4=4502
+%term BCOMU8=8598
+
+%term BORI4=4517
+%term BORI8=8613
+%term BORU4=4518
+%term BORU8=8614
+
+%term BXORI4=4533
+%term BXORI8=8629
+%term BXORU4=4534
+%term BXORU8=8630
+
+%term DIVF4=4545
+%term DIVF8=8641
+%term DIVF16=16833
+%term DIVI4=4549
+%term DIVI8=8645
+%term DIVU4=4550
+%term DIVU8=8646
+
+%term MULF4=4561
+%term MULF8=8657
+%term MULF16=16849
+%term MULI4=4565
+%term MULI8=8661
+%term MULU4=4566
+%term MULU8=8662
+
+%term EQF4=4577
+%term EQF8=8673
+%term EQF16=16865
+%term EQI4=4581
+%term EQI8=8677
+%term EQU4=4582
+%term EQU8=8678
+
+%term GEF4=4593
+%term GEF8=8689
+%term GEI4=4597
+%term GEI8=8693
+%term GEI16=16885
+%term GEU4=4598
+%term GEU8=8694
+
+%term GTF4=4609
+%term GTF8=8705
+%term GTF16=16897
+%term GTI4=4613
+%term GTI8=8709
+%term GTU4=4614
+%term GTU8=8710
+
+%term LEF4=4625
+%term LEF8=8721
+%term LEF16=16913
+%term LEI4=4629
+%term LEI8=8725
+%term LEU4=4630
+%term LEU8=8726
+
+%term LTF4=4641
+%term LTF8=8737
+%term LTF16=16929
+%term LTI4=4645
+%term LTI8=8741
+%term LTU4=4646
+%term LTU8=8742
+
+%term NEF4=4657
+%term NEF8=8753
+%term NEF16=16945
+%term NEI4=4661
+%term NEI8=8757
+%term NEU4=4662
+%term NEU8=8758
+
+%term JUMPV=584
+
+%term LABELV=600
+
+%term LOADB=233
+%term LOADF4=4321
+%term LOADF8=8417
+%term LOADF16=16609
+%term LOADI1=1253
+%term LOADI2=2277
+%term LOADI4=4325
+%term LOADI8=8421
+%term LOADP4=4327
+%term LOADP8=8423
+%term LOADU1=1254
+%term LOADU2=2278
+%term LOADU4=4326
+%term LOADU8=8422
+
+%term VREGP=711
+%%
+reg: INDIRI1(VREGP) "# read register\n"
+reg: INDIRU1(VREGP) "# read register\n"
+
+reg: INDIRI2(VREGP) "# read register\n"
+reg: INDIRU2(VREGP) "# read register\n"
+
+reg: INDIRF4(VREGP) "# read register\n"
+reg: INDIRI4(VREGP) "# read register\n"
+reg: INDIRP4(VREGP) "# read register\n"
+reg: INDIRU4(VREGP) "# read register\n"
+
+reg: INDIRF8(VREGP) "# read register\n"
+reg: INDIRI8(VREGP) "# read register\n"
+reg: INDIRP8(VREGP) "# read register\n"
+reg: INDIRU8(VREGP) "# read register\n"
+
+stmt: ASGNI1(VREGP,reg) "# write register\n"
+stmt: ASGNU1(VREGP,reg) "# write register\n"
+
+stmt: ASGNI2(VREGP,reg) "# write register\n"
+stmt: ASGNU2(VREGP,reg) "# write register\n"
+
+stmt: ASGNF4(VREGP,reg) "# write register\n"
+stmt: ASGNI4(VREGP,reg) "# write register\n"
+stmt: ASGNP4(VREGP,reg) "# write register\n"
+stmt: ASGNU4(VREGP,reg) "# write register\n"
+
+stmt: ASGNF8(VREGP,reg) "# write register\n"
+stmt: ASGNI8(VREGP,reg) "# write register\n"
+stmt: ASGNP8(VREGP,reg) "# write register\n"
+stmt: ASGNU8(VREGP,reg) "# write register\n"
+con: CNSTI1 "%a"
+con: CNSTU1 "%a"
+
+con: CNSTI2 "%a"
+con: CNSTU2 "%a"
+
+con: CNSTI4 "%a"
+con: CNSTU4 "%a"
+con: CNSTP4 "%a"
+
+con: CNSTI8 "%a"
+con: CNSTU8 "%a"
+con: CNSTP8 "%a"
+stmt: reg ""
+acon: ADDRGP4 "(%a)"
+acon: con "(%0)"
+base: ADDRGP4 "(%a)"
+base: reg "[%0]"
+base: ADDI4(reg,acon) "%1[%0]"
+base: ADDP4(reg,acon) "%1[%0]"
+base: ADDU4(reg,acon) "%1[%0]"
+base: ADDRFP4 "(%a)[ebp]"
+base: ADDRLP4 "(%a)[ebp]"
+index: reg "%0"
+index: LSHI4(reg,con1) "%0*2"
+index: LSHI4(reg,con2) "%0*4"
+index: LSHI4(reg,con3) "%0*8"
+
+con1: CNSTI4 "1" range(a, 1, 1)
+con1: CNSTU4 "1" range(a, 1, 1)
+con2: CNSTI4 "2" range(a, 2, 2)
+con2: CNSTU4 "2" range(a, 2, 2)
+con3: CNSTI4 "3" range(a, 3, 3)
+con3: CNSTU4 "3" range(a, 3, 3)
+index: LSHU4(reg,con1) "%0*2"
+index: LSHU4(reg,con2) "%0*4"
+index: LSHU4(reg,con3) "%0*8"
+addr: base "%0"
+addr: ADDI4(index,base) "%1[%0]"
+addr: ADDP4(index,base) "%1[%0]"
+addr: ADDU4(index,base) "%1[%0]"
+addr: index "[%0]"
+mem: INDIRI1(addr) "byte ptr %0"
+mem: INDIRI2(addr) "word ptr %0"
+mem: INDIRI4(addr) "dword ptr %0"
+mem: INDIRU1(addr) "byte ptr %0"
+mem: INDIRU2(addr) "word ptr %0"
+mem: INDIRU4(addr) "dword ptr %0"
+mem: INDIRP4(addr) "dword ptr %0"
+rc: reg "%0"
+rc: con "%0"
+
+mr: reg "%0"
+mr: mem "%0"
+
+mrc0: mem "%0"
+mrc0: rc "%0"
+mrc1: mem "%0" 1
+mrc1: rc "%0"
+
+mrc3: mem "%0" 3
+mrc3: rc "%0"
+reg: addr "lea %c,%0\n" 1
+reg: mrc0 "mov %c,%0\n" 1
+reg: LOADI1(reg) "# move\n" 1
+reg: LOADI2(reg) "# move\n" 1
+reg: LOADI4(reg) "# move\n" move(a)
+reg: LOADU1(reg) "# move\n" 1
+reg: LOADU2(reg) "# move\n" 1
+reg: LOADU4(reg) "# move\n" move(a)
+reg: LOADP4(reg) "# move\n" move(a)
+reg: ADDI4(reg,mrc1) "?mov %c,%0\nadd %c,%1\n" 1
+reg: ADDP4(reg,mrc1) "?mov %c,%0\nadd %c,%1\n" 1
+reg: ADDU4(reg,mrc1) "?mov %c,%0\nadd %c,%1\n" 1
+reg: SUBI4(reg,mrc1) "?mov %c,%0\nsub %c,%1\n" 1
+reg: SUBP4(reg,mrc1) "?mov %c,%0\nsub %c,%1\n" 1
+reg: SUBU4(reg,mrc1) "?mov %c,%0\nsub %c,%1\n" 1
+reg: BANDI4(reg,mrc1) "?mov %c,%0\nand %c,%1\n" 1
+reg: BORI4(reg,mrc1) "?mov %c,%0\nor %c,%1\n" 1
+reg: BXORI4(reg,mrc1) "?mov %c,%0\nxor %c,%1\n" 1
+reg: BANDU4(reg,mrc1) "?mov %c,%0\nand %c,%1\n" 1
+reg: BORU4(reg,mrc1) "?mov %c,%0\nor %c,%1\n" 1
+reg: BXORU4(reg,mrc1) "?mov %c,%0\nxor %c,%1\n" 1
+stmt: ASGNI4(addr,ADDI4(mem,con1)) "inc %1\n" memop(a)
+stmt: ASGNI4(addr,ADDU4(mem,con1)) "inc %1\n" memop(a)
+stmt: ASGNP4(addr,ADDP4(mem,con1)) "inc %1\n" memop(a)
+stmt: ASGNI4(addr,SUBI4(mem,con1)) "dec %1\n" memop(a)
+stmt: ASGNI4(addr,SUBU4(mem,con1)) "dec %1\n" memop(a)
+stmt: ASGNP4(addr,SUBP4(mem,con1)) "dec %1\n" memop(a)
+stmt: ASGNI4(addr,ADDI4(mem,rc)) "add %1,%2\n" memop(a)
+stmt: ASGNI4(addr,SUBI4(mem,rc)) "sub %1,%2\n" memop(a)
+stmt: ASGNU4(addr,ADDU4(mem,rc)) "add %1,%2\n" memop(a)
+stmt: ASGNU4(addr,SUBU4(mem,rc)) "sub %1,%2\n" memop(a)
+
+stmt: ASGNI4(addr,BANDI4(mem,rc)) "and %1,%2\n" memop(a)
+stmt: ASGNI4(addr,BORI4(mem,rc)) "or %1,%2\n" memop(a)
+stmt: ASGNI4(addr,BXORI4(mem,rc)) "xor %1,%2\n" memop(a)
+stmt: ASGNU4(addr,BANDU4(mem,rc)) "and %1,%2\n" memop(a)
+stmt: ASGNU4(addr,BORU4(mem,rc)) "or %1,%2\n" memop(a)
+stmt: ASGNU4(addr,BXORU4(mem,rc)) "xor %1,%2\n" memop(a)
+reg: BCOMI4(reg) "?mov %c,%0\nnot %c\n" 2
+reg: BCOMU4(reg) "?mov %c,%0\nnot %c\n" 2
+reg: NEGI4(reg) "?mov %c,%0\nneg %c\n" 2
+
+stmt: ASGNI4(addr,BCOMI4(mem)) "not %1\n" memop(a)
+stmt: ASGNU4(addr,BCOMU4(mem)) "not %1\n" memop(a)
+stmt: ASGNI4(addr,NEGI4(mem)) "neg %1\n" memop(a)
+reg: LSHI4(reg,con5) "?mov %c,%0\nsal %c,%1\n" 2
+reg: LSHU4(reg,con5) "?mov %c,%0\nshl %c,%1\n" 2
+reg: RSHI4(reg,con5) "?mov %c,%0\nsar %c,%1\n" 2
+reg: RSHU4(reg,con5) "?mov %c,%0\nshr %c,%1\n" 2
+
+stmt: ASGNI4(addr,LSHI4(mem,con5)) "sal %1,%2\n" memop(a)
+stmt: ASGNI4(addr,LSHU4(mem,con5)) "shl %1,%2\n" memop(a)
+stmt: ASGNI4(addr,RSHI4(mem,con5)) "sar %1,%2\n" memop(a)
+stmt: ASGNI4(addr,RSHU4(mem,con5)) "shr %1,%2\n" memop(a)
+
+con5: CNSTI4 "%a" range(a, 0, 31)
+
+reg: LSHI4(reg,reg) "?mov %c,%0\nmov ecx,%1\nsal %c,cl\n" 3
+reg: LSHU4(reg,reg) "?mov %c,%0\nmov ecx,%1\nshl %c,cl\n" 2
+reg: RSHI4(reg,reg) "?mov %c,%0\nmov ecx,%1\nsar %c,cl\n" 2
+reg: RSHU4(reg,reg) "?mov %c,%0\nmov ecx,%1\nshr %c,cl\n" 2
+reg: MULI4(reg,mrc3) "?mov %c,%0\nimul %c,%1\n" 14
+reg: MULI4(con,mr) "imul %c,%1,%0\n" 13
+reg: MULU4(reg,mr) "mul %1\n" 13
+reg: DIVU4(reg,reg) "xor edx,edx\ndiv %1\n"
+reg: MODU4(reg,reg) "xor edx,edx\ndiv %1\n"
+reg: DIVI4(reg,reg) "cdq\nidiv %1\n"
+reg: MODI4(reg,reg) "cdq\nidiv %1\n"
+reg: CVPU4(reg) "mov %c,%0\n" move(a)
+reg: CVUP4(reg) "mov %c,%0\n" move(a)
+reg: CVII4(INDIRI1(addr)) "movsx %c,byte ptr %0\n" 3
+reg: CVII4(INDIRI2(addr)) "movsx %c,word ptr %0\n" 3
+reg: CVUU4(INDIRU1(addr)) "movzx %c,byte ptr %0\n" 3
+reg: CVUU4(INDIRU2(addr)) "movzx %c,word ptr %0\n" 3
+reg: CVII4(reg) "# extend\n" 3
+reg: CVIU4(reg) "# extend\n" 3
+reg: CVUI4(reg) "# extend\n" 3
+reg: CVUU4(reg) "# extend\n" 3
+
+reg: CVII1(reg) "# truncate\n" 1
+reg: CVII2(reg) "# truncate\n" 1
+reg: CVUU1(reg) "# truncate\n" 1
+reg: CVUU2(reg) "# truncate\n" 1
+stmt: ASGNI1(addr,rc) "mov byte ptr %0,%1\n" 1
+stmt: ASGNI2(addr,rc) "mov word ptr %0,%1\n" 1
+stmt: ASGNI4(addr,rc) "mov dword ptr %0,%1\n" 1
+stmt: ASGNU1(addr,rc) "mov byte ptr %0,%1\n" 1
+stmt: ASGNU2(addr,rc) "mov word ptr %0,%1\n" 1
+stmt: ASGNU4(addr,rc) "mov dword ptr %0,%1\n" 1
+stmt: ASGNP4(addr,rc) "mov dword ptr %0,%1\n" 1
+stmt: ARGI4(mrc3) "push %0\n" 1
+stmt: ARGU4(mrc3) "push %0\n" 1
+stmt: ARGP4(mrc3) "push %0\n" 1
+stmt: ASGNB(reg,INDIRB(reg)) "mov ecx,%a\nrep movsb\n"
+stmt: ARGB(INDIRB(reg)) "sub esp,%a\nmov edi,esp\nmov ecx,%a\nrep movsb\n"
+
+memf: INDIRF8(addr) "qword ptr %0"
+memf: INDIRF4(addr) "dword ptr %0"
+memf: CVFF8(INDIRF4(addr)) "dword ptr %0"
+reg: memf "fld %0\n" 3
+stmt: ASGNF8(addr,reg) "fstp qword ptr %0\n" 7
+stmt: ASGNF4(addr,reg) "fstp dword ptr %0\n" 7
+stmt: ASGNF4(addr,CVFF4(reg)) "fstp dword ptr %0\n" 7
+stmt: ARGF8(reg) "sub esp,8\nfstp qword ptr [esp]\n"
+stmt: ARGF4(reg) "sub esp,4\nfstp dword ptr [esp]\n"
+reg: NEGF8(reg) "fchs\n"
+reg: NEGF4(reg) "fchs\n"
+flt: memf " %0"
+flt: reg "p st(1),st"
+reg: ADDF8(reg,flt) "fadd%1\n"
+reg: ADDF4(reg,flt) "fadd%1\n"
+reg: DIVF8(reg,flt) "fdiv%1\n"
+reg: DIVF4(reg,flt) "fdiv%1\n"
+reg: MULF8(reg,flt) "fmul%1\n"
+reg: MULF4(reg,flt) "fmul%1\n"
+reg: SUBF8(reg,flt) "fsub%1\n"
+reg: SUBF4(reg,flt) "fsub%1\n"
+reg: CVFF8(reg) "# CVFF8\n"
+reg: CVFF4(reg) "sub esp,4\nfstp dword ptr 0[esp]\nfld dword ptr 0[esp]\nadd esp,4\n" 12
+
+reg: CVFI4(reg) "call __ftol\n" 31
+reg: CVIF8(INDIRI4(addr)) "fild dword ptr %0\n" 10
+reg: CVIF4(reg) "push %0\nfild dword ptr 0[esp]\nadd esp,4\n" 12
+
+reg: CVIF8(reg) "push %0\nfild dword ptr 0[esp]\nadd esp,4\n" 12
+
+addrj: ADDRGP4 "%a"
+addrj: reg "%0" 2
+addrj: mem "%0" 2
+
+stmt: JUMPV(addrj) "jmp %0\n" 3
+stmt: LABELV "%a:\n"
+stmt: EQI4(mem,rc) "cmp %0,%1\nje %a\n" 5
+stmt: GEI4(mem,rc) "cmp %0,%1\njge %a\n" 5
+stmt: GTI4(mem,rc) "cmp %0,%1\njg %a\n" 5
+stmt: LEI4(mem,rc) "cmp %0,%1\njle %a\n" 5
+stmt: LTI4(mem,rc) "cmp %0,%1\njl %a\n" 5
+stmt: NEI4(mem,rc) "cmp %0,%1\njne %a\n" 5
+stmt: GEU4(mem,rc) "cmp %0,%1\njae %a\n" 5
+stmt: GTU4(mem,rc) "cmp %0,%1\nja %a\n" 5
+stmt: LEU4(mem,rc) "cmp %0,%1\njbe %a\n" 5
+stmt: LTU4(mem,rc) "cmp %0,%1\njb %a\n" 5
+stmt: EQI4(reg,mrc1) "cmp %0,%1\nje %a\n" 4
+stmt: GEI4(reg,mrc1) "cmp %0,%1\njge %a\n" 4
+stmt: GTI4(reg,mrc1) "cmp %0,%1\njg %a\n" 4
+stmt: LEI4(reg,mrc1) "cmp %0,%1\njle %a\n" 4
+stmt: LTI4(reg,mrc1) "cmp %0,%1\njl %a\n" 4
+stmt: NEI4(reg,mrc1) "cmp %0,%1\njne %a\n" 4
+
+stmt: EQU4(reg,mrc1) "cmp %0,%1\nje %a\n" 4
+stmt: GEU4(reg,mrc1) "cmp %0,%1\njae %a\n" 4
+stmt: GTU4(reg,mrc1) "cmp %0,%1\nja %a\n" 4
+stmt: LEU4(reg,mrc1) "cmp %0,%1\njbe %a\n" 4
+stmt: LTU4(reg,mrc1) "cmp %0,%1\njb %a\n" 4
+stmt: NEU4(reg,mrc1) "cmp %0,%1\njne %a\n" 4
+cmpf: memf " %0"
+cmpf: reg "p"
+stmt: EQF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\nje %a\n"
+stmt: GEF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njbe %a\n"
+stmt: GTF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njb %a\n"
+stmt: LEF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njae %a\n"
+stmt: LTF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\nja %a\n"
+stmt: NEF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njne %a\n"
+
+stmt: EQF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\nje %a\n"
+stmt: GEF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njbe %a\n"
+stmt: GTF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njb %a\n"
+stmt: LEF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njae %a\n"
+stmt: LTF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\nja %a\n"
+stmt: NEF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njne %a\n"
+reg: CALLI4(addrj) "call %0\nadd esp,%a\n"
+reg: CALLU4(addrj) "call %0\nadd esp,%a\n"
+reg: CALLP4(addrj) "call %0\nadd esp,%a\n"
+stmt: CALLV(addrj) "call %0\nadd esp,%a\n"
+reg: CALLF4(addrj) "call %0\nadd esp,%a\n"
+reg: CALLF8(addrj) "call %0\nadd esp,%a\n"
+stmt: CALLF4(addrj) "call %0\nadd esp,%a\nfstp\n"
+stmt: CALLF8(addrj) "call %0\nadd esp,%a\nfstp\n"
+
+stmt: RETI4(reg) "# ret\n"
+stmt: RETU4(reg) "# ret\n"
+stmt: RETP4(reg) "# ret\n"
+stmt: RETF4(reg) "# ret\n"
+stmt: RETF8(reg) "# ret\n"
+%%
+static void progbeg(int argc, char *argv[]) {
+ int i;
+
+ {
+ union {
+ char c;
+ int i;
+ } u;
+ u.i = 0;
+ u.c = 1;
+ swap = ((int)(u.i == 1)) != IR->little_endian;
+ }
+ parseflags(argc, argv);
+ intreg[EAX] = mkreg("eax", EAX, 1, IREG);
+ intreg[EDX] = mkreg("edx", EDX, 1, IREG);
+ intreg[ECX] = mkreg("ecx", ECX, 1, IREG);
+ intreg[EBX] = mkreg("ebx", EBX, 1, IREG);
+ intreg[ESI] = mkreg("esi", ESI, 1, IREG);
+ intreg[EDI] = mkreg("edi", EDI, 1, IREG);
+
+ shortreg[EAX] = mkreg("ax", EAX, 1, IREG);
+ shortreg[ECX] = mkreg("cx", ECX, 1, IREG);
+ shortreg[EDX] = mkreg("dx", EDX, 1, IREG);
+ shortreg[EBX] = mkreg("bx", EBX, 1, IREG);
+ shortreg[ESI] = mkreg("si", ESI, 1, IREG);
+ shortreg[EDI] = mkreg("di", EDI, 1, IREG);
+
+ charreg[EAX] = mkreg("al", EAX, 1, IREG);
+ charreg[ECX] = mkreg("cl", ECX, 1, IREG);
+ charreg[EDX] = mkreg("dl", EDX, 1, IREG);
+ charreg[EBX] = mkreg("bl", EBX, 1, IREG);
+ for (i = 0; i < 8; i++)
+ fltreg[i] = mkreg("%d", i, 0, FREG);
+ charregw = mkwildcard(charreg);
+ shortregw = mkwildcard(shortreg);
+ intregw = mkwildcard(intreg);
+ fltregw = mkwildcard(fltreg);
+
+ tmask[IREG] = (1<<EDI) | (1<<ESI) | (1<<EBX)
+ | (1<<EDX) | (1<<ECX) | (1<<EAX);
+ vmask[IREG] = 0;
+ tmask[FREG] = 0xff;
+ vmask[FREG] = 0;
+ print(".486\n");
+ print(".model flat\n");
+ print("extrn __fltused:near\n");
+ print("extrn __ftol:near\n");
+ cseg = 0;
+ quo = mkreg("eax", EAX, 1, IREG);
+ quo->x.regnode->mask |= 1<<EDX;
+ rem = mkreg("edx", EDX, 1, IREG);
+ rem->x.regnode->mask |= 1<<EAX;
+}
+static Symbol rmap(int opk) {
+ switch (optype(opk)) {
+ case B: case P:
+ return intregw;
+ case I: case U:
+ if (opsize(opk) == 1)
+ return charregw;
+ else if (opsize(opk) == 2)
+ return shortregw;
+ else
+ return intregw;
+ case F:
+ return fltregw;
+ default:
+ return 0;
+ }
+}
+static void segment(int n) {
+ if (n == cseg)
+ return;
+ if (cseg == CODE || cseg == LIT)
+ print("_TEXT ends\n");
+ else if (cseg == DATA || cseg == BSS)
+ print("_DATA ends\n");
+ cseg = n;
+ if (cseg == CODE || cseg == LIT)
+ print("_TEXT segment\n");
+ else if (cseg == DATA || cseg == BSS)
+ print("_DATA segment\n");
+}
+static void progend(void) {
+ segment(0);
+ print("end\n");
+}
+static void target(Node p) {
+ assert(p);
+ switch (specific(p->op)) {
+ case MUL+U:
+ setreg(p, quo);
+ rtarget(p, 0, intreg[EAX]);
+ break;
+ case DIV+I: case DIV+U:
+ setreg(p, quo);
+ rtarget(p, 0, quo);
+ break;
+ case MOD+I: case MOD+U:
+ setreg(p, rem);
+ rtarget(p, 0, quo);
+ break;
+ case ASGN+B:
+ rtarget(p, 0, intreg[EDI]);
+ rtarget(p->kids[1], 0, intreg[ESI]);
+ break;
+ case ARG+B:
+ rtarget(p->kids[0], 0, intreg[ESI]);
+ break;
+ case CVF+I:
+ setreg(p, intreg[EAX]);
+ break;
+ case CALL+I: case CALL+U: case CALL+P: case CALL+V:
+ setreg(p, intreg[EAX]);
+ break;
+ case RET+I: case RET+U: case RET+P:
+ rtarget(p, 0, intreg[EAX]);
+ break;
+ }
+}
+
+static void clobber(Node p) {
+ static int nstack = 0;
+
+ assert(p);
+ nstack = ckstack(p, nstack);
+ switch (specific(p->op)) {
+ case RSH+I: case RSH+U: case LSH+I: case LSH+U:
+ if (generic(p->kids[1]->op) != CNST
+ && !( generic(p->kids[1]->op) == INDIR
+ && specific(p->kids[1]->kids[0]->op) == VREG+P
+ && p->kids[1]->syms[RX]->u.t.cse
+ && generic(p->kids[1]->syms[RX]->u.t.cse->op) == CNST
+)) {
+ spill(1<<ECX, 1, p);
+ }
+ break;
+ case ASGN+B: case ARG+B:
+ spill(1<<ECX | 1<<ESI | 1<<EDI, IREG, p);
+ break;
+ case EQ+F: case LE+F: case GE+F: case LT+F: case GT+F: case NE+F:
+ spill(1<<EAX, IREG, p);
+ break;
+ case CALL+F:
+ spill(1<<EDX | 1<<EAX | 1<<ECX, IREG, p);
+ break;
+ case CALL+I: case CALL+U: case CALL+P: case CALL+V:
+ spill(1<<EDX | 1<<ECX, IREG, p);
+ break;
+ }
+}
+#define isfp(p) (optype((p)->op)==F)
+
+int ckstack(Node p, int n) {
+ int i;
+
+ for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++)
+ if (isfp(p->x.kids[i]))
+ n--;
+ if (isfp(p) && p->count > 0)
+ n++;
+ if (n > 8)
+ error("expression too complicated\n");
+ debug(fprint(stderr, "(ckstack(%x)=%d)\n", p, n));
+ assert(n >= 0);
+ return n;
+}
+int memop(Node p) {
+ assert(p);
+ assert(generic(p->op) == ASGN);
+ assert(p->kids[0]);
+ assert(p->kids[1]);
+ if (generic(p->kids[1]->kids[0]->op) == INDIR
+ && sametree(p->kids[0], p->kids[1]->kids[0]->kids[0]))
+ return 3;
+ else
+ return LBURG_MAX;
+}
+int sametree(Node p, Node q) {
+ return p == NULL && q == NULL
+ || p && q && p->op == q->op && p->syms[0] == q->syms[0]
+ && sametree(p->kids[0], q->kids[0])
+ && sametree(p->kids[1], q->kids[1]);
+}
+static void emit2(Node p) {
+ int op = specific(p->op);
+#define preg(f) ((f)[getregnum(p->x.kids[0])]->x.name)
+
+ if (op == CVI+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1)
+ print("movsx %s,%s\n", p->syms[RX]->x.name
+, preg(charreg));
+ else if (op == CVI+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1)
+ print("movsx %s,%s\n", p->syms[RX]->x.name
+, preg(charreg));
+ else if (op == CVI+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2)
+ print("movsx %s,%s\n", p->syms[RX]->x.name
+, preg(shortreg));
+ else if (op == CVI+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2)
+ print("movsx %s,%s\n", p->syms[RX]->x.name
+, preg(shortreg));
+
+ else if (op == CVU+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1)
+ print("movzx %s,%s\n", p->syms[RX]->x.name
+, preg(charreg));
+ else if (op == CVU+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1)
+ print("movzx %s,%s\n", p->syms[RX]->x.name
+, preg(charreg));
+ else if (op == CVU+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2)
+ print("movzx %s,%s\n", p->syms[RX]->x.name
+, preg(shortreg));
+ else if (op == CVU+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2)
+ print("movzx %s,%s\n", p->syms[RX]->x.name
+, preg(shortreg));
+ else if (generic(op) == CVI || generic(op) == CVU || generic(op) == LOAD) {
+ char *dst = intreg[getregnum(p)]->x.name;
+ char *src = preg(intreg);
+ assert(opsize(p->op) <= opsize(p->x.kids[0]->op));
+ if (dst != src)
+ print("mov %s,%s\n", dst, src);
+ }
+}
+
+static void doarg(Node p) {
+ assert(p && p->syms[0]);
+ mkactual(4, p->syms[0]->u.c.v.i);
+}
+static void blkfetch(int k, int off, int reg, int tmp) {}
+static void blkstore(int k, int off, int reg, int tmp) {}
+static void blkloop(int dreg, int doff, int sreg, int soff,
+ int size, int tmps[]) {}
+static void local(Symbol p) {
+ if (isfloat(p->type))
+ p->sclass = AUTO;
+ if (askregvar(p, (*IR->x.rmap)(ttob(p->type))) == 0)
+ mkauto(p);
+}
+static void function(Symbol f, Symbol caller[], Symbol callee[], int n) {
+ int i;
+
+ print("%s:\n", f->x.name);
+ print("push ebx\n");
+ print("push esi\n");
+ print("push edi\n");
+ print("push ebp\n");
+ print("mov ebp,esp\n");
+ usedmask[0] = usedmask[1] = 0;
+ freemask[0] = freemask[1] = ~(unsigned)0;
+ offset = 16 + 4;
+ for (i = 0; callee[i]; i++) {
+ Symbol p = callee[i];
+ Symbol q = caller[i];
+ assert(q);
+ p->x.offset = q->x.offset = offset;
+ p->x.name = q->x.name = stringf("%d", p->x.offset);
+ p->sclass = q->sclass = AUTO;
+ offset += roundup(q->type->size, 4);
+ }
+ assert(caller[i] == 0);
+ offset = maxoffset = 0;
+ gencode(caller, callee);
+ framesize = roundup(maxoffset, 4);
+ if (framesize > 0)
+ print("sub esp,%d\n", framesize);
+ emitcode();
+ print("mov esp,ebp\n");
+ print("pop ebp\n");
+ print("pop edi\n");
+ print("pop esi\n");
+ print("pop ebx\n");
+ print("ret\n");
+}
+static void defsymbol(Symbol p) {
+ if (p->scope >= LOCAL && p->sclass == STATIC)
+ p->x.name = stringf("L%d", genlabel(1));
+ else if (p->generated)
+ p->x.name = stringf("L%s", p->name);
+ else if (p->scope == GLOBAL || p->sclass == EXTERN)
+ p->x.name = stringf("_%s", p->name);
+ else if (p->scope == CONSTANTS
+ && (isint(p->type) || isptr(p->type))
+ && p->name[0] == '0' && p->name[1] == 'x')
+ p->x.name = stringf("0%sH", &p->name[2]);
+ else
+ p->x.name = p->name;
+}
+static void address(Symbol q, Symbol p, long n) {
+ if (p->scope == GLOBAL
+ || p->sclass == STATIC || p->sclass == EXTERN)
+ q->x.name = stringf("%s%s%D",
+ p->x.name, n >= 0 ? "+" : "", n);
+ else {
+ assert(n <= INT_MAX && n >= INT_MIN);
+ q->x.offset = p->x.offset + n;
+ q->x.name = stringd(q->x.offset);
+ }
+}
+static void defconst(int suffix, int size, Value v) {
+ if (suffix == I && size == 1)
+ print("db %d\n", v.u);
+ else if (suffix == I && size == 2)
+ print("dw %d\n", v.i);
+ else if (suffix == I && size == 4)
+ print("dd %d\n", v.i);
+ else if (suffix == U && size == 1)
+ print("db 0%xH\n", v.u);
+ else if (suffix == U && size == 2)
+ print("dw 0%xH\n", v.u);
+ else if (suffix == U && size == 4)
+ print("dd 0%xH\n", v.u);
+ else if (suffix == P && size == 4)
+ print("dd 0%xH\n", v.p);
+ else if (suffix == F && size == 4) {
+ float f = v.d;
+ print("dd 0%xH\n", *(unsigned *)&f);
+ }
+ else if (suffix == F && size == 8) {
+ double d = v.d;
+ unsigned *p = (unsigned *)&d;
+ print("dd 0%xH\ndd 0%xH\n", p[swap], p[!swap]);
+ }
+ else assert(0);
+}
+static void defaddress(Symbol p) {
+ print("dd %s\n", p->x.name);
+}
+static void defstring(int n, char *str) {
+ char *s;
+
+ for (s = str; s < str + n; s++)
+ print("db %d\n", (*s)&0377);
+}
+static void export(Symbol p) {
+ print("public %s\n", p->x.name);
+}
+static void import(Symbol p) {
+ int oldseg = cseg;
+
+ if (p->ref > 0) {
+ segment(0);
+ print("extrn %s:near\n", p->x.name);
+ segment(oldseg);
+ }
+}
+static void global(Symbol p) {
+ print("align %d\n",
+ p->type->align > 4 ? 4 : p->type->align);
+ print("%s label byte\n", p->x.name);
+ if (p->u.seg == BSS)
+ print("db %d dup (0)\n", p->type->size);
+}
+static void space(int n) {
+ if (cseg != BSS)
+ print("db %d dup (0)\n", n);
+}
+Interface x86IR = {
+ 1, 1, 0, /* char */
+ 2, 2, 0, /* short */
+ 4, 4, 0, /* int */
+ 4, 4, 0, /* long */
+ 4, 4, 0, /* long long */
+ 4, 4, 1, /* float */
+ 8, 4, 1, /* double */
+ 8, 4, 1, /* long double */
+ 4, 4, 0, /* T * */
+ 0, 4, 0, /* struct; so that ARGB keeps stack aligned */
+ 1, /* little_endian */
+ 0, /* mulops_calls */
+ 0, /* wants_callb */
+ 1, /* wants_argb */
+ 0, /* left_to_right */
+ 0, /* wants_dag */
+ 0, /* unsigned_char */
+ address,
+ blockbeg,
+ blockend,
+ defaddress,
+ defconst,
+ defstring,
+ defsymbol,
+ emit,
+ export,
+ function,
+ gen,
+ global,
+ import,
+ local,
+ progbeg,
+ progend,
+ segment,
+ space,
+ 0, 0, 0, 0, 0, 0, 0,
+ {1, rmap,
+ blkfetch, blkstore, blkloop,
+ _label,
+ _rule,
+ _nts,
+ _kids,
+ _string,
+ _templates,
+ _isinstruction,
+ _ntname,
+ emit2,
+ doarg,
+ target,
+ clobber,
+}
+};
+static char rcsid[] = "$Id: x86.md 145 2001-10-17 21:53:10Z timo $";
diff --git a/lcc/src/x86linux.md b/lcc/src/x86linux.md
new file mode 100755
index 0000000..b7baaff
--- /dev/null
+++ b/lcc/src/x86linux.md
@@ -0,0 +1,1081 @@
+%{
+/* x86/linux lburg spec. Derived from x86.md by
+Marcos Ramirez <marcos@inf.utfsm.cl>
+Horst von Brand <vonbrand@sleipnir.valparaiso.cl>
+Jacob Navia <jacob@jacob.remcomp.fr>
+*/
+enum { EAX=0, ECX=1, EDX=2, EBX=3, ESI=6, EDI=7 };
+#include "c.h"
+#define NODEPTR_TYPE Node
+#define OP_LABEL(p) ((p)->op)
+#define LEFT_CHILD(p) ((p)->kids[0])
+#define RIGHT_CHILD(p) ((p)->kids[1])
+#define STATE_LABEL(p) ((p)->x.state)
+extern int ckstack(Node, int);
+extern int memop(Node);
+extern int sametree(Node, Node);
+static Symbol charreg[32], shortreg[32], intreg[32];
+static Symbol fltreg[32];
+
+static Symbol charregw, shortregw, intregw, fltregw;
+
+static int cseg;
+
+static Symbol quo, rem;
+
+extern char *stabprefix;
+extern void stabblock(int, int, Symbol*);
+extern void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *);
+extern void stabfend(Symbol, int);
+extern void stabinit(char *, int, char *[]);
+extern void stabline(Coordinate *);
+extern void stabsym(Symbol);
+extern void stabtype(Symbol);
+
+static int pflag = 0;
+static char rcsid[] = "$Id: x86linux.md 145 2001-10-17 21:53:10Z timo $";
+
+#define hasargs(p) (p->syms[0] && p->syms[0]->u.c.v.i > 0 ? 0 : LBURG_MAX)
+%}
+%start stmt
+%term CNSTF4=4113
+%term CNSTF8=8209
+%term CNSTF16=16401
+%term CNSTI1=1045
+%term CNSTI2=2069
+%term CNSTI4=4117
+%term CNSTI8=8213
+%term CNSTP4=4119
+%term CNSTP8=8215
+%term CNSTU1=1046
+%term CNSTU2=2070
+%term CNSTU4=4118
+%term CNSTU8=8214
+
+%term ARGB=41
+%term ARGF4=4129
+%term ARGF8=8225
+%term ARGF16=16417
+%term ARGI4=4133
+%term ARGI8=8229
+%term ARGP4=4135
+%term ARGP8=8231
+%term ARGU4=4134
+%term ARGU8=8230
+
+%term ASGNB=57
+%term ASGNF4=4145
+%term ASGNF8=8241
+%term ASGNF16=16433
+%term ASGNI1=1077
+%term ASGNI2=2101
+%term ASGNI4=4149
+%term ASGNI8=8245
+%term ASGNP4=4151
+%term ASGNP8=8247
+%term ASGNU1=1078
+%term ASGNU2=2102
+%term ASGNU4=4150
+%term ASGNU8=8246
+
+%term INDIRB=73
+%term INDIRF4=4161
+%term INDIRF8=8257
+%term INDIRF16=16449
+%term INDIRI1=1093
+%term INDIRI2=2117
+%term INDIRI4=4165
+%term INDIRI8=8261
+%term INDIRP4=4167
+%term INDIRP8=8263
+%term INDIRU1=1094
+%term INDIRU2=2118
+%term INDIRU4=4166
+%term INDIRU8=8262
+
+%term CVFF4=4209
+%term CVFF8=8305
+%term CVFF16=16497
+%term CVFI4=4213
+%term CVFI8=8309
+
+%term CVIF4=4225
+%term CVIF8=8321
+%term CVIF16=16513
+%term CVII1=1157
+%term CVII2=2181
+%term CVII4=4229
+%term CVII8=8325
+%term CVIU1=1158
+%term CVIU2=2182
+%term CVIU4=4230
+%term CVIU8=8326
+
+%term CVPP4=4247
+%term CVPP8=8343
+%term CVPP16=16535
+%term CVPU4=4246
+%term CVPU8=8342
+
+%term CVUI1=1205
+%term CVUI2=2229
+%term CVUI4=4277
+%term CVUI8=8373
+%term CVUP4=4279
+%term CVUP8=8375
+%term CVUP16=16567
+%term CVUU1=1206
+%term CVUU2=2230
+%term CVUU4=4278
+%term CVUU8=8374
+
+%term NEGF4=4289
+%term NEGF8=8385
+%term NEGF16=16577
+%term NEGI4=4293
+%term NEGI8=8389
+
+%term CALLB=217
+%term CALLF4=4305
+%term CALLF8=8401
+%term CALLF16=16593
+%term CALLI4=4309
+%term CALLI8=8405
+%term CALLP4=4311
+%term CALLP8=8407
+%term CALLU4=4310
+%term CALLU8=8406
+%term CALLV=216
+
+%term RETF4=4337
+%term RETF8=8433
+%term RETF16=16625
+%term RETI4=4341
+%term RETI8=8437
+%term RETP4=4343
+%term RETP8=8439
+%term RETU4=4342
+%term RETU8=8438
+%term RETV=248
+
+%term ADDRGP4=4359
+%term ADDRGP8=8455
+
+%term ADDRFP4=4375
+%term ADDRFP8=8471
+
+%term ADDRLP4=4391
+%term ADDRLP8=8487
+
+%term ADDF4=4401
+%term ADDF8=8497
+%term ADDF16=16689
+%term ADDI4=4405
+%term ADDI8=8501
+%term ADDP4=4407
+%term ADDP8=8503
+%term ADDU4=4406
+%term ADDU8=8502
+
+%term SUBF4=4417
+%term SUBF8=8513
+%term SUBF16=16705
+%term SUBI4=4421
+%term SUBI8=8517
+%term SUBP4=4423
+%term SUBP8=8519
+%term SUBU4=4422
+%term SUBU8=8518
+
+%term LSHI4=4437
+%term LSHI8=8533
+%term LSHU4=4438
+%term LSHU8=8534
+
+%term MODI4=4453
+%term MODI8=8549
+%term MODU4=4454
+%term MODU8=8550
+
+%term RSHI4=4469
+%term RSHI8=8565
+%term RSHU4=4470
+%term RSHU8=8566
+
+%term BANDI4=4485
+%term BANDI8=8581
+%term BANDU4=4486
+%term BANDU8=8582
+
+%term BCOMI4=4501
+%term BCOMI8=8597
+%term BCOMU4=4502
+%term BCOMU8=8598
+
+%term BORI4=4517
+%term BORI8=8613
+%term BORU4=4518
+%term BORU8=8614
+
+%term BXORI4=4533
+%term BXORI8=8629
+%term BXORU4=4534
+%term BXORU8=8630
+
+%term DIVF4=4545
+%term DIVF8=8641
+%term DIVF16=16833
+%term DIVI4=4549
+%term DIVI8=8645
+%term DIVU4=4550
+%term DIVU8=8646
+
+%term MULF4=4561
+%term MULF8=8657
+%term MULF16=16849
+%term MULI4=4565
+%term MULI8=8661
+%term MULU4=4566
+%term MULU8=8662
+
+%term EQF4=4577
+%term EQF8=8673
+%term EQF16=16865
+%term EQI4=4581
+%term EQI8=8677
+%term EQU4=4582
+%term EQU8=8678
+
+%term GEF4=4593
+%term GEF8=8689
+%term GEI4=4597
+%term GEI8=8693
+%term GEI16=16885
+%term GEU4=4598
+%term GEU8=8694
+
+%term GTF4=4609
+%term GTF8=8705
+%term GTF16=16897
+%term GTI4=4613
+%term GTI8=8709
+%term GTU4=4614
+%term GTU8=8710
+
+%term LEF4=4625
+%term LEF8=8721
+%term LEF16=16913
+%term LEI4=4629
+%term LEI8=8725
+%term LEU4=4630
+%term LEU8=8726
+
+%term LTF4=4641
+%term LTF8=8737
+%term LTF16=16929
+%term LTI4=4645
+%term LTI8=8741
+%term LTU4=4646
+%term LTU8=8742
+
+%term NEF4=4657
+%term NEF8=8753
+%term NEF16=16945
+%term NEI4=4661
+%term NEI8=8757
+%term NEU4=4662
+%term NEU8=8758
+
+%term JUMPV=584
+
+%term LABELV=600
+
+%term LOADB=233
+%term LOADF4=4321
+%term LOADF8=8417
+%term LOADF16=16609
+%term LOADI1=1253
+%term LOADI2=2277
+%term LOADI4=4325
+%term LOADI8=8421
+%term LOADP4=4327
+%term LOADP8=8423
+%term LOADU1=1254
+%term LOADU2=2278
+%term LOADU4=4326
+%term LOADU8=8422
+
+%term VREGP=711
+%%
+reg: INDIRI1(VREGP) "# read register\n"
+reg: INDIRU1(VREGP) "# read register\n"
+
+reg: INDIRI2(VREGP) "# read register\n"
+reg: INDIRU2(VREGP) "# read register\n"
+
+reg: INDIRI4(VREGP) "# read register\n"
+reg: INDIRP4(VREGP) "# read register\n"
+reg: INDIRU4(VREGP) "# read register\n"
+
+reg: INDIRI8(VREGP) "# read register\n"
+reg: INDIRP8(VREGP) "# read register\n"
+reg: INDIRU8(VREGP) "# read register\n"
+
+freg: INDIRF4(VREGP) "# read register\n"
+freg: INDIRF8(VREGP) "# read register\n"
+
+stmt: ASGNI1(VREGP,reg) "# write register\n"
+stmt: ASGNU1(VREGP,reg) "# write register\n"
+
+stmt: ASGNI2(VREGP,reg) "# write register\n"
+stmt: ASGNU2(VREGP,reg) "# write register\n"
+
+stmt: ASGNF4(VREGP,reg) "# write register\n"
+stmt: ASGNI4(VREGP,reg) "# write register\n"
+stmt: ASGNP4(VREGP,reg) "# write register\n"
+stmt: ASGNU4(VREGP,reg) "# write register\n"
+
+stmt: ASGNF8(VREGP,reg) "# write register\n"
+stmt: ASGNI8(VREGP,reg) "# write register\n"
+stmt: ASGNP8(VREGP,reg) "# write register\n"
+stmt: ASGNU8(VREGP,reg) "# write register\n"
+
+cnst: CNSTI1 "%a"
+cnst: CNSTU1 "%a"
+
+cnst: CNSTI2 "%a"
+cnst: CNSTU2 "%a"
+
+cnst: CNSTI4 "%a"
+cnst: CNSTU4 "%a"
+cnst: CNSTP4 "%a"
+
+cnst: CNSTI8 "%a"
+cnst: CNSTU8 "%a"
+cnst: CNSTP8 "%a"
+
+con: cnst "$%0"
+
+stmt: reg ""
+stmt: freg ""
+
+acon: ADDRGP4 "%a"
+acon: ADDRGP8 "%a"
+acon: cnst "%0"
+
+baseaddr: ADDRGP4 "%a"
+base: reg "(%0)"
+base: ADDI4(reg,acon) "%1(%0)"
+base: ADDP4(reg,acon) "%1(%0)"
+base: ADDU4(reg,acon) "%1(%0)"
+base: ADDRFP4 "%a(%%ebp)"
+base: ADDRLP4 "%a(%%ebp)"
+
+index: reg "%0"
+index: LSHI4(reg,con1) "%0,2"
+index: LSHI4(reg,con2) "%0,4"
+index: LSHI4(reg,con3) "%0,8"
+index: LSHU4(reg,con1) "%0,2"
+index: LSHU4(reg,con2) "%0,4"
+index: LSHU4(reg,con3) "%0,8"
+
+con0: CNSTI4 "1" range(a, 0, 0)
+con0: CNSTU4 "1" range(a, 0, 0)
+con1: CNSTI4 "1" range(a, 1, 1)
+con1: CNSTU4 "1" range(a, 1, 1)
+con2: CNSTI4 "2" range(a, 2, 2)
+con2: CNSTU4 "2" range(a, 2, 2)
+con3: CNSTI4 "3" range(a, 3, 3)
+con3: CNSTU4 "3" range(a, 3, 3)
+
+addr: base "%0"
+addr: baseaddr "%0"
+addr: ADDI4(index,baseaddr) "%1(,%0)"
+addr: ADDP4(index,baseaddr) "%1(,%0)"
+addr: ADDU4(index,baseaddr) "%1(,%0)"
+
+addr: ADDI4(reg,baseaddr) "%1(%0)"
+addr: ADDP4(reg,baseaddr) "%1(%0)"
+addr: ADDU4(reg,baseaddr) "%1(%0)"
+
+addr: ADDI4(index,reg) "(%1,%0)"
+addr: ADDP4(index,reg) "(%1,%0)"
+addr: ADDU4(index,reg) "(%1,%0)"
+
+addr: index "(,%0)"
+
+mem1: INDIRI1(addr) "%0"
+mem1: INDIRU1(addr) "%0"
+mem2: INDIRI2(addr) "%0"
+mem2: INDIRU2(addr) "%0"
+mem4: INDIRI4(addr) "%0"
+mem4: INDIRU4(addr) "%0"
+mem4: INDIRP4(addr) "%0"
+
+rc: reg "%0"
+rc: con "%0"
+
+mr: reg "%0"
+mr: mem4 "%0"
+
+mr1: reg "%0"
+mr1: mem1 "%0"
+
+mr2: reg "%0"
+mr2: mem2 "%0"
+
+mrc: mem4 "%0" 1
+mrc: mem1 "%0" 1
+mrc: mem2 "%0" 1
+mrc: rc "%0"
+
+reg: addr "leal %0,%c\n" 1
+reg: mr "movl %0,%c\n" 1
+reg: mr1 "movb %0,%c\n" 1
+reg: mr2 "movw %0,%c\n" 1
+reg: con "movl %0,%c\n" 1
+
+reg: LOADI1(reg) "# move\n" 1
+reg: LOADI2(reg) "# move\n" 1
+reg: LOADI4(reg) "# move\n" move(a)
+reg: LOADU1(reg) "# move\n" 1
+reg: LOADU2(reg) "# move\n" 1
+reg: LOADU4(reg) "# move\n" move(a)
+reg: LOADP4(reg) "# move\n" move(a)
+reg: ADDI4(reg,mrc) "?movl %0,%c\naddl %1,%c\n" 1
+reg: ADDP4(reg,mrc) "?movl %0,%c\naddl %1,%c\n" 1
+reg: ADDU4(reg,mrc) "?movl %0,%c\naddl %1,%c\n" 1
+reg: SUBI4(reg,mrc) "?movl %0,%c\nsubl %1,%c\n" 1
+reg: SUBP4(reg,mrc) "?movl %0,%c\nsubl %1,%c\n" 1
+reg: SUBU4(reg,mrc) "?movl %0,%c\nsubl %1,%c\n" 1
+reg: BANDI4(reg,mrc) "?movl %0,%c\nandl %1,%c\n" 1
+reg: BORI4(reg,mrc) "?movl %0,%c\norl %1,%c\n" 1
+reg: BXORI4(reg,mrc) "?movl %0,%c\nxorl %1,%c\n" 1
+reg: BANDU4(reg,mrc) "?movl %0,%c\nandl %1,%c\n" 1
+reg: BORU4(reg,mrc) "?movl %0,%c\norl %1,%c\n" 1
+reg: BXORU4(reg,mrc) "?movl %0,%c\nxorl %1,%c\n" 1
+
+stmt: ASGNI4(addr,ADDI4(mem4,con1)) "incl %1\n" memop(a)
+stmt: ASGNI4(addr,ADDU4(mem4,con1)) "incl %1\n" memop(a)
+stmt: ASGNP4(addr,ADDP4(mem4,con1)) "incl %1\n" memop(a)
+stmt: ASGNI4(addr,SUBI4(mem4,con1)) "decl %1\n" memop(a)
+stmt: ASGNI4(addr,SUBU4(mem4,con1)) "decl %1\n" memop(a)
+stmt: ASGNP4(addr,SUBP4(mem4,con1)) "decl %1\n" memop(a)
+stmt: ASGNI4(addr,ADDI4(mem4,rc)) "addl %2,%1\n" memop(a)
+stmt: ASGNI4(addr,SUBI4(mem4,rc)) "sub %2,%1\n" memop(a)
+stmt: ASGNU4(addr,ADDU4(mem4,rc)) "add %2,%1\n" memop(a)
+stmt: ASGNU4(addr,SUBU4(mem4,rc)) "sub %2,%1\n" memop(a)
+
+stmt: ASGNI4(addr,BANDI4(mem4,rc)) "andl %2,%1\n" memop(a)
+stmt: ASGNI4(addr,BORI4(mem4,rc)) "orl %2,%1\n" memop(a)
+stmt: ASGNI4(addr,BXORI4(mem4,rc)) "xorl %2,%1\n" memop(a)
+stmt: ASGNU4(addr,BANDU4(mem4,rc)) "andl %2,%1\n" memop(a)
+stmt: ASGNU4(addr,BORU4(mem4,rc)) "orl %2,%1\n" memop(a)
+stmt: ASGNU4(addr,BXORU4(mem4,rc)) "xorl %2,%1\n" memop(a)
+reg: BCOMI4(reg) "?movl %0,%c\nnotl %c\n" 2
+reg: BCOMU4(reg) "?movl %0,%c\nnotl %c\n" 2
+reg: NEGI4(reg) "?movl %0,%c\nnegl %c\n" 2
+
+stmt: ASGNI4(addr,BCOMI4(mem4)) "notl %1\n" memop(a)
+stmt: ASGNU4(addr,BCOMU4(mem4)) "notl %1\n" memop(a)
+stmt: ASGNI4(addr,NEGI4(mem4)) "negl %1\n" memop(a)
+reg: LSHI4(reg,rc5) "?movl %0,%c\nsall %1,%c\n" 2
+reg: LSHU4(reg,rc5) "?movl %0,%c\nshll %1,%c\n" 2
+reg: RSHI4(reg,rc5) "?movl %0,%c\nsarl %1,%c\n" 2
+reg: RSHU4(reg,rc5) "?movl %0,%c\nshrl %1,%c\n" 2
+
+stmt: ASGNI4(addr,LSHI4(mem4,rc5)) "sall %2,%1\n" memop(a)
+stmt: ASGNI4(addr,LSHU4(mem4,rc5)) "shll %2,%1\n" memop(a)
+stmt: ASGNI4(addr,RSHI4(mem4,rc5)) "sarl %2,%1\n" memop(a)
+stmt: ASGNI4(addr,RSHU4(mem4,rc5)) "shrl %2,%1\n" memop(a)
+
+rc5: CNSTI4 "$%a" range(a, 0, 31)
+rc5: reg "%%cl"
+reg: MULI4(reg,mrc) "?movl %0,%c\nimull %1,%c\n" 14
+reg: MULI4(con,mr) "imul %0,%1,%c\n" 13
+reg: MULU4(reg,mr) "mull %1\n" 13
+reg: DIVU4(reg,reg) "xorl %%edx,%%edx\ndivl %1\n"
+reg: MODU4(reg,reg) "xorl %%edx,%%edx\ndivl %1\n"
+reg: DIVI4(reg,reg) "cdq\nidivl %1\n"
+reg: MODI4(reg,reg) "cdq\nidivl %1\n"
+reg: CVPU4(reg) "movl %0,%c\n" move(a)
+reg: CVUP4(reg) "movl %0,%c\n" move(a)
+reg: CVII4(INDIRI1(addr)) "movsbl %0,%c\n" 3
+reg: CVII4(INDIRI2(addr)) "movswl %0,%c\n" 3
+reg: CVUU4(INDIRU1(addr)) "movzbl %0,%c\n" 3
+reg: CVUU4(INDIRU2(addr)) "movzwl %0,%c\n" 3
+reg: CVII4(reg) "# extend\n" 3
+reg: CVIU4(reg) "# extend\n" 3
+reg: CVUI4(reg) "# extend\n" 3
+reg: CVUU4(reg) "# extend\n" 3
+
+reg: CVII1(reg) "# truncate\n" 1
+reg: CVII2(reg) "# truncate\n" 1
+reg: CVUU1(reg) "# truncate\n" 1
+reg: CVUU2(reg) "# truncate\n" 1
+
+mrca: mem4 "%0"
+mrca: rc "%0"
+mrca: ADDRGP4 "$%a"
+mrca: ADDRGP8 "$%a"
+
+stmt: ASGNI1(addr,rc) "movb %1,%0\n" 1
+stmt: ASGNI2(addr,rc) "movw %1,%0\n" 1
+stmt: ASGNI4(addr,rc) "movl %1,%0\n" 1
+stmt: ASGNU1(addr,rc) "movb %1,%0\n" 1
+stmt: ASGNU2(addr,rc) "movw %1,%0\n" 1
+stmt: ASGNU4(addr,rc) "movl %1,%0\n" 1
+stmt: ASGNP4(addr,rc) "movl %1,%0\n" 1
+stmt: ARGI4(mrca) "pushl %0\n" 1
+stmt: ARGU4(mrca) "pushl %0\n" 1
+stmt: ARGP4(mrca) "pushl %0\n" 1
+stmt: ASGNB(reg,INDIRB(reg)) "movl $%a,%%ecx\nrep\nmovsb\n"
+stmt: ARGB(INDIRB(reg)) "subl $%a,%%esp\nmovl %%esp,%%edi\nmovl $%a,%%ecx\nrep\nmovsb\n"
+
+memf: INDIRF8(addr) "l %0"
+memf: INDIRF4(addr) "s %0"
+memf: CVFF8(INDIRF4(addr)) "s %0"
+memf: CVFF4(INDIRF8(addr)) "l %0"
+
+freg: memf "fld%0\n" 3
+
+stmt: ASGNF8(addr,freg) "fstpl %0\n" 7
+stmt: ASGNF4(addr,freg) "fstps %0\n" 7
+stmt: ASGNF4(addr,CVFF4(freg)) "fstps %0\n" 7
+
+stmt: ARGF8(freg) "subl $8,%%esp\nfstpl (%%esp)\n"
+stmt: ARGF4(freg) "subl $4,%%esp\nfstps (%%esp)\n"
+freg: NEGF8(freg) "fchs\n"
+freg: NEGF4(freg) "fchs\n"
+
+flt: memf "%0"
+flt: freg "p %%st(1),%%st"
+
+freg: ADDF4(freg,flt) "fadd%1\n"
+freg: ADDF8(freg,flt) "fadd%1\n"
+
+freg: DIVF4(freg,flt) "fdiv%1\n"
+freg: DIVF8(freg,flt) "fdiv%1\n"
+
+freg: MULF4(freg,flt) "fmul%1\n"
+freg: MULF8(freg,flt) "fmul%1\n"
+
+freg: SUBF4(freg,flt) "fsub%1\n"
+freg: SUBF8(freg,flt) "fsub%1\n"
+
+freg: CVFF8(freg) "# CVFF8\n"
+freg: CVFF4(freg) "sub $4,%%esp\nfstps (%%esp)\nflds (%%esp)\naddl $4,%%esp\n" 12
+
+stmt: ASGNI4(addr,CVFI4(freg)) "fistpl %0\n" 29
+reg: CVFI4(freg) "subl $4,%%esp\nfistpl 0(%%esp)\npopl %c\n" 31
+
+freg: CVIF8(INDIRI4(addr)) "fildl %0\n" 10
+freg: CVIF8(reg) "pushl %0\nfildl (%%esp)\naddl $4,%%esp\n" 12
+
+freg: CVIF4(INDIRI4(addr)) "fildl %0\n" 10
+freg: CVIF4(reg) "pushl %0\nfildl (%%esp)\naddl $4,%%esp\n" 12
+
+addrj: ADDRGP4 "%a"
+addrj: reg "*%0" 2
+addrj: mem4 "*%0" 2
+
+stmt: LABELV "%a:\n"
+stmt: JUMPV(addrj) "jmp %0\n" 3
+stmt: EQI4(mem4,rc) "cmpl %1,%0\nje %a\n" 5
+stmt: GEI4(mem4,rc) "cmpl %1,%0\njge %a\n" 5
+stmt: GTI4(mem4,rc) "cmpl %1,%0\njg %a\n" 5
+stmt: LEI4(mem4,rc) "cmpl %1,%0\njle %a\n" 5
+stmt: LTI4(mem4,rc) "cmpl %1,%0\njl %a\n" 5
+stmt: NEI4(mem4,rc) "cmpl %1,%0\njne %a\n" 5
+stmt: GEU4(mem4,rc) "cmpl %1,%0\njae %a\n" 5
+stmt: GTU4(mem4,rc) "cmpl %1,%0\nja %a\n" 5
+stmt: LEU4(mem4,rc) "cmpl %1,%0\njbe %a\n" 5
+stmt: LTU4(mem4,rc) "cmpl %1,%0\njb %a\n" 5
+stmt: EQI4(reg,mrc) "cmpl %1,%0\nje %a\n" 4
+stmt: GEI4(reg,mrc) "cmpl %1,%0\njge %a\n" 4
+stmt: GTI4(reg,mrc) "cmpl %1,%0\njg %a\n" 4
+stmt: LEI4(reg,mrc) "cmpl %1,%0\njle %a\n" 4
+stmt: LTI4(reg,mrc) "cmpl %1,%0\njl %a\n" 4
+stmt: NEI4(reg,mrc) "cmpl %1,%0\njne %a\n" 4
+
+stmt: EQU4(reg,mrc) "cmpl %1,%0\nje %a\n" 4
+stmt: GEU4(reg,mrc) "cmpl %1,%0\njae %a\n" 4
+stmt: GTU4(reg,mrc) "cmpl %1,%0\nja %a\n" 4
+stmt: LEU4(reg,mrc) "cmpl %1,%0\njbe %a\n" 4
+stmt: LTU4(reg,mrc) "cmpl %1,%0\njb %a\n" 4
+stmt: NEU4(reg,mrc) "cmpl %1,%0\njne %a\n" 4
+
+stmt: EQI4(BANDU4(mr,con),con0) "testl %1,%0\nje %a\n" 3
+stmt: NEI4(BANDU4(mr,con),con0) "testl %1,%0\njne %a\n"
+
+stmt: EQI4(BANDU4(CVII2(INDIRI2(addr)),con),con0) "testw %1,%0\nje %a\n"
+stmt: NEI4(BANDU4(CVII2(INDIRI2(addr)),con),con0) "testw %1,%0\njne %a\n"
+stmt: EQI4(BANDU4(CVIU2(INDIRI2(addr)),con),con0) "testw %1,%0\nje %a\n"
+stmt: NEI4(BANDU4(CVIU2(INDIRI2(addr)),con),con0) "testw %1,%0\njne %a\n"
+stmt: EQI4(BANDU4(CVII1(INDIRI1(addr)),con),con0) "testb %1,%0\nje %a\n"
+
+cmpf: INDIRF8(addr) "l %0"
+cmpf: INDIRF4(addr) "s %0"
+cmpf: CVFF8(INDIRF4(addr)) "s %0"
+cmpf: freg "p"
+
+stmt: EQF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\nje %a\n"
+stmt: GEF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njbe %a\n"
+stmt: GTF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njb %a\n"
+stmt: LEF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njae %a\n"
+stmt: LTF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\nja %a\n"
+stmt: NEF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njne %a\n"
+
+stmt: EQF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\nje %a\n"
+stmt: GEF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njbe %a\n"
+stmt: GTF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njb %a\n"
+stmt: LEF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njae %a\n"
+stmt: LTF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\nja %a\n"
+stmt: NEF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njne %a\n"
+
+freg: DIVF8(freg,CVIF8(INDIRI4(addr))) "fidivl %1\n"
+freg: DIVF8(CVIF8(INDIRI4(addr)),freg) "fidivrl %0\n"
+freg: DIVF8(freg,CVIF8(CVII2(INDIRI2(addr)))) "fidivs %1\n"
+freg: DIVF8(CVIF8(CVII2(INDIRI2(addr))),freg) "fidivrs %0\n"
+freg: MULF8(freg,CVIF8(INDIRI4(addr))) "fimull %1\n"
+freg: MULF8(freg,CVIF8(CVII2(INDIRI2(addr)))) "fimuls %1\n"
+freg: SUBF8(freg,CVIF8(INDIRI4(addr))) "fisubl %1\n"
+freg: SUBF8(CVIF8(INDIRI4(addr)),freg) "fisubrl %0\n"
+freg: SUBF8(freg,CVIF8(CVII2(INDIRI2(addr)))) "fisubs %1\n"
+freg: SUBF8(CVIF8(CVII2(INDIRI2(addr))),freg) "fisubrs %0\n"
+freg: ADDF8(freg,CVIF8(INDIRI4(addr))) "fiaddl %1\n"
+freg: ADDF8(freg,CVIF8(CVII2(INDIRI2(addr)))) "fiadds %1\n"
+freg: ADDF8(freg,CVFF8(INDIRF4(addr))) "fdivs %1\n"
+freg: SUBF8(freg,CVFF8(INDIRF4(addr))) "fsubs %1\n"
+freg: MULF8(freg,CVFF8(INDIRF4(addr))) "fmuls %1\n"
+freg: DIVF8(freg,CVFF8(INDIRF4(addr))) "fdivs %1\n"
+freg: LOADF8(memf) "fld%0\n"
+
+reg: CALLI4(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a)
+reg: CALLU4(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a)
+reg: CALLP4(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a)
+
+reg: CALLI4(addrj) "call %0\n" 1
+reg: CALLU4(addrj) "call %0\n" 1
+reg: CALLP4(addrj) "call %0\n" 1
+
+stmt: CALLV(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a)
+stmt: CALLV(addrj) "call %0\n" 1
+
+freg: CALLF4(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a)
+freg: CALLF4(addrj) "call %0\n" 1
+
+stmt: CALLF4(addrj) "call %0\naddl $%a,%%esp\nfstp %%st(0)\n" hasargs(a)
+stmt: CALLF4(addrj) "call %0\nfstp %%st(0)\n" 1
+
+freg: CALLF8(addrj) "call %0\naddl $%a,%%esp\n" hasargs(a)
+freg: CALLF8(addrj) "call %0\n" 1
+
+stmt: CALLF8(addrj) "call %0\naddl $%a,%%esp\nfstp %%st(0)\n" hasargs(a)
+stmt: CALLF8(addrj) "call %0\nfstp %%st(0)\n" 1
+
+stmt: RETI4(reg) "# ret\n"
+stmt: RETU4(reg) "# ret\n"
+stmt: RETP4(reg) "# ret\n"
+stmt: RETF4(freg) "# ret\n"
+stmt: RETF8(freg) "# ret\n"
+%%
+static void progbeg(int argc, char *argv[]) {
+ int i;
+
+ {
+ union {
+ char c;
+ int i;
+ } u;
+ u.i = 0;
+ u.c = 1;
+ swap = ((int)(u.i == 1)) != IR->little_endian;
+ }
+ parseflags(argc, argv);
+ for (i = 0; i < argc; i++)
+ if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "-pg") == 0)
+ pflag = 1;
+ intreg[EAX] = mkreg("%%eax", EAX, 1, IREG);
+ intreg[EDX] = mkreg("%%edx", EDX, 1, IREG);
+ intreg[ECX] = mkreg("%%ecx", ECX, 1, IREG);
+ intreg[EBX] = mkreg("%%ebx", EBX, 1, IREG);
+ intreg[ESI] = mkreg("%%esi", ESI, 1, IREG);
+ intreg[EDI] = mkreg("%%edi", EDI, 1, IREG);
+ shortreg[EAX] = mkreg("%%ax", EAX, 1, IREG);
+ shortreg[ECX] = mkreg("%%cx", ECX, 1, IREG);
+ shortreg[EDX] = mkreg("%%dx", EDX, 1, IREG);
+ shortreg[EBX] = mkreg("%%bx", EBX, 1, IREG);
+ shortreg[ESI] = mkreg("%%si", ESI, 1, IREG);
+ shortreg[EDI] = mkreg("%%di", EDI, 1, IREG);
+ charreg[EAX] = mkreg("%%al", EAX, 1, IREG);
+ charreg[ECX] = mkreg("%%cl", ECX, 1, IREG);
+ charreg[EDX] = mkreg("%%dl", EDX, 1, IREG);
+ charreg[EBX] = mkreg("%%bl", EBX, 1, IREG);
+ for (i = 0; i < 8; i++)
+ fltreg[i] = mkreg("%d", i, 0, FREG);
+ charregw = mkwildcard(charreg);
+ shortregw = mkwildcard(shortreg);
+ intregw = mkwildcard(intreg);
+ fltregw = mkwildcard(fltreg);
+
+ tmask[IREG] = (1<<EDI) | (1<<ESI) | (1<<EBX)
+ | (1<<EDX) | (1<<ECX) | (1<<EAX);
+ vmask[IREG] = 0;
+ tmask[FREG] = 0xff;
+ vmask[FREG] = 0;
+
+ cseg = 0;
+ quo = mkreg("%%eax", EAX, 1, IREG);
+ quo->x.regnode->mask |= 1<<EDX;
+ rem = mkreg("%%edx", EDX, 1, IREG);
+ rem->x.regnode->mask |= 1<<EAX;
+
+ stabprefix = ".LL";
+}
+
+static Symbol rmap(int opk) {
+ switch (optype(opk)) {
+ case B: case P:
+ return intregw;
+ case I: case U:
+ if (opsize(opk) == 1)
+ return charregw;
+ else if (opsize(opk) == 2)
+ return shortregw;
+ else
+ return intregw;
+ case F:
+ return fltregw;
+ default:
+ return 0;
+ }
+}
+
+static Symbol prevg;
+
+static void globalend(void) {
+ if (prevg && prevg->type->size > 0)
+ print(".size %s,%d\n", prevg->x.name, prevg->type->size);
+ prevg = NULL;
+}
+
+static void progend(void) {
+ globalend();
+ (*IR->segment)(CODE);
+ print(".ident \"LCC: 4.1\"\n");
+}
+
+static void target(Node p) {
+ assert(p);
+ switch (specific(p->op)) {
+ case RSH+I: case RSH+U: case LSH+I: case LSH+U:
+ if (generic(p->kids[1]->op) != CNST
+ && !( generic(p->kids[1]->op) == INDIR
+ && specific(p->kids[1]->kids[0]->op) == VREG+P
+ && p->kids[1]->syms[RX]->u.t.cse
+ && generic(p->kids[1]->syms[RX]->u.t.cse->op) == CNST)) {
+ rtarget(p, 1, intreg[ECX]);
+ setreg(p, intreg[EAX]);
+ }
+ break;
+ case MUL+U:
+ setreg(p, quo);
+ rtarget(p, 0, intreg[EAX]);
+ break;
+ case DIV+I: case DIV+U:
+ setreg(p, quo);
+ rtarget(p, 0, intreg[EAX]);
+ rtarget(p, 1, intreg[ECX]);
+ break;
+ case MOD+I: case MOD+U:
+ setreg(p, rem);
+ rtarget(p, 0, intreg[EAX]);
+ rtarget(p, 1, intreg[ECX]);
+ break;
+ case ASGN+B:
+ rtarget(p, 0, intreg[EDI]);
+ rtarget(p->kids[1], 0, intreg[ESI]);
+ break;
+ case ARG+B:
+ rtarget(p->kids[0], 0, intreg[ESI]);
+ break;
+ case CVF+I:
+ setreg(p, intreg[EAX]);
+ break;
+ case CALL+I: case CALL+U: case CALL+P: case CALL+V:
+ setreg(p, intreg[EAX]);
+ break;
+ case RET+I: case RET+U: case RET+P:
+ rtarget(p, 0, intreg[EAX]);
+ break;
+ }
+}
+
+static void clobber(Node p) {
+ static int nstack = 0;
+
+ assert(p);
+ nstack = ckstack(p, nstack);
+ switch (specific(p->op)) {
+ case ASGN+B: case ARG+B:
+ spill(1<<ECX | 1<<ESI | 1<<EDI, IREG, p);
+ break;
+ case EQ+F: case LE+F: case GE+F: case LT+F: case GT+F: case NE+F:
+ spill(1<<EAX, IREG, p);
+ break;
+ case CALL+F:
+ spill(1<<EDX | 1<<EAX | 1<<ECX, IREG, p);
+ break;
+ case CALL+I: case CALL+U: case CALL+P: case CALL+V:
+ spill(1<<EDX | 1<<ECX, IREG, p);
+ break;
+ }
+}
+
+static void emit2(Node p) {
+ int op = specific(p->op);
+#define preg(f) ((f)[getregnum(p->x.kids[0])]->x.name)
+
+ if (op == CVI+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1)
+ print("movsbl %s,%s\n", preg(charreg), p->syms[RX]->x.name);
+ else if (op == CVI+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1)
+ print("movsbl %s,%s\n", preg(charreg), p->syms[RX]->x.name);
+ else if (op == CVI+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2)
+ print("movswl %s,%s\n", preg(shortreg), p->syms[RX]->x.name);
+ else if (op == CVI+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2)
+ print("movswl %s,%s\n", preg(shortreg), p->syms[RX]->x.name);
+ else if (op == CVU+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1)
+ print("movzbl %s,%s\n", preg(charreg), p->syms[RX]->x.name);
+ else if (op == CVU+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 1)
+ print("movzbl %s,%s\n", preg(charreg), p->syms[RX]->x.name);
+ else if (op == CVU+I && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2)
+ print("movzwl %s,%s\n", preg(shortreg), p->syms[RX]->x.name);
+ else if (op == CVU+U && opsize(p->op) == 4 && opsize(p->x.kids[0]->op) == 2)
+ print("movzwl %s,%s\n", preg(shortreg), p->syms[RX]->x.name);
+ else if (generic(op) == CVI || generic(op) == CVU || generic(op) == LOAD) {
+ char *dst = intreg[getregnum(p)]->x.name;
+ char *src = preg(intreg);
+ assert(opsize(p->op) <= opsize(p->x.kids[0]->op));
+ if (dst != src)
+ print("movl %s,%s\n", src, dst);
+ }
+}
+
+static void function(Symbol f, Symbol caller[], Symbol callee[], int n) {
+ int i;
+
+ globalend();
+ print(".align 16\n");
+ print(".type %s,@function\n", f->x.name);
+ print("%s:\n", f->x.name);
+ print("pushl %%ebp\n");
+ if (pflag) {
+ static int plab;
+ print("movl %%esp,%%ebp\n");
+ (*IR->segment)(DATA);
+ print(".align 4\n.LP%d:\n.long 0\n", plab);
+ (*IR->segment)(CODE);
+ print("movl $.LP%d,%%edx\ncall mcount\n", plab);
+ plab++;
+ }
+ print("pushl %%ebx\n");
+ print("pushl %%esi\n");
+ print("pushl %%edi\n");
+ print("movl %%esp,%%ebp\n");
+
+ usedmask[0] = usedmask[1] = 0;
+ freemask[0] = freemask[1] = ~0U;
+ offset = 16 + 4;
+ for (i = 0; callee[i]; i++) {
+ Symbol p = callee[i];
+ Symbol q = caller[i];
+ assert(q);
+ offset = roundup(offset, q->type->align);
+ p->x.offset = q->x.offset = offset;
+ p->x.name = q->x.name = stringf("%d", p->x.offset);
+ p->sclass = q->sclass = AUTO;
+ offset += roundup(q->type->size, 4);
+ }
+ assert(caller[i] == 0);
+ offset = maxoffset = 0;
+ gencode(caller, callee);
+ framesize = roundup(maxoffset, 4);
+ if (framesize > 0)
+ print("subl $%d,%%esp\n", framesize);
+ emitcode();
+ print("movl %%ebp,%%esp\n");
+ print("popl %%edi\n");
+ print("popl %%esi\n");
+ print("popl %%ebx\n");
+ print("popl %%ebp\n");
+ print("ret\n");
+ { int l = genlabel(1);
+ print(".Lf%d:\n", l);
+ print(".size %s,.Lf%d-%s\n", f->x.name, l, f->x.name);
+ }
+}
+
+static void defsymbol(Symbol p) {
+ if (p->scope >= LOCAL && p->sclass == STATIC)
+ p->x.name = stringf("%s.%d", p->name, genlabel(1));
+ else if (p->generated)
+ p->x.name = stringf(".LC%s", p->name);
+ else if (p->scope == GLOBAL || p->sclass == EXTERN)
+ p->x.name = stringf("%s", p->name);
+ else
+ p->x.name = p->name;
+}
+
+static void segment(int n) {
+ if (n == cseg)
+ return;
+ cseg = n;
+ if (cseg == CODE)
+ print(".text\n");
+ else if (cseg == BSS)
+ print(".bss\n");
+ else if (cseg == DATA || cseg == LIT)
+ print(".data\n");
+}
+
+static void defconst(int suffix, int size, Value v) {
+ if (suffix == I && size == 1)
+ print(".byte %d\n", v.u);
+ else if (suffix == I && size == 2)
+ print(".word %d\n", v.i);
+ else if (suffix == I && size == 4)
+ print(".long %d\n", v.i);
+ else if (suffix == U && size == 1)
+ print(".byte %d\n", v.u);
+ else if (suffix == U && size == 2)
+ print(".word %d\n", v.u);
+ else if (suffix == U && size == 4)
+ print(".long %d\n", v.u);
+ else if (suffix == P && size == 4)
+ print(".long %d\n", v.p);
+ else if (suffix == F && size == 4) {
+ float f = v.d;
+ print(".long %d\n", *(unsigned *)&f);
+ } else if (suffix == F && size == 8) {
+ double d = v.d;
+ unsigned *p = (unsigned *)&d;
+ print(".long %d\n.long %d\n", p[swap], p[!swap]);
+ }
+ else assert(0);
+}
+
+static void defaddress(Symbol p) {
+ print(".long %s\n", p->x.name);
+}
+
+static void defstring(int n, char *str) {
+ char *s;
+
+ for (s = str; s < str + n; s++)
+ print(".byte %d\n", (*s)&0377);
+}
+
+static void export(Symbol p) {
+ globalend();
+ print(".globl %s\n", p->x.name);
+}
+
+static void import(Symbol p) {}
+
+static void global(Symbol p) {
+ globalend();
+ print(".align %d\n", p->type->align > 4 ? 4 : p->type->align);
+ if (!p->generated) {
+ print(".type %s,@%s\n", p->x.name,
+ isfunc(p->type) ? "function" : "object");
+ if (p->type->size > 0)
+ print(".size %s,%d\n", p->x.name, p->type->size);
+ else
+ prevg = p;
+ }
+ if (p->u.seg == BSS) {
+ if (p->sclass == STATIC)
+ print(".lcomm %s,%d\n", p->x.name, p->type->size);
+ else
+ print(".comm %s,%d\n", p->x.name, p->type->size);
+ } else {
+ print("%s:\n", p->x.name);
+ }
+}
+
+static void space(int n) {
+ if (cseg != BSS)
+ print(".space %d\n", n);
+}
+
+Interface x86linuxIR = {
+ 1, 1, 0, /* char */
+ 2, 2, 0, /* short */
+ 4, 4, 0, /* int */
+ 4, 4, 0, /* long */
+ 4, 4, 0, /* long long */
+ 4, 4, 1, /* float */
+ 8, 4, 1, /* double */
+ 8, 4, 1, /* long double */
+ 4, 4, 0, /* T * */
+ 0, 4, 0, /* struct; so that ARGB keeps stack aligned */
+ 1, /* little_endian */
+ 0, /* mulops_calls */
+ 0, /* wants_callb */
+ 1, /* wants_argb */
+ 0, /* left_to_right */
+ 0, /* wants_dag */
+ 0, /* unsigned_char */
+ 0, /* address */
+ blockbeg,
+ blockend,
+ defaddress,
+ defconst,
+ defstring,
+ defsymbol,
+ emit,
+ export,
+ function,
+ gen,
+ global,
+ import,
+ 0, /* local */
+ progbeg,
+ progend,
+ segment,
+ space,
+ stabblock, stabend, 0, stabinit, stabline, stabsym, stabtype,
+ {1, rmap,
+ 0, 0, 0, /* blkfetch, blkstore, blkloop */
+ _label,
+ _rule,
+ _nts,
+ _kids,
+ _string,
+ _templates,
+ _isinstruction,
+ _ntname,
+ emit2,
+ 0, /* doarg */
+ target,
+ clobber,
+ }
+};
+
+void x86linux_init(int argc, char *argv[]) {
+ static int inited;
+ extern Interface x86IR;
+
+ if (inited)
+ return;
+ inited = 1;
+#define xx(f) assert(!x86linuxIR.f); x86linuxIR.f = x86IR.f
+ xx(address);
+ xx(local);
+ xx(x.blkfetch);
+ xx(x.blkstore);
+ xx(x.blkloop);
+ xx(x.doarg);
+#undef xx
+}