mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Rollup merge of #70289 - nnethercote:refactor-codegen, r=eddyb
Refactor `codegen` `codegen` in `src/librustc_codegen_llvm/back/write.rs` is long and has complex control flow. These commits refactor it and make it easier to understand.
This commit is contained in:
commit
170112cd15
@ -16,7 +16,7 @@ use crate::ModuleLlvm;
|
|||||||
use log::debug;
|
use log::debug;
|
||||||
use rustc::bug;
|
use rustc::bug;
|
||||||
use rustc::ty::TyCtxt;
|
use rustc::ty::TyCtxt;
|
||||||
use rustc_codegen_ssa::back::write::{run_assembler, CodegenContext, ModuleConfig};
|
use rustc_codegen_ssa::back::write::{run_assembler, CodegenContext, EmbedBitcode, ModuleConfig};
|
||||||
use rustc_codegen_ssa::traits::*;
|
use rustc_codegen_ssa::traits::*;
|
||||||
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, RLIB_BYTECODE_EXTENSION};
|
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, RLIB_BYTECODE_EXTENSION};
|
||||||
use rustc_data_structures::small_c_str::SmallCStr;
|
use rustc_data_structures::small_c_str::SmallCStr;
|
||||||
@ -634,30 +634,24 @@ pub(crate) unsafe fn codegen(
|
|||||||
f(cpm)
|
f(cpm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't have the integrated assembler, then we need to emit asm
|
// Two things to note:
|
||||||
// from LLVM and use `gcc` to create the object file.
|
// - If object files are just LLVM bitcode we write bitcode, copy it to
|
||||||
let asm_to_obj = config.emit_obj && config.no_integrated_as;
|
// the .o file, and delete the bitcode if it wasn't otherwise
|
||||||
|
// requested.
|
||||||
// Change what we write and cleanup based on whether obj files are
|
// - If we don't have the integrated assembler then we need to emit
|
||||||
// just llvm bitcode. In that case write bitcode, and possibly
|
// asm from LLVM and use `gcc` to create the object file.
|
||||||
// delete the bitcode if it wasn't requested. Don't generate the
|
|
||||||
// machine code, instead copy the .o file from the .bc
|
|
||||||
let write_bc = config.emit_bc || config.obj_is_bitcode;
|
|
||||||
let rm_bc = !config.emit_bc && config.obj_is_bitcode;
|
|
||||||
let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm_to_obj;
|
|
||||||
let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode;
|
|
||||||
|
|
||||||
let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
|
let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
|
||||||
let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
|
let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
|
||||||
|
|
||||||
if write_bc || config.emit_bc_compressed || config.embed_bitcode {
|
if config.bitcode_needed() {
|
||||||
let _timer = cgcx
|
let _timer = cgcx
|
||||||
.prof
|
.prof
|
||||||
.generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &module.name[..]);
|
.generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &module.name[..]);
|
||||||
let thin = ThinBuffer::new(llmod);
|
let thin = ThinBuffer::new(llmod);
|
||||||
let data = thin.data();
|
let data = thin.data();
|
||||||
|
|
||||||
if write_bc {
|
if config.emit_bc || config.obj_is_bitcode {
|
||||||
let _timer = cgcx.prof.generic_activity_with_arg(
|
let _timer = cgcx.prof.generic_activity_with_arg(
|
||||||
"LLVM_module_codegen_emit_bitcode",
|
"LLVM_module_codegen_emit_bitcode",
|
||||||
&module.name[..],
|
&module.name[..],
|
||||||
@ -668,7 +662,7 @@ pub(crate) unsafe fn codegen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.embed_bitcode {
|
if config.embed_bitcode == EmbedBitcode::Full {
|
||||||
let _timer = cgcx.prof.generic_activity_with_arg(
|
let _timer = cgcx.prof.generic_activity_with_arg(
|
||||||
"LLVM_module_codegen_embed_bitcode",
|
"LLVM_module_codegen_embed_bitcode",
|
||||||
&module.name[..],
|
&module.name[..],
|
||||||
@ -688,81 +682,75 @@ pub(crate) unsafe fn codegen(
|
|||||||
diag_handler.err(&msg);
|
diag_handler.err(&msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if config.embed_bitcode_marker {
|
} else if config.embed_bitcode == EmbedBitcode::Marker {
|
||||||
embed_bitcode(cgcx, llcx, llmod, None);
|
embed_bitcode(cgcx, llcx, llmod, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if config.emit_ir {
|
||||||
if config.emit_ir {
|
let _timer = cgcx
|
||||||
let _timer = cgcx
|
.prof
|
||||||
.prof
|
.generic_activity_with_arg("LLVM_module_codegen_emit_ir", &module.name[..]);
|
||||||
.generic_activity_with_arg("LLVM_module_codegen_emit_ir", &module.name[..]);
|
let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name);
|
||||||
let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name);
|
let out_c = path_to_c_string(&out);
|
||||||
let out_c = path_to_c_string(&out);
|
|
||||||
|
|
||||||
extern "C" fn demangle_callback(
|
extern "C" fn demangle_callback(
|
||||||
input_ptr: *const c_char,
|
input_ptr: *const c_char,
|
||||||
input_len: size_t,
|
input_len: size_t,
|
||||||
output_ptr: *mut c_char,
|
output_ptr: *mut c_char,
|
||||||
output_len: size_t,
|
output_len: size_t,
|
||||||
) -> size_t {
|
) -> size_t {
|
||||||
let input = unsafe {
|
let input =
|
||||||
slice::from_raw_parts(input_ptr as *const u8, input_len as usize)
|
unsafe { slice::from_raw_parts(input_ptr as *const u8, input_len as usize) };
|
||||||
};
|
|
||||||
|
|
||||||
let input = match str::from_utf8(input) {
|
let input = match str::from_utf8(input) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(_) => return 0,
|
Err(_) => return 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let output = unsafe {
|
let output = unsafe {
|
||||||
slice::from_raw_parts_mut(output_ptr as *mut u8, output_len as usize)
|
slice::from_raw_parts_mut(output_ptr as *mut u8, output_len as usize)
|
||||||
};
|
};
|
||||||
let mut cursor = io::Cursor::new(output);
|
let mut cursor = io::Cursor::new(output);
|
||||||
|
|
||||||
let demangled = match rustc_demangle::try_demangle(input) {
|
let demangled = match rustc_demangle::try_demangle(input) {
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
Err(_) => return 0,
|
Err(_) => return 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
if write!(cursor, "{:#}", demangled).is_err() {
|
if write!(cursor, "{:#}", demangled).is_err() {
|
||||||
// Possible only if provided buffer is not big enough
|
// Possible only if provided buffer is not big enough
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
cursor.position() as size_t
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback);
|
cursor.position() as size_t
|
||||||
result.into_result().map_err(|()| {
|
|
||||||
let msg = format!("failed to write LLVM IR to {}", out.display());
|
|
||||||
llvm_err(diag_handler, &msg)
|
|
||||||
})?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.emit_asm || asm_to_obj {
|
let result = llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback);
|
||||||
let _timer = cgcx
|
result.into_result().map_err(|()| {
|
||||||
.prof
|
let msg = format!("failed to write LLVM IR to {}", out.display());
|
||||||
.generic_activity_with_arg("LLVM_module_codegen_emit_asm", &module.name[..]);
|
llvm_err(diag_handler, &msg)
|
||||||
let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
// We can't use the same module for asm and binary output, because that triggers
|
let config_emit_normal_obj = config.emit_obj && !config.obj_is_bitcode;
|
||||||
// various errors like invalid IR or broken binaries, so we might have to clone the
|
|
||||||
// module to produce the asm output
|
|
||||||
let llmod = if config.emit_obj { llvm::LLVMCloneModule(llmod) } else { llmod };
|
|
||||||
with_codegen(tm, llmod, config.no_builtins, |cpm| {
|
|
||||||
write_output_file(
|
|
||||||
diag_handler,
|
|
||||||
tm,
|
|
||||||
cpm,
|
|
||||||
llmod,
|
|
||||||
&path,
|
|
||||||
llvm::FileType::AssemblyFile,
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if write_obj {
|
if config.emit_asm || (config_emit_normal_obj && config.no_integrated_as) {
|
||||||
|
let _timer = cgcx
|
||||||
|
.prof
|
||||||
|
.generic_activity_with_arg("LLVM_module_codegen_emit_asm", &module.name[..]);
|
||||||
|
let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
|
||||||
|
|
||||||
|
// We can't use the same module for asm and binary output, because that triggers
|
||||||
|
// various errors like invalid IR or broken binaries, so we might have to clone the
|
||||||
|
// module to produce the asm output
|
||||||
|
let llmod = if config.emit_obj { llvm::LLVMCloneModule(llmod) } else { llmod };
|
||||||
|
with_codegen(tm, llmod, config.no_builtins, |cpm| {
|
||||||
|
write_output_file(diag_handler, tm, cpm, llmod, &path, llvm::FileType::AssemblyFile)
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if config_emit_normal_obj {
|
||||||
|
if !config.no_integrated_as {
|
||||||
let _timer = cgcx
|
let _timer = cgcx
|
||||||
.prof
|
.prof
|
||||||
.generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]);
|
.generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]);
|
||||||
@ -776,7 +764,7 @@ pub(crate) unsafe fn codegen(
|
|||||||
llvm::FileType::ObjectFile,
|
llvm::FileType::ObjectFile,
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
} else if asm_to_obj {
|
} else {
|
||||||
let _timer = cgcx
|
let _timer = cgcx
|
||||||
.prof
|
.prof
|
||||||
.generic_activity_with_arg("LLVM_module_codegen_asm_to_obj", &module.name[..]);
|
.generic_activity_with_arg("LLVM_module_codegen_asm_to_obj", &module.name[..]);
|
||||||
@ -789,17 +777,19 @@ pub(crate) unsafe fn codegen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if copy_bc_to_obj {
|
if config.obj_is_bitcode {
|
||||||
debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out);
|
if config.emit_obj {
|
||||||
if let Err(e) = link_or_copy(&bc_out, &obj_out) {
|
debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out);
|
||||||
diag_handler.err(&format!("failed to copy bitcode to object file: {}", e));
|
if let Err(e) = link_or_copy(&bc_out, &obj_out) {
|
||||||
|
diag_handler.err(&format!("failed to copy bitcode to object file: {}", e));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if rm_bc {
|
if !config.emit_bc {
|
||||||
debug!("removing_bitcode {:?}", bc_out);
|
debug!("removing_bitcode {:?}", bc_out);
|
||||||
if let Err(e) = fs::remove_file(&bc_out) {
|
if let Err(e) = fs::remove_file(&bc_out) {
|
||||||
diag_handler.err(&format!("failed to remove bitcode: {}", e));
|
diag_handler.err(&format!("failed to remove bitcode: {}", e));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +51,14 @@ use std::thread;
|
|||||||
|
|
||||||
const PRE_LTO_BC_EXT: &str = "pre-lto.bc";
|
const PRE_LTO_BC_EXT: &str = "pre-lto.bc";
|
||||||
|
|
||||||
|
/// The kind of bitcode to embed in object files.
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub enum EmbedBitcode {
|
||||||
|
None,
|
||||||
|
Marker,
|
||||||
|
Full,
|
||||||
|
}
|
||||||
|
|
||||||
/// Module-specific configuration for `optimize_and_codegen`.
|
/// Module-specific configuration for `optimize_and_codegen`.
|
||||||
pub struct ModuleConfig {
|
pub struct ModuleConfig {
|
||||||
/// Names of additional optimization passes to run.
|
/// Names of additional optimization passes to run.
|
||||||
@ -74,7 +82,6 @@ pub struct ModuleConfig {
|
|||||||
pub emit_no_opt_bc: bool,
|
pub emit_no_opt_bc: bool,
|
||||||
pub emit_bc: bool,
|
pub emit_bc: bool,
|
||||||
pub emit_bc_compressed: bool,
|
pub emit_bc_compressed: bool,
|
||||||
pub emit_lto_bc: bool,
|
|
||||||
pub emit_ir: bool,
|
pub emit_ir: bool,
|
||||||
pub emit_asm: bool,
|
pub emit_asm: bool,
|
||||||
pub emit_obj: bool,
|
pub emit_obj: bool,
|
||||||
@ -94,8 +101,7 @@ pub struct ModuleConfig {
|
|||||||
// emscripten's ecc compiler, when used as the linker.
|
// emscripten's ecc compiler, when used as the linker.
|
||||||
pub obj_is_bitcode: bool,
|
pub obj_is_bitcode: bool,
|
||||||
pub no_integrated_as: bool,
|
pub no_integrated_as: bool,
|
||||||
pub embed_bitcode: bool,
|
pub embed_bitcode: EmbedBitcode,
|
||||||
pub embed_bitcode_marker: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleConfig {
|
impl ModuleConfig {
|
||||||
@ -116,13 +122,11 @@ impl ModuleConfig {
|
|||||||
emit_pre_lto_bc: false,
|
emit_pre_lto_bc: false,
|
||||||
emit_bc: false,
|
emit_bc: false,
|
||||||
emit_bc_compressed: false,
|
emit_bc_compressed: false,
|
||||||
emit_lto_bc: false,
|
|
||||||
emit_ir: false,
|
emit_ir: false,
|
||||||
emit_asm: false,
|
emit_asm: false,
|
||||||
emit_obj: false,
|
emit_obj: false,
|
||||||
obj_is_bitcode: false,
|
obj_is_bitcode: false,
|
||||||
embed_bitcode: false,
|
embed_bitcode: EmbedBitcode::None,
|
||||||
embed_bitcode_marker: false,
|
|
||||||
no_integrated_as: false,
|
no_integrated_as: false,
|
||||||
|
|
||||||
verify_llvm_ir: false,
|
verify_llvm_ir: false,
|
||||||
@ -145,16 +149,15 @@ impl ModuleConfig {
|
|||||||
self.new_llvm_pass_manager = sess.opts.debugging_opts.new_llvm_pass_manager;
|
self.new_llvm_pass_manager = sess.opts.debugging_opts.new_llvm_pass_manager;
|
||||||
self.obj_is_bitcode =
|
self.obj_is_bitcode =
|
||||||
sess.target.target.options.obj_is_bitcode || sess.opts.cg.linker_plugin_lto.enabled();
|
sess.target.target.options.obj_is_bitcode || sess.opts.cg.linker_plugin_lto.enabled();
|
||||||
let embed_bitcode =
|
self.embed_bitcode =
|
||||||
sess.target.target.options.embed_bitcode || sess.opts.debugging_opts.embed_bitcode;
|
if sess.target.target.options.embed_bitcode || sess.opts.debugging_opts.embed_bitcode {
|
||||||
if embed_bitcode {
|
match sess.opts.optimize {
|
||||||
match sess.opts.optimize {
|
config::OptLevel::No | config::OptLevel::Less => EmbedBitcode::Marker,
|
||||||
config::OptLevel::No | config::OptLevel::Less => {
|
_ => EmbedBitcode::Full,
|
||||||
self.embed_bitcode_marker = embed_bitcode;
|
|
||||||
}
|
}
|
||||||
_ => self.embed_bitcode = embed_bitcode,
|
} else {
|
||||||
}
|
EmbedBitcode::None
|
||||||
}
|
};
|
||||||
|
|
||||||
// Copy what clang does by turning on loop vectorization at O2 and
|
// Copy what clang does by turning on loop vectorization at O2 and
|
||||||
// slp vectorization at O3. Otherwise configure other optimization aspects
|
// slp vectorization at O3. Otherwise configure other optimization aspects
|
||||||
@ -190,7 +193,10 @@ impl ModuleConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn bitcode_needed(&self) -> bool {
|
pub fn bitcode_needed(&self) -> bool {
|
||||||
self.emit_bc || self.obj_is_bitcode || self.emit_bc_compressed || self.embed_bitcode
|
self.emit_bc
|
||||||
|
|| self.obj_is_bitcode
|
||||||
|
|| self.emit_bc_compressed
|
||||||
|
|| self.embed_bitcode == EmbedBitcode::Full
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,7 +385,6 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
|
|||||||
modules_config.emit_no_opt_bc = true;
|
modules_config.emit_no_opt_bc = true;
|
||||||
modules_config.emit_pre_lto_bc = true;
|
modules_config.emit_pre_lto_bc = true;
|
||||||
modules_config.emit_bc = true;
|
modules_config.emit_bc = true;
|
||||||
modules_config.emit_lto_bc = true;
|
|
||||||
metadata_config.emit_bc = true;
|
metadata_config.emit_bc = true;
|
||||||
allocator_config.emit_bc = true;
|
allocator_config.emit_bc = true;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user