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