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