110e730a2SDan Gohman //- WebAssemblyISelDAGToDAG.cpp - A dag to dag inst selector for WebAssembly -//
210e730a2SDan Gohman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610e730a2SDan Gohman //
710e730a2SDan Gohman //===----------------------------------------------------------------------===//
810e730a2SDan Gohman ///
910e730a2SDan Gohman /// \file
105f8f34e4SAdrian Prantl /// This file defines an instruction selector for the WebAssembly target.
1110e730a2SDan Gohman ///
1210e730a2SDan Gohman //===----------------------------------------------------------------------===//
1310e730a2SDan Gohman
1410e730a2SDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
156bda14b3SChandler Carruth #include "WebAssembly.h"
1646667a10SPaulo Matos #include "WebAssemblyISelLowering.h"
1710e730a2SDan Gohman #include "WebAssemblyTargetMachine.h"
1882f92e35SAndy Wingo #include "llvm/CodeGen/MachineFrameInfo.h"
1910e730a2SDan Gohman #include "llvm/CodeGen/SelectionDAGISel.h"
2031a71a39SHeejin Ahn #include "llvm/CodeGen/WasmEHFuncInfo.h"
2142bba4b8SGuanzhong Chen #include "llvm/IR/DiagnosticInfo.h"
2210e730a2SDan Gohman #include "llvm/IR/Function.h" // To access function attributes.
235d986953SReid Kleckner #include "llvm/IR/IntrinsicsWebAssembly.h"
2410e730a2SDan Gohman #include "llvm/Support/Debug.h"
25053cf4daSCraig Topper #include "llvm/Support/KnownBits.h"
2610e730a2SDan Gohman #include "llvm/Support/MathExtras.h"
2710e730a2SDan Gohman #include "llvm/Support/raw_ostream.h"
28d3a0a65bSPaulo Matos
2910e730a2SDan Gohman using namespace llvm;
3010e730a2SDan Gohman
3110e730a2SDan Gohman #define DEBUG_TYPE "wasm-isel"
3210e730a2SDan Gohman
3310e730a2SDan Gohman //===--------------------------------------------------------------------===//
3410e730a2SDan Gohman /// WebAssembly-specific code to select WebAssembly machine instructions for
3510e730a2SDan Gohman /// SelectionDAG operations.
3610e730a2SDan Gohman ///
3710e730a2SDan Gohman namespace {
3810e730a2SDan Gohman class WebAssemblyDAGToDAGISel final : public SelectionDAGISel {
3910e730a2SDan Gohman /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
4010e730a2SDan Gohman /// right decision when generating code for different targets.
4110e730a2SDan Gohman const WebAssemblySubtarget *Subtarget;
4210e730a2SDan Gohman
4310e730a2SDan Gohman public:
WebAssemblyDAGToDAGISel(WebAssemblyTargetMachine & TM,CodeGenOpt::Level OptLevel)4418c56a07SHeejin Ahn WebAssemblyDAGToDAGISel(WebAssemblyTargetMachine &TM,
4510e730a2SDan Gohman CodeGenOpt::Level OptLevel)
4670a3c9f5SHiroshi Yamauchi : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) {
4710e730a2SDan Gohman }
4810e730a2SDan Gohman
getPassName() const49117296c0SMehdi Amini StringRef getPassName() const override {
5010e730a2SDan Gohman return "WebAssembly Instruction Selection";
5110e730a2SDan Gohman }
5210e730a2SDan Gohman
runOnMachineFunction(MachineFunction & MF)5310e730a2SDan Gohman bool runOnMachineFunction(MachineFunction &MF) override {
54569f0909SHeejin Ahn LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n"
55569f0909SHeejin Ahn "********** Function: "
56569f0909SHeejin Ahn << MF.getName() << '\n');
57569f0909SHeejin Ahn
5810e730a2SDan Gohman Subtarget = &MF.getSubtarget<WebAssemblySubtarget>();
595b74c39dSThomas Lively
6010e730a2SDan Gohman return SelectionDAGISel::runOnMachineFunction(MF);
6110e730a2SDan Gohman }
6210e730a2SDan Gohman
6382f92e35SAndy Wingo void PreprocessISelDAG() override;
6482f92e35SAndy Wingo
65c6afd4bbSJustin Bogner void Select(SDNode *Node) override;
6610e730a2SDan Gohman
67f19ed562SDan Gohman bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
68f19ed562SDan Gohman std::vector<SDValue> &OutOps) override;
69f19ed562SDan Gohman
70b9073fb2SJF Bastien // Include the pieces autogenerated from the target description.
71b9073fb2SJF Bastien #include "WebAssemblyGenDAGISel.inc"
72b9073fb2SJF Bastien
7310e730a2SDan Gohman private:
7410e730a2SDan Gohman // add select functions here...
7510e730a2SDan Gohman };
7610e730a2SDan Gohman } // end anonymous namespace
7710e730a2SDan Gohman
PreprocessISelDAG()7882f92e35SAndy Wingo void WebAssemblyDAGToDAGISel::PreprocessISelDAG() {
7982f92e35SAndy Wingo // Stack objects that should be allocated to locals are hoisted to WebAssembly
8082f92e35SAndy Wingo // locals when they are first used. However for those without uses, we hoist
8182f92e35SAndy Wingo // them here. It would be nice if there were some hook to do this when they
8282f92e35SAndy Wingo // are added to the MachineFrameInfo, but that's not the case right now.
8382f92e35SAndy Wingo MachineFrameInfo &FrameInfo = MF->getFrameInfo();
8482f92e35SAndy Wingo for (int Idx = 0; Idx < FrameInfo.getObjectIndexEnd(); Idx++)
8582f92e35SAndy Wingo WebAssemblyFrameLowering::getLocalForStackObject(*MF, Idx);
8682f92e35SAndy Wingo
8782f92e35SAndy Wingo SelectionDAGISel::PreprocessISelDAG();
8882f92e35SAndy Wingo }
8982f92e35SAndy Wingo
getTagSymNode(int Tag,SelectionDAG * DAG)9031a71a39SHeejin Ahn static SDValue getTagSymNode(int Tag, SelectionDAG *DAG) {
91*28780e59SHeejin Ahn assert(Tag == WebAssembly::CPP_EXCEPTION || WebAssembly::C_LONGJMP);
9231a71a39SHeejin Ahn auto &MF = DAG->getMachineFunction();
9331a71a39SHeejin Ahn const auto &TLI = DAG->getTargetLoweringInfo();
9431a71a39SHeejin Ahn MVT PtrVT = TLI.getPointerTy(DAG->getDataLayout());
95*28780e59SHeejin Ahn const char *SymName = Tag == WebAssembly::CPP_EXCEPTION
96*28780e59SHeejin Ahn ? MF.createExternalSymbolName("__cpp_exception")
97*28780e59SHeejin Ahn : MF.createExternalSymbolName("__c_longjmp");
9831a71a39SHeejin Ahn return DAG->getTargetExternalSymbol(SymName, PtrVT);
9931a71a39SHeejin Ahn }
10031a71a39SHeejin Ahn
Select(SDNode * Node)101c6afd4bbSJustin Bogner void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
102b9073fb2SJF Bastien // If we have a custom node, we already have selected!
103b9073fb2SJF Bastien if (Node->isMachineOpcode()) {
104d34e60caSNicola Zaghen LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
105b9073fb2SJF Bastien Node->setNodeId(-1);
106c6afd4bbSJustin Bogner return;
107b9073fb2SJF Bastien }
108b9073fb2SJF Bastien
109b9a539c0SWouter van Oortmerssen MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
110b9a539c0SWouter van Oortmerssen auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
111b9a539c0SWouter van Oortmerssen : WebAssembly::GLOBAL_GET_I32;
112b9a539c0SWouter van Oortmerssen
11355146585SHeejin Ahn // Few custom selection stuff.
11455146585SHeejin Ahn SDLoc DL(Node);
11555146585SHeejin Ahn MachineFunction &MF = CurDAG->getMachineFunction();
116b9073fb2SJF Bastien switch (Node->getOpcode()) {
11755146585SHeejin Ahn case ISD::ATOMIC_FENCE: {
11855146585SHeejin Ahn if (!MF.getSubtarget<WebAssemblySubtarget>().hasAtomics())
11955146585SHeejin Ahn break;
12055146585SHeejin Ahn
121aa0b0fbbSHeejin Ahn uint64_t SyncScopeID = Node->getConstantOperandVal(2);
122d85fd5a3SHeejin Ahn MachineSDNode *Fence = nullptr;
12355146585SHeejin Ahn switch (SyncScopeID) {
124d85fd5a3SHeejin Ahn case SyncScope::SingleThread:
12555146585SHeejin Ahn // We lower a single-thread fence to a pseudo compiler barrier instruction
12655146585SHeejin Ahn // preventing instruction reordering. This will not be emitted in final
12755146585SHeejin Ahn // binary.
128d85fd5a3SHeejin Ahn Fence = CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE,
12955146585SHeejin Ahn DL, // debug loc
13055146585SHeejin Ahn MVT::Other, // outchain type
13155146585SHeejin Ahn Node->getOperand(0) // inchain
13255146585SHeejin Ahn );
133d85fd5a3SHeejin Ahn break;
134d85fd5a3SHeejin Ahn case SyncScope::System:
135d85fd5a3SHeejin Ahn // Currently wasm only supports sequentially consistent atomics, so we
136d85fd5a3SHeejin Ahn // always set the order to 0 (sequentially consistent).
137d85fd5a3SHeejin Ahn Fence = CurDAG->getMachineNode(
138d85fd5a3SHeejin Ahn WebAssembly::ATOMIC_FENCE,
13955146585SHeejin Ahn DL, // debug loc
14055146585SHeejin Ahn MVT::Other, // outchain type
141d85fd5a3SHeejin Ahn CurDAG->getTargetConstant(0, DL, MVT::i32), // order
14255146585SHeejin Ahn Node->getOperand(0) // inchain
143d85fd5a3SHeejin Ahn );
144d85fd5a3SHeejin Ahn break;
14555146585SHeejin Ahn default:
14655146585SHeejin Ahn llvm_unreachable("Unknown scope!");
14755146585SHeejin Ahn }
148d85fd5a3SHeejin Ahn
149d85fd5a3SHeejin Ahn ReplaceNode(Node, Fence);
150d85fd5a3SHeejin Ahn CurDAG->RemoveDeadNode(Node);
151d85fd5a3SHeejin Ahn return;
15255146585SHeejin Ahn }
15355146585SHeejin Ahn
15442bba4b8SGuanzhong Chen case ISD::INTRINSIC_WO_CHAIN: {
155aa0b0fbbSHeejin Ahn unsigned IntNo = Node->getConstantOperandVal(0);
15642bba4b8SGuanzhong Chen switch (IntNo) {
15742bba4b8SGuanzhong Chen case Intrinsic::wasm_tls_size: {
15842bba4b8SGuanzhong Chen MachineSDNode *TLSSize = CurDAG->getMachineNode(
159b9a539c0SWouter van Oortmerssen GlobalGetIns, DL, PtrVT,
160b9a539c0SWouter van Oortmerssen CurDAG->getTargetExternalSymbol("__tls_size", PtrVT));
16142bba4b8SGuanzhong Chen ReplaceNode(Node, TLSSize);
16242bba4b8SGuanzhong Chen return;
16342bba4b8SGuanzhong Chen }
16431a71a39SHeejin Ahn
1655204f761SGuanzhong Chen case Intrinsic::wasm_tls_align: {
1665204f761SGuanzhong Chen MachineSDNode *TLSAlign = CurDAG->getMachineNode(
167b9a539c0SWouter van Oortmerssen GlobalGetIns, DL, PtrVT,
168b9a539c0SWouter van Oortmerssen CurDAG->getTargetExternalSymbol("__tls_align", PtrVT));
1695204f761SGuanzhong Chen ReplaceNode(Node, TLSAlign);
1705204f761SGuanzhong Chen return;
1715204f761SGuanzhong Chen }
17242bba4b8SGuanzhong Chen }
17342bba4b8SGuanzhong Chen break;
17442bba4b8SGuanzhong Chen }
17531a71a39SHeejin Ahn
176801fa8e6SGuanzhong Chen case ISD::INTRINSIC_W_CHAIN: {
177aa0b0fbbSHeejin Ahn unsigned IntNo = Node->getConstantOperandVal(1);
17831a71a39SHeejin Ahn const auto &TLI = CurDAG->getTargetLoweringInfo();
17931a71a39SHeejin Ahn MVT PtrVT = TLI.getPointerTy(CurDAG->getDataLayout());
180801fa8e6SGuanzhong Chen switch (IntNo) {
181801fa8e6SGuanzhong Chen case Intrinsic::wasm_tls_base: {
182801fa8e6SGuanzhong Chen MachineSDNode *TLSBase = CurDAG->getMachineNode(
183b9a539c0SWouter van Oortmerssen GlobalGetIns, DL, PtrVT, MVT::Other,
184801fa8e6SGuanzhong Chen CurDAG->getTargetExternalSymbol("__tls_base", PtrVT),
185801fa8e6SGuanzhong Chen Node->getOperand(0));
186801fa8e6SGuanzhong Chen ReplaceNode(Node, TLSBase);
187801fa8e6SGuanzhong Chen return;
188801fa8e6SGuanzhong Chen }
18931a71a39SHeejin Ahn
190c2c9a3fdSHeejin Ahn case Intrinsic::wasm_catch: {
19131a71a39SHeejin Ahn int Tag = Node->getConstantOperandVal(2);
19231a71a39SHeejin Ahn SDValue SymNode = getTagSymNode(Tag, CurDAG);
19331a71a39SHeejin Ahn MachineSDNode *Catch =
19431a71a39SHeejin Ahn CurDAG->getMachineNode(WebAssembly::CATCH, DL,
19531a71a39SHeejin Ahn {
19631a71a39SHeejin Ahn PtrVT, // exception pointer
19731a71a39SHeejin Ahn MVT::Other // outchain type
19831a71a39SHeejin Ahn },
19931a71a39SHeejin Ahn {
20031a71a39SHeejin Ahn SymNode, // exception symbol
20131a71a39SHeejin Ahn Node->getOperand(0) // inchain
20231a71a39SHeejin Ahn });
20331a71a39SHeejin Ahn ReplaceNode(Node, Catch);
20431a71a39SHeejin Ahn return;
20531a71a39SHeejin Ahn }
206801fa8e6SGuanzhong Chen }
207801fa8e6SGuanzhong Chen break;
208801fa8e6SGuanzhong Chen }
20931a71a39SHeejin Ahn
21031a71a39SHeejin Ahn case ISD::INTRINSIC_VOID: {
21131a71a39SHeejin Ahn unsigned IntNo = Node->getConstantOperandVal(1);
21231a71a39SHeejin Ahn switch (IntNo) {
21331a71a39SHeejin Ahn case Intrinsic::wasm_throw: {
21431a71a39SHeejin Ahn int Tag = Node->getConstantOperandVal(2);
21531a71a39SHeejin Ahn SDValue SymNode = getTagSymNode(Tag, CurDAG);
21631a71a39SHeejin Ahn MachineSDNode *Throw =
21731a71a39SHeejin Ahn CurDAG->getMachineNode(WebAssembly::THROW, DL,
21831a71a39SHeejin Ahn MVT::Other, // outchain type
21931a71a39SHeejin Ahn {
22031a71a39SHeejin Ahn SymNode, // exception symbol
22131a71a39SHeejin Ahn Node->getOperand(3), // thrown value
22231a71a39SHeejin Ahn Node->getOperand(0) // inchain
22331a71a39SHeejin Ahn });
22431a71a39SHeejin Ahn ReplaceNode(Node, Throw);
22531a71a39SHeejin Ahn return;
22631a71a39SHeejin Ahn }
22731a71a39SHeejin Ahn }
22831a71a39SHeejin Ahn break;
22931a71a39SHeejin Ahn }
23031a71a39SHeejin Ahn
231ca9ba764SThomas Lively case WebAssemblyISD::CALL:
232ca9ba764SThomas Lively case WebAssemblyISD::RET_CALL: {
2337b64a590SThomas Lively // CALL has both variable operands and variable results, but ISel only
2347b64a590SThomas Lively // supports one or the other. Split calls into two nodes glued together, one
2357b64a590SThomas Lively // for the operands and one for the results. These two nodes will be
236d5191096SThomas Lively // recombined in a custom inserter hook into a single MachineInstr.
2377b64a590SThomas Lively SmallVector<SDValue, 16> Ops;
2387b64a590SThomas Lively for (size_t i = 1; i < Node->getNumOperands(); ++i) {
2397b64a590SThomas Lively SDValue Op = Node->getOperand(i);
240ca9ba764SThomas Lively if (i == 1 && Op->getOpcode() == WebAssemblyISD::Wrapper)
2417b64a590SThomas Lively Op = Op->getOperand(0);
2427b64a590SThomas Lively Ops.push_back(Op);
2437b64a590SThomas Lively }
244ca9ba764SThomas Lively
245ca9ba764SThomas Lively // Add the chain last
2467b64a590SThomas Lively Ops.push_back(Node->getOperand(0));
247d5191096SThomas Lively MachineSDNode *CallParams =
248d5191096SThomas Lively CurDAG->getMachineNode(WebAssembly::CALL_PARAMS, DL, MVT::Glue, Ops);
249ca9ba764SThomas Lively
250ca9ba764SThomas Lively unsigned Results = Node->getOpcode() == WebAssemblyISD::CALL
251ca9ba764SThomas Lively ? WebAssembly::CALL_RESULTS
252ca9ba764SThomas Lively : WebAssembly::RET_CALL_RESULTS;
253ca9ba764SThomas Lively
254d5191096SThomas Lively SDValue Link(CallParams, 0);
255ca9ba764SThomas Lively MachineSDNode *CallResults =
256ca9ba764SThomas Lively CurDAG->getMachineNode(Results, DL, Node->getVTList(), Link);
257d5191096SThomas Lively ReplaceNode(Node, CallResults);
2587b64a590SThomas Lively return;
2597b64a590SThomas Lively }
26042bba4b8SGuanzhong Chen
261b9073fb2SJF Bastien default:
262b9073fb2SJF Bastien break;
263b9073fb2SJF Bastien }
264b9073fb2SJF Bastien
265b9073fb2SJF Bastien // Select the default instruction.
266c6afd4bbSJustin Bogner SelectCode(Node);
26710e730a2SDan Gohman }
26810e730a2SDan Gohman
SelectInlineAsmMemoryOperand(const SDValue & Op,unsigned ConstraintID,std::vector<SDValue> & OutOps)269f19ed562SDan Gohman bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(
270f19ed562SDan Gohman const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
271f19ed562SDan Gohman switch (ConstraintID) {
272f19ed562SDan Gohman case InlineAsm::Constraint_m:
273f19ed562SDan Gohman // We just support simple memory operands that just have a single address
274f19ed562SDan Gohman // operand and need no special handling.
275f19ed562SDan Gohman OutOps.push_back(Op);
276f19ed562SDan Gohman return false;
277f19ed562SDan Gohman default:
278f19ed562SDan Gohman break;
279f19ed562SDan Gohman }
280f19ed562SDan Gohman
281f19ed562SDan Gohman return true;
282f19ed562SDan Gohman }
283f19ed562SDan Gohman
28410e730a2SDan Gohman /// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready
28510e730a2SDan Gohman /// for instruction scheduling.
createWebAssemblyISelDag(WebAssemblyTargetMachine & TM,CodeGenOpt::Level OptLevel)28610e730a2SDan Gohman FunctionPass *llvm::createWebAssemblyISelDag(WebAssemblyTargetMachine &TM,
28710e730a2SDan Gohman CodeGenOpt::Level OptLevel) {
28810e730a2SDan Gohman return new WebAssemblyDAGToDAGISel(TM, OptLevel);
28910e730a2SDan Gohman }
290