//- WebAssemblyISelDAGToDAG.cpp - A dag to dag inst selector for WebAssembly -// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief This file defines an instruction selector for the WebAssembly target. /// //===----------------------------------------------------------------------===// #include "WebAssembly.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "WebAssemblyTargetMachine.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/IR/Function.h" // To access function attributes. #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; #define DEBUG_TYPE "wasm-isel" //===--------------------------------------------------------------------===// /// WebAssembly-specific code to select WebAssembly machine instructions for /// SelectionDAG operations. /// namespace { class WebAssemblyDAGToDAGISel final : public SelectionDAGISel { /// Keep a pointer to the WebAssemblySubtarget around so that we can make the /// right decision when generating code for different targets. const WebAssemblySubtarget *Subtarget; bool ForCodeSize; public: WebAssemblyDAGToDAGISel(WebAssemblyTargetMachine &tm, CodeGenOpt::Level OptLevel) : SelectionDAGISel(tm, OptLevel), Subtarget(nullptr), ForCodeSize(false) { } const char *getPassName() const override { return "WebAssembly Instruction Selection"; } bool runOnMachineFunction(MachineFunction &MF) override { ForCodeSize = MF.getFunction()->hasFnAttribute(Attribute::OptimizeForSize) || MF.getFunction()->hasFnAttribute(Attribute::MinSize); Subtarget = &MF.getSubtarget<WebAssemblySubtarget>(); return SelectionDAGISel::runOnMachineFunction(MF); } SDNode *Select(SDNode *Node) override; bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) override; // Include the pieces autogenerated from the target description. #include "WebAssemblyGenDAGISel.inc" private: // add select functions here... }; } // end anonymous namespace SDNode *WebAssemblyDAGToDAGISel::Select(SDNode *Node) { // Dump information about the Node being selected. DEBUG(errs() << "Selecting: "); DEBUG(Node->dump(CurDAG)); DEBUG(errs() << "\n"); // If we have a custom node, we already have selected! if (Node->isMachineOpcode()) { DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); Node->setNodeId(-1); return nullptr; } // Few custom selection stuff. SDNode *ResNode = nullptr; EVT VT = Node->getValueType(0); switch (Node->getOpcode()) { default: break; // If we need WebAssembly-specific selection, it would go here. (void)VT; } // Select the default instruction. ResNode = SelectCode(Node); DEBUG(errs() << "=> "); if (ResNode == nullptr || ResNode == Node) DEBUG(Node->dump(CurDAG)); else DEBUG(ResNode->dump(CurDAG)); DEBUG(errs() << "\n"); return ResNode; } bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand( const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { switch (ConstraintID) { case InlineAsm::Constraint_i: case InlineAsm::Constraint_m: // We just support simple memory operands that just have a single address // operand and need no special handling. OutOps.push_back(Op); return false; default: break; } return true; } /// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready /// for instruction scheduling. FunctionPass *llvm::createWebAssemblyISelDag(WebAssemblyTargetMachine &TM, CodeGenOpt::Level OptLevel) { return new WebAssemblyDAGToDAGISel(TM, OptLevel); }