]> git.lizzy.rs Git - rust.git/commitdiff
Rewrite pass management with LLVM
authorAlex Crichton <alex@alexcrichton.com>
Fri, 23 Aug 2013 03:58:42 +0000 (20:58 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Tue, 27 Aug 2013 03:11:51 +0000 (20:11 -0700)
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`

12 files changed:
src/librustc/back/link.rs
src/librustc/back/passes.rs [deleted file]
src/librustc/driver/driver.rs
src/librustc/driver/session.rs
src/librustc/lib/llvm.rs
src/librustc/middle/trans/context.rs
src/librustc/rustc.rs
src/libstd/unstable/raw.rs
src/rustllvm/PassWrapper.cpp
src/rustllvm/RustWrapper.cpp
src/rustllvm/rustllvm.def.in
src/rustllvm/rustllvm.h

index db61042b9ff9893649da8ca5819c47c7028e6df1..ccebf88ec38b64bb69a982e54260f9aafcdc9f44 100644 (file)
@@ -27,7 +27,6 @@
 use std::hash::Streaming;
 use std::hash;
 use std::io;
-use std::libc::{c_int, c_uint};
 use std::os::consts::{macos, freebsd, linux, android, win32};
 use std::os;
 use std::ptr;
@@ -67,37 +66,19 @@ pub fn llvm_err(sess: Session, msg: ~str) -> ! {
     }
 }
 
-pub fn WriteOutputFile(sess: Session,
-        PM: lib::llvm::PassManagerRef, M: ModuleRef,
-        Triple: &str,
-        Cpu: &str,
-        Feature: &str,
+pub fn WriteOutputFile(
+        sess: Session,
+        Target: lib::llvm::TargetMachineRef,
+        PM: lib::llvm::PassManagerRef,
+        M: ModuleRef,
         Output: &str,
-        // FIXME: When #2334 is fixed, change
-        // c_uint to FileType
-        FileType: c_uint,
-        OptLevel: c_int,
-        EnableSegmentedStacks: bool) {
+        FileType: lib::llvm::FileType) {
     unsafe {
-        do Triple.with_c_str |Triple| {
-            do Cpu.with_c_str |Cpu| {
-                do Feature.with_c_str |Feature| {
-                    do Output.with_c_str |Output| {
-                        let result = llvm::LLVMRustWriteOutputFile(
-                                PM,
-                                M,
-                                Triple,
-                                Cpu,
-                                Feature,
-                                Output,
-                                FileType,
-                                OptLevel,
-                                EnableSegmentedStacks);
-                        if (!result) {
-                            llvm_err(sess, ~"Could not write output");
-                        }
-                    }
-                }
+        do Output.with_c_str |Output| {
+            let result = llvm::LLVMRustWriteOutputFile(
+                    Target, PM, M, Output, FileType);
+            if !result {
+                llvm_err(sess, ~"Could not write output");
             }
         }
     }
@@ -231,25 +212,15 @@ pub mod write {
     use driver::session::Session;
     use driver::session;
     use lib::llvm::llvm;
-    use lib::llvm::{ModuleRef, mk_pass_manager, mk_target_data};
-    use lib::llvm::{ContextRef};
+    use lib::llvm::{ModuleRef, ContextRef};
     use lib;
 
-    use back::passes;
-
     use std::c_str::ToCStr;
-    use std::libc::{c_int, c_uint};
+    use std::libc::c_uint;
     use std::path::Path;
     use std::run;
     use std::str;
 
-    pub fn is_object_or_assembly_or_exe(ot: output_type) -> bool {
-        match ot {
-            output_type_assembly | output_type_object | output_type_exe => true,
-            _ => false
-        }
-    }
-
     pub fn run_passes(sess: Session,
                       llcx: ContextRef,
                       llmod: ModuleRef,
@@ -258,163 +229,178 @@ pub fn run_passes(sess: Session,
         unsafe {
             llvm::LLVMInitializePasses();
 
-            let opts = sess.opts;
-            if sess.time_llvm_passes() { llvm::LLVMRustEnableTimePasses(); }
-            let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
-            let pm = mk_pass_manager();
-            llvm::LLVMAddTargetData(td.lltd, pm.llpm);
-
-            // Generate a pre-optimization intermediate file if -save-temps
-            // was specified.
-            if opts.save_temps {
-                match output_type {
-                  output_type_bitcode => {
-                    if opts.optimize != session::No {
-                        let filename = output.with_filetype("no-opt.bc");
-                        do filename.with_c_str |buf| {
-                            llvm::LLVMWriteBitcodeToFile(llmod, buf);
-                        }
-                    }
-                  }
-                  _ => {
-                    let filename = output.with_filetype("bc");
-                    do filename.with_c_str |buf| {
-                        llvm::LLVMWriteBitcodeToFile(llmod, buf);
-                    }
-                  }
+            // Only initialize the platforms supported by Rust here, because
+            // using --llvm-root will have multiple platforms that rustllvm
+            // doesn't actually link to and it's pointless to put target info
+            // into the registry that Rust can not generate machine code for.
+            llvm::LLVMInitializeX86TargetInfo();
+            llvm::LLVMInitializeX86Target();
+            llvm::LLVMInitializeX86TargetMC();
+            llvm::LLVMInitializeX86AsmPrinter();
+            llvm::LLVMInitializeX86AsmParser();
+
+            llvm::LLVMInitializeARMTargetInfo();
+            llvm::LLVMInitializeARMTarget();
+            llvm::LLVMInitializeARMTargetMC();
+            llvm::LLVMInitializeARMAsmPrinter();
+            llvm::LLVMInitializeARMAsmParser();
+
+            llvm::LLVMInitializeMipsTargetInfo();
+            llvm::LLVMInitializeMipsTarget();
+            llvm::LLVMInitializeMipsTargetMC();
+            llvm::LLVMInitializeMipsAsmPrinter();
+            llvm::LLVMInitializeMipsAsmParser();
+
+            if sess.opts.save_temps {
+                do output.with_filetype("no-opt.bc").with_c_str |buf| {
+                    llvm::LLVMWriteBitcodeToFile(llmod, buf);
                 }
             }
 
-            let mut mpm = passes::PassManager::new(td.lltd);
-
-            if !sess.no_verify() {
-                mpm.add_pass_from_name("verify");
-            }
+            // Copy what clan does by turning on loop vectorization at O2 and
+            // slp vectorization at O3
+            let vectorize_loop = !sess.no_vectorize_loops() &&
+                                 (sess.opts.optimize == session::Default ||
+                                  sess.opts.optimize == session::Aggressive);
+            let vectorize_slp = !sess.no_vectorize_slp() &&
+                                sess.opts.optimize == session::Aggressive;
+            llvm::LLVMRustSetLLVMOptions(sess.print_llvm_passes(),
+                                         vectorize_loop,
+                                         vectorize_slp,
+                                         sess.time_llvm_passes());
+
+            let OptLevel = match sess.opts.optimize {
+              session::No => lib::llvm::CodeGenLevelNone,
+              session::Less => lib::llvm::CodeGenLevelLess,
+              session::Default => lib::llvm::CodeGenLevelDefault,
+              session::Aggressive => lib::llvm::CodeGenLevelAggressive,
+            };
 
-            let passes = if sess.opts.custom_passes.len() > 0 {
-                sess.opts.custom_passes.clone()
-            } else {
-                if sess.lint_llvm() {
-                    mpm.add_pass_from_name("lint");
+            let tm = do sess.targ_cfg.target_strs.target_triple.with_c_str |T| {
+                do sess.opts.target_cpu.with_c_str |CPU| {
+                    do sess.opts.target_feature.with_c_str |Features| {
+                        llvm::LLVMRustCreateTargetMachine(
+                            T, CPU, Features,
+                            lib::llvm::CodeModelDefault,
+                            lib::llvm::RelocPIC,
+                            OptLevel,
+                            true
+                        )
+                    }
                 }
-                passes::create_standard_passes(opts.optimize)
             };
 
+            // Create the two optimizing pass managers. These mirror what clang
+            // does, and are by populated by LLVM's default PassManagerBuilder.
+            // Each manager has a different set of passes, but they also share
+            // some common passes. Each one is initialized with the analyis
+            // passes the target requires, and then further passes are added.
+            let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
+            let mpm = llvm::LLVMCreatePassManager();
+            llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
+            llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
+
+            // If we're verifying or linting, add them to the function pass
+            // manager.
+            let addpass = |pass: &str| {
+                do pass.with_c_str |s| { llvm::LLVMRustAddPass(fpm, s) }
+            };
+            if !sess.no_verify() { assert!(addpass("verify")); }
+            if sess.lint_llvm()  { assert!(addpass("lint"));   }
+
+            // Create the PassManagerBuilder for LLVM. We configure it with
+            // reasonable defaults and prepare it to actually populate the pass
+            // manager.
+            let builder = llvm::LLVMPassManagerBuilderCreate();
+            match sess.opts.optimize {
+                session::No => {
+                    // Don't add lifetime intrinsics add O0
+                    llvm::LLVMRustAddAlwaysInlinePass(builder, false);
+                }
+                // numeric values copied from clang
+                session::Less => {
+                    llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
+                                                                        225);
+                }
+                session::Default | session::Aggressive => {
+                    llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
+                                                                        275);
+                }
+            }
+            llvm::LLVMPassManagerBuilderSetOptLevel(builder, OptLevel as c_uint);
+            llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod);
+
+            // Use the builder to populate the function/module pass managers.
+            llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
+            llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
+            llvm::LLVMPassManagerBuilderDispose(builder);
+
+            for pass in sess.opts.custom_passes.iter() {
+                do pass.with_c_str |s| {
+                    if !llvm::LLVMRustAddPass(mpm, s) {
+                        sess.warn(fmt!("Unknown pass %s, ignoring", *pass));
+                    }
+                }
+            }
+
+            // Finally, run the actual optimization passes
+            llvm::LLVMRustRunFunctionPassManager(fpm, llmod);
+            llvm::LLVMRunPassManager(mpm, llmod);
 
-            debug!("Passes: %?", passes);
-            passes::populate_pass_manager(sess, &mut mpm, passes);
+            // Deallocate managers that we're now done with
+            llvm::LLVMDisposePassManager(fpm);
+            llvm::LLVMDisposePassManager(mpm);
 
-            debug!("Running Module Optimization Pass");
-            mpm.run(llmod);
+            if sess.opts.save_temps {
+                do output.with_filetype("bc").with_c_str |buf| {
+                    llvm::LLVMWriteBitcodeToFile(llmod, buf);
+                }
+            }
 
-            if opts.jit {
+            if sess.opts.jit {
                 // If we are using JIT, go ahead and create and execute the
-                // engine now.  JIT execution takes ownership of the module and
-                // context, so don't dispose and return.
+                // engine now. JIT execution takes ownership of the module and
+                // context, so don't dispose
                 jit::exec(sess, llcx, llmod, true);
+            } else {
+                // Create a codegen-specific pass manager to emit the actual
+                // assembly or object files. This may not end up getting used,
+                // but we make it anyway for good measure.
+                let cpm = llvm::LLVMCreatePassManager();
+                llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
+                llvm::LLVMRustAddLibraryInfo(cpm, llmod);
 
-                if sess.time_llvm_passes() {
-                    llvm::LLVMRustPrintPassTimings();
-                }
-                return;
-            } else if is_object_or_assembly_or_exe(output_type) {
-                let LLVMOptNone       = 0 as c_int; // -O0
-                let LLVMOptLess       = 1 as c_int; // -O1
-                let LLVMOptDefault    = 2 as c_int; // -O2, -Os
-                let LLVMOptAggressive = 3 as c_int; // -O3
-
-                let CodeGenOptLevel = match opts.optimize {
-                  session::No => LLVMOptNone,
-                  session::Less => LLVMOptLess,
-                  session::Default => LLVMOptDefault,
-                  session::Aggressive => LLVMOptAggressive
-                };
-
-                let FileType = match output_type {
-                    output_type_object | output_type_exe => lib::llvm::ObjectFile,
-                    _ => lib::llvm::AssemblyFile
-                };
-
-                // Write optimized bitcode if --save-temps was on.
-
-                if opts.save_temps {
-                    // Always output the bitcode file with --save-temps
-
-                    let filename = output.with_filetype("opt.bc");
-                    do filename.with_c_str |buf| {
-                        llvm::LLVMWriteBitcodeToFile(llmod, buf)
-                    };
-                    // Save the assembly file if -S is used
-                    if output_type == output_type_assembly {
-                        WriteOutputFile(
-                            sess,
-                            pm.llpm,
-                            llmod,
-                            sess.targ_cfg.target_strs.target_triple,
-                            opts.target_cpu,
-                            opts.target_feature,
-                            output.to_str(),
-                            lib::llvm::AssemblyFile as c_uint,
-                            CodeGenOptLevel,
-                            true);
+                match output_type {
+                    output_type_none => {}
+                    output_type_bitcode => {
+                        do output.with_c_str |buf| {
+                            llvm::LLVMWriteBitcodeToFile(llmod, buf);
+                        }
                     }
-
-                    // Save the object file for -c or --save-temps alone
-                    // This .o is needed when an exe is built
-                    if output_type == output_type_object ||
-                           output_type == output_type_exe {
-                        WriteOutputFile(
-                            sess,
-                            pm.llpm,
-                            llmod,
-                            sess.targ_cfg.target_strs.target_triple,
-                            opts.target_cpu,
-                            opts.target_feature,
-                            output.to_str(),
-                            lib::llvm::ObjectFile as c_uint,
-                            CodeGenOptLevel,
-                            true);
+                    output_type_llvm_assembly => {
+                        do output.with_c_str |output| {
+                            llvm::LLVMRustPrintModule(cpm, llmod, output)
+                        }
+                    }
+                    output_type_assembly => {
+                        WriteOutputFile(sess, tm, cpm, llmod, output.to_str(),
+                                        lib::llvm::AssemblyFile);
+                    }
+                    output_type_exe | output_type_object => {
+                        WriteOutputFile(sess, tm, cpm, llmod, output.to_str(),
+                                        lib::llvm::ObjectFile);
                     }
-                } else {
-                    // If we aren't saving temps then just output the file
-                    // type corresponding to the '-c' or '-S' flag used
-                    WriteOutputFile(
-                        sess,
-                        pm.llpm,
-                        llmod,
-                        sess.targ_cfg.target_strs.target_triple,
-                        opts.target_cpu,
-                        opts.target_feature,
-                        output.to_str(),
-                        FileType as c_uint,
-                        CodeGenOptLevel,
-                        true);
                 }
-                // Clean up and return
 
-                llvm::LLVMDisposeModule(llmod);
-                llvm::LLVMContextDispose(llcx);
-                if sess.time_llvm_passes() {
-                    llvm::LLVMRustPrintPassTimings();
-                }
-                return;
+                llvm::LLVMDisposePassManager(cpm);
             }
 
-            if output_type == output_type_llvm_assembly {
-                // Given options "-S --emit-llvm": output LLVM assembly
-                do output.with_c_str |buf_o| {
-                    llvm::LLVMRustAddPrintModulePass(pm.llpm, llmod, buf_o);
-                }
-            } else {
-                // If only a bitcode file is asked for by using the
-                // '--emit-llvm' flag, then output it here
-                do output.with_c_str |buf| {
-                    llvm::LLVMWriteBitcodeToFile(llmod, buf);
-                }
+            llvm::LLVMRustDisposeTargetMachine(tm);
+            // the jit takes ownership of these two items
+            if !sess.opts.jit {
+                llvm::LLVMDisposeModule(llmod);
+                llvm::LLVMContextDispose(llcx);
             }
-
-            llvm::LLVMDisposeModule(llmod);
-            llvm::LLVMContextDispose(llcx);
             if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
         }
     }
diff --git a/src/librustc/back/passes.rs b/src/librustc/back/passes.rs
deleted file mode 100644 (file)
index bb5ddc1..0000000
+++ /dev/null
@@ -1,349 +0,0 @@
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::c_str::ToCStr;
-use std::io;
-
-use driver::session::{OptLevel, No, Less, Aggressive};
-use driver::session::{Session};
-use lib::llvm::{PassRef, ModuleRef,PassManagerRef,TargetDataRef};
-use lib::llvm::llvm;
-use lib;
-
-pub struct PassManager {
-    priv llpm: PassManagerRef
-}
-
-impl Drop for PassManager {
-    fn drop(&self) {
-        unsafe {
-            llvm::LLVMDisposePassManager(self.llpm);
-        }
-    }
-}
-
-impl PassManager {
-    pub fn new(td: TargetDataRef) -> PassManager {
-        unsafe {
-            let pm = PassManager {
-                llpm: llvm::LLVMCreatePassManager()
-            };
-            llvm::LLVMAddTargetData(td, pm.llpm);
-
-            return pm;
-        }
-    }
-
-    pub fn add_pass(&mut self, pass:PassRef) {
-        unsafe {
-            llvm::LLVMAddPass(self.llpm, pass);
-        }
-    }
-
-    pub fn add_pass_from_name(&mut self, name:&str) {
-        let pass = create_pass(name).unwrap();
-        self.add_pass(pass);
-    }
-
-    pub fn run(&self, md:ModuleRef) -> bool {
-        unsafe {
-            llvm::LLVMRunPassManager(self.llpm, md) == lib::llvm::True
-        }
-    }
-}
-
-pub fn create_standard_passes(level: OptLevel) -> ~[~str] {
-    let mut passes = ~[];
-
-    // mostly identical to clang 3.3, all differences are documented with comments
-
-    if level != No {
-        passes.push(~"targetlibinfo");
-        passes.push(~"no-aa");
-        // "tbaa" omitted, we don't emit clang-style type-based alias analysis information
-        passes.push(~"basicaa");
-        passes.push(~"globalopt");
-        passes.push(~"ipsccp");
-        passes.push(~"deadargelim");
-        passes.push(~"instcombine");
-        passes.push(~"simplifycfg");
-    }
-
-    passes.push(~"basiccg");
-
-    if level != No {
-        passes.push(~"prune-eh");
-    }
-
-    passes.push(~"inline-cost");
-
-    if level == No || level == Less {
-        passes.push(~"always-inline");
-    } else {
-        passes.push(~"inline");
-    }
-
-    if level != No {
-        passes.push(~"functionattrs");
-        if level == Aggressive {
-            passes.push(~"argpromotion");
-        }
-        passes.push(~"sroa");
-        passes.push(~"domtree");
-        passes.push(~"early-cse");
-        passes.push(~"lazy-value-info");
-        passes.push(~"jump-threading");
-        passes.push(~"correlated-propagation");
-        passes.push(~"simplifycfg");
-        passes.push(~"instcombine");
-        passes.push(~"tailcallelim");
-        passes.push(~"simplifycfg");
-        passes.push(~"reassociate");
-        passes.push(~"domtree");
-        passes.push(~"loops");
-        passes.push(~"loop-simplify");
-        passes.push(~"lcssa");
-        passes.push(~"loop-rotate");
-        passes.push(~"licm");
-        passes.push(~"lcssa");
-        passes.push(~"loop-unswitch");
-        passes.push(~"instcombine");
-        passes.push(~"scalar-evolution");
-        passes.push(~"loop-simplify");
-        passes.push(~"lcssa");
-        passes.push(~"indvars");
-        passes.push(~"loop-idiom");
-        passes.push(~"loop-deletion");
-        if level == Aggressive {
-            passes.push(~"loop-simplify");
-            passes.push(~"lcssa");
-            passes.push(~"loop-vectorize");
-            passes.push(~"loop-simplify");
-            passes.push(~"lcssa");
-            passes.push(~"scalar-evolution");
-            passes.push(~"loop-simplify");
-            passes.push(~"lcssa");
-        }
-        if level != Less {
-            passes.push(~"loop-unroll");
-            passes.push(~"memdep");
-            passes.push(~"gvn");
-        }
-        passes.push(~"memdep");
-        passes.push(~"memcpyopt");
-        passes.push(~"sccp");
-        passes.push(~"instcombine");
-        passes.push(~"lazy-value-info");
-        passes.push(~"jump-threading");
-        passes.push(~"correlated-propagation");
-        passes.push(~"domtree");
-        passes.push(~"memdep");
-        passes.push(~"dse");
-        passes.push(~"adce");
-        passes.push(~"simplifycfg");
-        passes.push(~"instcombine");
-        // clang does `strip-dead-prototypes` here, since it does not emit them
-    }
-
-    // rustc emits dead prototypes, so always ask LLVM to strip them
-    passes.push(~"strip-dead-prototypes");
-
-    if level != Less {
-        passes.push(~"globaldce");
-        passes.push(~"constmerge");
-    }
-
-    passes
-}
-
-pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) {
-    for nm in pass_list.iter() {
-        match create_pass(*nm) {
-            Some(p) => pm.add_pass(p),
-            None    => sess.warn(fmt!("Unknown pass %s", *nm))
-        }
-    }
-}
-
-pub fn create_pass(name:&str) -> Option<PassRef> {
-    do name.with_c_str |s| {
-        unsafe {
-            let p = llvm::LLVMCreatePass(s);
-            if p.is_null() {
-                None
-            } else {
-                Some(p)
-            }
-        }
-    }
-}
-
-pub fn list_passes() {
-    io::println("\nAvailable Passes:");
-
-    io::println("\nAnalysis Passes:");
-    for &(name, desc) in analysis_passes.iter() {
-        printfln!("    %-30s -- %s", name, desc);
-    }
-    io::println("\nTransformation Passes:");
-    for &(name, desc) in transform_passes.iter() {
-        printfln!("    %-30s -- %s", name, desc);
-    }
-    io::println("\nUtility Passes:");
-    for &(name, desc) in utility_passes.iter() {
-        printfln!("    %-30s -- %s", name, desc);
-    }
-}
-
-/** Analysis Passes */
-pub static analysis_passes : &'static [(&'static str, &'static str)] = &'static [
-    ("aa-eval",                         "Exhausive Alias Analysis Precision Evaluator"),
-    ("asan",                            "AddressSanitizer"),
-    ("basicaa",                         "Basic Alias Analysis"),
-    ("basiccg",                         "Basic CallGraph Construction"),
-    ("block-freq",                      "Block Frequency Analysis"),
-    ("cost-model",                      "Cost Model Analysis"),
-    ("count-aa",                        "Count Alias Analysis Query Responses"),
-    ("da",                              "Dependence Analysis"),
-    ("debug-aa",                        "AA Use Debugger"),
-    ("domfrontier",                     "Dominance Frontier Construction"),
-    ("domtree",                         "Dominator Tree Construction"),
-    ("globalsmodref-aa",                "Simple mod/ref analysis for globals"),
-    ("instcount",                       "Count the various types of Instructions"),
-    ("intervals",                       "Interval Partition Construction"),
-    ("iv-users",                        "Induction Variable Users"),
-    ("lazy-value-info",                 "Lazy Value Information Analysis"),
-    ("libcall-aa",                      "LibCall Alias Analysis"),
-    ("lint",                            "Statically lint-check LLVM IR"),
-    ("loops",                           "Natural Loop Information"),
-    ("memdep",                          "Memory Dependence Analysis"),
-    ("module-debuginfo",                "Decodes module-level debug info"),
-    ("profile-estimator",               "Estimate profiling information"),
-    ("profile-loader",                  "Load profile information from llvmprof.out"),
-    ("profile-verifier",                "Verify profiling information"),
-    ("regions",                         "Detect single entry single exit regions"),
-    ("scalar-evolution",                "Scalar Evolution Analysis"),
-    ("scev-aa",                         "Scalar Evolution-based Alias Analysis"),
-    ("tbaa",                            "Type-Based Alias Analysis"),
-    ("tsan",                            "ThreadSanitizer"),
-];
-
-/** Transformation Passes */
-pub static transform_passes : &'static [(&'static str, &'static str)] = &'static [
-    ("adce",                            "Aggressive Dead Code Elimination"),
-    ("always-inline",                   "Inliner for #[inline] functions"),
-    ("argpromotion",                    "Promote 'by reference' arguments to scalars"),
-    ("bb-vectorize",                    "Basic-Block Vectorization"),
-    ("block-placement",                 "Profile Guided Basic Block Placement"),
-    ("bounds-checking",                 "Run-time bounds checking"),
-    ("break-crit-edges",                "Break critical edges in CFG"),
-    ("codegenprepare",                  "Optimize for code generation"),
-    ("constmerge",                      "Merge Duplicate Global Constants"),
-    ("constprop",                       "Simple constant propagation"),
-    ("correlated-propagation",          "Value Propagation"),
-    ("da",                              "Data Layout"),
-    ("dce",                             "Dead Code Elimination"),
-    ("deadargelim",                     "Dead Argument Elimination"),
-    ("die",                             "Dead Instruction Elimination"),
-    ("dse",                             "Dead Store Elimination"),
-    ("early-cse",                       "Early CSE"),
-    ("functionattrs",                   "Deduce function attributes"),
-    ("globaldce",                       "Dead Global Elimination"),
-    ("globalopt",                       "Global Variable Optimizer"),
-    ("gvn",                             "Global Value Numbering"),
-    ("indvars",                         "Canonicalize Induction Variables"),
-    ("inline",                          "Function Integration/Inlining"),
-    ("insert-edge-profiling",           "Insert instrumentation for edge profiling"),
-    ("insert-gcov-profiling",           "Insert instrumentation for GCOV profiling"),
-    ("insert-optimal-edge-profiling",   "Insert optimal instrumentation for edge profiling"),
-    ("instcombine",                     "Combine redundant instructions"),
-    ("instsimplify",                    "Remove redundant instructions"),
-    ("ipconstprop",                     "Interprocedural constant propagation"),
-    ("ipsccp",                          "Interprocedural Sparse Conditional Constant Propagation"),
-    ("jump-threading",                  "Jump Threading"),
-    ("lcssa",                           "Loop-Closed SSA Form Pass"),
-    ("licm",                            "Loop Invariant Code Motion"),
-    ("loop-deletion",                   "Delete dead loops"),
-    ("loop-extract",                    "Extract loops into new functions"),
-    ("loop-extract-single",             "Extract at most one loop into a new function"),
-    ("loop-idiom",                      "Recognise loop idioms"),
-    ("loop-instsimplify",               "Simplify instructions in loops"),
-    ("loop-reduce",                     "Loop Strength Reduction"),
-    ("loop-rotate",                     "Rotate Loops"),
-    ("loop-simplify",                   "Canonicalize natural loops"),
-    ("loop-unroll",                     "Unroll loops"),
-    ("loop-unswitch",                   "Unswitch loops"),
-    ("loop-vectorize",                  "Loop Vectorization"),
-    ("lower-expect",                    "Lower 'expect' Intrinsics"),
-    ("mem2reg",                         "Promote Memory to Register"),
-    ("memcpyopt",                       "MemCpy Optimization"),
-    ("mergefunc",                       "Merge Functions"),
-    ("mergereturn",                     "Unify function exit nodes"),
-    ("partial-inliner",                 "Partial Inliner"),
-    ("prune-eh",                        "Remove unused exception handling info"),
-    ("reassociate",                     "Reassociate expressions"),
-    ("reg2mem",                         "Demote all values to stack slots"),
-    ("scalarrepl",                      "Scalar Replacement of Aggregates (DT)"),
-    ("scalarrepl-ssa",                  "Scalar Replacement of Aggregates (SSAUp)"),
-    ("sccp",                            "Sparse Conditional Constant Propagation"),
-    ("simplifycfg",                     "Simplify the CFG"),
-    ("sink",                            "Code sinking"),
-    ("strip",                           "Strip all symbols from a module"),
-    ("strip-dead-debug-info",           "Strip debug info for unused symbols"),
-    ("strip-dead-prototypes",           "Strip Unused Function Prototypes"),
-    ("strip-debug-declare",             "Strip all llvm.dbg.declare intrinsics"),
-    ("strip-nondebug",                  "Strip all symbols, except dbg symbols, from a module"),
-    ("sroa",                            "Scalar Replacement of Aggregates"),
-    ("tailcallelim",                    "Tail Call Elimination"),
-];
-
-/** Utility Passes */
-static utility_passes : &'static [(&'static str, &'static str)] = &'static [
-    ("instnamer",                       "Assign names to anonymous instructions"),
-    ("verify",                          "Module Verifier"),
-];
-
-#[test]
-fn passes_exist() {
-    let mut failed = ~[];
-    unsafe { llvm::LLVMInitializePasses(); }
-    for &(name,_) in analysis_passes.iter() {
-        let pass = create_pass(name);
-        if !pass.is_some() {
-            failed.push(name);
-        } else {
-            unsafe { llvm::LLVMDestroyPass(pass.unwrap()) }
-        }
-    }
-    for &(name,_) in transform_passes.iter() {
-        let pass = create_pass(name);
-        if !pass.is_some() {
-            failed.push(name);
-        } else {
-            unsafe { llvm::LLVMDestroyPass(pass.unwrap()) }
-        }
-    }
-    for &(name,_) in utility_passes.iter() {
-        let pass = create_pass(name);
-        if !pass.is_some() {
-            failed.push(name);
-        } else {
-            unsafe { llvm::LLVMDestroyPass(pass.unwrap()) }
-        }
-    }
-
-    if failed.len() > 0 {
-        io::println("Some passes don't exist:");
-        for &n in failed.iter() {
-            printfln!("    %s", n);
-        }
-        fail!();
-    }
-}
index e0c5a729b3f88116804e629eb3c7df6b9d890cdc..003840b85a16744b063e9fe57bf8c4785be398cf 100644 (file)
@@ -848,8 +848,9 @@ pub fn optgroups() -> ~[getopts::groups::OptGroup] {
   optopt("", "opt-level",
                         "Optimize with possible levels 0-3", "LEVEL"),
   optopt("", "passes", "Comma or space separated list of pass names to use. \
-                        Overrides the default passes for optimization levels,\n\
-                        a value of \"list\" will list the available passes.", "NAMES"),
+                        Appends to the default list of passes to run for the \
+                        specified current optimization level. A value of \
+                        \"list\" will list all of the available passes", "NAMES"),
   optopt( "",  "out-dir",
                         "Write output to compiler-chosen filename
                           in <dir>", "DIR"),
index 50b29ff16be1a5a456be92758cc2477a24b63af8..912fc606f0a344d6e126c4f39c561002c0970b81 100644 (file)
@@ -76,6 +76,9 @@ pub struct config {
 pub static no_debug_borrows:        uint = 1 << 24;
 pub static lint_llvm:               uint = 1 << 25;
 pub static once_fns:                uint = 1 << 26;
+pub static print_llvm_passes:       uint = 1 << 27;
+pub static no_vectorize_loops:      uint = 1 << 28;
+pub static no_vectorize_slp:        uint = 1 << 29;
 
 pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
     ~[(~"verbose", ~"in general, enable more debug printouts", verbose),
@@ -120,6 +123,15 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
      (~"once-fns",
       ~"Allow 'once fn' closures to deinitialize captured variables",
       once_fns),
+     (~"print-llvm-passes",
+      ~"Prints the llvm optimization passes being run",
+      print_llvm_passes),
+     (~"no-vectorize-loops",
+      ~"Don't run the loop vectorization optimization passes",
+      no_vectorize_loops),
+     (~"no-vectorize-slp",
+      ~"Don't run LLVM's SLP vectorization passes",
+      no_vectorize_slp),
     ]
 }
 
@@ -305,6 +317,15 @@ pub fn debug_borrows(@self) -> bool {
         self.opts.optimize == No && !self.debugging_opt(no_debug_borrows)
     }
     pub fn once_fns(@self) -> bool { self.debugging_opt(once_fns) }
+    pub fn print_llvm_passes(@self) -> bool {
+        self.debugging_opt(print_llvm_passes)
+    }
+    pub fn no_vectorize_loops(@self) -> bool {
+        self.debugging_opt(no_vectorize_loops)
+    }
+    pub fn no_vectorize_slp(@self) -> bool {
+        self.debugging_opt(no_vectorize_slp)
+    }
 
     // pointless function, now...
     pub fn str_of(@self, id: ast::ident) -> @str {
index 60f8a1773fc84a59b1514bbcfcce11778f73278a..220b082fab1cf986fd7fa8318a3f853b1d50d4f5 100644 (file)
@@ -170,7 +170,6 @@ pub enum AtomicOrdering {
     SequentiallyConsistent = 7
 }
 
-// FIXME: Not used right now, but will be once #2334 is fixed
 // Consts for the LLVMCodeGenFileType type (in include/llvm/c/TargetMachine.h)
 pub enum FileType {
     AssemblyFile = 0,
@@ -192,6 +191,29 @@ pub enum AsmDialect {
     AD_Intel = 1
 }
 
+pub enum CodeGenOptLevel {
+    CodeGenLevelNone = 0,
+    CodeGenLevelLess = 1,
+    CodeGenLevelDefault = 2,
+    CodeGenLevelAggressive = 3,
+}
+
+pub enum RelocMode {
+    RelocDefault = 0,
+    RelocStatic = 1,
+    RelocPIC = 2,
+    RelocDynamicNoPic = 3,
+}
+
+pub enum CodeGenModel {
+    CodeModelDefault = 0,
+    CodeModelJITDefault = 1,
+    CodeModelSmall = 2,
+    CodeModelKernel = 3,
+    CodeModelMedium = 4,
+    CodeModelLarge = 5,
+}
+
 // Opaque pointer types
 pub enum Module_opaque {}
 pub type ModuleRef = *Module_opaque;
@@ -223,6 +245,8 @@ pub enum SectionIterator_opaque {}
 pub type SectionIteratorRef = *SectionIterator_opaque;
 pub enum Pass_opaque {}
 pub type PassRef = *Pass_opaque;
+pub enum TargetMachine_opaque {}
+pub type TargetMachineRef = *TargetMachine_opaque;
 
 pub mod debuginfo {
     use super::{ValueRef};
@@ -266,7 +290,8 @@ pub mod llvm {
     use super::{Bool, BuilderRef, ContextRef, MemoryBufferRef, ModuleRef};
     use super::{ObjectFileRef, Opcode, PassManagerRef, PassManagerBuilderRef};
     use super::{SectionIteratorRef, TargetDataRef, TypeKind, TypeRef, UseRef};
-    use super::{ValueRef, PassRef};
+    use super::{ValueRef, TargetMachineRef, FileType};
+    use super::{CodeGenModel, RelocMode, CodeGenOptLevel};
     use super::debuginfo::*;
     use std::libc::{c_char, c_int, c_longlong, c_ushort, c_uint, c_ulonglong};
 
@@ -1614,6 +1639,7 @@ pub fn LLVMCallFrameAlignmentOfType(TD: TargetDataRef, Ty: TypeRef)
         /** Creates a pass manager. */
         #[fast_ffi]
         pub fn LLVMCreatePassManager() -> PassManagerRef;
+
         /** Creates a function-by-function pass manager */
         #[fast_ffi]
         pub fn LLVMCreateFunctionPassManagerForModule(M: ModuleRef)
@@ -1643,15 +1669,6 @@ pub fn LLVMRunFunctionPassManager(FPM: PassManagerRef, F: ValueRef)
         #[fast_ffi]
         pub fn LLVMInitializePasses();
 
-        #[fast_ffi]
-        pub fn LLVMAddPass(PM: PassManagerRef, P: PassRef);
-
-        #[fast_ffi]
-        pub fn LLVMCreatePass(PassName: *c_char) -> PassRef;
-
-        #[fast_ffi]
-        pub fn LLVMDestroyPass(P: PassRef);
-
         /** Adds a verification pass. */
         #[fast_ffi]
         pub fn LLVMAddVerifierPass(PM: PassManagerRef);
@@ -1808,20 +1825,6 @@ pub fn LLVMIsSectionIteratorAtEnd(ObjFile: ObjectFileRef,
         pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(Path: *c_char)
             -> MemoryBufferRef;
 
-        #[fast_ffi]
-        pub fn LLVMRustWriteOutputFile(PM: PassManagerRef,
-                                       M: ModuleRef,
-                                       Triple: *c_char,
-                                       Cpu: *c_char,
-                                       Feature: *c_char,
-                                       Output: *c_char,
-                                       // FIXME: When #2334 is fixed,
-                                       // change c_uint to FileType
-                                       FileType: c_uint,
-                                       OptLevel: c_int,
-                                       EnableSegmentedStacks: bool)
-                                       -> bool;
-
         /** Returns a string describing the last error caused by an LLVMRust*
             call. */
         #[fast_ffi]
@@ -1842,24 +1845,6 @@ pub fn LLVMRustBuildJIT(MM: *(),
                                 EnableSegmentedStacks: bool)
                                 -> ExecutionEngineRef;
 
-        /** Parses the bitcode in the given memory buffer. */
-        #[fast_ffi]
-        pub fn LLVMRustParseBitcode(MemBuf: MemoryBufferRef) -> ModuleRef;
-
-        /** Parses LLVM asm in the given file */
-        #[fast_ffi]
-        pub fn LLVMRustParseAssemblyFile(Filename: *c_char, C: ContextRef)
-                                         -> ModuleRef;
-
-        #[fast_ffi]
-        pub fn LLVMRustAddPrintModulePass(PM: PassManagerRef,
-                                          M: ModuleRef,
-                                          Output: *c_char);
-
-        /** Turn on LLVM pass-timing. */
-        #[fast_ffi]
-        pub fn LLVMRustEnableTimePasses();
-
         /// Print the pass timings since static dtors aren't picking them up.
         #[fast_ffi]
         pub fn LLVMRustPrintPassTimings();
@@ -2097,6 +2082,55 @@ pub fn LLVMDIBuilderCreateTemplateTypeParameter(Builder: DIBuilderRef,
                                                         LineNo: c_uint,
                                                         ColumnNo: c_uint)
                                                         -> ValueRef;
+
+        pub fn LLVMInitializeX86TargetInfo();
+        pub fn LLVMInitializeX86Target();
+        pub fn LLVMInitializeX86TargetMC();
+        pub fn LLVMInitializeX86AsmPrinter();
+        pub fn LLVMInitializeX86AsmParser();
+        pub fn LLVMInitializeARMTargetInfo();
+        pub fn LLVMInitializeARMTarget();
+        pub fn LLVMInitializeARMTargetMC();
+        pub fn LLVMInitializeARMAsmPrinter();
+        pub fn LLVMInitializeARMAsmParser();
+        pub fn LLVMInitializeMipsTargetInfo();
+        pub fn LLVMInitializeMipsTarget();
+        pub fn LLVMInitializeMipsTargetMC();
+        pub fn LLVMInitializeMipsAsmPrinter();
+        pub fn LLVMInitializeMipsAsmParser();
+
+        pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: *c_char) -> bool;
+        pub fn LLVMRustCreateTargetMachine(Triple: *c_char,
+                                           CPU: *c_char,
+                                           Features: *c_char,
+                                           Model: CodeGenModel,
+                                           Reloc: RelocMode,
+                                           Level: CodeGenOptLevel,
+                                           EnableSegstk: bool) -> TargetMachineRef;
+        pub fn LLVMRustDisposeTargetMachine(T: TargetMachineRef);
+        pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef,
+                                         PM: PassManagerRef,
+                                         M: ModuleRef);
+        pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef,
+                                             M: ModuleRef);
+        pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef);
+        pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef);
+        pub fn LLVMRustWriteOutputFile(T: TargetMachineRef,
+                                       PM: PassManagerRef,
+                                       M: ModuleRef,
+                                       Output: *c_char,
+                                       FileType: FileType) -> bool;
+        pub fn LLVMRustPrintModule(PM: PassManagerRef,
+                                   M: ModuleRef,
+                                   Output: *c_char);
+        pub fn LLVMRustSetLLVMOptions(PrintPasses: bool,
+                                      VectorizeLoops: bool,
+                                      VectorizeSLP: bool,
+                                      TimePasses: bool);
+        pub fn LLVMRustPrintPasses();
+        pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *c_char);
+        pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef,
+                                           AddLifetimes: bool);
     }
 }
 
@@ -2244,7 +2278,6 @@ pub fn val_to_str(&self, val: ValueRef) -> ~str {
     }
 }
 
-
 /* Memory-managed interface to target data. */
 
 pub struct target_data_res {
index 1318ef2c8958db24cc07975df24b20df018846fe..9f99a0c92e534b12d77e56decf1aa87fc5df230f 100644 (file)
@@ -137,7 +137,7 @@ pub fn new(sess: session::Session,
                 llvm::LLVMSetDataLayout(llmod, buf)
             };
             do targ_triple.with_c_str |buf| {
-                llvm::LLVMSetTarget(llmod, buf)
+                llvm::LLVMRustSetNormalizedTarget(llmod, buf)
             };
             let targ_cfg = sess.targ_cfg;
 
index 33407c91bcc23b1a7a034cb305514b5b83dcde2e..06b3f6aae2710b142f11e20b24d16e6b2e85e7fd 100644 (file)
@@ -92,7 +92,6 @@ pub mod back {
     pub mod x86_64;
     pub mod rpath;
     pub mod target_strs;
-    pub mod passes;
 }
 
 pub mod metadata;
@@ -232,7 +231,7 @@ pub fn run_compiler(args: &[~str], demitter: diagnostic::Emitter) {
     }
 
     if getopts::opt_maybe_str(matches, "passes") == Some(~"list") {
-        back::passes::list_passes();
+        unsafe { lib::llvm::llvm::LLVMRustPrintPasses(); }
         return;
     }
 
index bdf84604fb37f852bf3898ba49efe3d800c996b6..a538566fa189822b1da848a41208098a025df4ea 100644 (file)
@@ -57,6 +57,7 @@ impl<'self> Repr<Slice<u8>> for &'self str {}
 impl<T> Repr<*Box<T>> for @T {}
 impl<T> Repr<*Box<Vec<T>>> for @[T] {}
 impl Repr<*String> for ~str {}
+impl Repr<*Box<String>> for @str {}
 
 // sure would be nice to have this
 // impl<T> Repr<*Vec<T>> for ~[T] {}
index 32b6df4e1dd595c572d1cab9a45b3731750798aa..56ba56cf89377fb2ea265ce1dca82df995bb5c70 100644 (file)
@@ -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);
 }
index 5b8c6bc883fb58816048478556e8d66da2e39303..40ee486ec2d9c6a2906e75f4ce132bc58024b1d1 100644 (file)
@@ -20,9 +20,7 @@
 using namespace llvm;
 using namespace llvm::sys;
 
-static const char *LLVMRustError;
-
-extern cl::opt<bool> EnableARMEHABI;
+const char *LLVMRustError;
 
 extern "C" LLVMMemoryBufferRef
 LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) {
@@ -36,62 +34,6 @@ extern "C" const char *LLVMRustGetLastError(void) {
   return LLVMRustError;
 }
 
-extern "C" void LLVMAddBasicAliasAnalysisPass(LLVMPassManagerRef PM);
-
-extern "C" void LLVMRustAddPrintModulePass(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));
-}
-
-void LLVMInitializeX86TargetInfo();
-void LLVMInitializeX86Target();
-void LLVMInitializeX86TargetMC();
-void LLVMInitializeX86AsmPrinter();
-void LLVMInitializeX86AsmParser();
-
-
-void LLVMInitializeARMTargetInfo();
-void LLVMInitializeARMTarget();
-void LLVMInitializeARMTargetMC();
-void LLVMInitializeARMAsmPrinter();
-void LLVMInitializeARMAsmParser();
-
-void LLVMInitializeMipsTargetInfo();
-void LLVMInitializeMipsTarget();
-void LLVMInitializeMipsTargetMC();
-void LLVMInitializeMipsAsmPrinter();
-void LLVMInitializeMipsAsmParser();
-// Only initialize the platforms supported by Rust here,
-// because using --llvm-root will have multiple platforms
-// that rustllvm doesn't actually link to and it's pointless to put target info
-// into the registry that Rust can not generate machine code for.
-
-void LLVMRustInitializeTargets() {
-  LLVMInitializeX86TargetInfo();
-  LLVMInitializeX86Target();
-  LLVMInitializeX86TargetMC();
-  LLVMInitializeX86AsmPrinter();
-  LLVMInitializeX86AsmParser();
-
-  LLVMInitializeARMTargetInfo();
-  LLVMInitializeARMTarget();
-  LLVMInitializeARMTargetMC();
-  LLVMInitializeARMAsmPrinter();
-  LLVMInitializeARMAsmParser();
-
-  LLVMInitializeMipsTargetInfo();
-  LLVMInitializeMipsTarget();
-  LLVMInitializeMipsTargetMC();
-  LLVMInitializeMipsAsmPrinter();
-  LLVMInitializeMipsAsmParser();
-}
-
 // Custom memory manager for MCJITting. It needs special features
 // that the generic JIT memory manager doesn't entail. Based on
 // code from LLI, change where needed for Rust.
@@ -367,85 +309,9 @@ LLVMRustBuildJIT(void* mem,
   return wrap(EE);
 }
 
-extern "C" bool
-LLVMRustWriteOutputFile(LLVMPassManagerRef PMR,
-                        LLVMModuleRef M,
-                        const char *triple,
-                        const char *cpu,
-                        const char *feature,
-                        const char *path,
-                        TargetMachine::CodeGenFileType FileType,
-                        CodeGenOpt::Level OptLevel,
-      bool EnableSegmentedStacks) {
-
-  LLVMRustInitializeTargets();
-
-  // 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 (!EnableARMEHABI) {
-    int argc = 3;
-    const char* argv[] = {"rustc", "-arm-enable-ehabi",
-        "-arm-enable-ehabi-descriptors"};
-    cl::ParseCommandLineOptions(argc, argv);
-  }
-
-  Triple Trip(Triple::normalize(triple));
-
-  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;
-
-  PassManager *PM = unwrap<PassManager>(PMR);
-
-  std::string Err;
-  std::string FeaturesStr(feature);
-  std::string CPUStr(cpu);
-  const Target *TheTarget = TargetRegistry::lookupTarget(Trip.getTriple(), Err);
-  TargetMachine *Target =
-    TheTarget->createTargetMachine(Trip.getTriple(), CPUStr, FeaturesStr,
-           Options, Reloc::PIC_,
-           CodeModel::Default, OptLevel);
-  Target->addAnalysisPasses(*PM);
-
-  bool NoVerify = false;
-  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);
-
-  bool foo = Target->addPassesToEmitFile(*PM, FOS, FileType, NoVerify);
-  assert(!foo);
-  (void)foo;
-  PM->run(*unwrap(M));
-  delete Target;
-  return true;
-}
-
-extern "C" LLVMModuleRef LLVMRustParseAssemblyFile(LLVMContextRef C,
-                                                   const char *Filename) {
-  SMDiagnostic d;
-  Module *m = ParseAssemblyFile(Filename, d, *unwrap(C));
-  if (m) {
-    return wrap(m);
-  } else {
-    LLVMRustError = d.getMessage().str().c_str();
-    return NULL;
-  }
-}
-
-extern "C" LLVMModuleRef LLVMRustParseBitcode(LLVMMemoryBufferRef MemBuf) {
-  LLVMModuleRef M;
-  return LLVMParseBitcode(MemBuf, &M, const_cast<char **>(&LLVMRustError))
-         ? NULL : M;
+extern "C" void
+LLVMRustSetNormalizedTarget(LLVMModuleRef M, const char *triple) {
+    unwrap(M)->setTargetTriple(Triple::normalize(triple));
 }
 
 extern "C" LLVMValueRef LLVMRustConstSmallInt(LLVMTypeRef IntTy, unsigned N,
@@ -463,11 +329,6 @@ extern "C" LLVMValueRef LLVMRustConstInt(LLVMTypeRef IntTy,
   return LLVMConstInt(IntTy, N, SignExtend);
 }
 
-extern bool llvm::TimePassesIsEnabled;
-extern "C" void LLVMRustEnableTimePasses() {
-  TimePassesIsEnabled = true;
-}
-
 extern "C" void LLVMRustPrintPassTimings() {
   raw_fd_ostream OS (2, false); // stderr.
   TimerGroup::printAll(OS);
index 75a55fdf88a4197c906f5bb111f9c2b73a0a77fb..e2cec6a04f346001e6a03dbbddca691e59a6ef6a 100644 (file)
@@ -1,5 +1,4 @@
 LLVMRustCreateMemoryBufferWithContentsOfFile
-LLVMRustEnableTimePasses
 LLVMRustWriteOutputFile
 LLVMRustGetLastError
 LLVMRustConstSmallInt
@@ -7,8 +6,6 @@ LLVMRustConstInt
 LLVMRustLoadCrate
 LLVMRustPrepareJIT
 LLVMRustBuildJIT
-LLVMRustParseBitcode
-LLVMRustParseAssemblyFile
 LLVMRustPrintPassTimings
 LLVMRustStartMultithreading
 LLVMCreateObjectFile
@@ -28,7 +25,6 @@ LLVMAddAlias
 LLVMAddArgumentPromotionPass
 LLVMAddAttribute
 LLVMAddBasicAliasAnalysisPass
-LLVMRustAddPrintModulePass
 LLVMAddCFGSimplificationPass
 LLVMAddCase
 LLVMAddClause
@@ -589,9 +585,6 @@ LLVMStructCreateNamed
 LLVMStructSetBody
 LLVMInlineAsm
 LLVMInitializePasses
-LLVMAddPass
-LLVMCreatePass
-LLVMDestroyPass
 LLVMDIBuilderCreate
 LLVMDIBuilderDispose
 LLVMDIBuilderFinalize
@@ -616,3 +609,15 @@ LLVMDIBuilderCreateEnumerationType
 LLVMDIBuilderCreateUnionType
 LLVMDIBuilderCreateTemplateTypeParameter
 LLVMSetUnnamedAddr
+LLVMRustAddPass
+LLVMRustAddAnalysisPasses
+LLVMRustAddLibraryInfo
+LLVMRustCreateTargetMachine
+LLVMRustRunFunctionPassManager
+LLVMRustPrintModule
+LLVMRustDisposeTargetMachine
+LLVMRustAddBuilderLibraryInfo
+LLVMRustSetLLVMOptions
+LLVMRustPrintPasses
+LLVMRustSetNormalizedTarget
+LLVMRustAddAlwaysInlinePass
index eeefb19883eb38666957f25fa5f4247439556e3f..94bb00aab77577cc4871d4c9d42cd6af762e33dd 100644 (file)
@@ -59,3 +59,5 @@
 #include <fcntl.h>
 #include <unistd.h>
 #endif
+
+extern const char* LLVMRustError;