| // cmd/9c/peep.c from Vita Nuova. |
| // |
| // 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-2008 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-2008 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" |
| |
| /* |
| static Reg* |
| rnops(Reg *r) |
| { |
| Prog *p; |
| Reg *r1; |
| |
| if(r != R) |
| for(;;){ |
| p = r->prog; |
| if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE) |
| break; |
| r1 = uniqs(r); |
| if(r1 == R) |
| break; |
| r = r1; |
| } |
| return r; |
| } |
| */ |
| |
| void |
| peep(void) |
| { |
| Reg *r, *r1, *r2; |
| Prog *p, *p1; |
| int t; |
| /* |
| * complete R structure |
| */ |
| t = 0; |
| for(r=firstr; r!=R; r=r1) { |
| r1 = r->link; |
| if(r1 == R) |
| break; |
| p = r->prog->link; |
| while(p != r1->prog) |
| switch(p->as) { |
| default: |
| r2 = rega(); |
| r->link = r2; |
| r2->link = r1; |
| |
| r2->prog = p; |
| r2->p1 = r; |
| r->s1 = r2; |
| r2->s1 = r1; |
| r1->p1 = r2; |
| |
| r = r2; |
| t++; |
| |
| case ADATA: |
| case AGLOBL: |
| case ANAME: |
| case ASIGNAME: |
| p = p->link; |
| } |
| } |
| |
| loop1: |
| t = 0; |
| for(r=firstr; r!=R; r=r->link) { |
| p = r->prog; |
| if(p->as == AMOVW || p->as == AMOVD || p->as == AFMOVS || p->as == AFMOVD) |
| if(regtyp(&p->to)) { |
| if(regtyp(&p->from)) |
| if(p->from.type == p->to.type) { |
| if(copyprop(r)) { |
| excise(r); |
| t++; |
| } else |
| if(subprop(r) && copyprop(r)) { |
| excise(r); |
| t++; |
| } |
| } |
| if(regzer(&p->from)) |
| if(p->to.type == D_REG) { |
| p->from.type = D_REG; |
| p->from.reg = REGZERO; |
| if(copyprop(r)) { |
| excise(r); |
| t++; |
| } else |
| if(subprop(r) && copyprop(r)) { |
| excise(r); |
| t++; |
| } |
| } |
| } |
| } |
| if(t) |
| goto loop1; |
| /* |
| * look for MOVB x,R; MOVB R,R |
| */ |
| for(r=firstr; r!=R; r=r->link) { |
| p = r->prog; |
| switch(p->as) { |
| default: |
| continue; |
| case AMOVH: |
| case AMOVHZ: |
| case AMOVB: |
| case AMOVBZ: |
| case AMOVW: |
| case AMOVWZ: |
| if(p->to.type != D_REG) |
| continue; |
| break; |
| } |
| r1 = r->link; |
| if(r1 == R) |
| continue; |
| p1 = r1->prog; |
| if(p1->as != p->as) |
| continue; |
| if(p1->from.type != D_REG || p1->from.reg != p->to.reg) |
| continue; |
| if(p1->to.type != D_REG || p1->to.reg != p->to.reg) |
| continue; |
| excise(r1); |
| } |
| |
| if(debug['D'] > 1) |
| return; /* allow following code improvement to be suppressed */ |
| |
| /* |
| * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R |
| * when OP can set condition codes correctly |
| */ |
| for(r=firstr; r!=R; r=r->link) { |
| p = r->prog; |
| switch(p->as) { |
| case ACMP: |
| case ACMPW: /* always safe? */ |
| if(!regzer(&p->to)) |
| continue; |
| r1 = r->s1; |
| if(r1 == R) |
| continue; |
| switch(r1->prog->as) { |
| default: |
| continue; |
| case ABCL: |
| case ABC: |
| /* the conditions can be complex and these are currently little used */ |
| continue; |
| case ABEQ: |
| case ABGE: |
| case ABGT: |
| case ABLE: |
| case ABLT: |
| case ABNE: |
| case ABVC: |
| case ABVS: |
| break; |
| } |
| r1 = r; |
| do |
| r1 = uniqp(r1); |
| while (r1 != R && r1->prog->as == ANOP); |
| if(r1 == R) |
| continue; |
| p1 = r1->prog; |
| if(p1->to.type != D_REG || p1->to.reg != p->from.reg) |
| continue; |
| switch(p1->as) { |
| case ASUB: |
| case AADD: |
| case AXOR: |
| case AOR: |
| /* irregular instructions */ |
| if(p1->from.type == D_CONST) |
| continue; |
| break; |
| } |
| switch(p1->as) { |
| default: |
| continue; |
| case AMOVW: |
| case AMOVD: |
| if(p1->from.type != D_REG) |
| continue; |
| continue; |
| case AANDCC: |
| case AANDNCC: |
| case AORCC: |
| case AORNCC: |
| case AXORCC: |
| case ASUBCC: |
| case ASUBECC: |
| case ASUBMECC: |
| case ASUBZECC: |
| case AADDCC: |
| case AADDCCC: |
| case AADDECC: |
| case AADDMECC: |
| case AADDZECC: |
| case ARLWMICC: |
| case ARLWNMCC: |
| t = p1->as; |
| break; |
| /* don't deal with floating point instructions for now */ |
| /* |
| case AFABS: t = AFABSCC; break; |
| case AFADD: t = AFADDCC; break; |
| case AFADDS: t = AFADDSCC; break; |
| case AFCTIW: t = AFCTIWCC; break; |
| case AFCTIWZ: t = AFCTIWZCC; break; |
| case AFDIV: t = AFDIVCC; break; |
| case AFDIVS: t = AFDIVSCC; break; |
| case AFMADD: t = AFMADDCC; break; |
| case AFMADDS: t = AFMADDSCC; break; |
| case AFMOVD: t = AFMOVDCC; break; |
| case AFMSUB: t = AFMSUBCC; break; |
| case AFMSUBS: t = AFMSUBSCC; break; |
| case AFMUL: t = AFMULCC; break; |
| case AFMULS: t = AFMULSCC; break; |
| case AFNABS: t = AFNABSCC; break; |
| case AFNEG: t = AFNEGCC; break; |
| case AFNMADD: t = AFNMADDCC; break; |
| case AFNMADDS: t = AFNMADDSCC; break; |
| case AFNMSUB: t = AFNMSUBCC; break; |
| case AFNMSUBS: t = AFNMSUBSCC; break; |
| case AFRSP: t = AFRSPCC; break; |
| case AFSUB: t = AFSUBCC; break; |
| case AFSUBS: t = AFSUBSCC; break; |
| case ACNTLZW: t = ACNTLZWCC; break; |
| case AMTFSB0: t = AMTFSB0CC; break; |
| case AMTFSB1: t = AMTFSB1CC; break; |
| */ |
| case AADD: t = AADDCC; break; |
| case AADDV: t = AADDVCC; break; |
| case AADDC: t = AADDCCC; break; |
| case AADDCV: t = AADDCVCC; break; |
| case AADDME: t = AADDMECC; break; |
| case AADDMEV: t = AADDMEVCC; break; |
| case AADDE: t = AADDECC; break; |
| case AADDEV: t = AADDEVCC; break; |
| case AADDZE: t = AADDZECC; break; |
| case AADDZEV: t = AADDZEVCC; break; |
| case AAND: t = AANDCC; break; |
| case AANDN: t = AANDNCC; break; |
| case ADIVW: t = ADIVWCC; break; |
| case ADIVWV: t = ADIVWVCC; break; |
| case ADIVWU: t = ADIVWUCC; break; |
| case ADIVWUV: t = ADIVWUVCC; break; |
| case ADIVD: t = ADIVDCC; break; |
| case ADIVDV: t = ADIVDVCC; break; |
| case ADIVDU: t = ADIVDUCC; break; |
| case ADIVDUV: t = ADIVDUVCC; break; |
| case AEQV: t = AEQVCC; break; |
| case AEXTSB: t = AEXTSBCC; break; |
| case AEXTSH: t = AEXTSHCC; break; |
| case AEXTSW: t = AEXTSWCC; break; |
| case AMULHW: t = AMULHWCC; break; |
| case AMULHWU: t = AMULHWUCC; break; |
| case AMULLW: t = AMULLWCC; break; |
| case AMULLWV: t = AMULLWVCC; break; |
| case AMULHD: t = AMULHDCC; break; |
| case AMULHDU: t = AMULHDUCC; break; |
| case AMULLD: t = AMULLDCC; break; |
| case AMULLDV: t = AMULLDVCC; break; |
| case ANAND: t = ANANDCC; break; |
| case ANEG: t = ANEGCC; break; |
| case ANEGV: t = ANEGVCC; break; |
| case ANOR: t = ANORCC; break; |
| case AOR: t = AORCC; break; |
| case AORN: t = AORNCC; break; |
| case AREM: t = AREMCC; break; |
| case AREMV: t = AREMVCC; break; |
| case AREMU: t = AREMUCC; break; |
| case AREMUV: t = AREMUVCC; break; |
| case AREMD: t = AREMDCC; break; |
| case AREMDV: t = AREMDVCC; break; |
| case AREMDU: t = AREMDUCC; break; |
| case AREMDUV: t = AREMDUVCC; break; |
| case ARLWMI: t = ARLWMICC; break; |
| case ARLWNM: t = ARLWNMCC; break; |
| case ASLW: t = ASLWCC; break; |
| case ASRAW: t = ASRAWCC; break; |
| case ASRW: t = ASRWCC; break; |
| case ASLD: t = ASLDCC; break; |
| case ASRAD: t = ASRADCC; break; |
| case ASRD: t = ASRDCC; break; |
| case ASUB: t = ASUBCC; break; |
| case ASUBV: t = ASUBVCC; break; |
| case ASUBC: t = ASUBCCC; break; |
| case ASUBCV: t = ASUBCVCC; break; |
| case ASUBME: t = ASUBMECC; break; |
| case ASUBMEV: t = ASUBMEVCC; break; |
| case ASUBE: t = ASUBECC; break; |
| case ASUBEV: t = ASUBEVCC; break; |
| case ASUBZE: t = ASUBZECC; break; |
| case ASUBZEV: t = ASUBZEVCC; break; |
| case AXOR: t = AXORCC; break; |
| break; |
| } |
| if(debug['D']) |
| print("cmp %P; %P -> ", p1, p); |
| p1->as = t; |
| if(debug['D']) |
| print("%P\n", p1); |
| excise(r); |
| continue; |
| } |
| } |
| } |
| |
| void |
| excise(Reg *r) |
| { |
| Prog *p; |
| |
| p = r->prog; |
| p->as = ANOP; |
| p->from = zprog.from; |
| p->from3 = zprog.from3; |
| p->to = zprog.to; |
| p->reg = zprog.reg; /**/ |
| } |
| |
| Reg* |
| uniqp(Reg *r) |
| { |
| Reg *r1; |
| |
| r1 = r->p1; |
| if(r1 == R) { |
| r1 = r->p2; |
| if(r1 == R || r1->p2link != R) |
| return R; |
| } else |
| if(r->p2 != R) |
| return R; |
| return r1; |
| } |
| |
| Reg* |
| uniqs(Reg *r) |
| { |
| Reg *r1; |
| |
| r1 = r->s1; |
| if(r1 == R) { |
| r1 = r->s2; |
| if(r1 == R) |
| return R; |
| } else |
| if(r->s2 != R) |
| return R; |
| return r1; |
| } |
| |
| /* |
| * if the system forces R0 to be zero, |
| * convert references to $0 to references to R0. |
| */ |
| int |
| regzer(Addr *a) |
| { |
| if(R0ISZERO) { |
| if(a->type == D_CONST) |
| if(a->sym == nil) |
| if(a->offset == 0) |
| return 1; |
| if(a->type == D_REG) |
| if(a->reg == REGZERO) |
| return 1; |
| } |
| return 0; |
| } |
| |
| int |
| regtyp(Addr *a) |
| { |
| |
| if(a->type == D_REG) { |
| if(!R0ISZERO || a->reg != REGZERO) |
| return 1; |
| return 0; |
| } |
| if(a->type == D_FREG) |
| return 1; |
| return 0; |
| } |
| |
| /* |
| * the idea is to substitute |
| * one register for another |
| * from one MOV to another |
| * MOV a, R0 |
| * ADD b, R0 / no use of R1 |
| * MOV R0, R1 |
| * would be converted to |
| * MOV a, R1 |
| * ADD b, R1 |
| * MOV R1, R0 |
| * hopefully, then the former or latter MOV |
| * will be eliminated by copy propagation. |
| */ |
| int |
| subprop(Reg *r0) |
| { |
| Prog *p; |
| Addr *v1, *v2; |
| Reg *r; |
| int t; |
| |
| p = r0->prog; |
| v1 = &p->from; |
| if(!regtyp(v1)) |
| return 0; |
| v2 = &p->to; |
| if(!regtyp(v2)) |
| return 0; |
| for(r=uniqp(r0); r!=R; r=uniqp(r)) { |
| if(uniqs(r) == R) |
| break; |
| p = r->prog; |
| switch(p->as) { |
| case ABL: |
| return 0; |
| |
| case AADD: |
| case AADDC: |
| case AADDCC: |
| case AADDE: |
| case AADDECC: |
| case ASUB: |
| case ASUBCC: |
| case ASUBC: |
| case ASUBCCC: |
| case ASUBE: |
| case ASUBECC: |
| case ASLW: |
| case ASRW: |
| case ASRWCC: |
| case ASRAW: |
| case ASRAWCC: |
| case ASLD: |
| case ASRD: |
| case ASRAD: |
| case AOR: |
| case AORCC: |
| case AORN: |
| case AORNCC: |
| case AAND: |
| case AANDCC: |
| case AANDN: |
| case AANDNCC: |
| case ANAND: |
| case ANANDCC: |
| case ANOR: |
| case ANORCC: |
| case AXOR: |
| case AXORCC: |
| case AMULHW: |
| case AMULHWU: |
| case AMULLW: |
| case AMULLD: |
| case ADIVW: |
| case ADIVWU: |
| case ADIVD: |
| case ADIVDU: |
| case AREM: |
| case AREMU: |
| case AREMD: |
| case AREMDU: |
| case ARLWNM: |
| case ARLWNMCC: |
| |
| case AFADD: |
| case AFADDS: |
| case AFSUB: |
| case AFSUBS: |
| case AFMUL: |
| case AFMULS: |
| case AFDIV: |
| case AFDIVS: |
| if(p->to.type == v1->type) |
| if(p->to.reg == v1->reg) { |
| if(p->reg == NREG) |
| p->reg = p->to.reg; |
| goto gotit; |
| } |
| break; |
| |
| case AADDME: |
| case AADDMECC: |
| case AADDZE: |
| case AADDZECC: |
| case ASUBME: |
| case ASUBMECC: |
| case ASUBZE: |
| case ASUBZECC: |
| case ANEG: |
| case ANEGCC: |
| case AFNEG: |
| case AFNEGCC: |
| case AFMOVS: |
| case AFMOVD: |
| case AMOVW: |
| case AMOVD: |
| if(p->to.type == v1->type) |
| if(p->to.reg == v1->reg) |
| goto gotit; |
| break; |
| } |
| if(copyau(&p->from, v2) || |
| copyau1(p, v2) || |
| copyau(&p->to, v2)) |
| break; |
| if(copysub(&p->from, v1, v2, 0) || |
| copysub1(p, v1, v2, 0) || |
| copysub(&p->to, v1, v2, 0)) |
| break; |
| } |
| return 0; |
| |
| gotit: |
| copysub(&p->to, v1, v2, 1); |
| if(debug['P']) { |
| print("gotit: %D->%D\n%P", v1, v2, r->prog); |
| if(p->from.type == v2->type) |
| print(" excise"); |
| print("\n"); |
| } |
| for(r=uniqs(r); r!=r0; r=uniqs(r)) { |
| p = r->prog; |
| copysub(&p->from, v1, v2, 1); |
| copysub1(p, v1, v2, 1); |
| copysub(&p->to, v1, v2, 1); |
| if(debug['P']) |
| print("%P\n", r->prog); |
| } |
| t = v1->reg; |
| v1->reg = v2->reg; |
| v2->reg = t; |
| if(debug['P']) |
| print("%P last\n", r->prog); |
| return 1; |
| } |
| |
| /* |
| * The idea is to remove redundant copies. |
| * v1->v2 F=0 |
| * (use v2 s/v2/v1/)* |
| * set v1 F=1 |
| * use v2 return fail |
| * ----------------- |
| * v1->v2 F=0 |
| * (use v2 s/v2/v1/)* |
| * set v1 F=1 |
| * set v2 return success |
| */ |
| int |
| copyprop(Reg *r0) |
| { |
| Prog *p; |
| Addr *v1, *v2; |
| Reg *r; |
| |
| p = r0->prog; |
| v1 = &p->from; |
| v2 = &p->to; |
| if(copyas(v1, v2)) |
| return 1; |
| for(r=firstr; r!=R; r=r->link) |
| r->active = 0; |
| return copy1(v1, v2, r0->s1, 0); |
| } |
| |
| int |
| copy1(Addr *v1, Addr *v2, Reg *r, int f) |
| { |
| int t; |
| Prog *p; |
| |
| if(r->active) { |
| if(debug['P']) |
| print("act set; return 1\n"); |
| return 1; |
| } |
| r->active = 1; |
| if(debug['P']) |
| print("copy %D->%D f=%d\n", v1, v2, f); |
| for(; r != R; r = r->s1) { |
| p = r->prog; |
| if(debug['P']) |
| print("%P", p); |
| if(!f && uniqp(r) == R) { |
| f = 1; |
| if(debug['P']) |
| print("; merge; f=%d", f); |
| } |
| t = copyu(p, v2, nil); |
| switch(t) { |
| case 2: /* rar, cant split */ |
| if(debug['P']) |
| print("; %Drar; return 0\n", v2); |
| return 0; |
| |
| case 3: /* set */ |
| if(debug['P']) |
| print("; %Dset; return 1\n", v2); |
| return 1; |
| |
| case 1: /* used, substitute */ |
| case 4: /* use and set */ |
| if(f) { |
| if(!debug['P']) |
| return 0; |
| if(t == 4) |
| print("; %Dused+set and f=%d; return 0\n", v2, f); |
| else |
| print("; %Dused and f=%d; return 0\n", v2, f); |
| return 0; |
| } |
| if(copyu(p, v2, v1)) { |
| if(debug['P']) |
| print("; sub fail; return 0\n"); |
| return 0; |
| } |
| if(debug['P']) |
| print("; sub%D/%D", v2, v1); |
| if(t == 4) { |
| if(debug['P']) |
| print("; %Dused+set; return 1\n", v2); |
| return 1; |
| } |
| break; |
| } |
| if(!f) { |
| t = copyu(p, v1, nil); |
| if(!f && (t == 2 || t == 3 || t == 4)) { |
| f = 1; |
| if(debug['P']) |
| print("; %Dset and !f; f=%d", v1, f); |
| } |
| } |
| if(debug['P']) |
| print("\n"); |
| if(r->s2) |
| if(!copy1(v1, v2, r->s2, f)) |
| return 0; |
| } |
| return 1; |
| } |
| |
| /* |
| * return |
| * 1 if v only used (and substitute), |
| * 2 if read-alter-rewrite |
| * 3 if set |
| * 4 if set and used |
| * 0 otherwise (not touched) |
| */ |
| int |
| copyu(Prog *p, Addr *v, Addr *s) |
| { |
| |
| switch(p->as) { |
| |
| default: |
| if(debug['P']) |
| print(" (\?\?\?)"); |
| return 2; |
| |
| |
| case ANOP: /* read, write */ |
| case AMOVH: |
| case AMOVHZ: |
| case AMOVB: |
| case AMOVBZ: |
| case AMOVW: |
| case AMOVWZ: |
| case AMOVD: |
| |
| case ANEG: |
| case ANEGCC: |
| case AADDME: |
| case AADDMECC: |
| case AADDZE: |
| case AADDZECC: |
| case ASUBME: |
| case ASUBMECC: |
| case ASUBZE: |
| case ASUBZECC: |
| |
| case AFCTIW: |
| case AFCTIWZ: |
| case AFMOVS: |
| case AFMOVD: |
| case AFRSP: |
| case AFNEG: |
| case AFNEGCC: |
| if(s != nil) { |
| if(copysub(&p->from, v, s, 1)) |
| return 1; |
| if(!copyas(&p->to, v)) |
| if(copysub(&p->to, v, s, 1)) |
| return 1; |
| return 0; |
| } |
| if(copyas(&p->to, v)) { |
| if(copyau(&p->from, v)) |
| return 4; |
| return 3; |
| } |
| if(copyau(&p->from, v)) |
| return 1; |
| if(copyau(&p->to, v)) |
| return 1; |
| return 0; |
| |
| case ARLWMI: /* read read rar */ |
| case ARLWMICC: |
| if(copyas(&p->to, v)) |
| return 2; |
| /* fall through */ |
| |
| case AADD: /* read read write */ |
| case AADDC: |
| case AADDE: |
| case ASUB: |
| case ASLW: |
| case ASRW: |
| case ASRAW: |
| case ASLD: |
| case ASRD: |
| case ASRAD: |
| case AOR: |
| case AORCC: |
| case AORN: |
| case AORNCC: |
| case AAND: |
| case AANDCC: |
| case AANDN: |
| case AANDNCC: |
| case ANAND: |
| case ANANDCC: |
| case ANOR: |
| case ANORCC: |
| case AXOR: |
| case AMULHW: |
| case AMULHWU: |
| case AMULLW: |
| case AMULLD: |
| case ADIVW: |
| case ADIVD: |
| case ADIVWU: |
| case ADIVDU: |
| case AREM: |
| case AREMU: |
| case AREMD: |
| case AREMDU: |
| case ARLWNM: |
| case ARLWNMCC: |
| |
| case AFADDS: |
| case AFADD: |
| case AFSUBS: |
| case AFSUB: |
| case AFMULS: |
| case AFMUL: |
| case AFDIVS: |
| case AFDIV: |
| if(s != nil) { |
| if(copysub(&p->from, v, s, 1)) |
| return 1; |
| if(copysub1(p, v, s, 1)) |
| return 1; |
| if(!copyas(&p->to, v)) |
| if(copysub(&p->to, v, s, 1)) |
| return 1; |
| return 0; |
| } |
| if(copyas(&p->to, v)) { |
| if(p->reg == NREG) |
| p->reg = p->to.reg; |
| if(copyau(&p->from, v)) |
| return 4; |
| if(copyau1(p, v)) |
| return 4; |
| return 3; |
| } |
| if(copyau(&p->from, v)) |
| return 1; |
| if(copyau1(p, v)) |
| return 1; |
| if(copyau(&p->to, v)) |
| return 1; |
| return 0; |
| |
| case ABEQ: |
| case ABGT: |
| case ABGE: |
| case ABLT: |
| case ABLE: |
| case ABNE: |
| case ABVC: |
| case ABVS: |
| break; |
| |
| case ACMP: /* read read */ |
| case ACMPU: |
| case ACMPW: |
| case ACMPWU: |
| case AFCMPO: |
| case AFCMPU: |
| if(s != nil) { |
| if(copysub(&p->from, v, s, 1)) |
| return 1; |
| return copysub(&p->to, v, s, 1); |
| } |
| if(copyau(&p->from, v)) |
| return 1; |
| if(copyau(&p->to, v)) |
| return 1; |
| break; |
| |
| case ABR: /* funny */ |
| if(s != nil) { |
| if(copysub(&p->to, v, s, 1)) |
| return 1; |
| return 0; |
| } |
| if(copyau(&p->to, v)) |
| return 1; |
| return 0; |
| |
| case ARETURN: /* funny */ |
| if(v->type == D_REG) |
| if(v->reg == REGRET) |
| return 2; |
| if(v->type == D_FREG) |
| if(v->reg == FREGRET) |
| return 2; |
| |
| case ABL: /* funny */ |
| if(v->type == D_REG) { |
| if(v->reg <= REGEXT && v->reg > exregoffset) |
| return 2; |
| if(v->reg == REGARG) |
| return 2; |
| } |
| if(v->type == D_FREG) { |
| if(v->reg <= FREGEXT && v->reg > exfregoffset) |
| return 2; |
| } |
| |
| if(s != nil) { |
| if(copysub(&p->to, v, s, 1)) |
| return 1; |
| return 0; |
| } |
| if(copyau(&p->to, v)) |
| return 4; |
| return 3; |
| |
| case ATEXT: /* funny */ |
| if(v->type == D_REG) |
| if(v->reg == REGARG) |
| return 3; |
| return 0; |
| } |
| return 0; |
| } |
| |
| int |
| a2type(Prog *p) |
| { |
| |
| switch(p->as) { |
| case AADD: |
| case AADDC: |
| case AADDCC: |
| case AADDCCC: |
| case AADDE: |
| case AADDECC: |
| case AADDME: |
| case AADDMECC: |
| case AADDZE: |
| case AADDZECC: |
| case ASUB: |
| case ASUBC: |
| case ASUBCC: |
| case ASUBCCC: |
| case ASUBE: |
| case ASUBECC: |
| case ASUBME: |
| case ASUBMECC: |
| case ASUBZE: |
| case ASUBZECC: |
| case ASLW: |
| case ASLWCC: |
| case ASRW: |
| case ASRWCC: |
| case ASRAW: |
| case ASRAWCC: |
| case ASLD: |
| case ASLDCC: |
| case ASRD: |
| case ASRDCC: |
| case ASRAD: |
| case ASRADCC: |
| case AOR: |
| case AORCC: |
| case AORN: |
| case AORNCC: |
| case AAND: |
| case AANDCC: |
| case AANDN: |
| case AANDNCC: |
| case AXOR: |
| case AXORCC: |
| case ANEG: |
| case ANEGCC: |
| case AMULHW: |
| case AMULHWU: |
| case AMULLW: |
| case AMULLWCC: |
| case ADIVW: |
| case ADIVWCC: |
| case ADIVWU: |
| case ADIVWUCC: |
| case AREM: |
| case AREMCC: |
| case AREMU: |
| case AREMUCC: |
| case AMULLD: |
| case AMULLDCC: |
| case ADIVD: |
| case ADIVDCC: |
| case ADIVDU: |
| case ADIVDUCC: |
| case AREMD: |
| case AREMDCC: |
| case AREMDU: |
| case AREMDUCC: |
| case ANAND: |
| case ANANDCC: |
| case ANOR: |
| case ANORCC: |
| case ARLWMI: |
| case ARLWMICC: |
| case ARLWNM: |
| case ARLWNMCC: |
| return D_REG; |
| |
| case AFADDS: |
| case AFADDSCC: |
| case AFADD: |
| case AFADDCC: |
| case AFSUBS: |
| case AFSUBSCC: |
| case AFSUB: |
| case AFSUBCC: |
| case AFMULS: |
| case AFMULSCC: |
| case AFMUL: |
| case AFMULCC: |
| case AFDIVS: |
| case AFDIVSCC: |
| case AFDIV: |
| case AFDIVCC: |
| case AFNEG: |
| case AFNEGCC: |
| return D_FREG; |
| } |
| return D_NONE; |
| } |
| |
| /* |
| * direct reference, |
| * could be set/use depending on |
| * semantics |
| */ |
| int |
| copyas(Addr *a, Addr *v) |
| { |
| |
| if(regtyp(v)) |
| if(a->type == v->type) |
| if(a->reg == v->reg) |
| return 1; |
| return 0; |
| } |
| |
| /* |
| * either direct or indirect |
| */ |
| int |
| copyau(Addr *a, Addr *v) |
| { |
| |
| if(copyas(a, v)) |
| return 1; |
| if(v->type == D_REG) |
| if(a->type == D_OREG) |
| if(v->reg == a->reg) |
| return 1; |
| return 0; |
| } |
| |
| int |
| copyau1(Prog *p, Addr *v) |
| { |
| |
| if(regtyp(v)) |
| if(p->from.type == v->type || p->to.type == v->type) |
| if(p->reg == v->reg) { |
| if(a2type(p) != v->type) |
| print("botch a2type %P\n", p); |
| return 1; |
| } |
| return 0; |
| } |
| |
| /* |
| * substitute s for v in a |
| * return failure to substitute |
| */ |
| int |
| copysub(Addr *a, Addr *v, Addr *s, int f) |
| { |
| |
| if(f) |
| if(copyau(a, v)) |
| a->reg = s->reg; |
| return 0; |
| } |
| |
| int |
| copysub1(Prog *p1, Addr *v, Addr *s, int f) |
| { |
| |
| if(f) |
| if(copyau1(p1, v)) |
| p1->reg = s->reg; |
| return 0; |
| } |