github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/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 (Hmul16 x y) -> (SRDconst [16] (MULLW (MOVHreg x) (MOVHreg y))) 48 (Hmul16u x y) -> (SRDconst [16] (MULLW (MOVHZreg x) (MOVHZreg y))) 49 (Hmul8 x y) -> (SRDconst [8] (MULLW (MOVBreg x) (MOVBreg y))) 50 (Hmul8u x y) -> (SRDconst [8] (MULLW (MOVBZreg x) (MOVBZreg y))) 51 52 (Mod64 x y) -> (MODD x y) 53 (Mod64u x y) -> (MODDU x y) 54 // MODW/MODWU has a 64-bit dividend and a 32-bit divisor, 55 // so a sign/zero extension of the dividend is required. 56 (Mod32 x y) -> (MODW (MOVWreg x) y) 57 (Mod32u x y) -> (MODWU (MOVWZreg x) y) 58 (Mod16 x y) -> (MODW (MOVHreg x) (MOVHreg y)) 59 (Mod16u x y) -> (MODWU (MOVHZreg x) (MOVHZreg y)) 60 (Mod8 x y) -> (MODW (MOVBreg x) (MOVBreg y)) 61 (Mod8u x y) -> (MODWU (MOVBZreg x) (MOVBZreg y)) 62 63 (Avg64u <t> x y) -> (ADD (ADD <t> (SRDconst <t> x [1]) (SRDconst <t> y [1])) (ANDconst <t> (AND <t> x y) [1])) 64 65 (And64 x y) -> (AND x y) 66 (And32 x y) -> (ANDW x y) 67 (And16 x y) -> (ANDW x y) 68 (And8 x y) -> (ANDW x y) 69 70 (Or64 x y) -> (OR x y) 71 (Or32 x y) -> (ORW x y) 72 (Or16 x y) -> (ORW x y) 73 (Or8 x y) -> (ORW x y) 74 75 (Xor64 x y) -> (XOR x y) 76 (Xor32 x y) -> (XORW x y) 77 (Xor16 x y) -> (XORW x y) 78 (Xor8 x y) -> (XORW x y) 79 80 (Neg64 x) -> (NEG x) 81 (Neg32 x) -> (NEGW x) 82 (Neg16 x) -> (NEGW (MOVHreg x)) 83 (Neg8 x) -> (NEGW (MOVBreg x)) 84 (Neg32F x) -> (FNEGS x) 85 (Neg64F x) -> (FNEG x) 86 87 (Com64 x) -> (NOT x) 88 (Com32 x) -> (NOTW x) 89 (Com16 x) -> (NOTW x) 90 (Com8 x) -> (NOTW x) 91 (NOT x) && true -> (XOR (MOVDconst [-1]) x) 92 (NOTW x) && true -> (XORWconst [-1] x) 93 94 // Lowering boolean ops 95 (AndB x y) -> (ANDW x y) 96 (OrB x y) -> (ORW x y) 97 (Not x) -> (XORWconst [1] x) 98 99 // Lowering pointer arithmetic 100 (OffPtr [off] ptr:(SP)) -> (MOVDaddr [off] ptr) 101 (OffPtr [off] ptr) && is32Bit(off) -> (ADDconst [off] ptr) 102 (OffPtr [off] ptr) -> (ADD (MOVDconst [off]) ptr) 103 104 // Ctz(x) = 64 - findLeftmostOne((x-1)&^x) 105 (Ctz64 <t> x) -> (SUB (MOVDconst [64]) (FLOGR (AND <t> (SUBconst <t> [1] x) (NOT <t> x)))) 106 (Ctz32 <t> x) -> (SUB (MOVDconst [64]) (FLOGR (MOVWZreg (ANDW <t> (SUBWconst <t> [1] x) (NOTW <t> x))))) 107 108 (Bswap64 x) -> (MOVDBR x) 109 (Bswap32 x) -> (MOVWBR x) 110 111 (Sqrt x) -> (FSQRT x) 112 113 // Atomic loads. 114 (AtomicLoad32 ptr mem) -> (MOVWZatomicload ptr mem) 115 (AtomicLoad64 ptr mem) -> (MOVDatomicload ptr mem) 116 (AtomicLoadPtr ptr mem) -> (MOVDatomicload ptr mem) 117 118 // Atomic stores. 119 (AtomicStore32 ptr val mem) -> (MOVWatomicstore ptr val mem) 120 (AtomicStore64 ptr val mem) -> (MOVDatomicstore ptr val mem) 121 (AtomicStorePtrNoWB ptr val mem) -> (MOVDatomicstore ptr val mem) 122 123 // Atomic adds. 124 (AtomicAdd32 ptr val mem) -> (AddTupleFirst32 (LAA ptr val mem) val) 125 (AtomicAdd64 ptr val mem) -> (AddTupleFirst64 (LAAG ptr val mem) val) 126 (Select0 <t> (AddTupleFirst32 tuple val)) -> (ADDW val (Select0 <t> tuple)) 127 (Select1 (AddTupleFirst32 tuple _ )) -> (Select1 tuple) 128 (Select0 <t> (AddTupleFirst64 tuple val)) -> (ADD val (Select0 <t> tuple)) 129 (Select1 (AddTupleFirst64 tuple _ )) -> (Select1 tuple) 130 131 // Atomic exchanges. 132 (AtomicExchange32 ptr val mem) -> (LoweredAtomicExchange32 ptr val mem) 133 (AtomicExchange64 ptr val mem) -> (LoweredAtomicExchange64 ptr val mem) 134 135 // Atomic compare and swap. 136 (AtomicCompareAndSwap32 ptr old new_ mem) -> (LoweredAtomicCas32 ptr old new_ mem) 137 (AtomicCompareAndSwap64 ptr old new_ mem) -> (LoweredAtomicCas64 ptr old new_ mem) 138 139 // Lowering extension 140 // Note: we always extend to 64 bits even though some ops don't need that many result bits. 141 (SignExt8to16 x) -> (MOVBreg x) 142 (SignExt8to32 x) -> (MOVBreg x) 143 (SignExt8to64 x) -> (MOVBreg x) 144 (SignExt16to32 x) -> (MOVHreg x) 145 (SignExt16to64 x) -> (MOVHreg x) 146 (SignExt32to64 x) -> (MOVWreg x) 147 148 (ZeroExt8to16 x) -> (MOVBZreg x) 149 (ZeroExt8to32 x) -> (MOVBZreg x) 150 (ZeroExt8to64 x) -> (MOVBZreg x) 151 (ZeroExt16to32 x) -> (MOVHZreg x) 152 (ZeroExt16to64 x) -> (MOVHZreg x) 153 (ZeroExt32to64 x) -> (MOVWZreg x) 154 155 (Slicemask <t> x) -> (SRADconst (NEG <t> x) [63]) 156 157 // Lowering truncation 158 // Because we ignore high parts of registers, truncates are just copies. 159 (Trunc16to8 x) -> x 160 (Trunc32to8 x) -> x 161 (Trunc32to16 x) -> x 162 (Trunc64to8 x) -> x 163 (Trunc64to16 x) -> x 164 (Trunc64to32 x) -> x 165 166 // Lowering float <-> int 167 (Cvt32to32F x) -> (CEFBRA x) 168 (Cvt32to64F x) -> (CDFBRA x) 169 (Cvt64to32F x) -> (CEGBRA x) 170 (Cvt64to64F x) -> (CDGBRA x) 171 172 (Cvt32Fto32 x) -> (CFEBRA x) 173 (Cvt32Fto64 x) -> (CGEBRA x) 174 (Cvt64Fto32 x) -> (CFDBRA x) 175 (Cvt64Fto64 x) -> (CGDBRA x) 176 177 (Cvt32Fto64F x) -> (LDEBR x) 178 (Cvt64Fto32F x) -> (LEDBR x) 179 180 // Lowering shifts 181 // Unsigned shifts need to return 0 if shift amount is >= width of shifted value. 182 // result = (arg << shift) & (shift >= argbits ? 0 : 0xffffffffffffffff) 183 (Lsh64x64 <t> x y) -> (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPUconst y [63]))) 184 (Lsh64x32 <t> x y) -> (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPWUconst y [63]))) 185 (Lsh64x16 <t> x y) -> (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVHZreg y) [63]))) 186 (Lsh64x8 <t> x y) -> (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVBZreg y) [63]))) 187 188 (Lsh32x64 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31]))) 189 (Lsh32x32 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31]))) 190 (Lsh32x16 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31]))) 191 (Lsh32x8 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31]))) 192 193 (Lsh16x64 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31]))) 194 (Lsh16x32 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31]))) 195 (Lsh16x16 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31]))) 196 (Lsh16x8 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31]))) 197 198 (Lsh8x64 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31]))) 199 (Lsh8x32 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31]))) 200 (Lsh8x16 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31]))) 201 (Lsh8x8 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31]))) 202 203 (Rsh64Ux64 <t> x y) -> (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPUconst y [63]))) 204 (Rsh64Ux32 <t> x y) -> (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPWUconst y [63]))) 205 (Rsh64Ux16 <t> x y) -> (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVHZreg y) [63]))) 206 (Rsh64Ux8 <t> x y) -> (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVBZreg y) [63]))) 207 208 (Rsh32Ux64 <t> x y) -> (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31]))) 209 (Rsh32Ux32 <t> x y) -> (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31]))) 210 (Rsh32Ux16 <t> x y) -> (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31]))) 211 (Rsh32Ux8 <t> x y) -> (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31]))) 212 213 (Rsh16Ux64 <t> x y) -> (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPUconst y [15]))) 214 (Rsh16Ux32 <t> x y) -> (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPWUconst y [15]))) 215 (Rsh16Ux16 <t> x y) -> (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [15]))) 216 (Rsh16Ux8 <t> x y) -> (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [15]))) 217 218 (Rsh8Ux64 <t> x y) -> (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPUconst y [7]))) 219 (Rsh8Ux32 <t> x y) -> (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPWUconst y [7]))) 220 (Rsh8Ux16 <t> x y) -> (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [7]))) 221 (Rsh8Ux8 <t> x y) -> (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [7]))) 222 223 // Signed right shift needs to return 0/-1 if shift amount is >= width of shifted value. 224 // We implement this by setting the shift value to -1 (all ones) if the shift value is >= width. 225 (Rsh64x64 <t> x y) -> (SRAD <t> x (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [63]))))) 226 (Rsh64x32 <t> x y) -> (SRAD <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [63]))))) 227 (Rsh64x16 <t> x y) -> (SRAD <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [63]))))) 228 (Rsh64x8 <t> x y) -> (SRAD <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [63]))))) 229 230 (Rsh32x64 <t> x y) -> (SRAW <t> x (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [31]))))) 231 (Rsh32x32 <t> x y) -> (SRAW <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [31]))))) 232 (Rsh32x16 <t> x y) -> (SRAW <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [31]))))) 233 (Rsh32x8 <t> x y) -> (SRAW <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [31]))))) 234 235 (Rsh16x64 <t> x y) -> (SRAW <t> (MOVHreg x) (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [15]))))) 236 (Rsh16x32 <t> x y) -> (SRAW <t> (MOVHreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [15]))))) 237 (Rsh16x16 <t> x y) -> (SRAW <t> (MOVHreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [15]))))) 238 (Rsh16x8 <t> x y) -> (SRAW <t> (MOVHreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [15]))))) 239 240 (Rsh8x64 <t> x y) -> (SRAW <t> (MOVBreg x) (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [7]))))) 241 (Rsh8x32 <t> x y) -> (SRAW <t> (MOVBreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [7]))))) 242 (Rsh8x16 <t> x y) -> (SRAW <t> (MOVBreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [7]))))) 243 (Rsh8x8 <t> x y) -> (SRAW <t> (MOVBreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [7]))))) 244 245 // Lowering comparisons 246 (Less64 x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP x y)) 247 (Less32 x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPW x y)) 248 (Less16 x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y))) 249 (Less8 x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y))) 250 (Less64U x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU x y)) 251 (Less32U x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y)) 252 (Less16U x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y))) 253 (Less8U x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y))) 254 // Use SETG with reversed operands to dodge NaN case. 255 (Less64F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP y x)) 256 (Less32F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS y x)) 257 258 (Leq64 x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP x y)) 259 (Leq32 x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y)) 260 (Leq16 x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y))) 261 (Leq8 x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y))) 262 (Leq64U x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU x y)) 263 (Leq32U x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y)) 264 (Leq16U x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y))) 265 (Leq8U x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y))) 266 // Use SETGE with reversed operands to dodge NaN case. 267 (Leq64F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP y x)) 268 (Leq32F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS y x)) 269 270 (Greater64 x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP x y)) 271 (Greater32 x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPW x y)) 272 (Greater16 x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y))) 273 (Greater8 x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y))) 274 (Greater64U x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU x y)) 275 (Greater32U x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y)) 276 (Greater16U x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y))) 277 (Greater8U x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y))) 278 (Greater64F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP x y)) 279 (Greater32F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y)) 280 281 (Geq64 x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP x y)) 282 (Geq32 x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y)) 283 (Geq16 x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y))) 284 (Geq8 x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y))) 285 (Geq64U x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU x y)) 286 (Geq32U x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y)) 287 (Geq16U x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y))) 288 (Geq8U x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y))) 289 (Geq64F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP x y)) 290 (Geq32F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y)) 291 292 (Eq64 x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP x y)) 293 (Eq32 x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMPW x y)) 294 (Eq16 x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y))) 295 (Eq8 x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y))) 296 (EqB x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y))) 297 (EqPtr x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP x y)) 298 (Eq64F x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (FCMP x y)) 299 (Eq32F x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y)) 300 301 (Neq64 x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP x y)) 302 (Neq32 x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y)) 303 (Neq16 x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y))) 304 (Neq8 x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y))) 305 (NeqB x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y))) 306 (NeqPtr x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP x y)) 307 (Neq64F x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (FCMP x y)) 308 (Neq32F x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y)) 309 310 // Lowering loads 311 (Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVDload ptr mem) 312 (Load <t> ptr mem) && is32BitInt(t) && isSigned(t) -> (MOVWload ptr mem) 313 (Load <t> ptr mem) && is32BitInt(t) && !isSigned(t) -> (MOVWZload ptr mem) 314 (Load <t> ptr mem) && is16BitInt(t) && isSigned(t) -> (MOVHload ptr mem) 315 (Load <t> ptr mem) && is16BitInt(t) && !isSigned(t) -> (MOVHZload ptr mem) 316 (Load <t> ptr mem) && is8BitInt(t) && isSigned(t) -> (MOVBload ptr mem) 317 (Load <t> ptr mem) && (t.IsBoolean() || (is8BitInt(t) && !isSigned(t))) -> (MOVBZload ptr mem) 318 (Load <t> ptr mem) && is32BitFloat(t) -> (FMOVSload ptr mem) 319 (Load <t> ptr mem) && is64BitFloat(t) -> (FMOVDload ptr mem) 320 321 // Lowering stores 322 // These more-specific FP versions of Store pattern should come first. 323 (Store [8] ptr val mem) && is64BitFloat(val.Type) -> (FMOVDstore ptr val mem) 324 (Store [4] ptr val mem) && is32BitFloat(val.Type) -> (FMOVSstore ptr val mem) 325 326 (Store [8] ptr val mem) -> (MOVDstore ptr val mem) 327 (Store [4] ptr val mem) -> (MOVWstore ptr val mem) 328 (Store [2] ptr val mem) -> (MOVHstore ptr val mem) 329 (Store [1] ptr val mem) -> (MOVBstore ptr val mem) 330 331 // Lowering moves 332 333 // Load and store for small copies. 334 (Move [s] _ _ mem) && SizeAndAlign(s).Size() == 0 -> mem 335 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore dst (MOVBZload src mem) mem) 336 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 -> (MOVHstore dst (MOVHZload src mem) mem) 337 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 -> (MOVWstore dst (MOVWZload src mem) mem) 338 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 -> (MOVDstore dst (MOVDload src mem) mem) 339 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 16 -> 340 (MOVDstore [8] dst (MOVDload [8] src mem) 341 (MOVDstore dst (MOVDload src mem) mem)) 342 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 24 -> 343 (MOVDstore [16] dst (MOVDload [16] src mem) 344 (MOVDstore [8] dst (MOVDload [8] src mem) 345 (MOVDstore dst (MOVDload src mem) mem))) 346 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 3 -> 347 (MOVBstore [2] dst (MOVBZload [2] src mem) 348 (MOVHstore dst (MOVHZload src mem) mem)) 349 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 5 -> 350 (MOVBstore [4] dst (MOVBZload [4] src mem) 351 (MOVWstore dst (MOVWZload src mem) mem)) 352 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 6 -> 353 (MOVHstore [4] dst (MOVHZload [4] src mem) 354 (MOVWstore dst (MOVWZload src mem) mem)) 355 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 7 -> 356 (MOVBstore [6] dst (MOVBZload [6] src mem) 357 (MOVHstore [4] dst (MOVHZload [4] src mem) 358 (MOVWstore dst (MOVWZload src mem) mem))) 359 360 // MVC for other moves. Use up to 4 instructions (sizes up to 1024 bytes). 361 (Move [s] dst src mem) && SizeAndAlign(s).Size() > 0 && SizeAndAlign(s).Size() <= 256 -> 362 (MVC [makeValAndOff(SizeAndAlign(s).Size(), 0)] dst src mem) 363 (Move [s] dst src mem) && SizeAndAlign(s).Size() > 256 && SizeAndAlign(s).Size() <= 512 -> 364 (MVC [makeValAndOff(SizeAndAlign(s).Size()-256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem)) 365 (Move [s] dst src mem) && SizeAndAlign(s).Size() > 512 && SizeAndAlign(s).Size() <= 768 -> 366 (MVC [makeValAndOff(SizeAndAlign(s).Size()-512, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem))) 367 (Move [s] dst src mem) && SizeAndAlign(s).Size() > 768 && SizeAndAlign(s).Size() <= 1024 -> 368 (MVC [makeValAndOff(SizeAndAlign(s).Size()-768, 768)] dst src (MVC [makeValAndOff(256, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem)))) 369 370 // Move more than 1024 bytes using a loop. 371 (Move [s] dst src mem) && SizeAndAlign(s).Size() > 1024 -> 372 (LoweredMove [SizeAndAlign(s).Size()%256] dst src (ADDconst <src.Type> src [(SizeAndAlign(s).Size()/256)*256]) mem) 373 374 // Lowering Zero instructions 375 (Zero [s] _ mem) && SizeAndAlign(s).Size() == 0 -> mem 376 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstoreconst [0] destptr mem) 377 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 2 -> (MOVHstoreconst [0] destptr mem) 378 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 4 -> (MOVWstoreconst [0] destptr mem) 379 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 8 -> (MOVDstoreconst [0] destptr mem) 380 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 3 -> 381 (MOVBstoreconst [makeValAndOff(0,2)] destptr 382 (MOVHstoreconst [0] destptr mem)) 383 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 5 -> 384 (MOVBstoreconst [makeValAndOff(0,4)] destptr 385 (MOVWstoreconst [0] destptr mem)) 386 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 6 -> 387 (MOVHstoreconst [makeValAndOff(0,4)] destptr 388 (MOVWstoreconst [0] destptr mem)) 389 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 7 -> 390 (MOVWstoreconst [makeValAndOff(0,3)] destptr 391 (MOVWstoreconst [0] destptr mem)) 392 393 (Zero [s] destptr mem) && SizeAndAlign(s).Size() > 0 && SizeAndAlign(s).Size() <= 1024 -> 394 (CLEAR [makeValAndOff(SizeAndAlign(s).Size(), 0)] destptr mem) 395 396 // Move more than 1024 bytes using a loop. 397 (Zero [s] destptr mem) && SizeAndAlign(s).Size() > 1024 -> 398 (LoweredZero [SizeAndAlign(s).Size()%256] destptr (ADDconst <destptr.Type> destptr [(SizeAndAlign(s).Size()/256)*256]) mem) 399 400 // Lowering constants 401 (Const8 [val]) -> (MOVDconst [val]) 402 (Const16 [val]) -> (MOVDconst [val]) 403 (Const32 [val]) -> (MOVDconst [val]) 404 (Const64 [val]) -> (MOVDconst [val]) 405 (Const32F [val]) -> (FMOVSconst [val]) 406 (Const64F [val]) -> (FMOVDconst [val]) 407 (ConstNil) -> (MOVDconst [0]) 408 (ConstBool [b]) -> (MOVDconst [b]) 409 410 // Lowering calls 411 (StaticCall [argwid] {target} mem) -> (CALLstatic [argwid] {target} mem) 412 (ClosureCall [argwid] entry closure mem) -> (CALLclosure [argwid] entry closure mem) 413 (DeferCall [argwid] mem) -> (CALLdefer [argwid] mem) 414 (GoCall [argwid] mem) -> (CALLgo [argwid] 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 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) == CMPeq -> x 450 (MOVDnop <t> x) && t.Compare(x.Type) == 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 (ADD (MOVDconst [c]) x) && is32Bit(c) -> (ADDconst [c] x) 518 (ADDW x (MOVDconst [c])) -> (ADDWconst [c] x) 519 (ADDW (MOVDconst [c]) x) -> (ADDWconst [c] x) 520 521 (SUB x (MOVDconst [c])) && is32Bit(c) -> (SUBconst x [c]) 522 (SUB (MOVDconst [c]) x) && is32Bit(c) -> (NEG (SUBconst <v.Type> x [c])) 523 (SUBW x (MOVDconst [c])) -> (SUBWconst x [c]) 524 (SUBW (MOVDconst [c]) x) -> (NEGW (SUBWconst <v.Type> x [c])) 525 526 (MULLD x (MOVDconst [c])) && is32Bit(c) -> (MULLDconst [c] x) 527 (MULLD (MOVDconst [c]) x) && is32Bit(c) -> (MULLDconst [c] x) 528 (MULLW x (MOVDconst [c])) -> (MULLWconst [c] x) 529 (MULLW (MOVDconst [c]) x) -> (MULLWconst [c] x) 530 531 // NILF instructions leave the high 32 bits unchanged which is 532 // equivalent to the leftmost 32 bits being set. 533 // TODO(mundaym): modify the assembler to accept 64-bit values 534 // and use isU32Bit(^c). 535 (AND x (MOVDconst [c])) && is32Bit(c) && c < 0 -> (ANDconst [c] x) 536 (AND (MOVDconst [c]) x) && is32Bit(c) && c < 0 -> (ANDconst [c] x) 537 (ANDW x (MOVDconst [c])) -> (ANDWconst [c] x) 538 (ANDW (MOVDconst [c]) x) -> (ANDWconst [c] x) 539 540 (ANDWconst [c] (ANDWconst [d] x)) -> (ANDWconst [c & d] x) 541 (ANDconst [c] (ANDconst [d] x)) -> (ANDconst [c & d] x) 542 543 (OR x (MOVDconst [c])) && isU32Bit(c) -> (ORconst [c] x) 544 (OR (MOVDconst [c]) x) && isU32Bit(c) -> (ORconst [c] x) 545 (ORW x (MOVDconst [c])) -> (ORWconst [c] x) 546 (ORW (MOVDconst [c]) x) -> (ORWconst [c] x) 547 548 (XOR x (MOVDconst [c])) && isU32Bit(c) -> (XORconst [c] x) 549 (XOR (MOVDconst [c]) x) && isU32Bit(c) -> (XORconst [c] x) 550 (XORW x (MOVDconst [c])) -> (XORWconst [c] x) 551 (XORW (MOVDconst [c]) x) -> (XORWconst [c] x) 552 553 (SLD x (MOVDconst [c])) -> (SLDconst [c&63] x) 554 (SLW x (MOVDconst [c])) -> (SLWconst [c&63] x) 555 (SRD x (MOVDconst [c])) -> (SRDconst [c&63] x) 556 (SRW x (MOVDconst [c])) -> (SRWconst [c&63] x) 557 (SRAD x (MOVDconst [c])) -> (SRADconst [c&63] x) 558 (SRAW x (MOVDconst [c])) -> (SRAWconst [c&63] x) 559 560 (SRAW x (ANDWconst [63] y)) -> (SRAW x y) 561 (SRAD x (ANDconst [63] y)) -> (SRAD x y) 562 (SLW x (ANDWconst [63] y)) -> (SLW x y) 563 (SLD x (ANDconst [63] y)) -> (SLD x y) 564 (SRW x (ANDWconst [63] y)) -> (SRW x y) 565 (SRD x (ANDconst [63] y)) -> (SRD x y) 566 567 // Rotate generation 568 (ADD (SLDconst x [c]) (SRDconst x [64-c])) -> (RLLGconst [ c] x) 569 ( OR (SLDconst x [c]) (SRDconst x [64-c])) -> (RLLGconst [ c] x) 570 (XOR (SLDconst x [c]) (SRDconst x [64-c])) -> (RLLGconst [ c] x) 571 (ADD (SRDconst x [c]) (SLDconst x [64-c])) -> (RLLGconst [64-c] x) 572 ( OR (SRDconst x [c]) (SLDconst x [64-c])) -> (RLLGconst [64-c] x) 573 (XOR (SRDconst x [c]) (SLDconst x [64-c])) -> (RLLGconst [64-c] x) 574 575 (ADDW (SLWconst x [c]) (SRWconst x [32-c])) -> (RLLconst [ c] x) 576 ( ORW (SLWconst x [c]) (SRWconst x [32-c])) -> (RLLconst [ c] x) 577 (XORW (SLWconst x [c]) (SRWconst x [32-c])) -> (RLLconst [ c] x) 578 (ADDW (SRWconst x [c]) (SLWconst x [32-c])) -> (RLLconst [32-c] x) 579 ( ORW (SRWconst x [c]) (SLWconst x [32-c])) -> (RLLconst [32-c] x) 580 (XORW (SRWconst x [c]) (SLWconst x [32-c])) -> (RLLconst [32-c] x) 581 582 (CMP x (MOVDconst [c])) && is32Bit(c) -> (CMPconst x [c]) 583 (CMP (MOVDconst [c]) x) && is32Bit(c) -> (InvertFlags (CMPconst x [c])) 584 (CMPW x (MOVDconst [c])) -> (CMPWconst x [c]) 585 (CMPW (MOVDconst [c]) x) -> (InvertFlags (CMPWconst x [c])) 586 (CMPU x (MOVDconst [c])) && is32Bit(c) -> (CMPUconst x [int64(uint32(c))]) 587 (CMPU (MOVDconst [c]) x) && is32Bit(c) -> (InvertFlags (CMPUconst x [int64(uint32(c))])) 588 (CMPWU x (MOVDconst [c])) -> (CMPWUconst x [int64(uint32(c))]) 589 (CMPWU (MOVDconst [c]) x) -> (InvertFlags (CMPWUconst x [int64(uint32(c))])) 590 591 // Using MOV{W,H,B}Zreg instead of AND is cheaper. 592 (AND (MOVDconst [0xFF]) x) -> (MOVBZreg x) 593 (AND x (MOVDconst [0xFF])) -> (MOVBZreg x) 594 (AND (MOVDconst [0xFFFF]) x) -> (MOVHZreg x) 595 (AND x (MOVDconst [0xFFFF])) -> (MOVHZreg x) 596 (AND (MOVDconst [0xFFFFFFFF]) x) -> (MOVWZreg x) 597 (AND x (MOVDconst [0xFFFFFFFF])) -> (MOVWZreg x) 598 (ANDWconst [0xFF] x) -> (MOVBZreg x) 599 (ANDWconst [0xFFFF] x) -> (MOVHZreg x) 600 601 // strength reduction 602 (MULLDconst [-1] x) -> (NEG x) 603 (MULLDconst [0] _) -> (MOVDconst [0]) 604 (MULLDconst [1] x) -> x 605 (MULLDconst [c] x) && isPowerOfTwo(c) -> (SLDconst [log2(c)] x) 606 (MULLDconst [c] x) && isPowerOfTwo(c+1) && c >= 15 -> (SUB (SLDconst <v.Type> [log2(c+1)] x) x) 607 (MULLDconst [c] x) && isPowerOfTwo(c-1) && c >= 17 -> (ADD (SLDconst <v.Type> [log2(c-1)] x) x) 608 609 (MULLWconst [-1] x) -> (NEGW x) 610 (MULLWconst [0] _) -> (MOVDconst [0]) 611 (MULLWconst [1] x) -> x 612 (MULLWconst [c] x) && isPowerOfTwo(c) -> (SLWconst [log2(c)] x) 613 (MULLWconst [c] x) && isPowerOfTwo(c+1) && c >= 15 -> (SUBW (SLWconst <v.Type> [log2(c+1)] x) x) 614 (MULLWconst [c] x) && isPowerOfTwo(c-1) && c >= 17 -> (ADDW (SLWconst <v.Type> [log2(c-1)] x) x) 615 616 // Fold ADD into MOVDaddr. Odd offsets from SB shouldn't be folded (LARL can't handle them). 617 (ADDconst [c] (MOVDaddr [d] {s} x:(SB))) && ((c+d)&1 == 0) && is32Bit(c+d) -> (MOVDaddr [c+d] {s} x) 618 (ADDconst [c] (MOVDaddr [d] {s} x)) && x.Op != OpSB && is20Bit(c+d) -> (MOVDaddr [c+d] {s} x) 619 (ADD x (MOVDaddr [c] {s} y)) && x.Op != OpSB && y.Op != OpSB -> (MOVDaddridx [c] {s} x y) 620 (ADD (MOVDaddr [c] {s} x) y) && x.Op != OpSB && y.Op != OpSB -> (MOVDaddridx [c] {s} x y) 621 622 // fold ADDconst into MOVDaddrx 623 (ADDconst [c] (MOVDaddridx [d] {s} x y)) && is20Bit(c+d) -> (MOVDaddridx [c+d] {s} x y) 624 (MOVDaddridx [c] {s} (ADDconst [d] x) y) && is20Bit(c+d) && x.Op != OpSB -> (MOVDaddridx [c+d] {s} x y) 625 (MOVDaddridx [c] {s} x (ADDconst [d] y)) && is20Bit(c+d) && y.Op != OpSB -> (MOVDaddridx [c+d] {s} x y) 626 627 // reverse ordering of compare instruction 628 (MOVDLT x y (InvertFlags cmp)) -> (MOVDGT x y cmp) 629 (MOVDGT x y (InvertFlags cmp)) -> (MOVDLT x y cmp) 630 (MOVDLE x y (InvertFlags cmp)) -> (MOVDGE x y cmp) 631 (MOVDGE x y (InvertFlags cmp)) -> (MOVDLE x y cmp) 632 (MOVDEQ x y (InvertFlags cmp)) -> (MOVDEQ x y cmp) 633 (MOVDNE x y (InvertFlags cmp)) -> (MOVDNE x y cmp) 634 635 // don't extend after proper load 636 (MOVBreg x:(MOVBload _ _)) -> (MOVDreg x) 637 (MOVBZreg x:(MOVBZload _ _)) -> (MOVDreg x) 638 (MOVHreg x:(MOVBload _ _)) -> (MOVDreg x) 639 (MOVHreg x:(MOVBZload _ _)) -> (MOVDreg x) 640 (MOVHreg x:(MOVHload _ _)) -> (MOVDreg x) 641 (MOVHZreg x:(MOVBZload _ _)) -> (MOVDreg x) 642 (MOVHZreg x:(MOVHZload _ _)) -> (MOVDreg x) 643 (MOVWreg x:(MOVBload _ _)) -> (MOVDreg x) 644 (MOVWreg x:(MOVBZload _ _)) -> (MOVDreg x) 645 (MOVWreg x:(MOVHload _ _)) -> (MOVDreg x) 646 (MOVWreg x:(MOVHZload _ _)) -> (MOVDreg x) 647 (MOVWreg x:(MOVWload _ _)) -> (MOVDreg x) 648 (MOVWZreg x:(MOVBZload _ _)) -> (MOVDreg x) 649 (MOVWZreg x:(MOVHZload _ _)) -> (MOVDreg x) 650 (MOVWZreg x:(MOVWZload _ _)) -> (MOVDreg x) 651 652 // don't extend if argument is already extended 653 (MOVBreg x:(Arg <t>)) && is8BitInt(t) && isSigned(t) -> (MOVDreg x) 654 (MOVBZreg x:(Arg <t>)) && is8BitInt(t) && !isSigned(t) -> (MOVDreg x) 655 (MOVHreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && isSigned(t) -> (MOVDreg x) 656 (MOVHZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && !isSigned(t) -> (MOVDreg x) 657 (MOVWreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t) -> (MOVDreg x) 658 (MOVWZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t) -> (MOVDreg x) 659 660 // fold double extensions 661 (MOVBreg x:(MOVBreg _)) -> (MOVDreg x) 662 (MOVBZreg x:(MOVBZreg _)) -> (MOVDreg x) 663 (MOVHreg x:(MOVBreg _)) -> (MOVDreg x) 664 (MOVHreg x:(MOVBZreg _)) -> (MOVDreg x) 665 (MOVHreg x:(MOVHreg _)) -> (MOVDreg x) 666 (MOVHZreg x:(MOVBZreg _)) -> (MOVDreg x) 667 (MOVHZreg x:(MOVHZreg _)) -> (MOVDreg x) 668 (MOVWreg x:(MOVBreg _)) -> (MOVDreg x) 669 (MOVWreg x:(MOVBZreg _)) -> (MOVDreg x) 670 (MOVWreg x:(MOVHreg _)) -> (MOVDreg x) 671 (MOVWreg x:(MOVHreg _)) -> (MOVDreg x) 672 (MOVWreg x:(MOVWreg _)) -> (MOVDreg x) 673 (MOVWZreg x:(MOVBZreg _)) -> (MOVDreg x) 674 (MOVWZreg x:(MOVHZreg _)) -> (MOVDreg x) 675 (MOVWZreg x:(MOVWZreg _)) -> (MOVDreg x) 676 677 // fold extensions into constants 678 (MOVBreg (MOVDconst [c])) -> (MOVDconst [int64(int8(c))]) 679 (MOVBZreg (MOVDconst [c])) -> (MOVDconst [int64(uint8(c))]) 680 (MOVHreg (MOVDconst [c])) -> (MOVDconst [int64(int16(c))]) 681 (MOVHZreg (MOVDconst [c])) -> (MOVDconst [int64(uint16(c))]) 682 (MOVWreg (MOVDconst [c])) -> (MOVDconst [int64(int32(c))]) 683 (MOVWZreg (MOVDconst [c])) -> (MOVDconst [int64(uint32(c))]) 684 685 // sign extended loads 686 // Note: The combined instruction must end up in the same block 687 // as the original load. If not, we end up making a value with 688 // memory type live in two different blocks, which can lead to 689 // multiple memory values alive simultaneously. 690 // Make sure we don't combine these ops if the load has another use. 691 // This prevents a single load from being split into multiple loads 692 // which then might return different values. See test/atomicload.go. 693 (MOVBreg x:(MOVBZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload <v.Type> [off] {sym} ptr mem) 694 (MOVBZreg x:(MOVBZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZload <v.Type> [off] {sym} ptr mem) 695 (MOVHreg x:(MOVHZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHload <v.Type> [off] {sym} ptr mem) 696 (MOVHZreg x:(MOVHZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZload <v.Type> [off] {sym} ptr mem) 697 (MOVWreg x:(MOVWZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <v.Type> [off] {sym} ptr mem) 698 (MOVWZreg x:(MOVWZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZload <v.Type> [off] {sym} ptr mem) 699 700 (MOVBZreg x:(MOVBZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZloadidx <v.Type> [off] {sym} ptr idx mem) 701 (MOVHZreg x:(MOVHZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZloadidx <v.Type> [off] {sym} ptr idx mem) 702 (MOVWZreg x:(MOVWZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZloadidx <v.Type> [off] {sym} ptr idx mem) 703 704 // replace load from same location as preceding store with copy 705 (MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x) 706 (MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x) 707 (MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x) 708 (MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x) 709 710 // Don't extend before storing 711 (MOVWstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVWstore [off] {sym} ptr x mem) 712 (MOVHstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVHstore [off] {sym} ptr x mem) 713 (MOVBstore [off] {sym} ptr (MOVBreg x) mem) -> (MOVBstore [off] {sym} ptr x mem) 714 (MOVWstore [off] {sym} ptr (MOVWZreg x) mem) -> (MOVWstore [off] {sym} ptr x mem) 715 (MOVHstore [off] {sym} ptr (MOVHZreg x) mem) -> (MOVHstore [off] {sym} ptr x mem) 716 (MOVBstore [off] {sym} ptr (MOVBZreg x) mem) -> (MOVBstore [off] {sym} ptr x mem) 717 718 // Fold constants into memory operations. 719 // Note that this is not always a good idea because if not all the uses of 720 // the ADDconst get eliminated, we still have to compute the ADDconst and we now 721 // have potentially two live values (ptr and (ADDconst [off] ptr)) instead of one. 722 // Nevertheless, let's do it! 723 (MOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVDload [off1+off2] {sym} ptr mem) 724 (MOVWload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVWload [off1+off2] {sym} ptr mem) 725 (MOVHload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVHload [off1+off2] {sym} ptr mem) 726 (MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVBload [off1+off2] {sym} ptr mem) 727 (MOVWZload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVWZload [off1+off2] {sym} ptr mem) 728 (MOVHZload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVHZload [off1+off2] {sym} ptr mem) 729 (MOVBZload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVBZload [off1+off2] {sym} ptr mem) 730 (FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (FMOVSload [off1+off2] {sym} ptr mem) 731 (FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (FMOVDload [off1+off2] {sym} ptr mem) 732 733 (MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVDstore [off1+off2] {sym} ptr val mem) 734 (MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVWstore [off1+off2] {sym} ptr val mem) 735 (MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVHstore [off1+off2] {sym} ptr val mem) 736 (MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVBstore [off1+off2] {sym} ptr val mem) 737 (FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (FMOVSstore [off1+off2] {sym} ptr val mem) 738 (FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (FMOVDstore [off1+off2] {sym} ptr val mem) 739 740 // Fold constants into stores. 741 (MOVDstore [off] {sym} ptr (MOVDconst [c]) mem) && validValAndOff(c,off) && int64(int16(c)) == c && ptr.Op != OpSB -> 742 (MOVDstoreconst [makeValAndOff(c,off)] {sym} ptr mem) 743 (MOVWstore [off] {sym} ptr (MOVDconst [c]) mem) && validOff(off) && int64(int16(c)) == c && ptr.Op != OpSB -> 744 (MOVWstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem) 745 (MOVHstore [off] {sym} ptr (MOVDconst [c]) mem) && validOff(off) && ptr.Op != OpSB -> 746 (MOVHstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem) 747 (MOVBstore [off] {sym} ptr (MOVDconst [c]) mem) && validOff(off) && ptr.Op != OpSB -> 748 (MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem) 749 750 // Fold address offsets into constant stores. 751 (MOVDstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) -> 752 (MOVDstoreconst [ValAndOff(sc).add(off)] {s} ptr mem) 753 (MOVWstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) -> 754 (MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem) 755 (MOVHstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) -> 756 (MOVHstoreconst [ValAndOff(sc).add(off)] {s} ptr mem) 757 (MOVBstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) -> 758 (MOVBstoreconst [ValAndOff(sc).add(off)] {s} ptr mem) 759 760 // We need to fold MOVDaddr into the MOVx ops so that the live variable analysis knows 761 // what variables are being read/written by the ops. 762 (MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 763 (MOVDload [off1+off2] {mergeSym(sym1,sym2)} base mem) 764 (MOVWZload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 765 (MOVWZload [off1+off2] {mergeSym(sym1,sym2)} base mem) 766 (MOVHZload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 767 (MOVHZload [off1+off2] {mergeSym(sym1,sym2)} base mem) 768 (MOVBZload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 769 (MOVBZload [off1+off2] {mergeSym(sym1,sym2)} base mem) 770 (FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 771 (FMOVSload [off1+off2] {mergeSym(sym1,sym2)} base mem) 772 (FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 773 (FMOVDload [off1+off2] {mergeSym(sym1,sym2)} base mem) 774 775 (MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 776 (MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem) 777 (MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 778 (MOVHload [off1+off2] {mergeSym(sym1,sym2)} base mem) 779 (MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 780 (MOVWload [off1+off2] {mergeSym(sym1,sym2)} base mem) 781 782 (MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 783 (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) 784 (MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 785 (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) 786 (MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 787 (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) 788 (MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 789 (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) 790 (FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 791 (FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) 792 (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 793 (FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) 794 795 (MOVDstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) -> 796 (MOVDstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem) 797 (MOVWstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) -> 798 (MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem) 799 (MOVHstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) -> 800 (MOVHstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem) 801 (MOVBstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) -> 802 (MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem) 803 804 // generating indexed loads and stores 805 (MOVBZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 806 (MOVBZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) 807 (MOVHZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 808 (MOVHZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) 809 (MOVWZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 810 (MOVWZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) 811 (MOVDload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 812 (MOVDloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) 813 (FMOVSload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 814 (FMOVSloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) 815 (FMOVDload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 816 (FMOVDloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem) 817 818 (MOVBstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 819 (MOVBstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) 820 (MOVHstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 821 (MOVHstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) 822 (MOVWstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 823 (MOVWstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) 824 (MOVDstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 825 (MOVDstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) 826 (FMOVSstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 827 (FMOVSstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) 828 (FMOVDstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> 829 (FMOVDstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) 830 831 (MOVBZload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVBZloadidx [off] {sym} ptr idx mem) 832 (MOVHZload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVHZloadidx [off] {sym} ptr idx mem) 833 (MOVWZload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVWZloadidx [off] {sym} ptr idx mem) 834 (MOVDload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVDloadidx [off] {sym} ptr idx mem) 835 (FMOVSload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (FMOVSloadidx [off] {sym} ptr idx mem) 836 (FMOVDload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (FMOVDloadidx [off] {sym} ptr idx mem) 837 (MOVBstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVBstoreidx [off] {sym} ptr idx val mem) 838 (MOVHstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVHstoreidx [off] {sym} ptr idx val mem) 839 (MOVWstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVWstoreidx [off] {sym} ptr idx val mem) 840 (MOVDstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVDstoreidx [off] {sym} ptr idx val mem) 841 (FMOVSstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (FMOVSstoreidx [off] {sym} ptr idx val mem) 842 (FMOVDstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (FMOVDstoreidx [off] {sym} ptr idx val mem) 843 844 // combine ADD into indexed loads and stores 845 (MOVBZloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (MOVBZloadidx [c+d] {sym} ptr idx mem) 846 (MOVHZloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (MOVHZloadidx [c+d] {sym} ptr idx mem) 847 (MOVWZloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (MOVWZloadidx [c+d] {sym} ptr idx mem) 848 (MOVDloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (MOVDloadidx [c+d] {sym} ptr idx mem) 849 (FMOVSloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (FMOVSloadidx [c+d] {sym} ptr idx mem) 850 (FMOVDloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (FMOVDloadidx [c+d] {sym} ptr idx mem) 851 852 (MOVBstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (MOVBstoreidx [c+d] {sym} ptr idx val mem) 853 (MOVHstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (MOVHstoreidx [c+d] {sym} ptr idx val mem) 854 (MOVWstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (MOVWstoreidx [c+d] {sym} ptr idx val mem) 855 (MOVDstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (MOVDstoreidx [c+d] {sym} ptr idx val mem) 856 (FMOVSstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (FMOVSstoreidx [c+d] {sym} ptr idx val mem) 857 (FMOVDstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (FMOVDstoreidx [c+d] {sym} ptr idx val mem) 858 859 (MOVBZloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (MOVBZloadidx [c+d] {sym} ptr idx mem) 860 (MOVHZloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (MOVHZloadidx [c+d] {sym} ptr idx mem) 861 (MOVWZloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (MOVWZloadidx [c+d] {sym} ptr idx mem) 862 (MOVDloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (MOVDloadidx [c+d] {sym} ptr idx mem) 863 (FMOVSloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (FMOVSloadidx [c+d] {sym} ptr idx mem) 864 (FMOVDloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (FMOVDloadidx [c+d] {sym} ptr idx mem) 865 866 (MOVBstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (MOVBstoreidx [c+d] {sym} ptr idx val mem) 867 (MOVHstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (MOVHstoreidx [c+d] {sym} ptr idx val mem) 868 (MOVWstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (MOVWstoreidx [c+d] {sym} ptr idx val mem) 869 (MOVDstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (MOVDstoreidx [c+d] {sym} ptr idx val mem) 870 (FMOVSstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (FMOVSstoreidx [c+d] {sym} ptr idx val mem) 871 (FMOVDstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (FMOVDstoreidx [c+d] {sym} ptr idx val mem) 872 873 // MOVDaddr into MOVDaddridx 874 (MOVDaddridx [off1] {sym1} (MOVDaddr [off2] {sym2} x) y) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB -> 875 (MOVDaddridx [off1+off2] {mergeSym(sym1,sym2)} x y) 876 (MOVDaddridx [off1] {sym1} x (MOVDaddr [off2] {sym2} y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB -> 877 (MOVDaddridx [off1+off2] {mergeSym(sym1,sym2)} x y) 878 879 // Absorb InvertFlags into branches. 880 (LT (InvertFlags cmp) yes no) -> (GT cmp yes no) 881 (GT (InvertFlags cmp) yes no) -> (LT cmp yes no) 882 (LE (InvertFlags cmp) yes no) -> (GE cmp yes no) 883 (GE (InvertFlags cmp) yes no) -> (LE cmp yes no) 884 (EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no) 885 (NE (InvertFlags cmp) yes no) -> (NE cmp yes no) 886 887 // Constant comparisons. 888 (CMPconst (MOVDconst [x]) [y]) && x==y -> (FlagEQ) 889 (CMPconst (MOVDconst [x]) [y]) && x<y -> (FlagLT) 890 (CMPconst (MOVDconst [x]) [y]) && x>y -> (FlagGT) 891 (CMPUconst (MOVDconst [x]) [y]) && uint64(x)==uint64(y) -> (FlagEQ) 892 (CMPUconst (MOVDconst [x]) [y]) && uint64(x)<uint64(y) -> (FlagLT) 893 (CMPUconst (MOVDconst [x]) [y]) && uint64(x)>uint64(y) -> (FlagGT) 894 895 (CMPWconst (MOVDconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ) 896 (CMPWconst (MOVDconst [x]) [y]) && int32(x)<int32(y) -> (FlagLT) 897 (CMPWconst (MOVDconst [x]) [y]) && int32(x)>int32(y) -> (FlagGT) 898 (CMPWUconst (MOVDconst [x]) [y]) && uint32(x)==uint32(y) -> (FlagEQ) 899 (CMPWUconst (MOVDconst [x]) [y]) && uint32(x)<uint32(y) -> (FlagLT) 900 (CMPWUconst (MOVDconst [x]) [y]) && uint32(x)>uint32(y) -> (FlagGT) 901 902 // Other known comparisons. 903 (CMPconst (MOVBZreg _) [c]) && 0xFF < c -> (FlagLT) 904 (CMPconst (MOVHZreg _) [c]) && 0xFFFF < c -> (FlagLT) 905 (CMPconst (MOVWZreg _) [c]) && 0xFFFFFFFF < c -> (FlagLT) 906 (CMPWconst (SRWconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n) -> (FlagLT) 907 (CMPconst (SRDconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n) -> (FlagLT) 908 (CMPconst (ANDconst _ [m]) [n]) && 0 <= m && m < n -> (FlagLT) 909 (CMPWconst (ANDWconst _ [m]) [n]) && 0 <= int32(m) && int32(m) < int32(n) -> (FlagLT) 910 911 // Absorb flag constants into SBB ops. 912 (SUBEcarrymask (FlagEQ)) -> (MOVDconst [-1]) 913 (SUBEcarrymask (FlagLT)) -> (MOVDconst [-1]) 914 (SUBEcarrymask (FlagGT)) -> (MOVDconst [0]) 915 (SUBEWcarrymask (FlagEQ)) -> (MOVDconst [-1]) 916 (SUBEWcarrymask (FlagLT)) -> (MOVDconst [-1]) 917 (SUBEWcarrymask (FlagGT)) -> (MOVDconst [0]) 918 919 // Absorb flag constants into branches. 920 (EQ (FlagEQ) yes no) -> (First nil yes no) 921 (EQ (FlagLT) yes no) -> (First nil no yes) 922 (EQ (FlagGT) yes no) -> (First nil no yes) 923 924 (NE (FlagEQ) yes no) -> (First nil no yes) 925 (NE (FlagLT) yes no) -> (First nil yes no) 926 (NE (FlagGT) yes no) -> (First nil yes no) 927 928 (LT (FlagEQ) yes no) -> (First nil no yes) 929 (LT (FlagLT) yes no) -> (First nil yes no) 930 (LT (FlagGT) yes no) -> (First nil no yes) 931 932 (LE (FlagEQ) yes no) -> (First nil yes no) 933 (LE (FlagLT) yes no) -> (First nil yes no) 934 (LE (FlagGT) yes no) -> (First nil no yes) 935 936 (GT (FlagEQ) yes no) -> (First nil no yes) 937 (GT (FlagLT) yes no) -> (First nil no yes) 938 (GT (FlagGT) yes no) -> (First nil yes no) 939 940 (GE (FlagEQ) yes no) -> (First nil yes no) 941 (GE (FlagLT) yes no) -> (First nil no yes) 942 (GE (FlagGT) yes no) -> (First nil yes no) 943 944 // Absorb flag constants into SETxx ops. 945 (MOVDEQ _ x (FlagEQ)) -> x 946 (MOVDEQ y _ (FlagLT)) -> y 947 (MOVDEQ y _ (FlagGT)) -> y 948 949 (MOVDNE y _ (FlagEQ)) -> y 950 (MOVDNE _ x (FlagLT)) -> x 951 (MOVDNE _ x (FlagGT)) -> x 952 953 (MOVDLT y _ (FlagEQ)) -> y 954 (MOVDLT _ x (FlagLT)) -> x 955 (MOVDLT y _ (FlagGT)) -> y 956 957 (MOVDLE _ x (FlagEQ)) -> x 958 (MOVDLE _ x (FlagLT)) -> x 959 (MOVDLE y _ (FlagGT)) -> y 960 961 (MOVDGT y _ (FlagEQ)) -> y 962 (MOVDGT y _ (FlagLT)) -> y 963 (MOVDGT _ x (FlagGT)) -> x 964 965 (MOVDGE _ x (FlagEQ)) -> x 966 (MOVDGE y _ (FlagLT)) -> y 967 (MOVDGE _ x (FlagGT)) -> x 968 969 // Remove redundant *const ops 970 (ADDconst [0] x) -> x 971 (ADDWconst [c] x) && int32(c)==0 -> x 972 (SUBconst [0] x) -> x 973 (SUBWconst [c] x) && int32(c) == 0 -> x 974 (ANDconst [0] _) -> (MOVDconst [0]) 975 (ANDWconst [c] _) && int32(c)==0 -> (MOVDconst [0]) 976 (ANDconst [-1] x) -> x 977 (ANDWconst [c] x) && int32(c)==-1 -> x 978 (ORconst [0] x) -> x 979 (ORWconst [c] x) && int32(c)==0 -> x 980 (ORconst [-1] _) -> (MOVDconst [-1]) 981 (ORWconst [c] _) && int32(c)==-1 -> (MOVDconst [-1]) 982 (XORconst [0] x) -> x 983 (XORWconst [c] x) && int32(c)==0 -> x 984 985 // Convert constant subtracts to constant adds. 986 (SUBconst [c] x) && c != -(1<<31) -> (ADDconst [-c] x) 987 (SUBWconst [c] x) -> (ADDWconst [int64(int32(-c))] x) 988 989 // generic constant folding 990 // TODO: more of this 991 (ADDconst [c] (MOVDconst [d])) -> (MOVDconst [c+d]) 992 (ADDWconst [c] (MOVDconst [d])) -> (MOVDconst [int64(int32(c+d))]) 993 (ADDconst [c] (ADDconst [d] x)) && is32Bit(c+d) -> (ADDconst [c+d] x) 994 (ADDWconst [c] (ADDWconst [d] x)) -> (ADDWconst [int64(int32(c+d))] x) 995 (SUBconst (MOVDconst [d]) [c]) -> (MOVDconst [d-c]) 996 (SUBconst (SUBconst x [d]) [c]) && is32Bit(-c-d) -> (ADDconst [-c-d] x) 997 (SRADconst [c] (MOVDconst [d])) -> (MOVDconst [d>>uint64(c)]) 998 (SRAWconst [c] (MOVDconst [d])) -> (MOVDconst [d>>uint64(c)]) 999 (NEG (MOVDconst [c])) -> (MOVDconst [-c]) 1000 (NEGW (MOVDconst [c])) -> (MOVDconst [int64(int32(-c))]) 1001 (MULLDconst [c] (MOVDconst [d])) -> (MOVDconst [c*d]) 1002 (MULLWconst [c] (MOVDconst [d])) -> (MOVDconst [int64(int32(c*d))]) 1003 (AND (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c&d]) 1004 (ANDconst [c] (MOVDconst [d])) -> (MOVDconst [c&d]) 1005 (ANDWconst [c] (MOVDconst [d])) -> (MOVDconst [c&d]) 1006 (OR (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c|d]) 1007 (ORconst [c] (MOVDconst [d])) -> (MOVDconst [c|d]) 1008 (ORWconst [c] (MOVDconst [d])) -> (MOVDconst [c|d]) 1009 (XOR (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c^d]) 1010 (XORconst [c] (MOVDconst [d])) -> (MOVDconst [c^d]) 1011 (XORWconst [c] (MOVDconst [d])) -> (MOVDconst [c^d]) 1012 1013 // generic simplifications 1014 // TODO: more of this 1015 (ADD x (NEG y)) -> (SUB x y) 1016 (ADDW x (NEGW y)) -> (SUBW x y) 1017 (SUB x x) -> (MOVDconst [0]) 1018 (SUBW x x) -> (MOVDconst [0]) 1019 (AND x x) -> x 1020 (ANDW x x) -> x 1021 (OR x x) -> x 1022 (ORW x x) -> x 1023 (XOR x x) -> (MOVDconst [0]) 1024 (XORW x x) -> (MOVDconst [0]) 1025 1026 // Fold memory operations into operations. 1027 // Exclude global data (SB) because these instructions cannot handle relative addresses. 1028 // TODO(mundaym): use LARL in the assembler to handle SB? 1029 // TODO(mundaym): indexed versions of these? 1030 (ADD <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1031 -> (ADDload <t> [off] {sym} x ptr mem) 1032 (ADD <t> g:(MOVDload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1033 -> (ADDload <t> [off] {sym} x ptr mem) 1034 (ADDW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1035 -> (ADDWload <t> [off] {sym} x ptr mem) 1036 (ADDW <t> g:(MOVWload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1037 -> (ADDWload <t> [off] {sym} x ptr mem) 1038 (ADDW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1039 -> (ADDWload <t> [off] {sym} x ptr mem) 1040 (ADDW <t> g:(MOVWZload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1041 -> (ADDWload <t> [off] {sym} x ptr mem) 1042 (MULLD <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1043 -> (MULLDload <t> [off] {sym} x ptr mem) 1044 (MULLD <t> g:(MOVDload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1045 -> (MULLDload <t> [off] {sym} x ptr mem) 1046 (MULLW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1047 -> (MULLWload <t> [off] {sym} x ptr mem) 1048 (MULLW <t> g:(MOVWload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1049 -> (MULLWload <t> [off] {sym} x ptr mem) 1050 (MULLW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1051 -> (MULLWload <t> [off] {sym} x ptr mem) 1052 (MULLW <t> g:(MOVWZload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1053 -> (MULLWload <t> [off] {sym} x ptr mem) 1054 (SUB <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1055 -> (SUBload <t> [off] {sym} x ptr mem) 1056 (SUBW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1057 -> (SUBWload <t> [off] {sym} x ptr mem) 1058 (SUBW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1059 -> (SUBWload <t> [off] {sym} x ptr mem) 1060 (AND <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1061 -> (ANDload <t> [off] {sym} x ptr mem) 1062 (AND <t> g:(MOVDload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1063 -> (ANDload <t> [off] {sym} x ptr mem) 1064 (ANDW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1065 -> (ANDWload <t> [off] {sym} x ptr mem) 1066 (ANDW <t> g:(MOVWload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1067 -> (ANDWload <t> [off] {sym} x ptr mem) 1068 (ANDW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1069 -> (ANDWload <t> [off] {sym} x ptr mem) 1070 (ANDW <t> g:(MOVWZload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1071 -> (ANDWload <t> [off] {sym} x ptr mem) 1072 (OR <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1073 -> (ORload <t> [off] {sym} x ptr mem) 1074 (OR <t> g:(MOVDload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1075 -> (ORload <t> [off] {sym} x ptr mem) 1076 (ORW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1077 -> (ORWload <t> [off] {sym} x ptr mem) 1078 (ORW <t> g:(MOVWload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1079 -> (ORWload <t> [off] {sym} x ptr mem) 1080 (ORW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1081 -> (ORWload <t> [off] {sym} x ptr mem) 1082 (ORW <t> g:(MOVWZload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1083 -> (ORWload <t> [off] {sym} x ptr mem) 1084 (XOR <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1085 -> (XORload <t> [off] {sym} x ptr mem) 1086 (XOR <t> g:(MOVDload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1087 -> (XORload <t> [off] {sym} x ptr mem) 1088 (XORW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1089 -> (XORWload <t> [off] {sym} x ptr mem) 1090 (XORW <t> g:(MOVWload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1091 -> (XORWload <t> [off] {sym} x ptr mem) 1092 (XORW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1093 -> (XORWload <t> [off] {sym} x ptr mem) 1094 (XORW <t> g:(MOVWZload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g) 1095 -> (XORWload <t> [off] {sym} x ptr mem) 1096 1097 // Combine constant stores into larger (unaligned) stores. 1098 // It doesn't work to global data (based on SB), 1099 // because STGRL doesn't support unaligned address 1100 (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem)) 1101 && p.Op != OpSB 1102 && x.Uses == 1 1103 && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() 1104 && clobber(x) 1105 -> (MOVHstoreconst [makeValAndOff(ValAndOff(c).Val()&0xff | ValAndOff(a).Val()<<8, ValAndOff(a).Off())] {s} p mem) 1106 (MOVHstoreconst [c] {s} p x:(MOVHstoreconst [a] {s} p mem)) 1107 && p.Op != OpSB 1108 && x.Uses == 1 1109 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() 1110 && clobber(x) 1111 -> (MOVWstoreconst [makeValAndOff(ValAndOff(c).Val()&0xffff | ValAndOff(a).Val()<<16, ValAndOff(a).Off())] {s} p mem) 1112 (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem)) 1113 && p.Op != OpSB 1114 && x.Uses == 1 1115 && ValAndOff(a).Off() + 4 == ValAndOff(c).Off() 1116 && clobber(x) 1117 -> (MOVDstore [ValAndOff(a).Off()] {s} p (MOVDconst [ValAndOff(c).Val()&0xffffffff | ValAndOff(a).Val()<<32]) mem) 1118 1119 // Combine stores into larger (unaligned) stores. 1120 // It doesn't work on global data (based on SB) because stores with relative addressing 1121 // require that the memory operand be aligned. 1122 (MOVBstore [i] {s} p w x:(MOVBstore [i-1] {s} p (SRDconst [8] w) mem)) 1123 && p.Op != OpSB 1124 && x.Uses == 1 1125 && clobber(x) 1126 -> (MOVHstore [i-1] {s} p w mem) 1127 (MOVBstore [i] {s} p w0:(SRDconst [j] w) x:(MOVBstore [i-1] {s} p (SRDconst [j+8] w) mem)) 1128 && p.Op != OpSB 1129 && x.Uses == 1 1130 && clobber(x) 1131 -> (MOVHstore [i-1] {s} p w0 mem) 1132 (MOVBstore [i] {s} p w x:(MOVBstore [i-1] {s} p (SRWconst [8] w) mem)) 1133 && p.Op != OpSB 1134 && x.Uses == 1 1135 && clobber(x) 1136 -> (MOVHstore [i-1] {s} p w mem) 1137 (MOVBstore [i] {s} p w0:(SRWconst [j] w) x:(MOVBstore [i-1] {s} p (SRWconst [j+8] w) mem)) 1138 && p.Op != OpSB 1139 && x.Uses == 1 1140 && clobber(x) 1141 -> (MOVHstore [i-1] {s} p w0 mem) 1142 (MOVHstore [i] {s} p w x:(MOVHstore [i-2] {s} p (SRDconst [16] w) mem)) 1143 && p.Op != OpSB 1144 && x.Uses == 1 1145 && clobber(x) 1146 -> (MOVWstore [i-2] {s} p w mem) 1147 (MOVHstore [i] {s} p w0:(SRDconst [j] w) x:(MOVHstore [i-2] {s} p (SRDconst [j+16] w) mem)) 1148 && p.Op != OpSB 1149 && x.Uses == 1 1150 && clobber(x) 1151 -> (MOVWstore [i-2] {s} p w0 mem) 1152 (MOVHstore [i] {s} p w x:(MOVHstore [i-2] {s} p (SRWconst [16] w) mem)) 1153 && p.Op != OpSB 1154 && x.Uses == 1 1155 && clobber(x) 1156 -> (MOVWstore [i-2] {s} p w mem) 1157 (MOVHstore [i] {s} p w0:(SRWconst [j] w) x:(MOVHstore [i-2] {s} p (SRWconst [j+16] w) mem)) 1158 && p.Op != OpSB 1159 && x.Uses == 1 1160 && clobber(x) 1161 -> (MOVWstore [i-2] {s} p w0 mem) 1162 (MOVWstore [i] {s} p (SRDconst [32] w) x:(MOVWstore [i-4] {s} p w mem)) 1163 && p.Op != OpSB 1164 && x.Uses == 1 1165 && clobber(x) 1166 -> (MOVDstore [i-4] {s} p w mem) 1167 (MOVWstore [i] {s} p w0:(SRDconst [j] w) x:(MOVWstore [i-4] {s} p (SRDconst [j+32] w) mem)) 1168 && p.Op != OpSB 1169 && x.Uses == 1 1170 && clobber(x) 1171 -> (MOVDstore [i-4] {s} p w0 mem) 1172 1173 (MOVBstoreidx [i] {s} p idx w x:(MOVBstoreidx [i-1] {s} p idx (SRDconst [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:(SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx (SRDconst [j+8] w) mem)) 1178 && x.Uses == 1 1179 && clobber(x) 1180 -> (MOVHstoreidx [i-1] {s} p idx w0 mem) 1181 (MOVBstoreidx [i] {s} p idx w x:(MOVBstoreidx [i-1] {s} p idx (SRWconst [8] w) mem)) 1182 && x.Uses == 1 1183 && clobber(x) 1184 -> (MOVHstoreidx [i-1] {s} p idx w mem) 1185 (MOVBstoreidx [i] {s} p idx w0:(SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx (SRWconst [j+8] w) mem)) 1186 && x.Uses == 1 1187 && clobber(x) 1188 -> (MOVHstoreidx [i-1] {s} p idx w0 mem) 1189 (MOVHstoreidx [i] {s} p idx w x:(MOVHstoreidx [i-2] {s} p idx (SRDconst [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:(SRDconst [j] w) x:(MOVHstoreidx [i-2] {s} p idx (SRDconst [j+16] w) mem)) 1194 && x.Uses == 1 1195 && clobber(x) 1196 -> (MOVWstoreidx [i-2] {s} p idx w0 mem) 1197 (MOVHstoreidx [i] {s} p idx w x:(MOVHstoreidx [i-2] {s} p idx (SRWconst [16] w) mem)) 1198 && x.Uses == 1 1199 && clobber(x) 1200 -> (MOVWstoreidx [i-2] {s} p idx w mem) 1201 (MOVHstoreidx [i] {s} p idx w0:(SRWconst [j] w) x:(MOVHstoreidx [i-2] {s} p idx (SRWconst [j+16] w) mem)) 1202 && x.Uses == 1 1203 && clobber(x) 1204 -> (MOVWstoreidx [i-2] {s} p idx w0 mem) 1205 (MOVWstoreidx [i] {s} p idx w x:(MOVWstoreidx [i-4] {s} p idx (SRDconst [32] w) mem)) 1206 && x.Uses == 1 1207 && clobber(x) 1208 -> (MOVDstoreidx [i-4] {s} p idx w mem) 1209 (MOVWstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVWstoreidx [i-4] {s} p idx (SRDconst [j+32] w) mem)) 1210 && x.Uses == 1 1211 && clobber(x) 1212 -> (MOVDstoreidx [i-4] {s} p idx w0 mem) 1213 1214 // Combine stores into larger (unaligned) stores with the bytes reversed (little endian). 1215 // Store-with-bytes-reversed instructions do not support relative memory addresses, 1216 // so these stores can't operate on global data (SB). 1217 (MOVBstore [i] {s} p (SRDconst [8] w) x:(MOVBstore [i-1] {s} p w mem)) 1218 && p.Op != OpSB 1219 && x.Uses == 1 1220 && clobber(x) 1221 -> (MOVHBRstore [i-1] {s} p w mem) 1222 (MOVBstore [i] {s} p (SRDconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SRDconst [j-8] w) mem)) 1223 && p.Op != OpSB 1224 && x.Uses == 1 1225 && clobber(x) 1226 -> (MOVHBRstore [i-1] {s} p w0 mem) 1227 (MOVBstore [i] {s} p (SRWconst [8] w) x:(MOVBstore [i-1] {s} p w mem)) 1228 && p.Op != OpSB 1229 && x.Uses == 1 1230 && clobber(x) 1231 -> (MOVHBRstore [i-1] {s} p w mem) 1232 (MOVBstore [i] {s} p (SRWconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SRWconst [j-8] w) mem)) 1233 && p.Op != OpSB 1234 && x.Uses == 1 1235 && clobber(x) 1236 -> (MOVHBRstore [i-1] {s} p w0 mem) 1237 (MOVHBRstore [i] {s} p (SRDconst [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 (SRDconst [j] w) x:(MOVHBRstore [i-2] {s} p w0:(SRDconst [j-16] w) mem)) 1242 && x.Uses == 1 1243 && clobber(x) 1244 -> (MOVWBRstore [i-2] {s} p w0 mem) 1245 (MOVHBRstore [i] {s} p (SRWconst [16] w) x:(MOVHBRstore [i-2] {s} p w mem)) 1246 && x.Uses == 1 1247 && clobber(x) 1248 -> (MOVWBRstore [i-2] {s} p w mem) 1249 (MOVHBRstore [i] {s} p (SRWconst [j] w) x:(MOVHBRstore [i-2] {s} p w0:(SRWconst [j-16] w) mem)) 1250 && x.Uses == 1 1251 && clobber(x) 1252 -> (MOVWBRstore [i-2] {s} p w0 mem) 1253 (MOVWBRstore [i] {s} p (SRDconst [32] w) x:(MOVWBRstore [i-4] {s} p w mem)) 1254 && x.Uses == 1 1255 && clobber(x) 1256 -> (MOVDBRstore [i-4] {s} p w mem) 1257 (MOVWBRstore [i] {s} p (SRDconst [j] w) x:(MOVWBRstore [i-4] {s} p w0:(SRDconst [j-32] w) mem)) 1258 && x.Uses == 1 1259 && clobber(x) 1260 -> (MOVDBRstore [i-4] {s} p w0 mem) 1261 1262 (MOVBstoreidx [i] {s} p idx (SRDconst [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 (SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx w0:(SRDconst [j-8] w) mem)) 1267 && x.Uses == 1 1268 && clobber(x) 1269 -> (MOVHBRstoreidx [i-1] {s} p idx w0 mem) 1270 (MOVBstoreidx [i] {s} p idx (SRWconst [8] w) x:(MOVBstoreidx [i-1] {s} p idx w mem)) 1271 && x.Uses == 1 1272 && clobber(x) 1273 -> (MOVHBRstoreidx [i-1] {s} p idx w mem) 1274 (MOVBstoreidx [i] {s} p idx (SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx w0:(SRWconst [j-8] w) mem)) 1275 && x.Uses == 1 1276 && clobber(x) 1277 -> (MOVHBRstoreidx [i-1] {s} p idx w0 mem) 1278 (MOVHBRstoreidx [i] {s} p idx (SRDconst [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 (SRDconst [j] w) x:(MOVHBRstoreidx [i-2] {s} p idx w0:(SRDconst [j-16] w) mem)) 1283 && x.Uses == 1 1284 && clobber(x) 1285 -> (MOVWBRstoreidx [i-2] {s} p idx w0 mem) 1286 (MOVHBRstoreidx [i] {s} p idx (SRWconst [16] w) x:(MOVHBRstoreidx [i-2] {s} p idx w mem)) 1287 && x.Uses == 1 1288 && clobber(x) 1289 -> (MOVWBRstoreidx [i-2] {s} p idx w mem) 1290 (MOVHBRstoreidx [i] {s} p idx (SRWconst [j] w) x:(MOVHBRstoreidx [i-2] {s} p idx w0:(SRWconst [j-16] w) mem)) 1291 && x.Uses == 1 1292 && clobber(x) 1293 -> (MOVWBRstoreidx [i-2] {s} p idx w0 mem) 1294 (MOVWBRstoreidx [i] {s} p idx (SRDconst [32] w) x:(MOVWBRstoreidx [i-4] {s} p idx w mem)) 1295 && x.Uses == 1 1296 && clobber(x) 1297 -> (MOVDBRstoreidx [i-4] {s} p idx w mem) 1298 (MOVWBRstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVWBRstoreidx [i-4] {s} p idx w0:(SRDconst [j-32] w) mem)) 1299 && x.Uses == 1 1300 && clobber(x) 1301 -> (MOVDBRstoreidx [i-4] {s} p idx w0 mem) 1302 1303 // Move shifts to second argument of ORs. Helps load combining rules below. 1304 (ORW x:(SLWconst _) y) && y.Op != OpS390XSLWconst -> (ORW y x) 1305 (OR x:(SLDconst _) y) && y.Op != OpS390XSLDconst -> (OR y x) 1306 1307 // Combining byte loads into larger (unaligned) loads. 1308 1309 // Little endian loads. 1310 1311 // b[0] | b[1]<<8 -> load 16-bit, reverse bytes 1312 (ORW x0:(MOVBZload [i] {s} p mem) 1313 s0:(SLWconst [8] x1:(MOVBZload [i+1] {s} p mem))) 1314 && p.Op != OpSB 1315 && x0.Uses == 1 1316 && x1.Uses == 1 1317 && s0.Uses == 1 1318 && mergePoint(b,x0,x1) != nil 1319 && clobber(x0) 1320 && clobber(x1) 1321 && clobber(s0) 1322 -> @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRload [i] {s} p mem)) 1323 1324 // b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24 -> load 32-bit, reverse bytes 1325 (ORW o0:(ORW z0:(MOVHZreg x0:(MOVHBRload [i] {s} p mem)) 1326 s0:(SLWconst [16] x1:(MOVBZload [i+2] {s} p mem))) 1327 s1:(SLWconst [24] x2:(MOVBZload [i+3] {s} p mem))) 1328 && p.Op != OpSB 1329 && z0.Uses == 1 1330 && x0.Uses == 1 1331 && x1.Uses == 1 1332 && x2.Uses == 1 1333 && s0.Uses == 1 1334 && s1.Uses == 1 1335 && o0.Uses == 1 1336 && mergePoint(b,x0,x1,x2) != nil 1337 && clobber(z0) 1338 && clobber(x0) 1339 && clobber(x1) 1340 && clobber(x2) 1341 && clobber(s0) 1342 && clobber(s1) 1343 && clobber(o0) 1344 -> @mergePoint(b,x0,x1,x2) (MOVWBRload [i] {s} p mem) 1345 1346 // b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24 | b[4]<<32 | b[5]<<40 | b[6]<<48 | b[7]<<56 -> load 64-bit, reverse bytes 1347 (OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR 1348 x0:(MOVBZload [i] {s} p mem) 1349 s0:(SLDconst [8] x1:(MOVBZload [i+1] {s} p mem))) 1350 s1:(SLDconst [16] x2:(MOVBZload [i+2] {s} p mem))) 1351 s2:(SLDconst [24] x3:(MOVBZload [i+3] {s} p mem))) 1352 s3:(SLDconst [32] x4:(MOVBZload [i+4] {s} p mem))) 1353 s4:(SLDconst [40] x5:(MOVBZload [i+5] {s} p mem))) 1354 s5:(SLDconst [48] x6:(MOVBZload [i+6] {s} p mem))) 1355 s6:(SLDconst [56] x7:(MOVBZload [i+7] {s} p mem))) 1356 && p.Op != OpSB 1357 && x0.Uses == 1 1358 && x1.Uses == 1 1359 && x2.Uses == 1 1360 && x3.Uses == 1 1361 && x4.Uses == 1 1362 && x5.Uses == 1 1363 && x6.Uses == 1 1364 && x7.Uses == 1 1365 && s0.Uses == 1 1366 && s1.Uses == 1 1367 && s2.Uses == 1 1368 && s3.Uses == 1 1369 && s4.Uses == 1 1370 && s5.Uses == 1 1371 && s6.Uses == 1 1372 && o0.Uses == 1 1373 && o1.Uses == 1 1374 && o2.Uses == 1 1375 && o3.Uses == 1 1376 && o4.Uses == 1 1377 && o5.Uses == 1 1378 && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil 1379 && clobber(x0) 1380 && clobber(x1) 1381 && clobber(x2) 1382 && clobber(x3) 1383 && clobber(x4) 1384 && clobber(x5) 1385 && clobber(x6) 1386 && clobber(x7) 1387 && clobber(s0) 1388 && clobber(s1) 1389 && clobber(s2) 1390 && clobber(s3) 1391 && clobber(s4) 1392 && clobber(s5) 1393 && clobber(s6) 1394 && clobber(o0) 1395 && clobber(o1) 1396 && clobber(o2) 1397 && clobber(o3) 1398 && clobber(o4) 1399 && clobber(o5) 1400 -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVDBRload [i] {s} p mem) 1401 1402 // b[0] | b[1]<<8 -> load 16-bit, reverse bytes 1403 (ORW x0:(MOVBZloadidx [i] {s} p idx mem) 1404 s0:(SLWconst [8] x1:(MOVBZloadidx [i+1] {s} p idx mem))) 1405 && x0.Uses == 1 1406 && x1.Uses == 1 1407 && s0.Uses == 1 1408 && mergePoint(b,x0,x1) != nil 1409 && clobber(x0) 1410 && clobber(x1) 1411 && clobber(s0) 1412 -> @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx <v.Type> [i] {s} p idx mem)) 1413 1414 // b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24 -> load 32-bit, reverse bytes 1415 (ORW o0:(ORW z0:(MOVHZreg x0:(MOVHBRloadidx [i] {s} p idx mem)) 1416 s0:(SLWconst [16] x1:(MOVBZloadidx [i+2] {s} p idx mem))) 1417 s1:(SLWconst [24] x2:(MOVBZloadidx [i+3] {s} p idx mem))) 1418 && z0.Uses == 1 1419 && x0.Uses == 1 1420 && x1.Uses == 1 1421 && x2.Uses == 1 1422 && s0.Uses == 1 1423 && s1.Uses == 1 1424 && o0.Uses == 1 1425 && mergePoint(b,x0,x1,x2) != nil 1426 && clobber(z0) 1427 && clobber(x0) 1428 && clobber(x1) 1429 && clobber(x2) 1430 && clobber(s0) 1431 && clobber(s1) 1432 && clobber(o0) 1433 -> @mergePoint(b,x0,x1,x2) (MOVWZreg (MOVWBRloadidx <v.Type> [i] {s} p idx mem)) 1434 1435 // b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24 | b[4]<<32 | b[5]<<40 | b[6]<<48 | b[7]<<56 -> load 64-bit, reverse bytes 1436 (OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR 1437 x0:(MOVBZloadidx [i] {s} p idx mem) 1438 s0:(SLDconst [8] x1:(MOVBZloadidx [i+1] {s} p idx mem))) 1439 s1:(SLDconst [16] x2:(MOVBZloadidx [i+2] {s} p idx mem))) 1440 s2:(SLDconst [24] x3:(MOVBZloadidx [i+3] {s} p idx mem))) 1441 s3:(SLDconst [32] x4:(MOVBZloadidx [i+4] {s} p idx mem))) 1442 s4:(SLDconst [40] x5:(MOVBZloadidx [i+5] {s} p idx mem))) 1443 s5:(SLDconst [48] x6:(MOVBZloadidx [i+6] {s} p idx mem))) 1444 s6:(SLDconst [56] x7:(MOVBZloadidx [i+7] {s} p idx mem))) 1445 && x0.Uses == 1 1446 && x1.Uses == 1 1447 && x2.Uses == 1 1448 && x3.Uses == 1 1449 && x4.Uses == 1 1450 && x5.Uses == 1 1451 && x6.Uses == 1 1452 && x7.Uses == 1 1453 && s0.Uses == 1 1454 && s1.Uses == 1 1455 && s2.Uses == 1 1456 && s3.Uses == 1 1457 && s4.Uses == 1 1458 && s5.Uses == 1 1459 && s6.Uses == 1 1460 && o0.Uses == 1 1461 && o1.Uses == 1 1462 && o2.Uses == 1 1463 && o3.Uses == 1 1464 && o4.Uses == 1 1465 && o5.Uses == 1 1466 && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil 1467 && clobber(x0) 1468 && clobber(x1) 1469 && clobber(x2) 1470 && clobber(x3) 1471 && clobber(x4) 1472 && clobber(x5) 1473 && clobber(x6) 1474 && clobber(x7) 1475 && clobber(s0) 1476 && clobber(s1) 1477 && clobber(s2) 1478 && clobber(s3) 1479 && clobber(s4) 1480 && clobber(s5) 1481 && clobber(s6) 1482 && clobber(o0) 1483 && clobber(o1) 1484 && clobber(o2) 1485 && clobber(o3) 1486 && clobber(o4) 1487 && clobber(o5) 1488 -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVDBRloadidx <v.Type> [i] {s} p idx mem) 1489 1490 // Big endian loads. 1491 1492 // b[1] | b[0]<<8 -> load 16-bit 1493 (ORW x0:(MOVBZload [i] {s} p mem) 1494 s0:(SLWconst [8] x1:(MOVBZload [i-1] {s} p mem))) 1495 && p.Op != OpSB 1496 && x0.Uses == 1 1497 && x1.Uses == 1 1498 && s0.Uses == 1 1499 && mergePoint(b,x0,x1) != nil 1500 && clobber(x0) 1501 && clobber(x1) 1502 && clobber(s0) 1503 -> @mergePoint(b,x0,x1) (MOVHZload [i-1] {s} p mem) 1504 1505 // b[3] | b[2]<<8 | b[1]<<16 | b[0]<<24 -> load 32-bit 1506 (ORW o0:(ORW x0:(MOVHZload [i] {s} p mem) 1507 s0:(SLWconst [16] x1:(MOVBZload [i-1] {s} p mem))) 1508 s1:(SLWconst [24] x2:(MOVBZload [i-2] {s} p mem))) 1509 && p.Op != OpSB 1510 && x0.Uses == 1 1511 && x1.Uses == 1 1512 && x2.Uses == 1 1513 && s0.Uses == 1 1514 && s1.Uses == 1 1515 && o0.Uses == 1 1516 && mergePoint(b,x0,x1,x2) != nil 1517 && clobber(x0) 1518 && clobber(x1) 1519 && clobber(x2) 1520 && clobber(s0) 1521 && clobber(s1) 1522 && clobber(o0) 1523 -> @mergePoint(b,x0,x1,x2) (MOVWZload [i-2] {s} p mem) 1524 1525 // b[7] | b[6]<<8 | b[5]<<16 | b[4]<<24 | b[3]<<32 | b[2]<<40 | b[1]<<48 | b[0]<<56 -> load 64-bit 1526 (OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR 1527 x0:(MOVBZload [i] {s} p mem) 1528 s0:(SLDconst [8] x1:(MOVBZload [i-1] {s} p mem))) 1529 s1:(SLDconst [16] x2:(MOVBZload [i-2] {s} p mem))) 1530 s2:(SLDconst [24] x3:(MOVBZload [i-3] {s} p mem))) 1531 s3:(SLDconst [32] x4:(MOVBZload [i-4] {s} p mem))) 1532 s4:(SLDconst [40] x5:(MOVBZload [i-5] {s} p mem))) 1533 s5:(SLDconst [48] x6:(MOVBZload [i-6] {s} p mem))) 1534 s6:(SLDconst [56] x7:(MOVBZload [i-7] {s} p mem))) 1535 && p.Op != OpSB 1536 && x0.Uses == 1 1537 && x1.Uses == 1 1538 && x2.Uses == 1 1539 && x3.Uses == 1 1540 && x4.Uses == 1 1541 && x5.Uses == 1 1542 && x6.Uses == 1 1543 && x7.Uses == 1 1544 && s0.Uses == 1 1545 && s1.Uses == 1 1546 && s2.Uses == 1 1547 && s3.Uses == 1 1548 && s4.Uses == 1 1549 && s5.Uses == 1 1550 && s6.Uses == 1 1551 && o0.Uses == 1 1552 && o1.Uses == 1 1553 && o2.Uses == 1 1554 && o3.Uses == 1 1555 && o4.Uses == 1 1556 && o5.Uses == 1 1557 && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil 1558 && clobber(x0) 1559 && clobber(x1) 1560 && clobber(x2) 1561 && clobber(x3) 1562 && clobber(x4) 1563 && clobber(x5) 1564 && clobber(x6) 1565 && clobber(x7) 1566 && clobber(s0) 1567 && clobber(s1) 1568 && clobber(s2) 1569 && clobber(s3) 1570 && clobber(s4) 1571 && clobber(s5) 1572 && clobber(s6) 1573 && clobber(o0) 1574 && clobber(o1) 1575 && clobber(o2) 1576 && clobber(o3) 1577 && clobber(o4) 1578 && clobber(o5) 1579 -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVDload [i-7] {s} p mem) 1580 1581 // b[1] | b[0]<<8 -> load 16-bit 1582 (ORW x0:(MOVBZloadidx [i] {s} p idx mem) 1583 s0:(SLWconst [8] x1:(MOVBZloadidx [i-1] {s} p idx mem))) 1584 && x0.Uses == 1 1585 && x1.Uses == 1 1586 && s0.Uses == 1 1587 && mergePoint(b,x0,x1) != nil 1588 && clobber(x0) 1589 && clobber(x1) 1590 && clobber(s0) 1591 -> @mergePoint(b,x0,x1) (MOVHZloadidx <v.Type> [i-1] {s} p idx mem) 1592 1593 // b[3] | b[2]<<8 | b[1]<<16 | b[0]<<24 -> load 32-bit 1594 (ORW o0:(ORW x0:(MOVHZloadidx [i] {s} p idx mem) 1595 s0:(SLWconst [16] x1:(MOVBZloadidx [i-1] {s} p idx mem))) 1596 s1:(SLWconst [24] x2:(MOVBZloadidx [i-2] {s} p idx mem))) 1597 && x0.Uses == 1 1598 && x1.Uses == 1 1599 && x2.Uses == 1 1600 && s0.Uses == 1 1601 && s1.Uses == 1 1602 && o0.Uses == 1 1603 && mergePoint(b,x0,x1,x2) != nil 1604 && clobber(x0) 1605 && clobber(x1) 1606 && clobber(x2) 1607 && clobber(s0) 1608 && clobber(s1) 1609 && clobber(o0) 1610 -> @mergePoint(b,x0,x1,x2) (MOVWZloadidx <v.Type> [i-2] {s} p idx mem) 1611 1612 // b[7] | b[6]<<8 | b[5]<<16 | b[4]<<24 | b[3]<<32 | b[2]<<40 | b[1]<<48 | b[0]<<56 -> load 64-bit 1613 (OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR 1614 x0:(MOVBZloadidx [i] {s} p idx mem) 1615 s0:(SLDconst [8] x1:(MOVBZloadidx [i-1] {s} p idx mem))) 1616 s1:(SLDconst [16] x2:(MOVBZloadidx [i-2] {s} p idx mem))) 1617 s2:(SLDconst [24] x3:(MOVBZloadidx [i-3] {s} p idx mem))) 1618 s3:(SLDconst [32] x4:(MOVBZloadidx [i-4] {s} p idx mem))) 1619 s4:(SLDconst [40] x5:(MOVBZloadidx [i-5] {s} p idx mem))) 1620 s5:(SLDconst [48] x6:(MOVBZloadidx [i-6] {s} p idx mem))) 1621 s6:(SLDconst [56] x7:(MOVBZloadidx [i-7] {s} p idx mem))) 1622 && x0.Uses == 1 1623 && x1.Uses == 1 1624 && x2.Uses == 1 1625 && x3.Uses == 1 1626 && x4.Uses == 1 1627 && x5.Uses == 1 1628 && x6.Uses == 1 1629 && x7.Uses == 1 1630 && s0.Uses == 1 1631 && s1.Uses == 1 1632 && s2.Uses == 1 1633 && s3.Uses == 1 1634 && s4.Uses == 1 1635 && s5.Uses == 1 1636 && s6.Uses == 1 1637 && o0.Uses == 1 1638 && o1.Uses == 1 1639 && o2.Uses == 1 1640 && o3.Uses == 1 1641 && o4.Uses == 1 1642 && o5.Uses == 1 1643 && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil 1644 && clobber(x0) 1645 && clobber(x1) 1646 && clobber(x2) 1647 && clobber(x3) 1648 && clobber(x4) 1649 && clobber(x5) 1650 && clobber(x6) 1651 && clobber(x7) 1652 && clobber(s0) 1653 && clobber(s1) 1654 && clobber(s2) 1655 && clobber(s3) 1656 && clobber(s4) 1657 && clobber(s5) 1658 && clobber(s6) 1659 && clobber(o0) 1660 && clobber(o1) 1661 && clobber(o2) 1662 && clobber(o3) 1663 && clobber(o4) 1664 && clobber(o5) 1665 -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVDloadidx <v.Type> [i-7] {s} p idx mem) 1666 1667 // Combine stores into store multiples. 1668 // 32-bit 1669 (MOVWstore [i] {s} p w1 x:(MOVWstore [i-4] {s} p w0 mem)) 1670 && p.Op != OpSB 1671 && x.Uses == 1 1672 && is20Bit(i-4) 1673 && clobber(x) 1674 -> (STM2 [i-4] {s} p w0 w1 mem) 1675 (MOVWstore [i] {s} p w2 x:(STM2 [i-8] {s} p w0 w1 mem)) 1676 && x.Uses == 1 1677 && is20Bit(i-8) 1678 && clobber(x) 1679 -> (STM3 [i-8] {s} p w0 w1 w2 mem) 1680 (MOVWstore [i] {s} p w3 x:(STM3 [i-12] {s} p w0 w1 w2 mem)) 1681 && x.Uses == 1 1682 && is20Bit(i-12) 1683 && clobber(x) 1684 -> (STM4 [i-12] {s} p w0 w1 w2 w3 mem) 1685 (STM2 [i] {s} p w2 w3 x:(STM2 [i-8] {s} p w0 w1 mem)) 1686 && x.Uses == 1 1687 && is20Bit(i-8) 1688 && clobber(x) 1689 -> (STM4 [i-8] {s} p w0 w1 w2 w3 mem) 1690 // 64-bit 1691 (MOVDstore [i] {s} p w1 x:(MOVDstore [i-8] {s} p w0 mem)) 1692 && p.Op != OpSB 1693 && x.Uses == 1 1694 && is20Bit(i-8) 1695 && clobber(x) 1696 -> (STMG2 [i-8] {s} p w0 w1 mem) 1697 (MOVDstore [i] {s} p w2 x:(STMG2 [i-16] {s} p w0 w1 mem)) 1698 && x.Uses == 1 1699 && is20Bit(i-16) 1700 && clobber(x) 1701 -> (STMG3 [i-16] {s} p w0 w1 w2 mem) 1702 (MOVDstore [i] {s} p w3 x:(STMG3 [i-24] {s} p w0 w1 w2 mem)) 1703 && x.Uses == 1 1704 && is20Bit(i-24) 1705 && clobber(x) 1706 -> (STMG4 [i-24] {s} p w0 w1 w2 w3 mem) 1707 (STMG2 [i] {s} p w2 w3 x:(STMG2 [i-16] {s} p w0 w1 mem)) 1708 && x.Uses == 1 1709 && is20Bit(i-16) 1710 && clobber(x) 1711 -> (STMG4 [i-16] {s} p w0 w1 w2 w3 mem) 1712 1713 // Convert 32-bit store multiples into 64-bit stores. 1714 (STM2 [i] {s} p (SRDconst [32] x) x mem) -> (MOVDstore [i] {s} p x mem)