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. 200b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 210b57cec5SDimitry Andric #include "llvm/Support/KnownBits.h" 220b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 230b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 240b57cec5SDimitry Andric using namespace llvm; 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-isel" 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 290b57cec5SDimitry Andric /// WebAssembly-specific code to select WebAssembly machine instructions for 300b57cec5SDimitry Andric /// SelectionDAG operations. 310b57cec5SDimitry Andric /// 320b57cec5SDimitry Andric namespace { 330b57cec5SDimitry Andric class WebAssemblyDAGToDAGISel final : public SelectionDAGISel { 340b57cec5SDimitry Andric /// Keep a pointer to the WebAssemblySubtarget around so that we can make the 350b57cec5SDimitry Andric /// right decision when generating code for different targets. 360b57cec5SDimitry Andric const WebAssemblySubtarget *Subtarget; 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric bool ForCodeSize; 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric public: 410b57cec5SDimitry Andric WebAssemblyDAGToDAGISel(WebAssemblyTargetMachine &TM, 420b57cec5SDimitry Andric CodeGenOpt::Level OptLevel) 430b57cec5SDimitry Andric : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr), ForCodeSize(false) { 440b57cec5SDimitry Andric } 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric StringRef getPassName() const override { 470b57cec5SDimitry Andric return "WebAssembly Instruction Selection"; 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 510b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n" 520b57cec5SDimitry Andric "********** Function: " 530b57cec5SDimitry Andric << MF.getName() << '\n'); 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric ForCodeSize = MF.getFunction().hasOptSize(); 560b57cec5SDimitry Andric Subtarget = &MF.getSubtarget<WebAssemblySubtarget>(); 57*8bcb0991SDimitry Andric 58*8bcb0991SDimitry Andric // Wasm64 is not fully supported right now (and is not specified) 59*8bcb0991SDimitry Andric if (Subtarget->hasAddr64()) 60*8bcb0991SDimitry Andric report_fatal_error( 61*8bcb0991SDimitry Andric "64-bit WebAssembly (wasm64) is not currently supported"); 62*8bcb0991SDimitry Andric 630b57cec5SDimitry Andric return SelectionDAGISel::runOnMachineFunction(MF); 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric void Select(SDNode *Node) override; 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, 690b57cec5SDimitry Andric std::vector<SDValue> &OutOps) override; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric // Include the pieces autogenerated from the target description. 720b57cec5SDimitry Andric #include "WebAssemblyGenDAGISel.inc" 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric private: 750b57cec5SDimitry Andric // add select functions here... 760b57cec5SDimitry Andric }; 770b57cec5SDimitry Andric } // end anonymous namespace 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric void WebAssemblyDAGToDAGISel::Select(SDNode *Node) { 800b57cec5SDimitry Andric // If we have a custom node, we already have selected! 810b57cec5SDimitry Andric if (Node->isMachineOpcode()) { 820b57cec5SDimitry Andric LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); 830b57cec5SDimitry Andric Node->setNodeId(-1); 840b57cec5SDimitry Andric return; 850b57cec5SDimitry Andric } 860b57cec5SDimitry 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(); 97*8bcb0991SDimitry Andric MachineSDNode *Fence = nullptr; 980b57cec5SDimitry Andric switch (SyncScopeID) { 99*8bcb0991SDimitry 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. 103*8bcb0991SDimitry 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 ); 108*8bcb0991SDimitry Andric break; 109*8bcb0991SDimitry Andric case SyncScope::System: 110*8bcb0991SDimitry Andric // Currently wasm only supports sequentially consistent atomics, so we 111*8bcb0991SDimitry Andric // always set the order to 0 (sequentially consistent). 112*8bcb0991SDimitry Andric Fence = CurDAG->getMachineNode( 113*8bcb0991SDimitry Andric WebAssembly::ATOMIC_FENCE, 1140b57cec5SDimitry Andric DL, // debug loc 1150b57cec5SDimitry Andric MVT::Other, // outchain type 116*8bcb0991SDimitry Andric CurDAG->getTargetConstant(0, DL, MVT::i32), // order 1170b57cec5SDimitry Andric Node->getOperand(0) // inchain 118*8bcb0991SDimitry Andric ); 119*8bcb0991SDimitry Andric break; 1200b57cec5SDimitry Andric default: 1210b57cec5SDimitry Andric llvm_unreachable("Unknown scope!"); 1220b57cec5SDimitry Andric } 123*8bcb0991SDimitry Andric 124*8bcb0991SDimitry Andric ReplaceNode(Node, Fence); 125*8bcb0991SDimitry Andric CurDAG->RemoveDeadNode(Node); 126*8bcb0991SDimitry 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 MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout()); 1510b57cec5SDimitry Andric assert(PtrVT == MVT::i32 && "only wasm32 is supported for now"); 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric SDValue TLSBaseSym = CurDAG->getTargetExternalSymbol("__tls_base", PtrVT); 1540b57cec5SDimitry Andric SDValue TLSOffsetSym = CurDAG->getTargetGlobalAddress( 1550b57cec5SDimitry Andric GA->getGlobal(), DL, PtrVT, GA->getOffset(), 0); 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric MachineSDNode *TLSBase = CurDAG->getMachineNode(WebAssembly::GLOBAL_GET_I32, 1580b57cec5SDimitry Andric DL, MVT::i32, TLSBaseSym); 1590b57cec5SDimitry Andric MachineSDNode *TLSOffset = CurDAG->getMachineNode( 1600b57cec5SDimitry Andric WebAssembly::CONST_I32, DL, MVT::i32, TLSOffsetSym); 1610b57cec5SDimitry Andric MachineSDNode *TLSAddress = 1620b57cec5SDimitry Andric CurDAG->getMachineNode(WebAssembly::ADD_I32, DL, MVT::i32, 1630b57cec5SDimitry Andric SDValue(TLSBase, 0), SDValue(TLSOffset, 0)); 1640b57cec5SDimitry Andric ReplaceNode(Node, TLSAddress); 1650b57cec5SDimitry Andric return; 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric case ISD::INTRINSIC_WO_CHAIN: { 1690b57cec5SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(0))->getZExtValue(); 1700b57cec5SDimitry Andric switch (IntNo) { 1710b57cec5SDimitry Andric case Intrinsic::wasm_tls_size: { 1720b57cec5SDimitry Andric MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout()); 1730b57cec5SDimitry Andric assert(PtrVT == MVT::i32 && "only wasm32 is supported for now"); 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric MachineSDNode *TLSSize = CurDAG->getMachineNode( 1760b57cec5SDimitry Andric WebAssembly::GLOBAL_GET_I32, DL, PtrVT, 1770b57cec5SDimitry Andric CurDAG->getTargetExternalSymbol("__tls_size", MVT::i32)); 1780b57cec5SDimitry Andric ReplaceNode(Node, TLSSize); 1790b57cec5SDimitry Andric return; 1800b57cec5SDimitry Andric } 181*8bcb0991SDimitry Andric case Intrinsic::wasm_tls_align: { 182*8bcb0991SDimitry Andric MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout()); 183*8bcb0991SDimitry Andric assert(PtrVT == MVT::i32 && "only wasm32 is supported for now"); 184*8bcb0991SDimitry Andric 185*8bcb0991SDimitry Andric MachineSDNode *TLSAlign = CurDAG->getMachineNode( 186*8bcb0991SDimitry Andric WebAssembly::GLOBAL_GET_I32, DL, PtrVT, 187*8bcb0991SDimitry Andric CurDAG->getTargetExternalSymbol("__tls_align", MVT::i32)); 188*8bcb0991SDimitry Andric ReplaceNode(Node, TLSAlign); 189*8bcb0991SDimitry Andric return; 190*8bcb0991SDimitry Andric } 191*8bcb0991SDimitry Andric } 192*8bcb0991SDimitry Andric break; 193*8bcb0991SDimitry Andric } 194*8bcb0991SDimitry Andric case ISD::INTRINSIC_W_CHAIN: { 195*8bcb0991SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 196*8bcb0991SDimitry Andric switch (IntNo) { 197*8bcb0991SDimitry Andric case Intrinsic::wasm_tls_base: { 198*8bcb0991SDimitry Andric MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout()); 199*8bcb0991SDimitry Andric assert(PtrVT == MVT::i32 && "only wasm32 is supported for now"); 200*8bcb0991SDimitry Andric 201*8bcb0991SDimitry Andric MachineSDNode *TLSBase = CurDAG->getMachineNode( 202*8bcb0991SDimitry Andric WebAssembly::GLOBAL_GET_I32, DL, MVT::i32, MVT::Other, 203*8bcb0991SDimitry Andric CurDAG->getTargetExternalSymbol("__tls_base", PtrVT), 204*8bcb0991SDimitry Andric Node->getOperand(0)); 205*8bcb0991SDimitry Andric ReplaceNode(Node, TLSBase); 206*8bcb0991SDimitry Andric return; 207*8bcb0991SDimitry Andric } 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric break; 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric default: 2130b57cec5SDimitry Andric break; 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric // Select the default instruction. 2170b57cec5SDimitry Andric SelectCode(Node); 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand( 2210b57cec5SDimitry Andric const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { 2220b57cec5SDimitry Andric switch (ConstraintID) { 2230b57cec5SDimitry Andric case InlineAsm::Constraint_i: 2240b57cec5SDimitry Andric case InlineAsm::Constraint_m: 2250b57cec5SDimitry Andric // We just support simple memory operands that just have a single address 2260b57cec5SDimitry Andric // operand and need no special handling. 2270b57cec5SDimitry Andric OutOps.push_back(Op); 2280b57cec5SDimitry Andric return false; 2290b57cec5SDimitry Andric default: 2300b57cec5SDimitry Andric break; 2310b57cec5SDimitry Andric } 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric return true; 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric /// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready 2370b57cec5SDimitry Andric /// for instruction scheduling. 2380b57cec5SDimitry Andric FunctionPass *llvm::createWebAssemblyISelDag(WebAssemblyTargetMachine &TM, 2390b57cec5SDimitry Andric CodeGenOpt::Level OptLevel) { 2400b57cec5SDimitry Andric return new WebAssemblyDAGToDAGISel(TM, OptLevel); 2410b57cec5SDimitry Andric } 242