1 //- WebAssemblyISelDAGToDAG.cpp - A dag to dag inst selector for WebAssembly -// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file defines an instruction selector for the WebAssembly target. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 15 #include "WebAssembly.h" 16 #include "WebAssemblyTargetMachine.h" 17 #include "llvm/CodeGen/SelectionDAGISel.h" 18 #include "llvm/IR/DiagnosticInfo.h" 19 #include "llvm/IR/Function.h" // To access function attributes. 20 #include "llvm/Support/Debug.h" 21 #include "llvm/Support/KnownBits.h" 22 #include "llvm/Support/MathExtras.h" 23 #include "llvm/Support/raw_ostream.h" 24 using namespace llvm; 25 26 #define DEBUG_TYPE "wasm-isel" 27 28 //===--------------------------------------------------------------------===// 29 /// WebAssembly-specific code to select WebAssembly machine instructions for 30 /// SelectionDAG operations. 31 /// 32 namespace { 33 class WebAssemblyDAGToDAGISel final : public SelectionDAGISel { 34 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the 35 /// right decision when generating code for different targets. 36 const WebAssemblySubtarget *Subtarget; 37 38 public: 39 WebAssemblyDAGToDAGISel(WebAssemblyTargetMachine &TM, 40 CodeGenOpt::Level OptLevel) 41 : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) { 42 } 43 44 StringRef getPassName() const override { 45 return "WebAssembly Instruction Selection"; 46 } 47 48 bool runOnMachineFunction(MachineFunction &MF) override { 49 LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n" 50 "********** Function: " 51 << MF.getName() << '\n'); 52 53 Subtarget = &MF.getSubtarget<WebAssemblySubtarget>(); 54 55 // Wasm64 is not fully supported right now (and is not specified) 56 if (Subtarget->hasAddr64()) 57 report_fatal_error( 58 "64-bit WebAssembly (wasm64) is not currently supported"); 59 60 return SelectionDAGISel::runOnMachineFunction(MF); 61 } 62 63 void Select(SDNode *Node) override; 64 65 bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, 66 std::vector<SDValue> &OutOps) override; 67 68 // Include the pieces autogenerated from the target description. 69 #include "WebAssemblyGenDAGISel.inc" 70 71 private: 72 // add select functions here... 73 }; 74 } // end anonymous namespace 75 76 void WebAssemblyDAGToDAGISel::Select(SDNode *Node) { 77 // If we have a custom node, we already have selected! 78 if (Node->isMachineOpcode()) { 79 LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); 80 Node->setNodeId(-1); 81 return; 82 } 83 84 // Few custom selection stuff. 85 SDLoc DL(Node); 86 MachineFunction &MF = CurDAG->getMachineFunction(); 87 switch (Node->getOpcode()) { 88 case ISD::ATOMIC_FENCE: { 89 if (!MF.getSubtarget<WebAssemblySubtarget>().hasAtomics()) 90 break; 91 92 uint64_t SyncScopeID = 93 cast<ConstantSDNode>(Node->getOperand(2).getNode())->getZExtValue(); 94 MachineSDNode *Fence = nullptr; 95 switch (SyncScopeID) { 96 case SyncScope::SingleThread: 97 // We lower a single-thread fence to a pseudo compiler barrier instruction 98 // preventing instruction reordering. This will not be emitted in final 99 // binary. 100 Fence = CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE, 101 DL, // debug loc 102 MVT::Other, // outchain type 103 Node->getOperand(0) // inchain 104 ); 105 break; 106 case SyncScope::System: 107 // Currently wasm only supports sequentially consistent atomics, so we 108 // always set the order to 0 (sequentially consistent). 109 Fence = CurDAG->getMachineNode( 110 WebAssembly::ATOMIC_FENCE, 111 DL, // debug loc 112 MVT::Other, // outchain type 113 CurDAG->getTargetConstant(0, DL, MVT::i32), // order 114 Node->getOperand(0) // inchain 115 ); 116 break; 117 default: 118 llvm_unreachable("Unknown scope!"); 119 } 120 121 ReplaceNode(Node, Fence); 122 CurDAG->RemoveDeadNode(Node); 123 return; 124 } 125 126 case ISD::GlobalTLSAddress: { 127 const auto *GA = cast<GlobalAddressSDNode>(Node); 128 129 if (!MF.getSubtarget<WebAssemblySubtarget>().hasBulkMemory()) 130 report_fatal_error("cannot use thread-local storage without bulk memory", 131 false); 132 133 // Currently Emscripten does not support dynamic linking with threads. 134 // Therefore, if we have thread-local storage, only the local-exec model 135 // is possible. 136 // TODO: remove this and implement proper TLS models once Emscripten 137 // supports dynamic linking with threads. 138 if (GA->getGlobal()->getThreadLocalMode() != 139 GlobalValue::LocalExecTLSModel && 140 !Subtarget->getTargetTriple().isOSEmscripten()) { 141 report_fatal_error("only -ftls-model=local-exec is supported for now on " 142 "non-Emscripten OSes: variable " + 143 GA->getGlobal()->getName(), 144 false); 145 } 146 147 MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout()); 148 assert(PtrVT == MVT::i32 && "only wasm32 is supported for now"); 149 150 SDValue TLSBaseSym = CurDAG->getTargetExternalSymbol("__tls_base", PtrVT); 151 SDValue TLSOffsetSym = CurDAG->getTargetGlobalAddress( 152 GA->getGlobal(), DL, PtrVT, GA->getOffset(), 0); 153 154 MachineSDNode *TLSBase = CurDAG->getMachineNode(WebAssembly::GLOBAL_GET_I32, 155 DL, MVT::i32, TLSBaseSym); 156 MachineSDNode *TLSOffset = CurDAG->getMachineNode( 157 WebAssembly::CONST_I32, DL, MVT::i32, TLSOffsetSym); 158 MachineSDNode *TLSAddress = 159 CurDAG->getMachineNode(WebAssembly::ADD_I32, DL, MVT::i32, 160 SDValue(TLSBase, 0), SDValue(TLSOffset, 0)); 161 ReplaceNode(Node, TLSAddress); 162 return; 163 } 164 165 case ISD::INTRINSIC_WO_CHAIN: { 166 unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(0))->getZExtValue(); 167 switch (IntNo) { 168 case Intrinsic::wasm_tls_size: { 169 MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout()); 170 assert(PtrVT == MVT::i32 && "only wasm32 is supported for now"); 171 172 MachineSDNode *TLSSize = CurDAG->getMachineNode( 173 WebAssembly::GLOBAL_GET_I32, DL, PtrVT, 174 CurDAG->getTargetExternalSymbol("__tls_size", MVT::i32)); 175 ReplaceNode(Node, TLSSize); 176 return; 177 } 178 case Intrinsic::wasm_tls_align: { 179 MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout()); 180 assert(PtrVT == MVT::i32 && "only wasm32 is supported for now"); 181 182 MachineSDNode *TLSAlign = CurDAG->getMachineNode( 183 WebAssembly::GLOBAL_GET_I32, DL, PtrVT, 184 CurDAG->getTargetExternalSymbol("__tls_align", MVT::i32)); 185 ReplaceNode(Node, TLSAlign); 186 return; 187 } 188 } 189 break; 190 } 191 case ISD::INTRINSIC_W_CHAIN: { 192 unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 193 switch (IntNo) { 194 case Intrinsic::wasm_tls_base: { 195 MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout()); 196 assert(PtrVT == MVT::i32 && "only wasm32 is supported for now"); 197 198 MachineSDNode *TLSBase = CurDAG->getMachineNode( 199 WebAssembly::GLOBAL_GET_I32, DL, MVT::i32, MVT::Other, 200 CurDAG->getTargetExternalSymbol("__tls_base", PtrVT), 201 Node->getOperand(0)); 202 ReplaceNode(Node, TLSBase); 203 return; 204 } 205 } 206 break; 207 } 208 209 default: 210 break; 211 } 212 213 // Select the default instruction. 214 SelectCode(Node); 215 } 216 217 bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand( 218 const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { 219 switch (ConstraintID) { 220 case InlineAsm::Constraint_i: 221 case InlineAsm::Constraint_m: 222 // We just support simple memory operands that just have a single address 223 // operand and need no special handling. 224 OutOps.push_back(Op); 225 return false; 226 default: 227 break; 228 } 229 230 return true; 231 } 232 233 /// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready 234 /// for instruction scheduling. 235 FunctionPass *llvm::createWebAssemblyISelDag(WebAssemblyTargetMachine &TM, 236 CodeGenOpt::Level OptLevel) { 237 return new WebAssemblyDAGToDAGISel(TM, OptLevel); 238 } 239