2021-12-31 15:26:32 +00:00
use std ::{ env , fs } ;
2020-05-10 14:54:30 +00:00
use gccjit ::OutputKind ;
use rustc_codegen_ssa ::{ CompiledModule , ModuleCodegen } ;
2023-10-09 19:53:34 +00:00
use rustc_codegen_ssa ::back ::link ::ensure_removed ;
use rustc_codegen_ssa ::back ::write ::{ BitcodeSection , CodegenContext , EmitObj , ModuleConfig } ;
2023-12-17 10:48:57 +00:00
use rustc_errors ::DiagCtxt ;
2023-10-09 19:53:34 +00:00
use rustc_fs_util ::link_or_copy ;
2020-05-10 14:54:30 +00:00
use rustc_session ::config ::OutputType ;
use rustc_span ::fatal_error ::FatalError ;
use rustc_target ::spec ::SplitDebuginfo ;
use crate ::{ GccCodegenBackend , GccContext } ;
2023-10-09 19:53:34 +00:00
use crate ::errors ::CopyBitcode ;
2020-05-10 14:54:30 +00:00
2023-12-17 23:15:45 +00:00
pub ( crate ) unsafe fn codegen ( cgcx : & CodegenContext < GccCodegenBackend > , dcx : & DiagCtxt , module : ModuleCodegen < GccContext > , config : & ModuleConfig ) -> Result < CompiledModule , FatalError > {
2023-10-09 19:53:34 +00:00
let _timer = cgcx . prof . generic_activity_with_arg ( " GCC_module_codegen " , & * module . name ) ;
2020-05-10 14:54:30 +00:00
{
let context = & module . module_llvm . context ;
let module_name = module . name . clone ( ) ;
2023-10-09 19:53:34 +00:00
let should_combine_object_files = module . module_llvm . should_combine_object_files ;
2020-05-10 14:54:30 +00:00
let module_name = Some ( & module_name [ .. ] ) ;
2023-10-09 19:53:34 +00:00
// NOTE: Only generate object files with GIMPLE when this environment variable is set for
// now because this requires a particular setup (same gcc/lto1/lto-wrapper commit as libgccjit).
let fat_lto = env ::var ( " EMBED_LTO_BITCODE " ) . as_deref ( ) = = Ok ( " 1 " ) ;
let bc_out = cgcx . output_filenames . temp_path ( OutputType ::Bitcode , module_name ) ;
2020-05-10 14:54:30 +00:00
let obj_out = cgcx . output_filenames . temp_path ( OutputType ::Object , module_name ) ;
2023-10-09 19:53:34 +00:00
if config . bitcode_needed ( ) & & fat_lto {
let _timer = cgcx
. prof
. generic_activity_with_arg ( " GCC_module_codegen_make_bitcode " , & * module . name ) ;
2021-08-15 12:28:46 +00:00
// TODO(antoyo)
2023-10-09 19:53:34 +00:00
/* if let Some(bitcode_filename) = bc_out.file_name() {
cgcx . prof . artifact_size (
" llvm_bitcode " ,
bitcode_filename . to_string_lossy ( ) ,
data . len ( ) as u64 ,
) ;
} * /
if config . emit_bc | | config . emit_obj = = EmitObj ::Bitcode {
let _timer = cgcx
. prof
. generic_activity_with_arg ( " GCC_module_codegen_emit_bitcode " , & * module . name ) ;
context . add_command_line_option ( " -flto=auto " ) ;
context . add_command_line_option ( " -flto-partition=one " ) ;
context . compile_to_file ( OutputKind ::ObjectFile , bc_out . to_str ( ) . expect ( " path to str " ) ) ;
}
if config . emit_obj = = EmitObj ::ObjectCode ( BitcodeSection ::Full ) {
let _timer = cgcx
. prof
. generic_activity_with_arg ( " GCC_module_codegen_embed_bitcode " , & * module . name ) ;
// TODO(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes?
//embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
context . add_command_line_option ( " -flto=auto " ) ;
context . add_command_line_option ( " -flto-partition=one " ) ;
context . add_command_line_option ( " -ffat-lto-objects " ) ;
// TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument).
context . compile_to_file ( OutputKind ::ObjectFile , bc_out . to_str ( ) . expect ( " path to str " ) ) ;
}
2021-08-15 12:28:46 +00:00
}
2020-05-10 14:54:30 +00:00
if config . emit_ir {
unimplemented! ( ) ;
}
if config . emit_asm {
let _timer = cgcx
. prof
2023-10-09 19:53:34 +00:00
. generic_activity_with_arg ( " GCC_module_codegen_emit_asm " , & * module . name ) ;
2020-05-10 14:54:30 +00:00
let path = cgcx . output_filenames . temp_path ( OutputType ::Assembly , module_name ) ;
context . compile_to_file ( OutputKind ::Assembler , path . to_str ( ) . expect ( " path to str " ) ) ;
}
match config . emit_obj {
EmitObj ::ObjectCode ( _ ) = > {
let _timer = cgcx
. prof
2023-10-09 19:53:34 +00:00
. generic_activity_with_arg ( " GCC_module_codegen_emit_obj " , & * module . name ) ;
2021-12-31 15:26:32 +00:00
if env ::var ( " CG_GCCJIT_DUMP_MODULE_NAMES " ) . as_deref ( ) = = Ok ( " 1 " ) {
println! ( " Module {} " , module . name ) ;
}
2022-03-26 17:29:37 +00:00
if env ::var ( " CG_GCCJIT_DUMP_ALL_MODULES " ) . as_deref ( ) = = Ok ( " 1 " ) | | env ::var ( " CG_GCCJIT_DUMP_MODULE " ) . as_deref ( ) = = Ok ( & module . name ) {
2021-12-31 15:26:32 +00:00
println! ( " Dumping reproducer {} " , module . name ) ;
let _ = fs ::create_dir ( " /tmp/reproducers " ) ;
// FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by
// transmuting an rvalue to an lvalue.
// Segfault is actually in gcc::jit::reproducer::get_identifier_as_lvalue
context . dump_reproducer_to_file ( & format! ( " /tmp/reproducers/ {} .c " , module . name ) ) ;
println! ( " Dumped reproducer {} " , module . name ) ;
2021-08-15 12:28:46 +00:00
}
2022-03-26 17:29:37 +00:00
if env ::var ( " CG_GCCJIT_DUMP_TO_FILE " ) . as_deref ( ) = = Ok ( " 1 " ) {
let _ = fs ::create_dir ( " /tmp/gccjit_dumps " ) ;
let path = & format! ( " /tmp/gccjit_dumps/ {} .c " , module . name ) ;
2023-03-05 17:03:19 +00:00
context . set_debug_info ( true ) ;
2022-03-26 17:29:37 +00:00
context . dump_to_file ( path , true ) ;
}
2023-10-09 19:53:34 +00:00
if should_combine_object_files & & fat_lto {
context . add_command_line_option ( " -flto=auto " ) ;
context . add_command_line_option ( " -flto-partition=one " ) ;
context . add_driver_option ( " -Wl,-r " ) ;
// NOTE: we need -nostdlib, otherwise, we get the following error:
// /usr/bin/ld: cannot find -lgcc_s: No such file or directory
context . add_driver_option ( " -nostdlib " ) ;
// NOTE: without -fuse-linker-plugin, we get the following error:
// lto1: internal compiler error: decompressed stream: Destination buffer is too small
context . add_driver_option ( " -fuse-linker-plugin " ) ;
// NOTE: this doesn't actually generate an executable. With the above flags, it combines the .o files together in another .o.
context . compile_to_file ( OutputKind ::Executable , obj_out . to_str ( ) . expect ( " path to str " ) ) ;
}
else {
context . compile_to_file ( OutputKind ::ObjectFile , obj_out . to_str ( ) . expect ( " path to str " ) ) ;
}
2020-05-10 14:54:30 +00:00
}
EmitObj ::Bitcode = > {
2023-10-09 19:53:34 +00:00
debug! ( " copying bitcode {:?} to obj {:?} " , bc_out , obj_out ) ;
if let Err ( err ) = link_or_copy ( & bc_out , & obj_out ) {
2023-12-17 23:15:45 +00:00
dcx . emit_err ( CopyBitcode { err } ) ;
2023-10-09 19:53:34 +00:00
}
if ! config . emit_bc {
debug! ( " removing_bitcode {:?} " , bc_out ) ;
2023-12-17 23:15:45 +00:00
ensure_removed ( dcx , & bc_out ) ;
2023-10-09 19:53:34 +00:00
}
2020-05-10 14:54:30 +00:00
}
EmitObj ::None = > { }
}
}
Ok ( module . into_compiled_module (
config . emit_obj ! = EmitObj ::None ,
cgcx . target_can_use_split_dwarf & & cgcx . split_debuginfo = = SplitDebuginfo ::Unpacked ,
config . emit_bc ,
& cgcx . output_filenames ,
) )
}
2023-12-17 23:15:45 +00:00
pub ( crate ) fn link ( _cgcx : & CodegenContext < GccCodegenBackend > , _dcx : & DiagCtxt , mut _modules : Vec < ModuleCodegen < GccContext > > ) -> Result < ModuleCodegen < GccContext > , FatalError > {
2020-05-10 14:54:30 +00:00
unimplemented! ( ) ;
}
2023-10-09 19:53:34 +00:00
pub ( crate ) fn save_temp_bitcode ( cgcx : & CodegenContext < GccCodegenBackend > , _module : & ModuleCodegen < GccContext > , _name : & str ) {
if ! cgcx . save_temps {
return ;
}
unimplemented! ( ) ;
/* unsafe {
let ext = format! ( " {} .bc " , name ) ;
let cgu = Some ( & module . name [ .. ] ) ;
let path = cgcx . output_filenames . temp_path_ext ( & ext , cgu ) ;
let cstr = path_to_c_string ( & path ) ;
let llmod = module . module_llvm . llmod ( ) ;
llvm ::LLVMWriteBitcodeToFile ( llmod , cstr . as_ptr ( ) ) ;
} * /
}