OpenCores
URL https://opencores.org/ocsvn/eco32/eco32/trunk

Subversion Repositories eco32

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /eco32/tags/eco32-0.26/lcc/src
    from Rev 252 to Rev 270
    Reverse comparison

Rev 252 → Rev 270

/x86.md
0,0 → 1,1012
%{
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)) "# ARGB\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\njp %b\nje %a\n%b:\n"
stmt: GEF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njbe %a\n"
stmt: GTF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njb %a\n"
stmt: LEF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njae %a\n"
stmt: LTF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\nja %a\n"
stmt: NEF8(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njne %a\n"
 
stmt: EQF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %b\nje %a\n%b:\n"
stmt: GEF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njbe %a\n\n"
stmt: GTF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njb %a\n"
stmt: LEF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\njae %a\n\n"
stmt: LTF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\nja %a\n"
stmt: NEF4(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njp %a\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);
if (specific(p->op) == EQ+F)
p->syms[1] = findlabel(genlabel(1));
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);
}
else if (op == ARG+B)
print("sub esp,%d\nmov edi,esp\nmov ecx,%d\nrep movsb\n",
roundup(p->syms[0]->u.c.v.i, 4), p->syms[0]->u.c.v.i);
}
 
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) {
assert(p->sclass == AUTO);
offset = roundup(offset + p->type->size,
p->type->align < 4 ? 4 : p->type->align);
p->x.offset = -offset;
p->x.name = stringd(-offset);
}
}
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 >= 4096)
print("mov eax,%d\ncall __chkstk\n", framesize);
else 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");
if (framesize >= 4096) {
int oldseg = cseg;
segment(0);
print("extrn __chkstk:near\n");
segment(oldseg);
}
}
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", (unsigned)((unsigned char)v.u));
else if (suffix == U && size == 2)
print("dw 0%xH\n", (unsigned)((unsigned short)v.u));
else if (suffix == U && size == 4)
print("dd 0%xH\n", (unsigned)v.u);
else if (suffix == P && size == 4)
print("dd 0%lxH\n", (unsigned long)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);
}
static void space(int n) {
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, 1, 0, /* struct */
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,v 1.1 2002/08/28 23:12:48 drh Exp $";
/sparc.md
0,0 → 1,1177
%{
#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) "fcmpd %%f%0,%%f%1; nop; fbe"
rel: EQF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbe"
rel: GEF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbuge"
rel: GEF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbuge"
rel: GTF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbug"
rel: GTF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbug"
rel: LEF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbule"
rel: LEF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbule"
rel: LTF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbul"
rel: LTF4(reg,reg) "fcmps %%f%0,%%f%1; nop; fbul"
rel: NEF8(reg,reg) "fcmpd %%f%0,%%f%1; nop; fbne"
rel: NEF4(reg,reg) "fcmps %%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 INDIR+F+sizeop(8):
if (generic(p->kids[0]->op) != VREG) {
int dst = getregnum(p);
print("ld ["); emitasm(p->kids[0], _base_NT); print( "],%%f%d; ", dst);
print("ld ["); emitasm(p->kids[0], _base_NT); print("+4],%%f%d\n", dst+1);
}
break;
case ASGN+F+sizeop(8):
if (generic(p->kids[0]->op) != VREG) {
int src = getregnum(p->kids[1]);
print("st %%f%d,[", src); emitasm(p->kids[0], _base_NT); print("]; ");
print("st %%f%d,[", src+1); emitasm(p->kids[0], _base_NT); print("+4]\n");
}
break;
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%lx\n", (unsigned long)v.p);
else if (size == 1)
print(".byte 0x%x\n", (unsigned)((unsigned char)(suffix == I ? v.i : v.u)));
else if (size == 2)
print(".half 0x%x\n", (unsigned)((unsigned short)(suffix == I ? v.i : v.u)));
else if (size == 4)
print(".word 0x%x\n", (unsigned)(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,v 1.1 2002/08/28 23:12:46 drh Exp $";
/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.ule.s $f%0,$f%1; bc1t %a\n" 2
stmt: LEF8(reg,reg) "c.ule.d $f%0,$f%1; bc1t %a\n" 2
stmt: LTF4(reg,reg) "c.ult.s $f%0,$f%1; bc1t %a\n" 2
stmt: LTF8(reg,reg) "c.ult.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, 16);
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%lx\n", (unsigned long)v.p);
else if (size == 1)
print(".byte 0x%x\n", (unsigned)((unsigned char)(suffix == I ? v.i : v.u)));
else if (size == 2)
print(".half 0x%x\n", (unsigned)((unsigned short)(suffix == I ? v.i : v.u)));
else if (size == 4)
print(".word 0x%x\n", (unsigned)(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,v 1.1 2002/08/28 23:12:44 drh Exp $";
/x86linux.md
0,0 → 1,1079
%{
/* 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,v 1.1 2002/08/28 23:12:48 drh Exp $";
 
#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 "mov %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)) "subl %2,%1\n" memop(a)
stmt: ASGNU4(addr,ADDU4(mem4,rc)) "addl %2,%1\n" memop(a)
stmt: ASGNU4(addr,SUBU4(mem4,rc)) "subl %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)) "# ARGB\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,%%st(1)"
flt2: memf "%0"
flt2: freg "rp %%st,%%st(1)"
 
freg: ADDF4(freg,flt) "fadd%1\n"
freg: ADDF8(freg,flt) "fadd%1\n"
 
freg: DIVF4(freg,flt2) "fdiv%1\n"
freg: DIVF8(freg,flt2) "fdiv%1\n"
 
freg: MULF4(freg,flt) "fmul%1\n"
freg: MULF8(freg,flt) "fmul%1\n"
 
freg: SUBF4(freg,flt2) "fsub%1\n"
freg: SUBF8(freg,flt2) "fsub%1\n"
 
freg: CVFF8(freg) "# CVFF8\n"
freg: CVFF4(freg) "sub $4,%%esp\nfstps (%%esp)\nflds (%%esp)\naddl $4,%%esp\n" 12
 
reg: CVFI4(freg) "subl $8,%%esp\nfnstcw 4(%%esp)\nmovl 4(%%esp),%%edx\nmovb $12,%%dh\nmovl %%edx,0(%%esp)\nfldcw 0(%%esp)\nfistpl 0(%%esp)\npopl %c\nfldcw 0(%%esp)\naddl $4,%%esp\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\njp 1f\nje %a\n1:\n"
stmt: GEF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njbe %a\n"
stmt: GTF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njb %a\n"
stmt: LEF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njae %a\n"
stmt: LTF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\nja %a\n"
stmt: NEF8(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njne %a\n"
 
stmt: EQF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp 1f\nje %a\n1:\n"
stmt: GEF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njbe %a\n"
stmt: GTF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njb %a\n"
stmt: LEF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\njae %a\n"
stmt: LTF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\nja %a\n"
stmt: NEF4(cmpf,freg) "fcomp%0\nfstsw %%ax\nsahf\njp %a\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;
extern Interface x86IR, x86linuxIR;
 
#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
{
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 CVF+I:
spill(1<<EDX, 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);
} else if (op == ARG+B)
print("subl $%d,%%esp\nmovl %%esp,%%edi\nmovl $%d,%%ecx\nrep\nmovsb\n",
roundup(p->syms[0]->u.c.v.i, 4), p->syms[0]->u.c.v.i);
}
 
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", (int)v.u);
else if (suffix == I && size == 2)
print(".word %d\n", (int)v.i);
else if (suffix == I && size == 4)
print(".long %d\n", (int)v.i);
else if (suffix == U && size == 1)
print(".byte %d\n", (int)((char)v.u));
else if (suffix == U && size == 2)
print(".word %d\n", (int)v.u);
else if (suffix == U && size == 4)
print(".long %d\n", (int)v.u);
else if (suffix == P && size == 4)
print(".long %ld\n", (long)v.p);
else if (suffix == F && size == 4) {
float f = v.d;
print(".long %d\n", (int)(*(unsigned *)&f));
} else if (suffix == F && size == 8) {
double d = v.d;
unsigned *p = (unsigned *)&d;
print(".long %d\n.long %d\n", (int)p[swap], (int)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, 1, 0, /* struct */
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,
}
};
/eco32.md
0,0 → 1,1014
%{
 
/*
* eco32.md -- ECO32 back-end specification
*
* register usage:
* $0 always zero
* $1 reserved for assembler
* $2 func return value
* $3 func return value
* $4 proc/func argument
* $5 proc/func argument
* $6 proc/func argument
* $7 proc/func argument
* $8 temporary register (caller-save)
* $9 temporary register (caller-save)
* $10 temporary register (caller-save)
* $11 temporary register (caller-save)
* $12 temporary register (caller-save)
* $13 temporary register (caller-save)
* $14 temporary register (caller-save)
* $15 temporary register (caller-save)
* $16 register variable (callee-save)
* $17 register variable (callee-save)
* $18 register variable (callee-save)
* $19 register variable (callee-save)
* $20 register variable (callee-save)
* $21 register variable (callee-save)
* $22 register variable (callee-save)
* $23 register variable (callee-save)
* $24 temporary register (caller-save)
* $25 temporary register (caller-save)
* $26 reserved for OS kernel
* $27 reserved for OS kernel
* $28 reserved for OS kernel
* $29 stack pointer
* $30 interrupt return address
* $31 proc/func return address
* caller-save registers are not preserved across procedure calls
* callee-save registers are preserved across procedure calls
*
* tree grammar terminals produced by:
* ops c=1 s=2 i=4 l=4 h=4 f=4 d=8 x=8 p=4
*/
 
#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 defaddress(Symbol);
static void defconst(int, int, Value);
static void defstring(int, char *);
static void defsymbol(Symbol);
static void export(Symbol);
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 Symbol rmap(int);
static void blkfetch(int, int, int, int);
static void blkstore(int, int, int, int);
static void blkloop(int, int, int, int, int, int []);
static void emit2(Node);
static void doarg(Node);
static void target(Node);
static void clobber(Node);
 
#define INTTMP 0x0100FF00
#define INTVAR 0x00FF0000
#define INTRET 0x00000004
#define FLTTMP 0x000F0FF0
#define FLTVAR 0xFFF00000
#define FLTRET 0x00000003
 
static Symbol ireg[32];
static Symbol iregw;
static Symbol freg2[32];
static Symbol freg2w;
static Symbol blkreg;
static int tmpregs[] = { 3, 9, 10 };
 
%}
 
%start stmt
 
%term CNSTF4=4113 CNSTF8=8209
%term CNSTI1=1045 CNSTI2=2069 CNSTI4=4117
%term CNSTP4=4119
%term CNSTU1=1046 CNSTU2=2070 CNSTU4=4118
 
%term ARGB=41
%term ARGF4=4129 ARGF8=8225
%term ARGI4=4133
%term ARGP4=4135
%term ARGU4=4134
 
%term ASGNB=57
%term ASGNF4=4145 ASGNF8=8241
%term ASGNI1=1077 ASGNI2=2101 ASGNI4=4149
%term ASGNP4=4151
%term ASGNU1=1078 ASGNU2=2102 ASGNU4=4150
 
%term INDIRB=73
%term INDIRF4=4161 INDIRF8=8257
%term INDIRI1=1093 INDIRI2=2117 INDIRI4=4165
%term INDIRP4=4167
%term INDIRU1=1094 INDIRU2=2118 INDIRU4=4166
 
%term CVFF4=4209 CVFF8=8305
%term CVFI4=4213
 
%term CVIF4=4225 CVIF8=8321
%term CVII1=1157 CVII2=2181 CVII4=4229
%term CVIU1=1158 CVIU2=2182 CVIU4=4230
 
%term CVPU4=4246
 
%term CVUI1=1205 CVUI2=2229 CVUI4=4277
%term CVUP4=4279
%term CVUU1=1206 CVUU2=2230 CVUU4=4278
 
%term NEGF4=4289 NEGF8=8385
%term NEGI4=4293
 
%term CALLB=217
%term CALLF4=4305 CALLF8=8401
%term CALLI4=4309
%term CALLP4=4311
%term CALLU4=4310
%term CALLV=216
 
%term RETF4=4337 RETF8=8433
%term RETI4=4341
%term RETP4=4343
%term RETU4=4342
%term RETV=248
 
%term ADDRGP4=4359
 
%term ADDRFP4=4375
 
%term ADDRLP4=4391
 
%term ADDF4=4401 ADDF8=8497
%term ADDI4=4405
%term ADDP4=4407
%term ADDU4=4406
 
%term SUBF4=4417 SUBF8=8513
%term SUBI4=4421
%term SUBP4=4423
%term SUBU4=4422
 
%term LSHI4=4437
%term LSHU4=4438
 
%term MODI4=4453
%term MODU4=4454
 
%term RSHI4=4469
%term RSHU4=4470
 
%term BANDI4=4485
%term BANDU4=4486
 
%term BCOMI4=4501
%term BCOMU4=4502
 
%term BORI4=4517
%term BORU4=4518
 
%term BXORI4=4533
%term BXORU4=4534
 
%term DIVF4=4545 DIVF8=8641
%term DIVI4=4549
%term DIVU4=4550
 
%term MULF4=4561 MULF8=8657
%term MULI4=4565
%term MULU4=4566
 
%term EQF4=4577 EQF8=8673
%term EQI4=4581
%term EQU4=4582
 
%term GEF4=4593 GEF8=8689
%term GEI4=4597
%term GEU4=4598
 
%term GTF4=4609 GTF8=8705
%term GTI4=4613
%term GTU4=4614
 
%term LEF4=4625 LEF8=8721
%term LEI4=4629
%term LEU4=4630
 
%term LTF4=4641 LTF8=8737
%term LTI4=4645
%term LTU4=4646
 
%term NEF4=4657 NEF8=8753
%term NEI4=4661
%term NEU4=4662
 
%term JUMPV=584
 
%term LABELV=600
 
%term LOADB=233
%term LOADF4=4321 LOADF8=8417
%term LOADI1=1253 LOADI2=2277 LOADI4=4325
%term LOADP4=4327
%term LOADU1=1254 LOADU2=2278 LOADU4=4326
 
%term VREGP=711
 
 
%%
 
 
reg: INDIRI1(VREGP) "# read register\n"
reg: INDIRI2(VREGP) "# read register\n"
reg: INDIRI4(VREGP) "# read register\n"
reg: INDIRP4(VREGP) "# read register\n"
reg: INDIRU1(VREGP) "# read register\n"
reg: INDIRU2(VREGP) "# read register\n"
reg: INDIRU4(VREGP) "# read register\n"
 
stmt: ASGNI1(VREGP,reg) "# write register\n"
stmt: ASGNI2(VREGP,reg) "# write register\n"
stmt: ASGNI4(VREGP,reg) "# write register\n"
stmt: ASGNP4(VREGP,reg) "# write register\n"
stmt: ASGNU1(VREGP,reg) "# write register\n"
stmt: ASGNU2(VREGP,reg) "# write register\n"
stmt: ASGNU4(VREGP,reg) "# write register\n"
 
con: CNSTI1 "%a"
con: CNSTI2 "%a"
con: CNSTI4 "%a"
con: CNSTP4 "%a"
con: CNSTU1 "%a"
con: CNSTU2 "%a"
con: CNSTU4 "%a"
 
stmt: reg ""
 
acon: con "%0"
acon: ADDRGP4 "%a"
 
addr: ADDI4(reg,acon) "$%0,%1"
addr: ADDP4(reg,acon) "$%0,%1"
addr: ADDU4(reg,acon) "$%0,%1"
 
addr: acon "$0,%0"
addr: reg "$%0,0"
addr: ADDRFP4 "$29,%a+%F"
addr: ADDRLP4 "$29,%a+%F"
 
reg: addr "\tadd\t$%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: 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)
 
stmt: ASGNI1(addr,reg) "\tstb\t$%1,%0\n" 1
stmt: ASGNI2(addr,reg) "\tsth\t$%1,%0\n" 1
stmt: ASGNI4(addr,reg) "\tstw\t$%1,%0\n" 1
stmt: ASGNP4(addr,reg) "\tstw\t$%1,%0\n" 1
stmt: ASGNU1(addr,reg) "\tstb\t$%1,%0\n" 1
stmt: ASGNU2(addr,reg) "\tsth\t$%1,%0\n" 1
stmt: ASGNU4(addr,reg) "\tstw\t$%1,%0\n" 1
 
reg: INDIRI1(addr) "\tldb\t$%c,%0\n" 1
reg: INDIRI2(addr) "\tldh\t$%c,%0\n" 1
reg: INDIRI4(addr) "\tldw\t$%c,%0\n" 1
reg: INDIRP4(addr) "\tldw\t$%c,%0\n" 1
reg: INDIRU1(addr) "\tldbu\t$%c,%0\n" 1
reg: INDIRU2(addr) "\tldhu\t$%c,%0\n" 1
reg: INDIRU4(addr) "\tldw\t$%c,%0\n" 1
 
reg: CVII4(INDIRI1(addr)) "\tldb\t$%c,%0\n" 1
reg: CVII4(INDIRI2(addr)) "\tldh\t$%c,%0\n" 1
reg: CVUU4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1
reg: CVUU4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1
reg: CVUI4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1
reg: CVUI4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1
 
rc: con "%0"
rc: reg "$%0"
 
reg: ADDI4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1
reg: ADDP4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1
reg: ADDU4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1
reg: SUBI4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1
reg: SUBP4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1
reg: SUBU4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1
reg: NEGI4(reg) "\tsub\t$%c,$0,$%0\n" 1
 
reg: MULI4(reg,rc) "\tmul\t$%c,$%0,%1\n" 1
reg: MULU4(reg,rc) "\tmulu\t$%c,$%0,%1\n" 1
reg: DIVI4(reg,rc) "\tdiv\t$%c,$%0,%1\n" 1
reg: DIVU4(reg,rc) "\tdivu\t$%c,$%0,%1\n" 1
reg: MODI4(reg,rc) "\trem\t$%c,$%0,%1\n" 1
reg: MODU4(reg,rc) "\tremu\t$%c,$%0,%1\n" 1
 
reg: BANDI4(reg,rc) "\tand\t$%c,$%0,%1\n" 1
reg: BANDU4(reg,rc) "\tand\t$%c,$%0,%1\n" 1
reg: BORI4(reg,rc) "\tor\t$%c,$%0,%1\n" 1
reg: BORU4(reg,rc) "\tor\t$%c,$%0,%1\n" 1
reg: BXORI4(reg,rc) "\txor\t$%c,$%0,%1\n" 1
reg: BXORU4(reg,rc) "\txor\t$%c,$%0,%1\n" 1
reg: BCOMI4(reg) "\txnor\t$%c,$0,$%0\n" 1
reg: BCOMU4(reg) "\txnor\t$%c,$0,$%0\n" 1
 
rc5: CNSTI4 "%a" range(a, 0, 31)
rc5: reg "$%0"
 
reg: LSHI4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1
reg: LSHU4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1
reg: RSHI4(reg,rc5) "\tsar\t$%c,$%0,%1\n" 1
reg: RSHU4(reg,rc5) "\tslr\t$%c,$%0,%1\n" 1
 
reg: LOADI1(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADI2(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADI4(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADP4(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADU1(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADU2(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADU4(reg) "\tadd\t$%c,$0,$%0\n" move(a)
 
reg: CVII4(reg) "\tsll\t$%c,$%0,8*(4-%a)\n\tsar\t$%c,$%c,8*(4-%a)\n" 2
reg: CVUI4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1
reg: CVUU4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1
 
stmt: LABELV "%a:\n"
stmt: JUMPV(acon) "\tj\t%0\n" 1
stmt: JUMPV(reg) "\tjr\t$%0\n" 1
 
stmt: EQI4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1
stmt: EQU4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1
stmt: NEI4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1
stmt: NEU4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1
stmt: LEI4(reg,reg) "\tble\t$%0,$%1,%a\n" 1
stmt: LEU4(reg,reg) "\tbleu\t$%0,$%1,%a\n" 1
stmt: LTI4(reg,reg) "\tblt\t$%0,$%1,%a\n" 1
stmt: LTU4(reg,reg) "\tbltu\t$%0,$%1,%a\n" 1
stmt: GEI4(reg,reg) "\tbge\t$%0,$%1,%a\n" 1
stmt: GEU4(reg,reg) "\tbgeu\t$%0,$%1,%a\n" 1
stmt: GTI4(reg,reg) "\tbgt\t$%0,$%1,%a\n" 1
stmt: GTU4(reg,reg) "\tbgtu\t$%0,$%1,%a\n" 1
 
reg: CALLI4(ar) "\tjal\t%0\n" 1
reg: CALLP4(ar) "\tjal\t%0\n" 1
reg: CALLU4(ar) "\tjal\t%0\n" 1
stmt: CALLV(ar) "\tjal\t%0\n" 1
 
ar: ADDRGP4 "%a"
ar: reg "$%0"
ar: CNSTP4 "%a" range(a, 0, 0x03FFFFFF)
 
stmt: RETI4(reg) "# ret\n" 1
stmt: RETP4(reg) "# ret\n" 1
stmt: RETU4(reg) "# ret\n" 1
stmt: RETV(reg) "# ret\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
 
reg: INDIRF4(VREGP) "# read register\n"
stmt: ASGNF4(VREGP,reg) "# write register\n"
reg: INDIRF4(addr) ";FP: l.s $f%c,%0\n" 1
stmt: ASGNF4(addr,reg) ";FP: s.s $f%1,%0\n" 1
reg: ADDF4(reg,reg) ";FP: add.s $f%c,$f%0,$f%1\n" 1
reg: SUBF4(reg,reg) ";FP: sub.s $f%c,$f%0,$f%1\n" 1
reg: MULF4(reg,reg) ";FP: mul.s $f%c,$f%0,$f%1\n" 1
reg: DIVF4(reg,reg) ";FP: div.s $f%c,$f%0,$f%1\n" 1
reg: LOADF4(reg) ";FP: mov.s $f%c,$f%0\n" 1
reg: NEGF4(reg) ";FP: neg.s $f%c,$f%0\n" 1
reg: CVFF4(reg) ";FP: cvt.s.d $f%c,$f%0\n" 1
reg: CVIF4(reg) ";FP: mtc1 $%0,$f%c; cvt.s.w $f%c,$f%c\n" 1
reg: CVFI4(reg) ";FP: trunc.w.s $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i == 4 ? 1 : LBURG_MAX)
stmt: EQF4(reg,reg) ";FP: c.eq.s $f%0,$f%1; bc1t %a\n" 1
stmt: LEF4(reg,reg) ";FP: c.ule.s $f%0,$f%1; bc1t %a\n" 1
stmt: LTF4(reg,reg) ";FP: c.ult.s $f%0,$f%1; bc1t %a\n" 1
stmt: GEF4(reg,reg) ";FP: c.lt.s $f%0,$f%1; bc1f %a\n" 1
stmt: GTF4(reg,reg) ";FP: c.le.s $f%0,$f%1; bc1f %a\n" 1
stmt: NEF4(reg,reg) ";FP: c.eq.s $f%0,$f%1; bc1f %a\n" 1
reg: CALLF4(ar) "\tjal\t%0\n" 1
stmt: RETF4(reg) "# ret\n" 1
stmt: ARGF4(reg) "# arg\n" 1
 
reg: INDIRF8(VREGP) "# read register\n"
stmt: ASGNF8(VREGP,reg) "# write register\n"
reg: INDIRF8(addr) ";FP: l.d $f%c,%0\n" 1
stmt: ASGNF8(addr,reg) ";FP: s.d $f%1,%0\n" 1
reg: ADDF8(reg,reg) ";FP: add.d $f%c,$f%0,$f%1\n" 1
reg: SUBF8(reg,reg) ";FP: sub.d $f%c,$f%0,$f%1\n" 1
reg: MULF8(reg,reg) ";FP: mul.d $f%c,$f%0,$f%1\n" 1
reg: DIVF8(reg,reg) ";FP: div.d $f%c,$f%0,$f%1\n" 1
reg: LOADF8(reg) ";FP: mov.d $f%c,$f%0\n" 1
reg: NEGF8(reg) ";FP: neg.d $f%c,$f%0\n" 1
reg: CVFF8(reg) ";FP: cvt.d.s $f%c,$f%0\n" 1
reg: CVIF8(reg) ";FP: mtc1 $%0,$f%c; cvt.d.w $f%c,$f%c\n" 1
reg: CVFI4(reg) ";FP: trunc.w.d $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i == 8 ? 1 : LBURG_MAX)
stmt: EQF8(reg,reg) ";FP: c.eq.d $f%0,$f%1; bc1t %a\n" 1
stmt: LEF8(reg,reg) ";FP: c.ule.d $f%0,$f%1; bc1t %a\n" 1
stmt: LTF8(reg,reg) ";FP: c.ult.d $f%0,$f%1; bc1t %a\n" 1
stmt: GEF8(reg,reg) ";FP: c.lt.d $f%0,$f%1; bc1f %a\n" 1
stmt: GTF8(reg,reg) ";FP: c.le.d $f%0,$f%1; bc1f %a\n" 1
stmt: NEF8(reg,reg) ";FP: c.eq.d $f%0,$f%1; bc1f %a\n" 1
reg: CALLF8(ar) "\tjal\t%0\n" 1
stmt: RETF8(reg) "# ret\n" 1
stmt: ARGF8(reg) "# arg\n" 1
 
 
%%
 
 
static void address(Symbol s1, Symbol s2, long n) {
if (s2->scope == GLOBAL ||
s2->sclass == STATIC ||
s2->sclass == EXTERN) {
s1->x.name = stringf("%s%s%D", s2->x.name, n >= 0 ? "+" : "", n);
} else {
assert(n >= INT_MIN && n <= INT_MAX);
s1->x.offset = s2->x.offset + n;
s1->x.name = stringd(s1->x.offset);
}
}
 
 
static void defaddress(Symbol s) {
print("\t.word\t%s\n", s->x.name);
}
 
 
static void defconst(int suffix, int size, Value v) {
float f;
double d;
unsigned *p;
 
if (suffix == F && size == 4) {
f = v.d;
print("\t.word\t0x%x\n", * (unsigned *) &f);
} else
if (suffix == F && size == 8) {
d = v.d;
p = (unsigned *) &d;
print("\t.word\t0x%x\n", p[swap]);
print("\t.word\t0x%x\n", p[1 - swap]);
} else
if (suffix == P) {
print("\t.word\t0x%lx\n", (unsigned long) v.p);
} else
if (size == 1) {
print("\t.byte\t0x%x\n",
(unsigned) ((unsigned char) (suffix == I ? v.i : v.u)));
} else
if (size == 2) {
print("\t.half\t0x%x\n",
(unsigned) ((unsigned short) (suffix == I ? v.i : v.u)));
} else
if (size == 4) {
print("\t.word\t0x%x\n", (unsigned) (suffix == I ? v.i : v.u));
}
}
 
 
static void defstring(int n, char *str) {
char *s;
 
for (s = str; s < str + n; s++) {
print("\t.byte\t0x%x\n", (*s) & 0xFF);
}
}
 
 
static void defsymbol(Symbol s) {
if (s->scope >= LOCAL && s->sclass == STATIC) {
s->x.name = stringf("L.%d", genlabel(1));
} else
if (s->generated) {
s->x.name = stringf("L.%s", s->name);
} else {
assert(s->scope != CONSTANTS || isint(s->type) || isptr(s->type));
s->x.name = s->name;
}
}
 
 
static void export(Symbol s) {
print("\t.export\t%s\n", s->name);
}
 
 
static int bitcount(unsigned mask) {
unsigned i, n;
 
n = 0;
for (i = 1; i != 0; i <<= 1) {
if (mask & i) {
n++;
}
}
return n;
}
 
 
static Symbol argreg(int argno, int offset, int ty, int sz, int ty0) {
assert((offset & 3) == 0);
if (offset > 12) {
return NULL;
}
return ireg[(offset / 4) + 4];
}
 
 
static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
int i;
Symbol p, q;
Symbol r;
int sizeisave;
int saved;
Symbol argregs[4];
 
usedmask[0] = usedmask[1] = 0;
freemask[0] = freemask[1] = ~((unsigned) 0);
offset = 0;
maxoffset = 0;
maxargoffset = 0;
for (i = 0; callee[i] != NULL; i++) {
p = callee[i];
q = caller[i];
assert(q != NULL);
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 (variadic(f->type)) {
p->sclass = AUTO;
} else
if (r != NULL && 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] == NULL);
offset = 0;
gencode(caller, callee);
if (ncalls != 0) {
usedmask[IREG] |= ((unsigned) 1) << 31;
}
usedmask[IREG] &= 0x80FF0000;
usedmask[FREG] &= 0xFFF00000;
maxargoffset = roundup(maxargoffset, 4);
if (ncalls != 0 && maxargoffset < 16) {
maxargoffset = 16;
}
sizeisave = 4 * bitcount(usedmask[IREG]);
framesize = roundup(maxargoffset + sizeisave + maxoffset, 16);
segment(CODE);
print("\t.align\t4\n");
print("%s:\n", f->x.name);
if (framesize > 0) {
print("\tsub\t$29,$29,%d\n", framesize);
}
saved = maxargoffset;
for (i = 16; i < 32; i++) {
if (usedmask[IREG] & (1 << i)) {
print("\tstw\t$%d,$29,%d\n", i, saved);
saved += 4;
}
}
for (i = 0; i < 4 && callee[i] != NULL; 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;
print("\tadd\t$%d,$0,$%d\n", outn, rn);
} else {
int off = in->x.offset + framesize;
int n = (in->type->size + 3) / 4;
int i;
for (i = rn; i < rn + n && i <= 7; i++) {
print("\tstw\t$%d,$29,%d\n", i, off + (i - rn) * 4);
}
}
}
}
if (variadic(f->type) && callee[i - 1] != NULL) {
i = callee[i - 1]->x.offset + callee[i - 1]->type->size;
for (i = roundup(i, 4)/4; i <= 3; i++) {
print("\tstw\t$%d,$29,%d\n", i + 4, framesize + 4 * i);
}
}
emitcode();
saved = maxargoffset;
for (i = 16; i < 32; i++) {
if (usedmask[IREG] & (1 << i)) {
print("\tldw\t$%d,$29,%d\n", i, saved);
saved += 4;
}
}
if (framesize > 0) {
print("\tadd\t$29,$29,%d\n", framesize);
}
print("\tjr\t$31\n");
print("\n");
}
 
 
static void global(Symbol s) {
if (s->type->align != 0) {
print("\t.align\t%d\n", s->type->align);
} else {
print("\t.align\t%d\n", 4);
}
print("%s:\n", s->x.name);
}
 
 
static void import(Symbol s) {
print("\t.import\t%s\n", s->name);
}
 
 
static void local(Symbol s) {
if (askregvar(s, rmap(ttob(s->type))) == 0) {
mkauto(s);
}
}
 
 
static void setSwap(void) {
union {
char c;
int i;
} u;
 
u.i = 0;
u.c = 1;
swap = ((u.i == 1) != IR->little_endian);
}
 
 
static void progbeg(int argc, char *argv[]) {
int i;
 
setSwap();
segment(CODE);
parseflags(argc, argv);
for (i = 0; i < 32; i++) {
ireg[i] = mkreg("%d", i, 1, IREG);
}
iregw = mkwildcard(ireg);
for (i = 0; i < 32; i += 2) {
freg2[i] = mkreg("%d", i, 3, FREG);
}
freg2w = mkwildcard(freg2);
tmask[IREG] = INTTMP;
vmask[IREG] = INTVAR;
tmask[FREG] = FLTTMP;
vmask[FREG] = FLTVAR;
blkreg = mkreg("8", 8, 7, IREG);
}
 
 
static void progend(void) {
}
 
 
static void segment(int n) {
static int currSeg = -1;
int newSeg;
 
switch (n) {
case CODE:
newSeg = CODE;
break;
case BSS:
newSeg = BSS;
break;
case DATA:
newSeg = DATA;
break;
case LIT:
newSeg = DATA;
break;
}
if (currSeg == newSeg) {
return;
}
switch (newSeg) {
case CODE:
print("\t.code\n");
break;
case BSS:
print("\t.bss\n");
break;
case DATA:
print("\t.data\n");
break;
}
currSeg = newSeg;
}
 
 
static void space(int n) {
print("\t.space\t%d\n", n);
}
 
 
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 blkfetch(int size, int off, int reg, int tmp) {
assert(size == 1 || size == 2 || size == 4);
if (size == 1) {
print("\tldbu\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 2) {
print("\tldhu\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 4) {
print("\tldw\t$%d,$%d,%d\n", tmp, reg, off);
}
}
 
 
static void blkstore(int size, int off, int reg, int tmp) {
assert(size == 1 || size == 2 || size == 4);
if (size == 1) {
print("\tstb\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 2) {
print("\tsth\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 4) {
print("\tstw\t$%d,$%d,%d\n", tmp, reg, off);
}
}
 
 
static void blkloop(int dreg, int doff,
int sreg, int soff,
int size, int tmps[]) {
int label;
 
label = genlabel(1);
print("\tadd\t$%d,$%d,%d\n", sreg, sreg, size & ~7);
print("\tadd\t$%d,$%d,%d\n", tmps[2], dreg, size & ~7);
blkcopy(tmps[2], doff, sreg, soff, size & 7, tmps);
print("L.%d:\n", label);
print("\tsub\t$%d,$%d,%d\n", sreg, sreg, 8);
print("\tsub\t$%d,$%d,%d\n", tmps[2], tmps[2], 8);
blkcopy(tmps[2], doff, sreg, soff, 8, tmps);
print("\tbltu\t$%d,$%d,L.%d\n", dreg, tmps[2], label);
}
 
 
static void emit2(Node p) {
static int ty0;
int ty, sz;
Symbol q;
int src;
int dst, n;
 
switch (specific(p->op)) {
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) {
print("\tstw\t$%d,$29,%d\n", src, p->syms[2]->u.c.v.i);
}
break;
case ASGN+B:
dalign = p->syms[1]->u.c.v.i;
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("\tldw\t$%d,$29,%d\n", (dst / 4) + 4, dst);
}
break;
}
}
 
 
static void doarg(Node p) {
static int argno;
int align;
int size;
int offset;
 
if (argoffset == 0) {
argno = 0;
}
p->x.argno = argno++;
align = p->syms[1]->u.c.v.i;
if (align < 4) {
align = 4;
}
size = p->syms[0]->u.c.v.i;
offset = mkactual(align, size);
p->syms[2] = intconst(offset);
}
 
 
static void target(Node p) {
static int ty0;
int ty;
Symbol q;
 
assert(p);
switch (specific(p->op)) {
case CNST+I:
case CNST+P:
case CNST+U:
if (range(p, 0, 0) == 0) {
setreg(p, ireg[0]);
p->x.registered = 1;
}
break;
case CALL+I:
case CALL+P:
case CALL+U:
rtarget(p, 0, ireg[25]);
setreg(p, ireg[2]);
break;
case CALL+F:
rtarget(p, 0, ireg[25]);
setreg(p, freg2[0]);
break;
case CALL+V:
rtarget(p, 0, ireg[25]);
break;
case RET+I:
case RET+P:
case RET+U:
rtarget(p, 0, ireg[2]);
break;
case RET+F:
rtarget(p, 0, freg2[0]);
break;
case ARG+I:
case ARG+P:
case ARG+U:
case ARG+F:
ty = optype(p->op);
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;
}
}
 
 
Interface eco32IR = {
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, 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, 0, 0, 0, 0,
{
1, /* max_unaligned_load */
rmap,
blkfetch, blkstore, blkloop,
_label,
_rule,
_nts,
_kids,
_string,
_templates,
_isinstruction,
_ntname,
emit2,
doarg,
target,
clobber
}
};
/bytecode.c
0,0 → 1,282
#include "c.h"
#define I(f) b_##f
 
static char rcsid[] = "$Id: bytecode.c,v 1.1 2002/08/28 23:12:41 drh Exp $";
 
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 {
double d = v.d;
unsigned *p = (unsigned *)&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;
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));
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);
}
 
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 (cp->y != prevline)
print("line %d\n", prevline = 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, 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 */
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) */
};
/trace.c
0,0 → 1,170
#include "c.h"
 
static char rcsid[] = "$Id: trace.c,v 1.1 2002/08/28 23:12:47 drh Exp $";
 
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, void *ignore) {
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);
}
 
/* traceInit - initialize for tracing */
void traceInit(char *arg) {
if (strncmp(arg, "-t", 2) == 0 && strchr(arg, '=') == NULL) {
Symbol printer = mksymbol(EXTERN, arg[2] ? &arg[2] : "printf",
ftype(inttype, ptr(qual(CONST, chartype)), voidtype, NULL));
printer->defined = 0;
attach((Apply)tracecall, printer, &events.entry);
attach((Apply)tracereturn, printer, &events.returns);
}
}
/stab.h
0,0 → 1,114
/* @(#)stab.h 1.11 92/05/11 SMI */
/* $Id: stab.h,v 1.1 2002/08/28 23:12:46 drh Exp $ */
/*
* 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
/output.c
0,0 → 1,135
#include "c.h"
 
static char rcsid[] = "$Id: output.c,v 1.1 2002/08/28 23:12:45 drh Exp $";
 
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';
}
/init.c
0,0 → 1,319
#include "c.h"
 
static char rcsid[] = "$Id: init.c,v 1.1 2002/08/28 23:12:43 drh Exp $";
 
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;
}
/types.c
0,0 → 1,755
#include "c.h"
#include <float.h>
 
static char rcsid[] = "$Id: types.c,v 1.1 2002/08/28 23:12:47 drh Exp $";
 
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, ...) {
va_list ap;
Type ty = NULL;
List list = NULL;
 
va_start(ap, rty);
ty = va_arg(ap, Type);
for ( ; ty != NULL; ty = va_arg(ap, Type))
list = append(ty, list);
va_end(ap);
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;
}
 
/string.c
0,0 → 1,123
#include "c.h"
 
static char rcsid[] = "$Id: string.c,v 1.1 2002/08/28 23:12:46 drh Exp $";
 
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;
}
}
/decl.c
0,0 → 1,1163
#include "c.h"
 
static char rcsid[] = "$Id: decl.c,v 1.1 2002/08/28 23:12:42 drh Exp $";
 
#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(unqual(rty)), PARAM);
compound(0, NULL, 0);
 
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(unqual(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 (level == LOCAL) {
Code cp;
for (cp = codelist; cp->kind < Label; cp = cp->prev)
;
if (cp->kind != Jump) {
if (freturn(cfunc->type) != voidtype) {
warning("missing return value\n");
retcode(cnsttree(inttype, 0L));
} else
retcode(NULL);
}
}
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;
if (isarray(ty))
p->addressed = 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;
}
 
/dagcheck.md
0,0 → 1,212
%{
#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);
xx(signedptr);
xx(unsignedptr);
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);
}
/simp.c
0,0 → 1,600
#include "c.h"
#include <float.h>
 
static char rcsid[] = "$Id: simp.c,v 1.1 2002/08/28 23:12:45 drh Exp $";
 
#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;
assert(IR->address);
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);
/*
Some assemblers, e.g., the MIPS, can't handle offsets
larger than 16 bits. A better solution would be to change
the interface so that address() could fail.
*/
if (l->op == ADDRG+P && l->u.sym->generated
&& (r->op == CNST+I && (r->u.v.i > 32767 || r->u.v.i < -32768)
|| r->op == CNST+U && r->u.v.u > 65536))
break;
if (IR->address
&& 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 (IR->address
&& 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 == 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);
if (r->op == CNST+I && r->u.v.i == 1) /* l%1 => (l,0) */
return tree(RIGHT, ty, root(l), cnsttree(ty, 0L));
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;
}
 
/sym.c
0,0 → 1,332
#include "c.h"
#include <stdio.h>
 
static char rcsid[] = "$Id: sym.c,v 1.1 2002/08/28 23:12:47 drh Exp $";
 
#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 newtable(int arena) {
Table new;
 
NEW0(new, arena);
return new;
}
 
Table table(Table tp, int level) {
Table new = newtable(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);
static union { int x; char endian; } little = { 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 (v.d == 0.0) {
float z1 = v.d, z2 = p->sym.u.c.v.d;
char *b1 = (char *)&z1, *b2 = (char *)&z2;
if (z1 == z2
&& (!little.endian && b1[0] == b2[0]
|| little.endian && b1[sizeof (z1)-1] == b2[sizeof (z2)-1]))
return &p->sym;
} else 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;
}
/config.h
0,0 → 1,101
/* $Id: config.h,v 1.1 2002/08/28 23:12:42 drh Exp $ */
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 unsigned emitasm(Node, 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 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);
 
#ifdef NDEBUG
#define debug(x) (void)0
#else
#define debug(x) (void)(dflag&&((x),0))
#endif
/null.c
0,0 → 1,75
#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) {}
 
static char rcsid[] = "$Id: null.c,v 1.1 2002/08/28 23:12:45 drh Exp $";
 
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)
};
/eco32.md.SAVE-0
0,0 → 1,884
%{
 
/*
* eco32.md -- ECO32 back-end specification
*
* register usage:
* $0 always zero
* $1 reserved for assembler
* $2 func return value
* $3 func return value
* $4 proc/func argument
* $5 proc/func argument
* $6 proc/func argument
* $7 proc/func argument
* $8 temporary register (caller-save)
* $9 temporary register (caller-save)
* $10 temporary register (caller-save)
* $11 temporary register (caller-save)
* $12 temporary register (caller-save)
* $13 temporary register (caller-save)
* $14 temporary register (caller-save)
* $15 temporary register (caller-save)
* $16 register variable (callee-save)
* $17 register variable (callee-save)
* $18 register variable (callee-save)
* $19 register variable (callee-save)
* $20 register variable (callee-save)
* $21 register variable (callee-save)
* $22 register variable (callee-save)
* $23 register variable (callee-save)
* $24 temporary register (caller-save)
* $25 temporary register (caller-save)
* $26 reserved for OS kernel
* $27 reserved for OS kernel
* $28 reserved for OS kernel
* $29 stack pointer
* $30 interrupt return address
* $31 proc/func return address
* caller-save registers are not preserved across procedure calls
* callee-save registers are preserved across procedure calls
*
* tree grammar terminals produced by:
* ops c=1 s=2 i=4 l=4 h=4 f=4 d=8 x=8 p=4
*/
 
#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 defaddress(Symbol);
static void defconst(int, int, Value);
static void defstring(int, char *);
static void defsymbol(Symbol);
static void export(Symbol);
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 Symbol rmap(int);
static void blkfetch(int, int, int, int);
static void blkstore(int, int, int, int);
static void blkloop(int, int, int, int, int, int []);
static void emit2(Node);
static void doarg(Node);
static void target(Node);
static void clobber(Node);
 
#define INTTMP 0x0100FF00
#define INTVAR 0x00FF0000
#define INTRET 0x00000004
#define FLTTMP 0x000F0FF0
#define FLTVAR 0xFFF00000
#define FLTRET 0x00000003
 
static Symbol ireg[32];
static Symbol iregw;
static Symbol freg2[32];
static Symbol freg2w;
 
%}
 
%start stmt
 
%term CNSTF4=4113 CNSTF8=8209
%term CNSTI1=1045 CNSTI2=2069 CNSTI4=4117
%term CNSTP4=4119
%term CNSTU1=1046 CNSTU2=2070 CNSTU4=4118
 
%term ARGB=41
%term ARGF4=4129 ARGF8=8225
%term ARGI4=4133
%term ARGP4=4135
%term ARGU4=4134
 
%term ASGNB=57
%term ASGNF4=4145 ASGNF8=8241
%term ASGNI1=1077 ASGNI2=2101 ASGNI4=4149
%term ASGNP4=4151
%term ASGNU1=1078 ASGNU2=2102 ASGNU4=4150
 
%term INDIRB=73
%term INDIRF4=4161 INDIRF8=8257
%term INDIRI1=1093 INDIRI2=2117 INDIRI4=4165
%term INDIRP4=4167
%term INDIRU1=1094 INDIRU2=2118 INDIRU4=4166
 
%term CVFF4=4209 CVFF8=8305
%term CVFI4=4213
 
%term CVIF4=4225 CVIF8=8321
%term CVII1=1157 CVII2=2181 CVII4=4229
%term CVIU1=1158 CVIU2=2182 CVIU4=4230
 
%term CVPU4=4246
 
%term CVUI1=1205 CVUI2=2229 CVUI4=4277
%term CVUP4=4279
%term CVUU1=1206 CVUU2=2230 CVUU4=4278
 
%term NEGF4=4289 NEGF8=8385
%term NEGI4=4293
 
%term CALLB=217
%term CALLF4=4305 CALLF8=8401
%term CALLI4=4309
%term CALLP4=4311
%term CALLU4=4310
%term CALLV=216
 
%term RETF4=4337 RETF8=8433
%term RETI4=4341
%term RETP4=4343
%term RETU4=4342
%term RETV=248
 
%term ADDRGP4=4359
 
%term ADDRFP4=4375
 
%term ADDRLP4=4391
 
%term ADDF4=4401 ADDF8=8497
%term ADDI4=4405
%term ADDP4=4407
%term ADDU4=4406
 
%term SUBF4=4417 SUBF8=8513
%term SUBI4=4421
%term SUBP4=4423
%term SUBU4=4422
 
%term LSHI4=4437
%term LSHU4=4438
 
%term MODI4=4453
%term MODU4=4454
 
%term RSHI4=4469
%term RSHU4=4470
 
%term BANDI4=4485
%term BANDU4=4486
 
%term BCOMI4=4501
%term BCOMU4=4502
 
%term BORI4=4517
%term BORU4=4518
 
%term BXORI4=4533
%term BXORU4=4534
 
%term DIVF4=4545 DIVF8=8641
%term DIVI4=4549
%term DIVU4=4550
 
%term MULF4=4561 MULF8=8657
%term MULI4=4565
%term MULU4=4566
 
%term EQF4=4577 EQF8=8673
%term EQI4=4581
%term EQU4=4582
 
%term GEF4=4593 GEF8=8689
%term GEI4=4597
%term GEU4=4598
 
%term GTF4=4609 GTF8=8705
%term GTI4=4613
%term GTU4=4614
 
%term LEF4=4625 LEF8=8721
%term LEI4=4629
%term LEU4=4630
 
%term LTF4=4641 LTF8=8737
%term LTI4=4645
%term LTU4=4646
 
%term NEF4=4657 NEF8=8753
%term NEI4=4661
%term NEU4=4662
 
%term JUMPV=584
 
%term LABELV=600
 
%term LOADB=233
%term LOADF4=4321 LOADF8=8417
%term LOADI1=1253 LOADI2=2277 LOADI4=4325
%term LOADP4=4327
%term LOADU1=1254 LOADU2=2278 LOADU4=4326
 
%term VREGP=711
 
 
%%
 
 
reg: INDIRI1(VREGP) "# read register\n"
reg: INDIRI2(VREGP) "# read register\n"
reg: INDIRI4(VREGP) "# read register\n"
reg: INDIRP4(VREGP) "# read register\n"
reg: INDIRU1(VREGP) "# read register\n"
reg: INDIRU2(VREGP) "# read register\n"
reg: INDIRU4(VREGP) "# read register\n"
 
stmt: ASGNI1(VREGP,reg) "# write register\n"
stmt: ASGNI2(VREGP,reg) "# write register\n"
stmt: ASGNI4(VREGP,reg) "# write register\n"
stmt: ASGNP4(VREGP,reg) "# write register\n"
stmt: ASGNU1(VREGP,reg) "# write register\n"
stmt: ASGNU2(VREGP,reg) "# write register\n"
stmt: ASGNU4(VREGP,reg) "# write register\n"
 
con: CNSTI1 "%a"
con: CNSTI2 "%a"
con: CNSTI4 "%a"
con: CNSTP4 "%a"
con: CNSTU1 "%a"
con: CNSTU2 "%a"
con: CNSTU4 "%a"
 
stmt: reg ""
 
acon: con "%0"
acon: ADDRGP4 "%a"
 
addr: ADDI4(reg,acon) "$%0,%1"
addr: ADDP4(reg,acon) "$%0,%1"
addr: ADDU4(reg,acon) "$%0,%1"
 
addr: acon "$0,%0"
addr: reg "$%0,0"
addr: ADDRFP4 "$29,%a+%F"
addr: ADDRLP4 "$29,%a+%F"
 
reg: addr "\tadd\t$%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: 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)
 
stmt: ASGNI1(addr,reg) "\tstb\t$%1,%0\n" 1
stmt: ASGNI2(addr,reg) "\tsth\t$%1,%0\n" 1
stmt: ASGNI4(addr,reg) "\tstw\t$%1,%0\n" 1
stmt: ASGNP4(addr,reg) "\tstw\t$%1,%0\n" 1
stmt: ASGNU1(addr,reg) "\tstb\t$%1,%0\n" 1
stmt: ASGNU2(addr,reg) "\tsth\t$%1,%0\n" 1
stmt: ASGNU4(addr,reg) "\tstw\t$%1,%0\n" 1
 
reg: INDIRI1(addr) "\tldb\t$%c,%0\n" 1
reg: INDIRI2(addr) "\tldh\t$%c,%0\n" 1
reg: INDIRI4(addr) "\tldw\t$%c,%0\n" 1
reg: INDIRP4(addr) "\tldw\t$%c,%0\n" 1
reg: INDIRU1(addr) "\tldbu\t$%c,%0\n" 1
reg: INDIRU2(addr) "\tldhu\t$%c,%0\n" 1
reg: INDIRU4(addr) "\tldw\t$%c,%0\n" 1
 
reg: CVII4(INDIRI1(addr)) "\tldb\t$%c,%0\n" 1
reg: CVII4(INDIRI2(addr)) "\tldh\t$%c,%0\n" 1
reg: CVUU4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1
reg: CVUU4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1
reg: CVUI4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1
reg: CVUI4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1
 
rc: con "%0"
rc: reg "$%0"
 
reg: ADDI4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1
reg: ADDP4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1
reg: ADDU4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1
reg: SUBI4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1
reg: SUBP4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1
reg: SUBU4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1
reg: NEGI4(reg) "\tsub\t$%c,$0,$%0\n" 1
 
reg: MULI4(reg,rc) "\tmul\t$%c,$%0,%1\n" 1
reg: MULU4(reg,rc) "\tmulu\t$%c,$%0,%1\n" 1
reg: DIVI4(reg,rc) "\tdiv\t$%c,$%0,%1\n" 1
reg: DIVU4(reg,rc) "\tdivu\t$%c,$%0,%1\n" 1
reg: MODI4(reg,rc) "\trem\t$%c,$%0,%1\n" 1
reg: MODU4(reg,rc) "\tremu\t$%c,$%0,%1\n" 1
 
reg: BANDI4(reg,rc) "\tand\t$%c,$%0,%1\n" 1
reg: BANDU4(reg,rc) "\tand\t$%c,$%0,%1\n" 1
reg: BORI4(reg,rc) "\tor\t$%c,$%0,%1\n" 1
reg: BORU4(reg,rc) "\tor\t$%c,$%0,%1\n" 1
reg: BXORI4(reg,rc) "\txor\t$%c,$%0,%1\n" 1
reg: BXORU4(reg,rc) "\txor\t$%c,$%0,%1\n" 1
reg: BCOMI4(reg) "\txnor\t$%c,$0,$%0\n" 1
reg: BCOMU4(reg) "\txnor\t$%c,$0,$%0\n" 1
 
rc5: CNSTI4 "%a" range(a, 0, 31)
rc5: reg "$%0"
 
reg: LSHI4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1
reg: LSHU4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1
reg: RSHI4(reg,rc5) "\tsar\t$%c,$%0,%1\n" 1
reg: RSHU4(reg,rc5) "\tslr\t$%c,$%0,%1\n" 1
 
reg: LOADI1(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADI2(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADI4(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADP4(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADU1(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADU2(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADU4(reg) "\tadd\t$%c,$0,$%0\n" move(a)
 
reg: CVII4(reg) "\tsll\t$%c,$%0,8*(4-%a)\n\tsar\t$%c,$%c,8*(4-%a)\n" 2
reg: CVUI4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1
reg: CVUU4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1
 
stmt: LABELV "%a:\n"
stmt: JUMPV(acon) "\tj\t%0\n" 1
stmt: JUMPV(reg) "\tjr\t$%0\n" 1
 
stmt: EQI4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1
stmt: EQU4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1
stmt: NEI4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1
stmt: NEU4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1
stmt: LEI4(reg,reg) "\tble\t$%0,$%1,%a\n" 1
stmt: LEU4(reg,reg) "\tbleu\t$%0,$%1,%a\n" 1
stmt: LTI4(reg,reg) "\tblt\t$%0,$%1,%a\n" 1
stmt: LTU4(reg,reg) "\tbltu\t$%0,$%1,%a\n" 1
stmt: GEI4(reg,reg) "\tbge\t$%0,$%1,%a\n" 1
stmt: GEU4(reg,reg) "\tbgeu\t$%0,$%1,%a\n" 1
stmt: GTI4(reg,reg) "\tbgt\t$%0,$%1,%a\n" 1
stmt: GTU4(reg,reg) "\tbgtu\t$%0,$%1,%a\n" 1
 
reg: CALLI4(ar) "\tjal\t%0\n" 1
reg: CALLP4(ar) "\tjal\t%0\n" 1
reg: CALLU4(ar) "\tjal\t%0\n" 1
stmt: CALLV(ar) "\tjal\t%0\n" 1
 
ar: ADDRGP4 "%a"
ar: reg "$%0"
ar: CNSTP4 "%a" range(a, 0, 0x03FFFFFF)
 
stmt: RETI4(reg) "# ret\n" 1
stmt: RETP4(reg) "# ret\n" 1
stmt: RETU4(reg) "# ret\n" 1
stmt: RETV(reg) "# ret\n" 1
 
stmt: ARGI4(reg) "# arg\n" 1
stmt: ARGP4(reg) "# arg\n" 1
stmt: ARGU4(reg) "# arg\n" 1
 
 
%%
 
 
static void address(Symbol s1, Symbol s2, long n) {
if (s2->scope == GLOBAL ||
s2->sclass == STATIC ||
s2->sclass == EXTERN) {
s1->x.name = stringf("%s%s%D", s2->x.name, n >= 0 ? "+" : "", n);
} else {
assert(n >= INT_MIN && n <= INT_MAX);
s1->x.offset = s2->x.offset + n;
s1->x.name = stringd(s1->x.offset);
}
}
 
 
static void defaddress(Symbol s) {
print("\t.word\t%s\n", s->x.name);
}
 
 
static void defconst(int suffix, int size, Value v) {
float f;
double d;
 
if (suffix == F && size == 4) {
f = v.d;
/* float not supported */
} else
if (suffix == F && size == 8) {
d = v.d;
/* double not supported */
} else
if (suffix == P) {
print("\t.word\t0x%x\n", (unsigned) v.p);
} else
if (size == 1) {
print("\t.byte\t0x%x\n",
(unsigned) ((unsigned char) (suffix == I ? v.i : v.u)));
} else
if (size == 2) {
print("\t.half\t0x%x\n",
(unsigned) ((unsigned short) (suffix == I ? v.i : v.u)));
} else
if (size == 4) {
print("\t.word\t0x%x\n", (unsigned) (suffix == I ? v.i : v.u));
}
}
 
 
static void defstring(int n, char *str) {
char *s;
 
for (s = str; s < str + n; s++) {
print("\t.byte\t0x%x\n", (*s) & 0xFF);
}
}
 
 
static void defsymbol(Symbol s) {
if (s->scope >= LOCAL && s->sclass == STATIC) {
s->x.name = stringf("L.%d", genlabel(1));
} else
if (s->generated) {
s->x.name = stringf("L.%s", s->name);
} else {
assert(s->scope != CONSTANTS || isint(s->type) || isptr(s->type));
s->x.name = s->name;
}
}
 
 
static void export(Symbol s) {
print("\t.export\t%s\n", s->name);
}
 
 
static int bitcount(unsigned mask) {
unsigned i, n;
 
n = 0;
for (i = 1; i != 0; i <<= 1) {
if (mask & i) {
n++;
}
}
return n;
}
 
 
static Symbol argreg(int argno, int offset, int ty, int sz, int ty0) {
assert((offset & 3) == 0);
if (offset > 12) {
return NULL;
}
return ireg[(offset / 4) + 4];
}
 
 
static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
int i;
Symbol p, q;
Symbol r;
int sizeisave;
int saved;
Symbol argregs[4];
 
usedmask[0] = usedmask[1] = 0;
freemask[0] = freemask[1] = ~((unsigned) 0);
offset = 0;
maxoffset = 0;
maxargoffset = 0;
for (i = 0; callee[i] != NULL; i++) {
p = callee[i];
q = caller[i];
assert(q != NULL);
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 (variadic(f->type)) {
p->sclass = AUTO;
} else
if (r != NULL && 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] == NULL);
offset = 0;
gencode(caller, callee);
if (ncalls != 0) {
usedmask[IREG] |= ((unsigned) 1) << 31;
}
usedmask[IREG] &= 0x80FF0000;
usedmask[FREG] &= 0xFFF00000;
maxargoffset = roundup(maxargoffset, 4);
if (ncalls != 0 && maxargoffset < 16) {
maxargoffset = 16;
}
sizeisave = 4 * bitcount(usedmask[IREG]);
framesize = roundup(maxargoffset + sizeisave + maxoffset, 16);
segment(CODE);
print("\t.align\t4\n");
print("%s:\n", f->x.name);
if (framesize > 0) {
print("\tsub\t$29,$29,%d\n", framesize);
}
saved = maxargoffset;
for (i = 16; i < 32; i++) {
if (usedmask[IREG] & (1 << i)) {
print("\tstw\t$%d,$29,%d\n", i, saved);
saved += 4;
}
}
for (i = 0; i < 4 && callee[i] != NULL; 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;
print("\tadd\t$%d,$0,$%d\n", outn, rn);
} else {
int off = in->x.offset + framesize;
int n = (in->type->size + 3) / 4;
int i;
for (i = rn; i < rn + n && i <= 7; i++) {
print("\tstw\t$%d,$29,%d\n", i, off + (i - rn) * 4);
}
}
}
}
if (variadic(f->type) && callee[i - 1] != NULL) {
i = callee[i - 1]->x.offset + callee[i - 1]->type->size;
for (i = roundup(i, 4)/4; i <= 3; i++) {
print("\tstw\t$%d,$29,%d\n", i + 4, framesize + 4 * i);
}
}
emitcode();
saved = maxargoffset;
for (i = 16; i < 32; i++) {
if (usedmask[IREG] & (1 << i)) {
print("\tldw\t$%d,$29,%d\n", i, saved);
saved += 4;
}
}
if (framesize > 0) {
print("\tadd\t$29,$29,%d\n", framesize);
}
print("\tjr\t$31\n");
print("\n");
}
 
 
static void global(Symbol s) {
print("\t.align\t%d\n", s->type->align);
print("%s:\n", s->x.name);
}
 
 
static void import(Symbol s) {
print("\t.import\t%s\n", s->name);
}
 
 
static void local(Symbol s) {
if (askregvar(s, rmap(ttob(s->type))) == 0) {
mkauto(s);
}
}
 
 
static void setSwap(void) {
union {
char c;
int i;
} u;
 
u.i = 0;
u.c = 1;
swap = ((u.i == 1) != IR->little_endian);
}
 
 
static void progbeg(int argc, char *argv[]) {
int i;
 
setSwap();
segment(CODE);
parseflags(argc, argv);
for (i = 0; i < 32; i++) {
ireg[i] = mkreg("%d", i, 1, IREG);
}
iregw = mkwildcard(ireg);
for (i = 0; i < 32; i += 2) {
freg2[i] = mkreg("%d", i, 3, FREG);
}
freg2w = mkwildcard(freg2);
tmask[IREG] = INTTMP;
vmask[IREG] = INTVAR;
tmask[FREG] = FLTTMP;
vmask[FREG] = FLTVAR;
}
 
 
static void progend(void) {
}
 
 
static void segment(int n) {
static int currSeg = -1;
int newSeg;
 
switch (n) {
case CODE:
newSeg = CODE;
break;
case BSS:
newSeg = BSS;
break;
case DATA:
newSeg = DATA;
break;
case LIT:
newSeg = DATA;
break;
}
if (currSeg == newSeg) {
return;
}
switch (newSeg) {
case CODE:
print("\t.code\n");
break;
case BSS:
print("\t.bss\n");
break;
case DATA:
print("\t.data\n");
break;
}
currSeg = newSeg;
}
 
 
static void space(int n) {
print("\t.space\t%d\n", n);
}
 
 
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 blkfetch(int n1, int n2, int n3, int n4) {
/* not supported yet */
}
 
 
static void blkstore(int n1, int n2, int n3, int n4) {
/* not supported yet */
}
 
 
static void blkloop(int n1, int n2, int n3, int n4, int n5, int n6[]) {
/* not supported yet */
}
 
 
static void emit2(Node p) {
static int ty0;
int ty, sz;
Symbol q;
int src;
 
switch (specific(p->op)) {
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) {
print("\tstw\t$%d,$29,%d\n", src, p->syms[2]->u.c.v.i);
}
break;
}
}
 
 
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 target(Node p) {
static int ty0;
int ty;
Symbol q;
 
assert(p);
switch (specific(p->op)) {
case CNST+I:
case CNST+P:
case CNST+U:
if (range(p, 0, 0) == 0) {
setreg(p, ireg[0]);
p->x.registered = 1;
}
break;
case CALL+I:
case CALL+P:
case CALL+U:
rtarget(p, 0, ireg[25]);
setreg(p, ireg[2]);
break;
case CALL+V:
rtarget(p, 0, ireg[25]);
break;
case RET+I:
case RET+P:
case RET+U:
rtarget(p, 0, ireg[2]);
break;
case ARG+I:
case ARG+P:
case ARG+U:
ty = optype(p->op);
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;
}
}
 
 
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;
}
}
 
 
Interface eco32IR = {
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, 0, 0, 0, 0,
{
1, /* max_unaligned_load */
rmap,
blkfetch, blkstore, blkloop,
_label,
_rule,
_nts,
_kids,
_string,
_templates,
_isinstruction,
_ntname,
emit2,
doarg,
target,
clobber
}
};
/eco32.md.SAVE-1
0,0 → 1,946
%{
 
/*
* eco32.md -- ECO32 back-end specification
*
* register usage:
* $0 always zero
* $1 reserved for assembler
* $2 func return value
* $3 func return value
* $4 proc/func argument
* $5 proc/func argument
* $6 proc/func argument
* $7 proc/func argument
* $8 temporary register (caller-save)
* $9 temporary register (caller-save)
* $10 temporary register (caller-save)
* $11 temporary register (caller-save)
* $12 temporary register (caller-save)
* $13 temporary register (caller-save)
* $14 temporary register (caller-save)
* $15 temporary register (caller-save)
* $16 register variable (callee-save)
* $17 register variable (callee-save)
* $18 register variable (callee-save)
* $19 register variable (callee-save)
* $20 register variable (callee-save)
* $21 register variable (callee-save)
* $22 register variable (callee-save)
* $23 register variable (callee-save)
* $24 temporary register (caller-save)
* $25 temporary register (caller-save)
* $26 reserved for OS kernel
* $27 reserved for OS kernel
* $28 reserved for OS kernel
* $29 stack pointer
* $30 interrupt return address
* $31 proc/func return address
* caller-save registers are not preserved across procedure calls
* callee-save registers are preserved across procedure calls
*
* tree grammar terminals produced by:
* ops c=1 s=2 i=4 l=4 h=4 f=4 d=8 x=8 p=4
*/
 
#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 defaddress(Symbol);
static void defconst(int, int, Value);
static void defstring(int, char *);
static void defsymbol(Symbol);
static void export(Symbol);
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 Symbol rmap(int);
static void blkfetch(int, int, int, int);
static void blkstore(int, int, int, int);
static void blkloop(int, int, int, int, int, int []);
static void emit2(Node);
static void doarg(Node);
static void target(Node);
static void clobber(Node);
 
#define INTTMP 0x0100FF00
#define INTVAR 0x00FF0000
#define INTRET 0x00000004
#define FLTTMP 0x000F0FF0
#define FLTVAR 0xFFF00000
#define FLTRET 0x00000003
 
static Symbol ireg[32];
static Symbol iregw;
static Symbol freg2[32];
static Symbol freg2w;
static Symbol blkreg;
static int tmpregs[] = { 3, 9, 10 };
 
%}
 
%start stmt
 
%term CNSTF4=4113 CNSTF8=8209
%term CNSTI1=1045 CNSTI2=2069 CNSTI4=4117
%term CNSTP4=4119
%term CNSTU1=1046 CNSTU2=2070 CNSTU4=4118
 
%term ARGB=41
%term ARGF4=4129 ARGF8=8225
%term ARGI4=4133
%term ARGP4=4135
%term ARGU4=4134
 
%term ASGNB=57
%term ASGNF4=4145 ASGNF8=8241
%term ASGNI1=1077 ASGNI2=2101 ASGNI4=4149
%term ASGNP4=4151
%term ASGNU1=1078 ASGNU2=2102 ASGNU4=4150
 
%term INDIRB=73
%term INDIRF4=4161 INDIRF8=8257
%term INDIRI1=1093 INDIRI2=2117 INDIRI4=4165
%term INDIRP4=4167
%term INDIRU1=1094 INDIRU2=2118 INDIRU4=4166
 
%term CVFF4=4209 CVFF8=8305
%term CVFI4=4213
 
%term CVIF4=4225 CVIF8=8321
%term CVII1=1157 CVII2=2181 CVII4=4229
%term CVIU1=1158 CVIU2=2182 CVIU4=4230
 
%term CVPU4=4246
 
%term CVUI1=1205 CVUI2=2229 CVUI4=4277
%term CVUP4=4279
%term CVUU1=1206 CVUU2=2230 CVUU4=4278
 
%term NEGF4=4289 NEGF8=8385
%term NEGI4=4293
 
%term CALLB=217
%term CALLF4=4305 CALLF8=8401
%term CALLI4=4309
%term CALLP4=4311
%term CALLU4=4310
%term CALLV=216
 
%term RETF4=4337 RETF8=8433
%term RETI4=4341
%term RETP4=4343
%term RETU4=4342
%term RETV=248
 
%term ADDRGP4=4359
 
%term ADDRFP4=4375
 
%term ADDRLP4=4391
 
%term ADDF4=4401 ADDF8=8497
%term ADDI4=4405
%term ADDP4=4407
%term ADDU4=4406
 
%term SUBF4=4417 SUBF8=8513
%term SUBI4=4421
%term SUBP4=4423
%term SUBU4=4422
 
%term LSHI4=4437
%term LSHU4=4438
 
%term MODI4=4453
%term MODU4=4454
 
%term RSHI4=4469
%term RSHU4=4470
 
%term BANDI4=4485
%term BANDU4=4486
 
%term BCOMI4=4501
%term BCOMU4=4502
 
%term BORI4=4517
%term BORU4=4518
 
%term BXORI4=4533
%term BXORU4=4534
 
%term DIVF4=4545 DIVF8=8641
%term DIVI4=4549
%term DIVU4=4550
 
%term MULF4=4561 MULF8=8657
%term MULI4=4565
%term MULU4=4566
 
%term EQF4=4577 EQF8=8673
%term EQI4=4581
%term EQU4=4582
 
%term GEF4=4593 GEF8=8689
%term GEI4=4597
%term GEU4=4598
 
%term GTF4=4609 GTF8=8705
%term GTI4=4613
%term GTU4=4614
 
%term LEF4=4625 LEF8=8721
%term LEI4=4629
%term LEU4=4630
 
%term LTF4=4641 LTF8=8737
%term LTI4=4645
%term LTU4=4646
 
%term NEF4=4657 NEF8=8753
%term NEI4=4661
%term NEU4=4662
 
%term JUMPV=584
 
%term LABELV=600
 
%term LOADB=233
%term LOADF4=4321 LOADF8=8417
%term LOADI1=1253 LOADI2=2277 LOADI4=4325
%term LOADP4=4327
%term LOADU1=1254 LOADU2=2278 LOADU4=4326
 
%term VREGP=711
 
 
%%
 
 
reg: INDIRI1(VREGP) "# read register\n"
reg: INDIRI2(VREGP) "# read register\n"
reg: INDIRI4(VREGP) "# read register\n"
reg: INDIRP4(VREGP) "# read register\n"
reg: INDIRU1(VREGP) "# read register\n"
reg: INDIRU2(VREGP) "# read register\n"
reg: INDIRU4(VREGP) "# read register\n"
 
stmt: ASGNI1(VREGP,reg) "# write register\n"
stmt: ASGNI2(VREGP,reg) "# write register\n"
stmt: ASGNI4(VREGP,reg) "# write register\n"
stmt: ASGNP4(VREGP,reg) "# write register\n"
stmt: ASGNU1(VREGP,reg) "# write register\n"
stmt: ASGNU2(VREGP,reg) "# write register\n"
stmt: ASGNU4(VREGP,reg) "# write register\n"
 
con: CNSTI1 "%a"
con: CNSTI2 "%a"
con: CNSTI4 "%a"
con: CNSTP4 "%a"
con: CNSTU1 "%a"
con: CNSTU2 "%a"
con: CNSTU4 "%a"
 
stmt: reg ""
 
acon: con "%0"
acon: ADDRGP4 "%a"
 
addr: ADDI4(reg,acon) "$%0,%1"
addr: ADDP4(reg,acon) "$%0,%1"
addr: ADDU4(reg,acon) "$%0,%1"
 
addr: acon "$0,%0"
addr: reg "$%0,0"
addr: ADDRFP4 "$29,%a+%F"
addr: ADDRLP4 "$29,%a+%F"
 
reg: addr "\tadd\t$%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: 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)
 
stmt: ASGNI1(addr,reg) "\tstb\t$%1,%0\n" 1
stmt: ASGNI2(addr,reg) "\tsth\t$%1,%0\n" 1
stmt: ASGNI4(addr,reg) "\tstw\t$%1,%0\n" 1
stmt: ASGNP4(addr,reg) "\tstw\t$%1,%0\n" 1
stmt: ASGNU1(addr,reg) "\tstb\t$%1,%0\n" 1
stmt: ASGNU2(addr,reg) "\tsth\t$%1,%0\n" 1
stmt: ASGNU4(addr,reg) "\tstw\t$%1,%0\n" 1
 
reg: INDIRI1(addr) "\tldb\t$%c,%0\n" 1
reg: INDIRI2(addr) "\tldh\t$%c,%0\n" 1
reg: INDIRI4(addr) "\tldw\t$%c,%0\n" 1
reg: INDIRP4(addr) "\tldw\t$%c,%0\n" 1
reg: INDIRU1(addr) "\tldbu\t$%c,%0\n" 1
reg: INDIRU2(addr) "\tldhu\t$%c,%0\n" 1
reg: INDIRU4(addr) "\tldw\t$%c,%0\n" 1
 
reg: CVII4(INDIRI1(addr)) "\tldb\t$%c,%0\n" 1
reg: CVII4(INDIRI2(addr)) "\tldh\t$%c,%0\n" 1
reg: CVUU4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1
reg: CVUU4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1
reg: CVUI4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1
reg: CVUI4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1
 
rc: con "%0"
rc: reg "$%0"
 
reg: ADDI4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1
reg: ADDP4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1
reg: ADDU4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1
reg: SUBI4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1
reg: SUBP4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1
reg: SUBU4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1
reg: NEGI4(reg) "\tsub\t$%c,$0,$%0\n" 1
 
reg: MULI4(reg,rc) "\tmul\t$%c,$%0,%1\n" 1
reg: MULU4(reg,rc) "\tmulu\t$%c,$%0,%1\n" 1
reg: DIVI4(reg,rc) "\tdiv\t$%c,$%0,%1\n" 1
reg: DIVU4(reg,rc) "\tdivu\t$%c,$%0,%1\n" 1
reg: MODI4(reg,rc) "\trem\t$%c,$%0,%1\n" 1
reg: MODU4(reg,rc) "\tremu\t$%c,$%0,%1\n" 1
 
reg: BANDI4(reg,rc) "\tand\t$%c,$%0,%1\n" 1
reg: BANDU4(reg,rc) "\tand\t$%c,$%0,%1\n" 1
reg: BORI4(reg,rc) "\tor\t$%c,$%0,%1\n" 1
reg: BORU4(reg,rc) "\tor\t$%c,$%0,%1\n" 1
reg: BXORI4(reg,rc) "\txor\t$%c,$%0,%1\n" 1
reg: BXORU4(reg,rc) "\txor\t$%c,$%0,%1\n" 1
reg: BCOMI4(reg) "\txnor\t$%c,$0,$%0\n" 1
reg: BCOMU4(reg) "\txnor\t$%c,$0,$%0\n" 1
 
rc5: CNSTI4 "%a" range(a, 0, 31)
rc5: reg "$%0"
 
reg: LSHI4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1
reg: LSHU4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1
reg: RSHI4(reg,rc5) "\tsar\t$%c,$%0,%1\n" 1
reg: RSHU4(reg,rc5) "\tslr\t$%c,$%0,%1\n" 1
 
reg: LOADI1(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADI2(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADI4(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADP4(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADU1(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADU2(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADU4(reg) "\tadd\t$%c,$0,$%0\n" move(a)
 
reg: CVII4(reg) "\tsll\t$%c,$%0,8*(4-%a)\n\tsar\t$%c,$%c,8*(4-%a)\n" 2
reg: CVUI4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1
reg: CVUU4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1
 
stmt: LABELV "%a:\n"
stmt: JUMPV(acon) "\tj\t%0\n" 1
stmt: JUMPV(reg) "\tjr\t$%0\n" 1
 
stmt: EQI4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1
stmt: EQU4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1
stmt: NEI4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1
stmt: NEU4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1
stmt: LEI4(reg,reg) "\tble\t$%0,$%1,%a\n" 1
stmt: LEU4(reg,reg) "\tbleu\t$%0,$%1,%a\n" 1
stmt: LTI4(reg,reg) "\tblt\t$%0,$%1,%a\n" 1
stmt: LTU4(reg,reg) "\tbltu\t$%0,$%1,%a\n" 1
stmt: GEI4(reg,reg) "\tbge\t$%0,$%1,%a\n" 1
stmt: GEU4(reg,reg) "\tbgeu\t$%0,$%1,%a\n" 1
stmt: GTI4(reg,reg) "\tbgt\t$%0,$%1,%a\n" 1
stmt: GTU4(reg,reg) "\tbgtu\t$%0,$%1,%a\n" 1
 
reg: CALLI4(ar) "\tjal\t%0\n" 1
reg: CALLP4(ar) "\tjal\t%0\n" 1
reg: CALLU4(ar) "\tjal\t%0\n" 1
stmt: CALLV(ar) "\tjal\t%0\n" 1
 
ar: ADDRGP4 "%a"
ar: reg "$%0"
ar: CNSTP4 "%a" range(a, 0, 0x03FFFFFF)
 
stmt: RETI4(reg) "# ret\n" 1
stmt: RETP4(reg) "# ret\n" 1
stmt: RETU4(reg) "# ret\n" 1
stmt: RETV(reg) "# ret\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 address(Symbol s1, Symbol s2, long n) {
if (s2->scope == GLOBAL ||
s2->sclass == STATIC ||
s2->sclass == EXTERN) {
s1->x.name = stringf("%s%s%D", s2->x.name, n >= 0 ? "+" : "", n);
} else {
assert(n >= INT_MIN && n <= INT_MAX);
s1->x.offset = s2->x.offset + n;
s1->x.name = stringd(s1->x.offset);
}
}
 
 
static void defaddress(Symbol s) {
print("\t.word\t%s\n", s->x.name);
}
 
 
static void defconst(int suffix, int size, Value v) {
float f;
double d;
 
if (suffix == F && size == 4) {
f = v.d;
/* float not supported */
} else
if (suffix == F && size == 8) {
d = v.d;
/* double not supported */
} else
if (suffix == P) {
print("\t.word\t0x%x\n", (unsigned) v.p);
} else
if (size == 1) {
print("\t.byte\t0x%x\n",
(unsigned) ((unsigned char) (suffix == I ? v.i : v.u)));
} else
if (size == 2) {
print("\t.half\t0x%x\n",
(unsigned) ((unsigned short) (suffix == I ? v.i : v.u)));
} else
if (size == 4) {
print("\t.word\t0x%x\n", (unsigned) (suffix == I ? v.i : v.u));
}
}
 
 
static void defstring(int n, char *str) {
char *s;
 
for (s = str; s < str + n; s++) {
print("\t.byte\t0x%x\n", (*s) & 0xFF);
}
}
 
 
static void defsymbol(Symbol s) {
if (s->scope >= LOCAL && s->sclass == STATIC) {
s->x.name = stringf("L.%d", genlabel(1));
} else
if (s->generated) {
s->x.name = stringf("L.%s", s->name);
} else {
assert(s->scope != CONSTANTS || isint(s->type) || isptr(s->type));
s->x.name = s->name;
}
}
 
 
static void export(Symbol s) {
print("\t.export\t%s\n", s->name);
}
 
 
static int bitcount(unsigned mask) {
unsigned i, n;
 
n = 0;
for (i = 1; i != 0; i <<= 1) {
if (mask & i) {
n++;
}
}
return n;
}
 
 
static Symbol argreg(int argno, int offset, int ty, int sz, int ty0) {
assert((offset & 3) == 0);
if (offset > 12) {
return NULL;
}
return ireg[(offset / 4) + 4];
}
 
 
static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
int i;
Symbol p, q;
Symbol r;
int sizeisave;
int saved;
Symbol argregs[4];
 
usedmask[0] = usedmask[1] = 0;
freemask[0] = freemask[1] = ~((unsigned) 0);
offset = 0;
maxoffset = 0;
maxargoffset = 0;
for (i = 0; callee[i] != NULL; i++) {
p = callee[i];
q = caller[i];
assert(q != NULL);
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 (variadic(f->type)) {
p->sclass = AUTO;
} else
if (r != NULL && 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] == NULL);
offset = 0;
gencode(caller, callee);
if (ncalls != 0) {
usedmask[IREG] |= ((unsigned) 1) << 31;
}
usedmask[IREG] &= 0x80FF0000;
usedmask[FREG] &= 0xFFF00000;
maxargoffset = roundup(maxargoffset, 4);
if (ncalls != 0 && maxargoffset < 16) {
maxargoffset = 16;
}
sizeisave = 4 * bitcount(usedmask[IREG]);
framesize = roundup(maxargoffset + sizeisave + maxoffset, 16);
segment(CODE);
print("\t.align\t4\n");
print("%s:\n", f->x.name);
if (framesize > 0) {
print("\tsub\t$29,$29,%d\n", framesize);
}
saved = maxargoffset;
for (i = 16; i < 32; i++) {
if (usedmask[IREG] & (1 << i)) {
print("\tstw\t$%d,$29,%d\n", i, saved);
saved += 4;
}
}
for (i = 0; i < 4 && callee[i] != NULL; 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;
print("\tadd\t$%d,$0,$%d\n", outn, rn);
} else {
int off = in->x.offset + framesize;
int n = (in->type->size + 3) / 4;
int i;
for (i = rn; i < rn + n && i <= 7; i++) {
print("\tstw\t$%d,$29,%d\n", i, off + (i - rn) * 4);
}
}
}
}
if (variadic(f->type) && callee[i - 1] != NULL) {
i = callee[i - 1]->x.offset + callee[i - 1]->type->size;
for (i = roundup(i, 4)/4; i <= 3; i++) {
print("\tstw\t$%d,$29,%d\n", i + 4, framesize + 4 * i);
}
}
emitcode();
saved = maxargoffset;
for (i = 16; i < 32; i++) {
if (usedmask[IREG] & (1 << i)) {
print("\tldw\t$%d,$29,%d\n", i, saved);
saved += 4;
}
}
if (framesize > 0) {
print("\tadd\t$29,$29,%d\n", framesize);
}
print("\tjr\t$31\n");
print("\n");
}
 
 
static void global(Symbol s) {
print("\t.align\t%d\n", s->type->align);
print("%s:\n", s->x.name);
}
 
 
static void import(Symbol s) {
print("\t.import\t%s\n", s->name);
}
 
 
static void local(Symbol s) {
if (askregvar(s, rmap(ttob(s->type))) == 0) {
mkauto(s);
}
}
 
 
static void setSwap(void) {
union {
char c;
int i;
} u;
 
u.i = 0;
u.c = 1;
swap = ((u.i == 1) != IR->little_endian);
}
 
 
static void progbeg(int argc, char *argv[]) {
int i;
 
setSwap();
segment(CODE);
parseflags(argc, argv);
for (i = 0; i < 32; i++) {
ireg[i] = mkreg("%d", i, 1, IREG);
}
iregw = mkwildcard(ireg);
for (i = 0; i < 32; i += 2) {
freg2[i] = mkreg("%d", i, 3, FREG);
}
freg2w = mkwildcard(freg2);
tmask[IREG] = INTTMP;
vmask[IREG] = INTVAR;
tmask[FREG] = FLTTMP;
vmask[FREG] = FLTVAR;
blkreg = mkreg("8", 8, 7, IREG);
}
 
 
static void progend(void) {
}
 
 
static void segment(int n) {
static int currSeg = -1;
int newSeg;
 
switch (n) {
case CODE:
newSeg = CODE;
break;
case BSS:
newSeg = BSS;
break;
case DATA:
newSeg = DATA;
break;
case LIT:
newSeg = DATA;
break;
}
if (currSeg == newSeg) {
return;
}
switch (newSeg) {
case CODE:
print("\t.code\n");
break;
case BSS:
print("\t.bss\n");
break;
case DATA:
print("\t.data\n");
break;
}
currSeg = newSeg;
}
 
 
static void space(int n) {
print("\t.space\t%d\n", n);
}
 
 
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 blkfetch(int size, int off, int reg, int tmp) {
assert(size == 1 || size == 2 || size == 4);
if (size == 1) {
print("\tldbu\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 2) {
print("\tldhu\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 4) {
print("\tldw\t$%d,$%d,%d\n", tmp, reg, off);
}
}
 
 
static void blkstore(int size, int off, int reg, int tmp) {
assert(size == 1 || size == 2 || size == 4);
if (size == 1) {
print("\tstb\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 2) {
print("\tsth\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 4) {
print("\tstw\t$%d,$%d,%d\n", tmp, reg, off);
}
}
 
 
static void blkloop(int dreg, int doff,
int sreg, int soff,
int size, int tmps[]) {
int label;
 
label = genlabel(1);
print("\tadd\t$%d,$%d,%d\n", sreg, sreg, size & ~7);
print("\tadd\t$%d,$%d,%d\n", tmps[2], dreg, size & ~7);
blkcopy(tmps[2], doff, sreg, soff, size & 7, tmps);
print("L.%d:\n", label);
print("\tsub\t$%d,$%d,%d\n", sreg, sreg, 8);
print("\tsub\t$%d,$%d,%d\n", tmps[2], tmps[2], 8);
blkcopy(tmps[2], doff, sreg, soff, 8, tmps);
print("\tbltu\t$%d,$%d,L.%d\n", dreg, tmps[2], label);
}
 
 
static void emit2(Node p) {
static int ty0;
int ty, sz;
Symbol q;
int src;
int dst, n;
 
switch (specific(p->op)) {
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) {
print("\tstw\t$%d,$29,%d\n", src, p->syms[2]->u.c.v.i);
}
break;
case ASGN+B:
dalign = p->syms[1]->u.c.v.i;
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("\tldw\t$%d,$29,%d\n", (dst / 4) + 4, dst);
}
break;
}
}
 
 
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 target(Node p) {
static int ty0;
int ty;
Symbol q;
 
assert(p);
switch (specific(p->op)) {
case CNST+I:
case CNST+P:
case CNST+U:
if (range(p, 0, 0) == 0) {
setreg(p, ireg[0]);
p->x.registered = 1;
}
break;
case CALL+I:
case CALL+P:
case CALL+U:
rtarget(p, 0, ireg[25]);
setreg(p, ireg[2]);
break;
case CALL+V:
rtarget(p, 0, ireg[25]);
break;
case RET+I:
case RET+P:
case RET+U:
rtarget(p, 0, ireg[2]);
break;
case ARG+I:
case ARG+P:
case ARG+U:
ty = optype(p->op);
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;
}
}
 
 
Interface eco32IR = {
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, 0, 0, 0, 0,
{
1, /* max_unaligned_load */
rmap,
blkfetch, blkstore, blkloop,
_label,
_rule,
_nts,
_kids,
_string,
_templates,
_isinstruction,
_ntname,
emit2,
doarg,
target,
clobber
}
};
/eco32.md.SAVE-2
0,0 → 1,1007
%{
 
/*
* eco32.md -- ECO32 back-end specification
*
* register usage:
* $0 always zero
* $1 reserved for assembler
* $2 func return value
* $3 func return value
* $4 proc/func argument
* $5 proc/func argument
* $6 proc/func argument
* $7 proc/func argument
* $8 temporary register (caller-save)
* $9 temporary register (caller-save)
* $10 temporary register (caller-save)
* $11 temporary register (caller-save)
* $12 temporary register (caller-save)
* $13 temporary register (caller-save)
* $14 temporary register (caller-save)
* $15 temporary register (caller-save)
* $16 register variable (callee-save)
* $17 register variable (callee-save)
* $18 register variable (callee-save)
* $19 register variable (callee-save)
* $20 register variable (callee-save)
* $21 register variable (callee-save)
* $22 register variable (callee-save)
* $23 register variable (callee-save)
* $24 temporary register (caller-save)
* $25 temporary register (caller-save)
* $26 reserved for OS kernel
* $27 reserved for OS kernel
* $28 reserved for OS kernel
* $29 stack pointer
* $30 interrupt return address
* $31 proc/func return address
* caller-save registers are not preserved across procedure calls
* callee-save registers are preserved across procedure calls
*
* tree grammar terminals produced by:
* ops c=1 s=2 i=4 l=4 h=4 f=4 d=8 x=8 p=4
*/
 
#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 defaddress(Symbol);
static void defconst(int, int, Value);
static void defstring(int, char *);
static void defsymbol(Symbol);
static void export(Symbol);
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 Symbol rmap(int);
static void blkfetch(int, int, int, int);
static void blkstore(int, int, int, int);
static void blkloop(int, int, int, int, int, int []);
static void emit2(Node);
static void doarg(Node);
static void target(Node);
static void clobber(Node);
 
#define INTTMP 0x0100FF00
#define INTVAR 0x00FF0000
#define INTRET 0x00000004
#define FLTTMP 0x000F0FF0
#define FLTVAR 0xFFF00000
#define FLTRET 0x00000003
 
static Symbol ireg[32];
static Symbol iregw;
static Symbol freg2[32];
static Symbol freg2w;
static Symbol blkreg;
static int tmpregs[] = { 3, 9, 10 };
 
%}
 
%start stmt
 
%term CNSTF4=4113 CNSTF8=8209
%term CNSTI1=1045 CNSTI2=2069 CNSTI4=4117
%term CNSTP4=4119
%term CNSTU1=1046 CNSTU2=2070 CNSTU4=4118
 
%term ARGB=41
%term ARGF4=4129 ARGF8=8225
%term ARGI4=4133
%term ARGP4=4135
%term ARGU4=4134
 
%term ASGNB=57
%term ASGNF4=4145 ASGNF8=8241
%term ASGNI1=1077 ASGNI2=2101 ASGNI4=4149
%term ASGNP4=4151
%term ASGNU1=1078 ASGNU2=2102 ASGNU4=4150
 
%term INDIRB=73
%term INDIRF4=4161 INDIRF8=8257
%term INDIRI1=1093 INDIRI2=2117 INDIRI4=4165
%term INDIRP4=4167
%term INDIRU1=1094 INDIRU2=2118 INDIRU4=4166
 
%term CVFF4=4209 CVFF8=8305
%term CVFI4=4213
 
%term CVIF4=4225 CVIF8=8321
%term CVII1=1157 CVII2=2181 CVII4=4229
%term CVIU1=1158 CVIU2=2182 CVIU4=4230
 
%term CVPU4=4246
 
%term CVUI1=1205 CVUI2=2229 CVUI4=4277
%term CVUP4=4279
%term CVUU1=1206 CVUU2=2230 CVUU4=4278
 
%term NEGF4=4289 NEGF8=8385
%term NEGI4=4293
 
%term CALLB=217
%term CALLF4=4305 CALLF8=8401
%term CALLI4=4309
%term CALLP4=4311
%term CALLU4=4310
%term CALLV=216
 
%term RETF4=4337 RETF8=8433
%term RETI4=4341
%term RETP4=4343
%term RETU4=4342
%term RETV=248
 
%term ADDRGP4=4359
 
%term ADDRFP4=4375
 
%term ADDRLP4=4391
 
%term ADDF4=4401 ADDF8=8497
%term ADDI4=4405
%term ADDP4=4407
%term ADDU4=4406
 
%term SUBF4=4417 SUBF8=8513
%term SUBI4=4421
%term SUBP4=4423
%term SUBU4=4422
 
%term LSHI4=4437
%term LSHU4=4438
 
%term MODI4=4453
%term MODU4=4454
 
%term RSHI4=4469
%term RSHU4=4470
 
%term BANDI4=4485
%term BANDU4=4486
 
%term BCOMI4=4501
%term BCOMU4=4502
 
%term BORI4=4517
%term BORU4=4518
 
%term BXORI4=4533
%term BXORU4=4534
 
%term DIVF4=4545 DIVF8=8641
%term DIVI4=4549
%term DIVU4=4550
 
%term MULF4=4561 MULF8=8657
%term MULI4=4565
%term MULU4=4566
 
%term EQF4=4577 EQF8=8673
%term EQI4=4581
%term EQU4=4582
 
%term GEF4=4593 GEF8=8689
%term GEI4=4597
%term GEU4=4598
 
%term GTF4=4609 GTF8=8705
%term GTI4=4613
%term GTU4=4614
 
%term LEF4=4625 LEF8=8721
%term LEI4=4629
%term LEU4=4630
 
%term LTF4=4641 LTF8=8737
%term LTI4=4645
%term LTU4=4646
 
%term NEF4=4657 NEF8=8753
%term NEI4=4661
%term NEU4=4662
 
%term JUMPV=584
 
%term LABELV=600
 
%term LOADB=233
%term LOADF4=4321 LOADF8=8417
%term LOADI1=1253 LOADI2=2277 LOADI4=4325
%term LOADP4=4327
%term LOADU1=1254 LOADU2=2278 LOADU4=4326
 
%term VREGP=711
 
 
%%
 
 
reg: INDIRI1(VREGP) "# read register\n"
reg: INDIRI2(VREGP) "# read register\n"
reg: INDIRI4(VREGP) "# read register\n"
reg: INDIRP4(VREGP) "# read register\n"
reg: INDIRU1(VREGP) "# read register\n"
reg: INDIRU2(VREGP) "# read register\n"
reg: INDIRU4(VREGP) "# read register\n"
 
stmt: ASGNI1(VREGP,reg) "# write register\n"
stmt: ASGNI2(VREGP,reg) "# write register\n"
stmt: ASGNI4(VREGP,reg) "# write register\n"
stmt: ASGNP4(VREGP,reg) "# write register\n"
stmt: ASGNU1(VREGP,reg) "# write register\n"
stmt: ASGNU2(VREGP,reg) "# write register\n"
stmt: ASGNU4(VREGP,reg) "# write register\n"
 
con: CNSTI1 "%a"
con: CNSTI2 "%a"
con: CNSTI4 "%a"
con: CNSTP4 "%a"
con: CNSTU1 "%a"
con: CNSTU2 "%a"
con: CNSTU4 "%a"
 
stmt: reg ""
 
acon: con "%0"
acon: ADDRGP4 "%a"
 
addr: ADDI4(reg,acon) "$%0,%1"
addr: ADDP4(reg,acon) "$%0,%1"
addr: ADDU4(reg,acon) "$%0,%1"
 
addr: acon "$0,%0"
addr: reg "$%0,0"
addr: ADDRFP4 "$29,%a+%F"
addr: ADDRLP4 "$29,%a+%F"
 
reg: addr "\tadd\t$%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: 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)
 
stmt: ASGNI1(addr,reg) "\tstb\t$%1,%0\n" 1
stmt: ASGNI2(addr,reg) "\tsth\t$%1,%0\n" 1
stmt: ASGNI4(addr,reg) "\tstw\t$%1,%0\n" 1
stmt: ASGNP4(addr,reg) "\tstw\t$%1,%0\n" 1
stmt: ASGNU1(addr,reg) "\tstb\t$%1,%0\n" 1
stmt: ASGNU2(addr,reg) "\tsth\t$%1,%0\n" 1
stmt: ASGNU4(addr,reg) "\tstw\t$%1,%0\n" 1
 
reg: INDIRI1(addr) "\tldb\t$%c,%0\n" 1
reg: INDIRI2(addr) "\tldh\t$%c,%0\n" 1
reg: INDIRI4(addr) "\tldw\t$%c,%0\n" 1
reg: INDIRP4(addr) "\tldw\t$%c,%0\n" 1
reg: INDIRU1(addr) "\tldbu\t$%c,%0\n" 1
reg: INDIRU2(addr) "\tldhu\t$%c,%0\n" 1
reg: INDIRU4(addr) "\tldw\t$%c,%0\n" 1
 
reg: CVII4(INDIRI1(addr)) "\tldb\t$%c,%0\n" 1
reg: CVII4(INDIRI2(addr)) "\tldh\t$%c,%0\n" 1
reg: CVUU4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1
reg: CVUU4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1
reg: CVUI4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1
reg: CVUI4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1
 
rc: con "%0"
rc: reg "$%0"
 
reg: ADDI4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1
reg: ADDP4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1
reg: ADDU4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1
reg: SUBI4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1
reg: SUBP4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1
reg: SUBU4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1
reg: NEGI4(reg) "\tsub\t$%c,$0,$%0\n" 1
 
reg: MULI4(reg,rc) "\tmul\t$%c,$%0,%1\n" 1
reg: MULU4(reg,rc) "\tmulu\t$%c,$%0,%1\n" 1
reg: DIVI4(reg,rc) "\tdiv\t$%c,$%0,%1\n" 1
reg: DIVU4(reg,rc) "\tdivu\t$%c,$%0,%1\n" 1
reg: MODI4(reg,rc) "\trem\t$%c,$%0,%1\n" 1
reg: MODU4(reg,rc) "\tremu\t$%c,$%0,%1\n" 1
 
reg: BANDI4(reg,rc) "\tand\t$%c,$%0,%1\n" 1
reg: BANDU4(reg,rc) "\tand\t$%c,$%0,%1\n" 1
reg: BORI4(reg,rc) "\tor\t$%c,$%0,%1\n" 1
reg: BORU4(reg,rc) "\tor\t$%c,$%0,%1\n" 1
reg: BXORI4(reg,rc) "\txor\t$%c,$%0,%1\n" 1
reg: BXORU4(reg,rc) "\txor\t$%c,$%0,%1\n" 1
reg: BCOMI4(reg) "\txnor\t$%c,$0,$%0\n" 1
reg: BCOMU4(reg) "\txnor\t$%c,$0,$%0\n" 1
 
rc5: CNSTI4 "%a" range(a, 0, 31)
rc5: reg "$%0"
 
reg: LSHI4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1
reg: LSHU4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1
reg: RSHI4(reg,rc5) "\tsar\t$%c,$%0,%1\n" 1
reg: RSHU4(reg,rc5) "\tslr\t$%c,$%0,%1\n" 1
 
reg: LOADI1(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADI2(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADI4(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADP4(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADU1(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADU2(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADU4(reg) "\tadd\t$%c,$0,$%0\n" move(a)
 
reg: CVII4(reg) "\tsll\t$%c,$%0,8*(4-%a)\n\tsar\t$%c,$%c,8*(4-%a)\n" 2
reg: CVUI4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1
reg: CVUU4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1
 
stmt: LABELV "%a:\n"
stmt: JUMPV(acon) "\tj\t%0\n" 1
stmt: JUMPV(reg) "\tjr\t$%0\n" 1
 
stmt: EQI4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1
stmt: EQU4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1
stmt: NEI4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1
stmt: NEU4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1
stmt: LEI4(reg,reg) "\tble\t$%0,$%1,%a\n" 1
stmt: LEU4(reg,reg) "\tbleu\t$%0,$%1,%a\n" 1
stmt: LTI4(reg,reg) "\tblt\t$%0,$%1,%a\n" 1
stmt: LTU4(reg,reg) "\tbltu\t$%0,$%1,%a\n" 1
stmt: GEI4(reg,reg) "\tbge\t$%0,$%1,%a\n" 1
stmt: GEU4(reg,reg) "\tbgeu\t$%0,$%1,%a\n" 1
stmt: GTI4(reg,reg) "\tbgt\t$%0,$%1,%a\n" 1
stmt: GTU4(reg,reg) "\tbgtu\t$%0,$%1,%a\n" 1
 
reg: CALLI4(ar) "\tjal\t%0\n" 1
reg: CALLP4(ar) "\tjal\t%0\n" 1
reg: CALLU4(ar) "\tjal\t%0\n" 1
stmt: CALLV(ar) "\tjal\t%0\n" 1
 
ar: ADDRGP4 "%a"
ar: reg "$%0"
ar: CNSTP4 "%a" range(a, 0, 0x03FFFFFF)
 
stmt: RETI4(reg) "# ret\n" 1
stmt: RETP4(reg) "# ret\n" 1
stmt: RETU4(reg) "# ret\n" 1
stmt: RETV(reg) "# ret\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
 
reg: INDIRF4(VREGP) "# read register\n"
stmt: ASGNF4(VREGP,reg) "# write register\n"
reg: INDIRF4(addr) ";FP: l.s $f%c,%0\n" 1
stmt: ASGNF4(addr,reg) ";FP: s.s $f%1,%0\n" 1
reg: ADDF4(reg,reg) ";FP: add.s $f%c,$f%0,$f%1\n" 1
reg: SUBF4(reg,reg) ";FP: sub.s $f%c,$f%0,$f%1\n" 1
reg: MULF4(reg,reg) ";FP: mul.s $f%c,$f%0,$f%1\n" 1
reg: DIVF4(reg,reg) ";FP: div.s $f%c,$f%0,$f%1\n" 1
reg: LOADF4(reg) ";FP: mov.s $f%c,$f%0\n" 1
reg: NEGF4(reg) ";FP: neg.s $f%c,$f%0\n" 1
reg: CVFF4(reg) ";FP: cvt.s.d $f%c,$f%0\n" 1
reg: CVIF4(reg) ";FP: mtc1 $%0,$f%c; cvt.s.w $f%c,$f%c\n" 1
reg: CVFI4(reg) ";FP: trunc.w.s $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i == 4 ? 1 : LBURG_MAX)
stmt: EQF4(reg,reg) ";FP: c.eq.s $f%0,$f%1; bc1t %a\n" 1
stmt: LEF4(reg,reg) ";FP: c.ule.s $f%0,$f%1; bc1t %a\n" 1
stmt: LTF4(reg,reg) ";FP: c.ult.s $f%0,$f%1; bc1t %a\n" 1
stmt: GEF4(reg,reg) ";FP: c.lt.s $f%0,$f%1; bc1f %a\n" 1
stmt: GTF4(reg,reg) ";FP: c.le.s $f%0,$f%1; bc1f %a\n" 1
stmt: NEF4(reg,reg) ";FP: c.eq.s $f%0,$f%1; bc1f %a\n" 1
reg: CALLF4(ar) "\tjal\t%0\n" 1
stmt: RETF4(reg) "# ret\n" 1
stmt: ARGF4(reg) "# arg\n" 1
 
reg: INDIRF8(VREGP) "# read register\n"
stmt: ASGNF8(VREGP,reg) "# write register\n"
reg: INDIRF8(addr) ";FP: l.d $f%c,%0\n" 1
stmt: ASGNF8(addr,reg) ";FP: s.d $f%1,%0\n" 1
reg: ADDF8(reg,reg) ";FP: add.d $f%c,$f%0,$f%1\n" 1
reg: SUBF8(reg,reg) ";FP: sub.d $f%c,$f%0,$f%1\n" 1
reg: MULF8(reg,reg) ";FP: mul.d $f%c,$f%0,$f%1\n" 1
reg: DIVF8(reg,reg) ";FP: div.d $f%c,$f%0,$f%1\n" 1
reg: LOADF8(reg) ";FP: mov.d $f%c,$f%0\n" 1
reg: NEGF8(reg) ";FP: neg.d $f%c,$f%0\n" 1
reg: CVFF8(reg) ";FP: cvt.d.s $f%c,$f%0\n" 1
reg: CVIF8(reg) ";FP: mtc1 $%0,$f%c; cvt.d.w $f%c,$f%c\n" 1
reg: CVFI4(reg) ";FP: trunc.w.d $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i == 8 ? 1 : LBURG_MAX)
stmt: EQF8(reg,reg) ";FP: c.eq.d $f%0,$f%1; bc1t %a\n" 1
stmt: LEF8(reg,reg) ";FP: c.ule.d $f%0,$f%1; bc1t %a\n" 1
stmt: LTF8(reg,reg) ";FP: c.ult.d $f%0,$f%1; bc1t %a\n" 1
stmt: GEF8(reg,reg) ";FP: c.lt.d $f%0,$f%1; bc1f %a\n" 1
stmt: GTF8(reg,reg) ";FP: c.le.d $f%0,$f%1; bc1f %a\n" 1
stmt: NEF8(reg,reg) ";FP: c.eq.d $f%0,$f%1; bc1f %a\n" 1
reg: CALLF8(ar) "\tjal\t%0\n" 1
stmt: RETF8(reg) "# ret\n" 1
stmt: ARGF8(reg) "# arg\n" 1
 
 
%%
 
 
static void address(Symbol s1, Symbol s2, long n) {
if (s2->scope == GLOBAL ||
s2->sclass == STATIC ||
s2->sclass == EXTERN) {
s1->x.name = stringf("%s%s%D", s2->x.name, n >= 0 ? "+" : "", n);
} else {
assert(n >= INT_MIN && n <= INT_MAX);
s1->x.offset = s2->x.offset + n;
s1->x.name = stringd(s1->x.offset);
}
}
 
 
static void defaddress(Symbol s) {
print("\t.word\t%s\n", s->x.name);
}
 
 
static void defconst(int suffix, int size, Value v) {
float f;
double d;
unsigned *p;
 
if (suffix == F && size == 4) {
f = v.d;
print("\t.word\t0x%x\n", * (unsigned *) &f);
} else
if (suffix == F && size == 8) {
d = v.d;
p = (unsigned *) &d;
print("\t.word\t0x%x\n", p[swap]);
print("\t.word\t0x%x\n", p[1 - swap]);
} else
if (suffix == P) {
print("\t.word\t0x%x\n", (unsigned) v.p);
} else
if (size == 1) {
print("\t.byte\t0x%x\n",
(unsigned) ((unsigned char) (suffix == I ? v.i : v.u)));
} else
if (size == 2) {
print("\t.half\t0x%x\n",
(unsigned) ((unsigned short) (suffix == I ? v.i : v.u)));
} else
if (size == 4) {
print("\t.word\t0x%x\n", (unsigned) (suffix == I ? v.i : v.u));
}
}
 
 
static void defstring(int n, char *str) {
char *s;
 
for (s = str; s < str + n; s++) {
print("\t.byte\t0x%x\n", (*s) & 0xFF);
}
}
 
 
static void defsymbol(Symbol s) {
if (s->scope >= LOCAL && s->sclass == STATIC) {
s->x.name = stringf("L.%d", genlabel(1));
} else
if (s->generated) {
s->x.name = stringf("L.%s", s->name);
} else {
assert(s->scope != CONSTANTS || isint(s->type) || isptr(s->type));
s->x.name = s->name;
}
}
 
 
static void export(Symbol s) {
print("\t.export\t%s\n", s->name);
}
 
 
static int bitcount(unsigned mask) {
unsigned i, n;
 
n = 0;
for (i = 1; i != 0; i <<= 1) {
if (mask & i) {
n++;
}
}
return n;
}
 
 
static Symbol argreg(int argno, int offset, int ty, int sz, int ty0) {
assert((offset & 3) == 0);
if (offset > 12) {
return NULL;
}
return ireg[(offset / 4) + 4];
}
 
 
static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
int i;
Symbol p, q;
Symbol r;
int sizeisave;
int saved;
Symbol argregs[4];
 
usedmask[0] = usedmask[1] = 0;
freemask[0] = freemask[1] = ~((unsigned) 0);
offset = 0;
maxoffset = 0;
maxargoffset = 0;
for (i = 0; callee[i] != NULL; i++) {
p = callee[i];
q = caller[i];
assert(q != NULL);
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 (variadic(f->type)) {
p->sclass = AUTO;
} else
if (r != NULL && 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] == NULL);
offset = 0;
gencode(caller, callee);
if (ncalls != 0) {
usedmask[IREG] |= ((unsigned) 1) << 31;
}
usedmask[IREG] &= 0x80FF0000;
usedmask[FREG] &= 0xFFF00000;
maxargoffset = roundup(maxargoffset, 4);
if (ncalls != 0 && maxargoffset < 16) {
maxargoffset = 16;
}
sizeisave = 4 * bitcount(usedmask[IREG]);
framesize = roundup(maxargoffset + sizeisave + maxoffset, 16);
segment(CODE);
print("\t.align\t4\n");
print("%s:\n", f->x.name);
if (framesize > 0) {
print("\tsub\t$29,$29,%d\n", framesize);
}
saved = maxargoffset;
for (i = 16; i < 32; i++) {
if (usedmask[IREG] & (1 << i)) {
print("\tstw\t$%d,$29,%d\n", i, saved);
saved += 4;
}
}
for (i = 0; i < 4 && callee[i] != NULL; 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;
print("\tadd\t$%d,$0,$%d\n", outn, rn);
} else {
int off = in->x.offset + framesize;
int n = (in->type->size + 3) / 4;
int i;
for (i = rn; i < rn + n && i <= 7; i++) {
print("\tstw\t$%d,$29,%d\n", i, off + (i - rn) * 4);
}
}
}
}
if (variadic(f->type) && callee[i - 1] != NULL) {
i = callee[i - 1]->x.offset + callee[i - 1]->type->size;
for (i = roundup(i, 4)/4; i <= 3; i++) {
print("\tstw\t$%d,$29,%d\n", i + 4, framesize + 4 * i);
}
}
emitcode();
saved = maxargoffset;
for (i = 16; i < 32; i++) {
if (usedmask[IREG] & (1 << i)) {
print("\tldw\t$%d,$29,%d\n", i, saved);
saved += 4;
}
}
if (framesize > 0) {
print("\tadd\t$29,$29,%d\n", framesize);
}
print("\tjr\t$31\n");
print("\n");
}
 
 
static void global(Symbol s) {
if (s->type->align != 0) {
print("\t.align\t%d\n", s->type->align);
} else {
print("\t.align\t%d\n", 4);
}
print("%s:\n", s->x.name);
}
 
 
static void import(Symbol s) {
print("\t.import\t%s\n", s->name);
}
 
 
static void local(Symbol s) {
if (askregvar(s, rmap(ttob(s->type))) == 0) {
mkauto(s);
}
}
 
 
static void setSwap(void) {
union {
char c;
int i;
} u;
 
u.i = 0;
u.c = 1;
swap = ((u.i == 1) != IR->little_endian);
}
 
 
static void progbeg(int argc, char *argv[]) {
int i;
 
setSwap();
segment(CODE);
parseflags(argc, argv);
for (i = 0; i < 32; i++) {
ireg[i] = mkreg("%d", i, 1, IREG);
}
iregw = mkwildcard(ireg);
for (i = 0; i < 32; i += 2) {
freg2[i] = mkreg("%d", i, 3, FREG);
}
freg2w = mkwildcard(freg2);
tmask[IREG] = INTTMP;
vmask[IREG] = INTVAR;
tmask[FREG] = FLTTMP;
vmask[FREG] = FLTVAR;
blkreg = mkreg("8", 8, 7, IREG);
}
 
 
static void progend(void) {
}
 
 
static void segment(int n) {
static int currSeg = -1;
int newSeg;
 
switch (n) {
case CODE:
newSeg = CODE;
break;
case BSS:
newSeg = BSS;
break;
case DATA:
newSeg = DATA;
break;
case LIT:
newSeg = DATA;
break;
}
if (currSeg == newSeg) {
return;
}
switch (newSeg) {
case CODE:
print("\t.code\n");
break;
case BSS:
print("\t.bss\n");
break;
case DATA:
print("\t.data\n");
break;
}
currSeg = newSeg;
}
 
 
static void space(int n) {
print("\t.space\t%d\n", n);
}
 
 
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 blkfetch(int size, int off, int reg, int tmp) {
assert(size == 1 || size == 2 || size == 4);
if (size == 1) {
print("\tldbu\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 2) {
print("\tldhu\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 4) {
print("\tldw\t$%d,$%d,%d\n", tmp, reg, off);
}
}
 
 
static void blkstore(int size, int off, int reg, int tmp) {
assert(size == 1 || size == 2 || size == 4);
if (size == 1) {
print("\tstb\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 2) {
print("\tsth\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 4) {
print("\tstw\t$%d,$%d,%d\n", tmp, reg, off);
}
}
 
 
static void blkloop(int dreg, int doff,
int sreg, int soff,
int size, int tmps[]) {
int label;
 
label = genlabel(1);
print("\tadd\t$%d,$%d,%d\n", sreg, sreg, size & ~7);
print("\tadd\t$%d,$%d,%d\n", tmps[2], dreg, size & ~7);
blkcopy(tmps[2], doff, sreg, soff, size & 7, tmps);
print("L.%d:\n", label);
print("\tsub\t$%d,$%d,%d\n", sreg, sreg, 8);
print("\tsub\t$%d,$%d,%d\n", tmps[2], tmps[2], 8);
blkcopy(tmps[2], doff, sreg, soff, 8, tmps);
print("\tbltu\t$%d,$%d,L.%d\n", dreg, tmps[2], label);
}
 
 
static void emit2(Node p) {
static int ty0;
int ty, sz;
Symbol q;
int src;
int dst, n;
 
switch (specific(p->op)) {
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) {
print("\tstw\t$%d,$29,%d\n", src, p->syms[2]->u.c.v.i);
}
break;
case ASGN+B:
dalign = p->syms[1]->u.c.v.i;
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("\tldw\t$%d,$29,%d\n", (dst / 4) + 4, dst);
}
break;
}
}
 
 
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 target(Node p) {
static int ty0;
int ty;
Symbol q;
 
assert(p);
switch (specific(p->op)) {
case CNST+I:
case CNST+P:
case CNST+U:
if (range(p, 0, 0) == 0) {
setreg(p, ireg[0]);
p->x.registered = 1;
}
break;
case CALL+I:
case CALL+P:
case CALL+U:
rtarget(p, 0, ireg[25]);
setreg(p, ireg[2]);
break;
case CALL+F:
rtarget(p, 0, ireg[25]);
setreg(p, freg2[0]);
break;
case CALL+V:
rtarget(p, 0, ireg[25]);
break;
case RET+I:
case RET+P:
case RET+U:
rtarget(p, 0, ireg[2]);
break;
case RET+F:
rtarget(p, 0, freg2[0]);
break;
case ARG+I:
case ARG+P:
case ARG+U:
case ARG+F:
ty = optype(p->op);
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;
}
}
 
 
Interface eco32IR = {
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, 0, 0, 0, 0,
{
1, /* max_unaligned_load */
rmap,
blkfetch, blkstore, blkloop,
_label,
_rule,
_nts,
_kids,
_string,
_templates,
_isinstruction,
_ntname,
emit2,
doarg,
target,
clobber
}
};
/eco32.md.SAVE-3
0,0 → 1,1014
%{
 
/*
* eco32.md -- ECO32 back-end specification
*
* register usage:
* $0 always zero
* $1 reserved for assembler
* $2 func return value
* $3 func return value
* $4 proc/func argument
* $5 proc/func argument
* $6 proc/func argument
* $7 proc/func argument
* $8 temporary register (caller-save)
* $9 temporary register (caller-save)
* $10 temporary register (caller-save)
* $11 temporary register (caller-save)
* $12 temporary register (caller-save)
* $13 temporary register (caller-save)
* $14 temporary register (caller-save)
* $15 temporary register (caller-save)
* $16 register variable (callee-save)
* $17 register variable (callee-save)
* $18 register variable (callee-save)
* $19 register variable (callee-save)
* $20 register variable (callee-save)
* $21 register variable (callee-save)
* $22 register variable (callee-save)
* $23 register variable (callee-save)
* $24 temporary register (caller-save)
* $25 temporary register (caller-save)
* $26 reserved for OS kernel
* $27 reserved for OS kernel
* $28 reserved for OS kernel
* $29 stack pointer
* $30 interrupt return address
* $31 proc/func return address
* caller-save registers are not preserved across procedure calls
* callee-save registers are preserved across procedure calls
*
* tree grammar terminals produced by:
* ops c=1 s=2 i=4 l=4 h=4 f=4 d=8 x=8 p=4
*/
 
#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 defaddress(Symbol);
static void defconst(int, int, Value);
static void defstring(int, char *);
static void defsymbol(Symbol);
static void export(Symbol);
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 Symbol rmap(int);
static void blkfetch(int, int, int, int);
static void blkstore(int, int, int, int);
static void blkloop(int, int, int, int, int, int []);
static void emit2(Node);
static void doarg(Node);
static void target(Node);
static void clobber(Node);
 
#define INTTMP 0x0100FF00
#define INTVAR 0x00FF0000
#define INTRET 0x00000004
#define FLTTMP 0x000F0FF0
#define FLTVAR 0xFFF00000
#define FLTRET 0x00000003
 
static Symbol ireg[32];
static Symbol iregw;
static Symbol freg2[32];
static Symbol freg2w;
static Symbol blkreg;
static int tmpregs[] = { 3, 9, 10 };
 
%}
 
%start stmt
 
%term CNSTF4=4113 CNSTF8=8209
%term CNSTI1=1045 CNSTI2=2069 CNSTI4=4117
%term CNSTP4=4119
%term CNSTU1=1046 CNSTU2=2070 CNSTU4=4118
 
%term ARGB=41
%term ARGF4=4129 ARGF8=8225
%term ARGI4=4133
%term ARGP4=4135
%term ARGU4=4134
 
%term ASGNB=57
%term ASGNF4=4145 ASGNF8=8241
%term ASGNI1=1077 ASGNI2=2101 ASGNI4=4149
%term ASGNP4=4151
%term ASGNU1=1078 ASGNU2=2102 ASGNU4=4150
 
%term INDIRB=73
%term INDIRF4=4161 INDIRF8=8257
%term INDIRI1=1093 INDIRI2=2117 INDIRI4=4165
%term INDIRP4=4167
%term INDIRU1=1094 INDIRU2=2118 INDIRU4=4166
 
%term CVFF4=4209 CVFF8=8305
%term CVFI4=4213
 
%term CVIF4=4225 CVIF8=8321
%term CVII1=1157 CVII2=2181 CVII4=4229
%term CVIU1=1158 CVIU2=2182 CVIU4=4230
 
%term CVPU4=4246
 
%term CVUI1=1205 CVUI2=2229 CVUI4=4277
%term CVUP4=4279
%term CVUU1=1206 CVUU2=2230 CVUU4=4278
 
%term NEGF4=4289 NEGF8=8385
%term NEGI4=4293
 
%term CALLB=217
%term CALLF4=4305 CALLF8=8401
%term CALLI4=4309
%term CALLP4=4311
%term CALLU4=4310
%term CALLV=216
 
%term RETF4=4337 RETF8=8433
%term RETI4=4341
%term RETP4=4343
%term RETU4=4342
%term RETV=248
 
%term ADDRGP4=4359
 
%term ADDRFP4=4375
 
%term ADDRLP4=4391
 
%term ADDF4=4401 ADDF8=8497
%term ADDI4=4405
%term ADDP4=4407
%term ADDU4=4406
 
%term SUBF4=4417 SUBF8=8513
%term SUBI4=4421
%term SUBP4=4423
%term SUBU4=4422
 
%term LSHI4=4437
%term LSHU4=4438
 
%term MODI4=4453
%term MODU4=4454
 
%term RSHI4=4469
%term RSHU4=4470
 
%term BANDI4=4485
%term BANDU4=4486
 
%term BCOMI4=4501
%term BCOMU4=4502
 
%term BORI4=4517
%term BORU4=4518
 
%term BXORI4=4533
%term BXORU4=4534
 
%term DIVF4=4545 DIVF8=8641
%term DIVI4=4549
%term DIVU4=4550
 
%term MULF4=4561 MULF8=8657
%term MULI4=4565
%term MULU4=4566
 
%term EQF4=4577 EQF8=8673
%term EQI4=4581
%term EQU4=4582
 
%term GEF4=4593 GEF8=8689
%term GEI4=4597
%term GEU4=4598
 
%term GTF4=4609 GTF8=8705
%term GTI4=4613
%term GTU4=4614
 
%term LEF4=4625 LEF8=8721
%term LEI4=4629
%term LEU4=4630
 
%term LTF4=4641 LTF8=8737
%term LTI4=4645
%term LTU4=4646
 
%term NEF4=4657 NEF8=8753
%term NEI4=4661
%term NEU4=4662
 
%term JUMPV=584
 
%term LABELV=600
 
%term LOADB=233
%term LOADF4=4321 LOADF8=8417
%term LOADI1=1253 LOADI2=2277 LOADI4=4325
%term LOADP4=4327
%term LOADU1=1254 LOADU2=2278 LOADU4=4326
 
%term VREGP=711
 
 
%%
 
 
reg: INDIRI1(VREGP) "# read register\n"
reg: INDIRI2(VREGP) "# read register\n"
reg: INDIRI4(VREGP) "# read register\n"
reg: INDIRP4(VREGP) "# read register\n"
reg: INDIRU1(VREGP) "# read register\n"
reg: INDIRU2(VREGP) "# read register\n"
reg: INDIRU4(VREGP) "# read register\n"
 
stmt: ASGNI1(VREGP,reg) "# write register\n"
stmt: ASGNI2(VREGP,reg) "# write register\n"
stmt: ASGNI4(VREGP,reg) "# write register\n"
stmt: ASGNP4(VREGP,reg) "# write register\n"
stmt: ASGNU1(VREGP,reg) "# write register\n"
stmt: ASGNU2(VREGP,reg) "# write register\n"
stmt: ASGNU4(VREGP,reg) "# write register\n"
 
con: CNSTI1 "%a"
con: CNSTI2 "%a"
con: CNSTI4 "%a"
con: CNSTP4 "%a"
con: CNSTU1 "%a"
con: CNSTU2 "%a"
con: CNSTU4 "%a"
 
stmt: reg ""
 
acon: con "%0"
acon: ADDRGP4 "%a"
 
addr: ADDI4(reg,acon) "$%0,%1"
addr: ADDP4(reg,acon) "$%0,%1"
addr: ADDU4(reg,acon) "$%0,%1"
 
addr: acon "$0,%0"
addr: reg "$%0,0"
addr: ADDRFP4 "$29,%a+%F"
addr: ADDRLP4 "$29,%a+%F"
 
reg: addr "\tadd\t$%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: 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)
 
stmt: ASGNI1(addr,reg) "\tstb\t$%1,%0\n" 1
stmt: ASGNI2(addr,reg) "\tsth\t$%1,%0\n" 1
stmt: ASGNI4(addr,reg) "\tstw\t$%1,%0\n" 1
stmt: ASGNP4(addr,reg) "\tstw\t$%1,%0\n" 1
stmt: ASGNU1(addr,reg) "\tstb\t$%1,%0\n" 1
stmt: ASGNU2(addr,reg) "\tsth\t$%1,%0\n" 1
stmt: ASGNU4(addr,reg) "\tstw\t$%1,%0\n" 1
 
reg: INDIRI1(addr) "\tldb\t$%c,%0\n" 1
reg: INDIRI2(addr) "\tldh\t$%c,%0\n" 1
reg: INDIRI4(addr) "\tldw\t$%c,%0\n" 1
reg: INDIRP4(addr) "\tldw\t$%c,%0\n" 1
reg: INDIRU1(addr) "\tldbu\t$%c,%0\n" 1
reg: INDIRU2(addr) "\tldhu\t$%c,%0\n" 1
reg: INDIRU4(addr) "\tldw\t$%c,%0\n" 1
 
reg: CVII4(INDIRI1(addr)) "\tldb\t$%c,%0\n" 1
reg: CVII4(INDIRI2(addr)) "\tldh\t$%c,%0\n" 1
reg: CVUU4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1
reg: CVUU4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1
reg: CVUI4(INDIRU1(addr)) "\tldbu\t$%c,%0\n" 1
reg: CVUI4(INDIRU2(addr)) "\tldhu\t$%c,%0\n" 1
 
rc: con "%0"
rc: reg "$%0"
 
reg: ADDI4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1
reg: ADDP4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1
reg: ADDU4(reg,rc) "\tadd\t$%c,$%0,%1\n" 1
reg: SUBI4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1
reg: SUBP4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1
reg: SUBU4(reg,rc) "\tsub\t$%c,$%0,%1\n" 1
reg: NEGI4(reg) "\tsub\t$%c,$0,$%0\n" 1
 
reg: MULI4(reg,rc) "\tmul\t$%c,$%0,%1\n" 1
reg: MULU4(reg,rc) "\tmulu\t$%c,$%0,%1\n" 1
reg: DIVI4(reg,rc) "\tdiv\t$%c,$%0,%1\n" 1
reg: DIVU4(reg,rc) "\tdivu\t$%c,$%0,%1\n" 1
reg: MODI4(reg,rc) "\trem\t$%c,$%0,%1\n" 1
reg: MODU4(reg,rc) "\tremu\t$%c,$%0,%1\n" 1
 
reg: BANDI4(reg,rc) "\tand\t$%c,$%0,%1\n" 1
reg: BANDU4(reg,rc) "\tand\t$%c,$%0,%1\n" 1
reg: BORI4(reg,rc) "\tor\t$%c,$%0,%1\n" 1
reg: BORU4(reg,rc) "\tor\t$%c,$%0,%1\n" 1
reg: BXORI4(reg,rc) "\txor\t$%c,$%0,%1\n" 1
reg: BXORU4(reg,rc) "\txor\t$%c,$%0,%1\n" 1
reg: BCOMI4(reg) "\txnor\t$%c,$0,$%0\n" 1
reg: BCOMU4(reg) "\txnor\t$%c,$0,$%0\n" 1
 
rc5: CNSTI4 "%a" range(a, 0, 31)
rc5: reg "$%0"
 
reg: LSHI4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1
reg: LSHU4(reg,rc5) "\tsll\t$%c,$%0,%1\n" 1
reg: RSHI4(reg,rc5) "\tsar\t$%c,$%0,%1\n" 1
reg: RSHU4(reg,rc5) "\tslr\t$%c,$%0,%1\n" 1
 
reg: LOADI1(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADI2(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADI4(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADP4(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADU1(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADU2(reg) "\tadd\t$%c,$0,$%0\n" move(a)
reg: LOADU4(reg) "\tadd\t$%c,$0,$%0\n" move(a)
 
reg: CVII4(reg) "\tsll\t$%c,$%0,8*(4-%a)\n\tsar\t$%c,$%c,8*(4-%a)\n" 2
reg: CVUI4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1
reg: CVUU4(reg) "\tand\t$%c,$%0,(1<<(8*%a))-1\n" 1
 
stmt: LABELV "%a:\n"
stmt: JUMPV(acon) "\tj\t%0\n" 1
stmt: JUMPV(reg) "\tjr\t$%0\n" 1
 
stmt: EQI4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1
stmt: EQU4(reg,reg) "\tbeq\t$%0,$%1,%a\n" 1
stmt: NEI4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1
stmt: NEU4(reg,reg) "\tbne\t$%0,$%1,%a\n" 1
stmt: LEI4(reg,reg) "\tble\t$%0,$%1,%a\n" 1
stmt: LEU4(reg,reg) "\tbleu\t$%0,$%1,%a\n" 1
stmt: LTI4(reg,reg) "\tblt\t$%0,$%1,%a\n" 1
stmt: LTU4(reg,reg) "\tbltu\t$%0,$%1,%a\n" 1
stmt: GEI4(reg,reg) "\tbge\t$%0,$%1,%a\n" 1
stmt: GEU4(reg,reg) "\tbgeu\t$%0,$%1,%a\n" 1
stmt: GTI4(reg,reg) "\tbgt\t$%0,$%1,%a\n" 1
stmt: GTU4(reg,reg) "\tbgtu\t$%0,$%1,%a\n" 1
 
reg: CALLI4(ar) "\tjal\t%0\n" 1
reg: CALLP4(ar) "\tjal\t%0\n" 1
reg: CALLU4(ar) "\tjal\t%0\n" 1
stmt: CALLV(ar) "\tjal\t%0\n" 1
 
ar: ADDRGP4 "%a"
ar: reg "$%0"
ar: CNSTP4 "%a" range(a, 0, 0x03FFFFFF)
 
stmt: RETI4(reg) "# ret\n" 1
stmt: RETP4(reg) "# ret\n" 1
stmt: RETU4(reg) "# ret\n" 1
stmt: RETV(reg) "# ret\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
 
reg: INDIRF4(VREGP) "# read register\n"
stmt: ASGNF4(VREGP,reg) "# write register\n"
reg: INDIRF4(addr) ";FP: l.s $f%c,%0\n" 1
stmt: ASGNF4(addr,reg) ";FP: s.s $f%1,%0\n" 1
reg: ADDF4(reg,reg) ";FP: add.s $f%c,$f%0,$f%1\n" 1
reg: SUBF4(reg,reg) ";FP: sub.s $f%c,$f%0,$f%1\n" 1
reg: MULF4(reg,reg) ";FP: mul.s $f%c,$f%0,$f%1\n" 1
reg: DIVF4(reg,reg) ";FP: div.s $f%c,$f%0,$f%1\n" 1
reg: LOADF4(reg) ";FP: mov.s $f%c,$f%0\n" 1
reg: NEGF4(reg) ";FP: neg.s $f%c,$f%0\n" 1
reg: CVFF4(reg) ";FP: cvt.s.d $f%c,$f%0\n" 1
reg: CVIF4(reg) ";FP: mtc1 $%0,$f%c; cvt.s.w $f%c,$f%c\n" 1
reg: CVFI4(reg) ";FP: trunc.w.s $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i == 4 ? 1 : LBURG_MAX)
stmt: EQF4(reg,reg) ";FP: c.eq.s $f%0,$f%1; bc1t %a\n" 1
stmt: LEF4(reg,reg) ";FP: c.ule.s $f%0,$f%1; bc1t %a\n" 1
stmt: LTF4(reg,reg) ";FP: c.ult.s $f%0,$f%1; bc1t %a\n" 1
stmt: GEF4(reg,reg) ";FP: c.lt.s $f%0,$f%1; bc1f %a\n" 1
stmt: GTF4(reg,reg) ";FP: c.le.s $f%0,$f%1; bc1f %a\n" 1
stmt: NEF4(reg,reg) ";FP: c.eq.s $f%0,$f%1; bc1f %a\n" 1
reg: CALLF4(ar) "\tjal\t%0\n" 1
stmt: RETF4(reg) "# ret\n" 1
stmt: ARGF4(reg) "# arg\n" 1
 
reg: INDIRF8(VREGP) "# read register\n"
stmt: ASGNF8(VREGP,reg) "# write register\n"
reg: INDIRF8(addr) ";FP: l.d $f%c,%0\n" 1
stmt: ASGNF8(addr,reg) ";FP: s.d $f%1,%0\n" 1
reg: ADDF8(reg,reg) ";FP: add.d $f%c,$f%0,$f%1\n" 1
reg: SUBF8(reg,reg) ";FP: sub.d $f%c,$f%0,$f%1\n" 1
reg: MULF8(reg,reg) ";FP: mul.d $f%c,$f%0,$f%1\n" 1
reg: DIVF8(reg,reg) ";FP: div.d $f%c,$f%0,$f%1\n" 1
reg: LOADF8(reg) ";FP: mov.d $f%c,$f%0\n" 1
reg: NEGF8(reg) ";FP: neg.d $f%c,$f%0\n" 1
reg: CVFF8(reg) ";FP: cvt.d.s $f%c,$f%0\n" 1
reg: CVIF8(reg) ";FP: mtc1 $%0,$f%c; cvt.d.w $f%c,$f%c\n" 1
reg: CVFI4(reg) ";FP: trunc.w.d $f2,$f%0,$%c; mfc1 $%c,$f2\n" (a->syms[0]->u.c.v.i == 8 ? 1 : LBURG_MAX)
stmt: EQF8(reg,reg) ";FP: c.eq.d $f%0,$f%1; bc1t %a\n" 1
stmt: LEF8(reg,reg) ";FP: c.ule.d $f%0,$f%1; bc1t %a\n" 1
stmt: LTF8(reg,reg) ";FP: c.ult.d $f%0,$f%1; bc1t %a\n" 1
stmt: GEF8(reg,reg) ";FP: c.lt.d $f%0,$f%1; bc1f %a\n" 1
stmt: GTF8(reg,reg) ";FP: c.le.d $f%0,$f%1; bc1f %a\n" 1
stmt: NEF8(reg,reg) ";FP: c.eq.d $f%0,$f%1; bc1f %a\n" 1
reg: CALLF8(ar) "\tjal\t%0\n" 1
stmt: RETF8(reg) "# ret\n" 1
stmt: ARGF8(reg) "# arg\n" 1
 
 
%%
 
 
static void address(Symbol s1, Symbol s2, long n) {
if (s2->scope == GLOBAL ||
s2->sclass == STATIC ||
s2->sclass == EXTERN) {
s1->x.name = stringf("%s%s%D", s2->x.name, n >= 0 ? "+" : "", n);
} else {
assert(n >= INT_MIN && n <= INT_MAX);
s1->x.offset = s2->x.offset + n;
s1->x.name = stringd(s1->x.offset);
}
}
 
 
static void defaddress(Symbol s) {
print("\t.word\t%s\n", s->x.name);
}
 
 
static void defconst(int suffix, int size, Value v) {
float f;
double d;
unsigned *p;
 
if (suffix == F && size == 4) {
f = v.d;
print("\t.word\t0x%x\n", * (unsigned *) &f);
} else
if (suffix == F && size == 8) {
d = v.d;
p = (unsigned *) &d;
print("\t.word\t0x%x\n", p[swap]);
print("\t.word\t0x%x\n", p[1 - swap]);
} else
if (suffix == P) {
print("\t.word\t0x%x\n", (unsigned) v.p);
} else
if (size == 1) {
print("\t.byte\t0x%x\n",
(unsigned) ((unsigned char) (suffix == I ? v.i : v.u)));
} else
if (size == 2) {
print("\t.half\t0x%x\n",
(unsigned) ((unsigned short) (suffix == I ? v.i : v.u)));
} else
if (size == 4) {
print("\t.word\t0x%x\n", (unsigned) (suffix == I ? v.i : v.u));
}
}
 
 
static void defstring(int n, char *str) {
char *s;
 
for (s = str; s < str + n; s++) {
print("\t.byte\t0x%x\n", (*s) & 0xFF);
}
}
 
 
static void defsymbol(Symbol s) {
if (s->scope >= LOCAL && s->sclass == STATIC) {
s->x.name = stringf("L.%d", genlabel(1));
} else
if (s->generated) {
s->x.name = stringf("L.%s", s->name);
} else {
assert(s->scope != CONSTANTS || isint(s->type) || isptr(s->type));
s->x.name = s->name;
}
}
 
 
static void export(Symbol s) {
print("\t.export\t%s\n", s->name);
}
 
 
static int bitcount(unsigned mask) {
unsigned i, n;
 
n = 0;
for (i = 1; i != 0; i <<= 1) {
if (mask & i) {
n++;
}
}
return n;
}
 
 
static Symbol argreg(int argno, int offset, int ty, int sz, int ty0) {
assert((offset & 3) == 0);
if (offset > 12) {
return NULL;
}
return ireg[(offset / 4) + 4];
}
 
 
static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
int i;
Symbol p, q;
Symbol r;
int sizeisave;
int saved;
Symbol argregs[4];
 
usedmask[0] = usedmask[1] = 0;
freemask[0] = freemask[1] = ~((unsigned) 0);
offset = 0;
maxoffset = 0;
maxargoffset = 0;
for (i = 0; callee[i] != NULL; i++) {
p = callee[i];
q = caller[i];
assert(q != NULL);
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 (variadic(f->type)) {
p->sclass = AUTO;
} else
if (r != NULL && 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] == NULL);
offset = 0;
gencode(caller, callee);
if (ncalls != 0) {
usedmask[IREG] |= ((unsigned) 1) << 31;
}
usedmask[IREG] &= 0x80FF0000;
usedmask[FREG] &= 0xFFF00000;
maxargoffset = roundup(maxargoffset, 4);
if (ncalls != 0 && maxargoffset < 16) {
maxargoffset = 16;
}
sizeisave = 4 * bitcount(usedmask[IREG]);
framesize = roundup(maxargoffset + sizeisave + maxoffset, 16);
segment(CODE);
print("\t.align\t4\n");
print("%s:\n", f->x.name);
if (framesize > 0) {
print("\tsub\t$29,$29,%d\n", framesize);
}
saved = maxargoffset;
for (i = 16; i < 32; i++) {
if (usedmask[IREG] & (1 << i)) {
print("\tstw\t$%d,$29,%d\n", i, saved);
saved += 4;
}
}
for (i = 0; i < 4 && callee[i] != NULL; 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;
print("\tadd\t$%d,$0,$%d\n", outn, rn);
} else {
int off = in->x.offset + framesize;
int n = (in->type->size + 3) / 4;
int i;
for (i = rn; i < rn + n && i <= 7; i++) {
print("\tstw\t$%d,$29,%d\n", i, off + (i - rn) * 4);
}
}
}
}
if (variadic(f->type) && callee[i - 1] != NULL) {
i = callee[i - 1]->x.offset + callee[i - 1]->type->size;
for (i = roundup(i, 4)/4; i <= 3; i++) {
print("\tstw\t$%d,$29,%d\n", i + 4, framesize + 4 * i);
}
}
emitcode();
saved = maxargoffset;
for (i = 16; i < 32; i++) {
if (usedmask[IREG] & (1 << i)) {
print("\tldw\t$%d,$29,%d\n", i, saved);
saved += 4;
}
}
if (framesize > 0) {
print("\tadd\t$29,$29,%d\n", framesize);
}
print("\tjr\t$31\n");
print("\n");
}
 
 
static void global(Symbol s) {
if (s->type->align != 0) {
print("\t.align\t%d\n", s->type->align);
} else {
print("\t.align\t%d\n", 4);
}
print("%s:\n", s->x.name);
}
 
 
static void import(Symbol s) {
print("\t.import\t%s\n", s->name);
}
 
 
static void local(Symbol s) {
if (askregvar(s, rmap(ttob(s->type))) == 0) {
mkauto(s);
}
}
 
 
static void setSwap(void) {
union {
char c;
int i;
} u;
 
u.i = 0;
u.c = 1;
swap = ((u.i == 1) != IR->little_endian);
}
 
 
static void progbeg(int argc, char *argv[]) {
int i;
 
setSwap();
segment(CODE);
parseflags(argc, argv);
for (i = 0; i < 32; i++) {
ireg[i] = mkreg("%d", i, 1, IREG);
}
iregw = mkwildcard(ireg);
for (i = 0; i < 32; i += 2) {
freg2[i] = mkreg("%d", i, 3, FREG);
}
freg2w = mkwildcard(freg2);
tmask[IREG] = INTTMP;
vmask[IREG] = INTVAR;
tmask[FREG] = FLTTMP;
vmask[FREG] = FLTVAR;
blkreg = mkreg("8", 8, 7, IREG);
}
 
 
static void progend(void) {
}
 
 
static void segment(int n) {
static int currSeg = -1;
int newSeg;
 
switch (n) {
case CODE:
newSeg = CODE;
break;
case BSS:
newSeg = BSS;
break;
case DATA:
newSeg = DATA;
break;
case LIT:
newSeg = DATA;
break;
}
if (currSeg == newSeg) {
return;
}
switch (newSeg) {
case CODE:
print("\t.code\n");
break;
case BSS:
print("\t.bss\n");
break;
case DATA:
print("\t.data\n");
break;
}
currSeg = newSeg;
}
 
 
static void space(int n) {
print("\t.space\t%d\n", n);
}
 
 
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 blkfetch(int size, int off, int reg, int tmp) {
assert(size == 1 || size == 2 || size == 4);
if (size == 1) {
print("\tldbu\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 2) {
print("\tldhu\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 4) {
print("\tldw\t$%d,$%d,%d\n", tmp, reg, off);
}
}
 
 
static void blkstore(int size, int off, int reg, int tmp) {
assert(size == 1 || size == 2 || size == 4);
if (size == 1) {
print("\tstb\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 2) {
print("\tsth\t$%d,$%d,%d\n", tmp, reg, off);
} else
if (size == 4) {
print("\tstw\t$%d,$%d,%d\n", tmp, reg, off);
}
}
 
 
static void blkloop(int dreg, int doff,
int sreg, int soff,
int size, int tmps[]) {
int label;
 
label = genlabel(1);
print("\tadd\t$%d,$%d,%d\n", sreg, sreg, size & ~7);
print("\tadd\t$%d,$%d,%d\n", tmps[2], dreg, size & ~7);
blkcopy(tmps[2], doff, sreg, soff, size & 7, tmps);
print("L.%d:\n", label);
print("\tsub\t$%d,$%d,%d\n", sreg, sreg, 8);
print("\tsub\t$%d,$%d,%d\n", tmps[2], tmps[2], 8);
blkcopy(tmps[2], doff, sreg, soff, 8, tmps);
print("\tbltu\t$%d,$%d,L.%d\n", dreg, tmps[2], label);
}
 
 
static void emit2(Node p) {
static int ty0;
int ty, sz;
Symbol q;
int src;
int dst, n;
 
switch (specific(p->op)) {
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) {
print("\tstw\t$%d,$29,%d\n", src, p->syms[2]->u.c.v.i);
}
break;
case ASGN+B:
dalign = p->syms[1]->u.c.v.i;
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 & ~3;
for (; dst <= 12 && dst < n; dst += 4) {
print("\tldw\t$%d,$29,%d\n", (dst / 4) + 4, dst);
}
break;
}
}
 
 
static void doarg(Node p) {
static int argno;
int align;
int size;
int offset;
 
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;
size = p->syms[0]->u.c.v.i < 4 ? 4 : p->syms[0]->u.c.v.i;
offset = mkactual(align, size);
if (p->syms[0]->u.c.v.i < 4) {
offset += 4 - p->syms[0]->u.c.v.i;
}
p->syms[2] = intconst(offset);
}
 
 
static void target(Node p) {
static int ty0;
int ty;
Symbol q;
 
assert(p);
switch (specific(p->op)) {
case CNST+I:
case CNST+P:
case CNST+U:
if (range(p, 0, 0) == 0) {
setreg(p, ireg[0]);
p->x.registered = 1;
}
break;
case CALL+I:
case CALL+P:
case CALL+U:
rtarget(p, 0, ireg[25]);
setreg(p, ireg[2]);
break;
case CALL+F:
rtarget(p, 0, ireg[25]);
setreg(p, freg2[0]);
break;
case CALL+V:
rtarget(p, 0, ireg[25]);
break;
case RET+I:
case RET+P:
case RET+U:
rtarget(p, 0, ireg[2]);
break;
case RET+F:
rtarget(p, 0, freg2[0]);
break;
case ARG+I:
case ARG+P:
case ARG+U:
case ARG+F:
ty = optype(p->op);
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;
}
}
 
 
Interface eco32IR = {
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, 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, 0, 0, 0, 0,
{
1, /* max_unaligned_load */
rmap,
blkfetch, blkstore, blkloop,
_label,
_rule,
_nts,
_kids,
_string,
_templates,
_isinstruction,
_ntname,
emit2,
doarg,
target,
clobber
}
};
/lex.c.ORIG
0,0 → 1,928
#include "c.h"
#include <float.h>
#include <errno.h>
 
static char rcsid[] = "$Id: lex.c,v 1.1 2002/08/28 23:12:44 drh Exp $";
 
#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)
continue;
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);
if (q == '"' && put == wcput && getchr() == 'L') {
if (limit - cp < 2)
fillbuf();
if (cp[1] == '"')
cp++;
}
} 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];
}
/stmt.c
0,0 → 1,708
#include "c.h"
 
static char rcsid[] = "$Id: stmt.c,v 1.1 2002/08/28 23:12:46 drh Exp $";
 
#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(cnsttree(inttype, 0L));
} else
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 {
Type ty = retv->type->type;
assert(isstruct(ty));
if (ty->u.sym->u.s.cfields) {
ty->u.sym->u.s.cfields = 0;
p = asgntree(ASGN, rvalue(idtree(retv)), p);
ty->u.sym->u.s.cfields = 1;
} 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\n");
}
}
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);
}
/error.c
0,0 → 1,138
#include "c.h"
 
static char rcsid[] = "$Id: error.c,v 1.1 2002/08/28 23:12:43 drh Exp $";
 
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);
}
/enode.c
0,0 → 1,550
#include "c.h"
 
static char rcsid[] = "$Id: enode.c,v 1.1 2002/08/28 23:12:42 drh Exp $";
 
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 (isunsigned(l->type))
l = cast(l, unsignedptr);
else
l = cast(l, signedptr);
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) {
ty1 = unqual(ty1);
ty2 = unqual(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 = unqual(l->type), yty = unqual(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);
}
/dag.c
0,0 → 1,740
#include "c.h"
 
static char rcsid[] = "$Id: dag.c,v 1.1 2002/08/28 23:12:42 drh Exp $";
 
#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 killnodes(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 && errcnt == 0)
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 killnodes(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;
if (isarray(tp->type))
op = tp->op + sizeop(voidptype->size);
else
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)
killnodes(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->generated)
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: assert(IR->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);
}
 
/profio.c
0,0 → 1,286
/* 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"
 
static char rcsid[] = "$Id: profio.c,v 1.1 2002/08/28 23:12:45 drh Exp $";
 
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(const void *x, const void *y) {
struct count *a = (struct count *)x, *b = (struct count *)y;
 
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;
}
}
if (p->counts[i].x != x || p->counts[i].y != y)
for (i = 0; i < p->count; i++)
if (p->counts[i].x == x && p->counts[i].y == y)
break;
if (i >= p->count)
if (i >= p->size)
apoint(i, file, x, y, count);
else {
p->count = i + 1;
p->counts[i].x = x;
p->counts[i].y = y;
p->counts[i].count = count;
}
else
p->counts[i].count += count;
}
 
/* 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, compare);
return 1;
}
return 0;
}
/tree.c
0,0 → 1,242
#include "c.h"
 
static char rcsid[] = "$Id: tree.c,v 1.1 2002/08/28 23:12:47 drh Exp $";
 
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 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 CVF:
if (optype(p->op) == I
|| p->type->size < p->kids[0]->type->size)
if (warn++ == 0)
warning("expression with no effect elided\n");
return root1(p->kids[0]);
case CVI:
if ((optype(p->op) == U || optype(p->op) == I)
&& p->type->size < p->kids[0]->type->size
&& specific(p->kids[0]->op) != CALL+I)
if (warn++ == 0)
warning("expression with no effect elided\n");
return root1(p->kids[0]);
case CVU: case CVP:
if (optype(p->op) == U && p->type->size < p->kids[0]->type->size
|| optype(p->op) == I && p->type->size <= p->kids[0]->type->size)
if (warn++ == 0)
warning("expression with no effect elided\n");
return root1(p->kids[0]);
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);
}
/input.c
0,0 → 1,146
#include "c.h"
 
static char rcsid[] = "$Id: input.c,v 1.1 2002/08/28 23:12:44 drh Exp $";
 
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();
}
 
/* ident - handle #ident "string" */
static void ident(void) {
while (*cp != '\n' && *cp != '\0')
cp++;
}
 
/* 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" ], #pragma, etc. */
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 (strncmp((char *)cp, "ident", 5) == 0) {
cp += 5;
ident();
} 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();
if (cp == limit)
break;
} else
break;
}
 
/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,v 1.1 2002/08/28 23:12:41 drh Exp $";
 
/ops.h
0,0 → 1,133
/* $Id: ops.h,v 1.2 2002/09/03 23:39:33 drh Exp $ */
 
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)
/prof.c
0,0 → 1,233
#include "c.h"
 
static char rcsid[] = "$Id: prof.c,v 1.1 2002/08/28 23:12:45 drh Exp $";
 
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 */
 
/* bbpad - emit space, if necessary, to make size%align == 0; return new size */
static int bbpad(int size, int align) {
if (size%align) {
(*IR->space)(align - size%align);
size = roundup(size, align);
}
return size;
}
 
/* 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;
 
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));
bbpad(2*voidptype->size + unsignedtype->size, p->type->align);
if (caller == 0) {
caller = mksymbol(EXTERN, "_caller", ptr(voidptype));
caller->defined = 0;
}
for (t = *e; generic(t->op) != CALL; t = t->kids[0])
assert(t->op == RIGHT || !t->kids[1]);
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]);
for ( ; generic((*e)->op) != CALL; e = &(*e)->kids[0])
;
*e = t;
}
 
/* bbentry - return tree for _prologue(&afunc, &YYlink)' */
static void bbentry(Symbol yylink, Symbol f, void *ignore) {
static Symbol prologue;
 
afunc = genident(STATIC, array(voidptype, 4, 0), GLOBAL);
if (prologue == 0) {
prologue = mksymbol(EXTERN, "_prologue", ftype(inttype, voidptype, voidptype, NULL));
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, NULL));
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, void *ignore) {
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));
bbpad(3*voidptype->size + unsignedtype->size, afunc->type->align);
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;
 
