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