LLVM  11.0.0git
WebAssemblyISelDAGToDAG.cpp
Go to the documentation of this file.
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 
15 #include "WebAssembly.h"
18 #include "llvm/IR/DiagnosticInfo.h"
19 #include "llvm/IR/Function.h" // To access function attributes.
20 #include "llvm/IR/IntrinsicsWebAssembly.h"
21 #include "llvm/Support/Debug.h"
22 #include "llvm/Support/KnownBits.h"
25 using namespace llvm;
26 
27 #define DEBUG_TYPE "wasm-isel"
28 
29 //===--------------------------------------------------------------------===//
30 /// WebAssembly-specific code to select WebAssembly machine instructions for
31 /// SelectionDAG operations.
32 ///
33 namespace {
34 class WebAssemblyDAGToDAGISel final : public SelectionDAGISel {
35  /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
36  /// right decision when generating code for different targets.
37  const WebAssemblySubtarget *Subtarget;
38 
39 public:
40  WebAssemblyDAGToDAGISel(WebAssemblyTargetMachine &TM,
41  CodeGenOpt::Level OptLevel)
42  : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) {
43  }
44 
45  StringRef getPassName() const override {
46  return "WebAssembly Instruction Selection";
47  }
48 
49  bool runOnMachineFunction(MachineFunction &MF) override {
50  LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n"
51  "********** Function: "
52  << MF.getName() << '\n');
53 
54  Subtarget = &MF.getSubtarget<WebAssemblySubtarget>();
55 
57  }
58 
59  void Select(SDNode *Node) override;
60 
61  bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
62  std::vector<SDValue> &OutOps) override;
63 
64 // Include the pieces autogenerated from the target description.
65 #include "WebAssemblyGenDAGISel.inc"
66 
67 private:
68  // add select functions here...
69 };
70 } // end anonymous namespace
71 
73  // If we have a custom node, we already have selected!
74  if (Node->isMachineOpcode()) {
75  LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
76  Node->setNodeId(-1);
77  return;
78  }
79 
80  MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
81  auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
82  : WebAssembly::GLOBAL_GET_I32;
83  auto ConstIns =
84  PtrVT == MVT::i64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32;
85  auto AddIns = PtrVT == MVT::i64 ? WebAssembly::ADD_I64 : WebAssembly::ADD_I32;
86 
87  // Few custom selection stuff.
88  SDLoc DL(Node);
89  MachineFunction &MF = CurDAG->getMachineFunction();
90  switch (Node->getOpcode()) {
91  case ISD::ATOMIC_FENCE: {
93  break;
94 
95  uint64_t SyncScopeID =
96  cast<ConstantSDNode>(Node->getOperand(2).getNode())->getZExtValue();
97  MachineSDNode *Fence = nullptr;
98  switch (SyncScopeID) {
100  // We lower a single-thread fence to a pseudo compiler barrier instruction
101  // preventing instruction reordering. This will not be emitted in final
102  // binary.
103  Fence = CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE,
104  DL, // debug loc
105  MVT::Other, // outchain type
106  Node->getOperand(0) // inchain
107  );
108  break;
109  case SyncScope::System:
110  // Currently wasm only supports sequentially consistent atomics, so we
111  // always set the order to 0 (sequentially consistent).
112  Fence = CurDAG->getMachineNode(
114  DL, // debug loc
115  MVT::Other, // outchain type
116  CurDAG->getTargetConstant(0, DL, MVT::i32), // order
117  Node->getOperand(0) // inchain
118  );
119  break;
120  default:
121  llvm_unreachable("Unknown scope!");
122  }
123 
124  ReplaceNode(Node, Fence);
125  CurDAG->RemoveDeadNode(Node);
126  return;
127  }
128 
129  case ISD::GlobalTLSAddress: {
130  const auto *GA = cast<GlobalAddressSDNode>(Node);
131 
133  report_fatal_error("cannot use thread-local storage without bulk memory",
134  false);
135 
136  // Currently Emscripten does not support dynamic linking with threads.
137  // Therefore, if we have thread-local storage, only the local-exec model
138  // is possible.
139  // TODO: remove this and implement proper TLS models once Emscripten
140  // supports dynamic linking with threads.
141  if (GA->getGlobal()->getThreadLocalMode() !=
143  !Subtarget->getTargetTriple().isOSEmscripten()) {
144  report_fatal_error("only -ftls-model=local-exec is supported for now on "
145  "non-Emscripten OSes: variable " +
146  GA->getGlobal()->getName(),
147  false);
148  }
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 =
155  CurDAG->getMachineNode(GlobalGetIns, DL, PtrVT, TLSBaseSym);
156  MachineSDNode *TLSOffset =
157  CurDAG->getMachineNode(ConstIns, DL, PtrVT, TLSOffsetSym);
158  MachineSDNode *TLSAddress = CurDAG->getMachineNode(
159  AddIns, DL, PtrVT, SDValue(TLSBase, 0), SDValue(TLSOffset, 0));
160  ReplaceNode(Node, TLSAddress);
161  return;
162  }
163 
165  unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(0))->getZExtValue();
166  switch (IntNo) {
167  case Intrinsic::wasm_tls_size: {
168  MachineSDNode *TLSSize = CurDAG->getMachineNode(
169  GlobalGetIns, DL, PtrVT,
170  CurDAG->getTargetExternalSymbol("__tls_size", PtrVT));
171  ReplaceNode(Node, TLSSize);
172  return;
173  }
174  case Intrinsic::wasm_tls_align: {
175  MachineSDNode *TLSAlign = CurDAG->getMachineNode(
176  GlobalGetIns, DL, PtrVT,
177  CurDAG->getTargetExternalSymbol("__tls_align", PtrVT));
178  ReplaceNode(Node, TLSAlign);
179  return;
180  }
181  }
182  break;
183  }
184  case ISD::INTRINSIC_W_CHAIN: {
185  unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
186  switch (IntNo) {
187  case Intrinsic::wasm_tls_base: {
188  MachineSDNode *TLSBase = CurDAG->getMachineNode(
189  GlobalGetIns, DL, PtrVT, MVT::Other,
190  CurDAG->getTargetExternalSymbol("__tls_base", PtrVT),
191  Node->getOperand(0));
192  ReplaceNode(Node, TLSBase);
193  return;
194  }
195  }
196  break;
197  }
199  case WebAssemblyISD::RET_CALL: {
200  // CALL has both variable operands and variable results, but ISel only
201  // supports one or the other. Split calls into two nodes glued together, one
202  // for the operands and one for the results. These two nodes will be
203  // recombined in a custom inserter hook into a single MachineInstr.
205  for (size_t i = 1; i < Node->getNumOperands(); ++i) {
206  SDValue Op = Node->getOperand(i);
207  if (i == 1 && Op->getOpcode() == WebAssemblyISD::Wrapper)
208  Op = Op->getOperand(0);
209  Ops.push_back(Op);
210  }
211 
212  // Add the chain last
213  Ops.push_back(Node->getOperand(0));
214  MachineSDNode *CallParams =
215  CurDAG->getMachineNode(WebAssembly::CALL_PARAMS, DL, MVT::Glue, Ops);
216 
217  unsigned Results = Node->getOpcode() == WebAssemblyISD::CALL
218  ? WebAssembly::CALL_RESULTS
219  : WebAssembly::RET_CALL_RESULTS;
220 
221  SDValue Link(CallParams, 0);
222  MachineSDNode *CallResults =
223  CurDAG->getMachineNode(Results, DL, Node->getVTList(), Link);
224  ReplaceNode(Node, CallResults);
225  return;
226  }
227 
228  default:
229  break;
230  }
231 
232  // Select the default instruction.
233  SelectCode(Node);
234 }
235 
236 bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(
237  const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
238  switch (ConstraintID) {
240  // We just support simple memory operands that just have a single address
241  // operand and need no special handling.
242  OutOps.push_back(Op);
243  return false;
244  default:
245  break;
246  }
247 
248  return true;
249 }
250 
251 /// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready
252 /// for instruction scheduling.
254  CodeGenOpt::Level OptLevel) {
255  return new WebAssemblyDAGToDAGISel(TM, OptLevel);
256 }
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:140
This class represents lattice values for constants.
Definition: AllocatorList.h:23
SDVTList getVTList() const
Function Alias Analysis Results
void setNodeId(int Id)
Set unique node id.
SDNode * getNode() const
get the SDNode which holds the desired result
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end...
OUTCHAIN = ATOMIC_FENCE(INCHAIN, ordering, scope) This corresponds to the fence instruction.
Definition: ISDOpcodes.h:993
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition: ISDOpcodes.h:176
amdgpu aa AMDGPU Address space based Alias Analysis Wrapper
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
This file declares the WebAssembly-specific subclass of TargetMachine.
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition: ISDOpcodes.h:168
Synchronized with respect to signal handlers executing in the same thread.
Definition: LLVMContext.h:55
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
Machine Value Type.
FunctionPass * createWebAssemblyISelDag(WebAssemblyTargetMachine &TM, CodeGenOpt::Level OptLevel)
This pass converts a legalized DAG into a WebAssembly-specific DAG, ready for instruction scheduling...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
const SDValue & getOperand(unsigned Num) const
This file provides WebAssembly-specific target descriptions.
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:284
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
bool isMachineOpcode() const
Test if this node has a post-isel opcode, directly corresponding to a MachineInstr opcode...
unsigned getNumOperands() const
Return the number of values used by this operation.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void dump() const
Dump this node, for debugging.
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:883
An SDNode that represents everything that will be needed to construct a MachineInstr.
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
Synchronized with respect to all concurrently executing threads.
Definition: LLVMContext.h:58
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:57
#define LLVM_DEBUG(X)
Definition: Debug.h:122
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL