LLVM  10.0.0svn
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/Support/Debug.h"
21 #include "llvm/Support/KnownBits.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  bool ForCodeSize;
39 
40 public:
41  WebAssemblyDAGToDAGISel(WebAssemblyTargetMachine &TM,
42  CodeGenOpt::Level OptLevel)
43  : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr), ForCodeSize(false) {
44  }
45 
46  StringRef getPassName() const override {
47  return "WebAssembly Instruction Selection";
48  }
49 
50  bool runOnMachineFunction(MachineFunction &MF) override {
51  LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n"
52  "********** Function: "
53  << MF.getName() << '\n');
54 
55  ForCodeSize = MF.getFunction().hasOptSize();
56  Subtarget = &MF.getSubtarget<WebAssemblySubtarget>();
58  }
59 
60  void Select(SDNode *Node) override;
61 
62  bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
63  std::vector<SDValue> &OutOps) override;
64 
65 // Include the pieces autogenerated from the target description.
66 #include "WebAssemblyGenDAGISel.inc"
67 
68 private:
69  // add select functions here...
70 };
71 } // end anonymous namespace
72 
74  // If we have a custom node, we already have selected!
75  if (Node->isMachineOpcode()) {
76  LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
77  Node->setNodeId(-1);
78  return;
79  }
80 
81  // Few custom selection stuff.
82  SDLoc DL(Node);
83  MachineFunction &MF = CurDAG->getMachineFunction();
84  switch (Node->getOpcode()) {
85  case ISD::ATOMIC_FENCE: {
87  break;
88 
89  uint64_t SyncScopeID =
90  cast<ConstantSDNode>(Node->getOperand(2).getNode())->getZExtValue();
91  MachineSDNode *Fence = nullptr;
92  switch (SyncScopeID) {
94  // We lower a single-thread fence to a pseudo compiler barrier instruction
95  // preventing instruction reordering. This will not be emitted in final
96  // binary.
97  Fence = CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE,
98  DL, // debug loc
99  MVT::Other, // outchain type
100  Node->getOperand(0) // inchain
101  );
102  break;
103  case SyncScope::System:
104  // Currently wasm only supports sequentially consistent atomics, so we
105  // always set the order to 0 (sequentially consistent).
106  Fence = CurDAG->getMachineNode(
108  DL, // debug loc
109  MVT::Other, // outchain type
110  CurDAG->getTargetConstant(0, DL, MVT::i32), // order
111  Node->getOperand(0) // inchain
112  );
113  break;
114  default:
115  llvm_unreachable("Unknown scope!");
116  }
117 
118  ReplaceNode(Node, Fence);
119  CurDAG->RemoveDeadNode(Node);
120  return;
121  }
122 
123  case ISD::GlobalTLSAddress: {
124  const auto *GA = cast<GlobalAddressSDNode>(Node);
125 
127  report_fatal_error("cannot use thread-local storage without bulk memory",
128  false);
129 
130  // Currently Emscripten does not support dynamic linking with threads.
131  // Therefore, if we have thread-local storage, only the local-exec model
132  // is possible.
133  // TODO: remove this and implement proper TLS models once Emscripten
134  // supports dynamic linking with threads.
135  if (GA->getGlobal()->getThreadLocalMode() !=
137  !Subtarget->getTargetTriple().isOSEmscripten()) {
138  report_fatal_error("only -ftls-model=local-exec is supported for now on "
139  "non-Emscripten OSes: variable " +
140  GA->getGlobal()->getName(),
141  false);
142  }
143 
144  MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
145  assert(PtrVT == MVT::i32 && "only wasm32 is supported for now");
146 
147  SDValue TLSBaseSym = CurDAG->getTargetExternalSymbol("__tls_base", PtrVT);
148  SDValue TLSOffsetSym = CurDAG->getTargetGlobalAddress(
149  GA->getGlobal(), DL, PtrVT, GA->getOffset(), 0);
150 
151  MachineSDNode *TLSBase = CurDAG->getMachineNode(WebAssembly::GLOBAL_GET_I32,
152  DL, MVT::i32, TLSBaseSym);
153  MachineSDNode *TLSOffset = CurDAG->getMachineNode(
154  WebAssembly::CONST_I32, DL, MVT::i32, TLSOffsetSym);
155  MachineSDNode *TLSAddress =
156  CurDAG->getMachineNode(WebAssembly::ADD_I32, DL, MVT::i32,
157  SDValue(TLSBase, 0), SDValue(TLSOffset, 0));
158  ReplaceNode(Node, TLSAddress);
159  return;
160  }
161 
163  unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(0))->getZExtValue();
164  switch (IntNo) {
165  case Intrinsic::wasm_tls_size: {
166  MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
167  assert(PtrVT == MVT::i32 && "only wasm32 is supported for now");
168 
169  MachineSDNode *TLSSize = CurDAG->getMachineNode(
170  WebAssembly::GLOBAL_GET_I32, DL, PtrVT,
171  CurDAG->getTargetExternalSymbol("__tls_size", MVT::i32));
172  ReplaceNode(Node, TLSSize);
173  return;
174  }
175  case Intrinsic::wasm_tls_align: {
176  MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
177  assert(PtrVT == MVT::i32 && "only wasm32 is supported for now");
178 
179  MachineSDNode *TLSAlign = CurDAG->getMachineNode(
180  WebAssembly::GLOBAL_GET_I32, DL, PtrVT,
181  CurDAG->getTargetExternalSymbol("__tls_align", MVT::i32));
182  ReplaceNode(Node, TLSAlign);
183  return;
184  }
185  }
186  break;
187  }
188  case ISD::INTRINSIC_W_CHAIN: {
189  unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
190  switch (IntNo) {
191  case Intrinsic::wasm_tls_base: {
192  MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
193  assert(PtrVT == MVT::i32 && "only wasm32 is supported for now");
194 
195  MachineSDNode *TLSBase = CurDAG->getMachineNode(
196  WebAssembly::GLOBAL_GET_I32, DL, MVT::i32, MVT::Other,
197  CurDAG->getTargetExternalSymbol("__tls_base", PtrVT),
198  Node->getOperand(0));
199  ReplaceNode(Node, TLSBase);
200  return;
201  }
202  }
203  break;
204  }
205 
206  default:
207  break;
208  }
209 
210  // Select the default instruction.
211  SelectCode(Node);
212 }
213 
214 bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(
215  const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
216  switch (ConstraintID) {
219  // We just support simple memory operands that just have a single address
220  // operand and need no special handling.
221  OutOps.push_back(Op);
222  return false;
223  default:
224  break;
225  }
226 
227  return true;
228 }
229 
230 /// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready
231 /// for instruction scheduling.
233  CodeGenOpt::Level OptLevel) {
234  return new WebAssemblyDAGToDAGISel(TM, OptLevel);
235 }
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
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:139
This class represents lattice values for constants.
Definition: AllocatorList.h:23
bool hasOptSize() const
Optimize this function for size (-Os) or minimum size (-Oz).
Definition: Function.h:622
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:812
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition: ISDOpcodes.h:158
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:150
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
bool isMachineOpcode() const
Test if this node has a post-isel opcode, directly corresponding to a MachineInstr opcode...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void dump() const
Dump this node, for debugging.
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...
const Function & getFunction() const
Return the LLVM function that this machine code represents.
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:54
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Synchronized with respect to signal handlers executing in the same thread.
Definition: LLVMContext.h:51
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
#define LLVM_DEBUG(X)
Definition: Debug.h:122
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation...