]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_codegen_llvm/src/attributes.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / compiler / rustc_codegen_llvm / src / attributes.rs
CommitLineData
54a0048b
SL
1//! Set and unset common attributes on LLVM values.
2
dfeec247 3use rustc_codegen_ssa::traits::*;
5e7ed085 4use rustc_data_structures::small_str::SmallStr;
29967ef6 5use rustc_hir::def_id::DefId;
ba9703b0 6use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
ba9703b0 7use rustc_middle::ty::{self, TyCtxt};
cdc7bbd5 8use rustc_session::config::OptLevel;
04454e1e 9use rustc_span::symbol::sym;
cdc7bbd5 10use rustc_target::spec::abi::Abi;
3c0e092e 11use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
5e7ed085 12use smallvec::SmallVec;
041b39d2 13
9fa01778 14use crate::attributes;
487cf647 15use crate::errors::{MissingFeatures, SanitizerMemtagRequiresMte, TargetFeatureDisableOrEnable};
9fa01778 16use crate::llvm::AttributePlace::Function;
487cf647 17use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects};
9fa01778 18use crate::llvm_util;
29967ef6 19pub use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
b7449926 20
9fa01778
XL
21use crate::context::CodegenCx;
22use crate::value::Value;
54a0048b 23
5e7ed085
FG
24pub fn apply_to_llfn(llfn: &Value, idx: AttributePlace, attrs: &[&Attribute]) {
25 if !attrs.is_empty() {
26 llvm::AddFunctionAttributes(llfn, idx, attrs);
27 }
28}
29
30pub fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[&Attribute]) {
31 if !attrs.is_empty() {
32 llvm::AddCallSiteAttributes(callsite, idx, attrs);
33 }
34}
35
36/// Get LLVM attribute for the provided inline heuristic.
54a0048b 37#[inline]
5e7ed085 38fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll Attribute> {
f2b60f7d
FG
39 if !cx.tcx.sess.opts.unstable_opts.inline_llvm {
40 // disable LLVM inlining
41 return Some(AttributeKind::NoInline.create_attr(cx.llcx));
42 }
54a0048b 43 match inline {
5e7ed085
FG
44 InlineAttr::Hint => Some(AttributeKind::InlineHint.create_attr(cx.llcx)),
45 InlineAttr::Always => Some(AttributeKind::AlwaysInline.create_attr(cx.llcx)),
46 InlineAttr::Never => {
47 if cx.sess().target.arch != "amdgpu" {
48 Some(AttributeKind::NoInline.create_attr(cx.llcx))
49 } else {
50 None
b7449926 51 }
dfeec247 52 }
5e7ed085
FG
53 InlineAttr::None => None,
54 }
54a0048b
SL
55}
56
5e7ed085 57/// Get LLVM sanitize attributes.
74b04a01 58#[inline]
5e7ed085
FG
59pub fn sanitize_attrs<'ll>(
60 cx: &CodegenCx<'ll, '_>,
61 no_sanitize: SanitizerSet,
62) -> SmallVec<[&'ll Attribute; 4]> {
63 let mut attrs = SmallVec::new();
064997fb 64 let enabled = cx.tcx.sess.opts.unstable_opts.sanitizer - no_sanitize;
f035d41b 65 if enabled.contains(SanitizerSet::ADDRESS) {
5e7ed085 66 attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx));
f035d41b
XL
67 }
68 if enabled.contains(SanitizerSet::MEMORY) {
5e7ed085 69 attrs.push(llvm::AttributeKind::SanitizeMemory.create_attr(cx.llcx));
f035d41b
XL
70 }
71 if enabled.contains(SanitizerSet::THREAD) {
5e7ed085 72 attrs.push(llvm::AttributeKind::SanitizeThread.create_attr(cx.llcx));
74b04a01 73 }
6a06907d 74 if enabled.contains(SanitizerSet::HWADDRESS) {
5e7ed085 75 attrs.push(llvm::AttributeKind::SanitizeHWAddress.create_attr(cx.llcx));
6a06907d 76 }
064997fb
FG
77 if enabled.contains(SanitizerSet::SHADOWCALLSTACK) {
78 attrs.push(llvm::AttributeKind::ShadowCallStack.create_attr(cx.llcx));
79 }
5099ac24
FG
80 if enabled.contains(SanitizerSet::MEMTAG) {
81 // Check to make sure the mte target feature is actually enabled.
5e7ed085
FG
82 let features = cx.tcx.global_backend_features(());
83 let mte_feature =
84 features.iter().map(|s| &s[..]).rfind(|n| ["+mte", "-mte"].contains(&&n[..]));
85 if let None | Some("-mte") = mte_feature {
487cf647 86 cx.tcx.sess.emit_err(SanitizerMemtagRequiresMte);
5099ac24
FG
87 }
88
5e7ed085 89 attrs.push(llvm::AttributeKind::SanitizeMemTag.create_attr(cx.llcx));
5099ac24 90 }
5e7ed085 91 attrs
74b04a01
XL
92}
93
54a0048b
SL
94/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
95#[inline]
5e7ed085 96pub fn uwtable_attr(llcx: &llvm::Context) -> &Attribute {
5099ac24
FG
97 // NOTE: We should determine if we even need async unwind tables, as they
98 // take have more overhead and if we can use sync unwind tables we
99 // probably should.
5e7ed085 100 llvm::CreateUWTableAttr(llcx, true)
54a0048b
SL
101}
102
5e7ed085 103pub fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
136023e0 104 let mut fp = cx.sess().target.frame_pointer;
9c376795 105 let opts = &cx.sess().opts;
136023e0
XL
106 // "mcount" function relies on stack pointer.
107 // See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
9c376795 108 if opts.unstable_opts.instrument_mcount || matches!(opts.cg.force_frame_pointers, Some(true)) {
136023e0 109 fp = FramePointer::Always;
54a0048b 110 }
136023e0 111 let attr_value = match fp {
5e7ed085
FG
112 FramePointer::Always => "all",
113 FramePointer::NonLeaf => "non-leaf",
114 FramePointer::MayOmit => return None,
136023e0 115 };
5e7ed085 116 Some(llvm::CreateAttrStringValue(cx.llcx, "frame-pointer", attr_value))
3157f602
XL
117}
118
0731742a
XL
119/// Tell LLVM what instrument function to insert.
120#[inline]
5e7ed085 121fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
9c376795 122 if cx.sess().opts.unstable_opts.instrument_mcount {
0731742a
XL
123 // Similar to `clang -pg` behavior. Handled by the
124 // `post-inline-ee-instrument` LLVM pass.
532ac7d7
XL
125
126 // The function name varies on platforms.
127 // See test/CodeGen/mcount.c in clang.
5e7ed085 128 let mcount_name = cx.sess().target.mcount.as_ref();
532ac7d7 129
5e7ed085
FG
130 Some(llvm::CreateAttrStringValue(
131 cx.llcx,
132 "instrument-function-entry-inlined",
dfeec247 133 &mcount_name,
5e7ed085
FG
134 ))
135 } else {
136 None
0731742a
XL
137 }
138}
139
9c376795
FG
140fn nojumptables_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
141 if !cx.sess().opts.unstable_opts.no_jump_tables {
142 return None;
143 }
144
145 Some(llvm::CreateAttrStringValue(cx.llcx, "no-jump-tables", "true"))
146}
147
5e7ed085 148fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
041b39d2 149 // Currently stack probes seem somewhat incompatible with the address
e74abb32
XL
150 // sanitizer and thread sanitizer. With asan we're already protected from
151 // stack overflow anyway so we don't really need stack probes regardless.
f035d41b
XL
152 if cx
153 .sess()
154 .opts
064997fb 155 .unstable_opts
f035d41b
XL
156 .sanitizer
157 .intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD)
158 {
5e7ed085 159 return None;
041b39d2
XL
160 }
161
dc9dc135
XL
162 // probestack doesn't play nice either with `-C profile-generate`.
163 if cx.sess().opts.cg.profile_generate.enabled() {
5e7ed085 164 return None;
0531ce1d
XL
165 }
166
8faf50e0 167 // probestack doesn't play nice either with gcov profiling.
064997fb 168 if cx.sess().opts.unstable_opts.profile {
5e7ed085 169 return None;
8faf50e0
XL
170 }
171
5869c6ff 172 let attr_value = match cx.sess().target.stack_probes {
5e7ed085 173 StackProbeType::None => return None,
5869c6ff
XL
174 // Request LLVM to generate the probes inline. If the given LLVM version does not support
175 // this, no probe is generated at all (even if the attribute is specified).
5e7ed085 176 StackProbeType::Inline => "inline-asm",
5869c6ff
XL
177 // Flag our internal `__rust_probestack` function as the stack probe symbol.
178 // This is defined in the `compiler-builtins` crate for each architecture.
5e7ed085 179 StackProbeType::Call => "__rust_probestack",
5869c6ff
XL
180 // Pick from the two above based on the LLVM version.
181 StackProbeType::InlineOrCall { min_llvm_version_for_inline } => {
182 if llvm_util::get_version() < min_llvm_version_for_inline {
5e7ed085 183 "__rust_probestack"
5869c6ff 184 } else {
5e7ed085 185 "inline-asm"
5869c6ff
XL
186 }
187 }
188 };
5e7ed085 189 Some(llvm::CreateAttrStringValue(cx.llcx, "probe-stack", attr_value))
041b39d2
XL
190}
191
5e7ed085 192fn stackprotector_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
3c0e092e 193 let sspattr = match cx.sess().stack_protector() {
5e7ed085
FG
194 StackProtector::None => return None,
195 StackProtector::All => AttributeKind::StackProtectReq,
196 StackProtector::Strong => AttributeKind::StackProtectStrong,
197 StackProtector::Basic => AttributeKind::StackProtect,
3c0e092e
XL
198 };
199
5e7ed085 200 Some(sspattr.create_attr(cx.llcx))
3c0e092e
XL
201}
202
5e7ed085
FG
203pub fn target_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll Attribute {
204 let target_cpu = llvm_util::target_cpu(cx.tcx.sess);
205 llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu)
b7449926
XL
206}
207
5e7ed085
FG
208pub fn tune_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
209 llvm_util::tune_cpu(cx.tcx.sess)
210 .map(|tune_cpu| llvm::CreateAttrStringValue(cx.llcx, "tune-cpu", tune_cpu))
29967ef6
XL
211}
212
5e7ed085
FG
213/// Get the `NonLazyBind` LLVM attribute,
214/// if the codegen options allow skipping the PLT.
215pub fn non_lazy_bind_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
0bf4aa26 216 // Don't generate calls through PLT if it's not necessary
5e7ed085
FG
217 if !cx.sess().needs_plt() {
218 Some(AttributeKind::NonLazyBind.create_attr(cx.llcx))
219 } else {
220 None
0bf4aa26
XL
221 }
222}
223
5e7ed085
FG
224/// Get the default optimizations attrs for a function.
225#[inline]
226pub(crate) fn default_optimisation_attrs<'ll>(
227 cx: &CodegenCx<'ll, '_>,
228) -> SmallVec<[&'ll Attribute; 2]> {
229 let mut attrs = SmallVec::new();
230 match cx.sess().opts.optimize {
9fa01778 231 OptLevel::Size => {
5e7ed085 232 attrs.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
dfeec247 233 }
9fa01778 234 OptLevel::SizeMin => {
5e7ed085
FG
235 attrs.push(llvm::AttributeKind::MinSize.create_attr(cx.llcx));
236 attrs.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
9fa01778
XL
237 }
238 _ => {}
239 }
5e7ed085 240 attrs
9fa01778
XL
241}
242
064997fb
FG
243fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute {
244 llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc")
245}
246
0731742a 247/// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
3157f602 248/// attributes.
a2a8927a
XL
249pub fn from_fn_attrs<'ll, 'tcx>(
250 cx: &CodegenCx<'ll, 'tcx>,
251 llfn: &'ll Value,
252 instance: ty::Instance<'tcx>,
253) {
60c5eb7d 254 let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
0531ce1d 255
5e7ed085
FG
256 let mut to_add = SmallVec::<[_; 16]>::new();
257
9fa01778
XL
258 match codegen_fn_attrs.optimize {
259 OptimizeAttr::None => {
5e7ed085 260 to_add.extend(default_optimisation_attrs(cx));
9fa01778
XL
261 }
262 OptimizeAttr::Size => {
5e7ed085
FG
263 to_add.push(llvm::AttributeKind::MinSize.create_attr(cx.llcx));
264 to_add.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
9fa01778 265 }
5e7ed085 266 OptimizeAttr::Speed => {}
9fa01778
XL
267 }
268
487cf647
FG
269 let inline =
270 if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) {
271 InlineAttr::Hint
272 } else {
273 codegen_fn_attrs.inline
274 };
5e7ed085 275 to_add.extend(inline_attr(cx, inline));
b7449926
XL
276
277 // The `uwtable` attribute according to LLVM is:
278 //
279 // This attribute indicates that the ABI being targeted requires that an
280 // unwind table entry be produced for this function even if we can show
281 // that no exceptions passes by it. This is normally the case for the
282 // ELF x86-64 abi, but it can be disabled for some compilation units.
283 //
284 // Typically when we're compiling with `-C panic=abort` (which implies this
285 // `no_landing_pads` check) we don't need `uwtable` because we can't
286 // generate any exceptions! On Windows, however, exceptions include other
287 // events such as illegal instructions, segfaults, etc. This means that on
288 // Windows we end up still needing the `uwtable` attribute even if the `-C
289 // panic=abort` flag is passed.
290 //
f035d41b 291 // You can also find more info on why Windows always requires uwtables here:
b7449926 292 // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078
f9f354fc 293 if cx.sess().must_emit_unwind_tables() {
5e7ed085 294 to_add.push(uwtable_attr(cx.llcx));
b7449926 295 }
3157f602 296
064997fb 297 if cx.sess().opts.unstable_opts.profile_sample_use.is_some() {
5e7ed085 298 to_add.push(llvm::CreateAttrString(cx.llcx, "use-sample-profile"));
c295e0f8
XL
299 }
300
cdc7bbd5 301 // FIXME: none of these three functions interact with source level attributes.
5e7ed085
FG
302 to_add.extend(frame_pointer_type_attr(cx));
303 to_add.extend(instrument_function_attr(cx));
9c376795 304 to_add.extend(nojumptables_attr(cx));
5e7ed085
FG
305 to_add.extend(probestack_attr(cx));
306 to_add.extend(stackprotector_attr(cx));
2c00a5a8 307
94b46f34 308 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
5e7ed085 309 to_add.push(AttributeKind::Cold.create_attr(cx.llcx));
0531ce1d 310 }
9fa01778 311 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) {
5e7ed085 312 to_add.push(AttributeKind::ReturnsTwice.create_attr(cx.llcx));
9fa01778 313 }
f9f354fc 314 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) {
487cf647 315 to_add.push(MemoryEffects::ReadOnly.create_attr(cx.llcx));
f9f354fc
XL
316 }
317 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_CONST) {
487cf647 318 to_add.push(MemoryEffects::None.create_attr(cx.llcx));
f9f354fc 319 }
94b46f34 320 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
5e7ed085 321 to_add.push(AttributeKind::Naked.create_attr(cx.llcx));
064997fb
FG
322 // HACK(jubilee): "indirect branch tracking" works by attaching prologues to functions.
323 // And it is a module-level attribute, so the alternative is pulling naked functions into new LLVM modules.
324 // Otherwise LLVM's "naked" functions come with endbr prefixes per https://github.com/rust-lang/rust/issues/98768
325 to_add.push(AttributeKind::NoCfCheck.create_attr(cx.llcx));
326 // Need this for AArch64.
327 to_add.push(llvm::CreateAttrStringValue(cx.llcx, "branch-target-enforcement", "false"));
0531ce1d 328 }
064997fb
FG
329 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR)
330 || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED)
331 {
332 if llvm_util::get_version() >= (15, 0, 0) {
333 to_add.push(create_alloc_family_attr(cx.llcx));
334 // apply to argument place instead of function
335 let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
336 attributes::apply_to_llfn(llfn, AttributePlace::Argument(1), &[alloc_align]);
337 to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 0));
338 let mut flags = AllocKindFlags::Alloc | AllocKindFlags::Aligned;
339 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
340 flags |= AllocKindFlags::Uninitialized;
341 } else {
342 flags |= AllocKindFlags::Zeroed;
343 }
344 to_add.push(llvm::CreateAllocKindAttr(cx.llcx, flags));
345 }
5e7ed085
FG
346 // apply to return place instead of function (unlike all other attributes applied in this function)
347 let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx);
348 attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]);
0531ce1d 349 }
064997fb
FG
350 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::REALLOCATOR) {
351 if llvm_util::get_version() >= (15, 0, 0) {
352 to_add.push(create_alloc_family_attr(cx.llcx));
353 to_add.push(llvm::CreateAllocKindAttr(
354 cx.llcx,
355 AllocKindFlags::Realloc | AllocKindFlags::Aligned,
356 ));
357 // applies to argument place instead of function place
358 let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
359 attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
360 // apply to argument place instead of function
361 let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
362 attributes::apply_to_llfn(llfn, AttributePlace::Argument(2), &[alloc_align]);
363 to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 3));
364 }
365 let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx);
366 attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]);
367 }
368 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::DEALLOCATOR) {
369 if llvm_util::get_version() >= (15, 0, 0) {
370 to_add.push(create_alloc_family_attr(cx.llcx));
371 to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free));
372 // applies to argument place instead of function place
373 let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
374 attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
375 }
376 }
1b1a35ee 377 if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) {
5e7ed085 378 to_add.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry"));
1b1a35ee 379 }
136023e0
XL
380 if let Some(align) = codegen_fn_attrs.alignment {
381 llvm::set_alignment(llfn, align as usize);
382 }
5e7ed085 383 to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize));
94b46f34 384
b7449926
XL
385 // Always annotate functions with the target-cpu they are compiled for.
386 // Without this, ThinLTO won't inline Rust functions into Clang generated
387 // functions (because Clang annotates functions this way too).
5e7ed085 388 to_add.push(target_cpu_attr(cx));
29967ef6
XL
389 // tune-cpu is only conveyed through the attribute for our purpose.
390 // The target doesn't care; the subtarget reads our attribute.
5e7ed085 391 to_add.extend(tune_cpu_attr(cx));
b7449926 392
5099ac24
FG
393 let function_features =
394 codegen_fn_attrs.target_features.iter().map(|f| f.as_str()).collect::<Vec<&str>>();
395
396 if let Some(f) = llvm_util::check_tied_features(
397 cx.tcx.sess,
398 &function_features.iter().map(|f| (*f, true)).collect(),
399 ) {
400 let span = cx
401 .tcx
f2b60f7d
FG
402 .get_attrs(instance.def_id(), sym::target_feature)
403 .next()
5099ac24 404 .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
487cf647
FG
405 cx.tcx
406 .sess
407 .create_err(TargetFeatureDisableOrEnable {
408 features: f,
409 span: Some(span),
410 missing_features: Some(MissingFeatures),
411 })
412 .emit();
5099ac24
FG
413 return;
414 }
415
416 let mut function_features = function_features
6a06907d 417 .iter()
5099ac24 418 .flat_map(|feat| {
5e7ed085 419 llvm_util::to_llvm_features(cx.tcx.sess, feat).into_iter().map(|f| format!("+{}", f))
6a06907d 420 })
29967ef6
XL
421 .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x {
422 InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(),
423 InstructionSetAttr::ArmT32 => "+thumb-mode".to_string(),
424 }))
6a06907d 425 .collect::<Vec<String>>();
0531ce1d 426
cdc7bbd5
XL
427 if cx.tcx.sess.target.is_like_wasm {
428 // If this function is an import from the environment but the wasm
429 // import has a specific module/name, apply them here.
60c5eb7d 430 if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) {
5e7ed085 431 to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-module", &module));
dfeec247
XL
432
433 let name =
434 codegen_fn_attrs.link_name.unwrap_or_else(|| cx.tcx.item_name(instance.def_id()));
5e7ed085
FG
435 let name = name.as_str();
436 to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-name", name));
0531ce1d 437 }
cdc7bbd5
XL
438
439 // The `"wasm"` abi on wasm targets automatically enables the
440 // `+multivalue` feature because the purpose of the wasm abi is to match
441 // the WebAssembly specification, which has this feature. This won't be
442 // needed when LLVM enables this `multivalue` feature by default.
443 if !cx.tcx.is_closure(instance.def_id()) {
444 let abi = cx.tcx.fn_sig(instance.def_id()).abi();
445 if abi == Abi::Wasm {
446 function_features.push("+multivalue".to_string());
447 }
448 }
449 }
450
5e7ed085
FG
451 let global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str());
452 let function_features = function_features.iter().map(|s| s.as_str());
453 let target_features =
454 global_features.chain(function_features).intersperse(",").collect::<SmallStr<1024>>();
455 if !target_features.is_empty() {
456 to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features));
0531ce1d 457 }
5e7ed085
FG
458
459 attributes::apply_to_llfn(llfn, Function, &to_add);
476ff2be
SL
460}
461
5e7ed085
FG
462fn wasm_import_module(tcx: TyCtxt<'_>, id: DefId) -> Option<&String> {
463 tcx.wasm_import_module_map(id.krate).get(&id)
0531ce1d 464}