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