#include "MCTargetDesc/HexagonBaseInfo.h"
#include "MCTargetDesc/HexagonMCInstrInfo.h"
#include "MCTargetDesc/HexagonMCShuffler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstdint>
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
};
static const 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};
static const 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};
static const 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};
static const 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};
static const 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};
static const 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};
static const 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};
static const 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};
static const 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,
};
static unsigned getCompoundCandidateGroup(MCInst const &MI, bool IsExtended) {
unsigned DstReg, SrcReg, Src1Reg, Src2Reg;
switch (MI.getOpcode()) {
default:
return HexagonII::HCG_None;
case Hexagon::C2_cmpeq:
case Hexagon::C2_cmpgt:
case Hexagon::C2_cmpgtu:
if (IsExtended)
return HexagonII::HCG_None;
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 HexagonII::HCG_None;
DstReg = MI.getOperand(0).getReg();
SrcReg = MI.getOperand(1).getReg();
if ((Hexagon::P0 == DstReg || Hexagon::P1 == DstReg) &&
HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) &&
(HexagonMCInstrInfo::inRange<5>(MI, 2) ||
HexagonMCInstrInfo::minConstant(MI, 2) == -1))
return HexagonII::HCG_A;
break;
case Hexagon::A2_tfr:
if (IsExtended)
return HexagonII::HCG_None;
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 HexagonII::HCG_None;
DstReg = MI.getOperand(0).getReg();
if (HexagonMCInstrInfo::minConstant(MI, 1) <= 63 &&
HexagonMCInstrInfo::minConstant(MI, 1) >= 0 &&
HexagonMCInstrInfo::isIntRegForSubInst(DstReg))
return HexagonII::HCG_A;
break;
case Hexagon::S2_tstbit_i:
if (IsExtended)
return HexagonII::HCG_None;
DstReg = MI.getOperand(0).getReg();
Src1Reg = MI.getOperand(1).getReg();
if ((Hexagon::P0 == DstReg || Hexagon::P1 == DstReg) &&
HexagonMCInstrInfo::isIntRegForSubInst(Src1Reg) &&
HexagonMCInstrInfo::minConstant(MI, 2) == 0)
return HexagonII::HCG_A;
break;
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;
case Hexagon::J2_jump:
case Hexagon::RESTORE_DEALLOC_RET_JMP_V4:
return HexagonII::HCG_C;
break;
}
return HexagonII::HCG_None;
}
static 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;
}
}
static MCInst *getCompoundInsn(MCContext &Context, MCInst const &L,
MCInst const &R) {
MCInst *CompoundInsn = nullptr;
unsigned compoundOpcode;
MCOperand Rs, Rt;
int64_t Value;
bool Success;
switch (L.getOpcode()) {
default:
LLVM_DEBUG(dbgs() << "Possible compound ignored\n");
return CompoundInsn;
case Hexagon::A2_tfrsi:
Rt = L.getOperand(0);
compoundOpcode = J4_jumpseti;
CompoundInsn = Context.createMCInst();
CompoundInsn->setOpcode(compoundOpcode);
CompoundInsn->addOperand(Rt);
CompoundInsn->addOperand(L.getOperand(1)); CompoundInsn->addOperand(R.getOperand(0)); break;
case Hexagon::A2_tfr:
Rt = L.getOperand(0);
Rs = L.getOperand(1);
compoundOpcode = J4_jumpsetr;
CompoundInsn = Context.createMCInst();
CompoundInsn->setOpcode(compoundOpcode);
CompoundInsn->addOperand(Rt);
CompoundInsn->addOperand(Rs);
CompoundInsn->addOperand(R.getOperand(0));
break;
case Hexagon::C2_cmpeq:
LLVM_DEBUG(dbgs() << "CX: C2_cmpeq\n");
Rs = L.getOperand(1);
Rt = L.getOperand(2);
compoundOpcode = cmpeqBitOpcode[getCompoundOp(R)];
CompoundInsn = Context.createMCInst();
CompoundInsn->setOpcode(compoundOpcode);
CompoundInsn->addOperand(Rs);
CompoundInsn->addOperand(Rt);
CompoundInsn->addOperand(R.getOperand(1));
break;
case Hexagon::C2_cmpgt:
LLVM_DEBUG(dbgs() << "CX: C2_cmpgt\n");
Rs = L.getOperand(1);
Rt = L.getOperand(2);
compoundOpcode = cmpgtBitOpcode[getCompoundOp(R)];
CompoundInsn = Context.createMCInst();
CompoundInsn->setOpcode(compoundOpcode);
CompoundInsn->addOperand(Rs);
CompoundInsn->addOperand(Rt);
CompoundInsn->addOperand(R.getOperand(1));
break;
case Hexagon::C2_cmpgtu:
LLVM_DEBUG(dbgs() << "CX: C2_cmpgtu\n");
Rs = L.getOperand(1);
Rt = L.getOperand(2);
compoundOpcode = cmpgtuBitOpcode[getCompoundOp(R)];
CompoundInsn = Context.createMCInst();
CompoundInsn->setOpcode(compoundOpcode);
CompoundInsn->addOperand(Rs);
CompoundInsn->addOperand(Rt);
CompoundInsn->addOperand(R.getOperand(1));
break;
case Hexagon::C2_cmpeqi:
LLVM_DEBUG(dbgs() << "CX: C2_cmpeqi\n");
Success = L.getOperand(2).getExpr()->evaluateAsAbsolute(Value);
(void)Success;
assert(Success);
if (Value == -1)
compoundOpcode = cmpeqn1BitOpcode[getCompoundOp(R)];
else
compoundOpcode = cmpeqiBitOpcode[getCompoundOp(R)];
Rs = L.getOperand(1);
CompoundInsn = Context.createMCInst();
CompoundInsn->setOpcode(compoundOpcode);
CompoundInsn->addOperand(Rs);
CompoundInsn->addOperand(L.getOperand(2));
CompoundInsn->addOperand(R.getOperand(1));
break;
case Hexagon::C2_cmpgti:
LLVM_DEBUG(dbgs() << "CX: C2_cmpgti\n");
Success = L.getOperand(2).getExpr()->evaluateAsAbsolute(Value);
(void)Success;
assert(Success);
if (Value == -1)
compoundOpcode = cmpgtn1BitOpcode[getCompoundOp(R)];
else
compoundOpcode = cmpgtiBitOpcode[getCompoundOp(R)];
Rs = L.getOperand(1);
CompoundInsn = Context.createMCInst();
CompoundInsn->setOpcode(compoundOpcode);
CompoundInsn->addOperand(Rs);
CompoundInsn->addOperand(L.getOperand(2));
CompoundInsn->addOperand(R.getOperand(1));
break;
case Hexagon::C2_cmpgtui:
LLVM_DEBUG(dbgs() << "CX: C2_cmpgtui\n");
Rs = L.getOperand(1);
compoundOpcode = cmpgtuiBitOpcode[getCompoundOp(R)];
CompoundInsn = Context.createMCInst();
CompoundInsn->setOpcode(compoundOpcode);
CompoundInsn->addOperand(Rs);
CompoundInsn->addOperand(L.getOperand(2));
CompoundInsn->addOperand(R.getOperand(1));
break;
case Hexagon::S2_tstbit_i:
LLVM_DEBUG(dbgs() << "CX: S2_tstbit_i\n");
Rs = L.getOperand(1);
compoundOpcode = tstBitOpcode[getCompoundOp(R)];
CompoundInsn = Context.createMCInst();
CompoundInsn->setOpcode(compoundOpcode);
CompoundInsn->addOperand(Rs);
CompoundInsn->addOperand(R.getOperand(1));
break;
}
return CompoundInsn;
}
static bool isOrderedCompoundPair(MCInst const &MIa, bool IsExtendedA,
MCInst const &MIb, bool IsExtendedB) {
unsigned MIaG = getCompoundCandidateGroup(MIa, IsExtendedA);
unsigned MIbG = getCompoundCandidateGroup(MIb, IsExtendedB);
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()));
}
static 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 (HexagonMCInstrInfo::getType(MCII, *JumpInst) == HexagonII::TypeJ) {
bool BExtended = false;
for (MCInst::iterator B =
MCI.begin() + HexagonMCInstrInfo::bundleInstructionsOffset;
B != MCI.end(); ++B) {
MCInst const *Inst = B->getInst();
if (JumpInst == Inst) {
BExtended = false;
continue;
}
if (HexagonMCInstrInfo::isImmext(*Inst)) {
BExtended = true;
continue;
}
LLVM_DEBUG(dbgs() << "J,B: " << JumpInst->getOpcode() << ","
<< Inst->getOpcode() << "\n");
if (isOrderedCompoundPair(*Inst, BExtended, *JumpInst, JExtended)) {
MCInst *CompoundInsn = getCompoundInsn(Context, *Inst, *JumpInst);
if (CompoundInsn) {
LLVM_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;
}
void HexagonMCInstrInfo::tryCompound(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
MCContext &Context, MCInst &MCI) {
assert(HexagonMCInstrInfo::isBundle(MCI) &&
"Non-Bundle where Bundle expected");
if (MCI.size() < 2)
return;
MCInst CheckList(MCI);
MCInst LastValidBundle(MCI);
bool PreviouslyValid = llvm::HexagonMCShuffle(Context, false, MCII, STI, MCI);
while (lookForCompound(MCII, Context, CheckList)) {
MCI = CheckList;
const bool IsValid = llvm::HexagonMCShuffle(Context, false, MCII, STI, MCI);
if (PreviouslyValid && !IsValid) {
LLVM_DEBUG(dbgs() << "Found ERROR\n");
MCI = LastValidBundle;
} else if (IsValid) {
LastValidBundle = MCI;
PreviouslyValid = true;
}
}
}