222 lines
7.3 KiB
C++
222 lines
7.3 KiB
C++
|
//===----- HexagonMCShuffler.cpp - MC bundle shuffling --------------------===//
|
||
|
//
|
||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
//
|
||
|
// This implements the shuffling of insns inside a bundle according to the
|
||
|
// packet formation rules of the Hexagon ISA.
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#define DEBUG_TYPE "hexagon-shuffle"
|
||
|
|
||
|
#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>
|
||
|
|
||
|
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)) {
|
||
|
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;
|
||
|
// 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));
|
||
|
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);
|
||
|
// 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);
|
||
|
return true;
|
||
|
}
|
||
|
LLVM_DEBUG(MCB.dump());
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool llvm::HexagonMCShuffle(MCContext &Context, bool Fatal,
|
||
|
MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
|
||
|
MCInst &MCB) {
|
||
|
HexagonMCShuffler MCS(Context, Fatal, MCII, STI, MCB);
|
||
|
|
||
|
if (DisableShuffle)
|
||
|
// Ignore if user chose so.
|
||
|
return false;
|
||
|
|
||
|
if (!HexagonMCInstrInfo::bundleSize(MCB)) {
|
||
|
// There once was a bundle:
|
||
|
// BUNDLE implicit-def %d2, implicit-def %r4, implicit-def %r5,
|
||
|
// implicit-def %d7, ...
|
||
|
// * %d2 = IMPLICIT_DEF; flags:
|
||
|
// * %d7 = IMPLICIT_DEF; flags:
|
||
|
// After the IMPLICIT_DEFs were removed by the asm printer, the bundle
|
||
|
// became empty.
|
||
|
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)
|
||
|
return false;
|
||
|
|
||
|
if (!HexagonMCInstrInfo::bundleSize(MCB)) {
|
||
|
// There once was a bundle:
|
||
|
// BUNDLE implicit-def %d2, implicit-def %r4, implicit-def %r5,
|
||
|
// implicit-def %d7, ...
|
||
|
// * %d2 = IMPLICIT_DEF; flags:
|
||
|
// * %d7 = IMPLICIT_DEF; flags:
|
||
|
// After the IMPLICIT_DEFs were removed by the asm printer, the bundle
|
||
|
// became empty.
|
||
|
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)) {
|
||
|
// case of Duplex Found
|
||
|
DuplexCandidate duplexToTry = possibleDuplexes.pop_back_val();
|
||
|
MCInst Attempt(MCB);
|
||
|
HexagonMCInstrInfo::replaceDuplex(Context, Attempt, duplexToTry);
|
||
|
HexagonMCShuffler MCS(Context, false, 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);
|
||
|
return false;
|
||
|
}
|
||
|
// try shuffle with this duplex
|
||
|
doneShuffling = MCS.reshuffleTo(MCB);
|
||
|
|
||
|
if (doneShuffling)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!doneShuffling) {
|
||
|
HexagonMCShuffler MCS(Context, false, MCII, STI, MCB);
|
||
|
doneShuffling = MCS.reshuffleTo(MCB); // shuffle
|
||
|
}
|
||
|
if (!doneShuffling)
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool llvm::HexagonMCShuffle(MCContext &Context, MCInstrInfo const &MCII,
|
||
|
MCSubtargetInfo const &STI, MCInst &MCB,
|
||
|
MCInst const &AddMI, int fixupCount) {
|
||
|
if (!HexagonMCInstrInfo::isBundle(MCB))
|
||
|
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;
|
||
|
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;
|
||
|
|
||
|
// mgl: temporary code (shuffler doesn't take into account the fact that
|
||
|
// a duplex takes up two slots. for example, 3 nops can be put into a packet
|
||
|
// containing a duplex oversubscribing slots by 1).
|
||
|
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);
|
||
|
}
|