| //===--- Passes.cpp - Swift Compiler SIL Pass Entrypoints -----------------===// |
| // |
| // 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 file provides implementations of a few helper functions |
| /// which provide abstracted entrypoints to the SILPasses stage. |
| /// |
| /// \note The actual SIL passes should be implemented in per-pass source files, |
| /// not in this file. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #define DEBUG_TYPE "sil-optimizer" |
| |
| #include "swift/SILOptimizer/PassManager/Passes.h" |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/Module.h" |
| #include "swift/SIL/SILModule.h" |
| #include "swift/SILOptimizer/Analysis/Analysis.h" |
| #include "swift/SILOptimizer/PassManager/PassManager.h" |
| #include "swift/SILOptimizer/PassManager/Transforms.h" |
| #include "swift/SILOptimizer/Utils/InstOptUtils.h" |
| #include "llvm/ADT/Statistic.h" |
| #include "llvm/ADT/StringSwitch.h" |
| #include "llvm/Support/CommandLine.h" |
| #include "llvm/Support/Debug.h" |
| #include "llvm/Support/ErrorOr.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include "llvm/Support/YAMLParser.h" |
| |
| using namespace swift; |
| |
| bool swift::runSILDiagnosticPasses(SILModule &Module) { |
| auto &opts = Module.getOptions(); |
| |
| // Verify the module, if required. |
| if (opts.VerifyAll) |
| Module.verify(); |
| |
| // If we parsed a .sil file that is already in canonical form, don't rerun |
| // the diagnostic passes. |
| if (Module.getStage() != SILStage::Raw) |
| return false; |
| |
| executePassPipelinePlan(&Module, |
| SILPassPipelinePlan::getDiagnosticPassPipeline(opts), |
| /*isMandatory*/ true); |
| |
| // If we were asked to debug serialization, exit now. |
| auto &Ctx = Module.getASTContext(); |
| if (opts.DebugSerialization) |
| return Ctx.hadError(); |
| |
| // Generate diagnostics. |
| Module.setStage(SILStage::Canonical); |
| |
| // Verify the module, if required. |
| if (opts.VerifyAll) |
| Module.verify(); |
| else { |
| LLVM_DEBUG(Module.verify()); |
| } |
| |
| // If errors were produced during SIL analysis, return true. |
| return Ctx.hadError(); |
| } |
| |
| bool swift::runSILOwnershipEliminatorPass(SILModule &Module) { |
| auto &Ctx = Module.getASTContext(); |
| |
| auto &opts = Module.getOptions(); |
| executePassPipelinePlan( |
| &Module, SILPassPipelinePlan::getOwnershipEliminatorPassPipeline(opts)); |
| |
| return Ctx.hadError(); |
| } |
| |
| void swift::runSILOptimizationPasses(SILModule &Module) { |
| auto &opts = Module.getOptions(); |
| |
| // Verify the module, if required. |
| if (opts.VerifyAll) |
| Module.verify(); |
| |
| if (opts.DisableSILPerfOptimizations) { |
| // If we are not supposed to run SIL perf optzns, we may still need to |
| // serialize. So serialize now. |
| executePassPipelinePlan( |
| &Module, SILPassPipelinePlan::getSerializeSILPassPipeline(opts), |
| /*isMandatory*/ true); |
| return; |
| } |
| |
| executePassPipelinePlan( |
| &Module, SILPassPipelinePlan::getPerformancePassPipeline(opts)); |
| |
| // Check if we actually serialized our module. If we did not, serialize now. |
| if (!Module.isSerialized()) { |
| executePassPipelinePlan( |
| &Module, SILPassPipelinePlan::getSerializeSILPassPipeline(opts), |
| /*isMandatory*/ true); |
| } |
| |
| // If we were asked to debug serialization, exit now. |
| if (opts.DebugSerialization) |
| return; |
| |
| // Verify the module, if required. |
| if (opts.VerifyAll) |
| Module.verify(); |
| else { |
| LLVM_DEBUG(Module.verify()); |
| } |
| } |
| |
| void swift::runSILPassesForOnone(SILModule &Module) { |
| // Verify the module, if required. |
| if (Module.getOptions().VerifyAll) |
| Module.verify(); |
| |
| // We want to run the Onone passes also for function which have an explicit |
| // Onone attribute. |
| executePassPipelinePlan( |
| &Module, SILPassPipelinePlan::getOnonePassPipeline(Module.getOptions()), |
| /*isMandatory*/ true); |
| |
| // Verify the module, if required. |
| if (Module.getOptions().VerifyAll) |
| Module.verify(); |
| else { |
| LLVM_DEBUG(Module.verify()); |
| } |
| } |
| |
| void swift::runSILOptimizationPassesWithFileSpecification(SILModule &M, |
| StringRef Filename) { |
| auto &opts = M.getOptions(); |
| executePassPipelinePlan( |
| &M, SILPassPipelinePlan::getPassPipelineFromFile(opts, Filename)); |
| } |
| |
| /// Get the Pass ID enum value from an ID string. |
| PassKind swift::PassKindFromString(StringRef IDString) { |
| return llvm::StringSwitch<PassKind>(IDString) |
| #define PASS(ID, TAG, DESCRIPTION) .Case(#ID, PassKind::ID) |
| #include "swift/SILOptimizer/PassManager/Passes.def" |
| .Default(PassKind::invalidPassKind); |
| } |
| |
| /// Get an ID string for the given pass Kind. |
| /// This is useful for tools that identify a pass |
| /// by its type name. |
| StringRef swift::PassKindID(PassKind Kind) { |
| switch (Kind) { |
| #define PASS(ID, TAG, DESCRIPTION) \ |
| case PassKind::ID: \ |
| return #ID; |
| #include "swift/SILOptimizer/PassManager/Passes.def" |
| case PassKind::invalidPassKind: |
| llvm_unreachable("Invalid pass kind?!"); |
| } |
| |
| llvm_unreachable("Unhandled PassKind in switch."); |
| } |
| |
| /// Get a tag string for the given pass Kind. |
| /// This format is useful for command line options. |
| StringRef swift::PassKindTag(PassKind Kind) { |
| switch (Kind) { |
| #define PASS(ID, TAG, DESCRIPTION) \ |
| case PassKind::ID: \ |
| return TAG; |
| #include "swift/SILOptimizer/PassManager/Passes.def" |
| case PassKind::invalidPassKind: |
| llvm_unreachable("Invalid pass kind?!"); |
| } |
| |
| llvm_unreachable("Unhandled PassKind in switch."); |
| } |
| |
| // During SIL Lowering, passes may see partially lowered SIL, which is |
| // inconsistent with the current (canonical) stage. We don't change the SIL |
| // stage until lowering is complete. Consequently, any pass added to this |
| // PassManager needs to be able to handle the output of the previous pass. If |
| // the function pass needs to read SIL from other functions, it may be best to |
| // convert it to a module pass to ensure that the SIL input is always at the |
| // same stage of lowering. |
| void swift::runSILLoweringPasses(SILModule &Module) { |
| auto &opts = Module.getOptions(); |
| executePassPipelinePlan(&Module, |
| SILPassPipelinePlan::getLoweringPassPipeline(opts), |
| /*isMandatory*/ true); |
| |
| assert(Module.getStage() == SILStage::Lowered); |
| } |