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