ref: 5fc5c18208546c77f2c279f7f6acf6b01a2d2645
dir: /sys/src/cmd/vc/mul.c/
#include "gc.h" /* * code sequences for multiply by constant. * [a-l][0-3] * lsl $(A-'a'),r0,r1 * [+][0-7] * add r0,r1,r2 * [-][0-7] * sub r0,r1,r2 */ static int multabp; static long mulval; static char* mulcp; static long valmax; static int shmax; static int docode(char *hp, char *cp, int r0, int r1); static int gen1(int len); static int gen2(int len, long r1); static int gen3(int len, long r0, long r1, int flag); enum { SR1 = 1<<0, /* r1 has been shifted */ SR0 = 1<<1, /* r0 has been shifted */ UR1 = 1<<2, /* r1 has not been used */ UR0 = 1<<3, /* r0 has not been used */ }; Multab* mulcon0(long v) { int a1, a2, g; Multab *m, *m1; char hint[10]; if(v < 0) v = -v; /* * look in cache */ m = multab; for(g=0; g<nelem(multab); g++) { if(m->val == v) { if(m->code[0] == 0) return 0; return m; } m++; } /* * select a spot in cache to overwrite */ multabp++; if(multabp < 0 || multabp >= nelem(multab)) multabp = 0; m = multab+multabp; m->val = v; mulval = v; /* * look in execption hint table */ a1 = 0; a2 = hintabsize; for(;;) { if(a1 >= a2) goto no; g = (a2 + a1)/2; if(v < hintab[g].val) { a2 = g; continue; } if(v > hintab[g].val) { a1 = g+1; continue; } break; } if(docode(hintab[g].hint, m->code, 1, 0)) return m; print("multiply table failure %ld\n", v); m->code[0] = 0; return 0; no: /* * try to search */ hint[0] = 0; for(g=1; g<=6; g++) { if(g >= 6 && v >= 65535) break; mulcp = hint+g; *mulcp = 0; if(gen1(g)) { if(docode(hint, m->code, 1, 0)) return m; print("multiply table failure %ld\n", v); break; } } /* * try a recur followed by a shift */ g = 0; while(!(v & 1)) { g++; v >>= 1; } if(g) { m1 = mulcon0(v); if(m1) { snprint(m->code, sizeof m->code, "%s%c0", m1->code, g+'a'); return m; } } m->code[0] = 0; return 0; } static int docode(char *hp, char *cp, int r0, int r1) { int c, i; c = *hp++; *cp = c; cp += 2; switch(c) { default: c -= 'a'; if(c < 1 || c >= 30) break; for(i=0; i<4; i++) { switch(i) { case 0: if(docode(hp, cp, r0<<c, r1)) goto out; break; case 1: if(docode(hp, cp, r1<<c, r1)) goto out; break; case 2: if(docode(hp, cp, r0, r0<<c)) goto out; break; case 3: if(docode(hp, cp, r0, r1<<c)) goto out; break; } } break; case '+': for(i=0; i<8; i++) { cp[-1] = i+'0'; switch(i) { case 1: if(docode(hp, cp, r0+r1, r1)) goto out; break; case 5: if(docode(hp, cp, r0, r0+r1)) goto out; break; } } break; case '-': for(i=0; i<8; i++) { cp[-1] = i+'0'; switch(i) { case 1: if(docode(hp, cp, r0-r1, r1)) goto out; break; case 2: if(docode(hp, cp, r1-r0, r1)) goto out; break; case 5: if(docode(hp, cp, r0, r0-r1)) goto out; break; case 6: if(docode(hp, cp, r0, r1-r0)) goto out; break; } } break; case 0: if(r0 == mulval) return 1; } return 0; out: cp[-1] = i+'0'; return 1; } static int gen1(int len) { int i; for(shmax=1; shmax<30; shmax++) { valmax = 1<<shmax; if(valmax >= mulval) break; } if(mulval == 1) return 1; len--; for(i=1; i<=shmax; i++) if(gen2(len, 1<<i)) { *--mulcp = 'a'+i; return 1; } return 0; } static int gen2(int len, long r1) { int i; if(len <= 0) { if(r1 == mulval) return 1; return 0; } len--; if(len == 0) goto calcr0; if(gen3(len, r1, r1+1, UR1)) { i = '+'; goto out; } if(gen3(len, r1-1, r1, UR0)) { i = '-'; goto out; } if(gen3(len, 1, r1+1, UR1)) { i = '+'; goto out; } if(gen3(len, 1, r1-1, UR1)) { i = '-'; goto out; } return 0; calcr0: if(mulval == r1+1) { i = '+'; goto out; } if(mulval == r1-1) { i = '-'; goto out; } return 0; out: *--mulcp = i; return 1; } static int gen3(int len, long r0, long r1, int flag) { int i, f1, f2; long x; if(r0 <= 0 || r0 >= r1 || r1 > valmax) return 0; len--; if(len == 0) goto calcr0; if(!(flag & UR1)) { f1 = UR1|SR1; for(i=1; i<=shmax; i++) { x = r0<<i; if(x > valmax) break; if(gen3(len, r0, x, f1)) { i += 'a'; goto out; } } } if(!(flag & UR0)) { f1 = UR1|SR1; for(i=1; i<=shmax; i++) { x = r1<<i; if(x > valmax) break; if(gen3(len, r1, x, f1)) { i += 'a'; goto out; } } } if(!(flag & SR1)) { f1 = UR1|SR1|(flag&UR0); for(i=1; i<=shmax; i++) { x = r1<<i; if(x > valmax) break; if(gen3(len, r0, x, f1)) { i += 'a'; goto out; } } } if(!(flag & SR0)) { f1 = UR0|SR0|(flag&(SR1|UR1)); f2 = UR1|SR1; if(flag & UR1) f2 |= UR0; if(flag & SR1) f2 |= SR0; for(i=1; i<=shmax; i++) { x = r0<<i; if(x > valmax) break; if(x > r1) { if(gen3(len, r1, x, f2)) { i += 'a'; goto out; } } else if(gen3(len, x, r1, f1)) { i += 'a'; goto out; } } } x = r1+r0; if(gen3(len, r0, x, UR1)) { i = '+'; goto out; } if(gen3(len, r1, x, UR1)) { i = '+'; goto out; } x = r1-r0; if(gen3(len, x, r1, UR0)) { i = '-'; goto out; } if(x > r0) { if(gen3(len, r0, x, UR1)) { i = '-'; goto out; } } else if(gen3(len, x, r0, UR0)) { i = '-'; goto out; } return 0; calcr0: f1 = flag & (UR0|UR1); if(f1 == UR1) { for(i=1; i<=shmax; i++) { x = r1<<i; if(x >= mulval) { if(x == mulval) { i += 'a'; goto out; } break; } } } if(mulval == r1+r0) { i = '+'; goto out; } if(mulval == r1-r0) { i = '-'; goto out; } return 0; out: *--mulcp = i; return 1; } /* * hint table has numbers that * the search algorithm fails on. * <1000: * all numbers * <5000: * ÷ by 5 * <10000: * ÷ by 50 * <65536: * ÷ by 250 */ Hintab hintab[] = { 683, "b++d+e+", 687, "b+e++e-", 691, "b++d+e+", 731, "b++d+e+", 811, "b++d+i+", 821, "b++e+e+", 843, "b+d++e+", 851, "b+f-+e-", 853, "b++e+e+", 877, "c++++g-", 933, "b+c++g-", 981, "c-+e-d+", 1375, "b+c+b+h-", 1675, "d+b++h+", 2425, "c++f-e+", 2675, "c+d++f-", 2750, "b+d-b+h-", 2775, "c-+g-e-", 3125, "b++e+g+", 3275, "b+c+g+e+", 3350, "c++++i+", 3475, "c-+e-f-", 3525, "c-+d+g-", 3625, "c-+e-j+", 3675, "b+d+d+e+", 3725, "b+d-+h+", 3925, "b+d+f-d-", 4275, "b+g++e+", 4325, "b+h-+d+", 4425, "b+b+g-j-", 4525, "b+d-d+f+", 4675, "c++d-g+", 4775, "b+d+b+g-", 4825, "c+c-+i-", 4850, "c++++i-", 4925, "b++e-g-", 4975, "c+f++e-", 5500, "b+g-c+d+", 6700, "d+b++i+", 9700, "d++++j-", 11000, "b+f-c-h-", 11750, "b+d+g+j-", 12500, "b+c+e-k+", 13250, "b+d+e-f+", 13750, "b+h-c-d+", 14250, "b+g-c+e-", 14500, "c+f+j-d-", 14750, "d-g--f+", 16750, "b+e-d-n+", 17750, "c+h-b+e+", 18250, "d+b+h-d+", 18750, "b+g-++f+", 19250, "b+e+b+h+", 19750, "b++h--f-", 20250, "b+e-l-c+", 20750, "c++bi+e-", 21250, "b+i+l+c+", 22000, "b+e+d-g-", 22250, "b+d-h+k-", 22750, "b+d-e-g+", 23250, "b+c+h+e-", 23500, "b+g-c-g-", 23750, "b+g-b+h-", 24250, "c++g+m-", 24750, "b+e+e+j-", 25000, "b++dh+g+", 25250, "b+e+d-g-", 25750, "b+e+b+j+", 26250, "b+h+c+e+", 26500, "b+h+c+g+", 26750, "b+d+e+g-", 27250, "b+e+e+f+", 27500, "c-i-c-d+", 27750, "b+bd++j+", 28250, "d-d-++i-", 28500, "c+c-h-e-", 29000, "b+g-d-f+", 29500, "c+h+++e-", 29750, "b+g+f-c+", 30250, "b+f-g-c+", 33500, "c-f-d-n+", 33750, "b+d-b+j-", 34250, "c+e+++i+", 35250, "e+b+d+k+", 35500, "c+e+d-g-", 35750, "c+i-++e+", 36250, "b+bh-d+e+", 36500, "c+c-h-e-", 36750, "d+e--i+", 37250, "b+g+g+b+", 37500, "b+h-b+f+", 37750, "c+be++j-", 38500, "b+e+b+i+", 38750, "d+i-b+d+", 39250, "b+g-l-+d+", 39500, "b+g-c+g-", 39750, "b+bh-c+f-", 40250, "b+bf+d+g-", 40500, "b+g-c+g+", 40750, "c+b+i-e+", 41250, "d++bf+h+", 41500, "b+j+c+d-", 41750, "c+f+b+h-", 42500, "c+h++g+", 42750, "b+g+d-f-", 43250, "b+l-e+d-", 43750, "c+bd+h+f-", 44000, "b+f+g-d-", 44250, "b+d-g--f+", 44500, "c+e+c+h+", 44750, "b+e+d-h-", 45250, "b++g+j-g+", 45500, "c+d+e-g+", 45750, "b+d-h-e-", 46250, "c+bd++j+", 46500, "b+d-c-j-", 46750, "e-e-b+g-", 47000, "b+c+d-j-", 47250, "b+e+e-g-", 47500, "b+g-c-h-", 47750, "b+f-c+h-", 48250, "d--h+n-", 48500, "b+c-g+m-", 48750, "b+e+e-g+", 49500, "c-f+e+j-", 49750, "c+c+g++f-", 50000, "b+e+e+k+", 50250, "b++i++g+", 50500, "c+g+f-i+", 50750, "b+e+d+k-", 51500, "b+i+c-f+", 51750, "b+bd+g-e-", 52250, "b+d+g-j+", 52500, "c+c+f+g+", 52750, "b+c+e+i+", 53000, "b+i+c+g+", 53500, "c+g+g-n+", 53750, "b+j+d-c+", 54250, "b+d-g-j-", 54500, "c-f+e+f+", 54750, "b+f-+c+g+", 55000, "b+g-d-g-", 55250, "b+e+e+g+", 55500, "b+cd++j+", 55750, "b+bh-d-f-", 56250, "c+d-b+j-", 56500, "c+d+c+i+", 56750, "b+e+d++h-", 57000, "b+d+g-f+", 57250, "b+f-m+d-", 57750, "b+i+c+e-", 58000, "b+e+d+h+", 58250, "c+b+g+g+", 58750, "d-e-j--e+", 59000, "d-i-+e+", 59250, "e--h-m+", 59500, "c+c-h+f-", 59750, "b+bh-e+i-", 60250, "b+bh-e-e-", 60500, "c+c-g-g-", 60750, "b+e-l-e-", 61250, "b+g-g-c+", 61750, "b+g-c+g+", 62250, "f--+c-i-", 62750, "e+f--+g+", 64750, "b+f+d+p-", }; int hintabsize = nelem(hintab);