]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_llvm/back/write.rs
Rollup merge of #67564 - Mark-Simulacrum:iter-adapter-panic, r=LukasKalbertodt
[rust.git] / src / librustc_codegen_llvm / back / write.rs
1 use crate::attributes;
2 use crate::back::bytecode;
3 use crate::back::lto::ThinBuffer;
4 use crate::base;
5 use crate::common;
6 use crate::consts;
7 use crate::context::{get_reloc_model, is_pie_binary};
8 use crate::llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
9 use crate::llvm_util;
10 use crate::type_::Type;
11 use crate::LlvmCodegenBackend;
12 use crate::ModuleLlvm;
13 use log::debug;
14 use rustc::bug;
15 use rustc::hir::def_id::LOCAL_CRATE;
16 use rustc::session::config::{self, Lto, OutputType, Passes, Sanitizer, SwitchWithOptPath};
17 use rustc::session::Session;
18 use rustc::ty::TyCtxt;
19 use rustc::util::common::time_ext;
20 use rustc_codegen_ssa::back::write::{run_assembler, CodegenContext, ModuleConfig};
21 use rustc_codegen_ssa::traits::*;
22 use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, RLIB_BYTECODE_EXTENSION};
23 use rustc_data_structures::small_c_str::SmallCStr;
24 use rustc_errors::{FatalError, Handler};
25 use rustc_fs_util::{link_or_copy, path_to_c_string};
26
27 use libc::{c_char, c_int, c_uint, c_void, size_t};
28 use std::ffi::CString;
29 use std::fs;
30 use std::io::{self, Write};
31 use std::path::{Path, PathBuf};
32 use std::slice;
33 use std::str;
34 use std::sync::Arc;
35
36 pub const RELOC_MODEL_ARGS: [(&str, llvm::RelocMode); 7] = [
37     ("pic", llvm::RelocMode::PIC),
38     ("static", llvm::RelocMode::Static),
39     ("default", llvm::RelocMode::Default),
40     ("dynamic-no-pic", llvm::RelocMode::DynamicNoPic),
41     ("ropi", llvm::RelocMode::ROPI),
42     ("rwpi", llvm::RelocMode::RWPI),
43     ("ropi-rwpi", llvm::RelocMode::ROPI_RWPI),
44 ];
45
46 pub const CODE_GEN_MODEL_ARGS: &[(&str, llvm::CodeModel)] = &[
47     ("small", llvm::CodeModel::Small),
48     ("kernel", llvm::CodeModel::Kernel),
49     ("medium", llvm::CodeModel::Medium),
50     ("large", llvm::CodeModel::Large),
51 ];
52
53 pub const TLS_MODEL_ARGS: [(&str, llvm::ThreadLocalMode); 4] = [
54     ("global-dynamic", llvm::ThreadLocalMode::GeneralDynamic),
55     ("local-dynamic", llvm::ThreadLocalMode::LocalDynamic),
56     ("initial-exec", llvm::ThreadLocalMode::InitialExec),
57     ("local-exec", llvm::ThreadLocalMode::LocalExec),
58 ];
59
60 pub fn llvm_err(handler: &rustc_errors::Handler, msg: &str) -> FatalError {
61     match llvm::last_error() {
62         Some(err) => handler.fatal(&format!("{}: {}", msg, err)),
63         None => handler.fatal(&msg),
64     }
65 }
66
67 pub fn write_output_file(
68     handler: &rustc_errors::Handler,
69     target: &'ll llvm::TargetMachine,
70     pm: &llvm::PassManager<'ll>,
71     m: &'ll llvm::Module,
72     output: &Path,
73     file_type: llvm::FileType,
74 ) -> Result<(), FatalError> {
75     unsafe {
76         let output_c = path_to_c_string(output);
77         let result = llvm::LLVMRustWriteOutputFile(target, pm, m, output_c.as_ptr(), file_type);
78         result.into_result().map_err(|()| {
79             let msg = format!("could not write output to {}", output.display());
80             llvm_err(handler, &msg)
81         })
82     }
83 }
84
85 pub fn create_informational_target_machine(
86     sess: &Session,
87     find_features: bool,
88 ) -> &'static mut llvm::TargetMachine {
89     target_machine_factory(sess, config::OptLevel::No, find_features)()
90         .unwrap_or_else(|err| llvm_err(sess.diagnostic(), &err).raise())
91 }
92
93 pub fn create_target_machine(
94     tcx: TyCtxt<'_>,
95     find_features: bool,
96 ) -> &'static mut llvm::TargetMachine {
97     target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE), find_features)()
98         .unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise())
99 }
100
101 pub fn to_llvm_opt_settings(
102     cfg: config::OptLevel,
103 ) -> (llvm::CodeGenOptLevel, llvm::CodeGenOptSize) {
104     use self::config::OptLevel::*;
105     match cfg {
106         No => (llvm::CodeGenOptLevel::None, llvm::CodeGenOptSizeNone),
107         Less => (llvm::CodeGenOptLevel::Less, llvm::CodeGenOptSizeNone),
108         Default => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeNone),
109         Aggressive => (llvm::CodeGenOptLevel::Aggressive, llvm::CodeGenOptSizeNone),
110         Size => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeDefault),
111         SizeMin => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeAggressive),
112     }
113 }
114
115 // If find_features is true this won't access `sess.crate_types` by assuming
116 // that `is_pie_binary` is false. When we discover LLVM target features
117 // `sess.crate_types` is uninitialized so we cannot access it.
118 pub fn target_machine_factory(
119     sess: &Session,
120     optlvl: config::OptLevel,
121     find_features: bool,
122 ) -> Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync> {
123     let reloc_model = get_reloc_model(sess);
124
125     let (opt_level, _) = to_llvm_opt_settings(optlvl);
126     let use_softfp = sess.opts.cg.soft_float;
127
128     let ffunction_sections = sess.target.target.options.function_sections;
129     let fdata_sections = ffunction_sections;
130
131     let code_model_arg =
132         sess.opts.cg.code_model.as_ref().or(sess.target.target.options.code_model.as_ref());
133
134     let code_model = match code_model_arg {
135         Some(s) => match CODE_GEN_MODEL_ARGS.iter().find(|arg| arg.0 == s) {
136             Some(x) => x.1,
137             _ => {
138                 sess.err(&format!("{:?} is not a valid code model", code_model_arg));
139                 sess.abort_if_errors();
140                 bug!();
141             }
142         },
143         None => llvm::CodeModel::None,
144     };
145
146     let features = attributes::llvm_target_features(sess).collect::<Vec<_>>();
147     let mut singlethread = sess.target.target.options.singlethread;
148
149     // On the wasm target once the `atomics` feature is enabled that means that
150     // we're no longer single-threaded, or otherwise we don't want LLVM to
151     // lower atomic operations to single-threaded operations.
152     if singlethread
153         && sess.target.target.llvm_target.contains("wasm32")
154         && features.iter().any(|s| *s == "+atomics")
155     {
156         singlethread = false;
157     }
158
159     let triple = SmallCStr::new(&sess.target.target.llvm_target);
160     let cpu = SmallCStr::new(llvm_util::target_cpu(sess));
161     let features = features.join(",");
162     let features = CString::new(features).unwrap();
163     let abi = SmallCStr::new(&sess.target.target.options.llvm_abiname);
164     let is_pie_binary = !find_features && is_pie_binary(sess);
165     let trap_unreachable = sess.target.target.options.trap_unreachable;
166     let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes;
167
168     let asm_comments = sess.asm_comments();
169     let relax_elf_relocations = sess.target.target.options.relax_elf_relocations;
170     Arc::new(move || {
171         let tm = unsafe {
172             llvm::LLVMRustCreateTargetMachine(
173                 triple.as_ptr(),
174                 cpu.as_ptr(),
175                 features.as_ptr(),
176                 abi.as_ptr(),
177                 code_model,
178                 reloc_model,
179                 opt_level,
180                 use_softfp,
181                 is_pie_binary,
182                 ffunction_sections,
183                 fdata_sections,
184                 trap_unreachable,
185                 singlethread,
186                 asm_comments,
187                 emit_stack_size_section,
188                 relax_elf_relocations,
189             )
190         };
191
192         tm.ok_or_else(|| {
193             format!("Could not create LLVM TargetMachine for triple: {}", triple.to_str().unwrap())
194         })
195     })
196 }
197
198 pub(crate) fn save_temp_bitcode(
199     cgcx: &CodegenContext<LlvmCodegenBackend>,
200     module: &ModuleCodegen<ModuleLlvm>,
201     name: &str,
202 ) {
203     if !cgcx.save_temps {
204         return;
205     }
206     unsafe {
207         let ext = format!("{}.bc", name);
208         let cgu = Some(&module.name[..]);
209         let path = cgcx.output_filenames.temp_path_ext(&ext, cgu);
210         let cstr = path_to_c_string(&path);
211         let llmod = module.module_llvm.llmod();
212         llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr());
213     }
214 }
215
216 pub struct DiagnosticHandlers<'a> {
217     data: *mut (&'a CodegenContext<LlvmCodegenBackend>, &'a Handler),
218     llcx: &'a llvm::Context,
219 }
220
221 impl<'a> DiagnosticHandlers<'a> {
222     pub fn new(
223         cgcx: &'a CodegenContext<LlvmCodegenBackend>,
224         handler: &'a Handler,
225         llcx: &'a llvm::Context,
226     ) -> Self {
227         let data = Box::into_raw(Box::new((cgcx, handler)));
228         unsafe {
229             llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data.cast());
230             llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, data.cast());
231         }
232         DiagnosticHandlers { data, llcx }
233     }
234 }
235
236 impl<'a> Drop for DiagnosticHandlers<'a> {
237     fn drop(&mut self) {
238         use std::ptr::null_mut;
239         unsafe {
240             llvm::LLVMRustSetInlineAsmDiagnosticHandler(self.llcx, inline_asm_handler, null_mut());
241             llvm::LLVMContextSetDiagnosticHandler(self.llcx, diagnostic_handler, null_mut());
242             drop(Box::from_raw(self.data));
243         }
244     }
245 }
246
247 unsafe extern "C" fn report_inline_asm(
248     cgcx: &CodegenContext<LlvmCodegenBackend>,
249     msg: &str,
250     cookie: c_uint,
251 ) {
252     cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_owned());
253 }
254
255 unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic, user: *const c_void, cookie: c_uint) {
256     if user.is_null() {
257         return;
258     }
259     let (cgcx, _) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, &Handler));
260
261     let msg = llvm::build_string(|s| llvm::LLVMRustWriteSMDiagnosticToString(diag, s))
262         .expect("non-UTF8 SMDiagnostic");
263
264     report_inline_asm(cgcx, &msg, cookie);
265 }
266
267 unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) {
268     if user.is_null() {
269         return;
270     }
271     let (cgcx, diag_handler) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, &Handler));
272
273     match llvm::diagnostic::Diagnostic::unpack(info) {
274         llvm::diagnostic::InlineAsm(inline) => {
275             report_inline_asm(cgcx, &llvm::twine_to_string(inline.message), inline.cookie);
276         }
277
278         llvm::diagnostic::Optimization(opt) => {
279             let enabled = match cgcx.remark {
280                 Passes::All => true,
281                 Passes::Some(ref v) => v.iter().any(|s| *s == opt.pass_name),
282             };
283
284             if enabled {
285                 diag_handler.note_without_error(&format!(
286                     "optimization {} for {} at {}:{}:{}: {}",
287                     opt.kind.describe(),
288                     opt.pass_name,
289                     opt.filename,
290                     opt.line,
291                     opt.column,
292                     opt.message
293                 ));
294             }
295         }
296         llvm::diagnostic::PGO(diagnostic_ref) | llvm::diagnostic::Linker(diagnostic_ref) => {
297             let msg = llvm::build_string(|s| {
298                 llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
299             })
300             .expect("non-UTF8 diagnostic");
301             diag_handler.warn(&msg);
302         }
303         llvm::diagnostic::UnknownDiagnostic(..) => {}
304     }
305 }
306
307 // Unsafe due to LLVM calls.
308 pub(crate) unsafe fn optimize(
309     cgcx: &CodegenContext<LlvmCodegenBackend>,
310     diag_handler: &Handler,
311     module: &ModuleCodegen<ModuleLlvm>,
312     config: &ModuleConfig,
313 ) -> Result<(), FatalError> {
314     let _timer = cgcx.prof.generic_activity("LLVM_module_optimize");
315
316     let llmod = module.module_llvm.llmod();
317     let llcx = &*module.module_llvm.llcx;
318     let tm = &*module.module_llvm.tm;
319     let _handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
320
321     let module_name = module.name.clone();
322     let module_name = Some(&module_name[..]);
323
324     if config.emit_no_opt_bc {
325         let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name);
326         let out = path_to_c_string(&out);
327         llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
328     }
329
330     if let Some(opt_level) = config.opt_level {
331         // Create the two optimizing pass managers. These mirror what clang
332         // does, and are by populated by LLVM's default PassManagerBuilder.
333         // Each manager has a different set of passes, but they also share
334         // some common passes.
335         let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
336         let mpm = llvm::LLVMCreatePassManager();
337
338         {
339             let find_pass = |pass_name: &str| {
340                 let pass_name = SmallCStr::new(pass_name);
341                 llvm::LLVMRustFindAndCreatePass(pass_name.as_ptr())
342             };
343
344             if config.verify_llvm_ir {
345                 // Verification should run as the very first pass.
346                 llvm::LLVMRustAddPass(fpm, find_pass("verify").unwrap());
347             }
348
349             let mut extra_passes = Vec::new();
350             let mut have_name_anon_globals_pass = false;
351
352             for pass_name in &config.passes {
353                 if pass_name == "lint" {
354                     // Linting should also be performed early, directly on the generated IR.
355                     llvm::LLVMRustAddPass(fpm, find_pass("lint").unwrap());
356                     continue;
357                 }
358
359                 if let Some(pass) = find_pass(pass_name) {
360                     extra_passes.push(pass);
361                 } else {
362                     diag_handler.warn(&format!("unknown pass `{}`, ignoring", pass_name));
363                 }
364
365                 if pass_name == "name-anon-globals" {
366                     have_name_anon_globals_pass = true;
367                 }
368             }
369
370             add_sanitizer_passes(config, &mut extra_passes);
371
372             // Some options cause LLVM bitcode to be emitted, which uses ThinLTOBuffers, so we need
373             // to make sure we run LLVM's NameAnonGlobals pass when emitting bitcode; otherwise
374             // we'll get errors in LLVM.
375             let using_thin_buffers = config.bitcode_needed();
376             if !config.no_prepopulate_passes {
377                 llvm::LLVMAddAnalysisPasses(tm, fpm);
378                 llvm::LLVMAddAnalysisPasses(tm, mpm);
379                 let opt_level = to_llvm_opt_settings(opt_level).0;
380                 let prepare_for_thin_lto = cgcx.lto == Lto::Thin
381                     || cgcx.lto == Lto::ThinLocal
382                     || (cgcx.lto != Lto::Fat && cgcx.opts.cg.linker_plugin_lto.enabled());
383                 with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| {
384                     llvm::LLVMRustAddLastExtensionPasses(
385                         b,
386                         extra_passes.as_ptr(),
387                         extra_passes.len() as size_t,
388                     );
389                     llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
390                     llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
391                 });
392
393                 have_name_anon_globals_pass = have_name_anon_globals_pass || prepare_for_thin_lto;
394                 if using_thin_buffers && !prepare_for_thin_lto {
395                     llvm::LLVMRustAddPass(mpm, find_pass("name-anon-globals").unwrap());
396                     have_name_anon_globals_pass = true;
397                 }
398             } else {
399                 // If we don't use the standard pipeline, directly populate the MPM
400                 // with the extra passes.
401                 for pass in extra_passes {
402                     llvm::LLVMRustAddPass(mpm, pass);
403                 }
404             }
405
406             if using_thin_buffers && !have_name_anon_globals_pass {
407                 // As described above, this will probably cause an error in LLVM
408                 if config.no_prepopulate_passes {
409                     diag_handler.err(
410                         "The current compilation is going to use thin LTO buffers \
411                                       without running LLVM's NameAnonGlobals pass. \
412                                       This will likely cause errors in LLVM. Consider adding \
413                                       -C passes=name-anon-globals to the compiler command line.",
414                     );
415                 } else {
416                     bug!(
417                         "We are using thin LTO buffers without running the NameAnonGlobals pass. \
418                           This will likely cause errors in LLVM and should never happen."
419                     );
420                 }
421             }
422         }
423
424         diag_handler.abort_if_errors();
425
426         // Finally, run the actual optimization passes
427         {
428             let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_function_passes");
429             time_ext(
430                 config.time_passes,
431                 &format!("llvm function passes [{}]", module_name.unwrap()),
432                 || llvm::LLVMRustRunFunctionPassManager(fpm, llmod),
433             );
434         }
435         {
436             let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_module_passes");
437             time_ext(
438                 config.time_passes,
439                 &format!("llvm module passes [{}]", module_name.unwrap()),
440                 || llvm::LLVMRunPassManager(mpm, llmod),
441             );
442         }
443
444         // Deallocate managers that we're now done with
445         llvm::LLVMDisposePassManager(fpm);
446         llvm::LLVMDisposePassManager(mpm);
447     }
448     Ok(())
449 }
450
451 unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static mut llvm::Pass>) {
452     let sanitizer = match &config.sanitizer {
453         None => return,
454         Some(s) => s,
455     };
456
457     let recover = config.sanitizer_recover.contains(sanitizer);
458     match sanitizer {
459         Sanitizer::Address => {
460             passes.push(llvm::LLVMRustCreateAddressSanitizerFunctionPass(recover));
461             passes.push(llvm::LLVMRustCreateModuleAddressSanitizerPass(recover));
462         }
463         Sanitizer::Memory => {
464             let track_origins = config.sanitizer_memory_track_origins as c_int;
465             passes.push(llvm::LLVMRustCreateMemorySanitizerPass(track_origins, recover));
466         }
467         Sanitizer::Thread => {
468             passes.push(llvm::LLVMRustCreateThreadSanitizerPass());
469         }
470         Sanitizer::Leak => {}
471     }
472 }
473
474 pub(crate) unsafe fn codegen(
475     cgcx: &CodegenContext<LlvmCodegenBackend>,
476     diag_handler: &Handler,
477     module: ModuleCodegen<ModuleLlvm>,
478     config: &ModuleConfig,
479 ) -> Result<CompiledModule, FatalError> {
480     let _timer = cgcx.prof.generic_activity("LLVM_module_codegen");
481     {
482         let llmod = module.module_llvm.llmod();
483         let llcx = &*module.module_llvm.llcx;
484         let tm = &*module.module_llvm.tm;
485         let module_name = module.name.clone();
486         let module_name = Some(&module_name[..]);
487         let handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
488
489         if cgcx.msvc_imps_needed {
490             create_msvc_imps(cgcx, llcx, llmod);
491         }
492
493         // A codegen-specific pass manager is used to generate object
494         // files for an LLVM module.
495         //
496         // Apparently each of these pass managers is a one-shot kind of
497         // thing, so we create a new one for each type of output. The
498         // pass manager passed to the closure should be ensured to not
499         // escape the closure itself, and the manager should only be
500         // used once.
501         unsafe fn with_codegen<'ll, F, R>(
502             tm: &'ll llvm::TargetMachine,
503             llmod: &'ll llvm::Module,
504             no_builtins: bool,
505             f: F,
506         ) -> R
507         where
508             F: FnOnce(&'ll mut PassManager<'ll>) -> R,
509         {
510             let cpm = llvm::LLVMCreatePassManager();
511             llvm::LLVMAddAnalysisPasses(tm, cpm);
512             llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
513             f(cpm)
514         }
515
516         // If we don't have the integrated assembler, then we need to emit asm
517         // from LLVM and use `gcc` to create the object file.
518         let asm_to_obj = config.emit_obj && config.no_integrated_as;
519
520         // Change what we write and cleanup based on whether obj files are
521         // just llvm bitcode. In that case write bitcode, and possibly
522         // delete the bitcode if it wasn't requested. Don't generate the
523         // machine code, instead copy the .o file from the .bc
524         let write_bc = config.emit_bc || config.obj_is_bitcode;
525         let rm_bc = !config.emit_bc && config.obj_is_bitcode;
526         let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm_to_obj;
527         let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode;
528
529         let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
530         let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
531
532         if write_bc || config.emit_bc_compressed || config.embed_bitcode {
533             let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_make_bitcode");
534             let thin = ThinBuffer::new(llmod);
535             let data = thin.data();
536
537             if write_bc {
538                 let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_bitcode");
539                 if let Err(e) = fs::write(&bc_out, data) {
540                     let msg = format!("failed to write bytecode to {}: {}", bc_out.display(), e);
541                     diag_handler.err(&msg);
542                 }
543             }
544
545             if config.embed_bitcode {
546                 let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_embed_bitcode");
547                 embed_bitcode(cgcx, llcx, llmod, Some(data));
548             }
549
550             if config.emit_bc_compressed {
551                 let _timer =
552                     cgcx.prof.generic_activity("LLVM_module_codegen_emit_compressed_bitcode");
553                 let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION);
554                 let data = bytecode::encode(&module.name, data);
555                 if let Err(e) = fs::write(&dst, data) {
556                     let msg = format!("failed to write bytecode to {}: {}", dst.display(), e);
557                     diag_handler.err(&msg);
558                 }
559             }
560         } else if config.embed_bitcode_marker {
561             embed_bitcode(cgcx, llcx, llmod, None);
562         }
563
564         time_ext(
565             config.time_passes,
566             &format!("codegen passes [{}]", module_name.unwrap()),
567             || -> Result<(), FatalError> {
568                 if config.emit_ir {
569                     let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_ir");
570                     let out =
571                         cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name);
572                     let out_c = path_to_c_string(&out);
573
574                     extern "C" fn demangle_callback(
575                         input_ptr: *const c_char,
576                         input_len: size_t,
577                         output_ptr: *mut c_char,
578                         output_len: size_t,
579                     ) -> size_t {
580                         let input = unsafe {
581                             slice::from_raw_parts(input_ptr as *const u8, input_len as usize)
582                         };
583
584                         let input = match str::from_utf8(input) {
585                             Ok(s) => s,
586                             Err(_) => return 0,
587                         };
588
589                         let output = unsafe {
590                             slice::from_raw_parts_mut(output_ptr as *mut u8, output_len as usize)
591                         };
592                         let mut cursor = io::Cursor::new(output);
593
594                         let demangled = match rustc_demangle::try_demangle(input) {
595                             Ok(d) => d,
596                             Err(_) => return 0,
597                         };
598
599                         if let Err(_) = write!(cursor, "{:#}", demangled) {
600                             // Possible only if provided buffer is not big enough
601                             return 0;
602                         }
603
604                         cursor.position() as size_t
605                     }
606
607                     let result =
608                         llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback);
609                     result.into_result().map_err(|()| {
610                         let msg = format!("failed to write LLVM IR to {}", out.display());
611                         llvm_err(diag_handler, &msg)
612                     })?;
613                 }
614
615                 if config.emit_asm || asm_to_obj {
616                     let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_asm");
617                     let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
618
619                     // We can't use the same module for asm and binary output, because that triggers
620                     // various errors like invalid IR or broken binaries, so we might have to clone the
621                     // module to produce the asm output
622                     let llmod = if config.emit_obj { llvm::LLVMCloneModule(llmod) } else { llmod };
623                     with_codegen(tm, llmod, config.no_builtins, |cpm| {
624                         write_output_file(
625                             diag_handler,
626                             tm,
627                             cpm,
628                             llmod,
629                             &path,
630                             llvm::FileType::AssemblyFile,
631                         )
632                     })?;
633                 }
634
635                 if write_obj {
636                     let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_obj");
637                     with_codegen(tm, llmod, config.no_builtins, |cpm| {
638                         write_output_file(
639                             diag_handler,
640                             tm,
641                             cpm,
642                             llmod,
643                             &obj_out,
644                             llvm::FileType::ObjectFile,
645                         )
646                     })?;
647                 } else if asm_to_obj {
648                     let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_asm_to_obj");
649                     let assembly =
650                         cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
651                     run_assembler(cgcx, diag_handler, &assembly, &obj_out);
652
653                     if !config.emit_asm && !cgcx.save_temps {
654                         drop(fs::remove_file(&assembly));
655                     }
656                 }
657
658                 Ok(())
659             },
660         )?;
661
662         if copy_bc_to_obj {
663             debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out);
664             if let Err(e) = link_or_copy(&bc_out, &obj_out) {
665                 diag_handler.err(&format!("failed to copy bitcode to object file: {}", e));
666             }
667         }
668
669         if rm_bc {
670             debug!("removing_bitcode {:?}", bc_out);
671             if let Err(e) = fs::remove_file(&bc_out) {
672                 diag_handler.err(&format!("failed to remove bitcode: {}", e));
673             }
674         }
675
676         drop(handlers);
677     }
678     Ok(module.into_compiled_module(
679         config.emit_obj,
680         config.emit_bc,
681         config.emit_bc_compressed,
682         &cgcx.output_filenames,
683     ))
684 }
685
686 /// Embed the bitcode of an LLVM module in the LLVM module itself.
687 ///
688 /// This is done primarily for iOS where it appears to be standard to compile C
689 /// code at least with `-fembed-bitcode` which creates two sections in the
690 /// executable:
691 ///
692 /// * __LLVM,__bitcode
693 /// * __LLVM,__cmdline
694 ///
695 /// It appears *both* of these sections are necessary to get the linker to
696 /// recognize what's going on. For us though we just always throw in an empty
697 /// cmdline section.
698 ///
699 /// Furthermore debug/O1 builds don't actually embed bitcode but rather just
700 /// embed an empty section.
701 ///
702 /// Basically all of this is us attempting to follow in the footsteps of clang
703 /// on iOS. See #35968 for lots more info.
704 unsafe fn embed_bitcode(
705     cgcx: &CodegenContext<LlvmCodegenBackend>,
706     llcx: &llvm::Context,
707     llmod: &llvm::Module,
708     bitcode: Option<&[u8]>,
709 ) {
710     let llconst = common::bytes_in_context(llcx, bitcode.unwrap_or(&[]));
711     let llglobal = llvm::LLVMAddGlobal(
712         llmod,
713         common::val_ty(llconst),
714         "rustc.embedded.module\0".as_ptr().cast(),
715     );
716     llvm::LLVMSetInitializer(llglobal, llconst);
717
718     let is_apple = cgcx.opts.target_triple.triple().contains("-ios")
719         || cgcx.opts.target_triple.triple().contains("-darwin");
720
721     let section = if is_apple { "__LLVM,__bitcode\0" } else { ".llvmbc\0" };
722     llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
723     llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
724     llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
725
726     let llconst = common::bytes_in_context(llcx, &[]);
727     let llglobal = llvm::LLVMAddGlobal(
728         llmod,
729         common::val_ty(llconst),
730         "rustc.embedded.cmdline\0".as_ptr().cast(),
731     );
732     llvm::LLVMSetInitializer(llglobal, llconst);
733     let section = if is_apple { "__LLVM,__cmdline\0" } else { ".llvmcmd\0" };
734     llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
735     llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
736 }
737
738 pub unsafe fn with_llvm_pmb(
739     llmod: &llvm::Module,
740     config: &ModuleConfig,
741     opt_level: llvm::CodeGenOptLevel,
742     prepare_for_thin_lto: bool,
743     f: &mut dyn FnMut(&llvm::PassManagerBuilder),
744 ) {
745     use std::ptr;
746
747     // Create the PassManagerBuilder for LLVM. We configure it with
748     // reasonable defaults and prepare it to actually populate the pass
749     // manager.
750     let builder = llvm::LLVMPassManagerBuilderCreate();
751     let opt_size =
752         config.opt_size.map(|x| to_llvm_opt_settings(x).1).unwrap_or(llvm::CodeGenOptSizeNone);
753     let inline_threshold = config.inline_threshold;
754
755     let pgo_gen_path = match config.pgo_gen {
756         SwitchWithOptPath::Enabled(ref opt_dir_path) => {
757             let path = if let Some(dir_path) = opt_dir_path {
758                 dir_path.join("default_%m.profraw")
759             } else {
760                 PathBuf::from("default_%m.profraw")
761             };
762
763             Some(CString::new(format!("{}", path.display())).unwrap())
764         }
765         SwitchWithOptPath::Disabled => None,
766     };
767
768     let pgo_use_path = config
769         .pgo_use
770         .as_ref()
771         .map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap());
772
773     llvm::LLVMRustConfigurePassManagerBuilder(
774         builder,
775         opt_level,
776         config.merge_functions,
777         config.vectorize_slp,
778         config.vectorize_loop,
779         prepare_for_thin_lto,
780         pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
781         pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
782     );
783
784     llvm::LLVMPassManagerBuilderSetSizeLevel(builder, opt_size as u32);
785
786     if opt_size != llvm::CodeGenOptSizeNone {
787         llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(builder, 1);
788     }
789
790     llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins);
791
792     // Here we match what clang does (kinda). For O0 we only inline
793     // always-inline functions (but don't add lifetime intrinsics), at O1 we
794     // inline with lifetime intrinsics, and O2+ we add an inliner with a
795     // thresholds copied from clang.
796     match (opt_level, opt_size, inline_threshold) {
797         (.., Some(t)) => {
798             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32);
799         }
800         (llvm::CodeGenOptLevel::Aggressive, ..) => {
801             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275);
802         }
803         (_, llvm::CodeGenOptSizeDefault, _) => {
804             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 75);
805         }
806         (_, llvm::CodeGenOptSizeAggressive, _) => {
807             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25);
808         }
809         (llvm::CodeGenOptLevel::None, ..) => {
810             llvm::LLVMRustAddAlwaysInlinePass(builder, false);
811         }
812         (llvm::CodeGenOptLevel::Less, ..) => {
813             llvm::LLVMRustAddAlwaysInlinePass(builder, true);
814         }
815         (llvm::CodeGenOptLevel::Default, ..) => {
816             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
817         }
818         (llvm::CodeGenOptLevel::Other, ..) => bug!("CodeGenOptLevel::Other selected"),
819     }
820
821     f(builder);
822     llvm::LLVMPassManagerBuilderDispose(builder);
823 }
824
825 // Create a `__imp_<symbol> = &symbol` global for every public static `symbol`.
826 // This is required to satisfy `dllimport` references to static data in .rlibs
827 // when using MSVC linker.  We do this only for data, as linker can fix up
828 // code references on its own.
829 // See #26591, #27438
830 fn create_msvc_imps(
831     cgcx: &CodegenContext<LlvmCodegenBackend>,
832     llcx: &llvm::Context,
833     llmod: &llvm::Module,
834 ) {
835     if !cgcx.msvc_imps_needed {
836         return;
837     }
838     // The x86 ABI seems to require that leading underscores are added to symbol
839     // names, so we need an extra underscore on x86. There's also a leading
840     // '\x01' here which disables LLVM's symbol mangling (e.g., no extra
841     // underscores added in front).
842     let prefix = if cgcx.target_arch == "x86" { "\x01__imp__" } else { "\x01__imp_" };
843
844     unsafe {
845         let i8p_ty = Type::i8p_llcx(llcx);
846         let globals = base::iter_globals(llmod)
847             .filter(|&val| {
848                 llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage
849                     && llvm::LLVMIsDeclaration(val) == 0
850             })
851             .filter_map(|val| {
852                 // Exclude some symbols that we know are not Rust symbols.
853                 let name = llvm::get_value_name(val);
854                 if ignored(name) { None } else { Some((val, name)) }
855             })
856             .map(move |(val, name)| {
857                 let mut imp_name = prefix.as_bytes().to_vec();
858                 imp_name.extend(name);
859                 let imp_name = CString::new(imp_name).unwrap();
860                 (imp_name, val)
861             })
862             .collect::<Vec<_>>();
863
864         for (imp_name, val) in globals {
865             let imp = llvm::LLVMAddGlobal(llmod, i8p_ty, imp_name.as_ptr().cast());
866             llvm::LLVMSetInitializer(imp, consts::ptrcast(val, i8p_ty));
867             llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage);
868         }
869     }
870
871     // Use this function to exclude certain symbols from `__imp` generation.
872     fn ignored(symbol_name: &[u8]) -> bool {
873         // These are symbols generated by LLVM's profiling instrumentation
874         symbol_name.starts_with(b"__llvm_profile_")
875     }
876 }