about summary refs log tree commit diff
path: root/src/rustllvm/PassWrapper.cpp
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-08-22 20:58:42 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-08-26 20:11:51 -0700
commit73540551e5051c524b5533a5ab3eb991dda4eaac (patch)
treed623ac8cc5a5a400e5dba821e59928fad876a079 /src/rustllvm/PassWrapper.cpp
parent6a649e6b8b3e42bb8fa8fa806d783ecd9b543784 (diff)
downloadrust-73540551e5051c524b5533a5ab3eb991dda4eaac.tar.gz
rust-73540551e5051c524b5533a5ab3eb991dda4eaac.zip
Rewrite pass management with LLVM
Beforehand, it was unclear whether rust was performing the "recommended set" of
optimizations provided by LLVM for code. This commit changes the way we run
passes to closely mirror that of clang, which in theory does it correctly. The
notable changes include:

* Passes are no longer explicitly added one by one. This would be difficult to
  keep up with as LLVM changes and we don't guaranteed always know the best
  order in which to run passes
* Passes are now managed by LLVM's PassManagerBuilder object. This is then used
  to populate the various pass managers run.
* We now run both a FunctionPassManager and a module-wide PassManager. This is
  what clang does, and I presume that we *may* see a speed boost from the
  module-wide passes just having to do less work. I have no measured this.
* The codegen pass manager has been extracted to its own separate pass manager
  to not get mixed up with the other passes
* All pass managers now include passes for target-specific data layout and
  analysis passes

Some new features include:

* You can now print all passes being run with `-Z print-llvm-passes`
* When specifying passes via `--passes`, the passes are now appended to the
  default list of passes instead of overwriting them.
* The output of `--passes list` is now generated by LLVM instead of maintaining
  a list of passes ourselves
* Loop vectorization is turned on by default as an optimization pass and can be
  disabled with `-Z no-vectorize-loops`
Diffstat (limited to 'src/rustllvm/PassWrapper.cpp')
-rw-r--r--src/rustllvm/PassWrapper.cpp221
1 files changed, 190 insertions, 31 deletions
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index 32b6df4e1dd..56ba56cf893 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -8,29 +8,29 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#include <stdio.h>
+
 #include "rustllvm.h"
 
-using namespace llvm;
+#include "llvm/Support/CBindingWrapping.h"
+#include "llvm/Target/TargetLibraryInfo.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
 
-// Pass conversion fns
-typedef struct LLVMOpaquePass *LLVMPassRef;
+#include "llvm-c/Transforms/PassManagerBuilder.h"
 
-inline Pass *unwrap(LLVMPassRef P) {
-    return reinterpret_cast<Pass*>(P);
-}
+using namespace llvm;
 
-inline LLVMPassRef wrap(const Pass *P) {
-    return reinterpret_cast<LLVMPassRef>(const_cast<Pass*>(P));
-}
+extern cl::opt<bool> EnableARMEHABI;
 
-template<typename T>
-inline T *unwrap(LLVMPassRef P) {
-    T *Q = (T*)unwrap(P);
-    assert(Q && "Invalid cast!");
-    return Q;
-}
+typedef struct LLVMOpaquePass *LLVMPassRef;
+typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
+
+DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef)
+DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
+DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder, LLVMPassManagerBuilderRef)
 
