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