1// WebAssemblyInstrMemory.td-WebAssembly Memory codegen support -*- tablegen -*- 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8/// 9/// \file 10/// WebAssembly Memory operand code-gen constructs. 11/// 12//===----------------------------------------------------------------------===// 13 14// TODO: 15// - HasAddr64 16// - WebAssemblyTargetLowering having to do with atomics 17// - Each has optional alignment. 18 19// WebAssembly has i8/i16/i32/i64/f32/f64 memory types, but doesn't have i8/i16 20// local types. These memory-only types instead zero- or sign-extend into local 21// types when loading, and truncate when storing. 22 23// WebAssembly constant offsets are performed as unsigned with infinite 24// precision, so we need to check for NoUnsignedWrap so that we don't fold an 25// offset for an add that needs wrapping. 26def regPlusImm : PatFrag<(ops node:$addr, node:$off), 27 (add node:$addr, node:$off), 28 [{ return N->getFlags().hasNoUnsignedWrap(); }]>; 29 30// Treat an 'or' node as an 'add' if the or'ed bits are known to be zero. 31def or_is_add : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{ 32 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N->getOperand(1))) 33 return CurDAG->MaskedValueIsZero(N->getOperand(0), CN->getAPIntValue()); 34 35 KnownBits Known0 = CurDAG->computeKnownBits(N->getOperand(0), 0); 36 KnownBits Known1 = CurDAG->computeKnownBits(N->getOperand(1), 0); 37 return (~Known0.Zero & ~Known1.Zero) == 0; 38}]>; 39 40// GlobalAddresses are conceptually unsigned values, so we can also fold them 41// into immediate values as long as the add is 'nuw'. 42// TODO: We'd like to also match GA offsets but there are cases where the 43// register can have a negative value. Find out what more we can do. 44def regPlusGA : PatFrag<(ops node:$addr, node:$off), 45 (add node:$addr, node:$off), 46 [{ 47 return N->getFlags().hasNoUnsignedWrap(); 48}]>; 49 50// We don't need a regPlusES because external symbols never have constant 51// offsets folded into them, so we can just use add. 52 53// Defines atomic and non-atomic loads, regular and extending. 54multiclass WebAssemblyLoad<WebAssemblyRegClass rc, string Name, int Opcode> { 55 let mayLoad = 1, UseNamedOperandTable = 1 in 56 defm "": I<(outs rc:$dst), 57 (ins P2Align:$p2align, offset32_op:$off, I32:$addr), 58 (outs), (ins P2Align:$p2align, offset32_op:$off), 59 [], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"), 60 !strconcat(Name, "\t${off}${p2align}"), Opcode>; 61} 62 63// Basic load. 64// FIXME: When we can break syntax compatibility, reorder the fields in the 65// asmstrings to match the binary encoding. 66defm LOAD_I32 : WebAssemblyLoad<I32, "i32.load", 0x28>; 67defm LOAD_I64 : WebAssemblyLoad<I64, "i64.load", 0x29>; 68defm LOAD_F32 : WebAssemblyLoad<F32, "f32.load", 0x2a>; 69defm LOAD_F64 : WebAssemblyLoad<F64, "f64.load", 0x2b>; 70 71// Select loads with no constant offset. 72class LoadPatNoOffset<ValueType ty, PatFrag kind, NI inst> : 73 Pat<(ty (kind I32:$addr)), (inst 0, 0, I32:$addr)>; 74 75def : LoadPatNoOffset<i32, load, LOAD_I32>; 76def : LoadPatNoOffset<i64, load, LOAD_I64>; 77def : LoadPatNoOffset<f32, load, LOAD_F32>; 78def : LoadPatNoOffset<f64, load, LOAD_F64>; 79 80 81// Select loads with a constant offset. 82 83// Pattern with address + immediate offset 84class LoadPatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> : 85 Pat<(ty (kind (operand I32:$addr, imm:$off))), (inst 0, imm:$off, I32:$addr)>; 86 87def : LoadPatImmOff<i32, load, regPlusImm, LOAD_I32>; 88def : LoadPatImmOff<i64, load, regPlusImm, LOAD_I64>; 89def : LoadPatImmOff<f32, load, regPlusImm, LOAD_F32>; 90def : LoadPatImmOff<f64, load, regPlusImm, LOAD_F64>; 91def : LoadPatImmOff<i32, load, or_is_add, LOAD_I32>; 92def : LoadPatImmOff<i64, load, or_is_add, LOAD_I64>; 93def : LoadPatImmOff<f32, load, or_is_add, LOAD_F32>; 94def : LoadPatImmOff<f64, load, or_is_add, LOAD_F64>; 95 96class LoadPatGlobalAddr<ValueType ty, PatFrag kind, NI inst> : 97 Pat<(ty (kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)))), 98 (inst 0, tglobaladdr:$off, I32:$addr)>, Requires<[IsNotPIC]>; 99 100def : LoadPatGlobalAddr<i32, load, LOAD_I32>; 101def : LoadPatGlobalAddr<i64, load, LOAD_I64>; 102def : LoadPatGlobalAddr<f32, load, LOAD_F32>; 103def : LoadPatGlobalAddr<f64, load, LOAD_F64>; 104 105// Select loads with just a constant offset. 106class LoadPatOffsetOnly<ValueType ty, PatFrag kind, NI inst> : 107 Pat<(ty (kind imm:$off)), (inst 0, imm:$off, (CONST_I32 0))>; 108 109def : LoadPatOffsetOnly<i32, load, LOAD_I32>; 110def : LoadPatOffsetOnly<i64, load, LOAD_I64>; 111def : LoadPatOffsetOnly<f32, load, LOAD_F32>; 112def : LoadPatOffsetOnly<f64, load, LOAD_F64>; 113 114class LoadPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> : 115 Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off))), 116 (inst 0, tglobaladdr:$off, (CONST_I32 0))>, Requires<[IsNotPIC]>; 117 118def : LoadPatGlobalAddrOffOnly<i32, load, LOAD_I32>; 119def : LoadPatGlobalAddrOffOnly<i64, load, LOAD_I64>; 120def : LoadPatGlobalAddrOffOnly<f32, load, LOAD_F32>; 121def : LoadPatGlobalAddrOffOnly<f64, load, LOAD_F64>; 122 123// Extending load. 124defm LOAD8_S_I32 : WebAssemblyLoad<I32, "i32.load8_s", 0x2c>; 125defm LOAD8_U_I32 : WebAssemblyLoad<I32, "i32.load8_u", 0x2d>; 126defm LOAD16_S_I32 : WebAssemblyLoad<I32, "i32.load16_s", 0x2e>; 127defm LOAD16_U_I32 : WebAssemblyLoad<I32, "i32.load16_u", 0x2f>; 128defm LOAD8_S_I64 : WebAssemblyLoad<I64, "i64.load8_s", 0x30>; 129defm LOAD8_U_I64 : WebAssemblyLoad<I64, "i64.load8_u", 0x31>; 130defm LOAD16_S_I64 : WebAssemblyLoad<I64, "i64.load16_s", 0x32>; 131defm LOAD16_U_I64 : WebAssemblyLoad<I64, "i64.load16_u", 0x33>; 132defm LOAD32_S_I64 : WebAssemblyLoad<I64, "i64.load32_s", 0x34>; 133defm LOAD32_U_I64 : WebAssemblyLoad<I64, "i64.load32_u", 0x35>; 134 135// Select extending loads with no constant offset. 136def : LoadPatNoOffset<i32, sextloadi8, LOAD8_S_I32>; 137def : LoadPatNoOffset<i32, zextloadi8, LOAD8_U_I32>; 138def : LoadPatNoOffset<i32, sextloadi16, LOAD16_S_I32>; 139def : LoadPatNoOffset<i32, zextloadi16, LOAD16_U_I32>; 140def : LoadPatNoOffset<i64, sextloadi8, LOAD8_S_I64>; 141def : LoadPatNoOffset<i64, zextloadi8, LOAD8_U_I64>; 142def : LoadPatNoOffset<i64, sextloadi16, LOAD16_S_I64>; 143def : LoadPatNoOffset<i64, zextloadi16, LOAD16_U_I64>; 144def : LoadPatNoOffset<i64, sextloadi32, LOAD32_S_I64>; 145def : LoadPatNoOffset<i64, zextloadi32, LOAD32_U_I64>; 146 147// Select extending loads with a constant offset. 148def : LoadPatImmOff<i32, sextloadi8, regPlusImm, LOAD8_S_I32>; 149def : LoadPatImmOff<i32, zextloadi8, regPlusImm, LOAD8_U_I32>; 150def : LoadPatImmOff<i32, sextloadi16, regPlusImm, LOAD16_S_I32>; 151def : LoadPatImmOff<i32, zextloadi16, regPlusImm, LOAD16_U_I32>; 152def : LoadPatImmOff<i64, sextloadi8, regPlusImm, LOAD8_S_I64>; 153def : LoadPatImmOff<i64, zextloadi8, regPlusImm, LOAD8_U_I64>; 154def : LoadPatImmOff<i64, sextloadi16, regPlusImm, LOAD16_S_I64>; 155def : LoadPatImmOff<i64, zextloadi16, regPlusImm, LOAD16_U_I64>; 156def : LoadPatImmOff<i64, sextloadi32, regPlusImm, LOAD32_S_I64>; 157def : LoadPatImmOff<i64, zextloadi32, regPlusImm, LOAD32_U_I64>; 158 159def : LoadPatImmOff<i32, sextloadi8, or_is_add, LOAD8_S_I32>; 160def : LoadPatImmOff<i32, zextloadi8, or_is_add, LOAD8_U_I32>; 161def : LoadPatImmOff<i32, sextloadi16, or_is_add, LOAD16_S_I32>; 162def : LoadPatImmOff<i32, zextloadi16, or_is_add, LOAD16_U_I32>; 163def : LoadPatImmOff<i64, sextloadi8, or_is_add, LOAD8_S_I64>; 164def : LoadPatImmOff<i64, zextloadi8, or_is_add, LOAD8_U_I64>; 165def : LoadPatImmOff<i64, sextloadi16, or_is_add, LOAD16_S_I64>; 166def : LoadPatImmOff<i64, zextloadi16, or_is_add, LOAD16_U_I64>; 167def : LoadPatImmOff<i64, sextloadi32, or_is_add, LOAD32_S_I64>; 168def : LoadPatImmOff<i64, zextloadi32, or_is_add, LOAD32_U_I64>; 169 170def : LoadPatGlobalAddr<i32, sextloadi8, LOAD8_S_I32>; 171def : LoadPatGlobalAddr<i32, zextloadi8, LOAD8_U_I32>; 172def : LoadPatGlobalAddr<i32, sextloadi16, LOAD16_S_I32>; 173def : LoadPatGlobalAddr<i32, zextloadi8, LOAD16_U_I32>; 174 175def : LoadPatGlobalAddr<i64, sextloadi8, LOAD8_S_I64>; 176def : LoadPatGlobalAddr<i64, zextloadi8, LOAD8_U_I64>; 177def : LoadPatGlobalAddr<i64, sextloadi16, LOAD16_S_I64>; 178def : LoadPatGlobalAddr<i64, zextloadi16, LOAD16_U_I64>; 179def : LoadPatGlobalAddr<i64, sextloadi32, LOAD32_S_I64>; 180def : LoadPatGlobalAddr<i64, zextloadi32, LOAD32_U_I64>; 181 182// Select extending loads with just a constant offset. 183def : LoadPatOffsetOnly<i32, sextloadi8, LOAD8_S_I32>; 184def : LoadPatOffsetOnly<i32, zextloadi8, LOAD8_U_I32>; 185def : LoadPatOffsetOnly<i32, sextloadi16, LOAD16_S_I32>; 186def : LoadPatOffsetOnly<i32, zextloadi16, LOAD16_U_I32>; 187 188def : LoadPatOffsetOnly<i64, sextloadi8, LOAD8_S_I64>; 189def : LoadPatOffsetOnly<i64, zextloadi8, LOAD8_U_I64>; 190def : LoadPatOffsetOnly<i64, sextloadi16, LOAD16_S_I64>; 191def : LoadPatOffsetOnly<i64, zextloadi16, LOAD16_U_I64>; 192def : LoadPatOffsetOnly<i64, sextloadi32, LOAD32_S_I64>; 193def : LoadPatOffsetOnly<i64, zextloadi32, LOAD32_U_I64>; 194 195def : LoadPatGlobalAddrOffOnly<i32, sextloadi8, LOAD8_S_I32>; 196def : LoadPatGlobalAddrOffOnly<i32, zextloadi8, LOAD8_U_I32>; 197def : LoadPatGlobalAddrOffOnly<i32, sextloadi16, LOAD16_S_I32>; 198def : LoadPatGlobalAddrOffOnly<i32, zextloadi16, LOAD16_U_I32>; 199def : LoadPatGlobalAddrOffOnly<i64, sextloadi8, LOAD8_S_I64>; 200def : LoadPatGlobalAddrOffOnly<i64, zextloadi8, LOAD8_U_I64>; 201def : LoadPatGlobalAddrOffOnly<i64, sextloadi16, LOAD16_S_I64>; 202def : LoadPatGlobalAddrOffOnly<i64, zextloadi16, LOAD16_U_I64>; 203def : LoadPatGlobalAddrOffOnly<i64, sextloadi32, LOAD32_S_I64>; 204def : LoadPatGlobalAddrOffOnly<i64, zextloadi32, LOAD32_U_I64>; 205 206// Resolve "don't care" extending loads to zero-extending loads. This is 207// somewhat arbitrary, but zero-extending is conceptually simpler. 208 209// Select "don't care" extending loads with no constant offset. 210def : LoadPatNoOffset<i32, extloadi8, LOAD8_U_I32>; 211def : LoadPatNoOffset<i32, extloadi16, LOAD16_U_I32>; 212def : LoadPatNoOffset<i64, extloadi8, LOAD8_U_I64>; 213def : LoadPatNoOffset<i64, extloadi16, LOAD16_U_I64>; 214def : LoadPatNoOffset<i64, extloadi32, LOAD32_U_I64>; 215 216// Select "don't care" extending loads with a constant offset. 217def : LoadPatImmOff<i32, extloadi8, regPlusImm, LOAD8_U_I32>; 218def : LoadPatImmOff<i32, extloadi16, regPlusImm, LOAD16_U_I32>; 219def : LoadPatImmOff<i64, extloadi8, regPlusImm, LOAD8_U_I64>; 220def : LoadPatImmOff<i64, extloadi16, regPlusImm, LOAD16_U_I64>; 221def : LoadPatImmOff<i64, extloadi32, regPlusImm, LOAD32_U_I64>; 222def : LoadPatImmOff<i32, extloadi8, or_is_add, LOAD8_U_I32>; 223def : LoadPatImmOff<i32, extloadi16, or_is_add, LOAD16_U_I32>; 224def : LoadPatImmOff<i64, extloadi8, or_is_add, LOAD8_U_I64>; 225def : LoadPatImmOff<i64, extloadi16, or_is_add, LOAD16_U_I64>; 226def : LoadPatImmOff<i64, extloadi32, or_is_add, LOAD32_U_I64>; 227def : LoadPatGlobalAddr<i32, extloadi8, LOAD8_U_I32>; 228def : LoadPatGlobalAddr<i32, extloadi16, LOAD16_U_I32>; 229def : LoadPatGlobalAddr<i64, extloadi8, LOAD8_U_I64>; 230def : LoadPatGlobalAddr<i64, extloadi16, LOAD16_U_I64>; 231def : LoadPatGlobalAddr<i64, extloadi32, LOAD32_U_I64>; 232 233// Select "don't care" extending loads with just a constant offset. 234def : LoadPatOffsetOnly<i32, extloadi8, LOAD8_U_I32>; 235def : LoadPatOffsetOnly<i32, extloadi16, LOAD16_U_I32>; 236def : LoadPatOffsetOnly<i64, extloadi8, LOAD8_U_I64>; 237def : LoadPatOffsetOnly<i64, extloadi16, LOAD16_U_I64>; 238def : LoadPatOffsetOnly<i64, extloadi32, LOAD32_U_I64>; 239def : LoadPatGlobalAddrOffOnly<i32, extloadi8, LOAD8_U_I32>; 240def : LoadPatGlobalAddrOffOnly<i32, extloadi16, LOAD16_U_I32>; 241def : LoadPatGlobalAddrOffOnly<i64, extloadi8, LOAD8_U_I64>; 242def : LoadPatGlobalAddrOffOnly<i64, extloadi16, LOAD16_U_I64>; 243def : LoadPatGlobalAddrOffOnly<i64, extloadi32, LOAD32_U_I64>; 244 245// Defines atomic and non-atomic stores, regular and truncating 246multiclass WebAssemblyStore<WebAssemblyRegClass rc, string Name, int Opcode> { 247 let mayStore = 1, UseNamedOperandTable = 1 in 248 defm "" : I<(outs), 249 (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val), 250 (outs), 251 (ins P2Align:$p2align, offset32_op:$off), [], 252 !strconcat(Name, "\t${off}(${addr})${p2align}, $val"), 253 !strconcat(Name, "\t${off}${p2align}"), Opcode>; 254} 255// Basic store. 256// Note: WebAssembly inverts SelectionDAG's usual operand order. 257defm STORE_I32 : WebAssemblyStore<I32, "i32.store", 0x36>; 258defm STORE_I64 : WebAssemblyStore<I64, "i64.store", 0x37>; 259defm STORE_F32 : WebAssemblyStore<F32, "f32.store", 0x38>; 260defm STORE_F64 : WebAssemblyStore<F64, "f64.store", 0x39>; 261 262// Select stores with no constant offset. 263class StorePatNoOffset<ValueType ty, PatFrag node, NI inst> : 264 Pat<(node ty:$val, I32:$addr), (inst 0, 0, I32:$addr, ty:$val)>; 265 266def : StorePatNoOffset<i32, store, STORE_I32>; 267def : StorePatNoOffset<i64, store, STORE_I64>; 268def : StorePatNoOffset<f32, store, STORE_F32>; 269def : StorePatNoOffset<f64, store, STORE_F64>; 270 271// Select stores with a constant offset. 272class StorePatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> : 273 Pat<(kind ty:$val, (operand I32:$addr, imm:$off)), 274 (inst 0, imm:$off, I32:$addr, ty:$val)>; 275 276def : StorePatImmOff<i32, store, regPlusImm, STORE_I32>; 277def : StorePatImmOff<i64, store, regPlusImm, STORE_I64>; 278def : StorePatImmOff<f32, store, regPlusImm, STORE_F32>; 279def : StorePatImmOff<f64, store, regPlusImm, STORE_F64>; 280def : StorePatImmOff<i32, store, or_is_add, STORE_I32>; 281def : StorePatImmOff<i64, store, or_is_add, STORE_I64>; 282def : StorePatImmOff<f32, store, or_is_add, STORE_F32>; 283def : StorePatImmOff<f64, store, or_is_add, STORE_F64>; 284 285class StorePatGlobalAddr<ValueType ty, PatFrag kind, NI inst> : 286 Pat<(kind ty:$val, 287 (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off))), 288 (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>, Requires<[IsNotPIC]>; 289def : StorePatGlobalAddr<i32, store, STORE_I32>; 290def : StorePatGlobalAddr<i64, store, STORE_I64>; 291def : StorePatGlobalAddr<f32, store, STORE_F32>; 292def : StorePatGlobalAddr<f64, store, STORE_F64>; 293 294// Select stores with just a constant offset. 295class StorePatOffsetOnly<ValueType ty, PatFrag kind, NI inst> : 296 Pat<(kind ty:$val, imm:$off), (inst 0, imm:$off, (CONST_I32 0), ty:$val)>; 297def : StorePatOffsetOnly<i32, store, STORE_I32>; 298def : StorePatOffsetOnly<i64, store, STORE_I64>; 299def : StorePatOffsetOnly<f32, store, STORE_F32>; 300def : StorePatOffsetOnly<f64, store, STORE_F64>; 301 302class StorePatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> : 303 Pat<(kind ty:$val, (WebAssemblywrapper tglobaladdr:$off)), 304 (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>, Requires<[IsNotPIC]>; 305def : StorePatGlobalAddrOffOnly<i32, store, STORE_I32>; 306def : StorePatGlobalAddrOffOnly<i64, store, STORE_I64>; 307def : StorePatGlobalAddrOffOnly<f32, store, STORE_F32>; 308def : StorePatGlobalAddrOffOnly<f64, store, STORE_F64>; 309 310// Truncating store. 311defm STORE8_I32 : WebAssemblyStore<I32, "i32.store8", 0x3a>; 312defm STORE16_I32 : WebAssemblyStore<I32, "i32.store16", 0x3b>; 313defm STORE8_I64 : WebAssemblyStore<I64, "i64.store8", 0x3c>; 314defm STORE16_I64 : WebAssemblyStore<I64, "i64.store16", 0x3d>; 315defm STORE32_I64 : WebAssemblyStore<I64, "i64.store32", 0x3e>; 316 317// Select truncating stores with no constant offset. 318def : StorePatNoOffset<i32, truncstorei8, STORE8_I32>; 319def : StorePatNoOffset<i32, truncstorei16, STORE16_I32>; 320def : StorePatNoOffset<i64, truncstorei8, STORE8_I64>; 321def : StorePatNoOffset<i64, truncstorei16, STORE16_I64>; 322def : StorePatNoOffset<i64, truncstorei32, STORE32_I64>; 323 324// Select truncating stores with a constant offset. 325def : StorePatImmOff<i32, truncstorei8, regPlusImm, STORE8_I32>; 326def : StorePatImmOff<i32, truncstorei16, regPlusImm, STORE16_I32>; 327def : StorePatImmOff<i64, truncstorei8, regPlusImm, STORE8_I64>; 328def : StorePatImmOff<i64, truncstorei16, regPlusImm, STORE16_I64>; 329def : StorePatImmOff<i64, truncstorei32, regPlusImm, STORE32_I64>; 330def : StorePatImmOff<i32, truncstorei8, or_is_add, STORE8_I32>; 331def : StorePatImmOff<i32, truncstorei16, or_is_add, STORE16_I32>; 332def : StorePatImmOff<i64, truncstorei8, or_is_add, STORE8_I64>; 333def : StorePatImmOff<i64, truncstorei16, or_is_add, STORE16_I64>; 334def : StorePatImmOff<i64, truncstorei32, or_is_add, STORE32_I64>; 335 336def : StorePatGlobalAddr<i32, truncstorei8, STORE8_I32>; 337def : StorePatGlobalAddr<i32, truncstorei16, STORE16_I32>; 338def : StorePatGlobalAddr<i64, truncstorei8, STORE8_I64>; 339def : StorePatGlobalAddr<i64, truncstorei16, STORE16_I64>; 340def : StorePatGlobalAddr<i64, truncstorei32, STORE32_I64>; 341 342// Select truncating stores with just a constant offset. 343def : StorePatOffsetOnly<i32, truncstorei8, STORE8_I32>; 344def : StorePatOffsetOnly<i32, truncstorei16, STORE16_I32>; 345def : StorePatOffsetOnly<i64, truncstorei8, STORE8_I64>; 346def : StorePatOffsetOnly<i64, truncstorei16, STORE16_I64>; 347def : StorePatOffsetOnly<i64, truncstorei32, STORE32_I64>; 348def : StorePatGlobalAddrOffOnly<i32, truncstorei8, STORE8_I32>; 349def : StorePatGlobalAddrOffOnly<i32, truncstorei16, STORE16_I32>; 350def : StorePatGlobalAddrOffOnly<i64, truncstorei8, STORE8_I64>; 351def : StorePatGlobalAddrOffOnly<i64, truncstorei16, STORE16_I64>; 352def : StorePatGlobalAddrOffOnly<i64, truncstorei32, STORE32_I64>; 353 354// Current memory size. 355defm MEMORY_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags), 356 (outs), (ins i32imm:$flags), 357 [(set I32:$dst, 358 (int_wasm_memory_size (i32 imm:$flags)))], 359 "memory.size\t$dst, $flags", "memory.size\t$flags", 360 0x3f>, 361 Requires<[HasAddr32]>; 362 363// Grow memory. 364defm MEMORY_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta), 365 (outs), (ins i32imm:$flags), 366 [(set I32:$dst, 367 (int_wasm_memory_grow (i32 imm:$flags), 368 I32:$delta))], 369 "memory.grow\t$dst, $flags, $delta", 370 "memory.grow\t$flags", 0x40>, 371 Requires<[HasAddr32]>; 372