| //===- ARCISelDAGToDAG.cpp - ARC dag to dag inst selector -------*- C++ -*-===// |
| // |
| // 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 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); |
| } |