|
19 | 19 | #include "WebAssemblyTargetMachine.h"
|
20 | 20 | #include "WebAssemblyUtilities.h"
|
21 | 21 | #include "llvm/CodeGen/CallingConvLower.h"
|
| 22 | +#include "llvm/CodeGen/ISDOpcodes.h" |
22 | 23 | #include "llvm/CodeGen/MachineFrameInfo.h"
|
23 | 24 | #include "llvm/CodeGen/MachineInstrBuilder.h"
|
24 | 25 | #include "llvm/CodeGen/MachineJumpTableInfo.h"
|
@@ -111,6 +112,17 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
|
111 | 112 | }
|
112 | 113 | }
|
113 | 114 |
|
| 115 | + // Likewise, transform extending loads for address space 1 |
| 116 | + for (auto T : {MVT::i32, MVT::i64}) { |
| 117 | + for (auto S : {MVT::i8, MVT::i16, MVT::i32}) { |
| 118 | + if (T != S) { |
| 119 | + setLoadExtAction(ISD::EXTLOAD, T, S, Custom); |
| 120 | + setLoadExtAction(ISD::ZEXTLOAD, T, S, Custom); |
| 121 | + setLoadExtAction(ISD::SEXTLOAD, T, S, Custom); |
| 122 | + } |
| 123 | + } |
| 124 | + } |
| 125 | + |
114 | 126 | setOperationAction(ISD::GlobalAddress, MVTPtr, Custom);
|
115 | 127 | setOperationAction(ISD::GlobalTLSAddress, MVTPtr, Custom);
|
116 | 128 | setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom);
|
@@ -1707,6 +1719,11 @@ static bool IsWebAssemblyGlobal(SDValue Op) {
|
1707 | 1719 | if (const GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op))
|
1708 | 1720 | return WebAssembly::isWasmVarAddressSpace(GA->getAddressSpace());
|
1709 | 1721 |
|
| 1722 | + if (Op->getOpcode() == WebAssemblyISD::Wrapper) |
| 1723 | + if (const GlobalAddressSDNode *GA = |
| 1724 | + dyn_cast<GlobalAddressSDNode>(Op->getOperand(0))) |
| 1725 | + return WebAssembly::isWasmVarAddressSpace(GA->getAddressSpace()); |
| 1726 | + |
1710 | 1727 | return false;
|
1711 | 1728 | }
|
1712 | 1729 |
|
@@ -1764,16 +1781,110 @@ SDValue WebAssemblyTargetLowering::LowerLoad(SDValue Op,
|
1764 | 1781 | LoadSDNode *LN = cast<LoadSDNode>(Op.getNode());
|
1765 | 1782 | const SDValue &Base = LN->getBasePtr();
|
1766 | 1783 | const SDValue &Offset = LN->getOffset();
|
| 1784 | + ISD::LoadExtType ExtType = LN->getExtensionType(); |
| 1785 | + EVT ResultType = LN->getValueType(0); |
1767 | 1786 |
|
1768 | 1787 | if (IsWebAssemblyGlobal(Base)) {
|
1769 | 1788 | if (!Offset->isUndef())
|
1770 | 1789 | report_fatal_error(
|
1771 | 1790 | "unexpected offset when loading from webassembly global", false);
|
1772 | 1791 |
|
1773 |
| - SDVTList Tys = DAG.getVTList(LN->getValueType(0), MVT::Other); |
1774 |
| - SDValue Ops[] = {LN->getChain(), Base}; |
1775 |
| - return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_GET, DL, Tys, Ops, |
1776 |
| - LN->getMemoryVT(), LN->getMemOperand()); |
| 1792 | + EVT GT = MVT::INVALID_SIMPLE_VALUE_TYPE; |
| 1793 | + |
| 1794 | + if (const GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Base)) |
| 1795 | + GT = EVT::getEVT(GA->getGlobal()->getValueType()); |
| 1796 | + if (Base->getOpcode() == WebAssemblyISD::Wrapper) |
| 1797 | + if (const GlobalAddressSDNode *GA = |
| 1798 | + dyn_cast<GlobalAddressSDNode>(Base->getOperand(0))) |
| 1799 | + GT = EVT::getEVT(GA->getGlobal()->getValueType()); |
| 1800 | + |
| 1801 | + if (GT != MVT::i8 && GT != MVT::i16 && GT != MVT::i32 && GT != MVT::i64 && |
| 1802 | + GT != MVT::f32 && GT != MVT::f64) |
| 1803 | + report_fatal_error("encountered unexpected global type for Base when " |
| 1804 | + "loading from webassembly global", |
| 1805 | + false); |
| 1806 | + |
| 1807 | + EVT PromotedGT = (GT == MVT::i8 || GT == MVT::i16) ? MVT::i32 : GT; |
| 1808 | + |
| 1809 | + if (ExtType == ISD::NON_EXTLOAD) { |
| 1810 | + // A normal, non-extending load may try to load more or less than the |
| 1811 | + // underlying global, which is invalid. We lower this to a load of the |
| 1812 | + // global (i32 or i64) then truncate or extend as needed |
| 1813 | + |
| 1814 | + // Modify the MMO to load the full global |
| 1815 | + MachineMemOperand *OldMMO = LN->getMemOperand(); |
| 1816 | + MachineMemOperand *NewMMO = DAG.getMachineFunction().getMachineMemOperand( |
| 1817 | + OldMMO->getPointerInfo(), OldMMO->getFlags(), |
| 1818 | + LLT(PromotedGT.getSimpleVT()), OldMMO->getBaseAlign(), |
| 1819 | + OldMMO->getAAInfo(), OldMMO->getRanges(), OldMMO->getSyncScopeID(), |
| 1820 | + OldMMO->getSuccessOrdering(), OldMMO->getFailureOrdering()); |
| 1821 | + |
| 1822 | + SDVTList Tys = DAG.getVTList(PromotedGT, MVT::Other); |
| 1823 | + SDValue Ops[] = {LN->getChain(), Base}; |
| 1824 | + SDValue GlobalGetNode = DAG.getMemIntrinsicNode( |
| 1825 | + WebAssemblyISD::GLOBAL_GET, DL, Tys, Ops, PromotedGT, NewMMO); |
| 1826 | + |
| 1827 | + if (ResultType.bitsEq(PromotedGT)) { |
| 1828 | + return GlobalGetNode; |
| 1829 | + } |
| 1830 | + |
| 1831 | + SDValue ValRes; |
| 1832 | + if (ResultType.isFloatingPoint()) |
| 1833 | + ValRes = DAG.getFPExtendOrRound(GlobalGetNode, DL, ResultType); |
| 1834 | + else |
| 1835 | + ValRes = DAG.getAnyExtOrTrunc(GlobalGetNode, DL, ResultType); |
| 1836 | + |
| 1837 | + return DAG.getMergeValues({ValRes, LN->getChain()}, DL); |
| 1838 | + } |
| 1839 | + |
| 1840 | + if (ExtType == ISD::ZEXTLOAD || ExtType == ISD::SEXTLOAD) { |
| 1841 | + // Turn the unsupported load into an EXTLOAD followed by an |
| 1842 | + // explicit zero/sign extend inreg. Same as Expand |
| 1843 | + |
| 1844 | + SDValue Result = |
| 1845 | + DAG.getExtLoad(ISD::EXTLOAD, DL, ResultType, LN->getChain(), Base, |
| 1846 | + LN->getMemoryVT(), LN->getMemOperand()); |
| 1847 | + SDValue ValRes; |
| 1848 | + if (ExtType == ISD::SEXTLOAD) |
| 1849 | + ValRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Result.getValueType(), |
| 1850 | + Result, DAG.getValueType(LN->getMemoryVT())); |
| 1851 | + else |
| 1852 | + ValRes = DAG.getZeroExtendInReg(Result, DL, LN->getMemoryVT()); |
| 1853 | + |
| 1854 | + return DAG.getMergeValues({ValRes, LN->getChain()}, DL); |
| 1855 | + } |
| 1856 | + |
| 1857 | + if (ExtType == ISD::EXTLOAD) { |
| 1858 | + // Expand the EXTLOAD into a regular LOAD of the global, and if |
| 1859 | + // needed, a zero-extension |
| 1860 | + |
| 1861 | + EVT OldLoadType = LN->getMemoryVT(); |
| 1862 | + EVT NewLoadType = (OldLoadType == MVT::i8 || OldLoadType == MVT::i16) |
| 1863 | + ? MVT::i32 |
| 1864 | + : OldLoadType; |
| 1865 | + |
| 1866 | + // Modify the MMO to load a whole WASM "register"'s worth |
| 1867 | + MachineMemOperand *OldMMO = LN->getMemOperand(); |
| 1868 | + MachineMemOperand *NewMMO = DAG.getMachineFunction().getMachineMemOperand( |
| 1869 | + OldMMO->getPointerInfo(), OldMMO->getFlags(), |
| 1870 | + LLT(NewLoadType.getSimpleVT()), OldMMO->getBaseAlign(), |
| 1871 | + OldMMO->getAAInfo(), OldMMO->getRanges(), OldMMO->getSyncScopeID(), |
| 1872 | + OldMMO->getSuccessOrdering(), OldMMO->getFailureOrdering()); |
| 1873 | + |
| 1874 | + SDValue Result = |
| 1875 | + DAG.getLoad(NewLoadType, DL, LN->getChain(), Base, NewMMO); |
| 1876 | + |
| 1877 | + if (NewLoadType != ResultType) { |
| 1878 | + SDValue ValRes = DAG.getNode(ISD::ANY_EXTEND, DL, ResultType, Result); |
| 1879 | + return DAG.getMergeValues({ValRes, LN->getChain()}, DL); |
| 1880 | + } |
| 1881 | + |
| 1882 | + return Result; |
| 1883 | + } |
| 1884 | + |
| 1885 | + report_fatal_error( |
| 1886 | + "encountered unexpected ExtType when loading from webassembly global", |
| 1887 | + false); |
1777 | 1888 | }
|
1778 | 1889 |
|
1779 | 1890 | if (std::optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) {
|
|
0 commit comments