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 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// Defines atomic and non-atomic stores, regular and truncating 307class WebAssemblyStore<WebAssemblyRegClass rc, string Name, int Opcode> : 308 I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val), [], 309 !strconcat(Name, "\t${off}(${addr})${p2align}, $val"), Opcode>; 310// Basic store. 311// Note: WebAssembly inverts SelectionDAG's usual operand order. 312def STORE_I32 : WebAssemblyStore<I32, "i32.store", 0x36>; 313def STORE_I64 : WebAssemblyStore<I64, "i64.store", 0x37>; 314def STORE_F32 : WebAssemblyStore<F32, "f32.store", 0x38>; 315def STORE_F64 : WebAssemblyStore<F64, "f64.store", 0x39>; 316 317} // Defs = [ARGUMENTS] 318 319// Select stores with no constant offset. 320class StorePatNoOffset<ValueType ty, PatFrag node, I inst> : 321 Pat<(node ty:$val, I32:$addr), (inst 0, 0, $addr, $val)>; 322 323def : StorePatNoOffset<i32, store, STORE_I32>; 324def : StorePatNoOffset<i64, store, STORE_I64>; 325def : StorePatNoOffset<f32, store, STORE_F32>; 326def : StorePatNoOffset<f64, store, STORE_F64>; 327 328// Select stores with a constant offset. 329class StorePatImmOff<ValueType ty, PatFrag storekind, PatFrag operand, I inst> : 330 Pat<(storekind ty:$val, (operand I32:$addr, imm:$off)), 331 (inst 0, imm:$off, $addr, ty:$val)>; 332 333def : StorePatImmOff<i32, store, regPlusImm, STORE_I32>; 334def : StorePatImmOff<i64, store, regPlusImm, STORE_I64>; 335def : StorePatImmOff<f32, store, regPlusImm, STORE_F32>; 336def : StorePatImmOff<f64, store, regPlusImm, STORE_F64>; 337def : StorePatImmOff<i32, store, or_is_add, STORE_I32>; 338def : StorePatImmOff<i64, store, or_is_add, STORE_I64>; 339def : StorePatImmOff<f32, store, or_is_add, STORE_F32>; 340def : StorePatImmOff<f64, store, or_is_add, STORE_F64>; 341 342class StorePatGlobalAddr<ValueType ty, PatFrag storekind, I inst> : 343 Pat<(storekind ty:$val, (regPlusGA I32:$addr, 344 (WebAssemblywrapper tglobaladdr:$off))), 345 (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>; 346def : StorePatGlobalAddr<i32, store, STORE_I32>; 347def : StorePatGlobalAddr<i64, store, STORE_I64>; 348def : StorePatGlobalAddr<f32, store, STORE_F32>; 349def : StorePatGlobalAddr<f64, store, STORE_F64>; 350 351class StorePatExternalSym<ValueType ty, PatFrag storekind, I inst> : 352 Pat<(storekind ty:$val, (add I32:$addr, 353 (WebAssemblywrapper texternalsym:$off))), 354 (inst 0, texternalsym:$off, I32:$addr, ty:$val)>; 355def : StorePatExternalSym<i32, store, STORE_I32>; 356def : StorePatExternalSym<i64, store, STORE_I64>; 357def : StorePatExternalSym<f32, store, STORE_F32>; 358def : StorePatExternalSym<f64, store, STORE_F64>; 359 360// Select stores with just a constant offset. 361class StorePatOffsetOnly<ValueType ty, PatFrag storekind, I inst> : 362 Pat<(storekind ty:$val, imm:$off), 363 (inst 0, imm:$off, (CONST_I32 0), ty:$val)>; 364def : StorePatOffsetOnly<i32, store, STORE_I32>; 365def : StorePatOffsetOnly<i64, store, STORE_I64>; 366def : StorePatOffsetOnly<f32, store, STORE_F32>; 367def : StorePatOffsetOnly<f64, store, STORE_F64>; 368 369class StorePatGlobalAddrOffOnly<ValueType ty, PatFrag storekind, I inst> : 370 Pat<(storekind ty:$val, (WebAssemblywrapper tglobaladdr:$off)), 371 (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>; 372def : StorePatGlobalAddrOffOnly<i32, store, STORE_I32>; 373def : StorePatGlobalAddrOffOnly<i64, store, STORE_I64>; 374def : StorePatGlobalAddrOffOnly<f32, store, STORE_F32>; 375def : StorePatGlobalAddrOffOnly<f64, store, STORE_F64>; 376 377class StorePatExternSymOffOnly<ValueType ty, PatFrag storekind, I inst> : 378 Pat<(storekind ty:$val, (WebAssemblywrapper texternalsym:$off)), 379 (inst 0, texternalsym:$off, (CONST_I32 0), ty:$val)>; 380def : StorePatExternSymOffOnly<i32, store, STORE_I32>; 381def : StorePatExternSymOffOnly<i64, store, STORE_I64>; 382def : StorePatExternSymOffOnly<f32, store, STORE_F32>; 383def : StorePatExternSymOffOnly<f64, store, STORE_F64>; 384 385 386let Defs = [ARGUMENTS] in { 387 388// Truncating store. 389def STORE8_I32 : WebAssemblyStore<I32, "i32.store8", 0x3a>; 390def STORE16_I32 : WebAssemblyStore<I32, "i32.store16", 0x3b>; 391def STORE8_I64 : WebAssemblyStore<I64, "i64.store8", 0x3c>; 392def STORE16_I64 : WebAssemblyStore<I64, "i64.store16", 0x3d>; 393def STORE32_I64 : WebAssemblyStore<I64, "i64.store32", 0x3e>; 394 395} // Defs = [ARGUMENTS] 396 397// Select truncating stores with no constant offset. 398def : StorePatNoOffset<i32, truncstorei8, STORE8_I32>; 399def : StorePatNoOffset<i32, truncstorei16, STORE16_I32>; 400def : StorePatNoOffset<i64, truncstorei8, STORE8_I64>; 401def : StorePatNoOffset<i64, truncstorei16, STORE16_I64>; 402def : StorePatNoOffset<i64, truncstorei32, STORE32_I64>; 403 404// Select truncating stores with a constant offset. 405def : StorePatImmOff<i32, truncstorei8, regPlusImm, STORE8_I32>; 406def : StorePatImmOff<i32, truncstorei16, regPlusImm, STORE16_I32>; 407def : StorePatImmOff<i64, truncstorei8, regPlusImm, STORE8_I64>; 408def : StorePatImmOff<i64, truncstorei16, regPlusImm, STORE16_I64>; 409def : StorePatImmOff<i64, truncstorei32, regPlusImm, STORE32_I64>; 410def : StorePatImmOff<i32, truncstorei8, or_is_add, STORE8_I32>; 411def : StorePatImmOff<i32, truncstorei16, or_is_add, STORE16_I32>; 412def : StorePatImmOff<i64, truncstorei8, or_is_add, STORE8_I64>; 413def : StorePatImmOff<i64, truncstorei16, or_is_add, STORE16_I64>; 414def : StorePatImmOff<i64, truncstorei32, or_is_add, STORE32_I64>; 415 416def : StorePatGlobalAddr<i32, truncstorei8, STORE8_I32>; 417def : StorePatGlobalAddr<i32, truncstorei16, STORE16_I32>; 418def : StorePatGlobalAddr<i64, truncstorei8, STORE8_I64>; 419def : StorePatGlobalAddr<i64, truncstorei16, STORE16_I64>; 420def : StorePatGlobalAddr<i64, truncstorei32, STORE32_I64>; 421def : StorePatExternalSym<i32, truncstorei8, STORE8_I32>; 422def : StorePatExternalSym<i32, truncstorei16, STORE16_I32>; 423def : StorePatExternalSym<i64, truncstorei8, STORE8_I64>; 424def : StorePatExternalSym<i64, truncstorei16, STORE16_I64>; 425def : StorePatExternalSym<i64, truncstorei32, STORE32_I64>; 426 427// Select truncating stores with just a constant offset. 428def : StorePatOffsetOnly<i32, truncstorei8, STORE8_I32>; 429def : StorePatOffsetOnly<i32, truncstorei16, STORE16_I32>; 430def : StorePatOffsetOnly<i64, truncstorei8, STORE8_I64>; 431def : StorePatOffsetOnly<i64, truncstorei16, STORE16_I64>; 432def : StorePatOffsetOnly<i64, truncstorei32, STORE32_I64>; 433def : StorePatGlobalAddrOffOnly<i32, truncstorei8, STORE8_I32>; 434def : StorePatGlobalAddrOffOnly<i32, truncstorei16, STORE16_I32>; 435def : StorePatGlobalAddrOffOnly<i64, truncstorei8, STORE8_I64>; 436def : StorePatGlobalAddrOffOnly<i64, truncstorei16, STORE16_I64>; 437def : StorePatGlobalAddrOffOnly<i64, truncstorei32, STORE32_I64>; 438def : StorePatExternSymOffOnly<i32, truncstorei8, STORE8_I32>; 439def : StorePatExternSymOffOnly<i32, truncstorei16, STORE16_I32>; 440def : StorePatExternSymOffOnly<i64, truncstorei8, STORE8_I64>; 441def : StorePatExternSymOffOnly<i64, truncstorei16, STORE16_I64>; 442def : StorePatExternSymOffOnly<i64, truncstorei32, STORE32_I64>; 443 444let Defs = [ARGUMENTS] in { 445 446// Current memory size. 447def MEM_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags), 448 [(set I32:$dst, (int_wasm_mem_size (i32 imm:$flags)))], 449 "mem.size\t$dst, $flags", 0x3f>, 450 Requires<[HasAddr32]>; 451def CURRENT_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags), 452 [], 453 "current_memory\t$dst", 0x3f>, 454 Requires<[HasAddr32]>; 455 456// Grow memory. 457def MEM_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta), 458 [(set I32:$dst, 459 (int_wasm_mem_grow (i32 imm:$flags), I32:$delta))], 460 "mem.grow\t$dst, $flags, $delta", 0x3f>, 461 Requires<[HasAddr32]>; 462def GROW_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta), 463 [], 464 "grow_memory\t$dst, $delta", 0x40>, 465 Requires<[HasAddr32]>; 466 467} // Defs = [ARGUMENTS] 468 469def : Pat<(int_wasm_current_memory), 470 (CURRENT_MEMORY_I32 0)>; 471def : Pat<(int_wasm_grow_memory I32:$delta), 472 (GROW_MEMORY_I32 0, $delta)>; 473