From 96e9134dc911a577018b74ab99f761e609a8734b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Aug 2024 21:32:32 +0200 Subject: [PATCH 1/3] declare imported functions with a nondescript signature This means when the function is imported with multiple different signatures, they don't clash --- compiler/rustc_ast_passes/src/feature_gate.rs | 2 +- compiler/rustc_codegen_llvm/src/abi.rs | 25 +- compiler/rustc_codegen_llvm/src/attributes.rs | 68 +++-- compiler/rustc_codegen_llvm/src/builder.rs | 6 +- compiler/rustc_codegen_llvm/src/declare.rs | 39 ++- tests/codegen/aarch64-struct-align-128.rs | 52 ++-- tests/codegen/align-byval-vector.rs | 8 +- tests/codegen/align-byval.rs | 256 +++++++++--------- tests/codegen/box-uninit-bytes.rs | 6 +- tests/codegen/cffi/ffi-const.rs | 11 +- tests/codegen/cffi/ffi-pure.rs | 11 +- tests/codegen/issues/issue-111603.rs | 2 +- tests/codegen/iter-repeat-n-trivial-drop.rs | 2 +- tests/codegen/no_builtins-at-crate.rs | 6 +- tests/codegen/pic-relocation-model.rs | 5 +- tests/codegen/pie-relocation-model.rs | 2 +- tests/codegen/powerpc64le-struct-align-128.rs | 29 +- tests/codegen/unwind-extern-imports.rs | 22 +- tests/codegen/unwind-landingpad-cold.rs | 3 +- .../feature-gate-link_llvm_intrinsics.rs | 2 +- .../feature-gate-link_llvm_intrinsics.stderr | 2 +- tests/ui/issues/issue-20313.rs | 2 +- tests/ui/issues/issue-20313.stderr | 2 +- 23 files changed, 332 insertions(+), 231 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 45e397a58c098..b090fb6137b0d 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -324,7 +324,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { &self, link_llvm_intrinsics, i.span, - "linking to LLVM intrinsics is experimental" + "linking to LLVM intrinsics is an internal feature reserved for the standard library" ); } } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index dea574a53cd7b..60d40fd7b8eb1 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -321,7 +321,12 @@ pub(crate) trait FnAbiLlvmExt<'ll, 'tcx> { ); /// Apply attributes to a function call. - fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value); + fn apply_attrs_callsite( + &self, + bx: &mut Builder<'_, 'll, 'tcx>, + callsite: &'ll Value, + instance: Option>, + ); } impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { @@ -527,11 +532,18 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { // If the declaration has an associated instance, compute extra attributes based on that. if let Some(instance) = instance { - llfn_attrs_from_instance(cx, llfn, instance); + llfn_attrs_from_instance(cx, instance, Some(llfn), |place, attrs| { + attributes::apply_to_llfn(llfn, place, attrs) + }); } } - fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value) { + fn apply_attrs_callsite( + &self, + bx: &mut Builder<'_, 'll, 'tcx>, + callsite: &'ll Value, + instance: Option>, + ) { let mut func_attrs = SmallVec::<[_; 2]>::new(); if self.ret.layout.abi.is_uninhabited() { func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(bx.cx.llcx)); @@ -649,6 +661,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { &[element_type_attr], ); } + + // If the call site has an associated instance, compute extra attributes based on that. + if let Some(instance) = instance { + llfn_attrs_from_instance(bx.cx, instance, None, |place, attrs| { + attributes::apply_to_callsite(callsite, place, attrs) + }); + } } } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 9d4497d73a8ae..067975dc72c90 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -14,8 +14,8 @@ use crate::context::CodegenCx; use crate::errors::{MissingFeatures, SanitizerMemtagRequiresMte, TargetFeatureDisableOrEnable}; use crate::llvm::AttributePlace::Function; use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects}; +use crate::llvm_util; use crate::value::Value; -use crate::{attributes, llvm_util}; pub(crate) fn apply_to_llfn(llfn: &Value, idx: AttributePlace, attrs: &[&Attribute]) { if !attrs.is_empty() { @@ -324,13 +324,18 @@ fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute { llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc") } -/// Helper for `FnAbi::apply_attrs_llfn`: +/// Helper for `FnAbi::apply_attrs_*`: /// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`) /// attributes. +/// +/// `apply_attrs` is called to apply the attributes, so this can be used both for declarations and +/// calls. However, some things are not represented as attributes and can only be set on +/// declarations, so `declare_llfn` should be `Some` if this is a declaration. pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, - llfn: &'ll Value, instance: ty::Instance<'tcx>, + declare_llfn: Option<&'ll Value>, + apply_attrs: impl Fn(AttributePlace, &[&Attribute]), ) { let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); @@ -445,7 +450,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( to_add.push(create_alloc_family_attr(cx.llcx)); // apply to argument place instead of function let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::Argument(1), &[alloc_align]); + apply_attrs(AttributePlace::Argument(1), &[alloc_align]); to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 0)); let mut flags = AllocKindFlags::Alloc | AllocKindFlags::Aligned; if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) { @@ -456,7 +461,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( to_add.push(llvm::CreateAllocKindAttr(cx.llcx, flags)); // apply to return place instead of function (unlike all other attributes applied in this function) let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]); + apply_attrs(AttributePlace::ReturnValue, &[no_alias]); } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::REALLOCATOR) { to_add.push(create_alloc_family_attr(cx.llcx)); @@ -466,26 +471,28 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( )); // applies to argument place instead of function place let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); + apply_attrs(AttributePlace::Argument(0), &[allocated_pointer]); // apply to argument place instead of function let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::Argument(2), &[alloc_align]); + apply_attrs(AttributePlace::Argument(2), &[alloc_align]); to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 3)); let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]); + apply_attrs(AttributePlace::ReturnValue, &[no_alias]); } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::DEALLOCATOR) { to_add.push(create_alloc_family_attr(cx.llcx)); to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free)); // applies to argument place instead of function place let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); + apply_attrs(AttributePlace::Argument(0), &[allocated_pointer]); } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) { to_add.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry")); } if let Some(align) = codegen_fn_attrs.alignment { - llvm::set_alignment(llfn, align); + if let Some(llfn) = declare_llfn { + llvm::set_alignment(llfn, align); + } } if let Some(backchain) = backchain_attr(cx) { to_add.push(backchain); @@ -503,24 +510,27 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( let function_features = codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::>(); - if let Some(f) = llvm_util::check_tied_features( - cx.tcx.sess, - &function_features.iter().map(|f| (*f, true)).collect(), - ) { - let span = cx - .tcx - .get_attrs(instance.def_id(), sym::target_feature) - .next() - .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span); - cx.tcx - .dcx() - .create_err(TargetFeatureDisableOrEnable { - features: f, - span: Some(span), - missing_features: Some(MissingFeatures), - }) - .emit(); - return; + // HACK: Avoid emitting the lint twice. + if declare_llfn.is_some() { + if let Some(f) = llvm_util::check_tied_features( + cx.tcx.sess, + &function_features.iter().map(|f| (*f, true)).collect(), + ) { + let span = cx + .tcx + .get_attrs(instance.def_id(), sym::target_feature) + .next() + .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span); + cx.tcx + .dcx() + .create_err(TargetFeatureDisableOrEnable { + features: f, + span: Some(span), + missing_features: Some(MissingFeatures), + }) + .emit(); + return; + } } let function_features = function_features @@ -562,7 +572,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features)); } - attributes::apply_to_llfn(llfn, Function, &to_add); + apply_attrs(Function, &to_add); } fn wasm_import_module(tcx: TyCtxt<'_>, id: DefId) -> Option<&String> { diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 40783825cae57..dd3587222a309 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -262,7 +262,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { ) }; if let Some(fn_abi) = fn_abi { - fn_abi.apply_attrs_callsite(self, invoke); + fn_abi.apply_attrs_callsite(self, invoke, instance); } invoke } @@ -1307,7 +1307,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { ) }; if let Some(fn_abi) = fn_abi { - fn_abi.apply_attrs_callsite(self, call); + fn_abi.apply_attrs_callsite(self, call, instance); } call } @@ -1657,7 +1657,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { ) }; if let Some(fn_abi) = fn_abi { - fn_abi.apply_attrs_callsite(self, callbr); + fn_abi.apply_attrs_callsite(self, callbr, instance); } callbr } diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 4e4500b637328..bca1848f5b7fa 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -12,8 +12,9 @@ //! * When in doubt, define. use itertools::Itertools; -use rustc_codegen_ssa::traits::TypeMembershipMethods; +use rustc_codegen_ssa::traits::{BaseTypeMethods, TypeMembershipMethods}; use rustc_data_structures::fx::FxIndexSet; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::{Instance, Ty}; use rustc_sanitizers::{cfi, kcfi}; use smallvec::SmallVec; @@ -127,6 +128,42 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { ) -> &'ll Value { debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi); + // FFI imports need to be treated specially: in Rust one can import the same function + // with different signatures, but LLVM can only import each function once. Within a + // codegen unit, whatever declaration we set up last will "win"; across codegen units, + // LLVM is doing some sort of unspecified merging as part of LTO. + // This is partially unsound due to LLVM bugs (https://github.com/llvm/llvm-project/issues/58976), + // but on the Rust side we try to ensure soundness by making the least amount of promises + // for these imports: no matter the signatures, we declare all functions as `fn()`. + // If the same symbol is declared both as a function and a static, we just hope that + // doesn't lead to unsoundness (or LLVM crashes)... + let is_foreign_item = instance.is_some_and(|i| self.tcx.is_foreign_item(i.def_id())); + // If this is a Rust native allocator function, we want its attributes, so we do not + // treat it like the other FFI imports. If a user declares `__rust_alloc` we're going to have + // one import with the attributes and one with the default signature; that should hopefully be fine + // even if LLVM only sees the default one. + let is_rust_alloc_fn = instance.is_some_and(|i| { + let codegen_fn_flags = self.tcx.codegen_fn_attrs(i.def_id()).flags; + codegen_fn_flags.contains(CodegenFnAttrFlags::ALLOCATOR) + || codegen_fn_flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED) + || codegen_fn_flags.contains(CodegenFnAttrFlags::REALLOCATOR) + || codegen_fn_flags.contains(CodegenFnAttrFlags::DEALLOCATOR) + }); + // If this is calling an LLVM intrinsic, we must set the right signature or LLVM complains. + // These are also unstable to call so nobody but us can screw up their signature. + let is_llvm_builtin = name.starts_with("llvm."); + if is_foreign_item && !is_rust_alloc_fn && !is_llvm_builtin { + return declare_raw_fn( + self, + name, + llvm::CallConv::CCallConv, + llvm::UnnamedAddr::Global, + llvm::Visibility::Default, + // The function type for `fn()`. + self.type_func(&[], self.type_void()), + ); + } + // Function addresses in Rust are never significant, allowing functions to // be merged. let llfn = declare_raw_fn( diff --git a/tests/codegen/aarch64-struct-align-128.rs b/tests/codegen/aarch64-struct-align-128.rs index 3fed19d96b122..49cf093967124 100644 --- a/tests/codegen/aarch64-struct-align-128.rs +++ b/tests/codegen/aarch64-struct-align-128.rs @@ -39,12 +39,17 @@ pub struct Wrapped8 { } extern "C" { - // linux: declare void @test_8([2 x i64], [2 x i64], [2 x i64]) - // darwin: declare void @test_8([2 x i64], [2 x i64], [2 x i64]) - // win: declare void @test_8([2 x i64], [2 x i64], [2 x i64]) fn test_8(a: Align8, b: Transparent8, c: Wrapped8); } +#[no_mangle] +fn call_test_8(a: Align8, b: Transparent8, c: Wrapped8) { + // linux: call void @test_8([2 x i64] {{%.*}}, [2 x i64] {{%.*}}, [2 x i64] {{%.*}}) + // darwin: call void @test_8([2 x i64] {{%.*}}, [2 x i64] {{%.*}}, [2 x i64] {{%.*}}) + // win: call void @test_8([2 x i64] {{%.*}}, [2 x i64] {{%.*}}, [2 x i64] {{%.*}}) + unsafe { test_8(a, b, c) } +} + // Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits. // EXCEPT on Linux, where there's a special case to use its unadjusted alignment, // making it the same as `Align8`, so it's be passed as `[i64 x 2]`. @@ -69,12 +74,17 @@ pub struct Wrapped16 { } extern "C" { - // linux: declare void @test_16([2 x i64], [2 x i64], i128) - // darwin: declare void @test_16(i128, i128, i128) - // win: declare void @test_16(i128, i128, i128) fn test_16(a: Align16, b: Transparent16, c: Wrapped16); } +#[no_mangle] +fn call_test_16(a: Align16, b: Transparent16, c: Wrapped16) { + // linux: call void @test_16([2 x i64] {{%.*}}, [2 x i64] {{%.*}}, i128 {{%.*}}) + // darwin: call void @test_16(i128 {{%.*}}, i128 {{%.*}}, i128 {{%.*}}) + // win: call void @test_16(i128 {{%.*}}, i128 {{%.*}}, i128 {{%.*}}) + unsafe { test_16(a, b, c) } +} + // Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits. #[repr(C)] pub struct I128 { @@ -94,12 +104,17 @@ pub struct WrappedI128 { } extern "C" { - // linux: declare void @test_i128(i128, i128, i128) - // darwin: declare void @test_i128(i128, i128, i128) - // win: declare void @test_i128(i128, i128, i128) fn test_i128(a: I128, b: TransparentI128, c: WrappedI128); } +#[no_mangle] +fn call_test_i128(a: I128, b: TransparentI128, c: WrappedI128) { + // linux: call void @test_i128(i128 {{%.*}}, i128 {{%.*}}, i128 {{%.*}}) + // darwin: call void @test_i128(i128 {{%.*}}, i128 {{%.*}}, i128 {{%.*}}) + // win: call void @test_i128(i128 {{%.*}}, i128 {{%.*}}, i128 {{%.*}}) + unsafe { test_i128(a, b, c) } +} + // Passed as `[2 x i64]`, since it's an aggregate with size <= 128 bits, align < 128 bits. // Note that the Linux special case does not apply, because packing is not considered "adjustment". #[repr(C)] @@ -121,12 +136,17 @@ pub struct WrappedPacked { } extern "C" { - // linux: declare void @test_packed([2 x i64], [2 x i64], [2 x i64]) - // darwin: declare void @test_packed([2 x i64], [2 x i64], [2 x i64]) - // win: declare void @test_packed([2 x i64], [2 x i64], [2 x i64]) fn test_packed(a: Packed, b: TransparentPacked, c: WrappedPacked); } +#[no_mangle] +fn call_test_packed(a: Packed, b: TransparentPacked, c: WrappedPacked) { + // linux: call void @test_packed([2 x i64] {{%.*}}, [2 x i64] {{%.*}}, [2 x i64] {{%.*}}) + // darwin: call void @test_packed([2 x i64] {{%.*}}, [2 x i64] {{%.*}}, [2 x i64] {{%.*}}) + // win: call void @test_packed([2 x i64] {{%.*}}, [2 x i64] {{%.*}}, [2 x i64] {{%.*}}) + unsafe { test_packed(a, b, c) } +} + pub unsafe fn main( a1: Align8, a2: Transparent8, @@ -141,8 +161,8 @@ pub unsafe fn main( d2: TransparentPacked, d3: WrappedPacked, ) { - test_8(a1, a2, a3); - test_16(b1, b2, b3); - test_i128(c1, c2, c3); - test_packed(d1, d2, d3); + call_test_8(a1, a2, a3); + call_test_16(b1, b2, b3); + call_test_i128(c1, c2, c3); + call_test_packed(d1, d2, d3); } diff --git a/tests/codegen/align-byval-vector.rs b/tests/codegen/align-byval-vector.rs index 60d49f9308197..af23862ec6566 100644 --- a/tests/codegen/align-byval-vector.rs +++ b/tests/codegen/align-byval-vector.rs @@ -37,18 +37,18 @@ pub struct DoubleFoo { } extern "C" { - // x86-linux: declare void @f({{.*}}byval([32 x i8]) align 4{{.*}}) - // x86-darwin: declare void @f({{.*}}byval([32 x i8]) align 16{{.*}}) fn f(foo: Foo); - // x86-linux: declare void @g({{.*}}byval([64 x i8]) align 4{{.*}}) - // x86-darwin: declare void @g({{.*}}byval([64 x i8]) align 16{{.*}}) fn g(foo: DoubleFoo); } pub fn main() { + // x86-linux: call void @f({{.*}}byval([32 x i8]) align 4 {{.*}}) + // x86-darwin: call void @f({{.*}}byval([32 x i8]) align 16 {{.*}}) unsafe { f(Foo { a: i32x4([1, 2, 3, 4]), b: 0 }) } + // x86-linux: call void @g({{.*}}byval([64 x i8]) align 4 {{.*}}) + // x86-darwin: call void @g({{.*}}byval([64 x i8]) align 16 {{.*}}) unsafe { g(DoubleFoo { one: Foo { a: i32x4([1, 2, 3, 4]), b: 0 }, diff --git a/tests/codegen/align-byval.rs b/tests/codegen/align-byval.rs index 223696229cb1b..c6d336f6fdc94 100644 --- a/tests/codegen/align-byval.rs +++ b/tests/codegen/align-byval.rs @@ -107,6 +107,10 @@ pub struct ForceAlign16 { // CHECK-LABEL: @call_na1 #[no_mangle] pub unsafe fn call_na1(x: NaturalAlign1) { + extern "C" { + fn natural_align_1(x: NaturalAlign1); + } + // CHECK: start: // m68k: [[ALLOCA:%[a-z0-9+]]] = alloca [2 x i8], align 1 @@ -115,9 +119,9 @@ pub unsafe fn call_na1(x: NaturalAlign1) { // wasm: [[ALLOCA:%[a-z0-9+]]] = alloca [2 x i8], align 1 // wasm: call void @natural_align_1({{.*}}byval([2 x i8]) align 1{{.*}} [[ALLOCA]]) - // x86_64-linux: call void @natural_align_1(i16 + // x86_64-linux: call void @natural_align_1(i16 % - // x86_64-windows: call void @natural_align_1(i16 + // x86_64-windows: call void @natural_align_1(i16 % // i686-linux: [[ALLOCA:%[a-z0-9+]]] = alloca [2 x i8], align 4 // i686-linux: call void @natural_align_1({{.*}}byval([2 x i8]) align 4{{.*}} [[ALLOCA]]) @@ -130,12 +134,19 @@ pub unsafe fn call_na1(x: NaturalAlign1) { // CHECK-LABEL: @call_na2 #[no_mangle] pub unsafe fn call_na2(x: NaturalAlign2) { + extern "C" { + fn natural_align_2(x: NaturalAlign2); + } + // CHECK: start: - // m68k-NEXT: call void @natural_align_2 - // wasm-NEXT: call void @natural_align_2 - // x86_64-linux-NEXT: call void @natural_align_2 + // m68k-NEXT: call void @natural_align_2({{.*}}byval([34 x i8]) align 2{{.*}}) + // wasm-NEXT: call void @natural_align_2({{.*}}byval([34 x i8]) align 2{{.*}}) + // x86_64-linux-NEXT: call void @natural_align_2({{.*}}byval([34 x i8]) align 2{{.*}}) + // x86_64-windows-NEXT: call void @natural_align_2 + // x86_64-windows-NOT: byval + // x86_64-windows-SAME: align 2{{.*}}) // i686-linux: [[ALLOCA:%[0-9]+]] = alloca [34 x i8], align 4 // i686-linux: call void @natural_align_2({{.*}}byval([34 x i8]) align 4{{.*}} [[ALLOCA]]) @@ -148,198 +159,175 @@ pub unsafe fn call_na2(x: NaturalAlign2) { // CHECK-LABEL: @call_fa4 #[no_mangle] pub unsafe fn call_fa4(x: ForceAlign4) { - // CHECK: start: - // CHECK-NEXT: call void @force_align_4 - force_align_4(x); -} + extern "C" { + fn force_align_4(x: ForceAlign4); + } -// CHECK-LABEL: @call_na8 -#[no_mangle] -pub unsafe fn call_na8(x: NaturalAlign8) { // CHECK: start: - // CHECK-NEXT: call void @natural_align_8 - natural_align_8(x); -} - -// CHECK-LABEL: @call_fa8 -#[no_mangle] -pub unsafe fn call_fa8(x: ForceAlign8) { - // CHECK: start: - // CHECK-NEXT: call void @force_align_8 - force_align_8(x); -} - -// CHECK-LABEL: @call_lfa8 -#[no_mangle] -pub unsafe fn call_lfa8(x: LowerFA8) { - // CHECK: start: - // CHECK-NEXT: call void @lower_fa8 - lower_fa8(x); -} - -// CHECK-LABEL: @call_wfa8 -#[no_mangle] -pub unsafe fn call_wfa8(x: WrappedFA8) { - // CHECK: start: - // CHECK-NEXT: call void @wrapped_fa8 - wrapped_fa8(x); -} - -// CHECK-LABEL: @call_tfa8 -#[no_mangle] -pub unsafe fn call_tfa8(x: TransparentFA8) { - // CHECK: start: - // CHECK-NEXT: call void @transparent_fa8 - transparent_fa8(x); -} - -// CHECK-LABEL: @call_fa16 -#[no_mangle] -pub unsafe fn call_fa16(x: ForceAlign16) { - // CHECK: start: - // CHECK-NEXT: call void @force_align_16 - force_align_16(x); -} - -extern "C" { - // m68k: declare void @natural_align_1({{.*}}byval([2 x i8]) align 1{{.*}}) - - // wasm: declare void @natural_align_1({{.*}}byval([2 x i8]) align 1{{.*}}) - - // x86_64-linux: declare void @natural_align_1(i16) - - // x86_64-windows: declare void @natural_align_1(i16) - - // i686-linux: declare void @natural_align_1({{.*}}byval([2 x i8]) align 4{{.*}}) + // m68k-NEXT: call void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}}) - // i686-windows: declare void @natural_align_1({{.*}}byval([2 x i8]) align 4{{.*}}) - fn natural_align_1(x: NaturalAlign1); + // wasm-NEXT: call void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}}) - // m68k: declare void @natural_align_2({{.*}}byval([34 x i8]) align 2{{.*}}) + // x86_64-linux-NEXT: call void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}}) - // wasm: declare void @natural_align_2({{.*}}byval([34 x i8]) align 2{{.*}}) - - // x86_64-linux: declare void @natural_align_2({{.*}}byval([34 x i8]) align 2{{.*}}) - - // x86_64-windows: declare void @natural_align_2( - // x86_64-windows-NOT: byval - // x86_64-windows-SAME: align 2{{.*}}) - - // i686-linux: declare void @natural_align_2({{.*}}byval([34 x i8]) align 4{{.*}}) - - // i686-windows: declare void @natural_align_2({{.*}}byval([34 x i8]) align 4{{.*}}) - fn natural_align_2(x: NaturalAlign2); - - // m68k: declare void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}}) - - // wasm: declare void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}}) - - // x86_64-linux: declare void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}}) - - // x86_64-windows: declare void @force_align_4( + // x86_64-windows-NEXT: call void @force_align_4( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 4{{.*}}) - // i686-linux: declare void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}}) + // i686-linux-NEXT: call void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}}) - // i686-windows: declare void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}}) - fn force_align_4(x: ForceAlign4); + // i686-windows-NEXT: call void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}}) + force_align_4(x); +} - // m68k: declare void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) +// CHECK-LABEL: @call_na8 +#[no_mangle] +pub unsafe fn call_na8(x: NaturalAlign8) { + extern "C" { + fn natural_align_8(x: NaturalAlign8); + } + + // CHECK: start: + // m68k-NEXT: call void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) - // wasm: declare void @natural_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) + // wasm-NEXT: call void @natural_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) - // x86_64-linux: declare void @natural_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) + // x86_64-linux-NEXT: call void @natural_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) - // x86_64-windows: declare void @natural_align_8( + // x86_64-windows-NEXT: call void @natural_align_8( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 8{{.*}}) - // i686-linux: declare void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) + // i686-linux-NEXT: call void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) - // i686-windows: declare void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) - fn natural_align_8(x: NaturalAlign8); + // i686-windows-NEXT: call void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) + natural_align_8(x); +} - // m68k: declare void @force_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) +// CHECK-LABEL: @call_fa8 +#[no_mangle] +pub unsafe fn call_fa8(x: ForceAlign8) { + extern "C" { + fn force_align_8(x: ForceAlign8); + } + + // CHECK: start: + // m68k-NEXT: call void @force_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) - // wasm: declare void @force_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) + // wasm-NEXT: call void @force_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) - // x86_64-linux: declare void @force_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) + // x86_64-linux-NEXT: call void @force_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) - // x86_64-windows: declare void @force_align_8( + // x86_64-windows-NEXT: call void @force_align_8( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 8{{.*}}) - // i686-linux: declare void @force_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) + // i686-linux-NEXT: call void @force_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) - // i686-windows: declare void @force_align_8( + // i686-windows-NEXT: call void @force_align_8( // i686-windows-NOT: byval // i686-windows-SAME: align 8{{.*}}) - fn force_align_8(x: ForceAlign8); + force_align_8(x); +} - // m68k: declare void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) +// CHECK-LABEL: @call_lfa8 +#[no_mangle] +pub unsafe fn call_lfa8(x: LowerFA8) { + extern "C" { + fn lower_fa8(x: LowerFA8); + } + + // CHECK: start: + // m68k-NEXT: call void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) - // wasm: declare void @lower_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) + // wasm-NEXT: call void @lower_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - // x86_64-linux: declare void @lower_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) + // x86_64-linux-NEXT: call void @lower_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - // x86_64-windows: declare void @lower_fa8( + // x86_64-windows-NEXT: call void @lower_fa8( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 8{{.*}}) - // i686-linux: declare void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) + // i686-linux-NEXT: call void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) - // i686-windows: declare void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) - fn lower_fa8(x: LowerFA8); + // i686-windows-NEXT: call void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) + lower_fa8(x); +} - // m68k: declare void @wrapped_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) +// CHECK-LABEL: @call_wfa8 +#[no_mangle] +pub unsafe fn call_wfa8(x: WrappedFA8) { + extern "C" { + fn wrapped_fa8(x: WrappedFA8); + } + + // CHECK: start: + // m68k-NEXT: call void @wrapped_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - // wasm: declare void @wrapped_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) + // wasm-NEXT: call void @wrapped_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - // x86_64-linux: declare void @wrapped_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) + // x86_64-linux-NEXT: call void @wrapped_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - // x86_64-windows: declare void @wrapped_fa8( + // x86_64-windows-NEXT: call void @wrapped_fa8( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 8{{.*}}) - // i686-linux: declare void @wrapped_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) + // i686-linux-NEXT: call void @wrapped_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) - // i686-windows: declare void @wrapped_fa8( + // i686-windows-NEXT: call void @wrapped_fa8( // i686-windows-NOT: byval // i686-windows-SAME: align 8{{.*}}) - fn wrapped_fa8(x: WrappedFA8); + wrapped_fa8(x); +} - // m68k: declare void @transparent_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) +// CHECK-LABEL: @call_tfa8 +#[no_mangle] +pub unsafe fn call_tfa8(x: TransparentFA8) { + extern "C" { + fn transparent_fa8(x: TransparentFA8); + } - // wasm: declare void @transparent_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) + // CHECK: start: + // m68k-NEXT: call void @transparent_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - // x86_64-linux: declare void @transparent_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) + // wasm-NEXT: call void @transparent_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - // x86_64-windows: declare void @transparent_fa8( + // x86_64-linux-NEXT: call void @transparent_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) + + // x86_64-windows-NEXT: call void @transparent_fa8( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 8{{.*}}) - // i686-linux: declare void @transparent_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) + // i686-linux-NEXT: call void @transparent_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) - // i686-windows: declare void @transparent_fa8( + // i686-windows-NEXT: call void @transparent_fa8( // i686-windows-NOT: byval // i686-windows-SAME: align 8{{.*}}) - fn transparent_fa8(x: TransparentFA8); + transparent_fa8(x); +} - // m68k: declare void @force_align_16({{.*}}byval([80 x i8]) align 16{{.*}}) +// CHECK-LABEL: @call_fa16 +#[no_mangle] +pub unsafe fn call_fa16(x: ForceAlign16) { + extern "C" { + fn force_align_16(x: ForceAlign16); + } - // wasm: declare void @force_align_16({{.*}}byval([80 x i8]) align 16{{.*}}) + // CHECK: start: + // m68k-NEXT: call void @force_align_16({{.*}}byval([80 x i8]) align 16{{.*}}) + + // wasm-NEXT: call void @force_align_16({{.*}}byval([80 x i8]) align 16{{.*}}) - // x86_64-linux: declare void @force_align_16({{.*}}byval([80 x i8]) align 16{{.*}}) + // x86_64-linux-NEXT: call void @force_align_16({{.*}}byval([80 x i8]) align 16{{.*}}) - // x86_64-windows: declare void @force_align_16( + // x86_64-windows-NEXT: call void @force_align_16( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 16{{.*}}) - // i686-linux: declare void @force_align_16({{.*}}byval([80 x i8]) align 4{{.*}}) + // i686-linux-NEXT: call void @force_align_16({{.*}}byval([80 x i8]) align 4{{.*}}) - // i686-windows: declare void @force_align_16( + // i686-windows-NEXT: call void @force_align_16( // i686-windows-NOT: byval // i686-windows-SAME: align 16{{.*}}) - fn force_align_16(x: ForceAlign16); + force_align_16(x); } diff --git a/tests/codegen/box-uninit-bytes.rs b/tests/codegen/box-uninit-bytes.rs index 63a6c7b841560..70a2f91ab66d9 100644 --- a/tests/codegen/box-uninit-bytes.rs +++ b/tests/codegen/box-uninit-bytes.rs @@ -8,7 +8,7 @@ use std::mem::MaybeUninit; pub fn box_uninitialized() -> Box> { // CHECK-LABEL: @box_uninitialized // CHECK-NOT: store - // CHECK-NOT: alloca + // CHECK-NOT: alloca{{ }} // CHECK-NOT: memcpy // CHECK-NOT: memset Box::new(MaybeUninit::uninit()) @@ -19,7 +19,7 @@ pub fn box_uninitialized() -> Box> { pub fn box_uninitialized2() -> Box> { // CHECK-LABEL: @box_uninitialized2 // CHECK-NOT: store - // CHECK-NOT: alloca + // CHECK-NOT: alloca{{ }} // CHECK-NOT: memcpy // CHECK-NOT: memset Box::new(MaybeUninit::uninit()) @@ -32,7 +32,7 @@ pub struct LotsaPadding(usize); #[no_mangle] pub fn box_lotsa_padding() -> Box { // CHECK-LABEL: @box_lotsa_padding - // CHECK-NOT: alloca + // CHECK-NOT: alloca{{ }} // CHECK-NOT: getelementptr // CHECK-NOT: memcpy // CHECK-NOT: memset diff --git a/tests/codegen/cffi/ffi-const.rs b/tests/codegen/cffi/ffi-const.rs index 564b8f7f8d8d2..d241642cb2838 100644 --- a/tests/codegen/cffi/ffi-const.rs +++ b/tests/codegen/cffi/ffi-const.rs @@ -2,15 +2,18 @@ #![crate_type = "lib"] #![feature(ffi_const)] +#[no_mangle] pub fn bar() { + // CHECK-LABEL: @bar + // CHECK: @foo + // CHECK-SAME: [[ATTRS:#[0-9]+]] unsafe { foo() } } extern "C" { - // CHECK-LABEL: declare{{.*}}void @foo() - // CHECK-SAME: [[ATTRS:#[0-9]+]] - // The attribute changed from `readnone` to `memory(none)` with LLVM 16.0. - // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}{{readnone|memory\(none\)}}{{.*}} } #[ffi_const] pub fn foo(); } + +// The attribute changed from `readnone` to `memory(none)` with LLVM 16.0. +// CHECK: attributes [[ATTRS]] = { {{.*}}{{readnone|memory\(none\)}}{{.*}} } diff --git a/tests/codegen/cffi/ffi-pure.rs b/tests/codegen/cffi/ffi-pure.rs index 601509d5c90fe..17a39ba2690c2 100644 --- a/tests/codegen/cffi/ffi-pure.rs +++ b/tests/codegen/cffi/ffi-pure.rs @@ -2,15 +2,18 @@ #![crate_type = "lib"] #![feature(ffi_pure)] +#[no_mangle] pub fn bar() { + // CHECK-LABEL: @bar + // CHECK: @foo + // CHECK-SAME: [[ATTRS:#[0-9]+]] unsafe { foo() } } extern "C" { - // CHECK-LABEL: declare{{.*}}void @foo() - // CHECK-SAME: [[ATTRS:#[0-9]+]] - // The attribute changed from `readonly` to `memory(read)` with LLVM 16.0. - // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}{{readonly|memory\(read\)}}{{.*}} } #[ffi_pure] pub fn foo(); } + +// The attribute changed from `readonly` to `memory(read)` with LLVM 16.0. +// CHECK: attributes [[ATTRS]] = { {{.*}}{{readonly|memory\(read\)}}{{.*}} } diff --git a/tests/codegen/issues/issue-111603.rs b/tests/codegen/issues/issue-111603.rs index 41bfb493ff580..ca5b073bea0f8 100644 --- a/tests/codegen/issues/issue-111603.rs +++ b/tests/codegen/issues/issue-111603.rs @@ -12,7 +12,7 @@ pub fn new_from_array(x: u64) -> Arc<[u64]> { // CHECK: alloca // CHECK-SAME: [8000 x i8] - // CHECK-NOT: alloca + // CHECK-NOT: alloca{{ }} let array = [x; 1000]; Arc::new(array) } diff --git a/tests/codegen/iter-repeat-n-trivial-drop.rs b/tests/codegen/iter-repeat-n-trivial-drop.rs index 7de224b92d853..f2abefd9c59ec 100644 --- a/tests/codegen/iter-repeat-n-trivial-drop.rs +++ b/tests/codegen/iter-repeat-n-trivial-drop.rs @@ -47,7 +47,7 @@ pub fn iter_repeat_n_next(it: &mut std::iter::RepeatN) -> Option Vec { - // CHECK: %[[ADDR:.+]] = tail call {{(noalias )?}}noundef dereferenceable_or_null(1234) ptr @__rust_alloc(i64 noundef 1234, i64 noundef 1) + // CHECK: %[[ADDR:.+]] = tail call {{(noalias )?}}noundef dereferenceable_or_null(1234) ptr @__rust_alloc(i64 noundef 1234, i64 {{(allocalign )?}}noundef 1) // CHECK: tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(1234) %[[ADDR]], i8 42, i64 1234, let n = 1234_usize; diff --git a/tests/codegen/no_builtins-at-crate.rs b/tests/codegen/no_builtins-at-crate.rs index ba1d31f60c390..234fb8e99842e 100644 --- a/tests/codegen/no_builtins-at-crate.rs +++ b/tests/codegen/no_builtins-at-crate.rs @@ -10,15 +10,13 @@ pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, size: usize) { // CHECK: call // CHECK-SAME: @memcpy( + // CHECK-SAME: #2 memcpy(dest, src, size); } -// CHECK: declare -// CHECK-SAME: @memcpy -// CHECK-SAME: #0 extern "C" { pub fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; } -// CHECK: attributes #0 +// CHECK: attributes #2 // CHECK-SAME: "no-builtins" diff --git a/tests/codegen/pic-relocation-model.rs b/tests/codegen/pic-relocation-model.rs index a1d1678a6bda5..54fbc2092d1c6 100644 --- a/tests/codegen/pic-relocation-model.rs +++ b/tests/codegen/pic-relocation-model.rs @@ -8,10 +8,7 @@ pub fn call_foreign_fn() -> u8 { unsafe { foreign_fn() } } -// (Allow but do not require `zeroext` here, because it is not worth effort to -// spell out which targets have it and which ones do not; see rust#97800.) - -// CHECK: declare{{( zeroext)?}} i8 @foreign_fn() +// CHECK: declare void @foreign_fn() extern "C" { fn foreign_fn() -> u8; } diff --git a/tests/codegen/pie-relocation-model.rs b/tests/codegen/pie-relocation-model.rs index b10af69345228..a678b4baa08df 100644 --- a/tests/codegen/pie-relocation-model.rs +++ b/tests/codegen/pie-relocation-model.rs @@ -13,7 +13,7 @@ pub fn call_foreign_fn() -> u8 { // External functions are still marked as non-dso_local, since we don't know if the symbol // is defined in the binary or in the shared library. -// CHECK: declare zeroext i8 @foreign_fn() +// CHECK: declare void @foreign_fn() extern "C" { fn foreign_fn() -> u8; } diff --git a/tests/codegen/powerpc64le-struct-align-128.rs b/tests/codegen/powerpc64le-struct-align-128.rs index 3981cd1212961..555fb9596b40d 100644 --- a/tests/codegen/powerpc64le-struct-align-128.rs +++ b/tests/codegen/powerpc64le-struct-align-128.rs @@ -32,10 +32,15 @@ pub struct Wrapped8 { } extern "C" { - // CHECK: declare void @test_8([2 x i64], [2 x i64], [2 x i64]) fn test_8(a: Align8, b: Transparent8, c: Wrapped8); } +#[no_mangle] +fn call_test_8(a: Align8, b: Transparent8, c: Wrapped8) { + // CHECK: call void @test_8([2 x i64] {{%.*}}, [2 x i64] {{%.*}}, [2 x i64] {{%.*}}) + unsafe { test_8(a, b, c) } +} + #[repr(C)] #[repr(align(16))] pub struct Align16 { @@ -54,11 +59,16 @@ pub struct Wrapped16 { } extern "C" { - // It's important that this produces [1 x i128] rather than just i128! - // CHECK: declare void @test_16([1 x i128], [1 x i128], [1 x i128]) fn test_16(a: Align16, b: Transparent16, c: Wrapped16); } +#[no_mangle] +fn call_test_16(a: Align16, b: Transparent16, c: Wrapped16) { + // It's important that this produces [1 x i128] rather than just i128! + // CHECK: call void @test_16([1 x i128] {{%.*}}, [1 x i128] {{%.*}}, [1 x i128] {{%.*}}) + unsafe { test_16(a, b, c) } +} + #[repr(C)] #[repr(align(32))] pub struct Align32 { @@ -78,10 +88,15 @@ pub struct Wrapped32 { } extern "C" { - // CHECK: declare void @test_32([2 x i128], [2 x i128], [2 x i128]) fn test_32(a: Align32, b: Transparent32, c: Wrapped32); } +#[no_mangle] +fn call_test_32(a: Align32, b: Transparent32, c: Wrapped32) { + // CHECK: call void @test_32([2 x i128] {{%.*}}, [2 x i128] {{%.*}}, [2 x i128] {{%.*}}) + unsafe { test_32(a, b, c) } +} + pub unsafe fn main( a1: Align8, a2: Transparent8, @@ -93,7 +108,7 @@ pub unsafe fn main( c2: Transparent32, c3: Wrapped32, ) { - test_8(a1, a2, a3); - test_16(b1, b2, b3); - test_32(c1, c2, c3); + call_test_8(a1, a2, a3); + call_test_16(b1, b2, b3); + call_test_32(c1, c2, c3); } diff --git a/tests/codegen/unwind-extern-imports.rs b/tests/codegen/unwind-extern-imports.rs index dfae8aae64a51..0dbddfa4061c2 100644 --- a/tests/codegen/unwind-extern-imports.rs +++ b/tests/codegen/unwind-extern-imports.rs @@ -3,9 +3,20 @@ #![crate_type = "lib"] +// The flag are only at the call sites, not at the declarations. +// CHECK-LABEL: @force_declare +#[no_mangle] +pub unsafe fn force_declare() { + // CHECK: call void @extern_fn() [[NOUNWIND_ATTR:#[0-9]+]] + extern_fn(); + // Call without attributes. + // CHECK: call void @c_unwind_extern_fn() [[UNWIND_ATTR:#[0-9]+]] + c_unwind_extern_fn(); +} + extern "C" { - // CHECK: Function Attrs:{{.*}}nounwind - // CHECK-NEXT: declare{{.*}}void @extern_fn + // CHECK-NOT: nounwind + // CHECK: declare{{.*}}void @extern_fn fn extern_fn(); } @@ -15,7 +26,6 @@ extern "C-unwind" { fn c_unwind_extern_fn(); } -pub unsafe fn force_declare() { - extern_fn(); - c_unwind_extern_fn(); -} +// CHECK: attributes [[NOUNWIND_ATTR]] = { {{.*}}nounwind{{.*}} } +// CHECK: attributes [[UNWIND_ATTR]] +// CHECK-NOT: nounwind diff --git a/tests/codegen/unwind-landingpad-cold.rs b/tests/codegen/unwind-landingpad-cold.rs index fa200bc300cf9..9d9b1bf07566a 100644 --- a/tests/codegen/unwind-landingpad-cold.rs +++ b/tests/codegen/unwind-landingpad-cold.rs @@ -8,7 +8,8 @@ // CHECK-LABEL: @check_cold // CHECK: {{(call|invoke) void .+}}drop_in_place{{.+}} [[ATTRIBUTES:#[0-9]+]] -// CHECK: attributes [[ATTRIBUTES]] = { cold } +// CHECK: attributes [[ATTRIBUTES]] +// CHECK-SAME: cold #[no_mangle] pub fn check_cold(f: fn(), x: Box) { // this may unwind diff --git a/tests/ui/feature-gates/feature-gate-link_llvm_intrinsics.rs b/tests/ui/feature-gates/feature-gate-link_llvm_intrinsics.rs index 7391ea94ebc04..30dba599a95a2 100644 --- a/tests/ui/feature-gates/feature-gate-link_llvm_intrinsics.rs +++ b/tests/ui/feature-gates/feature-gate-link_llvm_intrinsics.rs @@ -1,7 +1,7 @@ extern "C" { #[link_name = "llvm.sqrt.f32"] fn sqrt(x: f32) -> f32; -//~^ ERROR linking to LLVM intrinsics is experimental +//~^ ERROR linking to LLVM intrinsics } fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-link_llvm_intrinsics.stderr b/tests/ui/feature-gates/feature-gate-link_llvm_intrinsics.stderr index 686007dcbb7ea..106b93f770e63 100644 --- a/tests/ui/feature-gates/feature-gate-link_llvm_intrinsics.stderr +++ b/tests/ui/feature-gates/feature-gate-link_llvm_intrinsics.stderr @@ -1,4 +1,4 @@ -error[E0658]: linking to LLVM intrinsics is experimental +error[E0658]: linking to LLVM intrinsics is an internal feature reserved for the standard library --> $DIR/feature-gate-link_llvm_intrinsics.rs:3:5 | LL | fn sqrt(x: f32) -> f32; diff --git a/tests/ui/issues/issue-20313.rs b/tests/ui/issues/issue-20313.rs index a72af650c7071..e51d3935bf55f 100644 --- a/tests/ui/issues/issue-20313.rs +++ b/tests/ui/issues/issue-20313.rs @@ -1,6 +1,6 @@ extern "C" { #[link_name = "llvm.sqrt.f32"] - fn sqrt(x: f32) -> f32; //~ ERROR linking to LLVM intrinsics is experimental + fn sqrt(x: f32) -> f32; //~ ERROR linking to LLVM intrinsics } fn main() {} diff --git a/tests/ui/issues/issue-20313.stderr b/tests/ui/issues/issue-20313.stderr index a61495440f0fa..4d963efec055f 100644 --- a/tests/ui/issues/issue-20313.stderr +++ b/tests/ui/issues/issue-20313.stderr @@ -1,4 +1,4 @@ -error[E0658]: linking to LLVM intrinsics is experimental +error[E0658]: linking to LLVM intrinsics is an internal feature reserved for the standard library --> $DIR/issue-20313.rs:3:5 | LL | fn sqrt(x: f32) -> f32; From dfcd0db85ec9dfeeca65e0095922454de99c4997 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Sep 2024 07:38:53 +0200 Subject: [PATCH 2/3] do not set the attributes quite as often --- compiler/rustc_codegen_llvm/src/abi.rs | 7 ++++++- tests/codegen/cffi/ffi-out-of-bounds-loads.rs | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 60d40fd7b8eb1..cc2b3e8e58025 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -663,7 +663,12 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } // If the call site has an associated instance, compute extra attributes based on that. - if let Some(instance) = instance { + // However, only do that for calls to imported functions: all the others have these + // attributes applied already to the declaration, so we can save some work by not also + // applying them here (and this really shows in perf). + if let Some(instance) = instance + && bx.tcx.is_foreign_item(instance.def_id()) + { llfn_attrs_from_instance(bx.cx, instance, None, |place, attrs| { attributes::apply_to_callsite(callsite, place, attrs) }); diff --git a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs index ae8d8383f5b91..338ef325f2099 100644 --- a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs +++ b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs @@ -1,6 +1,6 @@ //@ revisions: linux apple //@ min-llvm-version: 19 -//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes -Zlint-llvm-ir -Cllvm-args=-lint-abort-on-error +//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes -Zlint-llvm-ir //@[linux] compile-flags: --target x86_64-unknown-linux-gnu //@[linux] needs-llvm-components: x86 From a78c911ecf11ae34715989bce30461e396e035b9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 10 Sep 2024 15:18:46 +0200 Subject: [PATCH 3/3] add foreign-vectorcall test --- tests/ui/extern/auxiliary/foreign-vectorcall.rs | 10 ++++++++++ tests/ui/extern/extern-vectorcall.rs | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/ui/extern/auxiliary/foreign-vectorcall.rs diff --git a/tests/ui/extern/auxiliary/foreign-vectorcall.rs b/tests/ui/extern/auxiliary/foreign-vectorcall.rs new file mode 100644 index 0000000000000..834678fc88dc0 --- /dev/null +++ b/tests/ui/extern/auxiliary/foreign-vectorcall.rs @@ -0,0 +1,10 @@ +// Make the aux build not use `dylib` to avoid https://github.com/rust-lang/rust/issues/130196 +//@ no-prefer-dynamic +#![feature(abi_vectorcall)] +#![crate_type = "lib"] + +#[no_mangle] +#[inline(never)] +pub extern "vectorcall" fn call_with_42(i: i32) { + assert_eq!(i, 42); +} diff --git a/tests/ui/extern/extern-vectorcall.rs b/tests/ui/extern/extern-vectorcall.rs index c0d872bc14beb..2cd7c70a31e87 100644 --- a/tests/ui/extern/extern-vectorcall.rs +++ b/tests/ui/extern/extern-vectorcall.rs @@ -1,10 +1,19 @@ //@ run-pass +//@ aux-build:foreign-vectorcall.rs //@ revisions: x64 x32 //@ [x64]only-x86_64 //@ [x32]only-x86 #![feature(abi_vectorcall)] +extern crate foreign_vectorcall; + +// Import this as a foreign function, that's the code path we are interested in +// (LLVM has to do some name mangling here). +extern "vectorcall" { + fn call_with_42(i: i32); +} + trait A { extern "vectorcall" fn test1(i: i32); } @@ -24,4 +33,5 @@ extern "vectorcall" fn test2(i: i32) { fn main() { ::test1(1); test2(2); + unsafe { call_with_42(42) }; }