From 7724e8efa2d3b71f293807f4323f4e760a37f249 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Sun, 1 Feb 2015 10:11:22 +0000 Subject: [PATCH] [PM] Port TTI to the new pass manager, introducing a TargetIRAnalysis to produce it. This adds a function to the TargetMachine that produces this analysis via a callback for each function. This in turn faves the way to produce a *different* TTI per-function with the correct subtarget cached. I've also done the necessary wiring in the opt tool to thread the target machine down and make it available to the pass registry so that we can construct this analysis from a target machine when available. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@227721 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Analysis/TargetTransformInfo.h | 80 +++++++++++++++++++++ include/llvm/Target/TargetMachine.h | 7 ++ lib/Analysis/TargetTransformInfo.cpp | 17 +++++ lib/Target/TargetMachine.cpp | 7 ++ test/Other/new-pass-manager.ll | 12 ++++ tools/opt/NewPMDriver.cpp | 8 ++- tools/opt/NewPMDriver.h | 6 +- tools/opt/PassRegistry.def | 2 + tools/opt/Passes.cpp | 2 + tools/opt/Passes.h | 5 ++ tools/opt/opt.cpp | 18 ++--- 11 files changed, 150 insertions(+), 14 deletions(-) diff --git a/include/llvm/Analysis/TargetTransformInfo.h b/include/llvm/Analysis/TargetTransformInfo.h index 20bc70dfd66..9908853bc49 100644 --- a/include/llvm/Analysis/TargetTransformInfo.h +++ b/include/llvm/Analysis/TargetTransformInfo.h @@ -32,6 +32,7 @@ namespace llvm { class Function; class GlobalValue; class Loop; +class PreservedAnalyses; class Type; class User; class Value; @@ -76,6 +77,17 @@ public: // out-of-line. ~TargetTransformInfo(); + /// \brief Handle the invalidation of this information. + /// + /// When used as a result of \c TargetIRAnalysis this method will be called + /// when the function this was computed for changes. When it returns false, + /// the information is preserved across those changes. + bool invalidate(Function &, const PreservedAnalyses &) { + // FIXME: We should probably in some way ensure that the subtarget + // information for a function hasn't changed. + return false; + } + /// \name Generic Target Information /// @{ @@ -706,6 +718,74 @@ template TargetTransformInfo::TargetTransformInfo(T Impl) : TTIImpl(new Model(Impl)) {} +/// \brief Analysis pass providing the \c TargetTransformInfo. +/// +/// The core idea of the TargetIRAnalysis is to expose an interface through +/// which LLVM targets can analyze and provide information about the middle +/// end's target-independent IR. This supports use cases such as target-aware +/// cost modeling of IR constructs. +/// +/// This is a function analysis because much of the cost modeling for targets +/// is done in a subtarget specific way and LLVM supports compiling different +/// functions targeting different subtargets in order to support runtime +/// dispatch according to the observed subtarget. +class TargetIRAnalysis { +public: + typedef TargetTransformInfo Result; + + /// \brief Opaque, unique identifier for this analysis pass. + static void *ID() { return (void *)&PassID; } + + /// \brief Provide access to a name for this pass for debugging purposes. + static StringRef name() { return "TargetIRAnalysis"; } + + /// \brief Default construct a target IR analysis. + /// + /// This will use the module's datalayout to construct a baseline + /// conservative TTI result. + TargetIRAnalysis(); + + /// \brief Construct an IR analysis pass around a target-provide callback. + /// + /// The callback will be called with a particular function for which the TTI + /// is needed and must return a TTI object for that function. + TargetIRAnalysis(std::function TTICallback); + + // Value semantics. We spell out the constructors for MSVC. + TargetIRAnalysis(const TargetIRAnalysis &Arg) + : TTICallback(Arg.TTICallback) {} + TargetIRAnalysis(TargetIRAnalysis &&Arg) + : TTICallback(std::move(Arg.TTICallback)) {} + TargetIRAnalysis &operator=(const TargetIRAnalysis &RHS) { + TTICallback = RHS.TTICallback; + return *this; + } + TargetIRAnalysis &operator=(TargetIRAnalysis &&RHS) { + TTICallback = std::move(RHS.TTICallback); + return *this; + } + + Result run(Function &F); + +private: + static char PassID; + + /// \brief The callback used to produce a result. + /// + /// We use a completely opaque callback so that targets can provide whatever + /// mechanism they desire for constructing the TTI for a given function. + /// + /// FIXME: Should we really use std::function? It's relatively inefficient. + /// It might be possible to arrange for even stateful callbacks to outlive + /// the analysis and thus use a function_ref which would be lighter weight. + /// This may also be less error prone as the callback is likely to reference + /// the external TargetMachine, and that reference needs to never dangle. + std::function TTICallback; + + /// \brief Helper function used as the callback in the default constructor. + static Result getDefaultTTI(Function &F); +}; + /// \brief Wrapper pass for TargetTransformInfo. /// /// This pass can be constructed from a TTI object which it stores internally diff --git a/include/llvm/Target/TargetMachine.h b/include/llvm/Target/TargetMachine.h index 109985abb1e..dd61c0ab057 100644 --- a/include/llvm/Target/TargetMachine.h +++ b/include/llvm/Target/TargetMachine.h @@ -34,6 +34,7 @@ class Target; class DataLayout; class TargetLibraryInfo; class TargetFrameLowering; +class TargetIRAnalysis; class TargetIntrinsicInfo; class TargetLowering; class TargetPassConfig; @@ -187,6 +188,12 @@ public: /// sections. void setFunctionSections(bool); + /// \brief Get a \c TargetIRAnalysis appropriate for the target. + /// + /// This is used to construct the new pass manager's target IR analysis pass, + /// set up appropriately for this target machine. + virtual TargetIRAnalysis getTargetIRAnalysis(); + /// \brief Get a TTI implementation for the target. /// /// Targets should override this method to provide target-accurate diff --git a/lib/Analysis/TargetTransformInfo.cpp b/lib/Analysis/TargetTransformInfo.cpp index a78d1db396a..6bd79f667b4 100644 --- a/lib/Analysis/TargetTransformInfo.cpp +++ b/lib/Analysis/TargetTransformInfo.cpp @@ -14,6 +14,7 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" #include "llvm/Support/ErrorHandling.h" @@ -255,6 +256,22 @@ Value *TargetTransformInfo::getOrCreateResultFromMemIntrinsic( TargetTransformInfo::Concept::~Concept() {} +TargetIRAnalysis::TargetIRAnalysis() : TTICallback(&getDefaultTTI) {} + +TargetIRAnalysis::TargetIRAnalysis( + std::function TTICallback) + : TTICallback(TTICallback) {} + +TargetIRAnalysis::Result TargetIRAnalysis::run(Function &F) { + return TTICallback(F); +} + +char TargetIRAnalysis::PassID; + +TargetIRAnalysis::Result TargetIRAnalysis::getDefaultTTI(Function &F) { + return Result(F.getParent()->getDataLayout()); +} + // Register the basic pass. INITIALIZE_PASS(TargetTransformInfoWrapperPass, "tti", "Target Transform Information", false, true) diff --git a/lib/Target/TargetMachine.cpp b/lib/Target/TargetMachine.cpp index a8c877f848a..1e5bfb24729 100644 --- a/lib/Target/TargetMachine.cpp +++ b/lib/Target/TargetMachine.cpp @@ -172,6 +172,13 @@ void TargetMachine::setDataSections(bool V) { Options.DataSections = V; } +TargetIRAnalysis TargetMachine::getTargetIRAnalysis() { + // While targets are free to just override getTTI and rely on this analysis, + // it would be more efficient to override and provide an analysis that could + // directly construct that target's TTI without the virtual call. + return TargetIRAnalysis([this](Function &) { return getTTI(); }); +} + TargetTransformInfo TargetMachine::getTTI() { return TargetTransformInfo(getDataLayout()); } diff --git a/test/Other/new-pass-manager.ll b/test/Other/new-pass-manager.ll index 2cb54ba49a8..a1bffe4d63d 100644 --- a/test/Other/new-pass-manager.ll +++ b/test/Other/new-pass-manager.ll @@ -278,6 +278,18 @@ ; CHECK-TLI-NOT: Running analysis: TargetLibraryAnalysis ; CHECK-TLI: Finished pass manager +; RUN: opt -disable-output -disable-verify -debug-pass-manager %s 2>&1 \ +; RUN: -passes='require,invalidate,require' \ +; RUN: | FileCheck %s --check-prefix=CHECK-TIRA +; CHECK-TIRA: Starting pass manager +; CHECK-TIRA: Running pass: RequireAnalysisPass +; CHECK-TIRA: Running analysis: TargetIRAnalysis +; CHECK-TIRA: Running pass: InvalidateAllAnalysesPass +; CHECK-TIRA-NOT: Invalidating analysis: TargetIRAnalysis +; CHECK-TIRA: Running pass: RequireAnalysisPass +; CHECK-TIRA-NOT: Running analysis: TargetIRAnalysis +; CHECK-TIRA: Finished pass manager + define void @foo() { ret void } diff --git a/tools/opt/NewPMDriver.cpp b/tools/opt/NewPMDriver.cpp index b0845c7b1f5..a73750dd492 100644 --- a/tools/opt/NewPMDriver.cpp +++ b/tools/opt/NewPMDriver.cpp @@ -27,6 +27,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Target/TargetMachine.h" using namespace llvm; using namespace opt_tool; @@ -36,9 +37,10 @@ static cl::opt cl::desc("Print pass management debugging information")); bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M, - tool_output_file *Out, StringRef PassPipeline, - OutputKind OK, VerifierKind VK) { - Passes P; + TargetMachine *TM, tool_output_file *Out, + StringRef PassPipeline, OutputKind OK, + VerifierKind VK) { + Passes P(TM); FunctionAnalysisManager FAM(DebugPM); CGSCCAnalysisManager CGAM(DebugPM); diff --git a/tools/opt/NewPMDriver.h b/tools/opt/NewPMDriver.h index f977baca7f8..5384fe295e1 100644 --- a/tools/opt/NewPMDriver.h +++ b/tools/opt/NewPMDriver.h @@ -26,6 +26,7 @@ namespace llvm { class LLVMContext; class Module; +class TargetMachine; class tool_output_file; namespace opt_tool { @@ -48,8 +49,9 @@ enum VerifierKind { /// file. It's interface is consequentially somewhat ad-hoc, but will go away /// when the transition finishes. bool runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M, - tool_output_file *Out, StringRef PassPipeline, - opt_tool::OutputKind OK, opt_tool::VerifierKind VK); + TargetMachine *TM, tool_output_file *Out, + StringRef PassPipeline, opt_tool::OutputKind OK, + opt_tool::VerifierKind VK); } #endif diff --git a/tools/opt/PassRegistry.def b/tools/opt/PassRegistry.def index 9361d98c9a5..4ee9e97158e 100644 --- a/tools/opt/PassRegistry.def +++ b/tools/opt/PassRegistry.def @@ -55,6 +55,8 @@ FUNCTION_ANALYSIS("domtree", DominatorTreeAnalysis()) FUNCTION_ANALYSIS("loops", LoopAnalysis()) FUNCTION_ANALYSIS("no-op-function", NoOpFunctionAnalysis()) FUNCTION_ANALYSIS("targetlibinfo", TargetLibraryAnalysis()) +FUNCTION_ANALYSIS("targetir", + TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis()) #undef FUNCTION_ANALYSIS #ifndef FUNCTION_PASS diff --git a/tools/opt/Passes.cpp b/tools/opt/Passes.cpp index 46c165abc03..b098a7c2351 100644 --- a/tools/opt/Passes.cpp +++ b/tools/opt/Passes.cpp @@ -20,11 +20,13 @@ #include "llvm/Analysis/LazyCallGraph.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/Debug.h" +#include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/InstCombine/InstCombine.h" #include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h" diff --git a/tools/opt/Passes.h b/tools/opt/Passes.h index 90a6c6b871d..d3cb628469b 100644 --- a/tools/opt/Passes.h +++ b/tools/opt/Passes.h @@ -21,6 +21,7 @@ #include "llvm/IR/PassManager.h" namespace llvm { +class TargetMachine; /// \brief This class provides access to all of LLVM's passes. /// @@ -29,7 +30,11 @@ namespace llvm { /// of the built-in passes, and those may reference these members during /// construction. class Passes { + TargetMachine *TM; + public: + explicit Passes(TargetMachine *TM = nullptr) : TM(TM) {} + /// \brief Registers all available module analysis passes. /// /// This is an interface that can be used to populate a \c diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 93b44d4f7f4..af2cdd82460 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -370,6 +370,12 @@ int main(int argc, char **argv) { } } + Triple ModuleTriple(M->getTargetTriple()); + TargetMachine *Machine = nullptr; + if (ModuleTriple.getArch()) + Machine = GetTargetMachine(ModuleTriple); + std::unique_ptr TM(Machine); + // If the output is set to be emitted to standard out, and standard out is a // console, print out a warning message and refuse to do it. We don't // impress anyone by spewing tons of binary goo to a terminal. @@ -391,8 +397,8 @@ int main(int argc, char **argv) { // The user has asked to use the new pass manager and provided a pipeline // string. Hand off the rest of the functionality to the new code for that // layer. - return runPassPipeline(argv[0], Context, *M, Out.get(), PassPipeline, - OK, VK) + return runPassPipeline(argv[0], Context, *M, TM.get(), Out.get(), + PassPipeline, OK, VK) ? 0 : 1; } @@ -403,7 +409,7 @@ int main(int argc, char **argv) { PassManager Passes; // Add an appropriate TargetLibraryInfo pass for the module's triple. - TargetLibraryInfoImpl TLII(Triple(M->getTargetTriple())); + TargetLibraryInfoImpl TLII(ModuleTriple); // The -disable-simplify-libcalls flag actually disables all builtin optzns. if (DisableSimplifyLibCalls) @@ -420,12 +426,6 @@ int main(int argc, char **argv) { if (DL) Passes.add(new DataLayoutPass()); - Triple ModuleTriple(M->getTargetTriple()); - TargetMachine *Machine = nullptr; - if (ModuleTriple.getArch()) - Machine = GetTargetMachine(Triple(ModuleTriple)); - std::unique_ptr TM(Machine); - // Add internal analysis passes from the target machine. Passes.add(createTargetTransformInfoWrapperPass( TM ? TM->getTTI() : TargetTransformInfo(DL))); -- 2.34.1