diff options
Diffstat (limited to 'llvm/lib/Target/ARC/ARCInstrInfo.cpp')
-rw-r--r-- | llvm/lib/Target/ARC/ARCInstrInfo.cpp | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/llvm/lib/Target/ARC/ARCInstrInfo.cpp b/llvm/lib/Target/ARC/ARCInstrInfo.cpp new file mode 100644 index 00000000000..48d5a00d594 --- /dev/null +++ b/llvm/lib/Target/ARC/ARCInstrInfo.cpp @@ -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(); +} |