#include "MCTargetDesc/HexagonMCShuffler.h"
#include "MCTargetDesc/HexagonMCInstrInfo.h"
#include "MCTargetDesc/HexagonShuffler.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#define DEBUG_TYPE "hexagon-shuffle"
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;
for (const auto &I : HexagonMCInstrInfo::bundleInstructions(MCB)) {
MCInst &MI = *const_cast<MCInst *>(I.getInst());
LLVM_DEBUG(dbgs() << "Shuffling: " << MCII.getName(MI.getOpcode())
<< '\n');
assert(!HexagonMCInstrInfo::getDesc(MCII, MI).isPseudo());
if (!HexagonMCInstrInfo::isImmext(MI)) {
append(MI, Extender, HexagonMCInstrInfo::getUnits(MCII, STI, MI));
Extender = nullptr;
} else
Extender = &MI;
}
}
Loc = MCB.getLoc();
BundleFlags = MCB.getOperand(0).getImm();
}
void HexagonMCShuffler::init(MCInst &MCB, MCInst const &AddMI,
bool bInsertAtFront) {
if (HexagonMCInstrInfo::isBundle(MCB)) {
if (bInsertAtFront)
append(AddMI, nullptr, HexagonMCInstrInfo::getUnits(MCII, STI, AddMI));
MCInst const *Extender = nullptr;
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));
Extender = nullptr;
} else
Extender = &MI;
}
if (!bInsertAtFront)
append(AddMI, nullptr, HexagonMCInstrInfo::getUnits(MCII, STI, AddMI));
}
Loc = MCB.getLoc();
BundleFlags = MCB.getOperand(0).getImm();
}
void HexagonMCShuffler::copyTo(MCInst &MCB) {
MCB.clear();
MCB.addOperand(MCOperand::createImm(BundleFlags));
MCB.setLoc(Loc);
for (auto &I : *this) {
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()) {
copyTo(MCB);
return true;
}
LLVM_DEBUG(MCB.dump());
return false;
}
bool llvm::HexagonMCShuffle(MCContext &Context, bool ReportErrors,
MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
MCInst &MCB) {
HexagonMCShuffler MCS(Context, ReportErrors, MCII, STI, MCB);
if (DisableShuffle)
return false;
if (!HexagonMCInstrInfo::bundleSize(MCB)) {
LLVM_DEBUG(dbgs() << "Skipping empty bundle");
return false;
} else if (!HexagonMCInstrInfo::isBundle(MCB)) {
LLVM_DEBUG(dbgs() << "Skipping stand-alone insn");
return false;
}
return MCS.reshuffleTo(MCB);
}
bool llvm::HexagonMCShuffle(MCContext &Context, MCInstrInfo const &MCII,
MCSubtargetInfo const &STI, MCInst &MCB,
SmallVector<DuplexCandidate, 8> possibleDuplexes) {
if (DisableShuffle || possibleDuplexes.size() == 0)
return false;
if (!HexagonMCInstrInfo::bundleSize(MCB)) {
LLVM_DEBUG(dbgs() << "Skipping empty bundle");
return false;
} else if (!HexagonMCInstrInfo::isBundle(MCB)) {
LLVM_DEBUG(dbgs() << "Skipping stand-alone insn");
return false;
}
bool doneShuffling = false;
while (possibleDuplexes.size() > 0 && (!doneShuffling)) {
DuplexCandidate duplexToTry = possibleDuplexes.pop_back_val();
MCInst Attempt(MCB);
HexagonMCInstrInfo::replaceDuplex(Context, Attempt, duplexToTry);
HexagonMCShuffler MCS(Context, false, MCII, STI, Attempt); if (MCS.size() == 1) { MCS.copyTo(MCB);
return false;
}
doneShuffling = MCS.reshuffleTo(MCB);
if (doneShuffling)
break;
}
if (!doneShuffling) {
HexagonMCShuffler MCS(Context, false, MCII, STI, MCB);
doneShuffling = MCS.reshuffleTo(MCB); }
return doneShuffling;
}
bool llvm::HexagonMCShuffle(MCContext &Context, MCInstrInfo const &MCII,
MCSubtargetInfo const &STI, MCInst &MCB,
MCInst const &AddMI, int fixupCount) {
if (!HexagonMCInstrInfo::isBundle(MCB))
return false;
unsigned int bundleSize = HexagonMCInstrInfo::bundleSize(MCB);
if (bundleSize >= HEXAGON_PACKET_SIZE)
return false;
bool bhasDuplex = HexagonMCInstrInfo::hasDuplex(MCII, MCB);
if (fixupCount >= 2) {
if (bhasDuplex) {
if (bundleSize >= HEXAGON_PACKET_SIZE - 1) {
return false;
}
} else {
return false;
}
} else {
if (bundleSize == HEXAGON_PACKET_SIZE - 1 && fixupCount)
return false;
}
if (DisableShuffle)
return false;
unsigned maxBundleSize = (HexagonMCInstrInfo::hasImmExt(MCB))
? HEXAGON_PACKET_SIZE
: HEXAGON_PACKET_SIZE - 1;
if (bhasDuplex && bundleSize >= maxBundleSize)
return false;
HexagonMCShuffler MCS(Context, false, MCII, STI, MCB, AddMI, false);
return MCS.reshuffleTo(MCB);
}