%{ /* This file is an almost complete machine description file of the MC68000 family for the lburg code generator generator. What's missing can be easily filled in for a specific MC68k assembler. A change must be made to config.h in order to use this file. The Xnode struct's kids field must be enlarged to 4. A completed version of this file forms the basis for the MPW version of the lcc compiler targeted for the Apple Macintosh. The code emitted by this specification is for the Apple MPW Assembler which has a syntax similar to Motorola's assembler. A major difference between this lburg specification and the examples in the lcc distribution is that switch statement tables are stored in the code segment and are addressed by the pc relative addressing mode. Registers A2-A7,D3-D7,FP4-FP7 are preserved across function calls. Registers D0 and FP0 store function results. Parameters are passed from right to left on the stack. All floating point values are first promoted to Motorola extended format before being pushed on the stack. Here are some benchmark results of some compilers available for the Apple Macintosh. The programs are similar to those found in the Hennessy suite. MPW C is the Apple C compiler. Gcc is the MPW port of gcc version 1.37.1r15. SC is the Symantec C compiler (ex-Zortech with m68k backend). SCG is the Symantec C compiler with all optimizations on. This compiler does global optimizations. LCC is the lcc compiler produced with this machine description file. MW is the Metrowerks 68k C compiler from Code Warrior. All tests were run on a Macintosh Centris 650 with MC68040 @25MHz using 020 addressing modes and FPU. MPW C gcc gcc -O SC SCG LCC MW opt Perm 13 13 11 17 19 12 22 Towers 12 15 10 17 16 12 11 Queens 6 7 5 7 8 8 4 Intmm 19 18 16 18 11 19 17 Mm 17 19 16 18 10 20 18 Puzzle 68 86 48 74 35 74 47 Quick 8 10 5 13 11 8 14 Bubble 11 16 7 19 10 12 11 FFT 25 28 16 24 20 25 19 Hopefully this file will prove useful to those wishing to target lcc to Atari's, Amiga's, Sun's and Next's. Let me know if you retarget lcc to any other m68k machines using this file. Please report any bugs to: Woodrow Yeung yeung@reed.edu */ enum { D0, D1, D2, D3, D4, D5, D6, D7 }; enum { A0, A1, A2, A3, A4, A5, A6, A7 }; enum { FP0, FP1, FP2, FP3, FP4, FP5, FP6, FP7 }; #define realparamsize 12 #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 ARGS((Symbol, Symbol, int)); static void blkfetch ARGS((int, int, int, int)); static void blkloop ARGS((int, int, int, int, int, int[])); static void blkstore ARGS((int, int, int, int)); static void defaddress ARGS((Symbol)); static void defconst ARGS((int, Value)); static void defstring ARGS((int, char *)); static void defsymbol ARGS((Symbol)); static void doarg ARGS((Node)); static void emit2 ARGS((Node)); static void export ARGS((Symbol)); static void clobber ARGS((Node)); static void function ARGS((Symbol, Symbol [], Symbol [], int)); static void global ARGS((Symbol)); static void import ARGS((Symbol)); static void local ARGS((Symbol)); static void progbeg ARGS((int, char **)); static void progend ARGS((void)); static void segment ARGS((int)); static void space ARGS((int)); static void target ARGS((Node)); static int sametree ARGS((Node, Node)); static int memop ARGS((Node)); static Symbol ireg[32], *dreg = &ireg[0], areg[32], freg[32]; static int cseg; %} %start stmt %term ADDD=306 ADDF=305 ADDI=309 ADDP=311 ADDU=310 ADDC=307 ADDS=308 %term ADDRFP=279 %term ADDRGP=263 %term ADDRLP=295 %term ARGB=41 ARGD=34 ARGF=33 ARGI=37 ARGP=39 %term ASGNB=57 ASGNC=51 ASGND=50 ASGNF=49 ASGNI=53 ASGNP=55 ASGNS=52 ASGNU=54 %term BANDU=390 %term BCOMU=406 %term BORU=422 %term BXORU=438 %term CALLB=217 CALLD=210 CALLF=209 CALLI=213 CALLV=216 %term CNSTC=19 CNSTD=18 CNSTF=17 CNSTI=21 CNSTP=23 CNSTS=20 CNSTU=22 %term CVCI=85 CVCU=86 %term CVDF=97 CVDI=101 %term CVFD=114 %term CVIC=131 CVID=130 CVIS=132 CVIU=134 %term CVPU=150 %term CVSI=165 CVSU=166 %term CVUC=179 CVUI=181 CVUP=183 CVUS=180 %term DIVD=450 DIVF=449 DIVI=453 DIVU=454 %term EQD=482 EQF=481 EQI=485 %term GED=498 GEF=497 GEI=501 GEU=502 %term GTD=514 GTF=513 GTI=517 GTU=518 %term INDIRB=73 INDIRC=67 INDIRD=66 INDIRF=65 INDIRI=69 INDIRP=71 INDIRS=68 %term JUMPV=584 %term LABELV=600 %term LED=530 LEF=529 LEI=533 LEU=534 %term LOADB=233 LOADC=227 LOADD=226 LOADF=225 LOADI=229 LOADP=231 LOADS=228 LOADU=230 %term LSHI=341 LSHU=342 %term LTD=546 LTF=545 LTI=549 LTU=550 %term MODI=357 MODU=358 %term MULD=466 MULF=465 MULI=469 MULU=470 %term NED=562 NEF=561 NEI=565 %term NEGD=194 NEGF=193 NEGI=197 %term RETD=242 RETF=241 RETI=245 %term RSHI=373 RSHU=374 %term SUBD=322 SUBF=321 SUBI=325 SUBP=327 SUBU=326 SUBC=323 SUBS=324 %term VREGP=615 %% reg: INDIRC(VREGP) "# read register\n" reg: INDIRD(VREGP) "# read register\n" reg: INDIRF(VREGP) "# read register\n" reg: INDIRI(VREGP) "# read register\n" reg: INDIRP(VREGP) "# read register\n" reg: INDIRS(VREGP) "# read register\n" stmt: ASGNC(VREGP,reg) "# write register\n" stmt: ASGND(VREGP,reg) "# write register\n" stmt: ASGNF(VREGP,reg) "# write register\n" stmt: ASGNI(VREGP,reg) "# write register\n" stmt: ASGND(VREGP,reg) "# write register\n" stmt: ASGNP(VREGP,reg) "# write register\n" stmt: ASGNS(VREGP,reg) "# write register\n" con: CNSTC "%#%a" con: CNSTI "%#%a" con: CNSTP "%#%a" con: CNSTS "%#%a" con: CNSTU "%#%a" stmt: reg "" reg: CVIU(reg) "%0" notarget(a) reg: CVUI(reg) "%0" notarget(a) disp16: CNSTI "%a" range(a, -32768, 32767) disp8: CNSTI "%a" range(a, -128, 127) base: ADDP(reg,disp16) "%1(%0" base: ADDRFP "%a(A6" range(a, -32768, 32767) base: ADDRLP "%a(A6" range(a, -32768, 32767) base: basei "%0" basei: reg "(%0" basei: ADDP(reg,disp8) "%1(%0" basei: ADDRFP "%a(A6" range(a, -128, 127) basei: ADDRLP "%a(A6" range(a, -128, 127) basei: ADDRFP "(%a,A6" 1 basei: ADDRLP "(%a,A6" 1 addr: ADDRGP "%a(A5)" acon: ADDRGP "%a" table: ADDRGP "\tLEA %a,%c\n" index: reg "%0" index: LSHI(reg,scf) "%0*%1" addr: base "%0)" addr: ADDP(index,basei) "%1,%0)" case: ADDP(index,table) "(%1,%0)" avar: acon "%0" avar: reg "(%0)" 1 avar: addr "%0" 2 con0: CNSTI "%#0" range(a, 0, 0) con0: CNSTP "%#0" range(a, 0, 0) con0: CNSTU "%#0" range(a, 0, 0) con3: CNSTI "%#%a" range(a, 1, 8) con3: CNSTP "%#%a" range(a, 1, 8) scf: CNSTI "2" range(a, 1, 1) scf: CNSTI "4" range(a, 2, 2) scf: CNSTI "8" range(a, 3, 3) mem: INDIRI(addr) "%0" mem: INDIRP(addr) "%0" pcrel: INDIRP(case) "\tMOVE.L %0,%c\n" ri: reg "%0" ri: con "%0" ri3: con3 "%0" ri3: reg "%0" ea0: mem "%0" ea0: ri "%0" ea1: mem "%0" 1 ea1: ri "%0" ea3: mem "%0" 3 ea3: ri "%0" reg: addr "\tLEA %0,%c\n" 1 reg: ri "\tMOVE.L %0,%c\n" 1 reg: INDIRC(addr) "\tMOVE.B %0,%c\n" 1 reg: INDIRI(addr) "\tMOVE.L %0,%c\n" 1 reg: INDIRP(addr) "\tMOVE.L %0,%c\n" 1 reg: INDIRS(addr) "\tMOVE.W %0,%c\n" 1 reg: LOADC(reg) "\tMOVE.L %0,%c\n" move(a) reg: LOADI(reg) "\tMOVE.L %0,%c\n" move(a) reg: LOADP(reg) "\tMOVE.L %0,%c\n" move(a) reg: LOADS(reg) "\tMOVE.L %0,%c\n" move(a) reg: LOADU(reg) "\tMOVE.L %0,%c\n" move(a) reg: ADDI(reg,con3) "?\tMOVE.L %0,%c\n\tADDQ.L %1,%c\n" reg: SUBI(reg,con3) "?\tMOVE.L %0,%c\n\tSUBQ.L %1,%c\n" reg: ADDI(reg,ea1) "?\tMOVE.L %0,%c\n\tADD.L %1,%c\n" 1 reg: ADDP(reg,ea1) "?\tMOVE.L %0,%c\n\tADDA.L %1,%c\n" 1 reg: ADDU(reg,ea1) "?\tMOVE.L %0,%c\n\tADD.L %1,%c\n" 1 reg: SUBI(reg,ea1) "?\tMOVE.L %0,%c\n\tSUB.L %1,%c\n" 1 reg: SUBP(reg,ea1) "?\tMOVE.L %0,%c\n\tSUBA.L %1,%c\n" 1 reg: SUBU(reg,ea1) "?\tMOVE.L %0,%c\n\tSUB.L %1,%c\n" 1 stmt: ASGNI(addr,ADDI(mem,ri)) "\tADD.L %2,%1\n" memop(a) stmt: ASGNI(addr,ADDU(mem,ri)) "\tADD.L %2,%1\n" memop(a) stmt: ASGNI(addr,SUBI(mem,ri)) "\tSUB.L %2,%1\n" memop(a) stmt: ASGNI(addr,SUBU(mem,ri)) "\tSUB.L %2,%1\n" memop(a) reg: BANDU(reg,ea1) "?\tMOVE.L %0,%c\n\tAND.L %1,%c\n" 1 reg: BORU(reg,ea1) "?\tMOVE.L %0,%c\n\tOR.L %1,%c\n" 1 reg: BXORU(reg,reg) "?\tMOVE.L %0,%c\n\tEOR.L %1,%c\n" 1 stmt: ASGNI(addr,BANDU(mem,ri)) "\tAND.L %2,%1\n" memop(a) stmt: ASGNI(addr,BORU(mem,ri)) "\tOR.L %2,%1\n" memop(a) stmt: ASGNI(addr,BXORU(mem,reg)) "\tEOR.L %2,%1\n" memop(a) reg: BCOMU(reg) "?\tMOVE.L %0,%c\n\tNOT.L %c\n" 1 reg: NEGI(reg) "?\tMOVE.L %0,%c\n\tNEG.L %c\n" 1 stmt: ASGNI(addr,BCOMU(mem)) "\tNOT.L %1\n" memop(a) stmt: ASGNI(addr,NEGI(mem)) "\tNEG.L %1\n" memop(a) reg: LSHI(reg,ri3) "?\tMOVE.L %0,%c\n\tASL.L %1,%c\n" 1 reg: LSHU(reg,ri3) "?\tMOVE.L %0,%c\n\tLSL.L %1,%c\n" 1 reg: RSHI(reg,ri3) "?\tMOVE.L %0,%c\n\tASR.L %1,%c\n" 1 reg: RSHU(reg,ri3) "?\tMOVE.L %0,%c\n\tLSR.L %1,%c\n" 1 reg: MULI(reg,ea3) "?\tMOVE.L %0,%c\n\tMULS.L %1,%c\n" 12 reg: MULU(reg,ea3) "?\tMOVE.L %0,%c\n\tMULU.L %1,%c\n" 12 reg: DIVU(reg,ea3) "?\tMOVE.L %0,%c\n\tDIVU.L %1,%c\n" reg: DIVI(reg,ea3) "?\tMOVE.L %0,%c\n\tDIVS.L %1,%c\n" reg: MODU(reg,ea3) "\tMOVE.L %0,D1\n\tCLR.L %c\n\tDIVU.L %1,%c:D1\n" reg: MODI(reg,reg) "#\tCLR.L %c\n\tDIVS.L %1,%0\n" reg: CVCI(reg) "\tMOVE.B %0,%c\n\tEXT.W %c\n\tEXT.L %c\n" 2 reg: CVCU(reg) "\tMOVE.B %0,%c\n\tAND.L #$FF,%0\n" 3 reg: CVSI(reg) "\tMOVE.W %0,%c\n\tEXT.L %c\n" 1 reg: CVSU(reg) "\tMOVE.W %0,%c\n\tAND.L #$FFFF,%0\n" 3 reg: CVCI(INDIRC(addr)) "\tMOVE.B %0,%c\n\tEXT.W %c\n\tEXT.L %c\n" 2 reg: CVCU(INDIRC(addr)) "\tCLR.L %c\n\tMOVE.B %0,%c\n" 2 reg: CVSI(INDIRS(addr)) "\tMOVE.W %0,%c\n\tEXT.L %c\n" 2 reg: CVSU(INDIRS(addr)) "\tCLR.L %c\n\tMOVE.W %0,%c\n" 2 reg: CVIC(reg) "%0" notarget(a) reg: CVIS(reg) "%0" notarget(a) reg: CVUC(reg) "%0" notarget(a) reg: CVUS(reg) "%0" notarget(a) reg: CVIC(reg) "\tMOVE.L %0,%c\n" move(a) reg: CVIS(reg) "\tMOVE.L %0,%c\n" move(a) reg: CVIU(reg) "\tMOVE.L %0,%c\n" move(a) reg: CVPU(reg) "\tMOVE.L %0,%c\n" reg: CVUC(reg) "\tMOVE.L %0,%c\n" move(a) reg: CVUI(reg) "\tMOVE.L %0,%c\n" move(a) reg: CVUP(reg) "\tMOVE.L %0,%c\n" reg: CVUS(reg) "\tMOVE.L %0,%c\n" move(a) reg: CVDF(reg) "%0" notarget(a) reg: CVFD(reg) "%0" notarget(a) reg: CVDF(reg) "\tFMOVE.X %0,%c\n" move(a) reg: CVFD(reg) "\tFMOVE.X %0,%c\n" move(a) reg: CVID(ea0) "\tFMOVE.L %0,%c\n" reg: CVDI(reg) "\tFMOVE.L %0,%c\n" stmt: ASGNC(addr,ea1) "\tMOVE.B %1,%0\n" 1 stmt: ASGNC(addr,con0) "\tCLR.L %0\n" stmt: ASGNI(addr,ea1) "\tMOVE.L %1,%0\n" 1 stmt: ASGNI(addr,con0) "\tCLR.L %0\n" stmt: ASGNI(addr,CVDI(reg)) "\tFMOVE.L %1,%0\n" stmt: ASGNP(addr,ea1) "\tMOVE.L %1,%0\n" 1 stmt: ASGNP(addr,con0) "\tCLR.L %0\n" stmt: ASGNS(addr,ea1) "\tMOVE.W %1,%0\n" 1 stmt: ASGNS(addr,con0) "\tCLR.W %0\n" stmt: ARGI(ea0) "\tMOVE.L %0,-(SP)\n" 1 stmt: ARGI(addr) "\tPEA.L %0\n" 1 stmt: ARGP(ea0) "\tMOVE.L %0,-(SP)\n" 1 stmt: ARGP(addr) "\tPEA.L %0\n" 1 stmt: ASGNB(reg, INDIRB(reg)) "# MOVE (src)+,(dst)+\n" 2 stmt: ARGB(INDIRB(reg)) "# Copy to stack\n" 2 reg: LOADD(reg) "\tFMOVE.X %0,%c\n" move(a) reg: LOADF(reg) "\tFMOVE.X %0,%c\n" move(a) reg: INDIRD(addr) "\tFMOVE.D %0,%c\n" 3 reg: INDIRF(addr) "\tFMOVE.S %0,%c\n" 3 mem: INDIRD(addr) "%0" mem: INDIRF(addr) "%0" stmt: ASGND(addr,reg) "\tFMOVE.D %1,%0\n" 4 stmt: ASGND(addr,mem) "\tLEA.L %1,A0\n\tLEA.L %0,A1\n\tMOVE.L (A0)+,(A1)+\n\tMOVE.L (A0),(A1)\n" 3 stmt: ASGNF(addr,reg) "\tFMOVE.S %1,%0\n" 4 stmt: ASGNF(addr,mem) "\tMOVE.L %1,%0\n" 1 stmt: ARGD(reg) "\tFMOVE.X %0,-(SP)\n" 3 stmt: ARGF(reg) "\tFMOVE.X %0,-(SP)\n" 3 reg: ADDD(reg,reg) "?\tFMOVE.X %0,%c\n\tFADD.X %1,%c\n" reg: ADDF(reg,reg) "?\tFMOVE.X %0,%c\n\tFADD.X %1,%c\n" reg: SUBD(reg,reg) "?\tFMOVE.X %0,%c\n\tFSUB.X %1,%c\n" reg: SUBF(reg,reg) "?\tFMOVE.X %0,%c\n\tFSUB.X %1,%c\n" reg: MULD(reg,reg) "?\tFMOVE.X %0,%c\n\tFMUL.X %1,%c\n" reg: MULF(reg,reg) "?\tFMOVE.X %0,%c\n\tFMUL.X %1,%c\n" reg: DIVD(reg,reg) "?\tFMOVE.X %0,%c\n\tFDIV.X %1,%c\n" reg: DIVF(reg,reg) "?\tFMOVE.X %0,%c\n\tFDIV.X %1,%c\n" reg: NEGD(reg) "\tFNEG.X %c\n" reg: NEGF(reg) "\tFNEG.X %c\n" stmt: JUMPV(acon) "\tBRA %0\n" stmt: JUMPV(pcrel) "\tJMP (PC,%0)\n" stmt: LABELV "%a:\n" stmt: EQI(ea0,con0) "\tTST.L %0\n\tBEQ %a\n" 2 stmt: NEI(ea0,con0) "\tTST.L %0\n\tBNE %a\n" 2 stmt: EQI(reg,ea1) "\tCMP.L %1,%0\n\tBEQ %a\n" 3 stmt: GEI(reg,ea1) "\tCMP.L %1,%0\n\tBGE %a\n" 3 stmt: GTI(reg,ea1) "\tCMP.L %1,%0\n\tBGT %a\n" 3 stmt: LEI(reg,ea1) "\tCMP.L %1,%0\n\tBLE %a\n" 3 stmt: LTI(reg,ea1) "\tCMP.L %1,%0\n\tBLT %a\n" 3 stmt: NEI(reg,ea1) "\tCMP.L %1,%0\n\tBNE %a\n" 3 stmt: GEU(reg,ea1) "\tCMP.L %1,%0\n\tBHS %a\n" 3 stmt: GTU(reg,ea1) "\tCMP.L %1,%0\n\tBHI %a\n" 3 stmt: LEU(reg,ea1) "\tCMP.L %1,%0\n\tBLS %a\n" 3 stmt: LTU(reg,ea1) "\tCMP.L %1,%0\n\tBLO %a\n" 3 stmt: EQD(reg,reg) "\tFCMP.X %1,%0\n\tFBEQ.W %a\n" stmt: GED(reg,reg) "\tFCMP.X %1,%0\n\tFBGE.W %a\n" stmt: GTD(reg,reg) "\tFCMP.X %1,%0\n\tFBGT.W %a\n" stmt: LED(reg,reg) "\tFCMP.X %1,%0\n\tFBLE.W %a\n" stmt: LTD(reg,reg) "\tFCMP.X %1,%0\n\tFBLT.W %a\n" stmt: NED(reg,reg) "\tFCMP.X %1,%0\n\tFBNE.W %a\n" stmt: EQF(reg,reg) "\tFCMP.X %1,%0\n\tFBEQ.W %a\n" stmt: GEF(reg,reg) "\tFCMP.X %1,%0\n\tFBGE.W %a\n" stmt: GTF(reg,reg) "\tFCMP.X %1,%0\n\tFBGT.W %a\n" stmt: LEF(reg,reg) "\tFCMP.X %1,%0\n\tFBLE.W %a\n" stmt: LTF(reg,reg) "\tFCMP.X %1,%0\n\tFBLT.W %a\n" stmt: NEF(reg,reg) "\tFCMP.X %1,%0\n\tFBNE.W %a\n" reg: CALLI(avar) "\tJSR %0\n\tADDA.L %#%a,SP\n" stmt: CALLV(avar) "\tJSR %0\n\tADDA.L %#%a,SP\n" reg: CALLF(avar) "\tJSR %0\n\tADDA.L %#%a,SP\n" reg: CALLD(avar) "\tJSR %0\n\tADDA.L %#%a,SP\n" stmt: RETI(reg) "# RTS\n" stmt: RETF(reg) "# RTS\n" stmt: RETD(reg) "# RTS\n" %% static void progbeg(argc, argv) char *argv[]; { int i; { union { char c; int i; } u; u.i = 0; u.c = 1; swap = (u.i == 1) != IR->little_endian; } parseflags(argc, argv); for(i=0;iop) { case ASGNB: rtarget(p, 1, areg[A0+8]); /* A0 Source */ rtarget(p, 0, areg[A1+8]); /* A1 Destination */ break; case ARGB: rtarget(p->kids[0], 0, areg[A0+8]); /* A0 Source */ break; case CALLI: case CALLV: setreg(p, dreg[D0]); break; case CALLD: case CALLF: setreg(p, freg[FP0]); break; case RETI: rtarget(p, 0, ireg[D0]); break; case RETF: case RETD: rtarget(p, 0, freg[FP0]); break; } } static void clobber(p) Node p; { assert(p); switch (p->op) { case MULI: case MULU: break; case DIVI: case DIVU: break; case MODI: case MODU: spill(1<op == q->op && p->syms[0] == q->syms[0] && sametree(p->kids[0], q->kids[0]) && sametree(p->kids[1], q->kids[1]); } static int memop(p) 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) { assert(p->kids[1]->kids[0]); return sametree(p->kids[0], p->kids[1]->kids[0]->kids[0]) ? 2 : SHRT_MAX; } else return SHRT_MAX; } static void emit2(p) Node p; { switch(p->op) { case ASGNB: { int lab1 = genlabel(1), lab2 = genlabel(1); int src = getregnum(p->x.kids[1]), dst = getregnum(p->x.kids[0]); int size = p->syms[0]->u.c.v.i; if(size % 2) print("\tMOVE.L %#%d,D0\n", size); else print("\tMOVE.L %#%d,D0\n", size / 2); print("\tBRA.S @%d\n", lab2); print("@%d:\n", lab1); if(size % 2) print("\tMOVE.B (A%d)+,(A%d)+\n", src, dst); else print("\tMOVE.W (A%d)+,(A%d)+\n", src, dst); print("@%d:\n", lab2); print("\tDBF.W D0,@%d\n", lab1); break; } case ARGB: { int lab1 = genlabel(1), lab2 = genlabel(1); int size = p->syms[0]->u.c.v.i, src = getregnum(p->x.kids[0]); if(size % 2) ++size; print("\tSUBA.L %#%d,SP\n", size); print("\tMOVE.L SP,A1\n"); print("\tMOVE.L %#%d,D0\n", size / 2); print("\tBRA.S @%d\n", lab2); print("@%d:\n", lab1); print("\tMOVE.W (A%d)+,(A1)+\n", src); print("@%d:\n", lab2); print("\tDBF.W D0,@%d\n", lab1); } break; case MODI: { int lab1 = genlabel(1), lab2 = genlabel(1); int rem = getregnum(p), quo = getregnum(p->x.kids[0]); int divisor = getregnum(p->x.kids[1]); /* use D2 as scratch for testing sign use D1 for quotient since dividend gets clobbered */ print("\tMOVE.L D%d,D%d\n", quo, D1); print("\tMOVEQ.L #-1,D%d\n", rem); print("\tMOVE.L #31,D%d\n", D2); print("\tBTST.L D%d,D%d\n", D2, D1); print("\tBNE.S @%d\n", lab1); print("\tCLR.L D%d\n", rem); print("@%d:\n", lab1); print("\tDIVS.L D%d,D%d:D%d\n", divisor, rem, D1); break; } } } static void doarg(p) Node p; { assert(p && p->syms[0]); switch(p->op) { case ARGD: case ARGF: mkactual(2,realparamsize); /* pass all floats as extended which are 96-bits */ break; default: mkactual(2, p->syms[0]->u.c.v.i); } } static void blkfetch(k, off, reg, tmp) {} static void blkstore(k, off, reg, tmp) {} static void blkloop(dreg, doff, sreg, soff, size, tmps) int tmps[]; {} static void local(p) Symbol p; { if (askregvar(p, rmap[ttob(p->type)]) == 0) mkauto(p); } static void function(f, caller, callee, n) Symbol f, callee[], caller[]; { int i, count, acount, inseq; char reglist[256]; char temp[4]; print("%s\tPROC", f->x.name); if(!(f->sclass==STATIC)) print("\tEXPORT"); print("\n"); usedmask[0] = usedmask[1] = 0; freemask[0] = freemask[1] = ~(unsigned)0; offset = 4 + 4; /* FP and return address */ 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; if( p->type == floattype || p->type == doubletype) offset += roundup(realparamsize, 2); else offset += roundup(q->type->size, 2); } assert(caller[i] == 0); offset = maxoffset = 0; gencode(caller, callee); framesize = roundup(maxoffset, 2); if (framesize > 0) print("\tLINK A6,#%d\n", -framesize); else print("\tLINK A6,#0\n"); /* format save register mask */ reglist[0]= 0; count = acount = inseq = 0; for(i=D3;i<=D7;++i) { if(usedmask[IREG] & (1<1) { temp[0] = '-'; temp[1] = 'D'; temp[2] = i - 1 + '0'; temp[3] = 0; strcat(reglist,temp); } inseq = 0; } } if(inseq>1) { temp[0] = '-'; temp[1] = 'D'; temp[2] = '7'; temp[3] = 0; strcat(reglist,temp); } if(usedmask[IREG] & ((1<1) { temp[0] = '-'; temp[1] = 'A'; temp[2] = i - 1 + '0'; temp[3] = 0; strcat(reglist,temp); } inseq = 0; } } if(inseq>1) { temp[0] = '-'; temp[1] = 'A'; temp[2] = '4'; temp[3] = 0; strcat(reglist,temp); } } count += acount; if(count > 1) print("\tMOVEM.L %s,-(SP)\n", reglist); else if(count == 1) print("\tMOVE.L %s,-(SP)\n", reglist); /* save floating point regs */ for(i=FP4;i<=FP7;++i) if(usedmask[FREG] & (1<type == floattype) { print("\tFMOVE.X %d(A6),FP1\n", p->x.offset); print("\tFMOVE.S FP1,%d(A6)\n", p->x.offset); } else if(p->type == doubletype) { print("\tFMOVE.X %d(A6),FP1\n", p->x.offset); print("\tFMOVE.D FP1,%d(A6)\n", p->x.offset); } } emitcode(); for(i=FP7;i>=FP4;--i) if(usedmask[FREG] & (1< 1) print("\tMOVEM.L (SP)+,%s\n", reglist); else if(count == 1) print("\tMOVE.L (SP)+,%s\n", reglist); print("\tUNLK A6\n"); print("\tRTS\n"); } static void defsymbol(p) 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); /* no leading underscore */ else if (p->scope == CONSTANTS && (isint(p->type) || isptr(p->type)) && p->name[0] == '0' && p->name[1] == 'x') p->x.name = stringf("$%s", &p->name[2]); /* hex */ else p->x.name = p->name; } static void address(q, p, n) Symbol q, p; int 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 { q->x.offset = p->x.offset + n; q->x.name = stringd(q->x.offset); } } static void defconst(ty, v) Value v; { switch (ty) { case C: print("\tDC.B %d\n", v.uc); return; case S: print("\tDC.W %d\n", v.ss); return; case I: print("\tDC.L %d\n", v.i ); return; case U: print("\tDC.L $%x\n", v.u ); return; case P: print("\tDC.L $%x\n", v.p ); return; case F: print("\tDC.L $%x\n", *(unsigned *)&v.f); return; case D: { unsigned *p = (unsigned *)&v.d; print("\tDC.L $%x, $%x\n", p[swap], p[1 - swap]); return; } } assert(0); } static void defaddress(p) Symbol p; {} static void export(p) Symbol p; {} static void import(p) Symbol p; {} static void global(p) Symbol p; {} static void space(n) {} Interface m68kIR = { 1, 1, 0, /* char */ 2, 2, 0, /* short */ 4, 2, 0, /* int */ 4, 2, 1, /* float */ 8, 2, 1, /* double */ 4, 2, 0, /* T * */ 0, 2, 0, /* struct so that ARGB keeps stack aligned */ 0, /* little_endian */ 0, /* mulops_calls */ 0, /* wants_callb */ 1, /* wants_argb */ 0, /* left_to_right */ 0, /* wants_dag */ 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, blkfetch, blkstore, blkloop, _label, _rule, _nts, _kids, _opname, _arity, _string, _templates, _isinstruction, _ntname, emit2, doarg, target, clobber, } };