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