aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/9g/peep.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/9g/peep.c')
-rw-r--r--src/cmd/9g/peep.c959
1 files changed, 0 insertions, 959 deletions
diff --git a/src/cmd/9g/peep.c b/src/cmd/9g/peep.c
deleted file mode 100644
index cf96d5dcda..0000000000
--- a/src/cmd/9g/peep.c
+++ /dev/null
@@ -1,959 +0,0 @@
-// Derived from Inferno utils/6c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.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 <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "../gc/popt.h"
-#include "opt.h"
-
-static int regzer(Addr *a);
-static int subprop(Flow*);
-static int copyprop(Flow*);
-static int copy1(Addr*, Addr*, Flow*, int);
-static int copyas(Addr*, Addr*);
-static int copyau(Addr*, Addr*);
-static int copysub(Addr*, Addr*, Addr*, int);
-static int copysub1(Prog*, Addr*, Addr*, int);
-static int copyau1(Prog *p, Addr *v);
-static int copyu(Prog *p, Addr *v, Addr *s);
-
-static uint32 gactive;
-
-void
-peep(Prog *firstp)
-{
- Graph *g;
- Flow *r, *r1;
- Prog *p, *p1;
- int t;
-
- g = flowstart(firstp, 0);
- if(g == nil)
- return;
- gactive = 0;
-
-loop1:
- if(debug['P'] && debug['v'])
- dumpit("loop1", g->start, 0);
-
- t = 0;
- for(r=g->start; r!=nil; r=r->link) {
- p = r->prog;
- // TODO(austin) Handle smaller moves. arm and amd64
- // distinguish between moves that moves that *must*
- // sign/zero extend and moves that don't care so they
- // can eliminate moves that don't care without
- // breaking moves that do care. This might let us
- // simplify or remove the next peep loop, too.
- if(p->as == AMOVD || p->as == AFMOVD)
- if(regtyp(&p->to)) {
- // Try to eliminate reg->reg moves
- 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++;
- }
- }
- // Convert uses to $0 to uses of R0 and
- // propagate R0
- if(regzer(&p->from))
- if(p->to.type == TYPE_REG) {
- p->from.type = TYPE_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 small MOVs not handled above)
- */
- for(r=g->start; r!=nil; 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 != TYPE_REG)
- continue;
- break;
- }
- r1 = r->link;
- if(r1 == nil)
- continue;
- p1 = r1->prog;
- if(p1->as != p->as)
- continue;
- if(p1->from.type != TYPE_REG || p1->from.reg != p->to.reg)
- continue;
- if(p1->to.type != TYPE_REG || p1->to.reg != p->to.reg)
- continue;
- excise(r1);
- }
-
- if(debug['D'] > 1)
- goto ret; /* 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=g->start; r!=nil; 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 == nil)
- 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 != nil && r1->prog->as == ANOP);
- if(r1 == nil)
- continue;
- p1 = r1->prog;
- if(p1->to.type != TYPE_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 == TYPE_CONST || p1->from.type == TYPE_ADDR)
- continue;
- break;
- }
- switch(p1->as) {
- default:
- continue;
- case AMOVW:
- case AMOVD:
- if(p1->from.type != TYPE_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:
- /* don't deal with floating point instructions for now */
-/*
- case AFABS:
- case AFADD:
- case AFADDS:
- case AFCTIW:
- case AFCTIWZ:
- case AFDIV:
- case AFDIVS:
- case AFMADD:
- case AFMADDS:
- case AFMOVD:
- case AFMSUB:
- case AFMSUBS:
- case AFMUL:
- case AFMULS:
- case AFNABS:
- case AFNEG:
- case AFNMADD:
- case AFNMADDS:
- case AFNMSUB:
- case AFNMSUBS:
- case AFRSP:
- case AFSUB:
- case AFSUBS:
- case ACNTLZW:
- case AMTFSB0:
- case AMTFSB1:
-*/
- case AADD:
- case AADDV:
- case AADDC:
- case AADDCV:
- case AADDME:
- case AADDMEV:
- case AADDE:
- case AADDEV:
- case AADDZE:
- case AADDZEV:
- case AAND:
- case AANDN:
- case ADIVW:
- case ADIVWV:
- case ADIVWU:
- case ADIVWUV:
- case ADIVD:
- case ADIVDV:
- case ADIVDU:
- case ADIVDUV:
- case AEQV:
- case AEXTSB:
- case AEXTSH:
- case AEXTSW:
- case AMULHW:
- case AMULHWU:
- case AMULLW:
- case AMULLWV:
- case AMULHD:
- case AMULHDU:
- case AMULLD:
- case AMULLDV:
- case ANAND:
- case ANEG:
- case ANEGV:
- case ANOR:
- case AOR:
- case AORN:
- case AREM:
- case AREMV:
- case AREMU:
- case AREMUV:
- case AREMD:
- case AREMDV:
- case AREMDU:
- case AREMDUV:
- case ARLWMI:
- case ARLWNM:
- case ASLW:
- case ASRAW:
- case ASRW:
- case ASLD:
- case ASRAD:
- case ASRD:
- case ASUB:
- case ASUBV:
- case ASUBC:
- case ASUBCV:
- case ASUBME:
- case ASUBMEV:
- case ASUBE:
- case ASUBEV:
- case ASUBZE:
- case ASUBZEV:
- case AXOR:
- t = variant2as(p1->as, as2variant(p1->as) | V_CC);
- break;
- }
- if(debug['D'])
- print("cmp %P; %P -> ", p1, p);
- p1->as = t;
- if(debug['D'])
- print("%P\n", p1);
- excise(r);
- continue;
- }
- }
-
-ret:
- flowend(g);
-}
-
-void
-excise(Flow *r)
-{
- Prog *p;
-
- p = r->prog;
- if(debug['P'] && debug['v'])
- print("%P ===delete===\n", p);
- nopout(p);
- ostats.ndelmov++;
-}
-
-/*
- * regzer returns 1 if a's value is 0 (a is R0 or $0)
- */
-static int
-regzer(Addr *a)
-{
- if(a->type == TYPE_CONST || a->type == TYPE_ADDR)
- if(a->sym == nil && a->reg == 0)
- if(a->offset == 0)
- return 1;
- if(a->type == TYPE_REG)
- if(a->reg == REGZERO)
- return 1;
- return 0;
-}
-
-int
-regtyp(Adr *a)
-{
- // TODO(rsc): Floating point register exclusions?
- return a->type == TYPE_REG && REG_R0 <= a->reg && a->reg <= REG_F31 && a->reg != REGZERO;
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R1
- * ADD b, R1 / no use of R2
- * MOV R1, R2
- * would be converted to
- * MOV a, R2
- * ADD b, R2
- * MOV R2, R1
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- *
- * r0 (the argument, not the register) is the MOV at the end of the
- * above sequences. This returns 1 if it modified any instructions.
- */
-static int
-subprop(Flow *r0)
-{
- Prog *p;
- Addr *v1, *v2;
- Flow *r;
- int t;
- ProgInfo info;
-
- p = r0->prog;
- v1 = &p->from;
- if(!regtyp(v1))
- return 0;
- v2 = &p->to;
- if(!regtyp(v2))
- return 0;
- for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
- if(uniqs(r) == nil)
- break;
- p = r->prog;
- if(p->as == AVARDEF || p->as == AVARKILL)
- continue;
- proginfo(&info, p);
- if(info.flags & Call)
- return 0;
-
- if((info.flags & (RightRead|RightWrite)) == RightWrite) {
- if(p->to.type == v1->type)
- if(p->to.reg == v1->reg)
- goto gotit;
- }
-
- 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 move must remain)
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success (caller can remove v1->v2 move)
- */
-static int
-copyprop(Flow *r0)
-{
- Prog *p;
- Addr *v1, *v2;
-
- p = r0->prog;
- v1 = &p->from;
- v2 = &p->to;
- if(copyas(v1, v2)) {
- if(debug['P'])
- print("eliminating self-move\n", r0->prog);
- return 1;
- }
- gactive++;
- if(debug['P'])
- print("trying to eliminate %D->%D move from:\n%P\n", v1, v2, r0->prog);
- return copy1(v1, v2, r0->s1, 0);
-}
-
-// copy1 replaces uses of v2 with v1 starting at r and returns 1 if
-// all uses were rewritten.
-static int
-copy1(Addr *v1, Addr *v2, Flow *r, int f)
-{
- int t;
- Prog *p;
-
- if(r->active == gactive) {
- if(debug['P'])
- print("act set; return 1\n");
- return 1;
- }
- r->active = gactive;
- if(debug['P'])
- print("copy1 replace %D with %D f=%d\n", v2, v1, f);
- for(; r != nil; r = r->s1) {
- p = r->prog;
- if(debug['P'])
- print("%P", p);
- if(!f && uniqp(r) == nil) {
- // Multiple predecessors; conservatively
- // assume v1 was set on other path
- f = 1;
- if(debug['P'])
- print("; merge; f=%d", f);
- }
- t = copyu(p, v2, nil);
- switch(t) {
- case 2: /* rar, can't split */
- if(debug['P'])
- print("; %D rar; return 0\n", v2);
- return 0;
-
- case 3: /* set */
- if(debug['P'])
- print("; %D set; 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("; %D used+set and f=%d; return 0\n", v2, f);
- else
- print("; %D used 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\n => %P", v2, v1, p);
- if(t == 4) {
- if(debug['P'])
- print("; %D used+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("; %D set 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;
-}
-
-// If s==nil, copyu returns the set/use of v in p; otherwise, it
-// modifies p to replace reads of v with reads of s and returns 0 for
-// success or non-zero for failure.
-//
-// If s==nil, copy returns one of the following values:
-// 1 if v only used
-// 2 if v is set and used in one address (read-alter-rewrite;
-// can't substitute)
-// 3 if v is only set
-// 4 if v is set in one address and used in another (so addresses
-// can be rewritten independently)
-// 0 otherwise (not touched)
-static int
-copyu(Prog *p, Addr *v, Addr *s)
-{
- if(p->from3.type != TYPE_NONE)
- // 9g never generates a from3
- print("copyu: from3 (%D) not implemented\n", &p->from3);
-
- switch(p->as) {
-
- default:
- print("copyu: can't find %A\n", p->as);
- return 2;
-
- case ANOP: /* read p->from, write p->to */
- 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 AFCTID:
- case AFCTIDZ:
- case AFCFID:
- case AFCFIDCC:
- case AFMOVS:
- case AFMOVD:
- case AFRSP:
- case AFNEG:
- case AFNEGCC:
- if(s != nil) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- // Update only indirect uses of v in p->to
- if(!copyas(&p->to, v))
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyas(&p->to, v)) {
- // Fix up implicit from
- if(p->from.type == TYPE_NONE)
- p->from = p->to;
- if(copyau(&p->from, v))
- return 4;
- return 3;
- }
- if(copyau(&p->from, v))
- return 1;
- if(copyau(&p->to, v))
- // p->to only indirectly uses v
- return 1;
- return 0;
-
- case AMOVBU: /* rar p->from, write p->to or read p->from, rar p->to */
- case AMOVBZU:
- case AMOVHU:
- case AMOVHZU:
- case AMOVWZU:
- case AMOVDU:
- if(p->from.type == TYPE_MEM) {
- if(copyas(&p->from, v))
- // No s!=nil check; need to fail
- // anyway in that case
- return 2;
- if(s != nil) {
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyas(&p->to, v))
- return 3;
- } else if (p->to.type == TYPE_MEM) {
- if(copyas(&p->to, v))
- return 2;
- if(s != nil) {
- if(copysub(&p->from, v, s, 1))
- return 1;
- return 0;
- }
- if(copyau(&p->from, v))
- return 1;
- } else {
- print("copyu: bad %P\n", p);
- }
- return 0;
-
- case ARLWMI: /* read p->from, read p->reg, rar p->to */
- case ARLWMICC:
- if(copyas(&p->to, v))
- return 2;
- /* fall through */
-
- case AADD: /* read p->from, read p->reg, write p->to */
- 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;
- // Update only indirect uses of v in p->to
- if(!copyas(&p->to, v))
- if(copysub(&p->to, v, s, 1))
- return 1;
- return 0;
- }
- if(copyas(&p->to, v)) {
- if(p->reg == 0)
- // Fix up implicit reg (e.g., ADD
- // R3,R4 -> ADD R3,R4,R4) so we can
- // update reg and to separately.
- 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:
- return 0;
-
- case ACHECKNIL: /* read p->from */
- case ACMP: /* read p->from, read p->to */
- 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;
- return 0;
-
- case ABR: /* read p->to */
- // 9g never generates a branch to a GPR (this isn't
- // even a normal instruction; liblink turns it in to a
- // mov and a branch).
- 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(s != nil)
- return 0;
- // All registers die at this point, so claim
- // everything is set (and not used).
- return 3;
-
- case ABL: /* funny */
- if(v->type == TYPE_REG) {
- // TODO(rsc): REG_R0 and REG_F0 used to be
- // (when register numbers started at 0) exregoffset and exfregoffset,
- // which are unset entirely.
- // It's strange that this handles R0 and F0 differently from the other
- // registers. Possible failure to optimize?
- if(REG_R0 < v->reg && v->reg <= REGEXT)
- return 2;
- if(v->reg == REGARG)
- return 2;
- if(REG_F0 < v->reg && v->reg <= FREGEXT)
- return 2;
- }
- if(p->from.type == TYPE_REG && v->type == TYPE_REG && p->from.reg == v->reg)
- 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 ADUFFZERO:
- // R0 is zero, used by DUFFZERO, cannot be substituted.
- // R3 is ptr to memory, used and set, cannot be substituted.
- if(v->type == TYPE_REG) {
- if(v->reg == 0)
- return 1;
- if(v->reg == 3)
- return 2;
- }
- return 0;
-
- case ADUFFCOPY:
- // R3, R4 are ptr to src, dst, used and set, cannot be substituted.
- // R5 is scratch, set by DUFFCOPY, cannot be substituted.
- if(v->type == TYPE_REG) {
- if(v->reg == 3 || v->reg == 4)
- return 2;
- if(v->reg == 5)
- return 3;
- }
- return 0;
-
- case ATEXT: /* funny */
- if(v->type == TYPE_REG)
- if(v->reg == REGARG)
- return 3;
- return 0;
-
- case APCDATA:
- case AFUNCDATA:
- case AVARDEF:
- case AVARKILL:
- return 0;
- }
-}
-
-// copyas returns 1 if a and v address the same register.
-//
-// If a is the from operand, this means this operation reads the
-// register in v. If a is the to operand, this means this operation
-// writes the register in v.
-static int
-copyas(Addr *a, Addr *v)
-{
- if(regtyp(v))
- if(a->type == v->type)
- if(a->reg == v->reg)
- return 1;
- return 0;
-}
-
-// copyau returns 1 if a either directly or indirectly addresses the
-// same register as v.
-//
-// If a is the from operand, this means this operation reads the
-// register in v. If a is the to operand, this means the operation
-// either reads or writes the register in v (if !copyas(a, v), then
-// the operation reads the register in v).
-static int
-copyau(Addr *a, Addr *v)
-{
- if(copyas(a, v))
- return 1;
- if(v->type == TYPE_REG)
- if(a->type == TYPE_MEM || (a->type == TYPE_ADDR && a->reg != 0))
- if(v->reg == a->reg)
- return 1;
- return 0;
-}
-
-// copyau1 returns 1 if p->reg references the same register as v and v
-// is a direct reference.
-static int
-copyau1(Prog *p, Addr *v)
-{
- if(regtyp(v) && v->reg != 0)
- if(p->reg == v->reg)
- return 1;
- return 0;
-}
-
-// copysub replaces v with s in a if f!=0 or indicates it if could if f==0.
-// Returns 1 on failure to substitute (it always succeeds on ppc64).
-static int
-copysub(Addr *a, Addr *v, Addr *s, int f)
-{
- if(f)
- if(copyau(a, v))
- a->reg = s->reg;
- return 0;
-}
-
-// copysub1 replaces v with s in p1->reg if f!=0 or indicates if it could if f==0.
-// Returns 1 on failure to substitute (it always succeeds on ppc64).
-static int
-copysub1(Prog *p1, Addr *v, Addr *s, int f)
-{
- if(f)
- if(copyau1(p1, v))
- p1->reg = s->reg;
- return 0;
-}
-
-int
-sameaddr(Addr *a, Addr *v)
-{
- if(a->type != v->type)
- return 0;
- if(regtyp(v) && a->reg == v->reg)
- return 1;
- if(v->type == NAME_AUTO || v->type == NAME_PARAM)
- if(v->offset == a->offset)
- return 1;
- return 0;
-}
-
-int
-smallindir(Addr *a, Addr *reg)
-{
- return reg->type == TYPE_REG && a->type == TYPE_MEM &&
- a->reg == reg->reg &&
- 0 <= a->offset && a->offset < 4096;
-}
-
-int
-stackaddr(Addr *a)
-{
- return a->type == TYPE_REG && a->reg == REGSP;
-}