]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/ssa/_gen/PPC64Ops.go
cmd/compile/internal/ssa: on PPC64, merge (CMPconst [0] (op ...)) more aggressively
[gostls13.git] / src / cmd / compile / internal / ssa / _gen / PPC64Ops.go
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 main
6
7 import "strings"
8
9 // Notes:
10 //  - Less-than-64-bit integer types live in the low portion of registers.
11 //    The upper portion is junk.
12 //  - Boolean types are zero or 1; stored in a byte, with upper bytes of the register containing junk.
13 //  - *const instructions may use a constant larger than the instruction can encode.
14 //    In this case the assembler expands to multiple instructions and uses tmp
15 //    register (R31).
16
17 var regNamesPPC64 = []string{
18         "R0", // REGZERO, not used, but simplifies counting in regalloc
19         "SP", // REGSP
20         "SB", // REGSB
21         "R3",
22         "R4",
23         "R5",
24         "R6",
25         "R7",
26         "R8",
27         "R9",
28         "R10",
29         "R11", // REGCTXT for closures
30         "R12",
31         "R13", // REGTLS
32         "R14",
33         "R15",
34         "R16",
35         "R17",
36         "R18",
37         "R19",
38         "R20",
39         "R21",
40         "R22",
41         "R23",
42         "R24",
43         "R25",
44         "R26",
45         "R27",
46         "R28",
47         "R29",
48         "g",   // REGG.  Using name "g" and setting Config.hasGReg makes it "just happen".
49         "R31", // REGTMP
50
51         "F0",
52         "F1",
53         "F2",
54         "F3",
55         "F4",
56         "F5",
57         "F6",
58         "F7",
59         "F8",
60         "F9",
61         "F10",
62         "F11",
63         "F12",
64         "F13",
65         "F14",
66         "F15",
67         "F16",
68         "F17",
69         "F18",
70         "F19",
71         "F20",
72         "F21",
73         "F22",
74         "F23",
75         "F24",
76         "F25",
77         "F26",
78         "F27",
79         "F28",
80         "F29",
81         "F30",
82         // "F31", the allocator is limited to 64 entries. We sacrifice this FPR to support XER.
83
84         "XER",
85
86         // If you add registers, update asyncPreempt in runtime.
87
88         // "CR0",
89         // "CR1",
90         // "CR2",
91         // "CR3",
92         // "CR4",
93         // "CR5",
94         // "CR6",
95         // "CR7",
96
97         // "CR",
98         // "LR",
99         // "CTR",
100 }
101
102 func init() {
103         // Make map from reg names to reg integers.
104         if len(regNamesPPC64) > 64 {
105                 panic("too many registers")
106         }
107         num := map[string]int{}
108         for i, name := range regNamesPPC64 {
109                 num[name] = i
110         }
111         buildReg := func(s string) regMask {
112                 m := regMask(0)
113                 for _, r := range strings.Split(s, " ") {
114                         if n, ok := num[r]; ok {
115                                 m |= regMask(1) << uint(n)
116                                 continue
117                         }
118                         panic("register " + r + " not found")
119                 }
120                 return m
121         }
122
123         var (
124                 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")
125                 fp  = buildReg("F0 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 F27 F28 F29 F30")
126                 sp  = buildReg("SP")
127                 sb  = buildReg("SB")
128                 gr  = buildReg("g")
129                 xer = buildReg("XER")
130                 // cr  = buildReg("CR")
131                 // ctr = buildReg("CTR")
132                 // lr  = buildReg("LR")
133                 tmp     = buildReg("R31")
134                 ctxt    = buildReg("R11")
135                 callptr = buildReg("R12")
136                 // tls = buildReg("R13")
137                 gp01        = regInfo{inputs: nil, outputs: []regMask{gp}}
138                 gp11        = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}
139                 xergp       = regInfo{inputs: []regMask{xer}, outputs: []regMask{gp}, clobbers: xer}
140                 gp11cxer    = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}, clobbers: xer}
141                 gp11xer     = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp, xer}}
142                 gp21        = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}}
143                 gp21a0      = regInfo{inputs: []regMask{gp, gp | sp | sb}, outputs: []regMask{gp}}
144                 gp21cxer    = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}, clobbers: xer}
145                 gp21xer     = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp, xer}, clobbers: xer}
146                 gp2xer1xer  = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, xer}, outputs: []regMask{gp, xer}, clobbers: xer}
147                 gp31        = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}}
148                 gp1cr       = regInfo{inputs: []regMask{gp | sp | sb}}
149                 gp2cr       = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}}
150                 crgp        = regInfo{inputs: nil, outputs: []regMask{gp}}
151                 crgp11      = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}
152                 crgp21      = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}}
153                 gpload      = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}
154                 gploadidx   = regInfo{inputs: []regMask{gp | sp | sb, gp}, outputs: []regMask{gp}}
155                 prefreg     = regInfo{inputs: []regMask{gp | sp | sb}}
156                 gpstore     = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}}
157                 gpstoreidx  = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, gp | sp | sb}}
158                 gpstorezero = regInfo{inputs: []regMask{gp | sp | sb}} // ppc64.REGZERO is reserved zero value
159                 gpxchg      = regInfo{inputs: []regMask{gp | sp | sb, gp}, outputs: []regMask{gp}}
160                 gpcas       = regInfo{inputs: []regMask{gp | sp | sb, gp, gp}, outputs: []regMask{gp}}
161                 fp01        = regInfo{inputs: nil, outputs: []regMask{fp}}
162                 fp11        = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
163                 fpgp        = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
164                 gpfp        = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}
165                 fp21        = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
166                 fp31        = regInfo{inputs: []regMask{fp, fp, fp}, outputs: []regMask{fp}}
167                 fp2cr       = regInfo{inputs: []regMask{fp, fp}}
168                 fpload      = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{fp}}
169                 fploadidx   = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{fp}}
170                 fpstore     = regInfo{inputs: []regMask{gp | sp | sb, fp}}
171                 fpstoreidx  = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, fp}}
172                 callerSave  = regMask(gp | fp | gr | xer)
173                 r3          = buildReg("R3")
174                 r4          = buildReg("R4")
175                 r5          = buildReg("R5")
176                 r6          = buildReg("R6")
177         )
178         ops := []opData{
179                 {name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true},                              // arg0 + arg1
180                 {name: "ADDCC", argLength: 2, reg: gp21, asm: "ADDCC", commutative: true, typ: "(Int,Flags)"},      // arg0 + arg1
181                 {name: "ADDconst", argLength: 1, reg: gp11, asm: "ADD", aux: "Int64"},                              // arg0 + auxInt
182                 {name: "ADDCCconst", argLength: 1, reg: gp11cxer, asm: "ADDCCC", aux: "Int64", typ: "(Int,Flags)"}, // arg0 + auxInt sets CC, clobbers XER
183                 {name: "FADD", argLength: 2, reg: fp21, asm: "FADD", commutative: true},                            // arg0+arg1
184                 {name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true},                          // arg0+arg1
185                 {name: "SUB", argLength: 2, reg: gp21, asm: "SUB"},                                                 // arg0-arg1
186                 {name: "SUBCC", argLength: 2, reg: gp21, asm: "SUBCC", typ: "(Int,Flags)"},                         // arg0-arg1 sets CC
187                 {name: "SUBFCconst", argLength: 1, reg: gp11cxer, asm: "SUBC", aux: "Int64"},                       // auxInt - arg0 (carry is ignored)
188                 {name: "FSUB", argLength: 2, reg: fp21, asm: "FSUB"},                                               // arg0-arg1
189                 {name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS"},                                             // arg0-arg1
190
191                 {name: "MULLD", argLength: 2, reg: gp21, asm: "MULLD", typ: "Int64", commutative: true}, // arg0*arg1 (signed 64-bit)
192                 {name: "MULLW", argLength: 2, reg: gp21, asm: "MULLW", typ: "Int32", commutative: true}, // arg0*arg1 (signed 32-bit)
193                 {name: "MULLDconst", argLength: 1, reg: gp11, asm: "MULLD", aux: "Int32", typ: "Int64"}, // arg0*auxInt (signed 64-bit)
194                 {name: "MULLWconst", argLength: 1, reg: gp11, asm: "MULLW", aux: "Int32", typ: "Int64"}, // arg0*auxInt (signed 64-bit)
195                 {name: "MADDLD", argLength: 3, reg: gp31, asm: "MADDLD", typ: "Int64"},                  // (arg0*arg1)+arg2 (signed 64-bit)
196
197                 {name: "MULHD", argLength: 2, reg: gp21, asm: "MULHD", commutative: true},   // (arg0 * arg1) >> 64, signed
198                 {name: "MULHW", argLength: 2, reg: gp21, asm: "MULHW", commutative: true},   // (arg0 * arg1) >> 32, signed
199                 {name: "MULHDU", argLength: 2, reg: gp21, asm: "MULHDU", commutative: true}, // (arg0 * arg1) >> 64, unsigned
200                 {name: "MULHWU", argLength: 2, reg: gp21, asm: "MULHWU", commutative: true}, // (arg0 * arg1) >> 32, unsigned
201
202                 {name: "FMUL", argLength: 2, reg: fp21, asm: "FMUL", commutative: true},   // arg0*arg1
203                 {name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true}, // arg0*arg1
204
205                 {name: "FMADD", argLength: 3, reg: fp31, asm: "FMADD"},   // arg0*arg1 + arg2
206                 {name: "FMADDS", argLength: 3, reg: fp31, asm: "FMADDS"}, // arg0*arg1 + arg2
207                 {name: "FMSUB", argLength: 3, reg: fp31, asm: "FMSUB"},   // arg0*arg1 - arg2
208                 {name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS"}, // arg0*arg1 - arg2
209
210                 {name: "SRAD", argLength: 2, reg: gp21cxer, asm: "SRAD"}, // signed arg0 >> (arg1&127), 64 bit width (note: 127, not 63!)
211                 {name: "SRAW", argLength: 2, reg: gp21cxer, asm: "SRAW"}, // signed arg0 >> (arg1&63), 32 bit width
212                 {name: "SRD", argLength: 2, reg: gp21, asm: "SRD"},       // unsigned arg0 >> (arg1&127), 64 bit width
213                 {name: "SRW", argLength: 2, reg: gp21, asm: "SRW"},       // unsigned arg0 >> (arg1&63), 32 bit width
214                 {name: "SLD", argLength: 2, reg: gp21, asm: "SLD"},       // arg0 << (arg1&127), 64 bit width
215                 {name: "SLW", argLength: 2, reg: gp21, asm: "SLW"},       // arg0 << (arg1&63), 32 bit width
216
217                 {name: "ROTL", argLength: 2, reg: gp21, asm: "ROTL"},   // arg0 rotate left by arg1 mod 64
218                 {name: "ROTLW", argLength: 2, reg: gp21, asm: "ROTLW"}, // uint32(arg0) rotate left by arg1 mod 32
219                 // The following are ops to implement the extended mnemonics for shifts as described in section C.8 of the ISA.
220                 // The constant shift values are packed into the aux int32.
221                 {name: "CLRLSLWI", argLength: 1, reg: gp11, asm: "CLRLSLWI", aux: "Int32"}, //
222                 {name: "CLRLSLDI", argLength: 1, reg: gp11, asm: "CLRLSLDI", aux: "Int32"}, //
223
224                 // Operations which consume or generate the CA (xer)
225                 {name: "ADDC", argLength: 2, reg: gp21xer, asm: "ADDC", commutative: true, typ: "(UInt64, UInt64)"},    // arg0 + arg1 -> out, CA
226                 {name: "SUBC", argLength: 2, reg: gp21xer, asm: "SUBC", typ: "(UInt64, UInt64)"},                       // arg0 - arg1 -> out, CA
227                 {name: "ADDCconst", argLength: 1, reg: gp11xer, asm: "ADDC", typ: "(UInt64, UInt64)", aux: "Int64"},    // arg0 + imm16 -> out, CA
228                 {name: "SUBCconst", argLength: 1, reg: gp11xer, asm: "SUBC", typ: "(UInt64, UInt64)", aux: "Int64"},    // imm16 - arg0 -> out, CA
229                 {name: "ADDE", argLength: 3, reg: gp2xer1xer, asm: "ADDE", typ: "(UInt64, UInt64)", commutative: true}, // arg0 + arg1 + CA (arg2) -> out, CA
230                 {name: "SUBE", argLength: 3, reg: gp2xer1xer, asm: "SUBE", typ: "(UInt64, UInt64)"},                    // arg0 - arg1 - CA (arg2) -> out, CA
231                 {name: "ADDZEzero", argLength: 1, reg: xergp, asm: "ADDZE", typ: "UInt64"},                             // CA (arg0) + $0 -> out
232                 {name: "SUBZEzero", argLength: 1, reg: xergp, asm: "SUBZE", typ: "UInt64"},                             // $0 - CA (arg0) -> out
233
234                 {name: "SRADconst", argLength: 1, reg: gp11cxer, asm: "SRAD", aux: "Int64"}, // signed arg0 >> auxInt, 0 <= auxInt < 64, 64 bit width
235                 {name: "SRAWconst", argLength: 1, reg: gp11cxer, asm: "SRAW", aux: "Int64"}, // signed arg0 >> auxInt, 0 <= auxInt < 32, 32 bit width
236                 {name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"},       // unsigned arg0 >> auxInt, 0 <= auxInt < 64, 64 bit width
237                 {name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int64"},       // unsigned arg0 >> auxInt, 0 <= auxInt < 32, 32 bit width
238                 {name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int64"},       // arg0 << auxInt, 0 <= auxInt < 64, 64 bit width
239                 {name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int64"},       // arg0 << auxInt, 0 <= auxInt < 32, 32 bit width
240
241                 {name: "ROTLconst", argLength: 1, reg: gp11, asm: "ROTL", aux: "Int64"},   // arg0 rotate left by auxInt bits
242                 {name: "ROTLWconst", argLength: 1, reg: gp11, asm: "ROTLW", aux: "Int64"}, // uint32(arg0) rotate left by auxInt bits
243                 {name: "EXTSWSLconst", argLength: 1, reg: gp11, asm: "EXTSWSLI", aux: "Int64"},
244
245                 {name: "RLWINM", argLength: 1, reg: gp11, asm: "RLWNM", aux: "Int64"},                      // Rotate and mask by immediate "rlwinm". encodePPC64RotateMask describes aux
246                 {name: "RLWNM", argLength: 2, reg: gp21, asm: "RLWNM", aux: "Int64"},                       // Rotate and mask by "rlwnm". encodePPC64RotateMask describes aux
247                 {name: "RLWMI", argLength: 2, reg: gp21a0, asm: "RLWMI", aux: "Int64", resultInArg0: true}, // "rlwimi" similar aux encoding as above
248                 {name: "RLDICL", argLength: 1, reg: gp11, asm: "RLDICL", aux: "Int64"},                     // Auxint is encoded similarly to RLWINM, but only MB and SH are valid. ME is always 63.
249                 {name: "RLDICR", argLength: 1, reg: gp11, asm: "RLDICR", aux: "Int64"},                     // Likewise, but only ME and SH are valid. MB is always 0.
250
251                 {name: "CNTLZD", argLength: 1, reg: gp11, asm: "CNTLZD"},                          // count leading zeros
252                 {name: "CNTLZDCC", argLength: 1, reg: gp11, asm: "CNTLZDCC", typ: "(Int, Flags)"}, // count leading zeros, sets CC
253                 {name: "CNTLZW", argLength: 1, reg: gp11, asm: "CNTLZW"},                          // count leading zeros (32 bit)
254
255                 {name: "CNTTZD", argLength: 1, reg: gp11, asm: "CNTTZD"}, // count trailing zeros
256                 {name: "CNTTZW", argLength: 1, reg: gp11, asm: "CNTTZW"}, // count trailing zeros (32 bit)
257
258                 {name: "POPCNTD", argLength: 1, reg: gp11, asm: "POPCNTD"}, // number of set bits in arg0
259                 {name: "POPCNTW", argLength: 1, reg: gp11, asm: "POPCNTW"}, // number of set bits in each word of arg0 placed in corresponding word
260                 {name: "POPCNTB", argLength: 1, reg: gp11, asm: "POPCNTB"}, // number of set bits in each byte of arg0 placed in corresponding byte
261
262                 {name: "FDIV", argLength: 2, reg: fp21, asm: "FDIV"},   // arg0/arg1
263                 {name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS"}, // arg0/arg1
264
265                 {name: "DIVD", argLength: 2, reg: gp21, asm: "DIVD", typ: "Int64"},   // arg0/arg1 (signed 64-bit)
266                 {name: "DIVW", argLength: 2, reg: gp21, asm: "DIVW", typ: "Int32"},   // arg0/arg1 (signed 32-bit)
267                 {name: "DIVDU", argLength: 2, reg: gp21, asm: "DIVDU", typ: "Int64"}, // arg0/arg1 (unsigned 64-bit)
268                 {name: "DIVWU", argLength: 2, reg: gp21, asm: "DIVWU", typ: "Int32"}, // arg0/arg1 (unsigned 32-bit)
269
270                 {name: "MODUD", argLength: 2, reg: gp21, asm: "MODUD", typ: "UInt64"}, // arg0 % arg1 (unsigned 64-bit)
271                 {name: "MODSD", argLength: 2, reg: gp21, asm: "MODSD", typ: "Int64"},  // arg0 % arg1 (signed 64-bit)
272                 {name: "MODUW", argLength: 2, reg: gp21, asm: "MODUW", typ: "UInt32"}, // arg0 % arg1 (unsigned 32-bit)
273                 {name: "MODSW", argLength: 2, reg: gp21, asm: "MODSW", typ: "Int32"},  // arg0 % arg1 (signed 32-bit)
274                 // MOD is implemented as rem := arg0 - (arg0/arg1) * arg1
275
276                 // Conversions are all float-to-float register operations.  "Integer" refers to encoding in the FP register.
277                 {name: "FCTIDZ", argLength: 1, reg: fp11, asm: "FCTIDZ", typ: "Float64"}, // convert float to 64-bit int round towards zero
278                 {name: "FCTIWZ", argLength: 1, reg: fp11, asm: "FCTIWZ", typ: "Float64"}, // convert float to 32-bit int round towards zero
279                 {name: "FCFID", argLength: 1, reg: fp11, asm: "FCFID", typ: "Float64"},   // convert 64-bit integer to float
280                 {name: "FCFIDS", argLength: 1, reg: fp11, asm: "FCFIDS", typ: "Float32"}, // convert 32-bit integer to float
281                 {name: "FRSP", argLength: 1, reg: fp11, asm: "FRSP", typ: "Float64"},     // round float to 32-bit value
282
283                 // Movement between float and integer registers with no change in bits; accomplished with stores+loads on PPC.
284                 // Because the 32-bit load-literal-bits instructions have impoverished addressability, always widen the
285                 // data instead and use FMOVDload and FMOVDstore instead (this will also dodge endianess issues).
286                 // There are optimizations that should apply -- (Xi2f64 (MOVWload (not-ADD-ptr+offset) ) ) could use
287                 // the word-load instructions.  (Xi2f64 (MOVDload ptr )) can be (FMOVDload ptr)
288
289                 {name: "MFVSRD", argLength: 1, reg: fpgp, asm: "MFVSRD", typ: "Int64"},   // move 64 bits of F register into G register
290                 {name: "MTVSRD", argLength: 1, reg: gpfp, asm: "MTVSRD", typ: "Float64"}, // move 64 bits of G register into F register
291
292                 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true},                           // arg0&arg1
293                 {name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"},                                            // arg0&^arg1
294                 {name: "ANDNCC", argLength: 2, reg: gp21, asm: "ANDNCC", typ: "(Int64,Flags)"},                  // arg0&^arg1 sets CC
295                 {name: "ANDCC", argLength: 2, reg: gp21, asm: "ANDCC", commutative: true, typ: "(Int64,Flags)"}, // arg0&arg1 sets CC
296                 {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},                             // arg0|arg1
297                 {name: "ORN", argLength: 2, reg: gp21, asm: "ORN"},                                              // arg0|^arg1
298                 {name: "ORCC", argLength: 2, reg: gp21, asm: "ORCC", commutative: true, typ: "(Int,Flags)"},     // arg0|arg1 sets CC
299                 {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true},                           // ^(arg0|arg1)
300                 {name: "NORCC", argLength: 2, reg: gp21, asm: "NORCC", commutative: true, typ: "(Int,Flags)"},   // ^(arg0|arg1) sets CC
301                 {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", typ: "Int64", commutative: true},             // arg0^arg1
302                 {name: "XORCC", argLength: 2, reg: gp21, asm: "XORCC", commutative: true, typ: "(Int,Flags)"},   // arg0^arg1 sets CC
303                 {name: "EQV", argLength: 2, reg: gp21, asm: "EQV", typ: "Int64", commutative: true},             // arg0^^arg1
304                 {name: "NEG", argLength: 1, reg: gp11, asm: "NEG"},                                              // -arg0 (integer)
305                 {name: "NEGCC", argLength: 1, reg: gp11, asm: "NEGCC", typ: "(Int,Flags)"},                      // -arg0 (integer) sets CC
306                 {name: "BRD", argLength: 1, reg: gp11, asm: "BRD"},                                              // reversebytes64(arg0)
307                 {name: "BRW", argLength: 1, reg: gp11, asm: "BRW"},                                              // reversebytes32(arg0)
308                 {name: "BRH", argLength: 1, reg: gp11, asm: "BRH"},                                              // reversebytes16(arg0)
309                 {name: "FNEG", argLength: 1, reg: fp11, asm: "FNEG"},                                            // -arg0 (floating point)
310                 {name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"},                                          // sqrt(arg0) (floating point)
311                 {name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"},                                        // sqrt(arg0) (floating point, single precision)
312                 {name: "FFLOOR", argLength: 1, reg: fp11, asm: "FRIM"},                                          // floor(arg0), float64
313                 {name: "FCEIL", argLength: 1, reg: fp11, asm: "FRIP"},                                           // ceil(arg0), float64
314                 {name: "FTRUNC", argLength: 1, reg: fp11, asm: "FRIZ"},                                          // trunc(arg0), float64
315                 {name: "FROUND", argLength: 1, reg: fp11, asm: "FRIN"},                                          // round(arg0), float64
316                 {name: "FABS", argLength: 1, reg: fp11, asm: "FABS"},                                            // abs(arg0), float64
317                 {name: "FNABS", argLength: 1, reg: fp11, asm: "FNABS"},                                          // -abs(arg0), float64
318                 {name: "FCPSGN", argLength: 2, reg: fp21, asm: "FCPSGN"},                                        // copysign arg0 -> arg1, float64
319
320                 {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"},                                                                                       // arg0|aux
321                 {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64"},                                                                                     // arg0^aux
322                 {name: "ANDCCconst", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}, asm: "ANDCC", aux: "Int64", typ: "(Int,Flags)"}, // arg0&aux == 0 // and-immediate sets CC on PPC, always.
323
324                 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB", typ: "Int64"},   // sign extend int8 to int64
325                 {name: "MOVBZreg", argLength: 1, reg: gp11, asm: "MOVBZ", typ: "Int64"}, // zero extend uint8 to uint64
326                 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH", typ: "Int64"},   // sign extend int16 to int64
327                 {name: "MOVHZreg", argLength: 1, reg: gp11, asm: "MOVHZ", typ: "Int64"}, // zero extend uint16 to uint64
328                 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW", typ: "Int64"},   // sign extend int32 to int64
329                 {name: "MOVWZreg", argLength: 1, reg: gp11, asm: "MOVWZ", typ: "Int64"}, // zero extend uint32 to uint64
330
331                 // Load bytes in the endian order of the arch from arg0+aux+auxint into a 64 bit register.
332                 {name: "MOVBZload", argLength: 2, reg: gpload, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // load byte zero extend
333                 {name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // load 2 bytes sign extend
334                 {name: "MOVHZload", argLength: 2, reg: gpload, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load 2 bytes zero extend
335                 {name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"},    // load 4 bytes sign extend
336                 {name: "MOVWZload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load 4 bytes zero extend
337                 {name: "MOVDload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", typ: "Int64", faultOnNilArg0: true, symEffect: "Read"},    // load 8 bytes
338
339                 // Load bytes in reverse endian order of the arch from arg0 into a 64 bit register, all zero extend.
340                 // The generated instructions are indexed loads with no offset field in the instruction so the aux fields are not used.
341                 // In these cases the index register field is set to 0 and the full address is in the base register.
342                 {name: "MOVDBRload", argLength: 2, reg: gpload, asm: "MOVDBR", typ: "UInt64", faultOnNilArg0: true}, // load 8 bytes reverse order
343                 {name: "MOVWBRload", argLength: 2, reg: gpload, asm: "MOVWBR", typ: "UInt32", faultOnNilArg0: true}, // load 4 bytes zero extend reverse order
344                 {name: "MOVHBRload", argLength: 2, reg: gpload, asm: "MOVHBR", typ: "UInt16", faultOnNilArg0: true}, // load 2 bytes zero extend reverse order
345
346                 // In these cases an index register is used in addition to a base register
347                 // Loads from memory location arg[0] + arg[1].
348                 {name: "MOVBZloadidx", argLength: 3, reg: gploadidx, asm: "MOVBZ", typ: "UInt8"},  // zero extend uint8 to uint64
349                 {name: "MOVHloadidx", argLength: 3, reg: gploadidx, asm: "MOVH", typ: "Int16"},    // sign extend int16 to int64
350                 {name: "MOVHZloadidx", argLength: 3, reg: gploadidx, asm: "MOVHZ", typ: "UInt16"}, // zero extend uint16 to uint64
351                 {name: "MOVWloadidx", argLength: 3, reg: gploadidx, asm: "MOVW", typ: "Int32"},    // sign extend int32 to int64
352                 {name: "MOVWZloadidx", argLength: 3, reg: gploadidx, asm: "MOVWZ", typ: "UInt32"}, // zero extend uint32 to uint64
353                 {name: "MOVDloadidx", argLength: 3, reg: gploadidx, asm: "MOVD", typ: "Int64"},
354                 {name: "MOVHBRloadidx", argLength: 3, reg: gploadidx, asm: "MOVHBR", typ: "Int16"}, // sign extend int16 to int64
355                 {name: "MOVWBRloadidx", argLength: 3, reg: gploadidx, asm: "MOVWBR", typ: "Int32"}, // sign extend int32 to int64
356                 {name: "MOVDBRloadidx", argLength: 3, reg: gploadidx, asm: "MOVDBR", typ: "Int64"},
357                 {name: "FMOVDloadidx", argLength: 3, reg: fploadidx, asm: "FMOVD", typ: "Float64"},
358                 {name: "FMOVSloadidx", argLength: 3, reg: fploadidx, asm: "FMOVS", typ: "Float32"},
359
360                 // Prefetch instruction
361                 // Do prefetch of address generated with arg0 and arg1 with option aux. arg0=addr,arg1=memory, aux=option.
362                 {name: "DCBT", argLength: 2, aux: "Int64", reg: prefreg, asm: "DCBT", hasSideEffects: true},
363
364                 // Store bytes in the reverse endian order of the arch into arg0.
365                 // These are indexed stores with no offset field in the instruction so the auxint fields are not used.
366                 {name: "MOVDBRstore", argLength: 3, reg: gpstore, asm: "MOVDBR", typ: "Mem", faultOnNilArg0: true}, // store 8 bytes reverse order
367                 {name: "MOVWBRstore", argLength: 3, reg: gpstore, asm: "MOVWBR", typ: "Mem", faultOnNilArg0: true}, // store 4 bytes reverse order
368                 {name: "MOVHBRstore", argLength: 3, reg: gpstore, asm: "MOVHBR", typ: "Mem", faultOnNilArg0: true}, // store 2 bytes reverse order
369
370                 // Floating point loads from arg0+aux+auxint
371                 {name: "FMOVDload", argLength: 2, reg: fpload, asm: "FMOVD", aux: "SymOff", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load double float
372                 {name: "FMOVSload", argLength: 2, reg: fpload, asm: "FMOVS", aux: "SymOff", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // load single float
373
374                 // Store bytes in the endian order of the arch into arg0+aux+auxint
375                 {name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store byte
376                 {name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes
377                 {name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes
378                 {name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes
379
380                 // Store floating point value into arg0+aux+auxint
381                 {name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "FMOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store double flot
382                 {name: "FMOVSstore", argLength: 3, reg: fpstore, asm: "FMOVS", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store single float
383
384                 // Stores using index and base registers
385                 // Stores to arg[0] + arg[1]
386                 {name: "MOVBstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVB", typ: "Mem"},     // store bye
387                 {name: "MOVHstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVH", typ: "Mem"},     // store half word
388                 {name: "MOVWstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVW", typ: "Mem"},     // store word
389                 {name: "MOVDstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVD", typ: "Mem"},     // store double word
390                 {name: "FMOVDstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVD", typ: "Mem"},   // store double float
391                 {name: "FMOVSstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVS", typ: "Mem"},   // store single float
392                 {name: "MOVHBRstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVHBR", typ: "Mem"}, // store half word reversed byte using index reg
393                 {name: "MOVWBRstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVWBR", typ: "Mem"}, // store word reversed byte using index reg
394                 {name: "MOVDBRstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVDBR", typ: "Mem"}, // store double word reversed byte using index reg
395
396                 // The following ops store 0 into arg0+aux+auxint arg1=mem
397                 {name: "MOVBstorezero", argLength: 2, reg: gpstorezero, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 1 byte
398                 {name: "MOVHstorezero", argLength: 2, reg: gpstorezero, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 2 bytes
399                 {name: "MOVWstorezero", argLength: 2, reg: gpstorezero, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 4 bytes
400                 {name: "MOVDstorezero", argLength: 2, reg: gpstorezero, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 8 bytes
401
402                 {name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{sp | sb | gp}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB/GP
403
404                 {name: "MOVDconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVD", typ: "Int64", rematerializeable: true}, //
405                 {name: "FMOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVD", rematerializeable: true},           //
406                 {name: "FMOVSconst", argLength: 0, reg: fp01, aux: "Float32", asm: "FMOVS", rematerializeable: true},           //
407                 {name: "FCMPU", argLength: 2, reg: fp2cr, asm: "FCMPU", typ: "Flags"},
408
409                 {name: "CMP", argLength: 2, reg: gp2cr, asm: "CMP", typ: "Flags"},     // arg0 compare to arg1
410                 {name: "CMPU", argLength: 2, reg: gp2cr, asm: "CMPU", typ: "Flags"},   // arg0 compare to arg1
411                 {name: "CMPW", argLength: 2, reg: gp2cr, asm: "CMPW", typ: "Flags"},   // arg0 compare to arg1
412                 {name: "CMPWU", argLength: 2, reg: gp2cr, asm: "CMPWU", typ: "Flags"}, // arg0 compare to arg1
413                 {name: "CMPconst", argLength: 1, reg: gp1cr, asm: "CMP", aux: "Int64", typ: "Flags"},
414                 {name: "CMPUconst", argLength: 1, reg: gp1cr, asm: "CMPU", aux: "Int64", typ: "Flags"},
415                 {name: "CMPWconst", argLength: 1, reg: gp1cr, asm: "CMPW", aux: "Int32", typ: "Flags"},
416                 {name: "CMPWUconst", argLength: 1, reg: gp1cr, asm: "CMPWU", aux: "Int32", typ: "Flags"},
417
418                 // ISEL  arg2 ? arg0 : arg1
419                 // ISELZ arg1 ? arg0 : $0
420                 // auxInt values 0=LT 1=GT 2=EQ 3=SO (summary overflow/unordered) 4=GE 5=LE 6=NE 7=NSO (not summary overflow/not unordered)
421                 // Note, auxInt^4 inverts the comparison condition. For example, LT^4 becomes GE, and "ISEL [a] x y z" is equivalent to ISEL [a^4] y x z".
422                 {name: "ISEL", argLength: 3, reg: crgp21, asm: "ISEL", aux: "Int32", typ: "Int32"},
423                 {name: "ISELZ", argLength: 2, reg: crgp11, asm: "ISEL", aux: "Int32"},
424
425                 // SETBC auxInt values 0=LT 1=GT 2=EQ     (CRbit=1)? 1 : 0
426                 {name: "SETBC", argLength: 1, reg: crgp, asm: "SETBC", aux: "Int32", typ: "Int32"},
427                 // SETBCR auxInt values 0=LT 1=GT 2=EQ     (CRbit=1)? 0 : 1
428                 {name: "SETBCR", argLength: 1, reg: crgp, asm: "SETBCR", aux: "Int32", typ: "Int32"},
429
430                 // pseudo-ops
431                 {name: "Equal", argLength: 1, reg: crgp},         // bool, true flags encode x==y false otherwise.
432                 {name: "NotEqual", argLength: 1, reg: crgp},      // bool, true flags encode x!=y false otherwise.
433                 {name: "LessThan", argLength: 1, reg: crgp},      // bool, true flags encode  x<y false otherwise.
434                 {name: "FLessThan", argLength: 1, reg: crgp},     // bool, true flags encode  x<y false otherwise.
435                 {name: "LessEqual", argLength: 1, reg: crgp},     // bool, true flags encode  x<=y false otherwise.
436                 {name: "FLessEqual", argLength: 1, reg: crgp},    // bool, true flags encode  x<=y false otherwise; PPC <= === !> which is wrong for NaN
437                 {name: "GreaterThan", argLength: 1, reg: crgp},   // bool, true flags encode  x>y false otherwise.
438                 {name: "FGreaterThan", argLength: 1, reg: crgp},  // bool, true flags encode  x>y false otherwise.
439                 {name: "GreaterEqual", argLength: 1, reg: crgp},  // bool, true flags encode  x>=y false otherwise.
440                 {name: "FGreaterEqual", argLength: 1, reg: crgp}, // bool, true flags encode  x>=y false otherwise.; PPC >= === !< which is wrong for NaN
441
442                 // Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
443                 // and sorts it to the very beginning of the block to prevent other
444                 // use of the closure pointer.
445                 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{ctxt}}, zeroWidth: true},
446
447                 // LoweredGetCallerSP returns the SP of the caller of the current function. arg0=mem.
448                 {name: "LoweredGetCallerSP", argLength: 1, reg: gp01, rematerializeable: true},
449
450                 // LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
451                 // I.e., if f calls g "calls" getcallerpc,
452                 // the result should be the PC within f that g will return to.
453                 // See runtime/stubs.go for a more detailed discussion.
454                 {name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
455
456                 //arg0=ptr,arg1=mem, returns void.  Faults if ptr is nil.
457                 {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true},
458                 // Round ops to block fused-multiply-add extraction.
459                 {name: "LoweredRound32F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true},
460                 {name: "LoweredRound64F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true},
461
462                 {name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                                       // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
463                 {name: "CALLtail", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true},                         // tail call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
464                 {name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{callptr, ctxt, 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
465                 {name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{callptr}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},            // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
466
467                 // large or unaligned zeroing
468                 // arg0 = address of memory to zero (in R3, changed as side effect)
469                 // returns mem
470                 //
471                 // a loop is generated when there is more than one iteration
472                 // needed to clear 4 doublewords
473                 //
474                 //      XXLXOR  VS32,VS32,VS32
475                 //      MOVD    $len/32,R31
476                 //      MOVD    R31,CTR
477                 //      MOVD    $16,R31
478                 //      loop:
479                 //      STXVD2X VS32,(R0)(R3)
480                 //      STXVD2X VS32,(R31)(R3)
481                 //      ADD     R3,32
482                 //      BC      loop
483
484                 // remaining doubleword clears generated as needed
485                 //      MOVD    R0,(R3)
486                 //      MOVD    R0,8(R3)
487                 //      MOVD    R0,16(R3)
488                 //      MOVD    R0,24(R3)
489
490                 // one or more of these to clear remainder < 8 bytes
491                 //      MOVW    R0,n1(R3)
492                 //      MOVH    R0,n2(R3)
493                 //      MOVB    R0,n3(R3)
494                 {
495                         name:      "LoweredZero",
496                         aux:       "Int64",
497                         argLength: 2,
498                         reg: regInfo{
499                                 inputs:   []regMask{buildReg("R20")},
500                                 clobbers: buildReg("R20"),
501                         },
502                         clobberFlags:   true,
503                         typ:            "Mem",
504                         faultOnNilArg0: true,
505                         unsafePoint:    true,
506                 },
507                 {
508                         name:      "LoweredZeroShort",
509                         aux:       "Int64",
510                         argLength: 2,
511                         reg: regInfo{
512                                 inputs: []regMask{gp}},
513                         typ:            "Mem",
514                         faultOnNilArg0: true,
515                         unsafePoint:    true,
516                 },
517                 {
518                         name:      "LoweredQuadZeroShort",
519                         aux:       "Int64",
520                         argLength: 2,
521                         reg: regInfo{
522                                 inputs: []regMask{gp},
523                         },
524                         typ:            "Mem",
525                         faultOnNilArg0: true,
526                         unsafePoint:    true,
527                 },
528                 {
529                         name:      "LoweredQuadZero",
530                         aux:       "Int64",
531                         argLength: 2,
532                         reg: regInfo{
533                                 inputs:   []regMask{buildReg("R20")},
534                                 clobbers: buildReg("R20"),
535                         },
536                         clobberFlags:   true,
537                         typ:            "Mem",
538                         faultOnNilArg0: true,
539                         unsafePoint:    true,
540                 },
541
542                 // R31 is temp register
543                 // Loop code:
544                 //      MOVD len/32,R31         set up loop ctr
545                 //      MOVD R31,CTR
546                 //      MOVD $16,R31            index register
547                 // loop:
548                 //      LXVD2X (R0)(R4),VS32
549                 //      LXVD2X (R31)(R4),VS33
550                 //      ADD  R4,$32          increment src
551                 //      STXVD2X VS32,(R0)(R3)
552                 //      STXVD2X VS33,(R31)(R3)
553                 //      ADD  R3,$32          increment dst
554                 //      BC 16,0,loop         branch ctr
555                 // For this purpose, VS32 and VS33 are treated as
556                 // scratch registers. Since regalloc does not
557                 // track vector registers, even if it could be marked
558                 // as clobbered it would have no effect.
559                 // TODO: If vector registers are managed by regalloc
560                 // mark these as clobbered.
561                 //
562                 // Bytes not moved by this loop are moved
563                 // with a combination of the following instructions,
564                 // starting with the largest sizes and generating as
565                 // many as needed, using the appropriate offset value.
566                 //      MOVD  n(R4),R14
567                 //      MOVD  R14,n(R3)
568                 //      MOVW  n1(R4),R14
569                 //      MOVW  R14,n1(R3)
570                 //      MOVH  n2(R4),R14
571                 //      MOVH  R14,n2(R3)
572                 //      MOVB  n3(R4),R14
573                 //      MOVB  R14,n3(R3)
574
575                 {
576                         name:      "LoweredMove",
577                         aux:       "Int64",
578                         argLength: 3,
579                         reg: regInfo{
580                                 inputs:   []regMask{buildReg("R20"), buildReg("R21")},
581                                 clobbers: buildReg("R20 R21"),
582                         },
583                         clobberFlags:   true,
584                         typ:            "Mem",
585                         faultOnNilArg0: true,
586                         faultOnNilArg1: true,
587                         unsafePoint:    true,
588                 },
589                 {
590                         name:      "LoweredMoveShort",
591                         aux:       "Int64",
592                         argLength: 3,
593                         reg: regInfo{
594                                 inputs: []regMask{gp, gp},
595                         },
596                         typ:            "Mem",
597                         faultOnNilArg0: true,
598                         faultOnNilArg1: true,
599                         unsafePoint:    true,
600                 },
601
602                 // The following is similar to the LoweredMove, but uses
603                 // LXV instead of LXVD2X, which does not require an index
604                 // register and will do 4 in a loop instead of only.
605                 {
606                         name:      "LoweredQuadMove",
607                         aux:       "Int64",
608                         argLength: 3,
609                         reg: regInfo{
610                                 inputs:   []regMask{buildReg("R20"), buildReg("R21")},
611                                 clobbers: buildReg("R20 R21"),
612                         },
613                         clobberFlags:   true,
614                         typ:            "Mem",
615                         faultOnNilArg0: true,
616                         faultOnNilArg1: true,
617                         unsafePoint:    true,
618                 },
619
620                 {
621                         name:      "LoweredQuadMoveShort",
622                         aux:       "Int64",
623                         argLength: 3,
624                         reg: regInfo{
625                                 inputs: []regMask{gp, gp},
626                         },
627                         typ:            "Mem",
628                         faultOnNilArg0: true,
629                         faultOnNilArg1: true,
630                         unsafePoint:    true,
631                 },
632
633                 {name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, typ: "Mem", aux: "Int64", faultOnNilArg0: true, hasSideEffects: true},
634                 {name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, typ: "Mem", aux: "Int64", faultOnNilArg0: true, hasSideEffects: true},
635                 {name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, typ: "Mem", aux: "Int64", faultOnNilArg0: true, hasSideEffects: true},
636
637                 {name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, typ: "UInt8", aux: "Int64", clobberFlags: true, faultOnNilArg0: true},
638                 {name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, typ: "UInt32", aux: "Int64", clobberFlags: true, faultOnNilArg0: true},
639                 {name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, typ: "Int64", aux: "Int64", clobberFlags: true, faultOnNilArg0: true},
640                 {name: "LoweredAtomicLoadPtr", argLength: 2, reg: gpload, typ: "Int64", aux: "Int64", clobberFlags: true, faultOnNilArg0: true},
641
642                 // atomic add32, 64
643                 // LWSYNC
644                 // LDAR         (Rarg0), Rout
645                 // ADD          Rarg1, Rout
646                 // STDCCC       Rout, (Rarg0)
647                 // BNE          -3(PC)
648                 // return new sum
649                 {name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
650                 {name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
651
652                 // atomic exchange32, 64
653                 // LWSYNC
654                 // LDAR         (Rarg0), Rout
655                 // STDCCC       Rarg1, (Rarg0)
656                 // BNE          -2(PC)
657                 // ISYNC
658                 // return old val
659                 {name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
660                 {name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
661
662                 // atomic compare and swap.
663                 // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. auxint must be zero.
664                 // if *arg0 == arg1 {
665                 //   *arg0 = arg2
666                 //   return (true, memory)
667                 // } else {
668                 //   return (false, memory)
669                 // }
670                 // SYNC
671                 // LDAR         (Rarg0), Rtmp
672                 // CMP          Rarg1, Rtmp
673                 // BNE          3(PC)
674                 // STDCCC       Rarg2, (Rarg0)
675                 // BNE          -4(PC)
676                 // CBNZ         Rtmp, -4(PC)
677                 // CSET         EQ, Rout
678                 {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, aux: "Int64", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
679                 {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, aux: "Int64", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
680
681                 // atomic 8/32 and/or.
682                 // *arg0 &= (|=) arg1. arg2=mem. returns memory. auxint must be zero.
683                 // LBAR/LWAT    (Rarg0), Rtmp
684                 // AND/OR       Rarg1, Rtmp
685                 // STBCCC/STWCCC Rtmp, (Rarg0), Rtmp
686                 // BNE          Rtmp, -3(PC)
687                 {name: "LoweredAtomicAnd8", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true},
688                 {name: "LoweredAtomicAnd32", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true},
689                 {name: "LoweredAtomicOr8", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true},
690                 {name: "LoweredAtomicOr32", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true},
691
692                 // LoweredWB invokes runtime.gcWriteBarrier. arg0=mem, auxint=# of buffer entries needed
693                 // It preserves R0 through R17 (except special registers R1, R2, R11, R12, R13), g, and R20 and R21,
694                 // but may clobber anything else, including R31 (REGTMP).
695                 // Returns a pointer to a write barrier buffer in R29.
696                 {name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ buildReg("R0 R3 R4 R5 R6 R7 R8 R9 R10 R14 R15 R16 R17 R20 R21 g")) | buildReg("R31"), outputs: []regMask{buildReg("R29")}}, clobberFlags: true, aux: "Int64"},
697
698                 {name: "LoweredPubBarrier", argLength: 1, asm: "LWSYNC", hasSideEffects: true}, // Do data barrier. arg0=memory
699                 // There are three of these functions so that they can have three different register inputs.
700                 // When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
701                 // default registers to match so we don't need to copy registers around unnecessarily.
702                 {name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r5, r6}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
703                 {name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r4, r5}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
704                 {name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r3, r4}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
705
706                 // (InvertFlags (CMP a b)) == (CMP b a)
707                 // So if we want (LessThan (CMP a b)) but we can't do that because a is a constant,
708                 // then we do (LessThan (InvertFlags (CMP b a))) instead.
709                 // Rewrites will convert this to (GreaterThan (CMP b a)).
710                 // InvertFlags is a pseudo-op which can't appear in assembly output.
711                 {name: "InvertFlags", argLength: 1}, // reverse direction of arg0
712
713                 // Constant flag values. For any comparison, there are 3 possible
714                 // outcomes: either the three from the signed total order (<,==,>)
715                 // or the three from the unsigned total order, depending on which
716                 // comparison operation was used (CMP or CMPU -- PPC is different from
717                 // the other architectures, which have a single comparison producing
718                 // both signed and unsigned comparison results.)
719
720                 // These ops are for temporary use by rewrite rules. They
721                 // cannot appear in the generated assembly.
722                 {name: "FlagEQ"}, // equal
723                 {name: "FlagLT"}, // signed < or unsigned <
724                 {name: "FlagGT"}, // signed > or unsigned >
725         }
726
727         blocks := []blockData{
728                 {name: "EQ", controls: 1},
729                 {name: "NE", controls: 1},
730                 {name: "LT", controls: 1},
731                 {name: "LE", controls: 1},
732                 {name: "GT", controls: 1},
733                 {name: "GE", controls: 1},
734                 {name: "FLT", controls: 1},
735                 {name: "FLE", controls: 1},
736                 {name: "FGT", controls: 1},
737                 {name: "FGE", controls: 1},
738         }
739
740         archs = append(archs, arch{
741                 name:               "PPC64",
742                 pkg:                "cmd/internal/obj/ppc64",
743                 genfile:            "../../ppc64/ssa.go",
744                 ops:                ops,
745                 blocks:             blocks,
746                 regnames:           regNamesPPC64,
747                 ParamIntRegNames:   "R3 R4 R5 R6 R7 R8 R9 R10 R14 R15 R16 R17",
748                 ParamFloatRegNames: "F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12",
749                 gpregmask:          gp,
750                 fpregmask:          fp,
751                 specialregmask:     xer,
752                 framepointerreg:    -1,
753                 linkreg:            -1, // not used
754         })
755 }