-extern "C" void LLVMInitializePasses() {
+extern "C" void
+LLVMInitializePasses() {
   PassRegistry &Registry = *PassRegistry::getPassRegistry();
   initializeCore(Registry);
   initializeCodeGen(Registry);
@@ -45,26 +45,185 @@ extern "C" void LLVMInitializePasses() {
   initializeTarget(Registry);
 }
 
-extern "C" void LLVMAddPass(LLVMPassManagerRef PM, LLVMPassRef P) {
-    PassManagerBase * pm = unwrap(PM);
-    Pass * p = unwrap(P);
-
-    pm->add(p);
-}
+extern "C" bool
+LLVMRustAddPass(LLVMPassManagerRef PM, const char *PassName) {
+    PassManagerBase *pm = unwrap(PM);
 
-extern "C" LLVMPassRef LLVMCreatePass(const char * PassName) {
     StringRef SR(PassName);
-    PassRegistry * PR = PassRegistry::getPassRegistry();
+    PassRegistry *PR = PassRegistry::getPassRegistry();
 
-    const PassInfo * PI = PR->getPassInfo(SR);
+    const PassInfo *PI = PR->getPassInfo(SR);
     if (PI) {
-        return wrap(PI->createPass());
-    } else {
-        return (LLVMPassRef)0;
+        pm->add(PI->createPass());
+        return true;
+    }
+    return false;
+}
+
+extern "C" LLVMTargetMachineRef
+LLVMRustCreateTargetMachine(const char *triple,
+                            const char *cpu,
+                            const char *feature,
+                            CodeModel::Model CM,
+                            Reloc::Model RM,
+                            CodeGenOpt::Level OptLevel,
+                            bool EnableSegmentedStacks) {
+    std::string Error;
+    Triple Trip(Triple::normalize(triple));
+    const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Trip.getTriple(),
+                                                                 Error);
+    if (TheTarget == NULL) {
+        LLVMRustError = Error.c_str();
+        return NULL;
+    }
+
+    TargetOptions Options;
+    Options.EnableSegmentedStacks = EnableSegmentedStacks;
+    Options.FixedStackSegmentSize = 2 * 1024 * 1024; // XXX: This is too big.
+    Options.FloatABIType =
+         (Trip.getEnvironment() == Triple::GNUEABIHF) ? FloatABI::Hard :
+                                                        FloatABI::Default;
+
+    TargetMachine *TM = TheTarget->createTargetMachine(Trip.getTriple(),
+                                                       cpu,
+                                                       feature,
+                                                       Options,
+                                                       RM,
+                                                       CM,
+                                                       OptLevel);
+    return wrap(TM);
+}
+
+extern "C" void
+LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
+    delete unwrap(TM);
+}
+
+// Unfortunately, LLVM doesn't expose a C API to add the corresponding analysis
+// passes for a target to a pass manager. We export that functionality through
+// this function.
+extern "C" void
+LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM,
+                          LLVMPassManagerRef PMR,
+                          LLVMModuleRef M) {
+    PassManagerBase *PM = unwrap(PMR);
+    PM->add(new DataLayout(unwrap(M)));
+    unwrap(TM)->addAnalysisPasses(*PM);
+}
+
+// Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo`
+// field of a PassManagerBuilder, we expose our own method of doing so.
+extern "C" void
+LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMB, LLVMModuleRef M) {
+    Triple TargetTriple(unwrap(M)->getTargetTriple());
+    unwrap(PMB)->LibraryInfo = new TargetLibraryInfo(TargetTriple);
+}
+
+// Unfortunately, the LLVM C API doesn't provide a way to create the
+// TargetLibraryInfo pass, so we use this method to do so.
+extern "C" void
+LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB, LLVMModuleRef M) {
+    Triple TargetTriple(unwrap(M)->getTargetTriple());
+    unwrap(PMB)->add(new TargetLibraryInfo(TargetTriple));
+}
+
+// Unfortunately, the LLVM C API doesn't provide an easy way of iterating over
+// all the functions in a module, so we do that manually here. You'll find
+// similar code in clang's BackendUtil.cpp file.
+extern "C" void
+LLVMRustRunFunctionPassManager(LLVMPassManagerRef PM, LLVMModuleRef M) {
+    FunctionPassManager *P = unwrap<FunctionPassManager>(PM);
+    P->doInitialization();
+    for (Module::iterator I = unwrap(M)->begin(),
+         E = unwrap(M)->end(); I != E; ++I)
+        if (!I->isDeclaration())
+            P->run(*I);
+    P->doFinalization();
+}
+
+extern "C" void
+LLVMRustSetLLVMOptions(bool PrintPasses,
+                       bool VectorizeLoops,
+                       bool VectorizeSLP,
+                       bool TimePasses) {
+    // Initializing the command-line options more than once is not allowed. So,
+    // check if they've already been initialized.  (This could happen if we're
+    // being called from rustpkg, for example). If the arguments change, then
+    // that's just kinda unfortunate.
+    static bool initialized = false;
+    if (initialized) return;
+
+    int argc = 3;
+    const char *argv[20] = {"rustc",
+                            "-arm-enable-ehabi",
+                            "-arm-enable-ehabi-descriptors"};
+    if (PrintPasses) {
+        argv[argc++] = "-debug-pass";
+        argv[argc++] = "Structure";
+    }
+    if (VectorizeLoops) {
+        argv[argc++] = "-vectorize-loops";
+    }
+    if (VectorizeSLP) {
+        argv[argc++] = "-vectorize-slp";
     }
+    if (TimePasses) {
+        argv[argc++] = "-time-passes";
+    }
+    cl::ParseCommandLineOptions(argc, argv);
+    initialized = true;
+}
+
+extern "C" bool
+LLVMRustWriteOutputFile(LLVMTargetMachineRef Target,
+                        LLVMPassManagerRef PMR,
+                        LLVMModuleRef M,
+                        const char *path,
+                        TargetMachine::CodeGenFileType FileType) {
+  PassManager *PM = unwrap<PassManager>(PMR);
+
+  std::string ErrorInfo;
+  raw_fd_ostream OS(path, ErrorInfo, sys::fs::F_Binary);
+  if (ErrorInfo != "") {
+    LLVMRustError = ErrorInfo.c_str();
+    return false;
+  }
+  formatted_raw_ostream FOS(OS);
+
+  unwrap(Target)->addPassesToEmitFile(*PM, FOS, FileType, false);
+  PM->run(*unwrap(M));
+  return true;
+}
+
+extern "C" void
+LLVMRustPrintModule(LLVMPassManagerRef PMR,
+                    LLVMModuleRef M,
+                    const char* path) {
+  PassManager *PM = unwrap<PassManager>(PMR);
+  std::string ErrorInfo;
+  raw_fd_ostream OS(path, ErrorInfo, sys::fs::F_Binary);
+  formatted_raw_ostream FOS(OS);
+  PM->add(createPrintModulePass(&FOS));
+  PM->run(*unwrap(M));
+}
+
+extern "C" void
+LLVMRustPrintPasses() {
+    LLVMInitializePasses();
+    struct MyListener : PassRegistrationListener {
+        void passEnumerate(const PassInfo *info) {
+            if (info->getPassArgument() && *info->getPassArgument()) {
+                printf("%15s - %s\n", info->getPassArgument(),
+                       info->getPassName());
+            }
+        }
+    } listener;
+
+    PassRegistry *PR = PassRegistry::getPassRegistry();
+    PR->enumerateWith(&listener);
 }
 
-extern "C" void LLVMDestroyPass(LLVMPassRef PassRef) {
-    Pass *p = unwrap(PassRef);
-    delete p;
+extern "C" void
+LLVMRustAddAlwaysInlinePass(LLVMPassManagerBuilderRef PMB, bool AddLifetimes) {
+    unwrap(PMB)->Inliner = createAlwaysInlinerPass(AddLifetimes);
 }