github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/compile/internal/arm/peep.go (about)

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