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 (AddPtr x y) -> (ADDV x y)
      6 (Add64 x y) -> (ADDV x y)
      7 (Add32 x y) -> (ADDV x y)
      8 (Add16 x y) -> (ADDV x y)
      9 (Add8 x y) -> (ADDV x y)
     10 (Add32F x y) -> (ADDF x y)
     11 (Add64F x y) -> (ADDD x y)
     12 
     13 (SubPtr x y) -> (SUBV x y)
     14 (Sub64 x y) -> (SUBV x y)
     15 (Sub32 x y) -> (SUBV x y)
     16 (Sub16 x y) -> (SUBV x y)
     17 (Sub8 x y) -> (SUBV x y)
     18 (Sub32F x y) -> (SUBF x y)
     19 (Sub64F x y) -> (SUBD x y)
     20 
     21 (Mul64 x y) -> (Select1 (MULVU x y))
     22 (Mul32 x y) -> (Select1 (MULVU x y))
     23 (Mul16 x y) -> (Select1 (MULVU x y))
     24 (Mul8 x y) -> (Select1 (MULVU x y))
     25 (Mul32F x y) -> (MULF x y)
     26 (Mul64F x y) -> (MULD x y)
     27 
     28 (Hmul64 x y) -> (Select0 (MULV x y))
     29 (Hmul64u x y) -> (Select0 (MULVU x y))
     30 (Hmul32 x y) -> (SRAVconst (Select1 <config.fe.TypeInt64()> (MULV (SignExt32to64 x) (SignExt32to64 y))) [32])
     31 (Hmul32u x y) -> (SRLVconst (Select1 <config.fe.TypeUInt64()> (MULVU (ZeroExt32to64 x) (ZeroExt32to64 y))) [32])
     32 (Hmul16 x y) -> (SRAVconst (Select1 <config.fe.TypeInt32()> (MULV (SignExt16to64 x) (SignExt16to64 y))) [16])
     33 (Hmul16u x y) -> (SRLVconst (Select1 <config.fe.TypeUInt32()> (MULVU (ZeroExt16to64 x) (ZeroExt16to64 y))) [16])
     34 (Hmul8 x y) -> (SRAVconst (Select1 <config.fe.TypeInt16()> (MULV (SignExt8to64 x) (SignExt8to64 y))) [8])
     35 (Hmul8u x y) -> (SRLVconst (Select1 <config.fe.TypeUInt16()> (MULVU (ZeroExt8to64 x) (ZeroExt8to64 y))) [8])
     36 
     37 (Div64 x y) -> (Select1 (DIVV x y))
     38 (Div64u x y) -> (Select1 (DIVVU x y))
     39 (Div32 x y) -> (Select1 (DIVV (SignExt32to64 x) (SignExt32to64 y)))
     40 (Div32u x y) -> (Select1 (DIVVU (ZeroExt32to64 x) (ZeroExt32to64 y)))
     41 (Div16 x y) -> (Select1 (DIVV (SignExt16to64 x) (SignExt16to64 y)))
     42 (Div16u x y) -> (Select1 (DIVVU (ZeroExt16to64 x) (ZeroExt16to64 y)))
     43 (Div8 x y) -> (Select1 (DIVV (SignExt8to64 x) (SignExt8to64 y)))
     44 (Div8u x y) -> (Select1 (DIVVU (ZeroExt8to64 x) (ZeroExt8to64 y)))
     45 (Div32F x y) -> (DIVF x y)
     46 (Div64F x y) -> (DIVD x y)
     47 
     48 (Mod64 x y) -> (Select0 (DIVV x y))
     49 (Mod64u x y) -> (Select0 (DIVVU x y))
     50 (Mod32 x y) -> (Select0 (DIVV (SignExt32to64 x) (SignExt32to64 y)))
     51 (Mod32u x y) -> (Select0 (DIVVU (ZeroExt32to64 x) (ZeroExt32to64 y)))
     52 (Mod16 x y) -> (Select0 (DIVV (SignExt16to64 x) (SignExt16to64 y)))
     53 (Mod16u x y) -> (Select0 (DIVVU (ZeroExt16to64 x) (ZeroExt16to64 y)))
     54 (Mod8 x y) -> (Select0 (DIVV (SignExt8to64 x) (SignExt8to64 y)))
     55 (Mod8u x y) -> (Select0 (DIVVU (ZeroExt8to64 x) (ZeroExt8to64 y)))
     56 
     57 (Avg64u <t> x y) -> (ADDV (ADDV <t> (SRLVconst <t> x [1]) (SRLVconst <t> y [1])) (AND <t> (AND <t> x y) (MOVVconst [1])))
     58 
     59 (And64 x y) -> (AND x y)
     60 (And32 x y) -> (AND x y)
     61 (And16 x y) -> (AND x y)
     62 (And8 x y) -> (AND x y)
     63 
     64 (Or64 x y) -> (OR x y)
     65 (Or32 x y) -> (OR x y)
     66 (Or16 x y) -> (OR x y)
     67 (Or8 x y) -> (OR x y)
     68 
     69 (Xor64 x y) -> (XOR x y)
     70 (Xor32 x y) -> (XOR x y)
     71 (Xor16 x y) -> (XOR x y)
     72 (Xor8 x y) -> (XOR x y)
     73 
     74 // shifts
     75 // hardware instruction uses only the low 6 bits of the shift
     76 // we compare to 64 to ensure Go semantics for large shifts
     77 (Lsh64x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
     78 (Lsh64x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
     79 (Lsh64x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
     80 (Lsh64x8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
     81 
     82 (Lsh32x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
     83 (Lsh32x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
     84 (Lsh32x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
     85 (Lsh32x8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
     86 
     87 (Lsh16x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
     88 (Lsh16x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
     89 (Lsh16x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
     90 (Lsh16x8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
     91 
     92 (Lsh8x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
     93 (Lsh8x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
     94 (Lsh8x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
     95 (Lsh8x8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
     96 
     97 (Rsh64Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> x y))
     98 (Rsh64Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> x (ZeroExt32to64 y)))
     99 (Rsh64Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> x (ZeroExt16to64 y)))
    100 (Rsh64Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SRLV <t> x (ZeroExt8to64  y)))
    101 
    102 (Rsh32Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> (ZeroExt32to64 x) y))
    103 (Rsh32Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt32to64 y)))
    104 (Rsh32Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt16to64 y)))
    105 (Rsh32Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt8to64  y)))
    106 
    107 (Rsh16Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> (ZeroExt16to64 x) y))
    108 (Rsh16Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt32to64 y)))
    109 (Rsh16Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt16to64 y)))
    110 (Rsh16Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt8to64  y)))
    111 
    112 (Rsh8Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> (ZeroExt8to64 x) y))
    113 (Rsh8Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt32to64 y)))
    114 (Rsh8Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt16to64 y)))
    115 (Rsh8Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt8to64  y)))
    116 
    117 (Rsh64x64 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
    118 (Rsh64x32 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
    119 (Rsh64x16 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
    120 (Rsh64x8  <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64  y)))
    121 
    122 (Rsh32x64 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
    123 (Rsh32x32 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
    124 (Rsh32x16 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
    125 (Rsh32x8  <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64  y)))
    126 
    127 (Rsh16x64 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
    128 (Rsh16x32 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
    129 (Rsh16x16 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
    130 (Rsh16x8  <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64  y)))
    131 
    132 (Rsh8x64 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
    133 (Rsh8x32 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
    134 (Rsh8x16 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
    135 (Rsh8x8  <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64  y)))
    136 
    137 // unary ops
    138 (Neg64 x) -> (NEGV x)
    139 (Neg32 x) -> (NEGV x)
    140 (Neg16 x) -> (NEGV x)
    141 (Neg8 x) -> (NEGV x)
    142 (Neg32F x) -> (NEGF x)
    143 (Neg64F x) -> (NEGD x)
    144 
    145 (Com64 x) -> (NOR (MOVVconst [0]) x)
    146 (Com32 x) -> (NOR (MOVVconst [0]) x)
    147 (Com16 x) -> (NOR (MOVVconst [0]) x)
    148 (Com8 x) -> (NOR (MOVVconst [0]) x)
    149 
    150 // boolean ops -- booleans are represented with 0=false, 1=true
    151 (AndB x y) -> (AND x y)
    152 (OrB x y) -> (OR x y)
    153 (EqB x y) -> (XOR (MOVVconst [1]) (XOR <config.fe.TypeBool()> x y))
    154 (NeqB x y) -> (XOR x y)
    155 (Not x) -> (XORconst [1] x)
    156 
    157 // constants
    158 (Const64 [val]) -> (MOVVconst [val])
    159 (Const32 [val]) -> (MOVVconst [val])
    160 (Const16 [val]) -> (MOVVconst [val])
    161 (Const8 [val]) -> (MOVVconst [val])
    162 (Const32F [val]) -> (MOVFconst [val])
    163 (Const64F [val]) -> (MOVDconst [val])
    164 (ConstNil) -> (MOVVconst [0])
    165 (ConstBool [b]) -> (MOVVconst [b])
    166 
    167 (Slicemask <t> x) -> (NORconst [0] (SRAVconst <t> (SUBVconst <t> x [1]) [63]))
    168 
    169 // truncations
    170 // Because we ignore high parts of registers, truncates are just copies.
    171 (Trunc16to8 x) -> x
    172 (Trunc32to8 x) -> x
    173 (Trunc32to16 x) -> x
    174 (Trunc64to8 x) -> x
    175 (Trunc64to16 x) -> x
    176 (Trunc64to32 x) -> x
    177 
    178 // Zero-/Sign-extensions
    179 (ZeroExt8to16 x) -> (MOVBUreg x)
    180 (ZeroExt8to32 x) -> (MOVBUreg x)
    181 (ZeroExt16to32 x) -> (MOVHUreg x)
    182 (ZeroExt8to64 x) -> (MOVBUreg x)
    183 (ZeroExt16to64 x) -> (MOVHUreg x)
    184 (ZeroExt32to64 x) -> (MOVWUreg x)
    185 
    186 (SignExt8to16 x) -> (MOVBreg x)
    187 (SignExt8to32 x) -> (MOVBreg x)
    188 (SignExt16to32 x) -> (MOVHreg x)
    189 (SignExt8to64 x) -> (MOVBreg x)
    190 (SignExt16to64 x) -> (MOVHreg x)
    191 (SignExt32to64 x) -> (MOVWreg x)
    192 
    193 // float <-> int conversion
    194 (Cvt32to32F x) -> (MOVWF x)
    195 (Cvt32to64F x) -> (MOVWD x)
    196 (Cvt64to32F x) -> (MOVVF x)
    197 (Cvt64to64F x) -> (MOVVD x)
    198 (Cvt32Fto32 x) -> (TRUNCFW x)
    199 (Cvt64Fto32 x) -> (TRUNCDW x)
    200 (Cvt32Fto64 x) -> (TRUNCFV x)
    201 (Cvt64Fto64 x) -> (TRUNCDV x)
    202 (Cvt32Fto64F x) -> (MOVFD x)
    203 (Cvt64Fto32F x) -> (MOVDF x)
    204 
    205 // comparisons
    206 (Eq8 x y)  -> (SGTU (MOVVconst [1]) (XOR (ZeroExt8to64 x) (ZeroExt8to64 y)))
    207 (Eq16 x y) -> (SGTU (MOVVconst [1]) (XOR (ZeroExt16to64 x) (ZeroExt16to64 y)))
    208 (Eq32 x y) -> (SGTU (MOVVconst [1]) (XOR (ZeroExt32to64 x) (ZeroExt32to64 y)))
    209 (Eq64 x y) -> (SGTU (MOVVconst [1]) (XOR x y))
    210 (EqPtr x y) -> (SGTU (MOVVconst [1]) (XOR x y))
    211 (Eq32F x y) -> (FPFlagTrue (CMPEQF x y))
    212 (Eq64F x y) -> (FPFlagTrue (CMPEQD x y))
    213 
    214 (Neq8 x y)  -> (SGTU (XOR (ZeroExt8to64 x) (ZeroExt8to64 y)) (MOVVconst [0]))
    215 (Neq16 x y) -> (SGTU (XOR (ZeroExt16to32 x) (ZeroExt16to64 y)) (MOVVconst [0]))
    216 (Neq32 x y) -> (SGTU (XOR (ZeroExt32to64 x) (ZeroExt32to64 y)) (MOVVconst [0]))
    217 (Neq64 x y) -> (SGTU (XOR x y) (MOVVconst [0]))
    218 (NeqPtr x y) -> (SGTU (XOR x y) (MOVVconst [0]))
    219 (Neq32F x y) -> (FPFlagFalse (CMPEQF x y))
    220 (Neq64F x y) -> (FPFlagFalse (CMPEQD x y))
    221 
    222 (Less8 x y)  -> (SGT (SignExt8to64 y) (SignExt8to64 x))
    223 (Less16 x y) -> (SGT (SignExt16to64 y) (SignExt16to64 x))
    224 (Less32 x y) -> (SGT (SignExt32to64 y) (SignExt32to64 x))
    225 (Less64 x y) -> (SGT y x)
    226 (Less32F x y) -> (FPFlagTrue (CMPGTF y x)) // reverse operands to work around NaN
    227 (Less64F x y) -> (FPFlagTrue (CMPGTD y x)) // reverse operands to work around NaN
    228 
    229 (Less8U x y)  -> (SGTU (ZeroExt8to64 y) (ZeroExt8to64 x))
    230 (Less16U x y) -> (SGTU (ZeroExt16to64 y) (ZeroExt16to64 x))
    231 (Less32U x y) -> (SGTU (ZeroExt32to64 y) (ZeroExt32to64 x))
    232 (Less64U x y) -> (SGTU y x)
    233 
    234 (Leq8 x y)  -> (XOR (MOVVconst [1]) (SGT (SignExt8to64 x) (SignExt8to64 y)))
    235 (Leq16 x y) -> (XOR (MOVVconst [1]) (SGT (SignExt16to64 x) (SignExt16to64 y)))
    236 (Leq32 x y) -> (XOR (MOVVconst [1]) (SGT (SignExt32to64 x) (SignExt32to64 y)))
    237 (Leq64 x y) -> (XOR (MOVVconst [1]) (SGT x y))
    238 (Leq32F x y) -> (FPFlagTrue (CMPGEF y x)) // reverse operands to work around NaN
    239 (Leq64F x y) -> (FPFlagTrue (CMPGED y x)) // reverse operands to work around NaN
    240 
    241 (Leq8U x y)  -> (XOR (MOVVconst [1]) (SGTU (ZeroExt8to64 x) (ZeroExt8to64 y)))
    242 (Leq16U x y) -> (XOR (MOVVconst [1]) (SGTU (ZeroExt16to64 x) (ZeroExt16to64 y)))
    243 (Leq32U x y) -> (XOR (MOVVconst [1]) (SGTU (ZeroExt32to64 x) (ZeroExt32to64 y)))
    244 (Leq64U x y) -> (XOR (MOVVconst [1]) (SGTU x y))
    245 
    246 (Greater8 x y)  -> (SGT (SignExt8to64 x) (SignExt8to64 y))
    247 (Greater16 x y) -> (SGT (SignExt16to64 x) (SignExt16to64 y))
    248 (Greater32 x y) -> (SGT (SignExt32to64 x) (SignExt32to64 y))
    249 (Greater64 x y) -> (SGT x y)
    250 (Greater32F x y) -> (FPFlagTrue (CMPGTF x y))
    251 (Greater64F x y) -> (FPFlagTrue (CMPGTD x y))
    252 
    253 (Greater8U x y)  -> (SGTU (ZeroExt8to64 x) (ZeroExt8to64 y))
    254 (Greater16U x y) -> (SGTU (ZeroExt16to64 x) (ZeroExt16to64 y))
    255 (Greater32U x y) -> (SGTU (ZeroExt32to64 x) (ZeroExt32to64 y))
    256 (Greater64U x y) -> (SGTU x y)
    257 
    258 (Geq8 x y)  -> (XOR (MOVVconst [1]) (SGT (SignExt8to64 y) (SignExt8to64 x)))
    259 (Geq16 x y) -> (XOR (MOVVconst [1]) (SGT (SignExt16to64 y) (SignExt16to64 x)))
    260 (Geq32 x y) -> (XOR (MOVVconst [1]) (SGT (SignExt32to64 y) (SignExt32to64 x)))
    261 (Geq64 x y) -> (XOR (MOVVconst [1]) (SGT y x))
    262 (Geq32F x y) -> (FPFlagTrue (CMPGEF x y))
    263 (Geq64F x y) -> (FPFlagTrue (CMPGED x y))
    264 
    265 (Geq8U x y)  -> (XOR (MOVVconst [1]) (SGTU (ZeroExt8to64 y) (ZeroExt8to64 x)))
    266 (Geq16U x y) -> (XOR (MOVVconst [1]) (SGTU (ZeroExt16to64 y) (ZeroExt16to64 x)))
    267 (Geq32U x y) -> (XOR (MOVVconst [1]) (SGTU (ZeroExt32to64 y) (ZeroExt32to64 x)))
    268 (Geq64U x y) -> (XOR (MOVVconst [1]) (SGTU y x))
    269 
    270 (OffPtr [off] ptr:(SP)) -> (MOVVaddr [off] ptr)
    271 (OffPtr [off] ptr) -> (ADDVconst [off] ptr)
    272 
    273 (Addr {sym} base) -> (MOVVaddr {sym} base)
    274 
    275 // loads
    276 (Load <t> ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem)
    277 (Load <t> ptr mem) && (is8BitInt(t) && isSigned(t)) -> (MOVBload ptr mem)
    278 (Load <t> ptr mem) && (is8BitInt(t) && !isSigned(t)) -> (MOVBUload ptr mem)
    279 (Load <t> ptr mem) && (is16BitInt(t) && isSigned(t)) -> (MOVHload ptr mem)
    280 (Load <t> ptr mem) && (is16BitInt(t) && !isSigned(t)) -> (MOVHUload ptr mem)
    281 (Load <t> ptr mem) && (is32BitInt(t) && isSigned(t)) -> (MOVWload ptr mem)
    282 (Load <t> ptr mem) && (is32BitInt(t) && !isSigned(t)) -> (MOVWUload ptr mem)
    283 (Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVVload ptr mem)
    284 (Load <t> ptr mem) && is32BitFloat(t) -> (MOVFload ptr mem)
    285 (Load <t> ptr mem) && is64BitFloat(t) -> (MOVDload ptr mem)
    286 
    287 // stores
    288 (Store [1] ptr val mem) -> (MOVBstore ptr val mem)
    289 (Store [2] ptr val mem) -> (MOVHstore ptr val mem)
    290 (Store [4] ptr val mem) && !is32BitFloat(val.Type) -> (MOVWstore ptr val mem)
    291 (Store [8] ptr val mem) && !is64BitFloat(val.Type) -> (MOVVstore ptr val mem)
    292 (Store [4] ptr val mem) && is32BitFloat(val.Type) -> (MOVFstore ptr val mem)
    293 (Store [8] ptr val mem) && is64BitFloat(val.Type) -> (MOVDstore ptr val mem)
    294 
    295 // zeroing
    296 (Zero [s] _ mem) && SizeAndAlign(s).Size() == 0 -> mem
    297 (Zero [s] ptr mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore ptr (MOVVconst [0]) mem)
    298 (Zero [s] ptr mem) && SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0 ->
    299 	(MOVHstore ptr (MOVVconst [0]) mem)
    300 (Zero [s] ptr mem) && SizeAndAlign(s).Size() == 2 ->
    301 	(MOVBstore [1] ptr (MOVVconst [0])
    302 		(MOVBstore [0] ptr (MOVVconst [0]) mem))
    303 (Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0 ->
    304 	(MOVWstore ptr (MOVVconst [0]) mem)
    305 (Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
    306 	(MOVHstore [2] ptr (MOVVconst [0])
    307 		(MOVHstore [0] ptr (MOVVconst [0]) mem))
    308 (Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 ->
    309 	(MOVBstore [3] ptr (MOVVconst [0])
    310 		(MOVBstore [2] ptr (MOVVconst [0])
    311 			(MOVBstore [1] ptr (MOVVconst [0])
    312 				(MOVBstore [0] ptr (MOVVconst [0]) mem))))
    313 (Zero [s] ptr mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0 ->
    314 	(MOVVstore ptr (MOVVconst [0]) mem)
    315 (Zero [s] ptr mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0 ->
    316 	(MOVWstore [4] ptr (MOVVconst [0])
    317 		(MOVWstore [0] ptr (MOVVconst [0]) mem))
    318 (Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 ->
    319 	(MOVHstore [6] ptr (MOVVconst [0])
    320 		(MOVHstore [4] ptr (MOVVconst [0])
    321 			(MOVHstore [2] ptr (MOVVconst [0])
    322 				(MOVHstore [0] ptr (MOVVconst [0]) mem))))
    323 
    324 (Zero [s] ptr mem) && SizeAndAlign(s).Size() == 3 ->
    325 	(MOVBstore [2] ptr (MOVVconst [0])
    326 		(MOVBstore [1] ptr (MOVVconst [0])
    327 			(MOVBstore [0] ptr (MOVVconst [0]) mem)))
    328 (Zero [s] ptr mem) && SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0 ->
    329 	(MOVHstore [4] ptr (MOVVconst [0])
    330 		(MOVHstore [2] ptr (MOVVconst [0])
    331 			(MOVHstore [0] ptr (MOVVconst [0]) mem)))
    332 (Zero [s] ptr mem) && SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0 ->
    333 	(MOVWstore [8] ptr (MOVVconst [0])
    334 		(MOVWstore [4] ptr (MOVVconst [0])
    335 			(MOVWstore [0] ptr (MOVVconst [0]) mem)))
    336 (Zero [s] ptr mem) && SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0 ->
    337 	(MOVVstore [8] ptr (MOVVconst [0])
    338 		(MOVVstore [0] ptr (MOVVconst [0]) mem))
    339 (Zero [s] ptr mem) && SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0 ->
    340 	(MOVVstore [16] ptr (MOVVconst [0])
    341 		(MOVVstore [8] ptr (MOVVconst [0])
    342 			(MOVVstore [0] ptr (MOVVconst [0]) mem)))
    343 
    344 // medium zeroing uses a duff device
    345 // 8, and 128 are magic constants, see runtime/mkduff.go
    346 (Zero [s] ptr mem)
    347 	&& SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size() <= 8*128
    348 	&& SizeAndAlign(s).Align()%8 == 0 && !config.noDuffDevice ->
    349 	(DUFFZERO [8 * (128 - int64(SizeAndAlign(s).Size()/8))] ptr mem)
    350 
    351 // large or unaligned zeroing uses a loop
    352 (Zero [s] ptr mem)
    353 	&& (SizeAndAlign(s).Size() > 8*128 || config.noDuffDevice) || SizeAndAlign(s).Align()%8 != 0 ->
    354 	(LoweredZero [SizeAndAlign(s).Align()]
    355 		ptr
    356 		(ADDVconst <ptr.Type> ptr [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)])
    357 		mem)
    358 
    359 // moves
    360 (Move [s] _ _ mem) && SizeAndAlign(s).Size() == 0 -> mem
    361 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore dst (MOVBload src mem) mem)
    362 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0 ->
    363 	(MOVHstore dst (MOVHload src mem) mem)
    364 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 ->
    365 	(MOVBstore [1] dst (MOVBload [1] src mem)
    366 		(MOVBstore dst (MOVBload src mem) mem))
    367 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0 ->
    368 	(MOVWstore dst (MOVWload src mem) mem)
    369 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
    370 	(MOVHstore [2] dst (MOVHload [2] src mem)
    371 		(MOVHstore dst (MOVHload src mem) mem))
    372 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 ->
    373 	(MOVBstore [3] dst (MOVBload [3] src mem)
    374 		(MOVBstore [2] dst (MOVBload [2] src mem)
    375 			(MOVBstore [1] dst (MOVBload [1] src mem)
    376 				(MOVBstore dst (MOVBload src mem) mem))))
    377 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0 ->
    378 	(MOVVstore dst (MOVVload src mem) mem)
    379 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0 ->
    380 	(MOVWstore [4] dst (MOVWload [4] src mem)
    381 		(MOVWstore dst (MOVWload src mem) mem))
    382 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%2 == 0 ->
    383 	(MOVHstore [6] dst (MOVHload [6] src mem)
    384 		(MOVHstore [4] dst (MOVHload [4] src mem)
    385 			(MOVHstore [2] dst (MOVHload [2] src mem)
    386 				(MOVHstore dst (MOVHload src mem) mem))))
    387 
    388 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 3 ->
    389 	(MOVBstore [2] dst (MOVBload [2] src mem)
    390 		(MOVBstore [1] dst (MOVBload [1] src mem)
    391 			(MOVBstore dst (MOVBload src mem) mem)))
    392 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0 ->
    393 	(MOVHstore [4] dst (MOVHload [4] src mem)
    394 		(MOVHstore [2] dst (MOVHload [2] src mem)
    395 			(MOVHstore dst (MOVHload src mem) mem)))
    396 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0 ->
    397 	(MOVWstore [8] dst (MOVWload [8] src mem)
    398 		(MOVWstore [4] dst (MOVWload [4] src mem)
    399 			(MOVWstore dst (MOVWload src mem) mem)))
    400 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0 ->
    401 	(MOVVstore [8] dst (MOVVload [8] src mem)
    402 		(MOVVstore dst (MOVVload src mem) mem))
    403 (Move [s] dst src mem) && SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0 ->
    404 	(MOVVstore [16] dst (MOVVload [16] src mem)
    405 		(MOVVstore [8] dst (MOVVload [8] src mem)
    406 			(MOVVstore dst (MOVVload src mem) mem)))
    407 
    408 // large or unaligned move uses a loop
    409 (Move [s] dst src mem)
    410 	&& SizeAndAlign(s).Size() > 24 || SizeAndAlign(s).Align()%8 != 0 ->
    411 	(LoweredMove [SizeAndAlign(s).Align()]
    412 		dst
    413 		src
    414 		(ADDVconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)])
    415 		mem)
    416 
    417 // calls
    418 (StaticCall [argwid] {target} mem) -> (CALLstatic [argwid] {target} mem)
    419 (ClosureCall [argwid] entry closure mem) -> (CALLclosure [argwid] entry closure mem)
    420 (DeferCall [argwid] mem) -> (CALLdefer [argwid] mem)
    421 (GoCall [argwid] mem) -> (CALLgo [argwid] mem)
    422 (InterCall [argwid] entry mem) -> (CALLinter [argwid] entry mem)
    423 
    424 // checks
    425 (NilCheck ptr mem) -> (LoweredNilCheck ptr mem)
    426 (IsNonNil ptr) -> (SGTU ptr (MOVVconst [0]))
    427 (IsInBounds idx len) -> (SGTU len idx)
    428 (IsSliceInBounds idx len) -> (XOR (MOVVconst [1]) (SGTU idx len))
    429 
    430 // pseudo-ops
    431 (GetClosurePtr) -> (LoweredGetClosurePtr)
    432 (Convert x mem) -> (MOVVconvert x mem)
    433 
    434 (If cond yes no) -> (NE cond yes no)
    435 
    436 // Optimizations
    437 
    438 // Absorb boolean tests into block
    439 (NE (FPFlagTrue cmp) yes no) -> (FPT cmp yes no)
    440 (NE (FPFlagFalse cmp) yes no) -> (FPF cmp yes no)
    441 (EQ (FPFlagTrue cmp) yes no) -> (FPF cmp yes no)
    442 (EQ (FPFlagFalse cmp) yes no) -> (FPT cmp yes no)
    443 (NE (XORconst [1] cmp:(SGT _ _)) yes no) -> (EQ cmp yes no)
    444 (NE (XORconst [1] cmp:(SGTU _ _)) yes no) -> (EQ cmp yes no)
    445 (NE (XORconst [1] cmp:(SGTconst _)) yes no) -> (EQ cmp yes no)
    446 (NE (XORconst [1] cmp:(SGTUconst _)) yes no) -> (EQ cmp yes no)
    447 (EQ (XORconst [1] cmp:(SGT _ _)) yes no) -> (NE cmp yes no)
    448 (EQ (XORconst [1] cmp:(SGTU _ _)) yes no) -> (NE cmp yes no)
    449 (EQ (XORconst [1] cmp:(SGTconst _)) yes no) -> (NE cmp yes no)
    450 (EQ (XORconst [1] cmp:(SGTUconst _)) yes no) -> (NE cmp yes no)
    451 (NE (SGTUconst [1] x) yes no) -> (EQ x yes no)
    452 (EQ (SGTUconst [1] x) yes no) -> (NE x yes no)
    453 (NE (SGTU x (MOVVconst [0])) yes no) -> (NE x yes no)
    454 (EQ (SGTU x (MOVVconst [0])) yes no) -> (EQ x yes no)
    455 (NE (SGTconst [0] x) yes no) -> (LTZ x yes no)
    456 (EQ (SGTconst [0] x) yes no) -> (GEZ x yes no)
    457 (NE (SGT x (MOVVconst [0])) yes no) -> (GTZ x yes no)
    458 (EQ (SGT x (MOVVconst [0])) yes no) -> (LEZ x yes no)
    459 
    460 // fold offset into address
    461 (ADDVconst [off1] (MOVVaddr [off2] {sym} ptr)) -> (MOVVaddr [off1+off2] {sym} ptr)
    462 
    463 // fold address into load/store
    464 (MOVBload  [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVBload  [off1+off2] {sym} ptr mem)
    465 (MOVBUload [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVBUload [off1+off2] {sym} ptr mem)
    466 (MOVHload  [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVHload  [off1+off2] {sym} ptr mem)
    467 (MOVHUload [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVHUload [off1+off2] {sym} ptr mem)
    468 (MOVWload  [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVWload  [off1+off2] {sym} ptr mem)
    469 (MOVWUload [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVWUload [off1+off2] {sym} ptr mem)
    470 (MOVVload  [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVVload  [off1+off2] {sym} ptr mem)
    471 (MOVFload  [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVFload  [off1+off2] {sym} ptr mem)
    472 (MOVDload  [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVDload  [off1+off2] {sym} ptr mem)
    473 
    474 (MOVBstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVBstore [off1+off2] {sym} ptr val mem)
    475 (MOVHstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVHstore [off1+off2] {sym} ptr val mem)
    476 (MOVWstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVWstore [off1+off2] {sym} ptr val mem)
    477 (MOVVstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVVstore [off1+off2] {sym} ptr val mem)
    478 (MOVFstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVFstore [off1+off2] {sym} ptr val mem)
    479 (MOVDstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVDstore [off1+off2] {sym} ptr val mem)
    480 (MOVBstorezero [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVBstorezero [off1+off2] {sym} ptr mem)
    481 (MOVHstorezero [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVHstorezero [off1+off2] {sym} ptr mem)
    482 (MOVWstorezero [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVWstorezero [off1+off2] {sym} ptr mem)
    483 (MOVVstorezero [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVVstorezero [off1+off2] {sym} ptr mem)
    484 
    485 (MOVBload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    486 	(MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
    487 (MOVBUload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    488 	(MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
    489 (MOVHload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    490 	(MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
    491 (MOVHUload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    492 	(MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
    493 (MOVWload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    494 	(MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
    495 (MOVWUload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    496 	(MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
    497 (MOVVload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    498 	(MOVVload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
    499 (MOVFload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    500 	(MOVFload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
    501 (MOVDload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    502 	(MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
    503 
    504 (MOVBstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    505 	(MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
    506 (MOVHstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    507 	(MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
    508 (MOVWstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    509 	(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
    510 (MOVVstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    511 	(MOVVstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
    512 (MOVFstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    513 	(MOVFstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
    514 (MOVDstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    515 	(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
    516 (MOVBstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    517 	(MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
    518 (MOVHstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    519 	(MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
    520 (MOVWstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    521 	(MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
    522 (MOVVstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
    523 	(MOVVstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
    524 
    525 // store zero
    526 (MOVBstore [off] {sym} ptr (MOVVconst [0]) mem) -> (MOVBstorezero [off] {sym} ptr mem)
    527 (MOVHstore [off] {sym} ptr (MOVVconst [0]) mem) -> (MOVHstorezero [off] {sym} ptr mem)
    528 (MOVWstore [off] {sym} ptr (MOVVconst [0]) mem) -> (MOVWstorezero [off] {sym} ptr mem)
    529 (MOVVstore [off] {sym} ptr (MOVVconst [0]) mem) -> (MOVVstorezero [off] {sym} ptr mem)
    530 
    531 // don't extend after proper load
    532 (MOVBreg x:(MOVBload _ _)) -> (MOVVreg x)
    533 (MOVBUreg x:(MOVBUload _ _)) -> (MOVVreg x)
    534 (MOVHreg x:(MOVBload _ _)) -> (MOVVreg x)
    535 (MOVHreg x:(MOVBUload _ _)) -> (MOVVreg x)
    536 (MOVHreg x:(MOVHload _ _)) -> (MOVVreg x)
    537 (MOVHUreg x:(MOVBUload _ _)) -> (MOVVreg x)
    538 (MOVHUreg x:(MOVHUload _ _)) -> (MOVVreg x)
    539 (MOVWreg x:(MOVBload _ _)) -> (MOVVreg x)
    540 (MOVWreg x:(MOVBUload _ _)) -> (MOVVreg x)
    541 (MOVWreg x:(MOVHload _ _)) -> (MOVVreg x)
    542 (MOVWreg x:(MOVHUload _ _)) -> (MOVVreg x)
    543 (MOVWreg x:(MOVWload _ _)) -> (MOVVreg x)
    544 (MOVWUreg x:(MOVBUload _ _)) -> (MOVVreg x)
    545 (MOVWUreg x:(MOVHUload _ _)) -> (MOVVreg x)
    546 (MOVWUreg x:(MOVWUload _ _)) -> (MOVVreg x)
    547 
    548 // fold double extensions
    549 (MOVBreg x:(MOVBreg _)) -> (MOVVreg x)
    550 (MOVBUreg x:(MOVBUreg _)) -> (MOVVreg x)
    551 (MOVHreg x:(MOVBreg _)) -> (MOVVreg x)
    552 (MOVHreg x:(MOVBUreg _)) -> (MOVVreg x)
    553 (MOVHreg x:(MOVHreg _)) -> (MOVVreg x)
    554 (MOVHUreg x:(MOVBUreg _)) -> (MOVVreg x)
    555 (MOVHUreg x:(MOVHUreg _)) -> (MOVVreg x)
    556 (MOVWreg x:(MOVBreg _)) -> (MOVVreg x)
    557 (MOVWreg x:(MOVBUreg _)) -> (MOVVreg x)
    558 (MOVWreg x:(MOVHreg _)) -> (MOVVreg x)
    559 (MOVWreg x:(MOVHreg _)) -> (MOVVreg x)
    560 (MOVWreg x:(MOVWreg _)) -> (MOVVreg x)
    561 (MOVWUreg x:(MOVBUreg _)) -> (MOVVreg x)
    562 (MOVWUreg x:(MOVHUreg _)) -> (MOVVreg x)
    563 (MOVWUreg x:(MOVWUreg _)) -> (MOVVreg x)
    564 
    565 // don't extend before store
    566 (MOVBstore [off] {sym} ptr (MOVBreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
    567 (MOVBstore [off] {sym} ptr (MOVBUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
    568 (MOVBstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
    569 (MOVBstore [off] {sym} ptr (MOVHUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
    570 (MOVBstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
    571 (MOVBstore [off] {sym} ptr (MOVWUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
    572 (MOVHstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
    573 (MOVHstore [off] {sym} ptr (MOVHUreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
    574 (MOVHstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
    575 (MOVHstore [off] {sym} ptr (MOVWUreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
    576 (MOVWstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
    577 (MOVWstore [off] {sym} ptr (MOVWUreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
    578 
    579 // if a register move has only 1 use, just use the same register without emitting instruction
    580 // MOVVnop doesn't emit instruction, only for ensuring the type.
    581 (MOVVreg x) && x.Uses == 1 -> (MOVVnop x)
    582 
    583 // fold constant into arithmatic ops
    584 (ADDV (MOVVconst [c]) x) && is32Bit(c) -> (ADDVconst [c] x)
    585 (ADDV x (MOVVconst [c])) && is32Bit(c) -> (ADDVconst [c] x)
    586 (SUBV x (MOVVconst [c])) && is32Bit(c) -> (SUBVconst [c] x)
    587 (AND (MOVVconst [c]) x) && is32Bit(c) -> (ANDconst [c] x)
    588 (AND x (MOVVconst [c])) && is32Bit(c) -> (ANDconst [c] x)
    589 (OR  (MOVVconst [c]) x) && is32Bit(c) -> (ORconst  [c] x)
    590 (OR  x (MOVVconst [c])) && is32Bit(c) -> (ORconst  [c] x)
    591 (XOR (MOVVconst [c]) x) && is32Bit(c) -> (XORconst [c] x)
    592 (XOR x (MOVVconst [c])) && is32Bit(c) -> (XORconst [c] x)
    593 (NOR (MOVVconst [c]) x) && is32Bit(c) -> (NORconst [c] x)
    594 (NOR x (MOVVconst [c])) && is32Bit(c) -> (NORconst [c] x)
    595 
    596 (SLLV _ (MOVVconst [c])) && uint64(c)>=64 -> (MOVVconst [0])
    597 (SRLV _ (MOVVconst [c])) && uint64(c)>=64 -> (MOVVconst [0])
    598 (SRAV x (MOVVconst [c])) && uint64(c)>=64 -> (SRAVconst x [63])
    599 (SLLV x (MOVVconst [c])) -> (SLLVconst x [c])
    600 (SRLV x (MOVVconst [c])) -> (SRLVconst x [c])
    601 (SRAV x (MOVVconst [c])) -> (SRAVconst x [c])
    602 
    603 (SGT  (MOVVconst [c]) x) && is32Bit(c) -> (SGTconst  [c] x)
    604 (SGTU (MOVVconst [c]) x) && is32Bit(c) -> (SGTUconst [c] x)
    605 
    606 // mul by constant
    607 (Select1 (MULVU x (MOVVconst [-1]))) -> (NEGV x)
    608 (Select1 (MULVU _ (MOVVconst [0]))) -> (MOVVconst [0])
    609 (Select1 (MULVU x (MOVVconst [1]))) -> x
    610 (Select1 (MULVU x (MOVVconst [c]))) && isPowerOfTwo(c) -> (SLLVconst [log2(c)] x)
    611 
    612 (Select1 (MULVU (MOVVconst [-1]) x)) -> (NEGV x)
    613 (Select1 (MULVU (MOVVconst [0]) _)) -> (MOVVconst [0])
    614 (Select1 (MULVU (MOVVconst [1]) x)) -> x
    615 (Select1 (MULVU (MOVVconst [c]) x)) && isPowerOfTwo(c) -> (SLLVconst [log2(c)] x)
    616 
    617 // div by constant
    618 (Select1 (DIVVU x (MOVVconst [1]))) -> x
    619 (Select1 (DIVVU x (MOVVconst [c]))) && isPowerOfTwo(c) -> (SRLVconst [log2(c)] x)
    620 (Select0 (DIVVU _ (MOVVconst [1]))) -> (MOVVconst [0])                       // mod
    621 (Select0 (DIVVU x (MOVVconst [c]))) && isPowerOfTwo(c) -> (ANDconst [c-1] x) // mod
    622 
    623 // generic simplifications
    624 (ADDV x (NEGV y)) -> (SUBV x y)
    625 (ADDV (NEGV y) x) -> (SUBV x y)
    626 (SUBV x x) -> (MOVVconst [0])
    627 (SUBV (MOVVconst [0]) x) -> (NEGV x)
    628 (AND x x) -> x
    629 (OR  x x) -> x
    630 (XOR x x) -> (MOVVconst [0])
    631 
    632 // remove redundant *const ops
    633 (ADDVconst [0]  x) -> x
    634 (SUBVconst [0]  x) -> x
    635 (ANDconst [0]  _) -> (MOVVconst [0])
    636 (ANDconst [-1] x) -> x
    637 (ORconst  [0]  x) -> x
    638 (ORconst  [-1] _) -> (MOVVconst [-1])
    639 (XORconst [0]  x) -> x
    640 (XORconst [-1] x) -> (NORconst [0] x)
    641 
    642 // generic constant folding
    643 (ADDVconst [c] (MOVVconst [d]))  -> (MOVVconst [c+d])
    644 (ADDVconst [c] (ADDVconst [d] x)) && is32Bit(c+d) -> (ADDVconst [c+d] x)
    645 (ADDVconst [c] (SUBVconst [d] x)) && is32Bit(c-d) -> (ADDVconst [c-d] x)
    646 (SUBVconst [c] (MOVVconst [d]))  -> (MOVVconst [d-c])
    647 (SUBVconst [c] (SUBVconst [d] x)) && is32Bit(-c-d) -> (ADDVconst [-c-d] x)
    648 (SUBVconst [c] (ADDVconst [d] x)) && is32Bit(-c+d) -> (ADDVconst [-c+d] x)
    649 (SLLVconst [c] (MOVVconst [d]))  -> (MOVVconst [int64(d)<<uint64(c)])
    650 (SRLVconst [c] (MOVVconst [d]))  -> (MOVVconst [int64(uint64(d)>>uint64(c))])
    651 (SRAVconst [c] (MOVVconst [d]))  -> (MOVVconst [int64(d)>>uint64(c)])
    652 (Select1 (MULVU (MOVVconst [c]) (MOVVconst [d]))) -> (MOVVconst [c*d])
    653 (Select1 (DIVV  (MOVVconst [c]) (MOVVconst [d]))) -> (MOVVconst [int64(c)/int64(d)])
    654 (Select1 (DIVVU (MOVVconst [c]) (MOVVconst [d]))) -> (MOVVconst [int64(uint64(c)/uint64(d))])
    655 (Select0 (DIVV  (MOVVconst [c]) (MOVVconst [d]))) -> (MOVVconst [int64(c)%int64(d)])   // mod
    656 (Select0 (DIVVU (MOVVconst [c]) (MOVVconst [d]))) -> (MOVVconst [int64(uint64(c)%uint64(d))]) // mod
    657 (ANDconst [c] (MOVVconst [d])) -> (MOVVconst [c&d])
    658 (ANDconst [c] (ANDconst [d] x)) -> (ANDconst [c&d] x)
    659 (ORconst [c] (MOVVconst [d])) -> (MOVVconst [c|d])
    660 (ORconst [c] (ORconst [d] x)) && is32Bit(c|d) -> (ORconst [c|d] x)
    661 (XORconst [c] (MOVVconst [d])) -> (MOVVconst [c^d])
    662 (XORconst [c] (XORconst [d] x)) && is32Bit(c^d) -> (XORconst [c^d] x)
    663 (NORconst [c] (MOVVconst [d])) -> (MOVVconst [^(c|d)])
    664 (NEGV (MOVVconst [c])) -> (MOVVconst [-c])
    665 (MOVBreg  (MOVVconst [c])) -> (MOVVconst [int64(int8(c))])
    666 (MOVBUreg (MOVVconst [c])) -> (MOVVconst [int64(uint8(c))])
    667 (MOVHreg  (MOVVconst [c])) -> (MOVVconst [int64(int16(c))])
    668 (MOVHUreg (MOVVconst [c])) -> (MOVVconst [int64(uint16(c))])
    669 (MOVWreg  (MOVVconst [c])) -> (MOVVconst [int64(int32(c))])
    670 (MOVWUreg (MOVVconst [c])) -> (MOVVconst [int64(uint32(c))])
    671 (MOVVreg  (MOVVconst [c])) -> (MOVVconst [c])
    672 
    673 // constant comparisons
    674 (SGTconst [c] (MOVVconst [d])) && int64(c)>int64(d) -> (MOVVconst [1])
    675 (SGTconst [c] (MOVVconst [d])) && int64(c)<=int64(d) -> (MOVVconst [0])
    676 (SGTUconst [c] (MOVVconst [d])) && uint64(c)>uint64(d) -> (MOVVconst [1])
    677 (SGTUconst [c] (MOVVconst [d])) && uint64(c)<=uint64(d) -> (MOVVconst [0])
    678 
    679 // other known comparisons
    680 (SGTconst [c] (MOVBreg _)) && 0x7f < int64(c) -> (MOVVconst [1])
    681 (SGTconst [c] (MOVBreg _)) && int64(c) <= -0x80 -> (MOVVconst [0])
    682 (SGTconst [c] (MOVBUreg _)) && 0xff < int64(c) -> (MOVVconst [1])
    683 (SGTconst [c] (MOVBUreg _)) && int64(c) < 0 -> (MOVVconst [0])
    684 (SGTUconst [c] (MOVBUreg _)) && 0xff < uint64(c) -> (MOVVconst [1])
    685 (SGTconst [c] (MOVHreg _)) && 0x7fff < int64(c) -> (MOVVconst [1])
    686 (SGTconst [c] (MOVHreg _)) && int64(c) <= -0x8000 -> (MOVVconst [0])
    687 (SGTconst [c] (MOVHUreg _)) && 0xffff < int64(c) -> (MOVVconst [1])
    688 (SGTconst [c] (MOVHUreg _)) && int64(c) < 0 -> (MOVVconst [0])
    689 (SGTUconst [c] (MOVHUreg _)) && 0xffff < uint64(c) -> (MOVVconst [1])
    690 (SGTconst [c] (MOVWUreg _)) && int64(c) < 0 -> (MOVVconst [0])
    691 (SGTconst [c] (ANDconst [m] _)) && 0 <= m && m < c -> (MOVVconst [1])
    692 (SGTUconst [c] (ANDconst [m] _)) && uint64(m) < uint64(c) -> (MOVVconst [1])
    693 (SGTconst [c] (SRLVconst _ [d])) && 0 <= c && 0 < d && d <= 63 && 1<<uint64(64-d) <= c -> (MOVVconst [1])
    694 (SGTUconst [c] (SRLVconst _ [d])) && 0 < d && d <= 63 && 1<<uint64(64-d) <= uint64(c) -> (MOVVconst [1])
    695 
    696 // absorb constants into branches
    697 (EQ  (MOVVconst [0]) yes no) -> (First nil yes no)
    698 (EQ  (MOVVconst [c]) yes no) && c != 0 -> (First nil no yes)
    699 (NE  (MOVVconst [0]) yes no) -> (First nil no yes)
    700 (NE  (MOVVconst [c]) yes no) && c != 0 -> (First nil yes no)
    701 (LTZ (MOVVconst [c]) yes no) && c <  0 -> (First nil yes no)
    702 (LTZ (MOVVconst [c]) yes no) && c >= 0 -> (First nil no yes)
    703 (LEZ (MOVVconst [c]) yes no) && c <= 0 -> (First nil yes no)
    704 (LEZ (MOVVconst [c]) yes no) && c >  0 -> (First nil no yes)
    705 (GTZ (MOVVconst [c]) yes no) && c >  0 -> (First nil yes no)
    706 (GTZ (MOVVconst [c]) yes no) && c <= 0 -> (First nil no yes)
    707 (GEZ (MOVVconst [c]) yes no) && c >= 0 -> (First nil yes no)
    708 (GEZ (MOVVconst [c]) yes no) && c <  0 -> (First nil no yes)
    709