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