2014-05-24 12:50:23 +00:00
|
|
|
//==-- AArch64DeadRegisterDefinitions.cpp - Replace dead defs w/ zero reg --==//
|
2014-03-29 10:18:08 +00:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// When allowed by the instruction, replace a dead definition of a GPR with
|
|
|
|
// the zero register. This makes the code a bit friendlier towards the
|
|
|
|
// hardware's register renamer.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2014-05-24 12:50:23 +00:00
|
|
|
#include "AArch64.h"
|
|
|
|
#include "AArch64RegisterInfo.h"
|
2014-03-29 10:18:08 +00:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
2014-07-25 11:42:14 +00:00
|
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
2014-03-29 10:18:08 +00:00
|
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2014-08-04 21:25:23 +00:00
|
|
|
#include "llvm/Target/TargetSubtargetInfo.h"
|
2014-03-29 10:18:08 +00:00
|
|
|
using namespace llvm;
|
|
|
|
|
2014-05-24 12:50:23 +00:00
|
|
|
#define DEBUG_TYPE "aarch64-dead-defs"
|
2014-04-22 02:41:26 +00:00
|
|
|
|
2014-03-29 10:18:08 +00:00
|
|
|
STATISTIC(NumDeadDefsReplaced, "Number of dead definitions replaced");
|
|
|
|
|
|
|
|
namespace {
|
2014-05-24 12:50:23 +00:00
|
|
|
class AArch64DeadRegisterDefinitions : public MachineFunctionPass {
|
2014-03-29 10:18:08 +00:00
|
|
|
private:
|
2014-04-03 20:51:08 +00:00
|
|
|
const TargetRegisterInfo *TRI;
|
2014-04-16 11:52:51 +00:00
|
|
|
bool implicitlyDefinesOverlappingReg(unsigned Reg, const MachineInstr &MI);
|
2014-04-15 02:14:09 +00:00
|
|
|
bool processMachineBasicBlock(MachineBasicBlock &MBB);
|
|
|
|
bool usesFrameIndex(const MachineInstr &MI);
|
2014-03-29 10:18:08 +00:00
|
|
|
public:
|
|
|
|
static char ID; // Pass identification, replacement for typeid.
|
2014-05-24 12:50:23 +00:00
|
|
|
explicit AArch64DeadRegisterDefinitions() : MachineFunctionPass(ID) {}
|
2014-03-29 10:18:08 +00:00
|
|
|
|
2014-08-30 16:48:34 +00:00
|
|
|
bool runOnMachineFunction(MachineFunction &F) override;
|
2014-03-29 10:18:08 +00:00
|
|
|
|
2014-04-29 07:58:25 +00:00
|
|
|
const char *getPassName() const override { return "Dead register definitions"; }
|
2014-03-29 10:18:08 +00:00
|
|
|
|
2014-08-30 16:48:34 +00:00
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
2014-03-29 10:18:08 +00:00
|
|
|
AU.setPreservesCFG();
|
|
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
|
|
}
|
|
|
|
};
|
2014-05-24 12:50:23 +00:00
|
|
|
char AArch64DeadRegisterDefinitions::ID = 0;
|
2014-03-29 10:18:08 +00:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
2014-05-24 12:50:23 +00:00
|
|
|
bool AArch64DeadRegisterDefinitions::implicitlyDefinesOverlappingReg(
|
2014-04-16 11:52:51 +00:00
|
|
|
unsigned Reg, const MachineInstr &MI) {
|
2014-04-15 02:14:09 +00:00
|
|
|
for (const MachineOperand &MO : MI.implicit_operands())
|
2014-04-03 20:51:08 +00:00
|
|
|
if (MO.isReg() && MO.isDef())
|
2014-04-16 11:52:51 +00:00
|
|
|
if (TRI->regsOverlap(Reg, MO.getReg()))
|
2014-04-03 20:51:08 +00:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-05-24 12:50:23 +00:00
|
|
|
bool AArch64DeadRegisterDefinitions::usesFrameIndex(const MachineInstr &MI) {
|
2014-04-15 02:14:09 +00:00
|
|
|
for (const MachineOperand &Op : MI.uses())
|
|
|
|
if (Op.isFI())
|
2014-04-14 21:05:05 +00:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-05-24 12:50:23 +00:00
|
|
|
bool AArch64DeadRegisterDefinitions::processMachineBasicBlock(
|
|
|
|
MachineBasicBlock &MBB) {
|
2014-03-29 10:18:08 +00:00
|
|
|
bool Changed = false;
|
2014-04-15 02:14:09 +00:00
|
|
|
for (MachineInstr &MI : MBB) {
|
2014-04-14 21:05:05 +00:00
|
|
|
if (usesFrameIndex(MI)) {
|
|
|
|
// We need to skip this instruction because while it appears to have a
|
|
|
|
// dead def it uses a frame index which might expand into a multi
|
2014-04-15 02:14:09 +00:00
|
|
|
// instruction sequence during EPI.
|
2014-04-14 21:05:05 +00:00
|
|
|
DEBUG(dbgs() << " Ignoring, operand is frame index\n");
|
|
|
|
continue;
|
|
|
|
}
|
2014-04-15 02:14:09 +00:00
|
|
|
for (int i = 0, e = MI.getDesc().getNumDefs(); i != e; ++i) {
|
|
|
|
MachineOperand &MO = MI.getOperand(i);
|
2014-03-29 10:18:08 +00:00
|
|
|
if (MO.isReg() && MO.isDead() && MO.isDef()) {
|
|
|
|
assert(!MO.isImplicit() && "Unexpected implicit def!");
|
|
|
|
DEBUG(dbgs() << " Dead def operand #" << i << " in:\n ";
|
2014-04-15 02:14:09 +00:00
|
|
|
MI.print(dbgs()));
|
2014-03-29 10:18:08 +00:00
|
|
|
// Be careful not to change the register if it's a tied operand.
|
2014-04-15 02:14:09 +00:00
|
|
|
if (MI.isRegTiedToUseOperand(i)) {
|
2014-03-29 10:18:08 +00:00
|
|
|
DEBUG(dbgs() << " Ignoring, def is tied operand.\n");
|
|
|
|
continue;
|
|
|
|
}
|
2014-04-16 11:52:51 +00:00
|
|
|
// Don't change the register if there's an implicit def of a subreg or
|
|
|
|
// supperreg.
|
|
|
|
if (implicitlyDefinesOverlappingReg(MO.getReg(), MI)) {
|
|
|
|
DEBUG(dbgs() << " Ignoring, implicitly defines overlap reg.\n");
|
2014-04-03 20:51:08 +00:00
|
|
|
continue;
|
|
|
|
}
|
2014-03-29 10:18:08 +00:00
|
|
|
// Make sure the instruction take a register class that contains
|
|
|
|
// the zero register and replace it if so.
|
|
|
|
unsigned NewReg;
|
2014-04-15 02:14:09 +00:00
|
|
|
switch (MI.getDesc().OpInfo[i].RegClass) {
|
2014-03-29 10:18:08 +00:00
|
|
|
default:
|
|
|
|
DEBUG(dbgs() << " Ignoring, register is not a GPR.\n");
|
|
|
|
continue;
|
2014-05-24 12:50:23 +00:00
|
|
|
case AArch64::GPR32RegClassID:
|
|
|
|
NewReg = AArch64::WZR;
|
2014-03-29 10:18:08 +00:00
|
|
|
break;
|
2014-05-24 12:50:23 +00:00
|
|
|
case AArch64::GPR64RegClassID:
|
|
|
|
NewReg = AArch64::XZR;
|
2014-03-29 10:18:08 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
DEBUG(dbgs() << " Replacing with zero register. New:\n ");
|
|
|
|
MO.setReg(NewReg);
|
2014-04-15 02:14:09 +00:00
|
|
|
DEBUG(MI.print(dbgs()));
|
2014-03-29 10:18:08 +00:00
|
|
|
++NumDeadDefsReplaced;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Scan the function for instructions that have a dead definition of a
|
|
|
|
// register. Replace that register with the zero register when possible.
|
2014-05-24 12:50:23 +00:00
|
|
|
bool AArch64DeadRegisterDefinitions::runOnMachineFunction(MachineFunction &MF) {
|
2014-08-05 02:39:49 +00:00
|
|
|
TRI = MF.getSubtarget().getRegisterInfo();
|
2014-03-29 10:18:08 +00:00
|
|
|
bool Changed = false;
|
2014-05-24 12:50:23 +00:00
|
|
|
DEBUG(dbgs() << "***** AArch64DeadRegisterDefinitions *****\n");
|
2014-03-29 10:18:08 +00:00
|
|
|
|
2014-04-15 02:14:09 +00:00
|
|
|
for (auto &MBB : MF)
|
|
|
|
if (processMachineBasicBlock(MBB))
|
2014-03-29 10:18:08 +00:00
|
|
|
Changed = true;
|
|
|
|
return Changed;
|
|
|
|
}
|
|
|
|
|
2014-05-24 12:50:23 +00:00
|
|
|
FunctionPass *llvm::createAArch64DeadRegisterDefinitions() {
|
|
|
|
return new AArch64DeadRegisterDefinitions();
|
2014-03-29 10:18:08 +00:00
|
|
|
}
|