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  switch (SyncScopeID) {
93  // We lower a single-thread fence to a pseudo compiler barrier instruction
94  // preventing instruction reordering. This will not be emitted in final
95  // binary.
96  MachineSDNode *Fence =
97  CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE,
98  DL, // debug loc
99  MVT::Other, // outchain type
100  Node->getOperand(0) // inchain
101  );
102  ReplaceNode(Node, Fence);
103  CurDAG->RemoveDeadNode(Node);
104  return;
105  }
106 
107  case SyncScope::System: {
108  // For non-emscripten systems, we have not decided on what we should
109  // traslate fences to yet.
110  if (!Subtarget->getTargetTriple().isOSEmscripten())
112  "ATOMIC_FENCE is not yet supported in non-emscripten OSes");
113 
114  // Wasm does not have a fence instruction, but because all atomic
115  // instructions in wasm are sequentially consistent, we translate a
116  // fence to an idempotent atomic RMW instruction to a linear memory
117  // address. All atomic instructions in wasm are sequentially consistent,
118  // but this is to ensure a fence also prevents reordering of non-atomic
119  // instructions in the VM. Even though LLVM IR's fence instruction does
120  // not say anything about its relationship with non-atomic instructions,
121  // we think this is more user-friendly.
122  //
123  // While any address can work, here we use a value stored in
124  // __stack_pointer wasm global because there's high chance that area is
125  // in cache.
126  //
127  // So the selected instructions will be in the form of:
128  // %addr = get_global $__stack_pointer
129  // %0 = i32.const 0
130  // i32.atomic.rmw.or %addr, %0
131  SDValue StackPtrSym = CurDAG->getTargetExternalSymbol(
132  "__stack_pointer", TLI->getPointerTy(CurDAG->getDataLayout()));
133  MachineSDNode *GetGlobal =
134  CurDAG->getMachineNode(WebAssembly::GLOBAL_GET_I32, // opcode
135  DL, // debug loc
136  MVT::i32, // result type
137  StackPtrSym // __stack_pointer symbol
138  );
139 
140  SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i32);
141  auto *MMO = MF.getMachineMemOperand(
143  // FIXME Volatile isn't really correct, but currently all LLVM
144  // atomic instructions are treated as volatiles in the backend, so
145  // we should be consistent.
148  4, 4, AAMDNodes(), nullptr, SyncScope::System,
150  MachineSDNode *Const0 =
151  CurDAG->getMachineNode(WebAssembly::CONST_I32, DL, MVT::i32, Zero);
152  MachineSDNode *AtomicRMW = CurDAG->getMachineNode(
153  WebAssembly::ATOMIC_RMW_OR_I32, // opcode
154  DL, // debug loc
155  MVT::i32, // result type
156  MVT::Other, // outchain type
157  {
158  Zero, // alignment
159  Zero, // offset
160  SDValue(GetGlobal, 0), // __stack_pointer
161  SDValue(Const0, 0), // OR with 0 to make it idempotent
162  Node->getOperand(0) // inchain
163  });
164 
165  CurDAG->setNodeMemRefs(AtomicRMW, {MMO});
166  ReplaceUses(SDValue(Node, 0), SDValue(AtomicRMW, 1));
167  CurDAG->RemoveDeadNode(Node);
168  return;
169  }
170  default:
171  llvm_unreachable("Unknown scope!");
172  }
173  }
174 
175  case ISD::GlobalTLSAddress: {
176  const auto *GA = cast<GlobalAddressSDNode>(Node);
177 
179  report_fatal_error("cannot use thread-local storage without bulk memory",
180  false);
181 
182  // Currently Emscripten does not support dynamic linking with threads.
183  // Therefore, if we have thread-local storage, only the local-exec model
184  // is possible.
185  // TODO: remove this and implement proper TLS models once Emscripten
186  // supports dynamic linking with threads.
187  if (GA->getGlobal()->getThreadLocalMode() !=
189  !Subtarget->getTargetTriple().isOSEmscripten()) {
190  report_fatal_error("only -ftls-model=local-exec is supported for now on "
191  "non-Emscripten OSes: variable " +
192  GA->getGlobal()->getName(),
193  false);
194  }
195 
196  MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
197  assert(PtrVT == MVT::i32 && "only wasm32 is supported for now");
198 
199  SDValue TLSBaseSym = CurDAG->getTargetExternalSymbol("__tls_base", PtrVT);
200  SDValue TLSOffsetSym = CurDAG->getTargetGlobalAddress(
201  GA->getGlobal(), DL, PtrVT, GA->getOffset(), 0);
202 
203  MachineSDNode *TLSBase = CurDAG->getMachineNode(WebAssembly::GLOBAL_GET_I32,
204  DL, MVT::i32, TLSBaseSym);
205  MachineSDNode *TLSOffset = CurDAG->getMachineNode(
206  WebAssembly::CONST_I32, DL, MVT::i32, TLSOffsetSym);
207  MachineSDNode *TLSAddress =
208  CurDAG->getMachineNode(WebAssembly::ADD_I32, DL, MVT::i32,
209  SDValue(TLSBase, 0), SDValue(TLSOffset, 0));
210  ReplaceNode(Node, TLSAddress);
211  return;
212  }
213 
215  unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(0))->getZExtValue();
216  switch (IntNo) {
217  case Intrinsic::wasm_tls_size: {
218  MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
219  assert(PtrVT == MVT::i32 && "only wasm32 is supported for now");
220 
221  MachineSDNode *TLSSize = CurDAG->getMachineNode(
222  WebAssembly::GLOBAL_GET_I32, DL, PtrVT,
223  CurDAG->getTargetExternalSymbol("__tls_size", MVT::i32));
224  ReplaceNode(Node, TLSSize);
225  return;
226  }
227  case Intrinsic::wasm_tls_align: {
228  MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
229  assert(PtrVT == MVT::i32 && "only wasm32 is supported for now");
230 
231  MachineSDNode *TLSAlign = CurDAG->getMachineNode(
232  WebAssembly::GLOBAL_GET_I32, DL, PtrVT,
233  CurDAG->getTargetExternalSymbol("__tls_align", MVT::i32));
234  ReplaceNode(Node, TLSAlign);
235  return;
236  }
237  }
238  break;
239  }
240  case ISD::INTRINSIC_W_CHAIN: {
241  unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
242  switch (IntNo) {
243  case Intrinsic::wasm_tls_base: {
244  MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
245  assert(PtrVT == MVT::i32 && "only wasm32 is supported for now");
246 
247  MachineSDNode *TLSBase = CurDAG->getMachineNode(
248  WebAssembly::GLOBAL_GET_I32, DL, MVT::i32, MVT::Other,
249  CurDAG->getTargetExternalSymbol("__tls_base", PtrVT),
250  Node->getOperand(0));
251  ReplaceNode(Node, TLSBase);
252  return;
253  }
254  }
255  break;
256  }
257 
258  default:
259  break;
260  }
261 
262  // Select the default instruction.
263  SelectCode(Node);
264 }
265 
266 bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(
267  const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
268  switch (ConstraintID) {
271  // We just support simple memory operands that just have a single address
272  // operand and need no special handling.
273  OutOps.push_back(Op);
274  return false;
275  default:
276  break;
277  }
278 
279  return true;
280 }
281 
282 /// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready
283 /// for instruction scheduling.
285  CodeGenOpt::Level OptLevel) {
286  return new WebAssemblyDAGToDAGISel(TM, OptLevel);
287 }
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
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, uint64_t s, unsigned base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
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.
The memory access is volatile.
Synchronized with respect to all concurrently executing threads.
Definition: LLVMContext.h:54
static MachinePointerInfo getUnknownStack(MachineFunction &MF)
Stack memory without other information.
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.
The memory access writes data.
void dump() const
Dump this node, for debugging.
An SDNode that represents everything that will be needed to construct a MachineInstr.
A collection of metadata nodes that might be associated with a memory access used by the alias-analys...
Definition: Metadata.h:643
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
The memory access reads data.
Synchronized with respect to signal handlers executing in the same thread.
Definition: LLVMContext.h:51
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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...