Files
llvm/bolt/lib/Passes/AllocCombiner.cpp
Rafael Auler 42465efd17 [BOLT] Increase coverage of shrink wrapping [1/5]
Change how function score is calculated and provide more
detailed statistics when reporting back frame optimizer and shrink
wrapping results. In this new statistics, we provide dynamic coverage
numbers. The main metric for shrink wrapping is the number of executed
stores that were saved because of shrink wrapping (push instructions
that were either entirely moved away from the hot block or converted
to a stack adjustment instruction). There is still a number of reduced
load instructions (pop) that we are not counting at the moment. Also
update alloc combiner to report dynamic numbers, as well as frame
optimizer.

For debugging purposes, we also include a list of top 10 functions
optimized by shrink wrapping. These changes are aimed at better
understanding the impact of shrink wrapping in a given binary.

We also remove an assertion in dataflow analysis to do not choke on
empty functions (which makes no sense).

Reviewed By: Amir

Differential Revision: https://reviews.llvm.org/D126111
2022-07-11 17:29:22 -07:00

126 lines
3.5 KiB
C++

//===- bolt/Passes/AllocCombiner.cpp --------------------------------------===//
//
// 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 the AllocCombinerPass class.
//
//===----------------------------------------------------------------------===//
#include "bolt/Passes/AllocCombiner.h"
#define DEBUG_TYPE "alloccombiner"
using namespace llvm;
namespace opts {
extern cl::opt<bolt::FrameOptimizationType> FrameOptimization;
} // end namespace opts
namespace llvm {
namespace bolt {
namespace {
bool getStackAdjustmentSize(const BinaryContext &BC, const MCInst &Inst,
int64_t &Adjustment) {
return BC.MIB->evaluateStackOffsetExpr(
Inst, Adjustment, std::make_pair(BC.MIB->getStackPointer(), 0LL),
std::make_pair(0, 0LL));
}
bool isIndifferentToSP(const MCInst &Inst, const BinaryContext &BC) {
if (BC.MIB->isCFI(Inst))
return true;
const MCInstrDesc II = BC.MII->get(Inst.getOpcode());
if (BC.MIB->isTerminator(Inst) ||
II.hasImplicitDefOfPhysReg(BC.MIB->getStackPointer(), BC.MRI.get()) ||
II.hasImplicitUseOfPhysReg(BC.MIB->getStackPointer()))
return false;
for (const MCOperand &Operand : MCPlus::primeOperands(Inst))
if (Operand.isReg() && Operand.getReg() == BC.MIB->getStackPointer())
return false;
return true;
}
bool shouldProcess(const BinaryFunction &Function) {
return Function.isSimple() && Function.hasCFG() && !Function.isIgnored();
}
void runForAllWeCare(std::map<uint64_t, BinaryFunction> &BFs,
std::function<void(BinaryFunction &)> Task) {
for (auto &It : BFs) {
BinaryFunction &Function = It.second;
if (shouldProcess(Function))
Task(Function);
}
}
} // end anonymous namespace
void AllocCombinerPass::combineAdjustments(BinaryFunction &BF) {
BinaryContext &BC = BF.getBinaryContext();
for (BinaryBasicBlock &BB : BF) {
MCInst *Prev = nullptr;
for (auto I = BB.rbegin(), E = BB.rend(); I != E; ++I) {
MCInst &Inst = *I;
if (isIndifferentToSP(Inst, BC))
continue; // Skip updating Prev
int64_t Adjustment = 0LL;
if (!Prev || !BC.MIB->isStackAdjustment(Inst) ||
!BC.MIB->isStackAdjustment(*Prev) ||
!getStackAdjustmentSize(BC, *Prev, Adjustment)) {
Prev = &Inst;
continue;
}
LLVM_DEBUG({
dbgs() << "At \"" << BF.getPrintName() << "\", combining: \n";
Inst.dump();
Prev->dump();
dbgs() << "Adjustment: " << Adjustment << "\n";
});
if (BC.MIB->isSUB(Inst))
Adjustment = -Adjustment;
BC.MIB->addToImm(Inst, Adjustment, BC.Ctx.get());
LLVM_DEBUG({
dbgs() << "After adjustment:\n";
Inst.dump();
});
BB.eraseInstruction(BB.findInstruction(Prev));
++NumCombined;
DynamicCountCombined += BB.getKnownExecutionCount();
FuncsChanged.insert(&BF);
Prev = &Inst;
}
}
}
void AllocCombinerPass::runOnFunctions(BinaryContext &BC) {
if (opts::FrameOptimization == FOP_NONE)
return;
runForAllWeCare(BC.getBinaryFunctions(), [&](BinaryFunction &Function) {
combineAdjustments(Function);
});
outs() << "BOLT-INFO: Allocation combiner: " << NumCombined
<< " empty spaces coalesced (dyn count: " << DynamicCountCombined
<< ").\n";
}
} // end namespace bolt
} // end namespace llvm