if (needconst)
return;
/* 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, void *ignore, void *ignore2) {
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(inttype, n, 0);
defglobal(YYcounts, BSS);
(*IR->space)(YYcounts->type->size);
}
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);
(*IR->defconst)(U, unsignedtype->size, (v.u = 0, v));
defglobal(yylink, DATA);
defpointer(NULL);
(*IR->defconst)(U, inttype->size, (v.u = n, v));
bbpad(voidptype->size + inttype->size, yylink->type->align);
defpointer(YYcounts);
defpointer(coords);
defpointer(files);
defpointer(funclist);
}
 
/* profInit - initialize basic block profiling options */
void profInit(char *arg) {
if (strncmp(arg, "-a", 2) == 0) {
if (ncalled == -1
&& process(arg[2] ? &arg[2] : "prof.out") > 0)
ncalled = 0;
} else if ((strcmp(arg, "-b") == 0
|| strcmp(arg, "-C") == 0) && YYlink == 0) {
YYlink = genident(STATIC, array(voidptype, 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(arg, "-b") == 0) {
YYcounts = genident(STATIC, array(inttype, 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);
}
}
}
/gen.c
0,0 → 1,830
#include "c.h"
 
static char rcsid[] = "$Id: gen.c,v 1.1 2002/08/28 23:12:43 drh Exp $";
 
#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 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");
}
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;
}
 
