github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/ssa/gen/PPC64Ops.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build ignore 6 7 package main 8 9 import "strings" 10 11 // Notes: 12 // - Less-than-64-bit integer types live in the low portion of registers. 13 // For now, the upper portion is junk; sign/zero-extension might be optimized in the future, but not yet. 14 // - Boolean types are zero or 1; stored in a byte, but loaded with AMOVBZ so the upper bytes of a register are zero. 15 // - *const instructions may use a constant larger than the instruction can encode. 16 // In this case the assembler expands to multiple instructions and uses tmp 17 // register (R31). 18 19 var regNamesPPC64 = []string{ 20 "R0", // REGZERO, not used, but simplifies counting in regalloc 21 "SP", // REGSP 22 "SB", // REGSB 23 "R3", 24 "R4", 25 "R5", 26 "R6", 27 "R7", 28 "R8", 29 "R9", 30 "R10", 31 "R11", // REGCTXT for closures 32 "R12", 33 "R13", // REGTLS 34 "R14", 35 "R15", 36 "R16", 37 "R17", 38 "R18", 39 "R19", 40 "R20", 41 "R21", 42 "R22", 43 "R23", 44 "R24", 45 "R25", 46 "R26", 47 "R27", 48 "R28", 49 "R29", 50 "g", // REGG. Using name "g" and setting Config.hasGReg makes it "just happen". 51 "R31", // REGTMP 52 53 "F0", 54 "F1", 55 "F2", 56 "F3", 57 "F4", 58 "F5", 59 "F6", 60 "F7", 61 "F8", 62 "F9", 63 "F10", 64 "F11", 65 "F12", 66 "F13", 67 "F14", 68 "F15", 69 "F16", 70 "F17", 71 "F18", 72 "F19", 73 "F20", 74 "F21", 75 "F22", 76 "F23", 77 "F24", 78 "F25", 79 "F26", 80 "F27", 81 "F28", 82 "F29", 83 "F30", 84 "F31", 85 86 // 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 // "XER", 99 // "LR", 100 // "CTR", 101 } 102 103 func init() { 104 // Make map from reg names to reg integers. 105 if len(regNamesPPC64) > 64 { 106 panic("too many registers") 107 } 108 num := map[string]int{} 109 for i, name := range regNamesPPC64 { 110 num[name] = i 111 } 112 buildReg := func(s string) regMask { 113 m := regMask(0) 114 for _, r := range strings.Split(s, " ") { 115 if n, ok := num[r]; ok { 116 m |= regMask(1) << uint(n) 117 continue 118 } 119 panic("register " + r + " not found") 120 } 121 return m 122 } 123 124 var ( 125 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") 126 fp = buildReg("F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26") 127 sp = buildReg("SP") 128 sb = buildReg("SB") 129 gr = buildReg("g") 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 gp21 = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}} 140 gp22 = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp, gp}} 141 gp32 = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp, gp}} 142 gp1cr = regInfo{inputs: []regMask{gp | sp | sb}} 143 gp2cr = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}} 144 crgp = regInfo{inputs: nil, outputs: []regMask{gp}} 145 crgp11 = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}} 146 crgp21 = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}} 147 gpload = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}} 148 gploadidx = regInfo{inputs: []regMask{gp | sp | sb, gp}, outputs: []regMask{gp}} 149 gpstore = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}} 150 gpstoreidx = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, gp | sp | sb}} 151 gpstorezero = regInfo{inputs: []regMask{gp | sp | sb}} // ppc64.REGZERO is reserved zero value 152 gpxchg = regInfo{inputs: []regMask{gp | sp | sb, gp}, outputs: []regMask{gp}} 153 gpcas = regInfo{inputs: []regMask{gp | sp | sb, gp, gp}, outputs: []regMask{gp}} 154 fp01 = regInfo{inputs: nil, outputs: []regMask{fp}} 155 fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}} 156 fpgp = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}} 157 gpfp = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}} 158 fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}} 159 fp31 = regInfo{inputs: []regMask{fp, fp, fp}, outputs: []regMask{fp}} 160 fp2cr = regInfo{inputs: []regMask{fp, fp}} 161 fpload = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{fp}} 162 fploadidx = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{fp}} 163 fpstore = regInfo{inputs: []regMask{gp | sp | sb, fp}} 164 fpstoreidx = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, fp}} 165 callerSave = regMask(gp | fp | gr) 166 r3 = buildReg("R3") 167 r4 = buildReg("R4") 168 r5 = buildReg("R5") 169 r6 = buildReg("R6") 170 ) 171 ops := []opData{ 172 {name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true}, // arg0 + arg1 173 {name: "ADDconst", argLength: 1, reg: gp11, asm: "ADD", aux: "Int64"}, // arg0 + auxInt 174 {name: "FADD", argLength: 2, reg: fp21, asm: "FADD", commutative: true}, // arg0+arg1 175 {name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true}, // arg0+arg1 176 {name: "SUB", argLength: 2, reg: gp21, asm: "SUB"}, // arg0-arg1 177 {name: "FSUB", argLength: 2, reg: fp21, asm: "FSUB"}, // arg0-arg1 178 {name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS"}, // arg0-arg1 179 180 {name: "MULLD", argLength: 2, reg: gp21, asm: "MULLD", typ: "Int64", commutative: true}, // arg0*arg1 (signed 64-bit) 181 {name: "MULLW", argLength: 2, reg: gp21, asm: "MULLW", typ: "Int32", commutative: true}, // arg0*arg1 (signed 32-bit) 182 183 {name: "MULHD", argLength: 2, reg: gp21, asm: "MULHD", commutative: true}, // (arg0 * arg1) >> 64, signed 184 {name: "MULHW", argLength: 2, reg: gp21, asm: "MULHW", commutative: true}, // (arg0 * arg1) >> 32, signed 185 {name: "MULHDU", argLength: 2, reg: gp21, asm: "MULHDU", commutative: true}, // (arg0 * arg1) >> 64, unsigned 186 {name: "MULHWU", argLength: 2, reg: gp21, asm: "MULHWU", commutative: true}, // (arg0 * arg1) >> 32, unsigned 187 {name: "LoweredMuluhilo", argLength: 2, reg: gp22, resultNotInArgs: true}, // arg0 * arg1, returns (hi, lo) 188 189 {name: "FMUL", argLength: 2, reg: fp21, asm: "FMUL", commutative: true}, // arg0*arg1 190 {name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true}, // arg0*arg1 191 192 {name: "FMADD", argLength: 3, reg: fp31, asm: "FMADD"}, // arg0*arg1 + arg2 193 {name: "FMADDS", argLength: 3, reg: fp31, asm: "FMADDS"}, // arg0*arg1 + arg2 194 {name: "FMSUB", argLength: 3, reg: fp31, asm: "FMSUB"}, // arg0*arg1 - arg2 195 {name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS"}, // arg0*arg1 - arg2 196 197 {name: "SRAD", argLength: 2, reg: gp21, asm: "SRAD"}, // arg0 >>a arg1, 64 bits (all sign if arg1 & 64 != 0) 198 {name: "SRAW", argLength: 2, reg: gp21, asm: "SRAW"}, // arg0 >>a arg1, 32 bits (all sign if arg1 & 32 != 0) 199 {name: "SRD", argLength: 2, reg: gp21, asm: "SRD"}, // arg0 >> arg1, 64 bits (0 if arg1 & 64 != 0) 200 {name: "SRW", argLength: 2, reg: gp21, asm: "SRW"}, // arg0 >> arg1, 32 bits (0 if arg1 & 32 != 0) 201 {name: "SLD", argLength: 2, reg: gp21, asm: "SLD"}, // arg0 << arg1, 64 bits (0 if arg1 & 64 != 0) 202 {name: "SLW", argLength: 2, reg: gp21, asm: "SLW"}, // arg0 << arg1, 32 bits (0 if arg1 & 32 != 0) 203 204 {name: "ROTL", argLength: 2, reg: gp21, asm: "ROTL"}, // arg0 rotate left by arg1 mod 64 205 {name: "ROTLW", argLength: 2, reg: gp21, asm: "ROTLW"}, // uint32(arg0) rotate left by arg1 mod 32 206 207 {name: "LoweredAdd64Carry", argLength: 3, reg: gp32, resultNotInArgs: true}, // arg0 + arg1 + carry, returns (sum, carry) 208 {name: "ADDconstForCarry", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, aux: "Int16", asm: "ADDC", typ: "Flags"}, // _, carry := arg0 + aux 209 {name: "MaskIfNotCarry", argLength: 1, reg: crgp, asm: "ADDME", typ: "Int64"}, // carry - 1 (if carry then 0 else -1) 210 211 {name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int64"}, // arg0 >>a aux, 64 bits 212 {name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int64"}, // arg0 >>a aux, 32 bits 213 {name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"}, // arg0 >> aux, 64 bits 214 {name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int64"}, // arg0 >> aux, 32 bits 215 {name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int64"}, // arg0 << aux, 64 bits 216 {name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int64"}, // arg0 << aux, 32 bits 217 218 {name: "ROTLconst", argLength: 1, reg: gp11, asm: "ROTL", aux: "Int64"}, // arg0 rotate left by auxInt bits 219 {name: "ROTLWconst", argLength: 1, reg: gp11, asm: "ROTLW", aux: "Int64"}, // uint32(arg0) rotate left by auxInt bits 220 221 {name: "CNTLZD", argLength: 1, reg: gp11, asm: "CNTLZD", clobberFlags: true}, // count leading zeros 222 {name: "CNTLZW", argLength: 1, reg: gp11, asm: "CNTLZW", clobberFlags: true}, // count leading zeros (32 bit) 223 224 {name: "CNTTZD", argLength: 1, reg: gp11, asm: "CNTTZD"}, // count trailing zeros 225 {name: "CNTTZW", argLength: 1, reg: gp11, asm: "CNTTZW"}, // count trailing zeros (32 bit) 226 227 {name: "POPCNTD", argLength: 1, reg: gp11, asm: "POPCNTD"}, // number of set bits in arg0 228 {name: "POPCNTW", argLength: 1, reg: gp11, asm: "POPCNTW"}, // number of set bits in each word of arg0 placed in corresponding word 229 {name: "POPCNTB", argLength: 1, reg: gp11, asm: "POPCNTB"}, // number of set bits in each byte of arg0 placed in corresponding byte 230 231 {name: "FDIV", argLength: 2, reg: fp21, asm: "FDIV"}, // arg0/arg1 232 {name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS"}, // arg0/arg1 233 234 {name: "DIVD", argLength: 2, reg: gp21, asm: "DIVD", typ: "Int64"}, // arg0/arg1 (signed 64-bit) 235 {name: "DIVW", argLength: 2, reg: gp21, asm: "DIVW", typ: "Int32"}, // arg0/arg1 (signed 32-bit) 236 {name: "DIVDU", argLength: 2, reg: gp21, asm: "DIVDU", typ: "Int64"}, // arg0/arg1 (unsigned 64-bit) 237 {name: "DIVWU", argLength: 2, reg: gp21, asm: "DIVWU", typ: "Int32"}, // arg0/arg1 (unsigned 32-bit) 238 239 // MOD is implemented as rem := arg0 - (arg0/arg1) * arg1 240 241 // Conversions are all float-to-float register operations. "Integer" refers to encoding in the FP register. 242 {name: "FCTIDZ", argLength: 1, reg: fp11, asm: "FCTIDZ", typ: "Float64"}, // convert float to 64-bit int round towards zero 243 {name: "FCTIWZ", argLength: 1, reg: fp11, asm: "FCTIWZ", typ: "Float64"}, // convert float to 32-bit int round towards zero 244 {name: "FCFID", argLength: 1, reg: fp11, asm: "FCFID", typ: "Float64"}, // convert 64-bit integer to float 245 {name: "FCFIDS", argLength: 1, reg: fp11, asm: "FCFIDS", typ: "Float32"}, // convert 32-bit integer to float 246 {name: "FRSP", argLength: 1, reg: fp11, asm: "FRSP", typ: "Float64"}, // round float to 32-bit value 247 248 // Movement between float and integer registers with no change in bits; accomplished with stores+loads on PPC. 249 // Because the 32-bit load-literal-bits instructions have impoverished addressability, always widen the 250 // data instead and use FMOVDload and FMOVDstore instead (this will also dodge endianess issues). 251 // There are optimizations that should apply -- (Xi2f64 (MOVWload (not-ADD-ptr+offset) ) ) could use 252 // the word-load instructions. (Xi2f64 (MOVDload ptr )) can be (FMOVDload ptr) 253 254 {name: "MFVSRD", argLength: 1, reg: fpgp, asm: "MFVSRD", typ: "Int64"}, // move 64 bits of F register into G register 255 {name: "MTVSRD", argLength: 1, reg: gpfp, asm: "MTVSRD", typ: "Float64"}, // move 64 bits of G register into F register 256 257 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0&arg1 258 {name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"}, // arg0&^arg1 259 {name: "ANDCC", argLength: 2, reg: gp2cr, asm: "ANDCC", commutative: true, typ: "Flags"}, // arg0&arg1 sets CC 260 {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0|arg1 261 {name: "ORN", argLength: 2, reg: gp21, asm: "ORN"}, // arg0|^arg1 262 {name: "ORCC", argLength: 2, reg: gp2cr, asm: "ORCC", commutative: true, typ: "Flags"}, // arg0|arg1 sets CC 263 {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0|arg1) 264 {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", typ: "Int64", commutative: true}, // arg0^arg1 265 {name: "XORCC", argLength: 2, reg: gp2cr, asm: "XORCC", commutative: true, typ: "Flags"}, // arg0^arg1 sets CC 266 {name: "EQV", argLength: 2, reg: gp21, asm: "EQV", typ: "Int64", commutative: true}, // arg0^^arg1 267 {name: "NEG", argLength: 1, reg: gp11, asm: "NEG"}, // -arg0 (integer) 268 {name: "FNEG", argLength: 1, reg: fp11, asm: "FNEG"}, // -arg0 (floating point) 269 {name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0) (floating point) 270 {name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"}, // sqrt(arg0) (floating point, single precision) 271 {name: "FFLOOR", argLength: 1, reg: fp11, asm: "FRIM"}, // floor(arg0), float64 272 {name: "FCEIL", argLength: 1, reg: fp11, asm: "FRIP"}, // ceil(arg0), float64 273 {name: "FTRUNC", argLength: 1, reg: fp11, asm: "FRIZ"}, // trunc(arg0), float64 274 {name: "FROUND", argLength: 1, reg: fp11, asm: "FRIN"}, // round(arg0), float64 275 {name: "FABS", argLength: 1, reg: fp11, asm: "FABS"}, // abs(arg0), float64 276 {name: "FNABS", argLength: 1, reg: fp11, asm: "FNABS"}, // -abs(arg0), float64 277 {name: "FCPSGN", argLength: 2, reg: fp21, asm: "FCPSGN"}, // copysign arg0 -> arg1, float64 278 279 {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"}, // arg0|aux 280 {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64"}, // arg0^aux 281 {name: "ANDconst", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}, asm: "ANDCC", aux: "Int64", clobberFlags: true}, // arg0&aux // and-immediate sets CC on PPC, always. 282 {name: "ANDCCconst", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}}, asm: "ANDCC", aux: "Int64", typ: "Flags"}, // arg0&aux == 0 // and-immediate sets CC on PPC, always. 283 284 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB", typ: "Int64"}, // sign extend int8 to int64 285 {name: "MOVBZreg", argLength: 1, reg: gp11, asm: "MOVBZ", typ: "Int64"}, // zero extend uint8 to uint64 286 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH", typ: "Int64"}, // sign extend int16 to int64 287 {name: "MOVHZreg", argLength: 1, reg: gp11, asm: "MOVHZ", typ: "Int64"}, // zero extend uint16 to uint64 288 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW", typ: "Int64"}, // sign extend int32 to int64 289 {name: "MOVWZreg", argLength: 1, reg: gp11, asm: "MOVWZ", typ: "Int64"}, // zero extend uint32 to uint64 290 291 // Load bytes in the endian order of the arch from arg0+aux+auxint into a 64 bit register. 292 {name: "MOVBZload", argLength: 2, reg: gpload, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load byte zero extend 293 {name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // load 2 bytes sign extend 294 {name: "MOVHZload", argLength: 2, reg: gpload, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load 2 bytes zero extend 295 {name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"}, // load 4 bytes sign extend 296 {name: "MOVWZload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load 4 bytes zero extend 297 {name: "MOVDload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", typ: "Int64", faultOnNilArg0: true, symEffect: "Read"}, // load 8 bytes 298 299 // Load bytes in reverse endian order of the arch from arg0 into a 64 bit register, all zero extend. 300 // The generated instructions are indexed loads with no offset field in the instruction so the aux fields are not used. 301 // In these cases the index register field is set to 0 and the full address is in the base register. 302 {name: "MOVDBRload", argLength: 2, reg: gpload, asm: "MOVDBR", aux: "SymOff", typ: "Int64", faultOnNilArg0: true, symEffect: "Read"}, // load 8 bytes reverse order 303 {name: "MOVWBRload", argLength: 2, reg: gpload, asm: "MOVWBR", aux: "SymOff", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"}, // load 4 bytes zero extend reverse order 304 {name: "MOVHBRload", argLength: 2, reg: gpload, asm: "MOVHBR", aux: "SymOff", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // load 2 bytes zero extend reverse order 305 306 // In these cases an index register is used in addition to a base register 307 {name: "MOVBZloadidx", argLength: 3, reg: gploadidx, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // zero extend uint8 to uint64 308 {name: "MOVHloadidx", argLength: 3, reg: gploadidx, asm: "MOVH", aux: "SymOff", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // sign extend int16 to int64 309 {name: "MOVHZloadidx", argLength: 3, reg: gploadidx, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // zero extend uint16 to uint64 310 {name: "MOVWloadidx", argLength: 3, reg: gploadidx, asm: "MOVW", aux: "SymOff", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"}, // sign extend int32 to int64 311 {name: "MOVWZloadidx", argLength: 3, reg: gploadidx, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // zero extend uint32 to uint64 312 {name: "MOVDloadidx", argLength: 3, reg: gploadidx, asm: "MOVD", aux: "SymOff", typ: "Int64", faultOnNilArg0: true, symEffect: "Read"}, 313 {name: "MOVHBRloadidx", argLength: 3, reg: gploadidx, asm: "MOVHBR", aux: "SymOff", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // sign extend int16 to int64 314 {name: "MOVWBRloadidx", argLength: 3, reg: gploadidx, asm: "MOVWBR", aux: "SymOff", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"}, // sign extend int32 to int64 315 {name: "MOVDBRloadidx", argLength: 3, reg: gploadidx, asm: "MOVDBR", aux: "SymOff", typ: "Int64", faultOnNilArg0: true, symEffect: "Read"}, 316 {name: "FMOVDloadidx", argLength: 3, reg: fploadidx, asm: "FMOVD", aux: "SymOff", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, 317 {name: "FMOVSloadidx", argLength: 3, reg: fploadidx, asm: "FMOVS", aux: "SymOff", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, 318 319 // Store bytes in the reverse endian order of the arch into arg0. 320 // These are indexes stores with no offset field in the instruction so the aux fields are not used. 321 {name: "MOVDBRstore", argLength: 3, reg: gpstore, asm: "MOVDBR", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes reverse order 322 {name: "MOVWBRstore", argLength: 3, reg: gpstore, asm: "MOVWBR", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes reverse order 323 {name: "MOVHBRstore", argLength: 3, reg: gpstore, asm: "MOVHBR", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes reverse order 324 325 // Floating point loads from arg0+aux+auxint 326 {name: "FMOVDload", argLength: 2, reg: fpload, asm: "FMOVD", aux: "SymOff", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load double float 327 {name: "FMOVSload", argLength: 2, reg: fpload, asm: "FMOVS", aux: "SymOff", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // load single float 328 329 // Store bytes in the endian order of the arch into arg0+aux+auxint 330 {name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store byte 331 {name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes 332 {name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes 333 {name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes 334 335 // Store floating point value into arg0+aux+auxint 336 {name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "FMOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store double flot 337 {name: "FMOVSstore", argLength: 3, reg: fpstore, asm: "FMOVS", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store single float 338 339 // Stores using index and base registers 340 {name: "MOVBstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store bye 341 {name: "MOVHstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store half word 342 {name: "MOVWstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store word 343 {name: "MOVDstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store double word 344 {name: "FMOVDstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store double float 345 {name: "FMOVSstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVS", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store single float 346 {name: "MOVHBRstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVHBR", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store half word reversed byte using index reg 347 {name: "MOVWBRstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVWBR", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store word reversed byte using index reg 348 {name: "MOVDBRstoreidx", argLength: 4, reg: gpstoreidx, asm: "MOVDBR", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store double word reversed byte using index reg 349 350 // The following ops store 0 into arg0+aux+auxint arg1=mem 351 {name: "MOVBstorezero", argLength: 2, reg: gpstorezero, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 1 byte 352 {name: "MOVHstorezero", argLength: 2, reg: gpstorezero, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 2 bytes 353 {name: "MOVWstorezero", argLength: 2, reg: gpstorezero, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 4 bytes 354 {name: "MOVDstorezero", argLength: 2, reg: gpstorezero, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 8 bytes 355 356 {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 357 358 {name: "MOVDconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVD", typ: "Int64", rematerializeable: true}, // 359 {name: "FMOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVD", rematerializeable: true}, // 360 {name: "FMOVSconst", argLength: 0, reg: fp01, aux: "Float32", asm: "FMOVS", rematerializeable: true}, // 361 {name: "FCMPU", argLength: 2, reg: fp2cr, asm: "FCMPU", typ: "Flags"}, 362 363 {name: "CMP", argLength: 2, reg: gp2cr, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1 364 {name: "CMPU", argLength: 2, reg: gp2cr, asm: "CMPU", typ: "Flags"}, // arg0 compare to arg1 365 {name: "CMPW", argLength: 2, reg: gp2cr, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1 366 {name: "CMPWU", argLength: 2, reg: gp2cr, asm: "CMPWU", typ: "Flags"}, // arg0 compare to arg1 367 {name: "CMPconst", argLength: 1, reg: gp1cr, asm: "CMP", aux: "Int64", typ: "Flags"}, 368 {name: "CMPUconst", argLength: 1, reg: gp1cr, asm: "CMPU", aux: "Int64", typ: "Flags"}, 369 {name: "CMPWconst", argLength: 1, reg: gp1cr, asm: "CMPW", aux: "Int32", typ: "Flags"}, 370 {name: "CMPWUconst", argLength: 1, reg: gp1cr, asm: "CMPWU", aux: "Int32", typ: "Flags"}, 371 372 // ISEL auxInt values 0=LT 1=GT 2=EQ arg2 ? arg0 : arg1 373 // ISEL auxInt values 4=GE 5=LE 6=NE arg2 ? arg1 : arg0 374 // ISELB special case where arg0, arg1 values are 0, 1 for boolean result 375 {name: "ISEL", argLength: 3, reg: crgp21, asm: "ISEL", aux: "Int32", typ: "Int32"}, // see above 376 {name: "ISELB", argLength: 2, reg: crgp11, asm: "ISEL", aux: "Int32", typ: "Int32"}, // see above 377 378 // pseudo-ops 379 {name: "Equal", argLength: 1, reg: crgp}, // bool, true flags encode x==y false otherwise. 380 {name: "NotEqual", argLength: 1, reg: crgp}, // bool, true flags encode x!=y false otherwise. 381 {name: "LessThan", argLength: 1, reg: crgp}, // bool, true flags encode x<y false otherwise. 382 {name: "FLessThan", argLength: 1, reg: crgp}, // bool, true flags encode x<y false otherwise. 383 {name: "LessEqual", argLength: 1, reg: crgp}, // bool, true flags encode x<=y false otherwise. 384 {name: "FLessEqual", argLength: 1, reg: crgp}, // bool, true flags encode x<=y false otherwise; PPC <= === !> which is wrong for NaN 385 {name: "GreaterThan", argLength: 1, reg: crgp}, // bool, true flags encode x>y false otherwise. 386 {name: "FGreaterThan", argLength: 1, reg: crgp}, // bool, true flags encode x>y false otherwise. 387 {name: "GreaterEqual", argLength: 1, reg: crgp}, // bool, true flags encode x>=y false otherwise. 388 {name: "FGreaterEqual", argLength: 1, reg: crgp}, // bool, true flags encode x>=y false otherwise.; PPC >= === !< which is wrong for NaN 389 390 // Scheduler ensures LoweredGetClosurePtr occurs only in entry block, 391 // and sorts it to the very beginning of the block to prevent other 392 // use of the closure pointer. 393 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{ctxt}}, zeroWidth: true}, 394 395 // LoweredGetCallerSP returns the SP of the caller of the current function. 396 {name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true}, 397 398 // LoweredGetCallerPC evaluates to the PC to which its "caller" will return. 399 // I.e., if f calls g "calls" getcallerpc, 400 // the result should be the PC within f that g will return to. 401 // See runtime/stubs.go for a more detailed discussion. 402 {name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true}, 403 404 //arg0=ptr,arg1=mem, returns void. Faults if ptr is nil. 405 {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true}, 406 // Round ops to block fused-multiply-add extraction. 407 {name: "LoweredRound32F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true}, 408 {name: "LoweredRound64F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true}, 409 410 {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true, symEffect: "None"}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem 411 {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{callptr, ctxt, 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem 412 {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{callptr}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem 413 414 // large or unaligned zeroing 415 // arg0 = address of memory to zero (in R3, changed as side effect) 416 // returns mem 417 // 418 // a loop is generated when there is more than one iteration 419 // needed to clear 4 doublewords 420 // 421 // XXLXOR VS32,VS32,VS32 422 // MOVD $len/32,R31 423 // MOVD R31,CTR 424 // MOVD $16,R31 425 // loop: 426 // STXVD2X VS32,(R0)(R3) 427 // STXVD2X VS32,(R31),R3) 428 // ADD R3,32 429 // BC loop 430 431 // remaining doubleword clears generated as needed 432 // MOVD R0,(R3) 433 // MOVD R0,8(R3) 434 // MOVD R0,16(R3) 435 // MOVD R0,24(R3) 436 437 // one or more of these to clear remainder < 8 bytes 438 // MOVW R0,n1(R3) 439 // MOVH R0,n2(R3) 440 // MOVB R0,n3(R3) 441 { 442 name: "LoweredZero", 443 aux: "Int64", 444 argLength: 2, 445 reg: regInfo{ 446 inputs: []regMask{buildReg("R3")}, 447 clobbers: buildReg("R3"), 448 }, 449 clobberFlags: true, 450 typ: "Mem", 451 faultOnNilArg0: true, 452 unsafePoint: true, 453 }, 454 // R31 is temp register 455 // Loop code: 456 // MOVD len/32,R31 set up loop ctr 457 // MOVD R31,CTR 458 // MOVD $16,R31 index register 459 // loop: 460 // LXVD2X (R0)(R4),VS32 461 // LXVD2X (R31)(R4),VS33 462 // ADD R4,$32 increment src 463 // STXVD2X VS32,(R0)(R3) 464 // STXVD2X VS33,(R31)(R3) 465 // ADD R3,$32 increment dst 466 // BC 16,0,loop branch ctr 467 // For this purpose, VS32 and VS33 are treated as 468 // scratch registers. Since regalloc does not 469 // track vector registers, even if it could be marked 470 // as clobbered it would have no effect. 471 // TODO: If vector registers are managed by regalloc 472 // mark these as clobbered. 473 // 474 // Bytes not moved by this loop are moved 475 // with a combination of the following instructions, 476 // starting with the largest sizes and generating as 477 // many as needed, using the appropriate offset value. 478 // MOVD n(R4),R14 479 // MOVD R14,n(R3) 480 // MOVW n1(R4),R14 481 // MOVW R14,n1(R3) 482 // MOVH n2(R4),R14 483 // MOVH R14,n2(R3) 484 // MOVB n3(R4),R14 485 // MOVB R14,n3(R3) 486 487 { 488 name: "LoweredMove", 489 aux: "Int64", 490 argLength: 3, 491 reg: regInfo{ 492 inputs: []regMask{buildReg("R3"), buildReg("R4")}, 493 clobbers: buildReg("R3 R4 R14"), 494 }, 495 clobberFlags: true, 496 typ: "Mem", 497 faultOnNilArg0: true, 498 faultOnNilArg1: true, 499 unsafePoint: true, 500 }, 501 502 {name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, typ: "Mem", aux: "Int64", faultOnNilArg0: true, hasSideEffects: true}, 503 {name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, typ: "Mem", aux: "Int64", faultOnNilArg0: true, hasSideEffects: true}, 504 {name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, typ: "Mem", aux: "Int64", faultOnNilArg0: true, hasSideEffects: true}, 505 506 {name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, typ: "UInt8", aux: "Int64", clobberFlags: true, faultOnNilArg0: true}, 507 {name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, typ: "UInt32", aux: "Int64", clobberFlags: true, faultOnNilArg0: true}, 508 {name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, typ: "Int64", aux: "Int64", clobberFlags: true, faultOnNilArg0: true}, 509 {name: "LoweredAtomicLoadPtr", argLength: 2, reg: gpload, typ: "Int64", aux: "Int64", clobberFlags: true, faultOnNilArg0: true}, 510 511 // atomic add32, 64 512 // SYNC 513 // LDAR (Rarg0), Rout 514 // ADD Rarg1, Rout 515 // STDCCC Rout, (Rarg0) 516 // BNE -3(PC) 517 // ISYNC 518 // return new sum 519 520 {name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true}, 521 {name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true}, 522 523 // atomic exchange32, 64 524 // SYNC 525 // LDAR (Rarg0), Rout 526 // STDCCC Rarg1, (Rarg0) 527 // BNE -2(PC) 528 // ISYNC 529 // return old val 530 531 {name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true}, 532 {name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true}, 533 534 // atomic compare and swap. 535 // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. auxint must be zero. 536 // if *arg0 == arg1 { 537 // *arg0 = arg2 538 // return (true, memory) 539 // } else { 540 // return (false, memory) 541 // } 542 // SYNC 543 // LDAR (Rarg0), Rtmp 544 // CMP Rarg1, Rtmp 545 // BNE 3(PC) 546 // STDCCC Rarg2, (Rarg0) 547 // BNE -4(PC) 548 // CBNZ Rtmp, -4(PC) 549 // CSET EQ, Rout 550 {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, aux: "Int64", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true}, 551 {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, aux: "Int64", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true}, 552 553 // atomic 8 and/or. 554 // *arg0 &= (|=) arg1. arg2=mem. returns memory. auxint must be zero. 555 // LBAR (Rarg0), Rtmp 556 // AND/OR Rarg1, Rtmp 557 // STBCCC Rtmp, (Rarg0), Rtmp 558 // BNE Rtmp, -3(PC) 559 560 {name: "LoweredAtomicAnd8", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true}, 561 {name: "LoweredAtomicOr8", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true}, 562 563 // LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier 564 // It preserves R0 through R15, g, and its arguments R20 and R21, 565 // but may clobber anything else, including R31 (REGTMP). 566 {name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R20"), buildReg("R21")}, clobbers: (callerSave &^ buildReg("R0 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R20 R21 g")) | buildReg("R31")}, clobberFlags: true, aux: "Sym", symEffect: "None"}, 567 568 // There are three of these functions so that they can have three different register inputs. 569 // When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the 570 // default registers to match so we don't need to copy registers around unnecessarily. 571 {name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r5, r6}}, typ: "Mem"}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go). 572 {name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r4, r5}}, typ: "Mem"}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go). 573 {name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r3, r4}}, typ: "Mem"}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go). 574 575 // (InvertFlags (CMP a b)) == (CMP b a) 576 // So if we want (LessThan (CMP a b)) but we can't do that because a is a constant, 577 // then we do (LessThan (InvertFlags (CMP b a))) instead. 578 // Rewrites will convert this to (GreaterThan (CMP b a)). 579 // InvertFlags is a pseudo-op which can't appear in assembly output. 580 {name: "InvertFlags", argLength: 1}, // reverse direction of arg0 581 582 // Constant flag values. For any comparison, there are 3 possible 583 // outcomes: either the three from the signed total order (<,==,>) 584 // or the three from the unsigned total order, depending on which 585 // comparison operation was used (CMP or CMPU -- PPC is different from 586 // the other architectures, which have a single comparison producing 587 // both signed and unsigned comparison results.) 588 589 // These ops are for temporary use by rewrite rules. They 590 // cannot appear in the generated assembly. 591 {name: "FlagEQ"}, // equal 592 {name: "FlagLT"}, // signed < or unsigned < 593 {name: "FlagGT"}, // signed > or unsigned > 594 595 } 596 597 blocks := []blockData{ 598 {name: "EQ", controls: 1}, 599 {name: "NE", controls: 1}, 600 {name: "LT", controls: 1}, 601 {name: "LE", controls: 1}, 602 {name: "GT", controls: 1}, 603 {name: "GE", controls: 1}, 604 {name: "FLT", controls: 1}, 605 {name: "FLE", controls: 1}, 606 {name: "FGT", controls: 1}, 607 {name: "FGE", controls: 1}, 608 } 609 610 archs = append(archs, arch{ 611 name: "PPC64", 612 pkg: "github.com/gagliardetto/golang-go/cmd/internal/obj/ppc64", 613 genfile: "../../ppc64/ssa.go", 614 ops: ops, 615 blocks: blocks, 616 regnames: regNamesPPC64, 617 gpregmask: gp, 618 fpregmask: fp, 619 framepointerreg: int8(num["SP"]), 620 linkreg: -1, // not used 621 }) 622 }