1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
//===---- RemoveLoadsIntoFakeUses.cpp - Remove loads with no real uses ----===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// The FAKE_USE instruction is used to preserve certain values through
/// optimizations for the sake of debugging. This may result in spilled values
/// being loaded into registers that are only used by FAKE_USEs; this is not
/// necessary for debugging purposes, because at that point the value must be on
/// the stack and hence available for debugging. Therefore, this pass removes
/// loads that are only used by FAKE_USEs.
///
/// This pass should run very late, to ensure that we don't inadvertently
/// shorten stack lifetimes by removing these loads, since the FAKE_USEs will
/// also no longer be in effect. Running immediately before LiveDebugValues
/// ensures that LDV will have accurate information of the machine location of
/// debug values.
///
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/RemoveLoadsIntoFakeUses.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/LiveRegUnits.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachinePassManager.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm;
#define DEBUG_TYPE "remove-loads-into-fake-uses"
STATISTIC(NumLoadsDeleted, "Number of dead load instructions deleted");
STATISTIC(NumFakeUsesDeleted, "Number of FAKE_USE instructions deleted");
class RemoveLoadsIntoFakeUsesLegacy : public MachineFunctionPass {
public:
static char ID;
RemoveLoadsIntoFakeUsesLegacy() : MachineFunctionPass(ID) {
initializeRemoveLoadsIntoFakeUsesLegacyPass(
*PassRegistry::getPassRegistry());
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
MachineFunctionPass::getAnalysisUsage(AU);
}
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().setNoVRegs();
}
StringRef getPassName() const override {
return "Remove Loads Into Fake Uses";
}
bool runOnMachineFunction(MachineFunction &MF) override;
};
struct RemoveLoadsIntoFakeUses {
bool run(MachineFunction &MF);
};
char RemoveLoadsIntoFakeUsesLegacy::ID = 0;
char &llvm::RemoveLoadsIntoFakeUsesID = RemoveLoadsIntoFakeUsesLegacy::ID;
INITIALIZE_PASS_BEGIN(RemoveLoadsIntoFakeUsesLegacy, DEBUG_TYPE,
"Remove Loads Into Fake Uses", false, false)
INITIALIZE_PASS_END(RemoveLoadsIntoFakeUsesLegacy, DEBUG_TYPE,
"Remove Loads Into Fake Uses", false, false)
bool RemoveLoadsIntoFakeUsesLegacy::runOnMachineFunction(MachineFunction &MF) {
if (skipFunction(MF.getFunction()))
return false;
return RemoveLoadsIntoFakeUses().run(MF);
}
PreservedAnalyses
RemoveLoadsIntoFakeUsesPass::run(MachineFunction &MF,
MachineFunctionAnalysisManager &MFAM) {
MFPropsModifier _(*this, MF);
if (!RemoveLoadsIntoFakeUses().run(MF))
return PreservedAnalyses::all();
auto PA = getMachineFunctionPassPreservedAnalyses();
PA.preserveSet<CFGAnalyses>();
return PA;
}
bool RemoveLoadsIntoFakeUses::run(MachineFunction &MF) {
// Skip this pass if we would use VarLoc-based LDV, as there may be DBG_VALUE
// instructions of the restored values that would become invalid.
if (!MF.useDebugInstrRef())
return false;
// Only run this for functions that have fake uses.
if (!MF.hasFakeUses())
return false;
bool AnyChanges = false;
LiveRegUnits LivePhysRegs;
const MachineRegisterInfo *MRI = &MF.getRegInfo();
const TargetSubtargetInfo &ST = MF.getSubtarget();
const TargetInstrInfo *TII = ST.getInstrInfo();
const TargetRegisterInfo *TRI = ST.getRegisterInfo();
SmallVector<MachineInstr *> RegFakeUses;
LivePhysRegs.init(*TRI);
for (MachineBasicBlock *MBB : post_order(&MF)) {
RegFakeUses.clear();
LivePhysRegs.addLiveOuts(*MBB);
for (MachineInstr &MI : make_early_inc_range(reverse(*MBB))) {
if (MI.isFakeUse()) {
if (MI.getNumOperands() == 0 || !MI.getOperand(0).isReg())
continue;
// Track the Fake Uses that use these register units so that we can
// delete them if we delete the corresponding load.
RegFakeUses.push_back(&MI);
// Do not record FAKE_USE uses in LivePhysRegs so that we can recognize
// otherwise-unused loads.
continue;
}
// If the restore size is not std::nullopt then we are dealing with a
// reload of a spilled register.
if (MI.getRestoreSize(TII)) {
Register Reg = MI.getOperand(0).getReg();
// Don't delete live physreg defs, or any reserved register defs.
if (!LivePhysRegs.available(Reg) || MRI->isReserved(Reg))
continue;
// There should typically be an exact match between the loaded register
// and the FAKE_USE, but sometimes regalloc will choose to load a larger
// value than is needed. Therefore, as long as the load isn't used by
// anything except at least one FAKE_USE, we will delete it. If it isn't
// used by any fake uses, it should still be safe to delete but we
// choose to ignore it so that this pass has no side effects unrelated
// to fake uses.
SmallDenseSet<MachineInstr *> FakeUsesToDelete;
for (MachineInstr *&FakeUse : reverse(RegFakeUses)) {
if (FakeUse->readsRegister(Reg, TRI)) {
FakeUsesToDelete.insert(FakeUse);
RegFakeUses.erase(&FakeUse);
}
}
if (!FakeUsesToDelete.empty()) {
LLVM_DEBUG(dbgs() << "RemoveLoadsIntoFakeUses: DELETING: " << MI);
// Since this load only exists to restore a spilled register and we
// haven't, run LiveDebugValues yet, there shouldn't be any DBG_VALUEs
// for this load; otherwise, deleting this would be incorrect.
MI.eraseFromParent();
AnyChanges = true;
++NumLoadsDeleted;
for (MachineInstr *FakeUse : FakeUsesToDelete) {
LLVM_DEBUG(dbgs()
<< "RemoveLoadsIntoFakeUses: DELETING: " << *FakeUse);
FakeUse->eraseFromParent();
}
NumFakeUsesDeleted += FakeUsesToDelete.size();
}
continue;
}
// In addition to tracking LivePhysRegs, we need to clear RegFakeUses each
// time a register is defined, as existing FAKE_USEs no longer apply to
// that register.
if (!RegFakeUses.empty()) {
for (const MachineOperand &MO : MI.operands()) {
if (!MO.isReg())
continue;
Register Reg = MO.getReg();
// We clear RegFakeUses for this register and all subregisters,
// because any such FAKE_USE encountered prior is no longer relevant
// for later encountered loads.
for (MachineInstr *&FakeUse : reverse(RegFakeUses))
if (FakeUse->readsRegister(Reg, TRI))
RegFakeUses.erase(&FakeUse);
}
}
LivePhysRegs.stepBackward(MI);
}
}
return AnyChanges;
}
|