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