10b57cec5SDimitry Andric //- WebAssemblyISelDAGToDAG.cpp - A dag to dag inst selector for WebAssembly -// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// This file defines an instruction selector for the WebAssembly target. 110b57cec5SDimitry Andric /// 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 150b57cec5SDimitry Andric #include "WebAssembly.h" 160b57cec5SDimitry Andric #include "WebAssemblyTargetMachine.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAGISel.h" 180b57cec5SDimitry Andric #include "llvm/IR/DiagnosticInfo.h" 190b57cec5SDimitry Andric #include "llvm/IR/Function.h" // To access function attributes. 20480093f4SDimitry Andric #include "llvm/IR/IntrinsicsWebAssembly.h" 210b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 220b57cec5SDimitry Andric #include "llvm/Support/KnownBits.h" 230b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 240b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 250b57cec5SDimitry Andric using namespace llvm; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-isel" 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 300b57cec5SDimitry Andric /// WebAssembly-specific code to select WebAssembly machine instructions for 310b57cec5SDimitry Andric /// SelectionDAG operations. 320b57cec5SDimitry Andric /// 330b57cec5SDimitry Andric namespace { 340b57cec5SDimitry Andric class WebAssemblyDAGToDAGISel final : public SelectionDAGISel { 350b57cec5SDimitry Andric /// Keep a pointer to the WebAssemblySubtarget around so that we can make the 360b57cec5SDimitry Andric /// right decision when generating code for different targets. 370b57cec5SDimitry Andric const WebAssemblySubtarget *Subtarget; 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric public: 400b57cec5SDimitry Andric WebAssemblyDAGToDAGISel(WebAssemblyTargetMachine &TM, 410b57cec5SDimitry Andric CodeGenOpt::Level OptLevel) 42480093f4SDimitry Andric : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) { 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric StringRef getPassName() const override { 460b57cec5SDimitry Andric return "WebAssembly Instruction Selection"; 470b57cec5SDimitry Andric } 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 500b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n" 510b57cec5SDimitry Andric "********** Function: " 520b57cec5SDimitry Andric << MF.getName() << '\n'); 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric Subtarget = &MF.getSubtarget<WebAssemblySubtarget>(); 558bcb0991SDimitry Andric 560b57cec5SDimitry Andric return SelectionDAGISel::runOnMachineFunction(MF); 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric void Select(SDNode *Node) override; 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, 620b57cec5SDimitry Andric std::vector<SDValue> &OutOps) override; 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric // Include the pieces autogenerated from the target description. 650b57cec5SDimitry Andric #include "WebAssemblyGenDAGISel.inc" 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric private: 680b57cec5SDimitry Andric // add select functions here... 690b57cec5SDimitry Andric }; 700b57cec5SDimitry Andric } // end anonymous namespace 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric void WebAssemblyDAGToDAGISel::Select(SDNode *Node) { 730b57cec5SDimitry Andric // If we have a custom node, we already have selected! 740b57cec5SDimitry Andric if (Node->isMachineOpcode()) { 750b57cec5SDimitry Andric LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); 760b57cec5SDimitry Andric Node->setNodeId(-1); 770b57cec5SDimitry Andric return; 780b57cec5SDimitry Andric } 790b57cec5SDimitry Andric 80*5ffd83dbSDimitry Andric MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout()); 81*5ffd83dbSDimitry Andric auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64 82*5ffd83dbSDimitry Andric : WebAssembly::GLOBAL_GET_I32; 83*5ffd83dbSDimitry Andric auto ConstIns = 84*5ffd83dbSDimitry Andric PtrVT == MVT::i64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32; 85*5ffd83dbSDimitry Andric auto AddIns = PtrVT == MVT::i64 ? WebAssembly::ADD_I64 : WebAssembly::ADD_I32; 86*5ffd83dbSDimitry Andric 870b57cec5SDimitry Andric // Few custom selection stuff. 880b57cec5SDimitry Andric SDLoc DL(Node); 890b57cec5SDimitry Andric MachineFunction &MF = CurDAG->getMachineFunction(); 900b57cec5SDimitry Andric switch (Node->getOpcode()) { 910b57cec5SDimitry Andric case ISD::ATOMIC_FENCE: { 920b57cec5SDimitry Andric if (!MF.getSubtarget<WebAssemblySubtarget>().hasAtomics()) 930b57cec5SDimitry Andric break; 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric uint64_t SyncScopeID = 960b57cec5SDimitry Andric cast<ConstantSDNode>(Node->getOperand(2).getNode())->getZExtValue(); 978bcb0991SDimitry Andric MachineSDNode *Fence = nullptr; 980b57cec5SDimitry Andric switch (SyncScopeID) { 998bcb0991SDimitry Andric case SyncScope::SingleThread: 1000b57cec5SDimitry Andric // We lower a single-thread fence to a pseudo compiler barrier instruction 1010b57cec5SDimitry Andric // preventing instruction reordering. This will not be emitted in final 1020b57cec5SDimitry Andric // binary. 1038bcb0991SDimitry Andric Fence = CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE, 1040b57cec5SDimitry Andric DL, // debug loc 1050b57cec5SDimitry Andric MVT::Other, // outchain type 1060b57cec5SDimitry Andric Node->getOperand(0) // inchain 1070b57cec5SDimitry Andric ); 1088bcb0991SDimitry Andric break; 1098bcb0991SDimitry Andric case SyncScope::System: 1108bcb0991SDimitry Andric // Currently wasm only supports sequentially consistent atomics, so we 1118bcb0991SDimitry Andric // always set the order to 0 (sequentially consistent). 1128bcb0991SDimitry Andric Fence = CurDAG->getMachineNode( 1138bcb0991SDimitry Andric WebAssembly::ATOMIC_FENCE, 1140b57cec5SDimitry Andric DL, // debug loc 1150b57cec5SDimitry Andric MVT::Other, // outchain type 1168bcb0991SDimitry Andric CurDAG->getTargetConstant(0, DL, MVT::i32), // order 1170b57cec5SDimitry Andric Node->getOperand(0) // inchain 1188bcb0991SDimitry Andric ); 1198bcb0991SDimitry Andric break; 1200b57cec5SDimitry Andric default: 1210b57cec5SDimitry Andric llvm_unreachable("Unknown scope!"); 1220b57cec5SDimitry Andric } 1238bcb0991SDimitry Andric 1248bcb0991SDimitry Andric ReplaceNode(Node, Fence); 1258bcb0991SDimitry Andric CurDAG->RemoveDeadNode(Node); 1268bcb0991SDimitry Andric return; 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric case ISD::GlobalTLSAddress: { 1300b57cec5SDimitry Andric const auto *GA = cast<GlobalAddressSDNode>(Node); 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric if (!MF.getSubtarget<WebAssemblySubtarget>().hasBulkMemory()) 1330b57cec5SDimitry Andric report_fatal_error("cannot use thread-local storage without bulk memory", 1340b57cec5SDimitry Andric false); 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric // Currently Emscripten does not support dynamic linking with threads. 1370b57cec5SDimitry Andric // Therefore, if we have thread-local storage, only the local-exec model 1380b57cec5SDimitry Andric // is possible. 1390b57cec5SDimitry Andric // TODO: remove this and implement proper TLS models once Emscripten 1400b57cec5SDimitry Andric // supports dynamic linking with threads. 1410b57cec5SDimitry Andric if (GA->getGlobal()->getThreadLocalMode() != 1420b57cec5SDimitry Andric GlobalValue::LocalExecTLSModel && 1430b57cec5SDimitry Andric !Subtarget->getTargetTriple().isOSEmscripten()) { 1440b57cec5SDimitry Andric report_fatal_error("only -ftls-model=local-exec is supported for now on " 1450b57cec5SDimitry Andric "non-Emscripten OSes: variable " + 1460b57cec5SDimitry Andric GA->getGlobal()->getName(), 1470b57cec5SDimitry Andric false); 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric SDValue TLSBaseSym = CurDAG->getTargetExternalSymbol("__tls_base", PtrVT); 1510b57cec5SDimitry Andric SDValue TLSOffsetSym = CurDAG->getTargetGlobalAddress( 1520b57cec5SDimitry Andric GA->getGlobal(), DL, PtrVT, GA->getOffset(), 0); 1530b57cec5SDimitry Andric 154*5ffd83dbSDimitry Andric MachineSDNode *TLSBase = 155*5ffd83dbSDimitry Andric CurDAG->getMachineNode(GlobalGetIns, DL, PtrVT, TLSBaseSym); 156*5ffd83dbSDimitry Andric MachineSDNode *TLSOffset = 157*5ffd83dbSDimitry Andric CurDAG->getMachineNode(ConstIns, DL, PtrVT, TLSOffsetSym); 158*5ffd83dbSDimitry Andric MachineSDNode *TLSAddress = CurDAG->getMachineNode( 159*5ffd83dbSDimitry Andric AddIns, DL, PtrVT, SDValue(TLSBase, 0), SDValue(TLSOffset, 0)); 1600b57cec5SDimitry Andric ReplaceNode(Node, TLSAddress); 1610b57cec5SDimitry Andric return; 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric case ISD::INTRINSIC_WO_CHAIN: { 1650b57cec5SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(0))->getZExtValue(); 1660b57cec5SDimitry Andric switch (IntNo) { 1670b57cec5SDimitry Andric case Intrinsic::wasm_tls_size: { 1680b57cec5SDimitry Andric MachineSDNode *TLSSize = CurDAG->getMachineNode( 169*5ffd83dbSDimitry Andric GlobalGetIns, DL, PtrVT, 170*5ffd83dbSDimitry Andric CurDAG->getTargetExternalSymbol("__tls_size", PtrVT)); 1710b57cec5SDimitry Andric ReplaceNode(Node, TLSSize); 1720b57cec5SDimitry Andric return; 1730b57cec5SDimitry Andric } 1748bcb0991SDimitry Andric case Intrinsic::wasm_tls_align: { 1758bcb0991SDimitry Andric MachineSDNode *TLSAlign = CurDAG->getMachineNode( 176*5ffd83dbSDimitry Andric GlobalGetIns, DL, PtrVT, 177*5ffd83dbSDimitry Andric CurDAG->getTargetExternalSymbol("__tls_align", PtrVT)); 1788bcb0991SDimitry Andric ReplaceNode(Node, TLSAlign); 1798bcb0991SDimitry Andric return; 1808bcb0991SDimitry Andric } 1818bcb0991SDimitry Andric } 1828bcb0991SDimitry Andric break; 1838bcb0991SDimitry Andric } 1848bcb0991SDimitry Andric case ISD::INTRINSIC_W_CHAIN: { 1858bcb0991SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 1868bcb0991SDimitry Andric switch (IntNo) { 1878bcb0991SDimitry Andric case Intrinsic::wasm_tls_base: { 1888bcb0991SDimitry Andric MachineSDNode *TLSBase = CurDAG->getMachineNode( 189*5ffd83dbSDimitry Andric GlobalGetIns, DL, PtrVT, MVT::Other, 1908bcb0991SDimitry Andric CurDAG->getTargetExternalSymbol("__tls_base", PtrVT), 1918bcb0991SDimitry Andric Node->getOperand(0)); 1928bcb0991SDimitry Andric ReplaceNode(Node, TLSBase); 1938bcb0991SDimitry Andric return; 1948bcb0991SDimitry Andric } 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric break; 1970b57cec5SDimitry Andric } 198*5ffd83dbSDimitry Andric case WebAssemblyISD::CALL: 199*5ffd83dbSDimitry Andric case WebAssemblyISD::RET_CALL: { 200*5ffd83dbSDimitry Andric // CALL has both variable operands and variable results, but ISel only 201*5ffd83dbSDimitry Andric // supports one or the other. Split calls into two nodes glued together, one 202*5ffd83dbSDimitry Andric // for the operands and one for the results. These two nodes will be 203*5ffd83dbSDimitry Andric // recombined in a custom inserter hook into a single MachineInstr. 204*5ffd83dbSDimitry Andric SmallVector<SDValue, 16> Ops; 205*5ffd83dbSDimitry Andric for (size_t i = 1; i < Node->getNumOperands(); ++i) { 206*5ffd83dbSDimitry Andric SDValue Op = Node->getOperand(i); 207*5ffd83dbSDimitry Andric if (i == 1 && Op->getOpcode() == WebAssemblyISD::Wrapper) 208*5ffd83dbSDimitry Andric Op = Op->getOperand(0); 209*5ffd83dbSDimitry Andric Ops.push_back(Op); 210*5ffd83dbSDimitry Andric } 211*5ffd83dbSDimitry Andric 212*5ffd83dbSDimitry Andric // Add the chain last 213*5ffd83dbSDimitry Andric Ops.push_back(Node->getOperand(0)); 214*5ffd83dbSDimitry Andric MachineSDNode *CallParams = 215*5ffd83dbSDimitry Andric CurDAG->getMachineNode(WebAssembly::CALL_PARAMS, DL, MVT::Glue, Ops); 216*5ffd83dbSDimitry Andric 217*5ffd83dbSDimitry Andric unsigned Results = Node->getOpcode() == WebAssemblyISD::CALL 218*5ffd83dbSDimitry Andric ? WebAssembly::CALL_RESULTS 219*5ffd83dbSDimitry Andric : WebAssembly::RET_CALL_RESULTS; 220*5ffd83dbSDimitry Andric 221*5ffd83dbSDimitry Andric SDValue Link(CallParams, 0); 222*5ffd83dbSDimitry Andric MachineSDNode *CallResults = 223*5ffd83dbSDimitry Andric CurDAG->getMachineNode(Results, DL, Node->getVTList(), Link); 224*5ffd83dbSDimitry Andric ReplaceNode(Node, CallResults); 225*5ffd83dbSDimitry Andric return; 226*5ffd83dbSDimitry Andric } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric default: 2290b57cec5SDimitry Andric break; 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric // Select the default instruction. 2330b57cec5SDimitry Andric SelectCode(Node); 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand( 2370b57cec5SDimitry Andric const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { 2380b57cec5SDimitry Andric switch (ConstraintID) { 2390b57cec5SDimitry Andric case InlineAsm::Constraint_m: 2400b57cec5SDimitry Andric // We just support simple memory operands that just have a single address 2410b57cec5SDimitry Andric // operand and need no special handling. 2420b57cec5SDimitry Andric OutOps.push_back(Op); 2430b57cec5SDimitry Andric return false; 2440b57cec5SDimitry Andric default: 2450b57cec5SDimitry Andric break; 2460b57cec5SDimitry Andric } 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric return true; 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric /// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready 2520b57cec5SDimitry Andric /// for instruction scheduling. 2530b57cec5SDimitry Andric FunctionPass *llvm::createWebAssemblyISelDag(WebAssemblyTargetMachine &TM, 2540b57cec5SDimitry Andric CodeGenOpt::Level OptLevel) { 2550b57cec5SDimitry Andric return new WebAssemblyDAGToDAGISel(TM, OptLevel); 2560b57cec5SDimitry Andric } 257