HexagonFixupHwLoops.cpp [plain text]
#include "llvm/ADT/DenseMap.h"
#include "Hexagon.h"
#include "HexagonTargetMachine.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/PassSupport.h"
#include "llvm/Target/TargetInstrInfo.h"
using namespace llvm;
static cl::opt<unsigned> MaxLoopRange(
"hexagon-loop-range", cl::Hidden, cl::init(200),
cl::desc("Restrict range of loopN instructions (testing only)"));
namespace llvm {
FunctionPass *createHexagonFixupHwLoops();
void initializeHexagonFixupHwLoopsPass(PassRegistry&);
}
namespace {
struct HexagonFixupHwLoops : public MachineFunctionPass {
public:
static char ID;
HexagonFixupHwLoops() : MachineFunctionPass(ID) {
initializeHexagonFixupHwLoopsPass(*PassRegistry::getPassRegistry());
}
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
return "Hexagon Hardware Loop Fixup";
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
MachineFunctionPass::getAnalysisUsage(AU);
}
private:
bool fixupLoopInstrs(MachineFunction &MF);
void useExtLoopInstr(MachineFunction &MF,
MachineBasicBlock::iterator &MII);
};
char HexagonFixupHwLoops::ID = 0;
}
INITIALIZE_PASS(HexagonFixupHwLoops, "hwloopsfixup",
"Hexagon Hardware Loops Fixup", false, false)
FunctionPass *llvm::createHexagonFixupHwLoops() {
return new HexagonFixupHwLoops();
}
static bool isHardwareLoop(const MachineInstr *MI) {
return MI->getOpcode() == Hexagon::J2_loop0r ||
MI->getOpcode() == Hexagon::J2_loop0i ||
MI->getOpcode() == Hexagon::J2_loop1r ||
MI->getOpcode() == Hexagon::J2_loop1i;
}
bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) {
return fixupLoopInstrs(MF);
}
bool HexagonFixupHwLoops::fixupLoopInstrs(MachineFunction &MF) {
unsigned InstOffset = 0;
DenseMap<const MachineBasicBlock *, unsigned> BlockToInstOffset;
const HexagonInstrInfo *HII =
static_cast<const HexagonInstrInfo *>(MF.getSubtarget().getInstrInfo());
for (const MachineBasicBlock &MBB : MF) {
if (MBB.getAlignment()) {
int ByteAlign = (1u << MBB.getAlignment()) - 1;
InstOffset = (InstOffset + ByteAlign) & ~(ByteAlign);
}
BlockToInstOffset[&MBB] = InstOffset;
for (const MachineInstr &MI : MBB)
InstOffset += HII->getSize(&MI);
}
InstOffset = 0;
bool Changed = false;
for (MachineBasicBlock &MBB : MF) {
InstOffset = BlockToInstOffset[&MBB];
MachineBasicBlock::iterator MII = MBB.begin();
MachineBasicBlock::iterator MIE = MBB.end();
while (MII != MIE) {
InstOffset += HII->getSize(&*MII);
if (MII->isDebugValue()) {
++MII;
continue;
}
if (isHardwareLoop(MII)) {
assert(MII->getOperand(0).isMBB() &&
"Expect a basic block as loop operand");
int diff = InstOffset - BlockToInstOffset[MII->getOperand(0).getMBB()];
if ((unsigned)abs(diff) > MaxLoopRange) {
useExtLoopInstr(MF, MII);
MII = MBB.erase(MII);
Changed = true;
} else {
++MII;
}
} else {
++MII;
}
}
}
return Changed;
}
void HexagonFixupHwLoops::useExtLoopInstr(MachineFunction &MF,
MachineBasicBlock::iterator &MII) {
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
MachineBasicBlock *MBB = MII->getParent();
DebugLoc DL = MII->getDebugLoc();
MachineInstrBuilder MIB;
unsigned newOp;
switch (MII->getOpcode()) {
case Hexagon::J2_loop0r:
newOp = Hexagon::J2_loop0rext;
break;
case Hexagon::J2_loop0i:
newOp = Hexagon::J2_loop0iext;
break;
case Hexagon::J2_loop1r:
newOp = Hexagon::J2_loop1rext;
break;
case Hexagon::J2_loop1i:
newOp = Hexagon::J2_loop1iext;
break;
default:
llvm_unreachable("Invalid Hardware Loop Instruction.");
}
MIB = BuildMI(*MBB, MII, DL, TII->get(newOp));
for (unsigned i = 0; i < MII->getNumOperands(); ++i)
MIB.addOperand(MII->getOperand(i));
}