Home | History | Annotate | Download | only in WebAssembly
      1 // WebAssemblyInstrAtomics.td-WebAssembly Atomic 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 Atomic operand code-gen constructs.
     12 ///
     13 //===----------------------------------------------------------------------===//
     14 
     15 //===----------------------------------------------------------------------===//
     16 // Atomic loads
     17 //===----------------------------------------------------------------------===//
     18 
     19 let Defs = [ARGUMENTS] in {
     20 defm ATOMIC_LOAD_I32 : WebAssemblyLoad<I32, "i32.atomic.load", 0xfe10>;
     21 defm ATOMIC_LOAD_I64 : WebAssemblyLoad<I64, "i64.atomic.load", 0xfe11>;
     22 } // Defs = [ARGUMENTS]
     23 
     24 // Select loads with no constant offset.
     25 let Predicates = [HasAtomics] in {
     26 def : LoadPatNoOffset<i32, atomic_load_32, ATOMIC_LOAD_I32>;
     27 def : LoadPatNoOffset<i64, atomic_load_64, ATOMIC_LOAD_I64>;
     28 
     29 // Select loads with a constant offset.
     30 
     31 // Pattern with address + immediate offset
     32 def : LoadPatImmOff<i32, atomic_load_32, regPlusImm, ATOMIC_LOAD_I32>;
     33 def : LoadPatImmOff<i64, atomic_load_64, regPlusImm, ATOMIC_LOAD_I64>;
     34 def : LoadPatImmOff<i32, atomic_load_32, or_is_add, ATOMIC_LOAD_I32>;
     35 def : LoadPatImmOff<i64, atomic_load_64, or_is_add, ATOMIC_LOAD_I64>;
     36 
     37 def : LoadPatGlobalAddr<i32, atomic_load_32, ATOMIC_LOAD_I32>;
     38 def : LoadPatGlobalAddr<i64, atomic_load_64, ATOMIC_LOAD_I64>;
     39 
     40 def : LoadPatExternalSym<i32, atomic_load_32, ATOMIC_LOAD_I32>;
     41 def : LoadPatExternalSym<i64, atomic_load_64, ATOMIC_LOAD_I64>;
     42 
     43 // Select loads with just a constant offset.
     44 def : LoadPatOffsetOnly<i32, atomic_load_32, ATOMIC_LOAD_I32>;
     45 def : LoadPatOffsetOnly<i64, atomic_load_64, ATOMIC_LOAD_I64>;
     46 
     47 def : LoadPatGlobalAddrOffOnly<i32, atomic_load_32, ATOMIC_LOAD_I32>;
     48 def : LoadPatGlobalAddrOffOnly<i64, atomic_load_64, ATOMIC_LOAD_I64>;
     49 
     50 def : LoadPatExternSymOffOnly<i32, atomic_load_32, ATOMIC_LOAD_I32>;
     51 def : LoadPatExternSymOffOnly<i64, atomic_load_64, ATOMIC_LOAD_I64>;
     52 
     53 } // Predicates = [HasAtomics]
     54 
     55 // Extending loads. Note that there are only zero-extending atomic loads, no
     56 // sign-extending loads.
     57 let Defs = [ARGUMENTS] in {
     58 defm ATOMIC_LOAD8_U_I32 : WebAssemblyLoad<I32, "i32.atomic.load8_u", 0xfe12>;
     59 defm ATOMIC_LOAD16_U_I32 : WebAssemblyLoad<I32, "i32.atomic.load16_u", 0xfe13>;
     60 defm ATOMIC_LOAD8_U_I64 : WebAssemblyLoad<I64, "i64.atomic.load8_u", 0xfe14>;
     61 defm ATOMIC_LOAD16_U_I64 : WebAssemblyLoad<I64, "i64.atomic.load16_u", 0xfe15>;
     62 defm ATOMIC_LOAD32_U_I64 : WebAssemblyLoad<I64, "i64.atomic.load32_u", 0xfe16>;
     63 } // Defs = [ARGUMENTS]
     64 
     65 // Fragments for extending loads. These are different from regular loads because
     66 // the SDNodes are derived from AtomicSDNode rather than LoadSDNode and
     67 // therefore don't have the extension type field. So instead of matching that,
     68 // we match the patterns that the type legalizer expands them to.
     69 
     70 // We directly match zext patterns and select the zext atomic loads.
     71 // i32 (zext (i8 (atomic_load_8))) gets legalized to
     72 // i32 (and (i32 (atomic_load_8)), 255)
     73 // These can be selected to a single zero-extending atomic load instruction.
     74 def zext_aload_8_32 :
     75   PatFrag<(ops node:$addr), (and (i32 (atomic_load_8 node:$addr)), 255)>;
     76 def zext_aload_16_32 :
     77   PatFrag<(ops node:$addr), (and (i32 (atomic_load_16 node:$addr)), 65535)>;
     78 // Unlike regular loads, extension to i64 is handled differently than i32.
     79 // i64 (zext (i8 (atomic_load_8))) gets legalized to
     80 // i64 (and (i64 (anyext (i32 (atomic_load_8)))), 255)
     81 def zext_aload_8_64 :
     82   PatFrag<(ops node:$addr),
     83           (and (i64 (anyext (i32 (atomic_load_8 node:$addr)))), 255)>;
     84 def zext_aload_16_64 :
     85   PatFrag<(ops node:$addr),
     86           (and (i64 (anyext (i32 (atomic_load_16 node:$addr)))), 65535)>;
     87 def zext_aload_32_64 :
     88   PatFrag<(ops node:$addr),
     89           (zext (i32 (atomic_load node:$addr)))>;
     90 
     91 // We don't have single sext atomic load instructions. So for sext loads, we
     92 // match bare subword loads (for 32-bit results) and anyext loads (for 64-bit
     93 // results) and select a zext load; the next instruction will be sext_inreg
     94 // which is selected by itself.
     95 def sext_aload_8_64 :
     96   PatFrag<(ops node:$addr), (anyext (i32 (atomic_load_8 node:$addr)))>;
     97 def sext_aload_16_64 :
     98   PatFrag<(ops node:$addr), (anyext (i32 (atomic_load_16 node:$addr)))>;
     99 
    100 let Predicates = [HasAtomics] in {
    101 // Select zero-extending loads with no constant offset.
    102 def : LoadPatNoOffset<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
    103 def : LoadPatNoOffset<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
    104 def : LoadPatNoOffset<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
    105 def : LoadPatNoOffset<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
    106 def : LoadPatNoOffset<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
    107 
    108 // Select sign-extending loads with no constant offset
    109 def : LoadPatNoOffset<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
    110 def : LoadPatNoOffset<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
    111 def : LoadPatNoOffset<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
    112 def : LoadPatNoOffset<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
    113 // 32->64 sext load gets selected as i32.atomic.load, i64.extend_s/i32
    114 
    115 // Zero-extending loads with constant offset
    116 def : LoadPatImmOff<i32, zext_aload_8_32, regPlusImm, ATOMIC_LOAD8_U_I32>;
    117 def : LoadPatImmOff<i32, zext_aload_16_32, regPlusImm, ATOMIC_LOAD16_U_I32>;
    118 def : LoadPatImmOff<i32, zext_aload_8_32, or_is_add, ATOMIC_LOAD8_U_I32>;
    119 def : LoadPatImmOff<i32, zext_aload_16_32, or_is_add, ATOMIC_LOAD16_U_I32>;
    120 def : LoadPatImmOff<i64, zext_aload_8_64, regPlusImm, ATOMIC_LOAD8_U_I64>;
    121 def : LoadPatImmOff<i64, zext_aload_16_64, regPlusImm, ATOMIC_LOAD16_U_I64>;
    122 def : LoadPatImmOff<i64, zext_aload_32_64, regPlusImm, ATOMIC_LOAD32_U_I64>;
    123 def : LoadPatImmOff<i64, zext_aload_8_64, or_is_add, ATOMIC_LOAD8_U_I64>;
    124 def : LoadPatImmOff<i64, zext_aload_16_64, or_is_add, ATOMIC_LOAD16_U_I64>;
    125 def : LoadPatImmOff<i64, zext_aload_32_64, or_is_add, ATOMIC_LOAD32_U_I64>;
    126 
    127 // Sign-extending loads with constant offset
    128 def : LoadPatImmOff<i32, atomic_load_8, regPlusImm, ATOMIC_LOAD8_U_I32>;
    129 def : LoadPatImmOff<i32, atomic_load_16, regPlusImm, ATOMIC_LOAD16_U_I32>;
    130 def : LoadPatImmOff<i32, atomic_load_8, or_is_add, ATOMIC_LOAD8_U_I32>;
    131 def : LoadPatImmOff<i32, atomic_load_16, or_is_add, ATOMIC_LOAD16_U_I32>;
    132 def : LoadPatImmOff<i64, sext_aload_8_64, regPlusImm, ATOMIC_LOAD8_U_I64>;
    133 def : LoadPatImmOff<i64, sext_aload_16_64, regPlusImm, ATOMIC_LOAD16_U_I64>;
    134 def : LoadPatImmOff<i64, sext_aload_8_64, or_is_add, ATOMIC_LOAD8_U_I64>;
    135 def : LoadPatImmOff<i64, sext_aload_16_64, or_is_add, ATOMIC_LOAD16_U_I64>;
    136 // No 32->64 patterns, just use i32.atomic.load and i64.extend_s/i64
    137 
    138 def : LoadPatGlobalAddr<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
    139 def : LoadPatGlobalAddr<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
    140 def : LoadPatGlobalAddr<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
    141 def : LoadPatGlobalAddr<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
    142 def : LoadPatGlobalAddr<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
    143 def : LoadPatGlobalAddr<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
    144 def : LoadPatGlobalAddr<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
    145 def : LoadPatGlobalAddr<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
    146 def : LoadPatGlobalAddr<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
    147 
    148 def : LoadPatExternalSym<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
    149 def : LoadPatExternalSym<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
    150 def : LoadPatExternalSym<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
    151 def : LoadPatExternalSym<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
    152 def : LoadPatExternalSym<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
    153 def : LoadPatExternalSym<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
    154 def : LoadPatExternalSym<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
    155 def : LoadPatExternalSym<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
    156 def : LoadPatExternalSym<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
    157 
    158 // Extending loads with just a constant offset
    159 def : LoadPatOffsetOnly<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
    160 def : LoadPatOffsetOnly<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
    161 def : LoadPatOffsetOnly<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
    162 def : LoadPatOffsetOnly<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
    163 def : LoadPatOffsetOnly<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
    164 def : LoadPatOffsetOnly<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
    165 def : LoadPatOffsetOnly<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
    166 def : LoadPatOffsetOnly<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
    167 def : LoadPatOffsetOnly<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
    168 
    169 def : LoadPatGlobalAddrOffOnly<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
    170 def : LoadPatGlobalAddrOffOnly<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
    171 def : LoadPatGlobalAddrOffOnly<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
    172 def : LoadPatGlobalAddrOffOnly<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
    173 def : LoadPatGlobalAddrOffOnly<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
    174 def : LoadPatGlobalAddrOffOnly<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
    175 def : LoadPatGlobalAddrOffOnly<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
    176 def : LoadPatGlobalAddrOffOnly<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
    177 def : LoadPatGlobalAddrOffOnly<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
    178 
    179 def : LoadPatExternSymOffOnly<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
    180 def : LoadPatExternSymOffOnly<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
    181 def : LoadPatExternSymOffOnly<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
    182 def : LoadPatExternSymOffOnly<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
    183 def : LoadPatExternSymOffOnly<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
    184 def : LoadPatExternSymOffOnly<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
    185 def : LoadPatExternSymOffOnly<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
    186 def : LoadPatExternSymOffOnly<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
    187 def : LoadPatExternSymOffOnly<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
    188 
    189 } // Predicates = [HasAtomics]
    190 
    191 //===----------------------------------------------------------------------===//
    192 // Atomic stores
    193 //===----------------------------------------------------------------------===//
    194 
    195 let Defs = [ARGUMENTS] in {
    196 defm ATOMIC_STORE_I32 : WebAssemblyStore<I32, "i32.atomic.store", 0xfe17>;
    197 defm ATOMIC_STORE_I64 : WebAssemblyStore<I64, "i64.atomic.store", 0xfe18>;
    198 } // Defs = [ARGUMENTS]
    199 
    200 // We need an 'atomic' version of store patterns because store and atomic_store
    201 // nodes have different operand orders:
    202 // store: (store $val, $ptr)
    203 // atomic_store: (store $ptr, $val)
    204 
    205 let Predicates = [HasAtomics] in {
    206 
    207 // Select stores with no constant offset.
    208 class AStorePatNoOffset<ValueType ty, PatFrag kind, NI inst> :
    209   Pat<(kind I32:$addr, ty:$val), (inst 0, 0, I32:$addr, ty:$val)>;
    210 def : AStorePatNoOffset<i32, atomic_store_32, ATOMIC_STORE_I32>;
    211 def : AStorePatNoOffset<i64, atomic_store_64, ATOMIC_STORE_I64>;
    212 
    213 // Select stores with a constant offset.
    214 
    215 // Pattern with address + immediate offset
    216 class AStorePatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
    217   Pat<(kind (operand I32:$addr, imm:$off), ty:$val),
    218       (inst 0, imm:$off, I32:$addr, ty:$val)>;
    219 def : AStorePatImmOff<i32, atomic_store_32, regPlusImm, ATOMIC_STORE_I32>;
    220 def : AStorePatImmOff<i64, atomic_store_64, regPlusImm, ATOMIC_STORE_I64>;
    221 def : AStorePatImmOff<i32, atomic_store_32, or_is_add, ATOMIC_STORE_I32>;
    222 def : AStorePatImmOff<i64, atomic_store_64, or_is_add, ATOMIC_STORE_I64>;
    223 
    224 class AStorePatGlobalAddr<ValueType ty, PatFrag kind, NI inst> :
    225   Pat<(kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)),
    226             ty:$val),
    227       (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>;
    228 def : AStorePatGlobalAddr<i32, atomic_store_32, ATOMIC_STORE_I32>;
    229 def : AStorePatGlobalAddr<i64, atomic_store_64, ATOMIC_STORE_I64>;
    230 
    231 class AStorePatExternalSym<ValueType ty, PatFrag kind, NI inst> :
    232   Pat<(kind (add I32:$addr, (WebAssemblywrapper texternalsym:$off)), ty:$val),
    233       (inst 0, texternalsym:$off, I32:$addr, ty:$val)>;
    234 def : AStorePatExternalSym<i32, atomic_store_32, ATOMIC_STORE_I32>;
    235 def : AStorePatExternalSym<i64, atomic_store_64, ATOMIC_STORE_I64>;
    236 
    237 // Select stores with just a constant offset.
    238 class AStorePatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
    239   Pat<(kind imm:$off, ty:$val), (inst 0, imm:$off, (CONST_I32 0), ty:$val)>;
    240 def : AStorePatOffsetOnly<i32, atomic_store_32, ATOMIC_STORE_I32>;
    241 def : AStorePatOffsetOnly<i64, atomic_store_64, ATOMIC_STORE_I64>;
    242 
    243 class AStorePatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
    244   Pat<(kind (WebAssemblywrapper tglobaladdr:$off), ty:$val),
    245       (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>;
    246 def : AStorePatGlobalAddrOffOnly<i32, atomic_store_32, ATOMIC_STORE_I32>;
    247 def : AStorePatGlobalAddrOffOnly<i64, atomic_store_64, ATOMIC_STORE_I64>;
    248 
    249 class AStorePatExternSymOffOnly<ValueType ty, PatFrag kind, NI inst> :
    250   Pat<(kind (WebAssemblywrapper texternalsym:$off), ty:$val),
    251       (inst 0, texternalsym:$off, (CONST_I32 0), ty:$val)>;
    252 def : AStorePatExternSymOffOnly<i32, atomic_store_32, ATOMIC_STORE_I32>;
    253 def : AStorePatExternSymOffOnly<i64, atomic_store_64, ATOMIC_STORE_I64>;
    254 
    255 } // Predicates = [HasAtomics]
    256 
    257 // Truncating stores.
    258 let Defs = [ARGUMENTS] in {
    259 defm ATOMIC_STORE8_I32 : WebAssemblyStore<I32, "i32.atomic.store8", 0xfe19>;
    260 defm ATOMIC_STORE16_I32 : WebAssemblyStore<I32, "i32.atomic.store16", 0xfe1a>;
    261 defm ATOMIC_STORE8_I64 : WebAssemblyStore<I64, "i64.atomic.store8", 0xfe1b>;
    262 defm ATOMIC_STORE16_I64 : WebAssemblyStore<I64, "i64.atomic.store16", 0xfe1c>;
    263 defm ATOMIC_STORE32_I64 : WebAssemblyStore<I64, "i64.atomic.store32", 0xfe1d>;
    264 } // Defs = [ARGUMENTS]
    265 
    266 // Fragments for truncating stores.
    267 
    268 // We don't have single truncating atomic store instructions. For 32-bit
    269 // instructions, we just need to match bare atomic stores. On the other hand,
    270 // truncating stores from i64 values are once truncated to i32 first.
    271 class trunc_astore_64<PatFrag kind> :
    272   PatFrag<(ops node:$addr, node:$val),
    273           (kind node:$addr, (i32 (trunc (i64 node:$val))))>;
    274 def trunc_astore_8_64 : trunc_astore_64<atomic_store_8>;
    275 def trunc_astore_16_64 : trunc_astore_64<atomic_store_16>;
    276 def trunc_astore_32_64 : trunc_astore_64<atomic_store_32>;
    277 
    278 let Predicates = [HasAtomics] in {
    279 
    280 // Truncating stores with no constant offset
    281 def : AStorePatNoOffset<i32, atomic_store_8, ATOMIC_STORE8_I32>;
    282 def : AStorePatNoOffset<i32, atomic_store_16, ATOMIC_STORE16_I32>;
    283 def : AStorePatNoOffset<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
    284 def : AStorePatNoOffset<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
    285 def : AStorePatNoOffset<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
    286 
    287 // Truncating stores with a constant offset
    288 def : AStorePatImmOff<i32, atomic_store_8, regPlusImm, ATOMIC_STORE8_I32>;
    289 def : AStorePatImmOff<i32, atomic_store_16, regPlusImm, ATOMIC_STORE16_I32>;
    290 def : AStorePatImmOff<i64, trunc_astore_8_64, regPlusImm, ATOMIC_STORE8_I64>;
    291 def : AStorePatImmOff<i64, trunc_astore_16_64, regPlusImm, ATOMIC_STORE16_I64>;
    292 def : AStorePatImmOff<i64, trunc_astore_32_64, regPlusImm, ATOMIC_STORE32_I64>;
    293 def : AStorePatImmOff<i32, atomic_store_8, or_is_add, ATOMIC_STORE8_I32>;
    294 def : AStorePatImmOff<i32, atomic_store_16, or_is_add, ATOMIC_STORE16_I32>;
    295 def : AStorePatImmOff<i64, trunc_astore_8_64, or_is_add, ATOMIC_STORE8_I64>;
    296 def : AStorePatImmOff<i64, trunc_astore_16_64, or_is_add, ATOMIC_STORE16_I64>;
    297 def : AStorePatImmOff<i64, trunc_astore_32_64, or_is_add, ATOMIC_STORE32_I64>;
    298 
    299 def : AStorePatGlobalAddr<i32, atomic_store_8, ATOMIC_STORE8_I32>;
    300 def : AStorePatGlobalAddr<i32, atomic_store_16, ATOMIC_STORE16_I32>;
    301 def : AStorePatGlobalAddr<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
    302 def : AStorePatGlobalAddr<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
    303 def : AStorePatGlobalAddr<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
    304 
    305 def : AStorePatExternalSym<i32, atomic_store_8, ATOMIC_STORE8_I32>;
    306 def : AStorePatExternalSym<i32, atomic_store_16, ATOMIC_STORE16_I32>;
    307 def : AStorePatExternalSym<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
    308 def : AStorePatExternalSym<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
    309 def : AStorePatExternalSym<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
    310 
    311 // Truncating stores with just a constant offset
    312 def : AStorePatOffsetOnly<i32, atomic_store_8, ATOMIC_STORE8_I32>;
    313 def : AStorePatOffsetOnly<i32, atomic_store_16, ATOMIC_STORE16_I32>;
    314 def : AStorePatOffsetOnly<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
    315 def : AStorePatOffsetOnly<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
    316 def : AStorePatOffsetOnly<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
    317 
    318 def : AStorePatGlobalAddrOffOnly<i32, atomic_store_8, ATOMIC_STORE8_I32>;
    319 def : AStorePatGlobalAddrOffOnly<i32, atomic_store_16, ATOMIC_STORE16_I32>;
    320 def : AStorePatGlobalAddrOffOnly<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
    321 def : AStorePatGlobalAddrOffOnly<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
    322 def : AStorePatGlobalAddrOffOnly<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
    323 
    324 def : AStorePatExternSymOffOnly<i32, atomic_store_8, ATOMIC_STORE8_I32>;
    325 def : AStorePatExternSymOffOnly<i32, atomic_store_16, ATOMIC_STORE16_I32>;
    326 def : AStorePatExternSymOffOnly<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
    327 def : AStorePatExternSymOffOnly<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
    328 def : AStorePatExternSymOffOnly<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
    329 
    330 } // Predicates = [HasAtomics]
    331 
    332 //===----------------------------------------------------------------------===//
    333 // Atomic binary read-modify-writes
    334 //===----------------------------------------------------------------------===//
    335 
    336 let Defs = [ARGUMENTS] in {
    337 
    338 multiclass WebAssemblyBinRMW<WebAssemblyRegClass rc, string Name, int Opcode> {
    339   defm "" : I<(outs rc:$dst),
    340               (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
    341               (outs), (ins P2Align:$p2align, offset32_op:$off), [],
    342               !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}, $val"),
    343               !strconcat(Name, "\t${off}, ${p2align}"), Opcode>;
    344 }
    345 
    346 defm ATOMIC_RMW_ADD_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.add", 0xfe1e>;
    347 defm ATOMIC_RMW_ADD_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.add", 0xfe1f>;
    348 defm ATOMIC_RMW8_U_ADD_I32 :
    349   WebAssemblyBinRMW<I32, "i32.atomic.rmw8_u.add", 0xfe20>;
    350 defm ATOMIC_RMW16_U_ADD_I32 :
    351   WebAssemblyBinRMW<I32, "i32.atomic.rmw16_u.add", 0xfe21>;
    352 defm ATOMIC_RMW8_U_ADD_I64 :
    353   WebAssemblyBinRMW<I64, "i64.atomic.rmw8_u.add", 0xfe22>;
    354 defm ATOMIC_RMW16_U_ADD_I64 :
    355   WebAssemblyBinRMW<I64, "i64.atomic.rmw16_u.add", 0xfe23>;
    356 defm ATOMIC_RMW32_U_ADD_I64 :
    357   WebAssemblyBinRMW<I64, "i64.atomic.rmw32_u.add", 0xfe24>;
    358 
    359 defm ATOMIC_RMW_SUB_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.sub", 0xfe25>;
    360 defm ATOMIC_RMW_SUB_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.sub", 0xfe26>;
    361 defm ATOMIC_RMW8_U_SUB_I32 :
    362   WebAssemblyBinRMW<I32, "i32.atomic.rmw8_u.sub", 0xfe27>;
    363 defm ATOMIC_RMW16_U_SUB_I32 :
    364   WebAssemblyBinRMW<I32, "i32.atomic.rmw16_u.sub", 0xfe28>;
    365 defm ATOMIC_RMW8_U_SUB_I64 :
    366   WebAssemblyBinRMW<I64, "i64.atomic.rmw8_u.sub", 0xfe29>;
    367 defm ATOMIC_RMW16_U_SUB_I64 :
    368   WebAssemblyBinRMW<I64, "i64.atomic.rmw16_u.sub", 0xfe2a>;
    369 defm ATOMIC_RMW32_U_SUB_I64 :
    370   WebAssemblyBinRMW<I64, "i64.atomic.rmw32_u.sub", 0xfe2b>;
    371 
    372 defm ATOMIC_RMW_AND_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.and", 0xfe2c>;
    373 defm ATOMIC_RMW_AND_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.and", 0xfe2d>;
    374 defm ATOMIC_RMW8_U_AND_I32 :
    375   WebAssemblyBinRMW<I32, "i32.atomic.rmw8_u.and", 0xfe2e>;
    376 defm ATOMIC_RMW16_U_AND_I32 :
    377   WebAssemblyBinRMW<I32, "i32.atomic.rmw16_u.and", 0xfe2f>;
    378 defm ATOMIC_RMW8_U_AND_I64 :
    379   WebAssemblyBinRMW<I64, "i64.atomic.rmw8_u.and", 0xfe30>;
    380 defm ATOMIC_RMW16_U_AND_I64 :
    381   WebAssemblyBinRMW<I64, "i64.atomic.rmw16_u.and", 0xfe31>;
    382 defm ATOMIC_RMW32_U_AND_I64 :
    383   WebAssemblyBinRMW<I64, "i64.atomic.rmw32_u.and", 0xfe32>;
    384 
    385 defm ATOMIC_RMW_OR_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.or", 0xfe33>;
    386 defm ATOMIC_RMW_OR_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.or", 0xfe34>;
    387 defm ATOMIC_RMW8_U_OR_I32 :
    388   WebAssemblyBinRMW<I32, "i32.atomic.rmw8_u.or", 0xfe35>;
    389 defm ATOMIC_RMW16_U_OR_I32 :
    390   WebAssemblyBinRMW<I32, "i32.atomic.rmw16_u.or", 0xfe36>;
    391 defm ATOMIC_RMW8_U_OR_I64 :
    392   WebAssemblyBinRMW<I64, "i64.atomic.rmw8_u.or", 0xfe37>;
    393 defm ATOMIC_RMW16_U_OR_I64 :
    394   WebAssemblyBinRMW<I64, "i64.atomic.rmw16_u.or", 0xfe38>;
    395 defm ATOMIC_RMW32_U_OR_I64 :
    396   WebAssemblyBinRMW<I64, "i64.atomic.rmw32_u.or", 0xfe39>;
    397 
    398 defm ATOMIC_RMW_XOR_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.xor", 0xfe3a>;
    399 defm ATOMIC_RMW_XOR_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.xor", 0xfe3b>;
    400 defm ATOMIC_RMW8_U_XOR_I32 :
    401   WebAssemblyBinRMW<I32, "i32.atomic.rmw8_u.xor", 0xfe3c>;
    402 defm ATOMIC_RMW16_U_XOR_I32 :
    403   WebAssemblyBinRMW<I32, "i32.atomic.rmw16_u.xor", 0xfe3d>;
    404 defm ATOMIC_RMW8_U_XOR_I64 :
    405   WebAssemblyBinRMW<I64, "i64.atomic.rmw8_u.xor", 0xfe3e>;
    406 defm ATOMIC_RMW16_U_XOR_I64 :
    407   WebAssemblyBinRMW<I64, "i64.atomic.rmw16_u.xor", 0xfe3f>;
    408 defm ATOMIC_RMW32_U_XOR_I64 :
    409   WebAssemblyBinRMW<I64, "i64.atomic.rmw32_u.xor", 0xfe40>;
    410 
    411 defm ATOMIC_RMW_XCHG_I32 :
    412   WebAssemblyBinRMW<I32, "i32.atomic.rmw.xchg", 0xfe41>;
    413 defm ATOMIC_RMW_XCHG_I64 :
    414   WebAssemblyBinRMW<I64, "i64.atomic.rmw.xchg", 0xfe42>;
    415 defm ATOMIC_RMW8_U_XCHG_I32 :
    416   WebAssemblyBinRMW<I32, "i32.atomic.rmw8_u.xchg", 0xfe43>;
    417 defm ATOMIC_RMW16_U_XCHG_I32 :
    418   WebAssemblyBinRMW<I32, "i32.atomic.rmw16_u.xchg", 0xfe44>;
    419 defm ATOMIC_RMW8_U_XCHG_I64 :
    420   WebAssemblyBinRMW<I64, "i64.atomic.rmw8_u.xchg", 0xfe45>;
    421 defm ATOMIC_RMW16_U_XCHG_I64 :
    422   WebAssemblyBinRMW<I64, "i64.atomic.rmw16_u.xchg", 0xfe46>;
    423 defm ATOMIC_RMW32_U_XCHG_I64 :
    424   WebAssemblyBinRMW<I64, "i64.atomic.rmw32_u.xchg", 0xfe47>;
    425 }
    426 
    427 // Select binary RMWs with no constant offset.
    428 class BinRMWPatNoOffset<ValueType ty, PatFrag kind, NI inst> :
    429   Pat<(ty (kind I32:$addr, ty:$val)), (inst 0, 0, I32:$addr, ty:$val)>;
    430 
    431 // Select binary RMWs with a constant offset.
    432 
    433 // Pattern with address + immediate offset
    434 class BinRMWPatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
    435   Pat<(ty (kind (operand I32:$addr, imm:$off), ty:$val)),
    436       (inst 0, imm:$off, I32:$addr, ty:$val)>;
    437 
    438 class BinRMWPatGlobalAddr<ValueType ty, PatFrag kind, NI inst> :
    439   Pat<(ty (kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)),
    440                 ty:$val)),
    441       (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>;
    442 
    443 class BinRMWPatExternalSym<ValueType ty, PatFrag kind, NI inst> :
    444   Pat<(ty (kind (add I32:$addr, (WebAssemblywrapper texternalsym:$off)),
    445                 ty:$val)),
    446       (inst 0, texternalsym:$off, I32:$addr, ty:$val)>;
    447 
    448 // Select binary RMWs with just a constant offset.
    449 class BinRMWPatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
    450   Pat<(ty (kind imm:$off, ty:$val)),
    451       (inst 0, imm:$off, (CONST_I32 0), ty:$val)>;
    452 
    453 class BinRMWPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
    454   Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off), ty:$val)),
    455       (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>;
    456 
    457 class BinRMWPatExternSymOffOnly<ValueType ty, PatFrag kind, NI inst> :
    458   Pat<(ty (kind (WebAssemblywrapper texternalsym:$off), ty:$val)),
    459       (inst 0, texternalsym:$off, (CONST_I32 0), ty:$val)>;
    460 
    461 // Patterns for various addressing modes.
    462 multiclass BinRMWPattern<PatFrag rmw_32, PatFrag rmw_64, NI inst_32,
    463                          NI inst_64> {
    464   def : BinRMWPatNoOffset<i32, rmw_32, inst_32>;
    465   def : BinRMWPatNoOffset<i64, rmw_64, inst_64>;
    466 
    467   def : BinRMWPatImmOff<i32, rmw_32, regPlusImm, inst_32>;
    468   def : BinRMWPatImmOff<i64, rmw_64, regPlusImm, inst_64>;
    469   def : BinRMWPatImmOff<i32, rmw_32, or_is_add, inst_32>;
    470   def : BinRMWPatImmOff<i64, rmw_64, or_is_add, inst_64>;
    471 
    472   def : BinRMWPatGlobalAddr<i32, rmw_32, inst_32>;
    473   def : BinRMWPatGlobalAddr<i64, rmw_64, inst_64>;
    474 
    475   def : BinRMWPatExternalSym<i32, rmw_32, inst_32>;
    476   def : BinRMWPatExternalSym<i64, rmw_64, inst_64>;
    477 
    478   def : BinRMWPatOffsetOnly<i32, rmw_32, inst_32>;
    479   def : BinRMWPatOffsetOnly<i64, rmw_64, inst_64>;
    480 
    481   def : BinRMWPatGlobalAddrOffOnly<i32, rmw_32, inst_32>;
    482   def : BinRMWPatGlobalAddrOffOnly<i64, rmw_64, inst_64>;
    483 
    484   def : BinRMWPatExternSymOffOnly<i32, rmw_32, inst_32>;
    485   def : BinRMWPatExternSymOffOnly<i64, rmw_64, inst_64>;
    486 }
    487 
    488 let Predicates = [HasAtomics] in {
    489 defm : BinRMWPattern<atomic_load_add_32, atomic_load_add_64, ATOMIC_RMW_ADD_I32,
    490                      ATOMIC_RMW_ADD_I64>;
    491 defm : BinRMWPattern<atomic_load_sub_32, atomic_load_sub_64, ATOMIC_RMW_SUB_I32,
    492                      ATOMIC_RMW_SUB_I64>;
    493 defm : BinRMWPattern<atomic_load_and_32, atomic_load_and_64, ATOMIC_RMW_AND_I32,
    494                      ATOMIC_RMW_AND_I64>;
    495 defm : BinRMWPattern<atomic_load_or_32, atomic_load_or_64, ATOMIC_RMW_OR_I32,
    496                      ATOMIC_RMW_OR_I64>;
    497 defm : BinRMWPattern<atomic_load_xor_32, atomic_load_xor_64, ATOMIC_RMW_XOR_I32,
    498                      ATOMIC_RMW_XOR_I64>;
    499 defm : BinRMWPattern<atomic_swap_32, atomic_swap_64, ATOMIC_RMW_XCHG_I32,
    500                      ATOMIC_RMW_XCHG_I64>;
    501 } // Predicates = [HasAtomics]
    502 
    503 // Truncating & zero-extending binary RMW patterns.
    504 // These are combined patterns of truncating store patterns and zero-extending
    505 // load patterns above.
    506 class zext_bin_rmw_8_32<PatFrag kind> :
    507   PatFrag<(ops node:$addr, node:$val),
    508           (and (i32 (kind node:$addr, node:$val)), 255)>;
    509 class zext_bin_rmw_16_32<PatFrag kind> :
    510   PatFrag<(ops node:$addr, node:$val),
    511           (and (i32 (kind node:$addr, node:$val)), 65535)>;
    512 class zext_bin_rmw_8_64<PatFrag kind> :
    513   PatFrag<(ops node:$addr, node:$val),
    514     (and (i64 (anyext (i32 (kind node:$addr,
    515                                  (i32 (trunc (i64 node:$val))))))), 255)>;
    516 class zext_bin_rmw_16_64<PatFrag kind> :
    517   PatFrag<(ops node:$addr, node:$val),
    518     (and (i64 (anyext (i32 (kind node:$addr,
    519                                  (i32 (trunc (i64 node:$val))))))), 65535)>;
    520 class zext_bin_rmw_32_64<PatFrag kind> :
    521   PatFrag<(ops node:$addr, node:$val),
    522           (zext (i32 (kind node:$addr, (i32 (trunc (i64 node:$val))))))>;
    523 
    524 // Truncating & sign-extending binary RMW patterns.
    525 // These are combined patterns of truncating store patterns and sign-extending
    526 // load patterns above. We match subword RMWs (for 32-bit) and anyext RMWs (for
    527 // 64-bit) and select a zext RMW; the next instruction will be sext_inreg which
    528 // is selected by itself.
    529 class sext_bin_rmw_8_32<PatFrag kind> :
    530   PatFrag<(ops node:$addr, node:$val), (kind node:$addr, node:$val)>;
    531 class sext_bin_rmw_16_32<PatFrag kind> : sext_bin_rmw_8_32<kind>;
    532 class sext_bin_rmw_8_64<PatFrag kind> :
    533   PatFrag<(ops node:$addr, node:$val),
    534           (anyext (i32 (kind node:$addr, (i32 (trunc (i64 node:$val))))))>;
    535 class sext_bin_rmw_16_64<PatFrag kind> : sext_bin_rmw_8_64<kind>;
    536 // 32->64 sext RMW gets selected as i32.atomic.rmw.***, i64.extend_s/i32
    537 
    538 // Patterns for various addressing modes for truncating-extending binary RMWs.
    539 multiclass BinRMWTruncExtPattern<
    540   PatFrag rmw_8, PatFrag rmw_16, PatFrag rmw_32, PatFrag rmw_64,
    541   NI inst8_32, NI inst16_32, NI inst8_64, NI inst16_64, NI inst32_64> {
    542   // Truncating-extending binary RMWs with no constant offset
    543   def : BinRMWPatNoOffset<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
    544   def : BinRMWPatNoOffset<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
    545   def : BinRMWPatNoOffset<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
    546   def : BinRMWPatNoOffset<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
    547   def : BinRMWPatNoOffset<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
    548 
    549   def : BinRMWPatNoOffset<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
    550   def : BinRMWPatNoOffset<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
    551   def : BinRMWPatNoOffset<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
    552   def : BinRMWPatNoOffset<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
    553 
    554   // Truncating-extending binary RMWs with a constant offset
    555   def : BinRMWPatImmOff<i32, zext_bin_rmw_8_32<rmw_8>, regPlusImm, inst8_32>;
    556   def : BinRMWPatImmOff<i32, zext_bin_rmw_16_32<rmw_16>, regPlusImm, inst16_32>;
    557   def : BinRMWPatImmOff<i64, zext_bin_rmw_8_64<rmw_8>, regPlusImm, inst8_64>;
    558   def : BinRMWPatImmOff<i64, zext_bin_rmw_16_64<rmw_16>, regPlusImm, inst16_64>;
    559   def : BinRMWPatImmOff<i64, zext_bin_rmw_32_64<rmw_32>, regPlusImm, inst32_64>;
    560   def : BinRMWPatImmOff<i32, zext_bin_rmw_8_32<rmw_8>, or_is_add, inst8_32>;
    561   def : BinRMWPatImmOff<i32, zext_bin_rmw_16_32<rmw_16>, or_is_add, inst16_32>;
    562   def : BinRMWPatImmOff<i64, zext_bin_rmw_8_64<rmw_8>, or_is_add, inst8_64>;
    563   def : BinRMWPatImmOff<i64, zext_bin_rmw_16_64<rmw_16>, or_is_add, inst16_64>;
    564   def : BinRMWPatImmOff<i64, zext_bin_rmw_32_64<rmw_32>, or_is_add, inst32_64>;
    565 
    566   def : BinRMWPatImmOff<i32, sext_bin_rmw_8_32<rmw_8>, regPlusImm, inst8_32>;
    567   def : BinRMWPatImmOff<i32, sext_bin_rmw_16_32<rmw_16>, regPlusImm, inst16_32>;
    568   def : BinRMWPatImmOff<i64, sext_bin_rmw_8_64<rmw_8>, regPlusImm, inst8_64>;
    569   def : BinRMWPatImmOff<i64, sext_bin_rmw_16_64<rmw_16>, regPlusImm, inst16_64>;
    570   def : BinRMWPatImmOff<i32, sext_bin_rmw_8_32<rmw_8>, or_is_add, inst8_32>;
    571   def : BinRMWPatImmOff<i32, sext_bin_rmw_16_32<rmw_16>, or_is_add, inst16_32>;
    572   def : BinRMWPatImmOff<i64, sext_bin_rmw_8_64<rmw_8>, or_is_add, inst8_64>;
    573   def : BinRMWPatImmOff<i64, sext_bin_rmw_16_64<rmw_16>, or_is_add, inst16_64>;
    574 
    575   def : BinRMWPatGlobalAddr<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
    576   def : BinRMWPatGlobalAddr<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
    577   def : BinRMWPatGlobalAddr<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
    578   def : BinRMWPatGlobalAddr<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
    579   def : BinRMWPatGlobalAddr<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
    580 
    581   def : BinRMWPatGlobalAddr<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
    582   def : BinRMWPatGlobalAddr<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
    583   def : BinRMWPatGlobalAddr<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
    584   def : BinRMWPatGlobalAddr<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
    585 
    586   def : BinRMWPatExternalSym<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
    587   def : BinRMWPatExternalSym<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
    588   def : BinRMWPatExternalSym<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
    589   def : BinRMWPatExternalSym<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
    590   def : BinRMWPatExternalSym<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
    591 
    592   def : BinRMWPatExternalSym<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
    593   def : BinRMWPatExternalSym<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
    594   def : BinRMWPatExternalSym<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
    595   def : BinRMWPatExternalSym<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
    596 
    597   // Truncating-extending binary RMWs with just a constant offset
    598   def : BinRMWPatOffsetOnly<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
    599   def : BinRMWPatOffsetOnly<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
    600   def : BinRMWPatOffsetOnly<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
    601   def : BinRMWPatOffsetOnly<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
    602   def : BinRMWPatOffsetOnly<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
    603 
    604   def : BinRMWPatOffsetOnly<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
    605   def : BinRMWPatOffsetOnly<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
    606   def : BinRMWPatOffsetOnly<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
    607   def : BinRMWPatOffsetOnly<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
    608 
    609   def : BinRMWPatGlobalAddrOffOnly<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
    610   def : BinRMWPatGlobalAddrOffOnly<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
    611   def : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
    612   def : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
    613   def : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
    614 
    615   def : BinRMWPatGlobalAddrOffOnly<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
    616   def : BinRMWPatGlobalAddrOffOnly<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
    617   def : BinRMWPatGlobalAddrOffOnly<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
    618   def : BinRMWPatGlobalAddrOffOnly<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
    619 
    620   def : BinRMWPatExternSymOffOnly<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
    621   def : BinRMWPatExternSymOffOnly<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
    622   def : BinRMWPatExternSymOffOnly<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
    623   def : BinRMWPatExternSymOffOnly<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
    624   def : BinRMWPatExternSymOffOnly<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
    625 
    626   def : BinRMWPatExternSymOffOnly<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
    627   def : BinRMWPatExternSymOffOnly<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
    628   def : BinRMWPatExternSymOffOnly<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
    629   def : BinRMWPatExternSymOffOnly<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
    630 }
    631 
    632 let Predicates = [HasAtomics] in {
    633 defm : BinRMWTruncExtPattern<
    634   atomic_load_add_8, atomic_load_add_16, atomic_load_add_32, atomic_load_add_64,
    635   ATOMIC_RMW8_U_ADD_I32, ATOMIC_RMW16_U_ADD_I32,
    636   ATOMIC_RMW8_U_ADD_I64, ATOMIC_RMW16_U_ADD_I64, ATOMIC_RMW32_U_ADD_I64>;
    637 defm : BinRMWTruncExtPattern<
    638   atomic_load_sub_8, atomic_load_sub_16, atomic_load_sub_32, atomic_load_sub_64,
    639   ATOMIC_RMW8_U_SUB_I32, ATOMIC_RMW16_U_SUB_I32,
    640   ATOMIC_RMW8_U_SUB_I64, ATOMIC_RMW16_U_SUB_I64, ATOMIC_RMW32_U_SUB_I64>;
    641 defm : BinRMWTruncExtPattern<
    642   atomic_load_and_8, atomic_load_and_16, atomic_load_and_32, atomic_load_and_64,
    643   ATOMIC_RMW8_U_AND_I32, ATOMIC_RMW16_U_AND_I32,
    644   ATOMIC_RMW8_U_AND_I64, ATOMIC_RMW16_U_AND_I64, ATOMIC_RMW32_U_AND_I64>;
    645 defm : BinRMWTruncExtPattern<
    646   atomic_load_or_8, atomic_load_or_16, atomic_load_or_32, atomic_load_or_64,
    647   ATOMIC_RMW8_U_OR_I32, ATOMIC_RMW16_U_OR_I32,
    648   ATOMIC_RMW8_U_OR_I64, ATOMIC_RMW16_U_OR_I64, ATOMIC_RMW32_U_OR_I64>;
    649 defm : BinRMWTruncExtPattern<
    650   atomic_load_xor_8, atomic_load_xor_16, atomic_load_xor_32, atomic_load_xor_64,
    651   ATOMIC_RMW8_U_XOR_I32, ATOMIC_RMW16_U_XOR_I32,
    652   ATOMIC_RMW8_U_XOR_I64, ATOMIC_RMW16_U_XOR_I64, ATOMIC_RMW32_U_XOR_I64>;
    653 defm : BinRMWTruncExtPattern<
    654   atomic_swap_8, atomic_swap_16, atomic_swap_32, atomic_swap_64,
    655   ATOMIC_RMW8_U_XCHG_I32, ATOMIC_RMW16_U_XCHG_I32,
    656   ATOMIC_RMW8_U_XCHG_I64, ATOMIC_RMW16_U_XCHG_I64, ATOMIC_RMW32_U_XCHG_I64>;
    657 } // Predicates = [HasAtomics]
    658