github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/src/cmd/compile/internal/ssa/gen/PPC64Ops.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  // +build ignore
     6  
     7  package main
     8  
     9  import "strings"
    10  
    11  // Notes:
    12  //  - Less-than-64-bit integer types live in the low portion of registers.
    13  //    For now, the upper portion is junk; sign/zero-extension might be optimized in the future, but not yet.
    14  //  - Boolean types are zero or 1; stored in a byte, but loaded with AMOVBZ so the upper bytes of a register are zero.
    15  //  - *const instructions may use a constant larger than the instruction can encode.
    16  //    In this case the assembler expands to multiple instructions and uses tmp
    17  //    register (R31).
    18  
    19  var regNamesPPC64 = []string{
    20  	"R0", // REGZERO, not used, but simplifies counting in regalloc
    21  	"SP", // REGSP
    22  	"SB", // REGSB
    23  	"R3",
    24  	"R4",
    25  	"R5",
    26  	"R6",
    27  	"R7",
    28  	"R8",
    29  	"R9",
    30  	"R10",
    31  	"R11", // REGCTXT for closures
    32  	"R12",
    33  	"R13", // REGTLS
    34  	"R14",
    35  	"R15",
    36  	"R16",
    37  	"R17",
    38  	"R18",
    39  	"R19",
    40  	"R20",
    41  	"R21",
    42  	"R22",
    43  	"R23",
    44  	"R24",
    45  	"R25",
    46  	"R26",
    47  	"R27",
    48  	"R28",
    49  	"R29",
    50  	"g",   // REGG.  Using name "g" and setting Config.hasGReg makes it "just happen".
    51  	"R31", // REGTMP
    52  
    53  	"F0",
    54  	"F1",
    55  	"F2",
    56  	"F3",
    57  	"F4",
    58  	"F5",
    59  	"F6",
    60  	"F7",
    61  	"F8",
    62  	"F9",
    63  	"F10",
    64  	"F11",
    65  	"F12",
    66  	"F13",
    67  	"F14",
    68  	"F15",
    69  	"F16",
    70  	"F17",
    71  	"F18",
    72  	"F19",
    73  	"F20",
    74  	"F21",
    75  	"F22",
    76  	"F23",
    77  	"F24",
    78  	"F25",
    79  	"F26",
    80  	"F27",
    81  	"F28",
    82  	"F29",
    83  	"F30",
    84  	"F31",
    85  
    86  	// "CR0",
    87  	// "CR1",
    88  	// "CR2",
    89  	// "CR3",
    90  	// "CR4",
    91  	// "CR5",
    92  	// "CR6",
    93  	// "CR7",
    94  
    95  	// "CR",
    96  	// "XER",
    97  	// "LR",
    98  	// "CTR",
    99  }
   100  
   101  func init() {
   102  	// Make map from reg names to reg integers.
   103  	if len(regNamesPPC64) > 64 {
   104  		panic("too many registers")
   105  	}
   106  	num := map[string]int{}
   107  	for i, name := range regNamesPPC64 {
   108  		num[name] = i
   109  	}
   110  	buildReg := func(s string) regMask {
   111  		m := regMask(0)
   112  		for _, r := range strings.Split(s, " ") {
   113  			if n, ok := num[r]; ok {
   114  				m |= regMask(1) << uint(n)
   115  				continue
   116  			}
   117  			panic("register " + r + " not found")
   118  		}
   119  		return m
   120  	}
   121  
   122  	var (
   123  		gp = buildReg("R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29")
   124  		fp = buildReg("F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26")
   125  		sp = buildReg("SP")
   126  		sb = buildReg("SB")
   127  		gr = buildReg("g")
   128  		// cr  = buildReg("CR")
   129  		// ctr = buildReg("CTR")
   130  		// lr  = buildReg("LR")
   131  		tmp  = buildReg("R31")
   132  		ctxt = buildReg("R11")
   133  		// tls = buildReg("R13")
   134  		gp01        = regInfo{inputs: nil, outputs: []regMask{gp}}
   135  		gp11        = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}
   136  		gp21        = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}}
   137  		gp1cr       = regInfo{inputs: []regMask{gp | sp | sb}}
   138  		gp2cr       = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}}
   139  		crgp        = regInfo{inputs: nil, outputs: []regMask{gp}}
   140  		gpload      = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}
   141  		gpstore     = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}}
   142  		gpstorezero = regInfo{inputs: []regMask{gp | sp | sb}} // ppc64.REGZERO is reserved zero value
   143  		gpxchg      = regInfo{inputs: []regMask{gp | sp | sb, gp}, outputs: []regMask{gp}}
   144  		gpcas       = regInfo{inputs: []regMask{gp | sp | sb, gp, gp}, outputs: []regMask{gp}}
   145  		fp01        = regInfo{inputs: nil, outputs: []regMask{fp}}
   146  		fp11        = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
   147  		fpgp        = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
   148  		gpfp        = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}
   149  		fp21        = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
   150  		fp31        = regInfo{inputs: []regMask{fp, fp, fp}, outputs: []regMask{fp}}
   151  		fp2cr       = regInfo{inputs: []regMask{fp, fp}}
   152  		fpload      = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{fp}}
   153  		fpstore     = regInfo{inputs: []regMask{gp | sp | sb, fp}}
   154  		callerSave  = regMask(gp | fp | gr)
   155  	)
   156  	ops := []opData{
   157  		{name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true},                     // arg0 + arg1
   158  		{name: "ADDconst", argLength: 1, reg: gp11, asm: "ADD", aux: "SymOff", symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym)
   159  		{name: "FADD", argLength: 2, reg: fp21, asm: "FADD", commutative: true},                   // arg0+arg1
   160  		{name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true},                 // arg0+arg1
   161  		{name: "SUB", argLength: 2, reg: gp21, asm: "SUB"},                                        // arg0-arg1
   162  		{name: "FSUB", argLength: 2, reg: fp21, asm: "FSUB"},                                      // arg0-arg1
   163  		{name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS"},                                    // arg0-arg1
   164  
   165  		{name: "MULLD", argLength: 2, reg: gp21, asm: "MULLD", typ: "Int64", commutative: true}, // arg0*arg1 (signed 64-bit)
   166  		{name: "MULLW", argLength: 2, reg: gp21, asm: "MULLW", typ: "Int32", commutative: true}, // arg0*arg1 (signed 32-bit)
   167  
   168  		{name: "MULHD", argLength: 2, reg: gp21, asm: "MULHD", commutative: true},   // (arg0 * arg1) >> 64, signed
   169  		{name: "MULHW", argLength: 2, reg: gp21, asm: "MULHW", commutative: true},   // (arg0 * arg1) >> 32, signed
   170  		{name: "MULHDU", argLength: 2, reg: gp21, asm: "MULHDU", commutative: true}, // (arg0 * arg1) >> 64, unsigned
   171  		{name: "MULHWU", argLength: 2, reg: gp21, asm: "MULHWU", commutative: true}, // (arg0 * arg1) >> 32, unsigned
   172  
   173  		{name: "FMUL", argLength: 2, reg: fp21, asm: "FMUL", commutative: true},   // arg0*arg1
   174  		{name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true}, // arg0*arg1
   175  
   176  		{name: "FMADD", argLength: 3, reg: fp31, asm: "FMADD"},   // arg0*arg1 + arg2
   177  		{name: "FMADDS", argLength: 3, reg: fp31, asm: "FMADDS"}, // arg0*arg1 + arg2
   178  		{name: "FMSUB", argLength: 3, reg: fp31, asm: "FMSUB"},   // arg0*arg1 - arg2
   179  		{name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS"}, // arg0*arg1 - arg2
   180  
   181  		{name: "SRAD", argLength: 2, reg: gp21, asm: "SRAD"}, // arg0 >>a arg1, 64 bits (all sign if arg1 & 64 != 0)
   182  		{name: "SRAW", argLength: 2, reg: gp21, asm: "SRAW"}, // arg0 >>a arg1, 32 bits (all sign if arg1 & 32 != 0)
   183  		{name: "SRD", argLength: 2, reg: gp21, asm: "SRD"},   // arg0 >> arg1, 64 bits  (0 if arg1 & 64 != 0)
   184  		{name: "SRW", argLength: 2, reg: gp21, asm: "SRW"},   // arg0 >> arg1, 32 bits  (0 if arg1 & 32 != 0)
   185  		{name: "SLD", argLength: 2, reg: gp21, asm: "SLD"},   // arg0 << arg1, 64 bits  (0 if arg1 & 64 != 0)
   186  		{name: "SLW", argLength: 2, reg: gp21, asm: "SLW"},   // arg0 << arg1, 32 bits  (0 if arg1 & 32 != 0)
   187  
   188  		{name: "ADDconstForCarry", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, aux: "Int16", asm: "ADDC", typ: "Flags"}, // _, carry := arg0 + aux
   189  		{name: "MaskIfNotCarry", argLength: 1, reg: crgp, asm: "ADDME", typ: "Int64"},                                                                   // carry - 1 (if carry then 0 else -1)
   190  
   191  		{name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int64"}, // arg0 >>a aux, 64 bits
   192  		{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int64"}, // arg0 >>a aux, 32 bits
   193  		{name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"},   // arg0 >> aux, 64 bits
   194  		{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int64"},   // arg0 >> aux, 32 bits
   195  		{name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int64"},   // arg0 << aux, 64 bits
   196  		{name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int64"},   // arg0 << aux, 32 bits
   197  
   198  		{name: "ROTLconst", argLength: 1, reg: gp11, asm: "ROTL", aux: "Int64"},   // arg0 rotate left by auxInt bits
   199  		{name: "ROTLWconst", argLength: 1, reg: gp11, asm: "ROTLW", aux: "Int64"}, // uint32(arg0) rotate left by auxInt bits
   200  
   201  		{name: "FDIV", argLength: 2, reg: fp21, asm: "FDIV"},   // arg0/arg1
   202  		{name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS"}, // arg0/arg1
   203  
   204  		{name: "DIVD", argLength: 2, reg: gp21, asm: "DIVD", typ: "Int64"},   // arg0/arg1 (signed 64-bit)
   205  		{name: "DIVW", argLength: 2, reg: gp21, asm: "DIVW", typ: "Int32"},   // arg0/arg1 (signed 32-bit)
   206  		{name: "DIVDU", argLength: 2, reg: gp21, asm: "DIVDU", typ: "Int64"}, // arg0/arg1 (unsigned 64-bit)
   207  		{name: "DIVWU", argLength: 2, reg: gp21, asm: "DIVWU", typ: "Int32"}, // arg0/arg1 (unsigned 32-bit)
   208  
   209  		// MOD is implemented as rem := arg0 - (arg0/arg1) * arg1
   210  
   211  		// Conversions are all float-to-float register operations.  "Integer" refers to encoding in the FP register.
   212  		{name: "FCTIDZ", argLength: 1, reg: fp11, asm: "FCTIDZ", typ: "Float64"}, // convert float to 64-bit int round towards zero
   213  		{name: "FCTIWZ", argLength: 1, reg: fp11, asm: "FCTIWZ", typ: "Float64"}, // convert float to 32-bit int round towards zero
   214  		{name: "FCFID", argLength: 1, reg: fp11, asm: "FCFID", typ: "Float64"},   // convert 64-bit integer to float
   215  		{name: "FRSP", argLength: 1, reg: fp11, asm: "FRSP", typ: "Float64"},     // round float to 32-bit value
   216  
   217  		// Movement between float and integer registers with no change in bits; accomplished with stores+loads on PPC.
   218  		// Because the 32-bit load-literal-bits instructions have impoverished addressability, always widen the
   219  		// data instead and use FMOVDload and FMOVDstore instead (this will also dodge endianess issues).
   220  		// There are optimizations that should apply -- (Xi2f64 (MOVWload (not-ADD-ptr+offset) ) ) could use
   221  		// the word-load instructions.  (Xi2f64 (MOVDload ptr )) can be (FMOVDload ptr)
   222  
   223  		{name: "Xf2i64", argLength: 1, reg: fpgp, typ: "Int64"},   // move 64 bits of F register into G register
   224  		{name: "Xi2f64", argLength: 1, reg: gpfp, typ: "Float64"}, // move 64 bits of G register into F register
   225  
   226  		{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true},               // arg0&arg1
   227  		{name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"},                                // arg0&^arg1
   228  		{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},                 // arg0|arg1
   229  		{name: "ORN", argLength: 2, reg: gp21, asm: "ORN"},                                  // arg0|^arg1
   230  		{name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true},               // ^(arg0|arg1)
   231  		{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", typ: "Int64", commutative: true}, // arg0^arg1
   232  		{name: "EQV", argLength: 2, reg: gp21, asm: "EQV", typ: "Int64", commutative: true}, // arg0^^arg1
   233  		{name: "NEG", argLength: 1, reg: gp11, asm: "NEG"},                                  // -arg0 (integer)
   234  		{name: "FNEG", argLength: 1, reg: fp11, asm: "FNEG"},                                // -arg0 (floating point)
   235  		{name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"},                              // sqrt(arg0) (floating point)
   236  		{name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"},                            // sqrt(arg0) (floating point, single precision)
   237  
   238  		{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"},                                                                                     // arg0|aux
   239  		{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64"},                                                                                   // arg0^aux
   240  		{name: "ANDconst", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}, asm: "ANDCC", aux: "Int64", clobberFlags: true}, // arg0&aux // and-immediate sets CC on PPC, always.
   241  		{name: "ANDCCconst", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}}, asm: "ANDCC", aux: "Int64", typ: "Flags"},                             // arg0&aux == 0 // and-immediate sets CC on PPC, always.
   242  
   243  		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB", typ: "Int64"},                                                               // sign extend int8 to int64
   244  		{name: "MOVBZreg", argLength: 1, reg: gp11, asm: "MOVBZ", typ: "Int64"},                                                             // zero extend uint8 to uint64
   245  		{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH", typ: "Int64"},                                                               // sign extend int16 to int64
   246  		{name: "MOVHZreg", argLength: 1, reg: gp11, asm: "MOVHZ", typ: "Int64"},                                                             // zero extend uint16 to uint64
   247  		{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW", typ: "Int64"},                                                               // sign extend int32 to int64
   248  		{name: "MOVWZreg", argLength: 1, reg: gp11, asm: "MOVWZ", typ: "Int64"},                                                             // zero extend uint32 to uint64
   249  		{name: "MOVBZload", argLength: 2, reg: gpload, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // zero extend uint8 to uint64
   250  		{name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // sign extend int16 to int64
   251  		{name: "MOVHZload", argLength: 2, reg: gpload, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // zero extend uint16 to uint64
   252  		{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"},    // sign extend int32 to int64
   253  		{name: "MOVWZload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // zero extend uint32 to uint64
   254  		{name: "MOVDload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", typ: "Int64", faultOnNilArg0: true, symEffect: "Read"},
   255  
   256  		{name: "FMOVDload", argLength: 2, reg: fpload, asm: "FMOVD", aux: "SymOff", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"},
   257  		{name: "FMOVSload", argLength: 2, reg: fpload, asm: "FMOVS", aux: "SymOff", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"},
   258  		{name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
   259  		{name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
   260  		{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
   261  		{name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
   262  		{name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "FMOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
   263  		{name: "FMOVSstore", argLength: 3, reg: fpstore, asm: "FMOVS", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
   264  
   265  		{name: "MOVBstorezero", argLength: 2, reg: gpstorezero, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero byte to arg0+aux.  arg1=mem
   266  		{name: "MOVHstorezero", argLength: 2, reg: gpstorezero, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 2 bytes to ...
   267  		{name: "MOVWstorezero", argLength: 2, reg: gpstorezero, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 4 bytes to ...
   268  		{name: "MOVDstorezero", argLength: 2, reg: gpstorezero, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 8 bytes to ...
   269  
   270  		{name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{sp | sb}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
   271  
   272  		{name: "MOVDconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVD", typ: "Int64", rematerializeable: true}, //
   273  		{name: "FMOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVD", rematerializeable: true},           //
   274  		{name: "FMOVSconst", argLength: 0, reg: fp01, aux: "Float32", asm: "FMOVS", rematerializeable: true},           //
   275  		{name: "FCMPU", argLength: 2, reg: fp2cr, asm: "FCMPU", typ: "Flags"},
   276  
   277  		{name: "CMP", argLength: 2, reg: gp2cr, asm: "CMP", typ: "Flags"},     // arg0 compare to arg1
   278  		{name: "CMPU", argLength: 2, reg: gp2cr, asm: "CMPU", typ: "Flags"},   // arg0 compare to arg1
   279  		{name: "CMPW", argLength: 2, reg: gp2cr, asm: "CMPW", typ: "Flags"},   // arg0 compare to arg1
   280  		{name: "CMPWU", argLength: 2, reg: gp2cr, asm: "CMPWU", typ: "Flags"}, // arg0 compare to arg1
   281  		{name: "CMPconst", argLength: 1, reg: gp1cr, asm: "CMP", aux: "Int64", typ: "Flags"},
   282  		{name: "CMPUconst", argLength: 1, reg: gp1cr, asm: "CMPU", aux: "Int64", typ: "Flags"},
   283  		{name: "CMPWconst", argLength: 1, reg: gp1cr, asm: "CMPW", aux: "Int32", typ: "Flags"},
   284  		{name: "CMPWUconst", argLength: 1, reg: gp1cr, asm: "CMPWU", aux: "Int32", typ: "Flags"},
   285  
   286  		// pseudo-ops
   287  		{name: "Equal", argLength: 1, reg: crgp},         // bool, true flags encode x==y false otherwise.
   288  		{name: "NotEqual", argLength: 1, reg: crgp},      // bool, true flags encode x!=y false otherwise.
   289  		{name: "LessThan", argLength: 1, reg: crgp},      // bool, true flags encode  x<y false otherwise.
   290  		{name: "FLessThan", argLength: 1, reg: crgp},     // bool, true flags encode  x<y false otherwise.
   291  		{name: "LessEqual", argLength: 1, reg: crgp},     // bool, true flags encode  x<=y false otherwise.
   292  		{name: "FLessEqual", argLength: 1, reg: crgp},    // bool, true flags encode  x<=y false otherwise; PPC <= === !> which is wrong for NaN
   293  		{name: "GreaterThan", argLength: 1, reg: crgp},   // bool, true flags encode  x>y false otherwise.
   294  		{name: "FGreaterThan", argLength: 1, reg: crgp},  // bool, true flags encode  x>y false otherwise.
   295  		{name: "GreaterEqual", argLength: 1, reg: crgp},  // bool, true flags encode  x>=y false otherwise.
   296  		{name: "FGreaterEqual", argLength: 1, reg: crgp}, // bool, true flags encode  x>=y false otherwise.; PPC >= === !< which is wrong for NaN
   297  
   298  		// Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
   299  		// and sorts it to the very beginning of the block to prevent other
   300  		// use of the closure pointer.
   301  		{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{ctxt}}},
   302  
   303  		//arg0=ptr,arg1=mem, returns void.  Faults if ptr is nil.
   304  		{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true},
   305  		// Round ops to block fused-multiply-add extraction.
   306  		{name: "LoweredRound32F", argLength: 1, reg: fp11, resultInArg0: true},
   307  		{name: "LoweredRound64F", argLength: 1, reg: fp11, resultInArg0: true},
   308  
   309  		// Convert pointer to integer, takes a memory operand for ordering.
   310  		{name: "MOVDconvert", argLength: 2, reg: gp11, asm: "MOVD"},
   311  
   312  		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true, symEffect: "None"},                   // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
   313  		{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gp | sp, ctxt, 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
   314  		{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                 // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
   315  
   316  		// large or unaligned zeroing
   317  		// arg0 = address of memory to zero (in R3, changed as side effect)
   318  		// returns mem
   319  		//
   320  		// a loop is generated when there is more than one iteration
   321  		// needed to clear 4 doublewords
   322  		//
   323  		// 	MOVD	$len/32,R31
   324  		//	MOVD	R31,CTR
   325  		//	loop:
   326  		//	MOVD	R0,(R3)
   327  		//	MOVD	R0,8(R3)
   328  		//	MOVD	R0,16(R3)
   329  		//	MOVD	R0,24(R3)
   330  		//	ADD	R3,32
   331  		//	BC	loop
   332  
   333  		// remaining doubleword clears generated as needed
   334  		//	MOVD	R0,(R3)
   335  		//	MOVD	R0,8(R3)
   336  		//	MOVD	R0,16(R3)
   337  		//	MOVD	R0,24(R3)
   338  
   339  		// one or more of these to clear remainder < 8 bytes
   340  		//	MOVW	R0,n1(R3)
   341  		//	MOVH	R0,n2(R3)
   342  		//	MOVB	R0,n3(R3)
   343  		{
   344  			name:      "LoweredZero",
   345  			aux:       "Int64",
   346  			argLength: 2,
   347  			reg: regInfo{
   348  				inputs:   []regMask{buildReg("R3")},
   349  				clobbers: buildReg("R3"),
   350  			},
   351  			clobberFlags:   true,
   352  			typ:            "Mem",
   353  			faultOnNilArg0: true,
   354  		},
   355  		// Loop code:
   356  		//	MOVD len/32,REG_TMP  only for loop
   357  		//	MOVD REG_TMP,CTR     only for loop
   358  		// loop:
   359  		//	MOVD (R4),R7
   360  		//	MOVD 8(R4),R8
   361  		//	MOVD 16(R4),R9
   362  		//	MOVD 24(R4),R10
   363  		//	ADD  R4,$32          only with loop
   364  		//	MOVD R7,(R3)
   365  		//	MOVD R8,8(R3)
   366  		//	MOVD R9,16(R3)
   367  		//	MOVD R10,24(R3)
   368  		//	ADD  R3,$32          only with loop
   369  		//	BC 16,0,loop         only with loop
   370  		// Bytes not moved by this loop are moved
   371  		// with a combination of the following instructions,
   372  		// starting with the largest sizes and generating as
   373  		// many as needed, using the appropriate offset value.
   374  		//	MOVD  n(R4),R7
   375  		//	MOVD  R7,n(R3)
   376  		//	MOVW  n1(R4),R7
   377  		//	MOVW  R7,n1(R3)
   378  		//	MOVH  n2(R4),R7
   379  		//	MOVH  R7,n2(R3)
   380  		//	MOVB  n3(R4),R7
   381  		//	MOVB  R7,n3(R3)
   382  
   383  		{
   384  			name:      "LoweredMove",
   385  			aux:       "Int64",
   386  			argLength: 3,
   387  			reg: regInfo{
   388  				inputs:   []regMask{buildReg("R3"), buildReg("R4")},
   389  				clobbers: buildReg("R3 R4 R7 R8 R9 R10"),
   390  			},
   391  			clobberFlags:   true,
   392  			typ:            "Mem",
   393  			faultOnNilArg0: true,
   394  			faultOnNilArg1: true,
   395  		},
   396  
   397  		{name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, typ: "Mem", faultOnNilArg0: true, hasSideEffects: true},
   398  		{name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, typ: "Mem", faultOnNilArg0: true, hasSideEffects: true},
   399  
   400  		{name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, typ: "UInt32", clobberFlags: true, faultOnNilArg0: true},
   401  		{name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, typ: "Int64", clobberFlags: true, faultOnNilArg0: true},
   402  		{name: "LoweredAtomicLoadPtr", argLength: 2, reg: gpload, typ: "Int64", clobberFlags: true, faultOnNilArg0: true},
   403  
   404  		// atomic add32, 64
   405  		// SYNC
   406  		// LDAR         (Rarg0), Rout
   407  		// ADD		Rarg1, Rout
   408  		// STDCCC       Rout, (Rarg0)
   409  		// BNE          -3(PC)
   410  		// ISYNC
   411  		// return new sum
   412  
   413  		{name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
   414  		{name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
   415  
   416  		// atomic exchange32, 64
   417  		// SYNC
   418  		// LDAR         (Rarg0), Rout
   419  		// STDCCC       Rarg1, (Rarg0)
   420  		// BNE          -2(PC)
   421  		// ISYNC
   422  		// return old val
   423  
   424  		{name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
   425  		{name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
   426  
   427  		// atomic compare and swap.
   428  		// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. auxint must be zero.
   429  		// if *arg0 == arg1 {
   430  		//   *arg0 = arg2
   431  		//   return (true, memory)
   432  		// } else {
   433  		//   return (false, memory)
   434  		// }
   435  		// SYNC
   436  		// LDAR		(Rarg0), Rtmp
   437  		// CMP		Rarg1, Rtmp
   438  		// BNE		3(PC)
   439  		// STDCCC	Rarg2, (Rarg0)
   440  		// BNE		-4(PC)
   441  		// CBNZ         Rtmp, -4(PC)
   442  		// CSET         EQ, Rout
   443  		{name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
   444  		{name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
   445  
   446  		// atomic 8 and/or.
   447  		// *arg0 &= (|=) arg1. arg2=mem. returns memory. auxint must be zero.
   448  		// LBAR		(Rarg0), Rtmp
   449  		// AND/OR	Rarg1, Rtmp
   450  		// STBCCC	Rtmp, (Rarg0), Rtmp
   451  		// BNE		Rtmp, -3(PC)
   452  
   453  		{name: "LoweredAtomicAnd8", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true},
   454  		{name: "LoweredAtomicOr8", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true},
   455  
   456  		// (InvertFlags (CMP a b)) == (CMP b a)
   457  		// So if we want (LessThan (CMP a b)) but we can't do that because a is a constant,
   458  		// then we do (LessThan (InvertFlags (CMP b a))) instead.
   459  		// Rewrites will convert this to (GreaterThan (CMP b a)).
   460  		// InvertFlags is a pseudo-op which can't appear in assembly output.
   461  		{name: "InvertFlags", argLength: 1}, // reverse direction of arg0
   462  
   463  		// Constant flag values. For any comparison, there are 3 possible
   464  		// outcomes: either the three from the signed total order (<,==,>)
   465  		// or the three from the unsigned total order, depending on which
   466  		// comparison operation was used (CMP or CMPU -- PPC is different from
   467  		// the other architectures, which have a single comparison producing
   468  		// both signed and unsigned comparison results.)
   469  
   470  		// These ops are for temporary use by rewrite rules. They
   471  		// cannot appear in the generated assembly.
   472  		{name: "FlagEQ"}, // equal
   473  		{name: "FlagLT"}, // signed < or unsigned <
   474  		{name: "FlagGT"}, // signed > or unsigned >
   475  
   476  	}
   477  
   478  	blocks := []blockData{
   479  		{name: "EQ"},
   480  		{name: "NE"},
   481  		{name: "LT"},
   482  		{name: "LE"},
   483  		{name: "GT"},
   484  		{name: "GE"},
   485  		{name: "FLT"},
   486  		{name: "FLE"},
   487  		{name: "FGT"},
   488  		{name: "FGE"},
   489  	}
   490  
   491  	archs = append(archs, arch{
   492  		name:            "PPC64",
   493  		pkg:             "cmd/internal/obj/ppc64",
   494  		genfile:         "../../ppc64/ssa.go",
   495  		ops:             ops,
   496  		blocks:          blocks,
   497  		regnames:        regNamesPPC64,
   498  		gpregmask:       gp,
   499  		fpregmask:       fp,
   500  		framepointerreg: int8(num["SP"]),
   501  		linkreg:         -1, // not used
   502  	})
   503  }