Files
swift-mirror/tools/swift-llvm-opt/LLVMOpt.cpp
Erik Eckstein f0022a5aac Add an LLVM pass to merge similar functions.
It's like LLVM's MergeFunctions pass, except that it can also merge functions which differ by some constants.
The intention is to merge specialized functions which only differ by metadata lookups. But it can also merge other types of functions.
It gives ~7% code size reducation for the stdlib.

There are still some open TODOs, e.g. to share common code with LLVM's MergeFunctions pass (currently much code is just copied).
2016-05-11 09:46:46 -07:00

312 lines
11 KiB
C++

//===--- LLVMOpt.cpp ------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// This is a simple reimplementation of opt that includes support for Swift-
/// specific LLVM passes. It is meant to make it easier to handle issues related
/// to transitioning to the new LLVM pass manager (which lacks the dynamism of
/// the old pass manager) and also problems during the code base transition to
/// that pass manager. Additionally it will enable a user to exactly simulate
/// Swift's LLVM pass pipeline by using the same pass pipeline building
/// machinery in IRGen, something not possible with opt.
///
//===----------------------------------------------------------------------===//
#include "swift/Subsystems.h"
#include "swift/Basic/LLVMInitialize.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/LLVMPasses/PassesFwd.h"
#include "swift/LLVMPasses/Passes.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/CallGraphSCCPass.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/RegionPass.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/CodeGen/CommandFlags.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/LegacyPassNameParser.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/InitializePasses.h"
#include "llvm/LinkAllIR.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/SystemUtils.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
using namespace swift;
//===----------------------------------------------------------------------===//
// Option Declarations
//===----------------------------------------------------------------------===//
// The OptimizationList is automatically populated with registered passes by the
// PassNameParser.
//
static llvm::cl::list<const llvm::PassInfo *, bool, llvm::PassNameParser>
PassList(llvm::cl::desc("Optimizations available:"));
static llvm::cl::opt<bool>
Optimized("O", llvm::cl::desc("Optimization level O. Similar to swift -O"));
// TODO: I wanted to call this 'verify', but some other pass is using this
// option.
static llvm::cl::opt<bool> VerifyEach(
"verify-each",
llvm::cl::desc("Should we spend time verifying that the IR is well "
"formed"));
static llvm::cl::opt<std::string>
TargetTriple("mtriple",
llvm::cl::desc("Override target triple for module"));
static llvm::cl::opt<bool>
PrintStats("print-stats",
llvm::cl::desc("Should LLVM Statistics be printed"));
static cl::opt<std::string> InputFilename(cl::Positional,
cl::desc("<input file>"),
cl::init("-"),
cl::value_desc("filename"));
static cl::opt<std::string> OutputFilename("o",
cl::desc("Override output filename"),
cl::value_desc("filename"));
static cl::opt<std::string> DefaultDataLayout(
"default-data-layout",
cl::desc("data layout string to use if not specified by module"),
cl::value_desc("layout-string"), cl::init(""));
//===----------------------------------------------------------------------===//
// Helper Methods
//===----------------------------------------------------------------------===//
static llvm::CodeGenOpt::Level GetCodeGenOptLevel() {
// TODO: Is this the right thing to do here?
if (Optimized)
return CodeGenOpt::Default;
return CodeGenOpt::None;
}
// Returns the TargetMachine instance or zero if no triple is provided.
static llvm::TargetMachine *
getTargetMachine(llvm::Triple TheTriple, StringRef CPUStr,
StringRef FeaturesStr, const llvm::TargetOptions &Options) {
std::string Error;
const auto *TheTarget =
llvm::TargetRegistry::lookupTarget(MArch, TheTriple, Error);
// Some modules don't specify a triple, and this is okay.
if (!TheTarget) {
return nullptr;
}
return TheTarget->createTargetMachine(TheTriple.getTriple(), CPUStr,
FeaturesStr, Options, RelocModel,
CMModel, GetCodeGenOptLevel());
}
static void dumpOutput(llvm::Module &M, llvm::raw_ostream &os) {
// For now just always dump assembly.
legacy::PassManager EmitPasses;
EmitPasses.add(createPrintModulePass(os));
EmitPasses.run(M);
}
// This function isn't referenced outside its translation unit, but it
// can't use the "static" keyword because its address is used for
// getMainExecutable (since some platforms don't support taking the
// address of main, and some platforms can't implement getMainExecutable
// without being given the address of a function in the main executable).
void anchorForGetMainExecutable() {}
static inline void addPass(legacy::PassManagerBase &PM, Pass *P) {
// Add the pass to the pass manager...
PM.add(P);
if (P->getPassID() == &SwiftAAWrapperPass::ID) {
PM.add(createExternalAAWrapperPass([](Pass &P, Function &, AAResults &AAR) {
if (auto *WrapperPass = P.getAnalysisIfAvailable<SwiftAAWrapperPass>())
AAR.addAAResult(WrapperPass->getResult());
}));
}
// If we are verifying all of the intermediate steps, add the verifier...
if (VerifyEach)
PM.add(createVerifierPass());
}
static void runSpecificPasses(StringRef Binary, llvm::Module *M,
llvm::TargetMachine *TM,
llvm::Triple &ModuleTriple) {
llvm::legacy::PassManager Passes;
llvm::TargetLibraryInfoImpl TLII(ModuleTriple);
Passes.add(new TargetLibraryInfoWrapperPass(TLII));
const llvm::DataLayout &DL = M->getDataLayout();
if (DL.isDefault() && !DefaultDataLayout.empty()) {
M->setDataLayout(DefaultDataLayout);
}
// Add internal analysis passes from the target machine.
Passes.add(createTargetTransformInfoWrapperPass(TM ? TM->getTargetIRAnalysis()
: TargetIRAnalysis()));
for (const llvm::PassInfo *PassInfo : PassList) {
llvm::Pass *P = nullptr;
if (PassInfo->getTargetMachineCtor())
P = PassInfo->getTargetMachineCtor()(TM);
else if (PassInfo->getNormalCtor())
P = PassInfo->getNormalCtor()();
else
errs() << Binary << ": cannot create pass: " << PassInfo->getPassName()
<< "\n";
if (P) {
addPass(Passes, P);
}
}
// Do it.
Passes.run(*M);
}
//===----------------------------------------------------------------------===//
// Main Implementation
//===----------------------------------------------------------------------===//
int main(int argc, char **argv) {
INITIALIZE_LLVM(argc, argv);
// Initialize passes
PassRegistry &Registry = *PassRegistry::getPassRegistry();
initializeCore(Registry);
initializeScalarOpts(Registry);
initializeObjCARCOpts(Registry);
initializeVectorization(Registry);
initializeIPO(Registry);
initializeAnalysis(Registry);
initializeTransformUtils(Registry);
initializeInstCombine(Registry);
initializeInstrumentation(Registry);
initializeTarget(Registry);
// For codegen passes, only passes that do IR to IR transformation are
// supported.
initializeCodeGenPreparePass(Registry);
initializeAtomicExpandPass(Registry);
initializeRewriteSymbolsPass(Registry);
initializeWinEHPreparePass(Registry);
initializeDwarfEHPreparePass(Registry);
initializeSjLjEHPreparePass(Registry);
// Register Swift Only Passes.
initializeSwiftAAWrapperPassPass(Registry);
initializeSwiftRCIdentityPass(Registry);
initializeSwiftARCOptPass(Registry);
initializeSwiftARCContractPass(Registry);
initializeSwiftStackPromotionPass(Registry);
initializeInlineTreePrinterPass(Registry);
initializeSwiftMergeFunctionsPass(Registry);
llvm::cl::ParseCommandLineOptions(argc, argv, "Swift LLVM optimizer\n");
if (PrintStats)
llvm::EnableStatistics();
llvm::SMDiagnostic Err;
// Load the input module...
std::unique_ptr<Module> M =
parseIRFile(InputFilename, Err, getGlobalContext());
if (!M) {
Err.print(argv[0], errs());
return 1;
}
if (verifyModule(*M, &errs())) {
errs() << argv[0] << ": " << InputFilename
<< ": error: input module is broken!\n";
return 1;
}
// If we are supposed to override the target triple, do so now.
if (!TargetTriple.empty())
M->setTargetTriple(llvm::Triple::normalize(TargetTriple));
// Figure out what stream we are supposed to write to...
std::unique_ptr<llvm::tool_output_file> Out;
// Default to standard output.
if (OutputFilename.empty())
OutputFilename = "-";
std::error_code EC;
Out.reset(
new llvm::tool_output_file(OutputFilename, EC, llvm::sys::fs::F_None));
if (EC) {
errs() << EC.message() << '\n';
return 1;
}
llvm::Triple ModuleTriple(M->getTargetTriple());
std::string CPUStr, FeaturesStr;
llvm::TargetMachine *Machine = nullptr;
const llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
if (ModuleTriple.getArch()) {
CPUStr = getCPUStr();
FeaturesStr = getFeaturesStr();
Machine = getTargetMachine(ModuleTriple, CPUStr, FeaturesStr, Options);
}
std::unique_ptr<llvm::TargetMachine> TM(Machine);
// Override function attributes based on CPUStr, FeaturesStr, and command line
// flags.
setFunctionAttributes(CPUStr, FeaturesStr, *M);
if (Optimized) {
IRGenOptions Opts;
Opts.Optimize = true;
// Then perform the optimizations.
performLLVMOptimizations(Opts, M.get(), TM.get());
} else {
runSpecificPasses(argv[0], M.get(), TM.get(), ModuleTriple);
}
// Finally dump the output.
dumpOutput(*M, Out->os());
return 0;
}