Index: lib/Target/NDS32/CMakeLists.txt =================================================================== --- lib/Target/NDS32/CMakeLists.txt +++ lib/Target/NDS32/CMakeLists.txt @@ -13,6 +13,7 @@ NDS32ISelDAGToDAG.cpp NDS32ISelLowering.cpp NDS32MachineFunctionInfo.cpp + NDS32InstrInfo.cpp NDS32TargetMachine.cpp ) Index: lib/Target/NDS32/NDS32InstrInfo.h =================================================================== --- /dev/null +++ lib/Target/NDS32/NDS32InstrInfo.h @@ -0,0 +1,98 @@ +//===-- NDS32InstrInfo.h - NDS32 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 NDS32 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_NDS32_NDS32INSTRINFO_H +#define LLVM_LIB_TARGET_NDS32_NDS32INSTRINFO_H + +#include "NDS32RegisterInfo.h" +#include "llvm/Target/TargetInstrInfo.h" + +#define GET_INSTRINFO_HEADER +#include "NDS32GenInstrInfo.inc" + +namespace llvm { + +class NDS32Subtarget; + +class NDS32InstrInfo : public NDS32GenInstrInfo { + const NDS32Subtarget &Subtarget; + const NDS32RegisterInfo RI; + virtual void anchor(); +public: + explicit NDS32InstrInfo(NDS32Subtarget &STI); + + /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As + /// such, whenever a client has an instance of instruction info, it should + /// always be able to get register info as well (through this method). + /// + const NDS32RegisterInfo &getRegisterInfo() const { return RI; } + + static const NDS32InstrInfo *create(NDS32Subtarget &STI); + + 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 FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override; + + // Branch folding goodness + bool + reverseBranchCondition(SmallVectorImpl &Cond) const override; + bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const override; + + unsigned removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved = nullptr) const override; + + unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, ArrayRef Cond, + const DebugLoc &DL, + int *BytesAdded = nullptr) const override; + + // Adjust SP by Amount bytes. + void adjustStackPtr(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + bool expandPostRAPseudo(MachineInstr &MI) const override; + +protected: + MachineMemOperand *GetMemOperand(MachineBasicBlock &MBB, int FI, + MachineMemOperand::Flags Flags) const; + +private: + void BuildCondBr(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + const DebugLoc &DL, ArrayRef Cond) const; + + void AnalyzeCondBr(const MachineInstr *Inst, unsigned Opc, + MachineBasicBlock *&BB, + SmallVectorImpl &Cond) const; + + void expandMEMCPY(MachineBasicBlock::iterator) const; +}; + +const NDS32InstrInfo *createNDS32InstrInfo(const NDS32Subtarget &STI); +} + +#endif Index: lib/Target/NDS32/NDS32InstrInfo.cpp =================================================================== --- /dev/null +++ lib/Target/NDS32/NDS32InstrInfo.cpp @@ -0,0 +1,435 @@ +//===-- NDS32InstrInfo.cpp - NDS32 Instruction Information ----------------===// +// +// 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 NDS32 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "NDS32InstrInfo.h" +#include "NDS32.h" +#include "NDS32MachineFunctionInfo.h" +#include "NDS32TargetMachine.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +#define GET_INSTRINFO_CTOR_DTOR +#include "NDS32GenInstrInfo.inc" + +// Pin the vtable to this file. +void NDS32InstrInfo::anchor() {} + +NDS32InstrInfo::NDS32InstrInfo(NDS32Subtarget &STI) + : NDS32GenInstrInfo(NDS32::ADJCALLSTACKDOWN, NDS32::ADJCALLSTACKUP), + Subtarget(STI), + RI() {} + +const NDS32InstrInfo *NDS32InstrInfo::create(NDS32Subtarget &STI) { + return new NDS32InstrInfo(STI); +} + +/// Adjust SP by Amount bytes. +void NDS32InstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + DebugLoc DL; + // Use R15 as temp register + unsigned Reg = NDS32::R15; + + if (Amount == 0) + return; + + // addi immediate require fit imm15s + if (isInt<15>(Amount)) { + // addi sp, sp, amount + BuildMI(MBB, I, DL, get(NDS32::ADDI), SP). + addReg(SP).addImm(Amount); + // movi immediate require fit imm20s + } else if (isInt<20>(Amount)) { + // movi r15, amount + // add sp, sp, r15 + BuildMI(MBB, I, DL, get(NDS32::MOVI), Reg) + .addImm(Amount); + BuildMI(MBB, I, DL, get(NDS32::ADD), SP) + . addReg(SP).addReg(Reg, RegState::Kill); + } else { + // sethi r15, hi20 (amount) + // ori r15, lo12 (amount) + // add sp, sp, r15 + BuildMI(MBB, I, DL, get(NDS32::SETHI), Reg) + .addImm((Amount >> 12) & 0xfffff); + BuildMI(MBB, I, DL, get(NDS32::ORI), Reg).addReg(Reg) + .addImm(Amount & 0xfff); + BuildMI(MBB, I, DL, get(NDS32::ADD), SP) + .addReg(SP).addReg(Reg, RegState::Kill); + } +} + +MachineMemOperand * +NDS32InstrInfo::GetMemOperand(MachineBasicBlock &MBB, int FI, + MachineMemOperand::Flags Flags) const { + MachineFunction &MF = *MBB.getParent(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + unsigned Align = MFI.getObjectAlignment(FI); + + return MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(MF, FI), + Flags, MFI.getObjectSize(FI), Align); +} + +void NDS32InstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, int FI, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL; + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + // Defined instruction operand as MemOperand, + // then the replaceFrameIndices () function + // in Prologue/Epilogue Insertion & Frame Finalization Pass + // could eliminate the stack slot number to base with frame index, + MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOStore); + + if (RC == &NDS32::GPRRegClass || + RC == &NDS32::lGPRRegClass || + RC == &NDS32::mGPRRegClass || + RC == &NDS32::FPRegRegClass || + RC == &NDS32::SPRegRegClass || + RC == &NDS32::hGPRRegClass) { + BuildMI(MBB, MI, DL, get(NDS32::SWI)) + .addReg(SrcReg,getKillRegState(isKill)) + .addFrameIndex(FI) + .addImm(0) + .addMemOperand(MMO); + } else + llvm_unreachable("Cannot store this register to stack slot!"); +} + +void NDS32InstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FI, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const{ + DebugLoc DL; + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + // Defined instruction operand as MemOperand, + // then the replaceFrameIndices () function + // in Prologue/Epilogue Insertion & Frame Finalization Pass + // could eliminate the stack slot number to base with frame index, + MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOStore); + + if (RC == &NDS32::GPRRegClass || + RC == &NDS32::lGPRRegClass || + RC == &NDS32::mGPRRegClass || + RC == &NDS32::FPRegRegClass || + RC == &NDS32::SPRegRegClass || + RC == &NDS32::hGPRRegClass) { + BuildMI(MBB, MI, DL, get(NDS32::LWI), DestReg) + .addFrameIndex(FI) + .addImm(0) + .addMemOperand(MMO); + } else + llvm_unreachable("Cannot load this register from stack slot!"); +} + +void NDS32InstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + const DebugLoc &DL, unsigned DestReg, + unsigned SrcReg, bool KillSrc) const { + MachineFunction &MF = *I->getParent()->getParent(); + const NDS32Subtarget &Subtarget = MF.getSubtarget(); + unsigned Opc; + + // Generate 32-bit ADDI when no-16bit is enabled + if (NDS32::GPRRegClass.contains(DestReg, SrcReg)) { + if (Subtarget.has16Bit()) + Opc = NDS32::MOV55; + else + Opc = NDS32::ADDI; + } else + llvm_unreachable("Impossible reg-to-reg copy"); + + if (Opc == NDS32::MOV55) + BuildMI(MBB, I, DL, get(Opc), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); + else + BuildMI(MBB, I, DL, get(Opc), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)).addImm(0); +} + +//===----------------------------------------------------------------------===// +// Branch Analysis +//===----------------------------------------------------------------------===// + +static bool isUncondBranch(unsigned Opcode) { + + if (Opcode == NDS32::J || + Opcode == NDS32::J8) + return true; + return false; +} + +static bool isCondBranch(unsigned Opcode) { + + if (Opcode == NDS32::BEQ || + Opcode == NDS32::BNE || + Opcode == NDS32::BEQZ || + Opcode == NDS32::BNEZ || + Opcode == NDS32::BGEZ || + Opcode == NDS32::BGTZ || + Opcode == NDS32::BLEZ || + Opcode == NDS32::BLTZ || + Opcode == NDS32::BEQC || + Opcode == NDS32::BNEC || + Opcode == NDS32::BEQZ38 || + Opcode == NDS32::BNEZ38) + return true; + return false; +} + +static bool isIndirectBranch(unsigned Opcode) { + if (Opcode == NDS32::JR || + Opcode == NDS32::JR_TOFF || + Opcode == NDS32::JR_ITOFF || + Opcode == NDS32::JRNEZ || + Opcode == NDS32::JR5) + return true; + return false; +} + +void NDS32InstrInfo::BuildCondBr(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + const DebugLoc &DL, + ArrayRef Cond) const { + unsigned Opc = Cond[0].getImm(); + const MCInstrDesc &MCID = get(Opc); + MachineInstrBuilder MIB = BuildMI(&MBB, DL, MCID); + + for (unsigned i = 1; i < Cond.size(); ++i) { + if (Cond[i].isReg()) + MIB.addReg(Cond[i].getReg()); + else if (Cond[i].isImm()) + MIB.addImm(Cond[i].getImm()); + else + assert(false && "Cannot copy operand"); + } + MIB.addMBB(TBB); +} + +unsigned NDS32InstrInfo::insertBranch(MachineBasicBlock &MBB, + MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + ArrayRef Cond, + const DebugLoc &DL, + int *BytesAdded) const { + // Shouldn't be a fall through. + assert(TBB && "InsertBranch must not be told to insert a fallthrough"); + + // Two-way Conditional branch. + if (FBB) { + BuildCondBr(MBB, TBB, DL, Cond); + BuildMI(&MBB, DL, get(NDS32::J)).addMBB(FBB); + return 2; + } + + // One way branch. + // Unconditional branch. + if (Cond.empty()) + BuildMI(&MBB, DL, get(NDS32::J)).addMBB(TBB); + else // Conditional branch. + BuildCondBr(MBB, TBB, DL, Cond); + return 1; +} + +// removeBranch will remove last branch or last two +// conditional and unconditional branches which let BranchFolding +// could do the right thing. +unsigned NDS32InstrInfo::removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved) const { + assert(!BytesRemoved && "code size not handled"); + + MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); + if (I == MBB.end()) + return 0; + + if (!isUncondBranch(I->getOpcode()) && + !isCondBranch(I->getOpcode())) + return 0; + + // Remove the branch. + I->eraseFromParent(); + + I = MBB.end(); + + if (I == MBB.begin()) return 1; + --I; + if (!isCondBranch(I->getOpcode())) + return 1; + + // Remove the branch. + I->eraseFromParent(); + return 2; +} + +bool NDS32InstrInfo:: +reverseBranchCondition(SmallVectorImpl &Cond) const { + + return true; +} + +void NDS32InstrInfo::AnalyzeCondBr(const MachineInstr *Inst, unsigned Opc, + MachineBasicBlock *&BB, + SmallVectorImpl &Cond) const { + int NumOp = Inst->getNumExplicitOperands(); + + // for both int and fp branches, the last explicit operand is the + // MBB. + BB = Inst->getOperand(NumOp-1).getMBB(); + Cond.push_back(MachineOperand::CreateImm(Opc)); + + for (int i=0; igetOperand(i)); +} + +bool NDS32InstrInfo::analyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const { + // Start from the bottom of the block and work up, examining the + // terminator instructions. + MachineBasicBlock::iterator I = MBB.end(); + while (I != MBB.begin()) { + --I; + if (I->isDebugValue()) + continue; + + // Working from the bottom, when we see a non-terminator + // instruction, we're done. + if (!isUnpredicatedTerminator(*I)) + break; + + // A terminator that isn't a branch can't easily be handled + // by this analysis. + if (!I->isBranch()) + return true; + + // Cannot handle indirect branches. + if (isIndirectBranch (I->getOpcode())) + return true; + + // Handle unconditional branches. + if (isUncondBranch (I->getOpcode())) { + if (!AllowModify) { + TBB = I->getOperand(0).getMBB(); + continue; + } + + // If the block has any instructions after a J, delete them. + while (std::next(I) != MBB.end()) + std::next(I)->eraseFromParent(); + Cond.clear(); + FBB = nullptr; + + // Delete the J if it's equivalent to a fall-through. + if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) { + TBB = nullptr; + I->eraseFromParent(); + I = MBB.end(); + continue; + } + + // TBB is used to indicate the unconditinal destination. + TBB = I->getOperand(0).getMBB(); + continue; + } + + // Handle conditional branches. + if (isCondBranch (I->getOpcode())) { + // Working from the bottom, handle the first conditional branch. + if (!Cond.empty()) + return true; + + FBB = TBB; + MachineInstr *LastInst = &*I; + AnalyzeCondBr(LastInst, I->getOpcode(), TBB, Cond); + return false; + } + + return true; + } + + return false; +} + +bool NDS32InstrInfo::expandPostRAPseudo(MachineInstr &MI) const { + if (MI.getOpcode() == NDS32::MEMCPY) { + expandMEMCPY(MI); + return true; + } + return false; +} + +void NDS32InstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const { + const NDS32InstrInfo *TII = Subtarget.getInstrInfo(); + + DebugLoc dl = MI->getDebugLoc(); + MachineBasicBlock *BB = MI->getParent(); + + MachineInstrBuilder LDM, STM; + + unsigned SrcBaseReg = MI->getOperand(0).getReg(); + unsigned DstBaseReg = MI->getOperand(1).getReg(); + + // Sort the scratch registers into ascending order. + const TargetRegisterInfo &TRI = getRegisterInfo(); + llvm::SmallVector ScratchRegs; + for(unsigned I = 5; I < MI->getNumOperands(); ++I) + ScratchRegs.push_back(MI->getOperand(I).getReg()); + std::sort(ScratchRegs.begin(), ScratchRegs.end(), + [&TRI](const unsigned &Reg1, + const unsigned &Reg2) -> bool { + return TRI.getEncodingValue(Reg1) < + TRI.getEncodingValue(Reg2); + }); + + LDM = BuildMI(*BB, MI, dl, TII->get(NDS32::LMW_BIM)); + STM = BuildMI(*BB, MI, dl, TII->get(NDS32::SMW_BIM)); + LDM.addReg(DstBaseReg, RegState::Define); // add $wb + STM.addReg(SrcBaseReg, RegState::Define); // add $wb + LDM.addReg(DstBaseReg, RegState::Define); // add BaseReg [Ra] + STM.addReg(SrcBaseReg, RegState::Define); // add BaseReg [Ra] + + unsigned LastReg = 0; + for (const auto &Reg : ScratchRegs) { + if (LastReg) { + // Split to another multiple load/store pair + // when the register number not continuous + if (LastReg + 1 != Reg) { + // create another multiple load/store pair + LDM = BuildMI(*BB, MI, dl, TII->get(NDS32::LMW_BIM)); + STM = BuildMI(*BB, MI, dl, TII->get(NDS32::SMW_BIM)); + LDM.addReg(DstBaseReg, RegState::Define); // add $wb + STM.addReg(SrcBaseReg, RegState::Define); // add $wb + LDM.addReg(DstBaseReg, RegState::Define); // add BaseReg [Ra] + STM.addReg(SrcBaseReg, RegState::Define); // add BaseReg [Ra] + } + } + LDM.addReg(Reg, RegState::Define); // add Register list + STM.addReg(Reg, RegState::Kill); // add Register list + LastReg = Reg; + } + + BB->erase(MI); +}