github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/cmd/compile/internal/ssa/gen/S390XOps.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 // - Integer types live in the low portion of registers. Upper portions are junk. 13 // - Boolean types use the low-order byte of a register. 0=false, 1=true. 14 // Upper bytes are junk. 15 // - When doing sub-register operations, we try to write the whole 16 // destination register to avoid a partial-register write. 17 // - Unused portions of AuxInt (or the Val portion of ValAndOff) are 18 // filled by sign-extending the used portion. Users of AuxInt which interpret 19 // AuxInt as unsigned (e.g. shifts) must be careful. 20 // - The SB 'register' is implemented using instruction-relative addressing. This 21 // places some limitations on when and how memory operands that are addressed 22 // relative to SB can be used: 23 // 24 // 1. Pseudo-instructions do not always map to a single machine instruction when 25 // using the SB 'register' to address data. This is because many machine 26 // instructions do not have relative long (RL suffix) equivalents. For example, 27 // ADDload, which is assembled as AG. 28 // 29 // 2. Loads and stores using relative addressing require the data be aligned 30 // according to its size (8-bytes for double words, 4-bytes for words 31 // and so on). 32 // 33 // We can always work around these by inserting LARL instructions (load address 34 // relative long) in the assembler, but typically this results in worse code 35 // generation because the address can't be re-used. Inserting instructions in the 36 // assembler also means clobbering the temp register and it is a long-term goal 37 // to prevent the compiler doing this so that it can be allocated as a normal 38 // register. 39 // 40 // For more information about the z/Architecture, the instruction set and the 41 // addressing modes it supports take a look at the z/Architecture Principles of 42 // Operation: http://publibfp.boulder.ibm.com/epubs/pdf/dz9zr010.pdf 43 // 44 // Suffixes encode the bit width of pseudo-instructions. 45 // D (double word) = 64 bit (frequently omitted) 46 // W (word) = 32 bit 47 // H (half word) = 16 bit 48 // B (byte) = 8 bit 49 // S (single prec.) = 32 bit (double precision is omitted) 50 51 // copied from ../../s390x/reg.go 52 var regNamesS390X = []string{ 53 "R0", 54 "R1", 55 "R2", 56 "R3", 57 "R4", 58 "R5", 59 "R6", 60 "R7", 61 "R8", 62 "R9", 63 "R10", 64 "R11", 65 "R12", 66 "g", // R13 67 "R14", 68 "SP", // R15 69 "F0", 70 "F1", 71 "F2", 72 "F3", 73 "F4", 74 "F5", 75 "F6", 76 "F7", 77 "F8", 78 "F9", 79 "F10", 80 "F11", 81 "F12", 82 "F13", 83 "F14", 84 "F15", 85 86 //pseudo-registers 87 "SB", 88 } 89 90 func init() { 91 // Make map from reg names to reg integers. 92 if len(regNamesS390X) > 64 { 93 panic("too many registers") 94 } 95 num := map[string]int{} 96 for i, name := range regNamesS390X { 97 num[name] = i 98 } 99 buildReg := func(s string) regMask { 100 m := regMask(0) 101 for _, r := range strings.Split(s, " ") { 102 if n, ok := num[r]; ok { 103 m |= regMask(1) << uint(n) 104 continue 105 } 106 panic("register " + r + " not found") 107 } 108 return m 109 } 110 111 // Common individual register masks 112 var ( 113 sp = buildReg("SP") 114 sb = buildReg("SB") 115 r0 = buildReg("R0") 116 tmp = buildReg("R11") // R11 is used as a temporary in a small number of instructions. 117 118 // R10 is reserved by the assembler. 119 gp = buildReg("R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14") 120 gpg = gp | buildReg("g") 121 gpsp = gp | sp 122 123 // R0 is considered to contain the value 0 in address calculations. 124 ptr = gp &^ r0 125 ptrsp = ptr | sp 126 ptrspsb = ptrsp | sb 127 128 fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15") 129 callerSave = gp | fp | buildReg("g") // runtime.setg (and anything calling it) may clobber g 130 ) 131 // Common slices of register masks 132 var ( 133 gponly = []regMask{gp} 134 fponly = []regMask{fp} 135 ) 136 137 // Common regInfo 138 var ( 139 gp01 = regInfo{inputs: []regMask{}, outputs: gponly} 140 gp11 = regInfo{inputs: []regMask{gp}, outputs: gponly} 141 gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: gponly} 142 gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly} 143 gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly} 144 gp21tmp = regInfo{inputs: []regMask{gp &^ tmp, gp &^ tmp}, outputs: []regMask{gp &^ tmp}, clobbers: tmp} 145 146 // R0 evaluates to 0 when used as the number of bits to shift 147 // so we need to exclude it from that operand. 148 sh21 = regInfo{inputs: []regMask{gp, ptr}, outputs: gponly} 149 150 addr = regInfo{inputs: []regMask{sp | sb}, outputs: gponly} 151 addridx = regInfo{inputs: []regMask{sp | sb, ptrsp}, outputs: gponly} 152 153 gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}} 154 gp1flags = regInfo{inputs: []regMask{gpsp}} 155 gp2flags1 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly} 156 157 gpload = regInfo{inputs: []regMask{ptrspsb, 0}, outputs: gponly} 158 gploadidx = regInfo{inputs: []regMask{ptrspsb, ptrsp, 0}, outputs: gponly} 159 gpopload = regInfo{inputs: []regMask{gp, ptrsp, 0}, outputs: gponly} 160 gpstore = regInfo{inputs: []regMask{ptrspsb, gpsp, 0}} 161 gpstoreconst = regInfo{inputs: []regMask{ptrspsb, 0}} 162 gpstoreidx = regInfo{inputs: []regMask{ptrsp, ptrsp, gpsp, 0}} 163 gpstorebr = regInfo{inputs: []regMask{ptrsp, gpsp, 0}} 164 gpstorelaa = regInfo{inputs: []regMask{ptrspsb, gpsp, 0}, outputs: gponly} 165 166 gpmvc = regInfo{inputs: []regMask{ptrsp, ptrsp, 0}} 167 168 fp01 = regInfo{inputs: []regMask{}, outputs: fponly} 169 fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: fponly} 170 fp31 = regInfo{inputs: []regMask{fp, fp, fp}, outputs: fponly} 171 fp21clobber = regInfo{inputs: []regMask{fp, fp}, outputs: fponly} 172 fpgp = regInfo{inputs: fponly, outputs: gponly} 173 gpfp = regInfo{inputs: gponly, outputs: fponly} 174 fp11 = regInfo{inputs: fponly, outputs: fponly} 175 fp11clobber = regInfo{inputs: fponly, outputs: fponly} 176 fp2flags = regInfo{inputs: []regMask{fp, fp}} 177 178 fpload = regInfo{inputs: []regMask{ptrspsb, 0}, outputs: fponly} 179 fploadidx = regInfo{inputs: []regMask{ptrsp, ptrsp, 0}, outputs: fponly} 180 181 fpstore = regInfo{inputs: []regMask{ptrspsb, fp, 0}} 182 fpstoreidx = regInfo{inputs: []regMask{ptrsp, ptrsp, fp, 0}} 183 184 // LoweredAtomicCas may overwrite arg1, so force it to R0 for now. 185 cas = regInfo{inputs: []regMask{ptrsp, r0, gpsp, 0}, outputs: []regMask{gp, 0}, clobbers: r0} 186 187 // LoweredAtomicExchange overwrites the output before executing 188 // CS{,G}, so the output register must not be the same as the 189 // input register. For now we just force the output register to 190 // R0. 191 exchange = regInfo{inputs: []regMask{ptrsp, gpsp &^ r0, 0}, outputs: []regMask{r0, 0}} 192 ) 193 194 var S390Xops = []opData{ 195 // fp ops 196 {name: "FADDS", argLength: 2, reg: fp21clobber, asm: "FADDS", commutative: true, resultInArg0: true, clobberFlags: true}, // fp32 arg0 + arg1 197 {name: "FADD", argLength: 2, reg: fp21clobber, asm: "FADD", commutative: true, resultInArg0: true, clobberFlags: true}, // fp64 arg0 + arg1 198 {name: "FSUBS", argLength: 2, reg: fp21clobber, asm: "FSUBS", resultInArg0: true, clobberFlags: true}, // fp32 arg0 - arg1 199 {name: "FSUB", argLength: 2, reg: fp21clobber, asm: "FSUB", resultInArg0: true, clobberFlags: true}, // fp64 arg0 - arg1 200 {name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true, resultInArg0: true}, // fp32 arg0 * arg1 201 {name: "FMUL", argLength: 2, reg: fp21, asm: "FMUL", commutative: true, resultInArg0: true}, // fp64 arg0 * arg1 202 {name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS", resultInArg0: true}, // fp32 arg0 / arg1 203 {name: "FDIV", argLength: 2, reg: fp21, asm: "FDIV", resultInArg0: true}, // fp64 arg0 / arg1 204 {name: "FNEGS", argLength: 1, reg: fp11clobber, asm: "FNEGS", clobberFlags: true}, // fp32 -arg0 205 {name: "FNEG", argLength: 1, reg: fp11clobber, asm: "FNEG", clobberFlags: true}, // fp64 -arg0 206 {name: "FMADDS", argLength: 3, reg: fp31, asm: "FMADDS", resultInArg0: true}, // fp32 arg1 * arg2 + arg0 207 {name: "FMADD", argLength: 3, reg: fp31, asm: "FMADD", resultInArg0: true}, // fp64 arg1 * arg2 + arg0 208 {name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS", resultInArg0: true}, // fp32 arg1 * arg2 - arg0 209 {name: "FMSUB", argLength: 3, reg: fp31, asm: "FMSUB", resultInArg0: true}, // fp64 arg1 * arg2 - arg0 210 {name: "LPDFR", argLength: 1, reg: fp11, asm: "LPDFR"}, // fp64/fp32 set sign bit 211 {name: "LNDFR", argLength: 1, reg: fp11, asm: "LNDFR"}, // fp64/fp32 clear sign bit 212 {name: "CPSDR", argLength: 2, reg: fp21, asm: "CPSDR"}, // fp64/fp32 copy arg1 sign bit to arg0 213 214 // Round to integer, float64 only. 215 // 216 // aux | rounding mode 217 // ----+----------------------------------- 218 // 1 | round to nearest, ties away from 0 219 // 4 | round to nearest, ties to even 220 // 5 | round toward 0 221 // 6 | round toward +∞ 222 // 7 | round toward -∞ 223 {name: "FIDBR", argLength: 1, reg: fp11, asm: "FIDBR", aux: "Int8"}, 224 225 {name: "FMOVSload", argLength: 2, reg: fpload, asm: "FMOVS", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // fp32 load 226 {name: "FMOVDload", argLength: 2, reg: fpload, asm: "FMOVD", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // fp64 load 227 {name: "FMOVSconst", reg: fp01, asm: "FMOVS", aux: "Float32", rematerializeable: true}, // fp32 constant 228 {name: "FMOVDconst", reg: fp01, asm: "FMOVD", aux: "Float64", rematerializeable: true}, // fp64 constant 229 {name: "FMOVSloadidx", argLength: 3, reg: fploadidx, asm: "FMOVS", aux: "SymOff", symEffect: "Read"}, // fp32 load indexed by i 230 {name: "FMOVDloadidx", argLength: 3, reg: fploadidx, asm: "FMOVD", aux: "SymOff", symEffect: "Read"}, // fp64 load indexed by i 231 232 {name: "FMOVSstore", argLength: 3, reg: fpstore, asm: "FMOVS", aux: "SymOff", faultOnNilArg0: true, symEffect: "Write"}, // fp32 store 233 {name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "FMOVD", aux: "SymOff", faultOnNilArg0: true, symEffect: "Write"}, // fp64 store 234 {name: "FMOVSstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVS", aux: "SymOff", symEffect: "Write"}, // fp32 indexed by i store 235 {name: "FMOVDstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVD", aux: "SymOff", symEffect: "Write"}, // fp64 indexed by i store 236 237 // binary ops 238 {name: "ADD", argLength: 2, reg: gp21sp, asm: "ADD", commutative: true, clobberFlags: true}, // arg0 + arg1 239 {name: "ADDW", argLength: 2, reg: gp21sp, asm: "ADDW", commutative: true, clobberFlags: true}, // arg0 + arg1 240 {name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADD", aux: "Int32", typ: "UInt64", clobberFlags: true}, // arg0 + auxint 241 {name: "ADDWconst", argLength: 1, reg: gp11sp, asm: "ADDW", aux: "Int32", clobberFlags: true}, // arg0 + auxint 242 {name: "ADDload", argLength: 3, reg: gpopload, asm: "ADD", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 + *arg1. arg2=mem 243 {name: "ADDWload", argLength: 3, reg: gpopload, asm: "ADDW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 + *arg1. arg2=mem 244 245 {name: "SUB", argLength: 2, reg: gp21, asm: "SUB", clobberFlags: true}, // arg0 - arg1 246 {name: "SUBW", argLength: 2, reg: gp21, asm: "SUBW", clobberFlags: true}, // arg0 - arg1 247 {name: "SUBconst", argLength: 1, reg: gp11, asm: "SUB", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 - auxint 248 {name: "SUBWconst", argLength: 1, reg: gp11, asm: "SUBW", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 - auxint 249 {name: "SUBload", argLength: 3, reg: gpopload, asm: "SUB", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 - *arg1. arg2=mem 250 {name: "SUBWload", argLength: 3, reg: gpopload, asm: "SUBW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 - *arg1. arg2=mem 251 252 {name: "MULLD", argLength: 2, reg: gp21, asm: "MULLD", typ: "Int64", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 * arg1 253 {name: "MULLW", argLength: 2, reg: gp21, asm: "MULLW", typ: "Int32", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 * arg1 254 {name: "MULLDconst", argLength: 1, reg: gp11, asm: "MULLD", aux: "Int32", typ: "Int64", resultInArg0: true, clobberFlags: true}, // arg0 * auxint 255 {name: "MULLWconst", argLength: 1, reg: gp11, asm: "MULLW", aux: "Int32", typ: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 * auxint 256 {name: "MULLDload", argLength: 3, reg: gpopload, asm: "MULLD", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 * *arg1. arg2=mem 257 {name: "MULLWload", argLength: 3, reg: gpopload, asm: "MULLW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 * *arg1. arg2=mem 258 259 {name: "MULHD", argLength: 2, reg: gp21tmp, asm: "MULHD", typ: "Int64", commutative: true, resultInArg0: true, clobberFlags: true}, // (arg0 * arg1) >> width 260 {name: "MULHDU", argLength: 2, reg: gp21tmp, asm: "MULHDU", typ: "Int64", commutative: true, resultInArg0: true, clobberFlags: true}, // (arg0 * arg1) >> width 261 262 {name: "DIVD", argLength: 2, reg: gp21tmp, asm: "DIVD", resultInArg0: true, clobberFlags: true}, // arg0 / arg1 263 {name: "DIVW", argLength: 2, reg: gp21tmp, asm: "DIVW", resultInArg0: true, clobberFlags: true}, // arg0 / arg1 264 {name: "DIVDU", argLength: 2, reg: gp21tmp, asm: "DIVDU", resultInArg0: true, clobberFlags: true}, // arg0 / arg1 265 {name: "DIVWU", argLength: 2, reg: gp21tmp, asm: "DIVWU", resultInArg0: true, clobberFlags: true}, // arg0 / arg1 266 267 {name: "MODD", argLength: 2, reg: gp21tmp, asm: "MODD", resultInArg0: true, clobberFlags: true}, // arg0 % arg1 268 {name: "MODW", argLength: 2, reg: gp21tmp, asm: "MODW", resultInArg0: true, clobberFlags: true}, // arg0 % arg1 269 270 {name: "MODDU", argLength: 2, reg: gp21tmp, asm: "MODDU", resultInArg0: true, clobberFlags: true}, // arg0 % arg1 271 {name: "MODWU", argLength: 2, reg: gp21tmp, asm: "MODWU", resultInArg0: true, clobberFlags: true}, // arg0 % arg1 272 273 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true, clobberFlags: true}, // arg0 & arg1 274 {name: "ANDW", argLength: 2, reg: gp21, asm: "ANDW", commutative: true, clobberFlags: true}, // arg0 & arg1 275 {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64", resultInArg0: true, clobberFlags: true}, // arg0 & auxint 276 {name: "ANDWconst", argLength: 1, reg: gp11, asm: "ANDW", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 & auxint 277 {name: "ANDload", argLength: 3, reg: gpopload, asm: "AND", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 & *arg1. arg2=mem 278 {name: "ANDWload", argLength: 3, reg: gpopload, asm: "ANDW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 & *arg1. arg2=mem 279 280 {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true, clobberFlags: true}, // arg0 | arg1 281 {name: "ORW", argLength: 2, reg: gp21, asm: "ORW", commutative: true, clobberFlags: true}, // arg0 | arg1 282 {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64", resultInArg0: true, clobberFlags: true}, // arg0 | auxint 283 {name: "ORWconst", argLength: 1, reg: gp11, asm: "ORW", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 | auxint 284 {name: "ORload", argLength: 3, reg: gpopload, asm: "OR", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 | *arg1. arg2=mem 285 {name: "ORWload", argLength: 3, reg: gpopload, asm: "ORW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 | *arg1. arg2=mem 286 287 {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, clobberFlags: true}, // arg0 ^ arg1 288 {name: "XORW", argLength: 2, reg: gp21, asm: "XORW", commutative: true, clobberFlags: true}, // arg0 ^ arg1 289 {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64", resultInArg0: true, clobberFlags: true}, // arg0 ^ auxint 290 {name: "XORWconst", argLength: 1, reg: gp11, asm: "XORW", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 ^ auxint 291 {name: "XORload", argLength: 3, reg: gpopload, asm: "XOR", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 ^ *arg1. arg2=mem 292 {name: "XORWload", argLength: 3, reg: gpopload, asm: "XORW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 ^ *arg1. arg2=mem 293 294 {name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1 295 {name: "CMPW", argLength: 2, reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1 296 297 {name: "CMPU", argLength: 2, reg: gp2flags, asm: "CMPU", typ: "Flags"}, // arg0 compare to arg1 298 {name: "CMPWU", argLength: 2, reg: gp2flags, asm: "CMPWU", typ: "Flags"}, // arg0 compare to arg1 299 300 {name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", typ: "Flags", aux: "Int32"}, // arg0 compare to auxint 301 {name: "CMPWconst", argLength: 1, reg: gp1flags, asm: "CMPW", typ: "Flags", aux: "Int32"}, // arg0 compare to auxint 302 {name: "CMPUconst", argLength: 1, reg: gp1flags, asm: "CMPU", typ: "Flags", aux: "Int32"}, // arg0 compare to auxint 303 {name: "CMPWUconst", argLength: 1, reg: gp1flags, asm: "CMPWU", typ: "Flags", aux: "Int32"}, // arg0 compare to auxint 304 305 {name: "FCMPS", argLength: 2, reg: fp2flags, asm: "CEBR", typ: "Flags"}, // arg0 compare to arg1, f32 306 {name: "FCMP", argLength: 2, reg: fp2flags, asm: "FCMPU", typ: "Flags"}, // arg0 compare to arg1, f64 307 308 {name: "SLD", argLength: 2, reg: sh21, asm: "SLD"}, // arg0 << arg1, shift amount is mod 64 309 {name: "SLW", argLength: 2, reg: sh21, asm: "SLW"}, // arg0 << arg1, shift amount is mod 32 310 {name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int8"}, // arg0 << auxint, shift amount 0-63 311 {name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int8"}, // arg0 << auxint, shift amount 0-31 312 313 {name: "SRD", argLength: 2, reg: sh21, asm: "SRD"}, // unsigned arg0 >> arg1, shift amount is mod 64 314 {name: "SRW", argLength: 2, reg: sh21, asm: "SRW"}, // unsigned uint32(arg0) >> arg1, shift amount is mod 32 315 {name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int8"}, // unsigned arg0 >> auxint, shift amount 0-63 316 {name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int8"}, // unsigned uint32(arg0) >> auxint, shift amount 0-31 317 318 // Arithmetic shifts clobber flags. 319 {name: "SRAD", argLength: 2, reg: sh21, asm: "SRAD", clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 64 320 {name: "SRAW", argLength: 2, reg: sh21, asm: "SRAW", clobberFlags: true}, // signed int32(arg0) >> arg1, shift amount is mod 32 321 {name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int8", clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63 322 {name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int8", clobberFlags: true}, // signed int32(arg0) >> auxint, shift amount 0-31 323 324 {name: "RLLG", argLength: 2, reg: sh21, asm: "RLLG"}, // arg0 rotate left arg1, rotate amount 0-63 325 {name: "RLL", argLength: 2, reg: sh21, asm: "RLL"}, // arg0 rotate left arg1, rotate amount 0-31 326 {name: "RLLGconst", argLength: 1, reg: gp11, asm: "RLLG", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-63 327 {name: "RLLconst", argLength: 1, reg: gp11, asm: "RLL", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-31 328 329 // unary ops 330 {name: "NEG", argLength: 1, reg: gp11, asm: "NEG", clobberFlags: true}, // -arg0 331 {name: "NEGW", argLength: 1, reg: gp11, asm: "NEGW", clobberFlags: true}, // -arg0 332 333 {name: "NOT", argLength: 1, reg: gp11, resultInArg0: true, clobberFlags: true}, // ^arg0 334 {name: "NOTW", argLength: 1, reg: gp11, resultInArg0: true, clobberFlags: true}, // ^arg0 335 336 {name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0) 337 338 {name: "MOVDEQ", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDEQ"}, // extract == condition from arg0 339 {name: "MOVDNE", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDNE"}, // extract != condition from arg0 340 {name: "MOVDLT", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDLT"}, // extract signed < condition from arg0 341 {name: "MOVDLE", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDLE"}, // extract signed <= condition from arg0 342 {name: "MOVDGT", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDGT"}, // extract signed > condition from arg0 343 {name: "MOVDGE", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDGE"}, // extract signed >= condition from arg0 344 345 // Different rules for floating point conditions because 346 // any comparison involving a NaN is always false and thus 347 // the patterns for inverting conditions cannot be used. 348 {name: "MOVDGTnoinv", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDGT"}, // extract floating > condition from arg0 349 {name: "MOVDGEnoinv", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDGE"}, // extract floating >= condition from arg0 350 351 {name: "MOVBreg", argLength: 1, reg: gp11sp, asm: "MOVB", typ: "Int64"}, // sign extend arg0 from int8 to int64 352 {name: "MOVBZreg", argLength: 1, reg: gp11sp, asm: "MOVBZ", typ: "UInt64"}, // zero extend arg0 from int8 to int64 353 {name: "MOVHreg", argLength: 1, reg: gp11sp, asm: "MOVH", typ: "Int64"}, // sign extend arg0 from int16 to int64 354 {name: "MOVHZreg", argLength: 1, reg: gp11sp, asm: "MOVHZ", typ: "UInt64"}, // zero extend arg0 from int16 to int64 355 {name: "MOVWreg", argLength: 1, reg: gp11sp, asm: "MOVW", typ: "Int64"}, // sign extend arg0 from int32 to int64 356 {name: "MOVWZreg", argLength: 1, reg: gp11sp, asm: "MOVWZ", typ: "UInt64"}, // zero extend arg0 from int32 to int64 357 {name: "MOVDreg", argLength: 1, reg: gp11sp, asm: "MOVD"}, // move from arg0 358 359 {name: "MOVDnop", argLength: 1, reg: gp11, resultInArg0: true}, // nop, return arg0 in same register 360 361 {name: "MOVDconst", reg: gp01, asm: "MOVD", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint 362 363 {name: "LDGR", argLength: 1, reg: gpfp, asm: "LDGR"}, // move int64 to float64 (no conversion) 364 {name: "LGDR", argLength: 1, reg: fpgp, asm: "LGDR"}, // move float64 to int64 (no conversion) 365 {name: "CFDBRA", argLength: 1, reg: fpgp, asm: "CFDBRA"}, // convert float64 to int32 366 {name: "CGDBRA", argLength: 1, reg: fpgp, asm: "CGDBRA"}, // convert float64 to int64 367 {name: "CFEBRA", argLength: 1, reg: fpgp, asm: "CFEBRA"}, // convert float32 to int32 368 {name: "CGEBRA", argLength: 1, reg: fpgp, asm: "CGEBRA"}, // convert float32 to int64 369 {name: "CEFBRA", argLength: 1, reg: gpfp, asm: "CEFBRA"}, // convert int32 to float32 370 {name: "CDFBRA", argLength: 1, reg: gpfp, asm: "CDFBRA"}, // convert int32 to float64 371 {name: "CEGBRA", argLength: 1, reg: gpfp, asm: "CEGBRA"}, // convert int64 to float32 372 {name: "CDGBRA", argLength: 1, reg: gpfp, asm: "CDGBRA"}, // convert int64 to float64 373 {name: "LEDBR", argLength: 1, reg: fp11, asm: "LEDBR"}, // convert float64 to float32 374 {name: "LDEBR", argLength: 1, reg: fp11, asm: "LDEBR"}, // convert float32 to float64 375 376 {name: "MOVDaddr", argLength: 1, reg: addr, aux: "SymOff", rematerializeable: true, symEffect: "Read"}, // arg0 + auxint + offset encoded in aux 377 {name: "MOVDaddridx", argLength: 2, reg: addridx, aux: "SymOff", symEffect: "Read"}, // arg0 + arg1 + auxint + aux 378 379 // auxint+aux == add auxint and the offset of the symbol in aux (if any) to the effective address 380 {name: "MOVBZload", argLength: 2, reg: gpload, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"}, // load byte from arg0+auxint+aux. arg1=mem. Zero extend. 381 {name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"}, // ditto, sign extend to int64 382 {name: "MOVHZload", argLength: 2, reg: gpload, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"}, // load 2 bytes from arg0+auxint+aux. arg1=mem. Zero extend. 383 {name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"}, // ditto, sign extend to int64 384 {name: "MOVWZload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"}, // load 4 bytes from arg0+auxint+aux. arg1=mem. Zero extend. 385 {name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"}, // ditto, sign extend to int64 386 {name: "MOVDload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", typ: "UInt64", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"}, // load 8 bytes from arg0+auxint+aux. arg1=mem 387 388 {name: "MOVWBR", argLength: 1, reg: gp11, asm: "MOVWBR"}, // arg0 swap bytes 389 {name: "MOVDBR", argLength: 1, reg: gp11, asm: "MOVDBR"}, // arg0 swap bytes 390 391 {name: "MOVHBRload", argLength: 2, reg: gpload, asm: "MOVHBR", aux: "SymOff", typ: "UInt16", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"}, // load 2 bytes from arg0+auxint+aux. arg1=mem. Reverse bytes. 392 {name: "MOVWBRload", argLength: 2, reg: gpload, asm: "MOVWBR", aux: "SymOff", typ: "UInt32", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"}, // load 4 bytes from arg0+auxint+aux. arg1=mem. Reverse bytes. 393 {name: "MOVDBRload", argLength: 2, reg: gpload, asm: "MOVDBR", aux: "SymOff", typ: "UInt64", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read"}, // load 8 bytes from arg0+auxint+aux. arg1=mem. Reverse bytes. 394 395 {name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, // store byte in arg1 to arg0+auxint+aux. arg2=mem 396 {name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem 397 {name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem 398 {name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem 399 {name: "MOVHBRstore", argLength: 3, reg: gpstorebr, asm: "MOVHBR", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem. Reverse bytes. 400 {name: "MOVWBRstore", argLength: 3, reg: gpstorebr, asm: "MOVWBR", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem. Reverse bytes. 401 {name: "MOVDBRstore", argLength: 3, reg: gpstorebr, asm: "MOVDBR", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem. Reverse bytes. 402 403 {name: "MVC", argLength: 3, reg: gpmvc, asm: "MVC", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, faultOnNilArg1: true, symEffect: "None"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size,off 404 405 // indexed loads/stores 406 {name: "MOVBZloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", clobberFlags: true, symEffect: "Read"}, // load a byte from arg0+arg1+auxint+aux. arg2=mem. Zero extend. 407 {name: "MOVBloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVB", aux: "SymOff", typ: "Int8", clobberFlags: true, symEffect: "Read"}, // load a byte from arg0+arg1+auxint+aux. arg2=mem. Sign extend. 408 {name: "MOVHZloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", clobberFlags: true, symEffect: "Read"}, // load 2 bytes from arg0+arg1+auxint+aux. arg2=mem. Zero extend. 409 {name: "MOVHloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVH", aux: "SymOff", typ: "Int16", clobberFlags: true, symEffect: "Read"}, // load 2 bytes from arg0+arg1+auxint+aux. arg2=mem. Sign extend. 410 {name: "MOVWZloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", clobberFlags: true, symEffect: "Read"}, // load 4 bytes from arg0+arg1+auxint+aux. arg2=mem. Zero extend. 411 {name: "MOVWloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVW", aux: "SymOff", typ: "Int32", clobberFlags: true, symEffect: "Read"}, // load 4 bytes from arg0+arg1+auxint+aux. arg2=mem. Sign extend. 412 {name: "MOVDloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVD", aux: "SymOff", typ: "UInt64", clobberFlags: true, symEffect: "Read"}, // load 8 bytes from arg0+arg1+auxint+aux. arg2=mem 413 {name: "MOVHBRloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVHBR", aux: "SymOff", typ: "Int16", clobberFlags: true, symEffect: "Read"}, // load 2 bytes from arg0+arg1+auxint+aux. arg2=mem. Reverse bytes. 414 {name: "MOVWBRloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVWBR", aux: "SymOff", typ: "Int32", clobberFlags: true, symEffect: "Read"}, // load 4 bytes from arg0+arg1+auxint+aux. arg2=mem. Reverse bytes. 415 {name: "MOVDBRloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVDBR", aux: "SymOff", typ: "Int64", clobberFlags: true, symEffect: "Read"}, // load 8 bytes from arg0+arg1+auxint+aux. arg2=mem. Reverse bytes. 416 {name: "MOVBstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVB", aux: "SymOff", clobberFlags: true, symEffect: "Write"}, // store byte in arg2 to arg0+arg1+auxint+aux. arg3=mem 417 {name: "MOVHstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVH", aux: "SymOff", clobberFlags: true, symEffect: "Write"}, // store 2 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem 418 {name: "MOVWstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVW", aux: "SymOff", clobberFlags: true, symEffect: "Write"}, // store 4 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem 419 {name: "MOVDstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVD", aux: "SymOff", clobberFlags: true, symEffect: "Write"}, // store 8 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem 420 {name: "MOVHBRstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVHBR", aux: "SymOff", clobberFlags: true, symEffect: "Write"}, // store 2 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem. Reverse bytes. 421 {name: "MOVWBRstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVWBR", aux: "SymOff", clobberFlags: true, symEffect: "Write"}, // store 4 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem. Reverse bytes. 422 {name: "MOVDBRstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVDBR", aux: "SymOff", clobberFlags: true, symEffect: "Write"}, // store 8 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem. Reverse bytes. 423 424 // For storeconst ops, the AuxInt field encodes both 425 // the value to store and an address offset of the store. 426 // Cast AuxInt to a ValAndOff to extract Val and Off fields. 427 {name: "MOVBstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVB", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low byte of ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux. arg1=mem 428 {name: "MOVHstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVH", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low 2 bytes of ... 429 {name: "MOVWstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVW", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low 4 bytes of ... 430 {name: "MOVDstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVD", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of ... 431 432 {name: "CLEAR", argLength: 2, reg: regInfo{inputs: []regMask{ptr, 0}}, asm: "CLEAR", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, 433 434 {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 435 {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{ptrsp, buildReg("R12"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem 436 {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{ptr}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem 437 438 // (InvertFlags (CMP a b)) == (CMP b a) 439 // InvertFlags is a pseudo-op which can't appear in assembly output. 440 {name: "InvertFlags", argLength: 1}, // reverse direction of arg0 441 442 // Pseudo-ops 443 {name: "LoweredGetG", argLength: 1, reg: gp01}, // arg0=mem 444 // Scheduler ensures LoweredGetClosurePtr occurs only in entry block, 445 // and sorts it to the very beginning of the block to prevent other 446 // use of R12 (the closure pointer) 447 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R12")}}, zeroWidth: true}, 448 // arg0=ptr,arg1=mem, returns void. Faults if ptr is nil. 449 // LoweredGetCallerSP returns the SP of the caller of the current function. 450 {name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true}, 451 // LoweredGetCallerPC evaluates to the PC to which its "caller" will return. 452 // I.e., if f calls g "calls" getcallerpc, 453 // the result should be the PC within f that g will return to. 454 // See runtime/stubs.go for a more detailed discussion. 455 {name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true}, 456 {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{ptrsp}}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true}, 457 // Round ops to block fused-multiply-add extraction. 458 {name: "LoweredRound32F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true}, 459 {name: "LoweredRound64F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true}, 460 461 // LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier 462 // It saves all GP registers if necessary, 463 // but clobbers R14 (LR) because it's a call. 464 {name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R2"), buildReg("R3")}, clobbers: (callerSave &^ gpg) | buildReg("R14")}, clobberFlags: true, aux: "Sym", symEffect: "None"}, 465 466 // Constant flag values. For any comparison, there are 5 possible 467 // outcomes: the three from the signed total order (<,==,>) and the 468 // three from the unsigned total order. The == cases overlap. 469 // Note: there's a sixth "unordered" outcome for floating-point 470 // comparisons, but we don't use such a beast yet. 471 // These ops are for temporary use by rewrite rules. They 472 // cannot appear in the generated assembly. 473 {name: "FlagEQ"}, // equal 474 {name: "FlagLT"}, // < 475 {name: "FlagGT"}, // > 476 477 // Atomic loads. These are just normal loads but return <value,memory> tuples 478 // so they can be properly ordered with other loads. 479 // load from arg0+auxint+aux. arg1=mem. 480 {name: "MOVWZatomicload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, 481 {name: "MOVDatomicload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, 482 483 // Atomic stores. These are just normal stores. 484 // store arg1 to arg0+auxint+aux. arg2=mem. 485 {name: "MOVWatomicstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "Write"}, 486 {name: "MOVDatomicstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "Write"}, 487 488 // Atomic adds. 489 // *(arg0+auxint+aux) += arg1. arg2=mem. 490 // Returns a tuple of <old contents of *(arg0+auxint+aux), memory>. 491 {name: "LAA", argLength: 3, reg: gpstorelaa, asm: "LAA", typ: "(UInt32,Mem)", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, 492 {name: "LAAG", argLength: 3, reg: gpstorelaa, asm: "LAAG", typ: "(UInt64,Mem)", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, 493 {name: "AddTupleFirst32", argLength: 2}, // arg1=tuple <x,y>. Returns <x+arg0,y>. 494 {name: "AddTupleFirst64", argLength: 2}, // arg1=tuple <x,y>. Returns <x+arg0,y>. 495 496 // Compare and swap. 497 // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. 498 // if *(arg0+auxint+aux) == arg1 { 499 // *(arg0+auxint+aux) = arg2 500 // return (true, memory) 501 // } else { 502 // return (false, memory) 503 // } 504 // Note that these instructions also return the old value in arg1, but we ignore it. 505 // TODO: have these return flags instead of bool. The current system generates: 506 // CS ... 507 // MOVD $0, ret 508 // BNE 2(PC) 509 // MOVD $1, ret 510 // CMPW ret, $0 511 // BNE ... 512 // instead of just 513 // CS ... 514 // BEQ ... 515 // but we can't do that because memory-using ops can't generate flags yet 516 // (flagalloc wants to move flag-generating instructions around). 517 {name: "LoweredAtomicCas32", argLength: 4, reg: cas, asm: "CS", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, 518 {name: "LoweredAtomicCas64", argLength: 4, reg: cas, asm: "CSG", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, 519 520 // Lowered atomic swaps, emulated using compare-and-swap. 521 // store arg1 to arg0+auxint+aux, arg2=mem. 522 {name: "LoweredAtomicExchange32", argLength: 3, reg: exchange, asm: "CS", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, 523 {name: "LoweredAtomicExchange64", argLength: 3, reg: exchange, asm: "CSG", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, 524 525 // find leftmost one 526 { 527 name: "FLOGR", 528 argLength: 1, 529 reg: regInfo{inputs: gponly, outputs: []regMask{buildReg("R0")}, clobbers: buildReg("R1")}, 530 asm: "FLOGR", 531 typ: "UInt64", 532 clobberFlags: true, 533 }, 534 535 // population count 536 // 537 // Counts the number of ones in each byte of arg0 538 // and places the result into the corresponding byte 539 // of the result. 540 { 541 name: "POPCNT", 542 argLength: 1, 543 reg: gp11, 544 asm: "POPCNT", 545 typ: "UInt64", 546 clobberFlags: true, 547 }, 548 549 // pseudo operations to sum the output of the POPCNT instruction 550 {name: "SumBytes2", argLength: 1, typ: "UInt8"}, // sum the rightmost 2 bytes in arg0 ignoring overflow 551 {name: "SumBytes4", argLength: 1, typ: "UInt8"}, // sum the rightmost 4 bytes in arg0 ignoring overflow 552 {name: "SumBytes8", argLength: 1, typ: "UInt8"}, // sum all the bytes in arg0 ignoring overflow 553 554 // store multiple 555 { 556 name: "STMG2", 557 argLength: 4, 558 reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), 0}}, 559 aux: "SymOff", 560 typ: "Mem", 561 asm: "STMG", 562 faultOnNilArg0: true, 563 symEffect: "Write", 564 }, 565 { 566 name: "STMG3", 567 argLength: 5, 568 reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), buildReg("R3"), 0}}, 569 aux: "SymOff", 570 typ: "Mem", 571 asm: "STMG", 572 faultOnNilArg0: true, 573 symEffect: "Write", 574 }, 575 { 576 name: "STMG4", 577 argLength: 6, 578 reg: regInfo{inputs: []regMask{ 579 ptrsp, 580 buildReg("R1"), 581 buildReg("R2"), 582 buildReg("R3"), 583 buildReg("R4"), 584 0, 585 }}, 586 aux: "SymOff", 587 typ: "Mem", 588 asm: "STMG", 589 faultOnNilArg0: true, 590 symEffect: "Write", 591 }, 592 { 593 name: "STM2", 594 argLength: 4, 595 reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), 0}}, 596 aux: "SymOff", 597 typ: "Mem", 598 asm: "STMY", 599 faultOnNilArg0: true, 600 symEffect: "Write", 601 }, 602 { 603 name: "STM3", 604 argLength: 5, 605 reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), buildReg("R3"), 0}}, 606 aux: "SymOff", 607 typ: "Mem", 608 asm: "STMY", 609 faultOnNilArg0: true, 610 symEffect: "Write", 611 }, 612 { 613 name: "STM4", 614 argLength: 6, 615 reg: regInfo{inputs: []regMask{ 616 ptrsp, 617 buildReg("R1"), 618 buildReg("R2"), 619 buildReg("R3"), 620 buildReg("R4"), 621 0, 622 }}, 623 aux: "SymOff", 624 typ: "Mem", 625 asm: "STMY", 626 faultOnNilArg0: true, 627 symEffect: "Write", 628 }, 629 630 // large move 631 // auxint = remaining bytes after loop (rem) 632 // arg0 = address of dst memory (in R1, changed as a side effect) 633 // arg1 = address of src memory (in R2, changed as a side effect) 634 // arg2 = pointer to last address to move in loop + 256 635 // arg3 = mem 636 // returns mem 637 // 638 // mvc: MVC $256, 0(R2), 0(R1) 639 // MOVD $256(R1), R1 640 // MOVD $256(R2), R2 641 // CMP R2, Rarg2 642 // BNE mvc 643 // MVC $rem, 0(R2), 0(R1) // if rem > 0 644 { 645 name: "LoweredMove", 646 aux: "Int64", 647 argLength: 4, 648 reg: regInfo{ 649 inputs: []regMask{buildReg("R1"), buildReg("R2"), gpsp}, 650 clobbers: buildReg("R1 R2"), 651 }, 652 clobberFlags: true, 653 typ: "Mem", 654 faultOnNilArg0: true, 655 faultOnNilArg1: true, 656 }, 657 658 // large clear 659 // auxint = remaining bytes after loop (rem) 660 // arg0 = address of dst memory (in R1, changed as a side effect) 661 // arg1 = pointer to last address to zero in loop + 256 662 // arg2 = mem 663 // returns mem 664 // 665 // clear: CLEAR $256, 0(R1) 666 // MOVD $256(R1), R1 667 // CMP R1, Rarg2 668 // BNE clear 669 // CLEAR $rem, 0(R1) // if rem > 0 670 { 671 name: "LoweredZero", 672 aux: "Int64", 673 argLength: 3, 674 reg: regInfo{ 675 inputs: []regMask{buildReg("R1"), gpsp}, 676 clobbers: buildReg("R1"), 677 }, 678 clobberFlags: true, 679 typ: "Mem", 680 faultOnNilArg0: true, 681 }, 682 } 683 684 var S390Xblocks = []blockData{ 685 {name: "EQ"}, 686 {name: "NE"}, 687 {name: "LT"}, 688 {name: "LE"}, 689 {name: "GT"}, 690 {name: "GE"}, 691 {name: "GTF"}, // FP comparison 692 {name: "GEF"}, // FP comparison 693 } 694 695 archs = append(archs, arch{ 696 name: "S390X", 697 pkg: "cmd/internal/obj/s390x", 698 genfile: "../../s390x/ssa.go", 699 ops: S390Xops, 700 blocks: S390Xblocks, 701 regnames: regNamesS390X, 702 gpregmask: gp, 703 fpregmask: fp, 704 framepointerreg: -1, // not used 705 linkreg: int8(num["R14"]), 706 }) 707 }