github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/src/cmd/compile/internal/ppc64/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 ppc64
     6  
     7  import (
     8  	"cmd/compile/internal/gc"
     9  	"cmd/compile/internal/ssa"
    10  	"cmd/internal/obj"
    11  	"cmd/internal/obj/ppc64"
    12  	"math"
    13  )
    14  
    15  // iselOp encodes mapping of comparison operations onto ISEL operands
    16  type iselOp struct {
    17  	cond        int64
    18  	valueIfCond int // if cond is true, the value to return (0 or 1)
    19  }
    20  
    21  // Input registers to ISEL used for comparison. Index 0 is zero, 1 is (will be) 1
    22  var iselRegs = [2]int16{ppc64.REG_R0, ppc64.REGTMP}
    23  
    24  var iselOps = map[ssa.Op]iselOp{
    25  	ssa.OpPPC64Equal:         iselOp{cond: ppc64.C_COND_EQ, valueIfCond: 1},
    26  	ssa.OpPPC64NotEqual:      iselOp{cond: ppc64.C_COND_EQ, valueIfCond: 0},
    27  	ssa.OpPPC64LessThan:      iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1},
    28  	ssa.OpPPC64GreaterEqual:  iselOp{cond: ppc64.C_COND_LT, valueIfCond: 0},
    29  	ssa.OpPPC64GreaterThan:   iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1},
    30  	ssa.OpPPC64LessEqual:     iselOp{cond: ppc64.C_COND_GT, valueIfCond: 0},
    31  	ssa.OpPPC64FLessThan:     iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1},
    32  	ssa.OpPPC64FGreaterThan:  iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1},
    33  	ssa.OpPPC64FLessEqual:    iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1}, // 2 comparisons, 2nd is EQ
    34  	ssa.OpPPC64FGreaterEqual: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1}, // 2 comparisons, 2nd is EQ
    35  }
    36  
    37  // markMoves marks any MOVXconst ops that need to avoid clobbering flags.
    38  func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
    39  	//	flive := b.FlagsLiveAtEnd
    40  	//	if b.Control != nil && b.Control.Type.IsFlags() {
    41  	//		flive = true
    42  	//	}
    43  	//	for i := len(b.Values) - 1; i >= 0; i-- {
    44  	//		v := b.Values[i]
    45  	//		if flive && (v.Op == v.Op == ssa.OpPPC64MOVDconst) {
    46  	//			// The "mark" is any non-nil Aux value.
    47  	//			v.Aux = v
    48  	//		}
    49  	//		if v.Type.IsFlags() {
    50  	//			flive = false
    51  	//		}
    52  	//		for _, a := range v.Args {
    53  	//			if a.Type.IsFlags() {
    54  	//				flive = true
    55  	//			}
    56  	//		}
    57  	//	}
    58  }
    59  
    60  // loadByType returns the load instruction of the given type.
    61  func loadByType(t ssa.Type) obj.As {
    62  	if t.IsFloat() {
    63  		switch t.Size() {
    64  		case 4:
    65  			return ppc64.AFMOVS
    66  		case 8:
    67  			return ppc64.AFMOVD
    68  		}
    69  	} else {
    70  		switch t.Size() {
    71  		case 1:
    72  			if t.IsSigned() {
    73  				return ppc64.AMOVB
    74  			} else {
    75  				return ppc64.AMOVBZ
    76  			}
    77  		case 2:
    78  			if t.IsSigned() {
    79  				return ppc64.AMOVH
    80  			} else {
    81  				return ppc64.AMOVHZ
    82  			}
    83  		case 4:
    84  			if t.IsSigned() {
    85  				return ppc64.AMOVW
    86  			} else {
    87  				return ppc64.AMOVWZ
    88  			}
    89  		case 8:
    90  			return ppc64.AMOVD
    91  		}
    92  	}
    93  	panic("bad load type")
    94  }
    95  
    96  // storeByType returns the store instruction of the given type.
    97  func storeByType(t ssa.Type) obj.As {
    98  	if t.IsFloat() {
    99  		switch t.Size() {
   100  		case 4:
   101  			return ppc64.AFMOVS
   102  		case 8:
   103  			return ppc64.AFMOVD
   104  		}
   105  	} else {
   106  		switch t.Size() {
   107  		case 1:
   108  			return ppc64.AMOVB
   109  		case 2:
   110  			return ppc64.AMOVH
   111  		case 4:
   112  			return ppc64.AMOVW
   113  		case 8:
   114  			return ppc64.AMOVD
   115  		}
   116  	}
   117  	panic("bad store type")
   118  }
   119  
   120  func ssaGenISEL(s *gc.SSAGenState, v *ssa.Value, cr int64, r1, r2 int16) {
   121  	r := v.Reg()
   122  	p := s.Prog(ppc64.AISEL)
   123  	p.To.Type = obj.TYPE_REG
   124  	p.To.Reg = r
   125  	p.Reg = r1
   126  	p.From3 = &obj.Addr{Type: obj.TYPE_REG, Reg: r2}
   127  	p.From.Type = obj.TYPE_CONST
   128  	p.From.Offset = cr
   129  }
   130  
   131  func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
   132  	switch v.Op {
   133  	case ssa.OpCopy, ssa.OpPPC64MOVDconvert:
   134  		t := v.Type
   135  		if t.IsMemory() {
   136  			return
   137  		}
   138  		x := v.Args[0].Reg()
   139  		y := v.Reg()
   140  		if x != y {
   141  			rt := obj.TYPE_REG
   142  			op := ppc64.AMOVD
   143  
   144  			if t.IsFloat() {
   145  				op = ppc64.AFMOVD
   146  			}
   147  			p := s.Prog(op)
   148  			p.From.Type = rt
   149  			p.From.Reg = x
   150  			p.To.Type = rt
   151  			p.To.Reg = y
   152  		}
   153  
   154  	case ssa.OpPPC64Xf2i64:
   155  		{
   156  			x := v.Args[0].Reg()
   157  			y := v.Reg()
   158  
   159  			p := s.Prog(ppc64.AMFVSRD)
   160  			p.From.Type = obj.TYPE_REG
   161  			p.From.Reg = x
   162  			p.To.Type = obj.TYPE_REG
   163  			p.To.Reg = y
   164  		}
   165  	case ssa.OpPPC64Xi2f64:
   166  		{
   167  			x := v.Args[0].Reg()
   168  			y := v.Reg()
   169  
   170  			p := s.Prog(ppc64.AMTVSRD)
   171  			p.From.Type = obj.TYPE_REG
   172  			p.From.Reg = x
   173  			p.To.Type = obj.TYPE_REG
   174  			p.To.Reg = y
   175  		}
   176  
   177  	case ssa.OpPPC64LoweredAtomicAnd8,
   178  		ssa.OpPPC64LoweredAtomicOr8:
   179  		// SYNC
   180  		// LBAR		(Rarg0), Rtmp
   181  		// AND/OR	Rarg1, Rtmp
   182  		// STBCCC	Rtmp, (Rarg0)
   183  		// BNE		-3(PC)
   184  		// ISYNC
   185  		r0 := v.Args[0].Reg()
   186  		r1 := v.Args[1].Reg()
   187  		psync := s.Prog(ppc64.ASYNC)
   188  		psync.To.Type = obj.TYPE_NONE
   189  		p := s.Prog(ppc64.ALBAR)
   190  		p.From.Type = obj.TYPE_MEM
   191  		p.From.Reg = r0
   192  		p.To.Type = obj.TYPE_REG
   193  		p.To.Reg = ppc64.REGTMP
   194  		p1 := s.Prog(v.Op.Asm())
   195  		p1.From.Type = obj.TYPE_REG
   196  		p1.From.Reg = r1
   197  		p1.To.Type = obj.TYPE_REG
   198  		p1.To.Reg = ppc64.REGTMP
   199  		p2 := s.Prog(ppc64.ASTBCCC)
   200  		p2.From.Type = obj.TYPE_REG
   201  		p2.From.Reg = ppc64.REGTMP
   202  		p2.To.Type = obj.TYPE_MEM
   203  		p2.To.Reg = r0
   204  		p2.RegTo2 = ppc64.REGTMP
   205  		p3 := s.Prog(ppc64.ABNE)
   206  		p3.To.Type = obj.TYPE_BRANCH
   207  		gc.Patch(p3, p)
   208  		pisync := s.Prog(ppc64.AISYNC)
   209  		pisync.To.Type = obj.TYPE_NONE
   210  
   211  	case ssa.OpPPC64LoweredAtomicAdd32,
   212  		ssa.OpPPC64LoweredAtomicAdd64:
   213  		// SYNC
   214  		// LDAR/LWAR    (Rarg0), Rout
   215  		// ADD		Rarg1, Rout
   216  		// STDCCC/STWCCC Rout, (Rarg0)
   217  		// BNE         -3(PC)
   218  		// ISYNC
   219  		// MOVW		Rout,Rout (if Add32)
   220  		ld := ppc64.ALDAR
   221  		st := ppc64.ASTDCCC
   222  		if v.Op == ssa.OpPPC64LoweredAtomicAdd32 {
   223  			ld = ppc64.ALWAR
   224  			st = ppc64.ASTWCCC
   225  		}
   226  		r0 := v.Args[0].Reg()
   227  		r1 := v.Args[1].Reg()
   228  		out := v.Reg0()
   229  		// SYNC
   230  		psync := s.Prog(ppc64.ASYNC)
   231  		psync.To.Type = obj.TYPE_NONE
   232  		// LDAR or LWAR
   233  		p := s.Prog(ld)
   234  		p.From.Type = obj.TYPE_MEM
   235  		p.From.Reg = r0
   236  		p.To.Type = obj.TYPE_REG
   237  		p.To.Reg = out
   238  		// ADD reg1,out
   239  		p1 := s.Prog(ppc64.AADD)
   240  		p1.From.Type = obj.TYPE_REG
   241  		p1.From.Reg = r1
   242  		p1.To.Reg = out
   243  		p1.To.Type = obj.TYPE_REG
   244  		// STDCCC or STWCCC
   245  		p3 := s.Prog(st)
   246  		p3.From.Type = obj.TYPE_REG
   247  		p3.From.Reg = out
   248  		p3.To.Type = obj.TYPE_MEM
   249  		p3.To.Reg = r0
   250  		// BNE retry
   251  		p4 := s.Prog(ppc64.ABNE)
   252  		p4.To.Type = obj.TYPE_BRANCH
   253  		gc.Patch(p4, p)
   254  		// ISYNC
   255  		pisync := s.Prog(ppc64.AISYNC)
   256  		pisync.To.Type = obj.TYPE_NONE
   257  
   258  		// Ensure a 32 bit result
   259  		if v.Op == ssa.OpPPC64LoweredAtomicAdd32 {
   260  			p5 := s.Prog(ppc64.AMOVWZ)
   261  			p5.To.Type = obj.TYPE_REG
   262  			p5.To.Reg = out
   263  			p5.From.Type = obj.TYPE_REG
   264  			p5.From.Reg = out
   265  		}
   266  
   267  	case ssa.OpPPC64LoweredAtomicExchange32,
   268  		ssa.OpPPC64LoweredAtomicExchange64:
   269  		// SYNC
   270  		// LDAR/LWAR    (Rarg0), Rout
   271  		// STDCCC/STWCCC Rout, (Rarg0)
   272  		// BNE         -2(PC)
   273  		// ISYNC
   274  		ld := ppc64.ALDAR
   275  		st := ppc64.ASTDCCC
   276  		if v.Op == ssa.OpPPC64LoweredAtomicExchange32 {
   277  			ld = ppc64.ALWAR
   278  			st = ppc64.ASTWCCC
   279  		}
   280  		r0 := v.Args[0].Reg()
   281  		r1 := v.Args[1].Reg()
   282  		out := v.Reg0()
   283  		// SYNC
   284  		psync := s.Prog(ppc64.ASYNC)
   285  		psync.To.Type = obj.TYPE_NONE
   286  		// LDAR or LWAR
   287  		p := s.Prog(ld)
   288  		p.From.Type = obj.TYPE_MEM
   289  		p.From.Reg = r0
   290  		p.To.Type = obj.TYPE_REG
   291  		p.To.Reg = out
   292  		// STDCCC or STWCCC
   293  		p1 := s.Prog(st)
   294  		p1.From.Type = obj.TYPE_REG
   295  		p1.From.Reg = r1
   296  		p1.To.Type = obj.TYPE_MEM
   297  		p1.To.Reg = r0
   298  		// BNE retry
   299  		p2 := s.Prog(ppc64.ABNE)
   300  		p2.To.Type = obj.TYPE_BRANCH
   301  		gc.Patch(p2, p)
   302  		// ISYNC
   303  		pisync := s.Prog(ppc64.AISYNC)
   304  		pisync.To.Type = obj.TYPE_NONE
   305  
   306  	case ssa.OpPPC64LoweredAtomicLoad32,
   307  		ssa.OpPPC64LoweredAtomicLoad64,
   308  		ssa.OpPPC64LoweredAtomicLoadPtr:
   309  		// SYNC
   310  		// MOVD/MOVW (Rarg0), Rout
   311  		// CMP Rout,Rout
   312  		// BNE 1(PC)
   313  		// ISYNC
   314  		ld := ppc64.AMOVD
   315  		cmp := ppc64.ACMP
   316  		if v.Op == ssa.OpPPC64LoweredAtomicLoad32 {
   317  			ld = ppc64.AMOVW
   318  			cmp = ppc64.ACMPW
   319  		}
   320  		arg0 := v.Args[0].Reg()
   321  		out := v.Reg0()
   322  		// SYNC
   323  		psync := s.Prog(ppc64.ASYNC)
   324  		psync.To.Type = obj.TYPE_NONE
   325  		// Load
   326  		p := s.Prog(ld)
   327  		p.From.Type = obj.TYPE_MEM
   328  		p.From.Reg = arg0
   329  		p.To.Type = obj.TYPE_REG
   330  		p.To.Reg = out
   331  		// CMP
   332  		p1 := s.Prog(cmp)
   333  		p1.From.Type = obj.TYPE_REG
   334  		p1.From.Reg = out
   335  		p1.To.Type = obj.TYPE_REG
   336  		p1.To.Reg = out
   337  		// BNE
   338  		p2 := s.Prog(ppc64.ABNE)
   339  		p2.To.Type = obj.TYPE_BRANCH
   340  		// ISYNC
   341  		pisync := s.Prog(ppc64.AISYNC)
   342  		pisync.To.Type = obj.TYPE_NONE
   343  		gc.Patch(p2, pisync)
   344  
   345  	case ssa.OpPPC64LoweredAtomicStore32,
   346  		ssa.OpPPC64LoweredAtomicStore64:
   347  		// SYNC
   348  		// MOVD/MOVW arg1,(arg0)
   349  		st := ppc64.AMOVD
   350  		if v.Op == ssa.OpPPC64LoweredAtomicStore32 {
   351  			st = ppc64.AMOVW
   352  		}
   353  		arg0 := v.Args[0].Reg()
   354  		arg1 := v.Args[1].Reg()
   355  		// SYNC
   356  		psync := s.Prog(ppc64.ASYNC)
   357  		psync.To.Type = obj.TYPE_NONE
   358  		// Store
   359  		p := s.Prog(st)
   360  		p.To.Type = obj.TYPE_MEM
   361  		p.To.Reg = arg0
   362  		p.From.Type = obj.TYPE_REG
   363  		p.From.Reg = arg1
   364  
   365  	case ssa.OpPPC64LoweredAtomicCas64,
   366  		ssa.OpPPC64LoweredAtomicCas32:
   367  		// SYNC
   368  		// loop:
   369  		// LDAR        (Rarg0), Rtmp
   370  		// CMP         Rarg1, Rtmp
   371  		// BNE         fail
   372  		// STDCCC      Rarg2, (Rarg0)
   373  		// BNE         loop
   374  		// ISYNC
   375  		// MOVD        $1, Rout
   376  		// BR          end
   377  		// fail:
   378  		// MOVD        $0, Rout
   379  		// end:
   380  		ld := ppc64.ALDAR
   381  		st := ppc64.ASTDCCC
   382  		cmp := ppc64.ACMP
   383  		if v.Op == ssa.OpPPC64LoweredAtomicCas32 {
   384  			ld = ppc64.ALWAR
   385  			st = ppc64.ASTWCCC
   386  			cmp = ppc64.ACMPW
   387  		}
   388  		r0 := v.Args[0].Reg()
   389  		r1 := v.Args[1].Reg()
   390  		r2 := v.Args[2].Reg()
   391  		out := v.Reg0()
   392  		// SYNC
   393  		psync := s.Prog(ppc64.ASYNC)
   394  		psync.To.Type = obj.TYPE_NONE
   395  		// LDAR or LWAR
   396  		p := s.Prog(ld)
   397  		p.From.Type = obj.TYPE_MEM
   398  		p.From.Reg = r0
   399  		p.To.Type = obj.TYPE_REG
   400  		p.To.Reg = ppc64.REGTMP
   401  		// CMP reg1,reg2
   402  		p1 := s.Prog(cmp)
   403  		p1.From.Type = obj.TYPE_REG
   404  		p1.From.Reg = r1
   405  		p1.To.Reg = ppc64.REGTMP
   406  		p1.To.Type = obj.TYPE_REG
   407  		// BNE cas_fail
   408  		p2 := s.Prog(ppc64.ABNE)
   409  		p2.To.Type = obj.TYPE_BRANCH
   410  		// STDCCC or STWCCC
   411  		p3 := s.Prog(st)
   412  		p3.From.Type = obj.TYPE_REG
   413  		p3.From.Reg = r2
   414  		p3.To.Type = obj.TYPE_MEM
   415  		p3.To.Reg = r0
   416  		// BNE retry
   417  		p4 := s.Prog(ppc64.ABNE)
   418  		p4.To.Type = obj.TYPE_BRANCH
   419  		gc.Patch(p4, p)
   420  		// ISYNC
   421  		pisync := s.Prog(ppc64.AISYNC)
   422  		pisync.To.Type = obj.TYPE_NONE
   423  		// return true
   424  		p5 := s.Prog(ppc64.AMOVD)
   425  		p5.From.Type = obj.TYPE_CONST
   426  		p5.From.Offset = 1
   427  		p5.To.Type = obj.TYPE_REG
   428  		p5.To.Reg = out
   429  		// BR done
   430  		p6 := s.Prog(obj.AJMP)
   431  		p6.To.Type = obj.TYPE_BRANCH
   432  		// return false
   433  		p7 := s.Prog(ppc64.AMOVD)
   434  		p7.From.Type = obj.TYPE_CONST
   435  		p7.From.Offset = 0
   436  		p7.To.Type = obj.TYPE_REG
   437  		p7.To.Reg = out
   438  		gc.Patch(p2, p7)
   439  		// done (label)
   440  		p8 := s.Prog(obj.ANOP)
   441  		gc.Patch(p6, p8)
   442  
   443  	case ssa.OpPPC64LoweredGetClosurePtr:
   444  		// Closure pointer is R11 (already)
   445  		gc.CheckLoweredGetClosurePtr(v)
   446  
   447  	case ssa.OpPPC64LoweredRound32F, ssa.OpPPC64LoweredRound64F:
   448  		// input is already rounded
   449  
   450  	case ssa.OpLoadReg:
   451  		loadOp := loadByType(v.Type)
   452  		p := s.Prog(loadOp)
   453  		gc.AddrAuto(&p.From, v.Args[0])
   454  		p.To.Type = obj.TYPE_REG
   455  		p.To.Reg = v.Reg()
   456  
   457  	case ssa.OpStoreReg:
   458  		storeOp := storeByType(v.Type)
   459  		p := s.Prog(storeOp)
   460  		p.From.Type = obj.TYPE_REG
   461  		p.From.Reg = v.Args[0].Reg()
   462  		gc.AddrAuto(&p.To, v)
   463  
   464  	case ssa.OpPPC64DIVD:
   465  		// For now,
   466  		//
   467  		// cmp arg1, -1
   468  		// be  ahead
   469  		// v = arg0 / arg1
   470  		// b over
   471  		// ahead: v = - arg0
   472  		// over: nop
   473  		r := v.Reg()
   474  		r0 := v.Args[0].Reg()
   475  		r1 := v.Args[1].Reg()
   476  
   477  		p := s.Prog(ppc64.ACMP)
   478  		p.From.Type = obj.TYPE_REG
   479  		p.From.Reg = r1
   480  		p.To.Type = obj.TYPE_CONST
   481  		p.To.Offset = -1
   482  
   483  		pbahead := s.Prog(ppc64.ABEQ)
   484  		pbahead.To.Type = obj.TYPE_BRANCH
   485  
   486  		p = s.Prog(v.Op.Asm())
   487  		p.From.Type = obj.TYPE_REG
   488  		p.From.Reg = r1
   489  		p.Reg = r0
   490  		p.To.Type = obj.TYPE_REG
   491  		p.To.Reg = r
   492  
   493  		pbover := s.Prog(obj.AJMP)
   494  		pbover.To.Type = obj.TYPE_BRANCH
   495  
   496  		p = s.Prog(ppc64.ANEG)
   497  		p.To.Type = obj.TYPE_REG
   498  		p.To.Reg = r
   499  		p.From.Type = obj.TYPE_REG
   500  		p.From.Reg = r0
   501  		gc.Patch(pbahead, p)
   502  
   503  		p = s.Prog(obj.ANOP)
   504  		gc.Patch(pbover, p)
   505  
   506  	case ssa.OpPPC64DIVW:
   507  		// word-width version of above
   508  		r := v.Reg()
   509  		r0 := v.Args[0].Reg()
   510  		r1 := v.Args[1].Reg()
   511  
   512  		p := s.Prog(ppc64.ACMPW)
   513  		p.From.Type = obj.TYPE_REG
   514  		p.From.Reg = r1
   515  		p.To.Type = obj.TYPE_CONST
   516  		p.To.Offset = -1
   517  
   518  		pbahead := s.Prog(ppc64.ABEQ)
   519  		pbahead.To.Type = obj.TYPE_BRANCH
   520  
   521  		p = s.Prog(v.Op.Asm())
   522  		p.From.Type = obj.TYPE_REG
   523  		p.From.Reg = r1
   524  		p.Reg = r0
   525  		p.To.Type = obj.TYPE_REG
   526  		p.To.Reg = r
   527  
   528  		pbover := s.Prog(obj.AJMP)
   529  		pbover.To.Type = obj.TYPE_BRANCH
   530  
   531  		p = s.Prog(ppc64.ANEG)
   532  		p.To.Type = obj.TYPE_REG
   533  		p.To.Reg = r
   534  		p.From.Type = obj.TYPE_REG
   535  		p.From.Reg = r0
   536  		gc.Patch(pbahead, p)
   537  
   538  		p = s.Prog(obj.ANOP)
   539  		gc.Patch(pbover, p)
   540  
   541  	case ssa.OpPPC64ADD, ssa.OpPPC64FADD, ssa.OpPPC64FADDS, ssa.OpPPC64SUB, ssa.OpPPC64FSUB, ssa.OpPPC64FSUBS,
   542  		ssa.OpPPC64MULLD, ssa.OpPPC64MULLW, ssa.OpPPC64DIVDU, ssa.OpPPC64DIVWU,
   543  		ssa.OpPPC64SRAD, ssa.OpPPC64SRAW, ssa.OpPPC64SRD, ssa.OpPPC64SRW, ssa.OpPPC64SLD, ssa.OpPPC64SLW,
   544  		ssa.OpPPC64MULHD, ssa.OpPPC64MULHW, ssa.OpPPC64MULHDU, ssa.OpPPC64MULHWU,
   545  		ssa.OpPPC64FMUL, ssa.OpPPC64FMULS, ssa.OpPPC64FDIV, ssa.OpPPC64FDIVS,
   546  		ssa.OpPPC64AND, ssa.OpPPC64OR, ssa.OpPPC64ANDN, ssa.OpPPC64ORN, ssa.OpPPC64NOR, ssa.OpPPC64XOR, ssa.OpPPC64EQV:
   547  		r := v.Reg()
   548  		r1 := v.Args[0].Reg()
   549  		r2 := v.Args[1].Reg()
   550  		p := s.Prog(v.Op.Asm())
   551  		p.From.Type = obj.TYPE_REG
   552  		p.From.Reg = r2
   553  		p.Reg = r1
   554  		p.To.Type = obj.TYPE_REG
   555  		p.To.Reg = r
   556  
   557  	case ssa.OpPPC64ROTLconst, ssa.OpPPC64ROTLWconst:
   558  		p := s.Prog(v.Op.Asm())
   559  		p.From.Type = obj.TYPE_CONST
   560  		p.From.Offset = v.AuxInt
   561  		p.Reg = v.Args[0].Reg()
   562  		p.To.Type = obj.TYPE_REG
   563  		p.To.Reg = v.Reg()
   564  
   565  	case ssa.OpPPC64FMADD, ssa.OpPPC64FMADDS, ssa.OpPPC64FMSUB, ssa.OpPPC64FMSUBS:
   566  		r := v.Reg()
   567  		r1 := v.Args[0].Reg()
   568  		r2 := v.Args[1].Reg()
   569  		r3 := v.Args[2].Reg()
   570  		// r = r1*r2 ± r3
   571  		p := s.Prog(v.Op.Asm())
   572  		p.From.Type = obj.TYPE_REG
   573  		p.From.Reg = r1
   574  		p.Reg = r3
   575  		p.From3 = new(obj.Addr)
   576  		p.From3.Type = obj.TYPE_REG
   577  		p.From3.Reg = r2
   578  		p.To.Type = obj.TYPE_REG
   579  		p.To.Reg = r
   580  
   581  	case ssa.OpPPC64MaskIfNotCarry:
   582  		r := v.Reg()
   583  		p := s.Prog(v.Op.Asm())
   584  		p.From.Type = obj.TYPE_REG
   585  		p.From.Reg = ppc64.REGZERO
   586  		p.To.Type = obj.TYPE_REG
   587  		p.To.Reg = r
   588  
   589  	case ssa.OpPPC64ADDconstForCarry:
   590  		r1 := v.Args[0].Reg()
   591  		p := s.Prog(v.Op.Asm())
   592  		p.Reg = r1
   593  		p.From.Type = obj.TYPE_CONST
   594  		p.From.Offset = v.AuxInt
   595  		p.To.Type = obj.TYPE_REG
   596  		p.To.Reg = ppc64.REGTMP // Ignored; this is for the carry effect.
   597  
   598  	case ssa.OpPPC64NEG, ssa.OpPPC64FNEG, ssa.OpPPC64FSQRT, ssa.OpPPC64FSQRTS, ssa.OpPPC64FCTIDZ, ssa.OpPPC64FCTIWZ, ssa.OpPPC64FCFID, ssa.OpPPC64FRSP:
   599  		r := v.Reg()
   600  		p := s.Prog(v.Op.Asm())
   601  		p.To.Type = obj.TYPE_REG
   602  		p.To.Reg = r
   603  		p.From.Type = obj.TYPE_REG
   604  		p.From.Reg = v.Args[0].Reg()
   605  
   606  	case ssa.OpPPC64ADDconst, ssa.OpPPC64ANDconst, ssa.OpPPC64ORconst, ssa.OpPPC64XORconst,
   607  		ssa.OpPPC64SRADconst, ssa.OpPPC64SRAWconst, ssa.OpPPC64SRDconst, ssa.OpPPC64SRWconst, ssa.OpPPC64SLDconst, ssa.OpPPC64SLWconst:
   608  		p := s.Prog(v.Op.Asm())
   609  		p.Reg = v.Args[0].Reg()
   610  
   611  		if v.Aux != nil {
   612  			p.From.Type = obj.TYPE_CONST
   613  			p.From.Offset = gc.AuxOffset(v)
   614  		} else {
   615  			p.From.Type = obj.TYPE_CONST
   616  			p.From.Offset = v.AuxInt
   617  		}
   618  
   619  		p.To.Type = obj.TYPE_REG
   620  		p.To.Reg = v.Reg()
   621  
   622  	case ssa.OpPPC64ANDCCconst:
   623  		p := s.Prog(v.Op.Asm())
   624  		p.Reg = v.Args[0].Reg()
   625  
   626  		if v.Aux != nil {
   627  			p.From.Type = obj.TYPE_CONST
   628  			p.From.Offset = gc.AuxOffset(v)
   629  		} else {
   630  			p.From.Type = obj.TYPE_CONST
   631  			p.From.Offset = v.AuxInt
   632  		}
   633  
   634  		p.To.Type = obj.TYPE_REG
   635  		p.To.Reg = ppc64.REGTMP // discard result
   636  
   637  	case ssa.OpPPC64MOVDaddr:
   638  		p := s.Prog(ppc64.AMOVD)
   639  		p.From.Type = obj.TYPE_ADDR
   640  		p.To.Type = obj.TYPE_REG
   641  		p.To.Reg = v.Reg()
   642  
   643  		var wantreg string
   644  		// Suspect comment, copied from ARM code
   645  		// MOVD $sym+off(base), R
   646  		// the assembler expands it as the following:
   647  		// - base is SP: add constant offset to SP
   648  		//               when constant is large, tmp register (R11) may be used
   649  		// - base is SB: load external address from constant pool (use relocation)
   650  		switch v.Aux.(type) {
   651  		default:
   652  			v.Fatalf("aux is of unknown type %T", v.Aux)
   653  		case *ssa.ExternSymbol:
   654  			wantreg = "SB"
   655  			gc.AddAux(&p.From, v)
   656  		case *ssa.ArgSymbol, *ssa.AutoSymbol:
   657  			wantreg = "SP"
   658  			gc.AddAux(&p.From, v)
   659  		case nil:
   660  			// No sym, just MOVD $off(SP), R
   661  			wantreg = "SP"
   662  			p.From.Reg = ppc64.REGSP
   663  			p.From.Offset = v.AuxInt
   664  		}
   665  		if reg := v.Args[0].RegName(); reg != wantreg {
   666  			v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
   667  		}
   668  
   669  	case ssa.OpPPC64MOVDconst:
   670  		p := s.Prog(v.Op.Asm())
   671  		p.From.Type = obj.TYPE_CONST
   672  		p.From.Offset = v.AuxInt
   673  		p.To.Type = obj.TYPE_REG
   674  		p.To.Reg = v.Reg()
   675  
   676  	case ssa.OpPPC64FMOVDconst, ssa.OpPPC64FMOVSconst:
   677  		p := s.Prog(v.Op.Asm())
   678  		p.From.Type = obj.TYPE_FCONST
   679  		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
   680  		p.To.Type = obj.TYPE_REG
   681  		p.To.Reg = v.Reg()
   682  
   683  	case ssa.OpPPC64FCMPU, ssa.OpPPC64CMP, ssa.OpPPC64CMPW, ssa.OpPPC64CMPU, ssa.OpPPC64CMPWU:
   684  		p := s.Prog(v.Op.Asm())
   685  		p.From.Type = obj.TYPE_REG
   686  		p.From.Reg = v.Args[0].Reg()
   687  		p.To.Type = obj.TYPE_REG
   688  		p.To.Reg = v.Args[1].Reg()
   689  
   690  	case ssa.OpPPC64CMPconst, ssa.OpPPC64CMPUconst, ssa.OpPPC64CMPWconst, ssa.OpPPC64CMPWUconst:
   691  		p := s.Prog(v.Op.Asm())
   692  		p.From.Type = obj.TYPE_REG
   693  		p.From.Reg = v.Args[0].Reg()
   694  		p.To.Type = obj.TYPE_CONST
   695  		p.To.Offset = v.AuxInt
   696  
   697  	case ssa.OpPPC64MOVBreg, ssa.OpPPC64MOVBZreg, ssa.OpPPC64MOVHreg, ssa.OpPPC64MOVHZreg, ssa.OpPPC64MOVWreg, ssa.OpPPC64MOVWZreg:
   698  		// Shift in register to required size
   699  		p := s.Prog(v.Op.Asm())
   700  		p.From.Type = obj.TYPE_REG
   701  		p.From.Reg = v.Args[0].Reg()
   702  		p.To.Reg = v.Reg()
   703  		p.To.Type = obj.TYPE_REG
   704  
   705  	case ssa.OpPPC64MOVDload, ssa.OpPPC64MOVWload, ssa.OpPPC64MOVHload, ssa.OpPPC64MOVWZload, ssa.OpPPC64MOVBZload, ssa.OpPPC64MOVHZload:
   706  		p := s.Prog(v.Op.Asm())
   707  		p.From.Type = obj.TYPE_MEM
   708  		p.From.Reg = v.Args[0].Reg()
   709  		gc.AddAux(&p.From, v)
   710  		p.To.Type = obj.TYPE_REG
   711  		p.To.Reg = v.Reg()
   712  
   713  	case ssa.OpPPC64FMOVDload, ssa.OpPPC64FMOVSload:
   714  		p := s.Prog(v.Op.Asm())
   715  		p.From.Type = obj.TYPE_MEM
   716  		p.From.Reg = v.Args[0].Reg()
   717  		gc.AddAux(&p.From, v)
   718  		p.To.Type = obj.TYPE_REG
   719  		p.To.Reg = v.Reg()
   720  
   721  	case ssa.OpPPC64MOVDstorezero, ssa.OpPPC64MOVWstorezero, ssa.OpPPC64MOVHstorezero, ssa.OpPPC64MOVBstorezero:
   722  		p := s.Prog(v.Op.Asm())
   723  		p.From.Type = obj.TYPE_REG
   724  		p.From.Reg = ppc64.REGZERO
   725  		p.To.Type = obj.TYPE_MEM
   726  		p.To.Reg = v.Args[0].Reg()
   727  		gc.AddAux(&p.To, v)
   728  
   729  	case ssa.OpPPC64MOVDstore, ssa.OpPPC64MOVWstore, ssa.OpPPC64MOVHstore, ssa.OpPPC64MOVBstore:
   730  		p := s.Prog(v.Op.Asm())
   731  		p.From.Type = obj.TYPE_REG
   732  		p.From.Reg = v.Args[1].Reg()
   733  		p.To.Type = obj.TYPE_MEM
   734  		p.To.Reg = v.Args[0].Reg()
   735  		gc.AddAux(&p.To, v)
   736  	case ssa.OpPPC64FMOVDstore, ssa.OpPPC64FMOVSstore:
   737  		p := s.Prog(v.Op.Asm())
   738  		p.From.Type = obj.TYPE_REG
   739  		p.From.Reg = v.Args[1].Reg()
   740  		p.To.Type = obj.TYPE_MEM
   741  		p.To.Reg = v.Args[0].Reg()
   742  		gc.AddAux(&p.To, v)
   743  
   744  	case ssa.OpPPC64Equal,
   745  		ssa.OpPPC64NotEqual,
   746  		ssa.OpPPC64LessThan,
   747  		ssa.OpPPC64FLessThan,
   748  		ssa.OpPPC64LessEqual,
   749  		ssa.OpPPC64GreaterThan,
   750  		ssa.OpPPC64FGreaterThan,
   751  		ssa.OpPPC64GreaterEqual:
   752  
   753  		// On Power7 or later, can use isel instruction:
   754  		// for a < b, a > b, a = b:
   755  		//   rtmp := 1
   756  		//   isel rt,rtmp,r0,cond // rt is target in ppc asm
   757  
   758  		// for  a >= b, a <= b, a != b:
   759  		//   rtmp := 1
   760  		//   isel rt,0,rtmp,!cond // rt is target in ppc asm
   761  
   762  		p := s.Prog(ppc64.AMOVD)
   763  		p.From.Type = obj.TYPE_CONST
   764  		p.From.Offset = 1
   765  		p.To.Type = obj.TYPE_REG
   766  		p.To.Reg = iselRegs[1]
   767  		iop := iselOps[v.Op]
   768  		ssaGenISEL(s, v, iop.cond, iselRegs[iop.valueIfCond], iselRegs[1-iop.valueIfCond])
   769  
   770  	case ssa.OpPPC64FLessEqual, // These include a second branch for EQ -- dealing with NaN prevents REL= to !REL conversion
   771  		ssa.OpPPC64FGreaterEqual:
   772  
   773  		p := s.Prog(ppc64.AMOVD)
   774  		p.From.Type = obj.TYPE_CONST
   775  		p.From.Offset = 1
   776  		p.To.Type = obj.TYPE_REG
   777  		p.To.Reg = iselRegs[1]
   778  		iop := iselOps[v.Op]
   779  		ssaGenISEL(s, v, iop.cond, iselRegs[iop.valueIfCond], iselRegs[1-iop.valueIfCond])
   780  		ssaGenISEL(s, v, ppc64.C_COND_EQ, iselRegs[1], v.Reg())
   781  
   782  	case ssa.OpPPC64LoweredZero:
   783  
   784  		// unaligned data doesn't hurt performance
   785  		// for these instructions on power8 or later
   786  
   787  		// for sizes >= 64 generate a loop as follows:
   788  
   789  		// set up loop counter in CTR, used by BC
   790  		//	 MOVD len/32,REG_TMP
   791  		//	 MOVD REG_TMP,CTR
   792  		//	 loop:
   793  		//	 MOVD R0,(R3)
   794  		//	 MOVD R0,8(R3)
   795  		//	 MOVD R0,16(R3)
   796  		//	 MOVD R0,24(R3)
   797  		//	 ADD  $32,R3
   798  		//	 BC   16, 0, loop
   799  		//
   800  		// any remainder is done as described below
   801  
   802  		// for sizes < 64 bytes, first clear as many doublewords as possible,
   803  		// then handle the remainder
   804  		//	MOVD R0,(R3)
   805  		//	MOVD R0,8(R3)
   806  		// .... etc.
   807  		//
   808  		// the remainder bytes are cleared using one or more
   809  		// of the following instructions with the appropriate
   810  		// offsets depending which instructions are needed
   811  		//
   812  		//	MOVW R0,n1(R3)	4 bytes
   813  		//	MOVH R0,n2(R3)	2 bytes
   814  		//	MOVB R0,n3(R3)	1 byte
   815  		//
   816  		// 7 bytes: MOVW, MOVH, MOVB
   817  		// 6 bytes: MOVW, MOVH
   818  		// 5 bytes: MOVW, MOVB
   819  		// 3 bytes: MOVH, MOVB
   820  
   821  		// each loop iteration does 32 bytes
   822  		ctr := v.AuxInt / 32
   823  
   824  		// remainder bytes
   825  		rem := v.AuxInt % 32
   826  
   827  		// only generate a loop if there is more
   828  		// than 1 iteration.
   829  		if ctr > 1 {
   830  			// Set up CTR loop counter
   831  			p := s.Prog(ppc64.AMOVD)
   832  			p.From.Type = obj.TYPE_CONST
   833  			p.From.Offset = ctr
   834  			p.To.Type = obj.TYPE_REG
   835  			p.To.Reg = ppc64.REGTMP
   836  
   837  			p = s.Prog(ppc64.AMOVD)
   838  			p.From.Type = obj.TYPE_REG
   839  			p.From.Reg = ppc64.REGTMP
   840  			p.To.Type = obj.TYPE_REG
   841  			p.To.Reg = ppc64.REG_CTR
   842  
   843  			// generate 4 MOVDs
   844  			// when this is a loop then the top must be saved
   845  			var top *obj.Prog
   846  			for offset := int64(0); offset < 32; offset += 8 {
   847  				// This is the top of loop
   848  				p := s.Prog(ppc64.AMOVD)
   849  				p.From.Type = obj.TYPE_REG
   850  				p.From.Reg = ppc64.REG_R0
   851  				p.To.Type = obj.TYPE_MEM
   852  				p.To.Reg = v.Args[0].Reg()
   853  				p.To.Offset = offset
   854  				// Save the top of loop
   855  				if top == nil {
   856  					top = p
   857  				}
   858  			}
   859  
   860  			// Increment address for the
   861  			// 4 doublewords just zeroed.
   862  			p = s.Prog(ppc64.AADD)
   863  			p.Reg = v.Args[0].Reg()
   864  			p.From.Type = obj.TYPE_CONST
   865  			p.From.Offset = 32
   866  			p.To.Type = obj.TYPE_REG
   867  			p.To.Reg = v.Args[0].Reg()
   868  
   869  			// Branch back to top of loop
   870  			// based on CTR
   871  			// BC with BO_BCTR generates bdnz
   872  			p = s.Prog(ppc64.ABC)
   873  			p.From.Type = obj.TYPE_CONST
   874  			p.From.Offset = ppc64.BO_BCTR
   875  			p.Reg = ppc64.REG_R0
   876  			p.To.Type = obj.TYPE_BRANCH
   877  			gc.Patch(p, top)
   878  		}
   879  
   880  		// when ctr == 1 the loop was not generated but
   881  		// there are at least 32 bytes to clear, so add
   882  		// that to the remainder to generate the code
   883  		// to clear those doublewords
   884  		if ctr == 1 {
   885  			rem += 32
   886  		}
   887  
   888  		// clear the remainder starting at offset zero
   889  		offset := int64(0)
   890  
   891  		// first clear as many doublewords as possible
   892  		// then clear remaining sizes as available
   893  		for rem > 0 {
   894  			op, size := ppc64.AMOVB, int64(1)
   895  			switch {
   896  			case rem >= 8:
   897  				op, size = ppc64.AMOVD, 8
   898  			case rem >= 4:
   899  				op, size = ppc64.AMOVW, 4
   900  			case rem >= 2:
   901  				op, size = ppc64.AMOVH, 2
   902  			}
   903  			p := s.Prog(op)
   904  			p.From.Type = obj.TYPE_REG
   905  			p.From.Reg = ppc64.REG_R0
   906  			p.To.Type = obj.TYPE_MEM
   907  			p.To.Reg = v.Args[0].Reg()
   908  			p.To.Offset = offset
   909  			rem -= size
   910  			offset += size
   911  		}
   912  
   913  	case ssa.OpPPC64LoweredMove:
   914  
   915  		// This will be used when moving more
   916  		// than 8 bytes.  Moves start with as
   917  		// as many 8 byte moves as possible, then
   918  		// 4, 2, or 1 byte(s) as remaining.  This will
   919  		// work and be efficient for power8 or later.
   920  		// If there are 64 or more bytes, then a
   921  		// loop is generated to move 32 bytes and
   922  		// update the src and dst addresses on each
   923  		// iteration. When < 64 bytes, the appropriate
   924  		// number of moves are generated based on the
   925  		// size.
   926  		// When moving >= 64 bytes a loop is used
   927  		//	MOVD len/32,REG_TMP
   928  		//	MOVD REG_TMP,CTR
   929  		// top:
   930  		//	MOVD (R4),R7
   931  		//	MOVD 8(R4),R8
   932  		//	MOVD 16(R4),R9
   933  		//	MOVD 24(R4),R10
   934  		//	ADD  R4,$32
   935  		//	MOVD R7,(R3)
   936  		//	MOVD R8,8(R3)
   937  		//	MOVD R9,16(R3)
   938  		//	MOVD R10,24(R3)
   939  		//	ADD  R3,$32
   940  		//	BC 16,0,top
   941  		// Bytes not moved by this loop are moved
   942  		// with a combination of the following instructions,
   943  		// starting with the largest sizes and generating as
   944  		// many as needed, using the appropriate offset value.
   945  		//	MOVD  n(R4),R7
   946  		//	MOVD  R7,n(R3)
   947  		//	MOVW  n1(R4),R7
   948  		//	MOVW  R7,n1(R3)
   949  		//	MOVH  n2(R4),R7
   950  		//	MOVH  R7,n2(R3)
   951  		//	MOVB  n3(R4),R7
   952  		//	MOVB  R7,n3(R3)
   953  
   954  		// Each loop iteration moves 32 bytes
   955  		ctr := v.AuxInt / 32
   956  
   957  		// Remainder after the loop
   958  		rem := v.AuxInt % 32
   959  
   960  		dst_reg := v.Args[0].Reg()
   961  		src_reg := v.Args[1].Reg()
   962  
   963  		// The set of registers used here, must match the clobbered reg list
   964  		// in PPC64Ops.go.
   965  		useregs := []int16{ppc64.REG_R7, ppc64.REG_R8, ppc64.REG_R9, ppc64.REG_R10}
   966  		offset := int64(0)
   967  
   968  		// top of the loop
   969  		var top *obj.Prog
   970  		// Only generate looping code when loop counter is > 1 for >= 64 bytes
   971  		if ctr > 1 {
   972  			// Set up the CTR
   973  			p := s.Prog(ppc64.AMOVD)
   974  			p.From.Type = obj.TYPE_CONST
   975  			p.From.Offset = ctr
   976  			p.To.Type = obj.TYPE_REG
   977  			p.To.Reg = ppc64.REGTMP
   978  
   979  			p = s.Prog(ppc64.AMOVD)
   980  			p.From.Type = obj.TYPE_REG
   981  			p.From.Reg = ppc64.REGTMP
   982  			p.To.Type = obj.TYPE_REG
   983  			p.To.Reg = ppc64.REG_CTR
   984  
   985  			// Generate all the MOVDs for loads
   986  			// based off the same register, increasing
   987  			// the offset by 8 for each instruction
   988  			for _, rg := range useregs {
   989  				p := s.Prog(ppc64.AMOVD)
   990  				p.From.Type = obj.TYPE_MEM
   991  				p.From.Reg = src_reg
   992  				p.From.Offset = offset
   993  				p.To.Type = obj.TYPE_REG
   994  				p.To.Reg = rg
   995  				if top == nil {
   996  					top = p
   997  				}
   998  				offset += 8
   999  			}
  1000  			// increment the src_reg for next iteration
  1001  			p = s.Prog(ppc64.AADD)
  1002  			p.Reg = src_reg
  1003  			p.From.Type = obj.TYPE_CONST
  1004  			p.From.Offset = 32
  1005  			p.To.Type = obj.TYPE_REG
  1006  			p.To.Reg = src_reg
  1007  
  1008  			// generate the MOVDs for stores, based
  1009  			// off the same register, using the same
  1010  			// offsets as in the loads.
  1011  			offset = int64(0)
  1012  			for _, rg := range useregs {
  1013  				p := s.Prog(ppc64.AMOVD)
  1014  				p.From.Type = obj.TYPE_REG
  1015  				p.From.Reg = rg
  1016  				p.To.Type = obj.TYPE_MEM
  1017  				p.To.Reg = dst_reg
  1018  				p.To.Offset = offset
  1019  				offset += 8
  1020  			}
  1021  			// increment the dst_reg for next iteration
  1022  			p = s.Prog(ppc64.AADD)
  1023  			p.Reg = dst_reg
  1024  			p.From.Type = obj.TYPE_CONST
  1025  			p.From.Offset = 32
  1026  			p.To.Type = obj.TYPE_REG
  1027  			p.To.Reg = dst_reg
  1028  
  1029  			// BC with BO_BCTR generates bdnz to branch on nonzero CTR
  1030  			// to loop top.
  1031  			p = s.Prog(ppc64.ABC)
  1032  			p.From.Type = obj.TYPE_CONST
  1033  			p.From.Offset = ppc64.BO_BCTR
  1034  			p.Reg = ppc64.REG_R0
  1035  			p.To.Type = obj.TYPE_BRANCH
  1036  			gc.Patch(p, top)
  1037  
  1038  			// src_reg and dst_reg were incremented in the loop, so
  1039  			// later instructions start with offset 0.
  1040  			offset = int64(0)
  1041  		}
  1042  
  1043  		// No loop was generated for one iteration, so
  1044  		// add 32 bytes to the remainder to move those bytes.
  1045  		if ctr == 1 {
  1046  			rem += 32
  1047  		}
  1048  
  1049  		// Generate all the remaining load and store pairs, starting with
  1050  		// as many 8 byte moves as possible, then 4, 2, 1.
  1051  		for rem > 0 {
  1052  			op, size := ppc64.AMOVB, int64(1)
  1053  			switch {
  1054  			case rem >= 8:
  1055  				op, size = ppc64.AMOVD, 8
  1056  			case rem >= 4:
  1057  				op, size = ppc64.AMOVW, 4
  1058  			case rem >= 2:
  1059  				op, size = ppc64.AMOVH, 2
  1060  			}
  1061  			// Load
  1062  			p := s.Prog(op)
  1063  			p.To.Type = obj.TYPE_REG
  1064  			p.To.Reg = ppc64.REG_R7
  1065  			p.From.Type = obj.TYPE_MEM
  1066  			p.From.Reg = src_reg
  1067  			p.From.Offset = offset
  1068  
  1069  			// Store
  1070  			p = s.Prog(op)
  1071  			p.From.Type = obj.TYPE_REG
  1072  			p.From.Reg = ppc64.REG_R7
  1073  			p.To.Type = obj.TYPE_MEM
  1074  			p.To.Reg = dst_reg
  1075  			p.To.Offset = offset
  1076  			rem -= size
  1077  			offset += size
  1078  		}
  1079  
  1080  	case ssa.OpPPC64CALLstatic:
  1081  		s.Call(v)
  1082  
  1083  	case ssa.OpPPC64CALLclosure, ssa.OpPPC64CALLinter:
  1084  		p := s.Prog(ppc64.AMOVD)
  1085  		p.From.Type = obj.TYPE_REG
  1086  		p.From.Reg = v.Args[0].Reg()
  1087  		p.To.Type = obj.TYPE_REG
  1088  		p.To.Reg = ppc64.REG_CTR
  1089  
  1090  		if gc.Ctxt.Flag_shared && p.From.Reg != ppc64.REG_R12 {
  1091  			// Make sure function pointer is in R12 as well when
  1092  			// compiling Go into PIC.
  1093  			// TODO(mwhudson): it would obviously be better to
  1094  			// change the register allocation to put the value in
  1095  			// R12 already, but I don't know how to do that.
  1096  			// TODO: We have the technology now to implement TODO above.
  1097  			q := s.Prog(ppc64.AMOVD)
  1098  			q.From = p.From
  1099  			q.To.Type = obj.TYPE_REG
  1100  			q.To.Reg = ppc64.REG_R12
  1101  		}
  1102  
  1103  		pp := s.Call(v)
  1104  		pp.To.Reg = ppc64.REG_CTR
  1105  
  1106  		if gc.Ctxt.Flag_shared {
  1107  			// When compiling Go into PIC, the function we just
  1108  			// called via pointer might have been implemented in
  1109  			// a separate module and so overwritten the TOC
  1110  			// pointer in R2; reload it.
  1111  			q := s.Prog(ppc64.AMOVD)
  1112  			q.From.Type = obj.TYPE_MEM
  1113  			q.From.Offset = 24
  1114  			q.From.Reg = ppc64.REGSP
  1115  			q.To.Type = obj.TYPE_REG
  1116  			q.To.Reg = ppc64.REG_R2
  1117  		}
  1118  
  1119  	case ssa.OpPPC64LoweredNilCheck:
  1120  		// Issue a load which will fault if arg is nil.
  1121  		p := s.Prog(ppc64.AMOVBZ)
  1122  		p.From.Type = obj.TYPE_MEM
  1123  		p.From.Reg = v.Args[0].Reg()
  1124  		gc.AddAux(&p.From, v)
  1125  		p.To.Type = obj.TYPE_REG
  1126  		p.To.Reg = ppc64.REGTMP
  1127  		if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
  1128  			gc.Warnl(v.Pos, "generated nil check")
  1129  		}
  1130  
  1131  	case ssa.OpPPC64InvertFlags:
  1132  		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
  1133  	case ssa.OpPPC64FlagEQ, ssa.OpPPC64FlagLT, ssa.OpPPC64FlagGT:
  1134  		v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
  1135  	case ssa.OpClobber:
  1136  		// TODO: implement for clobberdead experiment. Nop is ok for now.
  1137  	default:
  1138  		v.Fatalf("genValue not implemented: %s", v.LongString())
  1139  	}
  1140  }
  1141  
  1142  var blockJump = [...]struct {
  1143  	asm, invasm     obj.As
  1144  	asmeq, invasmun bool
  1145  }{
  1146  	ssa.BlockPPC64EQ: {ppc64.ABEQ, ppc64.ABNE, false, false},
  1147  	ssa.BlockPPC64NE: {ppc64.ABNE, ppc64.ABEQ, false, false},
  1148  
  1149  	ssa.BlockPPC64LT: {ppc64.ABLT, ppc64.ABGE, false, false},
  1150  	ssa.BlockPPC64GE: {ppc64.ABGE, ppc64.ABLT, false, false},
  1151  	ssa.BlockPPC64LE: {ppc64.ABLE, ppc64.ABGT, false, false},
  1152  	ssa.BlockPPC64GT: {ppc64.ABGT, ppc64.ABLE, false, false},
  1153  
  1154  	// TODO: need to work FP comparisons into block jumps
  1155  	ssa.BlockPPC64FLT: {ppc64.ABLT, ppc64.ABGE, false, false},
  1156  	ssa.BlockPPC64FGE: {ppc64.ABGT, ppc64.ABLT, true, true}, // GE = GT or EQ; !GE = LT or UN
  1157  	ssa.BlockPPC64FLE: {ppc64.ABLT, ppc64.ABGT, true, true}, // LE = LT or EQ; !LE = GT or UN
  1158  	ssa.BlockPPC64FGT: {ppc64.ABGT, ppc64.ABLE, false, false},
  1159  }
  1160  
  1161  func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
  1162  	switch b.Kind {
  1163  	case ssa.BlockDefer:
  1164  		// defer returns in R3:
  1165  		// 0 if we should continue executing
  1166  		// 1 if we should jump to deferreturn call
  1167  		p := s.Prog(ppc64.ACMP)
  1168  		p.From.Type = obj.TYPE_REG
  1169  		p.From.Reg = ppc64.REG_R3
  1170  		p.To.Type = obj.TYPE_REG
  1171  		p.To.Reg = ppc64.REG_R0
  1172  
  1173  		p = s.Prog(ppc64.ABNE)
  1174  		p.To.Type = obj.TYPE_BRANCH
  1175  		s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
  1176  		if b.Succs[0].Block() != next {
  1177  			p := s.Prog(obj.AJMP)
  1178  			p.To.Type = obj.TYPE_BRANCH
  1179  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
  1180  		}
  1181  
  1182  	case ssa.BlockPlain:
  1183  		if b.Succs[0].Block() != next {
  1184  			p := s.Prog(obj.AJMP)
  1185  			p.To.Type = obj.TYPE_BRANCH
  1186  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
  1187  		}
  1188  	case ssa.BlockExit:
  1189  		s.Prog(obj.AUNDEF) // tell plive.go that we never reach here
  1190  	case ssa.BlockRet:
  1191  		s.Prog(obj.ARET)
  1192  	case ssa.BlockRetJmp:
  1193  		p := s.Prog(obj.AJMP)
  1194  		p.To.Type = obj.TYPE_MEM
  1195  		p.To.Name = obj.NAME_EXTERN
  1196  		p.To.Sym = b.Aux.(*obj.LSym)
  1197  
  1198  	case ssa.BlockPPC64EQ, ssa.BlockPPC64NE,
  1199  		ssa.BlockPPC64LT, ssa.BlockPPC64GE,
  1200  		ssa.BlockPPC64LE, ssa.BlockPPC64GT,
  1201  		ssa.BlockPPC64FLT, ssa.BlockPPC64FGE,
  1202  		ssa.BlockPPC64FLE, ssa.BlockPPC64FGT:
  1203  		jmp := blockJump[b.Kind]
  1204  		var p *obj.Prog
  1205  		switch next {
  1206  		case b.Succs[0].Block():
  1207  			p = s.Prog(jmp.invasm)
  1208  			p.To.Type = obj.TYPE_BRANCH
  1209  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
  1210  			if jmp.invasmun {
  1211  				// TODO: The second branch is probably predict-not-taken since it is for FP unordered
  1212  				q := s.Prog(ppc64.ABVS)
  1213  				q.To.Type = obj.TYPE_BRANCH
  1214  				s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
  1215  			}
  1216  		case b.Succs[1].Block():
  1217  			p = s.Prog(jmp.asm)
  1218  			p.To.Type = obj.TYPE_BRANCH
  1219  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
  1220  			if jmp.asmeq {
  1221  				q := s.Prog(ppc64.ABEQ)
  1222  				q.To.Type = obj.TYPE_BRANCH
  1223  				s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[0].Block()})
  1224  			}
  1225  		default:
  1226  			p = s.Prog(jmp.asm)
  1227  			p.To.Type = obj.TYPE_BRANCH
  1228  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
  1229  			if jmp.asmeq {
  1230  				q := s.Prog(ppc64.ABEQ)
  1231  				q.To.Type = obj.TYPE_BRANCH
  1232  				s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[0].Block()})
  1233  			}
  1234  			q := s.Prog(obj.AJMP)
  1235  			q.To.Type = obj.TYPE_BRANCH
  1236  			s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
  1237  		}
  1238  
  1239  	default:
  1240  		b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
  1241  	}
  1242  }