github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/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 // If you add registers, update asyncPreempt in runtime. 87 88 //pseudo-registers 89 "SB", 90 } 91 92 func init() { 93 // Make map from reg names to reg integers. 94 if len(regNamesS390X) > 64 { 95 panic("too many registers") 96 } 97 num := map[string]int{} 98 for i, name := range regNamesS390X { 99 num[name] = i 100 } 101 buildReg := func(s string) regMask { 102 m := regMask(0) 103 for _, r := range strings.Split(s, " ") { 104 if n, ok := num[r]; ok { 105 m |= regMask(1) << uint(n) 106 continue 107 } 108 panic("register " + r + " not found") 109 } 110 return m 111 } 112 113 // Common individual register masks 114 var ( 115 sp = buildReg("SP") 116 sb = buildReg("SB") 117 r0 = buildReg("R0") 118 tmp = buildReg("R11") // R11 is used as a temporary in a small number of instructions. 119 120 // R10 is reserved by the assembler. 121 gp = buildReg("R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14") 122 gpg = gp | buildReg("g") 123 gpsp = gp | sp 124 125 // R0 is considered to contain the value 0 in address calculations. 126 ptr = gp &^ r0 127 ptrsp = ptr | sp 128 ptrspsb = ptrsp | sb 129 130 fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15") 131 callerSave = gp | fp | buildReg("g") // runtime.setg (and anything calling it) may clobber g 132 r1 = buildReg("R1") 133 r2 = buildReg("R2") 134 r3 = buildReg("R3") 135 ) 136 // Common slices of register masks 137 var ( 138 gponly = []regMask{gp} 139 fponly = []regMask{fp} 140 ) 141 142 // Common regInfo 143 var ( 144 gp01 = regInfo{inputs: []regMask{}, outputs: gponly} 145 gp11 = regInfo{inputs: []regMask{gp}, outputs: gponly} 146 gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: gponly} 147 gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly} 148 gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly} 149 gp21tmp = regInfo{inputs: []regMask{gp &^ tmp, gp &^ tmp}, outputs: []regMask{gp &^ tmp}, clobbers: tmp} 150 151 // R0 evaluates to 0 when used as the number of bits to shift 152 // so we need to exclude it from that operand. 153 sh21 = regInfo{inputs: []regMask{gp, ptr}, outputs: gponly} 154 155 addr = regInfo{inputs: []regMask{sp | sb}, outputs: gponly} 156 addridx = regInfo{inputs: []regMask{sp | sb, ptrsp}, outputs: gponly} 157 158 gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}} 159 gp1flags = regInfo{inputs: []regMask{gpsp}} 160 gp2flags1 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly} 161 gp11flags = regInfo{inputs: []regMask{gp}, outputs: gponly} 162 gp21flags = regInfo{inputs: []regMask{gp, gp}, outputs: gponly} 163 gp2flags1flags = regInfo{inputs: []regMask{gp, gp}, outputs: gponly} 164 165 gpload = regInfo{inputs: []regMask{ptrspsb, 0}, outputs: gponly} 166 gploadidx = regInfo{inputs: []regMask{ptrspsb, ptrsp, 0}, outputs: gponly} 167 gpopload = regInfo{inputs: []regMask{gp, ptrsp, 0}, outputs: gponly} 168 gpstore = regInfo{inputs: []regMask{ptrspsb, gpsp, 0}} 169 gpstoreconst = regInfo{inputs: []regMask{ptrspsb, 0}} 170 gpstoreidx = regInfo{inputs: []regMask{ptrsp, ptrsp, gpsp, 0}} 171 gpstorebr = regInfo{inputs: []regMask{ptrsp, gpsp, 0}} 172 gpstorelaa = regInfo{inputs: []regMask{ptrspsb, gpsp, 0}, outputs: gponly} 173 gpstorelab = regInfo{inputs: []regMask{r1, gpsp, 0}, clobbers: r1} 174 175 gpmvc = regInfo{inputs: []regMask{ptrsp, ptrsp, 0}} 176 177 fp01 = regInfo{inputs: []regMask{}, outputs: fponly} 178 fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: fponly} 179 fp31 = regInfo{inputs: []regMask{fp, fp, fp}, outputs: fponly} 180 fp21clobber = regInfo{inputs: []regMask{fp, fp}, outputs: fponly} 181 fpgp = regInfo{inputs: fponly, outputs: gponly} 182 gpfp = regInfo{inputs: gponly, outputs: fponly} 183 fp11 = regInfo{inputs: fponly, outputs: fponly} 184 fp11clobber = regInfo{inputs: fponly, outputs: fponly} 185 fp2flags = regInfo{inputs: []regMask{fp, fp}} 186 187 fpload = regInfo{inputs: []regMask{ptrspsb, 0}, outputs: fponly} 188 fploadidx = regInfo{inputs: []regMask{ptrsp, ptrsp, 0}, outputs: fponly} 189 190 fpstore = regInfo{inputs: []regMask{ptrspsb, fp, 0}} 191 fpstoreidx = regInfo{inputs: []regMask{ptrsp, ptrsp, fp, 0}} 192 193 sync = regInfo{inputs: []regMask{0}} 194 195 // LoweredAtomicCas may overwrite arg1, so force it to R0 for now. 196 cas = regInfo{inputs: []regMask{ptrsp, r0, gpsp, 0}, outputs: []regMask{gp, 0}, clobbers: r0} 197 198 // LoweredAtomicExchange overwrites the output before executing 199 // CS{,G}, so the output register must not be the same as the 200 // input register. For now we just force the output register to 201 // R0. 202 exchange = regInfo{inputs: []regMask{ptrsp, gpsp &^ r0, 0}, outputs: []regMask{r0, 0}} 203 ) 204 205 var S390Xops = []opData{ 206 // fp ops 207 {name: "FADDS", argLength: 2, reg: fp21clobber, asm: "FADDS", commutative: true, resultInArg0: true, clobberFlags: true}, // fp32 arg0 + arg1 208 {name: "FADD", argLength: 2, reg: fp21clobber, asm: "FADD", commutative: true, resultInArg0: true, clobberFlags: true}, // fp64 arg0 + arg1 209 {name: "FSUBS", argLength: 2, reg: fp21clobber, asm: "FSUBS", resultInArg0: true, clobberFlags: true}, // fp32 arg0 - arg1 210 {name: "FSUB", argLength: 2, reg: fp21clobber, asm: "FSUB", resultInArg0: true, clobberFlags: true}, // fp64 arg0 - arg1 211 {name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true, resultInArg0: true}, // fp32 arg0 * arg1 212 {name: "FMUL", argLength: 2, reg: fp21, asm: "FMUL", commutative: true, resultInArg0: true}, // fp64 arg0 * arg1 213 {name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS", resultInArg0: true}, // fp32 arg0 / arg1 214 {name: "FDIV", argLength: 2, reg: fp21, asm: "FDIV", resultInArg0: true}, // fp64 arg0 / arg1 215 {name: "FNEGS", argLength: 1, reg: fp11clobber, asm: "FNEGS", clobberFlags: true}, // fp32 -arg0 216 {name: "FNEG", argLength: 1, reg: fp11clobber, asm: "FNEG", clobberFlags: true}, // fp64 -arg0 217 {name: "FMADDS", argLength: 3, reg: fp31, asm: "FMADDS", resultInArg0: true}, // fp32 arg1 * arg2 + arg0 218 {name: "FMADD", argLength: 3, reg: fp31, asm: "FMADD", resultInArg0: true}, // fp64 arg1 * arg2 + arg0 219 {name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS", resultInArg0: true}, // fp32 arg1 * arg2 - arg0 220 {name: "FMSUB", argLength: 3, reg: fp31, asm: "FMSUB", resultInArg0: true}, // fp64 arg1 * arg2 - arg0 221 {name: "LPDFR", argLength: 1, reg: fp11, asm: "LPDFR"}, // fp64/fp32 set sign bit 222 {name: "LNDFR", argLength: 1, reg: fp11, asm: "LNDFR"}, // fp64/fp32 clear sign bit 223 {name: "CPSDR", argLength: 2, reg: fp21, asm: "CPSDR"}, // fp64/fp32 copy arg1 sign bit to arg0 224 225 // Round to integer, float64 only. 226 // 227 // aux | rounding mode 228 // ----+----------------------------------- 229 // 1 | round to nearest, ties away from 0 230 // 4 | round to nearest, ties to even 231 // 5 | round toward 0 232 // 6 | round toward +∞ 233 // 7 | round toward -∞ 234 {name: "FIDBR", argLength: 1, reg: fp11, asm: "FIDBR", aux: "Int8"}, 235 236 {name: "FMOVSload", argLength: 2, reg: fpload, asm: "FMOVS", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // fp32 load 237 {name: "FMOVDload", argLength: 2, reg: fpload, asm: "FMOVD", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // fp64 load 238 {name: "FMOVSconst", reg: fp01, asm: "FMOVS", aux: "Float32", rematerializeable: true}, // fp32 constant 239 {name: "FMOVDconst", reg: fp01, asm: "FMOVD", aux: "Float64", rematerializeable: true}, // fp64 constant 240 {name: "FMOVSloadidx", argLength: 3, reg: fploadidx, asm: "FMOVS", aux: "SymOff", symEffect: "Read"}, // fp32 load indexed by i 241 {name: "FMOVDloadidx", argLength: 3, reg: fploadidx, asm: "FMOVD", aux: "SymOff", symEffect: "Read"}, // fp64 load indexed by i 242 243 {name: "FMOVSstore", argLength: 3, reg: fpstore, asm: "FMOVS", aux: "SymOff", faultOnNilArg0: true, symEffect: "Write"}, // fp32 store 244 {name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "FMOVD", aux: "SymOff", faultOnNilArg0: true, symEffect: "Write"}, // fp64 store 245 {name: "FMOVSstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVS", aux: "SymOff", symEffect: "Write"}, // fp32 indexed by i store 246 {name: "FMOVDstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVD", aux: "SymOff", symEffect: "Write"}, // fp64 indexed by i store 247 248 // binary ops 249 {name: "ADD", argLength: 2, reg: gp21sp, asm: "ADD", commutative: true, clobberFlags: true}, // arg0 + arg1 250 {name: "ADDW", argLength: 2, reg: gp21sp, asm: "ADDW", commutative: true, clobberFlags: true}, // arg0 + arg1 251 {name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADD", aux: "Int32", typ: "UInt64", clobberFlags: true}, // arg0 + auxint 252 {name: "ADDWconst", argLength: 1, reg: gp11sp, asm: "ADDW", aux: "Int32", clobberFlags: true}, // arg0 + auxint 253 {name: "ADDload", argLength: 3, reg: gpopload, asm: "ADD", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 + *arg1. arg2=mem 254 {name: "ADDWload", argLength: 3, reg: gpopload, asm: "ADDW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 + *arg1. arg2=mem 255 256 {name: "SUB", argLength: 2, reg: gp21, asm: "SUB", clobberFlags: true}, // arg0 - arg1 257 {name: "SUBW", argLength: 2, reg: gp21, asm: "SUBW", clobberFlags: true}, // arg0 - arg1 258 {name: "SUBconst", argLength: 1, reg: gp11, asm: "SUB", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 - auxint 259 {name: "SUBWconst", argLength: 1, reg: gp11, asm: "SUBW", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 - auxint 260 {name: "SUBload", argLength: 3, reg: gpopload, asm: "SUB", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 - *arg1. arg2=mem 261 {name: "SUBWload", argLength: 3, reg: gpopload, asm: "SUBW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 - *arg1. arg2=mem 262 263 {name: "MULLD", argLength: 2, reg: gp21, asm: "MULLD", typ: "Int64", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 * arg1 264 {name: "MULLW", argLength: 2, reg: gp21, asm: "MULLW", typ: "Int32", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 * arg1 265 {name: "MULLDconst", argLength: 1, reg: gp11, asm: "MULLD", aux: "Int32", typ: "Int64", resultInArg0: true, clobberFlags: true}, // arg0 * auxint 266 {name: "MULLWconst", argLength: 1, reg: gp11, asm: "MULLW", aux: "Int32", typ: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 * auxint 267 {name: "MULLDload", argLength: 3, reg: gpopload, asm: "MULLD", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 * *arg1. arg2=mem 268 {name: "MULLWload", argLength: 3, reg: gpopload, asm: "MULLW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 * *arg1. arg2=mem 269 270 {name: "MULHD", argLength: 2, reg: gp21tmp, asm: "MULHD", typ: "Int64", commutative: true, resultInArg0: true, clobberFlags: true}, // (arg0 * arg1) >> width 271 {name: "MULHDU", argLength: 2, reg: gp21tmp, asm: "MULHDU", typ: "Int64", commutative: true, resultInArg0: true, clobberFlags: true}, // (arg0 * arg1) >> width 272 273 {name: "DIVD", argLength: 2, reg: gp21tmp, asm: "DIVD", resultInArg0: true, clobberFlags: true}, // arg0 / arg1 274 {name: "DIVW", argLength: 2, reg: gp21tmp, asm: "DIVW", resultInArg0: true, clobberFlags: true}, // arg0 / arg1 275 {name: "DIVDU", argLength: 2, reg: gp21tmp, asm: "DIVDU", resultInArg0: true, clobberFlags: true}, // arg0 / arg1 276 {name: "DIVWU", argLength: 2, reg: gp21tmp, asm: "DIVWU", resultInArg0: true, clobberFlags: true}, // arg0 / arg1 277 278 {name: "MODD", argLength: 2, reg: gp21tmp, asm: "MODD", resultInArg0: true, clobberFlags: true}, // arg0 % arg1 279 {name: "MODW", argLength: 2, reg: gp21tmp, asm: "MODW", resultInArg0: true, clobberFlags: true}, // arg0 % arg1 280 281 {name: "MODDU", argLength: 2, reg: gp21tmp, asm: "MODDU", resultInArg0: true, clobberFlags: true}, // arg0 % arg1 282 {name: "MODWU", argLength: 2, reg: gp21tmp, asm: "MODWU", resultInArg0: true, clobberFlags: true}, // arg0 % arg1 283 284 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true, clobberFlags: true}, // arg0 & arg1 285 {name: "ANDW", argLength: 2, reg: gp21, asm: "ANDW", commutative: true, clobberFlags: true}, // arg0 & arg1 286 {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64", resultInArg0: true, clobberFlags: true}, // arg0 & auxint 287 {name: "ANDWconst", argLength: 1, reg: gp11, asm: "ANDW", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 & auxint 288 {name: "ANDload", argLength: 3, reg: gpopload, asm: "AND", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 & *arg1. arg2=mem 289 {name: "ANDWload", argLength: 3, reg: gpopload, asm: "ANDW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 & *arg1. arg2=mem 290 291 {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true, clobberFlags: true}, // arg0 | arg1 292 {name: "ORW", argLength: 2, reg: gp21, asm: "ORW", commutative: true, clobberFlags: true}, // arg0 | arg1 293 {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64", resultInArg0: true, clobberFlags: true}, // arg0 | auxint 294 {name: "ORWconst", argLength: 1, reg: gp11, asm: "ORW", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 | auxint 295 {name: "ORload", argLength: 3, reg: gpopload, asm: "OR", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 | *arg1. arg2=mem 296 {name: "ORWload", argLength: 3, reg: gpopload, asm: "ORW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 | *arg1. arg2=mem 297 298 {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, clobberFlags: true}, // arg0 ^ arg1 299 {name: "XORW", argLength: 2, reg: gp21, asm: "XORW", commutative: true, clobberFlags: true}, // arg0 ^ arg1 300 {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64", resultInArg0: true, clobberFlags: true}, // arg0 ^ auxint 301 {name: "XORWconst", argLength: 1, reg: gp11, asm: "XORW", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 ^ auxint 302 {name: "XORload", argLength: 3, reg: gpopload, asm: "XOR", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 ^ *arg1. arg2=mem 303 {name: "XORWload", argLength: 3, reg: gpopload, asm: "XORW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 ^ *arg1. arg2=mem 304 305 // Arithmetic ops with carry/borrow chain. 306 // 307 // A carry is represented by a condition code of 2 or 3 (GT or OV). 308 // A borrow is represented by a condition code of 0 or 1 (EQ or LT). 309 {name: "ADDC", argLength: 2, reg: gp21flags, asm: "ADDC", typ: "(UInt64,Flags)", commutative: true}, // (arg0 + arg1, carry out) 310 {name: "ADDCconst", argLength: 1, reg: gp11flags, asm: "ADDC", typ: "(UInt64,Flags)", aux: "Int16"}, // (arg0 + auxint, carry out) 311 {name: "ADDE", argLength: 3, reg: gp2flags1flags, asm: "ADDE", typ: "(UInt64,Flags)", commutative: true, resultInArg0: true}, // (arg0 + arg1 + arg2 (carry in), carry out) 312 {name: "SUBC", argLength: 2, reg: gp21flags, asm: "SUBC", typ: "(UInt64,Flags)"}, // (arg0 - arg1, borrow out) 313 {name: "SUBE", argLength: 3, reg: gp2flags1flags, asm: "SUBE", typ: "(UInt64,Flags)", resultInArg0: true}, // (arg0 - arg1 - arg2 (borrow in), borrow out) 314 315 // Comparisons. 316 {name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1 317 {name: "CMPW", argLength: 2, reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1 318 319 {name: "CMPU", argLength: 2, reg: gp2flags, asm: "CMPU", typ: "Flags"}, // arg0 compare to arg1 320 {name: "CMPWU", argLength: 2, reg: gp2flags, asm: "CMPWU", typ: "Flags"}, // arg0 compare to arg1 321 322 {name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", typ: "Flags", aux: "Int32"}, // arg0 compare to auxint 323 {name: "CMPWconst", argLength: 1, reg: gp1flags, asm: "CMPW", typ: "Flags", aux: "Int32"}, // arg0 compare to auxint 324 {name: "CMPUconst", argLength: 1, reg: gp1flags, asm: "CMPU", typ: "Flags", aux: "Int32"}, // arg0 compare to auxint 325 {name: "CMPWUconst", argLength: 1, reg: gp1flags, asm: "CMPWU", typ: "Flags", aux: "Int32"}, // arg0 compare to auxint 326 327 {name: "FCMPS", argLength: 2, reg: fp2flags, asm: "CEBR", typ: "Flags"}, // arg0 compare to arg1, f32 328 {name: "FCMP", argLength: 2, reg: fp2flags, asm: "FCMPU", typ: "Flags"}, // arg0 compare to arg1, f64 329 330 {name: "SLD", argLength: 2, reg: sh21, asm: "SLD"}, // arg0 << arg1, shift amount is mod 64 331 {name: "SLW", argLength: 2, reg: sh21, asm: "SLW"}, // arg0 << arg1, shift amount is mod 32 332 {name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int8"}, // arg0 << auxint, shift amount 0-63 333 {name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int8"}, // arg0 << auxint, shift amount 0-31 334 335 {name: "SRD", argLength: 2, reg: sh21, asm: "SRD"}, // unsigned arg0 >> arg1, shift amount is mod 64 336 {name: "SRW", argLength: 2, reg: sh21, asm: "SRW"}, // unsigned uint32(arg0) >> arg1, shift amount is mod 32 337 {name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int8"}, // unsigned arg0 >> auxint, shift amount 0-63 338 {name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int8"}, // unsigned uint32(arg0) >> auxint, shift amount 0-31 339 340 // Arithmetic shifts clobber flags. 341 {name: "SRAD", argLength: 2, reg: sh21, asm: "SRAD", clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 64 342 {name: "SRAW", argLength: 2, reg: sh21, asm: "SRAW", clobberFlags: true}, // signed int32(arg0) >> arg1, shift amount is mod 32 343 {name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int8", clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63 344 {name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int8", clobberFlags: true}, // signed int32(arg0) >> auxint, shift amount 0-31 345 346 {name: "RLLG", argLength: 2, reg: sh21, asm: "RLLG"}, // arg0 rotate left arg1, rotate amount 0-63 347 {name: "RLL", argLength: 2, reg: sh21, asm: "RLL"}, // arg0 rotate left arg1, rotate amount 0-31 348 {name: "RLLGconst", argLength: 1, reg: gp11, asm: "RLLG", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-63 349 {name: "RLLconst", argLength: 1, reg: gp11, asm: "RLL", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-31 350 351 // Rotate then (and|or|xor|insert) selected bits instructions. 352 // 353 // Aux is an s390x.RotateParams struct containing Start, End and rotation 354 // Amount fields. 355 // 356 // arg1 is rotated left by the rotation amount then the bits from the start 357 // bit to the end bit (inclusive) are combined with arg0 using the logical 358 // operation specified. Bit indices are specified from left to right - the 359 // MSB is 0 and the LSB is 63. 360 // 361 // Examples: 362 // | aux | 363 // | instruction | start | end | amount | arg0 | arg1 | result | 364 // +-------------+-------+-----+--------+-----------------------+-----------------------+-----------------------+ 365 // | RXSBG (XOR) | 0 | 1 | 0 | 0xffff_ffff_ffff_ffff | 0xffff_ffff_ffff_ffff | 0x3fff_ffff_ffff_ffff | 366 // | RXSBG (XOR) | 62 | 63 | 0 | 0xffff_ffff_ffff_ffff | 0xffff_ffff_ffff_ffff | 0xffff_ffff_ffff_fffc | 367 // | RXSBG (XOR) | 0 | 47 | 16 | 0xffff_ffff_ffff_ffff | 0x0000_0000_0000_ffff | 0xffff_ffff_0000_ffff | 368 // +-------------+-------+-----+--------+-----------------------+-----------------------+-----------------------+ 369 // 370 {name: "RXSBG", argLength: 2, reg: gp21, asm: "RXSBG", resultInArg0: true, aux: "ArchSpecific", clobberFlags: true}, // rotate then xor selected bits 371 372 // unary ops 373 {name: "NEG", argLength: 1, reg: gp11, asm: "NEG", clobberFlags: true}, // -arg0 374 {name: "NEGW", argLength: 1, reg: gp11, asm: "NEGW", clobberFlags: true}, // -arg0 375 376 {name: "NOT", argLength: 1, reg: gp11, resultInArg0: true, clobberFlags: true}, // ^arg0 377 {name: "NOTW", argLength: 1, reg: gp11, resultInArg0: true, clobberFlags: true}, // ^arg0 378 379 {name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0) 380 381 // Conditional register-register moves. 382 // The aux for these values is an s390x.CCMask value representing the condition code mask. 383 {name: "LOCGR", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "LOCGR", aux: "ArchSpecific"}, // load arg1 into arg0 if the condition code in arg2 matches a masked bit in aux. 384 385 {name: "MOVBreg", argLength: 1, reg: gp11sp, asm: "MOVB", typ: "Int64"}, // sign extend arg0 from int8 to int64 386 {name: "MOVBZreg", argLength: 1, reg: gp11sp, asm: "MOVBZ", typ: "UInt64"}, // zero extend arg0 from int8 to int64 387 {name: "MOVHreg", argLength: 1, reg: gp11sp, asm: "MOVH", typ: "Int64"}, // sign extend arg0 from int16 to int64 388 {name: "MOVHZreg", argLength: 1, reg: gp11sp, asm: "MOVHZ", typ: "UInt64"}, // zero extend arg0 from int16 to int64 389 {name: "MOVWreg", argLength: 1, reg: gp11sp, asm: "MOVW", typ: "Int64"}, // sign extend arg0 from int32 to int64 390 {name: "MOVWZreg", argLength: 1, reg: gp11sp, asm: "MOVWZ", typ: "UInt64"}, // zero extend arg0 from int32 to int64 391 392 {name: "MOVDconst", reg: gp01, asm: "MOVD", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint 393 394 {name: "LDGR", argLength: 1, reg: gpfp, asm: "LDGR"}, // move int64 to float64 (no conversion) 395 {name: "LGDR", argLength: 1, reg: fpgp, asm: "LGDR"}, // move float64 to int64 (no conversion) 396 {name: "CFDBRA", argLength: 1, reg: fpgp, asm: "CFDBRA"}, // convert float64 to int32 397 {name: "CGDBRA", argLength: 1, reg: fpgp, asm: "CGDBRA"}, // convert float64 to int64 398 {name: "CFEBRA", argLength: 1, reg: fpgp, asm: "CFEBRA"}, // convert float32 to int32 399 {name: "CGEBRA", argLength: 1, reg: fpgp, asm: "CGEBRA"}, // convert float32 to int64 400 {name: "CEFBRA", argLength: 1, reg: gpfp, asm: "CEFBRA"}, // convert int32 to float32 401 {name: "CDFBRA", argLength: 1, reg: gpfp, asm: "CDFBRA"}, // convert int32 to float64 402 {name: "CEGBRA", argLength: 1, reg: gpfp, asm: "CEGBRA"}, // convert int64 to float32 403 {name: "CDGBRA", argLength: 1, reg: gpfp, asm: "CDGBRA"}, // convert int64 to float64 404 {name: "LEDBR", argLength: 1, reg: fp11, asm: "LEDBR"}, // convert float64 to float32 405 {name: "LDEBR", argLength: 1, reg: fp11, asm: "LDEBR"}, // convert float32 to float64 406 407 {name: "MOVDaddr", argLength: 1, reg: addr, aux: "SymOff", rematerializeable: true, symEffect: "Read"}, // arg0 + auxint + offset encoded in aux 408 {name: "MOVDaddridx", argLength: 2, reg: addridx, aux: "SymOff", symEffect: "Read"}, // arg0 + arg1 + auxint + aux 409 410 // auxint+aux == add auxint and the offset of the symbol in aux (if any) to the effective address 411 {name: "MOVBZload", argLength: 2, reg: gpload, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load byte from arg0+auxint+aux. arg1=mem. Zero extend. 412 {name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVB", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // ditto, sign extend to int64 413 {name: "MOVHZload", argLength: 2, reg: gpload, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load 2 bytes from arg0+auxint+aux. arg1=mem. Zero extend. 414 {name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // ditto, sign extend to int64 415 {name: "MOVWZload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load 4 bytes from arg0+auxint+aux. arg1=mem. Zero extend. 416 {name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // ditto, sign extend to int64 417 {name: "MOVDload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"}, // load 8 bytes from arg0+auxint+aux. arg1=mem 418 419 {name: "MOVWBR", argLength: 1, reg: gp11, asm: "MOVWBR"}, // arg0 swap bytes 420 {name: "MOVDBR", argLength: 1, reg: gp11, asm: "MOVDBR"}, // arg0 swap bytes 421 422 {name: "MOVHBRload", argLength: 2, reg: gpload, asm: "MOVHBR", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load 2 bytes from arg0+auxint+aux. arg1=mem. Reverse bytes. 423 {name: "MOVWBRload", argLength: 2, reg: gpload, asm: "MOVWBR", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load 4 bytes from arg0+auxint+aux. arg1=mem. Reverse bytes. 424 {name: "MOVDBRload", argLength: 2, reg: gpload, asm: "MOVDBR", aux: "SymOff", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"}, // load 8 bytes from arg0+auxint+aux. arg1=mem. Reverse bytes. 425 426 {name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store byte in arg1 to arg0+auxint+aux. arg2=mem 427 {name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem 428 {name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem 429 {name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem 430 {name: "MOVHBRstore", argLength: 3, reg: gpstorebr, asm: "MOVHBR", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem. Reverse bytes. 431 {name: "MOVWBRstore", argLength: 3, reg: gpstorebr, asm: "MOVWBR", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem. Reverse bytes. 432 {name: "MOVDBRstore", argLength: 3, reg: gpstorebr, asm: "MOVDBR", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem. Reverse bytes. 433 434 {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 435 436 // indexed loads/stores 437 {name: "MOVBZloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", symEffect: "Read"}, // load a byte from arg0+arg1+auxint+aux. arg2=mem. Zero extend. 438 {name: "MOVBloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVB", aux: "SymOff", typ: "Int8", symEffect: "Read"}, // load a byte from arg0+arg1+auxint+aux. arg2=mem. Sign extend. 439 {name: "MOVHZloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", symEffect: "Read"}, // load 2 bytes from arg0+arg1+auxint+aux. arg2=mem. Zero extend. 440 {name: "MOVHloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVH", aux: "SymOff", typ: "Int16", symEffect: "Read"}, // load 2 bytes from arg0+arg1+auxint+aux. arg2=mem. Sign extend. 441 {name: "MOVWZloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", symEffect: "Read"}, // load 4 bytes from arg0+arg1+auxint+aux. arg2=mem. Zero extend. 442 {name: "MOVWloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVW", aux: "SymOff", typ: "Int32", symEffect: "Read"}, // load 4 bytes from arg0+arg1+auxint+aux. arg2=mem. Sign extend. 443 {name: "MOVDloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVD", aux: "SymOff", typ: "UInt64", symEffect: "Read"}, // load 8 bytes from arg0+arg1+auxint+aux. arg2=mem 444 {name: "MOVHBRloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVHBR", aux: "SymOff", typ: "Int16", symEffect: "Read"}, // load 2 bytes from arg0+arg1+auxint+aux. arg2=mem. Reverse bytes. 445 {name: "MOVWBRloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVWBR", aux: "SymOff", typ: "Int32", symEffect: "Read"}, // load 4 bytes from arg0+arg1+auxint+aux. arg2=mem. Reverse bytes. 446 {name: "MOVDBRloadidx", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVDBR", aux: "SymOff", typ: "Int64", symEffect: "Read"}, // load 8 bytes from arg0+arg1+auxint+aux. arg2=mem. Reverse bytes. 447 {name: "MOVBstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVB", aux: "SymOff", symEffect: "Write"}, // store byte in arg2 to arg0+arg1+auxint+aux. arg3=mem 448 {name: "MOVHstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVH", aux: "SymOff", symEffect: "Write"}, // store 2 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem 449 {name: "MOVWstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVW", aux: "SymOff", symEffect: "Write"}, // store 4 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem 450 {name: "MOVDstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVD", aux: "SymOff", symEffect: "Write"}, // store 8 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem 451 {name: "MOVHBRstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVHBR", aux: "SymOff", symEffect: "Write"}, // store 2 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem. Reverse bytes. 452 {name: "MOVWBRstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVWBR", aux: "SymOff", symEffect: "Write"}, // store 4 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem. Reverse bytes. 453 {name: "MOVDBRstoreidx", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVDBR", aux: "SymOff", symEffect: "Write"}, // store 8 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem. Reverse bytes. 454 455 // For storeconst ops, the AuxInt field encodes both 456 // the value to store and an address offset of the store. 457 // Cast AuxInt to a ValAndOff to extract Val and Off fields. 458 {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 459 {name: "MOVHstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVH", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low 2 bytes of ... 460 {name: "MOVWstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVW", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low 4 bytes of ... 461 {name: "MOVDstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVD", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of ... 462 463 {name: "CLEAR", argLength: 2, reg: regInfo{inputs: []regMask{ptr, 0}}, asm: "CLEAR", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"}, 464 465 {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 466 {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 467 {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 468 469 // (InvertFlags (CMP a b)) == (CMP b a) 470 // InvertFlags is a pseudo-op which can't appear in assembly output. 471 {name: "InvertFlags", argLength: 1}, // reverse direction of arg0 472 473 // Pseudo-ops 474 {name: "LoweredGetG", argLength: 1, reg: gp01}, // arg0=mem 475 // Scheduler ensures LoweredGetClosurePtr occurs only in entry block, 476 // and sorts it to the very beginning of the block to prevent other 477 // use of R12 (the closure pointer) 478 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R12")}}, zeroWidth: true}, 479 // arg0=ptr,arg1=mem, returns void. Faults if ptr is nil. 480 // LoweredGetCallerSP returns the SP of the caller of the current function. 481 {name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true}, 482 // LoweredGetCallerPC evaluates to the PC to which its "caller" will return. 483 // I.e., if f calls g "calls" getcallerpc, 484 // the result should be the PC within f that g will return to. 485 // See runtime/stubs.go for a more detailed discussion. 486 {name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true}, 487 {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{ptrsp}}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true}, 488 // Round ops to block fused-multiply-add extraction. 489 {name: "LoweredRound32F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true}, 490 {name: "LoweredRound64F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true}, 491 492 // LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier 493 // It saves all GP registers if necessary, 494 // but clobbers R14 (LR) because it's a call. 495 {name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R2"), buildReg("R3")}, clobbers: (callerSave &^ gpg) | buildReg("R14")}, clobberFlags: true, aux: "Sym", symEffect: "None"}, 496 497 // There are three of these functions so that they can have three different register inputs. 498 // When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the 499 // default registers to match so we don't need to copy registers around unnecessarily. 500 {name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r2, r3}}, typ: "Mem"}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in generic.go). 501 {name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r1, r2}}, typ: "Mem"}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in generic.go). 502 {name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r0, r1}}, typ: "Mem"}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in generic.go). 503 504 // Constant condition code values. The condition code can be 0, 1, 2 or 3. 505 {name: "FlagEQ"}, // CC=0 (equal) 506 {name: "FlagLT"}, // CC=1 (less than) 507 {name: "FlagGT"}, // CC=2 (greater than) 508 {name: "FlagOV"}, // CC=3 (overflow) 509 510 // Fast-BCR-serialization to ensure store-load ordering. 511 {name: "SYNC", argLength: 1, reg: sync, asm: "SYNC", typ: "Mem"}, 512 513 // Atomic loads. These are just normal loads but return <value,memory> tuples 514 // so they can be properly ordered with other loads. 515 // load from arg0+auxint+aux. arg1=mem. 516 {name: "MOVBZatomicload", argLength: 2, reg: gpload, asm: "MOVBZ", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, 517 {name: "MOVWZatomicload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, 518 {name: "MOVDatomicload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, 519 520 // Atomic stores. These are just normal stores. 521 // store arg1 to arg0+auxint+aux. arg2=mem. 522 {name: "MOVBatomicstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "Write"}, 523 {name: "MOVWatomicstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "Write"}, 524 {name: "MOVDatomicstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "Write"}, 525 526 // Atomic adds. 527 // *(arg0+auxint+aux) += arg1. arg2=mem. 528 // Returns a tuple of <old contents of *(arg0+auxint+aux), memory>. 529 {name: "LAA", argLength: 3, reg: gpstorelaa, asm: "LAA", typ: "(UInt32,Mem)", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, 530 {name: "LAAG", argLength: 3, reg: gpstorelaa, asm: "LAAG", typ: "(UInt64,Mem)", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, 531 {name: "AddTupleFirst32", argLength: 2}, // arg1=tuple <x,y>. Returns <x+arg0,y>. 532 {name: "AddTupleFirst64", argLength: 2}, // arg1=tuple <x,y>. Returns <x+arg0,y>. 533 534 // Atomic bitwise operations. 535 // Note: 'floor' operations round the pointer down to the nearest word boundary 536 // which reflects how they are used in the runtime. 537 {name: "LAOfloor", argLength: 3, reg: gpstorelab, asm: "LAO", typ: "Mem", clobberFlags: true, hasSideEffects: true}, // *(floor(arg0, 4)) |= arg1. arg2 = mem. 538 {name: "LANfloor", argLength: 3, reg: gpstorelab, asm: "LAN", typ: "Mem", clobberFlags: true, hasSideEffects: true}, // *(floor(arg0, 4)) &= arg1. arg2 = mem. 539 540 // Compare and swap. 541 // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. 542 // if *(arg0+auxint+aux) == arg1 { 543 // *(arg0+auxint+aux) = arg2 544 // return (true, memory) 545 // } else { 546 // return (false, memory) 547 // } 548 // Note that these instructions also return the old value in arg1, but we ignore it. 549 // TODO: have these return flags instead of bool. The current system generates: 550 // CS ... 551 // MOVD $0, ret 552 // BNE 2(PC) 553 // MOVD $1, ret 554 // CMPW ret, $0 555 // BNE ... 556 // instead of just 557 // CS ... 558 // BEQ ... 559 // but we can't do that because memory-using ops can't generate flags yet 560 // (flagalloc wants to move flag-generating instructions around). 561 {name: "LoweredAtomicCas32", argLength: 4, reg: cas, asm: "CS", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, 562 {name: "LoweredAtomicCas64", argLength: 4, reg: cas, asm: "CSG", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, 563 564 // Lowered atomic swaps, emulated using compare-and-swap. 565 // store arg1 to arg0+auxint+aux, arg2=mem. 566 {name: "LoweredAtomicExchange32", argLength: 3, reg: exchange, asm: "CS", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, 567 {name: "LoweredAtomicExchange64", argLength: 3, reg: exchange, asm: "CSG", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, 568 569 // find leftmost one 570 { 571 name: "FLOGR", 572 argLength: 1, 573 reg: regInfo{inputs: gponly, outputs: []regMask{buildReg("R0")}, clobbers: buildReg("R1")}, 574 asm: "FLOGR", 575 typ: "UInt64", 576 clobberFlags: true, 577 }, 578 579 // population count 580 // 581 // Counts the number of ones in each byte of arg0 582 // and places the result into the corresponding byte 583 // of the result. 584 { 585 name: "POPCNT", 586 argLength: 1, 587 reg: gp11, 588 asm: "POPCNT", 589 typ: "UInt64", 590 clobberFlags: true, 591 }, 592 593 // unsigned multiplication (64x64 → 128) 594 // 595 // Multiply the two 64-bit input operands together and place the 128-bit result into 596 // an even-odd register pair. The second register in the target pair also contains 597 // one of the input operands. Since we don't currently have a way to specify an 598 // even-odd register pair we hardcode this register pair as R2:R3. 599 { 600 name: "MLGR", 601 argLength: 2, 602 reg: regInfo{inputs: []regMask{gp, r3}, outputs: []regMask{r2, r3}}, 603 asm: "MLGR", 604 }, 605 606 // pseudo operations to sum the output of the POPCNT instruction 607 {name: "SumBytes2", argLength: 1, typ: "UInt8"}, // sum the rightmost 2 bytes in arg0 ignoring overflow 608 {name: "SumBytes4", argLength: 1, typ: "UInt8"}, // sum the rightmost 4 bytes in arg0 ignoring overflow 609 {name: "SumBytes8", argLength: 1, typ: "UInt8"}, // sum all the bytes in arg0 ignoring overflow 610 611 // store multiple 612 { 613 name: "STMG2", 614 argLength: 4, 615 reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), 0}}, 616 aux: "SymOff", 617 typ: "Mem", 618 asm: "STMG", 619 faultOnNilArg0: true, 620 symEffect: "Write", 621 }, 622 { 623 name: "STMG3", 624 argLength: 5, 625 reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), buildReg("R3"), 0}}, 626 aux: "SymOff", 627 typ: "Mem", 628 asm: "STMG", 629 faultOnNilArg0: true, 630 symEffect: "Write", 631 }, 632 { 633 name: "STMG4", 634 argLength: 6, 635 reg: regInfo{inputs: []regMask{ 636 ptrsp, 637 buildReg("R1"), 638 buildReg("R2"), 639 buildReg("R3"), 640 buildReg("R4"), 641 0, 642 }}, 643 aux: "SymOff", 644 typ: "Mem", 645 asm: "STMG", 646 faultOnNilArg0: true, 647 symEffect: "Write", 648 }, 649 { 650 name: "STM2", 651 argLength: 4, 652 reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), 0}}, 653 aux: "SymOff", 654 typ: "Mem", 655 asm: "STMY", 656 faultOnNilArg0: true, 657 symEffect: "Write", 658 }, 659 { 660 name: "STM3", 661 argLength: 5, 662 reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), buildReg("R3"), 0}}, 663 aux: "SymOff", 664 typ: "Mem", 665 asm: "STMY", 666 faultOnNilArg0: true, 667 symEffect: "Write", 668 }, 669 { 670 name: "STM4", 671 argLength: 6, 672 reg: regInfo{inputs: []regMask{ 673 ptrsp, 674 buildReg("R1"), 675 buildReg("R2"), 676 buildReg("R3"), 677 buildReg("R4"), 678 0, 679 }}, 680 aux: "SymOff", 681 typ: "Mem", 682 asm: "STMY", 683 faultOnNilArg0: true, 684 symEffect: "Write", 685 }, 686 687 // large move 688 // auxint = remaining bytes after loop (rem) 689 // arg0 = address of dst memory (in R1, changed as a side effect) 690 // arg1 = address of src memory (in R2, changed as a side effect) 691 // arg2 = pointer to last address to move in loop + 256 692 // arg3 = mem 693 // returns mem 694 // 695 // mvc: MVC $256, 0(R2), 0(R1) 696 // MOVD $256(R1), R1 697 // MOVD $256(R2), R2 698 // CMP R2, Rarg2 699 // BNE mvc 700 // MVC $rem, 0(R2), 0(R1) // if rem > 0 701 { 702 name: "LoweredMove", 703 aux: "Int64", 704 argLength: 4, 705 reg: regInfo{ 706 inputs: []regMask{buildReg("R1"), buildReg("R2"), gpsp}, 707 clobbers: buildReg("R1 R2"), 708 }, 709 clobberFlags: true, 710 typ: "Mem", 711 faultOnNilArg0: true, 712 faultOnNilArg1: true, 713 }, 714 715 // large clear 716 // auxint = remaining bytes after loop (rem) 717 // arg0 = address of dst memory (in R1, changed as a side effect) 718 // arg1 = pointer to last address to zero in loop + 256 719 // arg2 = mem 720 // returns mem 721 // 722 // clear: CLEAR $256, 0(R1) 723 // MOVD $256(R1), R1 724 // CMP R1, Rarg2 725 // BNE clear 726 // CLEAR $rem, 0(R1) // if rem > 0 727 { 728 name: "LoweredZero", 729 aux: "Int64", 730 argLength: 3, 731 reg: regInfo{ 732 inputs: []regMask{buildReg("R1"), gpsp}, 733 clobbers: buildReg("R1"), 734 }, 735 clobberFlags: true, 736 typ: "Mem", 737 faultOnNilArg0: true, 738 }, 739 } 740 741 // All blocks on s390x have their condition code mask (s390x.CCMask) as the Aux value. 742 // The condition code mask is a 4-bit mask where each bit corresponds to a condition 743 // code value. If the value of the condition code matches a bit set in the condition 744 // code mask then the first successor is executed. Otherwise the second successor is 745 // executed. 746 // 747 // | condition code value | mask bit | 748 // +----------------------+------------+ 749 // | 0 (equal) | 0b1000 (8) | 750 // | 1 (less than) | 0b0100 (4) | 751 // | 2 (greater than) | 0b0010 (2) | 752 // | 3 (unordered) | 0b0001 (1) | 753 // 754 // Note: that compare-and-branch instructions must not have bit 3 (0b0001) set. 755 var S390Xblocks = []blockData{ 756 // branch on condition 757 {name: "BRC", controls: 1}, // condition code value (flags) is Controls[0] 758 759 // compare-and-branch (register-register) 760 // - integrates comparison of Controls[0] with Controls[1] 761 // - both control values must be in general purpose registers 762 {name: "CRJ", controls: 2}, // signed 32-bit integer comparison 763 {name: "CGRJ", controls: 2}, // signed 64-bit integer comparison 764 {name: "CLRJ", controls: 2}, // unsigned 32-bit integer comparison 765 {name: "CLGRJ", controls: 2}, // unsigned 64-bit integer comparison 766 767 // compare-and-branch (register-immediate) 768 // - integrates comparison of Controls[0] with AuxInt 769 // - control value must be in a general purpose register 770 // - the AuxInt value is sign-extended for signed comparisons 771 // and zero-extended for unsigned comparisons 772 {name: "CIJ", controls: 1, auxint: "Int8"}, // signed 32-bit integer comparison 773 {name: "CGIJ", controls: 1, auxint: "Int8"}, // signed 64-bit integer comparison 774 {name: "CLIJ", controls: 1, auxint: "UInt8"}, // unsigned 32-bit integer comparison 775 {name: "CLGIJ", controls: 1, auxint: "UInt8"}, // unsigned 64-bit integer comparison 776 } 777 778 archs = append(archs, arch{ 779 name: "S390X", 780 pkg: "github.com/gagliardetto/golang-go/cmd/internal/obj/s390x", 781 genfile: "../../s390x/ssa.go", 782 ops: S390Xops, 783 blocks: S390Xblocks, 784 regnames: regNamesS390X, 785 gpregmask: gp, 786 fpregmask: fp, 787 framepointerreg: -1, // not used 788 linkreg: int8(num["R14"]), 789 imports: []string{ 790 "github.com/gagliardetto/golang-go/cmd/internal/obj/s390x", 791 }, 792 }) 793 }