| // Inferno utils/5c/mul.c |
| // http://code.google.com/p/inferno-os/source/browse/utils/5c/mul.c |
| // |
| // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. |
| // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) |
| // Portions Copyright © 1997-1999 Vita Nuova Limited |
| // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) |
| // Portions Copyright © 2004,2006 Bruce Ellis |
| // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) |
| // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others |
| // Portions Copyright © 2009 The Go Authors. All rights reserved. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a copy |
| // of this software and associated documentation files (the "Software"), to deal |
| // in the Software without restriction, including without limitation the rights |
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| // copies of the Software, and to permit persons to whom the Software is |
| // furnished to do so, subject to the following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included in |
| // all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| // THE SOFTWARE. |
| |
| |
| #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 maxmulops = 3; /* max # of ops to replace mul with */ |
| static int multabp; |
| static int32 mulval; |
| static char* mulcp; |
| static int32 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, int32 r1); |
| static int gen3(int len, int32 r0, int32 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(int32 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 %d\n", v); |
| m->code[0] = 0; |
| return 0; |
| |
| no: |
| /* |
| * try to search |
| */ |
| hint[0] = 0; |
| for(g=1; g<=maxmulops; g++) { |
| if(g >= maxmulops && v >= 65535) |
| break; |
| mulcp = hint+g; |
| *mulcp = 0; |
| if(gen1(g)) { |
| if(docode(hint, m->code, 1, 0)) |
| return m; |
| print("multiply table failure %d\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) { |
| strcpy(m->code, m1->code); |
| sprint(strchr(m->code, 0), "%c0", 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, int32 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, int32 r0, int32 r1, int flag) |
| { |
| int i, f1, f2; |
| int32 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); |