blob: 97259649ab858d9b407b9d30adb8092cf10e6987 [file] [log] [blame]
//===- ReduceRegisterDefs.cpp - Specialized Delta Pass --------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements a function which calls the Generic Delta pass in order
// to reduce uninteresting register uses from the MachineFunction.
//
//===----------------------------------------------------------------------===//
#include "ReduceRegisterDefs.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
using namespace llvm;
static void removeDefsFromFunction(Oracle &O, MachineFunction &MF) {
MachineRegisterInfo &MRI = MF.getRegInfo();
const TargetSubtargetInfo &STI = MF.getSubtarget();
const TargetInstrInfo *TII = STI.getInstrInfo();
DenseSet<MachineOperand *> KeepDefs;
DenseSet<TargetInstrInfo::RegSubRegPair> DeleteDefs;
for (MachineBasicBlock &MBB : MF) {
for (MachineBasicBlock::iterator It = MBB.begin(),
E = MBB.getFirstTerminator();
It != E;) {
MachineBasicBlock::iterator InsPt = It;
MachineInstr &MI = *It;
++It;
KeepDefs.clear();
DeleteDefs.clear();
int NumOperands = MI.getNumOperands();
int NumRequiredOps = MI.getNumExplicitOperands() +
MI.getDesc().implicit_defs().size() +
MI.getDesc().implicit_uses().size();
bool HaveDelete = false;
// Do an initial scan in case the instruction defines the same register
// multiple times.
for (int I = NumOperands - 1; I >= 0; --I) {
MachineOperand &MO = MI.getOperand(I);
if (!MO.isReg() || !MO.isDef())
continue;
TargetInstrInfo::RegSubRegPair RegPair(MO.getReg(), MO.getSubReg());
if (!RegPair.Reg.isVirtual())
continue;
if (O.shouldKeep())
KeepDefs.insert(&MO);
else
HaveDelete = true;
}
if (!HaveDelete)
continue;
bool HaveKeptDef = !KeepDefs.empty();
for (int I = NumOperands - 1; I >= 0; --I) {
MachineOperand &MO = MI.getOperand(I);
if (!MO.isReg() || !MO.isDef())
continue;
if (KeepDefs.count(&MO))
continue;
TargetInstrInfo::RegSubRegPair RegPair(MO.getReg(), MO.getSubReg());
if (!RegPair.Reg.isVirtual())
continue;
if (!DeleteDefs.insert(RegPair).second)
continue;
if (MRI.use_empty(RegPair.Reg)) {
if (I >= NumRequiredOps) {
// Delete implicit def operands that aren't part of the instruction
// definition
MI.removeOperand(I);
}
continue;
}
// If we aren't going to delete the instruction, replace it with a dead
// def.
if (HaveKeptDef)
MO.setReg(MRI.cloneVirtualRegister(MO.getReg()));
bool IsGeneric = MRI.getRegClassOrNull(RegPair.Reg) == nullptr;
unsigned ImpDef = IsGeneric ? TargetOpcode::G_IMPLICIT_DEF
: TargetOpcode::IMPLICIT_DEF;
unsigned OpFlags = getRegState(MO) & ~RegState::Implicit;
InsPt = BuildMI(MBB, InsPt, DebugLoc(), TII->get(ImpDef))
.addReg(RegPair.Reg, OpFlags, RegPair.SubReg);
}
if (!HaveKeptDef)
MI.eraseFromParent();
}
}
}
static void removeDefsFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
for (const Function &F : WorkItem.getModule()) {
if (auto *MF = WorkItem.MMI->getMachineFunction(F))
removeDefsFromFunction(O, *MF);
}
}
void llvm::reduceRegisterDefsMIRDeltaPass(TestRunner &Test) {
runDeltaPass(Test, removeDefsFromModule, "Reducing register defs");
}