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::errors::{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 let patchable_spec = attr.unwrap_or_else(|| {
90 PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry)
91 });
92 let entry = patchable_spec.entry();
93 let prefix = patchable_spec.prefix();
94 if entry > 0 {
95 attrs.push(llvm::CreateAttrStringValue(
96 cx.llcx,
97 "patchable-function-entry",
98 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}", entry))
})format!("{}", entry),
99 ));
100 }
101 if prefix > 0 {
102 attrs.push(llvm::CreateAttrStringValue(
103 cx.llcx,
104 "patchable-function-prefix",
105 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}", prefix))
})format!("{}", prefix),
106 ));
107 }
108 attrs
109}
110
111#[inline]
113pub(crate) fn sanitize_attrs<'ll, 'tcx>(
114 cx: &SimpleCx<'ll>,
115 tcx: TyCtxt<'tcx>,
116 sanitizer_fn_attr: SanitizerFnAttrs,
117) -> SmallVec<[&'ll Attribute; 4]> {
118 let mut attrs = SmallVec::new();
119 let enabled = tcx.sess.sanitizers() - sanitizer_fn_attr.disabled;
120 if enabled.contains(SanitizerSet::ADDRESS) || enabled.contains(SanitizerSet::KERNELADDRESS) {
121 attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx));
122 }
123 if enabled.contains(SanitizerSet::MEMORY) {
124 attrs.push(llvm::AttributeKind::SanitizeMemory.create_attr(cx.llcx));
125 }
126 if enabled.contains(SanitizerSet::THREAD) {
127 attrs.push(llvm::AttributeKind::SanitizeThread.create_attr(cx.llcx));
128 }
129 if enabled.contains(SanitizerSet::HWADDRESS) || enabled.contains(SanitizerSet::KERNELHWADDRESS)
130 {
131 attrs.push(llvm::AttributeKind::SanitizeHWAddress.create_attr(cx.llcx));
132 }
133 if enabled.contains(SanitizerSet::SHADOWCALLSTACK) {
134 attrs.push(llvm::AttributeKind::ShadowCallStack.create_attr(cx.llcx));
135 }
136 if enabled.contains(SanitizerSet::MEMTAG) {
137 let features = tcx.global_backend_features(());
139 let mte_feature =
140 features.iter().map(|s| &s[..]).rfind(|n| ["+mte", "-mte"].contains(&&n[..]));
141 if let None | Some("-mte") = mte_feature {
142 tcx.dcx().emit_err(SanitizerMemtagRequiresMte);
143 }
144
145 attrs.push(llvm::AttributeKind::SanitizeMemTag.create_attr(cx.llcx));
146 }
147 if enabled.contains(SanitizerSet::SAFESTACK) {
148 attrs.push(llvm::AttributeKind::SanitizeSafeStack.create_attr(cx.llcx));
149 }
150 if tcx.sess.sanitizers().contains(SanitizerSet::REALTIME) {
151 match sanitizer_fn_attr.rtsan_setting {
152 RtsanSetting::Nonblocking => {
153 attrs.push(llvm::AttributeKind::SanitizeRealtimeNonblocking.create_attr(cx.llcx))
154 }
155 RtsanSetting::Blocking => {
156 attrs.push(llvm::AttributeKind::SanitizeRealtimeBlocking.create_attr(cx.llcx))
157 }
158 RtsanSetting::Caller => (),
160 }
161 }
162 attrs
163}
164
165#[inline]
167pub(crate) fn uwtable_attr(llcx: &llvm::Context, use_sync_unwind: Option<bool>) -> &Attribute {
168 let async_unwind = !use_sync_unwind.unwrap_or(false);
174 llvm::CreateUWTableAttr(llcx, async_unwind)
175}
176
177pub(crate) fn frame_pointer(sess: &Session) -> FramePointer {
178 let mut fp = sess.target.frame_pointer;
179 let opts = &sess.opts;
180 if opts.unstable_opts.instrument_mcount == InstrumentMcount::Mcount {
183 fp.ratchet(FramePointer::Always);
184 }
185 fp.ratchet(opts.cg.force_frame_pointers);
186 fp
187}
188
189pub(crate) fn frame_pointer_type_attr<'ll>(
190 cx: &SimpleCx<'ll>,
191 sess: &Session,
192) -> Option<&'ll Attribute> {
193 let fp = frame_pointer(sess);
194 let attr_value = match fp {
195 FramePointer::Always => "all",
196 FramePointer::NonLeaf => "non-leaf",
197 FramePointer::MayOmit => return None,
198 };
199 Some(llvm::CreateAttrStringValue(cx.llcx, "frame-pointer", attr_value))
200}
201
202fn function_return_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
203 let function_return_attr = match sess.opts.unstable_opts.function_return {
204 FunctionReturn::Keep => return None,
205 FunctionReturn::ThunkExtern => AttributeKind::FnRetThunkExtern,
206 };
207
208 Some(function_return_attr.create_attr(cx.llcx))
209}
210
211#[inline]
213fn instrument_function_attr<'ll>(
214 cx: &SimpleCx<'ll>,
215 sess: &Session,
216 instrument_fn: InstrumentFnAttr,
217) -> SmallVec<[&'ll Attribute; 4]> {
218 let mut attrs = SmallVec::new();
219 if sess.opts.unstable_opts.instrument_mcount != InstrumentMcount::Disabled {
220 let instrument_entry = match instrument_fn {
224 InstrumentFnAttr::Default | InstrumentFnAttr::On => true,
225 InstrumentFnAttr::Off => false,
226 };
227
228 if instrument_entry {
229 match sess.opts.unstable_opts.instrument_mcount {
230 InstrumentMcount::Mcount => {
231 let mcount_name = match &sess.target.llvm_mcount_intrinsic {
234 Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(),
235 None => sess.target.mcount.as_ref(),
236 };
237
238 attrs.push(llvm::CreateAttrStringValue(
239 cx.llcx,
240 "instrument-function-entry-inlined",
241 mcount_name,
242 ));
243 }
244 InstrumentMcount::Fentry => {
245 attrs.push(llvm::CreateAttrStringValue(cx.llcx, "fentry-call", "true"));
246 }
247 InstrumentMcount::Disabled => {}
248 }
249 }
250 }
251 if let Some(options) = &sess.opts.unstable_opts.instrument_xray {
252 let mut never = options.never;
257 let mut always = options.always;
258
259 match instrument_fn {
261 InstrumentFnAttr::Default => {}
262 InstrumentFnAttr::On => {
263 always = true;
264 }
265 InstrumentFnAttr::Off => {
266 never = true;
267 }
268 }
269
270 if never {
271 attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-never"));
272 }
273 if always {
274 attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-always"));
275 }
276
277 if options.ignore_loops {
278 attrs.push(llvm::CreateAttrString(cx.llcx, "xray-ignore-loops"));
279 }
280 let threshold = options.instruction_threshold.unwrap_or(200);
283 attrs.push(llvm::CreateAttrStringValue(
284 cx.llcx,
285 "xray-instruction-threshold",
286 &threshold.to_string(),
287 ));
288 if options.skip_entry {
289 attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-entry"));
290 }
291 if options.skip_exit {
292 attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-exit"));
293 }
294 }
295 attrs
296}
297
298fn nojumptables_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
299 if sess.opts.cg.jump_tables {
300 return None;
301 }
302
303 Some(llvm::CreateAttrStringValue(cx.llcx, "no-jump-tables", "true"))
304}
305
306fn probestack_attr<'ll, 'tcx>(cx: &SimpleCx<'ll>, tcx: TyCtxt<'tcx>) -> Option<&'ll Attribute> {
307 if tcx.sess.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD) {
311 return None;
312 }
313
314 if tcx.sess.opts.cg.profile_generate.enabled() {
316 return None;
317 }
318
319 let attr_value = match tcx.sess.target.stack_probes {
320 StackProbeType::None => return None,
321 StackProbeType::Inline => "inline-asm",
324 StackProbeType::Call => &mangle_internal_symbol(tcx, "__rust_probestack"),
327 StackProbeType::InlineOrCall { min_llvm_version_for_inline } => {
329 if llvm_util::get_version() < min_llvm_version_for_inline {
330 &mangle_internal_symbol(tcx, "__rust_probestack")
331 } else {
332 "inline-asm"
333 }
334 }
335 };
336 Some(llvm::CreateAttrStringValue(cx.llcx, "probe-stack", attr_value))
337}
338
339fn stackprotector_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
340 let sspattr = match sess.stack_protector() {
341 StackProtector::None => return None,
342 StackProtector::All => AttributeKind::StackProtectReq,
343 StackProtector::Strong => AttributeKind::StackProtectStrong,
344 StackProtector::Basic => AttributeKind::StackProtect,
345 };
346
347 Some(sspattr.create_attr(cx.llcx))
348}
349
350fn packed_stack_attr<'ll>(
351 cx: &SimpleCx<'ll>,
352 sess: &Session,
353 function_attributes: &Vec<TargetFeature>,
354) -> Option<&'ll Attribute> {
355 if sess.target.arch != Arch::S390x {
356 return None;
357 }
358 if !sess.opts.unstable_opts.packed_stack {
359 return None;
360 }
361
362 let have_backchain = sess.unstable_target_features.contains(&sym::backchain)
365 || function_attributes.iter().any(|feature| feature.name == sym::backchain);
366 let have_softfloat = sess.unstable_target_features.contains(&sym::soft_float)
367 || function_attributes.iter().any(|feature| feature.name == sym::soft_float);
368
369 if have_backchain && !have_softfloat {
373 sess.dcx().emit_err(PackedStackBackchainNeedsSoftfloat);
374 return None;
375 }
376
377 Some(llvm::CreateAttrString(cx.llcx, "packed-stack"))
378}
379
380pub(crate) fn target_cpu_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> &'ll Attribute {
381 let target_cpu = llvm_util::target_cpu(sess);
382 llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu)
383}
384
385pub(crate) fn tune_cpu_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
386 llvm_util::tune_cpu(sess)
387 .map(|tune_cpu| llvm::CreateAttrStringValue(cx.llcx, "tune-cpu", tune_cpu))
388}
389
390pub(crate) fn target_features_attr<'ll, 'tcx>(
392 cx: &SimpleCx<'ll>,
393 tcx: TyCtxt<'tcx>,
394 function_features: Vec<String>,
395) -> Option<&'ll Attribute> {
396 let global_features = tcx.global_backend_features(()).iter().map(String::as_str);
397 let function_features = function_features.iter().map(String::as_str);
398 let target_features =
399 global_features.chain(function_features).intersperse(",").collect::<String>();
400 (!target_features.is_empty())
401 .then(|| llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features))
402}
403
404pub(crate) fn non_lazy_bind_attr<'ll>(
407 cx: &SimpleCx<'ll>,
408 sess: &Session,
409) -> Option<&'ll Attribute> {
410 if !sess.needs_plt() { Some(AttributeKind::NonLazyBind.create_attr(cx.llcx)) } else { None }
412}
413
414#[inline]
416pub(crate) fn default_optimisation_attrs<'ll>(
417 cx: &SimpleCx<'ll>,
418 sess: &Session,
419) -> SmallVec<[&'ll Attribute; 2]> {
420 let mut attrs = SmallVec::new();
421 match sess.opts.optimize {
422 OptLevel::Size => {
423 attrs.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
424 }
425 OptLevel::SizeMin => {
426 attrs.push(llvm::AttributeKind::MinSize.create_attr(cx.llcx));
427 attrs.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
428 }
429 _ => {}
430 }
431 attrs
432}
433
434fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute {
435 llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc")
436}
437
438pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
442 cx: &SimpleCx<'ll>,
443 tcx: TyCtxt<'tcx>,
444 llfn: &'ll Value,
445 codegen_fn_attrs: &CodegenFnAttrs,
446 instance: Option<ty::Instance<'tcx>>,
447) {
448 let sess = tcx.sess;
449 let mut to_add = SmallVec::<[_; 16]>::new();
450
451 match codegen_fn_attrs.optimize {
452 OptimizeAttr::Default => {
453 to_add.extend(default_optimisation_attrs(cx, sess));
454 }
455 OptimizeAttr::DoNotOptimize => {
456 to_add.push(llvm::AttributeKind::OptimizeNone.create_attr(cx.llcx));
457 }
458 OptimizeAttr::Size => {
459 to_add.push(llvm::AttributeKind::MinSize.create_attr(cx.llcx));
460 to_add.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
461 }
462 OptimizeAttr::Speed => {}
463 }
464
465 if let Some(instance) = instance {
466 to_add.extend(inline_attr(cx, tcx, instance, codegen_fn_attrs));
467 }
468
469 if sess.must_emit_unwind_tables() {
470 to_add.push(uwtable_attr(cx.llcx, sess.opts.unstable_opts.use_sync_unwind));
471 }
472
473 if sess.opts.unstable_opts.profile_sample_use.is_some() {
474 to_add.push(llvm::CreateAttrString(cx.llcx, "use-sample-profile"));
475 }
476
477 to_add.extend(frame_pointer_type_attr(cx, sess));
479 to_add.extend(function_return_attr(cx, sess));
480 to_add.extend(instrument_function_attr(cx, sess, codegen_fn_attrs.instrument_fn));
481 to_add.extend(nojumptables_attr(cx, sess));
482 to_add.extend(probestack_attr(cx, tcx));
483 to_add.extend(stackprotector_attr(cx, sess));
484
485 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_BUILTINS) {
486 to_add.push(llvm::CreateAttrString(cx.llcx, "no-builtins"));
487 }
488
489 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::OFFLOAD_KERNEL) {
490 to_add.push(llvm::CreateAttrString(cx.llcx, "offload-kernel"))
491 }
492
493 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
494 to_add.push(AttributeKind::Cold.create_attr(cx.llcx));
495 }
496 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) {
497 to_add.push(MemoryEffects::ReadOnly.create_attr(cx.llcx));
498 }
499 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_CONST) {
500 to_add.push(MemoryEffects::None.create_attr(cx.llcx));
501 }
502 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
503 } else {
507 to_add.extend(sanitize_attrs(cx, tcx, codegen_fn_attrs.sanitizers));
509
510 if let Some(BranchProtection { bti, pac_ret, gcs }) =
512 sess.opts.unstable_opts.branch_protection
513 {
514 if !(sess.target.arch == Arch::AArch64) {
::core::panicking::panic("assertion failed: sess.target.arch == Arch::AArch64")
};assert!(sess.target.arch == Arch::AArch64);
515 if bti {
516 to_add.push(llvm::CreateAttrString(cx.llcx, "branch-target-enforcement"));
517 }
518 if gcs {
519 to_add.push(llvm::CreateAttrString(cx.llcx, "guarded-control-stack"));
520 }
521 if let Some(PacRet { leaf, pc, key }) = pac_ret {
522 if pc {
523 to_add.push(llvm::CreateAttrString(cx.llcx, "branch-protection-pauth-lr"));
524 }
525 to_add.push(llvm::CreateAttrStringValue(
526 cx.llcx,
527 "sign-return-address",
528 if leaf { "all" } else { "non-leaf" },
529 ));
530 to_add.push(llvm::CreateAttrStringValue(
531 cx.llcx,
532 "sign-return-address-key",
533 if key == PAuthKey::A { "a_key" } else { "b_key" },
534 ));
535 }
536 }
537 }
538 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR)
539 || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED)
540 {
541 to_add.push(create_alloc_family_attr(cx.llcx));
542 if let Some(instance) = instance
543 && let Some(name) =
544 {
{
'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)
545 {
546 to_add.push(llvm::CreateAttrStringValue(
547 cx.llcx,
548 "alloc-variant-zeroed",
549 &mangle_internal_symbol(tcx, name.as_str()),
550 ));
551 }
552 let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
554 attributes::apply_to_llfn(llfn, AttributePlace::Argument(1), &[alloc_align]);
555 to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 0));
556 let mut flags = AllocKindFlags::Alloc | AllocKindFlags::Aligned;
557 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
558 flags |= AllocKindFlags::Uninitialized;
559 } else {
560 flags |= AllocKindFlags::Zeroed;
561 }
562 to_add.push(llvm::CreateAllocKindAttr(cx.llcx, flags));
563 let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx);
566 attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]);
567 }
568 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::REALLOCATOR) {
569 to_add.push(create_alloc_family_attr(cx.llcx));
570 to_add.push(llvm::CreateAllocKindAttr(
571 cx.llcx,
572 AllocKindFlags::Realloc | AllocKindFlags::Aligned,
573 ));
574 let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
576 attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
577 let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
579 attributes::apply_to_llfn(llfn, AttributePlace::Argument(2), &[alloc_align]);
580 to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 3));
581 let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx);
582 attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]);
583 }
584 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::DEALLOCATOR) {
585 to_add.push(create_alloc_family_attr(cx.llcx));
586 to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free));
587 let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
589 let captures_addr = AttributeKind::CapturesAddress.create_attr(cx.llcx);
593 let attrs = &[allocated_pointer, captures_addr];
594 attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), attrs);
595 }
596 if let Some(align) = codegen_fn_attrs.alignment {
597 llvm::set_alignment(llfn, align);
598 }
599 if let Some(packed_stack) = packed_stack_attr(cx, sess, &codegen_fn_attrs.target_features) {
600 to_add.push(packed_stack);
601 }
602 to_add.extend(patchable_function_entry_attrs(
603 cx,
604 sess,
605 codegen_fn_attrs.patchable_function_entry,
606 ));
607
608 to_add.push(target_cpu_attr(cx, sess));
612 to_add.extend(tune_cpu_attr(cx, sess));
615
616 let function_features =
617 codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
618
619 let function_features = function_features
620 .iter()
621 .flat_map(|feat| llvm_util::to_llvm_features(sess, feat))
623 .flat_map(|feat| feat.into_iter().map(|f| ::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("+{0}", f)) })format!("+{f}")))
625 .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x {
626 InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(),
627 InstructionSetAttr::ArmT32 => "+thumb-mode".to_string(),
628 }))
629 .collect::<Vec<String>>();
630
631 if sess.target.is_like_wasm {
632 if let Some(instance) = instance
635 && let Some(module) = wasm_import_module(tcx, instance.def_id())
636 {
637 to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-module", module));
638
639 let name =
640 codegen_fn_attrs.symbol_name.unwrap_or_else(|| tcx.item_name(instance.def_id()));
641 let name = name.as_str();
642 to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-name", name));
643 }
644 }
645
646 to_add.extend(target_features_attr(cx, tcx, function_features));
647
648 attributes::apply_to_llfn(llfn, Function, &to_add);
649}
650
651fn wasm_import_module(tcx: TyCtxt<'_>, id: DefId) -> Option<&String> {
652 tcx.wasm_import_module_map(id.krate).get(&id)
653}