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