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