]>
Commit | Line | Data |
---|---|---|
9fa01778 | 1 | use crate::attributes; |
48663c56 | 2 | use crate::back::bytecode; |
9fa01778 XL |
3 | use crate::back::lto::ThinBuffer; |
4 | use crate::base; | |
5 | use crate::consts; | |
9fa01778 XL |
6 | use crate::llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic}; |
7 | use crate::llvm_util; | |
8 | use crate::ModuleLlvm; | |
9 | use crate::type_::Type; | |
10 | use crate::context::{is_pie_binary, get_reloc_model}; | |
11 | use crate::common; | |
12 | use crate::LlvmCodegenBackend; | |
60c5eb7d | 13 | use rustc::bug; |
532ac7d7 | 14 | use rustc::hir::def_id::LOCAL_CRATE; |
a1dfa0c6 XL |
15 | use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, run_assembler}; |
16 | use rustc_codegen_ssa::traits::*; | |
60c5eb7d | 17 | use rustc::session::config::{self, OutputType, Passes, Lto, Sanitizer, SwitchWithOptPath}; |
7cac9316 | 18 | use rustc::session::Session; |
9fa01778 | 19 | use rustc::ty::TyCtxt; |
48663c56 | 20 | use rustc_codegen_ssa::{RLIB_BYTECODE_EXTENSION, ModuleCodegen, CompiledModule}; |
a1dfa0c6 XL |
21 | use rustc::util::common::time_ext; |
22 | use rustc_fs_util::{path_to_c_string, link_or_copy}; | |
b7449926 | 23 | use rustc_data_structures::small_c_str::SmallCStr; |
60c5eb7d XL |
24 | use rustc_errors::{Handler, FatalError}; |
25 | use log::debug; | |
1a4d82fc | 26 | |
60c5eb7d | 27 | use std::ffi::CString; |
2c00a5a8 XL |
28 | use std::fs; |
29 | use std::io::{self, Write}; | |
48663c56 | 30 | use std::path::{Path, PathBuf}; |
1a4d82fc | 31 | use std::str; |
3b2f2976 | 32 | use std::sync::Arc; |
041b39d2 | 33 | use std::slice; |
60c5eb7d | 34 | use libc::{c_int, c_uint, c_void, c_char, size_t}; |
1a4d82fc | 35 | |
a1dfa0c6 | 36 | pub const RELOC_MODEL_ARGS : [(&str, llvm::RelocMode); 7] = [ |
5bcae85e SL |
37 | ("pic", llvm::RelocMode::PIC), |
38 | ("static", llvm::RelocMode::Static), | |
39 | ("default", llvm::RelocMode::Default), | |
40 | ("dynamic-no-pic", llvm::RelocMode::DynamicNoPic), | |
7cac9316 XL |
41 | ("ropi", llvm::RelocMode::ROPI), |
42 | ("rwpi", llvm::RelocMode::RWPI), | |
43 | ("ropi-rwpi", llvm::RelocMode::ROPI_RWPI), | |
5bcae85e SL |
44 | ]; |
45 | ||
2c00a5a8 | 46 | pub const CODE_GEN_MODEL_ARGS: &[(&str, llvm::CodeModel)] = &[ |
5bcae85e SL |
47 | ("small", llvm::CodeModel::Small), |
48 | ("kernel", llvm::CodeModel::Kernel), | |
49 | ("medium", llvm::CodeModel::Medium), | |
50 | ("large", llvm::CodeModel::Large), | |
51 | ]; | |
52 | ||
a1dfa0c6 | 53 | pub const TLS_MODEL_ARGS : [(&str, llvm::ThreadLocalMode); 4] = [ |
abe05a73 XL |
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 | ||
60c5eb7d | 60 | pub fn llvm_err(handler: &rustc_errors::Handler, msg: &str) -> FatalError { |
7453a54e | 61 | match llvm::last_error() { |
041b39d2 XL |
62 | Some(err) => handler.fatal(&format!("{}: {}", msg, err)), |
63 | None => handler.fatal(&msg), | |
1a4d82fc JJ |
64 | } |
65 | } | |
66 | ||
67 | pub fn write_output_file( | |
60c5eb7d | 68 | handler: &rustc_errors::Handler, |
b7449926 XL |
69 | target: &'ll llvm::TargetMachine, |
70 | pm: &llvm::PassManager<'ll>, | |
71 | m: &'ll llvm::Module, | |
1a4d82fc | 72 | output: &Path, |
041b39d2 | 73 | file_type: llvm::FileType) -> Result<(), FatalError> { |
1a4d82fc | 74 | unsafe { |
a1dfa0c6 XL |
75 | let output_c = path_to_c_string(output); |
76 | let result = llvm::LLVMRustWriteOutputFile(target, pm, m, output_c.as_ptr(), file_type); | |
532ac7d7 | 77 | result.into_result().map_err(|()| { |
041b39d2 | 78 | let msg = format!("could not write output to {}", output.display()); |
532ac7d7 XL |
79 | llvm_err(handler, &msg) |
80 | }) | |
1a4d82fc | 81 | } |
1a4d82fc JJ |
82 | } |
83 | ||
9fa01778 | 84 | pub fn create_informational_target_machine( |
b7449926 XL |
85 | sess: &Session, |
86 | find_features: bool, | |
87 | ) -> &'static mut llvm::TargetMachine { | |
9fa01778 | 88 | target_machine_factory(sess, config::OptLevel::No, find_features)().unwrap_or_else(|err| { |
a1dfa0c6 | 89 | llvm_err(sess.diagnostic(), &err).raise() |
ea8adc8c XL |
90 | }) |
91 | } | |
92 | ||
532ac7d7 | 93 | pub fn create_target_machine( |
dc9dc135 | 94 | tcx: TyCtxt<'_>, |
532ac7d7 XL |
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| { | |
99 | llvm_err(tcx.sess.diagnostic(), &err).raise() | |
100 | }) | |
101 | } | |
9fa01778 XL |
102 | |
103 | pub fn to_llvm_opt_settings(cfg: config::OptLevel) -> (llvm::CodeGenOptLevel, llvm::CodeGenOptSize) | |
104 | { | |
105 | use self::config::OptLevel::*; | |
106 | match cfg { | |
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), | |
113 | } | |
114 | } | |
115 | ||
83c7162d XL |
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. | |
9fa01778 | 119 | pub fn target_machine_factory(sess: &Session, optlvl: config::OptLevel, find_features: bool) |
b7449926 | 120 | -> Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync> |
ea8adc8c | 121 | { |
5bcae85e | 122 | let reloc_model = get_reloc_model(sess); |
1a4d82fc | 123 | |
9fa01778 | 124 | let (opt_level, _) = to_llvm_opt_settings(optlvl); |
1a4d82fc JJ |
125 | let use_softfp = sess.opts.cg.soft_float; |
126 | ||
1a4d82fc JJ |
127 | let ffunction_sections = sess.target.target.options.function_sections; |
128 | let fdata_sections = ffunction_sections; | |
129 | ||
2c00a5a8 XL |
130 | let code_model_arg = sess.opts.cg.code_model.as_ref().or( |
131 | sess.target.target.options.code_model.as_ref(), | |
132 | ); | |
133 | ||
134 | let code_model = match code_model_arg { | |
135 | Some(s) => { | |
136 | match CODE_GEN_MODEL_ARGS.iter().find(|arg| arg.0 == s) { | |
137 | Some(x) => x.1, | |
138 | _ => { | |
139 | sess.err(&format!("{:?} is not a valid code model", | |
140 | code_model_arg)); | |
141 | sess.abort_if_errors(); | |
142 | bug!(); | |
143 | } | |
144 | } | |
1a4d82fc | 145 | } |
2c00a5a8 | 146 | None => llvm::CodeModel::None, |
1a4d82fc JJ |
147 | }; |
148 | ||
b7449926 XL |
149 | let features = attributes::llvm_target_features(sess).collect::<Vec<_>>(); |
150 | let mut singlethread = sess.target.target.options.singlethread; | |
abe05a73 | 151 | |
b7449926 XL |
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. | |
155 | if singlethread && | |
156 | sess.target.target.llvm_target.contains("wasm32") && | |
157 | features.iter().any(|s| *s == "+atomics") | |
158 | { | |
159 | singlethread = false; | |
160 | } | |
1a4d82fc | 161 | |
b7449926 XL |
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(","); | |
83c7162d | 165 | let features = CString::new(features).unwrap(); |
60c5eb7d | 166 | let abi = SmallCStr::new(&sess.target.target.options.llvm_abiname); |
83c7162d | 167 | let is_pie_binary = !find_features && is_pie_binary(sess); |
abe05a73 | 168 | let trap_unreachable = sess.target.target.options.trap_unreachable; |
0bf4aa26 | 169 | let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes; |
ea8adc8c | 170 | |
b7449926 | 171 | let asm_comments = sess.asm_comments(); |
60c5eb7d | 172 | let relax_elf_relocations = sess.target.target.options.relax_elf_relocations; |
ea8adc8c XL |
173 | Arc::new(move || { |
174 | let tm = unsafe { | |
175 | llvm::LLVMRustCreateTargetMachine( | |
60c5eb7d | 176 | triple.as_ptr(), cpu.as_ptr(), features.as_ptr(), abi.as_ptr(), |
ea8adc8c XL |
177 | code_model, |
178 | reloc_model, | |
179 | opt_level, | |
180 | use_softfp, | |
181 | is_pie_binary, | |
182 | ffunction_sections, | |
183 | fdata_sections, | |
abe05a73 XL |
184 | trap_unreachable, |
185 | singlethread, | |
b7449926 | 186 | asm_comments, |
0bf4aa26 | 187 | emit_stack_size_section, |
60c5eb7d | 188 | relax_elf_relocations, |
ea8adc8c XL |
189 | ) |
190 | }; | |
1a4d82fc | 191 | |
b7449926 XL |
192 | tm.ok_or_else(|| { |
193 | format!("Could not create LLVM TargetMachine for triple: {}", | |
194 | triple.to_str().unwrap()) | |
195 | }) | |
ea8adc8c | 196 | }) |
1a4d82fc JJ |
197 | } |
198 | ||
a1dfa0c6 XL |
199 | pub(crate) fn save_temp_bitcode( |
200 | cgcx: &CodegenContext<LlvmCodegenBackend>, | |
201 | module: &ModuleCodegen<ModuleLlvm>, | |
202 | name: &str | |
203 | ) { | |
204 | if !cgcx.save_temps { | |
205 | return | |
ea8adc8c | 206 | } |
a1dfa0c6 XL |
207 | unsafe { |
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()); | |
ea8adc8c XL |
214 | } |
215 | } | |
216 | ||
b7449926 | 217 | pub struct DiagnosticHandlers<'a> { |
a1dfa0c6 | 218 | data: *mut (&'a CodegenContext<LlvmCodegenBackend>, &'a Handler), |
b7449926 | 219 | llcx: &'a llvm::Context, |
ea8adc8c XL |
220 | } |
221 | ||
222 | impl<'a> DiagnosticHandlers<'a> { | |
a1dfa0c6 | 223 | pub fn new(cgcx: &'a CodegenContext<LlvmCodegenBackend>, |
b7449926 XL |
224 | handler: &'a Handler, |
225 | llcx: &'a llvm::Context) -> Self { | |
8faf50e0 | 226 | let data = Box::into_raw(Box::new((cgcx, handler))); |
ea8adc8c | 227 | unsafe { |
e74abb32 XL |
228 | llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data.cast()); |
229 | llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, data.cast()); | |
ea8adc8c | 230 | } |
8faf50e0 | 231 | DiagnosticHandlers { data, llcx } |
ea8adc8c | 232 | } |
1a4d82fc JJ |
233 | } |
234 | ||
ea8adc8c XL |
235 | impl<'a> Drop for DiagnosticHandlers<'a> { |
236 | fn drop(&mut self) { | |
8faf50e0 | 237 | use std::ptr::null_mut; |
ea8adc8c | 238 | unsafe { |
8faf50e0 XL |
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)); | |
ea8adc8c XL |
242 | } |
243 | } | |
1a4d82fc JJ |
244 | } |
245 | ||
416331ca XL |
246 | unsafe extern "C" fn report_inline_asm(cgcx: &CodegenContext<LlvmCodegenBackend>, |
247 | msg: &str, | |
248 | cookie: c_uint) { | |
a1dfa0c6 | 249 | cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_owned()); |
1a4d82fc JJ |
250 | } |
251 | ||
b7449926 | 252 | unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic, |
85aaf69f SL |
253 | user: *const c_void, |
254 | cookie: c_uint) { | |
ea8adc8c XL |
255 | if user.is_null() { |
256 | return | |
257 | } | |
a1dfa0c6 | 258 | let (cgcx, _) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, &Handler)); |
85aaf69f | 259 | |
5bcae85e | 260 | let msg = llvm::build_string(|s| llvm::LLVMRustWriteSMDiagnosticToString(diag, s)) |
85aaf69f SL |
261 | .expect("non-UTF8 SMDiagnostic"); |
262 | ||
cc61c64b | 263 | report_inline_asm(cgcx, &msg, cookie); |
85aaf69f SL |
264 | } |
265 | ||
b7449926 | 266 | unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) { |
ea8adc8c XL |
267 | if user.is_null() { |
268 | return | |
269 | } | |
a1dfa0c6 | 270 | let (cgcx, diag_handler) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, &Handler)); |
1a4d82fc JJ |
271 | |
272 | match llvm::diagnostic::Diagnostic::unpack(info) { | |
85aaf69f SL |
273 | llvm::diagnostic::InlineAsm(inline) => { |
274 | report_inline_asm(cgcx, | |
7453a54e | 275 | &llvm::twine_to_string(inline.message), |
85aaf69f SL |
276 | inline.cookie); |
277 | } | |
278 | ||
1a4d82fc | 279 | llvm::diagnostic::Optimization(opt) => { |
1a4d82fc | 280 | let enabled = match cgcx.remark { |
b7449926 XL |
281 | Passes::All => true, |
282 | Passes::Some(ref v) => v.iter().any(|s| *s == opt.pass_name), | |
1a4d82fc JJ |
283 | }; |
284 | ||
285 | if enabled { | |
3b2f2976 | 286 | diag_handler.note_without_error(&format!("optimization {} for {} at {}:{}:{}: {}", |
9cc50fc6 | 287 | opt.kind.describe(), |
476ff2be | 288 | opt.pass_name, |
3b2f2976 XL |
289 | opt.filename, |
290 | opt.line, | |
291 | opt.column, | |
476ff2be | 292 | opt.message)); |
1a4d82fc JJ |
293 | } |
294 | } | |
b7449926 XL |
295 | llvm::diagnostic::PGO(diagnostic_ref) | |
296 | llvm::diagnostic::Linker(diagnostic_ref) => { | |
0531ce1d XL |
297 | let msg = llvm::build_string(|s| { |
298 | llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) | |
b7449926 | 299 | }).expect("non-UTF8 diagnostic"); |
0531ce1d XL |
300 | diag_handler.warn(&msg); |
301 | } | |
302 | llvm::diagnostic::UnknownDiagnostic(..) => {}, | |
1a4d82fc JJ |
303 | } |
304 | } | |
305 | ||
306 | // Unsafe due to LLVM calls. | |
a1dfa0c6 | 307 | pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>, |
ea8adc8c | 308 | diag_handler: &Handler, |
a1dfa0c6 | 309 | module: &ModuleCodegen<ModuleLlvm>, |
532ac7d7 | 310 | config: &ModuleConfig) |
ea8adc8c | 311 | -> Result<(), FatalError> |
041b39d2 | 312 | { |
e74abb32 XL |
313 | let _timer = cgcx.prof.generic_activity("LLVM_module_optimize"); |
314 | ||
b7449926 XL |
315 | let llmod = module.module_llvm.llmod(); |
316 | let llcx = &*module.module_llvm.llcx; | |
317 | let tm = &*module.module_llvm.tm; | |
ea8adc8c | 318 | let _handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx); |
1a4d82fc | 319 | |
94b46f34 | 320 | let module_name = module.name.clone(); |
3b2f2976 | 321 | let module_name = Some(&module_name[..]); |
5bcae85e | 322 | |
1a4d82fc | 323 | if config.emit_no_opt_bc { |
ea8adc8c | 324 | let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name); |
a1dfa0c6 | 325 | let out = path_to_c_string(&out); |
1a4d82fc JJ |
326 | llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); |
327 | } | |
328 | ||
60c5eb7d | 329 | if let Some(opt_level) = config.opt_level { |
c1a9b12d SL |
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(); | |
336 | ||
b7449926 | 337 | { |
416331ca | 338 | let find_pass = |pass_name: &str| { |
b7449926 | 339 | let pass_name = SmallCStr::new(pass_name); |
416331ca | 340 | llvm::LLVMRustFindAndCreatePass(pass_name.as_ptr()) |
7453a54e | 341 | }; |
1a4d82fc | 342 | |
416331ca XL |
343 | if config.verify_llvm_ir { |
344 | // Verification should run as the very first pass. | |
345 | llvm::LLVMRustAddPass(fpm, find_pass("verify").unwrap()); | |
346 | } | |
347 | ||
348 | let mut extra_passes = Vec::new(); | |
349 | let mut have_name_anon_globals_pass = false; | |
350 | ||
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()); | |
355 | continue; | |
356 | } | |
357 | ||
358 | if let Some(pass) = find_pass(pass_name) { | |
359 | extra_passes.push(pass); | |
360 | } else { | |
361 | diag_handler.warn(&format!("unknown pass `{}`, ignoring", pass_name)); | |
362 | } | |
363 | ||
364 | if pass_name == "name-anon-globals" { | |
365 | have_name_anon_globals_pass = true; | |
366 | } | |
367 | } | |
368 | ||
60c5eb7d | 369 | add_sanitizer_passes(config, &mut extra_passes); |
b7449926 XL |
370 | |
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. | |
a1dfa0c6 | 374 | let using_thin_buffers = config.bitcode_needed(); |
b7449926 | 375 | if !config.no_prepopulate_passes { |
60c5eb7d XL |
376 | llvm::LLVMAddAnalysisPasses(tm, fpm); |
377 | llvm::LLVMAddAnalysisPasses(tm, mpm); | |
378 | let opt_level = to_llvm_opt_settings(opt_level).0; | |
b7449926 | 379 | let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal || |
9fa01778 | 380 | (cgcx.lto != Lto::Fat && cgcx.opts.cg.linker_plugin_lto.enabled()); |
a1dfa0c6 | 381 | with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| { |
416331ca XL |
382 | llvm::LLVMRustAddLastExtensionPasses( |
383 | b, extra_passes.as_ptr(), extra_passes.len() as size_t); | |
a1dfa0c6 XL |
384 | llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm); |
385 | llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm); | |
386 | }); | |
387 | ||
b7449926 XL |
388 | have_name_anon_globals_pass = have_name_anon_globals_pass || prepare_for_thin_lto; |
389 | if using_thin_buffers && !prepare_for_thin_lto { | |
416331ca | 390 | llvm::LLVMRustAddPass(mpm, find_pass("name-anon-globals").unwrap()); |
b7449926 XL |
391 | have_name_anon_globals_pass = true; |
392 | } | |
416331ca XL |
393 | } else { |
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); | |
b7449926 | 398 | } |
1a4d82fc JJ |
399 | } |
400 | ||
b7449926 XL |
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 \ | |
a1dfa0c6 XL |
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."); | |
b7449926 XL |
408 | } else { |
409 | bug!("We are using thin LTO buffers without running the NameAnonGlobals pass. \ | |
a1dfa0c6 | 410 | This will likely cause errors in LLVM and should never happen."); |
b7449926 | 411 | } |
9346a6ac | 412 | } |
c1a9b12d | 413 | } |
9346a6ac | 414 | |
3b2f2976 | 415 | diag_handler.abort_if_errors(); |
9346a6ac | 416 | |
c1a9b12d | 417 | // Finally, run the actual optimization passes |
532ac7d7 | 418 | { |
e74abb32 | 419 | let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_function_passes"); |
532ac7d7 | 420 | time_ext(config.time_passes, |
532ac7d7 XL |
421 | &format!("llvm function passes [{}]", module_name.unwrap()), |
422 | || { | |
423 | llvm::LLVMRustRunFunctionPassManager(fpm, llmod) | |
424 | }); | |
425 | } | |
426 | { | |
e74abb32 | 427 | let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_module_passes"); |
532ac7d7 | 428 | time_ext(config.time_passes, |
532ac7d7 XL |
429 | &format!("llvm module passes [{}]", module_name.unwrap()), |
430 | || { | |
431 | llvm::LLVMRunPassManager(mpm, llmod) | |
432 | }); | |
433 | } | |
1a4d82fc | 434 | |
c1a9b12d SL |
435 | // Deallocate managers that we're now done with |
436 | llvm::LLVMDisposePassManager(fpm); | |
437 | llvm::LLVMDisposePassManager(mpm); | |
ea8adc8c XL |
438 | } |
439 | Ok(()) | |
440 | } | |
1a4d82fc | 441 | |
60c5eb7d XL |
442 | unsafe fn add_sanitizer_passes(config: &ModuleConfig, |
443 | passes: &mut Vec<&'static mut llvm::Pass>) { | |
444 | ||
445 | let sanitizer = match &config.sanitizer { | |
446 | None => return, | |
447 | Some(s) => s, | |
448 | }; | |
449 | ||
450 | let recover = config.sanitizer_recover.contains(sanitizer); | |
451 | match sanitizer { | |
452 | Sanitizer::Address => { | |
453 | passes.push(llvm::LLVMRustCreateAddressSanitizerFunctionPass(recover)); | |
454 | passes.push(llvm::LLVMRustCreateModuleAddressSanitizerPass(recover)); | |
455 | } | |
456 | Sanitizer::Memory => { | |
457 | let track_origins = config.sanitizer_memory_track_origins as c_int; | |
458 | passes.push(llvm::LLVMRustCreateMemorySanitizerPass(track_origins, recover)); | |
459 | } | |
460 | Sanitizer::Thread => { | |
461 | passes.push(llvm::LLVMRustCreateThreadSanitizerPass()); | |
462 | } | |
463 | Sanitizer::Leak => {} | |
464 | } | |
465 | } | |
466 | ||
a1dfa0c6 | 467 | pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>, |
ea8adc8c | 468 | diag_handler: &Handler, |
a1dfa0c6 | 469 | module: ModuleCodegen<ModuleLlvm>, |
532ac7d7 | 470 | config: &ModuleConfig) |
ea8adc8c XL |
471 | -> Result<CompiledModule, FatalError> |
472 | { | |
e74abb32 | 473 | let _timer = cgcx.prof.generic_activity("LLVM_module_codegen"); |
1a4d82fc | 474 | { |
b7449926 XL |
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); | |
1a4d82fc | 481 | |
b7449926 XL |
482 | if cgcx.msvc_imps_needed { |
483 | create_msvc_imps(cgcx, llcx, llmod); | |
484 | } | |
485 | ||
486 | // A codegen-specific pass manager is used to generate object | |
487 | // files for an LLVM module. | |
488 | // | |
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 | |
493 | // used once. | |
494 | unsafe fn with_codegen<'ll, F, R>(tm: &'ll llvm::TargetMachine, | |
a1dfa0c6 XL |
495 | llmod: &'ll llvm::Module, |
496 | no_builtins: bool, | |
497 | f: F) -> R | |
b7449926 XL |
498 | where F: FnOnce(&'ll mut PassManager<'ll>) -> R, |
499 | { | |
500 | let cpm = llvm::LLVMCreatePassManager(); | |
60c5eb7d | 501 | llvm::LLVMAddAnalysisPasses(tm, cpm); |
b7449926 XL |
502 | llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); |
503 | f(cpm) | |
504 | } | |
505 | ||
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; | |
509 | ||
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; | |
518 | ||
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); | |
521 | ||
522 | ||
523 | if write_bc || config.emit_bc_compressed || config.embed_bitcode { | |
e74abb32 | 524 | let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_make_bitcode"); |
a1dfa0c6 XL |
525 | let thin = ThinBuffer::new(llmod); |
526 | let data = thin.data(); | |
abe05a73 | 527 | |
b7449926 | 528 | if write_bc { |
e74abb32 | 529 | let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_bitcode"); |
b7449926 | 530 | if let Err(e) = fs::write(&bc_out, data) { |
532ac7d7 XL |
531 | let msg = format!("failed to write bytecode to {}: {}", bc_out.display(), e); |
532 | diag_handler.err(&msg); | |
b7449926 | 533 | } |
abe05a73 | 534 | } |
abe05a73 | 535 | |
b7449926 | 536 | if config.embed_bitcode { |
e74abb32 | 537 | let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_embed_bitcode"); |
b7449926 | 538 | embed_bitcode(cgcx, llcx, llmod, Some(data)); |
b7449926 | 539 | } |
0531ce1d | 540 | |
b7449926 | 541 | if config.emit_bc_compressed { |
e74abb32 XL |
542 | let _timer = |
543 | cgcx.prof.generic_activity("LLVM_module_codegen_emit_compressed_bitcode"); | |
b7449926 XL |
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) { | |
532ac7d7 XL |
547 | let msg = format!("failed to write bytecode to {}: {}", dst.display(), e); |
548 | diag_handler.err(&msg); | |
b7449926 | 549 | } |
abe05a73 | 550 | } |
b7449926 XL |
551 | } else if config.embed_bitcode_marker { |
552 | embed_bitcode(cgcx, llcx, llmod, None); | |
553 | } | |
554 | ||
e74abb32 | 555 | time_ext(config.time_passes, &format!("codegen passes [{}]", module_name.unwrap()), |
b7449926 XL |
556 | || -> Result<(), FatalError> { |
557 | if config.emit_ir { | |
e74abb32 | 558 | let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_ir"); |
b7449926 | 559 | let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name); |
532ac7d7 | 560 | let out_c = path_to_c_string(&out); |
b7449926 XL |
561 | |
562 | extern "C" fn demangle_callback(input_ptr: *const c_char, | |
563 | input_len: size_t, | |
564 | output_ptr: *mut c_char, | |
565 | output_len: size_t) -> size_t { | |
566 | let input = unsafe { | |
567 | slice::from_raw_parts(input_ptr as *const u8, input_len as usize) | |
568 | }; | |
1a4d82fc | 569 | |
b7449926 XL |
570 | let input = match str::from_utf8(input) { |
571 | Ok(s) => s, | |
572 | Err(_) => return 0, | |
573 | }; | |
041b39d2 | 574 | |
b7449926 XL |
575 | let output = unsafe { |
576 | slice::from_raw_parts_mut(output_ptr as *mut u8, output_len as usize) | |
577 | }; | |
578 | let mut cursor = io::Cursor::new(output); | |
041b39d2 | 579 | |
b7449926 XL |
580 | let demangled = match rustc_demangle::try_demangle(input) { |
581 | Ok(d) => d, | |
582 | Err(_) => return 0, | |
583 | }; | |
041b39d2 | 584 | |
b7449926 XL |
585 | if let Err(_) = write!(cursor, "{:#}", demangled) { |
586 | // Possible only if provided buffer is not big enough | |
587 | return 0; | |
588 | } | |
041b39d2 | 589 | |
b7449926 | 590 | cursor.position() as size_t |
041b39d2 XL |
591 | } |
592 | ||
60c5eb7d XL |
593 | let result = |
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) | |
532ac7d7 | 598 | })?; |
041b39d2 XL |
599 | } |
600 | ||
b7449926 | 601 | if config.emit_asm || asm_to_obj { |
e74abb32 | 602 | let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_asm"); |
b7449926 | 603 | let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); |
9cc50fc6 | 604 | |
b7449926 XL |
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) | |
610 | } else { | |
611 | llmod | |
612 | }; | |
613 | with_codegen(tm, llmod, config.no_builtins, |cpm| { | |
614 | write_output_file(diag_handler, tm, cpm, llmod, &path, | |
a1dfa0c6 | 615 | llvm::FileType::AssemblyFile) |
b7449926 | 616 | })?; |
9cc50fc6 | 617 | } |
1a4d82fc | 618 | |
b7449926 | 619 | if write_obj { |
e74abb32 | 620 | let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_obj"); |
b7449926 XL |
621 | with_codegen(tm, llmod, config.no_builtins, |cpm| { |
622 | write_output_file(diag_handler, tm, cpm, llmod, &obj_out, | |
a1dfa0c6 | 623 | llvm::FileType::ObjectFile) |
b7449926 | 624 | })?; |
b7449926 | 625 | } else if asm_to_obj { |
e74abb32 | 626 | let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_asm_to_obj"); |
b7449926 XL |
627 | let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); |
628 | run_assembler(cgcx, diag_handler, &assembly, &obj_out); | |
b7449926 XL |
629 | |
630 | if !config.emit_asm && !cgcx.save_temps { | |
631 | drop(fs::remove_file(&assembly)); | |
632 | } | |
2c00a5a8 | 633 | } |
041b39d2 | 634 | |
b7449926 XL |
635 | Ok(()) |
636 | })?; | |
1a4d82fc | 637 | |
b7449926 XL |
638 | if copy_bc_to_obj { |
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)); | |
642 | } | |
7453a54e | 643 | } |
7453a54e | 644 | |
b7449926 XL |
645 | if rm_bc { |
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)); | |
649 | } | |
7453a54e | 650 | } |
7453a54e | 651 | |
b7449926 XL |
652 | drop(handlers); |
653 | } | |
94b46f34 | 654 | Ok(module.into_compiled_module(config.emit_obj, |
ea8adc8c | 655 | config.emit_bc, |
abe05a73 | 656 | config.emit_bc_compressed, |
ea8adc8c | 657 | &cgcx.output_filenames)) |
1a4d82fc JJ |
658 | } |
659 | ||
0531ce1d | 660 | /// Embed the bitcode of an LLVM module in the LLVM module itself. |
abe05a73 | 661 | /// |
0531ce1d XL |
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 | |
664 | /// executable: | |
665 | /// | |
666 | /// * __LLVM,__bitcode | |
667 | /// * __LLVM,__cmdline | |
668 | /// | |
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 | |
671 | /// cmdline section. | |
672 | /// | |
673 | /// Furthermore debug/O1 builds don't actually embed bitcode but rather just | |
674 | /// embed an empty section. | |
675 | /// | |
676 | /// Basically all of this is us attempting to follow in the footsteps of clang | |
677 | /// on iOS. See #35968 for lots more info. | |
a1dfa0c6 | 678 | unsafe fn embed_bitcode(cgcx: &CodegenContext<LlvmCodegenBackend>, |
b7449926 XL |
679 | llcx: &llvm::Context, |
680 | llmod: &llvm::Module, | |
0531ce1d | 681 | bitcode: Option<&[u8]>) { |
a1dfa0c6 | 682 | let llconst = common::bytes_in_context(llcx, bitcode.unwrap_or(&[])); |
0531ce1d XL |
683 | let llglobal = llvm::LLVMAddGlobal( |
684 | llmod, | |
a1dfa0c6 | 685 | common::val_ty(llconst), |
e74abb32 | 686 | "rustc.embedded.module\0".as_ptr().cast(), |
0531ce1d XL |
687 | ); |
688 | llvm::LLVMSetInitializer(llglobal, llconst); | |
83c7162d XL |
689 | |
690 | let is_apple = cgcx.opts.target_triple.triple().contains("-ios") || | |
691 | cgcx.opts.target_triple.triple().contains("-darwin"); | |
692 | ||
693 | let section = if is_apple { | |
0531ce1d XL |
694 | "__LLVM,__bitcode\0" |
695 | } else { | |
696 | ".llvmbc\0" | |
697 | }; | |
e74abb32 | 698 | llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); |
0531ce1d | 699 | llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); |
83c7162d | 700 | llvm::LLVMSetGlobalConstant(llglobal, llvm::True); |
0531ce1d | 701 | |
a1dfa0c6 | 702 | let llconst = common::bytes_in_context(llcx, &[]); |
0531ce1d XL |
703 | let llglobal = llvm::LLVMAddGlobal( |
704 | llmod, | |
a1dfa0c6 | 705 | common::val_ty(llconst), |
e74abb32 | 706 | "rustc.embedded.cmdline\0".as_ptr().cast(), |
0531ce1d XL |
707 | ); |
708 | llvm::LLVMSetInitializer(llglobal, llconst); | |
83c7162d | 709 | let section = if is_apple { |
0531ce1d XL |
710 | "__LLVM,__cmdline\0" |
711 | } else { | |
712 | ".llvmcmd\0" | |
713 | }; | |
e74abb32 | 714 | llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); |
0531ce1d | 715 | llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); |
abe05a73 XL |
716 | } |
717 | ||
b7449926 | 718 | pub unsafe fn with_llvm_pmb(llmod: &llvm::Module, |
c1a9b12d | 719 | config: &ModuleConfig, |
abe05a73 | 720 | opt_level: llvm::CodeGenOptLevel, |
94b46f34 | 721 | prepare_for_thin_lto: bool, |
b7449926 | 722 | f: &mut dyn FnMut(&llvm::PassManagerBuilder)) { |
0531ce1d XL |
723 | use std::ptr; |
724 | ||
1a4d82fc JJ |
725 | // Create the PassManagerBuilder for LLVM. We configure it with |
726 | // reasonable defaults and prepare it to actually populate the pass | |
727 | // manager. | |
728 | let builder = llvm::LLVMPassManagerBuilderCreate(); | |
9fa01778 XL |
729 | let opt_size = config.opt_size.map(|x| to_llvm_opt_settings(x).1) |
730 | .unwrap_or(llvm::CodeGenOptSizeNone); | |
92a42be0 | 731 | let inline_threshold = config.inline_threshold; |
62682a34 | 732 | |
48663c56 | 733 | let pgo_gen_path = match config.pgo_gen { |
dc9dc135 | 734 | SwitchWithOptPath::Enabled(ref opt_dir_path) => { |
48663c56 XL |
735 | let path = if let Some(dir_path) = opt_dir_path { |
736 | dir_path.join("default_%m.profraw") | |
737 | } else { | |
738 | PathBuf::from("default_%m.profraw") | |
739 | }; | |
740 | ||
741 | Some(CString::new(format!("{}", path.display())).unwrap()) | |
742 | } | |
dc9dc135 | 743 | SwitchWithOptPath::Disabled => { |
48663c56 XL |
744 | None |
745 | } | |
746 | }; | |
0531ce1d | 747 | |
dc9dc135 XL |
748 | let pgo_use_path = config.pgo_use.as_ref().map(|path_buf| { |
749 | CString::new(path_buf.to_string_lossy().as_bytes()).unwrap() | |
750 | }); | |
0531ce1d XL |
751 | |
752 | llvm::LLVMRustConfigurePassManagerBuilder( | |
753 | builder, | |
754 | opt_level, | |
755 | config.merge_functions, | |
756 | config.vectorize_slp, | |
757 | config.vectorize_loop, | |
94b46f34 | 758 | prepare_for_thin_lto, |
0531ce1d XL |
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()), | |
761 | ); | |
762 | ||
a7813a04 XL |
763 | llvm::LLVMPassManagerBuilderSetSizeLevel(builder, opt_size as u32); |
764 | ||
765 | if opt_size != llvm::CodeGenOptSizeNone { | |
766 | llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(builder, 1); | |
767 | } | |
62682a34 SL |
768 | |
769 | llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins); | |
770 | ||
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. | |
a7813a04 | 775 | match (opt_level, opt_size, inline_threshold) { |
9e0c209e | 776 | (.., Some(t)) => { |
92a42be0 SL |
777 | llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32); |
778 | } | |
9e0c209e | 779 | (llvm::CodeGenOptLevel::Aggressive, ..) => { |
a7813a04 XL |
780 | llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275); |
781 | } | |
782 | (_, llvm::CodeGenOptSizeDefault, _) => { | |
783 | llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 75); | |
784 | } | |
785 | (_, llvm::CodeGenOptSizeAggressive, _) => { | |
786 | llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25); | |
787 | } | |
9e0c209e | 788 | (llvm::CodeGenOptLevel::None, ..) => { |
1a4d82fc JJ |
789 | llvm::LLVMRustAddAlwaysInlinePass(builder, false); |
790 | } | |
9e0c209e | 791 | (llvm::CodeGenOptLevel::Less, ..) => { |
1a4d82fc JJ |
792 | llvm::LLVMRustAddAlwaysInlinePass(builder, true); |
793 | } | |
9e0c209e | 794 | (llvm::CodeGenOptLevel::Default, ..) => { |
62682a34 | 795 | llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225); |
1a4d82fc | 796 | } |
9e0c209e | 797 | (llvm::CodeGenOptLevel::Other, ..) => { |
5bcae85e SL |
798 | bug!("CodeGenOptLevel::Other selected") |
799 | } | |
1a4d82fc | 800 | } |
1a4d82fc | 801 | |
c1a9b12d | 802 | f(builder); |
1a4d82fc | 803 | llvm::LLVMPassManagerBuilderDispose(builder); |
1a4d82fc | 804 | } |
3b2f2976 | 805 | |
abe05a73 XL |
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 | |
a1dfa0c6 XL |
811 | fn create_msvc_imps( |
812 | cgcx: &CodegenContext<LlvmCodegenBackend>, | |
813 | llcx: &llvm::Context, | |
814 | llmod: &llvm::Module | |
815 | ) { | |
abe05a73 XL |
816 | if !cgcx.msvc_imps_needed { |
817 | return | |
818 | } | |
819 | // The x86 ABI seems to require that leading underscores are added to symbol | |
48663c56 | 820 | // names, so we need an extra underscore on x86. There's also a leading |
0731742a | 821 | // '\x01' here which disables LLVM's symbol mangling (e.g., no extra |
abe05a73 | 822 | // underscores added in front). |
48663c56 | 823 | let prefix = if cgcx.target_arch == "x86" { |
abe05a73 XL |
824 | "\x01__imp__" |
825 | } else { | |
826 | "\x01__imp_" | |
827 | }; | |
48663c56 | 828 | |
abe05a73 XL |
829 | unsafe { |
830 | let i8p_ty = Type::i8p_llcx(llcx); | |
831 | let globals = base::iter_globals(llmod) | |
832 | .filter(|&val| { | |
833 | llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage && | |
834 | llvm::LLVMIsDeclaration(val) == 0 | |
835 | }) | |
48663c56 XL |
836 | .filter_map(|val| { |
837 | // Exclude some symbols that we know are not Rust symbols. | |
60c5eb7d XL |
838 | let name = llvm::get_value_name(val); |
839 | if ignored(name) { | |
48663c56 XL |
840 | None |
841 | } else { | |
842 | Some((val, name)) | |
843 | } | |
844 | }) | |
845 | .map(move |(val, name)| { | |
abe05a73 | 846 | let mut imp_name = prefix.as_bytes().to_vec(); |
60c5eb7d | 847 | imp_name.extend(name); |
abe05a73 XL |
848 | let imp_name = CString::new(imp_name).unwrap(); |
849 | (imp_name, val) | |
850 | }) | |
851 | .collect::<Vec<_>>(); | |
48663c56 | 852 | |
abe05a73 XL |
853 | for (imp_name, val) in globals { |
854 | let imp = llvm::LLVMAddGlobal(llmod, | |
b7449926 | 855 | i8p_ty, |
e74abb32 | 856 | imp_name.as_ptr().cast()); |
abe05a73 XL |
857 | llvm::LLVMSetInitializer(imp, consts::ptrcast(val, i8p_ty)); |
858 | llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage); | |
859 | } | |
860 | } | |
48663c56 XL |
861 | |
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_") | |
866 | } | |
abe05a73 | 867 | } |