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:
Mazdak Farrokhzad 2020-03-24 07:13:42 +01:00 committed by GitHub
commit 170112cd15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 99 additions and 104 deletions

View File

@ -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));
}
} }
} }

View File

@ -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;
} }