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