mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
The legacy pass manager is being taken down in LLVM. This patch removes the initializers that were removed from LLVM from the swift_llvm_opt_main tool. The rest of the compiler has already been migrated to the new pass manager, so I don't think this will break the main parts of the compiler.
327 lines
12 KiB
C++
327 lines
12 KiB
C++
//===--- swift_llvm_opt_main.cpp ------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://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/TargetParser/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/CodeGen/TargetPassConfig.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/TargetParser/SubtargetFeature.h"
|
|
#include "llvm/MC/TargetRegistry.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/TargetSelect.h"
|
|
#include "llvm/Support/ToolOutputFile.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
// TODO: Replace pass manager:
|
|
// Removed in: d623b2f95fd559901f008a0588dddd0949a8db01
|
|
/* #include "llvm/Transforms/IPO/PassManagerBuilder.h" */
|
|
|
|
using namespace swift;
|
|
|
|
static llvm::codegen::RegisterCodeGenFlags CGF;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Option Declarations
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
struct SwiftLLVMOptOptions {
|
|
// The OptimizationList is automatically populated with registered passes by the
|
|
// PassNameParser.
|
|
//
|
|
llvm::cl::list<const llvm::PassInfo *, bool, llvm::PassNameParser>
|
|
PassList = llvm::cl::list<const llvm::PassInfo *, bool, llvm::PassNameParser>(llvm::cl::desc("Optimizations available:"));
|
|
|
|
llvm::cl::opt<bool>
|
|
Optimized = llvm::cl::opt<bool>("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.
|
|
llvm::cl::opt<bool>
|
|
VerifyEach = llvm::cl::opt<bool>(
|
|
"verify-each",
|
|
llvm::cl::desc("Should we spend time verifying that the IR is well "
|
|
"formed"));
|
|
|
|
llvm::cl::opt<std::string>
|
|
TargetTriple = llvm::cl::opt<std::string>("mtriple",
|
|
llvm::cl::desc("Override target triple for module"));
|
|
|
|
llvm::cl::opt<bool>
|
|
PrintStats = llvm::cl::opt<bool>("print-stats",
|
|
llvm::cl::desc("Should LLVM Statistics be printed"));
|
|
|
|
llvm::cl::opt<std::string>
|
|
InputFilename = llvm::cl::opt<std::string>(llvm::cl::Positional,
|
|
llvm::cl::desc("<input file>"),
|
|
llvm::cl::init("-"),
|
|
llvm::cl::value_desc("filename"));
|
|
|
|
llvm::cl::opt<std::string>
|
|
OutputFilename = llvm::cl::opt<std::string>("o", llvm::cl::desc("Override output filename"),
|
|
llvm::cl::value_desc("filename"));
|
|
|
|
llvm::cl::opt<std::string>
|
|
DefaultDataLayout = llvm::cl::opt<std::string>(
|
|
"default-data-layout",
|
|
llvm::cl::desc("data layout string to use if not specified by module"),
|
|
llvm::cl::value_desc("layout-string"), llvm::cl::init(""));
|
|
};
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Helper Methods
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
static llvm::CodeGenOpt::Level GetCodeGenOptLevel(const SwiftLLVMOptOptions &options) {
|
|
// TODO: Is this the right thing to do here?
|
|
if (options.Optimized)
|
|
return llvm::CodeGenOpt::Default;
|
|
return llvm::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 &targetOptions,
|
|
const SwiftLLVMOptOptions &options) {
|
|
std::string Error;
|
|
const auto *TheTarget = llvm::TargetRegistry::lookupTarget(
|
|
llvm::codegen::getMArch(), TheTriple, Error);
|
|
// Some modules don't specify a triple, and this is okay.
|
|
if (!TheTarget) {
|
|
return nullptr;
|
|
}
|
|
|
|
return TheTarget->createTargetMachine(
|
|
TheTriple.getTriple(), CPUStr, FeaturesStr, targetOptions,
|
|
llvm::Optional<llvm::Reloc::Model>(
|
|
llvm::codegen::getExplicitRelocModel()),
|
|
llvm::codegen::getExplicitCodeModel(), GetCodeGenOptLevel(options));
|
|
}
|
|
|
|
static void dumpOutput(llvm::Module &M, llvm::raw_ostream &os) {
|
|
// For now just always dump assembly.
|
|
llvm::legacy::PassManager EmitPasses;
|
|
EmitPasses.add(createPrintModulePass(os));
|
|
EmitPasses.run(M);
|
|
}
|
|
|
|
static inline void addPass(llvm::legacy::PassManagerBase &PM, llvm::Pass *P,
|
|
const SwiftLLVMOptOptions &options) {
|
|
// Add the pass to the pass manager...
|
|
PM.add(P);
|
|
if (P->getPassID() == &SwiftAAWrapperPass::ID) {
|
|
PM.add(llvm::createExternalAAWrapperPass([](llvm::Pass &P, llvm::Function &,
|
|
llvm::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 (options.VerifyEach)
|
|
PM.add(llvm::createVerifierPass());
|
|
}
|
|
|
|
static void runSpecificPasses(StringRef Binary, llvm::Module *M,
|
|
llvm::TargetMachine *TM,
|
|
llvm::Triple &ModuleTriple,
|
|
const SwiftLLVMOptOptions &options) {
|
|
llvm::legacy::PassManager Passes;
|
|
llvm::TargetLibraryInfoImpl TLII(ModuleTriple);
|
|
Passes.add(new llvm::TargetLibraryInfoWrapperPass(TLII));
|
|
|
|
const llvm::DataLayout &DL = M->getDataLayout();
|
|
if (DL.isDefault() && !options.DefaultDataLayout.empty()) {
|
|
M->setDataLayout(options.DefaultDataLayout);
|
|
}
|
|
|
|
// Add internal analysis passes from the target machine.
|
|
Passes.add(createTargetTransformInfoWrapperPass(
|
|
TM ? TM->getTargetIRAnalysis() : llvm::TargetIRAnalysis()));
|
|
|
|
if (TM) {
|
|
// FIXME: We should dyn_cast this when supported.
|
|
auto <M = static_cast<llvm::LLVMTargetMachine &>(*TM);
|
|
llvm::Pass *TPC = LTM.createPassConfig(Passes);
|
|
Passes.add(TPC);
|
|
}
|
|
|
|
for (const llvm::PassInfo *PassInfo : options.PassList) {
|
|
llvm::Pass *P = nullptr;
|
|
if (PassInfo->getNormalCtor())
|
|
P = PassInfo->getNormalCtor()();
|
|
else
|
|
llvm::errs() << Binary
|
|
<< ": cannot create pass: " << PassInfo->getPassName()
|
|
<< "\n";
|
|
if (P) {
|
|
addPass(Passes, P, options);
|
|
}
|
|
}
|
|
|
|
// Do it.
|
|
Passes.run(*M);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Main Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
int swift_llvm_opt_main(ArrayRef<const char *> argv, void *MainAddr) {
|
|
INITIALIZE_LLVM();
|
|
|
|
// Initialize passes
|
|
llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
|
|
initializeCore(Registry);
|
|
initializeScalarOpts(Registry);
|
|
initializeVectorization(Registry);
|
|
initializeIPO(Registry);
|
|
initializeAnalysis(Registry);
|
|
initializeTransformUtils(Registry);
|
|
initializeInstCombine(Registry);
|
|
initializeTarget(Registry);
|
|
// For codegen passes, only passes that do IR to IR transformation are
|
|
// supported.
|
|
initializeCodeGenPreparePass(Registry);
|
|
initializeAtomicExpandPass(Registry);
|
|
initializeWinEHPreparePass(Registry);
|
|
initializeDwarfEHPrepareLegacyPassPass(Registry);
|
|
initializeSjLjEHPreparePass(Registry);
|
|
|
|
// Register Swift Only Passes.
|
|
initializeSwiftAAWrapperPassPass(Registry);
|
|
initializeSwiftARCOptPass(Registry);
|
|
initializeSwiftARCContractPass(Registry);
|
|
initializeInlineTreePrinterPass(Registry);
|
|
initializeLegacySwiftMergeFunctionsPass(Registry);
|
|
|
|
SwiftLLVMOptOptions options;
|
|
|
|
llvm::cl::ParseCommandLineOptions(argv.size(), argv.data(), "Swift LLVM optimizer\n");
|
|
|
|
if (options.PrintStats)
|
|
llvm::EnableStatistics();
|
|
|
|
llvm::SMDiagnostic Err;
|
|
|
|
// Load the input module...
|
|
auto LLVMContext = std::make_unique<llvm::LLVMContext>();
|
|
std::unique_ptr<llvm::Module> M =
|
|
parseIRFile(options.InputFilename, Err, *LLVMContext.get());
|
|
|
|
if (!M) {
|
|
Err.print(argv[0], llvm::errs());
|
|
return 1;
|
|
}
|
|
|
|
if (verifyModule(*M, &llvm::errs())) {
|
|
llvm::errs() << argv[0] << ": " << options.InputFilename
|
|
<< ": error: input module is broken!\n";
|
|
return 1;
|
|
}
|
|
|
|
// If we are supposed to override the target triple, do so now.
|
|
if (!options.TargetTriple.empty())
|
|
M->setTargetTriple(llvm::Triple::normalize(options.TargetTriple));
|
|
|
|
// Figure out what stream we are supposed to write to...
|
|
std::unique_ptr<llvm::ToolOutputFile> Out;
|
|
// Default to standard output.
|
|
if (options.OutputFilename.empty())
|
|
options.OutputFilename = "-";
|
|
|
|
std::error_code EC;
|
|
Out.reset(
|
|
new llvm::ToolOutputFile(options.OutputFilename, EC, llvm::sys::fs::OF_None));
|
|
if (EC) {
|
|
llvm::errs() << EC.message() << '\n';
|
|
return 1;
|
|
}
|
|
|
|
llvm::Triple ModuleTriple(M->getTargetTriple());
|
|
std::string CPUStr, FeaturesStr;
|
|
llvm::TargetMachine *Machine = nullptr;
|
|
const llvm::TargetOptions targetOptions =
|
|
llvm::codegen::InitTargetOptionsFromCodeGenFlags(ModuleTriple);
|
|
|
|
if (ModuleTriple.getArch()) {
|
|
CPUStr = llvm::codegen::getCPUStr();
|
|
FeaturesStr = llvm::codegen::getFeaturesStr();
|
|
Machine = getTargetMachine(ModuleTriple, CPUStr, FeaturesStr, targetOptions, options);
|
|
}
|
|
|
|
std::unique_ptr<llvm::TargetMachine> TM(Machine);
|
|
|
|
// Override function attributes based on CPUStr, FeaturesStr, and command line
|
|
// flags.
|
|
llvm::codegen::setFunctionAttributes(CPUStr, FeaturesStr, *M);
|
|
|
|
if (options.Optimized) {
|
|
IRGenOptions Opts;
|
|
Opts.OptMode = OptimizationMode::ForSpeed;
|
|
Opts.OutputKind = IRGenOutputKind::LLVMAssemblyAfterOptimization;
|
|
|
|
// Then perform the optimizations.
|
|
performLLVMOptimizations(Opts, M.get(), TM.get(), &Out->os());
|
|
} else {
|
|
runSpecificPasses(argv[0], M.get(), TM.get(), ModuleTriple, options);
|
|
// Finally dump the output.
|
|
dumpOutput(*M, Out->os());
|
|
}
|
|
|
|
return 0;
|
|
}
|