Home | History | Annotate | Download | only in gen
      1 // Copyright 2016 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // 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) -> (XOR (MOVDconst [-1]) (SRADconst <t> (SUBconst <t> x [1]) [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 (Lrot64 <t> x [c]) -> (RLLGconst <t> [c&63] x)
    204 (Lrot32 <t> x [c]) -> (RLLconst <t> [c&31] x)
    205 
    206 (Rsh64Ux64 <t> x y) -> (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPUconst y [63])))
    207 (Rsh64Ux32 <t> x y) -> (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPWUconst y [63])))
    208 (Rsh64Ux16 <t> x y) -> (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVHZreg y) [63])))
    209 (Rsh64Ux8  <t> x y) -> (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVBZreg y) [63])))
    210 
    211 (Rsh32Ux64 <t> x y) -> (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31])))
    212 (Rsh32Ux32 <t> x y) -> (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31])))
    213 (Rsh32Ux16 <t> x y) -> (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31])))
    214 (Rsh32Ux8  <t> x y) -> (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31])))
    215 
    216 (Rsh16Ux64 <t> x y) -> (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPUconst y [15])))
    217 (Rsh16Ux32 <t> x y) -> (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPWUconst y [15])))
    218 (Rsh16Ux16 <t> x y) -> (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [15])))
    219 (Rsh16Ux8  <t> x y) -> (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [15])))
    220 
    221 (Rsh8Ux64 <t> x y)  -> (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPUconst y [7])))
    222 (Rsh8Ux32 <t> x y)  -> (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPWUconst y [7])))
    223 (Rsh8Ux16 <t> x y)  -> (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [7])))
    224 (Rsh8Ux8  <t> x y)  -> (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [7])))
    225 
    226 // Signed right shift needs to return 0/-1 if shift amount is >= width of shifted value.
    227 // We implement this by setting the shift value to -1 (all ones) if the shift value is >= width.
    228 (Rsh64x64 <t> x y) -> (SRAD <t> x (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [63])))))
    229 (Rsh64x32 <t> x y) -> (SRAD <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [63])))))
    230 (Rsh64x16 <t> x y) -> (SRAD <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [63])))))
    231 (Rsh64x8  <t> x y) -> (SRAD <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [63])))))
    232 
    233 (Rsh32x64 <t> x y) -> (SRAW <t> x (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [31])))))
    234 (Rsh32x32 <t> x y) -> (SRAW <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [31])))))
    235 (Rsh32x16 <t> x y) -> (SRAW <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [31])))))
    236 (Rsh32x8  <t> x y) -> (SRAW <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [31])))))
    237 
    238 (Rsh16x64 <t> x y) -> (SRAW <t> (MOVHreg x) (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [15])))))
    239 (Rsh16x32 <t> x y) -> (SRAW <t> (MOVHreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [15])))))
    240 (Rsh16x16 <t> x y) -> (SRAW <t> (MOVHreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [15])))))
    241 (Rsh16x8  <t> x y) -> (SRAW <t> (MOVHreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [15])))))
    242 
    243 (Rsh8x64 <t> x y)  -> (SRAW <t> (MOVBreg x) (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [7])))))
    244 (Rsh8x32 <t> x y)  -> (SRAW <t> (MOVBreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [7])))))
    245 (Rsh8x16 <t> x y)  -> (SRAW <t> (MOVBreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [7])))))
    246 (Rsh8x8  <t> x y)  -> (SRAW <t> (MOVBreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [7])))))
    247 
    248 // Lowering comparisons
    249 (Less64  x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
    250 (Less32  x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
    251 (Less16  x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
    252 (Less8   x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
    253 (Less64U x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
    254 (Less32U x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
    255 (Less16U x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
    256 (Less8U  x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
    257 // Use SETG with reversed operands to dodge NaN case.
    258 (Less64F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP y x))
    259 (Less32F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS y x))
    260 
    261 (Leq64  x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
    262 (Leq32  x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
    263 (Leq16  x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
    264 (Leq8   x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
    265 (Leq64U x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
    266 (Leq32U x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
    267 (Leq16U x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
    268 (Leq8U  x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
    269 // Use SETGE with reversed operands to dodge NaN case.
    270 (Leq64F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP y x))
    271 (Leq32F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS y x))
    272 
    273 (Greater64  x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
    274 (Greater32  x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
    275 (Greater16  x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
    276 (Greater8   x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
    277 (Greater64U x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
    278 (Greater32U x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
    279 (Greater16U x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
    280 (Greater8U  x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
    281 (Greater64F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
    282 (Greater32F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
    283 
    284 (Geq64  x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
    285 (Geq32  x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
    286 (Geq16  x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
    287 (Geq8   x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
    288 (Geq64U x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
    289 (Geq32U x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
    290 (Geq16U x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
    291 (Geq8U  x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
    292 (Geq64F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
    293 (Geq32F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
    294 
    295 (Eq64  x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
    296 (Eq32  x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
    297 (Eq16  x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
    298 (Eq8   x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
    299 (EqB   x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
    300 (EqPtr x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
    301 (Eq64F x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
    302 (Eq32F x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
    303 
    304 (Neq64  x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
    305 (Neq32  x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
    306 (Neq16  x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
    307 (Neq8   x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
    308 (NeqB   x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
    309 (NeqPtr x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
    310 (Neq64F x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
    311 (Neq32F x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
    312 
    313 // Lowering loads
    314 (Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVDload ptr mem)
    315 (Load <t> ptr mem) && is32BitInt(t) && isSigned(t) -> (MOVWload ptr mem)
    316 (Load <t> ptr mem) && is32BitInt(t) && !isSigned(t) -> (MOVWZload ptr mem)
    317 (Load <t> ptr mem) && is16BitInt(t) && isSigned(t) -> (MOVHload ptr mem)
    318 (Load <t> ptr mem) && is16BitInt(t) && !isSigned(t) -> (MOVHZload ptr mem)
    319 (Load <t> ptr mem) && is8BitInt(t) && isSigned(t) -> (MOVBload ptr mem)
    320 (Load <t> ptr mem) && (t.IsBoolean() || (is8BitInt(t) && !isSigned(t))) -> (MOVBZload ptr mem)
    321 (Load <t> ptr mem) && is32BitFloat(t) -> (FMOVSload ptr mem)
    322 (Load <t> ptr mem) && is64BitFloat(t) -> (FMOVDload ptr mem)
    323 
    324 // Lowering stores
    325 // These more-specific FP versions of Store pattern should come first.
    326 (Store [8] ptr val mem) && is64BitFloat(val.Type) -> (FMOVDstore ptr val mem)
    327 (Store [4] ptr val mem) && is32BitFloat(val.Type) -> (FMOVSstore ptr val mem)
    328 
    329 (Store [8] ptr val mem) -> (MOVDstore ptr val mem)
    330 (Store [4] ptr val mem) -> (MOVWstore ptr val mem)
    331 (Store [2] ptr val mem) -> (MOVHstore ptr val mem)
    332 (Store [1] ptr val mem) -> (MOVBstore ptr val mem)
    333 
    334 // Lowering moves
    335 
    336 // Load and store for small copies.
    337 (Move [s] _ _ mem) && SizeAndAlign(s).Size() == 0 -> mem
    338 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore dst (MOVBZload src mem) mem)
    339 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 -> (MOVHstore dst (MOVHZload src mem) mem)
    340 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 -> (MOVWstore dst (MOVWZload src mem) mem)
    341 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 -> (MOVDstore dst (MOVDload src mem) mem)
    342 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 16 ->
    343 	(MOVDstore [8] dst (MOVDload [8] src mem)
    344 		(MOVDstore dst (MOVDload src mem) mem))
    345 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 24 ->
    346         (MOVDstore [16] dst (MOVDload [16] src mem)
    347 	        (MOVDstore [8] dst (MOVDload [8] src mem)
    348                 (MOVDstore dst (MOVDload src mem) mem)))
    349 (Move [s] dst src mem)  && SizeAndAlign(s).Size() == 3 ->
    350 	(MOVBstore [2] dst (MOVBZload [2] src mem)
    351 		(MOVHstore dst (MOVHZload src mem) mem))
    352 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 5 ->
    353 	(MOVBstore [4] dst (MOVBZload [4] src mem)
    354 		(MOVWstore dst (MOVWZload src mem) mem))
    355 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 6 ->
    356 	(MOVHstore [4] dst (MOVHZload [4] src mem)
    357 		(MOVWstore dst (MOVWZload src mem) mem))
    358 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 7 ->
    359 	(MOVBstore [6] dst (MOVBZload [6] src mem)
    360 		(MOVHstore [4] dst (MOVHZload [4] src mem)
    361 			(MOVWstore dst (MOVWZload src mem) mem)))
    362 
    363 // MVC for other moves. Use up to 4 instructions (sizes up to 1024 bytes).
    364 (Move [s] dst src mem) && SizeAndAlign(s).Size() > 0 && SizeAndAlign(s).Size() <= 256 ->
    365 	(MVC [makeValAndOff(SizeAndAlign(s).Size(), 0)] dst src mem)
    366 (Move [s] dst src mem) && SizeAndAlign(s).Size() > 256 && SizeAndAlign(s).Size() <= 512 ->
    367 	(MVC [makeValAndOff(SizeAndAlign(s).Size()-256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem))
    368 (Move [s] dst src mem) && SizeAndAlign(s).Size() > 512 && SizeAndAlign(s).Size() <= 768 ->
    369 	(MVC [makeValAndOff(SizeAndAlign(s).Size()-512, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem)))
    370 (Move [s] dst src mem) && SizeAndAlign(s).Size() > 768 && SizeAndAlign(s).Size() <= 1024 ->
    371 	(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))))
    372 
    373 // Move more than 1024 bytes using a loop.
    374 (Move [s] dst src mem) && SizeAndAlign(s).Size() > 1024 ->
    375 	(LoweredMove [SizeAndAlign(s).Size()%256] dst src (ADDconst <src.Type> src [(SizeAndAlign(s).Size()/256)*256]) mem)
    376 
    377 // Lowering Zero instructions
    378 (Zero [s] _ mem) && SizeAndAlign(s).Size() == 0 -> mem
    379 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstoreconst [0] destptr mem)
    380 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 2 -> (MOVHstoreconst [0] destptr mem)
    381 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 4 -> (MOVWstoreconst [0] destptr mem)
    382 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 8 -> (MOVDstoreconst [0] destptr mem)
    383 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 3 ->
    384 	(MOVBstoreconst [makeValAndOff(0,2)] destptr
    385 		(MOVHstoreconst [0] destptr mem))
    386 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 5 ->
    387 	(MOVBstoreconst [makeValAndOff(0,4)] destptr
    388 		(MOVWstoreconst [0] destptr mem))
    389 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 6 ->
    390 	(MOVHstoreconst [makeValAndOff(0,4)] destptr
    391 		(MOVWstoreconst [0] destptr mem))
    392 (Zero [s] destptr mem) && SizeAndAlign(s).Size() == 7 ->
    393 	(MOVWstoreconst [makeValAndOff(0,3)] destptr
    394 		(MOVWstoreconst [0] destptr mem))
    395 
    396 (Zero [s] destptr mem) && SizeAndAlign(s).Size() > 0 && SizeAndAlign(s).Size() <= 1024 ->
    397 	(CLEAR [makeValAndOff(SizeAndAlign(s).Size(), 0)] destptr mem)
    398 
    399 // Move more than 1024 bytes using a loop.
    400 (Zero [s] destptr mem) && SizeAndAlign(s).Size() > 1024 ->
    401 	(LoweredZero [SizeAndAlign(s).Size()%256] destptr (ADDconst <destptr.Type> destptr [(SizeAndAlign(s).Size()/256)*256]) mem)
    402 
    403 // Lowering constants
    404 (Const8   [val]) -> (MOVDconst [val])
    405 (Const16  [val]) -> (MOVDconst [val])
    406 (Const32  [val]) -> (MOVDconst [val])
    407 (Const64  [val]) -> (MOVDconst [val])
    408 (Const32F [val]) -> (FMOVSconst [val])
    409 (Const64F [val]) -> (FMOVDconst [val])
    410 (ConstNil) -> (MOVDconst [0])
    411 (ConstBool [b]) -> (MOVDconst [b])
    412 
    413 // Lowering calls
    414 (StaticCall [argwid] {target} mem) -> (CALLstatic [argwid] {target} mem)
    415 (ClosureCall [argwid] entry closure mem) -> (CALLclosure [argwid] entry closure mem)
    416 (DeferCall [argwid] mem) -> (CALLdefer [argwid] mem)
    417 (GoCall [argwid] mem) -> (CALLgo [argwid] mem)
    418 (InterCall [argwid] entry mem) -> (CALLinter [argwid] entry mem)
    419 
    420 // Miscellaneous
    421 (Convert <t> x mem) -> (MOVDconvert <t> x mem)
    422 (IsNonNil p) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMPconst p [0]))
    423 (IsInBounds idx len) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU idx len))
    424 (IsSliceInBounds idx len) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU idx len))
    425 (NilCheck ptr mem) -> (LoweredNilCheck ptr mem)
    426 (GetG mem) -> (LoweredGetG mem)
    427 (GetClosurePtr) -> (LoweredGetClosurePtr)
    428 (Addr {sym} base) -> (MOVDaddr {sym} base)
    429 (ITab (Load ptr mem)) -> (MOVDload ptr mem)
    430 
    431 // block rewrites
    432 (If (MOVDLT (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (LT cmp yes no)
    433 (If (MOVDLE (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (LE cmp yes no)
    434 (If (MOVDGT (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (GT cmp yes no)
    435 (If (MOVDGE (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (GE cmp yes no)
    436 (If (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (EQ cmp yes no)
    437 (If (MOVDNE (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (NE cmp yes no)
    438 
    439 // Special case for floating point - LF/LEF not generated.
    440 (If (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (GTF cmp yes no)
    441 (If (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (GEF cmp yes no)
    442 
    443 (If cond yes no) -> (NE (CMPWconst [0] (MOVBZreg cond)) yes no)
    444 
    445 // ***************************
    446 // Above: lowering rules
    447 // Below: optimizations
    448 // ***************************
    449 // TODO: Should the optimizations be a separate pass?
    450 
    451 // if a register move has only 1 use, just use the same register without emitting instruction
    452 // MOVDnop doesn't emit instruction, only for ensuring the type.
    453 (MOVDreg x) && x.Uses == 1 -> (MOVDnop x)
    454 
    455 // Fold sign extensions into conditional moves of constants.
    456 // Designed to remove the MOVBZreg inserted by the If lowering.
    457 (MOVBZreg x:(MOVDLT (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
    458 (MOVBZreg x:(MOVDLE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
    459 (MOVBZreg x:(MOVDGT (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
    460 (MOVBZreg x:(MOVDGE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
    461 (MOVBZreg x:(MOVDEQ (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
    462 (MOVBZreg x:(MOVDNE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
    463 (MOVBZreg x:(MOVDGTnoinv (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
    464 (MOVBZreg x:(MOVDGEnoinv (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
    465 
    466 // Fold boolean tests into blocks.
    467 (NE (CMPWconst [0] (MOVDLT (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (LT cmp yes no)
    468 (NE (CMPWconst [0] (MOVDLE (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (LE cmp yes no)
    469 (NE (CMPWconst [0] (MOVDGT (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (GT cmp yes no)
    470 (NE (CMPWconst [0] (MOVDGE (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (GE cmp yes no)
    471 (NE (CMPWconst [0] (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (EQ cmp yes no)
    472 (NE (CMPWconst [0] (MOVDNE (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (NE cmp yes no)
    473 (NE (CMPWconst [0] (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (GTF cmp yes no)
    474 (NE (CMPWconst [0] (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (GEF cmp yes no)
    475 
    476 // Fold constants into instructions.
    477 (ADD x (MOVDconst [c])) && is32Bit(c) -> (ADDconst [c] x)
    478 (ADD (MOVDconst [c]) x) && is32Bit(c) -> (ADDconst [c] x)
    479 (ADDW x (MOVDconst [c])) -> (ADDWconst [c] x)
    480 (ADDW (MOVDconst [c]) x) -> (ADDWconst [c] x)
    481 
    482 (SUB x (MOVDconst [c])) && is32Bit(c) -> (SUBconst x [c])
    483 (SUB (MOVDconst [c]) x) && is32Bit(c) -> (NEG (SUBconst <v.Type> x [c]))
    484 (SUBW x (MOVDconst [c])) -> (SUBWconst x [c])
    485 (SUBW (MOVDconst [c]) x) -> (NEGW (SUBWconst <v.Type> x [c]))
    486 
    487 (MULLD x (MOVDconst [c])) && is32Bit(c) -> (MULLDconst [c] x)
    488 (MULLD (MOVDconst [c]) x) && is32Bit(c) -> (MULLDconst [c] x)
    489 (MULLW x (MOVDconst [c])) -> (MULLWconst [c] x)
    490 (MULLW (MOVDconst [c]) x) -> (MULLWconst [c] x)
    491 
    492 // NILF instructions leave the high 32 bits unchanged which is
    493 // equivalent to the leftmost 32 bits being set.
    494 // TODO(mundaym): modify the assembler to accept 64-bit values
    495 // and use isU32Bit(^c).
    496 (AND x (MOVDconst [c])) && is32Bit(c) && c < 0 -> (ANDconst [c] x)
    497 (AND (MOVDconst [c]) x) && is32Bit(c) && c < 0 -> (ANDconst [c] x)
    498 (ANDW x (MOVDconst [c])) -> (ANDWconst [c] x)
    499 (ANDW (MOVDconst [c]) x) -> (ANDWconst [c] x)
    500 
    501 (ANDWconst [c] (ANDWconst [d] x)) -> (ANDWconst [c & d] x)
    502 (ANDconst [c] (ANDconst [d] x)) -> (ANDconst [c & d] x)
    503 
    504 (OR x (MOVDconst [c])) && isU32Bit(c) -> (ORconst [c] x)
    505 (OR (MOVDconst [c]) x) && isU32Bit(c) -> (ORconst [c] x)
    506 (ORW x (MOVDconst [c])) -> (ORWconst [c] x)
    507 (ORW (MOVDconst [c]) x) -> (ORWconst [c] x)
    508 
    509 (XOR x (MOVDconst [c])) && isU32Bit(c) -> (XORconst [c] x)
    510 (XOR (MOVDconst [c]) x) && isU32Bit(c) -> (XORconst [c] x)
    511 (XORW x (MOVDconst [c])) -> (XORWconst [c] x)
    512 (XORW (MOVDconst [c]) x) -> (XORWconst [c] x)
    513 
    514 (SLD x (MOVDconst [c])) -> (SLDconst [c&63] x)
    515 (SLW x (MOVDconst [c])) -> (SLWconst [c&63] x)
    516 (SRD x (MOVDconst [c])) -> (SRDconst [c&63] x)
    517 (SRW x (MOVDconst [c])) -> (SRWconst [c&63] x)
    518 (SRAD x (MOVDconst [c])) -> (SRADconst [c&63] x)
    519 (SRAW x (MOVDconst [c])) -> (SRAWconst [c&63] x)
    520 
    521 (SRAW x (ANDWconst [63] y)) -> (SRAW x y)
    522 (SRAD x (ANDconst [63] y)) -> (SRAD x y)
    523 (SLW x (ANDWconst [63] y)) -> (SLW x y)
    524 (SLD x (ANDconst [63] y)) -> (SLD x y)
    525 (SRW x (ANDWconst [63] y)) -> (SRW x y)
    526 (SRD x (ANDconst [63] y)) -> (SRD x y)
    527 
    528 (CMP x (MOVDconst [c])) && is32Bit(c) -> (CMPconst x [c])
    529 (CMP (MOVDconst [c]) x) && is32Bit(c) -> (InvertFlags (CMPconst x [c]))
    530 (CMPW x (MOVDconst [c])) -> (CMPWconst x [c])
    531 (CMPW (MOVDconst [c]) x) -> (InvertFlags (CMPWconst x [c]))
    532 (CMPU x (MOVDconst [c])) && is32Bit(c) -> (CMPUconst x [int64(uint32(c))])
    533 (CMPU (MOVDconst [c]) x) && is32Bit(c) -> (InvertFlags (CMPUconst x [int64(uint32(c))]))
    534 (CMPWU x (MOVDconst [c])) -> (CMPWUconst x [int64(uint32(c))])
    535 (CMPWU (MOVDconst [c]) x) -> (InvertFlags (CMPWUconst x [int64(uint32(c))]))
    536 
    537 // Using MOV{W,H,B}Zreg instead of AND is cheaper.
    538 (AND (MOVDconst [0xFF]) x) -> (MOVBZreg x)
    539 (AND x (MOVDconst [0xFF])) -> (MOVBZreg x)
    540 (AND (MOVDconst [0xFFFF]) x) -> (MOVHZreg x)
    541 (AND x (MOVDconst [0xFFFF])) -> (MOVHZreg x)
    542 (AND (MOVDconst [0xFFFFFFFF]) x) -> (MOVWZreg x)
    543 (AND x (MOVDconst [0xFFFFFFFF])) -> (MOVWZreg x)
    544 (ANDWconst [0xFF] x) -> (MOVBZreg x)
    545 (ANDWconst [0xFFFF] x) -> (MOVHZreg x)
    546 
    547 // strength reduction
    548 (MULLDconst [-1] x) -> (NEG x)
    549 (MULLDconst [0] _) -> (MOVDconst [0])
    550 (MULLDconst [1] x) -> x
    551 (MULLDconst [c] x) && isPowerOfTwo(c) -> (SLDconst [log2(c)] x)
    552 (MULLDconst [c] x) && isPowerOfTwo(c+1) && c >= 15 -> (SUB (SLDconst <v.Type> [log2(c+1)] x) x)
    553 (MULLDconst [c] x) && isPowerOfTwo(c-1) && c >= 17 -> (ADD (SLDconst <v.Type> [log2(c-1)] x) x)
    554 
    555 (MULLWconst [-1] x) -> (NEGW x)
    556 (MULLWconst [0] _) -> (MOVDconst [0])
    557 (MULLWconst [1] x) -> x
    558 (MULLWconst [c] x) && isPowerOfTwo(c) -> (SLWconst [log2(c)] x)
    559 (MULLWconst [c] x) && isPowerOfTwo(c+1) && c >= 15 -> (SUBW (SLWconst <v.Type> [log2(c+1)] x) x)
    560 (MULLWconst [c] x) && isPowerOfTwo(c-1) && c >= 17 -> (ADDW (SLWconst <v.Type> [log2(c-1)] x) x)
    561 
    562 // Fold ADD into MOVDaddr. Odd offsets from SB shouldn't be folded (LARL can't handle them).
    563 (ADDconst [c] (MOVDaddr [d] {s} x:(SB))) && ((c+d)&1 == 0) && is32Bit(c+d) -> (MOVDaddr [c+d] {s} x)
    564 (ADDconst [c] (MOVDaddr [d] {s} x)) && x.Op != OpSB && is20Bit(c+d) -> (MOVDaddr [c+d] {s} x)
    565 (ADD x (MOVDaddr [c] {s} y)) && x.Op != OpSB && y.Op != OpSB -> (MOVDaddridx [c] {s} x y)
    566 (ADD (MOVDaddr [c] {s} x) y) && x.Op != OpSB && y.Op != OpSB -> (MOVDaddridx [c] {s} x y)
    567 
    568 // fold ADDconst into MOVDaddrx
    569 (ADDconst [c] (MOVDaddridx [d] {s} x y)) && is20Bit(c+d) -> (MOVDaddridx [c+d] {s} x y)
    570 (MOVDaddridx [c] {s} (ADDconst [d] x) y) && is20Bit(c+d) && x.Op != OpSB -> (MOVDaddridx [c+d] {s} x y)
    571 (MOVDaddridx [c] {s} x (ADDconst [d] y)) && is20Bit(c+d) && y.Op != OpSB -> (MOVDaddridx [c+d] {s} x y)
    572 
    573 // reverse ordering of compare instruction
    574 (MOVDLT x y (InvertFlags cmp)) -> (MOVDGT x y cmp)
    575 (MOVDGT x y (InvertFlags cmp)) -> (MOVDLT x y cmp)
    576 (MOVDLE x y (InvertFlags cmp)) -> (MOVDGE x y cmp)
    577 (MOVDGE x y (InvertFlags cmp)) -> (MOVDLE x y cmp)
    578 (MOVDEQ x y (InvertFlags cmp)) -> (MOVDEQ x y cmp)
    579 (MOVDNE x y (InvertFlags cmp)) -> (MOVDNE x y cmp)
    580 
    581 // don't extend after proper load
    582 (MOVBreg x:(MOVBload _ _)) -> (MOVDreg x)
    583 (MOVBZreg x:(MOVBZload _ _)) -> (MOVDreg x)
    584 (MOVHreg x:(MOVBload _ _)) -> (MOVDreg x)
    585 (MOVHreg x:(MOVBZload _ _)) -> (MOVDreg x)
    586 (MOVHreg x:(MOVHload _ _)) -> (MOVDreg x)
    587 (MOVHZreg x:(MOVBZload _ _)) -> (MOVDreg x)
    588 (MOVHZreg x:(MOVHZload _ _)) -> (MOVDreg x)
    589 (MOVWreg x:(MOVBload _ _)) -> (MOVDreg x)
    590 (MOVWreg x:(MOVBZload _ _)) -> (MOVDreg x)
    591 (MOVWreg x:(MOVHload _ _)) -> (MOVDreg x)
    592 (MOVWreg x:(MOVHZload _ _)) -> (MOVDreg x)
    593 (MOVWreg x:(MOVWload _ _)) -> (MOVDreg x)
    594 (MOVWZreg x:(MOVBZload _ _)) -> (MOVDreg x)
    595 (MOVWZreg x:(MOVHZload _ _)) -> (MOVDreg x)
    596 (MOVWZreg x:(MOVWZload _ _)) -> (MOVDreg x)
    597 
    598 // don't extend if argument is already extended
    599 (MOVBreg x:(Arg <t>)) && is8BitInt(t) && isSigned(t) -> (MOVDreg x)
    600 (MOVBZreg x:(Arg <t>)) && is8BitInt(t) && !isSigned(t) -> (MOVDreg x)
    601 (MOVHreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && isSigned(t) -> (MOVDreg x)
    602 (MOVHZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && !isSigned(t) -> (MOVDreg x)
    603 (MOVWreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t) -> (MOVDreg x)
    604 (MOVWZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t) -> (MOVDreg x)
    605 
    606 // fold double extensions
    607 (MOVBreg x:(MOVBreg _)) -> (MOVDreg x)
    608 (MOVBZreg x:(MOVBZreg _)) -> (MOVDreg x)
    609 (MOVHreg x:(MOVBreg _)) -> (MOVDreg x)
    610 (MOVHreg x:(MOVBZreg _)) -> (MOVDreg x)
    611 (MOVHreg x:(MOVHreg _)) -> (MOVDreg x)
    612 (MOVHZreg x:(MOVBZreg _)) -> (MOVDreg x)
    613 (MOVHZreg x:(MOVHZreg _)) -> (MOVDreg x)
    614 (MOVWreg x:(MOVBreg _)) -> (MOVDreg x)
    615 (MOVWreg x:(MOVBZreg _)) -> (MOVDreg x)
    616 (MOVWreg x:(MOVHreg _)) -> (MOVDreg x)
    617 (MOVWreg x:(MOVHreg _)) -> (MOVDreg x)
    618 (MOVWreg x:(MOVWreg _)) -> (MOVDreg x)
    619 (MOVWZreg x:(MOVBZreg _)) -> (MOVDreg x)
    620 (MOVWZreg x:(MOVHZreg _)) -> (MOVDreg x)
    621 (MOVWZreg x:(MOVWZreg _)) -> (MOVDreg x)
    622 
    623 // fold extensions into constants
    624 (MOVBreg (MOVDconst [c])) -> (MOVDconst [int64(int8(c))])
    625 (MOVBZreg (MOVDconst [c])) -> (MOVDconst [int64(uint8(c))])
    626 (MOVHreg (MOVDconst [c])) -> (MOVDconst [int64(int16(c))])
    627 (MOVHZreg (MOVDconst [c])) -> (MOVDconst [int64(uint16(c))])
    628 (MOVWreg (MOVDconst [c])) -> (MOVDconst [int64(int32(c))])
    629 (MOVWZreg (MOVDconst [c])) -> (MOVDconst [int64(uint32(c))])
    630 
    631 // sign extended loads
    632 // Note: The combined instruction must end up in the same block
    633 // as the original load. If not, we end up making a value with
    634 // memory type live in two different blocks, which can lead to
    635 // multiple memory values alive simultaneously.
    636 // Make sure we don't combine these ops if the load has another use.
    637 // This prevents a single load from being split into multiple loads
    638 // which then might return different values.  See test/atomicload.go.
    639 (MOVBreg x:(MOVBZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
    640 (MOVBZreg x:(MOVBZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZload <v.Type> [off] {sym} ptr mem)
    641 (MOVHreg x:(MOVHZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHload <v.Type> [off] {sym} ptr mem)
    642 (MOVHZreg x:(MOVHZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZload <v.Type> [off] {sym} ptr mem)
    643 (MOVWreg x:(MOVWZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
    644 (MOVWZreg x:(MOVWZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZload <v.Type> [off] {sym} ptr mem)
    645 
    646 (MOVBZreg x:(MOVBZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZloadidx <v.Type> [off] {sym} ptr idx mem)
    647 (MOVHZreg x:(MOVHZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZloadidx <v.Type> [off] {sym} ptr idx mem)
    648 (MOVWZreg x:(MOVWZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZloadidx <v.Type> [off] {sym} ptr idx mem)
    649 
    650 // replace load from same location as preceding store with copy
    651 (MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
    652 (MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
    653 (MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
    654 (MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
    655 
    656 // Don't extend before storing
    657 (MOVWstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
    658 (MOVHstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
    659 (MOVBstore [off] {sym} ptr (MOVBreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
    660 (MOVWstore [off] {sym} ptr (MOVWZreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
    661 (MOVHstore [off] {sym} ptr (MOVHZreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
    662 (MOVBstore [off] {sym} ptr (MOVBZreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
    663 
    664 // Fold constants into memory operations.
    665 // Note that this is not always a good idea because if not all the uses of
    666 // the ADDconst get eliminated, we still have to compute the ADDconst and we now
    667 // have potentially two live values (ptr and (ADDconst [off] ptr)) instead of one.
    668 // Nevertheless, let's do it!
    669 (MOVDload   [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVDload  [off1+off2] {sym} ptr mem)
    670 (MOVWload   [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVWload  [off1+off2] {sym} ptr mem)
    671 (MOVHload   [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVHload  [off1+off2] {sym} ptr mem)
    672 (MOVBload   [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVBload  [off1+off2] {sym} ptr mem)
    673 (MOVWZload  [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVWZload [off1+off2] {sym} ptr mem)
    674 (MOVHZload  [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVHZload [off1+off2] {sym} ptr mem)
    675 (MOVBZload  [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVBZload [off1+off2] {sym} ptr mem)
    676 (FMOVSload  [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (FMOVSload [off1+off2] {sym} ptr mem)
    677 (FMOVDload  [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (FMOVDload [off1+off2] {sym} ptr mem)
    678 
    679 (MOVDstore  [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVDstore  [off1+off2] {sym} ptr val mem)
    680 (MOVWstore  [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVWstore  [off1+off2] {sym} ptr val mem)
    681 (MOVHstore  [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVHstore  [off1+off2] {sym} ptr val mem)
    682 (MOVBstore  [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVBstore  [off1+off2] {sym} ptr val mem)
    683 (FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (FMOVSstore [off1+off2] {sym} ptr val mem)
    684 (FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (FMOVDstore [off1+off2] {sym} ptr val mem)
    685 
    686 // Fold constants into stores.
    687 (MOVDstore [off] {sym} ptr (MOVDconst [c]) mem) && validValAndOff(c,off) && int64(int16(c)) == c && ptr.Op != OpSB ->
    688 	(MOVDstoreconst [makeValAndOff(c,off)] {sym} ptr mem)
    689 (MOVWstore [off] {sym} ptr (MOVDconst [c]) mem) && validOff(off) && int64(int16(c)) == c && ptr.Op != OpSB ->
    690 	(MOVWstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
    691 (MOVHstore [off] {sym} ptr (MOVDconst [c]) mem) && validOff(off) && ptr.Op != OpSB ->
    692 	(MOVHstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
    693 (MOVBstore [off] {sym} ptr (MOVDconst [c]) mem) && validOff(off) && ptr.Op != OpSB ->
    694 	(MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
    695 
    696 // Fold address offsets into constant stores.
    697 (MOVDstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
    698 	(MOVDstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
    699 (MOVWstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
    700 	(MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
    701 (MOVHstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
    702 	(MOVHstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
    703 (MOVBstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
    704 	(MOVBstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
    705 
    706 // We need to fold MOVDaddr into the MOVx ops so that the live variable analysis knows
    707 // what variables are being read/written by the ops.
    708 (MOVDload  [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    709 	(MOVDload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
    710 (MOVWZload  [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    711 	(MOVWZload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
    712 (MOVHZload  [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    713 	(MOVHZload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
    714 (MOVBZload  [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    715 	(MOVBZload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
    716 (FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    717 	(FMOVSload [off1+off2] {mergeSym(sym1,sym2)} base mem)
    718 (FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    719 	(FMOVDload [off1+off2] {mergeSym(sym1,sym2)} base mem)
    720 
    721 (MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    722 	(MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem)
    723 (MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    724 	(MOVHload [off1+off2] {mergeSym(sym1,sym2)} base mem)
    725 (MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    726 	(MOVWload [off1+off2] {mergeSym(sym1,sym2)} base mem)
    727 
    728 (MOVDstore  [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    729 	(MOVDstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
    730 (MOVWstore  [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    731 	(MOVWstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
    732 (MOVHstore  [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    733 	(MOVHstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
    734 (MOVBstore  [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    735 	(MOVBstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
    736 (FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    737 	(FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
    738 (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    739 	(FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
    740 
    741 (MOVDstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
    742 	(MOVDstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
    743 (MOVWstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
    744 	(MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
    745 (MOVHstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
    746 	(MOVHstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
    747 (MOVBstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
    748 	(MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
    749 
    750 // generating indexed loads and stores
    751 (MOVBZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    752 	(MOVBZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
    753 (MOVHZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    754 	(MOVHZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
    755 (MOVWZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    756 	(MOVWZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
    757 (MOVDload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    758 	(MOVDloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
    759 (FMOVSload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    760 	(FMOVSloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
    761 (FMOVDload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    762 	(FMOVDloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
    763 
    764 (MOVBstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    765 	(MOVBstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
    766 (MOVHstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    767 	(MOVHstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
    768 (MOVWstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    769 	(MOVWstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
    770 (MOVDstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    771 	(MOVDstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
    772 (FMOVSstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    773 	(FMOVSstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
    774 (FMOVDstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
    775 	(FMOVDstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
    776 
    777 (MOVBZload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVBZloadidx [off] {sym} ptr idx mem)
    778 (MOVHZload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVHZloadidx [off] {sym} ptr idx mem)
    779 (MOVWZload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVWZloadidx [off] {sym} ptr idx mem)
    780 (MOVDload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVDloadidx [off] {sym} ptr idx mem)
    781 (FMOVSload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (FMOVSloadidx [off] {sym} ptr idx mem)
    782 (FMOVDload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (FMOVDloadidx [off] {sym} ptr idx mem)
    783 (MOVBstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVBstoreidx [off] {sym} ptr idx val mem)
    784 (MOVHstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVHstoreidx [off] {sym} ptr idx val mem)
    785 (MOVWstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVWstoreidx [off] {sym} ptr idx val mem)
    786 (MOVDstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVDstoreidx [off] {sym} ptr idx val mem)
    787 (FMOVSstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (FMOVSstoreidx [off] {sym} ptr idx val mem)
    788 (FMOVDstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (FMOVDstoreidx [off] {sym} ptr idx val mem)
    789 
    790 // combine ADD into indexed loads and stores
    791 (MOVBZloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (MOVBZloadidx [c+d] {sym} ptr idx mem)
    792 (MOVHZloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (MOVHZloadidx [c+d] {sym} ptr idx mem)
    793 (MOVWZloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (MOVWZloadidx [c+d] {sym} ptr idx mem)
    794 (MOVDloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (MOVDloadidx [c+d] {sym} ptr idx mem)
    795 (FMOVSloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (FMOVSloadidx [c+d] {sym} ptr idx mem)
    796 (FMOVDloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (FMOVDloadidx [c+d] {sym} ptr idx mem)
    797 
    798 (MOVBstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (MOVBstoreidx [c+d] {sym} ptr idx val mem)
    799 (MOVHstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (MOVHstoreidx [c+d] {sym} ptr idx val mem)
    800 (MOVWstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (MOVWstoreidx [c+d] {sym} ptr idx val mem)
    801 (MOVDstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (MOVDstoreidx [c+d] {sym} ptr idx val mem)
    802 (FMOVSstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (FMOVSstoreidx [c+d] {sym} ptr idx val mem)
    803 (FMOVDstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (FMOVDstoreidx [c+d] {sym} ptr idx val mem)
    804 
    805 (MOVBZloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (MOVBZloadidx [c+d] {sym} ptr idx mem)
    806 (MOVHZloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (MOVHZloadidx [c+d] {sym} ptr idx mem)
    807 (MOVWZloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (MOVWZloadidx [c+d] {sym} ptr idx mem)
    808 (MOVDloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (MOVDloadidx [c+d] {sym} ptr idx mem)
    809 (FMOVSloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (FMOVSloadidx [c+d] {sym} ptr idx mem)
    810 (FMOVDloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (FMOVDloadidx [c+d] {sym} ptr idx mem)
    811 
    812 (MOVBstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (MOVBstoreidx [c+d] {sym} ptr idx val mem)
    813 (MOVHstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (MOVHstoreidx [c+d] {sym} ptr idx val mem)
    814 (MOVWstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (MOVWstoreidx [c+d] {sym} ptr idx val mem)
    815 (MOVDstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (MOVDstoreidx [c+d] {sym} ptr idx val mem)
    816 (FMOVSstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (FMOVSstoreidx [c+d] {sym} ptr idx val mem)
    817 (FMOVDstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (FMOVDstoreidx [c+d] {sym} ptr idx val mem)
    818 
    819 // MOVDaddr into MOVDaddridx
    820 (MOVDaddridx [off1] {sym1} (MOVDaddr [off2] {sym2} x) y) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB ->
    821        (MOVDaddridx [off1+off2] {mergeSym(sym1,sym2)} x y)
    822 (MOVDaddridx [off1] {sym1} x (MOVDaddr [off2] {sym2} y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB ->
    823        (MOVDaddridx [off1+off2] {mergeSym(sym1,sym2)} x y)
    824 
    825 // Absorb InvertFlags into branches.
    826 (LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
    827 (GT (InvertFlags cmp) yes no) -> (LT cmp yes no)
    828 (LE (InvertFlags cmp) yes no) -> (GE cmp yes no)
    829 (GE (InvertFlags cmp) yes no) -> (LE cmp yes no)
    830 (EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
    831 (NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
    832 
    833 // Constant comparisons.
    834 (CMPconst (MOVDconst [x]) [y]) && x==y -> (FlagEQ)
    835 (CMPconst (MOVDconst [x]) [y]) && x<y -> (FlagLT)
    836 (CMPconst (MOVDconst [x]) [y]) && x>y -> (FlagGT)
    837 (CMPUconst (MOVDconst [x]) [y]) && uint64(x)==uint64(y) -> (FlagEQ)
    838 (CMPUconst (MOVDconst [x]) [y]) && uint64(x)<uint64(y) -> (FlagLT)
    839 (CMPUconst (MOVDconst [x]) [y]) && uint64(x)>uint64(y) -> (FlagGT)
    840 
    841 (CMPWconst (MOVDconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
    842 (CMPWconst (MOVDconst [x]) [y]) && int32(x)<int32(y) -> (FlagLT)
    843 (CMPWconst (MOVDconst [x]) [y]) && int32(x)>int32(y) -> (FlagGT)
    844 (CMPWUconst (MOVDconst [x]) [y]) && uint32(x)==uint32(y) -> (FlagEQ)
    845 (CMPWUconst (MOVDconst [x]) [y]) && uint32(x)<uint32(y) -> (FlagLT)
    846 (CMPWUconst (MOVDconst [x]) [y]) && uint32(x)>uint32(y) -> (FlagGT)
    847 
    848 // Other known comparisons.
    849 (CMPconst (MOVBZreg _) [c]) && 0xFF < c -> (FlagLT)
    850 (CMPconst (MOVHZreg _) [c]) && 0xFFFF < c -> (FlagLT)
    851 (CMPconst (MOVWZreg _) [c]) && 0xFFFFFFFF < c -> (FlagLT)
    852 (CMPWconst (SRWconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n) -> (FlagLT)
    853 (CMPconst (SRDconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n) -> (FlagLT)
    854 (CMPconst (ANDconst _ [m]) [n]) && 0 <= m && m < n -> (FlagLT)
    855 (CMPWconst (ANDWconst _ [m]) [n]) && 0 <= int32(m) && int32(m) < int32(n) -> (FlagLT)
    856 
    857 // Absorb flag constants into SBB ops.
    858 (SUBEcarrymask (FlagEQ)) -> (MOVDconst [-1])
    859 (SUBEcarrymask (FlagLT)) -> (MOVDconst [-1])
    860 (SUBEcarrymask (FlagGT)) -> (MOVDconst [0])
    861 (SUBEWcarrymask (FlagEQ)) -> (MOVDconst [-1])
    862 (SUBEWcarrymask (FlagLT)) -> (MOVDconst [-1])
    863 (SUBEWcarrymask (FlagGT)) -> (MOVDconst [0])
    864 
    865 // Absorb flag constants into branches.
    866 (EQ (FlagEQ) yes no) -> (First nil yes no)
    867 (EQ (FlagLT) yes no) -> (First nil no yes)
    868 (EQ (FlagGT) yes no) -> (First nil no yes)
    869 
    870 (NE (FlagEQ) yes no) -> (First nil no yes)
    871 (NE (FlagLT) yes no) -> (First nil yes no)
    872 (NE (FlagGT) yes no) -> (First nil yes no)
    873 
    874 (LT (FlagEQ) yes no) -> (First nil no yes)
    875 (LT (FlagLT) yes no) -> (First nil yes no)
    876 (LT (FlagGT) yes no) -> (First nil no yes)
    877 
    878 (LE (FlagEQ) yes no) -> (First nil yes no)
    879 (LE (FlagLT) yes no) -> (First nil yes no)
    880 (LE (FlagGT) yes no) -> (First nil no yes)
    881 
    882 (GT (FlagEQ) yes no) -> (First nil no yes)
    883 (GT (FlagLT) yes no) -> (First nil no yes)
    884 (GT (FlagGT) yes no) -> (First nil yes no)
    885 
    886 (GE (FlagEQ) yes no) -> (First nil yes no)
    887 (GE (FlagLT) yes no) -> (First nil no yes)
    888 (GE (FlagGT) yes no) -> (First nil yes no)
    889 
    890 // Absorb flag constants into SETxx ops.
    891 (MOVDEQ _ x (FlagEQ)) -> x
    892 (MOVDEQ y _ (FlagLT)) -> y
    893 (MOVDEQ y _ (FlagGT)) -> y
    894 
    895 (MOVDNE y _ (FlagEQ)) -> y
    896 (MOVDNE _ x (FlagLT)) -> x
    897 (MOVDNE _ x (FlagGT)) -> x
    898 
    899 (MOVDLT y _ (FlagEQ)) -> y
    900 (MOVDLT _ x (FlagLT)) -> x
    901 (MOVDLT y _ (FlagGT)) -> y
    902 
    903 (MOVDLE _ x (FlagEQ)) -> x
    904 (MOVDLE _ x (FlagLT)) -> x
    905 (MOVDLE y _ (FlagGT)) -> y
    906 
    907 (MOVDGT y _ (FlagEQ)) -> y
    908 (MOVDGT y _ (FlagLT)) -> y
    909 (MOVDGT _ x (FlagGT)) -> x
    910 
    911 (MOVDGE _ x (FlagEQ)) -> x
    912 (MOVDGE y _ (FlagLT)) -> y
    913 (MOVDGE _ x (FlagGT)) -> x
    914 
    915 // Remove redundant *const ops
    916 (ADDconst [0] x) -> x
    917 (ADDWconst [c] x) && int32(c)==0 -> x
    918 (SUBconst [0] x) -> x
    919 (SUBWconst [c] x) && int32(c) == 0 -> x
    920 (ANDconst [0] _)                 -> (MOVDconst [0])
    921 (ANDWconst [c] _) && int32(c)==0  -> (MOVDconst [0])
    922 (ANDconst [-1] x)                -> x
    923 (ANDWconst [c] x) && int32(c)==-1 -> x
    924 (ORconst [0] x)                  -> x
    925 (ORWconst [c] x) && int32(c)==0   -> x
    926 (ORconst [-1] _)                 -> (MOVDconst [-1])
    927 (ORWconst [c] _) && int32(c)==-1  -> (MOVDconst [-1])
    928 (XORconst [0] x)                  -> x
    929 (XORWconst [c] x) && int32(c)==0   -> x
    930 
    931 // Convert constant subtracts to constant adds.
    932 (SUBconst [c] x) && c != -(1<<31) -> (ADDconst [-c] x)
    933 (SUBWconst [c] x) -> (ADDWconst [int64(int32(-c))] x)
    934 
    935 // generic constant folding
    936 // TODO: more of this
    937 (ADDconst [c] (MOVDconst [d])) -> (MOVDconst [c+d])
    938 (ADDWconst [c] (MOVDconst [d])) -> (MOVDconst [int64(int32(c+d))])
    939 (ADDconst [c] (ADDconst [d] x)) && is32Bit(c+d) -> (ADDconst [c+d] x)
    940 (ADDWconst [c] (ADDWconst [d] x)) -> (ADDWconst [int64(int32(c+d))] x)
    941 (SUBconst (MOVDconst [d]) [c]) -> (MOVDconst [d-c])
    942 (SUBconst (SUBconst x [d]) [c]) && is32Bit(-c-d) -> (ADDconst [-c-d] x)
    943 (SRADconst [c] (MOVDconst [d])) -> (MOVDconst [d>>uint64(c)])
    944 (SRAWconst [c] (MOVDconst [d])) -> (MOVDconst [d>>uint64(c)])
    945 (NEG (MOVDconst [c])) -> (MOVDconst [-c])
    946 (NEGW (MOVDconst [c])) -> (MOVDconst [int64(int32(-c))])
    947 (MULLDconst [c] (MOVDconst [d])) -> (MOVDconst [c*d])
    948 (MULLWconst [c] (MOVDconst [d])) -> (MOVDconst [int64(int32(c*d))])
    949 (AND (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c&d])
    950 (ANDconst [c] (MOVDconst [d])) -> (MOVDconst [c&d])
    951 (ANDWconst [c] (MOVDconst [d])) -> (MOVDconst [c&d])
    952 (OR (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c|d])
    953 (ORconst [c] (MOVDconst [d])) -> (MOVDconst [c|d])
    954 (ORWconst [c] (MOVDconst [d])) -> (MOVDconst [c|d])
    955 (XOR (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c^d])
    956 (XORconst [c] (MOVDconst [d])) -> (MOVDconst [c^d])
    957 (XORWconst [c] (MOVDconst [d])) -> (MOVDconst [c^d])
    958 
    959 // generic simplifications
    960 // TODO: more of this
    961 (ADD x (NEG y)) -> (SUB x y)
    962 (ADDW x (NEGW y)) -> (SUBW x y)
    963 (SUB x x) -> (MOVDconst [0])
    964 (SUBW x x) -> (MOVDconst [0])
    965 (AND x x) -> x
    966 (ANDW x x) -> x
    967 (OR x x) -> x
    968 (ORW x x) -> x
    969 (XOR x x) -> (MOVDconst [0])
    970 (XORW x x) -> (MOVDconst [0])
    971 
    972 // Fold memory operations into operations.
    973 // Exclude global data (SB) because these instructions cannot handle relative addresses.
    974 // TODO(mundaym): use LARL in the assembler to handle SB?
    975 // TODO(mundaym): indexed versions of these?
    976 (ADD <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
    977 	-> (ADDload <t> [off] {sym} x ptr mem)
    978 (ADD <t> g:(MOVDload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
    979 	-> (ADDload <t> [off] {sym} x ptr mem)
    980 (ADDW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
    981 	-> (ADDWload <t> [off] {sym} x ptr mem)
    982 (ADDW <t> g:(MOVWload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
    983 	-> (ADDWload <t> [off] {sym} x ptr mem)
    984 (ADDW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
    985 	-> (ADDWload <t> [off] {sym} x ptr mem)
    986 (ADDW <t> g:(MOVWZload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
    987 	-> (ADDWload <t> [off] {sym} x ptr mem)
    988 (MULLD <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
    989 	-> (MULLDload <t> [off] {sym} x ptr mem)
    990 (MULLD <t> g:(MOVDload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
    991 	-> (MULLDload <t> [off] {sym} x ptr mem)
    992 (MULLW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
    993 	-> (MULLWload <t> [off] {sym} x ptr mem)
    994 (MULLW <t> g:(MOVWload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
    995 	-> (MULLWload <t> [off] {sym} x ptr mem)
    996 (MULLW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
    997 	-> (MULLWload <t> [off] {sym} x ptr mem)
    998 (MULLW <t> g:(MOVWZload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
    999 	-> (MULLWload <t> [off] {sym} x ptr mem)
   1000 (SUB <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1001 	-> (SUBload <t> [off] {sym} x ptr mem)
   1002 (SUBW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1003 	-> (SUBWload <t> [off] {sym} x ptr mem)
   1004 (SUBW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1005 	-> (SUBWload <t> [off] {sym} x ptr mem)
   1006 (AND <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1007 	-> (ANDload <t> [off] {sym} x ptr mem)
   1008 (AND <t> g:(MOVDload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1009 	-> (ANDload <t> [off] {sym} x ptr mem)
   1010 (ANDW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1011 	-> (ANDWload <t> [off] {sym} x ptr mem)
   1012 (ANDW <t> g:(MOVWload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1013 	-> (ANDWload <t> [off] {sym} x ptr mem)
   1014 (ANDW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1015 	-> (ANDWload <t> [off] {sym} x ptr mem)
   1016 (ANDW <t> g:(MOVWZload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1017 	-> (ANDWload <t> [off] {sym} x ptr mem)
   1018 (OR <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1019 	-> (ORload <t> [off] {sym} x ptr mem)
   1020 (OR <t> g:(MOVDload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1021 	-> (ORload <t> [off] {sym} x ptr mem)
   1022 (ORW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1023 	-> (ORWload <t> [off] {sym} x ptr mem)
   1024 (ORW <t> g:(MOVWload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1025 	-> (ORWload <t> [off] {sym} x ptr mem)
   1026 (ORW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1027 	-> (ORWload <t> [off] {sym} x ptr mem)
   1028 (ORW <t> g:(MOVWZload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1029 	-> (ORWload <t> [off] {sym} x ptr mem)
   1030 (XOR <t> x g:(MOVDload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1031 	-> (XORload <t> [off] {sym} x ptr mem)
   1032 (XOR <t> g:(MOVDload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1033 	-> (XORload <t> [off] {sym} x ptr mem)
   1034 (XORW <t> x g:(MOVWload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1035 	-> (XORWload <t> [off] {sym} x ptr mem)
   1036 (XORW <t> g:(MOVWload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1037 	-> (XORWload <t> [off] {sym} x ptr mem)
   1038 (XORW <t> x g:(MOVWZload [off] {sym} ptr mem)) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1039 	-> (XORWload <t> [off] {sym} x ptr mem)
   1040 (XORW <t> g:(MOVWZload [off] {sym} ptr mem) x) && g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
   1041 	-> (XORWload <t> [off] {sym} x ptr mem)
   1042 
   1043 // Combine constant stores into larger (unaligned) stores.
   1044 // It doesn't work to global data (based on SB),
   1045 // because STGRL doesn't support unaligned address
   1046 (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
   1047   && p.Op != OpSB
   1048   && x.Uses == 1
   1049   && ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
   1050   && clobber(x)
   1051   -> (MOVHstoreconst [makeValAndOff(ValAndOff(c).Val()&0xff | ValAndOff(a).Val()<<8, ValAndOff(a).Off())] {s} p mem)
   1052 (MOVHstoreconst [c] {s} p x:(MOVHstoreconst [a] {s} p mem))
   1053   && p.Op != OpSB
   1054   && x.Uses == 1
   1055   && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
   1056   && clobber(x)
   1057   -> (MOVWstoreconst [makeValAndOff(ValAndOff(c).Val()&0xffff | ValAndOff(a).Val()<<16, ValAndOff(a).Off())] {s} p mem)
   1058 (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
   1059   && p.Op != OpSB
   1060   && x.Uses == 1
   1061   && ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
   1062   && clobber(x)
   1063   -> (MOVDstore [ValAndOff(a).Off()] {s} p (MOVDconst [ValAndOff(c).Val()&0xffffffff | ValAndOff(a).Val()<<32]) mem)
   1064 
   1065 // Combine stores into larger (unaligned) stores.
   1066 // It doesn't work on global data (based on SB) because stores with relative addressing
   1067 // require that the memory operand be aligned.
   1068 (MOVBstore [i] {s} p w x:(MOVBstore [i-1] {s} p (SRDconst [8] w) mem))
   1069   && p.Op != OpSB
   1070   && x.Uses == 1
   1071   && clobber(x)
   1072   -> (MOVHstore [i-1] {s} p w mem)
   1073 (MOVBstore [i] {s} p w0:(SRDconst [j] w) x:(MOVBstore [i-1] {s} p (SRDconst [j+8] w) mem))
   1074   && p.Op != OpSB
   1075   && x.Uses == 1
   1076   && clobber(x)
   1077   -> (MOVHstore [i-1] {s} p w0 mem)
   1078 (MOVBstore [i] {s} p w x:(MOVBstore [i-1] {s} p (SRWconst [8] w) mem))
   1079   && p.Op != OpSB
   1080   && x.Uses == 1
   1081   && clobber(x)
   1082   -> (MOVHstore [i-1] {s} p w mem)
   1083 (MOVBstore [i] {s} p w0:(SRWconst [j] w) x:(MOVBstore [i-1] {s} p (SRWconst [j+8] w) mem))
   1084   && p.Op != OpSB
   1085   && x.Uses == 1
   1086   && clobber(x)
   1087   -> (MOVHstore [i-1] {s} p w0 mem)
   1088 (MOVHstore [i] {s} p w x:(MOVHstore [i-2] {s} p (SRDconst [16] w) mem))
   1089   && p.Op != OpSB
   1090   && x.Uses == 1
   1091   && clobber(x)
   1092   -> (MOVWstore [i-2] {s} p w mem)
   1093 (MOVHstore [i] {s} p w0:(SRDconst [j] w) x:(MOVHstore [i-2] {s} p (SRDconst [j+16] w) mem))
   1094   && p.Op != OpSB
   1095   && x.Uses == 1
   1096   && clobber(x)
   1097   -> (MOVWstore [i-2] {s} p w0 mem)
   1098 (MOVHstore [i] {s} p w x:(MOVHstore [i-2] {s} p (SRWconst [16] w) mem))
   1099   && p.Op != OpSB
   1100   && x.Uses == 1
   1101   && clobber(x)
   1102   -> (MOVWstore [i-2] {s} p w mem)
   1103 (MOVHstore [i] {s} p w0:(SRWconst [j] w) x:(MOVHstore [i-2] {s} p (SRWconst [j+16] w) mem))
   1104   && p.Op != OpSB
   1105   && x.Uses == 1
   1106   && clobber(x)
   1107   -> (MOVWstore [i-2] {s} p w0 mem)
   1108 (MOVWstore [i] {s} p (SRDconst [32] w) x:(MOVWstore [i-4] {s} p w mem))
   1109   && p.Op != OpSB
   1110   && x.Uses == 1
   1111   && clobber(x)
   1112   -> (MOVDstore [i-4] {s} p w mem)
   1113 (MOVWstore [i] {s} p w0:(SRDconst [j] w) x:(MOVWstore [i-4] {s} p (SRDconst [j+32] w) mem))
   1114   && p.Op != OpSB
   1115   && x.Uses == 1
   1116   && clobber(x)
   1117   -> (MOVDstore [i-4] {s} p w0 mem)
   1118 
   1119 (MOVBstoreidx [i] {s} p idx w x:(MOVBstoreidx [i-1] {s} p idx (SRDconst [8] w) mem))
   1120   && x.Uses == 1
   1121   && clobber(x)
   1122   -> (MOVHstoreidx [i-1] {s} p idx w mem)
   1123 (MOVBstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx (SRDconst [j+8] w) mem))
   1124   && x.Uses == 1
   1125   && clobber(x)
   1126   -> (MOVHstoreidx [i-1] {s} p idx w0 mem)
   1127 (MOVBstoreidx [i] {s} p idx w x:(MOVBstoreidx [i-1] {s} p idx (SRWconst [8] w) mem))
   1128   && x.Uses == 1
   1129   && clobber(x)
   1130   -> (MOVHstoreidx [i-1] {s} p idx w mem)
   1131 (MOVBstoreidx [i] {s} p idx w0:(SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx (SRWconst [j+8] w) mem))
   1132   && x.Uses == 1
   1133   && clobber(x)
   1134   -> (MOVHstoreidx [i-1] {s} p idx w0 mem)
   1135 (MOVHstoreidx [i] {s} p idx w x:(MOVHstoreidx [i-2] {s} p idx (SRDconst [16] w) mem))
   1136   && x.Uses == 1
   1137   && clobber(x)
   1138   -> (MOVWstoreidx [i-2] {s} p idx w mem)
   1139 (MOVHstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVHstoreidx [i-2] {s} p idx (SRDconst [j+16] w) mem))
   1140   && x.Uses == 1
   1141   && clobber(x)
   1142   -> (MOVWstoreidx [i-2] {s} p idx w0 mem)
   1143 (MOVHstoreidx [i] {s} p idx w x:(MOVHstoreidx [i-2] {s} p idx (SRWconst [16] w) mem))
   1144   && x.Uses == 1
   1145   && clobber(x)
   1146   -> (MOVWstoreidx [i-2] {s} p idx w mem)
   1147 (MOVHstoreidx [i] {s} p idx w0:(SRWconst [j] w) x:(MOVHstoreidx [i-2] {s} p idx (SRWconst [j+16] w) mem))
   1148   && x.Uses == 1
   1149   && clobber(x)
   1150   -> (MOVWstoreidx [i-2] {s} p idx w0 mem)
   1151 (MOVWstoreidx [i] {s} p idx w x:(MOVWstoreidx [i-4] {s} p idx (SRDconst [32] w) mem))
   1152   && x.Uses == 1
   1153   && clobber(x)
   1154   -> (MOVDstoreidx [i-4] {s} p idx w mem)
   1155 (MOVWstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVWstoreidx [i-4] {s} p idx (SRDconst [j+32] w) mem))
   1156   && x.Uses == 1
   1157   && clobber(x)
   1158   -> (MOVDstoreidx [i-4] {s} p idx w0 mem)
   1159 
   1160 // Combine stores into larger (unaligned) stores with the bytes reversed (little endian).
   1161 // Store-with-bytes-reversed instructions do not support relative memory addresses,
   1162 // so these stores can't operate on global data (SB).
   1163 (MOVBstore [i] {s} p (SRDconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
   1164   && p.Op != OpSB
   1165   && x.Uses == 1
   1166   && clobber(x)
   1167   -> (MOVHBRstore [i-1] {s} p w mem)
   1168 (MOVBstore [i] {s} p (SRDconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SRDconst [j-8] w) mem))
   1169   && p.Op != OpSB
   1170   && x.Uses == 1
   1171   && clobber(x)
   1172   -> (MOVHBRstore [i-1] {s} p w0 mem)
   1173 (MOVBstore [i] {s} p (SRWconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
   1174   && p.Op != OpSB
   1175   && x.Uses == 1
   1176   && clobber(x)
   1177   -> (MOVHBRstore [i-1] {s} p w mem)
   1178 (MOVBstore [i] {s} p (SRWconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SRWconst [j-8] w) mem))
   1179   && p.Op != OpSB
   1180   && x.Uses == 1
   1181   && clobber(x)
   1182   -> (MOVHBRstore [i-1] {s} p w0 mem)
   1183 (MOVHBRstore [i] {s} p (SRDconst [16] w) x:(MOVHBRstore [i-2] {s} p w mem))
   1184   && x.Uses == 1
   1185   && clobber(x)
   1186   -> (MOVWBRstore [i-2] {s} p w mem)
   1187 (MOVHBRstore [i] {s} p (SRDconst [j] w) x:(MOVHBRstore [i-2] {s} p w0:(SRDconst [j-16] w) mem))
   1188   && x.Uses == 1
   1189   && clobber(x)
   1190   -> (MOVWBRstore [i-2] {s} p w0 mem)
   1191 (MOVHBRstore [i] {s} p (SRWconst [16] w) x:(MOVHBRstore [i-2] {s} p w mem))
   1192   && x.Uses == 1
   1193   && clobber(x)
   1194   -> (MOVWBRstore [i-2] {s} p w mem)
   1195 (MOVHBRstore [i] {s} p (SRWconst [j] w) x:(MOVHBRstore [i-2] {s} p w0:(SRWconst [j-16] w) mem))
   1196   && x.Uses == 1
   1197   && clobber(x)
   1198   -> (MOVWBRstore [i-2] {s} p w0 mem)
   1199 (MOVWBRstore [i] {s} p (SRDconst [32] w) x:(MOVWBRstore [i-4] {s} p w mem))
   1200   && x.Uses == 1
   1201   && clobber(x)
   1202   -> (MOVDBRstore [i-4] {s} p w mem)
   1203 (MOVWBRstore [i] {s} p (SRDconst [j] w) x:(MOVWBRstore [i-4] {s} p w0:(SRDconst [j-32] w) mem))
   1204   && x.Uses == 1
   1205   && clobber(x)
   1206   -> (MOVDBRstore [i-4] {s} p w0 mem)
   1207 
   1208 (MOVBstoreidx [i] {s} p idx (SRDconst [8] w) x:(MOVBstoreidx [i-1] {s} p idx w mem))
   1209   && x.Uses == 1
   1210   && clobber(x)
   1211   -> (MOVHBRstoreidx [i-1] {s} p idx w mem)
   1212 (MOVBstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx w0:(SRDconst [j-8] w) mem))
   1213   && x.Uses == 1
   1214   && clobber(x)
   1215   -> (MOVHBRstoreidx [i-1] {s} p idx w0 mem)
   1216 (MOVBstoreidx [i] {s} p idx (SRWconst [8] w) x:(MOVBstoreidx [i-1] {s} p idx w mem))
   1217   && x.Uses == 1
   1218   && clobber(x)
   1219   -> (MOVHBRstoreidx [i-1] {s} p idx w mem)
   1220 (MOVBstoreidx [i] {s} p idx (SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx w0:(SRWconst [j-8] w) mem))
   1221   && x.Uses == 1
   1222   && clobber(x)
   1223   -> (MOVHBRstoreidx [i-1] {s} p idx w0 mem)
   1224 (MOVHBRstoreidx [i] {s} p idx (SRDconst [16] w) x:(MOVHBRstoreidx [i-2] {s} p idx w mem))
   1225   && x.Uses == 1
   1226   && clobber(x)
   1227   -> (MOVWBRstoreidx [i-2] {s} p idx w mem)
   1228 (MOVHBRstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVHBRstoreidx [i-2] {s} p idx w0:(SRDconst [j-16] w) mem))
   1229   && x.Uses == 1
   1230   && clobber(x)
   1231   -> (MOVWBRstoreidx [i-2] {s} p idx w0 mem)
   1232 (MOVHBRstoreidx [i] {s} p idx (SRWconst [16] w) x:(MOVHBRstoreidx [i-2] {s} p idx w mem))
   1233   && x.Uses == 1
   1234   && clobber(x)
   1235   -> (MOVWBRstoreidx [i-2] {s} p idx w mem)
   1236 (MOVHBRstoreidx [i] {s} p idx (SRWconst [j] w) x:(MOVHBRstoreidx [i-2] {s} p idx w0:(SRWconst [j-16] w) mem))
   1237   && x.Uses == 1
   1238   && clobber(x)
   1239   -> (MOVWBRstoreidx [i-2] {s} p idx w0 mem)
   1240 (MOVWBRstoreidx [i] {s} p idx (SRDconst [32] w) x:(MOVWBRstoreidx [i-4] {s} p idx w mem))
   1241   && x.Uses == 1
   1242   && clobber(x)
   1243   -> (MOVDBRstoreidx [i-4] {s} p idx w mem)
   1244 (MOVWBRstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVWBRstoreidx [i-4] {s} p idx w0:(SRDconst [j-32] w) mem))
   1245   && x.Uses == 1
   1246   && clobber(x)
   1247   -> (MOVDBRstoreidx [i-4] {s} p idx w0 mem)
   1248 
   1249 // Combining byte loads into larger (unaligned) loads.
   1250 
   1251 // Little endian loads.
   1252 
   1253 // b[0] | b[1]<<8 -> load 16-bit, reverse bytes
   1254 (ORW                 x0:(MOVBZload [i]   {s} p mem)
   1255     s0:(SLWconst [8] x1:(MOVBZload [i+1] {s} p mem)))
   1256   && p.Op != OpSB
   1257   && x0.Uses == 1
   1258   && x1.Uses == 1
   1259   && s0.Uses == 1
   1260   && mergePoint(b,x0,x1) != nil
   1261   && clobber(x0)
   1262   && clobber(x1)
   1263   && clobber(s0)
   1264   -> @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRload [i] {s} p mem))
   1265 
   1266 // b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24 -> load 32-bit, reverse bytes
   1267 (ORW o0:(ORW z0:(MOVHZreg x0:(MOVHBRload [i] {s} p mem))
   1268     s0:(SLWconst [16] x1:(MOVBZload [i+2] {s} p mem)))
   1269     s1:(SLWconst [24] x2:(MOVBZload [i+3] {s} p mem)))
   1270   && p.Op != OpSB
   1271   && z0.Uses == 1
   1272   && x0.Uses == 1
   1273   && x1.Uses == 1
   1274   && x2.Uses == 1
   1275   && s0.Uses == 1
   1276   && s1.Uses == 1
   1277   && o0.Uses == 1
   1278   && mergePoint(b,x0,x1,x2) != nil
   1279   && clobber(z0)
   1280   && clobber(x0)
   1281   && clobber(x1)
   1282   && clobber(x2)
   1283   && clobber(s0)
   1284   && clobber(s1)
   1285   && clobber(o0)
   1286   -> @mergePoint(b,x0,x1,x2) (MOVWBRload [i] {s} p mem)
   1287 
   1288 // 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
   1289 (OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR
   1290                       x0:(MOVBZload [i]   {s} p mem)
   1291     s0:(SLDconst [8]  x1:(MOVBZload [i+1] {s} p mem)))
   1292     s1:(SLDconst [16] x2:(MOVBZload [i+2] {s} p mem)))
   1293     s2:(SLDconst [24] x3:(MOVBZload [i+3] {s} p mem)))
   1294     s3:(SLDconst [32] x4:(MOVBZload [i+4] {s} p mem)))
   1295     s4:(SLDconst [40] x5:(MOVBZload [i+5] {s} p mem)))
   1296     s5:(SLDconst [48] x6:(MOVBZload [i+6] {s} p mem)))
   1297     s6:(SLDconst [56] x7:(MOVBZload [i+7] {s} p mem)))
   1298   && p.Op != OpSB
   1299   && x0.Uses == 1
   1300   && x1.Uses == 1
   1301   && x2.Uses == 1
   1302   && x3.Uses == 1
   1303   && x4.Uses == 1
   1304   && x5.Uses == 1
   1305   && x6.Uses == 1
   1306   && x7.Uses == 1
   1307   && s0.Uses == 1
   1308   && s1.Uses == 1
   1309   && s2.Uses == 1
   1310   && s3.Uses == 1
   1311   && s4.Uses == 1
   1312   && s5.Uses == 1
   1313   && s6.Uses == 1
   1314   && o0.Uses == 1
   1315   && o1.Uses == 1
   1316   && o2.Uses == 1
   1317   && o3.Uses == 1
   1318   && o4.Uses == 1
   1319   && o5.Uses == 1
   1320   && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil
   1321   && clobber(x0)
   1322   && clobber(x1)
   1323   && clobber(x2)
   1324   && clobber(x3)
   1325   && clobber(x4)
   1326   && clobber(x5)
   1327   && clobber(x6)
   1328   && clobber(x7)
   1329   && clobber(s0)
   1330   && clobber(s1)
   1331   && clobber(s2)
   1332   && clobber(s3)
   1333   && clobber(s4)
   1334   && clobber(s5)
   1335   && clobber(s6)
   1336   && clobber(o0)
   1337   && clobber(o1)
   1338   && clobber(o2)
   1339   && clobber(o3)
   1340   && clobber(o4)
   1341   && clobber(o5)
   1342   -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVDBRload [i] {s} p mem)
   1343 
   1344 // b[0] | b[1]<<8 -> load 16-bit, reverse bytes
   1345 (ORW                 x0:(MOVBZloadidx [i]   {s} p idx mem)
   1346     s0:(SLWconst [8] x1:(MOVBZloadidx [i+1] {s} p idx mem)))
   1347   && x0.Uses == 1
   1348   && x1.Uses == 1
   1349   && s0.Uses == 1
   1350   && mergePoint(b,x0,x1) != nil
   1351   && clobber(x0)
   1352   && clobber(x1)
   1353   && clobber(s0)
   1354   -> @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRloadidx <v.Type> [i] {s} p idx mem))
   1355 
   1356 // b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24 -> load 32-bit, reverse bytes
   1357 (ORW o0:(ORW z0:(MOVHZreg x0:(MOVHBRloadidx [i] {s} p idx mem))
   1358     s0:(SLWconst [16] x1:(MOVBZloadidx [i+2] {s} p idx mem)))
   1359     s1:(SLWconst [24] x2:(MOVBZloadidx [i+3] {s} p idx mem)))
   1360   && z0.Uses == 1
   1361   && x0.Uses == 1
   1362   && x1.Uses == 1
   1363   && x2.Uses == 1
   1364   && s0.Uses == 1
   1365   && s1.Uses == 1
   1366   && o0.Uses == 1
   1367   && mergePoint(b,x0,x1,x2) != nil
   1368   && clobber(z0)
   1369   && clobber(x0)
   1370   && clobber(x1)
   1371   && clobber(x2)
   1372   && clobber(s0)
   1373   && clobber(s1)
   1374   && clobber(o0)
   1375   -> @mergePoint(b,x0,x1,x2) (MOVWZreg (MOVWBRloadidx <v.Type> [i] {s} p idx mem))
   1376 
   1377 // 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
   1378 (OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR
   1379                       x0:(MOVBZloadidx [i]   {s} p idx mem)
   1380     s0:(SLDconst [8]  x1:(MOVBZloadidx [i+1] {s} p idx mem)))
   1381     s1:(SLDconst [16] x2:(MOVBZloadidx [i+2] {s} p idx mem)))
   1382     s2:(SLDconst [24] x3:(MOVBZloadidx [i+3] {s} p idx mem)))
   1383     s3:(SLDconst [32] x4:(MOVBZloadidx [i+4] {s} p idx mem)))
   1384     s4:(SLDconst [40] x5:(MOVBZloadidx [i+5] {s} p idx mem)))
   1385     s5:(SLDconst [48] x6:(MOVBZloadidx [i+6] {s} p idx mem)))
   1386     s6:(SLDconst [56] x7:(MOVBZloadidx [i+7] {s} p idx mem)))
   1387   && x0.Uses == 1
   1388   && x1.Uses == 1
   1389   && x2.Uses == 1
   1390   && x3.Uses == 1
   1391   && x4.Uses == 1
   1392   && x5.Uses == 1
   1393   && x6.Uses == 1
   1394   && x7.Uses == 1
   1395   && s0.Uses == 1
   1396   && s1.Uses == 1
   1397   && s2.Uses == 1
   1398   && s3.Uses == 1
   1399   && s4.Uses == 1
   1400   && s5.Uses == 1
   1401   && s6.Uses == 1
   1402   && o0.Uses == 1
   1403   && o1.Uses == 1
   1404   && o2.Uses == 1
   1405   && o3.Uses == 1
   1406   && o4.Uses == 1
   1407   && o5.Uses == 1
   1408   && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil
   1409   && clobber(x0)
   1410   && clobber(x1)
   1411   && clobber(x2)
   1412   && clobber(x3)
   1413   && clobber(x4)
   1414   && clobber(x5)
   1415   && clobber(x6)
   1416   && clobber(x7)
   1417   && clobber(s0)
   1418   && clobber(s1)
   1419   && clobber(s2)
   1420   && clobber(s3)
   1421   && clobber(s4)
   1422   && clobber(s5)
   1423   && clobber(s6)
   1424   && clobber(o0)
   1425   && clobber(o1)
   1426   && clobber(o2)
   1427   && clobber(o3)
   1428   && clobber(o4)
   1429   && clobber(o5)
   1430   -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVDBRloadidx <v.Type> [i] {s} p idx mem)
   1431 
   1432 // Big endian loads.
   1433 
   1434 // b[1] | b[0]<<8 -> load 16-bit
   1435 (ORW                  x0:(MOVBZload [i]   {s} p mem)
   1436     s0:(SLWconst [8] x1:(MOVBZload [i-1] {s} p mem)))
   1437   && p.Op != OpSB
   1438   && x0.Uses == 1
   1439   && x1.Uses == 1
   1440   && s0.Uses == 1
   1441   && mergePoint(b,x0,x1) != nil
   1442   && clobber(x0)
   1443   && clobber(x1)
   1444   && clobber(s0)
   1445   -> @mergePoint(b,x0,x1) (MOVHZload [i-1] {s} p mem)
   1446 
   1447 // b[3] | b[2]<<8 | b[1]<<16 | b[0]<<24 -> load 32-bit
   1448 (ORW o0:(ORW x0:(MOVHZload [i] {s} p mem)
   1449     s0:(SLWconst [16] x1:(MOVBZload [i-1] {s} p mem)))
   1450     s1:(SLWconst [24] x2:(MOVBZload [i-2] {s} p mem)))
   1451   && p.Op != OpSB
   1452   && x0.Uses == 1
   1453   && x1.Uses == 1
   1454   && x2.Uses == 1
   1455   && s0.Uses == 1
   1456   && s1.Uses == 1
   1457   && o0.Uses == 1
   1458   && mergePoint(b,x0,x1,x2) != nil
   1459   && clobber(x0)
   1460   && clobber(x1)
   1461   && clobber(x2)
   1462   && clobber(s0)
   1463   && clobber(s1)
   1464   && clobber(o0)
   1465   -> @mergePoint(b,x0,x1,x2) (MOVWZload [i-2] {s} p mem)
   1466 
   1467 // 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
   1468 (OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR
   1469                       x0:(MOVBZload [i]   {s} p mem)
   1470     s0:(SLDconst [8]  x1:(MOVBZload [i-1] {s} p mem)))
   1471     s1:(SLDconst [16] x2:(MOVBZload [i-2] {s} p mem)))
   1472     s2:(SLDconst [24] x3:(MOVBZload [i-3] {s} p mem)))
   1473     s3:(SLDconst [32] x4:(MOVBZload [i-4] {s} p mem)))
   1474     s4:(SLDconst [40] x5:(MOVBZload [i-5] {s} p mem)))
   1475     s5:(SLDconst [48] x6:(MOVBZload [i-6] {s} p mem)))
   1476     s6:(SLDconst [56] x7:(MOVBZload [i-7] {s} p mem)))
   1477   && p.Op != OpSB
   1478   && x0.Uses == 1
   1479   && x1.Uses == 1
   1480   && x2.Uses == 1
   1481   && x3.Uses == 1
   1482   && x4.Uses == 1
   1483   && x5.Uses == 1
   1484   && x6.Uses == 1
   1485   && x7.Uses == 1
   1486   && s0.Uses == 1
   1487   && s1.Uses == 1
   1488   && s2.Uses == 1
   1489   && s3.Uses == 1
   1490   && s4.Uses == 1
   1491   && s5.Uses == 1
   1492   && s6.Uses == 1
   1493   && o0.Uses == 1
   1494   && o1.Uses == 1
   1495   && o2.Uses == 1
   1496   && o3.Uses == 1
   1497   && o4.Uses == 1
   1498   && o5.Uses == 1
   1499   && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil
   1500   && clobber(x0)
   1501   && clobber(x1)
   1502   && clobber(x2)
   1503   && clobber(x3)
   1504   && clobber(x4)
   1505   && clobber(x5)
   1506   && clobber(x6)
   1507   && clobber(x7)
   1508   && clobber(s0)
   1509   && clobber(s1)
   1510   && clobber(s2)
   1511   && clobber(s3)
   1512   && clobber(s4)
   1513   && clobber(s5)
   1514   && clobber(s6)
   1515   && clobber(o0)
   1516   && clobber(o1)
   1517   && clobber(o2)
   1518   && clobber(o3)
   1519   && clobber(o4)
   1520   && clobber(o5)
   1521   -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVDload [i-7] {s} p mem)
   1522 
   1523 // b[1] | b[0]<<8 -> load 16-bit
   1524 (ORW                 x0:(MOVBZloadidx [i]   {s} p idx mem)
   1525     s0:(SLWconst [8] x1:(MOVBZloadidx [i-1] {s} p idx mem)))
   1526   && x0.Uses == 1
   1527   && x1.Uses == 1
   1528   && s0.Uses == 1
   1529   && mergePoint(b,x0,x1) != nil
   1530   && clobber(x0)
   1531   && clobber(x1)
   1532   && clobber(s0)
   1533   -> @mergePoint(b,x0,x1) (MOVHZloadidx <v.Type> [i-1] {s} p idx mem)
   1534 
   1535 // b[3] | b[2]<<8 | b[1]<<16 | b[0]<<24 -> load 32-bit
   1536 (ORW o0:(ORW x0:(MOVHZloadidx [i] {s} p idx mem)
   1537     s0:(SLWconst [16] x1:(MOVBZloadidx [i-1] {s} p idx mem)))
   1538     s1:(SLWconst [24] x2:(MOVBZloadidx [i-2] {s} p idx mem)))
   1539   && x0.Uses == 1
   1540   && x1.Uses == 1
   1541   && x2.Uses == 1
   1542   && s0.Uses == 1
   1543   && s1.Uses == 1
   1544   && o0.Uses == 1
   1545   && mergePoint(b,x0,x1,x2) != nil
   1546   && clobber(x0)
   1547   && clobber(x1)
   1548   && clobber(x2)
   1549   && clobber(s0)
   1550   && clobber(s1)
   1551   && clobber(o0)
   1552   -> @mergePoint(b,x0,x1,x2) (MOVWZloadidx <v.Type> [i-2] {s} p idx mem)
   1553 
   1554 // 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
   1555 (OR o0:(OR o1:(OR o2:(OR o3:(OR o4:(OR o5:(OR
   1556                       x0:(MOVBZloadidx [i]   {s} p idx mem)
   1557     s0:(SLDconst [8]  x1:(MOVBZloadidx [i-1] {s} p idx mem)))
   1558     s1:(SLDconst [16] x2:(MOVBZloadidx [i-2] {s} p idx mem)))
   1559     s2:(SLDconst [24] x3:(MOVBZloadidx [i-3] {s} p idx mem)))
   1560     s3:(SLDconst [32] x4:(MOVBZloadidx [i-4] {s} p idx mem)))
   1561     s4:(SLDconst [40] x5:(MOVBZloadidx [i-5] {s} p idx mem)))
   1562     s5:(SLDconst [48] x6:(MOVBZloadidx [i-6] {s} p idx mem)))
   1563     s6:(SLDconst [56] x7:(MOVBZloadidx [i-7] {s} p idx mem)))
   1564   && x0.Uses == 1
   1565   && x1.Uses == 1
   1566   && x2.Uses == 1
   1567   && x3.Uses == 1
   1568   && x4.Uses == 1
   1569   && x5.Uses == 1
   1570   && x6.Uses == 1
   1571   && x7.Uses == 1
   1572   && s0.Uses == 1
   1573   && s1.Uses == 1
   1574   && s2.Uses == 1
   1575   && s3.Uses == 1
   1576   && s4.Uses == 1
   1577   && s5.Uses == 1
   1578   && s6.Uses == 1
   1579   && o0.Uses == 1
   1580   && o1.Uses == 1
   1581   && o2.Uses == 1
   1582   && o3.Uses == 1
   1583   && o4.Uses == 1
   1584   && o5.Uses == 1
   1585   && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil
   1586   && clobber(x0)
   1587   && clobber(x1)
   1588   && clobber(x2)
   1589   && clobber(x3)
   1590   && clobber(x4)
   1591   && clobber(x5)
   1592   && clobber(x6)
   1593   && clobber(x7)
   1594   && clobber(s0)
   1595   && clobber(s1)
   1596   && clobber(s2)
   1597   && clobber(s3)
   1598   && clobber(s4)
   1599   && clobber(s5)
   1600   && clobber(s6)
   1601   && clobber(o0)
   1602   && clobber(o1)
   1603   && clobber(o2)
   1604   && clobber(o3)
   1605   && clobber(o4)
   1606   && clobber(o5)
   1607   -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVDloadidx <v.Type> [i-7] {s} p idx mem)
   1608 
   1609 // Combine stores into store multiples.
   1610 // 32-bit
   1611 (MOVWstore [i] {s} p w1 x:(MOVWstore [i-4] {s} p w0 mem))
   1612   && p.Op != OpSB
   1613   && x.Uses == 1
   1614   && is20Bit(i-4)
   1615   && clobber(x)
   1616   -> (STM2 [i-4] {s} p w0 w1 mem)
   1617 (MOVWstore [i] {s} p w2 x:(STM2 [i-8] {s} p w0 w1 mem))
   1618   && x.Uses == 1
   1619   && is20Bit(i-8)
   1620   && clobber(x)
   1621   -> (STM3 [i-8] {s} p w0 w1 w2 mem)
   1622 (MOVWstore [i] {s} p w3 x:(STM3 [i-12] {s} p w0 w1 w2 mem))
   1623   && x.Uses == 1
   1624   && is20Bit(i-12)
   1625   && clobber(x)
   1626   -> (STM4 [i-12] {s} p w0 w1 w2 w3 mem)
   1627 (STM2 [i] {s} p w2 w3 x:(STM2 [i-8] {s} p w0 w1 mem))
   1628   && x.Uses == 1
   1629   && is20Bit(i-8)
   1630   && clobber(x)
   1631   -> (STM4 [i-8] {s} p w0 w1 w2 w3 mem)
   1632 // 64-bit
   1633 (MOVDstore [i] {s} p w1 x:(MOVDstore [i-8] {s} p w0 mem))
   1634   && p.Op != OpSB
   1635   && x.Uses == 1
   1636   && is20Bit(i-8)
   1637   && clobber(x)
   1638   -> (STMG2 [i-8] {s} p w0 w1 mem)
   1639 (MOVDstore [i] {s} p w2 x:(STMG2 [i-16] {s} p w0 w1 mem))
   1640   && x.Uses == 1
   1641   && is20Bit(i-16)
   1642   && clobber(x)
   1643   -> (STMG3 [i-16] {s} p w0 w1 w2 mem)
   1644 (MOVDstore [i] {s} p w3 x:(STMG3 [i-24] {s} p w0 w1 w2 mem))
   1645   && x.Uses == 1
   1646   && is20Bit(i-24)
   1647   && clobber(x)
   1648   -> (STMG4 [i-24] {s} p w0 w1 w2 w3 mem)
   1649 (STMG2 [i] {s} p w2 w3 x:(STMG2 [i-16] {s} p w0 w1 mem))
   1650   && x.Uses == 1
   1651   && is20Bit(i-16)
   1652   && clobber(x)
   1653   -> (STMG4 [i-16] {s} p w0 w1 w2 w3 mem)
   1654 
   1655 // Convert 32-bit store multiples into 64-bit stores.
   1656 (STM2 [i] {s} p (SRDconst [32] x) x mem) -> (MOVDstore [i] {s} p x mem)
   1657