/config.h.ORIG
0,0 → 1,104
/* $Id: config.h,v 1.1 2002/08/28 23:12:42 drh Exp $ */
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 unsigned emitasm(Node, 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
/list.c
0,0 → 1,57
#include "c.h"
 
static char rcsid[] = "$Id: list.c,v 1.1 2002/08/28 23:12:44 drh Exp $";
 
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;
}
/bind.c
0,0 → 1,30
#include "c.h"
#undef yy
#define yy \
xx(alpha/osf, alphaIR) \
xx(mips/irix, mipsebIR) \
xx(eco32/linux, eco32IR) \
xx(eco32/netbsd, eco32IR) \
xx(eco32/eos32, eco32IR) \
xx(sparc/sun, sparcIR) \
xx(sparc/solaris,solarisIR) \
xx(x86/win32, x86IR) \
xx(x86/linux, x86linuxIR) \
xx(symbolic/osf, symbolic64IR) \
xx(symbolic/irix,symbolicIR) \
xx(symbolic, symbolicIR) \
xx(bytecode, bytecodeIR) \
xx(null, nullIR)
 
#undef xx
#define xx(a,b) extern Interface b;
yy
 
Binding bindings[] = {
#undef xx
#define xx(a,b) #a, &b,
yy
NULL, NULL
};
#undef yy
#undef xx
/expr.c
0,0 → 1,711
#include "c.h"
 
