2 use crate::back
::bytecode
;
3 use crate::back
::lto
::ThinBuffer
;
6 use crate::llvm
::{self, DiagnosticInfo, PassManager, SMDiagnostic}
;
9 use crate::type_
::Type
;
10 use crate::context
::{is_pie_binary, get_reloc_model}
;
12 use crate::LlvmCodegenBackend
;
14 use rustc
::hir
::def_id
::LOCAL_CRATE
;
15 use rustc_codegen_ssa
::back
::write
::{CodegenContext, ModuleConfig, run_assembler}
;
16 use rustc_codegen_ssa
::traits
::*;
17 use rustc
::session
::config
::{self, OutputType, Passes, Lto, Sanitizer, SwitchWithOptPath}
;
18 use rustc
::session
::Session
;
19 use rustc
::ty
::TyCtxt
;
20 use rustc_codegen_ssa
::{RLIB_BYTECODE_EXTENSION, ModuleCodegen, CompiledModule}
;
21 use rustc
::util
::common
::time_ext
;
22 use rustc_fs_util
::{path_to_c_string, link_or_copy}
;
23 use rustc_data_structures
::small_c_str
::SmallCStr
;
24 use rustc_errors
::{Handler, FatalError}
;
27 use std
::ffi
::CString
;
29 use std
::io
::{self, Write}
;
30 use std
::path
::{Path, PathBuf}
;
34 use libc
::{c_int, c_uint, c_void, c_char, size_t}
;
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
),
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
),
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
),
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
),
67 pub fn write_output_file(
68 handler
: &rustc_errors
::Handler
,
69 target
: &'ll llvm
::TargetMachine
,
70 pm
: &llvm
::PassManager
<'ll
>,
73 file_type
: llvm
::FileType
) -> Result
<(), FatalError
> {
75 let output_c
= path_to_c_string(output
);
76 let result
= llvm
::LLVMRustWriteOutputFile(target
, pm
, m
, output_c
.as_ptr(), file_type
);
77 result
.into_result().map_err(|()| {
78 let msg
= format
!("could not write output to {}", output
.display());
79 llvm_err(handler
, &msg
)
84 pub fn create_informational_target_machine(
87 ) -> &'
static mut llvm
::TargetMachine
{
88 target_machine_factory(sess
, config
::OptLevel
::No
, find_features
)().unwrap_or_else(|err
| {
89 llvm_err(sess
.diagnostic(), &err
).raise()
93 pub fn create_target_machine(
96 ) -> &'
static mut llvm
::TargetMachine
{
97 target_machine_factory(&tcx
.sess
, tcx
.backend_optimization_level(LOCAL_CRATE
), find_features
)()
98 .unwrap_or_else(|err
| {
99 llvm_err(tcx
.sess
.diagnostic(), &err
).raise()
103 pub fn to_llvm_opt_settings(cfg
: config
::OptLevel
) -> (llvm
::CodeGenOptLevel
, llvm
::CodeGenOptSize
)
105 use self::config
::OptLevel
::*;
107 No
=> (llvm
::CodeGenOptLevel
::None
, llvm
::CodeGenOptSizeNone
),
108 Less
=> (llvm
::CodeGenOptLevel
::Less
, llvm
::CodeGenOptSizeNone
),
109 Default
=> (llvm
::CodeGenOptLevel
::Default
, llvm
::CodeGenOptSizeNone
),
110 Aggressive
=> (llvm
::CodeGenOptLevel
::Aggressive
, llvm
::CodeGenOptSizeNone
),
111 Size
=> (llvm
::CodeGenOptLevel
::Default
, llvm
::CodeGenOptSizeDefault
),
112 SizeMin
=> (llvm
::CodeGenOptLevel
::Default
, llvm
::CodeGenOptSizeAggressive
),
116 // If find_features is true this won't access `sess.crate_types` by assuming
117 // that `is_pie_binary` is false. When we discover LLVM target features
118 // `sess.crate_types` is uninitialized so we cannot access it.
119 pub fn target_machine_factory(sess
: &Session
, optlvl
: config
::OptLevel
, find_features
: bool
)
120 -> Arc
<dyn Fn() -> Result
<&'
static mut llvm
::TargetMachine
, String
> + Send
+ Sync
>
122 let reloc_model
= get_reloc_model(sess
);
124 let (opt_level
, _
) = to_llvm_opt_settings(optlvl
);
125 let use_softfp
= sess
.opts
.cg
.soft_float
;
127 let ffunction_sections
= sess
.target
.target
.options
.function_sections
;
128 let fdata_sections
= ffunction_sections
;
130 let code_model_arg
= sess
.opts
.cg
.code_model
.as_ref().or(
131 sess
.target
.target
.options
.code_model
.as_ref(),
134 let code_model
= match code_model_arg
{
136 match CODE_GEN_MODEL_ARGS
.iter().find(|arg
| arg
.0 == s
) {
139 sess
.err(&format
!("{:?} is not a valid code model",
141 sess
.abort_if_errors();
146 None
=> llvm
::CodeModel
::None
,
149 let features
= attributes
::llvm_target_features(sess
).collect
::<Vec
<_
>>();
150 let mut singlethread
= sess
.target
.target
.options
.singlethread
;
152 // On the wasm target once the `atomics` feature is enabled that means that
153 // we're no longer single-threaded, or otherwise we don't want LLVM to
154 // lower atomic operations to single-threaded operations.
156 sess
.target
.target
.llvm_target
.contains("wasm32") &&
157 features
.iter().any(|s
| *s
== "+atomics")
159 singlethread
= false;
162 let triple
= SmallCStr
::new(&sess
.target
.target
.llvm_target
);
163 let cpu
= SmallCStr
::new(llvm_util
::target_cpu(sess
));
164 let features
= features
.join(",");
165 let features
= CString
::new(features
).unwrap();
166 let abi
= SmallCStr
::new(&sess
.target
.target
.options
.llvm_abiname
);
167 let is_pie_binary
= !find_features
&& is_pie_binary(sess
);
168 let trap_unreachable
= sess
.target
.target
.options
.trap_unreachable
;
169 let emit_stack_size_section
= sess
.opts
.debugging_opts
.emit_stack_sizes
;
171 let asm_comments
= sess
.asm_comments();
172 let relax_elf_relocations
= sess
.target
.target
.options
.relax_elf_relocations
;
175 llvm
::LLVMRustCreateTargetMachine(
176 triple
.as_ptr(), cpu
.as_ptr(), features
.as_ptr(), abi
.as_ptr(),
187 emit_stack_size_section
,
188 relax_elf_relocations
,
193 format
!("Could not create LLVM TargetMachine for triple: {}",
194 triple
.to_str().unwrap())
199 pub(crate) fn save_temp_bitcode(
200 cgcx
: &CodegenContext
<LlvmCodegenBackend
>,
201 module
: &ModuleCodegen
<ModuleLlvm
>,
204 if !cgcx
.save_temps
{
208 let ext
= format
!("{}.bc", name
);
209 let cgu
= Some(&module
.name
[..]);
210 let path
= cgcx
.output_filenames
.temp_path_ext(&ext
, cgu
);
211 let cstr
= path_to_c_string(&path
);
212 let llmod
= module
.module_llvm
.llmod();
213 llvm
::LLVMWriteBitcodeToFile(llmod
, cstr
.as_ptr());
217 pub struct DiagnosticHandlers
<'a
> {
218 data
: *mut (&'a CodegenContext
<LlvmCodegenBackend
>, &'a Handler
),
219 llcx
: &'a llvm
::Context
,
222 impl<'a
> DiagnosticHandlers
<'a
> {
223 pub fn new(cgcx
: &'a CodegenContext
<LlvmCodegenBackend
>,
224 handler
: &'a Handler
,
225 llcx
: &'a llvm
::Context
) -> Self {
226 let data
= Box
::into_raw(Box
::new((cgcx
, handler
)));
228 llvm
::LLVMRustSetInlineAsmDiagnosticHandler(llcx
, inline_asm_handler
, data
.cast());
229 llvm
::LLVMContextSetDiagnosticHandler(llcx
, diagnostic_handler
, data
.cast());
231 DiagnosticHandlers { data, llcx }
235 impl<'a
> Drop
for DiagnosticHandlers
<'a
> {
237 use std
::ptr
::null_mut
;
239 llvm
::LLVMRustSetInlineAsmDiagnosticHandler(self.llcx
, inline_asm_handler
, null_mut());
240 llvm
::LLVMContextSetDiagnosticHandler(self.llcx
, diagnostic_handler
, null_mut());
241 drop(Box
::from_raw(self.data
));
246 unsafe extern "C" fn report_inline_asm(cgcx
: &CodegenContext
<LlvmCodegenBackend
>,
249 cgcx
.diag_emitter
.inline_asm_error(cookie
as u32, msg
.to_owned());
252 unsafe extern "C" fn inline_asm_handler(diag
: &SMDiagnostic
,
258 let (cgcx
, _
) = *(user
as *const (&CodegenContext
<LlvmCodegenBackend
>, &Handler
));
260 let msg
= llvm
::build_string(|s
| llvm
::LLVMRustWriteSMDiagnosticToString(diag
, s
))
261 .expect("non-UTF8 SMDiagnostic");
263 report_inline_asm(cgcx
, &msg
, cookie
);
266 unsafe extern "C" fn diagnostic_handler(info
: &DiagnosticInfo
, user
: *mut c_void
) {
270 let (cgcx
, diag_handler
) = *(user
as *const (&CodegenContext
<LlvmCodegenBackend
>, &Handler
));
272 match llvm
::diagnostic
::Diagnostic
::unpack(info
) {
273 llvm
::diagnostic
::InlineAsm(inline
) => {
274 report_inline_asm(cgcx
,
275 &llvm
::twine_to_string(inline
.message
),
279 llvm
::diagnostic
::Optimization(opt
) => {
280 let enabled
= match cgcx
.remark
{
282 Passes
::Some(ref v
) => v
.iter().any(|s
| *s
== opt
.pass_name
),
286 diag_handler
.note_without_error(&format
!("optimization {} for {} at {}:{}:{}: {}",
295 llvm
::diagnostic
::PGO(diagnostic_ref
) |
296 llvm
::diagnostic
::Linker(diagnostic_ref
) => {
297 let msg
= llvm
::build_string(|s
| {
298 llvm
::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref
, s
)
299 }).expect("non-UTF8 diagnostic");
300 diag_handler
.warn(&msg
);
302 llvm
::diagnostic
::UnknownDiagnostic(..) => {}
,
306 // Unsafe due to LLVM calls.
307 pub(crate) unsafe fn optimize(cgcx
: &CodegenContext
<LlvmCodegenBackend
>,
308 diag_handler
: &Handler
,
309 module
: &ModuleCodegen
<ModuleLlvm
>,
310 config
: &ModuleConfig
)
311 -> Result
<(), FatalError
>
313 let _timer
= cgcx
.prof
.generic_activity("LLVM_module_optimize");
315 let llmod
= module
.module_llvm
.llmod();
316 let llcx
= &*module
.module_llvm
.llcx
;
317 let tm
= &*module
.module_llvm
.tm
;
318 let _handlers
= DiagnosticHandlers
::new(cgcx
, diag_handler
, llcx
);
320 let module_name
= module
.name
.clone();
321 let module_name
= Some(&module_name
[..]);
323 if config
.emit_no_opt_bc
{
324 let out
= cgcx
.output_filenames
.temp_path_ext("no-opt.bc", module_name
);
325 let out
= path_to_c_string(&out
);
326 llvm
::LLVMWriteBitcodeToFile(llmod
, out
.as_ptr());
329 if let Some(opt_level
) = config
.opt_level
{
330 // Create the two optimizing pass managers. These mirror what clang
331 // does, and are by populated by LLVM's default PassManagerBuilder.
332 // Each manager has a different set of passes, but they also share
333 // some common passes.
334 let fpm
= llvm
::LLVMCreateFunctionPassManagerForModule(llmod
);
335 let mpm
= llvm
::LLVMCreatePassManager();
338 let find_pass
= |pass_name
: &str| {
339 let pass_name
= SmallCStr
::new(pass_name
);
340 llvm
::LLVMRustFindAndCreatePass(pass_name
.as_ptr())
343 if config
.verify_llvm_ir
{
344 // Verification should run as the very first pass.
345 llvm
::LLVMRustAddPass(fpm
, find_pass("verify").unwrap());
348 let mut extra_passes
= Vec
::new();
349 let mut have_name_anon_globals_pass
= false;
351 for pass_name
in &config
.passes
{
352 if pass_name
== "lint" {
353 // Linting should also be performed early, directly on the generated IR.
354 llvm
::LLVMRustAddPass(fpm
, find_pass("lint").unwrap());
358 if let Some(pass
) = find_pass(pass_name
) {
359 extra_passes
.push(pass
);
361 diag_handler
.warn(&format
!("unknown pass `{}`, ignoring", pass_name
));
364 if pass_name
== "name-anon-globals" {
365 have_name_anon_globals_pass
= true;
369 add_sanitizer_passes(config
, &mut extra_passes
);
371 // Some options cause LLVM bitcode to be emitted, which uses ThinLTOBuffers, so we need
372 // to make sure we run LLVM's NameAnonGlobals pass when emitting bitcode; otherwise
373 // we'll get errors in LLVM.
374 let using_thin_buffers
= config
.bitcode_needed();
375 if !config
.no_prepopulate_passes
{
376 llvm
::LLVMAddAnalysisPasses(tm
, fpm
);
377 llvm
::LLVMAddAnalysisPasses(tm
, mpm
);
378 let opt_level
= to_llvm_opt_settings(opt_level
).0;
379 let prepare_for_thin_lto
= cgcx
.lto
== Lto
::Thin
|| cgcx
.lto
== Lto
::ThinLocal
||
380 (cgcx
.lto
!= Lto
::Fat
&& cgcx
.opts
.cg
.linker_plugin_lto
.enabled());
381 with_llvm_pmb(llmod
, &config
, opt_level
, prepare_for_thin_lto
, &mut |b
| {
382 llvm
::LLVMRustAddLastExtensionPasses(
383 b
, extra_passes
.as_ptr(), extra_passes
.len() as size_t
);
384 llvm
::LLVMPassManagerBuilderPopulateFunctionPassManager(b
, fpm
);
385 llvm
::LLVMPassManagerBuilderPopulateModulePassManager(b
, mpm
);
388 have_name_anon_globals_pass
= have_name_anon_globals_pass
|| prepare_for_thin_lto
;
389 if using_thin_buffers
&& !prepare_for_thin_lto
{
390 llvm
::LLVMRustAddPass(mpm
, find_pass("name-anon-globals").unwrap());
391 have_name_anon_globals_pass
= true;
394 // If we don't use the standard pipeline, directly populate the MPM
395 // with the extra passes.
396 for pass
in extra_passes
{
397 llvm
::LLVMRustAddPass(mpm
, pass
);
401 if using_thin_buffers
&& !have_name_anon_globals_pass
{
402 // As described above, this will probably cause an error in LLVM
403 if config
.no_prepopulate_passes
{
404 diag_handler
.err("The current compilation is going to use thin LTO buffers \
405 without running LLVM's NameAnonGlobals pass. \
406 This will likely cause errors in LLVM. Consider adding \
407 -C passes=name-anon-globals to the compiler command line.");
409 bug
!("We are using thin LTO buffers without running the NameAnonGlobals pass. \
410 This will likely cause errors in LLVM and should never happen.");
415 diag_handler
.abort_if_errors();
417 // Finally, run the actual optimization passes
419 let _timer
= cgcx
.prof
.generic_activity("LLVM_module_optimize_function_passes");
420 time_ext(config
.time_passes
,
421 &format
!("llvm function passes [{}]", module_name
.unwrap()),
423 llvm
::LLVMRustRunFunctionPassManager(fpm
, llmod
)
427 let _timer
= cgcx
.prof
.generic_activity("LLVM_module_optimize_module_passes");
428 time_ext(config
.time_passes
,
429 &format
!("llvm module passes [{}]", module_name
.unwrap()),
431 llvm
::LLVMRunPassManager(mpm
, llmod
)
435 // Deallocate managers that we're now done with
436 llvm
::LLVMDisposePassManager(fpm
);
437 llvm
::LLVMDisposePassManager(mpm
);
442 unsafe fn add_sanitizer_passes(config
: &ModuleConfig
,
443 passes
: &mut Vec
<&'
static mut llvm
::Pass
>) {
445 let sanitizer
= match &config
.sanitizer
{
450 let recover
= config
.sanitizer_recover
.contains(sanitizer
);
452 Sanitizer
::Address
=> {
453 passes
.push(llvm
::LLVMRustCreateAddressSanitizerFunctionPass(recover
));
454 passes
.push(llvm
::LLVMRustCreateModuleAddressSanitizerPass(recover
));
456 Sanitizer
::Memory
=> {
457 let track_origins
= config
.sanitizer_memory_track_origins
as c_int
;
458 passes
.push(llvm
::LLVMRustCreateMemorySanitizerPass(track_origins
, recover
));
460 Sanitizer
::Thread
=> {
461 passes
.push(llvm
::LLVMRustCreateThreadSanitizerPass());
463 Sanitizer
::Leak
=> {}
467 pub(crate) unsafe fn codegen(cgcx
: &CodegenContext
<LlvmCodegenBackend
>,
468 diag_handler
: &Handler
,
469 module
: ModuleCodegen
<ModuleLlvm
>,
470 config
: &ModuleConfig
)
471 -> Result
<CompiledModule
, FatalError
>
473 let _timer
= cgcx
.prof
.generic_activity("LLVM_module_codegen");
475 let llmod
= module
.module_llvm
.llmod();
476 let llcx
= &*module
.module_llvm
.llcx
;
477 let tm
= &*module
.module_llvm
.tm
;
478 let module_name
= module
.name
.clone();
479 let module_name
= Some(&module_name
[..]);
480 let handlers
= DiagnosticHandlers
::new(cgcx
, diag_handler
, llcx
);
482 if cgcx
.msvc_imps_needed
{
483 create_msvc_imps(cgcx
, llcx
, llmod
);
486 // A codegen-specific pass manager is used to generate object
487 // files for an LLVM module.
489 // Apparently each of these pass managers is a one-shot kind of
490 // thing, so we create a new one for each type of output. The
491 // pass manager passed to the closure should be ensured to not
492 // escape the closure itself, and the manager should only be
494 unsafe fn with_codegen
<'ll
, F
, R
>(tm
: &'ll llvm
::TargetMachine
,
495 llmod
: &'ll llvm
::Module
,
498 where F
: FnOnce(&'ll
mut PassManager
<'ll
>) -> R
,
500 let cpm
= llvm
::LLVMCreatePassManager();
501 llvm
::LLVMAddAnalysisPasses(tm
, cpm
);
502 llvm
::LLVMRustAddLibraryInfo(cpm
, llmod
, no_builtins
);
506 // If we don't have the integrated assembler, then we need to emit asm
507 // from LLVM and use `gcc` to create the object file.
508 let asm_to_obj
= config
.emit_obj
&& config
.no_integrated_as
;
510 // Change what we write and cleanup based on whether obj files are
511 // just llvm bitcode. In that case write bitcode, and possibly
512 // delete the bitcode if it wasn't requested. Don't generate the
513 // machine code, instead copy the .o file from the .bc
514 let write_bc
= config
.emit_bc
|| config
.obj_is_bitcode
;
515 let rm_bc
= !config
.emit_bc
&& config
.obj_is_bitcode
;
516 let write_obj
= config
.emit_obj
&& !config
.obj_is_bitcode
&& !asm_to_obj
;
517 let copy_bc_to_obj
= config
.emit_obj
&& config
.obj_is_bitcode
;
519 let bc_out
= cgcx
.output_filenames
.temp_path(OutputType
::Bitcode
, module_name
);
520 let obj_out
= cgcx
.output_filenames
.temp_path(OutputType
::Object
, module_name
);
523 if write_bc
|| config
.emit_bc_compressed
|| config
.embed_bitcode
{
524 let _timer
= cgcx
.prof
.generic_activity("LLVM_module_codegen_make_bitcode");
525 let thin
= ThinBuffer
::new(llmod
);
526 let data
= thin
.data();
529 let _timer
= cgcx
.prof
.generic_activity("LLVM_module_codegen_emit_bitcode");
530 if let Err(e
) = fs
::write(&bc_out
, data
) {
531 let msg
= format
!("failed to write bytecode to {}: {}", bc_out
.display(), e
);
532 diag_handler
.err(&msg
);
536 if config
.embed_bitcode
{
537 let _timer
= cgcx
.prof
.generic_activity("LLVM_module_codegen_embed_bitcode");
538 embed_bitcode(cgcx
, llcx
, llmod
, Some(data
));
541 if config
.emit_bc_compressed
{
543 cgcx
.prof
.generic_activity("LLVM_module_codegen_emit_compressed_bitcode");
544 let dst
= bc_out
.with_extension(RLIB_BYTECODE_EXTENSION
);
545 let data
= bytecode
::encode(&module
.name
, data
);
546 if let Err(e
) = fs
::write(&dst
, data
) {
547 let msg
= format
!("failed to write bytecode to {}: {}", dst
.display(), e
);
548 diag_handler
.err(&msg
);
551 } else if config
.embed_bitcode_marker
{
552 embed_bitcode(cgcx
, llcx
, llmod
, None
);
555 time_ext(config
.time_passes
, &format
!("codegen passes [{}]", module_name
.unwrap()),
556 || -> Result
<(), FatalError
> {
558 let _timer
= cgcx
.prof
.generic_activity("LLVM_module_codegen_emit_ir");
559 let out
= cgcx
.output_filenames
.temp_path(OutputType
::LlvmAssembly
, module_name
);
560 let out_c
= path_to_c_string(&out
);
562 extern "C" fn demangle_callback(input_ptr
: *const c_char
,
564 output_ptr
: *mut c_char
,
565 output_len
: size_t
) -> size_t
{
567 slice
::from_raw_parts(input_ptr
as *const u8, input_len
as usize)
570 let input
= match str::from_utf8(input
) {
575 let output
= unsafe {
576 slice
::from_raw_parts_mut(output_ptr
as *mut u8, output_len
as usize)
578 let mut cursor
= io
::Cursor
::new(output
);
580 let demangled
= match rustc_demangle
::try_demangle(input
) {
585 if let Err(_
) = write
!(cursor
, "{:#}", demangled
) {
586 // Possible only if provided buffer is not big enough
590 cursor
.position() as size_t
594 llvm
::LLVMRustPrintModule(llmod
, out_c
.as_ptr(), demangle_callback
);
595 result
.into_result().map_err(|()| {
596 let msg
= format
!("failed to write LLVM IR to {}", out
.display());
597 llvm_err(diag_handler
, &msg
)
601 if config
.emit_asm
|| asm_to_obj
{
602 let _timer
= cgcx
.prof
.generic_activity("LLVM_module_codegen_emit_asm");
603 let path
= cgcx
.output_filenames
.temp_path(OutputType
::Assembly
, module_name
);
605 // We can't use the same module for asm and binary output, because that triggers
606 // various errors like invalid IR or broken binaries, so we might have to clone the
607 // module to produce the asm output
608 let llmod
= if config
.emit_obj
{
609 llvm
::LLVMCloneModule(llmod
)
613 with_codegen(tm
, llmod
, config
.no_builtins
, |cpm
| {
614 write_output_file(diag_handler
, tm
, cpm
, llmod
, &path
,
615 llvm
::FileType
::AssemblyFile
)
620 let _timer
= cgcx
.prof
.generic_activity("LLVM_module_codegen_emit_obj");
621 with_codegen(tm
, llmod
, config
.no_builtins
, |cpm
| {
622 write_output_file(diag_handler
, tm
, cpm
, llmod
, &obj_out
,
623 llvm
::FileType
::ObjectFile
)
625 } else if asm_to_obj
{
626 let _timer
= cgcx
.prof
.generic_activity("LLVM_module_codegen_asm_to_obj");
627 let assembly
= cgcx
.output_filenames
.temp_path(OutputType
::Assembly
, module_name
);
628 run_assembler(cgcx
, diag_handler
, &assembly
, &obj_out
);
630 if !config
.emit_asm
&& !cgcx
.save_temps
{
631 drop(fs
::remove_file(&assembly
));
639 debug
!("copying bitcode {:?} to obj {:?}", bc_out
, obj_out
);
640 if let Err(e
) = link_or_copy(&bc_out
, &obj_out
) {
641 diag_handler
.err(&format
!("failed to copy bitcode to object file: {}", e
));
646 debug
!("removing_bitcode {:?}", bc_out
);
647 if let Err(e
) = fs
::remove_file(&bc_out
) {
648 diag_handler
.err(&format
!("failed to remove bitcode: {}", e
));
654 Ok(module
.into_compiled_module(config
.emit_obj
,
656 config
.emit_bc_compressed
,
657 &cgcx
.output_filenames
))
660 /// Embed the bitcode of an LLVM module in the LLVM module itself.
662 /// This is done primarily for iOS where it appears to be standard to compile C
663 /// code at least with `-fembed-bitcode` which creates two sections in the
666 /// * __LLVM,__bitcode
667 /// * __LLVM,__cmdline
669 /// It appears *both* of these sections are necessary to get the linker to
670 /// recognize what's going on. For us though we just always throw in an empty
673 /// Furthermore debug/O1 builds don't actually embed bitcode but rather just
674 /// embed an empty section.
676 /// Basically all of this is us attempting to follow in the footsteps of clang
677 /// on iOS. See #35968 for lots more info.
678 unsafe fn embed_bitcode(cgcx
: &CodegenContext
<LlvmCodegenBackend
>,
679 llcx
: &llvm
::Context
,
680 llmod
: &llvm
::Module
,
681 bitcode
: Option
<&[u8]>) {
682 let llconst
= common
::bytes_in_context(llcx
, bitcode
.unwrap_or(&[]));
683 let llglobal
= llvm
::LLVMAddGlobal(
685 common
::val_ty(llconst
),
686 "rustc.embedded.module\0".as_ptr().cast(),
688 llvm
::LLVMSetInitializer(llglobal
, llconst
);
690 let is_apple
= cgcx
.opts
.target_triple
.triple().contains("-ios") ||
691 cgcx
.opts
.target_triple
.triple().contains("-darwin");
693 let section
= if is_apple
{
698 llvm
::LLVMSetSection(llglobal
, section
.as_ptr().cast());
699 llvm
::LLVMRustSetLinkage(llglobal
, llvm
::Linkage
::PrivateLinkage
);
700 llvm
::LLVMSetGlobalConstant(llglobal
, llvm
::True
);
702 let llconst
= common
::bytes_in_context(llcx
, &[]);
703 let llglobal
= llvm
::LLVMAddGlobal(
705 common
::val_ty(llconst
),
706 "rustc.embedded.cmdline\0".as_ptr().cast(),
708 llvm
::LLVMSetInitializer(llglobal
, llconst
);
709 let section
= if is_apple
{
714 llvm
::LLVMSetSection(llglobal
, section
.as_ptr().cast());
715 llvm
::LLVMRustSetLinkage(llglobal
, llvm
::Linkage
::PrivateLinkage
);
718 pub unsafe fn with_llvm_pmb(llmod
: &llvm
::Module
,
719 config
: &ModuleConfig
,
720 opt_level
: llvm
::CodeGenOptLevel
,
721 prepare_for_thin_lto
: bool
,
722 f
: &mut dyn FnMut(&llvm
::PassManagerBuilder
)) {
725 // Create the PassManagerBuilder for LLVM. We configure it with
726 // reasonable defaults and prepare it to actually populate the pass
728 let builder
= llvm
::LLVMPassManagerBuilderCreate();
729 let opt_size
= config
.opt_size
.map(|x
| to_llvm_opt_settings(x
).1)
730 .unwrap_or(llvm
::CodeGenOptSizeNone
);
731 let inline_threshold
= config
.inline_threshold
;
733 let pgo_gen_path
= match config
.pgo_gen
{
734 SwitchWithOptPath
::Enabled(ref opt_dir_path
) => {
735 let path
= if let Some(dir_path
) = opt_dir_path
{
736 dir_path
.join("default_%m.profraw")
738 PathBuf
::from("default_%m.profraw")
741 Some(CString
::new(format
!("{}", path
.display())).unwrap())
743 SwitchWithOptPath
::Disabled
=> {
748 let pgo_use_path
= config
.pgo_use
.as_ref().map(|path_buf
| {
749 CString
::new(path_buf
.to_string_lossy().as_bytes()).unwrap()
752 llvm
::LLVMRustConfigurePassManagerBuilder(
755 config
.merge_functions
,
756 config
.vectorize_slp
,
757 config
.vectorize_loop
,
758 prepare_for_thin_lto
,
759 pgo_gen_path
.as_ref().map_or(ptr
::null(), |s
| s
.as_ptr()),
760 pgo_use_path
.as_ref().map_or(ptr
::null(), |s
| s
.as_ptr()),
763 llvm
::LLVMPassManagerBuilderSetSizeLevel(builder
, opt_size
as u32);
765 if opt_size
!= llvm
::CodeGenOptSizeNone
{
766 llvm
::LLVMPassManagerBuilderSetDisableUnrollLoops(builder
, 1);
769 llvm
::LLVMRustAddBuilderLibraryInfo(builder
, llmod
, config
.no_builtins
);
771 // Here we match what clang does (kinda). For O0 we only inline
772 // always-inline functions (but don't add lifetime intrinsics), at O1 we
773 // inline with lifetime intrinsics, and O2+ we add an inliner with a
774 // thresholds copied from clang.
775 match (opt_level
, opt_size
, inline_threshold
) {
777 llvm
::LLVMPassManagerBuilderUseInlinerWithThreshold(builder
, t
as u32);
779 (llvm
::CodeGenOptLevel
::Aggressive
, ..) => {
780 llvm
::LLVMPassManagerBuilderUseInlinerWithThreshold(builder
, 275);
782 (_
, llvm
::CodeGenOptSizeDefault
, _
) => {
783 llvm
::LLVMPassManagerBuilderUseInlinerWithThreshold(builder
, 75);
785 (_
, llvm
::CodeGenOptSizeAggressive
, _
) => {
786 llvm
::LLVMPassManagerBuilderUseInlinerWithThreshold(builder
, 25);
788 (llvm
::CodeGenOptLevel
::None
, ..) => {
789 llvm
::LLVMRustAddAlwaysInlinePass(builder
, false);
791 (llvm
::CodeGenOptLevel
::Less
, ..) => {
792 llvm
::LLVMRustAddAlwaysInlinePass(builder
, true);
794 (llvm
::CodeGenOptLevel
::Default
, ..) => {
795 llvm
::LLVMPassManagerBuilderUseInlinerWithThreshold(builder
, 225);
797 (llvm
::CodeGenOptLevel
::Other
, ..) => {
798 bug
!("CodeGenOptLevel::Other selected")
803 llvm
::LLVMPassManagerBuilderDispose(builder
);
806 // Create a `__imp_<symbol> = &symbol` global for every public static `symbol`.
807 // This is required to satisfy `dllimport` references to static data in .rlibs
808 // when using MSVC linker. We do this only for data, as linker can fix up
809 // code references on its own.
810 // See #26591, #27438
812 cgcx
: &CodegenContext
<LlvmCodegenBackend
>,
813 llcx
: &llvm
::Context
,
816 if !cgcx
.msvc_imps_needed
{
819 // The x86 ABI seems to require that leading underscores are added to symbol
820 // names, so we need an extra underscore on x86. There's also a leading
821 // '\x01' here which disables LLVM's symbol mangling (e.g., no extra
822 // underscores added in front).
823 let prefix
= if cgcx
.target_arch
== "x86" {
830 let i8p_ty
= Type
::i8p_llcx(llcx
);
831 let globals
= base
::iter_globals(llmod
)
833 llvm
::LLVMRustGetLinkage(val
) == llvm
::Linkage
::ExternalLinkage
&&
834 llvm
::LLVMIsDeclaration(val
) == 0
837 // Exclude some symbols that we know are not Rust symbols.
838 let name
= llvm
::get_value_name(val
);
845 .map(move |(val
, name
)| {
846 let mut imp_name
= prefix
.as_bytes().to_vec();
847 imp_name
.extend(name
);
848 let imp_name
= CString
::new(imp_name
).unwrap();
851 .collect
::<Vec
<_
>>();
853 for (imp_name
, val
) in globals
{
854 let imp
= llvm
::LLVMAddGlobal(llmod
,
856 imp_name
.as_ptr().cast());
857 llvm
::LLVMSetInitializer(imp
, consts
::ptrcast(val
, i8p_ty
));
858 llvm
::LLVMRustSetLinkage(imp
, llvm
::Linkage
::ExternalLinkage
);
862 // Use this function to exclude certain symbols from `__imp` generation.
863 fn ignored(symbol_name
: &[u8]) -> bool
{
864 // These are symbols generated by LLVM's profiling instrumentation
865 symbol_name
.starts_with(b
"__llvm_profile_")