move back:🔗:write into a separate file
This commit is contained in:
parent
0ab27b1d5b
commit
e29aa1430b
@ -13,12 +13,11 @@
|
||||
use super::rpath;
|
||||
use super::rpath::RPathConfig;
|
||||
use super::svh::Svh;
|
||||
use super::write::{OutputTypeBitcode, OutputTypeExe, OutputTypeObject};
|
||||
use driver::driver::{CrateTranslation, OutputFilenames, Input, FileInput};
|
||||
use driver::config::NoDebugInfo;
|
||||
use driver::session::Session;
|
||||
use driver::config;
|
||||
use llvm;
|
||||
use llvm::ModuleRef;
|
||||
use metadata::common::LinkMeta;
|
||||
use metadata::{encoder, cstore, filesearch, csearch, loader, creader};
|
||||
use middle::trans::context::CrateContext;
|
||||
@ -28,13 +27,11 @@
|
||||
use util::ppaux;
|
||||
use util::sha2::{Digest, Sha256};
|
||||
|
||||
use std::c_str::{ToCStr, CString};
|
||||
use std::char;
|
||||
use std::collections::HashSet;
|
||||
use std::io::{fs, TempDir, Command};
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::str;
|
||||
use std::string::String;
|
||||
use flate;
|
||||
@ -77,477 +74,6 @@
|
||||
RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET + 8;
|
||||
|
||||
|
||||
#[deriving(Clone, PartialEq, PartialOrd, Ord, Eq)]
|
||||
pub enum OutputType {
|
||||
OutputTypeBitcode,
|
||||
OutputTypeAssembly,
|
||||
OutputTypeLlvmAssembly,
|
||||
OutputTypeObject,
|
||||
OutputTypeExe,
|
||||
}
|
||||
|
||||
pub fn llvm_err(sess: &Session, msg: String) -> ! {
|
||||
unsafe {
|
||||
let cstr = llvm::LLVMRustGetLastError();
|
||||
if cstr == ptr::null() {
|
||||
sess.fatal(msg.as_slice());
|
||||
} else {
|
||||
let err = CString::new(cstr, true);
|
||||
let err = String::from_utf8_lossy(err.as_bytes());
|
||||
sess.fatal(format!("{}: {}",
|
||||
msg.as_slice(),
|
||||
err.as_slice()).as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_output_file(
|
||||
sess: &Session,
|
||||
target: llvm::TargetMachineRef,
|
||||
pm: llvm::PassManagerRef,
|
||||
m: ModuleRef,
|
||||
output: &Path,
|
||||
file_type: llvm::FileType) {
|
||||
unsafe {
|
||||
output.with_c_str(|output| {
|
||||
let result = llvm::LLVMRustWriteOutputFile(
|
||||
target, pm, m, output, file_type);
|
||||
if !result {
|
||||
llvm_err(sess, "could not write output".to_string());
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub mod write {
|
||||
|
||||
use super::super::lto;
|
||||
use super::{write_output_file, OutputType};
|
||||
use super::{OutputTypeAssembly, OutputTypeBitcode};
|
||||
use super::{OutputTypeExe, OutputTypeLlvmAssembly};
|
||||
use super::{OutputTypeObject};
|
||||
use driver::driver::{CrateTranslation, OutputFilenames};
|
||||
use driver::config::NoDebugInfo;
|
||||
use driver::session::Session;
|
||||
use driver::config;
|
||||
use llvm;
|
||||
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef};
|
||||
use util::common::time;
|
||||
use syntax::abi;
|
||||
|
||||
use std::c_str::ToCStr;
|
||||
use std::io::{Command};
|
||||
use libc::{c_uint, c_int};
|
||||
use std::str;
|
||||
|
||||
// On android, we by default compile for armv7 processors. This enables
|
||||
// things like double word CAS instructions (rather than emulating them)
|
||||
// which are *far* more efficient. This is obviously undesirable in some
|
||||
// cases, so if any sort of target feature is specified we don't append v7
|
||||
// to the feature list.
|
||||
//
|
||||
// On iOS only armv7 and newer are supported. So it is useful to
|
||||
// get all hardware potential via VFP3 (hardware floating point)
|
||||
// and NEON (SIMD) instructions supported by LLVM.
|
||||
// Note that without those flags various linking errors might
|
||||
// arise as some of intrinsics are converted into function calls
|
||||
// and nobody provides implementations those functions
|
||||
fn target_feature<'a>(sess: &'a Session) -> &'a str {
|
||||
match sess.targ_cfg.os {
|
||||
abi::OsAndroid => {
|
||||
if "" == sess.opts.cg.target_feature.as_slice() {
|
||||
"+v7"
|
||||
} else {
|
||||
sess.opts.cg.target_feature.as_slice()
|
||||
}
|
||||
},
|
||||
abi::OsiOS if sess.targ_cfg.arch == abi::Arm => {
|
||||
"+v7,+thumb2,+vfp3,+neon"
|
||||
},
|
||||
_ => sess.opts.cg.target_feature.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_passes(sess: &Session,
|
||||
trans: &CrateTranslation,
|
||||
output_types: &[OutputType],
|
||||
output: &OutputFilenames) {
|
||||
let llmod = trans.module;
|
||||
let llcx = trans.context;
|
||||
unsafe {
|
||||
configure_llvm(sess);
|
||||
|
||||
if sess.opts.cg.save_temps {
|
||||
output.with_extension("no-opt.bc").with_c_str(|buf| {
|
||||
llvm::LLVMWriteBitcodeToFile(llmod, buf);
|
||||
})
|
||||
}
|
||||
|
||||
let opt_level = match sess.opts.optimize {
|
||||
config::No => llvm::CodeGenLevelNone,
|
||||
config::Less => llvm::CodeGenLevelLess,
|
||||
config::Default => llvm::CodeGenLevelDefault,
|
||||
config::Aggressive => llvm::CodeGenLevelAggressive,
|
||||
};
|
||||
let use_softfp = sess.opts.cg.soft_float;
|
||||
|
||||
// FIXME: #11906: Omitting frame pointers breaks retrieving the value of a parameter.
|
||||
// FIXME: #11954: mac64 unwinding may not work with fp elim
|
||||
let no_fp_elim = (sess.opts.debuginfo != NoDebugInfo) ||
|
||||
(sess.targ_cfg.os == abi::OsMacos &&
|
||||
sess.targ_cfg.arch == abi::X86_64);
|
||||
|
||||
// OSX has -dead_strip, which doesn't rely on ffunction_sections
|
||||
// FIXME(#13846) this should be enabled for windows
|
||||
let ffunction_sections = sess.targ_cfg.os != abi::OsMacos &&
|
||||
sess.targ_cfg.os != abi::OsWindows;
|
||||
let fdata_sections = ffunction_sections;
|
||||
|
||||
let reloc_model = match sess.opts.cg.relocation_model.as_slice() {
|
||||
"pic" => llvm::RelocPIC,
|
||||
"static" => llvm::RelocStatic,
|
||||
"default" => llvm::RelocDefault,
|
||||
"dynamic-no-pic" => llvm::RelocDynamicNoPic,
|
||||
_ => {
|
||||
sess.err(format!("{} is not a valid relocation mode",
|
||||
sess.opts
|
||||
.cg
|
||||
.relocation_model).as_slice());
|
||||
sess.abort_if_errors();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let code_model = match sess.opts.cg.code_model.as_slice() {
|
||||
"default" => llvm::CodeModelDefault,
|
||||
"small" => llvm::CodeModelSmall,
|
||||
"kernel" => llvm::CodeModelKernel,
|
||||
"medium" => llvm::CodeModelMedium,
|
||||
"large" => llvm::CodeModelLarge,
|
||||
_ => {
|
||||
sess.err(format!("{} is not a valid code model",
|
||||
sess.opts
|
||||
.cg
|
||||
.code_model).as_slice());
|
||||
sess.abort_if_errors();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let tm = sess.targ_cfg
|
||||
.target_strs
|
||||
.target_triple
|
||||
.as_slice()
|
||||
.with_c_str(|t| {
|
||||
sess.opts.cg.target_cpu.as_slice().with_c_str(|cpu| {
|
||||
target_feature(sess).with_c_str(|features| {
|
||||
llvm::LLVMRustCreateTargetMachine(
|
||||
t, cpu, features,
|
||||
code_model,
|
||||
reloc_model,
|
||||
opt_level,
|
||||
true /* EnableSegstk */,
|
||||
use_softfp,
|
||||
no_fp_elim,
|
||||
ffunction_sections,
|
||||
fdata_sections,
|
||||
)
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
// 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.
|
||||
let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
|
||||
let mpm = llvm::LLVMCreatePassManager();
|
||||
|
||||
// If we're verifying or linting, add them to the function pass
|
||||
// manager.
|
||||
let addpass = |pass: &str| {
|
||||
pass.as_slice().with_c_str(|s| llvm::LLVMRustAddPass(fpm, s))
|
||||
};
|
||||
if !sess.no_verify() { assert!(addpass("verify")); }
|
||||
|
||||
if !sess.opts.cg.no_prepopulate_passes {
|
||||
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
|
||||
llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
|
||||
populate_llvm_passes(fpm, mpm, llmod, opt_level,
|
||||
trans.no_builtins);
|
||||
}
|
||||
|
||||
for pass in sess.opts.cg.passes.iter() {
|
||||
pass.as_slice().with_c_str(|s| {
|
||||
if !llvm::LLVMRustAddPass(mpm, s) {
|
||||
sess.warn(format!("unknown pass {}, ignoring",
|
||||
*pass).as_slice());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Finally, run the actual optimization passes
|
||||
time(sess.time_passes(), "llvm function passes", (), |()|
|
||||
llvm::LLVMRustRunFunctionPassManager(fpm, llmod));
|
||||
time(sess.time_passes(), "llvm module passes", (), |()|
|
||||
llvm::LLVMRunPassManager(mpm, llmod));
|
||||
|
||||
// Deallocate managers that we're now done with
|
||||
llvm::LLVMDisposePassManager(fpm);
|
||||
llvm::LLVMDisposePassManager(mpm);
|
||||
|
||||
// Emit the bytecode if we're either saving our temporaries or
|
||||
// emitting an rlib. Whenever an rlib is created, the bytecode is
|
||||
// inserted into the archive in order to allow LTO against it.
|
||||
if sess.opts.cg.save_temps ||
|
||||
(sess.crate_types.borrow().contains(&config::CrateTypeRlib) &&
|
||||
sess.opts.output_types.contains(&OutputTypeExe)) {
|
||||
output.temp_path(OutputTypeBitcode).with_c_str(|buf| {
|
||||
llvm::LLVMWriteBitcodeToFile(llmod, buf);
|
||||
})
|
||||
}
|
||||
|
||||
if sess.lto() {
|
||||
time(sess.time_passes(), "all lto passes", (), |()|
|
||||
lto::run(sess, llmod, tm, trans.reachable.as_slice()));
|
||||
|
||||
if sess.opts.cg.save_temps {
|
||||
output.with_extension("lto.bc").with_c_str(|buf| {
|
||||
llvm::LLVMWriteBitcodeToFile(llmod, buf);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// A codegen-specific pass manager is used to generate object
|
||||
// files for an LLVM module.
|
||||
//
|
||||
// Apparently each of these pass managers is a one-shot kind of
|
||||
// thing, so we create a new one for each type of output. The
|
||||
// pass manager passed to the closure should be ensured to not
|
||||
// escape the closure itself, and the manager should only be
|
||||
// used once.
|
||||
fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef,
|
||||
no_builtins: bool, f: |PassManagerRef|) {
|
||||
unsafe {
|
||||
let cpm = llvm::LLVMCreatePassManager();
|
||||
llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
|
||||
llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
|
||||
f(cpm);
|
||||
llvm::LLVMDisposePassManager(cpm);
|
||||
}
|
||||
}
|
||||
|
||||
let mut object_file = None;
|
||||
let mut needs_metadata = false;
|
||||
for output_type in output_types.iter() {
|
||||
let path = output.path(*output_type);
|
||||
match *output_type {
|
||||
OutputTypeBitcode => {
|
||||
path.with_c_str(|buf| {
|
||||
llvm::LLVMWriteBitcodeToFile(llmod, buf);
|
||||
})
|
||||
}
|
||||
OutputTypeLlvmAssembly => {
|
||||
path.with_c_str(|output| {
|
||||
with_codegen(tm, llmod, trans.no_builtins, |cpm| {
|
||||
llvm::LLVMRustPrintModule(cpm, llmod, output);
|
||||
})
|
||||
})
|
||||
}
|
||||
OutputTypeAssembly => {
|
||||
// If we're not using the LLVM assembler, this function
|
||||
// could be invoked specially with output_type_assembly,
|
||||
// so in this case we still want the metadata object
|
||||
// file.
|
||||
let ty = OutputTypeAssembly;
|
||||
let path = if sess.opts.output_types.contains(&ty) {
|
||||
path
|
||||
} else {
|
||||
needs_metadata = true;
|
||||
output.temp_path(OutputTypeAssembly)
|
||||
};
|
||||
with_codegen(tm, llmod, trans.no_builtins, |cpm| {
|
||||
write_output_file(sess, tm, cpm, llmod, &path,
|
||||
llvm::AssemblyFile);
|
||||
});
|
||||
}
|
||||
OutputTypeObject => {
|
||||
object_file = Some(path);
|
||||
}
|
||||
OutputTypeExe => {
|
||||
object_file = Some(output.temp_path(OutputTypeObject));
|
||||
needs_metadata = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
time(sess.time_passes(), "codegen passes", (), |()| {
|
||||
match object_file {
|
||||
Some(ref path) => {
|
||||
with_codegen(tm, llmod, trans.no_builtins, |cpm| {
|
||||
write_output_file(sess, tm, cpm, llmod, path,
|
||||
llvm::ObjectFile);
|
||||
});
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
if needs_metadata {
|
||||
with_codegen(tm, trans.metadata_module,
|
||||
trans.no_builtins, |cpm| {
|
||||
let out = output.temp_path(OutputTypeObject)
|
||||
.with_extension("metadata.o");
|
||||
write_output_file(sess, tm, cpm,
|
||||
trans.metadata_module, &out,
|
||||
llvm::ObjectFile);
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
llvm::LLVMRustDisposeTargetMachine(tm);
|
||||
llvm::LLVMDisposeModule(trans.metadata_module);
|
||||
llvm::LLVMContextDispose(trans.metadata_context);
|
||||
llvm::LLVMDisposeModule(llmod);
|
||||
llvm::LLVMContextDispose(llcx);
|
||||
if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
|
||||
let pname = super::get_cc_prog(sess);
|
||||
let mut cmd = Command::new(pname.as_slice());
|
||||
|
||||
cmd.arg("-c").arg("-o").arg(outputs.path(OutputTypeObject))
|
||||
.arg(outputs.temp_path(OutputTypeAssembly));
|
||||
debug!("{}", &cmd);
|
||||
|
||||
match cmd.output() {
|
||||
Ok(prog) => {
|
||||
if !prog.status.success() {
|
||||
sess.err(format!("linking with `{}` failed: {}",
|
||||
pname,
|
||||
prog.status).as_slice());
|
||||
sess.note(format!("{}", &cmd).as_slice());
|
||||
let mut note = prog.error.clone();
|
||||
note.push_all(prog.output.as_slice());
|
||||
sess.note(str::from_utf8(note.as_slice()).unwrap());
|
||||
sess.abort_if_errors();
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
sess.err(format!("could not exec the linker `{}`: {}",
|
||||
pname,
|
||||
e).as_slice());
|
||||
sess.abort_if_errors();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn configure_llvm(sess: &Session) {
|
||||
use std::sync::{Once, ONCE_INIT};
|
||||
static mut INIT: Once = ONCE_INIT;
|
||||
|
||||
// Copy what clang does by turning on loop vectorization at O2 and
|
||||
// slp vectorization at O3
|
||||
let vectorize_loop = !sess.opts.cg.no_vectorize_loops &&
|
||||
(sess.opts.optimize == config::Default ||
|
||||
sess.opts.optimize == config::Aggressive);
|
||||
let vectorize_slp = !sess.opts.cg.no_vectorize_slp &&
|
||||
sess.opts.optimize == config::Aggressive;
|
||||
|
||||
let mut llvm_c_strs = Vec::new();
|
||||
let mut llvm_args = Vec::new();
|
||||
{
|
||||
let add = |arg: &str| {
|
||||
let s = arg.to_c_str();
|
||||
llvm_args.push(s.as_ptr());
|
||||
llvm_c_strs.push(s);
|
||||
};
|
||||
add("rustc"); // fake program name
|
||||
if vectorize_loop { add("-vectorize-loops"); }
|
||||
if vectorize_slp { add("-vectorize-slp"); }
|
||||
if sess.time_llvm_passes() { add("-time-passes"); }
|
||||
if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
|
||||
|
||||
for arg in sess.opts.cg.llvm_args.iter() {
|
||||
add((*arg).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
INIT.doit(|| {
|
||||
llvm::LLVMInitializePasses();
|
||||
|
||||
// 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 cannot 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();
|
||||
|
||||
llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
|
||||
llvm_args.as_ptr());
|
||||
});
|
||||
}
|
||||
|
||||
unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef,
|
||||
mpm: llvm::PassManagerRef,
|
||||
llmod: ModuleRef,
|
||||
opt: llvm::CodeGenOptLevel,
|
||||
no_builtins: bool) {
|
||||
// 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 opt {
|
||||
llvm::CodeGenLevelNone => {
|
||||
// Don't add lifetime intrinsics at O0
|
||||
llvm::LLVMRustAddAlwaysInlinePass(builder, false);
|
||||
}
|
||||
llvm::CodeGenLevelLess => {
|
||||
llvm::LLVMRustAddAlwaysInlinePass(builder, true);
|
||||
}
|
||||
// numeric values copied from clang
|
||||
llvm::CodeGenLevelDefault => {
|
||||
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
|
||||
225);
|
||||
}
|
||||
llvm::CodeGenLevelAggressive => {
|
||||
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
|
||||
275);
|
||||
}
|
||||
}
|
||||
llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt as c_uint);
|
||||
llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, no_builtins);
|
||||
|
||||
// Use the builder to populate the function/module pass managers.
|
||||
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
|
||||
llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
|
||||
llvm::LLVMPassManagerBuilderDispose(builder);
|
||||
|
||||
match opt {
|
||||
llvm::CodeGenLevelDefault | llvm::CodeGenLevelAggressive => {
|
||||
"mergefunc".with_c_str(|s| llvm::LLVMRustAddPass(mpm, s));
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Name mangling and its relationship to metadata. This is complex. Read
|
||||
* carefully.
|
||||
@ -878,7 +404,7 @@ pub fn get_ar_prog(sess: &Session) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
fn remove(sess: &Session, path: &Path) {
|
||||
pub fn remove(sess: &Session, path: &Path) {
|
||||
match fs::unlink(path) {
|
||||
Ok(..) => {}
|
||||
Err(e) => {
|
||||
|
@ -9,6 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use super::link;
|
||||
use super::write;
|
||||
use driver::session;
|
||||
use driver::config;
|
||||
use llvm;
|
||||
@ -119,9 +120,9 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
|
||||
if !llvm::LLVMRustLinkInExternalBitcode(llmod,
|
||||
ptr as *const libc::c_char,
|
||||
bc_decoded.len() as libc::size_t) {
|
||||
link::llvm_err(sess,
|
||||
format!("failed to load bc of `{}`",
|
||||
name.as_slice()));
|
||||
write::llvm_err(sess,
|
||||
format!("failed to load bc of `{}`",
|
||||
name.as_slice()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
476
src/librustc/back/write.rs
Normal file
476
src/librustc/back/write.rs
Normal file
@ -0,0 +1,476 @@
|
||||
// Copyright 2013-2014 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 back::lto;
|
||||
use back::link::get_cc_prog;
|
||||
use driver::driver::{CrateTranslation, OutputFilenames};
|
||||
use driver::config::NoDebugInfo;
|
||||
use driver::session::Session;
|
||||
use driver::config;
|
||||
use llvm;
|
||||
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef};
|
||||
use util::common::time;
|
||||
use syntax::abi;
|
||||
|
||||
use std::c_str::{ToCStr, CString};
|
||||
use std::io::Command;
|
||||
use std::ptr;
|
||||
use std::str;
|
||||
use libc::{c_uint, c_int};
|
||||
|
||||
|
||||
#[deriving(Clone, PartialEq, PartialOrd, Ord, Eq)]
|
||||
pub enum OutputType {
|
||||
OutputTypeBitcode,
|
||||
OutputTypeAssembly,
|
||||
OutputTypeLlvmAssembly,
|
||||
OutputTypeObject,
|
||||
OutputTypeExe,
|
||||
}
|
||||
|
||||
|
||||
pub fn llvm_err(sess: &Session, msg: String) -> ! {
|
||||
unsafe {
|
||||
let cstr = llvm::LLVMRustGetLastError();
|
||||
if cstr == ptr::null() {
|
||||
sess.fatal(msg.as_slice());
|
||||
} else {
|
||||
let err = CString::new(cstr, true);
|
||||
let err = String::from_utf8_lossy(err.as_bytes());
|
||||
sess.fatal(format!("{}: {}",
|
||||
msg.as_slice(),
|
||||
err.as_slice()).as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_output_file(
|
||||
sess: &Session,
|
||||
target: llvm::TargetMachineRef,
|
||||
pm: llvm::PassManagerRef,
|
||||
m: ModuleRef,
|
||||
output: &Path,
|
||||
file_type: llvm::FileType) {
|
||||
unsafe {
|
||||
output.with_c_str(|output| {
|
||||
let result = llvm::LLVMRustWriteOutputFile(
|
||||
target, pm, m, output, file_type);
|
||||
if !result {
|
||||
llvm_err(sess, "could not write output".to_string());
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// On android, we by default compile for armv7 processors. This enables
|
||||
// things like double word CAS instructions (rather than emulating them)
|
||||
// which are *far* more efficient. This is obviously undesirable in some
|
||||
// cases, so if any sort of target feature is specified we don't append v7
|
||||
// to the feature list.
|
||||
//
|
||||
// On iOS only armv7 and newer are supported. So it is useful to
|
||||
// get all hardware potential via VFP3 (hardware floating point)
|
||||
// and NEON (SIMD) instructions supported by LLVM.
|
||||
// Note that without those flags various linking errors might
|
||||
// arise as some of intrinsics are converted into function calls
|
||||
// and nobody provides implementations those functions
|
||||
fn target_feature<'a>(sess: &'a Session) -> &'a str {
|
||||
match sess.targ_cfg.os {
|
||||
abi::OsAndroid => {
|
||||
if "" == sess.opts.cg.target_feature.as_slice() {
|
||||
"+v7"
|
||||
} else {
|
||||
sess.opts.cg.target_feature.as_slice()
|
||||
}
|
||||
},
|
||||
abi::OsiOS if sess.targ_cfg.arch == abi::Arm => {
|
||||
"+v7,+thumb2,+vfp3,+neon"
|
||||
},
|
||||
_ => sess.opts.cg.target_feature.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_passes(sess: &Session,
|
||||
trans: &CrateTranslation,
|
||||
output_types: &[OutputType],
|
||||
output: &OutputFilenames) {
|
||||
let llmod = trans.module;
|
||||
let llcx = trans.context;
|
||||
unsafe {
|
||||
configure_llvm(sess);
|
||||
|
||||
if sess.opts.cg.save_temps {
|
||||
output.with_extension("no-opt.bc").with_c_str(|buf| {
|
||||
llvm::LLVMWriteBitcodeToFile(llmod, buf);
|
||||
})
|
||||
}
|
||||
|
||||
let opt_level = match sess.opts.optimize {
|
||||
config::No => llvm::CodeGenLevelNone,
|
||||
config::Less => llvm::CodeGenLevelLess,
|
||||
config::Default => llvm::CodeGenLevelDefault,
|
||||
config::Aggressive => llvm::CodeGenLevelAggressive,
|
||||
};
|
||||
let use_softfp = sess.opts.cg.soft_float;
|
||||
|
||||
// FIXME: #11906: Omitting frame pointers breaks retrieving the value of a parameter.
|
||||
// FIXME: #11954: mac64 unwinding may not work with fp elim
|
||||
let no_fp_elim = (sess.opts.debuginfo != NoDebugInfo) ||
|
||||
(sess.targ_cfg.os == abi::OsMacos &&
|
||||
sess.targ_cfg.arch == abi::X86_64);
|
||||
|
||||
// OSX has -dead_strip, which doesn't rely on ffunction_sections
|
||||
// FIXME(#13846) this should be enabled for windows
|
||||
let ffunction_sections = sess.targ_cfg.os != abi::OsMacos &&
|
||||
sess.targ_cfg.os != abi::OsWindows;
|
||||
let fdata_sections = ffunction_sections;
|
||||
|
||||
let reloc_model = match sess.opts.cg.relocation_model.as_slice() {
|
||||
"pic" => llvm::RelocPIC,
|
||||
"static" => llvm::RelocStatic,
|
||||
"default" => llvm::RelocDefault,
|
||||
"dynamic-no-pic" => llvm::RelocDynamicNoPic,
|
||||
_ => {
|
||||
sess.err(format!("{} is not a valid relocation mode",
|
||||
sess.opts
|
||||
.cg
|
||||
.relocation_model).as_slice());
|
||||
sess.abort_if_errors();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let code_model = match sess.opts.cg.code_model.as_slice() {
|
||||
"default" => llvm::CodeModelDefault,
|
||||
"small" => llvm::CodeModelSmall,
|
||||
"kernel" => llvm::CodeModelKernel,
|
||||
"medium" => llvm::CodeModelMedium,
|
||||
"large" => llvm::CodeModelLarge,
|
||||
_ => {
|
||||
sess.err(format!("{} is not a valid code model",
|
||||
sess.opts
|
||||
.cg
|
||||
.code_model).as_slice());
|
||||
sess.abort_if_errors();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let tm = sess.targ_cfg
|
||||
.target_strs
|
||||
.target_triple
|
||||
.as_slice()
|
||||
.with_c_str(|t| {
|
||||
sess.opts.cg.target_cpu.as_slice().with_c_str(|cpu| {
|
||||
target_feature(sess).with_c_str(|features| {
|
||||
llvm::LLVMRustCreateTargetMachine(
|
||||
t, cpu, features,
|
||||
code_model,
|
||||
reloc_model,
|
||||
opt_level,
|
||||
true /* EnableSegstk */,
|
||||
use_softfp,
|
||||
no_fp_elim,
|
||||
ffunction_sections,
|
||||
fdata_sections,
|
||||
)
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
// 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.
|
||||
let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
|
||||
let mpm = llvm::LLVMCreatePassManager();
|
||||
|
||||
// If we're verifying or linting, add them to the function pass
|
||||
// manager.
|
||||
let addpass = |pass: &str| {
|
||||
pass.as_slice().with_c_str(|s| llvm::LLVMRustAddPass(fpm, s))
|
||||
};
|
||||
if !sess.no_verify() { assert!(addpass("verify")); }
|
||||
|
||||
if !sess.opts.cg.no_prepopulate_passes {
|
||||
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
|
||||
llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
|
||||
populate_llvm_passes(fpm, mpm, llmod, opt_level,
|
||||
trans.no_builtins);
|
||||
}
|
||||
|
||||
for pass in sess.opts.cg.passes.iter() {
|
||||
pass.as_slice().with_c_str(|s| {
|
||||
if !llvm::LLVMRustAddPass(mpm, s) {
|
||||
sess.warn(format!("unknown pass {}, ignoring",
|
||||
*pass).as_slice());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Finally, run the actual optimization passes
|
||||
time(sess.time_passes(), "llvm function passes", (), |()|
|
||||
llvm::LLVMRustRunFunctionPassManager(fpm, llmod));
|
||||
time(sess.time_passes(), "llvm module passes", (), |()|
|
||||
llvm::LLVMRunPassManager(mpm, llmod));
|
||||
|
||||
// Deallocate managers that we're now done with
|
||||
llvm::LLVMDisposePassManager(fpm);
|
||||
llvm::LLVMDisposePassManager(mpm);
|
||||
|
||||
// Emit the bytecode if we're either saving our temporaries or
|
||||
// emitting an rlib. Whenever an rlib is created, the bytecode is
|
||||
// inserted into the archive in order to allow LTO against it.
|
||||
if sess.opts.cg.save_temps ||
|
||||
(sess.crate_types.borrow().contains(&config::CrateTypeRlib) &&
|
||||
sess.opts.output_types.contains(&OutputTypeExe)) {
|
||||
output.temp_path(OutputTypeBitcode).with_c_str(|buf| {
|
||||
llvm::LLVMWriteBitcodeToFile(llmod, buf);
|
||||
})
|
||||
}
|
||||
|
||||
if sess.lto() {
|
||||
time(sess.time_passes(), "all lto passes", (), |()|
|
||||
lto::run(sess, llmod, tm, trans.reachable.as_slice()));
|
||||
|
||||
if sess.opts.cg.save_temps {
|
||||
output.with_extension("lto.bc").with_c_str(|buf| {
|
||||
llvm::LLVMWriteBitcodeToFile(llmod, buf);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// A codegen-specific pass manager is used to generate object
|
||||
// files for an LLVM module.
|
||||
//
|
||||
// Apparently each of these pass managers is a one-shot kind of
|
||||
// thing, so we create a new one for each type of output. The
|
||||
// pass manager passed to the closure should be ensured to not
|
||||
// escape the closure itself, and the manager should only be
|
||||
// used once.
|
||||
fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef,
|
||||
no_builtins: bool, f: |PassManagerRef|) {
|
||||
unsafe {
|
||||
let cpm = llvm::LLVMCreatePassManager();
|
||||
llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
|
||||
llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
|
||||
f(cpm);
|
||||
llvm::LLVMDisposePassManager(cpm);
|
||||
}
|
||||
}
|
||||
|
||||
let mut object_file = None;
|
||||
let mut needs_metadata = false;
|
||||
for output_type in output_types.iter() {
|
||||
let path = output.path(*output_type);
|
||||
match *output_type {
|
||||
OutputTypeBitcode => {
|
||||
path.with_c_str(|buf| {
|
||||
llvm::LLVMWriteBitcodeToFile(llmod, buf);
|
||||
})
|
||||
}
|
||||
OutputTypeLlvmAssembly => {
|
||||
path.with_c_str(|output| {
|
||||
with_codegen(tm, llmod, trans.no_builtins, |cpm| {
|
||||
llvm::LLVMRustPrintModule(cpm, llmod, output);
|
||||
})
|
||||
})
|
||||
}
|
||||
OutputTypeAssembly => {
|
||||
// If we're not using the LLVM assembler, this function
|
||||
// could be invoked specially with output_type_assembly,
|
||||
// so in this case we still want the metadata object
|
||||
// file.
|
||||
let ty = OutputTypeAssembly;
|
||||
let path = if sess.opts.output_types.contains(&ty) {
|
||||
path
|
||||
} else {
|
||||
needs_metadata = true;
|
||||
output.temp_path(OutputTypeAssembly)
|
||||
};
|
||||
with_codegen(tm, llmod, trans.no_builtins, |cpm| {
|
||||
write_output_file(sess, tm, cpm, llmod, &path,
|
||||
llvm::AssemblyFile);
|
||||
});
|
||||
}
|
||||
OutputTypeObject => {
|
||||
object_file = Some(path);
|
||||
}
|
||||
OutputTypeExe => {
|
||||
object_file = Some(output.temp_path(OutputTypeObject));
|
||||
needs_metadata = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
time(sess.time_passes(), "codegen passes", (), |()| {
|
||||
match object_file {
|
||||
Some(ref path) => {
|
||||
with_codegen(tm, llmod, trans.no_builtins, |cpm| {
|
||||
write_output_file(sess, tm, cpm, llmod, path,
|
||||
llvm::ObjectFile);
|
||||
});
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
if needs_metadata {
|
||||
with_codegen(tm, trans.metadata_module,
|
||||
trans.no_builtins, |cpm| {
|
||||
let out = output.temp_path(OutputTypeObject)
|
||||
.with_extension("metadata.o");
|
||||
write_output_file(sess, tm, cpm,
|
||||
trans.metadata_module, &out,
|
||||
llvm::ObjectFile);
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
llvm::LLVMRustDisposeTargetMachine(tm);
|
||||
llvm::LLVMDisposeModule(trans.metadata_module);
|
||||
llvm::LLVMDisposeModule(llmod);
|
||||
llvm::LLVMContextDispose(llcx);
|
||||
if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
|
||||
let pname = get_cc_prog(sess);
|
||||
let mut cmd = Command::new(pname.as_slice());
|
||||
|
||||
cmd.arg("-c").arg("-o").arg(outputs.path(OutputTypeObject))
|
||||
.arg(outputs.temp_path(OutputTypeAssembly));
|
||||
debug!("{}", &cmd);
|
||||
|
||||
match cmd.output() {
|
||||
Ok(prog) => {
|
||||
if !prog.status.success() {
|
||||
sess.err(format!("linking with `{}` failed: {}",
|
||||
pname,
|
||||
prog.status).as_slice());
|
||||
sess.note(format!("{}", &cmd).as_slice());
|
||||
let mut note = prog.error.clone();
|
||||
note.push_all(prog.output.as_slice());
|
||||
sess.note(str::from_utf8(note.as_slice()).unwrap());
|
||||
sess.abort_if_errors();
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
sess.err(format!("could not exec the linker `{}`: {}",
|
||||
pname,
|
||||
e).as_slice());
|
||||
sess.abort_if_errors();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn configure_llvm(sess: &Session) {
|
||||
use std::sync::{Once, ONCE_INIT};
|
||||
static mut INIT: Once = ONCE_INIT;
|
||||
|
||||
// Copy what clang does by turning on loop vectorization at O2 and
|
||||
// slp vectorization at O3
|
||||
let vectorize_loop = !sess.opts.cg.no_vectorize_loops &&
|
||||
(sess.opts.optimize == config::Default ||
|
||||
sess.opts.optimize == config::Aggressive);
|
||||
let vectorize_slp = !sess.opts.cg.no_vectorize_slp &&
|
||||
sess.opts.optimize == config::Aggressive;
|
||||
|
||||
let mut llvm_c_strs = Vec::new();
|
||||
let mut llvm_args = Vec::new();
|
||||
{
|
||||
let add = |arg: &str| {
|
||||
let s = arg.to_c_str();
|
||||
llvm_args.push(s.as_ptr());
|
||||
llvm_c_strs.push(s);
|
||||
};
|
||||
add("rustc"); // fake program name
|
||||
if vectorize_loop { add("-vectorize-loops"); }
|
||||
if vectorize_slp { add("-vectorize-slp"); }
|
||||
if sess.time_llvm_passes() { add("-time-passes"); }
|
||||
if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
|
||||
|
||||
for arg in sess.opts.cg.llvm_args.iter() {
|
||||
add((*arg).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
INIT.doit(|| {
|
||||
llvm::LLVMInitializePasses();
|
||||
|
||||
// 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 cannot 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();
|
||||
|
||||
llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
|
||||
llvm_args.as_ptr());
|
||||
});
|
||||
}
|
||||
|
||||
unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef,
|
||||
mpm: llvm::PassManagerRef,
|
||||
llmod: ModuleRef,
|
||||
opt: llvm::CodeGenOptLevel,
|
||||
no_builtins: bool) {
|
||||
// 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 opt {
|
||||
llvm::CodeGenLevelNone => {
|
||||
// Don't add lifetime intrinsics at O0
|
||||
llvm::LLVMRustAddAlwaysInlinePass(builder, false);
|
||||
}
|
||||
llvm::CodeGenLevelLess => {
|
||||
llvm::LLVMRustAddAlwaysInlinePass(builder, true);
|
||||
}
|
||||
// numeric values copied from clang
|
||||
llvm::CodeGenLevelDefault => {
|
||||
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
|
||||
225);
|
||||
}
|
||||
llvm::CodeGenLevelAggressive => {
|
||||
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
|
||||
275);
|
||||
}
|
||||
}
|
||||
llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt as c_uint);
|
||||
llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, no_builtins);
|
||||
|
||||
// Use the builder to populate the function/module pass managers.
|
||||
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
|
||||
llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
|
||||
llvm::LLVMPassManagerBuilderDispose(builder);
|
||||
|
||||
match opt {
|
||||
llvm::CodeGenLevelDefault | llvm::CodeGenLevelAggressive => {
|
||||
"mergefunc".with_c_str(|s| llvm::LLVMRustAddPass(mpm, s));
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
use driver::session::Session;
|
||||
|
||||
use back;
|
||||
use back::link;
|
||||
use back::write;
|
||||
use back::target_strs;
|
||||
use back::{arm, x86, x86_64, mips, mipsel};
|
||||
use lint;
|
||||
@ -72,7 +72,7 @@ pub struct Options {
|
||||
pub debuginfo: DebugInfoLevel,
|
||||
pub lint_opts: Vec<(String, lint::Level)>,
|
||||
pub describe_lints: bool,
|
||||
pub output_types: Vec<back::link::OutputType> ,
|
||||
pub output_types: Vec<back::write::OutputType> ,
|
||||
// This was mutable for rustpkg, which updates search paths based on the
|
||||
// parsed code. It remains mutable in case its replacements wants to use
|
||||
// this.
|
||||
@ -646,11 +646,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||
for unparsed_output_type in unparsed_output_types.iter() {
|
||||
for part in unparsed_output_type.as_slice().split(',') {
|
||||
let output_type = match part.as_slice() {
|
||||
"asm" => link::OutputTypeAssembly,
|
||||
"ir" => link::OutputTypeLlvmAssembly,
|
||||
"bc" => link::OutputTypeBitcode,
|
||||
"obj" => link::OutputTypeObject,
|
||||
"link" => link::OutputTypeExe,
|
||||
"asm" => write::OutputTypeAssembly,
|
||||
"ir" => write::OutputTypeLlvmAssembly,
|
||||
"bc" => write::OutputTypeBitcode,
|
||||
"obj" => write::OutputTypeObject,
|
||||
"link" => write::OutputTypeExe,
|
||||
_ => {
|
||||
early_error(format!("unknown emission type: `{}`",
|
||||
part).as_slice())
|
||||
@ -663,7 +663,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||
output_types.as_mut_slice().sort();
|
||||
output_types.dedup();
|
||||
if output_types.len() == 0 {
|
||||
output_types.push(link::OutputTypeExe);
|
||||
output_types.push(write::OutputTypeExe);
|
||||
}
|
||||
|
||||
let sysroot_opt = matches.opt_str("sysroot").map(|m| Path::new(m));
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
|
||||
use back::link;
|
||||
use back::write;
|
||||
use driver::session::Session;
|
||||
use driver::config;
|
||||
use front;
|
||||
@ -473,23 +474,23 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
|
||||
trans: &CrateTranslation,
|
||||
outputs: &OutputFilenames) {
|
||||
if sess.opts.cg.no_integrated_as {
|
||||
let output_type = link::OutputTypeAssembly;
|
||||
let output_type = write::OutputTypeAssembly;
|
||||
|
||||
time(sess.time_passes(), "LLVM passes", (), |_|
|
||||
link::write::run_passes(sess, trans, [output_type], outputs));
|
||||
write::run_passes(sess, trans, [output_type], outputs));
|
||||
|
||||
link::write::run_assembler(sess, outputs);
|
||||
write::run_assembler(sess, outputs);
|
||||
|
||||
// Remove assembly source, unless --save-temps was specified
|
||||
if !sess.opts.cg.save_temps {
|
||||
fs::unlink(&outputs.temp_path(link::OutputTypeAssembly)).unwrap();
|
||||
fs::unlink(&outputs.temp_path(write::OutputTypeAssembly)).unwrap();
|
||||
}
|
||||
} else {
|
||||
time(sess.time_passes(), "LLVM passes", (), |_|
|
||||
link::write::run_passes(sess,
|
||||
trans,
|
||||
sess.opts.output_types.as_slice(),
|
||||
outputs));
|
||||
write::run_passes(sess,
|
||||
trans,
|
||||
sess.opts.output_types.as_slice(),
|
||||
outputs));
|
||||
}
|
||||
}
|
||||
|
||||
@ -533,7 +534,7 @@ pub fn stop_after_phase_2(sess: &Session) -> bool {
|
||||
}
|
||||
|
||||
pub fn stop_after_phase_5(sess: &Session) -> bool {
|
||||
if !sess.opts.output_types.iter().any(|&i| i == link::OutputTypeExe) {
|
||||
if !sess.opts.output_types.iter().any(|&i| i == write::OutputTypeExe) {
|
||||
debug!("not building executable, returning early from compile_input");
|
||||
return true;
|
||||
}
|
||||
@ -549,7 +550,7 @@ fn write_out_deps(sess: &Session,
|
||||
for output_type in sess.opts.output_types.iter() {
|
||||
let file = outputs.path(*output_type);
|
||||
match *output_type {
|
||||
link::OutputTypeExe => {
|
||||
write::OutputTypeExe => {
|
||||
for output in sess.crate_types.borrow().iter() {
|
||||
let p = link::filename_for_input(sess, *output,
|
||||
id, &file);
|
||||
@ -688,7 +689,7 @@ pub struct OutputFilenames {
|
||||
}
|
||||
|
||||
impl OutputFilenames {
|
||||
pub fn path(&self, flavor: link::OutputType) -> Path {
|
||||
pub fn path(&self, flavor: write::OutputType) -> Path {
|
||||
match self.single_output_file {
|
||||
Some(ref path) => return path.clone(),
|
||||
None => {}
|
||||
@ -696,14 +697,14 @@ pub fn path(&self, flavor: link::OutputType) -> Path {
|
||||
self.temp_path(flavor)
|
||||
}
|
||||
|
||||
pub fn temp_path(&self, flavor: link::OutputType) -> Path {
|
||||
pub fn temp_path(&self, flavor: write::OutputType) -> Path {
|
||||
let base = self.out_directory.join(self.filestem());
|
||||
match flavor {
|
||||
link::OutputTypeBitcode => base.with_extension("bc"),
|
||||
link::OutputTypeAssembly => base.with_extension("s"),
|
||||
link::OutputTypeLlvmAssembly => base.with_extension("ll"),
|
||||
link::OutputTypeObject => base.with_extension("o"),
|
||||
link::OutputTypeExe => base,
|
||||
write::OutputTypeBitcode => base.with_extension("bc"),
|
||||
write::OutputTypeAssembly => base.with_extension("s"),
|
||||
write::OutputTypeLlvmAssembly => base.with_extension("ll"),
|
||||
write::OutputTypeObject => base.with_extension("o"),
|
||||
write::OutputTypeExe => base,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,7 @@ pub mod back {
|
||||
|
||||
pub mod link;
|
||||
pub mod lto;
|
||||
pub mod write;
|
||||
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
use std::collections::{HashSet, HashMap};
|
||||
use testing;
|
||||
use rustc::back::link;
|
||||
use rustc::back::write;
|
||||
use rustc::driver::config;
|
||||
use rustc::driver::driver;
|
||||
use rustc::driver::session;
|
||||
@ -120,7 +120,7 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, externs: core::Exte
|
||||
maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()),
|
||||
addl_lib_search_paths: RefCell::new(libs),
|
||||
crate_types: vec!(config::CrateTypeExecutable),
|
||||
output_types: vec!(link::OutputTypeExe),
|
||||
output_types: vec!(write::OutputTypeExe),
|
||||
no_trans: no_run,
|
||||
externs: externs,
|
||||
cg: config::CodegenOptions {
|
||||
|
Loading…
Reference in New Issue
Block a user