diff options
Diffstat (limited to 'llvm/lib/Target/RISCV/RISCVInstrInfo.cpp')
-rw-r--r-- | llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 259 |
1 files changed, 256 insertions, 3 deletions
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp index 084839299530..3b416ce3d3f4 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -24,6 +24,9 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetRegistry.h" +#define GEN_CHECK_COMPRESS_INSTR +#include "RISCVGenCompressInstEmitter.inc" + #define GET_INSTRINFO_CTOR_DTOR #include "RISCVGenInstrInfo.inc" @@ -84,8 +87,8 @@ unsigned RISCVInstrInfo::isStoreToStackSlot(const MachineInstr &MI, void RISCVInstrInfo::copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, - const DebugLoc &DL, unsigned DstReg, - unsigned SrcReg, bool KillSrc) const { + const DebugLoc &DL, MCRegister DstReg, + MCRegister SrcReg, bool KillSrc) const { if (RISCV::GPRRegClass.contains(DstReg, SrcReg)) { BuildMI(MBB, MBBI, DL, get(RISCV::ADDI), DstReg) .addReg(SrcReg, getKillRegState(KillSrc)) @@ -451,7 +454,18 @@ unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { unsigned Opcode = MI.getOpcode(); switch (Opcode) { - default: { return get(Opcode).getSize(); } + default: { + if (MI.getParent() && MI.getParent()->getParent()) { + const auto MF = MI.getMF(); + const auto &TM = static_cast<const RISCVTargetMachine &>(MF->getTarget()); + const MCRegisterInfo &MRI = *TM.getMCRegisterInfo(); + const MCSubtargetInfo &STI = *TM.getMCSubtargetInfo(); + const RISCVSubtarget &ST = MF->getSubtarget<RISCVSubtarget>(); + if (isCompressibleInst(MI, &ST, MRI, STI)) + return 2; + } + return get(Opcode).getSize(); + } case TargetOpcode::EH_LABEL: case TargetOpcode::IMPLICIT_DEF: case TargetOpcode::KILL: @@ -542,3 +556,242 @@ bool RISCVInstrInfo::verifyInstruction(const MachineInstr &MI, return true; } + +// Return true if get the base operand, byte offset of an instruction and the +// memory width. Width is the size of memory that is being loaded/stored. +bool RISCVInstrInfo::getMemOperandWithOffsetWidth( + const MachineInstr &LdSt, const MachineOperand *&BaseReg, int64_t &Offset, + unsigned &Width, const TargetRegisterInfo *TRI) const { + if (!LdSt.mayLoadOrStore()) + return false; + + // Here we assume the standard RISC-V ISA, which uses a base+offset + // addressing mode. You'll need to relax these conditions to support custom + // load/stores instructions. + if (LdSt.getNumExplicitOperands() != 3) + return false; + if (!LdSt.getOperand(1).isReg() || !LdSt.getOperand(2).isImm()) + return false; + + if (!LdSt.hasOneMemOperand()) + return false; + + Width = (*LdSt.memoperands_begin())->getSize(); + BaseReg = &LdSt.getOperand(1); + Offset = LdSt.getOperand(2).getImm(); + return true; +} + +bool RISCVInstrInfo::areMemAccessesTriviallyDisjoint( + const MachineInstr &MIa, const MachineInstr &MIb) const { + assert(MIa.mayLoadOrStore() && "MIa must be a load or store."); + assert(MIb.mayLoadOrStore() && "MIb must be a load or store."); + + if (MIa.hasUnmodeledSideEffects() || MIb.hasUnmodeledSideEffects() || + MIa.hasOrderedMemoryRef() || MIb.hasOrderedMemoryRef()) + return false; + + // Retrieve the base register, offset from the base register and width. Width + // is the size of memory that is being loaded/stored (e.g. 1, 2, 4). If + // base registers are identical, and the offset of a lower memory access + + // the width doesn't overlap the offset of a higher memory access, + // then the memory accesses are different. + const TargetRegisterInfo *TRI = STI.getRegisterInfo(); + const MachineOperand *BaseOpA = nullptr, *BaseOpB = nullptr; + int64_t OffsetA = 0, OffsetB = 0; + unsigned int WidthA = 0, WidthB = 0; + if (getMemOperandWithOffsetWidth(MIa, BaseOpA, OffsetA, WidthA, TRI) && + getMemOperandWithOffsetWidth(MIb, BaseOpB, OffsetB, WidthB, TRI)) { + if (BaseOpA->isIdenticalTo(*BaseOpB)) { + int LowOffset = std::min(OffsetA, OffsetB); + int HighOffset = std::max(OffsetA, OffsetB); + int LowWidth = (LowOffset == OffsetA) ? WidthA : WidthB; + if (LowOffset + LowWidth <= HighOffset) + return true; + } + } + return false; +} + +std::pair<unsigned, unsigned> +RISCVInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const { + const unsigned Mask = RISCVII::MO_DIRECT_FLAG_MASK; + return std::make_pair(TF & Mask, TF & ~Mask); +} + +ArrayRef<std::pair<unsigned, const char *>> +RISCVInstrInfo::getSerializableDirectMachineOperandTargetFlags() const { + using namespace RISCVII; + static const std::pair<unsigned, const char *> TargetFlags[] = { + {MO_CALL, "riscv-call"}, + {MO_PLT, "riscv-plt"}, + {MO_LO, "riscv-lo"}, + {MO_HI, "riscv-hi"}, + {MO_PCREL_LO, "riscv-pcrel-lo"}, + {MO_PCREL_HI, "riscv-pcrel-hi"}, + {MO_GOT_HI, "riscv-got-hi"}, + {MO_TPREL_LO, "riscv-tprel-lo"}, + {MO_TPREL_HI, "riscv-tprel-hi"}, + {MO_TPREL_ADD, "riscv-tprel-add"}, + {MO_TLS_GOT_HI, "riscv-tls-got-hi"}, + {MO_TLS_GD_HI, "riscv-tls-gd-hi"}}; + return makeArrayRef(TargetFlags); +} +bool RISCVInstrInfo::isFunctionSafeToOutlineFrom( + MachineFunction &MF, bool OutlineFromLinkOnceODRs) const { + const Function &F = MF.getFunction(); + + // Can F be deduplicated by the linker? If it can, don't outline from it. + if (!OutlineFromLinkOnceODRs && F.hasLinkOnceODRLinkage()) + return false; + + // Don't outline from functions with section markings; the program could + // expect that all the code is in the named section. + if (F.hasSection()) + return false; + + // It's safe to outline from MF. + return true; +} + +bool RISCVInstrInfo::isMBBSafeToOutlineFrom(MachineBasicBlock &MBB, + unsigned &Flags) const { + // More accurate safety checking is done in getOutliningCandidateInfo. + return true; +} + +// Enum values indicating how an outlined call should be constructed. +enum MachineOutlinerConstructionID { + MachineOutlinerDefault +}; + +outliner::OutlinedFunction RISCVInstrInfo::getOutliningCandidateInfo( + std::vector<outliner::Candidate> &RepeatedSequenceLocs) const { + + // First we need to filter out candidates where the X5 register (IE t0) can't + // be used to setup the function call. + auto CannotInsertCall = [](outliner::Candidate &C) { + const TargetRegisterInfo *TRI = C.getMF()->getSubtarget().getRegisterInfo(); + + C.initLRU(*TRI); + LiveRegUnits LRU = C.LRU; + return !LRU.available(RISCV::X5); + }; + + RepeatedSequenceLocs.erase(std::remove_if(RepeatedSequenceLocs.begin(), + RepeatedSequenceLocs.end(), + CannotInsertCall), + RepeatedSequenceLocs.end()); + + // If the sequence doesn't have enough candidates left, then we're done. + if (RepeatedSequenceLocs.size() < 2) + return outliner::OutlinedFunction(); + + unsigned SequenceSize = 0; + + auto I = RepeatedSequenceLocs[0].front(); + auto E = std::next(RepeatedSequenceLocs[0].back()); + for (; I != E; ++I) + SequenceSize += getInstSizeInBytes(*I); + + // call t0, function = 8 bytes. + unsigned CallOverhead = 8; + for (auto &C : RepeatedSequenceLocs) + C.setCallInfo(MachineOutlinerDefault, CallOverhead); + + // jr t0 = 4 bytes, 2 bytes if compressed instructions are enabled. + unsigned FrameOverhead = 4; + if (RepeatedSequenceLocs[0].getMF()->getSubtarget() + .getFeatureBits()[RISCV::FeatureStdExtC]) + FrameOverhead = 2; + + return outliner::OutlinedFunction(RepeatedSequenceLocs, SequenceSize, + FrameOverhead, MachineOutlinerDefault); +} + +outliner::InstrType +RISCVInstrInfo::getOutliningType(MachineBasicBlock::iterator &MBBI, + unsigned Flags) const { + MachineInstr &MI = *MBBI; + MachineBasicBlock *MBB = MI.getParent(); + const TargetRegisterInfo *TRI = + MBB->getParent()->getSubtarget().getRegisterInfo(); + + // Positions generally can't safely be outlined. + if (MI.isPosition()) { + // We can manually strip out CFI instructions later. + if (MI.isCFIInstruction()) + return outliner::InstrType::Invisible; + + return outliner::InstrType::Illegal; + } + + // Don't trust the user to write safe inline assembly. + if (MI.isInlineAsm()) + return outliner::InstrType::Illegal; + + // We can't outline branches to other basic blocks. + if (MI.isTerminator() && !MBB->succ_empty()) + return outliner::InstrType::Illegal; + + // We need support for tail calls to outlined functions before return + // statements can be allowed. + if (MI.isReturn()) + return outliner::InstrType::Illegal; + + // Don't allow modifying the X5 register which we use for return addresses for + // these outlined functions. + if (MI.modifiesRegister(RISCV::X5, TRI) || + MI.getDesc().hasImplicitDefOfPhysReg(RISCV::X5)) + return outliner::InstrType::Illegal; + + // Make sure the operands don't reference something unsafe. + for (const auto &MO : MI.operands()) + if (MO.isMBB() || MO.isBlockAddress() || MO.isCPI()) + return outliner::InstrType::Illegal; + + // Don't allow instructions which won't be materialized to impact outlining + // analysis. + if (MI.isMetaInstruction()) + return outliner::InstrType::Invisible; + + return outliner::InstrType::Legal; +} + +void RISCVInstrInfo::buildOutlinedFrame( + MachineBasicBlock &MBB, MachineFunction &MF, + const outliner::OutlinedFunction &OF) const { + + // Strip out any CFI instructions + bool Changed = true; + while (Changed) { + Changed = false; + auto I = MBB.begin(); + auto E = MBB.end(); + for (; I != E; ++I) { + if (I->isCFIInstruction()) { + I->removeFromParent(); + Changed = true; + break; + } + } + } + + // Add in a return instruction to the end of the outlined frame. + MBB.insert(MBB.end(), BuildMI(MF, DebugLoc(), get(RISCV::JALR)) + .addReg(RISCV::X0, RegState::Define) + .addReg(RISCV::X5) + .addImm(0)); +} + +MachineBasicBlock::iterator RISCVInstrInfo::insertOutlinedCall( + Module &M, MachineBasicBlock &MBB, MachineBasicBlock::iterator &It, + MachineFunction &MF, const outliner::Candidate &C) const { + + // Add in a call instruction to the outlined function at the given location. + It = MBB.insert(It, + BuildMI(MF, DebugLoc(), get(RISCV::PseudoCALLReg), RISCV::X5) + .addGlobalAddress(M.getNamedValue(MF.getName()), 0, + RISCVII::MO_CALL)); + return It; +} |