1use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr, RtsanSetting};
3use rustc_hir::def_id::DefId;
4use rustc_hir::find_attr;
5use rustc_middle::middle::codegen_fn_attrs::{
6 CodegenFnAttrFlags, CodegenFnAttrs, InstrumentFnAttr, PatchableFunctionEntry, SanitizerFnAttrs,
7 TargetFeature,
8};
9use rustc_middle::ty::{self, Instance, TyCtxt};
10use rustc_session::config::{
11 BranchProtection, FunctionReturn, InstrumentMcount, OptLevel, PAuthKey, PacRet,
12};
13use rustc_span::sym;
14use rustc_symbol_mangling::mangle_internal_symbol;
15use rustc_target::spec::{
16 Arch, FramePointer, LlvmAbi, SanitizerSet, StackProbeType, StackProtector,
17};
18use smallvec::SmallVec;
19
20use crate::common::pauth_fn_attrs;
21use crate::context::SimpleCx;
22use crate::errors::{PackedStackBackchainNeedsSoftfloat, SanitizerMemtagRequiresMte};
23use crate::llvm::AttributePlace::Function;
24use crate::llvm::{
25 self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects, Value,
26};
27use crate::{Session, attributes, llvm_util};
28
29pub(crate) fn apply_to_llfn(llfn: &Value, idx: AttributePlace, attrs: &[&Attribute]) {
30 if !attrs.is_empty() {
31 llvm::AddFunctionAttributes(llfn, idx, attrs);
32 }
33}
34
35pub(crate) fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[&Attribute]) {
36 if !attrs.is_empty() {
37 llvm::AddCallSiteAttributes(callsite, idx, attrs);
38 }
39}
40
41pub(crate) fn has_string_attr(llfn: &Value, name: &str) -> bool {
42 llvm::HasStringAttribute(llfn, name)
43}
44
45pub(crate) fn remove_string_attr_from_llfn(llfn: &Value, name: &str) {
46 llvm::RemoveStringAttrFromFn(llfn, name);
47}
48
49#[inline]
51pub(crate) fn inline_attr<'tcx, 'll>(
52 cx: &SimpleCx<'ll>,
53 tcx: TyCtxt<'tcx>,
54 instance: Instance<'tcx>,
55 codegen_fn_attrs: &CodegenFnAttrs,
56) -> Option<&'ll Attribute> {
57 if !tcx.sess.opts.unstable_opts.inline_llvm {
58 return Some(AttributeKind::NoInline.create_attr(cx.llcx));
60 }
61
62 let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) {
64 (_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never,
65 (InlineAttr::None, _) if instance.def.requires_inline(tcx) => InlineAttr::Hint,
66 (inline, _) => inline,
67 };
68
69 match inline {
70 InlineAttr::Hint => Some(AttributeKind::InlineHint.create_attr(cx.llcx)),
71 InlineAttr::Always | InlineAttr::Force { .. } => {
72 Some(AttributeKind::AlwaysInline.create_attr(cx.llcx))
73 }
74 InlineAttr::Never => {
75 if tcx.sess.target.arch != Arch::AmdGpu {
76 Some(AttributeKind::NoInline.create_attr(cx.llcx))
77 } else {
78 None
79 }
80 }
81 InlineAttr::None => None,
82 }
83}
84
85#[inline]
86fn patchable_function_entry_attrs<'ll>(
87 cx: &SimpleCx<'ll>,
88 sess: &Session,
89 attr: Option<PatchableFunctionEntry>,
90) -> SmallVec<[&'ll Attribute; 2]> {
91 let mut attrs = SmallVec::new();
92
93 let mut entry = sess.opts.unstable_opts.patchable_function_entry.entry();
94 let mut prefix = sess.opts.unstable_opts.patchable_function_entry.prefix();
95 let mut section = sess.opts.unstable_opts.patchable_function_entry.section();
96 let section_sym;
97
98 if let Some(patchable_spec) = attr {
100 if let Some(sym) = patchable_spec.section() {
101 section_sym = sym;
102 section = Some(section_sym.as_str());
103 }
104 if patchable_spec.entry().is_some() || patchable_spec.prefix().is_some() {
107 entry = patchable_spec.entry().unwrap_or(0);
108 prefix = patchable_spec.prefix().unwrap_or(0);
109 }
110 }
111
112 if entry > 0 {
113 attrs.push(llvm::CreateAttrStringValue(
114 cx.llcx,
115 "patchable-function-entry",
116 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}", entry))
})format!("{}", entry),
117 ));
118 }
119 if prefix > 0 {
120 attrs.push(llvm::CreateAttrStringValue(
121 cx.llcx,
122 "patchable-function-prefix",
123 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}", prefix))
})format!("{}", prefix),
124 ));
125 }
126 if let Some(section) = section {
127 attrs.push(llvm::CreateAttrStringValue(
128 cx.llcx,
129 "patchable-function-entry-section",
130 section,
131 ));
132 }
133 attrs
134}
135
136#[inline]
138pub(crate) fn sanitize_attrs<'ll, 'tcx>(
139 cx: &SimpleCx<'ll>,
140 tcx: TyCtxt<'tcx>,
141 sanitizer_fn_attr: SanitizerFnAttrs,
142) -> SmallVec<[&'ll Attribute; 4]> {
143 let mut attrs = SmallVec::new();
144 let enabled = tcx.sess.sanitizers() - sanitizer_fn_attr.disabled;
145 if enabled.contains(SanitizerSet::ADDRESS) || enabled.contains(SanitizerSet::KERNELADDRESS) {
146 attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx));
147 }
148 if enabled.contains(SanitizerSet::MEMORY) {
149 attrs.push(llvm::AttributeKind::SanitizeMemory.create_attr(cx.llcx));
150 }
151 if enabled.contains(SanitizerSet::THREAD) {
152 attrs.push(llvm::AttributeKind::SanitizeThread.create_attr(cx.llcx));
153 }
154 if enabled.contains(SanitizerSet::HWADDRESS) || enabled.contains(SanitizerSet::KERNELHWADDRESS)
155 {
156 attrs.push(llvm::AttributeKind::SanitizeHWAddress.create_attr(cx.llcx));
157 }
158 if enabled.contains(SanitizerSet::SHADOWCALLSTACK) {
159 attrs.push(llvm::AttributeKind::ShadowCallStack.create_attr(cx.llcx));
160 }
161 if enabled.contains(SanitizerSet::MEMTAG) {
162 let features = tcx.global_backend_features(());
164 let mte_feature =
165 features.iter().map(|s| &s[..]).rfind(|n| ["+mte", "-mte"].contains(&&n[..]));
166 if let None | Some("-mte") = mte_feature {
167 tcx.dcx().emit_err(SanitizerMemtagRequiresMte);
168 }
169
170 attrs.push(llvm::AttributeKind::SanitizeMemTag.create_attr(cx.llcx));
171 }
172 if enabled.contains(SanitizerSet::SAFESTACK) {
173 attrs.push(llvm::AttributeKind::SanitizeSafeStack.create_attr(cx.llcx));
174 }
175 if tcx.sess.sanitizers().contains(SanitizerSet::REALTIME) {
176 match sanitizer_fn_attr.rtsan_setting {
177 RtsanSetting::Nonblocking => {
178 attrs.push(llvm::AttributeKind::SanitizeRealtimeNonblocking.create_attr(cx.llcx))
179 }
180 RtsanSetting::Blocking => {
181 attrs.push(llvm::AttributeKind::SanitizeRealtimeBlocking.create_attr(cx.llcx))
182 }
183 RtsanSetting::Caller => (),
185 }
186 }
187 attrs
188}
189
190#[inline]
192pub(crate) fn uwtable_attr(llcx: &llvm::Context, use_sync_unwind: Option<bool>) -> &Attribute {
193 let async_unwind = !use_sync_unwind.unwrap_or(false);
199 llvm::CreateUWTableAttr(llcx, async_unwind)
200}
201
202pub(crate) fn frame_pointer(sess: &Session) -> FramePointer {
203 let mut fp = sess.target.frame_pointer;
204 let opts = &sess.opts;
205 if opts.unstable_opts.instrument_mcount == InstrumentMcount::Mcount {
208 fp.ratchet(FramePointer::Always);
209 }
210 fp.ratchet(opts.cg.force_frame_pointers);
211 fp
212}
213
214pub(crate) fn frame_pointer_type_attr<'ll>(
215 cx: &SimpleCx<'ll>,
216 sess: &Session,
217) -> Option<&'ll Attribute> {
218 let fp = frame_pointer(sess);
219 let attr_value = match fp {
220 FramePointer::Always => "all",
221 FramePointer::NonLeaf => "non-leaf",
222 FramePointer::MayOmit => return None,
223 };
224 Some(llvm::CreateAttrStringValue(cx.llcx, "frame-pointer", attr_value))
225}
226
227fn function_return_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
228 let function_return_attr = match sess.opts.unstable_opts.function_return {
229 FunctionReturn::Keep => return None,
230 FunctionReturn::ThunkExtern => AttributeKind::FnRetThunkExtern,
231 };
232
233 Some(function_return_attr.create_attr(cx.llcx))
234}
235
236#[inline]
238fn instrument_function_attr<'ll>(
239 cx: &SimpleCx<'ll>,
240 sess: &Session,
241 instrument_fn: InstrumentFnAttr,
242) -> SmallVec<[&'ll Attribute; 4]> {
243 let mut attrs = SmallVec::new();
244 if sess.opts.unstable_opts.instrument_mcount != InstrumentMcount::Disabled {
245 let instrument_entry = match instrument_fn {
249 InstrumentFnAttr::Default | InstrumentFnAttr::On => true,
250 InstrumentFnAttr::Off => false,
251 };
252
253 if instrument_entry {
254 match sess.opts.unstable_opts.instrument_mcount {
255 InstrumentMcount::Mcount => {
256 let mcount_name = match &sess.target.llvm_mcount_intrinsic {
259 Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(),
260 None => sess.target.mcount.as_ref(),
261 };
262
263 attrs.push(llvm::CreateAttrStringValue(
264 cx.llcx,
265 "instrument-function-entry-inlined",
266 mcount_name,
267 ));
268 }
269 InstrumentMcount::Fentry => {
270 attrs.push(llvm::CreateAttrStringValue(cx.llcx, "fentry-call", "true"));
271 }
272 InstrumentMcount::Disabled => {}
273 }
274 }
275 }
276 if let Some(options) = &sess.opts.unstable_opts.instrument_xray {
277 let mut never = options.never;
282 let mut always = options.always;
283
284 match instrument_fn {
286 InstrumentFnAttr::Default => {}
287 InstrumentFnAttr::On => {
288 always = true;
289 }
290 InstrumentFnAttr::Off => {
291 never = true;
292 }
293 }
294
295 if never {
296 attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-never"));
297 }
298 if always {
299 attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-always"));
300 }
301
302 if options.ignore_loops {
303 attrs.push(llvm::CreateAttrString(cx.llcx, "xray-ignore-loops"));
304 }
305 let threshold = options.instruction_threshold.unwrap_or(200);
308 attrs.push(llvm::CreateAttrStringValue(
309 cx.llcx,
310 "xray-instruction-threshold",
311 &threshold.to_string(),
312 ));
313 if options.skip_entry {
314 attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-entry"));
315 }
316 if options.skip_exit {
317 attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-exit"));
318 }
319 }
320 attrs
321}
322
323fn nojumptables_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
324 if sess.opts.cg.jump_tables {
325 return None;
326 }
327
328 Some(llvm::CreateAttrStringValue(cx.llcx, "no-jump-tables", "true"))
329}
330
331fn probestack_attr<'ll, 'tcx>(cx: &SimpleCx<'ll>, tcx: TyCtxt<'tcx>) -> Option<&'ll Attribute> {
332 if tcx.sess.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD) {
336 return None;
337 }
338
339 if tcx.sess.opts.cg.profile_generate.enabled() {
341 return None;
342 }
343
344 let attr_value = match tcx.sess.target.stack_probes {
345 StackProbeType::None => return None,
346 StackProbeType::Inline => "inline-asm",
349 StackProbeType::Call => &mangle_internal_symbol(tcx, "__rust_probestack"),
352 StackProbeType::InlineOrCall { min_llvm_version_for_inline } => {
354 if llvm_util::get_version() < min_llvm_version_for_inline {
355 &mangle_internal_symbol(tcx, "__rust_probestack")
356 } else {
357 "inline-asm"
358 }
359 }
360 };
361 Some(llvm::CreateAttrStringValue(cx.llcx, "probe-stack", attr_value))
362}
363
364fn stackprotector_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
365 let sspattr = match sess.stack_protector() {
366 StackProtector::None => return None,
367 StackProtector::All => AttributeKind::StackProtectReq,
368 StackProtector::Strong => AttributeKind::StackProtectStrong,
369 StackProtector::Basic => AttributeKind::StackProtect,
370 };
371
372 Some(sspattr.create_attr(cx.llcx))
373}
374
375fn packed_stack_attr<'ll>(
376 cx: &SimpleCx<'ll>,
377 sess: &Session,
378 function_attributes: &Vec<TargetFeature>,
379) -> Option<&'ll Attribute> {
380 if sess.target.arch != Arch::S390x {
381 return None;
382 }
383 if !sess.opts.unstable_opts.packed_stack {
384 return None;
385 }
386
387 let have_backchain = sess.unstable_target_features.contains(&sym::backchain)
390 || function_attributes.iter().any(|feature| feature.name == sym::backchain);
391 let have_softfloat = sess.unstable_target_features.contains(&sym::soft_float)
392 || function_attributes.iter().any(|feature| feature.name == sym::soft_float);
393
394 if have_backchain && !have_softfloat {
398 sess.dcx().emit_err(PackedStackBackchainNeedsSoftfloat);
399 return None;
400 }
401
402 Some(llvm::CreateAttrString(cx.llcx, "packed-stack"))
403}
404
405pub(crate) fn target_cpu_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> &'ll Attribute {
406 let target_cpu = llvm_util::target_cpu(sess);
407 llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu)
408}
409
410pub(crate) fn tune_cpu_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
411 llvm_util::tune_cpu(sess)
412 .map(|tune_cpu| llvm::CreateAttrStringValue(cx.llcx, "tune-cpu", tune_cpu))
413}
414
415pub(crate) fn target_features_attr<'ll, 'tcx>(
417 cx: &SimpleCx<'ll>,
418 tcx: TyCtxt<'tcx>,
419 function_features: Vec<String>,
420) -> Option<&'ll Attribute> {
421 let global_features = tcx.global_backend_features(()).iter().map(String::as_str);
422 let function_features = function_features.iter().map(String::as_str);
423 let target_features =
424 global_features.chain(function_features).intersperse(",").collect::<String>();
425 (!target_features.is_empty())
426 .then(|| llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features))
427}
428
429pub(crate) fn non_lazy_bind_attr<'ll>(
432 cx: &SimpleCx<'ll>,
433 sess: &Session,
434) -> Option<&'ll Attribute> {
435 if !sess.needs_plt() { Some(AttributeKind::NonLazyBind.create_attr(cx.llcx)) } else { None }
437}
438
439#[inline]
441pub(crate) fn default_optimisation_attrs<'ll>(
442 cx: &SimpleCx<'ll>,
443 sess: &Session,
444) -> SmallVec<[&'ll Attribute; 2]> {
445 let mut attrs = SmallVec::new();
446 match sess.opts.optimize {
447 OptLevel::Size => {
448 attrs.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
449 }
450 OptLevel::SizeMin => {
451 attrs.push(llvm::AttributeKind::MinSize.create_attr(cx.llcx));
452 attrs.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
453 }
454 _ => {}
455 }
456 attrs
457}
458
459fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute {
460 llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc")
461}
462
463pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
467 cx: &SimpleCx<'ll>,
468 tcx: TyCtxt<'tcx>,
469 llfn: &'ll Value,
470 codegen_fn_attrs: &CodegenFnAttrs,
471 instance: Option<ty::Instance<'tcx>>,
472) {
473 let sess = tcx.sess;
474 let mut to_add = SmallVec::<[_; 16]>::new();
475
476 match codegen_fn_attrs.optimize {
477 OptimizeAttr::Default => {
478 to_add.extend(default_optimisation_attrs(cx, sess));
479 }
480 OptimizeAttr::DoNotOptimize => {
481 to_add.push(llvm::AttributeKind::OptimizeNone.create_attr(cx.llcx));
482 }
483 OptimizeAttr::Size => {
484 to_add.push(llvm::AttributeKind::MinSize.create_attr(cx.llcx));
485 to_add.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
486 }
487 OptimizeAttr::Speed => {}
488 }
489
490 if let Some(instance) = instance {
491 to_add.extend(inline_attr(cx, tcx, instance, codegen_fn_attrs));
492 }
493
494 if sess.must_emit_unwind_tables() {
495 to_add.push(uwtable_attr(cx.llcx, sess.opts.unstable_opts.use_sync_unwind));
496 }
497
498 if sess.opts.unstable_opts.profile_sample_use.is_some() {
499 to_add.push(llvm::CreateAttrString(cx.llcx, "use-sample-profile"));
500 }
501
502 to_add.extend(frame_pointer_type_attr(cx, sess));
504 to_add.extend(function_return_attr(cx, sess));
505 to_add.extend(instrument_function_attr(cx, sess, codegen_fn_attrs.instrument_fn));
506 to_add.extend(nojumptables_attr(cx, sess));
507 to_add.extend(probestack_attr(cx, tcx));
508 to_add.extend(stackprotector_attr(cx, sess));
509
510 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_BUILTINS) {
511 to_add.push(llvm::CreateAttrString(cx.llcx, "no-builtins"));
512 }
513
514 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::OFFLOAD_KERNEL) {
515 to_add.push(llvm::CreateAttrString(cx.llcx, "offload-kernel"))
516 }
517
518 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
519 to_add.push(AttributeKind::Cold.create_attr(cx.llcx));
520 }
521 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) {
522 to_add.push(MemoryEffects::ReadOnly.create_attr(cx.llcx));
523 }
524 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_CONST) {
525 to_add.push(MemoryEffects::None.create_attr(cx.llcx));
526 }
527 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
528 } else {
532 to_add.extend(sanitize_attrs(cx, tcx, codegen_fn_attrs.sanitizers));
534
535 if let Some(BranchProtection { bti, pac_ret, gcs }) =
537 sess.opts.unstable_opts.branch_protection
538 {
539 if !(sess.target.arch == Arch::AArch64) {
::core::panicking::panic("assertion failed: sess.target.arch == Arch::AArch64")
};assert!(sess.target.arch == Arch::AArch64);
540 if bti {
541 to_add.push(llvm::CreateAttrString(cx.llcx, "branch-target-enforcement"));
542 }
543 if gcs {
544 to_add.push(llvm::CreateAttrString(cx.llcx, "guarded-control-stack"));
545 }
546 if let Some(PacRet { leaf, pc, key }) = pac_ret {
547 if pc {
548 to_add.push(llvm::CreateAttrString(cx.llcx, "branch-protection-pauth-lr"));
549 }
550 to_add.push(llvm::CreateAttrStringValue(
551 cx.llcx,
552 "sign-return-address",
553 if leaf { "all" } else { "non-leaf" },
554 ));
555 to_add.push(llvm::CreateAttrStringValue(
556 cx.llcx,
557 "sign-return-address-key",
558 if key == PAuthKey::A { "a_key" } else { "b_key" },
559 ));
560 }
561 }
562 }
563 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR)
564 || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED)
565 {
566 to_add.push(create_alloc_family_attr(cx.llcx));
567 if let Some(instance) = instance
568 && let Some(name) =
569 {
{
'done:
{
for i in
::rustc_hir::attrs::HasAttrs::get_attrs(instance.def_id(),
&tcx) {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(RustcAllocatorZeroedVariant {
name }) => {
break 'done Some(name);
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}find_attr!(tcx, instance.def_id(), RustcAllocatorZeroedVariant {name} => name)
570 {
571 to_add.push(llvm::CreateAttrStringValue(
572 cx.llcx,
573 "alloc-variant-zeroed",
574 &mangle_internal_symbol(tcx, name.as_str()),
575 ));
576 }
577 let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
579 attributes::apply_to_llfn(llfn, AttributePlace::Argument(1), &[alloc_align]);
580 to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 0));
581 let mut flags = AllocKindFlags::Alloc | AllocKindFlags::Aligned;
582 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
583 flags |= AllocKindFlags::Uninitialized;
584 } else {
585 flags |= AllocKindFlags::Zeroed;
586 }
587 to_add.push(llvm::CreateAllocKindAttr(cx.llcx, flags));
588 let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx);
591 attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]);
592 }
593 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::REALLOCATOR) {
594 to_add.push(create_alloc_family_attr(cx.llcx));
595 to_add.push(llvm::CreateAllocKindAttr(
596 cx.llcx,
597 AllocKindFlags::Realloc | AllocKindFlags::Aligned,
598 ));
599 let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
601 attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
602 let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
604 attributes::apply_to_llfn(llfn, AttributePlace::Argument(2), &[alloc_align]);
605 to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 3));
606 let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx);
607 attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]);
608 }
609 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::DEALLOCATOR) {
610 to_add.push(create_alloc_family_attr(cx.llcx));
611 to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free));
612 let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
614 let captures_addr = AttributeKind::CapturesAddress.create_attr(cx.llcx);
618 let attrs = &[allocated_pointer, captures_addr];
619 attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), attrs);
620 }
621 if let Some(align) = codegen_fn_attrs.alignment {
622 llvm::set_alignment(llfn, align);
623 }
624 if let Some(packed_stack) = packed_stack_attr(cx, sess, &codegen_fn_attrs.target_features) {
625 to_add.push(packed_stack);
626 }
627 to_add.extend(patchable_function_entry_attrs(
628 cx,
629 sess,
630 codegen_fn_attrs.patchable_function_entry,
631 ));
632
633 to_add.push(target_cpu_attr(cx, sess));
637 to_add.extend(tune_cpu_attr(cx, sess));
640
641 let function_features =
642 codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
643
644 let function_features = function_features
645 .iter()
646 .flat_map(|feat| llvm_util::to_llvm_features(sess, feat))
648 .flat_map(|feat| feat.into_iter().map(|f| ::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("+{0}", f)) })format!("+{f}")))
650 .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x {
651 InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(),
652 InstructionSetAttr::ArmT32 => "+thumb-mode".to_string(),
653 }))
654 .collect::<Vec<String>>();
655
656 if sess.target.is_like_wasm {
657 if let Some(instance) = instance
660 && let Some(module) = wasm_import_module(tcx, instance.def_id())
661 {
662 to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-module", module));
663
664 let name =
665 codegen_fn_attrs.symbol_name.unwrap_or_else(|| tcx.item_name(instance.def_id()));
666 let name = name.as_str();
667 to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-name", name));
668 }
669 }
670
671 if sess.target.llvm_abiname == LlvmAbi::Pauthtest {
672 for &ptrauth_attr in pauth_fn_attrs() {
673 to_add.push(llvm::CreateAttrString(cx.llcx, ptrauth_attr));
674 }
675 }
676
677 to_add.extend(target_features_attr(cx, tcx, function_features));
678
679 attributes::apply_to_llfn(llfn, Function, &to_add);
680}
681
682fn wasm_import_module(tcx: TyCtxt<'_>, id: DefId) -> Option<&String> {
683 tcx.wasm_import_module_map(id.krate).get(&id)
684}