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