//===- HexagonMCInstrInfo.cpp - Hexagon sub-class of MCInst ---------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This class extends MCInstrInfo to allow Hexagon specific MCInstr queries // //===----------------------------------------------------------------------===// #include "MCTargetDesc/HexagonMCInstrInfo.h" #include "MCTargetDesc/HexagonBaseInfo.h" #include "MCTargetDesc/HexagonMCChecker.h" #include "MCTargetDesc/HexagonMCExpr.h" #include "MCTargetDesc/HexagonMCShuffler.h" #include "MCTargetDesc/HexagonMCTargetDesc.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCInstrItineraries.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include #include #include using namespace llvm; bool HexagonMCInstrInfo::PredicateInfo::isPredicated() const { return Register != Hexagon::NoRegister; } Hexagon::PacketIterator::PacketIterator(MCInstrInfo const &MCII, MCInst const &Inst) : MCII(MCII), BundleCurrent(Inst.begin() + HexagonMCInstrInfo::bundleInstructionsOffset), BundleEnd(Inst.end()), DuplexCurrent(Inst.end()), DuplexEnd(Inst.end()) {} Hexagon::PacketIterator::PacketIterator(MCInstrInfo const &MCII, MCInst const &Inst, std::nullptr_t) : MCII(MCII), BundleCurrent(Inst.end()), BundleEnd(Inst.end()), DuplexCurrent(Inst.end()), DuplexEnd(Inst.end()) {} Hexagon::PacketIterator &Hexagon::PacketIterator::operator++() { if (DuplexCurrent != DuplexEnd) { ++DuplexCurrent; if (DuplexCurrent == DuplexEnd) { DuplexCurrent = BundleEnd; DuplexEnd = BundleEnd; ++BundleCurrent; } return *this; } ++BundleCurrent; if (BundleCurrent != BundleEnd) { MCInst const &Inst = *BundleCurrent->getInst(); if (HexagonMCInstrInfo::isDuplex(MCII, Inst)) { DuplexCurrent = Inst.begin(); DuplexEnd = Inst.end(); } } return *this; } MCInst const &Hexagon::PacketIterator::operator*() const { if (DuplexCurrent != DuplexEnd) return *DuplexCurrent->getInst(); return *BundleCurrent->getInst(); } bool Hexagon::PacketIterator::operator==(PacketIterator const &Other) const { return BundleCurrent == Other.BundleCurrent && BundleEnd == Other.BundleEnd && DuplexCurrent == Other.DuplexCurrent && DuplexEnd == Other.DuplexEnd; } void HexagonMCInstrInfo::addConstant(MCInst &MI, uint64_t Value, MCContext &Context) { MI.addOperand(MCOperand::createExpr(MCConstantExpr::create(Value, Context))); } void HexagonMCInstrInfo::addConstExtender(MCContext &Context, MCInstrInfo const &MCII, MCInst &MCB, MCInst const &MCI) { assert(HexagonMCInstrInfo::isBundle(MCB)); MCOperand const &exOp = MCI.getOperand(HexagonMCInstrInfo::getExtendableOp(MCII, MCI)); // Create the extender. MCInst *XMCI = new (Context) MCInst(HexagonMCInstrInfo::deriveExtender(MCII, MCI, exOp)); XMCI->setLoc(MCI.getLoc()); MCB.addOperand(MCOperand::createInst(XMCI)); } iterator_range HexagonMCInstrInfo::bundleInstructions(MCInstrInfo const &MCII, MCInst const &MCI) { assert(isBundle(MCI)); return make_range(Hexagon::PacketIterator(MCII, MCI), Hexagon::PacketIterator(MCII, MCI, nullptr)); } iterator_range HexagonMCInstrInfo::bundleInstructions(MCInst const &MCI) { assert(isBundle(MCI)); return drop_begin(MCI, bundleInstructionsOffset); } size_t HexagonMCInstrInfo::bundleSize(MCInst const &MCI) { if (HexagonMCInstrInfo::isBundle(MCI)) return (MCI.size() - bundleInstructionsOffset); else return (1); } namespace { bool canonicalizePacketImpl(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCContext &Context, MCInst &MCB, HexagonMCChecker *Check) { // Check the bundle for errors. bool CheckOk = Check ? Check->check(false) : true; if (!CheckOk) return false; MCInst OrigMCB = MCB; // Examine the packet and convert pairs of instructions to compound // instructions when possible. if (!HexagonDisableCompound) HexagonMCInstrInfo::tryCompound(MCII, STI, Context, MCB); HexagonMCShuffle(Context, false, MCII, STI, MCB); const SmallVector possibleDuplexes = (STI.hasFeature(Hexagon::FeatureDuplex)) ? HexagonMCInstrInfo::getDuplexPossibilties(MCII, STI, MCB) : SmallVector(); // Examine the packet and convert pairs of instructions to duplex // instructions when possible. HexagonMCShuffle(Context, MCII, STI, MCB, possibleDuplexes); // Examines packet and pad the packet, if needed, when an // end-loop is in the bundle. HexagonMCInstrInfo::padEndloop(MCB, Context); // If compounding and duplexing didn't reduce the size below // 4 or less we have a packet that is too big. if (HexagonMCInstrInfo::bundleSize(MCB) > HEXAGON_PACKET_SIZE) { if (Check) Check->reportError("invalid instruction packet: out of slots"); return false; } // Check the bundle for errors. CheckOk = Check ? Check->check(true) : true; if (!CheckOk) return false; HexagonMCShuffle(Context, true, MCII, STI, MCB); return true; } } // namespace bool HexagonMCInstrInfo::canonicalizePacket(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCContext &Context, MCInst &MCB, HexagonMCChecker *Check, bool AttemptCompatibility) { auto ArchSTI = Hexagon_MC::getArchSubtarget(&STI); if (!AttemptCompatibility || ArchSTI == nullptr) return canonicalizePacketImpl(MCII, STI, Context, MCB, Check); const MCRegisterInfo *RI = Context.getRegisterInfo(); HexagonMCChecker DefaultCheck(Context, MCII, STI, MCB, *RI, false); HexagonMCChecker *BaseCheck = (Check == nullptr) ? &DefaultCheck : Check; HexagonMCChecker PerfCheck(*BaseCheck, STI, false); if (canonicalizePacketImpl(MCII, STI, Context, MCB, &PerfCheck)) return true; HexagonMCChecker ArchCheck(*BaseCheck, *ArchSTI, true); return canonicalizePacketImpl(MCII, *ArchSTI, Context, MCB, &ArchCheck); } MCInst HexagonMCInstrInfo::deriveExtender(MCInstrInfo const &MCII, MCInst const &Inst, MCOperand const &MO) { assert(HexagonMCInstrInfo::isExtendable(MCII, Inst) || HexagonMCInstrInfo::isExtended(MCII, Inst)); MCInst XMI; XMI.setOpcode(Hexagon::A4_ext); if (MO.isImm()) XMI.addOperand(MCOperand::createImm(MO.getImm() & (~0x3f))); else if (MO.isExpr()) XMI.addOperand(MCOperand::createExpr(MO.getExpr())); else llvm_unreachable("invalid extendable operand"); return XMI; } MCInst *HexagonMCInstrInfo::deriveDuplex(MCContext &Context, unsigned iClass, MCInst const &inst0, MCInst const &inst1) { assert((iClass <= 0xf) && "iClass must have range of 0 to 0xf"); MCInst *duplexInst = new (Context) MCInst; duplexInst->setOpcode(Hexagon::DuplexIClass0 + iClass); MCInst *SubInst0 = new (Context) MCInst(deriveSubInst(inst0)); MCInst *SubInst1 = new (Context) MCInst(deriveSubInst(inst1)); duplexInst->addOperand(MCOperand::createInst(SubInst0)); duplexInst->addOperand(MCOperand::createInst(SubInst1)); return duplexInst; } MCInst const *HexagonMCInstrInfo::extenderForIndex(MCInst const &MCB, size_t Index) { assert(Index <= bundleSize(MCB)); if (Index == 0) return nullptr; MCInst const *Inst = MCB.getOperand(Index + bundleInstructionsOffset - 1).getInst(); if (isImmext(*Inst)) return Inst; return nullptr; } void HexagonMCInstrInfo::extendIfNeeded(MCContext &Context, MCInstrInfo const &MCII, MCInst &MCB, MCInst const &MCI) { if (isConstExtended(MCII, MCI)) addConstExtender(Context, MCII, MCB, MCI); } unsigned HexagonMCInstrInfo::getMemAccessSize(MCInstrInfo const &MCII, MCInst const &MCI) { uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; unsigned S = (F >> HexagonII::MemAccessSizePos) & HexagonII::MemAccesSizeMask; return HexagonII::getMemAccessSizeInBytes(HexagonII::MemAccessSize(S)); } unsigned HexagonMCInstrInfo::getAddrMode(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return static_cast((F >> HexagonII::AddrModePos) & HexagonII::AddrModeMask); } MCInstrDesc const &HexagonMCInstrInfo::getDesc(MCInstrInfo const &MCII, MCInst const &MCI) { return MCII.get(MCI.getOpcode()); } unsigned HexagonMCInstrInfo::getDuplexRegisterNumbering(unsigned Reg) { using namespace Hexagon; switch (Reg) { default: llvm_unreachable("unknown duplex register"); // Rs Rss case R0: case D0: return 0; case R1: case D1: return 1; case R2: case D2: return 2; case R3: case D3: return 3; case R4: case D8: return 4; case R5: case D9: return 5; case R6: case D10: return 6; case R7: case D11: return 7; case R16: return 8; case R17: return 9; case R18: return 10; case R19: return 11; case R20: return 12; case R21: return 13; case R22: return 14; case R23: return 15; } } MCExpr const &HexagonMCInstrInfo::getExpr(MCExpr const &Expr) { const auto &HExpr = cast(Expr); assert(HExpr.getExpr()); return *HExpr.getExpr(); } unsigned short HexagonMCInstrInfo::getExtendableOp(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::ExtendableOpPos) & HexagonII::ExtendableOpMask); } MCOperand const & HexagonMCInstrInfo::getExtendableOperand(MCInstrInfo const &MCII, MCInst const &MCI) { unsigned O = HexagonMCInstrInfo::getExtendableOp(MCII, MCI); MCOperand const &MO = MCI.getOperand(O); assert((HexagonMCInstrInfo::isExtendable(MCII, MCI) || HexagonMCInstrInfo::isExtended(MCII, MCI)) && (MO.isImm() || MO.isExpr())); return (MO); } unsigned HexagonMCInstrInfo::getExtentAlignment(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::ExtentAlignPos) & HexagonII::ExtentAlignMask); } unsigned HexagonMCInstrInfo::getExtentBits(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::ExtentBitsPos) & HexagonII::ExtentBitsMask); } bool HexagonMCInstrInfo::isExtentSigned(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return (F >> HexagonII::ExtentSignedPos) & HexagonII::ExtentSignedMask; } /// Return the maximum value of an extendable operand. int HexagonMCInstrInfo::getMaxValue(MCInstrInfo const &MCII, MCInst const &MCI) { assert(HexagonMCInstrInfo::isExtendable(MCII, MCI) || HexagonMCInstrInfo::isExtended(MCII, MCI)); if (HexagonMCInstrInfo::isExtentSigned(MCII, MCI)) // if value is signed return (1 << (HexagonMCInstrInfo::getExtentBits(MCII, MCI) - 1)) - 1; return (1 << HexagonMCInstrInfo::getExtentBits(MCII, MCI)) - 1; } /// Return the minimum value of an extendable operand. int HexagonMCInstrInfo::getMinValue(MCInstrInfo const &MCII, MCInst const &MCI) { assert(HexagonMCInstrInfo::isExtendable(MCII, MCI) || HexagonMCInstrInfo::isExtended(MCII, MCI)); if (HexagonMCInstrInfo::isExtentSigned(MCII, MCI)) // if value is signed return -(1 << (HexagonMCInstrInfo::getExtentBits(MCII, MCI) - 1)); return 0; } StringRef HexagonMCInstrInfo::getName(MCInstrInfo const &MCII, MCInst const &MCI) { return MCII.getName(MCI.getOpcode()); } unsigned short HexagonMCInstrInfo::getNewValueOp(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::NewValueOpPos) & HexagonII::NewValueOpMask); } MCOperand const &HexagonMCInstrInfo::getNewValueOperand(MCInstrInfo const &MCII, MCInst const &MCI) { if (HexagonMCInstrInfo::hasTmpDst(MCII, MCI)) { // VTMP doesn't actually exist in the encodings for these 184 // 3 instructions so go ahead and create it here. static MCOperand MCO = MCOperand::createReg(Hexagon::VTMP); return (MCO); } else { unsigned O = HexagonMCInstrInfo::getNewValueOp(MCII, MCI); MCOperand const &MCO = MCI.getOperand(O); assert((HexagonMCInstrInfo::isNewValue(MCII, MCI) || HexagonMCInstrInfo::hasNewValue(MCII, MCI)) && MCO.isReg()); return (MCO); } } /// Return the new value or the newly produced value. unsigned short HexagonMCInstrInfo::getNewValueOp2(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::NewValueOpPos2) & HexagonII::NewValueOpMask2); } MCOperand const & HexagonMCInstrInfo::getNewValueOperand2(MCInstrInfo const &MCII, MCInst const &MCI) { unsigned O = HexagonMCInstrInfo::getNewValueOp2(MCII, MCI); MCOperand const &MCO = MCI.getOperand(O); assert((HexagonMCInstrInfo::isNewValue(MCII, MCI) || HexagonMCInstrInfo::hasNewValue2(MCII, MCI)) && MCO.isReg()); return (MCO); } /// Return the Hexagon ISA class for the insn. unsigned HexagonMCInstrInfo::getType(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = MCII.get(MCI.getOpcode()).TSFlags; return ((F >> HexagonII::TypePos) & HexagonII::TypeMask); } /// Return the resources used by this instruction unsigned HexagonMCInstrInfo::getCVIResources(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCInst const &MCI) { const InstrItinerary *II = STI.getSchedModel().InstrItineraries; int SchedClass = HexagonMCInstrInfo::getDesc(MCII, MCI).getSchedClass(); int Size = II[SchedClass].LastStage - II[SchedClass].FirstStage; // HVX resources used are currenty located at the second to last stage. // This could also be done with a linear search of the stages looking for: // CVI_ALL, CVI_MPY01, CVI_XLSHF, CVI_MPY0, CVI_MPY1, CVI_SHIFT, CVI_XLANE, // CVI_ZW unsigned Stage = II[SchedClass].LastStage - 1; if (Size < 2) return 0; return ((Stage + HexagonStages)->getUnits()); } /// Return the slots this instruction can execute out of unsigned HexagonMCInstrInfo::getUnits(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCInst const &MCI) { const InstrItinerary *II = STI.getSchedModel().InstrItineraries; int SchedClass = HexagonMCInstrInfo::getDesc(MCII, MCI).getSchedClass(); return ((II[SchedClass].FirstStage + HexagonStages)->getUnits()); } /// Return the slots this instruction consumes in addition to /// the slot(s) it can execute out of unsigned HexagonMCInstrInfo::getOtherReservedSlots(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCInst const &MCI) { const InstrItinerary *II = STI.getSchedModel().InstrItineraries; int SchedClass = HexagonMCInstrInfo::getDesc(MCII, MCI).getSchedClass(); unsigned Slots = 0; // FirstStage are slots that this instruction can execute in. // FirstStage+1 are slots that are also consumed by this instruction. // For example: vmemu can only execute in slot 0 but also consumes slot 1. for (unsigned Stage = II[SchedClass].FirstStage + 1; Stage < II[SchedClass].LastStage; ++Stage) { unsigned Units = (Stage + HexagonStages)->getUnits(); if (Units > HexagonGetLastSlot()) break; // fyi: getUnits() will return 0x1, 0x2, 0x4 or 0x8 Slots |= Units; } // if 0 is returned, then no additional slots are consumed by this inst. return Slots; } bool HexagonMCInstrInfo::hasDuplex(MCInstrInfo const &MCII, MCInst const &MCI) { if (!HexagonMCInstrInfo::isBundle(MCI)) return false; for (auto const &I : HexagonMCInstrInfo::bundleInstructions(MCI)) { if (HexagonMCInstrInfo::isDuplex(MCII, *I.getInst())) return true; } return false; } bool HexagonMCInstrInfo::hasExtenderForIndex(MCInst const &MCB, size_t Index) { return extenderForIndex(MCB, Index) != nullptr; } bool HexagonMCInstrInfo::hasImmExt(MCInst const &MCI) { if (!HexagonMCInstrInfo::isBundle(MCI)) return false; for (const auto &I : HexagonMCInstrInfo::bundleInstructions(MCI)) { if (isImmext(*I.getInst())) return true; } return false; } /// Return whether the insn produces a value. bool HexagonMCInstrInfo::hasNewValue(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::hasNewValuePos) & HexagonII::hasNewValueMask); } /// Return whether the insn produces a second value. bool HexagonMCInstrInfo::hasNewValue2(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::hasNewValuePos2) & HexagonII::hasNewValueMask2); } MCInst const &HexagonMCInstrInfo::instruction(MCInst const &MCB, size_t Index) { assert(isBundle(MCB)); assert(Index < HEXAGON_PRESHUFFLE_PACKET_SIZE); return *MCB.getOperand(bundleInstructionsOffset + Index).getInst(); } /// Return where the instruction is an accumulator. bool HexagonMCInstrInfo::isAccumulator(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::AccumulatorPos) & HexagonII::AccumulatorMask); } bool HexagonMCInstrInfo::isBundle(MCInst const &MCI) { auto Result = Hexagon::BUNDLE == MCI.getOpcode(); assert(!Result || (MCI.size() > 0 && MCI.getOperand(0).isImm())); return Result; } bool HexagonMCInstrInfo::isConstExtended(MCInstrInfo const &MCII, MCInst const &MCI) { if (HexagonMCInstrInfo::isExtended(MCII, MCI)) return true; if (!HexagonMCInstrInfo::isExtendable(MCII, MCI)) return false; MCOperand const &MO = HexagonMCInstrInfo::getExtendableOperand(MCII, MCI); if (isa(MO.getExpr()) && HexagonMCInstrInfo::mustExtend(*MO.getExpr())) return true; // Branch insns are handled as necessary by relaxation. if ((HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeJ) || (HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeCJ && HexagonMCInstrInfo::getDesc(MCII, MCI).isBranch()) || (HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeNCJ && HexagonMCInstrInfo::getDesc(MCII, MCI).isBranch())) return false; // Otherwise loop instructions and other CR insts are handled by relaxation else if ((HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeCR) && (MCI.getOpcode() != Hexagon::C4_addipc)) return false; assert(!MO.isImm()); if (isa(MO.getExpr()) && HexagonMCInstrInfo::mustNotExtend(*MO.getExpr())) return false; int64_t Value; if (!MO.getExpr()->evaluateAsAbsolute(Value)) return true; if (HexagonMCInstrInfo::isExtentSigned(MCII, MCI)) { int32_t SValue = Value; int32_t MinValue = HexagonMCInstrInfo::getMinValue(MCII, MCI); int32_t MaxValue = HexagonMCInstrInfo::getMaxValue(MCII, MCI); return SValue < MinValue || SValue > MaxValue; } uint32_t UValue = Value; uint32_t MinValue = HexagonMCInstrInfo::getMinValue(MCII, MCI); uint32_t MaxValue = HexagonMCInstrInfo::getMaxValue(MCII, MCI); return UValue < MinValue || UValue > MaxValue; } bool HexagonMCInstrInfo::isCanon(MCInstrInfo const &MCII, MCInst const &MCI) { return !HexagonMCInstrInfo::getDesc(MCII, MCI).isPseudo() && !HexagonMCInstrInfo::isPrefix(MCII, MCI); } bool HexagonMCInstrInfo::isCofMax1(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::CofMax1Pos) & HexagonII::CofMax1Mask); } bool HexagonMCInstrInfo::isCofRelax1(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::CofRelax1Pos) & HexagonII::CofRelax1Mask); } bool HexagonMCInstrInfo::isCofRelax2(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::CofRelax2Pos) & HexagonII::CofRelax2Mask); } bool HexagonMCInstrInfo::isCompound(MCInstrInfo const &MCII, MCInst const &MCI) { return (getType(MCII, MCI) == HexagonII::TypeCJ); } bool HexagonMCInstrInfo::isCVINew(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::CVINewPos) & HexagonII::CVINewMask); } bool HexagonMCInstrInfo::isDblRegForSubInst(unsigned Reg) { return ((Reg >= Hexagon::D0 && Reg <= Hexagon::D3) || (Reg >= Hexagon::D8 && Reg <= Hexagon::D11)); } bool HexagonMCInstrInfo::isDuplex(MCInstrInfo const &MCII, MCInst const &MCI) { return HexagonII::TypeDUPLEX == HexagonMCInstrInfo::getType(MCII, MCI); } bool HexagonMCInstrInfo::isExtendable(MCInstrInfo const &MCII, MCInst const &MCI) { uint64_t const F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return (F >> HexagonII::ExtendablePos) & HexagonII::ExtendableMask; } bool HexagonMCInstrInfo::isExtended(MCInstrInfo const &MCII, MCInst const &MCI) { uint64_t const F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return (F >> HexagonII::ExtendedPos) & HexagonII::ExtendedMask; } bool HexagonMCInstrInfo::isFloat(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::FPPos) & HexagonII::FPMask); } bool HexagonMCInstrInfo::isHVX(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t V = getType(MCII, MCI); return HexagonII::TypeCVI_FIRST <= V && V <= HexagonII::TypeCVI_LAST; } bool HexagonMCInstrInfo::isImmext(MCInst const &MCI) { return MCI.getOpcode() == Hexagon::A4_ext; } bool HexagonMCInstrInfo::isInnerLoop(MCInst const &MCI) { assert(isBundle(MCI)); int64_t Flags = MCI.getOperand(0).getImm(); return (Flags & innerLoopMask) != 0; } bool HexagonMCInstrInfo::isIntReg(unsigned Reg) { return (Reg >= Hexagon::R0 && Reg <= Hexagon::R31); } bool HexagonMCInstrInfo::isIntRegForSubInst(unsigned Reg) { return ((Reg >= Hexagon::R0 && Reg <= Hexagon::R7) || (Reg >= Hexagon::R16 && Reg <= Hexagon::R23)); } /// Return whether the insn expects newly produced value. bool HexagonMCInstrInfo::isNewValue(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::NewValuePos) & HexagonII::NewValueMask); } bool HexagonMCInstrInfo::isNewValueStore(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return (F >> HexagonII::NVStorePos) & HexagonII::NVStoreMask; } /// Return whether the operand is extendable. bool HexagonMCInstrInfo::isOpExtendable(MCInstrInfo const &MCII, MCInst const &MCI, unsigned short O) { return (O == HexagonMCInstrInfo::getExtendableOp(MCII, MCI)); } bool HexagonMCInstrInfo::isOuterLoop(MCInst const &MCI) { assert(isBundle(MCI)); int64_t Flags = MCI.getOperand(0).getImm(); return (Flags & outerLoopMask) != 0; } bool HexagonMCInstrInfo::IsVecRegPair(unsigned VecReg) { return (VecReg >= Hexagon::W0 && VecReg <= Hexagon::W15) || (VecReg >= Hexagon::WR0 && VecReg <= Hexagon::WR15); } bool HexagonMCInstrInfo::IsReverseVecRegPair(unsigned VecReg) { return (VecReg >= Hexagon::WR0 && VecReg <= Hexagon::WR15); } bool HexagonMCInstrInfo::IsVecRegSingle(unsigned VecReg) { return (VecReg >= Hexagon::V0 && VecReg <= Hexagon::V31); } std::pair HexagonMCInstrInfo::GetVecRegPairIndices(unsigned VecRegPair) { assert(IsVecRegPair(VecRegPair) && "VecRegPair must be a vector register pair"); const bool IsRev = IsReverseVecRegPair(VecRegPair); const unsigned PairIndex = 2 * (IsRev ? VecRegPair - Hexagon::WR0 : VecRegPair - Hexagon::W0); return IsRev ? std::make_pair(PairIndex, PairIndex + 1) : std::make_pair(PairIndex + 1, PairIndex); } bool HexagonMCInstrInfo::IsSingleConsumerRefPairProducer(unsigned Producer, unsigned Consumer) { if (IsVecRegPair(Producer) && IsVecRegSingle(Consumer)) { const unsigned ProdPairIndex = IsReverseVecRegPair(Producer) ? Producer - Hexagon::WR0 : Producer - Hexagon::W0; const unsigned ConsumerSingleIndex = (Consumer - Hexagon::V0) >> 1; return ConsumerSingleIndex == ProdPairIndex; } return false; } bool HexagonMCInstrInfo::isPredicated(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::PredicatedPos) & HexagonII::PredicatedMask); } bool HexagonMCInstrInfo::isPrefix(MCInstrInfo const &MCII, MCInst const &MCI) { return HexagonII::TypeEXTENDER == HexagonMCInstrInfo::getType(MCII, MCI); } bool HexagonMCInstrInfo::isPredicateLate(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return (F >> HexagonII::PredicateLatePos & HexagonII::PredicateLateMask); } /// Return whether the insn is newly predicated. bool HexagonMCInstrInfo::isPredicatedNew(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::PredicatedNewPos) & HexagonII::PredicatedNewMask); } bool HexagonMCInstrInfo::isPredicatedTrue(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ( !((F >> HexagonII::PredicatedFalsePos) & HexagonII::PredicatedFalseMask)); } bool HexagonMCInstrInfo::isPredReg(MCRegisterInfo const &MRI, unsigned Reg) { auto &PredRegClass = MRI.getRegClass(Hexagon::PredRegsRegClassID); return PredRegClass.contains(Reg); } bool HexagonMCInstrInfo::isPredRegister(MCInstrInfo const &MCII, MCInst const &Inst, unsigned I) { MCInstrDesc const &Desc = HexagonMCInstrInfo::getDesc(MCII, Inst); return Inst.getOperand(I).isReg() && Desc.operands()[I].RegClass == Hexagon::PredRegsRegClassID; } /// Return whether the insn can be packaged only with A and X-type insns. bool HexagonMCInstrInfo::isSoloAX(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::SoloAXPos) & HexagonII::SoloAXMask); } /// Return whether the insn can be packaged only with an A-type insn in slot #1. bool HexagonMCInstrInfo::isRestrictSlot1AOK(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::RestrictSlot1AOKPos) & HexagonII::RestrictSlot1AOKMask); } bool HexagonMCInstrInfo::isRestrictNoSlot1Store(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::RestrictNoSlot1StorePos) & HexagonII::RestrictNoSlot1StoreMask); } /// Return whether the insn is solo, i.e., cannot be in a packet. bool HexagonMCInstrInfo::isSolo(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = MCII.get(MCI.getOpcode()).TSFlags; return ((F >> HexagonII::SoloPos) & HexagonII::SoloMask); } bool HexagonMCInstrInfo::isMemReorderDisabled(MCInst const &MCI) { assert(isBundle(MCI)); auto Flags = MCI.getOperand(0).getImm(); return (Flags & memReorderDisabledMask) != 0; } bool HexagonMCInstrInfo::isSubInstruction(MCInst const &MCI) { switch (MCI.getOpcode()) { default: return false; case Hexagon::SA1_addi: case Hexagon::SA1_addrx: case Hexagon::SA1_addsp: case Hexagon::SA1_and1: case Hexagon::SA1_clrf: case Hexagon::SA1_clrfnew: case Hexagon::SA1_clrt: case Hexagon::SA1_clrtnew: case Hexagon::SA1_cmpeqi: case Hexagon::SA1_combine0i: case Hexagon::SA1_combine1i: case Hexagon::SA1_combine2i: case Hexagon::SA1_combine3i: case Hexagon::SA1_combinerz: case Hexagon::SA1_combinezr: case Hexagon::SA1_dec: case Hexagon::SA1_inc: case Hexagon::SA1_seti: case Hexagon::SA1_setin1: case Hexagon::SA1_sxtb: case Hexagon::SA1_sxth: case Hexagon::SA1_tfr: case Hexagon::SA1_zxtb: case Hexagon::SA1_zxth: case Hexagon::SL1_loadri_io: case Hexagon::SL1_loadrub_io: case Hexagon::SL2_deallocframe: case Hexagon::SL2_jumpr31: case Hexagon::SL2_jumpr31_f: case Hexagon::SL2_jumpr31_fnew: case Hexagon::SL2_jumpr31_t: case Hexagon::SL2_jumpr31_tnew: case Hexagon::SL2_loadrb_io: case Hexagon::SL2_loadrd_sp: case Hexagon::SL2_loadrh_io: case Hexagon::SL2_loadri_sp: case Hexagon::SL2_loadruh_io: case Hexagon::SL2_return: case Hexagon::SL2_return_f: case Hexagon::SL2_return_fnew: case Hexagon::SL2_return_t: case Hexagon::SL2_return_tnew: case Hexagon::SS1_storeb_io: case Hexagon::SS1_storew_io: case Hexagon::SS2_allocframe: case Hexagon::SS2_storebi0: case Hexagon::SS2_storebi1: case Hexagon::SS2_stored_sp: case Hexagon::SS2_storeh_io: case Hexagon::SS2_storew_sp: case Hexagon::SS2_storewi0: case Hexagon::SS2_storewi1: return true; } } bool HexagonMCInstrInfo::isVector(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return (F >> HexagonII::isCVIPos) & HexagonII::isCVIMask; } int64_t HexagonMCInstrInfo::minConstant(MCInst const &MCI, size_t Index) { auto Sentinel = static_cast(std::numeric_limits::max()) << 8; if (MCI.size() <= Index) return Sentinel; MCOperand const &MCO = MCI.getOperand(Index); if (!MCO.isExpr()) return Sentinel; int64_t Value; if (!MCO.getExpr()->evaluateAsAbsolute(Value)) return Sentinel; return Value; } void HexagonMCInstrInfo::setMustExtend(MCExpr const &Expr, bool Val) { HexagonMCExpr &HExpr = const_cast(cast(Expr)); HExpr.setMustExtend(Val); } bool HexagonMCInstrInfo::mustExtend(MCExpr const &Expr) { HexagonMCExpr const &HExpr = cast(Expr); return HExpr.mustExtend(); } void HexagonMCInstrInfo::setMustNotExtend(MCExpr const &Expr, bool Val) { HexagonMCExpr &HExpr = const_cast(cast(Expr)); HExpr.setMustNotExtend(Val); } bool HexagonMCInstrInfo::mustNotExtend(MCExpr const &Expr) { HexagonMCExpr const &HExpr = cast(Expr); return HExpr.mustNotExtend(); } void HexagonMCInstrInfo::setS27_2_reloc(MCExpr const &Expr, bool Val) { HexagonMCExpr &HExpr = const_cast(*cast(&Expr)); HExpr.setS27_2_reloc(Val); } bool HexagonMCInstrInfo::s27_2_reloc(MCExpr const &Expr) { HexagonMCExpr const *HExpr = dyn_cast(&Expr); if (!HExpr) return false; return HExpr->s27_2_reloc(); } unsigned HexagonMCInstrInfo::packetSizeSlots(MCSubtargetInfo const &STI) { const bool IsTiny = STI.hasFeature(Hexagon::ProcTinyCore); return IsTiny ? (HEXAGON_PACKET_SIZE - 1) : HEXAGON_PACKET_SIZE; } unsigned HexagonMCInstrInfo::packetSize(StringRef CPU) { return llvm::StringSwitch(CPU) .Case("hexagonv67t", 3) .Default(4); } void HexagonMCInstrInfo::padEndloop(MCInst &MCB, MCContext &Context) { MCInst Nop; Nop.setOpcode(Hexagon::A2_nop); assert(isBundle(MCB)); while (LoopNeedsPadding(MCB)) MCB.addOperand(MCOperand::createInst(new (Context) MCInst(Nop))); } HexagonMCInstrInfo::PredicateInfo HexagonMCInstrInfo::predicateInfo(MCInstrInfo const &MCII, MCInst const &MCI) { if (!isPredicated(MCII, MCI)) return {0, 0, false}; MCInstrDesc const &Desc = getDesc(MCII, MCI); for (auto I = Desc.getNumDefs(), N = Desc.getNumOperands(); I != N; ++I) if (Desc.operands()[I].RegClass == Hexagon::PredRegsRegClassID) return {MCI.getOperand(I).getReg(), I, isPredicatedTrue(MCII, MCI)}; return {0, 0, false}; } bool HexagonMCInstrInfo::prefersSlot3(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return (F >> HexagonII::PrefersSlot3Pos) & HexagonII::PrefersSlot3Mask; } bool HexagonMCInstrInfo::hasTmpDst(MCInstrInfo const &MCII, MCInst const &MCI) { switch (MCI.getOpcode()) { default: return false; case Hexagon::V6_vgathermh: case Hexagon::V6_vgathermhq: case Hexagon::V6_vgathermhw: case Hexagon::V6_vgathermhwq: case Hexagon::V6_vgathermw: case Hexagon::V6_vgathermwq: return true; } return false; } bool HexagonMCInstrInfo::hasHvxTmp(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return (F >> HexagonII::HasHvxTmpPos) & HexagonII::HasHvxTmpMask; } bool HexagonMCInstrInfo::requiresSlot(MCSubtargetInfo const &STI, MCInst const &MCI) { const unsigned OpCode = MCI.getOpcode(); const bool IsTiny = STI.getFeatureBits() [Hexagon::ProcTinyCore]; const bool NoSlotReqd = Hexagon::A4_ext == OpCode || (IsTiny && Hexagon::A2_nop == OpCode) || (IsTiny && Hexagon::J4_hintjumpr == OpCode); return !NoSlotReqd; } unsigned HexagonMCInstrInfo::slotsConsumed(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCInst const &MCI) { unsigned slotsUsed = 0; for (auto HMI : bundleInstructions(MCI)) { MCInst const &MCI = *HMI.getInst(); if (!requiresSlot(STI, MCI)) continue; if (isDuplex(MCII, MCI)) slotsUsed += 2; else ++slotsUsed; } return slotsUsed; } void HexagonMCInstrInfo::replaceDuplex(MCContext &Context, MCInst &MCB, DuplexCandidate Candidate) { assert(Candidate.packetIndexI < MCB.size()); assert(Candidate.packetIndexJ < MCB.size()); assert(isBundle(MCB)); MCInst *Duplex = deriveDuplex(Context, Candidate.iClass, *MCB.getOperand(Candidate.packetIndexJ).getInst(), *MCB.getOperand(Candidate.packetIndexI).getInst()); assert(Duplex != nullptr); MCB.getOperand(Candidate.packetIndexI).setInst(Duplex); MCB.erase(MCB.begin() + Candidate.packetIndexJ); } void HexagonMCInstrInfo::setInnerLoop(MCInst &MCI) { assert(isBundle(MCI)); MCOperand &Operand = MCI.getOperand(0); Operand.setImm(Operand.getImm() | innerLoopMask); } void HexagonMCInstrInfo::setMemReorderDisabled(MCInst &MCI) { assert(isBundle(MCI)); MCOperand &Operand = MCI.getOperand(0); Operand.setImm(Operand.getImm() | memReorderDisabledMask); assert(isMemReorderDisabled(MCI)); } void HexagonMCInstrInfo::setOuterLoop(MCInst &MCI) { assert(isBundle(MCI)); MCOperand &Operand = MCI.getOperand(0); Operand.setImm(Operand.getImm() | outerLoopMask); } unsigned HexagonMCInstrInfo::SubregisterBit(unsigned Consumer, unsigned Producer, unsigned Producer2) { // If we're a single vector consumer of a double producer, set subreg bit // based on if we're accessing the lower or upper register component if (IsVecRegPair(Producer) && IsVecRegSingle(Consumer)) { unsigned Rev = IsReverseVecRegPair(Producer); return ((Consumer - Hexagon::V0) & 0x1) ^ Rev; } if (Producer2 != Hexagon::NoRegister) return Consumer == Producer; return 0; } bool HexagonMCInstrInfo::LoopNeedsPadding(MCInst const &MCB) { return ( (HexagonMCInstrInfo::isInnerLoop(MCB) && (HexagonMCInstrInfo::bundleSize(MCB) < HEXAGON_PACKET_INNER_SIZE)) || ((HexagonMCInstrInfo::isOuterLoop(MCB) && (HexagonMCInstrInfo::bundleSize(MCB) < HEXAGON_PACKET_OUTER_SIZE)))); } bool HexagonMCInstrInfo::IsABranchingInst(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCInst const &I) { assert(!HexagonMCInstrInfo::isBundle(I)); MCInstrDesc const &Desc = HexagonMCInstrInfo::getDesc(MCII, I); return (Desc.isBranch() || Desc.isCall() || Desc.isReturn()); }