//===- XtensaISelDAGToDAG.cpp - A dag to dag inst selector for Xtensa -----===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines an instruction selector for the Xtensa target. // //===----------------------------------------------------------------------===// #include "Xtensa.h" #include "XtensaTargetMachine.h" #include "XtensaUtils.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; #define DEBUG_TYPE "xtensa-isel" namespace { class XtensaDAGToDAGISel : public SelectionDAGISel { public: XtensaDAGToDAGISel(XtensaTargetMachine &TM, CodeGenOptLevel OptLevel) : SelectionDAGISel(TM, OptLevel) {} void Select(SDNode *Node) override; // For load/store instructions generate (base+offset) pair from // memory address. The offset must be a multiple of scale argument. bool selectMemRegAddr(SDValue Addr, SDValue &Base, SDValue &Offset, int Scale) { EVT ValTy = Addr.getValueType(); // if Address is FI, get the TargetFrameIndex. if (FrameIndexSDNode *FIN = dyn_cast(Addr)) { Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), ValTy); return true; } if (TM.isPositionIndependent()) { DiagnosticInfoUnsupported Diag(CurDAG->getMachineFunction().getFunction(), "PIC relocations are not supported ", Addr.getDebugLoc()); CurDAG->getContext()->diagnose(Diag); } if ((Addr.getOpcode() == ISD::TargetExternalSymbol || Addr.getOpcode() == ISD::TargetGlobalAddress)) return false; // Addresses of the form FI+const bool Valid = false; if (CurDAG->isBaseWithConstantOffset(Addr)) { ConstantSDNode *CN = dyn_cast(Addr.getOperand(1)); int64_t OffsetVal = CN->getSExtValue(); Valid = isValidAddrOffset(Scale, OffsetVal); if (Valid) { // If the first operand is a FI, get the TargetFI Node if (FrameIndexSDNode *FIN = dyn_cast(Addr.getOperand(0))) Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); else Base = Addr.getOperand(0); Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), ValTy); return true; } } // Last case Base = Addr; Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), Addr.getValueType()); return true; } bool selectMemRegAddrISH1(SDValue Addr, SDValue &Base, SDValue &Offset) { return selectMemRegAddr(Addr, Base, Offset, 1); } bool selectMemRegAddrISH2(SDValue Addr, SDValue &Base, SDValue &Offset) { return selectMemRegAddr(Addr, Base, Offset, 2); } bool selectMemRegAddrISH4(SDValue Addr, SDValue &Base, SDValue &Offset) { return selectMemRegAddr(Addr, Base, Offset, 4); } // Include the pieces autogenerated from the target description. #include "XtensaGenDAGISel.inc" }; // namespace class XtensaDAGToDAGISelLegacy : public SelectionDAGISelLegacy { public: static char ID; XtensaDAGToDAGISelLegacy(XtensaTargetMachine &TM, CodeGenOptLevel OptLevel) : SelectionDAGISelLegacy( ID, std::make_unique(TM, OptLevel)) {} StringRef getPassName() const override { return "Xtensa DAG->DAG Pattern Instruction Selection"; } }; } // end anonymous namespace char XtensaDAGToDAGISelLegacy::ID = 0; FunctionPass *llvm::createXtensaISelDag(XtensaTargetMachine &TM, CodeGenOptLevel OptLevel) { return new XtensaDAGToDAGISelLegacy(TM, OptLevel); } void XtensaDAGToDAGISel::Select(SDNode *Node) { SDLoc DL(Node); // If we have a custom node, we already have selected! if (Node->isMachineOpcode()) { Node->setNodeId(-1); return; } SelectCode(Node); }