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

     1  // Derived from Inferno utils/6c/peep.c
     2  // https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6c/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 s390x
    32  
    33  import (
    34  	"cmd/compile/internal/gc"
    35  	"cmd/internal/obj"
    36  	"cmd/internal/obj/s390x"
    37  	"fmt"
    38  )
    39  
    40  type usage int
    41  
    42  const (
    43  	_None          usage = iota // no usage found
    44  	_Read                       // only read from
    45  	_ReadWriteSame              // both read from and written to in a single operand
    46  	_Write                      // only written to
    47  	_ReadWriteDiff              // both read from and written to in different operands
    48  )
    49  
    50  var gactive uint32
    51  
    52  func peep(firstp *obj.Prog) {
    53  	g := gc.Flowstart(firstp, nil)
    54  	if g == nil {
    55  		return
    56  	}
    57  	gactive = 0
    58  
    59  	run := func(name string, pass func(r *gc.Flow) int) int {
    60  		n := pass(g.Start)
    61  		if gc.Debug['P'] != 0 {
    62  			fmt.Println(name, ":", n)
    63  		}
    64  		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    65  			gc.Dumpit(name, g.Start, 0)
    66  		}
    67  		return n
    68  	}
    69  
    70  	for {
    71  		n := 0
    72  		n += run("constant propagation", constantPropagation)
    73  		n += run("copy propagation", copyPropagation)
    74  		n += run("cast propagation", castPropagation)
    75  		n += run("remove load-hit-stores", removeLoadHitStores)
    76  		n += run("dead code elimination", deadCodeElimination)
    77  		if n == 0 {
    78  			break
    79  		}
    80  	}
    81  	run("fuse op moves", fuseOpMoves)
    82  	run("fuse clears", fuseClear)
    83  	run("load pipelining", loadPipelining)
    84  	run("fuse compare branch", fuseCompareBranch)
    85  	run("simplify ops", simplifyOps)
    86  	run("dead code elimination", deadCodeElimination)
    87  
    88  	// TODO(mundaym): load/store multiple aren't currently handled by copyu
    89  	// so this pass must be last.
    90  	run("fuse multiple", fuseMultiple)
    91  
    92  	gc.Flowend(g)
    93  }
    94  
    95  func pushback(r0 *gc.Flow) {
    96  	var r *gc.Flow
    97  
    98  	var b *gc.Flow
    99  	p0 := r0.Prog
   100  	for r = gc.Uniqp(r0); r != nil && gc.Uniqs(r) != nil; r = gc.Uniqp(r) {
   101  		p := r.Prog
   102  		if p.As != obj.ANOP {
   103  			if !(isReg(&p.From) || isConst(&p.From)) || !isReg(&p.To) {
   104  				break
   105  			}
   106  			if copyu(p, &p0.To, nil) != _None || copyu(p0, &p.To, nil) != _None {
   107  				break
   108  			}
   109  		}
   110  
   111  		if p.As == obj.ACALL {
   112  			break
   113  		}
   114  		b = r
   115  	}
   116  
   117  	if b == nil {
   118  		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   119  			fmt.Printf("no pushback: %v\n", r0.Prog)
   120  			if r != nil {
   121  				fmt.Printf("\t%v [%v]\n", r.Prog, gc.Uniqs(r) != nil)
   122  			}
   123  		}
   124  
   125  		return
   126  	}
   127  
   128  	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   129  		fmt.Printf("pushback\n")
   130  		for r := b; ; r = r.Link {
   131  			fmt.Printf("\t%v\n", r.Prog)
   132  			if r == r0 {
   133  				break
   134  			}
   135  		}
   136  	}
   137  
   138  	t := *r0.Prog
   139  	for r = gc.Uniqp(r0); ; r = gc.Uniqp(r) {
   140  		p0 = r.Link.Prog
   141  		p := r.Prog
   142  		p0.As = p.As
   143  		p0.Lineno = p.Lineno
   144  		p0.From = p.From
   145  		p0.To = p.To
   146  		p0.From3 = p.From3
   147  		p0.Reg = p.Reg
   148  		p0.RegTo2 = p.RegTo2
   149  		if r == b {
   150  			break
   151  		}
   152  	}
   153  
   154  	p0 = r.Prog
   155  	p0.As = t.As
   156  	p0.Lineno = t.Lineno
   157  	p0.From = t.From
   158  	p0.To = t.To
   159  	p0.From3 = t.From3
   160  	p0.Reg = t.Reg
   161  	p0.RegTo2 = t.RegTo2
   162  
   163  	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   164  		fmt.Printf("\tafter\n")
   165  		for r := b; ; r = r.Link {
   166  			fmt.Printf("\t%v\n", r.Prog)
   167  			if r == r0 {
   168  				break
   169  			}
   170  		}
   171  	}
   172  }
   173  
   174  // excise replaces the given instruction with a NOP and clears
   175  // its operands.
   176  func excise(r *gc.Flow) {
   177  	p := r.Prog
   178  	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   179  		fmt.Printf("%v ===delete===\n", p)
   180  	}
   181  	obj.Nopout(p)
   182  	gc.Ostats.Ndelmov++
   183  }
   184  
   185  // isZero returns true if a is either the constant 0 or the register
   186  // REGZERO.
   187  func isZero(a *obj.Addr) bool {
   188  	if a.Type == obj.TYPE_CONST && a.Offset == 0 {
   189  		return true
   190  	}
   191  	if a.Type == obj.TYPE_REG && a.Reg == s390x.REGZERO {
   192  		return true
   193  	}
   194  	return false
   195  }
   196  
   197  // isReg returns true if a is a general purpose or floating point
   198  // register (GPR or FPR).
   199  //
   200  // TODO(mundaym): currently this excludes REGZER0, but not other
   201  // special registers.
   202  func isReg(a *obj.Addr) bool {
   203  	return a.Type == obj.TYPE_REG &&
   204  		s390x.REG_R0 <= a.Reg &&
   205  		a.Reg <= s390x.REG_F15 &&
   206  		a.Reg != s390x.REGZERO
   207  }
   208  
   209  // isGPR returns true if a is a general purpose register (GPR).
   210  // REGZERO is treated as a GPR.
   211  func isGPR(a *obj.Addr) bool {
   212  	return a.Type == obj.TYPE_REG &&
   213  		s390x.REG_R0 <= a.Reg &&
   214  		a.Reg <= s390x.REG_R15
   215  }
   216  
   217  // isFPR returns true if a is a floating point register (FPR).
   218  func isFPR(a *obj.Addr) bool {
   219  	return a.Type == obj.TYPE_REG &&
   220  		s390x.REG_F0 <= a.Reg &&
   221  		a.Reg <= s390x.REG_F15
   222  }
   223  
   224  // isConst returns true if a refers to a constant (integer or
   225  // floating point, not string currently).
   226  func isConst(a *obj.Addr) bool {
   227  	return a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_FCONST
   228  }
   229  
   230  // isBDMem returns true if a refers to a memory location addressable by a
   231  // base register (B) and a displacement (D), such as:
   232  // 	x+8(R1)
   233  // and
   234  //	0(R10)
   235  // It returns false if the address contains an index register (X) such as:
   236  // 	16(R1)(R2*1)
   237  // or if a relocation is required.
   238  func isBDMem(a *obj.Addr) bool {
   239  	return a.Type == obj.TYPE_MEM &&
   240  		a.Index == 0 &&
   241  		(a.Name == obj.NAME_NONE || a.Name == obj.NAME_AUTO || a.Name == obj.NAME_PARAM)
   242  }
   243  
   244  // the idea is to substitute
   245  // one register for another
   246  // from one MOV to another
   247  //	MOV	a, R1
   248  //	ADD	b, R1	/ no use of R2
   249  //	MOV	R1, R2
   250  // would be converted to
   251  //	MOV	a, R2
   252  //	ADD	b, R2
   253  //	MOV	R2, R1
   254  // hopefully, then the former or latter MOV
   255  // will be eliminated by copy propagation.
   256  //
   257  // r0 (the argument, not the register) is the MOV at the end of the
   258  // above sequences. subprop returns true if it modified any instructions.
   259  func subprop(r0 *gc.Flow) bool {
   260  	p := r0.Prog
   261  	v1 := &p.From
   262  	if !isReg(v1) {
   263  		return false
   264  	}
   265  	v2 := &p.To
   266  	if !isReg(v2) {
   267  		return false
   268  	}
   269  	cast := false
   270  	switch p.As {
   271  	case s390x.AMOVW, s390x.AMOVWZ,
   272  		s390x.AMOVH, s390x.AMOVHZ,
   273  		s390x.AMOVB, s390x.AMOVBZ:
   274  		cast = true
   275  	}
   276  	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
   277  		if gc.Uniqs(r) == nil {
   278  			break
   279  		}
   280  		p = r.Prog
   281  		switch copyu(p, v1, nil) {
   282  		case _Write, _ReadWriteDiff:
   283  			if p.As == obj.ACALL {
   284  				return false
   285  			}
   286  			if (!cast || p.As == r0.Prog.As) && p.To.Type == v1.Type && p.To.Reg == v1.Reg {
   287  				copysub(&p.To, v1, v2)
   288  				for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
   289  					p = r.Prog
   290  					copysub(&p.From, v1, v2)
   291  					copysub1(p, v1, v2)
   292  					copysub(&p.To, v1, v2)
   293  				}
   294  				v1.Reg, v2.Reg = v2.Reg, v1.Reg
   295  				return true
   296  			}
   297  			if cast {
   298  				return false
   299  			}
   300  		case _ReadWriteSame:
   301  			if cast {
   302  				return false
   303  			}
   304  		}
   305  		if copyu(p, v2, nil) != _None {
   306  			return false
   307  		}
   308  	}
   309  	return false
   310  }
   311  
   312  // The idea is to remove redundant copies.
   313  //     v1->v2  F=0
   314  //     (use v2 s/v2/v1/)*
   315  //     set v1  F=1
   316  //     use v2  return fail (v1->v2 move must remain)
   317  //     -----------------
   318  //     v1->v2  F=0
   319  //     (use v2 s/v2/v1/)*
   320  //     set v1  F=1
   321  //     set v2  return success (caller can remove v1->v2 move)
   322  func copyprop(r *gc.Flow) bool {
   323  	p := r.Prog
   324  
   325  	canSub := false
   326  	switch p.As {
   327  	case s390x.AFMOVS, s390x.AFMOVD, s390x.AMOVD:
   328  		canSub = true
   329  	default:
   330  		for rr := gc.Uniqp(r); rr != nil; rr = gc.Uniqp(rr) {
   331  			if gc.Uniqs(rr) == nil {
   332  				break
   333  			}
   334  			switch copyu(rr.Prog, &p.From, nil) {
   335  			case _Read, _None:
   336  				continue
   337  			}
   338  			// write
   339  			if rr.Prog.As == p.As {
   340  				canSub = true
   341  			}
   342  			break
   343  		}
   344  	}
   345  	if !canSub {
   346  		return false
   347  	}
   348  	if copyas(&p.From, &p.To) {
   349  		return true
   350  	}
   351  
   352  	gactive++
   353  	return copy1(&p.From, &p.To, r.S1, 0)
   354  }
   355  
   356  // copy1 replaces uses of v2 with v1 starting at r and returns true if
   357  // all uses were rewritten.
   358  func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
   359  	if uint32(r.Active) == gactive {
   360  		return true
   361  	}
   362  	r.Active = int32(gactive)
   363  	for ; r != nil; r = r.S1 {
   364  		p := r.Prog
   365  		if f == 0 && gc.Uniqp(r) == nil {
   366  			// Multiple predecessors; conservatively
   367  			// assume v1 was set on other path
   368  			f = 1
   369  		}
   370  		t := copyu(p, v2, nil)
   371  		switch t {
   372  		case _ReadWriteSame:
   373  			return false
   374  		case _Write:
   375  			return true
   376  		case _Read, _ReadWriteDiff:
   377  			if f != 0 {
   378  				return false
   379  			}
   380  			if copyu(p, v2, v1) != 0 {
   381  				return false
   382  			}
   383  			if t == _ReadWriteDiff {
   384  				return true
   385  			}
   386  		}
   387  		if f == 0 {
   388  			switch copyu(p, v1, nil) {
   389  			case _ReadWriteSame, _ReadWriteDiff, _Write:
   390  				f = 1
   391  			}
   392  		}
   393  		if r.S2 != nil {
   394  			if !copy1(v1, v2, r.S2, f) {
   395  				return false
   396  			}
   397  		}
   398  	}
   399  	return true
   400  }
   401  
   402  // If s==nil, copyu returns the set/use of v in p; otherwise, it
   403  // modifies p to replace reads of v with reads of s and returns 0 for
   404  // success or non-zero for failure.
   405  //
   406  // If s==nil, copy returns one of the following values:
   407  // 	_Read           if v only used
   408  //	_ReadWriteSame  if v is set and used in one address (read-alter-rewrite;
   409  // 	                can't substitute)
   410  //	_Write          if v is only set
   411  //	_ReadWriteDiff  if v is set in one address and used in another (so addresses
   412  // 	                can be rewritten independently)
   413  //	_None           otherwise (not touched)
   414  func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) usage {
   415  	if p.From3Type() != obj.TYPE_NONE && p.From3Type() != obj.TYPE_CONST {
   416  		// Currently we never generate a From3 with anything other than a constant in it.
   417  		fmt.Printf("copyu: From3 (%v) not implemented\n", gc.Ctxt.Dconv(p.From3))
   418  	}
   419  
   420  	switch p.As {
   421  	default:
   422  		fmt.Printf("copyu: can't find %v\n", p.As)
   423  		return _ReadWriteSame
   424  
   425  	case // read p.From, write p.To
   426  		s390x.AMOVH,
   427  		s390x.AMOVHZ,
   428  		s390x.AMOVB,
   429  		s390x.AMOVBZ,
   430  		s390x.AMOVW,
   431  		s390x.AMOVWZ,
   432  		s390x.AMOVD,
   433  		s390x.ANEG,
   434  		s390x.AADDME,
   435  		s390x.AADDZE,
   436  		s390x.ASUBME,
   437  		s390x.ASUBZE,
   438  		s390x.AFMOVS,
   439  		s390x.AFMOVD,
   440  		s390x.ALEDBR,
   441  		s390x.AFNEG,
   442  		s390x.ALDEBR,
   443  		s390x.ACLFEBR,
   444  		s390x.ACLGEBR,
   445  		s390x.ACLFDBR,
   446  		s390x.ACLGDBR,
   447  		s390x.ACFEBRA,
   448  		s390x.ACGEBRA,
   449  		s390x.ACFDBRA,
   450  		s390x.ACGDBRA,
   451  		s390x.ACELFBR,
   452  		s390x.ACELGBR,
   453  		s390x.ACDLFBR,
   454  		s390x.ACDLGBR,
   455  		s390x.ACEFBRA,
   456  		s390x.ACEGBRA,
   457  		s390x.ACDFBRA,
   458  		s390x.ACDGBRA,
   459  		s390x.AFSQRT:
   460  
   461  		if s != nil {
   462  			copysub(&p.From, v, s)
   463  
   464  			// Update only indirect uses of v in p.To
   465  			if !copyas(&p.To, v) {
   466  				copysub(&p.To, v, s)
   467  			}
   468  			return _None
   469  		}
   470  
   471  		if copyas(&p.To, v) {
   472  			// Fix up implicit from
   473  			if p.From.Type == obj.TYPE_NONE {
   474  				p.From = p.To
   475  			}
   476  			if copyau(&p.From, v) {
   477  				return _ReadWriteDiff
   478  			}
   479  			return _Write
   480  		}
   481  
   482  		if copyau(&p.From, v) {
   483  			return _Read
   484  		}
   485  		if copyau(&p.To, v) {
   486  			// p.To only indirectly uses v
   487  			return _Read
   488  		}
   489  
   490  		return _None
   491  
   492  	// read p.From, read p.Reg, write p.To
   493  	case s390x.AADD,
   494  		s390x.AADDC,
   495  		s390x.AADDE,
   496  		s390x.ASUB,
   497  		s390x.ASLW,
   498  		s390x.ASRW,
   499  		s390x.ASRAW,
   500  		s390x.ASLD,
   501  		s390x.ASRD,
   502  		s390x.ASRAD,
   503  		s390x.ARLL,
   504  		s390x.ARLLG,
   505  		s390x.AOR,
   506  		s390x.AORN,
   507  		s390x.AAND,
   508  		s390x.AANDN,
   509  		s390x.ANAND,
   510  		s390x.ANOR,
   511  		s390x.AXOR,
   512  		s390x.AMULLW,
   513  		s390x.AMULLD,
   514  		s390x.AMULHD,
   515  		s390x.AMULHDU,
   516  		s390x.ADIVW,
   517  		s390x.ADIVD,
   518  		s390x.ADIVWU,
   519  		s390x.ADIVDU,
   520  		s390x.AFADDS,
   521  		s390x.AFADD,
   522  		s390x.AFSUBS,
   523  		s390x.AFSUB,
   524  		s390x.AFMULS,
   525  		s390x.AFMUL,
   526  		s390x.AFDIVS,
   527  		s390x.AFDIV:
   528  		if s != nil {
   529  			copysub(&p.From, v, s)
   530  			copysub1(p, v, s)
   531  
   532  			// Update only indirect uses of v in p.To
   533  			if !copyas(&p.To, v) {
   534  				copysub(&p.To, v, s)
   535  			}
   536  		}
   537  
   538  		if copyas(&p.To, v) {
   539  			if p.Reg == 0 {
   540  				p.Reg = p.To.Reg
   541  			}
   542  			if copyau(&p.From, v) || copyau1(p, v) {
   543  				return _ReadWriteDiff
   544  			}
   545  			return _Write
   546  		}
   547  
   548  		if copyau(&p.From, v) {
   549  			return _Read
   550  		}
   551  		if copyau1(p, v) {
   552  			return _Read
   553  		}
   554  		if copyau(&p.To, v) {
   555  			return _Read
   556  		}
   557  		return _None
   558  
   559  	case s390x.ABEQ,
   560  		s390x.ABGT,
   561  		s390x.ABGE,
   562  		s390x.ABLT,
   563  		s390x.ABLE,
   564  		s390x.ABNE,
   565  		s390x.ABVC,
   566  		s390x.ABVS:
   567  		return _None
   568  
   569  	case obj.ACHECKNIL, // read p.From
   570  		s390x.ACMP, // read p.From, read p.To
   571  		s390x.ACMPU,
   572  		s390x.ACMPW,
   573  		s390x.ACMPWU,
   574  		s390x.AFCMPO,
   575  		s390x.AFCMPU,
   576  		s390x.ACEBR,
   577  		s390x.AMVC,
   578  		s390x.ACLC,
   579  		s390x.AXC,
   580  		s390x.AOC,
   581  		s390x.ANC:
   582  		if s != nil {
   583  			copysub(&p.From, v, s)
   584  			copysub(&p.To, v, s)
   585  			return _None
   586  		}
   587  
   588  		if copyau(&p.From, v) {
   589  			return _Read
   590  		}
   591  		if copyau(&p.To, v) {
   592  			return _Read
   593  		}
   594  		return _None
   595  
   596  	case s390x.ACMPBNE, s390x.ACMPBEQ,
   597  		s390x.ACMPBLT, s390x.ACMPBLE,
   598  		s390x.ACMPBGT, s390x.ACMPBGE,
   599  		s390x.ACMPUBNE, s390x.ACMPUBEQ,
   600  		s390x.ACMPUBLT, s390x.ACMPUBLE,
   601  		s390x.ACMPUBGT, s390x.ACMPUBGE:
   602  		if s != nil {
   603  			copysub(&p.From, v, s)
   604  			copysub1(p, v, s)
   605  			return _None
   606  		}
   607  		if copyau(&p.From, v) {
   608  			return _Read
   609  		}
   610  		if copyau1(p, v) {
   611  			return _Read
   612  		}
   613  		return _None
   614  
   615  	case s390x.ACLEAR:
   616  		if s != nil {
   617  			copysub(&p.To, v, s)
   618  			return _None
   619  		}
   620  		if copyau(&p.To, v) {
   621  			return _Read
   622  		}
   623  		return _None
   624  
   625  	// go never generates a branch to a GPR
   626  	// read p.To
   627  	case s390x.ABR:
   628  		if s != nil {
   629  			copysub(&p.To, v, s)
   630  			return _None
   631  		}
   632  
   633  		if copyau(&p.To, v) {
   634  			return _Read
   635  		}
   636  		return _None
   637  
   638  	case obj.ARET, obj.AUNDEF:
   639  		if s != nil {
   640  			return _None
   641  		}
   642  
   643  		// All registers die at this point, so claim
   644  		// everything is set (and not used).
   645  		return _Write
   646  
   647  	case s390x.ABL:
   648  		if v.Type == obj.TYPE_REG {
   649  			if s390x.REGARG != -1 && v.Reg == s390x.REGARG {
   650  				return _ReadWriteSame
   651  			}
   652  			if p.From.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
   653  				return _ReadWriteSame
   654  			}
   655  			if v.Reg == s390x.REGZERO {
   656  				// Deliberately inserted nops set R0.
   657  				return _ReadWriteSame
   658  			}
   659  			if v.Reg == s390x.REGCTXT {
   660  				// Context register for closures.
   661  				// TODO(mundaym): not sure if we need to exclude this.
   662  				return _ReadWriteSame
   663  			}
   664  		}
   665  		if s != nil {
   666  			copysub(&p.To, v, s)
   667  			return _None
   668  		}
   669  		if copyau(&p.To, v) {
   670  			return _ReadWriteDiff
   671  		}
   672  		return _Write
   673  
   674  	case obj.ATEXT:
   675  		if v.Type == obj.TYPE_REG {
   676  			if v.Reg == s390x.REGARG {
   677  				return _Write
   678  			}
   679  		}
   680  		return _None
   681  
   682  	case obj.APCDATA,
   683  		obj.AFUNCDATA,
   684  		obj.AVARDEF,
   685  		obj.AVARKILL,
   686  		obj.AVARLIVE,
   687  		obj.AUSEFIELD,
   688  		obj.ANOP:
   689  		return _None
   690  	}
   691  }
   692  
   693  // copyas returns 1 if a and v address the same register.
   694  //
   695  // If a is the from operand, this means this operation reads the
   696  // register in v.  If a is the to operand, this means this operation
   697  // writes the register in v.
   698  func copyas(a *obj.Addr, v *obj.Addr) bool {
   699  	if isReg(v) {
   700  		if a.Type == v.Type {
   701  			if a.Reg == v.Reg {
   702  				return true
   703  			}
   704  		}
   705  	}
   706  	return false
   707  }
   708  
   709  // copyau returns 1 if a either directly or indirectly addresses the
   710  // same register as v.
   711  //
   712  // If a is the from operand, this means this operation reads the
   713  // register in v.  If a is the to operand, this means the operation
   714  // either reads or writes the register in v (if !copyas(a, v), then
   715  // the operation reads the register in v).
   716  func copyau(a *obj.Addr, v *obj.Addr) bool {
   717  	if copyas(a, v) {
   718  		return true
   719  	}
   720  	if v.Type == obj.TYPE_REG {
   721  		if a.Type == obj.TYPE_MEM || (a.Type == obj.TYPE_ADDR && a.Reg != 0) {
   722  			if v.Reg == a.Reg {
   723  				return true
   724  			}
   725  		}
   726  	}
   727  	return false
   728  }
   729  
   730  // copyau1 returns 1 if p.Reg references the same register as v and v
   731  // is a direct reference.
   732  func copyau1(p *obj.Prog, v *obj.Addr) bool {
   733  	if isReg(v) && v.Reg != 0 {
   734  		if p.Reg == v.Reg {
   735  			return true
   736  		}
   737  	}
   738  	return false
   739  }
   740  
   741  // copysub replaces v.Reg with s.Reg if a.Reg and v.Reg are direct
   742  // references to the same register.
   743  func copysub(a, v, s *obj.Addr) {
   744  	if copyau(a, v) {
   745  		a.Reg = s.Reg
   746  	}
   747  }
   748  
   749  // copysub1 replaces p.Reg with s.Reg if p.Reg and v.Reg are direct
   750  // references to the same register.
   751  func copysub1(p *obj.Prog, v, s *obj.Addr) {
   752  	if copyau1(p, v) {
   753  		p.Reg = s.Reg
   754  	}
   755  }
   756  
   757  func sameaddr(a *obj.Addr, v *obj.Addr) bool {
   758  	if a.Type != v.Type {
   759  		return false
   760  	}
   761  	if isReg(v) && a.Reg == v.Reg {
   762  		return true
   763  	}
   764  	if v.Type == obj.NAME_AUTO || v.Type == obj.NAME_PARAM {
   765  		// TODO(mundaym): is the offset enough here? Node?
   766  		if v.Offset == a.Offset {
   767  			return true
   768  		}
   769  	}
   770  	return false
   771  }
   772  
   773  func smallindir(a *obj.Addr, reg *obj.Addr) bool {
   774  	return reg.Type == obj.TYPE_REG &&
   775  		a.Type == obj.TYPE_MEM &&
   776  		a.Reg == reg.Reg &&
   777  		0 <= a.Offset && a.Offset < 4096
   778  }
   779  
   780  func stackaddr(a *obj.Addr) bool {
   781  	// TODO(mundaym): the name implies this should check
   782  	// for TYPE_ADDR with a base register REGSP.
   783  	return a.Type == obj.TYPE_REG && a.Reg == s390x.REGSP
   784  }
   785  
   786  // isMove returns true if p is a move. Moves may imply
   787  // sign/zero extension.
   788  func isMove(p *obj.Prog) bool {
   789  	switch p.As {
   790  	case s390x.AMOVD,
   791  		s390x.AMOVW, s390x.AMOVWZ,
   792  		s390x.AMOVH, s390x.AMOVHZ,
   793  		s390x.AMOVB, s390x.AMOVBZ,
   794  		s390x.AFMOVD, s390x.AFMOVS:
   795  		return true
   796  	}
   797  	return false
   798  }
   799  
   800  // isLoad returns true if p is a move from memory to a register.
   801  func isLoad(p *obj.Prog) bool {
   802  	if !isMove(p) {
   803  		return false
   804  	}
   805  	if !(isGPR(&p.To) || isFPR(&p.To)) {
   806  		return false
   807  	}
   808  	if p.From.Type != obj.TYPE_MEM {
   809  		return false
   810  	}
   811  	return true
   812  }
   813  
   814  // isStore returns true if p is a move from a register to memory.
   815  func isStore(p *obj.Prog) bool {
   816  	if !isMove(p) {
   817  		return false
   818  	}
   819  	if !(isGPR(&p.From) || isFPR(&p.From) || isConst(&p.From)) {
   820  		return false
   821  	}
   822  	if p.To.Type != obj.TYPE_MEM {
   823  		return false
   824  	}
   825  	return true
   826  }
   827  
   828  // sameStackMem returns true if a and b are both memory operands
   829  // and address the same location which must reside on the stack.
   830  func sameStackMem(a, b *obj.Addr) bool {
   831  	if a.Type != obj.TYPE_MEM ||
   832  		b.Type != obj.TYPE_MEM ||
   833  		a.Name != b.Name ||
   834  		a.Sym != b.Sym ||
   835  		a.Node != b.Node ||
   836  		a.Reg != b.Reg ||
   837  		a.Index != b.Index ||
   838  		a.Offset != b.Offset {
   839  		return false
   840  	}
   841  	switch a.Name {
   842  	case obj.NAME_NONE:
   843  		return a.Reg == s390x.REGSP
   844  	case obj.NAME_PARAM, obj.NAME_AUTO:
   845  		// params and autos are always on the stack
   846  		return true
   847  	}
   848  	return false
   849  }
   850  
   851  // removeLoadHitStores trys to remove loads that take place
   852  // immediately after a store to the same location. Returns
   853  // true if load-hit-stores were removed.
   854  //
   855  // For example:
   856  // 	MOVD	R1, 0(R15)
   857  // 	MOVD	0(R15), R2
   858  // Would become:
   859  // 	MOVD	R1, 0(R15)
   860  // 	MOVD	R1, R2
   861  func removeLoadHitStores(r *gc.Flow) int {
   862  	n := 0
   863  	for ; r != nil; r = r.Link {
   864  		p := r.Prog
   865  		if !isStore(p) {
   866  			continue
   867  		}
   868  		for rr := gc.Uniqs(r); rr != nil; rr = gc.Uniqs(rr) {
   869  			pp := rr.Prog
   870  			if gc.Uniqp(rr) == nil {
   871  				break
   872  			}
   873  			if pp.As == obj.ANOP {
   874  				continue
   875  			}
   876  			if isLoad(pp) && sameStackMem(&p.To, &pp.From) {
   877  				if size(p.As) >= size(pp.As) && isGPR(&p.From) == isGPR(&pp.To) {
   878  					pp.From = p.From
   879  				}
   880  			}
   881  			if !isMove(pp) || isStore(pp) {
   882  				break
   883  			}
   884  			if copyau(&p.From, &pp.To) {
   885  				break
   886  			}
   887  		}
   888  	}
   889  	return n
   890  }
   891  
   892  // size returns the width of the given move.
   893  func size(as obj.As) int {
   894  	switch as {
   895  	case s390x.AMOVD, s390x.AFMOVD:
   896  		return 8
   897  	case s390x.AMOVW, s390x.AMOVWZ, s390x.AFMOVS:
   898  		return 4
   899  	case s390x.AMOVH, s390x.AMOVHZ:
   900  		return 2
   901  	case s390x.AMOVB, s390x.AMOVBZ:
   902  		return 1
   903  	}
   904  	return -1
   905  }
   906  
   907  // castPropagation tries to eliminate unecessary casts.
   908  //
   909  // For example:
   910  // 	MOVHZ	R1, R2     // uint16
   911  //	MOVB	R2, 0(R15) // int8
   912  // Can be simplified to:
   913  //	MOVB	R1, 0(R15)
   914  func castPropagation(r *gc.Flow) int {
   915  	n := 0
   916  	for ; r != nil; r = r.Link {
   917  		p := r.Prog
   918  		if !isMove(p) || !isGPR(&p.To) {
   919  			continue
   920  		}
   921  
   922  		// r is a move with a destination register
   923  		var move *gc.Flow
   924  		for rr := gc.Uniqs(r); rr != nil; rr = gc.Uniqs(rr) {
   925  			if gc.Uniqp(rr) == nil {
   926  				// branch target: leave alone
   927  				break
   928  			}
   929  			pp := rr.Prog
   930  			if isMove(pp) && copyas(&pp.From, &p.To) {
   931  				if pp.To.Type == obj.TYPE_MEM {
   932  					if p.From.Type == obj.TYPE_MEM ||
   933  						p.From.Type == obj.TYPE_ADDR {
   934  						break
   935  					}
   936  					if p.From.Type == obj.TYPE_CONST &&
   937  						int64(int16(p.From.Offset)) != p.From.Offset {
   938  						break
   939  					}
   940  				}
   941  				move = rr
   942  				break
   943  			}
   944  			if pp.As == obj.ANOP {
   945  				continue
   946  			}
   947  			break
   948  		}
   949  		if move == nil {
   950  			continue
   951  		}
   952  
   953  		// we have a move that reads from our destination reg, check if any future
   954  		// instructions also read from the reg
   955  		mp := move.Prog
   956  		if !copyas(&mp.From, &mp.To) {
   957  			safe := false
   958  			for rr := gc.Uniqs(move); rr != nil; rr = gc.Uniqs(rr) {
   959  				if gc.Uniqp(rr) == nil {
   960  					break
   961  				}
   962  				switch copyu(rr.Prog, &p.To, nil) {
   963  				case _None:
   964  					continue
   965  				case _Write:
   966  					safe = true
   967  				}
   968  				break
   969  			}
   970  			if !safe {
   971  				continue
   972  			}
   973  		}
   974  
   975  		// at this point we have something like:
   976  		// MOV* const/mem/reg, reg
   977  		// MOV* reg, reg/mem
   978  		// now check if this is a cast that cannot be forward propagated
   979  		execute := false
   980  		if p.As == mp.As || isZero(&p.From) || size(p.As) == size(mp.As) {
   981  			execute = true
   982  		} else if isGPR(&p.From) && size(p.As) >= size(mp.As) {
   983  			execute = true
   984  		}
   985  
   986  		if execute {
   987  			mp.From = p.From
   988  			excise(r)
   989  			n++
   990  		}
   991  	}
   992  	return n
   993  }
   994  
   995  // fuseClear merges memory clear operations.
   996  //
   997  // Looks for this pattern (sequence of clears):
   998  // 	MOVD	R0, n(R15)
   999  // 	MOVD	R0, n+8(R15)
  1000  // 	MOVD	R0, n+16(R15)
  1001  // Replaces with:
  1002  //	CLEAR	$24, n(R15)
  1003  func fuseClear(r *gc.Flow) int {
  1004  	n := 0
  1005  	var align int64
  1006  	var clear *obj.Prog
  1007  	for ; r != nil; r = r.Link {
  1008  		// If there is a branch into the instruction stream then
  1009  		// we can't fuse into previous instructions.
  1010  		if gc.Uniqp(r) == nil {
  1011  			clear = nil
  1012  		}
  1013  
  1014  		p := r.Prog
  1015  		if p.As == obj.ANOP {
  1016  			continue
  1017  		}
  1018  		if p.As == s390x.AXC {
  1019  			if p.From.Reg == p.To.Reg && p.From.Offset == p.To.Offset {
  1020  				// TODO(mundaym): merge clears?
  1021  				p.As = s390x.ACLEAR
  1022  				p.From.Offset = p.From3.Offset
  1023  				p.From3 = nil
  1024  				p.From.Type = obj.TYPE_CONST
  1025  				p.From.Reg = 0
  1026  				clear = p
  1027  			} else {
  1028  				clear = nil
  1029  			}
  1030  			continue
  1031  		}
  1032  
  1033  		// Is our source a constant zero?
  1034  		if !isZero(&p.From) {
  1035  			clear = nil
  1036  			continue
  1037  		}
  1038  
  1039  		// Are we moving to memory?
  1040  		if p.To.Type != obj.TYPE_MEM ||
  1041  			p.To.Index != 0 ||
  1042  			p.To.Offset >= 4096 ||
  1043  			!(p.To.Name == obj.NAME_NONE || p.To.Name == obj.NAME_AUTO || p.To.Name == obj.NAME_PARAM) {
  1044  			clear = nil
  1045  			continue
  1046  		}
  1047  
  1048  		size := int64(0)
  1049  		switch p.As {
  1050  		default:
  1051  			clear = nil
  1052  			continue
  1053  		case s390x.AMOVB, s390x.AMOVBZ:
  1054  			size = 1
  1055  		case s390x.AMOVH, s390x.AMOVHZ:
  1056  			size = 2
  1057  		case s390x.AMOVW, s390x.AMOVWZ:
  1058  			size = 4
  1059  		case s390x.AMOVD:
  1060  			size = 8
  1061  		}
  1062  
  1063  		// doubleword aligned clears should be kept doubleword
  1064  		// aligned
  1065  		if (size == 8 && align != 8) || (size != 8 && align == 8) {
  1066  			clear = nil
  1067  		}
  1068  
  1069  		if clear != nil &&
  1070  			clear.To.Reg == p.To.Reg &&
  1071  			clear.To.Name == p.To.Name &&
  1072  			clear.To.Node == p.To.Node &&
  1073  			clear.To.Sym == p.To.Sym {
  1074  
  1075  			min := clear.To.Offset
  1076  			max := clear.To.Offset + clear.From.Offset
  1077  
  1078  			// previous clear is already clearing this region
  1079  			if min <= p.To.Offset && max >= p.To.Offset+size {
  1080  				excise(r)
  1081  				n++
  1082  				continue
  1083  			}
  1084  
  1085  			// merge forwards
  1086  			if max == p.To.Offset {
  1087  				clear.From.Offset += size
  1088  				excise(r)
  1089  				n++
  1090  				continue
  1091  			}
  1092  
  1093  			// merge backwards
  1094  			if min-size == p.To.Offset {
  1095  				clear.From.Offset += size
  1096  				clear.To.Offset -= size
  1097  				excise(r)
  1098  				n++
  1099  				continue
  1100  			}
  1101  		}
  1102  
  1103  		// transform into clear
  1104  		p.From.Type = obj.TYPE_CONST
  1105  		p.From.Offset = size
  1106  		p.From.Reg = 0
  1107  		p.As = s390x.ACLEAR
  1108  		clear = p
  1109  		align = size
  1110  	}
  1111  	return n
  1112  }
  1113  
  1114  // fuseMultiple merges memory loads and stores into load multiple and
  1115  // store multiple operations.
  1116  //
  1117  // Looks for this pattern (sequence of loads or stores):
  1118  // 	MOVD	R1, 0(R15)
  1119  //	MOVD	R2, 8(R15)
  1120  //	MOVD	R3, 16(R15)
  1121  // Replaces with:
  1122  //	STMG	R1, R3, 0(R15)
  1123  func fuseMultiple(r *gc.Flow) int {
  1124  	n := 0
  1125  	var fused *obj.Prog
  1126  	for ; r != nil; r = r.Link {
  1127  		// If there is a branch into the instruction stream then
  1128  		// we can't fuse into previous instructions.
  1129  		if gc.Uniqp(r) == nil {
  1130  			fused = nil
  1131  		}
  1132  
  1133  		p := r.Prog
  1134  
  1135  		isStore := isGPR(&p.From) && isBDMem(&p.To)
  1136  		isLoad := isGPR(&p.To) && isBDMem(&p.From)
  1137  
  1138  		// are we a candidate?
  1139  		size := int64(0)
  1140  		switch p.As {
  1141  		default:
  1142  			fused = nil
  1143  			continue
  1144  		case obj.ANOP:
  1145  			// skip over nops
  1146  			continue
  1147  		case s390x.AMOVW, s390x.AMOVWZ:
  1148  			size = 4
  1149  			// TODO(mundaym): 32-bit load multiple is currently not supported
  1150  			// as it requires sign/zero extension.
  1151  			if !isStore {
  1152  				fused = nil
  1153  				continue
  1154  			}
  1155  		case s390x.AMOVD:
  1156  			size = 8
  1157  			if !isLoad && !isStore {
  1158  				fused = nil
  1159  				continue
  1160  			}
  1161  		}
  1162  
  1163  		// If we merge two loads/stores with different source/destination Nodes
  1164  		// then we will lose a reference the second Node which means that the
  1165  		// compiler might mark the Node as unused and free its slot on the stack.
  1166  		// TODO(mundaym): allow this by adding a dummy reference to the Node.
  1167  		if fused == nil ||
  1168  			fused.From.Node != p.From.Node ||
  1169  			fused.From.Type != p.From.Type ||
  1170  			fused.To.Node != p.To.Node ||
  1171  			fused.To.Type != p.To.Type {
  1172  			fused = p
  1173  			continue
  1174  		}
  1175  
  1176  		// check two addresses
  1177  		ca := func(a, b *obj.Addr, offset int64) bool {
  1178  			return a.Reg == b.Reg && a.Offset+offset == b.Offset &&
  1179  				a.Sym == b.Sym && a.Name == b.Name
  1180  		}
  1181  
  1182  		switch fused.As {
  1183  		default:
  1184  			fused = p
  1185  		case s390x.AMOVW, s390x.AMOVWZ:
  1186  			if size == 4 && fused.From.Reg+1 == p.From.Reg && ca(&fused.To, &p.To, 4) {
  1187  				fused.As = s390x.ASTMY
  1188  				fused.Reg = p.From.Reg
  1189  				excise(r)
  1190  				n++
  1191  			} else {
  1192  				fused = p
  1193  			}
  1194  		case s390x.AMOVD:
  1195  			if size == 8 && fused.From.Reg+1 == p.From.Reg && ca(&fused.To, &p.To, 8) {
  1196  				fused.As = s390x.ASTMG
  1197  				fused.Reg = p.From.Reg
  1198  				excise(r)
  1199  				n++
  1200  			} else if size == 8 && fused.To.Reg+1 == p.To.Reg && ca(&fused.From, &p.From, 8) {
  1201  				fused.As = s390x.ALMG
  1202  				fused.Reg = fused.To.Reg
  1203  				fused.To.Reg = p.To.Reg
  1204  				excise(r)
  1205  				n++
  1206  			} else {
  1207  				fused = p
  1208  			}
  1209  		case s390x.ASTMG, s390x.ASTMY:
  1210  			if (fused.As == s390x.ASTMY && size != 4) ||
  1211  				(fused.As == s390x.ASTMG && size != 8) {
  1212  				fused = p
  1213  				continue
  1214  			}
  1215  			offset := size * int64(fused.Reg-fused.From.Reg+1)
  1216  			if fused.Reg+1 == p.From.Reg && ca(&fused.To, &p.To, offset) {
  1217  				fused.Reg = p.From.Reg
  1218  				excise(r)
  1219  				n++
  1220  			} else {
  1221  				fused = p
  1222  			}
  1223  		case s390x.ALMG:
  1224  			offset := 8 * int64(fused.To.Reg-fused.Reg+1)
  1225  			if size == 8 && fused.To.Reg+1 == p.To.Reg && ca(&fused.From, &p.From, offset) {
  1226  				fused.To.Reg = p.To.Reg
  1227  				excise(r)
  1228  				n++
  1229  			} else {
  1230  				fused = p
  1231  			}
  1232  		}
  1233  	}
  1234  	return n
  1235  }
  1236  
  1237  // simplifyOps looks for side-effect free ops that can be removed or
  1238  // replaced with moves.
  1239  //
  1240  // For example:
  1241  // 	XOR $0, R1 => NOP
  1242  //	ADD $0, R1, R2 => MOVD R1, R2
  1243  func simplifyOps(r *gc.Flow) int {
  1244  	n := 0
  1245  	for ; r != nil; r = r.Link {
  1246  		p := r.Prog
  1247  
  1248  		// if the target is R0 then this is a required NOP
  1249  		if isGPR(&p.To) && p.To.Reg == s390x.REGZERO {
  1250  			continue
  1251  		}
  1252  
  1253  		switch p.As {
  1254  		case s390x.AADD, s390x.ASUB,
  1255  			s390x.AOR, s390x.AXOR,
  1256  			s390x.ASLW, s390x.ASRW, s390x.ASRAW,
  1257  			s390x.ASLD, s390x.ASRD, s390x.ASRAD,
  1258  			s390x.ARLL, s390x.ARLLG:
  1259  			if isZero(&p.From) && isGPR(&p.To) {
  1260  				if p.Reg == 0 || p.Reg == p.To.Reg {
  1261  					excise(r)
  1262  					n++
  1263  				} else {
  1264  					p.As = s390x.AMOVD
  1265  					p.From.Type = obj.TYPE_REG
  1266  					p.From.Reg = p.Reg
  1267  					p.Reg = 0
  1268  				}
  1269  			}
  1270  		case s390x.AMULLW, s390x.AAND:
  1271  			if isZero(&p.From) && isGPR(&p.To) {
  1272  				p.As = s390x.AMOVD
  1273  				p.From.Type = obj.TYPE_REG
  1274  				p.From.Reg = s390x.REGZERO
  1275  				p.Reg = 0
  1276  			}
  1277  		}
  1278  	}
  1279  	return n
  1280  }
  1281  
  1282  // fuseOpMoves looks for moves following 2-operand operations and trys to merge them into
  1283  // a 3-operand operation.
  1284  //
  1285  // For example:
  1286  //	ADD R1, R2
  1287  //	MOVD R2, R3
  1288  // might become
  1289  //	ADD R1, R2, R3
  1290  func fuseOpMoves(r *gc.Flow) int {
  1291  	n := 0
  1292  	for ; r != nil; r = r.Link {
  1293  		p := r.Prog
  1294  		switch p.As {
  1295  		case s390x.AADD:
  1296  		case s390x.ASUB:
  1297  			if isConst(&p.From) && int64(int16(p.From.Offset)) != p.From.Offset {
  1298  				continue
  1299  			}
  1300  		case s390x.ASLW,
  1301  			s390x.ASRW,
  1302  			s390x.ASRAW,
  1303  			s390x.ASLD,
  1304  			s390x.ASRD,
  1305  			s390x.ASRAD,
  1306  			s390x.ARLL,
  1307  			s390x.ARLLG:
  1308  			// ok - p.From will be a reg or a constant
  1309  		case s390x.AOR,
  1310  			s390x.AORN,
  1311  			s390x.AAND,
  1312  			s390x.AANDN,
  1313  			s390x.ANAND,
  1314  			s390x.ANOR,
  1315  			s390x.AXOR,
  1316  			s390x.AMULLW,
  1317  			s390x.AMULLD:
  1318  			if isConst(&p.From) {
  1319  				// these instructions can either use 3 register form
  1320  				// or have an immediate but not both
  1321  				continue
  1322  			}
  1323  		default:
  1324  			continue
  1325  		}
  1326  
  1327  		if p.Reg != 0 && p.Reg != p.To.Reg {
  1328  			continue
  1329  		}
  1330  
  1331  		var move *gc.Flow
  1332  		rr := gc.Uniqs(r)
  1333  		for {
  1334  			if rr == nil || gc.Uniqp(rr) == nil || rr == r {
  1335  				break
  1336  			}
  1337  			pp := rr.Prog
  1338  			switch copyu(pp, &p.To, nil) {
  1339  			case _None:
  1340  				rr = gc.Uniqs(rr)
  1341  				continue
  1342  			case _Read:
  1343  				if move == nil && pp.As == s390x.AMOVD && isGPR(&pp.From) && isGPR(&pp.To) {
  1344  					move = rr
  1345  					rr = gc.Uniqs(rr)
  1346  					continue
  1347  				}
  1348  			case _Write:
  1349  				if move == nil {
  1350  					// dead code
  1351  					excise(r)
  1352  					n++
  1353  				} else {
  1354  					for prev := gc.Uniqp(move); prev != r; prev = gc.Uniqp(prev) {
  1355  						if copyu(prev.Prog, &move.Prog.To, nil) != 0 {
  1356  							move = nil
  1357  							break
  1358  						}
  1359  					}
  1360  					if move == nil {
  1361  						break
  1362  					}
  1363  					p.Reg, p.To.Reg = p.To.Reg, move.Prog.To.Reg
  1364  					excise(move)
  1365  					n++
  1366  
  1367  					// clean up
  1368  					if p.From.Reg == p.To.Reg && isCommutative(p.As) {
  1369  						p.From.Reg, p.Reg = p.Reg, 0
  1370  					}
  1371  					if p.To.Reg == p.Reg {
  1372  						p.Reg = 0
  1373  					}
  1374  					// we could try again if p has become a 2-operand op
  1375  					// but in testing nothing extra was extracted
  1376  				}
  1377  			}
  1378  			break
  1379  		}
  1380  	}
  1381  	return n
  1382  }
  1383  
  1384  // isCommutative returns true if the order of input operands
  1385  // does not affect the result. For example:
  1386  //	x + y == y + x so ADD is commutative
  1387  //	x ^ y == y ^ x so XOR is commutative
  1388  func isCommutative(as obj.As) bool {
  1389  	switch as {
  1390  	case s390x.AADD,
  1391  		s390x.AOR,
  1392  		s390x.AAND,
  1393  		s390x.AXOR,
  1394  		s390x.AMULLW,
  1395  		s390x.AMULLD:
  1396  		return true
  1397  	}
  1398  	return false
  1399  }
  1400  
  1401  // applyCast applies the cast implied by the given move
  1402  // instruction to v and returns the result.
  1403  func applyCast(cast obj.As, v int64) int64 {
  1404  	switch cast {
  1405  	case s390x.AMOVWZ:
  1406  		return int64(uint32(v))
  1407  	case s390x.AMOVHZ:
  1408  		return int64(uint16(v))
  1409  	case s390x.AMOVBZ:
  1410  		return int64(uint8(v))
  1411  	case s390x.AMOVW:
  1412  		return int64(int32(v))
  1413  	case s390x.AMOVH:
  1414  		return int64(int16(v))
  1415  	case s390x.AMOVB:
  1416  		return int64(int8(v))
  1417  	}
  1418  	return v
  1419  }
  1420  
  1421  // constantPropagation removes redundant constant copies.
  1422  func constantPropagation(r *gc.Flow) int {
  1423  	n := 0
  1424  	// find MOV $con,R followed by
  1425  	// another MOV $con,R without
  1426  	// setting R in the interim
  1427  	for ; r != nil; r = r.Link {
  1428  		p := r.Prog
  1429  		if isMove(p) {
  1430  			if !isReg(&p.To) {
  1431  				continue
  1432  			}
  1433  			if !isConst(&p.From) {
  1434  				continue
  1435  			}
  1436  		} else {
  1437  			continue
  1438  		}
  1439  
  1440  		rr := r
  1441  		for {
  1442  			rr = gc.Uniqs(rr)
  1443  			if rr == nil || rr == r {
  1444  				break
  1445  			}
  1446  			if gc.Uniqp(rr) == nil {
  1447  				break
  1448  			}
  1449  
  1450  			pp := rr.Prog
  1451  			t := copyu(pp, &p.To, nil)
  1452  			switch t {
  1453  			case _None:
  1454  				continue
  1455  			case _Read:
  1456  				if !isGPR(&pp.From) || !isMove(pp) {
  1457  					continue
  1458  				}
  1459  				if p.From.Type == obj.TYPE_CONST {
  1460  					v := applyCast(p.As, p.From.Offset)
  1461  					if isGPR(&pp.To) {
  1462  						if int64(int32(v)) == v || ((v>>32)<<32) == v {
  1463  							pp.From.Reg = 0
  1464  							pp.From.Offset = v
  1465  							pp.From.Type = obj.TYPE_CONST
  1466  							n++
  1467  						}
  1468  					} else if int64(int16(v)) == v {
  1469  						pp.From.Reg = 0
  1470  						pp.From.Offset = v
  1471  						pp.From.Type = obj.TYPE_CONST
  1472  						n++
  1473  					}
  1474  				}
  1475  				continue
  1476  			case _Write:
  1477  				if p.As != pp.As || p.From.Type != pp.From.Type {
  1478  					break
  1479  				}
  1480  				if p.From.Type == obj.TYPE_CONST && p.From.Offset == pp.From.Offset {
  1481  					excise(rr)
  1482  					n++
  1483  					continue
  1484  				} else if p.From.Type == obj.TYPE_FCONST {
  1485  					if p.From.Val.(float64) == pp.From.Val.(float64) {
  1486  						excise(rr)
  1487  						n++
  1488  						continue
  1489  					}
  1490  				}
  1491  			}
  1492  			break
  1493  		}
  1494  	}
  1495  	return n
  1496  }
  1497  
  1498  // copyPropagation tries to eliminate register-to-register moves.
  1499  func copyPropagation(r *gc.Flow) int {
  1500  	n := 0
  1501  	for ; r != nil; r = r.Link {
  1502  		p := r.Prog
  1503  		if isMove(p) && isReg(&p.To) {
  1504  			// Convert uses to $0 to uses of R0 and
  1505  			// propagate R0
  1506  			if isGPR(&p.To) && isZero(&p.From) {
  1507  				p.From.Type = obj.TYPE_REG
  1508  				p.From.Reg = s390x.REGZERO
  1509  			}
  1510  
  1511  			// Try to eliminate reg->reg moves
  1512  			if isGPR(&p.From) || isFPR(&p.From) {
  1513  				if copyprop(r) || (subprop(r) && copyprop(r)) {
  1514  					excise(r)
  1515  					n++
  1516  				}
  1517  			}
  1518  		}
  1519  	}
  1520  	return n
  1521  }
  1522  
  1523  // loadPipelining pushes any load from memory as early as possible.
  1524  func loadPipelining(r *gc.Flow) int {
  1525  	for ; r != nil; r = r.Link {
  1526  		p := r.Prog
  1527  		if isLoad(p) {
  1528  			pushback(r)
  1529  		}
  1530  	}
  1531  	return 0
  1532  }
  1533  
  1534  // fuseCompareBranch finds comparisons followed by a branch and converts
  1535  // them into a compare-and-branch instruction (which avoid setting the
  1536  // condition code).
  1537  func fuseCompareBranch(r *gc.Flow) int {
  1538  	n := 0
  1539  	for ; r != nil; r = r.Link {
  1540  		p := r.Prog
  1541  		r1 := gc.Uniqs(r)
  1542  		if r1 == nil {
  1543  			continue
  1544  		}
  1545  		p1 := r1.Prog
  1546  
  1547  		var ins obj.As
  1548  		switch p.As {
  1549  		case s390x.ACMP:
  1550  			switch p1.As {
  1551  			case s390x.ABCL, s390x.ABC:
  1552  				continue
  1553  			case s390x.ABEQ:
  1554  				ins = s390x.ACMPBEQ
  1555  			case s390x.ABGE:
  1556  				ins = s390x.ACMPBGE
  1557  			case s390x.ABGT:
  1558  				ins = s390x.ACMPBGT
  1559  			case s390x.ABLE:
  1560  				ins = s390x.ACMPBLE
  1561  			case s390x.ABLT:
  1562  				ins = s390x.ACMPBLT
  1563  			case s390x.ABNE:
  1564  				ins = s390x.ACMPBNE
  1565  			default:
  1566  				continue
  1567  			}
  1568  
  1569  		case s390x.ACMPU:
  1570  			switch p1.As {
  1571  			case s390x.ABCL, s390x.ABC:
  1572  				continue
  1573  			case s390x.ABEQ:
  1574  				ins = s390x.ACMPUBEQ
  1575  			case s390x.ABGE:
  1576  				ins = s390x.ACMPUBGE
  1577  			case s390x.ABGT:
  1578  				ins = s390x.ACMPUBGT
  1579  			case s390x.ABLE:
  1580  				ins = s390x.ACMPUBLE
  1581  			case s390x.ABLT:
  1582  				ins = s390x.ACMPUBLT
  1583  			case s390x.ABNE:
  1584  				ins = s390x.ACMPUBNE
  1585  			default:
  1586  				continue
  1587  			}
  1588  
  1589  		case s390x.ACMPW, s390x.ACMPWU:
  1590  			continue
  1591  
  1592  		default:
  1593  			continue
  1594  		}
  1595  
  1596  		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
  1597  			fmt.Printf("cnb %v; %v  ", p, p1)
  1598  		}
  1599  
  1600  		if p1.To.Sym != nil {
  1601  			continue
  1602  		}
  1603  
  1604  		if p.To.Type == obj.TYPE_REG {
  1605  			p1.As = ins
  1606  			p1.From = p.From
  1607  			p1.Reg = p.To.Reg
  1608  			p1.From3 = nil
  1609  		} else if p.To.Type == obj.TYPE_CONST {
  1610  			switch p.As {
  1611  			case s390x.ACMP, s390x.ACMPW:
  1612  				if (p.To.Offset < -(1 << 7)) || (p.To.Offset >= ((1 << 7) - 1)) {
  1613  					continue
  1614  				}
  1615  			case s390x.ACMPU, s390x.ACMPWU:
  1616  				if p.To.Offset >= (1 << 8) {
  1617  					continue
  1618  				}
  1619  			default:
  1620  			}
  1621  			p1.As = ins
  1622  			p1.From = p.From
  1623  			p1.Reg = 0
  1624  			p1.From3 = new(obj.Addr)
  1625  			*(p1.From3) = p.To
  1626  		} else {
  1627  			continue
  1628  		}
  1629  
  1630  		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
  1631  			fmt.Printf("%v\n", p1)
  1632  		}
  1633  		excise(r)
  1634  		n++
  1635  	}
  1636  	return n
  1637  }
  1638  
  1639  // deadCodeElimination removes writes to registers which are written
  1640  // to again before they are next read.
  1641  func deadCodeElimination(r *gc.Flow) int {
  1642  	n := 0
  1643  	for ; r != nil; r = r.Link {
  1644  		p := r.Prog
  1645  		// Currently there are no instructions which write to multiple
  1646  		// registers in copyu. This check will need to change if there
  1647  		// ever are.
  1648  		if !(isGPR(&p.To) || isFPR(&p.To)) || copyu(p, &p.To, nil) != _Write {
  1649  			continue
  1650  		}
  1651  		for rr := gc.Uniqs(r); rr != nil; rr = gc.Uniqs(rr) {
  1652  			t := copyu(rr.Prog, &p.To, nil)
  1653  			if t == _None {
  1654  				continue
  1655  			}
  1656  			if t == _Write {
  1657  				excise(r)
  1658  				n++
  1659  			}
  1660  			break
  1661  		}
  1662  	}
  1663  	return n
  1664  }