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