Home | History | Annotate | Download | only in WebAssembly
      1 // WebAssemblyInstrMemory.td-WebAssembly Memory codegen support -*- tablegen -*-
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 ///
     10 /// \file
     11 /// WebAssembly Memory operand code-gen constructs.
     12 ///
     13 //===----------------------------------------------------------------------===//
     14 
     15 // TODO:
     16 //  - HasAddr64
     17 //  - WebAssemblyTargetLowering having to do with atomics
     18 //  - Each has optional alignment.
     19 
     20 // WebAssembly has i8/i16/i32/i64/f32/f64 memory types, but doesn't have i8/i16
     21 // local types. These memory-only types instead zero- or sign-extend into local
     22 // types when loading, and truncate when storing.
     23 
     24 // WebAssembly constant offsets are performed as unsigned with infinite
     25 // precision, so we need to check for NoUnsignedWrap so that we don't fold an
     26 // offset for an add that needs wrapping.
     27 def regPlusImm : PatFrag<(ops node:$addr, node:$off),
     28                          (add node:$addr, node:$off),
     29                          [{ return N->getFlags().hasNoUnsignedWrap(); }]>;
     30 
     31 // Treat an 'or' node as an 'add' if the or'ed bits are known to be zero.
     32 def or_is_add : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{
     33   if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))
     34     return CurDAG->MaskedValueIsZero(N->getOperand(0), CN->getAPIntValue());
     35 
     36   KnownBits Known0;
     37   CurDAG->computeKnownBits(N->getOperand(0), Known0, 0);
     38   KnownBits Known1;
     39   CurDAG->computeKnownBits(N->getOperand(1), Known1, 0);
     40   return (~Known0.Zero & ~Known1.Zero) == 0;
     41 }]>;
     42 
     43 // GlobalAddresses are conceptually unsigned values, so we can also fold them
     44 // into immediate values as long as the add is 'nuw'.
     45 // TODO: We'd like to also match GA offsets but there are cases where the
     46 // register can have a negative value. Find out what more we can do.
     47 def regPlusGA : PatFrag<(ops node:$addr, node:$off),
     48                         (add node:$addr, node:$off),
     49                         [{
     50   return N->getFlags().hasNoUnsignedWrap();
     51 }]>;
     52 
     53 // We don't need a regPlusES because external symbols never have constant
     54 // offsets folded into them, so we can just use add.
     55 
     56 let Defs = [ARGUMENTS] in {
     57 
     58 // Defines atomic and non-atomic loads, regular and extending.
     59 multiclass WebAssemblyLoad<WebAssemblyRegClass rc, string Name, int Opcode> {
     60   defm "": I<(outs rc:$dst),
     61              (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
     62              (outs), (ins P2Align:$p2align, offset32_op:$off),
     63              [], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"),
     64              !strconcat(Name, "\t${off}, ${p2align}"), Opcode>;
     65 }
     66 
     67 // Basic load.
     68 // FIXME: When we can break syntax compatibility, reorder the fields in the
     69 // asmstrings to match the binary encoding.
     70 defm LOAD_I32 : WebAssemblyLoad<I32, "i32.load", 0x28>;
     71 defm LOAD_I64 : WebAssemblyLoad<I64, "i64.load", 0x29>;
     72 defm LOAD_F32 : WebAssemblyLoad<F32, "f32.load", 0x2a>;
     73 defm LOAD_F64 : WebAssemblyLoad<F64, "f64.load", 0x2b>;
     74 
     75 } // Defs = [ARGUMENTS]
     76 
     77 // Select loads with no constant offset.
     78 class LoadPatNoOffset<ValueType ty, PatFrag kind, NI inst> :
     79   Pat<(ty (kind I32:$addr)), (inst 0, 0, I32:$addr)>;
     80 
     81 def : LoadPatNoOffset<i32, load, LOAD_I32>;
     82 def : LoadPatNoOffset<i64, load, LOAD_I64>;
     83 def : LoadPatNoOffset<f32, load, LOAD_F32>;
     84 def : LoadPatNoOffset<f64, load, LOAD_F64>;
     85 
     86 
     87 // Select loads with a constant offset.
     88 
     89 // Pattern with address + immediate offset
     90 class LoadPatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
     91   Pat<(ty (kind (operand I32:$addr, imm:$off))), (inst 0, imm:$off, I32:$addr)>;
     92 
     93 def : LoadPatImmOff<i32, load, regPlusImm, LOAD_I32>;
     94 def : LoadPatImmOff<i64, load, regPlusImm, LOAD_I64>;
     95 def : LoadPatImmOff<f32, load, regPlusImm, LOAD_F32>;
     96 def : LoadPatImmOff<f64, load, regPlusImm, LOAD_F64>;
     97 def : LoadPatImmOff<i32, load, or_is_add, LOAD_I32>;
     98 def : LoadPatImmOff<i64, load, or_is_add, LOAD_I64>;
     99 def : LoadPatImmOff<f32, load, or_is_add, LOAD_F32>;
    100 def : LoadPatImmOff<f64, load, or_is_add, LOAD_F64>;
    101 
    102 class LoadPatGlobalAddr<ValueType ty, PatFrag kind, NI inst> :
    103   Pat<(ty (kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)))),
    104       (inst 0, tglobaladdr:$off, I32:$addr)>;
    105 
    106 def : LoadPatGlobalAddr<i32, load, LOAD_I32>;
    107 def : LoadPatGlobalAddr<i64, load, LOAD_I64>;
    108 def : LoadPatGlobalAddr<f32, load, LOAD_F32>;
    109 def : LoadPatGlobalAddr<f64, load, LOAD_F64>;
    110 
    111 class LoadPatExternalSym<ValueType ty, PatFrag kind, NI inst> :
    112   Pat<(ty (kind (add I32:$addr, (WebAssemblywrapper texternalsym:$off)))),
    113       (inst 0, texternalsym:$off, I32:$addr)>;
    114 def : LoadPatExternalSym<i32, load, LOAD_I32>;
    115 def : LoadPatExternalSym<i64, load, LOAD_I64>;
    116 def : LoadPatExternalSym<f32, load, LOAD_F32>;
    117 def : LoadPatExternalSym<f64, load, LOAD_F64>;
    118 
    119 
    120 // Select loads with just a constant offset.
    121 class LoadPatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
    122   Pat<(ty (kind imm:$off)), (inst 0, imm:$off, (CONST_I32 0))>;
    123 
    124 def : LoadPatOffsetOnly<i32, load, LOAD_I32>;
    125 def : LoadPatOffsetOnly<i64, load, LOAD_I64>;
    126 def : LoadPatOffsetOnly<f32, load, LOAD_F32>;
    127 def : LoadPatOffsetOnly<f64, load, LOAD_F64>;
    128 
    129 class LoadPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
    130   Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off))),
    131       (inst 0, tglobaladdr:$off, (CONST_I32 0))>;
    132 
    133 def : LoadPatGlobalAddrOffOnly<i32, load, LOAD_I32>;
    134 def : LoadPatGlobalAddrOffOnly<i64, load, LOAD_I64>;
    135 def : LoadPatGlobalAddrOffOnly<f32, load, LOAD_F32>;
    136 def : LoadPatGlobalAddrOffOnly<f64, load, LOAD_F64>;
    137 
    138 class LoadPatExternSymOffOnly<ValueType ty, PatFrag kind, NI inst> :
    139   Pat<(ty (kind (WebAssemblywrapper texternalsym:$off))),
    140       (inst 0, texternalsym:$off, (CONST_I32 0))>;
    141 def : LoadPatExternSymOffOnly<i32, load, LOAD_I32>;
    142 def : LoadPatExternSymOffOnly<i64, load, LOAD_I64>;
    143 def : LoadPatExternSymOffOnly<f32, load, LOAD_F32>;
    144 def : LoadPatExternSymOffOnly<f64, load, LOAD_F64>;
    145 
    146 let Defs = [ARGUMENTS] in {
    147 
    148 // Extending load.
    149 defm LOAD8_S_I32 : WebAssemblyLoad<I32, "i32.load8_s", 0x2c>;
    150 defm LOAD8_U_I32 : WebAssemblyLoad<I32, "i32.load8_u", 0x2d>;
    151 defm LOAD16_S_I32 : WebAssemblyLoad<I32, "i32.load16_s", 0x2e>;
    152 defm LOAD16_U_I32 : WebAssemblyLoad<I32, "i32.load16_u", 0x2f>;
    153 defm LOAD8_S_I64 : WebAssemblyLoad<I64, "i64.load8_s", 0x30>;
    154 defm LOAD8_U_I64 : WebAssemblyLoad<I64, "i64.load8_u", 0x31>;
    155 defm LOAD16_S_I64 : WebAssemblyLoad<I64, "i64.load16_s", 0x32>;
    156 defm LOAD16_U_I64 : WebAssemblyLoad<I64, "i64.load16_u", 0x33>;
    157 defm LOAD32_S_I64 : WebAssemblyLoad<I64, "i64.load32_s", 0x34>;
    158 defm LOAD32_U_I64 : WebAssemblyLoad<I64, "i64.load32_u", 0x35>;
    159 
    160 } // Defs = [ARGUMENTS]
    161 
    162 // Select extending loads with no constant offset.
    163 def : LoadPatNoOffset<i32, sextloadi8, LOAD8_S_I32>;
    164 def : LoadPatNoOffset<i32, zextloadi8, LOAD8_U_I32>;
    165 def : LoadPatNoOffset<i32, sextloadi16, LOAD16_S_I32>;
    166 def : LoadPatNoOffset<i32, zextloadi16, LOAD16_U_I32>;
    167 def : LoadPatNoOffset<i64, sextloadi8, LOAD8_S_I64>;
    168 def : LoadPatNoOffset<i64, zextloadi8, LOAD8_U_I64>;
    169 def : LoadPatNoOffset<i64, sextloadi16, LOAD16_S_I64>;
    170 def : LoadPatNoOffset<i64, zextloadi16, LOAD16_U_I64>;
    171 def : LoadPatNoOffset<i64, sextloadi32, LOAD32_S_I64>;
    172 def : LoadPatNoOffset<i64, zextloadi32, LOAD32_U_I64>;
    173 
    174 // Select extending loads with a constant offset.
    175 def : LoadPatImmOff<i32, sextloadi8, regPlusImm, LOAD8_S_I32>;
    176 def : LoadPatImmOff<i32, zextloadi8, regPlusImm, LOAD8_U_I32>;
    177 def : LoadPatImmOff<i32, sextloadi16, regPlusImm, LOAD16_S_I32>;
    178 def : LoadPatImmOff<i32, zextloadi16, regPlusImm, LOAD16_U_I32>;
    179 def : LoadPatImmOff<i64, sextloadi8, regPlusImm, LOAD8_S_I64>;
    180 def : LoadPatImmOff<i64, zextloadi8, regPlusImm, LOAD8_U_I64>;
    181 def : LoadPatImmOff<i64, sextloadi16, regPlusImm, LOAD16_S_I64>;
    182 def : LoadPatImmOff<i64, zextloadi16, regPlusImm, LOAD16_U_I64>;
    183 def : LoadPatImmOff<i64, sextloadi32, regPlusImm, LOAD32_S_I64>;
    184 def : LoadPatImmOff<i64, zextloadi32, regPlusImm, LOAD32_U_I64>;
    185 
    186 def : LoadPatImmOff<i32, sextloadi8, or_is_add, LOAD8_S_I32>;
    187 def : LoadPatImmOff<i32, zextloadi8, or_is_add, LOAD8_U_I32>;
    188 def : LoadPatImmOff<i32, sextloadi16, or_is_add, LOAD16_S_I32>;
    189 def : LoadPatImmOff<i32, zextloadi16, or_is_add, LOAD16_U_I32>;
    190 def : LoadPatImmOff<i64, sextloadi8, or_is_add, LOAD8_S_I64>;
    191 def : LoadPatImmOff<i64, zextloadi8, or_is_add, LOAD8_U_I64>;
    192 def : LoadPatImmOff<i64, sextloadi16, or_is_add, LOAD16_S_I64>;
    193 def : LoadPatImmOff<i64, zextloadi16, or_is_add, LOAD16_U_I64>;
    194 def : LoadPatImmOff<i64, sextloadi32, or_is_add, LOAD32_S_I64>;
    195 def : LoadPatImmOff<i64, zextloadi32, or_is_add, LOAD32_U_I64>;
    196 
    197 def : LoadPatGlobalAddr<i32, sextloadi8, LOAD8_S_I32>;
    198 def : LoadPatGlobalAddr<i32, zextloadi8, LOAD8_U_I32>;
    199 def : LoadPatGlobalAddr<i32, sextloadi16, LOAD16_S_I32>;
    200 def : LoadPatGlobalAddr<i32, zextloadi8, LOAD16_U_I32>;
    201 
    202 def : LoadPatGlobalAddr<i64, sextloadi8, LOAD8_S_I64>;
    203 def : LoadPatGlobalAddr<i64, zextloadi8, LOAD8_U_I64>;
    204 def : LoadPatGlobalAddr<i64, sextloadi16, LOAD16_S_I64>;
    205 def : LoadPatGlobalAddr<i64, zextloadi16, LOAD16_U_I64>;
    206 def : LoadPatGlobalAddr<i64, sextloadi32, LOAD32_S_I64>;
    207 def : LoadPatGlobalAddr<i64, zextloadi32, LOAD32_U_I64>;
    208 
    209 def : LoadPatExternalSym<i32, sextloadi8, LOAD8_S_I32>;
    210 def : LoadPatExternalSym<i32, zextloadi8, LOAD8_U_I32>;
    211 def : LoadPatExternalSym<i32, sextloadi16, LOAD16_S_I32>;
    212 def : LoadPatExternalSym<i32, zextloadi16, LOAD16_U_I32>;
    213 def : LoadPatExternalSym<i64, sextloadi8, LOAD8_S_I64>;
    214 def : LoadPatExternalSym<i64, zextloadi8, LOAD8_U_I64>;
    215 def : LoadPatExternalSym<i64, sextloadi16, LOAD16_S_I64>;
    216 def : LoadPatExternalSym<i64, zextloadi16, LOAD16_U_I64>;
    217 def : LoadPatExternalSym<i64, sextloadi32, LOAD32_S_I64>;
    218 def : LoadPatExternalSym<i64, zextloadi32, LOAD32_U_I64>;
    219 
    220 
    221 // Select extending loads with just a constant offset.
    222 def : LoadPatOffsetOnly<i32, sextloadi8, LOAD8_S_I32>;
    223 def : LoadPatOffsetOnly<i32, zextloadi8, LOAD8_U_I32>;
    224 def : LoadPatOffsetOnly<i32, sextloadi16, LOAD16_S_I32>;
    225 def : LoadPatOffsetOnly<i32, zextloadi16, LOAD16_U_I32>;
    226 
    227 def : LoadPatOffsetOnly<i64, sextloadi8, LOAD8_S_I64>;
    228 def : LoadPatOffsetOnly<i64, zextloadi8, LOAD8_U_I64>;
    229 def : LoadPatOffsetOnly<i64, sextloadi16, LOAD16_S_I64>;
    230 def : LoadPatOffsetOnly<i64, zextloadi16, LOAD16_U_I64>;
    231 def : LoadPatOffsetOnly<i64, sextloadi32, LOAD32_S_I64>;
    232 def : LoadPatOffsetOnly<i64, zextloadi32, LOAD32_U_I64>;
    233 
    234 def : LoadPatGlobalAddrOffOnly<i32, sextloadi8, LOAD8_S_I32>;
    235 def : LoadPatGlobalAddrOffOnly<i32, zextloadi8, LOAD8_U_I32>;
    236 def : LoadPatGlobalAddrOffOnly<i32, sextloadi16, LOAD16_S_I32>;
    237 def : LoadPatGlobalAddrOffOnly<i32, zextloadi16, LOAD16_U_I32>;
    238 def : LoadPatGlobalAddrOffOnly<i64, sextloadi8, LOAD8_S_I64>;
    239 def : LoadPatGlobalAddrOffOnly<i64, zextloadi8, LOAD8_U_I64>;
    240 def : LoadPatGlobalAddrOffOnly<i64, sextloadi16, LOAD16_S_I64>;
    241 def : LoadPatGlobalAddrOffOnly<i64, zextloadi16, LOAD16_U_I64>;
    242 def : LoadPatGlobalAddrOffOnly<i64, sextloadi32, LOAD32_S_I64>;
    243 def : LoadPatGlobalAddrOffOnly<i64, zextloadi32, LOAD32_U_I64>;
    244 
    245 def : LoadPatExternSymOffOnly<i32, sextloadi8, LOAD8_S_I32>;
    246 def : LoadPatExternSymOffOnly<i32, zextloadi8, LOAD8_U_I32>;
    247 def : LoadPatExternSymOffOnly<i32, sextloadi16, LOAD16_S_I32>;
    248 def : LoadPatExternSymOffOnly<i32, zextloadi16, LOAD16_U_I32>;
    249 def : LoadPatExternSymOffOnly<i64, sextloadi8, LOAD8_S_I64>;
    250 def : LoadPatExternSymOffOnly<i64, zextloadi8, LOAD8_U_I64>;
    251 def : LoadPatExternSymOffOnly<i64, sextloadi16, LOAD16_S_I64>;
    252 def : LoadPatExternSymOffOnly<i64, zextloadi16, LOAD16_U_I64>;
    253 def : LoadPatExternSymOffOnly<i64, sextloadi32, LOAD32_S_I64>;
    254 def : LoadPatExternSymOffOnly<i64, zextloadi32, LOAD32_U_I64>;
    255 
    256 // Resolve "don't care" extending loads to zero-extending loads. This is
    257 // somewhat arbitrary, but zero-extending is conceptually simpler.
    258 
    259 // Select "don't care" extending loads with no constant offset.
    260 def : LoadPatNoOffset<i32, extloadi8, LOAD8_U_I32>;
    261 def : LoadPatNoOffset<i32, extloadi16, LOAD16_U_I32>;
    262 def : LoadPatNoOffset<i64, extloadi8, LOAD8_U_I64>;
    263 def : LoadPatNoOffset<i64, extloadi16, LOAD16_U_I64>;
    264 def : LoadPatNoOffset<i64, extloadi32, LOAD32_U_I64>;
    265 
    266 // Select "don't care" extending loads with a constant offset.
    267 def : LoadPatImmOff<i32, extloadi8, regPlusImm, LOAD8_U_I32>;
    268 def : LoadPatImmOff<i32, extloadi16, regPlusImm, LOAD16_U_I32>;
    269 def : LoadPatImmOff<i64, extloadi8, regPlusImm, LOAD8_U_I64>;
    270 def : LoadPatImmOff<i64, extloadi16, regPlusImm, LOAD16_U_I64>;
    271 def : LoadPatImmOff<i64, extloadi32, regPlusImm, LOAD32_U_I64>;
    272 def : LoadPatImmOff<i32, extloadi8, or_is_add, LOAD8_U_I32>;
    273 def : LoadPatImmOff<i32, extloadi16, or_is_add, LOAD16_U_I32>;
    274 def : LoadPatImmOff<i64, extloadi8, or_is_add, LOAD8_U_I64>;
    275 def : LoadPatImmOff<i64, extloadi16, or_is_add, LOAD16_U_I64>;
    276 def : LoadPatImmOff<i64, extloadi32, or_is_add, LOAD32_U_I64>;
    277 def : LoadPatGlobalAddr<i32, extloadi8, LOAD8_U_I32>;
    278 def : LoadPatGlobalAddr<i32, extloadi16, LOAD16_U_I32>;
    279 def : LoadPatGlobalAddr<i64, extloadi8, LOAD8_U_I64>;
    280 def : LoadPatGlobalAddr<i64, extloadi16, LOAD16_U_I64>;
    281 def : LoadPatGlobalAddr<i64, extloadi32, LOAD32_U_I64>;
    282 def : LoadPatExternalSym<i32, extloadi8, LOAD8_U_I32>;
    283 def : LoadPatExternalSym<i32, extloadi16, LOAD16_U_I32>;
    284 def : LoadPatExternalSym<i64, extloadi8, LOAD8_U_I64>;
    285 def : LoadPatExternalSym<i64, extloadi16, LOAD16_U_I64>;
    286 def : LoadPatExternalSym<i64, extloadi32, LOAD32_U_I64>;
    287 
    288 // Select "don't care" extending loads with just a constant offset.
    289 def : LoadPatOffsetOnly<i32, extloadi8, LOAD8_U_I32>;
    290 def : LoadPatOffsetOnly<i32, extloadi16, LOAD16_U_I32>;
    291 def : LoadPatOffsetOnly<i64, extloadi8, LOAD8_U_I64>;
    292 def : LoadPatOffsetOnly<i64, extloadi16, LOAD16_U_I64>;
    293 def : LoadPatOffsetOnly<i64, extloadi32, LOAD32_U_I64>;
    294 def : LoadPatGlobalAddrOffOnly<i32, extloadi8, LOAD8_U_I32>;
    295 def : LoadPatGlobalAddrOffOnly<i32, extloadi16, LOAD16_U_I32>;
    296 def : LoadPatGlobalAddrOffOnly<i64, extloadi8, LOAD8_U_I64>;
    297 def : LoadPatGlobalAddrOffOnly<i64, extloadi16, LOAD16_U_I64>;
    298 def : LoadPatGlobalAddrOffOnly<i64, extloadi32, LOAD32_U_I64>;
    299 def : LoadPatExternSymOffOnly<i32, extloadi8, LOAD8_U_I32>;
    300 def : LoadPatExternSymOffOnly<i32, extloadi16, LOAD16_U_I32>;
    301 def : LoadPatExternSymOffOnly<i64, extloadi8, LOAD8_U_I64>;
    302 def : LoadPatExternSymOffOnly<i64, extloadi16, LOAD16_U_I64>;
    303 def : LoadPatExternSymOffOnly<i64, extloadi32, LOAD32_U_I64>;
    304 
    305 
    306 let Defs = [ARGUMENTS] in {
    307 
    308 // Defines atomic and non-atomic stores, regular and truncating
    309 multiclass WebAssemblyStore<WebAssemblyRegClass rc, string Name, int Opcode> {
    310   defm "" : I<(outs),
    311               (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
    312               (outs),
    313               (ins P2Align:$p2align, offset32_op:$off), [],
    314               !strconcat(Name, "\t${off}(${addr})${p2align}, $val"),
    315               !strconcat(Name, "\t${off}, ${p2align}"), Opcode>;
    316 }
    317 // Basic store.
    318 // Note: WebAssembly inverts SelectionDAG's usual operand order.
    319 defm STORE_I32  : WebAssemblyStore<I32, "i32.store", 0x36>;
    320 defm STORE_I64  : WebAssemblyStore<I64, "i64.store", 0x37>;
    321 defm STORE_F32  : WebAssemblyStore<F32, "f32.store", 0x38>;
    322 defm STORE_F64  : WebAssemblyStore<F64, "f64.store", 0x39>;
    323 
    324 } // Defs = [ARGUMENTS]
    325 
    326 // Select stores with no constant offset.
    327 class StorePatNoOffset<ValueType ty, PatFrag node, NI inst> :
    328   Pat<(node ty:$val, I32:$addr), (inst 0, 0, I32:$addr, ty:$val)>;
    329 
    330 def : StorePatNoOffset<i32, store, STORE_I32>;
    331 def : StorePatNoOffset<i64, store, STORE_I64>;
    332 def : StorePatNoOffset<f32, store, STORE_F32>;
    333 def : StorePatNoOffset<f64, store, STORE_F64>;
    334 
    335 // Select stores with a constant offset.
    336 class StorePatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
    337   Pat<(kind ty:$val, (operand I32:$addr, imm:$off)),
    338       (inst 0, imm:$off, I32:$addr, ty:$val)>;
    339 
    340 def : StorePatImmOff<i32, store, regPlusImm, STORE_I32>;
    341 def : StorePatImmOff<i64, store, regPlusImm, STORE_I64>;
    342 def : StorePatImmOff<f32, store, regPlusImm, STORE_F32>;
    343 def : StorePatImmOff<f64, store, regPlusImm, STORE_F64>;
    344 def : StorePatImmOff<i32, store, or_is_add, STORE_I32>;
    345 def : StorePatImmOff<i64, store, or_is_add, STORE_I64>;
    346 def : StorePatImmOff<f32, store, or_is_add, STORE_F32>;
    347 def : StorePatImmOff<f64, store, or_is_add, STORE_F64>;
    348 
    349 class StorePatGlobalAddr<ValueType ty, PatFrag kind, NI inst> :
    350   Pat<(kind ty:$val,
    351             (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off))),
    352       (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>;
    353 def : StorePatGlobalAddr<i32, store, STORE_I32>;
    354 def : StorePatGlobalAddr<i64, store, STORE_I64>;
    355 def : StorePatGlobalAddr<f32, store, STORE_F32>;
    356 def : StorePatGlobalAddr<f64, store, STORE_F64>;
    357 
    358 class StorePatExternalSym<ValueType ty, PatFrag kind, NI inst> :
    359   Pat<(kind ty:$val, (add I32:$addr, (WebAssemblywrapper texternalsym:$off))),
    360       (inst 0, texternalsym:$off, I32:$addr, ty:$val)>;
    361 def : StorePatExternalSym<i32, store, STORE_I32>;
    362 def : StorePatExternalSym<i64, store, STORE_I64>;
    363 def : StorePatExternalSym<f32, store, STORE_F32>;
    364 def : StorePatExternalSym<f64, store, STORE_F64>;
    365 
    366 // Select stores with just a constant offset.
    367 class StorePatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
    368   Pat<(kind ty:$val, imm:$off), (inst 0, imm:$off, (CONST_I32 0), ty:$val)>;
    369 def : StorePatOffsetOnly<i32, store, STORE_I32>;
    370 def : StorePatOffsetOnly<i64, store, STORE_I64>;
    371 def : StorePatOffsetOnly<f32, store, STORE_F32>;
    372 def : StorePatOffsetOnly<f64, store, STORE_F64>;
    373 
    374 class StorePatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
    375   Pat<(kind ty:$val, (WebAssemblywrapper tglobaladdr:$off)),
    376       (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>;
    377 def : StorePatGlobalAddrOffOnly<i32, store, STORE_I32>;
    378 def : StorePatGlobalAddrOffOnly<i64, store, STORE_I64>;
    379 def : StorePatGlobalAddrOffOnly<f32, store, STORE_F32>;
    380 def : StorePatGlobalAddrOffOnly<f64, store, STORE_F64>;
    381 
    382 class StorePatExternSymOffOnly<ValueType ty, PatFrag kind, NI inst> :
    383   Pat<(kind ty:$val, (WebAssemblywrapper texternalsym:$off)),
    384       (inst 0, texternalsym:$off, (CONST_I32 0), ty:$val)>;
    385 def : StorePatExternSymOffOnly<i32, store, STORE_I32>;
    386 def : StorePatExternSymOffOnly<i64, store, STORE_I64>;
    387 def : StorePatExternSymOffOnly<f32, store, STORE_F32>;
    388 def : StorePatExternSymOffOnly<f64, store, STORE_F64>;
    389 
    390 
    391 let Defs = [ARGUMENTS] in {
    392 
    393 // Truncating store.
    394 defm STORE8_I32 : WebAssemblyStore<I32, "i32.store8", 0x3a>;
    395 defm STORE16_I32 : WebAssemblyStore<I32, "i32.store16", 0x3b>;
    396 defm STORE8_I64 : WebAssemblyStore<I64, "i64.store8", 0x3c>;
    397 defm STORE16_I64 : WebAssemblyStore<I64, "i64.store16", 0x3d>;
    398 defm STORE32_I64 : WebAssemblyStore<I64, "i64.store32", 0x3e>;
    399 
    400 } // Defs = [ARGUMENTS]
    401 
    402 // Select truncating stores with no constant offset.
    403 def : StorePatNoOffset<i32, truncstorei8, STORE8_I32>;
    404 def : StorePatNoOffset<i32, truncstorei16, STORE16_I32>;
    405 def : StorePatNoOffset<i64, truncstorei8, STORE8_I64>;
    406 def : StorePatNoOffset<i64, truncstorei16, STORE16_I64>;
    407 def : StorePatNoOffset<i64, truncstorei32, STORE32_I64>;
    408 
    409 // Select truncating stores with a constant offset.
    410 def : StorePatImmOff<i32, truncstorei8, regPlusImm, STORE8_I32>;
    411 def : StorePatImmOff<i32, truncstorei16, regPlusImm, STORE16_I32>;
    412 def : StorePatImmOff<i64, truncstorei8, regPlusImm, STORE8_I64>;
    413 def : StorePatImmOff<i64, truncstorei16, regPlusImm, STORE16_I64>;
    414 def : StorePatImmOff<i64, truncstorei32, regPlusImm, STORE32_I64>;
    415 def : StorePatImmOff<i32, truncstorei8, or_is_add, STORE8_I32>;
    416 def : StorePatImmOff<i32, truncstorei16, or_is_add, STORE16_I32>;
    417 def : StorePatImmOff<i64, truncstorei8, or_is_add, STORE8_I64>;
    418 def : StorePatImmOff<i64, truncstorei16, or_is_add, STORE16_I64>;
    419 def : StorePatImmOff<i64, truncstorei32, or_is_add, STORE32_I64>;
    420 
    421 def : StorePatGlobalAddr<i32, truncstorei8, STORE8_I32>;
    422 def : StorePatGlobalAddr<i32, truncstorei16, STORE16_I32>;
    423 def : StorePatGlobalAddr<i64, truncstorei8, STORE8_I64>;
    424 def : StorePatGlobalAddr<i64, truncstorei16, STORE16_I64>;
    425 def : StorePatGlobalAddr<i64, truncstorei32, STORE32_I64>;
    426 def : StorePatExternalSym<i32, truncstorei8, STORE8_I32>;
    427 def : StorePatExternalSym<i32, truncstorei16, STORE16_I32>;
    428 def : StorePatExternalSym<i64, truncstorei8, STORE8_I64>;
    429 def : StorePatExternalSym<i64, truncstorei16, STORE16_I64>;
    430 def : StorePatExternalSym<i64, truncstorei32, STORE32_I64>;
    431 
    432 // Select truncating stores with just a constant offset.
    433 def : StorePatOffsetOnly<i32, truncstorei8, STORE8_I32>;
    434 def : StorePatOffsetOnly<i32, truncstorei16, STORE16_I32>;
    435 def : StorePatOffsetOnly<i64, truncstorei8, STORE8_I64>;
    436 def : StorePatOffsetOnly<i64, truncstorei16, STORE16_I64>;
    437 def : StorePatOffsetOnly<i64, truncstorei32, STORE32_I64>;
    438 def : StorePatGlobalAddrOffOnly<i32, truncstorei8, STORE8_I32>;
    439 def : StorePatGlobalAddrOffOnly<i32, truncstorei16, STORE16_I32>;
    440 def : StorePatGlobalAddrOffOnly<i64, truncstorei8, STORE8_I64>;
    441 def : StorePatGlobalAddrOffOnly<i64, truncstorei16, STORE16_I64>;
    442 def : StorePatGlobalAddrOffOnly<i64, truncstorei32, STORE32_I64>;
    443 def : StorePatExternSymOffOnly<i32, truncstorei8, STORE8_I32>;
    444 def : StorePatExternSymOffOnly<i32, truncstorei16, STORE16_I32>;
    445 def : StorePatExternSymOffOnly<i64, truncstorei8, STORE8_I64>;
    446 def : StorePatExternSymOffOnly<i64, truncstorei16, STORE16_I64>;
    447 def : StorePatExternSymOffOnly<i64, truncstorei32, STORE32_I64>;
    448 
    449 let Defs = [ARGUMENTS] in {
    450 
    451 // Current memory size.
    452 defm MEMORY_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags),
    453                          (outs), (ins i32imm:$flags),
    454                          [(set I32:$dst,
    455                            (int_wasm_memory_size (i32 imm:$flags)))],
    456                          "memory.size\t$dst, $flags", "memory.size\t$flags",
    457                          0x3f>,
    458                        Requires<[HasAddr32]>;
    459 defm MEM_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags),
    460                       (outs), (ins i32imm:$flags),
    461                       [(set I32:$dst, (int_wasm_mem_size (i32 imm:$flags)))],
    462                       "mem.size\t$dst, $flags", "mem.size\t$flags", 0x3f>,
    463                     Requires<[HasAddr32]>;
    464 defm CURRENT_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags),
    465                             (outs), (ins i32imm:$flags),
    466                             [],
    467                             "current_memory\t$dst",
    468                             "current_memory\t$flags", 0x3f>,
    469                           Requires<[HasAddr32]>;
    470 
    471 // Grow memory.
    472 defm MEMORY_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta),
    473                          (outs), (ins i32imm:$flags, I32:$delta),
    474                          [(set I32:$dst,
    475                            (int_wasm_memory_grow (i32 imm:$flags),
    476                              I32:$delta))],
    477                          "memory.grow\t$dst, $flags, $delta",
    478                          "memory.grow\t$flags, $delta", 0x3f>,
    479                        Requires<[HasAddr32]>;
    480 defm MEM_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta),
    481                       (outs), (ins i32imm:$flags),
    482                       [(set I32:$dst,
    483                             (int_wasm_mem_grow (i32 imm:$flags), I32:$delta))],
    484                       "mem.grow\t$dst, $flags, $delta", "mem.grow\t$flags",
    485                       0x3f>,
    486                     Requires<[HasAddr32]>;
    487 defm GROW_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta),
    488                          (outs), (ins i32imm:$flags),
    489                          [],
    490                          "grow_memory\t$dst, $delta", "grow_memory\t$flags",
    491                          0x40>,
    492                        Requires<[HasAddr32]>;
    493 
    494 } // Defs = [ARGUMENTS]
    495 
    496 def : Pat<(int_wasm_current_memory),
    497           (CURRENT_MEMORY_I32 0)>;
    498 def : Pat<(int_wasm_grow_memory I32:$delta),
    499           (GROW_MEMORY_I32 0, $delta)>;
    500