github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/cmd/compile/internal/ssa/gen/S390X.rules (about)

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