| //===- ARCISelDAGToDAG.cpp - ARC dag to dag inst selector -------*- C++ -*-===// | |
| // | |
| // 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 ARC target. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "ARC.h" | |
| #include "ARCTargetMachine.h" | |
| #include "llvm/CodeGen/MachineFrameInfo.h" | |
| #include "llvm/CodeGen/MachineFunction.h" | |
| #include "llvm/CodeGen/MachineInstrBuilder.h" | |
| #include "llvm/CodeGen/MachineRegisterInfo.h" | |
| #include "llvm/CodeGen/SelectionDAG.h" | |
| #include "llvm/CodeGen/SelectionDAGISel.h" | |
| #include "llvm/CodeGen/TargetLowering.h" | |
| #include "llvm/IR/CallingConv.h" | |
| #include "llvm/IR/Constants.h" | |
| #include "llvm/IR/DerivedTypes.h" | |
| #include "llvm/IR/Function.h" | |
| #include "llvm/IR/Intrinsics.h" | |
| #include "llvm/IR/LLVMContext.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; | |
| /// ARCDAGToDAGISel - ARC specific code to select ARC machine | |
| /// instructions for SelectionDAG operations. | |
| namespace { | |
| class ARCDAGToDAGISel : public SelectionDAGISel { | |
| public: | |
| ARCDAGToDAGISel(ARCTargetMachine &TM, CodeGenOpt::Level OptLevel) | |
| : SelectionDAGISel(TM, OptLevel) {} | |
| void Select(SDNode *N) override; | |
| // Complex Pattern Selectors. | |
| bool SelectFrameADDR_ri(SDValue Addr, SDValue &Base, SDValue &Offset); | |
| bool SelectAddrModeS9(SDValue Addr, SDValue &Base, SDValue &Offset); | |
| bool SelectAddrModeImm(SDValue Addr, SDValue &Base, SDValue &Offset); | |
| bool SelectAddrModeFar(SDValue Addr, SDValue &Base, SDValue &Offset); | |
| bool SelectCMOVPred(SDValue N, SDValue &Pred, SDValue &Reg) { | |
| const ConstantSDNode *CN = cast<ConstantSDNode>(N); | |
| Pred = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(N), MVT::i32); | |
| Reg = CurDAG->getRegister(ARC::STATUS32, MVT::i32); | |
| return true; | |
| } | |
| StringRef getPassName() const override { | |
| return "ARC DAG->DAG Pattern Instruction Selection"; | |
| } | |
| // Include the pieces autogenerated from the target description. | |
| #include "ARCGenDAGISel.inc" | |
| }; | |
| } // end anonymous namespace | |
| /// This pass converts a legalized DAG into a ARC-specific DAG, ready for | |
| /// instruction scheduling. | |
| FunctionPass *llvm::createARCISelDag(ARCTargetMachine &TM, | |
| CodeGenOpt::Level OptLevel) { | |
| return new ARCDAGToDAGISel(TM, OptLevel); | |
| } | |
| bool ARCDAGToDAGISel::SelectAddrModeImm(SDValue Addr, SDValue &Base, | |
| SDValue &Offset) { | |
| if (Addr.getOpcode() == ARCISD::GAWRAPPER) { | |
| Base = Addr.getOperand(0); | |
| Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool ARCDAGToDAGISel::SelectAddrModeS9(SDValue Addr, SDValue &Base, | |
| SDValue &Offset) { | |
| if (Addr.getOpcode() == ARCISD::GAWRAPPER) { | |
| return false; | |
| } | |
| if (Addr.getOpcode() != ISD::ADD && Addr.getOpcode() != ISD::SUB && | |
| !CurDAG->isBaseWithConstantOffset(Addr)) { | |
| if (Addr.getOpcode() == ISD::FrameIndex) { | |
| // Match frame index. | |
| int FI = cast<FrameIndexSDNode>(Addr)->getIndex(); | |
| Base = CurDAG->getTargetFrameIndex( | |
| FI, TLI->getPointerTy(CurDAG->getDataLayout())); | |
| } else { | |
| Base = Addr; | |
| } | |
| Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); | |
| return true; | |
| } | |
| if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { | |
| int32_t RHSC = RHS->getSExtValue(); | |
| if (Addr.getOpcode() == ISD::SUB) | |
| RHSC = -RHSC; | |
| // Do we need more than 9 bits to encode? | |
| if (!isInt<9>(RHSC)) | |
| return false; | |
| Base = Addr.getOperand(0); | |
| if (Base.getOpcode() == ISD::FrameIndex) { | |
| int FI = cast<FrameIndexSDNode>(Base)->getIndex(); | |
| Base = CurDAG->getTargetFrameIndex( | |
| FI, TLI->getPointerTy(CurDAG->getDataLayout())); | |
| } | |
| Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32); | |
| return true; | |
| } | |
| Base = Addr; | |
| Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); | |
| return true; | |
| } | |
| bool ARCDAGToDAGISel::SelectAddrModeFar(SDValue Addr, SDValue &Base, | |
| SDValue &Offset) { | |
| if (SelectAddrModeS9(Addr, Base, Offset)) | |
| return false; | |
| if (Addr.getOpcode() == ARCISD::GAWRAPPER) { | |
| return false; | |
| } | |
| if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { | |
| int32_t RHSC = RHS->getSExtValue(); | |
| if (Addr.getOpcode() == ISD::SUB) | |
| RHSC = -RHSC; | |
| Base = Addr.getOperand(0); | |
| Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32); | |
| return true; | |
| } | |
| return false; | |
| } | |
| // Is this a legal frame index addressing expression. | |
| bool ARCDAGToDAGISel::SelectFrameADDR_ri(SDValue Addr, SDValue &Base, | |
| SDValue &Offset) { | |
| FrameIndexSDNode *FIN = nullptr; | |
| if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) { | |
| Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); | |
| Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); | |
| return true; | |
| } | |
| if (Addr.getOpcode() == ISD::ADD) { | |
| ConstantSDNode *CN = nullptr; | |
| 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(), SDLoc(Addr), MVT::i32); | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| void ARCDAGToDAGISel::Select(SDNode *N) { | |
| switch (N->getOpcode()) { | |
| case ISD::Constant: { | |
| uint64_t CVal = cast<ConstantSDNode>(N)->getZExtValue(); | |
| ReplaceNode(N, CurDAG->getMachineNode( | |
| isInt<12>(CVal) ? ARC::MOV_rs12 : ARC::MOV_rlimm, | |
| SDLoc(N), MVT::i32, | |
| CurDAG->getTargetConstant(CVal, SDLoc(N), MVT::i32))); | |
| return; | |
| } | |
| } | |
| SelectCode(N); | |
| } |