Home | History | Annotate | Download | only in gen
      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 		fp01        = regInfo{inputs: nil, outputs: []regMask{fp}}
    144 		fp11        = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
    145 		fpgp        = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
    146 		gpfp        = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}
    147 		fp21        = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
    148 		fp2cr       = regInfo{inputs: []regMask{fp, fp}}
    149 		fpload      = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{fp}}
    150 		fpstore     = regInfo{inputs: []regMask{gp | sp | sb, fp}}
    151 		callerSave  = regMask(gp | fp | gr)
    152 	)
    153 	ops := []opData{
    154 		{name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true},     // arg0 + arg1
    155 		{name: "ADDconst", argLength: 1, reg: gp11, asm: "ADD", aux: "SymOff"},    // arg0 + auxInt + aux.(*gc.Sym)
    156 		{name: "FADD", argLength: 2, reg: fp21, asm: "FADD", commutative: true},   // arg0+arg1
    157 		{name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true}, // arg0+arg1
    158 		{name: "SUB", argLength: 2, reg: gp21, asm: "SUB"},                        // arg0-arg1
    159 		{name: "FSUB", argLength: 2, reg: fp21, asm: "FSUB"},                      // arg0-arg1
    160 		{name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS"},                    // arg0-arg1
    161 
    162 		{name: "MULLD", argLength: 2, reg: gp21, asm: "MULLD", typ: "Int64", commutative: true}, // arg0*arg1 (signed 64-bit)
    163 		{name: "MULLW", argLength: 2, reg: gp21, asm: "MULLW", typ: "Int32", commutative: true}, // arg0*arg1 (signed 32-bit)
    164 
    165 		{name: "MULHD", argLength: 2, reg: gp21, asm: "MULHD", commutative: true},   // (arg0 * arg1) >> 64, signed
    166 		{name: "MULHW", argLength: 2, reg: gp21, asm: "MULHW", commutative: true},   // (arg0 * arg1) >> 32, signed
    167 		{name: "MULHDU", argLength: 2, reg: gp21, asm: "MULHDU", commutative: true}, // (arg0 * arg1) >> 64, unsigned
    168 		{name: "MULHWU", argLength: 2, reg: gp21, asm: "MULHWU", commutative: true}, // (arg0 * arg1) >> 32, unsigned
    169 
    170 		{name: "FMUL", argLength: 2, reg: fp21, asm: "FMUL", commutative: true},   // arg0*arg1
    171 		{name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true}, // arg0*arg1
    172 
    173 		{name: "SRAD", argLength: 2, reg: gp21, asm: "SRAD"}, // arg0 >>a arg1, 64 bits (all sign if arg1 & 64 != 0)
    174 		{name: "SRAW", argLength: 2, reg: gp21, asm: "SRAW"}, // arg0 >>a arg1, 32 bits (all sign if arg1 & 32 != 0)
    175 		{name: "SRD", argLength: 2, reg: gp21, asm: "SRD"},   // arg0 >> arg1, 64 bits  (0 if arg1 & 64 != 0)
    176 		{name: "SRW", argLength: 2, reg: gp21, asm: "SRW"},   // arg0 >> arg1, 32 bits  (0 if arg1 & 32 != 0)
    177 		{name: "SLD", argLength: 2, reg: gp21, asm: "SLD"},   // arg0 << arg1, 64 bits  (0 if arg1 & 64 != 0)
    178 		{name: "SLW", argLength: 2, reg: gp21, asm: "SLW"},   // arg0 << arg1, 32 bits  (0 if arg1 & 32 != 0)
    179 
    180 		{name: "ADDconstForCarry", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, aux: "Int16", asm: "ADDC", typ: "Flags"}, // _, carry := arg0 + aux
    181 		{name: "MaskIfNotCarry", argLength: 1, reg: crgp, asm: "ADDME", typ: "Int64"},                                                                   // carry - 1 (if carry then 0 else -1)
    182 
    183 		{name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int64"}, // arg0 >>a aux, 64 bits
    184 		{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int64"}, // arg0 >>a aux, 32 bits
    185 		{name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"},   // arg0 >> aux, 64 bits
    186 		{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int64"},   // arg0 >> aux, 32 bits
    187 		{name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int64"},   // arg0 << aux, 64 bits
    188 		{name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int64"},   // arg0 << aux, 32 bits
    189 
    190 		{name: "FDIV", argLength: 2, reg: fp21, asm: "FDIV"},   // arg0/arg1
    191 		{name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS"}, // arg0/arg1
    192 
    193 		{name: "DIVD", argLength: 2, reg: gp21, asm: "DIVD", typ: "Int64"},   // arg0/arg1 (signed 64-bit)
    194 		{name: "DIVW", argLength: 2, reg: gp21, asm: "DIVW", typ: "Int32"},   // arg0/arg1 (signed 32-bit)
    195 		{name: "DIVDU", argLength: 2, reg: gp21, asm: "DIVDU", typ: "Int64"}, // arg0/arg1 (unsigned 64-bit)
    196 		{name: "DIVWU", argLength: 2, reg: gp21, asm: "DIVWU", typ: "Int32"}, // arg0/arg1 (unsigned 32-bit)
    197 
    198 		// MOD is implemented as rem := arg0 - (arg0/arg1) * arg1
    199 
    200 		// Conversions are all float-to-float register operations.  "Integer" refers to encoding in the FP register.
    201 		{name: "FCTIDZ", argLength: 1, reg: fp11, asm: "FCTIDZ", typ: "Float64"}, // convert float to 64-bit int round towards zero
    202 		{name: "FCTIWZ", argLength: 1, reg: fp11, asm: "FCTIWZ", typ: "Float64"}, // convert float to 32-bit int round towards zero
    203 		{name: "FCFID", argLength: 1, reg: fp11, asm: "FCFID", typ: "Float64"},   // convert 64-bit integer to float
    204 		{name: "FRSP", argLength: 1, reg: fp11, asm: "FRSP", typ: "Float64"},     // round float to 32-bit value
    205 
    206 		// Movement between float and integer registers with no change in bits; accomplished with stores+loads on PPC.
    207 		// Because the 32-bit load-literal-bits instructions have impoverished addressability, always widen the
    208 		// data instead and use FMOVDload and FMOVDstore instead (this will also dodge endianess issues).
    209 		// There are optimizations that should apply -- (Xi2f64 (MOVWload (not-ADD-ptr+offset) ) ) could use
    210 		// the word-load instructions.  (Xi2f64 (MOVDload ptr )) can be (FMOVDload ptr)
    211 
    212 		{name: "Xf2i64", argLength: 1, reg: fpgp, typ: "Int64", usesScratch: true},   // move 64 bits of F register into G register
    213 		{name: "Xi2f64", argLength: 1, reg: gpfp, typ: "Float64", usesScratch: true}, // move 64 bits of G register into F register
    214 
    215 		{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true},               // arg0&arg1
    216 		{name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"},                                // arg0&^arg1
    217 		{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},                 // arg0|arg1
    218 		{name: "ORN", argLength: 2, reg: gp21, asm: "ORN"},                                  // arg0|^arg1
    219 		{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", typ: "Int64", commutative: true}, // arg0^arg1
    220 		{name: "EQV", argLength: 2, reg: gp21, asm: "EQV", typ: "Int64", commutative: true}, // arg0^^arg1
    221 		{name: "NEG", argLength: 1, reg: gp11, asm: "NEG"},                                  // -arg0 (integer)
    222 		{name: "FNEG", argLength: 1, reg: fp11, asm: "FNEG"},                                // -arg0 (floating point)
    223 		{name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"},                              // sqrt(arg0) (floating point)
    224 		{name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"},                            // sqrt(arg0) (floating point, single precision)
    225 
    226 		{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"},                                                                                     // arg0|aux
    227 		{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64"},                                                                                   // arg0^aux
    228 		{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.
    229 		{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.
    230 
    231 		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB", typ: "Int64"},                                            // sign extend int8 to int64
    232 		{name: "MOVBZreg", argLength: 1, reg: gp11, asm: "MOVBZ", typ: "Int64"},                                          // zero extend uint8 to uint64
    233 		{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH", typ: "Int64"},                                            // sign extend int16 to int64
    234 		{name: "MOVHZreg", argLength: 1, reg: gp11, asm: "MOVHZ", typ: "Int64"},                                          // zero extend uint16 to uint64
    235 		{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW", typ: "Int64"},                                            // sign extend int32 to int64
    236 		{name: "MOVWZreg", argLength: 1, reg: gp11, asm: "MOVWZ", typ: "Int64"},                                          // zero extend uint32 to uint64
    237 		{name: "MOVBZload", argLength: 2, reg: gpload, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true},  // zero extend uint8 to uint64
    238 		{name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", typ: "Int16", faultOnNilArg0: true},    // sign extend int16 to int64
    239 		{name: "MOVHZload", argLength: 2, reg: gpload, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true}, // zero extend uint16 to uint64
    240 		{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", typ: "Int32", faultOnNilArg0: true},    // sign extend int32 to int64
    241 		{name: "MOVWZload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true}, // zero extend uint32 to uint64
    242 		{name: "MOVDload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", typ: "Int64", faultOnNilArg0: true},
    243 
    244 		{name: "FMOVDload", argLength: 2, reg: fpload, asm: "FMOVD", aux: "SymOff", typ: "Float64", faultOnNilArg0: true},
    245 		{name: "FMOVSload", argLength: 2, reg: fpload, asm: "FMOVS", aux: "SymOff", typ: "Float32", faultOnNilArg0: true},
    246 		{name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},
    247 		{name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},
    248 		{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},
    249 		{name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},
    250 		{name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "FMOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},
    251 		{name: "FMOVSstore", argLength: 3, reg: fpstore, asm: "FMOVS", aux: "SymOff", typ: "Mem", faultOnNilArg0: true},
    252 
    253 		{name: "MOVBstorezero", argLength: 2, reg: gpstorezero, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true}, // store zero byte to arg0+aux.  arg1=mem
    254 		{name: "MOVHstorezero", argLength: 2, reg: gpstorezero, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true}, // store zero 2 bytes to ...
    255 		{name: "MOVWstorezero", argLength: 2, reg: gpstorezero, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true}, // store zero 4 bytes to ...
    256 		{name: "MOVDstorezero", argLength: 2, reg: gpstorezero, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true}, // store zero 8 bytes to ...
    257 
    258 		{name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{sp | sb}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
    259 
    260 		{name: "MOVDconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVD", typ: "Int64", rematerializeable: true}, //
    261 		{name: "FMOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVD", rematerializeable: true},           //
    262 		{name: "FMOVSconst", argLength: 0, reg: fp01, aux: "Float32", asm: "FMOVS", rematerializeable: true},           //
    263 		{name: "FCMPU", argLength: 2, reg: fp2cr, asm: "FCMPU", typ: "Flags"},
    264 
    265 		{name: "CMP", argLength: 2, reg: gp2cr, asm: "CMP", typ: "Flags"},     // arg0 compare to arg1
    266 		{name: "CMPU", argLength: 2, reg: gp2cr, asm: "CMPU", typ: "Flags"},   // arg0 compare to arg1
    267 		{name: "CMPW", argLength: 2, reg: gp2cr, asm: "CMPW", typ: "Flags"},   // arg0 compare to arg1
    268 		{name: "CMPWU", argLength: 2, reg: gp2cr, asm: "CMPWU", typ: "Flags"}, // arg0 compare to arg1
    269 		{name: "CMPconst", argLength: 1, reg: gp1cr, asm: "CMP", aux: "Int64", typ: "Flags"},
    270 		{name: "CMPUconst", argLength: 1, reg: gp1cr, asm: "CMPU", aux: "Int64", typ: "Flags"},
    271 		{name: "CMPWconst", argLength: 1, reg: gp1cr, asm: "CMPW", aux: "Int32", typ: "Flags"},
    272 		{name: "CMPWUconst", argLength: 1, reg: gp1cr, asm: "CMPWU", aux: "Int32", typ: "Flags"},
    273 
    274 		// pseudo-ops
    275 		{name: "Equal", argLength: 1, reg: crgp},         // bool, true flags encode x==y false otherwise.
    276 		{name: "NotEqual", argLength: 1, reg: crgp},      // bool, true flags encode x!=y false otherwise.
    277 		{name: "LessThan", argLength: 1, reg: crgp},      // bool, true flags encode  x<y false otherwise.
    278 		{name: "FLessThan", argLength: 1, reg: crgp},     // bool, true flags encode  x<y false otherwise.
    279 		{name: "LessEqual", argLength: 1, reg: crgp},     // bool, true flags encode  x<=y false otherwise.
    280 		{name: "FLessEqual", argLength: 1, reg: crgp},    // bool, true flags encode  x<=y false otherwise; PPC <= === !> which is wrong for NaN
    281 		{name: "GreaterThan", argLength: 1, reg: crgp},   // bool, true flags encode  x>y false otherwise.
    282 		{name: "FGreaterThan", argLength: 1, reg: crgp},  // bool, true flags encode  x>y false otherwise.
    283 		{name: "GreaterEqual", argLength: 1, reg: crgp},  // bool, true flags encode  x>=y false otherwise.
    284 		{name: "FGreaterEqual", argLength: 1, reg: crgp}, // bool, true flags encode  x>=y false otherwise.; PPC >= === !< which is wrong for NaN
    285 
    286 		// Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
    287 		// and sorts it to the very beginning of the block to prevent other
    288 		// use of the closure pointer.
    289 		{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{ctxt}}},
    290 
    291 		//arg0=ptr,arg1=mem, returns void.  Faults if ptr is nil.
    292 		{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true},
    293 
    294 		// Convert pointer to integer, takes a memory operand for ordering.
    295 		{name: "MOVDconvert", argLength: 2, reg: gp11, asm: "MOVD"},
    296 
    297 		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true},                                      // call static function aux.(*gc.Sym).  arg0=mem, auxint=argsize, returns mem
    298 		{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
    299 		{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                        // call deferproc.  arg0=mem, auxint=argsize, returns mem
    300 		{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                                           // call newproc.  arg0=mem, auxint=argsize, returns mem
    301 		{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
    302 
    303 		// large or unaligned zeroing
    304 		// arg0 = address of memory to zero (in R3, changed as side effect)
    305 		// arg1 = address of the last element to zero
    306 		// arg2 = mem
    307 		// returns mem
    308 		//  ADD -8,R3,R3 // intermediate value not valid GC ptr, cannot expose to opt+GC
    309 		//	MOVDU	R0, 8(R3)
    310 		//	CMP	R3, Rarg1
    311 		//	BLE	-2(PC)
    312 		{
    313 			name:      "LoweredZero",
    314 			aux:       "Int64",
    315 			argLength: 3,
    316 			reg: regInfo{
    317 				inputs:   []regMask{buildReg("R3"), gp},
    318 				clobbers: buildReg("R3"),
    319 			},
    320 			clobberFlags:   true,
    321 			typ:            "Mem",
    322 			faultOnNilArg0: true,
    323 		},
    324 
    325 		// large or unaligned move
    326 		// arg0 = address of dst memory (in R3, changed as side effect)
    327 		// arg1 = address of src memory (in R4, changed as side effect)
    328 		// arg2 = address of the last element of src
    329 		// arg3 = mem
    330 		// returns mem
    331 		//  ADD -8,R3,R3 // intermediate value not valid GC ptr, cannot expose to opt+GC
    332 		//  ADD -8,R4,R4 // intermediate value not valid GC ptr, cannot expose to opt+GC
    333 		//	MOVDU	8(R4), Rtmp
    334 		//	MOVDU	Rtmp, 8(R3)
    335 		//	CMP	R4, Rarg2
    336 		//	BLT	-3(PC)
    337 		{
    338 			name:      "LoweredMove",
    339 			aux:       "Int64",
    340 			argLength: 4,
    341 			reg: regInfo{
    342 				inputs:   []regMask{buildReg("R3"), buildReg("R4"), gp},
    343 				clobbers: buildReg("R3 R4"),
    344 			},
    345 			clobberFlags:   true,
    346 			typ:            "Mem",
    347 			faultOnNilArg0: true,
    348 			faultOnNilArg1: true,
    349 		},
    350 
    351 		// (InvertFlags (CMP a b)) == (CMP b a)
    352 		// So if we want (LessThan (CMP a b)) but we can't do that because a is a constant,
    353 		// then we do (LessThan (InvertFlags (CMP b a))) instead.
    354 		// Rewrites will convert this to (GreaterThan (CMP b a)).
    355 		// InvertFlags is a pseudo-op which can't appear in assembly output.
    356 		{name: "InvertFlags", argLength: 1}, // reverse direction of arg0
    357 
    358 		// Constant flag values. For any comparison, there are 3 possible
    359 		// outcomes: either the three from the signed total order (<,==,>)
    360 		// or the three from the unsigned total order, depending on which
    361 		// comparison operation was used (CMP or CMPU -- PPC is different from
    362 		// the other architectures, which have a single comparison producing
    363 		// both signed and unsigned comparison results.)
    364 
    365 		// These ops are for temporary use by rewrite rules. They
    366 		// cannot appear in the generated assembly.
    367 		{name: "FlagEQ"}, // equal
    368 		{name: "FlagLT"}, // signed < or unsigned <
    369 		{name: "FlagGT"}, // signed > or unsigned >
    370 
    371 	}
    372 
    373 	blocks := []blockData{
    374 		{name: "EQ"},
    375 		{name: "NE"},
    376 		{name: "LT"},
    377 		{name: "LE"},
    378 		{name: "GT"},
    379 		{name: "GE"},
    380 		{name: "FLT"},
    381 		{name: "FLE"},
    382 		{name: "FGT"},
    383 		{name: "FGE"},
    384 	}
    385 
    386 	archs = append(archs, arch{
    387 		name:            "PPC64",
    388 		pkg:             "cmd/internal/obj/ppc64",
    389 		genfile:         "../../ppc64/ssa.go",
    390 		ops:             ops,
    391 		blocks:          blocks,
    392 		regnames:        regNamesPPC64,
    393 		gpregmask:       gp,
    394 		fpregmask:       fp,
    395 		framepointerreg: int8(num["SP"]),
    396 		linkreg:         -1, // not used
    397 	})
    398 }
    399