[polly] r309826 - [Polly][PM][WIP] Polly pass registration
Michael Kruse via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 2 09:57:29 PDT 2017
Hi Philipp,
before committing Phabricator patches, could remove the tags [Polly]
and [WIP]? Thank you.
Michael
2017-08-02 17:52 GMT+02:00 Philip Pfaffe via llvm-commits
<llvm-commits at lists.llvm.org>:
> Author: pfaffe
> Date: Wed Aug 2 08:52:25 2017
> New Revision: 309826
>
> URL: http://llvm.org/viewvc/llvm-project?rev=309826&view=rev
> Log:
> [Polly][PM][WIP] Polly pass registration
>
> Summary:
> This patch is a first attempt at registering Polly passes with the LLVM tools. Tool plugins are still unsupported, but this registration is usable from the tools if Polly is linked into them (albeit requiring minimal patches to those tools). Registration requires a small amount of machinery (the owning analysis proxies), necessary for injecting ScopAnalysisManager objects into the calling tools.
>
> This patch is marked WIP because the registration is incomplete. Parsing manual pipelines is fully supported, but default pass injection into the O3 pipeline is lacking, mostly because there is opportunity for some redesign here, I believe. The first point of order would be insertion points. I think it makes sense to run before the vectorizers. Running Polly Early, however, is weird. Mostly because it actually is the default (which to me is unexpected), and because Polly runs it's own O1 pipeline. Why not instead insert it at an appropriate place somewhere after simplification happend? Running after the loop optimizers seems intuitive, but it also seems wasteful, since multiple consecutive loops might well be a single scop, and we don't need to run for all of them.
>
> My second request for comments would be regarding all those smallish helper passes we have, like PollyViewer, PollyPrinter, PollyImportJScop. Right now these are controlled by command line options, deciding whether they should be part of the Polly pipeline. What is your opinion on treating them like real passes, and have the user write an appropriate pipeline if they want to use any of them?
>
> Reviewers: grosser, Meinersbur, bollu
>
> Reviewed By: grosser
>
> Subscribers: llvm-commits, pollydev
>
> Tags: #polly
>
> Differential Revision: https://reviews.llvm.org/D35458
>
> Added:
> polly/trunk/include/polly/CodePreparation.h
> polly/trunk/lib/Support/PollyPasses.def
> Modified:
> polly/trunk/include/polly/ScopPass.h
> polly/trunk/include/polly/Support/ScopHelper.h
> polly/trunk/lib/Analysis/ScopPass.cpp
> polly/trunk/lib/Support/RegisterPasses.cpp
> polly/trunk/lib/Support/ScopHelper.cpp
> polly/trunk/lib/Transform/CodePreparation.cpp
>
> Added: polly/trunk/include/polly/CodePreparation.h
> URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/CodePreparation.h?rev=309826&view=auto
> ==============================================================================
> --- polly/trunk/include/polly/CodePreparation.h (added)
> +++ polly/trunk/include/polly/CodePreparation.h Wed Aug 2 08:52:25 2017
> @@ -0,0 +1,13 @@
> +#ifndef POLLY_CODEPREPARATION_H
> +#define POLLY_CODEPREPARATION_H
> +
> +#include "llvm/IR/PassManager.h"
> +
> +namespace polly {
> +struct CodePreparationPass : public llvm::PassInfoMixin<CodePreparationPass> {
> + llvm::PreservedAnalyses run(llvm::Function &F,
> + llvm::FunctionAnalysisManager &FAM);
> +};
> +}
> +
> +#endif /* POLLY_CODEPREPARATION_H */
>
> Modified: polly/trunk/include/polly/ScopPass.h
> URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/ScopPass.h?rev=309826&r1=309825&r2=309826&view=diff
> ==============================================================================
> --- polly/trunk/include/polly/ScopPass.h (original)
> +++ polly/trunk/include/polly/ScopPass.h Wed Aug 2 08:52:25 2017
> @@ -77,6 +77,21 @@ private:
> ScopInfo *SI;
> };
>
> +// A partial specialization of the require analysis template pass to handle
> +// extra parameters
> +template <typename AnalysisT>
> +struct RequireAnalysisPass<AnalysisT, Scop, ScopAnalysisManager,
> + ScopStandardAnalysisResults &, SPMUpdater &>
> + : PassInfoMixin<
> + RequireAnalysisPass<AnalysisT, Scop, ScopAnalysisManager,
> + ScopStandardAnalysisResults &, SPMUpdater &>> {
> + PreservedAnalyses run(Scop &L, ScopAnalysisManager &AM,
> + ScopStandardAnalysisResults &AR, SPMUpdater &) {
> + (void)AM.template getResult<AnalysisT>(L, AR);
> + return PreservedAnalyses::all();
> + }
> +};
> +
> template <>
> InnerAnalysisManagerProxy<ScopAnalysisManager, Function>::Result
> InnerAnalysisManagerProxy<ScopAnalysisManager, Function>::run(
> @@ -95,6 +110,40 @@ extern template class OuterAnalysisManag
> } // namespace llvm
>
> namespace polly {
> +
> +template <typename AnalysisManagerT, typename IRUnitT, typename... ExtraArgTs>
> +class OwningInnerAnalysisManagerProxy
> + : public InnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT> {
> +public:
> + OwningInnerAnalysisManagerProxy()
> + : InnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT>(InnerAM) {}
> + using Result = typename InnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT,
> + ExtraArgTs...>::Result;
> + Result run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
> + ExtraArgTs...) {
> + return Result(InnerAM);
> + }
> +
> + AnalysisManagerT &getManager() { return InnerAM; }
> +
> +private:
> + friend AnalysisInfoMixin<
> + OwningInnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT>>;
> +
> + static AnalysisKey Key;
> +
> + AnalysisManagerT InnerAM;
> +};
> +
> +template <>
> +OwningInnerAnalysisManagerProxy<ScopAnalysisManager, Function>::Result
> +OwningInnerAnalysisManagerProxy<ScopAnalysisManager, Function>::run(
> + Function &F, FunctionAnalysisManager &FAM);
> +extern template class OwningInnerAnalysisManagerProxy<ScopAnalysisManager,
> + Function>;
> +
> +using OwningScopAnalysisManagerFunctionProxy =
> + OwningInnerAnalysisManagerProxy<ScopAnalysisManager, Function>;
> using ScopPassManager =
> PassManager<Scop, ScopAnalysisManager, ScopStandardAnalysisResults &,
> SPMUpdater &>;
>
> Modified: polly/trunk/include/polly/Support/ScopHelper.h
> URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/Support/ScopHelper.h?rev=309826&r1=309825&r2=309826&view=diff
> ==============================================================================
> --- polly/trunk/include/polly/Support/ScopHelper.h (original)
> +++ polly/trunk/include/polly/Support/ScopHelper.h Wed Aug 2 08:52:25 2017
> @@ -315,6 +315,16 @@ void simplifyRegion(llvm::Region *R, llv
> ///
> void splitEntryBlockForAlloca(llvm::BasicBlock *EntryBlock, llvm::Pass *P);
>
> +/// Split the entry block of a function to store the newly inserted
> +/// allocations outside of all Scops.
> +///
> +/// @param DT DominatorTree to be updated.
> +/// @param LI LoopInfo to be updated.
> +/// @param RI RegionInfo to be updated.
> +void splitEntryBlockForAlloca(llvm::BasicBlock *EntryBlock,
> + llvm::DominatorTree *DT, llvm::LoopInfo *LI,
> + llvm::RegionInfo *RI);
> +
> /// Wrapper for SCEVExpander extended to all Polly features.
> ///
> /// This wrapper will internally call the SCEVExpander but also makes sure that
>
> Modified: polly/trunk/lib/Analysis/ScopPass.cpp
> URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopPass.cpp?rev=309826&r1=309825&r2=309826&view=diff
> ==============================================================================
> --- polly/trunk/lib/Analysis/ScopPass.cpp (original)
> +++ polly/trunk/lib/Analysis/ScopPass.cpp Wed Aug 2 08:52:25 2017
> @@ -41,6 +41,8 @@ void ScopPass::getAnalysisUsage(Analysis
> AU.setPreservesAll();
> }
>
> +template class OwningInnerAnalysisManagerProxy<ScopAnalysisManager, Function>;
> +
> namespace llvm {
>
> template class PassManager<Scop, ScopAnalysisManager,
> @@ -130,6 +132,12 @@ bool ScopAnalysisManagerFunctionProxy::R
> }
>
> template <>
> +OwningScopAnalysisManagerFunctionProxy::Result
> +OwningScopAnalysisManagerFunctionProxy::run(Function &F,
> + FunctionAnalysisManager &FAM) {
> + return Result(InnerAM, FAM.getResult<ScopInfoAnalysis>(F));
> +}
> +template <>
> ScopAnalysisManagerFunctionProxy::Result
> ScopAnalysisManagerFunctionProxy::run(Function &F,
> FunctionAnalysisManager &FAM) {
>
> Added: polly/trunk/lib/Support/PollyPasses.def
> URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Support/PollyPasses.def?rev=309826&view=auto
> ==============================================================================
> --- polly/trunk/lib/Support/PollyPasses.def (added)
> +++ polly/trunk/lib/Support/PollyPasses.def Wed Aug 2 08:52:25 2017
> @@ -0,0 +1,29 @@
> +#ifndef FUNCTION_ANALYSIS
> +#define FUNCTION_ANALYSIS(NAME, CREATE_PASS)
> +#endif
> +FUNCTION_ANALYSIS("polly-detect", ScopAnalysis())
> +FUNCTION_ANALYSIS("polly-function-scops", ScopInfoAnalysis())
> +#undef FUNCTION_ANALYSIS
> +
> +#ifndef FUNCTION_PASS
> +#define FUNCTION_PASS(NAME, CREATE_PASS)
> +#endif
> +FUNCTION_PASS("polly-prepare", CodePreparationPass())
> +FUNCTION_PASS("print<polly-detect>", ScopAnalysisPrinterPass(errs()))
> +FUNCTION_PASS("print<polly-function-scops>", ScopInfoPrinterPass(errs()))
> +#undef FUNCTION_PASS
> +
> +#ifndef SCOP_ANALYSIS
> +#define SCOP_ANALYSIS(NAME, CREATE_PASS)
> +#endif
> +SCOP_ANALYSIS("polly-ast", IslAstAnalysis())
> +SCOP_ANALYSIS("polly-dependences", DependenceAnalysis())
> +#undef SCOP_ANALYSIS
> +
> +#ifndef SCOP_PASS
> +#define SCOP_PASS(NAME, CREATE_PASS)
> +#endif
> +SCOP_PASS("print<polly-ast>", IslAstPrinterPass(outs()))
> +SCOP_PASS("print<polly-dependences>", DependenceInfoPrinterPass(outs()))
> +SCOP_PASS("polly-codegen", CodeGenerationPass())
> +#undef SCOP_PASS
>
> Modified: polly/trunk/lib/Support/RegisterPasses.cpp
> URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Support/RegisterPasses.cpp?rev=309826&r1=309825&r2=309826&view=diff
> ==============================================================================
> --- polly/trunk/lib/Support/RegisterPasses.cpp (original)
> +++ polly/trunk/lib/Support/RegisterPasses.cpp Wed Aug 2 08:52:25 2017
> @@ -23,7 +23,9 @@
> #include "polly/Canonicalization.h"
> #include "polly/CodeGen/CodeGeneration.h"
> #include "polly/CodeGen/CodegenCleanup.h"
> +#include "polly/CodeGen/IslAst.h"
> #include "polly/CodeGen/PPCGCodeGeneration.h"
> +#include "polly/CodePreparation.h"
> #include "polly/DeLICM.h"
> #include "polly/DependenceInfo.h"
> #include "polly/FlattenSchedule.h"
> @@ -37,6 +39,8 @@
> #include "polly/Support/DumpModulePass.h"
> #include "llvm/Analysis/CFGPrinter.h"
> #include "llvm/IR/LegacyPassManager.h"
> +#include "llvm/IR/Verifier.h"
> +#include "llvm/Passes/PassBuilder.h"
> #include "llvm/Support/TargetSelect.h"
> #include "llvm/Transforms/IPO.h"
> #include "llvm/Transforms/IPO/PassManagerBuilder.h"
> @@ -430,6 +434,69 @@ registerPollyScalarOptimizerLatePasses(c
> PM.add(createCodegenCleanupPass());
> }
>
> +static void buildDefaultPollyPipeline(FunctionPassManager &PM,
> + PassBuilder::OptimizationLevel Level) {
> + if (!polly::shouldEnablePolly())
> + return;
> + PassBuilder PB;
> + ScopPassManager SPM;
> +
> + // TODO add utility passes for the various command line options, once they're
> + // ported
> + assert(!DumpBefore && "This option is not implemented");
> + assert(DumpBeforeFile.empty() && "This option is not implemented");
> +
> + if (PollyDetectOnly)
> + return;
> +
> + assert(!PollyViewer && "This option is not implemented");
> + assert(!PollyOnlyViewer && "This option is not implemented");
> + assert(!PollyPrinter && "This option is not implemented");
> + assert(!PollyOnlyPrinter && "This option is not implemented");
> + assert(!EnablePolyhedralInfo && "This option is not implemented");
> + assert(!EnableDeLICM && "This option is not implemented");
> + assert(!EnableSimplify && "This option is not implemented");
> + assert(!ImportJScop && "This option is not implemented");
> + assert(!DeadCodeElim && "This option is not implemented");
> + assert(!EnablePruneUnprofitable && "This option is not implemented");
> + if (Target == TARGET_CPU || Target == TARGET_HYBRID)
> + switch (Optimizer) {
> + case OPTIMIZER_NONE:
> + break; /* Do nothing */
> + case OPTIMIZER_ISL:
> + assert("ISL optimizer is not implemented");
> + break;
> + }
> +
> + assert(!ExportJScop && "This option is not implemented");
> +
> + if (Target == TARGET_CPU || Target == TARGET_HYBRID) {
> + switch (CodeGeneration) {
> + case CODEGEN_FULL:
> + SPM.addPass(polly::CodeGenerationPass());
> + break;
> + case CODEGEN_AST:
> + default: // Does it actually make sense to distinguish IslAst codegen?
> + break;
> + }
> + }
> +#ifdef GPU_CODEGEN
> + else
> + assert("Hybrid Target with GPU support is not implemented");
> +#endif
> +
> + PM.addPass(CodePreparationPass());
> + PM.addPass(createFunctionToScopPassAdaptor(std::move(SPM)));
> + PM.addPass(PB.buildFunctionSimplificationPipeline(
> + Level, PassBuilder::ThinLTOPhase::None)); // Cleanup
> +
> + assert(!DumpAfter && "This option is not implemented");
> + assert(DumpAfterFile.empty() && "This option is not implemented");
> +
> + if (CFGPrinter)
> + PM.addPass(llvm::CFGPrinterPass());
> +}
> +
> /// Register Polly to be available as an optimizer
> ///
> ///
> @@ -478,4 +545,140 @@ static llvm::RegisterStandardPasses
> static llvm::RegisterStandardPasses RegisterPollyOptimizerScalarLate(
> llvm::PassManagerBuilder::EP_VectorizerStart,
> registerPollyScalarOptimizerLatePasses);
> +
> +static OwningScopAnalysisManagerFunctionProxy
> +createScopAnalyses(FunctionAnalysisManager &FAM) {
> + OwningScopAnalysisManagerFunctionProxy Proxy;
> +#define SCOP_ANALYSIS(NAME, CREATE_PASS) \
> + Proxy.getManager().registerPass([] { return CREATE_PASS; });
> +
> +#include "PollyPasses.def"
> +
> + Proxy.getManager().registerPass(
> + [&FAM] { return FunctionAnalysisManagerScopProxy(FAM); });
> + return Proxy;
> +}
> +
> +static void registerFunctionAnalyses(FunctionAnalysisManager &FAM) {
> +#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \
> + FAM.registerPass([] { return CREATE_PASS; });
> +
> +#include "PollyPasses.def"
> +
> + FAM.registerPass([&FAM] { return createScopAnalyses(FAM); });
> +}
> +
> +static bool
> +parseFunctionPipeline(StringRef Name, FunctionPassManager &FPM,
> + ArrayRef<PassBuilder::PipelineElement> Pipeline) {
> + if (parseAnalysisUtilityPasses<OwningScopAnalysisManagerFunctionProxy>(
> + "polly-scop-analyses", Name, FPM))
> + return true;
> +
> +#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \
> + if (parseAnalysisUtilityPasses< \
> + std::remove_reference<decltype(CREATE_PASS)>::type>(NAME, Name, \
> + FPM)) \
> + return true;
> +
> +#define FUNCTION_PASS(NAME, CREATE_PASS) \
> + if (Name == NAME) { \
> + FPM.addPass(CREATE_PASS); \
> + return true; \
> + }
> +
> +#include "PollyPasses.def"
> + return false;
> +}
> +
> +static bool parseScopPass(StringRef Name, ScopPassManager &SPM) {
> +#define SCOP_ANALYSIS(NAME, CREATE_PASS) \
> + if (parseAnalysisUtilityPasses< \
> + std::remove_reference<decltype(CREATE_PASS)>::type>(NAME, Name, \
> + SPM)) \
> + return true;
> +
> +#define SCOP_PASS(NAME, CREATE_PASS) \
> + if (Name == NAME) { \
> + SPM.addPass(CREATE_PASS); \
> + return true; \
> + }
> +
> +#include "PollyPasses.def"
> +
> + return false;
> +}
> +
> +static bool parseScopPipeline(StringRef Name, FunctionPassManager &FPM,
> + ArrayRef<PassBuilder::PipelineElement> Pipeline) {
> + if (Name != "scop")
> + return false;
> + if (!Pipeline.empty()) {
> + ScopPassManager SPM;
> + for (const auto &E : Pipeline)
> + if (!parseScopPass(E.Name, SPM))
> + return false;
> + FPM.addPass(createFunctionToScopPassAdaptor(std::move(SPM)));
> + }
> + return true;
> +}
> +
> +static bool isScopPassName(StringRef Name) {
> +#define SCOP_ANALYSIS(NAME, CREATE_PASS) \
> + if (Name == "require<" NAME ">") \
> + return true; \
> + if (Name == "invalidate<" NAME ">") \
> + return true;
> +
> +#define SCOP_PASS(NAME, CREATE_PASS) \
> + if (Name == NAME) \
> + return true;
> +
> +#include "PollyPasses.def"
> +
> + return false;
> +}
> +
> +static bool
> +parseTopLevelPipeline(ModulePassManager &MPM,
> + ArrayRef<PassBuilder::PipelineElement> Pipeline,
> + bool VerifyEachPass, bool DebugLogging) {
> + std::vector<PassBuilder::PipelineElement> FullPipeline;
> + StringRef FirstName = Pipeline.front().Name;
> +
> + if (!isScopPassName(FirstName))
> + return false;
> +
> + FunctionPassManager FPM(DebugLogging);
> + ScopPassManager SPM(DebugLogging);
> +
> + for (auto &Element : Pipeline) {
> + auto &Name = Element.Name;
> + auto &InnerPipeline = Element.InnerPipeline;
> + if (!InnerPipeline.empty()) // Scop passes don't have inner pipelines
> + return false;
> + if (!parseScopPass(Name, SPM))
> + return false;
> + }
> +
> + FPM.addPass(createFunctionToScopPassAdaptor(std::move(SPM)));
> + if (VerifyEachPass)
> + FPM.addPass(VerifierPass());
> + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
> + if (VerifyEachPass)
> + MPM.addPass(VerifierPass());
> +
> + return true;
> +}
> +
> +void RegisterPollyPasses(PassBuilder &PB) {
> + PB.registerAnalysisRegistrationCallback(registerFunctionAnalyses);
> + PB.registerPipelineParsingCallback(parseFunctionPipeline);
> + PB.registerPipelineParsingCallback(parseScopPipeline);
> + PB.registerParseTopLevelPipelineCallback(parseTopLevelPipeline);
> +
> + if (PassPosition == POSITION_BEFORE_VECTORIZER)
> + PB.registerVectorizerStartEPCallback(buildDefaultPollyPipeline);
> + // FIXME else Error?
> +}
> } // namespace polly
>
> Modified: polly/trunk/lib/Support/ScopHelper.cpp
> URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Support/ScopHelper.cpp?rev=309826&r1=309825&r2=309826&view=diff
> ==============================================================================
> --- polly/trunk/lib/Support/ScopHelper.cpp (original)
> +++ polly/trunk/lib/Support/ScopHelper.cpp Wed Aug 2 08:52:25 2017
> @@ -194,13 +194,19 @@ static BasicBlock *splitBlock(BasicBlock
> return NewBlock;
> }
>
> -void polly::splitEntryBlockForAlloca(BasicBlock *EntryBlock, Pass *P) {
> +void polly::splitEntryBlockForAlloca(BasicBlock *EntryBlock, DominatorTree *DT,
> + LoopInfo *LI, RegionInfo *RI) {
> // Find first non-alloca instruction. Every basic block has a non-alloca
> // instruction, as every well formed basic block has a terminator.
> BasicBlock::iterator I = EntryBlock->begin();
> while (isa<AllocaInst>(I))
> ++I;
>
> + // splitBlock updates DT, LI and RI.
> + splitBlock(EntryBlock, &*I, DT, LI, RI);
> +}
> +
> +void polly::splitEntryBlockForAlloca(BasicBlock *EntryBlock, Pass *P) {
> auto *DTWP = P->getAnalysisIfAvailable<DominatorTreeWrapperPass>();
> auto *DT = DTWP ? &DTWP->getDomTree() : nullptr;
> auto *LIWP = P->getAnalysisIfAvailable<LoopInfoWrapperPass>();
> @@ -209,7 +215,7 @@ void polly::splitEntryBlockForAlloca(Bas
> RegionInfo *RI = RIP ? &RIP->getRegionInfo() : nullptr;
>
> // splitBlock updates DT, LI and RI.
> - splitBlock(EntryBlock, &*I, DT, LI, RI);
> + polly::splitEntryBlockForAlloca(EntryBlock, DT, LI, RI);
> }
>
> /// The SCEVExpander will __not__ generate any code for an existing SDiv/SRem
>
> Modified: polly/trunk/lib/Transform/CodePreparation.cpp
> URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Transform/CodePreparation.cpp?rev=309826&r1=309825&r2=309826&view=diff
> ==============================================================================
> --- polly/trunk/lib/Transform/CodePreparation.cpp (original)
> +++ polly/trunk/lib/Transform/CodePreparation.cpp Wed Aug 2 08:52:25 2017
> @@ -16,6 +16,7 @@
> //
> //===----------------------------------------------------------------------===//
>
> +#include "polly/CodePreparation.h"
> #include "polly/LinkAllPasses.h"
> #include "polly/ScopDetection.h"
> #include "polly/Support/ScopHelper.h"
> @@ -57,6 +58,28 @@ public:
> };
> } // namespace
>
> +PreservedAnalyses CodePreparationPass::run(Function &F,
> + FunctionAnalysisManager &FAM) {
> +
> + // Find first non-alloca instruction. Every basic block has a non-alloca
> + // instruction, as every well formed basic block has a terminator.
> + auto &EntryBlock = F.getEntryBlock();
> + BasicBlock::iterator I = EntryBlock.begin();
> + while (isa<AllocaInst>(I))
> + ++I;
> +
> + auto &DT = FAM.getResult<DominatorTreeAnalysis>(F);
> + auto &LI = FAM.getResult<LoopAnalysis>(F);
> +
> + // splitBlock updates DT, LI and RI.
> + splitEntryBlockForAlloca(&EntryBlock, &DT, &LI, nullptr);
> +
> + PreservedAnalyses PA;
> + PA.preserve<DominatorTreeAnalysis>();
> + PA.preserve<LoopAnalysis>();
> + return PA;
> +}
> +
> void CodePreparation::clear() {}
>
> CodePreparation::~CodePreparation() { clear(); }
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list