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