| use std::{env, fs}; | |
| use gccjit::{Context, OutputKind}; | |
| use rustc_codegen_ssa::back::link::ensure_removed; | |
| use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig}; | |
| use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; | |
| use rustc_data_structures::profiling::SelfProfilerRef; | |
| use rustc_errors::DiagCtxtHandle; | |
| use rustc_fs_util::link_or_copy; | |
| use rustc_log::tracing::debug; | |
| use rustc_session::config::OutputType; | |
| use rustc_target::spec::SplitDebuginfo; | |
| use crate::base::add_pic_option; | |
| use crate::diagnostics::CopyBitcode; | |
| use crate::{GccContext, LtoMode}; | |
| pub(crate) fn codegen( | |
| cgcx: &CodegenContext, | |
| prof: &SelfProfilerRef, | |
| dcx: DiagCtxtHandle<'_>, | |
| module: ModuleCodegen<GccContext>, | |
| config: &ModuleConfig, | |
| ) -> CompiledModule { | |
| let _timer = prof.generic_activity_with_arg("GCC_module_codegen", &*module.name); | |
| { | |
| let context = &module.module_llvm.context; | |
| let lto_mode = module.module_llvm.lto_mode; | |
| let lto_supported = module.module_llvm.lto_supported; | |
| let bc_out = cgcx.output_filenames.temp_path_for_cgu(OutputType::Bitcode, &module.name); | |
| let obj_out = cgcx.output_filenames.temp_path_for_cgu(OutputType::Object, &module.name); | |
| if config.bitcode_needed() { | |
| let _timer = | |
| prof.generic_activity_with_arg("GCC_module_codegen_make_bitcode", &*module.name); | |
| // FIXME(antoyo) | |
| /*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 = prof | |
| .generic_activity_with_arg("GCC_module_codegen_emit_bitcode", &*module.name); | |
| if lto_supported { | |
| 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 = prof | |
| .generic_activity_with_arg("GCC_module_codegen_embed_bitcode", &*module.name); | |
| if lto_supported { | |
| // FIXME(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"); | |
| } | |
| // FIXME(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")); | |
| } | |
| } | |
| if config.emit_ir { | |
| let out = | |
| cgcx.output_filenames.temp_path_for_cgu(OutputType::LlvmAssembly, &module.name); | |
| std::fs::write(out, "").expect("write file"); | |
| } | |
| if config.emit_asm { | |
| let _timer = | |
| prof.generic_activity_with_arg("GCC_module_codegen_emit_asm", &*module.name); | |
| let path = cgcx.output_filenames.temp_path_for_cgu(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 = | |
| prof.generic_activity_with_arg("GCC_module_codegen_emit_obj", &*module.name); | |
| if env::var("CG_GCCJIT_DUMP_MODULE_NAMES").as_deref() == Ok("1") { | |
| println!("Module {}", module.name); | |
| } | |
| if env::var("CG_GCCJIT_DUMP_ALL_MODULES").as_deref() == Ok("1") | |
| || env::var("CG_GCCJIT_DUMP_MODULE").as_deref() == Ok(&module.name) | |
| { | |
| 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); | |
| } | |
| 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); | |
| context.set_debug_info(true); | |
| context.dump_to_file(path, true); | |
| } | |
| if lto_mode != LtoMode::None { | |
| let fat_lto = lto_mode == LtoMode::Fat; | |
| // We need to check if we're doing LTO since this code is also used for the | |
| // dummy ThinLTO implementation to combine the object files. | |
| if fat_lto { | |
| context.add_command_line_option("-flto=auto"); | |
| context.add_command_line_option("-flto-partition=one"); | |
| // NOTE: without -fuse-linker-plugin, we get the following error: | |
| // lto1: internal compiler error: decompressed stream: Destination buffer is too small | |
| // FIXME(antoyo): since we do not do LTO when the linker is invoked anymore, perhaps | |
| // the following flag is not necessary anymore. | |
| context.add_driver_option("-fuse-linker-plugin"); | |
| } | |
| 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"); | |
| let path = obj_out.to_str().expect("path to str"); | |
| if fat_lto { | |
| let lto_path = format!("{}.lto", path); | |
| // cSpell:disable | |
| // FIXME(antoyo): The LTO frontend generates the following warning: | |
| // ../build_sysroot/sysroot_src/library/core/src/num/dec2flt/lemire.rs:150:15: warning: type of ā_ZN4core3num7dec2flt5table17POWER_OF_FIVE_12817ha449a68fb31379e4Eā does not match original declaration [-Wlto-type-mismatch] | |
| // 150 | let (lo5, hi5) = POWER_OF_FIVE_128[index]; | |
| // | ^ | |
| // lto1: note: ā_ZN4core3num7dec2flt5table17POWER_OF_FIVE_12817ha449a68fb31379e4Eā was previously declared here | |
| // | |
| // This option is to mute it to make the UI tests pass with LTO enabled. | |
| // cSpell:enable | |
| context.add_driver_option("-Wno-lto-type-mismatch"); | |
| // 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, <o_path); | |
| let context = Context::default(); | |
| if cgcx.target_arch == "x86" || cgcx.target_arch == "x86_64" { | |
| // NOTE: it seems we need to use add_driver_option instead of | |
| // add_command_line_option here because we use the LTO frontend via gcc. | |
| context.add_driver_option("-masm=intel"); | |
| } | |
| // NOTE: these two options are needed to invoke LTO to produce an object file. | |
| // We need to initiate a second compilation because the arguments "-x lto" | |
| // needs to be at the very beginning. | |
| context.add_driver_option("-x"); | |
| context.add_driver_option("lto"); | |
| add_pic_option(&context, module.module_llvm.relocation_model); | |
| context.add_driver_option(lto_path); | |
| context.compile_to_file(OutputKind::ObjectFile, path); | |
| } else { | |
| // 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, path); | |
| } | |
| } else { | |
| context.compile_to_file( | |
| OutputKind::ObjectFile, | |
| obj_out.to_str().expect("path to str"), | |
| ); | |
| } | |
| } | |
| EmitObj::Bitcode => { | |
| debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out); | |
| if let Err(err) = link_or_copy(&bc_out, &obj_out) { | |
| dcx.emit_err(CopyBitcode { err }); | |
| } | |
| if !config.emit_bc { | |
| debug!("removing_bitcode {:?}", bc_out); | |
| ensure_removed(dcx, &bc_out); | |
| } | |
| } | |
| EmitObj::None => {} | |
| } | |
| } | |
| module.into_compiled_module( | |
| config.emit_obj != EmitObj::None, | |
| cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked, | |
| config.emit_bc, | |
| config.emit_asm, | |
| config.emit_ir, | |
| &cgcx.output_filenames, | |
| ) | |
| } | |
| pub(crate) fn save_temp_bitcode( | |
| cgcx: &CodegenContext, | |
| _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()); | |
| }*/ | |
| } |