//===- BlackfinISelDAGToDAG.cpp - A dag to dag inst selector for Blackfin -===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines an instruction selector for the Blackfin target. // //===----------------------------------------------------------------------===// #include "Blackfin.h" #include "BlackfinTargetMachine.h" #include "BlackfinRegisterInfo.h" #include "llvm/Intrinsics.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; //===----------------------------------------------------------------------===// // Instruction Selector Implementation //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// /// BlackfinDAGToDAGISel - Blackfin specific code to select blackfin machine /// instructions for SelectionDAG operations. namespace { class BlackfinDAGToDAGISel : public SelectionDAGISel { /// Subtarget - Keep a pointer to the Blackfin Subtarget around so that we /// can make the right decision when generating code for different targets. //const BlackfinSubtarget &Subtarget; public: BlackfinDAGToDAGISel(BlackfinTargetMachine &TM, CodeGenOpt::Level OptLevel) : SelectionDAGISel(TM, OptLevel) {} virtual void PostprocessISelDAG(); virtual const char *getPassName() const { return "Blackfin DAG->DAG Pattern Instruction Selection"; } // Include the pieces autogenerated from the target description. #include "BlackfinGenDAGISel.inc" private: SDNode *Select(SDNode *N); bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset); // Walk the DAG after instruction selection, fixing register class issues. void FixRegisterClasses(SelectionDAG &DAG); const BlackfinInstrInfo &getInstrInfo() { return *static_cast<const BlackfinTargetMachine&>(TM).getInstrInfo(); } const BlackfinRegisterInfo *getRegisterInfo() { return static_cast<const BlackfinTargetMachine&>(TM).getRegisterInfo(); } }; } // end anonymous namespace FunctionPass *llvm::createBlackfinISelDag(BlackfinTargetMachine &TM, CodeGenOpt::Level OptLevel) { return new BlackfinDAGToDAGISel(TM, OptLevel); } void BlackfinDAGToDAGISel::PostprocessISelDAG() { FixRegisterClasses(*CurDAG); } SDNode *BlackfinDAGToDAGISel::Select(SDNode *N) { if (N->isMachineOpcode()) return NULL; // Already selected. switch (N->getOpcode()) { default: break; case ISD::FrameIndex: { // Selects to ADDpp FI, 0 which in turn will become ADDimm7 SP, imm or ADDpp // SP, Px int FI = cast<FrameIndexSDNode>(N)->getIndex(); SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32); return CurDAG->SelectNodeTo(N, BF::ADDpp, MVT::i32, TFI, CurDAG->getTargetConstant(0, MVT::i32)); } } return SelectCode(N); } bool BlackfinDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset) { FrameIndexSDNode *FIN = 0; if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) { Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); Offset = CurDAG->getTargetConstant(0, MVT::i32); return true; } if (Addr.getOpcode() == ISD::ADD) { ConstantSDNode *CN = 0; if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) { // Constant positive word offset from frame index Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32); return true; } } return false; } static inline bool isCC(const TargetRegisterClass *RC) { return BF::AnyCCRegClass.hasSubClassEq(RC); } static inline bool isDCC(const TargetRegisterClass *RC) { return BF::DRegClass.hasSubClassEq(RC) || isCC(RC); } static void UpdateNodeOperand(SelectionDAG &DAG, SDNode *N, unsigned Num, SDValue Val) { SmallVector<SDValue, 8> ops(N->op_begin(), N->op_end()); ops[Num] = Val; SDNode *New = DAG.UpdateNodeOperands(N, ops.data(), ops.size()); DAG.ReplaceAllUsesWith(N, New); } // After instruction selection, insert COPY_TO_REGCLASS nodes to help in // choosing the proper register classes. void BlackfinDAGToDAGISel::FixRegisterClasses(SelectionDAG &DAG) { const BlackfinInstrInfo &TII = getInstrInfo(); const BlackfinRegisterInfo *TRI = getRegisterInfo(); DAG.AssignTopologicalOrder(); HandleSDNode Dummy(DAG.getRoot()); for (SelectionDAG::allnodes_iterator NI = DAG.allnodes_begin(); NI != DAG.allnodes_end(); ++NI) { if (NI->use_empty() || !NI->isMachineOpcode()) continue; const MCInstrDesc &DefMCID = TII.get(NI->getMachineOpcode()); for (SDNode::use_iterator UI = NI->use_begin(); !UI.atEnd(); ++UI) { if (!UI->isMachineOpcode()) continue; if (UI.getUse().getResNo() >= DefMCID.getNumDefs()) continue; const TargetRegisterClass *DefRC = TII.getRegClass(DefMCID, UI.getUse().getResNo(), TRI); const MCInstrDesc &UseMCID = TII.get(UI->getMachineOpcode()); if (UseMCID.getNumDefs()+UI.getOperandNo() >= UseMCID.getNumOperands()) continue; const TargetRegisterClass *UseRC = TII.getRegClass(UseMCID, UseMCID.getNumDefs()+UI.getOperandNo(), TRI); if (!DefRC || !UseRC) continue; // We cannot copy CC <-> !(CC/D) if ((isCC(DefRC) && !isDCC(UseRC)) || (isCC(UseRC) && !isDCC(DefRC))) { SDNode *Copy = DAG.getMachineNode(TargetOpcode::COPY_TO_REGCLASS, NI->getDebugLoc(), MVT::i32, UI.getUse().get(), DAG.getTargetConstant(BF::DRegClassID, MVT::i32)); UpdateNodeOperand(DAG, *UI, UI.getOperandNo(), SDValue(Copy, 0)); } } } DAG.setRoot(Dummy.getValue()); }