--- /dev/null
+/* PDP-11 desciptor table for ACK target optimizer */
+
+/* Tunable constants: */
+
+MAXOP 2;
+LABEL_STARTER 'I';
+OPC_TERMINATOR ' ';
+
+%%;
+
+/* useful addressing modes: */
+
+ZERO {strcmp(VAL,"$00") == 0 };
+ONE {strcmp(VAL,"$01") == 0 };
+CONST {VAL[0] == '$' }; /* constant */
+A,B {no_side_effects(VAL) };
+X,Y {TRUE };
+REG {is_register(VAL) }; /* register */
+SREG {is_scratchreg(VAL) }; /* scratch reg */
+M_ONE {strcmp(VAL,"$037777777777") == 0 }; /* -1 */
+LAB,L1,L2 {VAL[0] == 'I' }; /* label */
+
+%%;
+
+/* optimization patterns: */
+
+add ZERO,A {carry_dead(REST)} -> ;
+add ONE, X {carry_dead(REST)} -> inc X;
+sub ONE, X {carry_dead(REST)} -> dec X;
+
+/* tst-elimination */
+tst (sp)+ : tst X -> mov X,(sp)+;
+tst (sp)+ : mov X,-(sp) -> mov X,(sp);
+mov A,X : tst A -> mov A,X;
+
+/* register subsumption */
+mov REG,A : ANY A,X -> mov REG,A : ANY REG,X;
+mov REG,A : ANY *A -> mov REG,A : ANY *REG;
+mov REG,A : ANY *A,X -> mov REG,A : ANY *REG,X;
+mov REG,A : ANY X,*A -> mov REG,A : ANY X,*REG;
+
+/* compare with -1 */
+cmp SREG,M_ONE : jeq LAB -> inc SREG : jeq LAB;
+cmp SREG,M_ONE : jne LAB -> inc SREG : jne LAB;
+
+/* skip over jump */
+jeq L1 : jbr L2: labdef L1 -> jne L2 : labdef L1;
+jge L1 : jbr L2: labdef L1 -> jlt L2 : labdef L1;
+jgt L1 : jbr L2: labdef L1 -> jle L2 : labdef L1;
+jlt L1 : jbr L2: labdef L1 -> jge L2 : labdef L1;
+jle L1 : jbr L2: labdef L1 -> jgt L2 : labdef L1;
+jne L1 : jbr L2: labdef L1 -> jeq L2 : labdef L1;
+
+/* byte-test */
+clr SREG : bisb X,SREG : tst SREG : jeq LAB
+ -> tstb X : jeq LAB;
+clr SREG : bisb X,SREG : tst SREG : jne LAB
+ -> tstb X : jne LAB;
+
+%%;
+
+/* 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 is_register(s)
+ register char *s;
+{
+ return *s++ == 'r' && *s >= '0' && *s <= '5';
+}
+
+int is_scratchreg(s)
+ register char *s;
+{
+ return *s++ == 'r' && (*s == '0' || *s == '1' || *s == '3');
+}
+
+int carry_dead(s)
+ char *s;
+{
+ switch(*s++) {
+ case 'a': /* adc and adcb */
+ return *s++ != 'd' || *s != 'c';
+ case 'b': /* bcc, bcs, bhi, bhis, blo, blos */
+ return *s != 'c' && *s != 'h' &&
+ (*s++ != 'l' || *s != 'o');
+ case 's': /* sbc and sbcb */
+ return *s++ != 'b' || *s != 'c';
+ default:
+ return TRUE;
+ }
+}