[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / lib / Target / WebAssembly / WebAssemblyISelDAGToDAG.cpp
blob818c9c8633bcb95758c1b103ba2605d4598cfb50
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 //===----------------------------------------------------------------------===//
14 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
15 #include "WebAssembly.h"
16 #include "WebAssemblyISelLowering.h"
17 #include "WebAssemblyTargetMachine.h"
18 #include "llvm/CodeGen/MachineFrameInfo.h"
19 #include "llvm/CodeGen/SelectionDAGISel.h"
20 #include "llvm/CodeGen/WasmEHFuncInfo.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"
26 #include "llvm/Support/MathExtras.h"
27 #include "llvm/Support/raw_ostream.h"
29 using namespace llvm;
31 #define DEBUG_TYPE "wasm-isel"
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;
43 public:
44 WebAssemblyDAGToDAGISel(WebAssemblyTargetMachine &TM,
45 CodeGenOpt::Level OptLevel)
46 : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) {
49 StringRef getPassName() const override {
50 return "WebAssembly Instruction Selection";
53 bool runOnMachineFunction(MachineFunction &MF) override {
54 LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n"
55 "********** Function: "
56 << MF.getName() << '\n');
58 Subtarget = &MF.getSubtarget<WebAssemblySubtarget>();
60 return SelectionDAGISel::runOnMachineFunction(MF);
63 void PreprocessISelDAG() override;
65 void Select(SDNode *Node) override;
67 bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
68 std::vector<SDValue> &OutOps) override;
69 bool SelectExternRefAddr(const SDValue &Addr, const SDValue &Base);
71 // Include the pieces autogenerated from the target description.
72 #include "WebAssemblyGenDAGISel.inc"
74 private:
75 // add select functions here...
77 } // end anonymous namespace
79 void WebAssemblyDAGToDAGISel::PreprocessISelDAG() {
80 // Stack objects that should be allocated to locals are hoisted to WebAssembly
81 // locals when they are first used. However for those without uses, we hoist
82 // them here. It would be nice if there were some hook to do this when they
83 // are added to the MachineFrameInfo, but that's not the case right now.
84 MachineFrameInfo &FrameInfo = MF->getFrameInfo();
85 for (int Idx = 0; Idx < FrameInfo.getObjectIndexEnd(); Idx++)
86 WebAssemblyFrameLowering::getLocalForStackObject(*MF, Idx);
88 SelectionDAGISel::PreprocessISelDAG();
91 static SDValue getTagSymNode(int Tag, SelectionDAG *DAG) {
92 assert(Tag == WebAssembly::CPP_EXCEPTION);
93 auto &MF = DAG->getMachineFunction();
94 const auto &TLI = DAG->getTargetLoweringInfo();
95 MVT PtrVT = TLI.getPointerTy(DAG->getDataLayout());
96 const char *SymName = MF.createExternalSymbolName("__cpp_exception");
97 return DAG->getTargetExternalSymbol(SymName, PtrVT);
100 void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
101 // If we have a custom node, we already have selected!
102 if (Node->isMachineOpcode()) {
103 LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
104 Node->setNodeId(-1);
105 return;
108 MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
109 auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
110 : WebAssembly::GLOBAL_GET_I32;
112 // Few custom selection stuff.
113 SDLoc DL(Node);
114 MachineFunction &MF = CurDAG->getMachineFunction();
115 switch (Node->getOpcode()) {
116 case ISD::ATOMIC_FENCE: {
117 if (!MF.getSubtarget<WebAssemblySubtarget>().hasAtomics())
118 break;
120 uint64_t SyncScopeID = Node->getConstantOperandVal(2);
121 MachineSDNode *Fence = nullptr;
122 switch (SyncScopeID) {
123 case SyncScope::SingleThread:
124 // We lower a single-thread fence to a pseudo compiler barrier instruction
125 // preventing instruction reordering. This will not be emitted in final
126 // binary.
127 Fence = CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE,
128 DL, // debug loc
129 MVT::Other, // outchain type
130 Node->getOperand(0) // inchain
132 break;
133 case SyncScope::System:
134 // Currently wasm only supports sequentially consistent atomics, so we
135 // always set the order to 0 (sequentially consistent).
136 Fence = CurDAG->getMachineNode(
137 WebAssembly::ATOMIC_FENCE,
138 DL, // debug loc
139 MVT::Other, // outchain type
140 CurDAG->getTargetConstant(0, DL, MVT::i32), // order
141 Node->getOperand(0) // inchain
143 break;
144 default:
145 llvm_unreachable("Unknown scope!");
148 ReplaceNode(Node, Fence);
149 CurDAG->RemoveDeadNode(Node);
150 return;
153 case ISD::INTRINSIC_WO_CHAIN: {
154 unsigned IntNo = Node->getConstantOperandVal(0);
155 switch (IntNo) {
156 case Intrinsic::wasm_tls_size: {
157 MachineSDNode *TLSSize = CurDAG->getMachineNode(
158 GlobalGetIns, DL, PtrVT,
159 CurDAG->getTargetExternalSymbol("__tls_size", PtrVT));
160 ReplaceNode(Node, TLSSize);
161 return;
164 case Intrinsic::wasm_tls_align: {
165 MachineSDNode *TLSAlign = CurDAG->getMachineNode(
166 GlobalGetIns, DL, PtrVT,
167 CurDAG->getTargetExternalSymbol("__tls_align", PtrVT));
168 ReplaceNode(Node, TLSAlign);
169 return;
172 break;
175 case ISD::INTRINSIC_W_CHAIN: {
176 unsigned IntNo = Node->getConstantOperandVal(1);
177 const auto &TLI = CurDAG->getTargetLoweringInfo();
178 MVT PtrVT = TLI.getPointerTy(CurDAG->getDataLayout());
179 switch (IntNo) {
180 case Intrinsic::wasm_tls_base: {
181 MachineSDNode *TLSBase = CurDAG->getMachineNode(
182 GlobalGetIns, DL, PtrVT, MVT::Other,
183 CurDAG->getTargetExternalSymbol("__tls_base", PtrVT),
184 Node->getOperand(0));
185 ReplaceNode(Node, TLSBase);
186 return;
189 case Intrinsic::wasm_catch_exn: {
190 int Tag = Node->getConstantOperandVal(2);
191 SDValue SymNode = getTagSymNode(Tag, CurDAG);
192 MachineSDNode *Catch =
193 CurDAG->getMachineNode(WebAssembly::CATCH, DL,
195 PtrVT, // exception pointer
196 MVT::Other // outchain type
199 SymNode, // exception symbol
200 Node->getOperand(0) // inchain
202 ReplaceNode(Node, Catch);
203 return;
206 break;
209 case ISD::INTRINSIC_VOID: {
210 unsigned IntNo = Node->getConstantOperandVal(1);
211 switch (IntNo) {
212 case Intrinsic::wasm_throw: {
213 int Tag = Node->getConstantOperandVal(2);
214 SDValue SymNode = getTagSymNode(Tag, CurDAG);
215 MachineSDNode *Throw =
216 CurDAG->getMachineNode(WebAssembly::THROW, DL,
217 MVT::Other, // outchain type
219 SymNode, // exception symbol
220 Node->getOperand(3), // thrown value
221 Node->getOperand(0) // inchain
223 ReplaceNode(Node, Throw);
224 return;
227 break;
230 case WebAssemblyISD::CALL:
231 case WebAssemblyISD::RET_CALL: {
232 // CALL has both variable operands and variable results, but ISel only
233 // supports one or the other. Split calls into two nodes glued together, one
234 // for the operands and one for the results. These two nodes will be
235 // recombined in a custom inserter hook into a single MachineInstr.
236 SmallVector<SDValue, 16> Ops;
237 for (size_t i = 1; i < Node->getNumOperands(); ++i) {
238 SDValue Op = Node->getOperand(i);
239 if (i == 1 && Op->getOpcode() == WebAssemblyISD::Wrapper)
240 Op = Op->getOperand(0);
241 Ops.push_back(Op);
244 // Add the chain last
245 Ops.push_back(Node->getOperand(0));
246 MachineSDNode *CallParams =
247 CurDAG->getMachineNode(WebAssembly::CALL_PARAMS, DL, MVT::Glue, Ops);
249 unsigned Results = Node->getOpcode() == WebAssemblyISD::CALL
250 ? WebAssembly::CALL_RESULTS
251 : WebAssembly::RET_CALL_RESULTS;
253 SDValue Link(CallParams, 0);
254 MachineSDNode *CallResults =
255 CurDAG->getMachineNode(Results, DL, Node->getVTList(), Link);
256 ReplaceNode(Node, CallResults);
257 return;
260 default:
261 break;
264 // Select the default instruction.
265 SelectCode(Node);
268 bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(
269 const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
270 switch (ConstraintID) {
271 case InlineAsm::Constraint_m:
272 // We just support simple memory operands that just have a single address
273 // operand and need no special handling.
274 OutOps.push_back(Op);
275 return false;
276 default:
277 break;
280 return true;
283 /// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready
284 /// for instruction scheduling.
285 FunctionPass *llvm::createWebAssemblyISelDag(WebAssemblyTargetMachine &TM,
286 CodeGenOpt::Level OptLevel) {
287 return new WebAssemblyDAGToDAGISel(TM, OptLevel);