mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 02:33:06 +01:00
6a49dbd1a3
This adds a function specialization pass to LLVM. Constant parameters like function pointers and constant globals are propagated to the callee by specializing the function. This is a first version with a number of limitations: - The pass is off by default, so needs to be enabled on the command line, - It does not handle specialization of recursive functions, - It does not yet handle constants and constant ranges, - Only 1 argument per function is specialised, - The cost-model could be further looked into, and perhaps related, - We are not yet caching analysis results. This is based on earlier work by Matthew Simpson (D36432) and Vinay Madhusudan. More recently this was also discussed on the list, see: https://lists.llvm.org/pipermail/llvm-dev/2021-March/149380.html. The motivation for this work is that function specialisation often comes up as a reason for performance differences of generated code between LLVM and GCC, which has this enabled by default from optimisation level -O3 and up. And while this certainly helps a few cpu benchmark cases, this also triggers in real world codes and is thus a generally useful transformation to have in LLVM. Function specialisation has great potential to increase compile-times and code-size. The summary from some investigations with this patch is: - Compile-time increases for short compile jobs is high relatively, but the increase in absolute numbers still low. - For longer compile-jobs, the extra compile time is around 1%, and very much in line with GCC. - It is difficult to blame one thing for compile-time increases: it looks like everywhere a little bit more time is spent processing more functions and instructions. - But the function specialisation pass itself is not very expensive; it doesn't show up very high in the profile of the optimisation passes. The goal of this work is to reach parity with GCC which means that eventually we would like to get this enabled by default. But first we would like to address some of the limitations before that. Differential Revision: https://reviews.llvm.org/D93838
196 lines
7.3 KiB
C++
196 lines
7.3 KiB
C++
//===-- SCCP.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 Interprocedural Sparse Conditional Constant Propagation.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Transforms/IPO/SCCP.h"
|
|
#include "llvm/Analysis/AssumptionCache.h"
|
|
#include "llvm/Analysis/PostDominators.h"
|
|
#include "llvm/Analysis/TargetLibraryInfo.h"
|
|
#include "llvm/Analysis/TargetTransformInfo.h"
|
|
#include "llvm/InitializePasses.h"
|
|
#include "llvm/Transforms/IPO.h"
|
|
#include "llvm/Transforms/Scalar/SCCP.h"
|
|
|
|
using namespace llvm;
|
|
|
|
PreservedAnalyses IPSCCPPass::run(Module &M, ModuleAnalysisManager &AM) {
|
|
const DataLayout &DL = M.getDataLayout();
|
|
auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
|
|
auto GetTLI = [&FAM](Function &F) -> const TargetLibraryInfo & {
|
|
return FAM.getResult<TargetLibraryAnalysis>(F);
|
|
};
|
|
auto getAnalysis = [&FAM](Function &F) -> AnalysisResultsForFn {
|
|
DominatorTree &DT = FAM.getResult<DominatorTreeAnalysis>(F);
|
|
return {
|
|
std::make_unique<PredicateInfo>(F, DT, FAM.getResult<AssumptionAnalysis>(F)),
|
|
&DT, FAM.getCachedResult<PostDominatorTreeAnalysis>(F)};
|
|
};
|
|
|
|
if (!runIPSCCP(M, DL, GetTLI, getAnalysis))
|
|
return PreservedAnalyses::all();
|
|
|
|
PreservedAnalyses PA;
|
|
PA.preserve<DominatorTreeAnalysis>();
|
|
PA.preserve<PostDominatorTreeAnalysis>();
|
|
PA.preserve<FunctionAnalysisManagerModuleProxy>();
|
|
return PA;
|
|
}
|
|
|
|
namespace {
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
//
|
|
/// IPSCCP Class - This class implements interprocedural Sparse Conditional
|
|
/// Constant Propagation.
|
|
///
|
|
class IPSCCPLegacyPass : public ModulePass {
|
|
public:
|
|
static char ID;
|
|
|
|
IPSCCPLegacyPass() : ModulePass(ID) {
|
|
initializeIPSCCPLegacyPassPass(*PassRegistry::getPassRegistry());
|
|
}
|
|
|
|
bool runOnModule(Module &M) override {
|
|
if (skipModule(M))
|
|
return false;
|
|
const DataLayout &DL = M.getDataLayout();
|
|
auto GetTLI = [this](Function &F) -> const TargetLibraryInfo & {
|
|
return this->getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
|
|
};
|
|
auto getAnalysis = [this](Function &F) -> AnalysisResultsForFn {
|
|
DominatorTree &DT =
|
|
this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
|
|
return {
|
|
std::make_unique<PredicateInfo>(
|
|
F, DT,
|
|
this->getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
|
|
F)),
|
|
nullptr, // We cannot preserve the DT or PDT with the legacy pass
|
|
nullptr}; // manager, so set them to nullptr.
|
|
};
|
|
|
|
return runIPSCCP(M, DL, GetTLI, getAnalysis);
|
|
}
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.addRequired<AssumptionCacheTracker>();
|
|
AU.addRequired<DominatorTreeWrapperPass>();
|
|
AU.addRequired<TargetLibraryInfoWrapperPass>();
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
char IPSCCPLegacyPass::ID = 0;
|
|
|
|
INITIALIZE_PASS_BEGIN(IPSCCPLegacyPass, "ipsccp",
|
|
"Interprocedural Sparse Conditional Constant Propagation",
|
|
false, false)
|
|
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
|
|
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
|
|
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
|
|
INITIALIZE_PASS_END(IPSCCPLegacyPass, "ipsccp",
|
|
"Interprocedural Sparse Conditional Constant Propagation",
|
|
false, false)
|
|
|
|
// createIPSCCPPass - This is the public interface to this file.
|
|
ModulePass *llvm::createIPSCCPPass() { return new IPSCCPLegacyPass(); }
|
|
|
|
PreservedAnalyses FunctionSpecializationPass::run(Module &M,
|
|
ModuleAnalysisManager &AM) {
|
|
const DataLayout &DL = M.getDataLayout();
|
|
auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
|
|
auto GetTLI = [&FAM](Function &F) -> TargetLibraryInfo & {
|
|
return FAM.getResult<TargetLibraryAnalysis>(F);
|
|
};
|
|
auto GetTTI = [&FAM](Function &F) -> TargetTransformInfo & {
|
|
return FAM.getResult<TargetIRAnalysis>(F);
|
|
};
|
|
auto GetAC = [&FAM](Function &F) -> AssumptionCache & {
|
|
return FAM.getResult<AssumptionAnalysis>(F);
|
|
};
|
|
auto GetAnalysis = [&FAM](Function &F) -> AnalysisResultsForFn {
|
|
DominatorTree &DT = FAM.getResult<DominatorTreeAnalysis>(F);
|
|
return {std::make_unique<PredicateInfo>(
|
|
F, DT, FAM.getResult<AssumptionAnalysis>(F)),
|
|
&DT, FAM.getCachedResult<PostDominatorTreeAnalysis>(F)};
|
|
};
|
|
|
|
if (!runFunctionSpecialization(M, DL, GetTLI, GetTTI, GetAC, GetAnalysis))
|
|
return PreservedAnalyses::all();
|
|
|
|
PreservedAnalyses PA;
|
|
PA.preserve<DominatorTreeAnalysis>();
|
|
PA.preserve<PostDominatorTreeAnalysis>();
|
|
PA.preserve<FunctionAnalysisManagerModuleProxy>();
|
|
return PA;
|
|
}
|
|
|
|
struct FunctionSpecializationLegacyPass : public ModulePass {
|
|
static char ID; // Pass identification, replacement for typeid
|
|
FunctionSpecializationLegacyPass() : ModulePass(ID) {}
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.addRequired<AssumptionCacheTracker>();
|
|
AU.addRequired<DominatorTreeWrapperPass>();
|
|
AU.addRequired<TargetLibraryInfoWrapperPass>();
|
|
AU.addRequired<TargetTransformInfoWrapperPass>();
|
|
}
|
|
|
|
virtual bool runOnModule(Module &M) override {
|
|
if (skipModule(M))
|
|
return false;
|
|
|
|
const DataLayout &DL = M.getDataLayout();
|
|
auto GetTLI = [this](Function &F) -> TargetLibraryInfo & {
|
|
return this->getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
|
|
};
|
|
auto GetTTI = [this](Function &F) -> TargetTransformInfo & {
|
|
return this->getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
|
|
};
|
|
auto GetAC = [this](Function &F) -> AssumptionCache & {
|
|
return this->getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
|
|
};
|
|
|
|
auto GetAnalysis = [this](Function &F) -> AnalysisResultsForFn {
|
|
DominatorTree &DT =
|
|
this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
|
|
return {
|
|
std::make_unique<PredicateInfo>(
|
|
F, DT,
|
|
this->getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
|
|
F)),
|
|
nullptr, // We cannot preserve the DT or PDT with the legacy pass
|
|
nullptr}; // manager, so set them to nullptr.
|
|
};
|
|
return runFunctionSpecialization(M, DL, GetTLI, GetTTI, GetAC, GetAnalysis);
|
|
}
|
|
};
|
|
|
|
char FunctionSpecializationLegacyPass::ID = 0;
|
|
|
|
INITIALIZE_PASS_BEGIN(
|
|
FunctionSpecializationLegacyPass, "function-specialization",
|
|
"Propagate constant arguments by specializing the function", false, false)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
|
|
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
|
|
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
|
|
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
|
|
INITIALIZE_PASS_END(FunctionSpecializationLegacyPass, "function-specialization",
|
|
"Propagate constant arguments by specializing the function",
|
|
false, false)
|
|
|
|
ModulePass *llvm::createFunctionSpecializationPass() {
|
|
return new FunctionSpecializationLegacyPass();
|
|
}
|