aboutsummaryrefslogtreecommitdiff
path: root/lib/Target/Hexagon/MCTargetDesc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/Hexagon/MCTargetDesc')
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/CMakeLists.txt4
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp269
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h22
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonELFObjectWriter.cpp306
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp118
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.h19
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp2
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.h4
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp221
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.h10
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCCompound.cpp420
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp1100
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp271
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h154
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCShuffler.cpp237
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCShuffler.h65
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp10
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h4
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp385
-rw-r--r--lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h139
20 files changed, 3594 insertions, 166 deletions
diff --git a/lib/Target/Hexagon/MCTargetDesc/CMakeLists.txt b/lib/Target/Hexagon/MCTargetDesc/CMakeLists.txt
index 4c987ed32a64..6253686b4993 100644
--- a/lib/Target/Hexagon/MCTargetDesc/CMakeLists.txt
+++ b/lib/Target/Hexagon/MCTargetDesc/CMakeLists.txt
@@ -4,8 +4,12 @@ add_llvm_library(LLVMHexagonDesc
HexagonInstPrinter.cpp
HexagonMCAsmInfo.cpp
HexagonMCCodeEmitter.cpp
+ HexagonMCCompound.cpp
+ HexagonMCDuplexInfo.cpp
HexagonMCInstrInfo.cpp
+ HexagonMCShuffler.cpp
HexagonMCTargetDesc.cpp
+ HexagonShuffler.cpp
)
add_dependencies(LLVMHexagonDesc HexagonCommonTableGen)
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp
index 155aa9ef9557..76894840153d 100644
--- a/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp
@@ -7,19 +7,150 @@
//
//===----------------------------------------------------------------------===//
+#include "Hexagon.h"
+#include "HexagonFixupKinds.h"
#include "HexagonMCTargetDesc.h"
+#include "MCTargetDesc/HexagonBaseInfo.h"
+#include "MCTargetDesc/HexagonMCInstrInfo.h"
#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCELFObjectWriter.h"
+#include "llvm/MC/MCFixupKindInfo.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
+using namespace Hexagon;
namespace {
class HexagonAsmBackend : public MCAsmBackend {
+ uint8_t OSABI;
+ StringRef CPU;
+ mutable uint64_t relaxedCnt;
+ std::unique_ptr <MCInstrInfo> MCII;
+ std::unique_ptr <MCInst *> RelaxTarget;
public:
- HexagonAsmBackend(Target const & /*T*/) {}
+ HexagonAsmBackend(Target const &T, uint8_t OSABI, StringRef CPU) :
+ OSABI(OSABI), MCII (T.createMCInstrInfo()), RelaxTarget(new MCInst *){}
- unsigned getNumFixupKinds() const override { return 0; }
+ MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override {
+ return createHexagonELFObjectWriter(OS, OSABI, CPU);
+ }
+
+ unsigned getNumFixupKinds() const override {
+ return Hexagon::NumTargetFixupKinds;
+ }
+
+ const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override {
+ const static MCFixupKindInfo Infos[Hexagon::NumTargetFixupKinds] = {
+ // This table *must* be in same the order of fixup_* kinds in
+ // HexagonFixupKinds.h.
+ //
+ // namei offset bits flags
+ {"fixup_Hexagon_B22_PCREL", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_B15_PCREL", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_B7_PCREL", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_LO16", 0, 32, 0},
+ {"fixup_Hexagon_HI16", 0, 32, 0},
+ {"fixup_Hexagon_32", 0, 32, 0},
+ {"fixup_Hexagon_16", 0, 32, 0},
+ {"fixup_Hexagon_8", 0, 32, 0},
+ {"fixup_Hexagon_GPREL16_0", 0, 32, 0},
+ {"fixup_Hexagon_GPREL16_1", 0, 32, 0},
+ {"fixup_Hexagon_GPREL16_2", 0, 32, 0},
+ {"fixup_Hexagon_GPREL16_3", 0, 32, 0},
+ {"fixup_Hexagon_HL16", 0, 32, 0},
+ {"fixup_Hexagon_B13_PCREL", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_B9_PCREL", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_B32_PCREL_X", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_32_6_X", 0, 32, 0},
+ {"fixup_Hexagon_B22_PCREL_X", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_B15_PCREL_X", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_B13_PCREL_X", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_B9_PCREL_X", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_B7_PCREL_X", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_16_X", 0, 32, 0},
+ {"fixup_Hexagon_12_X", 0, 32, 0},
+ {"fixup_Hexagon_11_X", 0, 32, 0},
+ {"fixup_Hexagon_10_X", 0, 32, 0},
+ {"fixup_Hexagon_9_X", 0, 32, 0},
+ {"fixup_Hexagon_8_X", 0, 32, 0},
+ {"fixup_Hexagon_7_X", 0, 32, 0},
+ {"fixup_Hexagon_6_X", 0, 32, 0},
+ {"fixup_Hexagon_32_PCREL", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_COPY", 0, 32, 0},
+ {"fixup_Hexagon_GLOB_DAT", 0, 32, 0},
+ {"fixup_Hexagon_JMP_SLOT", 0, 32, 0},
+ {"fixup_Hexagon_RELATIVE", 0, 32, 0},
+ {"fixup_Hexagon_PLT_B22_PCREL", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_GOTREL_LO16", 0, 32, 0},
+ {"fixup_Hexagon_GOTREL_HI16", 0, 32, 0},
+ {"fixup_Hexagon_GOTREL_32", 0, 32, 0},
+ {"fixup_Hexagon_GOT_LO16", 0, 32, 0},
+ {"fixup_Hexagon_GOT_HI16", 0, 32, 0},
+ {"fixup_Hexagon_GOT_32", 0, 32, 0},
+ {"fixup_Hexagon_GOT_16", 0, 32, 0},
+ {"fixup_Hexagon_DTPMOD_32", 0, 32, 0},
+ {"fixup_Hexagon_DTPREL_LO16", 0, 32, 0},
+ {"fixup_Hexagon_DTPREL_HI16", 0, 32, 0},
+ {"fixup_Hexagon_DTPREL_32", 0, 32, 0},
+ {"fixup_Hexagon_DTPREL_16", 0, 32, 0},
+ {"fixup_Hexagon_GD_PLT_B22_PCREL", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_LD_PLT_B22_PCREL", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_GD_GOT_LO16", 0, 32, 0},
+ {"fixup_Hexagon_GD_GOT_HI16", 0, 32, 0},
+ {"fixup_Hexagon_GD_GOT_32", 0, 32, 0},
+ {"fixup_Hexagon_GD_GOT_16", 0, 32, 0},
+ {"fixup_Hexagon_LD_GOT_LO16", 0, 32, 0},
+ {"fixup_Hexagon_LD_GOT_HI16", 0, 32, 0},
+ {"fixup_Hexagon_LD_GOT_32", 0, 32, 0},
+ {"fixup_Hexagon_LD_GOT_16", 0, 32, 0},
+ {"fixup_Hexagon_IE_LO16", 0, 32, 0},
+ {"fixup_Hexagon_IE_HI16", 0, 32, 0},
+ {"fixup_Hexagon_IE_32", 0, 32, 0},
+ {"fixup_Hexagon_IE_16", 0, 32, 0},
+ {"fixup_Hexagon_IE_GOT_LO16", 0, 32, 0},
+ {"fixup_Hexagon_IE_GOT_HI16", 0, 32, 0},
+ {"fixup_Hexagon_IE_GOT_32", 0, 32, 0},
+ {"fixup_Hexagon_IE_GOT_16", 0, 32, 0},
+ {"fixup_Hexagon_TPREL_LO16", 0, 32, 0},
+ {"fixup_Hexagon_TPREL_HI16", 0, 32, 0},
+ {"fixup_Hexagon_TPREL_32", 0, 32, 0},
+ {"fixup_Hexagon_TPREL_16", 0, 32, 0},
+ {"fixup_Hexagon_6_PCREL_X", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_Hexagon_GOTREL_32_6_X", 0, 32, 0},
+ {"fixup_Hexagon_GOTREL_16_X", 0, 32, 0},
+ {"fixup_Hexagon_GOTREL_11_X", 0, 32, 0},
+ {"fixup_Hexagon_GOT_32_6_X", 0, 32, 0},
+ {"fixup_Hexagon_GOT_16_X", 0, 32, 0},
+ {"fixup_Hexagon_GOT_11_X", 0, 32, 0},
+ {"fixup_Hexagon_DTPREL_32_6_X", 0, 32, 0},
+ {"fixup_Hexagon_DTPREL_16_X", 0, 32, 0},
+ {"fixup_Hexagon_DTPREL_11_X", 0, 32, 0},
+ {"fixup_Hexagon_GD_GOT_32_6_X", 0, 32, 0},
+ {"fixup_Hexagon_GD_GOT_16_X", 0, 32, 0},
+ {"fixup_Hexagon_GD_GOT_11_X", 0, 32, 0},
+ {"fixup_Hexagon_LD_GOT_32_6_X", 0, 32, 0},
+ {"fixup_Hexagon_LD_GOT_16_X", 0, 32, 0},
+ {"fixup_Hexagon_LD_GOT_11_X", 0, 32, 0},
+ {"fixup_Hexagon_IE_32_6_X", 0, 32, 0},
+ {"fixup_Hexagon_IE_16_X", 0, 32, 0},
+ {"fixup_Hexagon_IE_GOT_32_6_X", 0, 32, 0},
+ {"fixup_Hexagon_IE_GOT_16_X", 0, 32, 0},
+ {"fixup_Hexagon_IE_GOT_11_X", 0, 32, 0},
+ {"fixup_Hexagon_TPREL_32_6_X", 0, 32, 0},
+ {"fixup_Hexagon_TPREL_16_X", 0, 32, 0},
+ {"fixup_Hexagon_TPREL_11_X", 0, 32, 0}};
+
+ if (Kind < FirstTargetFixupKind) {
+ return MCAsmBackend::getFixupKindInfo(Kind);
+ }
+
+ assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
+ "Invalid kind!");
+ return Infos[Kind - FirstTargetFixupKind];
+ }
void applyFixup(MCFixup const & /*Fixup*/, char * /*Data*/,
unsigned /*DataSize*/, uint64_t /*Value*/,
@@ -27,14 +158,119 @@ public:
return;
}
- bool mayNeedRelaxation(MCInst const & /*Inst*/) const override {
+ bool isInstRelaxable(MCInst const &HMI) const {
+ const MCInstrDesc &MCID = HexagonMCInstrInfo::getDesc(*MCII, HMI);
+ bool Relaxable = false;
+ // Branches and loop-setup insns are handled as necessary by relaxation.
+ if (llvm::HexagonMCInstrInfo::getType(*MCII, HMI) == HexagonII::TypeJ ||
+ (llvm::HexagonMCInstrInfo::getType(*MCII, HMI) == HexagonII::TypeNV &&
+ MCID.isBranch()) ||
+ (llvm::HexagonMCInstrInfo::getType(*MCII, HMI) == HexagonII::TypeCR &&
+ HMI.getOpcode() != Hexagon::C4_addipc))
+ if (HexagonMCInstrInfo::isExtendable(*MCII, HMI))
+ Relaxable = true;
+
+ return Relaxable;
+ }
+
+ /// MayNeedRelaxation - Check whether the given instruction may need
+ /// relaxation.
+ ///
+ /// \param Inst - The instruction to test.
+ bool mayNeedRelaxation(MCInst const &Inst) const override {
+ assert(HexagonMCInstrInfo::isBundle(Inst));
+ bool PreviousIsExtender = false;
+ for (auto const &I : HexagonMCInstrInfo::bundleInstructions(Inst)) {
+ auto const &Inst = *I.getInst();
+ if (!PreviousIsExtender) {
+ if (isInstRelaxable(Inst))
+ return true;
+ }
+ PreviousIsExtender = HexagonMCInstrInfo::isImmext(Inst);
+ }
return false;
}
- bool fixupNeedsRelaxation(MCFixup const & /*Fixup*/, uint64_t /*Value*/,
- MCRelaxableFragment const * /*DF*/,
- MCAsmLayout const & /*Layout*/) const override {
- llvm_unreachable("fixupNeedsRelaxation() unimplemented");
+ /// fixupNeedsRelaxation - Target specific predicate for whether a given
+ /// fixup requires the associated instruction to be relaxed.
+ bool fixupNeedsRelaxationAdvanced(const MCFixup &Fixup, bool Resolved,
+ uint64_t Value,
+ const MCRelaxableFragment *DF,
+ const MCAsmLayout &Layout) const override {
+ MCInst const &MCB = DF->getInst();
+ assert(HexagonMCInstrInfo::isBundle(MCB));
+
+ *RelaxTarget = nullptr;
+ MCInst &MCI = const_cast<MCInst &>(HexagonMCInstrInfo::instruction(
+ MCB, Fixup.getOffset() / HEXAGON_INSTR_SIZE));
+ // If we cannot resolve the fixup value, it requires relaxation.
+ if (!Resolved) {
+ switch ((unsigned)Fixup.getKind()) {
+ case fixup_Hexagon_B22_PCREL:
+ // GetFixupCount assumes B22 won't relax
+ // Fallthrough
+ default:
+ return false;
+ break;
+ case fixup_Hexagon_B13_PCREL:
+ case fixup_Hexagon_B15_PCREL:
+ case fixup_Hexagon_B9_PCREL:
+ case fixup_Hexagon_B7_PCREL: {
+ if (HexagonMCInstrInfo::bundleSize(MCB) < HEXAGON_PACKET_SIZE) {
+ ++relaxedCnt;
+ *RelaxTarget = &MCI;
+ return true;
+ } else {
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ bool Relaxable = isInstRelaxable(MCI);
+ if (Relaxable == false)
+ return false;
+
+ MCFixupKind Kind = Fixup.getKind();
+ int64_t sValue = Value;
+ int64_t maxValue;
+
+ switch ((unsigned)Kind) {
+ case fixup_Hexagon_B7_PCREL:
+ maxValue = 1 << 8;
+ break;
+ case fixup_Hexagon_B9_PCREL:
+ maxValue = 1 << 10;
+ break;
+ case fixup_Hexagon_B15_PCREL:
+ maxValue = 1 << 16;
+ break;
+ case fixup_Hexagon_B22_PCREL:
+ maxValue = 1 << 23;
+ break;
+ default:
+ maxValue = INT64_MAX;
+ break;
+ }
+
+ bool isFarAway = -maxValue > sValue || sValue > maxValue - 1;
+
+ if (isFarAway) {
+ if (HexagonMCInstrInfo::bundleSize(MCB) < HEXAGON_PACKET_SIZE) {
+ ++relaxedCnt;
+ *RelaxTarget = &MCI;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /// Simple predicate for targets where !Resolved implies requiring relaxation
+ bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
+ const MCRelaxableFragment *DF,
+ const MCAsmLayout &Layout) const override {
+ llvm_unreachable("Handled by fixupNeedsRelaxationAdvanced");
}
void relaxInstruction(MCInst const & /*Inst*/,
@@ -49,26 +285,11 @@ public:
};
} // end anonymous namespace
-namespace {
-class ELFHexagonAsmBackend : public HexagonAsmBackend {
- uint8_t OSABI;
-
-public:
- ELFHexagonAsmBackend(Target const &T, uint8_t OSABI)
- : HexagonAsmBackend(T), OSABI(OSABI) {}
-
- MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override {
- StringRef CPU("HexagonV4");
- return createHexagonELFObjectWriter(OS, OSABI, CPU);
- }
-};
-} // end anonymous namespace
-
namespace llvm {
MCAsmBackend *createHexagonAsmBackend(Target const &T,
MCRegisterInfo const & /*MRI*/,
- StringRef TT, StringRef /*CPU*/) {
+ StringRef TT, StringRef CPU) {
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(Triple(TT).getOS());
- return new ELFHexagonAsmBackend(T, OSABI);
+ return new HexagonAsmBackend(T, OSABI, CPU);
}
}
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h b/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h
index 6a72f205e9d3..f4d162ccf6a8 100644
--- a/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h
@@ -43,6 +43,7 @@ namespace HexagonII {
TypeXTYPE = 8,
TypeMEMOP = 9,
TypeNV = 10,
+ TypeDUPLEX = 11,
TypePREFIX = 30, // Such as extenders.
TypeENDLOOP = 31 // Such as end of a HW loop.
};
@@ -190,7 +191,26 @@ namespace HexagonII {
MO_GPREL
};
- enum class InstParseBits : uint32_t {
+ // Hexagon Sub-instruction classes.
+ enum SubInstructionGroup {
+ HSIG_None = 0,
+ HSIG_L1,
+ HSIG_L2,
+ HSIG_S1,
+ HSIG_S2,
+ HSIG_A,
+ HSIG_Compound
+ };
+
+ // Hexagon Compound classes.
+ enum CompoundGroup {
+ HCG_None = 0,
+ HCG_A,
+ HCG_B,
+ HCG_C
+ };
+
+ enum InstParseBits {
INST_PARSE_MASK = 0x0000c000,
INST_PARSE_PACKET_END = 0x0000c000,
INST_PARSE_LOOP_END = 0x00008000,
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonELFObjectWriter.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonELFObjectWriter.cpp
index fde935b2758b..843072302b21 100644
--- a/lib/Target/Hexagon/MCTargetDesc/HexagonELFObjectWriter.cpp
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonELFObjectWriter.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "Hexagon.h"
+#include "MCTargetDesc/HexagonFixupKinds.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/Support/Debug.h"
@@ -40,17 +41,306 @@ HexagonELFObjectWriter::HexagonELFObjectWriter(uint8_t OSABI, StringRef C)
unsigned HexagonELFObjectWriter::GetRelocType(MCValue const &/*Target*/,
MCFixup const &Fixup,
bool IsPCRel) const {
+ // determine the type of the relocation
unsigned Type = (unsigned)ELF::R_HEX_NONE;
- llvm::MCFixupKind Kind = Fixup.getKind();
+ unsigned Kind = (unsigned)Fixup.getKind();
switch (Kind) {
- default:
- DEBUG(dbgs() << "unrecognized relocation " << Fixup.getKind() << "\n");
- llvm_unreachable("Unimplemented Fixup kind!");
- break;
- case FK_Data_4:
- Type = (IsPCRel) ? ELF::R_HEX_32_PCREL : ELF::R_HEX_32;
- break;
+ default:
+ DEBUG(dbgs() << "unrecognized relocation " << Fixup.getKind() << "\n");
+ llvm_unreachable("Unimplemented Fixup kind!");
+ break;
+ case FK_Data_4:
+ Type = (IsPCRel) ? ELF::R_HEX_32_PCREL : ELF::R_HEX_32;
+ break;
+ case FK_PCRel_4:
+ Type = ELF::R_HEX_32_PCREL;
+ break;
+ case FK_Data_2:
+ Type = ELF::R_HEX_16;
+ break;
+ case FK_Data_1:
+ Type = ELF::R_HEX_8;
+ break;
+ case fixup_Hexagon_B22_PCREL:
+ Type = ELF::R_HEX_B22_PCREL;
+ break;
+ case fixup_Hexagon_B15_PCREL:
+ Type = ELF::R_HEX_B15_PCREL;
+ break;
+ case fixup_Hexagon_B7_PCREL:
+ Type = ELF::R_HEX_B7_PCREL;
+ break;
+ case fixup_Hexagon_LO16:
+ Type = ELF::R_HEX_LO16;
+ break;
+ case fixup_Hexagon_HI16:
+ Type = ELF::R_HEX_HI16;
+ break;
+ case fixup_Hexagon_32:
+ Type = ELF::R_HEX_32;
+ break;
+ case fixup_Hexagon_16:
+ Type = ELF::R_HEX_16;
+ break;
+ case fixup_Hexagon_8:
+ Type = ELF::R_HEX_8;
+ break;
+ case fixup_Hexagon_GPREL16_0:
+ Type = ELF::R_HEX_GPREL16_0;
+ break;
+ case fixup_Hexagon_GPREL16_1:
+ Type = ELF::R_HEX_GPREL16_1;
+ break;
+ case fixup_Hexagon_GPREL16_2:
+ Type = ELF::R_HEX_GPREL16_2;
+ break;
+ case fixup_Hexagon_GPREL16_3:
+ Type = ELF::R_HEX_GPREL16_3;
+ break;
+ case fixup_Hexagon_HL16:
+ Type = ELF::R_HEX_HL16;
+ break;
+ case fixup_Hexagon_B13_PCREL:
+ Type = ELF::R_HEX_B13_PCREL;
+ break;
+ case fixup_Hexagon_B9_PCREL:
+ Type = ELF::R_HEX_B9_PCREL;
+ break;
+ case fixup_Hexagon_B32_PCREL_X:
+ Type = ELF::R_HEX_B32_PCREL_X;
+ break;
+ case fixup_Hexagon_32_6_X:
+ Type = ELF::R_HEX_32_6_X;
+ break;
+ case fixup_Hexagon_B22_PCREL_X:
+ Type = ELF::R_HEX_B22_PCREL_X;
+ break;
+ case fixup_Hexagon_B15_PCREL_X:
+ Type = ELF::R_HEX_B15_PCREL_X;
+ break;
+ case fixup_Hexagon_B13_PCREL_X:
+ Type = ELF::R_HEX_B13_PCREL_X;
+ break;
+ case fixup_Hexagon_B9_PCREL_X:
+ Type = ELF::R_HEX_B9_PCREL_X;
+ break;
+ case fixup_Hexagon_B7_PCREL_X:
+ Type = ELF::R_HEX_B7_PCREL_X;
+ break;
+ case fixup_Hexagon_16_X:
+ Type = ELF::R_HEX_16_X;
+ break;
+ case fixup_Hexagon_12_X:
+ Type = ELF::R_HEX_12_X;
+ break;
+ case fixup_Hexagon_11_X:
+ Type = ELF::R_HEX_11_X;
+ break;
+ case fixup_Hexagon_10_X:
+ Type = ELF::R_HEX_10_X;
+ break;
+ case fixup_Hexagon_9_X:
+ Type = ELF::R_HEX_9_X;
+ break;
+ case fixup_Hexagon_8_X:
+ Type = ELF::R_HEX_8_X;
+ break;
+ case fixup_Hexagon_7_X:
+ Type = ELF::R_HEX_7_X;
+ break;
+ case fixup_Hexagon_6_X:
+ Type = ELF::R_HEX_6_X;
+ break;
+ case fixup_Hexagon_32_PCREL:
+ Type = ELF::R_HEX_32_PCREL;
+ break;
+ case fixup_Hexagon_COPY:
+ Type = ELF::R_HEX_COPY;
+ break;
+ case fixup_Hexagon_GLOB_DAT:
+ Type = ELF::R_HEX_GLOB_DAT;
+ break;
+ case fixup_Hexagon_JMP_SLOT:
+ Type = ELF::R_HEX_JMP_SLOT;
+ break;
+ case fixup_Hexagon_RELATIVE:
+ Type = ELF::R_HEX_RELATIVE;
+ break;
+ case fixup_Hexagon_PLT_B22_PCREL:
+ Type = ELF::R_HEX_PLT_B22_PCREL;
+ break;
+ case fixup_Hexagon_GOTREL_LO16:
+ Type = ELF::R_HEX_GOTREL_LO16;
+ break;
+ case fixup_Hexagon_GOTREL_HI16:
+ Type = ELF::R_HEX_GOTREL_HI16;
+ break;
+ case fixup_Hexagon_GOTREL_32:
+ Type = ELF::R_HEX_GOTREL_32;
+ break;
+ case fixup_Hexagon_GOT_LO16:
+ Type = ELF::R_HEX_GOT_LO16;
+ break;
+ case fixup_Hexagon_GOT_HI16:
+ Type = ELF::R_HEX_GOT_HI16;
+ break;
+ case fixup_Hexagon_GOT_32:
+ Type = ELF::R_HEX_GOT_32;
+ break;
+ case fixup_Hexagon_GOT_16:
+ Type = ELF::R_HEX_GOT_16;
+ break;
+ case fixup_Hexagon_DTPMOD_32:
+ Type = ELF::R_HEX_DTPMOD_32;
+ break;
+ case fixup_Hexagon_DTPREL_LO16:
+ Type = ELF::R_HEX_DTPREL_LO16;
+ break;
+ case fixup_Hexagon_DTPREL_HI16:
+ Type = ELF::R_HEX_DTPREL_HI16;
+ break;
+ case fixup_Hexagon_DTPREL_32:
+ Type = ELF::R_HEX_DTPREL_32;
+ break;
+ case fixup_Hexagon_DTPREL_16:
+ Type = ELF::R_HEX_DTPREL_16;
+ break;
+ case fixup_Hexagon_GD_PLT_B22_PCREL:
+ Type = ELF::R_HEX_GD_PLT_B22_PCREL;
+ break;
+ case fixup_Hexagon_LD_PLT_B22_PCREL:
+ Type = ELF::R_HEX_LD_PLT_B22_PCREL;
+ break;
+ case fixup_Hexagon_GD_GOT_LO16:
+ Type = ELF::R_HEX_GD_GOT_LO16;
+ break;
+ case fixup_Hexagon_GD_GOT_HI16:
+ Type = ELF::R_HEX_GD_GOT_HI16;
+ break;
+ case fixup_Hexagon_GD_GOT_32:
+ Type = ELF::R_HEX_GD_GOT_32;
+ break;
+ case fixup_Hexagon_GD_GOT_16:
+ Type = ELF::R_HEX_GD_GOT_16;
+ break;
+ case fixup_Hexagon_LD_GOT_LO16:
+ Type = ELF::R_HEX_LD_GOT_LO16;
+ break;
+ case fixup_Hexagon_LD_GOT_HI16:
+ Type = ELF::R_HEX_LD_GOT_HI16;
+ break;
+ case fixup_Hexagon_LD_GOT_32:
+ Type = ELF::R_HEX_LD_GOT_32;
+ break;
+ case fixup_Hexagon_LD_GOT_16:
+ Type = ELF::R_HEX_LD_GOT_16;
+ break;
+ case fixup_Hexagon_IE_LO16:
+ Type = ELF::R_HEX_IE_LO16;
+ break;
+ case fixup_Hexagon_IE_HI16:
+ Type = ELF::R_HEX_IE_HI16;
+ break;
+ case fixup_Hexagon_IE_32:
+ Type = ELF::R_HEX_IE_32;
+ break;
+ case fixup_Hexagon_IE_GOT_LO16:
+ Type = ELF::R_HEX_IE_GOT_LO16;
+ break;
+ case fixup_Hexagon_IE_GOT_HI16:
+ Type = ELF::R_HEX_IE_GOT_HI16;
+ break;
+ case fixup_Hexagon_IE_GOT_32:
+ Type = ELF::R_HEX_IE_GOT_32;
+ break;
+ case fixup_Hexagon_IE_GOT_16:
+ Type = ELF::R_HEX_IE_GOT_16;
+ break;
+ case fixup_Hexagon_TPREL_LO16:
+ Type = ELF::R_HEX_TPREL_LO16;
+ break;
+ case fixup_Hexagon_TPREL_HI16:
+ Type = ELF::R_HEX_TPREL_HI16;
+ break;
+ case fixup_Hexagon_TPREL_32:
+ Type = ELF::R_HEX_TPREL_32;
+ break;
+ case fixup_Hexagon_TPREL_16:
+ Type = ELF::R_HEX_TPREL_16;
+ break;
+ case fixup_Hexagon_6_PCREL_X:
+ Type = ELF::R_HEX_6_PCREL_X;
+ break;
+ case fixup_Hexagon_GOTREL_32_6_X:
+ Type = ELF::R_HEX_GOTREL_32_6_X;
+ break;
+ case fixup_Hexagon_GOTREL_16_X:
+ Type = ELF::R_HEX_GOTREL_16_X;
+ break;
+ case fixup_Hexagon_GOTREL_11_X:
+ Type = ELF::R_HEX_GOTREL_11_X;
+ break;
+ case fixup_Hexagon_GOT_32_6_X:
+ Type = ELF::R_HEX_GOT_32_6_X;
+ break;
+ case fixup_Hexagon_GOT_16_X:
+ Type = ELF::R_HEX_GOT_16_X;
+ break;
+ case fixup_Hexagon_GOT_11_X:
+ Type = ELF::R_HEX_GOT_11_X;
+ break;
+ case fixup_Hexagon_DTPREL_32_6_X:
+ Type = ELF::R_HEX_DTPREL_32_6_X;
+ break;
+ case fixup_Hexagon_DTPREL_16_X:
+ Type = ELF::R_HEX_DTPREL_16_X;
+ break;
+ case fixup_Hexagon_DTPREL_11_X:
+ Type = ELF::R_HEX_DTPREL_11_X;
+ break;
+ case fixup_Hexagon_GD_GOT_32_6_X:
+ Type = ELF::R_HEX_GD_GOT_32_6_X;
+ break;
+ case fixup_Hexagon_GD_GOT_16_X:
+ Type = ELF::R_HEX_GD_GOT_16_X;
+ break;
+ case fixup_Hexagon_GD_GOT_11_X:
+ Type = ELF::R_HEX_GD_GOT_11_X;
+ break;
+ case fixup_Hexagon_LD_GOT_32_6_X:
+ Type = ELF::R_HEX_LD_GOT_32_6_X;
+ break;
+ case fixup_Hexagon_LD_GOT_16_X:
+ Type = ELF::R_HEX_LD_GOT_16_X;
+ break;
+ case fixup_Hexagon_LD_GOT_11_X:
+ Type = ELF::R_HEX_LD_GOT_11_X;
+ break;
+ case fixup_Hexagon_IE_32_6_X:
+ Type = ELF::R_HEX_IE_32_6_X;
+ break;
+ case fixup_Hexagon_IE_16_X:
+ Type = ELF::R_HEX_IE_16_X;
+ break;
+ case fixup_Hexagon_IE_GOT_32_6_X:
+ Type = ELF::R_HEX_IE_GOT_32_6_X;
+ break;
+ case fixup_Hexagon_IE_GOT_16_X:
+ Type = ELF::R_HEX_IE_GOT_16_X;
+ break;
+ case fixup_Hexagon_IE_GOT_11_X:
+ Type = ELF::R_HEX_IE_GOT_11_X;
+ break;
+ case fixup_Hexagon_TPREL_32_6_X:
+ Type = ELF::R_HEX_TPREL_32_6_X;
+ break;
+ case fixup_Hexagon_TPREL_16_X:
+ Type = ELF::R_HEX_TPREL_16_X;
+ break;
+ case fixup_Hexagon_TPREL_11_X:
+ Type = ELF::R_HEX_TPREL_11_X;
+ break;
}
return Type;
}
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp
index 15cda717cf1c..36f81465eef6 100644
--- a/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp
@@ -28,7 +28,47 @@ using namespace llvm;
#define GET_INSTRUCTION_NAME
#include "HexagonGenAsmWriter.inc"
-const char HexagonInstPrinter::PacketPadding = '\t';
+HexagonAsmInstPrinter::HexagonAsmInstPrinter(MCInstPrinter *RawPrinter)
+ : MCInstPrinter(*RawPrinter), RawPrinter(RawPrinter) {}
+
+void HexagonAsmInstPrinter::printInst(MCInst const *MI, raw_ostream &O,
+ StringRef Annot,
+ MCSubtargetInfo const &STI) {
+ assert(HexagonMCInstrInfo::isBundle(*MI));
+ assert(HexagonMCInstrInfo::bundleSize(*MI) <= HEXAGON_PACKET_SIZE);
+ std::string Buffer;
+ {
+ raw_string_ostream TempStream(Buffer);
+ RawPrinter->printInst(MI, TempStream, "", STI);
+ }
+ StringRef Contents(Buffer);
+ auto PacketBundle = Contents.rsplit('\n');
+ auto HeadTail = PacketBundle.first.split('\n');
+ auto Preamble = "\t{\n\t\t";
+ auto Separator = "";
+ while(!HeadTail.first.empty()) {
+ O << Separator;
+ StringRef Inst;
+ auto Duplex = HeadTail.first.split('\v');
+ if(!Duplex.second.empty()){
+ O << Duplex.first << "\n";
+ Inst = Duplex.second;
+ }
+ else
+ Inst = Duplex.first;
+ O << Preamble;
+ O << Inst;
+ HeadTail = HeadTail.second.split('\n');
+ Preamble = "";
+ Separator = "\n\t\t";
+ }
+ O << "\n\t}" << PacketBundle.second;
+}
+
+void HexagonAsmInstPrinter::printRegName(raw_ostream &O, unsigned RegNo) const {
+ RawPrinter->printRegName(O, RegNo);
+}
+
// Return the minimum value that a constant extendable operand can have
// without being extended.
static int getMinValue(uint64_t TSFlags) {
@@ -77,48 +117,44 @@ void HexagonInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
OS << getRegisterName(RegNo);
}
-void HexagonInstPrinter::printInst(MCInst const *MI, raw_ostream &O,
- StringRef Annot,
- const MCSubtargetInfo &STI) {
- const char startPacket = '{',
- endPacket = '}';
- // TODO: add outer HW loop when it's supported too.
- if (MI->getOpcode() == Hexagon::ENDLOOP0) {
- // Ending a harware loop is different from ending an regular packet.
- assert(HexagonMCInstrInfo::isPacketEnd(*MI) && "Loop-end must also end the packet");
-
- if (HexagonMCInstrInfo::isPacketBegin(*MI)) {
- // There must be a packet to end a loop.
- // FIXME: when shuffling is always run, this shouldn't be needed.
- MCInst Nop;
- StringRef NoAnnot;
-
- Nop.setOpcode (Hexagon::A2_nop);
- HexagonMCInstrInfo::setPacketBegin (Nop, HexagonMCInstrInfo::isPacketBegin(*MI));
- printInst (&Nop, O, NoAnnot, STI);
- }
+void HexagonInstPrinter::setExtender(MCInst const &MCI) {
+ HasExtender = HexagonMCInstrInfo::isImmext(MCI);
+}
- // Close the packet.
- if (HexagonMCInstrInfo::isPacketEnd(*MI))
- O << PacketPadding << endPacket;
+void HexagonInstPrinter::printInst(MCInst const *MI, raw_ostream &OS,
+ StringRef Annot,
+ MCSubtargetInfo const &STI) {
+ assert(HexagonMCInstrInfo::isBundle(*MI));
+ assert(HexagonMCInstrInfo::bundleSize(*MI) <= HEXAGON_PACKET_SIZE);
+ HasExtender = false;
+ for (auto const &I : HexagonMCInstrInfo::bundleInstructions(*MI)) {
+ MCInst const &MCI = *I.getInst();
+ if (HexagonMCInstrInfo::isDuplex(MII, MCI)) {
+ printInstruction(MCI.getOperand(1).getInst(), OS);
+ OS << '\v';
+ HasExtender = false;
+ printInstruction(MCI.getOperand(0).getInst(), OS);
+ } else
+ printInstruction(&MCI, OS);
+ setExtender(MCI);
+ OS << "\n";
+ }
- printInstruction(MI, O);
+ auto Separator = "";
+ if (HexagonMCInstrInfo::isInnerLoop(*MI)) {
+ OS << Separator;
+ Separator = " ";
+ MCInst ME;
+ ME.setOpcode(Hexagon::ENDLOOP0);
+ printInstruction(&ME, OS);
}
- else {
- // Prefix the insn opening the packet.
- if (HexagonMCInstrInfo::isPacketBegin(*MI))
- O << PacketPadding << startPacket << '\n';
-
- printInstruction(MI, O);
-
- // Suffix the insn closing the packet.
- if (HexagonMCInstrInfo::isPacketEnd(*MI))
- // Suffix the packet in a new line always, since the GNU assembler has
- // issues with a closing brace on the same line as CONST{32,64}.
- O << '\n' << PacketPadding << endPacket;
+ if (HexagonMCInstrInfo::isOuterLoop(*MI)) {
+ OS << Separator;
+ Separator = " ";
+ MCInst ME;
+ ME.setOpcode(Hexagon::ENDLOOP1);
+ printInstruction(&ME, OS);
}
-
- printAnnotation(O, Annot);
}
void HexagonInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
@@ -128,7 +164,7 @@ void HexagonInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
if (MO.isReg()) {
printRegName(O, MO.getReg());
} else if(MO.isExpr()) {
- O << *MO.getExpr();
+ MO.getExpr()->print(O, &MAI);
} else if(MO.isImm()) {
printImmOperand(MI, OpNo, O);
} else {
@@ -141,7 +177,7 @@ void HexagonInstPrinter::printImmOperand(const MCInst *MI, unsigned OpNo,
const MCOperand& MO = MI->getOperand(OpNo);
if(MO.isExpr()) {
- O << *MO.getExpr();
+ MO.getExpr()->print(O, &MAI);
} else if(MO.isImm()) {
O << MI->getOperand(OpNo).getImm();
} else {
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.h b/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.h
index 3fedaed8fbf9..534ac237d635 100644
--- a/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.h
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.h
@@ -18,6 +18,21 @@
#include "llvm/MC/MCInstrInfo.h"
namespace llvm {
+class HexagonAsmInstPrinter : public MCInstPrinter {
+public:
+ HexagonAsmInstPrinter(MCInstPrinter *RawPrinter);
+ void printInst(MCInst const *MI, raw_ostream &O, StringRef Annot,
+ MCSubtargetInfo const &STI) override;
+ void printRegName(raw_ostream &O, unsigned RegNo) const override;
+ std::unique_ptr<MCInstPrinter> RawPrinter;
+};
+/// Prints bundles as a newline separated list of individual instructions
+/// Duplexes are separated by a vertical tab \v character
+/// A trailing line includes bundle properties such as endloop0/1
+///
+/// r0 = add(r1, r2)
+/// r0 = #0 \v jump 0x0
+/// :endloop0 :endloop1
class HexagonInstPrinter : public MCInstPrinter {
public:
explicit HexagonInstPrinter(MCAsmInfo const &MAI,
@@ -74,11 +89,11 @@ namespace llvm {
void printSymbol(const MCInst *MI, unsigned OpNo, raw_ostream &O, bool hi)
const;
- static const char PacketPadding;
-
private:
const MCInstrInfo &MII;
+ bool HasExtender;
+ void setExtender(MCInst const &MCI);
};
} // end namespace llvm
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp
index ad5e0fb15e7f..51d2f1c878dc 100644
--- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp
@@ -18,7 +18,7 @@ using namespace llvm;
// Pin the vtable to this file.
void HexagonMCAsmInfo::anchor() {}
-HexagonMCAsmInfo::HexagonMCAsmInfo(StringRef TT) {
+HexagonMCAsmInfo::HexagonMCAsmInfo(const Triple &TT) {
Data16bitsDirective = "\t.half\t";
Data32bitsDirective = "\t.word\t";
Data64bitsDirective = nullptr; // .xword is only supported by V9.
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.h b/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.h
index ab18f0b37ba6..dc0706994786 100644
--- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.h
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.h
@@ -18,10 +18,12 @@
#include "llvm/MC/MCAsmInfoELF.h"
namespace llvm {
+ class Triple;
+
class HexagonMCAsmInfo : public MCAsmInfoELF {
void anchor() override;
public:
- explicit HexagonMCAsmInfo(StringRef TT);
+ explicit HexagonMCAsmInfo(const Triple &TT);
};
} // namespace llvm
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp
index ae3953abba10..1eee852996fd 100644
--- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp
@@ -22,6 +22,7 @@
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/EndianStream.h"
#include "llvm/Support/raw_ostream.h"
#define DEBUG_TYPE "mccodeemitter"
@@ -31,38 +32,206 @@ using namespace Hexagon;
STATISTIC(MCNumEmitted, "Number of MC instructions emitted");
-namespace {
-/// \brief 10.6 Instruction Packets
-/// Possible values for instruction packet parse field.
-enum class ParseField { duplex = 0x0, last0 = 0x1, last1 = 0x2, end = 0x3 };
-/// \brief Returns the packet bits based on instruction position.
-uint32_t getPacketBits(MCInst const &HMI) {
- unsigned const ParseFieldOffset = 14;
- ParseField Field = HexagonMCInstrInfo::isPacketEnd(HMI) ? ParseField::end
- : ParseField::last0;
- return static_cast<uint32_t>(Field) << ParseFieldOffset;
-}
-void emitLittleEndian(uint64_t Binary, raw_ostream &OS) {
- OS << static_cast<uint8_t>((Binary >> 0x00) & 0xff);
- OS << static_cast<uint8_t>((Binary >> 0x08) & 0xff);
- OS << static_cast<uint8_t>((Binary >> 0x10) & 0xff);
- OS << static_cast<uint8_t>((Binary >> 0x18) & 0xff);
-}
-}
-
HexagonMCCodeEmitter::HexagonMCCodeEmitter(MCInstrInfo const &aMII,
MCContext &aMCT)
: MCT(aMCT), MCII(aMII), Addend(new unsigned(0)),
- Extended(new bool(false)) {}
+ Extended(new bool(false)), CurrentBundle(new MCInst const *) {}
+
+uint32_t HexagonMCCodeEmitter::parseBits(size_t Instruction, size_t Last,
+ MCInst const &MCB,
+ MCInst const &MCI) const {
+ bool Duplex = HexagonMCInstrInfo::isDuplex(MCII, MCI);
+ if (Instruction == 0) {
+ if (HexagonMCInstrInfo::isInnerLoop(MCB)) {
+ assert(!Duplex);
+ assert(Instruction != Last);
+ return HexagonII::INST_PARSE_LOOP_END;
+ }
+ }
+ if (Instruction == 1) {
+ if (HexagonMCInstrInfo::isOuterLoop(MCB)) {
+ assert(!Duplex);
+ assert(Instruction != Last);
+ return HexagonII::INST_PARSE_LOOP_END;
+ }
+ }
+ if (Duplex) {
+ assert(Instruction == Last);
+ return HexagonII::INST_PARSE_DUPLEX;
+ }
+ if(Instruction == Last)
+ return HexagonII::INST_PARSE_PACKET_END;
+ return HexagonII::INST_PARSE_NOT_END;
+}
void HexagonMCCodeEmitter::encodeInstruction(MCInst const &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
MCSubtargetInfo const &STI) const {
- uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI) | getPacketBits(MI);
- assert(HexagonMCInstrInfo::getDesc(MCII, MI).getSize() == 4 &&
- "All instructions should be 32bit");
- (void)&MCII;
- emitLittleEndian(Binary, OS);
+ MCInst &HMB = const_cast<MCInst &>(MI);
+
+ assert(HexagonMCInstrInfo::isBundle(HMB));
+ DEBUG(dbgs() << "Encoding bundle\n";);
+ *Addend = 0;
+ *Extended = false;
+ *CurrentBundle = &MI;
+ size_t Instruction = 0;
+ size_t Last = HexagonMCInstrInfo::bundleSize(HMB) - 1;
+ for (auto &I : HexagonMCInstrInfo::bundleInstructions(HMB)) {
+ MCInst &HMI = const_cast<MCInst &>(*I.getInst());
+ EncodeSingleInstruction(HMI, OS, Fixups, STI,
+ parseBits(Instruction, Last, HMB, HMI),
+ Instruction);
+ *Extended = HexagonMCInstrInfo::isImmext(HMI);
+ *Addend += HEXAGON_INSTR_SIZE;
+ ++Instruction;
+ }
+ return;
+}
+
+/// EncodeSingleInstruction - Emit a single
+void HexagonMCCodeEmitter::EncodeSingleInstruction(
+ const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI, uint32_t Parse, size_t Index) const {
+ MCInst HMB = MI;
+ assert(!HexagonMCInstrInfo::isBundle(HMB));
+ uint64_t Binary;
+
+ // Pseudo instructions don't get encoded and shouldn't be here
+ // in the first place!
+ assert(!HexagonMCInstrInfo::getDesc(MCII, HMB).isPseudo() &&
+ "pseudo-instruction found");
+ DEBUG(dbgs() << "Encoding insn"
+ " `" << HexagonMCInstrInfo::getName(MCII, HMB) << "'"
+ "\n");
+
+ if (HexagonMCInstrInfo::isNewValue(MCII, HMB)) {
+ // Calculate the new value distance to the associated producer
+ MCOperand &MCO =
+ HMB.getOperand(HexagonMCInstrInfo::getNewValueOp(MCII, HMB));
+ unsigned SOffset = 0;
+ unsigned Register = MCO.getReg();
+ unsigned Register1;
+ auto Instructions = HexagonMCInstrInfo::bundleInstructions(**CurrentBundle);
+ auto i = Instructions.begin() + Index - 1;
+ for (;; --i) {
+ assert(i != Instructions.begin() - 1 && "Couldn't find producer");
+ MCInst const &Inst = *i->getInst();
+ if (HexagonMCInstrInfo::isImmext(Inst))
+ continue;
+ ++SOffset;
+ Register1 =
+ HexagonMCInstrInfo::hasNewValue(MCII, Inst)
+ ? HexagonMCInstrInfo::getNewValueOperand(MCII, Inst).getReg()
+ : static_cast<unsigned>(Hexagon::NoRegister);
+ if (Register != Register1)
+ // This isn't the register we're looking for
+ continue;
+ if (!HexagonMCInstrInfo::isPredicated(MCII, Inst))
+ // Producer is unpredicated
+ break;
+ assert(HexagonMCInstrInfo::isPredicated(MCII, HMB) &&
+ "Unpredicated consumer depending on predicated producer");
+ if (HexagonMCInstrInfo::isPredicatedTrue(MCII, Inst) ==
+ HexagonMCInstrInfo::isPredicatedTrue(MCII, HMB))
+ // Producer predicate sense matched ours
+ break;
+ }
+ // Hexagon PRM 10.11 Construct Nt from distance
+ unsigned Offset = SOffset;
+ Offset <<= 1;
+ MCO.setReg(Offset + Hexagon::R0);
+ }
+
+ Binary = getBinaryCodeForInstr(HMB, Fixups, STI);
+ // Check for unimplemented instructions. Immediate extenders
+ // are encoded as zero, so they need to be accounted for.
+ if ((!Binary) &&
+ ((HMB.getOpcode() != DuplexIClass0) && (HMB.getOpcode() != A4_ext) &&
+ (HMB.getOpcode() != A4_ext_b) && (HMB.getOpcode() != A4_ext_c) &&
+ (HMB.getOpcode() != A4_ext_g))) {
+ // Use a A2_nop for unimplemented instructions.
+ DEBUG(dbgs() << "Unimplemented inst: "
+ " `" << HexagonMCInstrInfo::getName(MCII, HMB) << "'"
+ "\n");
+ llvm_unreachable("Unimplemented Instruction");
+ }
+ Binary |= Parse;
+
+ // if we need to emit a duplexed instruction
+ if (HMB.getOpcode() >= Hexagon::DuplexIClass0 &&
+ HMB.getOpcode() <= Hexagon::DuplexIClassF) {
+ assert(Parse == HexagonII::INST_PARSE_DUPLEX &&
+ "Emitting duplex without duplex parse bits");
+ unsigned dupIClass;
+ switch (HMB.getOpcode()) {
+ case Hexagon::DuplexIClass0:
+ dupIClass = 0;
+ break;
+ case Hexagon::DuplexIClass1:
+ dupIClass = 1;
+ break;
+ case Hexagon::DuplexIClass2:
+ dupIClass = 2;
+ break;
+ case Hexagon::DuplexIClass3:
+ dupIClass = 3;
+ break;
+ case Hexagon::DuplexIClass4:
+ dupIClass = 4;
+ break;
+ case Hexagon::DuplexIClass5:
+ dupIClass = 5;
+ break;
+ case Hexagon::DuplexIClass6:
+ dupIClass = 6;
+ break;
+ case Hexagon::DuplexIClass7:
+ dupIClass = 7;
+ break;
+ case Hexagon::DuplexIClass8:
+ dupIClass = 8;
+ break;
+ case Hexagon::DuplexIClass9:
+ dupIClass = 9;
+ break;
+ case Hexagon::DuplexIClassA:
+ dupIClass = 10;
+ break;
+ case Hexagon::DuplexIClassB:
+ dupIClass = 11;
+ break;
+ case Hexagon::DuplexIClassC:
+ dupIClass = 12;
+ break;
+ case Hexagon::DuplexIClassD:
+ dupIClass = 13;
+ break;
+ case Hexagon::DuplexIClassE:
+ dupIClass = 14;
+ break;
+ case Hexagon::DuplexIClassF:
+ dupIClass = 15;
+ break;
+ default:
+ llvm_unreachable("Unimplemented DuplexIClass");
+ break;
+ }
+ // 29 is the bit position.
+ // 0b1110 =0xE bits are masked off and down shifted by 1 bit.
+ // Last bit is moved to bit position 13
+ Binary = ((dupIClass & 0xE) << (29 - 1)) | ((dupIClass & 0x1) << 13);
+
+ const MCInst *subInst0 = HMB.getOperand(0).getInst();
+ const MCInst *subInst1 = HMB.getOperand(1).getInst();
+
+ // get subinstruction slot 0
+ unsigned subInstSlot0Bits = getBinaryCodeForInstr(*subInst0, Fixups, STI);
+ // get subinstruction slot 1
+ unsigned subInstSlot1Bits = getBinaryCodeForInstr(*subInst1, Fixups, STI);
+
+ Binary |= subInstSlot0Bits | (subInstSlot1Bits << 16);
+ }
+ support::endian::Writer<support::little>(OS).write<uint32_t>(Binary);
++MCNumEmitted;
}
@@ -182,7 +351,7 @@ unsigned HexagonMCCodeEmitter::getExprOpValue(const MCInst &MI,
{
int64_t Res;
- if (ME->EvaluateAsAbsolute(Res))
+ if (ME->evaluateAsAbsolute(Res))
return Res;
MCExpr::ExprKind MK = ME->getKind();
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.h b/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.h
index 939380af1013..9aa258cee4c6 100644
--- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.h
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.h
@@ -30,6 +30,7 @@ class HexagonMCCodeEmitter : public MCCodeEmitter {
MCInstrInfo const &MCII;
std::unique_ptr<unsigned> Addend;
std::unique_ptr<bool> Extended;
+ std::unique_ptr<MCInst const *> CurrentBundle;
// helper routine for getMachineOpValue()
unsigned getExprOpValue(const MCInst &MI, const MCOperand &MO,
@@ -39,12 +40,21 @@ class HexagonMCCodeEmitter : public MCCodeEmitter {
public:
HexagonMCCodeEmitter(MCInstrInfo const &aMII, MCContext &aMCT);
+ // Return parse bits for instruction `MCI' inside bundle `MCB'
+ uint32_t parseBits(size_t Instruction, size_t Last, MCInst const &MCB,
+ MCInst const &MCI) const;
+
MCSubtargetInfo const &getSubtargetInfo() const;
void encodeInstruction(MCInst const &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
MCSubtargetInfo const &STI) const override;
+ void EncodeSingleInstruction(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI,
+ uint32_t Parse, size_t Index) const;
+
// \brief TableGen'erated function for getting the
// binary encoding for an instruction.
uint64_t getBinaryCodeForInstr(MCInst const &MI,
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCCompound.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonMCCompound.cpp
new file mode 100644
index 000000000000..108093547f82
--- /dev/null
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCCompound.cpp
@@ -0,0 +1,420 @@
+
+//=== HexagonMCCompound.cpp - Hexagon Compound checker -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is looks at a packet and tries to form compound insns
+//
+//===----------------------------------------------------------------------===//
+#include "Hexagon.h"
+#include "MCTargetDesc/HexagonBaseInfo.h"
+#include "MCTargetDesc/HexagonMCShuffler.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCSectionELF.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace Hexagon;
+
+#define DEBUG_TYPE "hexagon-mccompound"
+
+enum OpcodeIndex {
+ fp0_jump_nt = 0,
+ fp0_jump_t,
+ fp1_jump_nt,
+ fp1_jump_t,
+ tp0_jump_nt,
+ tp0_jump_t,
+ tp1_jump_nt,
+ tp1_jump_t
+};
+
+unsigned tstBitOpcode[8] = {J4_tstbit0_fp0_jump_nt, J4_tstbit0_fp0_jump_t,
+ J4_tstbit0_fp1_jump_nt, J4_tstbit0_fp1_jump_t,
+ J4_tstbit0_tp0_jump_nt, J4_tstbit0_tp0_jump_t,
+ J4_tstbit0_tp1_jump_nt, J4_tstbit0_tp1_jump_t};
+unsigned cmpeqBitOpcode[8] = {J4_cmpeq_fp0_jump_nt, J4_cmpeq_fp0_jump_t,
+ J4_cmpeq_fp1_jump_nt, J4_cmpeq_fp1_jump_t,
+ J4_cmpeq_tp0_jump_nt, J4_cmpeq_tp0_jump_t,
+ J4_cmpeq_tp1_jump_nt, J4_cmpeq_tp1_jump_t};
+unsigned cmpgtBitOpcode[8] = {J4_cmpgt_fp0_jump_nt, J4_cmpgt_fp0_jump_t,
+ J4_cmpgt_fp1_jump_nt, J4_cmpgt_fp1_jump_t,
+ J4_cmpgt_tp0_jump_nt, J4_cmpgt_tp0_jump_t,
+ J4_cmpgt_tp1_jump_nt, J4_cmpgt_tp1_jump_t};
+unsigned cmpgtuBitOpcode[8] = {J4_cmpgtu_fp0_jump_nt, J4_cmpgtu_fp0_jump_t,
+ J4_cmpgtu_fp1_jump_nt, J4_cmpgtu_fp1_jump_t,
+ J4_cmpgtu_tp0_jump_nt, J4_cmpgtu_tp0_jump_t,
+ J4_cmpgtu_tp1_jump_nt, J4_cmpgtu_tp1_jump_t};
+unsigned cmpeqiBitOpcode[8] = {J4_cmpeqi_fp0_jump_nt, J4_cmpeqi_fp0_jump_t,
+ J4_cmpeqi_fp1_jump_nt, J4_cmpeqi_fp1_jump_t,
+ J4_cmpeqi_tp0_jump_nt, J4_cmpeqi_tp0_jump_t,
+ J4_cmpeqi_tp1_jump_nt, J4_cmpeqi_tp1_jump_t};
+unsigned cmpgtiBitOpcode[8] = {J4_cmpgti_fp0_jump_nt, J4_cmpgti_fp0_jump_t,
+ J4_cmpgti_fp1_jump_nt, J4_cmpgti_fp1_jump_t,
+ J4_cmpgti_tp0_jump_nt, J4_cmpgti_tp0_jump_t,
+ J4_cmpgti_tp1_jump_nt, J4_cmpgti_tp1_jump_t};
+unsigned cmpgtuiBitOpcode[8] = {J4_cmpgtui_fp0_jump_nt, J4_cmpgtui_fp0_jump_t,
+ J4_cmpgtui_fp1_jump_nt, J4_cmpgtui_fp1_jump_t,
+ J4_cmpgtui_tp0_jump_nt, J4_cmpgtui_tp0_jump_t,
+ J4_cmpgtui_tp1_jump_nt, J4_cmpgtui_tp1_jump_t};
+unsigned cmpeqn1BitOpcode[8] = {J4_cmpeqn1_fp0_jump_nt, J4_cmpeqn1_fp0_jump_t,
+ J4_cmpeqn1_fp1_jump_nt, J4_cmpeqn1_fp1_jump_t,
+ J4_cmpeqn1_tp0_jump_nt, J4_cmpeqn1_tp0_jump_t,
+ J4_cmpeqn1_tp1_jump_nt, J4_cmpeqn1_tp1_jump_t};
+unsigned cmpgtn1BitOpcode[8] = {
+ J4_cmpgtn1_fp0_jump_nt, J4_cmpgtn1_fp0_jump_t, J4_cmpgtn1_fp1_jump_nt,
+ J4_cmpgtn1_fp1_jump_t, J4_cmpgtn1_tp0_jump_nt, J4_cmpgtn1_tp0_jump_t,
+ J4_cmpgtn1_tp1_jump_nt, J4_cmpgtn1_tp1_jump_t,
+};
+
+// enum HexagonII::CompoundGroup
+namespace {
+unsigned getCompoundCandidateGroup(MCInst const &MI, bool IsExtended) {
+ unsigned DstReg, SrcReg, Src1Reg, Src2Reg;
+
+ switch (MI.getOpcode()) {
+ default:
+ return HexagonII::HCG_None;
+ //
+ // Compound pairs.
+ // "p0=cmp.eq(Rs16,Rt16); if (p0.new) jump:nt #r9:2"
+ // "Rd16=#U6 ; jump #r9:2"
+ // "Rd16=Rs16 ; jump #r9:2"
+ //
+ case Hexagon::C2_cmpeq:
+ case Hexagon::C2_cmpgt:
+ case Hexagon::C2_cmpgtu:
+ if (IsExtended)
+ return false;
+ DstReg = MI.getOperand(0).getReg();
+ Src1Reg = MI.getOperand(1).getReg();
+ Src2Reg = MI.getOperand(2).getReg();
+ if ((Hexagon::P0 == DstReg || Hexagon::P1 == DstReg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(Src1Reg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(Src2Reg))
+ return HexagonII::HCG_A;
+ break;
+ case Hexagon::C2_cmpeqi:
+ case Hexagon::C2_cmpgti:
+ case Hexagon::C2_cmpgtui:
+ if (IsExtended)
+ return false;
+ // P0 = cmp.eq(Rs,#u2)
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
+ if ((Hexagon::P0 == DstReg || Hexagon::P1 == DstReg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) &&
+ MI.getOperand(2).isImm() && ((isUInt<5>(MI.getOperand(2).getImm())) ||
+ (MI.getOperand(2).getImm() == -1)))
+ return HexagonII::HCG_A;
+ break;
+ case Hexagon::A2_tfr:
+ if (IsExtended)
+ return false;
+ // Rd = Rs
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
+ if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(SrcReg))
+ return HexagonII::HCG_A;
+ break;
+ case Hexagon::A2_tfrsi:
+ if (IsExtended)
+ return false;
+ // Rd = #u6
+ DstReg = MI.getOperand(0).getReg();
+ if (MI.getOperand(1).isImm() && MI.getOperand(1).getImm() <= 63 &&
+ MI.getOperand(1).getImm() >= 0 &&
+ HexagonMCInstrInfo::isIntRegForSubInst(DstReg))
+ return HexagonII::HCG_A;
+ break;
+ case Hexagon::S2_tstbit_i:
+ if (IsExtended)
+ return false;
+ DstReg = MI.getOperand(0).getReg();
+ Src1Reg = MI.getOperand(1).getReg();
+ if ((Hexagon::P0 == DstReg || Hexagon::P1 == DstReg) &&
+ MI.getOperand(2).isImm() &&
+ HexagonMCInstrInfo::isIntRegForSubInst(Src1Reg) &&
+ (MI.getOperand(2).getImm() == 0))
+ return HexagonII::HCG_A;
+ break;
+ // The fact that .new form is used pretty much guarantees
+ // that predicate register will match. Nevertheless,
+ // there could be some false positives without additional
+ // checking.
+ case Hexagon::J2_jumptnew:
+ case Hexagon::J2_jumpfnew:
+ case Hexagon::J2_jumptnewpt:
+ case Hexagon::J2_jumpfnewpt:
+ Src1Reg = MI.getOperand(0).getReg();
+ if (Hexagon::P0 == Src1Reg || Hexagon::P1 == Src1Reg)
+ return HexagonII::HCG_B;
+ break;
+ // Transfer and jump:
+ // Rd=#U6 ; jump #r9:2
+ // Rd=Rs ; jump #r9:2
+ // Do not test for jump range here.
+ case Hexagon::J2_jump:
+ case Hexagon::RESTORE_DEALLOC_RET_JMP_V4:
+ return HexagonII::HCG_C;
+ break;
+ }
+
+ return HexagonII::HCG_None;
+}
+}
+
+/// getCompoundOp - Return the index from 0-7 into the above opcode lists.
+namespace {
+unsigned getCompoundOp(MCInst const &HMCI) {
+ const MCOperand &Predicate = HMCI.getOperand(0);
+ unsigned PredReg = Predicate.getReg();
+
+ assert((PredReg == Hexagon::P0) || (PredReg == Hexagon::P1) ||
+ (PredReg == Hexagon::P2) || (PredReg == Hexagon::P3));
+
+ switch (HMCI.getOpcode()) {
+ default:
+ llvm_unreachable("Expected match not found.\n");
+ break;
+ case Hexagon::J2_jumpfnew:
+ return (PredReg == Hexagon::P0) ? fp0_jump_nt : fp1_jump_nt;
+ case Hexagon::J2_jumpfnewpt:
+ return (PredReg == Hexagon::P0) ? fp0_jump_t : fp1_jump_t;
+ case Hexagon::J2_jumptnew:
+ return (PredReg == Hexagon::P0) ? tp0_jump_nt : tp1_jump_nt;
+ case Hexagon::J2_jumptnewpt:
+ return (PredReg == Hexagon::P0) ? tp0_jump_t : tp1_jump_t;
+ }
+}
+}
+
+namespace {
+MCInst *getCompoundInsn(MCContext &Context, MCInst const &L, MCInst const &R) {
+ MCInst *CompoundInsn = 0;
+ unsigned compoundOpcode;
+ MCOperand Rs, Rt;
+
+ switch (L.getOpcode()) {
+ default:
+ DEBUG(dbgs() << "Possible compound ignored\n");
+ return CompoundInsn;
+
+ case Hexagon::A2_tfrsi:
+ Rt = L.getOperand(0);
+ compoundOpcode = J4_jumpseti;
+ CompoundInsn = new (Context) MCInst;
+ CompoundInsn->setOpcode(compoundOpcode);
+
+ CompoundInsn->addOperand(Rt);
+ CompoundInsn->addOperand(L.getOperand(1)); // Immediate
+ CompoundInsn->addOperand(R.getOperand(0)); // Jump target
+ break;
+
+ case Hexagon::A2_tfr:
+ Rt = L.getOperand(0);
+ Rs = L.getOperand(1);
+
+ compoundOpcode = J4_jumpsetr;
+ CompoundInsn = new (Context) MCInst;
+ CompoundInsn->setOpcode(compoundOpcode);
+ CompoundInsn->addOperand(Rt);
+ CompoundInsn->addOperand(Rs);
+ CompoundInsn->addOperand(R.getOperand(0)); // Jump target.
+
+ break;
+
+ case Hexagon::C2_cmpeq:
+ DEBUG(dbgs() << "CX: C2_cmpeq\n");
+ Rs = L.getOperand(1);
+ Rt = L.getOperand(2);
+
+ compoundOpcode = cmpeqBitOpcode[getCompoundOp(R)];
+ CompoundInsn = new (Context) MCInst;
+ CompoundInsn->setOpcode(compoundOpcode);
+ CompoundInsn->addOperand(Rs);
+ CompoundInsn->addOperand(Rt);
+ CompoundInsn->addOperand(R.getOperand(1));
+ break;
+
+ case Hexagon::C2_cmpgt:
+ DEBUG(dbgs() << "CX: C2_cmpgt\n");
+ Rs = L.getOperand(1);
+ Rt = L.getOperand(2);
+
+ compoundOpcode = cmpgtBitOpcode[getCompoundOp(R)];
+ CompoundInsn = new (Context) MCInst;
+ CompoundInsn->setOpcode(compoundOpcode);
+ CompoundInsn->addOperand(Rs);
+ CompoundInsn->addOperand(Rt);
+ CompoundInsn->addOperand(R.getOperand(1));
+ break;
+
+ case Hexagon::C2_cmpgtu:
+ DEBUG(dbgs() << "CX: C2_cmpgtu\n");
+ Rs = L.getOperand(1);
+ Rt = L.getOperand(2);
+
+ compoundOpcode = cmpgtuBitOpcode[getCompoundOp(R)];
+ CompoundInsn = new (Context) MCInst;
+ CompoundInsn->setOpcode(compoundOpcode);
+ CompoundInsn->addOperand(Rs);
+ CompoundInsn->addOperand(Rt);
+ CompoundInsn->addOperand(R.getOperand(1));
+ break;
+
+ case Hexagon::C2_cmpeqi:
+ DEBUG(dbgs() << "CX: C2_cmpeqi\n");
+ if (L.getOperand(2).getImm() == -1)
+ compoundOpcode = cmpeqn1BitOpcode[getCompoundOp(R)];
+ else
+ compoundOpcode = cmpeqiBitOpcode[getCompoundOp(R)];
+
+ Rs = L.getOperand(1);
+ CompoundInsn = new (Context) MCInst;
+ CompoundInsn->setOpcode(compoundOpcode);
+ CompoundInsn->addOperand(Rs);
+ if (L.getOperand(2).getImm() != -1)
+ CompoundInsn->addOperand(L.getOperand(2));
+ CompoundInsn->addOperand(R.getOperand(1));
+ break;
+
+ case Hexagon::C2_cmpgti:
+ DEBUG(dbgs() << "CX: C2_cmpgti\n");
+ if (L.getOperand(2).getImm() == -1)
+ compoundOpcode = cmpgtn1BitOpcode[getCompoundOp(R)];
+ else
+ compoundOpcode = cmpgtiBitOpcode[getCompoundOp(R)];
+
+ Rs = L.getOperand(1);
+ CompoundInsn = new (Context) MCInst;
+ CompoundInsn->setOpcode(compoundOpcode);
+ CompoundInsn->addOperand(Rs);
+ if (L.getOperand(2).getImm() != -1)
+ CompoundInsn->addOperand(L.getOperand(2));
+ CompoundInsn->addOperand(R.getOperand(1));
+ break;
+
+ case Hexagon::C2_cmpgtui:
+ DEBUG(dbgs() << "CX: C2_cmpgtui\n");
+ Rs = L.getOperand(1);
+ compoundOpcode = cmpgtuiBitOpcode[getCompoundOp(R)];
+ CompoundInsn = new (Context) MCInst;
+ CompoundInsn->setOpcode(compoundOpcode);
+ CompoundInsn->addOperand(Rs);
+ CompoundInsn->addOperand(L.getOperand(2));
+ CompoundInsn->addOperand(R.getOperand(1));
+ break;
+
+ case Hexagon::S2_tstbit_i:
+ DEBUG(dbgs() << "CX: S2_tstbit_i\n");
+ Rs = L.getOperand(1);
+ compoundOpcode = tstBitOpcode[getCompoundOp(R)];
+ CompoundInsn = new (Context) MCInst;
+ CompoundInsn->setOpcode(compoundOpcode);
+ CompoundInsn->addOperand(Rs);
+ CompoundInsn->addOperand(R.getOperand(1));
+ break;
+ }
+
+ return CompoundInsn;
+}
+}
+
+/// Non-Symmetrical. See if these two instructions are fit for compound pair.
+namespace {
+bool isOrderedCompoundPair(MCInst const &MIa, bool IsExtendedA,
+ MCInst const &MIb, bool IsExtendedB) {
+ unsigned MIaG = getCompoundCandidateGroup(MIa, IsExtendedA);
+ unsigned MIbG = getCompoundCandidateGroup(MIb, IsExtendedB);
+ // We have two candidates - check that this is the same register
+ // we are talking about.
+ unsigned Opca = MIa.getOpcode();
+ if (MIaG == HexagonII::HCG_A && MIbG == HexagonII::HCG_C &&
+ (Opca == Hexagon::A2_tfr || Opca == Hexagon::A2_tfrsi))
+ return true;
+ return ((MIaG == HexagonII::HCG_A && MIbG == HexagonII::HCG_B) &&
+ (MIa.getOperand(0).getReg() == MIb.getOperand(0).getReg()));
+}
+}
+
+namespace {
+bool lookForCompound(MCInstrInfo const &MCII, MCContext &Context, MCInst &MCI) {
+ assert(HexagonMCInstrInfo::isBundle(MCI));
+ bool JExtended = false;
+ for (MCInst::iterator J =
+ MCI.begin() + HexagonMCInstrInfo::bundleInstructionsOffset;
+ J != MCI.end(); ++J) {
+ MCInst const *JumpInst = J->getInst();
+ if (HexagonMCInstrInfo::isImmext(*JumpInst)) {
+ JExtended = true;
+ continue;
+ }
+ if (llvm::HexagonMCInstrInfo::getType(MCII, *JumpInst) ==
+ HexagonII::TypeJ) {
+ // Try to pair with another insn (B)undled with jump.
+ bool BExtended = false;
+ for (MCInst::iterator B =
+ MCI.begin() + HexagonMCInstrInfo::bundleInstructionsOffset;
+ B != MCI.end(); ++B) {
+ MCInst const *Inst = B->getInst();
+ if (JumpInst == Inst)
+ continue;
+ if (HexagonMCInstrInfo::isImmext(*Inst)) {
+ BExtended = true;
+ continue;
+ }
+ DEBUG(dbgs() << "J,B: " << JumpInst->getOpcode() << ","
+ << Inst->getOpcode() << "\n");
+ if (isOrderedCompoundPair(*Inst, BExtended, *JumpInst, JExtended)) {
+ MCInst *CompoundInsn = getCompoundInsn(Context, *Inst, *JumpInst);
+ if (CompoundInsn) {
+ DEBUG(dbgs() << "B: " << Inst->getOpcode() << ","
+ << JumpInst->getOpcode() << " Compounds to "
+ << CompoundInsn->getOpcode() << "\n");
+ J->setInst(CompoundInsn);
+ MCI.erase(B);
+ return true;
+ }
+ }
+ BExtended = false;
+ }
+ }
+ JExtended = false;
+ }
+ return false;
+}
+}
+
+/// tryCompound - Given a bundle check for compound insns when one
+/// is found update the contents fo the bundle with the compound insn.
+/// If a compound instruction is found then the bundle will have one
+/// additional slot.
+void HexagonMCInstrInfo::tryCompound(MCInstrInfo const &MCII,
+ MCContext &Context, MCInst &MCI) {
+ assert(MCI.getOpcode() == Hexagon::BUNDLE &&
+ "Non-Bundle where Bundle expected");
+
+ // By definition a compound must have 2 insn.
+ if (MCI.size() < 2)
+ return;
+
+ // Look for compounds until none are found, only update the bundle when
+ // a compound is found.
+ while (lookForCompound(MCII, Context, MCI))
+ ;
+
+ return;
+}
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp
new file mode 100644
index 000000000000..eb629774a2cd
--- /dev/null
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp
@@ -0,0 +1,1100 @@
+//===----- HexagonMCDuplexInfo.cpp - Instruction bundle checking ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This implements duplexing of instructions to reduce code size
+//
+//===----------------------------------------------------------------------===//
+
+#include "HexagonBaseInfo.h"
+#include "MCTargetDesc/HexagonMCInstrInfo.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <map>
+
+using namespace llvm;
+using namespace Hexagon;
+
+#define DEBUG_TYPE "hexagon-mcduplex-info"
+
+// pair table of subInstructions with opcodes
+static std::pair<unsigned, unsigned> opcodeData[] = {
+ std::make_pair((unsigned)V4_SA1_addi, 0),
+ std::make_pair((unsigned)V4_SA1_addrx, 6144),
+ std::make_pair((unsigned)V4_SA1_addsp, 3072),
+ std::make_pair((unsigned)V4_SA1_and1, 4608),
+ std::make_pair((unsigned)V4_SA1_clrf, 6768),
+ std::make_pair((unsigned)V4_SA1_clrfnew, 6736),
+ std::make_pair((unsigned)V4_SA1_clrt, 6752),
+ std::make_pair((unsigned)V4_SA1_clrtnew, 6720),
+ std::make_pair((unsigned)V4_SA1_cmpeqi, 6400),
+ std::make_pair((unsigned)V4_SA1_combine0i, 7168),
+ std::make_pair((unsigned)V4_SA1_combine1i, 7176),
+ std::make_pair((unsigned)V4_SA1_combine2i, 7184),
+ std::make_pair((unsigned)V4_SA1_combine3i, 7192),
+ std::make_pair((unsigned)V4_SA1_combinerz, 7432),
+ std::make_pair((unsigned)V4_SA1_combinezr, 7424),
+ std::make_pair((unsigned)V4_SA1_dec, 4864),
+ std::make_pair((unsigned)V4_SA1_inc, 4352),
+ std::make_pair((unsigned)V4_SA1_seti, 2048),
+ std::make_pair((unsigned)V4_SA1_setin1, 6656),
+ std::make_pair((unsigned)V4_SA1_sxtb, 5376),
+ std::make_pair((unsigned)V4_SA1_sxth, 5120),
+ std::make_pair((unsigned)V4_SA1_tfr, 4096),
+ std::make_pair((unsigned)V4_SA1_zxtb, 5888),
+ std::make_pair((unsigned)V4_SA1_zxth, 5632),
+ std::make_pair((unsigned)V4_SL1_loadri_io, 0),
+ std::make_pair((unsigned)V4_SL1_loadrub_io, 4096),
+ std::make_pair((unsigned)V4_SL2_deallocframe, 7936),
+ std::make_pair((unsigned)V4_SL2_jumpr31, 8128),
+ std::make_pair((unsigned)V4_SL2_jumpr31_f, 8133),
+ std::make_pair((unsigned)V4_SL2_jumpr31_fnew, 8135),
+ std::make_pair((unsigned)V4_SL2_jumpr31_t, 8132),
+ std::make_pair((unsigned)V4_SL2_jumpr31_tnew, 8134),
+ std::make_pair((unsigned)V4_SL2_loadrb_io, 4096),
+ std::make_pair((unsigned)V4_SL2_loadrd_sp, 7680),
+ std::make_pair((unsigned)V4_SL2_loadrh_io, 0),
+ std::make_pair((unsigned)V4_SL2_loadri_sp, 7168),
+ std::make_pair((unsigned)V4_SL2_loadruh_io, 2048),
+ std::make_pair((unsigned)V4_SL2_return, 8000),
+ std::make_pair((unsigned)V4_SL2_return_f, 8005),
+ std::make_pair((unsigned)V4_SL2_return_fnew, 8007),
+ std::make_pair((unsigned)V4_SL2_return_t, 8004),
+ std::make_pair((unsigned)V4_SL2_return_tnew, 8006),
+ std::make_pair((unsigned)V4_SS1_storeb_io, 4096),
+ std::make_pair((unsigned)V4_SS1_storew_io, 0),
+ std::make_pair((unsigned)V4_SS2_allocframe, 7168),
+ std::make_pair((unsigned)V4_SS2_storebi0, 4608),
+ std::make_pair((unsigned)V4_SS2_storebi1, 4864),
+ std::make_pair((unsigned)V4_SS2_stored_sp, 2560),
+ std::make_pair((unsigned)V4_SS2_storeh_io, 0),
+ std::make_pair((unsigned)V4_SS2_storew_sp, 2048),
+ std::make_pair((unsigned)V4_SS2_storewi0, 4096),
+ std::make_pair((unsigned)V4_SS2_storewi1, 4352)};
+
+static std::map<unsigned, unsigned>
+ subinstOpcodeMap(opcodeData,
+ opcodeData + sizeof(opcodeData) / sizeof(opcodeData[0]));
+
+bool HexagonMCInstrInfo::isDuplexPairMatch(unsigned Ga, unsigned Gb) {
+ switch (Ga) {
+ case HexagonII::HSIG_None:
+ default:
+ return false;
+ case HexagonII::HSIG_L1:
+ return (Gb == HexagonII::HSIG_L1 || Gb == HexagonII::HSIG_A);
+ case HexagonII::HSIG_L2:
+ return (Gb == HexagonII::HSIG_L1 || Gb == HexagonII::HSIG_L2 ||
+ Gb == HexagonII::HSIG_A);
+ case HexagonII::HSIG_S1:
+ return (Gb == HexagonII::HSIG_L1 || Gb == HexagonII::HSIG_L2 ||
+ Gb == HexagonII::HSIG_S1 || Gb == HexagonII::HSIG_A);
+ case HexagonII::HSIG_S2:
+ return (Gb == HexagonII::HSIG_L1 || Gb == HexagonII::HSIG_L2 ||
+ Gb == HexagonII::HSIG_S1 || Gb == HexagonII::HSIG_S2 ||
+ Gb == HexagonII::HSIG_A);
+ case HexagonII::HSIG_A:
+ return (Gb == HexagonII::HSIG_A);
+ case HexagonII::HSIG_Compound:
+ return (Gb == HexagonII::HSIG_Compound);
+ }
+ return false;
+}
+
+unsigned HexagonMCInstrInfo::iClassOfDuplexPair(unsigned Ga, unsigned Gb) {
+ switch (Ga) {
+ case HexagonII::HSIG_None:
+ default:
+ break;
+ case HexagonII::HSIG_L1:
+ switch (Gb) {
+ default:
+ break;
+ case HexagonII::HSIG_L1:
+ return 0;
+ case HexagonII::HSIG_A:
+ return 0x4;
+ }
+ case HexagonII::HSIG_L2:
+ switch (Gb) {
+ default:
+ break;
+ case HexagonII::HSIG_L1:
+ return 0x1;
+ case HexagonII::HSIG_L2:
+ return 0x2;
+ case HexagonII::HSIG_A:
+ return 0x5;
+ }
+ case HexagonII::HSIG_S1:
+ switch (Gb) {
+ default:
+ break;
+ case HexagonII::HSIG_L1:
+ return 0x8;
+ case HexagonII::HSIG_L2:
+ return 0x9;
+ case HexagonII::HSIG_S1:
+ return 0xA;
+ case HexagonII::HSIG_A:
+ return 0x6;
+ }
+ case HexagonII::HSIG_S2:
+ switch (Gb) {
+ default:
+ break;
+ case HexagonII::HSIG_L1:
+ return 0xC;
+ case HexagonII::HSIG_L2:
+ return 0xD;
+ case HexagonII::HSIG_S1:
+ return 0xB;
+ case HexagonII::HSIG_S2:
+ return 0xE;
+ case HexagonII::HSIG_A:
+ return 0x7;
+ }
+ case HexagonII::HSIG_A:
+ switch (Gb) {
+ default:
+ break;
+ case HexagonII::HSIG_A:
+ return 0x3;
+ }
+ case HexagonII::HSIG_Compound:
+ switch (Gb) {
+ case HexagonII::HSIG_Compound:
+ return 0xFFFFFFFF;
+ }
+ }
+ return 0xFFFFFFFF;
+}
+
+unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) {
+ unsigned DstReg, PredReg, SrcReg, Src1Reg, Src2Reg;
+
+ switch (MCI.getOpcode()) {
+ default:
+ return HexagonII::HSIG_None;
+ //
+ // Group L1:
+ //
+ // Rd = memw(Rs+#u4:2)
+ // Rd = memub(Rs+#u4:0)
+ case Hexagon::L2_loadri_io:
+ DstReg = MCI.getOperand(0).getReg();
+ SrcReg = MCI.getOperand(1).getReg();
+ // Special case this one from Group L2.
+ // Rd = memw(r29+#u5:2)
+ if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg)) {
+ if (HexagonMCInstrInfo::isIntReg(SrcReg) && Hexagon::R29 == SrcReg &&
+ MCI.getOperand(2).isImm() &&
+ isShiftedUInt<5, 2>(MCI.getOperand(2).getImm())) {
+ return HexagonII::HSIG_L2;
+ }
+ // Rd = memw(Rs+#u4:2)
+ if (HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) &&
+ (MCI.getOperand(2).isImm() &&
+ isShiftedUInt<4, 2>(MCI.getOperand(2).getImm()))) {
+ return HexagonII::HSIG_L1;
+ }
+ }
+ break;
+ case Hexagon::L2_loadrub_io:
+ // Rd = memub(Rs+#u4:0)
+ DstReg = MCI.getOperand(0).getReg();
+ SrcReg = MCI.getOperand(1).getReg();
+ if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) &&
+ MCI.getOperand(2).isImm() && isUInt<4>(MCI.getOperand(2).getImm())) {
+ return HexagonII::HSIG_L1;
+ }
+ break;
+ //
+ // Group L2:
+ //
+ // Rd = memh/memuh(Rs+#u3:1)
+ // Rd = memb(Rs+#u3:0)
+ // Rd = memw(r29+#u5:2) - Handled above.
+ // Rdd = memd(r29+#u5:3)
+ // deallocframe
+ // [if ([!]p0[.new])] dealloc_return
+ // [if ([!]p0[.new])] jumpr r31
+ case Hexagon::L2_loadrh_io:
+ case Hexagon::L2_loadruh_io:
+ // Rd = memh/memuh(Rs+#u3:1)
+ DstReg = MCI.getOperand(0).getReg();
+ SrcReg = MCI.getOperand(1).getReg();
+ if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) &&
+ MCI.getOperand(2).isImm() &&
+ isShiftedUInt<3, 1>(MCI.getOperand(2).getImm())) {
+ return HexagonII::HSIG_L2;
+ }
+ break;
+ case Hexagon::L2_loadrb_io:
+ // Rd = memb(Rs+#u3:0)
+ DstReg = MCI.getOperand(0).getReg();
+ SrcReg = MCI.getOperand(1).getReg();
+ if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) &&
+ MCI.getOperand(2).isImm() && isUInt<3>(MCI.getOperand(2).getImm())) {
+ return HexagonII::HSIG_L2;
+ }
+ break;
+ case Hexagon::L2_loadrd_io:
+ // Rdd = memd(r29+#u5:3)
+ DstReg = MCI.getOperand(0).getReg();
+ SrcReg = MCI.getOperand(1).getReg();
+ if (HexagonMCInstrInfo::isDblRegForSubInst(DstReg) &&
+ HexagonMCInstrInfo::isIntReg(SrcReg) && Hexagon::R29 == SrcReg &&
+ MCI.getOperand(2).isImm() &&
+ isShiftedUInt<5, 3>(MCI.getOperand(2).getImm())) {
+ return HexagonII::HSIG_L2;
+ }
+ break;
+
+ case Hexagon::L4_return:
+
+ case Hexagon::L2_deallocframe:
+
+ return HexagonII::HSIG_L2;
+ case Hexagon::EH_RETURN_JMPR:
+
+ case Hexagon::J2_jumpr:
+ case Hexagon::JMPret:
+ // jumpr r31
+ // Actual form JMPR %PC<imp-def>, %R31<imp-use>, %R0<imp-use,internal>.
+ DstReg = MCI.getOperand(0).getReg();
+ if (Hexagon::R31 == DstReg) {
+ return HexagonII::HSIG_L2;
+ }
+ break;
+
+ case Hexagon::J2_jumprt:
+ case Hexagon::J2_jumprf:
+ case Hexagon::J2_jumprtnew:
+ case Hexagon::J2_jumprfnew:
+ case Hexagon::JMPrett:
+ case Hexagon::JMPretf:
+ case Hexagon::JMPrettnew:
+ case Hexagon::JMPretfnew:
+ case Hexagon::JMPrettnewpt:
+ case Hexagon::JMPretfnewpt:
+ DstReg = MCI.getOperand(1).getReg();
+ SrcReg = MCI.getOperand(0).getReg();
+ // [if ([!]p0[.new])] jumpr r31
+ if ((HexagonMCInstrInfo::isPredReg(SrcReg) && (Hexagon::P0 == SrcReg)) &&
+ (Hexagon::R31 == DstReg)) {
+ return HexagonII::HSIG_L2;
+ }
+ break;
+ case Hexagon::L4_return_t:
+
+ case Hexagon::L4_return_f:
+
+ case Hexagon::L4_return_tnew_pnt:
+
+ case Hexagon::L4_return_fnew_pnt:
+
+ case Hexagon::L4_return_tnew_pt:
+
+ case Hexagon::L4_return_fnew_pt:
+ // [if ([!]p0[.new])] dealloc_return
+ SrcReg = MCI.getOperand(0).getReg();
+ if (Hexagon::P0 == SrcReg) {
+ return HexagonII::HSIG_L2;
+ }
+ break;
+ //
+ // Group S1:
+ //
+ // memw(Rs+#u4:2) = Rt
+ // memb(Rs+#u4:0) = Rt
+ case Hexagon::S2_storeri_io:
+ // Special case this one from Group S2.
+ // memw(r29+#u5:2) = Rt
+ Src1Reg = MCI.getOperand(0).getReg();
+ Src2Reg = MCI.getOperand(2).getReg();
+ if (HexagonMCInstrInfo::isIntReg(Src1Reg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(Src2Reg) &&
+ Hexagon::R29 == Src1Reg && MCI.getOperand(1).isImm() &&
+ isShiftedUInt<5, 2>(MCI.getOperand(1).getImm())) {
+ return HexagonII::HSIG_S2;
+ }
+ // memw(Rs+#u4:2) = Rt
+ if (HexagonMCInstrInfo::isIntRegForSubInst(Src1Reg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(Src2Reg) &&
+ MCI.getOperand(1).isImm() &&
+ isShiftedUInt<4, 2>(MCI.getOperand(1).getImm())) {
+ return HexagonII::HSIG_S1;
+ }
+ break;
+ case Hexagon::S2_storerb_io:
+ // memb(Rs+#u4:0) = Rt
+ Src1Reg = MCI.getOperand(0).getReg();
+ Src2Reg = MCI.getOperand(2).getReg();
+ if (HexagonMCInstrInfo::isIntRegForSubInst(Src1Reg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(Src2Reg) &&
+ MCI.getOperand(1).isImm() && isUInt<4>(MCI.getOperand(1).getImm())) {
+ return HexagonII::HSIG_S1;
+ }
+ break;
+ //
+ // Group S2:
+ //
+ // memh(Rs+#u3:1) = Rt
+ // memw(r29+#u5:2) = Rt
+ // memd(r29+#s6:3) = Rtt
+ // memw(Rs+#u4:2) = #U1
+ // memb(Rs+#u4) = #U1
+ // allocframe(#u5:3)
+ case Hexagon::S2_storerh_io:
+ // memh(Rs+#u3:1) = Rt
+ Src1Reg = MCI.getOperand(0).getReg();
+ Src2Reg = MCI.getOperand(2).getReg();
+ if (HexagonMCInstrInfo::isIntRegForSubInst(Src1Reg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(Src2Reg) &&
+ MCI.getOperand(1).isImm() &&
+ isShiftedUInt<3, 1>(MCI.getOperand(1).getImm())) {
+ return HexagonII::HSIG_S2;
+ }
+ break;
+ case Hexagon::S2_storerd_io:
+ // memd(r29+#s6:3) = Rtt
+ Src1Reg = MCI.getOperand(0).getReg();
+ Src2Reg = MCI.getOperand(2).getReg();
+ if (HexagonMCInstrInfo::isDblRegForSubInst(Src2Reg) &&
+ HexagonMCInstrInfo::isIntReg(Src1Reg) && Hexagon::R29 == Src1Reg &&
+ MCI.getOperand(1).isImm() &&
+ isShiftedInt<6, 3>(MCI.getOperand(1).getImm())) {
+ return HexagonII::HSIG_S2;
+ }
+ break;
+ case Hexagon::S4_storeiri_io:
+ // memw(Rs+#u4:2) = #U1
+ Src1Reg = MCI.getOperand(0).getReg();
+ if (HexagonMCInstrInfo::isIntRegForSubInst(Src1Reg) &&
+ MCI.getOperand(1).isImm() &&
+ isShiftedUInt<4, 2>(MCI.getOperand(1).getImm()) &&
+ MCI.getOperand(2).isImm() && isUInt<1>(MCI.getOperand(2).getImm())) {
+ return HexagonII::HSIG_S2;
+ }
+ break;
+ case Hexagon::S4_storeirb_io:
+ // memb(Rs+#u4) = #U1
+ Src1Reg = MCI.getOperand(0).getReg();
+ if (HexagonMCInstrInfo::isIntRegForSubInst(Src1Reg) &&
+ MCI.getOperand(1).isImm() && isUInt<4>(MCI.getOperand(1).getImm()) &&
+ MCI.getOperand(2).isImm() && MCI.getOperand(2).isImm() &&
+ isUInt<1>(MCI.getOperand(2).getImm())) {
+ return HexagonII::HSIG_S2;
+ }
+ break;
+ case Hexagon::S2_allocframe:
+ if (MCI.getOperand(0).isImm() &&
+ isShiftedUInt<5, 3>(MCI.getOperand(0).getImm())) {
+ return HexagonII::HSIG_S2;
+ }
+ break;
+ //
+ // Group A:
+ //
+ // Rx = add(Rx,#s7)
+ // Rd = Rs
+ // Rd = #u6
+ // Rd = #-1
+ // if ([!]P0[.new]) Rd = #0
+ // Rd = add(r29,#u6:2)
+ // Rx = add(Rx,Rs)
+ // P0 = cmp.eq(Rs,#u2)
+ // Rdd = combine(#0,Rs)
+ // Rdd = combine(Rs,#0)
+ // Rdd = combine(#u2,#U2)
+ // Rd = add(Rs,#1)
+ // Rd = add(Rs,#-1)
+ // Rd = sxth/sxtb/zxtb/zxth(Rs)
+ // Rd = and(Rs,#1)
+ case Hexagon::A2_addi:
+ DstReg = MCI.getOperand(0).getReg();
+ SrcReg = MCI.getOperand(1).getReg();
+ if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg)) {
+ // Rd = add(r29,#u6:2)
+ if (HexagonMCInstrInfo::isIntReg(SrcReg) && Hexagon::R29 == SrcReg &&
+ MCI.getOperand(2).isImm() &&
+ isShiftedUInt<6, 2>(MCI.getOperand(2).getImm())) {
+ return HexagonII::HSIG_A;
+ }
+ // Rx = add(Rx,#s7)
+ if (DstReg == SrcReg) {
+ return HexagonII::HSIG_A;
+ }
+ // Rd = add(Rs,#1)
+ // Rd = add(Rs,#-1)
+ if (HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) &&
+ MCI.getOperand(2).isImm() && ((MCI.getOperand(2).getImm() == 1) ||
+ (MCI.getOperand(2).getImm() == -1))) {
+ return HexagonII::HSIG_A;
+ }
+ }
+ break;
+ case Hexagon::A2_add:
+ // Rx = add(Rx,Rs)
+ DstReg = MCI.getOperand(0).getReg();
+ Src1Reg = MCI.getOperand(1).getReg();
+ Src2Reg = MCI.getOperand(2).getReg();
+ if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg) && (DstReg == Src1Reg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(Src2Reg)) {
+ return HexagonII::HSIG_A;
+ }
+ break;
+ case Hexagon::A2_andir:
+ DstReg = MCI.getOperand(0).getReg();
+ SrcReg = MCI.getOperand(1).getReg();
+ if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) &&
+ MCI.getOperand(2).isImm() && ((MCI.getOperand(2).getImm() == 1) ||
+ (MCI.getOperand(2).getImm() == 255))) {
+ return HexagonII::HSIG_A;
+ }
+ break;
+ case Hexagon::A2_tfr:
+ // Rd = Rs
+ DstReg = MCI.getOperand(0).getReg();
+ SrcReg = MCI.getOperand(1).getReg();
+ if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(SrcReg)) {
+ return HexagonII::HSIG_A;
+ }
+ break;
+ case Hexagon::A2_tfrsi:
+ DstReg = MCI.getOperand(0).getReg();
+
+ if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg)) {
+ return HexagonII::HSIG_A;
+ }
+ break;
+ case Hexagon::C2_cmoveit:
+ case Hexagon::C2_cmovenewit:
+ case Hexagon::C2_cmoveif:
+ case Hexagon::C2_cmovenewif:
+ // if ([!]P0[.new]) Rd = #0
+ // Actual form:
+ // %R16<def> = C2_cmovenewit %P0<internal>, 0, %R16<imp-use,undef>;
+ DstReg = MCI.getOperand(0).getReg(); // Rd
+ PredReg = MCI.getOperand(1).getReg(); // P0
+ if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg) &&
+ Hexagon::P0 == PredReg && MCI.getOperand(2).isImm() &&
+ MCI.getOperand(2).getImm() == 0) {
+ return HexagonII::HSIG_A;
+ }
+ break;
+ case Hexagon::C2_cmpeqi:
+ // P0 = cmp.eq(Rs,#u2)
+ DstReg = MCI.getOperand(0).getReg();
+ SrcReg = MCI.getOperand(1).getReg();
+ if (Hexagon::P0 == DstReg &&
+ HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) &&
+ MCI.getOperand(2).isImm() && isUInt<2>(MCI.getOperand(2).getImm())) {
+ return HexagonII::HSIG_A;
+ }
+ break;
+ case Hexagon::A2_combineii:
+ case Hexagon::A4_combineii:
+ // Rdd = combine(#u2,#U2)
+ DstReg = MCI.getOperand(0).getReg();
+ if (HexagonMCInstrInfo::isDblRegForSubInst(DstReg) &&
+ // TODO: Handle Globals/Symbols
+ (MCI.getOperand(1).isImm() && isUInt<2>(MCI.getOperand(1).getImm())) &&
+ ((MCI.getOperand(2).isImm() &&
+ isUInt<2>(MCI.getOperand(2).getImm())))) {
+ return HexagonII::HSIG_A;
+ }
+ break;
+ case Hexagon::A4_combineri:
+ // Rdd = combine(Rs,#0)
+ DstReg = MCI.getOperand(0).getReg();
+ SrcReg = MCI.getOperand(1).getReg();
+ if (HexagonMCInstrInfo::isDblRegForSubInst(DstReg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) &&
+ (MCI.getOperand(2).isImm() && MCI.getOperand(2).getImm() == 0)) {
+ return HexagonII::HSIG_A;
+ }
+ break;
+ case Hexagon::A4_combineir:
+ // Rdd = combine(#0,Rs)
+ DstReg = MCI.getOperand(0).getReg();
+ SrcReg = MCI.getOperand(2).getReg();
+ if (HexagonMCInstrInfo::isDblRegForSubInst(DstReg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) &&
+ (MCI.getOperand(1).isImm() && MCI.getOperand(1).getImm() == 0)) {
+ return HexagonII::HSIG_A;
+ }
+ break;
+ case Hexagon::A2_sxtb:
+ case Hexagon::A2_sxth:
+ case Hexagon::A2_zxtb:
+ case Hexagon::A2_zxth:
+ // Rd = sxth/sxtb/zxtb/zxth(Rs)
+ DstReg = MCI.getOperand(0).getReg();
+ SrcReg = MCI.getOperand(1).getReg();
+ if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg) &&
+ HexagonMCInstrInfo::isIntRegForSubInst(SrcReg)) {
+ return HexagonII::HSIG_A;
+ }
+ break;
+ }
+
+ return HexagonII::HSIG_None;
+}
+
+bool HexagonMCInstrInfo::subInstWouldBeExtended(MCInst const &potentialDuplex) {
+
+ unsigned DstReg, SrcReg;
+
+ switch (potentialDuplex.getOpcode()) {
+ case Hexagon::A2_addi:
+ // testing for case of: Rx = add(Rx,#s7)
+ DstReg = potentialDuplex.getOperand(0).getReg();
+ SrcReg = potentialDuplex.getOperand(1).getReg();
+ if (DstReg == SrcReg && HexagonMCInstrInfo::isIntRegForSubInst(DstReg)) {
+ if (potentialDuplex.getOperand(2).isExpr())
+ return true;
+ if (potentialDuplex.getOperand(2).isImm() &&
+ !(isShiftedInt<7, 0>(potentialDuplex.getOperand(2).getImm())))
+ return true;
+ }
+ break;
+ case Hexagon::A2_tfrsi:
+ DstReg = potentialDuplex.getOperand(0).getReg();
+
+ if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg)) {
+ if (potentialDuplex.getOperand(1).isExpr())
+ return true;
+ // Check for case of Rd = #-1.
+ if (potentialDuplex.getOperand(1).isImm() &&
+ (potentialDuplex.getOperand(1).getImm() == -1))
+ return false;
+ // Check for case of Rd = #u6.
+ if (potentialDuplex.getOperand(1).isImm() &&
+ !isShiftedUInt<6, 0>(potentialDuplex.getOperand(1).getImm()))
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+/// non-Symmetrical. See if these two instructions are fit for duplex pair.
+bool HexagonMCInstrInfo::isOrderedDuplexPair(MCInstrInfo const &MCII,
+ MCInst const &MIa, bool ExtendedA,
+ MCInst const &MIb, bool ExtendedB,
+ bool bisReversable) {
+ // Slot 1 cannot be extended in duplexes PRM 10.5
+ if (ExtendedA)
+ return false;
+ // Only A2_addi and A2_tfrsi can be extended in duplex form PRM 10.5
+ if (ExtendedB) {
+ unsigned Opcode = MIb.getOpcode();
+ if ((Opcode != Hexagon::A2_addi) && (Opcode != Hexagon::A2_tfrsi))
+ return false;
+ }
+ unsigned MIaG = HexagonMCInstrInfo::getDuplexCandidateGroup(MIa),
+ MIbG = HexagonMCInstrInfo::getDuplexCandidateGroup(MIb);
+
+ // If a duplex contains 2 insns in the same group, the insns must be
+ // ordered such that the numerically smaller opcode is in slot 1.
+ if ((MIaG != HexagonII::HSIG_None) && (MIaG == MIbG) && bisReversable) {
+ MCInst SubInst0 = HexagonMCInstrInfo::deriveSubInst(MIa);
+ MCInst SubInst1 = HexagonMCInstrInfo::deriveSubInst(MIb);
+
+ unsigned zeroedSubInstS0 =
+ subinstOpcodeMap.find(SubInst0.getOpcode())->second;
+ unsigned zeroedSubInstS1 =
+ subinstOpcodeMap.find(SubInst1.getOpcode())->second;
+
+ if (zeroedSubInstS0 < zeroedSubInstS1)
+ // subinstS0 (maps to slot 0) must be greater than
+ // subinstS1 (maps to slot 1)
+ return false;
+ }
+
+ // allocframe must always be in slot 0
+ if (MIb.getOpcode() == Hexagon::S2_allocframe)
+ return false;
+
+ if ((MIaG != HexagonII::HSIG_None) && (MIbG != HexagonII::HSIG_None)) {
+ // Prevent 2 instructions with extenders from duplexing
+ // Note that MIb (slot1) can be extended and MIa (slot0)
+ // can never be extended
+ if (subInstWouldBeExtended(MIa))
+ return false;
+
+ // If duplexing produces an extender, but the original did not
+ // have an extender, do not duplex.
+ if (subInstWouldBeExtended(MIb) && !ExtendedB)
+ return false;
+ }
+
+ // If jumpr r31 appears, it must be in slot 0, and never slot 1 (MIb).
+ if (MIbG == HexagonII::HSIG_L2) {
+ if ((MIb.getNumOperands() > 1) && MIb.getOperand(1).isReg() &&
+ (MIb.getOperand(1).getReg() == Hexagon::R31))
+ return false;
+ if ((MIb.getNumOperands() > 0) && MIb.getOperand(0).isReg() &&
+ (MIb.getOperand(0).getReg() == Hexagon::R31))
+ return false;
+ }
+
+ // If a store appears, it must be in slot 0 (MIa) 1st, and then slot 1 (MIb);
+ // therefore, not duplexable if slot 1 is a store, and slot 0 is not.
+ if ((MIbG == HexagonII::HSIG_S1) || (MIbG == HexagonII::HSIG_S2)) {
+ if ((MIaG != HexagonII::HSIG_S1) && (MIaG != HexagonII::HSIG_S2))
+ return false;
+ }
+
+ return (isDuplexPairMatch(MIaG, MIbG));
+}
+
+/// Symmetrical. See if these two instructions are fit for duplex pair.
+bool HexagonMCInstrInfo::isDuplexPair(MCInst const &MIa, MCInst const &MIb) {
+ unsigned MIaG = getDuplexCandidateGroup(MIa),
+ MIbG = getDuplexCandidateGroup(MIb);
+ return (isDuplexPairMatch(MIaG, MIbG) || isDuplexPairMatch(MIbG, MIaG));
+}
+
+inline static void addOps(MCInst &subInstPtr, MCInst const &Inst,
+ unsigned opNum) {
+ if (Inst.getOperand(opNum).isReg()) {
+ switch (Inst.getOperand(opNum).getReg()) {
+ default:
+ llvm_unreachable("Not Duplexable Register");
+ break;
+ case Hexagon::R0:
+ case Hexagon::R1:
+ case Hexagon::R2:
+ case Hexagon::R3:
+ case Hexagon::R4:
+ case Hexagon::R5:
+ case Hexagon::R6:
+ case Hexagon::R7:
+ case Hexagon::D0:
+ case Hexagon::D1:
+ case Hexagon::D2:
+ case Hexagon::D3:
+ case Hexagon::R16:
+ case Hexagon::R17:
+ case Hexagon::R18:
+ case Hexagon::R19:
+ case Hexagon::R20:
+ case Hexagon::R21:
+ case Hexagon::R22:
+ case Hexagon::R23:
+ case Hexagon::D8:
+ case Hexagon::D9:
+ case Hexagon::D10:
+ case Hexagon::D11:
+ subInstPtr.addOperand(Inst.getOperand(opNum));
+ break;
+ }
+ } else
+ subInstPtr.addOperand(Inst.getOperand(opNum));
+}
+
+MCInst HexagonMCInstrInfo::deriveSubInst(MCInst const &Inst) {
+ MCInst Result;
+ switch (Inst.getOpcode()) {
+ default:
+ // dbgs() << "opcode: "<< Inst->getOpcode() << "\n";
+ llvm_unreachable("Unimplemented subinstruction \n");
+ break;
+ case Hexagon::A2_addi:
+ if (Inst.getOperand(2).isImm() && Inst.getOperand(2).getImm() == 1) {
+ Result.setOpcode(Hexagon::V4_SA1_inc);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ break;
+ } // 1,2 SUBInst $Rd = add($Rs, #1)
+ else if (Inst.getOperand(2).isImm() && Inst.getOperand(2).getImm() == -1) {
+ Result.setOpcode(Hexagon::V4_SA1_dec);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ break;
+ } // 1,2 SUBInst $Rd = add($Rs,#-1)
+ else if (Inst.getOperand(1).getReg() == Hexagon::R29) {
+ Result.setOpcode(Hexagon::V4_SA1_addsp);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 2);
+ break;
+ } // 1,3 SUBInst $Rd = add(r29, #$u6_2)
+ else {
+ Result.setOpcode(Hexagon::V4_SA1_addi);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ addOps(Result, Inst, 2);
+ break;
+ } // 1,2,3 SUBInst $Rx = add($Rx, #$s7)
+ case Hexagon::A2_add:
+ Result.setOpcode(Hexagon::V4_SA1_addrx);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ addOps(Result, Inst, 2);
+ break; // 1,2,3 SUBInst $Rx = add($_src_, $Rs)
+ case Hexagon::S2_allocframe:
+ Result.setOpcode(Hexagon::V4_SS2_allocframe);
+ addOps(Result, Inst, 0);
+ break; // 1 SUBInst allocframe(#$u5_3)
+ case Hexagon::A2_andir:
+ if (Inst.getOperand(2).getImm() == 255) {
+ Result.setOpcode(Hexagon::V4_SA1_zxtb);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ break; // 1,2 $Rd = and($Rs, #255)
+ } else {
+ Result.setOpcode(Hexagon::V4_SA1_and1);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ break; // 1,2 SUBInst $Rd = and($Rs, #1)
+ }
+ case Hexagon::C2_cmpeqi:
+ Result.setOpcode(Hexagon::V4_SA1_cmpeqi);
+ addOps(Result, Inst, 1);
+ addOps(Result, Inst, 2);
+ break; // 2,3 SUBInst p0 = cmp.eq($Rs, #$u2)
+ case Hexagon::A4_combineii:
+ case Hexagon::A2_combineii:
+ if (Inst.getOperand(1).getImm() == 1) {
+ Result.setOpcode(Hexagon::V4_SA1_combine1i);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 2);
+ break; // 1,3 SUBInst $Rdd = combine(#1, #$u2)
+ }
+
+ if (Inst.getOperand(1).getImm() == 3) {
+ Result.setOpcode(Hexagon::V4_SA1_combine3i);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 2);
+ break; // 1,3 SUBInst $Rdd = combine(#3, #$u2)
+ }
+ if (Inst.getOperand(1).getImm() == 0) {
+ Result.setOpcode(Hexagon::V4_SA1_combine0i);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 2);
+ break; // 1,3 SUBInst $Rdd = combine(#0, #$u2)
+ }
+ if (Inst.getOperand(1).getImm() == 2) {
+ Result.setOpcode(Hexagon::V4_SA1_combine2i);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 2);
+ break; // 1,3 SUBInst $Rdd = combine(#2, #$u2)
+ }
+ case Hexagon::A4_combineir:
+ Result.setOpcode(Hexagon::V4_SA1_combinezr);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 2);
+ break; // 1,3 SUBInst $Rdd = combine(#0, $Rs)
+
+ case Hexagon::A4_combineri:
+ Result.setOpcode(Hexagon::V4_SA1_combinerz);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ break; // 1,2 SUBInst $Rdd = combine($Rs, #0)
+ case Hexagon::L4_return_tnew_pnt:
+ case Hexagon::L4_return_tnew_pt:
+ Result.setOpcode(Hexagon::V4_SL2_return_tnew);
+ break; // none SUBInst if (p0.new) dealloc_return:nt
+ case Hexagon::L4_return_fnew_pnt:
+ case Hexagon::L4_return_fnew_pt:
+ Result.setOpcode(Hexagon::V4_SL2_return_fnew);
+ break; // none SUBInst if (!p0.new) dealloc_return:nt
+ case Hexagon::L4_return_f:
+ Result.setOpcode(Hexagon::V4_SL2_return_f);
+ break; // none SUBInst if (!p0) dealloc_return
+ case Hexagon::L4_return_t:
+ Result.setOpcode(Hexagon::V4_SL2_return_t);
+ break; // none SUBInst if (p0) dealloc_return
+ case Hexagon::L4_return:
+ Result.setOpcode(Hexagon::V4_SL2_return);
+ break; // none SUBInst dealloc_return
+ case Hexagon::L2_deallocframe:
+ Result.setOpcode(Hexagon::V4_SL2_deallocframe);
+ break; // none SUBInst deallocframe
+ case Hexagon::EH_RETURN_JMPR:
+ case Hexagon::J2_jumpr:
+ case Hexagon::JMPret:
+ Result.setOpcode(Hexagon::V4_SL2_jumpr31);
+ break; // none SUBInst jumpr r31
+ case Hexagon::J2_jumprf:
+ case Hexagon::JMPretf:
+ Result.setOpcode(Hexagon::V4_SL2_jumpr31_f);
+ break; // none SUBInst if (!p0) jumpr r31
+ case Hexagon::J2_jumprfnew:
+ case Hexagon::JMPretfnewpt:
+ case Hexagon::JMPretfnew:
+ Result.setOpcode(Hexagon::V4_SL2_jumpr31_fnew);
+ break; // none SUBInst if (!p0.new) jumpr:nt r31
+ case Hexagon::J2_jumprt:
+ case Hexagon::JMPrett:
+ Result.setOpcode(Hexagon::V4_SL2_jumpr31_t);
+ break; // none SUBInst if (p0) jumpr r31
+ case Hexagon::J2_jumprtnew:
+ case Hexagon::JMPrettnewpt:
+ case Hexagon::JMPrettnew:
+ Result.setOpcode(Hexagon::V4_SL2_jumpr31_tnew);
+ break; // none SUBInst if (p0.new) jumpr:nt r31
+ case Hexagon::L2_loadrb_io:
+ Result.setOpcode(Hexagon::V4_SL2_loadrb_io);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ addOps(Result, Inst, 2);
+ break; // 1,2,3 SUBInst $Rd = memb($Rs + #$u3_0)
+ case Hexagon::L2_loadrd_io:
+ Result.setOpcode(Hexagon::V4_SL2_loadrd_sp);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 2);
+ break; // 1,3 SUBInst $Rdd = memd(r29 + #$u5_3)
+ case Hexagon::L2_loadrh_io:
+ Result.setOpcode(Hexagon::V4_SL2_loadrh_io);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ addOps(Result, Inst, 2);
+ break; // 1,2,3 SUBInst $Rd = memh($Rs + #$u3_1)
+ case Hexagon::L2_loadrub_io:
+ Result.setOpcode(Hexagon::V4_SL1_loadrub_io);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ addOps(Result, Inst, 2);
+ break; // 1,2,3 SUBInst $Rd = memub($Rs + #$u4_0)
+ case Hexagon::L2_loadruh_io:
+ Result.setOpcode(Hexagon::V4_SL2_loadruh_io);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ addOps(Result, Inst, 2);
+ break; // 1,2,3 SUBInst $Rd = memuh($Rs + #$u3_1)
+ case Hexagon::L2_loadri_io:
+ if (Inst.getOperand(1).getReg() == Hexagon::R29) {
+ Result.setOpcode(Hexagon::V4_SL2_loadri_sp);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 2);
+ break; // 2 1,3 SUBInst $Rd = memw(r29 + #$u5_2)
+ } else {
+ Result.setOpcode(Hexagon::V4_SL1_loadri_io);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ addOps(Result, Inst, 2);
+ break; // 1,2,3 SUBInst $Rd = memw($Rs + #$u4_2)
+ }
+ case Hexagon::S4_storeirb_io:
+ if (Inst.getOperand(2).getImm() == 0) {
+ Result.setOpcode(Hexagon::V4_SS2_storebi0);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ break; // 1,2 SUBInst memb($Rs + #$u4_0)=#0
+ } else if (Inst.getOperand(2).getImm() == 1) {
+ Result.setOpcode(Hexagon::V4_SS2_storebi1);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ break; // 2 1,2 SUBInst memb($Rs + #$u4_0)=#1
+ }
+ case Hexagon::S2_storerb_io:
+ Result.setOpcode(Hexagon::V4_SS1_storeb_io);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ addOps(Result, Inst, 2);
+ break; // 1,2,3 SUBInst memb($Rs + #$u4_0) = $Rt
+ case Hexagon::S2_storerd_io:
+ Result.setOpcode(Hexagon::V4_SS2_stored_sp);
+ addOps(Result, Inst, 1);
+ addOps(Result, Inst, 2);
+ break; // 2,3 SUBInst memd(r29 + #$s6_3) = $Rtt
+ case Hexagon::S2_storerh_io:
+ Result.setOpcode(Hexagon::V4_SS2_storeh_io);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ addOps(Result, Inst, 2);
+ break; // 1,2,3 SUBInst memb($Rs + #$u4_0) = $Rt
+ case Hexagon::S4_storeiri_io:
+ if (Inst.getOperand(2).getImm() == 0) {
+ Result.setOpcode(Hexagon::V4_SS2_storewi0);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ break; // 3 1,2 SUBInst memw($Rs + #$u4_2)=#0
+ } else if (Inst.getOperand(2).getImm() == 1) {
+ Result.setOpcode(Hexagon::V4_SS2_storewi1);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ break; // 3 1,2 SUBInst memw($Rs + #$u4_2)=#1
+ } else if (Inst.getOperand(0).getReg() == Hexagon::R29) {
+ Result.setOpcode(Hexagon::V4_SS2_storew_sp);
+ addOps(Result, Inst, 1);
+ addOps(Result, Inst, 2);
+ break; // 1 2,3 SUBInst memw(r29 + #$u5_2) = $Rt
+ }
+ case Hexagon::S2_storeri_io:
+ if (Inst.getOperand(0).getReg() == Hexagon::R29) {
+ Result.setOpcode(Hexagon::V4_SS2_storew_sp);
+ addOps(Result, Inst, 1);
+ addOps(Result, Inst, 2); // 1,2,3 SUBInst memw(sp + #$u5_2) = $Rt
+ } else {
+ Result.setOpcode(Hexagon::V4_SS1_storew_io);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ addOps(Result, Inst, 2); // 1,2,3 SUBInst memw($Rs + #$u4_2) = $Rt
+ }
+ break;
+ case Hexagon::A2_sxtb:
+ Result.setOpcode(Hexagon::V4_SA1_sxtb);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ break; // 1,2 SUBInst $Rd = sxtb($Rs)
+ case Hexagon::A2_sxth:
+ Result.setOpcode(Hexagon::V4_SA1_sxth);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ break; // 1,2 SUBInst $Rd = sxth($Rs)
+ case Hexagon::A2_tfr:
+ Result.setOpcode(Hexagon::V4_SA1_tfr);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ break; // 1,2 SUBInst $Rd = $Rs
+ case Hexagon::C2_cmovenewif:
+ Result.setOpcode(Hexagon::V4_SA1_clrfnew);
+ addOps(Result, Inst, 0);
+ break; // 2 SUBInst if (!p0.new) $Rd = #0
+ case Hexagon::C2_cmovenewit:
+ Result.setOpcode(Hexagon::V4_SA1_clrtnew);
+ addOps(Result, Inst, 0);
+ break; // 2 SUBInst if (p0.new) $Rd = #0
+ case Hexagon::C2_cmoveif:
+ Result.setOpcode(Hexagon::V4_SA1_clrf);
+ addOps(Result, Inst, 0);
+ break; // 2 SUBInst if (!p0) $Rd = #0
+ case Hexagon::C2_cmoveit:
+ Result.setOpcode(Hexagon::V4_SA1_clrt);
+ addOps(Result, Inst, 0);
+ break; // 2 SUBInst if (p0) $Rd = #0
+ case Hexagon::A2_tfrsi:
+ if (Inst.getOperand(1).isImm() && Inst.getOperand(1).getImm() == -1) {
+ Result.setOpcode(Hexagon::V4_SA1_setin1);
+ addOps(Result, Inst, 0);
+ break; // 2 1 SUBInst $Rd = #-1
+ } else {
+ Result.setOpcode(Hexagon::V4_SA1_seti);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ break; // 1,2 SUBInst $Rd = #$u6
+ }
+ case Hexagon::A2_zxtb:
+ Result.setOpcode(Hexagon::V4_SA1_zxtb);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ break; // 1,2 $Rd = and($Rs, #255)
+
+ case Hexagon::A2_zxth:
+ Result.setOpcode(Hexagon::V4_SA1_zxth);
+ addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
+ break; // 1,2 SUBInst $Rd = zxth($Rs)
+ }
+ return Result;
+}
+
+static bool isStoreInst(unsigned opCode) {
+ switch (opCode) {
+ case Hexagon::S2_storeri_io:
+ case Hexagon::S2_storerb_io:
+ case Hexagon::S2_storerh_io:
+ case Hexagon::S2_storerd_io:
+ case Hexagon::S4_storeiri_io:
+ case Hexagon::S4_storeirb_io:
+ case Hexagon::S2_allocframe:
+ return true;
+ default:
+ return false;
+ }
+}
+
+SmallVector<DuplexCandidate, 8>
+HexagonMCInstrInfo::getDuplexPossibilties(MCInstrInfo const &MCII,
+ MCInst const &MCB) {
+ assert(isBundle(MCB));
+ SmallVector<DuplexCandidate, 8> duplexToTry;
+ // Use an "order matters" version of isDuplexPair.
+ unsigned numInstrInPacket = MCB.getNumOperands();
+
+ for (unsigned distance = 1; distance < numInstrInPacket; ++distance) {
+ for (unsigned j = HexagonMCInstrInfo::bundleInstructionsOffset,
+ k = j + distance;
+ (j < numInstrInPacket) && (k < numInstrInPacket); ++j, ++k) {
+
+ // Check if reversable.
+ bool bisReversable = true;
+ if (isStoreInst(MCB.getOperand(j).getInst()->getOpcode()) &&
+ isStoreInst(MCB.getOperand(k).getInst()->getOpcode())) {
+ DEBUG(dbgs() << "skip out of order write pair: " << k << "," << j
+ << "\n");
+ bisReversable = false;
+ }
+
+ // Try in order.
+ if (isOrderedDuplexPair(
+ MCII, *MCB.getOperand(k).getInst(),
+ HexagonMCInstrInfo::hasExtenderForIndex(MCB, k - 1),
+ *MCB.getOperand(j).getInst(),
+ HexagonMCInstrInfo::hasExtenderForIndex(MCB, j - 1),
+ bisReversable)) {
+ // Get iClass.
+ unsigned iClass = iClassOfDuplexPair(
+ getDuplexCandidateGroup(*MCB.getOperand(k).getInst()),
+ getDuplexCandidateGroup(*MCB.getOperand(j).getInst()));
+
+ // Save off pairs for duplex checking.
+ duplexToTry.push_back(DuplexCandidate(j, k, iClass));
+ DEBUG(dbgs() << "adding pair: " << j << "," << k << ":"
+ << MCB.getOperand(j).getInst()->getOpcode() << ","
+ << MCB.getOperand(k).getInst()->getOpcode() << "\n");
+ continue;
+ } else {
+ DEBUG(dbgs() << "skipping pair: " << j << "," << k << ":"
+ << MCB.getOperand(j).getInst()->getOpcode() << ","
+ << MCB.getOperand(k).getInst()->getOpcode() << "\n");
+ }
+
+ // Try reverse.
+ if (bisReversable) {
+ if (isOrderedDuplexPair(
+ MCII, *MCB.getOperand(j).getInst(),
+ HexagonMCInstrInfo::hasExtenderForIndex(MCB, j - 1),
+ *MCB.getOperand(k).getInst(),
+ HexagonMCInstrInfo::hasExtenderForIndex(MCB, k - 1),
+ bisReversable)) {
+ // Get iClass.
+ unsigned iClass = iClassOfDuplexPair(
+ getDuplexCandidateGroup(*MCB.getOperand(j).getInst()),
+ getDuplexCandidateGroup(*MCB.getOperand(k).getInst()));
+
+ // Save off pairs for duplex checking.
+ duplexToTry.push_back(DuplexCandidate(k, j, iClass));
+ DEBUG(dbgs() << "adding pair:" << k << "," << j << ":"
+ << MCB.getOperand(j).getInst()->getOpcode() << ","
+ << MCB.getOperand(k).getInst()->getOpcode() << "\n");
+ } else {
+ DEBUG(dbgs() << "skipping pair: " << k << "," << j << ":"
+ << MCB.getOperand(j).getInst()->getOpcode() << ","
+ << MCB.getOperand(k).getInst()->getOpcode() << "\n");
+ }
+ }
+ }
+ }
+ return duplexToTry;
+}
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp
index 93c7a0d98bf2..2731278f0e41 100644
--- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp
@@ -12,12 +12,53 @@
//===----------------------------------------------------------------------===//
#include "HexagonMCInstrInfo.h"
+
+#include "Hexagon.h"
#include "HexagonBaseInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+
namespace llvm {
-void HexagonMCInstrInfo::AppendImplicitOperands(MCInst &MCI) {
- MCI.addOperand(MCOperand::createImm(0));
- MCI.addOperand(MCOperand::createInst(nullptr));
+iterator_range<MCInst::const_iterator>
+HexagonMCInstrInfo::bundleInstructions(MCInst const &MCI) {
+ assert(isBundle(MCI));
+ return iterator_range<MCInst::const_iterator>(
+ MCI.begin() + bundleInstructionsOffset, MCI.end());
+}
+
+size_t HexagonMCInstrInfo::bundleSize(MCInst const &MCI) {
+ if (HexagonMCInstrInfo::isBundle(MCI))
+ return (MCI.size() - bundleInstructionsOffset);
+ else
+ return (1);
+}
+
+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;
}
HexagonII::MemAccessSize
@@ -46,6 +87,24 @@ MCInstrDesc const &HexagonMCInstrInfo::getDesc(MCInstrInfo const &MCII,
return (MCII.get(MCI.getOpcode()));
}
+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;
@@ -58,12 +117,6 @@ unsigned HexagonMCInstrInfo::getExtentBits(MCInstrInfo const &MCII,
return ((F >> HexagonII::ExtentBitsPos) & HexagonII::ExtentBitsMask);
}
-std::bitset<16> HexagonMCInstrInfo::GetImplicitBits(MCInst const &MCI) {
- SanityCheckImplicitOperands(MCI);
- std::bitset<16> Bits(MCI.getOperand(MCI.getNumOperands() - 2).getImm());
- return Bits;
-}
-
// Return the max value that a constant extendable operand can have
// without being extended.
int HexagonMCInstrInfo::getMaxValue(MCInstrInfo const &MCII,
@@ -99,9 +152,14 @@ char const *HexagonMCInstrInfo::getName(MCInstrInfo const &MCII,
return MCII.getName(MCI.getOpcode());
}
-// Return the operand that consumes or produces a new value.
-MCOperand const &HexagonMCInstrInfo::getNewValue(MCInstrInfo const &MCII,
+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) {
uint64_t const F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags;
unsigned const O =
(F >> HexagonII::NewValueOpPos) & HexagonII::NewValueOpMask;
@@ -113,6 +171,21 @@ MCOperand const &HexagonMCInstrInfo::getNewValue(MCInstrInfo const &MCII,
return (MCO);
}
+int HexagonMCInstrInfo::getSubTarget(MCInstrInfo const &MCII,
+ MCInst const &MCI) {
+ const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags;
+
+ HexagonII::SubTarget Target = static_cast<HexagonII::SubTarget>(
+ (F >> HexagonII::validSubTargetPos) & HexagonII::validSubTargetMask);
+
+ switch (Target) {
+ default:
+ return Hexagon::ArchV4;
+ case HexagonII::HasV5SubT:
+ return Hexagon::ArchV5;
+ }
+}
+
// Return the Hexagon ISA class for the insn.
unsigned HexagonMCInstrInfo::getType(MCInstrInfo const &MCII,
MCInst const &MCI) {
@@ -121,6 +194,32 @@ unsigned HexagonMCInstrInfo::getType(MCInstrInfo const &MCII,
return ((F >> HexagonII::TypePos) & HexagonII::TypeMask);
}
+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());
+}
+
+bool HexagonMCInstrInfo::hasImmExt(MCInst const &MCI) {
+ if (!HexagonMCInstrInfo::isBundle(MCI))
+ return false;
+
+ for (const auto &I : HexagonMCInstrInfo::bundleInstructions(MCI)) {
+ auto MI = I.getInst();
+ if (isImmext(*MI))
+ return true;
+ }
+
+ return false;
+}
+
+bool HexagonMCInstrInfo::hasExtenderForIndex(MCInst const &MCB, size_t Index) {
+ return extenderForIndex(MCB, Index) != nullptr;
+}
+
// Return whether the instruction is a legal new-value producer.
bool HexagonMCInstrInfo::hasNewValue(MCInstrInfo const &MCII,
MCInst const &MCI) {
@@ -128,6 +227,18 @@ bool HexagonMCInstrInfo::hasNewValue(MCInstrInfo const &MCII,
return ((F >> HexagonII::hasNewValuePos) & HexagonII::hasNewValueMask);
}
+MCInst const &HexagonMCInstrInfo::instruction(MCInst const &MCB, size_t Index) {
+ assert(isBundle(MCB));
+ assert(Index < HEXAGON_PACKET_SIZE);
+ return *MCB.getOperand(bundleInstructionsOffset + Index).getInst();
+}
+
+bool HexagonMCInstrInfo::isBundle(MCInst const &MCI) {
+ auto Result = Hexagon::BUNDLE == MCI.getOpcode();
+ assert(!Result || (MCI.size() > 0 && MCI.getOperand(0).isImm()));
+ return Result;
+}
+
// Return whether the insn is an actual insn.
bool HexagonMCInstrInfo::isCanon(MCInstrInfo const &MCII, MCInst const &MCI) {
return (!HexagonMCInstrInfo::getDesc(MCII, MCI).isPseudo() &&
@@ -135,6 +246,15 @@ bool HexagonMCInstrInfo::isCanon(MCInstrInfo const &MCII, MCInst const &MCI) {
HexagonMCInstrInfo::getType(MCII, MCI) != HexagonII::TypeENDLOOP);
}
+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);
+}
+
// Return whether the instruction needs to be constant extended.
// 1) Always return true if the instruction has 'isExtended' flag set.
//
@@ -173,20 +293,44 @@ bool HexagonMCInstrInfo::isConstExtended(MCInstrInfo const &MCII,
return (ImmValue < MinValue || ImmValue > MaxValue);
}
-// Return true if the instruction may be extended based on the operand value.
bool HexagonMCInstrInfo::isExtendable(MCInstrInfo const &MCII,
MCInst const &MCI) {
uint64_t const F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags;
return (F >> HexagonII::ExtendablePos) & HexagonII::ExtendableMask;
}
-// Return whether the instruction must be always extended.
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::isImmext(MCInst const &MCI) {
+ auto Op = MCI.getOpcode();
+ return (Op == Hexagon::A4_ext_b || Op == Hexagon::A4_ext_c ||
+ Op == Hexagon::A4_ext_g || Op == 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 is a new-value consumer.
bool HexagonMCInstrInfo::isNewValue(MCInstrInfo const &MCII,
MCInst const &MCI) {
@@ -203,46 +347,103 @@ bool HexagonMCInstrInfo::isOperandExtended(MCInstrInfo const &MCII,
OperandNum;
}
-bool HexagonMCInstrInfo::isPacketBegin(MCInst const &MCI) {
- std::bitset<16> Bits(GetImplicitBits(MCI));
- return Bits.test(packetBeginIndex);
+bool HexagonMCInstrInfo::isOuterLoop(MCInst const &MCI) {
+ assert(isBundle(MCI));
+ int64_t Flags = MCI.getOperand(0).getImm();
+ return (Flags & outerLoopMask) != 0;
}
-bool HexagonMCInstrInfo::isPacketEnd(MCInst const &MCI) {
- std::bitset<16> Bits(GetImplicitBits(MCI));
- return Bits.test(packetEndIndex);
+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::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(unsigned Reg) {
+ return (Reg >= Hexagon::P0 && Reg <= Hexagon::P3_0);
}
-// Return whether the insn is a prefix.
bool HexagonMCInstrInfo::isPrefix(MCInstrInfo const &MCII, MCInst const &MCI) {
return (HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypePREFIX);
}
-// 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 = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags;
return ((F >> HexagonII::SoloPos) & HexagonII::SoloMask);
}
-void HexagonMCInstrInfo::resetPacket(MCInst &MCI) {
- setPacketBegin(MCI, false);
- setPacketEnd(MCI, false);
+bool HexagonMCInstrInfo::isSoloAX(MCInstrInfo const &MCII, MCInst const &MCI) {
+ const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags;
+ return ((F >> HexagonII::SoloAXPos) & HexagonII::SoloAXMask);
+}
+
+bool HexagonMCInstrInfo::isSoloAin1(MCInstrInfo const &MCII,
+ MCInst const &MCI) {
+ const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags;
+ return ((F >> HexagonII::SoloAin1Pos) & HexagonII::SoloAin1Mask);
+}
+
+void HexagonMCInstrInfo::padEndloop(MCInst &MCB) {
+ MCInst Nop;
+ Nop.setOpcode(Hexagon::A2_nop);
+ assert(isBundle(MCB));
+ while ((HexagonMCInstrInfo::isInnerLoop(MCB) &&
+ (HexagonMCInstrInfo::bundleSize(MCB) < HEXAGON_PACKET_INNER_SIZE)) ||
+ ((HexagonMCInstrInfo::isOuterLoop(MCB) &&
+ (HexagonMCInstrInfo::bundleSize(MCB) < HEXAGON_PACKET_OUTER_SIZE))))
+ MCB.addOperand(MCOperand::createInst(new MCInst(Nop)));
+}
+
+bool HexagonMCInstrInfo::prefersSlot3(MCInstrInfo const &MCII,
+ MCInst const &MCI) {
+ if (HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeCR)
+ return false;
+
+ unsigned SchedClass = HexagonMCInstrInfo::getDesc(MCII, MCI).getSchedClass();
+ switch (SchedClass) {
+ case Hexagon::Sched::ALU32_3op_tc_2_SLOT0123:
+ case Hexagon::Sched::ALU64_tc_2_SLOT23:
+ case Hexagon::Sched::ALU64_tc_3x_SLOT23:
+ case Hexagon::Sched::M_tc_2_SLOT23:
+ case Hexagon::Sched::M_tc_3x_SLOT23:
+ case Hexagon::Sched::S_2op_tc_2_SLOT23:
+ case Hexagon::Sched::S_3op_tc_2_SLOT23:
+ case Hexagon::Sched::S_3op_tc_3x_SLOT23:
+ return true;
+ }
+ return false;
}
-void HexagonMCInstrInfo::SetImplicitBits(MCInst &MCI, std::bitset<16> Bits) {
- SanityCheckImplicitOperands(MCI);
- MCI.getOperand(MCI.getNumOperands() - 2).setImm(Bits.to_ulong());
+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::setPacketBegin(MCInst &MCI, bool f) {
- std::bitset<16> Bits(GetImplicitBits(MCI));
- Bits.set(packetBeginIndex, f);
- SetImplicitBits(MCI, Bits);
+void HexagonMCInstrInfo::setInnerLoop(MCInst &MCI) {
+ assert(isBundle(MCI));
+ MCOperand &Operand = MCI.getOperand(0);
+ Operand.setImm(Operand.getImm() | innerLoopMask);
}
-void HexagonMCInstrInfo::setPacketEnd(MCInst &MCI, bool f) {
- std::bitset<16> Bits(GetImplicitBits(MCI));
- Bits.set(packetEndIndex, f);
- SetImplicitBits(MCI, Bits);
+void HexagonMCInstrInfo::setOuterLoop(MCInst &MCI) {
+ assert(isBundle(MCI));
+ MCOperand &Operand = MCI.getOperand(0);
+ Operand.setImm(Operand.getImm() | outerLoopMask);
}
}
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h b/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h
index 082c80d5ac05..09f305f638e2 100644
--- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h
@@ -1,4 +1,4 @@
-//===- HexagonMCInstrInfo.cpp - Hexagon sub-class of MCInst ---------------===//
+//===- HexagonMCInstrInfo.cpp - Utility functions on Hexagon MCInsts ------===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,20 +15,47 @@
#define LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONMCINSTRINFO_H
#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCInstrInfo.h"
-
-#include <bitset>
namespace llvm {
+class MCContext;
class MCInstrDesc;
class MCInstrInfo;
class MCInst;
class MCOperand;
+class MCSubtargetInfo;
namespace HexagonII {
enum class MemAccessSize;
}
+class DuplexCandidate {
+public:
+ unsigned packetIndexI, packetIndexJ, iClass;
+ DuplexCandidate(unsigned i, unsigned j, unsigned iClass)
+ : packetIndexI(i), packetIndexJ(j), iClass(iClass) {}
+};
namespace HexagonMCInstrInfo {
-void AppendImplicitOperands(MCInst &MCI);
+size_t const innerLoopOffset = 0;
+int64_t const innerLoopMask = 1 << innerLoopOffset;
+
+size_t const outerLoopOffset = 1;
+int64_t const outerLoopMask = 1 << outerLoopOffset;
+
+size_t const bundleInstructionsOffset = 1;
+
+// Returns the number of instructions in the bundle
+size_t bundleSize(MCInst const &MCI);
+
+// Returns a iterator range of instructions in this bundle
+iterator_range<MCInst::const_iterator> bundleInstructions(MCInst const &MCI);
+
+// Return the extender for instruction at Index or nullptr if none
+MCInst const *extenderForIndex(MCInst const &MCB, size_t Index);
+
+// Create a duplex instruction given the two subinsts
+MCInst *deriveDuplex(MCContext &Context, unsigned iClass, MCInst const &inst0,
+ MCInst const &inst1);
+
+// Convert this instruction in to a duplex subinst
+MCInst deriveSubInst(MCInst const &Inst);
// Return memory access size
HexagonII::MemAccessSize getAccessSize(MCInstrInfo const &MCII,
@@ -42,14 +69,26 @@ unsigned short getCExtOpNum(MCInstrInfo const &MCII, MCInst const &MCI);
MCInstrDesc const &getDesc(MCInstrInfo const &MCII, MCInst const &MCI);
+// Return which duplex group this instruction belongs to
+unsigned getDuplexCandidateGroup(MCInst const &MI);
+
+// Return a list of all possible instruction duplex combinations
+SmallVector<DuplexCandidate, 8> getDuplexPossibilties(MCInstrInfo const &MCII,
+ MCInst const &MCB);
+
+// Return the index of the extendable operand
+unsigned short getExtendableOp(MCInstrInfo const &MCII, MCInst const &MCI);
+
+// Return a reference to the extendable operand
+MCOperand const &getExtendableOperand(MCInstrInfo const &MCII,
+ MCInst const &MCI);
+
// Return the implicit alignment of the extendable operand
unsigned getExtentAlignment(MCInstrInfo const &MCII, MCInst const &MCI);
// Return the number of logical bits of the extendable operand
unsigned getExtentBits(MCInstrInfo const &MCII, MCInst const &MCI);
-std::bitset<16> GetImplicitBits(MCInst const &MCI);
-
// Return the max value that a constant extendable operand can have
// without being extended.
int getMaxValue(MCInstrInfo const &MCII, MCInst const &MCI);
@@ -61,27 +100,77 @@ int getMinValue(MCInstrInfo const &MCII, MCInst const &MCI);
// Return instruction name
char const *getName(MCInstrInfo const &MCII, MCInst const &MCI);
+// Return the operand index for the new value.
+unsigned short getNewValueOp(MCInstrInfo const &MCII, MCInst const &MCI);
+
// Return the operand that consumes or produces a new value.
-MCOperand const &getNewValue(MCInstrInfo const &MCII, MCInst const &MCI);
+MCOperand const &getNewValueOperand(MCInstrInfo const &MCII, MCInst const &MCI);
+
+int getSubTarget(MCInstrInfo const &MCII, MCInst const &MCI);
// Return the Hexagon ISA class for the insn.
unsigned getType(MCInstrInfo const &MCII, MCInst const &MCI);
+/// Return the slots used by the insn.
+unsigned getUnits(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
+ MCInst const &MCI);
+
+// Does the packet have an extender for the instruction at Index
+bool hasExtenderForIndex(MCInst const &MCB, size_t Index);
+
+bool hasImmExt(MCInst const &MCI);
+
// Return whether the instruction is a legal new-value producer.
bool hasNewValue(MCInstrInfo const &MCII, MCInst const &MCI);
+// Return the instruction at Index
+MCInst const &instruction(MCInst const &MCB, size_t Index);
+
+// Returns whether this MCInst is a wellformed bundle
+bool isBundle(MCInst const &MCI);
+
// Return whether the insn is an actual insn.
bool isCanon(MCInstrInfo const &MCII, MCInst const &MCI);
+// Return the duplex iclass given the two duplex classes
+unsigned iClassOfDuplexPair(unsigned Ga, unsigned Gb);
+
// Return whether the instruction needs to be constant extended.
bool isConstExtended(MCInstrInfo const &MCII, MCInst const &MCI);
+// Is this double register suitable for use in a duplex subinst
+bool isDblRegForSubInst(unsigned Reg);
+
+// Is this a duplex instruction
+bool isDuplex(MCInstrInfo const &MCII, MCInst const &MCI);
+
+// Can these instructions be duplexed
+bool isDuplexPair(MCInst const &MIa, MCInst const &MIb);
+
+// Can these duplex classes be combine in to a duplex instruction
+bool isDuplexPairMatch(unsigned Ga, unsigned Gb);
+
// Return true if the insn may be extended based on the operand value.
bool isExtendable(MCInstrInfo const &MCII, MCInst const &MCI);
// Return whether the instruction must be always extended.
bool isExtended(MCInstrInfo const &MCII, MCInst const &MCI);
+/// Return whether it is a floating-point insn.
+bool isFloat(MCInstrInfo const &MCII, MCInst const &MCI);
+
+// Returns whether this instruction is an immediate extender
+bool isImmext(MCInst const &MCI);
+
+// Returns whether this bundle is an endloop0
+bool isInnerLoop(MCInst const &MCI);
+
+// Is this an integer register
+bool isIntReg(unsigned Reg);
+
+// Is this register suitable for use in a duplex subinst
+bool isIntRegForSubInst(unsigned Reg);
+
// Return whether the insn is a new-value consumer.
bool isNewValue(MCInstrInfo const &MCII, MCInst const &MCI);
@@ -89,9 +178,22 @@ bool isNewValue(MCInstrInfo const &MCII, MCInst const &MCI);
bool isOperandExtended(MCInstrInfo const &MCII, MCInst const &MCI,
unsigned short OperandNum);
-bool isPacketBegin(MCInst const &MCI);
+// Can these two instructions be duplexed
+bool isOrderedDuplexPair(MCInstrInfo const &MCII, MCInst const &MIa,
+ bool ExtendedA, MCInst const &MIb, bool ExtendedB,
+ bool bisReversable);
+
+// Returns whether this bundle is an endloop1
+bool isOuterLoop(MCInst const &MCI);
+
+// Return whether this instruction is predicated
+bool isPredicated(MCInstrInfo const &MCII, MCInst const &MCI);
+
+// Return whether the predicate sense is true
+bool isPredicatedTrue(MCInstrInfo const &MCII, MCInst const &MCI);
-bool isPacketEnd(MCInst const &MCI);
+// Is this a predicate register
+bool isPredReg(unsigned Reg);
// Return whether the insn is a prefix.
bool isPrefix(MCInstrInfo const &MCII, MCInst const &MCI);
@@ -99,23 +201,31 @@ bool isPrefix(MCInstrInfo const &MCII, MCInst const &MCI);
// Return whether the insn is solo, i.e., cannot be in a packet.
bool isSolo(MCInstrInfo const &MCII, MCInst const &MCI);
-static const size_t packetBeginIndex = 0;
-static const size_t packetEndIndex = 1;
+/// Return whether the insn can be packaged only with A and X-type insns.
+bool isSoloAX(MCInstrInfo const &MCII, MCInst const &MCI);
-void resetPacket(MCInst &MCI);
+/// Return whether the insn can be packaged only with an A-type insn in slot #1.
+bool isSoloAin1(MCInstrInfo const &MCII, MCInst const &MCI);
-inline void SanityCheckImplicitOperands(MCInst const &MCI) {
- assert(MCI.getNumOperands() >= 2 && "At least the two implicit operands");
- assert(MCI.getOperand(MCI.getNumOperands() - 1).isInst() &&
- "Implicit bits and flags");
- assert(MCI.getOperand(MCI.getNumOperands() - 2).isImm() && "Parent pointer");
-}
+// Pad the bundle with nops to satisfy endloop requirements
+void padEndloop(MCInst &MCI);
+
+bool prefersSlot3(MCInstrInfo const &MCII, MCInst const &MCI);
+
+// Replace the instructions inside MCB, represented by Candidate
+void replaceDuplex(MCContext &Context, MCInst &MCB, DuplexCandidate Candidate);
+
+// Marks a bundle as endloop0
+void setInnerLoop(MCInst &MCI);
-void SetImplicitBits(MCInst &MCI, std::bitset<16> Bits);
+// Marks a bundle as endloop1
+void setOuterLoop(MCInst &MCI);
-void setPacketBegin(MCInst &MCI, bool Y);
+// Would duplexing this instruction create a requirement to extend
+bool subInstWouldBeExtended(MCInst const &potentialDuplex);
-void setPacketEnd(MCInst &MCI, bool Y);
+// Attempt to find and replace compound pairs
+void tryCompound(MCInstrInfo const &MCII, MCContext &Context, MCInst &MCI);
}
}
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCShuffler.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonMCShuffler.cpp
new file mode 100644
index 000000000000..8e70280c1a0d
--- /dev/null
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCShuffler.cpp
@@ -0,0 +1,237 @@
+//===----- HexagonMCShuffler.cpp - MC bundle shuffling --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This implements the shuffling of insns inside a bundle according to the
+// packet formation rules of the Hexagon ISA.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "hexagon-shuffle"
+
+#include "Hexagon.h"
+#include "MCTargetDesc/HexagonMCInstrInfo.h"
+#include "MCTargetDesc/HexagonMCShuffler.h"
+#include "MCTargetDesc/HexagonMCTargetDesc.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+static cl::opt<bool>
+ DisableShuffle("disable-hexagon-shuffle", cl::Hidden, cl::init(false),
+ cl::desc("Disable Hexagon instruction shuffling"));
+
+void HexagonMCShuffler::init(MCInst &MCB) {
+ if (HexagonMCInstrInfo::isBundle(MCB)) {
+ MCInst const *Extender = nullptr;
+ // Copy the bundle for the shuffling.
+ for (const auto &I : HexagonMCInstrInfo::bundleInstructions(MCB)) {
+ assert(!HexagonMCInstrInfo::getDesc(MCII, *I.getInst()).isPseudo());
+ MCInst *MI = const_cast<MCInst *>(I.getInst());
+
+ if (!HexagonMCInstrInfo::isImmext(*MI)) {
+ append(MI, Extender, HexagonMCInstrInfo::getUnits(MCII, STI, *MI),
+ false);
+ Extender = nullptr;
+ } else
+ Extender = MI;
+ }
+ }
+
+ BundleFlags = MCB.getOperand(0).getImm();
+}
+
+void HexagonMCShuffler::init(MCInst &MCB, MCInst const *AddMI,
+ bool bInsertAtFront) {
+ if (HexagonMCInstrInfo::isBundle(MCB)) {
+ if (bInsertAtFront && AddMI)
+ append(AddMI, nullptr, HexagonMCInstrInfo::getUnits(MCII, STI, *AddMI),
+ false);
+ MCInst const *Extender = nullptr;
+ // Copy the bundle for the shuffling.
+ for (auto const &I : HexagonMCInstrInfo::bundleInstructions(MCB)) {
+ assert(!HexagonMCInstrInfo::getDesc(MCII, *I.getInst()).isPseudo());
+ MCInst *MI = const_cast<MCInst *>(I.getInst());
+ if (!HexagonMCInstrInfo::isImmext(*MI)) {
+ append(MI, Extender, HexagonMCInstrInfo::getUnits(MCII, STI, *MI),
+ false);
+ Extender = nullptr;
+ } else
+ Extender = MI;
+ }
+ if (!bInsertAtFront && AddMI)
+ append(AddMI, nullptr, HexagonMCInstrInfo::getUnits(MCII, STI, *AddMI),
+ false);
+ }
+
+ BundleFlags = MCB.getOperand(0).getImm();
+}
+
+void HexagonMCShuffler::copyTo(MCInst &MCB) {
+ MCB.clear();
+ MCB.addOperand(MCOperand::createImm(BundleFlags));
+ // Copy the results into the bundle.
+ for (HexagonShuffler::iterator I = begin(); I != end(); ++I) {
+
+ MCInst const *MI = I->getDesc();
+ MCInst const *Extender = I->getExtender();
+ if (Extender)
+ MCB.addOperand(MCOperand::createInst(Extender));
+ MCB.addOperand(MCOperand::createInst(MI));
+ }
+}
+
+bool HexagonMCShuffler::reshuffleTo(MCInst &MCB) {
+ if (shuffle()) {
+ // Copy the results into the bundle.
+ copyTo(MCB);
+ } else
+ DEBUG(MCB.dump());
+
+ return (!getError());
+}
+
+bool llvm::HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
+ MCInst &MCB) {
+ HexagonMCShuffler MCS(MCII, STI, MCB);
+
+ if (DisableShuffle)
+ // Ignore if user chose so.
+ return false;
+
+ if (!HexagonMCInstrInfo::bundleSize(MCB)) {
+ // There once was a bundle:
+ // BUNDLE %D2<imp-def>, %R4<imp-def>, %R5<imp-def>, %D7<imp-def>, ...
+ // * %D2<def> = IMPLICIT_DEF; flags:
+ // * %D7<def> = IMPLICIT_DEF; flags:
+ // After the IMPLICIT_DEFs were removed by the asm printer, the bundle
+ // became empty.
+ DEBUG(dbgs() << "Skipping empty bundle");
+ return false;
+ } else if (!HexagonMCInstrInfo::isBundle(MCB)) {
+ DEBUG(dbgs() << "Skipping stand-alone insn");
+ return false;
+ }
+
+ // Reorder the bundle and copy the result.
+ if (!MCS.reshuffleTo(MCB)) {
+ // Unless there is any error, which should not happen at this point.
+ unsigned shuffleError = MCS.getError();
+ switch (shuffleError) {
+ default:
+ llvm_unreachable("unknown error");
+ case HexagonShuffler::SHUFFLE_ERROR_INVALID:
+ llvm_unreachable("invalid packet");
+ case HexagonShuffler::SHUFFLE_ERROR_STORES:
+ llvm_unreachable("too many stores");
+ case HexagonShuffler::SHUFFLE_ERROR_LOADS:
+ llvm_unreachable("too many loads");
+ case HexagonShuffler::SHUFFLE_ERROR_BRANCHES:
+ llvm_unreachable("too many branches");
+ case HexagonShuffler::SHUFFLE_ERROR_NOSLOTS:
+ llvm_unreachable("no suitable slot");
+ case HexagonShuffler::SHUFFLE_ERROR_SLOTS:
+ llvm_unreachable("over-subscribed slots");
+ case HexagonShuffler::SHUFFLE_SUCCESS: // Single instruction case.
+ return true;
+ }
+ }
+
+ return true;
+}
+
+unsigned
+llvm::HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
+ MCContext &Context, MCInst &MCB,
+ SmallVector<DuplexCandidate, 8> possibleDuplexes) {
+
+ if (DisableShuffle)
+ return HexagonShuffler::SHUFFLE_SUCCESS;
+
+ if (!HexagonMCInstrInfo::bundleSize(MCB)) {
+ // There once was a bundle:
+ // BUNDLE %D2<imp-def>, %R4<imp-def>, %R5<imp-def>, %D7<imp-def>, ...
+ // * %D2<def> = IMPLICIT_DEF; flags:
+ // * %D7<def> = IMPLICIT_DEF; flags:
+ // After the IMPLICIT_DEFs were removed by the asm printer, the bundle
+ // became empty.
+ DEBUG(dbgs() << "Skipping empty bundle");
+ return HexagonShuffler::SHUFFLE_SUCCESS;
+ } else if (!HexagonMCInstrInfo::isBundle(MCB)) {
+ DEBUG(dbgs() << "Skipping stand-alone insn");
+ return HexagonShuffler::SHUFFLE_SUCCESS;
+ }
+
+ bool doneShuffling = false;
+ unsigned shuffleError;
+ while (possibleDuplexes.size() > 0 && (!doneShuffling)) {
+ // case of Duplex Found
+ DuplexCandidate duplexToTry = possibleDuplexes.pop_back_val();
+ MCInst Attempt(MCB);
+ HexagonMCInstrInfo::replaceDuplex(Context, Attempt, duplexToTry);
+ HexagonMCShuffler MCS(MCII, STI, Attempt); // copy packet to the shuffler
+ if (MCS.size() == 1) { // case of one duplex
+ // copy the created duplex in the shuffler to the bundle
+ MCS.copyTo(MCB);
+ doneShuffling = true;
+ return HexagonShuffler::SHUFFLE_SUCCESS;
+ }
+ // try shuffle with this duplex
+ doneShuffling = MCS.reshuffleTo(MCB);
+ shuffleError = MCS.getError();
+
+ if (doneShuffling)
+ break;
+ }
+
+ if (doneShuffling == false) {
+ HexagonMCShuffler MCS(MCII, STI, MCB);
+ doneShuffling = MCS.reshuffleTo(MCB); // shuffle
+ shuffleError = MCS.getError();
+ }
+ if (!doneShuffling)
+ return shuffleError;
+
+ return HexagonShuffler::SHUFFLE_SUCCESS;
+}
+
+bool llvm::HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
+ MCInst &MCB, MCInst const *AddMI, int fixupCount) {
+ if (!HexagonMCInstrInfo::isBundle(MCB) || !AddMI)
+ return false;
+
+ // if fixups present, make sure we don't insert too many nops that would
+ // later prevent an extender from being inserted.
+ unsigned int bundleSize = HexagonMCInstrInfo::bundleSize(MCB);
+ if (bundleSize >= HEXAGON_PACKET_SIZE)
+ return false;
+ if (fixupCount >= 2) {
+ return false;
+ } else {
+ if (bundleSize == HEXAGON_PACKET_SIZE - 1 && fixupCount)
+ return false;
+ }
+
+ if (DisableShuffle)
+ return false;
+
+ HexagonMCShuffler MCS(MCII, STI, MCB, AddMI);
+ if (!MCS.reshuffleTo(MCB)) {
+ unsigned shuffleError = MCS.getError();
+ switch (shuffleError) {
+ default:
+ return false;
+ case HexagonShuffler::SHUFFLE_SUCCESS: // single instruction case
+ return true;
+ }
+ }
+
+ return true;
+}
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCShuffler.h b/lib/Target/Hexagon/MCTargetDesc/HexagonMCShuffler.h
new file mode 100644
index 000000000000..a21cce1fc240
--- /dev/null
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCShuffler.h
@@ -0,0 +1,65 @@
+//=-- HexagonMCShuffler.h ---------------------------------------------------=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This declares the shuffling of insns inside a bundle according to the
+// packet formation rules of the Hexagon ISA.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef HEXAGONMCSHUFFLER_H
+#define HEXAGONMCSHUFFLER_H
+
+#include "MCTargetDesc/HexagonShuffler.h"
+
+namespace llvm {
+
+class MCInst;
+
+// Insn bundle shuffler.
+class HexagonMCShuffler : public HexagonShuffler {
+ bool immext_present;
+ bool duplex_present;
+
+public:
+ HexagonMCShuffler(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
+ MCInst &MCB)
+ : HexagonShuffler(MCII, STI) {
+ init(MCB);
+ };
+ HexagonMCShuffler(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
+ MCInst &MCB, const MCInst *AddMI,
+ bool bInsertAtFront = false)
+ : HexagonShuffler(MCII, STI) {
+ init(MCB, AddMI, bInsertAtFront);
+ };
+
+ // Copy reordered bundle to another.
+ void copyTo(MCInst &MCB);
+ // Reorder and copy result to another.
+ bool reshuffleTo(MCInst &MCB);
+
+ bool immextPresent() const { return immext_present; };
+ bool duplexPresent() const { return duplex_present; };
+
+private:
+ void init(MCInst &MCB);
+ void init(MCInst &MCB, const MCInst *AddMI, bool bInsertAtFront = false);
+};
+
+// Invocation of the shuffler.
+bool HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
+ MCInst &);
+bool HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
+ MCInst &, const MCInst *, int);
+unsigned HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
+ MCContext &Context, MCInst &,
+ SmallVector<DuplexCandidate, 8>);
+}
+
+#endif // HEXAGONMCSHUFFLER_H
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
index 59395e230fa9..43734ed6ca3f 100644
--- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
@@ -55,7 +55,7 @@ createHexagonMCSubtargetInfo(StringRef TT, StringRef CPU, StringRef FS) {
}
static MCAsmInfo *createHexagonMCAsmInfo(const MCRegisterInfo &MRI,
- StringRef TT) {
+ const Triple &TT) {
MCAsmInfo *MAI = new HexagonMCAsmInfo(TT);
// VirtualFP = (R30 + #0).
@@ -112,11 +112,11 @@ extern "C" void LLVMInitializeHexagonTargetMC() {
TargetRegistry::RegisterMCCodeEmitter(TheHexagonTarget,
createHexagonMCCodeEmitter);
- // Register the MC Inst Printer
- TargetRegistry::RegisterMCInstPrinter(TheHexagonTarget,
- createHexagonMCInstPrinter);
-
// Register the asm backend
TargetRegistry::RegisterMCAsmBackend(TheHexagonTarget,
createHexagonAsmBackend);
+
+ // Register the MC Inst Printer
+ TargetRegistry::RegisterMCInstPrinter(TheHexagonTarget,
+ createHexagonMCInstPrinter);
}
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h b/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h
index de63fd271aea..81211cc026db 100644
--- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h
@@ -17,6 +17,8 @@
#include <cstdint>
namespace llvm {
+struct InstrItinerary;
+struct InstrStage;
class MCAsmBackend;
class MCCodeEmitter;
class MCContext;
@@ -31,6 +33,8 @@ class raw_pwrite_stream;
extern Target TheHexagonTarget;
+extern const InstrStage HexagonStages[];
+
MCInstrInfo *createHexagonMCInstrInfo();
MCCodeEmitter *createHexagonMCCodeEmitter(MCInstrInfo const &MCII,
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp
new file mode 100644
index 000000000000..feaaa4f780d5
--- /dev/null
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp
@@ -0,0 +1,385 @@
+//===----- HexagonShuffler.cpp - Instruction bundle shuffling -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This implements the shuffling of insns inside a bundle according to the
+// packet formation rules of the Hexagon ISA.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "hexagon-shuffle"
+
+#include <algorithm>
+#include <utility>
+#include "Hexagon.h"
+#include "MCTargetDesc/HexagonBaseInfo.h"
+#include "MCTargetDesc/HexagonMCTargetDesc.h"
+#include "MCTargetDesc/HexagonMCInstrInfo.h"
+#include "HexagonShuffler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+// Insn shuffling priority.
+class HexagonBid {
+ // The priority is directly proportional to how restricted the insn is based
+ // on its flexibility to run on the available slots. So, the fewer slots it
+ // may run on, the higher its priority.
+ enum { MAX = 360360 }; // LCD of 1/2, 1/3, 1/4,... 1/15.
+ unsigned Bid;
+
+public:
+ HexagonBid() : Bid(0){};
+ HexagonBid(unsigned B) { Bid = B ? MAX / countPopulation(B) : 0; };
+
+ // Check if the insn priority is overflowed.
+ bool isSold() const { return (Bid >= MAX); };
+
+ HexagonBid &operator+=(const HexagonBid &B) {
+ Bid += B.Bid;
+ return *this;
+ };
+};
+
+// Slot shuffling allocation.
+class HexagonUnitAuction {
+ HexagonBid Scores[HEXAGON_PACKET_SIZE];
+ // Mask indicating which slot is unavailable.
+ unsigned isSold : HEXAGON_PACKET_SIZE;
+
+public:
+ HexagonUnitAuction() : isSold(0){};
+
+ // Allocate slots.
+ bool bid(unsigned B) {
+ // Exclude already auctioned slots from the bid.
+ unsigned b = B & ~isSold;
+ if (b) {
+ for (unsigned i = 0; i < HEXAGON_PACKET_SIZE; ++i)
+ if (b & (1 << i)) {
+ // Request candidate slots.
+ Scores[i] += HexagonBid(b);
+ isSold |= Scores[i].isSold() << i;
+ }
+ return true;
+ ;
+ } else
+ // Error if the desired slots are already full.
+ return false;
+ };
+};
+
+unsigned HexagonResource::setWeight(unsigned s) {
+ const unsigned SlotWeight = 8;
+ const unsigned MaskWeight = SlotWeight - 1;
+ bool Key = (1 << s) & getUnits();
+
+ // Calculate relative weight of the insn for the given slot, weighing it the
+ // heavier the more restrictive the insn is and the lowest the slots that the
+ // insn may be executed in.
+ Weight =
+ (Key << (SlotWeight * s)) * ((MaskWeight - countPopulation(getUnits()))
+ << countTrailingZeros(getUnits()));
+ return (Weight);
+}
+
+HexagonShuffler::HexagonShuffler(MCInstrInfo const &MCII,
+ MCSubtargetInfo const &STI)
+ : MCII(MCII), STI(STI) {
+ reset();
+}
+
+void HexagonShuffler::reset() {
+ Packet.clear();
+ BundleFlags = 0;
+ Error = SHUFFLE_SUCCESS;
+}
+
+void HexagonShuffler::append(MCInst const *ID, MCInst const *Extender,
+ unsigned S, bool X) {
+ HexagonInstr PI(ID, Extender, S, X);
+
+ Packet.push_back(PI);
+}
+
+/// Check that the packet is legal and enforce relative insn order.
+bool HexagonShuffler::check() {
+ // Descriptive slot masks.
+ const unsigned slotSingleLoad = 0x1, slotSingleStore = 0x1, slotOne = 0x2,
+ slotThree = 0x8, slotFirstJump = 0x8, slotLastJump = 0x4,
+ slotFirstLoadStore = 0x2, slotLastLoadStore = 0x1;
+ // Highest slots for branches and stores used to keep their original order.
+ unsigned slotJump = slotFirstJump;
+ unsigned slotLoadStore = slotFirstLoadStore;
+ // Number of branches, solo branches, indirect branches.
+ unsigned jumps = 0, jump1 = 0, jumpr = 0;
+ // Number of memory operations, loads, solo loads, stores, solo stores, single
+ // stores.
+ unsigned memory = 0, loads = 0, load0 = 0, stores = 0, store0 = 0, store1 = 0;
+ // Number of duplex insns, solo insns.
+ unsigned duplex = 0, solo = 0;
+ // Number of insns restricting other insns in the packet to A and X types,
+ // which is neither A or X types.
+ unsigned onlyAX = 0, neitherAnorX = 0;
+ // Number of insns restricting other insns in slot #1 to A type.
+ unsigned onlyAin1 = 0;
+ // Number of insns restricting any insn in slot #1, except A2_nop.
+ unsigned onlyNo1 = 0;
+ unsigned xtypeFloat = 0;
+ unsigned pSlot3Cnt = 0;
+ iterator slot3ISJ = end();
+
+ // Collect information from the insns in the packet.
+ for (iterator ISJ = begin(); ISJ != end(); ++ISJ) {
+ MCInst const *ID = ISJ->getDesc();
+
+ if (HexagonMCInstrInfo::isSolo(MCII, *ID))
+ solo += !ISJ->isSoloException();
+ else if (HexagonMCInstrInfo::isSoloAX(MCII, *ID))
+ onlyAX += !ISJ->isSoloException();
+ else if (HexagonMCInstrInfo::isSoloAin1(MCII, *ID))
+ onlyAin1 += !ISJ->isSoloException();
+ if (HexagonMCInstrInfo::getType(MCII, *ID) != HexagonII::TypeALU32 &&
+ HexagonMCInstrInfo::getType(MCII, *ID) != HexagonII::TypeXTYPE)
+ ++neitherAnorX;
+ if (HexagonMCInstrInfo::prefersSlot3(MCII, *ID)) {
+ ++pSlot3Cnt;
+ slot3ISJ = ISJ;
+ }
+
+ switch (HexagonMCInstrInfo::getType(MCII, *ID)) {
+ case HexagonII::TypeXTYPE:
+ if (HexagonMCInstrInfo::isFloat(MCII, *ID))
+ ++xtypeFloat;
+ break;
+ case HexagonII::TypeJR:
+ ++jumpr;
+ // Fall-through.
+ case HexagonII::TypeJ:
+ ++jumps;
+ break;
+ case HexagonII::TypeLD:
+ ++loads;
+ ++memory;
+ if (ISJ->Core.getUnits() == slotSingleLoad)
+ ++load0;
+ if (HexagonMCInstrInfo::getDesc(MCII, *ID).isReturn())
+ ++jumps, ++jump1; // DEALLOC_RETURN is of type LD.
+ break;
+ case HexagonII::TypeST:
+ ++stores;
+ ++memory;
+ if (ISJ->Core.getUnits() == slotSingleStore)
+ ++store0;
+ break;
+ case HexagonII::TypeMEMOP:
+ ++loads;
+ ++stores;
+ ++store1;
+ ++memory;
+ break;
+ case HexagonII::TypeNV:
+ ++memory; // NV insns are memory-like.
+ if (HexagonMCInstrInfo::getDesc(MCII, *ID).isBranch())
+ ++jumps, ++jump1;
+ break;
+ case HexagonII::TypeCR:
+ // Legacy conditional branch predicated on a register.
+ case HexagonII::TypeSYSTEM:
+ if (HexagonMCInstrInfo::getDesc(MCII, *ID).mayLoad())
+ ++loads;
+ break;
+ }
+ }
+
+ // Check if the packet is legal.
+ if ((load0 > 1 || store0 > 1) || (duplex > 1 || (duplex && memory)) ||
+ (solo && size() > 1) || (onlyAX && neitherAnorX > 1) ||
+ (onlyAX && xtypeFloat)) {
+ Error = SHUFFLE_ERROR_INVALID;
+ return false;
+ }
+
+ if (jump1 && jumps > 1) {
+ // Error if single branch with another branch.
+ Error = SHUFFLE_ERROR_BRANCHES;
+ return false;
+ }
+
+ // Modify packet accordingly.
+ // TODO: need to reserve slots #0 and #1 for duplex insns.
+ bool bOnlySlot3 = false;
+ for (iterator ISJ = begin(); ISJ != end(); ++ISJ) {
+ MCInst const *ID = ISJ->getDesc();
+
+ if (!ISJ->Core.getUnits()) {
+ // Error if insn may not be executed in any slot.
+ Error = SHUFFLE_ERROR_UNKNOWN;
+ return false;
+ }
+
+ // Exclude from slot #1 any insn but A2_nop.
+ if (HexagonMCInstrInfo::getDesc(MCII, *ID).getOpcode() != Hexagon::A2_nop)
+ if (onlyNo1)
+ ISJ->Core.setUnits(ISJ->Core.getUnits() & ~slotOne);
+
+ // Exclude from slot #1 any insn but A-type.
+ if (HexagonMCInstrInfo::getType(MCII, *ID) != HexagonII::TypeALU32)
+ if (onlyAin1)
+ ISJ->Core.setUnits(ISJ->Core.getUnits() & ~slotOne);
+
+ // Branches must keep the original order.
+ if (HexagonMCInstrInfo::getDesc(MCII, *ID).isBranch() ||
+ HexagonMCInstrInfo::getDesc(MCII, *ID).isCall())
+ if (jumps > 1) {
+ if (jumpr || slotJump < slotLastJump) {
+ // Error if indirect branch with another branch or
+ // no more slots available for branches.
+ Error = SHUFFLE_ERROR_BRANCHES;
+ return false;
+ }
+ // Pin the branch to the highest slot available to it.
+ ISJ->Core.setUnits(ISJ->Core.getUnits() & slotJump);
+ // Update next highest slot available to branches.
+ slotJump >>= 1;
+ }
+
+ // A single load must use slot #0.
+ if (HexagonMCInstrInfo::getDesc(MCII, *ID).mayLoad()) {
+ if (loads == 1 && loads == memory)
+ // Pin the load to slot #0.
+ ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleLoad);
+ }
+
+ // A single store must use slot #0.
+ if (HexagonMCInstrInfo::getDesc(MCII, *ID).mayStore()) {
+ if (!store0) {
+ if (stores == 1)
+ ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleStore);
+ else if (stores > 1) {
+ if (slotLoadStore < slotLastLoadStore) {
+ // Error if no more slots available for stores.
+ Error = SHUFFLE_ERROR_STORES;
+ return false;
+ }
+ // Pin the store to the highest slot available to it.
+ ISJ->Core.setUnits(ISJ->Core.getUnits() & slotLoadStore);
+ // Update the next highest slot available to stores.
+ slotLoadStore >>= 1;
+ }
+ }
+ if (store1 && stores > 1) {
+ // Error if a single store with another store.
+ Error = SHUFFLE_ERROR_STORES;
+ return false;
+ }
+ }
+
+ // flag if an instruction can only be executed in slot 3
+ if (ISJ->Core.getUnits() == slotThree)
+ bOnlySlot3 = true;
+
+ if (!ISJ->Core.getUnits()) {
+ // Error if insn may not be executed in any slot.
+ Error = SHUFFLE_ERROR_NOSLOTS;
+ return false;
+ }
+ }
+
+ bool validateSlots = true;
+ if (bOnlySlot3 == false && pSlot3Cnt == 1 && slot3ISJ != end()) {
+ // save off slot mask of instruction marked with A_PREFER_SLOT3
+ // and then pin it to slot #3
+ unsigned saveUnits = slot3ISJ->Core.getUnits();
+ slot3ISJ->Core.setUnits(saveUnits & slotThree);
+
+ HexagonUnitAuction AuctionCore;
+ std::sort(begin(), end(), HexagonInstr::lessCore);
+
+ // see if things ok with that instruction being pinned to slot #3
+ bool bFail = false;
+ for (iterator I = begin(); I != end() && bFail != true; ++I)
+ if (!AuctionCore.bid(I->Core.getUnits()))
+ bFail = true;
+
+ // if yes, great, if not then restore original slot mask
+ if (!bFail)
+ validateSlots = false; // all good, no need to re-do auction
+ else
+ for (iterator ISJ = begin(); ISJ != end(); ++ISJ) {
+ MCInst const *ID = ISJ->getDesc();
+ if (HexagonMCInstrInfo::prefersSlot3(MCII, *ID))
+ ISJ->Core.setUnits(saveUnits);
+ }
+ }
+
+ // Check if any slot, core, is over-subscribed.
+ // Verify the core slot subscriptions.
+ if (validateSlots) {
+ HexagonUnitAuction AuctionCore;
+
+ std::sort(begin(), end(), HexagonInstr::lessCore);
+
+ for (iterator I = begin(); I != end(); ++I)
+ if (!AuctionCore.bid(I->Core.getUnits())) {
+ Error = SHUFFLE_ERROR_SLOTS;
+ return false;
+ }
+ }
+
+ Error = SHUFFLE_SUCCESS;
+ return true;
+}
+
+bool HexagonShuffler::shuffle() {
+ if (size() > HEXAGON_PACKET_SIZE) {
+ // Ignore a packet with with more than what a packet can hold
+ // or with compound or duplex insns for now.
+ Error = SHUFFLE_ERROR_INVALID;
+ return false;
+ }
+
+ // Check and prepare packet.
+ if (size() > 1 && check())
+ // Reorder the handles for each slot.
+ for (unsigned nSlot = 0, emptySlots = 0; nSlot < HEXAGON_PACKET_SIZE;
+ ++nSlot) {
+ iterator ISJ, ISK;
+ unsigned slotSkip, slotWeight;
+
+ // Prioritize the handles considering their restrictions.
+ for (ISJ = ISK = Packet.begin(), slotSkip = slotWeight = 0;
+ ISK != Packet.end(); ++ISK, ++slotSkip)
+ if (slotSkip < nSlot - emptySlots)
+ // Note which handle to begin at.
+ ++ISJ;
+ else
+ // Calculate the weight of the slot.
+ slotWeight += ISK->Core.setWeight(HEXAGON_PACKET_SIZE - nSlot - 1);
+
+ if (slotWeight)
+ // Sort the packet, favoring source order,
+ // beginning after the previous slot.
+ std::sort(ISJ, Packet.end());
+ else
+ // Skip unused slot.
+ ++emptySlots;
+ }
+
+ for (iterator ISJ = begin(); ISJ != end(); ++ISJ)
+ DEBUG(dbgs().write_hex(ISJ->Core.getUnits());
+ dbgs() << ':'
+ << HexagonMCInstrInfo::getDesc(MCII, *ISJ->getDesc())
+ .getOpcode();
+ dbgs() << '\n');
+ DEBUG(dbgs() << '\n');
+
+ return (!getError());
+}
diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h b/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h
new file mode 100644
index 000000000000..9218fd3eb070
--- /dev/null
+++ b/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h
@@ -0,0 +1,139 @@
+//===----- HexagonShuffler.h - Instruction bundle shuffling ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This implements the shuffling of insns inside a bundle according to the
+// packet formation rules of the Hexagon ISA.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef HEXAGONSHUFFLER_H
+#define HEXAGONSHUFFLER_H
+
+#include "Hexagon.h"
+#include "MCTargetDesc/HexagonMCInstrInfo.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/MC/MCInstrInfo.h"
+
+using namespace llvm;
+
+namespace llvm {
+// Insn resources.
+class HexagonResource {
+ // Mask of the slots or units that may execute the insn and
+ // the weight or priority that the insn requires to be assigned a slot.
+ unsigned Slots, Weight;
+
+public:
+ HexagonResource(unsigned s) { setUnits(s); };
+
+ void setUnits(unsigned s) {
+ Slots = s & ~(-1 << HEXAGON_PACKET_SIZE);
+ setWeight(s);
+ };
+ unsigned setWeight(unsigned s);
+
+ unsigned getUnits() const { return (Slots); };
+ unsigned getWeight() const { return (Weight); };
+
+ // Check if the resources are in ascending slot order.
+ static bool lessUnits(const HexagonResource &A, const HexagonResource &B) {
+ return (countPopulation(A.getUnits()) < countPopulation(B.getUnits()));
+ };
+ // Check if the resources are in ascending weight order.
+ static bool lessWeight(const HexagonResource &A, const HexagonResource &B) {
+ return (A.getWeight() < B.getWeight());
+ };
+};
+
+// Handle to an insn used by the shuffling algorithm.
+class HexagonInstr {
+ friend class HexagonShuffler;
+
+ MCInst const *ID;
+ MCInst const *Extender;
+ HexagonResource Core;
+ bool SoloException;
+
+public:
+ HexagonInstr(MCInst const *id, MCInst const *Extender, unsigned s,
+ bool x = false)
+ : ID(id), Extender(Extender), Core(s), SoloException(x){};
+
+ MCInst const *getDesc() const { return (ID); };
+
+ MCInst const *getExtender() const { return Extender; }
+
+ unsigned isSoloException() const { return (SoloException); };
+
+ // Check if the handles are in ascending order for shuffling purposes.
+ bool operator<(const HexagonInstr &B) const {
+ return (HexagonResource::lessWeight(B.Core, Core));
+ };
+ // Check if the handles are in ascending order by core slots.
+ static bool lessCore(const HexagonInstr &A, const HexagonInstr &B) {
+ return (HexagonResource::lessUnits(A.Core, B.Core));
+ };
+};
+
+// Bundle shuffler.
+class HexagonShuffler {
+ typedef SmallVector<HexagonInstr, HEXAGON_PRESHUFFLE_PACKET_SIZE>
+ HexagonPacket;
+
+ // Insn handles in a bundle.
+ HexagonPacket Packet;
+
+ // Shuffling error code.
+ unsigned Error;
+
+protected:
+ int64_t BundleFlags;
+ MCInstrInfo const &MCII;
+ MCSubtargetInfo const &STI;
+
+public:
+ typedef HexagonPacket::iterator iterator;
+
+ enum {
+ SHUFFLE_SUCCESS = 0, ///< Successful operation.
+ SHUFFLE_ERROR_INVALID, ///< Invalid bundle.
+ SHUFFLE_ERROR_STORES, ///< No free slots for store insns.
+ SHUFFLE_ERROR_LOADS, ///< No free slots for load insns.
+ SHUFFLE_ERROR_BRANCHES, ///< No free slots for branch insns.
+ SHUFFLE_ERROR_NOSLOTS, ///< No free slots for other insns.
+ SHUFFLE_ERROR_SLOTS, ///< Over-subscribed slots.
+ SHUFFLE_ERROR_UNKNOWN ///< Unknown error.
+ };
+
+ explicit HexagonShuffler(MCInstrInfo const &MCII, MCSubtargetInfo const &STI);
+
+ // Reset to initial state.
+ void reset();
+ // Check if the bundle may be validly shuffled.
+ bool check();
+ // Reorder the insn handles in the bundle.
+ bool shuffle();
+
+ unsigned size() const { return (Packet.size()); };
+
+ iterator begin() { return (Packet.begin()); };
+ iterator end() { return (Packet.end()); };
+
+ // Add insn handle to the bundle .
+ void append(MCInst const *ID, MCInst const *Extender, unsigned S,
+ bool X = false);
+
+ // Return the error code for the last check or shuffling of the bundle.
+ void setError(unsigned Err) { Error = Err; };
+ unsigned getError() const { return (Error); };
+};
+}
+
+#endif // HEXAGONSHUFFLER_H