github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/5g/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 main
    32  
    33  import (
    34  	"cmd/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.ACASE,
  1202  		arm.ATST:
  1203  		/* read,, */
  1204  		if s != nil {
  1205  			if copysub(&p.From, v, s, 1) != 0 {
  1206  				return 1
  1207  			}
  1208  			if copysub1(p, v, s, 1) != 0 {
  1209  				return 1
  1210  			}
  1211  			if !copyas(&p.To, v) {
  1212  				if copysub(&p.To, v, s, 1) != 0 {
  1213  					return 1
  1214  				}
  1215  			}
  1216  			return 0
  1217  		}
  1218  
  1219  		if copyas(&p.To, v) {
  1220  			if p.Scond != arm.C_SCOND_NONE {
  1221  				return 2
  1222  			}
  1223  			if p.Reg == 0 {
  1224  				p.Reg = p.To.Reg
  1225  			}
  1226  			if copyau(&p.From, v) {
  1227  				return 4
  1228  			}
  1229  			if copyau1(p, v) {
  1230  				return 4
  1231  			}
  1232  			return 3
  1233  		}
  1234  
  1235  		if copyau(&p.From, v) {
  1236  			return 1
  1237  		}
  1238  		if copyau1(p, v) {
  1239  			return 1
  1240  		}
  1241  		if copyau(&p.To, v) {
  1242  			return 1
  1243  		}
  1244  		return 0
  1245  
  1246  	case arm.ABEQ, /* read, read */
  1247  		arm.ABNE,
  1248  		arm.ABCS,
  1249  		arm.ABHS,
  1250  		arm.ABCC,
  1251  		arm.ABLO,
  1252  		arm.ABMI,
  1253  		arm.ABPL,
  1254  		arm.ABVS,
  1255  		arm.ABVC,
  1256  		arm.ABHI,
  1257  		arm.ABLS,
  1258  		arm.ABGE,
  1259  		arm.ABLT,
  1260  		arm.ABGT,
  1261  		arm.ABLE:
  1262  		if s != nil {
  1263  			if copysub(&p.From, v, s, 1) != 0 {
  1264  				return 1
  1265  			}
  1266  			return copysub1(p, v, s, 1)
  1267  		}
  1268  
  1269  		if copyau(&p.From, v) {
  1270  			return 1
  1271  		}
  1272  		if copyau1(p, v) {
  1273  			return 1
  1274  		}
  1275  		return 0
  1276  
  1277  	case arm.AB: /* funny */
  1278  		if s != nil {
  1279  			if copysub(&p.To, v, s, 1) != 0 {
  1280  				return 1
  1281  			}
  1282  			return 0
  1283  		}
  1284  
  1285  		if copyau(&p.To, v) {
  1286  			return 1
  1287  		}
  1288  		return 0
  1289  
  1290  	case obj.ARET: /* funny */
  1291  		if s != nil {
  1292  			return 1
  1293  		}
  1294  		return 3
  1295  
  1296  	case arm.ABL: /* funny */
  1297  		if v.Type == obj.TYPE_REG {
  1298  			// TODO(rsc): REG_R0 and REG_F0 used to be
  1299  			// (when register numbers started at 0) exregoffset and exfregoffset,
  1300  			// which are unset entirely.
  1301  			// It's strange that this handles R0 and F0 differently from the other
  1302  			// registers. Possible failure to optimize?
  1303  			if arm.REG_R0 < v.Reg && v.Reg <= arm.REGEXT {
  1304  				return 2
  1305  			}
  1306  			if v.Reg == arm.REGARG {
  1307  				return 2
  1308  			}
  1309  			if arm.REG_F0 < v.Reg && v.Reg <= arm.FREGEXT {
  1310  				return 2
  1311  			}
  1312  		}
  1313  
  1314  		if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
  1315  			return 2
  1316  		}
  1317  
  1318  		if s != nil {
  1319  			if copysub(&p.To, v, s, 1) != 0 {
  1320  				return 1
  1321  			}
  1322  			return 0
  1323  		}
  1324  
  1325  		if copyau(&p.To, v) {
  1326  			return 4
  1327  		}
  1328  		return 3
  1329  
  1330  		// R0 is zero, used by DUFFZERO, cannot be substituted.
  1331  	// R1 is ptr to memory, used and set, cannot be substituted.
  1332  	case obj.ADUFFZERO:
  1333  		if v.Type == obj.TYPE_REG {
  1334  			if v.Reg == arm.REG_R0 {
  1335  				return 1
  1336  			}
  1337  			if v.Reg == arm.REG_R0+1 {
  1338  				return 2
  1339  			}
  1340  		}
  1341  
  1342  		return 0
  1343  
  1344  		// R0 is scratch, set by DUFFCOPY, cannot be substituted.
  1345  	// R1, R2 areptr to src, dst, used and set, cannot be substituted.
  1346  	case obj.ADUFFCOPY:
  1347  		if v.Type == obj.TYPE_REG {
  1348  			if v.Reg == arm.REG_R0 {
  1349  				return 3
  1350  			}
  1351  			if v.Reg == arm.REG_R0+1 || v.Reg == arm.REG_R0+2 {
  1352  				return 2
  1353  			}
  1354  		}
  1355  
  1356  		return 0
  1357  
  1358  	case obj.ATEXT: /* funny */
  1359  		if v.Type == obj.TYPE_REG {
  1360  			if v.Reg == arm.REGARG {
  1361  				return 3
  1362  			}
  1363  		}
  1364  		return 0
  1365  
  1366  	case obj.APCDATA,
  1367  		obj.AFUNCDATA,
  1368  		obj.AVARDEF,
  1369  		obj.AVARKILL:
  1370  		return 0
  1371  	}
  1372  }
  1373  
  1374  /*
  1375   * direct reference,
  1376   * could be set/use depending on
  1377   * semantics
  1378   */
  1379  func copyas(a *obj.Addr, v *obj.Addr) bool {
  1380  	if regtyp(v) {
  1381  		if a.Type == v.Type {
  1382  			if a.Reg == v.Reg {
  1383  				return true
  1384  			}
  1385  		}
  1386  	} else if v.Type == obj.TYPE_CONST { /* for constprop */
  1387  		if a.Type == v.Type {
  1388  			if a.Name == v.Name {
  1389  				if a.Sym == v.Sym {
  1390  					if a.Reg == v.Reg {
  1391  						if a.Offset == v.Offset {
  1392  							return true
  1393  						}
  1394  					}
  1395  				}
  1396  			}
  1397  		}
  1398  	}
  1399  
  1400  	return false
  1401  }
  1402  
  1403  func sameaddr(a *obj.Addr, v *obj.Addr) bool {
  1404  	if a.Type != v.Type {
  1405  		return false
  1406  	}
  1407  	if regtyp(v) && a.Reg == v.Reg {
  1408  		return true
  1409  	}
  1410  
  1411  	// TODO(rsc): Change v->type to v->name and enable.
  1412  	//if(v->type == NAME_AUTO || v->type == NAME_PARAM) {
  1413  	//	if(v->offset == a->offset)
  1414  	//		return 1;
  1415  	//}
  1416  	return false
  1417  }
  1418  
  1419  /*
  1420   * either direct or indirect
  1421   */
  1422  func copyau(a *obj.Addr, v *obj.Addr) bool {
  1423  	if copyas(a, v) {
  1424  		return true
  1425  	}
  1426  	if v.Type == obj.TYPE_REG {
  1427  		if a.Type == obj.TYPE_ADDR && a.Reg != 0 {
  1428  			if a.Reg == v.Reg {
  1429  				return true
  1430  			}
  1431  		} else if a.Type == obj.TYPE_MEM {
  1432  			if a.Reg == v.Reg {
  1433  				return true
  1434  			}
  1435  		} else if a.Type == obj.TYPE_REGREG || a.Type == obj.TYPE_REGREG2 {
  1436  			if a.Reg == v.Reg {
  1437  				return true
  1438  			}
  1439  			if a.Offset == int64(v.Reg) {
  1440  				return true
  1441  			}
  1442  		} else if a.Type == obj.TYPE_SHIFT {
  1443  			if a.Offset&0xf == int64(v.Reg-arm.REG_R0) {
  1444  				return true
  1445  			}
  1446  			if (a.Offset&(1<<4) != 0) && (a.Offset>>8)&0xf == int64(v.Reg-arm.REG_R0) {
  1447  				return true
  1448  			}
  1449  		}
  1450  	}
  1451  
  1452  	return false
  1453  }
  1454  
  1455  /*
  1456   * compare v to the center
  1457   * register in p (p->reg)
  1458   */
  1459  func copyau1(p *obj.Prog, v *obj.Addr) bool {
  1460  	if v.Type == obj.TYPE_REG && v.Reg == 0 {
  1461  		return false
  1462  	}
  1463  	return p.Reg == v.Reg
  1464  }
  1465  
  1466  /*
  1467   * substitute s for v in a
  1468   * return failure to substitute
  1469   */
  1470  func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int {
  1471  	if f != 0 {
  1472  		if copyau(a, v) {
  1473  			if a.Type == obj.TYPE_SHIFT {
  1474  				if a.Offset&0xf == int64(v.Reg-arm.REG_R0) {
  1475  					a.Offset = a.Offset&^0xf | int64(s.Reg)&0xf
  1476  				}
  1477  				if (a.Offset&(1<<4) != 0) && (a.Offset>>8)&0xf == int64(v.Reg-arm.REG_R0) {
  1478  					a.Offset = a.Offset&^(0xf<<8) | (int64(s.Reg)&0xf)<<8
  1479  				}
  1480  			} else if a.Type == obj.TYPE_REGREG || a.Type == obj.TYPE_REGREG2 {
  1481  				if a.Offset == int64(v.Reg) {
  1482  					a.Offset = int64(s.Reg)
  1483  				}
  1484  				if a.Reg == v.Reg {
  1485  					a.Reg = s.Reg
  1486  				}
  1487  			} else {
  1488  				a.Reg = s.Reg
  1489  			}
  1490  		}
  1491  	}
  1492  
  1493  	return 0
  1494  }
  1495  
  1496  func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f int) int {
  1497  	if f != 0 {
  1498  		if copyau1(p1, v) {
  1499  			p1.Reg = s.Reg
  1500  		}
  1501  	}
  1502  	return 0
  1503  }
  1504  
  1505  var predinfo = []struct {
  1506  	opcode    int
  1507  	notopcode int
  1508  	scond     int
  1509  	notscond  int
  1510  }{
  1511  	{arm.ABEQ, arm.ABNE, 0x0, 0x1},
  1512  	{arm.ABNE, arm.ABEQ, 0x1, 0x0},
  1513  	{arm.ABCS, arm.ABCC, 0x2, 0x3},
  1514  	{arm.ABHS, arm.ABLO, 0x2, 0x3},
  1515  	{arm.ABCC, arm.ABCS, 0x3, 0x2},
  1516  	{arm.ABLO, arm.ABHS, 0x3, 0x2},
  1517  	{arm.ABMI, arm.ABPL, 0x4, 0x5},
  1518  	{arm.ABPL, arm.ABMI, 0x5, 0x4},
  1519  	{arm.ABVS, arm.ABVC, 0x6, 0x7},
  1520  	{arm.ABVC, arm.ABVS, 0x7, 0x6},
  1521  	{arm.ABHI, arm.ABLS, 0x8, 0x9},
  1522  	{arm.ABLS, arm.ABHI, 0x9, 0x8},
  1523  	{arm.ABGE, arm.ABLT, 0xA, 0xB},
  1524  	{arm.ABLT, arm.ABGE, 0xB, 0xA},
  1525  	{arm.ABGT, arm.ABLE, 0xC, 0xD},
  1526  	{arm.ABLE, arm.ABGT, 0xD, 0xC},
  1527  }
  1528  
  1529  type Joininfo struct {
  1530  	start *gc.Flow
  1531  	last  *gc.Flow
  1532  	end   *gc.Flow
  1533  	len   int
  1534  }
  1535  
  1536  const (
  1537  	Join = iota
  1538  	Split
  1539  	End
  1540  	Branch
  1541  	Setcond
  1542  	Toolong
  1543  )
  1544  
  1545  const (
  1546  	Falsecond = iota
  1547  	Truecond
  1548  	Delbranch
  1549  	Keepbranch
  1550  )
  1551  
  1552  func isbranch(p *obj.Prog) bool {
  1553  	return (arm.ABEQ <= p.As) && (p.As <= arm.ABLE)
  1554  }
  1555  
  1556  func predicable(p *obj.Prog) bool {
  1557  	switch p.As {
  1558  	case obj.ANOP,
  1559  		obj.AXXX,
  1560  		obj.ADATA,
  1561  		obj.AGLOBL,
  1562  		obj.ATEXT,
  1563  		arm.AWORD,
  1564  		arm.ABCASE,
  1565  		arm.ACASE:
  1566  		return false
  1567  	}
  1568  
  1569  	if isbranch(p) {
  1570  		return false
  1571  	}
  1572  	return true
  1573  }
  1574  
  1575  /*
  1576   * Depends on an analysis of the encodings performed by 5l.
  1577   * These seem to be all of the opcodes that lead to the "S" bit
  1578   * being set in the instruction encodings.
  1579   *
  1580   * C_SBIT may also have been set explicitly in p->scond.
  1581   */
  1582  func modifiescpsr(p *obj.Prog) bool {
  1583  	switch p.As {
  1584  	case arm.AMULLU,
  1585  		arm.AMULA,
  1586  		arm.AMULU,
  1587  		arm.ADIVU,
  1588  		arm.ATEQ,
  1589  		arm.ACMN,
  1590  		arm.ATST,
  1591  		arm.ACMP,
  1592  		arm.AMUL,
  1593  		arm.ADIV,
  1594  		arm.AMOD,
  1595  		arm.AMODU,
  1596  		arm.ABL:
  1597  		return true
  1598  	}
  1599  
  1600  	if p.Scond&arm.C_SBIT != 0 {
  1601  		return true
  1602  	}
  1603  	return false
  1604  }
  1605  
  1606  /*
  1607   * Find the maximal chain of instructions starting with r which could
  1608   * be executed conditionally
  1609   */
  1610  func joinsplit(r *gc.Flow, j *Joininfo) int {
  1611  	j.start = r
  1612  	j.last = r
  1613  	j.len = 0
  1614  	for {
  1615  		if r.P2 != nil && (r.P1 != nil || r.P2.P2link != nil) {
  1616  			j.end = r
  1617  			return Join
  1618  		}
  1619  
  1620  		if r.S1 != nil && r.S2 != nil {
  1621  			j.end = r
  1622  			return Split
  1623  		}
  1624  
  1625  		j.last = r
  1626  		if r.Prog.As != obj.ANOP {
  1627  			j.len++
  1628  		}
  1629  		if r.S1 == nil && r.S2 == nil {
  1630  			j.end = r.Link
  1631  			return End
  1632  		}
  1633  
  1634  		if r.S2 != nil {
  1635  			j.end = r.S2
  1636  			return Branch
  1637  		}
  1638  
  1639  		if modifiescpsr(r.Prog) {
  1640  			j.end = r.S1
  1641  			return Setcond
  1642  		}
  1643  
  1644  		r = r.S1
  1645  		if j.len >= 4 {
  1646  			break
  1647  		}
  1648  	}
  1649  
  1650  	j.end = r
  1651  	return Toolong
  1652  }
  1653  
  1654  func successor(r *gc.Flow) *gc.Flow {
  1655  	if r.S1 != nil {
  1656  		return r.S1
  1657  	} else {
  1658  		return r.S2
  1659  	}
  1660  }
  1661  
  1662  func applypred(rstart *gc.Flow, j *Joininfo, cond int, branch int) {
  1663  	if j.len == 0 {
  1664  		return
  1665  	}
  1666  	var pred int
  1667  	if cond == Truecond {
  1668  		pred = predinfo[rstart.Prog.As-arm.ABEQ].scond
  1669  	} else {
  1670  		pred = predinfo[rstart.Prog.As-arm.ABEQ].notscond
  1671  	}
  1672  
  1673  	for r := (*gc.Flow)(j.start); ; r = successor(r) {
  1674  		if r.Prog.As == arm.AB {
  1675  			if r != j.last || branch == Delbranch {
  1676  				excise(r)
  1677  			} else {
  1678  				if cond == Truecond {
  1679  					r.Prog.As = int16(predinfo[rstart.Prog.As-arm.ABEQ].opcode)
  1680  				} else {
  1681  					r.Prog.As = int16(predinfo[rstart.Prog.As-arm.ABEQ].notopcode)
  1682  				}
  1683  			}
  1684  		} else if predicable(r.Prog) {
  1685  			r.Prog.Scond = uint8(int(r.Prog.Scond&^arm.C_SCOND) | pred)
  1686  		}
  1687  		if r.S1 != r.Link {
  1688  			r.S1 = r.Link
  1689  			r.Link.P1 = r
  1690  		}
  1691  
  1692  		if r == j.last {
  1693  			break
  1694  		}
  1695  	}
  1696  }
  1697  
  1698  func predicate(g *gc.Graph) {
  1699  	var t1 int
  1700  	var t2 int
  1701  	var j1 Joininfo
  1702  	var j2 Joininfo
  1703  
  1704  	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
  1705  		if isbranch(r.Prog) {
  1706  			t1 = joinsplit(r.S1, &j1)
  1707  			t2 = joinsplit(r.S2, &j2)
  1708  			if j1.last.Link != j2.start {
  1709  				continue
  1710  			}
  1711  			if j1.end == j2.end {
  1712  				if (t1 == Branch && (t2 == Join || t2 == Setcond)) || (t2 == Join && (t1 == Join || t1 == Setcond)) {
  1713  					applypred(r, &j1, Falsecond, Delbranch)
  1714  					applypred(r, &j2, Truecond, Delbranch)
  1715  					excise(r)
  1716  					continue
  1717  				}
  1718  			}
  1719  
  1720  			if t1 == End || t1 == Branch {
  1721  				applypred(r, &j1, Falsecond, Keepbranch)
  1722  				excise(r)
  1723  				continue
  1724  			}
  1725  		}
  1726  	}
  1727  }
  1728  
  1729  func isdconst(a *obj.Addr) bool {
  1730  	return a.Type == obj.TYPE_CONST
  1731  }
  1732  
  1733  func isfloatreg(a *obj.Addr) bool {
  1734  	return arm.REG_F0 <= a.Reg && a.Reg <= arm.REG_F15
  1735  }
  1736  
  1737  func stackaddr(a *obj.Addr) bool {
  1738  	return regtyp(a) && a.Reg == arm.REGSP
  1739  }
  1740  
  1741  func smallindir(a *obj.Addr, reg *obj.Addr) bool {
  1742  	return reg.Type == obj.TYPE_REG && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && 0 <= a.Offset && a.Offset < 4096
  1743  }
  1744  
  1745  func excise(r *gc.Flow) {
  1746  	p := (*obj.Prog)(r.Prog)
  1747  	obj.Nopout(p)
  1748  }