LLVM  14.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"
21 #include "llvm/IR/DiagnosticInfo.h"
22 #include "llvm/IR/Function.h" // To access function attributes.
23 #include "llvm/IR/IntrinsicsWebAssembly.h"
24 #include "llvm/Support/Debug.h"
25 #include "llvm/Support/KnownBits.h"
28 
29 using namespace llvm;
30 
31 #define DEBUG_TYPE "wasm-isel"
32 
33 //===--------------------------------------------------------------------===//
34 /// WebAssembly-specific code to select WebAssembly machine instructions for
35 /// SelectionDAG operations.
36 ///
37 namespace {
38 class WebAssemblyDAGToDAGISel final : public SelectionDAGISel {
39  /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
40  /// right decision when generating code for different targets.
41  const WebAssemblySubtarget *Subtarget;
42 
43 public:
44  WebAssemblyDAGToDAGISel(WebAssemblyTargetMachine &TM,
45  CodeGenOpt::Level OptLevel)
46  : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) {
47  }
48 
49  StringRef getPassName() const override {
50  return "WebAssembly Instruction Selection";
51  }
52 
53  bool runOnMachineFunction(MachineFunction &MF) override {
54  LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n"
55  "********** Function: "
56  << MF.getName() << '\n');
57 
58  Subtarget = &MF.getSubtarget<WebAssemblySubtarget>();
59 
61  }
62 
63  void PreprocessISelDAG() override;
64 
65  void Select(SDNode *Node) override;
66 
67  bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
68  std::vector<SDValue> &OutOps) override;
69 
70 // Include the pieces autogenerated from the target description.
71 #include "WebAssemblyGenDAGISel.inc"
72 
73 private:
74  // add select functions here...
75 };
76 } // end anonymous namespace
77 
78 void WebAssemblyDAGToDAGISel::PreprocessISelDAG() {
79  // Stack objects that should be allocated to locals are hoisted to WebAssembly
80  // locals when they are first used. However for those without uses, we hoist
81  // them here. It would be nice if there were some hook to do this when they
82  // are added to the MachineFrameInfo, but that's not the case right now.
83  MachineFrameInfo &FrameInfo = MF->getFrameInfo();
84  for (int Idx = 0; Idx < FrameInfo.getObjectIndexEnd(); Idx++)
86 
88 }
89 
90 static SDValue getTagSymNode(int Tag, SelectionDAG *DAG) {
92  auto &MF = DAG->getMachineFunction();
93  const auto &TLI = DAG->getTargetLoweringInfo();
94  MVT PtrVT = TLI.getPointerTy(DAG->getDataLayout());
95  const char *SymName = Tag == WebAssembly::CPP_EXCEPTION
96  ? MF.createExternalSymbolName("__cpp_exception")
97  : MF.createExternalSymbolName("__c_longjmp");
98  return DAG->getTargetExternalSymbol(SymName, PtrVT);
99 }
100 
102  // If we have a custom node, we already have selected!
103  if (Node->isMachineOpcode()) {
104  LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
105  Node->setNodeId(-1);
106  return;
107  }
108 
109  MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
110  auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
111  : WebAssembly::GLOBAL_GET_I32;
112 
113  // Few custom selection stuff.
114  SDLoc DL(Node);
115  MachineFunction &MF = CurDAG->getMachineFunction();
116  switch (Node->getOpcode()) {
117  case ISD::ATOMIC_FENCE: {
119  break;
120 
121  uint64_t SyncScopeID = Node->getConstantOperandVal(2);
122  MachineSDNode *Fence = nullptr;
123  switch (SyncScopeID) {
125  // We lower a single-thread fence to a pseudo compiler barrier instruction
126  // preventing instruction reordering. This will not be emitted in final
127  // binary.
128  Fence = CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE,
129  DL, // debug loc
130  MVT::Other, // outchain type
131  Node->getOperand(0) // inchain
132  );
133  break;
134  case SyncScope::System:
135  // Currently wasm only supports sequentially consistent atomics, so we
136  // always set the order to 0 (sequentially consistent).
137  Fence = CurDAG->getMachineNode(
139  DL, // debug loc
140  MVT::Other, // outchain type
141  CurDAG->getTargetConstant(0, DL, MVT::i32), // order
142  Node->getOperand(0) // inchain
143  );
144  break;
145  default:
146  llvm_unreachable("Unknown scope!");
147  }
148 
149  ReplaceNode(Node, Fence);
150  CurDAG->RemoveDeadNode(Node);
151  return;
152  }
153 
155  unsigned IntNo = Node->getConstantOperandVal(0);
156  switch (IntNo) {
157  case Intrinsic::wasm_tls_size: {
158  MachineSDNode *TLSSize = CurDAG->getMachineNode(
159  GlobalGetIns, DL, PtrVT,
160  CurDAG->getTargetExternalSymbol("__tls_size", PtrVT));
161  ReplaceNode(Node, TLSSize);
162  return;
163  }
164 
165  case Intrinsic::wasm_tls_align: {
166  MachineSDNode *TLSAlign = CurDAG->getMachineNode(
167  GlobalGetIns, DL, PtrVT,
168  CurDAG->getTargetExternalSymbol("__tls_align", PtrVT));
169  ReplaceNode(Node, TLSAlign);
170  return;
171  }
172  }
173  break;
174  }
175 
176  case ISD::INTRINSIC_W_CHAIN: {
177  unsigned IntNo = Node->getConstantOperandVal(1);
178  const auto &TLI = CurDAG->getTargetLoweringInfo();
179  MVT PtrVT = TLI.getPointerTy(CurDAG->getDataLayout());
180  switch (IntNo) {
181  case Intrinsic::wasm_tls_base: {
182  MachineSDNode *TLSBase = CurDAG->getMachineNode(
183  GlobalGetIns, DL, PtrVT, MVT::Other,
184  CurDAG->getTargetExternalSymbol("__tls_base", PtrVT),
185  Node->getOperand(0));
186  ReplaceNode(Node, TLSBase);
187  return;
188  }
189 
190  case Intrinsic::wasm_catch: {
191  int Tag = Node->getConstantOperandVal(2);
192  SDValue SymNode = getTagSymNode(Tag, CurDAG);
194  CurDAG->getMachineNode(WebAssembly::CATCH, DL,
195  {
196  PtrVT, // exception pointer
197  MVT::Other // outchain type
198  },
199  {
200  SymNode, // exception symbol
201  Node->getOperand(0) // inchain
202  });
203  ReplaceNode(Node, Catch);
204  return;
205  }
206  }
207  break;
208  }
209 
210  case ISD::INTRINSIC_VOID: {
211  unsigned IntNo = Node->getConstantOperandVal(1);
212  switch (IntNo) {
213  case Intrinsic::wasm_throw: {
214  int Tag = Node->getConstantOperandVal(2);
215  SDValue SymNode = getTagSymNode(Tag, CurDAG);
216  MachineSDNode *Throw =
217  CurDAG->getMachineNode(WebAssembly::THROW, DL,
218  MVT::Other, // outchain type
219  {
220  SymNode, // exception symbol
221  Node->getOperand(3), // thrown value
222  Node->getOperand(0) // inchain
223  });
224  ReplaceNode(Node, Throw);
225  return;
226  }
227  }
228  break;
229  }
230 
232  case WebAssemblyISD::RET_CALL: {
233  // CALL has both variable operands and variable results, but ISel only
234  // supports one or the other. Split calls into two nodes glued together, one
235  // for the operands and one for the results. These two nodes will be
236  // recombined in a custom inserter hook into a single MachineInstr.
238  for (size_t i = 1; i < Node->getNumOperands(); ++i) {
239  SDValue Op = Node->getOperand(i);
240  if (i == 1 && Op->getOpcode() == WebAssemblyISD::Wrapper)
241  Op = Op->getOperand(0);
242  Ops.push_back(Op);
243  }
244 
245  // Add the chain last
246  Ops.push_back(Node->getOperand(0));
247  MachineSDNode *CallParams =
248  CurDAG->getMachineNode(WebAssembly::CALL_PARAMS, DL, MVT::Glue, Ops);
249 
250  unsigned Results = Node->getOpcode() == WebAssemblyISD::CALL
251  ? WebAssembly::CALL_RESULTS
252  : WebAssembly::RET_CALL_RESULTS;
253 
254  SDValue Link(CallParams, 0);
255  MachineSDNode *CallResults =
256  CurDAG->getMachineNode(Results, DL, Node->getVTList(), Link);
257  ReplaceNode(Node, CallResults);
258  return;
259  }
260 
261  default:
262  break;
263  }
264 
265  // Select the default instruction.
266  SelectCode(Node);
267 }
268 
269 bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(
270  const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
271  switch (ConstraintID) {
273  // We just support simple memory operands that just have a single address
274  // operand and need no special handling.
275  OutOps.push_back(Op);
276  return false;
277  default:
278  break;
279  }
280 
281  return true;
282 }
283 
284 /// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready
285 /// for instruction scheduling.
287  CodeGenOpt::Level OptLevel) {
288  return new WebAssemblyDAGToDAGISel(TM, OptLevel);
289 }
i
i
Definition: README.txt:29
llvm::ISD::INTRINSIC_VOID
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
Definition: ISDOpcodes.h:199
MathExtras.h
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AllocatorList.h:23
WebAssembly.h
llvm::SDLoc
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Definition: SelectionDAGNodes.h:1085
WebAssemblyISelLowering.h
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1168
Wrapper
amdgpu aa AMDGPU Address space based Alias Analysis Wrapper
Definition: AMDGPUAliasAnalysis.cpp:31
llvm::WebAssembly::C_LONGJMP
@ C_LONGJMP
Definition: WasmEHFuncInfo.h:27
llvm::MachineSDNode
An SDNode that represents everything that will be needed to construct a MachineInstr.
Definition: SelectionDAGNodes.h:2762
llvm::createWebAssemblyISelDag
FunctionPass * createWebAssemblyISelDag(WebAssemblyTargetMachine &TM, CodeGenOpt::Level OptLevel)
This pass converts a legalized DAG into a WebAssembly-specific DAG, ready for instruction scheduling.
Definition: WebAssemblyISelDAGToDAG.cpp:286
llvm::SDNode
Represents one node in the SelectionDAG.
Definition: SelectionDAGNodes.h:454
llvm::MVT::Glue
@ Glue
Definition: MachineValueType.h:262
getTagSymNode
static SDValue getTagSymNode(int Tag, SelectionDAG *DAG)
Definition: WebAssemblyISelDAGToDAG.cpp:90
llvm::AArch64ISD::CALL
@ CALL
Definition: AArch64ISelLowering.h:52
Results
Function Alias Analysis Results
Definition: AliasAnalysis.cpp:847
llvm::errs
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
Definition: raw_ostream.cpp:893
WebAssemblyTargetMachine.h
llvm::codeview::Link
@ Link
Definition: CodeView.h:154
llvm::MachineFrameInfo::getObjectIndexEnd
int getObjectIndexEnd() const
Return one past the maximum frame object index.
Definition: MachineFrameInfo.h:393
llvm::dwarf::Tag
Tag
Definition: Dwarf.h:104
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
KnownBits.h
llvm::SelectionDAGISel::PreprocessISelDAG
virtual void PreprocessISelDAG()
PreprocessISelDAG - This hook allows targets to hack on the graph before instruction selection starts...
Definition: SelectionDAGISel.h:77
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
llvm::InlineAsm::Constraint_m
@ Constraint_m
Definition: InlineAsm.h:247
llvm::SelectionDAG
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
Definition: SelectionDAG.h:216
llvm::SelectionDAG::getTargetLoweringInfo
const TargetLowering & getTargetLoweringInfo() const
Definition: SelectionDAG.h:443
llvm::WebAssemblyTargetMachine
Definition: WebAssemblyTargetMachine.h:23
WebAssemblyMCTargetDesc.h
llvm::MachineFunction::getSubtarget
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Definition: MachineFunction.h:641
llvm::ISD::ATOMIC_FENCE
@ ATOMIC_FENCE
OUTCHAIN = ATOMIC_FENCE(INCHAIN, ordering, scope) This corresponds to the fence instruction.
Definition: ISDOpcodes.h:1110
uint64_t
llvm::MachineFunction::getName
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
Definition: MachineFunction.cpp:545
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::MVT::Other
@ Other
Definition: MachineValueType.h:42
llvm::SyncScope::SingleThread
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
Definition: LLVMContext.h:55
llvm::MVT
Machine Value Type.
Definition: MachineValueType.h:31
llvm::MachineFunction
Definition: MachineFunction.h:241
SelectionDAGISel.h
llvm::MVT::i64
@ i64
Definition: MachineValueType.h:47
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:57
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:134
DL
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Definition: AArch64SLSHardening.cpp:76
llvm::WebAssemblySubtarget
Definition: WebAssemblySubtarget.h:35
llvm::CodeGenOpt::Level
Level
Definition: CodeGen.h:52
llvm::ISD::INTRINSIC_WO_CHAIN
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition: ISDOpcodes.h:184
llvm::SyncScope::System
@ System
Synchronized with respect to all concurrently executing threads.
Definition: LLVMContext.h:58
llvm::MCID::Select
@ Select
Definition: MCInstrDesc.h:162
llvm::WebAssembly::CPP_EXCEPTION
@ CPP_EXCEPTION
Definition: WasmEHFuncInfo.h:27
llvm::AMDGPU::SendMsg::Op
Op
Definition: SIDefines.h:325
MachineFrameInfo.h
WasmEHFuncInfo.h
llvm::SelectionDAG::getDataLayout
const DataLayout & getDataLayout() const
Definition: SelectionDAG.h:440
DiagnosticInfo.h
Function.h
llvm::SelectionDAG::getTargetExternalSymbol
SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned TargetFlags=0)
Definition: SelectionDAG.cpp:1778
llvm::MVT::i32
@ i32
Definition: MachineValueType.h:46
llvm::SDValue
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
Definition: SelectionDAGNodes.h:137
llvm::ClrHandlerType::Catch
@ Catch
llvm::MachineFrameInfo
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
Definition: MachineFrameInfo.h:107
llvm::SelectionDAGISel
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
Definition: SelectionDAGISel.h:39
TM
const char LLVMTargetMachineRef TM
Definition: PassBuilderBindings.cpp:47
llvm::FunctionPass
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:298
llvm::ISD::INTRINSIC_W_CHAIN
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition: ISDOpcodes.h:192
llvm::SelectionDAG::getMachineFunction
MachineFunction & getMachineFunction() const
Definition: SelectionDAG.h:437
llvm::WebAssemblySubtarget::hasAtomics
bool hasAtomics() const
Definition: WebAssemblySubtarget.h:94
raw_ostream.h
llvm::SelectionDAGISel::runOnMachineFunction
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
Definition: SelectionDAGISel.cpp:416
llvm::WebAssemblyFrameLowering::getLocalForStackObject
static Optional< unsigned > getLocalForStackObject(MachineFunction &MF, int FrameIndex)
Definition: WebAssemblyFrameLowering.cpp:54
Debug.h