mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 09:14:20 +00:00
auto merge of #8700 : alexcrichton/rust/better-llvm, r=thestinger
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` All of these "copies" of clang are based off their [source code](http://clang.llvm.org/doxygen/BackendUtil_8cpp_source.html) in case anyone is curious what my source is. I was hoping that this would fix #8665, but this does not help the performance issues found there. Hopefully i'll allow us to tweak passes or see what's going on to try to debug that problem.
This commit is contained in:
commit
35f975b838
@ -27,7 +27,6 @@ use std::char;
|
||||
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 mod write {
|
||||
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);
|
||||
// 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();
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
llvm::LLVMInitializeARMTargetInfo();
|
||||
llvm::LLVMInitializeARMTarget();
|
||||
llvm::LLVMInitializeARMTargetMC();
|
||||
llvm::LLVMInitializeARMAsmPrinter();
|
||||
llvm::LLVMInitializeARMAsmParser();
|
||||
|
||||
let mut mpm = passes::PassManager::new(td.lltd);
|
||||
llvm::LLVMInitializeMipsTargetInfo();
|
||||
llvm::LLVMInitializeMipsTarget();
|
||||
llvm::LLVMInitializeMipsTargetMC();
|
||||
llvm::LLVMInitializeMipsAsmPrinter();
|
||||
llvm::LLVMInitializeMipsAsmParser();
|
||||
|
||||
if !sess.no_verify() {
|
||||
mpm.add_pass_from_name("verify");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
passes::create_standard_passes(opts.optimize)
|
||||
};
|
||||
|
||||
|
||||
debug!("Passes: %?", passes);
|
||||
passes::populate_pass_manager(sess, &mut mpm, passes);
|
||||
|
||||
debug!("Running Module Optimization Pass");
|
||||
mpm.run(llmod);
|
||||
|
||||
if 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.
|
||||
jit::exec(sess, llcx, llmod, true);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
||||
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| {
|
||||
if sess.opts.save_temps {
|
||||
do output.with_filetype("no-opt.bc").with_c_str |buf| {
|
||||
llvm::LLVMWriteBitcodeToFile(llmod, buf);
|
||||
}
|
||||
}
|
||||
|
||||
llvm::LLVMDisposeModule(llmod);
|
||||
llvm::LLVMContextDispose(llcx);
|
||||
// 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 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
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
||||
// Deallocate managers that we're now done with
|
||||
llvm::LLVMDisposePassManager(fpm);
|
||||
llvm::LLVMDisposePassManager(mpm);
|
||||
|
||||
if sess.opts.save_temps {
|
||||
do output.with_filetype("bc").with_c_str |buf| {
|
||||
llvm::LLVMWriteBitcodeToFile(llmod, buf);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
|
||||
match output_type {
|
||||
output_type_none => {}
|
||||
output_type_bitcode => {
|
||||
do output.with_c_str |buf| {
|
||||
llvm::LLVMWriteBitcodeToFile(llmod, buf);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
llvm::LLVMDisposePassManager(cpm);
|
||||
}
|
||||
|
||||
llvm::LLVMRustDisposeTargetMachine(tm);
|
||||
// the jit takes ownership of these two items
|
||||
if !sess.opts.jit {
|
||||
llvm::LLVMDisposeModule(llmod);
|
||||
llvm::LLVMContextDispose(llcx);
|
||||
}
|
||||
if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
|
||||
}
|
||||
}
|
||||
|
@ -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!();
|
||||
}
|
||||
}
|
@ -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"),
|
||||
|
@ -76,6 +76,9 @@ pub static print_link_args: uint = 1 << 23;
|
||||
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 @@ impl Session_ {
|
||||
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 {
|
||||
|
@ -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 mod llvm {
|
||||
/** 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 mod llvm {
|
||||
#[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 mod llvm {
|
||||
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 mod llvm {
|
||||
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 mod llvm {
|
||||
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 @@ impl TypeNames {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Memory-managed interface to target data. */
|
||||
|
||||
pub struct target_data_res {
|
||||
|
@ -137,7 +137,7 @@ impl CrateContext {
|
||||
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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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] {}
|
||||
|
@ -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"
|
||||
|
||||
#include "llvm/Support/CBindingWrapping.h"
|
||||
#include "llvm/Target/TargetLibraryInfo.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
|
||||
#include "llvm-c/Transforms/PassManagerBuilder.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
// Pass conversion fns
|
||||
extern cl::opt<bool> EnableARMEHABI;
|
||||
|
||||
typedef struct LLVMOpaquePass *LLVMPassRef;
|
||||
typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
|
||||
|
||||
inline Pass *unwrap(LLVMPassRef P) {
|
||||
return reinterpret_cast<Pass*>(P);
|
||||
}
|
||||
DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef)
|
||||
DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
|
||||
DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder, LLVMPassManagerBuilderRef)
|
||||
|
||||
inline LLVMPassRef wrap(const Pass *P) {
|
||||
return reinterpret_cast<LLVMPassRef>(const_cast<Pass*>(P));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T *unwrap(LLVMPassRef P) {
|
||||
T *Q = (T*)unwrap(P);
|
||||
assert(Q && "Invalid cast!");
|
||||
return Q;
|
||||
}
|
||||
|
||||
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);
|
||||
extern "C" bool
|
||||
LLVMRustAddPass(LLVMPassManagerRef PM, const char *PassName) {
|
||||
PassManagerBase *pm = unwrap(PM);
|
||||
|
||||
pm->add(p);
|
||||
}
|
||||
|
||||
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" void LLVMDestroyPass(LLVMPassRef PassRef) {
|
||||
Pass *p = unwrap(PassRef);
|
||||
delete p;
|
||||
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
|
||||
LLVMRustAddAlwaysInlinePass(LLVMPassManagerBuilderRef PMB, bool AddLifetimes) {
|
||||
unwrap(PMB)->Inliner = createAlwaysInlinerPass(AddLifetimes);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -59,3 +59,5 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
extern const char* LLVMRustError;
|
||||
|
Loading…
Reference in New Issue
Block a user