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