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