Text file src/cmd/compile/internal/ssa/_gen/Wasm.rules

     1  // Copyright 2018 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  (Last ___) => v.Args[len(v.Args)-1]
     6  
     7  // Lowering arithmetic
     8  (Add(64|32|16|8|Ptr) ...) => (I64Add ...)
     9  (Add(64|32)F ...) => (F(64|32)Add ...)
    10  
    11  (Sub(64|32|16|8|Ptr) ...) => (I64Sub ...)
    12  (Sub(64|32)F ...) => (F(64|32)Sub ...)
    13  
    14  (Mul(64|32|16|8) ...) => (I64Mul ...)
    15  (Mul(64|32)F ...) => (F(64|32)Mul ...)
    16  
    17  (Div64 [false] x y) => (I64DivS x y)
    18  (Div32 [false] x y) => (I64DivS (SignExt32to64 x) (SignExt32to64 y))
    19  (Div16 [false] x y) => (I64DivS (SignExt16to64 x) (SignExt16to64 y))
    20  (Div8          x y) => (I64DivS (SignExt8to64 x) (SignExt8to64 y))
    21  (Div64u ...) => (I64DivU ...)
    22  (Div32u x y) => (I64DivU (ZeroExt32to64 x) (ZeroExt32to64 y))
    23  (Div16u x y) => (I64DivU (ZeroExt16to64 x) (ZeroExt16to64 y))
    24  (Div8u  x y) => (I64DivU (ZeroExt8to64 x) (ZeroExt8to64 y))
    25  (Div(64|32)F ...) => (F(64|32)Div ...)
    26  
    27  (Min(64|32)F ...) => (F(64|32)Min ...)
    28  (Max(64|32)F ...) => (F(64|32)Max ...)
    29  
    30  (Mod64 [false] x y) => (I64RemS x y)
    31  (Mod32 [false] x y) => (I64RemS (SignExt32to64 x) (SignExt32to64 y))
    32  (Mod16 [false] x y) => (I64RemS (SignExt16to64 x) (SignExt16to64 y))
    33  (Mod8          x y) => (I64RemS (SignExt8to64  x) (SignExt8to64  y))
    34  (Mod64u ...) => (I64RemU ...)
    35  (Mod32u x y) => (I64RemU (ZeroExt32to64 x) (ZeroExt32to64 y))
    36  (Mod16u x y) => (I64RemU (ZeroExt16to64 x) (ZeroExt16to64 y))
    37  (Mod8u  x y) => (I64RemU (ZeroExt8to64  x) (ZeroExt8to64  y))
    38  
    39  (And(64|32|16|8|B) ...) => (I64And ...)
    40  
    41  (Or(64|32|16|8|B) ...) => (I64Or ...)
    42  
    43  (Xor(64|32|16|8) ...) => (I64Xor ...)
    44  
    45  (Neg(64|32|16|8) x) => (I64Sub (I64Const [0]) x)
    46  (Neg(64|32)F ...) => (F(64|32)Neg ...)
    47  
    48  (Com(64|32|16|8) x) => (I64Xor x (I64Const [-1]))
    49  
    50  (Not ...) => (I64Eqz ...)
    51  
    52  (Avg64u x y) => (I64Add (I64ShrU (I64Sub x y) (I64Const [1])) y)
    53  
    54  // High word of multiply without carry bits; see Hacker's Delight, 2nd. ed, Figure 8-2, p. 174.
    55  (Hmul64 <t> x y) =>
    56  	(Last <t>
    57  		x0: (ZeroExt32to64 x)
    58  		x1: (I64ShrS x (I64Const [32]))
    59  		y0: (ZeroExt32to64 y)
    60  		y1: (I64ShrS y (I64Const [32]))
    61  		x0y0: (I64Mul x0 y0)
    62  		tt: (I64Add (I64Mul x1 y0) (I64ShrU x0y0 (I64Const [32])))
    63  		w1: (I64Add (I64Mul x0 y1) (ZeroExt32to64 tt))
    64  		w2: (I64ShrS tt (I64Const [32]))
    65  		(I64Add (I64Add (I64Mul x1 y1) w2) (I64ShrS w1 (I64Const [32]))))
    66  
    67  // Same as Hmul64 but signed shifts now unsigned.
    68  (Hmul64u <t> x y) =>
    69  	(Last <t>
    70  		x0: (ZeroExt32to64 x)
    71  		x1: (I64ShrU x (I64Const [32]))
    72  		y0: (ZeroExt32to64 y)
    73  		y1: (I64ShrU y (I64Const [32]))
    74  		w0: (I64Mul x0 y0)
    75  		tt: (I64Add (I64Mul x1 y0) (I64ShrU w0 (I64Const [32])))
    76  		w1: (I64Add (I64Mul x0 y1) (ZeroExt32to64 tt))
    77  		w2: (I64ShrU tt (I64Const [32]))
    78  		hi: (I64Add (I64Add (I64Mul x1 y1) w2) (I64ShrU w1 (I64Const [32]))))
    79  
    80  (Select0 <t> (Mul64uhilo x y)) => (Hmul64u <t> x y)
    81  (Select1 <t> (Mul64uhilo x y)) => (I64Mul x y)
    82  
    83  // Lowering pointer arithmetic
    84  (OffPtr ...) => (I64AddConst ...)
    85  
    86  // Lowering extension
    87  // It is unnecessary to extend loads
    88  (SignExt32to64        x:(I64Load32S _ _)) => x
    89  (SignExt16to(64|32)   x:(I64Load16S _ _)) => x
    90  (SignExt8to(64|32|16) x:(I64Load8S  _ _)) => x
    91  (ZeroExt32to64        x:(I64Load32U _ _)) => x
    92  (ZeroExt16to(64|32)   x:(I64Load16U _ _)) => x
    93  (ZeroExt8to(64|32|16) x:(I64Load8U  _ _)) => x
    94  (SignExt32to64        x) => (I64Extend32S x)
    95  (SignExt8to(64|32|16) x) => (I64Extend8S x)
    96  (SignExt16to(64|32)   x) => (I64Extend16S x)
    97  (ZeroExt32to64        x) => (I64And x (I64Const [0xffffffff]))
    98  (ZeroExt16to(64|32)   x) => (I64And x (I64Const [0xffff]))
    99  (ZeroExt8to(64|32|16) x) => (I64And x (I64Const [0xff]))
   100  
   101  (Slicemask x) => (I64ShrS (I64Sub (I64Const [0]) x) (I64Const [63]))
   102  
   103  // Lowering truncation
   104  // Because we ignore the high parts, truncates are just copies.
   105  (Trunc64to(32|16|8) ...) => (Copy ...)
   106  (Trunc32to(16|8)    ...) => (Copy ...)
   107  (Trunc16to8         ...) => (Copy ...)
   108  
   109  // Lowering float <=> int
   110  (Cvt32to(64|32)F x) => (F(64|32)ConvertI64S (SignExt32to64 x))
   111  (Cvt64to(64|32)F ...) => (F(64|32)ConvertI64S ...)
   112  (Cvt32Uto(64|32)F x) => (F(64|32)ConvertI64U (ZeroExt32to64 x))
   113  (Cvt64Uto(64|32)F ...) => (F(64|32)ConvertI64U ...)
   114  
   115  (Cvt32Fto32 ...) => (I64TruncSatF32S ...)
   116  (Cvt32Fto64 ...) => (I64TruncSatF32S ...)
   117  (Cvt64Fto32 ...) => (I64TruncSatF64S ...)
   118  (Cvt64Fto64 ...) => (I64TruncSatF64S ...)
   119  (Cvt32Fto32U ...) => (I64TruncSatF32U ...)
   120  (Cvt32Fto64U ...) => (I64TruncSatF32U ...)
   121  (Cvt64Fto32U ...) => (I64TruncSatF64U ...)
   122  (Cvt64Fto64U ...) => (I64TruncSatF64U ...)
   123  
   124  (Cvt32Fto64F ...) => (F64PromoteF32 ...)
   125  (Cvt64Fto32F ...) => (F32DemoteF64 ...)
   126  
   127  (CvtBoolToUint8 ...) => (Copy ...)
   128  
   129  (Round32F ...) => (Copy ...)
   130  (Round64F ...) => (Copy ...)
   131  
   132  // Lowering shifts
   133  // Unsigned shifts need to return 0 if shift amount is >= width of shifted value.
   134  
   135  (Lsh64x64 x y) && ssa.ShiftIsBounded(v) => (I64Shl x y)
   136  (Lsh64x64 x (I64Const [c])) && uint64(c) < 64 => (I64Shl x (I64Const [c]))
   137  (Lsh64x64 x (I64Const [c])) && uint64(c) >= 64 => (I64Const [0])
   138  (Lsh64x64 x y) => (Select (I64Shl x y) (I64Const [0]) (I64LtU y (I64Const [64])))
   139  (Lsh64x(32|16|8) [c] x y) => (Lsh64x64 [c] x (ZeroExt(32|16|8)to64 y))
   140  
   141  (Lsh32x64 ...) => (Lsh64x64 ...)
   142  (Lsh32x(32|16|8) [c] x y) => (Lsh64x64 [c] x (ZeroExt(32|16|8)to64 y))
   143  
   144  (Lsh16x64 ...) => (Lsh64x64 ...)
   145  (Lsh16x(32|16|8) [c] x y) => (Lsh64x64 [c] x (ZeroExt(32|16|8)to64 y))
   146  
   147  (Lsh8x64 ...) => (Lsh64x64 ...)
   148  (Lsh8x(32|16|8) [c] x y) => (Lsh64x64 [c] x (ZeroExt(32|16|8)to64 y))
   149  
   150  (Rsh64Ux64 x y) && ssa.ShiftIsBounded(v) => (I64ShrU x y)
   151  (Rsh64Ux64 x (I64Const [c])) && uint64(c) < 64 => (I64ShrU x (I64Const [c]))
   152  (Rsh64Ux64 x (I64Const [c])) && uint64(c) >= 64 => (I64Const [0])
   153  (Rsh64Ux64 x y) => (Select (I64ShrU x y) (I64Const [0]) (I64LtU y (I64Const [64])))
   154  (Rsh64Ux(32|16|8) [c] x y) => (Rsh64Ux64 [c] x (ZeroExt(32|16|8)to64 y))
   155  
   156  (Rsh32Ux64 [c] x y) => (Rsh64Ux64 [c] (ZeroExt32to64 x) y)
   157  (Rsh32Ux(32|16|8) [c] x y) => (Rsh64Ux64 [c] (ZeroExt32to64 x) (ZeroExt(32|16|8)to64 y))
   158  
   159  (Rsh16Ux64 [c] x y) => (Rsh64Ux64 [c] (ZeroExt16to64 x) y)
   160  (Rsh16Ux(32|16|8) [c] x y) => (Rsh64Ux64 [c] (ZeroExt16to64 x) (ZeroExt(32|16|8)to64 y))
   161  
   162  (Rsh8Ux64 [c] x y) => (Rsh64Ux64 [c] (ZeroExt8to64 x) y)
   163  (Rsh8Ux(32|16|8) [c] x y) => (Rsh64Ux64 [c] (ZeroExt8to64 x) (ZeroExt(32|16|8)to64 y))
   164  
   165  // Signed right shift needs to return 0/-1 if shift amount is >= width of shifted value.
   166  // We implement this by setting the shift value to (width - 1) if the shift value is >= width.
   167  
   168  (Rsh64x64 x y) && ssa.ShiftIsBounded(v) => (I64ShrS x y)
   169  (Rsh64x64 x (I64Const [c])) && uint64(c) < 64 => (I64ShrS x (I64Const [c]))
   170  (Rsh64x64 x (I64Const [c])) && uint64(c) >= 64 => (I64ShrS x (I64Const [63]))
   171  (Rsh64x64 x y) => (I64ShrS x (Select <typ.Int64> y (I64Const [63]) (I64LtU y (I64Const [64]))))
   172  (Rsh64x(32|16|8) [c] x y) => (Rsh64x64 [c] x (ZeroExt(32|16|8)to64 y))
   173  
   174  (Rsh32x64 [c] x y) => (Rsh64x64 [c] (SignExt32to64 x) y)
   175  (Rsh32x(32|16|8) [c] x y) => (Rsh64x64 [c] (SignExt32to64 x) (ZeroExt(32|16|8)to64 y))
   176  
   177  (Rsh16x64 [c] x y) => (Rsh64x64 [c] (SignExt16to64 x) y)
   178  (Rsh16x(32|16|8) [c] x y) => (Rsh64x64 [c] (SignExt16to64 x) (ZeroExt(32|16|8)to64 y))
   179  
   180  (Rsh8x64 [c] x y)  => (Rsh64x64 [c] (SignExt8to64 x) y)
   181  (Rsh8x(32|16|8) [c] x y)  => (Rsh64x64 [c] (SignExt8to64 x) (ZeroExt(32|16|8)to64 y))
   182  
   183  // Lowering rotates
   184  (RotateLeft8 <t> x (I64Const [c])) => (Or8 (Lsh8x64 <t> x (I64Const [c&7])) (Rsh8Ux64 <t> x (I64Const [-c&7])))
   185  (RotateLeft16 <t> x (I64Const [c])) => (Or16 (Lsh16x64 <t> x (I64Const [c&15])) (Rsh16Ux64 <t> x (I64Const [-c&15])))
   186  (RotateLeft32 ...) => (I32Rotl ...)
   187  (RotateLeft64 ...) => (I64Rotl ...)
   188  
   189  // Lowering comparisons
   190  (Less64  ...) => (I64LtS ...)
   191  (Less32  x y) => (I64LtS (SignExt32to64 x) (SignExt32to64 y))
   192  (Less16  x y) => (I64LtS (SignExt16to64 x) (SignExt16to64 y))
   193  (Less8   x y) => (I64LtS (SignExt8to64  x) (SignExt8to64  y))
   194  (Less64U ...) => (I64LtU ...)
   195  (Less32U x y) => (I64LtU (ZeroExt32to64 x) (ZeroExt32to64 y))
   196  (Less16U x y) => (I64LtU (ZeroExt16to64 x) (ZeroExt16to64 y))
   197  (Less8U  x y) => (I64LtU (ZeroExt8to64  x) (ZeroExt8to64  y))
   198  (Less(64|32)F ...) => (F(64|32)Lt ...)
   199  
   200  (Leq64  ...) => (I64LeS ...)
   201  (Leq32  x y) => (I64LeS (SignExt32to64 x) (SignExt32to64 y))
   202  (Leq16  x y) => (I64LeS (SignExt16to64 x) (SignExt16to64 y))
   203  (Leq8   x y) => (I64LeS (SignExt8to64  x) (SignExt8to64  y))
   204  (Leq64U ...) => (I64LeU ...)
   205  (Leq32U x y) => (I64LeU (ZeroExt32to64 x) (ZeroExt32to64 y))
   206  (Leq16U x y) => (I64LeU (ZeroExt16to64 x) (ZeroExt16to64 y))
   207  (Leq8U  x y) => (I64LeU (ZeroExt8to64  x) (ZeroExt8to64  y))
   208  (Leq(64|32)F ...) => (F(64|32)Le ...)
   209  
   210  (Eq64  ...) => (I64Eq ...)
   211  (Eq32  x y) => (I64Eq (ZeroExt32to64 x) (ZeroExt32to64 y))
   212  (Eq16  x y) => (I64Eq (ZeroExt16to64 x) (ZeroExt16to64 y))
   213  (Eq8   x y) => (I64Eq (ZeroExt8to64  x) (ZeroExt8to64  y))
   214  (EqB   ...) => (I64Eq ...)
   215  (EqPtr ...) => (I64Eq ...)
   216  (Eq(64|32)F ...) => (F(64|32)Eq ...)
   217  
   218  (Neq64  ...) => (I64Ne ...)
   219  (Neq32  x y) => (I64Ne (ZeroExt32to64 x) (ZeroExt32to64 y))
   220  (Neq16  x y) => (I64Ne (ZeroExt16to64 x) (ZeroExt16to64 y))
   221  (Neq8   x y) => (I64Ne (ZeroExt8to64  x) (ZeroExt8to64  y))
   222  (NeqB   ...) => (I64Ne ...)
   223  (NeqPtr ...) => (I64Ne ...)
   224  (Neq(64|32)F ...) => (F(64|32)Ne ...)
   225  
   226  // Lowering loads
   227  (Load <t> ptr mem) && ssa.Is32BitFloat(t) => (F32Load ptr mem)
   228  (Load <t> ptr mem) && ssa.Is64BitFloat(t) => (F64Load ptr mem)
   229  (Load <t> ptr mem) && t.Size() == 16 => (V128Load ptr mem)
   230  (Load <t> ptr mem) && t.Size() == 8 => (I64Load ptr mem)
   231  (Load <t> ptr mem) && t.Size() == 4 && !t.IsSigned() => (I64Load32U ptr mem)
   232  (Load <t> ptr mem) && t.Size() == 4 &&  t.IsSigned() => (I64Load32S ptr mem)
   233  (Load <t> ptr mem) && t.Size() == 2 && !t.IsSigned() => (I64Load16U ptr mem)
   234  (Load <t> ptr mem) && t.Size() == 2 &&  t.IsSigned() => (I64Load16S ptr mem)
   235  (Load <t> ptr mem) && t.Size() == 1 && !t.IsSigned() => (I64Load8U ptr mem)
   236  (Load <t> ptr mem) && t.Size() == 1 &&  t.IsSigned() => (I64Load8S ptr mem)
   237  
   238  // Lowering stores
   239  (Store {t} ptr val mem) && ssa.Is64BitFloat(t) => (F64Store ptr val mem)
   240  (Store {t} ptr val mem) && ssa.Is32BitFloat(t) => (F32Store ptr val mem)
   241  (Store {t} ptr val mem) && t.Size() == 16 => (V128Store ptr val mem)
   242  (Store {t} ptr val mem) && t.Size() == 8 => (I64Store ptr val mem)
   243  (Store {t} ptr val mem) && t.Size() == 4 => (I64Store32 ptr val mem)
   244  (Store {t} ptr val mem) && t.Size() == 2 => (I64Store16 ptr val mem)
   245  (Store {t} ptr val mem) && t.Size() == 1 => (I64Store8 ptr val mem)
   246  
   247  (ZeroSIMD ...) => (V128Zero ...)
   248  
   249  // Lowering moves
   250  (Move [0] _ _ mem) => mem
   251  (Move [1] dst src mem) => (I64Store8 dst (I64Load8U src mem) mem)
   252  (Move [2] dst src mem) => (I64Store16 dst (I64Load16U src mem) mem)
   253  (Move [4] dst src mem) => (I64Store32 dst (I64Load32U src mem) mem)
   254  (Move [8] dst src mem) => (I64Store dst (I64Load src mem) mem)
   255  (Move [16] dst src mem) =>
   256  	(I64Store [8] dst (I64Load [8] src mem)
   257  		(I64Store dst (I64Load src mem) mem))
   258  (Move [3] dst src mem) =>
   259  	(I64Store8 [2] dst (I64Load8U [2] src mem)
   260  		(I64Store16 dst (I64Load16U src mem) mem))
   261  (Move [5] dst src mem) =>
   262  	(I64Store8 [4] dst (I64Load8U [4] src mem)
   263  		(I64Store32 dst (I64Load32U src mem) mem))
   264  (Move [6] dst src mem) =>
   265  	(I64Store16 [4] dst (I64Load16U [4] src mem)
   266  		(I64Store32 dst (I64Load32U src mem) mem))
   267  (Move [7] dst src mem) =>
   268  	(I64Store32 [3] dst (I64Load32U [3] src mem)
   269  		(I64Store32 dst (I64Load32U src mem) mem))
   270  (Move [s] dst src mem) && s > 8 && s < 16 =>
   271  	(I64Store [s-8] dst (I64Load [s-8] src mem)
   272  		(I64Store dst (I64Load src mem) mem))
   273  
   274  // Large copying uses helper.
   275  (Move [s] dst src mem) && ssa.LogLargeCopyValue(v, s) =>
   276  	(LoweredMove [s] dst src mem)
   277  
   278  // Lowering Zero instructions
   279  (Zero [0] _ mem) => mem
   280  (Zero [1] destptr mem) => (I64Store8 destptr (I64Const [0]) mem)
   281  (Zero [2] destptr mem) => (I64Store16 destptr (I64Const [0]) mem)
   282  (Zero [4] destptr mem) => (I64Store32 destptr (I64Const [0]) mem)
   283  (Zero [8] destptr mem) => (I64Store destptr (I64Const [0]) mem)
   284  
   285  (Zero [3] destptr mem) =>
   286  	(I64Store8 [2] destptr (I64Const [0])
   287  		(I64Store16 destptr (I64Const [0]) mem))
   288  (Zero [5] destptr mem) =>
   289  	(I64Store8 [4] destptr (I64Const [0])
   290  		(I64Store32 destptr (I64Const [0]) mem))
   291  (Zero [6] destptr mem) =>
   292  	(I64Store16 [4] destptr (I64Const [0])
   293  		(I64Store32 destptr (I64Const [0]) mem))
   294  (Zero [7] destptr mem) =>
   295  	(I64Store32 [3] destptr (I64Const [0])
   296  		(I64Store32 destptr (I64Const [0]) mem))
   297  
   298  // Strip off any fractional word zeroing.
   299  (Zero [s] destptr mem) && s%8 != 0 && s > 8 && s < 32 =>
   300  	(Zero [s-s%8] (OffPtr <destptr.Type> destptr [s%8])
   301  		(I64Store destptr (I64Const [0]) mem))
   302  
   303  // Zero small numbers of words directly.
   304  (Zero [16] destptr mem) =>
   305  	(I64Store [8] destptr (I64Const [0])
   306  		(I64Store destptr (I64Const [0]) mem))
   307  (Zero [24] destptr mem) =>
   308  	(I64Store [16] destptr (I64Const [0])
   309  		(I64Store [8] destptr (I64Const [0])
   310  			(I64Store destptr (I64Const [0]) mem)))
   311  (Zero [32] destptr mem) =>
   312  	(I64Store [24] destptr (I64Const [0])
   313  		(I64Store [16] destptr (I64Const [0])
   314  			(I64Store [8] destptr (I64Const [0])
   315  				(I64Store destptr (I64Const [0]) mem))))
   316  
   317  // Large zeroing uses helper.
   318  (Zero [s] destptr mem) =>
   319  	(LoweredZero [s] destptr mem)
   320  
   321  // Lowering constants
   322  (Const64 ...) => (I64Const ...)
   323  (Const(32|16|8) [c]) => (I64Const [int64(c)])
   324  (Const(64|32)F ...) => (F(64|32)Const ...)
   325  (ConstNil) => (I64Const [0])
   326  (ConstBool [c]) => (I64Const [ssa.B2i(c)])
   327  
   328  // Lowering calls
   329  (StaticCall ...) => (LoweredStaticCall ...)
   330  (ClosureCall ...) => (LoweredClosureCall ...)
   331  (InterCall ...) => (LoweredInterCall ...)
   332  (TailCall ...) => (LoweredTailCall ...)
   333  (TailCallInter ...) => (LoweredTailCallInter ...)
   334  
   335  // Miscellaneous
   336  (Convert ...) => (LoweredConvert ...)
   337  (IsNonNil p) => (I64Eqz (I64Eqz p))
   338  (IsInBounds ...) => (I64LtU ...)
   339  (IsSliceInBounds ...) => (I64LeU ...)
   340  (NilCheck ...) => (LoweredNilCheck ...)
   341  (GetClosurePtr ...) => (LoweredGetClosurePtr ...)
   342  (GetCallerPC ...) => (LoweredGetCallerPC ...)
   343  (GetCallerSP ...) => (LoweredGetCallerSP ...)
   344  (Addr {sym} base) => (LoweredAddr {sym} [0] base)
   345  (LocalAddr <t> {sym} base mem) && t.Elem().HasPointers() => (LoweredAddr {sym} (SPanchored base mem))
   346  (LocalAddr <t> {sym} base _)  && !t.Elem().HasPointers() => (LoweredAddr {sym} base)
   347  
   348  // Write barrier.
   349  (WB ...) => (LoweredWB ...)
   350  
   351  // --- Intrinsics ---
   352  (Sqrt ...) => (F64Sqrt ...)
   353  (Trunc ...) => (F64Trunc ...)
   354  (Ceil ...) => (F64Ceil ...)
   355  (Floor ...) => (F64Floor ...)
   356  (RoundToEven ...) => (F64Nearest ...)
   357  (Abs ...) => (F64Abs ...)
   358  (Copysign ...) => (F64Copysign ...)
   359  
   360  (F32DemoteF64 (F64(Sqrt|Trunc|Ceil|Floor|Nearest|Abs) (F64PromoteF32 x))) => (F32(Sqrt|Trunc|Ceil|Floor|Nearest|Abs) x)
   361  (F32DemoteF64 (F64Copysign (F64PromoteF32 x) (F64PromoteF32 y))) => (F32Copysign x y)
   362  
   363  (Sqrt32 ...) => (F32Sqrt ...)
   364  
   365  (Ctz64 ...) => (I64Ctz ...)
   366  (Ctz32 x) => (I64Ctz (I64Or x (I64Const [0x100000000])))
   367  (Ctz16 x) => (I64Ctz (I64Or x (I64Const [0x10000])))
   368  (Ctz8  x) => (I64Ctz (I64Or x (I64Const [0x100])))
   369  
   370  (Ctz(64|32|16|8)NonZero ...) => (I64Ctz ...)
   371  
   372  (BitLen64 x) => (I64Sub (I64Const [64]) (I64Clz x))
   373  (BitLen(32|16|8) x) => (BitLen64 (ZeroExt(32|16|8)to64 x))
   374  
   375  (PopCount64 ...) => (I64Popcnt ...)
   376  (PopCount32 x) => (I64Popcnt (ZeroExt32to64 x))
   377  (PopCount16 x) => (I64Popcnt (ZeroExt16to64 x))
   378  (PopCount8  x) => (I64Popcnt (ZeroExt8to64  x))
   379  
   380  (CondSelect ...) => (Select ...)
   381  
   382  // --- Optimizations ---
   383  (I64Add (I64Const [x]) (I64Const [y])) => (I64Const [x + y])
   384  (I64Sub (I64Const [x]) (I64Const [y])) => (I64Const [x - y])
   385  (I64Mul (I64Const [x]) (I64Const [y])) => (I64Const [x * y])
   386  (I64And (I64Const [x]) (I64Const [y])) => (I64Const [x & y])
   387  (I64Or  (I64Const [x]) (I64Const [y])) => (I64Const [x | y])
   388  (I64Xor (I64Const [x]) (I64Const [y])) => (I64Const [x ^ y])
   389  (F64Add (F64Const [x]) (F64Const [y])) => (F64Const [x + y])
   390  (F64Mul (F64Const [x]) (F64Const [y])) && !math.IsNaN(x * y) => (F64Const [x * y])
   391  (I64Eq  (I64Const [x]) (I64Const [y])) && x == y => (I64Const [1])
   392  (I64Eq  (I64Const [x]) (I64Const [y])) && x != y => (I64Const [0])
   393  (I64Ne  (I64Const [x]) (I64Const [y])) && x == y => (I64Const [0])
   394  (I64Ne  (I64Const [x]) (I64Const [y])) && x != y => (I64Const [1])
   395  
   396  (I64Shl (I64Const [x]) (I64Const [y])) => (I64Const [x << uint64(y)])
   397  (I64ShrU (I64Const [x]) (I64Const [y])) => (I64Const [int64(uint64(x) >> uint64(y))])
   398  (I64ShrS (I64Const [x]) (I64Const [y])) => (I64Const [x >> uint64(y)])
   399  
   400  // Identity and absorption rules for AND/OR/XOR/MUL.
   401  // These fire on nodes created during or after lowering.
   402  (I64And x (I64Const [-1])) => x
   403  (I64And x (I64Const [0])) => (I64Const [0])
   404  (I64Or  x (I64Const [0])) => x
   405  (I64Or  x (I64Const [-1])) => (I64Const [-1])
   406  (I64Xor x (I64Const [0])) => x
   407  (I64Mul x (I64Const [0])) => (I64Const [0])
   408  (I64Mul x (I64Const [1])) => x
   409  
   410  // Double-mask elimination: cascaded zero-extensions produce
   411  // (I64And (I64And x C1) C2) which can be collapsed to a single mask.
   412  (I64And (I64And x (I64Const [c1])) (I64Const [c2])) => (I64And x (I64Const [c1 & c2]))
   413  
   414  // Redundant sign-extensions: idempotent and narrower-subsumes-wider.
   415  (I64Extend32S (I64Extend32S x)) => (I64Extend32S x)
   416  (I64Extend16S (I64Extend16S x)) => (I64Extend16S x)
   417  (I64Extend8S  (I64Extend8S  x)) => (I64Extend8S  x)
   418  (I64Extend32S (I64Extend16S x)) => (I64Extend16S x)
   419  (I64Extend32S (I64Extend8S  x)) => (I64Extend8S  x)
   420  (I64Extend16S (I64Extend8S  x)) => (I64Extend8S  x)
   421  
   422  // Sign-extend of a value already zero-extended from fewer bits is a no-op.
   423  // E.g. (I64Extend32S (I64And x (I64Const [0xff]))) — top 33 bits are already
   424  // zero, so sign-extending from 32 is identity.
   425  (I64Extend32S x:(I64And _ (I64Const [c]))) && c >= 0 && int64(int32(c)) == c => x
   426  (I64Extend16S x:(I64And _ (I64Const [c]))) && c >= 0 && int64(int16(c)) == c => x
   427  (I64Extend8S  x:(I64And _ (I64Const [c]))) && c >= 0 && int64(int8(c))  == c => x
   428  
   429  // Narrow loads already extend their results.
   430  (I64Extend32S x:(I64Load32S _ _)) => x
   431  (I64Extend16S x:(I64Load16S _ _)) => x
   432  (I64Extend8S  x:(I64Load8S  _ _)) => x
   433  (I64And x:(I64Load32U _ _) (I64Const [0xffffffff])) => x
   434  (I64And x:(I64Load16U _ _) (I64Const [0xffff]))     => x
   435  (I64And x:(I64Load8U  _ _) (I64Const [0xff]))       => x
   436  
   437  // genssa sign-extends signed arguments of 32 bits or less.
   438  (I64Extend32S x:(Arg <t>)) && t.Size() == 4 && t.IsSigned() => x
   439  (I64Extend16S x:(Arg <t>)) && t.Size() == 2 && t.IsSigned() => x
   440  (I64Extend8S  x:(Arg <t>)) && t.Size() == 1 && t.IsSigned() => x
   441  
   442  // Fold sign extensions of constants.
   443  (I64Extend32S (I64Const [c])) => (I64Const [int64(int32(c))])
   444  (I64Extend16S (I64Const [c])) => (I64Const [int64(int16(c))])
   445  (I64Extend8S  (I64Const [c])) => (I64Const [int64(int8(c))])
   446  
   447  // TODO: declare these operations as commutative and get rid of these rules?
   448  (I64Add (I64Const [x]) y) && y.Op != ssaop.OpWasmI64Const => (I64Add y (I64Const [x]))
   449  (I64Mul (I64Const [x]) y) && y.Op != ssaop.OpWasmI64Const => (I64Mul y (I64Const [x]))
   450  (I64And (I64Const [x]) y) && y.Op != ssaop.OpWasmI64Const => (I64And y (I64Const [x]))
   451  (I64Or  (I64Const [x]) y) && y.Op != ssaop.OpWasmI64Const => (I64Or  y (I64Const [x]))
   452  (I64Xor (I64Const [x]) y) && y.Op != ssaop.OpWasmI64Const => (I64Xor y (I64Const [x]))
   453  (F64Add (F64Const [x]) y) && y.Op != ssaop.OpWasmF64Const => (F64Add y (F64Const [x]))
   454  (F64Mul (F64Const [x]) y) && y.Op != ssaop.OpWasmF64Const => (F64Mul y (F64Const [x]))
   455  (I64Eq  (I64Const [x]) y) && y.Op != ssaop.OpWasmI64Const => (I64Eq y  (I64Const [x]))
   456  (I64Ne  (I64Const [x]) y) && y.Op != ssaop.OpWasmI64Const => (I64Ne y  (I64Const [x]))
   457  
   458  (I64Eq x (I64Const [0])) => (I64Eqz x)
   459  (I64LtU (I64Const [0]) x) => (I64Eqz (I64Eqz x))
   460  (I64LeU x (I64Const [0])) => (I64Eqz x)
   461  (I64LtU x (I64Const [1])) => (I64Eqz x)
   462  (I64LeU (I64Const [1]) x) => (I64Eqz (I64Eqz x))
   463  (I64Ne x (I64Const [0])) => (I64Eqz (I64Eqz x))
   464  
   465  (I64Add x (I64Const <t> [y])) && !t.IsPtr() => (I64AddConst [y] x)
   466  (I64AddConst [0] x) => x
   467  (I64Eqz (I64Eqz (I64Eqz x))) => (I64Eqz x)
   468  
   469  // folding offset into load/store
   470  ((I64Load|I64Load32U|I64Load32S|I64Load16U|I64Load16S|I64Load8U|I64Load8S) [off] (I64AddConst [off2] ptr) mem)
   471  	&& ssa.IsU32Bit(off+off2) =>
   472  	((I64Load|I64Load32U|I64Load32S|I64Load16U|I64Load16S|I64Load8U|I64Load8S) [off+off2] ptr mem)
   473  
   474  ((I64Store|I64Store32|I64Store16|I64Store8) [off] (I64AddConst [off2] ptr) val mem)
   475  	&& ssa.IsU32Bit(off+off2) =>
   476  	((I64Store|I64Store32|I64Store16|I64Store8) [off+off2] ptr val mem)
   477  
   478  // folding offset into address
   479  (I64AddConst [off] (LoweredAddr {sym} [off2] base)) && ssa.IsU32Bit(off+int64(off2)) =>
   480  	(LoweredAddr {sym} [int32(off)+off2] base)
   481  (I64AddConst [off] x:(SP)) && ssa.IsU32Bit(off) => (LoweredAddr [int32(off)] x) // so it is rematerializeable
   482  
   483  // transforming readonly globals into constants
   484  (I64Load [off] (LoweredAddr {sym} [off2] (SB)) _) && ssa.SymIsRO(sym) && ssa.IsU32Bit(off+int64(off2)) => (I64Const [int64(ssa.Read64(sym, off+int64(off2), config.Ctxt.Arch.ByteOrder))])
   485  (I64Load32U [off] (LoweredAddr {sym} [off2] (SB)) _) && ssa.SymIsRO(sym) && ssa.IsU32Bit(off+int64(off2)) => (I64Const [int64(ssa.Read32(sym, off+int64(off2), config.Ctxt.Arch.ByteOrder))])
   486  (I64Load16U [off] (LoweredAddr {sym} [off2] (SB)) _) && ssa.SymIsRO(sym) && ssa.IsU32Bit(off+int64(off2)) => (I64Const [int64(ssa.Read16(sym, off+int64(off2), config.Ctxt.Arch.ByteOrder))])
   487  (I64Load8U [off] (LoweredAddr {sym} [off2] (SB)) _) && ssa.SymIsRO(sym) && ssa.IsU32Bit(off+int64(off2)) => (I64Const [int64(ssa.Read8(sym, off+int64(off2)))])
   488  (I64Load32S [off] (LoweredAddr {sym} [off2] (SB)) _) && ssa.SymIsRO(sym) && ssa.IsU32Bit(off+int64(off2)) => (I64Const [int64(int32(ssa.Read32(sym, off+int64(off2), config.Ctxt.Arch.ByteOrder)))])
   489  (I64Load16S [off] (LoweredAddr {sym} [off2] (SB)) _) && ssa.SymIsRO(sym) && ssa.IsU32Bit(off+int64(off2)) => (I64Const [int64(int16(ssa.Read16(sym, off+int64(off2), config.Ctxt.Arch.ByteOrder)))])
   490  (I64Load8S [off] (LoweredAddr {sym} [off2] (SB)) _) && ssa.SymIsRO(sym) && ssa.IsU32Bit(off+int64(off2)) => (I64Const [int64(int8(ssa.Read8(sym, off+int64(off2))))])
   491  

View as plain text