github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/cmd/compile/internal/ssa/gen/S390X.rules (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 // Lowering arithmetic 6 (Add(64|Ptr) x y) -> (ADD x y) 7 (Add(32|16|8) x y) -> (ADDW x y) 8 (Add32F x y) -> (FADDS x y) 9 (Add64F x y) -> (FADD x y) 10 11 (Sub(64|Ptr) x y) -> (SUB x y) 12 (Sub(32|16|8) x y) -> (SUBW x y) 13 (Sub32F x y) -> (FSUBS x y) 14 (Sub64F x y) -> (FSUB x y) 15 16 (Mul64 x y) -> (MULLD x y) 17 (Mul(32|16|8) x y) -> (MULLW x y) 18 (Mul32F x y) -> (FMULS x y) 19 (Mul64F x y) -> (FMUL x y) 20 21 (Div32F x y) -> (FDIVS x y) 22 (Div64F x y) -> (FDIV x y) 23 24 (Div64 x y) -> (DIVD x y) 25 (Div64u x y) -> (DIVDU x y) 26 // DIVW/DIVWU has a 64-bit dividend and a 32-bit divisor, 27 // so a sign/zero extension of the dividend is required. 28 (Div32 x y) -> (DIVW (MOVWreg x) y) 29 (Div32u x y) -> (DIVWU (MOVWZreg x) y) 30 (Div16 x y) -> (DIVW (MOVHreg x) (MOVHreg y)) 31 (Div16u x y) -> (DIVWU (MOVHZreg x) (MOVHZreg y)) 32 (Div8 x y) -> (DIVW (MOVBreg x) (MOVBreg y)) 33 (Div8u x y) -> (DIVWU (MOVBZreg x) (MOVBZreg y)) 34 35 (Hmul(64|64u) x y) -> (MULH(D|DU) x y) 36 (Hmul32 x y) -> (SRDconst [32] (MULLD (MOVWreg x) (MOVWreg y))) 37 (Hmul32u x y) -> (SRDconst [32] (MULLD (MOVWZreg x) (MOVWZreg y))) 38 39 (Mod(64|64u) x y) -> (MOD(D|DU) x y) 40 // MODW/MODWU has a 64-bit dividend and a 32-bit divisor, 41 // so a sign/zero extension of the dividend is required. 42 (Mod32 x y) -> (MODW (MOVWreg x) y) 43 (Mod32u x y) -> (MODWU (MOVWZreg x) y) 44 (Mod16 x y) -> (MODW (MOVHreg x) (MOVHreg y)) 45 (Mod16u x y) -> (MODWU (MOVHZreg x) (MOVHZreg y)) 46 (Mod8 x y) -> (MODW (MOVBreg x) (MOVBreg y)) 47 (Mod8u x y) -> (MODWU (MOVBZreg x) (MOVBZreg y)) 48 49 // (x + y) / 2 with x>=y -> (x - y) / 2 + y 50 (Avg64u <t> x y) -> (ADD (SRDconst <t> (SUB <t> x y) [1]) y) 51 52 (And64 x y) -> (AND x y) 53 (And(32|16|8) x y) -> (ANDW x y) 54 55 (Or64 x y) -> (OR x y) 56 (Or(32|16|8) x y) -> (ORW x y) 57 58 (Xor64 x y) -> (XOR x y) 59 (Xor(32|16|8) x y) -> (XORW x y) 60 61 (Neg64 x) -> (NEG x) 62 (Neg(32|16|8) x) -> (NEGW x) 63 (Neg32F x) -> (FNEGS x) 64 (Neg64F x) -> (FNEG x) 65 66 (Com64 x) -> (NOT x) 67 (Com(32|16|8) x) -> (NOTW x) 68 (NOT x) && true -> (XOR (MOVDconst [-1]) x) 69 (NOTW x) && true -> (XORWconst [-1] x) 70 71 // Lowering boolean ops 72 (AndB x y) -> (ANDW x y) 73 (OrB x y) -> (ORW x y) 74 (Not x) -> (XORWconst [1] x) 75 76 // Lowering pointer arithmetic 77 (OffPtr [off] ptr:(SP)) -> (MOVDaddr [off] ptr) 78 (OffPtr [off] ptr) && is32Bit(off) -> (ADDconst [off] ptr) 79 (OffPtr [off] ptr) -> (ADD (MOVDconst [off]) ptr) 80 81 // TODO: optimize these cases? 82 (Ctz64NonZero x) -> (Ctz64 x) 83 (Ctz32NonZero x) -> (Ctz32 x) 84 85 // Ctz(x) = 64 - findLeftmostOne((x-1)&^x) 86 (Ctz64 <t> x) -> (SUB (MOVDconst [64]) (FLOGR (AND <t> (SUBconst <t> [1] x) (NOT <t> x)))) 87 (Ctz32 <t> x) -> (SUB (MOVDconst [64]) (FLOGR (MOVWZreg (ANDW <t> (SUBWconst <t> [1] x) (NOTW <t> x))))) 88 89 (BitLen64 x) -> (SUB (MOVDconst [64]) (FLOGR x)) 90 91 // POPCNT treats the input register as a vector of 8 bytes, producing 92 // a population count for each individual byte. For inputs larger than 93 // a single byte we therefore need to sum the individual bytes produced 94 // by the POPCNT instruction. For example, the following instruction 95 // sequence could be used to calculate the population count of a 4-byte 96 // value: 97 // 98 // MOVD $0x12345678, R1 // R1=0x12345678 <-- input 99 // POPCNT R1, R2 // R2=0x02030404 100 // SRW $16, R2, R3 // R3=0x00000203 101 // ADDW R2, R3, R4 // R4=0x02030607 102 // SRW $8, R4, R5 // R5=0x00020306 103 // ADDW R4, R5, R6 // R6=0x0205090d 104 // MOVBZ R6, R7 // R7=0x0000000d <-- result is 13 105 // 106 (PopCount8 x) -> (POPCNT (MOVBZreg x)) 107 (PopCount16 x) -> (MOVBZreg (SumBytes2 (POPCNT <typ.UInt16> x))) 108 (PopCount32 x) -> (MOVBZreg (SumBytes4 (POPCNT <typ.UInt32> x))) 109 (PopCount64 x) -> (MOVBZreg (SumBytes8 (POPCNT <typ.UInt64> x))) 110 111 // SumBytes{2,4,8} pseudo operations sum the values of the rightmost 112 // 2, 4 or 8 bytes respectively. The result is a single byte however 113 // other bytes might contain junk so a zero extension is required if 114 // the desired output type is larger than 1 byte. 115 (SumBytes2 x) -> (ADDW (SRWconst <typ.UInt8> x [8]) x) 116 (SumBytes4 x) -> (SumBytes2 (ADDW <typ.UInt16> (SRWconst <typ.UInt16> x [16]) x)) 117 (SumBytes8 x) -> (SumBytes4 (ADDW <typ.UInt32> (SRDconst <typ.UInt32> x [32]) x)) 118 119 (Bswap64 x) -> (MOVDBR x) 120 (Bswap32 x) -> (MOVWBR x) 121 122 // math package intrinsics 123 (Sqrt x) -> (FSQRT x) 124 (Floor x) -> (FIDBR [7] x) 125 (Ceil x) -> (FIDBR [6] x) 126 (Trunc x) -> (FIDBR [5] x) 127 (RoundToEven x) -> (FIDBR [4] x) 128 (Round x) -> (FIDBR [1] x) 129 130 // Atomic loads. 131 (AtomicLoad32 ptr mem) -> (MOVWZatomicload ptr mem) 132 (AtomicLoad64 ptr mem) -> (MOVDatomicload ptr mem) 133 (AtomicLoadPtr ptr mem) -> (MOVDatomicload ptr mem) 134 135 // Atomic stores. 136 (AtomicStore32 ptr val mem) -> (MOVWatomicstore ptr val mem) 137 (AtomicStore64 ptr val mem) -> (MOVDatomicstore ptr val mem) 138 (AtomicStorePtrNoWB ptr val mem) -> (MOVDatomicstore ptr val mem) 139 140 // Atomic adds. 141 (AtomicAdd32 ptr val mem) -> (AddTupleFirst32 val (LAA ptr val mem)) 142 (AtomicAdd64 ptr val mem) -> (AddTupleFirst64 val (LAAG ptr val mem)) 143 (Select0 <t> (AddTupleFirst32 val tuple)) -> (ADDW val (Select0 <t> tuple)) 144 (Select1 (AddTupleFirst32 _ tuple)) -> (Select1 tuple) 145 (Select0 <t> (AddTupleFirst64 val tuple)) -> (ADD val (Select0 <t> tuple)) 146 (Select1 (AddTupleFirst64 _ tuple)) -> (Select1 tuple) 147 148 // Atomic exchanges. 149 (AtomicExchange32 ptr val mem) -> (LoweredAtomicExchange32 ptr val mem) 150 (AtomicExchange64 ptr val mem) -> (LoweredAtomicExchange64 ptr val mem) 151 152 // Atomic compare and swap. 153 (AtomicCompareAndSwap32 ptr old new_ mem) -> (LoweredAtomicCas32 ptr old new_ mem) 154 (AtomicCompareAndSwap64 ptr old new_ mem) -> (LoweredAtomicCas64 ptr old new_ mem) 155 156 // Lowering extension 157 // Note: we always extend to 64 bits even though some ops don't need that many result bits. 158 (SignExt8to(16|32|64) x) -> (MOVBreg x) 159 (SignExt16to(32|64) x) -> (MOVHreg x) 160 (SignExt32to64 x) -> (MOVWreg x) 161 162 (ZeroExt8to(16|32|64) x) -> (MOVBZreg x) 163 (ZeroExt16to(32|64) x) -> (MOVHZreg x) 164 (ZeroExt32to64 x) -> (MOVWZreg x) 165 166 (Slicemask <t> x) -> (SRADconst (NEG <t> x) [63]) 167 168 // Lowering truncation 169 // Because we ignore high parts of registers, truncates are just copies. 170 (Trunc(16|32|64)to8 x) -> x 171 (Trunc(32|64)to16 x) -> x 172 (Trunc64to32 x) -> x 173 174 // Lowering float <-> int 175 (Cvt32to32F x) -> (CEFBRA x) 176 (Cvt32to64F x) -> (CDFBRA x) 177 (Cvt64to32F x) -> (CEGBRA x) 178 (Cvt64to64F x) -> (CDGBRA x) 179 180 (Cvt32Fto32 x) -> (CFEBRA x) 181 (Cvt32Fto64 x) -> (CGEBRA x) 182 (Cvt64Fto32 x) -> (CFDBRA x) 183 (Cvt64Fto64 x) -> (CGDBRA x) 184 185 (Cvt32Fto64F x) -> (LDEBR x) 186 (Cvt64Fto32F x) -> (LEDBR x) 187 188 (Round(32|64)F x) -> (LoweredRound(32|64)F x) 189 190 // Lowering shifts 191 192 // Lower bounded shifts first. No need to check shift value. 193 (Lsh64x(64|32|16|8) x y) && shiftIsBounded(v) -> (SLD x y) 194 (Lsh32x(64|32|16|8) x y) && shiftIsBounded(v) -> (SLW x y) 195 (Lsh16x(64|32|16|8) x y) && shiftIsBounded(v) -> (SLW x y) 196 (Lsh8x(64|32|16|8) x y) && shiftIsBounded(v) -> (SLW x y) 197 (Rsh64Ux(64|32|16|8) x y) && shiftIsBounded(v) -> (SRD x y) 198 (Rsh32Ux(64|32|16|8) x y) && shiftIsBounded(v) -> (SRW x y) 199 (Rsh16Ux(64|32|16|8) x y) && shiftIsBounded(v) -> (SRW (MOVHZreg x) y) 200 (Rsh8Ux(64|32|16|8) x y) && shiftIsBounded(v) -> (SRW (MOVBZreg x) y) 201 (Rsh64x(64|32|16|8) x y) && shiftIsBounded(v) -> (SRAD x y) 202 (Rsh32x(64|32|16|8) x y) && shiftIsBounded(v) -> (SRAW x y) 203 (Rsh16x(64|32|16|8) x y) && shiftIsBounded(v) -> (SRAW (MOVHreg x) y) 204 (Rsh8x(64|32|16|8) x y) && shiftIsBounded(v) -> (SRAW (MOVBreg x) y) 205 206 // Unsigned shifts need to return 0 if shift amount is >= width of shifted value. 207 // result = shift >= 64 ? 0 : arg << shift 208 (Lsh(64|32|16|8)x64 <t> x y) -> (MOVDGE <t> (SL(D|W|W|W) <t> x y) (MOVDconst [0]) (CMPUconst y [64])) 209 (Lsh(64|32|16|8)x32 <t> x y) -> (MOVDGE <t> (SL(D|W|W|W) <t> x y) (MOVDconst [0]) (CMPWUconst y [64])) 210 (Lsh(64|32|16|8)x16 <t> x y) -> (MOVDGE <t> (SL(D|W|W|W) <t> x y) (MOVDconst [0]) (CMPWUconst (MOVHZreg y) [64])) 211 (Lsh(64|32|16|8)x8 <t> x y) -> (MOVDGE <t> (SL(D|W|W|W) <t> x y) (MOVDconst [0]) (CMPWUconst (MOVBZreg y) [64])) 212 213 (Rsh(64|32)Ux64 <t> x y) -> (MOVDGE <t> (SR(D|W) <t> x y) (MOVDconst [0]) (CMPUconst y [64])) 214 (Rsh(64|32)Ux32 <t> x y) -> (MOVDGE <t> (SR(D|W) <t> x y) (MOVDconst [0]) (CMPWUconst y [64])) 215 (Rsh(64|32)Ux16 <t> x y) -> (MOVDGE <t> (SR(D|W) <t> x y) (MOVDconst [0]) (CMPWUconst (MOVHZreg y) [64])) 216 (Rsh(64|32)Ux8 <t> x y) -> (MOVDGE <t> (SR(D|W) <t> x y) (MOVDconst [0]) (CMPWUconst (MOVBZreg y) [64])) 217 218 (Rsh(16|8)Ux64 <t> x y) -> (MOVDGE <t> (SRW <t> (MOV(H|B)Zreg x) y) (MOVDconst [0]) (CMPUconst y [64])) 219 (Rsh(16|8)Ux32 <t> x y) -> (MOVDGE <t> (SRW <t> (MOV(H|B)Zreg x) y) (MOVDconst [0]) (CMPWUconst y [64])) 220 (Rsh(16|8)Ux16 <t> x y) -> (MOVDGE <t> (SRW <t> (MOV(H|B)Zreg x) y) (MOVDconst [0]) (CMPWUconst (MOVHZreg y) [64])) 221 (Rsh(16|8)Ux8 <t> x y) -> (MOVDGE <t> (SRW <t> (MOV(H|B)Zreg x) y) (MOVDconst [0]) (CMPWUconst (MOVBZreg y) [64])) 222 223 // Signed right shift needs to return 0/-1 if shift amount is >= width of shifted value. 224 // We implement this by setting the shift value to 63 (all ones) if the shift value is more than 63. 225 // result = arg >> (shift >= 64 ? 63 : shift) 226 (Rsh(64|32)x64 x y) -> (SRA(D|W) x (MOVDGE <y.Type> y (MOVDconst <y.Type> [63]) (CMPUconst y [64]))) 227 (Rsh(64|32)x32 x y) -> (SRA(D|W) x (MOVDGE <y.Type> y (MOVDconst <y.Type> [63]) (CMPWUconst y [64]))) 228 (Rsh(64|32)x16 x y) -> (SRA(D|W) x (MOVDGE <y.Type> y (MOVDconst <y.Type> [63]) (CMPWUconst (MOVHZreg y) [64]))) 229 (Rsh(64|32)x8 x y) -> (SRA(D|W) x (MOVDGE <y.Type> y (MOVDconst <y.Type> [63]) (CMPWUconst (MOVBZreg y) [64]))) 230 231 (Rsh(16|8)x64 x y) -> (SRAW (MOV(H|B)reg x) (MOVDGE <y.Type> y (MOVDconst <y.Type> [63]) (CMPUconst y [64]))) 232 (Rsh(16|8)x32 x y) -> (SRAW (MOV(H|B)reg x) (MOVDGE <y.Type> y (MOVDconst <y.Type> [63]) (CMPWUconst y [64]))) 233 (Rsh(16|8)x16 x y) -> (SRAW (MOV(H|B)reg x) (MOVDGE <y.Type> y (MOVDconst <y.Type> [63]) (CMPWUconst (MOVHZreg y) [64]))) 234 (Rsh(16|8)x8 x y) -> (SRAW (MOV(H|B)reg x) (MOVDGE <y.Type> y (MOVDconst <y.Type> [63]) (CMPWUconst (MOVBZreg y) [64]))) 235 236 // Lowering rotates 237 (RotateLeft32 x y) -> (RLL x y) 238 (RotateLeft64 x y) -> (RLLG x y) 239 240 // Lowering comparisons 241 (Less64 x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP x y)) 242 (Less32 x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPW x y)) 243 (Less(16|8) x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPW (MOV(H|B)reg x) (MOV(H|B)reg y))) 244 (Less64U x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU x y)) 245 (Less32U x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y)) 246 (Less(16|8)U x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPWU (MOV(H|B)Zreg x) (MOV(H|B)Zreg y))) 247 // Use SETG with reversed operands to dodge NaN case. 248 (Less64F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP y x)) 249 (Less32F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS y x)) 250 251 (Leq64 x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP x y)) 252 (Leq32 x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y)) 253 (Leq(16|8) x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPW (MOV(H|B)reg x) (MOV(H|B)reg y))) 254 (Leq64U x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU x y)) 255 (Leq32U x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y)) 256 (Leq(16|8)U x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPWU (MOV(H|B)Zreg x) (MOV(H|B)Zreg y))) 257 // Use SETGE with reversed operands to dodge NaN case. 258 (Leq64F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP y x)) 259 (Leq32F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS y x)) 260 261 (Greater64 x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP x y)) 262 (Greater32 x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPW x y)) 263 (Greater(16|8) x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPW (MOV(H|B)reg x) (MOV(H|B)reg y))) 264 (Greater64U x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU x y)) 265 (Greater32U x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y)) 266 (Greater(16|8)U x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPWU (MOV(H|B)Zreg x) (MOV(H|B)Zreg y))) 267 (Greater64F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP x y)) 268 (Greater32F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y)) 269 270 (Geq64 x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP x y)) 271 (Geq32 x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y)) 272 (Geq(16|8) x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPW (MOV(H|B)reg x) (MOV(H|B)reg y))) 273 (Geq64U x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU x y)) 274 (Geq32U x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y)) 275 (Geq(16|8)U x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPWU (MOV(H|B)Zreg x) (MOV(H|B)Zreg y))) 276 (Geq64F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP x y)) 277 (Geq32F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y)) 278 279 (Eq(64|Ptr) x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP x y)) 280 (Eq32 x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMPW x y)) 281 (Eq(16|8|B) x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMPW (MOV(H|B|B)reg x) (MOV(H|B|B)reg y))) 282 (Eq64F x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (FCMP x y)) 283 (Eq32F x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y)) 284 285 (Neq(64|Ptr) x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP x y)) 286 (Neq32 x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y)) 287 (Neq(16|8|B) x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMPW (MOV(H|B|B)reg x) (MOV(H|B|B)reg y))) 288 (Neq64F x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (FCMP x y)) 289 (Neq32F x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y)) 290 291 // Lowering loads 292 (Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVDload ptr mem) 293 (Load <t> ptr mem) && is32BitInt(t) && isSigned(t) -> (MOVWload ptr mem) 294 (Load <t> ptr mem) && is32BitInt(t) && !isSigned(t) -> (MOVWZload ptr mem) 295 (Load <t> ptr mem) && is16BitInt(t) && isSigned(t) -> (MOVHload ptr mem) 296 (Load <t> ptr mem) && is16BitInt(t) && !isSigned(t) -> (MOVHZload ptr mem) 297 (Load <t> ptr mem) && is8BitInt(t) && isSigned(t) -> (MOVBload ptr mem) 298 (Load <t> ptr mem) && (t.IsBoolean() || (is8BitInt(t) && !isSigned(t))) -> (MOVBZload ptr mem) 299 (Load <t> ptr mem) && is32BitFloat(t) -> (FMOVSload ptr mem) 300 (Load <t> ptr mem) && is64BitFloat(t) -> (FMOVDload ptr mem) 301 302 // Lowering stores 303 // These more-specific FP versions of Store pattern should come first. 304 (Store {t} ptr val mem) && t.(*types.Type).Size() == 8 && is64BitFloat(val.Type) -> (FMOVDstore ptr val mem) 305 (Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && is32BitFloat(val.Type) -> (FMOVSstore ptr val mem) 306 307 (Store {t} ptr val mem) && t.(*types.Type).Size() == 8 -> (MOVDstore ptr val mem) 308 (Store {t} ptr val mem) && t.(*types.Type).Size() == 4 -> (MOVWstore ptr val mem) 309 (Store {t} ptr val mem) && t.(*types.Type).Size() == 2 -> (MOVHstore ptr val mem) 310 (Store {t} ptr val mem) && t.(*types.Type).Size() == 1 -> (MOVBstore ptr val mem) 311 312 // Lowering moves 313 314 // Load and store for small copies. 315 (Move [0] _ _ mem) -> mem 316 (Move [1] dst src mem) -> (MOVBstore dst (MOVBZload src mem) mem) 317 (Move [2] dst src mem) -> (MOVHstore dst (MOVHZload src mem) mem) 318 (Move [4] dst src mem) -> (MOVWstore dst (MOVWZload src mem) mem) 319 (Move [8] dst src mem) -> (MOVDstore dst (MOVDload src mem) mem) 320 (Move [16] dst src mem) -> 321 (MOVDstore [8] dst (MOVDload [8] src mem) 322 (MOVDstore dst (MOVDload src mem) mem)) 323 (Move [24] dst src mem) -> 324 (MOVDstore [16] dst (MOVDload [16] src mem) 325 (MOVDstore [8] dst (MOVDload [8] src mem) 326 (MOVDstore dst (MOVDload src mem) mem))) 327 (Move [3] dst src mem) -> 328 (MOVBstore [2] dst (MOVBZload [2] src mem) 329 (MOVHstore dst (MOVHZload src mem) mem)) 330 (Move [5] dst src mem) -> 331 (MOVBstore [4] dst (MOVBZload [4] src mem) 332 (MOVWstore dst (MOVWZload src mem) mem)) 333 (Move [6] dst src mem) -> 334 (MOVHstore [4] dst (MOVHZload [4] src mem) 335 (MOVWstore dst (MOVWZload src mem) mem)) 336 (Move [7] dst src mem) -> 337 (MOVBstore [6] dst (MOVBZload [6] src mem) 338 (MOVHstore [4] dst (MOVHZload [4] src mem) 339 (MOVWstore dst (MOVWZload src mem) mem))) 340 341 // MVC for other moves. Use up to 4 instructions (sizes up to 1024 bytes). 342 (Move [s] dst src mem) && s > 0 && s <= 256 -> 343 (MVC [makeValAndOff(s, 0)] dst src mem) 344 (Move [s] dst src mem) && s > 256 && s <= 512 -> 345 (MVC [makeValAndOff(s-256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem)) 346 (Move [s] dst src mem) && s > 512 && s <= 768 -> 347 (MVC [makeValAndOff(s-512, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem))) 348 (Move [s] dst src mem) && s > 768 && s <= 1024 -> 349 (MVC [makeValAndOff(s-768, 768)] dst src (MVC [makeValAndOff(256, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem)))) 350 351 // Move more than 1024 bytes using a loop. 352 (Move [s] dst src mem) && s > 1024 -> 353 (LoweredMove [s%256] dst src (ADD <src.Type> src (MOVDconst [(s/256)*256])) mem) 354 355 // Lowering Zero instructions 356 (Zero [0] _ mem) -> mem 357 (Zero [1] destptr mem) -> (MOVBstoreconst [0] destptr mem) 358 (Zero [2] destptr mem) -> (MOVHstoreconst [0] destptr mem) 359 (Zero [4] destptr mem) -> (MOVWstoreconst [0] destptr mem) 360 (Zero [8] destptr mem) -> (MOVDstoreconst [0] destptr mem) 361 (Zero [3] destptr mem) -> 362 (MOVBstoreconst [makeValAndOff(0,2)] destptr 363 (MOVHstoreconst [0] destptr mem)) 364 (Zero [5] destptr mem) -> 365 (MOVBstoreconst [makeValAndOff(0,4)] destptr 366 (MOVWstoreconst [0] destptr mem)) 367 (Zero [6] destptr mem) -> 368 (MOVHstoreconst [makeValAndOff(0,4)] destptr 369 (MOVWstoreconst [0] destptr mem)) 370 (Zero [7] destptr mem) -> 371 (MOVWstoreconst [makeValAndOff(0,3)] destptr 372 (MOVWstoreconst [0] destptr mem)) 373 374 (Zero [s] destptr mem) && s > 0 && s <= 1024 -> 375 (CLEAR [makeValAndOff(s, 0)] destptr mem) 376 377 // Move more than 1024 bytes using a loop. 378 (Zero [s] destptr mem) && s > 1024 -> 379 (LoweredZero [s%256] destptr (ADDconst <destptr.Type> destptr [(s/256)*256]) mem) 380 381 // Lowering constants 382 (Const(64|32|16|8) [val]) -> (MOVDconst [val]) 383 (Const(32|64)F [val]) -> (FMOV(S|D)const [val]) 384 (ConstNil) -> (MOVDconst [0]) 385 (ConstBool [b]) -> (MOVDconst [b]) 386 387 // Lowering calls 388 (StaticCall [argwid] {target} mem) -> (CALLstatic [argwid] {target} mem) 389 (ClosureCall [argwid] entry closure mem) -> (CALLclosure [argwid] entry closure mem) 390 (InterCall [argwid] entry mem) -> (CALLinter [argwid] entry mem) 391 392 // Miscellaneous 393 (IsNonNil p) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMPconst p [0])) 394 (IsInBounds idx len) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU idx len)) 395 (IsSliceInBounds idx len) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU idx len)) 396 (NilCheck ptr mem) -> (LoweredNilCheck ptr mem) 397 (GetG mem) -> (LoweredGetG mem) 398 (GetClosurePtr) -> (LoweredGetClosurePtr) 399 (GetCallerSP) -> (LoweredGetCallerSP) 400 (GetCallerPC) -> (LoweredGetCallerPC) 401 (Addr {sym} base) -> (MOVDaddr {sym} base) 402 (LocalAddr {sym} base _) -> (MOVDaddr {sym} base) 403 (ITab (Load ptr mem)) -> (MOVDload ptr mem) 404 405 // block rewrites 406 (If (MOVDLT (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (LT cmp yes no) 407 (If (MOVDLE (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (LE cmp yes no) 408 (If (MOVDGT (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (GT cmp yes no) 409 (If (MOVDGE (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (GE cmp yes no) 410 (If (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (EQ cmp yes no) 411 (If (MOVDNE (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (NE cmp yes no) 412 413 // Special case for floating point - LF/LEF not generated. 414 (If (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (GTF cmp yes no) 415 (If (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (GEF cmp yes no) 416 417 (If cond yes no) -> (NE (CMPWconst [0] (MOVBZreg <typ.Bool> cond)) yes no) 418 419 // Write barrier. 420 (WB {fn} destptr srcptr mem) -> (LoweredWB {fn} destptr srcptr mem) 421 422 // *************************** 423 // Above: lowering rules 424 // Below: optimizations 425 // *************************** 426 // TODO: Should the optimizations be a separate pass? 427 428 // Fold unnecessary type conversions. 429 (MOVDreg <t> x) && t.Compare(x.Type) == types.CMPeq -> x 430 (MOVDnop <t> x) && t.Compare(x.Type) == types.CMPeq -> x 431 432 // Propagate constants through type conversions. 433 (MOVDreg (MOVDconst [c])) -> (MOVDconst [c]) 434 (MOVDnop (MOVDconst [c])) -> (MOVDconst [c]) 435 436 // If a register move has only 1 use, just use the same register without emitting instruction. 437 // MOVDnop doesn't emit instruction, only for ensuring the type. 438 (MOVDreg x) && x.Uses == 1 -> (MOVDnop x) 439 440 // Fold type changes into loads. 441 (MOVDreg <t> x:(MOVBZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZload <t> [off] {sym} ptr mem) 442 (MOVDreg <t> x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload <t> [off] {sym} ptr mem) 443 (MOVDreg <t> x:(MOVHZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZload <t> [off] {sym} ptr mem) 444 (MOVDreg <t> x:(MOVHload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHload <t> [off] {sym} ptr mem) 445 (MOVDreg <t> x:(MOVWZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZload <t> [off] {sym} ptr mem) 446 (MOVDreg <t> x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <t> [off] {sym} ptr mem) 447 (MOVDreg <t> x:(MOVDload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVDload <t> [off] {sym} ptr mem) 448 449 (MOVDnop <t> x:(MOVBZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZload <t> [off] {sym} ptr mem) 450 (MOVDnop <t> x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload <t> [off] {sym} ptr mem) 451 (MOVDnop <t> x:(MOVHZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZload <t> [off] {sym} ptr mem) 452 (MOVDnop <t> x:(MOVHload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHload <t> [off] {sym} ptr mem) 453 (MOVDnop <t> x:(MOVWZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZload <t> [off] {sym} ptr mem) 454 (MOVDnop <t> x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <t> [off] {sym} ptr mem) 455 (MOVDnop <t> x:(MOVDload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVDload <t> [off] {sym} ptr mem) 456 457 (MOVDreg <t> x:(MOVBZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZloadidx <t> [off] {sym} ptr idx mem) 458 (MOVDreg <t> x:(MOVBloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBloadidx <t> [off] {sym} ptr idx mem) 459 (MOVDreg <t> x:(MOVHZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZloadidx <t> [off] {sym} ptr idx mem) 460 (MOVDreg <t> x:(MOVHloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHloadidx <t> [off] {sym} ptr idx mem) 461 (MOVDreg <t> x:(MOVWZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZloadidx <t> [off] {sym} ptr idx mem) 462 (MOVDreg <t> x:(MOVWloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx <t> [off] {sym} ptr idx mem) 463 (MOVDreg <t> x:(MOVDloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVDloadidx <t> [off] {sym} ptr idx mem) 464 465 (MOVDnop <t> x:(MOVBZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZloadidx <t> [off] {sym} ptr idx mem) 466 (MOVDnop <t> x:(MOVBloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBloadidx <t> [off] {sym} ptr idx mem) 467 (MOVDnop <t> x:(MOVHZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZloadidx <t> [off] {sym} ptr idx mem) 468 (MOVDnop <t> x:(MOVHloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHloadidx <t> [off] {sym} ptr idx mem) 469 (MOVDnop <t> x:(MOVWZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZloadidx <t> [off] {sym} ptr idx mem) 470 (MOVDnop <t> x:(MOVWloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx <t> [off] {sym} ptr idx mem) 471 (MOVDnop <t> x:(MOVDloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVDloadidx <t> [off] {sym} ptr idx mem) 472 473 // Fold sign extensions into conditional moves of constants. 474 // Designed to remove the MOVBZreg inserted by the If lowering. 475 (MOVBZreg x:(MOVDLT (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x) 476 (MOVBZreg x:(MOVDLE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x) 477 (MOVBZreg x:(MOVDGT (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x) 478 (MOVBZreg x:(MOVDGE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x) 479 (MOVBZreg x:(MOVDEQ (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x) 480 (MOVBZreg x:(MOVDNE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x) 481 (MOVBZreg x:(MOVDGTnoinv (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x) 482 (MOVBZreg x:(MOVDGEnoinv (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x) 483 484 // Fold boolean tests into blocks. 485 (NE (CMPWconst [0] (MOVDLT (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (LT cmp yes no) 486 (NE (CMPWconst [0] (MOVDLE (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (LE cmp yes no) 487 (NE (CMPWconst [0] (MOVDGT (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (GT cmp yes no) 488 (NE (CMPWconst [0] (MOVDGE (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (GE cmp yes no) 489 (NE (CMPWconst [0] (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (EQ cmp yes no) 490 (NE (CMPWconst [0] (MOVDNE (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (NE cmp yes no) 491 (NE (CMPWconst [0] (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (GTF cmp yes no) 492 (NE (CMPWconst [0] (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (GEF cmp yes no) 493 494 // Fold constants into instructions. 495 (ADD x (MOVDconst [c])) && is32Bit(c) -> (ADDconst [c] x) 496 (ADDW x (MOVDconst [c])) -> (ADDWconst [int64(int32(c))] x) 497 498 (SUB x (MOVDconst [c])) && is32Bit(c) -> (SUBconst x [c]) 499 (SUB (MOVDconst [c]) x) && is32Bit(c) -> (NEG (SUBconst <v.Type> x [c])) 500 (SUBW x (MOVDconst [c])) -> (SUBWconst x [int64(int32(c))]) 501 (SUBW (MOVDconst [c]) x) -> (NEGW (SUBWconst <v.Type> x [int64(int32(c))])) 502 503 (MULLD x (MOVDconst [c])) && is32Bit(c) -> (MULLDconst [c] x) 504 (MULLW x (MOVDconst [c])) -> (MULLWconst [int64(int32(c))] x) 505 506 // NILF instructions leave the high 32 bits unchanged which is 507 // equivalent to the leftmost 32 bits being set. 508 // TODO(mundaym): modify the assembler to accept 64-bit values 509 // and use isU32Bit(^c). 510 (AND x (MOVDconst [c])) && is32Bit(c) && c < 0 -> (ANDconst [c] x) 511 (AND x (MOVDconst [c])) && is32Bit(c) && c >= 0 -> (MOVWZreg (ANDWconst <typ.UInt32> [int64(int32(c))] x)) 512 (ANDW x (MOVDconst [c])) -> (ANDWconst [int64(int32(c))] x) 513 514 (ANDWconst [c] (ANDWconst [d] x)) -> (ANDWconst [c & d] x) 515 (ANDconst [c] (ANDconst [d] x)) -> (ANDconst [c & d] x) 516 517 (OR x (MOVDconst [c])) && isU32Bit(c) -> (ORconst [c] x) 518 (ORW x (MOVDconst [c])) -> (ORWconst [int64(int32(c))] x) 519 520 (XOR x (MOVDconst [c])) && isU32Bit(c) -> (XORconst [c] x) 521 (XORW x (MOVDconst [c])) -> (XORWconst [int64(int32(c))] x) 522 523 // Constant shifts. 524 (S(LD|RD|RAD|LW|RW|RAW) x (MOVDconst [c])) 525 -> (S(LD|RD|RAD|LW|RW|RAW)const x [c&63]) 526 527 // Shifts only use the rightmost 6 bits of the shift value. 528 (S(LD|RD|RAD|LW|RW|RAW) x (AND (MOVDconst [c]) y)) 529 -> (S(LD|RD|RAD|LW|RW|RAW) x (ANDWconst <typ.UInt32> [c&63] y)) 530 (S(LD|RD|RAD|LW|RW|RAW) x (ANDWconst [c] y)) && c&63 == 63 531 -> (S(LD|RD|RAD|LW|RW|RAW) x y) 532 (SLD x (MOV(D|W|H|B|WZ|HZ|BZ)reg y)) -> (SLD x y) 533 (SRD x (MOV(D|W|H|B|WZ|HZ|BZ)reg y)) -> (SRD x y) 534 (SRAD x (MOV(D|W|H|B|WZ|HZ|BZ)reg y)) -> (SRAD x y) 535 (SLW x (MOV(D|W|H|B|WZ|HZ|BZ)reg y)) -> (SLW x y) 536 (SRW x (MOV(D|W|H|B|WZ|HZ|BZ)reg y)) -> (SRW x y) 537 (SRAW x (MOV(D|W|H|B|WZ|HZ|BZ)reg y)) -> (SRAW x y) 538 539 // Constant rotate generation 540 (RLL x (MOVDconst [c])) -> (RLLconst x [c&31]) 541 (RLLG x (MOVDconst [c])) -> (RLLGconst x [c&63]) 542 543 (ADD (SLDconst x [c]) (SRDconst x [d])) && d == 64-c -> (RLLGconst [c] x) 544 ( OR (SLDconst x [c]) (SRDconst x [d])) && d == 64-c -> (RLLGconst [c] x) 545 (XOR (SLDconst x [c]) (SRDconst x [d])) && d == 64-c -> (RLLGconst [c] x) 546 547 (ADDW (SLWconst x [c]) (SRWconst x [d])) && d == 32-c -> (RLLconst [c] x) 548 ( ORW (SLWconst x [c]) (SRWconst x [d])) && d == 32-c -> (RLLconst [c] x) 549 (XORW (SLWconst x [c]) (SRWconst x [d])) && d == 32-c -> (RLLconst [c] x) 550 551 (CMP x (MOVDconst [c])) && is32Bit(c) -> (CMPconst x [c]) 552 (CMP (MOVDconst [c]) x) && is32Bit(c) -> (InvertFlags (CMPconst x [c])) 553 (CMPW x (MOVDconst [c])) -> (CMPWconst x [int64(int32(c))]) 554 (CMPW (MOVDconst [c]) x) -> (InvertFlags (CMPWconst x [int64(int32(c))])) 555 (CMPU x (MOVDconst [c])) && isU32Bit(c) -> (CMPUconst x [int64(int32(c))]) 556 (CMPU (MOVDconst [c]) x) && isU32Bit(c) -> (InvertFlags (CMPUconst x [int64(int32(c))])) 557 (CMPWU x (MOVDconst [c])) -> (CMPWUconst x [int64(int32(c))]) 558 (CMPWU (MOVDconst [c]) x) -> (InvertFlags (CMPWUconst x [int64(int32(c))])) 559 560 // Using MOV{W,H,B}Zreg instead of AND is cheaper. 561 (AND x (MOVDconst [0xFF])) -> (MOVBZreg x) 562 (AND x (MOVDconst [0xFFFF])) -> (MOVHZreg x) 563 (AND x (MOVDconst [0xFFFFFFFF])) -> (MOVWZreg x) 564 (ANDWconst [0xFF] x) -> (MOVBZreg x) 565 (ANDWconst [0xFFFF] x) -> (MOVHZreg x) 566 567 // strength reduction 568 (MULLDconst [-1] x) -> (NEG x) 569 (MULLDconst [0] _) -> (MOVDconst [0]) 570 (MULLDconst [1] x) -> x 571 (MULLDconst [c] x) && isPowerOfTwo(c) -> (SLDconst [log2(c)] x) 572 (MULLDconst [c] x) && isPowerOfTwo(c+1) && c >= 15 -> (SUB (SLDconst <v.Type> [log2(c+1)] x) x) 573 (MULLDconst [c] x) && isPowerOfTwo(c-1) && c >= 17 -> (ADD (SLDconst <v.Type> [log2(c-1)] x) x) 574 575 (MULLWconst [-1] x) -> (NEGW x) 576 (MULLWconst [0] _) -> (MOVDconst [0]) 577 (MULLWconst [1] x) -> x 578 (MULLWconst [c] x) && isPowerOfTwo(c) -> (SLWconst [log2(c)] x) 579 (MULLWconst [c] x) && isPowerOfTwo(c+1) && c >= 15 -> (SUBW (SLWconst <v.Type> [log2(c+1)] x) x) 580 (MULLWconst [c] x) && isPowerOfTwo(c-1) && c >= 17 -> (ADDW (SLWconst <v.Type> [log2(c-1)] x) x) 581 582 // Fold ADD into MOVDaddr. Odd offsets from SB shouldn't be folded (LARL can't handle them). 583 (ADDconst [c] (MOVDaddr [d] {s} x:(SB))) && ((c+d)&1 == 0) && is32Bit(c+d) -> (MOVDaddr [c+d] {s} x) 584 (ADDconst [c] (MOVDaddr [d] {s} x)) && x.Op != OpSB && is20Bit(c+d) -> (MOVDaddr [c+d] {s} x) 585 (ADD idx (MOVDaddr [c] {s} ptr)) && ptr.Op != OpSB && idx.Op != OpSB -> (MOVDaddridx [c] {s} ptr idx) 586 587 // fold ADDconst into MOVDaddrx 588 (ADDconst [c] (MOVDaddridx [d] {s} x y)) && is20Bit(c+d) -> (MOVDaddridx [c+d] {s} x y) 589 (MOVDaddridx [c] {s} (ADDconst [d] x) y) && is20Bit(c+d) && x.Op != OpSB -> (MOVDaddridx [c+d] {s} x y) 590 (MOVDaddridx [c] {s} x (ADDconst [d] y)) && is20Bit(c+d) && y.Op != OpSB -> (MOVDaddridx [c+d] {s} x y) 591 592 // reverse ordering of compare instruction 593 (MOVDLT x y (InvertFlags cmp)) -> (MOVDGT x y cmp) 594 (MOVDGT x y (InvertFlags cmp)) -> (MOVDLT x y cmp) 595 (MOVDLE x y (InvertFlags cmp)) -> (MOVDGE x y cmp) 596 (MOVDGE x y (InvertFlags cmp)) -> (MOVDLE x y cmp) 597 (MOVDEQ x y (InvertFlags cmp)) -> (MOVDEQ x y cmp) 598 (MOVDNE x y (InvertFlags cmp)) -> (MOVDNE x y cmp) 599 600 // don't extend after proper load 601 (MOVBreg x:(MOVBload _ _)) -> (MOVDreg x) 602 (MOVBZreg x:(MOVBZload _ _)) -> (MOVDreg x) 603 (MOVHreg x:(MOVBload _ _)) -> (MOVDreg x) 604 (MOVHreg x:(MOVBZload _ _)) -> (MOVDreg x) 605 (MOVHreg x:(MOVHload _ _)) -> (MOVDreg x) 606 (MOVHZreg x:(MOVBZload _ _)) -> (MOVDreg x) 607 (MOVHZreg x:(MOVHZload _ _)) -> (MOVDreg x) 608 (MOVWreg x:(MOVBload _ _)) -> (MOVDreg x) 609 (MOVWreg x:(MOVBZload _ _)) -> (MOVDreg x) 610 (MOVWreg x:(MOVHload _ _)) -> (MOVDreg x) 611 (MOVWreg x:(MOVHZload _ _)) -> (MOVDreg x) 612 (MOVWreg x:(MOVWload _ _)) -> (MOVDreg x) 613 (MOVWZreg x:(MOVBZload _ _)) -> (MOVDreg x) 614 (MOVWZreg x:(MOVHZload _ _)) -> (MOVDreg x) 615 (MOVWZreg x:(MOVWZload _ _)) -> (MOVDreg x) 616 617 // don't extend if argument is already extended 618 (MOVBreg x:(Arg <t>)) && is8BitInt(t) && isSigned(t) -> (MOVDreg x) 619 (MOVBZreg x:(Arg <t>)) && is8BitInt(t) && !isSigned(t) -> (MOVDreg x) 620 (MOVHreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && isSigned(t) -> (MOVDreg x) 621 (MOVHZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && !isSigned(t) -> (MOVDreg x) 622 (MOVWreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t) -> (MOVDreg x) 623 (MOVWZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t) -> (MOVDreg x) 624 625 // fold double extensions 626 (MOVBreg x:(MOVBreg _)) -> (MOVDreg x) 627 (MOVBZreg x:(MOVBZreg _)) -> (MOVDreg x) 628 (MOVHreg x:(MOVBreg _)) -> (MOVDreg x) 629 (MOVHreg x:(MOVBZreg _)) -> (MOVDreg x) 630 (MOVHreg x:(MOVHreg _)) -> (MOVDreg x) 631 (MOVHZreg x:(MOVBZreg _)) -> (MOVDreg x) 632 (MOVHZreg x:(MOVHZreg _)) -> (MOVDreg x) 633 (MOVWreg x:(MOVBreg _)) -> (MOVDreg x) 634 (MOVWreg x:(MOVBZreg _)) -> (MOVDreg x) 635 (MOVWreg x:(MOVHreg _)) -> (MOVDreg x) 636 (MOVWreg x:(MOVHZreg _)) -> (MOVDreg x) 637 (MOVWreg x:(MOVWreg _)) -> (MOVDreg x) 638 (MOVWZreg x:(MOVBZreg _)) -> (MOVDreg x) 639 (MOVWZreg x:(MOVHZreg _)) -> (MOVDreg x) 640 (MOVWZreg x:(MOVWZreg _)) -> (MOVDreg x) 641 642 (MOVBreg (MOVBZreg x)) -> (MOVBreg x) 643 (MOVBZreg (MOVBreg x)) -> (MOVBZreg x) 644 (MOVHreg (MOVHZreg x)) -> (MOVHreg x) 645 (MOVHZreg (MOVHreg x)) -> (MOVHZreg x) 646 (MOVWreg (MOVWZreg x)) -> (MOVWreg x) 647 (MOVWZreg (MOVWreg x)) -> (MOVWZreg x) 648 649 // fold extensions into constants 650 (MOVBreg (MOVDconst [c])) -> (MOVDconst [int64(int8(c))]) 651 (MOVBZreg (MOVDconst [c])) -> (MOVDconst [int64(uint8(c))]) 652 (MOVHreg (MOVDconst [c])) -> (MOVDconst [int64(int16(c))]) 653 (MOVHZreg (MOVDconst [c])) -> (MOVDconst [int64(uint16(c))]) 654 (MOVWreg (MOVDconst [c])) -> (MOVDconst [int64(int32(c))]) 655 (MOVWZreg (MOVDconst [c])) -> (MOVDconst [int64(uint32(c))]) 656 657 // sign extended loads 658 // Note: The combined instruction must end up in the same block 659 // as the original load. If not, we end up making a value with 660 // memory type live in two different blocks, which can lead to 661 // multiple memory values alive simultaneously. 662 // Make sure we don't combine these ops if the load has another use. 663 // This prevents a single load from being split into multiple loads 664 // which then might return different values. See test/atomicload.go. 665 (MOVBreg x:(MOVBZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload <v.Type> [off] {sym} ptr mem) 666 (MOVBreg x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload <v.Type> [off] {sym} ptr mem) 667 (MOVBZreg x:(MOVBZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZload <v.Type> [off] {sym} ptr mem) 668 (MOVBZreg x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZload <v.Type> [off] {sym} ptr mem) 669 (MOVHreg x:(MOVHZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHload <v.Type> [off] {sym} ptr mem) 670 (MOVHreg x:(MOVHload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHload <v.Type> [off] {sym} ptr mem) 671 (MOVHZreg x:(MOVHZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZload <v.Type> [off] {sym} ptr mem) 672 (MOVHZreg x:(MOVHload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZload <v.Type> [off] {sym} ptr mem) 673 (MOVWreg x:(MOVWZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <v.Type> [off] {sym} ptr mem) 674 (MOVWreg x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <v.Type> [off] {sym} ptr mem) 675 (MOVWZreg x:(MOVWZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZload <v.Type> [off] {sym} ptr mem) 676 (MOVWZreg x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZload <v.Type> [off] {sym} ptr mem) 677 678 (MOVBreg x:(MOVBZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBloadidx <v.Type> [off] {sym} ptr idx mem) 679 (MOVBreg x:(MOVBloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBloadidx <v.Type> [off] {sym} ptr idx mem) 680 (MOVBZreg x:(MOVBZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZloadidx <v.Type> [off] {sym} ptr idx mem) 681 (MOVBZreg x:(MOVBloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZloadidx <v.Type> [off] {sym} ptr idx mem) 682 (MOVHreg x:(MOVHZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHloadidx <v.Type> [off] {sym} ptr idx mem) 683 (MOVHreg x:(MOVHloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHloadidx <v.Type> [off] {sym} ptr idx mem) 684 (MOVHZreg x:(MOVHZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZloadidx <v.Type> [off] {sym} ptr idx mem) 685 (MOVHZreg x:(MOVHloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZloadidx <v.Type> [off] {sym} ptr idx mem) 686 (MOVWreg x:(MOVWZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx <v.Type> [off] {sym} ptr idx mem) 687 (MOVWreg x:(MOVWloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx <v.Type> [off] {sym} ptr idx mem) 688 (MOVWZreg x:(MOVWZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZloadidx <v.Type> [off] {sym} ptr idx mem) 689 (MOVWZreg x:(MOVWloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZloadidx <v.Type> [off] {sym} ptr idx mem) 690 691 // replace load from same location as preceding store with copy 692 (MOVDload [off] {sym} ptr1 (MOVDstore [off] {sym} ptr2 x _)) && isSamePtr(ptr1, ptr2) -> (MOVDreg x) 693 (MOVWload [off] {sym} ptr1 (MOVWstore [off] {sym} ptr2 x _)) && isSamePtr(ptr1, ptr2) -> (MOVWreg x) 694 (MOVHload [off] {sym} ptr1 (MOVHstore [off] {sym} ptr2 x _)) && isSamePtr(ptr1, ptr2) -> (MOVHreg x) 695 (MOVBload [off] {sym} ptr1 (MOVBstore [off] {sym} ptr2 x _)) && isSamePtr(ptr1, ptr2) -> (MOVBreg x) 696 (MOVWZload [off] {sym} ptr1 (MOVWstore [off] {sym} ptr2 x _)) && isSamePtr(ptr1, ptr2) -> (MOVWZreg x) 697 (MOVHZload [off] {sym} ptr1 (MOVHstore [off] {sym} ptr2 x _)) && isSamePtr(ptr1, ptr2) -> (MOVHZreg x) 698 (MOVBZload [off] {sym} ptr1 (MOVBstore [off] {sym} ptr2 x _)) && isSamePtr(ptr1, ptr2) -> (MOVBZreg x) 699 (MOVDload [off] {sym} ptr1 (FMOVDstore [off] {sym} ptr2 x _)) && isSamePtr(ptr1, ptr2) -> (LGDR x) 700 (FMOVDload [off] {sym} ptr1 (MOVDstore [off] {sym} ptr2 x _)) && isSamePtr(ptr1, ptr2) -> (LDGR x) 701 (FMOVDload [off] {sym} ptr1 (FMOVDstore [off] {sym} ptr2 x _)) && isSamePtr(ptr1, ptr2) -> x 702 (FMOVSload [off] {sym} ptr1 (FMOVSstore [off] {sym} ptr2 x _)) && isSamePtr(ptr1, ptr2) -> x 703 704 // prefer FPR <-> GPR moves over combined load ops 705 (MULLDload <t> [off] {sym} x ptr1 (FMOVDstore [off] {sym} ptr2 y _)) && isSamePtr(ptr1, ptr2) -> (MULLD x (LGDR <t> y)) 706 (ADDload <t> [off] {sym} x ptr1 (FMOVDstore [off] {sym} ptr2 y _)) && isSamePtr(ptr1, ptr2) -> (ADD x (LGDR <t> y)) 707 (SUBload <t> [off] {sym} x ptr1 (FMOVDstore [off] {sym} ptr2 y _)) && isSamePtr(ptr1, ptr2) -> (SUB x (LGDR <t> y)) 708 (ORload <t> [off] {sym} x ptr1 (FMOVDstore [off] {sym} ptr2 y _)) && isSamePtr(ptr1, ptr2) -> (OR x (LGDR <t> y)) 709 (ANDload <t> [off] {sym} x ptr1 (FMOVDstore [off] {sym} ptr2 y _)) && isSamePtr(ptr1, ptr2) -> (AND x (LGDR <t> y)) 710 (XORload <t> [off] {sym} x ptr1 (FMOVDstore [off] {sym} ptr2 y _)) && isSamePtr(ptr1, ptr2) -> (XOR x (LGDR <t> y)) 711 712 // detect attempts to set/clear the sign bit 713 // may need to be reworked when NIHH/OIHH are added 714 (SRDconst [1] (SLDconst [1] (LGDR <t> x))) -> (LGDR <t> (LPDFR <x.Type> x)) 715 (LDGR <t> (SRDconst [1] (SLDconst [1] x))) -> (LPDFR (LDGR <t> x)) 716 (OR (MOVDconst [-1<<63]) (LGDR <t> x)) -> (LGDR <t> (LNDFR <x.Type> x)) 717 (LDGR <t> (OR (MOVDconst [-1<<63]) x)) -> (LNDFR (LDGR <t> x)) 718 719 // detect attempts to set the sign bit with load 720 (LDGR <t> x:(ORload <t1> [off] {sym} (MOVDconst [-1<<63]) ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (LNDFR <t> (LDGR <t> (MOVDload <t1> [off] {sym} ptr mem))) 721 722 // detect copysign 723 (OR (SLDconst [63] (SRDconst [63] (LGDR x))) (LGDR (LPDFR <t> y))) -> (LGDR (CPSDR <t> y x)) 724 (OR (SLDconst [63] (SRDconst [63] (LGDR x))) (MOVDconst [c])) && c & -1<<63 == 0 -> (LGDR (CPSDR <x.Type> (FMOVDconst <x.Type> [c]) x)) 725 (CPSDR y (FMOVDconst [c])) && c & -1<<63 == 0 -> (LPDFR y) 726 (CPSDR y (FMOVDconst [c])) && c & -1<<63 != 0 -> (LNDFR y) 727 728 // absorb negations into set/clear sign bit 729 (FNEG (LPDFR x)) -> (LNDFR x) 730 (FNEG (LNDFR x)) -> (LPDFR x) 731 (FNEGS (LPDFR x)) -> (LNDFR x) 732 (FNEGS (LNDFR x)) -> (LPDFR x) 733 734 // no need to convert float32 to float64 to set/clear sign bit 735 (LEDBR (LPDFR (LDEBR x))) -> (LPDFR x) 736 (LEDBR (LNDFR (LDEBR x))) -> (LNDFR x) 737 738 // remove unnecessary FPR <-> GPR moves 739 (LDGR (LGDR x)) -> x 740 (LGDR (LDGR x)) -> (MOVDreg x) 741 742 // Don't extend before storing 743 (MOVWstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVWstore [off] {sym} ptr x mem) 744 (MOVHstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVHstore [off] {sym} ptr x mem) 745 (MOVBstore [off] {sym} ptr (MOVBreg x) mem) -> (MOVBstore [off] {sym} ptr x mem) 746 (MOVWstore [off] {sym} ptr (MOVWZreg x) mem) -> (MOVWstore [off] {sym} ptr x mem) 747 (MOVHstore [off] {sym} ptr (MOVHZreg x) mem) -> (MOVHstore [off] {sym} ptr x mem) 748 (MOVBstore [off] {sym} ptr (MOVBZreg x) mem) -> (MOVBstore [off] {sym} ptr x mem) 749 750 // Fold constants into memory operations. 751 // Note that this is not always a good idea because if not all the uses of 752 // the ADDconst get eliminated, we still have to compute the ADDconst and we now 753 // have potentially two live values (ptr and (ADDconst [off] ptr)) instead of one. 754 // Nevertheless, let's do it! 755 (MOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVDload [off1+off2] {sym} ptr mem) 756 (MOVWload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVWload [off1+off2] {sym} ptr mem) 757 (MOVHload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVHload [off1+off2] {sym} ptr mem) 758 (MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVBload [off1+off2] {sym} ptr mem) 759 (MOVWZload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVWZload [off1+off2] {sym} ptr mem) 760 (MOVHZload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVHZload [off1+off2] {sym} ptr mem) 761 (MOVBZload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVBZload [off1+off2] {sym} ptr mem) 762 (FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (FMOVSload [off1+off2] {sym} ptr mem) 763 (FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (FMOVDload [off1+off2] {sym} ptr mem) 764 765 (MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVDstore [off1+off2] {sym} ptr val mem) 766 (MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVWstore [off1+off2] {sym} ptr val mem) 767 (MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVHstore [off1+off2] {sym} ptr val mem) 768 (MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVBstore [off1+off2] {sym} ptr val mem) 769 (FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (FMOVSstore [off1+off2] {sym} ptr val mem) 770 (FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (FMOVDstore [off1+off2] {sym} ptr val mem) 771 772 (ADDload [off1] {sym} x (ADDconst [off2] ptr) mem) && ptr.Op != OpSB && is20Bit(off1+off2) -> (ADDload [off1+off2] {sym} x ptr mem) 773 (ADDWload [off1] {sym} x (ADDconst [off2] ptr) mem) && ptr.Op != OpSB && is20Bit(off1+off2) -> (ADDWload [off1+off2] {sym} x ptr mem) 774 (MULLDload [off1] {sym} x (ADDconst [off2] ptr) mem) && ptr.Op != OpSB && is20Bit(off1+off2) -> (MULLDload [off1+off2] {sym} x ptr mem) 775 (MULLWload [off1] {sym} x (ADDconst [off2] ptr) mem) && ptr.Op != OpSB && is20Bit(off1+off2) -> (MULLWload [off1+off2] {sym} x ptr mem) 776 (SUBload [off1] {sym} x (ADDconst [off2] ptr) mem) && ptr.Op != OpSB && is20Bit(off1+off2) -> (SUBload [off1+off2] {sym} x ptr mem) 777 (SUBWload [off1] {sym} x (ADDconst [off2] ptr) mem) && ptr.Op != OpSB && is20Bit(off1+off2) -> (SUBWload [off1+off2] {sym} x ptr mem) 778 779 (ANDload [off1] {sym} x (ADDconst [off2] ptr) mem) && ptr.Op != OpSB && is20Bit(off1+off2) -> (ANDload [off1+off2] {sym} x ptr mem) 780 (ANDWload [off1] {sym} x (ADDconst [off2] ptr) mem) && ptr.Op != OpSB && is20Bit(off1+off2) -> (ANDWload [off1+off2] {sym} x ptr mem) 781 (ORload [off1] {sym} x (ADDconst [off2] ptr) mem) && ptr.Op != OpSB && is20Bit(off1+off2) -> (ORload [off1+off2] {sym} x ptr mem) 782 (ORWload [off1] {sym} x (ADDconst [off2] ptr) mem) && ptr.Op != OpSB && is20Bit(off1+off2) -> (ORWload [off1+off2] {sym} x ptr mem) 783 (XORload [off1] {sym} x (ADDconst [off2] ptr) mem) && ptr.Op != OpSB && is20Bit(off1+off2) -> (XORload [off1+off2] {sym} x ptr mem) 784 (XORWload [off1] {sym} x (ADDconst [off2] ptr) mem) && ptr.Op != OpSB && is20Bit(off1+off2) -> (XORWload [off1+off2] {sym} x ptr mem) 785 786 // Fold constants into stores. 787 (MOVDstore [off] {sym} ptr (MOVDconst [c]) mem) && is16Bit(c) && isU12Bit(off) && ptr.Op != OpSB -> 788 (MOVDstoreconst [makeValAndOff(c,off)] {sym} ptr mem) 789 (MOVWstore [off] {sym} ptr (MOVDconst [c]) mem) && is16Bit(c) && isU12Bit(off) && ptr.Op != OpSB -> 790 (MOVWstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem) 791 (MOVHstore [off] {sym} ptr (MOVDconst [c]) mem) && isU12Bit(off) && ptr.Op != OpSB -> 792 (MOVHstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem) 793 (MOVBstore [off] {sym} ptr (MOVDconst [c]) mem) && is20Bit(off) && ptr.Op != OpSB -> 794 (MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem) 795 796 // Fold address offsets into constant stores. 797 (MOVDstoreconst [sc] {s} (ADDconst [off] ptr) mem) && isU12Bit(ValAndOff(sc).Off()+off) -> 798 (MOVDstoreconst [ValAndOff(sc).add(off)] {s} ptr mem) 799 (MOVWstoreconst [sc] {s} (ADDconst [off] ptr) mem) && isU12Bit(ValAndOff(sc).Off()+off) -> 800 (MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem) 801 (MOVHstoreconst [sc] {s} (ADDconst [off] ptr) mem) && isU12Bit(ValAndOff(sc).Off()+off) -> 802 (MOVHstoreconst [ValAndOff(sc).add(off)] {s} ptr mem) 803 (MOVBstoreconst [sc] {s} (ADDconst [off] ptr) mem) && is20Bit(ValAndOff(sc).Off()+off) -> 804 (MOVBstoreconst [ValAndOff(sc).add(off)] {s} ptr mem) 805 806 // Merge address calculations into loads and stores. 807 // Offsets from SB must not be merged into unaligned memory accesses because 808 // loads/stores using PC-relative addressing directly must be aligned to the 809 // size of the target. 810 (MOVDload [off1] {sym1} (MOVDaddr <t> [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || (t.IsPtr() && t.Elem().Alignment()%8 == 0 && (off1+off2)%8 == 0)) -> 811 (MOVDload [off1+off2] {mergeSym(sym1,sym2)} base mem) 812 (MOVWZload [off1] {sym1} (MOVDaddr <t> [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || (t.IsPtr() && t.Elem().Alignment()%4 == 0 && (off1+off2)%4 == 0)) -> 813 (MOVWZload [off1+off2] {mergeSym(sym1,sym2)} base mem) 814 (MOVHZload [off1] {sym1} (MOVDaddr <t> [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || (t.IsPtr() && t.Elem().Alignment()%2 == 0 && (off1+off2)%2 == 0)) -> 815 (MOVHZload [off1+off2] {mergeSym(sym1,sym2)} base mem) 816 (MOVBZload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 817 (MOVBZload [off1+off2] {mergeSym(sym1,sym2)} base mem) 818 (FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 819 (FMOVSload [off1+off2] {mergeSym(sym1,sym2)} base mem) 820 (FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 821 (FMOVDload [off1+off2] {mergeSym(sym1,sym2)} base mem) 822 823 (MOVWload [off1] {sym1} (MOVDaddr <t> [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || (t.IsPtr() && t.Elem().Alignment()%4 == 0 && (off1+off2)%4 == 0)) -> 824 (MOVWload [off1+off2] {mergeSym(sym1,sym2)} base mem) 825 (MOVHload [off1] {sym1} (MOVDaddr <t> [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || (t.IsPtr() && t.Elem().Alignment()%2 == 0 && (off1+off2)%2 == 0)) -> 826 (MOVHload [off1+off2] {mergeSym(sym1,sym2)} base mem) 827 (MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 828 (MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem) 829 830 (MOVDstore [off1] {sym1} (MOVDaddr <t> [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || (t.IsPtr() && t.Elem().Alignment()%8 == 0 && (off1+off2)%8 == 0)) -> 831 (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) 832 (MOVWstore [off1] {sym1} (MOVDaddr <t> [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || (t.IsPtr() && t.Elem().Alignment()%4 == 0 && (off1+off2)%4 == 0)) -> 833 (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) 834 (MOVHstore [off1] {sym1} (MOVDaddr <t> [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || (t.IsPtr() && t.Elem().Alignment()%2 == 0 && (off1+off2)%2 == 0)) -> 835 (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) 836 (MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 837 (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) 838 (FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 839 (FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) 840 (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 841 (FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) 842 843 (ADDload [o1] {s1} x (MOVDaddr [o2] {s2} ptr) mem) && ptr.Op != OpSB && is20Bit(o1+o2) && canMergeSym(s1, s2) -> (ADDload [o1+o2] {mergeSym(s1, s2)} x ptr mem) 844 (ADDWload [o1] {s1} x (MOVDaddr [o2] {s2} ptr) mem) && ptr.Op != OpSB && is20Bit(o1+o2) && canMergeSym(s1, s2) -> (ADDWload [o1+o2] {mergeSym(s1, s2)} x ptr mem) 845 (MULLDload [o1] {s1} x (MOVDaddr [o2] {s2} ptr) mem) && ptr.Op != OpSB && is20Bit(o1+o2) && canMergeSym(s1, s2) -> (MULLDload [o1+o2] {mergeSym(s1, s2)} x ptr mem) 846 (MULLWload [o1] {s1} x (MOVDaddr [o2] {s2} ptr) mem) && ptr.Op != OpSB && is20Bit(o1+o2) && canMergeSym(s1, s2) -> (MULLWload [o1+o2] {mergeSym(s1, s2)} x ptr mem) 847 (SUBload [o1] {s1} x (MOVDaddr [o2] {s2} ptr) mem) && ptr.Op != OpSB && is20Bit(o1+o2) && canMergeSym(s1, s2) -> (SUBload [o1+o2] {mergeSym(s1, s2)} x ptr mem) 848 (SUBWload [o1] {s1} x (MOVDaddr [o2] {s2} ptr) mem) && ptr.Op != OpSB && is20Bit(o1+o2) && canMergeSym(s1, s2) -> (SUBWload [o1+o2] {mergeSym(s1, s2)} x ptr mem) 849 850 (ANDload [o1] {s1} x (MOVDaddr [o2] {s2} ptr) mem) && ptr.Op != OpSB && is20Bit(o1+o2) && canMergeSym(s1, s2) -> (ANDload [o1+o2] {mergeSym(s1, s2)} x ptr mem) 851 (ANDWload [o1] {s1} x (MOVDaddr [o2] {s2} ptr) mem) && ptr.Op != OpSB && is20Bit(o1+o2) && canMergeSym(s1, s2) -> (ANDWload [o1+o2] {mergeSym(s1, s2)} x ptr mem) 852 (ORload [o1] {s1} x (MOVDaddr [o2] {s2} ptr) mem) && ptr.Op != OpSB && is20Bit(o1+o2) && canMergeSym(s1, s2) -> (ORload [o1+o2] {mergeSym(s1, s2)} x ptr mem) 853 (ORWload [o1] {s1} x (MOVDaddr [o2] {s2} ptr) mem) && ptr.Op != OpSB && is20Bit(o1+o2) && canMergeSym(s1, s2) -> (ORWload [o1+o2] {mergeSym(s1, s2)} x ptr mem) 854 (XORload [o1] {s1} x (MOVDaddr [o2] {s2} ptr) mem) && ptr.Op != OpSB && is20Bit(o1+o2) && canMergeSym(s1, s2) -> (XORload [o1+o2] {mergeSym(s1, s2)} x ptr mem) 855 (XORWload [o1] {s1} x (MOVDaddr [o2] {s2} ptr) mem) && ptr.Op != OpSB && is20Bit(o1+o2) && canMergeSym(s1, s2) -> (XORWload [o1+o2] {mergeSym(s1, s2)} x ptr mem) 856 857 // Cannot store constant to SB directly (no 'move relative long immediate' instructions). 858 (MOVDstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) -> 859 (MOVDstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem) 860 (MOVWstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) -> 861 (MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem) 862 (MOVHstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) -> 863 (MOVHstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem) 864 (MOVBstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && ptr.Op != OpSB && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) -> 865 (MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem) 866 867 // generating indexed loads and stores 868 (MOVBZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 869 (MOVBZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) 870 (MOVBload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 871 (MOVBloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) 872 (MOVHZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 873 (MOVHZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) 874 (MOVHload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 875 (MOVHloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) 876 (MOVWZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 877 (MOVWZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) 878 (MOVWload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 879 (MOVWloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) 880 (MOVDload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 881 (MOVDloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) 882 (FMOVSload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 883 (FMOVSloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) 884 (FMOVDload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 885 (FMOVDloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) 886 887 (MOVBstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 888 (MOVBstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) 889 (MOVHstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 890 (MOVHstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) 891 (MOVWstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 892 (MOVWstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) 893 (MOVDstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 894 (MOVDstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) 895 (FMOVSstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 896 (FMOVSstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) 897 (FMOVDstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 898 (FMOVDstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) 899 900 (MOVBZload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVBZloadidx [off] {sym} ptr idx mem) 901 (MOVBload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVBloadidx [off] {sym} ptr idx mem) 902 (MOVHZload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVHZloadidx [off] {sym} ptr idx mem) 903 (MOVHload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVHloadidx [off] {sym} ptr idx mem) 904 (MOVWZload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVWZloadidx [off] {sym} ptr idx mem) 905 (MOVWload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVWloadidx [off] {sym} ptr idx mem) 906 (MOVDload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVDloadidx [off] {sym} ptr idx mem) 907 (FMOVSload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (FMOVSloadidx [off] {sym} ptr idx mem) 908 (FMOVDload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (FMOVDloadidx [off] {sym} ptr idx mem) 909 910 (MOVBstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVBstoreidx [off] {sym} ptr idx val mem) 911 (MOVHstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVHstoreidx [off] {sym} ptr idx val mem) 912 (MOVWstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVWstoreidx [off] {sym} ptr idx val mem) 913 (MOVDstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVDstoreidx [off] {sym} ptr idx val mem) 914 (FMOVSstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (FMOVSstoreidx [off] {sym} ptr idx val mem) 915 (FMOVDstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (FMOVDstoreidx [off] {sym} ptr idx val mem) 916 917 // combine ADD into indexed loads and stores 918 (MOVBZloadidx [c] {sym} (ADDconst [d] ptr) idx mem) && is20Bit(c+d) -> (MOVBZloadidx [c+d] {sym} ptr idx mem) 919 (MOVBloadidx [c] {sym} (ADDconst [d] ptr) idx mem) && is20Bit(c+d) -> (MOVBloadidx [c+d] {sym} ptr idx mem) 920 (MOVHZloadidx [c] {sym} (ADDconst [d] ptr) idx mem) && is20Bit(c+d) -> (MOVHZloadidx [c+d] {sym} ptr idx mem) 921 (MOVHloadidx [c] {sym} (ADDconst [d] ptr) idx mem) && is20Bit(c+d) -> (MOVHloadidx [c+d] {sym} ptr idx mem) 922 (MOVWZloadidx [c] {sym} (ADDconst [d] ptr) idx mem) && is20Bit(c+d) -> (MOVWZloadidx [c+d] {sym} ptr idx mem) 923 (MOVWloadidx [c] {sym} (ADDconst [d] ptr) idx mem) && is20Bit(c+d) -> (MOVWloadidx [c+d] {sym} ptr idx mem) 924 (MOVDloadidx [c] {sym} (ADDconst [d] ptr) idx mem) && is20Bit(c+d) -> (MOVDloadidx [c+d] {sym} ptr idx mem) 925 (FMOVSloadidx [c] {sym} (ADDconst [d] ptr) idx mem) && is20Bit(c+d) -> (FMOVSloadidx [c+d] {sym} ptr idx mem) 926 (FMOVDloadidx [c] {sym} (ADDconst [d] ptr) idx mem) && is20Bit(c+d) -> (FMOVDloadidx [c+d] {sym} ptr idx mem) 927 928 (MOVBstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) && is20Bit(c+d) -> (MOVBstoreidx [c+d] {sym} ptr idx val mem) 929 (MOVHstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) && is20Bit(c+d) -> (MOVHstoreidx [c+d] {sym} ptr idx val mem) 930 (MOVWstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) && is20Bit(c+d) -> (MOVWstoreidx [c+d] {sym} ptr idx val mem) 931 (MOVDstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) && is20Bit(c+d) -> (MOVDstoreidx [c+d] {sym} ptr idx val mem) 932 (FMOVSstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) && is20Bit(c+d) -> (FMOVSstoreidx [c+d] {sym} ptr idx val mem) 933 (FMOVDstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) && is20Bit(c+d) -> (FMOVDstoreidx [c+d] {sym} ptr idx val mem) 934 935 (MOVBZloadidx [c] {sym} ptr (ADDconst [d] idx) mem) && is20Bit(c+d) -> (MOVBZloadidx [c+d] {sym} ptr idx mem) 936 (MOVBloadidx [c] {sym} ptr (ADDconst [d] idx) mem) && is20Bit(c+d) -> (MOVBloadidx [c+d] {sym} ptr idx mem) 937 (MOVHZloadidx [c] {sym} ptr (ADDconst [d] idx) mem) && is20Bit(c+d) -> (MOVHZloadidx [c+d] {sym} ptr idx mem) 938 (MOVHloadidx [c] {sym} ptr (ADDconst [d] idx) mem) && is20Bit(c+d) -> (MOVHloadidx [c+d] {sym} ptr idx mem) 939 (MOVWZloadidx [c] {sym} ptr (ADDconst [d] idx) mem) && is20Bit(c+d) -> (MOVWZloadidx [c+d] {sym} ptr idx mem) 940 (MOVWloadidx [c] {sym} ptr (ADDconst [d] idx) mem) && is20Bit(c+d) -> (MOVWloadidx [c+d] {sym} ptr idx mem) 941 (MOVDloadidx [c] {sym} ptr (ADDconst [d] idx) mem) && is20Bit(c+d) -> (MOVDloadidx [c+d] {sym} ptr idx mem) 942 (FMOVSloadidx [c] {sym} ptr (ADDconst [d] idx) mem) && is20Bit(c+d) -> (FMOVSloadidx [c+d] {sym} ptr idx mem) 943 (FMOVDloadidx [c] {sym} ptr (ADDconst [d] idx) mem) && is20Bit(c+d) -> (FMOVDloadidx [c+d] {sym} ptr idx mem) 944 945 (MOVBstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) && is20Bit(c+d) -> (MOVBstoreidx [c+d] {sym} ptr idx val mem) 946 (MOVHstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) && is20Bit(c+d) -> (MOVHstoreidx [c+d] {sym} ptr idx val mem) 947 (MOVWstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) && is20Bit(c+d) -> (MOVWstoreidx [c+d] {sym} ptr idx val mem) 948 (MOVDstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) && is20Bit(c+d) -> (MOVDstoreidx [c+d] {sym} ptr idx val mem) 949 (FMOVSstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) && is20Bit(c+d) -> (FMOVSstoreidx [c+d] {sym} ptr idx val mem) 950 (FMOVDstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) && is20Bit(c+d) -> (FMOVDstoreidx [c+d] {sym} ptr idx val mem) 951 952 // MOVDaddr into MOVDaddridx 953 (MOVDaddridx [off1] {sym1} (MOVDaddr [off2] {sym2} x) y) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB -> 954 (MOVDaddridx [off1+off2] {mergeSym(sym1,sym2)} x y) 955 (MOVDaddridx [off1] {sym1} x (MOVDaddr [off2] {sym2} y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB -> 956 (MOVDaddridx [off1+off2] {mergeSym(sym1,sym2)} x y) 957 958 // Absorb InvertFlags into branches. 959 ((LT|GT|LE|GE|EQ|NE) (InvertFlags cmp) yes no) -> ((GT|LT|GE|LE|EQ|NE) cmp yes no) 960 961 // Constant comparisons. 962 (CMPconst (MOVDconst [x]) [y]) && x==y -> (FlagEQ) 963 (CMPconst (MOVDconst [x]) [y]) && x<y -> (FlagLT) 964 (CMPconst (MOVDconst [x]) [y]) && x>y -> (FlagGT) 965 (CMPUconst (MOVDconst [x]) [y]) && uint64(x)==uint64(y) -> (FlagEQ) 966 (CMPUconst (MOVDconst [x]) [y]) && uint64(x)<uint64(y) -> (FlagLT) 967 (CMPUconst (MOVDconst [x]) [y]) && uint64(x)>uint64(y) -> (FlagGT) 968 969 (CMPWconst (MOVDconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ) 970 (CMPWconst (MOVDconst [x]) [y]) && int32(x)<int32(y) -> (FlagLT) 971 (CMPWconst (MOVDconst [x]) [y]) && int32(x)>int32(y) -> (FlagGT) 972 (CMPWUconst (MOVDconst [x]) [y]) && uint32(x)==uint32(y) -> (FlagEQ) 973 (CMPWUconst (MOVDconst [x]) [y]) && uint32(x)<uint32(y) -> (FlagLT) 974 (CMPWUconst (MOVDconst [x]) [y]) && uint32(x)>uint32(y) -> (FlagGT) 975 976 (CMP(W|WU)const (MOVBZreg _) [c]) && 0xff < c -> (FlagLT) 977 (CMP(W|WU)const (MOVHZreg _) [c]) && 0xffff < c -> (FlagLT) 978 979 (CMPconst (SRDconst _ [c]) [n]) && c > 0 && n < 0 -> (FlagGT) 980 (CMPWconst (SRWconst _ [c]) [n]) && c > 0 && n < 0 -> (FlagGT) 981 982 (CMPUconst (SRDconst _ [c]) [n]) && c > 0 && c < 64 && (1<<uint(64-c)) <= uint64(n) -> (FlagLT) 983 (CMPWUconst (SRWconst _ [c]) [n]) && c > 0 && c < 32 && (1<<uint(32-c)) <= uint32(n) -> (FlagLT) 984 985 (CMPWconst (ANDWconst _ [m]) [n]) && int32(m) >= 0 && int32(m) < int32(n) -> (FlagLT) 986 (CMPWUconst (ANDWconst _ [m]) [n]) && uint32(m) < uint32(n) -> (FlagLT) 987 988 // Convert 64-bit comparisons to 32-bit comparisons and signed comparisons 989 // to unsigned comparisons. 990 // Helps simplify constant comparison detection. 991 (CM(P|PU)const (MOV(W|WZ)reg x) [c]) -> (CMP(W|WU)const x [c]) 992 (CM(P|P|PU|PU)const x:(MOV(H|HZ|H|HZ)reg _) [c]) -> (CMP(W|W|WU|WU)const x [c]) 993 (CM(P|P|PU|PU)const x:(MOV(B|BZ|B|BZ)reg _) [c]) -> (CMP(W|W|WU|WU)const x [c]) 994 (CMPconst (MOV(WZ|W)reg x:(ANDWconst [m] _)) [c]) && int32(m) >= 0 && c >= 0 -> (CMPWUconst x [c]) 995 (CMPUconst (MOV(WZ|W)reg x:(ANDWconst [m] _)) [c]) && int32(m) >= 0 -> (CMPWUconst x [c]) 996 (CMPconst x:(SRDconst _ [c]) [n]) && c > 0 && n >= 0 -> (CMPUconst x [n]) 997 (CMPWconst x:(SRWconst _ [c]) [n]) && c > 0 && n >= 0 -> (CMPWUconst x [n]) 998 999 // Absorb sign and zero extensions into 32-bit comparisons. 1000 (CMP(W|W|WU|WU) x (MOV(W|WZ|W|WZ)reg y)) -> (CMP(W|W|WU|WU) x y) 1001 (CMP(W|W|WU|WU) (MOV(W|WZ|W|WZ)reg x) y) -> (CMP(W|W|WU|WU) x y) 1002 (CMP(W|W|WU|WU)const (MOV(W|WZ|W|WZ)reg x) [c]) -> (CMP(W|W|WU|WU)const x [c]) 1003 1004 // Absorb flag constants into branches. 1005 (EQ (FlagEQ) yes no) -> (First nil yes no) 1006 (EQ (FlagLT) yes no) -> (First nil no yes) 1007 (EQ (FlagGT) yes no) -> (First nil no yes) 1008 1009 (NE (FlagEQ) yes no) -> (First nil no yes) 1010 (NE (FlagLT) yes no) -> (First nil yes no) 1011 (NE (FlagGT) yes no) -> (First nil yes no) 1012 1013 (LT (FlagEQ) yes no) -> (First nil no yes) 1014 (LT (FlagLT) yes no) -> (First nil yes no) 1015 (LT (FlagGT) yes no) -> (First nil no yes) 1016 1017 (LE (FlagEQ) yes no) -> (First nil yes no) 1018 (LE (FlagLT) yes no) -> (First nil yes no) 1019 (LE (FlagGT) yes no) -> (First nil no yes) 1020 1021 (GT (FlagEQ) yes no) -> (First nil no yes) 1022 (GT (FlagLT) yes no) -> (First nil no yes) 1023 (GT (FlagGT) yes no) -> (First nil yes no) 1024 1025 (GE (FlagEQ) yes no) -> (First nil yes no) 1026 (GE (FlagLT) yes no) -> (First nil no yes) 1027 (GE (FlagGT) yes no) -> (First nil yes no) 1028 1029 // Absorb flag constants into SETxx ops. 1030 (MOVDEQ _ x (FlagEQ)) -> x 1031 (MOVDEQ y _ (FlagLT)) -> y 1032 (MOVDEQ y _ (FlagGT)) -> y 1033 1034 (MOVDNE y _ (FlagEQ)) -> y 1035 (MOVDNE _ x (FlagLT)) -> x 1036 (MOVDNE _ x (FlagGT)) -> x 1037 1038 (MOVDLT y _ (FlagEQ)) -> y 1039 (MOVDLT _ x (FlagLT)) -> x 1040 (MOVDLT y _ (FlagGT)) -> y 1041 1042 (MOVDLE _ x (FlagEQ)) -> x 1043 (MOVDLE _ x (FlagLT)) -> x 1044 (MOVDLE y _ (FlagGT)) -> y 1045 1046 (MOVDGT y _ (FlagEQ)) -> y 1047 (MOVDGT y _ (FlagLT)) -> y 1048 (MOVDGT _ x (FlagGT)) -> x 1049 1050 (MOVDGE _ x (FlagEQ)) -> x 1051 (MOVDGE y _ (FlagLT)) -> y 1052 (MOVDGE _ x (FlagGT)) -> x 1053 1054 // Remove redundant *const ops 1055 (ADDconst [0] x) -> x 1056 (ADDWconst [c] x) && int32(c)==0 -> x 1057 (SUBconst [0] x) -> x 1058 (SUBWconst [c] x) && int32(c) == 0 -> x 1059 (ANDconst [0] _) -> (MOVDconst [0]) 1060 (ANDWconst [c] _) && int32(c)==0 -> (MOVDconst [0]) 1061 (ANDconst [-1] x) -> x 1062 (ANDWconst [c] x) && int32(c)==-1 -> x 1063 (ORconst [0] x) -> x 1064 (ORWconst [c] x) && int32(c)==0 -> x 1065 (ORconst [-1] _) -> (MOVDconst [-1]) 1066 (ORWconst [c] _) && int32(c)==-1 -> (MOVDconst [-1]) 1067 (XORconst [0] x) -> x 1068 (XORWconst [c] x) && int32(c)==0 -> x 1069 1070 // Convert constant subtracts to constant adds. 1071 (SUBconst [c] x) && c != -(1<<31) -> (ADDconst [-c] x) 1072 (SUBWconst [c] x) -> (ADDWconst [int64(int32(-c))] x) 1073 1074 // generic constant folding 1075 // TODO: more of this 1076 (ADDconst [c] (MOVDconst [d])) -> (MOVDconst [c+d]) 1077 (ADDWconst [c] (MOVDconst [d])) -> (MOVDconst [int64(int32(c+d))]) 1078 (ADDconst [c] (ADDconst [d] x)) && is32Bit(c+d) -> (ADDconst [c+d] x) 1079 (ADDWconst [c] (ADDWconst [d] x)) -> (ADDWconst [int64(int32(c+d))] x) 1080 (SUBconst (MOVDconst [d]) [c]) -> (MOVDconst [d-c]) 1081 (SUBconst (SUBconst x [d]) [c]) && is32Bit(-c-d) -> (ADDconst [-c-d] x) 1082 (SRADconst [c] (MOVDconst [d])) -> (MOVDconst [d>>uint64(c)]) 1083 (SRAWconst [c] (MOVDconst [d])) -> (MOVDconst [int64(int32(d))>>uint64(c)]) 1084 (NEG (MOVDconst [c])) -> (MOVDconst [-c]) 1085 (NEGW (MOVDconst [c])) -> (MOVDconst [int64(int32(-c))]) 1086 (MULLDconst [c] (MOVDconst [d])) -> (MOVDconst [c*d]) 1087 (MULLWconst [c] (MOVDconst [d])) -> (MOVDconst [int64(int32(c*d))]) 1088 (AND (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c&d]) 1089 (ANDconst [c] (MOVDconst [d])) -> (MOVDconst [c&d]) 1090 (ANDWconst [c] (MOVDconst [d])) -> (MOVDconst [c&d]) 1091 (OR (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c|d]) 1092 (ORconst [c] (MOVDconst [d])) -> (MOVDconst [c|d]) 1093 (ORWconst [c] (MOVDconst [d])) -> (MOVDconst [c|d]) 1094 (XOR (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c^d]) 1095 (XORconst [c] (MOVDconst [d])) -> (MOVDconst [c^d]) 1096 (XORWconst [c] (MOVDconst [d])) -> (MOVDconst [c^d]) 1097 (LoweredRound32F x:(FMOVSconst)) -> x 1098 (LoweredRound64F x:(FMOVDconst)) -> x 1099 1100 // generic simplifications 1101 // TODO: more of this 1102 (ADD x (NEG y)) -> (SUB x y) 1103 (ADDW x (NEGW y)) -> (SUBW x y) 1104 (SUB x x) -> (MOVDconst [0]) 1105 (SUBW x x) -> (MOVDconst [0]) 1106 (AND x x) -> x 1107 (ANDW x x) -> x 1108 (OR x x) -> x 1109 (ORW x x) -> x 1110 (XOR x x) -> (MOVDconst [0]) 1111 (XORW x x) -> (MOVDconst [0]) 1112 (NEG (ADDconst [c] (NEG x))) && c != -(1<<31) -> (ADDconst [-c] x) 1113 (MOVBZreg (ANDWconst [m] x)) -> (MOVWZreg (ANDWconst <typ.UInt32> [int64( uint8(m))] x)) 1114 (MOVHZreg (ANDWconst [m] x)) -> (MOVWZreg (ANDWconst <typ.UInt32> [int64(uint16(m))] x)) 1115 (MOVBreg (ANDWconst [m] x)) && int8(m) >= 0 -> (MOVWZreg (ANDWconst <typ.UInt32> [int64( uint8(m))] x)) 1116 (MOVHreg (ANDWconst [m] x)) && int16(m) >= 0 -> (MOVWZreg (ANDWconst <typ.UInt32> [int64(uint16(m))] x)) 1117 1118 // fused multiply-add 1119 (FADD (FMUL y z) x) -> (FMADD x y z) 1120 (FADDS (FMULS y z) x) -> (FMADDS x y z) 1121 (FSUB (FMUL y z) x) -> (FMSUB x y z) 1122 (FSUBS (FMULS y z) x) -> (FMSUBS x y z) 1123 1124 // Fold memory operations into operations. 1125 // Exclude global data (SB) because these instructions cannot handle relative addresses. 1126 // TODO(mundaym): use LARL in the assembler to handle SB? 1127 // TODO(mundaym): indexed versions of these? 1128 (ADD <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1129 -> (ADDload <t> [off] {sym} x ptr mem) 1130 (ADD <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1131 -> (ADDload <t> [off] {sym} x ptr mem) 1132 (ADDW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1133 -> (ADDWload <t> [off] {sym} x ptr mem) 1134 (ADDW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1135 -> (ADDWload <t> [off] {sym} x ptr mem) 1136 (ADDW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1137 -> (ADDWload <t> [off] {sym} x ptr mem) 1138 (ADDW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1139 -> (ADDWload <t> [off] {sym} x ptr mem) 1140 (MULLD <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1141 -> (MULLDload <t> [off] {sym} x ptr mem) 1142 (MULLD <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1143 -> (MULLDload <t> [off] {sym} x ptr mem) 1144 (MULLW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1145 -> (MULLWload <t> [off] {sym} x ptr mem) 1146 (MULLW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1147 -> (MULLWload <t> [off] {sym} x ptr mem) 1148 (MULLW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1149 -> (MULLWload <t> [off] {sym} x ptr mem) 1150 (MULLW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1151 -> (MULLWload <t> [off] {sym} x ptr mem) 1152 (SUB <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1153 -> (SUBload <t> [off] {sym} x ptr mem) 1154 (SUBW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1155 -> (SUBWload <t> [off] {sym} x ptr mem) 1156 (SUBW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1157 -> (SUBWload <t> [off] {sym} x ptr mem) 1158 (AND <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1159 -> (ANDload <t> [off] {sym} x ptr mem) 1160 (AND <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1161 -> (ANDload <t> [off] {sym} x ptr mem) 1162 (ANDW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1163 -> (ANDWload <t> [off] {sym} x ptr mem) 1164 (ANDW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1165 -> (ANDWload <t> [off] {sym} x ptr mem) 1166 (ANDW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1167 -> (ANDWload <t> [off] {sym} x ptr mem) 1168 (ANDW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1169 -> (ANDWload <t> [off] {sym} x ptr mem) 1170 (OR <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1171 -> (ORload <t> [off] {sym} x ptr mem) 1172 (OR <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1173 -> (ORload <t> [off] {sym} x ptr mem) 1174 (ORW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1175 -> (ORWload <t> [off] {sym} x ptr mem) 1176 (ORW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1177 -> (ORWload <t> [off] {sym} x ptr mem) 1178 (ORW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1179 -> (ORWload <t> [off] {sym} x ptr mem) 1180 (ORW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1181 -> (ORWload <t> [off] {sym} x ptr mem) 1182 (XOR <t> x g:(MOVDload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1183 -> (XORload <t> [off] {sym} x ptr mem) 1184 (XOR <t> g:(MOVDload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1185 -> (XORload <t> [off] {sym} x ptr mem) 1186 (XORW <t> x g:(MOVWload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1187 -> (XORWload <t> [off] {sym} x ptr mem) 1188 (XORW <t> g:(MOVWload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1189 -> (XORWload <t> [off] {sym} x ptr mem) 1190 (XORW <t> x g:(MOVWZload [off] {sym} ptr mem)) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1191 -> (XORWload <t> [off] {sym} x ptr mem) 1192 (XORW <t> g:(MOVWZload [off] {sym} ptr mem) x) && ptr.Op != OpSB && is20Bit(off) && canMergeLoadClobber(v, g, x) && clobber(g) 1193 -> (XORWload <t> [off] {sym} x ptr mem) 1194 1195 // Combine constant stores into larger (unaligned) stores. 1196 // Avoid SB because constant stores to relative offsets are 1197 // emulated by the assembler and also can't handle unaligned offsets. 1198 (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem)) 1199 && p.Op != OpSB 1200 && x.Uses == 1 1201 && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() 1202 && clobber(x) 1203 -> (MOVHstoreconst [makeValAndOff(ValAndOff(c).Val()&0xff | ValAndOff(a).Val()<<8, ValAndOff(a).Off())] {s} p mem) 1204 (MOVHstoreconst [c] {s} p x:(MOVHstoreconst [a] {s} p mem)) 1205 && p.Op != OpSB 1206 && x.Uses == 1 1207 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() 1208 && clobber(x) 1209 -> (MOVWstore [ValAndOff(a).Off()] {s} p (MOVDconst [int64(int32(ValAndOff(c).Val()&0xffff | ValAndOff(a).Val()<<16))]) mem) 1210 (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem)) 1211 && p.Op != OpSB 1212 && x.Uses == 1 1213 && ValAndOff(a).Off() + 4 == ValAndOff(c).Off() 1214 && clobber(x) 1215 -> (MOVDstore [ValAndOff(a).Off()] {s} p (MOVDconst [ValAndOff(c).Val()&0xffffffff | ValAndOff(a).Val()<<32]) mem) 1216 1217 // Combine stores into larger (unaligned) stores. 1218 // It doesn't work on global data (based on SB) because stores with relative addressing 1219 // require that the memory operand be aligned. 1220 (MOVBstore [i] {s} p w x:(MOVBstore [i-1] {s} p (SRDconst [8] w) mem)) 1221 && p.Op != OpSB 1222 && x.Uses == 1 1223 && clobber(x) 1224 -> (MOVHstore [i-1] {s} p w mem) 1225 (MOVBstore [i] {s} p w0:(SRDconst [j] w) x:(MOVBstore [i-1] {s} p (SRDconst [j+8] w) mem)) 1226 && p.Op != OpSB 1227 && x.Uses == 1 1228 && clobber(x) 1229 -> (MOVHstore [i-1] {s} p w0 mem) 1230 (MOVBstore [i] {s} p w x:(MOVBstore [i-1] {s} p (SRWconst [8] w) mem)) 1231 && p.Op != OpSB 1232 && x.Uses == 1 1233 && clobber(x) 1234 -> (MOVHstore [i-1] {s} p w mem) 1235 (MOVBstore [i] {s} p w0:(SRWconst [j] w) x:(MOVBstore [i-1] {s} p (SRWconst [j+8] w) mem)) 1236 && p.Op != OpSB 1237 && x.Uses == 1 1238 && clobber(x) 1239 -> (MOVHstore [i-1] {s} p w0 mem) 1240 (MOVHstore [i] {s} p w x:(MOVHstore [i-2] {s} p (SRDconst [16] w) mem)) 1241 && p.Op != OpSB 1242 && x.Uses == 1 1243 && clobber(x) 1244 -> (MOVWstore [i-2] {s} p w mem) 1245 (MOVHstore [i] {s} p w0:(SRDconst [j] w) x:(MOVHstore [i-2] {s} p (SRDconst [j+16] w) mem)) 1246 && p.Op != OpSB 1247 && x.Uses == 1 1248 && clobber(x) 1249 -> (MOVWstore [i-2] {s} p w0 mem) 1250 (MOVHstore [i] {s} p w x:(MOVHstore [i-2] {s} p (SRWconst [16] w) mem)) 1251 && p.Op != OpSB 1252 && x.Uses == 1 1253 && clobber(x) 1254 -> (MOVWstore [i-2] {s} p w mem) 1255 (MOVHstore [i] {s} p w0:(SRWconst [j] w) x:(MOVHstore [i-2] {s} p (SRWconst [j+16] w) mem)) 1256 && p.Op != OpSB 1257 && x.Uses == 1 1258 && clobber(x) 1259 -> (MOVWstore [i-2] {s} p w0 mem) 1260 (MOVWstore [i] {s} p (SRDconst [32] w) x:(MOVWstore [i-4] {s} p w mem)) 1261 && p.Op != OpSB 1262 && x.Uses == 1 1263 && clobber(x) 1264 -> (MOVDstore [i-4] {s} p w mem) 1265 (MOVWstore [i] {s} p w0:(SRDconst [j] w) x:(MOVWstore [i-4] {s} p (SRDconst [j+32] w) mem)) 1266 && p.Op != OpSB 1267 && x.Uses == 1 1268 && clobber(x) 1269 -> (MOVDstore [i-4] {s} p w0 mem) 1270 1271 (MOVBstoreidx [i] {s} p idx w x:(MOVBstoreidx [i-1] {s} p idx (SRDconst [8] w) mem)) 1272 && x.Uses == 1 1273 && clobber(x) 1274 -> (MOVHstoreidx [i-1] {s} p idx w mem) 1275 (MOVBstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx (SRDconst [j+8] w) mem)) 1276 && x.Uses == 1 1277 && clobber(x) 1278 -> (MOVHstoreidx [i-1] {s} p idx w0 mem) 1279 (MOVBstoreidx [i] {s} p idx w x:(MOVBstoreidx [i-1] {s} p idx (SRWconst [8] w) mem)) 1280 && x.Uses == 1 1281 && clobber(x) 1282 -> (MOVHstoreidx [i-1] {s} p idx w mem) 1283 (MOVBstoreidx [i] {s} p idx w0:(SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx (SRWconst [j+8] w) mem)) 1284 && x.Uses == 1 1285 && clobber(x) 1286 -> (MOVHstoreidx [i-1] {s} p idx w0 mem) 1287 (MOVHstoreidx [i] {s} p idx w x:(MOVHstoreidx [i-2] {s} p idx (SRDconst [16] w) mem)) 1288 && x.Uses == 1 1289 && clobber(x) 1290 -> (MOVWstoreidx [i-2] {s} p idx w mem) 1291 (MOVHstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVHstoreidx [i-2] {s} p idx (SRDconst [j+16] w) mem)) 1292 && x.Uses == 1 1293 && clobber(x) 1294 -> (MOVWstoreidx [i-2] {s} p idx w0 mem) 1295 (MOVHstoreidx [i] {s} p idx w x:(MOVHstoreidx [i-2] {s} p idx (SRWconst [16] w) mem)) 1296 && x.Uses == 1 1297 && clobber(x) 1298 -> (MOVWstoreidx [i-2] {s} p idx w mem) 1299 (MOVHstoreidx [i] {s} p idx w0:(SRWconst [j] w) x:(MOVHstoreidx [i-2] {s} p idx (SRWconst [j+16] w) mem)) 1300 && x.Uses == 1 1301 && clobber(x) 1302 -> (MOVWstoreidx [i-2] {s} p idx w0 mem) 1303 (MOVWstoreidx [i] {s} p idx w x:(MOVWstoreidx [i-4] {s} p idx (SRDconst [32] w) mem)) 1304 && x.Uses == 1 1305 && clobber(x) 1306 -> (MOVDstoreidx [i-4] {s} p idx w mem) 1307 (MOVWstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVWstoreidx [i-4] {s} p idx (SRDconst [j+32] w) mem)) 1308 && x.Uses == 1 1309 && clobber(x) 1310 -> (MOVDstoreidx [i-4] {s} p idx w0 mem) 1311 1312 // Combine stores into larger (unaligned) stores with the bytes reversed (little endian). 1313 // Store-with-bytes-reversed instructions do not support relative memory addresses, 1314 // so these stores can't operate on global data (SB). 1315 (MOVBstore [i] {s} p (SRDconst [8] w) x:(MOVBstore [i-1] {s} p w mem)) 1316 && p.Op != OpSB 1317 && x.Uses == 1 1318 && clobber(x) 1319 -> (MOVHBRstore [i-1] {s} p w mem) 1320 (MOVBstore [i] {s} p (SRDconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SRDconst [j-8] w) mem)) 1321 && p.Op != OpSB 1322 && x.Uses == 1 1323 && clobber(x) 1324 -> (MOVHBRstore [i-1] {s} p w0 mem) 1325 (MOVBstore [i] {s} p (SRWconst [8] w) x:(MOVBstore [i-1] {s} p w mem)) 1326 && p.Op != OpSB 1327 && x.Uses == 1 1328 && clobber(x) 1329 -> (MOVHBRstore [i-1] {s} p w mem) 1330 (MOVBstore [i] {s} p (SRWconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SRWconst [j-8] w) mem)) 1331 && p.Op != OpSB 1332 && x.Uses == 1 1333 && clobber(x) 1334 -> (MOVHBRstore [i-1] {s} p w0 mem) 1335 (MOVHBRstore [i] {s} p (SRDconst [16] w) x:(MOVHBRstore [i-2] {s} p w mem)) 1336 && x.Uses == 1 1337 && clobber(x) 1338 -> (MOVWBRstore [i-2] {s} p w mem) 1339 (MOVHBRstore [i] {s} p (SRDconst [j] w) x:(MOVHBRstore [i-2] {s} p w0:(SRDconst [j-16] w) mem)) 1340 && x.Uses == 1 1341 && clobber(x) 1342 -> (MOVWBRstore [i-2] {s} p w0 mem) 1343 (MOVHBRstore [i] {s} p (SRWconst [16] w) x:(MOVHBRstore [i-2] {s} p w mem)) 1344 && x.Uses == 1 1345 && clobber(x) 1346 -> (MOVWBRstore [i-2] {s} p w mem) 1347 (MOVHBRstore [i] {s} p (SRWconst [j] w) x:(MOVHBRstore [i-2] {s} p w0:(SRWconst [j-16] w) mem)) 1348 && x.Uses == 1 1349 && clobber(x) 1350 -> (MOVWBRstore [i-2] {s} p w0 mem) 1351 (MOVWBRstore [i] {s} p (SRDconst [32] w) x:(MOVWBRstore [i-4] {s} p w mem)) 1352 && x.Uses == 1 1353 && clobber(x) 1354 -> (MOVDBRstore [i-4] {s} p w mem) 1355 (MOVWBRstore [i] {s} p (SRDconst [j] w) x:(MOVWBRstore [i-4] {s} p w0:(SRDconst [j-32] w) mem)) 1356 && x.Uses == 1 1357 && clobber(x) 1358 -> (MOVDBRstore [i-4] {s} p w0 mem) 1359 1360 (MOVBstoreidx [i] {s} p idx (SRDconst [8] w) x:(MOVBstoreidx [i-1] {s} p idx w mem)) 1361 && x.Uses == 1 1362 && clobber(x) 1363 -> (MOVHBRstoreidx [i-1] {s} p idx w mem) 1364 (MOVBstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx w0:(SRDconst [j-8] w) mem)) 1365 && x.Uses == 1 1366 && clobber(x) 1367 -> (MOVHBRstoreidx [i-1] {s} p idx w0 mem) 1368 (MOVBstoreidx [i] {s} p idx (SRWconst [8] w) x:(MOVBstoreidx [i-1] {s} p idx w mem)) 1369 && x.Uses == 1 1370 && clobber(x) 1371 -> (MOVHBRstoreidx [i-1] {s} p idx w mem) 1372 (MOVBstoreidx [i] {s} p idx (SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx w0:(SRWconst [j-8] w) mem)) 1373 && x.Uses == 1 1374 && clobber(x) 1375 -> (MOVHBRstoreidx [i-1] {s} p idx w0 mem) 1376 (MOVHBRstoreidx [i] {s} p idx (SRDconst [16] w) x:(MOVHBRstoreidx [i-2] {s} p idx w mem)) 1377 && x.Uses == 1 1378 && clobber(x) 1379 -> (MOVWBRstoreidx [i-2] {s} p idx w mem) 1380 (MOVHBRstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVHBRstoreidx [i-2] {s} p idx w0:(SRDconst [j-16] w) mem)) 1381 && x.Uses == 1 1382 && clobber(x) 1383 -> (MOVWBRstoreidx [i-2] {s} p idx w0 mem) 1384 (MOVHBRstoreidx [i] {s} p idx (SRWconst [16] w) x:(MOVHBRstoreidx [i-2] {s} p idx w mem)) 1385 && x.Uses == 1 1386 && clobber(x) 1387 -> (MOVWBRstoreidx [i-2] {s} p idx w mem) 1388 (MOVHBRstoreidx [i] {s} p idx (SRWconst [j] w) x:(MOVHBRstoreidx [i-2] {s} p idx w0:(SRWconst [j-16] w) mem)) 1389 && x.Uses == 1 1390 && clobber(x) 1391 -> (MOVWBRstoreidx [i-2] {s} p idx w0 mem) 1392 (MOVWBRstoreidx [i] {s} p idx (SRDconst [32] w) x:(MOVWBRstoreidx [i-4] {s} p idx w mem)) 1393 && x.Uses == 1 1394 && clobber(x) 1395 -> (MOVDBRstoreidx [i-4] {s} p idx w mem) 1396 (MOVWBRstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVWBRstoreidx [i-4] {s} p idx w0:(SRDconst [j-32] w) mem)) 1397 && x.Uses == 1 1398 && clobber(x) 1399 -> (MOVDBRstoreidx [i-4] {s} p idx w0 mem) 1400 1401 // Combining byte loads into larger (unaligned) loads. 1402 1403 // Big-endian loads 1404 1405 (ORW x1:(MOVBZload [i1] {s} p mem) 1406 sh:(SLWconst [8] x0:(MOVBZload [i0] {s} p mem))) 1407 && i1 == i0+1 1408 && p.Op != OpSB 1409 && x0.Uses == 1 1410 && x1.Uses == 1 1411 && sh.Uses == 1 1412 && mergePoint(b,x0,x1) != nil 1413 && clobber(x0) 1414 && clobber(x1) 1415 && clobber(sh) 1416 -> @mergePoint(b,x0,x1) (MOVHZload [i0] {s} p mem) 1417 1418 (OR x1:(MOVBZload [i1] {s} p mem) 1419 sh:(SLDconst [8] x0:(MOVBZload [i0] {s} p mem))) 1420 && i1 == i0+1 1421 && p.Op != OpSB 1422 && x0.Uses == 1 1423 && x1.Uses == 1 1424 && sh.Uses == 1 1425 && mergePoint(b,x0,x1) != nil 1426 && clobber(x0) 1427 && clobber(x1) 1428 && clobber(sh) 1429 -> @mergePoint(b,x0,x1) (MOVHZload [i0] {s} p mem) 1430 1431 (ORW x1:(MOVHZload [i1] {s} p mem) 1432 sh:(SLWconst [16] x0:(MOVHZload [i0] {s} p mem))) 1433 && i1 == i0+2 1434 && p.Op != OpSB 1435 && x0.Uses == 1 1436 && x1.Uses == 1 1437 && sh.Uses == 1 1438 && mergePoint(b,x0,x1) != nil 1439 && clobber(x0) 1440 && clobber(x1) 1441 && clobber(sh) 1442 -> @mergePoint(b,x0,x1) (MOVWZload [i0] {s} p mem) 1443 1444 (OR x1:(MOVHZload [i1] {s} p mem) 1445 sh:(SLDconst [16] x0:(MOVHZload [i0] {s} p mem))) 1446 && i1 == i0+2 1447 && p.Op != OpSB 1448 && x0.Uses == 1 1449 && x1.Uses == 1 1450 && sh.Uses == 1 1451 && mergePoint(b,x0,x1) != nil 1452 && clobber(x0) 1453 && clobber(x1) 1454 && clobber(sh) 1455 -> @mergePoint(b,x0,x1) (MOVWZload [i0] {s} p mem) 1456 1457 (OR x1:(MOVWZload [i1] {s} p mem) 1458 sh:(SLDconst [32] x0:(MOVWZload [i0] {s} p mem))) 1459 && i1 == i0+4 1460 && p.Op != OpSB 1461 && x0.Uses == 1 1462 && x1.Uses == 1 1463 && sh.Uses == 1 1464 && mergePoint(b,x0,x1) != nil 1465 && clobber(x0) 1466 && clobber(x1) 1467 && clobber(sh) 1468 -> @mergePoint(b,x0,x1) (MOVDload [i0] {s} p mem) 1469 1470 (ORW 1471 s0:(SLWconst [j0] x0:(MOVBZload [i0] {s} p mem)) 1472 or:(ORW 1473 s1:(SLWconst [j1] x1:(MOVBZload [i1] {s} p mem)) 1474 y)) 1475 && i1 == i0+1 1476 && j1 == j0-8 1477 && j1 % 16 == 0 1478 && x0.Uses == 1 1479 && x1.Uses == 1 1480 && s0.Uses == 1 1481 && s1.Uses == 1 1482 && or.Uses == 1 1483 && mergePoint(b,x0,x1) != nil 1484 && clobber(x0) 1485 && clobber(x1) 1486 && clobber(s0) 1487 && clobber(s1) 1488 && clobber(or) 1489 -> @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZload [i0] {s} p mem)) y) 1490 1491 (OR 1492 s0:(SLDconst [j0] x0:(MOVBZload [i0] {s} p mem)) 1493 or:(OR 1494 s1:(SLDconst [j1] x1:(MOVBZload [i1] {s} p mem)) 1495 y)) 1496 && i1 == i0+1 1497 && j1 == j0-8 1498 && j1 % 16 == 0 1499 && x0.Uses == 1 1500 && x1.Uses == 1 1501 && s0.Uses == 1 1502 && s1.Uses == 1 1503 && or.Uses == 1 1504 && mergePoint(b,x0,x1) != nil 1505 && clobber(x0) 1506 && clobber(x1) 1507 && clobber(s0) 1508 && clobber(s1) 1509 && clobber(or) 1510 -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZload [i0] {s} p mem)) y) 1511 1512 (OR 1513 s0:(SLDconst [j0] x0:(MOVHZload [i0] {s} p mem)) 1514 or:(OR 1515 s1:(SLDconst [j1] x1:(MOVHZload [i1] {s} p mem)) 1516 y)) 1517 && i1 == i0+2 1518 && j1 == j0-16 1519 && j1 % 32 == 0 1520 && x0.Uses == 1 1521 && x1.Uses == 1 1522 && s0.Uses == 1 1523 && s1.Uses == 1 1524 && or.Uses == 1 1525 && mergePoint(b,x0,x1) != nil 1526 && clobber(x0) 1527 && clobber(x1) 1528 && clobber(s0) 1529 && clobber(s1) 1530 && clobber(or) 1531 -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZload [i0] {s} p mem)) y) 1532 1533 // Big-endian indexed loads 1534 1535 (ORW x1:(MOVBZloadidx [i1] {s} p idx mem) 1536 sh:(SLWconst [8] x0:(MOVBZloadidx [i0] {s} p idx mem))) 1537 && i1 == i0+1 1538 && p.Op != OpSB 1539 && x0.Uses == 1 1540 && x1.Uses == 1 1541 && sh.Uses == 1 1542 && mergePoint(b,x0,x1) != nil 1543 && clobber(x0) 1544 && clobber(x1) 1545 && clobber(sh) 1546 -> @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem) 1547 1548 (OR x1:(MOVBZloadidx [i1] {s} p idx mem) 1549 sh:(SLDconst [8] x0:(MOVBZloadidx [i0] {s} p idx mem))) 1550 && i1 == i0+1 1551 && p.Op != OpSB 1552 && x0.Uses == 1 1553 && x1.Uses == 1 1554 && sh.Uses == 1 1555 && mergePoint(b,x0,x1) != nil 1556 && clobber(x0) 1557 && clobber(x1) 1558 && clobber(sh) 1559 -> @mergePoint(b,x0,x1) (MOVHZloadidx [i0] {s} p idx mem) 1560 1561 (ORW x1:(MOVHZloadidx [i1] {s} p idx mem) 1562 sh:(SLWconst [16] x0:(MOVHZloadidx [i0] {s} p idx mem))) 1563 && i1 == i0+2 1564 && p.Op != OpSB 1565 && x0.Uses == 1 1566 && x1.Uses == 1 1567 && sh.Uses == 1 1568 && mergePoint(b,x0,x1) != nil 1569 && clobber(x0) 1570 && clobber(x1) 1571 && clobber(sh) 1572 -> @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem) 1573 1574 (OR x1:(MOVHZloadidx [i1] {s} p idx mem) 1575 sh:(SLDconst [16] x0:(MOVHZloadidx [i0] {s} p idx mem))) 1576 && i1 == i0+2 1577 && p.Op != OpSB 1578 && x0.Uses == 1 1579 && x1.Uses == 1 1580 && sh.Uses == 1 1581 && mergePoint(b,x0,x1) != nil 1582 && clobber(x0) 1583 && clobber(x1) 1584 && clobber(sh) 1585 -> @mergePoint(b,x0,x1) (MOVWZloadidx [i0] {s} p idx mem) 1586 1587 (OR x1:(MOVWZloadidx [i1] {s} p idx mem) 1588 sh:(SLDconst [32] x0:(MOVWZloadidx [i0] {s} p idx mem))) 1589 && i1 == i0+4 1590 && p.Op != OpSB 1591 && x0.Uses == 1 1592 && x1.Uses == 1 1593 && sh.Uses == 1 1594 && mergePoint(b,x0,x1) != nil 1595 && clobber(x0) 1596 && clobber(x1) 1597 && clobber(sh) 1598 -> @mergePoint(b,x0,x1) (MOVDloadidx [i0] {s} p idx mem) 1599 1600 (ORW 1601 s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) 1602 or:(ORW 1603 s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) 1604 y)) 1605 && i1 == i0+1 1606 && j1 == j0-8 1607 && j1 % 16 == 0 1608 && x0.Uses == 1 1609 && x1.Uses == 1 1610 && s0.Uses == 1 1611 && s1.Uses == 1 1612 && or.Uses == 1 1613 && mergePoint(b,x0,x1) != nil 1614 && clobber(x0) 1615 && clobber(x1) 1616 && clobber(s0) 1617 && clobber(s1) 1618 && clobber(or) 1619 -> @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y) 1620 1621 (OR 1622 s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) 1623 or:(OR 1624 s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) 1625 y)) 1626 && i1 == i0+1 1627 && j1 == j0-8 1628 && j1 % 16 == 0 1629 && x0.Uses == 1 1630 && x1.Uses == 1 1631 && s0.Uses == 1 1632 && s1.Uses == 1 1633 && or.Uses == 1 1634 && mergePoint(b,x0,x1) != nil 1635 && clobber(x0) 1636 && clobber(x1) 1637 && clobber(s0) 1638 && clobber(s1) 1639 && clobber(or) 1640 -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVHZloadidx [i0] {s} p idx mem)) y) 1641 1642 (OR 1643 s0:(SLDconst [j0] x0:(MOVHZloadidx [i0] {s} p idx mem)) 1644 or:(OR 1645 s1:(SLDconst [j1] x1:(MOVHZloadidx [i1] {s} p idx mem)) 1646 y)) 1647 && i1 == i0+2 1648 && j1 == j0-16 1649 && j1 % 32 == 0 1650 && x0.Uses == 1 1651 && x1.Uses == 1 1652 && s0.Uses == 1 1653 && s1.Uses == 1 1654 && or.Uses == 1 1655 && mergePoint(b,x0,x1) != nil 1656 && clobber(x0) 1657 && clobber(x1) 1658 && clobber(s0) 1659 && clobber(s1) 1660 && clobber(or) 1661 -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j1] (MOVWZloadidx [i0] {s} p idx mem)) y) 1662 1663 // Little-endian loads 1664 1665 (ORW x0:(MOVBZload [i0] {s} p mem) 1666 sh:(SLWconst [8] x1:(MOVBZload [i1] {s} p mem))) 1667 && p.Op != OpSB 1668 && i1 == i0+1 1669 && x0.Uses == 1 1670 && x1.Uses == 1 1671 && sh.Uses == 1 1672 && mergePoint(b,x0,x1) != nil 1673 && clobber(x0) 1674 && clobber(x1) 1675 && clobber(sh) 1676 -> @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRload [i0] {s} p mem)) 1677 1678 (OR x0:(MOVBZload [i0] {s} p mem) 1679 sh:(SLDconst [8] x1:(MOVBZload [i1] {s} p mem))) 1680 && p.Op != OpSB 1681 && i1 == i0+1 1682 && x0.Uses == 1 1683 && x1.Uses == 1 1684 && sh.Uses == 1 1685 && mergePoint(b,x0,x1) != nil 1686 && clobber(x0) 1687 && clobber(x1) 1688 && clobber(sh) 1689 -> @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRload [i0] {s} p mem)) 1690 1691 (ORW r0:(MOVHZreg x0:(MOVHBRload [i0] {s} p mem)) 1692 sh:(SLWconst [16] r1:(MOVHZreg x1:(MOVHBRload [i1] {s} p mem)))) 1693 && i1 == i0+2 1694 && x0.Uses == 1 1695 && x1.Uses == 1 1696 && r0.Uses == 1 1697 && r1.Uses == 1 1698 && sh.Uses == 1 1699 && mergePoint(b,x0,x1) != nil 1700 && clobber(x0) 1701 && clobber(x1) 1702 && clobber(r0) 1703 && clobber(r1) 1704 && clobber(sh) 1705 -> @mergePoint(b,x0,x1) (MOVWBRload [i0] {s} p mem) 1706 1707 (OR r0:(MOVHZreg x0:(MOVHBRload [i0] {s} p mem)) 1708 sh:(SLDconst [16] r1:(MOVHZreg x1:(MOVHBRload [i1] {s} p mem)))) 1709 && i1 == i0+2 1710 && x0.Uses == 1 1711 && x1.Uses == 1 1712 && r0.Uses == 1 1713 && r1.Uses == 1 1714 && sh.Uses == 1 1715 && mergePoint(b,x0,x1) != nil 1716 && clobber(x0) 1717 && clobber(x1) 1718 && clobber(r0) 1719 && clobber(r1) 1720 && clobber(sh) 1721 -> @mergePoint(b,x0,x1) (MOVWZreg (MOVWBRload [i0] {s} p mem)) 1722 1723 (OR r0:(MOVWZreg x0:(MOVWBRload [i0] {s} p mem)) 1724 sh:(SLDconst [32] r1:(MOVWZreg x1:(MOVWBRload [i1] {s} p mem)))) 1725 && i1 == i0+4 1726 && x0.Uses == 1 1727 && x1.Uses == 1 1728 && r0.Uses == 1 1729 && r1.Uses == 1 1730 && sh.Uses == 1 1731 && mergePoint(b,x0,x1) != nil 1732 && clobber(x0) 1733 && clobber(x1) 1734 && clobber(r0) 1735 && clobber(r1) 1736 && clobber(sh) 1737 -> @mergePoint(b,x0,x1) (MOVDBRload [i0] {s} p mem) 1738 1739 (ORW 1740 s1:(SLWconst [j1] x1:(MOVBZload [i1] {s} p mem)) 1741 or:(ORW 1742 s0:(SLWconst [j0] x0:(MOVBZload [i0] {s} p mem)) 1743 y)) 1744 && p.Op != OpSB 1745 && i1 == i0+1 1746 && j1 == j0+8 1747 && j0 % 16 == 0 1748 && x0.Uses == 1 1749 && x1.Uses == 1 1750 && s0.Uses == 1 1751 && s1.Uses == 1 1752 && or.Uses == 1 1753 && mergePoint(b,x0,x1) != nil 1754 && clobber(x0) 1755 && clobber(x1) 1756 && clobber(s0) 1757 && clobber(s1) 1758 && clobber(or) 1759 -> @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRload [i0] {s} p mem))) y) 1760 1761 (OR 1762 s1:(SLDconst [j1] x1:(MOVBZload [i1] {s} p mem)) 1763 or:(OR 1764 s0:(SLDconst [j0] x0:(MOVBZload [i0] {s} p mem)) 1765 y)) 1766 && p.Op != OpSB 1767 && i1 == i0+1 1768 && j1 == j0+8 1769 && j0 % 16 == 0 1770 && x0.Uses == 1 1771 && x1.Uses == 1 1772 && s0.Uses == 1 1773 && s1.Uses == 1 1774 && or.Uses == 1 1775 && mergePoint(b,x0,x1) != nil 1776 && clobber(x0) 1777 && clobber(x1) 1778 && clobber(s0) 1779 && clobber(s1) 1780 && clobber(or) 1781 -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRload [i0] {s} p mem))) y) 1782 1783 (OR 1784 s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRload [i1] {s} p mem))) 1785 or:(OR 1786 s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRload [i0] {s} p mem))) 1787 y)) 1788 && i1 == i0+2 1789 && j1 == j0+16 1790 && j0 % 32 == 0 1791 && x0.Uses == 1 1792 && x1.Uses == 1 1793 && r0.Uses == 1 1794 && r1.Uses == 1 1795 && s0.Uses == 1 1796 && s1.Uses == 1 1797 && or.Uses == 1 1798 && mergePoint(b,x0,x1) != nil 1799 && clobber(x0) 1800 && clobber(x1) 1801 && clobber(r0) 1802 && clobber(r1) 1803 && clobber(s0) 1804 && clobber(s1) 1805 && clobber(or) 1806 -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRload [i0] {s} p mem))) y) 1807 1808 // Little-endian indexed loads 1809 1810 (ORW x0:(MOVBZloadidx [i0] {s} p idx mem) 1811 sh:(SLWconst [8] x1:(MOVBZloadidx [i1] {s} p idx mem))) 1812 && p.Op != OpSB 1813 && i1 == i0+1 1814 && x0.Uses == 1 1815 && x1.Uses == 1 1816 && sh.Uses == 1 1817 && mergePoint(b,x0,x1) != nil 1818 && clobber(x0) 1819 && clobber(x1) 1820 && clobber(sh) 1821 -> @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem)) 1822 1823 (OR x0:(MOVBZloadidx [i0] {s} p idx mem) 1824 sh:(SLDconst [8] x1:(MOVBZloadidx [i1] {s} p idx mem))) 1825 && p.Op != OpSB 1826 && i1 == i0+1 1827 && x0.Uses == 1 1828 && x1.Uses == 1 1829 && sh.Uses == 1 1830 && mergePoint(b,x0,x1) != nil 1831 && clobber(x0) 1832 && clobber(x1) 1833 && clobber(sh) 1834 -> @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem)) 1835 1836 (ORW r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem)) 1837 sh:(SLWconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem)))) 1838 && i1 == i0+2 1839 && x0.Uses == 1 1840 && x1.Uses == 1 1841 && r0.Uses == 1 1842 && r1.Uses == 1 1843 && sh.Uses == 1 1844 && mergePoint(b,x0,x1) != nil 1845 && clobber(x0) 1846 && clobber(x1) 1847 && clobber(r0) 1848 && clobber(r1) 1849 && clobber(sh) 1850 -> @mergePoint(b,x0,x1) (MOVWBRloadidx [i0] {s} p idx mem) 1851 1852 (OR r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem)) 1853 sh:(SLDconst [16] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem)))) 1854 && i1 == i0+2 1855 && x0.Uses == 1 1856 && x1.Uses == 1 1857 && r0.Uses == 1 1858 && r1.Uses == 1 1859 && sh.Uses == 1 1860 && mergePoint(b,x0,x1) != nil 1861 && clobber(x0) 1862 && clobber(x1) 1863 && clobber(r0) 1864 && clobber(r1) 1865 && clobber(sh) 1866 -> @mergePoint(b,x0,x1) (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem)) 1867 1868 (OR r0:(MOVWZreg x0:(MOVWBRloadidx [i0] {s} p idx mem)) 1869 sh:(SLDconst [32] r1:(MOVWZreg x1:(MOVWBRloadidx [i1] {s} p idx mem)))) 1870 && i1 == i0+4 1871 && x0.Uses == 1 1872 && x1.Uses == 1 1873 && r0.Uses == 1 1874 && r1.Uses == 1 1875 && sh.Uses == 1 1876 && mergePoint(b,x0,x1) != nil 1877 && clobber(x0) 1878 && clobber(x1) 1879 && clobber(r0) 1880 && clobber(r1) 1881 && clobber(sh) 1882 -> @mergePoint(b,x0,x1) (MOVDBRloadidx [i0] {s} p idx mem) 1883 1884 (ORW 1885 s1:(SLWconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) 1886 or:(ORW 1887 s0:(SLWconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) 1888 y)) 1889 && p.Op != OpSB 1890 && i1 == i0+1 1891 && j1 == j0+8 1892 && j0 % 16 == 0 1893 && x0.Uses == 1 1894 && x1.Uses == 1 1895 && s0.Uses == 1 1896 && s1.Uses == 1 1897 && or.Uses == 1 1898 && mergePoint(b,x0,x1) != nil 1899 && clobber(x0) 1900 && clobber(x1) 1901 && clobber(s0) 1902 && clobber(s1) 1903 && clobber(or) 1904 -> @mergePoint(b,x0,x1) (ORW <v.Type> (SLWconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y) 1905 1906 (OR 1907 s1:(SLDconst [j1] x1:(MOVBZloadidx [i1] {s} p idx mem)) 1908 or:(OR 1909 s0:(SLDconst [j0] x0:(MOVBZloadidx [i0] {s} p idx mem)) 1910 y)) 1911 && p.Op != OpSB 1912 && i1 == i0+1 1913 && j1 == j0+8 1914 && j0 % 16 == 0 1915 && x0.Uses == 1 1916 && x1.Uses == 1 1917 && s0.Uses == 1 1918 && s1.Uses == 1 1919 && or.Uses == 1 1920 && mergePoint(b,x0,x1) != nil 1921 && clobber(x0) 1922 && clobber(x1) 1923 && clobber(s0) 1924 && clobber(s1) 1925 && clobber(or) 1926 -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVHZreg (MOVHBRloadidx [i0] {s} p idx mem))) y) 1927 1928 (OR 1929 s1:(SLDconst [j1] r1:(MOVHZreg x1:(MOVHBRloadidx [i1] {s} p idx mem))) 1930 or:(OR 1931 s0:(SLDconst [j0] r0:(MOVHZreg x0:(MOVHBRloadidx [i0] {s} p idx mem))) 1932 y)) 1933 && i1 == i0+2 1934 && j1 == j0+16 1935 && j0 % 32 == 0 1936 && x0.Uses == 1 1937 && x1.Uses == 1 1938 && r0.Uses == 1 1939 && r1.Uses == 1 1940 && s0.Uses == 1 1941 && s1.Uses == 1 1942 && or.Uses == 1 1943 && mergePoint(b,x0,x1) != nil 1944 && clobber(x0) 1945 && clobber(x1) 1946 && clobber(r0) 1947 && clobber(r1) 1948 && clobber(s0) 1949 && clobber(s1) 1950 && clobber(or) 1951 -> @mergePoint(b,x0,x1) (OR <v.Type> (SLDconst <v.Type> [j0] (MOVWZreg (MOVWBRloadidx [i0] {s} p idx mem))) y) 1952 1953 // Combine stores into store multiples. 1954 // 32-bit 1955 (MOVWstore [i] {s} p w1 x:(MOVWstore [i-4] {s} p w0 mem)) 1956 && p.Op != OpSB 1957 && x.Uses == 1 1958 && is20Bit(i-4) 1959 && clobber(x) 1960 -> (STM2 [i-4] {s} p w0 w1 mem) 1961 (MOVWstore [i] {s} p w2 x:(STM2 [i-8] {s} p w0 w1 mem)) 1962 && x.Uses == 1 1963 && is20Bit(i-8) 1964 && clobber(x) 1965 -> (STM3 [i-8] {s} p w0 w1 w2 mem) 1966 (MOVWstore [i] {s} p w3 x:(STM3 [i-12] {s} p w0 w1 w2 mem)) 1967 && x.Uses == 1 1968 && is20Bit(i-12) 1969 && clobber(x) 1970 -> (STM4 [i-12] {s} p w0 w1 w2 w3 mem) 1971 (STM2 [i] {s} p w2 w3 x:(STM2 [i-8] {s} p w0 w1 mem)) 1972 && x.Uses == 1 1973 && is20Bit(i-8) 1974 && clobber(x) 1975 -> (STM4 [i-8] {s} p w0 w1 w2 w3 mem) 1976 // 64-bit 1977 (MOVDstore [i] {s} p w1 x:(MOVDstore [i-8] {s} p w0 mem)) 1978 && p.Op != OpSB 1979 && x.Uses == 1 1980 && is20Bit(i-8) 1981 && clobber(x) 1982 -> (STMG2 [i-8] {s} p w0 w1 mem) 1983 (MOVDstore [i] {s} p w2 x:(STMG2 [i-16] {s} p w0 w1 mem)) 1984 && x.Uses == 1 1985 && is20Bit(i-16) 1986 && clobber(x) 1987 -> (STMG3 [i-16] {s} p w0 w1 w2 mem) 1988 (MOVDstore [i] {s} p w3 x:(STMG3 [i-24] {s} p w0 w1 w2 mem)) 1989 && x.Uses == 1 1990 && is20Bit(i-24) 1991 && clobber(x) 1992 -> (STMG4 [i-24] {s} p w0 w1 w2 w3 mem) 1993 (STMG2 [i] {s} p w2 w3 x:(STMG2 [i-16] {s} p w0 w1 mem)) 1994 && x.Uses == 1 1995 && is20Bit(i-16) 1996 && clobber(x) 1997 -> (STMG4 [i-16] {s} p w0 w1 w2 w3 mem) 1998 1999 // Convert 32-bit store multiples into 64-bit stores. 2000 (STM2 [i] {s} p (SRDconst [32] x) x mem) -> (MOVDstore [i] {s} p x mem)