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. 27def 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. 32def 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. 47def 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// Defines atomic and non-atomic loads, regular and extending. 57multiclass WebAssemblyLoad<WebAssemblyRegClass rc, string Name, int Opcode> { 58 let mayLoad = 1 in 59 defm "": I<(outs rc:$dst), 60 (ins P2Align:$p2align, offset32_op:$off, I32:$addr), 61 (outs), (ins P2Align:$p2align, offset32_op:$off), 62 [], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"), 63 !strconcat(Name, "\t${off}${p2align}"), Opcode>; 64} 65 66// Basic load. 67// FIXME: When we can break syntax compatibility, reorder the fields in the 68// asmstrings to match the binary encoding. 69defm LOAD_I32 : WebAssemblyLoad<I32, "i32.load", 0x28>; 70defm LOAD_I64 : WebAssemblyLoad<I64, "i64.load", 0x29>; 71defm LOAD_F32 : WebAssemblyLoad<F32, "f32.load", 0x2a>; 72defm LOAD_F64 : WebAssemblyLoad<F64, "f64.load", 0x2b>; 73 74// Select loads with no constant offset. 75class LoadPatNoOffset<ValueType ty, PatFrag kind, NI inst> : 76 Pat<(ty (kind I32:$addr)), (inst 0, 0, I32:$addr)>; 77 78def : LoadPatNoOffset<i32, load, LOAD_I32>; 79def : LoadPatNoOffset<i64, load, LOAD_I64>; 80def : LoadPatNoOffset<f32, load, LOAD_F32>; 81def : LoadPatNoOffset<f64, load, LOAD_F64>; 82 83 84// Select loads with a constant offset. 85 86// Pattern with address + immediate offset 87class LoadPatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> : 88 Pat<(ty (kind (operand I32:$addr, imm:$off))), (inst 0, imm:$off, I32:$addr)>; 89 90def : LoadPatImmOff<i32, load, regPlusImm, LOAD_I32>; 91def : LoadPatImmOff<i64, load, regPlusImm, LOAD_I64>; 92def : LoadPatImmOff<f32, load, regPlusImm, LOAD_F32>; 93def : LoadPatImmOff<f64, load, regPlusImm, LOAD_F64>; 94def : LoadPatImmOff<i32, load, or_is_add, LOAD_I32>; 95def : LoadPatImmOff<i64, load, or_is_add, LOAD_I64>; 96def : LoadPatImmOff<f32, load, or_is_add, LOAD_F32>; 97def : LoadPatImmOff<f64, load, or_is_add, LOAD_F64>; 98 99class LoadPatGlobalAddr<ValueType ty, PatFrag kind, NI inst> : 100 Pat<(ty (kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)))), 101 (inst 0, tglobaladdr:$off, I32:$addr)>; 102 103def : LoadPatGlobalAddr<i32, load, LOAD_I32>; 104def : LoadPatGlobalAddr<i64, load, LOAD_I64>; 105def : LoadPatGlobalAddr<f32, load, LOAD_F32>; 106def : LoadPatGlobalAddr<f64, load, LOAD_F64>; 107 108class LoadPatExternalSym<ValueType ty, PatFrag kind, NI inst> : 109 Pat<(ty (kind (add I32:$addr, (WebAssemblywrapper texternalsym:$off)))), 110 (inst 0, texternalsym:$off, I32:$addr)>; 111def : LoadPatExternalSym<i32, load, LOAD_I32>; 112def : LoadPatExternalSym<i64, load, LOAD_I64>; 113def : LoadPatExternalSym<f32, load, LOAD_F32>; 114def : LoadPatExternalSym<f64, load, LOAD_F64>; 115 116 117// Select loads with just a constant offset. 118class LoadPatOffsetOnly<ValueType ty, PatFrag kind, NI inst> : 119 Pat<(ty (kind imm:$off)), (inst 0, imm:$off, (CONST_I32 0))>; 120 121def : LoadPatOffsetOnly<i32, load, LOAD_I32>; 122def : LoadPatOffsetOnly<i64, load, LOAD_I64>; 123def : LoadPatOffsetOnly<f32, load, LOAD_F32>; 124def : LoadPatOffsetOnly<f64, load, LOAD_F64>; 125 126class LoadPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> : 127 Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off))), 128 (inst 0, tglobaladdr:$off, (CONST_I32 0))>; 129 130def : LoadPatGlobalAddrOffOnly<i32, load, LOAD_I32>; 131def : LoadPatGlobalAddrOffOnly<i64, load, LOAD_I64>; 132def : LoadPatGlobalAddrOffOnly<f32, load, LOAD_F32>; 133def : LoadPatGlobalAddrOffOnly<f64, load, LOAD_F64>; 134 135class LoadPatExternSymOffOnly<ValueType ty, PatFrag kind, NI inst> : 136 Pat<(ty (kind (WebAssemblywrapper texternalsym:$off))), 137 (inst 0, texternalsym:$off, (CONST_I32 0))>; 138def : LoadPatExternSymOffOnly<i32, load, LOAD_I32>; 139def : LoadPatExternSymOffOnly<i64, load, LOAD_I64>; 140def : LoadPatExternSymOffOnly<f32, load, LOAD_F32>; 141def : LoadPatExternSymOffOnly<f64, load, LOAD_F64>; 142 143// Extending load. 144defm LOAD8_S_I32 : WebAssemblyLoad<I32, "i32.load8_s", 0x2c>; 145defm LOAD8_U_I32 : WebAssemblyLoad<I32, "i32.load8_u", 0x2d>; 146defm LOAD16_S_I32 : WebAssemblyLoad<I32, "i32.load16_s", 0x2e>; 147defm LOAD16_U_I32 : WebAssemblyLoad<I32, "i32.load16_u", 0x2f>; 148defm LOAD8_S_I64 : WebAssemblyLoad<I64, "i64.load8_s", 0x30>; 149defm LOAD8_U_I64 : WebAssemblyLoad<I64, "i64.load8_u", 0x31>; 150defm LOAD16_S_I64 : WebAssemblyLoad<I64, "i64.load16_s", 0x32>; 151defm LOAD16_U_I64 : WebAssemblyLoad<I64, "i64.load16_u", 0x33>; 152defm LOAD32_S_I64 : WebAssemblyLoad<I64, "i64.load32_s", 0x34>; 153defm LOAD32_U_I64 : WebAssemblyLoad<I64, "i64.load32_u", 0x35>; 154 155// Select extending loads with no constant offset. 156def : LoadPatNoOffset<i32, sextloadi8, LOAD8_S_I32>; 157def : LoadPatNoOffset<i32, zextloadi8, LOAD8_U_I32>; 158def : LoadPatNoOffset<i32, sextloadi16, LOAD16_S_I32>; 159def : LoadPatNoOffset<i32, zextloadi16, LOAD16_U_I32>; 160def : LoadPatNoOffset<i64, sextloadi8, LOAD8_S_I64>; 161def : LoadPatNoOffset<i64, zextloadi8, LOAD8_U_I64>; 162def : LoadPatNoOffset<i64, sextloadi16, LOAD16_S_I64>; 163def : LoadPatNoOffset<i64, zextloadi16, LOAD16_U_I64>; 164def : LoadPatNoOffset<i64, sextloadi32, LOAD32_S_I64>; 165def : LoadPatNoOffset<i64, zextloadi32, LOAD32_U_I64>; 166 167// Select extending loads with a constant offset. 168def : LoadPatImmOff<i32, sextloadi8, regPlusImm, LOAD8_S_I32>; 169def : LoadPatImmOff<i32, zextloadi8, regPlusImm, LOAD8_U_I32>; 170def : LoadPatImmOff<i32, sextloadi16, regPlusImm, LOAD16_S_I32>; 171def : LoadPatImmOff<i32, zextloadi16, regPlusImm, LOAD16_U_I32>; 172def : LoadPatImmOff<i64, sextloadi8, regPlusImm, LOAD8_S_I64>; 173def : LoadPatImmOff<i64, zextloadi8, regPlusImm, LOAD8_U_I64>; 174def : LoadPatImmOff<i64, sextloadi16, regPlusImm, LOAD16_S_I64>; 175def : LoadPatImmOff<i64, zextloadi16, regPlusImm, LOAD16_U_I64>; 176def : LoadPatImmOff<i64, sextloadi32, regPlusImm, LOAD32_S_I64>; 177def : LoadPatImmOff<i64, zextloadi32, regPlusImm, LOAD32_U_I64>; 178 179def : LoadPatImmOff<i32, sextloadi8, or_is_add, LOAD8_S_I32>; 180def : LoadPatImmOff<i32, zextloadi8, or_is_add, LOAD8_U_I32>; 181def : LoadPatImmOff<i32, sextloadi16, or_is_add, LOAD16_S_I32>; 182def : LoadPatImmOff<i32, zextloadi16, or_is_add, LOAD16_U_I32>; 183def : LoadPatImmOff<i64, sextloadi8, or_is_add, LOAD8_S_I64>; 184def : LoadPatImmOff<i64, zextloadi8, or_is_add, LOAD8_U_I64>; 185def : LoadPatImmOff<i64, sextloadi16, or_is_add, LOAD16_S_I64>; 186def : LoadPatImmOff<i64, zextloadi16, or_is_add, LOAD16_U_I64>; 187def : LoadPatImmOff<i64, sextloadi32, or_is_add, LOAD32_S_I64>; 188def : LoadPatImmOff<i64, zextloadi32, or_is_add, LOAD32_U_I64>; 189 190def : LoadPatGlobalAddr<i32, sextloadi8, LOAD8_S_I32>; 191def : LoadPatGlobalAddr<i32, zextloadi8, LOAD8_U_I32>; 192def : LoadPatGlobalAddr<i32, sextloadi16, LOAD16_S_I32>; 193def : LoadPatGlobalAddr<i32, zextloadi8, LOAD16_U_I32>; 194 195def : LoadPatGlobalAddr<i64, sextloadi8, LOAD8_S_I64>; 196def : LoadPatGlobalAddr<i64, zextloadi8, LOAD8_U_I64>; 197def : LoadPatGlobalAddr<i64, sextloadi16, LOAD16_S_I64>; 198def : LoadPatGlobalAddr<i64, zextloadi16, LOAD16_U_I64>; 199def : LoadPatGlobalAddr<i64, sextloadi32, LOAD32_S_I64>; 200def : LoadPatGlobalAddr<i64, zextloadi32, LOAD32_U_I64>; 201 202def : LoadPatExternalSym<i32, sextloadi8, LOAD8_S_I32>; 203def : LoadPatExternalSym<i32, zextloadi8, LOAD8_U_I32>; 204def : LoadPatExternalSym<i32, sextloadi16, LOAD16_S_I32>; 205def : LoadPatExternalSym<i32, zextloadi16, LOAD16_U_I32>; 206def : LoadPatExternalSym<i64, sextloadi8, LOAD8_S_I64>; 207def : LoadPatExternalSym<i64, zextloadi8, LOAD8_U_I64>; 208def : LoadPatExternalSym<i64, sextloadi16, LOAD16_S_I64>; 209def : LoadPatExternalSym<i64, zextloadi16, LOAD16_U_I64>; 210def : LoadPatExternalSym<i64, sextloadi32, LOAD32_S_I64>; 211def : LoadPatExternalSym<i64, zextloadi32, LOAD32_U_I64>; 212 213 214// Select extending loads with just a constant offset. 215def : LoadPatOffsetOnly<i32, sextloadi8, LOAD8_S_I32>; 216def : LoadPatOffsetOnly<i32, zextloadi8, LOAD8_U_I32>; 217def : LoadPatOffsetOnly<i32, sextloadi16, LOAD16_S_I32>; 218def : LoadPatOffsetOnly<i32, zextloadi16, LOAD16_U_I32>; 219 220def : LoadPatOffsetOnly<i64, sextloadi8, LOAD8_S_I64>; 221def : LoadPatOffsetOnly<i64, zextloadi8, LOAD8_U_I64>; 222def : LoadPatOffsetOnly<i64, sextloadi16, LOAD16_S_I64>; 223def : LoadPatOffsetOnly<i64, zextloadi16, LOAD16_U_I64>; 224def : LoadPatOffsetOnly<i64, sextloadi32, LOAD32_S_I64>; 225def : LoadPatOffsetOnly<i64, zextloadi32, LOAD32_U_I64>; 226 227def : LoadPatGlobalAddrOffOnly<i32, sextloadi8, LOAD8_S_I32>; 228def : LoadPatGlobalAddrOffOnly<i32, zextloadi8, LOAD8_U_I32>; 229def : LoadPatGlobalAddrOffOnly<i32, sextloadi16, LOAD16_S_I32>; 230def : LoadPatGlobalAddrOffOnly<i32, zextloadi16, LOAD16_U_I32>; 231def : LoadPatGlobalAddrOffOnly<i64, sextloadi8, LOAD8_S_I64>; 232def : LoadPatGlobalAddrOffOnly<i64, zextloadi8, LOAD8_U_I64>; 233def : LoadPatGlobalAddrOffOnly<i64, sextloadi16, LOAD16_S_I64>; 234def : LoadPatGlobalAddrOffOnly<i64, zextloadi16, LOAD16_U_I64>; 235def : LoadPatGlobalAddrOffOnly<i64, sextloadi32, LOAD32_S_I64>; 236def : LoadPatGlobalAddrOffOnly<i64, zextloadi32, LOAD32_U_I64>; 237 238def : LoadPatExternSymOffOnly<i32, sextloadi8, LOAD8_S_I32>; 239def : LoadPatExternSymOffOnly<i32, zextloadi8, LOAD8_U_I32>; 240def : LoadPatExternSymOffOnly<i32, sextloadi16, LOAD16_S_I32>; 241def : LoadPatExternSymOffOnly<i32, zextloadi16, LOAD16_U_I32>; 242def : LoadPatExternSymOffOnly<i64, sextloadi8, LOAD8_S_I64>; 243def : LoadPatExternSymOffOnly<i64, zextloadi8, LOAD8_U_I64>; 244def : LoadPatExternSymOffOnly<i64, sextloadi16, LOAD16_S_I64>; 245def : LoadPatExternSymOffOnly<i64, zextloadi16, LOAD16_U_I64>; 246def : LoadPatExternSymOffOnly<i64, sextloadi32, LOAD32_S_I64>; 247def : LoadPatExternSymOffOnly<i64, zextloadi32, LOAD32_U_I64>; 248 249// Resolve "don't care" extending loads to zero-extending loads. This is 250// somewhat arbitrary, but zero-extending is conceptually simpler. 251 252// Select "don't care" extending loads with no constant offset. 253def : LoadPatNoOffset<i32, extloadi8, LOAD8_U_I32>; 254def : LoadPatNoOffset<i32, extloadi16, LOAD16_U_I32>; 255def : LoadPatNoOffset<i64, extloadi8, LOAD8_U_I64>; 256def : LoadPatNoOffset<i64, extloadi16, LOAD16_U_I64>; 257def : LoadPatNoOffset<i64, extloadi32, LOAD32_U_I64>; 258 259// Select "don't care" extending loads with a constant offset. 260def : LoadPatImmOff<i32, extloadi8, regPlusImm, LOAD8_U_I32>; 261def : LoadPatImmOff<i32, extloadi16, regPlusImm, LOAD16_U_I32>; 262def : LoadPatImmOff<i64, extloadi8, regPlusImm, LOAD8_U_I64>; 263def : LoadPatImmOff<i64, extloadi16, regPlusImm, LOAD16_U_I64>; 264def : LoadPatImmOff<i64, extloadi32, regPlusImm, LOAD32_U_I64>; 265def : LoadPatImmOff<i32, extloadi8, or_is_add, LOAD8_U_I32>; 266def : LoadPatImmOff<i32, extloadi16, or_is_add, LOAD16_U_I32>; 267def : LoadPatImmOff<i64, extloadi8, or_is_add, LOAD8_U_I64>; 268def : LoadPatImmOff<i64, extloadi16, or_is_add, LOAD16_U_I64>; 269def : LoadPatImmOff<i64, extloadi32, or_is_add, LOAD32_U_I64>; 270def : LoadPatGlobalAddr<i32, extloadi8, LOAD8_U_I32>; 271def : LoadPatGlobalAddr<i32, extloadi16, LOAD16_U_I32>; 272def : LoadPatGlobalAddr<i64, extloadi8, LOAD8_U_I64>; 273def : LoadPatGlobalAddr<i64, extloadi16, LOAD16_U_I64>; 274def : LoadPatGlobalAddr<i64, extloadi32, LOAD32_U_I64>; 275def : LoadPatExternalSym<i32, extloadi8, LOAD8_U_I32>; 276def : LoadPatExternalSym<i32, extloadi16, LOAD16_U_I32>; 277def : LoadPatExternalSym<i64, extloadi8, LOAD8_U_I64>; 278def : LoadPatExternalSym<i64, extloadi16, LOAD16_U_I64>; 279def : LoadPatExternalSym<i64, extloadi32, LOAD32_U_I64>; 280 281// Select "don't care" extending loads with just a constant offset. 282def : LoadPatOffsetOnly<i32, extloadi8, LOAD8_U_I32>; 283def : LoadPatOffsetOnly<i32, extloadi16, LOAD16_U_I32>; 284def : LoadPatOffsetOnly<i64, extloadi8, LOAD8_U_I64>; 285def : LoadPatOffsetOnly<i64, extloadi16, LOAD16_U_I64>; 286def : LoadPatOffsetOnly<i64, extloadi32, LOAD32_U_I64>; 287def : LoadPatGlobalAddrOffOnly<i32, extloadi8, LOAD8_U_I32>; 288def : LoadPatGlobalAddrOffOnly<i32, extloadi16, LOAD16_U_I32>; 289def : LoadPatGlobalAddrOffOnly<i64, extloadi8, LOAD8_U_I64>; 290def : LoadPatGlobalAddrOffOnly<i64, extloadi16, LOAD16_U_I64>; 291def : LoadPatGlobalAddrOffOnly<i64, extloadi32, LOAD32_U_I64>; 292def : LoadPatExternSymOffOnly<i32, extloadi8, LOAD8_U_I32>; 293def : LoadPatExternSymOffOnly<i32, extloadi16, LOAD16_U_I32>; 294def : LoadPatExternSymOffOnly<i64, extloadi8, LOAD8_U_I64>; 295def : LoadPatExternSymOffOnly<i64, extloadi16, LOAD16_U_I64>; 296def : LoadPatExternSymOffOnly<i64, extloadi32, LOAD32_U_I64>; 297 298// Defines atomic and non-atomic stores, regular and truncating 299multiclass WebAssemblyStore<WebAssemblyRegClass rc, string Name, int Opcode> { 300 let mayStore = 1 in 301 defm "" : I<(outs), 302 (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val), 303 (outs), 304 (ins P2Align:$p2align, offset32_op:$off), [], 305 !strconcat(Name, "\t${off}(${addr})${p2align}, $val"), 306 !strconcat(Name, "\t${off}${p2align}"), Opcode>; 307} 308// Basic store. 309// Note: WebAssembly inverts SelectionDAG's usual operand order. 310defm STORE_I32 : WebAssemblyStore<I32, "i32.store", 0x36>; 311defm STORE_I64 : WebAssemblyStore<I64, "i64.store", 0x37>; 312defm STORE_F32 : WebAssemblyStore<F32, "f32.store", 0x38>; 313defm STORE_F64 : WebAssemblyStore<F64, "f64.store", 0x39>; 314 315// Select stores with no constant offset. 316class StorePatNoOffset<ValueType ty, PatFrag node, NI inst> : 317 Pat<(node ty:$val, I32:$addr), (inst 0, 0, I32:$addr, ty:$val)>; 318 319def : StorePatNoOffset<i32, store, STORE_I32>; 320def : StorePatNoOffset<i64, store, STORE_I64>; 321def : StorePatNoOffset<f32, store, STORE_F32>; 322def : StorePatNoOffset<f64, store, STORE_F64>; 323 324// Select stores with a constant offset. 325class StorePatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> : 326 Pat<(kind ty:$val, (operand I32:$addr, imm:$off)), 327 (inst 0, imm:$off, I32:$addr, ty:$val)>; 328 329def : StorePatImmOff<i32, store, regPlusImm, STORE_I32>; 330def : StorePatImmOff<i64, store, regPlusImm, STORE_I64>; 331def : StorePatImmOff<f32, store, regPlusImm, STORE_F32>; 332def : StorePatImmOff<f64, store, regPlusImm, STORE_F64>; 333def : StorePatImmOff<i32, store, or_is_add, STORE_I32>; 334def : StorePatImmOff<i64, store, or_is_add, STORE_I64>; 335def : StorePatImmOff<f32, store, or_is_add, STORE_F32>; 336def : StorePatImmOff<f64, store, or_is_add, STORE_F64>; 337 338class StorePatGlobalAddr<ValueType ty, PatFrag kind, NI inst> : 339 Pat<(kind ty:$val, 340 (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off))), 341 (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>; 342def : StorePatGlobalAddr<i32, store, STORE_I32>; 343def : StorePatGlobalAddr<i64, store, STORE_I64>; 344def : StorePatGlobalAddr<f32, store, STORE_F32>; 345def : StorePatGlobalAddr<f64, store, STORE_F64>; 346 347class StorePatExternalSym<ValueType ty, PatFrag kind, NI inst> : 348 Pat<(kind ty:$val, (add I32:$addr, (WebAssemblywrapper texternalsym:$off))), 349 (inst 0, texternalsym:$off, I32:$addr, ty:$val)>; 350def : StorePatExternalSym<i32, store, STORE_I32>; 351def : StorePatExternalSym<i64, store, STORE_I64>; 352def : StorePatExternalSym<f32, store, STORE_F32>; 353def : StorePatExternalSym<f64, store, STORE_F64>; 354 355// Select stores with just a constant offset. 356class StorePatOffsetOnly<ValueType ty, PatFrag kind, NI inst> : 357 Pat<(kind ty:$val, imm:$off), (inst 0, imm:$off, (CONST_I32 0), ty:$val)>; 358def : StorePatOffsetOnly<i32, store, STORE_I32>; 359def : StorePatOffsetOnly<i64, store, STORE_I64>; 360def : StorePatOffsetOnly<f32, store, STORE_F32>; 361def : StorePatOffsetOnly<f64, store, STORE_F64>; 362 363class StorePatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> : 364 Pat<(kind ty:$val, (WebAssemblywrapper tglobaladdr:$off)), 365 (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>; 366def : StorePatGlobalAddrOffOnly<i32, store, STORE_I32>; 367def : StorePatGlobalAddrOffOnly<i64, store, STORE_I64>; 368def : StorePatGlobalAddrOffOnly<f32, store, STORE_F32>; 369def : StorePatGlobalAddrOffOnly<f64, store, STORE_F64>; 370 371class StorePatExternSymOffOnly<ValueType ty, PatFrag kind, NI inst> : 372 Pat<(kind ty:$val, (WebAssemblywrapper texternalsym:$off)), 373 (inst 0, texternalsym:$off, (CONST_I32 0), ty:$val)>; 374def : StorePatExternSymOffOnly<i32, store, STORE_I32>; 375def : StorePatExternSymOffOnly<i64, store, STORE_I64>; 376def : StorePatExternSymOffOnly<f32, store, STORE_F32>; 377def : StorePatExternSymOffOnly<f64, store, STORE_F64>; 378 379// Truncating store. 380defm STORE8_I32 : WebAssemblyStore<I32, "i32.store8", 0x3a>; 381defm STORE16_I32 : WebAssemblyStore<I32, "i32.store16", 0x3b>; 382defm STORE8_I64 : WebAssemblyStore<I64, "i64.store8", 0x3c>; 383defm STORE16_I64 : WebAssemblyStore<I64, "i64.store16", 0x3d>; 384defm STORE32_I64 : WebAssemblyStore<I64, "i64.store32", 0x3e>; 385 386// Select truncating stores with no constant offset. 387def : StorePatNoOffset<i32, truncstorei8, STORE8_I32>; 388def : StorePatNoOffset<i32, truncstorei16, STORE16_I32>; 389def : StorePatNoOffset<i64, truncstorei8, STORE8_I64>; 390def : StorePatNoOffset<i64, truncstorei16, STORE16_I64>; 391def : StorePatNoOffset<i64, truncstorei32, STORE32_I64>; 392 393// Select truncating stores with a constant offset. 394def : StorePatImmOff<i32, truncstorei8, regPlusImm, STORE8_I32>; 395def : StorePatImmOff<i32, truncstorei16, regPlusImm, STORE16_I32>; 396def : StorePatImmOff<i64, truncstorei8, regPlusImm, STORE8_I64>; 397def : StorePatImmOff<i64, truncstorei16, regPlusImm, STORE16_I64>; 398def : StorePatImmOff<i64, truncstorei32, regPlusImm, STORE32_I64>; 399def : StorePatImmOff<i32, truncstorei8, or_is_add, STORE8_I32>; 400def : StorePatImmOff<i32, truncstorei16, or_is_add, STORE16_I32>; 401def : StorePatImmOff<i64, truncstorei8, or_is_add, STORE8_I64>; 402def : StorePatImmOff<i64, truncstorei16, or_is_add, STORE16_I64>; 403def : StorePatImmOff<i64, truncstorei32, or_is_add, STORE32_I64>; 404 405def : StorePatGlobalAddr<i32, truncstorei8, STORE8_I32>; 406def : StorePatGlobalAddr<i32, truncstorei16, STORE16_I32>; 407def : StorePatGlobalAddr<i64, truncstorei8, STORE8_I64>; 408def : StorePatGlobalAddr<i64, truncstorei16, STORE16_I64>; 409def : StorePatGlobalAddr<i64, truncstorei32, STORE32_I64>; 410def : StorePatExternalSym<i32, truncstorei8, STORE8_I32>; 411def : StorePatExternalSym<i32, truncstorei16, STORE16_I32>; 412def : StorePatExternalSym<i64, truncstorei8, STORE8_I64>; 413def : StorePatExternalSym<i64, truncstorei16, STORE16_I64>; 414def : StorePatExternalSym<i64, truncstorei32, STORE32_I64>; 415 416// Select truncating stores with just a constant offset. 417def : StorePatOffsetOnly<i32, truncstorei8, STORE8_I32>; 418def : StorePatOffsetOnly<i32, truncstorei16, STORE16_I32>; 419def : StorePatOffsetOnly<i64, truncstorei8, STORE8_I64>; 420def : StorePatOffsetOnly<i64, truncstorei16, STORE16_I64>; 421def : StorePatOffsetOnly<i64, truncstorei32, STORE32_I64>; 422def : StorePatGlobalAddrOffOnly<i32, truncstorei8, STORE8_I32>; 423def : StorePatGlobalAddrOffOnly<i32, truncstorei16, STORE16_I32>; 424def : StorePatGlobalAddrOffOnly<i64, truncstorei8, STORE8_I64>; 425def : StorePatGlobalAddrOffOnly<i64, truncstorei16, STORE16_I64>; 426def : StorePatGlobalAddrOffOnly<i64, truncstorei32, STORE32_I64>; 427def : StorePatExternSymOffOnly<i32, truncstorei8, STORE8_I32>; 428def : StorePatExternSymOffOnly<i32, truncstorei16, STORE16_I32>; 429def : StorePatExternSymOffOnly<i64, truncstorei8, STORE8_I64>; 430def : StorePatExternSymOffOnly<i64, truncstorei16, STORE16_I64>; 431def : StorePatExternSymOffOnly<i64, truncstorei32, STORE32_I64>; 432 433// Current memory size. 434defm MEMORY_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags), 435 (outs), (ins i32imm:$flags), 436 [(set I32:$dst, 437 (int_wasm_memory_size (i32 imm:$flags)))], 438 "memory.size\t$dst, $flags", "memory.size\t$flags", 439 0x3f>, 440 Requires<[HasAddr32]>; 441defm MEM_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags), 442 (outs), (ins i32imm:$flags), 443 [(set I32:$dst, (int_wasm_mem_size (i32 imm:$flags)))], 444 "mem.size\t$dst, $flags", "mem.size\t$flags", 0x3f>, 445 Requires<[HasAddr32]>; 446defm CURRENT_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags), 447 (outs), (ins i32imm:$flags), 448 [], 449 "current_memory\t$dst", 450 "current_memory\t$flags", 0x3f>, 451 Requires<[HasAddr32]>; 452 453// Grow memory. 454defm MEMORY_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta), 455 (outs), (ins i32imm:$flags), 456 [(set I32:$dst, 457 (int_wasm_memory_grow (i32 imm:$flags), 458 I32:$delta))], 459 "memory.grow\t$dst, $flags, $delta", 460 "memory.grow\t$flags", 0x40>, 461 Requires<[HasAddr32]>; 462defm MEM_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta), 463 (outs), (ins i32imm:$flags), 464 [(set I32:$dst, 465 (int_wasm_mem_grow (i32 imm:$flags), I32:$delta))], 466 "mem.grow\t$dst, $flags, $delta", "mem.grow\t$flags", 467 0x40>, 468 Requires<[HasAddr32]>; 469defm GROW_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta), 470 (outs), (ins i32imm:$flags), 471 [], 472 "grow_memory\t$dst, $delta", "grow_memory\t$flags", 473 0x40>, 474 Requires<[HasAddr32]>; 475 476def : Pat<(int_wasm_current_memory), 477 (CURRENT_MEMORY_I32 0)>; 478def : Pat<(int_wasm_grow_memory I32:$delta), 479 (GROW_MEMORY_I32 0, $delta)>; 480