github.com/aloncn/graphics-go@v0.0.1/src/cmd/compile/internal/arm/peep.go (about)

     1  // Inferno utils/5c/peep.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  package arm
    32  
    33  import (
    34  	"cmd/compile/internal/gc"
    35  	"cmd/internal/obj"
    36  	"cmd/internal/obj/arm"
    37  	"fmt"
    38  )
    39  
    40  var gactive uint32
    41  
    42  // UNUSED
    43  func peep(firstp *obj.Prog) {
    44  	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
    45  	if g == nil {
    46  		return
    47  	}
    48  	gactive = 0
    49  
    50  	var r *gc.Flow
    51  	var p *obj.Prog
    52  	var t int
    53  loop1:
    54  	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    55  		gc.Dumpit("loop1", g.Start, 0)
    56  	}
    57  
    58  	t = 0
    59  	for r = g.Start; r != nil; r = r.Link {
    60  		p = r.Prog
    61  		switch p.As {
    62  		/*
    63  		 * elide shift into TYPE_SHIFT operand of subsequent instruction
    64  		 */
    65  		//			if(shiftprop(r)) {
    66  		//				excise(r);
    67  		//				t++;
    68  		//				break;
    69  		//			}
    70  		case arm.ASLL,
    71  			arm.ASRL,
    72  			arm.ASRA:
    73  			break
    74  
    75  		case arm.AMOVB,
    76  			arm.AMOVH,
    77  			arm.AMOVW,
    78  			arm.AMOVF,
    79  			arm.AMOVD:
    80  			if regtyp(&p.From) {
    81  				if p.From.Type == p.To.Type && isfloatreg(&p.From) == isfloatreg(&p.To) {
    82  					if p.Scond == arm.C_SCOND_NONE {
    83  						if copyprop(g, r) {
    84  							excise(r)
    85  							t++
    86  							break
    87  						}
    88  
    89  						if subprop(r) && copyprop(g, r) {
    90  							excise(r)
    91  							t++
    92  							break
    93  						}
    94  					}
    95  				}
    96  			}
    97  
    98  		case arm.AMOVHS,
    99  			arm.AMOVHU,
   100  			arm.AMOVBS,
   101  			arm.AMOVBU:
   102  			if p.From.Type == obj.TYPE_REG {
   103  				if shortprop(r) {
   104  					t++
   105  				}
   106  			}
   107  		}
   108  	}
   109  
   110  	/*
   111  		if(p->scond == C_SCOND_NONE)
   112  		if(regtyp(&p->to))
   113  		if(isdconst(&p->from)) {
   114  			constprop(&p->from, &p->to, r->s1);
   115  		}
   116  		break;
   117  	*/
   118  	if t != 0 {
   119  		goto loop1
   120  	}
   121  
   122  	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
   123  		p = r.Prog
   124  		switch p.As {
   125  		/*
   126  		 * EOR -1,x,y => MVN x,y
   127  		 */
   128  		case arm.AEOR:
   129  			if isdconst(&p.From) && p.From.Offset == -1 {
   130  				p.As = arm.AMVN
   131  				p.From.Type = obj.TYPE_REG
   132  				if p.Reg != 0 {
   133  					p.From.Reg = p.Reg
   134  				} else {
   135  					p.From.Reg = p.To.Reg
   136  				}
   137  				p.Reg = 0
   138  			}
   139  		}
   140  	}
   141  
   142  	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
   143  		p = r.Prog
   144  		switch p.As {
   145  		case arm.AMOVW,
   146  			arm.AMOVB,
   147  			arm.AMOVBS,
   148  			arm.AMOVBU:
   149  			if p.From.Type == obj.TYPE_MEM && p.From.Offset == 0 {
   150  				xtramodes(g, r, &p.From)
   151  			} else if p.To.Type == obj.TYPE_MEM && p.To.Offset == 0 {
   152  				xtramodes(g, r, &p.To)
   153  			} else {
   154  				continue
   155  			}
   156  		}
   157  	}
   158  
   159  	//		case ACMP:
   160  	//			/*
   161  	//			 * elide CMP $0,x if calculation of x can set condition codes
   162  	//			 */
   163  	//			if(isdconst(&p->from) || p->from.offset != 0)
   164  	//				continue;
   165  	//			r2 = r->s1;
   166  	//			if(r2 == nil)
   167  	//				continue;
   168  	//			t = r2->prog->as;
   169  	//			switch(t) {
   170  	//			default:
   171  	//				continue;
   172  	//			case ABEQ:
   173  	//			case ABNE:
   174  	//			case ABMI:
   175  	//			case ABPL:
   176  	//				break;
   177  	//			case ABGE:
   178  	//				t = ABPL;
   179  	//				break;
   180  	//			case ABLT:
   181  	//				t = ABMI;
   182  	//				break;
   183  	//			case ABHI:
   184  	//				t = ABNE;
   185  	//				break;
   186  	//			case ABLS:
   187  	//				t = ABEQ;
   188  	//				break;
   189  	//			}
   190  	//			r1 = r;
   191  	//			do
   192  	//				r1 = uniqp(r1);
   193  	//			while (r1 != nil && r1->prog->as == ANOP);
   194  	//			if(r1 == nil)
   195  	//				continue;
   196  	//			p1 = r1->prog;
   197  	//			if(p1->to.type != TYPE_REG)
   198  	//				continue;
   199  	//			if(p1->to.reg != p->reg)
   200  	//			if(!(p1->as == AMOVW && p1->from.type == TYPE_REG && p1->from.reg == p->reg))
   201  	//				continue;
   202  	//
   203  	//			switch(p1->as) {
   204  	//			default:
   205  	//				continue;
   206  	//			case AMOVW:
   207  	//				if(p1->from.type != TYPE_REG)
   208  	//					continue;
   209  	//			case AAND:
   210  	//			case AEOR:
   211  	//			case AORR:
   212  	//			case ABIC:
   213  	//			case AMVN:
   214  	//			case ASUB:
   215  	//			case ARSB:
   216  	//			case AADD:
   217  	//			case AADC:
   218  	//			case ASBC:
   219  	//			case ARSC:
   220  	//				break;
   221  	//			}
   222  	//			p1->scond |= C_SBIT;
   223  	//			r2->prog->as = t;
   224  	//			excise(r);
   225  	//			continue;
   226  
   227  	//	predicate(g);
   228  
   229  	gc.Flowend(g)
   230  }
   231  
   232  func regtyp(a *obj.Addr) bool {
   233  	return a.Type == obj.TYPE_REG && (arm.REG_R0 <= a.Reg && a.Reg <= arm.REG_R15 || arm.REG_F0 <= a.Reg && a.Reg <= arm.REG_F15)
   234  }
   235  
   236  /*
   237   * the idea is to substitute
   238   * one register for another
   239   * from one MOV to another
   240   *	MOV	a, R0
   241   *	ADD	b, R0	/ no use of R1
   242   *	MOV	R0, R1
   243   * would be converted to
   244   *	MOV	a, R1
   245   *	ADD	b, R1
   246   *	MOV	R1, R0
   247   * hopefully, then the former or latter MOV
   248   * will be eliminated by copy propagation.
   249   */
   250  func subprop(r0 *gc.Flow) bool {
   251  	p := (*obj.Prog)(r0.Prog)
   252  	v1 := (*obj.Addr)(&p.From)
   253  	if !regtyp(v1) {
   254  		return false
   255  	}
   256  	v2 := (*obj.Addr)(&p.To)
   257  	if !regtyp(v2) {
   258  		return false
   259  	}
   260  	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
   261  		if gc.Uniqs(r) == nil {
   262  			break
   263  		}
   264  		p = r.Prog
   265  		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
   266  			continue
   267  		}
   268  		if p.Info.Flags&gc.Call != 0 {
   269  			return false
   270  		}
   271  
   272  		// TODO(rsc): Whatever invalidated the info should have done this call.
   273  		proginfo(p)
   274  
   275  		if (p.Info.Flags&gc.CanRegRead != 0) && p.To.Type == obj.TYPE_REG {
   276  			p.Info.Flags |= gc.RegRead
   277  			p.Info.Flags &^= (gc.CanRegRead | gc.RightRead)
   278  			p.Reg = p.To.Reg
   279  		}
   280  
   281  		switch p.As {
   282  		case arm.AMULLU,
   283  			arm.AMULA,
   284  			arm.AMVN:
   285  			return false
   286  		}
   287  
   288  		if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite {
   289  			if p.To.Type == v1.Type {
   290  				if p.To.Reg == v1.Reg {
   291  					if p.Scond == arm.C_SCOND_NONE {
   292  						copysub(&p.To, v1, v2, 1)
   293  						if gc.Debug['P'] != 0 {
   294  							fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
   295  							if p.From.Type == v2.Type {
   296  								fmt.Printf(" excise")
   297  							}
   298  							fmt.Printf("\n")
   299  						}
   300  
   301  						for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
   302  							p = r.Prog
   303  							copysub(&p.From, v1, v2, 1)
   304  							copysub1(p, v1, v2, 1)
   305  							copysub(&p.To, v1, v2, 1)
   306  							if gc.Debug['P'] != 0 {
   307  								fmt.Printf("%v\n", r.Prog)
   308  							}
   309  						}
   310  
   311  						t := int(int(v1.Reg))
   312  						v1.Reg = v2.Reg
   313  						v2.Reg = int16(t)
   314  						if gc.Debug['P'] != 0 {
   315  							fmt.Printf("%v last\n", r.Prog)
   316  						}
   317  						return true
   318  					}
   319  				}
   320  			}
   321  		}
   322  
   323  		if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) {
   324  			break
   325  		}
   326  		if copysub(&p.From, v1, v2, 0) != 0 || copysub1(p, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 {
   327  			break
   328  		}
   329  	}
   330  
   331  	return false
   332  }
   333  
   334  /*
   335   * The idea is to remove redundant copies.
   336   *	v1->v2	F=0
   337   *	(use v2	s/v2/v1/)*
   338   *	set v1	F=1
   339   *	use v2	return fail
   340   *	-----------------
   341   *	v1->v2	F=0
   342   *	(use v2	s/v2/v1/)*
   343   *	set v1	F=1
   344   *	set v2	return success
   345   */
   346  func copyprop(g *gc.Graph, r0 *gc.Flow) bool {
   347  	p := (*obj.Prog)(r0.Prog)
   348  	v1 := (*obj.Addr)(&p.From)
   349  	v2 := (*obj.Addr)(&p.To)
   350  	if copyas(v1, v2) {
   351  		return true
   352  	}
   353  	gactive++
   354  	return copy1(v1, v2, r0.S1, 0)
   355  }
   356  
   357  func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
   358  	if uint32(r.Active) == gactive {
   359  		if gc.Debug['P'] != 0 {
   360  			fmt.Printf("act set; return 1\n")
   361  		}
   362  		return true
   363  	}
   364  
   365  	r.Active = int32(gactive)
   366  	if gc.Debug['P'] != 0 {
   367  		fmt.Printf("copy %v->%v f=%d\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f)
   368  	}
   369  	var t int
   370  	var p *obj.Prog
   371  	for ; r != nil; r = r.S1 {
   372  		p = r.Prog
   373  		if gc.Debug['P'] != 0 {
   374  			fmt.Printf("%v", p)
   375  		}
   376  		if f == 0 && gc.Uniqp(r) == nil {
   377  			f = 1
   378  			if gc.Debug['P'] != 0 {
   379  				fmt.Printf("; merge; f=%d", f)
   380  			}
   381  		}
   382  
   383  		t = copyu(p, v2, nil)
   384  		switch t {
   385  		case 2: /* rar, can't split */
   386  			if gc.Debug['P'] != 0 {
   387  				fmt.Printf("; %vrar; return 0\n", gc.Ctxt.Dconv(v2))
   388  			}
   389  			return false
   390  
   391  		case 3: /* set */
   392  			if gc.Debug['P'] != 0 {
   393  				fmt.Printf("; %vset; return 1\n", gc.Ctxt.Dconv(v2))
   394  			}
   395  			return true
   396  
   397  		case 1, /* used, substitute */
   398  			4: /* use and set */
   399  			if f != 0 {
   400  				if gc.Debug['P'] == 0 {
   401  					return false
   402  				}
   403  				if t == 4 {
   404  					fmt.Printf("; %vused+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
   405  				} else {
   406  					fmt.Printf("; %vused and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
   407  				}
   408  				return false
   409  			}
   410  
   411  			if copyu(p, v2, v1) != 0 {
   412  				if gc.Debug['P'] != 0 {
   413  					fmt.Printf("; sub fail; return 0\n")
   414  				}
   415  				return false
   416  			}
   417  
   418  			if gc.Debug['P'] != 0 {
   419  				fmt.Printf("; sub%v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1))
   420  			}
   421  			if t == 4 {
   422  				if gc.Debug['P'] != 0 {
   423  					fmt.Printf("; %vused+set; return 1\n", gc.Ctxt.Dconv(v2))
   424  				}
   425  				return true
   426  			}
   427  		}
   428  
   429  		if f == 0 {
   430  			t = copyu(p, v1, nil)
   431  			if f == 0 && (t == 2 || t == 3 || t == 4) {
   432  				f = 1
   433  				if gc.Debug['P'] != 0 {
   434  					fmt.Printf("; %vset and !f; f=%d", gc.Ctxt.Dconv(v1), f)
   435  				}
   436  			}
   437  		}
   438  
   439  		if gc.Debug['P'] != 0 {
   440  			fmt.Printf("\n")
   441  		}
   442  		if r.S2 != nil {
   443  			if !copy1(v1, v2, r.S2, f) {
   444  				return false
   445  			}
   446  		}
   447  	}
   448  
   449  	return true
   450  }
   451  
   452  // UNUSED
   453  /*
   454   * The idea is to remove redundant constants.
   455   *	$c1->v1
   456   *	($c1->v2 s/$c1/v1)*
   457   *	set v1  return
   458   * The v1->v2 should be eliminated by copy propagation.
   459   */
   460  func constprop(c1 *obj.Addr, v1 *obj.Addr, r *gc.Flow) {
   461  	if gc.Debug['P'] != 0 {
   462  		fmt.Printf("constprop %v->%v\n", gc.Ctxt.Dconv(c1), gc.Ctxt.Dconv(v1))
   463  	}
   464  	var p *obj.Prog
   465  	for ; r != nil; r = r.S1 {
   466  		p = r.Prog
   467  		if gc.Debug['P'] != 0 {
   468  			fmt.Printf("%v", p)
   469  		}
   470  		if gc.Uniqp(r) == nil {
   471  			if gc.Debug['P'] != 0 {
   472  				fmt.Printf("; merge; return\n")
   473  			}
   474  			return
   475  		}
   476  
   477  		if p.As == arm.AMOVW && copyas(&p.From, c1) {
   478  			if gc.Debug['P'] != 0 {
   479  				fmt.Printf("; sub%v/%v", gc.Ctxt.Dconv(&p.From), gc.Ctxt.Dconv(v1))
   480  			}
   481  			p.From = *v1
   482  		} else if copyu(p, v1, nil) > 1 {
   483  			if gc.Debug['P'] != 0 {
   484  				fmt.Printf("; %vset; return\n", gc.Ctxt.Dconv(v1))
   485  			}
   486  			return
   487  		}
   488  
   489  		if gc.Debug['P'] != 0 {
   490  			fmt.Printf("\n")
   491  		}
   492  		if r.S2 != nil {
   493  			constprop(c1, v1, r.S2)
   494  		}
   495  	}
   496  }
   497  
   498  /*
   499   * shortprop eliminates redundant zero/sign extensions.
   500   *
   501   *   MOVBS x, R
   502   *   <no use R>
   503   *   MOVBS R, R'
   504   *
   505   * changed to
   506   *
   507   *   MOVBS x, R
   508   *   ...
   509   *   MOVB  R, R' (compiled to mov)
   510   *
   511   * MOVBS above can be a MOVBS, MOVBU, MOVHS or MOVHU.
   512   */
   513  func shortprop(r *gc.Flow) bool {
   514  	p := (*obj.Prog)(r.Prog)
   515  	r1 := (*gc.Flow)(findpre(r, &p.From))
   516  	if r1 == nil {
   517  		return false
   518  	}
   519  
   520  	p1 := (*obj.Prog)(r1.Prog)
   521  	if p1.As == p.As {
   522  		// Two consecutive extensions.
   523  		goto gotit
   524  	}
   525  
   526  	if p1.As == arm.AMOVW && isdconst(&p1.From) && p1.From.Offset >= 0 && p1.From.Offset < 128 {
   527  		// Loaded an immediate.
   528  		goto gotit
   529  	}
   530  
   531  	return false
   532  
   533  gotit:
   534  	if gc.Debug['P'] != 0 {
   535  		fmt.Printf("shortprop\n%v\n%v", p1, p)
   536  	}
   537  	switch p.As {
   538  	case arm.AMOVBS,
   539  		arm.AMOVBU:
   540  		p.As = arm.AMOVB
   541  
   542  	case arm.AMOVHS,
   543  		arm.AMOVHU:
   544  		p.As = arm.AMOVH
   545  	}
   546  
   547  	if gc.Debug['P'] != 0 {
   548  		fmt.Printf(" => %v\n", obj.Aconv(int(p.As)))
   549  	}
   550  	return true
   551  }
   552  
   553  // UNUSED
   554  /*
   555   * ASLL x,y,w
   556   * .. (not use w, not set x y w)
   557   * AXXX w,a,b (a != w)
   558   * .. (not use w)
   559   * (set w)
   560   * ----------- changed to
   561   * ..
   562   * AXXX (x<<y),a,b
   563   * ..
   564   */
   565  func shiftprop(r *gc.Flow) bool {
   566  	p := (*obj.Prog)(r.Prog)
   567  	if p.To.Type != obj.TYPE_REG {
   568  		if gc.Debug['P'] != 0 {
   569  			fmt.Printf("\tBOTCH: result not reg; FAILURE\n")
   570  		}
   571  		return false
   572  	}
   573  
   574  	n := int(int(p.To.Reg))
   575  	a := obj.Addr(obj.Addr{})
   576  	if p.Reg != 0 && p.Reg != p.To.Reg {
   577  		a.Type = obj.TYPE_REG
   578  		a.Reg = p.Reg
   579  	}
   580  
   581  	if gc.Debug['P'] != 0 {
   582  		fmt.Printf("shiftprop\n%v", p)
   583  	}
   584  	r1 := (*gc.Flow)(r)
   585  	var p1 *obj.Prog
   586  	for {
   587  		/* find first use of shift result; abort if shift operands or result are changed */
   588  		r1 = gc.Uniqs(r1)
   589  
   590  		if r1 == nil {
   591  			if gc.Debug['P'] != 0 {
   592  				fmt.Printf("\tbranch; FAILURE\n")
   593  			}
   594  			return false
   595  		}
   596  
   597  		if gc.Uniqp(r1) == nil {
   598  			if gc.Debug['P'] != 0 {
   599  				fmt.Printf("\tmerge; FAILURE\n")
   600  			}
   601  			return false
   602  		}
   603  
   604  		p1 = r1.Prog
   605  		if gc.Debug['P'] != 0 {
   606  			fmt.Printf("\n%v", p1)
   607  		}
   608  		switch copyu(p1, &p.To, nil) {
   609  		case 0: /* not used or set */
   610  			if (p.From.Type == obj.TYPE_REG && copyu(p1, &p.From, nil) > 1) || (a.Type == obj.TYPE_REG && copyu(p1, &a, nil) > 1) {
   611  				if gc.Debug['P'] != 0 {
   612  					fmt.Printf("\targs modified; FAILURE\n")
   613  				}
   614  				return false
   615  			}
   616  
   617  			continue
   618  		case 3: /* set, not used */
   619  			{
   620  				if gc.Debug['P'] != 0 {
   621  					fmt.Printf("\tBOTCH: noref; FAILURE\n")
   622  				}
   623  				return false
   624  			}
   625  		}
   626  
   627  		break
   628  	}
   629  
   630  	/* check whether substitution can be done */
   631  	switch p1.As {
   632  	default:
   633  		if gc.Debug['P'] != 0 {
   634  			fmt.Printf("\tnon-dpi; FAILURE\n")
   635  		}
   636  		return false
   637  
   638  	case arm.AAND,
   639  		arm.AEOR,
   640  		arm.AADD,
   641  		arm.AADC,
   642  		arm.AORR,
   643  		arm.ASUB,
   644  		arm.ASBC,
   645  		arm.ARSB,
   646  		arm.ARSC:
   647  		if int(p1.Reg) == n || (p1.Reg == 0 && p1.To.Type == obj.TYPE_REG && int(p1.To.Reg) == n) {
   648  			if p1.From.Type != obj.TYPE_REG {
   649  				if gc.Debug['P'] != 0 {
   650  					fmt.Printf("\tcan't swap; FAILURE\n")
   651  				}
   652  				return false
   653  			}
   654  
   655  			p1.Reg = p1.From.Reg
   656  			p1.From.Reg = int16(n)
   657  			switch p1.As {
   658  			case arm.ASUB:
   659  				p1.As = arm.ARSB
   660  
   661  			case arm.ARSB:
   662  				p1.As = arm.ASUB
   663  
   664  			case arm.ASBC:
   665  				p1.As = arm.ARSC
   666  
   667  			case arm.ARSC:
   668  				p1.As = arm.ASBC
   669  			}
   670  
   671  			if gc.Debug['P'] != 0 {
   672  				fmt.Printf("\t=>%v", p1)
   673  			}
   674  		}
   675  		fallthrough
   676  
   677  	case arm.ABIC,
   678  		arm.ATST,
   679  		arm.ACMP,
   680  		arm.ACMN:
   681  		if int(p1.Reg) == n {
   682  			if gc.Debug['P'] != 0 {
   683  				fmt.Printf("\tcan't swap; FAILURE\n")
   684  			}
   685  			return false
   686  		}
   687  
   688  		if p1.Reg == 0 && int(p1.To.Reg) == n {
   689  			if gc.Debug['P'] != 0 {
   690  				fmt.Printf("\tshift result used twice; FAILURE\n")
   691  			}
   692  			return false
   693  		}
   694  
   695  		//	case AMVN:
   696  		if p1.From.Type == obj.TYPE_SHIFT {
   697  			if gc.Debug['P'] != 0 {
   698  				fmt.Printf("\tshift result used in shift; FAILURE\n")
   699  			}
   700  			return false
   701  		}
   702  
   703  		if p1.From.Type != obj.TYPE_REG || int(p1.From.Reg) != n {
   704  			if gc.Debug['P'] != 0 {
   705  				fmt.Printf("\tBOTCH: where is it used?; FAILURE\n")
   706  			}
   707  			return false
   708  		}
   709  	}
   710  
   711  	/* check whether shift result is used subsequently */
   712  	p2 := (*obj.Prog)(p1)
   713  
   714  	if int(p1.To.Reg) != n {
   715  		var p1 *obj.Prog
   716  		for {
   717  			r1 = gc.Uniqs(r1)
   718  			if r1 == nil {
   719  				if gc.Debug['P'] != 0 {
   720  					fmt.Printf("\tinconclusive; FAILURE\n")
   721  				}
   722  				return false
   723  			}
   724  
   725  			p1 = r1.Prog
   726  			if gc.Debug['P'] != 0 {
   727  				fmt.Printf("\n%v", p1)
   728  			}
   729  			switch copyu(p1, &p.To, nil) {
   730  			case 0: /* not used or set */
   731  				continue
   732  
   733  			case 3: /* set, not used */
   734  				break
   735  
   736  			default: /* used */
   737  				if gc.Debug['P'] != 0 {
   738  					fmt.Printf("\treused; FAILURE\n")
   739  				}
   740  				return false
   741  			}
   742  
   743  			break
   744  		}
   745  	}
   746  
   747  	/* make the substitution */
   748  	p2.From.Reg = 0
   749  
   750  	o := int(int(p.Reg))
   751  	if o == 0 {
   752  		o = int(p.To.Reg)
   753  	}
   754  	o &= 15
   755  
   756  	switch p.From.Type {
   757  	case obj.TYPE_CONST:
   758  		o |= int((p.From.Offset & 0x1f) << 7)
   759  
   760  	case obj.TYPE_REG:
   761  		o |= 1<<4 | (int(p.From.Reg)&15)<<8
   762  	}
   763  
   764  	switch p.As {
   765  	case arm.ASLL:
   766  		o |= 0 << 5
   767  
   768  	case arm.ASRL:
   769  		o |= 1 << 5
   770  
   771  	case arm.ASRA:
   772  		o |= 2 << 5
   773  	}
   774  
   775  	p2.From = obj.Addr{}
   776  	p2.From.Type = obj.TYPE_SHIFT
   777  	p2.From.Offset = int64(o)
   778  	if gc.Debug['P'] != 0 {
   779  		fmt.Printf("\t=>%v\tSUCCEED\n", p2)
   780  	}
   781  	return true
   782  }
   783  
   784  /*
   785   * findpre returns the last instruction mentioning v
   786   * before r. It must be a set, and there must be
   787   * a unique path from that instruction to r.
   788   */
   789  func findpre(r *gc.Flow, v *obj.Addr) *gc.Flow {
   790  	var r1 *gc.Flow
   791  
   792  	for r1 = gc.Uniqp(r); r1 != nil; r, r1 = r1, gc.Uniqp(r1) {
   793  		if gc.Uniqs(r1) != r {
   794  			return nil
   795  		}
   796  		switch copyu(r1.Prog, v, nil) {
   797  		case 1, /* used */
   798  			2: /* read-alter-rewrite */
   799  			return nil
   800  
   801  		case 3, /* set */
   802  			4: /* set and used */
   803  			return r1
   804  		}
   805  	}
   806  
   807  	return nil
   808  }
   809  
   810  /*
   811   * findinc finds ADD instructions with a constant
   812   * argument which falls within the immed_12 range.
   813   */
   814  func findinc(r *gc.Flow, r2 *gc.Flow, v *obj.Addr) *gc.Flow {
   815  	var r1 *gc.Flow
   816  	var p *obj.Prog
   817  
   818  	for r1 = gc.Uniqs(r); r1 != nil && r1 != r2; r, r1 = r1, gc.Uniqs(r1) {
   819  		if gc.Uniqp(r1) != r {
   820  			return nil
   821  		}
   822  		switch copyu(r1.Prog, v, nil) {
   823  		case 0: /* not touched */
   824  			continue
   825  
   826  		case 4: /* set and used */
   827  			p = r1.Prog
   828  
   829  			if p.As == arm.AADD {
   830  				if isdconst(&p.From) {
   831  					if p.From.Offset > -4096 && p.From.Offset < 4096 {
   832  						return r1
   833  					}
   834  				}
   835  			}
   836  			fallthrough
   837  
   838  		default:
   839  			return nil
   840  		}
   841  	}
   842  
   843  	return nil
   844  }
   845  
   846  func nochange(r *gc.Flow, r2 *gc.Flow, p *obj.Prog) bool {
   847  	if r == r2 {
   848  		return true
   849  	}
   850  	n := int(0)
   851  	var a [3]obj.Addr
   852  	if p.Reg != 0 && p.Reg != p.To.Reg {
   853  		a[n].Type = obj.TYPE_REG
   854  		a[n].Reg = p.Reg
   855  		n++
   856  	}
   857  
   858  	switch p.From.Type {
   859  	case obj.TYPE_SHIFT:
   860  		a[n].Type = obj.TYPE_REG
   861  		a[n].Reg = int16(arm.REG_R0 + (p.From.Offset & 0xf))
   862  		n++
   863  		fallthrough
   864  
   865  	case obj.TYPE_REG:
   866  		a[n].Type = obj.TYPE_REG
   867  		a[n].Reg = p.From.Reg
   868  		n++
   869  	}
   870  
   871  	if n == 0 {
   872  		return true
   873  	}
   874  	var i int
   875  	for ; r != nil && r != r2; r = gc.Uniqs(r) {
   876  		p = r.Prog
   877  		for i = 0; i < n; i++ {
   878  			if copyu(p, &a[i], nil) > 1 {
   879  				return false
   880  			}
   881  		}
   882  	}
   883  
   884  	return true
   885  }
   886  
   887  func findu1(r *gc.Flow, v *obj.Addr) bool {
   888  	for ; r != nil; r = r.S1 {
   889  		if r.Active != 0 {
   890  			return false
   891  		}
   892  		r.Active = 1
   893  		switch copyu(r.Prog, v, nil) {
   894  		case 1, /* used */
   895  			2, /* read-alter-rewrite */
   896  			4: /* set and used */
   897  			return true
   898  
   899  		case 3: /* set */
   900  			return false
   901  		}
   902  
   903  		if r.S2 != nil {
   904  			if findu1(r.S2, v) {
   905  				return true
   906  			}
   907  		}
   908  	}
   909  
   910  	return false
   911  }
   912  
   913  func finduse(g *gc.Graph, r *gc.Flow, v *obj.Addr) bool {
   914  	for r1 := (*gc.Flow)(g.Start); r1 != nil; r1 = r1.Link {
   915  		r1.Active = 0
   916  	}
   917  	return findu1(r, v)
   918  }
   919  
   920  /*
   921   * xtramodes enables the ARM post increment and
   922   * shift offset addressing modes to transform
   923   *   MOVW   0(R3),R1
   924   *   ADD    $4,R3,R3
   925   * into
   926   *   MOVW.P 4(R3),R1
   927   * and
   928   *   ADD    R0,R1
   929   *   MOVBU  0(R1),R0
   930   * into
   931   *   MOVBU  R0<<0(R1),R0
   932   */
   933  func xtramodes(g *gc.Graph, r *gc.Flow, a *obj.Addr) bool {
   934  	p := (*obj.Prog)(r.Prog)
   935  	v := obj.Addr(*a)
   936  	v.Type = obj.TYPE_REG
   937  	r1 := (*gc.Flow)(findpre(r, &v))
   938  	if r1 != nil {
   939  		p1 := r1.Prog
   940  		if p1.To.Type == obj.TYPE_REG && p1.To.Reg == v.Reg {
   941  			switch p1.As {
   942  			case arm.AADD:
   943  				if p1.Scond&arm.C_SBIT != 0 {
   944  					// avoid altering ADD.S/ADC sequences.
   945  					break
   946  				}
   947  
   948  				if p1.From.Type == obj.TYPE_REG || (p1.From.Type == obj.TYPE_SHIFT && p1.From.Offset&(1<<4) == 0 && ((p.As != arm.AMOVB && p.As != arm.AMOVBS) || (a == &p.From && p1.From.Offset&^0xf == 0))) || ((p1.From.Type == obj.TYPE_ADDR || p1.From.Type == obj.TYPE_CONST) && p1.From.Offset > -4096 && p1.From.Offset < 4096) {
   949  					if nochange(gc.Uniqs(r1), r, p1) {
   950  						if a != &p.From || v.Reg != p.To.Reg {
   951  							if finduse(g, r.S1, &v) {
   952  								if p1.Reg == 0 || p1.Reg == v.Reg {
   953  									/* pre-indexing */
   954  									p.Scond |= arm.C_WBIT
   955  								} else {
   956  									return false
   957  								}
   958  							}
   959  						}
   960  
   961  						switch p1.From.Type {
   962  						/* register offset */
   963  						case obj.TYPE_REG:
   964  							if gc.Nacl {
   965  								return false
   966  							}
   967  							*a = obj.Addr{}
   968  							a.Type = obj.TYPE_SHIFT
   969  							a.Offset = int64(p1.From.Reg) & 15
   970  
   971  							/* scaled register offset */
   972  						case obj.TYPE_SHIFT:
   973  							if gc.Nacl {
   974  								return false
   975  							}
   976  							*a = obj.Addr{}
   977  							a.Type = obj.TYPE_SHIFT
   978  							fallthrough
   979  
   980  							/* immediate offset */
   981  						case obj.TYPE_CONST,
   982  							obj.TYPE_ADDR:
   983  							a.Offset = p1.From.Offset
   984  						}
   985  
   986  						if p1.Reg != 0 {
   987  							a.Reg = p1.Reg
   988  						}
   989  						excise(r1)
   990  						return true
   991  					}
   992  				}
   993  
   994  			case arm.AMOVW:
   995  				if p1.From.Type == obj.TYPE_REG {
   996  					r2 := (*gc.Flow)(findinc(r1, r, &p1.From))
   997  					if r2 != nil {
   998  						var r3 *gc.Flow
   999  						for r3 = gc.Uniqs(r2); r3.Prog.As == obj.ANOP; r3 = gc.Uniqs(r3) {
  1000  						}
  1001  						if r3 == r {
  1002  							/* post-indexing */
  1003  							p1 := r2.Prog
  1004  
  1005  							a.Reg = p1.To.Reg
  1006  							a.Offset = p1.From.Offset
  1007  							p.Scond |= arm.C_PBIT
  1008  							if !finduse(g, r, &r1.Prog.To) {
  1009  								excise(r1)
  1010  							}
  1011  							excise(r2)
  1012  							return true
  1013  						}
  1014  					}
  1015  				}
  1016  			}
  1017  		}
  1018  	}
  1019  
  1020  	if a != &p.From || a.Reg != p.To.Reg {
  1021  		r1 := (*gc.Flow)(findinc(r, nil, &v))
  1022  		if r1 != nil {
  1023  			/* post-indexing */
  1024  			p1 := r1.Prog
  1025  
  1026  			a.Offset = p1.From.Offset
  1027  			p.Scond |= arm.C_PBIT
  1028  			excise(r1)
  1029  			return true
  1030  		}
  1031  	}
  1032  
  1033  	return false
  1034  }
  1035  
  1036  /*
  1037   * return
  1038   * 1 if v only used (and substitute),
  1039   * 2 if read-alter-rewrite
  1040   * 3 if set
  1041   * 4 if set and used
  1042   * 0 otherwise (not touched)
  1043   */
  1044  func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
  1045  	switch p.As {
  1046  	default:
  1047  		fmt.Printf("copyu: can't find %v\n", obj.Aconv(int(p.As)))
  1048  		return 2
  1049  
  1050  	case arm.AMOVM:
  1051  		if v.Type != obj.TYPE_REG {
  1052  			return 0
  1053  		}
  1054  		if p.From.Type == obj.TYPE_CONST { /* read reglist, read/rar */
  1055  			if s != nil {
  1056  				if p.From.Offset&(1<<uint(v.Reg)) != 0 {
  1057  					return 1
  1058  				}
  1059  				if copysub(&p.To, v, s, 1) != 0 {
  1060  					return 1
  1061  				}
  1062  				return 0
  1063  			}
  1064  
  1065  			if copyau(&p.To, v) {
  1066  				if p.Scond&arm.C_WBIT != 0 {
  1067  					return 2
  1068  				}
  1069  				return 1
  1070  			}
  1071  
  1072  			if p.From.Offset&(1<<uint(v.Reg)) != 0 {
  1073  				return 1 /* read/rar, write reglist */
  1074  			}
  1075  		} else {
  1076  			if s != nil {
  1077  				if p.To.Offset&(1<<uint(v.Reg)) != 0 {
  1078  					return 1
  1079  				}
  1080  				if copysub(&p.From, v, s, 1) != 0 {
  1081  					return 1
  1082  				}
  1083  				return 0
  1084  			}
  1085  
  1086  			if copyau(&p.From, v) {
  1087  				if p.Scond&arm.C_WBIT != 0 {
  1088  					return 2
  1089  				}
  1090  				if p.To.Offset&(1<<uint(v.Reg)) != 0 {
  1091  					return 4
  1092  				}
  1093  				return 1
  1094  			}
  1095  
  1096  			if p.To.Offset&(1<<uint(v.Reg)) != 0 {
  1097  				return 3
  1098  			}
  1099  		}
  1100  
  1101  		return 0
  1102  
  1103  	case obj.ANOP, /* read,, write */
  1104  		arm.ASQRTD,
  1105  		arm.AMOVW,
  1106  		arm.AMOVF,
  1107  		arm.AMOVD,
  1108  		arm.AMOVH,
  1109  		arm.AMOVHS,
  1110  		arm.AMOVHU,
  1111  		arm.AMOVB,
  1112  		arm.AMOVBS,
  1113  		arm.AMOVBU,
  1114  		arm.AMOVFW,
  1115  		arm.AMOVWF,
  1116  		arm.AMOVDW,
  1117  		arm.AMOVWD,
  1118  		arm.AMOVFD,
  1119  		arm.AMOVDF:
  1120  		if p.Scond&(arm.C_WBIT|arm.C_PBIT) != 0 {
  1121  			if v.Type == obj.TYPE_REG {
  1122  				if p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_SHIFT {
  1123  					if p.From.Reg == v.Reg {
  1124  						return 2
  1125  					}
  1126  				} else {
  1127  					if p.To.Reg == v.Reg {
  1128  						return 2
  1129  					}
  1130  				}
  1131  			}
  1132  		}
  1133  
  1134  		if s != nil {
  1135  			if copysub(&p.From, v, s, 1) != 0 {
  1136  				return 1
  1137  			}
  1138  			if !copyas(&p.To, v) {
  1139  				if copysub(&p.To, v, s, 1) != 0 {
  1140  					return 1
  1141  				}
  1142  			}
  1143  			return 0
  1144  		}
  1145  
  1146  		if copyas(&p.To, v) {
  1147  			if p.Scond != arm.C_SCOND_NONE {
  1148  				return 2
  1149  			}
  1150  			if copyau(&p.From, v) {
  1151  				return 4
  1152  			}
  1153  			return 3
  1154  		}
  1155  
  1156  		if copyau(&p.From, v) {
  1157  			return 1
  1158  		}
  1159  		if copyau(&p.To, v) {
  1160  			return 1
  1161  		}
  1162  		return 0
  1163  
  1164  	case arm.AMULLU, /* read, read, write, write */
  1165  		arm.AMULL,
  1166  		arm.AMULA,
  1167  		arm.AMVN:
  1168  		return 2
  1169  
  1170  	case arm.AADD, /* read, read, write */
  1171  		arm.AADC,
  1172  		arm.ASUB,
  1173  		arm.ASBC,
  1174  		arm.ARSB,
  1175  		arm.ASLL,
  1176  		arm.ASRL,
  1177  		arm.ASRA,
  1178  		arm.AORR,
  1179  		arm.AAND,
  1180  		arm.AEOR,
  1181  		arm.AMUL,
  1182  		arm.AMULU,
  1183  		arm.ADIV,
  1184  		arm.ADIVU,
  1185  		arm.AMOD,
  1186  		arm.AMODU,
  1187  		arm.AADDF,
  1188  		arm.AADDD,
  1189  		arm.ASUBF,
  1190  		arm.ASUBD,
  1191  		arm.AMULF,
  1192  		arm.AMULD,
  1193  		arm.ADIVF,
  1194  		arm.ADIVD,
  1195  		obj.ACHECKNIL,
  1196  		/* read */
  1197  		arm.ACMPF, /* read, read, */
  1198  		arm.ACMPD,
  1199  		arm.ACMP,
  1200  		arm.ACMN,
  1201  		arm.ATST:
  1202  		/* read,, */
  1203  		if s != nil {
  1204  			if copysub(&p.From, v, s, 1) != 0 {
  1205  				return 1
  1206  			}
  1207  			if copysub1(p, v, s, 1) != 0 {
  1208  				return 1
  1209  			}
  1210  			if !copyas(&p.To, v) {
  1211  				if copysub(&p.To, v, s, 1) != 0 {
  1212  					return 1
  1213  				}
  1214  			}
  1215  			return 0
  1216  		}
  1217  
  1218  		if copyas(&p.To, v) {
  1219  			if p.Scond != arm.C_SCOND_NONE {
  1220  				return 2
  1221  			}
  1222  			if p.Reg == 0 {
  1223  				p.Reg = p.To.Reg
  1224  			}
  1225  			if copyau(&p.From, v) {
  1226  				return 4
  1227  			}
  1228  			if copyau1(p, v) {
  1229  				return 4
  1230  			}
  1231  			return 3
  1232  		}
  1233  
  1234  		if copyau(&p.From, v) {
  1235  			return 1
  1236  		}
  1237  		if copyau1(p, v) {
  1238  			return 1
  1239  		}
  1240  		if copyau(&p.To, v) {
  1241  			return 1
  1242  		}
  1243  		return 0
  1244  
  1245  	case arm.ABEQ, /* read, read */
  1246  		arm.ABNE,
  1247  		arm.ABCS,
  1248  		arm.ABHS,
  1249  		arm.ABCC,
  1250  		arm.ABLO,
  1251  		arm.ABMI,
  1252  		arm.ABPL,
  1253  		arm.ABVS,
  1254  		arm.ABVC,
  1255  		arm.ABHI,
  1256  		arm.ABLS,
  1257  		arm.ABGE,
  1258  		arm.ABLT,
  1259  		arm.ABGT,
  1260  		arm.ABLE:
  1261  		if s != nil {
  1262  			if copysub(&p.From, v, s, 1) != 0 {
  1263  				return 1
  1264  			}
  1265  			return copysub1(p, v, s, 1)
  1266  		}
  1267  
  1268  		if copyau(&p.From, v) {
  1269  			return 1
  1270  		}
  1271  		if copyau1(p, v) {
  1272  			return 1
  1273  		}
  1274  		return 0
  1275  
  1276  	case arm.AB: /* funny */
  1277  		if s != nil {
  1278  			if copysub(&p.To, v, s, 1) != 0 {
  1279  				return 1
  1280  			}
  1281  			return 0
  1282  		}
  1283  
  1284  		if copyau(&p.To, v) {
  1285  			return 1
  1286  		}
  1287  		return 0
  1288  
  1289  	case obj.ARET: /* funny */
  1290  		if s != nil {
  1291  			return 1
  1292  		}
  1293  		return 3
  1294  
  1295  	case arm.ABL: /* funny */
  1296  		if v.Type == obj.TYPE_REG {
  1297  			// TODO(rsc): REG_R0 and REG_F0 used to be
  1298  			// (when register numbers started at 0) exregoffset and exfregoffset,
  1299  			// which are unset entirely.
  1300  			// It's strange that this handles R0 and F0 differently from the other
  1301  			// registers. Possible failure to optimize?
  1302  			if arm.REG_R0 < v.Reg && v.Reg <= arm.REGEXT {
  1303  				return 2
  1304  			}
  1305  			if v.Reg == arm.REGARG {
  1306  				return 2
  1307  			}
  1308  			if arm.REG_F0 < v.Reg && v.Reg <= arm.FREGEXT {
  1309  				return 2
  1310  			}
  1311  		}
  1312  
  1313  		if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
  1314  			return 2
  1315  		}
  1316  
  1317  		if s != nil {
  1318  			if copysub(&p.To, v, s, 1) != 0 {
  1319  				return 1
  1320  			}
  1321  			return 0
  1322  		}
  1323  
  1324  		if copyau(&p.To, v) {
  1325  			return 4
  1326  		}
  1327  		return 3
  1328  
  1329  		// R0 is zero, used by DUFFZERO, cannot be substituted.
  1330  	// R1 is ptr to memory, used and set, cannot be substituted.
  1331  	case obj.ADUFFZERO:
  1332  		if v.Type == obj.TYPE_REG {
  1333  			if v.Reg == arm.REG_R0 {
  1334  				return 1
  1335  			}
  1336  			if v.Reg == arm.REG_R0+1 {
  1337  				return 2
  1338  			}
  1339  		}
  1340  
  1341  		return 0
  1342  
  1343  		// R0 is scratch, set by DUFFCOPY, cannot be substituted.
  1344  	// R1, R2 areptr to src, dst, used and set, cannot be substituted.
  1345  	case obj.ADUFFCOPY:
  1346  		if v.Type == obj.TYPE_REG {
  1347  			if v.Reg == arm.REG_R0 {
  1348  				return 3
  1349  			}
  1350  			if v.Reg == arm.REG_R0+1 || v.Reg == arm.REG_R0+2 {
  1351  				return 2
  1352  			}
  1353  		}
  1354  
  1355  		return 0
  1356  
  1357  	case obj.ATEXT: /* funny */
  1358  		if v.Type == obj.TYPE_REG {
  1359  			if v.Reg == arm.REGARG {
  1360  				return 3
  1361  			}
  1362  		}
  1363  		return 0
  1364  
  1365  	case obj.APCDATA,
  1366  		obj.AFUNCDATA,
  1367  		obj.AVARDEF,
  1368  		obj.AVARKILL,
  1369  		obj.AVARLIVE,
  1370  		obj.AUSEFIELD:
  1371  		return 0
  1372  	}
  1373  }
  1374  
  1375  /*
  1376   * direct reference,
  1377   * could be set/use depending on
  1378   * semantics
  1379   */
  1380  func copyas(a *obj.Addr, v *obj.Addr) bool {
  1381  	if regtyp(v) {
  1382  		if a.Type == v.Type {
  1383  			if a.Reg == v.Reg {
  1384  				return true
  1385  			}
  1386  		}
  1387  	} else if v.Type == obj.TYPE_CONST { /* for constprop */
  1388  		if a.Type == v.Type {
  1389  			if a.Name == v.Name {
  1390  				if a.Sym == v.Sym {
  1391  					if a.Reg == v.Reg {
  1392  						if a.Offset == v.Offset {
  1393  							return true
  1394  						}
  1395  					}
  1396  				}
  1397  			}
  1398  		}
  1399  	}
  1400  
  1401  	return false
  1402  }
  1403  
  1404  func sameaddr(a *obj.Addr, v *obj.Addr) bool {
  1405  	if a.Type != v.Type {
  1406  		return false
  1407  	}
  1408  	if regtyp(v) && a.Reg == v.Reg {
  1409  		return true
  1410  	}
  1411  
  1412  	// TODO(rsc): Change v->type to v->name and enable.
  1413  	//if(v->type == NAME_AUTO || v->type == NAME_PARAM) {
  1414  	//	if(v->offset == a->offset)
  1415  	//		return 1;
  1416  	//}
  1417  	return false
  1418  }
  1419  
  1420  /*
  1421   * either direct or indirect
  1422   */
  1423  func copyau(a *obj.Addr, v *obj.Addr) bool {
  1424  	if copyas(a, v) {
  1425  		return true
  1426  	}
  1427  	if v.Type == obj.TYPE_REG {
  1428  		if a.Type == obj.TYPE_ADDR && a.Reg != 0 {
  1429  			if a.Reg == v.Reg {
  1430  				return true
  1431  			}
  1432  		} else if a.Type == obj.TYPE_MEM {
  1433  			if a.Reg == v.Reg {
  1434  				return true
  1435  			}
  1436  		} else if a.Type == obj.TYPE_REGREG || a.Type == obj.TYPE_REGREG2 {
  1437  			if a.Reg == v.Reg {
  1438  				return true
  1439  			}
  1440  			if a.Offset == int64(v.Reg) {
  1441  				return true
  1442  			}
  1443  		} else if a.Type == obj.TYPE_SHIFT {
  1444  			if a.Offset&0xf == int64(v.Reg-arm.REG_R0) {
  1445  				return true
  1446  			}
  1447  			if (a.Offset&(1<<4) != 0) && (a.Offset>>8)&0xf == int64(v.Reg-arm.REG_R0) {
  1448  				return true
  1449  			}
  1450  		}
  1451  	}
  1452  
  1453  	return false
  1454  }
  1455  
  1456  /*
  1457   * compare v to the center
  1458   * register in p (p->reg)
  1459   */
  1460  func copyau1(p *obj.Prog, v *obj.Addr) bool {
  1461  	if v.Type == obj.TYPE_REG && v.Reg == 0 {
  1462  		return false
  1463  	}
  1464  	return p.Reg == v.Reg
  1465  }
  1466  
  1467  /*
  1468   * substitute s for v in a
  1469   * return failure to substitute
  1470   */
  1471  func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int {
  1472  	if f != 0 {
  1473  		if copyau(a, v) {
  1474  			if a.Type == obj.TYPE_SHIFT {
  1475  				if a.Offset&0xf == int64(v.Reg-arm.REG_R0) {
  1476  					a.Offset = a.Offset&^0xf | int64(s.Reg)&0xf
  1477  				}
  1478  				if (a.Offset&(1<<4) != 0) && (a.Offset>>8)&0xf == int64(v.Reg-arm.REG_R0) {
  1479  					a.Offset = a.Offset&^(0xf<<8) | (int64(s.Reg)&0xf)<<8
  1480  				}
  1481  			} else if a.Type == obj.TYPE_REGREG || a.Type == obj.TYPE_REGREG2 {
  1482  				if a.Offset == int64(v.Reg) {
  1483  					a.Offset = int64(s.Reg)
  1484  				}
  1485  				if a.Reg == v.Reg {
  1486  					a.Reg = s.Reg
  1487  				}
  1488  			} else {
  1489  				a.Reg = s.Reg
  1490  			}
  1491  		}
  1492  	}
  1493  
  1494  	return 0
  1495  }
  1496  
  1497  func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f int) int {
  1498  	if f != 0 {
  1499  		if copyau1(p1, v) {
  1500  			p1.Reg = s.Reg
  1501  		}
  1502  	}
  1503  	return 0
  1504  }
  1505  
  1506  var predinfo = []struct {
  1507  	opcode    int
  1508  	notopcode int
  1509  	scond     int
  1510  	notscond  int
  1511  }{
  1512  	{arm.ABEQ, arm.ABNE, 0x0, 0x1},
  1513  	{arm.ABNE, arm.ABEQ, 0x1, 0x0},
  1514  	{arm.ABCS, arm.ABCC, 0x2, 0x3},
  1515  	{arm.ABHS, arm.ABLO, 0x2, 0x3},
  1516  	{arm.ABCC, arm.ABCS, 0x3, 0x2},
  1517  	{arm.ABLO, arm.ABHS, 0x3, 0x2},
  1518  	{arm.ABMI, arm.ABPL, 0x4, 0x5},
  1519  	{arm.ABPL, arm.ABMI, 0x5, 0x4},
  1520  	{arm.ABVS, arm.ABVC, 0x6, 0x7},
  1521  	{arm.ABVC, arm.ABVS, 0x7, 0x6},
  1522  	{arm.ABHI, arm.ABLS, 0x8, 0x9},
  1523  	{arm.ABLS, arm.ABHI, 0x9, 0x8},
  1524  	{arm.ABGE, arm.ABLT, 0xA, 0xB},
  1525  	{arm.ABLT, arm.ABGE, 0xB, 0xA},
  1526  	{arm.ABGT, arm.ABLE, 0xC, 0xD},
  1527  	{arm.ABLE, arm.ABGT, 0xD, 0xC},
  1528  }
  1529  
  1530  type Joininfo struct {
  1531  	start *gc.Flow
  1532  	last  *gc.Flow
  1533  	end   *gc.Flow
  1534  	len   int
  1535  }
  1536  
  1537  const (
  1538  	Join = iota
  1539  	Split
  1540  	End
  1541  	Branch
  1542  	Setcond
  1543  	Toolong
  1544  )
  1545  
  1546  const (
  1547  	Falsecond = iota
  1548  	Truecond
  1549  	Delbranch
  1550  	Keepbranch
  1551  )
  1552  
  1553  func isbranch(p *obj.Prog) bool {
  1554  	return (arm.ABEQ <= p.As) && (p.As <= arm.ABLE)
  1555  }
  1556  
  1557  func predicable(p *obj.Prog) bool {
  1558  	switch p.As {
  1559  	case obj.ANOP,
  1560  		obj.AXXX,
  1561  		obj.ADATA,
  1562  		obj.AGLOBL,
  1563  		obj.ATEXT,
  1564  		arm.AWORD:
  1565  		return false
  1566  	}
  1567  
  1568  	if isbranch(p) {
  1569  		return false
  1570  	}
  1571  	return true
  1572  }
  1573  
  1574  /*
  1575   * Depends on an analysis of the encodings performed by 5l.
  1576   * These seem to be all of the opcodes that lead to the "S" bit
  1577   * being set in the instruction encodings.
  1578   *
  1579   * C_SBIT may also have been set explicitly in p->scond.
  1580   */
  1581  func modifiescpsr(p *obj.Prog) bool {
  1582  	switch p.As {
  1583  	case arm.AMULLU,
  1584  		arm.AMULA,
  1585  		arm.AMULU,
  1586  		arm.ADIVU,
  1587  		arm.ATEQ,
  1588  		arm.ACMN,
  1589  		arm.ATST,
  1590  		arm.ACMP,
  1591  		arm.AMUL,
  1592  		arm.ADIV,
  1593  		arm.AMOD,
  1594  		arm.AMODU,
  1595  		arm.ABL:
  1596  		return true
  1597  	}
  1598  
  1599  	if p.Scond&arm.C_SBIT != 0 {
  1600  		return true
  1601  	}
  1602  	return false
  1603  }
  1604  
  1605  /*
  1606   * Find the maximal chain of instructions starting with r which could
  1607   * be executed conditionally
  1608   */
  1609  func joinsplit(r *gc.Flow, j *Joininfo) int {
  1610  	j.start = r
  1611  	j.last = r
  1612  	j.len = 0
  1613  	for {
  1614  		if r.P2 != nil && (r.P1 != nil || r.P2.P2link != nil) {
  1615  			j.end = r
  1616  			return Join
  1617  		}
  1618  
  1619  		if r.S1 != nil && r.S2 != nil {
  1620  			j.end = r
  1621  			return Split
  1622  		}
  1623  
  1624  		j.last = r
  1625  		if r.Prog.As != obj.ANOP {
  1626  			j.len++
  1627  		}
  1628  		if r.S1 == nil && r.S2 == nil {
  1629  			j.end = r.Link
  1630  			return End
  1631  		}
  1632  
  1633  		if r.S2 != nil {
  1634  			j.end = r.S2
  1635  			return Branch
  1636  		}
  1637  
  1638  		if modifiescpsr(r.Prog) {
  1639  			j.end = r.S1
  1640  			return Setcond
  1641  		}
  1642  
  1643  		r = r.S1
  1644  		if j.len >= 4 {
  1645  			break
  1646  		}
  1647  	}
  1648  
  1649  	j.end = r
  1650  	return Toolong
  1651  }
  1652  
  1653  func successor(r *gc.Flow) *gc.Flow {
  1654  	if r.S1 != nil {
  1655  		return r.S1
  1656  	} else {
  1657  		return r.S2
  1658  	}
  1659  }
  1660  
  1661  func applypred(rstart *gc.Flow, j *Joininfo, cond int, branch int) {
  1662  	if j.len == 0 {
  1663  		return
  1664  	}
  1665  	var pred int
  1666  	if cond == Truecond {
  1667  		pred = predinfo[rstart.Prog.As-arm.ABEQ].scond
  1668  	} else {
  1669  		pred = predinfo[rstart.Prog.As-arm.ABEQ].notscond
  1670  	}
  1671  
  1672  	for r := (*gc.Flow)(j.start); ; r = successor(r) {
  1673  		if r.Prog.As == arm.AB {
  1674  			if r != j.last || branch == Delbranch {
  1675  				excise(r)
  1676  			} else {
  1677  				if cond == Truecond {
  1678  					r.Prog.As = int16(predinfo[rstart.Prog.As-arm.ABEQ].opcode)
  1679  				} else {
  1680  					r.Prog.As = int16(predinfo[rstart.Prog.As-arm.ABEQ].notopcode)
  1681  				}
  1682  			}
  1683  		} else if predicable(r.Prog) {
  1684  			r.Prog.Scond = uint8(int(r.Prog.Scond&^arm.C_SCOND) | pred)
  1685  		}
  1686  		if r.S1 != r.Link {
  1687  			r.S1 = r.Link
  1688  			r.Link.P1 = r
  1689  		}
  1690  
  1691  		if r == j.last {
  1692  			break
  1693  		}
  1694  	}
  1695  }
  1696  
  1697  func predicate(g *gc.Graph) {
  1698  	var t1 int
  1699  	var t2 int
  1700  	var j1 Joininfo
  1701  	var j2 Joininfo
  1702  
  1703  	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
  1704  		if isbranch(r.Prog) {
  1705  			t1 = joinsplit(r.S1, &j1)
  1706  			t2 = joinsplit(r.S2, &j2)
  1707  			if j1.last.Link != j2.start {
  1708  				continue
  1709  			}
  1710  			if j1.end == j2.end {
  1711  				if (t1 == Branch && (t2 == Join || t2 == Setcond)) || (t2 == Join && (t1 == Join || t1 == Setcond)) {
  1712  					applypred(r, &j1, Falsecond, Delbranch)
  1713  					applypred(r, &j2, Truecond, Delbranch)
  1714  					excise(r)
  1715  					continue
  1716  				}
  1717  			}
  1718  
  1719  			if t1 == End || t1 == Branch {
  1720  				applypred(r, &j1, Falsecond, Keepbranch)
  1721  				excise(r)
  1722  				continue
  1723  			}
  1724  		}
  1725  	}
  1726  }
  1727  
  1728  func isdconst(a *obj.Addr) bool {
  1729  	return a.Type == obj.TYPE_CONST
  1730  }
  1731  
  1732  func isfloatreg(a *obj.Addr) bool {
  1733  	return arm.REG_F0 <= a.Reg && a.Reg <= arm.REG_F15
  1734  }
  1735  
  1736  func stackaddr(a *obj.Addr) bool {
  1737  	return regtyp(a) && a.Reg == arm.REGSP
  1738  }
  1739  
  1740  func smallindir(a *obj.Addr, reg *obj.Addr) bool {
  1741  	return reg.Type == obj.TYPE_REG && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && 0 <= a.Offset && a.Offset < 4096
  1742  }
  1743  
  1744  func excise(r *gc.Flow) {
  1745  	p := (*obj.Prog)(r.Prog)
  1746  	obj.Nopout(p)
  1747  }