/* 68020 desciptor table for ACK target optimizer */ MAXOP 2; PAREN_OPEN "("; PAREN_CLOSE ")"; %%; /* useful addressing modes-> */ CONST {VAL[0] == '#' }; /* constant */ NUM {is_number(VAL) }; A,B {no_side_effects(VAL) }; D {VAL[0] != '#' && !is_areg(VAL) }; /* not an addr. reg */ X,Y {TRUE }; DREG,DREG2 {is_dreg(VAL) }; /* data register */ DSREG {is_dsreg(VAL) }; /* data register */ AREG {is_areg(VAL) }; /* addressregister */ FPREG,FPREG2 {is_fpreg(VAL) }; /* fp register */ LAB,L1,L2 {VAL[0] == 'I' }; /* label */ NO32 {no_part("div",VAL) && no_part("mul",VAL) && no_part(".l",VAL)}; /* for move.w ... */ BITNO {TRUE }; %%; /* optimization patterns-> */ /* rewriting rules */ tst X -> tst.w X ; cmp X,Y -> cmp.w X,Y ; /* special instructions */ move.w #0,D -> clr.w D ; move.l #0,D -> clr.l D ; move.l #0,AREG -> sub.l AREG,AREG ; /* tst-elimination */ add.l #2,sp : tst.w X {no_part("sp",X)} -> move.w X,(sp)+ ; add.l #4,sp : tst.l D {no_part("sp",D)} -> move.l D,(sp)+ ; add.l #2,sp : move.w X,-(sp) -> move.w X,(sp) ; add.l #4,sp : move.l X,-(sp) -> move.l X,(sp) ; add.l #4,sp : pea (NUM) -> move.l #NUM,(sp) ; add.l #4,sp : pea (AREG) -> move.l AREG,(sp) ; add.l #NUM,sp : unlk AREG -> unlk AREG ; add.l #NUM,sp : movem.l X,Y : unlk AREG {no_part("sp",X) && no_part("sp",Y)} -> movem.l X,Y : unlk AREG ; move.w A,X : tst.w A -> move.w A,X ; move.w X,A : tst.w A -> move.w X,A ; move.l A,D : tst.l A {no_part(D,A)} -> move.l A,D ; move.l X,D : tst.l D -> move.l X,D ; move.l A,AREG : tst.l A {no_part(AREG,A)} -> tst.l A : move.l A,AREG ; move.l X,AREG : move.l AREG,DREG : tst.l DREG : beq LAB -> move.l X,DREG : move.l DREG,AREG: beq LAB ; move.l X,AREG : move.l AREG,DREG : tst.l DREG : bne LAB -> move.l X,DREG : move.l DREG,AREG: bne LAB ; /* redundant move */ move.l DREG,DREG2 : move.l DREG2,DREG -> move.l DREG,DREG2 ; move.l DREG,AREG : move.l AREG,DREG -> move.l DREG,AREG : tst.l DREG ; move.l AREG,DREG : move.l DREG,AREG -> move.l AREG,DREG ; move.w DREG,DREG2 : move.w DREG2,DREG -> move.w DREG,DREG2 ; move.l AREG,AREG -> ; /* register subsumption */ move.w DREG,A : ANY A,X {reg_subs_allowed(ANY) && !is_dreg(A) } -> move.w DREG,A : ANY DREG,X ; move.l DREG,A : ANY A,X {reg_subs_allowed(ANY) && !is_dreg(A) } -> move.l DREG,A : ANY DREG,X ; move.w DREG,DREG2 : NO32 A,DREG2 : move.w DREG2,DREG {no_part(DREG2,A)} -> NO32 A,DREG : move.w DREG,DREG2 ; move.l DREG,DREG2 : ANY A,DREG2 : move.l DREG2,DREG {no_part(DREG2,A)} -> ANY A,DREG : move.l DREG,DREG2 ; cmp.b A,A : beq LAB -> bra LAB ; cmp.w A,A : beq LAB -> bra LAB ; cmp.l A,A : beq LAB -> bra LAB ; /* cannot delete cmp's because they affect condition codes (obvious, but ... )*/ cmp.b A,A : bne LAB -> cmp.b A,A ; cmp.w A,A : bne LAB -> cmp.w A,A ; cmp.l A,A : bne LAB -> cmp.l A,A ; /* change some compares to tests */ cmp.w #0,D : beq LAB -> tst.w D : beq LAB ; cmp.w #0,D : bne LAB -> tst.w D : bne LAB ; cmp.w #0,D : blt LAB -> tst.w D : blt LAB ; cmp.w #0,D : ble LAB -> tst.w D : ble LAB ; cmp.w #0,D : bge LAB -> tst.w D : bge LAB ; cmp.w #0,D : bgt LAB -> tst.w D : bgt LAB ; cmp.l #0,D : beq LAB -> tst.l D : beq LAB ; cmp.l #0,D : bne LAB -> tst.l D : bne LAB ; cmp.l #0,D : blt LAB -> tst.l D : blt LAB ; cmp.l #0,D : ble LAB -> tst.l D : ble LAB ; cmp.l #0,D : bge LAB -> tst.l D : bge LAB ; cmp.l #0,D : bgt LAB -> tst.l D : bgt LAB ; cmp.w D,#0 : beq LAB -> tst.w D : beq LAB ; cmp.w D,#0 : bne LAB -> tst.w D : bne LAB ; cmp.w D,#0 : blt LAB -> tst.w D : bgt LAB ; cmp.w D,#0 : ble LAB -> tst.w D : bge LAB ; cmp.w D,#0 : bge LAB -> tst.w D : ble LAB ; cmp.w D,#0 : bgt LAB -> tst.w D : blt LAB ; cmp.l D,#0 : beq LAB -> tst.l D : beq LAB ; cmp.l D,#0 : bne LAB -> tst.l D : bne LAB ; cmp.l D,#0 : blt LAB -> tst.l D : bgt LAB ; cmp.l D,#0 : ble LAB -> tst.l D : bge LAB ; cmp.l D,#0 : bge LAB -> tst.l D : ble LAB ; cmp.l D,#0 : bgt LAB -> tst.l D : blt LAB ; /* change "cmp" into "add" or "sub" (possibly "addq" or "subq") */ cmp.w #-NUM,DSREG : beq LAB -> add.w #NUM,DSREG : beq LAB ; cmp.l #-NUM,DSREG : beq LAB -> add.l #NUM,DSREG : beq LAB ; cmp.w #-NUM,DSREG : bne LAB -> add.w #NUM,DSREG : bne LAB ; cmp.l #-NUM,DSREG : bne LAB -> add.l #NUM,DSREG : bne LAB ; cmp.w #NUM,DSREG : beq LAB -> sub.w #NUM,DSREG : beq LAB ; cmp.l #NUM,DSREG : beq LAB -> sub.l #NUM,DSREG : beq LAB ; cmp.w #NUM,DSREG : bne LAB -> sub.w #NUM,DSREG : bne LAB ; cmp.l #NUM,DSREG : bne LAB -> sub.l #NUM,DSREG : bne LAB ; /* addq and subq */ lea -1(AREG),AREG -> sub.l #1,AREG ; add.w #-NUM,X -> sub.w #NUM,X ; add.l #-NUM,X -> sub.l #NUM,X ; sub.w #-NUM,X -> add.w #NUM,X ; sub.l #-NUM,X -> add.l #NUM,X ; /* bit-test instruction */ move.b X,DSREG : and.w #NUM,DSREG : tst.w DSREG : beq LAB { bitno(NUM,BITNO)} -> btst #BITNO,X ; move.b X,DSREG : and.l #NUM,DSREG : tst.l DSREG : beq LAB { bitno(NUM,BITNO)} -> btst #BITNO,X ; /* skip over jump */ beq L1 : bra L2: labdef L1 -> bne L2 : labdef L1 ; bge L1 : bra L2: labdef L1 -> blt L2 : labdef L1 ; bgt L1 : bra L2: labdef L1 -> ble L2 : labdef L1 ; blt L1 : bra L2: labdef L1 -> bge L2 : labdef L1 ; ble L1 : bra L2: labdef L1 -> bgt L2 : labdef L1 ; bne L1 : bra L2: labdef L1 -> beq L2 : labdef L1 ; move.l A, B : bra LAB : labdef L1 : move.l A, B : labdef LAB -> labdef L1 : move.l A, B : labdef LAB ; /* some strength reduction */ mulu.l #NUM,DREG -> muls.l #NUM,DREG ; muls.l #NUM,DREG {isshift_once(NUM,X,Y)} -> asl.l #X,DREG : asl.l #Y,DREG ; muls.l #NUM,DREG {is_shift_twice(NUM,X,Y)} -> asl.l #X,DREG : move.l DREG,-(sp) : asl.l #Y,DREG : add.l (sp)+,DREG ; asl.l #0,DREG -> ; asl.l #1,DREG -> add.l DREG,DREG ; move.l A,-(sp) : move.l B,-(sp) : fmove.d (sp)+,FPREG {combines_to_double(A,B)} -> fmove.d B,FPREG ; move.l A,-(sp) : move.l B,-(sp) : fmove.d X,FPREG : fmove.d (sp)+,FPREG2 {combines_to_double(A,B) && strcmp(FPREG,FPREG2) && no_part("sp",X) } -> fmove.d X,FPREG : fmove.d B,FPREG2 ; %%; /* auxiliary routines: */ int no_side_effects(s) register char *s; { for(;;) { switch(*s++) { case '\0': return TRUE; case '-': if (*s == '(') return FALSE; break; case ')': if (*s == '+') return FALSE; break; } } /* NOTREACHED */ } int isshift_once(s, c1, c2) char *s, *c1, *c2; { long atol(); register int i = 0; long val = atol(s), pow = 1; while (i <= 16) { if (pow & val) { val -= pow; if (val == 0) { sprintf(c1, "%d", i <= 8 ? i : 8); sprintf(c2, "%d", i <= 8 ? 0 : i - 8); return 1; } return 0; } pow <<= 1; i++; } return 0; } int is_shift_twice(s, c1, c2) char *s, *c1, *c2; { long atol(); register int i = 0; long val = atol(s), pow = 1; while (i <= 8) { if (pow & val) { val -= pow; sprintf(c1, "%d", i); break; } pow <<= 1; i++; } if (i > 8) return 0; if (pow > 0 && val) { i = 0; while (i <= 8) { if (pow & val) { val -= pow; sprintf(c2, "%d", i); if (val == 0) return 1; break; } pow <<= 1; i++; } } return 0; } int is_dreg(s) register char *s; { return *s++ == 'd' && *s >= '0' && *s++ <= '7' && *s == '\0'; } int is_fpreg(s) register char *s; { return *s++ == 'f' && *s++ == 'p' && *s >= '0' && *s++ <= '7' && *s == '\0'; } int is_dsreg(s) register char *s; { return *s++ == 'd' && *s >= '0' && *s++ <= '2' && *s == '\0'; } int is_areg(s) register char *s; { return *s++ == 'a' && *s >= '0' && *s++ <= '6' && *s == '\0'; } int no_part(part,s) char *part,*s; { char *tmp1,*tmp2; while (*s != '\0') { if (*s == *part) { for (tmp1=part,tmp2=s;; tmp1++,tmp2++) { if (*tmp1== '\0') return FALSE; if (*tmp1 != *tmp2) break; } } s++; } return TRUE; } /* see if register subsumption is allowed for instruction Opc */ int reg_subs_allowed(opc) char *opc; { return strcmp(opc,"cmp") != 0 && strcmp(opc,"lea") != 0; } int is_number(s) register char *s; { while (*s != '\0') { if (*s < '0' || *s++ > '9') return FALSE; } return TRUE; } int bitno(s,no) char *s,*no; { int n,i; n = atoi(s); if (n < 1 || n > 128) return FALSE; for (i = 0; i < 8 ; i++) { if (n == 1) { sprintf(no,"%d",i); return TRUE; } n >>= 1; } return FALSE; } int combines_to_double(a,b) register char *a,*b; { /* recognize (_name+4) combined with (_name), and (offset+4,...) combined with (offset,...) */ if (*a++ == '(' && *b++ == '(') { if (*a == '-' || *a >= '0' && *a <= '9') { int na = atoi(a); int nb = atoi(b); if (*a == '-') a++; if (*b == '-') b++; if (na == nb + 4) { while (*a >= '0' && *a <= '9') a++; while (*b >= '0' && *b <= '9') b++; return !strcmp(a,b) && *a++ == ',' && *a++ == 'a' && *a++ && *a++ == ')' && !*a; } return FALSE; } while (*a && *a == *b) { a++; b++; } if (*b++ == ')' && ! *b && *a++ == '+' && *a++ == '4' && *a++ == ')' && !*a) return TRUE; } return FALSE; }