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