home *** CD-ROM | disk | FTP | other *** search
- #include <sys/exec.h>
- #include <unistd.h>
- #include <string.h>
- #include "pico.h"
-
- typedef unsigned long Inst;
-
- static void gen(Tree *t);
- static void binop(Tree *t, int s1, int s2, int d);
- static void binconst(Tree *t, int s1, int s2, int d);
- static void dodump(Inst *, int);
- static void clearregs(void);
- static void freereg(int);
- static int findreg(void);
- static int mul(int,int), div(int,int), mod(int,int);
-
- static Inst *code;
- static ccset, boolean, last = 18, regs[6], spp, sppmax, result;
-
- #define zero 0
- #define tmp 1
- #define base 24 /* first arg */
- #define offset 25 /* etc. */
- #define a_mul 26
- #define a_div 27
- #define a_mod 28
- #define rx 16
- #define ry 17
- #define sp 14
- #define o0 8 /* first arg out */
- #define o1 9
-
- #define OP(rd,op,rs,i,r_or_d) ((2<<30)|(rd<<25)|(op<<19)|(rs<<14)|(i<<13)|(r_or_d&017777))
- #define MOP(rd,op,rs,i,r_or_d) ((3<<30)|(rd<<25)|(op<<19)|(rs<<14)|(i<<13)|(r_or_d&017777))
- #define SETHI(rd,op,imm) ((rd<<25)|(op<<22)|(imm&017777777))
-
- #define _ADD(a,b,c) *code++ = OP(c,000,a,0,b)
- #define _ADDcc(a,b,c) *code++ = OP(c,020,a,0,b)
- #define _SUB(a,b,c) *code++ = OP(c,004,a,0,b)
- #define _SUBcc(a,b,c) *code++ = OP(c,024,a,0,b)
- #define _XOR(a,b,c) *code++ = OP(c,003,a,0,b)
- #define _XORcc(a,b,c) *code++ = OP(c,023,a,0,b)
- #define _OR(a,b,c) *code++ = OP(c,002,a,0,b)
- #define _ORcc(a,b,c) *code++ = OP(c,022,a,0,b)
- #define _AND(a,b,c) *code++ = OP(c,001,a,0,b)
- #define _ANDcc(a,b,c) *code++ = OP(c,021,a,0,b)
- #define _NOR(a,b,c) *code++ = OP(c,006,a,0,b)
- #define _XORI(a,b,c) *code++ = OP(c,003,a,1,b)
- #define _XORIcc(a,b,c) *code++ = OP(c,023,a,1,b)
- #define _ORI(a,b,c) *code++ = OP(c,002,a,1,b)
- #define _ORIcc(a,b,c) *code++ = OP(c,022,a,1,b)
- #define _ADDI(a,b,c) *code++ = OP(c,000,a,1,b)
- #define _ADDIcc(a,b,c) *code++ = OP(c,020,a,1,b)
- #define _ANDI(a,b,c) *code++ = OP(c,001,a,1,b)
- #define _ANDIcc(a,b,c) *code++ = OP(c,021,a,1,b)
- #define _LBU(a,b,c) *code++ = MOP(a,001,b,0,c)
- #define _LBIU(a,b,c) *code++ = MOP(a,001,b,1,c)
- #define _SB(a,b,c) *code++ = MOP(a,005,b,0,c)
- #define _SBI(a,b,c) *code++ = MOP(a,005,b,1,c)
- #define _LW(a,b,c) *code++ = MOP(a,000,b,0,c)
- #define _LWI(a,b,c) *code++ = MOP(a,000,b,1,c)
- #define _SW(a,b,c) *code++ = MOP(a,004,b,0,c)
- #define _SWI(a,b,c) *code++ = MOP(a,004,b,1,c)
- #define _SETHI(a,b) *code++ = SETHI(a,04,b>>10)
- #define _SLL(a,b,c) *code++ = OP(c,045,a,0,b)
- #define _SRL(a,b,c) *code++ = OP(c,046,a,0,b)
- #define _SLLI(a,b,c) *code++ = OP(c,045,a,1,b)
- #define _SRLI(a,b,c) *code++ = OP(c,046,a,1,b)
- #define _CMP(a,b) *code++ = OP(zero,024,a,0,b) /* _SUBcc(a,b,zero); */
- #define _CMPI(a,b) *code++ = OP(zero,024,a,1,b) /* _SUBIcc(a,b,zero); */
- #define _B(cond,disp) SETHI(cond,02,disp)
- #define ALWAYS 010
- #define EQ 001
- #define NE 011
- #define GE 013
- #define LE 002
- #define GT 012
- #define LT 003
- #define _JAL(a) *code++ = OP(15,070,a,0,zero)
- #define _SAVE(a) *code++ = OP(sp,074,sp,1,a)
- #define _RET *code++ = 0x81c7e008 /* jmpl %o7+8,%g0 */
- #define _RESTORE *code++ = 0x81e80000 /* restore %g0,%g0,%g0 */
- #define _NOP *code++ = SETHI(zero,04,0)
-
- #define _PUSH(a) {\
- _SW(a,sp,spp);\
- spp += 4;\
- if (spp > sppmax)\
- sppmax = spp;\
- }
-
- #define _POP(a) {\
- spp -= 4;\
- _LW(a,sp,spp);\
- }
-
- static void loadimm(int i, int j) {
- if (j > 0x1777 || j < 0) {
- _SETHI(i,j);
- _ORIcc(i,(j&01777),i);
- } else
- _ORIcc(zero,j,i);
- }
-
- extern void compile(Tree *t) {
- Inst prog[1024], *remem1, *remem2;
- void (*progp)() = (void (*)()) prog;
- code = prog;
- clearregs();
- last = findreg();
- code = prog;
- _SAVE(0); /* value is or'ed in later */
- loadimm(ry,DEF_Y-1);
- remem1 = code;
- loadimm(rx,DEF_X-1);
- remem2 = code;
- gen(t);
- _SB(result,base,offset);
- _ADDI(offset,-1,offset);
- _CMP(rx,zero);
- *code = _B(NE,remem2-code); code++;
- _ADDI(rx,-1,rx);
- _CMP(ry,zero);
- *code = _B(NE,remem1-code); code++;
- _ADDI(ry,-1,ry);
- _RET;
- _RESTORE;
- *prog |= (-(sppmax+80))&017777;
- dodump(prog, (code - prog) * sizeof (Inst));
- progp(buf[0].data, (DEF_X*DEF_Y) - 1, mul, div, mod);
- }
-
- static int mul(int a, int b) {
- return a*b;
- }
-
- static int div(int a, int b) {
- return a/b;
- }
-
- static int mod(int a, int b) {
- return a%b;
- }
-
- static void gen(Tree *t) {
- Inst *remem;
- int i, saved, b1, b2, c1, c2;
- switch (t->t) {
- case Num:
- if (t->i == 0) {
- result = zero;
- ccset = 0;
- boolean = 1;
- } else {
- loadimm(result = last, t->i);
- boolean = !(t->i & ~1);
- ccset = 1;
- }
- break;
- case Xcoord:
- result = rx;
- boolean = 0;
- ccset = 0;
- break;
- case Ycoord:
- result = ry;
- boolean = 0;
- ccset = 0;
- break;
- case Bang:
- gen(t->kids[0]);
- if (!ccset)
- _CMP(result,zero);
- *code++ = _B(EQ,3);
- _ADDIcc(zero,1,last);
- _ADDIcc(zero,0,last);
- result = last;
- boolean = 1;
- ccset = 1;
- break;
- case Not:
- gen(t->kids[0]);
- _XORIcc(result,-1,last);
- result = last;
- boolean = 0;
- ccset = 1;
- break;
- case Neg:
- gen(t->kids[0]);
- _SUBcc(zero,result,last);
- result = last;
- boolean = 0;
- ccset = 1;
- break;
- case Cond:
- gen(t->kids[0]); /* test */
- if (!ccset)
- _CMP(result,zero);
- remem = code;
- *code++ = _B(EQ,0);
- _NOP;
- gen(t->kids[1]); /* iftrue */
- b1 = boolean;
- c1 = ccset;
- if (result != last)
- _ADD(result,zero,last);
- *remem |= code - remem + 1;
- remem = code - 1;
- *code = code[-1];
- code[-1] = _B(ALWAYS,0); /* fill delay slot */
- code++;
- gen(t->kids[2]); /* iffalse */
- b2 = boolean;
- c2 = ccset;
- if (result != last)
- _ADD(result,zero,last);
- result = last;
- boolean = (b1 & b2);
- ccset = (c1 & c2);
- *remem |= code - remem;
- break;
- case Andalso:
- case Orelse:
- gen(t->kids[0]);
- b1 = boolean;
- if (result != last)
- _ADDcc(result,zero,last);
- else if (!ccset)
- _CMP(result,zero);
- saved = last;
- remem = code;
- if (t->t == Andalso)
- *code++ = _B(EQ,0);
- else
- *code++ = _B(NE,0);
- _NOP;
- gen(t->kids[1]);
- b2 = boolean;
- if (result != saved) {
- _ADDcc(result,zero,saved);
- ccset = 1;
- }
- result = saved;
- *remem |= code - remem;
- if (!(b1&b2)) { /* "normalize" expr to {0,1} */
- if (!ccset)
- _CMP(result,0);
- *code++ = _B(NE,3);
- _ADDIcc(zero,0,result);
- _ADDIcc(zero,1,result);
- ccset = 1;
- }
- boolean = 1;
- break;
- case Coordpair:
- if (t->i > nfiles || t->i < 0)
- error("no such buffer");
- if (t->kids[0] != NULL) {
- gen(t->kids[0]);
- i = last;
- } else
- i = offset;
- loadimm(tmp,(int)buf[t->i].data);
- _LBU(last,tmp,i);
- result = last;
- ccset = 0;
- boolean = 0;
- break;
- default:
- gen(t->kids[0]);
- saved = result;
- if (((Tree *)t->kids[1])->t == Num && (i = ((Tree *)t->kids[1])->i) < 4096 && i > -4096) {
- binconst(t,result,i,last);
- } else {
- if (saved != rx && saved != ry && (last = findreg()) == -1) {
- last = saved;
- saved = -1;
- _PUSH(last);
- }
- gen(t->kids[1]);
- if (saved == -1) {
- _POP(tmp);
- binop(t,tmp,result,last);
- } else {
- binop(t,saved,result,last);
- if (saved != rx && saved != ry)
- freereg(saved);
- }
- }
- result = last;
- }
- }
-
- static void binop(Tree *t, int s1, int s2, int d) {
- boolean = 0;
- ccset = 1;
- switch (t->t) {
- default:
- error("not a binop in binop!");
- case Add:
- _ADDcc(s1,s2,d);
- break;
- case Sub:
- _SUBcc(s1,s2,d);
- break;
- case Mult:
- _ADD(zero,s1,o0);
- _JAL(a_mul);
- _ADD(zero,s2,o1);
- _ADDcc(zero,o0,d);
- break;
- case Div:
- _ADD(zero,s1,o0);
- _JAL(a_div);
- _ADD(zero,s2,o1);
- _ADDcc(zero,o0,d);
- break;
- case Mod:
- _ADD(zero,s1,o0);
- _JAL(a_mod);
- _ADD(zero,s2,o1);
- _ADDcc(zero,o0,d);
- break;
- case Gt:
- _CMP(s1,s2);
- *code++ = _B(GT,3);
- _ADDIcc(zero,0,d);
- _ADDIcc(zero,1,d);
- boolean = 1;
- break;
- case Lt:
- _CMP(s1,s2);
- *code++ = _B(LT,3);
- _ADDIcc(zero,0,d);
- _ADDIcc(zero,1,d);
- boolean = 1;
- break;
- case Ge:
- _CMP(s1,s2);
- *code++ = _B(GE,3);
- _ADDIcc(zero,0,d);
- _ADDIcc(zero,1,d);
- boolean = 1;
- break;
- case Le:
- _CMP(s1,s2);
- *code++ = _B(LE,3);
- _ADDIcc(zero,0,d);
- _ADDIcc(zero,1,d);
- boolean = 1;
- break;
- case Eq:
- _CMP(s1,s2);
- *code++ = _B(EQ,3);
- _ADDIcc(zero,0,d);
- _ADDIcc(zero,1,d);
- boolean = 1;
- break;
- case Ne:
- _CMP(s1,s2);
- *code++ = _B(NE,3);
- _ADDIcc(zero,0,d);
- _ADDIcc(zero,1,d);
- boolean = 1;
- break;
- case Xor:
- _XORcc(s1,s2,d);
- break;
- case And:
- _ANDcc(s1,s2,d);
- break;
- case Or:
- _ORcc(s1,s2,d);
- break;
- case Ll:
- _SLL(s1,s2,d);
- ccset = 0;
- break;
- case Rr:
- _SRL(s1,s2,d);
- ccset = 0;
- break;
- }
- }
-
- static void binconst(Tree *t, int s1, int s2, int d) {
- int shift;
- boolean = 0;
- ccset = 1;
- switch (t->t) {
- default:
- error("not a binop in binconst!");
- case Add:
- _ADDIcc(s1,s2,d);
- break;
- case Sub:
- _ADDIcc(s1,-s2,d);
- break;
- case Mult:
- case Div:
- if (s2 < 0 || s2 & (s2 - 1) != 0) {
- loadimm(s2,o1);
- _JAL(((t->t == Mult) ? a_mul : a_div));
- _ADD(zero,s1,o0);
- _ADDcc(zero,o0,d);
- } else {
- for (shift = 0; s2 != 0; shift++, s2 >>= 1)
- ;
- if (shift == 0) {
- if (t->t == Mult)
- loadimm(d,0);
- else
- error("division by zero");
- return;
- } else if (t->t == Mult) {
- _SLLI(s1,--shift,d);
- } else {
- _SRLI(s1,--shift,d);
- }
- ccset = 0;
- }
- break;
- case Mod:
- loadimm(s2,o1);
- _JAL(a_mod);
- _ADD(zero,s1,o0);
- _ADDcc(zero,o0,d);
- break;
- case Gt:
- _CMPI(s1,s2);
- *code++ = _B(GT,3);
- _ADDIcc(zero,0,d);
- _ADDIcc(zero,1,d);
- boolean = 1;
- break;
- case Lt:
- _CMPI(s1,s2);
- *code++ = _B(LT,3);
- _ADDIcc(zero,0,d);
- _ADDIcc(zero,1,d);
- boolean = 1;
- break;
- case Ge:
- _CMPI(s1,s2);
- *code++ = _B(GE,3);
- _ADDIcc(zero,0,d);
- _ADDIcc(zero,1,d);
- boolean = 1;
- break;
- case Le:
- _CMPI(s1,s2);
- *code++ = _B(LE,3);
- _ADDIcc(zero,0,d);
- _ADDIcc(zero,1,d);
- boolean = 1;
- break;
- case Eq:
- _CMPI(s1,s2);
- *code++ = _B(EQ,3);
- _ADDIcc(zero,0,d);
- _ADDIcc(zero,1,d);
- boolean = 1;
- break;
- case Ne:
- _CMPI(s1,s2);
- *code++ = _B(NE,3);
- _ADDIcc(zero,0,d);
- _ADDIcc(zero,1,d);
- boolean = 1;
- break;
- case Xor:
- _XORIcc(s1,s2,d);
- break;
- case And:
- _ANDIcc(s1,s2,d);
- break;
- case Or:
- _ORIcc(s1,s2,d);
- break;
- case Ll:
- _SLLI(s1,s2,d);
- ccset = 0;
- break;
- case Rr:
- _SRLI(s1,s2,d);
- ccset = 0;
- break;
- }
- }
-
- static void dodump(Inst *prog, int size) {
- if (debug) {
- int fd = creat("pico.out", 0644);
- struct exec exec;
- exec.a_machtype = M_SPARC;
- exec.a_magic = OMAGIC;
- exec.a_text = size;
- exec.a_data = 0;
- exec.a_bss = 0;
- exec.a_syms = 0;
- exec.a_entry = 0;
- exec.a_trsize = 0;
- exec.a_drsize = 0;
- if (fd < 0) {
- perror("pico.out");
- exit(1);
- }
- write(fd, &exec, sizeof exec);
- write(fd, prog, size);
- close(fd);
- }
- }
-
- static void clearregs() {
- int i;
- for (i = 0; i < 6; i++)
- regs[i] = 0;
- }
-
- static void freereg(int i) {
- regs[i-18] = 0;
- }
-
- static int findreg() {
- int i;
- for (i = 0; i < 6; i++)
- if (regs[i] == 0)
- break;
- if (i == 6)
- return -1;
- regs[i] = 1;
- return i+18;
- }
-