WebAssemblyInstrMemory.td revision 296417
11638Srgrimes// WebAssemblyInstrMemory.td-WebAssembly Memory codegen support -*- tablegen -*-
250476Speter//
31638Srgrimes//                     The LLVM Compiler Infrastructure
43470Srgrimes//
53470Srgrimes// This file is distributed under the University of Illinois Open Source
61638Srgrimes// License. See LICENSE.TXT for details.
774942Sru//
823559Swosch//===----------------------------------------------------------------------===//
91638Srgrimes///
1023559Swosch/// \file
1123559Swosch/// \brief WebAssembly Memory operand code-gen constructs.
1223559Swosch///
1323559Swosch//===----------------------------------------------------------------------===//
1423559Swosch
1523559Swosch// TODO:
1623559Swosch//  - HasAddr64
1723559Swosch//  - WebAssemblyTargetLowering having to do with atomics
1823559Swosch//  - Each has optional alignment.
1923559Swosch
2023559Swosch// WebAssembly has i8/i16/i32/i64/f32/f64 memory types, but doesn't have i8/i16
2123559Swosch// local types. These memory-only types instead zero- or sign-extend into local
2223559Swosch// types when loading, and truncate when storing.
2323559Swosch
2423559Swosch// WebAssembly constant offsets are performed as unsigned with infinite
2523559Swosch// precision, so we need to check for NoUnsignedWrap so that we don't fold an
2623559Swosch// offset for an add that needs wrapping.
271638Srgrimesdef regPlusImm : PatFrag<(ops node:$addr, node:$off),
281638Srgrimes                         (add node:$addr, node:$off),
291638Srgrimes                         [{ return N->getFlags()->hasNoUnsignedWrap(); }]>;
3023578Swosch
3123578Swosch// GlobalAddresses are conceptually unsigned values, so we can also fold them
3223578Swosch// into immediate values as long as their offsets are non-negative.
331638Srgrimesdef regPlusGA : PatFrag<(ops node:$addr, node:$off),
341638Srgrimes                        (add node:$addr, node:$off),
351638Srgrimes                        [{
361638Srgrimes  return N->getFlags()->hasNoUnsignedWrap() ||
371638Srgrimes         (N->getOperand(1)->getOpcode() == WebAssemblyISD::Wrapper &&
381638Srgrimes          isa<GlobalAddressSDNode>(N->getOperand(1)->getOperand(0)) &&
391638Srgrimes          cast<GlobalAddressSDNode>(N->getOperand(1)->getOperand(0))
401638Srgrimes             ->getOffset() >= 0);
411638Srgrimes}]>;
421638Srgrimes
431638Srgrimes// We don't need a regPlusES because external symbols never have constant
441638Srgrimes// offsets folded into them, so we can just use add.
451638Srgrimes
461638Srgrimeslet Defs = [ARGUMENTS] in {
471638Srgrimes
481638Srgrimes// Basic load.
491638Srgrimesdef LOAD_I32 : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr), [],
501638Srgrimes                 "i32.load\t$dst, ${off}(${addr})">;
511638Srgrimesdef LOAD_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr), [],
521638Srgrimes                 "i64.load\t$dst, ${off}(${addr})">;
531638Srgrimesdef LOAD_F32 : I<(outs F32:$dst), (ins i32imm:$off, I32:$addr), [],
541638Srgrimes                 "f32.load\t$dst, ${off}(${addr})">;
551638Srgrimesdef LOAD_F64 : I<(outs F64:$dst), (ins i32imm:$off, I32:$addr), [],
561638Srgrimes                 "f64.load\t$dst, ${off}(${addr})">;
571638Srgrimes
581638Srgrimes} // Defs = [ARGUMENTS]
591638Srgrimes
601638Srgrimes// Select loads with no constant offset.
611638Srgrimesdef : Pat<(i32 (load I32:$addr)), (LOAD_I32 0, $addr)>;
621638Srgrimesdef : Pat<(i64 (load I32:$addr)), (LOAD_I64 0, $addr)>;
631638Srgrimesdef : Pat<(f32 (load I32:$addr)), (LOAD_F32 0, $addr)>;
641638Srgrimesdef : Pat<(f64 (load I32:$addr)), (LOAD_F64 0, $addr)>;
651638Srgrimes
661638Srgrimes// Select loads with a constant offset.
671638Srgrimesdef : Pat<(i32 (load (regPlusImm I32:$addr, imm:$off))),
681638Srgrimes          (LOAD_I32 imm:$off, $addr)>;
691638Srgrimesdef : Pat<(i64 (load (regPlusImm I32:$addr, imm:$off))),
701638Srgrimes          (LOAD_I64 imm:$off, $addr)>;
711638Srgrimesdef : Pat<(f32 (load (regPlusImm I32:$addr, imm:$off))),
721638Srgrimes          (LOAD_F32 imm:$off, $addr)>;
731638Srgrimesdef : Pat<(f64 (load (regPlusImm I32:$addr, imm:$off))),
741638Srgrimes          (LOAD_F64 imm:$off, $addr)>;
751638Srgrimesdef : Pat<(i32 (load (regPlusGA I32:$addr,
761638Srgrimes                                (WebAssemblywrapper tglobaladdr:$off)))),
771638Srgrimes          (LOAD_I32 tglobaladdr:$off, $addr)>;
781638Srgrimesdef : Pat<(i64 (load (regPlusGA I32:$addr,
791638Srgrimes                                (WebAssemblywrapper tglobaladdr:$off)))),
801638Srgrimes          (LOAD_I64 tglobaladdr:$off, $addr)>;
811638Srgrimesdef : Pat<(f32 (load (regPlusGA I32:$addr,
821638Srgrimes                                (WebAssemblywrapper tglobaladdr:$off)))),
831638Srgrimes          (LOAD_F32 tglobaladdr:$off, $addr)>;
841638Srgrimesdef : Pat<(f64 (load (regPlusGA I32:$addr,
851638Srgrimes                                (WebAssemblywrapper tglobaladdr:$off)))),
861638Srgrimes          (LOAD_F64 tglobaladdr:$off, $addr)>;
871638Srgrimesdef : Pat<(i32 (load (add I32:$addr, (WebAssemblywrapper texternalsym:$off)))),
881638Srgrimes          (LOAD_I32 texternalsym:$off, $addr)>;
891638Srgrimesdef : Pat<(i64 (load (add I32:$addr, (WebAssemblywrapper texternalsym:$off)))),
901638Srgrimes          (LOAD_I64 texternalsym:$off, $addr)>;
911638Srgrimesdef : Pat<(f32 (load (add I32:$addr, (WebAssemblywrapper texternalsym:$off)))),
921638Srgrimes          (LOAD_F32 texternalsym:$off, $addr)>;
9383075Srudef : Pat<(f64 (load (add I32:$addr, (WebAssemblywrapper texternalsym:$off)))),
941638Srgrimes          (LOAD_F64 texternalsym:$off, $addr)>;
9583075Sru
9683075Sru// Select loads with just a constant offset.
971638Srgrimesdef : Pat<(i32 (load imm:$off)), (LOAD_I32 imm:$off, (CONST_I32 0))>;
9883075Srudef : Pat<(i64 (load imm:$off)), (LOAD_I64 imm:$off, (CONST_I32 0))>;
9983075Srudef : Pat<(f32 (load imm:$off)), (LOAD_F32 imm:$off, (CONST_I32 0))>;
10083075Srudef : Pat<(f64 (load imm:$off)), (LOAD_F64 imm:$off, (CONST_I32 0))>;
1011638Srgrimesdef : Pat<(i32 (load (WebAssemblywrapper tglobaladdr:$off))),
1021638Srgrimes          (LOAD_I32 tglobaladdr:$off, (CONST_I32 0))>;
1031638Srgrimesdef : Pat<(i64 (load (WebAssemblywrapper tglobaladdr:$off))),
1041638Srgrimes          (LOAD_I64 tglobaladdr:$off, (CONST_I32 0))>;
1051638Srgrimesdef : Pat<(f32 (load (WebAssemblywrapper tglobaladdr:$off))),
1061638Srgrimes          (LOAD_F32 tglobaladdr:$off, (CONST_I32 0))>;
1071638Srgrimesdef : Pat<(f64 (load (WebAssemblywrapper tglobaladdr:$off))),
1081638Srgrimes          (LOAD_F64 tglobaladdr:$off, (CONST_I32 0))>;
1091638Srgrimesdef : Pat<(i32 (load (WebAssemblywrapper texternalsym:$off))),
1101638Srgrimes          (LOAD_I32 texternalsym:$off, (CONST_I32 0))>;
1111638Srgrimesdef : Pat<(i64 (load (WebAssemblywrapper texternalsym:$off))),
1121638Srgrimes          (LOAD_I64 texternalsym:$off, (CONST_I32 0))>;
1131638Srgrimesdef : Pat<(f32 (load (WebAssemblywrapper texternalsym:$off))),
1141638Srgrimes          (LOAD_F32 texternalsym:$off, (CONST_I32 0))>;
11574942Srudef : Pat<(f64 (load (WebAssemblywrapper texternalsym:$off))),
1161638Srgrimes          (LOAD_F64 texternalsym:$off, (CONST_I32 0))>;
11758494Sru
1181638Srgrimeslet Defs = [ARGUMENTS] in {
1191638Srgrimes
1201638Srgrimes// Extending load.
12174942Srudef LOAD8_S_I32  : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr), [],
12274942Sru                     "i32.load8_s\t$dst, ${off}(${addr})">;
1231638Srgrimesdef LOAD8_U_I32  : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr), [],
1241638Srgrimes                     "i32.load8_u\t$dst, ${off}(${addr})">;
1251638Srgrimesdef LOAD16_S_I32 : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr), [],
1261638Srgrimes                     "i32.load16_s\t$dst, ${off}(${addr})">;
1271638Srgrimesdef LOAD16_U_I32 : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr), [],
1281638Srgrimes                     "i32.load16_u\t$dst, ${off}(${addr})">;
1291638Srgrimesdef LOAD8_S_I64  : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr), [],
1301638Srgrimes                     "i64.load8_s\t$dst, ${off}(${addr})">;
1311638Srgrimesdef LOAD8_U_I64  : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr), [],
1321638Srgrimes                     "i64.load8_u\t$dst, ${off}(${addr})">;
1331638Srgrimesdef LOAD16_S_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr), [],
1341638Srgrimes                     "i64.load16_s\t$dst, ${off}(${addr})">;
1351638Srgrimesdef LOAD16_U_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr), [],
1361638Srgrimes                     "i64.load16_u\t$dst, ${off}(${addr})">;
1371638Srgrimesdef LOAD32_S_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr), [],
1381638Srgrimes                     "i64.load32_s\t$dst, ${off}(${addr})">;
1391638Srgrimesdef LOAD32_U_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr), [],
1401638Srgrimes                     "i64.load32_u\t$dst, ${off}(${addr})">;
1411638Srgrimes
1421638Srgrimes} // Defs = [ARGUMENTS]
1431638Srgrimes
1441638Srgrimes// Select extending loads with no constant offset.
1451638Srgrimesdef : Pat<(i32 (sextloadi8 I32:$addr)), (LOAD8_S_I32 0, $addr)>;
1461638Srgrimesdef : Pat<(i32 (zextloadi8 I32:$addr)), (LOAD8_U_I32 0, $addr)>;
1471638Srgrimesdef : Pat<(i32 (sextloadi16 I32:$addr)), (LOAD16_S_I32 0, $addr)>;
1481638Srgrimesdef : Pat<(i32 (zextloadi16 I32:$addr)), (LOAD16_U_I32 0, $addr)>;
1491638Srgrimesdef : Pat<(i64 (sextloadi8 I32:$addr)), (LOAD8_S_I64 0, $addr)>;
1501638Srgrimesdef : Pat<(i64 (zextloadi8 I32:$addr)), (LOAD8_U_I64 0, $addr)>;
1511638Srgrimesdef : Pat<(i64 (sextloadi16 I32:$addr)), (LOAD16_S_I64 0, $addr)>;
1521638Srgrimesdef : Pat<(i64 (zextloadi16 I32:$addr)), (LOAD16_U_I64 0, $addr)>;
1531638Srgrimesdef : Pat<(i64 (sextloadi32 I32:$addr)), (LOAD32_S_I64 0, $addr)>;
1541638Srgrimesdef : Pat<(i64 (zextloadi32 I32:$addr)), (LOAD32_U_I64 0, $addr)>;
1551638Srgrimes
1561638Srgrimes// Select extending loads with a constant offset.
1571638Srgrimesdef : Pat<(i32 (sextloadi8 (regPlusImm I32:$addr, imm:$off))),
1581638Srgrimes          (LOAD8_S_I32 imm:$off, $addr)>;
1591638Srgrimesdef : Pat<(i32 (zextloadi8 (regPlusImm I32:$addr, imm:$off))),
1601638Srgrimes          (LOAD8_U_I32 imm:$off, $addr)>;
1611638Srgrimesdef : Pat<(i32 (sextloadi16 (regPlusImm I32:$addr, imm:$off))),
1621638Srgrimes          (LOAD16_S_I32 imm:$off, $addr)>;
1631638Srgrimesdef : Pat<(i32 (zextloadi16 (regPlusImm I32:$addr, imm:$off))),
1641638Srgrimes          (LOAD16_U_I32 imm:$off, $addr)>;
1651638Srgrimesdef : Pat<(i64 (sextloadi8 (regPlusImm I32:$addr, imm:$off))),
1661638Srgrimes          (LOAD8_S_I64 imm:$off, $addr)>;
1671638Srgrimesdef : Pat<(i64 (zextloadi8 (regPlusImm I32:$addr, imm:$off))),
1681638Srgrimes          (LOAD8_U_I64 imm:$off, $addr)>;
1691638Srgrimesdef : Pat<(i64 (sextloadi16 (regPlusImm I32:$addr, imm:$off))),
1701638Srgrimes          (LOAD16_S_I64 imm:$off, $addr)>;
1711638Srgrimesdef : Pat<(i64 (zextloadi16 (regPlusImm I32:$addr, imm:$off))),
1721638Srgrimes          (LOAD16_U_I64 imm:$off, $addr)>;
1731638Srgrimesdef : Pat<(i64 (sextloadi32 (regPlusImm I32:$addr, imm:$off))),
1741638Srgrimes          (LOAD32_S_I64 imm:$off, $addr)>;
1751638Srgrimesdef : Pat<(i64 (zextloadi32 (regPlusImm I32:$addr, imm:$off))),
1761638Srgrimes          (LOAD32_U_I64 imm:$off, $addr)>;
1771638Srgrimesdef : Pat<(i32 (sextloadi8 (regPlusGA I32:$addr,
1781638Srgrimes                                      (WebAssemblywrapper tglobaladdr:$off)))),
1791638Srgrimes          (LOAD8_S_I32 tglobaladdr:$off, $addr)>;
1801638Srgrimesdef : Pat<(i32 (zextloadi8 (regPlusGA I32:$addr,
1811638Srgrimes                                      (WebAssemblywrapper tglobaladdr:$off)))),
1821638Srgrimes          (LOAD8_U_I32 tglobaladdr:$off, $addr)>;
1831638Srgrimesdef : Pat<(i32 (sextloadi16 (regPlusGA I32:$addr,
1841638Srgrimes                                       (WebAssemblywrapper tglobaladdr:$off)))),
1851638Srgrimes          (LOAD16_S_I32 tglobaladdr:$off, $addr)>;
1861638Srgrimesdef : Pat<(i32 (zextloadi16 (regPlusGA I32:$addr,
1871638Srgrimes                                       (WebAssemblywrapper tglobaladdr:$off)))),
1881638Srgrimes          (LOAD16_U_I32 tglobaladdr:$off, $addr)>;
1891638Srgrimesdef : Pat<(i64 (sextloadi8 (regPlusGA I32:$addr,
1901638Srgrimes                                      (WebAssemblywrapper tglobaladdr:$off)))),
1911638Srgrimes          (LOAD8_S_I64 tglobaladdr:$off, $addr)>;
1921638Srgrimesdef : Pat<(i64 (zextloadi8 (regPlusGA I32:$addr,
19316437Sphk                                      (WebAssemblywrapper tglobaladdr:$off)))),
19416437Sphk          (LOAD8_U_I64 tglobaladdr:$off, $addr)>;
19516437Sphkdef : Pat<(i64 (sextloadi16 (regPlusGA I32:$addr,
1961638Srgrimes                                       (WebAssemblywrapper tglobaladdr:$off)))),
1971638Srgrimes          (LOAD16_S_I64 tglobaladdr:$off, $addr)>;
1981638Srgrimesdef : Pat<(i64 (zextloadi16 (regPlusGA I32:$addr,
1991638Srgrimes                                       (WebAssemblywrapper tglobaladdr:$off)))),
2001638Srgrimes          (LOAD16_U_I64 tglobaladdr:$off, $addr)>;
2011638Srgrimesdef : Pat<(i64 (sextloadi32 (regPlusGA I32:$addr,
2021638Srgrimes                                       (WebAssemblywrapper tglobaladdr:$off)))),
2031638Srgrimes          (LOAD32_S_I64 tglobaladdr:$off, $addr)>;
2041638Srgrimesdef : Pat<(i64 (zextloadi32 (regPlusGA I32:$addr,
2051638Srgrimes                                       (WebAssemblywrapper tglobaladdr:$off)))),
2061638Srgrimes          (LOAD32_U_I64 tglobaladdr:$off, $addr)>;
2071638Srgrimesdef : Pat<(i32 (sextloadi8 (add I32:$addr,
2081638Srgrimes                                (WebAssemblywrapper texternalsym:$off)))),
2091638Srgrimes          (LOAD8_S_I32 texternalsym:$off, $addr)>;
2101638Srgrimesdef : Pat<(i32 (zextloadi8 (add I32:$addr,
2111638Srgrimes                                (WebAssemblywrapper texternalsym:$off)))),
2121638Srgrimes          (LOAD8_U_I32 texternalsym:$off, $addr)>;
2131638Srgrimesdef : Pat<(i32 (sextloadi16 (add I32:$addr,
2141638Srgrimes                                 (WebAssemblywrapper texternalsym:$off)))),
2151638Srgrimes          (LOAD16_S_I32 texternalsym:$off, $addr)>;
2161638Srgrimesdef : Pat<(i32 (zextloadi16 (add I32:$addr,
2171638Srgrimes                                 (WebAssemblywrapper texternalsym:$off)))),
21874942Sru          (LOAD16_U_I32 texternalsym:$off, $addr)>;
21974942Srudef : Pat<(i64 (sextloadi8 (add I32:$addr,
2201638Srgrimes                                (WebAssemblywrapper texternalsym:$off)))),
2211638Srgrimes          (LOAD8_S_I64 texternalsym:$off, $addr)>;
2221638Srgrimesdef : Pat<(i64 (zextloadi8 (add I32:$addr,
2231638Srgrimes                                (WebAssemblywrapper texternalsym:$off)))),
22475083Sru          (LOAD8_U_I64 texternalsym:$off, $addr)>;
22575083Srudef : Pat<(i64 (sextloadi16 (add I32:$addr,
22675083Sru                                 (WebAssemblywrapper texternalsym:$off)))),
22753965Smharo          (LOAD16_S_I64 texternalsym:$off, $addr)>;
2281638Srgrimesdef : Pat<(i64 (zextloadi16 (add I32:$addr,
2291638Srgrimes                                 (WebAssemblywrapper texternalsym:$off)))),
2301638Srgrimes          (LOAD16_U_I64 texternalsym:$off, $addr)>;
2311638Srgrimesdef : Pat<(i64 (sextloadi32 (add I32:$addr,
2321638Srgrimes                                 (WebAssemblywrapper texternalsym:$off)))),
2331638Srgrimes          (LOAD32_S_I64 texternalsym:$off, $addr)>;
2341638Srgrimesdef : Pat<(i64 (zextloadi32 (add I32:$addr,
2351638Srgrimes                                 (WebAssemblywrapper texternalsym:$off)))),
23614701Sbde          (LOAD32_U_I64 texternalsym:$off, $addr)>;
23714701Sbde
23814701Sbde// Select extending loads with just a constant offset.
23914701Sbdedef : Pat<(i32 (sextloadi8 imm:$off)), (LOAD8_S_I32 imm:$off, (CONST_I32 0))>;
2401638Srgrimesdef : Pat<(i32 (zextloadi8 imm:$off)), (LOAD8_U_I32 imm:$off, (CONST_I32 0))>;
24114701Sbdedef : Pat<(i32 (sextloadi16 imm:$off)), (LOAD16_S_I32 imm:$off, (CONST_I32 0))>;
24214701Sbdedef : Pat<(i32 (zextloadi16 imm:$off)), (LOAD16_U_I32 imm:$off, (CONST_I32 0))>;
24314701Sbdedef : Pat<(i64 (sextloadi8 imm:$off)), (LOAD8_S_I64 imm:$off, (CONST_I32 0))>;
24414701Sbdedef : Pat<(i64 (zextloadi8 imm:$off)), (LOAD8_U_I64 imm:$off, (CONST_I32 0))>;
24514701Sbdedef : Pat<(i64 (sextloadi16 imm:$off)), (LOAD16_S_I64 imm:$off, (CONST_I32 0))>;
24614701Sbdedef : Pat<(i64 (zextloadi16 imm:$off)), (LOAD16_U_I64 imm:$off, (CONST_I32 0))>;
24714701Sbdedef : Pat<(i64 (sextloadi32 imm:$off)), (LOAD32_S_I64 imm:$off, (CONST_I32 0))>;
24814701Sbdedef : Pat<(i64 (zextloadi32 imm:$off)), (LOAD32_U_I64 imm:$off, (CONST_I32 0))>;
2491638Srgrimesdef : Pat<(i32 (sextloadi8 (WebAssemblywrapper tglobaladdr:$off))),
2501638Srgrimes          (LOAD8_S_I32 tglobaladdr:$off, (CONST_I32 0))>;
2511638Srgrimesdef : Pat<(i32 (zextloadi8 (WebAssemblywrapper tglobaladdr:$off))),
2521638Srgrimes          (LOAD8_U_I32 tglobaladdr:$off, (CONST_I32 0))>;
2531638Srgrimesdef : Pat<(i32 (sextloadi16 (WebAssemblywrapper tglobaladdr:$off))),
2541638Srgrimes          (LOAD16_S_I32 tglobaladdr:$off, (CONST_I32 0))>;
2551638Srgrimesdef : Pat<(i32 (zextloadi16 (WebAssemblywrapper tglobaladdr:$off))),
2561638Srgrimes          (LOAD16_U_I32 tglobaladdr:$off, (CONST_I32 0))>;
25775284Srudef : Pat<(i64 (sextloadi8 (WebAssemblywrapper tglobaladdr:$off))),
25875284Sru          (LOAD8_S_I64 tglobaladdr:$off, (CONST_I32 0))>;
25975284Srudef : Pat<(i64 (zextloadi8 (WebAssemblywrapper tglobaladdr:$off))),
26075284Sru          (LOAD8_U_I64 tglobaladdr:$off, (CONST_I32 0))>;
26175284Srudef : Pat<(i64 (sextloadi16 (WebAssemblywrapper tglobaladdr:$off))),
26274942Sru          (LOAD16_S_I64 tglobaladdr:$off, (CONST_I32 0))>;
26374942Srudef : Pat<(i64 (zextloadi16 (WebAssemblywrapper tglobaladdr:$off))),
2641638Srgrimes          (LOAD16_U_I64 tglobaladdr:$off, (CONST_I32 0))>;
2651638Srgrimesdef : Pat<(i64 (sextloadi32 (WebAssemblywrapper tglobaladdr:$off))),
2661638Srgrimes          (LOAD32_S_I64 tglobaladdr:$off, (CONST_I32 0))>;
2671638Srgrimesdef : Pat<(i64 (zextloadi32 (WebAssemblywrapper tglobaladdr:$off))),
2681638Srgrimes          (LOAD32_U_I64 tglobaladdr:$off, (CONST_I32 0))>;
2691638Srgrimesdef : Pat<(i32 (sextloadi8 (WebAssemblywrapper texternalsym:$off))),
2701638Srgrimes          (LOAD8_S_I32 texternalsym:$off, (CONST_I32 0))>;
2711638Srgrimesdef : Pat<(i32 (zextloadi8 (WebAssemblywrapper texternalsym:$off))),
2721638Srgrimes          (LOAD8_U_I32 texternalsym:$off, (CONST_I32 0))>;
2731638Srgrimesdef : Pat<(i32 (sextloadi16 (WebAssemblywrapper texternalsym:$off))),
2741638Srgrimes          (LOAD16_S_I32 texternalsym:$off, (CONST_I32 0))>;
27558494Srudef : Pat<(i32 (zextloadi16 (WebAssemblywrapper texternalsym:$off))),
2761638Srgrimes          (LOAD16_U_I32 texternalsym:$off, (CONST_I32 0))>;
2771638Srgrimesdef : Pat<(i64 (sextloadi8 (WebAssemblywrapper texternalsym:$off))),
2781638Srgrimes          (LOAD8_S_I64 texternalsym:$off, (CONST_I32 0))>;
2791638Srgrimesdef : Pat<(i64 (zextloadi8 (WebAssemblywrapper texternalsym:$off))),
2801638Srgrimes          (LOAD8_U_I64 texternalsym:$off, (CONST_I32 0))>;
2811638Srgrimesdef : Pat<(i64 (sextloadi16 (WebAssemblywrapper texternalsym:$off))),
2821638Srgrimes          (LOAD16_S_I64 texternalsym:$off, (CONST_I32 0))>;
2831638Srgrimesdef : Pat<(i64 (zextloadi16 (WebAssemblywrapper texternalsym:$off))),
2841638Srgrimes          (LOAD16_U_I64 texternalsym:$off, (CONST_I32 0))>;
2851638Srgrimesdef : Pat<(i64 (sextloadi32 (WebAssemblywrapper texternalsym:$off))),
2861638Srgrimes          (LOAD32_S_I64 texternalsym:$off, (CONST_I32 0))>;
2871638Srgrimesdef : Pat<(i64 (zextloadi32 (WebAssemblywrapper texternalsym:$off))),
2881638Srgrimes          (LOAD32_U_I64 texternalsym:$off, (CONST_I32 0))>;
2891638Srgrimes
2901638Srgrimes// Resolve "don't care" extending loads to zero-extending loads. This is
2911638Srgrimes// somewhat arbitrary, but zero-extending is conceptually simpler.
2921638Srgrimes
2931638Srgrimes// Select "don't care" extending loads with no constant offset.
2941638Srgrimesdef : Pat<(i32 (extloadi8 I32:$addr)),  (LOAD8_U_I32 0, $addr)>;
2951638Srgrimesdef : Pat<(i32 (extloadi16 I32:$addr)), (LOAD16_U_I32 0, $addr)>;
2961638Srgrimesdef : Pat<(i64 (extloadi8 I32:$addr)),  (LOAD8_U_I64 0, $addr)>;
2971638Srgrimesdef : Pat<(i64 (extloadi16 I32:$addr)), (LOAD16_U_I64 0, $addr)>;
2981638Srgrimesdef : Pat<(i64 (extloadi32 I32:$addr)), (LOAD32_U_I64 0, $addr)>;
2991638Srgrimes
3001638Srgrimes// Select "don't care" extending loads with a constant offset.
3011638Srgrimesdef : Pat<(i32 (extloadi8 (regPlusImm I32:$addr, imm:$off))),
3021638Srgrimes          (LOAD8_U_I32 imm:$off, $addr)>;
3031638Srgrimesdef : Pat<(i32 (extloadi16 (regPlusImm I32:$addr, imm:$off))),
3041638Srgrimes          (LOAD16_U_I32 imm:$off, $addr)>;
3051638Srgrimesdef : Pat<(i64 (extloadi8 (regPlusImm I32:$addr, imm:$off))),
3061638Srgrimes          (LOAD8_U_I64 imm:$off, $addr)>;
3071638Srgrimesdef : Pat<(i64 (extloadi16 (regPlusImm I32:$addr, imm:$off))),
3081638Srgrimes          (LOAD16_U_I64 imm:$off, $addr)>;
3091638Srgrimesdef : Pat<(i64 (extloadi32 (regPlusImm I32:$addr, imm:$off))),
3101638Srgrimes          (LOAD32_U_I64 imm:$off, $addr)>;
3111638Srgrimesdef : Pat<(i32 (extloadi8 (regPlusGA I32:$addr,
3121638Srgrimes                                     (WebAssemblywrapper tglobaladdr:$off)))),
3131638Srgrimes          (LOAD8_U_I32 tglobaladdr:$off, $addr)>;
3141638Srgrimesdef : Pat<(i32 (extloadi16 (regPlusGA I32:$addr,
3151638Srgrimes                                      (WebAssemblywrapper tglobaladdr:$off)))),
31674942Sru          (LOAD16_U_I32 tglobaladdr:$off, $addr)>;
3171638Srgrimesdef : Pat<(i64 (extloadi8 (regPlusGA I32:$addr,
3181638Srgrimes                                     (WebAssemblywrapper tglobaladdr:$off)))),
3191638Srgrimes          (LOAD8_U_I64 tglobaladdr:$off, $addr)>;
3201638Srgrimesdef : Pat<(i64 (extloadi16 (regPlusGA I32:$addr,
3211638Srgrimes                                      (WebAssemblywrapper tglobaladdr:$off)))),
3221638Srgrimes          (LOAD16_U_I64 tglobaladdr:$off, $addr)>;
32374942Srudef : Pat<(i64 (extloadi32 (regPlusGA I32:$addr,
32474942Sru                                      (WebAssemblywrapper tglobaladdr:$off)))),
3251638Srgrimes          (LOAD32_U_I64 tglobaladdr:$off, $addr)>;
3261638Srgrimesdef : Pat<(i32 (extloadi8 (add I32:$addr,
3271638Srgrimes                               (WebAssemblywrapper texternalsym:$off)))),
3281638Srgrimes          (LOAD8_U_I32 texternalsym:$off, $addr)>;
3291638Srgrimesdef : Pat<(i32 (extloadi16 (add I32:$addr,
330                                (WebAssemblywrapper texternalsym:$off)))),
331          (LOAD16_U_I32 texternalsym:$off, $addr)>;
332def : Pat<(i64 (extloadi8 (add I32:$addr,
333                               (WebAssemblywrapper texternalsym:$off)))),
334          (LOAD8_U_I64 texternalsym:$off, $addr)>;
335def : Pat<(i64 (extloadi16 (add I32:$addr,
336                                (WebAssemblywrapper texternalsym:$off)))),
337          (LOAD16_U_I64 texternalsym:$off, $addr)>;
338def : Pat<(i64 (extloadi32 (add I32:$addr,
339                                (WebAssemblywrapper texternalsym:$off)))),
340          (LOAD32_U_I64 texternalsym:$off, $addr)>;
341
342// Select "don't care" extending loads with just a constant offset.
343def : Pat<(i32 (extloadi8 imm:$off)), (LOAD8_U_I32 imm:$off, (CONST_I32 0))>;
344def : Pat<(i32 (extloadi16 imm:$off)), (LOAD16_U_I32 imm:$off, (CONST_I32 0))>;
345def : Pat<(i64 (extloadi8 imm:$off)), (LOAD8_U_I64 imm:$off, (CONST_I32 0))>;
346def : Pat<(i64 (extloadi16 imm:$off)), (LOAD16_U_I64 imm:$off, (CONST_I32 0))>;
347def : Pat<(i64 (extloadi32 imm:$off)), (LOAD32_U_I64 imm:$off, (CONST_I32 0))>;
348def : Pat<(i32 (extloadi8 (WebAssemblywrapper tglobaladdr:$off))),
349          (LOAD8_U_I32 tglobaladdr:$off, (CONST_I32 0))>;
350def : Pat<(i32 (extloadi16 (WebAssemblywrapper tglobaladdr:$off))),
351          (LOAD16_U_I32 tglobaladdr:$off, (CONST_I32 0))>;
352def : Pat<(i64 (extloadi8 (WebAssemblywrapper tglobaladdr:$off))),
353          (LOAD8_U_I64 tglobaladdr:$off, (CONST_I32 0))>;
354def : Pat<(i64 (extloadi16 (WebAssemblywrapper tglobaladdr:$off))),
355          (LOAD16_U_I64 tglobaladdr:$off, (CONST_I32 0))>;
356def : Pat<(i64 (extloadi32 (WebAssemblywrapper tglobaladdr:$off))),
357          (LOAD32_U_I64 tglobaladdr:$off, (CONST_I32 0))>;
358def : Pat<(i32 (extloadi8 (WebAssemblywrapper texternalsym:$off))),
359          (LOAD8_U_I32 texternalsym:$off, (CONST_I32 0))>;
360def : Pat<(i32 (extloadi16 (WebAssemblywrapper texternalsym:$off))),
361          (LOAD16_U_I32 texternalsym:$off, (CONST_I32 0))>;
362def : Pat<(i64 (extloadi8 (WebAssemblywrapper texternalsym:$off))),
363          (LOAD8_U_I64 texternalsym:$off, (CONST_I32 0))>;
364def : Pat<(i64 (extloadi16 (WebAssemblywrapper texternalsym:$off))),
365          (LOAD16_U_I64 texternalsym:$off, (CONST_I32 0))>;
366def : Pat<(i64 (extloadi32 (WebAssemblywrapper texternalsym:$off))),
367          (LOAD32_U_I64 tglobaladdr:$off, (CONST_I32 0))>;
368
369let Defs = [ARGUMENTS] in {
370
371// Basic store.
372// Note that we split the patterns out of the instruction definitions because
373// WebAssembly's stores return their operand value, and tablegen doesn't like
374// instruction definition patterns that don't reference all of the output
375// operands.
376// Note: WebAssembly inverts SelectionDAG's usual operand order.
377def STORE_I32  : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr, I32:$val), [],
378                   "i32.store\t$dst, ${off}(${addr}), $val">;
379def STORE_I64  : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr, I64:$val), [],
380                   "i64.store\t$dst, ${off}(${addr}), $val">;
381def STORE_F32  : I<(outs F32:$dst), (ins i32imm:$off, I32:$addr, F32:$val), [],
382                   "f32.store\t$dst, ${off}(${addr}), $val">;
383def STORE_F64  : I<(outs F64:$dst), (ins i32imm:$off, I32:$addr, F64:$val), [],
384                   "f64.store\t$dst, ${off}(${addr}), $val">;
385
386} // Defs = [ARGUMENTS]
387
388// Select stores with no constant offset.
389def : Pat<(store I32:$val, I32:$addr), (STORE_I32 0, I32:$addr, I32:$val)>;
390def : Pat<(store I64:$val, I32:$addr), (STORE_I64 0, I32:$addr, I64:$val)>;
391def : Pat<(store F32:$val, I32:$addr), (STORE_F32 0, I32:$addr, F32:$val)>;
392def : Pat<(store F64:$val, I32:$addr), (STORE_F64 0, I32:$addr, F64:$val)>;
393
394// Select stores with a constant offset.
395def : Pat<(store I32:$val, (regPlusImm I32:$addr, imm:$off)),
396          (STORE_I32 imm:$off, I32:$addr, I32:$val)>;
397def : Pat<(store I64:$val, (regPlusImm I32:$addr, imm:$off)),
398          (STORE_I64 imm:$off, I32:$addr, I64:$val)>;
399def : Pat<(store F32:$val, (regPlusImm I32:$addr, imm:$off)),
400          (STORE_F32 imm:$off, I32:$addr, F32:$val)>;
401def : Pat<(store F64:$val, (regPlusImm I32:$addr, imm:$off)),
402          (STORE_F64 imm:$off, I32:$addr, F64:$val)>;
403def : Pat<(store I32:$val, (regPlusGA I32:$addr,
404                                      (WebAssemblywrapper tglobaladdr:$off))),
405          (STORE_I32 tglobaladdr:$off, I32:$addr, I32:$val)>;
406def : Pat<(store I64:$val, (regPlusGA I32:$addr,
407                                      (WebAssemblywrapper tglobaladdr:$off))),
408          (STORE_I64 tglobaladdr:$off, I32:$addr, I64:$val)>;
409def : Pat<(store F32:$val, (regPlusGA I32:$addr,
410                                      (WebAssemblywrapper tglobaladdr:$off))),
411          (STORE_F32 tglobaladdr:$off, I32:$addr, F32:$val)>;
412def : Pat<(store F64:$val, (regPlusGA I32:$addr,
413                                      (WebAssemblywrapper tglobaladdr:$off))),
414          (STORE_F64 tglobaladdr:$off, I32:$addr, F64:$val)>;
415def : Pat<(store I32:$val, (add I32:$addr,
416                                (WebAssemblywrapper texternalsym:$off))),
417          (STORE_I32 texternalsym:$off, I32:$addr, I32:$val)>;
418def : Pat<(store I64:$val, (add I32:$addr,
419                                (WebAssemblywrapper texternalsym:$off))),
420          (STORE_I64 texternalsym:$off, I32:$addr, I64:$val)>;
421def : Pat<(store F32:$val, (add I32:$addr,
422                                (WebAssemblywrapper texternalsym:$off))),
423          (STORE_F32 texternalsym:$off, I32:$addr, F32:$val)>;
424def : Pat<(store F64:$val, (add I32:$addr,
425                                (WebAssemblywrapper texternalsym:$off))),
426          (STORE_F64 texternalsym:$off, I32:$addr, F64:$val)>;
427
428// Select stores with just a constant offset.
429def : Pat<(store I32:$val, imm:$off),
430          (STORE_I32 imm:$off, (CONST_I32 0), I32:$val)>;
431def : Pat<(store I64:$val, imm:$off),
432          (STORE_I64 imm:$off, (CONST_I32 0), I64:$val)>;
433def : Pat<(store F32:$val, imm:$off),
434          (STORE_F32 imm:$off, (CONST_I32 0), F32:$val)>;
435def : Pat<(store F64:$val, imm:$off),
436          (STORE_F64 imm:$off, (CONST_I32 0), F64:$val)>;
437def : Pat<(store I32:$val, (WebAssemblywrapper tglobaladdr:$off)),
438          (STORE_I32 tglobaladdr:$off, (CONST_I32 0), I32:$val)>;
439def : Pat<(store I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
440          (STORE_I64 tglobaladdr:$off, (CONST_I32 0), I64:$val)>;
441def : Pat<(store F32:$val, (WebAssemblywrapper tglobaladdr:$off)),
442          (STORE_F32 tglobaladdr:$off, (CONST_I32 0), F32:$val)>;
443def : Pat<(store F64:$val, (WebAssemblywrapper tglobaladdr:$off)),
444          (STORE_F64 tglobaladdr:$off, (CONST_I32 0), F64:$val)>;
445def : Pat<(store I32:$val, (WebAssemblywrapper texternalsym:$off)),
446          (STORE_I32 texternalsym:$off, (CONST_I32 0), I32:$val)>;
447def : Pat<(store I64:$val, (WebAssemblywrapper texternalsym:$off)),
448          (STORE_I64 texternalsym:$off, (CONST_I32 0), I64:$val)>;
449def : Pat<(store F32:$val, (WebAssemblywrapper texternalsym:$off)),
450          (STORE_F32 texternalsym:$off, (CONST_I32 0), F32:$val)>;
451def : Pat<(store F64:$val, (WebAssemblywrapper texternalsym:$off)),
452          (STORE_F64 texternalsym:$off, (CONST_I32 0), F64:$val)>;
453
454let Defs = [ARGUMENTS] in {
455
456// Truncating store.
457def STORE8_I32  : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr, I32:$val), [],
458                    "i32.store8\t$dst, ${off}(${addr}), $val">;
459def STORE16_I32 : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr, I32:$val), [],
460                    "i32.store16\t$dst, ${off}(${addr}), $val">;
461def STORE8_I64  : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr, I64:$val), [],
462                    "i64.store8\t$dst, ${off}(${addr}), $val">;
463def STORE16_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr, I64:$val), [],
464                    "i64.store16\t$dst, ${off}(${addr}), $val">;
465def STORE32_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr, I64:$val), [],
466                    "i64.store32\t$dst, ${off}(${addr}), $val">;
467
468} // Defs = [ARGUMENTS]
469
470// Select truncating stores with no constant offset.
471def : Pat<(truncstorei8 I32:$val, I32:$addr),
472          (STORE8_I32 0, I32:$addr, I32:$val)>;
473def : Pat<(truncstorei16 I32:$val, I32:$addr),
474          (STORE16_I32 0, I32:$addr, I32:$val)>;
475def : Pat<(truncstorei8 I64:$val, I32:$addr),
476          (STORE8_I64 0, I32:$addr, I64:$val)>;
477def : Pat<(truncstorei16 I64:$val, I32:$addr),
478          (STORE16_I64 0, I32:$addr, I64:$val)>;
479def : Pat<(truncstorei32 I64:$val, I32:$addr),
480          (STORE32_I64 0, I32:$addr, I64:$val)>;
481
482// Select truncating stores with a constant offset.
483def : Pat<(truncstorei8 I32:$val, (regPlusImm I32:$addr, imm:$off)),
484          (STORE8_I32 imm:$off, I32:$addr, I32:$val)>;
485def : Pat<(truncstorei16 I32:$val, (regPlusImm I32:$addr, imm:$off)),
486          (STORE16_I32 imm:$off, I32:$addr, I32:$val)>;
487def : Pat<(truncstorei8 I64:$val, (regPlusImm I32:$addr, imm:$off)),
488          (STORE8_I64 imm:$off, I32:$addr, I64:$val)>;
489def : Pat<(truncstorei16 I64:$val, (regPlusImm I32:$addr, imm:$off)),
490          (STORE16_I64 imm:$off, I32:$addr, I64:$val)>;
491def : Pat<(truncstorei32 I64:$val, (regPlusImm I32:$addr, imm:$off)),
492          (STORE32_I64 imm:$off, I32:$addr, I64:$val)>;
493def : Pat<(truncstorei8 I32:$val,
494                        (regPlusGA I32:$addr,
495                                   (WebAssemblywrapper tglobaladdr:$off))),
496          (STORE8_I32 tglobaladdr:$off, I32:$addr, I32:$val)>;
497def : Pat<(truncstorei16 I32:$val,
498                         (regPlusGA I32:$addr,
499                                    (WebAssemblywrapper tglobaladdr:$off))),
500          (STORE16_I32 tglobaladdr:$off, I32:$addr, I32:$val)>;
501def : Pat<(truncstorei8 I64:$val,
502                        (regPlusGA I32:$addr,
503                                   (WebAssemblywrapper tglobaladdr:$off))),
504          (STORE8_I64 tglobaladdr:$off, I32:$addr, I64:$val)>;
505def : Pat<(truncstorei16 I64:$val,
506                         (regPlusGA I32:$addr,
507                                    (WebAssemblywrapper tglobaladdr:$off))),
508          (STORE16_I64 tglobaladdr:$off, I32:$addr, I64:$val)>;
509def : Pat<(truncstorei32 I64:$val,
510                         (regPlusGA I32:$addr,
511                                    (WebAssemblywrapper tglobaladdr:$off))),
512          (STORE32_I64 tglobaladdr:$off, I32:$addr, I64:$val)>;
513def : Pat<(truncstorei8 I32:$val, (add I32:$addr,
514                                       (WebAssemblywrapper texternalsym:$off))),
515          (STORE8_I32 texternalsym:$off, I32:$addr, I32:$val)>;
516def : Pat<(truncstorei16 I32:$val,
517                         (add I32:$addr,
518                              (WebAssemblywrapper texternalsym:$off))),
519          (STORE16_I32 texternalsym:$off, I32:$addr, I32:$val)>;
520def : Pat<(truncstorei8 I64:$val,
521                        (add I32:$addr,
522                             (WebAssemblywrapper texternalsym:$off))),
523          (STORE8_I64 texternalsym:$off, I32:$addr, I64:$val)>;
524def : Pat<(truncstorei16 I64:$val,
525                         (add I32:$addr,
526                              (WebAssemblywrapper texternalsym:$off))),
527          (STORE16_I64 texternalsym:$off, I32:$addr, I64:$val)>;
528def : Pat<(truncstorei32 I64:$val,
529                         (add I32:$addr,
530                              (WebAssemblywrapper texternalsym:$off))),
531          (STORE32_I64 texternalsym:$off, I32:$addr, I64:$val)>;
532
533// Select truncating stores with just a constant offset.
534def : Pat<(truncstorei8 I32:$val, imm:$off),
535          (STORE8_I32 imm:$off, (CONST_I32 0), I32:$val)>;
536def : Pat<(truncstorei16 I32:$val, imm:$off),
537          (STORE16_I32 imm:$off, (CONST_I32 0), I32:$val)>;
538def : Pat<(truncstorei8 I64:$val, imm:$off),
539          (STORE8_I64 imm:$off, (CONST_I32 0), I64:$val)>;
540def : Pat<(truncstorei16 I64:$val, imm:$off),
541          (STORE16_I64 imm:$off, (CONST_I32 0), I64:$val)>;
542def : Pat<(truncstorei32 I64:$val, imm:$off),
543          (STORE32_I64 imm:$off, (CONST_I32 0), I64:$val)>;
544def : Pat<(truncstorei8 I32:$val, (WebAssemblywrapper tglobaladdr:$off)),
545          (STORE8_I32 tglobaladdr:$off, (CONST_I32 0), I32:$val)>;
546def : Pat<(truncstorei16 I32:$val, (WebAssemblywrapper tglobaladdr:$off)),
547          (STORE16_I32 tglobaladdr:$off, (CONST_I32 0), I32:$val)>;
548def : Pat<(truncstorei8 I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
549          (STORE8_I64 tglobaladdr:$off, (CONST_I32 0), I64:$val)>;
550def : Pat<(truncstorei16 I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
551          (STORE16_I64 tglobaladdr:$off, (CONST_I32 0), I64:$val)>;
552def : Pat<(truncstorei32 I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
553          (STORE32_I64 tglobaladdr:$off, (CONST_I32 0), I64:$val)>;
554def : Pat<(truncstorei8 I32:$val, (WebAssemblywrapper texternalsym:$off)),
555          (STORE8_I32 texternalsym:$off, (CONST_I32 0), I32:$val)>;
556def : Pat<(truncstorei16 I32:$val, (WebAssemblywrapper texternalsym:$off)),
557          (STORE16_I32 texternalsym:$off, (CONST_I32 0), I32:$val)>;
558def : Pat<(truncstorei8 I64:$val, (WebAssemblywrapper texternalsym:$off)),
559          (STORE8_I64 texternalsym:$off, (CONST_I32 0), I64:$val)>;
560def : Pat<(truncstorei16 I64:$val, (WebAssemblywrapper texternalsym:$off)),
561          (STORE16_I64 texternalsym:$off, (CONST_I32 0), I64:$val)>;
562def : Pat<(truncstorei32 I64:$val, (WebAssemblywrapper texternalsym:$off)),
563          (STORE32_I64 texternalsym:$off, (CONST_I32 0), I64:$val)>;
564
565let Defs = [ARGUMENTS] in {
566
567// Memory size.
568def MEMORY_SIZE_I32 : I<(outs I32:$dst), (ins),
569                        [(set I32:$dst, (int_wasm_memory_size))],
570                        "memory_size\t$dst">,
571                      Requires<[HasAddr32]>;
572def MEMORY_SIZE_I64 : I<(outs I64:$dst), (ins),
573                        [(set I64:$dst, (int_wasm_memory_size))],
574                        "memory_size\t$dst">,
575                      Requires<[HasAddr64]>;
576
577// Grow memory.
578def GROW_MEMORY_I32 : I<(outs), (ins I32:$delta),
579                        [(int_wasm_grow_memory I32:$delta)],
580                        "grow_memory\t$delta">,
581                      Requires<[HasAddr32]>;
582def GROW_MEMORY_I64 : I<(outs), (ins I64:$delta),
583                        [(int_wasm_grow_memory I64:$delta)],
584                        "grow_memory\t$delta">,
585                      Requires<[HasAddr64]>;
586
587} // Defs = [ARGUMENTS]
588