1
0
mirror of https://github.com/RPCS3/llvm.git synced 2025-03-04 00:29:28 +00:00

[Hexagon] Improve shuffle error reporting

Patch by Colin LeMahieu.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301823 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Krzysztof Parzyszek 2017-05-01 19:41:43 +00:00
parent 2e6f882a8d
commit 83ab9dc04d
11 changed files with 276 additions and 482 deletions

@ -459,94 +459,16 @@ bool HexagonAsmParser::finishBundle(SMLoc IDLoc, MCStreamer &Out) {
DEBUG(MCB.dump_pretty(dbgs()));
DEBUG(dbgs() << "--\n");
MCB.setLoc(IDLoc);
// Check the bundle for errors.
const MCRegisterInfo *RI = getContext().getRegisterInfo();
HexagonMCChecker Check(MCII, getSTI(), MCB, MCB, *RI);
HexagonMCChecker Check(getContext(), MCII, getSTI(), MCB, *RI);
bool CheckOk = HexagonMCInstrInfo::canonicalizePacket(MCII, getSTI(),
getContext(), MCB,
&Check);
while (Check.getNextErrInfo()) {
unsigned Reg = Check.getErrRegister();
Twine R(RI->getName(Reg));
uint64_t Err = Check.getError();
if (Err != HexagonMCErrInfo::CHECK_SUCCESS) {
if (HexagonMCErrInfo::CHECK_ERROR_BRANCHES & Err)
return Error(
IDLoc,
"unconditional branch cannot precede another branch in packet");
if (HexagonMCErrInfo::CHECK_ERROR_NEWP & Err ||
HexagonMCErrInfo::CHECK_ERROR_NEWV & Err)
return Error(IDLoc, "register `" + R +
"' used with `.new' "
"but not validly modified in the same packet");
if (HexagonMCErrInfo::CHECK_ERROR_REGISTERS & Err)
return Error(IDLoc, "register `" + R + "' modified more than once");
if (HexagonMCErrInfo::CHECK_ERROR_READONLY & Err)
return Error(IDLoc, "cannot write to read-only register `" + R + "'");
if (HexagonMCErrInfo::CHECK_ERROR_LOOP & Err)
return Error(IDLoc, "loop-setup and some branch instructions "
"cannot be in the same packet");
if (HexagonMCErrInfo::CHECK_ERROR_ENDLOOP & Err) {
Twine N(HexagonMCInstrInfo::isInnerLoop(MCB) ? '0' : '1');
return Error(IDLoc,
"packet marked with `:endloop" + N + "' " +
"cannot contain instructions that modify register " +
"`" + R + "'");
}
if (HexagonMCErrInfo::CHECK_ERROR_SOLO & Err)
return Error(
IDLoc,
"instruction cannot appear in packet with other instructions");
if (HexagonMCErrInfo::CHECK_ERROR_NOSLOTS & Err)
return Error(IDLoc, "too many slots used in packet");
if (Err & HexagonMCErrInfo::CHECK_ERROR_SHUFFLE) {
uint64_t Erm = Check.getShuffleError();
if (HexagonShuffler::SHUFFLE_ERROR_INVALID == Erm)
return Error(IDLoc, "invalid instruction packet");
else if (HexagonShuffler::SHUFFLE_ERROR_STORES == Erm)
return Error(IDLoc, "invalid instruction packet: too many stores");
else if (HexagonShuffler::SHUFFLE_ERROR_LOADS == Erm)
return Error(IDLoc, "invalid instruction packet: too many loads");
else if (HexagonShuffler::SHUFFLE_ERROR_BRANCHES == Erm)
return Error(IDLoc, "too many branches in packet");
else if (HexagonShuffler::SHUFFLE_ERROR_NOSLOTS == Erm)
return Error(IDLoc, "invalid instruction packet: out of slots");
else if (HexagonShuffler::SHUFFLE_ERROR_SLOTS == Erm)
return Error(IDLoc, "invalid instruction packet: slot error");
else if (HexagonShuffler::SHUFFLE_ERROR_ERRATA2 == Erm)
return Error(IDLoc, "v60 packet violation");
else if (HexagonShuffler::SHUFFLE_ERROR_STORE_LOAD_CONFLICT == Erm)
return Error(IDLoc, "slot 0 instruction does not allow slot 1 store");
else
return Error(IDLoc, "unknown error in instruction packet");
}
}
unsigned Warn = Check.getWarning();
if (Warn != HexagonMCErrInfo::CHECK_SUCCESS) {
if (HexagonMCErrInfo::CHECK_WARN_CURRENT & Warn)
Warning(IDLoc, "register `" + R + "' used with `.cur' "
"but not used in the same packet");
else if (HexagonMCErrInfo::CHECK_WARN_TEMPORARY & Warn)
Warning(IDLoc, "register `" + R + "' used with `.tmp' "
"but not used in the same packet");
}
}
if (CheckOk) {
MCB.setLoc(IDLoc);
if (HexagonMCInstrInfo::bundleSize(MCB) == 0) {
assert(!HexagonMCInstrInfo::isInnerLoop(MCB));
assert(!HexagonMCInstrInfo::isOuterLoop(MCB));

@ -191,7 +191,8 @@ DecodeStatus HexagonDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
return Result;
if (Size > HEXAGON_MAX_PACKET_SIZE)
return MCDisassembler::Fail;
HexagonMCChecker Checker(*MCII, STI, MI, MI, *getContext().getRegisterInfo());
HexagonMCChecker Checker(getContext(), *MCII, STI, MI,
*getContext().getRegisterInfo(), false);
if (!Checker.check())
return MCDisassembler::Fail;
return MCDisassembler::Success;

@ -58,6 +58,7 @@ class HexagonAsmBackend : public MCAsmBackend {
RF.getContents() = Code;
RF.getFixups() = Fixups;
}
public:
HexagonAsmBackend(const Target &T, const Triple &TT, uint8_t OSABI,
StringRef CPU) :
@ -711,22 +712,24 @@ public:
break;
}
case MCFragment::FT_Relaxable: {
MCContext &Context = Asm.getContext();
auto &RF = cast<MCRelaxableFragment>(*K);
auto &Inst = const_cast<MCInst &>(RF.getInst());
while (Size > 0 && HexagonMCInstrInfo::bundleSize(Inst) < 4) {
MCInst *Nop = new (Asm.getContext()) MCInst;
MCInst *Nop = new (Context) MCInst;
Nop->setOpcode(Hexagon::A2_nop);
Inst.addOperand(MCOperand::createInst(Nop));
Size -= 4;
if (!HexagonMCChecker(
*MCII, RF.getSubtargetInfo(), Inst, Inst,
*Asm.getContext().getRegisterInfo()).check()) {
Context, *MCII, RF.getSubtargetInfo(), Inst,
*Context.getRegisterInfo(), false)
.check()) {
Inst.erase(Inst.end() - 1);
Size = 0;
}
}
bool Error = HexagonMCShuffle(true, *MCII, RF.getSubtargetInfo(),
Inst);
bool Error = HexagonMCShuffle(Context, true, *MCII,
RF.getSubtargetInfo(), Inst);
//assert(!Error);
(void)Error;
ReplaceInstruction(Asm.getEmitter(), RF, Inst);

@ -16,19 +16,22 @@
#include "HexagonBaseInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
static cl::opt<bool> RelaxNVChecks("relax-nv-checks", cl::init(false),
cl::ZeroOrMore, cl::Hidden, cl::desc("Relax checks of new-value validity"));
static cl::opt<bool>
RelaxNVChecks("relax-nv-checks", cl::init(false), cl::ZeroOrMore,
cl::Hidden, cl::desc("Relax checks of new-value validity"));
const HexagonMCChecker::PredSense
HexagonMCChecker::Unconditional(Hexagon::NoRegister, false);
HexagonMCChecker::Unconditional(Hexagon::NoRegister, false);
void HexagonMCChecker::init() {
// Initialize read-only registers set.
@ -46,13 +49,12 @@ void HexagonMCChecker::init() {
if (HexagonMCInstrInfo::isBundle(MCB))
// Unfurl a bundle.
for (auto const&I : HexagonMCInstrInfo::bundleInstructions(MCB)) {
for (auto const &I : HexagonMCInstrInfo::bundleInstructions(MCB)) {
MCInst const &Inst = *I.getInst();
if (HexagonMCInstrInfo::isDuplex(MCII, Inst)) {
init(*Inst.getOperand(0).getInst());
init(*Inst.getOperand(1).getInst());
}
else
} else
init(Inst);
}
else
@ -69,20 +71,18 @@ void HexagonMCChecker::initReg(MCInst const &MCI, unsigned R, unsigned &PredReg,
// Note use of new predicate register.
if (HexagonMCInstrInfo::isPredicatedNew(MCII, MCI))
NewPreds.insert(PredReg);
}
else
} else
// Note register use. Super-registers are not tracked directly,
// but their components.
for(MCRegAliasIterator SRI(R, &RI, !MCSubRegIterator(R, &RI).isValid());
SRI.isValid();
++SRI)
for (MCRegAliasIterator SRI(R, &RI, !MCSubRegIterator(R, &RI).isValid());
SRI.isValid(); ++SRI)
if (!MCSubRegIterator(*SRI, &RI).isValid())
// Skip super-registers used indirectly.
Uses.insert(*SRI);
}
void HexagonMCChecker::init(MCInst const& MCI) {
const MCInstrDesc& MCID = HexagonMCInstrInfo::getDesc(MCII, MCI);
void HexagonMCChecker::init(MCInst const &MCI) {
const MCInstrDesc &MCID = HexagonMCInstrInfo::getDesc(MCII, MCI);
unsigned PredReg = Hexagon::NoRegister;
bool isTrue = false;
@ -109,10 +109,10 @@ void HexagonMCChecker::init(MCInst const& MCI) {
if (Hexagon::USR_OVF == R)
// Many insns change the USR implicitly, but only one or another flag.
// The instruction table models the USR.OVF flag, which can be implicitly
// modified more than once, but cannot be modified in the same packet
// with an instruction that modifies is explicitly. Deal with such situ-
// ations individually.
// The instruction table models the USR.OVF flag, which can be
// implicitly modified more than once, but cannot be modified in the
// same packet with an instruction that modifies is explicitly. Deal
// with such situ- ations individually.
SoftDefs.insert(R);
else if (isPredicateRegister(R) &&
HexagonMCInstrInfo::isPredicateLate(MCII, MCI))
@ -124,8 +124,7 @@ void HexagonMCChecker::init(MCInst const& MCI) {
// Figure out explicit register definitions.
for (unsigned i = 0; i < MCID.getNumDefs(); ++i) {
unsigned R = MCI.getOperand(i).getReg(),
S = Hexagon::NoRegister;
unsigned R = MCI.getOperand(i).getReg(), S = Hexagon::NoRegister;
// USR has subregisters (while C8 does not for technical reasons), so
// reset R to USR, since we know how to handle multiple defs of USR,
// taking into account its subregisters.
@ -134,9 +133,8 @@ void HexagonMCChecker::init(MCInst const& MCI) {
// Note register definitions, direct ones as well as indirect side-effects.
// Super-registers are not tracked directly, but their components.
for(MCRegAliasIterator SRI(R, &RI, !MCSubRegIterator(R, &RI).isValid());
SRI.isValid();
++SRI) {
for (MCRegAliasIterator SRI(R, &RI, !MCSubRegIterator(R, &RI).isValid());
SRI.isValid(); ++SRI) {
if (MCSubRegIterator(*SRI, &RI).isValid())
// Skip super-registers defined indirectly.
continue;
@ -156,22 +154,25 @@ void HexagonMCChecker::init(MCInst const& MCI) {
// Only an explicit definition of P3:0 is noted as such; if a
// side-effect, then note as a soft definition.
SoftDefs.insert(*SRI);
else if (HexagonMCInstrInfo::isPredicateLate(MCII, MCI) && isPredicateRegister(*SRI))
else if (HexagonMCInstrInfo::isPredicateLate(MCII, MCI) &&
isPredicateRegister(*SRI))
// Some insns produce predicates too late to be used in the same packet.
LatePreds.insert(*SRI);
else if (i == 0 && llvm::HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeCVI_VM_CUR_LD)
else if (i == 0 && llvm::HexagonMCInstrInfo::getType(MCII, MCI) ==
HexagonII::TypeCVI_VM_CUR_LD)
// Current loads should be used in the same packet.
// TODO: relies on the impossibility of a current and a temporary loads
// in the same packet.
CurDefs.insert(*SRI), Defs[*SRI].insert(PredSense(PredReg, isTrue));
else if (i == 0 && llvm::HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeCVI_VM_TMP_LD)
else if (i == 0 && llvm::HexagonMCInstrInfo::getType(MCII, MCI) ==
HexagonII::TypeCVI_VM_TMP_LD)
// Temporary loads should be used in the same packet, but don't commit
// results, so it should be disregarded if another insn changes the same
// register.
// TODO: relies on the impossibility of a current and a temporary loads
// in the same packet.
TmpDefs.insert(*SRI);
else if (i <= 1 && llvm::HexagonMCInstrInfo::hasNewValue2(MCII, MCI) )
else if (i <= 1 && llvm::HexagonMCInstrInfo::hasNewValue2(MCII, MCI))
// vshuff(Vx, Vy, Rx) <- Vx(0) and Vy(1) are both source and
// destination registers with this instruction. same for vdeal(Vx,Vy,Rx)
Uses.insert(*SRI);
@ -187,25 +188,26 @@ void HexagonMCChecker::init(MCInst const& MCI) {
if (HexagonMCInstrInfo::isCompound(MCII, MCI))
compoundRegisterMap(R); // Compound insns have a limited register range.
for(MCRegAliasIterator SRI(R, &RI, !MCSubRegIterator(R, &RI).isValid());
SRI.isValid();
++SRI)
for (MCRegAliasIterator SRI(R, &RI, !MCSubRegIterator(R, &RI).isValid());
SRI.isValid(); ++SRI)
if (!MCSubRegIterator(*SRI, &RI).isValid())
// No super-registers defined indirectly.
NewDefs[*SRI].push_back(NewSense::Def(PredReg, HexagonMCInstrInfo::isPredicatedTrue(MCII, MCI),
HexagonMCInstrInfo::isFloat(MCII, MCI)));
NewDefs[*SRI].push_back(NewSense::Def(
PredReg, HexagonMCInstrInfo::isPredicatedTrue(MCII, MCI),
HexagonMCInstrInfo::isFloat(MCII, MCI)));
// For fairly unique 2-dot-new producers, example:
// vdeal(V1, V9, R0) V1.new and V9.new can be used by consumers.
if (HexagonMCInstrInfo::hasNewValue2(MCII, MCI)) {
unsigned R2 = HexagonMCInstrInfo::getNewValueOperand2(MCII, MCI).getReg();
for(MCRegAliasIterator SRI(R2, &RI, !MCSubRegIterator(R2, &RI).isValid());
SRI.isValid();
++SRI)
for (MCRegAliasIterator SRI(R2, &RI,
!MCSubRegIterator(R2, &RI).isValid());
SRI.isValid(); ++SRI)
if (!MCSubRegIterator(*SRI, &RI).isValid())
NewDefs[*SRI].push_back(NewSense::Def(PredReg, HexagonMCInstrInfo::isPredicatedTrue(MCII, MCI),
HexagonMCInstrInfo::isFloat(MCII, MCI)));
NewDefs[*SRI].push_back(NewSense::Def(
PredReg, HexagonMCInstrInfo::isPredicatedTrue(MCII, MCI),
HexagonMCInstrInfo::isFloat(MCII, MCI)));
}
}
@ -227,18 +229,19 @@ void HexagonMCChecker::init(MCInst const& MCI) {
// Super-registers cannot use new values.
if (MCID.isBranch())
NewUses[N] = NewSense::Jmp(
llvm::HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeNCJ);
llvm::HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeNCJ);
else
NewUses[N] = NewSense::Use(
PredReg, HexagonMCInstrInfo::isPredicatedTrue(MCII, MCI));
PredReg, HexagonMCInstrInfo::isPredicatedTrue(MCII, MCI));
}
}
}
HexagonMCChecker::HexagonMCChecker(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCInst &mcb, MCInst &mcbdx,
MCRegisterInfo const &ri)
: MCB(mcb), MCBDX(mcbdx), RI(ri), MCII(MCII), STI(STI),
bLoadErrInfo(false) {
HexagonMCChecker::HexagonMCChecker(MCContext &Context, MCInstrInfo const &MCII,
MCSubtargetInfo const &STI, MCInst &mcb,
MCRegisterInfo const &ri, bool ReportErrors)
: Context(Context), MCB(mcb), RI(ri), MCII(MCII), STI(STI),
ReportErrors(ReportErrors) {
init();
}
@ -250,21 +253,19 @@ bool HexagonMCChecker::check(bool FullCheck) {
bool chkS = checkSolo();
bool chkSh = true;
if (FullCheck)
chkSh = checkShuffle();
chkSh = checkShuffle();
bool chkSl = true;
if (FullCheck)
chkSl = checkSlots();
chkSl = checkSlots();
bool chk = chkB && chkP && chkNV && chkR && chkS && chkSh && chkSl;
return chk;
}
bool HexagonMCChecker::checkSlots()
{
bool HexagonMCChecker::checkSlots() {
unsigned slotsUsed = 0;
for (auto HMI: HexagonMCInstrInfo::bundleInstructions(MCBDX)) {
MCInst const& MCI = *HMI.getInst();
for (auto HMI : HexagonMCInstrInfo::bundleInstructions(MCB)) {
MCInst const &MCI = *HMI.getInst();
if (HexagonMCInstrInfo::isImmext(MCI))
continue;
if (HexagonMCInstrInfo::isDuplex(MCII, MCI))
@ -274,9 +275,7 @@ bool HexagonMCChecker::checkSlots()
}
if (slotsUsed > HEXAGON_PACKET_SIZE) {
HexagonMCErrInfo errInfo;
errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_NOSLOTS);
addErrInfo(errInfo);
reportError("invalid instruction packet: out of slots");
return false;
}
return true;
@ -284,11 +283,9 @@ bool HexagonMCChecker::checkSlots()
// Check legal use of branches.
bool HexagonMCChecker::checkBranches() {
HexagonMCErrInfo errInfo;
if (HexagonMCInstrInfo::isBundle(MCB)) {
bool hasConditional = false;
unsigned Branches = 0,
Conditional = HEXAGON_PRESHUFFLE_PACKET_SIZE,
unsigned Branches = 0, Conditional = HEXAGON_PRESHUFFLE_PACKET_SIZE,
Unconditional = HEXAGON_PRESHUFFLE_PACKET_SIZE;
for (unsigned i = HexagonMCInstrInfo::bundleInstructionsOffset;
@ -314,16 +311,18 @@ bool HexagonMCChecker::checkBranches() {
if (HexagonMCInstrInfo::isInnerLoop(MCB) ||
HexagonMCInstrInfo::isOuterLoop(MCB)) {
// Error out if there's any branch in a loop-end packet.
errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_ENDLOOP, Hexagon::PC);
addErrInfo(errInfo);
Twine N(HexagonMCInstrInfo::isInnerLoop(MCB) ? '0' : '1');
reportError("packet marked with `:endloop" + N + "' " +
"cannot contain instructions that modify register " + "`" +
llvm::Twine(RI.getName(Hexagon::PC)) + "'");
return false;
}
if (Branches > 1)
if (!hasConditional || Conditional > Unconditional) {
// Error out if more than one unconditional branch or
// the conditional branch appears after the unconditional one.
errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_BRANCHES);
addErrInfo(errInfo);
reportError(
"unconditional branch cannot precede another branch in packet");
return false;
}
}
@ -333,31 +332,28 @@ bool HexagonMCChecker::checkBranches() {
// Check legal use of predicate registers.
bool HexagonMCChecker::checkPredicates() {
HexagonMCErrInfo errInfo;
// Check for proper use of new predicate registers.
for (const auto& I : NewPreds) {
for (const auto &I : NewPreds) {
unsigned P = I;
if (!Defs.count(P) || LatePreds.count(P)) {
// Error out if the new predicate register is not defined,
// or defined "late"
// (e.g., "{ if (p3.new)... ; p3 = sp1loop0(#r7:2, Rs) }").
errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_NEWP, P);
addErrInfo(errInfo);
reportErrorNewValue(P);
return false;
}
}
// Check for proper use of auto-anded of predicate registers.
for (const auto& I : LatePreds) {
for (const auto &I : LatePreds) {
unsigned P = I;
if (LatePreds.count(P) > 1 || Defs.count(P)) {
// Error out if predicate register defined "late" multiple times or
// defined late and regularly defined
// (e.g., "{ p3 = sp1loop0(...); p3 = cmp.eq(...) }".
errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_REGISTERS, P);
addErrInfo(errInfo);
reportErrorRegisters(P);
return false;
}
}
@ -367,15 +363,12 @@ bool HexagonMCChecker::checkPredicates() {
// Check legal use of new values.
bool HexagonMCChecker::checkNewValues() {
HexagonMCErrInfo errInfo;
memset(&errInfo, 0, sizeof(errInfo));
for (auto& I : NewUses) {
for (auto &I : NewUses) {
unsigned R = I.first;
NewSense &US = I.second;
if (!hasValidNewValueDef(US, NewDefs[R])) {
errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_NEWV, R);
addErrInfo(errInfo);
reportErrorNewValue(R);
return false;
}
}
@ -385,23 +378,22 @@ bool HexagonMCChecker::checkNewValues() {
// Check for legal register uses and definitions.
bool HexagonMCChecker::checkRegisters() {
HexagonMCErrInfo errInfo;
// Check for proper register definitions.
for (const auto& I : Defs) {
for (const auto &I : Defs) {
unsigned R = I.first;
if (ReadOnly.count(R)) {
// Error out for definitions of read-only registers.
errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_READONLY, R);
addErrInfo(errInfo);
reportError("cannot write to read-only register `" +
llvm::Twine(RI.getName(R)) + "'");
return false;
}
if (isLoopRegister(R) && Defs.count(R) > 1 &&
(HexagonMCInstrInfo::isInnerLoop(MCB) ||
HexagonMCInstrInfo::isOuterLoop(MCB))) {
// Error out for definitions of loop registers at the end of a loop.
errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_LOOP, R);
addErrInfo(errInfo);
reportError("loop-setup and some branch instructions "
"cannot be in the same packet");
return false;
}
if (SoftDefs.count(R)) {
@ -409,8 +401,7 @@ bool HexagonMCChecker::checkRegisters() {
// (e.g., "{ usr = r0; r0 = sfadd(...) }").
unsigned UsrR = Hexagon::USR; // Silence warning about mixed types in ?:.
unsigned BadR = RI.isSubRegister(Hexagon::USR, R) ? UsrR : R;
errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_REGISTERS, BadR);
addErrInfo(errInfo);
reportErrorRegisters(BadR);
return false;
}
if (!isPredicateRegister(R) && Defs[R].size() > 1) {
@ -423,20 +414,18 @@ bool HexagonMCChecker::checkRegisters() {
// changes, conditional or not.
unsigned UsrR = Hexagon::USR;
unsigned BadR = RI.isSubRegister(Hexagon::USR, R) ? UsrR : R;
errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_REGISTERS, BadR);
addErrInfo(errInfo);
reportErrorRegisters(BadR);
return false;
}
// Check for multiple conditional register definitions.
for (const auto& J : PM) {
for (const auto &J : PM) {
PredSense P = J;
// Check for multiple uses of the same condition.
if (PM.count(P) > 1) {
// Error out on conditional changes based on the same predicate
// (e.g., "{ if (!p0) r0 =...; if (!p0) r0 =... }").
errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_REGISTERS, R);
addErrInfo(errInfo);
reportErrorRegisters(R);
return false;
}
// Check for the use of the complementary condition.
@ -444,9 +433,9 @@ bool HexagonMCChecker::checkRegisters() {
if (PM.count(P) && PM.size() > 2) {
// Error out on conditional changes based on the same predicate
// multiple times
// (e.g., "{ if (p0) r0 =...; if (!p0) r0 =... }; if (!p0) r0 =... }").
errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_REGISTERS, R);
addErrInfo(errInfo);
// (e.g., "{ if (p0) r0 =...; if (!p0) r0 =... }; if (!p0) r0 =...
// }").
reportErrorRegisters(R);
return false;
}
}
@ -454,34 +443,37 @@ bool HexagonMCChecker::checkRegisters() {
}
// Check for use of current definitions.
for (const auto& I : CurDefs) {
for (const auto &I : CurDefs) {
unsigned R = I;
if (!Uses.count(R)) {
// Warn on an unused current definition.
errInfo.setWarning(HexagonMCErrInfo::CHECK_WARN_CURRENT, R);
addErrInfo(errInfo);
reportWarning("register `" + llvm::Twine(RI.getName(R)) +
"' used with `.cur' "
"but not used in the same packet");
return true;
}
}
// Check for use of temporary definitions.
for (const auto& I : TmpDefs) {
for (const auto &I : TmpDefs) {
unsigned R = I;
if (!Uses.count(R)) {
// special case for vhist
bool vHistFound = false;
for (auto const&HMI : HexagonMCInstrInfo::bundleInstructions(MCB)) {
if(llvm::HexagonMCInstrInfo::getType(MCII, *HMI.getInst()) == HexagonII::TypeCVI_HIST) {
vHistFound = true; // vhist() implicitly uses ALL REGxx.tmp
for (auto const &HMI : HexagonMCInstrInfo::bundleInstructions(MCB)) {
if (llvm::HexagonMCInstrInfo::getType(MCII, *HMI.getInst()) ==
HexagonII::TypeCVI_HIST) {
vHistFound = true; // vhist() implicitly uses ALL REGxx.tmp
break;
}
}
// Warn on an unused temporary definition.
if (vHistFound == false) {
errInfo.setWarning(HexagonMCErrInfo::CHECK_WARN_TEMPORARY, R);
addErrInfo(errInfo);
reportWarning("register `" + llvm::Twine(RI.getName(R)) +
"' used with `.tmp' "
"but not used in the same packet");
return true;
}
}
@ -492,13 +484,12 @@ bool HexagonMCChecker::checkRegisters() {
// Check for legal use of solo insns.
bool HexagonMCChecker::checkSolo() {
HexagonMCErrInfo errInfo;
if (HexagonMCInstrInfo::isBundle(MCB) &&
HexagonMCInstrInfo::bundleSize(MCB) > 1) {
for (auto const&I : HexagonMCInstrInfo::bundleInstructions(MCB)) {
for (auto const &I : HexagonMCInstrInfo::bundleInstructions(MCB)) {
if (llvm::HexagonMCInstrInfo::isSolo(MCII, *I.getInst())) {
errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_SOLO);
addErrInfo(errInfo);
reportError(
"instruction cannot appear in packet with other instructions");
return false;
}
}
@ -508,29 +499,11 @@ bool HexagonMCChecker::checkSolo() {
}
bool HexagonMCChecker::checkShuffle() {
HexagonMCErrInfo errInfo;
// Branch info is lost when duplexing. The unduplexed insns must be
// checked and only branch errors matter for this case.
HexagonMCShuffler MCS(true, MCII, STI, MCB);
if (!MCS.check()) {
if (MCS.getError() == HexagonShuffler::SHUFFLE_ERROR_BRANCHES) {
errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_SHUFFLE);
errInfo.setShuffleError(MCS.getError());
addErrInfo(errInfo);
return false;
}
}
HexagonMCShuffler MCSDX(true, MCII, STI, MCBDX);
if (!MCSDX.check()) {
errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_SHUFFLE);
errInfo.setShuffleError(MCSDX.getError());
addErrInfo(errInfo);
return false;
}
return true;
HexagonMCShuffler MCSDX(Context, ReportErrors, MCII, STI, MCB);
return MCSDX.check();
}
void HexagonMCChecker::compoundRegisterMap(unsigned& Register) {
void HexagonMCChecker::compoundRegisterMap(unsigned &Register) {
switch (Register) {
default:
break;
@ -562,7 +535,7 @@ void HexagonMCChecker::compoundRegisterMap(unsigned& Register) {
}
bool HexagonMCChecker::hasValidNewValueDef(const NewSense &Use,
const NewSenseList &Defs) const {
const NewSenseList &Defs) const {
bool Strict = !RelaxNVChecks;
for (unsigned i = 0, n = Defs.size(); i < n; ++i) {
@ -590,3 +563,26 @@ bool HexagonMCChecker::hasValidNewValueDef(const NewSense &Use,
return false;
}
void HexagonMCChecker::reportErrorRegisters(unsigned Register) {
reportError("register `" + llvm::Twine(RI.getName(Register)) +
"' modified more than once");
}
void HexagonMCChecker::reportErrorNewValue(unsigned Register) {
reportError("register `" + llvm::Twine(RI.getName(Register)) +
"' used with `.new' "
"but not validly modified in the same packet");
}
void HexagonMCChecker::reportError(llvm::Twine const &Msg) {
if (ReportErrors)
Context.reportError(MCB.getLoc(), Msg);
}
void HexagonMCChecker::reportWarning(llvm::Twine const &Msg) {
if (ReportErrors) {
auto SM = Context.getSourceManager();
if (SM)
SM->PrintMessage(MCB.getLoc(), SourceMgr::DK_Warning, Msg);
}
}

@ -24,59 +24,14 @@ using namespace llvm;
namespace llvm {
class MCOperandInfo;
typedef struct {
unsigned Error, Warning, ShuffleError;
unsigned Register;
} ErrInfo_T;
class HexagonMCErrInfo {
public:
enum {
CHECK_SUCCESS = 0,
// Errors.
CHECK_ERROR_BRANCHES = 0x00001,
CHECK_ERROR_NEWP = 0x00002,
CHECK_ERROR_NEWV = 0x00004,
CHECK_ERROR_REGISTERS = 0x00008,
CHECK_ERROR_READONLY = 0x00010,
CHECK_ERROR_LOOP = 0x00020,
CHECK_ERROR_ENDLOOP = 0x00040,
CHECK_ERROR_SOLO = 0x00080,
CHECK_ERROR_SHUFFLE = 0x00100,
CHECK_ERROR_NOSLOTS = 0x00200,
CHECK_ERROR_UNKNOWN = 0x00400,
// Warnings.
CHECK_WARN_CURRENT = 0x10000,
CHECK_WARN_TEMPORARY = 0x20000
};
ErrInfo_T s;
void reset() {
s.Error = CHECK_SUCCESS;
s.Warning = CHECK_SUCCESS;
s.ShuffleError = HexagonShuffler::SHUFFLE_SUCCESS;
s.Register = Hexagon::NoRegister;
};
HexagonMCErrInfo() {
reset();
};
void setError(unsigned e, unsigned r = Hexagon::NoRegister)
{ s.Error = e; s.Register = r; };
void setWarning(unsigned w, unsigned r = Hexagon::NoRegister)
{ s.Warning = w; s.Register = r; };
void setShuffleError(unsigned e) { s.ShuffleError = e; };
};
/// Check for a valid bundle.
class HexagonMCChecker {
/// Insn bundle.
MCInst& MCB;
MCInst& MCBDX;
const MCRegisterInfo& RI;
MCContext &Context;
MCInst &MCB;
const MCRegisterInfo &RI;
MCInstrInfo const &MCII;
MCSubtargetInfo const &STI;
bool bLoadErrInfo;
bool ReportErrors;
/// Set of definitions: register #, if predicated, if predicated true.
typedef std::pair<unsigned, bool> PredSense;
@ -99,23 +54,23 @@ class HexagonMCChecker {
bool IsFloat, IsNVJ, Cond;
// The special-case "constructors":
static NewSense Jmp(bool isNVJ) {
NewSense NS = { /*PredReg=*/ 0, /*IsFloat=*/ false, /*IsNVJ=*/ isNVJ,
/*Cond=*/ false };
NewSense NS = {/*PredReg=*/0, /*IsFloat=*/false, /*IsNVJ=*/isNVJ,
/*Cond=*/false};
return NS;
}
static NewSense Use(unsigned PR, bool True) {
NewSense NS = { /*PredReg=*/ PR, /*IsFloat=*/ false, /*IsNVJ=*/ false,
/*Cond=*/ True };
NewSense NS = {/*PredReg=*/PR, /*IsFloat=*/false, /*IsNVJ=*/false,
/*Cond=*/True};
return NS;
}
static NewSense Def(unsigned PR, bool True, bool Float) {
NewSense NS = { /*PredReg=*/ PR, /*IsFloat=*/ Float, /*IsNVJ=*/ false,
/*Cond=*/ True };
NewSense NS = {/*PredReg=*/PR, /*IsFloat=*/Float, /*IsNVJ=*/false,
/*Cond=*/True};
return NS;
}
};
/// Set of definitions that produce new register:
typedef llvm::SmallVector<NewSense,2> NewSenseList;
typedef llvm::SmallVector<NewSense, 2> NewSenseList;
typedef llvm::DenseMap<unsigned, NewSenseList>::iterator NewDefsIterator;
llvm::DenseMap<unsigned, NewSenseList> NewDefs;
@ -151,23 +106,8 @@ class HexagonMCChecker {
typedef std::set<unsigned>::iterator ReadOnlyIterator;
std::set<unsigned> ReadOnly;
std::queue<ErrInfo_T> ErrInfoQ;
HexagonMCErrInfo CrntErrInfo;
void getErrInfo() {
if (bLoadErrInfo == true) {
if (ErrInfoQ.empty()) {
CrntErrInfo.reset();
} else {
CrntErrInfo.s = ErrInfoQ.front();
ErrInfoQ.pop();
}
}
bLoadErrInfo = false;
}
void init();
void init(MCInst const&);
void init(MCInst const &);
void initReg(MCInst const &, unsigned, unsigned &PredReg, bool &isTrue);
// Checks performed.
@ -180,40 +120,31 @@ class HexagonMCChecker {
bool checkSlots();
bool checkSize();
static void compoundRegisterMap(unsigned&);
static void compoundRegisterMap(unsigned &);
bool isPredicateRegister(unsigned R) const {
return (Hexagon::P0 == R || Hexagon::P1 == R ||
Hexagon::P2 == R || Hexagon::P3 == R);
return (Hexagon::P0 == R || Hexagon::P1 == R || Hexagon::P2 == R ||
Hexagon::P3 == R);
};
bool isLoopRegister(unsigned R) const {
return (Hexagon::SA0 == R || Hexagon::LC0 == R ||
Hexagon::SA1 == R || Hexagon::LC1 == R);
return (Hexagon::SA0 == R || Hexagon::LC0 == R || Hexagon::SA1 == R ||
Hexagon::LC1 == R);
};
bool hasValidNewValueDef(const NewSense &Use,
const NewSenseList &Defs) const;
bool hasValidNewValueDef(const NewSense &Use, const NewSenseList &Defs) const;
public:
explicit HexagonMCChecker(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCInst& mcb, MCInst &mcbdx,
const MCRegisterInfo& ri);
public:
explicit HexagonMCChecker(MCContext &Context, MCInstrInfo const &MCII,
MCSubtargetInfo const &STI, MCInst &mcb,
const MCRegisterInfo &ri, bool ReportErrors = true);
bool check(bool FullCheck = true);
/// add a new error/warning
void addErrInfo(HexagonMCErrInfo &err) { ErrInfoQ.push(err.s); };
/// Return the error code for the last operation in the insn bundle.
unsigned getError() { getErrInfo(); return CrntErrInfo.s.Error; };
unsigned getWarning() { getErrInfo(); return CrntErrInfo.s.Warning; };
unsigned getShuffleError() { getErrInfo(); return CrntErrInfo.s.ShuffleError; };
unsigned getErrRegister() { getErrInfo(); return CrntErrInfo.s.Register; };
bool getNextErrInfo() {
bLoadErrInfo = true;
return (ErrInfoQ.empty()) ? false : (getErrInfo(), true);
}
void reportErrorRegisters(unsigned Register);
void reportErrorNewValue(unsigned Register);
void reportError(llvm::Twine const &Msg);
void reportWarning(llvm::Twine const &Msg);
};
}
} // namespace llvm
#endif // HEXAGONMCCHECKER_H

@ -406,7 +406,7 @@ void HexagonMCInstrInfo::tryCompound(MCInstrInfo const &MCII, MCSubtargetInfo co
if (MCI.size() < 2)
return;
bool StartedValid = llvm::HexagonMCShuffle(false, MCII, STI, MCI);
bool StartedValid = llvm::HexagonMCShuffle(Context, false, MCII, STI, MCI);
// Create a vector, needed to keep the order of jump instructions.
MCInst CheckList(MCI);
@ -420,8 +420,9 @@ void HexagonMCInstrInfo::tryCompound(MCInstrInfo const &MCII, MCSubtargetInfo co
// Need to update the bundle.
MCI = CheckList;
if (StartedValid && !llvm::HexagonMCShuffle(false, MCII, STI, MCI)) {
DEBUG(dbgs() << "Found ERROR\n");
if (StartedValid &&
!llvm::HexagonMCShuffle(Context, false, MCII, STI, MCI)) {
DEBUG(dbgs() << "Found ERROR\n");
MCI = OriginalBundle;
}
}

@ -66,7 +66,7 @@ bool HexagonMCInstrInfo::canonicalizePacket(MCInstrInfo const &MCII,
// instructions when possible.
if (!HexagonDisableCompound)
HexagonMCInstrInfo::tryCompound(MCII, STI, Context, MCB);
HexagonMCShuffle(false, MCII, STI, MCB);
HexagonMCShuffle(Context, false, MCII, STI, MCB);
// Examine the packet and convert pairs of instructions to duplex
// instructions when possible.
MCInst InstBundlePreDuplex = MCInst(MCB);
@ -74,7 +74,7 @@ bool HexagonMCInstrInfo::canonicalizePacket(MCInstrInfo const &MCII,
SmallVector<DuplexCandidate, 8> possibleDuplexes;
possibleDuplexes =
HexagonMCInstrInfo::getDuplexPossibilties(MCII, STI, MCB);
HexagonMCShuffle(MCII, STI, Context, MCB, possibleDuplexes);
HexagonMCShuffle(Context, MCII, STI, MCB, possibleDuplexes);
}
// Examines packet and pad the packet, if needed, when an
// end-loop is in the bundle.
@ -87,7 +87,7 @@ bool HexagonMCInstrInfo::canonicalizePacket(MCInstrInfo const &MCII,
CheckOk = Check ? Check->check(true) : true;
if (!CheckOk)
return false;
HexagonMCShuffle(true, MCII, STI, MCB);
HexagonMCShuffle(Context, true, MCII, STI, MCB);
return true;
}

@ -45,6 +45,7 @@ void HexagonMCShuffler::init(MCInst &MCB) {
}
}
Loc = MCB.getLoc();
BundleFlags = MCB.getOperand(0).getImm();
}
@ -68,12 +69,14 @@ void HexagonMCShuffler::init(MCInst &MCB, MCInst const &AddMI,
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) {
@ -89,15 +92,16 @@ bool HexagonMCShuffler::reshuffleTo(MCInst &MCB) {
if (shuffle()) {
// Copy the results into the bundle.
copyTo(MCB);
} else
DEBUG(MCB.dump());
return (!getError());
return true;
}
DEBUG(MCB.dump());
return false;
}
bool llvm::HexagonMCShuffle(bool Fatal, MCInstrInfo const &MCII,
MCSubtargetInfo const &STI, MCInst &MCB) {
HexagonMCShuffler MCS(true, MCII, STI, MCB);
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.
@ -117,52 +121,16 @@ bool llvm::HexagonMCShuffle(bool Fatal, MCInstrInfo const &MCII,
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();
if (!Fatal && (shuffleError != HexagonShuffler::SHUFFLE_SUCCESS))
return false;
if (shuffleError != HexagonShuffler::SHUFFLE_SUCCESS) {
errs() << "\nFailing packet:\n";
for (const auto& I : HexagonMCInstrInfo::bundleInstructions(MCB)) {
MCInst *MI = const_cast<MCInst *>(I.getInst());
errs() << HexagonMCInstrInfo::getName(MCII, *MI) << ' ' << HexagonMCInstrInfo::getDesc(MCII, *MI).getOpcode() << '\n';
}
errs() << '\n';
}
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;
return MCS.reshuffleTo(MCB);
}
unsigned
llvm::HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
MCContext &Context, MCInst &MCB,
bool
llvm::HexagonMCShuffle(MCContext &Context, MCInstrInfo const &MCII,
MCSubtargetInfo const &STI, MCInst &MCB,
SmallVector<DuplexCandidate, 8> possibleDuplexes) {
if (DisableShuffle)
return HexagonShuffler::SHUFFLE_SUCCESS;
return false;
if (!HexagonMCInstrInfo::bundleSize(MCB)) {
// There once was a bundle:
@ -172,46 +140,44 @@ llvm::HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
// After the IMPLICIT_DEFs were removed by the asm printer, the bundle
// became empty.
DEBUG(dbgs() << "Skipping empty bundle");
return HexagonShuffler::SHUFFLE_SUCCESS;
return false;
} else if (!HexagonMCInstrInfo::isBundle(MCB)) {
DEBUG(dbgs() << "Skipping stand-alone insn");
return HexagonShuffler::SHUFFLE_SUCCESS;
return false;
}
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(true, MCII, STI, Attempt); // copy packet to the shuffler
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 HexagonShuffler::SHUFFLE_SUCCESS;
return false;
}
// try shuffle with this duplex
doneShuffling = MCS.reshuffleTo(MCB);
shuffleError = MCS.getError();
if (doneShuffling)
break;
}
if (doneShuffling == false) {
HexagonMCShuffler MCS(true, MCII, STI, MCB);
HexagonMCShuffler MCS(Context, false, MCII, STI, MCB);
doneShuffling = MCS.reshuffleTo(MCB); // shuffle
shuffleError = MCS.getError();
}
if (!doneShuffling)
return shuffleError;
return true;
return HexagonShuffler::SHUFFLE_SUCCESS;
return false;
}
bool llvm::HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
MCInst &MCB, MCInst const &AddMI, int fixupCount) {
bool llvm::HexagonMCShuffle(MCContext &Context, MCInstrInfo const &MCII,
MCSubtargetInfo const &STI, MCInst &MCB,
MCInst const &AddMI, int fixupCount) {
if (!HexagonMCInstrInfo::isBundle(MCB))
return false;
@ -246,16 +212,6 @@ bool llvm::HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
if (bhasDuplex && bundleSize >= maxBundleSize)
return false;
HexagonMCShuffler MCS(MCII, STI, MCB, AddMI, false);
if (!MCS.reshuffleTo(MCB)) {
unsigned shuffleError = MCS.getError();
switch (shuffleError) {
default:
return false;
case HexagonShuffler::SHUFFLE_SUCCESS: // single instruction case
return true;
}
}
return true;
HexagonMCShuffler MCS(Context, false, MCII, STI, MCB, AddMI, false);
return MCS.reshuffleTo(MCB);
}

@ -18,24 +18,19 @@
#include "MCTargetDesc/HexagonShuffler.h"
namespace llvm {
class MCInst;
// Insn bundle shuffler.
class HexagonMCShuffler : public HexagonShuffler {
bool immext_present;
bool duplex_present;
public:
HexagonMCShuffler(bool Fatal, MCInstrInfo const &MCII,
HexagonMCShuffler(MCContext &Context, bool Fatal, MCInstrInfo const &MCII,
MCSubtargetInfo const &STI, MCInst &MCB)
: HexagonShuffler(MCII, STI) {
: HexagonShuffler(Context, Fatal, MCII, STI) {
init(MCB);
};
HexagonMCShuffler(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
MCInst &MCB, MCInst const &AddMI,
bool InsertAtFront)
: HexagonShuffler(MCII, STI) {
HexagonMCShuffler(MCContext &Context, bool Fatal, MCInstrInfo const &MCII,
MCSubtargetInfo const &STI, MCInst &MCB,
MCInst const &AddMI, bool InsertAtFront)
: HexagonShuffler(Context, Fatal, MCII, STI) {
init(MCB, AddMI, InsertAtFront);
};
@ -44,22 +39,20 @@ public:
// 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, MCInst const &AddMI, bool InsertAtFront);
};
// Invocation of the shuffler.
bool HexagonMCShuffle(bool Fatal, MCInstrInfo const &MCII,
bool HexagonMCShuffle(MCContext &Context, bool Fatal, MCInstrInfo const &MCII,
MCSubtargetInfo const &STI, MCInst &);
bool HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
MCInst &, MCInst const &, int);
unsigned HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
MCContext &Context, MCInst &,
SmallVector<DuplexCandidate, 8>);
}
bool HexagonMCShuffle(MCContext &Context, MCInstrInfo const &MCII,
MCSubtargetInfo const &STI, MCInst &, MCInst const &,
int);
bool HexagonMCShuffle(MCContext &Context, MCInstrInfo const &MCII,
MCSubtargetInfo const &STI, MCInst &,
SmallVector<DuplexCandidate, 8>);
} // namespace llvm
#endif // HEXAGONMCSHUFFLER_H

@ -14,17 +14,18 @@
#define DEBUG_TYPE "hexagon-shuffle"
#include <algorithm>
#include <utility>
#include "HexagonShuffler.h"
#include "Hexagon.h"
#include "MCTargetDesc/HexagonBaseInfo.h"
#include "MCTargetDesc/HexagonMCTargetDesc.h"
#include "MCTargetDesc/HexagonMCInstrInfo.h"
#include "HexagonShuffler.h"
#include "MCTargetDesc/HexagonMCTargetDesc.h"
#include "llvm/MC/MCContext.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <utility>
using namespace llvm;
@ -38,7 +39,7 @@ class HexagonBid {
unsigned Bid;
public:
HexagonBid() : Bid(0){}
HexagonBid() : Bid(0) {}
HexagonBid(unsigned B) { Bid = B ? MAX / countPopulation(B) : 0; }
// Check if the insn priority is overflowed.
@ -87,7 +88,7 @@ unsigned HexagonResource::setWeight(unsigned s) {
// 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.
if (Key == 0 || Units == 0 || (SlotWeight*s >= 32))
if (Key == 0 || Units == 0 || (SlotWeight * s >= 32))
return Weight = 0;
unsigned Ctpop = countPopulation(Units);
@ -106,9 +107,9 @@ void HexagonCVIResource::SetupTUL(TypeUnitsAndLanes *TUL, StringRef CPU) {
(*TUL)[HexagonII::TypeCVI_VP_VS] = UnitsAndLanes(CVI_XLANE, 2);
(*TUL)[HexagonII::TypeCVI_VS] = UnitsAndLanes(CVI_SHIFT, 1);
(*TUL)[HexagonII::TypeCVI_VINLANESAT] =
(CPU == "hexagonv60" || CPU == "hexagonv61" || CPU == "hexagonv61v1") ?
UnitsAndLanes(CVI_SHIFT, 1) :
UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1);
(CPU == "hexagonv60" || CPU == "hexagonv61" || CPU == "hexagonv61v1")
? UnitsAndLanes(CVI_SHIFT, 1)
: UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1);
(*TUL)[HexagonII::TypeCVI_VM_LD] =
UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1);
(*TUL)[HexagonII::TypeCVI_VM_TMP_LD] = UnitsAndLanes(CVI_NONE, 0);
@ -154,18 +155,19 @@ typedef SmallVector<struct CVIUnits, 8> HVXInstsT;
static unsigned makeAllBits(unsigned startBit, unsigned Lanes)
{
for (unsigned i = 1 ; i < Lanes ; ++i)
for (unsigned i = 1; i < Lanes; ++i)
startBit = (startBit << 1) | startBit;
return startBit;
}
static bool checkHVXPipes(const HVXInstsT& hvxInsts, unsigned startIdx, unsigned usedUnits)
static bool checkHVXPipes(const HVXInstsT &hvxInsts, unsigned startIdx,
unsigned usedUnits)
{
if (startIdx < hvxInsts.size()) {
if (!hvxInsts[startIdx].Units)
return checkHVXPipes(hvxInsts, startIdx + 1, usedUnits);
for (unsigned b = 0x1 ; b <= 0x8 ; b <<= 1) {
for (unsigned b = 0x1; b <= 0x8; b <<= 1) {
if ((hvxInsts[startIdx].Units & b) == 0)
continue;
unsigned allBits = makeAllBits(b, hvxInsts[startIdx].Lanes);
@ -179,9 +181,10 @@ static bool checkHVXPipes(const HVXInstsT& hvxInsts, unsigned startIdx, unsigned
return true;
}
HexagonShuffler::HexagonShuffler(MCInstrInfo const &MCII,
HexagonShuffler::HexagonShuffler(MCContext &Context, bool ReportErrors,
MCInstrInfo const &MCII,
MCSubtargetInfo const &STI)
: MCII(MCII), STI(STI) {
: Context(Context), MCII(MCII), STI(STI), ReportErrors(ReportErrors) {
reset();
HexagonCVIResource::SetupTUL(&TUL, STI.getCPU());
}
@ -189,7 +192,6 @@ HexagonShuffler::HexagonShuffler(MCInstrInfo const &MCII,
void HexagonShuffler::reset() {
Packet.clear();
BundleFlags = 0;
Error = SHUFFLE_SUCCESS;
}
void HexagonShuffler::append(MCInst const &ID, MCInst const *Extender,
@ -202,8 +204,8 @@ void HexagonShuffler::append(MCInst const &ID, MCInst const *Extender,
static struct {
unsigned first;
unsigned second;
} jumpSlots[] = { {8, 4}, {8, 2}, {8, 1}, {4, 2}, {4, 1}, {2, 1} };
#define MAX_JUMP_SLOTS (sizeof(jumpSlots)/sizeof(jumpSlots[0]))
} jumpSlots[] = {{8, 4}, {8, 2}, {8, 1}, {4, 2}, {4, 1}, {2, 1}};
#define MAX_JUMP_SLOTS (sizeof(jumpSlots) / sizeof(jumpSlots[0]))
namespace {
bool isDuplexAGroup(unsigned Opcode) {
@ -248,26 +250,23 @@ unsigned countNeitherAnorX(MCInstrInfo const &MCII, MCInst const &ID) {
Result += !isDuplexAGroup(subInst0Opcode);
Result += !isDuplexAGroup(subInst1Opcode);
} else
Result += Type != HexagonII::TypeALU32_2op &&
Type != HexagonII::TypeALU32_3op &&
Type != HexagonII::TypeALU32_ADDI &&
Type != HexagonII::TypeS_2op &&
Type != HexagonII::TypeS_3op &&
Type != HexagonII::TypeALU64 &&
(Type != HexagonII::TypeM ||
HexagonMCInstrInfo::isFloat(MCII, ID));
Result +=
Type != HexagonII::TypeALU32_2op && Type != HexagonII::TypeALU32_3op &&
Type != HexagonII::TypeALU32_ADDI && Type != HexagonII::TypeS_2op &&
Type != HexagonII::TypeS_3op && Type != HexagonII::TypeALU64 &&
(Type != HexagonII::TypeM || HexagonMCInstrInfo::isFloat(MCII, ID));
return Result;
}
}
} // namespace
/// 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,
slotFirstLoadStore = 0x2, slotLastLoadStore = 0x1;
slotThree = 0x8, // slotFirstJump = 0x8,
slotFirstLoadStore = 0x2, slotLastLoadStore = 0x1;
// Highest slots for branches and stores used to keep their original order.
//unsigned slotJump = slotFirstJump;
// unsigned slotJump = slotFirstJump;
unsigned slotLoadStore = slotFirstLoadStore;
// Number of branches, solo branches, indirect branches.
unsigned jumps = 0, jump1 = 0;
@ -287,6 +286,7 @@ bool HexagonShuffler::check() {
unsigned onlyNo1 = 0;
unsigned xtypeFloat = 0;
unsigned pSlot3Cnt = 0;
unsigned nvstores = 0;
unsigned memops = 0;
unsigned deallocs = 0;
iterator slot3ISJ = end();
@ -333,8 +333,7 @@ bool HexagonShuffler::check() {
++loads;
++memory;
if (ISJ->Core.getUnits() == slotSingleLoad ||
HexagonMCInstrInfo::getType(MCII, ID) ==
HexagonII::TypeCVI_VM_VP_LDU)
HexagonMCInstrInfo::getType(MCII, ID) == HexagonII::TypeCVI_VM_VP_LDU)
++load0;
if (HexagonMCInstrInfo::getDesc(MCII, ID).isReturn()) {
++deallocs, ++jumps, ++jump1; // DEALLOC_RETURN is of type LD.
@ -368,18 +367,19 @@ bool HexagonShuffler::check() {
}
break;
case HexagonII::TypeV2LDST:
if(HexagonMCInstrInfo::getDesc(MCII, ID).mayLoad()) {
if (HexagonMCInstrInfo::getDesc(MCII, ID).mayLoad()) {
++loads;
++memory;
if (ISJ->Core.getUnits() == slotSingleLoad ||
HexagonMCInstrInfo::getType(MCII,ID) ==
HexagonMCInstrInfo::getType(MCII, ID) ==
HexagonII::TypeCVI_VM_VP_LDU)
++load0;
}
else {
} else {
assert(HexagonMCInstrInfo::getDesc(MCII, ID).mayStore());
++memory;
++stores;
if (HexagonMCInstrInfo::isNewValue(MCII, ID))
++nvstores;
}
break;
case HexagonII::TypeCR:
@ -415,21 +415,21 @@ bool HexagonShuffler::check() {
if ((load0 > 1 || store0 > 1 || CVIloads > 1 || CVIstores > 1) ||
(duplex > 1 || (duplex && memory)) || (solo && size() > 1) ||
(onlyAX && neitherAnorX > 1) || (onlyAX && xtypeFloat)) {
Error = SHUFFLE_ERROR_INVALID;
reportError(llvm::Twine("invalid instruction packet"));
return false;
}
if (jump1 && jumps > 1) {
// Error if single branch with another branch.
Error = SHUFFLE_ERROR_BRANCHES;
reportError(llvm::Twine("too many branches in packet"));
return false;
}
if (memops && stores > 1) {
Error = SHUFFLE_ERROR_STORE_LOAD_CONFLICT;
if ((nvstores || memops) && stores > 1) {
reportError(llvm::Twine("slot 0 instruction does not allow slot 1 store"));
return false;
}
if (deallocs && stores) {
Error = SHUFFLE_ERROR_STORE_LOAD_CONFLICT;
reportError(llvm::Twine("slot 0 instruction does not allow slot 1 store"));
return false;
}
@ -441,7 +441,6 @@ bool HexagonShuffler::check() {
if (!ISJ->Core.getUnits()) {
// Error if insn may not be executed in any slot.
Error = SHUFFLE_ERROR_UNKNOWN;
return false;
}
@ -472,7 +471,8 @@ bool HexagonShuffler::check() {
else if (stores > 1) {
if (slotLoadStore < slotLastLoadStore) {
// Error if no more slots available for stores.
Error = SHUFFLE_ERROR_STORES;
reportError(
llvm::Twine("invalid instruction packet: too many stores"));
return false;
}
// Pin the store to the highest slot available to it.
@ -483,7 +483,7 @@ bool HexagonShuffler::check() {
}
if (store1 && stores > 1) {
// Error if a single store with another store.
Error = SHUFFLE_ERROR_STORES;
reportError(llvm::Twine("invalid instruction packet: too many stores"));
return false;
}
}
@ -494,7 +494,7 @@ bool HexagonShuffler::check() {
if (!ISJ->Core.getUnits()) {
// Error if insn may not be executed in any slot.
Error = SHUFFLE_ERROR_NOSLOTS;
reportError(llvm::Twine("invalid instruction packet: out of slots"));
return false;
}
}
@ -503,12 +503,12 @@ bool HexagonShuffler::check() {
bool validateSlots = true;
if (jumps > 1) {
if (foundBranches.size() > 2) {
Error = SHUFFLE_ERROR_BRANCHES;
reportError(llvm::Twine("too many branches in packet"));
return false;
}
// try all possible choices
for (unsigned int i = 0 ; i < MAX_JUMP_SLOTS ; ++i) {
for (unsigned int i = 0; i < MAX_JUMP_SLOTS; ++i) {
// validate first jump with this slot rule
if (!(jumpSlots[i].first & foundBranches[0]->Core.getUnits()))
continue;
@ -535,18 +535,18 @@ bool HexagonShuffler::check() {
if (!bFail) {
validateSlots = false; // all good, no need to re-do auction
break;
}
else
} else
// restore original values
Packet = PacketSave;
}
if (validateSlots == true) {
Error = SHUFFLE_ERROR_NOSLOTS;
reportError(llvm::Twine("invalid instruction packet: out of slots"));
return false;
}
}
if (jumps <= 1 && bOnlySlot3 == false && pSlot3Cnt == 1 && slot3ISJ != end()) {
if (jumps <= 1 && bOnlySlot3 == false && pSlot3Cnt == 1 &&
slot3ISJ != end()) {
validateSlots = true;
// save off slot mask of instruction marked with A_PREFER_SLOT3
// and then pin it to slot #3
@ -582,7 +582,7 @@ bool HexagonShuffler::check() {
for (iterator I = begin(); I != end(); ++I)
if (!AuctionCore.bid(I->Core.getUnits())) {
Error = SHUFFLE_ERROR_SLOTS;
reportError(llvm::Twine("invalid instruction packet: slot error"));
return false;
}
}
@ -605,12 +605,11 @@ bool HexagonShuffler::check() {
startIdx = usedUnits = 0x0;
if (checkHVXPipes(hvxInsts, startIdx, usedUnits) == false) {
// too many pipes used to be valid
Error = SHUFFLE_ERROR_SLOTS;
reportError(llvm::Twine("invalid instruction packet: slot error"));
return false;
}
}
Error = SHUFFLE_SUCCESS;
return true;
}
@ -618,12 +617,13 @@ 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;
reportError(llvm::Twine("invalid instruction packet"));
return false;
}
// Check and prepare packet.
if (size() > 1 && check())
bool Ok = true;
if (size() > 1 && (Ok = check()))
// Reorder the handles for each slot.
for (unsigned nSlot = 0, emptySlots = 0; nSlot < HEXAGON_PACKET_SIZE;
++nSlot) {
@ -659,5 +659,10 @@ bool HexagonShuffler::shuffle() {
dbgs() << '\n');
DEBUG(dbgs() << '\n');
return (!getError());
return Ok;
}
void HexagonShuffler::reportError(llvm::Twine const &Msg) {
if (ReportErrors)
Context.reportError(Loc, Msg);
}

@ -45,8 +45,7 @@ public:
// 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()));
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) {
@ -106,7 +105,7 @@ class HexagonInstr {
public:
HexagonInstr(HexagonCVIResource::TypeUnitsAndLanes *T,
MCInstrInfo const &MCII, MCInst const *id,
MCInst const *Extender, unsigned s)
MCInst const *Extender, unsigned s, bool x = false)
: ID(id), Extender(Extender), Core(s), CVI(T, MCII, s, id) {}
MCInst const &getDesc() const { return *ID; };
@ -136,33 +135,21 @@ class HexagonShuffler {
HexagonPacket Packet;
HexagonPacket PacketSave;
// Shuffling error code.
unsigned Error;
HexagonCVIResource::TypeUnitsAndLanes TUL;
protected:
MCContext &Context;
int64_t BundleFlags;
MCInstrInfo const &MCII;
MCSubtargetInfo const &STI;
SMLoc Loc;
bool ReportErrors;
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_ERRATA2, ///< Errata violation (v60).
SHUFFLE_ERROR_STORE_LOAD_CONFLICT, ///< store/load conflict
SHUFFLE_ERROR_UNKNOWN ///< Unknown error.
};
explicit HexagonShuffler(MCInstrInfo const &MCII, MCSubtargetInfo const &STI);
HexagonShuffler(MCContext &Context, bool ReportErrors,
MCInstrInfo const &MCII, MCSubtargetInfo const &STI);
// Reset to initial state.
void reset();
@ -180,9 +167,8 @@ public:
void append(MCInst const &ID, MCInst const *Extender, unsigned S);
// Return the error code for the last check or shuffling of the bundle.
void setError(unsigned Err) { Error = Err; };
unsigned getError() const { return (Error); };
void reportError(llvm::Twine const &Msg);
};
}
} // namespace llvm
#endif // HEXAGONSHUFFLER_H