static char rcsid[] = "$Id: expr.c,v 1.1 2002/08/28 23:12:43 drh Exp $";
 
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 (generic(p->op) != CNST && 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/widechar->size)*sizeof (int), PERM),
tsym->u.c.v.p, (tsym->type->size/widechar->size)*sizeof (int));
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, PERM);
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, signedptr));
 
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);
}
/event.c
0,0 → 1,29
#include "c.h"
 
static char rcsid[] = "$Id: event.c,v 1.1 2002/08/28 23:12:43 drh Exp $";
 
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);
}
}
 
/symbolic.c
0,0 → 1,525
#include <time.h>
#include <ctype.h>
#include "c.h"
 
#define I(f) s_##f
static char rcsid[] = "$Id: symbolic.c,v 1.1 2002/08/28 23:12:47 drh Exp $";
 
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));
}
ITEM;
int n = 0;
if (!html)
print(" ");
print("flags=");
#define yy(f) if (p->f) { if (n++) print("|"); print(#f); }
yy(structarg)
yy(addressed)
yy(computed)
yy(temporary)
yy(generated)
#undef yy
if (n == 0)
print("0");
END;
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);
double d = v.d;
if (d == 0.0) {
static union { int x; char endian; } little = { 1 };
signed char *b = (signed char *)&d;
if (!little.endian && b[0] < 0
|| little.endian && b[sizeof (d)-1] < 0)
print("-0.0");
else
print("0.0");
} else
print("%g", 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)
};
/main.c
0,0 → 1,230
#include "c.h"
 
