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::Session;
12use rustc_session::config::{
13 BranchProtection, FunctionReturn, InstrumentMcount, InstrumentMcountOpts, OptLevel, PAuthKey,
14 PacRet,
15};
16use rustc_span::sym;
17use rustc_symbol_mangling::mangle_internal_symbol;
18use rustc_target::spec::{Arch, FramePointer, SanitizerSet, StackProbeType, StackProtector};
19use smallvec::SmallVec;
20
21use crate::context::SimpleCx;
22use crate::diagnostics::{PackedStackBackchainNeedsSoftfloat, SanitizerMemtagRequiresMte};
23use crate::llvm::AttributePlace::Function;
24use crate::llvm::{
25 self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects, Value,
26};
27use crate::{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 instance: Option<ty::Instance<'tcx>>,
143 sanitizer_ignorelist: Option<&SanitizerIgnoreList>,
144) -> SmallVec<[&'ll Attribute; 4]> {
145 let mut attrs = SmallVec::new();
146 let mut enabled = tcx.sess.sanitizers() - sanitizer_fn_attr.disabled;
147 if let Some(ignorelist) = sanitizer_ignorelist {
148 if let Some(instance) = instance {
149 let result = ignorelist.filter_instance_sanitizers(tcx, instance, enabled);
150 enabled = result.enabled;
151 if result.ignore_cfi {
152 attrs.push(llvm::CreateAttrString(cx.llcx, "no-sanitize-cfi"));
153 }
154 if result.ignore_kcfi {
155 attrs.push(llvm::CreateAttrString(cx.llcx, "no-sanitize-kcfi"));
156 }
157 }
158 }
159
160 if enabled.contains(SanitizerSet::ADDRESS) || enabled.contains(SanitizerSet::KERNELADDRESS) {
161 attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx));
162 }
163 if enabled.contains(SanitizerSet::MEMORY) {
164 attrs.push(llvm::AttributeKind::SanitizeMemory.create_attr(cx.llcx));
165 }
166 if enabled.contains(SanitizerSet::THREAD) {
167 attrs.push(llvm::AttributeKind::SanitizeThread.create_attr(cx.llcx));
168 }
169 if enabled.contains(SanitizerSet::HWADDRESS) || enabled.contains(SanitizerSet::KERNELHWADDRESS)
170 {
171 attrs.push(llvm::AttributeKind::SanitizeHWAddress.create_attr(cx.llcx));
172 }
173 if enabled.contains(SanitizerSet::SHADOWCALLSTACK) {
174 attrs.push(llvm::AttributeKind::ShadowCallStack.create_attr(cx.llcx));
175 }
176 if enabled.contains(SanitizerSet::MEMTAG) {
177 let features = &tcx.sess.global_backend_features;
179 let mte_feature =
180 features.iter().map(|s| &s[..]).rfind(|n| ["+mte", "-mte"].contains(&&n[..]));
181 if let None | Some("-mte") = mte_feature {
182 tcx.dcx().emit_err(SanitizerMemtagRequiresMte);
183 }
184
185 attrs.push(llvm::AttributeKind::SanitizeMemTag.create_attr(cx.llcx));
186 }
187 if enabled.contains(SanitizerSet::SAFESTACK) {
188 attrs.push(llvm::AttributeKind::SanitizeSafeStack.create_attr(cx.llcx));
189 }
190 if tcx.sess.sanitizers().contains(SanitizerSet::REALTIME) {
191 match sanitizer_fn_attr.rtsan_setting {
192 RtsanSetting::Nonblocking => {
193 attrs.push(llvm::AttributeKind::SanitizeRealtimeNonblocking.create_attr(cx.llcx))
194 }
195 RtsanSetting::Blocking => {
196 attrs.push(llvm::AttributeKind::SanitizeRealtimeBlocking.create_attr(cx.llcx))
197 }
198 RtsanSetting::Caller => (),
200 }
201 }
202 attrs
203}
204
205#[inline]
207pub(crate) fn uwtable_attr(llcx: &llvm::Context, use_sync_unwind: Option<bool>) -> &Attribute {
208 let async_unwind = !use_sync_unwind.unwrap_or(false);
214 llvm::CreateUWTableAttr(llcx, async_unwind)
215}
216
217pub(crate) fn frame_pointer(sess: &Session) -> FramePointer {
218 let mut fp = sess.target.frame_pointer;
219 let opts = &sess.opts;
220 if let InstrumentMcount::Mcount(_) = opts.unstable_opts.instrument_mcount {
223 fp.ratchet(FramePointer::Always);
224 }
225 fp.ratchet(opts.cg.force_frame_pointers);
226 fp
227}
228
229pub(crate) fn frame_pointer_type_attr<'ll>(
230 cx: &SimpleCx<'ll>,
231 sess: &Session,
232) -> Option<&'ll Attribute> {
233 let fp = frame_pointer(sess);
234 let attr_value = match fp {
235 FramePointer::Always => "all",
236 FramePointer::NonLeaf => "non-leaf",
237 FramePointer::MayOmit => return None,
238 };
239 Some(llvm::CreateAttrStringValue(cx.llcx, "frame-pointer", attr_value))
240}
241
242fn function_return_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
243 let function_return_attr = match sess.opts.unstable_opts.function_return {
244 FunctionReturn::Keep => return None,
245 FunctionReturn::ThunkExtern => AttributeKind::FnRetThunkExtern,
246 };
247
248 Some(function_return_attr.create_attr(cx.llcx))
249}
250
251#[inline]
253fn instrument_function_attr<'ll>(
254 cx: &SimpleCx<'ll>,
255 sess: &Session,
256 instrument_fn: Option<InstrumentFnAttr>,
257) -> SmallVec<[&'ll Attribute; 4]> {
258 let mut attrs = SmallVec::new();
259 if sess.opts.unstable_opts.instrument_mcount != InstrumentMcount::Disabled {
260 let instrument_entry = match instrument_fn {
264 Some(InstrumentFnAttr::On) | None => true,
265 Some(InstrumentFnAttr::Off) => false,
266 };
267
268 if instrument_entry {
269 let mut opts = InstrumentMcountOpts::default();
270 match sess.opts.unstable_opts.instrument_mcount {
271 InstrumentMcount::Mcount(mopts) => {
272 let mcount_name = match &sess.target.llvm_mcount_intrinsic {
275 Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(),
276 None => sess.target.mcount.as_ref(),
277 };
278
279 attrs.push(llvm::CreateAttrStringValue(
280 cx.llcx,
281 "instrument-function-entry-inlined",
282 mcount_name,
283 ));
284 opts = mopts;
285 }
286 InstrumentMcount::Fentry(fopts) => {
287 attrs.push(llvm::CreateAttrStringValue(cx.llcx, "fentry-call", "true"));
288 opts = fopts;
289 }
290 InstrumentMcount::Disabled => {}
291 }
292 if opts.no_call {
293 attrs.push(llvm::CreateAttrString(cx.llcx, "mnop-mcount"));
294 }
295 if opts.record {
296 attrs.push(llvm::CreateAttrString(cx.llcx, "mrecord-mcount"));
297 }
298 }
299 }
300 if let Some(options) = &sess.opts.unstable_opts.instrument_xray {
301 let mut never = options.never;
306 let mut always = options.always;
307
308 match instrument_fn {
310 Some(InstrumentFnAttr::On) => {
311 always = true;
312 }
313 Some(InstrumentFnAttr::Off) => {
314 never = true;
315 }
316 None => {}
317 }
318
319 if never {
320 attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-never"));
321 }
322 if always {
323 attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-always"));
324 }
325
326 if options.ignore_loops {
327 attrs.push(llvm::CreateAttrString(cx.llcx, "xray-ignore-loops"));
328 }
329 let threshold = options.instruction_threshold.unwrap_or(200);
332 attrs.push(llvm::CreateAttrStringValue(
333 cx.llcx,
334 "xray-instruction-threshold",
335 &threshold.to_string(),
336 ));
337 if options.skip_entry {
338 attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-entry"));
339 }
340 if options.skip_exit {
341 attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-exit"));
342 }
343 }
344 attrs
345}
346
347fn nojumptables_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
348 if sess.opts.cg.jump_tables {
349 return None;
350 }
351
352 Some(llvm::CreateAttrStringValue(cx.llcx, "no-jump-tables", "true"))
353}
354
355fn probestack_attr<'ll, 'tcx>(cx: &SimpleCx<'ll>, tcx: TyCtxt<'tcx>) -> Option<&'ll Attribute> {
356 if tcx.sess.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD) {
360 return None;
361 }
362
363 if tcx.sess.opts.cg.profile_generate.enabled() {
365 return None;
366 }
367
368 let attr_value = match tcx.sess.target.stack_probes {
369 StackProbeType::None => return None,
370 StackProbeType::Inline => "inline-asm",
373 StackProbeType::Call => &mangle_internal_symbol(tcx, "__rust_probestack"),
376 StackProbeType::InlineOrCall { min_llvm_version_for_inline } => {
378 if llvm_util::get_version() < min_llvm_version_for_inline {
379 &mangle_internal_symbol(tcx, "__rust_probestack")
380 } else {
381 "inline-asm"
382 }
383 }
384 };
385 Some(llvm::CreateAttrStringValue(cx.llcx, "probe-stack", attr_value))
386}
387
388fn stackprotector_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
389 let sspattr = match sess.stack_protector() {
390 StackProtector::None => return None,
391 StackProtector::All => AttributeKind::StackProtectReq,
392 StackProtector::Strong => AttributeKind::StackProtectStrong,
393 StackProtector::Basic => AttributeKind::StackProtect,
394 };
395
396 Some(sspattr.create_attr(cx.llcx))
397}
398
399fn packed_stack_attr<'ll>(
400 cx: &SimpleCx<'ll>,
401 sess: &Session,
402 function_attributes: &Vec<TargetFeature>,
403) -> Option<&'ll Attribute> {
404 if sess.target.arch != Arch::S390x {
405 return None;
406 }
407 if !sess.opts.unstable_opts.packed_stack {
408 return None;
409 }
410
411 let have_backchain = sess.internal_target_features.contains(&sym::backchain)
414 || function_attributes.iter().any(|feature| feature.name == sym::backchain);
415 let have_softfloat = sess.internal_target_features.contains(&sym::soft_float)
416 || function_attributes.iter().any(|feature| feature.name == sym::soft_float);
417
418 if have_backchain && !have_softfloat {
422 sess.dcx().emit_err(PackedStackBackchainNeedsSoftfloat);
423 return None;
424 }
425
426 Some(llvm::CreateAttrString(cx.llcx, "packed-stack"))
427}
428
429pub(crate) fn target_cpu_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> &'ll Attribute {
430 let target_cpu = llvm_util::target_cpu(sess);
431 llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu)
432}
433
434pub(crate) fn tune_cpu_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
435 llvm_util::tune_cpu(sess)
436 .map(|tune_cpu| llvm::CreateAttrStringValue(cx.llcx, "tune-cpu", tune_cpu))
437}
438
439pub(crate) fn target_features_attr<'ll, 'tcx>(
441 cx: &SimpleCx<'ll>,
442 tcx: TyCtxt<'tcx>,
443 function_features: Vec<String>,
444) -> Option<&'ll Attribute> {
445 let global_features = tcx.sess.global_backend_features.iter().map(String::as_str);
446 let function_features = function_features.iter().map(String::as_str);
447 let target_features =
448 global_features.chain(function_features).intersperse(",").collect::<String>();
449 (!target_features.is_empty())
450 .then(|| llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features))
451}
452
453pub(crate) fn non_lazy_bind_attr<'ll>(
456 cx: &SimpleCx<'ll>,
457 sess: &Session,
458) -> Option<&'ll Attribute> {
459 if !sess.needs_plt() { Some(AttributeKind::NonLazyBind.create_attr(cx.llcx)) } else { None }
461}
462
463#[inline]
465pub(crate) fn default_optimisation_attrs<'ll>(
466 cx: &SimpleCx<'ll>,
467 sess: &Session,
468) -> SmallVec<[&'ll Attribute; 2]> {
469 let mut attrs = SmallVec::new();
470 match sess.opts.optimize {
471 OptLevel::Size => {
472 attrs.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
473 }
474 OptLevel::SizeMin => {
475 attrs.push(llvm::AttributeKind::MinSize.create_attr(cx.llcx));
476 attrs.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
477 }
478 _ => {}
479 }
480 attrs
481}
482
483fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute {
484 llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc")
485}
486
487pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
491 cx: &SimpleCx<'ll>,
492 tcx: TyCtxt<'tcx>,
493 llfn: &'ll Value,
494 codegen_fn_attrs: &CodegenFnAttrs,
495 instance: Option<ty::Instance<'tcx>>,
496 sanitizer_ignorelist: Option<&SanitizerIgnoreList>,
497) {
498 let sess = tcx.sess;
499 let mut to_add = SmallVec::<[_; 16]>::new();
500
501 match codegen_fn_attrs.optimize {
502 OptimizeAttr::Default => {
503 to_add.extend(default_optimisation_attrs(cx, sess));
504 }
505 OptimizeAttr::DoNotOptimize => {
506 to_add.push(llvm::AttributeKind::OptimizeNone.create_attr(cx.llcx));
507 }
508 OptimizeAttr::Size => {
509 to_add.push(llvm::AttributeKind::MinSize.create_attr(cx.llcx));
510 to_add.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
511 }
512 OptimizeAttr::Speed => {}
513 }
514
515 if let Some(instance) = instance {
516 to_add.extend(inline_attr(cx, tcx, instance, codegen_fn_attrs));
517 }
518
519 if sess.must_emit_unwind_tables() {
520 to_add.push(uwtable_attr(cx.llcx, sess.opts.unstable_opts.use_sync_unwind));
521 }
522
523 if sess.opts.cg.profile_sample_use.is_some() {
524 to_add.push(llvm::CreateAttrString(cx.llcx, "use-sample-profile"));
525 }
526
527 to_add.extend(frame_pointer_type_attr(cx, sess));
529 to_add.extend(function_return_attr(cx, sess));
530 to_add.extend(instrument_function_attr(cx, sess, codegen_fn_attrs.instrument_fn));
531 to_add.extend(nojumptables_attr(cx, sess));
532 to_add.extend(probestack_attr(cx, tcx));
533 to_add.extend(stackprotector_attr(cx, sess));
534
535 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_BUILTINS) {
536 to_add.push(llvm::CreateAttrString(cx.llcx, "no-builtins"));
537 }
538
539 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::OFFLOAD_KERNEL) {
540 to_add.push(llvm::CreateAttrString(cx.llcx, "offload-kernel"))
541 }
542
543 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
544 to_add.push(AttributeKind::Cold.create_attr(cx.llcx));
545 }
546 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) {
547 to_add.push(MemoryEffects::ReadOnly.create_attr(cx.llcx));
548 }
549 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_CONST) {
550 to_add.push(MemoryEffects::None.create_attr(cx.llcx));
551 }
552 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
553 } else {
557 to_add.extend(sanitize_attrs(
559 cx,
560 tcx,
561 codegen_fn_attrs.sanitizers,
562 instance,
563 sanitizer_ignorelist,
564 ));
565
566 if let Some(BranchProtection { bti, pac_ret, gcs }) = sess.branch_protection() {
568 if !(sess.target.arch == Arch::AArch64) {
::core::panicking::panic("assertion failed: sess.target.arch == Arch::AArch64")
};assert!(sess.target.arch == Arch::AArch64);
569 if bti {
570 to_add.push(llvm::CreateAttrString(cx.llcx, "branch-target-enforcement"));
571 }
572 if gcs {
573 to_add.push(llvm::CreateAttrString(cx.llcx, "guarded-control-stack"));
574 }
575 if let Some(PacRet { leaf, pc, key }) = pac_ret {
576 if pc {
577 to_add.push(llvm::CreateAttrString(cx.llcx, "branch-protection-pauth-lr"));
578 }
579 to_add.push(llvm::CreateAttrStringValue(
580 cx.llcx,
581 "sign-return-address",
582 if leaf { "all" } else { "non-leaf" },
583 ));
584 to_add.push(llvm::CreateAttrStringValue(
585 cx.llcx,
586 "sign-return-address-key",
587 if key == PAuthKey::A { "a_key" } else { "b_key" },
588 ));
589 }
590 }
591 }
592 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR)
593 || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED)
594 {
595 to_add.push(create_alloc_family_attr(cx.llcx));
596 if let Some(instance) = instance
597 && let Some(name) =
598 {
{
'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)
599 {
600 to_add.push(llvm::CreateAttrStringValue(
601 cx.llcx,
602 "alloc-variant-zeroed",
603 &mangle_internal_symbol(tcx, name.as_str()),
604 ));
605 }
606 let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
608 attributes::apply_to_llfn(llfn, AttributePlace::Argument(1), &[alloc_align]);
609 to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 0));
610 let mut flags = AllocKindFlags::Alloc | AllocKindFlags::Aligned;
611 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
612 flags |= AllocKindFlags::Uninitialized;
613 } else {
614 flags |= AllocKindFlags::Zeroed;
615 }
616 to_add.push(llvm::CreateAllocKindAttr(cx.llcx, flags));
617 let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx);
620 attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]);
621 }
622 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::REALLOCATOR) {
623 to_add.push(create_alloc_family_attr(cx.llcx));
624 to_add.push(llvm::CreateAllocKindAttr(
625 cx.llcx,
626 AllocKindFlags::Realloc | AllocKindFlags::Aligned,
627 ));
628 let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
630 attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
631 let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
633 attributes::apply_to_llfn(llfn, AttributePlace::Argument(2), &[alloc_align]);
634 to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 3));
635 let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx);
636 attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]);
637 }
638 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::DEALLOCATOR) {
639 to_add.push(create_alloc_family_attr(cx.llcx));
640 to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free));
641 let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
643 let captures_addr = AttributeKind::CapturesAddress.create_attr(cx.llcx);
647 let attrs = &[allocated_pointer, captures_addr];
648 attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), attrs);
649 }
650 if let Some(align) = codegen_fn_attrs.alignment {
651 llvm::set_alignment(llfn, align);
652 }
653 if let Some(packed_stack) = packed_stack_attr(cx, sess, &codegen_fn_attrs.target_features) {
654 to_add.push(packed_stack);
655 }
656 to_add.extend(patchable_function_entry_attrs(
657 cx,
658 sess,
659 codegen_fn_attrs.patchable_function_entry,
660 ));
661
662 to_add.push(target_cpu_attr(cx, sess));
666 to_add.extend(tune_cpu_attr(cx, sess));
669
670 let function_features =
671 codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
672
673 let function_features = function_features
674 .iter()
675 .flat_map(|feat| llvm_util::to_llvm_features(&sess.target, feat))
677 .flat_map(|feat| feat.into_iter().map(|f| ::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("+{0}", f)) })format!("+{f}")))
679 .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x {
680 InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(),
681 InstructionSetAttr::ArmT32 => "+thumb-mode".to_string(),
682 }))
683 .collect::<Vec<String>>();
684
685 if sess.target.is_like_wasm {
686 if let Some(instance) = instance
689 && let Some(module) = wasm_import_module(tcx, instance.def_id())
690 {
691 to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-module", module));
692
693 let name =
694 codegen_fn_attrs.symbol_name.unwrap_or_else(|| tcx.item_name(instance.def_id()));
695 let name = name.as_str();
696 to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-name", name));
697 }
698 }
699
700 if sess.pointer_authentication() {
701 let cfg = sess.pointer_auth_config.as_ref().unwrap();
702 for ptrauth_attr in cfg.fn_attrs() {
703 to_add.push(llvm::CreateAttrString(cx.llcx, ptrauth_attr));
704 }
705 }
706
707 to_add.extend(target_features_attr(cx, tcx, function_features));
708
709 attributes::apply_to_llfn(llfn, Function, &to_add);
710}
711
712fn wasm_import_module(tcx: TyCtxt<'_>, id: DefId) -> Option<&String> {
713 tcx.wasm_import_module_map(id.krate).get(&id)
714}