| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,183 @@ | ||
| //===- ARCBranchFinalize.cpp - ARC conditional branches ---------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This pass takes existing conditional branches and expands them into longer | ||
| // range conditional branches. | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #define DEBUG_TYPE "arc-branch-finalize" | ||
|
|
||
| #include "ARCInstrInfo.h" | ||
| #include "ARCTargetMachine.h" | ||
| #include "MCTargetDesc/ARCInfo.h" | ||
| #include "llvm/CodeGen/MachineFunctionPass.h" | ||
| #include "llvm/CodeGen/MachineInstrBuilder.h" | ||
| #include "llvm/CodeGen/MachineRegisterInfo.h" | ||
| #include "llvm/CodeGen/Passes.h" | ||
| #include "llvm/Support/Debug.h" | ||
| #include "llvm/Target/TargetInstrInfo.h" | ||
| #include <vector> | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| namespace llvm { | ||
|
|
||
| void initializeARCBranchFinalizePass(PassRegistry &Registry); | ||
| FunctionPass *createARCBranchFinalizePass(); | ||
|
|
||
| } // end namespace llvm | ||
|
|
||
| namespace { | ||
|
|
||
| class ARCBranchFinalize : public MachineFunctionPass { | ||
| public: | ||
| static char ID; | ||
|
|
||
| ARCBranchFinalize() : MachineFunctionPass(ID) { | ||
| initializeARCBranchFinalizePass(*PassRegistry::getPassRegistry()); | ||
| } | ||
|
|
||
| StringRef getPassName() const override { | ||
| return "ARC Branch Finalization Pass"; | ||
| } | ||
|
|
||
| bool runOnMachineFunction(MachineFunction &MF) override; | ||
| void replaceWithBRcc(MachineInstr *MI) const; | ||
| void replaceWithCmpBcc(MachineInstr *MI) const; | ||
|
|
||
| private: | ||
| const ARCInstrInfo *TII{nullptr}; | ||
| }; | ||
|
|
||
| char ARCBranchFinalize::ID = 0; | ||
|
|
||
| } // end anonymous namespace | ||
|
|
||
| INITIALIZE_PASS_BEGIN(ARCBranchFinalize, "arc-branch-finalize", | ||
| "ARC finalize branches", false, false) | ||
| INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) | ||
| INITIALIZE_PASS_END(ARCBranchFinalize, "arc-branch-finalize", | ||
| "ARC finalize branches", false, false) | ||
|
|
||
| // BRcc has 6 supported condition codes, which differ from the 16 | ||
| // condition codes supported in the predicated instructions: | ||
| // EQ -- 000 | ||
| // NE -- 001 | ||
| // LT -- 010 | ||
| // GE -- 011 | ||
| // LO -- 100 | ||
| // HS -- 101 | ||
| static unsigned getCCForBRcc(unsigned CC) { | ||
| switch (CC) { | ||
| case ARCCC::EQ: | ||
| return 0; | ||
| case ARCCC::NE: | ||
| return 1; | ||
| case ARCCC::LT: | ||
| return 2; | ||
| case ARCCC::GE: | ||
| return 3; | ||
| case ARCCC::LO: | ||
| return 4; | ||
| case ARCCC::HS: | ||
| return 5; | ||
| default: | ||
| return -1U; | ||
| } | ||
| } | ||
|
|
||
| static bool isBRccPseudo(MachineInstr *MI) { | ||
| return !(MI->getOpcode() != ARC::BRcc_rr_p && | ||
| MI->getOpcode() != ARC::BRcc_ru6_p); | ||
| } | ||
|
|
||
| static unsigned getBRccForPseudo(MachineInstr *MI) { | ||
| assert(isBRccPseudo(MI) && "Can't get BRcc for wrong instruction."); | ||
| if (MI->getOpcode() == ARC::BRcc_rr_p) | ||
| return ARC::BRcc_rr; | ||
| return ARC::BRcc_ru6; | ||
| } | ||
|
|
||
| static unsigned getCmpForPseudo(MachineInstr *MI) { | ||
| assert(isBRccPseudo(MI) && "Can't get BRcc for wrong instruction."); | ||
| if (MI->getOpcode() == ARC::BRcc_rr_p) | ||
| return ARC::CMP_rr; | ||
| return ARC::CMP_ru6; | ||
| } | ||
|
|
||
| void ARCBranchFinalize::replaceWithBRcc(MachineInstr *MI) const { | ||
| DEBUG(dbgs() << "Replacing pseudo branch with BRcc\n"); | ||
| unsigned CC = getCCForBRcc(MI->getOperand(3).getImm()); | ||
| if (CC != -1U) { | ||
| BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), | ||
| TII->get(getBRccForPseudo(MI))) | ||
| .addMBB(MI->getOperand(0).getMBB()) | ||
| .addReg(MI->getOperand(1).getReg()) | ||
| .add(MI->getOperand(2)) | ||
| .addImm(getCCForBRcc(MI->getOperand(3).getImm())); | ||
| MI->eraseFromParent(); | ||
| } else { | ||
| replaceWithCmpBcc(MI); | ||
| } | ||
| } | ||
|
|
||
| void ARCBranchFinalize::replaceWithCmpBcc(MachineInstr *MI) const { | ||
| DEBUG(dbgs() << "Branch: " << *MI << "\n"); | ||
| DEBUG(dbgs() << "Replacing pseudo branch with Cmp + Bcc\n"); | ||
| BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), | ||
| TII->get(getCmpForPseudo(MI))) | ||
| .addReg(MI->getOperand(1).getReg()) | ||
| .add(MI->getOperand(2)); | ||
| BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(ARC::Bcc)) | ||
| .addMBB(MI->getOperand(0).getMBB()) | ||
| .addImm(MI->getOperand(3).getImm()); | ||
| MI->eraseFromParent(); | ||
| } | ||
|
|
||
| bool ARCBranchFinalize::runOnMachineFunction(MachineFunction &MF) { | ||
| DEBUG(dbgs() << "Running ARC Branch Finalize on " | ||
| << MF.getFunction()->getName() << "\n"); | ||
| std::vector<MachineInstr *> Branches; | ||
| bool Changed = false; | ||
| unsigned MaxSize = 0; | ||
| TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo(); | ||
| std::map<MachineBasicBlock *, unsigned> BlockToPCMap; | ||
| std::vector<std::pair<MachineInstr *, unsigned>> BranchToPCList; | ||
| unsigned PC = 0; | ||
|
|
||
| for (auto &MBB : MF) { | ||
| BlockToPCMap.insert(std::make_pair(&MBB, PC)); | ||
| for (auto &MI : MBB) { | ||
| unsigned Size = TII->getInstSizeInBytes(MI); | ||
| if (Size > 8 || Size == 0) { | ||
| DEBUG(dbgs() << "Unknown (or size 0) size for: " << MI << "\n"); | ||
| } else { | ||
| MaxSize += Size; | ||
| } | ||
| if (MI.isBranch()) { | ||
| Branches.push_back(&MI); | ||
| BranchToPCList.emplace_back(&MI, PC); | ||
| } | ||
| PC += Size; | ||
| } | ||
| } | ||
| for (auto P : BranchToPCList) { | ||
| if (isBRccPseudo(P.first)) | ||
| isInt<9>(MaxSize) ? replaceWithBRcc(P.first) : replaceWithCmpBcc(P.first); | ||
| } | ||
|
|
||
| DEBUG(dbgs() << "Estimated function size for " << MF.getFunction()->getName() | ||
| << ": " << MaxSize << "\n"); | ||
|
|
||
| return Changed; | ||
| } | ||
|
|
||
| FunctionPass *llvm::createARCBranchFinalizePass() { | ||
| return new ARCBranchFinalize(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| //===- ARCCallingConv.td - Calling Conventions for ARC -----*- tablegen -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // This describes the calling conventions for ARC architecture. | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // ARC Return Value Calling Convention | ||
| //===----------------------------------------------------------------------===// | ||
| def RetCC_ARC : CallingConv<[ | ||
| // i32 are returned in registers R0, R1, R2, R3 | ||
| CCIfType<[i32, i64], CCAssignToReg<[R0, R1, R2, R3]>>, | ||
|
|
||
| // Integer values get stored in stack slots that are 4 bytes in | ||
| // size and 4-byte aligned. | ||
| CCIfType<[i64], CCAssignToStack<8, 4>>, | ||
| CCIfType<[i32], CCAssignToStack<4, 4>> | ||
| ]>; | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // ARC Argument Calling Conventions | ||
| //===----------------------------------------------------------------------===// | ||
| def CC_ARC : CallingConv<[ | ||
| // Promote i8/i16 arguments to i32. | ||
| CCIfType<[i8, i16], CCPromoteToType<i32>>, | ||
|
|
||
| // The first 8 integer arguments are passed in integer registers. | ||
| CCIfType<[i32, i64], CCAssignToReg<[R0, R1, R2, R3, R4, R5, R6, R7]>>, | ||
|
|
||
| // Integer values get stored in stack slots that are 4 bytes in | ||
| // size and 4-byte aligned. | ||
| CCIfType<[i64], CCAssignToStack<8, 4>>, | ||
| CCIfType<[i32], CCAssignToStack<4, 4>> | ||
| ]>; | ||
|
|
||
| def CSR_ARC : CalleeSavedRegs<(add (sequence "R%u", 13, 25), GP, FP)>; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| //===- ARCExpandPseudosPass - ARC expand pseudo loads -----------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This pass expands stores with large offsets into an appropriate sequence. | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "ARC.h" | ||
| #include "ARCInstrInfo.h" | ||
| #include "ARCRegisterInfo.h" | ||
| #include "ARCSubtarget.h" | ||
| #include "llvm/ADT/Statistic.h" | ||
| #include "llvm/CodeGen/MachineFunctionPass.h" | ||
| #include "llvm/CodeGen/MachineInstrBuilder.h" | ||
| #include "llvm/CodeGen/MachineRegisterInfo.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| #define DEBUG_TYPE "arc-expand-pseudos" | ||
|
|
||
| namespace { | ||
|
|
||
| class ARCExpandPseudos : public MachineFunctionPass { | ||
| public: | ||
| static char ID; | ||
| ARCExpandPseudos() : MachineFunctionPass(ID) {} | ||
|
|
||
| bool runOnMachineFunction(MachineFunction &Fn) override; | ||
|
|
||
| StringRef getPassName() const override { return "ARC Expand Pseudos"; } | ||
|
|
||
| private: | ||
| void ExpandStore(MachineFunction &, MachineBasicBlock::iterator); | ||
|
|
||
| const ARCInstrInfo *TII; | ||
| }; | ||
|
|
||
| char ARCExpandPseudos::ID = 0; | ||
|
|
||
| } // end anonymous namespace | ||
|
|
||
| static unsigned getMappedOp(unsigned PseudoOp) { | ||
| switch (PseudoOp) { | ||
| case ARC::ST_FAR: | ||
| return ARC::ST_rs9; | ||
| case ARC::STH_FAR: | ||
| return ARC::STH_rs9; | ||
| case ARC::STB_FAR: | ||
| return ARC::STB_rs9; | ||
| default: | ||
| llvm_unreachable("Unhandled pseudo op."); | ||
| } | ||
| } | ||
|
|
||
| void ARCExpandPseudos::ExpandStore(MachineFunction &MF, | ||
| MachineBasicBlock::iterator SII) { | ||
| MachineInstr &SI = *SII; | ||
| unsigned AddrReg = MF.getRegInfo().createVirtualRegister(&ARC::GPR32RegClass); | ||
| unsigned AddOpc = | ||
| isUInt<6>(SI.getOperand(2).getImm()) ? ARC::ADD_rru6 : ARC::ADD_rrlimm; | ||
| BuildMI(*SI.getParent(), SI, SI.getDebugLoc(), TII->get(AddOpc), AddrReg) | ||
| .addReg(SI.getOperand(1).getReg()) | ||
| .addImm(SI.getOperand(2).getImm()); | ||
| BuildMI(*SI.getParent(), SI, SI.getDebugLoc(), | ||
| TII->get(getMappedOp(SI.getOpcode()))) | ||
| .addReg(SI.getOperand(0).getReg()) | ||
| .addReg(AddrReg) | ||
| .addImm(0); | ||
| SI.eraseFromParent(); | ||
| } | ||
|
|
||
| bool ARCExpandPseudos::runOnMachineFunction(MachineFunction &MF) { | ||
| const ARCSubtarget *STI = &MF.getSubtarget<ARCSubtarget>(); | ||
| TII = STI->getInstrInfo(); | ||
| bool ExpandedStore = false; | ||
| for (auto &MBB : MF) { | ||
| MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); | ||
| while (MBBI != E) { | ||
| MachineBasicBlock::iterator NMBBI = std::next(MBBI); | ||
| switch (MBBI->getOpcode()) { | ||
| case ARC::ST_FAR: | ||
| case ARC::STH_FAR: | ||
| case ARC::STB_FAR: | ||
| ExpandStore(MF, MBBI); | ||
| ExpandedStore = true; | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
| MBBI = NMBBI; | ||
| } | ||
| } | ||
| return ExpandedStore; | ||
| } | ||
|
|
||
| FunctionPass *llvm::createARCExpandPseudosPass() { | ||
| return new ARCExpandPseudos(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| //===- ARCFrameLowering.h - Define frame lowering for ARC -------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This class implements the ARC specific frame lowering. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_ARC_ARCFRAMELOWERING_H | ||
| #define LLVM_LIB_TARGET_ARC_ARCFRAMELOWERING_H | ||
|
|
||
| #include "ARC.h" | ||
| #include "llvm/CodeGen/MachineBasicBlock.h" | ||
| #include "llvm/CodeGen/MachineFrameInfo.h" | ||
| #include "llvm/Target/TargetFrameLowering.h" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class MachineFunction; | ||
| class ARCSubtarget; | ||
| class ARCInstrInfo; | ||
|
|
||
| class ARCFrameLowering : public TargetFrameLowering { | ||
| public: | ||
| ARCFrameLowering(const ARCSubtarget &st) | ||
| : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 4, 0), ST(st) { | ||
| } | ||
|
|
||
| /// Insert Prologue into the function. | ||
| void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override; | ||
|
|
||
| /// Insert Epilogue into the function. | ||
| void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; | ||
|
|
||
| /// Add explicit callee save registers. | ||
| void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, | ||
| RegScavenger *RS) const override; | ||
|
|
||
| bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator MI, | ||
| const std::vector<CalleeSavedInfo> &CSI, | ||
| const TargetRegisterInfo *TRI) const override; | ||
|
|
||
| bool | ||
| restoreCalleeSavedRegisters(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator MI, | ||
| std::vector<CalleeSavedInfo> &CSI, | ||
| const TargetRegisterInfo *TRI) const override; | ||
|
|
||
| void processFunctionBeforeFrameFinalized(MachineFunction &MF, | ||
| RegScavenger *RS) const override; | ||
|
|
||
| bool hasFP(const MachineFunction &MF) const override; | ||
|
|
||
| MachineBasicBlock::iterator | ||
| eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator I) const override; | ||
|
|
||
| bool assignCalleeSavedSpillSlots( | ||
| llvm::MachineFunction &, const llvm::TargetRegisterInfo *, | ||
| std::vector<llvm::CalleeSavedInfo> &) const override; | ||
|
|
||
| private: | ||
| void adjustStackToMatchRecords(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator MI, | ||
| bool allocate) const; | ||
|
|
||
| const ARCSubtarget &ST; | ||
| }; | ||
|
|
||
| } // end namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_ARC_ARCFRAMELOWERING_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,182 @@ | ||
| //===- 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/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" | ||
| #include "llvm/Target/TargetLowering.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); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| //===- ARCISelLowering.h - ARC DAG Lowering Interface -----------*- 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 the interfaces that ARC uses to lower LLVM code into a | ||
| // selection DAG. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_ARC_ARCISELLOWERING_H | ||
| #define LLVM_LIB_TARGET_ARC_ARCISELLOWERING_H | ||
|
|
||
| #include "ARC.h" | ||
| #include "llvm/CodeGen/SelectionDAG.h" | ||
| #include "llvm/Target/TargetLowering.h" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| // Forward delcarations | ||
| class ARCSubtarget; | ||
| class ARCTargetMachine; | ||
|
|
||
| namespace ARCISD { | ||
|
|
||
| enum NodeType : unsigned { | ||
| // Start the numbering where the builtin ops and target ops leave off. | ||
| FIRST_NUMBER = ISD::BUILTIN_OP_END, | ||
|
|
||
| // Branch and link (call) | ||
| BL, | ||
|
|
||
| // Jump and link (indirect call) | ||
| JL, | ||
|
|
||
| // CMP | ||
| CMP, | ||
|
|
||
| // CMOV | ||
| CMOV, | ||
|
|
||
| // BRcc | ||
| BRcc, | ||
|
|
||
| // Global Address Wrapper | ||
| GAWRAPPER, | ||
|
|
||
| // return, (j_s [blink]) | ||
| RET | ||
| }; | ||
|
|
||
| } // end namespace ARCISD | ||
|
|
||
| //===--------------------------------------------------------------------===// | ||
| // TargetLowering Implementation | ||
| //===--------------------------------------------------------------------===// | ||
| class ARCTargetLowering : public TargetLowering { | ||
| public: | ||
| explicit ARCTargetLowering(const TargetMachine &TM, | ||
| const ARCSubtarget &Subtarget); | ||
|
|
||
| /// Provide custom lowering hooks for some operations. | ||
| SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; | ||
|
|
||
| /// This method returns the name of a target specific DAG node. | ||
| const char *getTargetNodeName(unsigned Opcode) const override; | ||
|
|
||
| /// Return true if the addressing mode represented by AM is legal for this | ||
| /// target, for a load/store of the specified type. | ||
| bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, | ||
| unsigned AS, | ||
| Instruction *I = nullptr) const override; | ||
|
|
||
| private: | ||
| const TargetMachine &TM; | ||
| const ARCSubtarget &Subtarget; | ||
|
|
||
| // Lower Operand helpers | ||
| SDValue LowerCallArguments(SDValue Chain, CallingConv::ID CallConv, | ||
| bool isVarArg, | ||
| const SmallVectorImpl<ISD::InputArg> &Ins, | ||
| SDLoc dl, SelectionDAG &DAG, | ||
| SmallVectorImpl<SDValue> &InVals) const; | ||
| // Lower Operand specifics | ||
| SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerSIGN_EXTEND_INREG(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override; | ||
|
|
||
| SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, | ||
| bool isVarArg, | ||
| const SmallVectorImpl<ISD::InputArg> &Ins, | ||
| const SDLoc &dl, SelectionDAG &DAG, | ||
| SmallVectorImpl<SDValue> &InVals) const override; | ||
|
|
||
| SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, | ||
| SmallVectorImpl<SDValue> &InVals) const override; | ||
|
|
||
| SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, | ||
| const SmallVectorImpl<ISD::OutputArg> &Outs, | ||
| const SmallVectorImpl<SDValue> &OutVals, const SDLoc &dl, | ||
| SelectionDAG &DAG) const override; | ||
|
|
||
| bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, | ||
| bool isVarArg, | ||
| const SmallVectorImpl<ISD::OutputArg> &ArgsFlags, | ||
| LLVMContext &Context) const override; | ||
|
|
||
| bool mayBeEmittedAsTailCall(const CallInst *CI) const override; | ||
| }; | ||
|
|
||
| } // end namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_ARC_ARCISELLOWERING_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,394 @@ | ||
| //===- ARCInstrInfo.cpp - ARC Instruction Information -----------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file contains the ARC implementation of the TargetInstrInfo class. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "ARCInstrInfo.h" | ||
| #include "ARC.h" | ||
| #include "ARCMachineFunctionInfo.h" | ||
| #include "ARCSubtarget.h" | ||
| #include "MCTargetDesc/ARCInfo.h" | ||
| #include "llvm/CodeGen/MachineFrameInfo.h" | ||
| #include "llvm/CodeGen/MachineInstrBuilder.h" | ||
| #include "llvm/CodeGen/MachineMemOperand.h" | ||
| #include "llvm/Support/Debug.h" | ||
| #include "llvm/Support/TargetRegistry.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| #define GET_INSTRINFO_CTOR_DTOR | ||
| #include "ARCGenInstrInfo.inc" | ||
|
|
||
| #define DEBUG_TYPE "arc-inst-info" | ||
| // Pin the vtable to this file. | ||
| void ARCInstrInfo::anchor() {} | ||
|
|
||
| ARCInstrInfo::ARCInstrInfo() | ||
| : ARCGenInstrInfo(ARC::ADJCALLSTACKDOWN, ARC::ADJCALLSTACKUP), RI() {} | ||
|
|
||
| static bool isZeroImm(const MachineOperand &Op) { | ||
| return Op.isImm() && Op.getImm() == 0; | ||
| } | ||
|
|
||
| static bool isLoad(int Opcode) { | ||
| return Opcode == ARC::LD_rs9 || Opcode == ARC::LDH_rs9 || | ||
| Opcode == ARC::LDB_rs9; | ||
| } | ||
|
|
||
| static bool isStore(int Opcode) { | ||
| return Opcode == ARC::ST_rs9 || Opcode == ARC::STH_rs9 || | ||
| Opcode == ARC::STB_rs9; | ||
| } | ||
|
|
||
| /// If the specified machine instruction is a direct | ||
| /// load from a stack slot, return the virtual or physical register number of | ||
| /// the destination along with the FrameIndex of the loaded stack slot. If | ||
| /// not, return 0. This predicate must return 0 if the instruction has | ||
| /// any side effects other than loading from the stack slot. | ||
| unsigned ARCInstrInfo::isLoadFromStackSlot(const MachineInstr &MI, | ||
| int &FrameIndex) const { | ||
| int Opcode = MI.getOpcode(); | ||
| if (isLoad(Opcode)) { | ||
| if ((MI.getOperand(1).isFI()) && // is a stack slot | ||
| (MI.getOperand(2).isImm()) && // the imm is zero | ||
| (isZeroImm(MI.getOperand(2)))) { | ||
| FrameIndex = MI.getOperand(1).getIndex(); | ||
| return MI.getOperand(0).getReg(); | ||
| } | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
| /// If the specified machine instruction is a direct | ||
| /// store to a stack slot, return the virtual or physical register number of | ||
| /// the source reg along with the FrameIndex of the loaded stack slot. If | ||
| /// not, return 0. This predicate must return 0 if the instruction has | ||
| /// any side effects other than storing to the stack slot. | ||
| unsigned ARCInstrInfo::isStoreToStackSlot(const MachineInstr &MI, | ||
| int &FrameIndex) const { | ||
| int Opcode = MI.getOpcode(); | ||
| if (isStore(Opcode)) { | ||
| if ((MI.getOperand(1).isFI()) && // is a stack slot | ||
| (MI.getOperand(2).isImm()) && // the imm is zero | ||
| (isZeroImm(MI.getOperand(2)))) { | ||
| FrameIndex = MI.getOperand(1).getIndex(); | ||
| return MI.getOperand(0).getReg(); | ||
| } | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
| /// Return the inverse of passed condition, i.e. turning COND_E to COND_NE. | ||
| static ARCCC::CondCode GetOppositeBranchCondition(ARCCC::CondCode CC) { | ||
| switch (CC) { | ||
| default: | ||
| llvm_unreachable("Illegal condition code!"); | ||
| case ARCCC::EQ: | ||
| return ARCCC::NE; | ||
| case ARCCC::NE: | ||
| return ARCCC::EQ; | ||
| case ARCCC::LO: | ||
| return ARCCC::HS; | ||
| case ARCCC::HS: | ||
| return ARCCC::LO; | ||
| case ARCCC::GT: | ||
| return ARCCC::LE; | ||
| case ARCCC::GE: | ||
| return ARCCC::LT; | ||
| case ARCCC::LT: | ||
| return ARCCC::GE; | ||
| case ARCCC::LE: | ||
| return ARCCC::GT; | ||
| case ARCCC::HI: | ||
| return ARCCC::LS; | ||
| case ARCCC::LS: | ||
| return ARCCC::HI; | ||
| case ARCCC::NZ: | ||
| return ARCCC::Z; | ||
| case ARCCC::Z: | ||
| return ARCCC::NZ; | ||
| } | ||
| } | ||
|
|
||
| static bool isUncondBranchOpcode(int Opc) { return Opc == ARC::BR; } | ||
|
|
||
| static bool isCondBranchOpcode(int Opc) { | ||
| return Opc == ARC::BRcc_rr_p || Opc == ARC::BRcc_ru6_p; | ||
| } | ||
|
|
||
| static bool isJumpOpcode(int Opc) { return Opc == ARC::J; } | ||
|
|
||
| /// Analyze the branching code at the end of MBB, returning | ||
| /// true if it cannot be understood (e.g. it's a switch dispatch or isn't | ||
| /// implemented for a target). Upon success, this returns false and returns | ||
| /// with the following information in various cases: | ||
| /// | ||
| /// 1. If this block ends with no branches (it just falls through to its succ) | ||
| /// just return false, leaving TBB/FBB null. | ||
| /// 2. If this block ends with only an unconditional branch, it sets TBB to be | ||
| /// the destination block. | ||
| /// 3. If this block ends with a conditional branch and it falls through to a | ||
| /// successor block, it sets TBB to be the branch destination block and a | ||
| /// list of operands that evaluate the condition. These operands can be | ||
| /// passed to other TargetInstrInfo methods to create new branches. | ||
| /// 4. If this block ends with a conditional branch followed by an | ||
| /// unconditional branch, it returns the 'true' destination in TBB, the | ||
| /// 'false' destination in FBB, and a list of operands that evaluate the | ||
| /// condition. These operands can be passed to other TargetInstrInfo | ||
| /// methods to create new branches. | ||
| /// | ||
| /// Note that RemoveBranch and InsertBranch must be implemented to support | ||
| /// cases where this method returns success. | ||
| /// | ||
| /// If AllowModify is true, then this routine is allowed to modify the basic | ||
| /// block (e.g. delete instructions after the unconditional branch). | ||
|
|
||
| bool ARCInstrInfo::analyzeBranch(MachineBasicBlock &MBB, | ||
| MachineBasicBlock *&TBB, | ||
| MachineBasicBlock *&FBB, | ||
| SmallVectorImpl<MachineOperand> &Cond, | ||
| bool AllowModify) const { | ||
| TBB = FBB = nullptr; | ||
| MachineBasicBlock::iterator I = MBB.end(); | ||
| if (I == MBB.begin()) | ||
| return false; | ||
| --I; | ||
|
|
||
| while (isPredicated(*I) || I->isTerminator() || I->isDebugValue()) { | ||
| // Flag to be raised on unanalyzeable instructions. This is useful in cases | ||
| // where we want to clean up on the end of the basic block before we bail | ||
| // out. | ||
| bool CantAnalyze = false; | ||
|
|
||
| // Skip over DEBUG values and predicated nonterminators. | ||
| while (I->isDebugValue() || !I->isTerminator()) { | ||
| if (I == MBB.begin()) | ||
| return false; | ||
| --I; | ||
| } | ||
|
|
||
| if (isJumpOpcode(I->getOpcode())) { | ||
| // Indirect branches and jump tables can't be analyzed, but we still want | ||
| // to clean up any instructions at the tail of the basic block. | ||
| CantAnalyze = true; | ||
| } else if (isUncondBranchOpcode(I->getOpcode())) { | ||
| TBB = I->getOperand(0).getMBB(); | ||
| } else if (isCondBranchOpcode(I->getOpcode())) { | ||
| // Bail out if we encounter multiple conditional branches. | ||
| if (!Cond.empty()) | ||
| return true; | ||
|
|
||
| assert(!FBB && "FBB should have been null."); | ||
| FBB = TBB; | ||
| TBB = I->getOperand(0).getMBB(); | ||
| Cond.push_back(I->getOperand(1)); | ||
| Cond.push_back(I->getOperand(2)); | ||
| Cond.push_back(I->getOperand(3)); | ||
| } else if (I->isReturn()) { | ||
| // Returns can't be analyzed, but we should run cleanup. | ||
| CantAnalyze = !isPredicated(*I); | ||
| } else { | ||
| // We encountered other unrecognized terminator. Bail out immediately. | ||
| return true; | ||
| } | ||
|
|
||
| // Cleanup code - to be run for unpredicated unconditional branches and | ||
| // returns. | ||
| if (!isPredicated(*I) && (isUncondBranchOpcode(I->getOpcode()) || | ||
| isJumpOpcode(I->getOpcode()) || I->isReturn())) { | ||
| // Forget any previous condition branch information - it no longer | ||
| // applies. | ||
| Cond.clear(); | ||
| FBB = nullptr; | ||
|
|
||
| // If we can modify the function, delete everything below this | ||
| // unconditional branch. | ||
| if (AllowModify) { | ||
| MachineBasicBlock::iterator DI = std::next(I); | ||
| while (DI != MBB.end()) { | ||
| MachineInstr &InstToDelete = *DI; | ||
| ++DI; | ||
| InstToDelete.eraseFromParent(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (CantAnalyze) | ||
| return true; | ||
|
|
||
| if (I == MBB.begin()) | ||
| return false; | ||
|
|
||
| --I; | ||
| } | ||
|
|
||
| // We made it past the terminators without bailing out - we must have | ||
| // analyzed this branch successfully. | ||
| return false; | ||
| } | ||
|
|
||
| unsigned ARCInstrInfo::removeBranch(MachineBasicBlock &MBB, | ||
| int *BytesRemoved) const { | ||
| assert(!BytesRemoved && "Code size not handled"); | ||
| MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); | ||
| if (I == MBB.end()) | ||
| return 0; | ||
|
|
||
| if (!isUncondBranchOpcode(I->getOpcode()) && | ||
| !isCondBranchOpcode(I->getOpcode())) | ||
| return 0; | ||
|
|
||
| // Remove the branch. | ||
| I->eraseFromParent(); | ||
|
|
||
| I = MBB.end(); | ||
|
|
||
| if (I == MBB.begin()) | ||
| return 1; | ||
| --I; | ||
| if (!isCondBranchOpcode(I->getOpcode())) | ||
| return 1; | ||
|
|
||
| // Remove the branch. | ||
| I->eraseFromParent(); | ||
| return 2; | ||
| } | ||
|
|
||
| void ARCInstrInfo::copyPhysReg(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator I, | ||
| const DebugLoc &dl, unsigned DestReg, | ||
| unsigned SrcReg, bool KillSrc) const { | ||
| assert(ARC::GPR32RegClass.contains(SrcReg) && | ||
| "Only GPR32 src copy supported."); | ||
| assert(ARC::GPR32RegClass.contains(DestReg) && | ||
| "Only GPR32 dest copy supported."); | ||
| BuildMI(MBB, I, dl, get(ARC::MOV_rr), DestReg) | ||
| .addReg(SrcReg, getKillRegState(KillSrc)); | ||
| } | ||
|
|
||
| void ARCInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator I, | ||
| unsigned SrcReg, bool isKill, | ||
| int FrameIndex, | ||
| const TargetRegisterClass *RC, | ||
| const TargetRegisterInfo *TRI) const { | ||
| DebugLoc dl = MBB.findDebugLoc(I); | ||
| MachineFunction &MF = *MBB.getParent(); | ||
| MachineFrameInfo &MFI = MF.getFrameInfo(); | ||
| unsigned Align = MFI.getObjectAlignment(FrameIndex); | ||
|
|
||
| MachineMemOperand *MMO = MF.getMachineMemOperand( | ||
| MachinePointerInfo::getFixedStack(MF, FrameIndex), | ||
| MachineMemOperand::MOStore, MFI.getObjectSize(FrameIndex), Align); | ||
|
|
||
| assert(MMO && "Couldn't get MachineMemOperand for store to stack."); | ||
| assert(TRI->getSpillSize(*RC) == 4 && | ||
| "Only support 4-byte stores to stack now."); | ||
| assert(ARC::GPR32RegClass.hasSubClassEq(RC) && | ||
| "Only support GPR32 stores to stack now."); | ||
| DEBUG(dbgs() << "Created store reg=" << PrintReg(SrcReg, TRI) | ||
| << " to FrameIndex=" << FrameIndex << "\n"); | ||
| BuildMI(MBB, I, dl, get(ARC::ST_rs9)) | ||
| .addReg(SrcReg, getKillRegState(isKill)) | ||
| .addFrameIndex(FrameIndex) | ||
| .addImm(0) | ||
| .addMemOperand(MMO); | ||
| } | ||
|
|
||
| void ARCInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator I, | ||
| unsigned DestReg, int FrameIndex, | ||
| const TargetRegisterClass *RC, | ||
| const TargetRegisterInfo *TRI) const { | ||
| DebugLoc dl = MBB.findDebugLoc(I); | ||
| MachineFunction &MF = *MBB.getParent(); | ||
| MachineFrameInfo &MFI = MF.getFrameInfo(); | ||
| unsigned Align = MFI.getObjectAlignment(FrameIndex); | ||
| MachineMemOperand *MMO = MF.getMachineMemOperand( | ||
| MachinePointerInfo::getFixedStack(MF, FrameIndex), | ||
| MachineMemOperand::MOLoad, MFI.getObjectSize(FrameIndex), Align); | ||
|
|
||
| assert(MMO && "Couldn't get MachineMemOperand for store to stack."); | ||
| assert(TRI->getSpillSize(*RC) == 4 && | ||
| "Only support 4-byte loads from stack now."); | ||
| assert(ARC::GPR32RegClass.hasSubClassEq(RC) && | ||
| "Only support GPR32 stores to stack now."); | ||
| DEBUG(dbgs() << "Created load reg=" << PrintReg(DestReg, TRI) | ||
| << " from FrameIndex=" << FrameIndex << "\n"); | ||
| BuildMI(MBB, I, dl, get(ARC::LD_rs9)) | ||
| .addReg(DestReg, RegState::Define) | ||
| .addFrameIndex(FrameIndex) | ||
| .addImm(0) | ||
| .addMemOperand(MMO); | ||
| } | ||
|
|
||
| /// Return the inverse opcode of the specified Branch instruction. | ||
| bool ARCInstrInfo::reverseBranchCondition( | ||
| SmallVectorImpl<MachineOperand> &Cond) const { | ||
| assert((Cond.size() == 3) && "Invalid ARC branch condition!"); | ||
| Cond[2].setImm(GetOppositeBranchCondition((ARCCC::CondCode)Cond[2].getImm())); | ||
| return false; | ||
| } | ||
|
|
||
| MachineBasicBlock::iterator | ||
| ARCInstrInfo::loadImmediate(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator MI, unsigned Reg, | ||
| uint64_t Value) const { | ||
| DebugLoc dl = MBB.findDebugLoc(MI); | ||
| if (isInt<12>(Value)) { | ||
| return BuildMI(MBB, MI, dl, get(ARC::MOV_rs12), Reg) | ||
| .addImm(Value) | ||
| .getInstr(); | ||
| } | ||
| llvm_unreachable("Need Arc long immediate instructions."); | ||
| } | ||
|
|
||
| unsigned ARCInstrInfo::insertBranch(MachineBasicBlock &MBB, | ||
| MachineBasicBlock *TBB, | ||
| MachineBasicBlock *FBB, | ||
| ArrayRef<MachineOperand> Cond, | ||
| const DebugLoc &dl, int *BytesAdded) const { | ||
| assert(!BytesAdded && "Code size not handled."); | ||
|
|
||
| // Shouldn't be a fall through. | ||
| assert(TBB && "InsertBranch must not be told to insert a fallthrough"); | ||
| assert((Cond.size() == 3 || Cond.size() == 0) && | ||
| "ARC branch conditions have two components!"); | ||
|
|
||
| if (Cond.empty()) { | ||
| BuildMI(&MBB, dl, get(ARC::BR)).addMBB(TBB); | ||
| return 1; | ||
| } | ||
| int BccOpc = Cond[1].isImm() ? ARC::BRcc_ru6_p : ARC::BRcc_rr_p; | ||
| MachineInstrBuilder MIB = BuildMI(&MBB, dl, get(BccOpc)); | ||
| MIB.addMBB(TBB); | ||
| for (unsigned i = 0; i < 3; i++) { | ||
| MIB.add(Cond[i]); | ||
| } | ||
|
|
||
| // One-way conditional branch. | ||
| if (!FBB) { | ||
| return 1; | ||
| } | ||
|
|
||
| // Two-way conditional branch. | ||
| BuildMI(&MBB, dl, get(ARC::BR)).addMBB(FBB); | ||
| return 2; | ||
| } | ||
|
|
||
| unsigned ARCInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { | ||
| if (MI.getOpcode() == TargetOpcode::INLINEASM) { | ||
| const MachineFunction *MF = MI.getParent()->getParent(); | ||
| const char *AsmStr = MI.getOperand(0).getSymbolName(); | ||
| return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo()); | ||
| } | ||
| return MI.getDesc().getSize(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| //===- ARCInstrInfo.h - ARC Instruction Information -------------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file contains the ARC implementation of the TargetInstrInfo class. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_ARC_ARCINSTRINFO_H | ||
| #define LLVM_LIB_TARGET_ARC_ARCINSTRINFO_H | ||
|
|
||
| #include "ARCRegisterInfo.h" | ||
| #include "llvm/Target/TargetInstrInfo.h" | ||
|
|
||
| #define GET_INSTRINFO_HEADER | ||
| #include "ARCGenInstrInfo.inc" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class ARCSubtarget; | ||
|
|
||
| class ARCInstrInfo : public ARCGenInstrInfo { | ||
| const ARCRegisterInfo RI; | ||
| virtual void anchor(); | ||
|
|
||
| public: | ||
| ARCInstrInfo(); | ||
|
|
||
| const ARCRegisterInfo &getRegisterInfo() const { return RI; } | ||
|
|
||
| /// If the specified machine instruction is a direct | ||
| /// load from a stack slot, return the virtual or physical register number of | ||
| /// the destination along with the FrameIndex of the loaded stack slot. If | ||
| /// not, return 0. This predicate must return 0 if the instruction has | ||
| /// any side effects other than loading from the stack slot. | ||
| unsigned isLoadFromStackSlot(const MachineInstr &MI, | ||
| int &FrameIndex) const override; | ||
|
|
||
| /// If the specified machine instruction is a direct | ||
| /// store to a stack slot, return the virtual or physical register number of | ||
| /// the source reg along with the FrameIndex of the loaded stack slot. If | ||
| /// not, return 0. This predicate must return 0 if the instruction has | ||
| /// any side effects other than storing to the stack slot. | ||
| unsigned isStoreToStackSlot(const MachineInstr &MI, | ||
| int &FrameIndex) const override; | ||
|
|
||
| unsigned getInstSizeInBytes(const MachineInstr &MI) const override; | ||
|
|
||
| bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, | ||
| MachineBasicBlock *&FBB, | ||
| SmallVectorImpl<MachineOperand> &Cond, | ||
| bool AllowModify) const override; | ||
|
|
||
| unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, | ||
| MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond, | ||
| const DebugLoc &dl, | ||
| int *BytesAdded = nullptr) const override; | ||
|
|
||
| unsigned removeBranch(MachineBasicBlock &MBB, | ||
| int *BytesRemoved = nullptr) const override; | ||
|
|
||
| void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, | ||
| const DebugLoc &dl, unsigned DestReg, unsigned SrcReg, | ||
| bool KillSrc) const override; | ||
|
|
||
| void storeRegToStackSlot(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator MI, unsigned SrcReg, | ||
| bool isKill, int FrameIndex, | ||
| const TargetRegisterClass *RC, | ||
| const TargetRegisterInfo *TRI) const override; | ||
|
|
||
| void loadRegFromStackSlot(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator MI, unsigned DestReg, | ||
| int FrameIndex, const TargetRegisterClass *RC, | ||
| const TargetRegisterInfo *TRI) const override; | ||
|
|
||
| bool | ||
| reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override; | ||
|
|
||
| // Emit code before MBBI to load immediate value into physical register Reg. | ||
| // Returns an iterator to the new instruction. | ||
| MachineBasicBlock::iterator loadImmediate(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator MI, | ||
| unsigned Reg, uint64_t Value) const; | ||
| }; | ||
|
|
||
| } // end namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_ARC_ARCINSTRINFO_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| //===- ARCMCInstLower.cpp - ARC MachineInstr to MCInst ----------*- C++ -*-===// | ||
| // | ||
| // 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 contains code to lower ARC MachineInstrs to their | ||
| /// corresponding MCInst records. | ||
| /// | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "ARCMCInstLower.h" | ||
| #include "llvm/CodeGen/AsmPrinter.h" | ||
| #include "llvm/CodeGen/MachineFunction.h" | ||
| #include "llvm/CodeGen/MachineInstr.h" | ||
| #include "llvm/CodeGen/MachineOperand.h" | ||
| #include "llvm/MC/MCContext.h" | ||
| #include "llvm/MC/MCExpr.h" | ||
| #include "llvm/MC/MCInst.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| ARCMCInstLower::ARCMCInstLower(MCContext *C, AsmPrinter &AsmPrinter) | ||
| : Ctx(C), Printer(AsmPrinter) {} | ||
|
|
||
| MCOperand ARCMCInstLower::LowerSymbolOperand(const MachineOperand &MO, | ||
| MachineOperandType MOTy, | ||
| unsigned Offset) const { | ||
| MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None; | ||
| const MCSymbol *Symbol; | ||
|
|
||
| switch (MOTy) { | ||
| case MachineOperand::MO_MachineBasicBlock: | ||
| Symbol = MO.getMBB()->getSymbol(); | ||
| break; | ||
| case MachineOperand::MO_GlobalAddress: | ||
| Symbol = Printer.getSymbol(MO.getGlobal()); | ||
| Offset += MO.getOffset(); | ||
| break; | ||
| case MachineOperand::MO_BlockAddress: | ||
| Symbol = Printer.GetBlockAddressSymbol(MO.getBlockAddress()); | ||
| Offset += MO.getOffset(); | ||
| break; | ||
| case MachineOperand::MO_ExternalSymbol: | ||
| Symbol = Printer.GetExternalSymbolSymbol(MO.getSymbolName()); | ||
| Offset += MO.getOffset(); | ||
| break; | ||
| case MachineOperand::MO_JumpTableIndex: | ||
| Symbol = Printer.GetJTISymbol(MO.getIndex()); | ||
| break; | ||
| case MachineOperand::MO_ConstantPoolIndex: | ||
| Symbol = Printer.GetCPISymbol(MO.getIndex()); | ||
| Offset += MO.getOffset(); | ||
| break; | ||
| default: | ||
| llvm_unreachable("<unknown operand type>"); | ||
| } | ||
|
|
||
| assert(Symbol && "Symbol creation failed.\n"); | ||
| const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Symbol, Kind, *Ctx); | ||
|
|
||
| if (!Offset) | ||
| return MCOperand::createExpr(MCSym); | ||
|
|
||
| // Assume offset is never negative. | ||
| assert(Offset > 0); | ||
|
|
||
| const MCConstantExpr *OffsetExpr = MCConstantExpr::create(Offset, *Ctx); | ||
| const MCBinaryExpr *Add = MCBinaryExpr::createAdd(MCSym, OffsetExpr, *Ctx); | ||
| return MCOperand::createExpr(Add); | ||
| } | ||
|
|
||
| MCOperand ARCMCInstLower::LowerOperand(const MachineOperand &MO, | ||
| unsigned Offset) const { | ||
| MachineOperandType MOTy = MO.getType(); | ||
|
|
||
| switch (MOTy) { | ||
| default: | ||
| llvm_unreachable("unknown operand type"); | ||
| case MachineOperand::MO_Register: | ||
| // Ignore all implicit register operands. | ||
| if (MO.isImplicit()) | ||
| break; | ||
| return MCOperand::createReg(MO.getReg()); | ||
| case MachineOperand::MO_Immediate: | ||
| return MCOperand::createImm(MO.getImm() + Offset); | ||
| case MachineOperand::MO_MachineBasicBlock: | ||
| case MachineOperand::MO_GlobalAddress: | ||
| case MachineOperand::MO_ExternalSymbol: | ||
| case MachineOperand::MO_JumpTableIndex: | ||
| case MachineOperand::MO_ConstantPoolIndex: | ||
| case MachineOperand::MO_BlockAddress: | ||
| return LowerSymbolOperand(MO, MOTy, Offset); | ||
| case MachineOperand::MO_RegisterMask: | ||
| break; | ||
| } | ||
|
|
||
| return {}; | ||
| } | ||
|
|
||
| void ARCMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { | ||
| OutMI.setOpcode(MI->getOpcode()); | ||
|
|
||
| for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { | ||
| const MachineOperand &MO = MI->getOperand(i); | ||
| MCOperand MCOp = LowerOperand(MO); | ||
|
|
||
| if (MCOp.isValid()) | ||
| OutMI.addOperand(MCOp); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| //===- ARCMCInstLower.h - Lower MachineInstr to MCInst ----------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_ARC_ARCMCINSTLOWER_H | ||
| #define LLVM_LIB_TARGET_ARC_ARCMCINSTLOWER_H | ||
|
|
||
| #include "llvm/CodeGen/MachineOperand.h" | ||
| #include "llvm/Support/Compiler.h" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class MCContext; | ||
| class MCInst; | ||
| class MCOperand; | ||
| class MachineInstr; | ||
| class MachineFunction; | ||
| class Mangler; | ||
| class AsmPrinter; | ||
|
|
||
| /// \brief This class is used to lower an MachineInstr into an MCInst. | ||
| class LLVM_LIBRARY_VISIBILITY ARCMCInstLower { | ||
| using MachineOperandType = MachineOperand::MachineOperandType; | ||
| MCContext *Ctx; | ||
| AsmPrinter &Printer; | ||
|
|
||
| public: | ||
| ARCMCInstLower(MCContext *C, AsmPrinter &asmprinter); | ||
| void Lower(const MachineInstr *MI, MCInst &OutMI) const; | ||
| MCOperand LowerOperand(const MachineOperand &MO, unsigned offset = 0) const; | ||
|
|
||
| private: | ||
| MCOperand LowerSymbolOperand(const MachineOperand &MO, | ||
| MachineOperandType MOTy, unsigned Offset) const; | ||
| }; | ||
|
|
||
| } // end namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_ARC_ARCMCINSTLOWER_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| //===- ARCMachineFunctionInfo.cpp - ARC machine func info -------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "ARCMachineFunctionInfo.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| void ARCFunctionInfo::anchor() {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| //===- ARCMachineFunctionInfo.h - ARC machine function info -----*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file declares ARC-specific per-machine-function information. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_ARC_ARCMACHINEFUNCTIONINFO_H | ||
| #define LLVM_LIB_TARGET_ARC_ARCMACHINEFUNCTIONINFO_H | ||
|
|
||
| #include "llvm/CodeGen/MachineFunction.h" | ||
| #include <vector> | ||
|
|
||
| namespace llvm { | ||
|
|
||
| /// ARCFunctionInfo - This class is derived from MachineFunction private | ||
| /// ARC target-specific information for each MachineFunction. | ||
| class ARCFunctionInfo : public MachineFunctionInfo { | ||
| virtual void anchor(); | ||
| bool ReturnStackOffsetSet; | ||
| int VarArgsFrameIndex; | ||
| unsigned VarArgFrameBytes; | ||
| unsigned ReturnStackOffset; | ||
|
|
||
| public: | ||
| ARCFunctionInfo() | ||
| : ReturnStackOffsetSet(false), VarArgsFrameIndex(0), VarArgFrameBytes(0), | ||
| ReturnStackOffset(-1U), MaxCallStackReq(0) {} | ||
|
|
||
| explicit ARCFunctionInfo(MachineFunction &MF) | ||
| : ReturnStackOffsetSet(false), VarArgsFrameIndex(0), VarArgFrameBytes(0), | ||
| ReturnStackOffset(-1U), MaxCallStackReq(0) { | ||
| // Functions are 4-byte (2**2) aligned. | ||
| MF.setAlignment(2); | ||
| } | ||
|
|
||
| ~ARCFunctionInfo() {} | ||
|
|
||
| void setVarArgsFrameIndex(int off) { VarArgsFrameIndex = off; } | ||
| int getVarArgsFrameIndex() const { return VarArgsFrameIndex; } | ||
|
|
||
| void setReturnStackOffset(unsigned value) { | ||
| assert(!ReturnStackOffsetSet && "Return stack offset set twice"); | ||
| ReturnStackOffset = value; | ||
| ReturnStackOffsetSet = true; | ||
| } | ||
|
|
||
| unsigned getReturnStackOffset() const { | ||
| assert(ReturnStackOffsetSet && "Return stack offset not set"); | ||
| return ReturnStackOffset; | ||
| } | ||
|
|
||
| unsigned MaxCallStackReq; | ||
| }; | ||
|
|
||
| } // end namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_ARC_ARCMACHINEFUNCTIONINFO_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,233 @@ | ||
| //===- ARCRegisterInfo.cpp - ARC Register Information -----------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file contains the ARC implementation of the MRegisterInfo class. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "ARCRegisterInfo.h" | ||
| #include "ARC.h" | ||
| #include "ARCInstrInfo.h" | ||
| #include "ARCMachineFunctionInfo.h" | ||
| #include "ARCSubtarget.h" | ||
| #include "llvm/ADT/BitVector.h" | ||
| #include "llvm/CodeGen/MachineFrameInfo.h" | ||
| #include "llvm/CodeGen/MachineFunction.h" | ||
| #include "llvm/CodeGen/MachineInstrBuilder.h" | ||
| #include "llvm/CodeGen/MachineModuleInfo.h" | ||
| #include "llvm/CodeGen/MachineRegisterInfo.h" | ||
| #include "llvm/CodeGen/RegisterScavenging.h" | ||
| #include "llvm/IR/Function.h" | ||
| #include "llvm/Support/Debug.h" | ||
| #include "llvm/Target/TargetFrameLowering.h" | ||
| #include "llvm/Target/TargetMachine.h" | ||
| #include "llvm/Target/TargetOptions.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| #define DEBUG_TYPE "arc-reg-info" | ||
|
|
||
| #define GET_REGINFO_TARGET_DESC | ||
| #include "ARCGenRegisterInfo.inc" | ||
|
|
||
| static void ReplaceFrameIndex(MachineBasicBlock::iterator II, | ||
| const ARCInstrInfo &TII, unsigned Reg, | ||
| unsigned FrameReg, int Offset, int StackSize, | ||
| int ObjSize, RegScavenger *RS, int SPAdj) { | ||
| assert(RS && "Need register scavenger."); | ||
| MachineInstr &MI = *II; | ||
| MachineBasicBlock &MBB = *MI.getParent(); | ||
| DebugLoc dl = MI.getDebugLoc(); | ||
| unsigned BaseReg = FrameReg; | ||
| unsigned KillState = 0; | ||
| if (MI.getOpcode() == ARC::LD_rs9 && (Offset >= 256 || Offset < -256)) { | ||
| // Loads can always be reached with LD_rlimm. | ||
| BuildMI(MBB, II, dl, TII.get(ARC::LD_rlimm), Reg) | ||
| .addReg(BaseReg) | ||
| .addImm(Offset) | ||
| .addMemOperand(*MI.memoperands_begin()); | ||
| MBB.erase(II); | ||
| return; | ||
| } | ||
|
|
||
| if (MI.getOpcode() != ARC::GETFI && (Offset >= 256 || Offset < -256)) { | ||
| // We need to use a scratch register to reach the far-away frame indexes. | ||
| BaseReg = RS->FindUnusedReg(&ARC::GPR32RegClass); | ||
| if (!BaseReg) { | ||
| // We can be sure that the scavenged-register slot is within the range | ||
| // of the load offset. | ||
| const TargetRegisterInfo *TRI = | ||
| MBB.getParent()->getSubtarget().getRegisterInfo(); | ||
| BaseReg = RS->scavengeRegister(&ARC::GPR32RegClass, II, SPAdj); | ||
| assert(BaseReg && "Register scavenging failed."); | ||
| DEBUG(dbgs() << "Scavenged register " << PrintReg(BaseReg, TRI) | ||
| << " for FrameReg=" << PrintReg(FrameReg, TRI) | ||
| << "+Offset=" << Offset << "\n"); | ||
| (void)TRI; | ||
| RS->setRegUsed(BaseReg); | ||
| } | ||
| unsigned AddOpc = isUInt<6>(Offset) ? ARC::ADD_rru6 : ARC::ADD_rrlimm; | ||
| BuildMI(MBB, II, dl, TII.get(AddOpc)) | ||
| .addReg(BaseReg, RegState::Define) | ||
| .addReg(FrameReg) | ||
| .addImm(Offset); | ||
| Offset = 0; | ||
| KillState = RegState::Kill; | ||
| } | ||
| switch (MI.getOpcode()) { | ||
| case ARC::LD_rs9: | ||
| assert((Offset % 4 == 0) && "LD needs 4 byte alignment."); | ||
| case ARC::LDH_rs9: | ||
| case ARC::LDH_X_rs9: | ||
| assert((Offset % 2 == 0) && "LDH needs 2 byte alignment."); | ||
| case ARC::LDB_rs9: | ||
| case ARC::LDB_X_rs9: | ||
| DEBUG(dbgs() << "Building LDFI\n"); | ||
| BuildMI(MBB, II, dl, TII.get(MI.getOpcode()), Reg) | ||
| .addReg(BaseReg, KillState) | ||
| .addImm(Offset) | ||
| .addMemOperand(*MI.memoperands_begin()); | ||
| break; | ||
| case ARC::ST_rs9: | ||
| assert((Offset % 4 == 0) && "ST needs 4 byte alignment."); | ||
| case ARC::STH_rs9: | ||
| assert((Offset % 2 == 0) && "STH needs 2 byte alignment."); | ||
| case ARC::STB_rs9: | ||
| DEBUG(dbgs() << "Building STFI\n"); | ||
| BuildMI(MBB, II, dl, TII.get(MI.getOpcode())) | ||
| .addReg(Reg, getKillRegState(MI.getOperand(0).isKill())) | ||
| .addReg(BaseReg, KillState) | ||
| .addImm(Offset) | ||
| .addMemOperand(*MI.memoperands_begin()); | ||
| break; | ||
| case ARC::GETFI: | ||
| DEBUG(dbgs() << "Building GETFI\n"); | ||
| BuildMI(MBB, II, dl, | ||
| TII.get(isUInt<6>(Offset) ? ARC::ADD_rru6 : ARC::ADD_rrlimm)) | ||
| .addReg(Reg, RegState::Define) | ||
| .addReg(FrameReg) | ||
| .addImm(Offset); | ||
| break; | ||
| default: | ||
| llvm_unreachable("Unhandled opcode."); | ||
| } | ||
|
|
||
| // Erase old instruction. | ||
| MBB.erase(II); | ||
| } | ||
|
|
||
| ARCRegisterInfo::ARCRegisterInfo() : ARCGenRegisterInfo(ARC::BLINK) {} | ||
|
|
||
| bool ARCRegisterInfo::needsFrameMoves(const MachineFunction &MF) { | ||
| return MF.getMMI().hasDebugInfo() || | ||
| MF.getFunction()->needsUnwindTableEntry(); | ||
| } | ||
|
|
||
| const MCPhysReg * | ||
| ARCRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { | ||
| return CSR_ARC_SaveList; | ||
| } | ||
|
|
||
| BitVector ARCRegisterInfo::getReservedRegs(const MachineFunction &MF) const { | ||
| BitVector Reserved(getNumRegs()); | ||
|
|
||
| Reserved.set(ARC::ILINK); | ||
| Reserved.set(ARC::SP); | ||
| Reserved.set(ARC::GP); | ||
| Reserved.set(ARC::R25); | ||
| Reserved.set(ARC::BLINK); | ||
| Reserved.set(ARC::FP); | ||
| return Reserved; | ||
| } | ||
|
|
||
| bool ARCRegisterInfo::requiresRegisterScavenging( | ||
| const MachineFunction &MF) const { | ||
| return true; | ||
| } | ||
|
|
||
| bool ARCRegisterInfo::trackLivenessAfterRegAlloc( | ||
| const MachineFunction &MF) const { | ||
| return true; | ||
| } | ||
|
|
||
| bool ARCRegisterInfo::useFPForScavengingIndex(const MachineFunction &MF) const { | ||
| return true; | ||
| } | ||
|
|
||
| void ARCRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, | ||
| int SPAdj, unsigned FIOperandNum, | ||
| RegScavenger *RS) const { | ||
| assert(SPAdj == 0 && "Unexpected"); | ||
| MachineInstr &MI = *II; | ||
| MachineOperand &FrameOp = MI.getOperand(FIOperandNum); | ||
| int FrameIndex = FrameOp.getIndex(); | ||
|
|
||
| MachineFunction &MF = *MI.getParent()->getParent(); | ||
| const ARCInstrInfo &TII = *MF.getSubtarget<ARCSubtarget>().getInstrInfo(); | ||
| const ARCFrameLowering *TFI = getFrameLowering(MF); | ||
| int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex); | ||
| int ObjSize = MF.getFrameInfo().getObjectSize(FrameIndex); | ||
| int StackSize = MF.getFrameInfo().getStackSize(); | ||
| int LocalFrameSize = MF.getFrameInfo().getLocalFrameSize(); | ||
|
|
||
| DEBUG(dbgs() << "\nFunction : " << MF.getName() << "\n"); | ||
| DEBUG(dbgs() << "<--------->\n"); | ||
| DEBUG(dbgs() << MI << "\n"); | ||
| DEBUG(dbgs() << "FrameIndex : " << FrameIndex << "\n"); | ||
| DEBUG(dbgs() << "ObjSize : " << ObjSize << "\n"); | ||
| DEBUG(dbgs() << "FrameOffset : " << Offset << "\n"); | ||
| DEBUG(dbgs() << "StackSize : " << StackSize << "\n"); | ||
| DEBUG(dbgs() << "LocalFrameSize : " << LocalFrameSize << "\n"); | ||
| (void)LocalFrameSize; | ||
|
|
||
| // Special handling of DBG_VALUE instructions. | ||
| if (MI.isDebugValue()) { | ||
| unsigned FrameReg = getFrameRegister(MF); | ||
| MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false /*isDef*/); | ||
| MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); | ||
| return; | ||
| } | ||
|
|
||
| // fold constant into offset. | ||
| Offset += MI.getOperand(FIOperandNum + 1).getImm(); | ||
|
|
||
| // TODO: assert based on the load type: | ||
| // ldb needs no alignment, | ||
| // ldh needs 2 byte alignment | ||
| // ld needs 4 byte alignment | ||
| DEBUG(dbgs() << "Offset : " << Offset << "\n" | ||
| << "<--------->\n"); | ||
|
|
||
| unsigned Reg = MI.getOperand(0).getReg(); | ||
| assert(ARC::GPR32RegClass.contains(Reg) && "Unexpected register operand"); | ||
|
|
||
| if (!TFI->hasFP(MF)) { | ||
| Offset = StackSize + Offset; | ||
| if (FrameIndex >= 0) | ||
| assert((Offset >= 0 && Offset < StackSize) && "SP Offset not in bounds."); | ||
| } else { | ||
| if (FrameIndex >= 0) { | ||
| assert((Offset < 0 && -Offset <= StackSize) && | ||
| "FP Offset not in bounds."); | ||
| } | ||
| } | ||
| ReplaceFrameIndex(II, TII, Reg, getFrameRegister(MF), Offset, StackSize, | ||
| ObjSize, RS, SPAdj); | ||
| } | ||
|
|
||
| unsigned ARCRegisterInfo::getFrameRegister(const MachineFunction &MF) const { | ||
| const ARCFrameLowering *TFI = getFrameLowering(MF); | ||
| return TFI->hasFP(MF) ? ARC::FP : ARC::SP; | ||
| } | ||
|
|
||
| const uint32_t * | ||
| ARCRegisterInfo::getCallPreservedMask(const MachineFunction &MF, | ||
| CallingConv::ID CC) const { | ||
| return CSR_ARC_RegMask; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| //===- ARCRegisterInfo.h - ARC Register Information Impl --------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file contains the ARC implementation of the MRegisterInfo class. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_ARC_ARCREGISTERINFO_H | ||
| #define LLVM_LIB_TARGET_ARC_ARCREGISTERINFO_H | ||
|
|
||
| #include "llvm/Target/TargetRegisterInfo.h" | ||
|
|
||
| #define GET_REGINFO_HEADER | ||
| #include "ARCGenRegisterInfo.inc" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class TargetInstrInfo; | ||
|
|
||
| struct ARCRegisterInfo : public ARCGenRegisterInfo { | ||
| public: | ||
| ARCRegisterInfo(); | ||
|
|
||
| /// Code Generation virtual methods... | ||
|
|
||
| const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override; | ||
|
|
||
| BitVector getReservedRegs(const MachineFunction &MF) const override; | ||
|
|
||
| bool requiresRegisterScavenging(const MachineFunction &MF) const override; | ||
|
|
||
| bool trackLivenessAfterRegAlloc(const MachineFunction &MF) const override; | ||
|
|
||
| bool useFPForScavengingIndex(const MachineFunction &MF) const override; | ||
|
|
||
| void eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, | ||
| unsigned FIOperandNum, | ||
| RegScavenger *RS = nullptr) const override; | ||
|
|
||
| const uint32_t *getCallPreservedMask(const MachineFunction &MF, | ||
| CallingConv::ID CC) const override; | ||
|
|
||
| // Debug information queries. | ||
| unsigned getFrameRegister(const MachineFunction &MF) const override; | ||
|
|
||
| //! Return whether to emit frame moves | ||
| static bool needsFrameMoves(const MachineFunction &MF); | ||
| }; | ||
|
|
||
| } // end namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_ARC_ARCREGISTERINFO_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| //===- ARCRegisterInfo.td - ARC Register defs --------------*- tablegen -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // Declarations that describe the ARC register file | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| class ARCReg<string n, list<string> altNames> : Register<n, altNames> { | ||
| field bits<6> HwEncoding; | ||
| let Namespace = "ARC"; | ||
| } | ||
|
|
||
| // Registers are identified with 6-bit ID numbers. | ||
| // Core - 32-bit core registers | ||
| class Core<int num, string n, list<string>altNames=[]> : ARCReg<n, altNames> { | ||
| let HWEncoding = num; | ||
| } | ||
|
|
||
| class Status<string n> : ARCReg<n, []> { | ||
| } | ||
|
|
||
| // Integer registers | ||
| def R0 : Core< 0, "%r0">, DwarfRegNum<[0]>; | ||
| def R1 : Core< 1, "%r1">, DwarfRegNum<[1]>; | ||
| def R2 : Core< 2, "%r2">, DwarfRegNum<[2]>; | ||
| def R3 : Core< 3, "%r3">, DwarfRegNum<[3]>; | ||
| let CostPerUse=1 in { | ||
| def R4 : Core< 4, "%r4">, DwarfRegNum<[4]>; | ||
| def R5 : Core< 5, "%r5">, DwarfRegNum<[5]>; | ||
| def R6 : Core< 6, "%r6">, DwarfRegNum<[6]>; | ||
| def R7 : Core< 7, "%r7">, DwarfRegNum<[7]>; | ||
| def R8 : Core< 8, "%r8">, DwarfRegNum<[8]>; | ||
| def R9 : Core< 9, "%r9">, DwarfRegNum<[9]>; | ||
| def R10 : Core<10, "%r10">, DwarfRegNum<[10]>; | ||
| def R11 : Core<11, "%r11">, DwarfRegNum<[11]>; | ||
| } | ||
| def R12 : Core<12, "%r12">, DwarfRegNum<[12]>; | ||
| def R13 : Core<13, "%r13">, DwarfRegNum<[13]>; | ||
| def R14 : Core<14, "%r14">, DwarfRegNum<[14]>; | ||
| def R15 : Core<15, "%r15">, DwarfRegNum<[15]>; | ||
|
|
||
| let CostPerUse=1 in { | ||
| def R16 : Core<16, "%r16">, DwarfRegNum<[16]>; | ||
| def R17 : Core<17, "%r17">, DwarfRegNum<[17]>; | ||
| def R18 : Core<18, "%r18">, DwarfRegNum<[18]>; | ||
| def R19 : Core<19, "%r19">, DwarfRegNum<[19]>; | ||
| def R20 : Core<20, "%r20">, DwarfRegNum<[20]>; | ||
| def R21 : Core<21, "%r21">, DwarfRegNum<[21]>; | ||
| def R22 : Core<22, "%r22">, DwarfRegNum<[22]>; | ||
| def R23 : Core<23, "%r23">, DwarfRegNum<[23]>; | ||
| def R24 : Core<24, "%r24">, DwarfRegNum<[24]>; | ||
| def R25 : Core<25, "%r25">, DwarfRegNum<[25]>; | ||
| def GP : Core<26, "%gp",["%r26"]>, DwarfRegNum<[26]>; | ||
| def FP : Core<27, "%fp", ["%r27"]>, DwarfRegNum<[27]>; | ||
| def SP : Core<28, "%sp", ["%r28"]>, DwarfRegNum<[28]>; | ||
| def ILINK : Core<29, "%ilink">, DwarfRegNum<[29]>; | ||
| def R30 : Core<30, "%r30">, DwarfRegNum<[30]>; | ||
| def BLINK: Core<31, "%blink">, DwarfRegNum<[31]>; | ||
|
|
||
| def STATUS32 : Status<"status32">, DwarfRegNum<[32]>; | ||
| } | ||
|
|
||
| // Register classes. | ||
| // | ||
| def GPR32: RegisterClass<"ARC", [i32], 32, | ||
| (add R0, R1, R2, R3, | ||
| R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19, | ||
| R20, R21, R22, R23, R24, R25, GP, FP, SP, ILINK, R30, BLINK)>; | ||
|
|
||
| def SREG : RegisterClass<"ARC", [i32], 1, (add STATUS32)>; | ||
|
|
||
| def GPR_S : RegisterClass<"ARC", [i32], 8, | ||
| (add R0, R1, R2, R3, R12, R13, R14, R15)>; | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| //===- ARCSubtarget.cpp - ARC Subtarget Information -------------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file implements the ARC specific subclass of TargetSubtargetInfo. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "ARCSubtarget.h" | ||
| #include "ARC.h" | ||
| #include "llvm/Support/TargetRegistry.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| #define DEBUG_TYPE "arc-subtarget" | ||
|
|
||
| #define GET_SUBTARGETINFO_TARGET_DESC | ||
| #define GET_SUBTARGETINFO_CTOR | ||
| #include "ARCGenSubtargetInfo.inc" | ||
|
|
||
| void ARCSubtarget::anchor() {} | ||
|
|
||
| ARCSubtarget::ARCSubtarget(const Triple &TT, const std::string &CPU, | ||
| const std::string &FS, const TargetMachine &TM) | ||
| : ARCGenSubtargetInfo(TT, CPU, FS), FrameLowering(*this), | ||
| TLInfo(TM, *this) {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| //===- ARCSubtarget.h - Define Subtarget for the ARC ------------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file declares the ARC specific subclass of TargetSubtargetInfo. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_ARC_ARCSUBTARGET_H | ||
| #define LLVM_LIB_TARGET_ARC_ARCSUBTARGET_H | ||
|
|
||
| #include "ARCFrameLowering.h" | ||
| #include "ARCISelLowering.h" | ||
| #include "ARCInstrInfo.h" | ||
| #include "llvm/CodeGen/SelectionDAGTargetInfo.h" | ||
| #include "llvm/Target/TargetSubtargetInfo.h" | ||
| #include <string> | ||
|
|
||
| #define GET_SUBTARGETINFO_HEADER | ||
| #include "ARCGenSubtargetInfo.inc" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class StringRef; | ||
| class TargetMachine; | ||
|
|
||
| class ARCSubtarget : public ARCGenSubtargetInfo { | ||
| virtual void anchor(); | ||
| ARCInstrInfo InstrInfo; | ||
| ARCFrameLowering FrameLowering; | ||
| ARCTargetLowering TLInfo; | ||
| SelectionDAGTargetInfo TSInfo; | ||
|
|
||
| public: | ||
| /// This constructor initializes the data members to match that | ||
| /// of the specified triple. | ||
| ARCSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS, | ||
| const TargetMachine &TM); | ||
|
|
||
| /// Parses features string setting specified subtarget options. | ||
| /// Definition of function is auto generated by tblgen. | ||
| void ParseSubtargetFeatures(StringRef CPU, StringRef FS); | ||
|
|
||
| const ARCInstrInfo *getInstrInfo() const override { return &InstrInfo; } | ||
| const ARCFrameLowering *getFrameLowering() const override { | ||
| return &FrameLowering; | ||
| } | ||
| const ARCTargetLowering *getTargetLowering() const override { | ||
| return &TLInfo; | ||
| } | ||
| const ARCRegisterInfo *getRegisterInfo() const override { | ||
| return &InstrInfo.getRegisterInfo(); | ||
| } | ||
| const SelectionDAGTargetInfo *getSelectionDAGInfo() const override { | ||
| return &TSInfo; | ||
| } | ||
| }; | ||
|
|
||
| } // end namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_ARC_ARCSUBTARGET_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| //===- ARCTargetMachine.cpp - Define TargetMachine for ARC ------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "ARCTargetMachine.h" | ||
| #include "ARC.h" | ||
| #include "ARCTargetTransformInfo.h" | ||
| #include "llvm/CodeGen/Passes.h" | ||
| #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" | ||
| #include "llvm/CodeGen/TargetPassConfig.h" | ||
| #include "llvm/Support/TargetRegistry.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| static Reloc::Model getRelocModel(Optional<Reloc::Model> RM) { | ||
| if (!RM.hasValue()) | ||
| return Reloc::Static; | ||
| return *RM; | ||
| } | ||
|
|
||
| static CodeModel::Model getEffectiveCodeModel(Optional<CodeModel::Model> CM) { | ||
| if (CM) | ||
| return *CM; | ||
| return CodeModel::Small; | ||
| } | ||
|
|
||
| /// ARCTargetMachine ctor - Create an ILP32 architecture model | ||
| ARCTargetMachine::ARCTargetMachine(const Target &T, const Triple &TT, | ||
| StringRef CPU, StringRef FS, | ||
| const TargetOptions &Options, | ||
| Optional<Reloc::Model> RM, | ||
| Optional<CodeModel::Model> CM, | ||
| CodeGenOpt::Level OL, bool JIT) | ||
| : LLVMTargetMachine(T, | ||
| "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" | ||
| "f32:32:32-i64:32-f64:32-a:0:32-n32", | ||
| TT, CPU, FS, Options, getRelocModel(RM), | ||
| getEffectiveCodeModel(CM), OL), | ||
| TLOF(make_unique<TargetLoweringObjectFileELF>()), | ||
| Subtarget(TT, CPU, FS, *this) { | ||
| initAsmInfo(); | ||
| } | ||
|
|
||
| ARCTargetMachine::~ARCTargetMachine() = default; | ||
|
|
||
| namespace { | ||
|
|
||
| /// ARC Code Generator Pass Configuration Options. | ||
| class ARCPassConfig : public TargetPassConfig { | ||
| public: | ||
| ARCPassConfig(ARCTargetMachine &TM, PassManagerBase &PM) | ||
| : TargetPassConfig(TM, PM) {} | ||
|
|
||
| ARCTargetMachine &getARCTargetMachine() const { | ||
| return getTM<ARCTargetMachine>(); | ||
| } | ||
|
|
||
| bool addInstSelector() override; | ||
| void addPreEmitPass() override; | ||
| void addPreRegAlloc() override; | ||
| }; | ||
|
|
||
| } // end anonymous namespace | ||
|
|
||
| TargetPassConfig *ARCTargetMachine::createPassConfig(PassManagerBase &PM) { | ||
| return new ARCPassConfig(*this, PM); | ||
| } | ||
|
|
||
| bool ARCPassConfig::addInstSelector() { | ||
| addPass(createARCISelDag(getARCTargetMachine(), getOptLevel())); | ||
| return false; | ||
| } | ||
|
|
||
| void ARCPassConfig::addPreEmitPass() { addPass(createARCBranchFinalizePass()); } | ||
|
|
||
| void ARCPassConfig::addPreRegAlloc() { addPass(createARCExpandPseudosPass()); } | ||
|
|
||
| // Force static initialization. | ||
| extern "C" void LLVMInitializeARCTarget() { | ||
| RegisterTargetMachine<ARCTargetMachine> X(getTheARCTarget()); | ||
| } | ||
|
|
||
| TargetIRAnalysis ARCTargetMachine::getTargetIRAnalysis() { | ||
| return TargetIRAnalysis([this](const Function &F) { | ||
| return TargetTransformInfo(ARCTTIImpl(this, F)); | ||
| }); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| //===- ARCTargetMachine.h - Define TargetMachine for ARC --------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file declares the ARC specific subclass of TargetMachine. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_ARC_ARCTARGETMACHINE_H | ||
| #define LLVM_LIB_TARGET_ARC_ARCTARGETMACHINE_H | ||
|
|
||
| #include "ARCSubtarget.h" | ||
| #include "llvm/Target/TargetMachine.h" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class TargetPassConfig; | ||
|
|
||
| class ARCTargetMachine : public LLVMTargetMachine { | ||
| std::unique_ptr<TargetLoweringObjectFile> TLOF; | ||
| ARCSubtarget Subtarget; | ||
|
|
||
| public: | ||
| ARCTargetMachine(const Target &T, const Triple &TT, StringRef CPU, | ||
| StringRef FS, const TargetOptions &Options, | ||
| Optional<Reloc::Model> RM, Optional<CodeModel::Model> CM, | ||
| CodeGenOpt::Level OL, bool JIT); | ||
| ~ARCTargetMachine() override; | ||
|
|
||
| const ARCSubtarget *getSubtargetImpl() const { return &Subtarget; } | ||
| const ARCSubtarget *getSubtargetImpl(const Function &) const override { | ||
| return &Subtarget; | ||
| } | ||
|
|
||
| // Pass Pipeline Configuration | ||
| TargetPassConfig *createPassConfig(PassManagerBase &PM) override; | ||
|
|
||
| TargetIRAnalysis getTargetIRAnalysis() override; | ||
| TargetLoweringObjectFile *getObjFileLowering() const override { | ||
| return TLOF.get(); | ||
| } | ||
| }; | ||
|
|
||
| } // end namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_ARC_ARCTARGETMACHINE_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| //===- ARCTargetStreamer.h - ARC Target Streamer ----------------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_ARC_ARCTARGETSTREAMER_H | ||
| #define LLVM_LIB_TARGET_ARC_ARCTARGETSTREAMER_H | ||
|
|
||
| #include "llvm/MC/MCStreamer.h" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class ARCTargetStreamer : public MCTargetStreamer { | ||
| public: | ||
| ARCTargetStreamer(MCStreamer &S); | ||
| ~ARCTargetStreamer() override; | ||
| }; | ||
|
|
||
| } // end namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_ARC_ARCTARGETSTREAMER_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| //===- ARCTargetTransformInfo.h - ARC specific TTI --------------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // \file | ||
| // This file contains a TargetTransformInfo::Concept conforming object specific | ||
| // to the ARC target machine. It uses the target's detailed information to | ||
| // provide more precise answers to certain TTI queries, while letting the | ||
| // target independent and default TTI implementations handle the rest. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_ARC_ARCTARGETTRANSFORMINFO_H | ||
| #define LLVM_LIB_TARGET_ARC_ARCTARGETTRANSFORMINFO_H | ||
|
|
||
| #include "ARC.h" | ||
| #include "llvm/Analysis/TargetTransformInfo.h" | ||
| #include "llvm/CodeGen/BasicTTIImpl.h" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class ARCSubtarget; | ||
| class ARCTargetLowering; | ||
| class ARCTargetMachine; | ||
|
|
||
| class ARCTTIImpl : public BasicTTIImplBase<ARCTTIImpl> { | ||
| using BaseT = BasicTTIImplBase<ARCTTIImpl>; | ||
| friend BaseT; | ||
|
|
||
| const ARCSubtarget *ST; | ||
| const ARCTargetLowering *TLI; | ||
|
|
||
| const ARCSubtarget *getST() const { return ST; } | ||
| const ARCTargetLowering *getTLI() const { return TLI; } | ||
|
|
||
| public: | ||
| explicit ARCTTIImpl(const ARCTargetMachine *TM, const Function &F) | ||
| : BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl()), | ||
| TLI(ST->getTargetLowering()) {} | ||
|
|
||
| // Provide value semantics. MSVC requires that we spell all of these out. | ||
| ARCTTIImpl(const ARCTTIImpl &Arg) | ||
| : BaseT(static_cast<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {} | ||
| ARCTTIImpl(ARCTTIImpl &&Arg) | ||
| : BaseT(std::move(static_cast<BaseT &>(Arg))), ST(std::move(Arg.ST)), | ||
| TLI(std::move(Arg.TLI)) {} | ||
| }; | ||
|
|
||
| } // end namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_ARC_ARCTARGETTRANSFORMINFO_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| set(LLVM_TARGET_DEFINITIONS ARC.td) | ||
|
|
||
| tablegen(LLVM ARCGenRegisterInfo.inc -gen-register-info) | ||
| tablegen(LLVM ARCGenInstrInfo.inc -gen-instr-info) | ||
| tablegen(LLVM ARCGenDisassemblerTables.inc -gen-disassembler) | ||
| tablegen(LLVM ARCGenAsmWriter.inc -gen-asm-writer) | ||
| tablegen(LLVM ARCGenDAGISel.inc -gen-dag-isel) | ||
| tablegen(LLVM ARCGenCallingConv.inc -gen-callingconv) | ||
| tablegen(LLVM ARCGenSubtargetInfo.inc -gen-subtarget) | ||
| add_public_tablegen_target(ARCCommonTableGen) | ||
|
|
||
| add_llvm_target(ARCCodeGen | ||
| ARCAsmPrinter.cpp | ||
| ARCBranchFinalize.cpp | ||
| ARCExpandPseudos.cpp | ||
| ARCFrameLowering.cpp | ||
| ARCInstrInfo.cpp | ||
| ARCISelDAGToDAG.cpp | ||
| ARCISelLowering.cpp | ||
| ARCMachineFunctionInfo.cpp | ||
| ARCMCInstLower.cpp | ||
| ARCRegisterInfo.cpp | ||
| ARCSubtarget.cpp | ||
| ARCTargetMachine.cpp | ||
| ) | ||
|
|
||
| add_subdirectory(InstPrinter) | ||
| add_subdirectory(TargetInfo) | ||
| add_subdirectory(MCTargetDesc) | ||
| add_subdirectory(Disassembler) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,298 @@ | ||
| //===- ARCDisassembler.cpp - Disassembler for ARC ---------------*- C++ -*-===// | ||
| // | ||
| // 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 is part of the ARC Disassembler. | ||
| /// | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "ARC.h" | ||
| #include "ARCRegisterInfo.h" | ||
| #include "MCTargetDesc/ARCMCTargetDesc.h" | ||
| #include "llvm/MC/MCContext.h" | ||
| #include "llvm/MC/MCDisassembler/MCDisassembler.h" | ||
| #include "llvm/MC/MCFixedLenDisassembler.h" | ||
| #include "llvm/MC/MCInst.h" | ||
| #include "llvm/MC/MCInstrInfo.h" | ||
| #include "llvm/MC/MCSubtargetInfo.h" | ||
| #include "llvm/Support/TargetRegistry.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| #define DEBUG_TYPE "arc-disassembler" | ||
|
|
||
| using DecodeStatus = MCDisassembler::DecodeStatus; | ||
|
|
||
| namespace { | ||
|
|
||
| /// \brief A disassembler class for ARC. | ||
| class ARCDisassembler : public MCDisassembler { | ||
| public: | ||
| std::unique_ptr<MCInstrInfo const> const MCII; | ||
|
|
||
| ARCDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, | ||
| MCInstrInfo const *MCII) | ||
| : MCDisassembler(STI, Ctx), MCII(MCII) {} | ||
|
|
||
| DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, | ||
| ArrayRef<uint8_t> Bytes, uint64_t Address, | ||
| raw_ostream &VStream, | ||
| raw_ostream &CStream) const override; | ||
| }; | ||
|
|
||
| } // end anonymous namespace | ||
|
|
||
| static bool readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address, | ||
| uint64_t &Size, uint32_t &Insn) { | ||
| Size = 4; | ||
| // Read 2 16-bit values, but swap hi/lo parts. | ||
| Insn = | ||
| (Bytes[0] << 16) | (Bytes[1] << 24) | (Bytes[2] << 0) | (Bytes[3] << 8); | ||
| return true; | ||
| } | ||
|
|
||
| static bool readInstruction64(ArrayRef<uint8_t> Bytes, uint64_t Address, | ||
| uint64_t &Size, uint64_t &Insn) { | ||
| Size = 8; | ||
| Insn = ((uint64_t)Bytes[0] << 16) | ((uint64_t)Bytes[1] << 24) | | ||
| ((uint64_t)Bytes[2] << 0) | ((uint64_t)Bytes[3] << 8) | | ||
| ((uint64_t)Bytes[4] << 48) | ((uint64_t)Bytes[5] << 56) | | ||
| ((uint64_t)Bytes[6] << 32) | ((uint64_t)Bytes[7] << 40); | ||
| return true; | ||
| } | ||
|
|
||
| static bool readInstruction16(ArrayRef<uint8_t> Bytes, uint64_t Address, | ||
| uint64_t &Size, uint32_t &Insn) { | ||
| Size = 2; | ||
| Insn = (Bytes[0] << 0) | (Bytes[1] << 8); | ||
| return true; | ||
| } | ||
|
|
||
| static MCDisassembler::DecodeStatus DecodeS12Operand(MCInst &, unsigned, | ||
| uint64_t, const void *); | ||
|
|
||
| static MCDisassembler::DecodeStatus DecodeS9Operand(MCInst &, unsigned, | ||
| uint64_t, const void *); | ||
|
|
||
| static MCDisassembler::DecodeStatus | ||
| DecodeBranchTargetS9(MCInst &, unsigned, uint64_t, const void *); | ||
|
|
||
| static MCDisassembler::DecodeStatus | ||
| DecodeBranchTargetS21(MCInst &, unsigned, uint64_t, const void *); | ||
|
|
||
| static MCDisassembler::DecodeStatus | ||
| DecodeBranchTargetS25(MCInst &, unsigned, uint64_t, const void *); | ||
|
|
||
| static MCDisassembler::DecodeStatus DecodeMEMrs9(MCInst &, unsigned, uint64_t, | ||
| const void *); | ||
|
|
||
| static MCDisassembler::DecodeStatus | ||
| DecodeLdLImmInstruction(MCInst &, uint64_t, uint64_t, const void *); | ||
|
|
||
| static MCDisassembler::DecodeStatus | ||
| DecodeStLImmInstruction(MCInst &, uint64_t, uint64_t, const void *); | ||
|
|
||
| static MCDisassembler::DecodeStatus | ||
| DecodeLdRLImmInstruction(MCInst &, uint64_t, uint64_t, const void *); | ||
|
|
||
| static const uint16_t GPR32DecoderTable[] = { | ||
| ARC::R0, ARC::R1, ARC::R2, ARC::R3, ARC::R4, ARC::R5, ARC::R6, | ||
| ARC::R7, ARC::R8, ARC::R9, ARC::R10, ARC::R11, ARC::R12, ARC::R13, | ||
| ARC::R14, ARC::R15, ARC::R16, ARC::R17, ARC::R18, ARC::R19, ARC::R20, | ||
| ARC::R21, ARC::R22, ARC::R23, ARC::R24, ARC::R25, ARC::GP, ARC::FP, | ||
| ARC::SP, ARC::ILINK, ARC::R30, ARC::BLINK}; | ||
|
|
||
| static DecodeStatus DecodeGPR32RegisterClass(MCInst &Inst, unsigned RegNo, | ||
| uint64_t Address, | ||
| const void *Decoder) { | ||
| if (RegNo >= 32) { | ||
| DEBUG(dbgs() << "Not a GPR32 register."); | ||
| return MCDisassembler::Fail; | ||
| } | ||
| unsigned Reg = GPR32DecoderTable[RegNo]; | ||
| Inst.addOperand(MCOperand::createReg(Reg)); | ||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| #include "ARCGenDisassemblerTables.inc" | ||
|
|
||
| static unsigned decodeCField(unsigned Insn) { | ||
| return fieldFromInstruction(Insn, 6, 6); | ||
| } | ||
|
|
||
| static unsigned decodeBField(unsigned Insn) { | ||
| return (fieldFromInstruction(Insn, 12, 3) << 3) | | ||
| fieldFromInstruction(Insn, 24, 3); | ||
| } | ||
|
|
||
| static unsigned decodeAField(unsigned Insn) { | ||
| return fieldFromInstruction(Insn, 0, 6); | ||
| } | ||
|
|
||
| static MCDisassembler::DecodeStatus | ||
| DecodeMEMrs9(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Dec) { | ||
| // We have the 9-bit immediate in the low bits, 6-bit register in high bits. | ||
| unsigned S9 = Insn & 0x1ff; | ||
| unsigned R = (Insn & (0x7fff & ~0x1ff)) >> 9; | ||
| DecodeGPR32RegisterClass(Inst, R, Address, Dec); | ||
| Inst.addOperand(MCOperand::createImm(SignExtend32<9>(S9))); | ||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| static MCDisassembler::DecodeStatus DecodeS9Operand(MCInst &Inst, | ||
| unsigned InsnS9, | ||
| uint64_t Address, | ||
| const void *Decoder) { | ||
| Inst.addOperand(MCOperand::createImm(SignExtend32<9>(0x1ff & InsnS9))); | ||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| static MCDisassembler::DecodeStatus DecodeS12Operand(MCInst &Inst, | ||
| unsigned InsnS12, | ||
| uint64_t Address, | ||
| const void *Decoder) { | ||
| Inst.addOperand(MCOperand::createImm(SignExtend32<12>(0xfff & InsnS12))); | ||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| static MCDisassembler::DecodeStatus DecodeBranchTargetS9(MCInst &Inst, | ||
| unsigned S, | ||
| uint64_t Address, | ||
| const void *Decoder) { | ||
| Inst.addOperand(MCOperand::createImm(SignExtend32<9>(S))); | ||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| static MCDisassembler::DecodeStatus DecodeBranchTargetS21(MCInst &Inst, | ||
| unsigned S, | ||
| uint64_t Address, | ||
| const void *Decoder) { | ||
| Inst.addOperand(MCOperand::createImm(SignExtend32<21>(S))); | ||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| static MCDisassembler::DecodeStatus DecodeBranchTargetS25(MCInst &Inst, | ||
| unsigned S, | ||
| uint64_t Address, | ||
| const void *Decoder) { | ||
| Inst.addOperand(MCOperand::createImm(SignExtend32<25>(S))); | ||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| static MCDisassembler::DecodeStatus | ||
| DecodeStLImmInstruction(MCInst &Inst, uint64_t Insn, uint64_t Address, | ||
| const void *Decoder) { | ||
| unsigned SrcC, DstB, LImm; | ||
| DstB = decodeBField(Insn); | ||
| if (DstB != 62) { | ||
| DEBUG(dbgs() << "Decoding StLImm found non-limm register."); | ||
| return MCDisassembler::Fail; | ||
| } | ||
| SrcC = decodeCField(Insn); | ||
| DecodeGPR32RegisterClass(Inst, SrcC, Address, Decoder); | ||
| LImm = (Insn >> 32); | ||
| Inst.addOperand(MCOperand::createImm(LImm)); | ||
| Inst.addOperand(MCOperand::createImm(0)); | ||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| static MCDisassembler::DecodeStatus | ||
| DecodeLdLImmInstruction(MCInst &Inst, uint64_t Insn, uint64_t Address, | ||
| const void *Decoder) { | ||
| unsigned DstA, SrcB, LImm; | ||
| DEBUG(dbgs() << "Decoding LdLImm:\n"); | ||
| SrcB = decodeBField(Insn); | ||
| if (SrcB != 62) { | ||
| DEBUG(dbgs() << "Decoding LdLImm found non-limm register."); | ||
| return MCDisassembler::Fail; | ||
| } | ||
| DstA = decodeAField(Insn); | ||
| DecodeGPR32RegisterClass(Inst, DstA, Address, Decoder); | ||
| LImm = (Insn >> 32); | ||
| Inst.addOperand(MCOperand::createImm(LImm)); | ||
| Inst.addOperand(MCOperand::createImm(0)); | ||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| static MCDisassembler::DecodeStatus | ||
| DecodeLdRLImmInstruction(MCInst &Inst, uint64_t Insn, uint64_t Address, | ||
| const void *Decoder) { | ||
| unsigned DstA, SrcB; | ||
| DEBUG(dbgs() << "Decoding LdRLimm\n"); | ||
| DstA = decodeAField(Insn); | ||
| DecodeGPR32RegisterClass(Inst, DstA, Address, Decoder); | ||
| SrcB = decodeBField(Insn); | ||
| DecodeGPR32RegisterClass(Inst, SrcB, Address, Decoder); | ||
| if (decodeCField(Insn) != 62) { | ||
| DEBUG(dbgs() << "Decoding LdRLimm found non-limm register."); | ||
| return MCDisassembler::Fail; | ||
| } | ||
| Inst.addOperand(MCOperand::createImm((uint32_t)(Insn >> 32))); | ||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| MCDisassembler::DecodeStatus ARCDisassembler::getInstruction( | ||
| MCInst &Instr, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t Address, | ||
| raw_ostream &vStream, raw_ostream &cStream) const { | ||
| MCDisassembler::DecodeStatus Result; | ||
| if (Bytes.size() < 2) { | ||
| Size = 0; | ||
| return Fail; | ||
| } | ||
| uint8_t DecodeByte = (Bytes[1] & 0xF7) >> 3; | ||
| // 0x00 -> 0x07 are 32-bit instructions. | ||
| // 0x08 -> 0x1F are 16-bit instructions. | ||
| if (DecodeByte < 0x08) { | ||
| // 32-bit instruction. | ||
| if (Bytes.size() < 4) { | ||
| // Did we decode garbage? | ||
| Size = 0; | ||
| return Fail; | ||
| } | ||
| if (Bytes.size() >= 8) { | ||
| // Attempt to decode 64-bit instruction. | ||
| uint64_t Insn64; | ||
| if (!readInstruction64(Bytes, Address, Size, Insn64)) | ||
| return Fail; | ||
| Result = | ||
| decodeInstruction(DecoderTable64, Instr, Insn64, Address, this, STI); | ||
| if (Result == MCDisassembler::Success) { | ||
| DEBUG(dbgs() << "Successfully decoded 64-bit instruction."); | ||
| return MCDisassembler::Success; | ||
| } | ||
| DEBUG(dbgs() << "Not a 64-bit instruction, falling back to 32-bit."); | ||
| } | ||
| uint32_t Insn32; | ||
| if (!readInstruction32(Bytes, Address, Size, Insn32)) { | ||
| return Fail; | ||
| } | ||
| // Calling the auto-generated decoder function. | ||
| return decodeInstruction(DecoderTable32, Instr, Insn32, Address, this, STI); | ||
| } | ||
|
|
||
| // 16-bit instruction. | ||
| uint32_t Insn16; | ||
| if (!readInstruction16(Bytes, Address, Size, Insn16)) { | ||
| return Fail; | ||
| } | ||
| // Calling the auto-generated decoder function. | ||
| return decodeInstruction(DecoderTable16, Instr, Insn16, Address, this, STI); | ||
| } | ||
|
|
||
| static MCDisassembler *createARCDisassembler(const Target &T, | ||
| const MCSubtargetInfo &STI, | ||
| MCContext &Ctx) { | ||
| return new ARCDisassembler(STI, Ctx, T.createMCInstrInfo()); | ||
| } | ||
|
|
||
| extern "C" void LLVMInitializeARCDisassembler() { | ||
| // Register the disassembler. | ||
| TargetRegistry::RegisterMCDisassembler(getTheARCTarget(), | ||
| createARCDisassembler); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| add_llvm_library(LLVMARCDisassembler | ||
| ARCDisassembler.cpp | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| ;===- ./lib/Target/ARC/Disassembler/LLVMBuild.txt ------------*- Conf -*--===; | ||
| ; | ||
| ; The LLVM Compiler Infrastructure | ||
| ; | ||
| ; This file is distributed under the University of Illinois Open Source | ||
| ; License. See LICENSE.TXT for details. | ||
| ; | ||
| ;===------------------------------------------------------------------------===; | ||
| ; | ||
| ; This is an LLVMBuild description file for the components in this subdirectory. | ||
| ; | ||
| ; For more information on the LLVMBuild system, please see: | ||
| ; | ||
| ; http://llvm.org/docs/LLVMBuild.html | ||
| ; | ||
| ;===------------------------------------------------------------------------===; | ||
|
|
||
| [component_0] | ||
| type = Library | ||
| name = ARCDisassembler | ||
| parent = ARC | ||
| required_libraries = MCDisassembler Support ARCInfo | ||
| add_to_library_groups = ARC |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,166 @@ | ||
| //===- ARCInstPrinter.cpp - ARC MCInst to assembly syntax -------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This class prints an ARC MCInst to a .s file. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "ARCInstPrinter.h" | ||
| #include "MCTargetDesc/ARCInfo.h" | ||
| #include "llvm/ADT/StringExtras.h" | ||
| #include "llvm/MC/MCExpr.h" | ||
| #include "llvm/MC/MCInst.h" | ||
| #include "llvm/MC/MCInstrInfo.h" | ||
| #include "llvm/MC/MCSymbol.h" | ||
| #include "llvm/Support/Casting.h" | ||
| #include "llvm/Support/Debug.h" | ||
| #include "llvm/Support/ErrorHandling.h" | ||
| #include "llvm/Support/raw_ostream.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| #define DEBUG_TYPE "asm-printer" | ||
|
|
||
| #include "ARCGenAsmWriter.inc" | ||
|
|
||
| static const char *ARCBRCondCodeToString(ARCCC::BRCondCode BRCC) { | ||
| switch (BRCC) { | ||
| case ARCCC::BREQ: | ||
| return "eq"; | ||
| case ARCCC::BRNE: | ||
| return "ne"; | ||
| case ARCCC::BRLT: | ||
| return "lt"; | ||
| case ARCCC::BRGE: | ||
| return "ge"; | ||
| case ARCCC::BRLO: | ||
| return "lo"; | ||
| case ARCCC::BRHS: | ||
| return "hs"; | ||
| default: | ||
| llvm_unreachable("Unhandled ARCCC::BRCondCode"); | ||
| } | ||
| } | ||
|
|
||
| static const char *ARCCondCodeToString(ARCCC::CondCode CC) { | ||
| switch (CC) { | ||
| case ARCCC::EQ: | ||
| return "eq"; | ||
| case ARCCC::NE: | ||
| return "ne"; | ||
| case ARCCC::P: | ||
| return "p"; | ||
| case ARCCC::N: | ||
| return "n"; | ||
| case ARCCC::HS: | ||
| return "hs"; | ||
| case ARCCC::LO: | ||
| return "lo"; | ||
| case ARCCC::GT: | ||
| return "gt"; | ||
| case ARCCC::GE: | ||
| return "ge"; | ||
| case ARCCC::LT: | ||
| return "lt"; | ||
| case ARCCC::LE: | ||
| return "le"; | ||
| case ARCCC::HI: | ||
| return "hi"; | ||
| case ARCCC::LS: | ||
| return "ls"; | ||
| case ARCCC::PNZ: | ||
| return "pnz"; | ||
| case ARCCC::AL: | ||
| return "al"; | ||
| case ARCCC::NZ: | ||
| return "nz"; | ||
| case ARCCC::Z: | ||
| return "z"; | ||
| } | ||
| llvm_unreachable("Unhandled ARCCC::CondCode"); | ||
| } | ||
|
|
||
| void ARCInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { | ||
| OS << StringRef(getRegisterName(RegNo)).lower(); | ||
| } | ||
|
|
||
| void ARCInstPrinter::printInst(const MCInst *MI, raw_ostream &O, | ||
| StringRef Annot, const MCSubtargetInfo &STI) { | ||
| printInstruction(MI, O); | ||
| printAnnotation(O, Annot); | ||
| } | ||
|
|
||
| static void printExpr(const MCExpr *Expr, const MCAsmInfo *MAI, | ||
| raw_ostream &OS) { | ||
| int Offset = 0; | ||
| const MCSymbolRefExpr *SRE; | ||
|
|
||
| if (const auto *BE = dyn_cast<MCBinaryExpr>(Expr)) { | ||
| SRE = dyn_cast<MCSymbolRefExpr>(BE->getLHS()); | ||
| const auto *CE = dyn_cast<MCConstantExpr>(BE->getRHS()); | ||
| assert(SRE && CE && "Binary expression must be sym+const."); | ||
| Offset = CE->getValue(); | ||
| } else { | ||
| SRE = dyn_cast<MCSymbolRefExpr>(Expr); | ||
| assert(SRE && "Unexpected MCExpr type."); | ||
| } | ||
| assert(SRE->getKind() == MCSymbolRefExpr::VK_None); | ||
|
|
||
| // Symbols are prefixed with '@' | ||
| OS << '@'; | ||
| SRE->getSymbol().print(OS, MAI); | ||
|
|
||
| if (Offset) { | ||
| if (Offset > 0) | ||
| OS << '+'; | ||
| OS << Offset; | ||
| } | ||
| } | ||
|
|
||
| void ARCInstPrinter::printOperand(const MCInst *MI, unsigned OpNum, | ||
| raw_ostream &O) { | ||
| const MCOperand &Op = MI->getOperand(OpNum); | ||
| if (Op.isReg()) { | ||
| printRegName(O, Op.getReg()); | ||
| return; | ||
| } | ||
|
|
||
| if (Op.isImm()) { | ||
| O << Op.getImm(); | ||
| return; | ||
| } | ||
|
|
||
| assert(Op.isExpr() && "unknown operand kind in printOperand"); | ||
| printExpr(Op.getExpr(), &MAI, O); | ||
| } | ||
|
|
||
| void ARCInstPrinter::printMemOperandRI(const MCInst *MI, unsigned OpNum, | ||
| raw_ostream &O) { | ||
| const MCOperand &base = MI->getOperand(OpNum); | ||
| const MCOperand &offset = MI->getOperand(OpNum + 1); | ||
| assert(base.isReg() && "Base should be register."); | ||
| assert(offset.isImm() && "Offset should be immediate."); | ||
| printRegName(O, base.getReg()); | ||
| O << "," << offset.getImm(); | ||
| } | ||
|
|
||
| void ARCInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum, | ||
| raw_ostream &O) { | ||
|
|
||
| const MCOperand &Op = MI->getOperand(OpNum); | ||
| assert(Op.isImm() && "Predicate operand is immediate."); | ||
| O << ARCCondCodeToString((ARCCC::CondCode)Op.getImm()); | ||
| } | ||
|
|
||
| void ARCInstPrinter::printBRCCPredicateOperand(const MCInst *MI, unsigned OpNum, | ||
| raw_ostream &O) { | ||
| const MCOperand &Op = MI->getOperand(OpNum); | ||
| assert(Op.isImm() && "Predicate operand is immediate."); | ||
| O << ARCBRCondCodeToString((ARCCC::BRCondCode)Op.getImm()); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| //===- ARCInstPrinter.h - Convert ARC MCInst to assembly syntax -*- C++ -*-===// | ||
| // | ||
| // 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 contains the declaration of the ARCInstPrinter class, | ||
| /// which is used to print ARC MCInst to a .s file. | ||
| /// | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_ARC_INSTPRINTER_ARCINSTPRINTER_H | ||
| #define LLVM_LIB_TARGET_ARC_INSTPRINTER_ARCINSTPRINTER_H | ||
|
|
||
| #include "llvm/MC/MCInstPrinter.h" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class ARCInstPrinter : public MCInstPrinter { | ||
| public: | ||
| ARCInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, | ||
| const MCRegisterInfo &MRI) | ||
| : MCInstPrinter(MAI, MII, MRI) {} | ||
|
|
||
| // Autogenerated by tblgen. | ||
| void printInstruction(const MCInst *MI, raw_ostream &O); | ||
| static const char *getRegisterName(unsigned RegNo); | ||
|
|
||
| void printRegName(raw_ostream &OS, unsigned RegNo) const override; | ||
| void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot, | ||
| const MCSubtargetInfo &STI) override; | ||
|
|
||
| private: | ||
| void printMemOperandRI(const MCInst *MI, unsigned OpNum, raw_ostream &O); | ||
| void printOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); | ||
| void printPredicateOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); | ||
| void printBRCCPredicateOperand(const MCInst *MI, unsigned OpNum, | ||
| raw_ostream &O); | ||
| }; | ||
| } // end namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_ARC_INSTPRINTER_ARCINSTPRINTER_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| add_llvm_library(LLVMARCAsmPrinter | ||
| ARCInstPrinter.cpp | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| ;===- ./lib/Target/ARC/InstPrinter/LLVMBuild.txt -------------*- Conf -*--===; | ||
| ; | ||
| ; The LLVM Compiler Infrastructure | ||
| ; | ||
| ; This file is distributed under the University of Illinois Open Source | ||
| ; License. See LICENSE.TXT for details. | ||
| ; | ||
| ;===------------------------------------------------------------------------===; | ||
| ; | ||
| ; This is an LLVMBuild description file for the components in this subdirectory. | ||
| ; | ||
| ; For more information on the LLVMBuild system, please see: | ||
| ; | ||
| ; http://llvm.org/docs/LLVMBuild.html | ||
| ; | ||
| ;===------------------------------------------------------------------------===; | ||
|
|
||
| [component_0] | ||
| type = Library | ||
| name = ARCAsmPrinter | ||
| parent = ARC | ||
| required_libraries = MC Support | ||
| add_to_library_groups = ARC |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| ;===- ./lib/Target/ARC/LLVMBuild.txt -------------------------*- Conf -*--===; | ||
| ; | ||
| ; The LLVM Compiler Infrastructure | ||
| ; | ||
| ; This file is distributed under the University of Illinois Open Source | ||
| ; License. See LICENSE.TXT for details. | ||
| ; | ||
| ;===------------------------------------------------------------------------===; | ||
| ; | ||
| ; This is an LLVMBuild description file for the components in this subdirectory. | ||
| ; | ||
| ; For more information on the LLVMBuild system, please see: | ||
| ; | ||
| ; http://llvm.org/docs/LLVMBuild.html | ||
| ; | ||
| ;===------------------------------------------------------------------------===; | ||
|
|
||
| [common] | ||
| subdirectories = Disassembler InstPrinter MCTargetDesc TargetInfo | ||
|
|
||
| [component_0] | ||
| type = TargetGroup | ||
| name = ARC | ||
| parent = Target | ||
| has_asmprinter = 1 | ||
| has_disassembler = 1 | ||
|
|
||
| [component_1] | ||
| type = Library | ||
| name = ARCCodeGen | ||
| parent = ARC | ||
| required_libraries = | ||
| Analysis | ||
| AsmPrinter | ||
| CodeGen | ||
| Core | ||
| MC | ||
| SelectionDAG | ||
| Support | ||
| Target | ||
| TransformUtils | ||
| ARCAsmPrinter | ||
| ARCDesc | ||
| ARCInfo | ||
| add_to_library_groups = ARC |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| //===- ARCInfo.h - Additional ARC Info --------------------------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file contains small standalone helper functions and enum definitions for | ||
| // the ARC target useful for the compiler back-end and the MC libraries. | ||
| // As such, it deliberately does not include references to LLVM core | ||
| // code gen types, passes, etc.. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_ARC_MCTARGETDESC_ARCINFO_H | ||
| #define LLVM_LIB_TARGET_ARC_MCTARGETDESC_ARCINFO_H | ||
|
|
||
| namespace llvm { | ||
|
|
||
| // Enums corresponding to ARC condition codes | ||
| namespace ARCCC { | ||
|
|
||
| enum CondCode { | ||
| AL = 0x0, | ||
| EQ = 0x1, | ||
| NE = 0x2, | ||
| P = 0x3, | ||
| N = 0x4, | ||
| LO = 0x5, | ||
| HS = 0x6, | ||
| GT = 0x9, | ||
| GE = 0xa, | ||
| LT = 0xb, | ||
| LE = 0xc, | ||
| HI = 0xd, | ||
| LS = 0xe, | ||
| PNZ = 0xf, | ||
| Z = 0x11, // Low 4-bits = EQ | ||
| NZ = 0x12 // Low 4-bits = NE | ||
| }; | ||
|
|
||
| enum BRCondCode { | ||
| BREQ = 0x0, | ||
| BRNE = 0x1, | ||
| BRLT = 0x2, | ||
| BRGE = 0x3, | ||
| BRLO = 0x4, | ||
| BRHS = 0x5 | ||
| }; | ||
|
|
||
| } // end namespace ARCCC | ||
|
|
||
| } // end namespace llvm | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| //===- ARCMCAsmInfo.cpp - ARC asm properties --------------------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "ARCMCAsmInfo.h" | ||
| using namespace llvm; | ||
|
|
||
| void ARCMCAsmInfo::anchor() {} | ||
|
|
||
| ARCMCAsmInfo::ARCMCAsmInfo(const Triple &TT) { | ||
| SupportsDebugInformation = true; | ||
| Data16bitsDirective = "\t.short\t"; | ||
| Data32bitsDirective = "\t.word\t"; | ||
| Data64bitsDirective = nullptr; | ||
| ZeroDirective = "\t.space\t"; | ||
| CommentString = ";"; | ||
|
|
||
| UsesELFSectionDirectiveForBSS = true; | ||
| AllowAtInName = true; | ||
| HiddenVisibilityAttr = MCSA_Invalid; | ||
| HiddenDeclarationVisibilityAttr = MCSA_Invalid; | ||
| ProtectedVisibilityAttr = MCSA_Invalid; | ||
|
|
||
| // Debug | ||
| ExceptionsType = ExceptionHandling::DwarfCFI; | ||
| DwarfRegNumForCFI = true; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| //===- ARCMCAsmInfo.h - ARC asm properties ----------------------*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file contains the declaration of the ARCMCAsmInfo class. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_ARC_MCTARGETDESC_ARCMCASMINFO_H | ||
| #define LLVM_LIB_TARGET_ARC_MCTARGETDESC_ARCMCASMINFO_H | ||
|
|
||
| #include "llvm/MC/MCAsmInfoELF.h" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class Triple; | ||
|
|
||
| class ARCMCAsmInfo : public MCAsmInfoELF { | ||
| void anchor() override; | ||
|
|
||
| public: | ||
| explicit ARCMCAsmInfo(const Triple &TT); | ||
| }; | ||
|
|
||
| } // end namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_ARC_MCTARGETDESC_ARCMCASMINFO_H |