static char rcsid[] = "$Name: v4_2 $($Id: main.c,v 1.1 2002/08/28 23:12:44 drh Exp $)";
 
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);
for (i = 1; i < argc; i++)
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 {
profInit(argv[i]);
traceInit(argv[i]);
}
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], "-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);
}
/token.h
0,0 → 1,134
/* $Id: token.h,v 1.1 2002/08/28 23:12:47 drh Exp $ */
/*
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
/inits.c
0,0 → 1,5
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 type_init(int, char *[]); type_init(argc, argv);}
}
/c.h
0,0 → 1,600
/* $Id: c.h,v 1.1 2002/08/28 23:12:41 drh Exp $ */
#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) (~(fieldsize(p) < 8*unsignedtype->size ? ~0u<<fieldsize(p) : 0u))
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 {
#include "ops.h"
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);
 
void profInit(char *);
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 newtable(int);
extern Table table(Table, int);
extern Symbol temporary(int, Type);
extern char *vtoa(Type, Value);
 
extern void traceInit(char *);
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, ...);
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);
 
/stab.c.ORIG
0,0 → 1,331
#include <string.h>
#include <stdlib.h>
#include "c.h"
#include "stab.h"
 
static char rcsid[] = "$Id: stab.c,v 1.1 2002/08/28 23:12:46 drh Exp $";
 
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);
}
/lex.c
0,0 → 1,930
#include "c.h"
#include <float.h>
#include <errno.h>
 
static char rcsid[] = "$Id: lex.c,v 1.1 2002/08/28 23:12:44 drh Exp $";
 
#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 (base != 10 &&
n > inttype->u.sym->u.limits.max.i &&
n <= unsignedtype->u.sym->u.limits.max.i)
tval.type = unsignedtype;
else if (n > inttype->u.sym->u.limits.max.i)
tval.type = longtype;
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)
continue;
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);
if (q == '"' && put == wcput && getchr() == 'L') {
if (limit - cp < 2)
fillbuf();
if (cp[1] == '"')
cp++;
}
} 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];
}
/stab.c
0,0 → 1,327
#include <string.h>
#include <stdlib.h>
#include "c.h"
#include "stab.h"
 
static char rcsid[] = "$Id: stab.c,v 1.1 2002/08/28 23:12:46 drh Exp $";
 
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 *);
 
print(".stabs \"lcc4_compiled.\",0x%x,0,0,0\n", N_OPT);
if (file && *file) {
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);
}
/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
/run.sh
0,0 → 1,52
#!/bin/sh
# $Id: run.sh,v 1.11 1997/07/03 00:15:10 drh Exp $
# 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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.