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