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/CodeGen/RegisterScavenging.h"
#include "llvm/PassSupport.h"
#include "llvm/Target/TargetInstrInfo.h"
using namespace llvm;
namespace llvm {
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:
static const unsigned MAX_LOOP_DISTANCE = 200;
bool fixupLoopInstrs(MachineFunction &MF);
void convertLoopInstr(MachineFunction &MF,
MachineBasicBlock::iterator &MII,
RegScavenger &RS);
};
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;
}
bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) {
bool Changed = fixupLoopInstrs(MF);
return Changed;
}
bool HexagonFixupHwLoops::fixupLoopInstrs(MachineFunction &MF) {
unsigned InstOffset = 0;
DenseMap<MachineBasicBlock*, unsigned> BlockToInstOffset;
for (MachineFunction::iterator MBB = MF.begin(), MBBe = MF.end();
MBB != MBBe; ++MBB) {
BlockToInstOffset[MBB] = InstOffset;
InstOffset += (MBB->size() * 4);
}
InstOffset = 0;
bool Changed = false;
RegScavenger RS;
for (MachineFunction::iterator MBB = MF.begin(), MBBe = MF.end();
MBB != MBBe; ++MBB) {
InstOffset = BlockToInstOffset[MBB];
RS.enterBasicBlock(MBB);
MachineBasicBlock::iterator MIE = MBB->end();
MachineBasicBlock::iterator MII = MBB->begin();
while (MII != MIE) {
if (isHardwareLoop(MII)) {
RS.forward(MII);
assert(MII->getOperand(0).isMBB() &&
"Expect a basic block as loop operand");
int Sub = InstOffset - BlockToInstOffset[MII->getOperand(0).getMBB()];
unsigned Dist = Sub > 0 ? Sub : -Sub;
if (Dist > MAX_LOOP_DISTANCE) {
convertLoopInstr(MF, MII, RS);
MII = MBB->erase(MII);
Changed = true;
} else {
++MII;
}
} else {
++MII;
}
InstOffset += 4;
}
}
return Changed;
}
void HexagonFixupHwLoops::convertLoopInstr(MachineFunction &MF,
MachineBasicBlock::iterator &MII,
RegScavenger &RS) {
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
MachineBasicBlock *MBB = MII->getParent();
DebugLoc DL = MII->getDebugLoc();
unsigned Scratch = RS.scavengeRegister(&Hexagon::IntRegsRegClass, MII, 0);
if (MII->getOperand(1).isReg()) {
BuildMI(*MBB, MII, DL, TII->get(Hexagon::A2_tfrrcr), Hexagon::LC0)
.addReg(MII->getOperand(1).getReg());
} else {
BuildMI(*MBB, MII, DL, TII->get(Hexagon::A2_tfrsi), Scratch)
.addImm(MII->getOperand(1).getImm());
BuildMI(*MBB, MII, DL, TII->get(Hexagon::A2_tfrrcr), Hexagon::LC0)
.addReg(Scratch);
}
BuildMI(*MBB, MII, DL, TII->get(Hexagon::CONST32_Label), Scratch)
.addMBB(MII->getOperand(0).getMBB());
BuildMI(*MBB, MII, DL, TII->get(Hexagon::A2_tfrrcr), Hexagon::SA0)
.addReg(Scratch);
}