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

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package x86
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  
    11  	"cmd/compile/internal/gc"
    12  	"cmd/compile/internal/ssa"
    13  	"cmd/internal/obj"
    14  	"cmd/internal/obj/x86"
    15  )
    16  
    17  // Smallest possible faulting page at address zero.
    18  const minZeroPage = 4096
    19  
    20  // ssaRegToReg maps ssa register numbers to obj register numbers.
    21  var ssaRegToReg = []int16{
    22  	x86.REG_AX,
    23  	x86.REG_CX,
    24  	x86.REG_DX,
    25  	x86.REG_BX,
    26  	x86.REG_SP,
    27  	x86.REG_BP,
    28  	x86.REG_SI,
    29  	x86.REG_DI,
    30  	x86.REG_X0,
    31  	x86.REG_X1,
    32  	x86.REG_X2,
    33  	x86.REG_X3,
    34  	x86.REG_X4,
    35  	x86.REG_X5,
    36  	x86.REG_X6,
    37  	x86.REG_X7,
    38  	0, // SB isn't a real register.  We fill an Addr.Reg field with 0 in this case.
    39  }
    40  
    41  // markMoves marks any MOVXconst ops that need to avoid clobbering flags.
    42  func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
    43  	flive := b.FlagsLiveAtEnd
    44  	if b.Control != nil && b.Control.Type.IsFlags() {
    45  		flive = true
    46  	}
    47  	for i := len(b.Values) - 1; i >= 0; i-- {
    48  		v := b.Values[i]
    49  		if flive && v.Op == ssa.Op386MOVLconst {
    50  			// The "mark" is any non-nil Aux value.
    51  			v.Aux = v
    52  		}
    53  		if v.Type.IsFlags() {
    54  			flive = false
    55  		}
    56  		for _, a := range v.Args {
    57  			if a.Type.IsFlags() {
    58  				flive = true
    59  			}
    60  		}
    61  	}
    62  }
    63  
    64  // loadByType returns the load instruction of the given type.
    65  func loadByType(t ssa.Type) obj.As {
    66  	// Avoid partial register write
    67  	if !t.IsFloat() && t.Size() <= 2 {
    68  		if t.Size() == 1 {
    69  			return x86.AMOVBLZX
    70  		} else {
    71  			return x86.AMOVWLZX
    72  		}
    73  	}
    74  	// Otherwise, there's no difference between load and store opcodes.
    75  	return storeByType(t)
    76  }
    77  
    78  // storeByType returns the store instruction of the given type.
    79  func storeByType(t ssa.Type) obj.As {
    80  	width := t.Size()
    81  	if t.IsFloat() {
    82  		switch width {
    83  		case 4:
    84  			return x86.AMOVSS
    85  		case 8:
    86  			return x86.AMOVSD
    87  		}
    88  	} else {
    89  		switch width {
    90  		case 1:
    91  			return x86.AMOVB
    92  		case 2:
    93  			return x86.AMOVW
    94  		case 4:
    95  			return x86.AMOVL
    96  		}
    97  	}
    98  	panic("bad store type")
    99  }
   100  
   101  // moveByType returns the reg->reg move instruction of the given type.
   102  func moveByType(t ssa.Type) obj.As {
   103  	if t.IsFloat() {
   104  		switch t.Size() {
   105  		case 4:
   106  			return x86.AMOVSS
   107  		case 8:
   108  			return x86.AMOVSD
   109  		default:
   110  			panic(fmt.Sprintf("bad float register width %d:%s", t.Size(), t))
   111  		}
   112  	} else {
   113  		switch t.Size() {
   114  		case 1:
   115  			// Avoids partial register write
   116  			return x86.AMOVL
   117  		case 2:
   118  			return x86.AMOVL
   119  		case 4:
   120  			return x86.AMOVL
   121  		default:
   122  			panic(fmt.Sprintf("bad int register width %d:%s", t.Size(), t))
   123  		}
   124  	}
   125  }
   126  
   127  // opregreg emits instructions for
   128  //     dest := dest(To) op src(From)
   129  // and also returns the created obj.Prog so it
   130  // may be further adjusted (offset, scale, etc).
   131  func opregreg(op obj.As, dest, src int16) *obj.Prog {
   132  	p := gc.Prog(op)
   133  	p.From.Type = obj.TYPE_REG
   134  	p.To.Type = obj.TYPE_REG
   135  	p.To.Reg = dest
   136  	p.From.Reg = src
   137  	return p
   138  }
   139  
   140  func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
   141  	s.SetLineno(v.Line)
   142  
   143  	if gc.Thearch.Use387 {
   144  		if ssaGenValue387(s, v) {
   145  			return // v was handled by 387 generation.
   146  		}
   147  	}
   148  
   149  	switch v.Op {
   150  	case ssa.Op386ADDL:
   151  		r := gc.SSARegNum(v)
   152  		r1 := gc.SSARegNum(v.Args[0])
   153  		r2 := gc.SSARegNum(v.Args[1])
   154  		switch {
   155  		case r == r1:
   156  			p := gc.Prog(v.Op.Asm())
   157  			p.From.Type = obj.TYPE_REG
   158  			p.From.Reg = r2
   159  			p.To.Type = obj.TYPE_REG
   160  			p.To.Reg = r
   161  		case r == r2:
   162  			p := gc.Prog(v.Op.Asm())
   163  			p.From.Type = obj.TYPE_REG
   164  			p.From.Reg = r1
   165  			p.To.Type = obj.TYPE_REG
   166  			p.To.Reg = r
   167  		default:
   168  			p := gc.Prog(x86.ALEAL)
   169  			p.From.Type = obj.TYPE_MEM
   170  			p.From.Reg = r1
   171  			p.From.Scale = 1
   172  			p.From.Index = r2
   173  			p.To.Type = obj.TYPE_REG
   174  			p.To.Reg = r
   175  		}
   176  
   177  	// 2-address opcode arithmetic
   178  	case ssa.Op386SUBL,
   179  		ssa.Op386MULL,
   180  		ssa.Op386ANDL,
   181  		ssa.Op386ORL,
   182  		ssa.Op386XORL,
   183  		ssa.Op386SHLL,
   184  		ssa.Op386SHRL, ssa.Op386SHRW, ssa.Op386SHRB,
   185  		ssa.Op386SARL, ssa.Op386SARW, ssa.Op386SARB,
   186  		ssa.Op386ADDSS, ssa.Op386ADDSD, ssa.Op386SUBSS, ssa.Op386SUBSD,
   187  		ssa.Op386MULSS, ssa.Op386MULSD, ssa.Op386DIVSS, ssa.Op386DIVSD,
   188  		ssa.Op386PXOR,
   189  		ssa.Op386ADCL,
   190  		ssa.Op386SBBL:
   191  		r := gc.SSARegNum(v)
   192  		if r != gc.SSARegNum(v.Args[0]) {
   193  			v.Fatalf("input[0] and output not in same register %s", v.LongString())
   194  		}
   195  		opregreg(v.Op.Asm(), r, gc.SSARegNum(v.Args[1]))
   196  
   197  	case ssa.Op386ADDLcarry, ssa.Op386SUBLcarry:
   198  		// output 0 is carry/borrow, output 1 is the low 32 bits.
   199  		r := gc.SSARegNum0(v)
   200  		if r != gc.SSARegNum(v.Args[0]) {
   201  			v.Fatalf("input[0] and output[0] not in same register %s", v.LongString())
   202  		}
   203  		opregreg(v.Op.Asm(), r, gc.SSARegNum(v.Args[1]))
   204  
   205  	case ssa.Op386ADDLconstcarry, ssa.Op386SUBLconstcarry:
   206  		// output 0 is carry/borrow, output 1 is the low 32 bits.
   207  		r := gc.SSARegNum0(v)
   208  		if r != gc.SSARegNum(v.Args[0]) {
   209  			v.Fatalf("input[0] and output[0] not in same register %s", v.LongString())
   210  		}
   211  		p := gc.Prog(v.Op.Asm())
   212  		p.From.Type = obj.TYPE_CONST
   213  		p.From.Offset = v.AuxInt
   214  		p.To.Type = obj.TYPE_REG
   215  		p.To.Reg = r
   216  
   217  	case ssa.Op386DIVL, ssa.Op386DIVW,
   218  		ssa.Op386DIVLU, ssa.Op386DIVWU,
   219  		ssa.Op386MODL, ssa.Op386MODW,
   220  		ssa.Op386MODLU, ssa.Op386MODWU:
   221  
   222  		// Arg[0] is already in AX as it's the only register we allow
   223  		// and AX is the only output
   224  		x := gc.SSARegNum(v.Args[1])
   225  
   226  		// CPU faults upon signed overflow, which occurs when most
   227  		// negative int is divided by -1.
   228  		var j *obj.Prog
   229  		if v.Op == ssa.Op386DIVL || v.Op == ssa.Op386DIVW ||
   230  			v.Op == ssa.Op386MODL || v.Op == ssa.Op386MODW {
   231  
   232  			var c *obj.Prog
   233  			switch v.Op {
   234  			case ssa.Op386DIVL, ssa.Op386MODL:
   235  				c = gc.Prog(x86.ACMPL)
   236  				j = gc.Prog(x86.AJEQ)
   237  				gc.Prog(x86.ACDQ) //TODO: fix
   238  
   239  			case ssa.Op386DIVW, ssa.Op386MODW:
   240  				c = gc.Prog(x86.ACMPW)
   241  				j = gc.Prog(x86.AJEQ)
   242  				gc.Prog(x86.ACWD)
   243  			}
   244  			c.From.Type = obj.TYPE_REG
   245  			c.From.Reg = x
   246  			c.To.Type = obj.TYPE_CONST
   247  			c.To.Offset = -1
   248  
   249  			j.To.Type = obj.TYPE_BRANCH
   250  		}
   251  
   252  		// for unsigned ints, we sign extend by setting DX = 0
   253  		// signed ints were sign extended above
   254  		if v.Op == ssa.Op386DIVLU || v.Op == ssa.Op386MODLU ||
   255  			v.Op == ssa.Op386DIVWU || v.Op == ssa.Op386MODWU {
   256  			c := gc.Prog(x86.AXORL)
   257  			c.From.Type = obj.TYPE_REG
   258  			c.From.Reg = x86.REG_DX
   259  			c.To.Type = obj.TYPE_REG
   260  			c.To.Reg = x86.REG_DX
   261  		}
   262  
   263  		p := gc.Prog(v.Op.Asm())
   264  		p.From.Type = obj.TYPE_REG
   265  		p.From.Reg = x
   266  
   267  		// signed division, rest of the check for -1 case
   268  		if j != nil {
   269  			j2 := gc.Prog(obj.AJMP)
   270  			j2.To.Type = obj.TYPE_BRANCH
   271  
   272  			var n *obj.Prog
   273  			if v.Op == ssa.Op386DIVL || v.Op == ssa.Op386DIVW {
   274  				// n * -1 = -n
   275  				n = gc.Prog(x86.ANEGL)
   276  				n.To.Type = obj.TYPE_REG
   277  				n.To.Reg = x86.REG_AX
   278  			} else {
   279  				// n % -1 == 0
   280  				n = gc.Prog(x86.AXORL)
   281  				n.From.Type = obj.TYPE_REG
   282  				n.From.Reg = x86.REG_DX
   283  				n.To.Type = obj.TYPE_REG
   284  				n.To.Reg = x86.REG_DX
   285  			}
   286  
   287  			j.To.Val = n
   288  			j2.To.Val = s.Pc()
   289  		}
   290  
   291  	case ssa.Op386HMULL, ssa.Op386HMULW, ssa.Op386HMULB,
   292  		ssa.Op386HMULLU, ssa.Op386HMULWU, ssa.Op386HMULBU:
   293  		// the frontend rewrites constant division by 8/16/32 bit integers into
   294  		// HMUL by a constant
   295  		// SSA rewrites generate the 64 bit versions
   296  
   297  		// Arg[0] is already in AX as it's the only register we allow
   298  		// and DX is the only output we care about (the high bits)
   299  		p := gc.Prog(v.Op.Asm())
   300  		p.From.Type = obj.TYPE_REG
   301  		p.From.Reg = gc.SSARegNum(v.Args[1])
   302  
   303  		// IMULB puts the high portion in AH instead of DL,
   304  		// so move it to DL for consistency
   305  		if v.Type.Size() == 1 {
   306  			m := gc.Prog(x86.AMOVB)
   307  			m.From.Type = obj.TYPE_REG
   308  			m.From.Reg = x86.REG_AH
   309  			m.To.Type = obj.TYPE_REG
   310  			m.To.Reg = x86.REG_DX
   311  		}
   312  
   313  	case ssa.Op386MULLQU:
   314  		// AX * args[1], high 32 bits in DX (result[0]), low 32 bits in AX (result[1]).
   315  		p := gc.Prog(v.Op.Asm())
   316  		p.From.Type = obj.TYPE_REG
   317  		p.From.Reg = gc.SSARegNum(v.Args[1])
   318  
   319  	case ssa.Op386ADDLconst:
   320  		r := gc.SSARegNum(v)
   321  		a := gc.SSARegNum(v.Args[0])
   322  		if r == a {
   323  			if v.AuxInt == 1 {
   324  				p := gc.Prog(x86.AINCL)
   325  				p.To.Type = obj.TYPE_REG
   326  				p.To.Reg = r
   327  				return
   328  			}
   329  			if v.AuxInt == -1 {
   330  				p := gc.Prog(x86.ADECL)
   331  				p.To.Type = obj.TYPE_REG
   332  				p.To.Reg = r
   333  				return
   334  			}
   335  			p := gc.Prog(v.Op.Asm())
   336  			p.From.Type = obj.TYPE_CONST
   337  			p.From.Offset = v.AuxInt
   338  			p.To.Type = obj.TYPE_REG
   339  			p.To.Reg = r
   340  			return
   341  		}
   342  		p := gc.Prog(x86.ALEAL)
   343  		p.From.Type = obj.TYPE_MEM
   344  		p.From.Reg = a
   345  		p.From.Offset = v.AuxInt
   346  		p.To.Type = obj.TYPE_REG
   347  		p.To.Reg = r
   348  
   349  	case ssa.Op386MULLconst:
   350  		r := gc.SSARegNum(v)
   351  		if r != gc.SSARegNum(v.Args[0]) {
   352  			v.Fatalf("input[0] and output not in same register %s", v.LongString())
   353  		}
   354  		p := gc.Prog(v.Op.Asm())
   355  		p.From.Type = obj.TYPE_CONST
   356  		p.From.Offset = v.AuxInt
   357  		p.To.Type = obj.TYPE_REG
   358  		p.To.Reg = r
   359  		// TODO: Teach doasm to compile the three-address multiply imul $c, r1, r2
   360  		// then we don't need to use resultInArg0 for these ops.
   361  		//p.From3 = new(obj.Addr)
   362  		//p.From3.Type = obj.TYPE_REG
   363  		//p.From3.Reg = gc.SSARegNum(v.Args[0])
   364  
   365  	case ssa.Op386SUBLconst,
   366  		ssa.Op386ADCLconst,
   367  		ssa.Op386SBBLconst,
   368  		ssa.Op386ANDLconst,
   369  		ssa.Op386ORLconst,
   370  		ssa.Op386XORLconst,
   371  		ssa.Op386SHLLconst,
   372  		ssa.Op386SHRLconst, ssa.Op386SHRWconst, ssa.Op386SHRBconst,
   373  		ssa.Op386SARLconst, ssa.Op386SARWconst, ssa.Op386SARBconst,
   374  		ssa.Op386ROLLconst, ssa.Op386ROLWconst, ssa.Op386ROLBconst:
   375  		r := gc.SSARegNum(v)
   376  		if r != gc.SSARegNum(v.Args[0]) {
   377  			v.Fatalf("input[0] and output not in same register %s", v.LongString())
   378  		}
   379  		p := gc.Prog(v.Op.Asm())
   380  		p.From.Type = obj.TYPE_CONST
   381  		p.From.Offset = v.AuxInt
   382  		p.To.Type = obj.TYPE_REG
   383  		p.To.Reg = r
   384  	case ssa.Op386SBBLcarrymask:
   385  		r := gc.SSARegNum(v)
   386  		p := gc.Prog(v.Op.Asm())
   387  		p.From.Type = obj.TYPE_REG
   388  		p.From.Reg = r
   389  		p.To.Type = obj.TYPE_REG
   390  		p.To.Reg = r
   391  	case ssa.Op386LEAL1, ssa.Op386LEAL2, ssa.Op386LEAL4, ssa.Op386LEAL8:
   392  		r := gc.SSARegNum(v.Args[0])
   393  		i := gc.SSARegNum(v.Args[1])
   394  		p := gc.Prog(x86.ALEAL)
   395  		switch v.Op {
   396  		case ssa.Op386LEAL1:
   397  			p.From.Scale = 1
   398  			if i == x86.REG_SP {
   399  				r, i = i, r
   400  			}
   401  		case ssa.Op386LEAL2:
   402  			p.From.Scale = 2
   403  		case ssa.Op386LEAL4:
   404  			p.From.Scale = 4
   405  		case ssa.Op386LEAL8:
   406  			p.From.Scale = 8
   407  		}
   408  		p.From.Type = obj.TYPE_MEM
   409  		p.From.Reg = r
   410  		p.From.Index = i
   411  		gc.AddAux(&p.From, v)
   412  		p.To.Type = obj.TYPE_REG
   413  		p.To.Reg = gc.SSARegNum(v)
   414  	case ssa.Op386LEAL:
   415  		p := gc.Prog(x86.ALEAL)
   416  		p.From.Type = obj.TYPE_MEM
   417  		p.From.Reg = gc.SSARegNum(v.Args[0])
   418  		gc.AddAux(&p.From, v)
   419  		p.To.Type = obj.TYPE_REG
   420  		p.To.Reg = gc.SSARegNum(v)
   421  	case ssa.Op386CMPL, ssa.Op386CMPW, ssa.Op386CMPB,
   422  		ssa.Op386TESTL, ssa.Op386TESTW, ssa.Op386TESTB:
   423  		opregreg(v.Op.Asm(), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v.Args[0]))
   424  	case ssa.Op386UCOMISS, ssa.Op386UCOMISD:
   425  		// Go assembler has swapped operands for UCOMISx relative to CMP,
   426  		// must account for that right here.
   427  		opregreg(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]))
   428  	case ssa.Op386CMPLconst, ssa.Op386CMPWconst, ssa.Op386CMPBconst:
   429  		p := gc.Prog(v.Op.Asm())
   430  		p.From.Type = obj.TYPE_REG
   431  		p.From.Reg = gc.SSARegNum(v.Args[0])
   432  		p.To.Type = obj.TYPE_CONST
   433  		p.To.Offset = v.AuxInt
   434  	case ssa.Op386TESTLconst, ssa.Op386TESTWconst, ssa.Op386TESTBconst:
   435  		p := gc.Prog(v.Op.Asm())
   436  		p.From.Type = obj.TYPE_CONST
   437  		p.From.Offset = v.AuxInt
   438  		p.To.Type = obj.TYPE_REG
   439  		p.To.Reg = gc.SSARegNum(v.Args[0])
   440  	case ssa.Op386MOVLconst:
   441  		x := gc.SSARegNum(v)
   442  		p := gc.Prog(v.Op.Asm())
   443  		p.From.Type = obj.TYPE_CONST
   444  		p.From.Offset = v.AuxInt
   445  		p.To.Type = obj.TYPE_REG
   446  		p.To.Reg = x
   447  		// If flags are live at this instruction, suppress the
   448  		// MOV $0,AX -> XOR AX,AX optimization.
   449  		if v.Aux != nil {
   450  			p.Mark |= x86.PRESERVEFLAGS
   451  		}
   452  	case ssa.Op386MOVSSconst, ssa.Op386MOVSDconst:
   453  		x := gc.SSARegNum(v)
   454  		p := gc.Prog(v.Op.Asm())
   455  		p.From.Type = obj.TYPE_FCONST
   456  		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
   457  		p.To.Type = obj.TYPE_REG
   458  		p.To.Reg = x
   459  	case ssa.Op386MOVSSconst1, ssa.Op386MOVSDconst1:
   460  		var literal string
   461  		if v.Op == ssa.Op386MOVSDconst1 {
   462  			literal = fmt.Sprintf("$f64.%016x", uint64(v.AuxInt))
   463  		} else {
   464  			literal = fmt.Sprintf("$f32.%08x", math.Float32bits(float32(math.Float64frombits(uint64(v.AuxInt)))))
   465  		}
   466  		p := gc.Prog(x86.ALEAL)
   467  		p.From.Type = obj.TYPE_MEM
   468  		p.From.Name = obj.NAME_EXTERN
   469  		p.From.Sym = obj.Linklookup(gc.Ctxt, literal, 0)
   470  		p.From.Sym.Local = true
   471  		p.To.Type = obj.TYPE_REG
   472  		p.To.Reg = gc.SSARegNum(v)
   473  	case ssa.Op386MOVSSconst2, ssa.Op386MOVSDconst2:
   474  		p := gc.Prog(v.Op.Asm())
   475  		p.From.Type = obj.TYPE_MEM
   476  		p.From.Reg = gc.SSARegNum(v.Args[0])
   477  		p.To.Type = obj.TYPE_REG
   478  		p.To.Reg = gc.SSARegNum(v)
   479  
   480  	case ssa.Op386MOVSSload, ssa.Op386MOVSDload, ssa.Op386MOVLload, ssa.Op386MOVWload, ssa.Op386MOVBload, ssa.Op386MOVBLSXload, ssa.Op386MOVWLSXload:
   481  		p := gc.Prog(v.Op.Asm())
   482  		p.From.Type = obj.TYPE_MEM
   483  		p.From.Reg = gc.SSARegNum(v.Args[0])
   484  		gc.AddAux(&p.From, v)
   485  		p.To.Type = obj.TYPE_REG
   486  		p.To.Reg = gc.SSARegNum(v)
   487  	case ssa.Op386MOVSDloadidx8:
   488  		p := gc.Prog(v.Op.Asm())
   489  		p.From.Type = obj.TYPE_MEM
   490  		p.From.Reg = gc.SSARegNum(v.Args[0])
   491  		gc.AddAux(&p.From, v)
   492  		p.From.Scale = 8
   493  		p.From.Index = gc.SSARegNum(v.Args[1])
   494  		p.To.Type = obj.TYPE_REG
   495  		p.To.Reg = gc.SSARegNum(v)
   496  	case ssa.Op386MOVLloadidx4, ssa.Op386MOVSSloadidx4:
   497  		p := gc.Prog(v.Op.Asm())
   498  		p.From.Type = obj.TYPE_MEM
   499  		p.From.Reg = gc.SSARegNum(v.Args[0])
   500  		gc.AddAux(&p.From, v)
   501  		p.From.Scale = 4
   502  		p.From.Index = gc.SSARegNum(v.Args[1])
   503  		p.To.Type = obj.TYPE_REG
   504  		p.To.Reg = gc.SSARegNum(v)
   505  	case ssa.Op386MOVWloadidx2:
   506  		p := gc.Prog(v.Op.Asm())
   507  		p.From.Type = obj.TYPE_MEM
   508  		p.From.Reg = gc.SSARegNum(v.Args[0])
   509  		gc.AddAux(&p.From, v)
   510  		p.From.Scale = 2
   511  		p.From.Index = gc.SSARegNum(v.Args[1])
   512  		p.To.Type = obj.TYPE_REG
   513  		p.To.Reg = gc.SSARegNum(v)
   514  	case ssa.Op386MOVBloadidx1, ssa.Op386MOVWloadidx1, ssa.Op386MOVLloadidx1, ssa.Op386MOVSSloadidx1, ssa.Op386MOVSDloadidx1:
   515  		r := gc.SSARegNum(v.Args[0])
   516  		i := gc.SSARegNum(v.Args[1])
   517  		if i == x86.REG_SP {
   518  			r, i = i, r
   519  		}
   520  		p := gc.Prog(v.Op.Asm())
   521  		p.From.Type = obj.TYPE_MEM
   522  		p.From.Reg = r
   523  		p.From.Scale = 1
   524  		p.From.Index = i
   525  		gc.AddAux(&p.From, v)
   526  		p.To.Type = obj.TYPE_REG
   527  		p.To.Reg = gc.SSARegNum(v)
   528  	case ssa.Op386MOVSSstore, ssa.Op386MOVSDstore, ssa.Op386MOVLstore, ssa.Op386MOVWstore, ssa.Op386MOVBstore:
   529  		p := gc.Prog(v.Op.Asm())
   530  		p.From.Type = obj.TYPE_REG
   531  		p.From.Reg = gc.SSARegNum(v.Args[1])
   532  		p.To.Type = obj.TYPE_MEM
   533  		p.To.Reg = gc.SSARegNum(v.Args[0])
   534  		gc.AddAux(&p.To, v)
   535  	case ssa.Op386MOVSDstoreidx8:
   536  		p := gc.Prog(v.Op.Asm())
   537  		p.From.Type = obj.TYPE_REG
   538  		p.From.Reg = gc.SSARegNum(v.Args[2])
   539  		p.To.Type = obj.TYPE_MEM
   540  		p.To.Reg = gc.SSARegNum(v.Args[0])
   541  		p.To.Scale = 8
   542  		p.To.Index = gc.SSARegNum(v.Args[1])
   543  		gc.AddAux(&p.To, v)
   544  	case ssa.Op386MOVSSstoreidx4, ssa.Op386MOVLstoreidx4:
   545  		p := gc.Prog(v.Op.Asm())
   546  		p.From.Type = obj.TYPE_REG
   547  		p.From.Reg = gc.SSARegNum(v.Args[2])
   548  		p.To.Type = obj.TYPE_MEM
   549  		p.To.Reg = gc.SSARegNum(v.Args[0])
   550  		p.To.Scale = 4
   551  		p.To.Index = gc.SSARegNum(v.Args[1])
   552  		gc.AddAux(&p.To, v)
   553  	case ssa.Op386MOVWstoreidx2:
   554  		p := gc.Prog(v.Op.Asm())
   555  		p.From.Type = obj.TYPE_REG
   556  		p.From.Reg = gc.SSARegNum(v.Args[2])
   557  		p.To.Type = obj.TYPE_MEM
   558  		p.To.Reg = gc.SSARegNum(v.Args[0])
   559  		p.To.Scale = 2
   560  		p.To.Index = gc.SSARegNum(v.Args[1])
   561  		gc.AddAux(&p.To, v)
   562  	case ssa.Op386MOVBstoreidx1, ssa.Op386MOVWstoreidx1, ssa.Op386MOVLstoreidx1, ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSDstoreidx1:
   563  		r := gc.SSARegNum(v.Args[0])
   564  		i := gc.SSARegNum(v.Args[1])
   565  		if i == x86.REG_SP {
   566  			r, i = i, r
   567  		}
   568  		p := gc.Prog(v.Op.Asm())
   569  		p.From.Type = obj.TYPE_REG
   570  		p.From.Reg = gc.SSARegNum(v.Args[2])
   571  		p.To.Type = obj.TYPE_MEM
   572  		p.To.Reg = r
   573  		p.To.Scale = 1
   574  		p.To.Index = i
   575  		gc.AddAux(&p.To, v)
   576  	case ssa.Op386MOVLstoreconst, ssa.Op386MOVWstoreconst, ssa.Op386MOVBstoreconst:
   577  		p := gc.Prog(v.Op.Asm())
   578  		p.From.Type = obj.TYPE_CONST
   579  		sc := v.AuxValAndOff()
   580  		p.From.Offset = sc.Val()
   581  		p.To.Type = obj.TYPE_MEM
   582  		p.To.Reg = gc.SSARegNum(v.Args[0])
   583  		gc.AddAux2(&p.To, v, sc.Off())
   584  	case ssa.Op386MOVLstoreconstidx1, ssa.Op386MOVLstoreconstidx4, ssa.Op386MOVWstoreconstidx1, ssa.Op386MOVWstoreconstidx2, ssa.Op386MOVBstoreconstidx1:
   585  		p := gc.Prog(v.Op.Asm())
   586  		p.From.Type = obj.TYPE_CONST
   587  		sc := v.AuxValAndOff()
   588  		p.From.Offset = sc.Val()
   589  		r := gc.SSARegNum(v.Args[0])
   590  		i := gc.SSARegNum(v.Args[1])
   591  		switch v.Op {
   592  		case ssa.Op386MOVBstoreconstidx1, ssa.Op386MOVWstoreconstidx1, ssa.Op386MOVLstoreconstidx1:
   593  			p.To.Scale = 1
   594  			if i == x86.REG_SP {
   595  				r, i = i, r
   596  			}
   597  		case ssa.Op386MOVWstoreconstidx2:
   598  			p.To.Scale = 2
   599  		case ssa.Op386MOVLstoreconstidx4:
   600  			p.To.Scale = 4
   601  		}
   602  		p.To.Type = obj.TYPE_MEM
   603  		p.To.Reg = r
   604  		p.To.Index = i
   605  		gc.AddAux2(&p.To, v, sc.Off())
   606  	case ssa.Op386MOVWLSX, ssa.Op386MOVBLSX, ssa.Op386MOVWLZX, ssa.Op386MOVBLZX,
   607  		ssa.Op386CVTSL2SS, ssa.Op386CVTSL2SD,
   608  		ssa.Op386CVTTSS2SL, ssa.Op386CVTTSD2SL,
   609  		ssa.Op386CVTSS2SD, ssa.Op386CVTSD2SS:
   610  		opregreg(v.Op.Asm(), gc.SSARegNum(v), gc.SSARegNum(v.Args[0]))
   611  	case ssa.Op386DUFFZERO:
   612  		p := gc.Prog(obj.ADUFFZERO)
   613  		p.To.Type = obj.TYPE_ADDR
   614  		p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
   615  		p.To.Offset = v.AuxInt
   616  	case ssa.Op386DUFFCOPY:
   617  		p := gc.Prog(obj.ADUFFCOPY)
   618  		p.To.Type = obj.TYPE_ADDR
   619  		p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg))
   620  		p.To.Offset = v.AuxInt
   621  
   622  	case ssa.OpCopy, ssa.Op386MOVLconvert: // TODO: use MOVLreg for reg->reg copies instead of OpCopy?
   623  		if v.Type.IsMemory() {
   624  			return
   625  		}
   626  		x := gc.SSARegNum(v.Args[0])
   627  		y := gc.SSARegNum(v)
   628  		if x != y {
   629  			opregreg(moveByType(v.Type), y, x)
   630  		}
   631  	case ssa.OpLoadReg:
   632  		if v.Type.IsFlags() {
   633  			v.Unimplementedf("load flags not implemented: %v", v.LongString())
   634  			return
   635  		}
   636  		p := gc.Prog(loadByType(v.Type))
   637  		n, off := gc.AutoVar(v.Args[0])
   638  		p.From.Type = obj.TYPE_MEM
   639  		p.From.Node = n
   640  		p.From.Sym = gc.Linksym(n.Sym)
   641  		p.From.Offset = off
   642  		if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
   643  			p.From.Name = obj.NAME_PARAM
   644  			p.From.Offset += n.Xoffset
   645  		} else {
   646  			p.From.Name = obj.NAME_AUTO
   647  		}
   648  		p.To.Type = obj.TYPE_REG
   649  		p.To.Reg = gc.SSARegNum(v)
   650  
   651  	case ssa.OpStoreReg:
   652  		if v.Type.IsFlags() {
   653  			v.Unimplementedf("store flags not implemented: %v", v.LongString())
   654  			return
   655  		}
   656  		p := gc.Prog(storeByType(v.Type))
   657  		p.From.Type = obj.TYPE_REG
   658  		p.From.Reg = gc.SSARegNum(v.Args[0])
   659  		n, off := gc.AutoVar(v)
   660  		p.To.Type = obj.TYPE_MEM
   661  		p.To.Node = n
   662  		p.To.Sym = gc.Linksym(n.Sym)
   663  		p.To.Offset = off
   664  		if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
   665  			p.To.Name = obj.NAME_PARAM
   666  			p.To.Offset += n.Xoffset
   667  		} else {
   668  			p.To.Name = obj.NAME_AUTO
   669  		}
   670  	case ssa.OpPhi:
   671  		gc.CheckLoweredPhi(v)
   672  	case ssa.OpInitMem:
   673  		// memory arg needs no code
   674  	case ssa.OpArg:
   675  		// input args need no code
   676  	case ssa.Op386LoweredGetClosurePtr:
   677  		// Closure pointer is DX.
   678  		gc.CheckLoweredGetClosurePtr(v)
   679  	case ssa.Op386LoweredGetG:
   680  		r := gc.SSARegNum(v)
   681  		// See the comments in cmd/internal/obj/x86/obj6.go
   682  		// near CanUse1InsnTLS for a detailed explanation of these instructions.
   683  		if x86.CanUse1InsnTLS(gc.Ctxt) {
   684  			// MOVL (TLS), r
   685  			p := gc.Prog(x86.AMOVL)
   686  			p.From.Type = obj.TYPE_MEM
   687  			p.From.Reg = x86.REG_TLS
   688  			p.To.Type = obj.TYPE_REG
   689  			p.To.Reg = r
   690  		} else {
   691  			// MOVL TLS, r
   692  			// MOVL (r)(TLS*1), r
   693  			p := gc.Prog(x86.AMOVL)
   694  			p.From.Type = obj.TYPE_REG
   695  			p.From.Reg = x86.REG_TLS
   696  			p.To.Type = obj.TYPE_REG
   697  			p.To.Reg = r
   698  			q := gc.Prog(x86.AMOVL)
   699  			q.From.Type = obj.TYPE_MEM
   700  			q.From.Reg = r
   701  			q.From.Index = x86.REG_TLS
   702  			q.From.Scale = 1
   703  			q.To.Type = obj.TYPE_REG
   704  			q.To.Reg = r
   705  		}
   706  	case ssa.Op386CALLstatic:
   707  		if v.Aux.(*gc.Sym) == gc.Deferreturn.Sym {
   708  			// Deferred calls will appear to be returning to
   709  			// the CALL deferreturn(SB) that we are about to emit.
   710  			// However, the stack trace code will show the line
   711  			// of the instruction byte before the return PC.
   712  			// To avoid that being an unrelated instruction,
   713  			// insert an actual hardware NOP that will have the right line number.
   714  			// This is different from obj.ANOP, which is a virtual no-op
   715  			// that doesn't make it into the instruction stream.
   716  			ginsnop()
   717  		}
   718  		p := gc.Prog(obj.ACALL)
   719  		p.To.Type = obj.TYPE_MEM
   720  		p.To.Name = obj.NAME_EXTERN
   721  		p.To.Sym = gc.Linksym(v.Aux.(*gc.Sym))
   722  		if gc.Maxarg < v.AuxInt {
   723  			gc.Maxarg = v.AuxInt
   724  		}
   725  	case ssa.Op386CALLclosure:
   726  		p := gc.Prog(obj.ACALL)
   727  		p.To.Type = obj.TYPE_REG
   728  		p.To.Reg = gc.SSARegNum(v.Args[0])
   729  		if gc.Maxarg < v.AuxInt {
   730  			gc.Maxarg = v.AuxInt
   731  		}
   732  	case ssa.Op386CALLdefer:
   733  		p := gc.Prog(obj.ACALL)
   734  		p.To.Type = obj.TYPE_MEM
   735  		p.To.Name = obj.NAME_EXTERN
   736  		p.To.Sym = gc.Linksym(gc.Deferproc.Sym)
   737  		if gc.Maxarg < v.AuxInt {
   738  			gc.Maxarg = v.AuxInt
   739  		}
   740  	case ssa.Op386CALLgo:
   741  		p := gc.Prog(obj.ACALL)
   742  		p.To.Type = obj.TYPE_MEM
   743  		p.To.Name = obj.NAME_EXTERN
   744  		p.To.Sym = gc.Linksym(gc.Newproc.Sym)
   745  		if gc.Maxarg < v.AuxInt {
   746  			gc.Maxarg = v.AuxInt
   747  		}
   748  	case ssa.Op386CALLinter:
   749  		p := gc.Prog(obj.ACALL)
   750  		p.To.Type = obj.TYPE_REG
   751  		p.To.Reg = gc.SSARegNum(v.Args[0])
   752  		if gc.Maxarg < v.AuxInt {
   753  			gc.Maxarg = v.AuxInt
   754  		}
   755  	case ssa.Op386NEGL,
   756  		ssa.Op386BSWAPL,
   757  		ssa.Op386NOTL:
   758  		r := gc.SSARegNum(v)
   759  		if r != gc.SSARegNum(v.Args[0]) {
   760  			v.Fatalf("input[0] and output not in same register %s", v.LongString())
   761  		}
   762  		p := gc.Prog(v.Op.Asm())
   763  		p.To.Type = obj.TYPE_REG
   764  		p.To.Reg = r
   765  	case ssa.Op386BSFL, ssa.Op386BSFW,
   766  		ssa.Op386BSRL, ssa.Op386BSRW,
   767  		ssa.Op386SQRTSD:
   768  		p := gc.Prog(v.Op.Asm())
   769  		p.From.Type = obj.TYPE_REG
   770  		p.From.Reg = gc.SSARegNum(v.Args[0])
   771  		p.To.Type = obj.TYPE_REG
   772  		p.To.Reg = gc.SSARegNum(v)
   773  	case ssa.OpSP, ssa.OpSB, ssa.OpSelect0, ssa.OpSelect1:
   774  		// nothing to do
   775  	case ssa.Op386SETEQ, ssa.Op386SETNE,
   776  		ssa.Op386SETL, ssa.Op386SETLE,
   777  		ssa.Op386SETG, ssa.Op386SETGE,
   778  		ssa.Op386SETGF, ssa.Op386SETGEF,
   779  		ssa.Op386SETB, ssa.Op386SETBE,
   780  		ssa.Op386SETORD, ssa.Op386SETNAN,
   781  		ssa.Op386SETA, ssa.Op386SETAE:
   782  		p := gc.Prog(v.Op.Asm())
   783  		p.To.Type = obj.TYPE_REG
   784  		p.To.Reg = gc.SSARegNum(v)
   785  
   786  	case ssa.Op386SETNEF:
   787  		p := gc.Prog(v.Op.Asm())
   788  		p.To.Type = obj.TYPE_REG
   789  		p.To.Reg = gc.SSARegNum(v)
   790  		q := gc.Prog(x86.ASETPS)
   791  		q.To.Type = obj.TYPE_REG
   792  		q.To.Reg = x86.REG_AX
   793  		opregreg(x86.AORL, gc.SSARegNum(v), x86.REG_AX)
   794  
   795  	case ssa.Op386SETEQF:
   796  		p := gc.Prog(v.Op.Asm())
   797  		p.To.Type = obj.TYPE_REG
   798  		p.To.Reg = gc.SSARegNum(v)
   799  		q := gc.Prog(x86.ASETPC)
   800  		q.To.Type = obj.TYPE_REG
   801  		q.To.Reg = x86.REG_AX
   802  		opregreg(x86.AANDL, gc.SSARegNum(v), x86.REG_AX)
   803  
   804  	case ssa.Op386InvertFlags:
   805  		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
   806  	case ssa.Op386FlagEQ, ssa.Op386FlagLT_ULT, ssa.Op386FlagLT_UGT, ssa.Op386FlagGT_ULT, ssa.Op386FlagGT_UGT:
   807  		v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
   808  	case ssa.Op386REPSTOSL:
   809  		gc.Prog(x86.AREP)
   810  		gc.Prog(x86.ASTOSL)
   811  	case ssa.Op386REPMOVSL:
   812  		gc.Prog(x86.AREP)
   813  		gc.Prog(x86.AMOVSL)
   814  	case ssa.OpVarDef:
   815  		gc.Gvardef(v.Aux.(*gc.Node))
   816  	case ssa.OpVarKill:
   817  		gc.Gvarkill(v.Aux.(*gc.Node))
   818  	case ssa.OpVarLive:
   819  		gc.Gvarlive(v.Aux.(*gc.Node))
   820  	case ssa.OpKeepAlive:
   821  		if !v.Args[0].Type.IsPtrShaped() {
   822  			v.Fatalf("keeping non-pointer alive %v", v.Args[0])
   823  		}
   824  		n, off := gc.AutoVar(v.Args[0])
   825  		if n == nil {
   826  			v.Fatalf("KeepLive with non-spilled value %s %s", v, v.Args[0])
   827  		}
   828  		if off != 0 {
   829  			v.Fatalf("KeepLive with non-zero offset spill location %s:%d", n, off)
   830  		}
   831  		gc.Gvarlive(n)
   832  	case ssa.Op386LoweredNilCheck:
   833  		// Optimization - if the subsequent block has a load or store
   834  		// at the same address, we don't need to issue this instruction.
   835  		mem := v.Args[1]
   836  		for _, w := range v.Block.Succs[0].Block().Values {
   837  			if w.Op == ssa.OpPhi {
   838  				if w.Type.IsMemory() {
   839  					mem = w
   840  				}
   841  				continue
   842  			}
   843  			if len(w.Args) == 0 || !w.Args[len(w.Args)-1].Type.IsMemory() {
   844  				// w doesn't use a store - can't be a memory op.
   845  				continue
   846  			}
   847  			if w.Args[len(w.Args)-1] != mem {
   848  				v.Fatalf("wrong store after nilcheck v=%s w=%s", v, w)
   849  			}
   850  			switch w.Op {
   851  			case ssa.Op386MOVLload, ssa.Op386MOVWload, ssa.Op386MOVBload,
   852  				ssa.Op386MOVLstore, ssa.Op386MOVWstore, ssa.Op386MOVBstore,
   853  				ssa.Op386MOVBLSXload, ssa.Op386MOVWLSXload,
   854  				ssa.Op386MOVSSload, ssa.Op386MOVSDload,
   855  				ssa.Op386MOVSSstore, ssa.Op386MOVSDstore:
   856  				if w.Args[0] == v.Args[0] && w.Aux == nil && w.AuxInt >= 0 && w.AuxInt < minZeroPage {
   857  					if gc.Debug_checknil != 0 && int(v.Line) > 1 {
   858  						gc.Warnl(v.Line, "removed nil check")
   859  					}
   860  					return
   861  				}
   862  			case ssa.Op386MOVLstoreconst, ssa.Op386MOVWstoreconst, ssa.Op386MOVBstoreconst:
   863  				off := ssa.ValAndOff(v.AuxInt).Off()
   864  				if w.Args[0] == v.Args[0] && w.Aux == nil && off >= 0 && off < minZeroPage {
   865  					if gc.Debug_checknil != 0 && int(v.Line) > 1 {
   866  						gc.Warnl(v.Line, "removed nil check")
   867  					}
   868  					return
   869  				}
   870  			}
   871  			if w.Type.IsMemory() {
   872  				if w.Op == ssa.OpVarDef || w.Op == ssa.OpVarKill || w.Op == ssa.OpVarLive {
   873  					// these ops are OK
   874  					mem = w
   875  					continue
   876  				}
   877  				// We can't delay the nil check past the next store.
   878  				break
   879  			}
   880  		}
   881  		// Issue a load which will fault if the input is nil.
   882  		// TODO: We currently use the 2-byte instruction TESTB AX, (reg).
   883  		// Should we use the 3-byte TESTB $0, (reg) instead?  It is larger
   884  		// but it doesn't have false dependency on AX.
   885  		// Or maybe allocate an output register and use MOVL (reg),reg2 ?
   886  		// That trades clobbering flags for clobbering a register.
   887  		p := gc.Prog(x86.ATESTB)
   888  		p.From.Type = obj.TYPE_REG
   889  		p.From.Reg = x86.REG_AX
   890  		p.To.Type = obj.TYPE_MEM
   891  		p.To.Reg = gc.SSARegNum(v.Args[0])
   892  		gc.AddAux(&p.To, v)
   893  		if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
   894  			gc.Warnl(v.Line, "generated nil check")
   895  		}
   896  	case ssa.Op386FCHS:
   897  		v.Fatalf("FCHS in non-387 mode")
   898  	default:
   899  		v.Unimplementedf("genValue not implemented: %s", v.LongString())
   900  	}
   901  }
   902  
   903  var blockJump = [...]struct {
   904  	asm, invasm obj.As
   905  }{
   906  	ssa.Block386EQ:  {x86.AJEQ, x86.AJNE},
   907  	ssa.Block386NE:  {x86.AJNE, x86.AJEQ},
   908  	ssa.Block386LT:  {x86.AJLT, x86.AJGE},
   909  	ssa.Block386GE:  {x86.AJGE, x86.AJLT},
   910  	ssa.Block386LE:  {x86.AJLE, x86.AJGT},
   911  	ssa.Block386GT:  {x86.AJGT, x86.AJLE},
   912  	ssa.Block386ULT: {x86.AJCS, x86.AJCC},
   913  	ssa.Block386UGE: {x86.AJCC, x86.AJCS},
   914  	ssa.Block386UGT: {x86.AJHI, x86.AJLS},
   915  	ssa.Block386ULE: {x86.AJLS, x86.AJHI},
   916  	ssa.Block386ORD: {x86.AJPC, x86.AJPS},
   917  	ssa.Block386NAN: {x86.AJPS, x86.AJPC},
   918  }
   919  
   920  var eqfJumps = [2][2]gc.FloatingEQNEJump{
   921  	{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPS, Index: 1}}, // next == b.Succs[0]
   922  	{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPC, Index: 0}}, // next == b.Succs[1]
   923  }
   924  var nefJumps = [2][2]gc.FloatingEQNEJump{
   925  	{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPC, Index: 1}}, // next == b.Succs[0]
   926  	{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPS, Index: 0}}, // next == b.Succs[1]
   927  }
   928  
   929  func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
   930  	s.SetLineno(b.Line)
   931  
   932  	if gc.Thearch.Use387 {
   933  		// Empty the 387's FP stack before the block ends.
   934  		flush387(s)
   935  	}
   936  
   937  	switch b.Kind {
   938  	case ssa.BlockPlain, ssa.BlockCall, ssa.BlockCheck:
   939  		if b.Succs[0].Block() != next {
   940  			p := gc.Prog(obj.AJMP)
   941  			p.To.Type = obj.TYPE_BRANCH
   942  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   943  		}
   944  	case ssa.BlockDefer:
   945  		// defer returns in rax:
   946  		// 0 if we should continue executing
   947  		// 1 if we should jump to deferreturn call
   948  		p := gc.Prog(x86.ATESTL)
   949  		p.From.Type = obj.TYPE_REG
   950  		p.From.Reg = x86.REG_AX
   951  		p.To.Type = obj.TYPE_REG
   952  		p.To.Reg = x86.REG_AX
   953  		p = gc.Prog(x86.AJNE)
   954  		p.To.Type = obj.TYPE_BRANCH
   955  		s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   956  		if b.Succs[0].Block() != next {
   957  			p := gc.Prog(obj.AJMP)
   958  			p.To.Type = obj.TYPE_BRANCH
   959  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   960  		}
   961  	case ssa.BlockExit:
   962  		gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here
   963  	case ssa.BlockRet:
   964  		gc.Prog(obj.ARET)
   965  	case ssa.BlockRetJmp:
   966  		p := gc.Prog(obj.AJMP)
   967  		p.To.Type = obj.TYPE_MEM
   968  		p.To.Name = obj.NAME_EXTERN
   969  		p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
   970  
   971  	case ssa.Block386EQF:
   972  		gc.SSAGenFPJump(s, b, next, &eqfJumps)
   973  
   974  	case ssa.Block386NEF:
   975  		gc.SSAGenFPJump(s, b, next, &nefJumps)
   976  
   977  	case ssa.Block386EQ, ssa.Block386NE,
   978  		ssa.Block386LT, ssa.Block386GE,
   979  		ssa.Block386LE, ssa.Block386GT,
   980  		ssa.Block386ULT, ssa.Block386UGT,
   981  		ssa.Block386ULE, ssa.Block386UGE:
   982  		jmp := blockJump[b.Kind]
   983  		likely := b.Likely
   984  		var p *obj.Prog
   985  		switch next {
   986  		case b.Succs[0].Block():
   987  			p = gc.Prog(jmp.invasm)
   988  			likely *= -1
   989  			p.To.Type = obj.TYPE_BRANCH
   990  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   991  		case b.Succs[1].Block():
   992  			p = gc.Prog(jmp.asm)
   993  			p.To.Type = obj.TYPE_BRANCH
   994  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   995  		default:
   996  			p = gc.Prog(jmp.asm)
   997  			p.To.Type = obj.TYPE_BRANCH
   998  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   999  			q := gc.Prog(obj.AJMP)
  1000  			q.To.Type = obj.TYPE_BRANCH
  1001  			s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
  1002  		}
  1003  
  1004  		// liblink reorders the instruction stream as it sees fit.
  1005  		// Pass along what we know so liblink can make use of it.
  1006  		// TODO: Once we've fully switched to SSA,
  1007  		// make liblink leave our output alone.
  1008  		switch likely {
  1009  		case ssa.BranchUnlikely:
  1010  			p.From.Type = obj.TYPE_CONST
  1011  			p.From.Offset = 0
  1012  		case ssa.BranchLikely:
  1013  			p.From.Type = obj.TYPE_CONST
  1014  			p.From.Offset = 1
  1015  		}
  1016  
  1017  	default:
  1018  		b.Unimplementedf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
  1019  	}
  1020  }