From 7ca9f9363dbb42a845ea70dfb449253f08c83ce1 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Tue, 1 Jul 2025 09:17:29 +0200 Subject: tests/codegen/enum/enum-match.rs: accept negative range attribute --- tests/codegen/enum/enum-match.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/codegen') diff --git a/tests/codegen/enum/enum-match.rs b/tests/codegen/enum/enum-match.rs index 6da6ad1f078..98635008d06 100644 --- a/tests/codegen/enum/enum-match.rs +++ b/tests/codegen/enum/enum-match.rs @@ -98,7 +98,7 @@ pub enum Enum2 { E, } -// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match2(i8{{.+}}%0) +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, -?[0-9]+\))?}} i8 @match2(i8{{.+}}%0) // CHECK-NEXT: start: // CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %0, 2 // CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 -- cgit 1.4.1-3-g733a5 From 8cf2c71243f8c093e7728370e6653aa940dbaf22 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 4 Jul 2025 23:16:41 -0700 Subject: Let `rvalue_creates_operand` return true for *all* `Rvalue::Aggregate`s Inspired by where I noticed that we were nearly at this point, plus the comments I was writing in 143410 that reminded me a type-dependent `true` is fine. This PR splits the `OperandRef::builder` logic out to a separate type, with the updates needed to handle SIMD as well. In doing so, that makes the existing `Aggregate` path in `codegen_rvalue_operand` capable of handing SIMD values just fine. As a result, we no longer need to do layout calculations for aggregate result types when running the analysis to determine which things can be SSA in codegen. --- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 3 +- compiler/rustc_codegen_ssa/src/mir/operand.rs | 175 +++++++++++++++++--------- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 25 ++-- tests/codegen/enum/enum-aggregate.rs | 15 +-- tests/codegen/simd/aggregate-simd.rs | 106 ++++++++++++++++ tests/codegen/union-aggregate.rs | 23 ++++ 6 files changed, 261 insertions(+), 86 deletions(-) create mode 100644 tests/codegen/simd/aggregate-simd.rs (limited to 'tests/codegen') diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 99f35b79208..6d6465dd798 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -171,8 +171,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> Visitor<'tcx> for LocalAnalyzer if let Some(local) = place.as_local() { self.define(local, DefLocation::Assignment(location)); if self.locals[local] != LocalKind::Memory { - let decl_span = self.fx.mir.local_decls[local].source_info.span; - if !self.fx.rvalue_creates_operand(rvalue, decl_span) { + if !self.fx.rvalue_creates_operand(rvalue) { self.locals[local] = LocalKind::Memory; } } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 2896dfd5463..e5b95e5ecc5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -565,118 +565,167 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } } } +} - /// Creates an incomplete operand containing the [`abi::Scalar`]s expected based - /// on the `layout` passed. This is for use with [`OperandRef::insert_field`] - /// later to set the necessary immediate(s), one-by-one converting all the `Right` to `Left`. - /// - /// Returns `None` for `layout`s which cannot be built this way. - pub(crate) fn builder( - layout: TyAndLayout<'tcx>, - ) -> Option>> { - // Uninhabited types are weird, because for example `Result` - // shows up as `FieldsShape::Primitive` and we need to be able to write - // a field into `(u32, !)`. We'll do that in an `alloca` instead. - if layout.uninhabited { - return None; - } +/// Each of these variants starts out as `Either::Right` when it's uninitialized, +/// then setting the field changes that to `Either::Left` with the backend value. +#[derive(Debug, Copy, Clone)] +enum OperandValueBuilder { + ZeroSized, + Immediate(Either), + Pair(Either, Either), + /// `repr(simd)` types need special handling because they each have a non-empty + /// array field (which uses [`OperandValue::Ref`]) despite the SIMD type itself + /// using [`OperandValue::Immediate`] which for any other kind of type would + /// mean that its one non-ZST field would also be [`OperandValue::Immediate`]. + Vector(Either), +} + +/// Allows building up an `OperandRef` by setting fields one at a time. +#[derive(Debug, Copy, Clone)] +pub(super) struct OperandRefBuilder<'tcx, V> { + val: OperandValueBuilder, + layout: TyAndLayout<'tcx>, +} +impl<'a, 'tcx, V: CodegenObject> OperandRefBuilder<'tcx, V> { + /// Creates an uninitialized builder for an instance of the `layout`. + /// + /// ICEs for [`BackendRepr::Memory`] types (other than ZSTs), which should + /// be built up inside a [`PlaceRef`] instead as they need an allocated place + /// into which to write the values of the fields. + pub(super) fn new(layout: TyAndLayout<'tcx>) -> Self { let val = match layout.backend_repr { - BackendRepr::Memory { .. } if layout.is_zst() => OperandValue::ZeroSized, - BackendRepr::Scalar(s) => OperandValue::Immediate(Either::Right(s)), - BackendRepr::ScalarPair(a, b) => OperandValue::Pair(Either::Right(a), Either::Right(b)), - BackendRepr::Memory { .. } | BackendRepr::SimdVector { .. } => return None, + BackendRepr::Memory { .. } if layout.is_zst() => OperandValueBuilder::ZeroSized, + BackendRepr::Scalar(s) => OperandValueBuilder::Immediate(Either::Right(s)), + BackendRepr::ScalarPair(a, b) => { + OperandValueBuilder::Pair(Either::Right(a), Either::Right(b)) + } + BackendRepr::SimdVector { .. } => OperandValueBuilder::Vector(Either::Right(())), + BackendRepr::Memory { .. } => { + bug!("Cannot use non-ZST Memory-ABI type in operand builder: {layout:?}"); + } }; - Some(OperandRef { val, layout }) + OperandRefBuilder { val, layout } } -} -impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Either> { - pub(crate) fn insert_field>( + pub(super) fn insert_field>( &mut self, bx: &mut Bx, - v: VariantIdx, - f: FieldIdx, - operand: OperandRef<'tcx, V>, + variant: VariantIdx, + field: FieldIdx, + field_operand: OperandRef<'tcx, V>, ) { - let (expect_zst, is_zero_offset) = if let abi::FieldsShape::Primitive = self.layout.fields { + if let OperandValue::ZeroSized = field_operand.val { + // A ZST never adds any state, so just ignore it. + // This special-casing is worth it because of things like + // `Result` where `Ok(never)` is legal to write, + // but the type shows as FieldShape::Primitive so we can't + // actually look at the layout for the field being set. + return; + } + + let is_zero_offset = if let abi::FieldsShape::Primitive = self.layout.fields { // The other branch looking at field layouts ICEs for primitives, // so we need to handle them separately. - // Multiple fields is possible for cases such as aggregating - // a thin pointer, where the second field is the unit. + // Because we handled ZSTs above (like the metadata in a thin pointer), + // the only possibility is that we're setting the one-and-only field. assert!(!self.layout.is_zst()); - assert_eq!(v, FIRST_VARIANT); - let first_field = f == FieldIdx::ZERO; - (!first_field, first_field) + assert_eq!(variant, FIRST_VARIANT); + assert_eq!(field, FieldIdx::ZERO); + true } else { - let variant_layout = self.layout.for_variant(bx.cx(), v); - let field_layout = variant_layout.field(bx.cx(), f.as_usize()); - let field_offset = variant_layout.fields.offset(f.as_usize()); - (field_layout.is_zst(), field_offset == Size::ZERO) + let variant_layout = self.layout.for_variant(bx.cx(), variant); + let field_offset = variant_layout.fields.offset(field.as_usize()); + field_offset == Size::ZERO }; let mut update = |tgt: &mut Either, src, from_scalar| { let to_scalar = tgt.unwrap_right(); + // We transmute here (rather than just `from_immediate`) because in + // `Result` the field of the `Ok` is an integer, + // but the corresponding scalar in the enum is a pointer. let imm = transmute_scalar(bx, src, from_scalar, to_scalar); *tgt = Either::Left(imm); }; - match (operand.val, operand.layout.backend_repr) { - (OperandValue::ZeroSized, _) if expect_zst => {} + match (field_operand.val, field_operand.layout.backend_repr) { + (OperandValue::ZeroSized, _) => unreachable!("Handled above"), (OperandValue::Immediate(v), BackendRepr::Scalar(from_scalar)) => match &mut self.val { - OperandValue::Immediate(val @ Either::Right(_)) if is_zero_offset => { + OperandValueBuilder::Immediate(val @ Either::Right(_)) if is_zero_offset => { update(val, v, from_scalar); } - OperandValue::Pair(fst @ Either::Right(_), _) if is_zero_offset => { + OperandValueBuilder::Pair(fst @ Either::Right(_), _) if is_zero_offset => { update(fst, v, from_scalar); } - OperandValue::Pair(_, snd @ Either::Right(_)) if !is_zero_offset => { + OperandValueBuilder::Pair(_, snd @ Either::Right(_)) if !is_zero_offset => { update(snd, v, from_scalar); } - _ => bug!("Tried to insert {operand:?} into {v:?}.{f:?} of {self:?}"), + _ => { + bug!("Tried to insert {field_operand:?} into {variant:?}.{field:?} of {self:?}") + } + }, + (OperandValue::Immediate(v), BackendRepr::SimdVector { .. }) => match &mut self.val { + OperandValueBuilder::Vector(val @ Either::Right(())) if is_zero_offset => { + *val = Either::Left(v); + } + _ => { + bug!("Tried to insert {field_operand:?} into {variant:?}.{field:?} of {self:?}") + } }, (OperandValue::Pair(a, b), BackendRepr::ScalarPair(from_sa, from_sb)) => { match &mut self.val { - OperandValue::Pair(fst @ Either::Right(_), snd @ Either::Right(_)) => { + OperandValueBuilder::Pair(fst @ Either::Right(_), snd @ Either::Right(_)) => { update(fst, a, from_sa); update(snd, b, from_sb); } - _ => bug!("Tried to insert {operand:?} into {v:?}.{f:?} of {self:?}"), + _ => bug!( + "Tried to insert {field_operand:?} into {variant:?}.{field:?} of {self:?}" + ), } } - _ => bug!("Unsupported operand {operand:?} inserting into {v:?}.{f:?} of {self:?}"), + (OperandValue::Ref(place), BackendRepr::Memory { .. }) => match &mut self.val { + OperandValueBuilder::Vector(val @ Either::Right(())) => { + let ibty = bx.cx().immediate_backend_type(self.layout); + let simd = bx.load_from_place(ibty, place); + *val = Either::Left(simd); + } + _ => { + bug!("Tried to insert {field_operand:?} into {variant:?}.{field:?} of {self:?}") + } + }, + _ => bug!("Operand cannot be used with `insert_field`: {field_operand:?}"), } } /// Insert the immediate value `imm` for field `f` in the *type itself*, /// rather than into one of the variants. /// - /// Most things want [`OperandRef::insert_field`] instead, but this one is + /// Most things want [`Self::insert_field`] instead, but this one is /// necessary for writing things like enum tags that aren't in any variant. pub(super) fn insert_imm(&mut self, f: FieldIdx, imm: V) { let field_offset = self.layout.fields.offset(f.as_usize()); let is_zero_offset = field_offset == Size::ZERO; match &mut self.val { - OperandValue::Immediate(val @ Either::Right(_)) if is_zero_offset => { + OperandValueBuilder::Immediate(val @ Either::Right(_)) if is_zero_offset => { *val = Either::Left(imm); } - OperandValue::Pair(fst @ Either::Right(_), _) if is_zero_offset => { + OperandValueBuilder::Pair(fst @ Either::Right(_), _) if is_zero_offset => { *fst = Either::Left(imm); } - OperandValue::Pair(_, snd @ Either::Right(_)) if !is_zero_offset => { + OperandValueBuilder::Pair(_, snd @ Either::Right(_)) if !is_zero_offset => { *snd = Either::Left(imm); } _ => bug!("Tried to insert {imm:?} into field {f:?} of {self:?}"), } } - /// After having set all necessary fields, this converts the - /// `OperandValue>` (as obtained from [`OperandRef::builder`]) - /// to the normal `OperandValue`. + /// After having set all necessary fields, this converts the builder back + /// to the normal `OperandRef`. /// /// ICEs if any required fields were not set. - pub fn build(&self, cx: &impl CodegenMethods<'tcx, Value = V>) -> OperandRef<'tcx, V> { - let OperandRef { val, layout } = *self; + pub(super) fn build(&self, cx: &impl CodegenMethods<'tcx, Value = V>) -> OperandRef<'tcx, V> { + let OperandRefBuilder { val, layout } = *self; // For something like `Option::::None`, it's expected that the // payload scalar will not actually have been set, so this converts @@ -692,10 +741,22 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Either> { }; let val = match val { - OperandValue::ZeroSized => OperandValue::ZeroSized, - OperandValue::Immediate(v) => OperandValue::Immediate(unwrap(v)), - OperandValue::Pair(a, b) => OperandValue::Pair(unwrap(a), unwrap(b)), - OperandValue::Ref(_) => bug!(), + OperandValueBuilder::ZeroSized => OperandValue::ZeroSized, + OperandValueBuilder::Immediate(v) => OperandValue::Immediate(unwrap(v)), + OperandValueBuilder::Pair(a, b) => OperandValue::Pair(unwrap(a), unwrap(b)), + OperandValueBuilder::Vector(v) => match v { + Either::Left(v) => OperandValue::Immediate(v), + Either::Right(()) + if let BackendRepr::SimdVector { element, .. } = layout.backend_repr + && element.is_uninit_valid() => + { + let bty = cx.immediate_backend_type(layout); + OperandValue::Immediate(cx.const_undef(bty)) + } + Either::Right(()) => { + bug!("OperandRef::build called while fields are missing {self:?}") + } + }, }; OperandRef { val, layout } } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 43726e93252..2a7efdfe8bb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -4,10 +4,9 @@ use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_session::config::OptLevel; -use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; -use super::operand::{OperandRef, OperandValue}; +use super::operand::{OperandRef, OperandRefBuilder, OperandValue}; use super::place::{PlaceRef, codegen_tag_value}; use super::{FunctionCx, LocalRef}; use crate::common::{IntPredicate, TypeKind}; @@ -181,7 +180,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } _ => { - assert!(self.rvalue_creates_operand(rvalue, DUMMY_SP)); + assert!(self.rvalue_creates_operand(rvalue)); let temp = self.codegen_rvalue_operand(bx, rvalue); temp.val.store(bx, dest); } @@ -354,10 +353,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx: &mut Bx, rvalue: &mir::Rvalue<'tcx>, ) -> OperandRef<'tcx, Bx::Value> { - assert!( - self.rvalue_creates_operand(rvalue, DUMMY_SP), - "cannot codegen {rvalue:?} to operand", - ); + assert!(self.rvalue_creates_operand(rvalue), "cannot codegen {rvalue:?} to operand",); match *rvalue { mir::Rvalue::Cast(ref kind, ref source, mir_cast_ty) => { @@ -668,9 +664,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // `rvalue_creates_operand` has arranged that we only get here if // we can build the aggregate immediate from the field immediates. - let Some(mut builder) = OperandRef::builder(layout) else { - bug!("Cannot use type in operand builder: {layout:?}") - }; + let mut builder = OperandRefBuilder::new(layout); for (field_idx, field) in fields.iter_enumerated() { let op = self.codegen_operand(bx, field); let fi = active_field_index.unwrap_or(field_idx); @@ -980,7 +974,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// will not actually take the operand path because the result type is such /// that it always gets an `alloca`, but where it's not worth re-checking the /// layout in this code when the right thing will happen anyway. - pub(crate) fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool { + pub(crate) fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>) -> bool { match *rvalue { mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, cast_ty) => { let operand_ty = operand.ty(self.mir, self.cx.tcx()); @@ -1025,18 +1019,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::NullaryOp(..) | mir::Rvalue::ThreadLocalRef(_) | mir::Rvalue::Use(..) | + mir::Rvalue::Aggregate(..) | // (*) mir::Rvalue::WrapUnsafeBinder(..) => // (*) true, // Arrays are always aggregates, so it's not worth checking anything here. // (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.) mir::Rvalue::Repeat(..) => false, - mir::Rvalue::Aggregate(..) => { - let ty = rvalue.ty(self.mir, self.cx.tcx()); - let ty = self.monomorphize(ty); - let layout = self.cx.spanned_layout_of(ty, span); - OperandRef::::builder(layout).is_some() - } - } + } // (*) this is only true if the type is suitable } diff --git a/tests/codegen/enum/enum-aggregate.rs b/tests/codegen/enum/enum-aggregate.rs index b6a9b8dd814..0161e5f3fa1 100644 --- a/tests/codegen/enum/enum-aggregate.rs +++ b/tests/codegen/enum/enum-aggregate.rs @@ -112,17 +112,14 @@ fn make_uninhabited_err_indirectly(n: Never) -> Result { #[no_mangle] fn make_fully_uninhabited_result(v: u32, n: Never) -> Result<(u32, Never), (Never, u32)> { - // We don't try to do this in SSA form since the whole type is uninhabited. + // Actually reaching this would be UB, so we don't actually build a result. // CHECK-LABEL: { i32, i32 } @make_fully_uninhabited_result(i32 %v) - // CHECK: %[[ALLOC_V:.+]] = alloca [4 x i8] - // CHECK: %[[RET:.+]] = alloca [8 x i8] - // CHECK: store i32 %v, ptr %[[ALLOC_V]] - // CHECK: %[[TEMP_V:.+]] = load i32, ptr %[[ALLOC_V]] - // CHECK: %[[INNER:.+]] = getelementptr inbounds i8, ptr %[[RET]] - // CHECK: store i32 %[[TEMP_V]], ptr %[[INNER]] - // CHECK: call void @llvm.trap() - // CHECK: unreachable + // CHECK-NEXT: start: + // CHECK-NEXT: call void @llvm.trap() + // CHECK-NEXT: call void @llvm.trap() + // CHECK-NEXT: call void @llvm.trap() + // CHECK-NEXT: unreachable Ok((v, n)) } diff --git a/tests/codegen/simd/aggregate-simd.rs b/tests/codegen/simd/aggregate-simd.rs new file mode 100644 index 00000000000..065e429a4c7 --- /dev/null +++ b/tests/codegen/simd/aggregate-simd.rs @@ -0,0 +1,106 @@ +//@ compile-flags: -C opt-level=3 -C no-prepopulate-passes +//@ only-64bit + +#![feature(core_intrinsics, repr_simd)] +#![no_std] +#![crate_type = "lib"] + +use core::intrinsics::simd::{simd_add, simd_extract}; + +#[repr(simd)] +#[derive(Clone, Copy)] +pub struct Simd([T; N]); + +#[repr(simd, packed)] +#[derive(Clone, Copy)] +pub struct PackedSimd([T; N]); + +#[repr(transparent)] +pub struct Transparent(T); + +// These tests don't actually care about the add/extract, but it ensures the +// aggregated temporaries are only used in potentially-SSA ways. + +#[no_mangle] +pub fn simd_aggregate_pot(x: [u32; 4], y: [u32; 4]) -> u32 { + // CHECK-LABEL: simd_aggregate_pot + // CHECK: %a = load <4 x i32>, ptr %x, align 4 + // CHECK: %b = load <4 x i32>, ptr %y, align 4 + // CHECK: add <4 x i32> %a, %b + + unsafe { + let a = Simd(x); + let b = Simd(y); + let c = simd_add(a, b); + simd_extract(c, 1) + } +} + +#[no_mangle] +pub fn simd_aggregate_npot(x: [u32; 7], y: [u32; 7]) -> u32 { + // CHECK-LABEL: simd_aggregate_npot + // CHECK: %a = load <7 x i32>, ptr %x, align 4 + // CHECK: %b = load <7 x i32>, ptr %y, align 4 + // CHECK: add <7 x i32> %a, %b + + unsafe { + let a = Simd(x); + let b = Simd(y); + let c = simd_add(a, b); + simd_extract(c, 1) + } +} + +#[no_mangle] +pub fn packed_simd_aggregate_pot(x: [u32; 4], y: [u32; 4]) -> u32 { + // CHECK-LABEL: packed_simd_aggregate_pot + // CHECK: %a = load <4 x i32>, ptr %x, align 4 + // CHECK: %b = load <4 x i32>, ptr %y, align 4 + // CHECK: add <4 x i32> %a, %b + + unsafe { + let a = PackedSimd(x); + let b = PackedSimd(y); + let c = simd_add(a, b); + simd_extract(c, 1) + } +} + +#[no_mangle] +pub fn packed_simd_aggregate_npot(x: [u32; 7], y: [u32; 7]) -> u32 { + // CHECK-LABEL: packed_simd_aggregate_npot + // CHECK: %b = alloca [28 x i8], align 4 + // CHECK: %a = alloca [28 x i8], align 4 + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a, ptr align 4 %x, i64 28, i1 false) + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %b, ptr align 4 %y, i64 28, i1 false) + // CHECK: %[[TEMPA:.+]] = load <7 x i32>, ptr %a, align 4 + // CHECK: %[[TEMPB:.+]] = load <7 x i32>, ptr %b, align 4 + // CHECK: add <7 x i32> %[[TEMPA]], %[[TEMPB]] + + unsafe { + let a = PackedSimd(x); + let b = PackedSimd(y); + let c = simd_add(a, b); + simd_extract(c, 1) + } +} + +#[no_mangle] +pub fn transparent_simd_aggregate(x: [u32; 4]) -> u32 { + // The transparent wrapper can just use the same SSA value as its field. + // No extra processing or spilling needed. + + // CHECK-LABEL: transparent_simd_aggregate + // CHECK-NOT: alloca + // CHECK: %[[RET:.+]] = alloca [4 x i8] + // CHECK-NOT: alloca + // CHECK: %a = load <4 x i32>, ptr %x, align 4 + // CHECK: %[[TEMP:.+]] = extractelement <4 x i32> %a, i32 1 + // CHECK: store i32 %[[TEMP]], ptr %[[RET]] + + unsafe { + let a = Simd(x); + let b = Transparent(a); + simd_extract(b.0, 1) + } +} diff --git a/tests/codegen/union-aggregate.rs b/tests/codegen/union-aggregate.rs index 3c6053379fa..aac66c5dcdd 100644 --- a/tests/codegen/union-aggregate.rs +++ b/tests/codegen/union-aggregate.rs @@ -4,6 +4,7 @@ #![crate_type = "lib"] #![feature(transparent_unions)] +#![feature(repr_simd)] #[repr(transparent)] union MU { @@ -83,3 +84,25 @@ fn make_mu_pair_uninit() -> MU<(u8, u32)> { // CHECK-NEXT: ret { i8, i32 } undef MU { uninit: () } } + +#[repr(simd)] +#[derive(Copy, Clone)] +struct I32X32([i32; 32]); + +#[no_mangle] +fn make_mu_simd(x: I32X32) -> MU { + // CHECK-LABEL: void @make_mu_simd(ptr{{.+}}%_0, ptr{{.+}}%x) + // CHECK-NEXT: start: + // CHECK-NEXT: %[[TEMP:.+]] = load <32 x i32>, ptr %x, + // CHECK-NEXT: store <32 x i32> %[[TEMP]], ptr %_0, + // CHECK-NEXT: ret void + MU { value: x } +} + +#[no_mangle] +fn make_mu_simd_uninit() -> MU { + // CHECK-LABEL: void @make_mu_simd_uninit(ptr{{.+}}%_0) + // CHECK-NEXT: start: + // CHECK-NEXT: ret void + MU { uninit: () } +} -- cgit 1.4.1-3-g733a5 From 486ffda9dcd0d4ef0a09d81e6ce5f241e77526a1 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 12 Mar 2025 10:26:37 +0000 Subject: Add opaque TypeId handles for CTFE --- compiler/rustc_codegen_cranelift/src/constant.rs | 13 ++++ compiler/rustc_codegen_gcc/src/common.rs | 10 ++- compiler/rustc_codegen_llvm/src/common.rs | 18 +++-- compiler/rustc_codegen_llvm/src/consts.rs | 5 +- compiler/rustc_codegen_ssa/src/mir/operand.rs | 2 +- compiler/rustc_const_eval/messages.ftl | 2 + compiler/rustc_const_eval/src/errors.rs | 6 +- .../rustc_const_eval/src/interpret/intrinsics.rs | 79 +++++++++++++++++++- compiler/rustc_const_eval/src/interpret/memory.rs | 30 +++++++- .../rustc_const_eval/src/interpret/projection.rs | 6 +- .../rustc_const_eval/src/interpret/validity.rs | 64 +++++++++-------- compiler/rustc_hir/src/lang_items.rs | 2 + compiler/rustc_hir_analysis/src/check/intrinsic.rs | 9 ++- compiler/rustc_middle/src/mir/interpret/error.rs | 2 + compiler/rustc_middle/src/mir/interpret/mod.rs | 33 +++++++-- compiler/rustc_middle/src/mir/pretty.rs | 1 + compiler/rustc_middle/src/ty/print/pretty.rs | 1 + compiler/rustc_monomorphize/src/collector.rs | 1 + compiler/rustc_passes/src/reachable.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + compiler/stable_mir/src/mir/alloc.rs | 3 + .../stable_mir/src/unstable/convert/stable/mir.rs | 3 + library/core/Cargo.toml | 2 - library/core/src/any.rs | 84 +++++++++++++++------- library/core/src/intrinsics/mod.rs | 15 +++- library/coretests/tests/any.rs | 8 --- library/std/Cargo.toml | 2 - library/sysroot/Cargo.toml | 1 - tests/codegen/error-provide.rs | 6 +- tests/ui/const-generics/issues/issue-90318.rs | 3 +- tests/ui/const-generics/issues/issue-90318.stderr | 25 +------ tests/ui/consts/const_cmp_type_id.rs | 3 +- tests/ui/consts/const_cmp_type_id.stderr | 20 +++--- tests/ui/consts/const_transmute_type_id.rs | 11 +++ tests/ui/consts/const_transmute_type_id.stderr | 12 ++++ tests/ui/consts/const_transmute_type_id2.rs | 14 ++++ tests/ui/consts/const_transmute_type_id2.stderr | 15 ++++ tests/ui/consts/const_transmute_type_id3.rs | 16 +++++ tests/ui/consts/const_transmute_type_id3.stderr | 15 ++++ tests/ui/consts/const_transmute_type_id4.rs | 16 +++++ tests/ui/consts/const_transmute_type_id4.stderr | 15 ++++ tests/ui/consts/issue-73976-monomorphic.rs | 2 +- tests/ui/consts/issue-73976-monomorphic.stderr | 9 --- 43 files changed, 438 insertions(+), 148 deletions(-) create mode 100644 tests/ui/consts/const_transmute_type_id.rs create mode 100644 tests/ui/consts/const_transmute_type_id.stderr create mode 100644 tests/ui/consts/const_transmute_type_id2.rs create mode 100644 tests/ui/consts/const_transmute_type_id2.stderr create mode 100644 tests/ui/consts/const_transmute_type_id3.rs create mode 100644 tests/ui/consts/const_transmute_type_id3.stderr create mode 100644 tests/ui/consts/const_transmute_type_id4.rs create mode 100644 tests/ui/consts/const_transmute_type_id4.stderr delete mode 100644 tests/ui/consts/issue-73976-monomorphic.stderr (limited to 'tests/codegen') diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index ed06423b260..85adf0f3716 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -175,6 +175,13 @@ pub(crate) fn codegen_const_value<'tcx>( fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } + GlobalAlloc::TypeId { .. } => { + return CValue::const_val( + fx, + layout, + ScalarInt::try_from_target_usize(offset.bytes(), fx.tcx).unwrap(), + ); + } GlobalAlloc::Static(def_id) => { assert!(fx.tcx.is_static(def_id)); let data_id = data_id_for_static( @@ -360,6 +367,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant GlobalAlloc::Memory(alloc) => alloc, GlobalAlloc::Function { .. } | GlobalAlloc::Static(_) + | GlobalAlloc::TypeId { .. } | GlobalAlloc::VTable(..) => { unreachable!() } @@ -471,6 +479,11 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant .principal() .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)), ), + GlobalAlloc::TypeId { .. } => { + // Nothing to do, the bytes/offset of this pointer have already been written together with all other bytes, + // so we just need to drop this provenance. + continue; + } GlobalAlloc::Static(def_id) => { if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 32713eb56c6..28848ca6184 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -1,7 +1,6 @@ use gccjit::{LValue, RValue, ToRValue, Type}; -use rustc_abi as abi; -use rustc_abi::HasDataLayout; use rustc_abi::Primitive::Pointer; +use rustc_abi::{self as abi, HasDataLayout}; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods, }; @@ -282,6 +281,13 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { let init = self.const_data_from_alloc(alloc); self.static_addr_of(init, alloc.inner().align, None) } + GlobalAlloc::TypeId { .. } => { + let val = self.const_usize(offset.bytes()); + // This is still a variable of pointer type, even though we only use the provenance + // of that pointer in CTFE and Miri. But to make LLVM's type system happy, + // we need an int-to-ptr cast here (it doesn't matter at all which provenance that picks). + return self.context.new_cast(None, val, ty); + } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); self.get_static(def_id).get_address(None) diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 92f38565eef..b9b5c776d86 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -3,9 +3,8 @@ use std::borrow::Borrow; use libc::{c_char, c_uint}; -use rustc_abi as abi; -use rustc_abi::HasDataLayout; use rustc_abi::Primitive::Pointer; +use rustc_abi::{self as abi, HasDataLayout as _}; use rustc_ast::Mutability; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; @@ -284,7 +283,8 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { self.const_bitcast(llval, llty) }; } else { - let init = const_alloc_to_llvm(self, alloc, /*static*/ false); + let init = + const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); let alloc = alloc.inner(); let value = match alloc.mutability { Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), @@ -316,15 +316,19 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { }), ))) .unwrap_memory(); - let init = const_alloc_to_llvm(self, alloc, /*static*/ false); - let value = self.static_addr_of_impl(init, alloc.inner().align, None); - value + let init = const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); + self.static_addr_of_impl(init, alloc.inner().align, None) } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); assert!(!self.tcx.is_thread_local_static(def_id)); self.get_static(def_id) } + GlobalAlloc::TypeId { .. } => { + // Drop the provenance, the offset contains the bytes of the hash + let llval = self.const_usize(offset.bytes()); + return unsafe { llvm::LLVMConstIntToPtr(llval, llty) }; + } }; let base_addr_space = global_alloc.address_space(self); let llval = unsafe { @@ -346,7 +350,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { } fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value { - const_alloc_to_llvm(self, alloc, /*static*/ false) + const_alloc_to_llvm(self, alloc.inner(), /*static*/ false) } fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 28f5282c6b0..21524fd2eb8 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -27,10 +27,9 @@ use crate::{base, debuginfo}; pub(crate) fn const_alloc_to_llvm<'ll>( cx: &CodegenCx<'ll, '_>, - alloc: ConstAllocation<'_>, + alloc: &Allocation, is_static: bool, ) -> &'ll Value { - let alloc = alloc.inner(); // We expect that callers of const_alloc_to_llvm will instead directly codegen a pointer or // integer for any &ZST where the ZST is a constant (i.e. not a static). We should never be // producing empty LLVM allocations as they're just adding noise to binaries and forcing less @@ -141,7 +140,7 @@ fn codegen_static_initializer<'ll, 'tcx>( def_id: DefId, ) -> Result<(&'ll Value, ConstAllocation<'tcx>), ErrorHandled> { let alloc = cx.tcx.eval_static_initializer(def_id)?; - Ok((const_alloc_to_llvm(cx, alloc, /*static*/ true), alloc)) + Ok((const_alloc_to_llvm(cx, alloc.inner(), /*static*/ true), alloc)) } fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Align) { diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 2896dfd5463..a639803ea60 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -186,7 +186,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { offset: Size, ) -> Self { let alloc_align = alloc.inner().align; - assert!(alloc_align >= layout.align.abi); + assert!(alloc_align >= layout.align.abi, "{alloc_align:?} < {:?}", layout.align.abi); let read_scalar = |start, size, s: abi::Scalar, ty| { match alloc.0.read_scalar( diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 22a1894ee72..b767ca9a3c2 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -78,6 +78,8 @@ const_eval_dealloc_kind_mismatch = const_eval_deref_function_pointer = accessing {$allocation} which contains a function +const_eval_deref_typeid_pointer = + accessing {$allocation} which contains a `TypeId` const_eval_deref_vtable_pointer = accessing {$allocation} which contains a vtable const_eval_division_by_zero = diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 9133a5fc8ef..49cd7138748 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -475,6 +475,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { WriteToReadOnly(_) => const_eval_write_to_read_only, DerefFunctionPointer(_) => const_eval_deref_function_pointer, DerefVTablePointer(_) => const_eval_deref_vtable_pointer, + DerefTypeIdPointer(_) => const_eval_deref_typeid_pointer, InvalidBool(_) => const_eval_invalid_bool, InvalidChar(_) => const_eval_invalid_char, InvalidTag(_) => const_eval_invalid_tag, @@ -588,7 +589,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { diag.arg("has", has.bytes()); diag.arg("msg", format!("{msg:?}")); } - WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => { + WriteToReadOnly(alloc) + | DerefFunctionPointer(alloc) + | DerefVTablePointer(alloc) + | DerefTypeIdPointer(alloc) => { diag.arg("allocation", alloc); } InvalidBool(b) => { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 378ed6d0e10..ee5382af0b2 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -4,8 +4,10 @@ use std::assert_matches::assert_matches; -use rustc_abi::Size; +use rustc_abi::{FieldIdx, Size}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; +use rustc_ast::Mutability; +use rustc_middle::mir::interpret::{AllocId, AllocInit, alloc_range}; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{Ty, TyCtxt}; @@ -29,6 +31,37 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll tcx.mk_const_alloc(alloc) } +pub(crate) fn alloc_type_id<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> AllocId { + let size = Size::from_bytes(16); + let align = tcx.data_layout.pointer_align(); + let mut alloc = Allocation::new(size, *align, AllocInit::Uninit, ()); + let ptr_size = tcx.data_layout.pointer_size(); + let type_id_hash = tcx.type_id_hash(ty).as_u128(); + alloc + .write_scalar( + &tcx, + alloc_range(Size::ZERO, Size::from_bytes(16)), + Scalar::from_u128(type_id_hash), + ) + .unwrap(); + + // Give the first pointer-size bytes provenance that knows about the type id + + let alloc_id = tcx.reserve_and_set_type_id_alloc(ty); + let offset = alloc + .read_scalar(&tcx, alloc_range(Size::ZERO, ptr_size), false) + .unwrap() + .to_target_usize(&tcx) + .unwrap(); + let ptr = Pointer::new(alloc_id.into(), Size::from_bytes(offset)); + let val = Scalar::from_pointer(ptr, &tcx); + alloc.write_scalar(&tcx, alloc_range(Size::ZERO, ptr_size), val).unwrap(); + + alloc.mutability = Mutability::Not; + + tcx.reserve_and_set_memory_alloc(tcx.mk_const_alloc(alloc)) +} + impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Returns `true` if emulation happened. /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own @@ -63,10 +96,52 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { sym::type_id => { let tp_ty = instance.args.type_at(0); ensure_monomorphic_enough(tcx, tp_ty)?; - let val = ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128()); + let alloc_id = alloc_type_id(tcx, tp_ty); + let val = ConstValue::Indirect { alloc_id, offset: Size::ZERO }; let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?; self.copy_op(&val, dest)?; } + sym::type_id_eq => { + // Both operands are `TypeId`, which is a newtype around an array of pointers. + // Project until we have the array elements. + let a_fields = self.project_field(&args[0], FieldIdx::ZERO)?; + let b_fields = self.project_field(&args[1], FieldIdx::ZERO)?; + + let mut a_fields = self.project_array_fields(&a_fields)?; + let mut b_fields = self.project_array_fields(&b_fields)?; + + let (_idx, a) = a_fields + .next(self)? + .expect("we know the layout of TypeId has at least 2 array elements"); + let a = self.deref_pointer(&a)?; + let (a, offset_a) = self.get_ptr_type_id(a.ptr())?; + + let (_idx, b) = b_fields + .next(self)? + .expect("we know the layout of TypeId has at least 2 array elements"); + let b = self.deref_pointer(&b)?; + let (b, offset_b) = self.get_ptr_type_id(b.ptr())?; + + let provenance_matches = a == b; + + let mut eq_id = offset_a == offset_b; + + while let Some((_, a)) = a_fields.next(self)? { + let (_, b) = b_fields.next(self)?.unwrap(); + + let a = self.read_target_usize(&a)?; + let b = self.read_target_usize(&b)?; + eq_id &= a == b; + } + + if !eq_id && provenance_matches { + throw_ub_format!( + "type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents" + ) + } + + self.write_scalar(Scalar::from_bool(provenance_matches), dest)?; + } sym::variant_count => { let tp_ty = instance.args.type_at(0); let ty = match tp_ty.kind() { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 524023b8104..bb301600135 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -15,9 +15,9 @@ use std::{fmt, ptr}; use rustc_abi::{Align, HasDataLayout, Size}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_middle::bug; use rustc_middle::mir::display_allocation; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_middle::{bug, throw_ub_format}; use tracing::{debug, instrument, trace}; use super::{ @@ -346,6 +346,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { kind = "vtable", ) } + Some(GlobalAlloc::TypeId { .. }) => { + err_ub_custom!( + fluent::const_eval_invalid_dealloc, + alloc_id = alloc_id, + kind = "typeid", + ) + } Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { err_ub_custom!( fluent::const_eval_invalid_dealloc, @@ -615,6 +622,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } Some(GlobalAlloc::Function { .. }) => throw_ub!(DerefFunctionPointer(id)), Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)), + Some(GlobalAlloc::TypeId { .. }) => throw_ub!(DerefTypeIdPointer(id)), None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccess)), Some(GlobalAlloc::Static(def_id)) => { assert!(self.tcx.is_static(def_id)); @@ -896,7 +904,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env); let mutbl = global_alloc.mutability(*self.tcx, self.typing_env); let kind = match global_alloc { - GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData, + GlobalAlloc::TypeId { .. } + | GlobalAlloc::Static { .. } + | GlobalAlloc::Memory { .. } => AllocKind::LiveData, GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"), GlobalAlloc::VTable { .. } => AllocKind::VTable, }; @@ -936,6 +946,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } + /// Takes a pointer that is the first chunk of a `TypeId` and return the type that its + /// provenance refers to, as well as the segment of the hash that this pointer covers. + pub fn get_ptr_type_id( + &self, + ptr: Pointer>, + ) -> InterpResult<'tcx, (Ty<'tcx>, Size)> { + let (alloc_id, offset, _meta) = self.ptr_get_alloc_id(ptr, 0)?; + let GlobalAlloc::TypeId { ty } = self.tcx.global_alloc(alloc_id) else { + throw_ub_format!("type_id_eq: `TypeId` provenance is not a type id") + }; + interp_ok((ty, offset)) + } + pub fn get_ptr_fn( &self, ptr: Pointer>, @@ -1197,6 +1220,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> { Some(GlobalAlloc::VTable(ty, dyn_ty)) => { write!(fmt, " (vtable: impl {dyn_ty} for {ty})")?; } + Some(GlobalAlloc::TypeId { ty }) => { + write!(fmt, " (typeid for {ty})")?; + } Some(GlobalAlloc::Static(did)) => { write!(fmt, " (static: {})", self.ecx.tcx.def_path_str(did))?; } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 306697d4ec9..f72c4418081 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -296,7 +296,11 @@ where base: &'a P, ) -> InterpResult<'tcx, ArrayIterator<'a, 'tcx, M::Provenance, P>> { let abi::FieldsShape::Array { stride, .. } = base.layout().fields else { - span_bug!(self.cur_span(), "project_array_fields: expected an array layout"); + span_bug!( + self.cur_span(), + "project_array_fields: expected an array layout, got {:#?}", + base.layout() + ); }; let len = base.len(self)?; let field_layout = base.layout().field(self, 0); diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index fc4d13af8c4..fc44490c96d 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -571,40 +571,42 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { let alloc_actual_mutbl = global_alloc.mutability(*self.ecx.tcx, self.ecx.typing_env); - if let GlobalAlloc::Static(did) = global_alloc { - let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { - bug!() - }; - // Special handling for pointers to statics (irrespective of their type). - assert!(!self.ecx.tcx.is_thread_local_static(did)); - assert!(self.ecx.tcx.is_static(did)); - // Mode-specific checks - match ctfe_mode { - CtfeValidationMode::Static { .. } - | CtfeValidationMode::Promoted { .. } => { - // We skip recursively checking other statics. These statics must be sound by - // themselves, and the only way to get broken statics here is by using - // unsafe code. - // The reasons we don't check other statics is twofold. For one, in all - // sound cases, the static was already validated on its own, and second, we - // trigger cycle errors if we try to compute the value of the other static - // and that static refers back to us (potentially through a promoted). - // This could miss some UB, but that's fine. - // We still walk nested allocations, as they are fundamentally part of this validation run. - // This means we will also recurse into nested statics of *other* - // statics, even though we do not recurse into other statics directly. - // That's somewhat inconsistent but harmless. - skip_recursive_check = !nested; - } - CtfeValidationMode::Const { .. } => { - // If this is mutable memory or an `extern static`, there's no point in checking it -- we'd - // just get errors trying to read the value. - if alloc_actual_mutbl.is_mut() || self.ecx.tcx.is_foreign_item(did) - { - skip_recursive_check = true; + match global_alloc { + GlobalAlloc::Static(did) => { + let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { + bug!() + }; + assert!(!self.ecx.tcx.is_thread_local_static(did)); + assert!(self.ecx.tcx.is_static(did)); + match ctfe_mode { + CtfeValidationMode::Static { .. } + | CtfeValidationMode::Promoted { .. } => { + // We skip recursively checking other statics. These statics must be sound by + // themselves, and the only way to get broken statics here is by using + // unsafe code. + // The reasons we don't check other statics is twofold. For one, in all + // sound cases, the static was already validated on its own, and second, we + // trigger cycle errors if we try to compute the value of the other static + // and that static refers back to us (potentially through a promoted). + // This could miss some UB, but that's fine. + // We still walk nested allocations, as they are fundamentally part of this validation run. + // This means we will also recurse into nested statics of *other* + // statics, even though we do not recurse into other statics directly. + // That's somewhat inconsistent but harmless. + skip_recursive_check = !nested; + } + CtfeValidationMode::Const { .. } => { + // If this is mutable memory or an `extern static`, there's no point in checking it -- we'd + // just get errors trying to read the value. + if alloc_actual_mutbl.is_mut() + || self.ecx.tcx.is_foreign_item(did) + { + skip_recursive_check = true; + } } } } + _ => (), } // If this allocation has size zero, there is no actual mutability here. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index c11db63ba11..6347f1bfa71 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -274,6 +274,8 @@ language_item_table! { PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1); CVoid, sym::c_void, c_void, Target::Enum, GenericRequirement::None; + TypeId, sym::type_id, type_id, Target::Struct, GenericRequirement::None; + // A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and // various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays. // diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index cebf7d1b532..e3532ade32f 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -93,6 +93,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::three_way_compare | sym::discriminant_value | sym::type_id + | sym::type_id_eq | sym::select_unpredictable | sym::cold_path | sym::ptr_guaranteed_cmp @@ -220,7 +221,13 @@ pub(crate) fn check_intrinsic_type( sym::needs_drop => (1, 0, vec![], tcx.types.bool), sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)), - sym::type_id => (1, 0, vec![], tcx.types.u128), + sym::type_id => { + (1, 0, vec![], tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity()) + } + sym::type_id_eq => { + let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity(); + (0, 0, vec![type_id, type_id], tcx.types.bool) + } sym::offset => (2, 0, vec![param(0), param(1)], param(0)), sym::arith_offset => ( 1, diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 8acb8fa9f80..71e0c943fbb 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -392,6 +392,8 @@ pub enum UndefinedBehaviorInfo<'tcx> { DerefFunctionPointer(AllocId), /// Trying to access the data behind a vtable pointer. DerefVTablePointer(AllocId), + /// Trying to access the actual type id. + DerefTypeIdPointer(AllocId), /// Using a non-boolean `u8` as bool. InvalidBool(u8), /// Using a non-character `u32` as character. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 0b2645013ba..bed99a4ff2a 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -103,6 +103,7 @@ enum AllocDiscriminant { Fn, VTable, Static, + Type, } pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>( @@ -127,6 +128,11 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>( ty.encode(encoder); poly_trait_ref.encode(encoder); } + GlobalAlloc::TypeId { ty } => { + trace!("encoding {alloc_id:?} with {ty:#?}"); + AllocDiscriminant::Type.encode(encoder); + ty.encode(encoder); + } GlobalAlloc::Static(did) => { assert!(!tcx.is_thread_local_static(did)); // References to statics doesn't need to know about their allocations, @@ -228,6 +234,12 @@ impl<'s> AllocDecodingSession<'s> { trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}"); decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref, CTFE_ALLOC_SALT) } + AllocDiscriminant::Type => { + trace!("creating typeid alloc ID"); + let ty = Decodable::decode(decoder); + trace!("decoded typid: {ty:?}"); + decoder.interner().reserve_and_set_type_id_alloc(ty) + } AllocDiscriminant::Static => { trace!("creating extern static alloc ID"); let did = >::decode(decoder); @@ -258,6 +270,9 @@ pub enum GlobalAlloc<'tcx> { Static(DefId), /// The alloc ID points to memory. Memory(ConstAllocation<'tcx>), + /// The first pointer-sized segment of a type id. On 64 bit systems, the 128 bit type id + /// is split into two segments, on 32 bit systems there are 4 segments, and so on. + TypeId { ty: Ty<'tcx> }, } impl<'tcx> GlobalAlloc<'tcx> { @@ -296,9 +311,10 @@ impl<'tcx> GlobalAlloc<'tcx> { pub fn address_space(&self, cx: &impl HasDataLayout) -> AddressSpace { match self { GlobalAlloc::Function { .. } => cx.data_layout().instruction_address_space, - GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => { - AddressSpace::ZERO - } + GlobalAlloc::TypeId { .. } + | GlobalAlloc::Static(..) + | GlobalAlloc::Memory(..) + | GlobalAlloc::VTable(..) => AddressSpace::ZERO, } } @@ -334,7 +350,7 @@ impl<'tcx> GlobalAlloc<'tcx> { } } GlobalAlloc::Memory(alloc) => alloc.inner().mutability, - GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => { + GlobalAlloc::TypeId { .. } | GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => { // These are immutable. Mutability::Not } @@ -380,8 +396,10 @@ impl<'tcx> GlobalAlloc<'tcx> { GlobalAlloc::Function { .. } => (Size::ZERO, Align::ONE), GlobalAlloc::VTable(..) => { // No data to be accessed here. But vtables are pointer-aligned. - return (Size::ZERO, tcx.data_layout.pointer_align().abi); + (Size::ZERO, tcx.data_layout.pointer_align().abi) } + // Fake allocation, there's nothing to access here + GlobalAlloc::TypeId { .. } => (Size::ZERO, Align::ONE), } } } @@ -487,6 +505,11 @@ impl<'tcx> TyCtxt<'tcx> { self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, dyn_ty), salt) } + /// Generates an [AllocId] for a [core::any::TypeId]. Will get deduplicated. + pub fn reserve_and_set_type_id_alloc(self, ty: Ty<'tcx>) -> AllocId { + self.reserve_and_set_dedup(GlobalAlloc::TypeId { ty }, 0) + } + /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical /// `Allocation` with a different `AllocId`. /// Statics with identical content will still point to the same `Allocation`, i.e., diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index e9f3fb6ac8d..8e403dfddae 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1621,6 +1621,7 @@ pub fn write_allocations<'tcx>( Some(GlobalAlloc::VTable(ty, dyn_ty)) => { write!(w, " (vtable: impl {dyn_ty} for {ty})")? } + Some(GlobalAlloc::TypeId { ty }) => write!(w, " (typeid for {ty})")?, Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { write!(w, " (static: {}", tcx.def_path_str(did))?; if body.phase <= MirPhase::Runtime(RuntimePhase::PostCleanup) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 4e078847815..7c48a4b0885 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1773,6 +1773,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } Some(GlobalAlloc::Function { .. }) => p!(""), Some(GlobalAlloc::VTable(..)) => p!(""), + Some(GlobalAlloc::TypeId { .. }) => p!(""), None => p!(""), } return Ok(()); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 131064f9832..91c8e64ce9a 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1219,6 +1219,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt )); collect_alloc(tcx, alloc_id, output) } + GlobalAlloc::TypeId { .. } => {} } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 7e15267a953..b49e8118fe3 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -325,6 +325,7 @@ impl<'tcx> ReachableContext<'tcx> { self.visit(args); } } + GlobalAlloc::TypeId { ty, .. } => self.visit(ty), GlobalAlloc::Memory(alloc) => self.propagate_from_alloc(alloc), } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 09f01d8704e..4df91cc3429 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2194,6 +2194,7 @@ symbols! { type_changing_struct_update, type_const, type_id, + type_id_eq, type_ir, type_ir_infer_ctxt_like, type_ir_inherent, diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs index 0d45e59885c..9a94551f3ec 100644 --- a/compiler/stable_mir/src/mir/alloc.rs +++ b/compiler/stable_mir/src/mir/alloc.rs @@ -23,6 +23,9 @@ pub enum GlobalAlloc { Static(StaticDef), /// The alloc ID points to memory. Memory(Allocation), + /// The first pointer-sized segment of a type id. On 64 bit systems, the 128 bit type id + /// is split into two segments, on 32 bit systems there are 4 segments, and so on. + TypeId { ty: Ty }, } impl From for GlobalAlloc { diff --git a/compiler/stable_mir/src/unstable/convert/stable/mir.rs b/compiler/stable_mir/src/unstable/convert/stable/mir.rs index f6f4706e40b..ad39fc37600 100644 --- a/compiler/stable_mir/src/unstable/convert/stable/mir.rs +++ b/compiler/stable_mir/src/unstable/convert/stable/mir.rs @@ -864,6 +864,9 @@ impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> { mir::interpret::GlobalAlloc::Memory(alloc) => { GlobalAlloc::Memory(alloc.stable(tables, cx)) } + mir::interpret::GlobalAlloc::TypeId { ty } => { + GlobalAlloc::TypeId { ty: ty.stable(tables, cx) } + } } } } diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index f88661ee001..3e34e03a61e 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -23,8 +23,6 @@ optimize_for_size = [] # Make `RefCell` store additional debugging information, which is printed out when # a borrow error occurs debug_refcell = [] -# Make `TypeId` store a reference to the name of the type, so that it can print that name. -debug_typeid = [] [lints.rust.unexpected_cfgs] level = "warn" diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 01dce114592..39cdf6efda0 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -707,19 +707,52 @@ impl dyn Any + Send + Sync { /// ``` #[derive(Clone, Copy, Eq, PartialOrd, Ord)] #[stable(feature = "rust1", since = "1.0.0")] +#[lang = "type_id"] pub struct TypeId { - // We avoid using `u128` because that imposes higher alignment requirements on many platforms. - // See issue #115620 for more information. - t: (u64, u64), - #[cfg(feature = "debug_typeid")] - name: &'static str, + /// This needs to be an array of pointers, since there is provenance + /// in the first array field. This provenance knows exactly which type + /// the TypeId actually is, allowing CTFE and miri to operate based off it. + /// At runtime all the pointers in the array contain bits of the hash, making + /// the entire `TypeId` actually just be a `u128` hash of the type. + pub(crate) data: [*const (); 16 / size_of::<*const ()>()], } +// SAFETY: the raw pointer is always an integer #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for TypeId { +unsafe impl Send for TypeId {} +// SAFETY: the raw pointer is always an integer +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for TypeId {} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_type_id", issue = "77125")] +impl const PartialEq for TypeId { #[inline] fn eq(&self, other: &Self) -> bool { - self.t == other.t + #[cfg(miri)] + return crate::intrinsics::type_id_eq(*self, *other); + #[cfg(not(miri))] + { + let this = self; + crate::intrinsics::const_eval_select!( + @capture { this: &TypeId, other: &TypeId } -> bool: + if const { + crate::intrinsics::type_id_eq(*this, *other) + } else { + // Ideally we would just invoke `type_id_eq` unconditionally here, + // but since we do not MIR inline intrinsics, because backends + // may want to override them (and miri does!), MIR opts do not + // clean up this call sufficiently for LLVM to turn repeated calls + // of `TypeId` comparisons against one specific `TypeId` into + // a lookup table. + // SAFETY: We know that at runtime none of the bits have provenance and all bits + // are initialized. So we can just convert the whole thing to a `u128` and compare that. + unsafe { + crate::mem::transmute::<_, u128>(*this) == crate::mem::transmute::<_, u128>(*other) + } + } + ) + } } } @@ -742,19 +775,19 @@ impl TypeId { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] pub const fn of() -> TypeId { - let t: u128 = const { intrinsics::type_id::() }; - let t1 = (t >> 64) as u64; - let t2 = t as u64; - - TypeId { - t: (t1, t2), - #[cfg(feature = "debug_typeid")] - name: type_name::(), - } + const { intrinsics::type_id::() } } fn as_u128(self) -> u128 { - u128::from(self.t.0) << 64 | u128::from(self.t.1) + let mut bytes = [0; 16]; + + // This is a provenance-stripping memcpy. + for (i, chunk) in self.data.iter().copied().enumerate() { + let chunk = chunk.expose_provenance().to_ne_bytes(); + let start = i * chunk.len(); + bytes[start..(start + chunk.len())].copy_from_slice(&chunk); + } + u128::from_ne_bytes(bytes) } } @@ -774,22 +807,19 @@ impl hash::Hash for TypeId { // - It is correct to do so -- only hashing a subset of `self` is still // compatible with an `Eq` implementation that considers the entire // value, as ours does. - self.t.1.hash(state); + let data = + // SAFETY: The `offset` stays in-bounds, it just moves the pointer to the 2nd half of the `TypeId`. + // Only the first ptr-sized chunk ever has provenance, so that second half is always + // fine to read at integer type. + unsafe { crate::ptr::read_unaligned(self.data.as_ptr().cast::().offset(1)) }; + data.hash(state); } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for TypeId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - #[cfg(feature = "debug_typeid")] - { - write!(f, "TypeId({:#034x} = {})", self.as_u128(), self.name)?; - } - #[cfg(not(feature = "debug_typeid"))] - { - write!(f, "TypeId({:#034x})", self.as_u128())?; - } - Ok(()) + write!(f, "TypeId({:#034x})", self.as_u128()) } } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 791d10eda6d..f5dcfeebed8 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2724,7 +2724,20 @@ pub const fn type_name() -> &'static str; #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -pub const fn type_id() -> u128; +pub const fn type_id() -> crate::any::TypeId; + +/// Tests (at compile-time) if two [`crate::any::TypeId`] instances identify the +/// same type. This is necessary because at const-eval time the actual discriminating +/// data is opaque and cannot be inspected directly. +/// +/// The stabilized version of this intrinsic is the [PartialEq] impl for [`core::any::TypeId`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_intrinsic] +#[rustc_do_not_const_check] +pub const fn type_id_eq(a: crate::any::TypeId, b: crate::any::TypeId) -> bool { + a.data == b.data +} /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. /// diff --git a/library/coretests/tests/any.rs b/library/coretests/tests/any.rs index 117ef004238..25002617d0b 100644 --- a/library/coretests/tests/any.rs +++ b/library/coretests/tests/any.rs @@ -118,14 +118,6 @@ fn any_unsized() { is_any::<[i32]>(); } -#[cfg(feature = "debug_typeid")] -#[test] -fn debug_typeid_includes_name() { - let type_id = TypeId::of::<[usize; 2]>(); - let debug_str = format!("{type_id:?}"); - assert!(debug_str.ends_with("= [usize; 2])"), "{debug_str:?} did not match"); -} - #[test] fn distinct_type_names() { // https://github.com/rust-lang/rust/issues/84666 diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 3a75d316871..62ece4b6961 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -113,8 +113,6 @@ optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"] # Make `RefCell` store additional debugging information, which is printed out when # a borrow error occurs debug_refcell = ["core/debug_refcell"] -# Make `TypeId` store a reference to the name of the type, so that it can print that name. -debug_typeid = ["core/debug_typeid"] # Enable std_detect default features for stdarch/crates/std_detect: diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 3adc0224971..c4937c36d4c 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -22,7 +22,6 @@ compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"] compiler-builtins-no-f16-f128 = ["std/compiler-builtins-no-f16-f128"] compiler-builtins-mangled-names = ["std/compiler-builtins-mangled-names"] debug_refcell = ["std/debug_refcell"] -debug_typeid = ["std/debug_typeid"] llvm-libunwind = ["std/llvm-libunwind"] system-llvm-libunwind = ["std/system-llvm-libunwind"] optimize_for_size = ["std/optimize_for_size"] diff --git a/tests/codegen/error-provide.rs b/tests/codegen/error-provide.rs index 25a66078fd4..7f091e34359 100644 --- a/tests/codegen/error-provide.rs +++ b/tests/codegen/error-provide.rs @@ -37,9 +37,9 @@ impl std::error::Error for MyError { // and eliminate redundant ones, rather than compare one-by-one. // CHECK-NEXT: start: - // CHECK-NEXT: %[[SCRUTINEE:[^ ]+]] = load i64, ptr - // CHECK-NEXT: switch i64 %[[SCRUTINEE]], label %{{.*}} [ - // CHECK-COUNT-3: i64 {{.*}}, label %{{.*}} + // CHECK-NEXT: %[[SCRUTINEE:[^ ]+]] = load i128, ptr + // CHECK-NEXT: switch i128 %[[SCRUTINEE]], label %{{.*}} [ + // CHECK-COUNT-3: i128 {{.*}}, label %{{.*}} // CHECK-NEXT: ] request .provide_ref::(&self.backtrace1) diff --git a/tests/ui/const-generics/issues/issue-90318.rs b/tests/ui/const-generics/issues/issue-90318.rs index 317ddad49cd..dfba90a5575 100644 --- a/tests/ui/const-generics/issues/issue-90318.rs +++ b/tests/ui/const-generics/issues/issue-90318.rs @@ -1,5 +1,6 @@ #![feature(const_type_id)] #![feature(generic_const_exprs)] +#![feature(const_trait_impl)] #![feature(core_intrinsics)] #![allow(incomplete_features)] @@ -13,7 +14,6 @@ fn consume(_val: T) where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, //~^ ERROR overly complex generic constant - //~| ERROR: cannot call { } @@ -21,7 +21,6 @@ fn test() where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, //~^ ERROR overly complex generic constant - //~| ERROR: cannot call { } diff --git a/tests/ui/const-generics/issues/issue-90318.stderr b/tests/ui/const-generics/issues/issue-90318.stderr index 9c7cb5ceb58..7031230db91 100644 --- a/tests/ui/const-generics/issues/issue-90318.stderr +++ b/tests/ui/const-generics/issues/issue-90318.stderr @@ -1,5 +1,5 @@ error: overly complex generic constant - --> $DIR/issue-90318.rs:14:8 + --> $DIR/issue-90318.rs:15:8 | LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, | ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,26 +20,5 @@ LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future -error[E0015]: cannot call non-const operator in constants - --> $DIR/issue-90318.rs:14:10 - | -LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: impl defined here, but it is not `const` - --> $SRC_DIR/core/src/any.rs:LL:COL - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const operator in constants - --> $DIR/issue-90318.rs:22:10 - | -LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: impl defined here, but it is not `const` - --> $SRC_DIR/core/src/any.rs:LL:COL - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs index dca0615083a..def615bd92b 100644 --- a/tests/ui/consts/const_cmp_type_id.rs +++ b/tests/ui/consts/const_cmp_type_id.rs @@ -6,10 +6,9 @@ use std::any::TypeId; fn main() { const { assert!(TypeId::of::() == TypeId::of::()); - //~^ ERROR the trait bound `TypeId: const PartialEq` is not satisfied assert!(TypeId::of::<()>() != TypeId::of::()); - //~^ ERROR the trait bound `TypeId: const PartialEq` is not satisfied let _a = TypeId::of::() < TypeId::of::(); + //~^ ERROR: cannot call non-const operator in constants // can't assert `_a` because it is not deterministic // FIXME(const_trait_impl) make it pass } diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr index a8242a200ef..540eec5098b 100644 --- a/tests/ui/consts/const_cmp_type_id.stderr +++ b/tests/ui/consts/const_cmp_type_id.stderr @@ -1,15 +1,13 @@ -error[E0277]: the trait bound `TypeId: const PartialEq` is not satisfied - --> $DIR/const_cmp_type_id.rs:8:17 +error[E0015]: cannot call non-const operator in constants + --> $DIR/const_cmp_type_id.rs:10:18 | -LL | assert!(TypeId::of::() == TypeId::of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `TypeId: const PartialEq` is not satisfied - --> $DIR/const_cmp_type_id.rs:10:17 +LL | let _a = TypeId::of::() < TypeId::of::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | assert!(TypeId::of::<()>() != TypeId::of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: calls in constants are limited to constant functions, tuple structs and tuple variants -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const_transmute_type_id.rs b/tests/ui/consts/const_transmute_type_id.rs new file mode 100644 index 00000000000..56ead6a622b --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id.rs @@ -0,0 +1,11 @@ +#![feature(const_type_id, const_trait_impl)] + +use std::any::TypeId; + +const _: () = { + let id = TypeId::of::(); + let id: u8 = unsafe { (&raw const id).cast::().read() }; + //~^ ERROR: unable to turn pointer into integer +}; + +fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id.stderr b/tests/ui/consts/const_transmute_type_id.stderr new file mode 100644 index 00000000000..85bd4ea2736 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id.stderr @@ -0,0 +1,12 @@ +error[E0080]: unable to turn pointer into integer + --> $DIR/const_transmute_type_id.rs:7:27 + | +LL | let id: u8 = unsafe { (&raw const id).cast::().read() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const_transmute_type_id2.rs b/tests/ui/consts/const_transmute_type_id2.rs new file mode 100644 index 00000000000..e29cf8171ac --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id2.rs @@ -0,0 +1,14 @@ +//@ normalize-stderr: "0x(ff)+" -> "" + +#![feature(const_type_id, const_trait_impl)] + +use std::any::TypeId; + +const _: () = { + let a: TypeId = unsafe { std::mem::transmute(u128::MAX) }; + let b: TypeId = unsafe { std::mem::transmute(u128::MAX) }; + assert!(a == b); + //~^ ERROR: pointer must point to some allocation +}; + +fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id2.stderr b/tests/ui/consts/const_transmute_type_id2.stderr new file mode 100644 index 00000000000..5646eb1257d --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id2.stderr @@ -0,0 +1,15 @@ +error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got [noalloc] which is a dangling pointer (it has no provenance) + --> $DIR/const_transmute_type_id2.rs:10:13 + | +LL | assert!(a == b); + | ^^^^^^ evaluation of `_` failed inside this call + | +note: inside `::eq` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `::eq::compiletime` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const_transmute_type_id3.rs b/tests/ui/consts/const_transmute_type_id3.rs new file mode 100644 index 00000000000..a870d6e7e80 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id3.rs @@ -0,0 +1,16 @@ +#![feature(const_type_id, const_trait_impl)] + +use std::any::TypeId; + +const _: () = { + let a = TypeId::of::<()>(); + let mut b = TypeId::of::<()>(); + unsafe { + let ptr = &mut b as *mut TypeId as *mut usize; + std::ptr::write(ptr.offset(1), 999); + } + assert!(a == b); + //~^ ERROR: one of the TypeId arguments is invalid, the hash does not match the type it represents +}; + +fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id3.stderr b/tests/ui/consts/const_transmute_type_id3.stderr new file mode 100644 index 00000000000..8cfdcfebaa4 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id3.stderr @@ -0,0 +1,15 @@ +error[E0080]: type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents + --> $DIR/const_transmute_type_id3.rs:12:13 + | +LL | assert!(a == b); + | ^^^^^^ evaluation of `_` failed inside this call + | +note: inside `::eq` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `::eq::compiletime` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const_transmute_type_id4.rs b/tests/ui/consts/const_transmute_type_id4.rs new file mode 100644 index 00000000000..bc71f961a51 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id4.rs @@ -0,0 +1,16 @@ +#![feature(const_type_id, const_trait_impl)] + +use std::any::TypeId; + +const _: () = { + let a = TypeId::of::<()>(); + let mut b = TypeId::of::<()>(); + unsafe { + let ptr = &mut b as *mut TypeId as *mut *const (); + std::ptr::write(ptr.offset(0), main as fn() as *const ()); + } + assert!(a == b); + //~^ ERROR: type_id_eq: `TypeId` provenance is not a type id +}; + +fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id4.stderr b/tests/ui/consts/const_transmute_type_id4.stderr new file mode 100644 index 00000000000..b418a79d7f0 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id4.stderr @@ -0,0 +1,15 @@ +error[E0080]: type_id_eq: `TypeId` provenance is not a type id + --> $DIR/const_transmute_type_id4.rs:12:13 + | +LL | assert!(a == b); + | ^^^^^^ evaluation of `_` failed inside this call + | +note: inside `::eq` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `::eq::compiletime` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-73976-monomorphic.rs b/tests/ui/consts/issue-73976-monomorphic.rs index 561c1976051..3bfdb397afb 100644 --- a/tests/ui/consts/issue-73976-monomorphic.rs +++ b/tests/ui/consts/issue-73976-monomorphic.rs @@ -1,4 +1,4 @@ -//@ known-bug: #110395 +//@ check-pass // // This test is complement to the test in issue-73976-polymorphic.rs. // In that test we ensure that polymorphic use of type_id and type_name in patterns diff --git a/tests/ui/consts/issue-73976-monomorphic.stderr b/tests/ui/consts/issue-73976-monomorphic.stderr deleted file mode 100644 index 367d5be09da..00000000000 --- a/tests/ui/consts/issue-73976-monomorphic.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0277]: the trait bound `TypeId: [const] PartialEq` is not satisfied - --> $DIR/issue-73976-monomorphic.rs:21:5 - | -LL | GetTypeId::::VALUE == GetTypeId::::VALUE - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. -- cgit 1.4.1-3-g733a5 From 58d7c2d5a760c1adfa4c3984eeb12787f5ad5b1d Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 9 Jul 2025 22:30:15 -0700 Subject: Make UB transmutes really UB in LLVM Ralf suggested in that UB transmutes shouldn't be trapping, which happened for the one path that PR was changing, but there's another path as well, so this PR changes that other path to match. --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 12 +++++------- tests/codegen/intrinsics/transmute.rs | 22 +++++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) (limited to 'tests/codegen') diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index cbbb0196890..1e3b76e5f93 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -236,14 +236,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { || operand.layout.is_uninhabited() || cast.is_uninhabited() { - if !operand.layout.is_uninhabited() { - // Since this is known statically and the input could have existed - // without already having hit UB, might as well trap for it. - bx.abort(); - } + // We can't use unreachable because that's a terminator, and we + // need something that can be in the middle of a basic block. + bx.assume(bx.cx().const_bool(false)); - // Because this transmute is UB, return something easy to generate, - // since it's fine that later uses of the value are probably UB. + // We still need to return a value of the appropriate type, but + // it's already UB so do the easiest thing available. return OperandValue::poison(bx, cast); } diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs index e375724bc1b..36d6a2f722f 100644 --- a/tests/codegen/intrinsics/transmute.rs +++ b/tests/codegen/intrinsics/transmute.rs @@ -58,9 +58,9 @@ pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] { - // CHECK-NOT: trap - // CHECK: call void @llvm.trap - // CHECK-NOT: trap + // CHECK-NOT: call + // CHECK: call void @llvm.assume(i1 false) + // CHECK-NOT: call mir! { { RET = CastTransmute(x); @@ -88,9 +88,9 @@ pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_to_uninhabited(x: u16) { - // CHECK-NOT: trap - // CHECK: call void @llvm.trap - // CHECK-NOT: trap + // CHECK-NOT: call + // CHECK: call void @llvm.assume(i1 false) + // CHECK-NOT: call mir! { let temp: BigNever; { @@ -104,6 +104,9 @@ pub unsafe fn check_to_uninhabited(x: u16) { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 { + // CHECK-NOT: call + // CHECK: call void @llvm.assume(i1 false) + // CHECK-NOT: call // CHECK: ret i16 poison mir! { { @@ -401,9 +404,9 @@ pub unsafe fn check_issue_109992(x: ()) -> [(); 1] { pub unsafe fn check_unit_to_never(x: ()) { // This uses custom MIR to avoid MIR optimizations having removed ZST ops. - // CHECK-NOT: trap - // CHECK: call void @llvm.trap - // CHECK-NOT: trap + // CHECK-NOT: call + // CHECK: call void @llvm.assume(i1 false) + // CHECK-NOT: call mir! { let temp: ZstNever; { @@ -420,6 +423,7 @@ pub unsafe fn check_unit_from_never(x: ZstNever) -> () { // This uses custom MIR to avoid MIR optimizations having removed ZST ops. // CHECK: start + // CHECK-NEXT: call void @llvm.assume(i1 false) // CHECK-NEXT: ret void mir! { { -- cgit 1.4.1-3-g733a5 From f5fc8727dbbf8c9e93bb0822b2e5bfa77dbd0208 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 10 Jul 2025 09:17:28 -0700 Subject: Add `BuilderMethods::unreachable_nonterminator` So places that need `unreachable` but in the middle of a basic block can call that instead of figuring out the best way to do it. --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 8 ++--- compiler/rustc_codegen_ssa/src/traits/builder.rs | 10 ++++++ tests/codegen/intrinsics/transmute.rs | 41 ++++++++++++------------ 3 files changed, 32 insertions(+), 27 deletions(-) (limited to 'tests/codegen') diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 1e3b76e5f93..bf3b1e73b94 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -207,9 +207,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { { // These cases are all UB to actually hit, so don't emit code for them. // (The size mismatches are reachable via `transmute_unchecked`.) - // We can't use unreachable because that's a terminator, and we - // need something that can be in the middle of a basic block. - bx.assume(bx.cx().const_bool(false)) + bx.unreachable_nonterminator(); } else { // Since in this path we have a place anyway, we can store or copy to it, // making sure we use the destination place's alignment even if the @@ -236,9 +234,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { || operand.layout.is_uninhabited() || cast.is_uninhabited() { - // We can't use unreachable because that's a terminator, and we - // need something that can be in the middle of a basic block. - bx.assume(bx.cx().const_bool(false)); + bx.unreachable_nonterminator(); // We still need to return a value of the appropriate type, but // it's already UB so do the easiest thing available. diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 9d367748c2a..0f1358ee508 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -136,6 +136,16 @@ pub trait BuilderMethods<'a, 'tcx>: ) -> Self::Value; fn unreachable(&mut self); + /// Like [`Self::unreachable`], but for use in the middle of a basic block. + fn unreachable_nonterminator(&mut self) { + // This is the preferred LLVM incantation for this per + // https://llvm.org/docs/Frontend/PerformanceTips.html#other-things-to-consider + // Other backends may override if they have a better way. + let const_true = self.cx().const_bool(true); + let poison_ptr = self.const_poison(self.cx().type_ptr()); + self.store(const_true, poison_ptr, Align::ONE); + } + fn add(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fadd_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs index 36d6a2f722f..c9a1cd58af3 100644 --- a/tests/codegen/intrinsics/transmute.rs +++ b/tests/codegen/intrinsics/transmute.rs @@ -29,28 +29,28 @@ pub struct Aggregate8(u8); // CHECK-LABEL: @check_bigger_size( #[no_mangle] pub unsafe fn check_bigger_size(x: u16) -> u32 { - // CHECK: call void @llvm.assume(i1 false) + // CHECK: store i1 true, ptr poison, align 1 transmute_unchecked(x) } // CHECK-LABEL: @check_smaller_size( #[no_mangle] pub unsafe fn check_smaller_size(x: u32) -> u16 { - // CHECK: call void @llvm.assume(i1 false) + // CHECK: store i1 true, ptr poison, align 1 transmute_unchecked(x) } // CHECK-LABEL: @check_smaller_array( #[no_mangle] pub unsafe fn check_smaller_array(x: [u32; 7]) -> [u32; 3] { - // CHECK: call void @llvm.assume(i1 false) + // CHECK: store i1 true, ptr poison, align 1 transmute_unchecked(x) } // CHECK-LABEL: @check_bigger_array( #[no_mangle] pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] { - // CHECK: call void @llvm.assume(i1 false) + // CHECK: store i1 true, ptr poison, align 1 transmute_unchecked(x) } @@ -58,9 +58,9 @@ pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] { - // CHECK-NOT: call - // CHECK: call void @llvm.assume(i1 false) - // CHECK-NOT: call + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void mir! { { RET = CastTransmute(x); @@ -73,9 +73,9 @@ pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] { - // CHECK-NOT: call - // CHECK: call void @llvm.assume(i1 false) - // CHECK-NOT: call + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void mir! { { RET = CastTransmute(x); @@ -88,9 +88,9 @@ pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_to_uninhabited(x: u16) { - // CHECK-NOT: call - // CHECK: call void @llvm.assume(i1 false) - // CHECK-NOT: call + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void mir! { let temp: BigNever; { @@ -104,10 +104,9 @@ pub unsafe fn check_to_uninhabited(x: u16) { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 { - // CHECK-NOT: call - // CHECK: call void @llvm.assume(i1 false) - // CHECK-NOT: call - // CHECK: ret i16 poison + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret i16 poison mir! { { RET = CastTransmute(x); @@ -404,9 +403,9 @@ pub unsafe fn check_issue_109992(x: ()) -> [(); 1] { pub unsafe fn check_unit_to_never(x: ()) { // This uses custom MIR to avoid MIR optimizations having removed ZST ops. - // CHECK-NOT: call - // CHECK: call void @llvm.assume(i1 false) - // CHECK-NOT: call + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void mir! { let temp: ZstNever; { @@ -423,7 +422,7 @@ pub unsafe fn check_unit_from_never(x: ZstNever) -> () { // This uses custom MIR to avoid MIR optimizations having removed ZST ops. // CHECK: start - // CHECK-NEXT: call void @llvm.assume(i1 false) + // CHECK-NEXT: store i1 true, ptr poison, align 1 // CHECK-NEXT: ret void mir! { { -- cgit 1.4.1-3-g733a5 From 13b1e4030aecb24b5a78cfa44594641e7d49b4b6 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 11 Jul 2025 03:57:19 -0700 Subject: More discriminant codegen tests These are from 139729, updated to pass on master. --- tests/codegen/enum/enum-discriminant-eq.rs | 231 ++++++++++++++++++++++ tests/codegen/enum/enum-match.rs | 307 +++++++++++++++++++++++++++++ 2 files changed, 538 insertions(+) create mode 100644 tests/codegen/enum/enum-discriminant-eq.rs (limited to 'tests/codegen') diff --git a/tests/codegen/enum/enum-discriminant-eq.rs b/tests/codegen/enum/enum-discriminant-eq.rs new file mode 100644 index 00000000000..fd6f3499cb1 --- /dev/null +++ b/tests/codegen/enum/enum-discriminant-eq.rs @@ -0,0 +1,231 @@ +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled +//@ min-llvm-version: 20 +//@ only-64bit + +// The `derive(PartialEq)` on enums with field-less variants compares discriminants, +// so make sure we emit that in some reasonable way. + +#![crate_type = "lib"] +#![feature(ascii_char)] +#![feature(core_intrinsics)] +#![feature(repr128)] + +use std::ascii::Char as AC; +use std::cmp::Ordering; +use std::intrinsics::discriminant_value; +use std::num::NonZero; + +// A type that's bigger than `isize`, unlike the usual cases that have small tags. +#[repr(u128)] +pub enum Giant { + Two = 2, + Three = 3, + Four = 4, +} + +#[unsafe(no_mangle)] +pub fn opt_bool_eq_discr(a: Option, b: Option) -> bool { + // CHECK-LABEL: @opt_bool_eq_discr( + // CHECK: %[[A:.+]] = icmp ne i8 %a, 2 + // CHECK: %[[B:.+]] = icmp eq i8 %b, 2 + // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] + // CHECK: ret i1 %[[R]] + + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn opt_ord_eq_discr(a: Option, b: Option) -> bool { + // CHECK-LABEL: @opt_ord_eq_discr( + // CHECK: %[[A:.+]] = icmp ne i8 %a, 2 + // CHECK: %[[B:.+]] = icmp eq i8 %b, 2 + // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] + // CHECK: ret i1 %[[R]] + + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn opt_nz32_eq_discr(a: Option>, b: Option>) -> bool { + // CHECK-LABEL: @opt_nz32_eq_discr( + // CHECK: %[[A:.+]] = icmp ne i32 %a, 0 + // CHECK: %[[B:.+]] = icmp eq i32 %b, 0 + // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] + // CHECK: ret i1 %[[R]] + + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn opt_ac_eq_discr(a: Option, b: Option) -> bool { + // CHECK-LABEL: @opt_ac_eq_discr( + // CHECK: %[[A:.+]] = icmp ne i8 %a, -128 + // CHECK: %[[B:.+]] = icmp eq i8 %b, -128 + // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] + // CHECK: ret i1 %[[R]] + + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn opt_giant_eq_discr(a: Option, b: Option) -> bool { + // CHECK-LABEL: @opt_giant_eq_discr( + // CHECK: %[[A:.+]] = icmp ne i128 %a, 1 + // CHECK: %[[B:.+]] = icmp eq i128 %b, 1 + // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] + // CHECK: ret i1 %[[R]] + + discriminant_value(&a) == discriminant_value(&b) +} + +pub enum Mid { + Before, + Thing(T), + After, +} + +#[unsafe(no_mangle)] +pub fn mid_bool_eq_discr(a: Mid, b: Mid) -> bool { + // CHECK-LABEL: @mid_bool_eq_discr( + + // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2 + // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3 + // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) + // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 + + // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2 + // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i8 %[[B_REL_DISCR]], 3 + // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) + // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 + + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn mid_ord_eq_discr(a: Mid, b: Mid) -> bool { + // CHECK-LABEL: @mid_ord_eq_discr( + + // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2 + // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3 + // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) + // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 + + // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2 + // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i8 %[[B_REL_DISCR]], 3 + // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) + // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 + + // CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]] + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn mid_nz32_eq_discr(a: Mid>, b: Mid>) -> bool { + // CHECK-LABEL: @mid_nz32_eq_discr( + // CHECK: %[[R:.+]] = icmp eq i32 %a.0, %b.0 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn mid_ac_eq_discr(a: Mid, b: Mid) -> bool { + // CHECK-LABEL: @mid_ac_eq_discr( + + // CHECK: %[[A_REL_DISCR:.+]] = xor i8 %a, -128 + // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3 + // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %a, -127 + // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) + // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 + + // CHECK: %[[B_REL_DISCR:.+]] = xor i8 %b, -128 + // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i8 %[[B_REL_DISCR]], 3 + // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %b, -127 + // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) + // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 + + // CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]] + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == discriminant_value(&b) +} + +// FIXME: This should be improved once our LLVM fork picks up the fix for +// +#[unsafe(no_mangle)] +pub fn mid_giant_eq_discr(a: Mid, b: Mid) -> bool { + // CHECK-LABEL: @mid_giant_eq_discr( + + // CHECK: %[[A_REL_DISCR_WIDE:.+]] = add nsw i128 %a, -5 + // CHECK: %[[A_REL_DISCR:.+]] = trunc nsw i128 %[[A_REL_DISCR_WIDE]] to i64 + // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i128 %[[A_REL_DISCR_WIDE]], 3 + // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i128 %[[A_REL_DISCR_WIDE]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) + // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i64 %[[A_REL_DISCR]], i64 1 + + // CHECK: %[[B_REL_DISCR_WIDE:.+]] = add nsw i128 %b, -5 + // CHECK: %[[B_REL_DISCR:.+]] = trunc nsw i128 %[[B_REL_DISCR_WIDE]] to i64 + // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i128 %[[B_REL_DISCR_WIDE]], 3 + // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i128 %[[B_REL_DISCR_WIDE]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) + // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i64 %[[B_REL_DISCR]], i64 1 + + // CHECK: %[[R:.+]] = icmp eq i64 %[[A_DISCR]], %[[B_DISCR]] + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == discriminant_value(&b) +} + +// In niche-encoded enums, testing for the untagged variant should optimize to a +// straight-forward comparison looking for the natural range of the payload value. +// FIXME: A bunch don't, though. + +#[unsafe(no_mangle)] +pub fn mid_bool_is_thing(a: Mid) -> bool { + // CHECK-LABEL: @mid_bool_is_thing( + + // CHECK: %[[REL_DISCR:.+]] = add nsw i8 %a, -2 + // CHECK: %[[R:.+]] = icmp ugt i8 %[[REL_DISCR]], 2 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == 1 +} + +#[unsafe(no_mangle)] +pub fn mid_ord_is_thing(a: Mid) -> bool { + // CHECK-LABEL: @mid_ord_is_thing( + // CHECK: %[[REL_DISCR:.+]] = add nsw i8 %a, -2 + // CHECK: %[[R:.+]] = icmp ugt i8 %[[REL_DISCR]], 2 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == 1 +} + +#[unsafe(no_mangle)] +pub fn mid_nz32_is_thing(a: Mid>) -> bool { + // CHECK-LABEL: @mid_nz32_is_thing( + // CHECK: %[[R:.+]] = icmp eq i32 %a.0, 1 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == 1 +} + +#[unsafe(no_mangle)] +pub fn mid_ac_is_thing(a: Mid) -> bool { + // CHECK-LABEL: @mid_ac_is_thing( + // CHECK: %[[R:.+]] = icmp sgt i8 %a, -1 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == 1 +} + +#[unsafe(no_mangle)] +pub fn mid_giant_is_thing(a: Mid) -> bool { + // CHECK-LABEL: @mid_giant_is_thing( + // CHECK: %[[REL_DISCR_WIDE:.+]] = add nsw i128 %a, -5 + // CHECK: %[[REL_DISCR:.+]] = trunc nsw i128 %[[REL_DISCR_WIDE]] to i64 + // CHECK: %[[NOT_NICHE:.+]] = icmp ugt i128 %[[REL_DISCR_WIDE]], 2 + // CHECK: %[[IS_MID_VARIANT:.+]] = icmp eq i64 %[[REL_DISCR]], 1 + // CHECK: %[[R:.+]] = select i1 %[[NOT_NICHE]], i1 true, i1 %[[IS_MID_VARIANT]] + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == 1 +} diff --git a/tests/codegen/enum/enum-match.rs b/tests/codegen/enum/enum-match.rs index 98635008d06..9725e64def6 100644 --- a/tests/codegen/enum/enum-match.rs +++ b/tests/codegen/enum/enum-match.rs @@ -471,3 +471,310 @@ pub fn match5(e: HugeVariantIndex) -> u8 { Possible259 => 100, } } + +// Make an enum where the niche tags wrap both as signed and as unsigned, to hit +// the most-fallback case where there's just nothing smart to do. + +pub enum E10Through65 { + D10 = 10, + D11 = 11, + D12 = 12, + D13 = 13, + D14 = 14, + D15 = 15, + D16 = 16, + D17 = 17, + D18 = 18, + D19 = 19, + D20 = 20, + D21 = 21, + D22 = 22, + D23 = 23, + D24 = 24, + D25 = 25, + D26 = 26, + D27 = 27, + D28 = 28, + D29 = 29, + D30 = 30, + D31 = 31, + D32 = 32, + D33 = 33, + D34 = 34, + D35 = 35, + D36 = 36, + D37 = 37, + D38 = 38, + D39 = 39, + D40 = 40, + D41 = 41, + D42 = 42, + D43 = 43, + D44 = 44, + D45 = 45, + D46 = 46, + D47 = 47, + D48 = 48, + D49 = 49, + D50 = 50, + D51 = 51, + D52 = 52, + D53 = 53, + D54 = 54, + D55 = 55, + D56 = 56, + D57 = 57, + D58 = 58, + D59 = 59, + D60 = 60, + D61 = 61, + D62 = 62, + D63 = 63, + D64 = 64, + D65 = 65, +} + +pub enum Tricky { + Untagged(E10Through65), + V001, + V002, + V003, + V004, + V005, + V006, + V007, + V008, + V009, + V010, + V011, + V012, + V013, + V014, + V015, + V016, + V017, + V018, + V019, + V020, + V021, + V022, + V023, + V024, + V025, + V026, + V027, + V028, + V029, + V030, + V031, + V032, + V033, + V034, + V035, + V036, + V037, + V038, + V039, + V040, + V041, + V042, + V043, + V044, + V045, + V046, + V047, + V048, + V049, + V050, + V051, + V052, + V053, + V054, + V055, + V056, + V057, + V058, + V059, + V060, + V061, + V062, + V063, + V064, + V065, + V066, + V067, + V068, + V069, + V070, + V071, + V072, + V073, + V074, + V075, + V076, + V077, + V078, + V079, + V080, + V081, + V082, + V083, + V084, + V085, + V086, + V087, + V088, + V089, + V090, + V091, + V092, + V093, + V094, + V095, + V096, + V097, + V098, + V099, + V100, + V101, + V102, + V103, + V104, + V105, + V106, + V107, + V108, + V109, + V110, + V111, + V112, + V113, + V114, + V115, + V116, + V117, + V118, + V119, + V120, + V121, + V122, + V123, + V124, + V125, + V126, + V127, + V128, + V129, + V130, + V131, + V132, + V133, + V134, + V135, + V136, + V137, + V138, + V139, + V140, + V141, + V142, + V143, + V144, + V145, + V146, + V147, + V148, + V149, + V150, + V151, + V152, + V153, + V154, + V155, + V156, + V157, + V158, + V159, + V160, + V161, + V162, + V163, + V164, + V165, + V166, + V167, + V168, + V169, + V170, + V171, + V172, + V173, + V174, + V175, + V176, + V177, + V178, + V179, + V180, + V181, + V182, + V183, + V184, + V185, + V186, + V187, + V188, + V189, + V190, + V191, + V192, + V193, + V194, + V195, + V196, + V197, + V198, + V199, + V200, +} + +const _: () = assert!(std::intrinsics::discriminant_value(&Tricky::V100) == 100); + +// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @discriminant6(i8 noundef %e) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %e, -66 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], -56 +// CHECK-NEXT: %[[TAGGED_DISCR:.+]] = add i8 %e, -65 +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i8 %[[TAGGED_DISCR]], i8 0 +// CHECK-NEXT: ret i8 %[[DISCR]] +#[no_mangle] +pub fn discriminant6(e: Tricky) -> u8 { + std::intrinsics::discriminant_value(&e) as _ +} + +// Case from , +// where sign-extension is important. + +pub enum OpenResult { + Ok(()), + Err(()), + TransportErr(TransportErr), +} + +#[repr(i32)] +pub enum TransportErr { + UnknownMethod = -2, +} + +#[no_mangle] +pub fn match7(result: OpenResult) -> u8 { + // CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match7(i32{{.+}}%result) + // CHECK-NEXT: start: + // CHECK-NEXT: %[[NOT_OK:.+]] = icmp ne i32 %result, -1 + // CHECK-NEXT: %[[RET:.+]] = zext i1 %[[NOT_OK]] to i8 + // CHECK-NEXT: ret i8 %[[RET]] + match result { + OpenResult::Ok(()) => 0, + _ => 1, + } +} -- cgit 1.4.1-3-g733a5 From d5bcfb334b616e01c3589ba7b1697c7ebc47a024 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 11 Jul 2025 05:07:37 -0700 Subject: Simplify codegen for niche-encoded variant tests --- compiler/rustc_abi/src/lib.rs | 35 +++++++++++- compiler/rustc_codegen_ssa/src/mir/operand.rs | 77 +++++++++++++++++---------- tests/codegen/enum/enum-discriminant-eq.rs | 42 ++++++--------- tests/codegen/enum/enum-match.rs | 19 ++++--- 4 files changed, 110 insertions(+), 63 deletions(-) (limited to 'tests/codegen') diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index de4b5a46c81..5bd73502d98 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -43,7 +43,7 @@ use std::fmt; #[cfg(feature = "nightly")] use std::iter::Step; use std::num::{NonZeroUsize, ParseIntError}; -use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub}; +use std::ops::{Add, AddAssign, Deref, Mul, RangeFull, RangeInclusive, Sub}; use std::str::FromStr; use bitflags::bitflags; @@ -1391,12 +1391,45 @@ impl WrappingRange { } /// Returns `true` if `size` completely fills the range. + /// + /// Note that this is *not* the same as `self == WrappingRange::full(size)`. + /// Niche calculations can produce full ranges which are not the canonical one; + /// for example `Option>` gets `valid_range: (..=0) | (1..)`. #[inline] fn is_full_for(&self, size: Size) -> bool { let max_value = size.unsigned_int_max(); debug_assert!(self.start <= max_value && self.end <= max_value); self.start == (self.end.wrapping_add(1) & max_value) } + + /// Checks whether this range is considered non-wrapping when the values are + /// interpreted as *unsigned* numbers of width `size`. + /// + /// Returns `Ok(true)` if there's no wrap-around, `Ok(false)` if there is, + /// and `Err(..)` if the range is full so it depends how you think about it. + #[inline] + pub fn no_unsigned_wraparound(&self, size: Size) -> Result { + if self.is_full_for(size) { Err(..) } else { Ok(self.start <= self.end) } + } + + /// Checks whether this range is considered non-wrapping when the values are + /// interpreted as *signed* numbers of width `size`. + /// + /// This is heavily dependent on the `size`, as `100..=200` does wrap when + /// interpreted as `i8`, but doesn't when interpreted as `i16`. + /// + /// Returns `Ok(true)` if there's no wrap-around, `Ok(false)` if there is, + /// and `Err(..)` if the range is full so it depends how you think about it. + #[inline] + pub fn no_signed_wraparound(&self, size: Size) -> Result { + if self.is_full_for(size) { + Err(..) + } else { + let start: i128 = size.sign_extend(self.start); + let end: i128 = size.sign_extend(self.end); + Ok(start <= end) + } + } } impl fmt::Debug for WrappingRange { diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index b0d191528a8..9910cb5469f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -486,6 +486,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { // value and the variant index match, since that's all `Niche` can encode. let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); + let niche_start_const = bx.cx().const_uint_big(tag_llty, niche_start); // We have a subrange `niche_start..=niche_end` inside `range`. // If the value of the tag is inside this subrange, it's a @@ -511,35 +512,44 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { // } else { // untagged_variant // } - let niche_start = bx.cx().const_uint_big(tag_llty, niche_start); - let is_niche = bx.icmp(IntPredicate::IntEQ, tag, niche_start); + let is_niche = bx.icmp(IntPredicate::IntEQ, tag, niche_start_const); let tagged_discr = bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64); (is_niche, tagged_discr, 0) } else { // The special cases don't apply, so we'll have to go with // the general algorithm. - let relative_discr = bx.sub(tag, bx.cx().const_uint_big(tag_llty, niche_start)); + + let tag_range = tag_scalar.valid_range(&dl); + let tag_size = tag_scalar.size(&dl); + let niche_end = u128::from(relative_max).wrapping_add(niche_start); + let niche_end = tag_size.truncate(niche_end); + + let relative_discr = bx.sub(tag, niche_start_const); let cast_tag = bx.intcast(relative_discr, cast_to, false); - let is_niche = bx.icmp( - IntPredicate::IntULE, - relative_discr, - bx.cx().const_uint(tag_llty, relative_max as u64), - ); - - // Thanks to parameter attributes and load metadata, LLVM already knows - // the general valid range of the tag. It's possible, though, for there - // to be an impossible value *in the middle*, which those ranges don't - // communicate, so it's worth an `assume` to let the optimizer know. - if niche_variants.contains(&untagged_variant) - && bx.cx().sess().opts.optimize != OptLevel::No - { - let impossible = - u64::from(untagged_variant.as_u32() - niche_variants.start().as_u32()); - let impossible = bx.cx().const_uint(tag_llty, impossible); - let ne = bx.icmp(IntPredicate::IntNE, relative_discr, impossible); - bx.assume(ne); - } + let is_niche = if tag_range.no_unsigned_wraparound(tag_size) == Ok(true) { + if niche_start == tag_range.start { + let niche_end_const = bx.cx().const_uint_big(tag_llty, niche_end); + bx.icmp(IntPredicate::IntULE, tag, niche_end_const) + } else { + assert_eq!(niche_end, tag_range.end); + bx.icmp(IntPredicate::IntUGE, tag, niche_start_const) + } + } else if tag_range.no_signed_wraparound(tag_size) == Ok(true) { + if niche_start == tag_range.start { + let niche_end_const = bx.cx().const_uint_big(tag_llty, niche_end); + bx.icmp(IntPredicate::IntSLE, tag, niche_end_const) + } else { + assert_eq!(niche_end, tag_range.end); + bx.icmp(IntPredicate::IntSGE, tag, niche_start_const) + } + } else { + bx.icmp( + IntPredicate::IntULE, + relative_discr, + bx.cx().const_uint(tag_llty, relative_max as u64), + ) + }; (is_niche, cast_tag, niche_variants.start().as_u32() as u128) }; @@ -550,11 +560,24 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { bx.add(tagged_discr, bx.cx().const_uint_big(cast_to, delta)) }; - let discr = bx.select( - is_niche, - tagged_discr, - bx.cx().const_uint(cast_to, untagged_variant.as_u32() as u64), - ); + let untagged_variant_const = + bx.cx().const_uint(cast_to, u64::from(untagged_variant.as_u32())); + + // Thanks to parameter attributes and load metadata, LLVM already knows + // the general valid range of the tag. It's possible, though, for there + // to be an impossible value *in the middle*, which those ranges don't + // communicate, so it's worth an `assume` to let the optimizer know. + // Most importantly, this means when optimizing a variant test like + // `SELECT(is_niche, complex, CONST) == CONST` it's ok to simplify that + // to `!is_niche` because the `complex` part can't possibly match. + if niche_variants.contains(&untagged_variant) + && bx.cx().sess().opts.optimize != OptLevel::No + { + let ne = bx.icmp(IntPredicate::IntNE, tagged_discr, untagged_variant_const); + bx.assume(ne); + } + + let discr = bx.select(is_niche, tagged_discr, untagged_variant_const); // In principle we could insert assumes on the possible range of `discr`, but // currently in LLVM this isn't worth it because the original `tag` will diff --git a/tests/codegen/enum/enum-discriminant-eq.rs b/tests/codegen/enum/enum-discriminant-eq.rs index fd6f3499cb1..0494c5f551b 100644 --- a/tests/codegen/enum/enum-discriminant-eq.rs +++ b/tests/codegen/enum/enum-discriminant-eq.rs @@ -89,13 +89,13 @@ pub fn mid_bool_eq_discr(a: Mid, b: Mid) -> bool { // CHECK-LABEL: @mid_bool_eq_discr( // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2 - // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3 + // CHECK: %[[A_IS_NICHE:.+]] = icmp samesign ugt i8 %a, 1 // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1 // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2 - // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i8 %[[B_REL_DISCR]], 3 + // CHECK: %[[B_IS_NICHE:.+]] = icmp samesign ugt i8 %b, 1 // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1 // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 @@ -109,13 +109,13 @@ pub fn mid_ord_eq_discr(a: Mid, b: Mid) -> bool { // CHECK-LABEL: @mid_ord_eq_discr( // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2 - // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3 + // CHECK: %[[A_IS_NICHE:.+]] = icmp sgt i8 %a, 1 // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1 // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2 - // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i8 %[[B_REL_DISCR]], 3 + // CHECK: %[[B_IS_NICHE:.+]] = icmp sgt i8 %b, 1 // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1 // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 @@ -138,13 +138,13 @@ pub fn mid_ac_eq_discr(a: Mid, b: Mid) -> bool { // CHECK-LABEL: @mid_ac_eq_discr( // CHECK: %[[A_REL_DISCR:.+]] = xor i8 %a, -128 - // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3 + // CHECK: %[[A_IS_NICHE:.+]] = icmp slt i8 %a, 0 // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %a, -127 // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 // CHECK: %[[B_REL_DISCR:.+]] = xor i8 %b, -128 - // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i8 %[[B_REL_DISCR]], 3 + // CHECK: %[[B_IS_NICHE:.+]] = icmp slt i8 %b, 0 // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %b, -127 // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 @@ -160,17 +160,17 @@ pub fn mid_ac_eq_discr(a: Mid, b: Mid) -> bool { pub fn mid_giant_eq_discr(a: Mid, b: Mid) -> bool { // CHECK-LABEL: @mid_giant_eq_discr( - // CHECK: %[[A_REL_DISCR_WIDE:.+]] = add nsw i128 %a, -5 - // CHECK: %[[A_REL_DISCR:.+]] = trunc nsw i128 %[[A_REL_DISCR_WIDE]] to i64 - // CHECK: %[[A_IS_NICHE:.+]] = icmp ult i128 %[[A_REL_DISCR_WIDE]], 3 - // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i128 %[[A_REL_DISCR_WIDE]], 1 + // CHECK: %[[A_TRUNC:.+]] = trunc nuw nsw i128 %a to i64 + // CHECK: %[[A_REL_DISCR:.+]] = add nsw i64 %[[A_TRUNC]], -5 + // CHECK: %[[A_IS_NICHE:.+]] = icmp samesign ugt i128 %a, 4 + // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i64 %[[A_REL_DISCR]], 1 // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i64 %[[A_REL_DISCR]], i64 1 - // CHECK: %[[B_REL_DISCR_WIDE:.+]] = add nsw i128 %b, -5 - // CHECK: %[[B_REL_DISCR:.+]] = trunc nsw i128 %[[B_REL_DISCR_WIDE]] to i64 - // CHECK: %[[B_IS_NICHE:.+]] = icmp ult i128 %[[B_REL_DISCR_WIDE]], 3 - // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i128 %[[B_REL_DISCR_WIDE]], 1 + // CHECK: %[[B_TRUNC:.+]] = trunc nuw nsw i128 %b to i64 + // CHECK: %[[B_REL_DISCR:.+]] = add nsw i64 %[[B_TRUNC]], -5 + // CHECK: %[[B_IS_NICHE:.+]] = icmp samesign ugt i128 %b, 4 + // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i64 %[[B_REL_DISCR]], 1 // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i64 %[[B_REL_DISCR]], i64 1 @@ -181,14 +181,11 @@ pub fn mid_giant_eq_discr(a: Mid, b: Mid) -> bool { // In niche-encoded enums, testing for the untagged variant should optimize to a // straight-forward comparison looking for the natural range of the payload value. -// FIXME: A bunch don't, though. #[unsafe(no_mangle)] pub fn mid_bool_is_thing(a: Mid) -> bool { // CHECK-LABEL: @mid_bool_is_thing( - - // CHECK: %[[REL_DISCR:.+]] = add nsw i8 %a, -2 - // CHECK: %[[R:.+]] = icmp ugt i8 %[[REL_DISCR]], 2 + // CHECK: %[[R:.+]] = icmp samesign ult i8 %a, 2 // CHECK: ret i1 %[[R]] discriminant_value(&a) == 1 } @@ -196,8 +193,7 @@ pub fn mid_bool_is_thing(a: Mid) -> bool { #[unsafe(no_mangle)] pub fn mid_ord_is_thing(a: Mid) -> bool { // CHECK-LABEL: @mid_ord_is_thing( - // CHECK: %[[REL_DISCR:.+]] = add nsw i8 %a, -2 - // CHECK: %[[R:.+]] = icmp ugt i8 %[[REL_DISCR]], 2 + // CHECK: %[[R:.+]] = icmp slt i8 %a, 2 // CHECK: ret i1 %[[R]] discriminant_value(&a) == 1 } @@ -221,11 +217,7 @@ pub fn mid_ac_is_thing(a: Mid) -> bool { #[unsafe(no_mangle)] pub fn mid_giant_is_thing(a: Mid) -> bool { // CHECK-LABEL: @mid_giant_is_thing( - // CHECK: %[[REL_DISCR_WIDE:.+]] = add nsw i128 %a, -5 - // CHECK: %[[REL_DISCR:.+]] = trunc nsw i128 %[[REL_DISCR_WIDE]] to i64 - // CHECK: %[[NOT_NICHE:.+]] = icmp ugt i128 %[[REL_DISCR_WIDE]], 2 - // CHECK: %[[IS_MID_VARIANT:.+]] = icmp eq i64 %[[REL_DISCR]], 1 - // CHECK: %[[R:.+]] = select i1 %[[NOT_NICHE]], i1 true, i1 %[[IS_MID_VARIANT]] + // CHECK: %[[R:.+]] = icmp samesign ult i128 %a, 5 // CHECK: ret i1 %[[R]] discriminant_value(&a) == 1 } diff --git a/tests/codegen/enum/enum-match.rs b/tests/codegen/enum/enum-match.rs index 9725e64def6..57db44ec74e 100644 --- a/tests/codegen/enum/enum-match.rs +++ b/tests/codegen/enum/enum-match.rs @@ -41,7 +41,7 @@ pub enum Enum1 { // CHECK-NEXT: start: // CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 // CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 -// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 2 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp{{( samesign)?}} ugt i8 %0, 1 // CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1 // CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0 // CHECK-NEXT: switch i64 %[[DISCR]] @@ -148,10 +148,10 @@ pub enum MiddleNiche { // CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 -?[0-9]+, -?[0-9]+\))?}} i8 @match4(i8{{.+}}%0) // CHECK-NEXT: start: // CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 -// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 5 // CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2 // CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) -// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i8 %[[REL_VAR]], i8 2 +// CHECK-NEXT: %[[NOT_NICHE:.+]] = icmp{{( samesign)?}} ult i8 %0, 2 +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[NOT_NICHE]], i8 2, i8 %[[REL_VAR]] // CHECK-NEXT: switch i8 %[[DISCR]] #[no_mangle] pub fn match4(e: MiddleNiche) -> u8 { @@ -167,11 +167,10 @@ pub fn match4(e: MiddleNiche) -> u8 { // CHECK-LABEL: define{{.+}}i1 @match4_is_c(i8{{.+}}%e) // CHECK-NEXT: start -// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %e, -2 -// CHECK-NEXT: %[[NOT_NICHE:.+]] = icmp ugt i8 %[[REL_VAR]], 4 -// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2 +// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %e, 4 // CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) -// CHECK-NEXT: ret i1 %[[NOT_NICHE]] +// CHECK-NEXT: %[[IS_C:.+]] = icmp{{( samesign)?}} ult i8 %e, 2 +// CHECK-NEXT: ret i1 %[[IS_C]] #[no_mangle] pub fn match4_is_c(e: MiddleNiche) -> bool { // Before #139098, this couldn't optimize out the `select` because it looked @@ -453,10 +452,10 @@ pub enum HugeVariantIndex { // CHECK-NEXT: start: // CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 // CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 -// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 3 -// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 1 -// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp{{( samesign)?}} ugt i8 %0, 1 // CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 257 +// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i64 %[[NICHE_DISCR]], 258 +// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) // CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 258 // CHECK-NEXT: switch i64 %[[DISCR]], // CHECK-NEXT: i64 257, -- cgit 1.4.1-3-g733a5 From 500b743f7ef8e38a0ad6154493a84c53e06ea888 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sun, 13 Jul 2025 12:11:37 +0200 Subject: tests: Test line debuginfo for linebreaked function parameters --- .../fn-parameters-on-different-lines-debuginfo.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/codegen/fn-parameters-on-different-lines-debuginfo.rs (limited to 'tests/codegen') diff --git a/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs b/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs new file mode 100644 index 00000000000..2097567f322 --- /dev/null +++ b/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs @@ -0,0 +1,22 @@ +//! Make sure that line debuginfo of function parameters are correct even if +//! they are not on the same line. Regression test for +// . + +//@ compile-flags: -g -Copt-level=0 + +#[rustfmt::skip] // Having parameters on different lines is crucial for this test. +pub fn foo( + x_parameter_not_in_std: i32, + y_parameter_not_in_std: i32, +) -> i32 { + x_parameter_not_in_std + y_parameter_not_in_std +} + +fn main() { + foo(42, 43); // Ensure `wasm32-wasip1` keeps `foo()` (even if `-Copt-level=0`) +} + +// CHECK: !DILocalVariable(name: "x_parameter_not_in_std", arg: 1, +// CHECK-SAME: line: 9 +// CHECK: !DILocalVariable(name: "y_parameter_not_in_std", arg: 2, +// CHECK-SAME: line: 10 -- cgit 1.4.1-3-g733a5 From f100767dce1fcc0287047053cc29659ac5321a6b Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 1 Jul 2025 20:02:31 +0200 Subject: fix `-Zsanitizer=kcfi` on `#[naked]` functions And more broadly only codegen `InstanceKind::Item` using the naked function codegen code. Other instance kinds should follow the normal path. --- compiler/rustc_codegen_cranelift/src/driver/aot.rs | 8 +++- compiler/rustc_codegen_ssa/src/mono_item.rs | 13 +++--- tests/codegen/sanitizer/kcfi/naked-function.rs | 47 ++++++++++++++++++++++ tests/ui/asm/naked-function-shim.rs | 31 ++++++++++++++ 4 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 tests/codegen/sanitizer/kcfi/naked-function.rs create mode 100644 tests/ui/asm/naked-function-shim.rs (limited to 'tests/codegen') diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 442151fe32d..727f2760c0f 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -530,8 +530,12 @@ fn codegen_cgu_content( for (mono_item, item_data) in mono_items { match mono_item { MonoItem::Fn(instance) => { - if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) - { + // Other `InstanceKind`s (e.g. `ReifyShim` generated by indirect calls) should be + // codegened like a normal function. + let is_item_instance = matches!(instance.def, InstanceKind::Item(_)); + + let flags = tcx.codegen_fn_attrs(instance.def_id()).flags; + if is_item_instance && flags.contains(CodegenFnAttrFlags::NAKED) { rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm( &mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm }, instance, diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index 7b4268abe4b..fa0ef04b2e6 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -1,5 +1,6 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility}; +use rustc_middle::ty::InstanceKind; use rustc_middle::ty::layout::HasTyCtxt; use tracing::debug; @@ -41,12 +42,12 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { base::codegen_global_asm(cx, item_id); } MonoItem::Fn(instance) => { - if cx - .tcx() - .codegen_fn_attrs(instance.def_id()) - .flags - .contains(CodegenFnAttrFlags::NAKED) - { + // Other `InstanceKind`s (e.g. `ReifyShim` generated by indirect calls) should be + // codegened like a normal function. + let is_item_instance = matches!(instance.def, InstanceKind::Item(_)); + + let flags = cx.tcx().codegen_fn_attrs(instance.def_id()).flags; + if is_item_instance && flags.contains(CodegenFnAttrFlags::NAKED) { naked_asm::codegen_naked_asm::(cx, instance, item_data); } else { base::codegen_instance::(cx, instance); diff --git a/tests/codegen/sanitizer/kcfi/naked-function.rs b/tests/codegen/sanitizer/kcfi/naked-function.rs new file mode 100644 index 00000000000..92431fc7d63 --- /dev/null +++ b/tests/codegen/sanitizer/kcfi/naked-function.rs @@ -0,0 +1,47 @@ +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: x86 +//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Cno-prepopulate-passes -Copt-level=0 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +struct Thing; +trait MyTrait { + #[unsafe(naked)] + extern "C" fn my_naked_function() { + // the real function is defined + // CHECK: .globl + // CHECK-SAME: my_naked_function + naked_asm!("ret") + } +} +impl MyTrait for Thing {} + +// CHECK-LABEL: main +#[unsafe(no_mangle)] +pub fn main() { + // Trick the compiler into generating an indirect call. + const F: extern "C" fn() = Thing::my_naked_function; + + // main calls the shim function + // CHECK: call + // CHECK-SAME: my_naked_function + // CHECK-SAME: reify.shim.fnptr + (F)(); +} + +// the shim calls the real function +// CHECK: define +// CHECK-SAME: my_naked_function +// CHECK-SAME: reify.shim.fnptr + +// CHECK: declare !kcfi_type +// CHECK-SAME: my_naked_function diff --git a/tests/ui/asm/naked-function-shim.rs b/tests/ui/asm/naked-function-shim.rs new file mode 100644 index 00000000000..4694d0cd963 --- /dev/null +++ b/tests/ui/asm/naked-function-shim.rs @@ -0,0 +1,31 @@ +// The indirect call will generate a shim that then calls the actual function. Test that +// this is handled correctly. See also https://github.com/rust-lang/rust/issues/143266. + +//@ build-pass +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: x86 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +trait MyTrait { + #[unsafe(naked)] + extern "C" fn foo(&self) { + naked_asm!("ret") + } +} + +impl MyTrait for i32 {} + +fn main() { + let x: extern "C" fn(&_) = ::foo; + x(&1); +} -- cgit 1.4.1-3-g733a5 From ec0ff720d1a89cb51edd90116c6e70051affa95f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 2 Jul 2025 10:46:15 +0200 Subject: add `codegen_instance_attrs` query and use it for naked functions --- compiler/rustc_codegen_cranelift/src/driver/aot.rs | 8 ++------ compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 1 + compiler/rustc_codegen_ssa/src/mir/debuginfo.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 5 ++--- compiler/rustc_codegen_ssa/src/mono_item.rs | 9 ++------- compiler/rustc_middle/src/middle/codegen_fn_attrs.rs | 20 ++++++++++++++++++++ tests/codegen/sanitizer/kcfi/naked-function.rs | 12 ++++++------ 7 files changed, 34 insertions(+), 23 deletions(-) (limited to 'tests/codegen') diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 727f2760c0f..8ec3599b63d 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -530,12 +530,8 @@ fn codegen_cgu_content( for (mono_item, item_data) in mono_items { match mono_item { MonoItem::Fn(instance) => { - // Other `InstanceKind`s (e.g. `ReifyShim` generated by indirect calls) should be - // codegened like a normal function. - let is_item_instance = matches!(instance.def, InstanceKind::Item(_)); - - let flags = tcx.codegen_fn_attrs(instance.def_id()).flags; - if is_item_instance && flags.contains(CodegenFnAttrFlags::NAKED) { + let flags = tcx.codegen_instance_attrs(instance.def).flags; + if flags.contains(CodegenFnAttrFlags::NAKED) { rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm( &mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm }, instance, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 85d01d4f938..a1dd64736fc 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -114,6 +114,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.export_name = Some(*name); } AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, + AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name), AttributeKind::LinkSection { name, .. } => { diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 025f5fb54f4..b8f635ab781 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -356,7 +356,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::Operand(operand) => { // Don't spill operands onto the stack in naked functions. // See: https://github.com/rust-lang/rust/issues/42779 - let attrs = bx.tcx().codegen_fn_attrs(self.instance.def_id()); + let attrs = bx.tcx().codegen_instance_attrs(self.instance.def); if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { return; } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index fa69820d5d2..50d0f910744 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -390,9 +390,8 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let mut num_untupled = None; - let codegen_fn_attrs = bx.tcx().codegen_fn_attrs(fx.instance.def_id()); - let naked = codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED); - if naked { + let codegen_fn_attrs = bx.tcx().codegen_instance_attrs(fx.instance.def); + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { return vec![]; } diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index fa0ef04b2e6..2c3a6de750e 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -1,6 +1,5 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility}; -use rustc_middle::ty::InstanceKind; use rustc_middle::ty::layout::HasTyCtxt; use tracing::debug; @@ -42,12 +41,8 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { base::codegen_global_asm(cx, item_id); } MonoItem::Fn(instance) => { - // Other `InstanceKind`s (e.g. `ReifyShim` generated by indirect calls) should be - // codegened like a normal function. - let is_item_instance = matches!(instance.def, InstanceKind::Item(_)); - - let flags = cx.tcx().codegen_fn_attrs(instance.def_id()).flags; - if is_item_instance && flags.contains(CodegenFnAttrFlags::NAKED) { + let flags = cx.tcx().codegen_instance_attrs(instance.def).flags; + if flags.contains(CodegenFnAttrFlags::NAKED) { naked_asm::codegen_naked_asm::(cx, instance, item_data); } else { base::codegen_instance::(cx, instance); diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 2f16d385efb..92670e7e018 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use rustc_abi::Align; use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs; use rustc_attr_data_structures::{InlineAttr, InstructionSetAttr, OptimizeAttr}; @@ -6,6 +8,24 @@ use rustc_span::Symbol; use rustc_target::spec::SanitizerSet; use crate::mir::mono::Linkage; +use crate::ty::{InstanceKind, TyCtxt}; + +impl<'tcx> TyCtxt<'tcx> { + pub fn codegen_instance_attrs( + self, + instance_kind: InstanceKind<'_>, + ) -> Cow<'tcx, CodegenFnAttrs> { + let mut attrs = Cow::Borrowed(self.codegen_fn_attrs(instance_kind.def_id())); + + // Drop the `#[naked]` attribute on non-item `InstanceKind`s, like the shims that + // are generated for indirect function calls. + if !matches!(instance_kind, InstanceKind::Item(_)) { + attrs.to_mut().flags.remove(CodegenFnAttrFlags::NAKED); + } + + attrs + } +} #[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)] pub struct CodegenFnAttrs { diff --git a/tests/codegen/sanitizer/kcfi/naked-function.rs b/tests/codegen/sanitizer/kcfi/naked-function.rs index 92431fc7d63..2c8cdc919b8 100644 --- a/tests/codegen/sanitizer/kcfi/naked-function.rs +++ b/tests/codegen/sanitizer/kcfi/naked-function.rs @@ -25,6 +25,11 @@ trait MyTrait { } impl MyTrait for Thing {} +// the shim calls the real function +// CHECK-LABEL: define +// CHECK-SAME: my_naked_function +// CHECK-SAME: reify.shim.fnptr + // CHECK-LABEL: main #[unsafe(no_mangle)] pub fn main() { @@ -32,16 +37,11 @@ pub fn main() { const F: extern "C" fn() = Thing::my_naked_function; // main calls the shim function - // CHECK: call + // CHECK: call void // CHECK-SAME: my_naked_function // CHECK-SAME: reify.shim.fnptr (F)(); } -// the shim calls the real function -// CHECK: define -// CHECK-SAME: my_naked_function -// CHECK-SAME: reify.shim.fnptr - // CHECK: declare !kcfi_type // CHECK-SAME: my_naked_function -- cgit 1.4.1-3-g733a5 From 69b71e44107b4905ec7ad84ccb3edf4f14b3df69 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 18 Jul 2025 00:10:46 +0800 Subject: Mitigate `#[align]` name resolution ambiguity regression with a rename From `#[align]` -> `#[rustc_align]`. Attributes starting with `rustc` are always perma-unstable and feature-gated by `feature(rustc_attrs)`. See regression RUST-143834. For the underlying problem where even introducing new feature-gated unstable built-in attributes can break user code such as ```rs macro_rules! align { () => { /* .. */ }; } pub(crate) use align; // `use` here becomes ambiguous ``` refer to RUST-134963. Since the `#[align]` attribute is still feature-gated by `feature(fn_align)`, we can rename it as a mitigation. Note that `#[rustc_align]` will obviously mean that current unstable user code using `feature(fn_aling)` will need additionally `feature(rustc_attrs)`, but this is a short-term mitigation to buy time, and is expected to be changed to a better name with less collision potential. See where mitigation options were considered. --- .../rustc_attr_data_structures/src/attributes.rs | 1 + .../src/attributes/codegen_attrs.rs | 3 +- compiler/rustc_attr_parsing/src/attributes/repr.rs | 2 +- compiler/rustc_feature/src/builtin_attrs.rs | 3 +- .../rustc_middle/src/middle/codegen_fn_attrs.rs | 1 + compiler/rustc_parse/src/validate_attr.rs | 4 +- compiler/rustc_passes/messages.ftl | 6 +- compiler/rustc_passes/src/check_attr.rs | 1 + compiler/rustc_span/src/symbol.rs | 2 + src/tools/miri/tests/pass/fn_align.rs | 10 +- tests/codegen/align-fn.rs | 54 +++---- tests/codegen/min-function-alignment.rs | 6 +- tests/codegen/naked-fn/aligned.rs | 5 +- tests/codegen/naked-fn/min-function-alignment.rs | 6 +- tests/ui/asm/naked-with-invalid-repr-attr.rs | 6 +- tests/ui/asm/naked-with-invalid-repr-attr.stderr | 12 +- tests/ui/attributes/fn-align-dyn.rs | 7 +- .../fn-align-nameres-ambiguity-143834.rs | 10 +- .../fn-align-nameres-ambiguity-143834.stderr | 22 --- tests/ui/attributes/malformed-attrs.rs | 3 +- tests/ui/attributes/malformed-attrs.stderr | 170 ++++++++++----------- tests/ui/attributes/malformed-fn-align.rs | 35 +++-- tests/ui/attributes/malformed-fn-align.stderr | 116 +++++++------- tests/ui/feature-gates/feature-gate-fn_align.rs | 14 +- .../ui/feature-gates/feature-gate-fn_align.stderr | 26 ++-- 25 files changed, 270 insertions(+), 255 deletions(-) delete mode 100644 tests/ui/attributes/fn-align-nameres-ambiguity-143834.stderr (limited to 'tests/codegen') diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 3157b18b635..9f99b33adcc 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -234,6 +234,7 @@ pub enum CfgEntry { pub enum AttributeKind { // tidy-alphabetical-start /// Represents `#[align(N)]`. + // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity Align { align: Align, span: Span }, /// Represents `#[rustc_allow_const_fn_unstable]`. diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 3e542771d58..bb28121c2c5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -177,7 +177,8 @@ impl AttributeParser for NakedParser { sym::instruction_set, sym::repr, sym::rustc_std_internal_symbol, - sym::align, + // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity + sym::rustc_align, // obviously compatible with self sym::naked, // documentation diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 6a45832ed7f..521acbb607c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -274,7 +274,7 @@ fn parse_alignment(node: &LitKind) -> Result { pub(crate) struct AlignParser(Option<(Align, Span)>); impl AlignParser { - const PATH: &'static [Symbol] = &[sym::align]; + const PATH: &'static [Symbol] = &[sym::rustc_align]; const TEMPLATE: AttributeTemplate = template!(List: ""); fn parse<'c, S: Stage>( diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 74872504b79..96df6aa19bc 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -490,7 +490,8 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No), - gated!(align, Normal, template!(List: "alignment"), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(align)), + // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity + gated!(rustc_align, Normal, template!(List: "alignment"), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(rustc_align)), ungated!(unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), ungated!(unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 6eae3b51e29..34a29acdc85 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -70,6 +70,7 @@ pub struct CodegenFnAttrs { /// switching between multiple instruction sets. pub instruction_set: Option, /// The `#[align(...)]` attribute. Determines the alignment of the function body. + // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity pub alignment: Option, /// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around /// the function entry. diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index a476f0db37e..cca621103b5 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -294,7 +294,9 @@ pub fn check_builtin_meta_item( | sym::rustc_paren_sugar | sym::type_const | sym::repr - | sym::align + // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres + // ambiguity + | sym::rustc_align | sym::deprecated | sym::optimize | sym::pointee diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index d1b856ca415..f5375f23541 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -14,7 +14,7 @@ passes_abi_of = fn_abi_of({$fn_name}) = {$fn_abi} passes_align_attr_application = - `#[align(...)]` should be applied to a function item + `#[rustc_align(...)]` should be applied to a function item .label = not a function item passes_align_on_fields = @@ -22,7 +22,7 @@ passes_align_on_fields = .warn = {-passes_previously_accepted} passes_align_should_be_repr_align = - `#[align(...)]` is not supported on {$item} items + `#[rustc_align(...)]` is not supported on {$item} items .suggestion = use `#[repr(align(...))]` instead passes_allow_incoherent_impl = @@ -604,7 +604,7 @@ passes_repr_align_greater_than_target_max = passes_repr_align_should_be_align = `#[repr(align(...))]` is not supported on {$item} items - .help = use `#[align(...)]` instead + .help = use `#[rustc_align(...)]` instead passes_repr_conflicting = conflicting representation hints diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2766b14bb8d..4f35bcc6be1 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1957,6 +1957,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if the `#[align]` attributes on `item` are valid. + // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity fn check_align( &self, span: Span, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d28a73bc139..762126a4aaa 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1809,6 +1809,8 @@ symbols! { rust_out, rustc, rustc_abi, + // FIXME(#82232, #143834): temporary name to mitigate `#[align]` nameres ambiguity + rustc_align, rustc_allocator, rustc_allocator_zeroed, rustc_allow_const_fn_unstable, diff --git a/src/tools/miri/tests/pass/fn_align.rs b/src/tools/miri/tests/pass/fn_align.rs index 28f92995880..9752d033458 100644 --- a/src/tools/miri/tests/pass/fn_align.rs +++ b/src/tools/miri/tests/pass/fn_align.rs @@ -1,15 +1,19 @@ //@compile-flags: -Zmin-function-alignment=8 + +// FIXME(rust-lang/rust#82232, rust-lang/rust#143834): temporarily renamed to mitigate `#[align]` +// nameres ambiguity +#![feature(rustc_attrs)] #![feature(fn_align)] // When a function uses `align(N)`, the function address should be a multiple of `N`. -#[align(256)] +#[rustc_align(256)] fn foo() {} -#[align(16)] +#[rustc_align(16)] fn bar() {} -#[align(4)] +#[rustc_align(4)] fn baz() {} fn main() { diff --git a/tests/codegen/align-fn.rs b/tests/codegen/align-fn.rs index fd572910c28..cbc24e2ae2e 100644 --- a/tests/codegen/align-fn.rs +++ b/tests/codegen/align-fn.rs @@ -3,11 +3,13 @@ //@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) #![crate_type = "lib"] +// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity +#![feature(rustc_attrs)] #![feature(fn_align)] // CHECK: align 16 #[unsafe(no_mangle)] -#[align(16)] +#[rustc_align(16)] pub fn fn_align() {} pub struct A; @@ -15,12 +17,12 @@ pub struct A; impl A { // CHECK: align 16 #[unsafe(no_mangle)] - #[align(16)] + #[rustc_align(16)] pub fn method_align(self) {} // CHECK: align 16 #[unsafe(no_mangle)] - #[align(16)] + #[rustc_align(16)] pub fn associated_fn() {} } @@ -29,18 +31,18 @@ trait T: Sized { fn trait_method(self) {} - #[align(8)] + #[rustc_align(8)] fn trait_method_inherit_low(self); - #[align(32)] + #[rustc_align(32)] fn trait_method_inherit_high(self); - #[align(32)] + #[rustc_align(32)] fn trait_method_inherit_default(self) {} - #[align(4)] - #[align(128)] - #[align(8)] + #[rustc_align(4)] + #[rustc_align(128)] + #[rustc_align(8)] fn inherit_highest(self) {} } @@ -48,27 +50,27 @@ impl T for A { // CHECK-LABEL: trait_fn // CHECK-SAME: align 16 #[unsafe(no_mangle)] - #[align(16)] + #[rustc_align(16)] fn trait_fn() {} // CHECK-LABEL: trait_method // CHECK-SAME: align 16 #[unsafe(no_mangle)] - #[align(16)] + #[rustc_align(16)] fn trait_method(self) {} // The prototype's align is ignored because the align here is higher. // CHECK-LABEL: trait_method_inherit_low // CHECK-SAME: align 16 #[unsafe(no_mangle)] - #[align(16)] + #[rustc_align(16)] fn trait_method_inherit_low(self) {} // The prototype's align is used because it is higher. // CHECK-LABEL: trait_method_inherit_high // CHECK-SAME: align 32 #[unsafe(no_mangle)] - #[align(16)] + #[rustc_align(16)] fn trait_method_inherit_high(self) {} // The prototype's align inherited. @@ -81,8 +83,8 @@ impl T for A { // CHECK-LABEL: inherit_highest // CHECK-SAME: align 128 #[unsafe(no_mangle)] - #[align(32)] - #[align(64)] + #[rustc_align(32)] + #[rustc_align(64)] fn inherit_highest(self) {} } @@ -90,7 +92,7 @@ trait HasDefaultImpl: Sized { // CHECK-LABEL: inherit_from_default_method // CHECK-LABEL: inherit_from_default_method // CHECK-SAME: align 32 - #[align(32)] + #[rustc_align(32)] fn inherit_from_default_method(self) {} } @@ -101,35 +103,35 @@ impl HasDefaultImpl for InstantiateDefaultMethods {} // CHECK-LABEL: align_specified_twice_1 // CHECK-SAME: align 64 #[unsafe(no_mangle)] -#[align(32)] -#[align(64)] +#[rustc_align(32)] +#[rustc_align(64)] pub fn align_specified_twice_1() {} // CHECK-LABEL: align_specified_twice_2 // CHECK-SAME: align 128 #[unsafe(no_mangle)] -#[align(128)] -#[align(32)] +#[rustc_align(128)] +#[rustc_align(32)] pub fn align_specified_twice_2() {} // CHECK-LABEL: align_specified_twice_3 // CHECK-SAME: align 256 #[unsafe(no_mangle)] -#[align(32)] -#[align(256)] +#[rustc_align(32)] +#[rustc_align(256)] pub fn align_specified_twice_3() {} const _: () = { // CHECK-LABEL: align_unmangled // CHECK-SAME: align 256 #[unsafe(no_mangle)] - #[align(32)] - #[align(256)] + #[rustc_align(32)] + #[rustc_align(256)] extern "C" fn align_unmangled() {} }; unsafe extern "C" { - #[align(256)] + #[rustc_align(256)] fn align_unmangled(); } @@ -137,5 +139,5 @@ unsafe extern "C" { // CHECK-LABEL: async_align // CHECK-SAME: align 64 #[unsafe(no_mangle)] -#[align(64)] +#[rustc_align(64)] pub async fn async_align() {} diff --git a/tests/codegen/min-function-alignment.rs b/tests/codegen/min-function-alignment.rs index 6a3843b0f4f..ea5f957e81f 100644 --- a/tests/codegen/min-function-alignment.rs +++ b/tests/codegen/min-function-alignment.rs @@ -5,6 +5,8 @@ //@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) #![crate_type = "lib"] +// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity +#![feature(rustc_attrs)] #![feature(fn_align)] // Functions without explicit alignment use the global minimum. @@ -21,7 +23,7 @@ pub fn no_explicit_align() {} // align16: align 16 // align1024: align 1024 #[no_mangle] -#[align(8)] +#[rustc_align(8)] pub fn lower_align() {} // the higher value of min-function-alignment and the align attribute wins out @@ -30,7 +32,7 @@ pub fn lower_align() {} // align16: align 32 // align1024: align 1024 #[no_mangle] -#[align(32)] +#[rustc_align(32)] pub fn higher_align() {} // cold functions follow the same rules as other functions diff --git a/tests/codegen/naked-fn/aligned.rs b/tests/codegen/naked-fn/aligned.rs index 2648b0213ca..d7281c4219a 100644 --- a/tests/codegen/naked-fn/aligned.rs +++ b/tests/codegen/naked-fn/aligned.rs @@ -4,12 +4,15 @@ //@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) #![crate_type = "lib"] +// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity +#![feature(rustc_attrs)] #![feature(fn_align)] + use std::arch::naked_asm; // CHECK: .balign 16 // CHECK-LABEL: naked_empty: -#[align(16)] +#[rustc_align(16)] #[no_mangle] #[unsafe(naked)] pub extern "C" fn naked_empty() { diff --git a/tests/codegen/naked-fn/min-function-alignment.rs b/tests/codegen/naked-fn/min-function-alignment.rs index 4ebaacd3eff..406e9334fa5 100644 --- a/tests/codegen/naked-fn/min-function-alignment.rs +++ b/tests/codegen/naked-fn/min-function-alignment.rs @@ -3,6 +3,8 @@ //@ ignore-arm no "ret" mnemonic //@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) +// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity +#![feature(rustc_attrs)] #![feature(fn_align)] #![crate_type = "lib"] @@ -17,7 +19,7 @@ pub extern "C" fn naked_no_explicit_align() { // CHECK: .balign 16 #[no_mangle] -#[align(8)] +#[rustc_align(8)] #[unsafe(naked)] pub extern "C" fn naked_lower_align() { core::arch::naked_asm!("ret") @@ -25,7 +27,7 @@ pub extern "C" fn naked_lower_align() { // CHECK: .balign 32 #[no_mangle] -#[align(32)] +#[rustc_align(32)] #[unsafe(naked)] pub extern "C" fn naked_higher_align() { core::arch::naked_asm!("ret") diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.rs b/tests/ui/asm/naked-with-invalid-repr-attr.rs index bfbbf29a69e..4620d007e4e 100644 --- a/tests/ui/asm/naked-with-invalid-repr-attr.rs +++ b/tests/ui/asm/naked-with-invalid-repr-attr.rs @@ -1,5 +1,9 @@ //@ needs-asm-support + +// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity +#![feature(rustc_attrs)] #![feature(fn_align)] + #![crate_type = "lib"] use std::arch::naked_asm; @@ -21,7 +25,7 @@ extern "C" fn example2() { #[repr(C)] //~^ ERROR attribute should be applied to a struct, enum, or union [E0517] -#[align(16)] +#[rustc_align(16)] #[unsafe(naked)] extern "C" fn example3() { //~^ NOTE not a struct, enum, or union diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.stderr b/tests/ui/asm/naked-with-invalid-repr-attr.stderr index 4eb4a4e5a04..8530495be66 100644 --- a/tests/ui/asm/naked-with-invalid-repr-attr.stderr +++ b/tests/ui/asm/naked-with-invalid-repr-attr.stderr @@ -1,5 +1,5 @@ error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/naked-with-invalid-repr-attr.rs:6:8 + --> $DIR/naked-with-invalid-repr-attr.rs:10:8 | LL | #[repr(C)] | ^ @@ -11,7 +11,7 @@ LL | | } | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/naked-with-invalid-repr-attr.rs:14:8 + --> $DIR/naked-with-invalid-repr-attr.rs:18:8 | LL | #[repr(transparent)] | ^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | | } | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/naked-with-invalid-repr-attr.rs:22:8 + --> $DIR/naked-with-invalid-repr-attr.rs:26:8 | LL | #[repr(C)] | ^ @@ -35,7 +35,7 @@ LL | | } | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/naked-with-invalid-repr-attr.rs:32:8 + --> $DIR/naked-with-invalid-repr-attr.rs:36:8 | LL | #[repr(C, packed)] | ^ @@ -48,7 +48,7 @@ LL | | } | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct or union - --> $DIR/naked-with-invalid-repr-attr.rs:32:11 + --> $DIR/naked-with-invalid-repr-attr.rs:36:11 | LL | #[repr(C, packed)] | ^^^^^^ @@ -61,7 +61,7 @@ LL | | } | |_- not a struct or union error[E0517]: attribute should be applied to an enum - --> $DIR/naked-with-invalid-repr-attr.rs:42:8 + --> $DIR/naked-with-invalid-repr-attr.rs:46:8 | LL | #[repr(u8)] | ^^ diff --git a/tests/ui/attributes/fn-align-dyn.rs b/tests/ui/attributes/fn-align-dyn.rs index 8ba4d5e2897..3778c75a2ca 100644 --- a/tests/ui/attributes/fn-align-dyn.rs +++ b/tests/ui/attributes/fn-align-dyn.rs @@ -1,12 +1,15 @@ //@ run-pass //@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) + +// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity +#![feature(rustc_attrs)] #![feature(fn_align)] trait Test { - #[align(4096)] + #[rustc_align(4096)] fn foo(&self); - #[align(4096)] + #[rustc_align(4096)] fn foo1(&self); } diff --git a/tests/ui/attributes/fn-align-nameres-ambiguity-143834.rs b/tests/ui/attributes/fn-align-nameres-ambiguity-143834.rs index 5629f92c468..536d6ff43fb 100644 --- a/tests/ui/attributes/fn-align-nameres-ambiguity-143834.rs +++ b/tests/ui/attributes/fn-align-nameres-ambiguity-143834.rs @@ -1,21 +1,19 @@ -//~ NOTE `align` could refer to a built-in attribute - // Anti-regression test to demonstrate that at least we mitigated breakage from adding a new // `#[align]` built-in attribute. +// +// See https://github.com/rust-lang/rust/issues/143834. + +//@ check-pass // Needs edition >= 2018 macro use behavior. //@ edition: 2018 macro_rules! align { - //~^ NOTE `align` could also refer to the macro defined here () => { /* .. */ }; } pub(crate) use align; -//~^ ERROR `align` is ambiguous -//~| NOTE ambiguous name -//~| NOTE ambiguous because of a name conflict with a builtin attribute fn main() {} diff --git a/tests/ui/attributes/fn-align-nameres-ambiguity-143834.stderr b/tests/ui/attributes/fn-align-nameres-ambiguity-143834.stderr deleted file mode 100644 index 304537173a8..00000000000 --- a/tests/ui/attributes/fn-align-nameres-ambiguity-143834.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0659]: `align` is ambiguous - --> $DIR/fn-align-nameres-ambiguity-143834.rs:16:16 - | -LL | pub(crate) use align; - | ^^^^^ ambiguous name - | - = note: ambiguous because of a name conflict with a builtin attribute - = note: `align` could refer to a built-in attribute -note: `align` could also refer to the macro defined here - --> $DIR/fn-align-nameres-ambiguity-143834.rs:9:1 - | -LL | / macro_rules! align { -LL | | -LL | | () => { -LL | | /* .. */ -LL | | }; -LL | | } - | |_^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index 5026687b97b..d4c6ecaa189 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -3,6 +3,7 @@ #![feature(rustc_attrs)] #![feature(rustc_allow_const_fn_unstable)] #![feature(allow_internal_unstable)] +// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity #![feature(fn_align)] #![feature(optimize_attribute)] #![feature(dropck_eyepatch)] @@ -53,7 +54,7 @@ #[inline = 5] //~^ ERROR valid forms for the attribute are //~| WARN this was previously accepted by the compiler -#[align] +#[rustc_align] //~^ ERROR malformed #[optimize] //~^ ERROR malformed diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 0d0c338d302..de53af851a3 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -1,5 +1,5 @@ error[E0539]: malformed `cfg` attribute input - --> $DIR/malformed-attrs.rs:102:1 + --> $DIR/malformed-attrs.rs:103:1 | LL | #[cfg] | ^^^^^^ @@ -8,7 +8,7 @@ LL | #[cfg] | help: must be of the form: `#[cfg(predicate)]` error: malformed `cfg_attr` attribute input - --> $DIR/malformed-attrs.rs:104:1 + --> $DIR/malformed-attrs.rs:105:1 | LL | #[cfg_attr] | ^^^^^^^^^^^ @@ -20,67 +20,67 @@ LL | #[cfg_attr(condition, attribute, other_attribute, ...)] | ++++++++++++++++++++++++++++++++++++++++++++ error[E0463]: can't find crate for `wloop` - --> $DIR/malformed-attrs.rs:211:1 + --> $DIR/malformed-attrs.rs:212:1 | LL | extern crate wloop; | ^^^^^^^^^^^^^^^^^^^ can't find crate error: malformed `windows_subsystem` attribute input - --> $DIR/malformed-attrs.rs:29:1 + --> $DIR/malformed-attrs.rs:30:1 | LL | #![windows_subsystem] | ^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![windows_subsystem = "windows|console"]` error: malformed `crate_name` attribute input - --> $DIR/malformed-attrs.rs:74:1 + --> $DIR/malformed-attrs.rs:75:1 | LL | #[crate_name] | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]` error: malformed `no_sanitize` attribute input - --> $DIR/malformed-attrs.rs:92:1 + --> $DIR/malformed-attrs.rs:93:1 | LL | #[no_sanitize] | ^^^^^^^^^^^^^^ help: must be of the form: `#[no_sanitize(address, kcfi, memory, thread)]` error: malformed `proc_macro` attribute input - --> $DIR/malformed-attrs.rs:99:1 + --> $DIR/malformed-attrs.rs:100:1 | LL | #[proc_macro = 18] | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]` error: malformed `instruction_set` attribute input - --> $DIR/malformed-attrs.rs:106:1 + --> $DIR/malformed-attrs.rs:107:1 | LL | #[instruction_set] | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[instruction_set(set)]` error: malformed `patchable_function_entry` attribute input - --> $DIR/malformed-attrs.rs:108:1 + --> $DIR/malformed-attrs.rs:109:1 | LL | #[patchable_function_entry] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` error: malformed `coroutine` attribute input - --> $DIR/malformed-attrs.rs:111:5 + --> $DIR/malformed-attrs.rs:112:5 | LL | #[coroutine = 63] || {} | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[coroutine]` error: malformed `proc_macro_attribute` attribute input - --> $DIR/malformed-attrs.rs:116:1 + --> $DIR/malformed-attrs.rs:117:1 | LL | #[proc_macro_attribute = 19] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]` error: malformed `proc_macro_derive` attribute input - --> $DIR/malformed-attrs.rs:123:1 + --> $DIR/malformed-attrs.rs:124:1 | LL | #[proc_macro_derive] | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` error: malformed `must_not_suspend` attribute input - --> $DIR/malformed-attrs.rs:132:1 + --> $DIR/malformed-attrs.rs:133:1 | LL | #[must_not_suspend()] | ^^^^^^^^^^^^^^^^^^^^^ @@ -95,67 +95,67 @@ LL + #[must_not_suspend] | error: malformed `cfi_encoding` attribute input - --> $DIR/malformed-attrs.rs:134:1 + --> $DIR/malformed-attrs.rs:135:1 | LL | #[cfi_encoding] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "encoding"]` error: malformed `linkage` attribute input - --> $DIR/malformed-attrs.rs:173:5 + --> $DIR/malformed-attrs.rs:174:5 | LL | #[linkage] | ^^^^^^^^^^ help: must be of the form: `#[linkage = "external|internal|..."]` error: malformed `allow` attribute input - --> $DIR/malformed-attrs.rs:178:1 + --> $DIR/malformed-attrs.rs:179:1 | LL | #[allow] | ^^^^^^^^ help: must be of the form: `#[allow(lint1, lint2, ..., /*opt*/ reason = "...")]` error: malformed `expect` attribute input - --> $DIR/malformed-attrs.rs:180:1 + --> $DIR/malformed-attrs.rs:181:1 | LL | #[expect] | ^^^^^^^^^ help: must be of the form: `#[expect(lint1, lint2, ..., /*opt*/ reason = "...")]` error: malformed `warn` attribute input - --> $DIR/malformed-attrs.rs:182:1 + --> $DIR/malformed-attrs.rs:183:1 | LL | #[warn] | ^^^^^^^ help: must be of the form: `#[warn(lint1, lint2, ..., /*opt*/ reason = "...")]` error: malformed `deny` attribute input - --> $DIR/malformed-attrs.rs:184:1 + --> $DIR/malformed-attrs.rs:185:1 | LL | #[deny] | ^^^^^^^ help: must be of the form: `#[deny(lint1, lint2, ..., /*opt*/ reason = "...")]` error: malformed `forbid` attribute input - --> $DIR/malformed-attrs.rs:186:1 + --> $DIR/malformed-attrs.rs:187:1 | LL | #[forbid] | ^^^^^^^^^ help: must be of the form: `#[forbid(lint1, lint2, ..., /*opt*/ reason = "...")]` error: malformed `debugger_visualizer` attribute input - --> $DIR/malformed-attrs.rs:188:1 + --> $DIR/malformed-attrs.rs:189:1 | LL | #[debugger_visualizer] | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]` error: malformed `thread_local` attribute input - --> $DIR/malformed-attrs.rs:203:1 + --> $DIR/malformed-attrs.rs:204:1 | LL | #[thread_local()] | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[thread_local]` error: malformed `no_link` attribute input - --> $DIR/malformed-attrs.rs:207:1 + --> $DIR/malformed-attrs.rs:208:1 | LL | #[no_link()] | ^^^^^^^^^^^^ help: must be of the form: `#[no_link]` error: malformed `macro_use` attribute input - --> $DIR/malformed-attrs.rs:209:1 + --> $DIR/malformed-attrs.rs:210:1 | LL | #[macro_use = 1] | ^^^^^^^^^^^^^^^^ @@ -170,7 +170,7 @@ LL + #[macro_use] | error: malformed `macro_export` attribute input - --> $DIR/malformed-attrs.rs:214:1 + --> $DIR/malformed-attrs.rs:215:1 | LL | #[macro_export = 18] | ^^^^^^^^^^^^^^^^^^^^ @@ -185,31 +185,31 @@ LL + #[macro_export] | error: malformed `allow_internal_unsafe` attribute input - --> $DIR/malformed-attrs.rs:216:1 + --> $DIR/malformed-attrs.rs:217:1 | LL | #[allow_internal_unsafe = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[allow_internal_unsafe]` error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:99:1 + --> $DIR/malformed-attrs.rs:100:1 | LL | #[proc_macro = 18] | ^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:116:1 + --> $DIR/malformed-attrs.rs:117:1 | LL | #[proc_macro_attribute = 19] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:123:1 + --> $DIR/malformed-attrs.rs:124:1 | LL | #[proc_macro_derive] | ^^^^^^^^^^^^^^^^^^^^ error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint - --> $DIR/malformed-attrs.rs:216:1 + --> $DIR/malformed-attrs.rs:217:1 | LL | #[allow_internal_unsafe = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -218,7 +218,7 @@ LL | #[allow_internal_unsafe = 1] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]` - --> $DIR/malformed-attrs.rs:43:1 + --> $DIR/malformed-attrs.rs:44:1 | LL | #[doc] | ^^^^^^ @@ -228,7 +228,7 @@ LL | #[doc] = note: `#[deny(ill_formed_attribute_input)]` on by default error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]` - --> $DIR/malformed-attrs.rs:76:1 + --> $DIR/malformed-attrs.rs:77:1 | LL | #[doc] | ^^^^^^ @@ -237,7 +237,7 @@ LL | #[doc] = note: for more information, see issue #57571 error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]` - --> $DIR/malformed-attrs.rs:83:1 + --> $DIR/malformed-attrs.rs:84:1 | LL | #[link] | ^^^^^^^ @@ -246,7 +246,7 @@ LL | #[link] = note: for more information, see issue #57571 error: invalid argument - --> $DIR/malformed-attrs.rs:188:1 + --> $DIR/malformed-attrs.rs:189:1 | LL | #[debugger_visualizer] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -256,7 +256,7 @@ LL | #[debugger_visualizer] = note: expected: `gdb_script_file = "..."` error[E0565]: malformed `omit_gdb_pretty_printer_section` attribute input - --> $DIR/malformed-attrs.rs:26:1 + --> $DIR/malformed-attrs.rs:27:1 | LL | #![omit_gdb_pretty_printer_section = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^ @@ -265,25 +265,25 @@ LL | #![omit_gdb_pretty_printer_section = 1] | help: must be of the form: `#[omit_gdb_pretty_printer_section]` error[E0539]: malformed `export_name` attribute input - --> $DIR/malformed-attrs.rs:32:1 + --> $DIR/malformed-attrs.rs:33:1 | LL | #[unsafe(export_name)] | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_name = "name"]` error: `rustc_allow_const_fn_unstable` expects a list of feature names - --> $DIR/malformed-attrs.rs:34:1 + --> $DIR/malformed-attrs.rs:35:1 | LL | #[rustc_allow_const_fn_unstable] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `allow_internal_unstable` expects a list of feature names - --> $DIR/malformed-attrs.rs:37:1 + --> $DIR/malformed-attrs.rs:38:1 | LL | #[allow_internal_unstable] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0539]: malformed `rustc_confusables` attribute input - --> $DIR/malformed-attrs.rs:39:1 + --> $DIR/malformed-attrs.rs:40:1 | LL | #[rustc_confusables] | ^^^^^^^^^^^^^^^^^^^^ @@ -292,7 +292,7 @@ LL | #[rustc_confusables] | help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` error[E0539]: malformed `deprecated` attribute input - --> $DIR/malformed-attrs.rs:41:1 + --> $DIR/malformed-attrs.rs:42:1 | LL | #[deprecated = 5] | ^^^^^^^^^^^^^^^-^ @@ -312,13 +312,13 @@ LL + #[deprecated] | error[E0539]: malformed `rustc_macro_transparency` attribute input - --> $DIR/malformed-attrs.rs:46:1 + --> $DIR/malformed-attrs.rs:47:1 | LL | #[rustc_macro_transparency] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_macro_transparency = "transparent|semitransparent|opaque"]` error[E0539]: malformed `repr` attribute input - --> $DIR/malformed-attrs.rs:48:1 + --> $DIR/malformed-attrs.rs:49:1 | LL | #[repr] | ^^^^^^^ @@ -327,7 +327,7 @@ LL | #[repr] | help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | | transparent)]` error[E0565]: malformed `rustc_as_ptr` attribute input - --> $DIR/malformed-attrs.rs:51:1 + --> $DIR/malformed-attrs.rs:52:1 | LL | #[rustc_as_ptr = 5] | ^^^^^^^^^^^^^^^---^ @@ -335,17 +335,17 @@ LL | #[rustc_as_ptr = 5] | | didn't expect any arguments here | help: must be of the form: `#[rustc_as_ptr]` -error[E0539]: malformed `align` attribute input - --> $DIR/malformed-attrs.rs:56:1 +error[E0539]: malformed `rustc_align` attribute input + --> $DIR/malformed-attrs.rs:57:1 | -LL | #[align] - | ^^^^^^^^ +LL | #[rustc_align] + | ^^^^^^^^^^^^^^ | | | expected this to be a list - | help: must be of the form: `#[align()]` + | help: must be of the form: `#[rustc_align()]` error[E0539]: malformed `optimize` attribute input - --> $DIR/malformed-attrs.rs:58:1 + --> $DIR/malformed-attrs.rs:59:1 | LL | #[optimize] | ^^^^^^^^^^^ @@ -354,7 +354,7 @@ LL | #[optimize] | help: must be of the form: `#[optimize(size|speed|none)]` error[E0565]: malformed `cold` attribute input - --> $DIR/malformed-attrs.rs:60:1 + --> $DIR/malformed-attrs.rs:61:1 | LL | #[cold = 1] | ^^^^^^^---^ @@ -363,13 +363,13 @@ LL | #[cold = 1] | help: must be of the form: `#[cold]` error: valid forms for the attribute are `#[must_use = "reason"]` and `#[must_use]` - --> $DIR/malformed-attrs.rs:62:1 + --> $DIR/malformed-attrs.rs:63:1 | LL | #[must_use()] | ^^^^^^^^^^^^^ error[E0565]: malformed `no_mangle` attribute input - --> $DIR/malformed-attrs.rs:64:1 + --> $DIR/malformed-attrs.rs:65:1 | LL | #[no_mangle = 1] | ^^^^^^^^^^^^---^ @@ -378,7 +378,7 @@ LL | #[no_mangle = 1] | help: must be of the form: `#[no_mangle]` error[E0565]: malformed `naked` attribute input - --> $DIR/malformed-attrs.rs:66:1 + --> $DIR/malformed-attrs.rs:67:1 | LL | #[unsafe(naked())] | ^^^^^^^^^^^^^^--^^ @@ -387,7 +387,7 @@ LL | #[unsafe(naked())] | help: must be of the form: `#[naked]` error[E0565]: malformed `track_caller` attribute input - --> $DIR/malformed-attrs.rs:68:1 + --> $DIR/malformed-attrs.rs:69:1 | LL | #[track_caller()] | ^^^^^^^^^^^^^^--^ @@ -396,13 +396,13 @@ LL | #[track_caller()] | help: must be of the form: `#[track_caller]` error[E0539]: malformed `export_name` attribute input - --> $DIR/malformed-attrs.rs:70:1 + --> $DIR/malformed-attrs.rs:71:1 | LL | #[export_name()] | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_name = "name"]` error[E0805]: malformed `used` attribute input - --> $DIR/malformed-attrs.rs:72:1 + --> $DIR/malformed-attrs.rs:73:1 | LL | #[used()] | ^^^^^^--^ @@ -418,7 +418,7 @@ LL + #[used] | error[E0539]: malformed `target_feature` attribute input - --> $DIR/malformed-attrs.rs:79:1 + --> $DIR/malformed-attrs.rs:80:1 | LL | #[target_feature] | ^^^^^^^^^^^^^^^^^ @@ -427,7 +427,7 @@ LL | #[target_feature] | help: must be of the form: `#[target_feature(enable = "feat1, feat2")]` error[E0565]: malformed `export_stable` attribute input - --> $DIR/malformed-attrs.rs:81:1 + --> $DIR/malformed-attrs.rs:82:1 | LL | #[export_stable = 1] | ^^^^^^^^^^^^^^^^---^ @@ -436,19 +436,19 @@ LL | #[export_stable = 1] | help: must be of the form: `#[export_stable]` error[E0539]: malformed `link_name` attribute input - --> $DIR/malformed-attrs.rs:86:1 + --> $DIR/malformed-attrs.rs:87:1 | LL | #[link_name] | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]` error[E0539]: malformed `link_section` attribute input - --> $DIR/malformed-attrs.rs:88:1 + --> $DIR/malformed-attrs.rs:89:1 | LL | #[link_section] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]` error[E0539]: malformed `coverage` attribute input - --> $DIR/malformed-attrs.rs:90:1 + --> $DIR/malformed-attrs.rs:91:1 | LL | #[coverage] | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -461,7 +461,7 @@ LL | #[coverage(on)] | ++++ error[E0565]: malformed `no_implicit_prelude` attribute input - --> $DIR/malformed-attrs.rs:97:1 + --> $DIR/malformed-attrs.rs:98:1 | LL | #[no_implicit_prelude = 23] | ^^^^^^^^^^^^^^^^^^^^^^----^ @@ -470,7 +470,7 @@ LL | #[no_implicit_prelude = 23] | help: must be of the form: `#[no_implicit_prelude]` error[E0539]: malformed `must_use` attribute input - --> $DIR/malformed-attrs.rs:119:1 + --> $DIR/malformed-attrs.rs:120:1 | LL | #[must_use = 1] | ^^^^^^^^^^^^^-^ @@ -487,7 +487,7 @@ LL + #[must_use] | error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input - --> $DIR/malformed-attrs.rs:128:1 + --> $DIR/malformed-attrs.rs:129:1 | LL | #[rustc_layout_scalar_valid_range_start] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -496,7 +496,7 @@ LL | #[rustc_layout_scalar_valid_range_start] | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]` error[E0539]: malformed `rustc_layout_scalar_valid_range_end` attribute input - --> $DIR/malformed-attrs.rs:130:1 + --> $DIR/malformed-attrs.rs:131:1 | LL | #[rustc_layout_scalar_valid_range_end] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -505,7 +505,7 @@ LL | #[rustc_layout_scalar_valid_range_end] | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]` error[E0565]: malformed `marker` attribute input - --> $DIR/malformed-attrs.rs:155:1 + --> $DIR/malformed-attrs.rs:156:1 | LL | #[marker = 3] | ^^^^^^^^^---^ @@ -514,7 +514,7 @@ LL | #[marker = 3] | help: must be of the form: `#[marker]` error[E0565]: malformed `fundamental` attribute input - --> $DIR/malformed-attrs.rs:157:1 + --> $DIR/malformed-attrs.rs:158:1 | LL | #[fundamental()] | ^^^^^^^^^^^^^--^ @@ -523,7 +523,7 @@ LL | #[fundamental()] | help: must be of the form: `#[fundamental]` error[E0565]: malformed `ffi_pure` attribute input - --> $DIR/malformed-attrs.rs:165:5 + --> $DIR/malformed-attrs.rs:166:5 | LL | #[unsafe(ffi_pure = 1)] | ^^^^^^^^^^^^^^^^^^---^^ @@ -532,7 +532,7 @@ LL | #[unsafe(ffi_pure = 1)] | help: must be of the form: `#[ffi_pure]` error[E0539]: malformed `link_ordinal` attribute input - --> $DIR/malformed-attrs.rs:167:5 + --> $DIR/malformed-attrs.rs:168:5 | LL | #[link_ordinal] | ^^^^^^^^^^^^^^^ @@ -541,7 +541,7 @@ LL | #[link_ordinal] | help: must be of the form: `#[link_ordinal(ordinal)]` error[E0565]: malformed `ffi_const` attribute input - --> $DIR/malformed-attrs.rs:171:5 + --> $DIR/malformed-attrs.rs:172:5 | LL | #[unsafe(ffi_const = 1)] | ^^^^^^^^^^^^^^^^^^^---^^ @@ -550,7 +550,7 @@ LL | #[unsafe(ffi_const = 1)] | help: must be of the form: `#[ffi_const]` error[E0565]: malformed `automatically_derived` attribute input - --> $DIR/malformed-attrs.rs:191:1 + --> $DIR/malformed-attrs.rs:192:1 | LL | #[automatically_derived = 18] | ^^^^^^^^^^^^^^^^^^^^^^^^----^ @@ -559,7 +559,7 @@ LL | #[automatically_derived = 18] | help: must be of the form: `#[automatically_derived]` error[E0565]: malformed `non_exhaustive` attribute input - --> $DIR/malformed-attrs.rs:197:1 + --> $DIR/malformed-attrs.rs:198:1 | LL | #[non_exhaustive = 1] | ^^^^^^^^^^^^^^^^^---^ @@ -568,7 +568,7 @@ LL | #[non_exhaustive = 1] | help: must be of the form: `#[non_exhaustive]` error[E0565]: malformed `type_const` attribute input - --> $DIR/malformed-attrs.rs:143:5 + --> $DIR/malformed-attrs.rs:144:5 | LL | #[type_const = 1] | ^^^^^^^^^^^^^---^ @@ -577,7 +577,7 @@ LL | #[type_const = 1] | help: must be of the form: `#[type_const]` error: attribute should be applied to `const fn` - --> $DIR/malformed-attrs.rs:34:1 + --> $DIR/malformed-attrs.rs:35:1 | LL | #[rustc_allow_const_fn_unstable] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -589,19 +589,19 @@ LL | | } | |_- not a `const fn` error: `#[repr(align(...))]` is not supported on function items - --> $DIR/malformed-attrs.rs:48:1 + --> $DIR/malformed-attrs.rs:49:1 | LL | #[repr] | ^^^^^^^ | -help: use `#[align(...)]` instead - --> $DIR/malformed-attrs.rs:48:1 +help: use `#[rustc_align(...)]` instead + --> $DIR/malformed-attrs.rs:49:1 | LL | #[repr] | ^^^^^^^ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/malformed-attrs.rs:149:1 + --> $DIR/malformed-attrs.rs:150:1 | LL | #[diagnostic::do_not_recommend()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -609,7 +609,7 @@ LL | #[diagnostic::do_not_recommend()] = note: `#[warn(malformed_diagnostic_attributes)]` on by default warning: missing options for `on_unimplemented` attribute - --> $DIR/malformed-attrs.rs:138:1 + --> $DIR/malformed-attrs.rs:139:1 | LL | #[diagnostic::on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -617,7 +617,7 @@ LL | #[diagnostic::on_unimplemented] = help: at least one of the `message`, `note` and `label` options are expected warning: malformed `on_unimplemented` attribute - --> $DIR/malformed-attrs.rs:140:1 + --> $DIR/malformed-attrs.rs:141:1 | LL | #[diagnostic::on_unimplemented = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -625,7 +625,7 @@ LL | #[diagnostic::on_unimplemented = 1] = help: only `message`, `note` and `label` are allowed as options error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]` - --> $DIR/malformed-attrs.rs:53:1 + --> $DIR/malformed-attrs.rs:54:1 | LL | #[inline = 5] | ^^^^^^^^^^^^^ @@ -634,7 +634,7 @@ LL | #[inline = 5] = note: for more information, see issue #57571 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:94:1 + --> $DIR/malformed-attrs.rs:95:1 | LL | #[ignore()] | ^^^^^^^^^^^ @@ -643,7 +643,7 @@ LL | #[ignore()] = note: for more information, see issue #57571 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:223:1 + --> $DIR/malformed-attrs.rs:224:1 | LL | #[ignore = 1] | ^^^^^^^^^^^^^ @@ -652,7 +652,7 @@ LL | #[ignore = 1] = note: for more information, see issue #57571 error[E0308]: mismatched types - --> $DIR/malformed-attrs.rs:111:23 + --> $DIR/malformed-attrs.rs:112:23 | LL | fn test() { | - help: a return type might be missing here: `-> _` @@ -660,7 +660,7 @@ LL | #[coroutine = 63] || {} | ^^^^^ expected `()`, found coroutine | = note: expected unit type `()` - found coroutine `{coroutine@$DIR/malformed-attrs.rs:111:23: 111:25}` + found coroutine `{coroutine@$DIR/malformed-attrs.rs:112:23: 112:25}` error: aborting due to 75 previous errors; 3 warnings emitted diff --git a/tests/ui/attributes/malformed-fn-align.rs b/tests/ui/attributes/malformed-fn-align.rs index e06e6116842..cf143b28e54 100644 --- a/tests/ui/attributes/malformed-fn-align.rs +++ b/tests/ui/attributes/malformed-fn-align.rs @@ -1,49 +1,54 @@ +// ignore-tidy-linelength + +// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity +#![feature(rustc_attrs)] #![feature(fn_align)] + #![crate_type = "lib"] trait MyTrait { - #[align] //~ ERROR malformed `align` attribute input + #[rustc_align] //~ ERROR malformed `rustc_align` attribute input fn myfun1(); - #[align(1, 2)] //~ ERROR malformed `align` attribute input + #[rustc_align(1, 2)] //~ ERROR malformed `rustc_align` attribute input fn myfun2(); } -#[align = 16] //~ ERROR malformed `align` attribute input +#[rustc_align = 16] //~ ERROR malformed `rustc_align` attribute input fn f1() {} -#[align("hello")] //~ ERROR invalid alignment value: not an unsuffixed integer +#[rustc_align("hello")] //~ ERROR invalid alignment value: not an unsuffixed integer fn f2() {} -#[align(0)] //~ ERROR invalid alignment value: not a power of two +#[rustc_align(0)] //~ ERROR invalid alignment value: not a power of two fn f3() {} #[repr(align(16))] //~ ERROR `#[repr(align(...))]` is not supported on function items fn f4() {} -#[align(-1)] //~ ERROR expected unsuffixed literal, found `-` +#[rustc_align(-1)] //~ ERROR expected unsuffixed literal, found `-` fn f5() {} -#[align(3)] //~ ERROR invalid alignment value: not a power of two +#[rustc_align(3)] //~ ERROR invalid alignment value: not a power of two fn f6() {} -#[align(4usize)] //~ ERROR invalid alignment value: not an unsuffixed integer [E0589] +#[rustc_align(4usize)] //~ ERROR invalid alignment value: not an unsuffixed integer [E0589] //~^ ERROR suffixed literals are not allowed in attributes fn f7() {} -#[align(16)] -#[align(3)] //~ ERROR invalid alignment value: not a power of two -#[align(16)] +#[rustc_align(16)] +#[rustc_align(3)] //~ ERROR invalid alignment value: not a power of two +#[rustc_align(16)] fn f8() {} -#[align(16)] //~ ERROR `#[align(...)]` is not supported on struct items +#[rustc_align(16)] //~ ERROR `#[rustc_align(...)]` is not supported on struct items struct S1; -#[align(32)] //~ ERROR `#[align(...)]` should be applied to a function item +#[rustc_align(32)] //~ ERROR `#[rustc_align(...)]` should be applied to a function item const FOO: i32 = 42; -#[align(32)] //~ ERROR `#[align(...)]` should be applied to a function item +#[rustc_align(32)] //~ ERROR `#[rustc_align(...)]` should be applied to a function item mod test {} -#[align(32)] //~ ERROR `#[align(...)]` should be applied to a function item +#[rustc_align(32)] //~ ERROR `#[rustc_align(...)]` should be applied to a function item use ::std::iter; diff --git a/tests/ui/attributes/malformed-fn-align.stderr b/tests/ui/attributes/malformed-fn-align.stderr index af3625b1f3b..d995a7bf070 100644 --- a/tests/ui/attributes/malformed-fn-align.stderr +++ b/tests/ui/attributes/malformed-fn-align.stderr @@ -1,119 +1,119 @@ error: expected unsuffixed literal, found `-` - --> $DIR/malformed-fn-align.rs:24:9 + --> $DIR/malformed-fn-align.rs:29:15 | -LL | #[align(-1)] - | ^ +LL | #[rustc_align(-1)] + | ^ error: suffixed literals are not allowed in attributes - --> $DIR/malformed-fn-align.rs:30:9 + --> $DIR/malformed-fn-align.rs:35:15 | -LL | #[align(4usize)] - | ^^^^^^ +LL | #[rustc_align(4usize)] + | ^^^^^^ | = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) -error[E0539]: malformed `align` attribute input - --> $DIR/malformed-fn-align.rs:5:5 +error[E0539]: malformed `rustc_align` attribute input + --> $DIR/malformed-fn-align.rs:10:5 | -LL | #[align] - | ^^^^^^^^ +LL | #[rustc_align] + | ^^^^^^^^^^^^^^ | | | expected this to be a list - | help: must be of the form: `#[align()]` + | help: must be of the form: `#[rustc_align()]` -error[E0805]: malformed `align` attribute input - --> $DIR/malformed-fn-align.rs:8:5 +error[E0805]: malformed `rustc_align` attribute input + --> $DIR/malformed-fn-align.rs:13:5 | -LL | #[align(1, 2)] - | ^^^^^^^------^ - | | | - | | expected a single argument here - | help: must be of the form: `#[align()]` +LL | #[rustc_align(1, 2)] + | ^^^^^^^^^^^^^------^ + | | | + | | expected a single argument here + | help: must be of the form: `#[rustc_align()]` -error[E0539]: malformed `align` attribute input - --> $DIR/malformed-fn-align.rs:12:1 +error[E0539]: malformed `rustc_align` attribute input + --> $DIR/malformed-fn-align.rs:17:1 | -LL | #[align = 16] - | ^^^^^^^^^^^^^ +LL | #[rustc_align = 16] + | ^^^^^^^^^^^^^^^^^^^ | | | expected this to be a list - | help: must be of the form: `#[align()]` + | help: must be of the form: `#[rustc_align()]` error[E0589]: invalid alignment value: not an unsuffixed integer - --> $DIR/malformed-fn-align.rs:15:9 + --> $DIR/malformed-fn-align.rs:20:15 | -LL | #[align("hello")] - | ^^^^^^^ +LL | #[rustc_align("hello")] + | ^^^^^^^ error[E0589]: invalid alignment value: not a power of two - --> $DIR/malformed-fn-align.rs:18:9 + --> $DIR/malformed-fn-align.rs:23:15 | -LL | #[align(0)] - | ^ +LL | #[rustc_align(0)] + | ^ error[E0589]: invalid alignment value: not a power of two - --> $DIR/malformed-fn-align.rs:27:9 + --> $DIR/malformed-fn-align.rs:32:15 | -LL | #[align(3)] - | ^ +LL | #[rustc_align(3)] + | ^ error[E0589]: invalid alignment value: not an unsuffixed integer - --> $DIR/malformed-fn-align.rs:30:9 + --> $DIR/malformed-fn-align.rs:35:15 | -LL | #[align(4usize)] - | ^^^^^^ +LL | #[rustc_align(4usize)] + | ^^^^^^ error[E0589]: invalid alignment value: not a power of two - --> $DIR/malformed-fn-align.rs:35:9 + --> $DIR/malformed-fn-align.rs:40:15 | -LL | #[align(3)] - | ^ +LL | #[rustc_align(3)] + | ^ error: `#[repr(align(...))]` is not supported on function items - --> $DIR/malformed-fn-align.rs:21:8 + --> $DIR/malformed-fn-align.rs:26:8 | LL | #[repr(align(16))] | ^^^^^^^^^ | -help: use `#[align(...)]` instead - --> $DIR/malformed-fn-align.rs:21:8 +help: use `#[rustc_align(...)]` instead + --> $DIR/malformed-fn-align.rs:26:8 | LL | #[repr(align(16))] | ^^^^^^^^^ -error: `#[align(...)]` is not supported on struct items - --> $DIR/malformed-fn-align.rs:39:1 +error: `#[rustc_align(...)]` is not supported on struct items + --> $DIR/malformed-fn-align.rs:44:1 | -LL | #[align(16)] - | ^^^^^^^^^^^^ +LL | #[rustc_align(16)] + | ^^^^^^^^^^^^^^^^^^ | help: use `#[repr(align(...))]` instead | -LL - #[align(16)] +LL - #[rustc_align(16)] LL + #[repr(align(16))] | -error: `#[align(...)]` should be applied to a function item - --> $DIR/malformed-fn-align.rs:42:1 +error: `#[rustc_align(...)]` should be applied to a function item + --> $DIR/malformed-fn-align.rs:47:1 | -LL | #[align(32)] - | ^^^^^^^^^^^^ +LL | #[rustc_align(32)] + | ^^^^^^^^^^^^^^^^^^ LL | const FOO: i32 = 42; | -------------------- not a function item -error: `#[align(...)]` should be applied to a function item - --> $DIR/malformed-fn-align.rs:45:1 +error: `#[rustc_align(...)]` should be applied to a function item + --> $DIR/malformed-fn-align.rs:50:1 | -LL | #[align(32)] - | ^^^^^^^^^^^^ +LL | #[rustc_align(32)] + | ^^^^^^^^^^^^^^^^^^ LL | mod test {} | ----------- not a function item -error: `#[align(...)]` should be applied to a function item - --> $DIR/malformed-fn-align.rs:48:1 +error: `#[rustc_align(...)]` should be applied to a function item + --> $DIR/malformed-fn-align.rs:53:1 | -LL | #[align(32)] - | ^^^^^^^^^^^^ +LL | #[rustc_align(32)] + | ^^^^^^^^^^^^^^^^^^ LL | use ::std::iter; | ---------------- not a function item diff --git a/tests/ui/feature-gates/feature-gate-fn_align.rs b/tests/ui/feature-gates/feature-gate-fn_align.rs index b6c300e5cbe..36e17c4a8dd 100644 --- a/tests/ui/feature-gates/feature-gate-fn_align.rs +++ b/tests/ui/feature-gates/feature-gate-fn_align.rs @@ -1,12 +1,16 @@ #![crate_type = "lib"] -#[align(16)] -//~^ ERROR the `#[align]` attribute is an experimental feature +// ignore-tidy-linelength + +// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity + +#[rustc_align(16)] +//~^ ERROR the `#[rustc_align]` attribute is an experimental feature fn requires_alignment() {} trait MyTrait { - #[align] - //~^ ERROR the `#[align]` attribute is an experimental feature - //~| ERROR malformed `align` attribute input + #[rustc_align] + //~^ ERROR the `#[rustc_align]` attribute is an experimental feature + //~| ERROR malformed `rustc_align` attribute input fn myfun(); } diff --git a/tests/ui/feature-gates/feature-gate-fn_align.stderr b/tests/ui/feature-gates/feature-gate-fn_align.stderr index 921cf08435c..6196f4f298f 100644 --- a/tests/ui/feature-gates/feature-gate-fn_align.stderr +++ b/tests/ui/feature-gates/feature-gate-fn_align.stderr @@ -1,31 +1,31 @@ -error[E0658]: the `#[align]` attribute is an experimental feature - --> $DIR/feature-gate-fn_align.rs:3:1 +error[E0658]: the `#[rustc_align]` attribute is an experimental feature + --> $DIR/feature-gate-fn_align.rs:7:1 | -LL | #[align(16)] - | ^^^^^^^^^^^^ +LL | #[rustc_align(16)] + | ^^^^^^^^^^^^^^^^^^ | = note: see issue #82232 for more information = help: add `#![feature(fn_align)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: the `#[align]` attribute is an experimental feature - --> $DIR/feature-gate-fn_align.rs:8:5 +error[E0658]: the `#[rustc_align]` attribute is an experimental feature + --> $DIR/feature-gate-fn_align.rs:12:5 | -LL | #[align] - | ^^^^^^^^ +LL | #[rustc_align] + | ^^^^^^^^^^^^^^ | = note: see issue #82232 for more information = help: add `#![feature(fn_align)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0539]: malformed `align` attribute input - --> $DIR/feature-gate-fn_align.rs:8:5 +error[E0539]: malformed `rustc_align` attribute input + --> $DIR/feature-gate-fn_align.rs:12:5 | -LL | #[align] - | ^^^^^^^^ +LL | #[rustc_align] + | ^^^^^^^^^^^^^^ | | | expected this to be a list - | help: must be of the form: `#[align()]` + | help: must be of the form: `#[rustc_align()]` error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From e2ab312c9408761faf64723c77cd4ba4a58792bc Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Fri, 18 Jul 2025 16:00:04 -0700 Subject: add gpu offload codegen host side test --- tests/codegen/gpu_offload/gpu_host.rs | 80 +++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 tests/codegen/gpu_offload/gpu_host.rs (limited to 'tests/codegen') diff --git a/tests/codegen/gpu_offload/gpu_host.rs b/tests/codegen/gpu_offload/gpu_host.rs new file mode 100644 index 00000000000..513e27426bc --- /dev/null +++ b/tests/codegen/gpu_offload/gpu_host.rs @@ -0,0 +1,80 @@ +//@ compile-flags: -Zoffload=Enable -Zunstable-options -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme + +// This test is verifying that we generate __tgt_target_data_*_mapper before and after a call to the +// kernel_1. Better documentation to what each global or variable means is available in the gpu +// offlaod code, or the LLVM offload documentation. This code does not launch any GPU kernels yet, +// and will be rewritten once a proper offload frontend has landed. +// +// We currently only handle memory transfer for specific calls to functions named `kernel_{num}`, +// when inside of a function called main. This, too, is a temporary workaround for not having a +// frontend. + +#![no_main] + +#[unsafe(no_mangle)] +fn main() { + let mut x = [3.0; 256]; + kernel_1(&mut x); + core::hint::black_box(&x); +} + +// CHECK: %struct.__tgt_offload_entry = type { i64, i16, i16, i32, ptr, ptr, i64, i64, ptr } +// CHECK: %struct.__tgt_kernel_arguments = type { i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, i64, i64, [3 x i32], [3 x i32], i32 } +// CHECK: %struct.ident_t = type { i32, i32, i32, i32, ptr } +// CHECK: %struct.__tgt_bin_desc = type { i32, ptr, ptr, ptr } + +// CHECK: @.offload_sizes.1 = private unnamed_addr constant [1 x i64] [i64 1024] +// CHECK: @.offload_maptypes.1 = private unnamed_addr constant [1 x i64] [i64 3] +// CHECK: @.kernel_1.region_id = weak unnamed_addr constant i8 0 +// CHECK: @.offloading.entry_name.1 = internal unnamed_addr constant [9 x i8] c"kernel_1\00", section ".llvm.rodata.offloading", align 1 +// CHECK: @.offloading.entry.kernel_1 = weak constant %struct.__tgt_offload_entry { i64 0, i16 1, i16 1, i32 0, ptr @.kernel_1.region_id, ptr @.offloading.entry_name.1, i64 0, i64 0, ptr null }, section ".omp_offloading_entries", align 1 +// CHECK: @my_struct_global2 = external global %struct.__tgt_kernel_arguments +// CHECK: @0 = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00", align 1 +// CHECK: @1 = private unnamed_addr constant %struct.ident_t { i32 0, i32 2, i32 0, i32 22, ptr @0 }, align 8 + +// CHECK: Function Attrs: +// CHECK-NEXT: define{{( dso_local)?}} void @main() +// CHECK-NEXT: start: +// CHECK-NEXT: %0 = alloca [8 x i8], align 8 +// CHECK-NEXT: %x = alloca [1024 x i8], align 16 +// CHECK-NEXT: %EmptyDesc = alloca %struct.__tgt_bin_desc, align 8 +// CHECK-NEXT: %.offload_baseptrs = alloca [1 x ptr], align 8 +// CHECK-NEXT: %.offload_ptrs = alloca [1 x ptr], align 8 +// CHECK-NEXT: %.offload_sizes = alloca [1 x i64], align 8 +// CHECK-NEXT: %x.addr = alloca ptr, align 8 +// CHECK-NEXT: store ptr %x, ptr %x.addr, align 8 +// CHECK-NEXT: %1 = load ptr, ptr %x.addr, align 8 +// CHECK-NEXT: %2 = getelementptr inbounds float, ptr %1, i32 0 +// CHECK: call void @llvm.memset.p0.i64(ptr align 8 %EmptyDesc, i8 0, i64 32, i1 false) +// CHECK-NEXT: call void @__tgt_register_lib(ptr %EmptyDesc) +// CHECK-NEXT: call void @__tgt_init_all_rtls() +// CHECK-NEXT: %3 = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// CHECK-NEXT: store ptr %1, ptr %3, align 8 +// CHECK-NEXT: %4 = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// CHECK-NEXT: store ptr %2, ptr %4, align 8 +// CHECK-NEXT: %5 = getelementptr inbounds [1 x i64], ptr %.offload_sizes, i32 0, i32 0 +// CHECK-NEXT: store i64 1024, ptr %5, align 8 +// CHECK-NEXT: %6 = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// CHECK-NEXT: %7 = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// CHECK-NEXT: %8 = getelementptr inbounds [1 x i64], ptr %.offload_sizes, i32 0, i32 0 +// CHECK-NEXT: call void @__tgt_target_data_begin_mapper(ptr @1, i64 -1, i32 1, ptr %6, ptr %7, ptr %8, ptr @.offload_maptypes.1, ptr null, ptr null) +// CHECK-NEXT: call void @kernel_1(ptr noalias noundef nonnull align 4 dereferenceable(1024) %x) +// CHECK-NEXT: %9 = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// CHECK-NEXT: %10 = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// CHECK-NEXT: %11 = getelementptr inbounds [1 x i64], ptr %.offload_sizes, i32 0, i32 0 +// CHECK-NEXT: call void @__tgt_target_data_end_mapper(ptr @1, i64 -1, i32 1, ptr %9, ptr %10, ptr %11, ptr @.offload_maptypes.1, ptr null, ptr null) +// CHECK-NEXT: call void @__tgt_unregister_lib(ptr %EmptyDesc) +// CHECK: store ptr %x, ptr %0, align 8 +// CHECK-NEXT: call void asm sideeffect "", "r,~{memory}"(ptr nonnull %0) +// CHECK: ret void +// CHECK-NEXT: } + +#[unsafe(no_mangle)] +#[inline(never)] +pub fn kernel_1(x: &mut [f32; 256]) { + for i in 0..256 { + x[i] = 21.0; + } +} -- cgit 1.4.1-3-g733a5 From 0586c63e070981af7df53e2f778d3e50293d8103 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 9 Jul 2025 23:59:00 -0700 Subject: Allow `Rvalue::Repeat` to return true in `rvalue_creates_operand` too The conversation in 143502 made be realize how easy this is to handle, since the only possibilty is ZSTs -- everything else ends up with the destination being `LocalKind::Memory` and thus doesn't call `codegen_rvalue_operand` at all. This gets us perilously close to a world where `rvalue_creates_operand` only ever returns true. I'll try out such a world next :) --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 16 +++++++++--- tests/codegen/repeat-operand.rs | 39 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 tests/codegen/repeat-operand.rs (limited to 'tests/codegen') diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 2587e89417a..e872f8434e5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -630,7 +630,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandRef { val: OperandValue::Immediate(static_), layout } } mir::Rvalue::Use(ref operand) => self.codegen_operand(bx, operand), - mir::Rvalue::Repeat(..) => bug!("{rvalue:?} in codegen_rvalue_operand"), + mir::Rvalue::Repeat(ref elem, len_const) => { + // All arrays have `BackendRepr::Memory`, so only the ZST cases + // end up here. Anything else forces the destination local to be + // `Memory`, and thus ends up handled in `codegen_rvalue` instead. + let operand = self.codegen_operand(bx, elem); + let array_ty = Ty::new_array_with_const_len(bx.tcx(), operand.layout.ty, len_const); + let array_ty = self.monomorphize(array_ty); + let array_layout = bx.layout_of(array_ty); + assert!(array_layout.is_zst()); + OperandRef { val: OperandValue::ZeroSized, layout: array_layout } + } mir::Rvalue::Aggregate(ref kind, ref fields) => { let (variant_index, active_field_index) = match **kind { mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => { @@ -1000,12 +1010,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::NullaryOp(..) | mir::Rvalue::ThreadLocalRef(_) | mir::Rvalue::Use(..) | + mir::Rvalue::Repeat(..) | // (*) mir::Rvalue::Aggregate(..) | // (*) mir::Rvalue::WrapUnsafeBinder(..) => // (*) true, - // Arrays are always aggregates, so it's not worth checking anything here. - // (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.) - mir::Rvalue::Repeat(..) => false, } // (*) this is only true if the type is suitable diff --git a/tests/codegen/repeat-operand.rs b/tests/codegen/repeat-operand.rs new file mode 100644 index 00000000000..6464b35ddca --- /dev/null +++ b/tests/codegen/repeat-operand.rs @@ -0,0 +1,39 @@ +//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes + +// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`. +// It only applies when the resulting array is a ZST, so the test is written in +// such a way as to keep MIR optimizations from seeing that fact and removing +// the local and statement altogether. (At the time of writing, no other codegen +// test hit that code path, nor did a stage 2 build of the compiler.) + +#![crate_type = "lib"] + +#[repr(transparent)] +pub struct Wrapper([T; N]); + +// CHECK-LABEL: define {{.+}}do_repeat{{.+}}() +// CHECK-NEXT: start: +// CHECK-NOT: alloca +// CHECK-NEXT: ret void +// CHECK-LABEL: define {{.+}}do_repeat{{.+}}(i32 noundef %x) +// CHECK-NEXT: start: +// CHECK-NOT: alloca +// CHECK-NEXT: ret void +#[inline(never)] +pub fn do_repeat(x: T) -> Wrapper { + Wrapper([x; N]) +} + +// CHECK-LABEL: @trigger_repeat_zero_len +#[no_mangle] +pub fn trigger_repeat_zero_len() -> Wrapper { + // CHECK: call void {{.+}}do_repeat{{.+}}(i32 noundef 4) + do_repeat(4) +} + +// CHECK-LABEL: @trigger_repeat_zst +#[no_mangle] +pub fn trigger_repeat_zst() -> Wrapper<(), 8> { + // CHECK: call void {{.+}}do_repeat{{.+}}() + do_repeat(()) +} -- cgit 1.4.1-3-g733a5 From 4b8f869c638e6d5090420ff46bd14e7b7d909690 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 19 Jul 2025 20:49:52 -0700 Subject: Split repeat-operand codegen test Looks like the output it's looking for can be in different orders, so separate tests will fix that. --- tests/codegen/repeat-operand-zero-len.rs | 28 +++++++++++++++++++++++ tests/codegen/repeat-operand-zst-elem.rs | 28 +++++++++++++++++++++++ tests/codegen/repeat-operand.rs | 39 -------------------------------- 3 files changed, 56 insertions(+), 39 deletions(-) create mode 100644 tests/codegen/repeat-operand-zero-len.rs create mode 100644 tests/codegen/repeat-operand-zst-elem.rs delete mode 100644 tests/codegen/repeat-operand.rs (limited to 'tests/codegen') diff --git a/tests/codegen/repeat-operand-zero-len.rs b/tests/codegen/repeat-operand-zero-len.rs new file mode 100644 index 00000000000..b4cec42a07c --- /dev/null +++ b/tests/codegen/repeat-operand-zero-len.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes + +// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`. +// It only applies when the resulting array is a ZST, so the test is written in +// such a way as to keep MIR optimizations from seeing that fact and removing +// the local and statement altogether. (At the time of writing, no other codegen +// test hit that code path, nor did a stage 2 build of the compiler.) + +#![crate_type = "lib"] + +#[repr(transparent)] +pub struct Wrapper([T; N]); + +// CHECK-LABEL: define {{.+}}do_repeat{{.+}}(i32 noundef %x) +// CHECK-NEXT: start: +// CHECK-NOT: alloca +// CHECK-NEXT: ret void +#[inline(never)] +pub fn do_repeat(x: T) -> Wrapper { + Wrapper([x; N]) +} + +// CHECK-LABEL: @trigger_repeat_zero_len +#[no_mangle] +pub fn trigger_repeat_zero_len() -> Wrapper { + // CHECK: call void {{.+}}do_repeat{{.+}}(i32 noundef 4) + do_repeat(4) +} diff --git a/tests/codegen/repeat-operand-zst-elem.rs b/tests/codegen/repeat-operand-zst-elem.rs new file mode 100644 index 00000000000..c3637759afa --- /dev/null +++ b/tests/codegen/repeat-operand-zst-elem.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes + +// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`. +// It only applies when the resulting array is a ZST, so the test is written in +// such a way as to keep MIR optimizations from seeing that fact and removing +// the local and statement altogether. (At the time of writing, no other codegen +// test hit that code path, nor did a stage 2 build of the compiler.) + +#![crate_type = "lib"] + +#[repr(transparent)] +pub struct Wrapper([T; N]); + +// CHECK-LABEL: define {{.+}}do_repeat{{.+}}() +// CHECK-NEXT: start: +// CHECK-NOT: alloca +// CHECK-NEXT: ret void +#[inline(never)] +pub fn do_repeat(x: T) -> Wrapper { + Wrapper([x; N]) +} + +// CHECK-LABEL: @trigger_repeat_zst_elem +#[no_mangle] +pub fn trigger_repeat_zst_elem() -> Wrapper<(), 8> { + // CHECK: call void {{.+}}do_repeat{{.+}}() + do_repeat(()) +} diff --git a/tests/codegen/repeat-operand.rs b/tests/codegen/repeat-operand.rs deleted file mode 100644 index 6464b35ddca..00000000000 --- a/tests/codegen/repeat-operand.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes - -// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`. -// It only applies when the resulting array is a ZST, so the test is written in -// such a way as to keep MIR optimizations from seeing that fact and removing -// the local and statement altogether. (At the time of writing, no other codegen -// test hit that code path, nor did a stage 2 build of the compiler.) - -#![crate_type = "lib"] - -#[repr(transparent)] -pub struct Wrapper([T; N]); - -// CHECK-LABEL: define {{.+}}do_repeat{{.+}}() -// CHECK-NEXT: start: -// CHECK-NOT: alloca -// CHECK-NEXT: ret void -// CHECK-LABEL: define {{.+}}do_repeat{{.+}}(i32 noundef %x) -// CHECK-NEXT: start: -// CHECK-NOT: alloca -// CHECK-NEXT: ret void -#[inline(never)] -pub fn do_repeat(x: T) -> Wrapper { - Wrapper([x; N]) -} - -// CHECK-LABEL: @trigger_repeat_zero_len -#[no_mangle] -pub fn trigger_repeat_zero_len() -> Wrapper { - // CHECK: call void {{.+}}do_repeat{{.+}}(i32 noundef 4) - do_repeat(4) -} - -// CHECK-LABEL: @trigger_repeat_zst -#[no_mangle] -pub fn trigger_repeat_zst() -> Wrapper<(), 8> { - // CHECK: call void {{.+}}do_repeat{{.+}}() - do_repeat(()) -} -- cgit 1.4.1-3-g733a5 From 08b816ff18347031b1160f1257cde2008c3c366e Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 12 Jul 2025 02:33:42 -0700 Subject: So many test updates x_x --- tests/auxiliary/minisimd.rs | 160 +++++++++++++++ tests/codegen/const-vector.rs | 38 ++-- .../simd-intrinsic/simd-intrinsic-float-abs.rs | 32 +-- .../simd-intrinsic/simd-intrinsic-float-ceil.rs | 32 +-- .../simd-intrinsic/simd-intrinsic-float-cos.rs | 32 +-- .../simd-intrinsic/simd-intrinsic-float-exp.rs | 32 +-- .../simd-intrinsic/simd-intrinsic-float-exp2.rs | 32 +-- .../simd-intrinsic/simd-intrinsic-float-floor.rs | 32 +-- .../simd-intrinsic/simd-intrinsic-float-fma.rs | 32 +-- .../simd-intrinsic/simd-intrinsic-float-fsqrt.rs | 32 +-- .../simd-intrinsic/simd-intrinsic-float-log.rs | 32 +-- .../simd-intrinsic/simd-intrinsic-float-log10.rs | 32 +-- .../simd-intrinsic/simd-intrinsic-float-log2.rs | 32 +-- .../simd-intrinsic/simd-intrinsic-float-minmax.rs | 8 +- .../simd-intrinsic/simd-intrinsic-float-sin.rs | 32 +-- ...simd-intrinsic-generic-arithmetic-saturating.rs | 63 +----- .../simd-intrinsic-generic-bitmask.rs | 16 +- .../simd-intrinsic-generic-gather.rs | 13 +- .../simd-intrinsic-generic-masked-load.rs | 13 +- .../simd-intrinsic-generic-masked-store.rs | 13 +- .../simd-intrinsic-generic-scatter.rs | 13 +- .../simd-intrinsic-generic-select.rs | 24 +-- .../simd-intrinsic/simd-intrinsic-mask-reduce.rs | 13 +- .../simd-intrinsic-transmute-array.rs | 15 +- tests/codegen/simd/aggregate-simd.rs | 10 +- tests/codegen/simd/packed-simd.rs | 12 +- tests/codegen/simd/simd_arith_offset.rs | 12 +- tests/ui/simd/generics.rs | 60 ++---- tests/ui/simd/intrinsic/float-math-pass.rs | 22 +-- tests/ui/simd/intrinsic/float-minmax-pass.rs | 16 +- tests/ui/simd/intrinsic/generic-arithmetic-pass.rs | 214 +++++++++++---------- .../generic-arithmetic-saturating-pass.rs | 82 ++++---- tests/ui/simd/intrinsic/generic-as.rs | 38 ++-- tests/ui/simd/intrinsic/generic-bswap-byte.rs | 16 +- tests/ui/simd/intrinsic/generic-cast-pass.rs | 38 ++-- .../simd/intrinsic/generic-cast-pointer-width.rs | 16 +- tests/ui/simd/intrinsic/generic-comparison-pass.rs | 43 ++--- tests/ui/simd/intrinsic/generic-elements-pass.rs | 120 ++++++------ .../simd/intrinsic/generic-gather-scatter-pass.rs | 34 ++-- tests/ui/simd/intrinsic/generic-select-pass.rs | 94 ++++----- tests/ui/simd/intrinsic/inlining-issue67557.rs | 20 +- tests/ui/simd/intrinsic/ptr-cast.rs | 16 +- tests/ui/simd/issue-39720.rs | 14 +- tests/ui/simd/issue-85915-simd-ptrs.rs | 32 ++- tests/ui/simd/issue-89193.rs | 22 ++- tests/ui/simd/masked-load-store.rs | 10 +- tests/ui/simd/monomorphize-shuffle-index.rs | 12 +- tests/ui/simd/repr_packed.rs | 28 ++- tests/ui/simd/shuffle.rs | 10 +- tests/ui/simd/simd-bitmask-notpow2.rs | 21 +- tests/ui/simd/simd-bitmask.rs | 16 +- tests/ui/simd/target-feature-mixup.rs | 41 ++-- 52 files changed, 805 insertions(+), 1037 deletions(-) create mode 100644 tests/auxiliary/minisimd.rs (limited to 'tests/codegen') diff --git a/tests/auxiliary/minisimd.rs b/tests/auxiliary/minisimd.rs new file mode 100644 index 00000000000..ff0c996de1c --- /dev/null +++ b/tests/auxiliary/minisimd.rs @@ -0,0 +1,160 @@ +//! Auxiliary crate for tests that need SIMD types. +//! +//! Historically the tests just made their own, but projections into simd types +//! was banned by , which +//! breaks `derive(Clone)`, so this exists to give easily-usable types that can +//! be used without copy-pasting the definitions of the helpers everywhere. +//! +//! This makes no attempt to guard against ICEs. Using it with proper types +//! and such is your responsibility in the tests you write. + +#![allow(unused)] +#![allow(non_camel_case_types)] + +// The field is currently left `pub` for convenience in porting tests, many of +// which attempt to just construct it directly. That still works; it's just the +// `.0` projection that doesn't. +#[repr(simd)] +#[derive(Copy, Eq)] +pub struct Simd(pub [T; N]); + +impl Clone for Simd { + fn clone(&self) -> Self { + *self + } +} + +impl PartialEq for Simd { + fn eq(&self, other: &Self) -> bool { + self.as_array() == other.as_array() + } +} + +impl core::fmt::Debug for Simd { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + <[T; N] as core::fmt::Debug>::fmt(self.as_array(), f) + } +} + +impl core::ops::Index for Simd { + type Output = T; + fn index(&self, i: usize) -> &T { + &self.as_array()[i] + } +} + +impl Simd { + pub const fn from_array(a: [T; N]) -> Self { + Simd(a) + } + pub fn as_array(&self) -> &[T; N] { + let p: *const Self = self; + unsafe { &*p.cast::<[T; N]>() } + } + pub fn into_array(self) -> [T; N] + where + T: Copy, + { + *self.as_array() + } +} + +pub type u8x2 = Simd; +pub type u8x4 = Simd; +pub type u8x8 = Simd; +pub type u8x16 = Simd; +pub type u8x32 = Simd; +pub type u8x64 = Simd; + +pub type u16x2 = Simd; +pub type u16x4 = Simd; +pub type u16x8 = Simd; +pub type u16x16 = Simd; +pub type u16x32 = Simd; + +pub type u32x2 = Simd; +pub type u32x4 = Simd; +pub type u32x8 = Simd; +pub type u32x16 = Simd; + +pub type u64x2 = Simd; +pub type u64x4 = Simd; +pub type u64x8 = Simd; + +pub type u128x2 = Simd; +pub type u128x4 = Simd; + +pub type i8x2 = Simd; +pub type i8x4 = Simd; +pub type i8x8 = Simd; +pub type i8x16 = Simd; +pub type i8x32 = Simd; +pub type i8x64 = Simd; + +pub type i16x2 = Simd; +pub type i16x4 = Simd; +pub type i16x8 = Simd; +pub type i16x16 = Simd; +pub type i16x32 = Simd; + +pub type i32x2 = Simd; +pub type i32x4 = Simd; +pub type i32x8 = Simd; +pub type i32x16 = Simd; + +pub type i64x2 = Simd; +pub type i64x4 = Simd; +pub type i64x8 = Simd; + +pub type i128x2 = Simd; +pub type i128x4 = Simd; + +pub type f32x2 = Simd; +pub type f32x4 = Simd; +pub type f32x8 = Simd; +pub type f32x16 = Simd; + +pub type f64x2 = Simd; +pub type f64x4 = Simd; +pub type f64x8 = Simd; + +// The field is currently left `pub` for convenience in porting tests, many of +// which attempt to just construct it directly. That still works; it's just the +// `.0` projection that doesn't. +#[repr(simd, packed)] +#[derive(Copy)] +pub struct PackedSimd(pub [T; N]); + +impl Clone for PackedSimd { + fn clone(&self) -> Self { + *self + } +} + +impl PartialEq for PackedSimd { + fn eq(&self, other: &Self) -> bool { + self.as_array() == other.as_array() + } +} + +impl core::fmt::Debug for PackedSimd { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + <[T; N] as core::fmt::Debug>::fmt(self.as_array(), f) + } +} + +impl PackedSimd { + pub const fn from_array(a: [T; N]) -> Self { + PackedSimd(a) + } + pub fn as_array(&self) -> &[T; N] { + let p: *const Self = self; + unsafe { &*p.cast::<[T; N]>() } + } + pub fn into_array(self) -> [T; N] + where + T: Copy, + { + *self.as_array() + } +} diff --git a/tests/codegen/const-vector.rs b/tests/codegen/const-vector.rs index 42921442e03..a2249f4fff7 100644 --- a/tests/codegen/const-vector.rs +++ b/tests/codegen/const-vector.rs @@ -16,18 +16,9 @@ #![feature(mips_target_feature)] #![allow(non_camel_case_types)] -// Setting up structs that can be used as const vectors -#[repr(simd)] -#[derive(Clone)] -pub struct i8x2([i8; 2]); - -#[repr(simd)] -#[derive(Clone)] -pub struct f32x2([f32; 2]); - -#[repr(simd, packed)] -#[derive(Copy, Clone)] -pub struct Simd([T; N]); +#[path = "../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::{PackedSimd as Simd, f32x2, i8x2}; // The following functions are required for the tests to ensure // that they are called with a const vector @@ -45,7 +36,7 @@ extern "unadjusted" { // Ensure the packed variant of the simd struct does not become a const vector // if the size is not a power of 2 -// CHECK: %"Simd" = type { [3 x i32] } +// CHECK: %"minisimd::PackedSimd" = type { [3 x i32] } #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] @@ -54,27 +45,34 @@ extern "unadjusted" { pub fn do_call() { unsafe { // CHECK: call void @test_i8x2(<2 x i8> - test_i8x2(const { i8x2([32, 64]) }); + test_i8x2(const { i8x2::from_array([32, 64]) }); // CHECK: call void @test_i8x2_two_args(<2 x i8> , <2 x i8> - test_i8x2_two_args(const { i8x2([32, 64]) }, const { i8x2([8, 16]) }); + test_i8x2_two_args( + const { i8x2::from_array([32, 64]) }, + const { i8x2::from_array([8, 16]) }, + ); // CHECK: call void @test_i8x2_mixed_args(<2 x i8> , i32 43, <2 x i8> - test_i8x2_mixed_args(const { i8x2([32, 64]) }, 43, const { i8x2([8, 16]) }); + test_i8x2_mixed_args( + const { i8x2::from_array([32, 64]) }, + 43, + const { i8x2::from_array([8, 16]) }, + ); // CHECK: call void @test_i8x2_arr(<2 x i8> - test_i8x2_arr(const { i8x2([32, 64]) }); + test_i8x2_arr(const { i8x2::from_array([32, 64]) }); // CHECK: call void @test_f32x2(<2 x float> - test_f32x2(const { f32x2([0.32, 0.64]) }); + test_f32x2(const { f32x2::from_array([0.32, 0.64]) }); // CHECK: void @test_f32x2_arr(<2 x float> - test_f32x2_arr(const { f32x2([0.32, 0.64]) }); + test_f32x2_arr(const { f32x2::from_array([0.32, 0.64]) }); // CHECK: call void @test_simd(<4 x i32> test_simd(const { Simd::([2, 4, 6, 8]) }); - // CHECK: call void @test_simd_unaligned(%"Simd" %1 + // CHECK: call void @test_simd_unaligned(%"minisimd::PackedSimd" %1 test_simd_unaligned(const { Simd::([2, 4, 6]) }); } } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs index 485ba92272d..baf445d0a1b 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs @@ -4,23 +4,11 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_fabs; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); +use std::intrinsics::simd::simd_fabs; // CHECK-LABEL: @fabs_32x2 #[no_mangle] @@ -50,18 +38,6 @@ pub unsafe fn fabs_32x16(a: f32x16) -> f32x16 { simd_fabs(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @fabs_64x4 #[no_mangle] pub unsafe fn fabs_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs index e8bda7c29c4..096de569274 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs @@ -4,23 +4,11 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_ceil; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); +use std::intrinsics::simd::simd_ceil; // CHECK-LABEL: @ceil_32x2 #[no_mangle] @@ -50,18 +38,6 @@ pub unsafe fn ceil_32x16(a: f32x16) -> f32x16 { simd_ceil(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @ceil_64x4 #[no_mangle] pub unsafe fn ceil_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs index 8dc967bc3ad..5b2197924bc 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs @@ -4,23 +4,11 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_fcos; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); +use std::intrinsics::simd::simd_fcos; // CHECK-LABEL: @fcos_32x2 #[no_mangle] @@ -50,18 +38,6 @@ pub unsafe fn fcos_32x16(a: f32x16) -> f32x16 { simd_fcos(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @fcos_64x4 #[no_mangle] pub unsafe fn fcos_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs index 00caca2f294..d4eadb36c65 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs @@ -4,23 +4,11 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_fexp; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); +use std::intrinsics::simd::simd_fexp; // CHECK-LABEL: @exp_32x2 #[no_mangle] @@ -50,18 +38,6 @@ pub unsafe fn exp_32x16(a: f32x16) -> f32x16 { simd_fexp(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @exp_64x4 #[no_mangle] pub unsafe fn exp_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs index eda4053189c..d32015b7990 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs @@ -4,23 +4,11 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_fexp2; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); +use std::intrinsics::simd::simd_fexp2; // CHECK-LABEL: @exp2_32x2 #[no_mangle] @@ -50,18 +38,6 @@ pub unsafe fn exp2_32x16(a: f32x16) -> f32x16 { simd_fexp2(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @exp2_64x4 #[no_mangle] pub unsafe fn exp2_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs index ad69d4cdd88..1e1c8ce0c35 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs @@ -4,23 +4,11 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_floor; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); +use std::intrinsics::simd::simd_floor; // CHECK-LABEL: @floor_32x2 #[no_mangle] @@ -50,18 +38,6 @@ pub unsafe fn floor_32x16(a: f32x16) -> f32x16 { simd_floor(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @floor_64x4 #[no_mangle] pub unsafe fn floor_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs index cbeefdc31c0..982077d81f9 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs @@ -4,23 +4,11 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_fma; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); +use std::intrinsics::simd::simd_fma; // CHECK-LABEL: @fma_32x2 #[no_mangle] @@ -50,18 +38,6 @@ pub unsafe fn fma_32x16(a: f32x16, b: f32x16, c: f32x16) -> f32x16 { simd_fma(a, b, c) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @fma_64x4 #[no_mangle] pub unsafe fn fma_64x4(a: f64x4, b: f64x4, c: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs index 618daa4b44d..e20a591f573 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs @@ -4,23 +4,11 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_fsqrt; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); +use std::intrinsics::simd::simd_fsqrt; // CHECK-LABEL: @fsqrt_32x2 #[no_mangle] @@ -50,18 +38,6 @@ pub unsafe fn fsqrt_32x16(a: f32x16) -> f32x16 { simd_fsqrt(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @fsqrt_64x4 #[no_mangle] pub unsafe fn fsqrt_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs index 98a481e4004..bf1ffc76330 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs @@ -4,23 +4,11 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_flog; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); +use std::intrinsics::simd::simd_flog; // CHECK-LABEL: @log_32x2 #[no_mangle] @@ -50,18 +38,6 @@ pub unsafe fn log_32x16(a: f32x16) -> f32x16 { simd_flog(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @log_64x4 #[no_mangle] pub unsafe fn log_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs index 9108cd963f0..ccf484e0e41 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs @@ -4,23 +4,11 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_flog10; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); +use std::intrinsics::simd::simd_flog10; // CHECK-LABEL: @log10_32x2 #[no_mangle] @@ -50,18 +38,6 @@ pub unsafe fn log10_32x16(a: f32x16) -> f32x16 { simd_flog10(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @log10_64x4 #[no_mangle] pub unsafe fn log10_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs index 2b20850dbd9..677d8b01e84 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs @@ -4,23 +4,11 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_flog2; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); +use std::intrinsics::simd::simd_flog2; // CHECK-LABEL: @log2_32x2 #[no_mangle] @@ -50,18 +38,6 @@ pub unsafe fn log2_32x16(a: f32x16) -> f32x16 { simd_flog2(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @log2_64x4 #[no_mangle] pub unsafe fn log2_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs index ce07b212e84..8dd464a1bff 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs @@ -4,11 +4,11 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::{simd_fmax, simd_fmin}; +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); +use std::intrinsics::simd::{simd_fmax, simd_fmin}; // CHECK-LABEL: @fmin #[no_mangle] diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs index 7de26b415bb..48becc72c0b 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs @@ -4,23 +4,11 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_fsin; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x2(pub [f32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8(pub [f32; 8]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x16(pub [f32; 16]); +use std::intrinsics::simd::simd_fsin; // CHECK-LABEL: @fsin_32x2 #[no_mangle] @@ -50,18 +38,6 @@ pub unsafe fn fsin_32x16(a: f32x16) -> f32x16 { simd_fsin(a) } -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x2(pub [f64; 2]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x4(pub [f64; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f64x8(pub [f64; 8]); - // CHECK-LABEL: @fsin_64x4 #[no_mangle] pub unsafe fn fsin_64x4(a: f64x4) -> f64x4 { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs index ecf5eb24ee5..06d46889715 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs @@ -5,66 +5,11 @@ #![allow(non_camel_case_types)] #![deny(unused)] -use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub}; - -#[rustfmt::skip] -mod types { - // signed integer types - - #[repr(simd)] #[derive(Copy, Clone)] pub struct i8x2([i8; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i8x4([i8; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i8x8([i8; 8]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i8x16([i8; 16]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i8x32([i8; 32]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i8x64([i8; 64]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct i16x2([i16; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i16x4([i16; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i16x8([i16; 8]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i16x16([i16; 16]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i16x32([i16; 32]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct i32x2([i32; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i32x4([i32; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i32x8([i32; 8]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i32x16([i32; 16]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct i64x2([i64; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i64x4([i64; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i64x8([i64; 8]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct i128x2([i128; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct i128x4([i128; 4]); - - // unsigned integer types +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; - #[repr(simd)] #[derive(Copy, Clone)] pub struct u8x2([u8; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u8x4([u8; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u8x8([u8; 8]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u8x16([u8; 16]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u8x32([u8; 32]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u8x64([u8; 64]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct u16x2([u16; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u16x4([u16; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u16x8([u16; 8]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u16x16([u16; 16]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u16x32([u16; 32]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct u32x2([u32; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u32x4([u32; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u32x8([u32; 8]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u32x16([u32; 16]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct u64x2([u64; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u64x4([u64; 4]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u64x8([u64; 8]); - - #[repr(simd)] #[derive(Copy, Clone)] pub struct u128x2([u128; 2]); - #[repr(simd)] #[derive(Copy, Clone)] pub struct u128x4([u128; 4]); -} - -use types::*; +use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub}; // NOTE(eddyb) `%{{x|0}}` is used because on some targets (e.g. WASM) // SIMD vectors are passed directly, resulting in `%x` being a vector, diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs index a2c40aa91b5..294262d8152 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs @@ -5,19 +5,11 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_bitmask; - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct u32x2([u32; 2]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct i32x2([i32; 2]); - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct i8x16([i8; 16]); +use std::intrinsics::simd::simd_bitmask; // NOTE(eddyb) `%{{x|1}}` is used because on some targets (e.g. WASM) // SIMD vectors are passed directly, resulting in `%x` being a vector, diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs index c06b36d68b9..690bfb432f9 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs @@ -6,15 +6,14 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_gather; +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec2(pub [T; 2]); +use std::intrinsics::simd::simd_gather; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec4(pub [T; 4]); +pub type Vec2 = Simd; +pub type Vec4 = Simd; // CHECK-LABEL: @gather_f32x2 #[no_mangle] diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs index 21578e67cff..fda315dc66c 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs @@ -4,15 +4,14 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_masked_load; +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec2(pub [T; 2]); +use std::intrinsics::simd::simd_masked_load; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec4(pub [T; 4]); +pub type Vec2 = Simd; +pub type Vec4 = Simd; // CHECK-LABEL: @load_f32x2 #[no_mangle] diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs index 22a8f7e54bd..6ca7388d464 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs @@ -4,15 +4,14 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_masked_store; +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec2(pub [T; 2]); +use std::intrinsics::simd::simd_masked_store; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec4(pub [T; 4]); +pub type Vec2 = Simd; +pub type Vec4 = Simd; // CHECK-LABEL: @store_f32x2 #[no_mangle] diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs index 0cc9e6ae59a..743652966e1 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs @@ -6,15 +6,14 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_scatter; +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec2(pub [T; 2]); +use std::intrinsics::simd::simd_scatter; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct Vec4(pub [T; 4]); +pub type Vec2 = Simd; +pub type Vec4 = Simd; // CHECK-LABEL: @scatter_f32x2 #[no_mangle] diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs index f6531c1b23a..2c0bad21f44 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs @@ -4,27 +4,13 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::{simd_select, simd_select_bitmask}; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x4(pub [f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct f32x8([f32; 8]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct b8x4(pub [i8; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct i32x4([i32; 4]); +use std::intrinsics::simd::{simd_select, simd_select_bitmask}; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct u32x4([u32; 4]); +pub type b8x4 = i8x4; // CHECK-LABEL: @select_m8 #[no_mangle] diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs index 269fe41225e..79f00a6ed60 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs @@ -4,15 +4,14 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::{simd_reduce_all, simd_reduce_any}; +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct mask32x2([i32; 2]); +use std::intrinsics::simd::{simd_reduce_all, simd_reduce_any}; -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct mask8x16([i8; 16]); +pub type mask32x2 = Simd; +pub type mask8x16 = Simd; // NOTE(eddyb) `%{{x|1}}` is used because on some targets (e.g. WASM) // SIMD vectors are passed directly, resulting in `%x` being a vector, diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs index 301f06c2d74..05c2f7e1bdf 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs @@ -8,13 +8,12 @@ #![allow(non_camel_case_types)] #![feature(repr_simd, core_intrinsics)] -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct S([f32; N]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct T([f32; 4]); +pub type S = Simd; +pub type T = Simd; // CHECK-LABEL: @array_align( #[no_mangle] @@ -34,7 +33,7 @@ pub fn vector_align() -> usize { #[no_mangle] pub fn build_array_s(x: [f32; 4]) -> S<4> { // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) - S::<4>(x) + Simd(x) } // CHECK-LABEL: @build_array_transmute_s @@ -48,7 +47,7 @@ pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> { #[no_mangle] pub fn build_array_t(x: [f32; 4]) -> T { // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) - T(x) + Simd(x) } // CHECK-LABEL: @build_array_transmute_t diff --git a/tests/codegen/simd/aggregate-simd.rs b/tests/codegen/simd/aggregate-simd.rs index 065e429a4c7..57a301d634c 100644 --- a/tests/codegen/simd/aggregate-simd.rs +++ b/tests/codegen/simd/aggregate-simd.rs @@ -5,15 +5,11 @@ #![no_std] #![crate_type = "lib"] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; use core::intrinsics::simd::{simd_add, simd_extract}; -#[repr(simd)] -#[derive(Clone, Copy)] -pub struct Simd([T; N]); - -#[repr(simd, packed)] -#[derive(Clone, Copy)] -pub struct PackedSimd([T; N]); +use minisimd::*; #[repr(transparent)] pub struct Transparent(T); diff --git a/tests/codegen/simd/packed-simd.rs b/tests/codegen/simd/packed-simd.rs index 73e0d29d7d6..70c03fcc955 100644 --- a/tests/codegen/simd/packed-simd.rs +++ b/tests/codegen/simd/packed-simd.rs @@ -9,18 +9,14 @@ use core::intrinsics::simd as intrinsics; use core::{mem, ptr}; +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::{PackedSimd, Simd as FullSimd}; + // Test codegen for not only "packed" but also "fully aligned" SIMD types, and conversion between // them. A repr(packed,simd) type with 3 elements can't exceed its element alignment, whereas the // same type as repr(simd) will instead have padding. -#[repr(simd, packed)] -#[derive(Copy, Clone)] -pub struct PackedSimd([T; N]); - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct FullSimd([T; N]); - // non-powers-of-two have padding and need to be expanded to full vectors fn load(v: PackedSimd) -> FullSimd { unsafe { diff --git a/tests/codegen/simd/simd_arith_offset.rs b/tests/codegen/simd/simd_arith_offset.rs index b8af6fce332..210b4e9bb50 100644 --- a/tests/codegen/simd/simd_arith_offset.rs +++ b/tests/codegen/simd/simd_arith_offset.rs @@ -5,16 +5,14 @@ #![crate_type = "lib"] #![feature(repr_simd, core_intrinsics)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; use std::intrinsics::simd::simd_arith_offset; -/// A vector of *const T. -#[derive(Debug, Copy, Clone)] -#[repr(simd)] -pub struct SimdConstPtr([*const T; LANES]); +use minisimd::*; -#[derive(Debug, Copy, Clone)] -#[repr(simd)] -pub struct Simd([T; LANES]); +/// A vector of *const T. +pub type SimdConstPtr = Simd<*const T, LANES>; // CHECK-LABEL: smoke #[no_mangle] diff --git a/tests/ui/simd/generics.rs b/tests/ui/simd/generics.rs index 1ae08fef7cd..54e76f7bc5d 100644 --- a/tests/ui/simd/generics.rs +++ b/tests/ui/simd/generics.rs @@ -2,24 +2,18 @@ #![allow(non_camel_case_types)] #![feature(repr_simd, core_intrinsics)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_add; use std::ops; -#[repr(simd)] -#[derive(Copy, Clone)] -struct f32x4([f32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct A([f32; N]); +type A = Simd; -#[repr(simd)] -#[derive(Copy, Clone)] -struct B([T; 4]); +type B = Simd; -#[repr(simd)] -#[derive(Copy, Clone)] -struct C([T; N]); +type C = Simd; fn add>(lhs: T, rhs: T) -> T { lhs + rhs @@ -33,48 +27,24 @@ impl ops::Add for f32x4 { } } -impl ops::Add for A<4> { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - unsafe { simd_add(self, rhs) } - } -} - -impl ops::Add for B { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - unsafe { simd_add(self, rhs) } - } -} - -impl ops::Add for C { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - unsafe { simd_add(self, rhs) } - } -} - pub fn main() { let x = [1.0f32, 2.0f32, 3.0f32, 4.0f32]; let y = [2.0f32, 4.0f32, 6.0f32, 8.0f32]; // lame-o - let a = f32x4([1.0f32, 2.0f32, 3.0f32, 4.0f32]); - let f32x4([a0, a1, a2, a3]) = add(a, a); + let a = f32x4::from_array([1.0f32, 2.0f32, 3.0f32, 4.0f32]); + let [a0, a1, a2, a3] = add(a, a).into_array(); assert_eq!(a0, 2.0f32); assert_eq!(a1, 4.0f32); assert_eq!(a2, 6.0f32); assert_eq!(a3, 8.0f32); - let a = A(x); - assert_eq!(add(a, a).0, y); + let a = A::from_array(x); + assert_eq!(add(a, a).into_array(), y); - let b = B(x); - assert_eq!(add(b, b).0, y); + let b = B::from_array(x); + assert_eq!(add(b, b).into_array(), y); - let c = C(x); - assert_eq!(add(c, c).0, y); + let c = C::from_array(x); + assert_eq!(add(c, c).into_array(), y); } diff --git a/tests/ui/simd/intrinsic/float-math-pass.rs b/tests/ui/simd/intrinsic/float-math-pass.rs index 01fed8537d0..743aae8d1c3 100644 --- a/tests/ui/simd/intrinsic/float-math-pass.rs +++ b/tests/ui/simd/intrinsic/float-math-pass.rs @@ -11,9 +11,9 @@ #![feature(repr_simd, intrinsics, core_intrinsics)] #![allow(non_camel_case_types)] -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4(pub [f32; 4]); +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; use std::intrinsics::simd::*; @@ -27,19 +27,19 @@ macro_rules! assert_approx_eq { ($a:expr, $b:expr) => {{ let a = $a; let b = $b; - assert_approx_eq_f32!(a.0[0], b.0[0]); - assert_approx_eq_f32!(a.0[1], b.0[1]); - assert_approx_eq_f32!(a.0[2], b.0[2]); - assert_approx_eq_f32!(a.0[3], b.0[3]); + assert_approx_eq_f32!(a[0], b[0]); + assert_approx_eq_f32!(a[1], b[1]); + assert_approx_eq_f32!(a[2], b[2]); + assert_approx_eq_f32!(a[3], b[3]); }}; } fn main() { - let x = f32x4([1.0, 1.0, 1.0, 1.0]); - let y = f32x4([-1.0, -1.0, -1.0, -1.0]); - let z = f32x4([0.0, 0.0, 0.0, 0.0]); + let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]); + let y = f32x4::from_array([-1.0, -1.0, -1.0, -1.0]); + let z = f32x4::from_array([0.0, 0.0, 0.0, 0.0]); - let h = f32x4([0.5, 0.5, 0.5, 0.5]); + let h = f32x4::from_array([0.5, 0.5, 0.5, 0.5]); unsafe { let r = simd_fabs(y); diff --git a/tests/ui/simd/intrinsic/float-minmax-pass.rs b/tests/ui/simd/intrinsic/float-minmax-pass.rs index 00c0d8cea3f..12210ba0ad1 100644 --- a/tests/ui/simd/intrinsic/float-minmax-pass.rs +++ b/tests/ui/simd/intrinsic/float-minmax-pass.rs @@ -6,15 +6,15 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4(pub [f32; 4]); +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; use std::intrinsics::simd::*; fn main() { - let x = f32x4([1.0, 2.0, 3.0, 4.0]); - let y = f32x4([2.0, 1.0, 4.0, 3.0]); + let x = f32x4::from_array([1.0, 2.0, 3.0, 4.0]); + let y = f32x4::from_array([2.0, 1.0, 4.0, 3.0]); #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] let nan = f32::NAN; @@ -23,13 +23,13 @@ fn main() { #[cfg(any(target_arch = "mips", target_arch = "mips64"))] let nan = f32::from_bits(f32::NAN.to_bits() - 1); - let n = f32x4([nan, nan, nan, nan]); + let n = f32x4::from_array([nan, nan, nan, nan]); unsafe { let min0 = simd_fmin(x, y); let min1 = simd_fmin(y, x); assert_eq!(min0, min1); - let e = f32x4([1.0, 1.0, 3.0, 3.0]); + let e = f32x4::from_array([1.0, 1.0, 3.0, 3.0]); assert_eq!(min0, e); let minn = simd_fmin(x, n); assert_eq!(minn, x); @@ -39,7 +39,7 @@ fn main() { let max0 = simd_fmax(x, y); let max1 = simd_fmax(y, x); assert_eq!(max0, max1); - let e = f32x4([2.0, 2.0, 4.0, 4.0]); + let e = f32x4::from_array([2.0, 2.0, 4.0, 4.0]); assert_eq!(max0, e); let maxn = simd_fmax(x, n); assert_eq!(maxn, x); diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs index 4c97fb2141d..bf38a8b1720 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs @@ -2,80 +2,77 @@ #![allow(non_camel_case_types)] #![feature(repr_simd, core_intrinsics)] -#[repr(simd)] -#[derive(Copy, Clone)] -struct i32x4(pub [i32; 4]); +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone)] -struct U32([u32; N]); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct f32x4(pub [f32; 4]); +type U32 = Simd; macro_rules! all_eq { - ($a: expr, $b: expr) => {{ + ($a: expr, $b: expr $(,)?) => {{ let a = $a; let b = $b; - assert!(a.0 == b.0); + assert!(a == b); }}; } use std::intrinsics::simd::*; fn main() { - let x1 = i32x4([1, 2, 3, 4]); - let y1 = U32::<4>([1, 2, 3, 4]); - let z1 = f32x4([1.0, 2.0, 3.0, 4.0]); - let x2 = i32x4([2, 3, 4, 5]); - let y2 = U32::<4>([2, 3, 4, 5]); - let z2 = f32x4([2.0, 3.0, 4.0, 5.0]); - let x3 = i32x4([0, i32::MAX, i32::MIN, -1_i32]); - let y3 = U32::<4>([0, i32::MAX as _, i32::MIN as _, -1_i32 as _]); + let x1 = i32x4::from_array([1, 2, 3, 4]); + let y1 = U32::<4>::from_array([1, 2, 3, 4]); + let z1 = f32x4::from_array([1.0, 2.0, 3.0, 4.0]); + let x2 = i32x4::from_array([2, 3, 4, 5]); + let y2 = U32::<4>::from_array([2, 3, 4, 5]); + let z2 = f32x4::from_array([2.0, 3.0, 4.0, 5.0]); + let x3 = i32x4::from_array([0, i32::MAX, i32::MIN, -1_i32]); + let y3 = U32::<4>::from_array([0, i32::MAX as _, i32::MIN as _, -1_i32 as _]); unsafe { - all_eq!(simd_add(x1, x2), i32x4([3, 5, 7, 9])); - all_eq!(simd_add(x2, x1), i32x4([3, 5, 7, 9])); - all_eq!(simd_add(y1, y2), U32::<4>([3, 5, 7, 9])); - all_eq!(simd_add(y2, y1), U32::<4>([3, 5, 7, 9])); - all_eq!(simd_add(z1, z2), f32x4([3.0, 5.0, 7.0, 9.0])); - all_eq!(simd_add(z2, z1), f32x4([3.0, 5.0, 7.0, 9.0])); - - all_eq!(simd_mul(x1, x2), i32x4([2, 6, 12, 20])); - all_eq!(simd_mul(x2, x1), i32x4([2, 6, 12, 20])); - all_eq!(simd_mul(y1, y2), U32::<4>([2, 6, 12, 20])); - all_eq!(simd_mul(y2, y1), U32::<4>([2, 6, 12, 20])); - all_eq!(simd_mul(z1, z2), f32x4([2.0, 6.0, 12.0, 20.0])); - all_eq!(simd_mul(z2, z1), f32x4([2.0, 6.0, 12.0, 20.0])); - - all_eq!(simd_sub(x2, x1), i32x4([1, 1, 1, 1])); - all_eq!(simd_sub(x1, x2), i32x4([-1, -1, -1, -1])); - all_eq!(simd_sub(y2, y1), U32::<4>([1, 1, 1, 1])); - all_eq!(simd_sub(y1, y2), U32::<4>([!0, !0, !0, !0])); - all_eq!(simd_sub(z2, z1), f32x4([1.0, 1.0, 1.0, 1.0])); - all_eq!(simd_sub(z1, z2), f32x4([-1.0, -1.0, -1.0, -1.0])); - - all_eq!(simd_div(x1, x1), i32x4([1, 1, 1, 1])); - all_eq!(simd_div(i32x4([2, 4, 6, 8]), i32x4([2, 2, 2, 2])), x1); - all_eq!(simd_div(y1, y1), U32::<4>([1, 1, 1, 1])); - all_eq!(simd_div(U32::<4>([2, 4, 6, 8]), U32::<4>([2, 2, 2, 2])), y1); - all_eq!(simd_div(z1, z1), f32x4([1.0, 1.0, 1.0, 1.0])); - all_eq!(simd_div(z1, z2), f32x4([1.0 / 2.0, 2.0 / 3.0, 3.0 / 4.0, 4.0 / 5.0])); - all_eq!(simd_div(z2, z1), f32x4([2.0 / 1.0, 3.0 / 2.0, 4.0 / 3.0, 5.0 / 4.0])); - - all_eq!(simd_rem(x1, x1), i32x4([0, 0, 0, 0])); - all_eq!(simd_rem(x2, x1), i32x4([0, 1, 1, 1])); - all_eq!(simd_rem(y1, y1), U32::<4>([0, 0, 0, 0])); - all_eq!(simd_rem(y2, y1), U32::<4>([0, 1, 1, 1])); - all_eq!(simd_rem(z1, z1), f32x4([0.0, 0.0, 0.0, 0.0])); + all_eq!(simd_add(x1, x2), i32x4::from_array([3, 5, 7, 9])); + all_eq!(simd_add(x2, x1), i32x4::from_array([3, 5, 7, 9])); + all_eq!(simd_add(y1, y2), U32::<4>::from_array([3, 5, 7, 9])); + all_eq!(simd_add(y2, y1), U32::<4>::from_array([3, 5, 7, 9])); + all_eq!(simd_add(z1, z2), f32x4::from_array([3.0, 5.0, 7.0, 9.0])); + all_eq!(simd_add(z2, z1), f32x4::from_array([3.0, 5.0, 7.0, 9.0])); + + all_eq!(simd_mul(x1, x2), i32x4::from_array([2, 6, 12, 20])); + all_eq!(simd_mul(x2, x1), i32x4::from_array([2, 6, 12, 20])); + all_eq!(simd_mul(y1, y2), U32::<4>::from_array([2, 6, 12, 20])); + all_eq!(simd_mul(y2, y1), U32::<4>::from_array([2, 6, 12, 20])); + all_eq!(simd_mul(z1, z2), f32x4::from_array([2.0, 6.0, 12.0, 20.0])); + all_eq!(simd_mul(z2, z1), f32x4::from_array([2.0, 6.0, 12.0, 20.0])); + + all_eq!(simd_sub(x2, x1), i32x4::from_array([1, 1, 1, 1])); + all_eq!(simd_sub(x1, x2), i32x4::from_array([-1, -1, -1, -1])); + all_eq!(simd_sub(y2, y1), U32::<4>::from_array([1, 1, 1, 1])); + all_eq!(simd_sub(y1, y2), U32::<4>::from_array([!0, !0, !0, !0])); + all_eq!(simd_sub(z2, z1), f32x4::from_array([1.0, 1.0, 1.0, 1.0])); + all_eq!(simd_sub(z1, z2), f32x4::from_array([-1.0, -1.0, -1.0, -1.0])); + + all_eq!(simd_div(x1, x1), i32x4::from_array([1, 1, 1, 1])); + all_eq!(simd_div(i32x4::from_array([2, 4, 6, 8]), i32x4::from_array([2, 2, 2, 2])), x1); + all_eq!(simd_div(y1, y1), U32::<4>::from_array([1, 1, 1, 1])); + all_eq!( + simd_div(U32::<4>::from_array([2, 4, 6, 8]), U32::<4>::from_array([2, 2, 2, 2])), + y1, + ); + all_eq!(simd_div(z1, z1), f32x4::from_array([1.0, 1.0, 1.0, 1.0])); + all_eq!(simd_div(z1, z2), f32x4::from_array([1.0 / 2.0, 2.0 / 3.0, 3.0 / 4.0, 4.0 / 5.0])); + all_eq!(simd_div(z2, z1), f32x4::from_array([2.0 / 1.0, 3.0 / 2.0, 4.0 / 3.0, 5.0 / 4.0])); + + all_eq!(simd_rem(x1, x1), i32x4::from_array([0, 0, 0, 0])); + all_eq!(simd_rem(x2, x1), i32x4::from_array([0, 1, 1, 1])); + all_eq!(simd_rem(y1, y1), U32::<4>::from_array([0, 0, 0, 0])); + all_eq!(simd_rem(y2, y1), U32::<4>::from_array([0, 1, 1, 1])); + all_eq!(simd_rem(z1, z1), f32x4::from_array([0.0, 0.0, 0.0, 0.0])); all_eq!(simd_rem(z1, z2), z1); - all_eq!(simd_rem(z2, z1), f32x4([0.0, 1.0, 1.0, 1.0])); + all_eq!(simd_rem(z2, z1), f32x4::from_array([0.0, 1.0, 1.0, 1.0])); - all_eq!(simd_shl(x1, x2), i32x4([1 << 2, 2 << 3, 3 << 4, 4 << 5])); - all_eq!(simd_shl(x2, x1), i32x4([2 << 1, 3 << 2, 4 << 3, 5 << 4])); - all_eq!(simd_shl(y1, y2), U32::<4>([1 << 2, 2 << 3, 3 << 4, 4 << 5])); - all_eq!(simd_shl(y2, y1), U32::<4>([2 << 1, 3 << 2, 4 << 3, 5 << 4])); + all_eq!(simd_shl(x1, x2), i32x4::from_array([1 << 2, 2 << 3, 3 << 4, 4 << 5])); + all_eq!(simd_shl(x2, x1), i32x4::from_array([2 << 1, 3 << 2, 4 << 3, 5 << 4])); + all_eq!(simd_shl(y1, y2), U32::<4>::from_array([1 << 2, 2 << 3, 3 << 4, 4 << 5])); + all_eq!(simd_shl(y2, y1), U32::<4>::from_array([2 << 1, 3 << 2, 4 << 3, 5 << 4])); // test right-shift by assuming left-shift is correct all_eq!(simd_shr(simd_shl(x1, x2), x2), x1); @@ -85,7 +82,7 @@ fn main() { all_eq!( simd_funnel_shl(x1, x2, x1), - i32x4([ + i32x4::from_array([ (1 << 1) | (2 >> 31), (2 << 2) | (3 >> 30), (3 << 3) | (4 >> 29), @@ -94,7 +91,7 @@ fn main() { ); all_eq!( simd_funnel_shl(x2, x1, x1), - i32x4([ + i32x4::from_array([ (2 << 1) | (1 >> 31), (3 << 2) | (2 >> 30), (4 << 3) | (3 >> 29), @@ -103,7 +100,7 @@ fn main() { ); all_eq!( simd_funnel_shl(y1, y2, y1), - U32::<4>([ + U32::<4>::from_array([ (1 << 1) | (2 >> 31), (2 << 2) | (3 >> 30), (3 << 3) | (4 >> 29), @@ -112,7 +109,7 @@ fn main() { ); all_eq!( simd_funnel_shl(y2, y1, y1), - U32::<4>([ + U32::<4>::from_array([ (2 << 1) | (1 >> 31), (3 << 2) | (2 >> 30), (4 << 3) | (3 >> 29), @@ -122,7 +119,7 @@ fn main() { all_eq!( simd_funnel_shr(x1, x2, x1), - i32x4([ + i32x4::from_array([ (1 << 31) | (2 >> 1), (2 << 30) | (3 >> 2), (3 << 29) | (4 >> 3), @@ -131,7 +128,7 @@ fn main() { ); all_eq!( simd_funnel_shr(x2, x1, x1), - i32x4([ + i32x4::from_array([ (2 << 31) | (1 >> 1), (3 << 30) | (2 >> 2), (4 << 29) | (3 >> 3), @@ -140,7 +137,7 @@ fn main() { ); all_eq!( simd_funnel_shr(y1, y2, y1), - U32::<4>([ + U32::<4>::from_array([ (1 << 31) | (2 >> 1), (2 << 30) | (3 >> 2), (3 << 29) | (4 >> 3), @@ -149,7 +146,7 @@ fn main() { ); all_eq!( simd_funnel_shr(y2, y1, y1), - U32::<4>([ + U32::<4>::from_array([ (2 << 31) | (1 >> 1), (3 << 30) | (2 >> 2), (4 << 29) | (3 >> 3), @@ -159,52 +156,69 @@ fn main() { // ensure we get logical vs. arithmetic shifts correct let (a, b, c, d) = (-12, -123, -1234, -12345); - all_eq!(simd_shr(i32x4([a, b, c, d]), x1), i32x4([a >> 1, b >> 2, c >> 3, d >> 4])); all_eq!( - simd_shr(U32::<4>([a as u32, b as u32, c as u32, d as u32]), y1), - U32::<4>([(a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4]) + simd_shr(i32x4::from_array([a, b, c, d]), x1), + i32x4::from_array([a >> 1, b >> 2, c >> 3, d >> 4]), + ); + all_eq!( + simd_shr(U32::<4>::from_array([a as u32, b as u32, c as u32, d as u32]), y1), + U32::<4>::from_array([ + (a as u32) >> 1, + (b as u32) >> 2, + (c as u32) >> 3, + (d as u32) >> 4, + ]), ); - all_eq!(simd_and(x1, x2), i32x4([0, 2, 0, 4])); - all_eq!(simd_and(x2, x1), i32x4([0, 2, 0, 4])); - all_eq!(simd_and(y1, y2), U32::<4>([0, 2, 0, 4])); - all_eq!(simd_and(y2, y1), U32::<4>([0, 2, 0, 4])); + all_eq!(simd_and(x1, x2), i32x4::from_array([0, 2, 0, 4])); + all_eq!(simd_and(x2, x1), i32x4::from_array([0, 2, 0, 4])); + all_eq!(simd_and(y1, y2), U32::<4>::from_array([0, 2, 0, 4])); + all_eq!(simd_and(y2, y1), U32::<4>::from_array([0, 2, 0, 4])); - all_eq!(simd_or(x1, x2), i32x4([3, 3, 7, 5])); - all_eq!(simd_or(x2, x1), i32x4([3, 3, 7, 5])); - all_eq!(simd_or(y1, y2), U32::<4>([3, 3, 7, 5])); - all_eq!(simd_or(y2, y1), U32::<4>([3, 3, 7, 5])); + all_eq!(simd_or(x1, x2), i32x4::from_array([3, 3, 7, 5])); + all_eq!(simd_or(x2, x1), i32x4::from_array([3, 3, 7, 5])); + all_eq!(simd_or(y1, y2), U32::<4>::from_array([3, 3, 7, 5])); + all_eq!(simd_or(y2, y1), U32::<4>::from_array([3, 3, 7, 5])); - all_eq!(simd_xor(x1, x2), i32x4([3, 1, 7, 1])); - all_eq!(simd_xor(x2, x1), i32x4([3, 1, 7, 1])); - all_eq!(simd_xor(y1, y2), U32::<4>([3, 1, 7, 1])); - all_eq!(simd_xor(y2, y1), U32::<4>([3, 1, 7, 1])); + all_eq!(simd_xor(x1, x2), i32x4::from_array([3, 1, 7, 1])); + all_eq!(simd_xor(x2, x1), i32x4::from_array([3, 1, 7, 1])); + all_eq!(simd_xor(y1, y2), U32::<4>::from_array([3, 1, 7, 1])); + all_eq!(simd_xor(y2, y1), U32::<4>::from_array([3, 1, 7, 1])); - all_eq!(simd_neg(x1), i32x4([-1, -2, -3, -4])); - all_eq!(simd_neg(x2), i32x4([-2, -3, -4, -5])); - all_eq!(simd_neg(z1), f32x4([-1.0, -2.0, -3.0, -4.0])); - all_eq!(simd_neg(z2), f32x4([-2.0, -3.0, -4.0, -5.0])); + all_eq!(simd_neg(x1), i32x4::from_array([-1, -2, -3, -4])); + all_eq!(simd_neg(x2), i32x4::from_array([-2, -3, -4, -5])); + all_eq!(simd_neg(z1), f32x4::from_array([-1.0, -2.0, -3.0, -4.0])); + all_eq!(simd_neg(z2), f32x4::from_array([-2.0, -3.0, -4.0, -5.0])); - all_eq!(simd_bswap(x1), i32x4([0x01000000, 0x02000000, 0x03000000, 0x04000000])); - all_eq!(simd_bswap(y1), U32::<4>([0x01000000, 0x02000000, 0x03000000, 0x04000000])); + all_eq!( + simd_bswap(x1), + i32x4::from_array([0x01000000, 0x02000000, 0x03000000, 0x04000000]), + ); + all_eq!( + simd_bswap(y1), + U32::<4>::from_array([0x01000000, 0x02000000, 0x03000000, 0x04000000]), + ); all_eq!( simd_bitreverse(x1), - i32x4([0x80000000u32 as i32, 0x40000000, 0xc0000000u32 as i32, 0x20000000]) + i32x4::from_array([0x80000000u32 as i32, 0x40000000, 0xc0000000u32 as i32, 0x20000000]) + ); + all_eq!( + simd_bitreverse(y1), + U32::<4>::from_array([0x80000000, 0x40000000, 0xc0000000, 0x20000000]), ); - all_eq!(simd_bitreverse(y1), U32::<4>([0x80000000, 0x40000000, 0xc0000000, 0x20000000])); - all_eq!(simd_ctlz(x1), i32x4([31, 30, 30, 29])); - all_eq!(simd_ctlz(y1), U32::<4>([31, 30, 30, 29])); + all_eq!(simd_ctlz(x1), i32x4::from_array([31, 30, 30, 29])); + all_eq!(simd_ctlz(y1), U32::<4>::from_array([31, 30, 30, 29])); - all_eq!(simd_ctpop(x1), i32x4([1, 1, 2, 1])); - all_eq!(simd_ctpop(y1), U32::<4>([1, 1, 2, 1])); - all_eq!(simd_ctpop(x2), i32x4([1, 2, 1, 2])); - all_eq!(simd_ctpop(y2), U32::<4>([1, 2, 1, 2])); - all_eq!(simd_ctpop(x3), i32x4([0, 31, 1, 32])); - all_eq!(simd_ctpop(y3), U32::<4>([0, 31, 1, 32])); + all_eq!(simd_ctpop(x1), i32x4::from_array([1, 1, 2, 1])); + all_eq!(simd_ctpop(y1), U32::<4>::from_array([1, 1, 2, 1])); + all_eq!(simd_ctpop(x2), i32x4::from_array([1, 2, 1, 2])); + all_eq!(simd_ctpop(y2), U32::<4>::from_array([1, 2, 1, 2])); + all_eq!(simd_ctpop(x3), i32x4::from_array([0, 31, 1, 32])); + all_eq!(simd_ctpop(y3), U32::<4>::from_array([0, 31, 1, 32])); - all_eq!(simd_cttz(x1), i32x4([0, 1, 0, 2])); - all_eq!(simd_cttz(y1), U32::<4>([0, 1, 0, 2])); + all_eq!(simd_cttz(x1), i32x4::from_array([0, 1, 0, 2])); + all_eq!(simd_cttz(y1), U32::<4>::from_array([0, 1, 0, 2])); } } diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs index 4d12a312331..a997f123703 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs @@ -4,26 +4,24 @@ #![allow(non_camel_case_types)] #![feature(repr_simd, core_intrinsics)] -use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub}; +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct u32x4(pub [u32; 4]); +use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub}; -#[repr(simd)] -#[derive(Copy, Clone)] -struct I32([i32; N]); +type I32 = Simd; fn main() { // unsigned { const M: u32 = u32::MAX; - let a = u32x4([1, 2, 3, 4]); - let b = u32x4([2, 4, 6, 8]); - let m = u32x4([M, M, M, M]); - let m1 = u32x4([M - 1, M - 1, M - 1, M - 1]); - let z = u32x4([0, 0, 0, 0]); + let a = u32x4::from_array([1, 2, 3, 4]); + let b = u32x4::from_array([2, 4, 6, 8]); + let m = u32x4::from_array([M, M, M, M]); + let m1 = u32x4::from_array([M - 1, M - 1, M - 1, M - 1]); + let z = u32x4::from_array([0, 0, 0, 0]); unsafe { assert_eq!(simd_saturating_add(z, z), z); @@ -48,41 +46,41 @@ fn main() { const MIN: i32 = i32::MIN; const MAX: i32 = i32::MAX; - let a = I32::<4>([1, 2, 3, 4]); - let b = I32::<4>([2, 4, 6, 8]); - let c = I32::<4>([-1, -2, -3, -4]); - let d = I32::<4>([-2, -4, -6, -8]); + let a = I32::<4>::from_array([1, 2, 3, 4]); + let b = I32::<4>::from_array([2, 4, 6, 8]); + let c = I32::<4>::from_array([-1, -2, -3, -4]); + let d = I32::<4>::from_array([-2, -4, -6, -8]); - let max = I32::<4>([MAX, MAX, MAX, MAX]); - let max1 = I32::<4>([MAX - 1, MAX - 1, MAX - 1, MAX - 1]); - let min = I32::<4>([MIN, MIN, MIN, MIN]); - let min1 = I32::<4>([MIN + 1, MIN + 1, MIN + 1, MIN + 1]); + let max = I32::<4>::from_array([MAX, MAX, MAX, MAX]); + let max1 = I32::<4>::from_array([MAX - 1, MAX - 1, MAX - 1, MAX - 1]); + let min = I32::<4>::from_array([MIN, MIN, MIN, MIN]); + let min1 = I32::<4>::from_array([MIN + 1, MIN + 1, MIN + 1, MIN + 1]); - let z = I32::<4>([0, 0, 0, 0]); + let z = I32::<4>::from_array([0, 0, 0, 0]); unsafe { - assert_eq!(simd_saturating_add(z, z).0, z.0); - assert_eq!(simd_saturating_add(z, a).0, a.0); - assert_eq!(simd_saturating_add(b, z).0, b.0); - assert_eq!(simd_saturating_add(a, a).0, b.0); - assert_eq!(simd_saturating_add(a, max).0, max.0); - assert_eq!(simd_saturating_add(max, b).0, max.0); - assert_eq!(simd_saturating_add(max1, a).0, max.0); - assert_eq!(simd_saturating_add(min1, z).0, min1.0); - assert_eq!(simd_saturating_add(min, z).0, min.0); - assert_eq!(simd_saturating_add(min1, c).0, min.0); - assert_eq!(simd_saturating_add(min, c).0, min.0); - assert_eq!(simd_saturating_add(min1, d).0, min.0); - assert_eq!(simd_saturating_add(min, d).0, min.0); + assert_eq!(simd_saturating_add(z, z), z); + assert_eq!(simd_saturating_add(z, a), a); + assert_eq!(simd_saturating_add(b, z), b); + assert_eq!(simd_saturating_add(a, a), b); + assert_eq!(simd_saturating_add(a, max), max); + assert_eq!(simd_saturating_add(max, b), max); + assert_eq!(simd_saturating_add(max1, a), max); + assert_eq!(simd_saturating_add(min1, z), min1); + assert_eq!(simd_saturating_add(min, z), min); + assert_eq!(simd_saturating_add(min1, c), min); + assert_eq!(simd_saturating_add(min, c), min); + assert_eq!(simd_saturating_add(min1, d), min); + assert_eq!(simd_saturating_add(min, d), min); - assert_eq!(simd_saturating_sub(b, z).0, b.0); - assert_eq!(simd_saturating_sub(b, a).0, a.0); - assert_eq!(simd_saturating_sub(a, a).0, z.0); - assert_eq!(simd_saturating_sub(a, b).0, c.0); - assert_eq!(simd_saturating_sub(z, max).0, min1.0); - assert_eq!(simd_saturating_sub(min1, z).0, min1.0); - assert_eq!(simd_saturating_sub(min1, a).0, min.0); - assert_eq!(simd_saturating_sub(min1, b).0, min.0); + assert_eq!(simd_saturating_sub(b, z), b); + assert_eq!(simd_saturating_sub(b, a), a); + assert_eq!(simd_saturating_sub(a, a), z); + assert_eq!(simd_saturating_sub(a, b), c); + assert_eq!(simd_saturating_sub(z, max), min1); + assert_eq!(simd_saturating_sub(min1, z), min1); + assert_eq!(simd_saturating_sub(min1, a), min); + assert_eq!(simd_saturating_sub(min1, b), min); } } } diff --git a/tests/ui/simd/intrinsic/generic-as.rs b/tests/ui/simd/intrinsic/generic-as.rs index da53211cbc7..f9ed416b6ff 100644 --- a/tests/ui/simd/intrinsic/generic-as.rs +++ b/tests/ui/simd/intrinsic/generic-as.rs @@ -2,45 +2,47 @@ #![feature(repr_simd, core_intrinsics)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_as; -#[derive(Copy, Clone)] -#[repr(simd)] -struct V([T; 2]); +type V = Simd; fn main() { unsafe { - let u = V::([u32::MIN, u32::MAX]); + let u: V:: = Simd([u32::MIN, u32::MAX]); let i: V = simd_as(u); - assert_eq!(i.0[0], u.0[0] as i16); - assert_eq!(i.0[1], u.0[1] as i16); + assert_eq!(i[0], u[0] as i16); + assert_eq!(i[1], u[1] as i16); } unsafe { - let f = V::([f32::MIN, f32::MAX]); + let f: V:: = Simd([f32::MIN, f32::MAX]); let i: V = simd_as(f); - assert_eq!(i.0[0], f.0[0] as i16); - assert_eq!(i.0[1], f.0[1] as i16); + assert_eq!(i[0], f[0] as i16); + assert_eq!(i[1], f[1] as i16); } unsafe { - let f = V::([f32::MIN, f32::MAX]); + let f: V:: = Simd([f32::MIN, f32::MAX]); let u: V = simd_as(f); - assert_eq!(u.0[0], f.0[0] as u8); - assert_eq!(u.0[1], f.0[1] as u8); + assert_eq!(u[0], f[0] as u8); + assert_eq!(u[1], f[1] as u8); } unsafe { - let f = V::([f64::MIN, f64::MAX]); + let f: V:: = Simd([f64::MIN, f64::MAX]); let i: V = simd_as(f); - assert_eq!(i.0[0], f.0[0] as isize); - assert_eq!(i.0[1], f.0[1] as isize); + assert_eq!(i[0], f[0] as isize); + assert_eq!(i[1], f[1] as isize); } unsafe { - let f = V::([f64::MIN, f64::MAX]); + let f: V:: = Simd([f64::MIN, f64::MAX]); let u: V = simd_as(f); - assert_eq!(u.0[0], f.0[0] as usize); - assert_eq!(u.0[1], f.0[1] as usize); + assert_eq!(u[0], f[0] as usize); + assert_eq!(u[1], f[1] as usize); } } diff --git a/tests/ui/simd/intrinsic/generic-bswap-byte.rs b/tests/ui/simd/intrinsic/generic-bswap-byte.rs index 903a07656a7..d30a560b1c2 100644 --- a/tests/ui/simd/intrinsic/generic-bswap-byte.rs +++ b/tests/ui/simd/intrinsic/generic-bswap-byte.rs @@ -2,19 +2,15 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_bswap; - -#[repr(simd)] -#[derive(Copy, Clone)] -struct i8x4([i8; 4]); +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone)] -struct u8x4([u8; 4]); +use std::intrinsics::simd::simd_bswap; fn main() { unsafe { - assert_eq!(simd_bswap(i8x4([0, 1, 2, 3])).0, [0, 1, 2, 3]); - assert_eq!(simd_bswap(u8x4([0, 1, 2, 3])).0, [0, 1, 2, 3]); + assert_eq!(simd_bswap(i8x4::from_array([0, 1, 2, 3])).into_array(), [0, 1, 2, 3]); + assert_eq!(simd_bswap(u8x4::from_array([0, 1, 2, 3])).into_array(), [0, 1, 2, 3]); } } diff --git a/tests/ui/simd/intrinsic/generic-cast-pass.rs b/tests/ui/simd/intrinsic/generic-cast-pass.rs index 7a4663bcad2..0c3b00d65bf 100644 --- a/tests/ui/simd/intrinsic/generic-cast-pass.rs +++ b/tests/ui/simd/intrinsic/generic-cast-pass.rs @@ -2,55 +2,57 @@ #![feature(repr_simd, core_intrinsics)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_cast; use std::cmp::{max, min}; -#[derive(Copy, Clone)] -#[repr(simd)] -struct V([T; 2]); +type V = Simd; fn main() { unsafe { - let u = V::([i16::MIN as u32, i16::MAX as u32]); + let u: V:: = Simd([i16::MIN as u32, i16::MAX as u32]); let i: V = simd_cast(u); - assert_eq!(i.0[0], u.0[0] as i16); - assert_eq!(i.0[1], u.0[1] as i16); + assert_eq!(i[0], u[0] as i16); + assert_eq!(i[1], u[1] as i16); } unsafe { - let f = V::([i16::MIN as f32, i16::MAX as f32]); + let f: V:: = Simd([i16::MIN as f32, i16::MAX as f32]); let i: V = simd_cast(f); - assert_eq!(i.0[0], f.0[0] as i16); - assert_eq!(i.0[1], f.0[1] as i16); + assert_eq!(i[0], f[0] as i16); + assert_eq!(i[1], f[1] as i16); } unsafe { - let f = V::([u8::MIN as f32, u8::MAX as f32]); + let f: V:: = Simd([u8::MIN as f32, u8::MAX as f32]); let u: V = simd_cast(f); - assert_eq!(u.0[0], f.0[0] as u8); - assert_eq!(u.0[1], f.0[1] as u8); + assert_eq!(u[0], f[0] as u8); + assert_eq!(u[1], f[1] as u8); } unsafe { // We would like to do isize::MIN..=isize::MAX, but those values are not representable in // an f64, so we clamp to the range of an i32 to prevent running into UB. - let f = V::([ + let f: V:: = Simd([ max(isize::MIN, i32::MIN as isize) as f64, min(isize::MAX, i32::MAX as isize) as f64, ]); let i: V = simd_cast(f); - assert_eq!(i.0[0], f.0[0] as isize); - assert_eq!(i.0[1], f.0[1] as isize); + assert_eq!(i[0], f[0] as isize); + assert_eq!(i[1], f[1] as isize); } unsafe { - let f = V::([ + let f: V:: = Simd([ max(usize::MIN, u32::MIN as usize) as f64, min(usize::MAX, u32::MAX as usize) as f64, ]); let u: V = simd_cast(f); - assert_eq!(u.0[0], f.0[0] as usize); - assert_eq!(u.0[1], f.0[1] as usize); + assert_eq!(u[0], f[0] as usize); + assert_eq!(u[1], f[1] as usize); } } diff --git a/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs b/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs index ea34e9ffeb8..594d1d25d16 100644 --- a/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs +++ b/tests/ui/simd/intrinsic/generic-cast-pointer-width.rs @@ -1,18 +1,24 @@ //@ run-pass #![feature(repr_simd, core_intrinsics)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_cast; -#[derive(Copy, Clone)] -#[repr(simd)] -struct V([T; 4]); +type V = Simd; fn main() { - let u = V::([0, 1, 2, 3]); + let u: V:: = Simd([0, 1, 2, 3]); let uu32: V = unsafe { simd_cast(u) }; let ui64: V = unsafe { simd_cast(u) }; - for (u, (uu32, ui64)) in u.0.iter().zip(uu32.0.iter().zip(ui64.0.iter())) { + for (u, (uu32, ui64)) in u + .as_array() + .iter() + .zip(uu32.as_array().iter().zip(ui64.as_array().iter())) + { assert_eq!(*u as u32, *uu32); assert_eq!(*u as i64, *ui64); } diff --git a/tests/ui/simd/intrinsic/generic-comparison-pass.rs b/tests/ui/simd/intrinsic/generic-comparison-pass.rs index 50a05eecb03..3e803e8f603 100644 --- a/tests/ui/simd/intrinsic/generic-comparison-pass.rs +++ b/tests/ui/simd/intrinsic/generic-comparison-pass.rs @@ -3,17 +3,11 @@ #![feature(repr_simd, core_intrinsics, macro_metavar_expr_concat)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::{simd_eq, simd_ge, simd_gt, simd_le, simd_lt, simd_ne}; +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone)] -struct i32x4([i32; 4]); -#[repr(simd)] -#[derive(Copy, Clone)] -struct u32x4(pub [u32; 4]); -#[repr(simd)] -#[derive(Copy, Clone)] -struct f32x4(pub [f32; 4]); +use std::intrinsics::simd::{simd_eq, simd_ge, simd_gt, simd_le, simd_lt, simd_ne}; macro_rules! cmp { ($method: ident($lhs: expr, $rhs: expr)) => {{ @@ -21,10 +15,11 @@ macro_rules! cmp { let rhs = $rhs; let e: u32x4 = ${concat(simd_, $method)}($lhs, $rhs); // assume the scalar version is correct/the behaviour we want. - assert!((e.0[0] != 0) == lhs.0[0].$method(&rhs.0[0])); - assert!((e.0[1] != 0) == lhs.0[1].$method(&rhs.0[1])); - assert!((e.0[2] != 0) == lhs.0[2].$method(&rhs.0[2])); - assert!((e.0[3] != 0) == lhs.0[3].$method(&rhs.0[3])); + let (lhs, rhs, e) = (lhs.as_array(), rhs.as_array(), e.as_array()); + assert!((e[0] != 0) == lhs[0].$method(&rhs[0])); + assert!((e[1] != 0) == lhs[1].$method(&rhs[1])); + assert!((e[2] != 0) == lhs[2].$method(&rhs[2])); + assert!((e[3] != 0) == lhs[3].$method(&rhs[3])); }}; } macro_rules! tests { @@ -53,17 +48,17 @@ macro_rules! tests { fn main() { // 13 vs. -100 tests that we get signed vs. unsigned comparisons // correct (i32: 13 > -100, u32: 13 < -100). let i1 = i32x4(10, -11, 12, 13); - let i1 = i32x4([10, -11, 12, 13]); - let i2 = i32x4([5, -5, 20, -100]); - let i3 = i32x4([10, -11, 20, -100]); + let i1 = i32x4::from_array([10, -11, 12, 13]); + let i2 = i32x4::from_array([5, -5, 20, -100]); + let i3 = i32x4::from_array([10, -11, 20, -100]); - let u1 = u32x4([10, !11 + 1, 12, 13]); - let u2 = u32x4([5, !5 + 1, 20, !100 + 1]); - let u3 = u32x4([10, !11 + 1, 20, !100 + 1]); + let u1 = u32x4::from_array([10, !11 + 1, 12, 13]); + let u2 = u32x4::from_array([5, !5 + 1, 20, !100 + 1]); + let u3 = u32x4::from_array([10, !11 + 1, 20, !100 + 1]); - let f1 = f32x4([10.0, -11.0, 12.0, 13.0]); - let f2 = f32x4([5.0, -5.0, 20.0, -100.0]); - let f3 = f32x4([10.0, -11.0, 20.0, -100.0]); + let f1 = f32x4::from_array([10.0, -11.0, 12.0, 13.0]); + let f2 = f32x4::from_array([5.0, -5.0, 20.0, -100.0]); + let f3 = f32x4::from_array([10.0, -11.0, 20.0, -100.0]); unsafe { tests! { @@ -84,7 +79,7 @@ fn main() { // NAN comparisons are special: // -11 (*) 13 // -5 -100 (*) - let f4 = f32x4([f32::NAN, f1.0[1], f32::NAN, f2.0[3]]); + let f4 = f32x4::from_array([f32::NAN, f1[1], f32::NAN, f2[3]]); unsafe { tests! { diff --git a/tests/ui/simd/intrinsic/generic-elements-pass.rs b/tests/ui/simd/intrinsic/generic-elements-pass.rs index e4d47cdb381..f441d992e11 100644 --- a/tests/ui/simd/intrinsic/generic-elements-pass.rs +++ b/tests/ui/simd/intrinsic/generic-elements-pass.rs @@ -2,23 +2,14 @@ #![feature(repr_simd, intrinsics, core_intrinsics)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::{ simd_extract, simd_extract_dyn, simd_insert, simd_insert_dyn, simd_shuffle, }; -#[repr(simd)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[allow(non_camel_case_types)] -struct i32x2([i32; 2]); -#[repr(simd)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[allow(non_camel_case_types)] -struct i32x4([i32; 4]); -#[repr(simd)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[allow(non_camel_case_types)] -struct i32x8([i32; 8]); - #[repr(simd)] struct SimdShuffleIdx([u32; LEN]); @@ -34,26 +25,26 @@ macro_rules! all_eq { } fn main() { - let x2 = i32x2([20, 21]); - let x4 = i32x4([40, 41, 42, 43]); - let x8 = i32x8([80, 81, 82, 83, 84, 85, 86, 87]); + let x2 = i32x2::from_array([20, 21]); + let x4 = i32x4::from_array([40, 41, 42, 43]); + let x8 = i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 87]); unsafe { - all_eq!(simd_insert(x2, 0, 100), i32x2([100, 21])); - all_eq!(simd_insert(x2, 1, 100), i32x2([20, 100])); - - all_eq!(simd_insert(x4, 0, 100), i32x4([100, 41, 42, 43])); - all_eq!(simd_insert(x4, 1, 100), i32x4([40, 100, 42, 43])); - all_eq!(simd_insert(x4, 2, 100), i32x4([40, 41, 100, 43])); - all_eq!(simd_insert(x4, 3, 100), i32x4([40, 41, 42, 100])); - - all_eq!(simd_insert(x8, 0, 100), i32x8([100, 81, 82, 83, 84, 85, 86, 87])); - all_eq!(simd_insert(x8, 1, 100), i32x8([80, 100, 82, 83, 84, 85, 86, 87])); - all_eq!(simd_insert(x8, 2, 100), i32x8([80, 81, 100, 83, 84, 85, 86, 87])); - all_eq!(simd_insert(x8, 3, 100), i32x8([80, 81, 82, 100, 84, 85, 86, 87])); - all_eq!(simd_insert(x8, 4, 100), i32x8([80, 81, 82, 83, 100, 85, 86, 87])); - all_eq!(simd_insert(x8, 5, 100), i32x8([80, 81, 82, 83, 84, 100, 86, 87])); - all_eq!(simd_insert(x8, 6, 100), i32x8([80, 81, 82, 83, 84, 85, 100, 87])); - all_eq!(simd_insert(x8, 7, 100), i32x8([80, 81, 82, 83, 84, 85, 86, 100])); + all_eq!(simd_insert(x2, 0, 100), i32x2::from_array([100, 21])); + all_eq!(simd_insert(x2, 1, 100), i32x2::from_array([20, 100])); + + all_eq!(simd_insert(x4, 0, 100), i32x4::from_array([100, 41, 42, 43])); + all_eq!(simd_insert(x4, 1, 100), i32x4::from_array([40, 100, 42, 43])); + all_eq!(simd_insert(x4, 2, 100), i32x4::from_array([40, 41, 100, 43])); + all_eq!(simd_insert(x4, 3, 100), i32x4::from_array([40, 41, 42, 100])); + + all_eq!(simd_insert(x8, 0, 100), i32x8::from_array([100, 81, 82, 83, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 1, 100), i32x8::from_array([80, 100, 82, 83, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 2, 100), i32x8::from_array([80, 81, 100, 83, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 3, 100), i32x8::from_array([80, 81, 82, 100, 84, 85, 86, 87])); + all_eq!(simd_insert(x8, 4, 100), i32x8::from_array([80, 81, 82, 83, 100, 85, 86, 87])); + all_eq!(simd_insert(x8, 5, 100), i32x8::from_array([80, 81, 82, 83, 84, 100, 86, 87])); + all_eq!(simd_insert(x8, 6, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 100, 87])); + all_eq!(simd_insert(x8, 7, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 100])); all_eq!(simd_extract(x2, 0), 20); all_eq!(simd_extract(x2, 1), 21); @@ -73,22 +64,22 @@ fn main() { all_eq!(simd_extract(x8, 7), 87); } unsafe { - all_eq!(simd_insert_dyn(x2, 0, 100), i32x2([100, 21])); - all_eq!(simd_insert_dyn(x2, 1, 100), i32x2([20, 100])); - - all_eq!(simd_insert_dyn(x4, 0, 100), i32x4([100, 41, 42, 43])); - all_eq!(simd_insert_dyn(x4, 1, 100), i32x4([40, 100, 42, 43])); - all_eq!(simd_insert_dyn(x4, 2, 100), i32x4([40, 41, 100, 43])); - all_eq!(simd_insert_dyn(x4, 3, 100), i32x4([40, 41, 42, 100])); - - all_eq!(simd_insert_dyn(x8, 0, 100), i32x8([100, 81, 82, 83, 84, 85, 86, 87])); - all_eq!(simd_insert_dyn(x8, 1, 100), i32x8([80, 100, 82, 83, 84, 85, 86, 87])); - all_eq!(simd_insert_dyn(x8, 2, 100), i32x8([80, 81, 100, 83, 84, 85, 86, 87])); - all_eq!(simd_insert_dyn(x8, 3, 100), i32x8([80, 81, 82, 100, 84, 85, 86, 87])); - all_eq!(simd_insert_dyn(x8, 4, 100), i32x8([80, 81, 82, 83, 100, 85, 86, 87])); - all_eq!(simd_insert_dyn(x8, 5, 100), i32x8([80, 81, 82, 83, 84, 100, 86, 87])); - all_eq!(simd_insert_dyn(x8, 6, 100), i32x8([80, 81, 82, 83, 84, 85, 100, 87])); - all_eq!(simd_insert_dyn(x8, 7, 100), i32x8([80, 81, 82, 83, 84, 85, 86, 100])); + all_eq!(simd_insert_dyn(x2, 0, 100), i32x2::from_array([100, 21])); + all_eq!(simd_insert_dyn(x2, 1, 100), i32x2::from_array([20, 100])); + + all_eq!(simd_insert_dyn(x4, 0, 100), i32x4::from_array([100, 41, 42, 43])); + all_eq!(simd_insert_dyn(x4, 1, 100), i32x4::from_array([40, 100, 42, 43])); + all_eq!(simd_insert_dyn(x4, 2, 100), i32x4::from_array([40, 41, 100, 43])); + all_eq!(simd_insert_dyn(x4, 3, 100), i32x4::from_array([40, 41, 42, 100])); + + all_eq!(simd_insert_dyn(x8, 0, 100), i32x8::from_array([100, 81, 82, 83, 84, 85, 86, 87])); + all_eq!(simd_insert_dyn(x8, 1, 100), i32x8::from_array([80, 100, 82, 83, 84, 85, 86, 87])); + all_eq!(simd_insert_dyn(x8, 2, 100), i32x8::from_array([80, 81, 100, 83, 84, 85, 86, 87])); + all_eq!(simd_insert_dyn(x8, 3, 100), i32x8::from_array([80, 81, 82, 100, 84, 85, 86, 87])); + all_eq!(simd_insert_dyn(x8, 4, 100), i32x8::from_array([80, 81, 82, 83, 100, 85, 86, 87])); + all_eq!(simd_insert_dyn(x8, 5, 100), i32x8::from_array([80, 81, 82, 83, 84, 100, 86, 87])); + all_eq!(simd_insert_dyn(x8, 6, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 100, 87])); + all_eq!(simd_insert_dyn(x8, 7, 100), i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 100])); all_eq!(simd_extract_dyn(x2, 0), 20); all_eq!(simd_extract_dyn(x2, 1), 21); @@ -108,38 +99,47 @@ fn main() { all_eq!(simd_extract_dyn(x8, 7), 87); } - let y2 = i32x2([120, 121]); - let y4 = i32x4([140, 141, 142, 143]); - let y8 = i32x8([180, 181, 182, 183, 184, 185, 186, 187]); + let y2 = i32x2::from_array([120, 121]); + let y4 = i32x4::from_array([140, 141, 142, 143]); + let y8 = i32x8::from_array([180, 181, 182, 183, 184, 185, 186, 187]); unsafe { - all_eq!(simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0]) }), i32x2([121, 20])); + all_eq!( + simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0]) }), + i32x2::from_array([121, 20]) + ); all_eq!( simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0, 1, 2]) }), - i32x4([121, 20, 21, 120]) + i32x4::from_array([121, 20, 21, 120]) ); all_eq!( simd_shuffle(x2, y2, const { SimdShuffleIdx([3u32, 0, 1, 2, 1, 2, 3, 0]) }), - i32x8([121, 20, 21, 120, 21, 120, 121, 20]) + i32x8::from_array([121, 20, 21, 120, 21, 120, 121, 20]) ); - all_eq!(simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2]) }), i32x2([143, 42])); + all_eq!( + simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2]) }), + i32x2::from_array([143, 42]) + ); all_eq!( simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2, 5, 0]) }), - i32x4([143, 42, 141, 40]) + i32x4::from_array([143, 42, 141, 40]) ); all_eq!( simd_shuffle(x4, y4, const { SimdShuffleIdx([7u32, 2, 5, 0, 3, 6, 4, 1]) }), - i32x8([143, 42, 141, 40, 43, 142, 140, 41]) + i32x8::from_array([143, 42, 141, 40, 43, 142, 140, 41]) ); - all_eq!(simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5]) }), i32x2([183, 85])); + all_eq!( + simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5]) }), + i32x2::from_array([183, 85]) + ); all_eq!( simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5, 15, 0]) }), - i32x4([183, 85, 187, 80]) + i32x4::from_array([183, 85, 187, 80]) ); all_eq!( simd_shuffle(x8, y8, const { SimdShuffleIdx([11u32, 5, 15, 0, 3, 8, 12, 1]) }), - i32x8([183, 85, 187, 80, 83, 180, 184, 81]) + i32x8::from_array([183, 85, 187, 80, 83, 180, 184, 81]) ); } } diff --git a/tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs b/tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs index b98d4d6575b..c2418c019ed 100644 --- a/tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs +++ b/tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs @@ -6,24 +6,26 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::{simd_gather, simd_scatter}; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct x4(pub [T; 4]); +type x4 = Simd; fn main() { let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.]; - let default = x4([-3_f32, -3., -3., -3.]); - let s_strided = x4([0_f32, 2., -3., 6.]); - let mask = x4([-1_i32, -1, 0, -1]); + let default = x4::from_array([-3_f32, -3., -3., -3.]); + let s_strided = x4::from_array([0_f32, 2., -3., 6.]); + let mask = x4::from_array([-1_i32, -1, 0, -1]); // reading from *const unsafe { let pointer = x.as_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); let r_strided = simd_gather(default, pointers, mask); @@ -34,7 +36,7 @@ fn main() { unsafe { let pointer = x.as_mut_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); let r_strided = simd_gather(default, pointers, mask); @@ -45,9 +47,9 @@ fn main() { unsafe { let pointer = x.as_mut_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); - let values = x4([42_f32, 43_f32, 44_f32, 45_f32]); + let values = x4::from_array([42_f32, 43_f32, 44_f32, 45_f32]); simd_scatter(values, pointers, mask); assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]); @@ -65,14 +67,14 @@ fn main() { &x[7] as *const f32, ]; - let default = x4([y[0], y[0], y[0], y[0]]); - let s_strided = x4([y[0], y[2], y[0], y[6]]); + let default = x4::from_array([y[0], y[0], y[0], y[0]]); + let s_strided = x4::from_array([y[0], y[2], y[0], y[6]]); // reading from *const unsafe { let pointer = y.as_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); let r_strided = simd_gather(default, pointers, mask); @@ -83,7 +85,7 @@ fn main() { unsafe { let pointer = y.as_mut_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); let r_strided = simd_gather(default, pointers, mask); @@ -94,9 +96,9 @@ fn main() { unsafe { let pointer = y.as_mut_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(2), pointer.offset(4), pointer.offset(6)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i * 2))); - let values = x4([y[7], y[6], y[5], y[1]]); + let values = x4::from_array([y[7], y[6], y[5], y[1]]); simd_scatter(values, pointers, mask); let s = [ diff --git a/tests/ui/simd/intrinsic/generic-select-pass.rs b/tests/ui/simd/intrinsic/generic-select-pass.rs index 0e5f7c4902f..ff2d70d6a97 100644 --- a/tests/ui/simd/intrinsic/generic-select-pass.rs +++ b/tests/ui/simd/intrinsic/generic-select-pass.rs @@ -6,38 +6,24 @@ // Test that the simd_select intrinsics produces correct results. #![feature(repr_simd, core_intrinsics)] -use std::intrinsics::simd::{simd_select, simd_select_bitmask}; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct i32x4(pub [i32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct u32x4(pub [u32; 4]); +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct u32x8([u32; 8]); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4(pub [f32; 4]); +use std::intrinsics::simd::{simd_select, simd_select_bitmask}; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct b8x4(pub [i8; 4]); +type b8x4 = i8x4; fn main() { - let m0 = b8x4([!0, !0, !0, !0]); - let m1 = b8x4([0, 0, 0, 0]); - let m2 = b8x4([!0, !0, 0, 0]); - let m3 = b8x4([0, 0, !0, !0]); - let m4 = b8x4([!0, 0, !0, 0]); + let m0 = b8x4::from_array([!0, !0, !0, !0]); + let m1 = b8x4::from_array([0, 0, 0, 0]); + let m2 = b8x4::from_array([!0, !0, 0, 0]); + let m3 = b8x4::from_array([0, 0, !0, !0]); + let m4 = b8x4::from_array([!0, 0, !0, 0]); unsafe { - let a = i32x4([1, -2, 3, 4]); - let b = i32x4([5, 6, -7, 8]); + let a = i32x4::from_array([1, -2, 3, 4]); + let b = i32x4::from_array([5, 6, -7, 8]); let r: i32x4 = simd_select(m0, a, b); let e = a; @@ -48,21 +34,21 @@ fn main() { assert_eq!(r, e); let r: i32x4 = simd_select(m2, a, b); - let e = i32x4([1, -2, -7, 8]); + let e = i32x4::from_array([1, -2, -7, 8]); assert_eq!(r, e); let r: i32x4 = simd_select(m3, a, b); - let e = i32x4([5, 6, 3, 4]); + let e = i32x4::from_array([5, 6, 3, 4]); assert_eq!(r, e); let r: i32x4 = simd_select(m4, a, b); - let e = i32x4([1, 6, 3, 8]); + let e = i32x4::from_array([1, 6, 3, 8]); assert_eq!(r, e); } unsafe { - let a = u32x4([1, 2, 3, 4]); - let b = u32x4([5, 6, 7, 8]); + let a = u32x4::from_array([1, 2, 3, 4]); + let b = u32x4::from_array([5, 6, 7, 8]); let r: u32x4 = simd_select(m0, a, b); let e = a; @@ -73,21 +59,21 @@ fn main() { assert_eq!(r, e); let r: u32x4 = simd_select(m2, a, b); - let e = u32x4([1, 2, 7, 8]); + let e = u32x4::from_array([1, 2, 7, 8]); assert_eq!(r, e); let r: u32x4 = simd_select(m3, a, b); - let e = u32x4([5, 6, 3, 4]); + let e = u32x4::from_array([5, 6, 3, 4]); assert_eq!(r, e); let r: u32x4 = simd_select(m4, a, b); - let e = u32x4([1, 6, 3, 8]); + let e = u32x4::from_array([1, 6, 3, 8]); assert_eq!(r, e); } unsafe { - let a = f32x4([1., 2., 3., 4.]); - let b = f32x4([5., 6., 7., 8.]); + let a = f32x4::from_array([1., 2., 3., 4.]); + let b = f32x4::from_array([5., 6., 7., 8.]); let r: f32x4 = simd_select(m0, a, b); let e = a; @@ -98,23 +84,23 @@ fn main() { assert_eq!(r, e); let r: f32x4 = simd_select(m2, a, b); - let e = f32x4([1., 2., 7., 8.]); + let e = f32x4::from_array([1., 2., 7., 8.]); assert_eq!(r, e); let r: f32x4 = simd_select(m3, a, b); - let e = f32x4([5., 6., 3., 4.]); + let e = f32x4::from_array([5., 6., 3., 4.]); assert_eq!(r, e); let r: f32x4 = simd_select(m4, a, b); - let e = f32x4([1., 6., 3., 8.]); + let e = f32x4::from_array([1., 6., 3., 8.]); assert_eq!(r, e); } unsafe { let t = !0 as i8; let f = 0 as i8; - let a = b8x4([t, f, t, f]); - let b = b8x4([f, f, f, t]); + let a = b8x4::from_array([t, f, t, f]); + let b = b8x4::from_array([f, f, f, t]); let r: b8x4 = simd_select(m0, a, b); let e = a; @@ -125,21 +111,21 @@ fn main() { assert_eq!(r, e); let r: b8x4 = simd_select(m2, a, b); - let e = b8x4([t, f, f, t]); + let e = b8x4::from_array([t, f, f, t]); assert_eq!(r, e); let r: b8x4 = simd_select(m3, a, b); - let e = b8x4([f, f, t, f]); + let e = b8x4::from_array([f, f, t, f]); assert_eq!(r, e); let r: b8x4 = simd_select(m4, a, b); - let e = b8x4([t, f, t, t]); + let e = b8x4::from_array([t, f, t, t]); assert_eq!(r, e); } unsafe { - let a = u32x8([0, 1, 2, 3, 4, 5, 6, 7]); - let b = u32x8([8, 9, 10, 11, 12, 13, 14, 15]); + let a = u32x8::from_array([0, 1, 2, 3, 4, 5, 6, 7]); + let b = u32x8::from_array([8, 9, 10, 11, 12, 13, 14, 15]); let r: u32x8 = simd_select_bitmask(0u8, a, b); let e = b; @@ -150,21 +136,21 @@ fn main() { assert_eq!(r, e); let r: u32x8 = simd_select_bitmask(0b01010101u8, a, b); - let e = u32x8([0, 9, 2, 11, 4, 13, 6, 15]); + let e = u32x8::from_array([0, 9, 2, 11, 4, 13, 6, 15]); assert_eq!(r, e); let r: u32x8 = simd_select_bitmask(0b10101010u8, a, b); - let e = u32x8([8, 1, 10, 3, 12, 5, 14, 7]); + let e = u32x8::from_array([8, 1, 10, 3, 12, 5, 14, 7]); assert_eq!(r, e); let r: u32x8 = simd_select_bitmask(0b11110000u8, a, b); - let e = u32x8([8, 9, 10, 11, 4, 5, 6, 7]); + let e = u32x8::from_array([8, 9, 10, 11, 4, 5, 6, 7]); assert_eq!(r, e); } unsafe { - let a = u32x4([0, 1, 2, 3]); - let b = u32x4([4, 5, 6, 7]); + let a = u32x4::from_array([0, 1, 2, 3]); + let b = u32x4::from_array([4, 5, 6, 7]); let r: u32x4 = simd_select_bitmask(0u8, a, b); let e = b; @@ -175,15 +161,15 @@ fn main() { assert_eq!(r, e); let r: u32x4 = simd_select_bitmask(0b0101u8, a, b); - let e = u32x4([0, 5, 2, 7]); + let e = u32x4::from_array([0, 5, 2, 7]); assert_eq!(r, e); let r: u32x4 = simd_select_bitmask(0b1010u8, a, b); - let e = u32x4([4, 1, 6, 3]); + let e = u32x4::from_array([4, 1, 6, 3]); assert_eq!(r, e); let r: u32x4 = simd_select_bitmask(0b1100u8, a, b); - let e = u32x4([4, 5, 2, 3]); + let e = u32x4::from_array([4, 5, 2, 3]); assert_eq!(r, e); } } diff --git a/tests/ui/simd/intrinsic/inlining-issue67557.rs b/tests/ui/simd/intrinsic/inlining-issue67557.rs index 13e7266b2a5..14f180425d8 100644 --- a/tests/ui/simd/intrinsic/inlining-issue67557.rs +++ b/tests/ui/simd/intrinsic/inlining-issue67557.rs @@ -5,11 +5,13 @@ //@ compile-flags: -Zmir-opt-level=4 #![feature(core_intrinsics, repr_simd)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_shuffle; -#[repr(simd)] -#[derive(Debug, PartialEq)] -struct Simd2([u8; 2]); +type Simd2 = u8x2; #[repr(simd)] struct SimdShuffleIdx([u32; LEN]); @@ -17,7 +19,11 @@ struct SimdShuffleIdx([u32; LEN]); fn main() { unsafe { const IDX: SimdShuffleIdx<2> = SimdShuffleIdx([0, 1]); - let p_res: Simd2 = simd_shuffle(Simd2([10, 11]), Simd2([12, 13]), IDX); + let p_res: Simd2 = simd_shuffle( + Simd2::from_array([10, 11]), + Simd2::from_array([12, 13]), + IDX, + ); let a_res: Simd2 = inline_me(); assert_10_11(p_res); @@ -27,16 +33,16 @@ fn main() { #[inline(never)] fn assert_10_11(x: Simd2) { - assert_eq!(x, Simd2([10, 11])); + assert_eq!(x.into_array(), [10, 11]); } #[inline(never)] fn assert_10_13(x: Simd2) { - assert_eq!(x, Simd2([10, 13])); + assert_eq!(x.into_array(), [10, 13]); } #[inline(always)] unsafe fn inline_me() -> Simd2 { const IDX: SimdShuffleIdx<2> = SimdShuffleIdx([0, 3]); - simd_shuffle(Simd2([10, 11]), Simd2([12, 13]), IDX) + simd_shuffle(Simd2::from_array([10, 11]), Simd2::from_array([12, 13]), IDX) } diff --git a/tests/ui/simd/intrinsic/ptr-cast.rs b/tests/ui/simd/intrinsic/ptr-cast.rs index 3a73c0273e1..63b65d83f76 100644 --- a/tests/ui/simd/intrinsic/ptr-cast.rs +++ b/tests/ui/simd/intrinsic/ptr-cast.rs @@ -2,18 +2,20 @@ #![feature(repr_simd, core_intrinsics)] +#[path = "../../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::{simd_cast_ptr, simd_expose_provenance, simd_with_exposed_provenance}; -#[derive(Copy, Clone)] -#[repr(simd)] -struct V([T; 2]); +type V = Simd; fn main() { unsafe { let mut foo = 4i8; let ptr = &mut foo as *mut i8; - let ptrs = V::<*mut i8>([ptr, core::ptr::null_mut()]); + let ptrs: V::<*mut i8> = Simd([ptr, core::ptr::null_mut()]); // change constness and type let const_ptrs: V<*const u8> = simd_cast_ptr(ptrs); @@ -22,8 +24,8 @@ fn main() { let with_exposed_provenance: V<*mut i8> = simd_with_exposed_provenance(exposed_addr); - assert!(const_ptrs.0 == [ptr as *const u8, core::ptr::null()]); - assert!(exposed_addr.0 == [ptr as usize, 0]); - assert!(with_exposed_provenance.0 == ptrs.0); + assert!(const_ptrs.into_array() == [ptr as *const u8, core::ptr::null()]); + assert!(exposed_addr.into_array() == [ptr as usize, 0]); + assert!(with_exposed_provenance.into_array() == ptrs.into_array()); } } diff --git a/tests/ui/simd/issue-39720.rs b/tests/ui/simd/issue-39720.rs index db441e55167..09d6142c920 100644 --- a/tests/ui/simd/issue-39720.rs +++ b/tests/ui/simd/issue-39720.rs @@ -2,16 +2,16 @@ #![feature(repr_simd, core_intrinsics)] -#[repr(simd)] -#[derive(Copy, Clone, Debug)] -pub struct Char3(pub [i8; 3]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, Debug)] -pub struct Short3(pub [i16; 3]); +pub type Char3 = Simd; + +pub type Short3 = Simd; fn main() { - let cast: Short3 = unsafe { std::intrinsics::simd::simd_cast(Char3([10, -3, -9])) }; + let cast: Short3 = unsafe { std::intrinsics::simd::simd_cast(Char3::from_array([10, -3, -9])) }; println!("{:?}", cast); } diff --git a/tests/ui/simd/issue-85915-simd-ptrs.rs b/tests/ui/simd/issue-85915-simd-ptrs.rs index 4e2379d0525..a74c36fabc1 100644 --- a/tests/ui/simd/issue-85915-simd-ptrs.rs +++ b/tests/ui/simd/issue-85915-simd-ptrs.rs @@ -6,35 +6,27 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::{simd_gather, simd_scatter}; - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct cptrx4([*const T; 4]); +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct mptrx4([*mut T; 4]); +use std::intrinsics::simd::{simd_gather, simd_scatter}; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4([f32; 4]); +type cptrx4 = Simd<*const T, 4>; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct i32x4([i32; 4]); +type mptrx4 = Simd<*mut T, 4>; fn main() { let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.]; - let default = f32x4([-3_f32, -3., -3., -3.]); - let s_strided = f32x4([0_f32, 2., -3., 6.]); - let mask = i32x4([-1_i32, -1, 0, -1]); + let default = f32x4::from_array([-3_f32, -3., -3., -3.]); + let s_strided = f32x4::from_array([0_f32, 2., -3., 6.]); + let mask = i32x4::from_array([-1_i32, -1, 0, -1]); // reading from *const unsafe { let pointer = &x as *const f32; - let pointers = cptrx4([ + let pointers = cptrx4::from_array([ pointer.offset(0) as *const f32, pointer.offset(2), pointer.offset(4), @@ -49,14 +41,14 @@ fn main() { // writing to *mut unsafe { let pointer = &mut x as *mut f32; - let pointers = mptrx4([ + let pointers = mptrx4::from_array([ pointer.offset(0) as *mut f32, pointer.offset(2), pointer.offset(4), pointer.offset(6), ]); - let values = f32x4([42_f32, 43_f32, 44_f32, 45_f32]); + let values = f32x4::from_array([42_f32, 43_f32, 44_f32, 45_f32]); simd_scatter(values, pointers, mask); assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]); diff --git a/tests/ui/simd/issue-89193.rs b/tests/ui/simd/issue-89193.rs index a6c3017572a..da4cd456589 100644 --- a/tests/ui/simd/issue-89193.rs +++ b/tests/ui/simd/issue-89193.rs @@ -6,36 +6,38 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::simd_gather; -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct x4(pub [T; 4]); +type x4 = Simd; fn main() { let x: [usize; 4] = [10, 11, 12, 13]; - let default = x4([0_usize, 1, 2, 3]); + let default = x4::from_array([0_usize, 1, 2, 3]); let all_set = u8::MAX as i8; // aka -1 - let mask = x4([all_set, all_set, all_set, all_set]); - let expected = x4([10_usize, 11, 12, 13]); + let mask = x4::from_array([all_set, all_set, all_set, all_set]); + let expected = x4::from_array([10_usize, 11, 12, 13]); unsafe { let pointer = x.as_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(1), pointer.offset(2), pointer.offset(3)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i))); let result = simd_gather(default, pointers, mask); assert_eq!(result, expected); } // and again for isize let x: [isize; 4] = [10, 11, 12, 13]; - let default = x4([0_isize, 1, 2, 3]); - let expected = x4([10_isize, 11, 12, 13]); + let default = x4::from_array([0_isize, 1, 2, 3]); + let expected = x4::from_array([10_isize, 11, 12, 13]); unsafe { let pointer = x.as_ptr(); let pointers = - x4([pointer.offset(0), pointer.offset(1), pointer.offset(2), pointer.offset(3)]); + x4::from_array(std::array::from_fn(|i| pointer.add(i))); let result = simd_gather(default, pointers, mask); assert_eq!(result, expected); } diff --git a/tests/ui/simd/masked-load-store.rs b/tests/ui/simd/masked-load-store.rs index 69ea76581ee..da32ba611c4 100644 --- a/tests/ui/simd/masked-load-store.rs +++ b/tests/ui/simd/masked-load-store.rs @@ -1,11 +1,11 @@ //@ run-pass #![feature(repr_simd, core_intrinsics)] -use std::intrinsics::simd::{simd_masked_load, simd_masked_store}; +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[derive(Copy, Clone)] -#[repr(simd)] -struct Simd([T; N]); +use std::intrinsics::simd::{simd_masked_load, simd_masked_store}; fn main() { unsafe { @@ -15,7 +15,7 @@ fn main() { let b: Simd = simd_masked_load(Simd::([-1, 0, -1, -1]), b_src.as_ptr(), b_default); - assert_eq!(&b.0, &[4, 9, 6, 7]); + assert_eq!(b.as_array(), &[4, 9, 6, 7]); let mut output = [u8::MAX; 5]; diff --git a/tests/ui/simd/monomorphize-shuffle-index.rs b/tests/ui/simd/monomorphize-shuffle-index.rs index a56f2ea1452..1490f8e2319 100644 --- a/tests/ui/simd/monomorphize-shuffle-index.rs +++ b/tests/ui/simd/monomorphize-shuffle-index.rs @@ -11,6 +11,10 @@ )] #![allow(incomplete_features)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + #[cfg(old)] use std::intrinsics::simd::simd_shuffle; @@ -18,10 +22,6 @@ use std::intrinsics::simd::simd_shuffle; #[rustc_intrinsic] unsafe fn simd_shuffle_const_generic(a: T, b: T) -> U; -#[derive(Copy, Clone)] -#[repr(simd)] -struct Simd([T; N]); - trait Shuffle { const I: Simd; const J: &'static [u32] = &Self::I.0; @@ -57,9 +57,9 @@ fn main() { let b = Simd::([4, 5, 6, 7]); unsafe { let x: Simd = I1.shuffle(a, b); - assert_eq!(x.0, [0, 2, 4, 6]); + assert_eq!(x.into_array(), [0, 2, 4, 6]); let y: Simd = I2.shuffle(a, b); - assert_eq!(y.0, [1, 5]); + assert_eq!(y.into_array(), [1, 5]); } } diff --git a/tests/ui/simd/repr_packed.rs b/tests/ui/simd/repr_packed.rs index cc54477ae71..f0c6de7c402 100644 --- a/tests/ui/simd/repr_packed.rs +++ b/tests/ui/simd/repr_packed.rs @@ -3,15 +3,16 @@ #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] -use std::intrinsics::simd::simd_add; +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[repr(simd, packed)] -struct Simd([T; N]); +use std::intrinsics::simd::simd_add; fn check_size_align() { use std::mem; - assert_eq!(mem::size_of::>(), mem::size_of::<[T; N]>()); - assert_eq!(mem::size_of::>() % mem::align_of::>(), 0); + assert_eq!(mem::size_of::>(), mem::size_of::<[T; N]>()); + assert_eq!(mem::size_of::>() % mem::align_of::>(), 0); } fn check_ty() { @@ -35,14 +36,21 @@ fn main() { unsafe { // powers-of-two have no padding and have the same layout as #[repr(simd)] - let x: Simd = - simd_add(Simd::([0., 1., 2., 3.]), Simd::([2., 2., 2., 2.])); - assert_eq!(std::mem::transmute::<_, [f64; 4]>(x), [2., 3., 4., 5.]); + let x: PackedSimd = + simd_add( + PackedSimd::([0., 1., 2., 3.]), + PackedSimd::([2., 2., 2., 2.]), + ); + assert_eq!(x.into_array(), [2., 3., 4., 5.]); // non-powers-of-two should have padding (which is removed by #[repr(packed)]), // but the intrinsic handles it - let x: Simd = simd_add(Simd::([0., 1., 2.]), Simd::([2., 2., 2.])); - let arr: [f64; 3] = x.0; + let x: PackedSimd = + simd_add( + PackedSimd::([0., 1., 2.]), + PackedSimd::([2., 2., 2.]), + ); + let arr: [f64; 3] = x.into_array(); assert_eq!(arr, [2., 3., 4.]); } } diff --git a/tests/ui/simd/shuffle.rs b/tests/ui/simd/shuffle.rs index cd270edcf00..061571a4786 100644 --- a/tests/ui/simd/shuffle.rs +++ b/tests/ui/simd/shuffle.rs @@ -10,10 +10,16 @@ use std::marker::ConstParamTy; use std::intrinsics::simd::simd_shuffle; +// not using `minisimd` because of the `ConstParamTy` #[derive(Copy, Clone, ConstParamTy, PartialEq, Eq)] #[repr(simd)] struct Simd([T; N]); +fn into_array(v: Simd) -> [T; N] { + const { assert!(size_of::>() == size_of::<[T; N]>()) } + unsafe { std::intrinsics::transmute_unchecked(v) } +} + unsafe fn __shuffle_vector16, T, U>(x: T, y: T) -> U { simd_shuffle(x, y, IDX) } @@ -25,10 +31,10 @@ fn main() { let b = Simd::([4, 5, 6, 7]); unsafe { let x: Simd = simd_shuffle(a, b, I1); - assert_eq!(x.0, [0, 2, 4, 6]); + assert_eq!(into_array(x), [0, 2, 4, 6]); let y: Simd = simd_shuffle(a, b, I2); - assert_eq!(y.0, [1, 5]); + assert_eq!(into_array(y), [1, 5]); } // Test that an indirection (via an unnamed constant) diff --git a/tests/ui/simd/simd-bitmask-notpow2.rs b/tests/ui/simd/simd-bitmask-notpow2.rs index 4935097065e..b9af591d1b9 100644 --- a/tests/ui/simd/simd-bitmask-notpow2.rs +++ b/tests/ui/simd/simd-bitmask-notpow2.rs @@ -4,21 +4,23 @@ //@ ignore-endian-big #![feature(repr_simd, core_intrinsics)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + use std::intrinsics::simd::{simd_bitmask, simd_select_bitmask}; fn main() { // Non-power-of-2 multi-byte mask. - #[repr(simd, packed)] #[allow(non_camel_case_types)] - #[derive(Copy, Clone, Debug, PartialEq)] - struct i32x10([i32; 10]); + type i32x10 = PackedSimd; impl i32x10 { fn splat(x: i32) -> Self { Self([x; 10]) } } unsafe { - let mask = i32x10([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]); + let mask = i32x10::from_array([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]); let mask_bits = if cfg!(target_endian = "little") { 0b0101001011 } else { 0b1101001010 }; let mask_bytes = if cfg!(target_endian = "little") { [0b01001011, 0b01] } else { [0b11, 0b01001010] }; @@ -43,17 +45,20 @@ fn main() { } // Test for a mask where the next multiple of 8 is not a power of two. - #[repr(simd, packed)] #[allow(non_camel_case_types)] - #[derive(Copy, Clone, Debug, PartialEq)] - struct i32x20([i32; 20]); + type i32x20 = PackedSimd; impl i32x20 { fn splat(x: i32) -> Self { Self([x; 20]) } } unsafe { - let mask = i32x20([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0, 0, 0, 0, !0, !0, !0, !0, !0, !0, !0]); + let mask = i32x20::from_array([ + !0, !0, 0, !0, 0, + 0, !0, 0, !0, 0, + 0, 0, 0, !0, !0, + !0, !0, !0, !0, !0, + ]); let mask_bits = if cfg!(target_endian = "little") { 0b11111110000101001011 } else { diff --git a/tests/ui/simd/simd-bitmask.rs b/tests/ui/simd/simd-bitmask.rs index 6fcceeaa24b..609dae3647b 100644 --- a/tests/ui/simd/simd-bitmask.rs +++ b/tests/ui/simd/simd-bitmask.rs @@ -1,11 +1,11 @@ //@run-pass #![feature(repr_simd, core_intrinsics)] -use std::intrinsics::simd::{simd_bitmask, simd_select_bitmask}; +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; -#[derive(Copy, Clone)] -#[repr(simd)] -struct Simd([T; N]); +use std::intrinsics::simd::{simd_bitmask, simd_select_bitmask}; fn main() { unsafe { @@ -41,11 +41,11 @@ fn main() { let mask = if cfg!(target_endian = "little") { 0b0101u8 } else { 0b1010u8 }; let r = simd_select_bitmask(mask, a, b); - assert_eq!(r.0, e); + assert_eq!(r.into_array(), e); let mask = if cfg!(target_endian = "little") { [0b0101u8] } else { [0b1010u8] }; let r = simd_select_bitmask(mask, a, b); - assert_eq!(r.0, e); + assert_eq!(r.into_array(), e); let a = Simd::([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); let b = Simd::([16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]); @@ -57,7 +57,7 @@ fn main() { 0b0011000000001010u16 }; let r = simd_select_bitmask(mask, a, b); - assert_eq!(r.0, e); + assert_eq!(r.into_array(), e); let mask = if cfg!(target_endian = "little") { [0b00001100u8, 0b01010000u8] @@ -65,6 +65,6 @@ fn main() { [0b00110000u8, 0b00001010u8] }; let r = simd_select_bitmask(mask, a, b); - assert_eq!(r.0, e); + assert_eq!(r.into_array(), e); } } diff --git a/tests/ui/simd/target-feature-mixup.rs b/tests/ui/simd/target-feature-mixup.rs index 77f18615248..82902891b97 100644 --- a/tests/ui/simd/target-feature-mixup.rs +++ b/tests/ui/simd/target-feature-mixup.rs @@ -8,6 +8,11 @@ #![feature(repr_simd, target_feature, cfg_target_feature)] +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +#[allow(unused)] +use minisimd::*; + use std::process::{Command, ExitStatus}; use std::env; @@ -50,19 +55,13 @@ fn is_sigill(status: ExitStatus) -> bool { #[allow(nonstandard_style)] mod test { // An SSE type - #[repr(simd)] - #[derive(PartialEq, Debug, Clone, Copy)] - struct __m128i([u64; 2]); + type __m128i = super::u64x2; // An AVX type - #[repr(simd)] - #[derive(PartialEq, Debug, Clone, Copy)] - struct __m256i([u64; 4]); + type __m256i = super::u64x4; // An AVX-512 type - #[repr(simd)] - #[derive(PartialEq, Debug, Clone, Copy)] - struct __m512i([u64; 8]); + type __m512i = super::u64x8; pub fn main(level: &str) { unsafe { @@ -88,9 +87,9 @@ mod test { )*) => ($( $(#[$attr])* unsafe fn $main(level: &str) { - let m128 = __m128i([1, 2]); - let m256 = __m256i([3, 4, 5, 6]); - let m512 = __m512i([7, 8, 9, 10, 11, 12, 13, 14]); + let m128 = __m128i::from_array([1, 2]); + let m256 = __m256i::from_array([3, 4, 5, 6]); + let m512 = __m512i::from_array([7, 8, 9, 10, 11, 12, 13, 14]); assert_eq!(id_sse_128(m128), m128); assert_eq!(id_sse_256(m256), m256); assert_eq!(id_sse_512(m512), m512); @@ -125,55 +124,55 @@ mod test { #[target_feature(enable = "sse2")] unsafe fn id_sse_128(a: __m128i) -> __m128i { - assert_eq!(a, __m128i([1, 2])); + assert_eq!(a, __m128i::from_array([1, 2])); a.clone() } #[target_feature(enable = "sse2")] unsafe fn id_sse_256(a: __m256i) -> __m256i { - assert_eq!(a, __m256i([3, 4, 5, 6])); + assert_eq!(a, __m256i::from_array([3, 4, 5, 6])); a.clone() } #[target_feature(enable = "sse2")] unsafe fn id_sse_512(a: __m512i) -> __m512i { - assert_eq!(a, __m512i([7, 8, 9, 10, 11, 12, 13, 14])); + assert_eq!(a, __m512i::from_array([7, 8, 9, 10, 11, 12, 13, 14])); a.clone() } #[target_feature(enable = "avx")] unsafe fn id_avx_128(a: __m128i) -> __m128i { - assert_eq!(a, __m128i([1, 2])); + assert_eq!(a, __m128i::from_array([1, 2])); a.clone() } #[target_feature(enable = "avx")] unsafe fn id_avx_256(a: __m256i) -> __m256i { - assert_eq!(a, __m256i([3, 4, 5, 6])); + assert_eq!(a, __m256i::from_array([3, 4, 5, 6])); a.clone() } #[target_feature(enable = "avx")] unsafe fn id_avx_512(a: __m512i) -> __m512i { - assert_eq!(a, __m512i([7, 8, 9, 10, 11, 12, 13, 14])); + assert_eq!(a, __m512i::from_array([7, 8, 9, 10, 11, 12, 13, 14])); a.clone() } #[target_feature(enable = "avx512bw")] unsafe fn id_avx512_128(a: __m128i) -> __m128i { - assert_eq!(a, __m128i([1, 2])); + assert_eq!(a, __m128i::from_array([1, 2])); a.clone() } #[target_feature(enable = "avx512bw")] unsafe fn id_avx512_256(a: __m256i) -> __m256i { - assert_eq!(a, __m256i([3, 4, 5, 6])); + assert_eq!(a, __m256i::from_array([3, 4, 5, 6])); a.clone() } #[target_feature(enable = "avx512bw")] unsafe fn id_avx512_512(a: __m512i) -> __m512i { - assert_eq!(a, __m512i([7, 8, 9, 10, 11, 12, 13, 14])); + assert_eq!(a, __m512i::from_array([7, 8, 9, 10, 11, 12, 13, 14])); a.clone() } } -- cgit 1.4.1-3-g733a5 From 41ce1ed252f194756fb2f3e3e92bbdfb3940088d Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 6 Mar 2025 19:13:46 -0800 Subject: Ban projecting into SIMD types [MCP838] --- compiler/rustc_codegen_ssa/src/mir/operand.rs | 19 ++++---------- compiler/rustc_mir_transform/src/validate.rs | 9 +++++++ tests/codegen/simd/project-to-simd-array-field.rs | 31 ----------------------- tests/ui/mir/validate/project-into-simd.rs | 18 +++++++++++++ tests/ui/simd/issue-105439.rs | 4 ++- 5 files changed, 35 insertions(+), 46 deletions(-) delete mode 100644 tests/codegen/simd/project-to-simd-array-field.rs create mode 100644 tests/ui/mir/validate/project-into-simd.rs (limited to 'tests/codegen') diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 6a3fdb6ede1..06bedaaa4a2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -329,20 +329,11 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let offset = self.layout.fields.offset(i); if !bx.is_backend_ref(self.layout) && bx.is_backend_ref(field) { - if let BackendRepr::SimdVector { count, .. } = self.layout.backend_repr - && let BackendRepr::Memory { sized: true } = field.backend_repr - && count.is_power_of_two() - { - assert_eq!(field.size, self.layout.size); - // This is being deprecated, but for now stdarch still needs it for - // Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]); - let place = PlaceRef::alloca(bx, field); - self.val.store(bx, place.val.with_type(self.layout)); - return bx.load_operand(place); - } else { - // Part of https://github.com/rust-lang/compiler-team/issues/838 - bug!("Non-ref type {self:?} cannot project to ref field type {field:?}"); - } + // Part of https://github.com/rust-lang/compiler-team/issues/838 + span_bug!( + fx.mir.span, + "Non-ref type {self:?} cannot project to ref field type {field:?}", + ); } let val = if field.is_zst() { diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 659ca4df159..5860072d541 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -721,6 +721,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } + if adt_def.repr().simd() { + self.fail( + location, + format!( + "Projecting into SIMD type {adt_def:?} is banned by MCP#838" + ), + ); + } + let var = parent_ty.variant_index.unwrap_or(FIRST_VARIANT); let Some(field) = adt_def.variant(var).fields.get(f) else { fail_out_of_bounds(self, location); diff --git a/tests/codegen/simd/project-to-simd-array-field.rs b/tests/codegen/simd/project-to-simd-array-field.rs deleted file mode 100644 index 29fab640633..00000000000 --- a/tests/codegen/simd/project-to-simd-array-field.rs +++ /dev/null @@ -1,31 +0,0 @@ -//@compile-flags: -Copt-level=3 - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] - -#[allow(non_camel_case_types)] -#[derive(Clone, Copy)] -#[repr(simd)] -struct i32x4([i32; 4]); - -#[inline(always)] -fn to_array4(a: i32x4) -> [i32; 4] { - a.0 -} - -// CHECK-LABEL: simd_add_self_then_return_array( -// CHECK-SAME: ptr{{.+}}sret{{.+}}%[[RET:.+]], -// CHECK-SAME: ptr{{.+}}%a) -#[no_mangle] -pub fn simd_add_self_then_return_array(a: &i32x4) -> [i32; 4] { - // It would be nice to just ban `.0` into simd types, - // but until we do this has to keep working. - // See also - - // CHECK: %[[T1:.+]] = load <4 x i32>, ptr %a - // CHECK: %[[T2:.+]] = shl <4 x i32> %[[T1]], {{splat \(i32 1\)|}} - // CHECK: store <4 x i32> %[[T2]], ptr %[[RET]] - let a = *a; - let b = unsafe { core::intrinsics::simd::simd_add(a, a) }; - to_array4(b) -} diff --git a/tests/ui/mir/validate/project-into-simd.rs b/tests/ui/mir/validate/project-into-simd.rs new file mode 100644 index 00000000000..67766c8c4b0 --- /dev/null +++ b/tests/ui/mir/validate/project-into-simd.rs @@ -0,0 +1,18 @@ +// Optimized MIR shouldn't have critical call edges +// +//@ build-fail +//@ edition: 2021 +//@ compile-flags: --crate-type=lib +//@ failure-status: 101 +//@ dont-check-compiler-stderr + +#![feature(repr_simd)] + +#[repr(simd)] +pub struct U32x4([u32; 4]); + +pub fn f(a: U32x4) -> [u32; 4] { + a.0 + //~^ ERROR broken MIR in Item + //~| ERROR Projecting into SIMD type U32x4 is banned by MCP#838 +} diff --git a/tests/ui/simd/issue-105439.rs b/tests/ui/simd/issue-105439.rs index 0a44f36fb2e..1d57eff341c 100644 --- a/tests/ui/simd/issue-105439.rs +++ b/tests/ui/simd/issue-105439.rs @@ -10,7 +10,9 @@ struct i32x4([i32; 4]); #[inline(always)] fn to_array(a: i32x4) -> [i32; 4] { - a.0 + // This was originally just `a.0`, but that ended up being annoying enough + // that it was banned by + unsafe { std::mem::transmute(a) } } fn main() { -- cgit 1.4.1-3-g733a5 From ed93c1783b404d728d4809973a0550eb33cd293f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 21 Jul 2025 14:22:51 +0200 Subject: Rename `tests/assembly` into `tests/assembly-llvm` --- .../rustc_codegen_gcc/build_system/src/test.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 7 +- src/bootstrap/src/core/builder/mod.rs | 4 +- src/ci/docker/host-x86_64/test-various/Dockerfile | 4 +- src/doc/rustc-dev-guide/src/asm.md | 4 +- src/doc/rustc-dev-guide/src/tests/compiletest.md | 4 +- src/tools/opt-dist/src/tests.rs | 2 +- src/tools/tidy/src/target_policy.rs | 6 +- tests/assembly-llvm/aarch64-pointer-auth.rs | 30 + tests/assembly-llvm/aarch64-xray.rs | 25 + tests/assembly-llvm/align_offset.rs | 47 + tests/assembly-llvm/asm/aarch64-el2vmsa.rs | 33 + tests/assembly-llvm/asm/aarch64-modifiers.rs | 128 +++ tests/assembly-llvm/asm/aarch64-outline-atomics.rs | 17 + tests/assembly-llvm/asm/aarch64-types.rs | 633 +++++++++++ tests/assembly-llvm/asm/arm-modifiers.rs | 122 +++ tests/assembly-llvm/asm/arm-types.rs | 639 ++++++++++++ tests/assembly-llvm/asm/avr-modifiers.rs | 43 + tests/assembly-llvm/asm/avr-types.rs | 205 ++++ tests/assembly-llvm/asm/bpf-types.rs | 133 +++ tests/assembly-llvm/asm/comments.rs | 12 + tests/assembly-llvm/asm/global_asm.rs | 32 + tests/assembly-llvm/asm/hexagon-types.rs | 139 +++ tests/assembly-llvm/asm/inline-asm-avx.rs | 25 + tests/assembly-llvm/asm/loongarch-type.rs | 190 ++++ tests/assembly-llvm/asm/m68k-types.rs | 67 ++ tests/assembly-llvm/asm/mips-types.rs | 211 ++++ tests/assembly-llvm/asm/msp430-types.rs | 141 +++ tests/assembly-llvm/asm/nvptx-types.rs | 115 ++ tests/assembly-llvm/asm/powerpc-types.rs | 474 +++++++++ tests/assembly-llvm/asm/riscv-types.rs | 227 ++++ tests/assembly-llvm/asm/s390x-types.rs | 350 +++++++ tests/assembly-llvm/asm/sparc-types.rs | 145 +++ tests/assembly-llvm/asm/wasm-types.rs | 131 +++ tests/assembly-llvm/asm/x86-modifiers.rs | 184 ++++ tests/assembly-llvm/asm/x86-types.rs | 1095 ++++++++++++++++++++ .../auxiliary/breakpoint-panic-handler.rs | 8 + .../auxiliary/dwarf-mixed-versions-lto-aux.rs | 5 + .../auxiliary/non-inline-dependency.rs | 14 + tests/assembly-llvm/breakpoint.rs | 14 + .../closure-inherit-target-feature.rs | 59 ++ tests/assembly-llvm/cmse.rs | 100 ++ .../compiletest-self-test/use-minicore-no-run.rs | 5 + tests/assembly-llvm/cstring-merging.rs | 30 + tests/assembly-llvm/dwarf-mixed-versions-lto.rs | 20 + tests/assembly-llvm/dwarf4.rs | 23 + tests/assembly-llvm/dwarf5.rs | 20 + tests/assembly-llvm/emit-intel-att-syntax.rs | 75 ++ tests/assembly-llvm/is_aligned.rs | 55 + .../issue-83585-small-pod-struct-equality.rs | 27 + .../assembly-llvm/libs/issue-115339-zip-arrays.rs | 25 + .../libs/issue-140207-slice-min-simd.rs | 13 + tests/assembly-llvm/manual-eq-efficient.rs | 22 + .../aarch64-naked-fn-no-bti-prolog.rs | 21 + tests/assembly-llvm/naked-functions/aix.rs | 35 + tests/assembly-llvm/naked-functions/wasm32.rs | 200 ++++ .../x86_64-naked-fn-no-cet-prolog.rs | 24 + tests/assembly-llvm/niche-prefer-zero.rs | 25 + tests/assembly-llvm/nvptx-arch-default.rs | 12 + tests/assembly-llvm/nvptx-arch-emit-asm.rs | 9 + tests/assembly-llvm/nvptx-arch-link-arg.rs | 13 + tests/assembly-llvm/nvptx-arch-target-cpu.rs | 12 + tests/assembly-llvm/nvptx-atomics.rs | 86 ++ tests/assembly-llvm/nvptx-c-abi-arg-v7.rs | 220 ++++ tests/assembly-llvm/nvptx-c-abi-ret-v7.rs | 244 +++++ tests/assembly-llvm/nvptx-internalizing.rs | 27 + .../nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs | 251 +++++ tests/assembly-llvm/nvptx-linking-binary.rs | 40 + tests/assembly-llvm/nvptx-linking-cdylib.rs | 39 + tests/assembly-llvm/nvptx-safe-naming.rs | 37 + tests/assembly-llvm/panic-no-unwind-no-uwtable.rs | 8 + tests/assembly-llvm/panic-unwind-no-uwtable.rs | 12 + tests/assembly-llvm/pic-relocation-model.rs | 31 + tests/assembly-llvm/pie-relocation-model.rs | 34 + tests/assembly-llvm/powerpc64-struct-abi.rs | 156 +++ tests/assembly-llvm/riscv-float-struct-abi.rs | 177 ++++ .../riscv-soft-abi-with-float-features.rs | 45 + tests/assembly-llvm/rust-abi-arg-attr.rs | 110 ++ tests/assembly-llvm/s390x-backchain-toggle.rs | 50 + tests/assembly-llvm/s390x-vector-abi.rs | 327 ++++++ .../sanitizer/kcfi/emit-arity-indicator.rs | 69 ++ tests/assembly-llvm/simd-bitmask.rs | 147 +++ tests/assembly-llvm/simd-intrinsic-gather.rs | 39 + tests/assembly-llvm/simd-intrinsic-mask-load.rs | 83 ++ tests/assembly-llvm/simd-intrinsic-mask-reduce.rs | 59 ++ tests/assembly-llvm/simd-intrinsic-mask-store.rs | 82 ++ tests/assembly-llvm/simd-intrinsic-scatter.rs | 35 + tests/assembly-llvm/simd-intrinsic-select.rs | 128 +++ tests/assembly-llvm/simd/reduce-fadd-unordered.rs | 31 + tests/assembly-llvm/slice-is_ascii.rs | 33 + tests/assembly-llvm/small_data_threshold.rs | 98 ++ tests/assembly-llvm/sparc-struct-abi.rs | 68 ++ tests/assembly-llvm/stack-probes.rs | 41 + ...ck-protector-heuristics-effect-windows-32bit.rs | 359 +++++++ ...ck-protector-heuristics-effect-windows-64bit.rs | 366 +++++++ .../stack-protector-heuristics-effect.rs | 345 ++++++ .../stack-protector-target-support.rs | 281 +++++ tests/assembly-llvm/static-relocation-model.rs | 69 ++ tests/assembly-llvm/strict_provenance.rs | 37 + tests/assembly-llvm/target-feature-multiple.rs | 40 + tests/assembly-llvm/targets/targets-amdgpu.rs | 22 + tests/assembly-llvm/targets/targets-elf.rs | 734 +++++++++++++ tests/assembly-llvm/targets/targets-macho.rs | 93 ++ tests/assembly-llvm/targets/targets-nvptx.rs | 22 + tests/assembly-llvm/targets/targets-pe.rs | 103 ++ tests/assembly-llvm/wasm_exceptions.rs | 67 ++ tests/assembly-llvm/x86-return-float.rs | 343 ++++++ .../x86_64-array-pair-load-store-merge.rs | 20 + tests/assembly-llvm/x86_64-bigint-helpers.rs | 61 ++ tests/assembly-llvm/x86_64-cmp.rs | 79 ++ tests/assembly-llvm/x86_64-floating-point-clamp.rs | 27 + ...x86_64-fortanix-unknown-sgx-lvi-generic-load.rs | 17 + .../x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs | 12 + ..._64-fortanix-unknown-sgx-lvi-inline-assembly.rs | 34 + tests/assembly-llvm/x86_64-function-return.rs | 30 + tests/assembly-llvm/x86_64-no-jump-tables.rs | 35 + tests/assembly-llvm/x86_64-sse_crc.rs | 12 + tests/assembly-llvm/x86_64-typed-swap.rs | 81 ++ tests/assembly-llvm/x86_64-windows-float-abi.rs | 46 + tests/assembly-llvm/x86_64-windows-i128-abi.rs | 26 + tests/assembly-llvm/x86_64-xray.rs | 25 + tests/assembly/aarch64-pointer-auth.rs | 30 - tests/assembly/aarch64-xray.rs | 25 - tests/assembly/align_offset.rs | 47 - tests/assembly/asm/aarch64-el2vmsa.rs | 33 - tests/assembly/asm/aarch64-modifiers.rs | 128 --- tests/assembly/asm/aarch64-outline-atomics.rs | 17 - tests/assembly/asm/aarch64-types.rs | 633 ----------- tests/assembly/asm/arm-modifiers.rs | 122 --- tests/assembly/asm/arm-types.rs | 639 ------------ tests/assembly/asm/avr-modifiers.rs | 43 - tests/assembly/asm/avr-types.rs | 205 ---- tests/assembly/asm/bpf-types.rs | 133 --- tests/assembly/asm/comments.rs | 12 - tests/assembly/asm/global_asm.rs | 32 - tests/assembly/asm/hexagon-types.rs | 139 --- tests/assembly/asm/inline-asm-avx.rs | 25 - tests/assembly/asm/loongarch-type.rs | 190 ---- tests/assembly/asm/m68k-types.rs | 67 -- tests/assembly/asm/mips-types.rs | 211 ---- tests/assembly/asm/msp430-types.rs | 141 --- tests/assembly/asm/nvptx-types.rs | 115 -- tests/assembly/asm/powerpc-types.rs | 474 --------- tests/assembly/asm/riscv-types.rs | 227 ---- tests/assembly/asm/s390x-types.rs | 350 ------- tests/assembly/asm/sparc-types.rs | 145 --- tests/assembly/asm/wasm-types.rs | 131 --- tests/assembly/asm/x86-modifiers.rs | 184 ---- tests/assembly/asm/x86-types.rs | 1095 -------------------- .../assembly/auxiliary/breakpoint-panic-handler.rs | 8 - .../auxiliary/dwarf-mixed-versions-lto-aux.rs | 5 - tests/assembly/auxiliary/non-inline-dependency.rs | 14 - tests/assembly/breakpoint.rs | 14 - tests/assembly/closure-inherit-target-feature.rs | 59 -- tests/assembly/cmse.rs | 100 -- .../compiletest-self-test/use-minicore-no-run.rs | 5 - tests/assembly/cstring-merging.rs | 30 - tests/assembly/dwarf-mixed-versions-lto.rs | 20 - tests/assembly/dwarf4.rs | 23 - tests/assembly/dwarf5.rs | 20 - tests/assembly/emit-intel-att-syntax.rs | 75 -- tests/assembly/is_aligned.rs | 55 - .../issue-83585-small-pod-struct-equality.rs | 27 - tests/assembly/libs/issue-115339-zip-arrays.rs | 25 - tests/assembly/libs/issue-140207-slice-min-simd.rs | 13 - tests/assembly/manual-eq-efficient.rs | 22 - .../aarch64-naked-fn-no-bti-prolog.rs | 21 - tests/assembly/naked-functions/aix.rs | 35 - tests/assembly/naked-functions/wasm32.rs | 200 ---- .../x86_64-naked-fn-no-cet-prolog.rs | 24 - tests/assembly/niche-prefer-zero.rs | 25 - tests/assembly/nvptx-arch-default.rs | 12 - tests/assembly/nvptx-arch-emit-asm.rs | 9 - tests/assembly/nvptx-arch-link-arg.rs | 13 - tests/assembly/nvptx-arch-target-cpu.rs | 12 - tests/assembly/nvptx-atomics.rs | 86 -- tests/assembly/nvptx-c-abi-arg-v7.rs | 220 ---- tests/assembly/nvptx-c-abi-ret-v7.rs | 244 ----- tests/assembly/nvptx-internalizing.rs | 27 - .../nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs | 251 ----- tests/assembly/nvptx-linking-binary.rs | 40 - tests/assembly/nvptx-linking-cdylib.rs | 39 - tests/assembly/nvptx-safe-naming.rs | 37 - tests/assembly/panic-no-unwind-no-uwtable.rs | 8 - tests/assembly/panic-unwind-no-uwtable.rs | 12 - tests/assembly/pic-relocation-model.rs | 31 - tests/assembly/pie-relocation-model.rs | 34 - tests/assembly/powerpc64-struct-abi.rs | 156 --- tests/assembly/riscv-float-struct-abi.rs | 177 ---- .../assembly/riscv-soft-abi-with-float-features.rs | 45 - tests/assembly/rust-abi-arg-attr.rs | 110 -- tests/assembly/s390x-backchain-toggle.rs | 50 - tests/assembly/s390x-vector-abi.rs | 327 ------ .../sanitizer/kcfi/emit-arity-indicator.rs | 69 -- tests/assembly/simd-bitmask.rs | 147 --- tests/assembly/simd-intrinsic-gather.rs | 39 - tests/assembly/simd-intrinsic-mask-load.rs | 83 -- tests/assembly/simd-intrinsic-mask-reduce.rs | 59 -- tests/assembly/simd-intrinsic-mask-store.rs | 82 -- tests/assembly/simd-intrinsic-scatter.rs | 35 - tests/assembly/simd-intrinsic-select.rs | 128 --- tests/assembly/simd/reduce-fadd-unordered.rs | 31 - tests/assembly/slice-is_ascii.rs | 33 - tests/assembly/small_data_threshold.rs | 98 -- tests/assembly/sparc-struct-abi.rs | 68 -- tests/assembly/stack-probes.rs | 41 - ...ck-protector-heuristics-effect-windows-32bit.rs | 359 ------- ...ck-protector-heuristics-effect-windows-64bit.rs | 366 ------- .../stack-protector-heuristics-effect.rs | 345 ------ .../stack-protector-target-support.rs | 281 ----- tests/assembly/static-relocation-model.rs | 69 -- tests/assembly/strict_provenance.rs | 37 - tests/assembly/target-feature-multiple.rs | 40 - tests/assembly/targets/targets-amdgpu.rs | 22 - tests/assembly/targets/targets-elf.rs | 734 ------------- tests/assembly/targets/targets-macho.rs | 93 -- tests/assembly/targets/targets-nvptx.rs | 22 - tests/assembly/targets/targets-pe.rs | 103 -- tests/assembly/wasm_exceptions.rs | 67 -- tests/assembly/x86-return-float.rs | 343 ------ .../assembly/x86_64-array-pair-load-store-merge.rs | 20 - tests/assembly/x86_64-bigint-helpers.rs | 61 -- tests/assembly/x86_64-cmp.rs | 79 -- tests/assembly/x86_64-floating-point-clamp.rs | 27 - ...x86_64-fortanix-unknown-sgx-lvi-generic-load.rs | 17 - .../x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs | 12 - ..._64-fortanix-unknown-sgx-lvi-inline-assembly.rs | 34 - tests/assembly/x86_64-function-return.rs | 30 - tests/assembly/x86_64-no-jump-tables.rs | 35 - tests/assembly/x86_64-sse_crc.rs | 12 - tests/assembly/x86_64-typed-swap.rs | 81 -- tests/assembly/x86_64-windows-float-abi.rs | 46 - tests/assembly/x86_64-windows-i128-abi.rs | 26 - tests/assembly/x86_64-xray.rs | 25 - tests/codegen/target-feature-overrides.rs | 2 +- tests/run-make/avr-rjmp-offset/rmake.rs | 2 +- triagebot.toml | 2 +- 237 files changed, 12674 insertions(+), 12669 deletions(-) create mode 100644 tests/assembly-llvm/aarch64-pointer-auth.rs create mode 100644 tests/assembly-llvm/aarch64-xray.rs create mode 100644 tests/assembly-llvm/align_offset.rs create mode 100644 tests/assembly-llvm/asm/aarch64-el2vmsa.rs create mode 100644 tests/assembly-llvm/asm/aarch64-modifiers.rs create mode 100644 tests/assembly-llvm/asm/aarch64-outline-atomics.rs create mode 100644 tests/assembly-llvm/asm/aarch64-types.rs create mode 100644 tests/assembly-llvm/asm/arm-modifiers.rs create mode 100644 tests/assembly-llvm/asm/arm-types.rs create mode 100644 tests/assembly-llvm/asm/avr-modifiers.rs create mode 100644 tests/assembly-llvm/asm/avr-types.rs create mode 100644 tests/assembly-llvm/asm/bpf-types.rs create mode 100644 tests/assembly-llvm/asm/comments.rs create mode 100644 tests/assembly-llvm/asm/global_asm.rs create mode 100644 tests/assembly-llvm/asm/hexagon-types.rs create mode 100644 tests/assembly-llvm/asm/inline-asm-avx.rs create mode 100644 tests/assembly-llvm/asm/loongarch-type.rs create mode 100644 tests/assembly-llvm/asm/m68k-types.rs create mode 100644 tests/assembly-llvm/asm/mips-types.rs create mode 100644 tests/assembly-llvm/asm/msp430-types.rs create mode 100644 tests/assembly-llvm/asm/nvptx-types.rs create mode 100644 tests/assembly-llvm/asm/powerpc-types.rs create mode 100644 tests/assembly-llvm/asm/riscv-types.rs create mode 100644 tests/assembly-llvm/asm/s390x-types.rs create mode 100644 tests/assembly-llvm/asm/sparc-types.rs create mode 100644 tests/assembly-llvm/asm/wasm-types.rs create mode 100644 tests/assembly-llvm/asm/x86-modifiers.rs create mode 100644 tests/assembly-llvm/asm/x86-types.rs create mode 100644 tests/assembly-llvm/auxiliary/breakpoint-panic-handler.rs create mode 100644 tests/assembly-llvm/auxiliary/dwarf-mixed-versions-lto-aux.rs create mode 100644 tests/assembly-llvm/auxiliary/non-inline-dependency.rs create mode 100644 tests/assembly-llvm/breakpoint.rs create mode 100644 tests/assembly-llvm/closure-inherit-target-feature.rs create mode 100644 tests/assembly-llvm/cmse.rs create mode 100644 tests/assembly-llvm/compiletest-self-test/use-minicore-no-run.rs create mode 100644 tests/assembly-llvm/cstring-merging.rs create mode 100644 tests/assembly-llvm/dwarf-mixed-versions-lto.rs create mode 100644 tests/assembly-llvm/dwarf4.rs create mode 100644 tests/assembly-llvm/dwarf5.rs create mode 100644 tests/assembly-llvm/emit-intel-att-syntax.rs create mode 100644 tests/assembly-llvm/is_aligned.rs create mode 100644 tests/assembly-llvm/issue-83585-small-pod-struct-equality.rs create mode 100644 tests/assembly-llvm/libs/issue-115339-zip-arrays.rs create mode 100644 tests/assembly-llvm/libs/issue-140207-slice-min-simd.rs create mode 100644 tests/assembly-llvm/manual-eq-efficient.rs create mode 100644 tests/assembly-llvm/naked-functions/aarch64-naked-fn-no-bti-prolog.rs create mode 100644 tests/assembly-llvm/naked-functions/aix.rs create mode 100644 tests/assembly-llvm/naked-functions/wasm32.rs create mode 100644 tests/assembly-llvm/naked-functions/x86_64-naked-fn-no-cet-prolog.rs create mode 100644 tests/assembly-llvm/niche-prefer-zero.rs create mode 100644 tests/assembly-llvm/nvptx-arch-default.rs create mode 100644 tests/assembly-llvm/nvptx-arch-emit-asm.rs create mode 100644 tests/assembly-llvm/nvptx-arch-link-arg.rs create mode 100644 tests/assembly-llvm/nvptx-arch-target-cpu.rs create mode 100644 tests/assembly-llvm/nvptx-atomics.rs create mode 100644 tests/assembly-llvm/nvptx-c-abi-arg-v7.rs create mode 100644 tests/assembly-llvm/nvptx-c-abi-ret-v7.rs create mode 100644 tests/assembly-llvm/nvptx-internalizing.rs create mode 100644 tests/assembly-llvm/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs create mode 100644 tests/assembly-llvm/nvptx-linking-binary.rs create mode 100644 tests/assembly-llvm/nvptx-linking-cdylib.rs create mode 100644 tests/assembly-llvm/nvptx-safe-naming.rs create mode 100644 tests/assembly-llvm/panic-no-unwind-no-uwtable.rs create mode 100644 tests/assembly-llvm/panic-unwind-no-uwtable.rs create mode 100644 tests/assembly-llvm/pic-relocation-model.rs create mode 100644 tests/assembly-llvm/pie-relocation-model.rs create mode 100644 tests/assembly-llvm/powerpc64-struct-abi.rs create mode 100644 tests/assembly-llvm/riscv-float-struct-abi.rs create mode 100644 tests/assembly-llvm/riscv-soft-abi-with-float-features.rs create mode 100644 tests/assembly-llvm/rust-abi-arg-attr.rs create mode 100644 tests/assembly-llvm/s390x-backchain-toggle.rs create mode 100644 tests/assembly-llvm/s390x-vector-abi.rs create mode 100644 tests/assembly-llvm/sanitizer/kcfi/emit-arity-indicator.rs create mode 100644 tests/assembly-llvm/simd-bitmask.rs create mode 100644 tests/assembly-llvm/simd-intrinsic-gather.rs create mode 100644 tests/assembly-llvm/simd-intrinsic-mask-load.rs create mode 100644 tests/assembly-llvm/simd-intrinsic-mask-reduce.rs create mode 100644 tests/assembly-llvm/simd-intrinsic-mask-store.rs create mode 100644 tests/assembly-llvm/simd-intrinsic-scatter.rs create mode 100644 tests/assembly-llvm/simd-intrinsic-select.rs create mode 100644 tests/assembly-llvm/simd/reduce-fadd-unordered.rs create mode 100644 tests/assembly-llvm/slice-is_ascii.rs create mode 100644 tests/assembly-llvm/small_data_threshold.rs create mode 100644 tests/assembly-llvm/sparc-struct-abi.rs create mode 100644 tests/assembly-llvm/stack-probes.rs create mode 100644 tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs create mode 100644 tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs create mode 100644 tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs create mode 100644 tests/assembly-llvm/stack-protector/stack-protector-target-support.rs create mode 100644 tests/assembly-llvm/static-relocation-model.rs create mode 100644 tests/assembly-llvm/strict_provenance.rs create mode 100644 tests/assembly-llvm/target-feature-multiple.rs create mode 100644 tests/assembly-llvm/targets/targets-amdgpu.rs create mode 100644 tests/assembly-llvm/targets/targets-elf.rs create mode 100644 tests/assembly-llvm/targets/targets-macho.rs create mode 100644 tests/assembly-llvm/targets/targets-nvptx.rs create mode 100644 tests/assembly-llvm/targets/targets-pe.rs create mode 100644 tests/assembly-llvm/wasm_exceptions.rs create mode 100644 tests/assembly-llvm/x86-return-float.rs create mode 100644 tests/assembly-llvm/x86_64-array-pair-load-store-merge.rs create mode 100644 tests/assembly-llvm/x86_64-bigint-helpers.rs create mode 100644 tests/assembly-llvm/x86_64-cmp.rs create mode 100644 tests/assembly-llvm/x86_64-floating-point-clamp.rs create mode 100644 tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs create mode 100644 tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs create mode 100644 tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs create mode 100644 tests/assembly-llvm/x86_64-function-return.rs create mode 100644 tests/assembly-llvm/x86_64-no-jump-tables.rs create mode 100644 tests/assembly-llvm/x86_64-sse_crc.rs create mode 100644 tests/assembly-llvm/x86_64-typed-swap.rs create mode 100644 tests/assembly-llvm/x86_64-windows-float-abi.rs create mode 100644 tests/assembly-llvm/x86_64-windows-i128-abi.rs create mode 100644 tests/assembly-llvm/x86_64-xray.rs delete mode 100644 tests/assembly/aarch64-pointer-auth.rs delete mode 100644 tests/assembly/aarch64-xray.rs delete mode 100644 tests/assembly/align_offset.rs delete mode 100644 tests/assembly/asm/aarch64-el2vmsa.rs delete mode 100644 tests/assembly/asm/aarch64-modifiers.rs delete mode 100644 tests/assembly/asm/aarch64-outline-atomics.rs delete mode 100644 tests/assembly/asm/aarch64-types.rs delete mode 100644 tests/assembly/asm/arm-modifiers.rs delete mode 100644 tests/assembly/asm/arm-types.rs delete mode 100644 tests/assembly/asm/avr-modifiers.rs delete mode 100644 tests/assembly/asm/avr-types.rs delete mode 100644 tests/assembly/asm/bpf-types.rs delete mode 100644 tests/assembly/asm/comments.rs delete mode 100644 tests/assembly/asm/global_asm.rs delete mode 100644 tests/assembly/asm/hexagon-types.rs delete mode 100644 tests/assembly/asm/inline-asm-avx.rs delete mode 100644 tests/assembly/asm/loongarch-type.rs delete mode 100644 tests/assembly/asm/m68k-types.rs delete mode 100644 tests/assembly/asm/mips-types.rs delete mode 100644 tests/assembly/asm/msp430-types.rs delete mode 100644 tests/assembly/asm/nvptx-types.rs delete mode 100644 tests/assembly/asm/powerpc-types.rs delete mode 100644 tests/assembly/asm/riscv-types.rs delete mode 100644 tests/assembly/asm/s390x-types.rs delete mode 100644 tests/assembly/asm/sparc-types.rs delete mode 100644 tests/assembly/asm/wasm-types.rs delete mode 100644 tests/assembly/asm/x86-modifiers.rs delete mode 100644 tests/assembly/asm/x86-types.rs delete mode 100644 tests/assembly/auxiliary/breakpoint-panic-handler.rs delete mode 100644 tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs delete mode 100644 tests/assembly/auxiliary/non-inline-dependency.rs delete mode 100644 tests/assembly/breakpoint.rs delete mode 100644 tests/assembly/closure-inherit-target-feature.rs delete mode 100644 tests/assembly/cmse.rs delete mode 100644 tests/assembly/compiletest-self-test/use-minicore-no-run.rs delete mode 100644 tests/assembly/cstring-merging.rs delete mode 100644 tests/assembly/dwarf-mixed-versions-lto.rs delete mode 100644 tests/assembly/dwarf4.rs delete mode 100644 tests/assembly/dwarf5.rs delete mode 100644 tests/assembly/emit-intel-att-syntax.rs delete mode 100644 tests/assembly/is_aligned.rs delete mode 100644 tests/assembly/issue-83585-small-pod-struct-equality.rs delete mode 100644 tests/assembly/libs/issue-115339-zip-arrays.rs delete mode 100644 tests/assembly/libs/issue-140207-slice-min-simd.rs delete mode 100644 tests/assembly/manual-eq-efficient.rs delete mode 100644 tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs delete mode 100644 tests/assembly/naked-functions/aix.rs delete mode 100644 tests/assembly/naked-functions/wasm32.rs delete mode 100644 tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs delete mode 100644 tests/assembly/niche-prefer-zero.rs delete mode 100644 tests/assembly/nvptx-arch-default.rs delete mode 100644 tests/assembly/nvptx-arch-emit-asm.rs delete mode 100644 tests/assembly/nvptx-arch-link-arg.rs delete mode 100644 tests/assembly/nvptx-arch-target-cpu.rs delete mode 100644 tests/assembly/nvptx-atomics.rs delete mode 100644 tests/assembly/nvptx-c-abi-arg-v7.rs delete mode 100644 tests/assembly/nvptx-c-abi-ret-v7.rs delete mode 100644 tests/assembly/nvptx-internalizing.rs delete mode 100644 tests/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs delete mode 100644 tests/assembly/nvptx-linking-binary.rs delete mode 100644 tests/assembly/nvptx-linking-cdylib.rs delete mode 100644 tests/assembly/nvptx-safe-naming.rs delete mode 100644 tests/assembly/panic-no-unwind-no-uwtable.rs delete mode 100644 tests/assembly/panic-unwind-no-uwtable.rs delete mode 100644 tests/assembly/pic-relocation-model.rs delete mode 100644 tests/assembly/pie-relocation-model.rs delete mode 100644 tests/assembly/powerpc64-struct-abi.rs delete mode 100644 tests/assembly/riscv-float-struct-abi.rs delete mode 100644 tests/assembly/riscv-soft-abi-with-float-features.rs delete mode 100644 tests/assembly/rust-abi-arg-attr.rs delete mode 100644 tests/assembly/s390x-backchain-toggle.rs delete mode 100644 tests/assembly/s390x-vector-abi.rs delete mode 100644 tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs delete mode 100644 tests/assembly/simd-bitmask.rs delete mode 100644 tests/assembly/simd-intrinsic-gather.rs delete mode 100644 tests/assembly/simd-intrinsic-mask-load.rs delete mode 100644 tests/assembly/simd-intrinsic-mask-reduce.rs delete mode 100644 tests/assembly/simd-intrinsic-mask-store.rs delete mode 100644 tests/assembly/simd-intrinsic-scatter.rs delete mode 100644 tests/assembly/simd-intrinsic-select.rs delete mode 100644 tests/assembly/simd/reduce-fadd-unordered.rs delete mode 100644 tests/assembly/slice-is_ascii.rs delete mode 100644 tests/assembly/small_data_threshold.rs delete mode 100644 tests/assembly/sparc-struct-abi.rs delete mode 100644 tests/assembly/stack-probes.rs delete mode 100644 tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs delete mode 100644 tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs delete mode 100644 tests/assembly/stack-protector/stack-protector-heuristics-effect.rs delete mode 100644 tests/assembly/stack-protector/stack-protector-target-support.rs delete mode 100644 tests/assembly/static-relocation-model.rs delete mode 100644 tests/assembly/strict_provenance.rs delete mode 100644 tests/assembly/target-feature-multiple.rs delete mode 100644 tests/assembly/targets/targets-amdgpu.rs delete mode 100644 tests/assembly/targets/targets-elf.rs delete mode 100644 tests/assembly/targets/targets-macho.rs delete mode 100644 tests/assembly/targets/targets-nvptx.rs delete mode 100644 tests/assembly/targets/targets-pe.rs delete mode 100644 tests/assembly/wasm_exceptions.rs delete mode 100644 tests/assembly/x86-return-float.rs delete mode 100644 tests/assembly/x86_64-array-pair-load-store-merge.rs delete mode 100644 tests/assembly/x86_64-bigint-helpers.rs delete mode 100644 tests/assembly/x86_64-cmp.rs delete mode 100644 tests/assembly/x86_64-floating-point-clamp.rs delete mode 100644 tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs delete mode 100644 tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs delete mode 100644 tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs delete mode 100644 tests/assembly/x86_64-function-return.rs delete mode 100644 tests/assembly/x86_64-no-jump-tables.rs delete mode 100644 tests/assembly/x86_64-sse_crc.rs delete mode 100644 tests/assembly/x86_64-typed-swap.rs delete mode 100644 tests/assembly/x86_64-windows-float-abi.rs delete mode 100644 tests/assembly/x86_64-windows-i128-abi.rs delete mode 100644 tests/assembly/x86_64-xray.rs (limited to 'tests/codegen') diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs index cbb0f949383..bc0fdd40b6e 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/test.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs @@ -588,7 +588,7 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> { &"always", &"--stage", &"0", - &"tests/assembly/asm", + &"tests/assembly-llvm/asm", &"--compiletest-rustc-args", &rustc_args, ], diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 8344b0e03b4..99c9e8ae92e 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1407,7 +1407,12 @@ test!(Pretty { test!(RunMake { path: "tests/run-make", mode: "run-make", suite: "run-make", default: true }); -test!(Assembly { path: "tests/assembly", mode: "assembly", suite: "assembly", default: true }); +test!(AssemblyLlvm { + path: "tests/assembly-llvm", + mode: "assembly", + suite: "assembly-llvm", + default: true +}); /// Runs the coverage test suite at `tests/coverage` in some or all of the /// coverage test modes. diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index d73e2bce25b..925e47a4164 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -411,7 +411,7 @@ const PATH_REMAP: &[(&str, &[&str])] = &[ "tests", &[ // tidy-alphabetical-start - "tests/assembly", + "tests/assembly-llvm", "tests/codegen", "tests/codegen-units", "tests/coverage", @@ -1051,7 +1051,7 @@ impl<'a> Builder<'a> { test::MirOpt, test::Codegen, test::CodegenUnits, - test::Assembly, + test::AssemblyLlvm, test::Incremental, test::Debuginfo, test::UiFullDeps, diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile index 8d2e45ae497..54ca7131608 100644 --- a/src/ci/docker/host-x86_64/test-various/Dockerfile +++ b/src/ci/docker/host-x86_64/test-various/Dockerfile @@ -66,13 +66,13 @@ ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_T tests/mir-opt \ tests/codegen-units \ tests/codegen \ - tests/assembly \ + tests/assembly-llvm \ library/core ENV NVPTX_TARGETS=nvptx64-nvidia-cuda ENV NVPTX_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $NVPTX_TARGETS \ tests/run-make \ - tests/assembly + tests/assembly-llvm ENV MUSL_TARGETS=x86_64-unknown-linux-musl \ CC_x86_64_unknown_linux_musl=x86_64-linux-musl-gcc \ diff --git a/src/doc/rustc-dev-guide/src/asm.md b/src/doc/rustc-dev-guide/src/asm.md index eec9d448b0c..3d93d5a4c57 100644 --- a/src/doc/rustc-dev-guide/src/asm.md +++ b/src/doc/rustc-dev-guide/src/asm.md @@ -155,9 +155,9 @@ can't know ahead of time whether a function will require a frame/base pointer. Various tests for inline assembly are available: -- `tests/assembly/asm` +- `tests/assembly-llvm/asm` - `tests/ui/asm` - `tests/codegen/asm-*` Every architecture supported by inline assembly must have exhaustive tests in -`tests/assembly/asm` which test all combinations of register classes and types. +`tests/assembly-llvm/asm` which test all combinations of register classes and types. diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index aa99347b2bb..6a60e7118d3 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -307,7 +307,7 @@ If you need to work with `#![no_std]` cross-compiling tests, consult the ### Assembly tests -The tests in [`tests/assembly`] test LLVM assembly output. They compile the test +The tests in [`tests/assembly-llvm`] test LLVM assembly output. They compile the test with the `--emit=asm` flag to emit a `.s` file with the assembly output. They then run the LLVM [FileCheck] tool. @@ -324,7 +324,7 @@ See also the [codegen tests](#codegen-tests) for a similar set of tests. If you need to work with `#![no_std]` cross-compiling tests, consult the [`minicore` test auxiliary](./minicore.md) chapter. -[`tests/assembly`]: https://github.com/rust-lang/rust/tree/master/tests/assembly +[`tests/assembly-llvm`]: https://github.com/rust-lang/rust/tree/master/tests/assembly-llvm ### Codegen-units tests diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs index c3c45d262dd..a70c257e52b 100644 --- a/src/tools/opt-dist/src/tests.rs +++ b/src/tools/opt-dist/src/tests.rs @@ -100,7 +100,7 @@ llvm-config = "{llvm_config}" env.host_tuple(), "--stage", "0", - "tests/assembly", + "tests/assembly-llvm", "tests/codegen", "tests/codegen-units", "tests/incremental", diff --git a/src/tools/tidy/src/target_policy.rs b/src/tools/tidy/src/target_policy.rs index 776221d3062..550932dbfdc 100644 --- a/src/tools/tidy/src/target_policy.rs +++ b/src/tools/tidy/src/target_policy.rs @@ -8,7 +8,7 @@ use std::path::Path; use crate::walk::{filter_not_rust, walk}; const TARGET_DEFINITIONS_PATH: &str = "compiler/rustc_target/src/spec/targets/"; -const ASSEMBLY_TEST_PATH: &str = "tests/assembly/targets/"; +const ASSEMBLY_LLVM_TEST_PATH: &str = "tests/assembly-llvm/targets/"; const REVISION_LINE_START: &str = "//@ revisions: "; const EXCEPTIONS: &[&str] = &[ // FIXME: disabled since it fails on CI saying the csky component is missing @@ -43,7 +43,7 @@ pub fn check(root_path: &Path, bad: &mut bool) { let _ = targets_to_find.insert(target_name); } - walk(&root_path.join(ASSEMBLY_TEST_PATH), |_, _| false, &mut |_, contents| { + walk(&root_path.join(ASSEMBLY_LLVM_TEST_PATH), |_, _| false, &mut |_, contents| { for line in contents.lines() { let Some(_) = line.find(REVISION_LINE_START) else { continue; @@ -55,7 +55,7 @@ pub fn check(root_path: &Path, bad: &mut bool) { for target in targets_to_find { if !EXCEPTIONS.contains(&target.as_str()) { - tidy_error!(bad, "{ASSEMBLY_TEST_PATH}: missing assembly test for {target}") + tidy_error!(bad, "{ASSEMBLY_LLVM_TEST_PATH}: missing assembly test for {target}") } } } diff --git a/tests/assembly-llvm/aarch64-pointer-auth.rs b/tests/assembly-llvm/aarch64-pointer-auth.rs new file mode 100644 index 00000000000..56a26df469f --- /dev/null +++ b/tests/assembly-llvm/aarch64-pointer-auth.rs @@ -0,0 +1,30 @@ +// Test that PAC instructions are emitted when branch-protection is specified. + +//@ add-core-stubs +//@ revisions: PACRET PAUTHLR_NOP PAUTHLR +//@ assembly-output: emit-asm +//@ needs-llvm-components: aarch64 +//@ compile-flags: --target aarch64-unknown-linux-gnu +//@ [PACRET] compile-flags: -Z branch-protection=pac-ret,leaf +//@ [PAUTHLR_NOP] compile-flags: -Z branch-protection=pac-ret,pc,leaf +//@ [PAUTHLR] compile-flags: -C target-feature=+pauth-lr -Z branch-protection=pac-ret,pc,leaf + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +// PACRET: hint #25 +// PACRET: hint #29 +// PAUTHLR_NOP: hint #25 +// PAUTHLR_NOP: hint #39 +// PAUTHLR_NOP: hint #29 +// PAUTHLR: paciasppc +// PAUTHLR: autiasppc +#[no_mangle] +pub fn test() -> u8 { + 42 +} diff --git a/tests/assembly-llvm/aarch64-xray.rs b/tests/assembly-llvm/aarch64-xray.rs new file mode 100644 index 00000000000..d5ee0111843 --- /dev/null +++ b/tests/assembly-llvm/aarch64-xray.rs @@ -0,0 +1,25 @@ +//@ assembly-output: emit-asm +//@ compile-flags: -Zinstrument-xray=always + +//@ revisions: aarch64-linux +//@[aarch64-linux] compile-flags: --target=aarch64-unknown-linux-gnu +//@[aarch64-linux] needs-llvm-components: aarch64 +//@[aarch64-linux] only-aarch64-unknown-linux-gnu + +//@ revisions: aarch64-darwin +//@[aarch64-darwin] compile-flags: --target=aarch64-apple-darwin +//@[aarch64-darwin] needs-llvm-components: aarch64 +//@[aarch64-darwin] only-aarch64-apple-darwin + +#![crate_type = "lib"] + +// CHECK-LABEL: xray_func: +#[no_mangle] +pub fn xray_func() { + // CHECK: nop + + std::hint::black_box(()); + + // CHECK: b #32 + // CHECK-NEXT: nop +} diff --git a/tests/assembly-llvm/align_offset.rs b/tests/assembly-llvm/align_offset.rs new file mode 100644 index 00000000000..d9902ce336b --- /dev/null +++ b/tests/assembly-llvm/align_offset.rs @@ -0,0 +1,47 @@ +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=1 +//@ only-x86_64 +#![crate_type = "rlib"] + +// CHECK-LABEL: align_offset_byte_ptr +// CHECK: leaq 31 +// CHECK: andq $-32 +// CHECK: subq +#[no_mangle] +pub fn align_offset_byte_ptr(ptr: *const u8) -> usize { + ptr.align_offset(32) +} + +// CHECK-LABEL: align_offset_byte_slice +// CHECK: leaq 31 +// CHECK: andq $-32 +// CHECK: subq +#[no_mangle] +pub fn align_offset_byte_slice(slice: &[u8]) -> usize { + slice.as_ptr().align_offset(32) +} + +// CHECK-LABEL: align_offset_word_ptr +// CHECK: leaq 31 +// CHECK: andq $-32 +// CHECK: subq +// CHECK: shrq +// This `ptr` is not known to be aligned, so it is required to check if it is at all possible to +// align. LLVM applies a simple mask. +// CHECK: orq +#[no_mangle] +pub fn align_offset_word_ptr(ptr: *const u32) -> usize { + ptr.align_offset(32) +} + +// CHECK-LABEL: align_offset_word_slice +// CHECK: leaq 31 +// CHECK: andq $-32 +// CHECK: subq +// CHECK: shrq +// `slice` is known to be aligned, so `!0` is not possible as a return +// CHECK-NOT: orq +#[no_mangle] +pub fn align_offset_word_slice(slice: &[u32]) -> usize { + slice.as_ptr().align_offset(32) +} diff --git a/tests/assembly-llvm/asm/aarch64-el2vmsa.rs b/tests/assembly-llvm/asm/aarch64-el2vmsa.rs new file mode 100644 index 00000000000..3652d58d85a --- /dev/null +++ b/tests/assembly-llvm/asm/aarch64-el2vmsa.rs @@ -0,0 +1,33 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: --target aarch64-unknown-linux-gnu +//@ needs-llvm-components: aarch64 + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: ttbr0_el2: +#[no_mangle] +pub fn ttbr0_el2() { + // CHECK: //APP + // CHECK-NEXT: msr TTBR0_EL2, x0 + // CHECK-NEXT: //NO_APP + unsafe { + asm!("msr ttbr0_el2, x0"); + } +} + +// CHECK-LABEL: vttbr_el2: +#[no_mangle] +pub fn vttbr_el2() { + // CHECK: //APP + // CHECK-NEXT: msr VTTBR_EL2, x0 + // CHECK-NEXT: //NO_APP + unsafe { + asm!("msr vttbr_el2, x0"); + } +} diff --git a/tests/assembly-llvm/asm/aarch64-modifiers.rs b/tests/assembly-llvm/asm/aarch64-modifiers.rs new file mode 100644 index 00000000000..58f7c114d3a --- /dev/null +++ b/tests/assembly-llvm/asm/aarch64-modifiers.rs @@ -0,0 +1,128 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 -C panic=abort +//@ compile-flags: --target aarch64-unknown-linux-gnu +//@ compile-flags: -Zmerge-functions=disabled +//@ needs-llvm-components: aarch64 + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register)] + +extern crate minicore; +use minicore::*; + +macro_rules! check { + ($func:ident $reg:ident $code:literal) => { + // -Copt-level=3 and extern "C" guarantee that the selected register is always r0/s0/d0/q0 + #[no_mangle] + pub unsafe extern "C" fn $func() -> i32 { + let y; + asm!($code, out($reg) y); + y + } + }; +} + +// CHECK-LABEL: reg: +// CHECK: //APP +// CHECK: mov x0, x0 +// CHECK: //NO_APP +check!(reg reg "mov {0}, {0}"); + +// CHECK-LABEL: reg_w: +// CHECK: //APP +// CHECK: mov w0, w0 +// CHECK: //NO_APP +check!(reg_w reg "mov {0:w}, {0:w}"); + +// CHECK-LABEL: reg_x: +// CHECK: //APP +// CHECK: mov x0, x0 +// CHECK: //NO_APP +check!(reg_x reg "mov {0:x}, {0:x}"); + +// CHECK-LABEL: vreg: +// CHECK: //APP +// CHECK: add v0.4s, v0.4s, v0.4s +// CHECK: //NO_APP +check!(vreg vreg "add {0}.4s, {0}.4s, {0}.4s"); + +// CHECK-LABEL: vreg_b: +// CHECK: //APP +// CHECK: ldr b0, [x0] +// CHECK: //NO_APP +check!(vreg_b vreg "ldr {:b}, [x0]"); + +// CHECK-LABEL: vreg_h: +// CHECK: //APP +// CHECK: ldr h0, [x0] +// CHECK: //NO_APP +check!(vreg_h vreg "ldr {:h}, [x0]"); + +// CHECK-LABEL: vreg_s: +// CHECK: //APP +// CHECK: ldr s0, [x0] +// CHECK: //NO_APP +check!(vreg_s vreg "ldr {:s}, [x0]"); + +// CHECK-LABEL: vreg_d: +// CHECK: //APP +// CHECK: ldr d0, [x0] +// CHECK: //NO_APP +check!(vreg_d vreg "ldr {:d}, [x0]"); + +// CHECK-LABEL: vreg_q: +// CHECK: //APP +// CHECK: ldr q0, [x0] +// CHECK: //NO_APP +check!(vreg_q vreg "ldr {:q}, [x0]"); + +// CHECK-LABEL: vreg_v: +// CHECK: //APP +// CHECK: add v0.4s, v0.4s, v0.4s +// CHECK: //NO_APP +check!(vreg_v vreg "add {0:v}.4s, {0:v}.4s, {0:v}.4s"); + +// CHECK-LABEL: vreg_low16: +// CHECK: //APP +// CHECK: add v0.4s, v0.4s, v0.4s +// CHECK: //NO_APP +check!(vreg_low16 vreg_low16 "add {0}.4s, {0}.4s, {0}.4s"); + +// CHECK-LABEL: vreg_low16_b: +// CHECK: //APP +// CHECK: ldr b0, [x0] +// CHECK: //NO_APP +check!(vreg_low16_b vreg_low16 "ldr {:b}, [x0]"); + +// CHECK-LABEL: vreg_low16_h: +// CHECK: //APP +// CHECK: ldr h0, [x0] +// CHECK: //NO_APP +check!(vreg_low16_h vreg_low16 "ldr {:h}, [x0]"); + +// CHECK-LABEL: vreg_low16_s: +// CHECK: //APP +// CHECK: ldr s0, [x0] +// CHECK: //NO_APP +check!(vreg_low16_s vreg_low16 "ldr {:s}, [x0]"); + +// CHECK-LABEL: vreg_low16_d: +// CHECK: //APP +// CHECK: ldr d0, [x0] +// CHECK: //NO_APP +check!(vreg_low16_d vreg_low16 "ldr {:d}, [x0]"); + +// CHECK-LABEL: vreg_low16_q: +// CHECK: //APP +// CHECK: ldr q0, [x0] +// CHECK: //NO_APP +check!(vreg_low16_q vreg_low16 "ldr {:q}, [x0]"); + +// CHECK-LABEL: vreg_low16_v: +// CHECK: //APP +// CHECK: add v0.4s, v0.4s, v0.4s +// CHECK: //NO_APP +check!(vreg_low16_v vreg_low16 "add {0:v}.4s, {0:v}.4s, {0:v}.4s"); diff --git a/tests/assembly-llvm/asm/aarch64-outline-atomics.rs b/tests/assembly-llvm/asm/aarch64-outline-atomics.rs new file mode 100644 index 00000000000..5990fb84942 --- /dev/null +++ b/tests/assembly-llvm/asm/aarch64-outline-atomics.rs @@ -0,0 +1,17 @@ +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 +//@ compile-flags: --target aarch64-unknown-linux-gnu +//@ needs-llvm-components: aarch64 +//@ only-aarch64 +//@ only-linux + +#![crate_type = "rlib"] + +use std::sync::atomic::AtomicI32; +use std::sync::atomic::Ordering::*; + +pub fn compare_exchange(a: &AtomicI32) { + // On AArch64 LLVM should outline atomic operations. + // CHECK: __aarch64_cas4_relax + let _ = a.compare_exchange(0, 10, Relaxed, Relaxed); +} diff --git a/tests/assembly-llvm/asm/aarch64-types.rs b/tests/assembly-llvm/asm/aarch64-types.rs new file mode 100644 index 00000000000..b7abeb02298 --- /dev/null +++ b/tests/assembly-llvm/asm/aarch64-types.rs @@ -0,0 +1,633 @@ +//@ add-core-stubs +//@ revisions: aarch64 arm64ec +//@ assembly-output: emit-asm +//@ [aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@ [aarch64] needs-llvm-components: aarch64 +//@ [arm64ec] compile-flags: --target arm64ec-pc-windows-msvc +//@ [arm64ec] needs-llvm-components: aarch64 +//@ compile-flags: -Zmerge-functions=disabled + +#![feature(no_core, repr_simd, f16, f128)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +type ptr = *mut u8; + +#[repr(simd)] +pub struct i8x8([i8; 8]); +#[repr(simd)] +pub struct i16x4([i16; 4]); +#[repr(simd)] +pub struct i32x2([i32; 2]); +#[repr(simd)] +pub struct i64x1([i64; 1]); +#[repr(simd)] +pub struct f16x4([f16; 4]); +#[repr(simd)] +pub struct f32x2([f32; 2]); +#[repr(simd)] +pub struct f64x1([f64; 1]); +#[repr(simd)] +pub struct i8x16([i8; 16]); +#[repr(simd)] +pub struct i16x8([i16; 8]); +#[repr(simd)] +pub struct i32x4([i32; 4]); +#[repr(simd)] +pub struct i64x2([i64; 2]); +#[repr(simd)] +pub struct f16x8([f16; 8]); +#[repr(simd)] +pub struct f32x4([f32; 4]); +#[repr(simd)] +pub struct f64x2([f64; 2]); + +impl Copy for i8x8 {} +impl Copy for i16x4 {} +impl Copy for i32x2 {} +impl Copy for i64x1 {} +impl Copy for f16x4 {} +impl Copy for f32x2 {} +impl Copy for f64x1 {} +impl Copy for i8x16 {} +impl Copy for i16x8 {} +impl Copy for i32x4 {} +impl Copy for i64x2 {} +impl Copy for f16x8 {} +impl Copy for f32x4 {} +impl Copy for f64x2 {} + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// CHECK-LABEL: {{("#)?}}sym_fn{{"?}} +// CHECK: //APP +// CHECK: bl extern_func +// CHECK: //NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("bl {}", sym extern_func); +} + +// CHECK-LABEL: {{("#)?}}sym_static{{"?}} +// CHECK: //APP +// CHECK: adr x0, extern_static +// CHECK: //NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!("adr x0, {}", sym extern_static); +} + +// Regression test for #75761 +// CHECK-LABEL: {{("#)?}}issue_75761{{"?}} +// x29 holds the frame pointer, right next to x30, so ldp/stp happens sometimes +// CHECK: st[[MAY_PAIR:(r|p).*]]x30 +// CHECK: //APP +// CHECK: //NO_APP +// CHECK: ld[[MAY_PAIR]]x30 +#[no_mangle] +pub unsafe fn issue_75761() { + asm!("", out("v0") _, out("x30") _); +} + +macro_rules! check { + ($func:ident $ty:ident $class:ident $mov:literal $modifier:literal) => { + // FIXME(f16_f128): Change back to `$func(x: $ty) -> $ty` once arm64ec can pass and return + // `f16` and `f128` without LLVM erroring. + // LLVM issue: + #[no_mangle] + pub unsafe fn $func(inp: &$ty, out: &mut $ty) { + let x = *inp; + let y; + asm!( + concat!($mov, " {:", $modifier, "}, {:", $modifier, "}"), + out($class) y, + in($class) x + ); + *out = y; + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt $mov:literal) => { + // FIXME(f16_f128): See FIXME in `check!` + #[no_mangle] + pub unsafe fn $func(inp: &$ty, out: &mut $ty) { + let x = *inp; + let y; + asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + *out = y; + } + }; +} + +// CHECK-LABEL: {{("#)?}}reg_i8{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check!(reg_i8 i8 reg "mov" ""); + +// CHECK-LABEL: {{("#)?}}reg_i16{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check!(reg_i16 i16 reg "mov" ""); + +// CHECK-LABEL: {{("#)?}}reg_f16{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check!(reg_f16 f16 reg "mov" ""); + +// CHECK-LABEL: {{("#)?}}reg_i32{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check!(reg_i32 i32 reg "mov" ""); + +// CHECK-LABEL: {{("#)?}}reg_f32{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check!(reg_f32 f32 reg "mov" ""); + +// CHECK-LABEL: {{("#)?}}reg_i64{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check!(reg_i64 i64 reg "mov" ""); + +// CHECK-LABEL: {{("#)?}}reg_f64{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check!(reg_f64 f64 reg "mov" ""); + +// CHECK-LABEL: {{("#)?}}reg_ptr{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check!(reg_ptr ptr reg "mov" ""); + +// CHECK-LABEL: {{("#)?}}vreg_i8{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i8 i8 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_i16{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i16 i16 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_f16{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f16 f16 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_i32{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i32 i32 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_f32{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f32 f32 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_i64{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i64 i64 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_f64{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f64 f64 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_f128{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f128 f128 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_ptr{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_ptr ptr vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_i8x8{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i8x8 i8x8 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_i16x4{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i16x4 i16x4 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_i32x2{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i32x2 i32x2 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_i64x1{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i64x1 i64x1 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_f16x4{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f16x4 f16x4 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_f32x2{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f32x2 f32x2 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_f64x1{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f64x1 f64x1 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_i8x16{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i8x16 i8x16 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_i16x8{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i16x8 i16x8 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_i32x4{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i32x4 i32x4 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_i64x2{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i64x2 i64x2 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_f16x8{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f16x8 f16x8 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_f32x4{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f32x4 f32x4 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_f64x2{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f64x2 f64x2 vreg "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_i8{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i8 i8 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_i16{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i16 i16 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_f16{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f16 f16 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_f32{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f32 f32 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_i64{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i64 i64 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_f64{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f64 f64 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_f128{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f128 f128 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_ptr{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_ptr ptr vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_i8x8{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i8x8 i8x8 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_i16x4{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i16x4 i16x4 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_i32x2{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i32x2 i32x2 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_i64x1{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i64x1 i64x1 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_f16x4{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f16x4 f16x4 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_f32x2{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f32x2 f32x2 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_f64x1{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f64x1 f64x1 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_i8x16{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i8x16 i8x16 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_i16x8{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i16x8 i16x8 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_i32x4{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i32x4 i32x4 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_i64x2{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i64x2 i64x2 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_f16x8{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f16x8 f16x8 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_f32x4{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f32x4 f32x4 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}vreg_low16_f64x2{{"?}} +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f64x2 f64x2 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: {{("#)?}}x0_i8{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check_reg!(x0_i8 i8 "x0" "mov"); + +// CHECK-LABEL: {{("#)?}}x0_i16{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check_reg!(x0_i16 i16 "x0" "mov"); + +// CHECK-LABEL: {{("#)?}}x0_f16{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check_reg!(x0_f16 f16 "x0" "mov"); + +// CHECK-LABEL: {{("#)?}}x0_i32{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check_reg!(x0_i32 i32 "x0" "mov"); + +// CHECK-LABEL: {{("#)?}}x0_f32{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check_reg!(x0_f32 f32 "x0" "mov"); + +// CHECK-LABEL: {{("#)?}}x0_i64{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check_reg!(x0_i64 i64 "x0" "mov"); + +// CHECK-LABEL: {{("#)?}}x0_f64{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check_reg!(x0_f64 f64 "x0" "mov"); + +// CHECK-LABEL: {{("#)?}}x0_ptr{{"?}} +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check_reg!(x0_ptr ptr "x0" "mov"); + +// CHECK-LABEL: {{("#)?}}v0_i8{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i8 i8 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_i16{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i16 i16 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_f16{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f16 f16 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_i32{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i32 i32 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_f32{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f32 f32 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_i64{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i64 i64 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_f64{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f64 f64 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_f128{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f128 f128 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_ptr{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_ptr ptr "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_i8x8{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i8x8 i8x8 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_i16x4{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i16x4 i16x4 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_i32x2{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i32x2 i32x2 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_i64x1{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i64x1 i64x1 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_f16x4{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f16x4 f16x4 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_f32x2{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f32x2 f32x2 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_f64x1{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f64x1 f64x1 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_i8x16{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i8x16 i8x16 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_i16x8{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i16x8 i16x8 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_i32x4{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i32x4 i32x4 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_i64x2{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i64x2 i64x2 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_f16x8{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f16x8 f16x8 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_f32x4{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f32x4 f32x4 "s0" "fmov"); + +// CHECK-LABEL: {{("#)?}}v0_f64x2{{"?}} +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f64x2 f64x2 "s0" "fmov"); diff --git a/tests/assembly-llvm/asm/arm-modifiers.rs b/tests/assembly-llvm/asm/arm-modifiers.rs new file mode 100644 index 00000000000..32a36840492 --- /dev/null +++ b/tests/assembly-llvm/asm/arm-modifiers.rs @@ -0,0 +1,122 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 -C panic=abort +//@ compile-flags: --target armv7-unknown-linux-gnueabihf +//@ compile-flags: -C target-feature=+neon +//@ compile-flags: -Zmerge-functions=disabled +//@ needs-llvm-components: arm + +#![feature(no_core, repr_simd)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +#[repr(simd)] +pub struct f32x4([f32; 4]); + +impl Copy for f32x4 {} + +macro_rules! check { + ($func:ident $modifier:literal $reg:ident $ty:ident $mov:literal) => { + // -Copt-level=3 and extern "C" guarantee that the selected register is always r0/s0/d0/q0 + #[no_mangle] + pub unsafe extern "C" fn $func() -> $ty { + let y; + asm!(concat!($mov, " {0:", $modifier, "}, {0:", $modifier, "}"), out($reg) y); + y + } + }; +} + +// CHECK-LABEL: reg: +// CHECK: @APP +// CHECK: mov r0, r0 +// CHECK: @NO_APP +check!(reg "" reg i32 "mov"); + +// CHECK-LABEL: sreg: +// CHECK: @APP +// CHECK: vmov.f32 s0, s0 +// CHECK: @NO_APP +check!(sreg "" sreg f32 "vmov.f32"); + +// CHECK-LABEL: sreg_low16: +// CHECK: @APP +// CHECK: vmov.f32 s0, s0 +// CHECK: @NO_APP +check!(sreg_low16 "" sreg_low16 f32 "vmov.f32"); + +// CHECK-LABEL: dreg: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check!(dreg "" dreg f64 "vmov.f64"); + +// CHECK-LABEL: dreg_low16: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check!(dreg_low16 "" dreg_low16 f64 "vmov.f64"); + +// CHECK-LABEL: dreg_low8: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check!(dreg_low8 "" dreg_low8 f64 "vmov.f64"); + +// CHECK-LABEL: qreg: +// CHECK: @APP +// CHECK: vorr q0, q0, q0 +// CHECK: @NO_APP +check!(qreg "" qreg f32x4 "vmov"); + +// CHECK-LABEL: qreg_e: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check!(qreg_e "e" qreg f32x4 "vmov.f64"); + +// CHECK-LABEL: qreg_f: +// CHECK: @APP +// CHECK: vmov.f64 d1, d1 +// CHECK: @NO_APP +check!(qreg_f "f" qreg f32x4 "vmov.f64"); + +// CHECK-LABEL: qreg_low8: +// CHECK: @APP +// CHECK: vorr q0, q0, q0 +// CHECK: @NO_APP +check!(qreg_low8 "" qreg_low8 f32x4 "vmov"); + +// CHECK-LABEL: qreg_low8_e: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check!(qreg_low8_e "e" qreg_low8 f32x4 "vmov.f64"); + +// CHECK-LABEL: qreg_low8_f: +// CHECK: @APP +// CHECK: vmov.f64 d1, d1 +// CHECK: @NO_APP +check!(qreg_low8_f "f" qreg_low8 f32x4 "vmov.f64"); + +// CHECK-LABEL: qreg_low4: +// CHECK: @APP +// CHECK: vorr q0, q0, q0 +// CHECK: @NO_APP +check!(qreg_low4 "" qreg_low4 f32x4 "vmov"); + +// CHECK-LABEL: qreg_low4_e: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check!(qreg_low4_e "e" qreg_low4 f32x4 "vmov.f64"); + +// CHECK-LABEL: qreg_low4_f: +// CHECK: @APP +// CHECK: vmov.f64 d1, d1 +// CHECK: @NO_APP +check!(qreg_low4_f "f" qreg_low4 f32x4 "vmov.f64"); diff --git a/tests/assembly-llvm/asm/arm-types.rs b/tests/assembly-llvm/asm/arm-types.rs new file mode 100644 index 00000000000..fb93f474c20 --- /dev/null +++ b/tests/assembly-llvm/asm/arm-types.rs @@ -0,0 +1,639 @@ +//@ add-core-stubs +//@ revisions: base d32 neon +//@ assembly-output: emit-asm +//@ compile-flags: --target armv7-unknown-linux-gnueabihf +//@ compile-flags: -C opt-level=0 +//@ compile-flags: -Zmerge-functions=disabled +//@[d32] compile-flags: -C target-feature=+d32 +//@[neon] compile-flags: -C target-feature=+neon --cfg d32 +//@[neon] filecheck-flags: --check-prefix d32 +//@ needs-llvm-components: arm + +#![feature(no_core, repr_simd, f16)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +type ptr = *mut u8; + +#[repr(simd)] +pub struct i8x8([i8; 8]); +#[repr(simd)] +pub struct i16x4([i16; 4]); +#[repr(simd)] +pub struct i32x2([i32; 2]); +#[repr(simd)] +pub struct i64x1([i64; 1]); +#[repr(simd)] +pub struct f16x4([f16; 4]); +#[repr(simd)] +pub struct f32x2([f32; 2]); +#[repr(simd)] +pub struct i8x16([i8; 16]); +#[repr(simd)] +pub struct i16x8([i16; 8]); +#[repr(simd)] +pub struct i32x4([i32; 4]); +#[repr(simd)] +pub struct i64x2([i64; 2]); +#[repr(simd)] +pub struct f16x8([f16; 8]); +#[repr(simd)] +pub struct f32x4([f32; 4]); + +impl Copy for i8x8 {} +impl Copy for i16x4 {} +impl Copy for i32x2 {} +impl Copy for i64x1 {} +impl Copy for f16x4 {} +impl Copy for f32x2 {} +impl Copy for i8x16 {} +impl Copy for i16x8 {} +impl Copy for i32x4 {} +impl Copy for i64x2 {} +impl Copy for f16x8 {} +impl Copy for f32x4 {} + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// CHECK-LABEL: sym_fn: +// CHECK: @APP +// CHECK: bl extern_func +// CHECK: @NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("bl {}", sym extern_func); +} + +// CHECK-LABEL: sym_static: +// CHECK: @APP +// CHECK: adr r0, extern_static +// CHECK: @NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!("adr r0, {}", sym extern_static); +} + +// Regression test for #82052. +// CHECK-LABEL: issue_82052 +// CHECK: push {{.*}}lr +// CHECK: @APP +// CHECK: @NO_APP +pub unsafe fn issue_82052() { + asm!("", out("r14") _); +} + +macro_rules! check { + ($func:ident $ty:ident $class:ident $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " {}, {}"), out($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +// CHECK-LABEL: reg_i8: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_i8 i8 reg "mov"); + +// CHECK-LABEL: reg_i16: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_i16 i16 reg "mov"); + +// CHECK-LABEL: reg_i32: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_i32 i32 reg "mov"); + +// CHECK-LABEL: reg_f16: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_f16 f16 reg "mov"); + +// CHECK-LABEL: reg_f32: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_f32 f32 reg "mov"); + +// CHECK-LABEL: reg_ptr: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_ptr ptr reg "mov"); + +// CHECK-LABEL: sreg_i32: +// CHECK: @APP +// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: @NO_APP +check!(sreg_i32 i32 sreg "vmov.f32"); + +// CHECK-LABEL: sreg_f16: +// CHECK: @APP +// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: @NO_APP +check!(sreg_f16 f16 sreg "vmov.f32"); + +// CHECK-LABEL: sreg_f32: +// CHECK: @APP +// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: @NO_APP +check!(sreg_f32 f32 sreg "vmov.f32"); + +// CHECK-LABEL: sreg_ptr: +// CHECK: @APP +// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: @NO_APP +check!(sreg_ptr ptr sreg "vmov.f32"); + +// CHECK-LABEL: sreg_low16_i32: +// CHECK: @APP +// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: @NO_APP +check!(sreg_low16_i32 i32 sreg_low16 "vmov.f32"); + +// CHECK-LABEL: sreg_low16_f16: +// CHECK: @APP +// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: @NO_APP +check!(sreg_low16_f16 f16 sreg_low16 "vmov.f32"); + +// CHECK-LABEL: sreg_low16_f32: +// CHECK: @APP +// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: @NO_APP +check!(sreg_low16_f32 f32 sreg_low16 "vmov.f32"); + +// d32-LABEL: dreg_i64: +// d32: @APP +// d32: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// d32: @NO_APP +#[cfg(d32)] +check!(dreg_i64 i64 dreg "vmov.f64"); + +// d32-LABEL: dreg_f64: +// d32: @APP +// d32: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// d32: @NO_APP +#[cfg(d32)] +check!(dreg_f64 f64 dreg "vmov.f64"); + +// neon-LABEL: dreg_i8x8: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_i8x8 i8x8 dreg "vmov.f64"); + +// neon-LABEL: dreg_i16x4: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_i16x4 i16x4 dreg "vmov.f64"); + +// neon-LABEL: dreg_i32x2: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_i32x2 i32x2 dreg "vmov.f64"); + +// neon-LABEL: dreg_i64x1: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_i64x1 i64x1 dreg "vmov.f64"); + +// neon-LABEL: dreg_f16x4: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_f16x4 f16x4 dreg "vmov.f64"); + +// neon-LABEL: dreg_f32x2: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_f32x2 f32x2 dreg "vmov.f64"); + +// CHECK-LABEL: dreg_low16_i64: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low16_i64 i64 dreg_low16 "vmov.f64"); + +// CHECK-LABEL: dreg_low16_f64: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low16_f64 f64 dreg_low16 "vmov.f64"); + +// neon-LABEL: dreg_low16_i8x8: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_low16_i8x8 i8x8 dreg_low16 "vmov.f64"); + +// neon-LABEL: dreg_low16_i16x4: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_low16_i16x4 i16x4 dreg_low16 "vmov.f64"); + +// neon-LABEL: dreg_low16_i32x2: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_low16_i32x2 i32x2 dreg_low16 "vmov.f64"); + +// neon-LABEL: dreg_low16_i64x1: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_low16_i64x1 i64x1 dreg_low16 "vmov.f64"); + +// neon-LABEL: dreg_low16_f16x4: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_low16_f16x4 f16x4 dreg_low16 "vmov.f64"); + +// neon-LABEL: dreg_low16_f32x2: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_low16_f32x2 f32x2 dreg_low16 "vmov.f64"); + +// CHECK-LABEL: dreg_low8_i64: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low8_i64 i64 dreg_low8 "vmov.f64"); + +// CHECK-LABEL: dreg_low8_f64: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low8_f64 f64 dreg_low8 "vmov.f64"); + +// neon-LABEL: dreg_low8_i8x8: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_low8_i8x8 i8x8 dreg_low8 "vmov.f64"); + +// neon-LABEL: dreg_low8_i16x4: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_low8_i16x4 i16x4 dreg_low8 "vmov.f64"); + +// neon-LABEL: dreg_low8_i32x2: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_low8_i32x2 i32x2 dreg_low8 "vmov.f64"); + +// neon-LABEL: dreg_low8_i64x1: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_low8_i64x1 i64x1 dreg_low8 "vmov.f64"); + +// neon-LABEL: dreg_low8_f16x4: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_low8_f16x4 f16x4 dreg_low8 "vmov.f64"); + +// neon-LABEL: dreg_low8_f32x2: +// neon: @APP +// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(dreg_low8_f32x2 f32x2 dreg_low8 "vmov.f64"); + +// neon-LABEL: qreg_i8x16: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_i8x16 i8x16 qreg "vmov"); + +// neon-LABEL: qreg_i16x8: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_i16x8 i16x8 qreg "vmov"); + +// neon-LABEL: qreg_i32x4: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_i32x4 i32x4 qreg "vmov"); + +// neon-LABEL: qreg_i64x2: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_i64x2 i64x2 qreg "vmov"); + +// neon-LABEL: qreg_f16x8: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_f16x8 f16x8 qreg "vmov"); + +// neon-LABEL: qreg_f32x4: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_f32x4 f32x4 qreg "vmov"); + +// neon-LABEL: qreg_low8_i8x16: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_low8_i8x16 i8x16 qreg_low8 "vmov"); + +// neon-LABEL: qreg_low8_i16x8: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_low8_i16x8 i16x8 qreg_low8 "vmov"); + +// neon-LABEL: qreg_low8_i32x4: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_low8_i32x4 i32x4 qreg_low8 "vmov"); + +// neon-LABEL: qreg_low8_i64x2: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_low8_i64x2 i64x2 qreg_low8 "vmov"); + +// neon-LABEL: qreg_low8_f16x8: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_low8_f16x8 f16x8 qreg_low8 "vmov"); + +// neon-LABEL: qreg_low8_f32x4: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_low8_f32x4 f32x4 qreg_low8 "vmov"); + +// neon-LABEL: qreg_low4_i8x16: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_low4_i8x16 i8x16 qreg_low4 "vmov"); + +// neon-LABEL: qreg_low4_i16x8: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_low4_i16x8 i16x8 qreg_low4 "vmov"); + +// neon-LABEL: qreg_low4_i32x4: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_low4_i32x4 i32x4 qreg_low4 "vmov"); + +// neon-LABEL: qreg_low4_i64x2: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_low4_i64x2 i64x2 qreg_low4 "vmov"); + +// neon-LABEL: qreg_low4_f16x8: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_low4_f16x8 f16x8 qreg_low4 "vmov"); + +// neon-LABEL: qreg_low4_f32x4: +// neon: @APP +// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// neon: @NO_APP +#[cfg(neon)] +check!(qreg_low4_f32x4 f32x4 qreg_low4 "vmov"); + +// CHECK-LABEL: r0_i8: +// CHECK: @APP +// CHECK: mov r0, r0 +// CHECK: @NO_APP +check_reg!(r0_i8 i8 "r0" "mov"); + +// CHECK-LABEL: r0_i16: +// CHECK: @APP +// CHECK: mov r0, r0 +// CHECK: @NO_APP +check_reg!(r0_i16 i16 "r0" "mov"); + +// CHECK-LABEL: r0_i32: +// CHECK: @APP +// CHECK: mov r0, r0 +// CHECK: @NO_APP +check_reg!(r0_i32 i32 "r0" "mov"); + +// CHECK-LABEL: r0_f16: +// CHECK: @APP +// CHECK: mov r0, r0 +// CHECK: @NO_APP +check_reg!(r0_f16 f16 "r0" "mov"); + +// CHECK-LABEL: r0_f32: +// CHECK: @APP +// CHECK: mov r0, r0 +// CHECK: @NO_APP +check_reg!(r0_f32 f32 "r0" "mov"); + +// CHECK-LABEL: r0_ptr: +// CHECK: @APP +// CHECK: mov r0, r0 +// CHECK: @NO_APP +check_reg!(r0_ptr ptr "r0" "mov"); + +// CHECK-LABEL: s0_i32: +// CHECK: @APP +// CHECK: vmov.f32 s0, s0 +// CHECK: @NO_APP +check_reg!(s0_i32 i32 "s0" "vmov.f32"); + +// CHECK-LABEL: s0_f16: +// CHECK: @APP +// CHECK: vmov.f32 s0, s0 +// CHECK: @NO_APP +check_reg!(s0_f16 f16 "s0" "vmov.f32"); + +// CHECK-LABEL: s0_f32: +// CHECK: @APP +// CHECK: vmov.f32 s0, s0 +// CHECK: @NO_APP +check_reg!(s0_f32 f32 "s0" "vmov.f32"); + +// CHECK-LABEL: s0_ptr: +// CHECK: @APP +// CHECK: vmov.f32 s0, s0 +// CHECK: @NO_APP +check_reg!(s0_ptr ptr "s0" "vmov.f32"); + +// FIXME(#126797): "d0" should work with `i64` and `f64` even when `d32` is disabled. +// d32-LABEL: d0_i64: +// d32: @APP +// d32: vmov.f64 d0, d0 +// d32: @NO_APP +#[cfg(d32)] +check_reg!(d0_i64 i64 "d0" "vmov.f64"); + +// d32-LABEL: d0_f64: +// d32: @APP +// d32: vmov.f64 d0, d0 +// d32: @NO_APP +#[cfg(d32)] +check_reg!(d0_f64 f64 "d0" "vmov.f64"); + +// neon-LABEL: d0_i8x8: +// neon: @APP +// neon: vmov.f64 d0, d0 +// neon: @NO_APP +#[cfg(neon)] +check_reg!(d0_i8x8 i8x8 "d0" "vmov.f64"); + +// neon-LABEL: d0_i16x4: +// neon: @APP +// neon: vmov.f64 d0, d0 +// neon: @NO_APP +#[cfg(neon)] +check_reg!(d0_i16x4 i16x4 "d0" "vmov.f64"); + +// neon-LABEL: d0_i32x2: +// neon: @APP +// neon: vmov.f64 d0, d0 +// neon: @NO_APP +#[cfg(neon)] +check_reg!(d0_i32x2 i32x2 "d0" "vmov.f64"); + +// neon-LABEL: d0_i64x1: +// neon: @APP +// neon: vmov.f64 d0, d0 +// neon: @NO_APP +#[cfg(neon)] +check_reg!(d0_i64x1 i64x1 "d0" "vmov.f64"); + +// neon-LABEL: d0_f16x4: +// neon: @APP +// neon: vmov.f64 d0, d0 +// neon: @NO_APP +#[cfg(neon)] +check_reg!(d0_f16x4 f16x4 "d0" "vmov.f64"); + +// neon-LABEL: d0_f32x2: +// neon: @APP +// neon: vmov.f64 d0, d0 +// neon: @NO_APP +#[cfg(neon)] +check_reg!(d0_f32x2 f32x2 "d0" "vmov.f64"); + +// neon-LABEL: q0_i8x16: +// neon: @APP +// neon: vorr q0, q0, q0 +// neon: @NO_APP +#[cfg(neon)] +check_reg!(q0_i8x16 i8x16 "q0" "vmov"); + +// neon-LABEL: q0_i16x8: +// neon: @APP +// neon: vorr q0, q0, q0 +// neon: @NO_APP +#[cfg(neon)] +check_reg!(q0_i16x8 i16x8 "q0" "vmov"); + +// neon-LABEL: q0_i32x4: +// neon: @APP +// neon: vorr q0, q0, q0 +// neon: @NO_APP +#[cfg(neon)] +check_reg!(q0_i32x4 i32x4 "q0" "vmov"); + +// neon-LABEL: q0_i64x2: +// neon: @APP +// neon: vorr q0, q0, q0 +// neon: @NO_APP +#[cfg(neon)] +check_reg!(q0_i64x2 i64x2 "q0" "vmov"); + +// neon-LABEL: q0_f16x8: +// neon: @APP +// neon: vorr q0, q0, q0 +// neon: @NO_APP +#[cfg(neon)] +check_reg!(q0_f16x8 f16x8 "q0" "vmov"); + +// neon-LABEL: q0_f32x4: +// neon: @APP +// neon: vorr q0, q0, q0 +// neon: @NO_APP +#[cfg(neon)] +check_reg!(q0_f32x4 f32x4 "q0" "vmov"); diff --git a/tests/assembly-llvm/asm/avr-modifiers.rs b/tests/assembly-llvm/asm/avr-modifiers.rs new file mode 100644 index 00000000000..124cad9bef6 --- /dev/null +++ b/tests/assembly-llvm/asm/avr-modifiers.rs @@ -0,0 +1,43 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: --target avr-none -C target-cpu=atmega328p +//@ needs-llvm-components: avr + +#![feature(no_core, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +type ptr = *const u64; + +macro_rules! check { + ($func:ident $hi:literal $lo:literal $reg:tt) => { + #[no_mangle] + unsafe fn $func() -> i16 { + let y; + asm!(concat!("mov {0:", $hi, "}, {0:", $lo, "}"), out($reg) y); + y + } + }; +} + +// CHECK-LABEL: reg_pair_modifiers: +// CHECK: ;APP +// CHECK: mov r{{[1-9]?[13579]}}, r{{[1-9]?[24680]}} +// CHECK: ;NO_APP +check!(reg_pair_modifiers "h" "l" reg_pair); + +// CHECK-LABEL: reg_iw_modifiers: +// CHECK: ;APP +// CHECK: mov r{{[1-9]?[13579]}}, r{{[1-9]?[24680]}} +// CHECK: ;NO_APP +check!(reg_iw_modifiers "h" "l" reg_iw); + +// CHECK-LABEL: reg_ptr_modifiers: +// CHECK: ;APP +// CHECK: mov r{{[1-9]?[13579]}}, r{{[1-9]?[24680]}} +// CHECK: ;NO_APP +check!(reg_ptr_modifiers "h" "l" reg_ptr); diff --git a/tests/assembly-llvm/asm/avr-types.rs b/tests/assembly-llvm/asm/avr-types.rs new file mode 100644 index 00000000000..309405f4d51 --- /dev/null +++ b/tests/assembly-llvm/asm/avr-types.rs @@ -0,0 +1,205 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: --target avr-none -C target-cpu=atmega328p +//@ needs-llvm-components: avr + +#![feature(no_core, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +type ptr = *const u64; + +macro_rules! check { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!("mov {}, {}", lateout($class) y, in($class) x); + y + } + }; +} + +macro_rules! checkw { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!("movw {}, {}", lateout($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!("mov ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +macro_rules! check_regw { + ($func:ident $ty:ident $reg:tt $reg_lit:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!("movw ", $reg_lit, ", ", $reg_lit), lateout($reg) y, in($reg) x); + y + } + }; +} + +extern "C" { + fn extern_func(); + static extern_static: i8; +} + +// CHECK-LABEL: sym_fn +// CHECK: ;APP +// CHECK: call extern_func +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: sym_static +// CHECK: ;APP +// CHECK: lds r{{[0-9]+}}, extern_static +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn sym_static() -> i8 { + let y; + asm!("lds {}, {}", lateout(reg) y, sym extern_static); + y +} + +// CHECK-LABEL: ld_z: +// CHECK: ;APP +// CHECK: ld r{{[0-9]+}}, Z +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn ld_z(x: i16) -> i8 { + let y; + asm!("ld {}, Z", out(reg) y, in("Z") x); + y +} + +// CHECK-LABEL: ldd_z: +// CHECK: ;APP +// CHECK: ldd r{{[0-9]+}}, Z+4 +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn ldd_z(x: i16) -> i8 { + let y; + asm!("ldd {}, Z+4", out(reg) y, in("Z") x); + y +} + +// CHECK-LABEL: ld_predecrement: +// CHECK: ;APP +// CHECK: ld r{{[0-9]+}}, -Z +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn ld_predecrement(x: i16) -> i8 { + let y; + asm!("ld {}, -Z", out(reg) y, in("Z") x); + y +} + +// CHECK-LABEL: ld_postincrement: +// CHECK: ;APP +// CHECK: ld r{{[0-9]+}}, Z+ +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn ld_postincrement(x: i16) -> i8 { + let y; + asm!("ld {}, Z+", out(reg) y, in("Z") x); + y +} + +// CHECK-LABEL: muls_clobber: +// CHECK: ;APP +// CHECK: muls r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: movw r{{[0-9]+}}, r0 +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn muls_clobber(x: i8, y: i8) -> i16 { + let z; + asm!( + "muls {}, {}", + "movw {}, r1:r0", + out(reg_iw) z, + in(reg) x, + in(reg) y, + ); + z +} + +// CHECK-LABEL: reg_i8: +// CHECK: ;APP +// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +check!(reg_i8 i8 reg); + +// CHECK-LABEL: reg_upper_i8: +// CHECK: ;APP +// CHECK: mov r{{[1-3][0-9]}}, r{{[1-3][0-9]}} +// CHECK: ;NO_APP +check!(reg_upper_i8 i8 reg_upper); + +// CHECK-LABEL: reg_pair_i16: +// CHECK: ;APP +// CHECK: movw r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +checkw!(reg_pair_i16 i16 reg_pair); + +// CHECK-LABEL: reg_iw_i16: +// CHECK: ;APP +// CHECK: movw r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +checkw!(reg_iw_i16 i16 reg_iw); + +// CHECK-LABEL: reg_ptr_i16: +// CHECK: ;APP +// CHECK: movw r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +checkw!(reg_ptr_i16 i16 reg_ptr); + +// CHECK-LABEL: r2_i8: +// CHECK: ;APP +// CHECK: mov r2, r2 +// CHECK: ;NO_APP +check_reg!(r2_i8 i8 "r2"); + +// CHECK-LABEL: xl_i8: +// CHECK: ;APP +// CHECK: mov r26, r26 +// CHECK: ;NO_APP +check_reg!(xl_i8 i8 "XL"); + +// CHECK-LABEL: xh_i8: +// CHECK: ;APP +// CHECK: mov r27, r27 +// CHECK: ;NO_APP +check_reg!(xh_i8 i8 "XH"); + +// CHECK-LABEL: x_i16: +// CHECK: ;APP +// CHECK: movw r26, r26 +// CHECK: ;NO_APP +check_regw!(x_i16 i16 "X" "X"); + +// CHECK-LABEL: r25r24_i16: +// CHECK: ;APP +// CHECK: movw r24, r24 +// CHECK: ;NO_APP +check_regw!(r25r24_i16 i16 "r25r24" "r24"); diff --git a/tests/assembly-llvm/asm/bpf-types.rs b/tests/assembly-llvm/asm/bpf-types.rs new file mode 100644 index 00000000000..07ea7bd5ce0 --- /dev/null +++ b/tests/assembly-llvm/asm/bpf-types.rs @@ -0,0 +1,133 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: --target bpfel-unknown-none -C target_feature=+alu32 +//@ needs-llvm-components: bpf + +#![feature(no_core, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +type ptr = *const u64; + +macro_rules! check { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!("{} = {}", out($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($reg, " = ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +extern "C" { + fn extern_func(); +} + +// CHECK-LABEL: sym_fn +// CHECK: #APP +// CHECK: call extern_func +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8 i8 reg); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16 i16 reg); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32 i32 reg); + +// CHECK-LABEL: reg_i64: +// CHECK: #APP +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i64 i64 reg); + +// CHECK-LABEL: wreg_i8: +// CHECK: #APP +// CHECK: w{{[0-9]+}} = w{{[0-9]+}} +// CHECK: #NO_APP +check!(wreg_i8 i8 wreg); + +// CHECK-LABEL: wreg_i16: +// CHECK: #APP +// CHECK: w{{[0-9]+}} = w{{[0-9]+}} +// CHECK: #NO_APP +check!(wreg_i16 i16 wreg); + +// CHECK-LABEL: wreg_i32: +// CHECK: #APP +// CHECK: w{{[0-9]+}} = w{{[0-9]+}} +// CHECK: #NO_APP +check!(wreg_i32 i32 wreg); + +// CHECK-LABEL: r0_i8: +// CHECK: #APP +// CHECK: r0 = r0 +// CHECK: #NO_APP +check_reg!(r0_i8 i8 "r0"); + +// CHECK-LABEL: r0_i16: +// CHECK: #APP +// CHECK: r0 = r0 +// CHECK: #NO_APP +check_reg!(r0_i16 i16 "r0"); + +// CHECK-LABEL: r0_i32: +// CHECK: #APP +// CHECK: r0 = r0 +// CHECK: #NO_APP +check_reg!(r0_i32 i32 "r0"); + +// CHECK-LABEL: r0_i64: +// CHECK: #APP +// CHECK: r0 = r0 +// CHECK: #NO_APP +check_reg!(r0_i64 i64 "r0"); + +// CHECK-LABEL: w0_i8: +// CHECK: #APP +// CHECK: w0 = w0 +// CHECK: #NO_APP +check_reg!(w0_i8 i8 "w0"); + +// CHECK-LABEL: w0_i16: +// CHECK: #APP +// CHECK: w0 = w0 +// CHECK: #NO_APP +check_reg!(w0_i16 i16 "w0"); + +// CHECK-LABEL: w0_i32: +// CHECK: #APP +// CHECK: w0 = w0 +// CHECK: #NO_APP +check_reg!(w0_i32 i32 "w0"); diff --git a/tests/assembly-llvm/asm/comments.rs b/tests/assembly-llvm/asm/comments.rs new file mode 100644 index 00000000000..557009975dd --- /dev/null +++ b/tests/assembly-llvm/asm/comments.rs @@ -0,0 +1,12 @@ +//@ assembly-output: emit-asm +//@ only-x86_64 +// Check that comments in assembly get passed + +#![crate_type = "lib"] + +// CHECK-LABEL: test_comments: +#[no_mangle] +pub fn test_comments() { + // CHECK: example comment + unsafe { core::arch::asm!("nop // example comment") }; +} diff --git a/tests/assembly-llvm/asm/global_asm.rs b/tests/assembly-llvm/asm/global_asm.rs new file mode 100644 index 00000000000..8a4bf98c745 --- /dev/null +++ b/tests/assembly-llvm/asm/global_asm.rs @@ -0,0 +1,32 @@ +//@ only-x86_64 +//@ only-linux +//@ assembly-output: emit-asm +//@ compile-flags: -C llvm-args=--x86-asm-syntax=intel +//@ compile-flags: -C symbol-mangling-version=v0 + +#![crate_type = "rlib"] + +use std::arch::global_asm; + +#[no_mangle] +fn my_func() {} + +#[no_mangle] +static MY_STATIC: i32 = 0; + +// CHECK: mov eax, eax +global_asm!("mov eax, eax"); +// CHECK: mov ebx, 5 +global_asm!("mov ebx, {}", const 5); +// CHECK: mov ecx, 5 +global_asm!("movl ${}, %ecx", const 5, options(att_syntax)); +// CHECK: call my_func +global_asm!("call {}", sym my_func); +// CHECK: lea rax, [rip + MY_STATIC] +global_asm!("lea rax, [rip + {}]", sym MY_STATIC); +// CHECK: call _RNvC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_10global_asm6foobar +global_asm!("call {}", sym foobar); +// CHECK: _RNvC[[CRATE_IDENT]]_10global_asm6foobar: +fn foobar() { + loop {} +} diff --git a/tests/assembly-llvm/asm/hexagon-types.rs b/tests/assembly-llvm/asm/hexagon-types.rs new file mode 100644 index 00000000000..ce80fa75b35 --- /dev/null +++ b/tests/assembly-llvm/asm/hexagon-types.rs @@ -0,0 +1,139 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: --target hexagon-unknown-linux-musl +//@ compile-flags: -Zmerge-functions=disabled +//@ needs-llvm-components: hexagon + +#![feature(no_core, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +type ptr = *const i32; + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +macro_rules! check { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!("{} = {}", out($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($reg, " = ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +// CHECK-LABEL: sym_static: +// CHECK: InlineAsm Start +// CHECK: r0 = {{#+}}extern_static +// CHECK: InlineAsm End +#[no_mangle] +pub unsafe fn sym_static() { + asm!("r0 = #{}", sym extern_static); +} + +// CHECK-LABEL: sym_fn: +// CHECK: InlineAsm Start +// CHECK: r0 = {{#+}}extern_func +// CHECK: InlineAsm End +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("r0 = #{}", sym extern_func); +} + +// This is a test for multi-instruction packets, +// which require the escaped braces. +// +// CHECK-LABEL: packet: +// CHECK: InlineAsm Start +// CHECK: { +// CHECK: r{{[0-9]+}} = r0 +// CHECK: memw(r1{{(\+#0)?}}) = r{{[0-9]+}} +// CHECK: } +// CHECK: InlineAsm End +#[no_mangle] +pub unsafe fn packet() { + let val = 1024; + asm!("{{ + {} = r0 + memw(r1) = {} + }}", out(reg) _, in(reg) &val); +} + +// CHECK-LABEL: reg_ptr: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_ptr ptr reg); + +// CHECK-LABEL: reg_f32: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_f32 f32 reg); + +// CHECK-LABEL: reg_i32: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_i32 i32 reg); + +// CHECK-LABEL: reg_i8: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_i8 i8 reg); + +// CHECK-LABEL: reg_i16: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_i16 i16 reg); + +// CHECK-LABEL: r0_ptr: +// CHECK: InlineAsm Start +// CHECK: r0 = r0 +// CHECK: InlineAsm End +check_reg!(r0_ptr ptr "r0"); + +// CHECK-LABEL: r0_f32: +// CHECK: InlineAsm Start +// CHECK: r0 = r0 +// CHECK: InlineAsm End +check_reg!(r0_f32 f32 "r0"); + +// CHECK-LABEL: r0_i32: +// CHECK: InlineAsm Start +// CHECK: r0 = r0 +// CHECK: InlineAsm End +check_reg!(r0_i32 i32 "r0"); + +// CHECK-LABEL: r0_i8: +// CHECK: InlineAsm Start +// CHECK: r0 = r0 +// CHECK: InlineAsm End +check_reg!(r0_i8 i8 "r0"); + +// CHECK-LABEL: r0_i16: +// CHECK: InlineAsm Start +// CHECK: r0 = r0 +// CHECK: InlineAsm End +check_reg!(r0_i16 i16 "r0"); diff --git a/tests/assembly-llvm/asm/inline-asm-avx.rs b/tests/assembly-llvm/asm/inline-asm-avx.rs new file mode 100644 index 00000000000..630acbb971a --- /dev/null +++ b/tests/assembly-llvm/asm/inline-asm-avx.rs @@ -0,0 +1,25 @@ +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib +//@ only-x86_64 +//@ ignore-sgx + +#![feature(portable_simd)] + +use std::arch::asm; +use std::simd::Simd; + +#[target_feature(enable = "avx")] +#[no_mangle] +// CHECK-LABEL: convert: +pub unsafe fn convert(a: *const f32) -> Simd { + // CHECK: vbroadcastss (%{{[er][a-ds0-9][xpi0-9]?}}), {{%ymm[0-7]}} + let b: Simd; + unsafe { + asm!( + "vbroadcastss {b}, [{a}]", + a = in(reg) a, + b = out(ymm_reg) b, + ); + } + b +} diff --git a/tests/assembly-llvm/asm/loongarch-type.rs b/tests/assembly-llvm/asm/loongarch-type.rs new file mode 100644 index 00000000000..c782be19f1d --- /dev/null +++ b/tests/assembly-llvm/asm/loongarch-type.rs @@ -0,0 +1,190 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: --target loongarch64-unknown-linux-gnu +//@ compile-flags: -Zmerge-functions=disabled +//@ needs-llvm-components: loongarch + +#![feature(no_core, f16)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +type ptr = *const i32; + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// CHECK-LABEL: sym_fn: +// CHECK: #APP +// CHECK: pcalau12i $t0, %got_pc_hi20(extern_func) +// CHECK: ld.d $t0, $t0, %got_pc_lo12(extern_func) +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("la.got $r12, {}", sym extern_func); +} + +// CHECK-LABEL: sym_static: +// CHECK: #APP +// CHECK: pcalau12i $t0, %got_pc_hi20(extern_static) +// CHECK: ld.d $t0, $t0, %got_pc_lo12(extern_static) +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!("la.got $r12, {}", sym extern_static); +} + +macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); + y + } +};} + +macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } +};} + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i8, i8, reg, "move"); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i16, i16, reg, "move"); + +// CHECK-LABEL: reg_f16: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f16, f16, reg, "move"); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i32, i32, reg, "move"); + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f32, f32, reg, "move"); + +// CHECK-LABEL: reg_i64: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i64, i64, reg, "move"); + +// CHECK-LABEL: reg_f64: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f64, f64, reg, "move"); + +// CHECK-LABEL: reg_ptr: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_ptr, ptr, reg, "move"); + +// CHECK-LABEL: freg_f16: +// CHECK: #APP +// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(freg_f16, f16, freg, "fmov.s"); + +// CHECK-LABEL: freg_f32: +// CHECK: #APP +// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(freg_f32, f32, freg, "fmov.s"); + +// CHECK-LABEL: freg_f64: +// CHECK: #APP +// CHECK: fmov.d $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(freg_f64, f64, freg, "fmov.d"); + +// CHECK-LABEL: r4_i8: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_i8, i8, "$r4", "move"); + +// CHECK-LABEL: r4_i16: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_i16, i16, "$r4", "move"); + +// CHECK-LABEL: r4_f16: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_f16, f16, "$r4", "move"); + +// CHECK-LABEL: r4_i32: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_i32, i32, "$r4", "move"); + +// CHECK-LABEL: r4_f32: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_f32, f32, "$r4", "move"); + +// CHECK-LABEL: r4_i64: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_i64, i64, "$r4", "move"); + +// CHECK-LABEL: r4_f64: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_f64, f64, "$r4", "move"); + +// CHECK-LABEL: r4_ptr: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_ptr, ptr, "$r4", "move"); + +// CHECK-LABEL: f0_f16: +// CHECK: #APP +// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} +// CHECK: #NO_APP +check_reg!(f0_f16, f16, "$f0", "fmov.s"); + +// CHECK-LABEL: f0_f32: +// CHECK: #APP +// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} +// CHECK: #NO_APP +check_reg!(f0_f32, f32, "$f0", "fmov.s"); + +// CHECK-LABEL: f0_f64: +// CHECK: #APP +// CHECK: fmov.d $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} +// CHECK: #NO_APP +check_reg!(f0_f64, f64, "$f0", "fmov.d"); diff --git a/tests/assembly-llvm/asm/m68k-types.rs b/tests/assembly-llvm/asm/m68k-types.rs new file mode 100644 index 00000000000..9e4f6d9a1a9 --- /dev/null +++ b/tests/assembly-llvm/asm/m68k-types.rs @@ -0,0 +1,67 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: --target m68k-unknown-linux-gnu +//@ needs-llvm-components: m68k + +#![feature(no_core, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +type ptr = *const u64; + +macro_rules! check { + ($func:ident $ty:ident $class:ident $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " {}, {};"), out($class) y, in($class) x); + y + } + }; +} + +// CHECK-LABEL: reg_data_i8: +// CHECK: ;APP +// CHECK: move.b %d{{[0-9]}}, %d{{[0-9]}} +// CHECK: ;NO_APP +check!(reg_data_i8 i8 reg_data "move.b"); + +// CHECK-LABEL: reg_data_i16: +// CHECK: ;APP +// CHECK: move.w %d{{[0-9]}}, %d{{[0-9]}} +// CHECK: ;NO_APP +check!(reg_data_i16 i16 reg_data "move.w"); + +// CHECK-LABEL: reg_data_i32: +// CHECK: ;APP +// CHECK: move.l %d{{[0-9]}}, %d{{[0-9]}} +// CHECK: ;NO_APP +check!(reg_data_i32 i32 reg_data "move.l"); + +// CHECK-LABEL: reg_addr_i16: +// CHECK: ;APP +// CHECK: move.w %a{{[0-9]}}, %a{{[0-9]}} +// CHECK: ;NO_APP +check!(reg_addr_i16 i16 reg_addr "move.w"); + +// CHECK-LABEL: reg_addr_i32: +// CHECK: ;APP +// CHECK: move.l %a{{[0-9]}}, %a{{[0-9]}} +// CHECK: ;NO_APP +check!(reg_addr_i32 i32 reg_addr "move.l"); + +// CHECK-LABEL: reg_i16: +// CHECK: ;APP +// CHECK: move.w %{{[da][0-9]}}, %{{[da][0-9]}} +// CHECK: ;NO_APP +check!(reg_i16 i16 reg "move.w"); + +// CHECK-LABEL: reg_i32: +// CHECK: ;APP +// CHECK: move.l %{{[da][0-9]}}, %{{[da][0-9]}} +// CHECK: ;NO_APP +check!(reg_i32 i32 reg "move.l"); diff --git a/tests/assembly-llvm/asm/mips-types.rs b/tests/assembly-llvm/asm/mips-types.rs new file mode 100644 index 00000000000..00e8ce0b874 --- /dev/null +++ b/tests/assembly-llvm/asm/mips-types.rs @@ -0,0 +1,211 @@ +//@ add-core-stubs +//@ revisions: mips32 mips64 +//@ assembly-output: emit-asm +//@[mips32] compile-flags: --target mips-unknown-linux-gnu +//@[mips32] needs-llvm-components: mips +//@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 +//@[mips64] needs-llvm-components: mips +//@ compile-flags: -Zmerge-functions=disabled + +#![feature(no_core, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +type ptr = *const i32; + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); + y + } +};} + +macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } +};} + +// mips32-LABEL: sym_static_32: +// mips32: #APP +// mips32: lw $3, %got(extern_static)($gp) +// mips32: #NO_APP +#[cfg(mips32)] +#[no_mangle] +pub unsafe fn sym_static_32() { + asm!("lw $v1, {}", sym extern_static); +} + +// mips32-LABEL: sym_fn_32: +// mips32: #APP +// mips32: lw $3, %got(extern_func)($gp) +// mips32: #NO_APP +#[cfg(mips32)] +#[no_mangle] +pub unsafe fn sym_fn_32() { + asm!("lw $v1, {}", sym extern_func); +} + +// mips64-LABEL: sym_static_64: +// mips64: #APP +// mips64: lui $3, %got_hi(extern_static) +// mips64: daddu $3, $3, $gp +// mips64: ld $3, %got_lo(extern_static)($3) +// mips64: #NO_APP +#[cfg(mips64)] +#[no_mangle] +pub unsafe fn sym_static_64() { + asm!("ld $v1, {}", sym extern_static); +} + +// mips64-LABEL: sym_fn_64: +// mips64: #APP +// mips64: lui $3, %got_hi(extern_func) +// mips64: daddu $3, $3, $gp +// mips64: ld $3, %got_lo(extern_func)($3) +// mips64: #NO_APP +#[cfg(mips64)] +#[no_mangle] +pub unsafe fn sym_fn_64() { + asm!("ld $v1, {}", sym extern_func); +} + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// CHECK: mov.s $f{{[0-9]+}}, $f{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f32, f32, freg, "mov.s"); + +// CHECK-LABEL: f0_f32: +// CHECK: #APP +// CHECK: mov.s $f0, $f0 +// CHECK: #NO_APP +#[no_mangle] +check_reg!(f0_f32, f32, "$f0", "mov.s"); + +// CHECK-LABEL: reg_f32_64: +// CHECK: #APP +// CHECK: mov.d $f{{[0-9]+}}, $f{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f32_64, f32, freg, "mov.d"); + +// CHECK-LABEL: f0_f32_64: +// CHECK: #APP +// CHECK: mov.d $f0, $f0 +// CHECK: #NO_APP +#[no_mangle] +check_reg!(f0_f32_64, f32, "$f0", "mov.d"); + +// CHECK-LABEL: reg_f64: +// CHECK: #APP +// CHECK: mov.d $f{{[0-9]+}}, $f{{[0-9]+}} +// CHECK: #NO_APP +#[no_mangle] +check!(reg_f64, f64, freg, "mov.d"); + +// CHECK-LABEL: f0_f64: +// CHECK: #APP +// CHECK: mov.d $f0, $f0 +// CHECK: #NO_APP +#[no_mangle] +check_reg!(f0_f64, f64, "$f0", "mov.d"); + +// CHECK-LABEL: reg_ptr: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_ptr, ptr, reg, "move"); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32, i32, reg, "move"); + +// CHECK-LABEL: reg_f32_soft: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f32_soft, f32, reg, "move"); + +// mips64-LABEL: reg_f64_soft: +// mips64: #APP +// mips64: move ${{[0-9]+}}, ${{[0-9]+}} +// mips64: #NO_APP +#[cfg(mips64)] +check!(reg_f64_soft, f64, reg, "move"); + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8, i8, reg, "move"); + +// CHECK-LABEL: reg_u8: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_u8, u8, reg, "move"); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16, i16, reg, "move"); + +// mips64-LABEL: reg_i64: +// mips64: #APP +// mips64: move ${{[0-9]+}}, ${{[0-9]+}} +// mips64: #NO_APP +#[cfg(mips64)] +check!(reg_i64, i64, reg, "move"); + +// CHECK-LABEL: r8_ptr: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_ptr, ptr, "$8", "move"); + +// CHECK-LABEL: r8_i32: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_i32, i32, "$8", "move"); + +// CHECK-LABEL: r8_f32: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_f32, f32, "$8", "move"); + +// CHECK-LABEL: r8_i8: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_i8, i8, "$8", "move"); + +// CHECK-LABEL: r8_u8: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_u8, u8, "$8", "move"); + +// CHECK-LABEL: r8_i16: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_i16, i16, "$8", "move"); diff --git a/tests/assembly-llvm/asm/msp430-types.rs b/tests/assembly-llvm/asm/msp430-types.rs new file mode 100644 index 00000000000..442dc77999f --- /dev/null +++ b/tests/assembly-llvm/asm/msp430-types.rs @@ -0,0 +1,141 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: --target msp430-none-elf +//@ needs-llvm-components: msp430 + +#![feature(no_core, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +type ptr = *const i16; + +macro_rules! check { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!("mov {}, {}", lateout($class) y, in($class) x); + y + } + }; +} + +macro_rules! checkb { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!("mov.b {}, {}", lateout($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!("mov ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +macro_rules! check_regb { + ($func:ident $ty:ident $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!("mov.b ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +extern "C" { + fn extern_func(); + static extern_static: i8; +} + +// CHECK-LABEL: sym_fn +// CHECK: ;APP +// CHECK: call extern_func +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: sym_static +// CHECK: ;APP +// CHECK: mov.b extern_static, r{{[0-9]+}} +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn sym_static() -> i8 { + let y; + asm!("mov.b {1}, {0}", lateout(reg) y, sym extern_static); + y +} + +// CHECK-LABEL: add_const: +// CHECK: ;APP +// CHECK: add.b #5, r{{[0-9]+}} +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn add_const() -> i8 { + let y; + asm!("add.b #{number}, {}", out(reg) y, number = const 5); + y +} + +// CHECK-LABEL: mov_postincrement: +// CHECK: ;APP +// CHECK: mov @r5+, r{{[0-9]+}} +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn mov_postincrement(mut x: *const i16) -> (i16, *const i16) { + let y; + asm!("mov @r5+, {0}", out(reg) y, inlateout("r5") x); + (y, x) +} + +// CHECK-LABEL: reg_i8: +// CHECK: ;APP +// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +check!(reg_i8 i8 reg); + +// CHECK-LABEL: reg_i16: +// CHECK: ;APP +// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +check!(reg_i16 i16 reg); + +// CHECK-LABEL: reg_i8b: +// CHECK: ;APP +// CHECK: mov.b r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +checkb!(reg_i8b i8 reg); + +// CHECK-LABEL: r5_i8: +// CHECK: ;APP +// CHECK: mov r5, r5 +// CHECK: ;NO_APP +check_reg!(r5_i8 i8 "r5"); + +// CHECK-LABEL: r5_i16: +// CHECK: ;APP +// CHECK: mov r5, r5 +// CHECK: ;NO_APP +check_reg!(r5_i16 i16 "r5"); + +// CHECK-LABEL: r5_i8b: +// CHECK: ;APP +// CHECK: mov.b r5, r5 +// CHECK: ;NO_APP +check_regb!(r5_i8b i8 "r5"); diff --git a/tests/assembly-llvm/asm/nvptx-types.rs b/tests/assembly-llvm/asm/nvptx-types.rs new file mode 100644 index 00000000000..7e8ebd03024 --- /dev/null +++ b/tests/assembly-llvm/asm/nvptx-types.rs @@ -0,0 +1,115 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: --target nvptx64-nvidia-cuda +//@ needs-llvm-components: nvptx + +#![feature(no_core, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +type ptr = *mut u8; + +// NVPTX does not support static variables +#[no_mangle] +fn extern_func() {} + +// CHECK-LABEL: .visible .func sym_fn() +// CHECK: // begin inline asm +// CHECK: call extern_func; +// CHECK: // end inline asm +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {};", sym extern_func); +} + +macro_rules! check { + ($func:ident $ty:ident $class:ident $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " {}, {};"), out($class) y, in($class) x); + y + } + }; +} + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg16_i8 +// CHECK: // begin inline asm +// CHECK: mov.i16 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg16_i8 i8 reg16 "mov.i16"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg16_i16 +// CHECK: // begin inline asm +// CHECK: mov.i16 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg16_i16 i16 reg16 "mov.i16"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i8 +// CHECK: // begin inline asm +// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg32_i8 i8 reg32 "mov.i32"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i16 +// CHECK: // begin inline asm +// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg32_i16 i16 reg32 "mov.i32"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i32 +// CHECK: // begin inline asm +// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg32_i32 i32 reg32 "mov.i32"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_f32 +// CHECK: // begin inline asm +// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg32_f32 f32 reg32 "mov.i32"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i8 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg64_i8 i8 reg64 "mov.i64"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i16 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg64_i16 i16 reg64 "mov.i64"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i32 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg64_i32 i32 reg64 "mov.i64"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_f32 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg64_f32 f32 reg64 "mov.i64"); + +// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_i64 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg64_i64 i64 reg64 "mov.i64"); + +// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_f64 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg64_f64 f64 reg64 "mov.i64"); + +// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_ptr +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg64_ptr ptr reg64 "mov.i64"); diff --git a/tests/assembly-llvm/asm/powerpc-types.rs b/tests/assembly-llvm/asm/powerpc-types.rs new file mode 100644 index 00000000000..4291e4c02f3 --- /dev/null +++ b/tests/assembly-llvm/asm/powerpc-types.rs @@ -0,0 +1,474 @@ +//@ add-core-stubs +//@ revisions: powerpc powerpc_altivec powerpc_vsx powerpc64 powerpc64_vsx +//@ assembly-output: emit-asm +//@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu +//@[powerpc] needs-llvm-components: powerpc +//@[powerpc_altivec] compile-flags: --target powerpc-unknown-linux-gnu -C target-feature=+altivec --cfg altivec +//@[powerpc_altivec] needs-llvm-components: powerpc +//@[powerpc_vsx] compile-flags: --target powerpc-unknown-linux-gnu -C target-feature=+altivec,+vsx --cfg altivec --cfg vsx +//@[powerpc_vsx] needs-llvm-components: powerpc +//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu --cfg altivec +//@[powerpc64] needs-llvm-components: powerpc +//@[powerpc64_vsx] compile-flags: --target powerpc64-unknown-linux-gnu -C target-feature=+vsx --cfg altivec --cfg vsx +//@[powerpc64_vsx] needs-llvm-components: powerpc +//@ compile-flags: -Zmerge-functions=disabled + +#![feature(no_core, repr_simd, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +#[cfg_attr(altivec, cfg(not(target_feature = "altivec")))] +#[cfg_attr(not(altivec), cfg(target_feature = "altivec"))] +compile_error!("altivec cfg and target feature mismatch"); +#[cfg_attr(vsx, cfg(not(target_feature = "vsx")))] +#[cfg_attr(not(vsx), cfg(target_feature = "vsx"))] +compile_error!("vsx cfg and target feature mismatch"); + +type ptr = *const i32; + +#[repr(simd)] +pub struct i8x16([i8; 16]); +#[repr(simd)] +pub struct i16x8([i16; 8]); +#[repr(simd)] +pub struct i32x4([i32; 4]); +#[repr(simd)] +pub struct i64x2([i64; 2]); +#[repr(simd)] +pub struct f32x4([f32; 4]); +#[repr(simd)] +pub struct f64x2([f64; 2]); + +impl Copy for i8x16 {} +impl Copy for i16x8 {} +impl Copy for i32x4 {} +impl Copy for i64x2 {} +impl Copy for f32x4 {} +impl Copy for f64x2 {} + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); + y + } +};} + +macro_rules! check_reg { ($func:ident, $ty:ty, $rego:tt, $regc:tt, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " ", $rego, ", ", $rego), lateout($regc) y, in($regc) x); + y + } +};} + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8, i8, reg, "mr"); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16, i16, reg, "mr"); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32, i32, reg, "mr"); + +// powerpc64-LABEL: reg_i64: +// powerpc64: #APP +// powerpc64: mr {{[0-9]+}}, {{[0-9]+}} +// powerpc64: #NO_APP +#[cfg(powerpc64)] +check!(reg_i64, i64, reg, "mr"); + +// CHECK-LABEL: reg_i8_nz: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8_nz, i8, reg_nonzero, "mr"); + +// CHECK-LABEL: reg_i16_nz: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16_nz, i16, reg_nonzero, "mr"); + +// CHECK-LABEL: reg_i32_nz: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32_nz, i32, reg_nonzero, "mr"); + +// powerpc64-LABEL: reg_i64_nz: +// powerpc64: #APP +// powerpc64: mr {{[0-9]+}}, {{[0-9]+}} +// powerpc64: #NO_APP +#[cfg(powerpc64)] +check!(reg_i64_nz, i64, reg_nonzero, "mr"); + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// CHECK: fmr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f32, f32, freg, "fmr"); + +// CHECK-LABEL: reg_f64: +// CHECK: #APP +// CHECK: fmr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f64, f64, freg, "fmr"); + +// powerpc_altivec-LABEL: vreg_i8x16: +// powerpc_altivec: #APP +// powerpc_altivec: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc_altivec: #NO_APP +// powerpc64-LABEL: vreg_i8x16: +// powerpc64: #APP +// powerpc64: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc64: #NO_APP +#[cfg(altivec)] +check!(vreg_i8x16, i8x16, vreg, "vmr"); + +// powerpc_altivec-LABEL: vreg_i16x8: +// powerpc_altivec: #APP +// powerpc_altivec: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc_altivec: #NO_APP +// powerpc64-LABEL: vreg_i16x8: +// powerpc64: #APP +// powerpc64: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc64: #NO_APP +#[cfg(altivec)] +check!(vreg_i16x8, i16x8, vreg, "vmr"); + +// powerpc_altivec-LABEL: vreg_i32x4: +// powerpc_altivec: #APP +// powerpc_altivec: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc_altivec: #NO_APP +// powerpc64-LABEL: vreg_i32x4: +// powerpc64: #APP +// powerpc64: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc64: #NO_APP +#[cfg(altivec)] +check!(vreg_i32x4, i32x4, vreg, "vmr"); + +// powerpc_vsx-LABEL: vreg_i64x2: +// powerpc_vsx: #APP +// powerpc_vsx: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc_vsx: #NO_APP +// powerpc64_vsx-LABEL: vreg_i64x2: +// powerpc64_vsx: #APP +// powerpc64_vsx: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc64_vsx: #NO_APP +#[cfg(vsx)] +check!(vreg_i64x2, i64x2, vreg, "vmr"); + +// powerpc_altivec-LABEL: vreg_f32x4: +// powerpc_altivec: #APP +// powerpc_altivec: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc_altivec: #NO_APP +// powerpc64-LABEL: vreg_f32x4: +// powerpc64: #APP +// powerpc64: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc64: #NO_APP +#[cfg(altivec)] +check!(vreg_f32x4, f32x4, vreg, "vmr"); + +// powerpc_vsx-LABEL: vreg_f64x2: +// powerpc_vsx: #APP +// powerpc_vsx: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc_vsx: #NO_APP +// powerpc64_vsx-LABEL: vreg_f64x2: +// powerpc64_vsx: #APP +// powerpc64_vsx: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc64_vsx: #NO_APP +#[cfg(vsx)] +check!(vreg_f64x2, f64x2, vreg, "vmr"); + +// powerpc_vsx-LABEL: vreg_f32: +// powerpc_vsx: #APP +// powerpc_vsx: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc_vsx: #NO_APP +// powerpc64_vsx-LABEL: vreg_f32: +// powerpc64_vsx: #APP +// powerpc64_vsx: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc64_vsx: #NO_APP +#[cfg(vsx)] +check!(vreg_f32, f32, vreg, "vmr"); + +// powerpc_vsx-LABEL: vreg_f64: +// powerpc_vsx: #APP +// powerpc_vsx: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc_vsx: #NO_APP +// powerpc64_vsx-LABEL: vreg_f64: +// powerpc64_vsx: #APP +// powerpc64_vsx: vmr {{[0-9]+}}, {{[0-9]+}} +// powerpc64_vsx: #NO_APP +#[cfg(vsx)] +check!(vreg_f64, f64, vreg, "vmr"); + +// CHECK-LABEL: reg_i8_r0: +// CHECK: #APP +// CHECK: mr 0, 0 +// CHECK: #NO_APP +check_reg!(reg_i8_r0, i8, "0", "0", "mr"); + +// CHECK-LABEL: reg_i16_r0: +// CHECK: #APP +// CHECK: mr 0, 0 +// CHECK: #NO_APP +check_reg!(reg_i16_r0, i16, "0", "0", "mr"); + +// CHECK-LABEL: reg_i32_r0: +// CHECK: #APP +// CHECK: mr 0, 0 +// CHECK: #NO_APP +check_reg!(reg_i32_r0, i32, "0", "0", "mr"); + +// powerpc64-LABEL: reg_i64_r0: +// powerpc64: #APP +// powerpc64: mr 0, 0 +// powerpc64: #NO_APP +#[cfg(powerpc64)] +check_reg!(reg_i64_r0, i64, "0", "0", "mr"); + +// CHECK-LABEL: reg_i8_r18: +// CHECK: #APP +// CHECK: mr 18, 18 +// CHECK: #NO_APP +check_reg!(reg_i8_r18, i8, "18", "18", "mr"); + +// CHECK-LABEL: reg_i16_r18: +// CHECK: #APP +// CHECK: mr 18, 18 +// CHECK: #NO_APP +check_reg!(reg_i16_r18, i16, "18", "18", "mr"); + +// CHECK-LABEL: reg_i32_r18: +// CHECK: #APP +// CHECK: mr 18, 18 +// CHECK: #NO_APP +check_reg!(reg_i32_r18, i32, "18", "18", "mr"); + +// powerpc64-LABEL: reg_i64_r18: +// powerpc64: #APP +// powerpc64: mr 18, 18 +// powerpc64: #NO_APP +#[cfg(powerpc64)] +check_reg!(reg_i64_r18, i64, "18", "18", "mr"); + +// CHECK-LABEL: reg_f32_f0: +// CHECK: #APP +// CHECK: fmr 0, 0 +// CHECK: #NO_APP +check_reg!(reg_f32_f0, f32, "0", "f0", "fmr"); + +// CHECK-LABEL: reg_f64_f0: +// CHECK: #APP +// CHECK: fmr 0, 0 +// CHECK: #NO_APP +check_reg!(reg_f64_f0, f64, "0", "f0", "fmr"); + +// CHECK-LABEL: reg_f32_f18: +// CHECK: #APP +// CHECK: fmr 18, 18 +// CHECK: #NO_APP +check_reg!(reg_f32_f18, f32, "18", "f18", "fmr"); + +// CHECK-LABEL: reg_f64_f18: +// CHECK: #APP +// CHECK: fmr 18, 18 +// CHECK: #NO_APP +check_reg!(reg_f64_f18, f64, "18", "f18", "fmr"); + +// powerpc_altivec-LABEL: vreg_i8x16_v0: +// powerpc_altivec: #APP +// powerpc_altivec: vmr 0, 0 +// powerpc_altivec: #NO_APP +// powerpc64-LABEL: vreg_i8x16_v0: +// powerpc64: #APP +// powerpc64: vmr 0, 0 +// powerpc64: #NO_APP +#[cfg(altivec)] +check_reg!(vreg_i8x16_v0, i8x16, "0", "v0", "vmr"); + +// powerpc_altivec-LABEL: vreg_i16x8_v0: +// powerpc_altivec: #APP +// powerpc_altivec: vmr 0, 0 +// powerpc_altivec: #NO_APP +// powerpc64-LABEL: vreg_i16x8_v0: +// powerpc64: #APP +// powerpc64: vmr 0, 0 +// powerpc64: #NO_APP +#[cfg(altivec)] +check_reg!(vreg_i16x8_v0, i16x8, "0", "v0", "vmr"); + +// powerpc_altivec-LABEL: vreg_i32x4_v0: +// powerpc_altivec: #APP +// powerpc_altivec: vmr 0, 0 +// powerpc_altivec: #NO_APP +// powerpc64-LABEL: vreg_i32x4_v0: +// powerpc64: #APP +// powerpc64: vmr 0, 0 +// powerpc64: #NO_APP +#[cfg(altivec)] +check_reg!(vreg_i32x4_v0, i32x4, "0", "v0", "vmr"); + +// powerpc_vsx-LABEL: vreg_i64x2_v0: +// powerpc_vsx: #APP +// powerpc_vsx: vmr 0, 0 +// powerpc_vsx: #NO_APP +// powerpc64_vsx-LABEL: vreg_i64x2_v0: +// powerpc64_vsx: #APP +// powerpc64_vsx: vmr 0, 0 +// powerpc64_vsx: #NO_APP +#[cfg(vsx)] +check_reg!(vreg_i64x2_v0, i64x2, "0", "v0", "vmr"); + +// powerpc_altivec-LABEL: vreg_f32x4_v0: +// powerpc_altivec: #APP +// powerpc_altivec: vmr 0, 0 +// powerpc_altivec: #NO_APP +// powerpc64-LABEL: vreg_f32x4_v0: +// powerpc64: #APP +// powerpc64: vmr 0, 0 +// powerpc64: #NO_APP +#[cfg(altivec)] +check_reg!(vreg_f32x4_v0, f32x4, "0", "v0", "vmr"); + +// powerpc_vsx-LABEL: vreg_f64x2_v0: +// powerpc_vsx: #APP +// powerpc_vsx: vmr 0, 0 +// powerpc_vsx: #NO_APP +// powerpc64_vsx-LABEL: vreg_f64x2_v0: +// powerpc64_vsx: #APP +// powerpc64_vsx: vmr 0, 0 +// powerpc64_vsx: #NO_APP +#[cfg(vsx)] +check_reg!(vreg_f64x2_v0, f64x2, "0", "v0", "vmr"); + +// powerpc_vsx-LABEL: vreg_f32_v0: +// powerpc_vsx: #APP +// powerpc_vsx: vmr 0, 0 +// powerpc_vsx: #NO_APP +// powerpc64_vsx-LABEL: vreg_f32_v0: +// powerpc64_vsx: #APP +// powerpc64_vsx: vmr 0, 0 +// powerpc64_vsx: #NO_APP +#[cfg(vsx)] +check_reg!(vreg_f32_v0, f32, "0", "v0", "vmr"); + +// powerpc_vsx-LABEL: vreg_f64_v0: +// powerpc_vsx: #APP +// powerpc_vsx: vmr 0, 0 +// powerpc_vsx: #NO_APP +// powerpc64_vsx-LABEL: vreg_f64_v0: +// powerpc64_vsx: #APP +// powerpc64_vsx: vmr 0, 0 +// powerpc64_vsx: #NO_APP +#[cfg(vsx)] +check_reg!(vreg_f64_v0, f64, "0", "v0", "vmr"); + +// powerpc_altivec-LABEL: vreg_i8x16_v18: +// powerpc_altivec: #APP +// powerpc_altivec: vmr 18, 18 +// powerpc_altivec: #NO_APP +// powerpc64-LABEL: vreg_i8x16_v18: +// powerpc64: #APP +// powerpc64: vmr 18, 18 +// powerpc64: #NO_APP +#[cfg(altivec)] +check_reg!(vreg_i8x16_v18, i8x16, "18", "v18", "vmr"); + +// powerpc_altivec-LABEL: vreg_i16x8_v18: +// powerpc_altivec: #APP +// powerpc_altivec: vmr 18, 18 +// powerpc_altivec: #NO_APP +// powerpc64-LABEL: vreg_i16x8_v18: +// powerpc64: #APP +// powerpc64: vmr 18, 18 +// powerpc64: #NO_APP +#[cfg(altivec)] +check_reg!(vreg_i16x8_v18, i16x8, "18", "v18", "vmr"); + +// powerpc_altivec-LABEL: vreg_i32x4_v18: +// powerpc_altivec: #APP +// powerpc_altivec: vmr 18, 18 +// powerpc_altivec: #NO_APP +// powerpc64-LABEL: vreg_i32x4_v18: +// powerpc64: #APP +// powerpc64: vmr 18, 18 +// powerpc64: #NO_APP +#[cfg(altivec)] +check_reg!(vreg_i32x4_v18, i32x4, "18", "v18", "vmr"); + +// powerpc_vsx-LABEL: vreg_i64x2_v18: +// powerpc_vsx: #APP +// powerpc_vsx: vmr 18, 18 +// powerpc_vsx: #NO_APP +// powerpc64_vsx-LABEL: vreg_i64x2_v18: +// powerpc64_vsx: #APP +// powerpc64_vsx: vmr 18, 18 +// powerpc64_vsx: #NO_APP +#[cfg(vsx)] +check_reg!(vreg_i64x2_v18, i64x2, "18", "v18", "vmr"); + +// powerpc_altivec-LABEL: vreg_f32x4_v18: +// powerpc_altivec: #APP +// powerpc_altivec: vmr 18, 18 +// powerpc_altivec: #NO_APP +// powerpc64-LABEL: vreg_f32x4_v18: +// powerpc64: #APP +// powerpc64: vmr 18, 18 +// powerpc64: #NO_APP +#[cfg(altivec)] +check_reg!(vreg_f32x4_v18, f32x4, "18", "v18", "vmr"); + +// powerpc_vsx-LABEL: vreg_f64x2_v18: +// powerpc_vsx: #APP +// powerpc_vsx: vmr 18, 18 +// powerpc_vsx: #NO_APP +// powerpc64_vsx-LABEL: vreg_f64x2_v18: +// powerpc64_vsx: #APP +// powerpc64_vsx: vmr 18, 18 +// powerpc64_vsx: #NO_APP +#[cfg(vsx)] +check_reg!(vreg_f64x2_v18, f64x2, "18", "v18", "vmr"); + +// powerpc_vsx-LABEL: vreg_f32_v18: +// powerpc_vsx: #APP +// powerpc_vsx: vmr 18, 18 +// powerpc_vsx: #NO_APP +// powerpc64_vsx-LABEL: vreg_f32_v18: +// powerpc64_vsx: #APP +// powerpc64_vsx: vmr 18, 18 +// powerpc64_vsx: #NO_APP +#[cfg(vsx)] +check_reg!(vreg_f32_v18, f32, "18", "v18", "vmr"); + +// powerpc_vsx-LABEL: vreg_f64_v18: +// powerpc_vsx: #APP +// powerpc_vsx: vmr 18, 18 +// powerpc_vsx: #NO_APP +// powerpc64_vsx-LABEL: vreg_f64_v18: +// powerpc64_vsx: #APP +// powerpc64_vsx: vmr 18, 18 +// powerpc64_vsx: #NO_APP +#[cfg(vsx)] +check_reg!(vreg_f64_v18, f64, "18", "v18", "vmr"); diff --git a/tests/assembly-llvm/asm/riscv-types.rs b/tests/assembly-llvm/asm/riscv-types.rs new file mode 100644 index 00000000000..724aa154da8 --- /dev/null +++ b/tests/assembly-llvm/asm/riscv-types.rs @@ -0,0 +1,227 @@ +//@ add-core-stubs +//@ revisions: riscv64 riscv32 riscv64-zfhmin riscv32-zfhmin riscv64-zfh riscv32-zfh +//@ assembly-output: emit-asm + +//@[riscv64] compile-flags: --target riscv64imac-unknown-none-elf +//@[riscv64] needs-llvm-components: riscv + +//@[riscv32] compile-flags: --target riscv32imac-unknown-none-elf +//@[riscv32] needs-llvm-components: riscv + +//@[riscv64-zfhmin] compile-flags: --target riscv64imac-unknown-none-elf --cfg riscv64 +//@[riscv64-zfhmin] needs-llvm-components: riscv +//@[riscv64-zfhmin] compile-flags: -C target-feature=+zfhmin +//@[riscv64-zfhmin] filecheck-flags: --check-prefix riscv64 + +//@[riscv32-zfhmin] compile-flags: --target riscv32imac-unknown-none-elf +//@[riscv32-zfhmin] needs-llvm-components: riscv +//@[riscv32-zfhmin] compile-flags: -C target-feature=+zfhmin + +//@[riscv64-zfh] compile-flags: --target riscv64imac-unknown-none-elf --cfg riscv64 +//@[riscv64-zfh] needs-llvm-components: riscv +//@[riscv64-zfh] compile-flags: -C target-feature=+zfh +//@[riscv64-zfh] filecheck-flags: --check-prefix riscv64 --check-prefix zfhmin + +//@[riscv32-zfh] compile-flags: --target riscv32imac-unknown-none-elf +//@[riscv32-zfh] needs-llvm-components: riscv +//@[riscv32-zfh] compile-flags: -C target-feature=+zfh +//@[riscv32-zfh] filecheck-flags: --check-prefix zfhmin + +//@ compile-flags: -C target-feature=+d +//@ compile-flags: -Zmerge-functions=disabled + +#![feature(no_core, f16)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register)] + +extern crate minicore; +use minicore::*; + +type ptr = *mut u8; + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// CHECK-LABEL: sym_fn: +// CHECK: #APP +// CHECK: call extern_func +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: sym_static: +// CHECK: #APP +// CHECK: auipc t0, %pcrel_hi(extern_static) +// CHECK: lb t0, %pcrel_lo(.Lpcrel_hi{{[0-9]+}})(t0) +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!("lb t0, {}", sym extern_static); +} + +macro_rules! check { + ($func:ident $ty:ident $class:ident $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " {}, {}"), out($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i8 i8 reg "mv"); + +// CHECK-LABEL: reg_f16: +// CHECK: #APP +// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f16 f16 reg "mv"); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i16 i16 reg "mv"); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i32 i32 reg "mv"); + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f32 f32 reg "mv"); + +// riscv64-LABEL: reg_i64: +// riscv64: #APP +// riscv64: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// riscv64: #NO_APP +#[cfg(riscv64)] +check!(reg_i64 i64 reg "mv"); + +// riscv64-LABEL: reg_f64: +// riscv64: #APP +// riscv64: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// riscv64: #NO_APP +#[cfg(riscv64)] +check!(reg_f64 f64 reg "mv"); + +// CHECK-LABEL: reg_ptr: +// CHECK: #APP +// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_ptr ptr reg "mv"); + +// CHECK-LABEL: freg_f16: +// zfhmin-NOT: or +// CHECK: #APP +// CHECK: fmv.s f{{[a-z0-9]+}}, f{{[a-z0-9]+}} +// CHECK: #NO_APP +// zfhmin-NOT: or +check!(freg_f16 f16 freg "fmv.s"); + +// CHECK-LABEL: freg_f32: +// CHECK: #APP +// CHECK: fmv.s f{{[a-z0-9]+}}, f{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(freg_f32 f32 freg "fmv.s"); + +// CHECK-LABEL: freg_f64: +// CHECK: #APP +// CHECK: fmv.d f{{[a-z0-9]+}}, f{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(freg_f64 f64 freg "fmv.d"); + +// CHECK-LABEL: a0_i8: +// CHECK: #APP +// CHECK: mv a0, a0 +// CHECK: #NO_APP +check_reg!(a0_i8 i8 "a0" "mv"); + +// CHECK-LABEL: a0_i16: +// CHECK: #APP +// CHECK: mv a0, a0 +// CHECK: #NO_APP +check_reg!(a0_i16 i16 "a0" "mv"); + +// CHECK-LABEL: a0_f16: +// CHECK: #APP +// CHECK: mv a0, a0 +// CHECK: #NO_APP +check_reg!(a0_f16 f16 "a0" "mv"); + +// CHECK-LABEL: a0_i32: +// CHECK: #APP +// CHECK: mv a0, a0 +// CHECK: #NO_APP +check_reg!(a0_i32 i32 "a0" "mv"); + +// CHECK-LABEL: a0_f32: +// CHECK: #APP +// CHECK: mv a0, a0 +// CHECK: #NO_APP +check_reg!(a0_f32 f32 "a0" "mv"); + +// riscv64-LABEL: a0_i64: +// riscv64: #APP +// riscv64: mv a0, a0 +// riscv64: #NO_APP +#[cfg(riscv64)] +check_reg!(a0_i64 i64 "a0" "mv"); + +// riscv64-LABEL: a0_f64: +// riscv64: #APP +// riscv64: mv a0, a0 +// riscv64: #NO_APP +#[cfg(riscv64)] +check_reg!(a0_f64 f64 "a0" "mv"); + +// CHECK-LABEL: a0_ptr: +// CHECK: #APP +// CHECK: mv a0, a0 +// CHECK: #NO_APP +check_reg!(a0_ptr ptr "a0" "mv"); + +// CHECK-LABEL: fa0_f16: +// zfhmin-NOT: or +// CHECK: #APP +// CHECK: fmv.s fa0, fa0 +// CHECK: #NO_APP +// zfhmin-NOT: or +check_reg!(fa0_f16 f16 "fa0" "fmv.s"); + +// CHECK-LABEL: fa0_f32: +// CHECK: #APP +// CHECK: fmv.s fa0, fa0 +// CHECK: #NO_APP +check_reg!(fa0_f32 f32 "fa0" "fmv.s"); + +// CHECK-LABEL: fa0_f64: +// CHECK: #APP +// CHECK: fmv.d fa0, fa0 +// CHECK: #NO_APP +check_reg!(fa0_f64 f64 "fa0" "fmv.d"); diff --git a/tests/assembly-llvm/asm/s390x-types.rs b/tests/assembly-llvm/asm/s390x-types.rs new file mode 100644 index 00000000000..e6fe38ecb0d --- /dev/null +++ b/tests/assembly-llvm/asm/s390x-types.rs @@ -0,0 +1,350 @@ +//@ add-core-stubs +//@ revisions: s390x s390x_vector +//@ assembly-output: emit-asm +//@[s390x] compile-flags: --target s390x-unknown-linux-gnu +//@[s390x] needs-llvm-components: systemz +//@[s390x_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector +//@[s390x_vector] needs-llvm-components: systemz +//@ compile-flags: -Zmerge-functions=disabled + +#![feature(no_core, repr_simd, f128)] +#![cfg_attr(s390x_vector, feature(asm_experimental_reg))] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +type ptr = *const i32; + +#[repr(simd)] +pub struct i8x16([i8; 16]); +#[repr(simd)] +pub struct i16x8([i16; 8]); +#[repr(simd)] +pub struct i32x4([i32; 4]); +#[repr(simd)] +pub struct i64x2([i64; 2]); +#[repr(simd)] +pub struct f32x4([f32; 4]); +#[repr(simd)] +pub struct f64x2([f64; 2]); + +impl Copy for i8x16 {} +impl Copy for i16x8 {} +impl Copy for i32x4 {} +impl Copy for i64x2 {} +impl Copy for f32x4 {} +impl Copy for f64x2 {} + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); + y + } +};} + +macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " %", $reg, ", %", $reg), lateout($reg) y, in($reg) x); + y + } +};} + +// CHECK-LABEL: sym_fn_32: +// CHECK: #APP +// CHECK: brasl %r14, extern_func +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn_32() { + asm!("brasl %r14, {}", sym extern_func); +} + +// CHECK-LABEL: sym_static: +// CHECK: #APP +// CHECK: brasl %r14, extern_static +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!("brasl %r14, {}", sym extern_static); +} + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8, i8, reg, "lgr"); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16, i16, reg, "lgr"); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32, i32, reg, "lgr"); + +// CHECK-LABEL: reg_i64: +// CHECK: #APP +// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i64, i64, reg, "lgr"); + +// CHECK-LABEL: reg_i8_addr: +// CHECK: #APP +// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8_addr, i8, reg_addr, "lgr"); + +// CHECK-LABEL: reg_i16_addr: +// CHECK: #APP +// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16_addr, i16, reg_addr, "lgr"); + +// CHECK-LABEL: reg_i32_addr: +// CHECK: #APP +// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32_addr, i32, reg_addr, "lgr"); + +// CHECK-LABEL: reg_i64_addr: +// CHECK: #APP +// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i64_addr, i64, reg_addr, "lgr"); + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// CHECK: ler %f{{[0-9]+}}, %f{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f32, f32, freg, "ler"); + +// CHECK-LABEL: reg_f64: +// CHECK: #APP +// CHECK: ldr %f{{[0-9]+}}, %f{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f64, f64, freg, "ldr"); + +// CHECK-LABEL: reg_ptr: +// CHECK: #APP +// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_ptr, ptr, reg, "lgr"); + +// s390x_vector-LABEL: vreg_i8x16: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_i8x16, i8x16, vreg, "vlr"); + +// s390x_vector-LABEL: vreg_i16x8: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_i16x8, i16x8, vreg, "vlr"); + +// s390x_vector-LABEL: vreg_i32x4: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_i32x4, i32x4, vreg, "vlr"); + +// s390x_vector-LABEL: vreg_i64x2: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_i64x2, i64x2, vreg, "vlr"); + +// s390x_vector-LABEL: vreg_f32x4: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_f32x4, f32x4, vreg, "vlr"); + +// s390x_vector-LABEL: vreg_f64x2: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_f64x2, f64x2, vreg, "vlr"); + +// s390x_vector-LABEL: vreg_i32: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_i32, i32, vreg, "vlr"); + +// s390x_vector-LABEL: vreg_i64: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_i64, i64, vreg, "vlr"); + +// s390x_vector-LABEL: vreg_i128: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_i128, i128, vreg, "vlr"); + +// s390x_vector-LABEL: vreg_f32: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_f32, f32, vreg, "vlr"); + +// s390x_vector-LABEL: vreg_f64: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_f64, f64, vreg, "vlr"); + +// s390x_vector-LABEL: vreg_f128: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_f128, f128, vreg, "vlr"); + +// CHECK-LABEL: r0_i8: +// CHECK: #APP +// CHECK: lr %r0, %r0 +// CHECK: #NO_APP +check_reg!(r0_i8, i8, "r0", "lr"); + +// CHECK-LABEL: r0_i16: +// CHECK: #APP +// CHECK: lr %r0, %r0 +// CHECK: #NO_APP +check_reg!(r0_i16, i16, "r0", "lr"); + +// CHECK-LABEL: r0_i32: +// CHECK: #APP +// CHECK: lr %r0, %r0 +// CHECK: #NO_APP +check_reg!(r0_i32, i32, "r0", "lr"); + +// CHECK-LABEL: r0_i64: +// CHECK: #APP +// CHECK: lr %r0, %r0 +// CHECK: #NO_APP +check_reg!(r0_i64, i64, "r0", "lr"); + +// CHECK-LABEL: f0_f32: +// CHECK: #APP +// CHECK: ler %f0, %f0 +// CHECK: #NO_APP +check_reg!(f0_f32, f32, "f0", "ler"); + +// CHECK-LABEL: f0_f64: +// CHECK: #APP +// CHECK: ldr %f0, %f0 +// CHECK: #NO_APP +check_reg!(f0_f64, f64, "f0", "ldr"); + +// s390x_vector-LABEL: v0_i8x16: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_i8x16, i8x16, "v0", "vlr"); + +// s390x_vector-LABEL: v0_i16x8: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_i16x8, i16x8, "v0", "vlr"); + +// s390x_vector-LABEL: v0_i32x4: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_i32x4, i32x4, "v0", "vlr"); + +// s390x_vector-LABEL: v0_i64x2: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_i64x2, i64x2, "v0", "vlr"); + +// s390x_vector-LABEL: v0_f32x4: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_f32x4, f32x4, "v0", "vlr"); + +// s390x_vector-LABEL: v0_f64x2: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_f64x2, f64x2, "v0", "vlr"); + +// s390x_vector-LABEL: v0_i32: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_i32, i32, "v0", "vlr"); + +// s390x_vector-LABEL: v0_i64: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_i64, i64, "v0", "vlr"); + +// s390x_vector-LABEL: v0_i128: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_i128, i128, "v0", "vlr"); + +// s390x_vector-LABEL: v0_f32: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_f32, f32, "v0", "vlr"); + +// s390x_vector-LABEL: v0_f64: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_f64, f64, "v0", "vlr"); + +// s390x_vector-LABEL: v0_f128: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_f128, f128, "v0", "vlr"); diff --git a/tests/assembly-llvm/asm/sparc-types.rs b/tests/assembly-llvm/asm/sparc-types.rs new file mode 100644 index 00000000000..49cc377cd95 --- /dev/null +++ b/tests/assembly-llvm/asm/sparc-types.rs @@ -0,0 +1,145 @@ +//@ add-core-stubs +//@ revisions: sparc sparcv8plus sparc64 +//@ assembly-output: emit-asm +//@[sparc] compile-flags: --target sparc-unknown-none-elf +//@[sparc] needs-llvm-components: sparc +//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu +//@[sparcv8plus] needs-llvm-components: sparc +//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparc64] needs-llvm-components: sparc +//@ compile-flags: -Zmerge-functions=disabled + +#![feature(no_core, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +type ptr = *const i32; + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov," {}, {}"), in($class) x, out($class) y); + y + } +};} + +macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " %", $reg, ", %", $reg), in($reg) x, lateout($reg) y); + y + } +};} + +// CHECK-LABEL: sym_fn_32: +// CHECK: !APP +// CHECK-NEXT: call extern_func +// CHECK-NEXT: !NO_APP +#[no_mangle] +pub unsafe fn sym_fn_32() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: sym_static: +// CHECK: !APP +// CHECK-NEXT: call extern_static +// CHECK-NEXT: !NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!("call {}", sym extern_static); +} + +// CHECK-LABEL: reg_i8: +// CHECK: !APP +// CHECK-NEXT: mov %{{[goli]}}{{[0-9]+}}, %{{[goli]}}{{[0-9]+}} +// CHECK-NEXT: !NO_APP +check!(reg_i8, i8, reg, "mov"); + +// CHECK-LABEL: reg_i16: +// CHECK: !APP +// CHECK-NEXT: mov %{{[goli]}}{{[0-9]+}}, %{{[goli]}}{{[0-9]+}} +// CHECK-NEXT: !NO_APP +check!(reg_i16, i16, reg, "mov"); + +// CHECK-LABEL: reg_i32: +// CHECK: !APP +// CHECK-NEXT: mov %{{[goli]}}{{[0-9]+}}, %{{[goli]}}{{[0-9]+}} +// CHECK-NEXT: !NO_APP +check!(reg_i32, i32, reg, "mov"); + +// FIXME: should be allowed for sparcv8plus but not yet supported in LLVM +// sparc64-LABEL: reg_i64: +// sparc64: !APP +// sparc64-NEXT: mov %{{[goli]}}{{[0-9]+}}, %{{[goli]}}{{[0-9]+}} +// sparc64-NEXT: !NO_APP +#[cfg(sparc64)] +check!(reg_i64, i64, reg, "mov"); + +// CHECK-LABEL: reg_ptr: +// CHECK: !APP +// CHECK-NEXT: mov %{{[goli]}}{{[0-9]+}}, %{{[goli]}}{{[0-9]+}} +// CHECK-NEXT: !NO_APP +check!(reg_ptr, ptr, reg, "mov"); + +// CHECK-LABEL: o0_i8: +// CHECK: !APP +// CHECK-NEXT: mov %o0, %o0 +// CHECK-NEXT: !NO_APP +check_reg!(o0_i8, i8, "o0", "mov"); + +// CHECK-LABEL: o0_i16: +// CHECK: !APP +// CHECK-NEXT: mov %o0, %o0 +// CHECK-NEXT: !NO_APP +check_reg!(o0_i16, i16, "o0", "mov"); + +// CHECK-LABEL: o0_i32: +// CHECK: !APP +// CHECK-NEXT: mov %o0, %o0 +// CHECK-NEXT: !NO_APP +check_reg!(o0_i32, i32, "o0", "mov"); + +// FIXME: should be allowed for sparcv8plus but not yet supported in LLVM +// sparc64-LABEL: o0_i64: +// sparc64: !APP +// sparc64-NEXT: mov %o0, %o0 +// sparc64-NEXT: !NO_APP +#[cfg(sparc64)] +check_reg!(o0_i64, i64, "o0", "mov"); + +// CHECK-LABEL: r9_i8: +// CHECK: !APP +// CHECK-NEXT: mov %o1, %o1 +// CHECK-NEXT: !NO_APP +check_reg!(r9_i8, i8, "r9", "mov"); + +// CHECK-LABEL: r9_i16: +// CHECK: !APP +// CHECK-NEXT: mov %o1, %o1 +// CHECK-NEXT: !NO_APP +check_reg!(r9_i16, i16, "r9", "mov"); + +// CHECK-LABEL: r9_i32: +// CHECK: !APP +// CHECK-NEXT: mov %o1, %o1 +// CHECK-NEXT: !NO_APP +check_reg!(r9_i32, i32, "r9", "mov"); + +// FIXME: should be allowed for sparcv8plus but not yet supported in LLVM +// sparc64-LABEL: r9_i64: +// sparc64: !APP +// sparc64-NEXT: mov %o1, %o1 +// sparc64-NEXT: !NO_APP +#[cfg(sparc64)] +check_reg!(r9_i64, i64, "r9", "mov"); diff --git a/tests/assembly-llvm/asm/wasm-types.rs b/tests/assembly-llvm/asm/wasm-types.rs new file mode 100644 index 00000000000..78e555c5317 --- /dev/null +++ b/tests/assembly-llvm/asm/wasm-types.rs @@ -0,0 +1,131 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: --target wasm32-unknown-unknown +//@ needs-llvm-components: webassembly + +#![feature(no_core, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +type ptr = *mut u8; + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// CHECK-LABEL: sym_fn: +// CHECK: #APP +// CHECK: call extern_func +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: sym_static +// CHECK: #APP +// CHECK: i32.const 42 +// CHECK: i32.store extern_static +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!(" + i32.const 42 + i32.store {} + ", sym extern_static); +} + +macro_rules! check { + ($func:ident $ty:ident $instr:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!("local.get {}\n", $instr, "\nlocal.set {}"), in(local) x, out(local) y); + y + } + }; +} + +// CHECK-LABEL: i8_i32: +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i32.clz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i8_i32 i8 "i32.clz"); + +// CHECK-LABEL: i16_i32: +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i32.clz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i16_i32 i16 "i32.clz"); + +// CHECK-LABEL: i32_i32: +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i32.clz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i32_i32 i32 "i32.clz"); + +// CHECK-LABEL: i8_i64 +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i64.clz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i8_i64 i8 "i64.clz"); + +// CHECK-LABEL: i16_i64 +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i64.clz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i16_i64 i16 "i64.clz"); + +// CHECK-LABEL: i32_i64 +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i64.clz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i32_i64 i32 "i64.clz"); + +// CHECK-LABEL: i64_i64 +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i64.clz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i64_i64 i64 "i64.clz"); + +// CHECK-LABEL: f32_f32 +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: f32.abs +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(f32_f32 f32 "f32.abs"); + +// CHECK-LABEL: f64_f64 +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: f64.abs +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(f64_f64 f64 "f64.abs"); + +// CHECK-LABEL: i32_ptr +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i32.eqz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i32_ptr ptr "i32.eqz"); diff --git a/tests/assembly-llvm/asm/x86-modifiers.rs b/tests/assembly-llvm/asm/x86-modifiers.rs new file mode 100644 index 00000000000..5f68e5c7317 --- /dev/null +++ b/tests/assembly-llvm/asm/x86-modifiers.rs @@ -0,0 +1,184 @@ +//@ add-core-stubs +//@ revisions: x86_64 i686 +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 -C panic=abort +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64] needs-llvm-components: x86 +//@[i686] compile-flags: --target i686-unknown-linux-gnu +//@[i686] needs-llvm-components: x86 +//@ compile-flags: -C llvm-args=--x86-asm-syntax=intel +//@ compile-flags: -C target-feature=+avx512bw +//@ compile-flags: -Zmerge-functions=disabled + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register)] + +extern crate minicore; +use minicore::*; + +macro_rules! check { + ($func:ident $modifier:literal $reg:ident $mov:literal) => { + // -Copt-level=3 and extern "C" guarantee that the selected register is always ax/xmm0 + #[no_mangle] + pub unsafe extern "C" fn $func() -> i32 { + let y; + asm!(concat!($mov, " {0:", $modifier, "}, {0:", $modifier, "}"), out($reg) y); + y + } + }; +} + +// CHECK-LABEL: reg: +// CHECK: #APP +// x86_64: mov rax, rax +// i686: mov eax, eax +// CHECK: #NO_APP +check!(reg "" reg "mov"); + +// x86_64-LABEL: reg_l: +// x86_64: #APP +// x86_64: mov al, al +// x86_64: #NO_APP +#[cfg(x86_64)] +check!(reg_l "l" reg "mov"); + +// CHECK-LABEL: reg_x: +// CHECK: #APP +// CHECK: mov ax, ax +// CHECK: #NO_APP +check!(reg_x "x" reg "mov"); + +// CHECK-LABEL: reg_e: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check!(reg_e "e" reg "mov"); + +// x86_64-LABEL: reg_r: +// x86_64: #APP +// x86_64: mov rax, rax +// x86_64: #NO_APP +#[cfg(x86_64)] +check!(reg_r "r" reg "mov"); + +// CHECK-LABEL: reg_abcd: +// CHECK: #APP +// x86_64: mov rax, rax +// i686: mov eax, eax +// CHECK: #NO_APP +check!(reg_abcd "" reg_abcd "mov"); + +// CHECK-LABEL: reg_abcd_l: +// CHECK: #APP +// CHECK: mov al, al +// CHECK: #NO_APP +check!(reg_abcd_l "l" reg_abcd "mov"); + +// CHECK-LABEL: reg_abcd_h: +// CHECK: #APP +// CHECK: mov ah, ah +// CHECK: #NO_APP +check!(reg_abcd_h "h" reg_abcd "mov"); + +// CHECK-LABEL: reg_abcd_x: +// CHECK: #APP +// CHECK: mov ax, ax +// CHECK: #NO_APP +check!(reg_abcd_x "x" reg_abcd "mov"); + +// CHECK-LABEL: reg_abcd_e: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check!(reg_abcd_e "e" reg_abcd "mov"); + +// x86_64-LABEL: reg_abcd_r: +// x86_64: #APP +// x86_64: mov rax, rax +// x86_64: #NO_APP +#[cfg(x86_64)] +check!(reg_abcd_r "r" reg_abcd "mov"); + +// CHECK-LABEL: xmm_reg +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check!(xmm_reg "" xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_x +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check!(xmm_reg_x "x" xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_y +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check!(xmm_reg_y "y" xmm_reg "vmovaps"); + +// CHECK-LABEL: xmm_reg_z +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check!(xmm_reg_z "z" xmm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg +// CHECK: #APP +// CHECK: movaps ymm0, ymm0 +// CHECK: #NO_APP +check!(ymm_reg "" ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_x +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check!(ymm_reg_x "x" ymm_reg "movaps"); + +// CHECK-LABEL: ymm_reg_y +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check!(ymm_reg_y "y" ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_z +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check!(ymm_reg_z "z" ymm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg +// CHECK: #APP +// CHECK: movaps zmm0, zmm0 +// CHECK: #NO_APP +check!(zmm_reg "" zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_x +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check!(zmm_reg_x "x" zmm_reg "movaps"); + +// CHECK-LABEL: zmm_reg_y +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check!(zmm_reg_y "y" zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_z +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check!(zmm_reg_z "z" zmm_reg "vmovaps"); + +// Note: we don't have any way of ensuring that k1 is actually the register +// chosen by the register allocator, so this check may fail if a different +// register is chosen. + +// CHECK-LABEL: kreg: +// CHECK: #APP +// CHECK: kmovb k1, k1 +// CHECK: #NO_APP +check!(kreg "" kreg "kmovb"); diff --git a/tests/assembly-llvm/asm/x86-types.rs b/tests/assembly-llvm/asm/x86-types.rs new file mode 100644 index 00000000000..6120ed0d532 --- /dev/null +++ b/tests/assembly-llvm/asm/x86-types.rs @@ -0,0 +1,1095 @@ +//@ add-core-stubs +//@ revisions: x86_64 i686 +//@ assembly-output: emit-asm +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64] needs-llvm-components: x86 +//@[i686] compile-flags: --target i686-unknown-linux-gnu +//@[i686] needs-llvm-components: x86 +//@ compile-flags: -C llvm-args=--x86-asm-syntax=intel +//@ compile-flags: -C target-feature=+avx512bw +//@ compile-flags: -Zmerge-functions=disabled + +#![feature(no_core, repr_simd, f16, f128)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +type ptr = *mut u8; + +#[repr(simd)] +pub struct i8x16([i8; 16]); +#[repr(simd)] +pub struct i16x8([i16; 8]); +#[repr(simd)] +pub struct i32x4([i32; 4]); +#[repr(simd)] +pub struct i64x2([i64; 2]); +#[repr(simd)] +pub struct f16x8([f16; 8]); +#[repr(simd)] +pub struct f32x4([f32; 4]); +#[repr(simd)] +pub struct f64x2([f64; 2]); + +#[repr(simd)] +pub struct i8x32([i8; 32]); +#[repr(simd)] +pub struct i16x16([i16; 16]); +#[repr(simd)] +pub struct i32x8([i32; 8]); +#[repr(simd)] +pub struct i64x4([i64; 4]); +#[repr(simd)] +pub struct f16x16([f16; 16]); +#[repr(simd)] +pub struct f32x8([f32; 8]); +#[repr(simd)] +pub struct f64x4([f64; 4]); + +#[repr(simd)] +pub struct i8x64([i8; 64]); +#[repr(simd)] +pub struct i16x32([i16; 32]); +#[repr(simd)] +pub struct i32x16([i32; 16]); +#[repr(simd)] +pub struct i64x8([i64; 8]); +#[repr(simd)] +pub struct f16x32([f16; 32]); +#[repr(simd)] +pub struct f32x16([f32; 16]); +#[repr(simd)] +pub struct f64x8([f64; 8]); + +macro_rules! impl_copy { + ($($ty:ident)*) => { + $( + impl Copy for $ty {} + )* + }; +} + +impl_copy!( + i8x16 i16x8 i32x4 i64x2 f16x8 f32x4 f64x2 + i8x32 i16x16 i32x8 i64x4 f16x16 f32x8 f64x4 + i8x64 i16x32 i32x16 i64x8 f16x32 f32x16 f64x8 +); + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// CHECK-LABEL: sym_fn: +// CHECK: #APP +// CHECK: call extern_func +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: sym_static: +// CHECK: #APP +// CHECK: mov al, byte ptr [extern_static] +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!("mov al, byte ptr [{}]", sym extern_static); +} + +macro_rules! check { + ($func:ident $ty:ident $class:ident $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " {}, {}"), lateout($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i16 i16 reg "mov"); + +// CHECK-LABEL: reg_f16: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f16 f16 reg "mov"); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i32 i32 reg "mov"); + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f32 f32 reg "mov"); + +// x86_64-LABEL: reg_i64: +// x86_64: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// x86_64: #NO_APP +#[cfg(x86_64)] +check!(reg_i64 i64 reg "mov"); + +// x86_64-LABEL: reg_f64: +// x86_64: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// x86_64: #NO_APP +#[cfg(x86_64)] +check!(reg_f64 f64 reg "mov"); + +// CHECK-LABEL: reg_ptr: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_ptr ptr reg "mov"); + +// CHECK-LABEL: reg_abcd_i16: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_abcd_i16 i16 reg_abcd "mov"); + +// CHECK-LABEL: reg_abcd_f16: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_abcd_f16 f16 reg_abcd "mov"); + +// CHECK-LABEL: reg_abcd_i32: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_abcd_i32 i32 reg_abcd "mov"); + +// CHECK-LABEL: reg_abcd_f32: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_abcd_f32 f32 reg_abcd "mov"); + +// x86_64-LABEL: reg_abcd_i64: +// x86_64: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// x86_64: #NO_APP +#[cfg(x86_64)] +check!(reg_abcd_i64 i64 reg_abcd "mov"); + +// x86_64-LABEL: reg_abcd_f64: +// x86_64: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// x86_64: #NO_APP +#[cfg(x86_64)] +check!(reg_abcd_f64 f64 reg_abcd "mov"); + +// CHECK-LABEL: reg_abcd_ptr: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_abcd_ptr ptr reg_abcd "mov"); + +// CHECK-LABEL: reg_byte: +// CHECK: #APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_byte i8 reg_byte "mov"); + +// CHECK-LABEL: xmm_reg_f16: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f16 f16 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_i32: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_i32 i32 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_f32: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f32 f32 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_i64: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_i64 i64 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_f64: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f64 f64 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_f128: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f128 f128 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_ptr: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_ptr ptr xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_i8x16: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_i8x16 i8x16 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_i16x8: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_i16x8 i16x8 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_i32x4: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_i32x4 i32x4 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_i64x2: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_i64x2 i64x2 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_f16x8: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f16x8 f16x8 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_f32x4: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f32x4 f32x4 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_f64x2: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f64x2 f64x2 xmm_reg "movaps"); + +// CHECK-LABEL: ymm_reg_f16: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f16 f16 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i32: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i32 i32 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_f32: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f32 f32 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i64: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i64 i64 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_f64: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f64 f64 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_f128: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f128 f128 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_ptr: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_ptr ptr ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i8x16: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i8x16 i8x16 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i16x8: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i16x8 i16x8 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i32x4: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i32x4 i32x4 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i64x2: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i64x2 i64x2 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_f16x8: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f16x8 f16x8 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_f32x4: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f32x4 f32x4 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_f64x2: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f64x2 f64x2 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i8x32: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i8x32 i8x32 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i16x16: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i16x16 i16x16 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i32x8: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i32x8 i32x8 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i64x4: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i64x4 i64x4 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_f16x16: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f16x16 f16x16 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_f32x8: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f32x8 f32x8 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_f64x4: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f64x4 f64x4 ymm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16 f16 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i32: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i32 i32 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f32: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f32 f32 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i64: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i64 i64 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f64: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f64 f64 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f128: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f128 f128 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_ptr: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_ptr ptr zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i8x16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i8x16 i8x16 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i16x8: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i16x8 i16x8 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i32x4: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i32x4 i32x4 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i64x2: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i64x2 i64x2 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f16x8: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16x8 f16x8 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f32x4: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f32x4 f32x4 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f64x2: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f64x2 f64x2 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i8x32: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i8x32 i8x32 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i16x16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i16x16 i16x16 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i32x8: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i32x8 i32x8 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i64x4: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i64x4 i64x4 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f16x16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16x16 f16x16 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f32x8: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f32x8 f32x8 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f64x4: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f64x4 f64x4 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i8x64: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i8x64 i8x64 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i16x32: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i16x32 i16x32 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i32x16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i32x16 i32x16 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i64x8: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i64x8 i64x8 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f16x32: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16x32 f16x32 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f32x16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f32x16 f32x16 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f64x8: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f64x8 f64x8 zmm_reg "vmovaps"); + +// CHECK-LABEL: kreg_i8: +// CHECK: #APP +// CHECK: kmovb k{{[0-9]+}}, k{{[0-9]+}} +// CHECK: #NO_APP +check!(kreg_i8 i8 kreg "kmovb"); + +// CHECK-LABEL: kreg_i16: +// CHECK: #APP +// CHECK: kmovw k{{[0-9]+}}, k{{[0-9]+}} +// CHECK: #NO_APP +check!(kreg_i16 i16 kreg "kmovw"); + +// CHECK-LABEL: kreg_i32: +// CHECK: #APP +// CHECK: kmovd k{{[0-9]+}}, k{{[0-9]+}} +// CHECK: #NO_APP +check!(kreg_i32 i32 kreg "kmovd"); + +// CHECK-LABEL: kreg_i64: +// CHECK: #APP +// CHECK: kmovq k{{[0-9]+}}, k{{[0-9]+}} +// CHECK: #NO_APP +check!(kreg_i64 i64 kreg "kmovq"); + +// CHECK-LABEL: kreg_ptr: +// CHECK: #APP +// CHECK: kmovq k{{[0-9]+}}, k{{[0-9]+}} +// CHECK: #NO_APP +check!(kreg_ptr ptr kreg "kmovq"); + +// CHECK-LABEL: eax_i16: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check_reg!(eax_i16 i16 "eax" "mov"); + +// CHECK-LABEL: eax_f16: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check_reg!(eax_f16 f16 "eax" "mov"); + +// CHECK-LABEL: eax_i32: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check_reg!(eax_i32 i32 "eax" "mov"); + +// CHECK-LABEL: eax_f32: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check_reg!(eax_f32 f32 "eax" "mov"); + +// x86_64-LABEL: eax_i64: +// x86_64: #APP +// x86_64: mov eax, eax +// x86_64: #NO_APP +#[cfg(x86_64)] +check_reg!(eax_i64 i64 "eax" "mov"); + +// x86_64-LABEL: eax_f64: +// x86_64: #APP +// x86_64: mov eax, eax +// x86_64: #NO_APP +#[cfg(x86_64)] +check_reg!(eax_f64 f64 "eax" "mov"); + +// CHECK-LABEL: eax_ptr: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check_reg!(eax_ptr ptr "eax" "mov"); + +// i686-LABEL: ah_byte: +// i686: #APP +// i686: mov ah, ah +// i686: #NO_APP +#[cfg(i686)] +check_reg!(ah_byte i8 "ah" "mov"); + +// CHECK-LABEL: xmm0_f16: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f16 f16 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_i32: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_i32 i32 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_f32: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f32 f32 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_i64: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_i64 i64 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_f64: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f64 f64 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_f128: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f128 f128 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_ptr: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_ptr ptr "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_i8x16: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_i8x16 i8x16 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_i16x8: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_i16x8 i16x8 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_i32x4: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_i32x4 i32x4 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_i64x2: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_i64x2 i64x2 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_f16x8: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f16x8 f16x8 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_f32x4: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f32x4 f32x4 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_f64x2: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f64x2 f64x2 "xmm0" "movaps"); + +// CHECK-LABEL: ymm0_f16: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f16 f16 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i32: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i32 i32 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_f32: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f32 f32 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i64: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i64 i64 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_f64: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f64 f64 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_f128: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f128 f128 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_ptr: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_ptr ptr "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i8x16: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i8x16 i8x16 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i16x8: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i16x8 i16x8 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i32x4: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i32x4 i32x4 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i64x2: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i64x2 i64x2 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_f16x8: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f16x8 f16x8 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_f32x4: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f32x4 f32x4 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_f64x2: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f64x2 f64x2 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i8x32: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i8x32 i8x32 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i16x16: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i16x16 i16x16 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i32x8: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i32x8 i32x8 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i64x4: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i64x4 i64x4 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_f16x16: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f16x16 f16x16 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_f32x8: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f32x8 f32x8 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_f64x4: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f64x4 f64x4 "ymm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16 f16 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i32: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i32 i32 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f32: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f32 f32 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i64: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i64 i64 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f64: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f64 f64 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f128: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f128 f128 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_ptr: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_ptr ptr "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i8x16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i8x16 i8x16 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i16x8: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i16x8 i16x8 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i32x4: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i32x4 i32x4 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i64x2: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i64x2 i64x2 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f16x8: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16x8 f16x8 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f32x4: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f32x4 f32x4 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f64x2: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f64x2 f64x2 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i8x32: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i8x32 i8x32 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i16x16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i16x16 i16x16 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i32x8: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i32x8 i32x8 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i64x4: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i64x4 i64x4 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f16x16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16x16 f16x16 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f32x8: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f32x8 f32x8 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f64x4: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f64x4 f64x4 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i8x64: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i8x64 i8x64 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i16x32: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i16x32 i16x32 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i32x16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i32x16 i32x16 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i64x8: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i64x8 i64x8 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f16x32: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16x32 f16x32 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f32x16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f32x16 f32x16 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f64x8: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f64x8 f64x8 "zmm0" "vmovaps"); + +// CHECK-LABEL: k1_i8: +// CHECK: #APP +// CHECK: kmovb k1, k1 +// CHECK: #NO_APP +check_reg!(k1_i8 i8 "k1" "kmovb"); + +// CHECK-LABEL: k1_i16: +// CHECK: #APP +// CHECK: kmovw k1, k1 +// CHECK: #NO_APP +check_reg!(k1_i16 i16 "k1" "kmovw"); + +// CHECK-LABEL: k1_i32: +// CHECK: #APP +// CHECK: kmovd k1, k1 +// CHECK: #NO_APP +check_reg!(k1_i32 i32 "k1" "kmovd"); + +// CHECK-LABEL: k1_i64: +// CHECK: #APP +// CHECK: kmovq k1, k1 +// CHECK: #NO_APP +check_reg!(k1_i64 i64 "k1" "kmovq"); + +// CHECK-LABEL: k1_ptr: +// CHECK: #APP +// CHECK: kmovq k1, k1 +// CHECK: #NO_APP +check_reg!(k1_ptr ptr "k1" "kmovq"); diff --git a/tests/assembly-llvm/auxiliary/breakpoint-panic-handler.rs b/tests/assembly-llvm/auxiliary/breakpoint-panic-handler.rs new file mode 100644 index 00000000000..d54c1181e1a --- /dev/null +++ b/tests/assembly-llvm/auxiliary/breakpoint-panic-handler.rs @@ -0,0 +1,8 @@ +#![feature(core_intrinsics)] +#![no_std] + +#[panic_handler] +unsafe fn breakpoint_panic_handler(_: &::core::panic::PanicInfo) -> ! { + core::intrinsics::breakpoint(); + core::hint::unreachable_unchecked(); +} diff --git a/tests/assembly-llvm/auxiliary/dwarf-mixed-versions-lto-aux.rs b/tests/assembly-llvm/auxiliary/dwarf-mixed-versions-lto-aux.rs new file mode 100644 index 00000000000..257608f881f --- /dev/null +++ b/tests/assembly-llvm/auxiliary/dwarf-mixed-versions-lto-aux.rs @@ -0,0 +1,5 @@ +//@ compile-flags: -g --crate-type=rlib -Cdwarf-version=4 + +pub fn check_is_even(number: &u64) -> bool { + number % 2 == 0 +} diff --git a/tests/assembly-llvm/auxiliary/non-inline-dependency.rs b/tests/assembly-llvm/auxiliary/non-inline-dependency.rs new file mode 100644 index 00000000000..57f3ee87cdb --- /dev/null +++ b/tests/assembly-llvm/auxiliary/non-inline-dependency.rs @@ -0,0 +1,14 @@ +#![no_std] +#![deny(warnings)] + +#[inline(never)] +#[no_mangle] +pub fn wrapping_external_fn(a: u32) -> u32 { + a.wrapping_mul(a) +} + +#[inline(never)] +#[no_mangle] +pub fn panicking_external_fn(a: u32) -> u32 { + a * a +} diff --git a/tests/assembly-llvm/breakpoint.rs b/tests/assembly-llvm/breakpoint.rs new file mode 100644 index 00000000000..e0cc2d1eebb --- /dev/null +++ b/tests/assembly-llvm/breakpoint.rs @@ -0,0 +1,14 @@ +//@ revisions: aarch64 x86_64 +//@ assembly-output: emit-asm +//@[aarch64] only-aarch64 +//@[x86_64] only-x86_64 + +#![feature(breakpoint)] +#![crate_type = "lib"] + +// CHECK-LABEL: use_bp +// aarch64: brk #0xf000 +// x86_64: int3 +pub fn use_bp() { + core::arch::breakpoint(); +} diff --git a/tests/assembly-llvm/closure-inherit-target-feature.rs b/tests/assembly-llvm/closure-inherit-target-feature.rs new file mode 100644 index 00000000000..069204bbd34 --- /dev/null +++ b/tests/assembly-llvm/closure-inherit-target-feature.rs @@ -0,0 +1,59 @@ +//@ only-x86_64 +//@ ignore-sgx Tests incompatible with LVI mitigations +//@ assembly-output: emit-asm +// make sure the feature is not enabled at compile-time +//@ compile-flags: -C opt-level=3 -C target-feature=-sse4.1 -C llvm-args=-x86-asm-syntax=intel + +#![crate_type = "rlib"] + +use std::arch::x86_64::{__m128, _mm_blend_ps}; + +// Use an explicit return pointer to prevent tail call optimization. +#[no_mangle] +pub unsafe fn sse41_blend_nofeature(x: __m128, y: __m128, ret: *mut __m128) { + let f = { + // check that _mm_blend_ps is not being inlined into the closure + // CHECK-LABEL: {{sse41_blend_nofeature.*closure.*:}} + // CHECK-NOT: blendps + // CHECK: {{call .*_mm_blend_ps.*}} + // CHECK-NOT: blendps + // CHECK: ret + #[inline(never)] + |x, y, ret: *mut __m128| unsafe { *ret = _mm_blend_ps(x, y, 0b0101) } + }; + f(x, y, ret); +} + +#[no_mangle] +#[target_feature(enable = "sse4.1")] +pub fn sse41_blend_noinline(x: __m128, y: __m128) -> __m128 { + let f = { + // check that _mm_blend_ps is being inlined into the closure + // CHECK-LABEL: {{sse41_blend_noinline.*closure.*:}} + // CHECK-NOT: _mm_blend_ps + // CHECK: blendps + // CHECK-NOT: _mm_blend_ps + // CHECK: ret + #[inline(never)] + |x, y| unsafe { _mm_blend_ps(x, y, 0b0101) } + }; + f(x, y) +} + +#[no_mangle] +#[target_feature(enable = "sse4.1")] +pub fn sse41_blend_doinline(x: __m128, y: __m128) -> __m128 { + // check that the closure and _mm_blend_ps are being inlined into the function + // CHECK-LABEL: sse41_blend_doinline: + // CHECK-NOT: {{sse41_blend_doinline.*closure.*}} + // CHECK-NOT: _mm_blend_ps + // CHECK: blendps + // CHECK-NOT: {{sse41_blend_doinline.*closure.*}} + // CHECK-NOT: _mm_blend_ps + // CHECK: ret + let f = { + #[inline] + |x, y| unsafe { _mm_blend_ps(x, y, 0b0101) } + }; + f(x, y) +} diff --git a/tests/assembly-llvm/cmse.rs b/tests/assembly-llvm/cmse.rs new file mode 100644 index 00000000000..a68ee99eac6 --- /dev/null +++ b/tests/assembly-llvm/cmse.rs @@ -0,0 +1,100 @@ +//@ add-core-stubs +//@ revisions: hard soft +//@ assembly-output: emit-asm +//@ [hard] compile-flags: --target thumbv8m.main-none-eabihf --crate-type lib -Copt-level=1 +//@ [soft] compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -Copt-level=1 +//@ [hard] needs-llvm-components: arm +//@ [soft] needs-llvm-components: arm +#![crate_type = "lib"] +#![feature(abi_cmse_nonsecure_call, cmse_nonsecure_entry, no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: __acle_se_entry_point: +// CHECK-NEXT: entry_point: +// +// Write return argument (two registers since 64bit integer) +// CHECK: movs r0, #0 +// CHECK: movs r1, #0 +// +// If we are using hard-float: +// * Check if the float registers were touched (bit 3 in CONTROL) +// hard: mrs [[REG:r[0-9]+]], control +// hard: tst.w [[REG]], #8 +// hard: beq [[LABEL:[\.a-zA-Z0-9_]+]] +// +// * If touched clear all float registers (d0..=d7) +// hard: vmov d0, +// hard: vmov d1, +// hard: vmov d2, +// hard: vmov d3, +// hard: vmov d4, +// hard: vmov d5, +// hard: vmov d6, +// hard: vmov d7, +// +// * If touched clear FPU status register +// hard: vmrs [[REG:r[0-9]+]], fpscr +// hard: bic [[REG]], [[REG]], #159 +// hard: bic [[REG]], [[REG]], #4026531840 +// hard: vmsr fpscr, [[REG]] +// hard: [[LABEL]]: +// +// Clear all other registers that might have been used +// CHECK: mov r2, +// CHECK: mov r3, +// CHECK: mov r12, +// +// Clear the flags +// CHECK: msr apsr_nzcvq, +// +// Branch back to non-secure side +// CHECK: bxns lr +#[no_mangle] +pub extern "cmse-nonsecure-entry" fn entry_point() -> i64 { + 0 +} + +// NOTE for future codegen changes: +// The specific register assignment is not important, however: +// * all registers must be cleared before `blxns` is executed +// (either by writing arguments or any other value) +// * the lowest bit on the address of the callee must be cleared +// * the flags need to be overwritten +// * `blxns` needs to be called with the callee address +// (with the lowest bit cleared) +// +// CHECK-LABEL: call_nonsecure +// Save callee pointer +// CHECK: mov r12, r0 +// +// All arguments are written to (writes r0..=r3) +// CHECK: movs r0, #0 +// CHECK: movs r1, #1 +// CHECK: movs r2, #2 +// CHECK: movs r3, #3 +// +// Lowest bit gets cleared on callee address +// CHECK: bic r12, r12, #1 +// +// Ununsed registers get cleared (r4..=r11) +// CHECK: mov r4, +// CHECK: mov r5, +// CHECK: mov r6, +// CHECK: mov r7, +// CHECK: mov r8, +// CHECK: mov r9, +// CHECK: mov r10, +// CHECK: mov r11, +// +// Flags get cleared +// CHECK: msr apsr_nzcvq, +// +// Call to non-secure +// CHECK: blxns r12 +#[no_mangle] +pub fn call_nonsecure(f: unsafe extern "cmse-nonsecure-call" fn(u32, u32, u32, u32) -> u64) -> u64 { + unsafe { f(0, 1, 2, 3) } +} diff --git a/tests/assembly-llvm/compiletest-self-test/use-minicore-no-run.rs b/tests/assembly-llvm/compiletest-self-test/use-minicore-no-run.rs new file mode 100644 index 00000000000..0e4f05c4b37 --- /dev/null +++ b/tests/assembly-llvm/compiletest-self-test/use-minicore-no-run.rs @@ -0,0 +1,5 @@ +//! `compiletest` self-test to check that `add-core-stubs` is incompatible with run pass modes. + +//@ add-core-stubs +//@ run-pass +//@ should-fail diff --git a/tests/assembly-llvm/cstring-merging.rs b/tests/assembly-llvm/cstring-merging.rs new file mode 100644 index 00000000000..03688e0068b --- /dev/null +++ b/tests/assembly-llvm/cstring-merging.rs @@ -0,0 +1,30 @@ +// MIPS assembler uses the label prefix `$anon.` for local anonymous variables +// other architectures (including ARM and x86-64) use the prefix `.Lanon.` +//@ only-linux +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -Copt-level=3 -Cllvm-args=-enable-global-merge=0 +//@ edition: 2024 + +use std::ffi::CStr; + +// CHECK: .section .rodata.str1.{{[12]}},"aMS" +// CHECK: {{(\.L|\$)}}anon.{{.+}}: +// CHECK-NEXT: .asciz "foo" +#[unsafe(no_mangle)] +static CSTR: &[u8; 4] = b"foo\0"; + +// CHECK-NOT: .section +// CHECK: {{(\.L|\$)}}anon.{{.+}}: +// CHECK-NEXT: .asciz "bar" +#[unsafe(no_mangle)] +pub fn cstr() -> &'static CStr { + c"bar" +} + +// CHECK-NOT: .section +// CHECK: {{(\.L|\$)}}anon.{{.+}}: +// CHECK-NEXT: .asciz "baz" +#[unsafe(no_mangle)] +pub fn manual_cstr() -> &'static str { + "baz\0" +} diff --git a/tests/assembly-llvm/dwarf-mixed-versions-lto.rs b/tests/assembly-llvm/dwarf-mixed-versions-lto.rs new file mode 100644 index 00000000000..9910a6e2f5f --- /dev/null +++ b/tests/assembly-llvm/dwarf-mixed-versions-lto.rs @@ -0,0 +1,20 @@ +// This test ensures that if LTO occurs between crates with different DWARF versions, we +// will choose the highest DWARF version for the final binary. This matches Clang's behavior. +// Note: `.2byte` directive is used on MIPS. + +//@ only-linux +//@ aux-build:dwarf-mixed-versions-lto-aux.rs +//@ compile-flags: -C lto -g -Cdwarf-version=5 +//@ assembly-output: emit-asm +//@ no-prefer-dynamic + +extern crate dwarf_mixed_versions_lto_aux; + +fn main() { + dwarf_mixed_versions_lto_aux::check_is_even(&0); +} + +// CHECK: .section .debug_info +// CHECK-NOT: {{\.(short|hword|2byte)}} 2 +// CHECK-NOT: {{\.(short|hword|2byte)}} 4 +// CHECK: {{\.(short|hword|2byte)}} 5 diff --git a/tests/assembly-llvm/dwarf4.rs b/tests/assembly-llvm/dwarf4.rs new file mode 100644 index 00000000000..03a388603b4 --- /dev/null +++ b/tests/assembly-llvm/dwarf4.rs @@ -0,0 +1,23 @@ +// Makes sure that `-C dwarf-version=4` causes `rustc` to emit DWARF version 4. +//@ assembly-output: emit-asm +//@ add-core-stubs +//@ compile-flags: -g --target x86_64-unknown-linux-gnu -C dwarf-version=4 -Copt-level=0 +//@ needs-llvm-components: x86 + +#![feature(no_core, lang_items)] +#![crate_type = "rlib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +pub fn wibble() {} + +pub struct X; + +// CHECK: .section .debug_info +// CHECK-NOT: .short 2 +// CHECK-NOT: .short 5 +// CHECK: .short 4 +// CHECK-NOT: .section .debug_pubnames +// CHECK-NOT: .section .debug_pubtypes diff --git a/tests/assembly-llvm/dwarf5.rs b/tests/assembly-llvm/dwarf5.rs new file mode 100644 index 00000000000..9bd92cc0d09 --- /dev/null +++ b/tests/assembly-llvm/dwarf5.rs @@ -0,0 +1,20 @@ +// Makes sure that `-C dwarf-version=5` causes `rustc` to emit DWARF version 5. +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: -g --target x86_64-unknown-linux-gnu -C dwarf-version=5 -Copt-level=0 +//@ needs-llvm-components: x86 + +#![feature(no_core, lang_items)] +#![crate_type = "rlib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +pub fn wibble() {} + +// CHECK: .section .debug_info +// CHECK-NOT: .short 2 +// CHECK-NOT: .short 4 +// CHECK: .short 5 +// CHECK: .section .debug_names diff --git a/tests/assembly-llvm/emit-intel-att-syntax.rs b/tests/assembly-llvm/emit-intel-att-syntax.rs new file mode 100644 index 00000000000..7b479a0f79e --- /dev/null +++ b/tests/assembly-llvm/emit-intel-att-syntax.rs @@ -0,0 +1,75 @@ +//@ assembly-output: emit-asm +//@ revisions: att intel +//@ [att] compile-flags: -Cllvm-args=-x86-asm-syntax=att +//@ [intel] compile-flags: -Cllvm-args=-x86-asm-syntax=intel +//@ only-x86_64 + +#![crate_type = "lib"] + +// CHECK-LABEL: naked_att: +// intel-CHECK: mov rax, qword ptr [rdi] +// intel-CHECK: ret +// att-CHECK: movq (%rdi), %rax +// att-CHECK: retq + +#[unsafe(naked)] +#[unsafe(no_mangle)] +extern "sysv64" fn naked_att() { + std::arch::naked_asm!( + " + movq (%rdi), %rax + retq + ", + options(att_syntax), + ); +} + +// CHECK-LABEL: naked_intel: +// intel-CHECK: mov rax, rdi +// intel-CHECK: ret +// att-CHECK: movq (%rdi), %rax +// att-CHECK: retq + +#[unsafe(naked)] +#[unsafe(no_mangle)] +extern "sysv64" fn naked_intel() { + std::arch::naked_asm!( + " + mov rax, rdi + ret + ", + options(), + ); +} + +// CHECK-LABEL: global_att: +// intel-CHECK: mov rax, rdi +// intel-CHECK: ret +// att-CHECK: movq (%rdi), %rax +// att-CHECK: retq + +core::arch::global_asm!( + " + .globl global_att + global_att: + movq (%rdi), %rax + retq + ", + options(att_syntax), +); + +// CHECK-LABEL: global_intel: +// intel-CHECK: mov rax, rdi +// intel-CHECK: ret +// att-CHECK: movq (%rdi), %rax +// att-CHECK: retq + +core::arch::global_asm!( + " + .globl global_intel + global_intel: + mov rax, rdi + ret + ", + options(), +); diff --git a/tests/assembly-llvm/is_aligned.rs b/tests/assembly-llvm/is_aligned.rs new file mode 100644 index 00000000000..ab8f7dea808 --- /dev/null +++ b/tests/assembly-llvm/is_aligned.rs @@ -0,0 +1,55 @@ +//@ assembly-output: emit-asm +//@ only-x86_64 +//@ ignore-sgx +//@ revisions: opt-speed opt-size +//@ [opt-speed] compile-flags: -Copt-level=2 -Cdebug-assertions=no +//@ [opt-size] compile-flags: -Copt-level=s -Cdebug-assertions=no +#![crate_type = "rlib"] +#![feature(core_intrinsics)] +#![feature(pointer_is_aligned_to)] + +// CHECK-LABEL: is_aligned_to_unchecked +// CHECK: decq +// CHECK-NEXT: testq +// CHECK-NEXT: sete +// CHECK: retq +#[no_mangle] +pub unsafe fn is_aligned_to_unchecked(ptr: *const u8, align: usize) -> bool { + unsafe { std::intrinsics::assume(align.is_power_of_two()) } + ptr.is_aligned_to(align) +} + +// CHECK-LABEL: is_aligned_1 +// CHECK: movb $1 +// CHECK: retq +#[no_mangle] +pub fn is_aligned_1(ptr: *const u8) -> bool { + ptr.is_aligned() +} + +// CHECK-LABEL: is_aligned_2 +// CHECK: testb $1 +// CHECK-NEXT: sete +// CHECK: retq +#[no_mangle] +pub fn is_aligned_2(ptr: *const u16) -> bool { + ptr.is_aligned() +} + +// CHECK-LABEL: is_aligned_4 +// CHECK: testb $3 +// CHECK-NEXT: sete +// CHECK: retq +#[no_mangle] +pub fn is_aligned_4(ptr: *const u32) -> bool { + ptr.is_aligned() +} + +// CHECK-LABEL: is_aligned_8 +// CHECK: testb $7 +// CHECK-NEXT: sete +// CHECK: retq +#[no_mangle] +pub fn is_aligned_8(ptr: *const u64) -> bool { + ptr.is_aligned() +} diff --git a/tests/assembly-llvm/issue-83585-small-pod-struct-equality.rs b/tests/assembly-llvm/issue-83585-small-pod-struct-equality.rs new file mode 100644 index 00000000000..14bec1337f0 --- /dev/null +++ b/tests/assembly-llvm/issue-83585-small-pod-struct-equality.rs @@ -0,0 +1,27 @@ +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 + +#![crate_type = "lib"] + +type T = u8; +type T1 = (T, T, T, T, T, T, T, T); + +// CHECK-LABEL: foo1a +// CHECK: cmpq +// CHECK-NEXT: sete +// CHECK-NEXT: {{retq|popq}} +#[no_mangle] +pub fn foo1a(a: T1, b: T1) -> bool { + a == b +} + +// CHECK-LABEL: foo1b +// CHECK: movq +// CHECK: cmpq +// CHECK-NEXT: sete +// CHECK-NEXT: {{retq|popq}} +#[no_mangle] +pub fn foo1b(a: &T1, b: &T1) -> bool { + a == b +} diff --git a/tests/assembly-llvm/libs/issue-115339-zip-arrays.rs b/tests/assembly-llvm/libs/issue-115339-zip-arrays.rs new file mode 100644 index 00000000000..098382502e8 --- /dev/null +++ b/tests/assembly-llvm/libs/issue-115339-zip-arrays.rs @@ -0,0 +1,25 @@ +//@ assembly-output: emit-asm +// # zen3 previously exhibited odd vectorization +//@ compile-flags: --crate-type=lib -Ctarget-cpu=znver3 -Copt-level=3 +//@ only-x86_64 +//@ ignore-sgx + +use std::iter; + +// previously this produced a long chain of +// 56: vpextrb $6, %xmm0, %ecx +// 57: orb %cl, 22(%rsi) +// 58: vpextrb $7, %xmm0, %ecx +// 59: orb %cl, 23(%rsi) +// [...] + +// CHECK-LABEL: zip_arrays: +#[no_mangle] +pub fn zip_arrays(mut a: [u8; 32], b: [u8; 32]) -> [u8; 32] { + // CHECK-NOT: vpextrb + // CHECK-NOT: orb %cl + // CHECK: vorps + iter::zip(&mut a, b).for_each(|(a, b)| *a |= b); + // CHECK: retq + a +} diff --git a/tests/assembly-llvm/libs/issue-140207-slice-min-simd.rs b/tests/assembly-llvm/libs/issue-140207-slice-min-simd.rs new file mode 100644 index 00000000000..86f067cac08 --- /dev/null +++ b/tests/assembly-llvm/libs/issue-140207-slice-min-simd.rs @@ -0,0 +1,13 @@ +//@ assembly-output: emit-asm +// # avx has a dedicated instruction for this +//@ compile-flags: --crate-type=lib -Ctarget-cpu=znver2 -Copt-level=3 +//@ only-x86_64 +//@ ignore-sgx +// https://github.com/rust-lang/rust/issues/140207 + +#[unsafe(no_mangle)] +pub fn array_min(a: &[u16; 8]) -> u16 { + // CHECK: vphminposuw + // CHECK: ret + a.iter().copied().min().unwrap() +} diff --git a/tests/assembly-llvm/manual-eq-efficient.rs b/tests/assembly-llvm/manual-eq-efficient.rs new file mode 100644 index 00000000000..8dafed354be --- /dev/null +++ b/tests/assembly-llvm/manual-eq-efficient.rs @@ -0,0 +1,22 @@ +// Regression test for #106269 +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -Copt-level=3 -C llvm-args=-x86-asm-syntax=intel +//@ only-x86_64 +//@ ignore-sgx + +pub struct S { + a: u8, + b: u8, + c: u8, + d: u8, +} + +// CHECK-LABEL: manual_eq: +#[no_mangle] +pub fn manual_eq(s1: &S, s2: &S) -> bool { + // CHECK: mov [[REG:[a-z0-9]+]], dword ptr [{{[a-z0-9]+}}] + // CHECK-NEXT: cmp [[REG]], dword ptr [{{[a-z0-9]+}}] + // CHECK-NEXT: sete al + // CHECK: ret + s1.a == s2.a && s1.b == s2.b && s1.c == s2.c && s1.d == s2.d +} diff --git a/tests/assembly-llvm/naked-functions/aarch64-naked-fn-no-bti-prolog.rs b/tests/assembly-llvm/naked-functions/aarch64-naked-fn-no-bti-prolog.rs new file mode 100644 index 00000000000..860ecc3cfcd --- /dev/null +++ b/tests/assembly-llvm/naked-functions/aarch64-naked-fn-no-bti-prolog.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -C no-prepopulate-passes -Zbranch-protection=bti +//@ assembly-output: emit-asm +//@ needs-asm-support +//@ only-aarch64 + +#![crate_type = "lib"] + +use std::arch::naked_asm; + +// The problem at hand: Rust has adopted a fairly strict meaning for "naked functions", +// meaning "no prologue whatsoever, no, really, not one instruction." +// Unfortunately, aarch64's "branch target identification" works via hints at landing sites. +// LLVM implements this via making sure of that, even for functions with the naked attribute. +// So, we must emit an appropriate instruction instead! +#[no_mangle] +#[unsafe(naked)] +pub extern "C" fn _hlt() -> ! { + // CHECK-NOT: hint #34 + // CHECK: hlt #0x1 + naked_asm!("hlt #1") +} diff --git a/tests/assembly-llvm/naked-functions/aix.rs b/tests/assembly-llvm/naked-functions/aix.rs new file mode 100644 index 00000000000..57ff0e183be --- /dev/null +++ b/tests/assembly-llvm/naked-functions/aix.rs @@ -0,0 +1,35 @@ +//@ revisions: elfv1-be aix +//@ add-core-stubs +//@ assembly-output: emit-asm +// +//@[elfv1-be] compile-flags: --target powerpc64-unknown-linux-gnu +//@[elfv1-be] needs-llvm-components: powerpc +// +//@[aix] compile-flags: --target powerpc64-ibm-aix +//@[aix] needs-llvm-components: powerpc + +#![crate_type = "lib"] +#![feature(no_core, asm_experimental_arch, f128, linkage, fn_align)] +#![no_core] + +// tests that naked functions work for the `powerpc64-ibm-aix` target. +// +// This target is special because it uses the XCOFF binary format +// It is tested alongside an elf powerpc target to pin down commonalities and differences. +// +// https://doc.rust-lang.org/rustc/platform-support/aix.html +// https://www.ibm.com/docs/en/aix/7.2?topic=formats-xcoff-object-file-format + +extern crate minicore; +use minicore::*; + +// elfv1-be: .p2align 2 +// aix: .align 2 +// CHECK: .globl blr +// CHECK-LABEL: blr: +// CHECK: blr +#[no_mangle] +#[unsafe(naked)] +extern "C" fn blr() { + naked_asm!("blr") +} diff --git a/tests/assembly-llvm/naked-functions/wasm32.rs b/tests/assembly-llvm/naked-functions/wasm32.rs new file mode 100644 index 00000000000..77547e82041 --- /dev/null +++ b/tests/assembly-llvm/naked-functions/wasm32.rs @@ -0,0 +1,200 @@ +//@ revisions: wasm32-unknown wasm64-unknown wasm32-wasip1 +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ [wasm32-unknown] compile-flags: --target wasm32-unknown-unknown +//@ [wasm64-unknown] compile-flags: --target wasm64-unknown-unknown +//@ [wasm32-wasip1] compile-flags: --target wasm32-wasip1 +//@ [wasm32-unknown] needs-llvm-components: webassembly +//@ [wasm64-unknown] needs-llvm-components: webassembly +//@ [wasm32-wasip1] needs-llvm-components: webassembly + +#![crate_type = "lib"] +#![feature(no_core, asm_experimental_arch, f128, linkage, fn_align)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK: .section .text.nop,"",@ +// CHECK: .globl nop +// CHECK-LABEL: nop: +// CHECK: .functype nop () -> () +// CHECK-NOT: .size +// CHECK: end_function +#[no_mangle] +#[unsafe(naked)] +extern "C" fn nop() { + naked_asm!("nop") +} + +// CHECK: .section .text.weak_nop,"",@ +// CHECK: .weak weak_nop +// CHECK-LABEL: nop: +// CHECK: .functype weak_nop () -> () +// CHECK-NOT: .size +// CHECK: end_function +#[no_mangle] +#[unsafe(naked)] +#[linkage = "weak"] +extern "C" fn weak_nop() { + naked_asm!("nop") +} + +// CHECK-LABEL: fn_i8_i8: +// CHECK-NEXT: .functype fn_i8_i8 (i32) -> (i32) +// +// CHECK-NEXT: local.get 0 +// CHECK-NEXT: local.get 0 +// CHECK-NEXT: i32.mul +// +// CHECK-NEXT: end_function +#[no_mangle] +#[unsafe(naked)] +extern "C" fn fn_i8_i8(num: i8) -> i8 { + naked_asm!("local.get 0", "local.get 0", "i32.mul") +} + +// CHECK-LABEL: fn_i8_i8_i8: +// CHECK: .functype fn_i8_i8_i8 (i32, i32) -> (i32) +#[no_mangle] +#[unsafe(naked)] +extern "C" fn fn_i8_i8_i8(a: i8, b: i8) -> i8 { + naked_asm!("local.get 1", "local.get 0", "i32.mul") +} + +// CHECK-LABEL: fn_unit_i8: +// CHECK: .functype fn_unit_i8 () -> (i32) +#[no_mangle] +#[unsafe(naked)] +extern "C" fn fn_unit_i8() -> i8 { + naked_asm!("i32.const 42") +} + +// CHECK-LABEL: fn_i8_unit: +// CHECK: .functype fn_i8_unit (i32) -> () +#[no_mangle] +#[unsafe(naked)] +extern "C" fn fn_i8_unit(_: i8) { + naked_asm!("nop") +} + +// CHECK-LABEL: fn_i32_i32: +// CHECK: .functype fn_i32_i32 (i32) -> (i32) +#[no_mangle] +#[unsafe(naked)] +extern "C" fn fn_i32_i32(num: i32) -> i32 { + naked_asm!("local.get 0", "local.get 0", "i32.mul") +} + +// CHECK-LABEL: fn_i64_i64: +// CHECK: .functype fn_i64_i64 (i64) -> (i64) +#[no_mangle] +#[unsafe(naked)] +extern "C" fn fn_i64_i64(num: i64) -> i64 { + naked_asm!("local.get 0", "local.get 0", "i64.mul") +} + +// CHECK-LABEL: fn_i128_i128: +// wasm32-unknown: .functype fn_i128_i128 (i32, i64, i64) -> () +// wasm32-wasip1: .functype fn_i128_i128 (i32, i64, i64) -> () +// wasm64-unknown: .functype fn_i128_i128 (i64, i64, i64) -> () +#[allow(improper_ctypes_definitions)] +#[no_mangle] +#[unsafe(naked)] +extern "C" fn fn_i128_i128(num: i128) -> i128 { + naked_asm!( + "local.get 0", + "local.get 2", + "i64.store 8", + "local.get 0", + "local.get 1", + "i64.store 0", + ) +} + +// CHECK-LABEL: fn_f128_f128: +// wasm32-unknown: .functype fn_f128_f128 (i32, i64, i64) -> () +// wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> () +// wasm64-unknown: .functype fn_f128_f128 (i64, i64, i64) -> () +#[no_mangle] +#[unsafe(naked)] +extern "C" fn fn_f128_f128(num: f128) -> f128 { + naked_asm!( + "local.get 0", + "local.get 2", + "i64.store 8", + "local.get 0", + "local.get 1", + "i64.store 0", + ) +} + +#[repr(C)] +struct Compound { + a: u16, + b: i64, +} + +// CHECK-LABEL: fn_compound_compound: +// wasm32-unknown: .functype fn_compound_compound (i32, i32) -> () +// wasm32-wasip1: .functype fn_compound_compound (i32, i32) -> () +// wasm64-unknown: .functype fn_compound_compound (i64, i64) -> () +#[no_mangle] +#[unsafe(naked)] +extern "C" fn fn_compound_compound(_: Compound) -> Compound { + // this is the wasm32-wasip1 assembly + naked_asm!( + "local.get 0", + "local.get 1", + "i64.load 8", + "i64.store 8", + "local.get 0", + "local.get 1", + "i32.load16_u 0", + "i32.store16 0", + ) +} + +#[repr(C)] +struct WrapperI32(i32); + +// CHECK-LABEL: fn_wrapperi32_wrapperi32: +// CHECK: .functype fn_wrapperi32_wrapperi32 (i32) -> (i32) +#[no_mangle] +#[unsafe(naked)] +extern "C" fn fn_wrapperi32_wrapperi32(_: WrapperI32) -> WrapperI32 { + naked_asm!("local.get 0") +} + +#[repr(C)] +struct WrapperI64(i64); + +// CHECK-LABEL: fn_wrapperi64_wrapperi64: +// CHECK: .functype fn_wrapperi64_wrapperi64 (i64) -> (i64) +#[no_mangle] +#[unsafe(naked)] +extern "C" fn fn_wrapperi64_wrapperi64(_: WrapperI64) -> WrapperI64 { + naked_asm!("local.get 0") +} + +#[repr(C)] +struct WrapperF32(f32); + +// CHECK-LABEL: fn_wrapperf32_wrapperf32: +// CHECK: .functype fn_wrapperf32_wrapperf32 (f32) -> (f32) +#[no_mangle] +#[unsafe(naked)] +extern "C" fn fn_wrapperf32_wrapperf32(_: WrapperF32) -> WrapperF32 { + naked_asm!("local.get 0") +} + +#[repr(C)] +struct WrapperF64(f64); + +// CHECK-LABEL: fn_wrapperf64_wrapperf64: +// CHECK: .functype fn_wrapperf64_wrapperf64 (f64) -> (f64) +#[no_mangle] +#[unsafe(naked)] +extern "C" fn fn_wrapperf64_wrapperf64(_: WrapperF64) -> WrapperF64 { + naked_asm!("local.get 0") +} diff --git a/tests/assembly-llvm/naked-functions/x86_64-naked-fn-no-cet-prolog.rs b/tests/assembly-llvm/naked-functions/x86_64-naked-fn-no-cet-prolog.rs new file mode 100644 index 00000000000..81ee9b13b4e --- /dev/null +++ b/tests/assembly-llvm/naked-functions/x86_64-naked-fn-no-cet-prolog.rs @@ -0,0 +1,24 @@ +//@ compile-flags: -C no-prepopulate-passes -Zcf-protection=full +//@ assembly-output: emit-asm +//@ needs-asm-support +//@ only-x86_64 + +#![crate_type = "lib"] + +use std::arch::naked_asm; + +// The problem at hand: Rust has adopted a fairly strict meaning for "naked functions", +// meaning "no prologue whatsoever, no, really, not one instruction." +// Unfortunately, x86's control-flow enforcement, specifically indirect branch protection, +// works by using an instruction for each possible landing site, +// and LLVM implements this via making sure of that. +#[no_mangle] +#[unsafe(naked)] +pub extern "sysv64" fn will_halt() -> ! { + // CHECK-NOT: endbr{{32|64}} + // CHECK: hlt + naked_asm!("hlt") +} + +// what about aarch64? +// "branch-protection"=false diff --git a/tests/assembly-llvm/niche-prefer-zero.rs b/tests/assembly-llvm/niche-prefer-zero.rs new file mode 100644 index 00000000000..4e260ebc09b --- /dev/null +++ b/tests/assembly-llvm/niche-prefer-zero.rs @@ -0,0 +1,25 @@ +// Check that niche selection prefers zero and that jumps are optimized away. +// See https://github.com/rust-lang/rust/pull/87794 +//@ assembly-output: emit-asm +//@ only-x86 +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[repr(u8)] +pub enum Size { + One = 1, + Two = 2, + Three = 3, +} + +#[no_mangle] +pub fn handle(x: Option) -> u8 { + match x { + None => 0, + Some(size) => size as u8, + } +} + +// There should be no jumps in output +// CHECK-NOT: j diff --git a/tests/assembly-llvm/nvptx-arch-default.rs b/tests/assembly-llvm/nvptx-arch-default.rs new file mode 100644 index 00000000000..a621fd6dcb2 --- /dev/null +++ b/tests/assembly-llvm/nvptx-arch-default.rs @@ -0,0 +1,12 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type cdylib -Z unstable-options -Clinker-flavor=llbc +//@ only-nvptx64 + +#![no_std] + +//@ aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +// Verify default target arch with ptx-linker. +// CHECK: .target sm_30 +// CHECK: .address_size 64 diff --git a/tests/assembly-llvm/nvptx-arch-emit-asm.rs b/tests/assembly-llvm/nvptx-arch-emit-asm.rs new file mode 100644 index 00000000000..e47f8e78e36 --- /dev/null +++ b/tests/assembly-llvm/nvptx-arch-emit-asm.rs @@ -0,0 +1,9 @@ +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type rlib +//@ only-nvptx64 + +#![no_std] + +// Verify default arch without ptx-linker involved. +// CHECK: .target sm_30 +// CHECK: .address_size 64 diff --git a/tests/assembly-llvm/nvptx-arch-link-arg.rs b/tests/assembly-llvm/nvptx-arch-link-arg.rs new file mode 100644 index 00000000000..3432e6161bf --- /dev/null +++ b/tests/assembly-llvm/nvptx-arch-link-arg.rs @@ -0,0 +1,13 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type cdylib -C link-arg=--arch=sm_60 +//@ only-nvptx64 +//@ ignore-nvptx64 + +#![no_std] + +//@ aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +// Verify target arch override via `link-arg`. +// CHECK: .target sm_60 +// CHECK: .address_size 64 diff --git a/tests/assembly-llvm/nvptx-arch-target-cpu.rs b/tests/assembly-llvm/nvptx-arch-target-cpu.rs new file mode 100644 index 00000000000..609ab297e63 --- /dev/null +++ b/tests/assembly-llvm/nvptx-arch-target-cpu.rs @@ -0,0 +1,12 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type cdylib -C target-cpu=sm_50 -Z unstable-options -Clinker-flavor=llbc +//@ only-nvptx64 + +#![no_std] + +//@ aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +// Verify target arch override via `target-cpu`. +// CHECK: .target sm_50 +// CHECK: .address_size 64 diff --git a/tests/assembly-llvm/nvptx-atomics.rs b/tests/assembly-llvm/nvptx-atomics.rs new file mode 100644 index 00000000000..52b8c86d8a9 --- /dev/null +++ b/tests/assembly-llvm/nvptx-atomics.rs @@ -0,0 +1,86 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type cdylib +//@ only-nvptx64 +//@ ignore-nvptx64 + +#![feature(abi_ptx, core_intrinsics)] +#![no_std] + +use core::intrinsics::*; + +//@ aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +// Currently, LLVM NVPTX backend can only emit atomic instructions with +// `relaxed` (PTX default) ordering. But it's also useful to make sure +// the backend won't fail with other orders. Apparently, the backend +// doesn't support fences as well. As a workaround `llvm.nvvm.membar.*` +// could work, and perhaps on the long run, all the atomic operations +// should rather be provided by `core::arch::nvptx`. + +// Also, PTX ISA doesn't have atomic `load`, `store` and `nand`. + +// FIXME(denzp): add tests for `core::sync::atomic::*`. + +#[no_mangle] +pub unsafe extern "ptx-kernel" fn atomics_kernel(a: *mut u32) { + // CHECK: atom.global.and.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.and.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_and(a, 1); + atomic_and_relaxed(a, 1); + + // CHECK: atom.global.cas.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1, 2; + // CHECK: atom.global.cas.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1, 2; + atomic_cxchg(a, 1, 2); + atomic_cxchg_relaxed(a, 1, 2); + + // CHECK: atom.global.max.s32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.max.s32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_max(a, 1); + atomic_max_relaxed(a, 1); + + // CHECK: atom.global.min.s32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.min.s32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_min(a, 1); + atomic_min_relaxed(a, 1); + + // CHECK: atom.global.or.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.or.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_or(a, 1); + atomic_or_relaxed(a, 1); + + // CHECK: atom.global.max.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.max.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_umax(a, 1); + atomic_umax_relaxed(a, 1); + + // CHECK: atom.global.min.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.min.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_umin(a, 1); + atomic_umin_relaxed(a, 1); + + // CHECK: atom.global.add.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.add.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_xadd(a, 1); + atomic_xadd_relaxed(a, 1); + + // CHECK: atom.global.exch.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.exch.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_xchg(a, 1); + atomic_xchg_relaxed(a, 1); + + // CHECK: atom.global.xor.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.xor.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_xor(a, 1); + atomic_xor_relaxed(a, 1); + + // CHECK: mov.u32 %[[sub_0_arg:r[0-9]+]], 100; + // CHECK: neg.s32 temp, %[[sub_0_arg]]; + // CHECK: atom.global.add.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], temp; + atomic_xsub(a, 100); + + // CHECK: mov.u32 %[[sub_1_arg:r[0-9]+]], 200; + // CHECK: neg.s32 temp, %[[sub_1_arg]]; + // CHECK: atom.global.add.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], temp; + atomic_xsub_relaxed(a, 200); +} diff --git a/tests/assembly-llvm/nvptx-c-abi-arg-v7.rs b/tests/assembly-llvm/nvptx-c-abi-arg-v7.rs new file mode 100644 index 00000000000..be98b167470 --- /dev/null +++ b/tests/assembly-llvm/nvptx-c-abi-arg-v7.rs @@ -0,0 +1,220 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86 -Z unstable-options -Clinker-flavor=llbc +//@ only-nvptx64 + +// The PTX ABI stability is tied to major versions of the PTX ISA +// These tests assume major version 7 + +// CHECK: .version 7 + +#![feature(abi_ptx, lang_items, no_core)] +#![no_core] + +#[lang = "pointee_sized"] +trait PointeeSized {} +#[lang = "meta_sized"] +trait MetaSized: PointeeSized {} +#[lang = "sized"] +trait Sized: MetaSized {} +#[lang = "copy"] +trait Copy {} + +#[repr(C)] +pub struct SingleU8 { + f: u8, +} + +#[repr(C)] +pub struct DoubleU8 { + f: u8, + g: u8, +} + +#[repr(C)] +pub struct TripleU8 { + f: u8, + g: u8, + h: u8, +} + +#[repr(C)] +pub struct TripleU16 { + f: u16, + g: u16, + h: u16, +} +#[repr(C)] +pub struct DoubleI32 { + f: i32, + g: i32, +} +#[repr(C)] +pub struct TripleU32 { + f: u32, + g: u32, + h: u32, +} +#[repr(C)] +pub struct TripleU64 { + f: u64, + g: u64, + h: u64, +} + +#[repr(C)] +pub struct DoubleFloat { + f: f32, + g: f32, +} + +#[repr(C)] +pub struct TripleFloat { + f: f32, + g: f32, + h: f32, +} + +#[repr(C)] +pub struct TripleDouble { + f: f64, + g: f64, + h: f64, +} + +#[repr(C)] +pub struct ManyIntegers { + f: u8, + g: u16, + h: u32, + i: u64, +} + +#[repr(C)] +pub struct ManyNumerics { + f: u8, + g: u16, + h: u32, + i: u64, + j: f32, + k: f64, +} + +// CHECK: .visible .func f_u8_arg( +// CHECK: .param .b32 f_u8_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_u8_arg(_a: u8) {} + +// CHECK: .visible .func f_u16_arg( +// CHECK: .param .b32 f_u16_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_u16_arg(_a: u16) {} + +// CHECK: .visible .func f_u32_arg( +// CHECK: .param .b32 f_u32_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_u32_arg(_a: u32) {} + +// CHECK: .visible .func f_u64_arg( +// CHECK: .param .b64 f_u64_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_u64_arg(_a: u64) {} + +// CHECK: .visible .func f_u128_arg( +// CHECK: .param .align 16 .b8 f_u128_arg_param_0[16] +#[no_mangle] +pub unsafe extern "C" fn f_u128_arg(_a: u128) {} + +// CHECK: .visible .func f_i8_arg( +// CHECK: .param .b32 f_i8_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_i8_arg(_a: i8) {} + +// CHECK: .visible .func f_i16_arg( +// CHECK: .param .b32 f_i16_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_i16_arg(_a: i16) {} + +// CHECK: .visible .func f_i32_arg( +// CHECK: .param .b32 f_i32_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_i32_arg(_a: i32) {} + +// CHECK: .visible .func f_i64_arg( +// CHECK: .param .b64 f_i64_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_i64_arg(_a: i64) {} + +// CHECK: .visible .func f_i128_arg( +// CHECK: .param .align 16 .b8 f_i128_arg_param_0[16] +#[no_mangle] +pub unsafe extern "C" fn f_i128_arg(_a: i128) {} + +// CHECK: .visible .func f_f32_arg( +// CHECK: .param .b32 f_f32_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_f32_arg(_a: f32) {} + +// CHECK: .visible .func f_f64_arg( +// CHECK: .param .b64 f_f64_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_f64_arg(_a: f64) {} + +// CHECK: .visible .func f_single_u8_arg( +// CHECK: .param .align 1 .b8 f_single_u8_arg_param_0[1] +#[no_mangle] +pub unsafe extern "C" fn f_single_u8_arg(_a: SingleU8) {} + +// CHECK: .visible .func f_double_u8_arg( +// CHECK: .param .align 1 .b8 f_double_u8_arg_param_0[2] +#[no_mangle] +pub unsafe extern "C" fn f_double_u8_arg(_a: DoubleU8) {} + +// CHECK: .visible .func f_triple_u8_arg( +// CHECK: .param .align 1 .b8 f_triple_u8_arg_param_0[3] +#[no_mangle] +pub unsafe extern "C" fn f_triple_u8_arg(_a: TripleU8) {} + +// CHECK: .visible .func f_triple_u16_arg( +// CHECK: .param .align 2 .b8 f_triple_u16_arg_param_0[6] +#[no_mangle] +pub unsafe extern "C" fn f_triple_u16_arg(_a: TripleU16) {} + +// CHECK: .visible .func f_triple_u32_arg( +// CHECK: .param .align 4 .b8 f_triple_u32_arg_param_0[12] +#[no_mangle] +pub unsafe extern "C" fn f_triple_u32_arg(_a: TripleU32) {} + +// CHECK: .visible .func f_double_i32_arg( +// CHECK: .param .align 4 .b8 f_double_i32_arg_param_0[8] +#[no_mangle] +pub unsafe extern "C" fn f_double_i32_arg(_a: DoubleI32) {} + +// CHECK: .visible .func f_triple_u64_arg( +// CHECK: .param .align 8 .b8 f_triple_u64_arg_param_0[24] +#[no_mangle] +pub unsafe extern "C" fn f_triple_u64_arg(_a: TripleU64) {} + +// CHECK: .visible .func f_many_integers_arg( +// CHECK: .param .align 8 .b8 f_many_integers_arg_param_0[16] +#[no_mangle] +pub unsafe extern "C" fn f_many_integers_arg(_a: ManyIntegers) {} + +// CHECK: .visible .func f_double_float_arg( +// CHECK: .param .align 4 .b8 f_double_float_arg_param_0[8] +#[no_mangle] +pub unsafe extern "C" fn f_double_float_arg(_a: DoubleFloat) {} + +// CHECK: .visible .func f_triple_float_arg( +// CHECK: .param .align 4 .b8 f_triple_float_arg_param_0[12] +#[no_mangle] +pub unsafe extern "C" fn f_triple_float_arg(_a: TripleFloat) {} + +// CHECK: .visible .func f_triple_double_arg( +// CHECK: .param .align 8 .b8 f_triple_double_arg_param_0[24] +#[no_mangle] +pub unsafe extern "C" fn f_triple_double_arg(_a: TripleDouble) {} + +// CHECK: .visible .func f_many_numerics_arg( +// CHECK: .param .align 8 .b8 f_many_numerics_arg_param_0[32] +#[no_mangle] +pub unsafe extern "C" fn f_many_numerics_arg(_a: ManyNumerics) {} diff --git a/tests/assembly-llvm/nvptx-c-abi-ret-v7.rs b/tests/assembly-llvm/nvptx-c-abi-ret-v7.rs new file mode 100644 index 00000000000..c68c71c872c --- /dev/null +++ b/tests/assembly-llvm/nvptx-c-abi-ret-v7.rs @@ -0,0 +1,244 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86 -Z unstable-options -Clinker-flavor=llbc +//@ only-nvptx64 + +// The PTX ABI stability is tied to major versions of the PTX ISA +// These tests assume major version 7 + +// CHECK: .version 7 + +#![feature(abi_ptx, lang_items, no_core)] +#![no_core] + +#[lang = "pointee_sized"] +trait PointeeSized {} +#[lang = "meta_sized"] +trait MetaSized: PointeeSized {} +#[lang = "sized"] +trait Sized: MetaSized {} +#[lang = "copy"] +trait Copy {} + +#[repr(C)] +pub struct SingleU8 { + f: u8, +} + +#[repr(C)] +pub struct DoubleU8 { + f: u8, + g: u8, +} + +#[repr(C)] +pub struct TripleU8 { + f: u8, + g: u8, + h: u8, +} + +#[repr(C)] +pub struct TripleU16 { + f: u16, + g: u16, + h: u16, +} +#[repr(C)] +pub struct DoubleI32 { + f: i32, + g: i32, +} +#[repr(C)] +pub struct TripleU32 { + f: u32, + g: u32, + h: u32, +} +#[repr(C)] +pub struct TripleU64 { + f: u64, + g: u64, + h: u64, +} + +#[repr(C)] +pub struct DoubleFloat { + f: f32, + g: f32, +} + +#[repr(C)] +pub struct TripleFloat { + f: f32, + g: f32, + h: f32, +} + +#[repr(C)] +pub struct TripleDouble { + f: f64, + g: f64, + h: f64, +} + +#[repr(C)] +pub struct ManyIntegers { + f: u8, + g: u16, + h: u32, + i: u64, +} + +#[repr(C)] +pub struct ManyNumerics { + f: u8, + g: u16, + h: u32, + i: u64, + j: f32, + k: f64, +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_u8_ret( +#[no_mangle] +pub unsafe extern "C" fn f_u8_ret() -> u8 { + 0 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_u16_ret( +#[no_mangle] +pub unsafe extern "C" fn f_u16_ret() -> u16 { + 1 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_u32_ret( +#[no_mangle] +pub unsafe extern "C" fn f_u32_ret() -> u32 { + 2 +} + +// CHECK: .visible .func (.param .b64 func_retval0) f_u64_ret( +#[no_mangle] +pub unsafe extern "C" fn f_u64_ret() -> u64 { + 3 +} + +// CHECK: .visible .func (.param .align 16 .b8 func_retval0[16]) f_u128_ret( +#[no_mangle] +pub unsafe extern "C" fn f_u128_ret() -> u128 { + 4 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_i8_ret( +#[no_mangle] +pub unsafe extern "C" fn f_i8_ret() -> i8 { + 5 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_i16_ret( +#[no_mangle] +pub unsafe extern "C" fn f_i16_ret() -> i16 { + 6 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_i32_ret( +#[no_mangle] +pub unsafe extern "C" fn f_i32_ret() -> i32 { + 7 +} + +// CHECK: .visible .func (.param .b64 func_retval0) f_i64_ret( +#[no_mangle] +pub unsafe extern "C" fn f_i64_ret() -> i64 { + 8 +} + +// CHECK: .visible .func (.param .align 16 .b8 func_retval0[16]) f_i128_ret( +#[no_mangle] +pub unsafe extern "C" fn f_i128_ret() -> i128 { + 9 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_f32_ret( +#[no_mangle] +pub unsafe extern "C" fn f_f32_ret() -> f32 { + 10.0 +} + +// CHECK: .visible .func (.param .b64 func_retval0) f_f64_ret( +#[no_mangle] +pub unsafe extern "C" fn f_f64_ret() -> f64 { + 11.0 +} + +// CHECK: .visible .func (.param .align 1 .b8 func_retval0[1]) f_single_u8_ret( +#[no_mangle] +pub unsafe extern "C" fn f_single_u8_ret() -> SingleU8 { + SingleU8 { f: 12 } +} + +// CHECK: .visible .func (.param .align 1 .b8 func_retval0[2]) f_double_u8_ret( +#[no_mangle] +pub unsafe extern "C" fn f_double_u8_ret() -> DoubleU8 { + DoubleU8 { f: 13, g: 14 } +} + +// CHECK: .visible .func (.param .align 1 .b8 func_retval0[3]) f_triple_u8_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_u8_ret() -> TripleU8 { + TripleU8 { f: 15, g: 16, h: 17 } +} + +// CHECK: .visible .func (.param .align 2 .b8 func_retval0[6]) f_triple_u16_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_u16_ret() -> TripleU16 { + TripleU16 { f: 18, g: 19, h: 20 } +} + +// CHECK: .visible .func (.param .align 4 .b8 func_retval0[8]) f_double_i32_ret( +#[no_mangle] +pub unsafe extern "C" fn f_double_i32_ret() -> DoubleI32 { + DoubleI32 { f: 1, g: 2 } +} + +// CHECK: .visible .func (.param .align 4 .b8 func_retval0[12]) f_triple_u32_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_u32_ret() -> TripleU32 { + TripleU32 { f: 20, g: 21, h: 22 } +} + +// CHECK: .visible .func (.param .align 8 .b8 func_retval0[24]) f_triple_u64_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_u64_ret() -> TripleU64 { + TripleU64 { f: 23, g: 24, h: 25 } +} + +// CHECK: .visible .func (.param .align 8 .b8 func_retval0[16]) f_many_integers_ret( +#[no_mangle] +pub unsafe extern "C" fn f_many_integers_ret() -> ManyIntegers { + ManyIntegers { f: 26, g: 27, h: 28, i: 29 } +} + +// CHECK: .visible .func (.param .align 4 .b8 func_retval0[8]) f_double_float_ret( +#[no_mangle] +pub unsafe extern "C" fn f_double_float_ret() -> DoubleFloat { + DoubleFloat { f: 29.0, g: 30.0 } +} + +// CHECK: .visible .func (.param .align 4 .b8 func_retval0[12]) f_triple_float_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_float_ret() -> TripleFloat { + TripleFloat { f: 31.0, g: 32.0, h: 33.0 } +} + +// CHECK: .visible .func (.param .align 8 .b8 func_retval0[24]) f_triple_double_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_double_ret() -> TripleDouble { + TripleDouble { f: 34.0, g: 35.0, h: 36.0 } +} + +// CHECK: .visible .func (.param .align 8 .b8 func_retval0[32]) f_many_numerics_ret( +#[no_mangle] +pub unsafe extern "C" fn f_many_numerics_ret() -> ManyNumerics { + ManyNumerics { f: 37, g: 38, h: 39, i: 40, j: 41.0, k: 43.0 } +} diff --git a/tests/assembly-llvm/nvptx-internalizing.rs b/tests/assembly-llvm/nvptx-internalizing.rs new file mode 100644 index 00000000000..0acfd5c2443 --- /dev/null +++ b/tests/assembly-llvm/nvptx-internalizing.rs @@ -0,0 +1,27 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type cdylib +//@ only-nvptx64 +//@ ignore-nvptx64 + +#![feature(abi_ptx)] +#![no_std] + +//@ aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +//@ aux-build: non-inline-dependency.rs +extern crate non_inline_dependency as dep; + +// Verify that no extra function declarations are present. +// CHECK-NOT: .func + +// CHECK: .visible .entry top_kernel( +#[no_mangle] +pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) { + // CHECK: add.s32 %{{r[0-9]+}}, %{{r[0-9]+}}, 5; + *b = *a + 5; +} + +// Verify that no extra function definitions are here. +// CHECK-NOT: .func +// CHECK-NOT: .entry diff --git a/tests/assembly-llvm/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs b/tests/assembly-llvm/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs new file mode 100644 index 00000000000..f245b4460f2 --- /dev/null +++ b/tests/assembly-llvm/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs @@ -0,0 +1,251 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86 -Z unstable-options -Clinker-flavor=llbc +//@ only-nvptx64 + +// The following ABI tests are made with nvcc 11.6 does. +// +// The PTX ABI stability is tied to major versions of the PTX ISA +// These tests assume major version 7 +// +// +// The following correspondence between types are assumed: +// u - uint_t +// i - int_t +// [T, N] - std::array +// &T - T const* +// &mut T - T* + +// CHECK: .version 7 + +#![feature(abi_ptx, lang_items, no_core)] +#![no_core] + +#[lang = "pointee_sized"] +trait PointeeSized {} +#[lang = "meta_sized"] +trait MetaSized: PointeeSized {} +#[lang = "sized"] +trait Sized: MetaSized {} +#[lang = "copy"] +trait Copy {} + +#[repr(C)] +pub struct SingleU8 { + f: u8, +} + +#[repr(C)] +pub struct DoubleU8 { + f: u8, + g: u8, +} + +#[repr(C)] +pub struct TripleU8 { + f: u8, + g: u8, + h: u8, +} + +#[repr(C)] +pub struct TripleU16 { + f: u16, + g: u16, + h: u16, +} +#[repr(C)] +pub struct DoubleI32 { + f: i32, + g: i32, +} +#[repr(C)] +pub struct TripleU32 { + f: u32, + g: u32, + h: u32, +} +#[repr(C)] +pub struct TripleU64 { + f: u64, + g: u64, + h: u64, +} + +#[repr(C)] +pub struct DoubleFloat { + f: f32, + g: f32, +} + +#[repr(C)] +pub struct TripleFloat { + f: f32, + g: f32, + h: f32, +} + +#[repr(C)] +pub struct TripleDouble { + f: f64, + g: f64, + h: f64, +} + +#[repr(C)] +pub struct ManyIntegers { + f: u8, + g: u16, + h: u32, + i: u64, +} + +#[repr(C)] +pub struct ManyNumerics { + f: u8, + g: u16, + h: u32, + i: u64, + j: f32, + k: f64, +} + +// CHECK: .visible .entry f_u8_arg( +// CHECK: .param .u8 f_u8_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_u8_arg(_a: u8) {} + +// CHECK: .visible .entry f_u16_arg( +// CHECK: .param .u16 f_u16_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_u16_arg(_a: u16) {} + +// CHECK: .visible .entry f_u32_arg( +// CHECK: .param .u32 f_u32_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_u32_arg(_a: u32) {} + +// CHECK: .visible .entry f_u64_arg( +// CHECK: .param .u64 f_u64_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_u64_arg(_a: u64) {} + +// CHECK: .visible .entry f_u128_arg( +// CHECK: .param .align 16 .b8 f_u128_arg_param_0[16] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_u128_arg(_a: u128) {} + +// CHECK: .visible .entry f_i8_arg( +// CHECK: .param .u8 f_i8_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_i8_arg(_a: i8) {} + +// CHECK: .visible .entry f_i16_arg( +// CHECK: .param .u16 f_i16_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_i16_arg(_a: i16) {} + +// CHECK: .visible .entry f_i32_arg( +// CHECK: .param .u32 f_i32_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_i32_arg(_a: i32) {} + +// CHECK: .visible .entry f_i64_arg( +// CHECK: .param .u64 f_i64_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_i64_arg(_a: i64) {} + +// CHECK: .visible .entry f_i128_arg( +// CHECK: .param .align 16 .b8 f_i128_arg_param_0[16] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_i128_arg(_a: i128) {} + +// CHECK: .visible .entry f_f32_arg( +// CHECK: .param .f32 f_f32_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_f32_arg(_a: f32) {} + +// CHECK: .visible .entry f_f64_arg( +// CHECK: .param .f64 f_f64_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_f64_arg(_a: f64) {} + +// CHECK: .visible .entry f_single_u8_arg( +// CHECK: .param .align 1 .b8 f_single_u8_arg_param_0[1] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_single_u8_arg(_a: SingleU8) {} + +// CHECK: .visible .entry f_double_u8_arg( +// CHECK: .param .align 1 .b8 f_double_u8_arg_param_0[2] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_double_u8_arg(_a: DoubleU8) {} + +// CHECK: .visible .entry f_triple_u8_arg( +// CHECK: .param .align 1 .b8 f_triple_u8_arg_param_0[3] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_triple_u8_arg(_a: TripleU8) {} + +// CHECK: .visible .entry f_triple_u16_arg( +// CHECK: .param .align 2 .b8 f_triple_u16_arg_param_0[6] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_triple_u16_arg(_a: TripleU16) {} + +// CHECK: .visible .entry f_double_i32_arg( +// CHECK: .param .align 4 .b8 f_double_i32_arg_param_0[8] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_double_i32_arg(_a: DoubleI32) {} + +// CHECK: .visible .entry f_triple_u32_arg( +// CHECK: .param .align 4 .b8 f_triple_u32_arg_param_0[12] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_triple_u32_arg(_a: TripleU32) {} + +// CHECK: .visible .entry f_triple_u64_arg( +// CHECK: .param .align 8 .b8 f_triple_u64_arg_param_0[24] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_triple_u64_arg(_a: TripleU64) {} + +// CHECK: .visible .entry f_many_integers_arg( +// CHECK: .param .align 8 .b8 f_many_integers_arg_param_0[16] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_many_integers_arg(_a: ManyIntegers) {} + +// CHECK: .visible .entry f_double_float_arg( +// CHECK: .param .align 4 .b8 f_double_float_arg_param_0[8] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_double_float_arg(_a: DoubleFloat) {} + +// CHECK: .visible .entry f_triple_float_arg( +// CHECK: .param .align 4 .b8 f_triple_float_arg_param_0[12] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_triple_float_arg(_a: TripleFloat) {} + +// CHECK: .visible .entry f_triple_double_arg( +// CHECK: .param .align 8 .b8 f_triple_double_arg_param_0[24] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_triple_double_arg(_a: TripleDouble) {} + +// CHECK: .visible .entry f_many_numerics_arg( +// CHECK: .param .align 8 .b8 f_many_numerics_arg_param_0[32] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_many_numerics_arg(_a: ManyNumerics) {} + +// CHECK: .visible .entry f_byte_array_arg( +// CHECK: .param .align 1 .b8 f_byte_array_arg_param_0[5] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_byte_array_arg(_a: [u8; 5]) {} + +// CHECK: .visible .entry f_float_array_arg( +// CHECK: .param .align 4 .b8 f_float_array_arg_param_0[20] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_float_array_arg(_a: [f32; 5]) {} + +// FIXME: u128 started to break compilation with disabled CI +// NO_CHECK: .visible .entry f_u128_array_arg( +// NO_CHECK: .param .align 16 .b8 f_u128_array_arg_param_0[80] +//#[no_mangle] +//pub unsafe extern "ptx-kernel" fn f_u128_array_arg(_a: [u128; 5]) {} + +// CHECK: .visible .entry f_u32_slice_arg( +// CHECK: .param .align 8 .b8 f_u32_slice_arg_param_0[16] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_u32_slice_arg(_a: &[u32]) {} diff --git a/tests/assembly-llvm/nvptx-linking-binary.rs b/tests/assembly-llvm/nvptx-linking-binary.rs new file mode 100644 index 00000000000..3b50b472ab1 --- /dev/null +++ b/tests/assembly-llvm/nvptx-linking-binary.rs @@ -0,0 +1,40 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type bin +//@ only-nvptx64 +//@ ignore-nvptx64 + +#![feature(abi_ptx)] +#![no_main] +#![no_std] + +//@ aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +//@ aux-build: non-inline-dependency.rs +extern crate non_inline_dependency as dep; + +// Make sure declarations are there. +// CHECK: .func (.param .b32 func_retval0) wrapping_external_fn +// CHECK: .func (.param .b32 func_retval0) panicking_external_fn + +// CHECK-LABEL: .visible .entry top_kernel( +#[no_mangle] +pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) { + // CHECK: call.uni (retval0), + // CHECK-NEXT: wrapping_external_fn + // CHECK: ld.param.b32 %[[LHS:r[0-9]+]], [retval0+0]; + let lhs = dep::wrapping_external_fn(*a); + + // CHECK: call.uni (retval0), + // CHECK-NEXT: panicking_external_fn + // CHECK: ld.param.b32 %[[RHS:r[0-9]+]], [retval0+0]; + let rhs = dep::panicking_external_fn(*a); + + // CHECK: add.s32 %[[RES:r[0-9]+]], %[[RHS]], %[[LHS]]; + // CHECK: st.global.u32 [%{{rd[0-9]+}}], %[[RES]]; + *b = lhs + rhs; +} + +// Verify that external function bodies are available. +// CHECK: .func (.param .b32 func_retval0) wrapping_external_fn +// CHECK: .func (.param .b32 func_retval0) panicking_external_fn diff --git a/tests/assembly-llvm/nvptx-linking-cdylib.rs b/tests/assembly-llvm/nvptx-linking-cdylib.rs new file mode 100644 index 00000000000..9742e26fb31 --- /dev/null +++ b/tests/assembly-llvm/nvptx-linking-cdylib.rs @@ -0,0 +1,39 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type cdylib +//@ only-nvptx64 +//@ ignore-nvptx64 + +#![feature(abi_ptx)] +#![no_std] + +//@ aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +//@ aux-build: non-inline-dependency.rs +extern crate non_inline_dependency as dep; + +// Make sure declarations are there. +// CHECK: .func (.param .b32 func_retval0) wrapping_external_fn +// CHECK: .func (.param .b32 func_retval0) panicking_external_fn + +// CHECK-LABEL: .visible .entry top_kernel( +#[no_mangle] +pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) { + // CHECK: call.uni (retval0), + // CHECK-NEXT: wrapping_external_fn + // CHECK: ld.param.b32 %[[LHS:r[0-9]+]], [retval0+0]; + let lhs = dep::wrapping_external_fn(*a); + + // CHECK: call.uni (retval0), + // CHECK-NEXT: panicking_external_fn + // CHECK: ld.param.b32 %[[RHS:r[0-9]+]], [retval0+0]; + let rhs = dep::panicking_external_fn(*a); + + // CHECK: add.s32 %[[RES:r[0-9]+]], %[[RHS]], %[[LHS]]; + // CHECK: st.global.u32 [%{{rd[0-9]+}}], %[[RES]]; + *b = lhs + rhs; +} + +// Verify that external function bodies are available. +// CHECK: .func (.param .b32 func_retval0) wrapping_external_fn +// CHECK: .func (.param .b32 func_retval0) panicking_external_fn diff --git a/tests/assembly-llvm/nvptx-safe-naming.rs b/tests/assembly-llvm/nvptx-safe-naming.rs new file mode 100644 index 00000000000..d7b46aadd9c --- /dev/null +++ b/tests/assembly-llvm/nvptx-safe-naming.rs @@ -0,0 +1,37 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type cdylib -Z unstable-options -Clinker-flavor=llbc +//@ only-nvptx64 + +#![feature(abi_ptx)] +#![no_std] + +//@ aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +// Verify function name doesn't contain unacceaptable characters. +// CHECK: .func (.param .b32 func_retval0) [[IMPL_FN:[a-zA-Z0-9$_]+square[a-zA-Z0-9$_]+]] + +// CHECK-LABEL: .visible .entry top_kernel( +#[no_mangle] +pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) { + // CHECK: call.uni (retval0), + // CHECK-NEXT: [[IMPL_FN]] + *b = deep::private::MyStruct::new(*a).square(); +} + +pub mod deep { + pub mod private { + pub struct MyStruct(T); + + impl MyStruct { + pub fn new(a: u32) -> Self { + MyStruct(a) + } + + #[inline(never)] + pub fn square(&self) -> u32 { + self.0.wrapping_mul(self.0) + } + } + } +} diff --git a/tests/assembly-llvm/panic-no-unwind-no-uwtable.rs b/tests/assembly-llvm/panic-no-unwind-no-uwtable.rs new file mode 100644 index 00000000000..b51b173e961 --- /dev/null +++ b/tests/assembly-llvm/panic-no-unwind-no-uwtable.rs @@ -0,0 +1,8 @@ +//@ assembly-output: emit-asm +//@ only-x86_64-unknown-linux-gnu +//@ compile-flags: -C panic=unwind -C force-unwind-tables=n -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-NOT: .cfi_startproc +pub fn foo() {} diff --git a/tests/assembly-llvm/panic-unwind-no-uwtable.rs b/tests/assembly-llvm/panic-unwind-no-uwtable.rs new file mode 100644 index 00000000000..181656a8987 --- /dev/null +++ b/tests/assembly-llvm/panic-unwind-no-uwtable.rs @@ -0,0 +1,12 @@ +//@ assembly-output: emit-asm +//@ only-x86_64-unknown-linux-gnu +//@ compile-flags: -C panic=unwind -C force-unwind-tables=n + +#![crate_type = "lib"] + +// CHECK-LABEL: foo: +// CHECK: .cfi_startproc +#[no_mangle] +fn foo() { + panic!(); +} diff --git a/tests/assembly-llvm/pic-relocation-model.rs b/tests/assembly-llvm/pic-relocation-model.rs new file mode 100644 index 00000000000..15a8723f756 --- /dev/null +++ b/tests/assembly-llvm/pic-relocation-model.rs @@ -0,0 +1,31 @@ +//@ add-core-stubs +//@ revisions: x64 +//@ assembly-output: emit-asm +//@ [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=pic +//@ [x64] needs-llvm-components: x86 + +#![feature(no_core, lang_items)] +#![no_core] +#![crate_type = "rlib"] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: call_other_fn: +// CHECK: {{(jmpq|callq)}} *other_fn@GOTPCREL(%rip) +#[no_mangle] +pub fn call_other_fn() -> u8 { + unsafe { other_fn() } +} + +// CHECK-LABEL: other_fn: +// CHECK: {{(jmpq|callq)}} *foreign_fn@GOTPCREL(%rip) +#[no_mangle] +#[inline(never)] +pub fn other_fn() -> u8 { + unsafe { foreign_fn() } +} + +extern "C" { + fn foreign_fn() -> u8; +} diff --git a/tests/assembly-llvm/pie-relocation-model.rs b/tests/assembly-llvm/pie-relocation-model.rs new file mode 100644 index 00000000000..cbe0001041e --- /dev/null +++ b/tests/assembly-llvm/pie-relocation-model.rs @@ -0,0 +1,34 @@ +//@ add-core-stubs +//@ revisions: x64 +//@ assembly-output: emit-asm +//@ [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=pie +//@ [x64] needs-llvm-components: x86 + +#![feature(no_core, lang_items)] +#![no_core] +#![crate_type = "rlib"] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: call_other_fn: +// With PIE local functions are called "directly". +// CHECK: {{(jmp|callq)}} other_fn +#[no_mangle] +pub fn call_other_fn() -> u8 { + unsafe { other_fn() } +} + +// CHECK-LABEL: other_fn: +// External functions are still called through GOT, since we don't know if the symbol +// is defined in the binary or in the shared library. +// CHECK: {{(jmpq|callq)}} *foreign_fn@GOTPCREL(%rip) +#[no_mangle] +#[inline(never)] +pub fn other_fn() -> u8 { + unsafe { foreign_fn() } +} + +extern "C" { + fn foreign_fn() -> u8; +} diff --git a/tests/assembly-llvm/powerpc64-struct-abi.rs b/tests/assembly-llvm/powerpc64-struct-abi.rs new file mode 100644 index 00000000000..ee4965deb4f --- /dev/null +++ b/tests/assembly-llvm/powerpc64-struct-abi.rs @@ -0,0 +1,156 @@ +//@ add-core-stubs +//@ revisions: elfv1-be elfv2-be elfv2-le aix +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 +//@[elfv1-be] compile-flags: --target powerpc64-unknown-linux-gnu +//@[elfv1-be] needs-llvm-components: powerpc +//@[elfv2-be] compile-flags: --target powerpc64-unknown-linux-musl +//@[elfv2-be] needs-llvm-components: powerpc +//@[elfv2-le] compile-flags: --target powerpc64le-unknown-linux-gnu -C target-cpu=pwr8 +//@[elfv2-le] needs-llvm-components: powerpc +//@[aix] compile-flags: --target powerpc64-ibm-aix +//@[aix] needs-llvm-components: powerpc +//@[elfv1-be] filecheck-flags: --check-prefix be +//@[elfv2-be] filecheck-flags: --check-prefix be +//@[elfv1-be] filecheck-flags: --check-prefix elf +//@[elfv2-be] filecheck-flags: --check-prefix elf +//@[elfv2-le] filecheck-flags: --check-prefix elf + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +impl Copy for FiveU32s {} +impl Copy for FiveU16s {} +impl Copy for ThreeU8s {} + +#[repr(C)] +struct FiveU32s(u32, u32, u32, u32, u32); + +#[repr(C)] +struct FiveU16s(u16, u16, u16, u16, u16); + +#[repr(C)] +struct ThreeU8s(u8, u8, u8); + +// CHECK-LABEL: read_large +// aix: lwz [[REG1:.*]], 16(4) +// aix-NEXT: lxv{{d2x|w4x}} 0, 0, 4 +// aix-NEXT: stw [[REG1]], 16(3) +// aix-NEXT: stxv{{d2x|w4x}} 0, 0, 3 +// be: lwz [[REG1:.*]], 16(4) +// be-NEXT: stw [[REG1]], 16(3) +// be-NEXT: ld [[REG2:.*]], 8(4) +// be-NEXT: ld [[REG3:.*]], 0(4) +// be-NEXT: std [[REG2]], 8(3) +// be-NEXT: std [[REG3]], 0(3) +// elfv2-le: lxvd2x [[REG1:.*]], 0, 4 +// elfv2-le-NEXT: lwz [[REG2:.*]], 16(4) +// elfv2-le-NEXT: stw [[REG2]], 16(3) +// elfv2-le-NEXT: stxvd2x [[REG1]], 0, 3 +// CHECK-NEXT: blr +#[no_mangle] +extern "C" fn read_large(x: &FiveU32s) -> FiveU32s { + *x +} + +// CHECK-LABEL: read_medium +// aix: lhz [[REG1:.*]], 8(4) +// aix-NEXT: ld [[REG2:.*]], 0(4) +// aix-NEXT: sth [[REG1]], 8(3) +// aix-NEXT: std [[REG2]], 0(3) +// elfv1-be: lhz [[REG1:.*]], 8(4) +// elfv1-be-NEXT: ld [[REG2:.*]], 0(4) +// elfv1-be-NEXT: sth [[REG1]], 8(3) +// elfv1-be-NEXT: std [[REG2]], 0(3) +// elfv2-be: lhz [[REG1:.*]], 8(3) +// elfv2-be-NEXT: ld 3, 0(3) +// elfv2-be-NEXT: sldi 4, [[REG1]], 48 +// elfv2-le: ld [[REG1:.*]], 0(3) +// elfv2-le-NEXT: lhz 4, 8(3) +// elfv2-le-NEXT: mr 3, [[REG1]] +// CHECK-NEXT: blr +#[no_mangle] +extern "C" fn read_medium(x: &FiveU16s) -> FiveU16s { + *x +} + +// CHECK-LABEL: read_small +// aix: lbz [[REG1:.*]], 2(4) +// aix-NEXT: lhz [[REG2:.*]], 0(4) +// aix-NEXT: stb [[REG1]], 2(3) +// aix-NEXT: sth [[REG2]], 0(3) +// elfv1-be: lbz [[REG1:.*]], 2(4) +// elfv1-be-NEXT: lhz [[REG2:.*]], 0(4) +// elfv1-be-NEXT: stb [[REG1]], 2(3) +// elfv1-be-NEXT: sth [[REG2]], 0(3) +// elfv2-be: lhz [[REG1:.*]], 0(3) +// elfv2-be-NEXT: lbz 3, 2(3) +// elfv2-be-NEXT: rldimi 3, [[REG1]], 8, 0 +// elfv2-le: lbz [[REG1:.*]], 2(3) +// elfv2-le-NEXT: lhz 3, 0(3) +// elfv2-le-NEXT: rldimi 3, [[REG1]], 16, 0 +// CHECK-NEXT: blr +#[no_mangle] +extern "C" fn read_small(x: &ThreeU8s) -> ThreeU8s { + *x +} + +// CHECK-LABEL: write_large +// aix: std 3, 48(1) +// aix-NEXT: rldicl [[REG1:.*]], 5, 32, 32 +// aix-NEXT: std 5, 64(1) +// aix-NEXT: std 4, 56(1) +// aix-NEXT: stw [[REG1]], 16(6) +// aix-NEXT: addi [[REG2:.*]], 1, 48 +// aix-NEXT: lxv{{d2x|w4x}} 0, 0, [[REG2]] +// aix-NEXT: stxv{{d2x|w4x}} 0, 0, 6 +// elf: std 3, 0(6) +// be-NEXT: rldicl [[REG1:.*]], 5, 32, 32 +// elf-NEXT: std 4, 8(6) +// be-NEXT: stw [[REG1]], 16(6) +// elfv2-le-NEXT: stw 5, 16(6) +// CHECK-NEXT: blr +#[no_mangle] +extern "C" fn write_large(x: FiveU32s, dest: &mut FiveU32s) { + *dest = x; +} + +// CHECK-LABEL: write_medium +// aix: std 4, 56(1) +// aix-NEXT: rldicl [[REG1:.*]], 4, 16, 48 +// aix-NEXT: std 3, 48(1) +// aix-NEXT: std 3, 0(5) +// aix-NEXT: sth [[REG1]], 8(5) +// elf: std 3, 0(5) +// be-NEXT: rldicl [[REG1:.*]], 4, 16, 48 +// be-NEXT: sth [[REG1]], 8(5) +// elfv2-le-NEXT: sth 4, 8(5) +// CHECK-NEXT: blr +#[no_mangle] +extern "C" fn write_medium(x: FiveU16s, dest: &mut FiveU16s) { + *dest = x; +} + +// CHECK-LABEL: write_small +// aix: std 3, 48(1) +// aix-NEXT: rldicl [[REG1:.*]], 3, 16, 48 +// aix-NEXT: sth 3, 0(4) +// aix-NEXT: lbz 3, 50(1) +// aix-NEXT: stb [[REG1]], 2(4) +// be: stb 3, 2(4) +// be-NEXT: srwi [[REG1:.*]], 3, 8 +// be-NEXT: sth [[REG1]], 0(4) +// The order these instructions are emitted in changed in LLVM 18. +// elfv2-le-DAG: sth 3, 0(4) +// elfv2-le-DAG: srwi [[REG1:.*]], 3, 16 +// elfv2-le-NEXT: stb [[REG1]], 2(4) +// CHECK-NEXT: blr +#[no_mangle] +extern "C" fn write_small(x: ThreeU8s, dest: &mut ThreeU8s) { + *dest = x; +} diff --git a/tests/assembly-llvm/riscv-float-struct-abi.rs b/tests/assembly-llvm/riscv-float-struct-abi.rs new file mode 100644 index 00000000000..5d9ac9d70b8 --- /dev/null +++ b/tests/assembly-llvm/riscv-float-struct-abi.rs @@ -0,0 +1,177 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 --target riscv64gc-unknown-linux-gnu +//@ needs-llvm-components: riscv + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +#[repr(C, align(64))] +struct Aligned(f64); + +#[repr(C)] +struct Padded(u8, Aligned); + +#[repr(C, packed)] +struct Packed(u8, f32); + +impl Copy for Aligned {} +impl Copy for Padded {} +impl Copy for Packed {} + +extern "C" { + fn take_padded(x: Padded); + fn get_padded() -> Padded; + fn take_packed(x: Packed); + fn get_packed() -> Packed; +} + +// CHECK-LABEL: pass_padded +#[unsafe(no_mangle)] +extern "C" fn pass_padded(out: &mut Padded, x: Padded) { + // CHECK: sb a1, 0(a0) + // CHECK-NEXT: fsd fa0, 64(a0) + // CHECK-NEXT: ret + *out = x; +} + +// CHECK-LABEL: ret_padded +#[unsafe(no_mangle)] +extern "C" fn ret_padded(x: &Padded) -> Padded { + // CHECK: fld fa0, 64(a0) + // CHECK-NEXT: lbu a0, 0(a0) + // CHECK-NEXT: ret + *x +} + +#[unsafe(no_mangle)] +extern "C" fn call_padded(x: &Padded) { + // CHECK: fld fa0, 64(a0) + // CHECK-NEXT: lbu a0, 0(a0) + // CHECK-NEXT: tail take_padded + unsafe { + take_padded(*x); + } +} + +#[unsafe(no_mangle)] +extern "C" fn receive_padded(out: &mut Padded) { + // CHECK: addi sp, sp, -16 + // CHECK-NEXT: .cfi_def_cfa_offset 16 + // CHECK-NEXT: sd ra, [[#%d,RA_SPILL:]](sp) + // CHECK-NEXT: sd [[TEMP:.*]], [[#%d,TEMP_SPILL:]](sp) + // CHECK-NEXT: .cfi_offset ra, [[#%d,RA_SPILL - 16]] + // CHECK-NEXT: .cfi_offset [[TEMP]], [[#%d,TEMP_SPILL - 16]] + // CHECK-NEXT: mv [[TEMP]], a0 + // CHECK-NEXT: call get_padded + // CHECK-NEXT: sb a0, 0([[TEMP]]) + // CHECK-NEXT: fsd fa0, 64([[TEMP]]) + // CHECK-NEXT: ld ra, [[#%d,RA_SPILL]](sp) + // CHECK-NEXT: ld [[TEMP]], [[#%d,TEMP_SPILL]](sp) + // CHECK: addi sp, sp, 16 + // CHECK: ret + unsafe { + *out = get_padded(); + } +} + +// CHECK-LABEL: pass_packed +#[unsafe(no_mangle)] +extern "C" fn pass_packed(out: &mut Packed, x: Packed) { + // CHECK: addi sp, sp, -16 + // CHECK-NEXT: .cfi_def_cfa_offset 16 + // CHECK-NEXT: sb a1, 0(a0) + // CHECK-NEXT: fsw fa0, 8(sp) + // CHECK-NEXT: lw [[VALUE:.*]], 8(sp) + // CHECK-DAG: srli [[BYTE4:.*]], [[VALUE]], 24 + // CHECK-DAG: srli [[BYTE3:.*]], [[VALUE]], 16 + // CHECK-DAG: srli [[BYTE2:.*]], [[VALUE]], 8 + // CHECK-DAG: sb [[VALUE]], 1(a0) + // CHECK-DAG: sb [[BYTE2]], 2(a0) + // CHECK-DAG: sb [[BYTE3]], 3(a0) + // CHECK-DAG: sb [[BYTE4]], 4(a0) + // CHECK-NEXT: addi sp, sp, 16 + // CHECK: ret + *out = x; +} + +// CHECK-LABEL: ret_packed +#[unsafe(no_mangle)] +extern "C" fn ret_packed(x: &Packed) -> Packed { + // CHECK: addi sp, sp, -16 + // CHECK-NEXT: .cfi_def_cfa_offset 16 + // CHECK-NEXT: lbu [[BYTE2:.*]], 2(a0) + // CHECK-NEXT: lbu [[BYTE1:.*]], 1(a0) + // CHECK-NEXT: lbu [[BYTE3:.*]], 3(a0) + // CHECK-NEXT: lbu [[BYTE4:.*]], 4(a0) + // CHECK-NEXT: slli [[SHIFTED2:.*]], [[BYTE2]], 8 + // CHECK-NEXT: or [[BYTE12:.*]], [[SHIFTED2]], [[BYTE1]] + // CHECK-NEXT: slli [[SHIFTED3:.*]], [[BYTE3]], 16 + // CHECK-NEXT: slli [[SHIFTED4:.*]], [[BYTE4]], 24 + // CHECK-NEXT: or [[BYTE34:.*]], [[SHIFTED3]], [[SHIFTED4]] + // CHECK-NEXT: or [[VALUE:.*]], [[BYTE12]], [[BYTE34]] + // CHECK-NEXT: sw [[VALUE]], 8(sp) + // CHECK-NEXT: flw fa0, 8(sp) + // CHECK-NEXT: lbu a0, 0(a0) + // CHECK-NEXT: addi sp, sp, 16 + // CHECK: ret + *x +} + +#[unsafe(no_mangle)] +extern "C" fn call_packed(x: &Packed) { + // CHECK: addi sp, sp, -16 + // CHECK-NEXT: .cfi_def_cfa_offset 16 + // CHECK-NEXT: lbu [[BYTE2:.*]], 2(a0) + // CHECK-NEXT: lbu [[BYTE1:.*]], 1(a0) + // CHECK-NEXT: lbu [[BYTE3:.*]], 3(a0) + // CHECK-NEXT: lbu [[BYTE4:.*]], 4(a0) + // CHECK-NEXT: slli [[SHIFTED2:.*]], [[BYTE2]], 8 + // CHECK-NEXT: or [[BYTE12:.*]], [[SHIFTED2]], [[BYTE1]] + // CHECK-NEXT: slli [[SHIFTED3:.*]], [[BYTE3]], 16 + // CHECK-NEXT: slli [[SHIFTED4:.*]], [[BYTE4]], 24 + // CHECK-NEXT: or [[BYTE34:.*]], [[SHIFTED3]], [[SHIFTED4]] + // CHECK-NEXT: or [[VALUE:.*]], [[BYTE12]], [[BYTE34]] + // CHECK-NEXT: sw [[VALUE]], 8(sp) + // CHECK-NEXT: flw fa0, 8(sp) + // CHECK-NEXT: lbu a0, 0(a0) + // CHECK-NEXT: addi sp, sp, 16 + // CHECK: tail take_packed + unsafe { + take_packed(*x); + } +} + +#[unsafe(no_mangle)] +extern "C" fn receive_packed(out: &mut Packed) { + // CHECK: addi sp, sp, -32 + // CHECK-NEXT: .cfi_def_cfa_offset 32 + // CHECK-NEXT: sd ra, [[#%d,RA_SPILL:]](sp) + // CHECK-NEXT: sd [[TEMP:.*]], [[#%d,TEMP_SPILL:]](sp) + // CHECK-NEXT: .cfi_offset ra, [[#%d,RA_SPILL - 32]] + // CHECK-NEXT: .cfi_offset [[TEMP]], [[#%d,TEMP_SPILL - 32]] + // CHECK-NEXT: mv [[TEMP]], a0 + // CHECK-NEXT: call get_packed + // CHECK-NEXT: sb a0, 0([[TEMP]]) + // CHECK-NEXT: fsw fa0, [[FLOAT_SPILL:.*]](sp) + // CHECK-NEXT: lw [[VALUE:.*]], [[FLOAT_SPILL]](sp) + // CHECK-DAG: srli [[BYTE4:.*]], [[VALUE]], 24 + // CHECK-DAG: srli [[BYTE3:.*]], [[VALUE]], 16 + // CHECK-DAG: srli [[BYTE2:.*]], [[VALUE]], 8 + // CHECK-DAG: sb [[VALUE]], 1([[TEMP]]) + // CHECK-DAG: sb [[BYTE2]], 2([[TEMP]]) + // CHECK-DAG: sb [[BYTE3]], 3([[TEMP]]) + // CHECK-DAG: sb [[BYTE4]], 4([[TEMP]]) + // CHECK-NEXT: ld ra, [[#%d,RA_SPILL]](sp) + // CHECK-NEXT: ld [[TEMP]], [[#%d,TEMP_SPILL]](sp) + // CHECK: addi sp, sp, 32 + // CHECK: ret + unsafe { + *out = get_packed(); + } +} diff --git a/tests/assembly-llvm/riscv-soft-abi-with-float-features.rs b/tests/assembly-llvm/riscv-soft-abi-with-float-features.rs new file mode 100644 index 00000000000..72cbd3841c1 --- /dev/null +++ b/tests/assembly-llvm/riscv-soft-abi-with-float-features.rs @@ -0,0 +1,45 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: --target riscv64imac-unknown-none-elf -Ctarget-feature=+f,+d +//@ needs-llvm-components: riscv +//@ revisions: LLVM-PRE-20 LLVM-POST-20 +//@ [LLVM-PRE-20] max-llvm-major-version: 19 +//@ [LLVM-POST-20] min-llvm-version: 20 + +#![feature(no_core, lang_items, f16)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +// This test checks that the floats are all returned in `a0` as required by the `lp64` ABI. + +// CHECK-LABEL: read_f16 +#[no_mangle] +pub extern "C" fn read_f16(x: &f16) -> f16 { + // CHECK: lh a0, 0(a0) + // CHECK-NEXT: lui a1, 1048560 + // CHECK-NEXT: or a0, a0, a1 + // CHECK-NEXT: ret + *x +} + +// CHECK-LABEL: read_f32 +#[no_mangle] +pub extern "C" fn read_f32(x: &f32) -> f32 { + // LLVM-PRE-20: flw fa5, 0(a0) + // LLVM-PRE-20-NEXT: fmv.x.w a0, fa5 + // LLVM-PRE-20-NEXT: ret + // LLVM-POST-20: lw a0, 0(a0) + // LLVM-POST-20-NEXT: ret + *x +} + +// CHECK-LABEL: read_f64 +#[no_mangle] +pub extern "C" fn read_f64(x: &f64) -> f64 { + // CHECK: ld a0, 0(a0) + // CHECK-NEXT: ret + *x +} diff --git a/tests/assembly-llvm/rust-abi-arg-attr.rs b/tests/assembly-llvm/rust-abi-arg-attr.rs new file mode 100644 index 00000000000..4f3673ccfc3 --- /dev/null +++ b/tests/assembly-llvm/rust-abi-arg-attr.rs @@ -0,0 +1,110 @@ +//@ assembly-output: emit-asm +//@ revisions: riscv64 riscv64-zbb loongarch64 +//@ compile-flags: -C opt-level=3 +//@ [riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu +//@ [riscv64] needs-llvm-components: riscv +//@ [riscv64-zbb] compile-flags: --target riscv64gc-unknown-linux-gnu +//@ [riscv64-zbb] compile-flags: -C target-feature=+zbb +//@ [riscv64-zbb] needs-llvm-components: riscv +//@ [loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@ [loongarch64] needs-llvm-components: loongarch + +#![feature(no_core, lang_items, intrinsics, rustc_attrs)] +#![crate_type = "lib"] +#![no_std] +#![no_core] +// FIXME: Migrate these code after PR #130693 is landed. + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} + +#[lang = "copy"] +trait Copy {} + +impl Copy for i8 {} +impl Copy for u32 {} +impl Copy for i32 {} + +#[lang = "neg"] +trait Neg { + type Output; + + fn neg(self) -> Self::Output; +} + +impl Neg for i8 { + type Output = i8; + + fn neg(self) -> Self::Output { + -self + } +} + +#[lang = "Ordering"] +#[repr(i8)] +enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, +} + +#[rustc_intrinsic] +fn three_way_compare(lhs: T, rhs: T) -> Ordering; + +// ^^^^^ core + +// Reimplementation of function `{integer}::max`. +macro_rules! max { + ($a:expr, $b:expr) => { + match three_way_compare($a, $b) { + Ordering::Less | Ordering::Equal => $b, + Ordering::Greater => $a, + } + }; +} + +#[no_mangle] +// CHECK-LABEL: issue_114508_u32: +pub fn issue_114508_u32(a: u32, b: u32) -> u32 { + // CHECK-NEXT: .cfi_startproc + + // riscv64-NEXT: bltu a1, a0, .[[RET:.+]] + // riscv64-NEXT: mv a0, a1 + // riscv64-NEXT: .[[RET]]: + + // riscv64-zbb-NEXT: maxu a0, a0, a1 + + // loongarch64-NEXT: sltu $a2, $a1, $a0 + // loongarch64-NEXT: masknez $a1, $a1, $a2 + // loongarch64-NEXT: maskeqz $a0, $a0, $a2 + // loongarch64-NEXT: or $a0, $a0, $a1 + + // CHECK-NEXT: ret + max!(a, b) +} + +#[no_mangle] +// CHECK-LABEL: issue_114508_i32: +pub fn issue_114508_i32(a: i32, b: i32) -> i32 { + // CHECK-NEXT: .cfi_startproc + + // riscv64-NEXT: blt a1, a0, .[[RET:.+]] + // riscv64-NEXT: mv a0, a1 + // riscv64-NEXT: .[[RET]]: + + // riscv64-zbb-NEXT: max a0, a0, a1 + + // loongarch64-NEXT: slt $a2, $a1, $a0 + // loongarch64-NEXT: masknez $a1, $a1, $a2 + // loongarch64-NEXT: maskeqz $a0, $a0, $a2 + // loongarch64-NEXT: or $a0, $a0, $a1 + + // CHECK-NEXT: ret + max!(a, b) +} diff --git a/tests/assembly-llvm/s390x-backchain-toggle.rs b/tests/assembly-llvm/s390x-backchain-toggle.rs new file mode 100644 index 00000000000..9bae15b7d11 --- /dev/null +++ b/tests/assembly-llvm/s390x-backchain-toggle.rs @@ -0,0 +1,50 @@ +//@ add-core-stubs +//@ revisions: enable-backchain disable-backchain default-backchain +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 --crate-type=lib --target=s390x-unknown-linux-gnu +//@ needs-llvm-components: systemz +//@[enable-backchain] compile-flags: -Ctarget-feature=+backchain +//@[disable-backchain] compile-flags: -Ctarget-feature=-backchain +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +extern "C" { + fn extern_func(); +} + +// CHECK-LABEL: test_backchain +#[no_mangle] +extern "C" fn test_backchain() -> i32 { + // Here we try to match if backchain register is saved to the parameter area (stored in r15/sp) + // And also if a new parameter area (160 bytes) is allocated for the upcoming function call + // enable-backchain: lgr [[REG1:.*]], %r15 + // enable-backchain-NEXT: aghi %r15, -160 + // enable-backchain: stg [[REG1]], 0(%r15) + // disable-backchain: aghi %r15, -160 + // disable-backchain-NOT: stg %r{{.*}}, 0(%r15) + // default-backchain: aghi %r15, -160 + // default-backchain-NOT: stg %r{{.*}}, 0(%r15) + unsafe { + extern_func(); + } + // enable-backchain-NEXT: brasl %r{{.*}}, extern_func@PLT + // disable-backchain: brasl %r{{.*}}, extern_func@PLT + + // Make sure that the expected return value is written into %r2 (return register): + // enable-backchain-NEXT: lghi %r2, 1 + // disable-backchain: lghi %r2, 0 + // default-backchain: lghi %r2, 0 + #[cfg(target_feature = "backchain")] + { + 1 + } + #[cfg(not(target_feature = "backchain"))] + { + 0 + } + // CHECK: br %r{{.*}} +} diff --git a/tests/assembly-llvm/s390x-vector-abi.rs b/tests/assembly-llvm/s390x-vector-abi.rs new file mode 100644 index 00000000000..fcf42664034 --- /dev/null +++ b/tests/assembly-llvm/s390x-vector-abi.rs @@ -0,0 +1,327 @@ +//@ revisions: z10 z10_vector z13 z13_no_vector +// ignore-tidy-linelength +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled +//@[z10] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z10 --cfg no_vector +//@[z10] needs-llvm-components: systemz +//@[z10_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z10 -C target-feature=+vector +//@[z10_vector] needs-llvm-components: systemz +//@[z13] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 +//@[z13] needs-llvm-components: systemz +//@[z13_no_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector --cfg no_vector +//@[z13_no_vector] needs-llvm-components: systemz + +#![feature(no_core, lang_items, repr_simd, s390x_target_feature)] +#![no_core] +#![crate_type = "lib"] +#![allow(non_camel_case_types)] +// Cases where vector feature is disabled are rejected. +// See tests/ui/simd-abi-checks-s390x.rs for test for them. + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} +#[lang = "copy"] +pub trait Copy {} +#[lang = "freeze"] +pub trait Freeze {} + +impl Copy for [T; N] {} + +#[lang = "phantom_data"] +pub struct PhantomData; +impl Copy for PhantomData {} + +#[repr(simd)] +pub struct i8x8([i8; 8]); +#[repr(simd)] +pub struct i8x16([i8; 16]); +#[repr(simd)] +pub struct i8x32([i8; 32]); +#[repr(C)] +pub struct Wrapper(T); +#[repr(C, align(16))] +pub struct WrapperAlign16(T); +#[repr(C)] +pub struct WrapperWithZst(T, PhantomData<()>); +#[repr(transparent)] +pub struct TransparentWrapper(T); + +impl Copy for i8 {} +impl Copy for i64 {} +impl Copy for i8x8 {} +impl Copy for i8x16 {} +impl Copy for i8x32 {} +impl Copy for Wrapper {} +impl Copy for WrapperAlign16 {} +impl Copy for WrapperWithZst {} +impl Copy for TransparentWrapper {} + +// CHECK-LABEL: vector_ret_small: +// CHECK: vlrepg %v24, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 { + *x +} +// CHECK-LABEL: vector_ret: +// CHECK: vl %v24, 0(%r2), 3 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_ret(x: &i8x16) -> i8x16 { + *x +} +// CHECK-LABEL: vector_ret_large: +// z10: vl %v0, 16(%r3), 4 +// z10-NEXT: vl %v1, 0(%r3), 4 +// z10-NEXT: vst %v0, 16(%r2), 4 +// z10-NEXT: vst %v1, 0(%r2), 4 +// z10-NEXT: br %r14 +// z13: vl %v0, 0(%r3), 4 +// z13-NEXT: vl %v1, 16(%r3), 4 +// z13-NEXT: vst %v1, 16(%r2), 4 +// z13-NEXT: vst %v0, 0(%r2), 4 +// z13-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_ret_large(x: &i8x32) -> i8x32 { + *x +} + +// CHECK-LABEL: vector_wrapper_ret_small: +// CHECK: mvc 0(8,%r2), 0(%r3) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_ret_small(x: &Wrapper) -> Wrapper { + *x +} +// CHECK-LABEL: vector_wrapper_ret: +// CHECK: mvc 0(16,%r2), 0(%r3) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_ret(x: &Wrapper) -> Wrapper { + *x +} +// CHECK-LABEL: vector_wrapper_ret_large: +// z10: vl %v0, 16(%r3), 4 +// z10-NEXT: vl %v1, 0(%r3), 4 +// z10-NEXT: vst %v0, 16(%r2), 4 +// z10-NEXT: vst %v1, 0(%r2), 4 +// z10-NEXT: br %r14 +// z13: vl %v0, 16(%r3), 4 +// z13-NEXT: vst %v0, 16(%r2), 4 +// z13-NEXT: vl %v0, 0(%r3), 4 +// z13-NEXT: vst %v0, 0(%r2), 4 +// z13-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_ret_large(x: &Wrapper) -> Wrapper { + *x +} + +// CHECK-LABEL: vector_wrapper_padding_ret: +// CHECK: mvc 0(16,%r2), 0(%r3) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_padding_ret(x: &WrapperAlign16) -> WrapperAlign16 { + *x +} + +// CHECK-LABEL: vector_wrapper_with_zst_ret_small: +// CHECK: mvc 0(8,%r2), 0(%r3) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_with_zst_ret_small( + x: &WrapperWithZst, +) -> WrapperWithZst { + *x +} +// CHECK-LABEL: vector_wrapper_with_zst_ret: +// CHECK: mvc 0(16,%r2), 0(%r3) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_with_zst_ret( + x: &WrapperWithZst, +) -> WrapperWithZst { + *x +} +// CHECK-LABEL: vector_wrapper_with_zst_ret_large: +// z10: vl %v0, 16(%r3), 4 +// z10-NEXT: vl %v1, 0(%r3), 4 +// z10-NEXT: vst %v0, 16(%r2), 4 +// z10-NEXT: vst %v1, 0(%r2), 4 +// z10-NEXT: br %r14 +// z13: vl %v0, 16(%r3), 4 +// z13-NEXT: vst %v0, 16(%r2), 4 +// z13-NEXT: vl %v0, 0(%r3), 4 +// z13-NEXT: vst %v0, 0(%r2), 4 +// z13-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_with_zst_ret_large( + x: &WrapperWithZst, +) -> WrapperWithZst { + *x +} + +// CHECK-LABEL: vector_transparent_wrapper_ret_small: +// CHECK: vlrepg %v24, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_transparent_wrapper_ret_small( + x: &TransparentWrapper, +) -> TransparentWrapper { + *x +} +// CHECK-LABEL: vector_transparent_wrapper_ret: +// CHECK: vl %v24, 0(%r2), 3 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_transparent_wrapper_ret( + x: &TransparentWrapper, +) -> TransparentWrapper { + *x +} +// CHECK-LABEL: vector_transparent_wrapper_ret_large: +// z10: vl %v0, 16(%r3), 4 +// z10-NEXT: vl %v1, 0(%r3), 4 +// z10-NEXT: vst %v0, 16(%r2), 4 +// z10-NEXT: vst %v1, 0(%r2), 4 +// z10-NEXT: br %r14 +// z13: vl %v0, 0(%r3), 4 +// z13-NEXT: vl %v1, 16(%r3), 4 +// z13-NEXT: vst %v1, 16(%r2), 4 +// z13-NEXT: vst %v0, 0(%r2), 4 +// z13-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_transparent_wrapper_ret_large( + x: &TransparentWrapper, +) -> TransparentWrapper { + *x +} + +// CHECK-LABEL: vector_arg_small: +// CHECK: vlgvg %r2, %v24, 0 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_arg_small(x: i8x8) -> i64 { + unsafe { *(&x as *const i8x8 as *const i64) } +} +// CHECK-LABEL: vector_arg: +// CHECK: vlgvg %r2, %v24, 0 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_arg(x: i8x16) -> i64 { + unsafe { *(&x as *const i8x16 as *const i64) } +} +// CHECK-LABEL: vector_arg_large: +// CHECK: lg %r2, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_arg_large(x: i8x32) -> i64 { + unsafe { *(&x as *const i8x32 as *const i64) } +} + +// CHECK-LABEL: vector_wrapper_arg_small: +// CHECK: vlgvg %r2, %v24, 0 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_arg_small(x: Wrapper) -> i64 { + unsafe { *(&x as *const Wrapper as *const i64) } +} +// CHECK-LABEL: vector_wrapper_arg: +// CHECK: vlgvg %r2, %v24, 0 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_arg(x: Wrapper) -> i64 { + unsafe { *(&x as *const Wrapper as *const i64) } +} +// CHECK-LABEL: vector_wrapper_arg_large: +// CHECK: lg %r2, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_arg_large(x: Wrapper) -> i64 { + unsafe { *(&x as *const Wrapper as *const i64) } +} + +// https://github.com/rust-lang/rust/pull/131586#discussion_r1837071121 +// CHECK-LABEL: vector_wrapper_padding_arg: +// CHECK: lg %r2, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_padding_arg(x: WrapperAlign16) -> i64 { + unsafe { *(&x as *const WrapperAlign16 as *const i64) } +} + +// CHECK-LABEL: vector_wrapper_with_zst_arg_small: +// CHECK: .cfi_startproc +// CHECK-NOT: vlgvg +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_with_zst_arg_small(x: WrapperWithZst) -> i64 { + unsafe { *(&x as *const WrapperWithZst as *const i64) } +} +// CHECK-LABEL: vector_wrapper_with_zst_arg: +// CHECK: lg %r2, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_with_zst_arg(x: WrapperWithZst) -> i64 { + unsafe { *(&x as *const WrapperWithZst as *const i64) } +} +// CHECK-LABEL: vector_wrapper_with_zst_arg_large: +// CHECK: lg %r2, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_with_zst_arg_large(x: WrapperWithZst) -> i64 { + unsafe { *(&x as *const WrapperWithZst as *const i64) } +} + +// CHECK-LABEL: vector_transparent_wrapper_arg_small: +// CHECK: vlgvg %r2, %v24, 0 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper) -> i64 { + unsafe { *(&x as *const TransparentWrapper as *const i64) } +} +// CHECK-LABEL: vector_transparent_wrapper_arg: +// CHECK: vlgvg %r2, %v24, 0 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper) -> i64 { + unsafe { *(&x as *const TransparentWrapper as *const i64) } +} +// CHECK-LABEL: vector_transparent_wrapper_arg_large: +// CHECK: lg %r2, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_transparent_wrapper_arg_large(x: TransparentWrapper) -> i64 { + unsafe { *(&x as *const TransparentWrapper as *const i64) } +} diff --git a/tests/assembly-llvm/sanitizer/kcfi/emit-arity-indicator.rs b/tests/assembly-llvm/sanitizer/kcfi/emit-arity-indicator.rs new file mode 100644 index 00000000000..f9966a23446 --- /dev/null +++ b/tests/assembly-llvm/sanitizer/kcfi/emit-arity-indicator.rs @@ -0,0 +1,69 @@ +// Verifies that KCFI arity indicator is emitted. +// +//@ add-core-stubs +//@ revisions: x86_64 +//@ assembly-output: emit-asm +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu -Cllvm-args=-x86-asm-syntax=intel -Ctarget-feature=-crt-static -Cpanic=abort -Zsanitizer=kcfi -Zsanitizer-kcfi-arity -Copt-level=0 +//@ [x86_64] needs-llvm-components: x86 +//@ min-llvm-version: 21.0.0 + +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] + +extern crate minicore; + +unsafe extern "C" { + safe fn add(x: i32, y: i32) -> i32; +} + +pub fn add_one(x: i32) -> i32 { + // CHECK-LABEL: __cfi__{{.*}}7add_one{{.*}}: + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: mov ecx, 2628068948 + add(x, 1) +} + +pub fn add_two(x: i32, _y: i32) -> i32 { + // CHECK-LABEL: __cfi__{{.*}}7add_two{{.*}}: + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: mov edx, 2505940310 + add(x, 2) +} + +pub fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: __cfi__{{.*}}8do_twice{{.*}}: + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: nop + // CHECK-NEXT: mov edx, 653723426 + add(f(arg), f(arg)) +} diff --git a/tests/assembly-llvm/simd-bitmask.rs b/tests/assembly-llvm/simd-bitmask.rs new file mode 100644 index 00000000000..d3e20f6ae1a --- /dev/null +++ b/tests/assembly-llvm/simd-bitmask.rs @@ -0,0 +1,147 @@ +//@ add-core-stubs +//@ revisions: x86 x86-avx2 x86-avx512 aarch64 +//@ [x86] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@ [x86] needs-llvm-components: x86 +//@ [x86-avx2] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@ [x86-avx2] compile-flags: -C target-feature=+avx2 +//@ [x86-avx2] needs-llvm-components: x86 +//@ [x86-avx512] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq +//@ [x86-avx512] needs-llvm-components: x86 +//@ [aarch64] compile-flags: --target=aarch64-unknown-linux-gnu +//@ [aarch64] needs-llvm-components: aarch64 +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort + +#![feature(no_core, lang_items, repr_simd, intrinsics)] +#![no_core] +#![allow(non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +#[repr(simd)] +pub struct m8x16([i8; 16]); + +#[repr(simd)] +pub struct m8x64([i8; 64]); + +#[repr(simd)] +pub struct m32x4([i32; 4]); + +#[repr(simd)] +pub struct m64x2([i64; 2]); + +#[repr(simd)] +pub struct m64x4([i64; 4]); + +#[rustc_intrinsic] +unsafe fn simd_bitmask(mask: V) -> B; + +// CHECK-LABEL: bitmask_m8x16 +#[no_mangle] +pub unsafe extern "C" fn bitmask_m8x16(mask: m8x16) -> u16 { + // The simd_bitmask intrinsic already uses the most significant bit, so no shift is necessary. + // Note that x86 has no byte shift, llvm uses a word shift to move the least significant bit + // of each byte into the right position. + // + // x86-NOT: psllw + // x86: movmskb eax, xmm0 + // + // x86-avx2-NOT: vpsllw + // x86-avx2: vpmovmskb eax, xmm0 + // + // x86-avx512-NOT: vpsllw xmm0 + // x86-avx512: vpmovmskb eax, xmm0 + // + // aarch64: adrp + // aarch64-NEXT: cmlt + // aarch64-NEXT: ldr + // aarch64-NEXT: and + // aarch64-NEXT: ext + // aarch64-NEXT: zip1 + // aarch64-NEXT: addv + // aarch64-NEXT: fmov + simd_bitmask(mask) +} + +// x86-avx512-LABEL: bitmask_m8x64 +#[no_mangle] +#[cfg(x86_avx512)] +pub unsafe extern "C" fn bitmask_m8x64(mask: m8x64) -> u64 { + // The simd_bitmask intrinsic already uses the most significant bit, so no shift is necessary. + // Note that x86 has no byte shift, llvm uses a word shift to move the least significant bit + // of each byte into the right position. + // + // The parameter is a 512 bit vector which in the C abi is only valid for avx512 targets. + // + // x86-avx512-NOT: vpsllw + // x86-avx512: vpmovb2m k0, zmm0 + // x86-avx512: kmovq rax, k0 + simd_bitmask(mask) +} + +// CHECK-LABEL: bitmask_m32x4 +#[no_mangle] +pub unsafe extern "C" fn bitmask_m32x4(mask: m32x4) -> u8 { + // The simd_bitmask intrinsic already uses the most significant bit, so no shift is necessary. + // + // x86-NOT: psllq + // x86: movmskps eax, xmm0 + // + // x86-avx2-NOT: vpsllq + // x86-avx2: vmovmskps eax, xmm0 + // + // x86-avx512-NOT: vpsllq + // x86-avx512: vmovmskps eax, xmm0 + // + // aarch64: adrp + // aarch64-NEXT: cmlt + // aarch64-NEXT: ldr + // aarch64-NEXT: and + // aarch64-NEXT: addv + // aarch64-NEXT: fmov + // aarch64-NEXT: and + simd_bitmask(mask) +} + +// CHECK-LABEL: bitmask_m64x2 +#[no_mangle] +pub unsafe extern "C" fn bitmask_m64x2(mask: m64x2) -> u8 { + // The simd_bitmask intrinsic already uses the most significant bit, so no shift is necessary. + // + // x86-NOT: psllq + // x86: movmskpd eax, xmm0 + // + // x86-avx2-NOT: vpsllq + // x86-avx2: vmovmskpd eax, xmm0 + // + // x86-avx512-NOT: vpsllq + // x86-avx512: vmovmskpd eax, xmm0 + // + // aarch64: adrp + // aarch64-NEXT: cmlt + // aarch64-NEXT: ldr + // aarch64-NEXT: and + // aarch64-NEXT: addp + // aarch64-NEXT: fmov + // aarch64-NEXT: and + simd_bitmask(mask) +} + +// x86-avx2-LABEL: bitmask_m64x4 +// x86-avx512-LABEL: bitmask_m64x4 +#[no_mangle] +#[cfg(any(x86_avx2, x86_avx512))] +pub unsafe extern "C" fn bitmask_m64x4(mask: m64x4) -> u8 { + // The simd_bitmask intrinsic already uses the most significant bit, so no shift is necessary. + // + // The parameter is a 256 bit vector which in the C abi is only valid for avx/avx512 targets. + // + // x86-avx2-NOT: vpsllq + // x86-avx2: vmovmskpd eax, ymm0 + // + // x86-avx512-NOT: vpsllq + // x86-avx512: vmovmskpd eax, ymm0 + simd_bitmask(mask) +} diff --git a/tests/assembly-llvm/simd-intrinsic-gather.rs b/tests/assembly-llvm/simd-intrinsic-gather.rs new file mode 100644 index 00000000000..bcab0ba1cc0 --- /dev/null +++ b/tests/assembly-llvm/simd-intrinsic-gather.rs @@ -0,0 +1,39 @@ +//@ add-core-stubs +//@ revisions: x86-avx512 +//@ [x86-avx512] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq +//@ [x86-avx512] needs-llvm-components: x86 +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort + +#![feature(no_core, lang_items, repr_simd, intrinsics)] +#![no_core] +#![allow(non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +#[repr(simd)] +pub struct f64x4([f64; 4]); + +#[repr(simd)] +pub struct m64x4([i64; 4]); + +#[repr(simd)] +pub struct pf64x4([*const f64; 4]); + +#[rustc_intrinsic] +unsafe fn simd_gather(values: V, mask: M, pointer: P) -> V; + +// CHECK-LABEL: gather_f64x4 +#[no_mangle] +pub unsafe extern "C" fn gather_f64x4(mask: m64x4, ptrs: pf64x4) -> f64x4 { + // FIXME: This should also get checked to generate a gather instruction for avx2. + // Currently llvm scalarizes this code, see https://github.com/llvm/llvm-project/issues/59789 + // + // x86-avx512-NOT: vpsllq + // x86-avx512: vpmovq2m k1, ymm0 + // x86-avx512-NEXT: vpxor xmm0, xmm0, xmm0 + // x86-avx512-NEXT: vgatherqpd ymm0 {k1}, {{(ymmword)|(qword)}} ptr [1*ymm1] + simd_gather(f64x4([0_f64, 0_f64, 0_f64, 0_f64]), ptrs, mask) +} diff --git a/tests/assembly-llvm/simd-intrinsic-mask-load.rs b/tests/assembly-llvm/simd-intrinsic-mask-load.rs new file mode 100644 index 00000000000..d3f3453a780 --- /dev/null +++ b/tests/assembly-llvm/simd-intrinsic-mask-load.rs @@ -0,0 +1,83 @@ +//@ add-core-stubs +//@ revisions: x86-avx2 x86-avx512 +//@ [x86-avx2] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@ [x86-avx2] compile-flags: -C target-feature=+avx2 +//@ [x86-avx2] needs-llvm-components: x86 +//@ [x86-avx512] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq +//@ [x86-avx512] needs-llvm-components: x86 +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort + +#![feature(no_core, lang_items, repr_simd, intrinsics)] +#![no_core] +#![allow(non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +#[repr(simd)] +pub struct i8x16([i8; 16]); + +#[repr(simd)] +pub struct m8x16([i8; 16]); + +#[repr(simd)] +pub struct f32x8([f32; 8]); + +#[repr(simd)] +pub struct m32x8([i32; 8]); + +#[repr(simd)] +pub struct f64x4([f64; 4]); + +#[repr(simd)] +pub struct m64x4([i64; 4]); + +#[rustc_intrinsic] +unsafe fn simd_masked_load(mask: M, pointer: P, values: T) -> T; + +// CHECK-LABEL: load_i8x16 +#[no_mangle] +pub unsafe extern "C" fn load_i8x16(mask: m8x16, pointer: *const i8) -> i8x16 { + // Since avx2 supports no masked loads for bytes, the code tests each individual bit + // and jumps to code that inserts individual bytes. + // x86-avx2-NOT: vpsllw + // x86-avx2-DAG: vpmovmskb eax + // x86-avx2-DAG: vpxor + // x86-avx2-NEXT: test al, 1 + // x86-avx2-NEXT: jne + // x86-avx2-NEXT: test al, 2 + // x86-avx2-NEXT: jne + // x86-avx2-DAG: movzx [[REG:[a-z]+]], byte ptr [rdi] + // x86-avx2-NEXT: vmovd xmm0, [[REG]] + // x86-avx2-DAG: vpinsrb xmm0, xmm0, byte ptr [rdi + 1], 1 + // + // x86-avx512-NOT: vpsllw + // x86-avx512: vpmovb2m k1, xmm0 + // x86-avx512-NEXT: vmovdqu8 xmm0 {k1} {z}, xmmword ptr [rdi] + simd_masked_load(mask, pointer, i8x16([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) +} + +// CHECK-LABEL: load_f32x8 +#[no_mangle] +pub unsafe extern "C" fn load_f32x8(mask: m32x8, pointer: *const f32) -> f32x8 { + // x86-avx2-NOT: vpslld + // x86-avx2: vmaskmovps ymm0, ymm0, ymmword ptr [rdi] + // + // x86-avx512-NOT: vpslld + // x86-avx512: vpmovd2m k1, ymm0 + // x86-avx512-NEXT: vmovups ymm0 {k1} {z}, ymmword ptr [rdi] + simd_masked_load(mask, pointer, f32x8([0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32])) +} + +// CHECK-LABEL: load_f64x4 +#[no_mangle] +pub unsafe extern "C" fn load_f64x4(mask: m64x4, pointer: *const f64) -> f64x4 { + // x86-avx2-NOT: vpsllq + // x86-avx2: vmaskmovpd ymm0, ymm0, ymmword ptr [rdi] + // + // x86-avx512-NOT: vpsllq + // x86-avx512: vpmovq2m k1, ymm0 + simd_masked_load(mask, pointer, f64x4([0_f64, 0_f64, 0_f64, 0_f64])) +} diff --git a/tests/assembly-llvm/simd-intrinsic-mask-reduce.rs b/tests/assembly-llvm/simd-intrinsic-mask-reduce.rs new file mode 100644 index 00000000000..8b15ed0a254 --- /dev/null +++ b/tests/assembly-llvm/simd-intrinsic-mask-reduce.rs @@ -0,0 +1,59 @@ +// verify that simd mask reductions do not introduce additional bit shift operations +//@ add-core-stubs +//@ revisions: x86 aarch64 +//@ [x86] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +// Set the base cpu explicitly, in case the default has been changed. +//@ [x86] compile-flags: -C target-cpu=x86-64 +//@ [x86] needs-llvm-components: x86 +//@ [aarch64] compile-flags: --target=aarch64-unknown-linux-gnu +//@ [aarch64] needs-llvm-components: aarch64 +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort + +#![feature(no_core, lang_items, repr_simd, intrinsics)] +#![no_core] +#![allow(non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +#[repr(simd)] +pub struct mask8x16([i8; 16]); + +#[rustc_intrinsic] +unsafe fn simd_reduce_all(x: T) -> bool; +#[rustc_intrinsic] +unsafe fn simd_reduce_any(x: T) -> bool; + +// CHECK-LABEL: mask_reduce_all: +#[no_mangle] +pub unsafe extern "C" fn mask_reduce_all(m: mask8x16) -> bool { + // x86-NOT: psllw + // x86: pmovmskb eax, xmm0 + // x86-NEXT: {{cmp ax, -1|cmp eax, 65535|xor eax, 65535}} + // x86-NEXT: sete al + // + // aarch64-NOT: shl + // aarch64: cmge v0.16b, v0.16b, #0 + // aarch64-DAG: mov [[REG1:[a-z0-9]+]], #1 + // aarch64-DAG: umaxv b0, v0.16b + // aarch64-NEXT: fmov [[REG2:[a-z0-9]+]], s0 + // aarch64-NEXT: bic w0, [[REG1]], [[REG2]] + simd_reduce_all(m) +} + +// CHECK-LABEL: mask_reduce_any: +#[no_mangle] +pub unsafe extern "C" fn mask_reduce_any(m: mask8x16) -> bool { + // x86-NOT: psllw + // x86: pmovmskb + // x86-NEXT: test eax, eax + // x86-NEXT: setne al + // + // aarch64-NOT: shl + // aarch64: cmlt v0.16b, v0.16b, #0 + // aarch64-NEXT: umaxv b0, v0.16b + // aarch64-NEXT: fmov [[REG:[a-z0-9]+]], s0 + // aarch64-NEXT: and w0, [[REG]], #0x1 + simd_reduce_any(m) +} diff --git a/tests/assembly-llvm/simd-intrinsic-mask-store.rs b/tests/assembly-llvm/simd-intrinsic-mask-store.rs new file mode 100644 index 00000000000..001762e5060 --- /dev/null +++ b/tests/assembly-llvm/simd-intrinsic-mask-store.rs @@ -0,0 +1,82 @@ +//@ add-core-stubs +//@ revisions: x86-avx2 x86-avx512 +//@ [x86-avx2] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@ [x86-avx2] compile-flags: -C target-feature=+avx2 +//@ [x86-avx2] needs-llvm-components: x86 +//@ [x86-avx512] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq +//@ [x86-avx512] needs-llvm-components: x86 +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort + +#![feature(no_core, lang_items, repr_simd, intrinsics)] +#![no_core] +#![allow(non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +#[repr(simd)] +pub struct i8x16([i8; 16]); + +#[repr(simd)] +pub struct m8x16([i8; 16]); + +#[repr(simd)] +pub struct f32x8([f32; 8]); + +#[repr(simd)] +pub struct m32x8([i32; 8]); + +#[repr(simd)] +pub struct f64x4([f64; 4]); + +#[repr(simd)] +pub struct m64x4([i64; 4]); + +#[rustc_intrinsic] +unsafe fn simd_masked_store(mask: M, pointer: P, values: T); + +// CHECK-LABEL: store_i8x16 +#[no_mangle] +pub unsafe extern "C" fn store_i8x16(mask: m8x16, pointer: *mut i8, value: i8x16) { + // Since avx2 supports no masked stores for bytes, the code tests each individual bit + // and jumps to code that extracts individual bytes to memory. + // x86-avx2-NOT: vpsllw + // x86-avx2: vpmovmskb eax, xmm0 + // x86-avx2-NEXT: test al, 1 + // x86-avx2-NEXT: jne + // x86-avx2-NEXT: test al, 2 + // x86-avx2-NEXT: jne + // x86-avx2-DAG: vpextrb byte ptr [rdi + 1], xmm1, 1 + // x86-avx2-DAG: vpextrb byte ptr [rdi], xmm1, 0 + // + // x86-avx512-NOT: vpsllw + // x86-avx512: vpmovb2m k1, xmm0 + // x86-avx512-NEXT: vmovdqu8 xmmword ptr [rdi] {k1}, xmm1 + simd_masked_store(mask, pointer, value) +} + +// CHECK-LABEL: store_f32x8 +#[no_mangle] +pub unsafe extern "C" fn store_f32x8(mask: m32x8, pointer: *mut f32, value: f32x8) { + // x86-avx2-NOT: vpslld + // x86-avx2: vmaskmovps ymmword ptr [rdi], ymm0, ymm1 + // + // x86-avx512-NOT: vpslld + // x86-avx512: vpmovd2m k1, ymm0 + // x86-avx512-NEXT: vmovups ymmword ptr [rdi] {k1}, ymm1 + simd_masked_store(mask, pointer, value) +} + +// CHECK-LABEL: store_f64x4 +#[no_mangle] +pub unsafe extern "C" fn store_f64x4(mask: m64x4, pointer: *mut f64, value: f64x4) { + // x86-avx2-NOT: vpsllq + // x86-avx2: vmaskmovpd ymmword ptr [rdi], ymm0, ymm1 + // + // x86-avx512-NOT: vpsllq + // x86-avx512: vpmovq2m k1, ymm0 + // x86-avx512-NEXT: vmovupd ymmword ptr [rdi] {k1}, ymm1 + simd_masked_store(mask, pointer, value) +} diff --git a/tests/assembly-llvm/simd-intrinsic-scatter.rs b/tests/assembly-llvm/simd-intrinsic-scatter.rs new file mode 100644 index 00000000000..d77dfad3546 --- /dev/null +++ b/tests/assembly-llvm/simd-intrinsic-scatter.rs @@ -0,0 +1,35 @@ +//@ add-core-stubs +//@ revisions: x86-avx512 +//@ [x86-avx512] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq +//@ [x86-avx512] needs-llvm-components: x86 +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort + +#![feature(no_core, lang_items, repr_simd, intrinsics)] +#![no_core] +#![allow(non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +#[repr(simd)] +pub struct f64x4([f64; 4]); + +#[repr(simd)] +pub struct m64x4([i64; 4]); + +#[repr(simd)] +pub struct pf64x4([*mut f64; 4]); + +#[rustc_intrinsic] +unsafe fn simd_scatter(values: V, pointer: P, mask: M); + +// CHECK-LABEL: scatter_f64x4 +#[no_mangle] +pub unsafe extern "C" fn scatter_f64x4(values: f64x4, ptrs: pf64x4, mask: m64x4) { + // x86-avx512-NOT: vpsllq + // x86-avx512: vpmovq2m k1, ymm2 + // x86-avx512-NEXT: vscatterqpd {{(ymmword)|(qword)}} ptr [1*ymm1] {k1}, ymm0 + simd_scatter(values, ptrs, mask) +} diff --git a/tests/assembly-llvm/simd-intrinsic-select.rs b/tests/assembly-llvm/simd-intrinsic-select.rs new file mode 100644 index 00000000000..e7c7b0db0d5 --- /dev/null +++ b/tests/assembly-llvm/simd-intrinsic-select.rs @@ -0,0 +1,128 @@ +//@ add-core-stubs +//@ revisions: x86-avx2 x86-avx512 aarch64 +//@ [x86-avx2] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@ [x86-avx2] compile-flags: -C target-feature=+avx2 +//@ [x86-avx2] needs-llvm-components: x86 +//@ [x86-avx512] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq +//@ [x86-avx512] needs-llvm-components: x86 +//@ [aarch64] compile-flags: --target=aarch64-unknown-linux-gnu +//@ [aarch64] needs-llvm-components: aarch64 +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort + +#![feature(no_core, lang_items, repr_simd, intrinsics)] +#![no_core] +#![allow(non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +#[repr(simd)] +pub struct i8x16([i8; 16]); + +#[repr(simd)] +pub struct m8x16([i8; 16]); + +#[repr(simd)] +pub struct f32x4([f32; 4]); + +#[repr(simd)] +pub struct m32x4([i32; 4]); + +#[repr(simd)] +pub struct f64x2([f64; 2]); + +#[repr(simd)] +pub struct m64x2([i64; 2]); + +#[repr(simd)] +pub struct f64x4([f64; 4]); + +#[repr(simd)] +pub struct m64x4([i64; 4]); + +#[repr(simd)] +pub struct f64x8([f64; 8]); + +#[repr(simd)] +pub struct m64x8([i64; 8]); + +#[rustc_intrinsic] +unsafe fn simd_select(mask: M, a: V, b: V) -> V; + +// CHECK-LABEL: select_i8x16 +#[no_mangle] +pub unsafe extern "C" fn select_i8x16(mask: m8x16, a: i8x16, b: i8x16) -> i8x16 { + // x86-avx2-NOT: vpsllw + // x86-avx2: vpblendvb xmm0, xmm2, xmm1, xmm0 + // + // x86-avx512-NOT: vpsllw + // x86-avx512: vpmovb2m k1, xmm0 + // x86-avx512-NEXT: vpblendmb xmm0 {k1}, xmm2, xmm1 + // + // aarch64-NOT: shl + // aarch64: cmlt v0.16b, v0.16b, #0 + // aarch64-NEXT: bsl v0.16b, v1.16b, v2.16b + simd_select(mask, a, b) +} + +// CHECK-LABEL: select_f32x4 +#[no_mangle] +pub unsafe extern "C" fn select_f32x4(mask: m32x4, a: f32x4, b: f32x4) -> f32x4 { + // x86-avx2-NOT: vpslld + // x86-avx2: vblendvps xmm0, xmm2, xmm1, xmm0 + // + // x86-avx512-NOT: vpslld + // x86-avx512: vpmovd2m k1, xmm0 + // x86-avx512-NEXT: vblendmps xmm0 {k1}, xmm2, xmm1 + // + // aarch64-NOT: shl + // aarch64: cmlt v0.4s, v0.4s, #0 + // aarch64-NEXT: bsl v0.16b, v1.16b, v2.16b + simd_select(mask, a, b) +} + +// CHECK-LABEL: select_f64x2 +#[no_mangle] +pub unsafe extern "C" fn select_f64x2(mask: m64x2, a: f64x2, b: f64x2) -> f64x2 { + // x86-avx2-NOT: vpsllq + // x86-avx2: vblendvpd xmm0, xmm2, xmm1, xmm0 + // + // x86-avx512-NOT: vpsllq + // x86-avx512: vpmovq2m k1, xmm0 + // x86-avx512-NEXT: vblendmpd xmm0 {k1}, xmm2, xmm1 + // + // aarch64-NOT: shl + // aarch64: cmlt v0.2d, v0.2d, #0 + // aarch64-NEXT: bsl v0.16b, v1.16b, v2.16b + simd_select(mask, a, b) +} + +// x86-avx2-LABEL: select_f64x4 +// x86-avx512-LABEL: select_f64x4 +#[no_mangle] +#[cfg(any(x86_avx2, x86_avx512))] +pub unsafe extern "C" fn select_f64x4(mask: m64x4, a: f64x4, b: f64x4) -> f64x4 { + // The parameter is a 256 bit vector which in the C abi is only valid for avx targets. + // + // x86-avx2-NOT: vpsllq + // x86-avx2: vblendvpd ymm0, ymm2, ymm1, ymm0 + // + // x86-avx512-NOT: vpsllq + // x86-avx512: vpmovq2m k1, ymm0 + // x86-avx512-NEXT: vblendmpd ymm0 {k1}, ymm2, ymm1 + simd_select(mask, a, b) +} + +// x86-avx512-LABEL: select_f64x8 +#[no_mangle] +#[cfg(x86_avx512)] +pub unsafe extern "C" fn select_f64x8(mask: m64x8, a: f64x8, b: f64x8) -> f64x8 { + // The parameter is a 256 bit vector which in the C abi is only valid for avx512 targets. + // + // x86-avx512-NOT: vpsllq + // x86-avx512: vpmovq2m k1, zmm0 + // x86-avx512-NEXT: vblendmpd zmm0 {k1}, zmm2, zmm1 + simd_select(mask, a, b) +} diff --git a/tests/assembly-llvm/simd/reduce-fadd-unordered.rs b/tests/assembly-llvm/simd/reduce-fadd-unordered.rs new file mode 100644 index 00000000000..e872826f6ef --- /dev/null +++ b/tests/assembly-llvm/simd/reduce-fadd-unordered.rs @@ -0,0 +1,31 @@ +//@ revisions: x86_64 aarch64 +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -Copt-level=3 + +//@[aarch64] only-aarch64 +//@[x86_64] only-x86_64 +//@[x86_64] compile-flags: -Ctarget-feature=+sse3 +//@ ignore-sgx Test incompatible with LVI mitigations +#![feature(portable_simd)] +#![feature(core_intrinsics)] +use std::intrinsics::simd as intrinsics; +use std::simd::*; +// Regression test for https://github.com/rust-lang/rust/issues/130028 +// This intrinsic produces much worse code if you use +0.0 instead of -0.0 because +// +0.0 isn't as easy to algebraically reassociate, even using LLVM's reassoc attribute! +// It would emit about an extra fadd, depending on the architecture. + +// CHECK-LABEL: reduce_fadd_negative_zero +pub unsafe fn reduce_fadd_negative_zero(v: f32x4) -> f32 { + // x86_64: addps + // x86_64-NEXT: movshdup + // x86_64-NEXT: addss + // x86_64-NOT: xorps + + // aarch64: faddp + // aarch64-NEXT: faddp + + // CHECK-NOT: {{f?}}add{{p?s*}} + // CHECK: ret + intrinsics::simd_reduce_add_unordered(v) +} diff --git a/tests/assembly-llvm/slice-is_ascii.rs b/tests/assembly-llvm/slice-is_ascii.rs new file mode 100644 index 00000000000..e53cd5160cf --- /dev/null +++ b/tests/assembly-llvm/slice-is_ascii.rs @@ -0,0 +1,33 @@ +//@ revisions: WIN LIN +//@ [WIN] only-windows +//@ [LIN] only-linux +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -Copt-level=3 -C llvm-args=-x86-asm-syntax=intel +//@ only-x86_64 +//@ ignore-sgx + +#![feature(str_internals)] + +// CHECK-LABEL: is_ascii_simple_demo: +#[no_mangle] +pub fn is_ascii_simple_demo(bytes: &[u8]) -> bool { + // Linux (System V): pointer is rdi; length is rsi + // Windows: pointer is rcx; length is rdx. + + // CHECK-NOT: mov + // CHECK-NOT: test + // CHECK-NOT: cmp + + // CHECK: .[[LOOPHEAD:.+]]: + // CHECK-NEXT: mov [[TEMP:.+]], [[LEN:rsi|rdx]] + // CHECK-NEXT: sub [[LEN]], 1 + // CHECK-NEXT: jb .[[LOOPEXIT:.+]] + // CHECK-NEXT: cmp byte ptr [{{rdi|rcx}} + [[TEMP]] - 1], 0 + // CHECK-NEXT: jns .[[LOOPHEAD]] + + // CHECK-NEXT: .[[LOOPEXIT]]: + // CHECK-NEXT: test [[TEMP]], [[TEMP]] + // CHECK-NEXT: sete al + // CHECK-NEXT: ret + core::slice::is_ascii_simple(bytes) +} diff --git a/tests/assembly-llvm/small_data_threshold.rs b/tests/assembly-llvm/small_data_threshold.rs new file mode 100644 index 00000000000..2abe8687d8b --- /dev/null +++ b/tests/assembly-llvm/small_data_threshold.rs @@ -0,0 +1,98 @@ +// Test for -Z small_data_threshold=... +//@ revisions: RISCV MIPS HEXAGON M68K +//@ assembly-output: emit-asm +//@ compile-flags: -Z small_data_threshold=4 +//@ [RISCV] compile-flags: --target=riscv32im-unknown-none-elf +//@ [RISCV] needs-llvm-components: riscv +//@ [MIPS] compile-flags: --target=mips-unknown-linux-uclibc -C relocation-model=static +//@ [MIPS] compile-flags: -C llvm-args=-mgpopt -C llvm-args=-mlocal-sdata +//@ [MIPS] compile-flags: -C target-feature=+noabicalls +//@ [MIPS] needs-llvm-components: mips +//@ [HEXAGON] compile-flags: --target=hexagon-unknown-linux-musl -C target-feature=+small-data +//@ [HEXAGON] compile-flags: -C llvm-args=--hexagon-statics-in-small-data +//@ [HEXAGON] needs-llvm-components: hexagon +//@ [M68K] compile-flags: --target=m68k-unknown-linux-gnu +//@ [M68K] needs-llvm-components: m68k + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} + +#[lang = "drop_in_place"] +fn drop_in_place(_: *mut T) {} + +#[used] +#[no_mangle] +// U is below the threshold, should be in sdata +static mut U: u16 = 123; + +#[used] +#[no_mangle] +// V is below the threshold, should be in sbss +static mut V: u16 = 0; + +#[used] +#[no_mangle] +// W is at the threshold, should be in sdata +static mut W: u32 = 123; + +#[used] +#[no_mangle] +// X is at the threshold, should be in sbss +static mut X: u32 = 0; + +#[used] +#[no_mangle] +// Y is over the threshold, should be in its own .data section +static mut Y: u64 = 123; + +#[used] +#[no_mangle] +// Z is over the threshold, should be in its own .bss section +static mut Z: u64 = 0; + +// Currently, only MIPS and RISCV successfully put any objects in the small data +// sections so the U/V/W/X tests are skipped on Hexagon and M68K + +// RISCV: .section .sdata +// RISCV-NOT: .section +// RISCV: U: +// RISCV: .section .sbss +// RISCV-NOT: .section +// RISCV: V: +// RISCV: .section .sdata +// RISCV-NOT: .section +// RISCV: W: +// RISCV: .section .sbss +// RISCV-NOT: .section +// RISCV: X: + +// MIPS: .section .sdata +// MIPS-NOT: .section +// MIPS: U: +// MIPS: .section .sbss +// MIPS-NOT: .section +// MIPS: V: +// MIPS: .section .sdata +// MIPS-NOT: .section +// MIPS: W: +// MIPS: .section .sbss +// MIPS-NOT: .section +// MIPS: X: + +// CHECK: .section .data.Y, +// CHECK-NOT: .section +// CHECK: Y: +// CHECK: .section .bss.Z, +// CHECK-NOT: .section +// CHECK: Z: diff --git a/tests/assembly-llvm/sparc-struct-abi.rs b/tests/assembly-llvm/sparc-struct-abi.rs new file mode 100644 index 00000000000..b1594428811 --- /dev/null +++ b/tests/assembly-llvm/sparc-struct-abi.rs @@ -0,0 +1,68 @@ +// Test SPARC64 ABI +// - float structure members are passes in floating point registers +// (#86163) + +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ needs-llvm-components: sparc +//@ compile-flags: --target=sparcv9-sun-solaris -Copt-level=3 +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(C)] +pub struct Franta { + a: f32, + b: f32, + c: f32, + d: f32, +} + +// NB: due to delay slots the `ld` following the call is actually executed before the call. +#[no_mangle] +pub unsafe extern "C" fn callee(arg: Franta) { + // CHECK-LABEL: callee: + // CHECK: st %f3, [[PLACE_D:.*]] + // CHECK: st %f2, [[PLACE_C:.*]] + // CHECK: st %f1, [[PLACE_B:.*]] + // CHECK: st %f0, [[PLACE_A:.*]] + // CHECK: call tst_use + // CHECK-NEXT: ld [[PLACE_A]], %f1 + // CHECK: call tst_use + // CHECK-NEXT: ld [[PLACE_B]], %f1 + // CHECK: call tst_use + // CHECK-NEXT: ld [[PLACE_C]], %f1 + // CHECK: call tst_use + // CHECK-NEXT: ld [[PLACE_D]], %f1 + clobber(); + tst_use(arg.a); + tst_use(arg.b); + tst_use(arg.c); + tst_use(arg.d); + tail_call_avoidance_fn(); +} + +extern "C" { + fn opaque_callee(arg: Franta, intarg: i32); + fn tst_use(arg: f32); + fn clobber(); + // This exists so that post-https://reviews.llvm.org/D138741 LLVM doesn't + // tail-call away some of our assertions. + fn tail_call_avoidance_fn(); +} + +#[no_mangle] +pub unsafe extern "C" fn caller() { + // CHECK-LABEL: caller: + // CHECK: ld [{{.*}}], %f0 + // CHECK: ld [{{.*}}], %f1 + // CHECK: ld [{{.*}}], %f2 + // CHECK: ld [{{.*}}], %f3 + // CHECK: call opaque_callee + // CHECK: mov 3, %o2 + opaque_callee(Franta { a: 1.0, b: 2.0, c: 3.0, d: 4.0 }, 3); + tail_call_avoidance_fn(); +} diff --git a/tests/assembly-llvm/stack-probes.rs b/tests/assembly-llvm/stack-probes.rs new file mode 100644 index 00000000000..de245431f47 --- /dev/null +++ b/tests/assembly-llvm/stack-probes.rs @@ -0,0 +1,41 @@ +//@ add-core-stubs +//@ revisions: x86_64 i686 aarch64 +//@ assembly-output: emit-asm +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@[x86_64] needs-llvm-components: x86 +//@[i686] compile-flags: --target i686-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@[i686] needs-llvm-components: x86 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: aarch64 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +// Check that inline-asm stack probes are generated correctly. +// To avoid making this test fragile to slight asm changes, +// we only check that the stack pointer is decremented by a page at a time, +// instead of matching the whole probe sequence. + +// CHECK-LABEL: small_stack_probe: +#[no_mangle] +pub fn small_stack_probe(x: u8, f: fn(&mut [u8; 8192])) { + // CHECK-NOT: __rust_probestack + // x86_64: sub rsp, 4096 + // i686: sub esp, 4096 + // aarch64: sub sp, sp, #1, lsl #12 + f(&mut [x; 8192]); +} + +// CHECK-LABEL: big_stack_probe: +#[no_mangle] +pub fn big_stack_probe(x: u8, f: fn(&[u8; 65536])) { + // CHECK-NOT: __rust_probestack + // x86_64: sub rsp, 4096 + // i686: sub esp, 4096 + // aarch64: sub sp, sp, #1, lsl #12 + f(&mut [x; 65536]); +} diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs new file mode 100644 index 00000000000..3287e018b40 --- /dev/null +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs @@ -0,0 +1,359 @@ +//@ revisions: all strong basic none missing +//@ assembly-output: emit-asm +//@ only-windows +//@ only-msvc +//@ ignore-64bit 64-bit table based SEH has slightly different behaviors than classic SEH +//@ [all] compile-flags: -Z stack-protector=all +//@ [strong] compile-flags: -Z stack-protector=strong +//@ [basic] compile-flags: -Z stack-protector=basic +//@ [none] compile-flags: -Z stack-protector=none +//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled + +#![crate_type = "lib"] +#![allow(internal_features)] +#![feature(unsized_fn_params)] + +// CHECK-LABEL: emptyfn: +#[no_mangle] +pub fn emptyfn() { + // all: __security_check_cookie + // strong-NOT: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: array_char +#[no_mangle] +pub fn array_char(f: fn(*const char)) { + let a = ['c'; 1]; + let b = ['d'; 3]; + let c = ['e'; 15]; + + f(&a as *const _); + f(&b as *const _); + f(&c as *const _); + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: array_u8_1 +#[no_mangle] +pub fn array_u8_1(f: fn(*const u8)) { + let a = [0u8; 1]; + f(&a as *const _); + + // The 'strong' heuristic adds stack protection to functions with local + // array variables regardless of their size. + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: array_u8_small: +#[no_mangle] +pub fn array_u8_small(f: fn(*const u8)) { + let a = [0u8; 2]; + let b = [0u8; 7]; + f(&a as *const _); + f(&b as *const _); + + // Small arrays do not lead to stack protection by the 'basic' heuristic. + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: array_u8_large: +#[no_mangle] +pub fn array_u8_large(f: fn(*const u8)) { + let a = [0u8; 9]; + f(&a as *const _); + + // Since `a` is a byte array with size greater than 8, the basic heuristic + // will also protect this function. + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +#[derive(Copy, Clone)] +pub struct ByteSizedNewtype(u8); + +// CHECK-LABEL: array_bytesizednewtype_9: +#[no_mangle] +pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { + let a = [ByteSizedNewtype(0); 9]; + f(&a as *const _); + + // Since `a` is a byte array in the LLVM output, the basic heuristic will + // also protect this function. + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: local_var_addr_used_indirectly +#[no_mangle] +pub fn local_var_addr_used_indirectly(f: fn(bool)) { + let a = 5; + let a_addr = &a as *const _ as usize; + f(a_addr & 0x10 == 0); + + // This function takes the address of a local variable taken. Although this + // address is never used as a way to refer to stack memory, the `strong` + // heuristic adds stack smash protection. This is also the case in C++: + // ``` + // cat << EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk + // #include + // void f(void (*g)(bool)) { + // int32_t x; + // g((reinterpret_cast(&x) & 0x10U) == 0); + // } + // EOF + // ``` + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: local_string_addr_taken +#[no_mangle] +pub fn local_string_addr_taken(f: fn(&String)) { + let x = String::new(); + f(&x); + + // Taking the address of the local variable `x` leads to stack smash + // protection with the `strong` heuristic, but not with the `basic` + // heuristic. It does not matter that the reference is not mut. + // + // An interesting note is that a similar function in C++ *would* be + // protected by the `basic` heuristic, because `std::string` has a char + // array internally as a small object optimization: + // ``` + // cat < + // void f(void (*g)(const std::string&)) { + // std::string x; + // g(x); + // } + // EOF + // ``` + // + + // all: __security_check_cookie + // strong-NOT: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +pub trait SelfByRef { + fn f(&self) -> i32; +} + +impl SelfByRef for i32 { + fn f(&self) -> i32 { + return self + 1; + } +} + +// CHECK-LABEL: local_var_addr_taken_used_locally_only +#[no_mangle] +pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) { + let x = factory(); + let g = x.f(); + sink(g); + + // Even though the local variable conceptually has its address taken, as + // it's passed by reference to the trait function, the use of the reference + // is easily inlined. There is therefore no stack smash protection even with + // the `strong` heuristic. + + // all: __security_check_cookie + // strong-NOT: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +pub struct Gigastruct { + does: u64, + not: u64, + have: u64, + array: u64, + members: u64, +} + +// CHECK-LABEL: local_large_var_moved +#[no_mangle] +pub fn local_large_var_moved(f: fn(Gigastruct)) { + let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }; + f(x); + + // Even though the local variable conceptually doesn't have its address + // taken, it's so large that the "move" is implemented with a reference to a + // stack-local variable in the ABI. Consequently, this function *is* + // protected. This is also the case for rvalue-references in C++, + // regardless of struct size: + // ``` + // cat < + // #include + // void f(void (*g)(uint64_t&&)) { + // uint64_t x; + // g(std::move(x)); + // } + // EOF + // ``` + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: local_large_var_cloned +#[no_mangle] +pub fn local_large_var_cloned(f: fn(Gigastruct)) { + f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }); + + // A new instance of `Gigastruct` is passed to `f()`, without any apparent + // connection to this stack frame. Still, since instances of `Gigastruct` + // are sufficiently large, it is allocated in the caller stack frame and + // passed as a pointer. As such, this function is *also* protected, just + // like `local_large_var_moved`. This is also the case for pass-by-value + // of sufficiently large structs in C++: + // ``` + // cat < + // #include + // struct Gigastruct { uint64_t a, b, c, d, e; }; + // void f(void (*g)(Gigastruct)) { + // g(Gigastruct{}); + // } + // EOF + // ``` + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +extern "C" { + // A call to an external `alloca` function is *not* recognized as an + // `alloca(3)` operation. This function is a compiler built-in, as the + // man page explains. Clang translates it to an LLVM `alloca` + // instruction with a count argument, which is also what the LLVM stack + // protector heuristics looks for. The man page for `alloca(3)` details + // a way to avoid using the compiler built-in: pass a -std=c11 + // argument, *and* don't include . Though this leads to an + // external alloca() function being called, it doesn't lead to stack + // protection being included. It even fails with a linker error + // "undefined reference to `alloca'". Example: + // ``` + // cat< + // void * alloca(size_t); + // void f(void (*g)(void*)) { + // void * p = alloca(10); + // g(p); + // } + // int main() { return 0; } + // EOF + // ``` + // The following tests demonstrate that calls to an external `alloca` + // function in Rust also doesn't trigger stack protection. + + fn alloca(size: usize) -> *mut (); +} + +// CHECK-LABEL: alloca_small_compile_time_constant_arg +#[no_mangle] +pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { + f(unsafe { alloca(8) }); + + // all: __security_check_cookie + // strong-NOT: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: alloca_large_compile_time_constant_arg +#[no_mangle] +pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { + f(unsafe { alloca(9) }); + + // all: __security_check_cookie + // strong-NOT: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: alloca_dynamic_arg +#[no_mangle] +pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { + f(unsafe { alloca(n) }); + + // all: __security_check_cookie + // strong-NOT: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// The question then is: in what ways can Rust code generate array-`alloca` +// LLVM instructions? This appears to only be generated by +// rustc_codegen_ssa::traits::Builder::array_alloca() through +// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT +// this is support for the "unsized locals" unstable feature: +// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html. + +// CHECK-LABEL: unsized_fn_param +#[no_mangle] +pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { + let n = if l { 1 } else { 2 }; + f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from + + // Even though slices are conceptually passed by-value both into this + // function and into `f()`, this is implemented with pass-by-reference + // using a suitably constructed fat-pointer (as if the functions + // accepted &[u8]). This function therefore doesn't need dynamic array + // alloca, and is therefore not protected by the `strong` or `basic` + // heuristics. + + // We should have a __security_check_cookie call in `all` and `strong` modes but + // LLVM does not support generating stack protectors in functions with funclet + // based EH personalities. + // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4 + // all-NOT: __security_check_cookie + // strong-NOT: __security_check_cookie + + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs new file mode 100644 index 00000000000..9a3dabc74dd --- /dev/null +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs @@ -0,0 +1,366 @@ +//@ revisions: all strong basic none missing +//@ assembly-output: emit-asm +//@ only-windows +//@ only-msvc +//@ ignore-32bit 64-bit table based SEH has slightly different behaviors than classic SEH +//@ [all] compile-flags: -Z stack-protector=all +//@ [strong] compile-flags: -Z stack-protector=strong +//@ [basic] compile-flags: -Z stack-protector=basic +//@ [none] compile-flags: -Z stack-protector=none +//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled + +#![crate_type = "lib"] +#![feature(unsized_fn_params)] + +// CHECK-LABEL: emptyfn: +#[no_mangle] +pub fn emptyfn() { + // all: __security_check_cookie + // strong-NOT: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: array_char +#[no_mangle] +pub fn array_char(f: fn(*const char)) { + let a = ['c'; 1]; + let b = ['d'; 3]; + let c = ['e'; 15]; + + f(&a as *const _); + f(&b as *const _); + f(&c as *const _); + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: array_u8_1 +#[no_mangle] +pub fn array_u8_1(f: fn(*const u8)) { + let a = [0u8; 1]; + f(&a as *const _); + + // The 'strong' heuristic adds stack protection to functions with local + // array variables regardless of their size. + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: array_u8_small: +#[no_mangle] +pub fn array_u8_small(f: fn(*const u8)) { + let a = [0u8; 2]; + let b = [0u8; 7]; + f(&a as *const _); + f(&b as *const _); + + // Small arrays do not lead to stack protection by the 'basic' heuristic. + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: array_u8_large: +#[no_mangle] +pub fn array_u8_large(f: fn(*const u8)) { + let a = [0u8; 9]; + f(&a as *const _); + + // Since `a` is a byte array with size greater than 8, the basic heuristic + // will also protect this function. + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +#[derive(Copy, Clone)] +pub struct ByteSizedNewtype(u8); + +// CHECK-LABEL: array_bytesizednewtype_9: +#[no_mangle] +pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { + let a = [ByteSizedNewtype(0); 9]; + f(&a as *const _); + + // Since `a` is a byte array in the LLVM output, the basic heuristic will + // also protect this function. + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: local_var_addr_used_indirectly +#[no_mangle] +pub fn local_var_addr_used_indirectly(f: fn(bool)) { + let a = 5; + let a_addr = &a as *const _ as usize; + f(a_addr & 0x10 == 0); + + // This function takes the address of a local variable taken. Although this + // address is never used as a way to refer to stack memory, the `strong` + // heuristic adds stack smash protection. This is also the case in C++: + // ``` + // cat << EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk + // #include + // void f(void (*g)(bool)) { + // int32_t x; + // g((reinterpret_cast(&x) & 0x10U) == 0); + // } + // EOF + // ``` + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: local_string_addr_taken +#[no_mangle] +pub fn local_string_addr_taken(f: fn(&String)) { + // CHECK-DAG: .seh_endprologue + let x = String::new(); + f(&x); + + // Taking the address of the local variable `x` leads to stack smash + // protection with the `strong` heuristic, but not with the `basic` + // heuristic. It does not matter that the reference is not mut. + // + // An interesting note is that a similar function in C++ *would* be + // protected by the `basic` heuristic, because `std::string` has a char + // array internally as a small object optimization: + // ``` + // cat < + // void f(void (*g)(const std::string&)) { + // std::string x; + // g(x); + // } + // EOF + // ``` + // + + // We should have a __security_check_cookie call in `all` and `strong` modes but + // LLVM does not support generating stack protectors in functions with funclet + // based EH personalities. + // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4 + // all-NOT: __security_check_cookie + // strong-NOT: __security_check_cookie + + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc +} + +pub trait SelfByRef { + fn f(&self) -> i32; +} + +impl SelfByRef for i32 { + fn f(&self) -> i32 { + return self + 1; + } +} + +// CHECK-LABEL: local_var_addr_taken_used_locally_only +#[no_mangle] +pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) { + let x = factory(); + let g = x.f(); + sink(g); + + // Even though the local variable conceptually has its address taken, as + // it's passed by reference to the trait function, the use of the reference + // is easily inlined. There is therefore no stack smash protection even with + // the `strong` heuristic. + + // all: __security_check_cookie + // strong-NOT: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +pub struct Gigastruct { + does: u64, + not: u64, + have: u64, + array: u64, + members: u64, +} + +// CHECK-LABEL: local_large_var_moved +#[no_mangle] +pub fn local_large_var_moved(f: fn(Gigastruct)) { + let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }; + f(x); + + // Even though the local variable conceptually doesn't have its address + // taken, it's so large that the "move" is implemented with a reference to a + // stack-local variable in the ABI. Consequently, this function *is* + // protected. This is also the case for rvalue-references in C++, + // regardless of struct size: + // ``` + // cat < + // #include + // void f(void (*g)(uint64_t&&)) { + // uint64_t x; + // g(std::move(x)); + // } + // EOF + // ``` + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: local_large_var_cloned +#[no_mangle] +pub fn local_large_var_cloned(f: fn(Gigastruct)) { + f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }); + + // A new instance of `Gigastruct` is passed to `f()`, without any apparent + // connection to this stack frame. Still, since instances of `Gigastruct` + // are sufficiently large, it is allocated in the caller stack frame and + // passed as a pointer. As such, this function is *also* protected, just + // like `local_large_var_moved`. This is also the case for pass-by-value + // of sufficiently large structs in C++: + // ``` + // cat < + // #include + // struct Gigastruct { uint64_t a, b, c, d, e; }; + // void f(void (*g)(Gigastruct)) { + // g(Gigastruct{}); + // } + // EOF + // ``` + + // all: __security_check_cookie + // strong: __security_check_cookie + // basic: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +extern "C" { + // A call to an external `alloca` function is *not* recognized as an + // `alloca(3)` operation. This function is a compiler built-in, as the + // man page explains. Clang translates it to an LLVM `alloca` + // instruction with a count argument, which is also what the LLVM stack + // protector heuristics looks for. The man page for `alloca(3)` details + // a way to avoid using the compiler built-in: pass a -std=c11 + // argument, *and* don't include . Though this leads to an + // external alloca() function being called, it doesn't lead to stack + // protection being included. It even fails with a linker error + // "undefined reference to `alloca'". Example: + // ``` + // cat< + // void * alloca(size_t); + // void f(void (*g)(void*)) { + // void * p = alloca(10); + // g(p); + // } + // int main() { return 0; } + // EOF + // ``` + // The following tests demonstrate that calls to an external `alloca` + // function in Rust also doesn't trigger stack protection. + + fn alloca(size: usize) -> *mut (); +} + +// CHECK-LABEL: alloca_small_compile_time_constant_arg +#[no_mangle] +pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { + f(unsafe { alloca(8) }); + + // all: __security_check_cookie + // strong-NOT: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: alloca_large_compile_time_constant_arg +#[no_mangle] +pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { + f(unsafe { alloca(9) }); + + // all: __security_check_cookie + // strong-NOT: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// CHECK-LABEL: alloca_dynamic_arg +#[no_mangle] +pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { + f(unsafe { alloca(n) }); + + // all: __security_check_cookie + // strong-NOT: __security_check_cookie + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// The question then is: in what ways can Rust code generate array-`alloca` +// LLVM instructions? This appears to only be generated by +// rustc_codegen_ssa::traits::Builder::array_alloca() through +// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT +// this is support for the "unsized locals" unstable feature: +// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html. + +// CHECK-LABEL: unsized_fn_param +#[no_mangle] +pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { + let n = if l { 1 } else { 2 }; + f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from + + // Even though slices are conceptually passed by-value both into this + // function and into `f()`, this is implemented with pass-by-reference + // using a suitably constructed fat-pointer (as if the functions + // accepted &[u8]). This function therefore doesn't need dynamic array + // alloca, and is therefore not protected by the `strong` or `basic` + // heuristics. + + // We should have a __security_check_cookie call in `all` and `strong` modes but + // LLVM does not support generating stack protectors in functions with funclet + // based EH personalities. + // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4 + // all-NOT: __security_check_cookie + // strong-NOT: __security_check_cookie + + // basic-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs new file mode 100644 index 00000000000..ae281cb95da --- /dev/null +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect.rs @@ -0,0 +1,345 @@ +//@ revisions: all strong basic none missing +//@ assembly-output: emit-asm +//@ ignore-apple slightly different policy on stack protection of arrays +//@ ignore-msvc stack check code uses different function names +//@ ignore-nvptx64 stack protector is not supported +//@ ignore-wasm32-bare +//@ [all] compile-flags: -Z stack-protector=all +//@ [strong] compile-flags: -Z stack-protector=strong +//@ [basic] compile-flags: -Z stack-protector=basic +//@ [none] compile-flags: -Z stack-protector=none +//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled + +// NOTE: the heuristics for stack smash protection inappropriately rely on types in LLVM IR, +// despite those types having no semantic meaning. This means that the `basic` and `strong` +// settings do not behave in a coherent way. This is a known issue in LLVM. +// See comments on https://github.com/rust-lang/rust/issues/114903. + +#![crate_type = "lib"] +#![allow(internal_features)] +#![feature(unsized_fn_params)] + +// CHECK-LABEL: emptyfn{{:|\[}} +#[no_mangle] +pub fn emptyfn() { + // all: __stack_chk_fail + // strong-NOT: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: array_char{{:|\[}} +#[no_mangle] +pub fn array_char(f: fn(*const char)) { + let a = ['c'; 1]; + let b = ['d'; 3]; + let c = ['e'; 15]; + + f(&a as *const _); + f(&b as *const _); + f(&c as *const _); + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: array_u8_1{{:|\[}} +#[no_mangle] +pub fn array_u8_1(f: fn(*const u8)) { + let a = [0u8; 1]; + f(&a as *const _); + + // The 'strong' heuristic adds stack protection to functions with local + // array variables regardless of their size. + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: array_u8_small{{:|\[}} +#[no_mangle] +pub fn array_u8_small(f: fn(*const u8)) { + let a = [0u8; 2]; + let b = [0u8; 7]; + f(&a as *const _); + f(&b as *const _); + + // Small arrays do not lead to stack protection by the 'basic' heuristic. + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: array_u8_large{{:|\[}} +#[no_mangle] +pub fn array_u8_large(f: fn(*const u8)) { + let a = [0u8; 9]; + f(&a as *const _); + + // Since `a` is a byte array with size greater than 8, the basic heuristic + // will also protect this function. + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +#[derive(Copy, Clone)] +pub struct ByteSizedNewtype(u8); + +// CHECK-LABEL: array_bytesizednewtype_9{{:|\[}} +#[no_mangle] +pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { + let a = [ByteSizedNewtype(0); 9]; + f(&a as *const _); + + // Since `a` is a byte array in the LLVM output, the basic heuristic will + // also protect this function. + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: local_var_addr_used_indirectly{{:|\[}} +#[no_mangle] +pub fn local_var_addr_used_indirectly(f: fn(bool)) { + let a = 5; + let a_addr = &a as *const _ as usize; + f(a_addr & 0x10 == 0); + + // This function takes the address of a local variable taken. Although this + // address is never used as a way to refer to stack memory, the `strong` + // heuristic adds stack smash protection. This is also the case in C++: + // ``` + // cat << EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk + // #include + // void f(void (*g)(bool)) { + // int32_t x; + // g((reinterpret_cast(&x) & 0x10U) == 0); + // } + // EOF + // ``` + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: local_string_addr_taken{{:|\[}} +#[no_mangle] +pub fn local_string_addr_taken(f: fn(&String)) { + let x = String::new(); + f(&x); + + // Taking the address of the local variable `x` leads to stack smash + // protection. It does not matter that the reference is not mut. + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +pub trait SelfByRef { + fn f(&self) -> i32; +} + +impl SelfByRef for i32 { + fn f(&self) -> i32 { + return self + 1; + } +} + +// CHECK-LABEL: local_var_addr_taken_used_locally_only{{:|\[}} +#[no_mangle] +pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) { + let x = factory(); + let g = x.f(); + sink(g); + + // Even though the local variable conceptually has its address taken, as + // it's passed by reference to the trait function, the use of the reference + // is easily inlined. There is therefore no stack smash protection even with + // the `strong` heuristic. + + // all: __stack_chk_fail + // strong-NOT: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +pub struct Gigastruct { + does: u64, + not: u64, + have: u64, + array: u64, + members: u64, +} + +// CHECK-LABEL: local_large_var_moved{{:|\[}} +#[no_mangle] +pub fn local_large_var_moved(f: fn(Gigastruct)) { + let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }; + f(x); + + // Even though the local variable conceptually doesn't have its address + // taken, it's so large that the "move" is implemented with a reference to a + // stack-local variable in the ABI. Consequently, this function *is* + // protected. This is also the case for rvalue-references in C++, + // regardless of struct size: + // ``` + // cat < + // #include + // void f(void (*g)(uint64_t&&)) { + // uint64_t x; + // g(std::move(x)); + // } + // EOF + // ``` + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: local_large_var_cloned{{:|\[}} +#[no_mangle] +pub fn local_large_var_cloned(f: fn(Gigastruct)) { + f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }); + + // A new instance of `Gigastruct` is passed to `f()`, without any apparent + // connection to this stack frame. Still, since instances of `Gigastruct` + // are sufficiently large, it is allocated in the caller stack frame and + // passed as a pointer. As such, this function is *also* protected, just + // like `local_large_var_moved`. This is also the case for pass-by-value + // of sufficiently large structs in C++: + // ``` + // cat < + // #include + // struct Gigastruct { uint64_t a, b, c, d, e; }; + // void f(void (*g)(Gigastruct)) { + // g(Gigastruct{}); + // } + // EOF + // ``` + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +extern "C" { + // A call to an external `alloca` function is *not* recognized as an + // `alloca(3)` operation. This function is a compiler built-in, as the + // man page explains. Clang translates it to an LLVM `alloca` + // instruction with a count argument, which is also what the LLVM stack + // protector heuristics looks for. The man page for `alloca(3)` details + // a way to avoid using the compiler built-in: pass a -std=c11 + // argument, *and* don't include . Though this leads to an + // external alloca() function being called, it doesn't lead to stack + // protection being included. It even fails with a linker error + // "undefined reference to `alloca'". Example: + // ``` + // cat< + // void * alloca(size_t); + // void f(void (*g)(void*)) { + // void * p = alloca(10); + // g(p); + // } + // int main() { return 0; } + // EOF + // ``` + // The following tests demonstrate that calls to an external `alloca` + // function in Rust also doesn't trigger stack protection. + + fn alloca(size: usize) -> *mut (); +} + +// CHECK-LABEL: alloca_small_compile_time_constant_arg{{:|\[}} +#[no_mangle] +pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { + f(unsafe { alloca(8) }); + + // all: __stack_chk_fail + // strong-NOT: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: alloca_large_compile_time_constant_arg{{:|\[}} +#[no_mangle] +pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { + f(unsafe { alloca(9) }); + + // all: __stack_chk_fail + // strong-NOT: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: alloca_dynamic_arg{{:|\[}} +#[no_mangle] +pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { + f(unsafe { alloca(n) }); + + // all: __stack_chk_fail + // strong-NOT: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// The question then is: in what ways can Rust code generate array-`alloca` +// LLVM instructions? This appears to only be generated by +// rustc_codegen_ssa::traits::Builder::array_alloca() through +// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT +// this is support for the "unsized locals" unstable feature: +// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html. + +// CHECK-LABEL: unsized_fn_param{{:|\[}} +#[no_mangle] +pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { + let n = if l { 1 } else { 2 }; + f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from + + // Even though slices are conceptually passed by-value both into this + // function and into `f()`, this is implemented with pass-by-reference + // using a suitably constructed fat-pointer (as if the functions + // accepted &[u8]). This function therefore doesn't need dynamic array + // alloca, and is therefore not protected by the `strong` or `basic` + // heuristics. + + // all: __stack_chk_fail + // strong-NOT: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} diff --git a/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs b/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs new file mode 100644 index 00000000000..a937256a60f --- /dev/null +++ b/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs @@ -0,0 +1,281 @@ +// Test that stack smash protection code is emitted for all tier1 and tier2 +// targets, with the exception of nvptx64-nvidia-cuda +// +//@ add-core-stubs +//@ revisions: r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 +//@ revisions: r24 r25 r26 r27 r28 r29 r30 r31 r32 r33 r36 r37 r38 r39 r40 r41 r42 r43 r44 +//@ revisions: r45 r46 r47 r48 r49 r50 r51 r52 r53 r54 r55 r56 r57 r58 r59 r60 r61 r62 r63 r64 r65 +//@ revisions: r66 r67 r68 r69 r70 r71 r72 r73 r74 r75 r76 r77 r78 r79 r80 r81 r82 r83 r84 r85 +//@ assembly-output: emit-asm +//@ [r1] compile-flags: --target aarch64-unknown-linux-gnu +//@ [r1] needs-llvm-components: aarch64 +//@ [r2] compile-flags: --target i686-pc-windows-gnu +//@ [r2] needs-llvm-components: x86 +//@ [r3] compile-flags: --target i686-pc-windows-msvc +//@ [r3] needs-llvm-components: x86 +//@ [r4] compile-flags: --target i686-unknown-linux-gnu +//@ [r4] needs-llvm-components: x86 +//@ [r5] compile-flags: --target x86_64-apple-darwin +//@ [r5] needs-llvm-components: x86 +//@ [r6] compile-flags: --target x86_64-pc-windows-gnu +//@ [r6] needs-llvm-components: x86 +//@ [r7] compile-flags: --target x86_64-pc-windows-msvc +//@ [r7] needs-llvm-components: x86 +//@ [r8] compile-flags: --target x86_64-unknown-linux-gnu +//@ [r8] needs-llvm-components: x86 +//@ [r9] compile-flags: --target aarch64-apple-darwin +//@ [r9] needs-llvm-components: aarch64 +//@ [r10] compile-flags: --target aarch64-apple-ios +//@ [r10] needs-llvm-components: aarch64 +//@ [r11] compile-flags: --target aarch64-unknown-fuchsia +//@ [r11] needs-llvm-components: aarch64 +//@ [r12] compile-flags: --target aarch64-linux-android +//@ [r12] needs-llvm-components: aarch64 +//@ [r13] compile-flags: --target aarch64-pc-windows-msvc +//@ [r13] needs-llvm-components: aarch64 +//@ [r14] compile-flags: --target aarch64-unknown-linux-musl +//@ [r14] needs-llvm-components: aarch64 +//@ [r15] compile-flags: --target aarch64-unknown-none +//@ [r15] needs-llvm-components: aarch64 +//@ [r16] compile-flags: --target aarch64-unknown-none-softfloat +//@ [r16] needs-llvm-components: aarch64 +//@ [r17] compile-flags: --target arm-linux-androideabi +//@ [r17] needs-llvm-components: arm +//@ [r18] compile-flags: --target arm-unknown-linux-gnueabi +//@ [r18] needs-llvm-components: arm +//@ [r19] compile-flags: --target arm-unknown-linux-gnueabihf +//@ [r19] needs-llvm-components: arm +//@ [r20] compile-flags: --target arm-unknown-linux-musleabi +//@ [r20] needs-llvm-components: arm +//@ [r21] compile-flags: --target arm-unknown-linux-musleabihf +//@ [r21] needs-llvm-components: arm +//@ [r22] compile-flags: --target armebv7r-none-eabi +//@ [r22] needs-llvm-components: arm +//@ [r23] compile-flags: --target armebv7r-none-eabihf +//@ [r23] needs-llvm-components: arm +//@ [r24] compile-flags: --target armv5te-unknown-linux-gnueabi +//@ [r24] needs-llvm-components: arm +//@ [r25] compile-flags: --target armv5te-unknown-linux-musleabi +//@ [r25] needs-llvm-components: arm +//@ [r26] compile-flags: --target armv7-linux-androideabi +//@ [r26] needs-llvm-components: arm +//@ [r27] compile-flags: --target armv7a-none-eabi +//@ [r27] needs-llvm-components: arm +//@ [r28] compile-flags: --target armv7r-none-eabi +//@ [r28] needs-llvm-components: arm +//@ [r29] compile-flags: --target armv7r-none-eabihf +//@ [r29] needs-llvm-components: arm +//@ [r30] compile-flags: --target armv7-unknown-linux-gnueabi +//@ [r30] needs-llvm-components: arm +//@ [r31] compile-flags: --target armv7-unknown-linux-gnueabihf +//@ [r31] needs-llvm-components: arm +//@ [r32] compile-flags: --target armv7-unknown-linux-musleabi +//@ [r32] needs-llvm-components: arm +//@ [r33] compile-flags: --target armv7-unknown-linux-musleabihf +//@ [r33] needs-llvm-components: arm +//@ [r36] compile-flags: --target i586-unknown-linux-gnu +//@ [r36] needs-llvm-components: x86 +//@ [r37] compile-flags: --target i586-unknown-linux-musl +//@ [r37] needs-llvm-components: x86 +//@ [r38] compile-flags: --target i686-linux-android +//@ [r38] needs-llvm-components: x86 +//@ [r39] compile-flags: --target i686-unknown-freebsd +//@ [r39] needs-llvm-components: x86 +//@ [r40] compile-flags: --target i686-unknown-linux-musl +//@ [r40] needs-llvm-components: x86 +//@ [r41] compile-flags: --target mips-unknown-linux-gnu +//@ [r41] needs-llvm-components: mips +//@ [r42] compile-flags: --target mips-unknown-linux-musl +//@ [r42] needs-llvm-components: mips +//@ [r43] compile-flags: --target mips64-unknown-linux-gnuabi64 +//@ [r43] needs-llvm-components: mips +//@ [r44] compile-flags: --target mips64-unknown-linux-muslabi64 +//@ [r44] needs-llvm-components: mips +//@ [r45] compile-flags: --target mips64el-unknown-linux-gnuabi64 +//@ [r45] needs-llvm-components: mips +//@ [r46] compile-flags: --target mips64el-unknown-linux-muslabi64 +//@ [r46] needs-llvm-components: mips +//@ [r47] compile-flags: --target mipsel-unknown-linux-gnu +//@ [r47] needs-llvm-components: mips +//@ [r48] compile-flags: --target mipsel-unknown-linux-musl +//@ [r48] needs-llvm-components: mips +//@ [r49] compile-flags: --target nvptx64-nvidia-cuda +//@ [r49] needs-llvm-components: nvptx +//@ [r50] compile-flags: --target powerpc-unknown-linux-gnu +//@ [r50] needs-llvm-components: powerpc +//@ [r51] compile-flags: --target powerpc64-unknown-linux-gnu +//@ [r51] needs-llvm-components: powerpc +//@ [r52] compile-flags: --target powerpc64le-unknown-linux-gnu +//@ [r52] needs-llvm-components: powerpc +//@ [r53] compile-flags: --target riscv32i-unknown-none-elf +//@ [r53] needs-llvm-components: riscv +//@ [r54] compile-flags: --target riscv32imac-unknown-none-elf +//@ [r54] needs-llvm-components: riscv +//@ [r55] compile-flags:--target riscv32imc-unknown-none-elf +//@ [r55] needs-llvm-components: riscv +//@ [r56] compile-flags:--target riscv64gc-unknown-linux-gnu +//@ [r56] needs-llvm-components: riscv +//@ [r57] compile-flags:--target riscv64gc-unknown-none-elf +//@ [r57] needs-llvm-components: riscv +//@ [r58] compile-flags:--target riscv64imac-unknown-none-elf +//@ [r58] needs-llvm-components: riscv +//@ [r59] compile-flags:--target s390x-unknown-linux-gnu +//@ [r59] needs-llvm-components: systemz +//@ [r60] compile-flags:--target sparc64-unknown-linux-gnu +//@ [r60] needs-llvm-components: sparc +//@ [r61] compile-flags:--target sparcv9-sun-solaris +//@ [r61] needs-llvm-components: sparc +//@ [r62] compile-flags:--target thumbv6m-none-eabi +//@ [r62] needs-llvm-components: arm +//@ [r63] compile-flags:--target thumbv7em-none-eabi +//@ [r63] needs-llvm-components: arm +//@ [r64] compile-flags:--target thumbv7em-none-eabihf +//@ [r64] needs-llvm-components: arm +//@ [r65] compile-flags:--target thumbv7m-none-eabi +//@ [r65] needs-llvm-components: arm +//@ [r66] compile-flags:--target thumbv7neon-linux-androideabi +//@ [r66] needs-llvm-components: arm +//@ [r67] compile-flags:--target thumbv7neon-unknown-linux-gnueabihf +//@ [r67] needs-llvm-components: arm +//@ [r68] compile-flags:--target thumbv8m.base-none-eabi +//@ [r68] needs-llvm-components: arm +//@ [r69] compile-flags:--target thumbv8m.main-none-eabi +//@ [r69] needs-llvm-components: arm +//@ [r70] compile-flags:--target thumbv8m.main-none-eabihf +//@ [r70] needs-llvm-components: arm +//@ [r71] compile-flags:--target wasm32-unknown-emscripten +//@ [r71] needs-llvm-components: webassembly +//@ [r72] compile-flags:--target wasm32-unknown-unknown +//@ [r72] needs-llvm-components: webassembly +//@ [r73] compile-flags:--target wasm32-wasip1 +//@ [r73] needs-llvm-components: webassembly +//@ [r74] compile-flags:--target wasm32-wasip1-threads +//@ [r74] needs-llvm-components: webassembly +//@ [r75] compile-flags:--target x86_64-apple-ios +//@ [r75] needs-llvm-components: x86 +//@ [r76] compile-flags:--target x86_64-fortanix-unknown-sgx +//@ [r76] needs-llvm-components: x86 +//@ [r77] compile-flags:--target x86_64-unknown-fuchsia +//@ [r77] needs-llvm-components: x86 +//@ [r78] compile-flags:--target x86_64-linux-android +//@ [r78] needs-llvm-components: x86 +//@ [r79] compile-flags:--target x86_64-pc-solaris +//@ [r79] needs-llvm-components: x86 +//@ [r80] compile-flags:--target x86_64-unknown-freebsd +//@ [r80] needs-llvm-components: x86 +//@ [r81] compile-flags:--target x86_64-unknown-illumos +//@ [r81] needs-llvm-components: x86 +//@ [r82] compile-flags:--target x86_64-unknown-linux-gnux32 +//@ [r82] needs-llvm-components: x86 +//@ [r83] compile-flags:--target x86_64-unknown-linux-musl +//@ [r83] needs-llvm-components: x86 +//@ [r84] compile-flags:--target x86_64-unknown-netbsd +//@ [r84] needs-llvm-components: x86 +//@ [r85] compile-flags: --target x86_64-unknown-redox +//@ [r85] needs-llvm-components: x86 +//@ compile-flags: -Z stack-protector=all +//@ compile-flags: -C opt-level=2 + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub fn foo() { + // CHECK: foo{{:|()}} + + // MSVC does the stack checking within a stack-check function: + // r3: calll @__security_check_cookie + // r7: callq __security_check_cookie + // r13: bl __security_check_cookie + + // cuda doesn't support stack-smash protection + // r49-NOT: __security_check_cookie + // r49-NOT: __stack_chk_fail + + // Other targets do stack checking within the function, and call a failure function on error + // r1: __stack_chk_fail + // r2: __stack_chk_fail + // r4: __stack_chk_fail + // r5: __stack_chk_fail + // r6: __stack_chk_fail + // r8: __stack_chk_fail + // r9: __stack_chk_fail + // r10: __stack_chk_fail + // r11: __stack_chk_fail + // r12: __stack_chk_fail + // r14: __stack_chk_fail + // r15: __stack_chk_fail + // r16: __stack_chk_fail + // r17: __stack_chk_fail + // r18: __stack_chk_fail + // r19: __stack_chk_fail + // r20: __stack_chk_fail + // r21: __stack_chk_fail + // r22: __stack_chk_fail + // r23: __stack_chk_fail + // r24: __stack_chk_fail + // r25: __stack_chk_fail + // r26: __stack_chk_fail + // r27: __stack_chk_fail + // r28: __stack_chk_fail + // r29: __stack_chk_fail + // r30: __stack_chk_fail + // r31: __stack_chk_fail + // r32: __stack_chk_fail + // r33: __stack_chk_fail + // r34: __stack_chk_fail + // r36: __stack_chk_fail + // r37: __stack_chk_fail + // r38: __stack_chk_fail + // r39: __stack_chk_fail + // r40: __stack_chk_fail + // r41: __stack_chk_fail + // r42: __stack_chk_fail + // r43: __stack_chk_fail + // r44: __stack_chk_fail + // r45: __stack_chk_fail + // r46: __stack_chk_fail + // r47: __stack_chk_fail + // r48: __stack_chk_fail + // r50: __stack_chk_fail + // r51: __stack_chk_fail + // r52: __stack_chk_fail + // r53: __stack_chk_fail + // r54: __stack_chk_fail + // r55: __stack_chk_fail + // r56: __stack_chk_fail + // r57: __stack_chk_fail + // r58: __stack_chk_fail + // r59: __stack_chk_fail + // r60: __stack_chk_fail + // r61: __stack_chk_fail + // r62: __stack_chk_fail + // r63: __stack_chk_fail + // r64: __stack_chk_fail + // r65: __stack_chk_fail + // r66: __stack_chk_fail + // r67: __stack_chk_fail + // r68: __stack_chk_fail + // r69: __stack_chk_fail + // r70: __stack_chk_fail + // r71: __stack_chk_fail + // r72: __stack_chk_fail + // r73: __stack_chk_fail + // r74: __stack_chk_fail + // r75: __stack_chk_fail + // r76: __stack_chk_fail + // r77: __stack_chk_fail + // r78: __stack_chk_fail + // r79: __stack_chk_fail + // r80: __stack_chk_fail + // r81: __stack_chk_fail + // r82: __stack_chk_fail + // r83: __stack_chk_fail + // r84: __stack_chk_fail + // r85: __stack_chk_fail +} diff --git a/tests/assembly-llvm/static-relocation-model.rs b/tests/assembly-llvm/static-relocation-model.rs new file mode 100644 index 00000000000..35ad94133b2 --- /dev/null +++ b/tests/assembly-llvm/static-relocation-model.rs @@ -0,0 +1,69 @@ +//@ add-core-stubs +//@ revisions: x64 A64 ppc64le +//@ assembly-output: emit-asm +//@ [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static +//@ [x64] needs-llvm-components: x86 +//@ [A64] compile-flags: --target aarch64-unknown-linux-gnu -Crelocation-model=static +//@ [A64] needs-llvm-components: aarch64 +//@ [ppc64le] compile-flags: --target powerpc64le-unknown-linux-gnu -Crelocation-model=static +//@ [ppc64le] needs-llvm-components: powerpc + +#![feature(no_core, lang_items)] +#![no_core] +#![crate_type = "rlib"] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub static PIERIS: u8 = 42; + +extern "C" { + static EXOCHORDA: *mut u8; + + fn chaenomeles(); +} + +// CHECK-LABEL: banana: +// LLVM may produce either kind of `mov` here, depending on version and optimization level. +// x64: {{movb|movzbl}} chaenomeles{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} +// A64: adrp [[REG:[a-z0-9]+]], chaenomeles +// A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG]], :lo12:chaenomeles] +#[no_mangle] +pub fn banana() -> u8 { + unsafe { *(chaenomeles as *mut u8) } +} + +// CHECK-LABEL: peach: +// x64: {{movb|movzbl}} banana{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} +// A64: adrp [[REG2:[a-z0-9]+]], banana +// A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:banana] +#[no_mangle] +pub fn peach() -> u8 { + unsafe { *(banana as *mut u8) } +} + +// CHECK-LABEL: mango: +// x64: movq EXOCHORDA{{(\(%[a-z0-9]+\))?}}, %[[REG:[a-z0-9]+]] +// x64-NEXT: {{movb|movzbl}} (%[[REG]]), %{{[a-z0-9]+}} +// A64: adrp [[REG2:[a-z0-9]+]], EXOCHORDA +// A64-NEXT: ldr {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:EXOCHORDA] +#[no_mangle] +pub fn mango() -> u8 { + unsafe { *EXOCHORDA } +} + +// CHECK-LABEL: orange: +// x64: mov{{l|absq}} $PIERIS, %{{[a-z0-9]+}} +// A64: adrp [[REG2:[a-z0-9]+]], PIERIS +// A64-NEXT: add {{[a-z0-9]+}}, [[REG2]], :lo12:PIERIS +#[no_mangle] +pub fn orange() -> &'static u8 { + &PIERIS +} + +// For ppc64 we need to make sure to generate TOC entries even with the static relocation model +// ppc64le: .tc chaenomeles[TC],chaenomeles +// ppc64le: .tc banana[TC],banana +// ppc64le: .tc EXOCHORDA[TC],EXOCHORDA +// ppc64le: .tc PIERIS[TC],PIERIS diff --git a/tests/assembly-llvm/strict_provenance.rs b/tests/assembly-llvm/strict_provenance.rs new file mode 100644 index 00000000000..1a797670962 --- /dev/null +++ b/tests/assembly-llvm/strict_provenance.rs @@ -0,0 +1,37 @@ +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=1 +//@ only-x86_64 +//@ ignore-sgx +#![crate_type = "rlib"] + +// CHECK-LABEL: old_style +// CHECK: movq %{{.*}}, %rax +// CHECK: orq $1, %rax +// CHECK: retq +#[no_mangle] +pub fn old_style(a: *mut u8) -> *mut u8 { + (a as usize | 1) as *mut u8 +} + +// CHECK-LABEL: cheri_compat +// CHECK: movq %{{.*}}, %rax +// CHECK: orq $1, %rax +// CHECK: retq +#[no_mangle] +pub fn cheri_compat(a: *mut u8) -> *mut u8 { + let old = a as usize; + let new = old | 1; + let diff = new.wrapping_sub(old); + a.wrapping_add(diff) +} + +// CHECK-LABEL: definitely_not_a_null_pointer +// CHECK: movq %{{.*}}, %rax +// CHECK: orq $1, %rax +// CHECK: retq +#[no_mangle] +pub fn definitely_not_a_null_pointer(a: *mut u8) -> *mut u8 { + let old = a as usize; + let new = old | 1; + a.wrapping_sub(old).wrapping_add(new) +} diff --git a/tests/assembly-llvm/target-feature-multiple.rs b/tests/assembly-llvm/target-feature-multiple.rs new file mode 100644 index 00000000000..bc432d21931 --- /dev/null +++ b/tests/assembly-llvm/target-feature-multiple.rs @@ -0,0 +1,40 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ needs-llvm-components: x86 +//@ revisions: TWOFLAGS SINGLEFLAG +//@ compile-flags: --target=x86_64-unknown-linux-gnu +//@ [TWOFLAGS] compile-flags: -C target-feature=+rdrnd -C target-feature=+rdseed +//@ [SINGLEFLAG] compile-flags: -C target-feature=+rdrnd,+rdseed + +// Target features set via flags aren't necessarily reflected in the IR, so the only way to test +// them is to build code that requires the features to be enabled to work. +// +// In this particular test if `rdrnd,rdseed` somehow didn't make it to LLVM, the instruction +// selection should crash. +// +// > LLVM ERROR: Cannot select: 0x7f00f400c010: i32,i32,ch = X86ISD::RDSEED 0x7f00f400bfa8:2 +// > In function: foo +// +// See also tests/codegen/target-feature-overrides.rs +#![feature(no_core, lang_items, link_llvm_intrinsics, abi_unadjusted)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +// Use of these requires target features to be enabled +extern "unadjusted" { + #[link_name = "llvm.x86.rdrand.32"] + fn x86_rdrand32_step() -> (u32, i32); + #[link_name = "llvm.x86.rdseed.32"] + fn x86_rdseed32_step() -> (u32, i32); +} + +#[no_mangle] +pub unsafe fn foo() -> (u32, u32) { + // CHECK-LABEL: foo: + // CHECK: rdrand + // CHECK: rdseed + (x86_rdrand32_step().0, x86_rdseed32_step().0) +} diff --git a/tests/assembly-llvm/targets/targets-amdgpu.rs b/tests/assembly-llvm/targets/targets-amdgpu.rs new file mode 100644 index 00000000000..1d10b8fc315 --- /dev/null +++ b/tests/assembly-llvm/targets/targets-amdgpu.rs @@ -0,0 +1,22 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +// ignore-tidy-linelength +//@ revisions: amdgcn_amd_amdhsa +//@ [amdgcn_amd_amdhsa] compile-flags: --target amdgcn-amd-amdhsa -Ctarget-cpu=gfx900 +//@ [amdgcn_amd_amdhsa] needs-llvm-components: amdgpu + +// Sanity-check that each target can produce assembly code. + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +pub fn test() -> u8 { + 42 +} + +// CHECK: .version diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs new file mode 100644 index 00000000000..edf16548e7d --- /dev/null +++ b/tests/assembly-llvm/targets/targets-elf.rs @@ -0,0 +1,734 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +// ignore-tidy-linelength +//@ revisions: aarch64_be_unknown_linux_gnu +//@ [aarch64_be_unknown_linux_gnu] compile-flags: --target aarch64_be-unknown-linux-gnu +//@ [aarch64_be_unknown_linux_gnu] needs-llvm-components: aarch64 +//@ revisions: aarch64_be_unknown_linux_gnu_ilp32 +//@ [aarch64_be_unknown_linux_gnu_ilp32] compile-flags: --target aarch64_be-unknown-linux-gnu_ilp32 +//@ [aarch64_be_unknown_linux_gnu_ilp32] needs-llvm-components: aarch64 +//@ revisions: aarch64_be_unknown_netbsd +//@ [aarch64_be_unknown_netbsd] compile-flags: --target aarch64_be-unknown-netbsd +//@ [aarch64_be_unknown_netbsd] needs-llvm-components: aarch64 +//@ revisions: aarch64_kmc_solid_asp3 +//@ [aarch64_kmc_solid_asp3] compile-flags: --target aarch64-kmc-solid_asp3 +//@ [aarch64_kmc_solid_asp3] needs-llvm-components: aarch64 +//@ revisions: aarch64_linux_android +//@ [aarch64_linux_android] compile-flags: --target aarch64-linux-android +//@ [aarch64_linux_android] needs-llvm-components: aarch64 +//@ revisions: aarch64_nintendo_switch_freestanding +//@ [aarch64_nintendo_switch_freestanding] compile-flags: --target aarch64-nintendo-switch-freestanding +//@ [aarch64_nintendo_switch_freestanding] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_freebsd +//@ [aarch64_unknown_freebsd] compile-flags: --target aarch64-unknown-freebsd +//@ [aarch64_unknown_freebsd] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_fuchsia +//@ [aarch64_unknown_fuchsia] compile-flags: --target aarch64-unknown-fuchsia +//@ [aarch64_unknown_fuchsia] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_hermit +//@ [aarch64_unknown_hermit] compile-flags: --target aarch64-unknown-hermit +//@ [aarch64_unknown_hermit] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_illumos +//@ [aarch64_unknown_illumos] compile-flags: --target aarch64-unknown-illumos +//@ [aarch64_unknown_illumos] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_linux_gnu +//@ [aarch64_unknown_linux_gnu] compile-flags: --target aarch64-unknown-linux-gnu +//@ [aarch64_unknown_linux_gnu] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_linux_gnu_ilp32 +//@ [aarch64_unknown_linux_gnu_ilp32] compile-flags: --target aarch64-unknown-linux-gnu_ilp32 +//@ [aarch64_unknown_linux_gnu_ilp32] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_linux_musl +//@ [aarch64_unknown_linux_musl] compile-flags: --target aarch64-unknown-linux-musl +//@ [aarch64_unknown_linux_musl] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_linux_ohos +//@ [aarch64_unknown_linux_ohos] compile-flags: --target aarch64-unknown-linux-ohos +//@ [aarch64_unknown_linux_ohos] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_netbsd +//@ [aarch64_unknown_netbsd] compile-flags: --target aarch64-unknown-netbsd +//@ [aarch64_unknown_netbsd] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_none +//@ [aarch64_unknown_none] compile-flags: --target aarch64-unknown-none +//@ [aarch64_unknown_none] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_none_softfloat +//@ [aarch64_unknown_none_softfloat] compile-flags: --target aarch64-unknown-none-softfloat +//@ [aarch64_unknown_none_softfloat] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_nto_qnx700 +//@ [aarch64_unknown_nto_qnx700] compile-flags: --target aarch64-unknown-nto-qnx700 +//@ [aarch64_unknown_nto_qnx700] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_nto_qnx710 +//@ [aarch64_unknown_nto_qnx710] compile-flags: --target aarch64-unknown-nto-qnx710 +//@ [aarch64_unknown_nto_qnx710] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_nto_qnx710_iosock +//@ [aarch64_unknown_nto_qnx710_iosock] compile-flags: --target aarch64-unknown-nto-qnx710_iosock +//@ [aarch64_unknown_nto_qnx710_iosock] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_nto_qnx800 +//@ [aarch64_unknown_nto_qnx800] compile-flags: --target aarch64-unknown-nto-qnx800 +//@ [aarch64_unknown_nto_qnx800] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_openbsd +//@ [aarch64_unknown_openbsd] compile-flags: --target aarch64-unknown-openbsd +//@ [aarch64_unknown_openbsd] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_redox +//@ [aarch64_unknown_redox] compile-flags: --target aarch64-unknown-redox +//@ [aarch64_unknown_redox] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_teeos +//@ [aarch64_unknown_teeos] compile-flags: --target aarch64-unknown-teeos +//@ [aarch64_unknown_teeos] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_nuttx +//@ [aarch64_unknown_nuttx] compile-flags: --target aarch64-unknown-nuttx +//@ [aarch64_unknown_nuttx] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_trusty +//@ [aarch64_unknown_trusty] compile-flags: --target aarch64-unknown-trusty +//@ [aarch64_unknown_trusty] needs-llvm-components: aarch64 +//@ revisions: aarch64_wrs_vxworks +//@ [aarch64_wrs_vxworks] compile-flags: --target aarch64-wrs-vxworks +//@ [aarch64_wrs_vxworks] needs-llvm-components: aarch64 +//@ revisions: arm_linux_androideabi +//@ [arm_linux_androideabi] compile-flags: --target arm-linux-androideabi +//@ [arm_linux_androideabi] needs-llvm-components: arm +//@ revisions: arm_unknown_linux_gnueabi +//@ [arm_unknown_linux_gnueabi] compile-flags: --target arm-unknown-linux-gnueabi +//@ [arm_unknown_linux_gnueabi] needs-llvm-components: arm +//@ revisions: arm_unknown_linux_gnueabihf +//@ [arm_unknown_linux_gnueabihf] compile-flags: --target arm-unknown-linux-gnueabihf +//@ [arm_unknown_linux_gnueabihf] needs-llvm-components: arm +//@ revisions: arm_unknown_linux_musleabi +//@ [arm_unknown_linux_musleabi] compile-flags: --target arm-unknown-linux-musleabi +//@ [arm_unknown_linux_musleabi] needs-llvm-components: arm +//@ revisions: arm_unknown_linux_musleabihf +//@ [arm_unknown_linux_musleabihf] compile-flags: --target arm-unknown-linux-musleabihf +//@ [arm_unknown_linux_musleabihf] needs-llvm-components: arm +//@ revisions: armeb_unknown_linux_gnueabi +//@ [armeb_unknown_linux_gnueabi] compile-flags: --target armeb-unknown-linux-gnueabi +//@ [armeb_unknown_linux_gnueabi] needs-llvm-components: arm +//@ revisions: armebv7r_none_eabi +//@ [armebv7r_none_eabi] compile-flags: --target armebv7r-none-eabi +//@ [armebv7r_none_eabi] needs-llvm-components: arm +//@ revisions: armebv7r_none_eabihf +//@ [armebv7r_none_eabihf] compile-flags: --target armebv7r-none-eabihf +//@ [armebv7r_none_eabihf] needs-llvm-components: arm +//@ revisions: armv4t_none_eabi +//@ [armv4t_none_eabi] compile-flags: --target armv4t-none-eabi +//@ [armv4t_none_eabi] needs-llvm-components: arm +//@ revisions: armv4t_unknown_linux_gnueabi +//@ [armv4t_unknown_linux_gnueabi] compile-flags: --target armv4t-unknown-linux-gnueabi +//@ [armv4t_unknown_linux_gnueabi] needs-llvm-components: arm +//@ revisions: armv5te_none_eabi +//@ [armv5te_none_eabi] compile-flags: --target armv5te-none-eabi +//@ [armv5te_none_eabi] needs-llvm-components: arm +//@ revisions: armv5te_unknown_linux_gnueabi +//@ [armv5te_unknown_linux_gnueabi] compile-flags: --target armv5te-unknown-linux-gnueabi +//@ [armv5te_unknown_linux_gnueabi] needs-llvm-components: arm +//@ revisions: armv5te_unknown_linux_musleabi +//@ [armv5te_unknown_linux_musleabi] compile-flags: --target armv5te-unknown-linux-musleabi +//@ [armv5te_unknown_linux_musleabi] needs-llvm-components: arm +//@ revisions: armv5te_unknown_linux_uclibceabi +//@ [armv5te_unknown_linux_uclibceabi] compile-flags: --target armv5te-unknown-linux-uclibceabi +//@ [armv5te_unknown_linux_uclibceabi] needs-llvm-components: arm +//@ revisions: armv6_unknown_freebsd +//@ [armv6_unknown_freebsd] compile-flags: --target armv6-unknown-freebsd +//@ [armv6_unknown_freebsd] needs-llvm-components: arm +//@ revisions: armv6_unknown_netbsd_eabihf +//@ [armv6_unknown_netbsd_eabihf] compile-flags: --target armv6-unknown-netbsd-eabihf +//@ [armv6_unknown_netbsd_eabihf] needs-llvm-components: arm +//@ revisions: armv6k_nintendo_3ds +//@ [armv6k_nintendo_3ds] compile-flags: --target armv6k-nintendo-3ds +//@ [armv6k_nintendo_3ds] needs-llvm-components: arm +//@ revisions: armv7_linux_androideabi +//@ [armv7_linux_androideabi] compile-flags: --target armv7-linux-androideabi +//@ [armv7_linux_androideabi] needs-llvm-components: arm +//@ revisions: armv7_rtems_eabihf +//@ [armv7_rtems_eabihf] compile-flags: --target armv7-rtems-eabihf +//@ [armv7_rtems_eabihf] needs-llvm-components: arm +//@ revisions: armv7_sony_vita_newlibeabihf +//@ [armv7_sony_vita_newlibeabihf] compile-flags: --target armv7-sony-vita-newlibeabihf +//@ [armv7_sony_vita_newlibeabihf] needs-llvm-components: arm +//@ revisions: armv7_unknown_freebsd +//@ [armv7_unknown_freebsd] compile-flags: --target armv7-unknown-freebsd +//@ [armv7_unknown_freebsd] needs-llvm-components: arm +//@ revisions: armv7_unknown_linux_gnueabi +//@ [armv7_unknown_linux_gnueabi] compile-flags: --target armv7-unknown-linux-gnueabi +//@ [armv7_unknown_linux_gnueabi] needs-llvm-components: arm +//@ revisions: armv7_unknown_linux_gnueabihf +//@ [armv7_unknown_linux_gnueabihf] compile-flags: --target armv7-unknown-linux-gnueabihf +//@ [armv7_unknown_linux_gnueabihf] needs-llvm-components: arm +//@ revisions: armv7_unknown_linux_musleabi +//@ [armv7_unknown_linux_musleabi] compile-flags: --target armv7-unknown-linux-musleabi +//@ [armv7_unknown_linux_musleabi] needs-llvm-components: arm +//@ revisions: armv7_unknown_linux_musleabihf +//@ [armv7_unknown_linux_musleabihf] compile-flags: --target armv7-unknown-linux-musleabihf +//@ [armv7_unknown_linux_musleabihf] needs-llvm-components: arm +//@ revisions: armv7_unknown_linux_ohos +//@ [armv7_unknown_linux_ohos] compile-flags: --target armv7-unknown-linux-ohos +//@ [armv7_unknown_linux_ohos] needs-llvm-components: arm +//@ revisions: armv7_unknown_linux_uclibceabi +//@ [armv7_unknown_linux_uclibceabi] compile-flags: --target armv7-unknown-linux-uclibceabi +//@ [armv7_unknown_linux_uclibceabi] needs-llvm-components: arm +//@ revisions: armv7_unknown_linux_uclibceabihf +//@ [armv7_unknown_linux_uclibceabihf] compile-flags: --target armv7-unknown-linux-uclibceabihf +//@ [armv7_unknown_linux_uclibceabihf] needs-llvm-components: arm +//@ revisions: armv7_unknown_netbsd_eabihf +//@ [armv7_unknown_netbsd_eabihf] compile-flags: --target armv7-unknown-netbsd-eabihf +//@ [armv7_unknown_netbsd_eabihf] needs-llvm-components: arm +//@ revisions: armv7_unknown_trusty +//@ [armv7_unknown_trusty] compile-flags: --target armv7-unknown-trusty +//@ [armv7_unknown_trusty] needs-llvm-components: arm +//@ revisions: armv7_wrs_vxworks_eabihf +//@ [armv7_wrs_vxworks_eabihf] compile-flags: --target armv7-wrs-vxworks-eabihf +//@ [armv7_wrs_vxworks_eabihf] needs-llvm-components: arm +//@ revisions: armv7a_kmc_solid_asp3_eabi +//@ [armv7a_kmc_solid_asp3_eabi] compile-flags: --target armv7a-kmc-solid_asp3-eabi +//@ [armv7a_kmc_solid_asp3_eabi] needs-llvm-components: arm +//@ revisions: armv7a_kmc_solid_asp3_eabihf +//@ [armv7a_kmc_solid_asp3_eabihf] compile-flags: --target armv7a-kmc-solid_asp3-eabihf +//@ [armv7a_kmc_solid_asp3_eabihf] needs-llvm-components: arm +//@ revisions: armv7a_none_eabi +//@ [armv7a_none_eabi] compile-flags: --target armv7a-none-eabi +//@ [armv7a_none_eabi] needs-llvm-components: arm +//@ revisions: armv7a_none_eabihf +//@ [armv7a_none_eabihf] compile-flags: --target armv7a-none-eabihf +//@ [armv7a_none_eabihf] needs-llvm-components: arm +//@ revisions: armv7a_nuttx_eabi +//@ [armv7a_nuttx_eabi] compile-flags: --target armv7a-nuttx-eabi +//@ [armv7a_nuttx_eabi] needs-llvm-components: arm +//@ revisions: armv7a_nuttx_eabihf +//@ [armv7a_nuttx_eabihf] compile-flags: --target armv7a-nuttx-eabihf +//@ [armv7a_nuttx_eabihf] needs-llvm-components: arm +//@ revisions: armv7r_none_eabi +//@ [armv7r_none_eabi] compile-flags: --target armv7r-none-eabi +//@ [armv7r_none_eabi] needs-llvm-components: arm +//@ revisions: armv7r_none_eabihf +//@ [armv7r_none_eabihf] compile-flags: --target armv7r-none-eabihf +//@ [armv7r_none_eabihf] needs-llvm-components: arm +//@ revisions: armv8r_none_eabihf +//@ [armv8r_none_eabihf] compile-flags: --target armv8r-none-eabihf +//@ [armv8r_none_eabihf] needs-llvm-components: arm +// FIXME: disabled since it fails on CI saying the csky component is missing +/* + revisions: csky_unknown_linux_gnuabiv2 + [csky_unknown_linux_gnuabiv2] compile-flags: --target csky-unknown-linux-gnuabiv2 + [csky_unknown_linux_gnuabiv2] needs-llvm-components: csky + revisions: csky_unknown_linux_gnuabiv2hf + [csky_unknown_linux_gnuabiv2hf] compile-flags: --target csky-unknown-linux-gnuabiv2hf + [csky_unknown_linux_gnuabiv2hf] needs-llvm-components: csky +*/ +//@ revisions: hexagon_unknown_linux_musl +//@ [hexagon_unknown_linux_musl] compile-flags: --target hexagon-unknown-linux-musl +//@ [hexagon_unknown_linux_musl] needs-llvm-components: hexagon +//@ revisions: hexagon_unknown_none_elf +//@ [hexagon_unknown_none_elf] compile-flags: --target hexagon-unknown-none-elf +//@ [hexagon_unknown_none_elf] needs-llvm-components: hexagon +//@ revisions: i686_pc_nto_qnx700 +//@ [i686_pc_nto_qnx700] compile-flags: --target i686-pc-nto-qnx700 +//@ [i686_pc_nto_qnx700] needs-llvm-components: x86 +//@ revisions: i586_unknown_linux_gnu +//@ [i586_unknown_linux_gnu] compile-flags: --target i586-unknown-linux-gnu +//@ [i586_unknown_linux_gnu] needs-llvm-components: x86 +//@ revisions: i586_unknown_linux_musl +//@ [i586_unknown_linux_musl] compile-flags: --target i586-unknown-linux-musl +//@ [i586_unknown_linux_musl] needs-llvm-components: x86 +//@ revisions: i586_unknown_netbsd +//@ [i586_unknown_netbsd] compile-flags: --target i586-unknown-netbsd +//@ [i586_unknown_netbsd] needs-llvm-components: x86 +//@ revisions: i586_unknown_redox +//@ [i586_unknown_redox] compile-flags: --target i586-unknown-redox +//@ [i586_unknown_redox] needs-llvm-components: x86 +//@ revisions: i686_linux_android +//@ [i686_linux_android] compile-flags: --target i686-linux-android +//@ [i686_linux_android] needs-llvm-components: x86 +//@ revisions: i686_unknown_freebsd +//@ [i686_unknown_freebsd] compile-flags: --target i686-unknown-freebsd +//@ [i686_unknown_freebsd] needs-llvm-components: x86 +//@ revisions: i686_unknown_haiku +//@ [i686_unknown_haiku] compile-flags: --target i686-unknown-haiku +//@ [i686_unknown_haiku] needs-llvm-components: x86 +//@ revisions: i686_unknown_hurd_gnu +//@ [i686_unknown_hurd_gnu] compile-flags: --target i686-unknown-hurd-gnu +//@ [i686_unknown_hurd_gnu] needs-llvm-components: x86 +//@ revisions: i686_unknown_linux_gnu +//@ [i686_unknown_linux_gnu] compile-flags: --target i686-unknown-linux-gnu +//@ [i686_unknown_linux_gnu] needs-llvm-components: x86 +//@ revisions: i686_unknown_linux_musl +//@ [i686_unknown_linux_musl] compile-flags: --target i686-unknown-linux-musl +//@ [i686_unknown_linux_musl] needs-llvm-components: x86 +//@ revisions: i686_unknown_netbsd +//@ [i686_unknown_netbsd] compile-flags: --target i686-unknown-netbsd +//@ [i686_unknown_netbsd] needs-llvm-components: x86 +//@ revisions: i686_unknown_openbsd +//@ [i686_unknown_openbsd] compile-flags: --target i686-unknown-openbsd +//@ [i686_unknown_openbsd] needs-llvm-components: x86 +//@ revisions: i686_wrs_vxworks +//@ [i686_wrs_vxworks] compile-flags: --target i686-wrs-vxworks +//@ [i686_wrs_vxworks] needs-llvm-components: x86 +//@ revisions: loongarch32_unknown_none +//@ [loongarch32_unknown_none] compile-flags: --target loongarch32-unknown-none +//@ [loongarch32_unknown_none] needs-llvm-components: loongarch +//@ revisions: loongarch32_unknown_none_softfloat +//@ [loongarch32_unknown_none_softfloat] compile-flags: --target loongarch32-unknown-none-softfloat +//@ [loongarch32_unknown_none_softfloat] needs-llvm-components: loongarch +//@ revisions: loongarch64_unknown_linux_gnu +//@ [loongarch64_unknown_linux_gnu] compile-flags: --target loongarch64-unknown-linux-gnu +//@ [loongarch64_unknown_linux_gnu] needs-llvm-components: loongarch +//@ revisions: loongarch64_unknown_linux_musl +//@ [loongarch64_unknown_linux_musl] compile-flags: --target loongarch64-unknown-linux-musl +//@ [loongarch64_unknown_linux_musl] needs-llvm-components: loongarch +//@ revisions: loongarch64_unknown_linux_ohos +//@ [loongarch64_unknown_linux_ohos] compile-flags: --target loongarch64-unknown-linux-ohos +//@ [loongarch64_unknown_linux_ohos] needs-llvm-components: loongarch +//@ revisions: loongarch64_unknown_none +//@ [loongarch64_unknown_none] compile-flags: --target loongarch64-unknown-none +//@ [loongarch64_unknown_none] needs-llvm-components: loongarch +//@ revisions: loongarch64_unknown_none_softfloat +//@ [loongarch64_unknown_none_softfloat] compile-flags: --target loongarch64-unknown-none-softfloat +//@ [loongarch64_unknown_none_softfloat] needs-llvm-components: loongarch +//@ revisions: m68k_unknown_linux_gnu +//@ [m68k_unknown_linux_gnu] compile-flags: --target m68k-unknown-linux-gnu +//@ [m68k_unknown_linux_gnu] needs-llvm-components: m68k +//@ revisions: m68k_unknown_none_elf +//@ [m68k_unknown_none_elf] compile-flags: --target m68k-unknown-none-elf +//@ [m68k_unknown_none_elf] needs-llvm-components: m68k +//@ revisions: mips64_openwrt_linux_musl +//@ [mips64_openwrt_linux_musl] compile-flags: --target mips64-openwrt-linux-musl +//@ [mips64_openwrt_linux_musl] needs-llvm-components: mips +//@ revisions: mips64_unknown_linux_gnuabi64 +//@ [mips64_unknown_linux_gnuabi64] compile-flags: --target mips64-unknown-linux-gnuabi64 +//@ [mips64_unknown_linux_gnuabi64] needs-llvm-components: mips +//@ revisions: mips64_unknown_linux_muslabi64 +//@ [mips64_unknown_linux_muslabi64] compile-flags: --target mips64-unknown-linux-muslabi64 +//@ [mips64_unknown_linux_muslabi64] needs-llvm-components: mips +//@ revisions: mips64el_unknown_linux_gnuabi64 +//@ [mips64el_unknown_linux_gnuabi64] compile-flags: --target mips64el-unknown-linux-gnuabi64 +//@ [mips64el_unknown_linux_gnuabi64] needs-llvm-components: mips +//@ revisions: mips64el_unknown_linux_muslabi64 +//@ [mips64el_unknown_linux_muslabi64] compile-flags: --target mips64el-unknown-linux-muslabi64 +//@ [mips64el_unknown_linux_muslabi64] needs-llvm-components: mips +//@ revisions: mips_unknown_linux_gnu +//@ [mips_unknown_linux_gnu] compile-flags: --target mips-unknown-linux-gnu +//@ [mips_unknown_linux_gnu] needs-llvm-components: mips +//@ revisions: mips_unknown_linux_musl +//@ [mips_unknown_linux_musl] compile-flags: --target mips-unknown-linux-musl +//@ [mips_unknown_linux_musl] needs-llvm-components: mips +//@ revisions: mips_unknown_linux_uclibc +//@ [mips_unknown_linux_uclibc] compile-flags: --target mips-unknown-linux-uclibc +//@ [mips_unknown_linux_uclibc] needs-llvm-components: mips +//@ revisions: mips_mti_none_elf +//@ [mips_mti_none_elf] compile-flags: --target mips-mti-none-elf +//@ [mips_mti_none_elf] needs-llvm-components: mips +//@ revisions: mipsel_mti_none_elf +//@ [mipsel_mti_none_elf] compile-flags: --target mipsel-mti-none-elf +//@ [mipsel_mti_none_elf] needs-llvm-components: mips +//@ revisions: mipsel_sony_psp +//@ [mipsel_sony_psp] compile-flags: --target mipsel-sony-psp +//@ [mipsel_sony_psp] needs-llvm-components: mips +//@ revisions: mipsel_sony_psx +//@ [mipsel_sony_psx] compile-flags: --target mipsel-sony-psx +//@ [mipsel_sony_psx] needs-llvm-components: mips +//@ revisions: mipsel_unknown_linux_gnu +//@ [mipsel_unknown_linux_gnu] compile-flags: --target mipsel-unknown-linux-gnu +//@ [mipsel_unknown_linux_gnu] needs-llvm-components: mips +//@ revisions: mipsel_unknown_linux_musl +//@ [mipsel_unknown_linux_musl] compile-flags: --target mipsel-unknown-linux-musl +//@ [mipsel_unknown_linux_musl] needs-llvm-components: mips +//@ revisions: mipsel_unknown_linux_uclibc +//@ [mipsel_unknown_linux_uclibc] compile-flags: --target mipsel-unknown-linux-uclibc +//@ [mipsel_unknown_linux_uclibc] needs-llvm-components: mips +//@ revisions: mipsel_unknown_netbsd +//@ [mipsel_unknown_netbsd] compile-flags: --target mipsel-unknown-netbsd +//@ [mipsel_unknown_netbsd] needs-llvm-components: mips +//@ revisions: mipsel_unknown_none +//@ [mipsel_unknown_none] compile-flags: --target mipsel-unknown-none +//@ [mipsel_unknown_none] needs-llvm-components: mips +//@ revisions: mipsisa32r6_unknown_linux_gnu +//@ [mipsisa32r6_unknown_linux_gnu] compile-flags: --target mipsisa32r6-unknown-linux-gnu +//@ [mipsisa32r6_unknown_linux_gnu] needs-llvm-components: mips +//@ revisions: mipsisa32r6el_unknown_linux_gnu +//@ [mipsisa32r6el_unknown_linux_gnu] compile-flags: --target mipsisa32r6el-unknown-linux-gnu +//@ [mipsisa32r6el_unknown_linux_gnu] needs-llvm-components: mips +//@ revisions: mipsisa64r6_unknown_linux_gnuabi64 +//@ [mipsisa64r6_unknown_linux_gnuabi64] compile-flags: --target mipsisa64r6-unknown-linux-gnuabi64 +//@ [mipsisa64r6_unknown_linux_gnuabi64] needs-llvm-components: mips +//@ revisions: mipsisa64r6el_unknown_linux_gnuabi64 +//@ [mipsisa64r6el_unknown_linux_gnuabi64] compile-flags: --target mipsisa64r6el-unknown-linux-gnuabi64 +//@ [mipsisa64r6el_unknown_linux_gnuabi64] needs-llvm-components: mips +//@ revisions: msp430_none_elf +//@ [msp430_none_elf] compile-flags: --target msp430-none-elf +//@ [msp430_none_elf] needs-llvm-components: msp430 +//@ revisions: powerpc64_unknown_freebsd +//@ [powerpc64_unknown_freebsd] compile-flags: --target powerpc64-unknown-freebsd +//@ [powerpc64_unknown_freebsd] needs-llvm-components: powerpc +//@ revisions: powerpc64_unknown_linux_gnu +//@ [powerpc64_unknown_linux_gnu] compile-flags: --target powerpc64-unknown-linux-gnu +//@ [powerpc64_unknown_linux_gnu] needs-llvm-components: powerpc +//@ revisions: powerpc64_unknown_linux_musl +//@ [powerpc64_unknown_linux_musl] compile-flags: --target powerpc64-unknown-linux-musl +//@ [powerpc64_unknown_linux_musl] needs-llvm-components: powerpc +//@ revisions: powerpc64_unknown_openbsd +//@ [powerpc64_unknown_openbsd] compile-flags: --target powerpc64-unknown-openbsd +//@ [powerpc64_unknown_openbsd] needs-llvm-components: powerpc +//@ revisions: powerpc64_wrs_vxworks +//@ [powerpc64_wrs_vxworks] compile-flags: --target powerpc64-wrs-vxworks +//@ [powerpc64_wrs_vxworks] needs-llvm-components: powerpc +//@ revisions: powerpc64le_unknown_freebsd +//@ [powerpc64le_unknown_freebsd] compile-flags: --target powerpc64le-unknown-freebsd +//@ [powerpc64le_unknown_freebsd] needs-llvm-components: powerpc +//@ revisions: powerpc64le_unknown_linux_gnu +//@ [powerpc64le_unknown_linux_gnu] compile-flags: --target powerpc64le-unknown-linux-gnu +//@ [powerpc64le_unknown_linux_gnu] needs-llvm-components: powerpc +//@ revisions: powerpc64le_unknown_linux_musl +//@ [powerpc64le_unknown_linux_musl] compile-flags: --target powerpc64le-unknown-linux-musl +//@ [powerpc64le_unknown_linux_musl] needs-llvm-components: powerpc +//@ revisions: powerpc_unknown_freebsd +//@ [powerpc_unknown_freebsd] compile-flags: --target powerpc-unknown-freebsd +//@ [powerpc_unknown_freebsd] needs-llvm-components: powerpc +//@ revisions: powerpc_unknown_linux_gnu +//@ [powerpc_unknown_linux_gnu] compile-flags: --target powerpc-unknown-linux-gnu +//@ [powerpc_unknown_linux_gnu] needs-llvm-components: powerpc +//@ revisions: powerpc_unknown_linux_gnuspe +//@ [powerpc_unknown_linux_gnuspe] compile-flags: --target powerpc-unknown-linux-gnuspe +//@ [powerpc_unknown_linux_gnuspe] needs-llvm-components: powerpc +//@ revisions: powerpc_unknown_linux_musl +//@ [powerpc_unknown_linux_musl] compile-flags: --target powerpc-unknown-linux-musl +//@ [powerpc_unknown_linux_musl] needs-llvm-components: powerpc +//@ revisions: powerpc_unknown_linux_muslspe +//@ [powerpc_unknown_linux_muslspe] compile-flags: --target powerpc-unknown-linux-muslspe +//@ [powerpc_unknown_linux_muslspe] needs-llvm-components: powerpc +//@ revisions: powerpc_unknown_netbsd +//@ [powerpc_unknown_netbsd] compile-flags: --target powerpc-unknown-netbsd +//@ [powerpc_unknown_netbsd] needs-llvm-components: powerpc +//@ revisions: powerpc_unknown_openbsd +//@ [powerpc_unknown_openbsd] compile-flags: --target powerpc-unknown-openbsd +//@ [powerpc_unknown_openbsd] needs-llvm-components: powerpc +//@ revisions: powerpc_wrs_vxworks +//@ [powerpc_wrs_vxworks] compile-flags: --target powerpc-wrs-vxworks +//@ [powerpc_wrs_vxworks] needs-llvm-components: powerpc +//@ revisions: powerpc_wrs_vxworks_spe +//@ [powerpc_wrs_vxworks_spe] compile-flags: --target powerpc-wrs-vxworks-spe +//@ [powerpc_wrs_vxworks_spe] needs-llvm-components: powerpc +//@ revisions: riscv32_wrs_vxworks +//@ [riscv32_wrs_vxworks] compile-flags: --target riscv32-wrs-vxworks +//@ [riscv32_wrs_vxworks] needs-llvm-components: riscv +//@ revisions: riscv32e_unknown_none_elf +//@ [riscv32e_unknown_none_elf] compile-flags: --target riscv32e-unknown-none-elf +//@ [riscv32e_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv32em_unknown_none_elf +//@ [riscv32em_unknown_none_elf] compile-flags: --target riscv32em-unknown-none-elf +//@ [riscv32em_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv32emc_unknown_none_elf +//@ [riscv32emc_unknown_none_elf] compile-flags: --target riscv32emc-unknown-none-elf +//@ [riscv32emc_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv32gc_unknown_linux_gnu +//@ [riscv32gc_unknown_linux_gnu] compile-flags: --target riscv32gc-unknown-linux-gnu +//@ [riscv32gc_unknown_linux_gnu] needs-llvm-components: riscv +//@ revisions: riscv32gc_unknown_linux_musl +//@ [riscv32gc_unknown_linux_musl] compile-flags: --target riscv32gc-unknown-linux-musl +//@ [riscv32gc_unknown_linux_musl] needs-llvm-components: riscv +//@ revisions: riscv32i_unknown_none_elf +//@ [riscv32i_unknown_none_elf] compile-flags: --target riscv32i-unknown-none-elf +//@ [riscv32i_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv32im_risc0_zkvm_elf +//@ [riscv32im_risc0_zkvm_elf] compile-flags: --target riscv32im-risc0-zkvm-elf +//@ [riscv32im_risc0_zkvm_elf] needs-llvm-components: riscv +//@ revisions: riscv32im_unknown_none_elf +//@ [riscv32im_unknown_none_elf] compile-flags: --target riscv32im-unknown-none-elf +//@ [riscv32im_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv32ima_unknown_none_elf +//@ [riscv32ima_unknown_none_elf] compile-flags: --target riscv32ima-unknown-none-elf +//@ [riscv32ima_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv32imac_esp_espidf +//@ [riscv32imac_esp_espidf] compile-flags: --target riscv32imac-esp-espidf +//@ [riscv32imac_esp_espidf] needs-llvm-components: riscv +//@ revisions: riscv32imac_unknown_none_elf +//@ [riscv32imac_unknown_none_elf] compile-flags: --target riscv32imac-unknown-none-elf +//@ [riscv32imac_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv32imac_unknown_xous_elf +//@ [riscv32imac_unknown_xous_elf] compile-flags: --target riscv32imac-unknown-xous-elf +//@ [riscv32imac_unknown_xous_elf] needs-llvm-components: riscv +//@ revisions: riscv32imafc_unknown_none_elf +//@ [riscv32imafc_unknown_none_elf] compile-flags: --target riscv32imafc-unknown-none-elf +//@ [riscv32imafc_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv32imafc_esp_espidf +//@ [riscv32imafc_esp_espidf] compile-flags: --target riscv32imafc-esp-espidf +//@ [riscv32imafc_esp_espidf] needs-llvm-components: riscv +//@ revisions: riscv32imc_esp_espidf +//@ [riscv32imc_esp_espidf] compile-flags: --target riscv32imc-esp-espidf +//@ [riscv32imc_esp_espidf] needs-llvm-components: riscv +//@ revisions: riscv32imc_unknown_none_elf +//@ [riscv32imc_unknown_none_elf] compile-flags: --target riscv32imc-unknown-none-elf +//@ [riscv32imc_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv64_linux_android +//@ [riscv64_linux_android] compile-flags: --target riscv64-linux-android +//@ [riscv64_linux_android] needs-llvm-components: riscv +//@ revisions: riscv64_wrs_vxworks +//@ [riscv64_wrs_vxworks] compile-flags: --target riscv64-wrs-vxworks +//@ [riscv64_wrs_vxworks] needs-llvm-components: riscv +//@ revisions: riscv64gc_unknown_freebsd +//@ [riscv64gc_unknown_freebsd] compile-flags: --target riscv64gc-unknown-freebsd +//@ [riscv64gc_unknown_freebsd] needs-llvm-components: riscv +//@ revisions: riscv64gc_unknown_fuchsia +//@ [riscv64gc_unknown_fuchsia] compile-flags: --target riscv64gc-unknown-fuchsia +//@ [riscv64gc_unknown_fuchsia] needs-llvm-components: riscv +//@ revisions: riscv64gc_unknown_hermit +//@ [riscv64gc_unknown_hermit] compile-flags: --target riscv64gc-unknown-hermit +//@ [riscv64gc_unknown_hermit] needs-llvm-components: riscv +//@ revisions: riscv64gc_unknown_linux_gnu +//@ [riscv64gc_unknown_linux_gnu] compile-flags: --target riscv64gc-unknown-linux-gnu +//@ [riscv64gc_unknown_linux_gnu] needs-llvm-components: riscv +//@ revisions: riscv64gc_unknown_linux_musl +//@ [riscv64gc_unknown_linux_musl] compile-flags: --target riscv64gc-unknown-linux-musl +//@ [riscv64gc_unknown_linux_musl] needs-llvm-components: riscv +//@ revisions: riscv64gc_unknown_netbsd +//@ [riscv64gc_unknown_netbsd] compile-flags: --target riscv64gc-unknown-netbsd +//@ [riscv64gc_unknown_netbsd] needs-llvm-components: riscv +//@ revisions: riscv64gc_unknown_none_elf +//@ [riscv64gc_unknown_none_elf] compile-flags: --target riscv64gc-unknown-none-elf +//@ [riscv64gc_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv64gc_unknown_openbsd +//@ [riscv64gc_unknown_openbsd] compile-flags: --target riscv64gc-unknown-openbsd +//@ [riscv64gc_unknown_openbsd] needs-llvm-components: riscv +//@ revisions: riscv64imac_unknown_none_elf +//@ [riscv64imac_unknown_none_elf] compile-flags: --target riscv64imac-unknown-none-elf +//@ [riscv64imac_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: s390x_unknown_linux_gnu +//@ [s390x_unknown_linux_gnu] compile-flags: --target s390x-unknown-linux-gnu +//@ [s390x_unknown_linux_gnu] needs-llvm-components: systemz +//@ revisions: s390x_unknown_linux_musl +//@ [s390x_unknown_linux_musl] compile-flags: --target s390x-unknown-linux-musl +//@ [s390x_unknown_linux_musl] needs-llvm-components: systemz +//@ revisions: sparc64_unknown_linux_gnu +//@ [sparc64_unknown_linux_gnu] compile-flags: --target sparc64-unknown-linux-gnu +//@ [sparc64_unknown_linux_gnu] needs-llvm-components: sparc +//@ revisions: sparc64_unknown_netbsd +//@ [sparc64_unknown_netbsd] compile-flags: --target sparc64-unknown-netbsd +//@ [sparc64_unknown_netbsd] needs-llvm-components: sparc +//@ revisions: sparc64_unknown_openbsd +//@ [sparc64_unknown_openbsd] compile-flags: --target sparc64-unknown-openbsd +//@ [sparc64_unknown_openbsd] needs-llvm-components: sparc +//@ revisions: sparc_unknown_linux_gnu +//@ [sparc_unknown_linux_gnu] compile-flags: --target sparc-unknown-linux-gnu +//@ [sparc_unknown_linux_gnu] needs-llvm-components: sparc +//@ revisions: sparc_unknown_none_elf +//@ [sparc_unknown_none_elf] compile-flags: --target sparc-unknown-none-elf +//@ [sparc_unknown_none_elf] needs-llvm-components: sparc +//@ revisions: sparcv9_sun_solaris +//@ [sparcv9_sun_solaris] compile-flags: --target sparcv9-sun-solaris +//@ [sparcv9_sun_solaris] needs-llvm-components: sparc +//@ revisions: thumbv4t_none_eabi +//@ [thumbv4t_none_eabi] compile-flags: --target thumbv4t-none-eabi +//@ [thumbv4t_none_eabi] needs-llvm-components: arm +//@ revisions: thumbv5te_none_eabi +//@ [thumbv5te_none_eabi] compile-flags: --target thumbv5te-none-eabi +//@ [thumbv5te_none_eabi] needs-llvm-components: arm +//@ revisions: thumbv6m_none_eabi +//@ [thumbv6m_none_eabi] compile-flags: --target thumbv6m-none-eabi +//@ [thumbv6m_none_eabi] needs-llvm-components: arm +//@ revisions: thumbv7em_none_eabi +//@ [thumbv7em_none_eabi] compile-flags: --target thumbv7em-none-eabi +//@ [thumbv7em_none_eabi] needs-llvm-components: arm +//@ revisions: thumbv7em_none_eabihf +//@ [thumbv7em_none_eabihf] compile-flags: --target thumbv7em-none-eabihf +//@ [thumbv7em_none_eabihf] needs-llvm-components: arm +//@ revisions: thumbv7m_none_eabi +//@ [thumbv7m_none_eabi] compile-flags: --target thumbv7m-none-eabi +//@ [thumbv7m_none_eabi] needs-llvm-components: arm +//@ revisions: thumbv7neon_linux_androideabi +//@ [thumbv7neon_linux_androideabi] compile-flags: --target thumbv7neon-linux-androideabi +//@ [thumbv7neon_linux_androideabi] needs-llvm-components: arm +//@ revisions: thumbv7neon_unknown_linux_gnueabihf +//@ [thumbv7neon_unknown_linux_gnueabihf] compile-flags: --target thumbv7neon-unknown-linux-gnueabihf +//@ [thumbv7neon_unknown_linux_gnueabihf] needs-llvm-components: arm +//@ revisions: thumbv7neon_unknown_linux_musleabihf +//@ [thumbv7neon_unknown_linux_musleabihf] compile-flags: --target thumbv7neon-unknown-linux-musleabihf +//@ [thumbv7neon_unknown_linux_musleabihf] needs-llvm-components: arm +//@ revisions: thumbv8m_base_none_eabi +//@ [thumbv8m_base_none_eabi] compile-flags: --target thumbv8m.base-none-eabi +//@ [thumbv8m_base_none_eabi] needs-llvm-components: arm +//@ revisions: thumbv8m_main_none_eabi +//@ [thumbv8m_main_none_eabi] compile-flags: --target thumbv8m.main-none-eabi +//@ [thumbv8m_main_none_eabi] needs-llvm-components: arm +//@ revisions: thumbv8m_main_none_eabihf +//@ [thumbv8m_main_none_eabihf] compile-flags: --target thumbv8m.main-none-eabihf +//@ [thumbv8m_main_none_eabihf] needs-llvm-components: arm +//@ revisions: wasm32_unknown_emscripten +//@ [wasm32_unknown_emscripten] compile-flags: --target wasm32-unknown-emscripten +//@ [wasm32_unknown_emscripten] needs-llvm-components: webassembly +//@ revisions: wasm32_unknown_unknown +//@ [wasm32_unknown_unknown] compile-flags: --target wasm32-unknown-unknown +//@ [wasm32_unknown_unknown] needs-llvm-components: webassembly +//@ revisions: wasm32v1_none +//@ [wasm32v1_none] compile-flags: --target wasm32v1-none +//@ [wasm32v1_none] needs-llvm-components: webassembly +//@ revisions: wasm32_wasip1 +//@ [wasm32_wasip1] compile-flags: --target wasm32-wasip1 +//@ [wasm32_wasip1] needs-llvm-components: webassembly +//@ revisions: wasm32_wasip1_threads +//@ [wasm32_wasip1_threads] compile-flags: --target wasm32-wasip1-threads +//@ [wasm32_wasip1_threads] needs-llvm-components: webassembly +//@ revisions: wasm32_wasip2 +//@ [wasm32_wasip2] compile-flags: --target wasm32-wasip2 +//@ [wasm32_wasip2] needs-llvm-components: webassembly +//@ revisions: wasm32_wali_linux_musl +//@ [wasm32_wali_linux_musl] compile-flags: --target wasm32-wali-linux-musl +//@ [wasm32_wali_linux_musl] needs-llvm-components: webassembly +//@ revisions: wasm64_unknown_unknown +//@ [wasm64_unknown_unknown] compile-flags: --target wasm64-unknown-unknown +//@ [wasm64_unknown_unknown] needs-llvm-components: webassembly +//@ revisions: x86_64_fortanix_unknown_sgx +//@ [x86_64_fortanix_unknown_sgx] compile-flags: --target x86_64-fortanix-unknown-sgx +//@ [x86_64_fortanix_unknown_sgx] needs-llvm-components: x86 +//@ revisions: x86_64_linux_android +//@ [x86_64_linux_android] compile-flags: --target x86_64-linux-android +//@ [x86_64_linux_android] needs-llvm-components: x86 +//@ revisions: x86_64_lynx_lynxos178 +//@ [x86_64_lynx_lynxos178] compile-flags: --target x86_64-lynx-lynxos178 +//@ [x86_64_lynx_lynxos178] needs-llvm-components: x86 +//@ revisions: x86_64_pc_nto_qnx710 +//@ [x86_64_pc_nto_qnx710] compile-flags: --target x86_64-pc-nto-qnx710 +//@ [x86_64_pc_nto_qnx710] needs-llvm-components: x86 +//@ revisions: x86_64_pc_nto_qnx710_iosock +//@ [x86_64_pc_nto_qnx710_iosock] compile-flags: --target x86_64-pc-nto-qnx710_iosock +//@ [x86_64_pc_nto_qnx710_iosock] needs-llvm-components: x86 +//@ revisions: x86_64_pc_nto_qnx800 +//@ [x86_64_pc_nto_qnx800] compile-flags: --target x86_64-pc-nto-qnx800 +//@ [x86_64_pc_nto_qnx800] needs-llvm-components: x86 +//@ revisions: x86_64_pc_solaris +//@ [x86_64_pc_solaris] compile-flags: --target x86_64-pc-solaris +//@ [x86_64_pc_solaris] needs-llvm-components: x86 +//@ revisions: x86_64_unikraft_linux_musl +//@ [x86_64_unikraft_linux_musl] compile-flags: --target x86_64-unikraft-linux-musl +//@ [x86_64_unikraft_linux_musl] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_dragonfly +//@ [x86_64_unknown_dragonfly] compile-flags: --target x86_64-unknown-dragonfly +//@ [x86_64_unknown_dragonfly] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_freebsd +//@ [x86_64_unknown_freebsd] compile-flags: --target x86_64-unknown-freebsd +//@ [x86_64_unknown_freebsd] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_fuchsia +//@ [x86_64_unknown_fuchsia] compile-flags: --target x86_64-unknown-fuchsia +//@ [x86_64_unknown_fuchsia] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_haiku +//@ [x86_64_unknown_haiku] compile-flags: --target x86_64-unknown-haiku +//@ [x86_64_unknown_haiku] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_hurd_gnu +//@ [x86_64_unknown_hurd_gnu] compile-flags: --target x86_64-unknown-hurd-gnu +//@ [x86_64_unknown_hurd_gnu] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_hermit +//@ [x86_64_unknown_hermit] compile-flags: --target x86_64-unknown-hermit +//@ [x86_64_unknown_hermit] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_illumos +//@ [x86_64_unknown_illumos] compile-flags: --target x86_64-unknown-illumos +//@ [x86_64_unknown_illumos] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_l4re_uclibc +//@ [x86_64_unknown_l4re_uclibc] compile-flags: --target x86_64-unknown-l4re-uclibc +//@ [x86_64_unknown_l4re_uclibc] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_linux_gnu +//@ [x86_64_unknown_linux_gnu] compile-flags: --target x86_64-unknown-linux-gnu +//@ [x86_64_unknown_linux_gnu] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_linux_gnux32 +//@ [x86_64_unknown_linux_gnux32] compile-flags: --target x86_64-unknown-linux-gnux32 +//@ [x86_64_unknown_linux_gnux32] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_linux_musl +//@ [x86_64_unknown_linux_musl] compile-flags: --target x86_64-unknown-linux-musl +//@ [x86_64_unknown_linux_musl] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_linux_ohos +//@ [x86_64_unknown_linux_ohos] compile-flags: --target x86_64-unknown-linux-ohos +//@ [x86_64_unknown_linux_ohos] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_linux_none +//@ [x86_64_unknown_linux_none] compile-flags: --target x86_64-unknown-linux-none +//@ [x86_64_unknown_linux_none] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_netbsd +//@ [x86_64_unknown_netbsd] compile-flags: --target x86_64-unknown-netbsd +//@ [x86_64_unknown_netbsd] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_none +//@ [x86_64_unknown_none] compile-flags: --target x86_64-unknown-none +//@ [x86_64_unknown_none] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_openbsd +//@ [x86_64_unknown_openbsd] compile-flags: --target x86_64-unknown-openbsd +//@ [x86_64_unknown_openbsd] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_redox +//@ [x86_64_unknown_redox] compile-flags: --target x86_64-unknown-redox +//@ [x86_64_unknown_redox] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_trusty +//@ [x86_64_unknown_trusty] compile-flags: --target x86_64-unknown-trusty +//@ [x86_64_unknown_trusty] needs-llvm-components: x86 +//@ revisions: x86_64_wrs_vxworks +//@ [x86_64_wrs_vxworks] compile-flags: --target x86_64-wrs-vxworks +//@ [x86_64_wrs_vxworks] needs-llvm-components: x86 +//@ revisions: thumbv6m_nuttx_eabi +//@ [thumbv6m_nuttx_eabi] compile-flags: --target thumbv6m-nuttx-eabi +//@ [thumbv6m_nuttx_eabi] needs-llvm-components: arm +//@ revisions: thumbv7a_nuttx_eabi +//@ [thumbv7a_nuttx_eabi] compile-flags: --target thumbv7a-nuttx-eabi +//@ [thumbv7a_nuttx_eabi] needs-llvm-components: arm +//@ revisions: thumbv7a_nuttx_eabihf +//@ [thumbv7a_nuttx_eabihf] compile-flags: --target thumbv7a-nuttx-eabihf +//@ [thumbv7a_nuttx_eabihf] needs-llvm-components: arm +//@ revisions: thumbv7m_nuttx_eabi +//@ [thumbv7m_nuttx_eabi] compile-flags: --target thumbv7m-nuttx-eabi +//@ [thumbv7m_nuttx_eabi] needs-llvm-components: arm +//@ revisions: thumbv7em_nuttx_eabi +//@ [thumbv7em_nuttx_eabi] compile-flags: --target thumbv7em-nuttx-eabi +//@ [thumbv7em_nuttx_eabi] needs-llvm-components: arm +//@ revisions: thumbv7em_nuttx_eabihf +//@ [thumbv7em_nuttx_eabihf] compile-flags: --target thumbv7em-nuttx-eabihf +//@ [thumbv7em_nuttx_eabihf] needs-llvm-components: arm +//@ revisions: thumbv8m_base_nuttx_eabi +//@ [thumbv8m_base_nuttx_eabi] compile-flags: --target thumbv8m.base-nuttx-eabi +//@ [thumbv8m_base_nuttx_eabi] needs-llvm-components: arm +//@ revisions: thumbv8m_main_nuttx_eabi +//@ [thumbv8m_main_nuttx_eabi] compile-flags: --target thumbv8m.main-nuttx-eabi +//@ [thumbv8m_main_nuttx_eabi] needs-llvm-components: arm +//@ revisions: thumbv8m_main_nuttx_eabihf +//@ [thumbv8m_main_nuttx_eabihf] compile-flags: --target thumbv8m.main-nuttx-eabihf +//@ [thumbv8m_main_nuttx_eabihf] needs-llvm-components: arm +//@ revisions: riscv32imc_unknown_nuttx_elf +//@ [riscv32imc_unknown_nuttx_elf] compile-flags: --target riscv32imc-unknown-nuttx-elf +//@ [riscv32imc_unknown_nuttx_elf] needs-llvm-components: riscv +//@ revisions: riscv32imac_unknown_nuttx_elf +//@ [riscv32imac_unknown_nuttx_elf] compile-flags: --target riscv32imac-unknown-nuttx-elf +//@ [riscv32imac_unknown_nuttx_elf] needs-llvm-components: riscv +//@ revisions: riscv32imafc_unknown_nuttx_elf +//@ [riscv32imafc_unknown_nuttx_elf] compile-flags: --target riscv32imafc-unknown-nuttx-elf +//@ [riscv32imafc_unknown_nuttx_elf] needs-llvm-components: riscv +//@ revisions: riscv64imac_unknown_nuttx_elf +//@ [riscv64imac_unknown_nuttx_elf] compile-flags: --target riscv64imac-unknown-nuttx-elf +//@ [riscv64imac_unknown_nuttx_elf] needs-llvm-components: riscv +//@ revisions: riscv64gc_unknown_nuttx_elf +//@ [riscv64gc_unknown_nuttx_elf] compile-flags: --target riscv64gc-unknown-nuttx-elf +//@ [riscv64gc_unknown_nuttx_elf] needs-llvm-components: riscv +// FIXME: disabled since it requires a custom LLVM until the upstream LLVM adds support for the target (https://github.com/espressif/llvm-project/issues/4) +/* + revisions: xtensa_esp32_none_elf + [xtensa_esp32_none_elf] compile-flags: --target xtensa-esp32-none-elf + [xtensa_esp32_none_elf] needs-llvm-components: xtensa + revisions: xtensa_esp32_espidf + [xtensa_esp32_espidf] compile-flags: --target xtensa-esp32s2-espidf + [xtensa_esp32_espidf] needs-llvm-components: xtensa + revisions: xtensa_esp32s2_none_elf + [xtensa_esp32s2_none_elf] compile-flags: --target xtensa-esp32s2-none-elf + [xtensa_esp32s2_none_elf] needs-llvm-components: xtensa + revisions: xtensa_esp32s2_espidf + [xtensa_esp32s2_espidf] compile-flags: --target xtensa-esp32s2-espidf + [xtensa_esp32s2_espidf] needs-llvm-components: xtensa + revisions: xtensa_esp32s3_none_elf + [xtensa_esp32s3_none_elf] compile-flags: --target xtensa-esp32s3-none-elf + [xtensa_esp32s3_none_elf] needs-llvm-components: xtensa + revisions: xtensa_esp32s3_espidf + [xtensa_esp32s3_espidf] compile-flags: --target xtensa-esp32s3-espidf + [xtensa_esp32s3_espidf] needs-llvm-components: xtensa +*/ +// Sanity-check that each target can produce assembly code. + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +// Force linkage to ensure code is actually generated +#[no_mangle] +pub fn test() -> u8 { + 42 +} + +// CHECK: .text diff --git a/tests/assembly-llvm/targets/targets-macho.rs b/tests/assembly-llvm/targets/targets-macho.rs new file mode 100644 index 00000000000..92bde1c6971 --- /dev/null +++ b/tests/assembly-llvm/targets/targets-macho.rs @@ -0,0 +1,93 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +// ignore-tidy-linelength +//@ revisions: aarch64_apple_darwin +//@ [aarch64_apple_darwin] compile-flags: --target aarch64-apple-darwin +//@ [aarch64_apple_darwin] needs-llvm-components: aarch64 +//@ revisions: aarch64_apple_ios +//@ [aarch64_apple_ios] compile-flags: --target aarch64-apple-ios +//@ [aarch64_apple_ios] needs-llvm-components: aarch64 +//@ revisions: aarch64_apple_ios_macabi +//@ [aarch64_apple_ios_macabi] compile-flags: --target aarch64-apple-ios-macabi +//@ [aarch64_apple_ios_macabi] needs-llvm-components: aarch64 +//@ revisions: aarch64_apple_ios_sim +//@ [aarch64_apple_ios_sim] compile-flags: --target aarch64-apple-ios-sim +//@ [aarch64_apple_ios_sim] needs-llvm-components: aarch64 +//@ revisions: aarch64_apple_tvos +//@ [aarch64_apple_tvos] compile-flags: --target aarch64-apple-tvos +//@ [aarch64_apple_tvos] needs-llvm-components: aarch64 +//@ revisions: aarch64_apple_tvos_sim +//@ [aarch64_apple_tvos_sim] compile-flags: --target aarch64-apple-tvos-sim +//@ [aarch64_apple_tvos_sim] needs-llvm-components: aarch64 +//@ revisions: arm64e_apple_tvos +//@ [arm64e_apple_tvos] compile-flags: --target arm64e-apple-tvos +//@ [arm64e_apple_tvos] needs-llvm-components: aarch64 +//@ revisions: aarch64_apple_watchos +//@ [aarch64_apple_watchos] compile-flags: --target aarch64-apple-watchos +//@ [aarch64_apple_watchos] needs-llvm-components: aarch64 +//@ revisions: aarch64_apple_watchos_sim +//@ [aarch64_apple_watchos_sim] compile-flags: --target aarch64-apple-watchos-sim +//@ [aarch64_apple_watchos_sim] needs-llvm-components: aarch64 +//@ revisions: arm64_32_apple_watchos +//@ [arm64_32_apple_watchos] compile-flags: --target arm64_32-apple-watchos +//@ [arm64_32_apple_watchos] needs-llvm-components: aarch64 +//@ revisions: aarch64_apple_visionos +//@ [aarch64_apple_visionos] compile-flags: --target aarch64-apple-visionos +//@ [aarch64_apple_visionos] needs-llvm-components: aarch64 +//@ revisions: aarch64_apple_visionos_sim +//@ [aarch64_apple_visionos_sim] compile-flags: --target aarch64-apple-visionos-sim +//@ [aarch64_apple_visionos_sim] needs-llvm-components: aarch64 +//@ revisions: arm64e_apple_darwin +//@ [arm64e_apple_darwin] compile-flags: --target arm64e-apple-darwin +//@ [arm64e_apple_darwin] needs-llvm-components: aarch64 +//@ revisions: arm64e_apple_ios +//@ [arm64e_apple_ios] compile-flags: --target arm64e-apple-ios +//@ [arm64e_apple_ios] needs-llvm-components: aarch64 +//@ revisions: armv7k_apple_watchos +//@ [armv7k_apple_watchos] compile-flags: --target armv7k-apple-watchos +//@ [armv7k_apple_watchos] needs-llvm-components: arm +//@ revisions: armv7s_apple_ios +//@ [armv7s_apple_ios] compile-flags: --target armv7s-apple-ios +//@ [armv7s_apple_ios] needs-llvm-components: arm +//@ revisions: i386_apple_ios +//@ [i386_apple_ios] compile-flags: --target i386-apple-ios +//@ [i386_apple_ios] needs-llvm-components: x86 +//@ revisions: i686_apple_darwin +//@ [i686_apple_darwin] compile-flags: --target i686-apple-darwin +//@ [i686_apple_darwin] needs-llvm-components: x86 +//@ revisions: x86_64_apple_darwin +//@ [x86_64_apple_darwin] compile-flags: --target x86_64-apple-darwin +//@ [x86_64_apple_darwin] needs-llvm-components: x86 +//@ revisions: x86_64_apple_ios +//@ [x86_64_apple_ios] compile-flags: --target x86_64-apple-ios +//@ [x86_64_apple_ios] needs-llvm-components: x86 +//@ revisions: x86_64_apple_ios_macabi +//@ [x86_64_apple_ios_macabi] compile-flags: --target x86_64-apple-ios-macabi +//@ [x86_64_apple_ios_macabi] needs-llvm-components: x86 +//@ revisions: x86_64_apple_tvos +//@ [x86_64_apple_tvos] compile-flags: --target x86_64-apple-tvos +//@ [x86_64_apple_tvos] needs-llvm-components: x86 +//@ revisions: x86_64_apple_watchos_sim +//@ [x86_64_apple_watchos_sim] compile-flags: --target x86_64-apple-watchos-sim +//@ [x86_64_apple_watchos_sim] needs-llvm-components: x86 +//@ revisions: x86_64h_apple_darwin +//@ [x86_64h_apple_darwin] compile-flags: --target x86_64h-apple-darwin +//@ [x86_64h_apple_darwin] needs-llvm-components: x86 + +// Sanity-check that each target can produce assembly code. + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +// Force linkage to ensure code is actually generated +#[no_mangle] +pub fn test() -> u8 { + 42 +} + +// CHECK: .section __TEXT,__text diff --git a/tests/assembly-llvm/targets/targets-nvptx.rs b/tests/assembly-llvm/targets/targets-nvptx.rs new file mode 100644 index 00000000000..49c12aebaaa --- /dev/null +++ b/tests/assembly-llvm/targets/targets-nvptx.rs @@ -0,0 +1,22 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +// ignore-tidy-linelength +//@ revisions: nvptx64_nvidia_cuda +//@ [nvptx64_nvidia_cuda] compile-flags: --target nvptx64-nvidia-cuda +//@ [nvptx64_nvidia_cuda] needs-llvm-components: nvptx + +// Sanity-check that each target can produce assembly code. + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +pub fn test() -> u8 { + 42 +} + +// CHECK: .version diff --git a/tests/assembly-llvm/targets/targets-pe.rs b/tests/assembly-llvm/targets/targets-pe.rs new file mode 100644 index 00000000000..de29b9af502 --- /dev/null +++ b/tests/assembly-llvm/targets/targets-pe.rs @@ -0,0 +1,103 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +// ignore-tidy-linelength +//@ revisions: aarch64_pc_windows_msvc +//@ [aarch64_pc_windows_msvc] compile-flags: --target aarch64-pc-windows-msvc +//@ [aarch64_pc_windows_msvc] needs-llvm-components: aarch64 +//@ revisions: aarch64_pc_windows_gnullvm +//@ [aarch64_pc_windows_gnullvm] compile-flags: --target aarch64-pc-windows-gnullvm +//@ [aarch64_pc_windows_gnullvm] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_uefi +//@ [aarch64_unknown_uefi] compile-flags: --target aarch64-unknown-uefi +//@ [aarch64_unknown_uefi] needs-llvm-components: aarch64 +//@ revisions: aarch64_uwp_windows_msvc +//@ [aarch64_uwp_windows_msvc] compile-flags: --target aarch64-uwp-windows-msvc +//@ [aarch64_uwp_windows_msvc] needs-llvm-components: aarch64 +//@ revisions: arm64ec_pc_windows_msvc +//@ [arm64ec_pc_windows_msvc] compile-flags: --target arm64ec-pc-windows-msvc +//@ [arm64ec_pc_windows_msvc] needs-llvm-components: aarch64 +//@ revisions: avr_none +//@ [avr_none] compile-flags: --target avr-none -C target-cpu=atmega328p +//@ [avr_none] needs-llvm-components: avr +//@ revisions: bpfeb_unknown_none +//@ [bpfeb_unknown_none] compile-flags: --target bpfeb-unknown-none +//@ [bpfeb_unknown_none] needs-llvm-components: bpf +//@ revisions: bpfel_unknown_none +//@ [bpfel_unknown_none] compile-flags: --target bpfel-unknown-none +//@ [bpfel_unknown_none] needs-llvm-components: bpf +//@ revisions: i686_pc_windows_gnu +//@ [i686_pc_windows_gnu] compile-flags: --target i686-pc-windows-gnu +//@ [i686_pc_windows_gnu] needs-llvm-components: x86 +//@ revisions: i686_pc_windows_msvc +//@ [i686_pc_windows_msvc] compile-flags: --target i686-pc-windows-msvc +//@ [i686_pc_windows_msvc] needs-llvm-components: x86 +//@ revisions: i686_pc_windows_gnullvm +//@ [i686_pc_windows_gnullvm] compile-flags: --target i686-pc-windows-gnullvm +//@ [i686_pc_windows_gnullvm] needs-llvm-components: x86 +//@ revisions: i686_uwp_windows_gnu +//@ [i686_uwp_windows_gnu] compile-flags: --target i686-uwp-windows-gnu +//@ [i686_uwp_windows_gnu] needs-llvm-components: x86 +//@ revisions: i686_win7_windows_gnu +//@ [i686_win7_windows_gnu] compile-flags: --target i686-win7-windows-gnu +//@ [i686_win7_windows_gnu] needs-llvm-components: x86 +//@ revisions: i686_unknown_uefi +//@ [i686_unknown_uefi] compile-flags: --target i686-unknown-uefi +//@ [i686_unknown_uefi] needs-llvm-components: x86 +//@ revisions: i686_uwp_windows_msvc +//@ [i686_uwp_windows_msvc] compile-flags: --target i686-uwp-windows-msvc +//@ [i686_uwp_windows_msvc] needs-llvm-components: x86 +//@ revisions: i686_win7_windows_msvc +//@ [i686_win7_windows_msvc] compile-flags: --target i686-win7-windows-msvc +//@ [i686_win7_windows_msvc] needs-llvm-components: x86 +//@ revisions: powerpc64_ibm_aix +//@ [powerpc64_ibm_aix] compile-flags: --target powerpc64-ibm-aix +//@ [powerpc64_ibm_aix] needs-llvm-components: powerpc +//@ revisions: thumbv7a_uwp_windows_msvc +//@ [thumbv7a_uwp_windows_msvc] compile-flags: --target thumbv7a-uwp-windows-msvc +//@ [thumbv7a_uwp_windows_msvc] needs-llvm-components: arm +//@ revisions: thumbv7a_pc_windows_msvc +//@ [thumbv7a_pc_windows_msvc] compile-flags: --target thumbv7a-pc-windows-msvc +//@ [thumbv7a_pc_windows_msvc] needs-llvm-components: arm +//@ revisions: x86_64_pc_windows_gnu +//@ [x86_64_pc_windows_gnu] compile-flags: --target x86_64-pc-windows-gnu +//@ [x86_64_pc_windows_gnu] needs-llvm-components: x86 +//@ revisions: x86_64_pc_windows_gnullvm +//@ [x86_64_pc_windows_gnullvm] compile-flags: --target x86_64-pc-windows-gnullvm +//@ [x86_64_pc_windows_gnullvm] needs-llvm-components: x86 +//@ revisions: x86_64_pc_windows_msvc +//@ [x86_64_pc_windows_msvc] compile-flags: --target x86_64-pc-windows-msvc +//@ [x86_64_pc_windows_msvc] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_uefi +//@ [x86_64_unknown_uefi] compile-flags: --target x86_64-unknown-uefi +//@ [x86_64_unknown_uefi] needs-llvm-components: x86 +//@ revisions: x86_64_uwp_windows_gnu +//@ [x86_64_uwp_windows_gnu] compile-flags: --target x86_64-uwp-windows-gnu +//@ [x86_64_uwp_windows_gnu] needs-llvm-components: x86 +//@ revisions: x86_64_win7_windows_gnu +//@ [x86_64_win7_windows_gnu] compile-flags: --target x86_64-win7-windows-gnu +//@ [x86_64_win7_windows_gnu] needs-llvm-components: x86 +//@ revisions: x86_64_uwp_windows_msvc +//@ [x86_64_uwp_windows_msvc] compile-flags: --target x86_64-uwp-windows-msvc +//@ [x86_64_uwp_windows_msvc] needs-llvm-components: x86 +//@ revisions: x86_64_win7_windows_msvc +//@ [x86_64_win7_windows_msvc] compile-flags: --target x86_64-win7-windows-msvc +//@ [x86_64_win7_windows_msvc] needs-llvm-components: x86 +//@ revisions: x86_64_pc_cygwin +//@ [x86_64_pc_cygwin] compile-flags: --target x86_64-pc-cygwin +//@ [x86_64_pc_cygwin] needs-llvm-components: x86 + +// Sanity-check that each target can produce assembly code. + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +pub fn test() -> u8 { + 42 +} + +// CHECK: .file diff --git a/tests/assembly-llvm/wasm_exceptions.rs b/tests/assembly-llvm/wasm_exceptions.rs new file mode 100644 index 00000000000..704e8026f3f --- /dev/null +++ b/tests/assembly-llvm/wasm_exceptions.rs @@ -0,0 +1,67 @@ +//@ only-wasm32 +//@ assembly-output: emit-asm +//@ compile-flags: -C target-feature=+exception-handling +//@ compile-flags: -C panic=unwind + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +extern "C-unwind" { + fn may_panic(); +} + +extern "C" { + fn log_number(number: usize); +} + +struct LogOnDrop; + +impl Drop for LogOnDrop { + fn drop(&mut self) { + unsafe { + log_number(0); + } + } +} + +// CHECK-LABEL: test_cleanup: +#[no_mangle] +pub fn test_cleanup() { + let _log_on_drop = LogOnDrop; + unsafe { + may_panic(); + } + + // CHECK-NOT: call + // CHECK: try + // CHECK: call may_panic + // CHECK: catch_all + // CHECK: rethrow + // CHECK: end_try +} + +// CHECK-LABEL: test_rtry: +#[no_mangle] +pub fn test_rtry() { + unsafe { + core::intrinsics::catch_unwind( + |_| { + may_panic(); + }, + core::ptr::null_mut(), + |data, exception| { + log_number(data as usize); + log_number(exception as usize); + }, + ); + } + + // CHECK-NOT: call + // CHECK: try + // CHECK: call may_panic + // CHECK: catch + // CHECK: call log_number + // CHECK: call log_number + // CHECK-NOT: rethrow + // CHECK: end_try +} diff --git a/tests/assembly-llvm/x86-return-float.rs b/tests/assembly-llvm/x86-return-float.rs new file mode 100644 index 00000000000..165c11d2280 --- /dev/null +++ b/tests/assembly-llvm/x86-return-float.rs @@ -0,0 +1,343 @@ +//@ assembly-output: emit-asm +// FIXME(#114479): LLVM miscompiles loading and storing `f32` and `f64` when SSE is disabled. +// There's no compiletest directive to ignore a test on i586 only, so just always explicitly enable +// SSE2. +// Use the same target CPU as `i686` so that LLVM orders the instructions in the same order. +//@ compile-flags: -Ctarget-feature=+sse2 -Ctarget-cpu=pentium4 +// Force frame pointers to make ASM more consistent between targets +//@ compile-flags: -C force-frame-pointers +// At opt-level=3, LLVM can merge two movss into one movsd, and we aren't testing for that. +//@ compile-flags: -Copt-level=2 +//@ filecheck-flags: --implicit-check-not fld --implicit-check-not fst +//@ revisions: linux win +//@ add-core-stubs +//@[linux] needs-llvm-components: x86 +//@[win] needs-llvm-components: x86 +//@[linux] compile-flags: --target i686-unknown-linux-gnu +//@[win] compile-flags: --target i686-pc-windows-msvc + +#![crate_type = "lib"] +#![feature(f16, f128)] +#![feature(no_core)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// Tests that returning `f32` and `f64` with the "Rust" ABI on 32-bit x86 doesn't use the x87 +// floating point stack, as loading and storing `f32`s and `f64`s to and from the x87 stack quietens +// signalling NaNs. + +// Returning individual floats + +// CHECK-LABEL: return_f32: +#[no_mangle] +pub fn return_f32(x: f32) -> f32 { + // CHECK: movss {{.*}}(%ebp), %xmm0 + // CHECK-NEXT: popl %ebp + // linux-NEXT: .cfi_def_cfa + // CHECK-NEXT: retl + x +} + +// CHECK-LABEL: return_f64: +#[no_mangle] +pub fn return_f64(x: f64) -> f64 { + // CHECK: movsd {{.*}}(%ebp), %xmm0 + // CHECK-NEXT: popl %ebp + // linux-NEXT: .cfi_def_cfa + // CHECK-NEXT: retl + x +} + +// Returning scalar pairs containing floats + +// CHECK-LABEL: return_f32_f32: +#[no_mangle] +pub fn return_f32_f32(x: (f32, f32)) -> (f32, f32) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_f64_f64: +#[no_mangle] +pub fn return_f64_f64(x: (f64, f64)) -> (f64, f64) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+12]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_f32_f64: +#[no_mangle] +pub fn return_f32_f64(x: (f32, f64)) -> (f32, f64) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movsd %[[VAL2]], {{4|8}}(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_f64_f32: +#[no_mangle] +pub fn return_f64_f32(x: (f64, f32)) -> (f64, f32) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+12]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 8(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_f32_other: +#[no_mangle] +pub fn return_f32_other(x: (f32, usize)) -> (f32, usize) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movl %[[VAL2]], 4(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_f64_other: +#[no_mangle] +pub fn return_f64_other(x: (f64, usize)) -> (f64, usize) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+12]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movl %[[VAL2]], 8(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_other_f32: +#[no_mangle] +pub fn return_other_f32(x: (usize, f32)) -> (usize, f32) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_other_f64: +#[no_mangle] +pub fn return_other_f64(x: (usize, f64)) -> (usize, f64) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movsd %[[VAL2]], {{4|8}}(%[[PTR]]) + // CHECK: retl + x +} + +// Calling functions returning floats + +// CHECK-LABEL: call_f32: +#[no_mangle] +pub unsafe fn call_f32(x: &mut f32) { + extern "Rust" { + fn get_f32() -> f32; + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f32 + // CHECK-NEXT: movss %xmm0, (%[[PTR]]) + *x = get_f32(); +} + +// CHECK-LABEL: call_f64: +#[no_mangle] +pub unsafe fn call_f64(x: &mut f64) { + extern "Rust" { + fn get_f64() -> f64; + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f64 + // CHECK-NEXT: movlps %xmm0, (%[[PTR]]) + *x = get_f64(); +} + +// Calling functions returning scalar pairs containing floats + +// CHECK-LABEL: call_f32_f32: +#[no_mangle] +pub unsafe fn call_f32_f32(x: &mut (f32, f32)) { + extern "Rust" { + fn get_f32_f32() -> (f32, f32); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f32_f32 + // CHECK: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) + *x = get_f32_f32(); +} + +// CHECK-LABEL: call_f64_f64: +#[no_mangle] +pub unsafe fn call_f64_f64(x: &mut (f64, f64)) { + extern "Rust" { + fn get_f64_f64() -> (f64, f64); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f64_f64 + // linux: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // linux-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // win: movsd (%esp), %[[VAL1:.*]] + // win-NEXT: movsd 8(%esp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) + *x = get_f64_f64(); +} + +// CHECK-LABEL: call_f32_f64: +#[no_mangle] +pub unsafe fn call_f32_f64(x: &mut (f32, f64)) { + extern "Rust" { + fn get_f32_f64() -> (f32, f64); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f32_f64 + // linux: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // linux-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] + // win: movss (%esp), %[[VAL1:.*]] + // win-NEXT: movsd 8(%esp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // linux-NEXT: movsd %[[VAL2]], 4(%[[PTR]]) + // win-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) + *x = get_f32_f64(); +} + +// CHECK-LABEL: call_f64_f32: +#[no_mangle] +pub unsafe fn call_f64_f32(x: &mut (f64, f32)) { + extern "Rust" { + fn get_f64_f32() -> (f64, f32); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f64_f32 + // linux: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // linux-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // win: movsd (%esp), %[[VAL1:.*]] + // win-NEXT: movss 8(%esp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 8(%[[PTR]]) + *x = get_f64_f32(); +} + +// CHECK-LABEL: call_f32_other: +#[no_mangle] +pub unsafe fn call_f32_other(x: &mut (f32, usize)) { + extern "Rust" { + fn get_f32_other() -> (f32, usize); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f32_other + // CHECK: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movl %[[VAL2]], 4(%[[PTR]]) + *x = get_f32_other(); +} + +// CHECK-LABEL: call_f64_other: +#[no_mangle] +pub unsafe fn call_f64_other(x: &mut (f64, usize)) { + extern "Rust" { + fn get_f64_other() -> (f64, usize); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f64_other + // linux: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // linux-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // win: movsd (%esp), %[[VAL1:.*]] + // win-NEXT: movl 8(%esp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movl %[[VAL2]], 8(%[[PTR]]) + *x = get_f64_other(); +} + +// CHECK-LABEL: call_other_f32: +#[no_mangle] +pub unsafe fn call_other_f32(x: &mut (usize, f32)) { + extern "Rust" { + fn get_other_f32() -> (usize, f32); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_other_f32 + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) + *x = get_other_f32(); +} + +// CHECK-LABEL: call_other_f64: +#[no_mangle] +pub unsafe fn call_other_f64(x: &mut (usize, f64)) { + extern "Rust" { + fn get_other_f64() -> (usize, f64); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_other_f64 + // linux: movl [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // linux-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] + // win: movl (%esp), %[[VAL1:.*]] + // win-NEXT: movsd 8(%esp), %[[VAL2:.*]] + // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) + // linux-NEXT: movsd %[[VAL2]], 4(%[[PTR]]) + // win-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) + *x = get_other_f64(); +} + +// The "C" ABI for `f16` and `f128` on x86 has never used the x87 floating point stack. Do some +// basic checks to ensure this remains the case for the "Rust" ABI. + +// CHECK-LABEL: return_f16: +#[no_mangle] +pub fn return_f16(x: f16) -> f16 { + // CHECK: pushl %ebp + // linux-NEXT: .cfi_def_cfa_offset + // linux-NEXT: .cfi_offset + // CHECK-NEXT: movl %esp, %ebp + // linux-NEXT: .cfi_def_cfa_register + // CHECK-NEXT: pinsrw $0, 8(%ebp), %xmm0 + // CHECK-NEXT: popl %ebp + // linux-NEXT: .cfi_def_cfa + // CHECK-NEXT: retl + x +} + +// CHECK-LABEL: return_f128: +#[no_mangle] +pub fn return_f128(x: f128) -> f128 { + // CHECK: pushl %ebp + // linux-NEXT: .cfi_def_cfa_offset + // linux-NEXT: .cfi_offset + // CHECK-NEXT: movl %esp, %ebp + // linux-NEXT: .cfi_def_cfa_register + // linux-NEXT: movaps 8(%ebp), %xmm0 + // win-NEXT: movups 8(%ebp), %xmm0 + // CHECK-NEXT: popl %ebp + // linux-NEXT: .cfi_def_cfa + // CHECK-NEXT: retl + x +} diff --git a/tests/assembly-llvm/x86_64-array-pair-load-store-merge.rs b/tests/assembly-llvm/x86_64-array-pair-load-store-merge.rs new file mode 100644 index 00000000000..56a1a9e8206 --- /dev/null +++ b/tests/assembly-llvm/x86_64-array-pair-load-store-merge.rs @@ -0,0 +1,20 @@ +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -Copt-level=3 -C llvm-args=-x86-asm-syntax=intel +//@ only-x86_64 +//@ ignore-sgx +//@ ignore-apple (manipulates rsp too) + +// Depending on various codegen choices, this might end up copying +// a `<2 x i8>`, an `i16`, or two `i8`s. +// Regardless of those choices, make sure the instructions use (2-byte) words. + +// CHECK-LABEL: array_copy_2_elements: +#[no_mangle] +pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) { + // CHECK-NOT: byte + // CHECK-NOT: mov + // CHECK: mov{{.+}}, word ptr + // CHECK-NEXT: mov word ptr + // CHECK-NEXT: ret + *p = *a; +} diff --git a/tests/assembly-llvm/x86_64-bigint-helpers.rs b/tests/assembly-llvm/x86_64-bigint-helpers.rs new file mode 100644 index 00000000000..58785932bc2 --- /dev/null +++ b/tests/assembly-llvm/x86_64-bigint-helpers.rs @@ -0,0 +1,61 @@ +//@ only-x86_64 +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -Copt-level=3 -C target-cpu=x86-64-v4 +//@ compile-flags: -C llvm-args=-x86-asm-syntax=intel +//@ revisions: llvm-pre-20 llvm-20 +//@ [llvm-20] min-llvm-version: 20 +//@ [llvm-pre-20] max-llvm-major-version: 19 + +#![no_std] +#![feature(bigint_helper_methods)] + +// This checks that the `carrying_add` and `borrowing_sub` implementation successfully chain, +// to catch issues like + +// This forces the ABI to avoid the windows-vs-linux ABI differences. + +// CHECK-LABEL: bigint_chain_carrying_add: +#[no_mangle] +pub unsafe extern "sysv64" fn bigint_chain_carrying_add( + dest: *mut u64, + src1: *const u64, + src2: *const u64, + n: usize, + mut carry: bool, +) -> bool { + // llvm-pre-20: mov [[TEMP:r..]], qword ptr [rsi + 8*[[IND:r..]] + 8] + // llvm-pre-20: adc [[TEMP]], qword ptr [rdx + 8*[[IND]] + 8] + // llvm-pre-20: mov qword ptr [rdi + 8*[[IND]] + 8], [[TEMP]] + // llvm-pre-20: mov [[TEMP]], qword ptr [rsi + 8*[[IND]] + 16] + // llvm-pre-20: adc [[TEMP]], qword ptr [rdx + 8*[[IND]] + 16] + // llvm-pre-20: mov qword ptr [rdi + 8*[[IND]] + 16], [[TEMP]] + // llvm-20: adc [[TEMP:r..]], qword ptr [rdx + 8*[[IND:r..]]] + // llvm-20: mov qword ptr [rdi + 8*[[IND]]], [[TEMP]] + // llvm-20: mov [[TEMP]], qword ptr [rsi + 8*[[IND]] + 8] + // llvm-20: adc [[TEMP]], qword ptr [rdx + 8*[[IND]] + 8] + for i in 0..n { + (*dest.add(i), carry) = u64::carrying_add(*src1.add(i), *src2.add(i), carry); + } + carry +} + +// CHECK-LABEL: bigint_chain_borrowing_sub: +#[no_mangle] +pub unsafe extern "sysv64" fn bigint_chain_borrowing_sub( + dest: *mut u64, + src1: *const u64, + src2: *const u64, + n: usize, + mut carry: bool, +) -> bool { + // CHECK: mov [[TEMP:r..]], qword ptr [rsi + 8*[[IND:r..]] + 8] + // CHECK: sbb [[TEMP]], qword ptr [rdx + 8*[[IND]] + 8] + // CHECK: mov qword ptr [rdi + 8*[[IND]] + 8], [[TEMP]] + // CHECK: mov [[TEMP]], qword ptr [rsi + 8*[[IND]] + 16] + // CHECK: sbb [[TEMP]], qword ptr [rdx + 8*[[IND]] + 16] + // CHECK: mov qword ptr [rdi + 8*[[IND]] + 16], [[TEMP]] + for i in 0..n { + (*dest.add(i), carry) = u64::borrowing_sub(*src1.add(i), *src2.add(i), carry); + } + carry +} diff --git a/tests/assembly-llvm/x86_64-cmp.rs b/tests/assembly-llvm/x86_64-cmp.rs new file mode 100644 index 00000000000..26c9013d96f --- /dev/null +++ b/tests/assembly-llvm/x86_64-cmp.rs @@ -0,0 +1,79 @@ +//@ revisions: LLVM-PRE-20-DEBUG LLVM-20-DEBUG LLVM-PRE-20-OPTIM LLVM-20-OPTIM +//@ [LLVM-PRE-20-DEBUG] compile-flags: -C opt-level=0 +//@ [LLVM-PRE-20-DEBUG] max-llvm-major-version: 19 +//@ [LLVM-20-DEBUG] compile-flags: -C opt-level=0 +//@ [LLVM-20-DEBUG] min-llvm-version: 20 +//@ [LLVM-PRE-20-OPTIM] compile-flags: -C opt-level=3 +//@ [LLVM-PRE-20-OPTIM] max-llvm-major-version: 19 +//@ [LLVM-20-OPTIM] compile-flags: -C opt-level=3 +//@ [LLVM-20-OPTIM] min-llvm-version: 20 +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -C llvm-args=-x86-asm-syntax=intel +//@ only-x86_64 +//@ ignore-sgx + +#![feature(core_intrinsics)] + +use std::intrinsics::three_way_compare; + +#[no_mangle] +// CHECK-LABEL: signed_cmp: +pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering { + // LLVM-PRE-20-DEBUG: cmp + // LLVM-PRE-20-DEBUG: setg + // LLVM-PRE-20-DEBUG: and + // LLVM-PRE-20-DEBUG: cmp + // LLVM-PRE-20-DEBUG: setl + // LLVM-PRE-20-DEBUG: and + // LLVM-PRE-20-DEBUG: sub + // + // LLVM-20-DEBUG: sub + // LLVM-20-DEBUG: setl + // LLVM-20-DEBUG: setg + // LLVM-20-DEBUG: sub + // LLVM-20-DEBUG: ret + + // LLVM-PRE-20-OPTIM: xor + // LLVM-PRE-20-OPTIM: cmp + // LLVM-PRE-20-OPTIM: setne + // LLVM-PRE-20-OPTIM: mov + // LLVM-PRE-20-OPTIM: cmovge + // LLVM-PRE-20-OPTIM: ret + // + // LLVM-20-OPTIM: cmp + // LLVM-20-OPTIM: setl + // LLVM-20-OPTIM: setg + // LLVM-20-OPTIM: sub + // LLVM-20-OPTIM: ret + three_way_compare(a, b) +} + +#[no_mangle] +// CHECK-LABEL: unsigned_cmp: +pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering { + // LLVM-PRE-20-DEBUG: cmp + // LLVM-PRE-20-DEBUG: seta + // LLVM-PRE-20-DEBUG: and + // LLVM-PRE-20-DEBUG: cmp + // LLVM-PRE-20-DEBUG: setb + // LLVM-PRE-20-DEBUG: and + // LLVM-PRE-20-DEBUG: sub + // + // LLVM-20-DEBUG: sub + // LLVM-20-DEBUG: seta + // LLVM-20-DEBUG: sbb + // LLVM-20-DEBUG: ret + + // LLVM-PRE-20-OPTIM: xor + // LLVM-PRE-20-OPTIM: cmp + // LLVM-PRE-20-OPTIM: setne + // LLVM-PRE-20-OPTIM: mov + // LLVM-PRE-20-OPTIM: cmovae + // LLVM-PRE-20-OPTIM: ret + // + // LLVM-20-OPTIM: cmp + // LLVM-20-OPTIM: seta + // LLVM-20-OPTIM: sbb + // LLVM-20-OPTIM: ret + three_way_compare(a, b) +} diff --git a/tests/assembly-llvm/x86_64-floating-point-clamp.rs b/tests/assembly-llvm/x86_64-floating-point-clamp.rs new file mode 100644 index 00000000000..6b0c29c5f21 --- /dev/null +++ b/tests/assembly-llvm/x86_64-floating-point-clamp.rs @@ -0,0 +1,27 @@ +// Floating-point clamp is designed to be implementable as max+min, +// so check to make sure that's what it's actually emitting. + +//@ assembly-output: emit-asm +// Set the base cpu explicitly, in case the default has been changed. +//@ compile-flags: --crate-type=lib -Copt-level=3 -C llvm-args=-x86-asm-syntax=intel -C target-cpu=x86-64 +//@ only-x86_64 +//@ ignore-sgx + +// CHECK-LABEL: clamp_demo: +#[no_mangle] +pub fn clamp_demo(a: f32, x: f32, y: f32) -> f32 { + // CHECK: maxss + // CHECK: minss + a.clamp(x, y) +} + +// CHECK-LABEL: clamp12_demo: +#[no_mangle] +pub fn clamp12_demo(a: f32) -> f32 { + // CHECK: movss xmm1 + // CHECK-NEXT: maxss xmm1, xmm0 + // CHECK-NEXT: movss xmm0 + // CHECK-NEXT: minss xmm0, xmm1 + // CHECK: ret + a.clamp(1.0, 2.0) +} diff --git a/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs new file mode 100644 index 00000000000..f5e2f18e68e --- /dev/null +++ b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs @@ -0,0 +1,17 @@ +// Test LVI load hardening on SGX enclave code + +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type staticlib +//@ only-x86_64-fortanix-unknown-sgx + +#[no_mangle] +pub extern "C" fn plus_one(r: &mut u64) { + *r = *r + 1; +} + +// CHECK: plus_one +// CHECK: lfence +// CHECK-NEXT: incq +// CHECK: popq [[REGISTER:%[a-z]+]] +// CHECK-NEXT: lfence +// CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs new file mode 100644 index 00000000000..f16d68fa255 --- /dev/null +++ b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs @@ -0,0 +1,12 @@ +// Test LVI ret hardening on generic rust code + +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type staticlib +//@ only-x86_64-fortanix-unknown-sgx + +#[no_mangle] +pub extern "C" fn myret() {} +// CHECK: myret: +// CHECK: popq [[REGISTER:%[a-z]+]] +// CHECK-NEXT: lfence +// CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs new file mode 100644 index 00000000000..a729df8e166 --- /dev/null +++ b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs @@ -0,0 +1,34 @@ +// Test LVI load hardening on SGX inline assembly code + +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type staticlib +//@ only-x86_64-fortanix-unknown-sgx + +use std::arch::asm; + +#[no_mangle] +pub extern "C" fn get(ptr: *const u64) -> u64 { + let value: u64; + unsafe { + asm!("mov {}, [{}]", + out(reg) value, + in(reg) ptr); + } + value +} + +// CHECK: get +// CHECK: movq +// CHECK-NEXT: lfence + +#[no_mangle] +pub extern "C" fn myret() { + unsafe { + asm!("ret"); + } +} + +// CHECK: myret +// CHECK: shlq $0, (%rsp) +// CHECK-NEXT: lfence +// CHECK-NEXT: retq diff --git a/tests/assembly-llvm/x86_64-function-return.rs b/tests/assembly-llvm/x86_64-function-return.rs new file mode 100644 index 00000000000..7fd57200a9e --- /dev/null +++ b/tests/assembly-llvm/x86_64-function-return.rs @@ -0,0 +1,30 @@ +// Test that the function return is (not) converted into a jump to the thunk +// when the `-Zfunction-return={keep,thunk-extern}` flag is (not) set. + +//@ revisions: unset keep thunk-extern keep-thunk-extern thunk-extern-keep +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 +//@ [keep] compile-flags: -Zfunction-return=keep +//@ [thunk-extern] compile-flags: -Zfunction-return=thunk-extern +//@ [keep-thunk-extern] compile-flags: -Zfunction-return=keep -Zfunction-return=thunk-extern +//@ [thunk-extern-keep] compile-flags: -Zfunction-return=thunk-extern -Zfunction-return=keep +//@ only-x86_64 +//@ ignore-apple Symbol is called `___x86_return_thunk` (Darwin's extra underscore) +//@ ignore-sgx Tests incompatible with LVI mitigations + +#![crate_type = "lib"] + +// CHECK-LABEL: foo: +#[no_mangle] +pub unsafe fn foo() { + // unset: ret + // unset-NOT: jmp __x86_return_thunk + // keep: ret + // keep-NOT: jmp __x86_return_thunk + // thunk-extern: jmp __x86_return_thunk + // thunk-extern-NOT: ret + // keep-thunk-extern: jmp __x86_return_thunk + // keep-thunk-extern-NOT: ret + // thunk-extern-keep: ret + // thunk-extern-keep-NOT: jmp __x86_return_thunk +} diff --git a/tests/assembly-llvm/x86_64-no-jump-tables.rs b/tests/assembly-llvm/x86_64-no-jump-tables.rs new file mode 100644 index 00000000000..bb10042d8f6 --- /dev/null +++ b/tests/assembly-llvm/x86_64-no-jump-tables.rs @@ -0,0 +1,35 @@ +// Test that jump tables are (not) emitted when the `-Zno-jump-tables` +// flag is (not) set. + +//@ revisions: unset set +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 +//@ [set] compile-flags: -Zno-jump-tables +//@ only-x86_64 +//@ ignore-sgx + +#![crate_type = "lib"] + +extern "C" { + fn bar1(); + fn bar2(); + fn bar3(); + fn bar4(); + fn bar5(); + fn bar6(); +} + +// CHECK-LABEL: foo: +#[no_mangle] +pub unsafe fn foo(x: i32) { + // unset: LJTI0_0 + // set-NOT: LJTI0_0 + match x { + 1 => bar1(), + 2 => bar2(), + 3 => bar3(), + 4 => bar4(), + 5 => bar5(), + _ => bar6(), + } +} diff --git a/tests/assembly-llvm/x86_64-sse_crc.rs b/tests/assembly-llvm/x86_64-sse_crc.rs new file mode 100644 index 00000000000..bde58955a21 --- /dev/null +++ b/tests/assembly-llvm/x86_64-sse_crc.rs @@ -0,0 +1,12 @@ +//@ only-x86_64 +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type staticlib -Ctarget-feature=+sse4.2 + +// CHECK-LABEL: banana +// CHECK: crc32 +#[no_mangle] +pub unsafe fn banana(v: u8) -> u32 { + use std::arch::x86_64::*; + let out = !0u32; + _mm_crc32_u8(out, v) +} diff --git a/tests/assembly-llvm/x86_64-typed-swap.rs b/tests/assembly-llvm/x86_64-typed-swap.rs new file mode 100644 index 00000000000..a6753011d36 --- /dev/null +++ b/tests/assembly-llvm/x86_64-typed-swap.rs @@ -0,0 +1,81 @@ +//@ revisions: WIN LIN +//@ [WIN] only-windows +//@ [LIN] only-linux +//@ only-x86_64 +//@ assembly-output: emit-asm +//@ compile-flags: --crate-type=lib -Copt-level=3 + +use std::arch::x86_64::__m128; +use std::mem::swap; + +// CHECK-LABEL: swap_i32: +#[no_mangle] +pub fn swap_i32(x: &mut i32, y: &mut i32) { + // CHECK: movl (%[[ARG1:.+]]), %[[T1:.+]] + // CHECK-NEXT: movl (%[[ARG2:.+]]), %[[T2:.+]] + // CHECK-DAG: movl %[[T2]], (%[[ARG1]]) + // CHECK-DAG: movl %[[T1]], (%[[ARG2]]) + // CHECK-NEXT: retq + swap(x, y) +} + +// CHECK-LABEL: swap_pair: +#[no_mangle] +pub fn swap_pair(x: &mut (i32, u32), y: &mut (i32, u32)) { + // CHECK: movq (%[[ARG1:r..?]]), %[[T1:.+]] + // CHECK-NEXT: movq (%[[ARG2:r..?]]), %[[T2:.+]] + // CHECK-DAG: movq %[[T2]], (%[[ARG1]]) + // CHECK-DAG: movq %[[T1]], (%[[ARG2]]) + // CHECK-NEXT: retq + swap(x, y) +} + +// CHECK-LABEL: swap_str: +#[no_mangle] +pub fn swap_str<'a>(x: &mut &'a str, y: &mut &'a str) { + // CHECK: movups (%[[ARG1:r..?]]), %[[T1:xmm.]] + // CHECK-NEXT: movups (%[[ARG2:r..?]]), %[[T2:xmm.]] + // CHECK-DAG: movups %[[T2]], (%[[ARG1]]) + // CHECK-DAG: movups %[[T1]], (%[[ARG2]]) + // CHECK-NEXT: retq + swap(x, y) +} + +// CHECK-LABEL: swap_simd: +#[no_mangle] +pub fn swap_simd(x: &mut __m128, y: &mut __m128) { + // CHECK: movaps (%[[ARG1:r..?]]), %[[T1:xmm.]] + // CHECK-NEXT: movaps (%[[ARG2:r..?]]), %[[T2:xmm.]] + // CHECK-DAG: movaps %[[T2]], (%[[ARG1]]) + // CHECK-DAG: movaps %[[T1]], (%[[ARG2]]) + // CHECK-NEXT: retq + swap(x, y) +} + +// CHECK-LABEL: swap_string: +#[no_mangle] +pub fn swap_string(x: &mut String, y: &mut String) { + // CHECK-NOT: mov + // CHECK-COUNT-4: movups + // CHECK-NOT: mov + // CHECK-COUNT-4: movq + // CHECK-NOT: mov + swap(x, y) +} + +// CHECK-LABEL: swap_44_bytes: +#[no_mangle] +pub fn swap_44_bytes(x: &mut [u8; 44], y: &mut [u8; 44]) { + // Ensure we do better than a long run of byte copies, + // see + + // CHECK-NOT: movb + // CHECK-COUNT-8: movups{{.+}}xmm + // CHECK-NOT: movb + // CHECK-COUNT-4: movq + // CHECK-NOT: movb + // CHECK-COUNT-4: movl + // CHECK-NOT: movb + // CHECK: retq + swap(x, y) +} diff --git a/tests/assembly-llvm/x86_64-windows-float-abi.rs b/tests/assembly-llvm/x86_64-windows-float-abi.rs new file mode 100644 index 00000000000..cbc80910851 --- /dev/null +++ b/tests/assembly-llvm/x86_64-windows-float-abi.rs @@ -0,0 +1,46 @@ +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 +//@ compile-flags: --target x86_64-pc-windows-msvc +//@ needs-llvm-components: x86 +//@ add-core-stubs + +#![feature(f16, f128)] +#![feature(no_core)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: second_f16 +// CHECK: movaps %xmm1, %xmm0 +// CHECK-NEXT: retq +#[no_mangle] +pub extern "C" fn second_f16(_: f16, x: f16) -> f16 { + x +} + +// CHECK-LABEL: second_f32 +// CHECK: movaps %xmm1, %xmm0 +// CHECK-NEXT: retq +#[no_mangle] +pub extern "C" fn second_f32(_: f32, x: f32) -> f32 { + x +} + +// CHECK-LABEL: second_f64 +// CHECK: movaps %xmm1, %xmm0 +// CHECK-NEXT: retq +#[no_mangle] +pub extern "C" fn second_f64(_: f64, x: f64) -> f64 { + x +} + +// CHECK-LABEL: second_f128 +// FIXME(llvm21): this can be just %rdx instead of the regex once we don't test on LLVM 20 +// CHECK: movaps {{(%xmm1|\(%rdx\))}}, %xmm0 +// CHECK-NEXT: retq +#[no_mangle] +pub extern "C" fn second_f128(_: f128, x: f128) -> f128 { + x +} diff --git a/tests/assembly-llvm/x86_64-windows-i128-abi.rs b/tests/assembly-llvm/x86_64-windows-i128-abi.rs new file mode 100644 index 00000000000..d2aefb7daa6 --- /dev/null +++ b/tests/assembly-llvm/x86_64-windows-i128-abi.rs @@ -0,0 +1,26 @@ +//@ assembly-output: emit-asm +//@ add-core-stubs +//@ revisions: msvc softfloat +//@ compile-flags: -Copt-level=3 +//@[msvc] compile-flags: --target x86_64-pc-windows-msvc +//@[msvc] needs-llvm-components: x86 +//@[softfloat] compile-flags: --target x86_64-unknown-uefi +//@[softfloat] needs-llvm-components: x86 + +#![feature(no_core)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: ret_i128 +// Hardfloat targets return via xmm0, softfloat targets via rax and rdx. +// msvc: movaps {{.*}}, %xmm0 +// softfloat: movq (%[[INPUT:.*]]), %rax +// softfloat-NEXT: movq 8(%[[INPUT]]), %rdx +// CHECK-NEXT: retq +#[no_mangle] +pub extern "C" fn ret_i128(x: &i128) -> i128 { + *x +} diff --git a/tests/assembly-llvm/x86_64-xray.rs b/tests/assembly-llvm/x86_64-xray.rs new file mode 100644 index 00000000000..4cf3e8cda13 --- /dev/null +++ b/tests/assembly-llvm/x86_64-xray.rs @@ -0,0 +1,25 @@ +//@ assembly-output: emit-asm +//@ compile-flags: -Zinstrument-xray=always -Cllvm-args=-x86-asm-syntax=intel + +//@ revisions: x86_64-linux +//@[x86_64-linux] compile-flags: --target=x86_64-unknown-linux-gnu +//@[x86_64-linux] needs-llvm-components: x86 +//@[x86_64-linux] only-x86_64-unknown-linux-gnu + +//@ revisions: x86_64-darwin +//@[x86_64-darwin] compile-flags: --target=x86_64-apple-darwin +//@[x86_64-darwin] needs-llvm-components: x86 +//@[x86_64-darwin] only-x86_64-apple-darwin + +#![crate_type = "lib"] + +// CHECK-LABEL: xray_func: +#[no_mangle] +pub fn xray_func() { + // CHECK: nop word ptr [rax + rax + 512] + + std::hint::black_box(()); + + // CHECK: ret + // CHECK-NEXT: nop word ptr cs:[rax + rax + 512] +} diff --git a/tests/assembly/aarch64-pointer-auth.rs b/tests/assembly/aarch64-pointer-auth.rs deleted file mode 100644 index 56a26df469f..00000000000 --- a/tests/assembly/aarch64-pointer-auth.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Test that PAC instructions are emitted when branch-protection is specified. - -//@ add-core-stubs -//@ revisions: PACRET PAUTHLR_NOP PAUTHLR -//@ assembly-output: emit-asm -//@ needs-llvm-components: aarch64 -//@ compile-flags: --target aarch64-unknown-linux-gnu -//@ [PACRET] compile-flags: -Z branch-protection=pac-ret,leaf -//@ [PAUTHLR_NOP] compile-flags: -Z branch-protection=pac-ret,pc,leaf -//@ [PAUTHLR] compile-flags: -C target-feature=+pauth-lr -Z branch-protection=pac-ret,pc,leaf - -#![feature(no_core, lang_items)] -#![no_std] -#![no_core] -#![crate_type = "lib"] - -extern crate minicore; -use minicore::*; - -// PACRET: hint #25 -// PACRET: hint #29 -// PAUTHLR_NOP: hint #25 -// PAUTHLR_NOP: hint #39 -// PAUTHLR_NOP: hint #29 -// PAUTHLR: paciasppc -// PAUTHLR: autiasppc -#[no_mangle] -pub fn test() -> u8 { - 42 -} diff --git a/tests/assembly/aarch64-xray.rs b/tests/assembly/aarch64-xray.rs deleted file mode 100644 index d5ee0111843..00000000000 --- a/tests/assembly/aarch64-xray.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ assembly-output: emit-asm -//@ compile-flags: -Zinstrument-xray=always - -//@ revisions: aarch64-linux -//@[aarch64-linux] compile-flags: --target=aarch64-unknown-linux-gnu -//@[aarch64-linux] needs-llvm-components: aarch64 -//@[aarch64-linux] only-aarch64-unknown-linux-gnu - -//@ revisions: aarch64-darwin -//@[aarch64-darwin] compile-flags: --target=aarch64-apple-darwin -//@[aarch64-darwin] needs-llvm-components: aarch64 -//@[aarch64-darwin] only-aarch64-apple-darwin - -#![crate_type = "lib"] - -// CHECK-LABEL: xray_func: -#[no_mangle] -pub fn xray_func() { - // CHECK: nop - - std::hint::black_box(()); - - // CHECK: b #32 - // CHECK-NEXT: nop -} diff --git a/tests/assembly/align_offset.rs b/tests/assembly/align_offset.rs deleted file mode 100644 index d9902ce336b..00000000000 --- a/tests/assembly/align_offset.rs +++ /dev/null @@ -1,47 +0,0 @@ -//@ assembly-output: emit-asm -//@ compile-flags: -Copt-level=1 -//@ only-x86_64 -#![crate_type = "rlib"] - -// CHECK-LABEL: align_offset_byte_ptr -// CHECK: leaq 31 -// CHECK: andq $-32 -// CHECK: subq -#[no_mangle] -pub fn align_offset_byte_ptr(ptr: *const u8) -> usize { - ptr.align_offset(32) -} - -// CHECK-LABEL: align_offset_byte_slice -// CHECK: leaq 31 -// CHECK: andq $-32 -// CHECK: subq -#[no_mangle] -pub fn align_offset_byte_slice(slice: &[u8]) -> usize { - slice.as_ptr().align_offset(32) -} - -// CHECK-LABEL: align_offset_word_ptr -// CHECK: leaq 31 -// CHECK: andq $-32 -// CHECK: subq -// CHECK: shrq -// This `ptr` is not known to be aligned, so it is required to check if it is at all possible to -// align. LLVM applies a simple mask. -// CHECK: orq -#[no_mangle] -pub fn align_offset_word_ptr(ptr: *const u32) -> usize { - ptr.align_offset(32) -} - -// CHECK-LABEL: align_offset_word_slice -// CHECK: leaq 31 -// CHECK: andq $-32 -// CHECK: subq -// CHECK: shrq -// `slice` is known to be aligned, so `!0` is not possible as a return -// CHECK-NOT: orq -#[no_mangle] -pub fn align_offset_word_slice(slice: &[u32]) -> usize { - slice.as_ptr().align_offset(32) -} diff --git a/tests/assembly/asm/aarch64-el2vmsa.rs b/tests/assembly/asm/aarch64-el2vmsa.rs deleted file mode 100644 index 3652d58d85a..00000000000 --- a/tests/assembly/asm/aarch64-el2vmsa.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: --target aarch64-unknown-linux-gnu -//@ needs-llvm-components: aarch64 - -#![feature(no_core)] -#![crate_type = "rlib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: ttbr0_el2: -#[no_mangle] -pub fn ttbr0_el2() { - // CHECK: //APP - // CHECK-NEXT: msr TTBR0_EL2, x0 - // CHECK-NEXT: //NO_APP - unsafe { - asm!("msr ttbr0_el2, x0"); - } -} - -// CHECK-LABEL: vttbr_el2: -#[no_mangle] -pub fn vttbr_el2() { - // CHECK: //APP - // CHECK-NEXT: msr VTTBR_EL2, x0 - // CHECK-NEXT: //NO_APP - unsafe { - asm!("msr vttbr_el2, x0"); - } -} diff --git a/tests/assembly/asm/aarch64-modifiers.rs b/tests/assembly/asm/aarch64-modifiers.rs deleted file mode 100644 index 58f7c114d3a..00000000000 --- a/tests/assembly/asm/aarch64-modifiers.rs +++ /dev/null @@ -1,128 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: -Copt-level=3 -C panic=abort -//@ compile-flags: --target aarch64-unknown-linux-gnu -//@ compile-flags: -Zmerge-functions=disabled -//@ needs-llvm-components: aarch64 - -#![feature(no_core)] -#![crate_type = "rlib"] -#![no_core] -#![allow(asm_sub_register)] - -extern crate minicore; -use minicore::*; - -macro_rules! check { - ($func:ident $reg:ident $code:literal) => { - // -Copt-level=3 and extern "C" guarantee that the selected register is always r0/s0/d0/q0 - #[no_mangle] - pub unsafe extern "C" fn $func() -> i32 { - let y; - asm!($code, out($reg) y); - y - } - }; -} - -// CHECK-LABEL: reg: -// CHECK: //APP -// CHECK: mov x0, x0 -// CHECK: //NO_APP -check!(reg reg "mov {0}, {0}"); - -// CHECK-LABEL: reg_w: -// CHECK: //APP -// CHECK: mov w0, w0 -// CHECK: //NO_APP -check!(reg_w reg "mov {0:w}, {0:w}"); - -// CHECK-LABEL: reg_x: -// CHECK: //APP -// CHECK: mov x0, x0 -// CHECK: //NO_APP -check!(reg_x reg "mov {0:x}, {0:x}"); - -// CHECK-LABEL: vreg: -// CHECK: //APP -// CHECK: add v0.4s, v0.4s, v0.4s -// CHECK: //NO_APP -check!(vreg vreg "add {0}.4s, {0}.4s, {0}.4s"); - -// CHECK-LABEL: vreg_b: -// CHECK: //APP -// CHECK: ldr b0, [x0] -// CHECK: //NO_APP -check!(vreg_b vreg "ldr {:b}, [x0]"); - -// CHECK-LABEL: vreg_h: -// CHECK: //APP -// CHECK: ldr h0, [x0] -// CHECK: //NO_APP -check!(vreg_h vreg "ldr {:h}, [x0]"); - -// CHECK-LABEL: vreg_s: -// CHECK: //APP -// CHECK: ldr s0, [x0] -// CHECK: //NO_APP -check!(vreg_s vreg "ldr {:s}, [x0]"); - -// CHECK-LABEL: vreg_d: -// CHECK: //APP -// CHECK: ldr d0, [x0] -// CHECK: //NO_APP -check!(vreg_d vreg "ldr {:d}, [x0]"); - -// CHECK-LABEL: vreg_q: -// CHECK: //APP -// CHECK: ldr q0, [x0] -// CHECK: //NO_APP -check!(vreg_q vreg "ldr {:q}, [x0]"); - -// CHECK-LABEL: vreg_v: -// CHECK: //APP -// CHECK: add v0.4s, v0.4s, v0.4s -// CHECK: //NO_APP -check!(vreg_v vreg "add {0:v}.4s, {0:v}.4s, {0:v}.4s"); - -// CHECK-LABEL: vreg_low16: -// CHECK: //APP -// CHECK: add v0.4s, v0.4s, v0.4s -// CHECK: //NO_APP -check!(vreg_low16 vreg_low16 "add {0}.4s, {0}.4s, {0}.4s"); - -// CHECK-LABEL: vreg_low16_b: -// CHECK: //APP -// CHECK: ldr b0, [x0] -// CHECK: //NO_APP -check!(vreg_low16_b vreg_low16 "ldr {:b}, [x0]"); - -// CHECK-LABEL: vreg_low16_h: -// CHECK: //APP -// CHECK: ldr h0, [x0] -// CHECK: //NO_APP -check!(vreg_low16_h vreg_low16 "ldr {:h}, [x0]"); - -// CHECK-LABEL: vreg_low16_s: -// CHECK: //APP -// CHECK: ldr s0, [x0] -// CHECK: //NO_APP -check!(vreg_low16_s vreg_low16 "ldr {:s}, [x0]"); - -// CHECK-LABEL: vreg_low16_d: -// CHECK: //APP -// CHECK: ldr d0, [x0] -// CHECK: //NO_APP -check!(vreg_low16_d vreg_low16 "ldr {:d}, [x0]"); - -// CHECK-LABEL: vreg_low16_q: -// CHECK: //APP -// CHECK: ldr q0, [x0] -// CHECK: //NO_APP -check!(vreg_low16_q vreg_low16 "ldr {:q}, [x0]"); - -// CHECK-LABEL: vreg_low16_v: -// CHECK: //APP -// CHECK: add v0.4s, v0.4s, v0.4s -// CHECK: //NO_APP -check!(vreg_low16_v vreg_low16 "add {0:v}.4s, {0:v}.4s, {0:v}.4s"); diff --git a/tests/assembly/asm/aarch64-outline-atomics.rs b/tests/assembly/asm/aarch64-outline-atomics.rs deleted file mode 100644 index 5990fb84942..00000000000 --- a/tests/assembly/asm/aarch64-outline-atomics.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ assembly-output: emit-asm -//@ compile-flags: -Copt-level=3 -//@ compile-flags: --target aarch64-unknown-linux-gnu -//@ needs-llvm-components: aarch64 -//@ only-aarch64 -//@ only-linux - -#![crate_type = "rlib"] - -use std::sync::atomic::AtomicI32; -use std::sync::atomic::Ordering::*; - -pub fn compare_exchange(a: &AtomicI32) { - // On AArch64 LLVM should outline atomic operations. - // CHECK: __aarch64_cas4_relax - let _ = a.compare_exchange(0, 10, Relaxed, Relaxed); -} diff --git a/tests/assembly/asm/aarch64-types.rs b/tests/assembly/asm/aarch64-types.rs deleted file mode 100644 index b7abeb02298..00000000000 --- a/tests/assembly/asm/aarch64-types.rs +++ /dev/null @@ -1,633 +0,0 @@ -//@ add-core-stubs -//@ revisions: aarch64 arm64ec -//@ assembly-output: emit-asm -//@ [aarch64] compile-flags: --target aarch64-unknown-linux-gnu -//@ [aarch64] needs-llvm-components: aarch64 -//@ [arm64ec] compile-flags: --target arm64ec-pc-windows-msvc -//@ [arm64ec] needs-llvm-components: aarch64 -//@ compile-flags: -Zmerge-functions=disabled - -#![feature(no_core, repr_simd, f16, f128)] -#![crate_type = "rlib"] -#![no_core] -#![allow(asm_sub_register, non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -type ptr = *mut u8; - -#[repr(simd)] -pub struct i8x8([i8; 8]); -#[repr(simd)] -pub struct i16x4([i16; 4]); -#[repr(simd)] -pub struct i32x2([i32; 2]); -#[repr(simd)] -pub struct i64x1([i64; 1]); -#[repr(simd)] -pub struct f16x4([f16; 4]); -#[repr(simd)] -pub struct f32x2([f32; 2]); -#[repr(simd)] -pub struct f64x1([f64; 1]); -#[repr(simd)] -pub struct i8x16([i8; 16]); -#[repr(simd)] -pub struct i16x8([i16; 8]); -#[repr(simd)] -pub struct i32x4([i32; 4]); -#[repr(simd)] -pub struct i64x2([i64; 2]); -#[repr(simd)] -pub struct f16x8([f16; 8]); -#[repr(simd)] -pub struct f32x4([f32; 4]); -#[repr(simd)] -pub struct f64x2([f64; 2]); - -impl Copy for i8x8 {} -impl Copy for i16x4 {} -impl Copy for i32x2 {} -impl Copy for i64x1 {} -impl Copy for f16x4 {} -impl Copy for f32x2 {} -impl Copy for f64x1 {} -impl Copy for i8x16 {} -impl Copy for i16x8 {} -impl Copy for i32x4 {} -impl Copy for i64x2 {} -impl Copy for f16x8 {} -impl Copy for f32x4 {} -impl Copy for f64x2 {} - -extern "C" { - fn extern_func(); - static extern_static: u8; -} - -// CHECK-LABEL: {{("#)?}}sym_fn{{"?}} -// CHECK: //APP -// CHECK: bl extern_func -// CHECK: //NO_APP -#[no_mangle] -pub unsafe fn sym_fn() { - asm!("bl {}", sym extern_func); -} - -// CHECK-LABEL: {{("#)?}}sym_static{{"?}} -// CHECK: //APP -// CHECK: adr x0, extern_static -// CHECK: //NO_APP -#[no_mangle] -pub unsafe fn sym_static() { - asm!("adr x0, {}", sym extern_static); -} - -// Regression test for #75761 -// CHECK-LABEL: {{("#)?}}issue_75761{{"?}} -// x29 holds the frame pointer, right next to x30, so ldp/stp happens sometimes -// CHECK: st[[MAY_PAIR:(r|p).*]]x30 -// CHECK: //APP -// CHECK: //NO_APP -// CHECK: ld[[MAY_PAIR]]x30 -#[no_mangle] -pub unsafe fn issue_75761() { - asm!("", out("v0") _, out("x30") _); -} - -macro_rules! check { - ($func:ident $ty:ident $class:ident $mov:literal $modifier:literal) => { - // FIXME(f16_f128): Change back to `$func(x: $ty) -> $ty` once arm64ec can pass and return - // `f16` and `f128` without LLVM erroring. - // LLVM issue: - #[no_mangle] - pub unsafe fn $func(inp: &$ty, out: &mut $ty) { - let x = *inp; - let y; - asm!( - concat!($mov, " {:", $modifier, "}, {:", $modifier, "}"), - out($class) y, - in($class) x - ); - *out = y; - } - }; -} - -macro_rules! check_reg { - ($func:ident $ty:ident $reg:tt $mov:literal) => { - // FIXME(f16_f128): See FIXME in `check!` - #[no_mangle] - pub unsafe fn $func(inp: &$ty, out: &mut $ty) { - let x = *inp; - let y; - asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); - *out = y; - } - }; -} - -// CHECK-LABEL: {{("#)?}}reg_i8{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check!(reg_i8 i8 reg "mov" ""); - -// CHECK-LABEL: {{("#)?}}reg_i16{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check!(reg_i16 i16 reg "mov" ""); - -// CHECK-LABEL: {{("#)?}}reg_f16{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check!(reg_f16 f16 reg "mov" ""); - -// CHECK-LABEL: {{("#)?}}reg_i32{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check!(reg_i32 i32 reg "mov" ""); - -// CHECK-LABEL: {{("#)?}}reg_f32{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check!(reg_f32 f32 reg "mov" ""); - -// CHECK-LABEL: {{("#)?}}reg_i64{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check!(reg_i64 i64 reg "mov" ""); - -// CHECK-LABEL: {{("#)?}}reg_f64{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check!(reg_f64 f64 reg "mov" ""); - -// CHECK-LABEL: {{("#)?}}reg_ptr{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check!(reg_ptr ptr reg "mov" ""); - -// CHECK-LABEL: {{("#)?}}vreg_i8{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_i8 i8 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_i16{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_i16 i16 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_f16{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_f16 f16 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_i32{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_i32 i32 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_f32{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_f32 f32 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_i64{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_i64 i64 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_f64{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_f64 f64 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_f128{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_f128 f128 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_ptr{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_ptr ptr vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_i8x8{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_i8x8 i8x8 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_i16x4{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_i16x4 i16x4 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_i32x2{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_i32x2 i32x2 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_i64x1{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_i64x1 i64x1 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_f16x4{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_f16x4 f16x4 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_f32x2{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_f32x2 f32x2 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_f64x1{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_f64x1 f64x1 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_i8x16{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_i8x16 i8x16 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_i16x8{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_i16x8 i16x8 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_i32x4{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_i32x4 i32x4 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_i64x2{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_i64x2 i64x2 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_f16x8{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_f16x8 f16x8 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_f32x4{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_f32x4 f32x4 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_f64x2{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_f64x2 f64x2 vreg "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_i8{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_i8 i8 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_i16{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_i16 i16 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_f16{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_f16 f16 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_f32{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_f32 f32 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_i64{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_i64 i64 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_f64{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_f64 f64 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_f128{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_f128 f128 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_ptr{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_ptr ptr vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_i8x8{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_i8x8 i8x8 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_i16x4{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_i16x4 i16x4 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_i32x2{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_i32x2 i32x2 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_i64x1{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_i64x1 i64x1 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_f16x4{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_f16x4 f16x4 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_f32x2{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_f32x2 f32x2 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_f64x1{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_f64x1 f64x1 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_i8x16{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_i8x16 i8x16 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_i16x8{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_i16x8 i16x8 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_i32x4{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_i32x4 i32x4 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_i64x2{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_i64x2 i64x2 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_f16x8{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_f16x8 f16x8 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_f32x4{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_f32x4 f32x4 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}vreg_low16_f64x2{{"?}} -// CHECK: //APP -// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: //NO_APP -check!(vreg_low16_f64x2 f64x2 vreg_low16 "fmov" "s"); - -// CHECK-LABEL: {{("#)?}}x0_i8{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check_reg!(x0_i8 i8 "x0" "mov"); - -// CHECK-LABEL: {{("#)?}}x0_i16{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check_reg!(x0_i16 i16 "x0" "mov"); - -// CHECK-LABEL: {{("#)?}}x0_f16{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check_reg!(x0_f16 f16 "x0" "mov"); - -// CHECK-LABEL: {{("#)?}}x0_i32{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check_reg!(x0_i32 i32 "x0" "mov"); - -// CHECK-LABEL: {{("#)?}}x0_f32{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check_reg!(x0_f32 f32 "x0" "mov"); - -// CHECK-LABEL: {{("#)?}}x0_i64{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check_reg!(x0_i64 i64 "x0" "mov"); - -// CHECK-LABEL: {{("#)?}}x0_f64{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check_reg!(x0_f64 f64 "x0" "mov"); - -// CHECK-LABEL: {{("#)?}}x0_ptr{{"?}} -// CHECK: //APP -// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} -// CHECK: //NO_APP -check_reg!(x0_ptr ptr "x0" "mov"); - -// CHECK-LABEL: {{("#)?}}v0_i8{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_i8 i8 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_i16{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_i16 i16 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_f16{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_f16 f16 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_i32{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_i32 i32 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_f32{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_f32 f32 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_i64{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_i64 i64 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_f64{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_f64 f64 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_f128{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_f128 f128 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_ptr{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_ptr ptr "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_i8x8{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_i8x8 i8x8 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_i16x4{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_i16x4 i16x4 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_i32x2{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_i32x2 i32x2 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_i64x1{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_i64x1 i64x1 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_f16x4{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_f16x4 f16x4 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_f32x2{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_f32x2 f32x2 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_f64x1{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_f64x1 f64x1 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_i8x16{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_i8x16 i8x16 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_i16x8{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_i16x8 i16x8 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_i32x4{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_i32x4 i32x4 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_i64x2{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_i64x2 i64x2 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_f16x8{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_f16x8 f16x8 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_f32x4{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_f32x4 f32x4 "s0" "fmov"); - -// CHECK-LABEL: {{("#)?}}v0_f64x2{{"?}} -// CHECK: //APP -// CHECK: fmov s0, s0 -// CHECK: //NO_APP -check_reg!(v0_f64x2 f64x2 "s0" "fmov"); diff --git a/tests/assembly/asm/arm-modifiers.rs b/tests/assembly/asm/arm-modifiers.rs deleted file mode 100644 index 32a36840492..00000000000 --- a/tests/assembly/asm/arm-modifiers.rs +++ /dev/null @@ -1,122 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: -Copt-level=3 -C panic=abort -//@ compile-flags: --target armv7-unknown-linux-gnueabihf -//@ compile-flags: -C target-feature=+neon -//@ compile-flags: -Zmerge-functions=disabled -//@ needs-llvm-components: arm - -#![feature(no_core, repr_simd)] -#![crate_type = "rlib"] -#![no_core] -#![allow(asm_sub_register, non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -#[repr(simd)] -pub struct f32x4([f32; 4]); - -impl Copy for f32x4 {} - -macro_rules! check { - ($func:ident $modifier:literal $reg:ident $ty:ident $mov:literal) => { - // -Copt-level=3 and extern "C" guarantee that the selected register is always r0/s0/d0/q0 - #[no_mangle] - pub unsafe extern "C" fn $func() -> $ty { - let y; - asm!(concat!($mov, " {0:", $modifier, "}, {0:", $modifier, "}"), out($reg) y); - y - } - }; -} - -// CHECK-LABEL: reg: -// CHECK: @APP -// CHECK: mov r0, r0 -// CHECK: @NO_APP -check!(reg "" reg i32 "mov"); - -// CHECK-LABEL: sreg: -// CHECK: @APP -// CHECK: vmov.f32 s0, s0 -// CHECK: @NO_APP -check!(sreg "" sreg f32 "vmov.f32"); - -// CHECK-LABEL: sreg_low16: -// CHECK: @APP -// CHECK: vmov.f32 s0, s0 -// CHECK: @NO_APP -check!(sreg_low16 "" sreg_low16 f32 "vmov.f32"); - -// CHECK-LABEL: dreg: -// CHECK: @APP -// CHECK: vmov.f64 d0, d0 -// CHECK: @NO_APP -check!(dreg "" dreg f64 "vmov.f64"); - -// CHECK-LABEL: dreg_low16: -// CHECK: @APP -// CHECK: vmov.f64 d0, d0 -// CHECK: @NO_APP -check!(dreg_low16 "" dreg_low16 f64 "vmov.f64"); - -// CHECK-LABEL: dreg_low8: -// CHECK: @APP -// CHECK: vmov.f64 d0, d0 -// CHECK: @NO_APP -check!(dreg_low8 "" dreg_low8 f64 "vmov.f64"); - -// CHECK-LABEL: qreg: -// CHECK: @APP -// CHECK: vorr q0, q0, q0 -// CHECK: @NO_APP -check!(qreg "" qreg f32x4 "vmov"); - -// CHECK-LABEL: qreg_e: -// CHECK: @APP -// CHECK: vmov.f64 d0, d0 -// CHECK: @NO_APP -check!(qreg_e "e" qreg f32x4 "vmov.f64"); - -// CHECK-LABEL: qreg_f: -// CHECK: @APP -// CHECK: vmov.f64 d1, d1 -// CHECK: @NO_APP -check!(qreg_f "f" qreg f32x4 "vmov.f64"); - -// CHECK-LABEL: qreg_low8: -// CHECK: @APP -// CHECK: vorr q0, q0, q0 -// CHECK: @NO_APP -check!(qreg_low8 "" qreg_low8 f32x4 "vmov"); - -// CHECK-LABEL: qreg_low8_e: -// CHECK: @APP -// CHECK: vmov.f64 d0, d0 -// CHECK: @NO_APP -check!(qreg_low8_e "e" qreg_low8 f32x4 "vmov.f64"); - -// CHECK-LABEL: qreg_low8_f: -// CHECK: @APP -// CHECK: vmov.f64 d1, d1 -// CHECK: @NO_APP -check!(qreg_low8_f "f" qreg_low8 f32x4 "vmov.f64"); - -// CHECK-LABEL: qreg_low4: -// CHECK: @APP -// CHECK: vorr q0, q0, q0 -// CHECK: @NO_APP -check!(qreg_low4 "" qreg_low4 f32x4 "vmov"); - -// CHECK-LABEL: qreg_low4_e: -// CHECK: @APP -// CHECK: vmov.f64 d0, d0 -// CHECK: @NO_APP -check!(qreg_low4_e "e" qreg_low4 f32x4 "vmov.f64"); - -// CHECK-LABEL: qreg_low4_f: -// CHECK: @APP -// CHECK: vmov.f64 d1, d1 -// CHECK: @NO_APP -check!(qreg_low4_f "f" qreg_low4 f32x4 "vmov.f64"); diff --git a/tests/assembly/asm/arm-types.rs b/tests/assembly/asm/arm-types.rs deleted file mode 100644 index fb93f474c20..00000000000 --- a/tests/assembly/asm/arm-types.rs +++ /dev/null @@ -1,639 +0,0 @@ -//@ add-core-stubs -//@ revisions: base d32 neon -//@ assembly-output: emit-asm -//@ compile-flags: --target armv7-unknown-linux-gnueabihf -//@ compile-flags: -C opt-level=0 -//@ compile-flags: -Zmerge-functions=disabled -//@[d32] compile-flags: -C target-feature=+d32 -//@[neon] compile-flags: -C target-feature=+neon --cfg d32 -//@[neon] filecheck-flags: --check-prefix d32 -//@ needs-llvm-components: arm - -#![feature(no_core, repr_simd, f16)] -#![crate_type = "rlib"] -#![no_core] -#![allow(asm_sub_register, non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -type ptr = *mut u8; - -#[repr(simd)] -pub struct i8x8([i8; 8]); -#[repr(simd)] -pub struct i16x4([i16; 4]); -#[repr(simd)] -pub struct i32x2([i32; 2]); -#[repr(simd)] -pub struct i64x1([i64; 1]); -#[repr(simd)] -pub struct f16x4([f16; 4]); -#[repr(simd)] -pub struct f32x2([f32; 2]); -#[repr(simd)] -pub struct i8x16([i8; 16]); -#[repr(simd)] -pub struct i16x8([i16; 8]); -#[repr(simd)] -pub struct i32x4([i32; 4]); -#[repr(simd)] -pub struct i64x2([i64; 2]); -#[repr(simd)] -pub struct f16x8([f16; 8]); -#[repr(simd)] -pub struct f32x4([f32; 4]); - -impl Copy for i8x8 {} -impl Copy for i16x4 {} -impl Copy for i32x2 {} -impl Copy for i64x1 {} -impl Copy for f16x4 {} -impl Copy for f32x2 {} -impl Copy for i8x16 {} -impl Copy for i16x8 {} -impl Copy for i32x4 {} -impl Copy for i64x2 {} -impl Copy for f16x8 {} -impl Copy for f32x4 {} - -extern "C" { - fn extern_func(); - static extern_static: u8; -} - -// CHECK-LABEL: sym_fn: -// CHECK: @APP -// CHECK: bl extern_func -// CHECK: @NO_APP -#[no_mangle] -pub unsafe fn sym_fn() { - asm!("bl {}", sym extern_func); -} - -// CHECK-LABEL: sym_static: -// CHECK: @APP -// CHECK: adr r0, extern_static -// CHECK: @NO_APP -#[no_mangle] -pub unsafe fn sym_static() { - asm!("adr r0, {}", sym extern_static); -} - -// Regression test for #82052. -// CHECK-LABEL: issue_82052 -// CHECK: push {{.*}}lr -// CHECK: @APP -// CHECK: @NO_APP -pub unsafe fn issue_82052() { - asm!("", out("r14") _); -} - -macro_rules! check { - ($func:ident $ty:ident $class:ident $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov, " {}, {}"), out($class) y, in($class) x); - y - } - }; -} - -macro_rules! check_reg { - ($func:ident $ty:ident $reg:tt $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); - y - } - }; -} - -// CHECK-LABEL: reg_i8: -// CHECK: @APP -// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: @NO_APP -check!(reg_i8 i8 reg "mov"); - -// CHECK-LABEL: reg_i16: -// CHECK: @APP -// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: @NO_APP -check!(reg_i16 i16 reg "mov"); - -// CHECK-LABEL: reg_i32: -// CHECK: @APP -// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: @NO_APP -check!(reg_i32 i32 reg "mov"); - -// CHECK-LABEL: reg_f16: -// CHECK: @APP -// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: @NO_APP -check!(reg_f16 f16 reg "mov"); - -// CHECK-LABEL: reg_f32: -// CHECK: @APP -// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: @NO_APP -check!(reg_f32 f32 reg "mov"); - -// CHECK-LABEL: reg_ptr: -// CHECK: @APP -// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: @NO_APP -check!(reg_ptr ptr reg "mov"); - -// CHECK-LABEL: sreg_i32: -// CHECK: @APP -// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: @NO_APP -check!(sreg_i32 i32 sreg "vmov.f32"); - -// CHECK-LABEL: sreg_f16: -// CHECK: @APP -// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: @NO_APP -check!(sreg_f16 f16 sreg "vmov.f32"); - -// CHECK-LABEL: sreg_f32: -// CHECK: @APP -// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: @NO_APP -check!(sreg_f32 f32 sreg "vmov.f32"); - -// CHECK-LABEL: sreg_ptr: -// CHECK: @APP -// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: @NO_APP -check!(sreg_ptr ptr sreg "vmov.f32"); - -// CHECK-LABEL: sreg_low16_i32: -// CHECK: @APP -// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: @NO_APP -check!(sreg_low16_i32 i32 sreg_low16 "vmov.f32"); - -// CHECK-LABEL: sreg_low16_f16: -// CHECK: @APP -// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: @NO_APP -check!(sreg_low16_f16 f16 sreg_low16 "vmov.f32"); - -// CHECK-LABEL: sreg_low16_f32: -// CHECK: @APP -// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} -// CHECK: @NO_APP -check!(sreg_low16_f32 f32 sreg_low16 "vmov.f32"); - -// d32-LABEL: dreg_i64: -// d32: @APP -// d32: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// d32: @NO_APP -#[cfg(d32)] -check!(dreg_i64 i64 dreg "vmov.f64"); - -// d32-LABEL: dreg_f64: -// d32: @APP -// d32: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// d32: @NO_APP -#[cfg(d32)] -check!(dreg_f64 f64 dreg "vmov.f64"); - -// neon-LABEL: dreg_i8x8: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_i8x8 i8x8 dreg "vmov.f64"); - -// neon-LABEL: dreg_i16x4: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_i16x4 i16x4 dreg "vmov.f64"); - -// neon-LABEL: dreg_i32x2: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_i32x2 i32x2 dreg "vmov.f64"); - -// neon-LABEL: dreg_i64x1: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_i64x1 i64x1 dreg "vmov.f64"); - -// neon-LABEL: dreg_f16x4: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_f16x4 f16x4 dreg "vmov.f64"); - -// neon-LABEL: dreg_f32x2: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_f32x2 f32x2 dreg "vmov.f64"); - -// CHECK-LABEL: dreg_low16_i64: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP -check!(dreg_low16_i64 i64 dreg_low16 "vmov.f64"); - -// CHECK-LABEL: dreg_low16_f64: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP -check!(dreg_low16_f64 f64 dreg_low16 "vmov.f64"); - -// neon-LABEL: dreg_low16_i8x8: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_low16_i8x8 i8x8 dreg_low16 "vmov.f64"); - -// neon-LABEL: dreg_low16_i16x4: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_low16_i16x4 i16x4 dreg_low16 "vmov.f64"); - -// neon-LABEL: dreg_low16_i32x2: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_low16_i32x2 i32x2 dreg_low16 "vmov.f64"); - -// neon-LABEL: dreg_low16_i64x1: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_low16_i64x1 i64x1 dreg_low16 "vmov.f64"); - -// neon-LABEL: dreg_low16_f16x4: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_low16_f16x4 f16x4 dreg_low16 "vmov.f64"); - -// neon-LABEL: dreg_low16_f32x2: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_low16_f32x2 f32x2 dreg_low16 "vmov.f64"); - -// CHECK-LABEL: dreg_low8_i64: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP -check!(dreg_low8_i64 i64 dreg_low8 "vmov.f64"); - -// CHECK-LABEL: dreg_low8_f64: -// CHECK: @APP -// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// CHECK: @NO_APP -check!(dreg_low8_f64 f64 dreg_low8 "vmov.f64"); - -// neon-LABEL: dreg_low8_i8x8: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_low8_i8x8 i8x8 dreg_low8 "vmov.f64"); - -// neon-LABEL: dreg_low8_i16x4: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_low8_i16x4 i16x4 dreg_low8 "vmov.f64"); - -// neon-LABEL: dreg_low8_i32x2: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_low8_i32x2 i32x2 dreg_low8 "vmov.f64"); - -// neon-LABEL: dreg_low8_i64x1: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_low8_i64x1 i64x1 dreg_low8 "vmov.f64"); - -// neon-LABEL: dreg_low8_f16x4: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_low8_f16x4 f16x4 dreg_low8 "vmov.f64"); - -// neon-LABEL: dreg_low8_f32x2: -// neon: @APP -// neon: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(dreg_low8_f32x2 f32x2 dreg_low8 "vmov.f64"); - -// neon-LABEL: qreg_i8x16: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_i8x16 i8x16 qreg "vmov"); - -// neon-LABEL: qreg_i16x8: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_i16x8 i16x8 qreg "vmov"); - -// neon-LABEL: qreg_i32x4: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_i32x4 i32x4 qreg "vmov"); - -// neon-LABEL: qreg_i64x2: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_i64x2 i64x2 qreg "vmov"); - -// neon-LABEL: qreg_f16x8: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_f16x8 f16x8 qreg "vmov"); - -// neon-LABEL: qreg_f32x4: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_f32x4 f32x4 qreg "vmov"); - -// neon-LABEL: qreg_low8_i8x16: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_low8_i8x16 i8x16 qreg_low8 "vmov"); - -// neon-LABEL: qreg_low8_i16x8: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_low8_i16x8 i16x8 qreg_low8 "vmov"); - -// neon-LABEL: qreg_low8_i32x4: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_low8_i32x4 i32x4 qreg_low8 "vmov"); - -// neon-LABEL: qreg_low8_i64x2: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_low8_i64x2 i64x2 qreg_low8 "vmov"); - -// neon-LABEL: qreg_low8_f16x8: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_low8_f16x8 f16x8 qreg_low8 "vmov"); - -// neon-LABEL: qreg_low8_f32x4: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_low8_f32x4 f32x4 qreg_low8 "vmov"); - -// neon-LABEL: qreg_low4_i8x16: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_low4_i8x16 i8x16 qreg_low4 "vmov"); - -// neon-LABEL: qreg_low4_i16x8: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_low4_i16x8 i16x8 qreg_low4 "vmov"); - -// neon-LABEL: qreg_low4_i32x4: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_low4_i32x4 i32x4 qreg_low4 "vmov"); - -// neon-LABEL: qreg_low4_i64x2: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_low4_i64x2 i64x2 qreg_low4 "vmov"); - -// neon-LABEL: qreg_low4_f16x8: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_low4_f16x8 f16x8 qreg_low4 "vmov"); - -// neon-LABEL: qreg_low4_f32x4: -// neon: @APP -// neon: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} -// neon: @NO_APP -#[cfg(neon)] -check!(qreg_low4_f32x4 f32x4 qreg_low4 "vmov"); - -// CHECK-LABEL: r0_i8: -// CHECK: @APP -// CHECK: mov r0, r0 -// CHECK: @NO_APP -check_reg!(r0_i8 i8 "r0" "mov"); - -// CHECK-LABEL: r0_i16: -// CHECK: @APP -// CHECK: mov r0, r0 -// CHECK: @NO_APP -check_reg!(r0_i16 i16 "r0" "mov"); - -// CHECK-LABEL: r0_i32: -// CHECK: @APP -// CHECK: mov r0, r0 -// CHECK: @NO_APP -check_reg!(r0_i32 i32 "r0" "mov"); - -// CHECK-LABEL: r0_f16: -// CHECK: @APP -// CHECK: mov r0, r0 -// CHECK: @NO_APP -check_reg!(r0_f16 f16 "r0" "mov"); - -// CHECK-LABEL: r0_f32: -// CHECK: @APP -// CHECK: mov r0, r0 -// CHECK: @NO_APP -check_reg!(r0_f32 f32 "r0" "mov"); - -// CHECK-LABEL: r0_ptr: -// CHECK: @APP -// CHECK: mov r0, r0 -// CHECK: @NO_APP -check_reg!(r0_ptr ptr "r0" "mov"); - -// CHECK-LABEL: s0_i32: -// CHECK: @APP -// CHECK: vmov.f32 s0, s0 -// CHECK: @NO_APP -check_reg!(s0_i32 i32 "s0" "vmov.f32"); - -// CHECK-LABEL: s0_f16: -// CHECK: @APP -// CHECK: vmov.f32 s0, s0 -// CHECK: @NO_APP -check_reg!(s0_f16 f16 "s0" "vmov.f32"); - -// CHECK-LABEL: s0_f32: -// CHECK: @APP -// CHECK: vmov.f32 s0, s0 -// CHECK: @NO_APP -check_reg!(s0_f32 f32 "s0" "vmov.f32"); - -// CHECK-LABEL: s0_ptr: -// CHECK: @APP -// CHECK: vmov.f32 s0, s0 -// CHECK: @NO_APP -check_reg!(s0_ptr ptr "s0" "vmov.f32"); - -// FIXME(#126797): "d0" should work with `i64` and `f64` even when `d32` is disabled. -// d32-LABEL: d0_i64: -// d32: @APP -// d32: vmov.f64 d0, d0 -// d32: @NO_APP -#[cfg(d32)] -check_reg!(d0_i64 i64 "d0" "vmov.f64"); - -// d32-LABEL: d0_f64: -// d32: @APP -// d32: vmov.f64 d0, d0 -// d32: @NO_APP -#[cfg(d32)] -check_reg!(d0_f64 f64 "d0" "vmov.f64"); - -// neon-LABEL: d0_i8x8: -// neon: @APP -// neon: vmov.f64 d0, d0 -// neon: @NO_APP -#[cfg(neon)] -check_reg!(d0_i8x8 i8x8 "d0" "vmov.f64"); - -// neon-LABEL: d0_i16x4: -// neon: @APP -// neon: vmov.f64 d0, d0 -// neon: @NO_APP -#[cfg(neon)] -check_reg!(d0_i16x4 i16x4 "d0" "vmov.f64"); - -// neon-LABEL: d0_i32x2: -// neon: @APP -// neon: vmov.f64 d0, d0 -// neon: @NO_APP -#[cfg(neon)] -check_reg!(d0_i32x2 i32x2 "d0" "vmov.f64"); - -// neon-LABEL: d0_i64x1: -// neon: @APP -// neon: vmov.f64 d0, d0 -// neon: @NO_APP -#[cfg(neon)] -check_reg!(d0_i64x1 i64x1 "d0" "vmov.f64"); - -// neon-LABEL: d0_f16x4: -// neon: @APP -// neon: vmov.f64 d0, d0 -// neon: @NO_APP -#[cfg(neon)] -check_reg!(d0_f16x4 f16x4 "d0" "vmov.f64"); - -// neon-LABEL: d0_f32x2: -// neon: @APP -// neon: vmov.f64 d0, d0 -// neon: @NO_APP -#[cfg(neon)] -check_reg!(d0_f32x2 f32x2 "d0" "vmov.f64"); - -// neon-LABEL: q0_i8x16: -// neon: @APP -// neon: vorr q0, q0, q0 -// neon: @NO_APP -#[cfg(neon)] -check_reg!(q0_i8x16 i8x16 "q0" "vmov"); - -// neon-LABEL: q0_i16x8: -// neon: @APP -// neon: vorr q0, q0, q0 -// neon: @NO_APP -#[cfg(neon)] -check_reg!(q0_i16x8 i16x8 "q0" "vmov"); - -// neon-LABEL: q0_i32x4: -// neon: @APP -// neon: vorr q0, q0, q0 -// neon: @NO_APP -#[cfg(neon)] -check_reg!(q0_i32x4 i32x4 "q0" "vmov"); - -// neon-LABEL: q0_i64x2: -// neon: @APP -// neon: vorr q0, q0, q0 -// neon: @NO_APP -#[cfg(neon)] -check_reg!(q0_i64x2 i64x2 "q0" "vmov"); - -// neon-LABEL: q0_f16x8: -// neon: @APP -// neon: vorr q0, q0, q0 -// neon: @NO_APP -#[cfg(neon)] -check_reg!(q0_f16x8 f16x8 "q0" "vmov"); - -// neon-LABEL: q0_f32x4: -// neon: @APP -// neon: vorr q0, q0, q0 -// neon: @NO_APP -#[cfg(neon)] -check_reg!(q0_f32x4 f32x4 "q0" "vmov"); diff --git a/tests/assembly/asm/avr-modifiers.rs b/tests/assembly/asm/avr-modifiers.rs deleted file mode 100644 index 124cad9bef6..00000000000 --- a/tests/assembly/asm/avr-modifiers.rs +++ /dev/null @@ -1,43 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: --target avr-none -C target-cpu=atmega328p -//@ needs-llvm-components: avr - -#![feature(no_core, asm_experimental_arch)] -#![crate_type = "rlib"] -#![no_core] -#![allow(non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -type ptr = *const u64; - -macro_rules! check { - ($func:ident $hi:literal $lo:literal $reg:tt) => { - #[no_mangle] - unsafe fn $func() -> i16 { - let y; - asm!(concat!("mov {0:", $hi, "}, {0:", $lo, "}"), out($reg) y); - y - } - }; -} - -// CHECK-LABEL: reg_pair_modifiers: -// CHECK: ;APP -// CHECK: mov r{{[1-9]?[13579]}}, r{{[1-9]?[24680]}} -// CHECK: ;NO_APP -check!(reg_pair_modifiers "h" "l" reg_pair); - -// CHECK-LABEL: reg_iw_modifiers: -// CHECK: ;APP -// CHECK: mov r{{[1-9]?[13579]}}, r{{[1-9]?[24680]}} -// CHECK: ;NO_APP -check!(reg_iw_modifiers "h" "l" reg_iw); - -// CHECK-LABEL: reg_ptr_modifiers: -// CHECK: ;APP -// CHECK: mov r{{[1-9]?[13579]}}, r{{[1-9]?[24680]}} -// CHECK: ;NO_APP -check!(reg_ptr_modifiers "h" "l" reg_ptr); diff --git a/tests/assembly/asm/avr-types.rs b/tests/assembly/asm/avr-types.rs deleted file mode 100644 index 309405f4d51..00000000000 --- a/tests/assembly/asm/avr-types.rs +++ /dev/null @@ -1,205 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: --target avr-none -C target-cpu=atmega328p -//@ needs-llvm-components: avr - -#![feature(no_core, asm_experimental_arch)] -#![crate_type = "rlib"] -#![no_core] -#![allow(non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -type ptr = *const u64; - -macro_rules! check { - ($func:ident $ty:ident $class:ident) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!("mov {}, {}", lateout($class) y, in($class) x); - y - } - }; -} - -macro_rules! checkw { - ($func:ident $ty:ident $class:ident) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!("movw {}, {}", lateout($class) y, in($class) x); - y - } - }; -} - -macro_rules! check_reg { - ($func:ident $ty:ident $reg:tt) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!("mov ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); - y - } - }; -} - -macro_rules! check_regw { - ($func:ident $ty:ident $reg:tt $reg_lit:tt) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!("movw ", $reg_lit, ", ", $reg_lit), lateout($reg) y, in($reg) x); - y - } - }; -} - -extern "C" { - fn extern_func(); - static extern_static: i8; -} - -// CHECK-LABEL: sym_fn -// CHECK: ;APP -// CHECK: call extern_func -// CHECK: ;NO_APP -#[no_mangle] -pub unsafe fn sym_fn() { - asm!("call {}", sym extern_func); -} - -// CHECK-LABEL: sym_static -// CHECK: ;APP -// CHECK: lds r{{[0-9]+}}, extern_static -// CHECK: ;NO_APP -#[no_mangle] -pub unsafe fn sym_static() -> i8 { - let y; - asm!("lds {}, {}", lateout(reg) y, sym extern_static); - y -} - -// CHECK-LABEL: ld_z: -// CHECK: ;APP -// CHECK: ld r{{[0-9]+}}, Z -// CHECK: ;NO_APP -#[no_mangle] -pub unsafe fn ld_z(x: i16) -> i8 { - let y; - asm!("ld {}, Z", out(reg) y, in("Z") x); - y -} - -// CHECK-LABEL: ldd_z: -// CHECK: ;APP -// CHECK: ldd r{{[0-9]+}}, Z+4 -// CHECK: ;NO_APP -#[no_mangle] -pub unsafe fn ldd_z(x: i16) -> i8 { - let y; - asm!("ldd {}, Z+4", out(reg) y, in("Z") x); - y -} - -// CHECK-LABEL: ld_predecrement: -// CHECK: ;APP -// CHECK: ld r{{[0-9]+}}, -Z -// CHECK: ;NO_APP -#[no_mangle] -pub unsafe fn ld_predecrement(x: i16) -> i8 { - let y; - asm!("ld {}, -Z", out(reg) y, in("Z") x); - y -} - -// CHECK-LABEL: ld_postincrement: -// CHECK: ;APP -// CHECK: ld r{{[0-9]+}}, Z+ -// CHECK: ;NO_APP -#[no_mangle] -pub unsafe fn ld_postincrement(x: i16) -> i8 { - let y; - asm!("ld {}, Z+", out(reg) y, in("Z") x); - y -} - -// CHECK-LABEL: muls_clobber: -// CHECK: ;APP -// CHECK: muls r{{[0-9]+}}, r{{[0-9]+}} -// CHECK: movw r{{[0-9]+}}, r0 -// CHECK: ;NO_APP -#[no_mangle] -pub unsafe fn muls_clobber(x: i8, y: i8) -> i16 { - let z; - asm!( - "muls {}, {}", - "movw {}, r1:r0", - out(reg_iw) z, - in(reg) x, - in(reg) y, - ); - z -} - -// CHECK-LABEL: reg_i8: -// CHECK: ;APP -// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}} -// CHECK: ;NO_APP -check!(reg_i8 i8 reg); - -// CHECK-LABEL: reg_upper_i8: -// CHECK: ;APP -// CHECK: mov r{{[1-3][0-9]}}, r{{[1-3][0-9]}} -// CHECK: ;NO_APP -check!(reg_upper_i8 i8 reg_upper); - -// CHECK-LABEL: reg_pair_i16: -// CHECK: ;APP -// CHECK: movw r{{[0-9]+}}, r{{[0-9]+}} -// CHECK: ;NO_APP -checkw!(reg_pair_i16 i16 reg_pair); - -// CHECK-LABEL: reg_iw_i16: -// CHECK: ;APP -// CHECK: movw r{{[0-9]+}}, r{{[0-9]+}} -// CHECK: ;NO_APP -checkw!(reg_iw_i16 i16 reg_iw); - -// CHECK-LABEL: reg_ptr_i16: -// CHECK: ;APP -// CHECK: movw r{{[0-9]+}}, r{{[0-9]+}} -// CHECK: ;NO_APP -checkw!(reg_ptr_i16 i16 reg_ptr); - -// CHECK-LABEL: r2_i8: -// CHECK: ;APP -// CHECK: mov r2, r2 -// CHECK: ;NO_APP -check_reg!(r2_i8 i8 "r2"); - -// CHECK-LABEL: xl_i8: -// CHECK: ;APP -// CHECK: mov r26, r26 -// CHECK: ;NO_APP -check_reg!(xl_i8 i8 "XL"); - -// CHECK-LABEL: xh_i8: -// CHECK: ;APP -// CHECK: mov r27, r27 -// CHECK: ;NO_APP -check_reg!(xh_i8 i8 "XH"); - -// CHECK-LABEL: x_i16: -// CHECK: ;APP -// CHECK: movw r26, r26 -// CHECK: ;NO_APP -check_regw!(x_i16 i16 "X" "X"); - -// CHECK-LABEL: r25r24_i16: -// CHECK: ;APP -// CHECK: movw r24, r24 -// CHECK: ;NO_APP -check_regw!(r25r24_i16 i16 "r25r24" "r24"); diff --git a/tests/assembly/asm/bpf-types.rs b/tests/assembly/asm/bpf-types.rs deleted file mode 100644 index 07ea7bd5ce0..00000000000 --- a/tests/assembly/asm/bpf-types.rs +++ /dev/null @@ -1,133 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: --target bpfel-unknown-none -C target_feature=+alu32 -//@ needs-llvm-components: bpf - -#![feature(no_core, asm_experimental_arch)] -#![crate_type = "rlib"] -#![no_core] -#![allow(asm_sub_register, non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -type ptr = *const u64; - -macro_rules! check { - ($func:ident $ty:ident $class:ident) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!("{} = {}", out($class) y, in($class) x); - y - } - }; -} - -macro_rules! check_reg { - ($func:ident $ty:ident $reg:tt) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($reg, " = ", $reg), lateout($reg) y, in($reg) x); - y - } - }; -} - -extern "C" { - fn extern_func(); -} - -// CHECK-LABEL: sym_fn -// CHECK: #APP -// CHECK: call extern_func -// CHECK: #NO_APP -#[no_mangle] -pub unsafe fn sym_fn() { - asm!("call {}", sym extern_func); -} - -// CHECK-LABEL: reg_i8: -// CHECK: #APP -// CHECK: r{{[0-9]+}} = r{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i8 i8 reg); - -// CHECK-LABEL: reg_i16: -// CHECK: #APP -// CHECK: r{{[0-9]+}} = r{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i16 i16 reg); - -// CHECK-LABEL: reg_i32: -// CHECK: #APP -// CHECK: r{{[0-9]+}} = r{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i32 i32 reg); - -// CHECK-LABEL: reg_i64: -// CHECK: #APP -// CHECK: r{{[0-9]+}} = r{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i64 i64 reg); - -// CHECK-LABEL: wreg_i8: -// CHECK: #APP -// CHECK: w{{[0-9]+}} = w{{[0-9]+}} -// CHECK: #NO_APP -check!(wreg_i8 i8 wreg); - -// CHECK-LABEL: wreg_i16: -// CHECK: #APP -// CHECK: w{{[0-9]+}} = w{{[0-9]+}} -// CHECK: #NO_APP -check!(wreg_i16 i16 wreg); - -// CHECK-LABEL: wreg_i32: -// CHECK: #APP -// CHECK: w{{[0-9]+}} = w{{[0-9]+}} -// CHECK: #NO_APP -check!(wreg_i32 i32 wreg); - -// CHECK-LABEL: r0_i8: -// CHECK: #APP -// CHECK: r0 = r0 -// CHECK: #NO_APP -check_reg!(r0_i8 i8 "r0"); - -// CHECK-LABEL: r0_i16: -// CHECK: #APP -// CHECK: r0 = r0 -// CHECK: #NO_APP -check_reg!(r0_i16 i16 "r0"); - -// CHECK-LABEL: r0_i32: -// CHECK: #APP -// CHECK: r0 = r0 -// CHECK: #NO_APP -check_reg!(r0_i32 i32 "r0"); - -// CHECK-LABEL: r0_i64: -// CHECK: #APP -// CHECK: r0 = r0 -// CHECK: #NO_APP -check_reg!(r0_i64 i64 "r0"); - -// CHECK-LABEL: w0_i8: -// CHECK: #APP -// CHECK: w0 = w0 -// CHECK: #NO_APP -check_reg!(w0_i8 i8 "w0"); - -// CHECK-LABEL: w0_i16: -// CHECK: #APP -// CHECK: w0 = w0 -// CHECK: #NO_APP -check_reg!(w0_i16 i16 "w0"); - -// CHECK-LABEL: w0_i32: -// CHECK: #APP -// CHECK: w0 = w0 -// CHECK: #NO_APP -check_reg!(w0_i32 i32 "w0"); diff --git a/tests/assembly/asm/comments.rs b/tests/assembly/asm/comments.rs deleted file mode 100644 index 557009975dd..00000000000 --- a/tests/assembly/asm/comments.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ assembly-output: emit-asm -//@ only-x86_64 -// Check that comments in assembly get passed - -#![crate_type = "lib"] - -// CHECK-LABEL: test_comments: -#[no_mangle] -pub fn test_comments() { - // CHECK: example comment - unsafe { core::arch::asm!("nop // example comment") }; -} diff --git a/tests/assembly/asm/global_asm.rs b/tests/assembly/asm/global_asm.rs deleted file mode 100644 index 8a4bf98c745..00000000000 --- a/tests/assembly/asm/global_asm.rs +++ /dev/null @@ -1,32 +0,0 @@ -//@ only-x86_64 -//@ only-linux -//@ assembly-output: emit-asm -//@ compile-flags: -C llvm-args=--x86-asm-syntax=intel -//@ compile-flags: -C symbol-mangling-version=v0 - -#![crate_type = "rlib"] - -use std::arch::global_asm; - -#[no_mangle] -fn my_func() {} - -#[no_mangle] -static MY_STATIC: i32 = 0; - -// CHECK: mov eax, eax -global_asm!("mov eax, eax"); -// CHECK: mov ebx, 5 -global_asm!("mov ebx, {}", const 5); -// CHECK: mov ecx, 5 -global_asm!("movl ${}, %ecx", const 5, options(att_syntax)); -// CHECK: call my_func -global_asm!("call {}", sym my_func); -// CHECK: lea rax, [rip + MY_STATIC] -global_asm!("lea rax, [rip + {}]", sym MY_STATIC); -// CHECK: call _RNvC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_10global_asm6foobar -global_asm!("call {}", sym foobar); -// CHECK: _RNvC[[CRATE_IDENT]]_10global_asm6foobar: -fn foobar() { - loop {} -} diff --git a/tests/assembly/asm/hexagon-types.rs b/tests/assembly/asm/hexagon-types.rs deleted file mode 100644 index ce80fa75b35..00000000000 --- a/tests/assembly/asm/hexagon-types.rs +++ /dev/null @@ -1,139 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: --target hexagon-unknown-linux-musl -//@ compile-flags: -Zmerge-functions=disabled -//@ needs-llvm-components: hexagon - -#![feature(no_core, asm_experimental_arch)] -#![crate_type = "rlib"] -#![no_core] -#![allow(asm_sub_register, non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -type ptr = *const i32; - -extern "C" { - fn extern_func(); - static extern_static: u8; -} - -macro_rules! check { - ($func:ident $ty:ident $class:ident) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!("{} = {}", out($class) y, in($class) x); - y - } - }; -} - -macro_rules! check_reg { - ($func:ident $ty:ident $reg:tt) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($reg, " = ", $reg), lateout($reg) y, in($reg) x); - y - } - }; -} - -// CHECK-LABEL: sym_static: -// CHECK: InlineAsm Start -// CHECK: r0 = {{#+}}extern_static -// CHECK: InlineAsm End -#[no_mangle] -pub unsafe fn sym_static() { - asm!("r0 = #{}", sym extern_static); -} - -// CHECK-LABEL: sym_fn: -// CHECK: InlineAsm Start -// CHECK: r0 = {{#+}}extern_func -// CHECK: InlineAsm End -#[no_mangle] -pub unsafe fn sym_fn() { - asm!("r0 = #{}", sym extern_func); -} - -// This is a test for multi-instruction packets, -// which require the escaped braces. -// -// CHECK-LABEL: packet: -// CHECK: InlineAsm Start -// CHECK: { -// CHECK: r{{[0-9]+}} = r0 -// CHECK: memw(r1{{(\+#0)?}}) = r{{[0-9]+}} -// CHECK: } -// CHECK: InlineAsm End -#[no_mangle] -pub unsafe fn packet() { - let val = 1024; - asm!("{{ - {} = r0 - memw(r1) = {} - }}", out(reg) _, in(reg) &val); -} - -// CHECK-LABEL: reg_ptr: -// CHECK: InlineAsm Start -// CHECK: r{{[0-9]+}} = r{{[0-9]+}} -// CHECK: InlineAsm End -check!(reg_ptr ptr reg); - -// CHECK-LABEL: reg_f32: -// CHECK: InlineAsm Start -// CHECK: r{{[0-9]+}} = r{{[0-9]+}} -// CHECK: InlineAsm End -check!(reg_f32 f32 reg); - -// CHECK-LABEL: reg_i32: -// CHECK: InlineAsm Start -// CHECK: r{{[0-9]+}} = r{{[0-9]+}} -// CHECK: InlineAsm End -check!(reg_i32 i32 reg); - -// CHECK-LABEL: reg_i8: -// CHECK: InlineAsm Start -// CHECK: r{{[0-9]+}} = r{{[0-9]+}} -// CHECK: InlineAsm End -check!(reg_i8 i8 reg); - -// CHECK-LABEL: reg_i16: -// CHECK: InlineAsm Start -// CHECK: r{{[0-9]+}} = r{{[0-9]+}} -// CHECK: InlineAsm End -check!(reg_i16 i16 reg); - -// CHECK-LABEL: r0_ptr: -// CHECK: InlineAsm Start -// CHECK: r0 = r0 -// CHECK: InlineAsm End -check_reg!(r0_ptr ptr "r0"); - -// CHECK-LABEL: r0_f32: -// CHECK: InlineAsm Start -// CHECK: r0 = r0 -// CHECK: InlineAsm End -check_reg!(r0_f32 f32 "r0"); - -// CHECK-LABEL: r0_i32: -// CHECK: InlineAsm Start -// CHECK: r0 = r0 -// CHECK: InlineAsm End -check_reg!(r0_i32 i32 "r0"); - -// CHECK-LABEL: r0_i8: -// CHECK: InlineAsm Start -// CHECK: r0 = r0 -// CHECK: InlineAsm End -check_reg!(r0_i8 i8 "r0"); - -// CHECK-LABEL: r0_i16: -// CHECK: InlineAsm Start -// CHECK: r0 = r0 -// CHECK: InlineAsm End -check_reg!(r0_i16 i16 "r0"); diff --git a/tests/assembly/asm/inline-asm-avx.rs b/tests/assembly/asm/inline-asm-avx.rs deleted file mode 100644 index 630acbb971a..00000000000 --- a/tests/assembly/asm/inline-asm-avx.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -//@ only-x86_64 -//@ ignore-sgx - -#![feature(portable_simd)] - -use std::arch::asm; -use std::simd::Simd; - -#[target_feature(enable = "avx")] -#[no_mangle] -// CHECK-LABEL: convert: -pub unsafe fn convert(a: *const f32) -> Simd { - // CHECK: vbroadcastss (%{{[er][a-ds0-9][xpi0-9]?}}), {{%ymm[0-7]}} - let b: Simd; - unsafe { - asm!( - "vbroadcastss {b}, [{a}]", - a = in(reg) a, - b = out(ymm_reg) b, - ); - } - b -} diff --git a/tests/assembly/asm/loongarch-type.rs b/tests/assembly/asm/loongarch-type.rs deleted file mode 100644 index c782be19f1d..00000000000 --- a/tests/assembly/asm/loongarch-type.rs +++ /dev/null @@ -1,190 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: --target loongarch64-unknown-linux-gnu -//@ compile-flags: -Zmerge-functions=disabled -//@ needs-llvm-components: loongarch - -#![feature(no_core, f16)] -#![crate_type = "rlib"] -#![no_core] -#![allow(asm_sub_register, non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -type ptr = *const i32; - -extern "C" { - fn extern_func(); - static extern_static: u8; -} - -// CHECK-LABEL: sym_fn: -// CHECK: #APP -// CHECK: pcalau12i $t0, %got_pc_hi20(extern_func) -// CHECK: ld.d $t0, $t0, %got_pc_lo12(extern_func) -// CHECK: #NO_APP -#[no_mangle] -pub unsafe fn sym_fn() { - asm!("la.got $r12, {}", sym extern_func); -} - -// CHECK-LABEL: sym_static: -// CHECK: #APP -// CHECK: pcalau12i $t0, %got_pc_hi20(extern_static) -// CHECK: ld.d $t0, $t0, %got_pc_lo12(extern_static) -// CHECK: #NO_APP -#[no_mangle] -pub unsafe fn sym_static() { - asm!("la.got $r12, {}", sym extern_static); -} - -macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); - y - } -};} - -macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); - y - } -};} - -// CHECK-LABEL: reg_i8: -// CHECK: #APP -// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_i8, i8, reg, "move"); - -// CHECK-LABEL: reg_i16: -// CHECK: #APP -// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_i16, i16, reg, "move"); - -// CHECK-LABEL: reg_f16: -// CHECK: #APP -// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_f16, f16, reg, "move"); - -// CHECK-LABEL: reg_i32: -// CHECK: #APP -// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_i32, i32, reg, "move"); - -// CHECK-LABEL: reg_f32: -// CHECK: #APP -// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_f32, f32, reg, "move"); - -// CHECK-LABEL: reg_i64: -// CHECK: #APP -// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_i64, i64, reg, "move"); - -// CHECK-LABEL: reg_f64: -// CHECK: #APP -// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_f64, f64, reg, "move"); - -// CHECK-LABEL: reg_ptr: -// CHECK: #APP -// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_ptr, ptr, reg, "move"); - -// CHECK-LABEL: freg_f16: -// CHECK: #APP -// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} -// CHECK: #NO_APP -check!(freg_f16, f16, freg, "fmov.s"); - -// CHECK-LABEL: freg_f32: -// CHECK: #APP -// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} -// CHECK: #NO_APP -check!(freg_f32, f32, freg, "fmov.s"); - -// CHECK-LABEL: freg_f64: -// CHECK: #APP -// CHECK: fmov.d $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} -// CHECK: #NO_APP -check!(freg_f64, f64, freg, "fmov.d"); - -// CHECK-LABEL: r4_i8: -// CHECK: #APP -// CHECK: move $a0, $a0 -// CHECK: #NO_APP -check_reg!(r4_i8, i8, "$r4", "move"); - -// CHECK-LABEL: r4_i16: -// CHECK: #APP -// CHECK: move $a0, $a0 -// CHECK: #NO_APP -check_reg!(r4_i16, i16, "$r4", "move"); - -// CHECK-LABEL: r4_f16: -// CHECK: #APP -// CHECK: move $a0, $a0 -// CHECK: #NO_APP -check_reg!(r4_f16, f16, "$r4", "move"); - -// CHECK-LABEL: r4_i32: -// CHECK: #APP -// CHECK: move $a0, $a0 -// CHECK: #NO_APP -check_reg!(r4_i32, i32, "$r4", "move"); - -// CHECK-LABEL: r4_f32: -// CHECK: #APP -// CHECK: move $a0, $a0 -// CHECK: #NO_APP -check_reg!(r4_f32, f32, "$r4", "move"); - -// CHECK-LABEL: r4_i64: -// CHECK: #APP -// CHECK: move $a0, $a0 -// CHECK: #NO_APP -check_reg!(r4_i64, i64, "$r4", "move"); - -// CHECK-LABEL: r4_f64: -// CHECK: #APP -// CHECK: move $a0, $a0 -// CHECK: #NO_APP -check_reg!(r4_f64, f64, "$r4", "move"); - -// CHECK-LABEL: r4_ptr: -// CHECK: #APP -// CHECK: move $a0, $a0 -// CHECK: #NO_APP -check_reg!(r4_ptr, ptr, "$r4", "move"); - -// CHECK-LABEL: f0_f16: -// CHECK: #APP -// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} -// CHECK: #NO_APP -check_reg!(f0_f16, f16, "$f0", "fmov.s"); - -// CHECK-LABEL: f0_f32: -// CHECK: #APP -// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} -// CHECK: #NO_APP -check_reg!(f0_f32, f32, "$f0", "fmov.s"); - -// CHECK-LABEL: f0_f64: -// CHECK: #APP -// CHECK: fmov.d $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} -// CHECK: #NO_APP -check_reg!(f0_f64, f64, "$f0", "fmov.d"); diff --git a/tests/assembly/asm/m68k-types.rs b/tests/assembly/asm/m68k-types.rs deleted file mode 100644 index 9e4f6d9a1a9..00000000000 --- a/tests/assembly/asm/m68k-types.rs +++ /dev/null @@ -1,67 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: --target m68k-unknown-linux-gnu -//@ needs-llvm-components: m68k - -#![feature(no_core, asm_experimental_arch)] -#![crate_type = "rlib"] -#![no_core] -#![allow(non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -type ptr = *const u64; - -macro_rules! check { - ($func:ident $ty:ident $class:ident $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov, " {}, {};"), out($class) y, in($class) x); - y - } - }; -} - -// CHECK-LABEL: reg_data_i8: -// CHECK: ;APP -// CHECK: move.b %d{{[0-9]}}, %d{{[0-9]}} -// CHECK: ;NO_APP -check!(reg_data_i8 i8 reg_data "move.b"); - -// CHECK-LABEL: reg_data_i16: -// CHECK: ;APP -// CHECK: move.w %d{{[0-9]}}, %d{{[0-9]}} -// CHECK: ;NO_APP -check!(reg_data_i16 i16 reg_data "move.w"); - -// CHECK-LABEL: reg_data_i32: -// CHECK: ;APP -// CHECK: move.l %d{{[0-9]}}, %d{{[0-9]}} -// CHECK: ;NO_APP -check!(reg_data_i32 i32 reg_data "move.l"); - -// CHECK-LABEL: reg_addr_i16: -// CHECK: ;APP -// CHECK: move.w %a{{[0-9]}}, %a{{[0-9]}} -// CHECK: ;NO_APP -check!(reg_addr_i16 i16 reg_addr "move.w"); - -// CHECK-LABEL: reg_addr_i32: -// CHECK: ;APP -// CHECK: move.l %a{{[0-9]}}, %a{{[0-9]}} -// CHECK: ;NO_APP -check!(reg_addr_i32 i32 reg_addr "move.l"); - -// CHECK-LABEL: reg_i16: -// CHECK: ;APP -// CHECK: move.w %{{[da][0-9]}}, %{{[da][0-9]}} -// CHECK: ;NO_APP -check!(reg_i16 i16 reg "move.w"); - -// CHECK-LABEL: reg_i32: -// CHECK: ;APP -// CHECK: move.l %{{[da][0-9]}}, %{{[da][0-9]}} -// CHECK: ;NO_APP -check!(reg_i32 i32 reg "move.l"); diff --git a/tests/assembly/asm/mips-types.rs b/tests/assembly/asm/mips-types.rs deleted file mode 100644 index 00e8ce0b874..00000000000 --- a/tests/assembly/asm/mips-types.rs +++ /dev/null @@ -1,211 +0,0 @@ -//@ add-core-stubs -//@ revisions: mips32 mips64 -//@ assembly-output: emit-asm -//@[mips32] compile-flags: --target mips-unknown-linux-gnu -//@[mips32] needs-llvm-components: mips -//@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 -//@[mips64] needs-llvm-components: mips -//@ compile-flags: -Zmerge-functions=disabled - -#![feature(no_core, asm_experimental_arch)] -#![crate_type = "rlib"] -#![no_core] -#![allow(asm_sub_register, non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -type ptr = *const i32; - -extern "C" { - fn extern_func(); - static extern_static: u8; -} - -macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); - y - } -};} - -macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); - y - } -};} - -// mips32-LABEL: sym_static_32: -// mips32: #APP -// mips32: lw $3, %got(extern_static)($gp) -// mips32: #NO_APP -#[cfg(mips32)] -#[no_mangle] -pub unsafe fn sym_static_32() { - asm!("lw $v1, {}", sym extern_static); -} - -// mips32-LABEL: sym_fn_32: -// mips32: #APP -// mips32: lw $3, %got(extern_func)($gp) -// mips32: #NO_APP -#[cfg(mips32)] -#[no_mangle] -pub unsafe fn sym_fn_32() { - asm!("lw $v1, {}", sym extern_func); -} - -// mips64-LABEL: sym_static_64: -// mips64: #APP -// mips64: lui $3, %got_hi(extern_static) -// mips64: daddu $3, $3, $gp -// mips64: ld $3, %got_lo(extern_static)($3) -// mips64: #NO_APP -#[cfg(mips64)] -#[no_mangle] -pub unsafe fn sym_static_64() { - asm!("ld $v1, {}", sym extern_static); -} - -// mips64-LABEL: sym_fn_64: -// mips64: #APP -// mips64: lui $3, %got_hi(extern_func) -// mips64: daddu $3, $3, $gp -// mips64: ld $3, %got_lo(extern_func)($3) -// mips64: #NO_APP -#[cfg(mips64)] -#[no_mangle] -pub unsafe fn sym_fn_64() { - asm!("ld $v1, {}", sym extern_func); -} - -// CHECK-LABEL: reg_f32: -// CHECK: #APP -// CHECK: mov.s $f{{[0-9]+}}, $f{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_f32, f32, freg, "mov.s"); - -// CHECK-LABEL: f0_f32: -// CHECK: #APP -// CHECK: mov.s $f0, $f0 -// CHECK: #NO_APP -#[no_mangle] -check_reg!(f0_f32, f32, "$f0", "mov.s"); - -// CHECK-LABEL: reg_f32_64: -// CHECK: #APP -// CHECK: mov.d $f{{[0-9]+}}, $f{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_f32_64, f32, freg, "mov.d"); - -// CHECK-LABEL: f0_f32_64: -// CHECK: #APP -// CHECK: mov.d $f0, $f0 -// CHECK: #NO_APP -#[no_mangle] -check_reg!(f0_f32_64, f32, "$f0", "mov.d"); - -// CHECK-LABEL: reg_f64: -// CHECK: #APP -// CHECK: mov.d $f{{[0-9]+}}, $f{{[0-9]+}} -// CHECK: #NO_APP -#[no_mangle] -check!(reg_f64, f64, freg, "mov.d"); - -// CHECK-LABEL: f0_f64: -// CHECK: #APP -// CHECK: mov.d $f0, $f0 -// CHECK: #NO_APP -#[no_mangle] -check_reg!(f0_f64, f64, "$f0", "mov.d"); - -// CHECK-LABEL: reg_ptr: -// CHECK: #APP -// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} -// CHECK: #NO_APP -check!(reg_ptr, ptr, reg, "move"); - -// CHECK-LABEL: reg_i32: -// CHECK: #APP -// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i32, i32, reg, "move"); - -// CHECK-LABEL: reg_f32_soft: -// CHECK: #APP -// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} -// CHECK: #NO_APP -check!(reg_f32_soft, f32, reg, "move"); - -// mips64-LABEL: reg_f64_soft: -// mips64: #APP -// mips64: move ${{[0-9]+}}, ${{[0-9]+}} -// mips64: #NO_APP -#[cfg(mips64)] -check!(reg_f64_soft, f64, reg, "move"); - -// CHECK-LABEL: reg_i8: -// CHECK: #APP -// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i8, i8, reg, "move"); - -// CHECK-LABEL: reg_u8: -// CHECK: #APP -// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} -// CHECK: #NO_APP -check!(reg_u8, u8, reg, "move"); - -// CHECK-LABEL: reg_i16: -// CHECK: #APP -// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i16, i16, reg, "move"); - -// mips64-LABEL: reg_i64: -// mips64: #APP -// mips64: move ${{[0-9]+}}, ${{[0-9]+}} -// mips64: #NO_APP -#[cfg(mips64)] -check!(reg_i64, i64, reg, "move"); - -// CHECK-LABEL: r8_ptr: -// CHECK: #APP -// CHECK: move $8, $8 -// CHECK: #NO_APP -check_reg!(r8_ptr, ptr, "$8", "move"); - -// CHECK-LABEL: r8_i32: -// CHECK: #APP -// CHECK: move $8, $8 -// CHECK: #NO_APP -check_reg!(r8_i32, i32, "$8", "move"); - -// CHECK-LABEL: r8_f32: -// CHECK: #APP -// CHECK: move $8, $8 -// CHECK: #NO_APP -check_reg!(r8_f32, f32, "$8", "move"); - -// CHECK-LABEL: r8_i8: -// CHECK: #APP -// CHECK: move $8, $8 -// CHECK: #NO_APP -check_reg!(r8_i8, i8, "$8", "move"); - -// CHECK-LABEL: r8_u8: -// CHECK: #APP -// CHECK: move $8, $8 -// CHECK: #NO_APP -check_reg!(r8_u8, u8, "$8", "move"); - -// CHECK-LABEL: r8_i16: -// CHECK: #APP -// CHECK: move $8, $8 -// CHECK: #NO_APP -check_reg!(r8_i16, i16, "$8", "move"); diff --git a/tests/assembly/asm/msp430-types.rs b/tests/assembly/asm/msp430-types.rs deleted file mode 100644 index 442dc77999f..00000000000 --- a/tests/assembly/asm/msp430-types.rs +++ /dev/null @@ -1,141 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: --target msp430-none-elf -//@ needs-llvm-components: msp430 - -#![feature(no_core, asm_experimental_arch)] -#![crate_type = "rlib"] -#![no_core] -#![allow(non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -type ptr = *const i16; - -macro_rules! check { - ($func:ident $ty:ident $class:ident) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!("mov {}, {}", lateout($class) y, in($class) x); - y - } - }; -} - -macro_rules! checkb { - ($func:ident $ty:ident $class:ident) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!("mov.b {}, {}", lateout($class) y, in($class) x); - y - } - }; -} - -macro_rules! check_reg { - ($func:ident $ty:ident $reg:tt) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!("mov ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); - y - } - }; -} - -macro_rules! check_regb { - ($func:ident $ty:ident $reg:tt) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!("mov.b ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); - y - } - }; -} - -extern "C" { - fn extern_func(); - static extern_static: i8; -} - -// CHECK-LABEL: sym_fn -// CHECK: ;APP -// CHECK: call extern_func -// CHECK: ;NO_APP -#[no_mangle] -pub unsafe fn sym_fn() { - asm!("call {}", sym extern_func); -} - -// CHECK-LABEL: sym_static -// CHECK: ;APP -// CHECK: mov.b extern_static, r{{[0-9]+}} -// CHECK: ;NO_APP -#[no_mangle] -pub unsafe fn sym_static() -> i8 { - let y; - asm!("mov.b {1}, {0}", lateout(reg) y, sym extern_static); - y -} - -// CHECK-LABEL: add_const: -// CHECK: ;APP -// CHECK: add.b #5, r{{[0-9]+}} -// CHECK: ;NO_APP -#[no_mangle] -pub unsafe fn add_const() -> i8 { - let y; - asm!("add.b #{number}, {}", out(reg) y, number = const 5); - y -} - -// CHECK-LABEL: mov_postincrement: -// CHECK: ;APP -// CHECK: mov @r5+, r{{[0-9]+}} -// CHECK: ;NO_APP -#[no_mangle] -pub unsafe fn mov_postincrement(mut x: *const i16) -> (i16, *const i16) { - let y; - asm!("mov @r5+, {0}", out(reg) y, inlateout("r5") x); - (y, x) -} - -// CHECK-LABEL: reg_i8: -// CHECK: ;APP -// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}} -// CHECK: ;NO_APP -check!(reg_i8 i8 reg); - -// CHECK-LABEL: reg_i16: -// CHECK: ;APP -// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}} -// CHECK: ;NO_APP -check!(reg_i16 i16 reg); - -// CHECK-LABEL: reg_i8b: -// CHECK: ;APP -// CHECK: mov.b r{{[0-9]+}}, r{{[0-9]+}} -// CHECK: ;NO_APP -checkb!(reg_i8b i8 reg); - -// CHECK-LABEL: r5_i8: -// CHECK: ;APP -// CHECK: mov r5, r5 -// CHECK: ;NO_APP -check_reg!(r5_i8 i8 "r5"); - -// CHECK-LABEL: r5_i16: -// CHECK: ;APP -// CHECK: mov r5, r5 -// CHECK: ;NO_APP -check_reg!(r5_i16 i16 "r5"); - -// CHECK-LABEL: r5_i8b: -// CHECK: ;APP -// CHECK: mov.b r5, r5 -// CHECK: ;NO_APP -check_regb!(r5_i8b i8 "r5"); diff --git a/tests/assembly/asm/nvptx-types.rs b/tests/assembly/asm/nvptx-types.rs deleted file mode 100644 index 7e8ebd03024..00000000000 --- a/tests/assembly/asm/nvptx-types.rs +++ /dev/null @@ -1,115 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: --target nvptx64-nvidia-cuda -//@ needs-llvm-components: nvptx - -#![feature(no_core, asm_experimental_arch)] -#![crate_type = "rlib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -type ptr = *mut u8; - -// NVPTX does not support static variables -#[no_mangle] -fn extern_func() {} - -// CHECK-LABEL: .visible .func sym_fn() -// CHECK: // begin inline asm -// CHECK: call extern_func; -// CHECK: // end inline asm -#[no_mangle] -pub unsafe fn sym_fn() { - asm!("call {};", sym extern_func); -} - -macro_rules! check { - ($func:ident $ty:ident $class:ident $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov, " {}, {};"), out($class) y, in($class) x); - y - } - }; -} - -// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg16_i8 -// CHECK: // begin inline asm -// CHECK: mov.i16 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; -// CHECK: // end inline asm -check!(reg16_i8 i8 reg16 "mov.i16"); - -// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg16_i16 -// CHECK: // begin inline asm -// CHECK: mov.i16 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; -// CHECK: // end inline asm -check!(reg16_i16 i16 reg16 "mov.i16"); - -// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i8 -// CHECK: // begin inline asm -// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; -// CHECK: // end inline asm -check!(reg32_i8 i8 reg32 "mov.i32"); - -// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i16 -// CHECK: // begin inline asm -// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; -// CHECK: // end inline asm -check!(reg32_i16 i16 reg32 "mov.i32"); - -// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i32 -// CHECK: // begin inline asm -// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; -// CHECK: // end inline asm -check!(reg32_i32 i32 reg32 "mov.i32"); - -// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_f32 -// CHECK: // begin inline asm -// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; -// CHECK: // end inline asm -check!(reg32_f32 f32 reg32 "mov.i32"); - -// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i8 -// CHECK: // begin inline asm -// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; -// CHECK: // end inline asm -check!(reg64_i8 i8 reg64 "mov.i64"); - -// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i16 -// CHECK: // begin inline asm -// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; -// CHECK: // end inline asm -check!(reg64_i16 i16 reg64 "mov.i64"); - -// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i32 -// CHECK: // begin inline asm -// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; -// CHECK: // end inline asm -check!(reg64_i32 i32 reg64 "mov.i64"); - -// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_f32 -// CHECK: // begin inline asm -// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; -// CHECK: // end inline asm -check!(reg64_f32 f32 reg64 "mov.i64"); - -// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_i64 -// CHECK: // begin inline asm -// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; -// CHECK: // end inline asm -check!(reg64_i64 i64 reg64 "mov.i64"); - -// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_f64 -// CHECK: // begin inline asm -// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; -// CHECK: // end inline asm -check!(reg64_f64 f64 reg64 "mov.i64"); - -// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_ptr -// CHECK: // begin inline asm -// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; -// CHECK: // end inline asm -check!(reg64_ptr ptr reg64 "mov.i64"); diff --git a/tests/assembly/asm/powerpc-types.rs b/tests/assembly/asm/powerpc-types.rs deleted file mode 100644 index 4291e4c02f3..00000000000 --- a/tests/assembly/asm/powerpc-types.rs +++ /dev/null @@ -1,474 +0,0 @@ -//@ add-core-stubs -//@ revisions: powerpc powerpc_altivec powerpc_vsx powerpc64 powerpc64_vsx -//@ assembly-output: emit-asm -//@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu -//@[powerpc] needs-llvm-components: powerpc -//@[powerpc_altivec] compile-flags: --target powerpc-unknown-linux-gnu -C target-feature=+altivec --cfg altivec -//@[powerpc_altivec] needs-llvm-components: powerpc -//@[powerpc_vsx] compile-flags: --target powerpc-unknown-linux-gnu -C target-feature=+altivec,+vsx --cfg altivec --cfg vsx -//@[powerpc_vsx] needs-llvm-components: powerpc -//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu --cfg altivec -//@[powerpc64] needs-llvm-components: powerpc -//@[powerpc64_vsx] compile-flags: --target powerpc64-unknown-linux-gnu -C target-feature=+vsx --cfg altivec --cfg vsx -//@[powerpc64_vsx] needs-llvm-components: powerpc -//@ compile-flags: -Zmerge-functions=disabled - -#![feature(no_core, repr_simd, asm_experimental_arch)] -#![crate_type = "rlib"] -#![no_core] -#![allow(asm_sub_register, non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -#[cfg_attr(altivec, cfg(not(target_feature = "altivec")))] -#[cfg_attr(not(altivec), cfg(target_feature = "altivec"))] -compile_error!("altivec cfg and target feature mismatch"); -#[cfg_attr(vsx, cfg(not(target_feature = "vsx")))] -#[cfg_attr(not(vsx), cfg(target_feature = "vsx"))] -compile_error!("vsx cfg and target feature mismatch"); - -type ptr = *const i32; - -#[repr(simd)] -pub struct i8x16([i8; 16]); -#[repr(simd)] -pub struct i16x8([i16; 8]); -#[repr(simd)] -pub struct i32x4([i32; 4]); -#[repr(simd)] -pub struct i64x2([i64; 2]); -#[repr(simd)] -pub struct f32x4([f32; 4]); -#[repr(simd)] -pub struct f64x2([f64; 2]); - -impl Copy for i8x16 {} -impl Copy for i16x8 {} -impl Copy for i32x4 {} -impl Copy for i64x2 {} -impl Copy for f32x4 {} -impl Copy for f64x2 {} - -extern "C" { - fn extern_func(); - static extern_static: u8; -} - -macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); - y - } -};} - -macro_rules! check_reg { ($func:ident, $ty:ty, $rego:tt, $regc:tt, $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov, " ", $rego, ", ", $rego), lateout($regc) y, in($regc) x); - y - } -};} - -// CHECK-LABEL: reg_i8: -// CHECK: #APP -// CHECK: mr {{[0-9]+}}, {{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i8, i8, reg, "mr"); - -// CHECK-LABEL: reg_i16: -// CHECK: #APP -// CHECK: mr {{[0-9]+}}, {{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i16, i16, reg, "mr"); - -// CHECK-LABEL: reg_i32: -// CHECK: #APP -// CHECK: mr {{[0-9]+}}, {{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i32, i32, reg, "mr"); - -// powerpc64-LABEL: reg_i64: -// powerpc64: #APP -// powerpc64: mr {{[0-9]+}}, {{[0-9]+}} -// powerpc64: #NO_APP -#[cfg(powerpc64)] -check!(reg_i64, i64, reg, "mr"); - -// CHECK-LABEL: reg_i8_nz: -// CHECK: #APP -// CHECK: mr {{[0-9]+}}, {{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i8_nz, i8, reg_nonzero, "mr"); - -// CHECK-LABEL: reg_i16_nz: -// CHECK: #APP -// CHECK: mr {{[0-9]+}}, {{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i16_nz, i16, reg_nonzero, "mr"); - -// CHECK-LABEL: reg_i32_nz: -// CHECK: #APP -// CHECK: mr {{[0-9]+}}, {{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i32_nz, i32, reg_nonzero, "mr"); - -// powerpc64-LABEL: reg_i64_nz: -// powerpc64: #APP -// powerpc64: mr {{[0-9]+}}, {{[0-9]+}} -// powerpc64: #NO_APP -#[cfg(powerpc64)] -check!(reg_i64_nz, i64, reg_nonzero, "mr"); - -// CHECK-LABEL: reg_f32: -// CHECK: #APP -// CHECK: fmr {{[0-9]+}}, {{[0-9]+}} -// CHECK: #NO_APP -check!(reg_f32, f32, freg, "fmr"); - -// CHECK-LABEL: reg_f64: -// CHECK: #APP -// CHECK: fmr {{[0-9]+}}, {{[0-9]+}} -// CHECK: #NO_APP -check!(reg_f64, f64, freg, "fmr"); - -// powerpc_altivec-LABEL: vreg_i8x16: -// powerpc_altivec: #APP -// powerpc_altivec: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i8x16: -// powerpc64: #APP -// powerpc64: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64: #NO_APP -#[cfg(altivec)] -check!(vreg_i8x16, i8x16, vreg, "vmr"); - -// powerpc_altivec-LABEL: vreg_i16x8: -// powerpc_altivec: #APP -// powerpc_altivec: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i16x8: -// powerpc64: #APP -// powerpc64: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64: #NO_APP -#[cfg(altivec)] -check!(vreg_i16x8, i16x8, vreg, "vmr"); - -// powerpc_altivec-LABEL: vreg_i32x4: -// powerpc_altivec: #APP -// powerpc_altivec: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i32x4: -// powerpc64: #APP -// powerpc64: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64: #NO_APP -#[cfg(altivec)] -check!(vreg_i32x4, i32x4, vreg, "vmr"); - -// powerpc_vsx-LABEL: vreg_i64x2: -// powerpc_vsx: #APP -// powerpc_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_i64x2: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP -#[cfg(vsx)] -check!(vreg_i64x2, i64x2, vreg, "vmr"); - -// powerpc_altivec-LABEL: vreg_f32x4: -// powerpc_altivec: #APP -// powerpc_altivec: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_f32x4: -// powerpc64: #APP -// powerpc64: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64: #NO_APP -#[cfg(altivec)] -check!(vreg_f32x4, f32x4, vreg, "vmr"); - -// powerpc_vsx-LABEL: vreg_f64x2: -// powerpc_vsx: #APP -// powerpc_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f64x2: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP -#[cfg(vsx)] -check!(vreg_f64x2, f64x2, vreg, "vmr"); - -// powerpc_vsx-LABEL: vreg_f32: -// powerpc_vsx: #APP -// powerpc_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f32: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP -#[cfg(vsx)] -check!(vreg_f32, f32, vreg, "vmr"); - -// powerpc_vsx-LABEL: vreg_f64: -// powerpc_vsx: #APP -// powerpc_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f64: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP -#[cfg(vsx)] -check!(vreg_f64, f64, vreg, "vmr"); - -// CHECK-LABEL: reg_i8_r0: -// CHECK: #APP -// CHECK: mr 0, 0 -// CHECK: #NO_APP -check_reg!(reg_i8_r0, i8, "0", "0", "mr"); - -// CHECK-LABEL: reg_i16_r0: -// CHECK: #APP -// CHECK: mr 0, 0 -// CHECK: #NO_APP -check_reg!(reg_i16_r0, i16, "0", "0", "mr"); - -// CHECK-LABEL: reg_i32_r0: -// CHECK: #APP -// CHECK: mr 0, 0 -// CHECK: #NO_APP -check_reg!(reg_i32_r0, i32, "0", "0", "mr"); - -// powerpc64-LABEL: reg_i64_r0: -// powerpc64: #APP -// powerpc64: mr 0, 0 -// powerpc64: #NO_APP -#[cfg(powerpc64)] -check_reg!(reg_i64_r0, i64, "0", "0", "mr"); - -// CHECK-LABEL: reg_i8_r18: -// CHECK: #APP -// CHECK: mr 18, 18 -// CHECK: #NO_APP -check_reg!(reg_i8_r18, i8, "18", "18", "mr"); - -// CHECK-LABEL: reg_i16_r18: -// CHECK: #APP -// CHECK: mr 18, 18 -// CHECK: #NO_APP -check_reg!(reg_i16_r18, i16, "18", "18", "mr"); - -// CHECK-LABEL: reg_i32_r18: -// CHECK: #APP -// CHECK: mr 18, 18 -// CHECK: #NO_APP -check_reg!(reg_i32_r18, i32, "18", "18", "mr"); - -// powerpc64-LABEL: reg_i64_r18: -// powerpc64: #APP -// powerpc64: mr 18, 18 -// powerpc64: #NO_APP -#[cfg(powerpc64)] -check_reg!(reg_i64_r18, i64, "18", "18", "mr"); - -// CHECK-LABEL: reg_f32_f0: -// CHECK: #APP -// CHECK: fmr 0, 0 -// CHECK: #NO_APP -check_reg!(reg_f32_f0, f32, "0", "f0", "fmr"); - -// CHECK-LABEL: reg_f64_f0: -// CHECK: #APP -// CHECK: fmr 0, 0 -// CHECK: #NO_APP -check_reg!(reg_f64_f0, f64, "0", "f0", "fmr"); - -// CHECK-LABEL: reg_f32_f18: -// CHECK: #APP -// CHECK: fmr 18, 18 -// CHECK: #NO_APP -check_reg!(reg_f32_f18, f32, "18", "f18", "fmr"); - -// CHECK-LABEL: reg_f64_f18: -// CHECK: #APP -// CHECK: fmr 18, 18 -// CHECK: #NO_APP -check_reg!(reg_f64_f18, f64, "18", "f18", "fmr"); - -// powerpc_altivec-LABEL: vreg_i8x16_v0: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 0, 0 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i8x16_v0: -// powerpc64: #APP -// powerpc64: vmr 0, 0 -// powerpc64: #NO_APP -#[cfg(altivec)] -check_reg!(vreg_i8x16_v0, i8x16, "0", "v0", "vmr"); - -// powerpc_altivec-LABEL: vreg_i16x8_v0: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 0, 0 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i16x8_v0: -// powerpc64: #APP -// powerpc64: vmr 0, 0 -// powerpc64: #NO_APP -#[cfg(altivec)] -check_reg!(vreg_i16x8_v0, i16x8, "0", "v0", "vmr"); - -// powerpc_altivec-LABEL: vreg_i32x4_v0: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 0, 0 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i32x4_v0: -// powerpc64: #APP -// powerpc64: vmr 0, 0 -// powerpc64: #NO_APP -#[cfg(altivec)] -check_reg!(vreg_i32x4_v0, i32x4, "0", "v0", "vmr"); - -// powerpc_vsx-LABEL: vreg_i64x2_v0: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_i64x2_v0: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 0, 0 -// powerpc64_vsx: #NO_APP -#[cfg(vsx)] -check_reg!(vreg_i64x2_v0, i64x2, "0", "v0", "vmr"); - -// powerpc_altivec-LABEL: vreg_f32x4_v0: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 0, 0 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_f32x4_v0: -// powerpc64: #APP -// powerpc64: vmr 0, 0 -// powerpc64: #NO_APP -#[cfg(altivec)] -check_reg!(vreg_f32x4_v0, f32x4, "0", "v0", "vmr"); - -// powerpc_vsx-LABEL: vreg_f64x2_v0: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f64x2_v0: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 0, 0 -// powerpc64_vsx: #NO_APP -#[cfg(vsx)] -check_reg!(vreg_f64x2_v0, f64x2, "0", "v0", "vmr"); - -// powerpc_vsx-LABEL: vreg_f32_v0: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f32_v0: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 0, 0 -// powerpc64_vsx: #NO_APP -#[cfg(vsx)] -check_reg!(vreg_f32_v0, f32, "0", "v0", "vmr"); - -// powerpc_vsx-LABEL: vreg_f64_v0: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f64_v0: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 0, 0 -// powerpc64_vsx: #NO_APP -#[cfg(vsx)] -check_reg!(vreg_f64_v0, f64, "0", "v0", "vmr"); - -// powerpc_altivec-LABEL: vreg_i8x16_v18: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 18, 18 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i8x16_v18: -// powerpc64: #APP -// powerpc64: vmr 18, 18 -// powerpc64: #NO_APP -#[cfg(altivec)] -check_reg!(vreg_i8x16_v18, i8x16, "18", "v18", "vmr"); - -// powerpc_altivec-LABEL: vreg_i16x8_v18: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 18, 18 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i16x8_v18: -// powerpc64: #APP -// powerpc64: vmr 18, 18 -// powerpc64: #NO_APP -#[cfg(altivec)] -check_reg!(vreg_i16x8_v18, i16x8, "18", "v18", "vmr"); - -// powerpc_altivec-LABEL: vreg_i32x4_v18: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 18, 18 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i32x4_v18: -// powerpc64: #APP -// powerpc64: vmr 18, 18 -// powerpc64: #NO_APP -#[cfg(altivec)] -check_reg!(vreg_i32x4_v18, i32x4, "18", "v18", "vmr"); - -// powerpc_vsx-LABEL: vreg_i64x2_v18: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 18, 18 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_i64x2_v18: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 18, 18 -// powerpc64_vsx: #NO_APP -#[cfg(vsx)] -check_reg!(vreg_i64x2_v18, i64x2, "18", "v18", "vmr"); - -// powerpc_altivec-LABEL: vreg_f32x4_v18: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 18, 18 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_f32x4_v18: -// powerpc64: #APP -// powerpc64: vmr 18, 18 -// powerpc64: #NO_APP -#[cfg(altivec)] -check_reg!(vreg_f32x4_v18, f32x4, "18", "v18", "vmr"); - -// powerpc_vsx-LABEL: vreg_f64x2_v18: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 18, 18 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f64x2_v18: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 18, 18 -// powerpc64_vsx: #NO_APP -#[cfg(vsx)] -check_reg!(vreg_f64x2_v18, f64x2, "18", "v18", "vmr"); - -// powerpc_vsx-LABEL: vreg_f32_v18: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 18, 18 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f32_v18: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 18, 18 -// powerpc64_vsx: #NO_APP -#[cfg(vsx)] -check_reg!(vreg_f32_v18, f32, "18", "v18", "vmr"); - -// powerpc_vsx-LABEL: vreg_f64_v18: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 18, 18 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f64_v18: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 18, 18 -// powerpc64_vsx: #NO_APP -#[cfg(vsx)] -check_reg!(vreg_f64_v18, f64, "18", "v18", "vmr"); diff --git a/tests/assembly/asm/riscv-types.rs b/tests/assembly/asm/riscv-types.rs deleted file mode 100644 index 724aa154da8..00000000000 --- a/tests/assembly/asm/riscv-types.rs +++ /dev/null @@ -1,227 +0,0 @@ -//@ add-core-stubs -//@ revisions: riscv64 riscv32 riscv64-zfhmin riscv32-zfhmin riscv64-zfh riscv32-zfh -//@ assembly-output: emit-asm - -//@[riscv64] compile-flags: --target riscv64imac-unknown-none-elf -//@[riscv64] needs-llvm-components: riscv - -//@[riscv32] compile-flags: --target riscv32imac-unknown-none-elf -//@[riscv32] needs-llvm-components: riscv - -//@[riscv64-zfhmin] compile-flags: --target riscv64imac-unknown-none-elf --cfg riscv64 -//@[riscv64-zfhmin] needs-llvm-components: riscv -//@[riscv64-zfhmin] compile-flags: -C target-feature=+zfhmin -//@[riscv64-zfhmin] filecheck-flags: --check-prefix riscv64 - -//@[riscv32-zfhmin] compile-flags: --target riscv32imac-unknown-none-elf -//@[riscv32-zfhmin] needs-llvm-components: riscv -//@[riscv32-zfhmin] compile-flags: -C target-feature=+zfhmin - -//@[riscv64-zfh] compile-flags: --target riscv64imac-unknown-none-elf --cfg riscv64 -//@[riscv64-zfh] needs-llvm-components: riscv -//@[riscv64-zfh] compile-flags: -C target-feature=+zfh -//@[riscv64-zfh] filecheck-flags: --check-prefix riscv64 --check-prefix zfhmin - -//@[riscv32-zfh] compile-flags: --target riscv32imac-unknown-none-elf -//@[riscv32-zfh] needs-llvm-components: riscv -//@[riscv32-zfh] compile-flags: -C target-feature=+zfh -//@[riscv32-zfh] filecheck-flags: --check-prefix zfhmin - -//@ compile-flags: -C target-feature=+d -//@ compile-flags: -Zmerge-functions=disabled - -#![feature(no_core, f16)] -#![crate_type = "rlib"] -#![no_core] -#![allow(asm_sub_register)] - -extern crate minicore; -use minicore::*; - -type ptr = *mut u8; - -extern "C" { - fn extern_func(); - static extern_static: u8; -} - -// CHECK-LABEL: sym_fn: -// CHECK: #APP -// CHECK: call extern_func -// CHECK: #NO_APP -#[no_mangle] -pub unsafe fn sym_fn() { - asm!("call {}", sym extern_func); -} - -// CHECK-LABEL: sym_static: -// CHECK: #APP -// CHECK: auipc t0, %pcrel_hi(extern_static) -// CHECK: lb t0, %pcrel_lo(.Lpcrel_hi{{[0-9]+}})(t0) -// CHECK: #NO_APP -#[no_mangle] -pub unsafe fn sym_static() { - asm!("lb t0, {}", sym extern_static); -} - -macro_rules! check { - ($func:ident $ty:ident $class:ident $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov, " {}, {}"), out($class) y, in($class) x); - y - } - }; -} - -macro_rules! check_reg { - ($func:ident $ty:ident $reg:tt $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); - y - } - }; -} - -// CHECK-LABEL: reg_i8: -// CHECK: #APP -// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_i8 i8 reg "mv"); - -// CHECK-LABEL: reg_f16: -// CHECK: #APP -// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_f16 f16 reg "mv"); - -// CHECK-LABEL: reg_i16: -// CHECK: #APP -// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_i16 i16 reg "mv"); - -// CHECK-LABEL: reg_i32: -// CHECK: #APP -// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_i32 i32 reg "mv"); - -// CHECK-LABEL: reg_f32: -// CHECK: #APP -// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_f32 f32 reg "mv"); - -// riscv64-LABEL: reg_i64: -// riscv64: #APP -// riscv64: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} -// riscv64: #NO_APP -#[cfg(riscv64)] -check!(reg_i64 i64 reg "mv"); - -// riscv64-LABEL: reg_f64: -// riscv64: #APP -// riscv64: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} -// riscv64: #NO_APP -#[cfg(riscv64)] -check!(reg_f64 f64 reg "mv"); - -// CHECK-LABEL: reg_ptr: -// CHECK: #APP -// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_ptr ptr reg "mv"); - -// CHECK-LABEL: freg_f16: -// zfhmin-NOT: or -// CHECK: #APP -// CHECK: fmv.s f{{[a-z0-9]+}}, f{{[a-z0-9]+}} -// CHECK: #NO_APP -// zfhmin-NOT: or -check!(freg_f16 f16 freg "fmv.s"); - -// CHECK-LABEL: freg_f32: -// CHECK: #APP -// CHECK: fmv.s f{{[a-z0-9]+}}, f{{[a-z0-9]+}} -// CHECK: #NO_APP -check!(freg_f32 f32 freg "fmv.s"); - -// CHECK-LABEL: freg_f64: -// CHECK: #APP -// CHECK: fmv.d f{{[a-z0-9]+}}, f{{[a-z0-9]+}} -// CHECK: #NO_APP -check!(freg_f64 f64 freg "fmv.d"); - -// CHECK-LABEL: a0_i8: -// CHECK: #APP -// CHECK: mv a0, a0 -// CHECK: #NO_APP -check_reg!(a0_i8 i8 "a0" "mv"); - -// CHECK-LABEL: a0_i16: -// CHECK: #APP -// CHECK: mv a0, a0 -// CHECK: #NO_APP -check_reg!(a0_i16 i16 "a0" "mv"); - -// CHECK-LABEL: a0_f16: -// CHECK: #APP -// CHECK: mv a0, a0 -// CHECK: #NO_APP -check_reg!(a0_f16 f16 "a0" "mv"); - -// CHECK-LABEL: a0_i32: -// CHECK: #APP -// CHECK: mv a0, a0 -// CHECK: #NO_APP -check_reg!(a0_i32 i32 "a0" "mv"); - -// CHECK-LABEL: a0_f32: -// CHECK: #APP -// CHECK: mv a0, a0 -// CHECK: #NO_APP -check_reg!(a0_f32 f32 "a0" "mv"); - -// riscv64-LABEL: a0_i64: -// riscv64: #APP -// riscv64: mv a0, a0 -// riscv64: #NO_APP -#[cfg(riscv64)] -check_reg!(a0_i64 i64 "a0" "mv"); - -// riscv64-LABEL: a0_f64: -// riscv64: #APP -// riscv64: mv a0, a0 -// riscv64: #NO_APP -#[cfg(riscv64)] -check_reg!(a0_f64 f64 "a0" "mv"); - -// CHECK-LABEL: a0_ptr: -// CHECK: #APP -// CHECK: mv a0, a0 -// CHECK: #NO_APP -check_reg!(a0_ptr ptr "a0" "mv"); - -// CHECK-LABEL: fa0_f16: -// zfhmin-NOT: or -// CHECK: #APP -// CHECK: fmv.s fa0, fa0 -// CHECK: #NO_APP -// zfhmin-NOT: or -check_reg!(fa0_f16 f16 "fa0" "fmv.s"); - -// CHECK-LABEL: fa0_f32: -// CHECK: #APP -// CHECK: fmv.s fa0, fa0 -// CHECK: #NO_APP -check_reg!(fa0_f32 f32 "fa0" "fmv.s"); - -// CHECK-LABEL: fa0_f64: -// CHECK: #APP -// CHECK: fmv.d fa0, fa0 -// CHECK: #NO_APP -check_reg!(fa0_f64 f64 "fa0" "fmv.d"); diff --git a/tests/assembly/asm/s390x-types.rs b/tests/assembly/asm/s390x-types.rs deleted file mode 100644 index e6fe38ecb0d..00000000000 --- a/tests/assembly/asm/s390x-types.rs +++ /dev/null @@ -1,350 +0,0 @@ -//@ add-core-stubs -//@ revisions: s390x s390x_vector -//@ assembly-output: emit-asm -//@[s390x] compile-flags: --target s390x-unknown-linux-gnu -//@[s390x] needs-llvm-components: systemz -//@[s390x_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector -//@[s390x_vector] needs-llvm-components: systemz -//@ compile-flags: -Zmerge-functions=disabled - -#![feature(no_core, repr_simd, f128)] -#![cfg_attr(s390x_vector, feature(asm_experimental_reg))] -#![crate_type = "rlib"] -#![no_core] -#![allow(asm_sub_register, non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -type ptr = *const i32; - -#[repr(simd)] -pub struct i8x16([i8; 16]); -#[repr(simd)] -pub struct i16x8([i16; 8]); -#[repr(simd)] -pub struct i32x4([i32; 4]); -#[repr(simd)] -pub struct i64x2([i64; 2]); -#[repr(simd)] -pub struct f32x4([f32; 4]); -#[repr(simd)] -pub struct f64x2([f64; 2]); - -impl Copy for i8x16 {} -impl Copy for i16x8 {} -impl Copy for i32x4 {} -impl Copy for i64x2 {} -impl Copy for f32x4 {} -impl Copy for f64x2 {} - -extern "C" { - fn extern_func(); - static extern_static: u8; -} - -macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); - y - } -};} - -macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov, " %", $reg, ", %", $reg), lateout($reg) y, in($reg) x); - y - } -};} - -// CHECK-LABEL: sym_fn_32: -// CHECK: #APP -// CHECK: brasl %r14, extern_func -// CHECK: #NO_APP -#[no_mangle] -pub unsafe fn sym_fn_32() { - asm!("brasl %r14, {}", sym extern_func); -} - -// CHECK-LABEL: sym_static: -// CHECK: #APP -// CHECK: brasl %r14, extern_static -// CHECK: #NO_APP -#[no_mangle] -pub unsafe fn sym_static() { - asm!("brasl %r14, {}", sym extern_static); -} - -// CHECK-LABEL: reg_i8: -// CHECK: #APP -// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i8, i8, reg, "lgr"); - -// CHECK-LABEL: reg_i16: -// CHECK: #APP -// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i16, i16, reg, "lgr"); - -// CHECK-LABEL: reg_i32: -// CHECK: #APP -// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i32, i32, reg, "lgr"); - -// CHECK-LABEL: reg_i64: -// CHECK: #APP -// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i64, i64, reg, "lgr"); - -// CHECK-LABEL: reg_i8_addr: -// CHECK: #APP -// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i8_addr, i8, reg_addr, "lgr"); - -// CHECK-LABEL: reg_i16_addr: -// CHECK: #APP -// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i16_addr, i16, reg_addr, "lgr"); - -// CHECK-LABEL: reg_i32_addr: -// CHECK: #APP -// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i32_addr, i32, reg_addr, "lgr"); - -// CHECK-LABEL: reg_i64_addr: -// CHECK: #APP -// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_i64_addr, i64, reg_addr, "lgr"); - -// CHECK-LABEL: reg_f32: -// CHECK: #APP -// CHECK: ler %f{{[0-9]+}}, %f{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_f32, f32, freg, "ler"); - -// CHECK-LABEL: reg_f64: -// CHECK: #APP -// CHECK: ldr %f{{[0-9]+}}, %f{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_f64, f64, freg, "ldr"); - -// CHECK-LABEL: reg_ptr: -// CHECK: #APP -// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} -// CHECK: #NO_APP -check!(reg_ptr, ptr, reg, "lgr"); - -// s390x_vector-LABEL: vreg_i8x16: -// s390x_vector: #APP -// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check!(vreg_i8x16, i8x16, vreg, "vlr"); - -// s390x_vector-LABEL: vreg_i16x8: -// s390x_vector: #APP -// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check!(vreg_i16x8, i16x8, vreg, "vlr"); - -// s390x_vector-LABEL: vreg_i32x4: -// s390x_vector: #APP -// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check!(vreg_i32x4, i32x4, vreg, "vlr"); - -// s390x_vector-LABEL: vreg_i64x2: -// s390x_vector: #APP -// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check!(vreg_i64x2, i64x2, vreg, "vlr"); - -// s390x_vector-LABEL: vreg_f32x4: -// s390x_vector: #APP -// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check!(vreg_f32x4, f32x4, vreg, "vlr"); - -// s390x_vector-LABEL: vreg_f64x2: -// s390x_vector: #APP -// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check!(vreg_f64x2, f64x2, vreg, "vlr"); - -// s390x_vector-LABEL: vreg_i32: -// s390x_vector: #APP -// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check!(vreg_i32, i32, vreg, "vlr"); - -// s390x_vector-LABEL: vreg_i64: -// s390x_vector: #APP -// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check!(vreg_i64, i64, vreg, "vlr"); - -// s390x_vector-LABEL: vreg_i128: -// s390x_vector: #APP -// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check!(vreg_i128, i128, vreg, "vlr"); - -// s390x_vector-LABEL: vreg_f32: -// s390x_vector: #APP -// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check!(vreg_f32, f32, vreg, "vlr"); - -// s390x_vector-LABEL: vreg_f64: -// s390x_vector: #APP -// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check!(vreg_f64, f64, vreg, "vlr"); - -// s390x_vector-LABEL: vreg_f128: -// s390x_vector: #APP -// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check!(vreg_f128, f128, vreg, "vlr"); - -// CHECK-LABEL: r0_i8: -// CHECK: #APP -// CHECK: lr %r0, %r0 -// CHECK: #NO_APP -check_reg!(r0_i8, i8, "r0", "lr"); - -// CHECK-LABEL: r0_i16: -// CHECK: #APP -// CHECK: lr %r0, %r0 -// CHECK: #NO_APP -check_reg!(r0_i16, i16, "r0", "lr"); - -// CHECK-LABEL: r0_i32: -// CHECK: #APP -// CHECK: lr %r0, %r0 -// CHECK: #NO_APP -check_reg!(r0_i32, i32, "r0", "lr"); - -// CHECK-LABEL: r0_i64: -// CHECK: #APP -// CHECK: lr %r0, %r0 -// CHECK: #NO_APP -check_reg!(r0_i64, i64, "r0", "lr"); - -// CHECK-LABEL: f0_f32: -// CHECK: #APP -// CHECK: ler %f0, %f0 -// CHECK: #NO_APP -check_reg!(f0_f32, f32, "f0", "ler"); - -// CHECK-LABEL: f0_f64: -// CHECK: #APP -// CHECK: ldr %f0, %f0 -// CHECK: #NO_APP -check_reg!(f0_f64, f64, "f0", "ldr"); - -// s390x_vector-LABEL: v0_i8x16: -// s390x_vector: #APP -// s390x_vector: vlr %v0, %v0 -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check_reg!(v0_i8x16, i8x16, "v0", "vlr"); - -// s390x_vector-LABEL: v0_i16x8: -// s390x_vector: #APP -// s390x_vector: vlr %v0, %v0 -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check_reg!(v0_i16x8, i16x8, "v0", "vlr"); - -// s390x_vector-LABEL: v0_i32x4: -// s390x_vector: #APP -// s390x_vector: vlr %v0, %v0 -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check_reg!(v0_i32x4, i32x4, "v0", "vlr"); - -// s390x_vector-LABEL: v0_i64x2: -// s390x_vector: #APP -// s390x_vector: vlr %v0, %v0 -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check_reg!(v0_i64x2, i64x2, "v0", "vlr"); - -// s390x_vector-LABEL: v0_f32x4: -// s390x_vector: #APP -// s390x_vector: vlr %v0, %v0 -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check_reg!(v0_f32x4, f32x4, "v0", "vlr"); - -// s390x_vector-LABEL: v0_f64x2: -// s390x_vector: #APP -// s390x_vector: vlr %v0, %v0 -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check_reg!(v0_f64x2, f64x2, "v0", "vlr"); - -// s390x_vector-LABEL: v0_i32: -// s390x_vector: #APP -// s390x_vector: vlr %v0, %v0 -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check_reg!(v0_i32, i32, "v0", "vlr"); - -// s390x_vector-LABEL: v0_i64: -// s390x_vector: #APP -// s390x_vector: vlr %v0, %v0 -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check_reg!(v0_i64, i64, "v0", "vlr"); - -// s390x_vector-LABEL: v0_i128: -// s390x_vector: #APP -// s390x_vector: vlr %v0, %v0 -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check_reg!(v0_i128, i128, "v0", "vlr"); - -// s390x_vector-LABEL: v0_f32: -// s390x_vector: #APP -// s390x_vector: vlr %v0, %v0 -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check_reg!(v0_f32, f32, "v0", "vlr"); - -// s390x_vector-LABEL: v0_f64: -// s390x_vector: #APP -// s390x_vector: vlr %v0, %v0 -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check_reg!(v0_f64, f64, "v0", "vlr"); - -// s390x_vector-LABEL: v0_f128: -// s390x_vector: #APP -// s390x_vector: vlr %v0, %v0 -// s390x_vector: #NO_APP -#[cfg(s390x_vector)] -check_reg!(v0_f128, f128, "v0", "vlr"); diff --git a/tests/assembly/asm/sparc-types.rs b/tests/assembly/asm/sparc-types.rs deleted file mode 100644 index 49cc377cd95..00000000000 --- a/tests/assembly/asm/sparc-types.rs +++ /dev/null @@ -1,145 +0,0 @@ -//@ add-core-stubs -//@ revisions: sparc sparcv8plus sparc64 -//@ assembly-output: emit-asm -//@[sparc] compile-flags: --target sparc-unknown-none-elf -//@[sparc] needs-llvm-components: sparc -//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu -//@[sparcv8plus] needs-llvm-components: sparc -//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu -//@[sparc64] needs-llvm-components: sparc -//@ compile-flags: -Zmerge-functions=disabled - -#![feature(no_core, asm_experimental_arch)] -#![crate_type = "rlib"] -#![no_core] -#![allow(asm_sub_register, non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -type ptr = *const i32; - -extern "C" { - fn extern_func(); - static extern_static: u8; -} - -macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov," {}, {}"), in($class) x, out($class) y); - y - } -};} - -macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov, " %", $reg, ", %", $reg), in($reg) x, lateout($reg) y); - y - } -};} - -// CHECK-LABEL: sym_fn_32: -// CHECK: !APP -// CHECK-NEXT: call extern_func -// CHECK-NEXT: !NO_APP -#[no_mangle] -pub unsafe fn sym_fn_32() { - asm!("call {}", sym extern_func); -} - -// CHECK-LABEL: sym_static: -// CHECK: !APP -// CHECK-NEXT: call extern_static -// CHECK-NEXT: !NO_APP -#[no_mangle] -pub unsafe fn sym_static() { - asm!("call {}", sym extern_static); -} - -// CHECK-LABEL: reg_i8: -// CHECK: !APP -// CHECK-NEXT: mov %{{[goli]}}{{[0-9]+}}, %{{[goli]}}{{[0-9]+}} -// CHECK-NEXT: !NO_APP -check!(reg_i8, i8, reg, "mov"); - -// CHECK-LABEL: reg_i16: -// CHECK: !APP -// CHECK-NEXT: mov %{{[goli]}}{{[0-9]+}}, %{{[goli]}}{{[0-9]+}} -// CHECK-NEXT: !NO_APP -check!(reg_i16, i16, reg, "mov"); - -// CHECK-LABEL: reg_i32: -// CHECK: !APP -// CHECK-NEXT: mov %{{[goli]}}{{[0-9]+}}, %{{[goli]}}{{[0-9]+}} -// CHECK-NEXT: !NO_APP -check!(reg_i32, i32, reg, "mov"); - -// FIXME: should be allowed for sparcv8plus but not yet supported in LLVM -// sparc64-LABEL: reg_i64: -// sparc64: !APP -// sparc64-NEXT: mov %{{[goli]}}{{[0-9]+}}, %{{[goli]}}{{[0-9]+}} -// sparc64-NEXT: !NO_APP -#[cfg(sparc64)] -check!(reg_i64, i64, reg, "mov"); - -// CHECK-LABEL: reg_ptr: -// CHECK: !APP -// CHECK-NEXT: mov %{{[goli]}}{{[0-9]+}}, %{{[goli]}}{{[0-9]+}} -// CHECK-NEXT: !NO_APP -check!(reg_ptr, ptr, reg, "mov"); - -// CHECK-LABEL: o0_i8: -// CHECK: !APP -// CHECK-NEXT: mov %o0, %o0 -// CHECK-NEXT: !NO_APP -check_reg!(o0_i8, i8, "o0", "mov"); - -// CHECK-LABEL: o0_i16: -// CHECK: !APP -// CHECK-NEXT: mov %o0, %o0 -// CHECK-NEXT: !NO_APP -check_reg!(o0_i16, i16, "o0", "mov"); - -// CHECK-LABEL: o0_i32: -// CHECK: !APP -// CHECK-NEXT: mov %o0, %o0 -// CHECK-NEXT: !NO_APP -check_reg!(o0_i32, i32, "o0", "mov"); - -// FIXME: should be allowed for sparcv8plus but not yet supported in LLVM -// sparc64-LABEL: o0_i64: -// sparc64: !APP -// sparc64-NEXT: mov %o0, %o0 -// sparc64-NEXT: !NO_APP -#[cfg(sparc64)] -check_reg!(o0_i64, i64, "o0", "mov"); - -// CHECK-LABEL: r9_i8: -// CHECK: !APP -// CHECK-NEXT: mov %o1, %o1 -// CHECK-NEXT: !NO_APP -check_reg!(r9_i8, i8, "r9", "mov"); - -// CHECK-LABEL: r9_i16: -// CHECK: !APP -// CHECK-NEXT: mov %o1, %o1 -// CHECK-NEXT: !NO_APP -check_reg!(r9_i16, i16, "r9", "mov"); - -// CHECK-LABEL: r9_i32: -// CHECK: !APP -// CHECK-NEXT: mov %o1, %o1 -// CHECK-NEXT: !NO_APP -check_reg!(r9_i32, i32, "r9", "mov"); - -// FIXME: should be allowed for sparcv8plus but not yet supported in LLVM -// sparc64-LABEL: r9_i64: -// sparc64: !APP -// sparc64-NEXT: mov %o1, %o1 -// sparc64-NEXT: !NO_APP -#[cfg(sparc64)] -check_reg!(r9_i64, i64, "r9", "mov"); diff --git a/tests/assembly/asm/wasm-types.rs b/tests/assembly/asm/wasm-types.rs deleted file mode 100644 index 78e555c5317..00000000000 --- a/tests/assembly/asm/wasm-types.rs +++ /dev/null @@ -1,131 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: --target wasm32-unknown-unknown -//@ needs-llvm-components: webassembly - -#![feature(no_core, asm_experimental_arch)] -#![crate_type = "rlib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -type ptr = *mut u8; - -extern "C" { - fn extern_func(); - static extern_static: u8; -} - -// CHECK-LABEL: sym_fn: -// CHECK: #APP -// CHECK: call extern_func -// CHECK: #NO_APP -#[no_mangle] -pub unsafe fn sym_fn() { - asm!("call {}", sym extern_func); -} - -// CHECK-LABEL: sym_static -// CHECK: #APP -// CHECK: i32.const 42 -// CHECK: i32.store extern_static -// CHECK: #NO_APP -#[no_mangle] -pub unsafe fn sym_static() { - asm!(" - i32.const 42 - i32.store {} - ", sym extern_static); -} - -macro_rules! check { - ($func:ident $ty:ident $instr:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!("local.get {}\n", $instr, "\nlocal.set {}"), in(local) x, out(local) y); - y - } - }; -} - -// CHECK-LABEL: i8_i32: -// CHECK: #APP -// CHECK: local.get {{[0-9]}} -// CHECK: i32.clz -// CHECK: local.set {{[0-9]}} -// CHECK: #NO_APP -check!(i8_i32 i8 "i32.clz"); - -// CHECK-LABEL: i16_i32: -// CHECK: #APP -// CHECK: local.get {{[0-9]}} -// CHECK: i32.clz -// CHECK: local.set {{[0-9]}} -// CHECK: #NO_APP -check!(i16_i32 i16 "i32.clz"); - -// CHECK-LABEL: i32_i32: -// CHECK: #APP -// CHECK: local.get {{[0-9]}} -// CHECK: i32.clz -// CHECK: local.set {{[0-9]}} -// CHECK: #NO_APP -check!(i32_i32 i32 "i32.clz"); - -// CHECK-LABEL: i8_i64 -// CHECK: #APP -// CHECK: local.get {{[0-9]}} -// CHECK: i64.clz -// CHECK: local.set {{[0-9]}} -// CHECK: #NO_APP -check!(i8_i64 i8 "i64.clz"); - -// CHECK-LABEL: i16_i64 -// CHECK: #APP -// CHECK: local.get {{[0-9]}} -// CHECK: i64.clz -// CHECK: local.set {{[0-9]}} -// CHECK: #NO_APP -check!(i16_i64 i16 "i64.clz"); - -// CHECK-LABEL: i32_i64 -// CHECK: #APP -// CHECK: local.get {{[0-9]}} -// CHECK: i64.clz -// CHECK: local.set {{[0-9]}} -// CHECK: #NO_APP -check!(i32_i64 i32 "i64.clz"); - -// CHECK-LABEL: i64_i64 -// CHECK: #APP -// CHECK: local.get {{[0-9]}} -// CHECK: i64.clz -// CHECK: local.set {{[0-9]}} -// CHECK: #NO_APP -check!(i64_i64 i64 "i64.clz"); - -// CHECK-LABEL: f32_f32 -// CHECK: #APP -// CHECK: local.get {{[0-9]}} -// CHECK: f32.abs -// CHECK: local.set {{[0-9]}} -// CHECK: #NO_APP -check!(f32_f32 f32 "f32.abs"); - -// CHECK-LABEL: f64_f64 -// CHECK: #APP -// CHECK: local.get {{[0-9]}} -// CHECK: f64.abs -// CHECK: local.set {{[0-9]}} -// CHECK: #NO_APP -check!(f64_f64 f64 "f64.abs"); - -// CHECK-LABEL: i32_ptr -// CHECK: #APP -// CHECK: local.get {{[0-9]}} -// CHECK: i32.eqz -// CHECK: local.set {{[0-9]}} -// CHECK: #NO_APP -check!(i32_ptr ptr "i32.eqz"); diff --git a/tests/assembly/asm/x86-modifiers.rs b/tests/assembly/asm/x86-modifiers.rs deleted file mode 100644 index 5f68e5c7317..00000000000 --- a/tests/assembly/asm/x86-modifiers.rs +++ /dev/null @@ -1,184 +0,0 @@ -//@ add-core-stubs -//@ revisions: x86_64 i686 -//@ assembly-output: emit-asm -//@ compile-flags: -Copt-level=3 -C panic=abort -//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu -//@[x86_64] needs-llvm-components: x86 -//@[i686] compile-flags: --target i686-unknown-linux-gnu -//@[i686] needs-llvm-components: x86 -//@ compile-flags: -C llvm-args=--x86-asm-syntax=intel -//@ compile-flags: -C target-feature=+avx512bw -//@ compile-flags: -Zmerge-functions=disabled - -#![feature(no_core)] -#![crate_type = "rlib"] -#![no_core] -#![allow(asm_sub_register)] - -extern crate minicore; -use minicore::*; - -macro_rules! check { - ($func:ident $modifier:literal $reg:ident $mov:literal) => { - // -Copt-level=3 and extern "C" guarantee that the selected register is always ax/xmm0 - #[no_mangle] - pub unsafe extern "C" fn $func() -> i32 { - let y; - asm!(concat!($mov, " {0:", $modifier, "}, {0:", $modifier, "}"), out($reg) y); - y - } - }; -} - -// CHECK-LABEL: reg: -// CHECK: #APP -// x86_64: mov rax, rax -// i686: mov eax, eax -// CHECK: #NO_APP -check!(reg "" reg "mov"); - -// x86_64-LABEL: reg_l: -// x86_64: #APP -// x86_64: mov al, al -// x86_64: #NO_APP -#[cfg(x86_64)] -check!(reg_l "l" reg "mov"); - -// CHECK-LABEL: reg_x: -// CHECK: #APP -// CHECK: mov ax, ax -// CHECK: #NO_APP -check!(reg_x "x" reg "mov"); - -// CHECK-LABEL: reg_e: -// CHECK: #APP -// CHECK: mov eax, eax -// CHECK: #NO_APP -check!(reg_e "e" reg "mov"); - -// x86_64-LABEL: reg_r: -// x86_64: #APP -// x86_64: mov rax, rax -// x86_64: #NO_APP -#[cfg(x86_64)] -check!(reg_r "r" reg "mov"); - -// CHECK-LABEL: reg_abcd: -// CHECK: #APP -// x86_64: mov rax, rax -// i686: mov eax, eax -// CHECK: #NO_APP -check!(reg_abcd "" reg_abcd "mov"); - -// CHECK-LABEL: reg_abcd_l: -// CHECK: #APP -// CHECK: mov al, al -// CHECK: #NO_APP -check!(reg_abcd_l "l" reg_abcd "mov"); - -// CHECK-LABEL: reg_abcd_h: -// CHECK: #APP -// CHECK: mov ah, ah -// CHECK: #NO_APP -check!(reg_abcd_h "h" reg_abcd "mov"); - -// CHECK-LABEL: reg_abcd_x: -// CHECK: #APP -// CHECK: mov ax, ax -// CHECK: #NO_APP -check!(reg_abcd_x "x" reg_abcd "mov"); - -// CHECK-LABEL: reg_abcd_e: -// CHECK: #APP -// CHECK: mov eax, eax -// CHECK: #NO_APP -check!(reg_abcd_e "e" reg_abcd "mov"); - -// x86_64-LABEL: reg_abcd_r: -// x86_64: #APP -// x86_64: mov rax, rax -// x86_64: #NO_APP -#[cfg(x86_64)] -check!(reg_abcd_r "r" reg_abcd "mov"); - -// CHECK-LABEL: xmm_reg -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check!(xmm_reg "" xmm_reg "movaps"); - -// CHECK-LABEL: xmm_reg_x -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check!(xmm_reg_x "x" xmm_reg "movaps"); - -// CHECK-LABEL: xmm_reg_y -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check!(xmm_reg_y "y" xmm_reg "vmovaps"); - -// CHECK-LABEL: xmm_reg_z -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check!(xmm_reg_z "z" xmm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg -// CHECK: #APP -// CHECK: movaps ymm0, ymm0 -// CHECK: #NO_APP -check!(ymm_reg "" ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_x -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check!(ymm_reg_x "x" ymm_reg "movaps"); - -// CHECK-LABEL: ymm_reg_y -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check!(ymm_reg_y "y" ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_z -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check!(ymm_reg_z "z" ymm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg -// CHECK: #APP -// CHECK: movaps zmm0, zmm0 -// CHECK: #NO_APP -check!(zmm_reg "" zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_x -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check!(zmm_reg_x "x" zmm_reg "movaps"); - -// CHECK-LABEL: zmm_reg_y -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check!(zmm_reg_y "y" zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_z -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check!(zmm_reg_z "z" zmm_reg "vmovaps"); - -// Note: we don't have any way of ensuring that k1 is actually the register -// chosen by the register allocator, so this check may fail if a different -// register is chosen. - -// CHECK-LABEL: kreg: -// CHECK: #APP -// CHECK: kmovb k1, k1 -// CHECK: #NO_APP -check!(kreg "" kreg "kmovb"); diff --git a/tests/assembly/asm/x86-types.rs b/tests/assembly/asm/x86-types.rs deleted file mode 100644 index 6120ed0d532..00000000000 --- a/tests/assembly/asm/x86-types.rs +++ /dev/null @@ -1,1095 +0,0 @@ -//@ add-core-stubs -//@ revisions: x86_64 i686 -//@ assembly-output: emit-asm -//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu -//@[x86_64] needs-llvm-components: x86 -//@[i686] compile-flags: --target i686-unknown-linux-gnu -//@[i686] needs-llvm-components: x86 -//@ compile-flags: -C llvm-args=--x86-asm-syntax=intel -//@ compile-flags: -C target-feature=+avx512bw -//@ compile-flags: -Zmerge-functions=disabled - -#![feature(no_core, repr_simd, f16, f128)] -#![crate_type = "rlib"] -#![no_core] -#![allow(asm_sub_register, non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -type ptr = *mut u8; - -#[repr(simd)] -pub struct i8x16([i8; 16]); -#[repr(simd)] -pub struct i16x8([i16; 8]); -#[repr(simd)] -pub struct i32x4([i32; 4]); -#[repr(simd)] -pub struct i64x2([i64; 2]); -#[repr(simd)] -pub struct f16x8([f16; 8]); -#[repr(simd)] -pub struct f32x4([f32; 4]); -#[repr(simd)] -pub struct f64x2([f64; 2]); - -#[repr(simd)] -pub struct i8x32([i8; 32]); -#[repr(simd)] -pub struct i16x16([i16; 16]); -#[repr(simd)] -pub struct i32x8([i32; 8]); -#[repr(simd)] -pub struct i64x4([i64; 4]); -#[repr(simd)] -pub struct f16x16([f16; 16]); -#[repr(simd)] -pub struct f32x8([f32; 8]); -#[repr(simd)] -pub struct f64x4([f64; 4]); - -#[repr(simd)] -pub struct i8x64([i8; 64]); -#[repr(simd)] -pub struct i16x32([i16; 32]); -#[repr(simd)] -pub struct i32x16([i32; 16]); -#[repr(simd)] -pub struct i64x8([i64; 8]); -#[repr(simd)] -pub struct f16x32([f16; 32]); -#[repr(simd)] -pub struct f32x16([f32; 16]); -#[repr(simd)] -pub struct f64x8([f64; 8]); - -macro_rules! impl_copy { - ($($ty:ident)*) => { - $( - impl Copy for $ty {} - )* - }; -} - -impl_copy!( - i8x16 i16x8 i32x4 i64x2 f16x8 f32x4 f64x2 - i8x32 i16x16 i32x8 i64x4 f16x16 f32x8 f64x4 - i8x64 i16x32 i32x16 i64x8 f16x32 f32x16 f64x8 -); - -extern "C" { - fn extern_func(); - static extern_static: u8; -} - -// CHECK-LABEL: sym_fn: -// CHECK: #APP -// CHECK: call extern_func -// CHECK: #NO_APP -#[no_mangle] -pub unsafe fn sym_fn() { - asm!("call {}", sym extern_func); -} - -// CHECK-LABEL: sym_static: -// CHECK: #APP -// CHECK: mov al, byte ptr [extern_static] -// CHECK: #NO_APP -#[no_mangle] -pub unsafe fn sym_static() { - asm!("mov al, byte ptr [{}]", sym extern_static); -} - -macro_rules! check { - ($func:ident $ty:ident $class:ident $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov, " {}, {}"), lateout($class) y, in($class) x); - y - } - }; -} - -macro_rules! check_reg { - ($func:ident $ty:ident $reg:tt $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); - y - } - }; -} - -// CHECK-LABEL: reg_i16: -// CHECK: #APP -// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} -// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_i16 i16 reg "mov"); - -// CHECK-LABEL: reg_f16: -// CHECK: #APP -// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} -// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_f16 f16 reg "mov"); - -// CHECK-LABEL: reg_i32: -// CHECK: #APP -// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} -// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_i32 i32 reg "mov"); - -// CHECK-LABEL: reg_f32: -// CHECK: #APP -// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} -// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_f32 f32 reg "mov"); - -// x86_64-LABEL: reg_i64: -// x86_64: #APP -// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} -// x86_64: #NO_APP -#[cfg(x86_64)] -check!(reg_i64 i64 reg "mov"); - -// x86_64-LABEL: reg_f64: -// x86_64: #APP -// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} -// x86_64: #NO_APP -#[cfg(x86_64)] -check!(reg_f64 f64 reg "mov"); - -// CHECK-LABEL: reg_ptr: -// CHECK: #APP -// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} -// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_ptr ptr reg "mov"); - -// CHECK-LABEL: reg_abcd_i16: -// CHECK: #APP -// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} -// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_abcd_i16 i16 reg_abcd "mov"); - -// CHECK-LABEL: reg_abcd_f16: -// CHECK: #APP -// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} -// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_abcd_f16 f16 reg_abcd "mov"); - -// CHECK-LABEL: reg_abcd_i32: -// CHECK: #APP -// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} -// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_abcd_i32 i32 reg_abcd "mov"); - -// CHECK-LABEL: reg_abcd_f32: -// CHECK: #APP -// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} -// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_abcd_f32 f32 reg_abcd "mov"); - -// x86_64-LABEL: reg_abcd_i64: -// x86_64: #APP -// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} -// x86_64: #NO_APP -#[cfg(x86_64)] -check!(reg_abcd_i64 i64 reg_abcd "mov"); - -// x86_64-LABEL: reg_abcd_f64: -// x86_64: #APP -// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} -// x86_64: #NO_APP -#[cfg(x86_64)] -check!(reg_abcd_f64 f64 reg_abcd "mov"); - -// CHECK-LABEL: reg_abcd_ptr: -// CHECK: #APP -// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} -// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_abcd_ptr ptr reg_abcd "mov"); - -// CHECK-LABEL: reg_byte: -// CHECK: #APP -// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: #NO_APP -check!(reg_byte i8 reg_byte "mov"); - -// CHECK-LABEL: xmm_reg_f16: -// CHECK: #APP -// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} -// CHECK: #NO_APP -check!(xmm_reg_f16 f16 xmm_reg "movaps"); - -// CHECK-LABEL: xmm_reg_i32: -// CHECK: #APP -// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} -// CHECK: #NO_APP -check!(xmm_reg_i32 i32 xmm_reg "movaps"); - -// CHECK-LABEL: xmm_reg_f32: -// CHECK: #APP -// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} -// CHECK: #NO_APP -check!(xmm_reg_f32 f32 xmm_reg "movaps"); - -// CHECK-LABEL: xmm_reg_i64: -// CHECK: #APP -// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} -// CHECK: #NO_APP -check!(xmm_reg_i64 i64 xmm_reg "movaps"); - -// CHECK-LABEL: xmm_reg_f64: -// CHECK: #APP -// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} -// CHECK: #NO_APP -check!(xmm_reg_f64 f64 xmm_reg "movaps"); - -// CHECK-LABEL: xmm_reg_f128: -// CHECK: #APP -// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} -// CHECK: #NO_APP -check!(xmm_reg_f128 f128 xmm_reg "movaps"); - -// CHECK-LABEL: xmm_reg_ptr: -// CHECK: #APP -// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} -// CHECK: #NO_APP -check!(xmm_reg_ptr ptr xmm_reg "movaps"); - -// CHECK-LABEL: xmm_reg_i8x16: -// CHECK: #APP -// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} -// CHECK: #NO_APP -check!(xmm_reg_i8x16 i8x16 xmm_reg "movaps"); - -// CHECK-LABEL: xmm_reg_i16x8: -// CHECK: #APP -// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} -// CHECK: #NO_APP -check!(xmm_reg_i16x8 i16x8 xmm_reg "movaps"); - -// CHECK-LABEL: xmm_reg_i32x4: -// CHECK: #APP -// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} -// CHECK: #NO_APP -check!(xmm_reg_i32x4 i32x4 xmm_reg "movaps"); - -// CHECK-LABEL: xmm_reg_i64x2: -// CHECK: #APP -// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} -// CHECK: #NO_APP -check!(xmm_reg_i64x2 i64x2 xmm_reg "movaps"); - -// CHECK-LABEL: xmm_reg_f16x8: -// CHECK: #APP -// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} -// CHECK: #NO_APP -check!(xmm_reg_f16x8 f16x8 xmm_reg "movaps"); - -// CHECK-LABEL: xmm_reg_f32x4: -// CHECK: #APP -// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} -// CHECK: #NO_APP -check!(xmm_reg_f32x4 f32x4 xmm_reg "movaps"); - -// CHECK-LABEL: xmm_reg_f64x2: -// CHECK: #APP -// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} -// CHECK: #NO_APP -check!(xmm_reg_f64x2 f64x2 xmm_reg "movaps"); - -// CHECK-LABEL: ymm_reg_f16: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_f16 f16 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_i32: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_i32 i32 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_f32: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_f32 f32 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_i64: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_i64 i64 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_f64: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_f64 f64 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_f128: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_f128 f128 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_ptr: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_ptr ptr ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_i8x16: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_i8x16 i8x16 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_i16x8: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_i16x8 i16x8 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_i32x4: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_i32x4 i32x4 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_i64x2: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_i64x2 i64x2 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_f16x8: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_f16x8 f16x8 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_f32x4: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_f32x4 f32x4 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_f64x2: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_f64x2 f64x2 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_i8x32: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_i8x32 i8x32 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_i16x16: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_i16x16 i16x16 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_i32x8: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_i32x8 i32x8 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_i64x4: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_i64x4 i64x4 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_f16x16: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_f16x16 f16x16 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_f32x8: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_f32x8 f32x8 ymm_reg "vmovaps"); - -// CHECK-LABEL: ymm_reg_f64x4: -// CHECK: #APP -// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} -// CHECK: #NO_APP -check!(ymm_reg_f64x4 f64x4 ymm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_f16: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_f16 f16 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_i32: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_i32 i32 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_f32: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_f32 f32 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_i64: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_i64 i64 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_f64: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_f64 f64 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_f128: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_f128 f128 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_ptr: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_ptr ptr zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_i8x16: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_i8x16 i8x16 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_i16x8: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_i16x8 i16x8 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_i32x4: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_i32x4 i32x4 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_i64x2: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_i64x2 i64x2 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_f16x8: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_f16x8 f16x8 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_f32x4: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_f32x4 f32x4 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_f64x2: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_f64x2 f64x2 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_i8x32: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_i8x32 i8x32 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_i16x16: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_i16x16 i16x16 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_i32x8: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_i32x8 i32x8 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_i64x4: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_i64x4 i64x4 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_f16x16: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_f16x16 f16x16 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_f32x8: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_f32x8 f32x8 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_f64x4: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_f64x4 f64x4 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_i8x64: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_i8x64 i8x64 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_i16x32: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_i16x32 i16x32 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_i32x16: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_i32x16 i32x16 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_i64x8: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_i64x8 i64x8 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_f16x32: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_f16x32 f16x32 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_f32x16: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_f32x16 f32x16 zmm_reg "vmovaps"); - -// CHECK-LABEL: zmm_reg_f64x8: -// CHECK: #APP -// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} -// CHECK: #NO_APP -check!(zmm_reg_f64x8 f64x8 zmm_reg "vmovaps"); - -// CHECK-LABEL: kreg_i8: -// CHECK: #APP -// CHECK: kmovb k{{[0-9]+}}, k{{[0-9]+}} -// CHECK: #NO_APP -check!(kreg_i8 i8 kreg "kmovb"); - -// CHECK-LABEL: kreg_i16: -// CHECK: #APP -// CHECK: kmovw k{{[0-9]+}}, k{{[0-9]+}} -// CHECK: #NO_APP -check!(kreg_i16 i16 kreg "kmovw"); - -// CHECK-LABEL: kreg_i32: -// CHECK: #APP -// CHECK: kmovd k{{[0-9]+}}, k{{[0-9]+}} -// CHECK: #NO_APP -check!(kreg_i32 i32 kreg "kmovd"); - -// CHECK-LABEL: kreg_i64: -// CHECK: #APP -// CHECK: kmovq k{{[0-9]+}}, k{{[0-9]+}} -// CHECK: #NO_APP -check!(kreg_i64 i64 kreg "kmovq"); - -// CHECK-LABEL: kreg_ptr: -// CHECK: #APP -// CHECK: kmovq k{{[0-9]+}}, k{{[0-9]+}} -// CHECK: #NO_APP -check!(kreg_ptr ptr kreg "kmovq"); - -// CHECK-LABEL: eax_i16: -// CHECK: #APP -// CHECK: mov eax, eax -// CHECK: #NO_APP -check_reg!(eax_i16 i16 "eax" "mov"); - -// CHECK-LABEL: eax_f16: -// CHECK: #APP -// CHECK: mov eax, eax -// CHECK: #NO_APP -check_reg!(eax_f16 f16 "eax" "mov"); - -// CHECK-LABEL: eax_i32: -// CHECK: #APP -// CHECK: mov eax, eax -// CHECK: #NO_APP -check_reg!(eax_i32 i32 "eax" "mov"); - -// CHECK-LABEL: eax_f32: -// CHECK: #APP -// CHECK: mov eax, eax -// CHECK: #NO_APP -check_reg!(eax_f32 f32 "eax" "mov"); - -// x86_64-LABEL: eax_i64: -// x86_64: #APP -// x86_64: mov eax, eax -// x86_64: #NO_APP -#[cfg(x86_64)] -check_reg!(eax_i64 i64 "eax" "mov"); - -// x86_64-LABEL: eax_f64: -// x86_64: #APP -// x86_64: mov eax, eax -// x86_64: #NO_APP -#[cfg(x86_64)] -check_reg!(eax_f64 f64 "eax" "mov"); - -// CHECK-LABEL: eax_ptr: -// CHECK: #APP -// CHECK: mov eax, eax -// CHECK: #NO_APP -check_reg!(eax_ptr ptr "eax" "mov"); - -// i686-LABEL: ah_byte: -// i686: #APP -// i686: mov ah, ah -// i686: #NO_APP -#[cfg(i686)] -check_reg!(ah_byte i8 "ah" "mov"); - -// CHECK-LABEL: xmm0_f16: -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check_reg!(xmm0_f16 f16 "xmm0" "movaps"); - -// CHECK-LABEL: xmm0_i32: -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check_reg!(xmm0_i32 i32 "xmm0" "movaps"); - -// CHECK-LABEL: xmm0_f32: -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check_reg!(xmm0_f32 f32 "xmm0" "movaps"); - -// CHECK-LABEL: xmm0_i64: -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check_reg!(xmm0_i64 i64 "xmm0" "movaps"); - -// CHECK-LABEL: xmm0_f64: -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check_reg!(xmm0_f64 f64 "xmm0" "movaps"); - -// CHECK-LABEL: xmm0_f128: -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check_reg!(xmm0_f128 f128 "xmm0" "movaps"); - -// CHECK-LABEL: xmm0_ptr: -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check_reg!(xmm0_ptr ptr "xmm0" "movaps"); - -// CHECK-LABEL: xmm0_i8x16: -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check_reg!(xmm0_i8x16 i8x16 "xmm0" "movaps"); - -// CHECK-LABEL: xmm0_i16x8: -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check_reg!(xmm0_i16x8 i16x8 "xmm0" "movaps"); - -// CHECK-LABEL: xmm0_i32x4: -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check_reg!(xmm0_i32x4 i32x4 "xmm0" "movaps"); - -// CHECK-LABEL: xmm0_i64x2: -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check_reg!(xmm0_i64x2 i64x2 "xmm0" "movaps"); - -// CHECK-LABEL: xmm0_f16x8: -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check_reg!(xmm0_f16x8 f16x8 "xmm0" "movaps"); - -// CHECK-LABEL: xmm0_f32x4: -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check_reg!(xmm0_f32x4 f32x4 "xmm0" "movaps"); - -// CHECK-LABEL: xmm0_f64x2: -// CHECK: #APP -// CHECK: movaps xmm0, xmm0 -// CHECK: #NO_APP -check_reg!(xmm0_f64x2 f64x2 "xmm0" "movaps"); - -// CHECK-LABEL: ymm0_f16: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_f16 f16 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_i32: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_i32 i32 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_f32: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_f32 f32 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_i64: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_i64 i64 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_f64: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_f64 f64 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_f128: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_f128 f128 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_ptr: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_ptr ptr "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_i8x16: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_i8x16 i8x16 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_i16x8: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_i16x8 i16x8 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_i32x4: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_i32x4 i32x4 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_i64x2: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_i64x2 i64x2 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_f16x8: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_f16x8 f16x8 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_f32x4: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_f32x4 f32x4 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_f64x2: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_f64x2 f64x2 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_i8x32: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_i8x32 i8x32 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_i16x16: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_i16x16 i16x16 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_i32x8: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_i32x8 i32x8 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_i64x4: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_i64x4 i64x4 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_f16x16: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_f16x16 f16x16 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_f32x8: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_f32x8 f32x8 "ymm0" "vmovaps"); - -// CHECK-LABEL: ymm0_f64x4: -// CHECK: #APP -// CHECK: vmovaps ymm0, ymm0 -// CHECK: #NO_APP -check_reg!(ymm0_f64x4 f64x4 "ymm0" "vmovaps"); - -// CHECK-LABEL: zmm0_f16: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_f16 f16 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_i32: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_i32 i32 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_f32: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_f32 f32 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_i64: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_i64 i64 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_f64: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_f64 f64 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_f128: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_f128 f128 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_ptr: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_ptr ptr "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_i8x16: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_i8x16 i8x16 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_i16x8: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_i16x8 i16x8 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_i32x4: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_i32x4 i32x4 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_i64x2: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_i64x2 i64x2 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_f16x8: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_f16x8 f16x8 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_f32x4: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_f32x4 f32x4 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_f64x2: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_f64x2 f64x2 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_i8x32: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_i8x32 i8x32 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_i16x16: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_i16x16 i16x16 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_i32x8: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_i32x8 i32x8 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_i64x4: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_i64x4 i64x4 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_f16x16: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_f16x16 f16x16 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_f32x8: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_f32x8 f32x8 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_f64x4: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_f64x4 f64x4 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_i8x64: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_i8x64 i8x64 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_i16x32: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_i16x32 i16x32 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_i32x16: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_i32x16 i32x16 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_i64x8: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_i64x8 i64x8 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_f16x32: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_f16x32 f16x32 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_f32x16: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_f32x16 f32x16 "zmm0" "vmovaps"); - -// CHECK-LABEL: zmm0_f64x8: -// CHECK: #APP -// CHECK: vmovaps zmm0, zmm0 -// CHECK: #NO_APP -check_reg!(zmm0_f64x8 f64x8 "zmm0" "vmovaps"); - -// CHECK-LABEL: k1_i8: -// CHECK: #APP -// CHECK: kmovb k1, k1 -// CHECK: #NO_APP -check_reg!(k1_i8 i8 "k1" "kmovb"); - -// CHECK-LABEL: k1_i16: -// CHECK: #APP -// CHECK: kmovw k1, k1 -// CHECK: #NO_APP -check_reg!(k1_i16 i16 "k1" "kmovw"); - -// CHECK-LABEL: k1_i32: -// CHECK: #APP -// CHECK: kmovd k1, k1 -// CHECK: #NO_APP -check_reg!(k1_i32 i32 "k1" "kmovd"); - -// CHECK-LABEL: k1_i64: -// CHECK: #APP -// CHECK: kmovq k1, k1 -// CHECK: #NO_APP -check_reg!(k1_i64 i64 "k1" "kmovq"); - -// CHECK-LABEL: k1_ptr: -// CHECK: #APP -// CHECK: kmovq k1, k1 -// CHECK: #NO_APP -check_reg!(k1_ptr ptr "k1" "kmovq"); diff --git a/tests/assembly/auxiliary/breakpoint-panic-handler.rs b/tests/assembly/auxiliary/breakpoint-panic-handler.rs deleted file mode 100644 index d54c1181e1a..00000000000 --- a/tests/assembly/auxiliary/breakpoint-panic-handler.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(core_intrinsics)] -#![no_std] - -#[panic_handler] -unsafe fn breakpoint_panic_handler(_: &::core::panic::PanicInfo) -> ! { - core::intrinsics::breakpoint(); - core::hint::unreachable_unchecked(); -} diff --git a/tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs b/tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs deleted file mode 100644 index 257608f881f..00000000000 --- a/tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ compile-flags: -g --crate-type=rlib -Cdwarf-version=4 - -pub fn check_is_even(number: &u64) -> bool { - number % 2 == 0 -} diff --git a/tests/assembly/auxiliary/non-inline-dependency.rs b/tests/assembly/auxiliary/non-inline-dependency.rs deleted file mode 100644 index 57f3ee87cdb..00000000000 --- a/tests/assembly/auxiliary/non-inline-dependency.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![no_std] -#![deny(warnings)] - -#[inline(never)] -#[no_mangle] -pub fn wrapping_external_fn(a: u32) -> u32 { - a.wrapping_mul(a) -} - -#[inline(never)] -#[no_mangle] -pub fn panicking_external_fn(a: u32) -> u32 { - a * a -} diff --git a/tests/assembly/breakpoint.rs b/tests/assembly/breakpoint.rs deleted file mode 100644 index e0cc2d1eebb..00000000000 --- a/tests/assembly/breakpoint.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ revisions: aarch64 x86_64 -//@ assembly-output: emit-asm -//@[aarch64] only-aarch64 -//@[x86_64] only-x86_64 - -#![feature(breakpoint)] -#![crate_type = "lib"] - -// CHECK-LABEL: use_bp -// aarch64: brk #0xf000 -// x86_64: int3 -pub fn use_bp() { - core::arch::breakpoint(); -} diff --git a/tests/assembly/closure-inherit-target-feature.rs b/tests/assembly/closure-inherit-target-feature.rs deleted file mode 100644 index 069204bbd34..00000000000 --- a/tests/assembly/closure-inherit-target-feature.rs +++ /dev/null @@ -1,59 +0,0 @@ -//@ only-x86_64 -//@ ignore-sgx Tests incompatible with LVI mitigations -//@ assembly-output: emit-asm -// make sure the feature is not enabled at compile-time -//@ compile-flags: -C opt-level=3 -C target-feature=-sse4.1 -C llvm-args=-x86-asm-syntax=intel - -#![crate_type = "rlib"] - -use std::arch::x86_64::{__m128, _mm_blend_ps}; - -// Use an explicit return pointer to prevent tail call optimization. -#[no_mangle] -pub unsafe fn sse41_blend_nofeature(x: __m128, y: __m128, ret: *mut __m128) { - let f = { - // check that _mm_blend_ps is not being inlined into the closure - // CHECK-LABEL: {{sse41_blend_nofeature.*closure.*:}} - // CHECK-NOT: blendps - // CHECK: {{call .*_mm_blend_ps.*}} - // CHECK-NOT: blendps - // CHECK: ret - #[inline(never)] - |x, y, ret: *mut __m128| unsafe { *ret = _mm_blend_ps(x, y, 0b0101) } - }; - f(x, y, ret); -} - -#[no_mangle] -#[target_feature(enable = "sse4.1")] -pub fn sse41_blend_noinline(x: __m128, y: __m128) -> __m128 { - let f = { - // check that _mm_blend_ps is being inlined into the closure - // CHECK-LABEL: {{sse41_blend_noinline.*closure.*:}} - // CHECK-NOT: _mm_blend_ps - // CHECK: blendps - // CHECK-NOT: _mm_blend_ps - // CHECK: ret - #[inline(never)] - |x, y| unsafe { _mm_blend_ps(x, y, 0b0101) } - }; - f(x, y) -} - -#[no_mangle] -#[target_feature(enable = "sse4.1")] -pub fn sse41_blend_doinline(x: __m128, y: __m128) -> __m128 { - // check that the closure and _mm_blend_ps are being inlined into the function - // CHECK-LABEL: sse41_blend_doinline: - // CHECK-NOT: {{sse41_blend_doinline.*closure.*}} - // CHECK-NOT: _mm_blend_ps - // CHECK: blendps - // CHECK-NOT: {{sse41_blend_doinline.*closure.*}} - // CHECK-NOT: _mm_blend_ps - // CHECK: ret - let f = { - #[inline] - |x, y| unsafe { _mm_blend_ps(x, y, 0b0101) } - }; - f(x, y) -} diff --git a/tests/assembly/cmse.rs b/tests/assembly/cmse.rs deleted file mode 100644 index a68ee99eac6..00000000000 --- a/tests/assembly/cmse.rs +++ /dev/null @@ -1,100 +0,0 @@ -//@ add-core-stubs -//@ revisions: hard soft -//@ assembly-output: emit-asm -//@ [hard] compile-flags: --target thumbv8m.main-none-eabihf --crate-type lib -Copt-level=1 -//@ [soft] compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -Copt-level=1 -//@ [hard] needs-llvm-components: arm -//@ [soft] needs-llvm-components: arm -#![crate_type = "lib"] -#![feature(abi_cmse_nonsecure_call, cmse_nonsecure_entry, no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: __acle_se_entry_point: -// CHECK-NEXT: entry_point: -// -// Write return argument (two registers since 64bit integer) -// CHECK: movs r0, #0 -// CHECK: movs r1, #0 -// -// If we are using hard-float: -// * Check if the float registers were touched (bit 3 in CONTROL) -// hard: mrs [[REG:r[0-9]+]], control -// hard: tst.w [[REG]], #8 -// hard: beq [[LABEL:[\.a-zA-Z0-9_]+]] -// -// * If touched clear all float registers (d0..=d7) -// hard: vmov d0, -// hard: vmov d1, -// hard: vmov d2, -// hard: vmov d3, -// hard: vmov d4, -// hard: vmov d5, -// hard: vmov d6, -// hard: vmov d7, -// -// * If touched clear FPU status register -// hard: vmrs [[REG:r[0-9]+]], fpscr -// hard: bic [[REG]], [[REG]], #159 -// hard: bic [[REG]], [[REG]], #4026531840 -// hard: vmsr fpscr, [[REG]] -// hard: [[LABEL]]: -// -// Clear all other registers that might have been used -// CHECK: mov r2, -// CHECK: mov r3, -// CHECK: mov r12, -// -// Clear the flags -// CHECK: msr apsr_nzcvq, -// -// Branch back to non-secure side -// CHECK: bxns lr -#[no_mangle] -pub extern "cmse-nonsecure-entry" fn entry_point() -> i64 { - 0 -} - -// NOTE for future codegen changes: -// The specific register assignment is not important, however: -// * all registers must be cleared before `blxns` is executed -// (either by writing arguments or any other value) -// * the lowest bit on the address of the callee must be cleared -// * the flags need to be overwritten -// * `blxns` needs to be called with the callee address -// (with the lowest bit cleared) -// -// CHECK-LABEL: call_nonsecure -// Save callee pointer -// CHECK: mov r12, r0 -// -// All arguments are written to (writes r0..=r3) -// CHECK: movs r0, #0 -// CHECK: movs r1, #1 -// CHECK: movs r2, #2 -// CHECK: movs r3, #3 -// -// Lowest bit gets cleared on callee address -// CHECK: bic r12, r12, #1 -// -// Ununsed registers get cleared (r4..=r11) -// CHECK: mov r4, -// CHECK: mov r5, -// CHECK: mov r6, -// CHECK: mov r7, -// CHECK: mov r8, -// CHECK: mov r9, -// CHECK: mov r10, -// CHECK: mov r11, -// -// Flags get cleared -// CHECK: msr apsr_nzcvq, -// -// Call to non-secure -// CHECK: blxns r12 -#[no_mangle] -pub fn call_nonsecure(f: unsafe extern "cmse-nonsecure-call" fn(u32, u32, u32, u32) -> u64) -> u64 { - unsafe { f(0, 1, 2, 3) } -} diff --git a/tests/assembly/compiletest-self-test/use-minicore-no-run.rs b/tests/assembly/compiletest-self-test/use-minicore-no-run.rs deleted file mode 100644 index 0e4f05c4b37..00000000000 --- a/tests/assembly/compiletest-self-test/use-minicore-no-run.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! `compiletest` self-test to check that `add-core-stubs` is incompatible with run pass modes. - -//@ add-core-stubs -//@ run-pass -//@ should-fail diff --git a/tests/assembly/cstring-merging.rs b/tests/assembly/cstring-merging.rs deleted file mode 100644 index 03688e0068b..00000000000 --- a/tests/assembly/cstring-merging.rs +++ /dev/null @@ -1,30 +0,0 @@ -// MIPS assembler uses the label prefix `$anon.` for local anonymous variables -// other architectures (including ARM and x86-64) use the prefix `.Lanon.` -//@ only-linux -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 -Cllvm-args=-enable-global-merge=0 -//@ edition: 2024 - -use std::ffi::CStr; - -// CHECK: .section .rodata.str1.{{[12]}},"aMS" -// CHECK: {{(\.L|\$)}}anon.{{.+}}: -// CHECK-NEXT: .asciz "foo" -#[unsafe(no_mangle)] -static CSTR: &[u8; 4] = b"foo\0"; - -// CHECK-NOT: .section -// CHECK: {{(\.L|\$)}}anon.{{.+}}: -// CHECK-NEXT: .asciz "bar" -#[unsafe(no_mangle)] -pub fn cstr() -> &'static CStr { - c"bar" -} - -// CHECK-NOT: .section -// CHECK: {{(\.L|\$)}}anon.{{.+}}: -// CHECK-NEXT: .asciz "baz" -#[unsafe(no_mangle)] -pub fn manual_cstr() -> &'static str { - "baz\0" -} diff --git a/tests/assembly/dwarf-mixed-versions-lto.rs b/tests/assembly/dwarf-mixed-versions-lto.rs deleted file mode 100644 index 9910a6e2f5f..00000000000 --- a/tests/assembly/dwarf-mixed-versions-lto.rs +++ /dev/null @@ -1,20 +0,0 @@ -// This test ensures that if LTO occurs between crates with different DWARF versions, we -// will choose the highest DWARF version for the final binary. This matches Clang's behavior. -// Note: `.2byte` directive is used on MIPS. - -//@ only-linux -//@ aux-build:dwarf-mixed-versions-lto-aux.rs -//@ compile-flags: -C lto -g -Cdwarf-version=5 -//@ assembly-output: emit-asm -//@ no-prefer-dynamic - -extern crate dwarf_mixed_versions_lto_aux; - -fn main() { - dwarf_mixed_versions_lto_aux::check_is_even(&0); -} - -// CHECK: .section .debug_info -// CHECK-NOT: {{\.(short|hword|2byte)}} 2 -// CHECK-NOT: {{\.(short|hword|2byte)}} 4 -// CHECK: {{\.(short|hword|2byte)}} 5 diff --git a/tests/assembly/dwarf4.rs b/tests/assembly/dwarf4.rs deleted file mode 100644 index 03a388603b4..00000000000 --- a/tests/assembly/dwarf4.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Makes sure that `-C dwarf-version=4` causes `rustc` to emit DWARF version 4. -//@ assembly-output: emit-asm -//@ add-core-stubs -//@ compile-flags: -g --target x86_64-unknown-linux-gnu -C dwarf-version=4 -Copt-level=0 -//@ needs-llvm-components: x86 - -#![feature(no_core, lang_items)] -#![crate_type = "rlib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -pub fn wibble() {} - -pub struct X; - -// CHECK: .section .debug_info -// CHECK-NOT: .short 2 -// CHECK-NOT: .short 5 -// CHECK: .short 4 -// CHECK-NOT: .section .debug_pubnames -// CHECK-NOT: .section .debug_pubtypes diff --git a/tests/assembly/dwarf5.rs b/tests/assembly/dwarf5.rs deleted file mode 100644 index 9bd92cc0d09..00000000000 --- a/tests/assembly/dwarf5.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Makes sure that `-C dwarf-version=5` causes `rustc` to emit DWARF version 5. -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: -g --target x86_64-unknown-linux-gnu -C dwarf-version=5 -Copt-level=0 -//@ needs-llvm-components: x86 - -#![feature(no_core, lang_items)] -#![crate_type = "rlib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -pub fn wibble() {} - -// CHECK: .section .debug_info -// CHECK-NOT: .short 2 -// CHECK-NOT: .short 4 -// CHECK: .short 5 -// CHECK: .section .debug_names diff --git a/tests/assembly/emit-intel-att-syntax.rs b/tests/assembly/emit-intel-att-syntax.rs deleted file mode 100644 index 7b479a0f79e..00000000000 --- a/tests/assembly/emit-intel-att-syntax.rs +++ /dev/null @@ -1,75 +0,0 @@ -//@ assembly-output: emit-asm -//@ revisions: att intel -//@ [att] compile-flags: -Cllvm-args=-x86-asm-syntax=att -//@ [intel] compile-flags: -Cllvm-args=-x86-asm-syntax=intel -//@ only-x86_64 - -#![crate_type = "lib"] - -// CHECK-LABEL: naked_att: -// intel-CHECK: mov rax, qword ptr [rdi] -// intel-CHECK: ret -// att-CHECK: movq (%rdi), %rax -// att-CHECK: retq - -#[unsafe(naked)] -#[unsafe(no_mangle)] -extern "sysv64" fn naked_att() { - std::arch::naked_asm!( - " - movq (%rdi), %rax - retq - ", - options(att_syntax), - ); -} - -// CHECK-LABEL: naked_intel: -// intel-CHECK: mov rax, rdi -// intel-CHECK: ret -// att-CHECK: movq (%rdi), %rax -// att-CHECK: retq - -#[unsafe(naked)] -#[unsafe(no_mangle)] -extern "sysv64" fn naked_intel() { - std::arch::naked_asm!( - " - mov rax, rdi - ret - ", - options(), - ); -} - -// CHECK-LABEL: global_att: -// intel-CHECK: mov rax, rdi -// intel-CHECK: ret -// att-CHECK: movq (%rdi), %rax -// att-CHECK: retq - -core::arch::global_asm!( - " - .globl global_att - global_att: - movq (%rdi), %rax - retq - ", - options(att_syntax), -); - -// CHECK-LABEL: global_intel: -// intel-CHECK: mov rax, rdi -// intel-CHECK: ret -// att-CHECK: movq (%rdi), %rax -// att-CHECK: retq - -core::arch::global_asm!( - " - .globl global_intel - global_intel: - mov rax, rdi - ret - ", - options(), -); diff --git a/tests/assembly/is_aligned.rs b/tests/assembly/is_aligned.rs deleted file mode 100644 index ab8f7dea808..00000000000 --- a/tests/assembly/is_aligned.rs +++ /dev/null @@ -1,55 +0,0 @@ -//@ assembly-output: emit-asm -//@ only-x86_64 -//@ ignore-sgx -//@ revisions: opt-speed opt-size -//@ [opt-speed] compile-flags: -Copt-level=2 -Cdebug-assertions=no -//@ [opt-size] compile-flags: -Copt-level=s -Cdebug-assertions=no -#![crate_type = "rlib"] -#![feature(core_intrinsics)] -#![feature(pointer_is_aligned_to)] - -// CHECK-LABEL: is_aligned_to_unchecked -// CHECK: decq -// CHECK-NEXT: testq -// CHECK-NEXT: sete -// CHECK: retq -#[no_mangle] -pub unsafe fn is_aligned_to_unchecked(ptr: *const u8, align: usize) -> bool { - unsafe { std::intrinsics::assume(align.is_power_of_two()) } - ptr.is_aligned_to(align) -} - -// CHECK-LABEL: is_aligned_1 -// CHECK: movb $1 -// CHECK: retq -#[no_mangle] -pub fn is_aligned_1(ptr: *const u8) -> bool { - ptr.is_aligned() -} - -// CHECK-LABEL: is_aligned_2 -// CHECK: testb $1 -// CHECK-NEXT: sete -// CHECK: retq -#[no_mangle] -pub fn is_aligned_2(ptr: *const u16) -> bool { - ptr.is_aligned() -} - -// CHECK-LABEL: is_aligned_4 -// CHECK: testb $3 -// CHECK-NEXT: sete -// CHECK: retq -#[no_mangle] -pub fn is_aligned_4(ptr: *const u32) -> bool { - ptr.is_aligned() -} - -// CHECK-LABEL: is_aligned_8 -// CHECK: testb $7 -// CHECK-NEXT: sete -// CHECK: retq -#[no_mangle] -pub fn is_aligned_8(ptr: *const u64) -> bool { - ptr.is_aligned() -} diff --git a/tests/assembly/issue-83585-small-pod-struct-equality.rs b/tests/assembly/issue-83585-small-pod-struct-equality.rs deleted file mode 100644 index 14bec1337f0..00000000000 --- a/tests/assembly/issue-83585-small-pod-struct-equality.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ assembly-output: emit-asm -//@ compile-flags: -Copt-level=3 -//@ only-x86_64 - -#![crate_type = "lib"] - -type T = u8; -type T1 = (T, T, T, T, T, T, T, T); - -// CHECK-LABEL: foo1a -// CHECK: cmpq -// CHECK-NEXT: sete -// CHECK-NEXT: {{retq|popq}} -#[no_mangle] -pub fn foo1a(a: T1, b: T1) -> bool { - a == b -} - -// CHECK-LABEL: foo1b -// CHECK: movq -// CHECK: cmpq -// CHECK-NEXT: sete -// CHECK-NEXT: {{retq|popq}} -#[no_mangle] -pub fn foo1b(a: &T1, b: &T1) -> bool { - a == b -} diff --git a/tests/assembly/libs/issue-115339-zip-arrays.rs b/tests/assembly/libs/issue-115339-zip-arrays.rs deleted file mode 100644 index 098382502e8..00000000000 --- a/tests/assembly/libs/issue-115339-zip-arrays.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ assembly-output: emit-asm -// # zen3 previously exhibited odd vectorization -//@ compile-flags: --crate-type=lib -Ctarget-cpu=znver3 -Copt-level=3 -//@ only-x86_64 -//@ ignore-sgx - -use std::iter; - -// previously this produced a long chain of -// 56: vpextrb $6, %xmm0, %ecx -// 57: orb %cl, 22(%rsi) -// 58: vpextrb $7, %xmm0, %ecx -// 59: orb %cl, 23(%rsi) -// [...] - -// CHECK-LABEL: zip_arrays: -#[no_mangle] -pub fn zip_arrays(mut a: [u8; 32], b: [u8; 32]) -> [u8; 32] { - // CHECK-NOT: vpextrb - // CHECK-NOT: orb %cl - // CHECK: vorps - iter::zip(&mut a, b).for_each(|(a, b)| *a |= b); - // CHECK: retq - a -} diff --git a/tests/assembly/libs/issue-140207-slice-min-simd.rs b/tests/assembly/libs/issue-140207-slice-min-simd.rs deleted file mode 100644 index 86f067cac08..00000000000 --- a/tests/assembly/libs/issue-140207-slice-min-simd.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ assembly-output: emit-asm -// # avx has a dedicated instruction for this -//@ compile-flags: --crate-type=lib -Ctarget-cpu=znver2 -Copt-level=3 -//@ only-x86_64 -//@ ignore-sgx -// https://github.com/rust-lang/rust/issues/140207 - -#[unsafe(no_mangle)] -pub fn array_min(a: &[u16; 8]) -> u16 { - // CHECK: vphminposuw - // CHECK: ret - a.iter().copied().min().unwrap() -} diff --git a/tests/assembly/manual-eq-efficient.rs b/tests/assembly/manual-eq-efficient.rs deleted file mode 100644 index 8dafed354be..00000000000 --- a/tests/assembly/manual-eq-efficient.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Regression test for #106269 -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 -C llvm-args=-x86-asm-syntax=intel -//@ only-x86_64 -//@ ignore-sgx - -pub struct S { - a: u8, - b: u8, - c: u8, - d: u8, -} - -// CHECK-LABEL: manual_eq: -#[no_mangle] -pub fn manual_eq(s1: &S, s2: &S) -> bool { - // CHECK: mov [[REG:[a-z0-9]+]], dword ptr [{{[a-z0-9]+}}] - // CHECK-NEXT: cmp [[REG]], dword ptr [{{[a-z0-9]+}}] - // CHECK-NEXT: sete al - // CHECK: ret - s1.a == s2.a && s1.b == s2.b && s1.c == s2.c && s1.d == s2.d -} diff --git a/tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs b/tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs deleted file mode 100644 index 860ecc3cfcd..00000000000 --- a/tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Zbranch-protection=bti -//@ assembly-output: emit-asm -//@ needs-asm-support -//@ only-aarch64 - -#![crate_type = "lib"] - -use std::arch::naked_asm; - -// The problem at hand: Rust has adopted a fairly strict meaning for "naked functions", -// meaning "no prologue whatsoever, no, really, not one instruction." -// Unfortunately, aarch64's "branch target identification" works via hints at landing sites. -// LLVM implements this via making sure of that, even for functions with the naked attribute. -// So, we must emit an appropriate instruction instead! -#[no_mangle] -#[unsafe(naked)] -pub extern "C" fn _hlt() -> ! { - // CHECK-NOT: hint #34 - // CHECK: hlt #0x1 - naked_asm!("hlt #1") -} diff --git a/tests/assembly/naked-functions/aix.rs b/tests/assembly/naked-functions/aix.rs deleted file mode 100644 index 57ff0e183be..00000000000 --- a/tests/assembly/naked-functions/aix.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@ revisions: elfv1-be aix -//@ add-core-stubs -//@ assembly-output: emit-asm -// -//@[elfv1-be] compile-flags: --target powerpc64-unknown-linux-gnu -//@[elfv1-be] needs-llvm-components: powerpc -// -//@[aix] compile-flags: --target powerpc64-ibm-aix -//@[aix] needs-llvm-components: powerpc - -#![crate_type = "lib"] -#![feature(no_core, asm_experimental_arch, f128, linkage, fn_align)] -#![no_core] - -// tests that naked functions work for the `powerpc64-ibm-aix` target. -// -// This target is special because it uses the XCOFF binary format -// It is tested alongside an elf powerpc target to pin down commonalities and differences. -// -// https://doc.rust-lang.org/rustc/platform-support/aix.html -// https://www.ibm.com/docs/en/aix/7.2?topic=formats-xcoff-object-file-format - -extern crate minicore; -use minicore::*; - -// elfv1-be: .p2align 2 -// aix: .align 2 -// CHECK: .globl blr -// CHECK-LABEL: blr: -// CHECK: blr -#[no_mangle] -#[unsafe(naked)] -extern "C" fn blr() { - naked_asm!("blr") -} diff --git a/tests/assembly/naked-functions/wasm32.rs b/tests/assembly/naked-functions/wasm32.rs deleted file mode 100644 index 77547e82041..00000000000 --- a/tests/assembly/naked-functions/wasm32.rs +++ /dev/null @@ -1,200 +0,0 @@ -//@ revisions: wasm32-unknown wasm64-unknown wasm32-wasip1 -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ [wasm32-unknown] compile-flags: --target wasm32-unknown-unknown -//@ [wasm64-unknown] compile-flags: --target wasm64-unknown-unknown -//@ [wasm32-wasip1] compile-flags: --target wasm32-wasip1 -//@ [wasm32-unknown] needs-llvm-components: webassembly -//@ [wasm64-unknown] needs-llvm-components: webassembly -//@ [wasm32-wasip1] needs-llvm-components: webassembly - -#![crate_type = "lib"] -#![feature(no_core, asm_experimental_arch, f128, linkage, fn_align)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK: .section .text.nop,"",@ -// CHECK: .globl nop -// CHECK-LABEL: nop: -// CHECK: .functype nop () -> () -// CHECK-NOT: .size -// CHECK: end_function -#[no_mangle] -#[unsafe(naked)] -extern "C" fn nop() { - naked_asm!("nop") -} - -// CHECK: .section .text.weak_nop,"",@ -// CHECK: .weak weak_nop -// CHECK-LABEL: nop: -// CHECK: .functype weak_nop () -> () -// CHECK-NOT: .size -// CHECK: end_function -#[no_mangle] -#[unsafe(naked)] -#[linkage = "weak"] -extern "C" fn weak_nop() { - naked_asm!("nop") -} - -// CHECK-LABEL: fn_i8_i8: -// CHECK-NEXT: .functype fn_i8_i8 (i32) -> (i32) -// -// CHECK-NEXT: local.get 0 -// CHECK-NEXT: local.get 0 -// CHECK-NEXT: i32.mul -// -// CHECK-NEXT: end_function -#[no_mangle] -#[unsafe(naked)] -extern "C" fn fn_i8_i8(num: i8) -> i8 { - naked_asm!("local.get 0", "local.get 0", "i32.mul") -} - -// CHECK-LABEL: fn_i8_i8_i8: -// CHECK: .functype fn_i8_i8_i8 (i32, i32) -> (i32) -#[no_mangle] -#[unsafe(naked)] -extern "C" fn fn_i8_i8_i8(a: i8, b: i8) -> i8 { - naked_asm!("local.get 1", "local.get 0", "i32.mul") -} - -// CHECK-LABEL: fn_unit_i8: -// CHECK: .functype fn_unit_i8 () -> (i32) -#[no_mangle] -#[unsafe(naked)] -extern "C" fn fn_unit_i8() -> i8 { - naked_asm!("i32.const 42") -} - -// CHECK-LABEL: fn_i8_unit: -// CHECK: .functype fn_i8_unit (i32) -> () -#[no_mangle] -#[unsafe(naked)] -extern "C" fn fn_i8_unit(_: i8) { - naked_asm!("nop") -} - -// CHECK-LABEL: fn_i32_i32: -// CHECK: .functype fn_i32_i32 (i32) -> (i32) -#[no_mangle] -#[unsafe(naked)] -extern "C" fn fn_i32_i32(num: i32) -> i32 { - naked_asm!("local.get 0", "local.get 0", "i32.mul") -} - -// CHECK-LABEL: fn_i64_i64: -// CHECK: .functype fn_i64_i64 (i64) -> (i64) -#[no_mangle] -#[unsafe(naked)] -extern "C" fn fn_i64_i64(num: i64) -> i64 { - naked_asm!("local.get 0", "local.get 0", "i64.mul") -} - -// CHECK-LABEL: fn_i128_i128: -// wasm32-unknown: .functype fn_i128_i128 (i32, i64, i64) -> () -// wasm32-wasip1: .functype fn_i128_i128 (i32, i64, i64) -> () -// wasm64-unknown: .functype fn_i128_i128 (i64, i64, i64) -> () -#[allow(improper_ctypes_definitions)] -#[no_mangle] -#[unsafe(naked)] -extern "C" fn fn_i128_i128(num: i128) -> i128 { - naked_asm!( - "local.get 0", - "local.get 2", - "i64.store 8", - "local.get 0", - "local.get 1", - "i64.store 0", - ) -} - -// CHECK-LABEL: fn_f128_f128: -// wasm32-unknown: .functype fn_f128_f128 (i32, i64, i64) -> () -// wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> () -// wasm64-unknown: .functype fn_f128_f128 (i64, i64, i64) -> () -#[no_mangle] -#[unsafe(naked)] -extern "C" fn fn_f128_f128(num: f128) -> f128 { - naked_asm!( - "local.get 0", - "local.get 2", - "i64.store 8", - "local.get 0", - "local.get 1", - "i64.store 0", - ) -} - -#[repr(C)] -struct Compound { - a: u16, - b: i64, -} - -// CHECK-LABEL: fn_compound_compound: -// wasm32-unknown: .functype fn_compound_compound (i32, i32) -> () -// wasm32-wasip1: .functype fn_compound_compound (i32, i32) -> () -// wasm64-unknown: .functype fn_compound_compound (i64, i64) -> () -#[no_mangle] -#[unsafe(naked)] -extern "C" fn fn_compound_compound(_: Compound) -> Compound { - // this is the wasm32-wasip1 assembly - naked_asm!( - "local.get 0", - "local.get 1", - "i64.load 8", - "i64.store 8", - "local.get 0", - "local.get 1", - "i32.load16_u 0", - "i32.store16 0", - ) -} - -#[repr(C)] -struct WrapperI32(i32); - -// CHECK-LABEL: fn_wrapperi32_wrapperi32: -// CHECK: .functype fn_wrapperi32_wrapperi32 (i32) -> (i32) -#[no_mangle] -#[unsafe(naked)] -extern "C" fn fn_wrapperi32_wrapperi32(_: WrapperI32) -> WrapperI32 { - naked_asm!("local.get 0") -} - -#[repr(C)] -struct WrapperI64(i64); - -// CHECK-LABEL: fn_wrapperi64_wrapperi64: -// CHECK: .functype fn_wrapperi64_wrapperi64 (i64) -> (i64) -#[no_mangle] -#[unsafe(naked)] -extern "C" fn fn_wrapperi64_wrapperi64(_: WrapperI64) -> WrapperI64 { - naked_asm!("local.get 0") -} - -#[repr(C)] -struct WrapperF32(f32); - -// CHECK-LABEL: fn_wrapperf32_wrapperf32: -// CHECK: .functype fn_wrapperf32_wrapperf32 (f32) -> (f32) -#[no_mangle] -#[unsafe(naked)] -extern "C" fn fn_wrapperf32_wrapperf32(_: WrapperF32) -> WrapperF32 { - naked_asm!("local.get 0") -} - -#[repr(C)] -struct WrapperF64(f64); - -// CHECK-LABEL: fn_wrapperf64_wrapperf64: -// CHECK: .functype fn_wrapperf64_wrapperf64 (f64) -> (f64) -#[no_mangle] -#[unsafe(naked)] -extern "C" fn fn_wrapperf64_wrapperf64(_: WrapperF64) -> WrapperF64 { - naked_asm!("local.get 0") -} diff --git a/tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs b/tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs deleted file mode 100644 index 81ee9b13b4e..00000000000 --- a/tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Zcf-protection=full -//@ assembly-output: emit-asm -//@ needs-asm-support -//@ only-x86_64 - -#![crate_type = "lib"] - -use std::arch::naked_asm; - -// The problem at hand: Rust has adopted a fairly strict meaning for "naked functions", -// meaning "no prologue whatsoever, no, really, not one instruction." -// Unfortunately, x86's control-flow enforcement, specifically indirect branch protection, -// works by using an instruction for each possible landing site, -// and LLVM implements this via making sure of that. -#[no_mangle] -#[unsafe(naked)] -pub extern "sysv64" fn will_halt() -> ! { - // CHECK-NOT: endbr{{32|64}} - // CHECK: hlt - naked_asm!("hlt") -} - -// what about aarch64? -// "branch-protection"=false diff --git a/tests/assembly/niche-prefer-zero.rs b/tests/assembly/niche-prefer-zero.rs deleted file mode 100644 index 4e260ebc09b..00000000000 --- a/tests/assembly/niche-prefer-zero.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Check that niche selection prefers zero and that jumps are optimized away. -// See https://github.com/rust-lang/rust/pull/87794 -//@ assembly-output: emit-asm -//@ only-x86 -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -#[repr(u8)] -pub enum Size { - One = 1, - Two = 2, - Three = 3, -} - -#[no_mangle] -pub fn handle(x: Option) -> u8 { - match x { - None => 0, - Some(size) => size as u8, - } -} - -// There should be no jumps in output -// CHECK-NOT: j diff --git a/tests/assembly/nvptx-arch-default.rs b/tests/assembly/nvptx-arch-default.rs deleted file mode 100644 index a621fd6dcb2..00000000000 --- a/tests/assembly/nvptx-arch-default.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ assembly-output: ptx-linker -//@ compile-flags: --crate-type cdylib -Z unstable-options -Clinker-flavor=llbc -//@ only-nvptx64 - -#![no_std] - -//@ aux-build: breakpoint-panic-handler.rs -extern crate breakpoint_panic_handler; - -// Verify default target arch with ptx-linker. -// CHECK: .target sm_30 -// CHECK: .address_size 64 diff --git a/tests/assembly/nvptx-arch-emit-asm.rs b/tests/assembly/nvptx-arch-emit-asm.rs deleted file mode 100644 index e47f8e78e36..00000000000 --- a/tests/assembly/nvptx-arch-emit-asm.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type rlib -//@ only-nvptx64 - -#![no_std] - -// Verify default arch without ptx-linker involved. -// CHECK: .target sm_30 -// CHECK: .address_size 64 diff --git a/tests/assembly/nvptx-arch-link-arg.rs b/tests/assembly/nvptx-arch-link-arg.rs deleted file mode 100644 index 3432e6161bf..00000000000 --- a/tests/assembly/nvptx-arch-link-arg.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ assembly-output: ptx-linker -//@ compile-flags: --crate-type cdylib -C link-arg=--arch=sm_60 -//@ only-nvptx64 -//@ ignore-nvptx64 - -#![no_std] - -//@ aux-build: breakpoint-panic-handler.rs -extern crate breakpoint_panic_handler; - -// Verify target arch override via `link-arg`. -// CHECK: .target sm_60 -// CHECK: .address_size 64 diff --git a/tests/assembly/nvptx-arch-target-cpu.rs b/tests/assembly/nvptx-arch-target-cpu.rs deleted file mode 100644 index 609ab297e63..00000000000 --- a/tests/assembly/nvptx-arch-target-cpu.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ assembly-output: ptx-linker -//@ compile-flags: --crate-type cdylib -C target-cpu=sm_50 -Z unstable-options -Clinker-flavor=llbc -//@ only-nvptx64 - -#![no_std] - -//@ aux-build: breakpoint-panic-handler.rs -extern crate breakpoint_panic_handler; - -// Verify target arch override via `target-cpu`. -// CHECK: .target sm_50 -// CHECK: .address_size 64 diff --git a/tests/assembly/nvptx-atomics.rs b/tests/assembly/nvptx-atomics.rs deleted file mode 100644 index 52b8c86d8a9..00000000000 --- a/tests/assembly/nvptx-atomics.rs +++ /dev/null @@ -1,86 +0,0 @@ -//@ assembly-output: ptx-linker -//@ compile-flags: --crate-type cdylib -//@ only-nvptx64 -//@ ignore-nvptx64 - -#![feature(abi_ptx, core_intrinsics)] -#![no_std] - -use core::intrinsics::*; - -//@ aux-build: breakpoint-panic-handler.rs -extern crate breakpoint_panic_handler; - -// Currently, LLVM NVPTX backend can only emit atomic instructions with -// `relaxed` (PTX default) ordering. But it's also useful to make sure -// the backend won't fail with other orders. Apparently, the backend -// doesn't support fences as well. As a workaround `llvm.nvvm.membar.*` -// could work, and perhaps on the long run, all the atomic operations -// should rather be provided by `core::arch::nvptx`. - -// Also, PTX ISA doesn't have atomic `load`, `store` and `nand`. - -// FIXME(denzp): add tests for `core::sync::atomic::*`. - -#[no_mangle] -pub unsafe extern "ptx-kernel" fn atomics_kernel(a: *mut u32) { - // CHECK: atom.global.and.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - // CHECK: atom.global.and.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - atomic_and(a, 1); - atomic_and_relaxed(a, 1); - - // CHECK: atom.global.cas.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1, 2; - // CHECK: atom.global.cas.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1, 2; - atomic_cxchg(a, 1, 2); - atomic_cxchg_relaxed(a, 1, 2); - - // CHECK: atom.global.max.s32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - // CHECK: atom.global.max.s32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - atomic_max(a, 1); - atomic_max_relaxed(a, 1); - - // CHECK: atom.global.min.s32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - // CHECK: atom.global.min.s32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - atomic_min(a, 1); - atomic_min_relaxed(a, 1); - - // CHECK: atom.global.or.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - // CHECK: atom.global.or.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - atomic_or(a, 1); - atomic_or_relaxed(a, 1); - - // CHECK: atom.global.max.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - // CHECK: atom.global.max.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - atomic_umax(a, 1); - atomic_umax_relaxed(a, 1); - - // CHECK: atom.global.min.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - // CHECK: atom.global.min.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - atomic_umin(a, 1); - atomic_umin_relaxed(a, 1); - - // CHECK: atom.global.add.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - // CHECK: atom.global.add.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - atomic_xadd(a, 1); - atomic_xadd_relaxed(a, 1); - - // CHECK: atom.global.exch.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - // CHECK: atom.global.exch.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - atomic_xchg(a, 1); - atomic_xchg_relaxed(a, 1); - - // CHECK: atom.global.xor.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - // CHECK: atom.global.xor.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; - atomic_xor(a, 1); - atomic_xor_relaxed(a, 1); - - // CHECK: mov.u32 %[[sub_0_arg:r[0-9]+]], 100; - // CHECK: neg.s32 temp, %[[sub_0_arg]]; - // CHECK: atom.global.add.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], temp; - atomic_xsub(a, 100); - - // CHECK: mov.u32 %[[sub_1_arg:r[0-9]+]], 200; - // CHECK: neg.s32 temp, %[[sub_1_arg]]; - // CHECK: atom.global.add.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], temp; - atomic_xsub_relaxed(a, 200); -} diff --git a/tests/assembly/nvptx-c-abi-arg-v7.rs b/tests/assembly/nvptx-c-abi-arg-v7.rs deleted file mode 100644 index be98b167470..00000000000 --- a/tests/assembly/nvptx-c-abi-arg-v7.rs +++ /dev/null @@ -1,220 +0,0 @@ -//@ assembly-output: ptx-linker -//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86 -Z unstable-options -Clinker-flavor=llbc -//@ only-nvptx64 - -// The PTX ABI stability is tied to major versions of the PTX ISA -// These tests assume major version 7 - -// CHECK: .version 7 - -#![feature(abi_ptx, lang_items, no_core)] -#![no_core] - -#[lang = "pointee_sized"] -trait PointeeSized {} -#[lang = "meta_sized"] -trait MetaSized: PointeeSized {} -#[lang = "sized"] -trait Sized: MetaSized {} -#[lang = "copy"] -trait Copy {} - -#[repr(C)] -pub struct SingleU8 { - f: u8, -} - -#[repr(C)] -pub struct DoubleU8 { - f: u8, - g: u8, -} - -#[repr(C)] -pub struct TripleU8 { - f: u8, - g: u8, - h: u8, -} - -#[repr(C)] -pub struct TripleU16 { - f: u16, - g: u16, - h: u16, -} -#[repr(C)] -pub struct DoubleI32 { - f: i32, - g: i32, -} -#[repr(C)] -pub struct TripleU32 { - f: u32, - g: u32, - h: u32, -} -#[repr(C)] -pub struct TripleU64 { - f: u64, - g: u64, - h: u64, -} - -#[repr(C)] -pub struct DoubleFloat { - f: f32, - g: f32, -} - -#[repr(C)] -pub struct TripleFloat { - f: f32, - g: f32, - h: f32, -} - -#[repr(C)] -pub struct TripleDouble { - f: f64, - g: f64, - h: f64, -} - -#[repr(C)] -pub struct ManyIntegers { - f: u8, - g: u16, - h: u32, - i: u64, -} - -#[repr(C)] -pub struct ManyNumerics { - f: u8, - g: u16, - h: u32, - i: u64, - j: f32, - k: f64, -} - -// CHECK: .visible .func f_u8_arg( -// CHECK: .param .b32 f_u8_arg_param_0 -#[no_mangle] -pub unsafe extern "C" fn f_u8_arg(_a: u8) {} - -// CHECK: .visible .func f_u16_arg( -// CHECK: .param .b32 f_u16_arg_param_0 -#[no_mangle] -pub unsafe extern "C" fn f_u16_arg(_a: u16) {} - -// CHECK: .visible .func f_u32_arg( -// CHECK: .param .b32 f_u32_arg_param_0 -#[no_mangle] -pub unsafe extern "C" fn f_u32_arg(_a: u32) {} - -// CHECK: .visible .func f_u64_arg( -// CHECK: .param .b64 f_u64_arg_param_0 -#[no_mangle] -pub unsafe extern "C" fn f_u64_arg(_a: u64) {} - -// CHECK: .visible .func f_u128_arg( -// CHECK: .param .align 16 .b8 f_u128_arg_param_0[16] -#[no_mangle] -pub unsafe extern "C" fn f_u128_arg(_a: u128) {} - -// CHECK: .visible .func f_i8_arg( -// CHECK: .param .b32 f_i8_arg_param_0 -#[no_mangle] -pub unsafe extern "C" fn f_i8_arg(_a: i8) {} - -// CHECK: .visible .func f_i16_arg( -// CHECK: .param .b32 f_i16_arg_param_0 -#[no_mangle] -pub unsafe extern "C" fn f_i16_arg(_a: i16) {} - -// CHECK: .visible .func f_i32_arg( -// CHECK: .param .b32 f_i32_arg_param_0 -#[no_mangle] -pub unsafe extern "C" fn f_i32_arg(_a: i32) {} - -// CHECK: .visible .func f_i64_arg( -// CHECK: .param .b64 f_i64_arg_param_0 -#[no_mangle] -pub unsafe extern "C" fn f_i64_arg(_a: i64) {} - -// CHECK: .visible .func f_i128_arg( -// CHECK: .param .align 16 .b8 f_i128_arg_param_0[16] -#[no_mangle] -pub unsafe extern "C" fn f_i128_arg(_a: i128) {} - -// CHECK: .visible .func f_f32_arg( -// CHECK: .param .b32 f_f32_arg_param_0 -#[no_mangle] -pub unsafe extern "C" fn f_f32_arg(_a: f32) {} - -// CHECK: .visible .func f_f64_arg( -// CHECK: .param .b64 f_f64_arg_param_0 -#[no_mangle] -pub unsafe extern "C" fn f_f64_arg(_a: f64) {} - -// CHECK: .visible .func f_single_u8_arg( -// CHECK: .param .align 1 .b8 f_single_u8_arg_param_0[1] -#[no_mangle] -pub unsafe extern "C" fn f_single_u8_arg(_a: SingleU8) {} - -// CHECK: .visible .func f_double_u8_arg( -// CHECK: .param .align 1 .b8 f_double_u8_arg_param_0[2] -#[no_mangle] -pub unsafe extern "C" fn f_double_u8_arg(_a: DoubleU8) {} - -// CHECK: .visible .func f_triple_u8_arg( -// CHECK: .param .align 1 .b8 f_triple_u8_arg_param_0[3] -#[no_mangle] -pub unsafe extern "C" fn f_triple_u8_arg(_a: TripleU8) {} - -// CHECK: .visible .func f_triple_u16_arg( -// CHECK: .param .align 2 .b8 f_triple_u16_arg_param_0[6] -#[no_mangle] -pub unsafe extern "C" fn f_triple_u16_arg(_a: TripleU16) {} - -// CHECK: .visible .func f_triple_u32_arg( -// CHECK: .param .align 4 .b8 f_triple_u32_arg_param_0[12] -#[no_mangle] -pub unsafe extern "C" fn f_triple_u32_arg(_a: TripleU32) {} - -// CHECK: .visible .func f_double_i32_arg( -// CHECK: .param .align 4 .b8 f_double_i32_arg_param_0[8] -#[no_mangle] -pub unsafe extern "C" fn f_double_i32_arg(_a: DoubleI32) {} - -// CHECK: .visible .func f_triple_u64_arg( -// CHECK: .param .align 8 .b8 f_triple_u64_arg_param_0[24] -#[no_mangle] -pub unsafe extern "C" fn f_triple_u64_arg(_a: TripleU64) {} - -// CHECK: .visible .func f_many_integers_arg( -// CHECK: .param .align 8 .b8 f_many_integers_arg_param_0[16] -#[no_mangle] -pub unsafe extern "C" fn f_many_integers_arg(_a: ManyIntegers) {} - -// CHECK: .visible .func f_double_float_arg( -// CHECK: .param .align 4 .b8 f_double_float_arg_param_0[8] -#[no_mangle] -pub unsafe extern "C" fn f_double_float_arg(_a: DoubleFloat) {} - -// CHECK: .visible .func f_triple_float_arg( -// CHECK: .param .align 4 .b8 f_triple_float_arg_param_0[12] -#[no_mangle] -pub unsafe extern "C" fn f_triple_float_arg(_a: TripleFloat) {} - -// CHECK: .visible .func f_triple_double_arg( -// CHECK: .param .align 8 .b8 f_triple_double_arg_param_0[24] -#[no_mangle] -pub unsafe extern "C" fn f_triple_double_arg(_a: TripleDouble) {} - -// CHECK: .visible .func f_many_numerics_arg( -// CHECK: .param .align 8 .b8 f_many_numerics_arg_param_0[32] -#[no_mangle] -pub unsafe extern "C" fn f_many_numerics_arg(_a: ManyNumerics) {} diff --git a/tests/assembly/nvptx-c-abi-ret-v7.rs b/tests/assembly/nvptx-c-abi-ret-v7.rs deleted file mode 100644 index c68c71c872c..00000000000 --- a/tests/assembly/nvptx-c-abi-ret-v7.rs +++ /dev/null @@ -1,244 +0,0 @@ -//@ assembly-output: ptx-linker -//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86 -Z unstable-options -Clinker-flavor=llbc -//@ only-nvptx64 - -// The PTX ABI stability is tied to major versions of the PTX ISA -// These tests assume major version 7 - -// CHECK: .version 7 - -#![feature(abi_ptx, lang_items, no_core)] -#![no_core] - -#[lang = "pointee_sized"] -trait PointeeSized {} -#[lang = "meta_sized"] -trait MetaSized: PointeeSized {} -#[lang = "sized"] -trait Sized: MetaSized {} -#[lang = "copy"] -trait Copy {} - -#[repr(C)] -pub struct SingleU8 { - f: u8, -} - -#[repr(C)] -pub struct DoubleU8 { - f: u8, - g: u8, -} - -#[repr(C)] -pub struct TripleU8 { - f: u8, - g: u8, - h: u8, -} - -#[repr(C)] -pub struct TripleU16 { - f: u16, - g: u16, - h: u16, -} -#[repr(C)] -pub struct DoubleI32 { - f: i32, - g: i32, -} -#[repr(C)] -pub struct TripleU32 { - f: u32, - g: u32, - h: u32, -} -#[repr(C)] -pub struct TripleU64 { - f: u64, - g: u64, - h: u64, -} - -#[repr(C)] -pub struct DoubleFloat { - f: f32, - g: f32, -} - -#[repr(C)] -pub struct TripleFloat { - f: f32, - g: f32, - h: f32, -} - -#[repr(C)] -pub struct TripleDouble { - f: f64, - g: f64, - h: f64, -} - -#[repr(C)] -pub struct ManyIntegers { - f: u8, - g: u16, - h: u32, - i: u64, -} - -#[repr(C)] -pub struct ManyNumerics { - f: u8, - g: u16, - h: u32, - i: u64, - j: f32, - k: f64, -} - -// CHECK: .visible .func (.param .b32 func_retval0) f_u8_ret( -#[no_mangle] -pub unsafe extern "C" fn f_u8_ret() -> u8 { - 0 -} - -// CHECK: .visible .func (.param .b32 func_retval0) f_u16_ret( -#[no_mangle] -pub unsafe extern "C" fn f_u16_ret() -> u16 { - 1 -} - -// CHECK: .visible .func (.param .b32 func_retval0) f_u32_ret( -#[no_mangle] -pub unsafe extern "C" fn f_u32_ret() -> u32 { - 2 -} - -// CHECK: .visible .func (.param .b64 func_retval0) f_u64_ret( -#[no_mangle] -pub unsafe extern "C" fn f_u64_ret() -> u64 { - 3 -} - -// CHECK: .visible .func (.param .align 16 .b8 func_retval0[16]) f_u128_ret( -#[no_mangle] -pub unsafe extern "C" fn f_u128_ret() -> u128 { - 4 -} - -// CHECK: .visible .func (.param .b32 func_retval0) f_i8_ret( -#[no_mangle] -pub unsafe extern "C" fn f_i8_ret() -> i8 { - 5 -} - -// CHECK: .visible .func (.param .b32 func_retval0) f_i16_ret( -#[no_mangle] -pub unsafe extern "C" fn f_i16_ret() -> i16 { - 6 -} - -// CHECK: .visible .func (.param .b32 func_retval0) f_i32_ret( -#[no_mangle] -pub unsafe extern "C" fn f_i32_ret() -> i32 { - 7 -} - -// CHECK: .visible .func (.param .b64 func_retval0) f_i64_ret( -#[no_mangle] -pub unsafe extern "C" fn f_i64_ret() -> i64 { - 8 -} - -// CHECK: .visible .func (.param .align 16 .b8 func_retval0[16]) f_i128_ret( -#[no_mangle] -pub unsafe extern "C" fn f_i128_ret() -> i128 { - 9 -} - -// CHECK: .visible .func (.param .b32 func_retval0) f_f32_ret( -#[no_mangle] -pub unsafe extern "C" fn f_f32_ret() -> f32 { - 10.0 -} - -// CHECK: .visible .func (.param .b64 func_retval0) f_f64_ret( -#[no_mangle] -pub unsafe extern "C" fn f_f64_ret() -> f64 { - 11.0 -} - -// CHECK: .visible .func (.param .align 1 .b8 func_retval0[1]) f_single_u8_ret( -#[no_mangle] -pub unsafe extern "C" fn f_single_u8_ret() -> SingleU8 { - SingleU8 { f: 12 } -} - -// CHECK: .visible .func (.param .align 1 .b8 func_retval0[2]) f_double_u8_ret( -#[no_mangle] -pub unsafe extern "C" fn f_double_u8_ret() -> DoubleU8 { - DoubleU8 { f: 13, g: 14 } -} - -// CHECK: .visible .func (.param .align 1 .b8 func_retval0[3]) f_triple_u8_ret( -#[no_mangle] -pub unsafe extern "C" fn f_triple_u8_ret() -> TripleU8 { - TripleU8 { f: 15, g: 16, h: 17 } -} - -// CHECK: .visible .func (.param .align 2 .b8 func_retval0[6]) f_triple_u16_ret( -#[no_mangle] -pub unsafe extern "C" fn f_triple_u16_ret() -> TripleU16 { - TripleU16 { f: 18, g: 19, h: 20 } -} - -// CHECK: .visible .func (.param .align 4 .b8 func_retval0[8]) f_double_i32_ret( -#[no_mangle] -pub unsafe extern "C" fn f_double_i32_ret() -> DoubleI32 { - DoubleI32 { f: 1, g: 2 } -} - -// CHECK: .visible .func (.param .align 4 .b8 func_retval0[12]) f_triple_u32_ret( -#[no_mangle] -pub unsafe extern "C" fn f_triple_u32_ret() -> TripleU32 { - TripleU32 { f: 20, g: 21, h: 22 } -} - -// CHECK: .visible .func (.param .align 8 .b8 func_retval0[24]) f_triple_u64_ret( -#[no_mangle] -pub unsafe extern "C" fn f_triple_u64_ret() -> TripleU64 { - TripleU64 { f: 23, g: 24, h: 25 } -} - -// CHECK: .visible .func (.param .align 8 .b8 func_retval0[16]) f_many_integers_ret( -#[no_mangle] -pub unsafe extern "C" fn f_many_integers_ret() -> ManyIntegers { - ManyIntegers { f: 26, g: 27, h: 28, i: 29 } -} - -// CHECK: .visible .func (.param .align 4 .b8 func_retval0[8]) f_double_float_ret( -#[no_mangle] -pub unsafe extern "C" fn f_double_float_ret() -> DoubleFloat { - DoubleFloat { f: 29.0, g: 30.0 } -} - -// CHECK: .visible .func (.param .align 4 .b8 func_retval0[12]) f_triple_float_ret( -#[no_mangle] -pub unsafe extern "C" fn f_triple_float_ret() -> TripleFloat { - TripleFloat { f: 31.0, g: 32.0, h: 33.0 } -} - -// CHECK: .visible .func (.param .align 8 .b8 func_retval0[24]) f_triple_double_ret( -#[no_mangle] -pub unsafe extern "C" fn f_triple_double_ret() -> TripleDouble { - TripleDouble { f: 34.0, g: 35.0, h: 36.0 } -} - -// CHECK: .visible .func (.param .align 8 .b8 func_retval0[32]) f_many_numerics_ret( -#[no_mangle] -pub unsafe extern "C" fn f_many_numerics_ret() -> ManyNumerics { - ManyNumerics { f: 37, g: 38, h: 39, i: 40, j: 41.0, k: 43.0 } -} diff --git a/tests/assembly/nvptx-internalizing.rs b/tests/assembly/nvptx-internalizing.rs deleted file mode 100644 index 0acfd5c2443..00000000000 --- a/tests/assembly/nvptx-internalizing.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ assembly-output: ptx-linker -//@ compile-flags: --crate-type cdylib -//@ only-nvptx64 -//@ ignore-nvptx64 - -#![feature(abi_ptx)] -#![no_std] - -//@ aux-build: breakpoint-panic-handler.rs -extern crate breakpoint_panic_handler; - -//@ aux-build: non-inline-dependency.rs -extern crate non_inline_dependency as dep; - -// Verify that no extra function declarations are present. -// CHECK-NOT: .func - -// CHECK: .visible .entry top_kernel( -#[no_mangle] -pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) { - // CHECK: add.s32 %{{r[0-9]+}}, %{{r[0-9]+}}, 5; - *b = *a + 5; -} - -// Verify that no extra function definitions are here. -// CHECK-NOT: .func -// CHECK-NOT: .entry diff --git a/tests/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs b/tests/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs deleted file mode 100644 index f245b4460f2..00000000000 --- a/tests/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs +++ /dev/null @@ -1,251 +0,0 @@ -//@ assembly-output: ptx-linker -//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86 -Z unstable-options -Clinker-flavor=llbc -//@ only-nvptx64 - -// The following ABI tests are made with nvcc 11.6 does. -// -// The PTX ABI stability is tied to major versions of the PTX ISA -// These tests assume major version 7 -// -// -// The following correspondence between types are assumed: -// u - uint_t -// i - int_t -// [T, N] - std::array -// &T - T const* -// &mut T - T* - -// CHECK: .version 7 - -#![feature(abi_ptx, lang_items, no_core)] -#![no_core] - -#[lang = "pointee_sized"] -trait PointeeSized {} -#[lang = "meta_sized"] -trait MetaSized: PointeeSized {} -#[lang = "sized"] -trait Sized: MetaSized {} -#[lang = "copy"] -trait Copy {} - -#[repr(C)] -pub struct SingleU8 { - f: u8, -} - -#[repr(C)] -pub struct DoubleU8 { - f: u8, - g: u8, -} - -#[repr(C)] -pub struct TripleU8 { - f: u8, - g: u8, - h: u8, -} - -#[repr(C)] -pub struct TripleU16 { - f: u16, - g: u16, - h: u16, -} -#[repr(C)] -pub struct DoubleI32 { - f: i32, - g: i32, -} -#[repr(C)] -pub struct TripleU32 { - f: u32, - g: u32, - h: u32, -} -#[repr(C)] -pub struct TripleU64 { - f: u64, - g: u64, - h: u64, -} - -#[repr(C)] -pub struct DoubleFloat { - f: f32, - g: f32, -} - -#[repr(C)] -pub struct TripleFloat { - f: f32, - g: f32, - h: f32, -} - -#[repr(C)] -pub struct TripleDouble { - f: f64, - g: f64, - h: f64, -} - -#[repr(C)] -pub struct ManyIntegers { - f: u8, - g: u16, - h: u32, - i: u64, -} - -#[repr(C)] -pub struct ManyNumerics { - f: u8, - g: u16, - h: u32, - i: u64, - j: f32, - k: f64, -} - -// CHECK: .visible .entry f_u8_arg( -// CHECK: .param .u8 f_u8_arg_param_0 -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_u8_arg(_a: u8) {} - -// CHECK: .visible .entry f_u16_arg( -// CHECK: .param .u16 f_u16_arg_param_0 -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_u16_arg(_a: u16) {} - -// CHECK: .visible .entry f_u32_arg( -// CHECK: .param .u32 f_u32_arg_param_0 -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_u32_arg(_a: u32) {} - -// CHECK: .visible .entry f_u64_arg( -// CHECK: .param .u64 f_u64_arg_param_0 -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_u64_arg(_a: u64) {} - -// CHECK: .visible .entry f_u128_arg( -// CHECK: .param .align 16 .b8 f_u128_arg_param_0[16] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_u128_arg(_a: u128) {} - -// CHECK: .visible .entry f_i8_arg( -// CHECK: .param .u8 f_i8_arg_param_0 -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_i8_arg(_a: i8) {} - -// CHECK: .visible .entry f_i16_arg( -// CHECK: .param .u16 f_i16_arg_param_0 -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_i16_arg(_a: i16) {} - -// CHECK: .visible .entry f_i32_arg( -// CHECK: .param .u32 f_i32_arg_param_0 -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_i32_arg(_a: i32) {} - -// CHECK: .visible .entry f_i64_arg( -// CHECK: .param .u64 f_i64_arg_param_0 -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_i64_arg(_a: i64) {} - -// CHECK: .visible .entry f_i128_arg( -// CHECK: .param .align 16 .b8 f_i128_arg_param_0[16] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_i128_arg(_a: i128) {} - -// CHECK: .visible .entry f_f32_arg( -// CHECK: .param .f32 f_f32_arg_param_0 -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_f32_arg(_a: f32) {} - -// CHECK: .visible .entry f_f64_arg( -// CHECK: .param .f64 f_f64_arg_param_0 -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_f64_arg(_a: f64) {} - -// CHECK: .visible .entry f_single_u8_arg( -// CHECK: .param .align 1 .b8 f_single_u8_arg_param_0[1] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_single_u8_arg(_a: SingleU8) {} - -// CHECK: .visible .entry f_double_u8_arg( -// CHECK: .param .align 1 .b8 f_double_u8_arg_param_0[2] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_double_u8_arg(_a: DoubleU8) {} - -// CHECK: .visible .entry f_triple_u8_arg( -// CHECK: .param .align 1 .b8 f_triple_u8_arg_param_0[3] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_triple_u8_arg(_a: TripleU8) {} - -// CHECK: .visible .entry f_triple_u16_arg( -// CHECK: .param .align 2 .b8 f_triple_u16_arg_param_0[6] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_triple_u16_arg(_a: TripleU16) {} - -// CHECK: .visible .entry f_double_i32_arg( -// CHECK: .param .align 4 .b8 f_double_i32_arg_param_0[8] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_double_i32_arg(_a: DoubleI32) {} - -// CHECK: .visible .entry f_triple_u32_arg( -// CHECK: .param .align 4 .b8 f_triple_u32_arg_param_0[12] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_triple_u32_arg(_a: TripleU32) {} - -// CHECK: .visible .entry f_triple_u64_arg( -// CHECK: .param .align 8 .b8 f_triple_u64_arg_param_0[24] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_triple_u64_arg(_a: TripleU64) {} - -// CHECK: .visible .entry f_many_integers_arg( -// CHECK: .param .align 8 .b8 f_many_integers_arg_param_0[16] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_many_integers_arg(_a: ManyIntegers) {} - -// CHECK: .visible .entry f_double_float_arg( -// CHECK: .param .align 4 .b8 f_double_float_arg_param_0[8] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_double_float_arg(_a: DoubleFloat) {} - -// CHECK: .visible .entry f_triple_float_arg( -// CHECK: .param .align 4 .b8 f_triple_float_arg_param_0[12] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_triple_float_arg(_a: TripleFloat) {} - -// CHECK: .visible .entry f_triple_double_arg( -// CHECK: .param .align 8 .b8 f_triple_double_arg_param_0[24] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_triple_double_arg(_a: TripleDouble) {} - -// CHECK: .visible .entry f_many_numerics_arg( -// CHECK: .param .align 8 .b8 f_many_numerics_arg_param_0[32] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_many_numerics_arg(_a: ManyNumerics) {} - -// CHECK: .visible .entry f_byte_array_arg( -// CHECK: .param .align 1 .b8 f_byte_array_arg_param_0[5] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_byte_array_arg(_a: [u8; 5]) {} - -// CHECK: .visible .entry f_float_array_arg( -// CHECK: .param .align 4 .b8 f_float_array_arg_param_0[20] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_float_array_arg(_a: [f32; 5]) {} - -// FIXME: u128 started to break compilation with disabled CI -// NO_CHECK: .visible .entry f_u128_array_arg( -// NO_CHECK: .param .align 16 .b8 f_u128_array_arg_param_0[80] -//#[no_mangle] -//pub unsafe extern "ptx-kernel" fn f_u128_array_arg(_a: [u128; 5]) {} - -// CHECK: .visible .entry f_u32_slice_arg( -// CHECK: .param .align 8 .b8 f_u32_slice_arg_param_0[16] -#[no_mangle] -pub unsafe extern "ptx-kernel" fn f_u32_slice_arg(_a: &[u32]) {} diff --git a/tests/assembly/nvptx-linking-binary.rs b/tests/assembly/nvptx-linking-binary.rs deleted file mode 100644 index 3b50b472ab1..00000000000 --- a/tests/assembly/nvptx-linking-binary.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@ assembly-output: ptx-linker -//@ compile-flags: --crate-type bin -//@ only-nvptx64 -//@ ignore-nvptx64 - -#![feature(abi_ptx)] -#![no_main] -#![no_std] - -//@ aux-build: breakpoint-panic-handler.rs -extern crate breakpoint_panic_handler; - -//@ aux-build: non-inline-dependency.rs -extern crate non_inline_dependency as dep; - -// Make sure declarations are there. -// CHECK: .func (.param .b32 func_retval0) wrapping_external_fn -// CHECK: .func (.param .b32 func_retval0) panicking_external_fn - -// CHECK-LABEL: .visible .entry top_kernel( -#[no_mangle] -pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) { - // CHECK: call.uni (retval0), - // CHECK-NEXT: wrapping_external_fn - // CHECK: ld.param.b32 %[[LHS:r[0-9]+]], [retval0+0]; - let lhs = dep::wrapping_external_fn(*a); - - // CHECK: call.uni (retval0), - // CHECK-NEXT: panicking_external_fn - // CHECK: ld.param.b32 %[[RHS:r[0-9]+]], [retval0+0]; - let rhs = dep::panicking_external_fn(*a); - - // CHECK: add.s32 %[[RES:r[0-9]+]], %[[RHS]], %[[LHS]]; - // CHECK: st.global.u32 [%{{rd[0-9]+}}], %[[RES]]; - *b = lhs + rhs; -} - -// Verify that external function bodies are available. -// CHECK: .func (.param .b32 func_retval0) wrapping_external_fn -// CHECK: .func (.param .b32 func_retval0) panicking_external_fn diff --git a/tests/assembly/nvptx-linking-cdylib.rs b/tests/assembly/nvptx-linking-cdylib.rs deleted file mode 100644 index 9742e26fb31..00000000000 --- a/tests/assembly/nvptx-linking-cdylib.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@ assembly-output: ptx-linker -//@ compile-flags: --crate-type cdylib -//@ only-nvptx64 -//@ ignore-nvptx64 - -#![feature(abi_ptx)] -#![no_std] - -//@ aux-build: breakpoint-panic-handler.rs -extern crate breakpoint_panic_handler; - -//@ aux-build: non-inline-dependency.rs -extern crate non_inline_dependency as dep; - -// Make sure declarations are there. -// CHECK: .func (.param .b32 func_retval0) wrapping_external_fn -// CHECK: .func (.param .b32 func_retval0) panicking_external_fn - -// CHECK-LABEL: .visible .entry top_kernel( -#[no_mangle] -pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) { - // CHECK: call.uni (retval0), - // CHECK-NEXT: wrapping_external_fn - // CHECK: ld.param.b32 %[[LHS:r[0-9]+]], [retval0+0]; - let lhs = dep::wrapping_external_fn(*a); - - // CHECK: call.uni (retval0), - // CHECK-NEXT: panicking_external_fn - // CHECK: ld.param.b32 %[[RHS:r[0-9]+]], [retval0+0]; - let rhs = dep::panicking_external_fn(*a); - - // CHECK: add.s32 %[[RES:r[0-9]+]], %[[RHS]], %[[LHS]]; - // CHECK: st.global.u32 [%{{rd[0-9]+}}], %[[RES]]; - *b = lhs + rhs; -} - -// Verify that external function bodies are available. -// CHECK: .func (.param .b32 func_retval0) wrapping_external_fn -// CHECK: .func (.param .b32 func_retval0) panicking_external_fn diff --git a/tests/assembly/nvptx-safe-naming.rs b/tests/assembly/nvptx-safe-naming.rs deleted file mode 100644 index d7b46aadd9c..00000000000 --- a/tests/assembly/nvptx-safe-naming.rs +++ /dev/null @@ -1,37 +0,0 @@ -//@ assembly-output: ptx-linker -//@ compile-flags: --crate-type cdylib -Z unstable-options -Clinker-flavor=llbc -//@ only-nvptx64 - -#![feature(abi_ptx)] -#![no_std] - -//@ aux-build: breakpoint-panic-handler.rs -extern crate breakpoint_panic_handler; - -// Verify function name doesn't contain unacceaptable characters. -// CHECK: .func (.param .b32 func_retval0) [[IMPL_FN:[a-zA-Z0-9$_]+square[a-zA-Z0-9$_]+]] - -// CHECK-LABEL: .visible .entry top_kernel( -#[no_mangle] -pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) { - // CHECK: call.uni (retval0), - // CHECK-NEXT: [[IMPL_FN]] - *b = deep::private::MyStruct::new(*a).square(); -} - -pub mod deep { - pub mod private { - pub struct MyStruct(T); - - impl MyStruct { - pub fn new(a: u32) -> Self { - MyStruct(a) - } - - #[inline(never)] - pub fn square(&self) -> u32 { - self.0.wrapping_mul(self.0) - } - } - } -} diff --git a/tests/assembly/panic-no-unwind-no-uwtable.rs b/tests/assembly/panic-no-unwind-no-uwtable.rs deleted file mode 100644 index b51b173e961..00000000000 --- a/tests/assembly/panic-no-unwind-no-uwtable.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ assembly-output: emit-asm -//@ only-x86_64-unknown-linux-gnu -//@ compile-flags: -C panic=unwind -C force-unwind-tables=n -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-NOT: .cfi_startproc -pub fn foo() {} diff --git a/tests/assembly/panic-unwind-no-uwtable.rs b/tests/assembly/panic-unwind-no-uwtable.rs deleted file mode 100644 index 181656a8987..00000000000 --- a/tests/assembly/panic-unwind-no-uwtable.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ assembly-output: emit-asm -//@ only-x86_64-unknown-linux-gnu -//@ compile-flags: -C panic=unwind -C force-unwind-tables=n - -#![crate_type = "lib"] - -// CHECK-LABEL: foo: -// CHECK: .cfi_startproc -#[no_mangle] -fn foo() { - panic!(); -} diff --git a/tests/assembly/pic-relocation-model.rs b/tests/assembly/pic-relocation-model.rs deleted file mode 100644 index 15a8723f756..00000000000 --- a/tests/assembly/pic-relocation-model.rs +++ /dev/null @@ -1,31 +0,0 @@ -//@ add-core-stubs -//@ revisions: x64 -//@ assembly-output: emit-asm -//@ [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=pic -//@ [x64] needs-llvm-components: x86 - -#![feature(no_core, lang_items)] -#![no_core] -#![crate_type = "rlib"] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: call_other_fn: -// CHECK: {{(jmpq|callq)}} *other_fn@GOTPCREL(%rip) -#[no_mangle] -pub fn call_other_fn() -> u8 { - unsafe { other_fn() } -} - -// CHECK-LABEL: other_fn: -// CHECK: {{(jmpq|callq)}} *foreign_fn@GOTPCREL(%rip) -#[no_mangle] -#[inline(never)] -pub fn other_fn() -> u8 { - unsafe { foreign_fn() } -} - -extern "C" { - fn foreign_fn() -> u8; -} diff --git a/tests/assembly/pie-relocation-model.rs b/tests/assembly/pie-relocation-model.rs deleted file mode 100644 index cbe0001041e..00000000000 --- a/tests/assembly/pie-relocation-model.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@ add-core-stubs -//@ revisions: x64 -//@ assembly-output: emit-asm -//@ [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=pie -//@ [x64] needs-llvm-components: x86 - -#![feature(no_core, lang_items)] -#![no_core] -#![crate_type = "rlib"] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: call_other_fn: -// With PIE local functions are called "directly". -// CHECK: {{(jmp|callq)}} other_fn -#[no_mangle] -pub fn call_other_fn() -> u8 { - unsafe { other_fn() } -} - -// CHECK-LABEL: other_fn: -// External functions are still called through GOT, since we don't know if the symbol -// is defined in the binary or in the shared library. -// CHECK: {{(jmpq|callq)}} *foreign_fn@GOTPCREL(%rip) -#[no_mangle] -#[inline(never)] -pub fn other_fn() -> u8 { - unsafe { foreign_fn() } -} - -extern "C" { - fn foreign_fn() -> u8; -} diff --git a/tests/assembly/powerpc64-struct-abi.rs b/tests/assembly/powerpc64-struct-abi.rs deleted file mode 100644 index ee4965deb4f..00000000000 --- a/tests/assembly/powerpc64-struct-abi.rs +++ /dev/null @@ -1,156 +0,0 @@ -//@ add-core-stubs -//@ revisions: elfv1-be elfv2-be elfv2-le aix -//@ assembly-output: emit-asm -//@ compile-flags: -Copt-level=3 -//@[elfv1-be] compile-flags: --target powerpc64-unknown-linux-gnu -//@[elfv1-be] needs-llvm-components: powerpc -//@[elfv2-be] compile-flags: --target powerpc64-unknown-linux-musl -//@[elfv2-be] needs-llvm-components: powerpc -//@[elfv2-le] compile-flags: --target powerpc64le-unknown-linux-gnu -C target-cpu=pwr8 -//@[elfv2-le] needs-llvm-components: powerpc -//@[aix] compile-flags: --target powerpc64-ibm-aix -//@[aix] needs-llvm-components: powerpc -//@[elfv1-be] filecheck-flags: --check-prefix be -//@[elfv2-be] filecheck-flags: --check-prefix be -//@[elfv1-be] filecheck-flags: --check-prefix elf -//@[elfv2-be] filecheck-flags: --check-prefix elf -//@[elfv2-le] filecheck-flags: --check-prefix elf - -#![feature(no_core, lang_items)] -#![no_std] -#![no_core] -#![crate_type = "lib"] - -extern crate minicore; -use minicore::*; - -impl Copy for FiveU32s {} -impl Copy for FiveU16s {} -impl Copy for ThreeU8s {} - -#[repr(C)] -struct FiveU32s(u32, u32, u32, u32, u32); - -#[repr(C)] -struct FiveU16s(u16, u16, u16, u16, u16); - -#[repr(C)] -struct ThreeU8s(u8, u8, u8); - -// CHECK-LABEL: read_large -// aix: lwz [[REG1:.*]], 16(4) -// aix-NEXT: lxv{{d2x|w4x}} 0, 0, 4 -// aix-NEXT: stw [[REG1]], 16(3) -// aix-NEXT: stxv{{d2x|w4x}} 0, 0, 3 -// be: lwz [[REG1:.*]], 16(4) -// be-NEXT: stw [[REG1]], 16(3) -// be-NEXT: ld [[REG2:.*]], 8(4) -// be-NEXT: ld [[REG3:.*]], 0(4) -// be-NEXT: std [[REG2]], 8(3) -// be-NEXT: std [[REG3]], 0(3) -// elfv2-le: lxvd2x [[REG1:.*]], 0, 4 -// elfv2-le-NEXT: lwz [[REG2:.*]], 16(4) -// elfv2-le-NEXT: stw [[REG2]], 16(3) -// elfv2-le-NEXT: stxvd2x [[REG1]], 0, 3 -// CHECK-NEXT: blr -#[no_mangle] -extern "C" fn read_large(x: &FiveU32s) -> FiveU32s { - *x -} - -// CHECK-LABEL: read_medium -// aix: lhz [[REG1:.*]], 8(4) -// aix-NEXT: ld [[REG2:.*]], 0(4) -// aix-NEXT: sth [[REG1]], 8(3) -// aix-NEXT: std [[REG2]], 0(3) -// elfv1-be: lhz [[REG1:.*]], 8(4) -// elfv1-be-NEXT: ld [[REG2:.*]], 0(4) -// elfv1-be-NEXT: sth [[REG1]], 8(3) -// elfv1-be-NEXT: std [[REG2]], 0(3) -// elfv2-be: lhz [[REG1:.*]], 8(3) -// elfv2-be-NEXT: ld 3, 0(3) -// elfv2-be-NEXT: sldi 4, [[REG1]], 48 -// elfv2-le: ld [[REG1:.*]], 0(3) -// elfv2-le-NEXT: lhz 4, 8(3) -// elfv2-le-NEXT: mr 3, [[REG1]] -// CHECK-NEXT: blr -#[no_mangle] -extern "C" fn read_medium(x: &FiveU16s) -> FiveU16s { - *x -} - -// CHECK-LABEL: read_small -// aix: lbz [[REG1:.*]], 2(4) -// aix-NEXT: lhz [[REG2:.*]], 0(4) -// aix-NEXT: stb [[REG1]], 2(3) -// aix-NEXT: sth [[REG2]], 0(3) -// elfv1-be: lbz [[REG1:.*]], 2(4) -// elfv1-be-NEXT: lhz [[REG2:.*]], 0(4) -// elfv1-be-NEXT: stb [[REG1]], 2(3) -// elfv1-be-NEXT: sth [[REG2]], 0(3) -// elfv2-be: lhz [[REG1:.*]], 0(3) -// elfv2-be-NEXT: lbz 3, 2(3) -// elfv2-be-NEXT: rldimi 3, [[REG1]], 8, 0 -// elfv2-le: lbz [[REG1:.*]], 2(3) -// elfv2-le-NEXT: lhz 3, 0(3) -// elfv2-le-NEXT: rldimi 3, [[REG1]], 16, 0 -// CHECK-NEXT: blr -#[no_mangle] -extern "C" fn read_small(x: &ThreeU8s) -> ThreeU8s { - *x -} - -// CHECK-LABEL: write_large -// aix: std 3, 48(1) -// aix-NEXT: rldicl [[REG1:.*]], 5, 32, 32 -// aix-NEXT: std 5, 64(1) -// aix-NEXT: std 4, 56(1) -// aix-NEXT: stw [[REG1]], 16(6) -// aix-NEXT: addi [[REG2:.*]], 1, 48 -// aix-NEXT: lxv{{d2x|w4x}} 0, 0, [[REG2]] -// aix-NEXT: stxv{{d2x|w4x}} 0, 0, 6 -// elf: std 3, 0(6) -// be-NEXT: rldicl [[REG1:.*]], 5, 32, 32 -// elf-NEXT: std 4, 8(6) -// be-NEXT: stw [[REG1]], 16(6) -// elfv2-le-NEXT: stw 5, 16(6) -// CHECK-NEXT: blr -#[no_mangle] -extern "C" fn write_large(x: FiveU32s, dest: &mut FiveU32s) { - *dest = x; -} - -// CHECK-LABEL: write_medium -// aix: std 4, 56(1) -// aix-NEXT: rldicl [[REG1:.*]], 4, 16, 48 -// aix-NEXT: std 3, 48(1) -// aix-NEXT: std 3, 0(5) -// aix-NEXT: sth [[REG1]], 8(5) -// elf: std 3, 0(5) -// be-NEXT: rldicl [[REG1:.*]], 4, 16, 48 -// be-NEXT: sth [[REG1]], 8(5) -// elfv2-le-NEXT: sth 4, 8(5) -// CHECK-NEXT: blr -#[no_mangle] -extern "C" fn write_medium(x: FiveU16s, dest: &mut FiveU16s) { - *dest = x; -} - -// CHECK-LABEL: write_small -// aix: std 3, 48(1) -// aix-NEXT: rldicl [[REG1:.*]], 3, 16, 48 -// aix-NEXT: sth 3, 0(4) -// aix-NEXT: lbz 3, 50(1) -// aix-NEXT: stb [[REG1]], 2(4) -// be: stb 3, 2(4) -// be-NEXT: srwi [[REG1:.*]], 3, 8 -// be-NEXT: sth [[REG1]], 0(4) -// The order these instructions are emitted in changed in LLVM 18. -// elfv2-le-DAG: sth 3, 0(4) -// elfv2-le-DAG: srwi [[REG1:.*]], 3, 16 -// elfv2-le-NEXT: stb [[REG1]], 2(4) -// CHECK-NEXT: blr -#[no_mangle] -extern "C" fn write_small(x: ThreeU8s, dest: &mut ThreeU8s) { - *dest = x; -} diff --git a/tests/assembly/riscv-float-struct-abi.rs b/tests/assembly/riscv-float-struct-abi.rs deleted file mode 100644 index 5d9ac9d70b8..00000000000 --- a/tests/assembly/riscv-float-struct-abi.rs +++ /dev/null @@ -1,177 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: -Copt-level=3 --target riscv64gc-unknown-linux-gnu -//@ needs-llvm-components: riscv - -#![feature(no_core, lang_items)] -#![no_std] -#![no_core] -#![crate_type = "lib"] - -extern crate minicore; -use minicore::*; - -#[repr(C, align(64))] -struct Aligned(f64); - -#[repr(C)] -struct Padded(u8, Aligned); - -#[repr(C, packed)] -struct Packed(u8, f32); - -impl Copy for Aligned {} -impl Copy for Padded {} -impl Copy for Packed {} - -extern "C" { - fn take_padded(x: Padded); - fn get_padded() -> Padded; - fn take_packed(x: Packed); - fn get_packed() -> Packed; -} - -// CHECK-LABEL: pass_padded -#[unsafe(no_mangle)] -extern "C" fn pass_padded(out: &mut Padded, x: Padded) { - // CHECK: sb a1, 0(a0) - // CHECK-NEXT: fsd fa0, 64(a0) - // CHECK-NEXT: ret - *out = x; -} - -// CHECK-LABEL: ret_padded -#[unsafe(no_mangle)] -extern "C" fn ret_padded(x: &Padded) -> Padded { - // CHECK: fld fa0, 64(a0) - // CHECK-NEXT: lbu a0, 0(a0) - // CHECK-NEXT: ret - *x -} - -#[unsafe(no_mangle)] -extern "C" fn call_padded(x: &Padded) { - // CHECK: fld fa0, 64(a0) - // CHECK-NEXT: lbu a0, 0(a0) - // CHECK-NEXT: tail take_padded - unsafe { - take_padded(*x); - } -} - -#[unsafe(no_mangle)] -extern "C" fn receive_padded(out: &mut Padded) { - // CHECK: addi sp, sp, -16 - // CHECK-NEXT: .cfi_def_cfa_offset 16 - // CHECK-NEXT: sd ra, [[#%d,RA_SPILL:]](sp) - // CHECK-NEXT: sd [[TEMP:.*]], [[#%d,TEMP_SPILL:]](sp) - // CHECK-NEXT: .cfi_offset ra, [[#%d,RA_SPILL - 16]] - // CHECK-NEXT: .cfi_offset [[TEMP]], [[#%d,TEMP_SPILL - 16]] - // CHECK-NEXT: mv [[TEMP]], a0 - // CHECK-NEXT: call get_padded - // CHECK-NEXT: sb a0, 0([[TEMP]]) - // CHECK-NEXT: fsd fa0, 64([[TEMP]]) - // CHECK-NEXT: ld ra, [[#%d,RA_SPILL]](sp) - // CHECK-NEXT: ld [[TEMP]], [[#%d,TEMP_SPILL]](sp) - // CHECK: addi sp, sp, 16 - // CHECK: ret - unsafe { - *out = get_padded(); - } -} - -// CHECK-LABEL: pass_packed -#[unsafe(no_mangle)] -extern "C" fn pass_packed(out: &mut Packed, x: Packed) { - // CHECK: addi sp, sp, -16 - // CHECK-NEXT: .cfi_def_cfa_offset 16 - // CHECK-NEXT: sb a1, 0(a0) - // CHECK-NEXT: fsw fa0, 8(sp) - // CHECK-NEXT: lw [[VALUE:.*]], 8(sp) - // CHECK-DAG: srli [[BYTE4:.*]], [[VALUE]], 24 - // CHECK-DAG: srli [[BYTE3:.*]], [[VALUE]], 16 - // CHECK-DAG: srli [[BYTE2:.*]], [[VALUE]], 8 - // CHECK-DAG: sb [[VALUE]], 1(a0) - // CHECK-DAG: sb [[BYTE2]], 2(a0) - // CHECK-DAG: sb [[BYTE3]], 3(a0) - // CHECK-DAG: sb [[BYTE4]], 4(a0) - // CHECK-NEXT: addi sp, sp, 16 - // CHECK: ret - *out = x; -} - -// CHECK-LABEL: ret_packed -#[unsafe(no_mangle)] -extern "C" fn ret_packed(x: &Packed) -> Packed { - // CHECK: addi sp, sp, -16 - // CHECK-NEXT: .cfi_def_cfa_offset 16 - // CHECK-NEXT: lbu [[BYTE2:.*]], 2(a0) - // CHECK-NEXT: lbu [[BYTE1:.*]], 1(a0) - // CHECK-NEXT: lbu [[BYTE3:.*]], 3(a0) - // CHECK-NEXT: lbu [[BYTE4:.*]], 4(a0) - // CHECK-NEXT: slli [[SHIFTED2:.*]], [[BYTE2]], 8 - // CHECK-NEXT: or [[BYTE12:.*]], [[SHIFTED2]], [[BYTE1]] - // CHECK-NEXT: slli [[SHIFTED3:.*]], [[BYTE3]], 16 - // CHECK-NEXT: slli [[SHIFTED4:.*]], [[BYTE4]], 24 - // CHECK-NEXT: or [[BYTE34:.*]], [[SHIFTED3]], [[SHIFTED4]] - // CHECK-NEXT: or [[VALUE:.*]], [[BYTE12]], [[BYTE34]] - // CHECK-NEXT: sw [[VALUE]], 8(sp) - // CHECK-NEXT: flw fa0, 8(sp) - // CHECK-NEXT: lbu a0, 0(a0) - // CHECK-NEXT: addi sp, sp, 16 - // CHECK: ret - *x -} - -#[unsafe(no_mangle)] -extern "C" fn call_packed(x: &Packed) { - // CHECK: addi sp, sp, -16 - // CHECK-NEXT: .cfi_def_cfa_offset 16 - // CHECK-NEXT: lbu [[BYTE2:.*]], 2(a0) - // CHECK-NEXT: lbu [[BYTE1:.*]], 1(a0) - // CHECK-NEXT: lbu [[BYTE3:.*]], 3(a0) - // CHECK-NEXT: lbu [[BYTE4:.*]], 4(a0) - // CHECK-NEXT: slli [[SHIFTED2:.*]], [[BYTE2]], 8 - // CHECK-NEXT: or [[BYTE12:.*]], [[SHIFTED2]], [[BYTE1]] - // CHECK-NEXT: slli [[SHIFTED3:.*]], [[BYTE3]], 16 - // CHECK-NEXT: slli [[SHIFTED4:.*]], [[BYTE4]], 24 - // CHECK-NEXT: or [[BYTE34:.*]], [[SHIFTED3]], [[SHIFTED4]] - // CHECK-NEXT: or [[VALUE:.*]], [[BYTE12]], [[BYTE34]] - // CHECK-NEXT: sw [[VALUE]], 8(sp) - // CHECK-NEXT: flw fa0, 8(sp) - // CHECK-NEXT: lbu a0, 0(a0) - // CHECK-NEXT: addi sp, sp, 16 - // CHECK: tail take_packed - unsafe { - take_packed(*x); - } -} - -#[unsafe(no_mangle)] -extern "C" fn receive_packed(out: &mut Packed) { - // CHECK: addi sp, sp, -32 - // CHECK-NEXT: .cfi_def_cfa_offset 32 - // CHECK-NEXT: sd ra, [[#%d,RA_SPILL:]](sp) - // CHECK-NEXT: sd [[TEMP:.*]], [[#%d,TEMP_SPILL:]](sp) - // CHECK-NEXT: .cfi_offset ra, [[#%d,RA_SPILL - 32]] - // CHECK-NEXT: .cfi_offset [[TEMP]], [[#%d,TEMP_SPILL - 32]] - // CHECK-NEXT: mv [[TEMP]], a0 - // CHECK-NEXT: call get_packed - // CHECK-NEXT: sb a0, 0([[TEMP]]) - // CHECK-NEXT: fsw fa0, [[FLOAT_SPILL:.*]](sp) - // CHECK-NEXT: lw [[VALUE:.*]], [[FLOAT_SPILL]](sp) - // CHECK-DAG: srli [[BYTE4:.*]], [[VALUE]], 24 - // CHECK-DAG: srli [[BYTE3:.*]], [[VALUE]], 16 - // CHECK-DAG: srli [[BYTE2:.*]], [[VALUE]], 8 - // CHECK-DAG: sb [[VALUE]], 1([[TEMP]]) - // CHECK-DAG: sb [[BYTE2]], 2([[TEMP]]) - // CHECK-DAG: sb [[BYTE3]], 3([[TEMP]]) - // CHECK-DAG: sb [[BYTE4]], 4([[TEMP]]) - // CHECK-NEXT: ld ra, [[#%d,RA_SPILL]](sp) - // CHECK-NEXT: ld [[TEMP]], [[#%d,TEMP_SPILL]](sp) - // CHECK: addi sp, sp, 32 - // CHECK: ret - unsafe { - *out = get_packed(); - } -} diff --git a/tests/assembly/riscv-soft-abi-with-float-features.rs b/tests/assembly/riscv-soft-abi-with-float-features.rs deleted file mode 100644 index 72cbd3841c1..00000000000 --- a/tests/assembly/riscv-soft-abi-with-float-features.rs +++ /dev/null @@ -1,45 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: --target riscv64imac-unknown-none-elf -Ctarget-feature=+f,+d -//@ needs-llvm-components: riscv -//@ revisions: LLVM-PRE-20 LLVM-POST-20 -//@ [LLVM-PRE-20] max-llvm-major-version: 19 -//@ [LLVM-POST-20] min-llvm-version: 20 - -#![feature(no_core, lang_items, f16)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -// This test checks that the floats are all returned in `a0` as required by the `lp64` ABI. - -// CHECK-LABEL: read_f16 -#[no_mangle] -pub extern "C" fn read_f16(x: &f16) -> f16 { - // CHECK: lh a0, 0(a0) - // CHECK-NEXT: lui a1, 1048560 - // CHECK-NEXT: or a0, a0, a1 - // CHECK-NEXT: ret - *x -} - -// CHECK-LABEL: read_f32 -#[no_mangle] -pub extern "C" fn read_f32(x: &f32) -> f32 { - // LLVM-PRE-20: flw fa5, 0(a0) - // LLVM-PRE-20-NEXT: fmv.x.w a0, fa5 - // LLVM-PRE-20-NEXT: ret - // LLVM-POST-20: lw a0, 0(a0) - // LLVM-POST-20-NEXT: ret - *x -} - -// CHECK-LABEL: read_f64 -#[no_mangle] -pub extern "C" fn read_f64(x: &f64) -> f64 { - // CHECK: ld a0, 0(a0) - // CHECK-NEXT: ret - *x -} diff --git a/tests/assembly/rust-abi-arg-attr.rs b/tests/assembly/rust-abi-arg-attr.rs deleted file mode 100644 index 4f3673ccfc3..00000000000 --- a/tests/assembly/rust-abi-arg-attr.rs +++ /dev/null @@ -1,110 +0,0 @@ -//@ assembly-output: emit-asm -//@ revisions: riscv64 riscv64-zbb loongarch64 -//@ compile-flags: -C opt-level=3 -//@ [riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu -//@ [riscv64] needs-llvm-components: riscv -//@ [riscv64-zbb] compile-flags: --target riscv64gc-unknown-linux-gnu -//@ [riscv64-zbb] compile-flags: -C target-feature=+zbb -//@ [riscv64-zbb] needs-llvm-components: riscv -//@ [loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu -//@ [loongarch64] needs-llvm-components: loongarch - -#![feature(no_core, lang_items, intrinsics, rustc_attrs)] -#![crate_type = "lib"] -#![no_std] -#![no_core] -// FIXME: Migrate these code after PR #130693 is landed. - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} - -#[lang = "copy"] -trait Copy {} - -impl Copy for i8 {} -impl Copy for u32 {} -impl Copy for i32 {} - -#[lang = "neg"] -trait Neg { - type Output; - - fn neg(self) -> Self::Output; -} - -impl Neg for i8 { - type Output = i8; - - fn neg(self) -> Self::Output { - -self - } -} - -#[lang = "Ordering"] -#[repr(i8)] -enum Ordering { - Less = -1, - Equal = 0, - Greater = 1, -} - -#[rustc_intrinsic] -fn three_way_compare(lhs: T, rhs: T) -> Ordering; - -// ^^^^^ core - -// Reimplementation of function `{integer}::max`. -macro_rules! max { - ($a:expr, $b:expr) => { - match three_way_compare($a, $b) { - Ordering::Less | Ordering::Equal => $b, - Ordering::Greater => $a, - } - }; -} - -#[no_mangle] -// CHECK-LABEL: issue_114508_u32: -pub fn issue_114508_u32(a: u32, b: u32) -> u32 { - // CHECK-NEXT: .cfi_startproc - - // riscv64-NEXT: bltu a1, a0, .[[RET:.+]] - // riscv64-NEXT: mv a0, a1 - // riscv64-NEXT: .[[RET]]: - - // riscv64-zbb-NEXT: maxu a0, a0, a1 - - // loongarch64-NEXT: sltu $a2, $a1, $a0 - // loongarch64-NEXT: masknez $a1, $a1, $a2 - // loongarch64-NEXT: maskeqz $a0, $a0, $a2 - // loongarch64-NEXT: or $a0, $a0, $a1 - - // CHECK-NEXT: ret - max!(a, b) -} - -#[no_mangle] -// CHECK-LABEL: issue_114508_i32: -pub fn issue_114508_i32(a: i32, b: i32) -> i32 { - // CHECK-NEXT: .cfi_startproc - - // riscv64-NEXT: blt a1, a0, .[[RET:.+]] - // riscv64-NEXT: mv a0, a1 - // riscv64-NEXT: .[[RET]]: - - // riscv64-zbb-NEXT: max a0, a0, a1 - - // loongarch64-NEXT: slt $a2, $a1, $a0 - // loongarch64-NEXT: masknez $a1, $a1, $a2 - // loongarch64-NEXT: maskeqz $a0, $a0, $a2 - // loongarch64-NEXT: or $a0, $a0, $a1 - - // CHECK-NEXT: ret - max!(a, b) -} diff --git a/tests/assembly/s390x-backchain-toggle.rs b/tests/assembly/s390x-backchain-toggle.rs deleted file mode 100644 index 9bae15b7d11..00000000000 --- a/tests/assembly/s390x-backchain-toggle.rs +++ /dev/null @@ -1,50 +0,0 @@ -//@ add-core-stubs -//@ revisions: enable-backchain disable-backchain default-backchain -//@ assembly-output: emit-asm -//@ compile-flags: -Copt-level=3 --crate-type=lib --target=s390x-unknown-linux-gnu -//@ needs-llvm-components: systemz -//@[enable-backchain] compile-flags: -Ctarget-feature=+backchain -//@[disable-backchain] compile-flags: -Ctarget-feature=-backchain -#![feature(no_core, lang_items)] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; - -extern "C" { - fn extern_func(); -} - -// CHECK-LABEL: test_backchain -#[no_mangle] -extern "C" fn test_backchain() -> i32 { - // Here we try to match if backchain register is saved to the parameter area (stored in r15/sp) - // And also if a new parameter area (160 bytes) is allocated for the upcoming function call - // enable-backchain: lgr [[REG1:.*]], %r15 - // enable-backchain-NEXT: aghi %r15, -160 - // enable-backchain: stg [[REG1]], 0(%r15) - // disable-backchain: aghi %r15, -160 - // disable-backchain-NOT: stg %r{{.*}}, 0(%r15) - // default-backchain: aghi %r15, -160 - // default-backchain-NOT: stg %r{{.*}}, 0(%r15) - unsafe { - extern_func(); - } - // enable-backchain-NEXT: brasl %r{{.*}}, extern_func@PLT - // disable-backchain: brasl %r{{.*}}, extern_func@PLT - - // Make sure that the expected return value is written into %r2 (return register): - // enable-backchain-NEXT: lghi %r2, 1 - // disable-backchain: lghi %r2, 0 - // default-backchain: lghi %r2, 0 - #[cfg(target_feature = "backchain")] - { - 1 - } - #[cfg(not(target_feature = "backchain"))] - { - 0 - } - // CHECK: br %r{{.*}} -} diff --git a/tests/assembly/s390x-vector-abi.rs b/tests/assembly/s390x-vector-abi.rs deleted file mode 100644 index fcf42664034..00000000000 --- a/tests/assembly/s390x-vector-abi.rs +++ /dev/null @@ -1,327 +0,0 @@ -//@ revisions: z10 z10_vector z13 z13_no_vector -// ignore-tidy-linelength -//@ assembly-output: emit-asm -//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled -//@[z10] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z10 --cfg no_vector -//@[z10] needs-llvm-components: systemz -//@[z10_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z10 -C target-feature=+vector -//@[z10_vector] needs-llvm-components: systemz -//@[z13] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -//@[z13] needs-llvm-components: systemz -//@[z13_no_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector --cfg no_vector -//@[z13_no_vector] needs-llvm-components: systemz - -#![feature(no_core, lang_items, repr_simd, s390x_target_feature)] -#![no_core] -#![crate_type = "lib"] -#![allow(non_camel_case_types)] -// Cases where vector feature is disabled are rejected. -// See tests/ui/simd-abi-checks-s390x.rs for test for them. - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} -#[lang = "copy"] -pub trait Copy {} -#[lang = "freeze"] -pub trait Freeze {} - -impl Copy for [T; N] {} - -#[lang = "phantom_data"] -pub struct PhantomData; -impl Copy for PhantomData {} - -#[repr(simd)] -pub struct i8x8([i8; 8]); -#[repr(simd)] -pub struct i8x16([i8; 16]); -#[repr(simd)] -pub struct i8x32([i8; 32]); -#[repr(C)] -pub struct Wrapper(T); -#[repr(C, align(16))] -pub struct WrapperAlign16(T); -#[repr(C)] -pub struct WrapperWithZst(T, PhantomData<()>); -#[repr(transparent)] -pub struct TransparentWrapper(T); - -impl Copy for i8 {} -impl Copy for i64 {} -impl Copy for i8x8 {} -impl Copy for i8x16 {} -impl Copy for i8x32 {} -impl Copy for Wrapper {} -impl Copy for WrapperAlign16 {} -impl Copy for WrapperWithZst {} -impl Copy for TransparentWrapper {} - -// CHECK-LABEL: vector_ret_small: -// CHECK: vlrepg %v24, 0(%r2) -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 { - *x -} -// CHECK-LABEL: vector_ret: -// CHECK: vl %v24, 0(%r2), 3 -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_ret(x: &i8x16) -> i8x16 { - *x -} -// CHECK-LABEL: vector_ret_large: -// z10: vl %v0, 16(%r3), 4 -// z10-NEXT: vl %v1, 0(%r3), 4 -// z10-NEXT: vst %v0, 16(%r2), 4 -// z10-NEXT: vst %v1, 0(%r2), 4 -// z10-NEXT: br %r14 -// z13: vl %v0, 0(%r3), 4 -// z13-NEXT: vl %v1, 16(%r3), 4 -// z13-NEXT: vst %v1, 16(%r2), 4 -// z13-NEXT: vst %v0, 0(%r2), 4 -// z13-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_ret_large(x: &i8x32) -> i8x32 { - *x -} - -// CHECK-LABEL: vector_wrapper_ret_small: -// CHECK: mvc 0(8,%r2), 0(%r3) -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_wrapper_ret_small(x: &Wrapper) -> Wrapper { - *x -} -// CHECK-LABEL: vector_wrapper_ret: -// CHECK: mvc 0(16,%r2), 0(%r3) -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_wrapper_ret(x: &Wrapper) -> Wrapper { - *x -} -// CHECK-LABEL: vector_wrapper_ret_large: -// z10: vl %v0, 16(%r3), 4 -// z10-NEXT: vl %v1, 0(%r3), 4 -// z10-NEXT: vst %v0, 16(%r2), 4 -// z10-NEXT: vst %v1, 0(%r2), 4 -// z10-NEXT: br %r14 -// z13: vl %v0, 16(%r3), 4 -// z13-NEXT: vst %v0, 16(%r2), 4 -// z13-NEXT: vl %v0, 0(%r3), 4 -// z13-NEXT: vst %v0, 0(%r2), 4 -// z13-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_wrapper_ret_large(x: &Wrapper) -> Wrapper { - *x -} - -// CHECK-LABEL: vector_wrapper_padding_ret: -// CHECK: mvc 0(16,%r2), 0(%r3) -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_wrapper_padding_ret(x: &WrapperAlign16) -> WrapperAlign16 { - *x -} - -// CHECK-LABEL: vector_wrapper_with_zst_ret_small: -// CHECK: mvc 0(8,%r2), 0(%r3) -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_wrapper_with_zst_ret_small( - x: &WrapperWithZst, -) -> WrapperWithZst { - *x -} -// CHECK-LABEL: vector_wrapper_with_zst_ret: -// CHECK: mvc 0(16,%r2), 0(%r3) -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_wrapper_with_zst_ret( - x: &WrapperWithZst, -) -> WrapperWithZst { - *x -} -// CHECK-LABEL: vector_wrapper_with_zst_ret_large: -// z10: vl %v0, 16(%r3), 4 -// z10-NEXT: vl %v1, 0(%r3), 4 -// z10-NEXT: vst %v0, 16(%r2), 4 -// z10-NEXT: vst %v1, 0(%r2), 4 -// z10-NEXT: br %r14 -// z13: vl %v0, 16(%r3), 4 -// z13-NEXT: vst %v0, 16(%r2), 4 -// z13-NEXT: vl %v0, 0(%r3), 4 -// z13-NEXT: vst %v0, 0(%r2), 4 -// z13-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_wrapper_with_zst_ret_large( - x: &WrapperWithZst, -) -> WrapperWithZst { - *x -} - -// CHECK-LABEL: vector_transparent_wrapper_ret_small: -// CHECK: vlrepg %v24, 0(%r2) -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_transparent_wrapper_ret_small( - x: &TransparentWrapper, -) -> TransparentWrapper { - *x -} -// CHECK-LABEL: vector_transparent_wrapper_ret: -// CHECK: vl %v24, 0(%r2), 3 -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_transparent_wrapper_ret( - x: &TransparentWrapper, -) -> TransparentWrapper { - *x -} -// CHECK-LABEL: vector_transparent_wrapper_ret_large: -// z10: vl %v0, 16(%r3), 4 -// z10-NEXT: vl %v1, 0(%r3), 4 -// z10-NEXT: vst %v0, 16(%r2), 4 -// z10-NEXT: vst %v1, 0(%r2), 4 -// z10-NEXT: br %r14 -// z13: vl %v0, 0(%r3), 4 -// z13-NEXT: vl %v1, 16(%r3), 4 -// z13-NEXT: vst %v1, 16(%r2), 4 -// z13-NEXT: vst %v0, 0(%r2), 4 -// z13-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_transparent_wrapper_ret_large( - x: &TransparentWrapper, -) -> TransparentWrapper { - *x -} - -// CHECK-LABEL: vector_arg_small: -// CHECK: vlgvg %r2, %v24, 0 -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_arg_small(x: i8x8) -> i64 { - unsafe { *(&x as *const i8x8 as *const i64) } -} -// CHECK-LABEL: vector_arg: -// CHECK: vlgvg %r2, %v24, 0 -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_arg(x: i8x16) -> i64 { - unsafe { *(&x as *const i8x16 as *const i64) } -} -// CHECK-LABEL: vector_arg_large: -// CHECK: lg %r2, 0(%r2) -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_arg_large(x: i8x32) -> i64 { - unsafe { *(&x as *const i8x32 as *const i64) } -} - -// CHECK-LABEL: vector_wrapper_arg_small: -// CHECK: vlgvg %r2, %v24, 0 -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_wrapper_arg_small(x: Wrapper) -> i64 { - unsafe { *(&x as *const Wrapper as *const i64) } -} -// CHECK-LABEL: vector_wrapper_arg: -// CHECK: vlgvg %r2, %v24, 0 -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_wrapper_arg(x: Wrapper) -> i64 { - unsafe { *(&x as *const Wrapper as *const i64) } -} -// CHECK-LABEL: vector_wrapper_arg_large: -// CHECK: lg %r2, 0(%r2) -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_wrapper_arg_large(x: Wrapper) -> i64 { - unsafe { *(&x as *const Wrapper as *const i64) } -} - -// https://github.com/rust-lang/rust/pull/131586#discussion_r1837071121 -// CHECK-LABEL: vector_wrapper_padding_arg: -// CHECK: lg %r2, 0(%r2) -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_wrapper_padding_arg(x: WrapperAlign16) -> i64 { - unsafe { *(&x as *const WrapperAlign16 as *const i64) } -} - -// CHECK-LABEL: vector_wrapper_with_zst_arg_small: -// CHECK: .cfi_startproc -// CHECK-NOT: vlgvg -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_wrapper_with_zst_arg_small(x: WrapperWithZst) -> i64 { - unsafe { *(&x as *const WrapperWithZst as *const i64) } -} -// CHECK-LABEL: vector_wrapper_with_zst_arg: -// CHECK: lg %r2, 0(%r2) -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_wrapper_with_zst_arg(x: WrapperWithZst) -> i64 { - unsafe { *(&x as *const WrapperWithZst as *const i64) } -} -// CHECK-LABEL: vector_wrapper_with_zst_arg_large: -// CHECK: lg %r2, 0(%r2) -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_wrapper_with_zst_arg_large(x: WrapperWithZst) -> i64 { - unsafe { *(&x as *const WrapperWithZst as *const i64) } -} - -// CHECK-LABEL: vector_transparent_wrapper_arg_small: -// CHECK: vlgvg %r2, %v24, 0 -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper) -> i64 { - unsafe { *(&x as *const TransparentWrapper as *const i64) } -} -// CHECK-LABEL: vector_transparent_wrapper_arg: -// CHECK: vlgvg %r2, %v24, 0 -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper) -> i64 { - unsafe { *(&x as *const TransparentWrapper as *const i64) } -} -// CHECK-LABEL: vector_transparent_wrapper_arg_large: -// CHECK: lg %r2, 0(%r2) -// CHECK-NEXT: br %r14 -#[cfg_attr(no_vector, target_feature(enable = "vector"))] -#[no_mangle] -unsafe extern "C" fn vector_transparent_wrapper_arg_large(x: TransparentWrapper) -> i64 { - unsafe { *(&x as *const TransparentWrapper as *const i64) } -} diff --git a/tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs b/tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs deleted file mode 100644 index f9966a23446..00000000000 --- a/tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Verifies that KCFI arity indicator is emitted. -// -//@ add-core-stubs -//@ revisions: x86_64 -//@ assembly-output: emit-asm -//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu -Cllvm-args=-x86-asm-syntax=intel -Ctarget-feature=-crt-static -Cpanic=abort -Zsanitizer=kcfi -Zsanitizer-kcfi-arity -Copt-level=0 -//@ [x86_64] needs-llvm-components: x86 -//@ min-llvm-version: 21.0.0 - -#![crate_type = "lib"] -#![feature(no_core)] -#![no_core] - -extern crate minicore; - -unsafe extern "C" { - safe fn add(x: i32, y: i32) -> i32; -} - -pub fn add_one(x: i32) -> i32 { - // CHECK-LABEL: __cfi__{{.*}}7add_one{{.*}}: - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: mov ecx, 2628068948 - add(x, 1) -} - -pub fn add_two(x: i32, _y: i32) -> i32 { - // CHECK-LABEL: __cfi__{{.*}}7add_two{{.*}}: - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: mov edx, 2505940310 - add(x, 2) -} - -pub fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: __cfi__{{.*}}8do_twice{{.*}}: - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: nop - // CHECK-NEXT: mov edx, 653723426 - add(f(arg), f(arg)) -} diff --git a/tests/assembly/simd-bitmask.rs b/tests/assembly/simd-bitmask.rs deleted file mode 100644 index d3e20f6ae1a..00000000000 --- a/tests/assembly/simd-bitmask.rs +++ /dev/null @@ -1,147 +0,0 @@ -//@ add-core-stubs -//@ revisions: x86 x86-avx2 x86-avx512 aarch64 -//@ [x86] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel -//@ [x86] needs-llvm-components: x86 -//@ [x86-avx2] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel -//@ [x86-avx2] compile-flags: -C target-feature=+avx2 -//@ [x86-avx2] needs-llvm-components: x86 -//@ [x86-avx512] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel -//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq -//@ [x86-avx512] needs-llvm-components: x86 -//@ [aarch64] compile-flags: --target=aarch64-unknown-linux-gnu -//@ [aarch64] needs-llvm-components: aarch64 -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort - -#![feature(no_core, lang_items, repr_simd, intrinsics)] -#![no_core] -#![allow(non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -#[repr(simd)] -pub struct m8x16([i8; 16]); - -#[repr(simd)] -pub struct m8x64([i8; 64]); - -#[repr(simd)] -pub struct m32x4([i32; 4]); - -#[repr(simd)] -pub struct m64x2([i64; 2]); - -#[repr(simd)] -pub struct m64x4([i64; 4]); - -#[rustc_intrinsic] -unsafe fn simd_bitmask(mask: V) -> B; - -// CHECK-LABEL: bitmask_m8x16 -#[no_mangle] -pub unsafe extern "C" fn bitmask_m8x16(mask: m8x16) -> u16 { - // The simd_bitmask intrinsic already uses the most significant bit, so no shift is necessary. - // Note that x86 has no byte shift, llvm uses a word shift to move the least significant bit - // of each byte into the right position. - // - // x86-NOT: psllw - // x86: movmskb eax, xmm0 - // - // x86-avx2-NOT: vpsllw - // x86-avx2: vpmovmskb eax, xmm0 - // - // x86-avx512-NOT: vpsllw xmm0 - // x86-avx512: vpmovmskb eax, xmm0 - // - // aarch64: adrp - // aarch64-NEXT: cmlt - // aarch64-NEXT: ldr - // aarch64-NEXT: and - // aarch64-NEXT: ext - // aarch64-NEXT: zip1 - // aarch64-NEXT: addv - // aarch64-NEXT: fmov - simd_bitmask(mask) -} - -// x86-avx512-LABEL: bitmask_m8x64 -#[no_mangle] -#[cfg(x86_avx512)] -pub unsafe extern "C" fn bitmask_m8x64(mask: m8x64) -> u64 { - // The simd_bitmask intrinsic already uses the most significant bit, so no shift is necessary. - // Note that x86 has no byte shift, llvm uses a word shift to move the least significant bit - // of each byte into the right position. - // - // The parameter is a 512 bit vector which in the C abi is only valid for avx512 targets. - // - // x86-avx512-NOT: vpsllw - // x86-avx512: vpmovb2m k0, zmm0 - // x86-avx512: kmovq rax, k0 - simd_bitmask(mask) -} - -// CHECK-LABEL: bitmask_m32x4 -#[no_mangle] -pub unsafe extern "C" fn bitmask_m32x4(mask: m32x4) -> u8 { - // The simd_bitmask intrinsic already uses the most significant bit, so no shift is necessary. - // - // x86-NOT: psllq - // x86: movmskps eax, xmm0 - // - // x86-avx2-NOT: vpsllq - // x86-avx2: vmovmskps eax, xmm0 - // - // x86-avx512-NOT: vpsllq - // x86-avx512: vmovmskps eax, xmm0 - // - // aarch64: adrp - // aarch64-NEXT: cmlt - // aarch64-NEXT: ldr - // aarch64-NEXT: and - // aarch64-NEXT: addv - // aarch64-NEXT: fmov - // aarch64-NEXT: and - simd_bitmask(mask) -} - -// CHECK-LABEL: bitmask_m64x2 -#[no_mangle] -pub unsafe extern "C" fn bitmask_m64x2(mask: m64x2) -> u8 { - // The simd_bitmask intrinsic already uses the most significant bit, so no shift is necessary. - // - // x86-NOT: psllq - // x86: movmskpd eax, xmm0 - // - // x86-avx2-NOT: vpsllq - // x86-avx2: vmovmskpd eax, xmm0 - // - // x86-avx512-NOT: vpsllq - // x86-avx512: vmovmskpd eax, xmm0 - // - // aarch64: adrp - // aarch64-NEXT: cmlt - // aarch64-NEXT: ldr - // aarch64-NEXT: and - // aarch64-NEXT: addp - // aarch64-NEXT: fmov - // aarch64-NEXT: and - simd_bitmask(mask) -} - -// x86-avx2-LABEL: bitmask_m64x4 -// x86-avx512-LABEL: bitmask_m64x4 -#[no_mangle] -#[cfg(any(x86_avx2, x86_avx512))] -pub unsafe extern "C" fn bitmask_m64x4(mask: m64x4) -> u8 { - // The simd_bitmask intrinsic already uses the most significant bit, so no shift is necessary. - // - // The parameter is a 256 bit vector which in the C abi is only valid for avx/avx512 targets. - // - // x86-avx2-NOT: vpsllq - // x86-avx2: vmovmskpd eax, ymm0 - // - // x86-avx512-NOT: vpsllq - // x86-avx512: vmovmskpd eax, ymm0 - simd_bitmask(mask) -} diff --git a/tests/assembly/simd-intrinsic-gather.rs b/tests/assembly/simd-intrinsic-gather.rs deleted file mode 100644 index bcab0ba1cc0..00000000000 --- a/tests/assembly/simd-intrinsic-gather.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@ add-core-stubs -//@ revisions: x86-avx512 -//@ [x86-avx512] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel -//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq -//@ [x86-avx512] needs-llvm-components: x86 -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort - -#![feature(no_core, lang_items, repr_simd, intrinsics)] -#![no_core] -#![allow(non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -#[repr(simd)] -pub struct f64x4([f64; 4]); - -#[repr(simd)] -pub struct m64x4([i64; 4]); - -#[repr(simd)] -pub struct pf64x4([*const f64; 4]); - -#[rustc_intrinsic] -unsafe fn simd_gather(values: V, mask: M, pointer: P) -> V; - -// CHECK-LABEL: gather_f64x4 -#[no_mangle] -pub unsafe extern "C" fn gather_f64x4(mask: m64x4, ptrs: pf64x4) -> f64x4 { - // FIXME: This should also get checked to generate a gather instruction for avx2. - // Currently llvm scalarizes this code, see https://github.com/llvm/llvm-project/issues/59789 - // - // x86-avx512-NOT: vpsllq - // x86-avx512: vpmovq2m k1, ymm0 - // x86-avx512-NEXT: vpxor xmm0, xmm0, xmm0 - // x86-avx512-NEXT: vgatherqpd ymm0 {k1}, {{(ymmword)|(qword)}} ptr [1*ymm1] - simd_gather(f64x4([0_f64, 0_f64, 0_f64, 0_f64]), ptrs, mask) -} diff --git a/tests/assembly/simd-intrinsic-mask-load.rs b/tests/assembly/simd-intrinsic-mask-load.rs deleted file mode 100644 index d3f3453a780..00000000000 --- a/tests/assembly/simd-intrinsic-mask-load.rs +++ /dev/null @@ -1,83 +0,0 @@ -//@ add-core-stubs -//@ revisions: x86-avx2 x86-avx512 -//@ [x86-avx2] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel -//@ [x86-avx2] compile-flags: -C target-feature=+avx2 -//@ [x86-avx2] needs-llvm-components: x86 -//@ [x86-avx512] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel -//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq -//@ [x86-avx512] needs-llvm-components: x86 -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort - -#![feature(no_core, lang_items, repr_simd, intrinsics)] -#![no_core] -#![allow(non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -#[repr(simd)] -pub struct i8x16([i8; 16]); - -#[repr(simd)] -pub struct m8x16([i8; 16]); - -#[repr(simd)] -pub struct f32x8([f32; 8]); - -#[repr(simd)] -pub struct m32x8([i32; 8]); - -#[repr(simd)] -pub struct f64x4([f64; 4]); - -#[repr(simd)] -pub struct m64x4([i64; 4]); - -#[rustc_intrinsic] -unsafe fn simd_masked_load(mask: M, pointer: P, values: T) -> T; - -// CHECK-LABEL: load_i8x16 -#[no_mangle] -pub unsafe extern "C" fn load_i8x16(mask: m8x16, pointer: *const i8) -> i8x16 { - // Since avx2 supports no masked loads for bytes, the code tests each individual bit - // and jumps to code that inserts individual bytes. - // x86-avx2-NOT: vpsllw - // x86-avx2-DAG: vpmovmskb eax - // x86-avx2-DAG: vpxor - // x86-avx2-NEXT: test al, 1 - // x86-avx2-NEXT: jne - // x86-avx2-NEXT: test al, 2 - // x86-avx2-NEXT: jne - // x86-avx2-DAG: movzx [[REG:[a-z]+]], byte ptr [rdi] - // x86-avx2-NEXT: vmovd xmm0, [[REG]] - // x86-avx2-DAG: vpinsrb xmm0, xmm0, byte ptr [rdi + 1], 1 - // - // x86-avx512-NOT: vpsllw - // x86-avx512: vpmovb2m k1, xmm0 - // x86-avx512-NEXT: vmovdqu8 xmm0 {k1} {z}, xmmword ptr [rdi] - simd_masked_load(mask, pointer, i8x16([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) -} - -// CHECK-LABEL: load_f32x8 -#[no_mangle] -pub unsafe extern "C" fn load_f32x8(mask: m32x8, pointer: *const f32) -> f32x8 { - // x86-avx2-NOT: vpslld - // x86-avx2: vmaskmovps ymm0, ymm0, ymmword ptr [rdi] - // - // x86-avx512-NOT: vpslld - // x86-avx512: vpmovd2m k1, ymm0 - // x86-avx512-NEXT: vmovups ymm0 {k1} {z}, ymmword ptr [rdi] - simd_masked_load(mask, pointer, f32x8([0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32])) -} - -// CHECK-LABEL: load_f64x4 -#[no_mangle] -pub unsafe extern "C" fn load_f64x4(mask: m64x4, pointer: *const f64) -> f64x4 { - // x86-avx2-NOT: vpsllq - // x86-avx2: vmaskmovpd ymm0, ymm0, ymmword ptr [rdi] - // - // x86-avx512-NOT: vpsllq - // x86-avx512: vpmovq2m k1, ymm0 - simd_masked_load(mask, pointer, f64x4([0_f64, 0_f64, 0_f64, 0_f64])) -} diff --git a/tests/assembly/simd-intrinsic-mask-reduce.rs b/tests/assembly/simd-intrinsic-mask-reduce.rs deleted file mode 100644 index 8b15ed0a254..00000000000 --- a/tests/assembly/simd-intrinsic-mask-reduce.rs +++ /dev/null @@ -1,59 +0,0 @@ -// verify that simd mask reductions do not introduce additional bit shift operations -//@ add-core-stubs -//@ revisions: x86 aarch64 -//@ [x86] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel -// Set the base cpu explicitly, in case the default has been changed. -//@ [x86] compile-flags: -C target-cpu=x86-64 -//@ [x86] needs-llvm-components: x86 -//@ [aarch64] compile-flags: --target=aarch64-unknown-linux-gnu -//@ [aarch64] needs-llvm-components: aarch64 -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort - -#![feature(no_core, lang_items, repr_simd, intrinsics)] -#![no_core] -#![allow(non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -#[repr(simd)] -pub struct mask8x16([i8; 16]); - -#[rustc_intrinsic] -unsafe fn simd_reduce_all(x: T) -> bool; -#[rustc_intrinsic] -unsafe fn simd_reduce_any(x: T) -> bool; - -// CHECK-LABEL: mask_reduce_all: -#[no_mangle] -pub unsafe extern "C" fn mask_reduce_all(m: mask8x16) -> bool { - // x86-NOT: psllw - // x86: pmovmskb eax, xmm0 - // x86-NEXT: {{cmp ax, -1|cmp eax, 65535|xor eax, 65535}} - // x86-NEXT: sete al - // - // aarch64-NOT: shl - // aarch64: cmge v0.16b, v0.16b, #0 - // aarch64-DAG: mov [[REG1:[a-z0-9]+]], #1 - // aarch64-DAG: umaxv b0, v0.16b - // aarch64-NEXT: fmov [[REG2:[a-z0-9]+]], s0 - // aarch64-NEXT: bic w0, [[REG1]], [[REG2]] - simd_reduce_all(m) -} - -// CHECK-LABEL: mask_reduce_any: -#[no_mangle] -pub unsafe extern "C" fn mask_reduce_any(m: mask8x16) -> bool { - // x86-NOT: psllw - // x86: pmovmskb - // x86-NEXT: test eax, eax - // x86-NEXT: setne al - // - // aarch64-NOT: shl - // aarch64: cmlt v0.16b, v0.16b, #0 - // aarch64-NEXT: umaxv b0, v0.16b - // aarch64-NEXT: fmov [[REG:[a-z0-9]+]], s0 - // aarch64-NEXT: and w0, [[REG]], #0x1 - simd_reduce_any(m) -} diff --git a/tests/assembly/simd-intrinsic-mask-store.rs b/tests/assembly/simd-intrinsic-mask-store.rs deleted file mode 100644 index 001762e5060..00000000000 --- a/tests/assembly/simd-intrinsic-mask-store.rs +++ /dev/null @@ -1,82 +0,0 @@ -//@ add-core-stubs -//@ revisions: x86-avx2 x86-avx512 -//@ [x86-avx2] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel -//@ [x86-avx2] compile-flags: -C target-feature=+avx2 -//@ [x86-avx2] needs-llvm-components: x86 -//@ [x86-avx512] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel -//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq -//@ [x86-avx512] needs-llvm-components: x86 -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort - -#![feature(no_core, lang_items, repr_simd, intrinsics)] -#![no_core] -#![allow(non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -#[repr(simd)] -pub struct i8x16([i8; 16]); - -#[repr(simd)] -pub struct m8x16([i8; 16]); - -#[repr(simd)] -pub struct f32x8([f32; 8]); - -#[repr(simd)] -pub struct m32x8([i32; 8]); - -#[repr(simd)] -pub struct f64x4([f64; 4]); - -#[repr(simd)] -pub struct m64x4([i64; 4]); - -#[rustc_intrinsic] -unsafe fn simd_masked_store(mask: M, pointer: P, values: T); - -// CHECK-LABEL: store_i8x16 -#[no_mangle] -pub unsafe extern "C" fn store_i8x16(mask: m8x16, pointer: *mut i8, value: i8x16) { - // Since avx2 supports no masked stores for bytes, the code tests each individual bit - // and jumps to code that extracts individual bytes to memory. - // x86-avx2-NOT: vpsllw - // x86-avx2: vpmovmskb eax, xmm0 - // x86-avx2-NEXT: test al, 1 - // x86-avx2-NEXT: jne - // x86-avx2-NEXT: test al, 2 - // x86-avx2-NEXT: jne - // x86-avx2-DAG: vpextrb byte ptr [rdi + 1], xmm1, 1 - // x86-avx2-DAG: vpextrb byte ptr [rdi], xmm1, 0 - // - // x86-avx512-NOT: vpsllw - // x86-avx512: vpmovb2m k1, xmm0 - // x86-avx512-NEXT: vmovdqu8 xmmword ptr [rdi] {k1}, xmm1 - simd_masked_store(mask, pointer, value) -} - -// CHECK-LABEL: store_f32x8 -#[no_mangle] -pub unsafe extern "C" fn store_f32x8(mask: m32x8, pointer: *mut f32, value: f32x8) { - // x86-avx2-NOT: vpslld - // x86-avx2: vmaskmovps ymmword ptr [rdi], ymm0, ymm1 - // - // x86-avx512-NOT: vpslld - // x86-avx512: vpmovd2m k1, ymm0 - // x86-avx512-NEXT: vmovups ymmword ptr [rdi] {k1}, ymm1 - simd_masked_store(mask, pointer, value) -} - -// CHECK-LABEL: store_f64x4 -#[no_mangle] -pub unsafe extern "C" fn store_f64x4(mask: m64x4, pointer: *mut f64, value: f64x4) { - // x86-avx2-NOT: vpsllq - // x86-avx2: vmaskmovpd ymmword ptr [rdi], ymm0, ymm1 - // - // x86-avx512-NOT: vpsllq - // x86-avx512: vpmovq2m k1, ymm0 - // x86-avx512-NEXT: vmovupd ymmword ptr [rdi] {k1}, ymm1 - simd_masked_store(mask, pointer, value) -} diff --git a/tests/assembly/simd-intrinsic-scatter.rs b/tests/assembly/simd-intrinsic-scatter.rs deleted file mode 100644 index d77dfad3546..00000000000 --- a/tests/assembly/simd-intrinsic-scatter.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@ add-core-stubs -//@ revisions: x86-avx512 -//@ [x86-avx512] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel -//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq -//@ [x86-avx512] needs-llvm-components: x86 -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort - -#![feature(no_core, lang_items, repr_simd, intrinsics)] -#![no_core] -#![allow(non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -#[repr(simd)] -pub struct f64x4([f64; 4]); - -#[repr(simd)] -pub struct m64x4([i64; 4]); - -#[repr(simd)] -pub struct pf64x4([*mut f64; 4]); - -#[rustc_intrinsic] -unsafe fn simd_scatter(values: V, pointer: P, mask: M); - -// CHECK-LABEL: scatter_f64x4 -#[no_mangle] -pub unsafe extern "C" fn scatter_f64x4(values: f64x4, ptrs: pf64x4, mask: m64x4) { - // x86-avx512-NOT: vpsllq - // x86-avx512: vpmovq2m k1, ymm2 - // x86-avx512-NEXT: vscatterqpd {{(ymmword)|(qword)}} ptr [1*ymm1] {k1}, ymm0 - simd_scatter(values, ptrs, mask) -} diff --git a/tests/assembly/simd-intrinsic-select.rs b/tests/assembly/simd-intrinsic-select.rs deleted file mode 100644 index e7c7b0db0d5..00000000000 --- a/tests/assembly/simd-intrinsic-select.rs +++ /dev/null @@ -1,128 +0,0 @@ -//@ add-core-stubs -//@ revisions: x86-avx2 x86-avx512 aarch64 -//@ [x86-avx2] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel -//@ [x86-avx2] compile-flags: -C target-feature=+avx2 -//@ [x86-avx2] needs-llvm-components: x86 -//@ [x86-avx512] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel -//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq -//@ [x86-avx512] needs-llvm-components: x86 -//@ [aarch64] compile-flags: --target=aarch64-unknown-linux-gnu -//@ [aarch64] needs-llvm-components: aarch64 -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort - -#![feature(no_core, lang_items, repr_simd, intrinsics)] -#![no_core] -#![allow(non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -#[repr(simd)] -pub struct i8x16([i8; 16]); - -#[repr(simd)] -pub struct m8x16([i8; 16]); - -#[repr(simd)] -pub struct f32x4([f32; 4]); - -#[repr(simd)] -pub struct m32x4([i32; 4]); - -#[repr(simd)] -pub struct f64x2([f64; 2]); - -#[repr(simd)] -pub struct m64x2([i64; 2]); - -#[repr(simd)] -pub struct f64x4([f64; 4]); - -#[repr(simd)] -pub struct m64x4([i64; 4]); - -#[repr(simd)] -pub struct f64x8([f64; 8]); - -#[repr(simd)] -pub struct m64x8([i64; 8]); - -#[rustc_intrinsic] -unsafe fn simd_select(mask: M, a: V, b: V) -> V; - -// CHECK-LABEL: select_i8x16 -#[no_mangle] -pub unsafe extern "C" fn select_i8x16(mask: m8x16, a: i8x16, b: i8x16) -> i8x16 { - // x86-avx2-NOT: vpsllw - // x86-avx2: vpblendvb xmm0, xmm2, xmm1, xmm0 - // - // x86-avx512-NOT: vpsllw - // x86-avx512: vpmovb2m k1, xmm0 - // x86-avx512-NEXT: vpblendmb xmm0 {k1}, xmm2, xmm1 - // - // aarch64-NOT: shl - // aarch64: cmlt v0.16b, v0.16b, #0 - // aarch64-NEXT: bsl v0.16b, v1.16b, v2.16b - simd_select(mask, a, b) -} - -// CHECK-LABEL: select_f32x4 -#[no_mangle] -pub unsafe extern "C" fn select_f32x4(mask: m32x4, a: f32x4, b: f32x4) -> f32x4 { - // x86-avx2-NOT: vpslld - // x86-avx2: vblendvps xmm0, xmm2, xmm1, xmm0 - // - // x86-avx512-NOT: vpslld - // x86-avx512: vpmovd2m k1, xmm0 - // x86-avx512-NEXT: vblendmps xmm0 {k1}, xmm2, xmm1 - // - // aarch64-NOT: shl - // aarch64: cmlt v0.4s, v0.4s, #0 - // aarch64-NEXT: bsl v0.16b, v1.16b, v2.16b - simd_select(mask, a, b) -} - -// CHECK-LABEL: select_f64x2 -#[no_mangle] -pub unsafe extern "C" fn select_f64x2(mask: m64x2, a: f64x2, b: f64x2) -> f64x2 { - // x86-avx2-NOT: vpsllq - // x86-avx2: vblendvpd xmm0, xmm2, xmm1, xmm0 - // - // x86-avx512-NOT: vpsllq - // x86-avx512: vpmovq2m k1, xmm0 - // x86-avx512-NEXT: vblendmpd xmm0 {k1}, xmm2, xmm1 - // - // aarch64-NOT: shl - // aarch64: cmlt v0.2d, v0.2d, #0 - // aarch64-NEXT: bsl v0.16b, v1.16b, v2.16b - simd_select(mask, a, b) -} - -// x86-avx2-LABEL: select_f64x4 -// x86-avx512-LABEL: select_f64x4 -#[no_mangle] -#[cfg(any(x86_avx2, x86_avx512))] -pub unsafe extern "C" fn select_f64x4(mask: m64x4, a: f64x4, b: f64x4) -> f64x4 { - // The parameter is a 256 bit vector which in the C abi is only valid for avx targets. - // - // x86-avx2-NOT: vpsllq - // x86-avx2: vblendvpd ymm0, ymm2, ymm1, ymm0 - // - // x86-avx512-NOT: vpsllq - // x86-avx512: vpmovq2m k1, ymm0 - // x86-avx512-NEXT: vblendmpd ymm0 {k1}, ymm2, ymm1 - simd_select(mask, a, b) -} - -// x86-avx512-LABEL: select_f64x8 -#[no_mangle] -#[cfg(x86_avx512)] -pub unsafe extern "C" fn select_f64x8(mask: m64x8, a: f64x8, b: f64x8) -> f64x8 { - // The parameter is a 256 bit vector which in the C abi is only valid for avx512 targets. - // - // x86-avx512-NOT: vpsllq - // x86-avx512: vpmovq2m k1, zmm0 - // x86-avx512-NEXT: vblendmpd zmm0 {k1}, zmm2, zmm1 - simd_select(mask, a, b) -} diff --git a/tests/assembly/simd/reduce-fadd-unordered.rs b/tests/assembly/simd/reduce-fadd-unordered.rs deleted file mode 100644 index e872826f6ef..00000000000 --- a/tests/assembly/simd/reduce-fadd-unordered.rs +++ /dev/null @@ -1,31 +0,0 @@ -//@ revisions: x86_64 aarch64 -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 - -//@[aarch64] only-aarch64 -//@[x86_64] only-x86_64 -//@[x86_64] compile-flags: -Ctarget-feature=+sse3 -//@ ignore-sgx Test incompatible with LVI mitigations -#![feature(portable_simd)] -#![feature(core_intrinsics)] -use std::intrinsics::simd as intrinsics; -use std::simd::*; -// Regression test for https://github.com/rust-lang/rust/issues/130028 -// This intrinsic produces much worse code if you use +0.0 instead of -0.0 because -// +0.0 isn't as easy to algebraically reassociate, even using LLVM's reassoc attribute! -// It would emit about an extra fadd, depending on the architecture. - -// CHECK-LABEL: reduce_fadd_negative_zero -pub unsafe fn reduce_fadd_negative_zero(v: f32x4) -> f32 { - // x86_64: addps - // x86_64-NEXT: movshdup - // x86_64-NEXT: addss - // x86_64-NOT: xorps - - // aarch64: faddp - // aarch64-NEXT: faddp - - // CHECK-NOT: {{f?}}add{{p?s*}} - // CHECK: ret - intrinsics::simd_reduce_add_unordered(v) -} diff --git a/tests/assembly/slice-is_ascii.rs b/tests/assembly/slice-is_ascii.rs deleted file mode 100644 index e53cd5160cf..00000000000 --- a/tests/assembly/slice-is_ascii.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@ revisions: WIN LIN -//@ [WIN] only-windows -//@ [LIN] only-linux -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 -C llvm-args=-x86-asm-syntax=intel -//@ only-x86_64 -//@ ignore-sgx - -#![feature(str_internals)] - -// CHECK-LABEL: is_ascii_simple_demo: -#[no_mangle] -pub fn is_ascii_simple_demo(bytes: &[u8]) -> bool { - // Linux (System V): pointer is rdi; length is rsi - // Windows: pointer is rcx; length is rdx. - - // CHECK-NOT: mov - // CHECK-NOT: test - // CHECK-NOT: cmp - - // CHECK: .[[LOOPHEAD:.+]]: - // CHECK-NEXT: mov [[TEMP:.+]], [[LEN:rsi|rdx]] - // CHECK-NEXT: sub [[LEN]], 1 - // CHECK-NEXT: jb .[[LOOPEXIT:.+]] - // CHECK-NEXT: cmp byte ptr [{{rdi|rcx}} + [[TEMP]] - 1], 0 - // CHECK-NEXT: jns .[[LOOPHEAD]] - - // CHECK-NEXT: .[[LOOPEXIT]]: - // CHECK-NEXT: test [[TEMP]], [[TEMP]] - // CHECK-NEXT: sete al - // CHECK-NEXT: ret - core::slice::is_ascii_simple(bytes) -} diff --git a/tests/assembly/small_data_threshold.rs b/tests/assembly/small_data_threshold.rs deleted file mode 100644 index 2abe8687d8b..00000000000 --- a/tests/assembly/small_data_threshold.rs +++ /dev/null @@ -1,98 +0,0 @@ -// Test for -Z small_data_threshold=... -//@ revisions: RISCV MIPS HEXAGON M68K -//@ assembly-output: emit-asm -//@ compile-flags: -Z small_data_threshold=4 -//@ [RISCV] compile-flags: --target=riscv32im-unknown-none-elf -//@ [RISCV] needs-llvm-components: riscv -//@ [MIPS] compile-flags: --target=mips-unknown-linux-uclibc -C relocation-model=static -//@ [MIPS] compile-flags: -C llvm-args=-mgpopt -C llvm-args=-mlocal-sdata -//@ [MIPS] compile-flags: -C target-feature=+noabicalls -//@ [MIPS] needs-llvm-components: mips -//@ [HEXAGON] compile-flags: --target=hexagon-unknown-linux-musl -C target-feature=+small-data -//@ [HEXAGON] compile-flags: -C llvm-args=--hexagon-statics-in-small-data -//@ [HEXAGON] needs-llvm-components: hexagon -//@ [M68K] compile-flags: --target=m68k-unknown-linux-gnu -//@ [M68K] needs-llvm-components: m68k - -#![feature(no_core, lang_items)] -#![no_std] -#![no_core] -#![crate_type = "lib"] - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} - -#[lang = "drop_in_place"] -fn drop_in_place(_: *mut T) {} - -#[used] -#[no_mangle] -// U is below the threshold, should be in sdata -static mut U: u16 = 123; - -#[used] -#[no_mangle] -// V is below the threshold, should be in sbss -static mut V: u16 = 0; - -#[used] -#[no_mangle] -// W is at the threshold, should be in sdata -static mut W: u32 = 123; - -#[used] -#[no_mangle] -// X is at the threshold, should be in sbss -static mut X: u32 = 0; - -#[used] -#[no_mangle] -// Y is over the threshold, should be in its own .data section -static mut Y: u64 = 123; - -#[used] -#[no_mangle] -// Z is over the threshold, should be in its own .bss section -static mut Z: u64 = 0; - -// Currently, only MIPS and RISCV successfully put any objects in the small data -// sections so the U/V/W/X tests are skipped on Hexagon and M68K - -// RISCV: .section .sdata -// RISCV-NOT: .section -// RISCV: U: -// RISCV: .section .sbss -// RISCV-NOT: .section -// RISCV: V: -// RISCV: .section .sdata -// RISCV-NOT: .section -// RISCV: W: -// RISCV: .section .sbss -// RISCV-NOT: .section -// RISCV: X: - -// MIPS: .section .sdata -// MIPS-NOT: .section -// MIPS: U: -// MIPS: .section .sbss -// MIPS-NOT: .section -// MIPS: V: -// MIPS: .section .sdata -// MIPS-NOT: .section -// MIPS: W: -// MIPS: .section .sbss -// MIPS-NOT: .section -// MIPS: X: - -// CHECK: .section .data.Y, -// CHECK-NOT: .section -// CHECK: Y: -// CHECK: .section .bss.Z, -// CHECK-NOT: .section -// CHECK: Z: diff --git a/tests/assembly/sparc-struct-abi.rs b/tests/assembly/sparc-struct-abi.rs deleted file mode 100644 index b1594428811..00000000000 --- a/tests/assembly/sparc-struct-abi.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Test SPARC64 ABI -// - float structure members are passes in floating point registers -// (#86163) - -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ needs-llvm-components: sparc -//@ compile-flags: --target=sparcv9-sun-solaris -Copt-level=3 -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[repr(C)] -pub struct Franta { - a: f32, - b: f32, - c: f32, - d: f32, -} - -// NB: due to delay slots the `ld` following the call is actually executed before the call. -#[no_mangle] -pub unsafe extern "C" fn callee(arg: Franta) { - // CHECK-LABEL: callee: - // CHECK: st %f3, [[PLACE_D:.*]] - // CHECK: st %f2, [[PLACE_C:.*]] - // CHECK: st %f1, [[PLACE_B:.*]] - // CHECK: st %f0, [[PLACE_A:.*]] - // CHECK: call tst_use - // CHECK-NEXT: ld [[PLACE_A]], %f1 - // CHECK: call tst_use - // CHECK-NEXT: ld [[PLACE_B]], %f1 - // CHECK: call tst_use - // CHECK-NEXT: ld [[PLACE_C]], %f1 - // CHECK: call tst_use - // CHECK-NEXT: ld [[PLACE_D]], %f1 - clobber(); - tst_use(arg.a); - tst_use(arg.b); - tst_use(arg.c); - tst_use(arg.d); - tail_call_avoidance_fn(); -} - -extern "C" { - fn opaque_callee(arg: Franta, intarg: i32); - fn tst_use(arg: f32); - fn clobber(); - // This exists so that post-https://reviews.llvm.org/D138741 LLVM doesn't - // tail-call away some of our assertions. - fn tail_call_avoidance_fn(); -} - -#[no_mangle] -pub unsafe extern "C" fn caller() { - // CHECK-LABEL: caller: - // CHECK: ld [{{.*}}], %f0 - // CHECK: ld [{{.*}}], %f1 - // CHECK: ld [{{.*}}], %f2 - // CHECK: ld [{{.*}}], %f3 - // CHECK: call opaque_callee - // CHECK: mov 3, %o2 - opaque_callee(Franta { a: 1.0, b: 2.0, c: 3.0, d: 4.0 }, 3); - tail_call_avoidance_fn(); -} diff --git a/tests/assembly/stack-probes.rs b/tests/assembly/stack-probes.rs deleted file mode 100644 index de245431f47..00000000000 --- a/tests/assembly/stack-probes.rs +++ /dev/null @@ -1,41 +0,0 @@ -//@ add-core-stubs -//@ revisions: x86_64 i686 aarch64 -//@ assembly-output: emit-asm -//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel -//@[x86_64] needs-llvm-components: x86 -//@[i686] compile-flags: --target i686-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel -//@[i686] needs-llvm-components: x86 -//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu -//@[aarch64] needs-llvm-components: aarch64 - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -// Check that inline-asm stack probes are generated correctly. -// To avoid making this test fragile to slight asm changes, -// we only check that the stack pointer is decremented by a page at a time, -// instead of matching the whole probe sequence. - -// CHECK-LABEL: small_stack_probe: -#[no_mangle] -pub fn small_stack_probe(x: u8, f: fn(&mut [u8; 8192])) { - // CHECK-NOT: __rust_probestack - // x86_64: sub rsp, 4096 - // i686: sub esp, 4096 - // aarch64: sub sp, sp, #1, lsl #12 - f(&mut [x; 8192]); -} - -// CHECK-LABEL: big_stack_probe: -#[no_mangle] -pub fn big_stack_probe(x: u8, f: fn(&[u8; 65536])) { - // CHECK-NOT: __rust_probestack - // x86_64: sub rsp, 4096 - // i686: sub esp, 4096 - // aarch64: sub sp, sp, #1, lsl #12 - f(&mut [x; 65536]); -} diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs deleted file mode 100644 index 3287e018b40..00000000000 --- a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs +++ /dev/null @@ -1,359 +0,0 @@ -//@ revisions: all strong basic none missing -//@ assembly-output: emit-asm -//@ only-windows -//@ only-msvc -//@ ignore-64bit 64-bit table based SEH has slightly different behaviors than classic SEH -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic -//@ [none] compile-flags: -Z stack-protector=none -//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled - -#![crate_type = "lib"] -#![allow(internal_features)] -#![feature(unsized_fn_params)] - -// CHECK-LABEL: emptyfn: -#[no_mangle] -pub fn emptyfn() { - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_char -#[no_mangle] -pub fn array_char(f: fn(*const char)) { - let a = ['c'; 1]; - let b = ['d'; 3]; - let c = ['e'; 15]; - - f(&a as *const _); - f(&b as *const _); - f(&c as *const _); - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_u8_1 -#[no_mangle] -pub fn array_u8_1(f: fn(*const u8)) { - let a = [0u8; 1]; - f(&a as *const _); - - // The 'strong' heuristic adds stack protection to functions with local - // array variables regardless of their size. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_u8_small: -#[no_mangle] -pub fn array_u8_small(f: fn(*const u8)) { - let a = [0u8; 2]; - let b = [0u8; 7]; - f(&a as *const _); - f(&b as *const _); - - // Small arrays do not lead to stack protection by the 'basic' heuristic. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_u8_large: -#[no_mangle] -pub fn array_u8_large(f: fn(*const u8)) { - let a = [0u8; 9]; - f(&a as *const _); - - // Since `a` is a byte array with size greater than 8, the basic heuristic - // will also protect this function. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -#[derive(Copy, Clone)] -pub struct ByteSizedNewtype(u8); - -// CHECK-LABEL: array_bytesizednewtype_9: -#[no_mangle] -pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { - let a = [ByteSizedNewtype(0); 9]; - f(&a as *const _); - - // Since `a` is a byte array in the LLVM output, the basic heuristic will - // also protect this function. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: local_var_addr_used_indirectly -#[no_mangle] -pub fn local_var_addr_used_indirectly(f: fn(bool)) { - let a = 5; - let a_addr = &a as *const _ as usize; - f(a_addr & 0x10 == 0); - - // This function takes the address of a local variable taken. Although this - // address is never used as a way to refer to stack memory, the `strong` - // heuristic adds stack smash protection. This is also the case in C++: - // ``` - // cat << EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk - // #include - // void f(void (*g)(bool)) { - // int32_t x; - // g((reinterpret_cast(&x) & 0x10U) == 0); - // } - // EOF - // ``` - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: local_string_addr_taken -#[no_mangle] -pub fn local_string_addr_taken(f: fn(&String)) { - let x = String::new(); - f(&x); - - // Taking the address of the local variable `x` leads to stack smash - // protection with the `strong` heuristic, but not with the `basic` - // heuristic. It does not matter that the reference is not mut. - // - // An interesting note is that a similar function in C++ *would* be - // protected by the `basic` heuristic, because `std::string` has a char - // array internally as a small object optimization: - // ``` - // cat < - // void f(void (*g)(const std::string&)) { - // std::string x; - // g(x); - // } - // EOF - // ``` - // - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -pub trait SelfByRef { - fn f(&self) -> i32; -} - -impl SelfByRef for i32 { - fn f(&self) -> i32 { - return self + 1; - } -} - -// CHECK-LABEL: local_var_addr_taken_used_locally_only -#[no_mangle] -pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) { - let x = factory(); - let g = x.f(); - sink(g); - - // Even though the local variable conceptually has its address taken, as - // it's passed by reference to the trait function, the use of the reference - // is easily inlined. There is therefore no stack smash protection even with - // the `strong` heuristic. - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -pub struct Gigastruct { - does: u64, - not: u64, - have: u64, - array: u64, - members: u64, -} - -// CHECK-LABEL: local_large_var_moved -#[no_mangle] -pub fn local_large_var_moved(f: fn(Gigastruct)) { - let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }; - f(x); - - // Even though the local variable conceptually doesn't have its address - // taken, it's so large that the "move" is implemented with a reference to a - // stack-local variable in the ABI. Consequently, this function *is* - // protected. This is also the case for rvalue-references in C++, - // regardless of struct size: - // ``` - // cat < - // #include - // void f(void (*g)(uint64_t&&)) { - // uint64_t x; - // g(std::move(x)); - // } - // EOF - // ``` - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: local_large_var_cloned -#[no_mangle] -pub fn local_large_var_cloned(f: fn(Gigastruct)) { - f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }); - - // A new instance of `Gigastruct` is passed to `f()`, without any apparent - // connection to this stack frame. Still, since instances of `Gigastruct` - // are sufficiently large, it is allocated in the caller stack frame and - // passed as a pointer. As such, this function is *also* protected, just - // like `local_large_var_moved`. This is also the case for pass-by-value - // of sufficiently large structs in C++: - // ``` - // cat < - // #include - // struct Gigastruct { uint64_t a, b, c, d, e; }; - // void f(void (*g)(Gigastruct)) { - // g(Gigastruct{}); - // } - // EOF - // ``` - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -extern "C" { - // A call to an external `alloca` function is *not* recognized as an - // `alloca(3)` operation. This function is a compiler built-in, as the - // man page explains. Clang translates it to an LLVM `alloca` - // instruction with a count argument, which is also what the LLVM stack - // protector heuristics looks for. The man page for `alloca(3)` details - // a way to avoid using the compiler built-in: pass a -std=c11 - // argument, *and* don't include . Though this leads to an - // external alloca() function being called, it doesn't lead to stack - // protection being included. It even fails with a linker error - // "undefined reference to `alloca'". Example: - // ``` - // cat< - // void * alloca(size_t); - // void f(void (*g)(void*)) { - // void * p = alloca(10); - // g(p); - // } - // int main() { return 0; } - // EOF - // ``` - // The following tests demonstrate that calls to an external `alloca` - // function in Rust also doesn't trigger stack protection. - - fn alloca(size: usize) -> *mut (); -} - -// CHECK-LABEL: alloca_small_compile_time_constant_arg -#[no_mangle] -pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { - f(unsafe { alloca(8) }); - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: alloca_large_compile_time_constant_arg -#[no_mangle] -pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { - f(unsafe { alloca(9) }); - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: alloca_dynamic_arg -#[no_mangle] -pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { - f(unsafe { alloca(n) }); - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// The question then is: in what ways can Rust code generate array-`alloca` -// LLVM instructions? This appears to only be generated by -// rustc_codegen_ssa::traits::Builder::array_alloca() through -// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT -// this is support for the "unsized locals" unstable feature: -// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html. - -// CHECK-LABEL: unsized_fn_param -#[no_mangle] -pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { - let n = if l { 1 } else { 2 }; - f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from - - // Even though slices are conceptually passed by-value both into this - // function and into `f()`, this is implemented with pass-by-reference - // using a suitably constructed fat-pointer (as if the functions - // accepted &[u8]). This function therefore doesn't need dynamic array - // alloca, and is therefore not protected by the `strong` or `basic` - // heuristics. - - // We should have a __security_check_cookie call in `all` and `strong` modes but - // LLVM does not support generating stack protectors in functions with funclet - // based EH personalities. - // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4 - // all-NOT: __security_check_cookie - // strong-NOT: __security_check_cookie - - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs deleted file mode 100644 index 9a3dabc74dd..00000000000 --- a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs +++ /dev/null @@ -1,366 +0,0 @@ -//@ revisions: all strong basic none missing -//@ assembly-output: emit-asm -//@ only-windows -//@ only-msvc -//@ ignore-32bit 64-bit table based SEH has slightly different behaviors than classic SEH -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic -//@ [none] compile-flags: -Z stack-protector=none -//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled - -#![crate_type = "lib"] -#![feature(unsized_fn_params)] - -// CHECK-LABEL: emptyfn: -#[no_mangle] -pub fn emptyfn() { - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_char -#[no_mangle] -pub fn array_char(f: fn(*const char)) { - let a = ['c'; 1]; - let b = ['d'; 3]; - let c = ['e'; 15]; - - f(&a as *const _); - f(&b as *const _); - f(&c as *const _); - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_u8_1 -#[no_mangle] -pub fn array_u8_1(f: fn(*const u8)) { - let a = [0u8; 1]; - f(&a as *const _); - - // The 'strong' heuristic adds stack protection to functions with local - // array variables regardless of their size. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_u8_small: -#[no_mangle] -pub fn array_u8_small(f: fn(*const u8)) { - let a = [0u8; 2]; - let b = [0u8; 7]; - f(&a as *const _); - f(&b as *const _); - - // Small arrays do not lead to stack protection by the 'basic' heuristic. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_u8_large: -#[no_mangle] -pub fn array_u8_large(f: fn(*const u8)) { - let a = [0u8; 9]; - f(&a as *const _); - - // Since `a` is a byte array with size greater than 8, the basic heuristic - // will also protect this function. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -#[derive(Copy, Clone)] -pub struct ByteSizedNewtype(u8); - -// CHECK-LABEL: array_bytesizednewtype_9: -#[no_mangle] -pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { - let a = [ByteSizedNewtype(0); 9]; - f(&a as *const _); - - // Since `a` is a byte array in the LLVM output, the basic heuristic will - // also protect this function. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: local_var_addr_used_indirectly -#[no_mangle] -pub fn local_var_addr_used_indirectly(f: fn(bool)) { - let a = 5; - let a_addr = &a as *const _ as usize; - f(a_addr & 0x10 == 0); - - // This function takes the address of a local variable taken. Although this - // address is never used as a way to refer to stack memory, the `strong` - // heuristic adds stack smash protection. This is also the case in C++: - // ``` - // cat << EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk - // #include - // void f(void (*g)(bool)) { - // int32_t x; - // g((reinterpret_cast(&x) & 0x10U) == 0); - // } - // EOF - // ``` - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: local_string_addr_taken -#[no_mangle] -pub fn local_string_addr_taken(f: fn(&String)) { - // CHECK-DAG: .seh_endprologue - let x = String::new(); - f(&x); - - // Taking the address of the local variable `x` leads to stack smash - // protection with the `strong` heuristic, but not with the `basic` - // heuristic. It does not matter that the reference is not mut. - // - // An interesting note is that a similar function in C++ *would* be - // protected by the `basic` heuristic, because `std::string` has a char - // array internally as a small object optimization: - // ``` - // cat < - // void f(void (*g)(const std::string&)) { - // std::string x; - // g(x); - // } - // EOF - // ``` - // - - // We should have a __security_check_cookie call in `all` and `strong` modes but - // LLVM does not support generating stack protectors in functions with funclet - // based EH personalities. - // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4 - // all-NOT: __security_check_cookie - // strong-NOT: __security_check_cookie - - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie - - // CHECK-DAG: .seh_endproc -} - -pub trait SelfByRef { - fn f(&self) -> i32; -} - -impl SelfByRef for i32 { - fn f(&self) -> i32 { - return self + 1; - } -} - -// CHECK-LABEL: local_var_addr_taken_used_locally_only -#[no_mangle] -pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) { - let x = factory(); - let g = x.f(); - sink(g); - - // Even though the local variable conceptually has its address taken, as - // it's passed by reference to the trait function, the use of the reference - // is easily inlined. There is therefore no stack smash protection even with - // the `strong` heuristic. - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -pub struct Gigastruct { - does: u64, - not: u64, - have: u64, - array: u64, - members: u64, -} - -// CHECK-LABEL: local_large_var_moved -#[no_mangle] -pub fn local_large_var_moved(f: fn(Gigastruct)) { - let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }; - f(x); - - // Even though the local variable conceptually doesn't have its address - // taken, it's so large that the "move" is implemented with a reference to a - // stack-local variable in the ABI. Consequently, this function *is* - // protected. This is also the case for rvalue-references in C++, - // regardless of struct size: - // ``` - // cat < - // #include - // void f(void (*g)(uint64_t&&)) { - // uint64_t x; - // g(std::move(x)); - // } - // EOF - // ``` - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: local_large_var_cloned -#[no_mangle] -pub fn local_large_var_cloned(f: fn(Gigastruct)) { - f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }); - - // A new instance of `Gigastruct` is passed to `f()`, without any apparent - // connection to this stack frame. Still, since instances of `Gigastruct` - // are sufficiently large, it is allocated in the caller stack frame and - // passed as a pointer. As such, this function is *also* protected, just - // like `local_large_var_moved`. This is also the case for pass-by-value - // of sufficiently large structs in C++: - // ``` - // cat < - // #include - // struct Gigastruct { uint64_t a, b, c, d, e; }; - // void f(void (*g)(Gigastruct)) { - // g(Gigastruct{}); - // } - // EOF - // ``` - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -extern "C" { - // A call to an external `alloca` function is *not* recognized as an - // `alloca(3)` operation. This function is a compiler built-in, as the - // man page explains. Clang translates it to an LLVM `alloca` - // instruction with a count argument, which is also what the LLVM stack - // protector heuristics looks for. The man page for `alloca(3)` details - // a way to avoid using the compiler built-in: pass a -std=c11 - // argument, *and* don't include . Though this leads to an - // external alloca() function being called, it doesn't lead to stack - // protection being included. It even fails with a linker error - // "undefined reference to `alloca'". Example: - // ``` - // cat< - // void * alloca(size_t); - // void f(void (*g)(void*)) { - // void * p = alloca(10); - // g(p); - // } - // int main() { return 0; } - // EOF - // ``` - // The following tests demonstrate that calls to an external `alloca` - // function in Rust also doesn't trigger stack protection. - - fn alloca(size: usize) -> *mut (); -} - -// CHECK-LABEL: alloca_small_compile_time_constant_arg -#[no_mangle] -pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { - f(unsafe { alloca(8) }); - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: alloca_large_compile_time_constant_arg -#[no_mangle] -pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { - f(unsafe { alloca(9) }); - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: alloca_dynamic_arg -#[no_mangle] -pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { - f(unsafe { alloca(n) }); - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// The question then is: in what ways can Rust code generate array-`alloca` -// LLVM instructions? This appears to only be generated by -// rustc_codegen_ssa::traits::Builder::array_alloca() through -// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT -// this is support for the "unsized locals" unstable feature: -// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html. - -// CHECK-LABEL: unsized_fn_param -#[no_mangle] -pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { - let n = if l { 1 } else { 2 }; - f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from - - // Even though slices are conceptually passed by-value both into this - // function and into `f()`, this is implemented with pass-by-reference - // using a suitably constructed fat-pointer (as if the functions - // accepted &[u8]). This function therefore doesn't need dynamic array - // alloca, and is therefore not protected by the `strong` or `basic` - // heuristics. - - // We should have a __security_check_cookie call in `all` and `strong` modes but - // LLVM does not support generating stack protectors in functions with funclet - // based EH personalities. - // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4 - // all-NOT: __security_check_cookie - // strong-NOT: __security_check_cookie - - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs deleted file mode 100644 index ae281cb95da..00000000000 --- a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs +++ /dev/null @@ -1,345 +0,0 @@ -//@ revisions: all strong basic none missing -//@ assembly-output: emit-asm -//@ ignore-apple slightly different policy on stack protection of arrays -//@ ignore-msvc stack check code uses different function names -//@ ignore-nvptx64 stack protector is not supported -//@ ignore-wasm32-bare -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic -//@ [none] compile-flags: -Z stack-protector=none -//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled - -// NOTE: the heuristics for stack smash protection inappropriately rely on types in LLVM IR, -// despite those types having no semantic meaning. This means that the `basic` and `strong` -// settings do not behave in a coherent way. This is a known issue in LLVM. -// See comments on https://github.com/rust-lang/rust/issues/114903. - -#![crate_type = "lib"] -#![allow(internal_features)] -#![feature(unsized_fn_params)] - -// CHECK-LABEL: emptyfn{{:|\[}} -#[no_mangle] -pub fn emptyfn() { - // all: __stack_chk_fail - // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: array_char{{:|\[}} -#[no_mangle] -pub fn array_char(f: fn(*const char)) { - let a = ['c'; 1]; - let b = ['d'; 3]; - let c = ['e'; 15]; - - f(&a as *const _); - f(&b as *const _); - f(&c as *const _); - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: array_u8_1{{:|\[}} -#[no_mangle] -pub fn array_u8_1(f: fn(*const u8)) { - let a = [0u8; 1]; - f(&a as *const _); - - // The 'strong' heuristic adds stack protection to functions with local - // array variables regardless of their size. - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: array_u8_small{{:|\[}} -#[no_mangle] -pub fn array_u8_small(f: fn(*const u8)) { - let a = [0u8; 2]; - let b = [0u8; 7]; - f(&a as *const _); - f(&b as *const _); - - // Small arrays do not lead to stack protection by the 'basic' heuristic. - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: array_u8_large{{:|\[}} -#[no_mangle] -pub fn array_u8_large(f: fn(*const u8)) { - let a = [0u8; 9]; - f(&a as *const _); - - // Since `a` is a byte array with size greater than 8, the basic heuristic - // will also protect this function. - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -#[derive(Copy, Clone)] -pub struct ByteSizedNewtype(u8); - -// CHECK-LABEL: array_bytesizednewtype_9{{:|\[}} -#[no_mangle] -pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { - let a = [ByteSizedNewtype(0); 9]; - f(&a as *const _); - - // Since `a` is a byte array in the LLVM output, the basic heuristic will - // also protect this function. - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: local_var_addr_used_indirectly{{:|\[}} -#[no_mangle] -pub fn local_var_addr_used_indirectly(f: fn(bool)) { - let a = 5; - let a_addr = &a as *const _ as usize; - f(a_addr & 0x10 == 0); - - // This function takes the address of a local variable taken. Although this - // address is never used as a way to refer to stack memory, the `strong` - // heuristic adds stack smash protection. This is also the case in C++: - // ``` - // cat << EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk - // #include - // void f(void (*g)(bool)) { - // int32_t x; - // g((reinterpret_cast(&x) & 0x10U) == 0); - // } - // EOF - // ``` - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: local_string_addr_taken{{:|\[}} -#[no_mangle] -pub fn local_string_addr_taken(f: fn(&String)) { - let x = String::new(); - f(&x); - - // Taking the address of the local variable `x` leads to stack smash - // protection. It does not matter that the reference is not mut. - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -pub trait SelfByRef { - fn f(&self) -> i32; -} - -impl SelfByRef for i32 { - fn f(&self) -> i32 { - return self + 1; - } -} - -// CHECK-LABEL: local_var_addr_taken_used_locally_only{{:|\[}} -#[no_mangle] -pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) { - let x = factory(); - let g = x.f(); - sink(g); - - // Even though the local variable conceptually has its address taken, as - // it's passed by reference to the trait function, the use of the reference - // is easily inlined. There is therefore no stack smash protection even with - // the `strong` heuristic. - - // all: __stack_chk_fail - // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -pub struct Gigastruct { - does: u64, - not: u64, - have: u64, - array: u64, - members: u64, -} - -// CHECK-LABEL: local_large_var_moved{{:|\[}} -#[no_mangle] -pub fn local_large_var_moved(f: fn(Gigastruct)) { - let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }; - f(x); - - // Even though the local variable conceptually doesn't have its address - // taken, it's so large that the "move" is implemented with a reference to a - // stack-local variable in the ABI. Consequently, this function *is* - // protected. This is also the case for rvalue-references in C++, - // regardless of struct size: - // ``` - // cat < - // #include - // void f(void (*g)(uint64_t&&)) { - // uint64_t x; - // g(std::move(x)); - // } - // EOF - // ``` - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: local_large_var_cloned{{:|\[}} -#[no_mangle] -pub fn local_large_var_cloned(f: fn(Gigastruct)) { - f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }); - - // A new instance of `Gigastruct` is passed to `f()`, without any apparent - // connection to this stack frame. Still, since instances of `Gigastruct` - // are sufficiently large, it is allocated in the caller stack frame and - // passed as a pointer. As such, this function is *also* protected, just - // like `local_large_var_moved`. This is also the case for pass-by-value - // of sufficiently large structs in C++: - // ``` - // cat < - // #include - // struct Gigastruct { uint64_t a, b, c, d, e; }; - // void f(void (*g)(Gigastruct)) { - // g(Gigastruct{}); - // } - // EOF - // ``` - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -extern "C" { - // A call to an external `alloca` function is *not* recognized as an - // `alloca(3)` operation. This function is a compiler built-in, as the - // man page explains. Clang translates it to an LLVM `alloca` - // instruction with a count argument, which is also what the LLVM stack - // protector heuristics looks for. The man page for `alloca(3)` details - // a way to avoid using the compiler built-in: pass a -std=c11 - // argument, *and* don't include . Though this leads to an - // external alloca() function being called, it doesn't lead to stack - // protection being included. It even fails with a linker error - // "undefined reference to `alloca'". Example: - // ``` - // cat< - // void * alloca(size_t); - // void f(void (*g)(void*)) { - // void * p = alloca(10); - // g(p); - // } - // int main() { return 0; } - // EOF - // ``` - // The following tests demonstrate that calls to an external `alloca` - // function in Rust also doesn't trigger stack protection. - - fn alloca(size: usize) -> *mut (); -} - -// CHECK-LABEL: alloca_small_compile_time_constant_arg{{:|\[}} -#[no_mangle] -pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { - f(unsafe { alloca(8) }); - - // all: __stack_chk_fail - // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: alloca_large_compile_time_constant_arg{{:|\[}} -#[no_mangle] -pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { - f(unsafe { alloca(9) }); - - // all: __stack_chk_fail - // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: alloca_dynamic_arg{{:|\[}} -#[no_mangle] -pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { - f(unsafe { alloca(n) }); - - // all: __stack_chk_fail - // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// The question then is: in what ways can Rust code generate array-`alloca` -// LLVM instructions? This appears to only be generated by -// rustc_codegen_ssa::traits::Builder::array_alloca() through -// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT -// this is support for the "unsized locals" unstable feature: -// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html. - -// CHECK-LABEL: unsized_fn_param{{:|\[}} -#[no_mangle] -pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { - let n = if l { 1 } else { 2 }; - f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from - - // Even though slices are conceptually passed by-value both into this - // function and into `f()`, this is implemented with pass-by-reference - // using a suitably constructed fat-pointer (as if the functions - // accepted &[u8]). This function therefore doesn't need dynamic array - // alloca, and is therefore not protected by the `strong` or `basic` - // heuristics. - - // all: __stack_chk_fail - // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} diff --git a/tests/assembly/stack-protector/stack-protector-target-support.rs b/tests/assembly/stack-protector/stack-protector-target-support.rs deleted file mode 100644 index a937256a60f..00000000000 --- a/tests/assembly/stack-protector/stack-protector-target-support.rs +++ /dev/null @@ -1,281 +0,0 @@ -// Test that stack smash protection code is emitted for all tier1 and tier2 -// targets, with the exception of nvptx64-nvidia-cuda -// -//@ add-core-stubs -//@ revisions: r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 -//@ revisions: r24 r25 r26 r27 r28 r29 r30 r31 r32 r33 r36 r37 r38 r39 r40 r41 r42 r43 r44 -//@ revisions: r45 r46 r47 r48 r49 r50 r51 r52 r53 r54 r55 r56 r57 r58 r59 r60 r61 r62 r63 r64 r65 -//@ revisions: r66 r67 r68 r69 r70 r71 r72 r73 r74 r75 r76 r77 r78 r79 r80 r81 r82 r83 r84 r85 -//@ assembly-output: emit-asm -//@ [r1] compile-flags: --target aarch64-unknown-linux-gnu -//@ [r1] needs-llvm-components: aarch64 -//@ [r2] compile-flags: --target i686-pc-windows-gnu -//@ [r2] needs-llvm-components: x86 -//@ [r3] compile-flags: --target i686-pc-windows-msvc -//@ [r3] needs-llvm-components: x86 -//@ [r4] compile-flags: --target i686-unknown-linux-gnu -//@ [r4] needs-llvm-components: x86 -//@ [r5] compile-flags: --target x86_64-apple-darwin -//@ [r5] needs-llvm-components: x86 -//@ [r6] compile-flags: --target x86_64-pc-windows-gnu -//@ [r6] needs-llvm-components: x86 -//@ [r7] compile-flags: --target x86_64-pc-windows-msvc -//@ [r7] needs-llvm-components: x86 -//@ [r8] compile-flags: --target x86_64-unknown-linux-gnu -//@ [r8] needs-llvm-components: x86 -//@ [r9] compile-flags: --target aarch64-apple-darwin -//@ [r9] needs-llvm-components: aarch64 -//@ [r10] compile-flags: --target aarch64-apple-ios -//@ [r10] needs-llvm-components: aarch64 -//@ [r11] compile-flags: --target aarch64-unknown-fuchsia -//@ [r11] needs-llvm-components: aarch64 -//@ [r12] compile-flags: --target aarch64-linux-android -//@ [r12] needs-llvm-components: aarch64 -//@ [r13] compile-flags: --target aarch64-pc-windows-msvc -//@ [r13] needs-llvm-components: aarch64 -//@ [r14] compile-flags: --target aarch64-unknown-linux-musl -//@ [r14] needs-llvm-components: aarch64 -//@ [r15] compile-flags: --target aarch64-unknown-none -//@ [r15] needs-llvm-components: aarch64 -//@ [r16] compile-flags: --target aarch64-unknown-none-softfloat -//@ [r16] needs-llvm-components: aarch64 -//@ [r17] compile-flags: --target arm-linux-androideabi -//@ [r17] needs-llvm-components: arm -//@ [r18] compile-flags: --target arm-unknown-linux-gnueabi -//@ [r18] needs-llvm-components: arm -//@ [r19] compile-flags: --target arm-unknown-linux-gnueabihf -//@ [r19] needs-llvm-components: arm -//@ [r20] compile-flags: --target arm-unknown-linux-musleabi -//@ [r20] needs-llvm-components: arm -//@ [r21] compile-flags: --target arm-unknown-linux-musleabihf -//@ [r21] needs-llvm-components: arm -//@ [r22] compile-flags: --target armebv7r-none-eabi -//@ [r22] needs-llvm-components: arm -//@ [r23] compile-flags: --target armebv7r-none-eabihf -//@ [r23] needs-llvm-components: arm -//@ [r24] compile-flags: --target armv5te-unknown-linux-gnueabi -//@ [r24] needs-llvm-components: arm -//@ [r25] compile-flags: --target armv5te-unknown-linux-musleabi -//@ [r25] needs-llvm-components: arm -//@ [r26] compile-flags: --target armv7-linux-androideabi -//@ [r26] needs-llvm-components: arm -//@ [r27] compile-flags: --target armv7a-none-eabi -//@ [r27] needs-llvm-components: arm -//@ [r28] compile-flags: --target armv7r-none-eabi -//@ [r28] needs-llvm-components: arm -//@ [r29] compile-flags: --target armv7r-none-eabihf -//@ [r29] needs-llvm-components: arm -//@ [r30] compile-flags: --target armv7-unknown-linux-gnueabi -//@ [r30] needs-llvm-components: arm -//@ [r31] compile-flags: --target armv7-unknown-linux-gnueabihf -//@ [r31] needs-llvm-components: arm -//@ [r32] compile-flags: --target armv7-unknown-linux-musleabi -//@ [r32] needs-llvm-components: arm -//@ [r33] compile-flags: --target armv7-unknown-linux-musleabihf -//@ [r33] needs-llvm-components: arm -//@ [r36] compile-flags: --target i586-unknown-linux-gnu -//@ [r36] needs-llvm-components: x86 -//@ [r37] compile-flags: --target i586-unknown-linux-musl -//@ [r37] needs-llvm-components: x86 -//@ [r38] compile-flags: --target i686-linux-android -//@ [r38] needs-llvm-components: x86 -//@ [r39] compile-flags: --target i686-unknown-freebsd -//@ [r39] needs-llvm-components: x86 -//@ [r40] compile-flags: --target i686-unknown-linux-musl -//@ [r40] needs-llvm-components: x86 -//@ [r41] compile-flags: --target mips-unknown-linux-gnu -//@ [r41] needs-llvm-components: mips -//@ [r42] compile-flags: --target mips-unknown-linux-musl -//@ [r42] needs-llvm-components: mips -//@ [r43] compile-flags: --target mips64-unknown-linux-gnuabi64 -//@ [r43] needs-llvm-components: mips -//@ [r44] compile-flags: --target mips64-unknown-linux-muslabi64 -//@ [r44] needs-llvm-components: mips -//@ [r45] compile-flags: --target mips64el-unknown-linux-gnuabi64 -//@ [r45] needs-llvm-components: mips -//@ [r46] compile-flags: --target mips64el-unknown-linux-muslabi64 -//@ [r46] needs-llvm-components: mips -//@ [r47] compile-flags: --target mipsel-unknown-linux-gnu -//@ [r47] needs-llvm-components: mips -//@ [r48] compile-flags: --target mipsel-unknown-linux-musl -//@ [r48] needs-llvm-components: mips -//@ [r49] compile-flags: --target nvptx64-nvidia-cuda -//@ [r49] needs-llvm-components: nvptx -//@ [r50] compile-flags: --target powerpc-unknown-linux-gnu -//@ [r50] needs-llvm-components: powerpc -//@ [r51] compile-flags: --target powerpc64-unknown-linux-gnu -//@ [r51] needs-llvm-components: powerpc -//@ [r52] compile-flags: --target powerpc64le-unknown-linux-gnu -//@ [r52] needs-llvm-components: powerpc -//@ [r53] compile-flags: --target riscv32i-unknown-none-elf -//@ [r53] needs-llvm-components: riscv -//@ [r54] compile-flags: --target riscv32imac-unknown-none-elf -//@ [r54] needs-llvm-components: riscv -//@ [r55] compile-flags:--target riscv32imc-unknown-none-elf -//@ [r55] needs-llvm-components: riscv -//@ [r56] compile-flags:--target riscv64gc-unknown-linux-gnu -//@ [r56] needs-llvm-components: riscv -//@ [r57] compile-flags:--target riscv64gc-unknown-none-elf -//@ [r57] needs-llvm-components: riscv -//@ [r58] compile-flags:--target riscv64imac-unknown-none-elf -//@ [r58] needs-llvm-components: riscv -//@ [r59] compile-flags:--target s390x-unknown-linux-gnu -//@ [r59] needs-llvm-components: systemz -//@ [r60] compile-flags:--target sparc64-unknown-linux-gnu -//@ [r60] needs-llvm-components: sparc -//@ [r61] compile-flags:--target sparcv9-sun-solaris -//@ [r61] needs-llvm-components: sparc -//@ [r62] compile-flags:--target thumbv6m-none-eabi -//@ [r62] needs-llvm-components: arm -//@ [r63] compile-flags:--target thumbv7em-none-eabi -//@ [r63] needs-llvm-components: arm -//@ [r64] compile-flags:--target thumbv7em-none-eabihf -//@ [r64] needs-llvm-components: arm -//@ [r65] compile-flags:--target thumbv7m-none-eabi -//@ [r65] needs-llvm-components: arm -//@ [r66] compile-flags:--target thumbv7neon-linux-androideabi -//@ [r66] needs-llvm-components: arm -//@ [r67] compile-flags:--target thumbv7neon-unknown-linux-gnueabihf -//@ [r67] needs-llvm-components: arm -//@ [r68] compile-flags:--target thumbv8m.base-none-eabi -//@ [r68] needs-llvm-components: arm -//@ [r69] compile-flags:--target thumbv8m.main-none-eabi -//@ [r69] needs-llvm-components: arm -//@ [r70] compile-flags:--target thumbv8m.main-none-eabihf -//@ [r70] needs-llvm-components: arm -//@ [r71] compile-flags:--target wasm32-unknown-emscripten -//@ [r71] needs-llvm-components: webassembly -//@ [r72] compile-flags:--target wasm32-unknown-unknown -//@ [r72] needs-llvm-components: webassembly -//@ [r73] compile-flags:--target wasm32-wasip1 -//@ [r73] needs-llvm-components: webassembly -//@ [r74] compile-flags:--target wasm32-wasip1-threads -//@ [r74] needs-llvm-components: webassembly -//@ [r75] compile-flags:--target x86_64-apple-ios -//@ [r75] needs-llvm-components: x86 -//@ [r76] compile-flags:--target x86_64-fortanix-unknown-sgx -//@ [r76] needs-llvm-components: x86 -//@ [r77] compile-flags:--target x86_64-unknown-fuchsia -//@ [r77] needs-llvm-components: x86 -//@ [r78] compile-flags:--target x86_64-linux-android -//@ [r78] needs-llvm-components: x86 -//@ [r79] compile-flags:--target x86_64-pc-solaris -//@ [r79] needs-llvm-components: x86 -//@ [r80] compile-flags:--target x86_64-unknown-freebsd -//@ [r80] needs-llvm-components: x86 -//@ [r81] compile-flags:--target x86_64-unknown-illumos -//@ [r81] needs-llvm-components: x86 -//@ [r82] compile-flags:--target x86_64-unknown-linux-gnux32 -//@ [r82] needs-llvm-components: x86 -//@ [r83] compile-flags:--target x86_64-unknown-linux-musl -//@ [r83] needs-llvm-components: x86 -//@ [r84] compile-flags:--target x86_64-unknown-netbsd -//@ [r84] needs-llvm-components: x86 -//@ [r85] compile-flags: --target x86_64-unknown-redox -//@ [r85] needs-llvm-components: x86 -//@ compile-flags: -Z stack-protector=all -//@ compile-flags: -C opt-level=2 - -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[no_mangle] -pub fn foo() { - // CHECK: foo{{:|()}} - - // MSVC does the stack checking within a stack-check function: - // r3: calll @__security_check_cookie - // r7: callq __security_check_cookie - // r13: bl __security_check_cookie - - // cuda doesn't support stack-smash protection - // r49-NOT: __security_check_cookie - // r49-NOT: __stack_chk_fail - - // Other targets do stack checking within the function, and call a failure function on error - // r1: __stack_chk_fail - // r2: __stack_chk_fail - // r4: __stack_chk_fail - // r5: __stack_chk_fail - // r6: __stack_chk_fail - // r8: __stack_chk_fail - // r9: __stack_chk_fail - // r10: __stack_chk_fail - // r11: __stack_chk_fail - // r12: __stack_chk_fail - // r14: __stack_chk_fail - // r15: __stack_chk_fail - // r16: __stack_chk_fail - // r17: __stack_chk_fail - // r18: __stack_chk_fail - // r19: __stack_chk_fail - // r20: __stack_chk_fail - // r21: __stack_chk_fail - // r22: __stack_chk_fail - // r23: __stack_chk_fail - // r24: __stack_chk_fail - // r25: __stack_chk_fail - // r26: __stack_chk_fail - // r27: __stack_chk_fail - // r28: __stack_chk_fail - // r29: __stack_chk_fail - // r30: __stack_chk_fail - // r31: __stack_chk_fail - // r32: __stack_chk_fail - // r33: __stack_chk_fail - // r34: __stack_chk_fail - // r36: __stack_chk_fail - // r37: __stack_chk_fail - // r38: __stack_chk_fail - // r39: __stack_chk_fail - // r40: __stack_chk_fail - // r41: __stack_chk_fail - // r42: __stack_chk_fail - // r43: __stack_chk_fail - // r44: __stack_chk_fail - // r45: __stack_chk_fail - // r46: __stack_chk_fail - // r47: __stack_chk_fail - // r48: __stack_chk_fail - // r50: __stack_chk_fail - // r51: __stack_chk_fail - // r52: __stack_chk_fail - // r53: __stack_chk_fail - // r54: __stack_chk_fail - // r55: __stack_chk_fail - // r56: __stack_chk_fail - // r57: __stack_chk_fail - // r58: __stack_chk_fail - // r59: __stack_chk_fail - // r60: __stack_chk_fail - // r61: __stack_chk_fail - // r62: __stack_chk_fail - // r63: __stack_chk_fail - // r64: __stack_chk_fail - // r65: __stack_chk_fail - // r66: __stack_chk_fail - // r67: __stack_chk_fail - // r68: __stack_chk_fail - // r69: __stack_chk_fail - // r70: __stack_chk_fail - // r71: __stack_chk_fail - // r72: __stack_chk_fail - // r73: __stack_chk_fail - // r74: __stack_chk_fail - // r75: __stack_chk_fail - // r76: __stack_chk_fail - // r77: __stack_chk_fail - // r78: __stack_chk_fail - // r79: __stack_chk_fail - // r80: __stack_chk_fail - // r81: __stack_chk_fail - // r82: __stack_chk_fail - // r83: __stack_chk_fail - // r84: __stack_chk_fail - // r85: __stack_chk_fail -} diff --git a/tests/assembly/static-relocation-model.rs b/tests/assembly/static-relocation-model.rs deleted file mode 100644 index 35ad94133b2..00000000000 --- a/tests/assembly/static-relocation-model.rs +++ /dev/null @@ -1,69 +0,0 @@ -//@ add-core-stubs -//@ revisions: x64 A64 ppc64le -//@ assembly-output: emit-asm -//@ [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static -//@ [x64] needs-llvm-components: x86 -//@ [A64] compile-flags: --target aarch64-unknown-linux-gnu -Crelocation-model=static -//@ [A64] needs-llvm-components: aarch64 -//@ [ppc64le] compile-flags: --target powerpc64le-unknown-linux-gnu -Crelocation-model=static -//@ [ppc64le] needs-llvm-components: powerpc - -#![feature(no_core, lang_items)] -#![no_core] -#![crate_type = "rlib"] - -extern crate minicore; -use minicore::*; - -#[no_mangle] -pub static PIERIS: u8 = 42; - -extern "C" { - static EXOCHORDA: *mut u8; - - fn chaenomeles(); -} - -// CHECK-LABEL: banana: -// LLVM may produce either kind of `mov` here, depending on version and optimization level. -// x64: {{movb|movzbl}} chaenomeles{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} -// A64: adrp [[REG:[a-z0-9]+]], chaenomeles -// A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG]], :lo12:chaenomeles] -#[no_mangle] -pub fn banana() -> u8 { - unsafe { *(chaenomeles as *mut u8) } -} - -// CHECK-LABEL: peach: -// x64: {{movb|movzbl}} banana{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} -// A64: adrp [[REG2:[a-z0-9]+]], banana -// A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:banana] -#[no_mangle] -pub fn peach() -> u8 { - unsafe { *(banana as *mut u8) } -} - -// CHECK-LABEL: mango: -// x64: movq EXOCHORDA{{(\(%[a-z0-9]+\))?}}, %[[REG:[a-z0-9]+]] -// x64-NEXT: {{movb|movzbl}} (%[[REG]]), %{{[a-z0-9]+}} -// A64: adrp [[REG2:[a-z0-9]+]], EXOCHORDA -// A64-NEXT: ldr {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:EXOCHORDA] -#[no_mangle] -pub fn mango() -> u8 { - unsafe { *EXOCHORDA } -} - -// CHECK-LABEL: orange: -// x64: mov{{l|absq}} $PIERIS, %{{[a-z0-9]+}} -// A64: adrp [[REG2:[a-z0-9]+]], PIERIS -// A64-NEXT: add {{[a-z0-9]+}}, [[REG2]], :lo12:PIERIS -#[no_mangle] -pub fn orange() -> &'static u8 { - &PIERIS -} - -// For ppc64 we need to make sure to generate TOC entries even with the static relocation model -// ppc64le: .tc chaenomeles[TC],chaenomeles -// ppc64le: .tc banana[TC],banana -// ppc64le: .tc EXOCHORDA[TC],EXOCHORDA -// ppc64le: .tc PIERIS[TC],PIERIS diff --git a/tests/assembly/strict_provenance.rs b/tests/assembly/strict_provenance.rs deleted file mode 100644 index 1a797670962..00000000000 --- a/tests/assembly/strict_provenance.rs +++ /dev/null @@ -1,37 +0,0 @@ -//@ assembly-output: emit-asm -//@ compile-flags: -Copt-level=1 -//@ only-x86_64 -//@ ignore-sgx -#![crate_type = "rlib"] - -// CHECK-LABEL: old_style -// CHECK: movq %{{.*}}, %rax -// CHECK: orq $1, %rax -// CHECK: retq -#[no_mangle] -pub fn old_style(a: *mut u8) -> *mut u8 { - (a as usize | 1) as *mut u8 -} - -// CHECK-LABEL: cheri_compat -// CHECK: movq %{{.*}}, %rax -// CHECK: orq $1, %rax -// CHECK: retq -#[no_mangle] -pub fn cheri_compat(a: *mut u8) -> *mut u8 { - let old = a as usize; - let new = old | 1; - let diff = new.wrapping_sub(old); - a.wrapping_add(diff) -} - -// CHECK-LABEL: definitely_not_a_null_pointer -// CHECK: movq %{{.*}}, %rax -// CHECK: orq $1, %rax -// CHECK: retq -#[no_mangle] -pub fn definitely_not_a_null_pointer(a: *mut u8) -> *mut u8 { - let old = a as usize; - let new = old | 1; - a.wrapping_sub(old).wrapping_add(new) -} diff --git a/tests/assembly/target-feature-multiple.rs b/tests/assembly/target-feature-multiple.rs deleted file mode 100644 index bc432d21931..00000000000 --- a/tests/assembly/target-feature-multiple.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ needs-llvm-components: x86 -//@ revisions: TWOFLAGS SINGLEFLAG -//@ compile-flags: --target=x86_64-unknown-linux-gnu -//@ [TWOFLAGS] compile-flags: -C target-feature=+rdrnd -C target-feature=+rdseed -//@ [SINGLEFLAG] compile-flags: -C target-feature=+rdrnd,+rdseed - -// Target features set via flags aren't necessarily reflected in the IR, so the only way to test -// them is to build code that requires the features to be enabled to work. -// -// In this particular test if `rdrnd,rdseed` somehow didn't make it to LLVM, the instruction -// selection should crash. -// -// > LLVM ERROR: Cannot select: 0x7f00f400c010: i32,i32,ch = X86ISD::RDSEED 0x7f00f400bfa8:2 -// > In function: foo -// -// See also tests/codegen/target-feature-overrides.rs -#![feature(no_core, lang_items, link_llvm_intrinsics, abi_unadjusted)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -// Use of these requires target features to be enabled -extern "unadjusted" { - #[link_name = "llvm.x86.rdrand.32"] - fn x86_rdrand32_step() -> (u32, i32); - #[link_name = "llvm.x86.rdseed.32"] - fn x86_rdseed32_step() -> (u32, i32); -} - -#[no_mangle] -pub unsafe fn foo() -> (u32, u32) { - // CHECK-LABEL: foo: - // CHECK: rdrand - // CHECK: rdseed - (x86_rdrand32_step().0, x86_rdseed32_step().0) -} diff --git a/tests/assembly/targets/targets-amdgpu.rs b/tests/assembly/targets/targets-amdgpu.rs deleted file mode 100644 index 1d10b8fc315..00000000000 --- a/tests/assembly/targets/targets-amdgpu.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -// ignore-tidy-linelength -//@ revisions: amdgcn_amd_amdhsa -//@ [amdgcn_amd_amdhsa] compile-flags: --target amdgcn-amd-amdhsa -Ctarget-cpu=gfx900 -//@ [amdgcn_amd_amdhsa] needs-llvm-components: amdgpu - -// Sanity-check that each target can produce assembly code. - -#![feature(no_core, lang_items)] -#![no_std] -#![no_core] -#![crate_type = "lib"] - -extern crate minicore; -use minicore::*; - -pub fn test() -> u8 { - 42 -} - -// CHECK: .version diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs deleted file mode 100644 index edf16548e7d..00000000000 --- a/tests/assembly/targets/targets-elf.rs +++ /dev/null @@ -1,734 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -// ignore-tidy-linelength -//@ revisions: aarch64_be_unknown_linux_gnu -//@ [aarch64_be_unknown_linux_gnu] compile-flags: --target aarch64_be-unknown-linux-gnu -//@ [aarch64_be_unknown_linux_gnu] needs-llvm-components: aarch64 -//@ revisions: aarch64_be_unknown_linux_gnu_ilp32 -//@ [aarch64_be_unknown_linux_gnu_ilp32] compile-flags: --target aarch64_be-unknown-linux-gnu_ilp32 -//@ [aarch64_be_unknown_linux_gnu_ilp32] needs-llvm-components: aarch64 -//@ revisions: aarch64_be_unknown_netbsd -//@ [aarch64_be_unknown_netbsd] compile-flags: --target aarch64_be-unknown-netbsd -//@ [aarch64_be_unknown_netbsd] needs-llvm-components: aarch64 -//@ revisions: aarch64_kmc_solid_asp3 -//@ [aarch64_kmc_solid_asp3] compile-flags: --target aarch64-kmc-solid_asp3 -//@ [aarch64_kmc_solid_asp3] needs-llvm-components: aarch64 -//@ revisions: aarch64_linux_android -//@ [aarch64_linux_android] compile-flags: --target aarch64-linux-android -//@ [aarch64_linux_android] needs-llvm-components: aarch64 -//@ revisions: aarch64_nintendo_switch_freestanding -//@ [aarch64_nintendo_switch_freestanding] compile-flags: --target aarch64-nintendo-switch-freestanding -//@ [aarch64_nintendo_switch_freestanding] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_freebsd -//@ [aarch64_unknown_freebsd] compile-flags: --target aarch64-unknown-freebsd -//@ [aarch64_unknown_freebsd] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_fuchsia -//@ [aarch64_unknown_fuchsia] compile-flags: --target aarch64-unknown-fuchsia -//@ [aarch64_unknown_fuchsia] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_hermit -//@ [aarch64_unknown_hermit] compile-flags: --target aarch64-unknown-hermit -//@ [aarch64_unknown_hermit] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_illumos -//@ [aarch64_unknown_illumos] compile-flags: --target aarch64-unknown-illumos -//@ [aarch64_unknown_illumos] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_linux_gnu -//@ [aarch64_unknown_linux_gnu] compile-flags: --target aarch64-unknown-linux-gnu -//@ [aarch64_unknown_linux_gnu] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_linux_gnu_ilp32 -//@ [aarch64_unknown_linux_gnu_ilp32] compile-flags: --target aarch64-unknown-linux-gnu_ilp32 -//@ [aarch64_unknown_linux_gnu_ilp32] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_linux_musl -//@ [aarch64_unknown_linux_musl] compile-flags: --target aarch64-unknown-linux-musl -//@ [aarch64_unknown_linux_musl] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_linux_ohos -//@ [aarch64_unknown_linux_ohos] compile-flags: --target aarch64-unknown-linux-ohos -//@ [aarch64_unknown_linux_ohos] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_netbsd -//@ [aarch64_unknown_netbsd] compile-flags: --target aarch64-unknown-netbsd -//@ [aarch64_unknown_netbsd] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_none -//@ [aarch64_unknown_none] compile-flags: --target aarch64-unknown-none -//@ [aarch64_unknown_none] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_none_softfloat -//@ [aarch64_unknown_none_softfloat] compile-flags: --target aarch64-unknown-none-softfloat -//@ [aarch64_unknown_none_softfloat] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_nto_qnx700 -//@ [aarch64_unknown_nto_qnx700] compile-flags: --target aarch64-unknown-nto-qnx700 -//@ [aarch64_unknown_nto_qnx700] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_nto_qnx710 -//@ [aarch64_unknown_nto_qnx710] compile-flags: --target aarch64-unknown-nto-qnx710 -//@ [aarch64_unknown_nto_qnx710] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_nto_qnx710_iosock -//@ [aarch64_unknown_nto_qnx710_iosock] compile-flags: --target aarch64-unknown-nto-qnx710_iosock -//@ [aarch64_unknown_nto_qnx710_iosock] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_nto_qnx800 -//@ [aarch64_unknown_nto_qnx800] compile-flags: --target aarch64-unknown-nto-qnx800 -//@ [aarch64_unknown_nto_qnx800] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_openbsd -//@ [aarch64_unknown_openbsd] compile-flags: --target aarch64-unknown-openbsd -//@ [aarch64_unknown_openbsd] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_redox -//@ [aarch64_unknown_redox] compile-flags: --target aarch64-unknown-redox -//@ [aarch64_unknown_redox] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_teeos -//@ [aarch64_unknown_teeos] compile-flags: --target aarch64-unknown-teeos -//@ [aarch64_unknown_teeos] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_nuttx -//@ [aarch64_unknown_nuttx] compile-flags: --target aarch64-unknown-nuttx -//@ [aarch64_unknown_nuttx] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_trusty -//@ [aarch64_unknown_trusty] compile-flags: --target aarch64-unknown-trusty -//@ [aarch64_unknown_trusty] needs-llvm-components: aarch64 -//@ revisions: aarch64_wrs_vxworks -//@ [aarch64_wrs_vxworks] compile-flags: --target aarch64-wrs-vxworks -//@ [aarch64_wrs_vxworks] needs-llvm-components: aarch64 -//@ revisions: arm_linux_androideabi -//@ [arm_linux_androideabi] compile-flags: --target arm-linux-androideabi -//@ [arm_linux_androideabi] needs-llvm-components: arm -//@ revisions: arm_unknown_linux_gnueabi -//@ [arm_unknown_linux_gnueabi] compile-flags: --target arm-unknown-linux-gnueabi -//@ [arm_unknown_linux_gnueabi] needs-llvm-components: arm -//@ revisions: arm_unknown_linux_gnueabihf -//@ [arm_unknown_linux_gnueabihf] compile-flags: --target arm-unknown-linux-gnueabihf -//@ [arm_unknown_linux_gnueabihf] needs-llvm-components: arm -//@ revisions: arm_unknown_linux_musleabi -//@ [arm_unknown_linux_musleabi] compile-flags: --target arm-unknown-linux-musleabi -//@ [arm_unknown_linux_musleabi] needs-llvm-components: arm -//@ revisions: arm_unknown_linux_musleabihf -//@ [arm_unknown_linux_musleabihf] compile-flags: --target arm-unknown-linux-musleabihf -//@ [arm_unknown_linux_musleabihf] needs-llvm-components: arm -//@ revisions: armeb_unknown_linux_gnueabi -//@ [armeb_unknown_linux_gnueabi] compile-flags: --target armeb-unknown-linux-gnueabi -//@ [armeb_unknown_linux_gnueabi] needs-llvm-components: arm -//@ revisions: armebv7r_none_eabi -//@ [armebv7r_none_eabi] compile-flags: --target armebv7r-none-eabi -//@ [armebv7r_none_eabi] needs-llvm-components: arm -//@ revisions: armebv7r_none_eabihf -//@ [armebv7r_none_eabihf] compile-flags: --target armebv7r-none-eabihf -//@ [armebv7r_none_eabihf] needs-llvm-components: arm -//@ revisions: armv4t_none_eabi -//@ [armv4t_none_eabi] compile-flags: --target armv4t-none-eabi -//@ [armv4t_none_eabi] needs-llvm-components: arm -//@ revisions: armv4t_unknown_linux_gnueabi -//@ [armv4t_unknown_linux_gnueabi] compile-flags: --target armv4t-unknown-linux-gnueabi -//@ [armv4t_unknown_linux_gnueabi] needs-llvm-components: arm -//@ revisions: armv5te_none_eabi -//@ [armv5te_none_eabi] compile-flags: --target armv5te-none-eabi -//@ [armv5te_none_eabi] needs-llvm-components: arm -//@ revisions: armv5te_unknown_linux_gnueabi -//@ [armv5te_unknown_linux_gnueabi] compile-flags: --target armv5te-unknown-linux-gnueabi -//@ [armv5te_unknown_linux_gnueabi] needs-llvm-components: arm -//@ revisions: armv5te_unknown_linux_musleabi -//@ [armv5te_unknown_linux_musleabi] compile-flags: --target armv5te-unknown-linux-musleabi -//@ [armv5te_unknown_linux_musleabi] needs-llvm-components: arm -//@ revisions: armv5te_unknown_linux_uclibceabi -//@ [armv5te_unknown_linux_uclibceabi] compile-flags: --target armv5te-unknown-linux-uclibceabi -//@ [armv5te_unknown_linux_uclibceabi] needs-llvm-components: arm -//@ revisions: armv6_unknown_freebsd -//@ [armv6_unknown_freebsd] compile-flags: --target armv6-unknown-freebsd -//@ [armv6_unknown_freebsd] needs-llvm-components: arm -//@ revisions: armv6_unknown_netbsd_eabihf -//@ [armv6_unknown_netbsd_eabihf] compile-flags: --target armv6-unknown-netbsd-eabihf -//@ [armv6_unknown_netbsd_eabihf] needs-llvm-components: arm -//@ revisions: armv6k_nintendo_3ds -//@ [armv6k_nintendo_3ds] compile-flags: --target armv6k-nintendo-3ds -//@ [armv6k_nintendo_3ds] needs-llvm-components: arm -//@ revisions: armv7_linux_androideabi -//@ [armv7_linux_androideabi] compile-flags: --target armv7-linux-androideabi -//@ [armv7_linux_androideabi] needs-llvm-components: arm -//@ revisions: armv7_rtems_eabihf -//@ [armv7_rtems_eabihf] compile-flags: --target armv7-rtems-eabihf -//@ [armv7_rtems_eabihf] needs-llvm-components: arm -//@ revisions: armv7_sony_vita_newlibeabihf -//@ [armv7_sony_vita_newlibeabihf] compile-flags: --target armv7-sony-vita-newlibeabihf -//@ [armv7_sony_vita_newlibeabihf] needs-llvm-components: arm -//@ revisions: armv7_unknown_freebsd -//@ [armv7_unknown_freebsd] compile-flags: --target armv7-unknown-freebsd -//@ [armv7_unknown_freebsd] needs-llvm-components: arm -//@ revisions: armv7_unknown_linux_gnueabi -//@ [armv7_unknown_linux_gnueabi] compile-flags: --target armv7-unknown-linux-gnueabi -//@ [armv7_unknown_linux_gnueabi] needs-llvm-components: arm -//@ revisions: armv7_unknown_linux_gnueabihf -//@ [armv7_unknown_linux_gnueabihf] compile-flags: --target armv7-unknown-linux-gnueabihf -//@ [armv7_unknown_linux_gnueabihf] needs-llvm-components: arm -//@ revisions: armv7_unknown_linux_musleabi -//@ [armv7_unknown_linux_musleabi] compile-flags: --target armv7-unknown-linux-musleabi -//@ [armv7_unknown_linux_musleabi] needs-llvm-components: arm -//@ revisions: armv7_unknown_linux_musleabihf -//@ [armv7_unknown_linux_musleabihf] compile-flags: --target armv7-unknown-linux-musleabihf -//@ [armv7_unknown_linux_musleabihf] needs-llvm-components: arm -//@ revisions: armv7_unknown_linux_ohos -//@ [armv7_unknown_linux_ohos] compile-flags: --target armv7-unknown-linux-ohos -//@ [armv7_unknown_linux_ohos] needs-llvm-components: arm -//@ revisions: armv7_unknown_linux_uclibceabi -//@ [armv7_unknown_linux_uclibceabi] compile-flags: --target armv7-unknown-linux-uclibceabi -//@ [armv7_unknown_linux_uclibceabi] needs-llvm-components: arm -//@ revisions: armv7_unknown_linux_uclibceabihf -//@ [armv7_unknown_linux_uclibceabihf] compile-flags: --target armv7-unknown-linux-uclibceabihf -//@ [armv7_unknown_linux_uclibceabihf] needs-llvm-components: arm -//@ revisions: armv7_unknown_netbsd_eabihf -//@ [armv7_unknown_netbsd_eabihf] compile-flags: --target armv7-unknown-netbsd-eabihf -//@ [armv7_unknown_netbsd_eabihf] needs-llvm-components: arm -//@ revisions: armv7_unknown_trusty -//@ [armv7_unknown_trusty] compile-flags: --target armv7-unknown-trusty -//@ [armv7_unknown_trusty] needs-llvm-components: arm -//@ revisions: armv7_wrs_vxworks_eabihf -//@ [armv7_wrs_vxworks_eabihf] compile-flags: --target armv7-wrs-vxworks-eabihf -//@ [armv7_wrs_vxworks_eabihf] needs-llvm-components: arm -//@ revisions: armv7a_kmc_solid_asp3_eabi -//@ [armv7a_kmc_solid_asp3_eabi] compile-flags: --target armv7a-kmc-solid_asp3-eabi -//@ [armv7a_kmc_solid_asp3_eabi] needs-llvm-components: arm -//@ revisions: armv7a_kmc_solid_asp3_eabihf -//@ [armv7a_kmc_solid_asp3_eabihf] compile-flags: --target armv7a-kmc-solid_asp3-eabihf -//@ [armv7a_kmc_solid_asp3_eabihf] needs-llvm-components: arm -//@ revisions: armv7a_none_eabi -//@ [armv7a_none_eabi] compile-flags: --target armv7a-none-eabi -//@ [armv7a_none_eabi] needs-llvm-components: arm -//@ revisions: armv7a_none_eabihf -//@ [armv7a_none_eabihf] compile-flags: --target armv7a-none-eabihf -//@ [armv7a_none_eabihf] needs-llvm-components: arm -//@ revisions: armv7a_nuttx_eabi -//@ [armv7a_nuttx_eabi] compile-flags: --target armv7a-nuttx-eabi -//@ [armv7a_nuttx_eabi] needs-llvm-components: arm -//@ revisions: armv7a_nuttx_eabihf -//@ [armv7a_nuttx_eabihf] compile-flags: --target armv7a-nuttx-eabihf -//@ [armv7a_nuttx_eabihf] needs-llvm-components: arm -//@ revisions: armv7r_none_eabi -//@ [armv7r_none_eabi] compile-flags: --target armv7r-none-eabi -//@ [armv7r_none_eabi] needs-llvm-components: arm -//@ revisions: armv7r_none_eabihf -//@ [armv7r_none_eabihf] compile-flags: --target armv7r-none-eabihf -//@ [armv7r_none_eabihf] needs-llvm-components: arm -//@ revisions: armv8r_none_eabihf -//@ [armv8r_none_eabihf] compile-flags: --target armv8r-none-eabihf -//@ [armv8r_none_eabihf] needs-llvm-components: arm -// FIXME: disabled since it fails on CI saying the csky component is missing -/* - revisions: csky_unknown_linux_gnuabiv2 - [csky_unknown_linux_gnuabiv2] compile-flags: --target csky-unknown-linux-gnuabiv2 - [csky_unknown_linux_gnuabiv2] needs-llvm-components: csky - revisions: csky_unknown_linux_gnuabiv2hf - [csky_unknown_linux_gnuabiv2hf] compile-flags: --target csky-unknown-linux-gnuabiv2hf - [csky_unknown_linux_gnuabiv2hf] needs-llvm-components: csky -*/ -//@ revisions: hexagon_unknown_linux_musl -//@ [hexagon_unknown_linux_musl] compile-flags: --target hexagon-unknown-linux-musl -//@ [hexagon_unknown_linux_musl] needs-llvm-components: hexagon -//@ revisions: hexagon_unknown_none_elf -//@ [hexagon_unknown_none_elf] compile-flags: --target hexagon-unknown-none-elf -//@ [hexagon_unknown_none_elf] needs-llvm-components: hexagon -//@ revisions: i686_pc_nto_qnx700 -//@ [i686_pc_nto_qnx700] compile-flags: --target i686-pc-nto-qnx700 -//@ [i686_pc_nto_qnx700] needs-llvm-components: x86 -//@ revisions: i586_unknown_linux_gnu -//@ [i586_unknown_linux_gnu] compile-flags: --target i586-unknown-linux-gnu -//@ [i586_unknown_linux_gnu] needs-llvm-components: x86 -//@ revisions: i586_unknown_linux_musl -//@ [i586_unknown_linux_musl] compile-flags: --target i586-unknown-linux-musl -//@ [i586_unknown_linux_musl] needs-llvm-components: x86 -//@ revisions: i586_unknown_netbsd -//@ [i586_unknown_netbsd] compile-flags: --target i586-unknown-netbsd -//@ [i586_unknown_netbsd] needs-llvm-components: x86 -//@ revisions: i586_unknown_redox -//@ [i586_unknown_redox] compile-flags: --target i586-unknown-redox -//@ [i586_unknown_redox] needs-llvm-components: x86 -//@ revisions: i686_linux_android -//@ [i686_linux_android] compile-flags: --target i686-linux-android -//@ [i686_linux_android] needs-llvm-components: x86 -//@ revisions: i686_unknown_freebsd -//@ [i686_unknown_freebsd] compile-flags: --target i686-unknown-freebsd -//@ [i686_unknown_freebsd] needs-llvm-components: x86 -//@ revisions: i686_unknown_haiku -//@ [i686_unknown_haiku] compile-flags: --target i686-unknown-haiku -//@ [i686_unknown_haiku] needs-llvm-components: x86 -//@ revisions: i686_unknown_hurd_gnu -//@ [i686_unknown_hurd_gnu] compile-flags: --target i686-unknown-hurd-gnu -//@ [i686_unknown_hurd_gnu] needs-llvm-components: x86 -//@ revisions: i686_unknown_linux_gnu -//@ [i686_unknown_linux_gnu] compile-flags: --target i686-unknown-linux-gnu -//@ [i686_unknown_linux_gnu] needs-llvm-components: x86 -//@ revisions: i686_unknown_linux_musl -//@ [i686_unknown_linux_musl] compile-flags: --target i686-unknown-linux-musl -//@ [i686_unknown_linux_musl] needs-llvm-components: x86 -//@ revisions: i686_unknown_netbsd -//@ [i686_unknown_netbsd] compile-flags: --target i686-unknown-netbsd -//@ [i686_unknown_netbsd] needs-llvm-components: x86 -//@ revisions: i686_unknown_openbsd -//@ [i686_unknown_openbsd] compile-flags: --target i686-unknown-openbsd -//@ [i686_unknown_openbsd] needs-llvm-components: x86 -//@ revisions: i686_wrs_vxworks -//@ [i686_wrs_vxworks] compile-flags: --target i686-wrs-vxworks -//@ [i686_wrs_vxworks] needs-llvm-components: x86 -//@ revisions: loongarch32_unknown_none -//@ [loongarch32_unknown_none] compile-flags: --target loongarch32-unknown-none -//@ [loongarch32_unknown_none] needs-llvm-components: loongarch -//@ revisions: loongarch32_unknown_none_softfloat -//@ [loongarch32_unknown_none_softfloat] compile-flags: --target loongarch32-unknown-none-softfloat -//@ [loongarch32_unknown_none_softfloat] needs-llvm-components: loongarch -//@ revisions: loongarch64_unknown_linux_gnu -//@ [loongarch64_unknown_linux_gnu] compile-flags: --target loongarch64-unknown-linux-gnu -//@ [loongarch64_unknown_linux_gnu] needs-llvm-components: loongarch -//@ revisions: loongarch64_unknown_linux_musl -//@ [loongarch64_unknown_linux_musl] compile-flags: --target loongarch64-unknown-linux-musl -//@ [loongarch64_unknown_linux_musl] needs-llvm-components: loongarch -//@ revisions: loongarch64_unknown_linux_ohos -//@ [loongarch64_unknown_linux_ohos] compile-flags: --target loongarch64-unknown-linux-ohos -//@ [loongarch64_unknown_linux_ohos] needs-llvm-components: loongarch -//@ revisions: loongarch64_unknown_none -//@ [loongarch64_unknown_none] compile-flags: --target loongarch64-unknown-none -//@ [loongarch64_unknown_none] needs-llvm-components: loongarch -//@ revisions: loongarch64_unknown_none_softfloat -//@ [loongarch64_unknown_none_softfloat] compile-flags: --target loongarch64-unknown-none-softfloat -//@ [loongarch64_unknown_none_softfloat] needs-llvm-components: loongarch -//@ revisions: m68k_unknown_linux_gnu -//@ [m68k_unknown_linux_gnu] compile-flags: --target m68k-unknown-linux-gnu -//@ [m68k_unknown_linux_gnu] needs-llvm-components: m68k -//@ revisions: m68k_unknown_none_elf -//@ [m68k_unknown_none_elf] compile-flags: --target m68k-unknown-none-elf -//@ [m68k_unknown_none_elf] needs-llvm-components: m68k -//@ revisions: mips64_openwrt_linux_musl -//@ [mips64_openwrt_linux_musl] compile-flags: --target mips64-openwrt-linux-musl -//@ [mips64_openwrt_linux_musl] needs-llvm-components: mips -//@ revisions: mips64_unknown_linux_gnuabi64 -//@ [mips64_unknown_linux_gnuabi64] compile-flags: --target mips64-unknown-linux-gnuabi64 -//@ [mips64_unknown_linux_gnuabi64] needs-llvm-components: mips -//@ revisions: mips64_unknown_linux_muslabi64 -//@ [mips64_unknown_linux_muslabi64] compile-flags: --target mips64-unknown-linux-muslabi64 -//@ [mips64_unknown_linux_muslabi64] needs-llvm-components: mips -//@ revisions: mips64el_unknown_linux_gnuabi64 -//@ [mips64el_unknown_linux_gnuabi64] compile-flags: --target mips64el-unknown-linux-gnuabi64 -//@ [mips64el_unknown_linux_gnuabi64] needs-llvm-components: mips -//@ revisions: mips64el_unknown_linux_muslabi64 -//@ [mips64el_unknown_linux_muslabi64] compile-flags: --target mips64el-unknown-linux-muslabi64 -//@ [mips64el_unknown_linux_muslabi64] needs-llvm-components: mips -//@ revisions: mips_unknown_linux_gnu -//@ [mips_unknown_linux_gnu] compile-flags: --target mips-unknown-linux-gnu -//@ [mips_unknown_linux_gnu] needs-llvm-components: mips -//@ revisions: mips_unknown_linux_musl -//@ [mips_unknown_linux_musl] compile-flags: --target mips-unknown-linux-musl -//@ [mips_unknown_linux_musl] needs-llvm-components: mips -//@ revisions: mips_unknown_linux_uclibc -//@ [mips_unknown_linux_uclibc] compile-flags: --target mips-unknown-linux-uclibc -//@ [mips_unknown_linux_uclibc] needs-llvm-components: mips -//@ revisions: mips_mti_none_elf -//@ [mips_mti_none_elf] compile-flags: --target mips-mti-none-elf -//@ [mips_mti_none_elf] needs-llvm-components: mips -//@ revisions: mipsel_mti_none_elf -//@ [mipsel_mti_none_elf] compile-flags: --target mipsel-mti-none-elf -//@ [mipsel_mti_none_elf] needs-llvm-components: mips -//@ revisions: mipsel_sony_psp -//@ [mipsel_sony_psp] compile-flags: --target mipsel-sony-psp -//@ [mipsel_sony_psp] needs-llvm-components: mips -//@ revisions: mipsel_sony_psx -//@ [mipsel_sony_psx] compile-flags: --target mipsel-sony-psx -//@ [mipsel_sony_psx] needs-llvm-components: mips -//@ revisions: mipsel_unknown_linux_gnu -//@ [mipsel_unknown_linux_gnu] compile-flags: --target mipsel-unknown-linux-gnu -//@ [mipsel_unknown_linux_gnu] needs-llvm-components: mips -//@ revisions: mipsel_unknown_linux_musl -//@ [mipsel_unknown_linux_musl] compile-flags: --target mipsel-unknown-linux-musl -//@ [mipsel_unknown_linux_musl] needs-llvm-components: mips -//@ revisions: mipsel_unknown_linux_uclibc -//@ [mipsel_unknown_linux_uclibc] compile-flags: --target mipsel-unknown-linux-uclibc -//@ [mipsel_unknown_linux_uclibc] needs-llvm-components: mips -//@ revisions: mipsel_unknown_netbsd -//@ [mipsel_unknown_netbsd] compile-flags: --target mipsel-unknown-netbsd -//@ [mipsel_unknown_netbsd] needs-llvm-components: mips -//@ revisions: mipsel_unknown_none -//@ [mipsel_unknown_none] compile-flags: --target mipsel-unknown-none -//@ [mipsel_unknown_none] needs-llvm-components: mips -//@ revisions: mipsisa32r6_unknown_linux_gnu -//@ [mipsisa32r6_unknown_linux_gnu] compile-flags: --target mipsisa32r6-unknown-linux-gnu -//@ [mipsisa32r6_unknown_linux_gnu] needs-llvm-components: mips -//@ revisions: mipsisa32r6el_unknown_linux_gnu -//@ [mipsisa32r6el_unknown_linux_gnu] compile-flags: --target mipsisa32r6el-unknown-linux-gnu -//@ [mipsisa32r6el_unknown_linux_gnu] needs-llvm-components: mips -//@ revisions: mipsisa64r6_unknown_linux_gnuabi64 -//@ [mipsisa64r6_unknown_linux_gnuabi64] compile-flags: --target mipsisa64r6-unknown-linux-gnuabi64 -//@ [mipsisa64r6_unknown_linux_gnuabi64] needs-llvm-components: mips -//@ revisions: mipsisa64r6el_unknown_linux_gnuabi64 -//@ [mipsisa64r6el_unknown_linux_gnuabi64] compile-flags: --target mipsisa64r6el-unknown-linux-gnuabi64 -//@ [mipsisa64r6el_unknown_linux_gnuabi64] needs-llvm-components: mips -//@ revisions: msp430_none_elf -//@ [msp430_none_elf] compile-flags: --target msp430-none-elf -//@ [msp430_none_elf] needs-llvm-components: msp430 -//@ revisions: powerpc64_unknown_freebsd -//@ [powerpc64_unknown_freebsd] compile-flags: --target powerpc64-unknown-freebsd -//@ [powerpc64_unknown_freebsd] needs-llvm-components: powerpc -//@ revisions: powerpc64_unknown_linux_gnu -//@ [powerpc64_unknown_linux_gnu] compile-flags: --target powerpc64-unknown-linux-gnu -//@ [powerpc64_unknown_linux_gnu] needs-llvm-components: powerpc -//@ revisions: powerpc64_unknown_linux_musl -//@ [powerpc64_unknown_linux_musl] compile-flags: --target powerpc64-unknown-linux-musl -//@ [powerpc64_unknown_linux_musl] needs-llvm-components: powerpc -//@ revisions: powerpc64_unknown_openbsd -//@ [powerpc64_unknown_openbsd] compile-flags: --target powerpc64-unknown-openbsd -//@ [powerpc64_unknown_openbsd] needs-llvm-components: powerpc -//@ revisions: powerpc64_wrs_vxworks -//@ [powerpc64_wrs_vxworks] compile-flags: --target powerpc64-wrs-vxworks -//@ [powerpc64_wrs_vxworks] needs-llvm-components: powerpc -//@ revisions: powerpc64le_unknown_freebsd -//@ [powerpc64le_unknown_freebsd] compile-flags: --target powerpc64le-unknown-freebsd -//@ [powerpc64le_unknown_freebsd] needs-llvm-components: powerpc -//@ revisions: powerpc64le_unknown_linux_gnu -//@ [powerpc64le_unknown_linux_gnu] compile-flags: --target powerpc64le-unknown-linux-gnu -//@ [powerpc64le_unknown_linux_gnu] needs-llvm-components: powerpc -//@ revisions: powerpc64le_unknown_linux_musl -//@ [powerpc64le_unknown_linux_musl] compile-flags: --target powerpc64le-unknown-linux-musl -//@ [powerpc64le_unknown_linux_musl] needs-llvm-components: powerpc -//@ revisions: powerpc_unknown_freebsd -//@ [powerpc_unknown_freebsd] compile-flags: --target powerpc-unknown-freebsd -//@ [powerpc_unknown_freebsd] needs-llvm-components: powerpc -//@ revisions: powerpc_unknown_linux_gnu -//@ [powerpc_unknown_linux_gnu] compile-flags: --target powerpc-unknown-linux-gnu -//@ [powerpc_unknown_linux_gnu] needs-llvm-components: powerpc -//@ revisions: powerpc_unknown_linux_gnuspe -//@ [powerpc_unknown_linux_gnuspe] compile-flags: --target powerpc-unknown-linux-gnuspe -//@ [powerpc_unknown_linux_gnuspe] needs-llvm-components: powerpc -//@ revisions: powerpc_unknown_linux_musl -//@ [powerpc_unknown_linux_musl] compile-flags: --target powerpc-unknown-linux-musl -//@ [powerpc_unknown_linux_musl] needs-llvm-components: powerpc -//@ revisions: powerpc_unknown_linux_muslspe -//@ [powerpc_unknown_linux_muslspe] compile-flags: --target powerpc-unknown-linux-muslspe -//@ [powerpc_unknown_linux_muslspe] needs-llvm-components: powerpc -//@ revisions: powerpc_unknown_netbsd -//@ [powerpc_unknown_netbsd] compile-flags: --target powerpc-unknown-netbsd -//@ [powerpc_unknown_netbsd] needs-llvm-components: powerpc -//@ revisions: powerpc_unknown_openbsd -//@ [powerpc_unknown_openbsd] compile-flags: --target powerpc-unknown-openbsd -//@ [powerpc_unknown_openbsd] needs-llvm-components: powerpc -//@ revisions: powerpc_wrs_vxworks -//@ [powerpc_wrs_vxworks] compile-flags: --target powerpc-wrs-vxworks -//@ [powerpc_wrs_vxworks] needs-llvm-components: powerpc -//@ revisions: powerpc_wrs_vxworks_spe -//@ [powerpc_wrs_vxworks_spe] compile-flags: --target powerpc-wrs-vxworks-spe -//@ [powerpc_wrs_vxworks_spe] needs-llvm-components: powerpc -//@ revisions: riscv32_wrs_vxworks -//@ [riscv32_wrs_vxworks] compile-flags: --target riscv32-wrs-vxworks -//@ [riscv32_wrs_vxworks] needs-llvm-components: riscv -//@ revisions: riscv32e_unknown_none_elf -//@ [riscv32e_unknown_none_elf] compile-flags: --target riscv32e-unknown-none-elf -//@ [riscv32e_unknown_none_elf] needs-llvm-components: riscv -//@ revisions: riscv32em_unknown_none_elf -//@ [riscv32em_unknown_none_elf] compile-flags: --target riscv32em-unknown-none-elf -//@ [riscv32em_unknown_none_elf] needs-llvm-components: riscv -//@ revisions: riscv32emc_unknown_none_elf -//@ [riscv32emc_unknown_none_elf] compile-flags: --target riscv32emc-unknown-none-elf -//@ [riscv32emc_unknown_none_elf] needs-llvm-components: riscv -//@ revisions: riscv32gc_unknown_linux_gnu -//@ [riscv32gc_unknown_linux_gnu] compile-flags: --target riscv32gc-unknown-linux-gnu -//@ [riscv32gc_unknown_linux_gnu] needs-llvm-components: riscv -//@ revisions: riscv32gc_unknown_linux_musl -//@ [riscv32gc_unknown_linux_musl] compile-flags: --target riscv32gc-unknown-linux-musl -//@ [riscv32gc_unknown_linux_musl] needs-llvm-components: riscv -//@ revisions: riscv32i_unknown_none_elf -//@ [riscv32i_unknown_none_elf] compile-flags: --target riscv32i-unknown-none-elf -//@ [riscv32i_unknown_none_elf] needs-llvm-components: riscv -//@ revisions: riscv32im_risc0_zkvm_elf -//@ [riscv32im_risc0_zkvm_elf] compile-flags: --target riscv32im-risc0-zkvm-elf -//@ [riscv32im_risc0_zkvm_elf] needs-llvm-components: riscv -//@ revisions: riscv32im_unknown_none_elf -//@ [riscv32im_unknown_none_elf] compile-flags: --target riscv32im-unknown-none-elf -//@ [riscv32im_unknown_none_elf] needs-llvm-components: riscv -//@ revisions: riscv32ima_unknown_none_elf -//@ [riscv32ima_unknown_none_elf] compile-flags: --target riscv32ima-unknown-none-elf -//@ [riscv32ima_unknown_none_elf] needs-llvm-components: riscv -//@ revisions: riscv32imac_esp_espidf -//@ [riscv32imac_esp_espidf] compile-flags: --target riscv32imac-esp-espidf -//@ [riscv32imac_esp_espidf] needs-llvm-components: riscv -//@ revisions: riscv32imac_unknown_none_elf -//@ [riscv32imac_unknown_none_elf] compile-flags: --target riscv32imac-unknown-none-elf -//@ [riscv32imac_unknown_none_elf] needs-llvm-components: riscv -//@ revisions: riscv32imac_unknown_xous_elf -//@ [riscv32imac_unknown_xous_elf] compile-flags: --target riscv32imac-unknown-xous-elf -//@ [riscv32imac_unknown_xous_elf] needs-llvm-components: riscv -//@ revisions: riscv32imafc_unknown_none_elf -//@ [riscv32imafc_unknown_none_elf] compile-flags: --target riscv32imafc-unknown-none-elf -//@ [riscv32imafc_unknown_none_elf] needs-llvm-components: riscv -//@ revisions: riscv32imafc_esp_espidf -//@ [riscv32imafc_esp_espidf] compile-flags: --target riscv32imafc-esp-espidf -//@ [riscv32imafc_esp_espidf] needs-llvm-components: riscv -//@ revisions: riscv32imc_esp_espidf -//@ [riscv32imc_esp_espidf] compile-flags: --target riscv32imc-esp-espidf -//@ [riscv32imc_esp_espidf] needs-llvm-components: riscv -//@ revisions: riscv32imc_unknown_none_elf -//@ [riscv32imc_unknown_none_elf] compile-flags: --target riscv32imc-unknown-none-elf -//@ [riscv32imc_unknown_none_elf] needs-llvm-components: riscv -//@ revisions: riscv64_linux_android -//@ [riscv64_linux_android] compile-flags: --target riscv64-linux-android -//@ [riscv64_linux_android] needs-llvm-components: riscv -//@ revisions: riscv64_wrs_vxworks -//@ [riscv64_wrs_vxworks] compile-flags: --target riscv64-wrs-vxworks -//@ [riscv64_wrs_vxworks] needs-llvm-components: riscv -//@ revisions: riscv64gc_unknown_freebsd -//@ [riscv64gc_unknown_freebsd] compile-flags: --target riscv64gc-unknown-freebsd -//@ [riscv64gc_unknown_freebsd] needs-llvm-components: riscv -//@ revisions: riscv64gc_unknown_fuchsia -//@ [riscv64gc_unknown_fuchsia] compile-flags: --target riscv64gc-unknown-fuchsia -//@ [riscv64gc_unknown_fuchsia] needs-llvm-components: riscv -//@ revisions: riscv64gc_unknown_hermit -//@ [riscv64gc_unknown_hermit] compile-flags: --target riscv64gc-unknown-hermit -//@ [riscv64gc_unknown_hermit] needs-llvm-components: riscv -//@ revisions: riscv64gc_unknown_linux_gnu -//@ [riscv64gc_unknown_linux_gnu] compile-flags: --target riscv64gc-unknown-linux-gnu -//@ [riscv64gc_unknown_linux_gnu] needs-llvm-components: riscv -//@ revisions: riscv64gc_unknown_linux_musl -//@ [riscv64gc_unknown_linux_musl] compile-flags: --target riscv64gc-unknown-linux-musl -//@ [riscv64gc_unknown_linux_musl] needs-llvm-components: riscv -//@ revisions: riscv64gc_unknown_netbsd -//@ [riscv64gc_unknown_netbsd] compile-flags: --target riscv64gc-unknown-netbsd -//@ [riscv64gc_unknown_netbsd] needs-llvm-components: riscv -//@ revisions: riscv64gc_unknown_none_elf -//@ [riscv64gc_unknown_none_elf] compile-flags: --target riscv64gc-unknown-none-elf -//@ [riscv64gc_unknown_none_elf] needs-llvm-components: riscv -//@ revisions: riscv64gc_unknown_openbsd -//@ [riscv64gc_unknown_openbsd] compile-flags: --target riscv64gc-unknown-openbsd -//@ [riscv64gc_unknown_openbsd] needs-llvm-components: riscv -//@ revisions: riscv64imac_unknown_none_elf -//@ [riscv64imac_unknown_none_elf] compile-flags: --target riscv64imac-unknown-none-elf -//@ [riscv64imac_unknown_none_elf] needs-llvm-components: riscv -//@ revisions: s390x_unknown_linux_gnu -//@ [s390x_unknown_linux_gnu] compile-flags: --target s390x-unknown-linux-gnu -//@ [s390x_unknown_linux_gnu] needs-llvm-components: systemz -//@ revisions: s390x_unknown_linux_musl -//@ [s390x_unknown_linux_musl] compile-flags: --target s390x-unknown-linux-musl -//@ [s390x_unknown_linux_musl] needs-llvm-components: systemz -//@ revisions: sparc64_unknown_linux_gnu -//@ [sparc64_unknown_linux_gnu] compile-flags: --target sparc64-unknown-linux-gnu -//@ [sparc64_unknown_linux_gnu] needs-llvm-components: sparc -//@ revisions: sparc64_unknown_netbsd -//@ [sparc64_unknown_netbsd] compile-flags: --target sparc64-unknown-netbsd -//@ [sparc64_unknown_netbsd] needs-llvm-components: sparc -//@ revisions: sparc64_unknown_openbsd -//@ [sparc64_unknown_openbsd] compile-flags: --target sparc64-unknown-openbsd -//@ [sparc64_unknown_openbsd] needs-llvm-components: sparc -//@ revisions: sparc_unknown_linux_gnu -//@ [sparc_unknown_linux_gnu] compile-flags: --target sparc-unknown-linux-gnu -//@ [sparc_unknown_linux_gnu] needs-llvm-components: sparc -//@ revisions: sparc_unknown_none_elf -//@ [sparc_unknown_none_elf] compile-flags: --target sparc-unknown-none-elf -//@ [sparc_unknown_none_elf] needs-llvm-components: sparc -//@ revisions: sparcv9_sun_solaris -//@ [sparcv9_sun_solaris] compile-flags: --target sparcv9-sun-solaris -//@ [sparcv9_sun_solaris] needs-llvm-components: sparc -//@ revisions: thumbv4t_none_eabi -//@ [thumbv4t_none_eabi] compile-flags: --target thumbv4t-none-eabi -//@ [thumbv4t_none_eabi] needs-llvm-components: arm -//@ revisions: thumbv5te_none_eabi -//@ [thumbv5te_none_eabi] compile-flags: --target thumbv5te-none-eabi -//@ [thumbv5te_none_eabi] needs-llvm-components: arm -//@ revisions: thumbv6m_none_eabi -//@ [thumbv6m_none_eabi] compile-flags: --target thumbv6m-none-eabi -//@ [thumbv6m_none_eabi] needs-llvm-components: arm -//@ revisions: thumbv7em_none_eabi -//@ [thumbv7em_none_eabi] compile-flags: --target thumbv7em-none-eabi -//@ [thumbv7em_none_eabi] needs-llvm-components: arm -//@ revisions: thumbv7em_none_eabihf -//@ [thumbv7em_none_eabihf] compile-flags: --target thumbv7em-none-eabihf -//@ [thumbv7em_none_eabihf] needs-llvm-components: arm -//@ revisions: thumbv7m_none_eabi -//@ [thumbv7m_none_eabi] compile-flags: --target thumbv7m-none-eabi -//@ [thumbv7m_none_eabi] needs-llvm-components: arm -//@ revisions: thumbv7neon_linux_androideabi -//@ [thumbv7neon_linux_androideabi] compile-flags: --target thumbv7neon-linux-androideabi -//@ [thumbv7neon_linux_androideabi] needs-llvm-components: arm -//@ revisions: thumbv7neon_unknown_linux_gnueabihf -//@ [thumbv7neon_unknown_linux_gnueabihf] compile-flags: --target thumbv7neon-unknown-linux-gnueabihf -//@ [thumbv7neon_unknown_linux_gnueabihf] needs-llvm-components: arm -//@ revisions: thumbv7neon_unknown_linux_musleabihf -//@ [thumbv7neon_unknown_linux_musleabihf] compile-flags: --target thumbv7neon-unknown-linux-musleabihf -//@ [thumbv7neon_unknown_linux_musleabihf] needs-llvm-components: arm -//@ revisions: thumbv8m_base_none_eabi -//@ [thumbv8m_base_none_eabi] compile-flags: --target thumbv8m.base-none-eabi -//@ [thumbv8m_base_none_eabi] needs-llvm-components: arm -//@ revisions: thumbv8m_main_none_eabi -//@ [thumbv8m_main_none_eabi] compile-flags: --target thumbv8m.main-none-eabi -//@ [thumbv8m_main_none_eabi] needs-llvm-components: arm -//@ revisions: thumbv8m_main_none_eabihf -//@ [thumbv8m_main_none_eabihf] compile-flags: --target thumbv8m.main-none-eabihf -//@ [thumbv8m_main_none_eabihf] needs-llvm-components: arm -//@ revisions: wasm32_unknown_emscripten -//@ [wasm32_unknown_emscripten] compile-flags: --target wasm32-unknown-emscripten -//@ [wasm32_unknown_emscripten] needs-llvm-components: webassembly -//@ revisions: wasm32_unknown_unknown -//@ [wasm32_unknown_unknown] compile-flags: --target wasm32-unknown-unknown -//@ [wasm32_unknown_unknown] needs-llvm-components: webassembly -//@ revisions: wasm32v1_none -//@ [wasm32v1_none] compile-flags: --target wasm32v1-none -//@ [wasm32v1_none] needs-llvm-components: webassembly -//@ revisions: wasm32_wasip1 -//@ [wasm32_wasip1] compile-flags: --target wasm32-wasip1 -//@ [wasm32_wasip1] needs-llvm-components: webassembly -//@ revisions: wasm32_wasip1_threads -//@ [wasm32_wasip1_threads] compile-flags: --target wasm32-wasip1-threads -//@ [wasm32_wasip1_threads] needs-llvm-components: webassembly -//@ revisions: wasm32_wasip2 -//@ [wasm32_wasip2] compile-flags: --target wasm32-wasip2 -//@ [wasm32_wasip2] needs-llvm-components: webassembly -//@ revisions: wasm32_wali_linux_musl -//@ [wasm32_wali_linux_musl] compile-flags: --target wasm32-wali-linux-musl -//@ [wasm32_wali_linux_musl] needs-llvm-components: webassembly -//@ revisions: wasm64_unknown_unknown -//@ [wasm64_unknown_unknown] compile-flags: --target wasm64-unknown-unknown -//@ [wasm64_unknown_unknown] needs-llvm-components: webassembly -//@ revisions: x86_64_fortanix_unknown_sgx -//@ [x86_64_fortanix_unknown_sgx] compile-flags: --target x86_64-fortanix-unknown-sgx -//@ [x86_64_fortanix_unknown_sgx] needs-llvm-components: x86 -//@ revisions: x86_64_linux_android -//@ [x86_64_linux_android] compile-flags: --target x86_64-linux-android -//@ [x86_64_linux_android] needs-llvm-components: x86 -//@ revisions: x86_64_lynx_lynxos178 -//@ [x86_64_lynx_lynxos178] compile-flags: --target x86_64-lynx-lynxos178 -//@ [x86_64_lynx_lynxos178] needs-llvm-components: x86 -//@ revisions: x86_64_pc_nto_qnx710 -//@ [x86_64_pc_nto_qnx710] compile-flags: --target x86_64-pc-nto-qnx710 -//@ [x86_64_pc_nto_qnx710] needs-llvm-components: x86 -//@ revisions: x86_64_pc_nto_qnx710_iosock -//@ [x86_64_pc_nto_qnx710_iosock] compile-flags: --target x86_64-pc-nto-qnx710_iosock -//@ [x86_64_pc_nto_qnx710_iosock] needs-llvm-components: x86 -//@ revisions: x86_64_pc_nto_qnx800 -//@ [x86_64_pc_nto_qnx800] compile-flags: --target x86_64-pc-nto-qnx800 -//@ [x86_64_pc_nto_qnx800] needs-llvm-components: x86 -//@ revisions: x86_64_pc_solaris -//@ [x86_64_pc_solaris] compile-flags: --target x86_64-pc-solaris -//@ [x86_64_pc_solaris] needs-llvm-components: x86 -//@ revisions: x86_64_unikraft_linux_musl -//@ [x86_64_unikraft_linux_musl] compile-flags: --target x86_64-unikraft-linux-musl -//@ [x86_64_unikraft_linux_musl] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_dragonfly -//@ [x86_64_unknown_dragonfly] compile-flags: --target x86_64-unknown-dragonfly -//@ [x86_64_unknown_dragonfly] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_freebsd -//@ [x86_64_unknown_freebsd] compile-flags: --target x86_64-unknown-freebsd -//@ [x86_64_unknown_freebsd] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_fuchsia -//@ [x86_64_unknown_fuchsia] compile-flags: --target x86_64-unknown-fuchsia -//@ [x86_64_unknown_fuchsia] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_haiku -//@ [x86_64_unknown_haiku] compile-flags: --target x86_64-unknown-haiku -//@ [x86_64_unknown_haiku] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_hurd_gnu -//@ [x86_64_unknown_hurd_gnu] compile-flags: --target x86_64-unknown-hurd-gnu -//@ [x86_64_unknown_hurd_gnu] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_hermit -//@ [x86_64_unknown_hermit] compile-flags: --target x86_64-unknown-hermit -//@ [x86_64_unknown_hermit] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_illumos -//@ [x86_64_unknown_illumos] compile-flags: --target x86_64-unknown-illumos -//@ [x86_64_unknown_illumos] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_l4re_uclibc -//@ [x86_64_unknown_l4re_uclibc] compile-flags: --target x86_64-unknown-l4re-uclibc -//@ [x86_64_unknown_l4re_uclibc] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_linux_gnu -//@ [x86_64_unknown_linux_gnu] compile-flags: --target x86_64-unknown-linux-gnu -//@ [x86_64_unknown_linux_gnu] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_linux_gnux32 -//@ [x86_64_unknown_linux_gnux32] compile-flags: --target x86_64-unknown-linux-gnux32 -//@ [x86_64_unknown_linux_gnux32] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_linux_musl -//@ [x86_64_unknown_linux_musl] compile-flags: --target x86_64-unknown-linux-musl -//@ [x86_64_unknown_linux_musl] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_linux_ohos -//@ [x86_64_unknown_linux_ohos] compile-flags: --target x86_64-unknown-linux-ohos -//@ [x86_64_unknown_linux_ohos] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_linux_none -//@ [x86_64_unknown_linux_none] compile-flags: --target x86_64-unknown-linux-none -//@ [x86_64_unknown_linux_none] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_netbsd -//@ [x86_64_unknown_netbsd] compile-flags: --target x86_64-unknown-netbsd -//@ [x86_64_unknown_netbsd] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_none -//@ [x86_64_unknown_none] compile-flags: --target x86_64-unknown-none -//@ [x86_64_unknown_none] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_openbsd -//@ [x86_64_unknown_openbsd] compile-flags: --target x86_64-unknown-openbsd -//@ [x86_64_unknown_openbsd] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_redox -//@ [x86_64_unknown_redox] compile-flags: --target x86_64-unknown-redox -//@ [x86_64_unknown_redox] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_trusty -//@ [x86_64_unknown_trusty] compile-flags: --target x86_64-unknown-trusty -//@ [x86_64_unknown_trusty] needs-llvm-components: x86 -//@ revisions: x86_64_wrs_vxworks -//@ [x86_64_wrs_vxworks] compile-flags: --target x86_64-wrs-vxworks -//@ [x86_64_wrs_vxworks] needs-llvm-components: x86 -//@ revisions: thumbv6m_nuttx_eabi -//@ [thumbv6m_nuttx_eabi] compile-flags: --target thumbv6m-nuttx-eabi -//@ [thumbv6m_nuttx_eabi] needs-llvm-components: arm -//@ revisions: thumbv7a_nuttx_eabi -//@ [thumbv7a_nuttx_eabi] compile-flags: --target thumbv7a-nuttx-eabi -//@ [thumbv7a_nuttx_eabi] needs-llvm-components: arm -//@ revisions: thumbv7a_nuttx_eabihf -//@ [thumbv7a_nuttx_eabihf] compile-flags: --target thumbv7a-nuttx-eabihf -//@ [thumbv7a_nuttx_eabihf] needs-llvm-components: arm -//@ revisions: thumbv7m_nuttx_eabi -//@ [thumbv7m_nuttx_eabi] compile-flags: --target thumbv7m-nuttx-eabi -//@ [thumbv7m_nuttx_eabi] needs-llvm-components: arm -//@ revisions: thumbv7em_nuttx_eabi -//@ [thumbv7em_nuttx_eabi] compile-flags: --target thumbv7em-nuttx-eabi -//@ [thumbv7em_nuttx_eabi] needs-llvm-components: arm -//@ revisions: thumbv7em_nuttx_eabihf -//@ [thumbv7em_nuttx_eabihf] compile-flags: --target thumbv7em-nuttx-eabihf -//@ [thumbv7em_nuttx_eabihf] needs-llvm-components: arm -//@ revisions: thumbv8m_base_nuttx_eabi -//@ [thumbv8m_base_nuttx_eabi] compile-flags: --target thumbv8m.base-nuttx-eabi -//@ [thumbv8m_base_nuttx_eabi] needs-llvm-components: arm -//@ revisions: thumbv8m_main_nuttx_eabi -//@ [thumbv8m_main_nuttx_eabi] compile-flags: --target thumbv8m.main-nuttx-eabi -//@ [thumbv8m_main_nuttx_eabi] needs-llvm-components: arm -//@ revisions: thumbv8m_main_nuttx_eabihf -//@ [thumbv8m_main_nuttx_eabihf] compile-flags: --target thumbv8m.main-nuttx-eabihf -//@ [thumbv8m_main_nuttx_eabihf] needs-llvm-components: arm -//@ revisions: riscv32imc_unknown_nuttx_elf -//@ [riscv32imc_unknown_nuttx_elf] compile-flags: --target riscv32imc-unknown-nuttx-elf -//@ [riscv32imc_unknown_nuttx_elf] needs-llvm-components: riscv -//@ revisions: riscv32imac_unknown_nuttx_elf -//@ [riscv32imac_unknown_nuttx_elf] compile-flags: --target riscv32imac-unknown-nuttx-elf -//@ [riscv32imac_unknown_nuttx_elf] needs-llvm-components: riscv -//@ revisions: riscv32imafc_unknown_nuttx_elf -//@ [riscv32imafc_unknown_nuttx_elf] compile-flags: --target riscv32imafc-unknown-nuttx-elf -//@ [riscv32imafc_unknown_nuttx_elf] needs-llvm-components: riscv -//@ revisions: riscv64imac_unknown_nuttx_elf -//@ [riscv64imac_unknown_nuttx_elf] compile-flags: --target riscv64imac-unknown-nuttx-elf -//@ [riscv64imac_unknown_nuttx_elf] needs-llvm-components: riscv -//@ revisions: riscv64gc_unknown_nuttx_elf -//@ [riscv64gc_unknown_nuttx_elf] compile-flags: --target riscv64gc-unknown-nuttx-elf -//@ [riscv64gc_unknown_nuttx_elf] needs-llvm-components: riscv -// FIXME: disabled since it requires a custom LLVM until the upstream LLVM adds support for the target (https://github.com/espressif/llvm-project/issues/4) -/* - revisions: xtensa_esp32_none_elf - [xtensa_esp32_none_elf] compile-flags: --target xtensa-esp32-none-elf - [xtensa_esp32_none_elf] needs-llvm-components: xtensa - revisions: xtensa_esp32_espidf - [xtensa_esp32_espidf] compile-flags: --target xtensa-esp32s2-espidf - [xtensa_esp32_espidf] needs-llvm-components: xtensa - revisions: xtensa_esp32s2_none_elf - [xtensa_esp32s2_none_elf] compile-flags: --target xtensa-esp32s2-none-elf - [xtensa_esp32s2_none_elf] needs-llvm-components: xtensa - revisions: xtensa_esp32s2_espidf - [xtensa_esp32s2_espidf] compile-flags: --target xtensa-esp32s2-espidf - [xtensa_esp32s2_espidf] needs-llvm-components: xtensa - revisions: xtensa_esp32s3_none_elf - [xtensa_esp32s3_none_elf] compile-flags: --target xtensa-esp32s3-none-elf - [xtensa_esp32s3_none_elf] needs-llvm-components: xtensa - revisions: xtensa_esp32s3_espidf - [xtensa_esp32s3_espidf] compile-flags: --target xtensa-esp32s3-espidf - [xtensa_esp32s3_espidf] needs-llvm-components: xtensa -*/ -// Sanity-check that each target can produce assembly code. - -#![feature(no_core, lang_items)] -#![no_std] -#![no_core] -#![crate_type = "lib"] - -extern crate minicore; -use minicore::*; - -// Force linkage to ensure code is actually generated -#[no_mangle] -pub fn test() -> u8 { - 42 -} - -// CHECK: .text diff --git a/tests/assembly/targets/targets-macho.rs b/tests/assembly/targets/targets-macho.rs deleted file mode 100644 index 92bde1c6971..00000000000 --- a/tests/assembly/targets/targets-macho.rs +++ /dev/null @@ -1,93 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -// ignore-tidy-linelength -//@ revisions: aarch64_apple_darwin -//@ [aarch64_apple_darwin] compile-flags: --target aarch64-apple-darwin -//@ [aarch64_apple_darwin] needs-llvm-components: aarch64 -//@ revisions: aarch64_apple_ios -//@ [aarch64_apple_ios] compile-flags: --target aarch64-apple-ios -//@ [aarch64_apple_ios] needs-llvm-components: aarch64 -//@ revisions: aarch64_apple_ios_macabi -//@ [aarch64_apple_ios_macabi] compile-flags: --target aarch64-apple-ios-macabi -//@ [aarch64_apple_ios_macabi] needs-llvm-components: aarch64 -//@ revisions: aarch64_apple_ios_sim -//@ [aarch64_apple_ios_sim] compile-flags: --target aarch64-apple-ios-sim -//@ [aarch64_apple_ios_sim] needs-llvm-components: aarch64 -//@ revisions: aarch64_apple_tvos -//@ [aarch64_apple_tvos] compile-flags: --target aarch64-apple-tvos -//@ [aarch64_apple_tvos] needs-llvm-components: aarch64 -//@ revisions: aarch64_apple_tvos_sim -//@ [aarch64_apple_tvos_sim] compile-flags: --target aarch64-apple-tvos-sim -//@ [aarch64_apple_tvos_sim] needs-llvm-components: aarch64 -//@ revisions: arm64e_apple_tvos -//@ [arm64e_apple_tvos] compile-flags: --target arm64e-apple-tvos -//@ [arm64e_apple_tvos] needs-llvm-components: aarch64 -//@ revisions: aarch64_apple_watchos -//@ [aarch64_apple_watchos] compile-flags: --target aarch64-apple-watchos -//@ [aarch64_apple_watchos] needs-llvm-components: aarch64 -//@ revisions: aarch64_apple_watchos_sim -//@ [aarch64_apple_watchos_sim] compile-flags: --target aarch64-apple-watchos-sim -//@ [aarch64_apple_watchos_sim] needs-llvm-components: aarch64 -//@ revisions: arm64_32_apple_watchos -//@ [arm64_32_apple_watchos] compile-flags: --target arm64_32-apple-watchos -//@ [arm64_32_apple_watchos] needs-llvm-components: aarch64 -//@ revisions: aarch64_apple_visionos -//@ [aarch64_apple_visionos] compile-flags: --target aarch64-apple-visionos -//@ [aarch64_apple_visionos] needs-llvm-components: aarch64 -//@ revisions: aarch64_apple_visionos_sim -//@ [aarch64_apple_visionos_sim] compile-flags: --target aarch64-apple-visionos-sim -//@ [aarch64_apple_visionos_sim] needs-llvm-components: aarch64 -//@ revisions: arm64e_apple_darwin -//@ [arm64e_apple_darwin] compile-flags: --target arm64e-apple-darwin -//@ [arm64e_apple_darwin] needs-llvm-components: aarch64 -//@ revisions: arm64e_apple_ios -//@ [arm64e_apple_ios] compile-flags: --target arm64e-apple-ios -//@ [arm64e_apple_ios] needs-llvm-components: aarch64 -//@ revisions: armv7k_apple_watchos -//@ [armv7k_apple_watchos] compile-flags: --target armv7k-apple-watchos -//@ [armv7k_apple_watchos] needs-llvm-components: arm -//@ revisions: armv7s_apple_ios -//@ [armv7s_apple_ios] compile-flags: --target armv7s-apple-ios -//@ [armv7s_apple_ios] needs-llvm-components: arm -//@ revisions: i386_apple_ios -//@ [i386_apple_ios] compile-flags: --target i386-apple-ios -//@ [i386_apple_ios] needs-llvm-components: x86 -//@ revisions: i686_apple_darwin -//@ [i686_apple_darwin] compile-flags: --target i686-apple-darwin -//@ [i686_apple_darwin] needs-llvm-components: x86 -//@ revisions: x86_64_apple_darwin -//@ [x86_64_apple_darwin] compile-flags: --target x86_64-apple-darwin -//@ [x86_64_apple_darwin] needs-llvm-components: x86 -//@ revisions: x86_64_apple_ios -//@ [x86_64_apple_ios] compile-flags: --target x86_64-apple-ios -//@ [x86_64_apple_ios] needs-llvm-components: x86 -//@ revisions: x86_64_apple_ios_macabi -//@ [x86_64_apple_ios_macabi] compile-flags: --target x86_64-apple-ios-macabi -//@ [x86_64_apple_ios_macabi] needs-llvm-components: x86 -//@ revisions: x86_64_apple_tvos -//@ [x86_64_apple_tvos] compile-flags: --target x86_64-apple-tvos -//@ [x86_64_apple_tvos] needs-llvm-components: x86 -//@ revisions: x86_64_apple_watchos_sim -//@ [x86_64_apple_watchos_sim] compile-flags: --target x86_64-apple-watchos-sim -//@ [x86_64_apple_watchos_sim] needs-llvm-components: x86 -//@ revisions: x86_64h_apple_darwin -//@ [x86_64h_apple_darwin] compile-flags: --target x86_64h-apple-darwin -//@ [x86_64h_apple_darwin] needs-llvm-components: x86 - -// Sanity-check that each target can produce assembly code. - -#![feature(no_core, lang_items)] -#![no_std] -#![no_core] -#![crate_type = "lib"] - -extern crate minicore; -use minicore::*; - -// Force linkage to ensure code is actually generated -#[no_mangle] -pub fn test() -> u8 { - 42 -} - -// CHECK: .section __TEXT,__text diff --git a/tests/assembly/targets/targets-nvptx.rs b/tests/assembly/targets/targets-nvptx.rs deleted file mode 100644 index 49c12aebaaa..00000000000 --- a/tests/assembly/targets/targets-nvptx.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -// ignore-tidy-linelength -//@ revisions: nvptx64_nvidia_cuda -//@ [nvptx64_nvidia_cuda] compile-flags: --target nvptx64-nvidia-cuda -//@ [nvptx64_nvidia_cuda] needs-llvm-components: nvptx - -// Sanity-check that each target can produce assembly code. - -#![feature(no_core, lang_items)] -#![no_std] -#![no_core] -#![crate_type = "lib"] - -extern crate minicore; -use minicore::*; - -pub fn test() -> u8 { - 42 -} - -// CHECK: .version diff --git a/tests/assembly/targets/targets-pe.rs b/tests/assembly/targets/targets-pe.rs deleted file mode 100644 index de29b9af502..00000000000 --- a/tests/assembly/targets/targets-pe.rs +++ /dev/null @@ -1,103 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -// ignore-tidy-linelength -//@ revisions: aarch64_pc_windows_msvc -//@ [aarch64_pc_windows_msvc] compile-flags: --target aarch64-pc-windows-msvc -//@ [aarch64_pc_windows_msvc] needs-llvm-components: aarch64 -//@ revisions: aarch64_pc_windows_gnullvm -//@ [aarch64_pc_windows_gnullvm] compile-flags: --target aarch64-pc-windows-gnullvm -//@ [aarch64_pc_windows_gnullvm] needs-llvm-components: aarch64 -//@ revisions: aarch64_unknown_uefi -//@ [aarch64_unknown_uefi] compile-flags: --target aarch64-unknown-uefi -//@ [aarch64_unknown_uefi] needs-llvm-components: aarch64 -//@ revisions: aarch64_uwp_windows_msvc -//@ [aarch64_uwp_windows_msvc] compile-flags: --target aarch64-uwp-windows-msvc -//@ [aarch64_uwp_windows_msvc] needs-llvm-components: aarch64 -//@ revisions: arm64ec_pc_windows_msvc -//@ [arm64ec_pc_windows_msvc] compile-flags: --target arm64ec-pc-windows-msvc -//@ [arm64ec_pc_windows_msvc] needs-llvm-components: aarch64 -//@ revisions: avr_none -//@ [avr_none] compile-flags: --target avr-none -C target-cpu=atmega328p -//@ [avr_none] needs-llvm-components: avr -//@ revisions: bpfeb_unknown_none -//@ [bpfeb_unknown_none] compile-flags: --target bpfeb-unknown-none -//@ [bpfeb_unknown_none] needs-llvm-components: bpf -//@ revisions: bpfel_unknown_none -//@ [bpfel_unknown_none] compile-flags: --target bpfel-unknown-none -//@ [bpfel_unknown_none] needs-llvm-components: bpf -//@ revisions: i686_pc_windows_gnu -//@ [i686_pc_windows_gnu] compile-flags: --target i686-pc-windows-gnu -//@ [i686_pc_windows_gnu] needs-llvm-components: x86 -//@ revisions: i686_pc_windows_msvc -//@ [i686_pc_windows_msvc] compile-flags: --target i686-pc-windows-msvc -//@ [i686_pc_windows_msvc] needs-llvm-components: x86 -//@ revisions: i686_pc_windows_gnullvm -//@ [i686_pc_windows_gnullvm] compile-flags: --target i686-pc-windows-gnullvm -//@ [i686_pc_windows_gnullvm] needs-llvm-components: x86 -//@ revisions: i686_uwp_windows_gnu -//@ [i686_uwp_windows_gnu] compile-flags: --target i686-uwp-windows-gnu -//@ [i686_uwp_windows_gnu] needs-llvm-components: x86 -//@ revisions: i686_win7_windows_gnu -//@ [i686_win7_windows_gnu] compile-flags: --target i686-win7-windows-gnu -//@ [i686_win7_windows_gnu] needs-llvm-components: x86 -//@ revisions: i686_unknown_uefi -//@ [i686_unknown_uefi] compile-flags: --target i686-unknown-uefi -//@ [i686_unknown_uefi] needs-llvm-components: x86 -//@ revisions: i686_uwp_windows_msvc -//@ [i686_uwp_windows_msvc] compile-flags: --target i686-uwp-windows-msvc -//@ [i686_uwp_windows_msvc] needs-llvm-components: x86 -//@ revisions: i686_win7_windows_msvc -//@ [i686_win7_windows_msvc] compile-flags: --target i686-win7-windows-msvc -//@ [i686_win7_windows_msvc] needs-llvm-components: x86 -//@ revisions: powerpc64_ibm_aix -//@ [powerpc64_ibm_aix] compile-flags: --target powerpc64-ibm-aix -//@ [powerpc64_ibm_aix] needs-llvm-components: powerpc -//@ revisions: thumbv7a_uwp_windows_msvc -//@ [thumbv7a_uwp_windows_msvc] compile-flags: --target thumbv7a-uwp-windows-msvc -//@ [thumbv7a_uwp_windows_msvc] needs-llvm-components: arm -//@ revisions: thumbv7a_pc_windows_msvc -//@ [thumbv7a_pc_windows_msvc] compile-flags: --target thumbv7a-pc-windows-msvc -//@ [thumbv7a_pc_windows_msvc] needs-llvm-components: arm -//@ revisions: x86_64_pc_windows_gnu -//@ [x86_64_pc_windows_gnu] compile-flags: --target x86_64-pc-windows-gnu -//@ [x86_64_pc_windows_gnu] needs-llvm-components: x86 -//@ revisions: x86_64_pc_windows_gnullvm -//@ [x86_64_pc_windows_gnullvm] compile-flags: --target x86_64-pc-windows-gnullvm -//@ [x86_64_pc_windows_gnullvm] needs-llvm-components: x86 -//@ revisions: x86_64_pc_windows_msvc -//@ [x86_64_pc_windows_msvc] compile-flags: --target x86_64-pc-windows-msvc -//@ [x86_64_pc_windows_msvc] needs-llvm-components: x86 -//@ revisions: x86_64_unknown_uefi -//@ [x86_64_unknown_uefi] compile-flags: --target x86_64-unknown-uefi -//@ [x86_64_unknown_uefi] needs-llvm-components: x86 -//@ revisions: x86_64_uwp_windows_gnu -//@ [x86_64_uwp_windows_gnu] compile-flags: --target x86_64-uwp-windows-gnu -//@ [x86_64_uwp_windows_gnu] needs-llvm-components: x86 -//@ revisions: x86_64_win7_windows_gnu -//@ [x86_64_win7_windows_gnu] compile-flags: --target x86_64-win7-windows-gnu -//@ [x86_64_win7_windows_gnu] needs-llvm-components: x86 -//@ revisions: x86_64_uwp_windows_msvc -//@ [x86_64_uwp_windows_msvc] compile-flags: --target x86_64-uwp-windows-msvc -//@ [x86_64_uwp_windows_msvc] needs-llvm-components: x86 -//@ revisions: x86_64_win7_windows_msvc -//@ [x86_64_win7_windows_msvc] compile-flags: --target x86_64-win7-windows-msvc -//@ [x86_64_win7_windows_msvc] needs-llvm-components: x86 -//@ revisions: x86_64_pc_cygwin -//@ [x86_64_pc_cygwin] compile-flags: --target x86_64-pc-cygwin -//@ [x86_64_pc_cygwin] needs-llvm-components: x86 - -// Sanity-check that each target can produce assembly code. - -#![feature(no_core, lang_items)] -#![no_std] -#![no_core] -#![crate_type = "lib"] - -extern crate minicore; -use minicore::*; - -pub fn test() -> u8 { - 42 -} - -// CHECK: .file diff --git a/tests/assembly/wasm_exceptions.rs b/tests/assembly/wasm_exceptions.rs deleted file mode 100644 index 704e8026f3f..00000000000 --- a/tests/assembly/wasm_exceptions.rs +++ /dev/null @@ -1,67 +0,0 @@ -//@ only-wasm32 -//@ assembly-output: emit-asm -//@ compile-flags: -C target-feature=+exception-handling -//@ compile-flags: -C panic=unwind - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -extern "C-unwind" { - fn may_panic(); -} - -extern "C" { - fn log_number(number: usize); -} - -struct LogOnDrop; - -impl Drop for LogOnDrop { - fn drop(&mut self) { - unsafe { - log_number(0); - } - } -} - -// CHECK-LABEL: test_cleanup: -#[no_mangle] -pub fn test_cleanup() { - let _log_on_drop = LogOnDrop; - unsafe { - may_panic(); - } - - // CHECK-NOT: call - // CHECK: try - // CHECK: call may_panic - // CHECK: catch_all - // CHECK: rethrow - // CHECK: end_try -} - -// CHECK-LABEL: test_rtry: -#[no_mangle] -pub fn test_rtry() { - unsafe { - core::intrinsics::catch_unwind( - |_| { - may_panic(); - }, - core::ptr::null_mut(), - |data, exception| { - log_number(data as usize); - log_number(exception as usize); - }, - ); - } - - // CHECK-NOT: call - // CHECK: try - // CHECK: call may_panic - // CHECK: catch - // CHECK: call log_number - // CHECK: call log_number - // CHECK-NOT: rethrow - // CHECK: end_try -} diff --git a/tests/assembly/x86-return-float.rs b/tests/assembly/x86-return-float.rs deleted file mode 100644 index 165c11d2280..00000000000 --- a/tests/assembly/x86-return-float.rs +++ /dev/null @@ -1,343 +0,0 @@ -//@ assembly-output: emit-asm -// FIXME(#114479): LLVM miscompiles loading and storing `f32` and `f64` when SSE is disabled. -// There's no compiletest directive to ignore a test on i586 only, so just always explicitly enable -// SSE2. -// Use the same target CPU as `i686` so that LLVM orders the instructions in the same order. -//@ compile-flags: -Ctarget-feature=+sse2 -Ctarget-cpu=pentium4 -// Force frame pointers to make ASM more consistent between targets -//@ compile-flags: -C force-frame-pointers -// At opt-level=3, LLVM can merge two movss into one movsd, and we aren't testing for that. -//@ compile-flags: -Copt-level=2 -//@ filecheck-flags: --implicit-check-not fld --implicit-check-not fst -//@ revisions: linux win -//@ add-core-stubs -//@[linux] needs-llvm-components: x86 -//@[win] needs-llvm-components: x86 -//@[linux] compile-flags: --target i686-unknown-linux-gnu -//@[win] compile-flags: --target i686-pc-windows-msvc - -#![crate_type = "lib"] -#![feature(f16, f128)] -#![feature(no_core)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// Tests that returning `f32` and `f64` with the "Rust" ABI on 32-bit x86 doesn't use the x87 -// floating point stack, as loading and storing `f32`s and `f64`s to and from the x87 stack quietens -// signalling NaNs. - -// Returning individual floats - -// CHECK-LABEL: return_f32: -#[no_mangle] -pub fn return_f32(x: f32) -> f32 { - // CHECK: movss {{.*}}(%ebp), %xmm0 - // CHECK-NEXT: popl %ebp - // linux-NEXT: .cfi_def_cfa - // CHECK-NEXT: retl - x -} - -// CHECK-LABEL: return_f64: -#[no_mangle] -pub fn return_f64(x: f64) -> f64 { - // CHECK: movsd {{.*}}(%ebp), %xmm0 - // CHECK-NEXT: popl %ebp - // linux-NEXT: .cfi_def_cfa - // CHECK-NEXT: retl - x -} - -// Returning scalar pairs containing floats - -// CHECK-LABEL: return_f32_f32: -#[no_mangle] -pub fn return_f32_f32(x: (f32, f32)) -> (f32, f32) { - // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] - // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] - // CHECK-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] - // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) - // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) - // CHECK: retl - x -} - -// CHECK-LABEL: return_f64_f64: -#[no_mangle] -pub fn return_f64_f64(x: (f64, f64)) -> (f64, f64) { - // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] - // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] - // CHECK-NEXT: movsd [[#%d,OFFSET+12]](%ebp), %[[VAL2:.*]] - // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) - // CHECK-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) - // CHECK: retl - x -} - -// CHECK-LABEL: return_f32_f64: -#[no_mangle] -pub fn return_f32_f64(x: (f32, f64)) -> (f32, f64) { - // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] - // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] - // CHECK-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] - // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) - // CHECK-NEXT: movsd %[[VAL2]], {{4|8}}(%[[PTR]]) - // CHECK: retl - x -} - -// CHECK-LABEL: return_f64_f32: -#[no_mangle] -pub fn return_f64_f32(x: (f64, f32)) -> (f64, f32) { - // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] - // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] - // CHECK-NEXT: movss [[#%d,OFFSET+12]](%ebp), %[[VAL2:.*]] - // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) - // CHECK-NEXT: movss %[[VAL2]], 8(%[[PTR]]) - // CHECK: retl - x -} - -// CHECK-LABEL: return_f32_other: -#[no_mangle] -pub fn return_f32_other(x: (f32, usize)) -> (f32, usize) { - // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] - // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] - // CHECK-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] - // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) - // CHECK-NEXT: movl %[[VAL2]], 4(%[[PTR]]) - // CHECK: retl - x -} - -// CHECK-LABEL: return_f64_other: -#[no_mangle] -pub fn return_f64_other(x: (f64, usize)) -> (f64, usize) { - // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] - // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] - // CHECK-NEXT: movl [[#%d,OFFSET+12]](%ebp), %[[VAL2:.*]] - // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) - // CHECK-NEXT: movl %[[VAL2]], 8(%[[PTR]]) - // CHECK: retl - x -} - -// CHECK-LABEL: return_other_f32: -#[no_mangle] -pub fn return_other_f32(x: (usize, f32)) -> (usize, f32) { - // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] - // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] - // CHECK-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] - // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) - // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) - // CHECK: retl - x -} - -// CHECK-LABEL: return_other_f64: -#[no_mangle] -pub fn return_other_f64(x: (usize, f64)) -> (usize, f64) { - // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] - // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] - // CHECK-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] - // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) - // CHECK-NEXT: movsd %[[VAL2]], {{4|8}}(%[[PTR]]) - // CHECK: retl - x -} - -// Calling functions returning floats - -// CHECK-LABEL: call_f32: -#[no_mangle] -pub unsafe fn call_f32(x: &mut f32) { - extern "Rust" { - fn get_f32() -> f32; - } - // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] - // CHECK: calll {{()|_}}get_f32 - // CHECK-NEXT: movss %xmm0, (%[[PTR]]) - *x = get_f32(); -} - -// CHECK-LABEL: call_f64: -#[no_mangle] -pub unsafe fn call_f64(x: &mut f64) { - extern "Rust" { - fn get_f64() -> f64; - } - // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] - // CHECK: calll {{()|_}}get_f64 - // CHECK-NEXT: movlps %xmm0, (%[[PTR]]) - *x = get_f64(); -} - -// Calling functions returning scalar pairs containing floats - -// CHECK-LABEL: call_f32_f32: -#[no_mangle] -pub unsafe fn call_f32_f32(x: &mut (f32, f32)) { - extern "Rust" { - fn get_f32_f32() -> (f32, f32); - } - // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] - // CHECK: calll {{()|_}}get_f32_f32 - // CHECK: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] - // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] - // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) - // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) - *x = get_f32_f32(); -} - -// CHECK-LABEL: call_f64_f64: -#[no_mangle] -pub unsafe fn call_f64_f64(x: &mut (f64, f64)) { - extern "Rust" { - fn get_f64_f64() -> (f64, f64); - } - // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] - // CHECK: calll {{()|_}}get_f64_f64 - // linux: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] - // linux-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] - // win: movsd (%esp), %[[VAL1:.*]] - // win-NEXT: movsd 8(%esp), %[[VAL2:.*]] - // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) - // CHECK-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) - *x = get_f64_f64(); -} - -// CHECK-LABEL: call_f32_f64: -#[no_mangle] -pub unsafe fn call_f32_f64(x: &mut (f32, f64)) { - extern "Rust" { - fn get_f32_f64() -> (f32, f64); - } - // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] - // CHECK: calll {{()|_}}get_f32_f64 - // linux: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] - // linux-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] - // win: movss (%esp), %[[VAL1:.*]] - // win-NEXT: movsd 8(%esp), %[[VAL2:.*]] - // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) - // linux-NEXT: movsd %[[VAL2]], 4(%[[PTR]]) - // win-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) - *x = get_f32_f64(); -} - -// CHECK-LABEL: call_f64_f32: -#[no_mangle] -pub unsafe fn call_f64_f32(x: &mut (f64, f32)) { - extern "Rust" { - fn get_f64_f32() -> (f64, f32); - } - // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] - // CHECK: calll {{()|_}}get_f64_f32 - // linux: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] - // linux-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] - // win: movsd (%esp), %[[VAL1:.*]] - // win-NEXT: movss 8(%esp), %[[VAL2:.*]] - // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) - // CHECK-NEXT: movss %[[VAL2]], 8(%[[PTR]]) - *x = get_f64_f32(); -} - -// CHECK-LABEL: call_f32_other: -#[no_mangle] -pub unsafe fn call_f32_other(x: &mut (f32, usize)) { - extern "Rust" { - fn get_f32_other() -> (f32, usize); - } - // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] - // CHECK: calll {{()|_}}get_f32_other - // CHECK: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] - // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] - // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) - // CHECK-NEXT: movl %[[VAL2]], 4(%[[PTR]]) - *x = get_f32_other(); -} - -// CHECK-LABEL: call_f64_other: -#[no_mangle] -pub unsafe fn call_f64_other(x: &mut (f64, usize)) { - extern "Rust" { - fn get_f64_other() -> (f64, usize); - } - // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] - // CHECK: calll {{()|_}}get_f64_other - // linux: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] - // linux-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] - // win: movsd (%esp), %[[VAL1:.*]] - // win-NEXT: movl 8(%esp), %[[VAL2:.*]] - // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) - // CHECK-NEXT: movl %[[VAL2]], 8(%[[PTR]]) - *x = get_f64_other(); -} - -// CHECK-LABEL: call_other_f32: -#[no_mangle] -pub unsafe fn call_other_f32(x: &mut (usize, f32)) { - extern "Rust" { - fn get_other_f32() -> (usize, f32); - } - // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] - // CHECK: calll {{()|_}}get_other_f32 - // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] - // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] - // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) - // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) - *x = get_other_f32(); -} - -// CHECK-LABEL: call_other_f64: -#[no_mangle] -pub unsafe fn call_other_f64(x: &mut (usize, f64)) { - extern "Rust" { - fn get_other_f64() -> (usize, f64); - } - // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] - // CHECK: calll {{()|_}}get_other_f64 - // linux: movl [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] - // linux-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] - // win: movl (%esp), %[[VAL1:.*]] - // win-NEXT: movsd 8(%esp), %[[VAL2:.*]] - // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) - // linux-NEXT: movsd %[[VAL2]], 4(%[[PTR]]) - // win-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) - *x = get_other_f64(); -} - -// The "C" ABI for `f16` and `f128` on x86 has never used the x87 floating point stack. Do some -// basic checks to ensure this remains the case for the "Rust" ABI. - -// CHECK-LABEL: return_f16: -#[no_mangle] -pub fn return_f16(x: f16) -> f16 { - // CHECK: pushl %ebp - // linux-NEXT: .cfi_def_cfa_offset - // linux-NEXT: .cfi_offset - // CHECK-NEXT: movl %esp, %ebp - // linux-NEXT: .cfi_def_cfa_register - // CHECK-NEXT: pinsrw $0, 8(%ebp), %xmm0 - // CHECK-NEXT: popl %ebp - // linux-NEXT: .cfi_def_cfa - // CHECK-NEXT: retl - x -} - -// CHECK-LABEL: return_f128: -#[no_mangle] -pub fn return_f128(x: f128) -> f128 { - // CHECK: pushl %ebp - // linux-NEXT: .cfi_def_cfa_offset - // linux-NEXT: .cfi_offset - // CHECK-NEXT: movl %esp, %ebp - // linux-NEXT: .cfi_def_cfa_register - // linux-NEXT: movaps 8(%ebp), %xmm0 - // win-NEXT: movups 8(%ebp), %xmm0 - // CHECK-NEXT: popl %ebp - // linux-NEXT: .cfi_def_cfa - // CHECK-NEXT: retl - x -} diff --git a/tests/assembly/x86_64-array-pair-load-store-merge.rs b/tests/assembly/x86_64-array-pair-load-store-merge.rs deleted file mode 100644 index 56a1a9e8206..00000000000 --- a/tests/assembly/x86_64-array-pair-load-store-merge.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 -C llvm-args=-x86-asm-syntax=intel -//@ only-x86_64 -//@ ignore-sgx -//@ ignore-apple (manipulates rsp too) - -// Depending on various codegen choices, this might end up copying -// a `<2 x i8>`, an `i16`, or two `i8`s. -// Regardless of those choices, make sure the instructions use (2-byte) words. - -// CHECK-LABEL: array_copy_2_elements: -#[no_mangle] -pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) { - // CHECK-NOT: byte - // CHECK-NOT: mov - // CHECK: mov{{.+}}, word ptr - // CHECK-NEXT: mov word ptr - // CHECK-NEXT: ret - *p = *a; -} diff --git a/tests/assembly/x86_64-bigint-helpers.rs b/tests/assembly/x86_64-bigint-helpers.rs deleted file mode 100644 index 58785932bc2..00000000000 --- a/tests/assembly/x86_64-bigint-helpers.rs +++ /dev/null @@ -1,61 +0,0 @@ -//@ only-x86_64 -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 -C target-cpu=x86-64-v4 -//@ compile-flags: -C llvm-args=-x86-asm-syntax=intel -//@ revisions: llvm-pre-20 llvm-20 -//@ [llvm-20] min-llvm-version: 20 -//@ [llvm-pre-20] max-llvm-major-version: 19 - -#![no_std] -#![feature(bigint_helper_methods)] - -// This checks that the `carrying_add` and `borrowing_sub` implementation successfully chain, -// to catch issues like - -// This forces the ABI to avoid the windows-vs-linux ABI differences. - -// CHECK-LABEL: bigint_chain_carrying_add: -#[no_mangle] -pub unsafe extern "sysv64" fn bigint_chain_carrying_add( - dest: *mut u64, - src1: *const u64, - src2: *const u64, - n: usize, - mut carry: bool, -) -> bool { - // llvm-pre-20: mov [[TEMP:r..]], qword ptr [rsi + 8*[[IND:r..]] + 8] - // llvm-pre-20: adc [[TEMP]], qword ptr [rdx + 8*[[IND]] + 8] - // llvm-pre-20: mov qword ptr [rdi + 8*[[IND]] + 8], [[TEMP]] - // llvm-pre-20: mov [[TEMP]], qword ptr [rsi + 8*[[IND]] + 16] - // llvm-pre-20: adc [[TEMP]], qword ptr [rdx + 8*[[IND]] + 16] - // llvm-pre-20: mov qword ptr [rdi + 8*[[IND]] + 16], [[TEMP]] - // llvm-20: adc [[TEMP:r..]], qword ptr [rdx + 8*[[IND:r..]]] - // llvm-20: mov qword ptr [rdi + 8*[[IND]]], [[TEMP]] - // llvm-20: mov [[TEMP]], qword ptr [rsi + 8*[[IND]] + 8] - // llvm-20: adc [[TEMP]], qword ptr [rdx + 8*[[IND]] + 8] - for i in 0..n { - (*dest.add(i), carry) = u64::carrying_add(*src1.add(i), *src2.add(i), carry); - } - carry -} - -// CHECK-LABEL: bigint_chain_borrowing_sub: -#[no_mangle] -pub unsafe extern "sysv64" fn bigint_chain_borrowing_sub( - dest: *mut u64, - src1: *const u64, - src2: *const u64, - n: usize, - mut carry: bool, -) -> bool { - // CHECK: mov [[TEMP:r..]], qword ptr [rsi + 8*[[IND:r..]] + 8] - // CHECK: sbb [[TEMP]], qword ptr [rdx + 8*[[IND]] + 8] - // CHECK: mov qword ptr [rdi + 8*[[IND]] + 8], [[TEMP]] - // CHECK: mov [[TEMP]], qword ptr [rsi + 8*[[IND]] + 16] - // CHECK: sbb [[TEMP]], qword ptr [rdx + 8*[[IND]] + 16] - // CHECK: mov qword ptr [rdi + 8*[[IND]] + 16], [[TEMP]] - for i in 0..n { - (*dest.add(i), carry) = u64::borrowing_sub(*src1.add(i), *src2.add(i), carry); - } - carry -} diff --git a/tests/assembly/x86_64-cmp.rs b/tests/assembly/x86_64-cmp.rs deleted file mode 100644 index 26c9013d96f..00000000000 --- a/tests/assembly/x86_64-cmp.rs +++ /dev/null @@ -1,79 +0,0 @@ -//@ revisions: LLVM-PRE-20-DEBUG LLVM-20-DEBUG LLVM-PRE-20-OPTIM LLVM-20-OPTIM -//@ [LLVM-PRE-20-DEBUG] compile-flags: -C opt-level=0 -//@ [LLVM-PRE-20-DEBUG] max-llvm-major-version: 19 -//@ [LLVM-20-DEBUG] compile-flags: -C opt-level=0 -//@ [LLVM-20-DEBUG] min-llvm-version: 20 -//@ [LLVM-PRE-20-OPTIM] compile-flags: -C opt-level=3 -//@ [LLVM-PRE-20-OPTIM] max-llvm-major-version: 19 -//@ [LLVM-20-OPTIM] compile-flags: -C opt-level=3 -//@ [LLVM-20-OPTIM] min-llvm-version: 20 -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -C llvm-args=-x86-asm-syntax=intel -//@ only-x86_64 -//@ ignore-sgx - -#![feature(core_intrinsics)] - -use std::intrinsics::three_way_compare; - -#[no_mangle] -// CHECK-LABEL: signed_cmp: -pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering { - // LLVM-PRE-20-DEBUG: cmp - // LLVM-PRE-20-DEBUG: setg - // LLVM-PRE-20-DEBUG: and - // LLVM-PRE-20-DEBUG: cmp - // LLVM-PRE-20-DEBUG: setl - // LLVM-PRE-20-DEBUG: and - // LLVM-PRE-20-DEBUG: sub - // - // LLVM-20-DEBUG: sub - // LLVM-20-DEBUG: setl - // LLVM-20-DEBUG: setg - // LLVM-20-DEBUG: sub - // LLVM-20-DEBUG: ret - - // LLVM-PRE-20-OPTIM: xor - // LLVM-PRE-20-OPTIM: cmp - // LLVM-PRE-20-OPTIM: setne - // LLVM-PRE-20-OPTIM: mov - // LLVM-PRE-20-OPTIM: cmovge - // LLVM-PRE-20-OPTIM: ret - // - // LLVM-20-OPTIM: cmp - // LLVM-20-OPTIM: setl - // LLVM-20-OPTIM: setg - // LLVM-20-OPTIM: sub - // LLVM-20-OPTIM: ret - three_way_compare(a, b) -} - -#[no_mangle] -// CHECK-LABEL: unsigned_cmp: -pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering { - // LLVM-PRE-20-DEBUG: cmp - // LLVM-PRE-20-DEBUG: seta - // LLVM-PRE-20-DEBUG: and - // LLVM-PRE-20-DEBUG: cmp - // LLVM-PRE-20-DEBUG: setb - // LLVM-PRE-20-DEBUG: and - // LLVM-PRE-20-DEBUG: sub - // - // LLVM-20-DEBUG: sub - // LLVM-20-DEBUG: seta - // LLVM-20-DEBUG: sbb - // LLVM-20-DEBUG: ret - - // LLVM-PRE-20-OPTIM: xor - // LLVM-PRE-20-OPTIM: cmp - // LLVM-PRE-20-OPTIM: setne - // LLVM-PRE-20-OPTIM: mov - // LLVM-PRE-20-OPTIM: cmovae - // LLVM-PRE-20-OPTIM: ret - // - // LLVM-20-OPTIM: cmp - // LLVM-20-OPTIM: seta - // LLVM-20-OPTIM: sbb - // LLVM-20-OPTIM: ret - three_way_compare(a, b) -} diff --git a/tests/assembly/x86_64-floating-point-clamp.rs b/tests/assembly/x86_64-floating-point-clamp.rs deleted file mode 100644 index 6b0c29c5f21..00000000000 --- a/tests/assembly/x86_64-floating-point-clamp.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Floating-point clamp is designed to be implementable as max+min, -// so check to make sure that's what it's actually emitting. - -//@ assembly-output: emit-asm -// Set the base cpu explicitly, in case the default has been changed. -//@ compile-flags: --crate-type=lib -Copt-level=3 -C llvm-args=-x86-asm-syntax=intel -C target-cpu=x86-64 -//@ only-x86_64 -//@ ignore-sgx - -// CHECK-LABEL: clamp_demo: -#[no_mangle] -pub fn clamp_demo(a: f32, x: f32, y: f32) -> f32 { - // CHECK: maxss - // CHECK: minss - a.clamp(x, y) -} - -// CHECK-LABEL: clamp12_demo: -#[no_mangle] -pub fn clamp12_demo(a: f32) -> f32 { - // CHECK: movss xmm1 - // CHECK-NEXT: maxss xmm1, xmm0 - // CHECK-NEXT: movss xmm0 - // CHECK-NEXT: minss xmm0, xmm1 - // CHECK: ret - a.clamp(1.0, 2.0) -} diff --git a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs b/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs deleted file mode 100644 index f5e2f18e68e..00000000000 --- a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Test LVI load hardening on SGX enclave code - -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type staticlib -//@ only-x86_64-fortanix-unknown-sgx - -#[no_mangle] -pub extern "C" fn plus_one(r: &mut u64) { - *r = *r + 1; -} - -// CHECK: plus_one -// CHECK: lfence -// CHECK-NEXT: incq -// CHECK: popq [[REGISTER:%[a-z]+]] -// CHECK-NEXT: lfence -// CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs b/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs deleted file mode 100644 index f16d68fa255..00000000000 --- a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Test LVI ret hardening on generic rust code - -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type staticlib -//@ only-x86_64-fortanix-unknown-sgx - -#[no_mangle] -pub extern "C" fn myret() {} -// CHECK: myret: -// CHECK: popq [[REGISTER:%[a-z]+]] -// CHECK-NEXT: lfence -// CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs b/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs deleted file mode 100644 index a729df8e166..00000000000 --- a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Test LVI load hardening on SGX inline assembly code - -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type staticlib -//@ only-x86_64-fortanix-unknown-sgx - -use std::arch::asm; - -#[no_mangle] -pub extern "C" fn get(ptr: *const u64) -> u64 { - let value: u64; - unsafe { - asm!("mov {}, [{}]", - out(reg) value, - in(reg) ptr); - } - value -} - -// CHECK: get -// CHECK: movq -// CHECK-NEXT: lfence - -#[no_mangle] -pub extern "C" fn myret() { - unsafe { - asm!("ret"); - } -} - -// CHECK: myret -// CHECK: shlq $0, (%rsp) -// CHECK-NEXT: lfence -// CHECK-NEXT: retq diff --git a/tests/assembly/x86_64-function-return.rs b/tests/assembly/x86_64-function-return.rs deleted file mode 100644 index 7fd57200a9e..00000000000 --- a/tests/assembly/x86_64-function-return.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Test that the function return is (not) converted into a jump to the thunk -// when the `-Zfunction-return={keep,thunk-extern}` flag is (not) set. - -//@ revisions: unset keep thunk-extern keep-thunk-extern thunk-extern-keep -//@ assembly-output: emit-asm -//@ compile-flags: -Copt-level=3 -//@ [keep] compile-flags: -Zfunction-return=keep -//@ [thunk-extern] compile-flags: -Zfunction-return=thunk-extern -//@ [keep-thunk-extern] compile-flags: -Zfunction-return=keep -Zfunction-return=thunk-extern -//@ [thunk-extern-keep] compile-flags: -Zfunction-return=thunk-extern -Zfunction-return=keep -//@ only-x86_64 -//@ ignore-apple Symbol is called `___x86_return_thunk` (Darwin's extra underscore) -//@ ignore-sgx Tests incompatible with LVI mitigations - -#![crate_type = "lib"] - -// CHECK-LABEL: foo: -#[no_mangle] -pub unsafe fn foo() { - // unset: ret - // unset-NOT: jmp __x86_return_thunk - // keep: ret - // keep-NOT: jmp __x86_return_thunk - // thunk-extern: jmp __x86_return_thunk - // thunk-extern-NOT: ret - // keep-thunk-extern: jmp __x86_return_thunk - // keep-thunk-extern-NOT: ret - // thunk-extern-keep: ret - // thunk-extern-keep-NOT: jmp __x86_return_thunk -} diff --git a/tests/assembly/x86_64-no-jump-tables.rs b/tests/assembly/x86_64-no-jump-tables.rs deleted file mode 100644 index bb10042d8f6..00000000000 --- a/tests/assembly/x86_64-no-jump-tables.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Test that jump tables are (not) emitted when the `-Zno-jump-tables` -// flag is (not) set. - -//@ revisions: unset set -//@ assembly-output: emit-asm -//@ compile-flags: -Copt-level=3 -//@ [set] compile-flags: -Zno-jump-tables -//@ only-x86_64 -//@ ignore-sgx - -#![crate_type = "lib"] - -extern "C" { - fn bar1(); - fn bar2(); - fn bar3(); - fn bar4(); - fn bar5(); - fn bar6(); -} - -// CHECK-LABEL: foo: -#[no_mangle] -pub unsafe fn foo(x: i32) { - // unset: LJTI0_0 - // set-NOT: LJTI0_0 - match x { - 1 => bar1(), - 2 => bar2(), - 3 => bar3(), - 4 => bar4(), - 5 => bar5(), - _ => bar6(), - } -} diff --git a/tests/assembly/x86_64-sse_crc.rs b/tests/assembly/x86_64-sse_crc.rs deleted file mode 100644 index bde58955a21..00000000000 --- a/tests/assembly/x86_64-sse_crc.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ only-x86_64 -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type staticlib -Ctarget-feature=+sse4.2 - -// CHECK-LABEL: banana -// CHECK: crc32 -#[no_mangle] -pub unsafe fn banana(v: u8) -> u32 { - use std::arch::x86_64::*; - let out = !0u32; - _mm_crc32_u8(out, v) -} diff --git a/tests/assembly/x86_64-typed-swap.rs b/tests/assembly/x86_64-typed-swap.rs deleted file mode 100644 index a6753011d36..00000000000 --- a/tests/assembly/x86_64-typed-swap.rs +++ /dev/null @@ -1,81 +0,0 @@ -//@ revisions: WIN LIN -//@ [WIN] only-windows -//@ [LIN] only-linux -//@ only-x86_64 -//@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 - -use std::arch::x86_64::__m128; -use std::mem::swap; - -// CHECK-LABEL: swap_i32: -#[no_mangle] -pub fn swap_i32(x: &mut i32, y: &mut i32) { - // CHECK: movl (%[[ARG1:.+]]), %[[T1:.+]] - // CHECK-NEXT: movl (%[[ARG2:.+]]), %[[T2:.+]] - // CHECK-DAG: movl %[[T2]], (%[[ARG1]]) - // CHECK-DAG: movl %[[T1]], (%[[ARG2]]) - // CHECK-NEXT: retq - swap(x, y) -} - -// CHECK-LABEL: swap_pair: -#[no_mangle] -pub fn swap_pair(x: &mut (i32, u32), y: &mut (i32, u32)) { - // CHECK: movq (%[[ARG1:r..?]]), %[[T1:.+]] - // CHECK-NEXT: movq (%[[ARG2:r..?]]), %[[T2:.+]] - // CHECK-DAG: movq %[[T2]], (%[[ARG1]]) - // CHECK-DAG: movq %[[T1]], (%[[ARG2]]) - // CHECK-NEXT: retq - swap(x, y) -} - -// CHECK-LABEL: swap_str: -#[no_mangle] -pub fn swap_str<'a>(x: &mut &'a str, y: &mut &'a str) { - // CHECK: movups (%[[ARG1:r..?]]), %[[T1:xmm.]] - // CHECK-NEXT: movups (%[[ARG2:r..?]]), %[[T2:xmm.]] - // CHECK-DAG: movups %[[T2]], (%[[ARG1]]) - // CHECK-DAG: movups %[[T1]], (%[[ARG2]]) - // CHECK-NEXT: retq - swap(x, y) -} - -// CHECK-LABEL: swap_simd: -#[no_mangle] -pub fn swap_simd(x: &mut __m128, y: &mut __m128) { - // CHECK: movaps (%[[ARG1:r..?]]), %[[T1:xmm.]] - // CHECK-NEXT: movaps (%[[ARG2:r..?]]), %[[T2:xmm.]] - // CHECK-DAG: movaps %[[T2]], (%[[ARG1]]) - // CHECK-DAG: movaps %[[T1]], (%[[ARG2]]) - // CHECK-NEXT: retq - swap(x, y) -} - -// CHECK-LABEL: swap_string: -#[no_mangle] -pub fn swap_string(x: &mut String, y: &mut String) { - // CHECK-NOT: mov - // CHECK-COUNT-4: movups - // CHECK-NOT: mov - // CHECK-COUNT-4: movq - // CHECK-NOT: mov - swap(x, y) -} - -// CHECK-LABEL: swap_44_bytes: -#[no_mangle] -pub fn swap_44_bytes(x: &mut [u8; 44], y: &mut [u8; 44]) { - // Ensure we do better than a long run of byte copies, - // see - - // CHECK-NOT: movb - // CHECK-COUNT-8: movups{{.+}}xmm - // CHECK-NOT: movb - // CHECK-COUNT-4: movq - // CHECK-NOT: movb - // CHECK-COUNT-4: movl - // CHECK-NOT: movb - // CHECK: retq - swap(x, y) -} diff --git a/tests/assembly/x86_64-windows-float-abi.rs b/tests/assembly/x86_64-windows-float-abi.rs deleted file mode 100644 index cbc80910851..00000000000 --- a/tests/assembly/x86_64-windows-float-abi.rs +++ /dev/null @@ -1,46 +0,0 @@ -//@ assembly-output: emit-asm -//@ compile-flags: -Copt-level=3 -//@ compile-flags: --target x86_64-pc-windows-msvc -//@ needs-llvm-components: x86 -//@ add-core-stubs - -#![feature(f16, f128)] -#![feature(no_core)] -#![no_core] -#![crate_type = "lib"] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: second_f16 -// CHECK: movaps %xmm1, %xmm0 -// CHECK-NEXT: retq -#[no_mangle] -pub extern "C" fn second_f16(_: f16, x: f16) -> f16 { - x -} - -// CHECK-LABEL: second_f32 -// CHECK: movaps %xmm1, %xmm0 -// CHECK-NEXT: retq -#[no_mangle] -pub extern "C" fn second_f32(_: f32, x: f32) -> f32 { - x -} - -// CHECK-LABEL: second_f64 -// CHECK: movaps %xmm1, %xmm0 -// CHECK-NEXT: retq -#[no_mangle] -pub extern "C" fn second_f64(_: f64, x: f64) -> f64 { - x -} - -// CHECK-LABEL: second_f128 -// FIXME(llvm21): this can be just %rdx instead of the regex once we don't test on LLVM 20 -// CHECK: movaps {{(%xmm1|\(%rdx\))}}, %xmm0 -// CHECK-NEXT: retq -#[no_mangle] -pub extern "C" fn second_f128(_: f128, x: f128) -> f128 { - x -} diff --git a/tests/assembly/x86_64-windows-i128-abi.rs b/tests/assembly/x86_64-windows-i128-abi.rs deleted file mode 100644 index d2aefb7daa6..00000000000 --- a/tests/assembly/x86_64-windows-i128-abi.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ assembly-output: emit-asm -//@ add-core-stubs -//@ revisions: msvc softfloat -//@ compile-flags: -Copt-level=3 -//@[msvc] compile-flags: --target x86_64-pc-windows-msvc -//@[msvc] needs-llvm-components: x86 -//@[softfloat] compile-flags: --target x86_64-unknown-uefi -//@[softfloat] needs-llvm-components: x86 - -#![feature(no_core)] -#![no_core] -#![crate_type = "lib"] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: ret_i128 -// Hardfloat targets return via xmm0, softfloat targets via rax and rdx. -// msvc: movaps {{.*}}, %xmm0 -// softfloat: movq (%[[INPUT:.*]]), %rax -// softfloat-NEXT: movq 8(%[[INPUT]]), %rdx -// CHECK-NEXT: retq -#[no_mangle] -pub extern "C" fn ret_i128(x: &i128) -> i128 { - *x -} diff --git a/tests/assembly/x86_64-xray.rs b/tests/assembly/x86_64-xray.rs deleted file mode 100644 index 4cf3e8cda13..00000000000 --- a/tests/assembly/x86_64-xray.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ assembly-output: emit-asm -//@ compile-flags: -Zinstrument-xray=always -Cllvm-args=-x86-asm-syntax=intel - -//@ revisions: x86_64-linux -//@[x86_64-linux] compile-flags: --target=x86_64-unknown-linux-gnu -//@[x86_64-linux] needs-llvm-components: x86 -//@[x86_64-linux] only-x86_64-unknown-linux-gnu - -//@ revisions: x86_64-darwin -//@[x86_64-darwin] compile-flags: --target=x86_64-apple-darwin -//@[x86_64-darwin] needs-llvm-components: x86 -//@[x86_64-darwin] only-x86_64-apple-darwin - -#![crate_type = "lib"] - -// CHECK-LABEL: xray_func: -#[no_mangle] -pub fn xray_func() { - // CHECK: nop word ptr [rax + rax + 512] - - std::hint::black_box(()); - - // CHECK: ret - // CHECK-NEXT: nop word ptr cs:[rax + rax + 512] -} diff --git a/tests/codegen/target-feature-overrides.rs b/tests/codegen/target-feature-overrides.rs index eb19b0de2fa..63a586d388b 100644 --- a/tests/codegen/target-feature-overrides.rs +++ b/tests/codegen/target-feature-overrides.rs @@ -6,7 +6,7 @@ //@ [COMPAT] compile-flags: -Ctarget-feature=+avx2 //@ [INCOMPAT] compile-flags: -Ctarget-feature=-avx2,-avx -// See also tests/assembly/target-feature-multiple.rs +// See also tests/assembly-llvm/target-feature-multiple.rs #![feature(no_core, lang_items)] #![crate_type = "lib"] #![no_core] diff --git a/tests/run-make/avr-rjmp-offset/rmake.rs b/tests/run-make/avr-rjmp-offset/rmake.rs index da314f26ca7..86d85e89f78 100644 --- a/tests/run-make/avr-rjmp-offset/rmake.rs +++ b/tests/run-make/avr-rjmp-offset/rmake.rs @@ -6,7 +6,7 @@ //! loop instruction to be missed. This test therefore contains a simple loop //! with trivial instructions in it, to see, where the label is placed. //! -//! This must be a `rmake`-test and cannot be a `tests/assembly`-test, since the +//! This must be a `rmake`-test and cannot be a `tests/assembly-llvm/`-test, since the //! wrong output is only produced with direct assembly generation, but not when //! "emit-asm" is used, as described in the issue description of #129301: //! https://github.com/rust-lang/rust/issues/129301#issue-2475070770 diff --git a/triagebot.toml b/triagebot.toml index 61d8a814c89..e34e4a88f42 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -302,7 +302,7 @@ trigger_files = [ "compiler", # Tests - "tests/assembly", + "tests/assembly-llvm", "tests/auxiliary", "tests/codegen", "tests/codegen-units", -- cgit 1.4.1-3-g733a5 From a27f3e3fd1e4d16160f8885b6b06665b5319f56c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 21 Jul 2025 14:34:12 +0200 Subject: Rename `tests/codegen` into `tests/codegen-llvm` --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- .../rustc_mir_transform/src/unreachable_prop.rs | 2 +- library/alloc/src/collections/vec_deque/drain.rs | 2 +- library/alloc/src/raw_vec/mod.rs | 2 +- rustfmt.toml | 4 +- src/bootstrap/src/core/build_steps/test.rs | 11 +- src/bootstrap/src/core/builder/mod.rs | 4 +- src/ci/docker/host-x86_64/test-various/Dockerfile | 2 +- src/doc/rustc-dev-guide/src/asm.md | 2 +- .../rustc-dev-guide/src/autodiff/installation.md | 2 +- .../src/llvm-coverage-instrumentation.md | 4 +- .../rustc-dev-guide/src/offload/installation.md | 2 +- .../src/profile-guided-optimization.md | 2 +- src/doc/rustc-dev-guide/src/sanitizers.md | 4 +- src/doc/rustc-dev-guide/src/tests/compiletest.md | 6 +- src/tools/opt-dist/src/tests.rs | 2 +- tests/assembly-llvm/target-feature-multiple.rs | 2 +- tests/codegen-llvm/README.md | 24 + tests/codegen-llvm/aarch64-softfloat.rs | 45 ++ tests/codegen-llvm/aarch64-struct-align-128.rs | 145 ++++ tests/codegen-llvm/abi-efiapi.rs | 30 + .../codegen-llvm/abi-main-signature-16bit-c-int.rs | 11 + .../codegen-llvm/abi-main-signature-32bit-c-int.rs | 11 + tests/codegen-llvm/abi-repr-ext.rs | 56 ++ tests/codegen-llvm/abi-sysv64.rs | 20 + tests/codegen-llvm/abi-win64-zst.rs | 54 ++ tests/codegen-llvm/abi-x86-interrupt.rs | 18 + tests/codegen-llvm/abi-x86-sse.rs | 43 ++ tests/codegen-llvm/abi-x86_64_sysv.rs | 29 + tests/codegen-llvm/addr-of-mutate.rs | 33 + tests/codegen-llvm/adjustments.rs | 28 + .../codegen-llvm/align-byval-alignment-mismatch.rs | 126 ++++ tests/codegen-llvm/align-byval-vector.rs | 55 ++ tests/codegen-llvm/align-byval.rs | 315 +++++++++ tests/codegen-llvm/align-enum.rs | 33 + tests/codegen-llvm/align-fn.rs | 143 ++++ tests/codegen-llvm/align-offset.rs | 75 ++ tests/codegen-llvm/align-struct.rs | 70 ++ tests/codegen-llvm/alloc-optimisation.rs | 13 + tests/codegen-llvm/amdgpu-addrspacecast.rs | 18 + tests/codegen-llvm/array-clone.rs | 15 + tests/codegen-llvm/array-cmp.rs | 74 ++ tests/codegen-llvm/array-codegen.rs | 62 ++ tests/codegen-llvm/array-equality.rs | 101 +++ tests/codegen-llvm/array-from_fn.rs | 13 + tests/codegen-llvm/array-map.rs | 35 + tests/codegen-llvm/array-optimized.rs | 33 + tests/codegen-llvm/array-repeat.rs | 15 + tests/codegen-llvm/ascii-char.rs | 36 + tests/codegen-llvm/asm/aarch64-clobbers.rs | 47 ++ tests/codegen-llvm/asm/avr-clobbers.rs | 39 ++ tests/codegen-llvm/asm/bpf-clobbers.rs | 31 + tests/codegen-llvm/asm/critical.rs | 36 + tests/codegen-llvm/asm/csky-clobbers.rs | 24 + tests/codegen-llvm/asm/foo.s | 3 + tests/codegen-llvm/asm/global_asm.rs | 28 + tests/codegen-llvm/asm/global_asm_include.rs | 21 + tests/codegen-llvm/asm/global_asm_x2.rs | 47 ++ tests/codegen-llvm/asm/goto.rs | 63 ++ tests/codegen-llvm/asm/hexagon-clobbers.rs | 33 + tests/codegen-llvm/asm/may_unwind.rs | 39 ++ tests/codegen-llvm/asm/maybe-uninit.rs | 27 + tests/codegen-llvm/asm/msp430-clobbers.rs | 32 + tests/codegen-llvm/asm/multiple-options.rs | 54 ++ tests/codegen-llvm/asm/options.rs | 104 +++ tests/codegen-llvm/asm/powerpc-clobbers.rs | 68 ++ tests/codegen-llvm/asm/riscv-clobbers.rs | 40 ++ tests/codegen-llvm/asm/s390x-clobbers.rs | 46 ++ tests/codegen-llvm/asm/sanitize-llvm.rs | 24 + tests/codegen-llvm/asm/sparc-clobbers.rs | 36 + tests/codegen-llvm/asm/x86-clobber_abi.rs | 36 + tests/codegen-llvm/asm/x86-clobbers.rs | 20 + tests/codegen-llvm/asm/x86-target-clobbers.rs | 29 + tests/codegen-llvm/assign-desugar-debuginfo.rs | 18 + tests/codegen-llvm/async-closure-debug.rs | 20 + tests/codegen-llvm/async-fn-debug-awaitee-field.rs | 28 + tests/codegen-llvm/async-fn-debug-msvc.rs | 55 ++ tests/codegen-llvm/async-fn-debug.rs | 59 ++ tests/codegen-llvm/atomic-operations.rs | 84 +++ tests/codegen-llvm/atomicptr.rs | 36 + tests/codegen-llvm/autodiff/batched.rs | 116 +++ tests/codegen-llvm/autodiff/generic.rs | 42 ++ tests/codegen-llvm/autodiff/identical_fnc.rs | 45 ++ tests/codegen-llvm/autodiff/inline.rs | 23 + tests/codegen-llvm/autodiff/scalar.rs | 33 + tests/codegen-llvm/autodiff/sret.rs | 45 ++ tests/codegen-llvm/autodiffv2.rs | 113 +++ .../autovec/dont-shuffle-bswaps-opt2.rs | 31 + .../autovec/dont-shuffle-bswaps-opt3.rs | 42 ++ tests/codegen-llvm/autovectorize-f32x4.rs | 37 + tests/codegen-llvm/auxiliary/extern_decl.rs | 13 + tests/codegen-llvm/auxiliary/nounwind.rs | 2 + tests/codegen-llvm/auxiliary/thread_local_aux.rs | 5 + tests/codegen-llvm/avr/avr-func-addrspace.rs | 106 +++ tests/codegen-llvm/bigint-helpers.rs | 13 + .../binary-heap-peek-mut-pop-no-panic.rs | 13 + .../binary-search-index-no-bound-check.rs | 35 + tests/codegen-llvm/bool-cmp.rs | 18 + .../bounds-checking/gep-issue-133979.rs | 22 + tests/codegen-llvm/box-default-debug-copies.rs | 28 + tests/codegen-llvm/box-uninit-bytes.rs | 46 ++ tests/codegen-llvm/bpf-alu32.rs | 11 + tests/codegen-llvm/branch-protection.rs | 94 +++ tests/codegen-llvm/call-llvm-intrinsics.rs | 30 + tests/codegen-llvm/call-tmps-lifetime.rs | 68 ++ tests/codegen-llvm/cast-optimized.rs | 33 + tests/codegen-llvm/cast-target-abi.rs | 599 ++++++++++++++++ tests/codegen-llvm/catch-unwind.rs | 32 + tests/codegen-llvm/cdylib-external-inline-fns.rs | 43 ++ tests/codegen-llvm/cf-protection.rs | 38 + tests/codegen-llvm/cffi/c-variadic-copy.rs | 16 + tests/codegen-llvm/cffi/c-variadic-naked.rs | 15 + tests/codegen-llvm/cffi/c-variadic-opt.rs | 30 + tests/codegen-llvm/cffi/c-variadic.rs | 71 ++ tests/codegen-llvm/cffi/ffi-const.rs | 15 + tests/codegen-llvm/cffi/ffi-out-of-bounds-loads.rs | 41 ++ tests/codegen-llvm/cffi/ffi-pure.rs | 15 + tests/codegen-llvm/cfguard-checks.rs | 10 + tests/codegen-llvm/cfguard-disabled.rs | 10 + tests/codegen-llvm/cfguard-nochecks.rs | 10 + tests/codegen-llvm/cfguard-non-msvc.rs | 10 + tests/codegen-llvm/char-ascii-branchless.rs | 47 ++ .../char-escape-debug-no-bounds-check.rs | 14 + tests/codegen-llvm/checked_ilog.rs | 20 + tests/codegen-llvm/checked_math.rs | 100 +++ tests/codegen-llvm/clone-shims.rs | 15 + tests/codegen-llvm/clone_as_copy.rs | 40 ++ tests/codegen-llvm/codemodels.rs | 20 + tests/codegen-llvm/coercions.rs | 19 + tests/codegen-llvm/cold-call-declare-and-call.rs | 27 + tests/codegen-llvm/common_prim_int_ptr.rs | 51 ++ .../codegen-llvm/comparison-operators-2-struct.rs | 61 ++ tests/codegen-llvm/comparison-operators-2-tuple.rs | 117 ++++ tests/codegen-llvm/comparison-operators-newtype.rs | 48 ++ .../compiletest-self-test/minicore-smoke-test.rs | 20 + tests/codegen-llvm/const-array.rs | 15 + tests/codegen-llvm/const-vector.rs | 78 +++ tests/codegen-llvm/const_scalar_pair.rs | 8 + tests/codegen-llvm/constant-branch.rs | 49 ++ tests/codegen-llvm/consts.rs | 55 ++ tests/codegen-llvm/coroutine-debug-msvc.rs | 60 ++ tests/codegen-llvm/coroutine-debug.rs | 64 ++ .../cross-crate-inlining/always-inline.rs | 13 + .../cross-crate-inlining/auxiliary/always.rs | 20 + .../cross-crate-inlining/auxiliary/leaf.rs | 20 + .../cross-crate-inlining/auxiliary/never.rs | 20 + .../cross-crate-inlining/leaf-inlining.rs | 20 + .../cross-crate-inlining/never-inline.rs | 13 + tests/codegen-llvm/dealloc-no-unwind.rs | 25 + .../codegen-llvm/debug-accessibility/crate-enum.rs | 28 + .../debug-accessibility/crate-struct.rs | 23 + .../debug-accessibility/private-enum.rs | 22 + .../debug-accessibility/private-struct.rs | 17 + .../debug-accessibility/public-enum.rs | 23 + .../debug-accessibility/public-struct.rs | 17 + .../debug-accessibility/struct-fields.rs | 30 + .../codegen-llvm/debug-accessibility/super-enum.rs | 28 + .../debug-accessibility/super-struct.rs | 23 + .../debug-accessibility/tuple-fields.rs | 24 + tests/codegen-llvm/debug-alignment.rs | 8 + tests/codegen-llvm/debug-column-msvc.rs | 16 + tests/codegen-llvm/debug-column.rs | 25 + tests/codegen-llvm/debug-compile-unit-path.rs | 9 + tests/codegen-llvm/debug-fndef-size.rs | 20 + tests/codegen-llvm/debug-limited.rs | 27 + tests/codegen-llvm/debug-line-directives-only.rs | 27 + tests/codegen-llvm/debug-line-tables-only.rs | 27 + tests/codegen-llvm/debug-linkage-name.rs | 42 ++ tests/codegen-llvm/debug-vtable.rs | 117 ++++ tests/codegen-llvm/debuginfo-constant-locals.rs | 28 + .../debuginfo-generic-closure-env-names.rs | 90 +++ .../debuginfo-inline-callsite-location.rs | 27 + .../debuginfo-proc-macro/auxiliary/macro_def.rs | 7 + .../mir_inlined_twice_var_locs.rs | 52 ++ tests/codegen-llvm/deduced-param-attrs.rs | 60 ++ tests/codegen-llvm/default-requires-uwtable.rs | 17 + tests/codegen-llvm/default-visibility.rs | 49 ++ tests/codegen-llvm/direct-access-external-data.rs | 21 + tests/codegen-llvm/dllimports/auxiliary/dummy.rs | 6 + tests/codegen-llvm/dllimports/auxiliary/wrapper.rs | 14 + tests/codegen-llvm/dllimports/main.rs | 43 ++ ...gen_private_const_fn_only_used_in_const_eval.rs | 27 + tests/codegen-llvm/drop-in-place-noalias.rs | 38 + tests/codegen-llvm/drop.rs | 36 + tests/codegen-llvm/dst-offset.rs | 84 +++ tests/codegen-llvm/dst-vtable-align-nonzero.rs | 67 ++ tests/codegen-llvm/dst-vtable-size-range.rs | 35 + tests/codegen-llvm/ehcontguard_disabled.rs | 9 + tests/codegen-llvm/ehcontguard_enabled.rs | 9 + .../codegen-llvm/emscripten-catch-unwind-js-eh.rs | 71 ++ .../emscripten-catch-unwind-wasm-eh.rs | 69 ++ tests/codegen-llvm/enable-lto-unit-splitting.rs | 9 + tests/codegen-llvm/enum/enum-aggregate.rs | 126 ++++ .../enum/enum-bounds-check-derived-idx.rs | 24 + .../enum/enum-bounds-check-issue-13926.rs | 18 + .../enum/enum-bounds-check-issue-82871.rs | 18 + tests/codegen-llvm/enum/enum-bounds-check.rs | 27 + tests/codegen-llvm/enum/enum-debug-clike.rs | 28 + tests/codegen-llvm/enum/enum-debug-niche-2.rs | 47 ++ tests/codegen-llvm/enum/enum-debug-niche.rs | 35 + tests/codegen-llvm/enum/enum-debug-tagged.rs | 31 + tests/codegen-llvm/enum/enum-discriminant-eq.rs | 223 ++++++ tests/codegen-llvm/enum/enum-discriminant-value.rs | 27 + .../enum/enum-early-otherwise-branch.rs | 25 + tests/codegen-llvm/enum/enum-match.rs | 779 +++++++++++++++++++++ tests/codegen-llvm/enum/enum-two-variants-match.rs | 130 ++++ tests/codegen-llvm/enum/enum-u128.rs | 25 + .../enum/unreachable_enum_default_branch.rs | 40 ++ tests/codegen-llvm/ergonomic-clones/closure.rs | 55 ++ tests/codegen-llvm/error-provide.rs | 50 ++ tests/codegen-llvm/export-no-mangle.rs | 31 + tests/codegen-llvm/external-no-mangle-fns.rs | 75 ++ tests/codegen-llvm/external-no-mangle-statics.rs | 77 ++ tests/codegen-llvm/f128-wasm32-callconv.rs | 49 ++ tests/codegen-llvm/fastcall-inreg.rs | 40 ++ tests/codegen-llvm/fatptr.rs | 12 + tests/codegen-llvm/fewer-names.rs | 19 + tests/codegen-llvm/fixed-x18.rs | 23 + tests/codegen-llvm/float/algebraic.rs | 149 ++++ tests/codegen-llvm/float/f128.rs | 441 ++++++++++++ tests/codegen-llvm/float/f16-f128-inline.rs | 29 + tests/codegen-llvm/float/f16.rs | 364 ++++++++++ tests/codegen-llvm/float_math.rs | 87 +++ tests/codegen-llvm/fn-impl-trait-self.rs | 17 + .../fn-parameters-on-different-lines-debuginfo.rs | 22 + tests/codegen-llvm/force-frame-pointers.rs | 18 + tests/codegen-llvm/force-no-unwind-tables.rs | 11 + tests/codegen-llvm/force-unwind-tables.rs | 6 + tests/codegen-llvm/frame-pointer-cli-control.rs | 61 ++ tests/codegen-llvm/frame-pointer.rs | 35 + tests/codegen-llvm/function-arguments-noopt.rs | 69 ++ tests/codegen-llvm/function-arguments.rs | 278 ++++++++ tests/codegen-llvm/function-return.rs | 35 + tests/codegen-llvm/gdb_debug_script_load.rs | 37 + tests/codegen-llvm/generic-debug.rs | 17 + tests/codegen-llvm/gep-index.rs | 37 + tests/codegen-llvm/gpu-kernel-abi.rs | 15 + tests/codegen-llvm/gpu_offload/gpu_host.rs | 80 +++ tests/codegen-llvm/hint/cold_path.rs | 54 ++ tests/codegen-llvm/hint/likely.rs | 81 +++ tests/codegen-llvm/hint/unlikely.rs | 80 +++ tests/codegen-llvm/i128-wasm32-callconv.rs | 49 ++ tests/codegen-llvm/i128-x86-align.rs | 105 +++ tests/codegen-llvm/i128-x86-callconv.rs | 87 +++ tests/codegen-llvm/infallible-unwrap-in-opt-z.rs | 26 + tests/codegen-llvm/inherit_overflow.rs | 14 + tests/codegen-llvm/inline-always-works-always.rs | 21 + tests/codegen-llvm/inline-debuginfo.rs | 17 + .../inline-function-args-debug-info.rs | 23 + tests/codegen-llvm/inline-hint.rs | 31 + .../instrument-coverage/instrument-coverage-off.rs | 21 + .../instrument-coverage/instrument-coverage.rs | 22 + tests/codegen-llvm/instrument-coverage/testprog.rs | 118 ++++ tests/codegen-llvm/instrument-mcount.rs | 7 + tests/codegen-llvm/instrument-xray/basic.rs | 9 + .../instrument-xray/options-combine.rs | 12 + .../instrument-xray/options-override.rs | 11 + tests/codegen-llvm/integer-cmp.rs | 62 ++ tests/codegen-llvm/integer-overflow.rs | 24 + tests/codegen-llvm/internalize-closures.rs | 13 + tests/codegen-llvm/intrinsic-no-unnamed-attr.rs | 13 + .../intrinsics/aggregate-thin-pointer.rs | 23 + tests/codegen-llvm/intrinsics/carrying_mul_add.rs | 136 ++++ tests/codegen-llvm/intrinsics/cold_path.rs | 13 + tests/codegen-llvm/intrinsics/cold_path2.rs | 37 + tests/codegen-llvm/intrinsics/cold_path3.rs | 87 +++ tests/codegen-llvm/intrinsics/compare_bytes.rs | 34 + tests/codegen-llvm/intrinsics/const_eval_select.rs | 22 + tests/codegen-llvm/intrinsics/ctlz.rs | 56 ++ tests/codegen-llvm/intrinsics/ctpop.rs | 31 + tests/codegen-llvm/intrinsics/disjoint_bitor.rs | 30 + tests/codegen-llvm/intrinsics/exact_div.rs | 20 + tests/codegen-llvm/intrinsics/likely.rs | 35 + tests/codegen-llvm/intrinsics/likely_assert.rs | 17 + tests/codegen-llvm/intrinsics/mask.rs | 12 + tests/codegen-llvm/intrinsics/nontemporal.rs | 32 + tests/codegen-llvm/intrinsics/offset.rs | 33 + tests/codegen-llvm/intrinsics/offset_from.rs | 36 + tests/codegen-llvm/intrinsics/prefetch.rs | 64 ++ tests/codegen-llvm/intrinsics/ptr_metadata.rs | 36 + tests/codegen-llvm/intrinsics/rotate_left.rs | 31 + .../rustc_intrinsic_must_be_overridden.rs | 14 + .../intrinsics/select_unpredictable.rs | 71 ++ tests/codegen-llvm/intrinsics/three_way_compare.rs | 28 + tests/codegen-llvm/intrinsics/transmute-niched.rs | 223 ++++++ tests/codegen-llvm/intrinsics/transmute-x64.rs | 28 + tests/codegen-llvm/intrinsics/transmute.rs | 497 +++++++++++++ tests/codegen-llvm/intrinsics/typed_swap.rs | 77 ++ tests/codegen-llvm/intrinsics/unchecked_math.rs | 46 ++ tests/codegen-llvm/intrinsics/unlikely.rs | 35 + tests/codegen-llvm/intrinsics/volatile.rs | 55 ++ tests/codegen-llvm/intrinsics/volatile_order.rs | 18 + tests/codegen-llvm/is_val_statically_known.rs | 163 +++++ tests/codegen-llvm/issue-97217.rs | 20 + tests/codegen-llvm/issues/issue-101048.rs | 12 + tests/codegen-llvm/issues/issue-101082.rs | 42 ++ tests/codegen-llvm/issues/issue-101814.rs | 18 + tests/codegen-llvm/issues/issue-103132.rs | 15 + .../issues/issue-103285-ptr-addr-overflow-check.rs | 15 + tests/codegen-llvm/issues/issue-103327.rs | 13 + tests/codegen-llvm/issues/issue-103840.rs | 9 + .../issues/issue-105386-ub-in-debuginfo.rs | 24 + tests/codegen-llvm/issues/issue-106369.rs | 14 + .../issues/issue-107681-unwrap_unchecked.rs | 19 + .../issues/issue-108395-branchy-bool-match.rs | 27 + .../issues/issue-109328-split_first.rs | 16 + .../issues/issue-110797-enum-jump-same.rs | 25 + tests/codegen-llvm/issues/issue-111603.rs | 40 ++ .../issues/issue-112509-slice-get-andthen-get.rs | 16 + .../issue-113757-bounds-check-after-cmp-max.rs | 18 + tests/codegen-llvm/issues/issue-114312.rs | 25 + .../issues/issue-115385-llvm-jump-threading.rs | 46 ++ tests/codegen-llvm/issues/issue-116878.rs | 11 + tests/codegen-llvm/issues/issue-118306.rs | 22 + tests/codegen-llvm/issues/issue-118392.rs | 10 + tests/codegen-llvm/issues/issue-119422.rs | 83 +++ .../issues/issue-121719-common-field-offset.rs | 44 ++ .../issues/issue-122600-ptr-discriminant-update.rs | 43 ++ .../issue-123712-str-to-lower-autovectorization.rs | 23 + tests/codegen-llvm/issues/issue-126585.rs | 23 + tests/codegen-llvm/issues/issue-129795.rs | 17 + tests/codegen-llvm/issues/issue-13018.rs | 14 + .../issues/issue-136329-optnone-noinline.rs | 21 + tests/codegen-llvm/issues/issue-15953.rs | 29 + tests/codegen-llvm/issues/issue-27130.rs | 21 + tests/codegen-llvm/issues/issue-32031.rs | 29 + tests/codegen-llvm/issues/issue-32364.rs | 17 + tests/codegen-llvm/issues/issue-34634.rs | 16 + tests/codegen-llvm/issues/issue-34947-pow-i32.rs | 13 + .../issues/issue-36010-some-box-is_some.rs | 28 + tests/codegen-llvm/issues/issue-37945.rs | 34 + tests/codegen-llvm/issues/issue-45222.rs | 62 ++ tests/codegen-llvm/issues/issue-45466.rs | 14 + .../issues/issue-45964-bounds-check-slice-pos.rs | 38 + tests/codegen-llvm/issues/issue-47278.rs | 11 + tests/codegen-llvm/issues/issue-47442.rs | 22 + tests/codegen-llvm/issues/issue-56267-2.rs | 18 + tests/codegen-llvm/issues/issue-56267.rs | 18 + tests/codegen-llvm/issues/issue-56927.rs | 46 ++ tests/codegen-llvm/issues/issue-58881.rs | 20 + tests/codegen-llvm/issues/issue-59352.rs | 18 + ...4219-fn-ptr-call-returning-never-is-noreturn.rs | 19 + .../issues/issue-68667-unwrap-combinators.rs | 15 + .../issues/issue-69101-bounds-check.rs | 42 ++ tests/codegen-llvm/issues/issue-73031.rs | 22 + tests/codegen-llvm/issues/issue-73258.rs | 40 ++ .../issues/issue-73338-effecient-cmp.rs | 39 ++ .../issue-73396-bounds-check-after-position.rs | 70 ++ .../issue-73827-bounds-check-index-in-subexpr.rs | 17 + .../issues/issue-74938-array-split-at.rs | 14 + .../issues/issue-75525-bounds-checks.rs | 26 + tests/codegen-llvm/issues/issue-75546.rs | 17 + tests/codegen-llvm/issues/issue-75659.rs | 63 ++ tests/codegen-llvm/issues/issue-75978.rs | 18 + tests/codegen-llvm/issues/issue-77812.rs | 32 + tests/codegen-llvm/issues/issue-84268.rs | 18 + .../issues/issue-85872-multiple-reverse.rs | 19 + tests/codegen-llvm/issues/issue-86106.rs | 63 ++ .../issue-86109-eliminate-div-by-zero-check.rs | 26 + .../issues/issue-93036-assert-index.rs | 14 + tests/codegen-llvm/issues/issue-96274.rs | 15 + .../issues/issue-96497-slice-size-nowrap.rs | 38 + .../issue-98294-get-mut-copy-from-slice-opt.rs | 17 + tests/codegen-llvm/issues/issue-98678-async.rs | 27 + .../issues/issue-98678-closure-coroutine.rs | 25 + tests/codegen-llvm/issues/issue-98678-enum.rs | 42 ++ .../issues/issue-98678-struct-union.rs | 27 + tests/codegen-llvm/issues/issue-99960.rs | 10 + .../issues/looping-over-ne-bytes-133528.rs | 17 + tests/codegen-llvm/issues/str-to-string-128690.rs | 38 + tests/codegen-llvm/iter-repeat-n-trivial-drop.rs | 70 ++ tests/codegen-llvm/layout-size-checks.rs | 30 + tests/codegen-llvm/lib-optimizations/iter-sum.rs | 13 + .../codegen-llvm/lib-optimizations/slice_rotate.rs | 30 + tests/codegen-llvm/lifetime_start_end.rs | 34 + tests/codegen-llvm/link-dead-code.rs | 28 + tests/codegen-llvm/link_section.rs | 35 + tests/codegen-llvm/llvm-ident.rs | 15 + tests/codegen-llvm/llvm_module_flags.rs | 7 + tests/codegen-llvm/loads.rs | 152 ++++ .../local-generics-in-exe-internalized.rs | 14 + .../loongarch-abi/call-llvm-intrinsics.rs | 31 + .../loongarch-abi/loongarch64-lp64d-abi.rs | 299 ++++++++ tests/codegen-llvm/lto-removes-invokes.rs | 21 + .../macos/i686-macosx-deployment-target.rs | 23 + .../macos/i686-no-macosx-deployment-target.rs | 23 + .../macos/x86_64-macosx-deployment-target.rs | 23 + .../macos/x86_64-no-macosx-deployment-target.rs | 23 + tests/codegen-llvm/mainsubprogram.rs | 12 + tests/codegen-llvm/match-optimized.rs | 60 ++ tests/codegen-llvm/match-optimizes-away.rs | 41 ++ tests/codegen-llvm/match-unoptimized.rs | 23 + tests/codegen-llvm/maybeuninit-rvo.rs | 34 + tests/codegen-llvm/mem-replace-big-type.rs | 36 + tests/codegen-llvm/mem-replace-simple-type.rs | 54 ++ tests/codegen-llvm/merge-functions.rs | 16 + tests/codegen-llvm/meta-filecheck/check-prefix.rs | 4 + .../codegen-llvm/meta-filecheck/filecheck-flags.rs | 8 + .../codegen-llvm/meta-filecheck/msvc-prefix-bad.rs | 7 + tests/codegen-llvm/meta-filecheck/no-directives.rs | 5 + .../codegen-llvm/meta-filecheck/revision-prefix.rs | 8 + tests/codegen-llvm/method-declaration.rs | 26 + tests/codegen-llvm/min-function-alignment.rs | 48 ++ tests/codegen-llvm/mir-aggregate-no-alloca.rs | 137 ++++ tests/codegen-llvm/mir-inlined-line-numbers.rs | 25 + tests/codegen-llvm/mir_zst_stores.rs | 19 + .../codegen-llvm/move-before-nocapture-ref-arg.rs | 21 + tests/codegen-llvm/move-operands.rs | 13 + tests/codegen-llvm/naked-asan.rs | 30 + tests/codegen-llvm/naked-fn/aligned.rs | 21 + tests/codegen-llvm/naked-fn/generics.rs | 111 +++ tests/codegen-llvm/naked-fn/instruction-set.rs | 53 ++ .../naked-fn/min-function-alignment.rs | 47 ++ tests/codegen-llvm/naked-fn/naked-functions.rs | 165 +++++ tests/codegen-llvm/no-alloca-inside-if-false.rs | 27 + tests/codegen-llvm/no-assumes-on-casts.rs | 19 + .../codegen-llvm/no-dllimport-w-cross-lang-lto.rs | 13 + tests/codegen-llvm/no-jump-tables.rs | 23 + tests/codegen-llvm/no-plt.rs | 17 + .../no-redundant-item-monomorphization.rs | 33 + tests/codegen-llvm/no_builtins-at-crate.rs | 24 + tests/codegen-llvm/noalias-box-off.rs | 11 + tests/codegen-llvm/noalias-box.rs | 8 + tests/codegen-llvm/noalias-flag.rs | 23 + tests/codegen-llvm/noalias-freeze.rs | 23 + tests/codegen-llvm/noalias-refcell.rs | 14 + tests/codegen-llvm/noalias-rwlockreadguard.rs | 14 + tests/codegen-llvm/noalias-unpin.rs | 15 + .../codegen-llvm/non-terminate/infinite-loop-1.rs | 17 + .../codegen-llvm/non-terminate/infinite-loop-2.rs | 19 + .../non-terminate/infinite-recursion.rs | 13 + .../non-terminate/nonempty-infinite-loop.rs | 28 + tests/codegen-llvm/noreturn-uninhabited.rs | 31 + tests/codegen-llvm/noreturnflag.rs | 22 + tests/codegen-llvm/nounwind.rs | 15 + tests/codegen-llvm/nrvo.rs | 17 + tests/codegen-llvm/optimize-attr-1.rs | 59 ++ tests/codegen-llvm/option-as-slice.rs | 71 ++ tests/codegen-llvm/option-niche-eq.rs | 87 +++ .../option-niche-unfixed/option-nonzero-eq.rs | 24 + tests/codegen-llvm/overaligned-constant.rs | 35 + tests/codegen-llvm/packed.rs | 153 ++++ tests/codegen-llvm/panic-abort-windows.rs | 16 + tests/codegen-llvm/panic-in-drop-abort.rs | 57 ++ tests/codegen-llvm/panic-unwind-default-uwtable.rs | 6 + .../patchable-function-entry-both-flags.rs | 64 ++ .../patchable-function-entry-no-flag.rs | 39 ++ .../patchable-function-entry-one-flag.rs | 66 ++ tests/codegen-llvm/pattern_type_symbols.rs | 22 + tests/codegen-llvm/personality_lifetimes.rs | 32 + tests/codegen-llvm/pgo-counter-bias.rs | 10 + tests/codegen-llvm/pgo-instrumentation.rs | 20 + tests/codegen-llvm/pic-relocation-model.rs | 19 + tests/codegen-llvm/pie-relocation-model.rs | 22 + tests/codegen-llvm/placement-new.rs | 39 ++ tests/codegen-llvm/powerpc64le-struct-align-128.rs | 96 +++ tests/codegen-llvm/precondition-checks.rs | 25 + tests/codegen-llvm/ptr-arithmetic.rs | 33 + tests/codegen-llvm/ptr-read-metadata.rs | 94 +++ tests/codegen-llvm/range-attribute.rs | 74 ++ tests/codegen-llvm/range-loop.rs | 44 ++ tests/codegen-llvm/range_to_inclusive.rs | 28 + tests/codegen-llvm/refs.rs | 21 + tests/codegen-llvm/reg-struct-return.rs | 206 ++++++ tests/codegen-llvm/regparm-inreg.rs | 125 ++++ tests/codegen-llvm/remap_path_prefix/aux_mod.rs | 6 + .../auxiliary/remap_path_prefix_aux.rs | 8 + .../remap_path_prefix/auxiliary/xcrate-generic.rs | 8 + .../remap_path_prefix/issue-73167-remap-std.rs | 15 + tests/codegen-llvm/remap_path_prefix/main.rs | 28 + .../remap_path_prefix/xcrate-generic.rs | 14 + tests/codegen-llvm/repeat-operand-zero-len.rs | 28 + tests/codegen-llvm/repeat-operand-zst-elem.rs | 28 + tests/codegen-llvm/repeat-trusted-len.rs | 20 + .../repr/transparent-byval-struct-ptr.rs | 111 +++ tests/codegen-llvm/repr/transparent-imm-array.rs | 116 +++ tests/codegen-llvm/repr/transparent-mips64.rs | 103 +++ tests/codegen-llvm/repr/transparent-opaque-ptr.rs | 109 +++ tests/codegen-llvm/repr/transparent-sparc64.rs | 113 +++ tests/codegen-llvm/repr/transparent-sysv64.rs | 49 ++ tests/codegen-llvm/repr/transparent.rs | 221 ++++++ tests/codegen-llvm/retpoline.rs | 27 + .../codegen-llvm/riscv-abi/call-llvm-intrinsics.rs | 30 + .../riscv-abi/cast-local-large-enough.rs | 44 ++ .../riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs | 176 +++++ tests/codegen-llvm/riscv-abi/riscv64-lp64d-abi.rs | 299 ++++++++ .../riscv-abi/riscv64-lp64f-lp64d-abi.rs | 283 ++++++++ tests/codegen-llvm/riscv-target-abi.rs | 21 + .../rust-abi-arch-specific-adjustment.rs | 111 +++ tests/codegen-llvm/s390x-simd.rs | 143 ++++ .../aarch64-shadow-call-stack-with-fixed-x18.rs | 20 + .../address-sanitizer-globals-tracking.rs | 44 ++ .../cfi/add-canonical-jump-tables-flag.rs | 10 + .../cfi/add-cfi-normalize-integers-flag.rs | 10 + .../cfi/add-enable-split-lto-unit-flag.rs | 10 + .../sanitizer/cfi/dbg-location-on-cfi-blocks.rs | 19 + .../cfi/emit-type-checks-attr-no-sanitize.rs | 18 + .../codegen-llvm/sanitizer/cfi/emit-type-checks.rs | 19 + .../cfi/emit-type-metadata-attr-cfi-encoding.rs | 73 ++ ...e-metadata-id-itanium-cxx-abi-const-generics.rs | 32 + ...pe-metadata-id-itanium-cxx-abi-drop-in-place.rs | 31 + ...e-metadata-id-itanium-cxx-abi-function-types.rs | 45 ++ ...t-type-metadata-id-itanium-cxx-abi-lifetimes.rs | 29 + ...a-id-itanium-cxx-abi-method-secondary-typeid.rs | 21 + .../emit-type-metadata-id-itanium-cxx-abi-paths.rs | 86 +++ ...pe-metadata-id-itanium-cxx-abi-pointer-types.rs | 54 ++ ...-metadata-id-itanium-cxx-abi-primitive-types.rs | 190 +++++ ...ta-id-itanium-cxx-abi-repr-transparent-types.rs | 79 +++ ...e-metadata-id-itanium-cxx-abi-sequence-types.rs | 36 + ...type-metadata-id-itanium-cxx-abi-trait-types.rs | 175 +++++ ...tadata-id-itanium-cxx-abi-user-defined-types.rs | 62 ++ ...it-type-metadata-itanium-cxx-abi-generalized.rs | 31 + ...adata-itanium-cxx-abi-normalized-generalized.rs | 31 + ...mit-type-metadata-itanium-cxx-abi-normalized.rs | 31 + .../cfi/emit-type-metadata-itanium-cxx-abi.rs | 31 + .../cfi/emit-type-metadata-trait-objects.rs | 145 ++++ .../sanitizer/cfi/external_weak_symbols.rs | 24 + .../sanitizer/cfi/generalize-pointers.rs | 46 ++ .../sanitizer/cfi/normalize-integers.rs | 46 ++ .../sanitizer/dataflow-instrument-functions.rs | 9 + .../sanitizer/kasan-emits-instrumentation.rs | 41 ++ .../kcfi/add-cfi-normalize-integers-flag.rs | 20 + .../sanitizer/kcfi/add-kcfi-arity-flag.rs | 19 + tests/codegen-llvm/sanitizer/kcfi/add-kcfi-flag.rs | 20 + .../sanitizer/kcfi/add-kcfi-offset-flag.rs | 20 + .../emit-kcfi-operand-bundle-attr-no-sanitize.rs | 27 + ...i-operand-bundle-itanium-cxx-abi-generalized.rs | 41 ++ ...undle-itanium-cxx-abi-normalized-generalized.rs | 41 ++ ...fi-operand-bundle-itanium-cxx-abi-normalized.rs | 41 ++ .../emit-kcfi-operand-bundle-itanium-cxx-abi.rs | 41 ++ .../sanitizer/kcfi/emit-kcfi-operand-bundle.rs | 24 + .../kcfi/emit-type-metadata-trait-objects.rs | 155 ++++ .../codegen-llvm/sanitizer/kcfi/naked-function.rs | 47 ++ .../codegen-llvm/sanitizer/memory-track-origins.rs | 31 + tests/codegen-llvm/sanitizer/memtag-attr-check.rs | 12 + .../codegen-llvm/sanitizer/no-sanitize-inlining.rs | 31 + tests/codegen-llvm/sanitizer/no-sanitize.rs | 39 ++ .../sanitizer/riscv64-shadow-call-stack.rs | 18 + .../codegen-llvm/sanitizer/safestack-attr-check.rs | 11 + tests/codegen-llvm/sanitizer/sanitizer-recover.rs | 50 ++ tests/codegen-llvm/sanitizer/scs-attr-check.rs | 17 + tests/codegen-llvm/scalar-pair-bool.rs | 45 ++ tests/codegen-llvm/set-discriminant-invalid.rs | 34 + .../simd-intrinsic/simd-intrinsic-float-abs.rs | 60 ++ .../simd-intrinsic/simd-intrinsic-float-ceil.rs | 60 ++ .../simd-intrinsic/simd-intrinsic-float-cos.rs | 60 ++ .../simd-intrinsic/simd-intrinsic-float-exp.rs | 60 ++ .../simd-intrinsic/simd-intrinsic-float-exp2.rs | 60 ++ .../simd-intrinsic/simd-intrinsic-float-floor.rs | 60 ++ .../simd-intrinsic/simd-intrinsic-float-fma.rs | 60 ++ .../simd-intrinsic/simd-intrinsic-float-fsqrt.rs | 60 ++ .../simd-intrinsic/simd-intrinsic-float-log.rs | 60 ++ .../simd-intrinsic/simd-intrinsic-float-log10.rs | 60 ++ .../simd-intrinsic/simd-intrinsic-float-log2.rs | 60 ++ .../simd-intrinsic/simd-intrinsic-float-minmax.rs | 25 + .../simd-intrinsic/simd-intrinsic-float-sin.rs | 60 ++ ...simd-intrinsic-generic-arithmetic-saturating.rs | 579 +++++++++++++++ .../simd-intrinsic-generic-bitmask.rs | 48 ++ .../simd-intrinsic-generic-gather.rs | 55 ++ .../simd-intrinsic-generic-masked-load.rs | 49 ++ .../simd-intrinsic-generic-masked-store.rs | 41 ++ .../simd-intrinsic-generic-scatter.rs | 47 ++ .../simd-intrinsic-generic-select.rs | 48 ++ .../simd-intrinsic/simd-intrinsic-mask-reduce.rs | 60 ++ .../simd-intrinsic-transmute-array.rs | 58 ++ tests/codegen-llvm/simd/aggregate-simd.rs | 102 +++ tests/codegen-llvm/simd/extract-insert-dyn.rs | 121 ++++ tests/codegen-llvm/simd/packed-simd-alignment.rs | 44 ++ tests/codegen-llvm/simd/packed-simd.rs | 56 ++ tests/codegen-llvm/simd/simd-wide-sum.rs | 59 ++ tests/codegen-llvm/simd/simd_arith_offset.rs | 22 + tests/codegen-llvm/simd/swap-simd-types.rs | 40 ++ tests/codegen-llvm/simd/unpadded-simd.rs | 19 + tests/codegen-llvm/skip-mono-inside-if-false.rs | 41 ++ tests/codegen-llvm/slice-as_chunks.rs | 30 + tests/codegen-llvm/slice-indexing.rs | 99 +++ tests/codegen-llvm/slice-init.rs | 108 +++ tests/codegen-llvm/slice-is-ascii.rs | 16 + tests/codegen-llvm/slice-iter-fold.rs | 12 + tests/codegen-llvm/slice-iter-len-eq-zero.rs | 60 ++ tests/codegen-llvm/slice-iter-nonnull.rs | 115 +++ .../slice-last-elements-optimization.rs | 37 + tests/codegen-llvm/slice-pointer-nonnull-unwrap.rs | 18 + tests/codegen-llvm/slice-position-bounds-check.rs | 25 + tests/codegen-llvm/slice-ref-equality.rs | 90 +++ tests/codegen-llvm/slice-reverse.rs | 27 + tests/codegen-llvm/slice-split-at.rs | 24 + .../codegen-llvm/slice-windows-no-bounds-check.rs | 32 + tests/codegen-llvm/slice_as_from_ptr_range.rs | 21 + .../some-abis-do-extend-params-to-32-bits.rs | 236 +++++++ tests/codegen-llvm/some-global-nonnull.rs | 25 + tests/codegen-llvm/sparc-struct-abi.rs | 97 +++ tests/codegen-llvm/split-lto-unit.rs | 10 + .../src-hash-algorithm/src-hash-algorithm-md5.rs | 6 + .../src-hash-algorithm/src-hash-algorithm-sha1.rs | 6 + .../src-hash-algorithm-sha256.rs | 6 + tests/codegen-llvm/sroa-fragment-debuginfo.rs | 46 ++ tests/codegen-llvm/sse42-implies-crc32.rs | 15 + tests/codegen-llvm/stack-probes-inline.rs | 33 + tests/codegen-llvm/stack-protector.rs | 34 + tests/codegen-llvm/static-relocation-model-msvc.rs | 24 + .../codegen-llvm/staticlib-external-inline-fns.rs | 43 ++ tests/codegen-llvm/step_by-overflow-checks.rs | 26 + tests/codegen-llvm/stores.rs | 35 + tests/codegen-llvm/string-push.rs | 11 + tests/codegen-llvm/swap-large-types.rs | 116 +++ tests/codegen-llvm/swap-small-types.rs | 182 +++++ tests/codegen-llvm/target-cpu-on-functions.rs | 22 + .../codegen-llvm/target-feature-inline-closure.rs | 33 + .../target-feature-negative-implication.rs | 20 + tests/codegen-llvm/target-feature-overrides.rs | 46 ++ tests/codegen-llvm/terminating-catchpad.rs | 43 ++ tests/codegen-llvm/thread-local.rs | 54 ++ tests/codegen-llvm/tied-features-strength.rs | 34 + tests/codegen-llvm/to_vec.rs | 10 + tests/codegen-llvm/trailing_zeros.rs | 21 + tests/codegen-llvm/transmute-optimized.rs | 120 ++++ tests/codegen-llvm/transmute-scalar.rs | 143 ++++ tests/codegen-llvm/try_question_mark_nop.rs | 243 +++++++ tests/codegen-llvm/tune-cpu-on-functions.rs | 21 + tests/codegen-llvm/tuple-layout-opt.rs | 57 ++ tests/codegen-llvm/ub-checks.rs | 28 + tests/codegen-llvm/unchecked-float-casts.rs | 36 + tests/codegen-llvm/unchecked_shifts.rs | 100 +++ .../uninhabited-transparent-return-abi.rs | 44 ++ tests/codegen-llvm/uninit-consts.rs | 54 ++ tests/codegen-llvm/uninit-repeat-in-aggregate.rs | 21 + tests/codegen-llvm/union-abi.rs | 145 ++++ tests/codegen-llvm/union-aggregate.rs | 108 +++ tests/codegen-llvm/unwind-abis/aapcs-unwind-abi.rs | 36 + .../unwind-abis/c-unwind-abi-panic-abort.rs | 27 + tests/codegen-llvm/unwind-abis/c-unwind-abi.rs | 27 + tests/codegen-llvm/unwind-abis/cdecl-unwind-abi.rs | 27 + .../unwind-abis/fastcall-unwind-abi.rs | 36 + .../unwind-abis/nounwind-on-stable-panic-abort.rs | 15 + tests/codegen-llvm/unwind-abis/nounwind.rs | 16 + .../codegen-llvm/unwind-abis/stdcall-unwind-abi.rs | 36 + .../codegen-llvm/unwind-abis/system-unwind-abi.rs | 27 + .../codegen-llvm/unwind-abis/sysv64-unwind-abi.rs | 36 + .../unwind-abis/thiscall-unwind-abi.rs | 36 + .../unwind-abis/vectorcall-unwind-abi.rs | 36 + tests/codegen-llvm/unwind-abis/win64-unwind-abi.rs | 36 + tests/codegen-llvm/unwind-and-panic-abort.rs | 16 + tests/codegen-llvm/unwind-extern-exports.rs | 15 + tests/codegen-llvm/unwind-extern-imports.rs | 21 + tests/codegen-llvm/unwind-landingpad-cold.rs | 15 + tests/codegen-llvm/unwind-landingpad-inline.rs | 39 ++ tests/codegen-llvm/used_with_arg.rs | 10 + tests/codegen-llvm/var-names.rs | 15 + tests/codegen-llvm/vec-as-ptr.rs | 19 + tests/codegen-llvm/vec-calloc.rs | 182 +++++ tests/codegen-llvm/vec-in-place.rs | 161 +++++ tests/codegen-llvm/vec-iter-collect-len.rs | 12 + tests/codegen-llvm/vec-iter.rs | 58 ++ tests/codegen-llvm/vec-len-invariant.rs | 16 + tests/codegen-llvm/vec-optimizes-away.rs | 12 + tests/codegen-llvm/vec-reserve-extend.rs | 14 + tests/codegen-llvm/vec-shrink-panik.rs | 31 + tests/codegen-llvm/vec-with-capacity.rs | 35 + tests/codegen-llvm/vec_pop_push_noop.rs | 24 + tests/codegen-llvm/vecdeque-drain.rs | 70 ++ .../codegen-llvm/vecdeque-nonempty-get-no-panic.rs | 16 + tests/codegen-llvm/vecdeque_no_panic.rs | 19 + tests/codegen-llvm/vecdeque_pop_push.rs | 67 ++ .../virtual-call-attrs-issue-137646.rs | 37 + .../virtual-function-elimination-32bit.rs | 35 + tests/codegen-llvm/virtual-function-elimination.rs | 98 +++ tests/codegen-llvm/vtable-loads.rs | 16 + tests/codegen-llvm/vtable-upcast.rs | 84 +++ tests/codegen-llvm/wasm_casts_trapping.rs | 157 +++++ tests/codegen-llvm/wasm_exceptions.rs | 59 ++ tests/codegen-llvm/zip.rs | 21 + tests/codegen-llvm/zst-offset.rs | 42 ++ tests/codegen/README.md | 24 - tests/codegen/aarch64-softfloat.rs | 45 -- tests/codegen/aarch64-struct-align-128.rs | 145 ---- tests/codegen/abi-efiapi.rs | 30 - tests/codegen/abi-main-signature-16bit-c-int.rs | 11 - tests/codegen/abi-main-signature-32bit-c-int.rs | 11 - tests/codegen/abi-repr-ext.rs | 56 -- tests/codegen/abi-sysv64.rs | 20 - tests/codegen/abi-win64-zst.rs | 54 -- tests/codegen/abi-x86-interrupt.rs | 18 - tests/codegen/abi-x86-sse.rs | 43 -- tests/codegen/abi-x86_64_sysv.rs | 29 - tests/codegen/addr-of-mutate.rs | 33 - tests/codegen/adjustments.rs | 28 - tests/codegen/align-byval-alignment-mismatch.rs | 126 ---- tests/codegen/align-byval-vector.rs | 55 -- tests/codegen/align-byval.rs | 315 --------- tests/codegen/align-enum.rs | 33 - tests/codegen/align-fn.rs | 143 ---- tests/codegen/align-offset.rs | 75 -- tests/codegen/align-struct.rs | 70 -- tests/codegen/alloc-optimisation.rs | 13 - tests/codegen/amdgpu-addrspacecast.rs | 18 - tests/codegen/array-clone.rs | 15 - tests/codegen/array-cmp.rs | 74 -- tests/codegen/array-codegen.rs | 62 -- tests/codegen/array-equality.rs | 101 --- tests/codegen/array-from_fn.rs | 13 - tests/codegen/array-map.rs | 35 - tests/codegen/array-optimized.rs | 33 - tests/codegen/array-repeat.rs | 15 - tests/codegen/ascii-char.rs | 36 - tests/codegen/asm/aarch64-clobbers.rs | 47 -- tests/codegen/asm/avr-clobbers.rs | 39 -- tests/codegen/asm/bpf-clobbers.rs | 31 - tests/codegen/asm/critical.rs | 36 - tests/codegen/asm/csky-clobbers.rs | 24 - tests/codegen/asm/foo.s | 3 - tests/codegen/asm/global_asm.rs | 28 - tests/codegen/asm/global_asm_include.rs | 21 - tests/codegen/asm/global_asm_x2.rs | 47 -- tests/codegen/asm/goto.rs | 63 -- tests/codegen/asm/hexagon-clobbers.rs | 33 - tests/codegen/asm/may_unwind.rs | 39 -- tests/codegen/asm/maybe-uninit.rs | 27 - tests/codegen/asm/msp430-clobbers.rs | 32 - tests/codegen/asm/multiple-options.rs | 54 -- tests/codegen/asm/options.rs | 104 --- tests/codegen/asm/powerpc-clobbers.rs | 68 -- tests/codegen/asm/riscv-clobbers.rs | 40 -- tests/codegen/asm/s390x-clobbers.rs | 46 -- tests/codegen/asm/sanitize-llvm.rs | 24 - tests/codegen/asm/sparc-clobbers.rs | 36 - tests/codegen/asm/x86-clobber_abi.rs | 36 - tests/codegen/asm/x86-clobbers.rs | 20 - tests/codegen/asm/x86-target-clobbers.rs | 29 - tests/codegen/assign-desugar-debuginfo.rs | 18 - tests/codegen/async-closure-debug.rs | 20 - tests/codegen/async-fn-debug-awaitee-field.rs | 28 - tests/codegen/async-fn-debug-msvc.rs | 55 -- tests/codegen/async-fn-debug.rs | 59 -- tests/codegen/atomic-operations.rs | 84 --- tests/codegen/atomicptr.rs | 36 - tests/codegen/autodiff/batched.rs | 116 --- tests/codegen/autodiff/generic.rs | 42 -- tests/codegen/autodiff/identical_fnc.rs | 45 -- tests/codegen/autodiff/inline.rs | 23 - tests/codegen/autodiff/scalar.rs | 33 - tests/codegen/autodiff/sret.rs | 45 -- tests/codegen/autodiffv2.rs | 113 --- tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs | 31 - tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs | 42 -- tests/codegen/autovectorize-f32x4.rs | 37 - tests/codegen/auxiliary/extern_decl.rs | 13 - tests/codegen/auxiliary/nounwind.rs | 2 - tests/codegen/auxiliary/thread_local_aux.rs | 5 - tests/codegen/avr/avr-func-addrspace.rs | 106 --- tests/codegen/bigint-helpers.rs | 13 - tests/codegen/binary-heap-peek-mut-pop-no-panic.rs | 13 - .../codegen/binary-search-index-no-bound-check.rs | 35 - tests/codegen/bool-cmp.rs | 18 - tests/codegen/bounds-checking/gep-issue-133979.rs | 22 - tests/codegen/box-default-debug-copies.rs | 28 - tests/codegen/box-uninit-bytes.rs | 46 -- tests/codegen/bpf-alu32.rs | 11 - tests/codegen/branch-protection.rs | 94 --- tests/codegen/call-llvm-intrinsics.rs | 30 - tests/codegen/call-tmps-lifetime.rs | 68 -- tests/codegen/cast-optimized.rs | 33 - tests/codegen/cast-target-abi.rs | 599 ---------------- tests/codegen/catch-unwind.rs | 32 - tests/codegen/cdylib-external-inline-fns.rs | 43 -- tests/codegen/cf-protection.rs | 38 - tests/codegen/cffi/c-variadic-copy.rs | 16 - tests/codegen/cffi/c-variadic-naked.rs | 15 - tests/codegen/cffi/c-variadic-opt.rs | 30 - tests/codegen/cffi/c-variadic.rs | 71 -- tests/codegen/cffi/ffi-const.rs | 15 - tests/codegen/cffi/ffi-out-of-bounds-loads.rs | 41 -- tests/codegen/cffi/ffi-pure.rs | 15 - tests/codegen/cfguard-checks.rs | 10 - tests/codegen/cfguard-disabled.rs | 10 - tests/codegen/cfguard-nochecks.rs | 10 - tests/codegen/cfguard-non-msvc.rs | 10 - tests/codegen/char-ascii-branchless.rs | 47 -- tests/codegen/char-escape-debug-no-bounds-check.rs | 14 - tests/codegen/checked_ilog.rs | 20 - tests/codegen/checked_math.rs | 100 --- tests/codegen/clone-shims.rs | 15 - tests/codegen/clone_as_copy.rs | 40 -- tests/codegen/codemodels.rs | 20 - tests/codegen/coercions.rs | 19 - tests/codegen/cold-call-declare-and-call.rs | 27 - tests/codegen/common_prim_int_ptr.rs | 51 -- tests/codegen/comparison-operators-2-struct.rs | 61 -- tests/codegen/comparison-operators-2-tuple.rs | 117 ---- tests/codegen/comparison-operators-newtype.rs | 48 -- .../compiletest-self-test/minicore-smoke-test.rs | 20 - tests/codegen/const-array.rs | 15 - tests/codegen/const-vector.rs | 78 --- tests/codegen/const_scalar_pair.rs | 8 - tests/codegen/constant-branch.rs | 49 -- tests/codegen/consts.rs | 55 -- tests/codegen/coroutine-debug-msvc.rs | 60 -- tests/codegen/coroutine-debug.rs | 64 -- .../codegen/cross-crate-inlining/always-inline.rs | 13 - .../cross-crate-inlining/auxiliary/always.rs | 20 - .../codegen/cross-crate-inlining/auxiliary/leaf.rs | 20 - .../cross-crate-inlining/auxiliary/never.rs | 20 - .../codegen/cross-crate-inlining/leaf-inlining.rs | 20 - tests/codegen/cross-crate-inlining/never-inline.rs | 13 - tests/codegen/dealloc-no-unwind.rs | 25 - tests/codegen/debug-accessibility/crate-enum.rs | 28 - tests/codegen/debug-accessibility/crate-struct.rs | 23 - tests/codegen/debug-accessibility/private-enum.rs | 22 - .../codegen/debug-accessibility/private-struct.rs | 17 - tests/codegen/debug-accessibility/public-enum.rs | 23 - tests/codegen/debug-accessibility/public-struct.rs | 17 - tests/codegen/debug-accessibility/struct-fields.rs | 30 - tests/codegen/debug-accessibility/super-enum.rs | 28 - tests/codegen/debug-accessibility/super-struct.rs | 23 - tests/codegen/debug-accessibility/tuple-fields.rs | 24 - tests/codegen/debug-alignment.rs | 8 - tests/codegen/debug-column-msvc.rs | 16 - tests/codegen/debug-column.rs | 25 - tests/codegen/debug-compile-unit-path.rs | 9 - tests/codegen/debug-fndef-size.rs | 20 - tests/codegen/debug-limited.rs | 27 - tests/codegen/debug-line-directives-only.rs | 27 - tests/codegen/debug-line-tables-only.rs | 27 - tests/codegen/debug-linkage-name.rs | 42 -- tests/codegen/debug-vtable.rs | 117 ---- tests/codegen/debuginfo-constant-locals.rs | 28 - .../codegen/debuginfo-generic-closure-env-names.rs | 90 --- .../codegen/debuginfo-inline-callsite-location.rs | 27 - .../debuginfo-proc-macro/auxiliary/macro_def.rs | 7 - .../mir_inlined_twice_var_locs.rs | 52 -- tests/codegen/deduced-param-attrs.rs | 60 -- tests/codegen/default-requires-uwtable.rs | 17 - tests/codegen/default-visibility.rs | 49 -- tests/codegen/direct-access-external-data.rs | 21 - tests/codegen/dllimports/auxiliary/dummy.rs | 6 - tests/codegen/dllimports/auxiliary/wrapper.rs | 14 - tests/codegen/dllimports/main.rs | 43 -- ...gen_private_const_fn_only_used_in_const_eval.rs | 27 - tests/codegen/drop-in-place-noalias.rs | 38 - tests/codegen/drop.rs | 36 - tests/codegen/dst-offset.rs | 84 --- tests/codegen/dst-vtable-align-nonzero.rs | 67 -- tests/codegen/dst-vtable-size-range.rs | 35 - tests/codegen/ehcontguard_disabled.rs | 9 - tests/codegen/ehcontguard_enabled.rs | 9 - tests/codegen/emscripten-catch-unwind-js-eh.rs | 71 -- tests/codegen/emscripten-catch-unwind-wasm-eh.rs | 69 -- tests/codegen/enable-lto-unit-splitting.rs | 9 - tests/codegen/enum/enum-aggregate.rs | 126 ---- .../codegen/enum/enum-bounds-check-derived-idx.rs | 24 - .../codegen/enum/enum-bounds-check-issue-13926.rs | 18 - .../codegen/enum/enum-bounds-check-issue-82871.rs | 18 - tests/codegen/enum/enum-bounds-check.rs | 27 - tests/codegen/enum/enum-debug-clike.rs | 28 - tests/codegen/enum/enum-debug-niche-2.rs | 47 -- tests/codegen/enum/enum-debug-niche.rs | 35 - tests/codegen/enum/enum-debug-tagged.rs | 31 - tests/codegen/enum/enum-discriminant-eq.rs | 223 ------ tests/codegen/enum/enum-discriminant-value.rs | 27 - tests/codegen/enum/enum-early-otherwise-branch.rs | 25 - tests/codegen/enum/enum-match.rs | 779 --------------------- tests/codegen/enum/enum-two-variants-match.rs | 130 ---- tests/codegen/enum/enum-u128.rs | 25 - .../enum/unreachable_enum_default_branch.rs | 40 -- tests/codegen/ergonomic-clones/closure.rs | 55 -- tests/codegen/error-provide.rs | 50 -- tests/codegen/export-no-mangle.rs | 31 - tests/codegen/external-no-mangle-fns.rs | 75 -- tests/codegen/external-no-mangle-statics.rs | 77 -- tests/codegen/f128-wasm32-callconv.rs | 49 -- tests/codegen/fastcall-inreg.rs | 40 -- tests/codegen/fatptr.rs | 12 - tests/codegen/fewer-names.rs | 19 - tests/codegen/fixed-x18.rs | 23 - tests/codegen/float/algebraic.rs | 149 ---- tests/codegen/float/f128.rs | 441 ------------ tests/codegen/float/f16-f128-inline.rs | 29 - tests/codegen/float/f16.rs | 364 ---------- tests/codegen/float_math.rs | 87 --- tests/codegen/fn-impl-trait-self.rs | 17 - .../fn-parameters-on-different-lines-debuginfo.rs | 22 - tests/codegen/force-frame-pointers.rs | 18 - tests/codegen/force-no-unwind-tables.rs | 11 - tests/codegen/force-unwind-tables.rs | 6 - tests/codegen/frame-pointer-cli-control.rs | 61 -- tests/codegen/frame-pointer.rs | 35 - tests/codegen/function-arguments-noopt.rs | 69 -- tests/codegen/function-arguments.rs | 278 -------- tests/codegen/function-return.rs | 35 - tests/codegen/gdb_debug_script_load.rs | 37 - tests/codegen/generic-debug.rs | 17 - tests/codegen/gep-index.rs | 37 - tests/codegen/gpu-kernel-abi.rs | 15 - tests/codegen/gpu_offload/gpu_host.rs | 80 --- tests/codegen/hint/cold_path.rs | 54 -- tests/codegen/hint/likely.rs | 81 --- tests/codegen/hint/unlikely.rs | 80 --- tests/codegen/i128-wasm32-callconv.rs | 49 -- tests/codegen/i128-x86-align.rs | 105 --- tests/codegen/i128-x86-callconv.rs | 87 --- tests/codegen/infallible-unwrap-in-opt-z.rs | 26 - tests/codegen/inherit_overflow.rs | 14 - tests/codegen/inline-always-works-always.rs | 21 - tests/codegen/inline-debuginfo.rs | 17 - tests/codegen/inline-function-args-debug-info.rs | 23 - tests/codegen/inline-hint.rs | 31 - .../instrument-coverage/instrument-coverage-off.rs | 21 - .../instrument-coverage/instrument-coverage.rs | 22 - tests/codegen/instrument-coverage/testprog.rs | 118 ---- tests/codegen/instrument-mcount.rs | 7 - tests/codegen/instrument-xray/basic.rs | 9 - tests/codegen/instrument-xray/options-combine.rs | 12 - tests/codegen/instrument-xray/options-override.rs | 11 - tests/codegen/integer-cmp.rs | 62 -- tests/codegen/integer-overflow.rs | 24 - tests/codegen/internalize-closures.rs | 13 - tests/codegen/intrinsic-no-unnamed-attr.rs | 13 - tests/codegen/intrinsics/aggregate-thin-pointer.rs | 23 - tests/codegen/intrinsics/carrying_mul_add.rs | 136 ---- tests/codegen/intrinsics/cold_path.rs | 13 - tests/codegen/intrinsics/cold_path2.rs | 37 - tests/codegen/intrinsics/cold_path3.rs | 87 --- tests/codegen/intrinsics/compare_bytes.rs | 34 - tests/codegen/intrinsics/const_eval_select.rs | 22 - tests/codegen/intrinsics/ctlz.rs | 56 -- tests/codegen/intrinsics/ctpop.rs | 31 - tests/codegen/intrinsics/disjoint_bitor.rs | 30 - tests/codegen/intrinsics/exact_div.rs | 20 - tests/codegen/intrinsics/likely.rs | 35 - tests/codegen/intrinsics/likely_assert.rs | 17 - tests/codegen/intrinsics/mask.rs | 12 - tests/codegen/intrinsics/nontemporal.rs | 32 - tests/codegen/intrinsics/offset.rs | 33 - tests/codegen/intrinsics/offset_from.rs | 36 - tests/codegen/intrinsics/prefetch.rs | 64 -- tests/codegen/intrinsics/ptr_metadata.rs | 36 - tests/codegen/intrinsics/rotate_left.rs | 31 - .../rustc_intrinsic_must_be_overridden.rs | 14 - tests/codegen/intrinsics/select_unpredictable.rs | 71 -- tests/codegen/intrinsics/three_way_compare.rs | 28 - tests/codegen/intrinsics/transmute-niched.rs | 223 ------ tests/codegen/intrinsics/transmute-x64.rs | 28 - tests/codegen/intrinsics/transmute.rs | 497 ------------- tests/codegen/intrinsics/typed_swap.rs | 77 -- tests/codegen/intrinsics/unchecked_math.rs | 46 -- tests/codegen/intrinsics/unlikely.rs | 35 - tests/codegen/intrinsics/volatile.rs | 55 -- tests/codegen/intrinsics/volatile_order.rs | 18 - tests/codegen/is_val_statically_known.rs | 163 ----- tests/codegen/issue-97217.rs | 20 - tests/codegen/issues/issue-101048.rs | 12 - tests/codegen/issues/issue-101082.rs | 42 -- tests/codegen/issues/issue-101814.rs | 18 - tests/codegen/issues/issue-103132.rs | 15 - .../issues/issue-103285-ptr-addr-overflow-check.rs | 15 - tests/codegen/issues/issue-103327.rs | 13 - tests/codegen/issues/issue-103840.rs | 9 - .../codegen/issues/issue-105386-ub-in-debuginfo.rs | 24 - tests/codegen/issues/issue-106369.rs | 14 - .../issues/issue-107681-unwrap_unchecked.rs | 19 - .../issues/issue-108395-branchy-bool-match.rs | 27 - tests/codegen/issues/issue-109328-split_first.rs | 16 - .../codegen/issues/issue-110797-enum-jump-same.rs | 25 - tests/codegen/issues/issue-111603.rs | 40 -- .../issues/issue-112509-slice-get-andthen-get.rs | 16 - .../issue-113757-bounds-check-after-cmp-max.rs | 18 - tests/codegen/issues/issue-114312.rs | 25 - .../issues/issue-115385-llvm-jump-threading.rs | 46 -- tests/codegen/issues/issue-116878.rs | 11 - tests/codegen/issues/issue-118306.rs | 22 - tests/codegen/issues/issue-118392.rs | 10 - tests/codegen/issues/issue-119422.rs | 83 --- .../issues/issue-121719-common-field-offset.rs | 44 -- .../issues/issue-122600-ptr-discriminant-update.rs | 43 -- .../issue-123712-str-to-lower-autovectorization.rs | 23 - tests/codegen/issues/issue-126585.rs | 23 - tests/codegen/issues/issue-129795.rs | 17 - tests/codegen/issues/issue-13018.rs | 14 - .../issues/issue-136329-optnone-noinline.rs | 21 - tests/codegen/issues/issue-15953.rs | 29 - tests/codegen/issues/issue-27130.rs | 21 - tests/codegen/issues/issue-32031.rs | 29 - tests/codegen/issues/issue-32364.rs | 17 - tests/codegen/issues/issue-34634.rs | 16 - tests/codegen/issues/issue-34947-pow-i32.rs | 13 - .../codegen/issues/issue-36010-some-box-is_some.rs | 28 - tests/codegen/issues/issue-37945.rs | 34 - tests/codegen/issues/issue-45222.rs | 62 -- tests/codegen/issues/issue-45466.rs | 14 - .../issues/issue-45964-bounds-check-slice-pos.rs | 38 - tests/codegen/issues/issue-47278.rs | 11 - tests/codegen/issues/issue-47442.rs | 22 - tests/codegen/issues/issue-56267-2.rs | 18 - tests/codegen/issues/issue-56267.rs | 18 - tests/codegen/issues/issue-56927.rs | 46 -- tests/codegen/issues/issue-58881.rs | 20 - tests/codegen/issues/issue-59352.rs | 18 - ...4219-fn-ptr-call-returning-never-is-noreturn.rs | 19 - .../issues/issue-68667-unwrap-combinators.rs | 15 - tests/codegen/issues/issue-69101-bounds-check.rs | 42 -- tests/codegen/issues/issue-73031.rs | 22 - tests/codegen/issues/issue-73258.rs | 40 -- tests/codegen/issues/issue-73338-effecient-cmp.rs | 39 -- .../issue-73396-bounds-check-after-position.rs | 70 -- .../issue-73827-bounds-check-index-in-subexpr.rs | 17 - tests/codegen/issues/issue-74938-array-split-at.rs | 14 - tests/codegen/issues/issue-75525-bounds-checks.rs | 26 - tests/codegen/issues/issue-75546.rs | 17 - tests/codegen/issues/issue-75659.rs | 63 -- tests/codegen/issues/issue-75978.rs | 18 - tests/codegen/issues/issue-77812.rs | 32 - tests/codegen/issues/issue-84268.rs | 18 - .../codegen/issues/issue-85872-multiple-reverse.rs | 19 - tests/codegen/issues/issue-86106.rs | 63 -- .../issue-86109-eliminate-div-by-zero-check.rs | 26 - tests/codegen/issues/issue-93036-assert-index.rs | 14 - tests/codegen/issues/issue-96274.rs | 15 - .../issues/issue-96497-slice-size-nowrap.rs | 38 - .../issue-98294-get-mut-copy-from-slice-opt.rs | 17 - tests/codegen/issues/issue-98678-async.rs | 27 - .../issues/issue-98678-closure-coroutine.rs | 25 - tests/codegen/issues/issue-98678-enum.rs | 42 -- tests/codegen/issues/issue-98678-struct-union.rs | 27 - tests/codegen/issues/issue-99960.rs | 10 - .../codegen/issues/looping-over-ne-bytes-133528.rs | 17 - tests/codegen/issues/str-to-string-128690.rs | 38 - tests/codegen/iter-repeat-n-trivial-drop.rs | 70 -- tests/codegen/layout-size-checks.rs | 30 - tests/codegen/lib-optimizations/iter-sum.rs | 13 - tests/codegen/lib-optimizations/slice_rotate.rs | 30 - tests/codegen/lifetime_start_end.rs | 34 - tests/codegen/link-dead-code.rs | 28 - tests/codegen/link_section.rs | 35 - tests/codegen/llvm-ident.rs | 15 - tests/codegen/llvm_module_flags.rs | 7 - tests/codegen/loads.rs | 152 ---- .../codegen/local-generics-in-exe-internalized.rs | 14 - .../codegen/loongarch-abi/call-llvm-intrinsics.rs | 31 - .../codegen/loongarch-abi/loongarch64-lp64d-abi.rs | 299 -------- tests/codegen/lto-removes-invokes.rs | 21 - .../codegen/macos/i686-macosx-deployment-target.rs | 23 - .../macos/i686-no-macosx-deployment-target.rs | 23 - .../macos/x86_64-macosx-deployment-target.rs | 23 - .../macos/x86_64-no-macosx-deployment-target.rs | 23 - tests/codegen/mainsubprogram.rs | 12 - tests/codegen/match-optimized.rs | 60 -- tests/codegen/match-optimizes-away.rs | 41 -- tests/codegen/match-unoptimized.rs | 23 - tests/codegen/maybeuninit-rvo.rs | 34 - tests/codegen/mem-replace-big-type.rs | 36 - tests/codegen/mem-replace-simple-type.rs | 54 -- tests/codegen/merge-functions.rs | 16 - tests/codegen/meta-filecheck/check-prefix.rs | 4 - tests/codegen/meta-filecheck/filecheck-flags.rs | 8 - tests/codegen/meta-filecheck/msvc-prefix-bad.rs | 7 - tests/codegen/meta-filecheck/no-directives.rs | 5 - tests/codegen/meta-filecheck/revision-prefix.rs | 8 - tests/codegen/method-declaration.rs | 26 - tests/codegen/min-function-alignment.rs | 48 -- tests/codegen/mir-aggregate-no-alloca.rs | 137 ---- tests/codegen/mir-inlined-line-numbers.rs | 25 - tests/codegen/mir_zst_stores.rs | 19 - tests/codegen/move-before-nocapture-ref-arg.rs | 21 - tests/codegen/move-operands.rs | 13 - tests/codegen/naked-asan.rs | 30 - tests/codegen/naked-fn/aligned.rs | 21 - tests/codegen/naked-fn/generics.rs | 111 --- tests/codegen/naked-fn/instruction-set.rs | 53 -- tests/codegen/naked-fn/min-function-alignment.rs | 47 -- tests/codegen/naked-fn/naked-functions.rs | 165 ----- tests/codegen/no-alloca-inside-if-false.rs | 27 - tests/codegen/no-assumes-on-casts.rs | 19 - tests/codegen/no-dllimport-w-cross-lang-lto.rs | 13 - tests/codegen/no-jump-tables.rs | 23 - tests/codegen/no-plt.rs | 17 - .../codegen/no-redundant-item-monomorphization.rs | 33 - tests/codegen/no_builtins-at-crate.rs | 24 - tests/codegen/noalias-box-off.rs | 11 - tests/codegen/noalias-box.rs | 8 - tests/codegen/noalias-flag.rs | 23 - tests/codegen/noalias-freeze.rs | 23 - tests/codegen/noalias-refcell.rs | 14 - tests/codegen/noalias-rwlockreadguard.rs | 14 - tests/codegen/noalias-unpin.rs | 15 - tests/codegen/non-terminate/infinite-loop-1.rs | 17 - tests/codegen/non-terminate/infinite-loop-2.rs | 19 - tests/codegen/non-terminate/infinite-recursion.rs | 13 - .../non-terminate/nonempty-infinite-loop.rs | 28 - tests/codegen/noreturn-uninhabited.rs | 31 - tests/codegen/noreturnflag.rs | 22 - tests/codegen/nounwind.rs | 15 - tests/codegen/nrvo.rs | 17 - tests/codegen/optimize-attr-1.rs | 59 -- tests/codegen/option-as-slice.rs | 71 -- tests/codegen/option-niche-eq.rs | 87 --- .../option-niche-unfixed/option-nonzero-eq.rs | 24 - tests/codegen/overaligned-constant.rs | 35 - tests/codegen/packed.rs | 153 ---- tests/codegen/panic-abort-windows.rs | 16 - tests/codegen/panic-in-drop-abort.rs | 57 -- tests/codegen/panic-unwind-default-uwtable.rs | 6 - .../patchable-function-entry-both-flags.rs | 64 -- .../patchable-function-entry-no-flag.rs | 39 -- .../patchable-function-entry-one-flag.rs | 66 -- tests/codegen/pattern_type_symbols.rs | 22 - tests/codegen/personality_lifetimes.rs | 32 - tests/codegen/pgo-counter-bias.rs | 10 - tests/codegen/pgo-instrumentation.rs | 20 - tests/codegen/pic-relocation-model.rs | 19 - tests/codegen/pie-relocation-model.rs | 22 - tests/codegen/placement-new.rs | 39 -- tests/codegen/powerpc64le-struct-align-128.rs | 96 --- tests/codegen/precondition-checks.rs | 25 - tests/codegen/ptr-arithmetic.rs | 33 - tests/codegen/ptr-read-metadata.rs | 94 --- tests/codegen/range-attribute.rs | 74 -- tests/codegen/range-loop.rs | 44 -- tests/codegen/range_to_inclusive.rs | 28 - tests/codegen/refs.rs | 21 - tests/codegen/reg-struct-return.rs | 206 ------ tests/codegen/regparm-inreg.rs | 125 ---- tests/codegen/remap_path_prefix/aux_mod.rs | 6 - .../auxiliary/remap_path_prefix_aux.rs | 8 - .../remap_path_prefix/auxiliary/xcrate-generic.rs | 8 - .../remap_path_prefix/issue-73167-remap-std.rs | 15 - tests/codegen/remap_path_prefix/main.rs | 28 - tests/codegen/remap_path_prefix/xcrate-generic.rs | 14 - tests/codegen/repeat-operand-zero-len.rs | 28 - tests/codegen/repeat-operand-zst-elem.rs | 28 - tests/codegen/repeat-trusted-len.rs | 20 - tests/codegen/repr/transparent-byval-struct-ptr.rs | 111 --- tests/codegen/repr/transparent-imm-array.rs | 116 --- tests/codegen/repr/transparent-mips64.rs | 103 --- tests/codegen/repr/transparent-opaque-ptr.rs | 109 --- tests/codegen/repr/transparent-sparc64.rs | 113 --- tests/codegen/repr/transparent-sysv64.rs | 49 -- tests/codegen/repr/transparent.rs | 221 ------ tests/codegen/retpoline.rs | 27 - tests/codegen/riscv-abi/call-llvm-intrinsics.rs | 30 - tests/codegen/riscv-abi/cast-local-large-enough.rs | 44 -- .../riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs | 176 ----- tests/codegen/riscv-abi/riscv64-lp64d-abi.rs | 299 -------- tests/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs | 283 -------- tests/codegen/riscv-target-abi.rs | 21 - tests/codegen/rust-abi-arch-specific-adjustment.rs | 111 --- tests/codegen/s390x-simd.rs | 143 ---- .../aarch64-shadow-call-stack-with-fixed-x18.rs | 20 - .../address-sanitizer-globals-tracking.rs | 44 -- .../cfi/add-canonical-jump-tables-flag.rs | 10 - .../cfi/add-cfi-normalize-integers-flag.rs | 10 - .../cfi/add-enable-split-lto-unit-flag.rs | 10 - .../sanitizer/cfi/dbg-location-on-cfi-blocks.rs | 19 - .../cfi/emit-type-checks-attr-no-sanitize.rs | 18 - tests/codegen/sanitizer/cfi/emit-type-checks.rs | 19 - .../cfi/emit-type-metadata-attr-cfi-encoding.rs | 73 -- ...e-metadata-id-itanium-cxx-abi-const-generics.rs | 32 - ...pe-metadata-id-itanium-cxx-abi-drop-in-place.rs | 31 - ...e-metadata-id-itanium-cxx-abi-function-types.rs | 45 -- ...t-type-metadata-id-itanium-cxx-abi-lifetimes.rs | 29 - ...a-id-itanium-cxx-abi-method-secondary-typeid.rs | 21 - .../emit-type-metadata-id-itanium-cxx-abi-paths.rs | 86 --- ...pe-metadata-id-itanium-cxx-abi-pointer-types.rs | 54 -- ...-metadata-id-itanium-cxx-abi-primitive-types.rs | 190 ----- ...ta-id-itanium-cxx-abi-repr-transparent-types.rs | 79 --- ...e-metadata-id-itanium-cxx-abi-sequence-types.rs | 36 - ...type-metadata-id-itanium-cxx-abi-trait-types.rs | 175 ----- ...tadata-id-itanium-cxx-abi-user-defined-types.rs | 62 -- ...it-type-metadata-itanium-cxx-abi-generalized.rs | 31 - ...adata-itanium-cxx-abi-normalized-generalized.rs | 31 - ...mit-type-metadata-itanium-cxx-abi-normalized.rs | 31 - .../cfi/emit-type-metadata-itanium-cxx-abi.rs | 31 - .../cfi/emit-type-metadata-trait-objects.rs | 145 ---- .../codegen/sanitizer/cfi/external_weak_symbols.rs | 24 - tests/codegen/sanitizer/cfi/generalize-pointers.rs | 46 -- tests/codegen/sanitizer/cfi/normalize-integers.rs | 46 -- .../sanitizer/dataflow-instrument-functions.rs | 9 - .../sanitizer/kasan-emits-instrumentation.rs | 41 -- .../kcfi/add-cfi-normalize-integers-flag.rs | 20 - .../codegen/sanitizer/kcfi/add-kcfi-arity-flag.rs | 19 - tests/codegen/sanitizer/kcfi/add-kcfi-flag.rs | 20 - .../codegen/sanitizer/kcfi/add-kcfi-offset-flag.rs | 20 - .../emit-kcfi-operand-bundle-attr-no-sanitize.rs | 27 - ...i-operand-bundle-itanium-cxx-abi-generalized.rs | 41 -- ...undle-itanium-cxx-abi-normalized-generalized.rs | 41 -- ...fi-operand-bundle-itanium-cxx-abi-normalized.rs | 41 -- .../emit-kcfi-operand-bundle-itanium-cxx-abi.rs | 41 -- .../sanitizer/kcfi/emit-kcfi-operand-bundle.rs | 24 - .../kcfi/emit-type-metadata-trait-objects.rs | 155 ---- tests/codegen/sanitizer/kcfi/naked-function.rs | 47 -- tests/codegen/sanitizer/memory-track-origins.rs | 31 - tests/codegen/sanitizer/memtag-attr-check.rs | 12 - tests/codegen/sanitizer/no-sanitize-inlining.rs | 31 - tests/codegen/sanitizer/no-sanitize.rs | 39 -- .../codegen/sanitizer/riscv64-shadow-call-stack.rs | 18 - tests/codegen/sanitizer/safestack-attr-check.rs | 11 - tests/codegen/sanitizer/sanitizer-recover.rs | 50 -- tests/codegen/sanitizer/scs-attr-check.rs | 17 - tests/codegen/scalar-pair-bool.rs | 45 -- tests/codegen/set-discriminant-invalid.rs | 34 - .../simd-intrinsic/simd-intrinsic-float-abs.rs | 60 -- .../simd-intrinsic/simd-intrinsic-float-ceil.rs | 60 -- .../simd-intrinsic/simd-intrinsic-float-cos.rs | 60 -- .../simd-intrinsic/simd-intrinsic-float-exp.rs | 60 -- .../simd-intrinsic/simd-intrinsic-float-exp2.rs | 60 -- .../simd-intrinsic/simd-intrinsic-float-floor.rs | 60 -- .../simd-intrinsic/simd-intrinsic-float-fma.rs | 60 -- .../simd-intrinsic/simd-intrinsic-float-fsqrt.rs | 60 -- .../simd-intrinsic/simd-intrinsic-float-log.rs | 60 -- .../simd-intrinsic/simd-intrinsic-float-log10.rs | 60 -- .../simd-intrinsic/simd-intrinsic-float-log2.rs | 60 -- .../simd-intrinsic/simd-intrinsic-float-minmax.rs | 25 - .../simd-intrinsic/simd-intrinsic-float-sin.rs | 60 -- ...simd-intrinsic-generic-arithmetic-saturating.rs | 579 --------------- .../simd-intrinsic-generic-bitmask.rs | 48 -- .../simd-intrinsic-generic-gather.rs | 55 -- .../simd-intrinsic-generic-masked-load.rs | 49 -- .../simd-intrinsic-generic-masked-store.rs | 41 -- .../simd-intrinsic-generic-scatter.rs | 47 -- .../simd-intrinsic-generic-select.rs | 48 -- .../simd-intrinsic/simd-intrinsic-mask-reduce.rs | 60 -- .../simd-intrinsic-transmute-array.rs | 58 -- tests/codegen/simd/aggregate-simd.rs | 102 --- tests/codegen/simd/extract-insert-dyn.rs | 121 ---- tests/codegen/simd/packed-simd-alignment.rs | 44 -- tests/codegen/simd/packed-simd.rs | 56 -- tests/codegen/simd/simd-wide-sum.rs | 59 -- tests/codegen/simd/simd_arith_offset.rs | 22 - tests/codegen/simd/swap-simd-types.rs | 40 -- tests/codegen/simd/unpadded-simd.rs | 19 - tests/codegen/skip-mono-inside-if-false.rs | 41 -- tests/codegen/slice-as_chunks.rs | 30 - tests/codegen/slice-indexing.rs | 99 --- tests/codegen/slice-init.rs | 108 --- tests/codegen/slice-is-ascii.rs | 16 - tests/codegen/slice-iter-fold.rs | 12 - tests/codegen/slice-iter-len-eq-zero.rs | 60 -- tests/codegen/slice-iter-nonnull.rs | 115 --- tests/codegen/slice-last-elements-optimization.rs | 37 - tests/codegen/slice-pointer-nonnull-unwrap.rs | 18 - tests/codegen/slice-position-bounds-check.rs | 25 - tests/codegen/slice-ref-equality.rs | 90 --- tests/codegen/slice-reverse.rs | 27 - tests/codegen/slice-split-at.rs | 24 - tests/codegen/slice-windows-no-bounds-check.rs | 32 - tests/codegen/slice_as_from_ptr_range.rs | 21 - .../some-abis-do-extend-params-to-32-bits.rs | 236 ------- tests/codegen/some-global-nonnull.rs | 25 - tests/codegen/sparc-struct-abi.rs | 97 --- tests/codegen/split-lto-unit.rs | 10 - .../src-hash-algorithm/src-hash-algorithm-md5.rs | 6 - .../src-hash-algorithm/src-hash-algorithm-sha1.rs | 6 - .../src-hash-algorithm-sha256.rs | 6 - tests/codegen/sroa-fragment-debuginfo.rs | 46 -- tests/codegen/sse42-implies-crc32.rs | 15 - tests/codegen/stack-probes-inline.rs | 33 - tests/codegen/stack-protector.rs | 34 - tests/codegen/static-relocation-model-msvc.rs | 24 - tests/codegen/staticlib-external-inline-fns.rs | 43 -- tests/codegen/step_by-overflow-checks.rs | 26 - tests/codegen/stores.rs | 35 - tests/codegen/string-push.rs | 11 - tests/codegen/swap-large-types.rs | 116 --- tests/codegen/swap-small-types.rs | 182 ----- tests/codegen/target-cpu-on-functions.rs | 22 - tests/codegen/target-feature-inline-closure.rs | 33 - .../codegen/target-feature-negative-implication.rs | 20 - tests/codegen/target-feature-overrides.rs | 46 -- tests/codegen/terminating-catchpad.rs | 43 -- tests/codegen/thread-local.rs | 54 -- tests/codegen/tied-features-strength.rs | 34 - tests/codegen/to_vec.rs | 10 - tests/codegen/trailing_zeros.rs | 21 - tests/codegen/transmute-optimized.rs | 120 ---- tests/codegen/transmute-scalar.rs | 143 ---- tests/codegen/try_question_mark_nop.rs | 243 ------- tests/codegen/tune-cpu-on-functions.rs | 21 - tests/codegen/tuple-layout-opt.rs | 57 -- tests/codegen/ub-checks.rs | 28 - tests/codegen/unchecked-float-casts.rs | 36 - tests/codegen/unchecked_shifts.rs | 100 --- .../codegen/uninhabited-transparent-return-abi.rs | 44 -- tests/codegen/uninit-consts.rs | 54 -- tests/codegen/uninit-repeat-in-aggregate.rs | 21 - tests/codegen/union-abi.rs | 145 ---- tests/codegen/union-aggregate.rs | 108 --- tests/codegen/unwind-abis/aapcs-unwind-abi.rs | 36 - .../unwind-abis/c-unwind-abi-panic-abort.rs | 27 - tests/codegen/unwind-abis/c-unwind-abi.rs | 27 - tests/codegen/unwind-abis/cdecl-unwind-abi.rs | 27 - tests/codegen/unwind-abis/fastcall-unwind-abi.rs | 36 - .../unwind-abis/nounwind-on-stable-panic-abort.rs | 15 - tests/codegen/unwind-abis/nounwind.rs | 16 - tests/codegen/unwind-abis/stdcall-unwind-abi.rs | 36 - tests/codegen/unwind-abis/system-unwind-abi.rs | 27 - tests/codegen/unwind-abis/sysv64-unwind-abi.rs | 36 - tests/codegen/unwind-abis/thiscall-unwind-abi.rs | 36 - tests/codegen/unwind-abis/vectorcall-unwind-abi.rs | 36 - tests/codegen/unwind-abis/win64-unwind-abi.rs | 36 - tests/codegen/unwind-and-panic-abort.rs | 16 - tests/codegen/unwind-extern-exports.rs | 15 - tests/codegen/unwind-extern-imports.rs | 21 - tests/codegen/unwind-landingpad-cold.rs | 15 - tests/codegen/unwind-landingpad-inline.rs | 39 -- tests/codegen/used_with_arg.rs | 10 - tests/codegen/var-names.rs | 15 - tests/codegen/vec-as-ptr.rs | 19 - tests/codegen/vec-calloc.rs | 182 ----- tests/codegen/vec-in-place.rs | 161 ----- tests/codegen/vec-iter-collect-len.rs | 12 - tests/codegen/vec-iter.rs | 58 -- tests/codegen/vec-len-invariant.rs | 16 - tests/codegen/vec-optimizes-away.rs | 12 - tests/codegen/vec-reserve-extend.rs | 14 - tests/codegen/vec-shrink-panik.rs | 31 - tests/codegen/vec-with-capacity.rs | 35 - tests/codegen/vec_pop_push_noop.rs | 24 - tests/codegen/vecdeque-drain.rs | 70 -- tests/codegen/vecdeque-nonempty-get-no-panic.rs | 16 - tests/codegen/vecdeque_no_panic.rs | 19 - tests/codegen/vecdeque_pop_push.rs | 67 -- tests/codegen/virtual-call-attrs-issue-137646.rs | 37 - .../codegen/virtual-function-elimination-32bit.rs | 35 - tests/codegen/virtual-function-elimination.rs | 98 --- tests/codegen/vtable-loads.rs | 16 - tests/codegen/vtable-upcast.rs | 84 --- tests/codegen/wasm_casts_trapping.rs | 157 ----- tests/codegen/wasm_exceptions.rs | 59 -- tests/codegen/zip.rs | 21 - tests/codegen/zst-offset.rs | 42 -- tests/run-make/llvm-ident/rmake.rs | 2 +- tests/ui/abi/fixed_x18.rs | 2 +- triagebot.toml | 18 +- 1332 files changed, 31747 insertions(+), 31742 deletions(-) create mode 100644 tests/codegen-llvm/README.md create mode 100644 tests/codegen-llvm/aarch64-softfloat.rs create mode 100644 tests/codegen-llvm/aarch64-struct-align-128.rs create mode 100644 tests/codegen-llvm/abi-efiapi.rs create mode 100644 tests/codegen-llvm/abi-main-signature-16bit-c-int.rs create mode 100644 tests/codegen-llvm/abi-main-signature-32bit-c-int.rs create mode 100644 tests/codegen-llvm/abi-repr-ext.rs create mode 100644 tests/codegen-llvm/abi-sysv64.rs create mode 100644 tests/codegen-llvm/abi-win64-zst.rs create mode 100644 tests/codegen-llvm/abi-x86-interrupt.rs create mode 100644 tests/codegen-llvm/abi-x86-sse.rs create mode 100644 tests/codegen-llvm/abi-x86_64_sysv.rs create mode 100644 tests/codegen-llvm/addr-of-mutate.rs create mode 100644 tests/codegen-llvm/adjustments.rs create mode 100644 tests/codegen-llvm/align-byval-alignment-mismatch.rs create mode 100644 tests/codegen-llvm/align-byval-vector.rs create mode 100644 tests/codegen-llvm/align-byval.rs create mode 100644 tests/codegen-llvm/align-enum.rs create mode 100644 tests/codegen-llvm/align-fn.rs create mode 100644 tests/codegen-llvm/align-offset.rs create mode 100644 tests/codegen-llvm/align-struct.rs create mode 100644 tests/codegen-llvm/alloc-optimisation.rs create mode 100644 tests/codegen-llvm/amdgpu-addrspacecast.rs create mode 100644 tests/codegen-llvm/array-clone.rs create mode 100644 tests/codegen-llvm/array-cmp.rs create mode 100644 tests/codegen-llvm/array-codegen.rs create mode 100644 tests/codegen-llvm/array-equality.rs create mode 100644 tests/codegen-llvm/array-from_fn.rs create mode 100644 tests/codegen-llvm/array-map.rs create mode 100644 tests/codegen-llvm/array-optimized.rs create mode 100644 tests/codegen-llvm/array-repeat.rs create mode 100644 tests/codegen-llvm/ascii-char.rs create mode 100644 tests/codegen-llvm/asm/aarch64-clobbers.rs create mode 100644 tests/codegen-llvm/asm/avr-clobbers.rs create mode 100644 tests/codegen-llvm/asm/bpf-clobbers.rs create mode 100644 tests/codegen-llvm/asm/critical.rs create mode 100644 tests/codegen-llvm/asm/csky-clobbers.rs create mode 100644 tests/codegen-llvm/asm/foo.s create mode 100644 tests/codegen-llvm/asm/global_asm.rs create mode 100644 tests/codegen-llvm/asm/global_asm_include.rs create mode 100644 tests/codegen-llvm/asm/global_asm_x2.rs create mode 100644 tests/codegen-llvm/asm/goto.rs create mode 100644 tests/codegen-llvm/asm/hexagon-clobbers.rs create mode 100644 tests/codegen-llvm/asm/may_unwind.rs create mode 100644 tests/codegen-llvm/asm/maybe-uninit.rs create mode 100644 tests/codegen-llvm/asm/msp430-clobbers.rs create mode 100644 tests/codegen-llvm/asm/multiple-options.rs create mode 100644 tests/codegen-llvm/asm/options.rs create mode 100644 tests/codegen-llvm/asm/powerpc-clobbers.rs create mode 100644 tests/codegen-llvm/asm/riscv-clobbers.rs create mode 100644 tests/codegen-llvm/asm/s390x-clobbers.rs create mode 100644 tests/codegen-llvm/asm/sanitize-llvm.rs create mode 100644 tests/codegen-llvm/asm/sparc-clobbers.rs create mode 100644 tests/codegen-llvm/asm/x86-clobber_abi.rs create mode 100644 tests/codegen-llvm/asm/x86-clobbers.rs create mode 100644 tests/codegen-llvm/asm/x86-target-clobbers.rs create mode 100644 tests/codegen-llvm/assign-desugar-debuginfo.rs create mode 100644 tests/codegen-llvm/async-closure-debug.rs create mode 100644 tests/codegen-llvm/async-fn-debug-awaitee-field.rs create mode 100644 tests/codegen-llvm/async-fn-debug-msvc.rs create mode 100644 tests/codegen-llvm/async-fn-debug.rs create mode 100644 tests/codegen-llvm/atomic-operations.rs create mode 100644 tests/codegen-llvm/atomicptr.rs create mode 100644 tests/codegen-llvm/autodiff/batched.rs create mode 100644 tests/codegen-llvm/autodiff/generic.rs create mode 100644 tests/codegen-llvm/autodiff/identical_fnc.rs create mode 100644 tests/codegen-llvm/autodiff/inline.rs create mode 100644 tests/codegen-llvm/autodiff/scalar.rs create mode 100644 tests/codegen-llvm/autodiff/sret.rs create mode 100644 tests/codegen-llvm/autodiffv2.rs create mode 100644 tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt2.rs create mode 100644 tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt3.rs create mode 100644 tests/codegen-llvm/autovectorize-f32x4.rs create mode 100644 tests/codegen-llvm/auxiliary/extern_decl.rs create mode 100644 tests/codegen-llvm/auxiliary/nounwind.rs create mode 100644 tests/codegen-llvm/auxiliary/thread_local_aux.rs create mode 100644 tests/codegen-llvm/avr/avr-func-addrspace.rs create mode 100644 tests/codegen-llvm/bigint-helpers.rs create mode 100644 tests/codegen-llvm/binary-heap-peek-mut-pop-no-panic.rs create mode 100644 tests/codegen-llvm/binary-search-index-no-bound-check.rs create mode 100644 tests/codegen-llvm/bool-cmp.rs create mode 100644 tests/codegen-llvm/bounds-checking/gep-issue-133979.rs create mode 100644 tests/codegen-llvm/box-default-debug-copies.rs create mode 100644 tests/codegen-llvm/box-uninit-bytes.rs create mode 100644 tests/codegen-llvm/bpf-alu32.rs create mode 100644 tests/codegen-llvm/branch-protection.rs create mode 100644 tests/codegen-llvm/call-llvm-intrinsics.rs create mode 100644 tests/codegen-llvm/call-tmps-lifetime.rs create mode 100644 tests/codegen-llvm/cast-optimized.rs create mode 100644 tests/codegen-llvm/cast-target-abi.rs create mode 100644 tests/codegen-llvm/catch-unwind.rs create mode 100644 tests/codegen-llvm/cdylib-external-inline-fns.rs create mode 100644 tests/codegen-llvm/cf-protection.rs create mode 100644 tests/codegen-llvm/cffi/c-variadic-copy.rs create mode 100644 tests/codegen-llvm/cffi/c-variadic-naked.rs create mode 100644 tests/codegen-llvm/cffi/c-variadic-opt.rs create mode 100644 tests/codegen-llvm/cffi/c-variadic.rs create mode 100644 tests/codegen-llvm/cffi/ffi-const.rs create mode 100644 tests/codegen-llvm/cffi/ffi-out-of-bounds-loads.rs create mode 100644 tests/codegen-llvm/cffi/ffi-pure.rs create mode 100644 tests/codegen-llvm/cfguard-checks.rs create mode 100644 tests/codegen-llvm/cfguard-disabled.rs create mode 100644 tests/codegen-llvm/cfguard-nochecks.rs create mode 100644 tests/codegen-llvm/cfguard-non-msvc.rs create mode 100644 tests/codegen-llvm/char-ascii-branchless.rs create mode 100644 tests/codegen-llvm/char-escape-debug-no-bounds-check.rs create mode 100644 tests/codegen-llvm/checked_ilog.rs create mode 100644 tests/codegen-llvm/checked_math.rs create mode 100644 tests/codegen-llvm/clone-shims.rs create mode 100644 tests/codegen-llvm/clone_as_copy.rs create mode 100644 tests/codegen-llvm/codemodels.rs create mode 100644 tests/codegen-llvm/coercions.rs create mode 100644 tests/codegen-llvm/cold-call-declare-and-call.rs create mode 100644 tests/codegen-llvm/common_prim_int_ptr.rs create mode 100644 tests/codegen-llvm/comparison-operators-2-struct.rs create mode 100644 tests/codegen-llvm/comparison-operators-2-tuple.rs create mode 100644 tests/codegen-llvm/comparison-operators-newtype.rs create mode 100644 tests/codegen-llvm/compiletest-self-test/minicore-smoke-test.rs create mode 100644 tests/codegen-llvm/const-array.rs create mode 100644 tests/codegen-llvm/const-vector.rs create mode 100644 tests/codegen-llvm/const_scalar_pair.rs create mode 100644 tests/codegen-llvm/constant-branch.rs create mode 100644 tests/codegen-llvm/consts.rs create mode 100644 tests/codegen-llvm/coroutine-debug-msvc.rs create mode 100644 tests/codegen-llvm/coroutine-debug.rs create mode 100644 tests/codegen-llvm/cross-crate-inlining/always-inline.rs create mode 100644 tests/codegen-llvm/cross-crate-inlining/auxiliary/always.rs create mode 100644 tests/codegen-llvm/cross-crate-inlining/auxiliary/leaf.rs create mode 100644 tests/codegen-llvm/cross-crate-inlining/auxiliary/never.rs create mode 100644 tests/codegen-llvm/cross-crate-inlining/leaf-inlining.rs create mode 100644 tests/codegen-llvm/cross-crate-inlining/never-inline.rs create mode 100644 tests/codegen-llvm/dealloc-no-unwind.rs create mode 100644 tests/codegen-llvm/debug-accessibility/crate-enum.rs create mode 100644 tests/codegen-llvm/debug-accessibility/crate-struct.rs create mode 100644 tests/codegen-llvm/debug-accessibility/private-enum.rs create mode 100644 tests/codegen-llvm/debug-accessibility/private-struct.rs create mode 100644 tests/codegen-llvm/debug-accessibility/public-enum.rs create mode 100644 tests/codegen-llvm/debug-accessibility/public-struct.rs create mode 100644 tests/codegen-llvm/debug-accessibility/struct-fields.rs create mode 100644 tests/codegen-llvm/debug-accessibility/super-enum.rs create mode 100644 tests/codegen-llvm/debug-accessibility/super-struct.rs create mode 100644 tests/codegen-llvm/debug-accessibility/tuple-fields.rs create mode 100644 tests/codegen-llvm/debug-alignment.rs create mode 100644 tests/codegen-llvm/debug-column-msvc.rs create mode 100644 tests/codegen-llvm/debug-column.rs create mode 100644 tests/codegen-llvm/debug-compile-unit-path.rs create mode 100644 tests/codegen-llvm/debug-fndef-size.rs create mode 100644 tests/codegen-llvm/debug-limited.rs create mode 100644 tests/codegen-llvm/debug-line-directives-only.rs create mode 100644 tests/codegen-llvm/debug-line-tables-only.rs create mode 100644 tests/codegen-llvm/debug-linkage-name.rs create mode 100644 tests/codegen-llvm/debug-vtable.rs create mode 100644 tests/codegen-llvm/debuginfo-constant-locals.rs create mode 100644 tests/codegen-llvm/debuginfo-generic-closure-env-names.rs create mode 100644 tests/codegen-llvm/debuginfo-inline-callsite-location.rs create mode 100644 tests/codegen-llvm/debuginfo-proc-macro/auxiliary/macro_def.rs create mode 100644 tests/codegen-llvm/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs create mode 100644 tests/codegen-llvm/deduced-param-attrs.rs create mode 100644 tests/codegen-llvm/default-requires-uwtable.rs create mode 100644 tests/codegen-llvm/default-visibility.rs create mode 100644 tests/codegen-llvm/direct-access-external-data.rs create mode 100644 tests/codegen-llvm/dllimports/auxiliary/dummy.rs create mode 100644 tests/codegen-llvm/dllimports/auxiliary/wrapper.rs create mode 100644 tests/codegen-llvm/dllimports/main.rs create mode 100644 tests/codegen-llvm/dont_codegen_private_const_fn_only_used_in_const_eval.rs create mode 100644 tests/codegen-llvm/drop-in-place-noalias.rs create mode 100644 tests/codegen-llvm/drop.rs create mode 100644 tests/codegen-llvm/dst-offset.rs create mode 100644 tests/codegen-llvm/dst-vtable-align-nonzero.rs create mode 100644 tests/codegen-llvm/dst-vtable-size-range.rs create mode 100644 tests/codegen-llvm/ehcontguard_disabled.rs create mode 100644 tests/codegen-llvm/ehcontguard_enabled.rs create mode 100644 tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs create mode 100644 tests/codegen-llvm/emscripten-catch-unwind-wasm-eh.rs create mode 100644 tests/codegen-llvm/enable-lto-unit-splitting.rs create mode 100644 tests/codegen-llvm/enum/enum-aggregate.rs create mode 100644 tests/codegen-llvm/enum/enum-bounds-check-derived-idx.rs create mode 100644 tests/codegen-llvm/enum/enum-bounds-check-issue-13926.rs create mode 100644 tests/codegen-llvm/enum/enum-bounds-check-issue-82871.rs create mode 100644 tests/codegen-llvm/enum/enum-bounds-check.rs create mode 100644 tests/codegen-llvm/enum/enum-debug-clike.rs create mode 100644 tests/codegen-llvm/enum/enum-debug-niche-2.rs create mode 100644 tests/codegen-llvm/enum/enum-debug-niche.rs create mode 100644 tests/codegen-llvm/enum/enum-debug-tagged.rs create mode 100644 tests/codegen-llvm/enum/enum-discriminant-eq.rs create mode 100644 tests/codegen-llvm/enum/enum-discriminant-value.rs create mode 100644 tests/codegen-llvm/enum/enum-early-otherwise-branch.rs create mode 100644 tests/codegen-llvm/enum/enum-match.rs create mode 100644 tests/codegen-llvm/enum/enum-two-variants-match.rs create mode 100644 tests/codegen-llvm/enum/enum-u128.rs create mode 100644 tests/codegen-llvm/enum/unreachable_enum_default_branch.rs create mode 100644 tests/codegen-llvm/ergonomic-clones/closure.rs create mode 100644 tests/codegen-llvm/error-provide.rs create mode 100644 tests/codegen-llvm/export-no-mangle.rs create mode 100644 tests/codegen-llvm/external-no-mangle-fns.rs create mode 100644 tests/codegen-llvm/external-no-mangle-statics.rs create mode 100644 tests/codegen-llvm/f128-wasm32-callconv.rs create mode 100644 tests/codegen-llvm/fastcall-inreg.rs create mode 100644 tests/codegen-llvm/fatptr.rs create mode 100644 tests/codegen-llvm/fewer-names.rs create mode 100644 tests/codegen-llvm/fixed-x18.rs create mode 100644 tests/codegen-llvm/float/algebraic.rs create mode 100644 tests/codegen-llvm/float/f128.rs create mode 100644 tests/codegen-llvm/float/f16-f128-inline.rs create mode 100644 tests/codegen-llvm/float/f16.rs create mode 100644 tests/codegen-llvm/float_math.rs create mode 100644 tests/codegen-llvm/fn-impl-trait-self.rs create mode 100644 tests/codegen-llvm/fn-parameters-on-different-lines-debuginfo.rs create mode 100644 tests/codegen-llvm/force-frame-pointers.rs create mode 100644 tests/codegen-llvm/force-no-unwind-tables.rs create mode 100644 tests/codegen-llvm/force-unwind-tables.rs create mode 100644 tests/codegen-llvm/frame-pointer-cli-control.rs create mode 100644 tests/codegen-llvm/frame-pointer.rs create mode 100644 tests/codegen-llvm/function-arguments-noopt.rs create mode 100644 tests/codegen-llvm/function-arguments.rs create mode 100644 tests/codegen-llvm/function-return.rs create mode 100644 tests/codegen-llvm/gdb_debug_script_load.rs create mode 100644 tests/codegen-llvm/generic-debug.rs create mode 100644 tests/codegen-llvm/gep-index.rs create mode 100644 tests/codegen-llvm/gpu-kernel-abi.rs create mode 100644 tests/codegen-llvm/gpu_offload/gpu_host.rs create mode 100644 tests/codegen-llvm/hint/cold_path.rs create mode 100644 tests/codegen-llvm/hint/likely.rs create mode 100644 tests/codegen-llvm/hint/unlikely.rs create mode 100644 tests/codegen-llvm/i128-wasm32-callconv.rs create mode 100644 tests/codegen-llvm/i128-x86-align.rs create mode 100644 tests/codegen-llvm/i128-x86-callconv.rs create mode 100644 tests/codegen-llvm/infallible-unwrap-in-opt-z.rs create mode 100644 tests/codegen-llvm/inherit_overflow.rs create mode 100644 tests/codegen-llvm/inline-always-works-always.rs create mode 100644 tests/codegen-llvm/inline-debuginfo.rs create mode 100644 tests/codegen-llvm/inline-function-args-debug-info.rs create mode 100644 tests/codegen-llvm/inline-hint.rs create mode 100644 tests/codegen-llvm/instrument-coverage/instrument-coverage-off.rs create mode 100644 tests/codegen-llvm/instrument-coverage/instrument-coverage.rs create mode 100644 tests/codegen-llvm/instrument-coverage/testprog.rs create mode 100644 tests/codegen-llvm/instrument-mcount.rs create mode 100644 tests/codegen-llvm/instrument-xray/basic.rs create mode 100644 tests/codegen-llvm/instrument-xray/options-combine.rs create mode 100644 tests/codegen-llvm/instrument-xray/options-override.rs create mode 100644 tests/codegen-llvm/integer-cmp.rs create mode 100644 tests/codegen-llvm/integer-overflow.rs create mode 100644 tests/codegen-llvm/internalize-closures.rs create mode 100644 tests/codegen-llvm/intrinsic-no-unnamed-attr.rs create mode 100644 tests/codegen-llvm/intrinsics/aggregate-thin-pointer.rs create mode 100644 tests/codegen-llvm/intrinsics/carrying_mul_add.rs create mode 100644 tests/codegen-llvm/intrinsics/cold_path.rs create mode 100644 tests/codegen-llvm/intrinsics/cold_path2.rs create mode 100644 tests/codegen-llvm/intrinsics/cold_path3.rs create mode 100644 tests/codegen-llvm/intrinsics/compare_bytes.rs create mode 100644 tests/codegen-llvm/intrinsics/const_eval_select.rs create mode 100644 tests/codegen-llvm/intrinsics/ctlz.rs create mode 100644 tests/codegen-llvm/intrinsics/ctpop.rs create mode 100644 tests/codegen-llvm/intrinsics/disjoint_bitor.rs create mode 100644 tests/codegen-llvm/intrinsics/exact_div.rs create mode 100644 tests/codegen-llvm/intrinsics/likely.rs create mode 100644 tests/codegen-llvm/intrinsics/likely_assert.rs create mode 100644 tests/codegen-llvm/intrinsics/mask.rs create mode 100644 tests/codegen-llvm/intrinsics/nontemporal.rs create mode 100644 tests/codegen-llvm/intrinsics/offset.rs create mode 100644 tests/codegen-llvm/intrinsics/offset_from.rs create mode 100644 tests/codegen-llvm/intrinsics/prefetch.rs create mode 100644 tests/codegen-llvm/intrinsics/ptr_metadata.rs create mode 100644 tests/codegen-llvm/intrinsics/rotate_left.rs create mode 100644 tests/codegen-llvm/intrinsics/rustc_intrinsic_must_be_overridden.rs create mode 100644 tests/codegen-llvm/intrinsics/select_unpredictable.rs create mode 100644 tests/codegen-llvm/intrinsics/three_way_compare.rs create mode 100644 tests/codegen-llvm/intrinsics/transmute-niched.rs create mode 100644 tests/codegen-llvm/intrinsics/transmute-x64.rs create mode 100644 tests/codegen-llvm/intrinsics/transmute.rs create mode 100644 tests/codegen-llvm/intrinsics/typed_swap.rs create mode 100644 tests/codegen-llvm/intrinsics/unchecked_math.rs create mode 100644 tests/codegen-llvm/intrinsics/unlikely.rs create mode 100644 tests/codegen-llvm/intrinsics/volatile.rs create mode 100644 tests/codegen-llvm/intrinsics/volatile_order.rs create mode 100644 tests/codegen-llvm/is_val_statically_known.rs create mode 100644 tests/codegen-llvm/issue-97217.rs create mode 100644 tests/codegen-llvm/issues/issue-101048.rs create mode 100644 tests/codegen-llvm/issues/issue-101082.rs create mode 100644 tests/codegen-llvm/issues/issue-101814.rs create mode 100644 tests/codegen-llvm/issues/issue-103132.rs create mode 100644 tests/codegen-llvm/issues/issue-103285-ptr-addr-overflow-check.rs create mode 100644 tests/codegen-llvm/issues/issue-103327.rs create mode 100644 tests/codegen-llvm/issues/issue-103840.rs create mode 100644 tests/codegen-llvm/issues/issue-105386-ub-in-debuginfo.rs create mode 100644 tests/codegen-llvm/issues/issue-106369.rs create mode 100644 tests/codegen-llvm/issues/issue-107681-unwrap_unchecked.rs create mode 100644 tests/codegen-llvm/issues/issue-108395-branchy-bool-match.rs create mode 100644 tests/codegen-llvm/issues/issue-109328-split_first.rs create mode 100644 tests/codegen-llvm/issues/issue-110797-enum-jump-same.rs create mode 100644 tests/codegen-llvm/issues/issue-111603.rs create mode 100644 tests/codegen-llvm/issues/issue-112509-slice-get-andthen-get.rs create mode 100644 tests/codegen-llvm/issues/issue-113757-bounds-check-after-cmp-max.rs create mode 100644 tests/codegen-llvm/issues/issue-114312.rs create mode 100644 tests/codegen-llvm/issues/issue-115385-llvm-jump-threading.rs create mode 100644 tests/codegen-llvm/issues/issue-116878.rs create mode 100644 tests/codegen-llvm/issues/issue-118306.rs create mode 100644 tests/codegen-llvm/issues/issue-118392.rs create mode 100644 tests/codegen-llvm/issues/issue-119422.rs create mode 100644 tests/codegen-llvm/issues/issue-121719-common-field-offset.rs create mode 100644 tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs create mode 100644 tests/codegen-llvm/issues/issue-123712-str-to-lower-autovectorization.rs create mode 100644 tests/codegen-llvm/issues/issue-126585.rs create mode 100644 tests/codegen-llvm/issues/issue-129795.rs create mode 100644 tests/codegen-llvm/issues/issue-13018.rs create mode 100644 tests/codegen-llvm/issues/issue-136329-optnone-noinline.rs create mode 100644 tests/codegen-llvm/issues/issue-15953.rs create mode 100644 tests/codegen-llvm/issues/issue-27130.rs create mode 100644 tests/codegen-llvm/issues/issue-32031.rs create mode 100644 tests/codegen-llvm/issues/issue-32364.rs create mode 100644 tests/codegen-llvm/issues/issue-34634.rs create mode 100644 tests/codegen-llvm/issues/issue-34947-pow-i32.rs create mode 100644 tests/codegen-llvm/issues/issue-36010-some-box-is_some.rs create mode 100644 tests/codegen-llvm/issues/issue-37945.rs create mode 100644 tests/codegen-llvm/issues/issue-45222.rs create mode 100644 tests/codegen-llvm/issues/issue-45466.rs create mode 100644 tests/codegen-llvm/issues/issue-45964-bounds-check-slice-pos.rs create mode 100644 tests/codegen-llvm/issues/issue-47278.rs create mode 100644 tests/codegen-llvm/issues/issue-47442.rs create mode 100644 tests/codegen-llvm/issues/issue-56267-2.rs create mode 100644 tests/codegen-llvm/issues/issue-56267.rs create mode 100644 tests/codegen-llvm/issues/issue-56927.rs create mode 100644 tests/codegen-llvm/issues/issue-58881.rs create mode 100644 tests/codegen-llvm/issues/issue-59352.rs create mode 100644 tests/codegen-llvm/issues/issue-64219-fn-ptr-call-returning-never-is-noreturn.rs create mode 100644 tests/codegen-llvm/issues/issue-68667-unwrap-combinators.rs create mode 100644 tests/codegen-llvm/issues/issue-69101-bounds-check.rs create mode 100644 tests/codegen-llvm/issues/issue-73031.rs create mode 100644 tests/codegen-llvm/issues/issue-73258.rs create mode 100644 tests/codegen-llvm/issues/issue-73338-effecient-cmp.rs create mode 100644 tests/codegen-llvm/issues/issue-73396-bounds-check-after-position.rs create mode 100644 tests/codegen-llvm/issues/issue-73827-bounds-check-index-in-subexpr.rs create mode 100644 tests/codegen-llvm/issues/issue-74938-array-split-at.rs create mode 100644 tests/codegen-llvm/issues/issue-75525-bounds-checks.rs create mode 100644 tests/codegen-llvm/issues/issue-75546.rs create mode 100644 tests/codegen-llvm/issues/issue-75659.rs create mode 100644 tests/codegen-llvm/issues/issue-75978.rs create mode 100644 tests/codegen-llvm/issues/issue-77812.rs create mode 100644 tests/codegen-llvm/issues/issue-84268.rs create mode 100644 tests/codegen-llvm/issues/issue-85872-multiple-reverse.rs create mode 100644 tests/codegen-llvm/issues/issue-86106.rs create mode 100644 tests/codegen-llvm/issues/issue-86109-eliminate-div-by-zero-check.rs create mode 100644 tests/codegen-llvm/issues/issue-93036-assert-index.rs create mode 100644 tests/codegen-llvm/issues/issue-96274.rs create mode 100644 tests/codegen-llvm/issues/issue-96497-slice-size-nowrap.rs create mode 100644 tests/codegen-llvm/issues/issue-98294-get-mut-copy-from-slice-opt.rs create mode 100644 tests/codegen-llvm/issues/issue-98678-async.rs create mode 100644 tests/codegen-llvm/issues/issue-98678-closure-coroutine.rs create mode 100644 tests/codegen-llvm/issues/issue-98678-enum.rs create mode 100644 tests/codegen-llvm/issues/issue-98678-struct-union.rs create mode 100644 tests/codegen-llvm/issues/issue-99960.rs create mode 100644 tests/codegen-llvm/issues/looping-over-ne-bytes-133528.rs create mode 100644 tests/codegen-llvm/issues/str-to-string-128690.rs create mode 100644 tests/codegen-llvm/iter-repeat-n-trivial-drop.rs create mode 100644 tests/codegen-llvm/layout-size-checks.rs create mode 100644 tests/codegen-llvm/lib-optimizations/iter-sum.rs create mode 100644 tests/codegen-llvm/lib-optimizations/slice_rotate.rs create mode 100644 tests/codegen-llvm/lifetime_start_end.rs create mode 100644 tests/codegen-llvm/link-dead-code.rs create mode 100644 tests/codegen-llvm/link_section.rs create mode 100644 tests/codegen-llvm/llvm-ident.rs create mode 100644 tests/codegen-llvm/llvm_module_flags.rs create mode 100644 tests/codegen-llvm/loads.rs create mode 100644 tests/codegen-llvm/local-generics-in-exe-internalized.rs create mode 100644 tests/codegen-llvm/loongarch-abi/call-llvm-intrinsics.rs create mode 100644 tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs create mode 100644 tests/codegen-llvm/lto-removes-invokes.rs create mode 100644 tests/codegen-llvm/macos/i686-macosx-deployment-target.rs create mode 100644 tests/codegen-llvm/macos/i686-no-macosx-deployment-target.rs create mode 100644 tests/codegen-llvm/macos/x86_64-macosx-deployment-target.rs create mode 100644 tests/codegen-llvm/macos/x86_64-no-macosx-deployment-target.rs create mode 100644 tests/codegen-llvm/mainsubprogram.rs create mode 100644 tests/codegen-llvm/match-optimized.rs create mode 100644 tests/codegen-llvm/match-optimizes-away.rs create mode 100644 tests/codegen-llvm/match-unoptimized.rs create mode 100644 tests/codegen-llvm/maybeuninit-rvo.rs create mode 100644 tests/codegen-llvm/mem-replace-big-type.rs create mode 100644 tests/codegen-llvm/mem-replace-simple-type.rs create mode 100644 tests/codegen-llvm/merge-functions.rs create mode 100644 tests/codegen-llvm/meta-filecheck/check-prefix.rs create mode 100644 tests/codegen-llvm/meta-filecheck/filecheck-flags.rs create mode 100644 tests/codegen-llvm/meta-filecheck/msvc-prefix-bad.rs create mode 100644 tests/codegen-llvm/meta-filecheck/no-directives.rs create mode 100644 tests/codegen-llvm/meta-filecheck/revision-prefix.rs create mode 100644 tests/codegen-llvm/method-declaration.rs create mode 100644 tests/codegen-llvm/min-function-alignment.rs create mode 100644 tests/codegen-llvm/mir-aggregate-no-alloca.rs create mode 100644 tests/codegen-llvm/mir-inlined-line-numbers.rs create mode 100644 tests/codegen-llvm/mir_zst_stores.rs create mode 100644 tests/codegen-llvm/move-before-nocapture-ref-arg.rs create mode 100644 tests/codegen-llvm/move-operands.rs create mode 100644 tests/codegen-llvm/naked-asan.rs create mode 100644 tests/codegen-llvm/naked-fn/aligned.rs create mode 100644 tests/codegen-llvm/naked-fn/generics.rs create mode 100644 tests/codegen-llvm/naked-fn/instruction-set.rs create mode 100644 tests/codegen-llvm/naked-fn/min-function-alignment.rs create mode 100644 tests/codegen-llvm/naked-fn/naked-functions.rs create mode 100644 tests/codegen-llvm/no-alloca-inside-if-false.rs create mode 100644 tests/codegen-llvm/no-assumes-on-casts.rs create mode 100644 tests/codegen-llvm/no-dllimport-w-cross-lang-lto.rs create mode 100644 tests/codegen-llvm/no-jump-tables.rs create mode 100644 tests/codegen-llvm/no-plt.rs create mode 100644 tests/codegen-llvm/no-redundant-item-monomorphization.rs create mode 100644 tests/codegen-llvm/no_builtins-at-crate.rs create mode 100644 tests/codegen-llvm/noalias-box-off.rs create mode 100644 tests/codegen-llvm/noalias-box.rs create mode 100644 tests/codegen-llvm/noalias-flag.rs create mode 100644 tests/codegen-llvm/noalias-freeze.rs create mode 100644 tests/codegen-llvm/noalias-refcell.rs create mode 100644 tests/codegen-llvm/noalias-rwlockreadguard.rs create mode 100644 tests/codegen-llvm/noalias-unpin.rs create mode 100644 tests/codegen-llvm/non-terminate/infinite-loop-1.rs create mode 100644 tests/codegen-llvm/non-terminate/infinite-loop-2.rs create mode 100644 tests/codegen-llvm/non-terminate/infinite-recursion.rs create mode 100644 tests/codegen-llvm/non-terminate/nonempty-infinite-loop.rs create mode 100644 tests/codegen-llvm/noreturn-uninhabited.rs create mode 100644 tests/codegen-llvm/noreturnflag.rs create mode 100644 tests/codegen-llvm/nounwind.rs create mode 100644 tests/codegen-llvm/nrvo.rs create mode 100644 tests/codegen-llvm/optimize-attr-1.rs create mode 100644 tests/codegen-llvm/option-as-slice.rs create mode 100644 tests/codegen-llvm/option-niche-eq.rs create mode 100644 tests/codegen-llvm/option-niche-unfixed/option-nonzero-eq.rs create mode 100644 tests/codegen-llvm/overaligned-constant.rs create mode 100644 tests/codegen-llvm/packed.rs create mode 100644 tests/codegen-llvm/panic-abort-windows.rs create mode 100644 tests/codegen-llvm/panic-in-drop-abort.rs create mode 100644 tests/codegen-llvm/panic-unwind-default-uwtable.rs create mode 100644 tests/codegen-llvm/patchable-function-entry/patchable-function-entry-both-flags.rs create mode 100644 tests/codegen-llvm/patchable-function-entry/patchable-function-entry-no-flag.rs create mode 100644 tests/codegen-llvm/patchable-function-entry/patchable-function-entry-one-flag.rs create mode 100644 tests/codegen-llvm/pattern_type_symbols.rs create mode 100644 tests/codegen-llvm/personality_lifetimes.rs create mode 100644 tests/codegen-llvm/pgo-counter-bias.rs create mode 100644 tests/codegen-llvm/pgo-instrumentation.rs create mode 100644 tests/codegen-llvm/pic-relocation-model.rs create mode 100644 tests/codegen-llvm/pie-relocation-model.rs create mode 100644 tests/codegen-llvm/placement-new.rs create mode 100644 tests/codegen-llvm/powerpc64le-struct-align-128.rs create mode 100644 tests/codegen-llvm/precondition-checks.rs create mode 100644 tests/codegen-llvm/ptr-arithmetic.rs create mode 100644 tests/codegen-llvm/ptr-read-metadata.rs create mode 100644 tests/codegen-llvm/range-attribute.rs create mode 100644 tests/codegen-llvm/range-loop.rs create mode 100644 tests/codegen-llvm/range_to_inclusive.rs create mode 100644 tests/codegen-llvm/refs.rs create mode 100644 tests/codegen-llvm/reg-struct-return.rs create mode 100644 tests/codegen-llvm/regparm-inreg.rs create mode 100644 tests/codegen-llvm/remap_path_prefix/aux_mod.rs create mode 100644 tests/codegen-llvm/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs create mode 100644 tests/codegen-llvm/remap_path_prefix/auxiliary/xcrate-generic.rs create mode 100644 tests/codegen-llvm/remap_path_prefix/issue-73167-remap-std.rs create mode 100644 tests/codegen-llvm/remap_path_prefix/main.rs create mode 100644 tests/codegen-llvm/remap_path_prefix/xcrate-generic.rs create mode 100644 tests/codegen-llvm/repeat-operand-zero-len.rs create mode 100644 tests/codegen-llvm/repeat-operand-zst-elem.rs create mode 100644 tests/codegen-llvm/repeat-trusted-len.rs create mode 100644 tests/codegen-llvm/repr/transparent-byval-struct-ptr.rs create mode 100644 tests/codegen-llvm/repr/transparent-imm-array.rs create mode 100644 tests/codegen-llvm/repr/transparent-mips64.rs create mode 100644 tests/codegen-llvm/repr/transparent-opaque-ptr.rs create mode 100644 tests/codegen-llvm/repr/transparent-sparc64.rs create mode 100644 tests/codegen-llvm/repr/transparent-sysv64.rs create mode 100644 tests/codegen-llvm/repr/transparent.rs create mode 100644 tests/codegen-llvm/retpoline.rs create mode 100644 tests/codegen-llvm/riscv-abi/call-llvm-intrinsics.rs create mode 100644 tests/codegen-llvm/riscv-abi/cast-local-large-enough.rs create mode 100644 tests/codegen-llvm/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs create mode 100644 tests/codegen-llvm/riscv-abi/riscv64-lp64d-abi.rs create mode 100644 tests/codegen-llvm/riscv-abi/riscv64-lp64f-lp64d-abi.rs create mode 100644 tests/codegen-llvm/riscv-target-abi.rs create mode 100644 tests/codegen-llvm/rust-abi-arch-specific-adjustment.rs create mode 100644 tests/codegen-llvm/s390x-simd.rs create mode 100644 tests/codegen-llvm/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs create mode 100644 tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs create mode 100644 tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs create mode 100644 tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs create mode 100644 tests/codegen-llvm/sanitizer/kasan-emits-instrumentation.rs create mode 100644 tests/codegen-llvm/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs create mode 100644 tests/codegen-llvm/sanitizer/kcfi/add-kcfi-arity-flag.rs create mode 100644 tests/codegen-llvm/sanitizer/kcfi/add-kcfi-flag.rs create mode 100644 tests/codegen-llvm/sanitizer/kcfi/add-kcfi-offset-flag.rs create mode 100644 tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs create mode 100644 tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs create mode 100644 tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs create mode 100644 tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs create mode 100644 tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs create mode 100644 tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs create mode 100644 tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs create mode 100644 tests/codegen-llvm/sanitizer/kcfi/naked-function.rs create mode 100644 tests/codegen-llvm/sanitizer/memory-track-origins.rs create mode 100644 tests/codegen-llvm/sanitizer/memtag-attr-check.rs create mode 100644 tests/codegen-llvm/sanitizer/no-sanitize-inlining.rs create mode 100644 tests/codegen-llvm/sanitizer/no-sanitize.rs create mode 100644 tests/codegen-llvm/sanitizer/riscv64-shadow-call-stack.rs create mode 100644 tests/codegen-llvm/sanitizer/safestack-attr-check.rs create mode 100644 tests/codegen-llvm/sanitizer/sanitizer-recover.rs create mode 100644 tests/codegen-llvm/sanitizer/scs-attr-check.rs create mode 100644 tests/codegen-llvm/scalar-pair-bool.rs create mode 100644 tests/codegen-llvm/set-discriminant-invalid.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-abs.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-ceil.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-cos.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp2.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-floor.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fma.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fsqrt.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log10.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log2.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-minmax.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-sin.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-bitmask.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-gather.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-load.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-store.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-scatter.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-select.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-mask-reduce.rs create mode 100644 tests/codegen-llvm/simd-intrinsic/simd-intrinsic-transmute-array.rs create mode 100644 tests/codegen-llvm/simd/aggregate-simd.rs create mode 100644 tests/codegen-llvm/simd/extract-insert-dyn.rs create mode 100644 tests/codegen-llvm/simd/packed-simd-alignment.rs create mode 100644 tests/codegen-llvm/simd/packed-simd.rs create mode 100644 tests/codegen-llvm/simd/simd-wide-sum.rs create mode 100644 tests/codegen-llvm/simd/simd_arith_offset.rs create mode 100644 tests/codegen-llvm/simd/swap-simd-types.rs create mode 100644 tests/codegen-llvm/simd/unpadded-simd.rs create mode 100644 tests/codegen-llvm/skip-mono-inside-if-false.rs create mode 100644 tests/codegen-llvm/slice-as_chunks.rs create mode 100644 tests/codegen-llvm/slice-indexing.rs create mode 100644 tests/codegen-llvm/slice-init.rs create mode 100644 tests/codegen-llvm/slice-is-ascii.rs create mode 100644 tests/codegen-llvm/slice-iter-fold.rs create mode 100644 tests/codegen-llvm/slice-iter-len-eq-zero.rs create mode 100644 tests/codegen-llvm/slice-iter-nonnull.rs create mode 100644 tests/codegen-llvm/slice-last-elements-optimization.rs create mode 100644 tests/codegen-llvm/slice-pointer-nonnull-unwrap.rs create mode 100644 tests/codegen-llvm/slice-position-bounds-check.rs create mode 100644 tests/codegen-llvm/slice-ref-equality.rs create mode 100644 tests/codegen-llvm/slice-reverse.rs create mode 100644 tests/codegen-llvm/slice-split-at.rs create mode 100644 tests/codegen-llvm/slice-windows-no-bounds-check.rs create mode 100644 tests/codegen-llvm/slice_as_from_ptr_range.rs create mode 100644 tests/codegen-llvm/some-abis-do-extend-params-to-32-bits.rs create mode 100644 tests/codegen-llvm/some-global-nonnull.rs create mode 100644 tests/codegen-llvm/sparc-struct-abi.rs create mode 100644 tests/codegen-llvm/split-lto-unit.rs create mode 100644 tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-md5.rs create mode 100644 tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha1.rs create mode 100644 tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha256.rs create mode 100644 tests/codegen-llvm/sroa-fragment-debuginfo.rs create mode 100644 tests/codegen-llvm/sse42-implies-crc32.rs create mode 100644 tests/codegen-llvm/stack-probes-inline.rs create mode 100644 tests/codegen-llvm/stack-protector.rs create mode 100644 tests/codegen-llvm/static-relocation-model-msvc.rs create mode 100644 tests/codegen-llvm/staticlib-external-inline-fns.rs create mode 100644 tests/codegen-llvm/step_by-overflow-checks.rs create mode 100644 tests/codegen-llvm/stores.rs create mode 100644 tests/codegen-llvm/string-push.rs create mode 100644 tests/codegen-llvm/swap-large-types.rs create mode 100644 tests/codegen-llvm/swap-small-types.rs create mode 100644 tests/codegen-llvm/target-cpu-on-functions.rs create mode 100644 tests/codegen-llvm/target-feature-inline-closure.rs create mode 100644 tests/codegen-llvm/target-feature-negative-implication.rs create mode 100644 tests/codegen-llvm/target-feature-overrides.rs create mode 100644 tests/codegen-llvm/terminating-catchpad.rs create mode 100644 tests/codegen-llvm/thread-local.rs create mode 100644 tests/codegen-llvm/tied-features-strength.rs create mode 100644 tests/codegen-llvm/to_vec.rs create mode 100644 tests/codegen-llvm/trailing_zeros.rs create mode 100644 tests/codegen-llvm/transmute-optimized.rs create mode 100644 tests/codegen-llvm/transmute-scalar.rs create mode 100644 tests/codegen-llvm/try_question_mark_nop.rs create mode 100644 tests/codegen-llvm/tune-cpu-on-functions.rs create mode 100644 tests/codegen-llvm/tuple-layout-opt.rs create mode 100644 tests/codegen-llvm/ub-checks.rs create mode 100644 tests/codegen-llvm/unchecked-float-casts.rs create mode 100644 tests/codegen-llvm/unchecked_shifts.rs create mode 100644 tests/codegen-llvm/uninhabited-transparent-return-abi.rs create mode 100644 tests/codegen-llvm/uninit-consts.rs create mode 100644 tests/codegen-llvm/uninit-repeat-in-aggregate.rs create mode 100644 tests/codegen-llvm/union-abi.rs create mode 100644 tests/codegen-llvm/union-aggregate.rs create mode 100644 tests/codegen-llvm/unwind-abis/aapcs-unwind-abi.rs create mode 100644 tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs create mode 100644 tests/codegen-llvm/unwind-abis/c-unwind-abi.rs create mode 100644 tests/codegen-llvm/unwind-abis/cdecl-unwind-abi.rs create mode 100644 tests/codegen-llvm/unwind-abis/fastcall-unwind-abi.rs create mode 100644 tests/codegen-llvm/unwind-abis/nounwind-on-stable-panic-abort.rs create mode 100644 tests/codegen-llvm/unwind-abis/nounwind.rs create mode 100644 tests/codegen-llvm/unwind-abis/stdcall-unwind-abi.rs create mode 100644 tests/codegen-llvm/unwind-abis/system-unwind-abi.rs create mode 100644 tests/codegen-llvm/unwind-abis/sysv64-unwind-abi.rs create mode 100644 tests/codegen-llvm/unwind-abis/thiscall-unwind-abi.rs create mode 100644 tests/codegen-llvm/unwind-abis/vectorcall-unwind-abi.rs create mode 100644 tests/codegen-llvm/unwind-abis/win64-unwind-abi.rs create mode 100644 tests/codegen-llvm/unwind-and-panic-abort.rs create mode 100644 tests/codegen-llvm/unwind-extern-exports.rs create mode 100644 tests/codegen-llvm/unwind-extern-imports.rs create mode 100644 tests/codegen-llvm/unwind-landingpad-cold.rs create mode 100644 tests/codegen-llvm/unwind-landingpad-inline.rs create mode 100644 tests/codegen-llvm/used_with_arg.rs create mode 100644 tests/codegen-llvm/var-names.rs create mode 100644 tests/codegen-llvm/vec-as-ptr.rs create mode 100644 tests/codegen-llvm/vec-calloc.rs create mode 100644 tests/codegen-llvm/vec-in-place.rs create mode 100644 tests/codegen-llvm/vec-iter-collect-len.rs create mode 100644 tests/codegen-llvm/vec-iter.rs create mode 100644 tests/codegen-llvm/vec-len-invariant.rs create mode 100644 tests/codegen-llvm/vec-optimizes-away.rs create mode 100644 tests/codegen-llvm/vec-reserve-extend.rs create mode 100644 tests/codegen-llvm/vec-shrink-panik.rs create mode 100644 tests/codegen-llvm/vec-with-capacity.rs create mode 100644 tests/codegen-llvm/vec_pop_push_noop.rs create mode 100644 tests/codegen-llvm/vecdeque-drain.rs create mode 100644 tests/codegen-llvm/vecdeque-nonempty-get-no-panic.rs create mode 100644 tests/codegen-llvm/vecdeque_no_panic.rs create mode 100644 tests/codegen-llvm/vecdeque_pop_push.rs create mode 100644 tests/codegen-llvm/virtual-call-attrs-issue-137646.rs create mode 100644 tests/codegen-llvm/virtual-function-elimination-32bit.rs create mode 100644 tests/codegen-llvm/virtual-function-elimination.rs create mode 100644 tests/codegen-llvm/vtable-loads.rs create mode 100644 tests/codegen-llvm/vtable-upcast.rs create mode 100644 tests/codegen-llvm/wasm_casts_trapping.rs create mode 100644 tests/codegen-llvm/wasm_exceptions.rs create mode 100644 tests/codegen-llvm/zip.rs create mode 100644 tests/codegen-llvm/zst-offset.rs delete mode 100644 tests/codegen/README.md delete mode 100644 tests/codegen/aarch64-softfloat.rs delete mode 100644 tests/codegen/aarch64-struct-align-128.rs delete mode 100644 tests/codegen/abi-efiapi.rs delete mode 100644 tests/codegen/abi-main-signature-16bit-c-int.rs delete mode 100644 tests/codegen/abi-main-signature-32bit-c-int.rs delete mode 100644 tests/codegen/abi-repr-ext.rs delete mode 100644 tests/codegen/abi-sysv64.rs delete mode 100644 tests/codegen/abi-win64-zst.rs delete mode 100644 tests/codegen/abi-x86-interrupt.rs delete mode 100644 tests/codegen/abi-x86-sse.rs delete mode 100644 tests/codegen/abi-x86_64_sysv.rs delete mode 100644 tests/codegen/addr-of-mutate.rs delete mode 100644 tests/codegen/adjustments.rs delete mode 100644 tests/codegen/align-byval-alignment-mismatch.rs delete mode 100644 tests/codegen/align-byval-vector.rs delete mode 100644 tests/codegen/align-byval.rs delete mode 100644 tests/codegen/align-enum.rs delete mode 100644 tests/codegen/align-fn.rs delete mode 100644 tests/codegen/align-offset.rs delete mode 100644 tests/codegen/align-struct.rs delete mode 100644 tests/codegen/alloc-optimisation.rs delete mode 100644 tests/codegen/amdgpu-addrspacecast.rs delete mode 100644 tests/codegen/array-clone.rs delete mode 100644 tests/codegen/array-cmp.rs delete mode 100644 tests/codegen/array-codegen.rs delete mode 100644 tests/codegen/array-equality.rs delete mode 100644 tests/codegen/array-from_fn.rs delete mode 100644 tests/codegen/array-map.rs delete mode 100644 tests/codegen/array-optimized.rs delete mode 100644 tests/codegen/array-repeat.rs delete mode 100644 tests/codegen/ascii-char.rs delete mode 100644 tests/codegen/asm/aarch64-clobbers.rs delete mode 100644 tests/codegen/asm/avr-clobbers.rs delete mode 100644 tests/codegen/asm/bpf-clobbers.rs delete mode 100644 tests/codegen/asm/critical.rs delete mode 100644 tests/codegen/asm/csky-clobbers.rs delete mode 100644 tests/codegen/asm/foo.s delete mode 100644 tests/codegen/asm/global_asm.rs delete mode 100644 tests/codegen/asm/global_asm_include.rs delete mode 100644 tests/codegen/asm/global_asm_x2.rs delete mode 100644 tests/codegen/asm/goto.rs delete mode 100644 tests/codegen/asm/hexagon-clobbers.rs delete mode 100644 tests/codegen/asm/may_unwind.rs delete mode 100644 tests/codegen/asm/maybe-uninit.rs delete mode 100644 tests/codegen/asm/msp430-clobbers.rs delete mode 100644 tests/codegen/asm/multiple-options.rs delete mode 100644 tests/codegen/asm/options.rs delete mode 100644 tests/codegen/asm/powerpc-clobbers.rs delete mode 100644 tests/codegen/asm/riscv-clobbers.rs delete mode 100644 tests/codegen/asm/s390x-clobbers.rs delete mode 100644 tests/codegen/asm/sanitize-llvm.rs delete mode 100644 tests/codegen/asm/sparc-clobbers.rs delete mode 100644 tests/codegen/asm/x86-clobber_abi.rs delete mode 100644 tests/codegen/asm/x86-clobbers.rs delete mode 100644 tests/codegen/asm/x86-target-clobbers.rs delete mode 100644 tests/codegen/assign-desugar-debuginfo.rs delete mode 100644 tests/codegen/async-closure-debug.rs delete mode 100644 tests/codegen/async-fn-debug-awaitee-field.rs delete mode 100644 tests/codegen/async-fn-debug-msvc.rs delete mode 100644 tests/codegen/async-fn-debug.rs delete mode 100644 tests/codegen/atomic-operations.rs delete mode 100644 tests/codegen/atomicptr.rs delete mode 100644 tests/codegen/autodiff/batched.rs delete mode 100644 tests/codegen/autodiff/generic.rs delete mode 100644 tests/codegen/autodiff/identical_fnc.rs delete mode 100644 tests/codegen/autodiff/inline.rs delete mode 100644 tests/codegen/autodiff/scalar.rs delete mode 100644 tests/codegen/autodiff/sret.rs delete mode 100644 tests/codegen/autodiffv2.rs delete mode 100644 tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs delete mode 100644 tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs delete mode 100644 tests/codegen/autovectorize-f32x4.rs delete mode 100644 tests/codegen/auxiliary/extern_decl.rs delete mode 100644 tests/codegen/auxiliary/nounwind.rs delete mode 100644 tests/codegen/auxiliary/thread_local_aux.rs delete mode 100644 tests/codegen/avr/avr-func-addrspace.rs delete mode 100644 tests/codegen/bigint-helpers.rs delete mode 100644 tests/codegen/binary-heap-peek-mut-pop-no-panic.rs delete mode 100644 tests/codegen/binary-search-index-no-bound-check.rs delete mode 100644 tests/codegen/bool-cmp.rs delete mode 100644 tests/codegen/bounds-checking/gep-issue-133979.rs delete mode 100644 tests/codegen/box-default-debug-copies.rs delete mode 100644 tests/codegen/box-uninit-bytes.rs delete mode 100644 tests/codegen/bpf-alu32.rs delete mode 100644 tests/codegen/branch-protection.rs delete mode 100644 tests/codegen/call-llvm-intrinsics.rs delete mode 100644 tests/codegen/call-tmps-lifetime.rs delete mode 100644 tests/codegen/cast-optimized.rs delete mode 100644 tests/codegen/cast-target-abi.rs delete mode 100644 tests/codegen/catch-unwind.rs delete mode 100644 tests/codegen/cdylib-external-inline-fns.rs delete mode 100644 tests/codegen/cf-protection.rs delete mode 100644 tests/codegen/cffi/c-variadic-copy.rs delete mode 100644 tests/codegen/cffi/c-variadic-naked.rs delete mode 100644 tests/codegen/cffi/c-variadic-opt.rs delete mode 100644 tests/codegen/cffi/c-variadic.rs delete mode 100644 tests/codegen/cffi/ffi-const.rs delete mode 100644 tests/codegen/cffi/ffi-out-of-bounds-loads.rs delete mode 100644 tests/codegen/cffi/ffi-pure.rs delete mode 100644 tests/codegen/cfguard-checks.rs delete mode 100644 tests/codegen/cfguard-disabled.rs delete mode 100644 tests/codegen/cfguard-nochecks.rs delete mode 100644 tests/codegen/cfguard-non-msvc.rs delete mode 100644 tests/codegen/char-ascii-branchless.rs delete mode 100644 tests/codegen/char-escape-debug-no-bounds-check.rs delete mode 100644 tests/codegen/checked_ilog.rs delete mode 100644 tests/codegen/checked_math.rs delete mode 100644 tests/codegen/clone-shims.rs delete mode 100644 tests/codegen/clone_as_copy.rs delete mode 100644 tests/codegen/codemodels.rs delete mode 100644 tests/codegen/coercions.rs delete mode 100644 tests/codegen/cold-call-declare-and-call.rs delete mode 100644 tests/codegen/common_prim_int_ptr.rs delete mode 100644 tests/codegen/comparison-operators-2-struct.rs delete mode 100644 tests/codegen/comparison-operators-2-tuple.rs delete mode 100644 tests/codegen/comparison-operators-newtype.rs delete mode 100644 tests/codegen/compiletest-self-test/minicore-smoke-test.rs delete mode 100644 tests/codegen/const-array.rs delete mode 100644 tests/codegen/const-vector.rs delete mode 100644 tests/codegen/const_scalar_pair.rs delete mode 100644 tests/codegen/constant-branch.rs delete mode 100644 tests/codegen/consts.rs delete mode 100644 tests/codegen/coroutine-debug-msvc.rs delete mode 100644 tests/codegen/coroutine-debug.rs delete mode 100644 tests/codegen/cross-crate-inlining/always-inline.rs delete mode 100644 tests/codegen/cross-crate-inlining/auxiliary/always.rs delete mode 100644 tests/codegen/cross-crate-inlining/auxiliary/leaf.rs delete mode 100644 tests/codegen/cross-crate-inlining/auxiliary/never.rs delete mode 100644 tests/codegen/cross-crate-inlining/leaf-inlining.rs delete mode 100644 tests/codegen/cross-crate-inlining/never-inline.rs delete mode 100644 tests/codegen/dealloc-no-unwind.rs delete mode 100644 tests/codegen/debug-accessibility/crate-enum.rs delete mode 100644 tests/codegen/debug-accessibility/crate-struct.rs delete mode 100644 tests/codegen/debug-accessibility/private-enum.rs delete mode 100644 tests/codegen/debug-accessibility/private-struct.rs delete mode 100644 tests/codegen/debug-accessibility/public-enum.rs delete mode 100644 tests/codegen/debug-accessibility/public-struct.rs delete mode 100644 tests/codegen/debug-accessibility/struct-fields.rs delete mode 100644 tests/codegen/debug-accessibility/super-enum.rs delete mode 100644 tests/codegen/debug-accessibility/super-struct.rs delete mode 100644 tests/codegen/debug-accessibility/tuple-fields.rs delete mode 100644 tests/codegen/debug-alignment.rs delete mode 100644 tests/codegen/debug-column-msvc.rs delete mode 100644 tests/codegen/debug-column.rs delete mode 100644 tests/codegen/debug-compile-unit-path.rs delete mode 100644 tests/codegen/debug-fndef-size.rs delete mode 100644 tests/codegen/debug-limited.rs delete mode 100644 tests/codegen/debug-line-directives-only.rs delete mode 100644 tests/codegen/debug-line-tables-only.rs delete mode 100644 tests/codegen/debug-linkage-name.rs delete mode 100644 tests/codegen/debug-vtable.rs delete mode 100644 tests/codegen/debuginfo-constant-locals.rs delete mode 100644 tests/codegen/debuginfo-generic-closure-env-names.rs delete mode 100644 tests/codegen/debuginfo-inline-callsite-location.rs delete mode 100644 tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs delete mode 100644 tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs delete mode 100644 tests/codegen/deduced-param-attrs.rs delete mode 100644 tests/codegen/default-requires-uwtable.rs delete mode 100644 tests/codegen/default-visibility.rs delete mode 100644 tests/codegen/direct-access-external-data.rs delete mode 100644 tests/codegen/dllimports/auxiliary/dummy.rs delete mode 100644 tests/codegen/dllimports/auxiliary/wrapper.rs delete mode 100644 tests/codegen/dllimports/main.rs delete mode 100644 tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs delete mode 100644 tests/codegen/drop-in-place-noalias.rs delete mode 100644 tests/codegen/drop.rs delete mode 100644 tests/codegen/dst-offset.rs delete mode 100644 tests/codegen/dst-vtable-align-nonzero.rs delete mode 100644 tests/codegen/dst-vtable-size-range.rs delete mode 100644 tests/codegen/ehcontguard_disabled.rs delete mode 100644 tests/codegen/ehcontguard_enabled.rs delete mode 100644 tests/codegen/emscripten-catch-unwind-js-eh.rs delete mode 100644 tests/codegen/emscripten-catch-unwind-wasm-eh.rs delete mode 100644 tests/codegen/enable-lto-unit-splitting.rs delete mode 100644 tests/codegen/enum/enum-aggregate.rs delete mode 100644 tests/codegen/enum/enum-bounds-check-derived-idx.rs delete mode 100644 tests/codegen/enum/enum-bounds-check-issue-13926.rs delete mode 100644 tests/codegen/enum/enum-bounds-check-issue-82871.rs delete mode 100644 tests/codegen/enum/enum-bounds-check.rs delete mode 100644 tests/codegen/enum/enum-debug-clike.rs delete mode 100644 tests/codegen/enum/enum-debug-niche-2.rs delete mode 100644 tests/codegen/enum/enum-debug-niche.rs delete mode 100644 tests/codegen/enum/enum-debug-tagged.rs delete mode 100644 tests/codegen/enum/enum-discriminant-eq.rs delete mode 100644 tests/codegen/enum/enum-discriminant-value.rs delete mode 100644 tests/codegen/enum/enum-early-otherwise-branch.rs delete mode 100644 tests/codegen/enum/enum-match.rs delete mode 100644 tests/codegen/enum/enum-two-variants-match.rs delete mode 100644 tests/codegen/enum/enum-u128.rs delete mode 100644 tests/codegen/enum/unreachable_enum_default_branch.rs delete mode 100644 tests/codegen/ergonomic-clones/closure.rs delete mode 100644 tests/codegen/error-provide.rs delete mode 100644 tests/codegen/export-no-mangle.rs delete mode 100644 tests/codegen/external-no-mangle-fns.rs delete mode 100644 tests/codegen/external-no-mangle-statics.rs delete mode 100644 tests/codegen/f128-wasm32-callconv.rs delete mode 100644 tests/codegen/fastcall-inreg.rs delete mode 100644 tests/codegen/fatptr.rs delete mode 100644 tests/codegen/fewer-names.rs delete mode 100644 tests/codegen/fixed-x18.rs delete mode 100644 tests/codegen/float/algebraic.rs delete mode 100644 tests/codegen/float/f128.rs delete mode 100644 tests/codegen/float/f16-f128-inline.rs delete mode 100644 tests/codegen/float/f16.rs delete mode 100644 tests/codegen/float_math.rs delete mode 100644 tests/codegen/fn-impl-trait-self.rs delete mode 100644 tests/codegen/fn-parameters-on-different-lines-debuginfo.rs delete mode 100644 tests/codegen/force-frame-pointers.rs delete mode 100644 tests/codegen/force-no-unwind-tables.rs delete mode 100644 tests/codegen/force-unwind-tables.rs delete mode 100644 tests/codegen/frame-pointer-cli-control.rs delete mode 100644 tests/codegen/frame-pointer.rs delete mode 100644 tests/codegen/function-arguments-noopt.rs delete mode 100644 tests/codegen/function-arguments.rs delete mode 100644 tests/codegen/function-return.rs delete mode 100644 tests/codegen/gdb_debug_script_load.rs delete mode 100644 tests/codegen/generic-debug.rs delete mode 100644 tests/codegen/gep-index.rs delete mode 100644 tests/codegen/gpu-kernel-abi.rs delete mode 100644 tests/codegen/gpu_offload/gpu_host.rs delete mode 100644 tests/codegen/hint/cold_path.rs delete mode 100644 tests/codegen/hint/likely.rs delete mode 100644 tests/codegen/hint/unlikely.rs delete mode 100644 tests/codegen/i128-wasm32-callconv.rs delete mode 100644 tests/codegen/i128-x86-align.rs delete mode 100644 tests/codegen/i128-x86-callconv.rs delete mode 100644 tests/codegen/infallible-unwrap-in-opt-z.rs delete mode 100644 tests/codegen/inherit_overflow.rs delete mode 100644 tests/codegen/inline-always-works-always.rs delete mode 100644 tests/codegen/inline-debuginfo.rs delete mode 100644 tests/codegen/inline-function-args-debug-info.rs delete mode 100644 tests/codegen/inline-hint.rs delete mode 100644 tests/codegen/instrument-coverage/instrument-coverage-off.rs delete mode 100644 tests/codegen/instrument-coverage/instrument-coverage.rs delete mode 100644 tests/codegen/instrument-coverage/testprog.rs delete mode 100644 tests/codegen/instrument-mcount.rs delete mode 100644 tests/codegen/instrument-xray/basic.rs delete mode 100644 tests/codegen/instrument-xray/options-combine.rs delete mode 100644 tests/codegen/instrument-xray/options-override.rs delete mode 100644 tests/codegen/integer-cmp.rs delete mode 100644 tests/codegen/integer-overflow.rs delete mode 100644 tests/codegen/internalize-closures.rs delete mode 100644 tests/codegen/intrinsic-no-unnamed-attr.rs delete mode 100644 tests/codegen/intrinsics/aggregate-thin-pointer.rs delete mode 100644 tests/codegen/intrinsics/carrying_mul_add.rs delete mode 100644 tests/codegen/intrinsics/cold_path.rs delete mode 100644 tests/codegen/intrinsics/cold_path2.rs delete mode 100644 tests/codegen/intrinsics/cold_path3.rs delete mode 100644 tests/codegen/intrinsics/compare_bytes.rs delete mode 100644 tests/codegen/intrinsics/const_eval_select.rs delete mode 100644 tests/codegen/intrinsics/ctlz.rs delete mode 100644 tests/codegen/intrinsics/ctpop.rs delete mode 100644 tests/codegen/intrinsics/disjoint_bitor.rs delete mode 100644 tests/codegen/intrinsics/exact_div.rs delete mode 100644 tests/codegen/intrinsics/likely.rs delete mode 100644 tests/codegen/intrinsics/likely_assert.rs delete mode 100644 tests/codegen/intrinsics/mask.rs delete mode 100644 tests/codegen/intrinsics/nontemporal.rs delete mode 100644 tests/codegen/intrinsics/offset.rs delete mode 100644 tests/codegen/intrinsics/offset_from.rs delete mode 100644 tests/codegen/intrinsics/prefetch.rs delete mode 100644 tests/codegen/intrinsics/ptr_metadata.rs delete mode 100644 tests/codegen/intrinsics/rotate_left.rs delete mode 100644 tests/codegen/intrinsics/rustc_intrinsic_must_be_overridden.rs delete mode 100644 tests/codegen/intrinsics/select_unpredictable.rs delete mode 100644 tests/codegen/intrinsics/three_way_compare.rs delete mode 100644 tests/codegen/intrinsics/transmute-niched.rs delete mode 100644 tests/codegen/intrinsics/transmute-x64.rs delete mode 100644 tests/codegen/intrinsics/transmute.rs delete mode 100644 tests/codegen/intrinsics/typed_swap.rs delete mode 100644 tests/codegen/intrinsics/unchecked_math.rs delete mode 100644 tests/codegen/intrinsics/unlikely.rs delete mode 100644 tests/codegen/intrinsics/volatile.rs delete mode 100644 tests/codegen/intrinsics/volatile_order.rs delete mode 100644 tests/codegen/is_val_statically_known.rs delete mode 100644 tests/codegen/issue-97217.rs delete mode 100644 tests/codegen/issues/issue-101048.rs delete mode 100644 tests/codegen/issues/issue-101082.rs delete mode 100644 tests/codegen/issues/issue-101814.rs delete mode 100644 tests/codegen/issues/issue-103132.rs delete mode 100644 tests/codegen/issues/issue-103285-ptr-addr-overflow-check.rs delete mode 100644 tests/codegen/issues/issue-103327.rs delete mode 100644 tests/codegen/issues/issue-103840.rs delete mode 100644 tests/codegen/issues/issue-105386-ub-in-debuginfo.rs delete mode 100644 tests/codegen/issues/issue-106369.rs delete mode 100644 tests/codegen/issues/issue-107681-unwrap_unchecked.rs delete mode 100644 tests/codegen/issues/issue-108395-branchy-bool-match.rs delete mode 100644 tests/codegen/issues/issue-109328-split_first.rs delete mode 100644 tests/codegen/issues/issue-110797-enum-jump-same.rs delete mode 100644 tests/codegen/issues/issue-111603.rs delete mode 100644 tests/codegen/issues/issue-112509-slice-get-andthen-get.rs delete mode 100644 tests/codegen/issues/issue-113757-bounds-check-after-cmp-max.rs delete mode 100644 tests/codegen/issues/issue-114312.rs delete mode 100644 tests/codegen/issues/issue-115385-llvm-jump-threading.rs delete mode 100644 tests/codegen/issues/issue-116878.rs delete mode 100644 tests/codegen/issues/issue-118306.rs delete mode 100644 tests/codegen/issues/issue-118392.rs delete mode 100644 tests/codegen/issues/issue-119422.rs delete mode 100644 tests/codegen/issues/issue-121719-common-field-offset.rs delete mode 100644 tests/codegen/issues/issue-122600-ptr-discriminant-update.rs delete mode 100644 tests/codegen/issues/issue-123712-str-to-lower-autovectorization.rs delete mode 100644 tests/codegen/issues/issue-126585.rs delete mode 100644 tests/codegen/issues/issue-129795.rs delete mode 100644 tests/codegen/issues/issue-13018.rs delete mode 100644 tests/codegen/issues/issue-136329-optnone-noinline.rs delete mode 100644 tests/codegen/issues/issue-15953.rs delete mode 100644 tests/codegen/issues/issue-27130.rs delete mode 100644 tests/codegen/issues/issue-32031.rs delete mode 100644 tests/codegen/issues/issue-32364.rs delete mode 100644 tests/codegen/issues/issue-34634.rs delete mode 100644 tests/codegen/issues/issue-34947-pow-i32.rs delete mode 100644 tests/codegen/issues/issue-36010-some-box-is_some.rs delete mode 100644 tests/codegen/issues/issue-37945.rs delete mode 100644 tests/codegen/issues/issue-45222.rs delete mode 100644 tests/codegen/issues/issue-45466.rs delete mode 100644 tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs delete mode 100644 tests/codegen/issues/issue-47278.rs delete mode 100644 tests/codegen/issues/issue-47442.rs delete mode 100644 tests/codegen/issues/issue-56267-2.rs delete mode 100644 tests/codegen/issues/issue-56267.rs delete mode 100644 tests/codegen/issues/issue-56927.rs delete mode 100644 tests/codegen/issues/issue-58881.rs delete mode 100644 tests/codegen/issues/issue-59352.rs delete mode 100644 tests/codegen/issues/issue-64219-fn-ptr-call-returning-never-is-noreturn.rs delete mode 100644 tests/codegen/issues/issue-68667-unwrap-combinators.rs delete mode 100644 tests/codegen/issues/issue-69101-bounds-check.rs delete mode 100644 tests/codegen/issues/issue-73031.rs delete mode 100644 tests/codegen/issues/issue-73258.rs delete mode 100644 tests/codegen/issues/issue-73338-effecient-cmp.rs delete mode 100644 tests/codegen/issues/issue-73396-bounds-check-after-position.rs delete mode 100644 tests/codegen/issues/issue-73827-bounds-check-index-in-subexpr.rs delete mode 100644 tests/codegen/issues/issue-74938-array-split-at.rs delete mode 100644 tests/codegen/issues/issue-75525-bounds-checks.rs delete mode 100644 tests/codegen/issues/issue-75546.rs delete mode 100644 tests/codegen/issues/issue-75659.rs delete mode 100644 tests/codegen/issues/issue-75978.rs delete mode 100644 tests/codegen/issues/issue-77812.rs delete mode 100644 tests/codegen/issues/issue-84268.rs delete mode 100644 tests/codegen/issues/issue-85872-multiple-reverse.rs delete mode 100644 tests/codegen/issues/issue-86106.rs delete mode 100644 tests/codegen/issues/issue-86109-eliminate-div-by-zero-check.rs delete mode 100644 tests/codegen/issues/issue-93036-assert-index.rs delete mode 100644 tests/codegen/issues/issue-96274.rs delete mode 100644 tests/codegen/issues/issue-96497-slice-size-nowrap.rs delete mode 100644 tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs delete mode 100644 tests/codegen/issues/issue-98678-async.rs delete mode 100644 tests/codegen/issues/issue-98678-closure-coroutine.rs delete mode 100644 tests/codegen/issues/issue-98678-enum.rs delete mode 100644 tests/codegen/issues/issue-98678-struct-union.rs delete mode 100644 tests/codegen/issues/issue-99960.rs delete mode 100644 tests/codegen/issues/looping-over-ne-bytes-133528.rs delete mode 100644 tests/codegen/issues/str-to-string-128690.rs delete mode 100644 tests/codegen/iter-repeat-n-trivial-drop.rs delete mode 100644 tests/codegen/layout-size-checks.rs delete mode 100644 tests/codegen/lib-optimizations/iter-sum.rs delete mode 100644 tests/codegen/lib-optimizations/slice_rotate.rs delete mode 100644 tests/codegen/lifetime_start_end.rs delete mode 100644 tests/codegen/link-dead-code.rs delete mode 100644 tests/codegen/link_section.rs delete mode 100644 tests/codegen/llvm-ident.rs delete mode 100644 tests/codegen/llvm_module_flags.rs delete mode 100644 tests/codegen/loads.rs delete mode 100644 tests/codegen/local-generics-in-exe-internalized.rs delete mode 100644 tests/codegen/loongarch-abi/call-llvm-intrinsics.rs delete mode 100644 tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs delete mode 100644 tests/codegen/lto-removes-invokes.rs delete mode 100644 tests/codegen/macos/i686-macosx-deployment-target.rs delete mode 100644 tests/codegen/macos/i686-no-macosx-deployment-target.rs delete mode 100644 tests/codegen/macos/x86_64-macosx-deployment-target.rs delete mode 100644 tests/codegen/macos/x86_64-no-macosx-deployment-target.rs delete mode 100644 tests/codegen/mainsubprogram.rs delete mode 100644 tests/codegen/match-optimized.rs delete mode 100644 tests/codegen/match-optimizes-away.rs delete mode 100644 tests/codegen/match-unoptimized.rs delete mode 100644 tests/codegen/maybeuninit-rvo.rs delete mode 100644 tests/codegen/mem-replace-big-type.rs delete mode 100644 tests/codegen/mem-replace-simple-type.rs delete mode 100644 tests/codegen/merge-functions.rs delete mode 100644 tests/codegen/meta-filecheck/check-prefix.rs delete mode 100644 tests/codegen/meta-filecheck/filecheck-flags.rs delete mode 100644 tests/codegen/meta-filecheck/msvc-prefix-bad.rs delete mode 100644 tests/codegen/meta-filecheck/no-directives.rs delete mode 100644 tests/codegen/meta-filecheck/revision-prefix.rs delete mode 100644 tests/codegen/method-declaration.rs delete mode 100644 tests/codegen/min-function-alignment.rs delete mode 100644 tests/codegen/mir-aggregate-no-alloca.rs delete mode 100644 tests/codegen/mir-inlined-line-numbers.rs delete mode 100644 tests/codegen/mir_zst_stores.rs delete mode 100644 tests/codegen/move-before-nocapture-ref-arg.rs delete mode 100644 tests/codegen/move-operands.rs delete mode 100644 tests/codegen/naked-asan.rs delete mode 100644 tests/codegen/naked-fn/aligned.rs delete mode 100644 tests/codegen/naked-fn/generics.rs delete mode 100644 tests/codegen/naked-fn/instruction-set.rs delete mode 100644 tests/codegen/naked-fn/min-function-alignment.rs delete mode 100644 tests/codegen/naked-fn/naked-functions.rs delete mode 100644 tests/codegen/no-alloca-inside-if-false.rs delete mode 100644 tests/codegen/no-assumes-on-casts.rs delete mode 100644 tests/codegen/no-dllimport-w-cross-lang-lto.rs delete mode 100644 tests/codegen/no-jump-tables.rs delete mode 100644 tests/codegen/no-plt.rs delete mode 100644 tests/codegen/no-redundant-item-monomorphization.rs delete mode 100644 tests/codegen/no_builtins-at-crate.rs delete mode 100644 tests/codegen/noalias-box-off.rs delete mode 100644 tests/codegen/noalias-box.rs delete mode 100644 tests/codegen/noalias-flag.rs delete mode 100644 tests/codegen/noalias-freeze.rs delete mode 100644 tests/codegen/noalias-refcell.rs delete mode 100644 tests/codegen/noalias-rwlockreadguard.rs delete mode 100644 tests/codegen/noalias-unpin.rs delete mode 100644 tests/codegen/non-terminate/infinite-loop-1.rs delete mode 100644 tests/codegen/non-terminate/infinite-loop-2.rs delete mode 100644 tests/codegen/non-terminate/infinite-recursion.rs delete mode 100644 tests/codegen/non-terminate/nonempty-infinite-loop.rs delete mode 100644 tests/codegen/noreturn-uninhabited.rs delete mode 100644 tests/codegen/noreturnflag.rs delete mode 100644 tests/codegen/nounwind.rs delete mode 100644 tests/codegen/nrvo.rs delete mode 100644 tests/codegen/optimize-attr-1.rs delete mode 100644 tests/codegen/option-as-slice.rs delete mode 100644 tests/codegen/option-niche-eq.rs delete mode 100644 tests/codegen/option-niche-unfixed/option-nonzero-eq.rs delete mode 100644 tests/codegen/overaligned-constant.rs delete mode 100644 tests/codegen/packed.rs delete mode 100644 tests/codegen/panic-abort-windows.rs delete mode 100644 tests/codegen/panic-in-drop-abort.rs delete mode 100644 tests/codegen/panic-unwind-default-uwtable.rs delete mode 100644 tests/codegen/patchable-function-entry/patchable-function-entry-both-flags.rs delete mode 100644 tests/codegen/patchable-function-entry/patchable-function-entry-no-flag.rs delete mode 100644 tests/codegen/patchable-function-entry/patchable-function-entry-one-flag.rs delete mode 100644 tests/codegen/pattern_type_symbols.rs delete mode 100644 tests/codegen/personality_lifetimes.rs delete mode 100644 tests/codegen/pgo-counter-bias.rs delete mode 100644 tests/codegen/pgo-instrumentation.rs delete mode 100644 tests/codegen/pic-relocation-model.rs delete mode 100644 tests/codegen/pie-relocation-model.rs delete mode 100644 tests/codegen/placement-new.rs delete mode 100644 tests/codegen/powerpc64le-struct-align-128.rs delete mode 100644 tests/codegen/precondition-checks.rs delete mode 100644 tests/codegen/ptr-arithmetic.rs delete mode 100644 tests/codegen/ptr-read-metadata.rs delete mode 100644 tests/codegen/range-attribute.rs delete mode 100644 tests/codegen/range-loop.rs delete mode 100644 tests/codegen/range_to_inclusive.rs delete mode 100644 tests/codegen/refs.rs delete mode 100644 tests/codegen/reg-struct-return.rs delete mode 100644 tests/codegen/regparm-inreg.rs delete mode 100644 tests/codegen/remap_path_prefix/aux_mod.rs delete mode 100644 tests/codegen/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs delete mode 100644 tests/codegen/remap_path_prefix/auxiliary/xcrate-generic.rs delete mode 100644 tests/codegen/remap_path_prefix/issue-73167-remap-std.rs delete mode 100644 tests/codegen/remap_path_prefix/main.rs delete mode 100644 tests/codegen/remap_path_prefix/xcrate-generic.rs delete mode 100644 tests/codegen/repeat-operand-zero-len.rs delete mode 100644 tests/codegen/repeat-operand-zst-elem.rs delete mode 100644 tests/codegen/repeat-trusted-len.rs delete mode 100644 tests/codegen/repr/transparent-byval-struct-ptr.rs delete mode 100644 tests/codegen/repr/transparent-imm-array.rs delete mode 100644 tests/codegen/repr/transparent-mips64.rs delete mode 100644 tests/codegen/repr/transparent-opaque-ptr.rs delete mode 100644 tests/codegen/repr/transparent-sparc64.rs delete mode 100644 tests/codegen/repr/transparent-sysv64.rs delete mode 100644 tests/codegen/repr/transparent.rs delete mode 100644 tests/codegen/retpoline.rs delete mode 100644 tests/codegen/riscv-abi/call-llvm-intrinsics.rs delete mode 100644 tests/codegen/riscv-abi/cast-local-large-enough.rs delete mode 100644 tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs delete mode 100644 tests/codegen/riscv-abi/riscv64-lp64d-abi.rs delete mode 100644 tests/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs delete mode 100644 tests/codegen/riscv-target-abi.rs delete mode 100644 tests/codegen/rust-abi-arch-specific-adjustment.rs delete mode 100644 tests/codegen/s390x-simd.rs delete mode 100644 tests/codegen/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs delete mode 100644 tests/codegen/sanitizer/address-sanitizer-globals-tracking.rs delete mode 100644 tests/codegen/sanitizer/cfi/add-canonical-jump-tables-flag.rs delete mode 100644 tests/codegen/sanitizer/cfi/add-cfi-normalize-integers-flag.rs delete mode 100644 tests/codegen/sanitizer/cfi/add-enable-split-lto-unit-flag.rs delete mode 100644 tests/codegen/sanitizer/cfi/dbg-location-on-cfi-blocks.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-checks.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs delete mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-trait-objects.rs delete mode 100644 tests/codegen/sanitizer/cfi/external_weak_symbols.rs delete mode 100644 tests/codegen/sanitizer/cfi/generalize-pointers.rs delete mode 100644 tests/codegen/sanitizer/cfi/normalize-integers.rs delete mode 100644 tests/codegen/sanitizer/dataflow-instrument-functions.rs delete mode 100644 tests/codegen/sanitizer/kasan-emits-instrumentation.rs delete mode 100644 tests/codegen/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs delete mode 100644 tests/codegen/sanitizer/kcfi/add-kcfi-arity-flag.rs delete mode 100644 tests/codegen/sanitizer/kcfi/add-kcfi-flag.rs delete mode 100644 tests/codegen/sanitizer/kcfi/add-kcfi-offset-flag.rs delete mode 100644 tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs delete mode 100644 tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs delete mode 100644 tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs delete mode 100644 tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs delete mode 100644 tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs delete mode 100644 tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle.rs delete mode 100644 tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs delete mode 100644 tests/codegen/sanitizer/kcfi/naked-function.rs delete mode 100644 tests/codegen/sanitizer/memory-track-origins.rs delete mode 100644 tests/codegen/sanitizer/memtag-attr-check.rs delete mode 100644 tests/codegen/sanitizer/no-sanitize-inlining.rs delete mode 100644 tests/codegen/sanitizer/no-sanitize.rs delete mode 100644 tests/codegen/sanitizer/riscv64-shadow-call-stack.rs delete mode 100644 tests/codegen/sanitizer/safestack-attr-check.rs delete mode 100644 tests/codegen/sanitizer/sanitizer-recover.rs delete mode 100644 tests/codegen/sanitizer/scs-attr-check.rs delete mode 100644 tests/codegen/scalar-pair-bool.rs delete mode 100644 tests/codegen/set-discriminant-invalid.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs delete mode 100644 tests/codegen/simd/aggregate-simd.rs delete mode 100644 tests/codegen/simd/extract-insert-dyn.rs delete mode 100644 tests/codegen/simd/packed-simd-alignment.rs delete mode 100644 tests/codegen/simd/packed-simd.rs delete mode 100644 tests/codegen/simd/simd-wide-sum.rs delete mode 100644 tests/codegen/simd/simd_arith_offset.rs delete mode 100644 tests/codegen/simd/swap-simd-types.rs delete mode 100644 tests/codegen/simd/unpadded-simd.rs delete mode 100644 tests/codegen/skip-mono-inside-if-false.rs delete mode 100644 tests/codegen/slice-as_chunks.rs delete mode 100644 tests/codegen/slice-indexing.rs delete mode 100644 tests/codegen/slice-init.rs delete mode 100644 tests/codegen/slice-is-ascii.rs delete mode 100644 tests/codegen/slice-iter-fold.rs delete mode 100644 tests/codegen/slice-iter-len-eq-zero.rs delete mode 100644 tests/codegen/slice-iter-nonnull.rs delete mode 100644 tests/codegen/slice-last-elements-optimization.rs delete mode 100644 tests/codegen/slice-pointer-nonnull-unwrap.rs delete mode 100644 tests/codegen/slice-position-bounds-check.rs delete mode 100644 tests/codegen/slice-ref-equality.rs delete mode 100644 tests/codegen/slice-reverse.rs delete mode 100644 tests/codegen/slice-split-at.rs delete mode 100644 tests/codegen/slice-windows-no-bounds-check.rs delete mode 100644 tests/codegen/slice_as_from_ptr_range.rs delete mode 100644 tests/codegen/some-abis-do-extend-params-to-32-bits.rs delete mode 100644 tests/codegen/some-global-nonnull.rs delete mode 100644 tests/codegen/sparc-struct-abi.rs delete mode 100644 tests/codegen/split-lto-unit.rs delete mode 100644 tests/codegen/src-hash-algorithm/src-hash-algorithm-md5.rs delete mode 100644 tests/codegen/src-hash-algorithm/src-hash-algorithm-sha1.rs delete mode 100644 tests/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs delete mode 100644 tests/codegen/sroa-fragment-debuginfo.rs delete mode 100644 tests/codegen/sse42-implies-crc32.rs delete mode 100644 tests/codegen/stack-probes-inline.rs delete mode 100644 tests/codegen/stack-protector.rs delete mode 100644 tests/codegen/static-relocation-model-msvc.rs delete mode 100644 tests/codegen/staticlib-external-inline-fns.rs delete mode 100644 tests/codegen/step_by-overflow-checks.rs delete mode 100644 tests/codegen/stores.rs delete mode 100644 tests/codegen/string-push.rs delete mode 100644 tests/codegen/swap-large-types.rs delete mode 100644 tests/codegen/swap-small-types.rs delete mode 100644 tests/codegen/target-cpu-on-functions.rs delete mode 100644 tests/codegen/target-feature-inline-closure.rs delete mode 100644 tests/codegen/target-feature-negative-implication.rs delete mode 100644 tests/codegen/target-feature-overrides.rs delete mode 100644 tests/codegen/terminating-catchpad.rs delete mode 100644 tests/codegen/thread-local.rs delete mode 100644 tests/codegen/tied-features-strength.rs delete mode 100644 tests/codegen/to_vec.rs delete mode 100644 tests/codegen/trailing_zeros.rs delete mode 100644 tests/codegen/transmute-optimized.rs delete mode 100644 tests/codegen/transmute-scalar.rs delete mode 100644 tests/codegen/try_question_mark_nop.rs delete mode 100644 tests/codegen/tune-cpu-on-functions.rs delete mode 100644 tests/codegen/tuple-layout-opt.rs delete mode 100644 tests/codegen/ub-checks.rs delete mode 100644 tests/codegen/unchecked-float-casts.rs delete mode 100644 tests/codegen/unchecked_shifts.rs delete mode 100644 tests/codegen/uninhabited-transparent-return-abi.rs delete mode 100644 tests/codegen/uninit-consts.rs delete mode 100644 tests/codegen/uninit-repeat-in-aggregate.rs delete mode 100644 tests/codegen/union-abi.rs delete mode 100644 tests/codegen/union-aggregate.rs delete mode 100644 tests/codegen/unwind-abis/aapcs-unwind-abi.rs delete mode 100644 tests/codegen/unwind-abis/c-unwind-abi-panic-abort.rs delete mode 100644 tests/codegen/unwind-abis/c-unwind-abi.rs delete mode 100644 tests/codegen/unwind-abis/cdecl-unwind-abi.rs delete mode 100644 tests/codegen/unwind-abis/fastcall-unwind-abi.rs delete mode 100644 tests/codegen/unwind-abis/nounwind-on-stable-panic-abort.rs delete mode 100644 tests/codegen/unwind-abis/nounwind.rs delete mode 100644 tests/codegen/unwind-abis/stdcall-unwind-abi.rs delete mode 100644 tests/codegen/unwind-abis/system-unwind-abi.rs delete mode 100644 tests/codegen/unwind-abis/sysv64-unwind-abi.rs delete mode 100644 tests/codegen/unwind-abis/thiscall-unwind-abi.rs delete mode 100644 tests/codegen/unwind-abis/vectorcall-unwind-abi.rs delete mode 100644 tests/codegen/unwind-abis/win64-unwind-abi.rs delete mode 100644 tests/codegen/unwind-and-panic-abort.rs delete mode 100644 tests/codegen/unwind-extern-exports.rs delete mode 100644 tests/codegen/unwind-extern-imports.rs delete mode 100644 tests/codegen/unwind-landingpad-cold.rs delete mode 100644 tests/codegen/unwind-landingpad-inline.rs delete mode 100644 tests/codegen/used_with_arg.rs delete mode 100644 tests/codegen/var-names.rs delete mode 100644 tests/codegen/vec-as-ptr.rs delete mode 100644 tests/codegen/vec-calloc.rs delete mode 100644 tests/codegen/vec-in-place.rs delete mode 100644 tests/codegen/vec-iter-collect-len.rs delete mode 100644 tests/codegen/vec-iter.rs delete mode 100644 tests/codegen/vec-len-invariant.rs delete mode 100644 tests/codegen/vec-optimizes-away.rs delete mode 100644 tests/codegen/vec-reserve-extend.rs delete mode 100644 tests/codegen/vec-shrink-panik.rs delete mode 100644 tests/codegen/vec-with-capacity.rs delete mode 100644 tests/codegen/vec_pop_push_noop.rs delete mode 100644 tests/codegen/vecdeque-drain.rs delete mode 100644 tests/codegen/vecdeque-nonempty-get-no-panic.rs delete mode 100644 tests/codegen/vecdeque_no_panic.rs delete mode 100644 tests/codegen/vecdeque_pop_push.rs delete mode 100644 tests/codegen/virtual-call-attrs-issue-137646.rs delete mode 100644 tests/codegen/virtual-function-elimination-32bit.rs delete mode 100644 tests/codegen/virtual-function-elimination.rs delete mode 100644 tests/codegen/vtable-loads.rs delete mode 100644 tests/codegen/vtable-upcast.rs delete mode 100644 tests/codegen/wasm_casts_trapping.rs delete mode 100644 tests/codegen/wasm_exceptions.rs delete mode 100644 tests/codegen/zip.rs delete mode 100644 tests/codegen/zst-offset.rs (limited to 'tests/codegen') diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index e872f8434e5..610e2fd2311 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -869,7 +869,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ltext = bx.zext(is_lt, bx.type_i8()); bx.unchecked_ssub(gtext, ltext) } else { - // These operations are those expected by `tests/codegen/integer-cmp.rs`, + // These operations are those expected by `tests/codegen-llvm/integer-cmp.rs`, // from . let is_lt = bx.icmp(pred(mir::BinOp::Lt), lhs, rhs); let is_ne = bx.icmp(pred(mir::BinOp::Ne), lhs, rhs); diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs index 13fb5b3e56f..c417a9272f2 100644 --- a/compiler/rustc_mir_transform/src/unreachable_prop.rs +++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs @@ -75,7 +75,7 @@ fn remove_successors_from_switch<'tcx>( let is_unreachable = |bb| unreachable_blocks.contains(&bb); // If there are multiple targets, we want to keep information about reachability for codegen. - // For example (see tests/codegen/match-optimizes-away.rs) + // For example (see tests/codegen-llvm/match-optimizes-away.rs) // // pub enum Two { A, B } // pub fn identity(x: Two) -> Two { diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs index 44fcef4ed7d..321621d18be 100644 --- a/library/alloc/src/collections/vec_deque/drain.rs +++ b/library/alloc/src/collections/vec_deque/drain.rs @@ -192,7 +192,7 @@ impl Drop for Drain<'_, T, A> { // this branch is never taken. // We use `#[cold]` instead of `#[inline(never)]`, because inlining this // function into the general case (`.drain(n..m)`) is fine. - // See `tests/codegen/vecdeque-drain.rs` for a test. + // See `tests/codegen-llvm/vecdeque-drain.rs` for a test. #[cold] fn join_head_and_tail_wrapping( source_deque: &mut VecDeque, diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index 3e006a2d1bd..40716755aad 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -761,7 +761,7 @@ impl RawVecInner { } // not marked inline(never) since we want optimizers to be able to observe the specifics of this -// function, see tests/codegen/vec-reserve-extend.rs. +// function, see tests/codegen-llvm/vec-reserve-extend.rs. #[cold] fn finish_grow( new_layout: Layout, diff --git a/rustfmt.toml b/rustfmt.toml index 689e390b990..6172a2bb3bf 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -14,7 +14,7 @@ ignore = [ "/vendor/", # Some tests are not formatted, for various reasons. - "/tests/codegen/simd-intrinsic/", # Many types like `u8x64` are better hand-formatted. + "/tests/codegen-llvm/simd-intrinsic/", # Many types like `u8x64` are better hand-formatted. "/tests/crashes/", # Many of these tests contain syntax errors. "/tests/debuginfo/", # These tests are somewhat sensitive to source code layout. "/tests/incremental/", # These tests are somewhat sensitive to source code layout. @@ -58,5 +58,5 @@ ignore = [ # Rustfmt doesn't support use closures yet "tests/mir-opt/ergonomic-clones/closure.rs", - "tests/codegen/ergonomic-clones/closure.rs", + "tests/codegen-llvm/ergonomic-clones/closure.rs", ] diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 99c9e8ae92e..d346062761c 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1342,7 +1342,12 @@ test!(Ui { path: "tests/ui", mode: "ui", suite: "ui", default: true }); test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes", default: true }); -test!(Codegen { path: "tests/codegen", mode: "codegen", suite: "codegen", default: true }); +test!(CodegenLlvm { + path: "tests/codegen-llvm", + mode: "codegen", + suite: "codegen-llvm", + default: true +}); test!(CodegenUnits { path: "tests/codegen-units", @@ -1620,7 +1625,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let suite_path = self.path; // Skip codegen tests if they aren't enabled in configuration. - if !builder.config.codegen_tests && suite == "codegen" { + if !builder.config.codegen_tests && mode == "codegen" { return; } @@ -1817,7 +1822,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] }; flags.push(format!( "-Cdebuginfo={}", - if suite == "codegen" { + if mode == "codegen" { // codegen tests typically check LLVM IR and are sensitive to additional debuginfo. // So do not apply `rust.debuginfo-level-tests` for codegen tests. if builder.config.rust_debuginfo_level_tests diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 925e47a4164..923c3a9a935 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -412,7 +412,7 @@ const PATH_REMAP: &[(&str, &[&str])] = &[ &[ // tidy-alphabetical-start "tests/assembly-llvm", - "tests/codegen", + "tests/codegen-llvm", "tests/codegen-units", "tests/coverage", "tests/coverage-run-rustdoc", @@ -1049,7 +1049,7 @@ impl<'a> Builder<'a> { test::Crashes, test::Coverage, test::MirOpt, - test::Codegen, + test::CodegenLlvm, test::CodegenUnits, test::AssemblyLlvm, test::Incremental, diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile index 54ca7131608..4d09bea69c0 100644 --- a/src/ci/docker/host-x86_64/test-various/Dockerfile +++ b/src/ci/docker/host-x86_64/test-various/Dockerfile @@ -65,7 +65,7 @@ ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_T tests/ui \ tests/mir-opt \ tests/codegen-units \ - tests/codegen \ + tests/codegen-llvm \ tests/assembly-llvm \ library/core diff --git a/src/doc/rustc-dev-guide/src/asm.md b/src/doc/rustc-dev-guide/src/asm.md index 3d93d5a4c57..1bb493e73d5 100644 --- a/src/doc/rustc-dev-guide/src/asm.md +++ b/src/doc/rustc-dev-guide/src/asm.md @@ -157,7 +157,7 @@ Various tests for inline assembly are available: - `tests/assembly-llvm/asm` - `tests/ui/asm` -- `tests/codegen/asm-*` +- `tests/codegen-llvm/asm-*` Every architecture supported by inline assembly must have exhaustive tests in `tests/assembly-llvm/asm` which test all combinations of register classes and types. diff --git a/src/doc/rustc-dev-guide/src/autodiff/installation.md b/src/doc/rustc-dev-guide/src/autodiff/installation.md index a550f6d233e..ddbb3a05424 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/installation.md +++ b/src/doc/rustc-dev-guide/src/autodiff/installation.md @@ -25,7 +25,7 @@ rustup toolchain install nightly # enables -Z unstable-options You can then run our test cases: ```bash -./x test --stage 1 tests/codegen/autodiff +./x test --stage 1 tests/codegen-llvm/autodiff ./x test --stage 1 tests/pretty/autodiff ./x test --stage 1 tests/ui/autodiff ./x test --stage 1 tests/ui/feature-gates/feature-gate-autodiff.rs diff --git a/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md b/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md index 28e0e7a908d..880363b94bf 100644 --- a/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md +++ b/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md @@ -117,7 +117,7 @@ human-readable coverage report. > directive, so they will be skipped if the profiler runtime has not been > [enabled in `bootstrap.toml`](#recommended-configtoml-settings). -Finally, the [`tests/codegen/instrument-coverage/testprog.rs`] test compiles a simple Rust program +Finally, the [`tests/codegen-llvm/instrument-coverage/testprog.rs`] test compiles a simple Rust program with `-C instrument-coverage` and compares the compiled program's LLVM IR to expected LLVM IR instructions and structured data for a coverage-enabled program, including various checks for Coverage Map-related metadata and the LLVM @@ -136,4 +136,4 @@ and `mir-opt` tests can be refreshed by running: [`tests/coverage`]: https://github.com/rust-lang/rust/tree/master/tests/coverage [`src/tools/coverage-dump`]: https://github.com/rust-lang/rust/tree/master/src/tools/coverage-dump [`tests/coverage-run-rustdoc`]: https://github.com/rust-lang/rust/tree/master/tests/coverage-run-rustdoc -[`tests/codegen/instrument-coverage/testprog.rs`]: https://github.com/rust-lang/rust/blob/master/tests/mir-opt/coverage/instrument_coverage.rs +[`tests/codegen-llvm/instrument-coverage/testprog.rs`]: https://github.com/rust-lang/rust/blob/master/tests/mir-opt/coverage/instrument_coverage.rs diff --git a/src/doc/rustc-dev-guide/src/offload/installation.md b/src/doc/rustc-dev-guide/src/offload/installation.md index 1962314c70a..1e792de3c8c 100644 --- a/src/doc/rustc-dev-guide/src/offload/installation.md +++ b/src/doc/rustc-dev-guide/src/offload/installation.md @@ -40,7 +40,7 @@ This gives you a working LLVM build. ## Testing run ``` -./x test --stage 1 tests/codegen/gpu_offload +./x test --stage 1 tests/codegen-llvm/gpu_offload ``` ## Usage diff --git a/src/doc/rustc-dev-guide/src/profile-guided-optimization.md b/src/doc/rustc-dev-guide/src/profile-guided-optimization.md index d279786ac45..2fa81021045 100644 --- a/src/doc/rustc-dev-guide/src/profile-guided-optimization.md +++ b/src/doc/rustc-dev-guide/src/profile-guided-optimization.md @@ -132,7 +132,7 @@ There is also a [codegen test][codegen-test] that checks that some expected instrumentation artifacts show up in LLVM IR. [rmake-tests]: https://github.com/rust-lang/rust/tree/master/tests/run-make -[codegen-test]: https://github.com/rust-lang/rust/blob/master/tests/codegen/pgo-instrumentation.rs +[codegen-test]: https://github.com/rust-lang/rust/blob/master/tests/codegen-llvm/pgo-instrumentation.rs ## Additional information diff --git a/src/doc/rustc-dev-guide/src/sanitizers.md b/src/doc/rustc-dev-guide/src/sanitizers.md index 664b4feac4f..29d9056c15d 100644 --- a/src/doc/rustc-dev-guide/src/sanitizers.md +++ b/src/doc/rustc-dev-guide/src/sanitizers.md @@ -76,7 +76,7 @@ implementation: ## Testing sanitizers Sanitizers are validated by code generation tests in -[`tests/codegen/sanitize*.rs`][test-cg] and end-to-end functional tests in +[`tests/codegen-llvm/sanitize*.rs`][test-cg] and end-to-end functional tests in [`tests/ui/sanitizer/`][test-ui] directory. Testing sanitizer functionality requires the sanitizer runtimes (built when @@ -85,7 +85,7 @@ sanitizer. When sanitizer is unsupported on given target, sanitizers tests will be ignored. This behaviour is controlled by compiletest `needs-sanitizer-*` directives. -[test-cg]: https://github.com/rust-lang/rust/tree/master/tests/codegen +[test-cg]: https://github.com/rust-lang/rust/tree/master/tests/codegen-llvm [test-ui]: https://github.com/rust-lang/rust/tree/master/tests/ui/sanitizer ## Enabling sanitizer on a new target diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index 6a60e7118d3..a108dfdef9b 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -68,7 +68,7 @@ The following test suites are available, with links for more information: | [`pretty`](#pretty-printer-tests) | Check pretty printing | | [`incremental`](#incremental-tests) | Check incremental compilation behavior | | [`debuginfo`](#debuginfo-tests) | Check debuginfo generation running debuggers | -| [`codegen`](#codegen-tests) | Check code generation | +| [`codegen-*`](#codegen-tests) | Check code generation | | [`codegen-units`](#codegen-units-tests) | Check codegen unit partitioning | | [`assembly`](#assembly-tests) | Check assembly output | | [`mir-opt`](#mir-opt-tests) | Check MIR generation and optimizations | @@ -290,7 +290,7 @@ For example, `./x test tests/debuginfo -- --debugger gdb` will only test GDB com ### Codegen tests -The tests in [`tests/codegen`] test LLVM code generation. They compile the test +The tests in [`tests/codegen-llvm`] test LLVM code generation. They compile the test with the `--emit=llvm-ir` flag to emit LLVM IR. They then run the LLVM [FileCheck] tool. The test is annotated with various `// CHECK` comments to check the generated code. See the [FileCheck] documentation for a tutorial and @@ -301,7 +301,7 @@ See also the [assembly tests](#assembly-tests) for a similar set of tests. If you need to work with `#![no_std]` cross-compiling tests, consult the [`minicore` test auxiliary](./minicore.md) chapter. -[`tests/codegen`]: https://github.com/rust-lang/rust/tree/master/tests/codegen +[`tests/codegen-llvm`]: https://github.com/rust-lang/rust/tree/master/tests/codegen-llvm [FileCheck]: https://llvm.org/docs/CommandGuide/FileCheck.html diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs index a70c257e52b..c9a21fc6fb2 100644 --- a/src/tools/opt-dist/src/tests.rs +++ b/src/tools/opt-dist/src/tests.rs @@ -101,7 +101,7 @@ llvm-config = "{llvm_config}" "--stage", "0", "tests/assembly-llvm", - "tests/codegen", + "tests/codegen-llvm", "tests/codegen-units", "tests/incremental", "tests/mir-opt", diff --git a/tests/assembly-llvm/target-feature-multiple.rs b/tests/assembly-llvm/target-feature-multiple.rs index bc432d21931..9a941c52bda 100644 --- a/tests/assembly-llvm/target-feature-multiple.rs +++ b/tests/assembly-llvm/target-feature-multiple.rs @@ -15,7 +15,7 @@ // > LLVM ERROR: Cannot select: 0x7f00f400c010: i32,i32,ch = X86ISD::RDSEED 0x7f00f400bfa8:2 // > In function: foo // -// See also tests/codegen/target-feature-overrides.rs +// See also tests/codegen-llvm/target-feature-overrides.rs #![feature(no_core, lang_items, link_llvm_intrinsics, abi_unadjusted)] #![crate_type = "lib"] #![no_core] diff --git a/tests/codegen-llvm/README.md b/tests/codegen-llvm/README.md new file mode 100644 index 00000000000..8f2daaafcc7 --- /dev/null +++ b/tests/codegen-llvm/README.md @@ -0,0 +1,24 @@ +The files here use the LLVM FileCheck framework, documented at +. + +One extension worth noting is the use of revisions as custom prefixes for +FileCheck. If your codegen test has different behavior based on the chosen +target or different compiler flags that you want to exercise, you can use a +revisions annotation, like so: + +```rust +// revisions: aaa bbb +// [bbb] compile-flags: --flags-for-bbb +``` + +After specifying those variations, you can write different expected, or +explicitly *unexpected* output by using `-SAME:` and `-NOT:`, +like so: + +```rust +// CHECK: expected code +// aaa-SAME: emitted-only-for-aaa +// aaa-NOT: emitted-only-for-bbb +// bbb-NOT: emitted-only-for-aaa +// bbb-SAME: emitted-only-for-bbb +``` diff --git a/tests/codegen-llvm/aarch64-softfloat.rs b/tests/codegen-llvm/aarch64-softfloat.rs new file mode 100644 index 00000000000..4f5366e047f --- /dev/null +++ b/tests/codegen-llvm/aarch64-softfloat.rs @@ -0,0 +1,45 @@ +//@ add-core-stubs +//@ compile-flags: --target aarch64-unknown-none-softfloat -Zmerge-functions=disabled +//@ needs-llvm-components: aarch64 +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK: i64 @pass_f64_C(i64 {{[^,]*}}) +#[no_mangle] +extern "C" fn pass_f64_C(x: f64) -> f64 { + x +} + +// CHECK: i64 @pass_f32_pair_C(i64 {{[^,]*}}) +#[no_mangle] +extern "C" fn pass_f32_pair_C(x: (f32, f32)) -> (f32, f32) { + x +} + +// CHECK: [2 x i64] @pass_f64_pair_C([2 x i64] {{[^,]*}}) +#[no_mangle] +extern "C" fn pass_f64_pair_C(x: (f64, f64)) -> (f64, f64) { + x +} + +// CHECK: i64 @pass_f64_Rust(i64 {{[^,]*}}) +#[no_mangle] +fn pass_f64_Rust(x: f64) -> f64 { + x +} + +// CHECK: i64 @pass_f32_pair_Rust(i64 {{[^,]*}}) +#[no_mangle] +fn pass_f32_pair_Rust(x: (f32, f32)) -> (f32, f32) { + x +} + +// CHECK: void @pass_f64_pair_Rust(ptr {{.*}}%{{[^ ]+}}, ptr {{.*}}%{{[^ ]+}}) +#[no_mangle] +fn pass_f64_pair_Rust(x: (f64, f64)) -> (f64, f64) { + x +} diff --git a/tests/codegen-llvm/aarch64-struct-align-128.rs b/tests/codegen-llvm/aarch64-struct-align-128.rs new file mode 100644 index 00000000000..ba1d19680f4 --- /dev/null +++ b/tests/codegen-llvm/aarch64-struct-align-128.rs @@ -0,0 +1,145 @@ +// Test that structs aligned to 128 bits are passed with the correct ABI on aarch64. + +//@ add-core-stubs +//@ revisions: linux darwin win +//@[linux] compile-flags: --target aarch64-unknown-linux-gnu +//@[darwin] compile-flags: --target aarch64-apple-darwin +//@[win] compile-flags: --target aarch64-pc-windows-msvc +//@[linux] needs-llvm-components: aarch64 +//@[darwin] needs-llvm-components: aarch64 +//@[win] needs-llvm-components: aarch64 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +// Passed as `[i64 x 2]`, since it's an aggregate with size <= 128 bits, align < 128 bits. +#[repr(C)] +pub struct Align8 { + pub a: u64, + pub b: u64, +} + +// repr(transparent), so same as above. +#[repr(transparent)] +pub struct Transparent8 { + a: Align8, +} + +// Passed as `[i64 x 2]`, since it's an aggregate with size <= 128 bits, align < 128 bits. +#[repr(C)] +pub struct Wrapped8 { + a: Align8, +} + +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); +} + +// 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]`. +#[repr(C)] +#[repr(align(16))] +pub struct Align16 { + pub a: u64, + pub b: u64, +} + +// repr(transparent), so same as above. +#[repr(transparent)] +pub struct Transparent16 { + a: Align16, +} + +// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits. +// On Linux, the "unadjustedness" doesn't recurse into fields, so this is passed as `i128`. +#[repr(C)] +pub struct Wrapped16 { + pub a: Align16, +} + +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); +} + +// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits. +#[repr(C)] +pub struct I128 { + pub a: i128, +} + +// repr(transparent), so same as above. +#[repr(transparent)] +pub struct TransparentI128 { + a: I128, +} + +// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits. +#[repr(C)] +pub struct WrappedI128 { + pub a: I128, +} + +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); +} + +// 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)] +#[repr(packed)] +pub struct Packed { + pub a: i128, +} + +// repr(transparent), so same as above. +#[repr(transparent)] +pub struct TransparentPacked { + a: Packed, +} + +// Passed as `[2 x i64]`, since it's an aggregate with size <= 128 bits, align < 128 bits. +#[repr(C)] +pub struct WrappedPacked { + pub a: Packed, +} + +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); +} + +pub unsafe fn main( + a1: Align8, + a2: Transparent8, + a3: Wrapped8, + b1: Align16, + b2: Transparent16, + b3: Wrapped16, + c1: I128, + c2: TransparentI128, + c3: WrappedI128, + d1: Packed, + d2: TransparentPacked, + d3: WrappedPacked, +) { + test_8(a1, a2, a3); + test_16(b1, b2, b3); + test_i128(c1, c2, c3); + test_packed(d1, d2, d3); +} diff --git a/tests/codegen-llvm/abi-efiapi.rs b/tests/codegen-llvm/abi-efiapi.rs new file mode 100644 index 00000000000..1736f0daf0f --- /dev/null +++ b/tests/codegen-llvm/abi-efiapi.rs @@ -0,0 +1,30 @@ +// Checks if the correct annotation for the efiapi ABI is passed to llvm. + +//@ add-core-stubs +//@ revisions:x86_64 i686 aarch64 arm riscv +//@[x86_64] compile-flags: --target x86_64-unknown-uefi +//@[x86_64] needs-llvm-components: aarch64 arm riscv +//@[i686] compile-flags: --target i686-unknown-linux-musl +//@[i686] needs-llvm-components: aarch64 arm riscv +//@[aarch64] compile-flags: --target aarch64-unknown-none +//@[aarch64] needs-llvm-components: aarch64 arm riscv +//@[arm] compile-flags: --target armv7r-none-eabi +//@[arm] needs-llvm-components: aarch64 arm riscv +//@[riscv] compile-flags: --target riscv64gc-unknown-none-elf +//@[riscv] needs-llvm-components: aarch64 arm riscv +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +//x86_64: define win64cc void @has_efiapi +//i686: define void @has_efiapi +//aarch64: define dso_local void @has_efiapi +//arm: define dso_local arm_aapcscc void @has_efiapi +//riscv: define dso_local void @has_efiapi +#[no_mangle] +pub extern "efiapi" fn has_efiapi() {} diff --git a/tests/codegen-llvm/abi-main-signature-16bit-c-int.rs b/tests/codegen-llvm/abi-main-signature-16bit-c-int.rs new file mode 100644 index 00000000000..d44b80475e4 --- /dev/null +++ b/tests/codegen-llvm/abi-main-signature-16bit-c-int.rs @@ -0,0 +1,11 @@ +// Checks the signature of the implicitly generated native main() +// entry point. It must match C's `int main(int, char **)`. + +// This test is for targets with 16bit c_int only. +//@ revisions: avr msp +//@[avr] only-avr +//@[msp] only-msp430 + +fn main() {} + +// CHECK: define i16 @main(i16, i8**) diff --git a/tests/codegen-llvm/abi-main-signature-32bit-c-int.rs b/tests/codegen-llvm/abi-main-signature-32bit-c-int.rs new file mode 100644 index 00000000000..ce475adde44 --- /dev/null +++ b/tests/codegen-llvm/abi-main-signature-32bit-c-int.rs @@ -0,0 +1,11 @@ +// Checks the signature of the implicitly generated native main() +// entry point. It must match C's `int main(int, char **)`. + +// This test is for targets with 32bit c_int only. +//@ ignore-msp430 +//@ ignore-avr +//@ ignore-wasi wasi codegens the main symbol differently + +fn main() {} + +// CHECK: define{{( hidden| noundef)*}} i32 @main(i32{{( %0)?}}, ptr{{( %1)?}}) diff --git a/tests/codegen-llvm/abi-repr-ext.rs b/tests/codegen-llvm/abi-repr-ext.rs new file mode 100644 index 00000000000..1da28a94d9d --- /dev/null +++ b/tests/codegen-llvm/abi-repr-ext.rs @@ -0,0 +1,56 @@ +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 + +//@ revisions:x86_64 i686 aarch64-apple aarch64-windows aarch64-linux arm riscv + +//@[x86_64] compile-flags: --target x86_64-unknown-uefi +//@[x86_64] needs-llvm-components: x86 +//@[i686] compile-flags: --target i686-unknown-linux-musl +//@[i686] needs-llvm-components: x86 +//@[aarch64-windows] compile-flags: --target aarch64-pc-windows-msvc +//@[aarch64-windows] needs-llvm-components: aarch64 +//@[aarch64-linux] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64-linux] needs-llvm-components: aarch64 +//@[aarch64-apple] compile-flags: --target aarch64-apple-darwin +//@[aarch64-apple] needs-llvm-components: aarch64 +//@[arm] compile-flags: --target armv7r-none-eabi +//@[arm] needs-llvm-components: arm +//@[riscv] compile-flags: --target riscv64gc-unknown-none-elf +//@[riscv] needs-llvm-components: riscv + +// See bottom of file for a corresponding C source file that is meant to yield +// equivalent declarations. +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(i8)] +pub enum Type { + Type1 = 0, + Type2 = 1, +} + +// To accommodate rust#97800, one might consider writing the below as: +// +// `define{{( dso_local)?}} noundef{{( signext)?}} i8 @test()` +// +// but based on rust#80556, it seems important to actually check for the +// presence of the `signext` for those targets where we expect it. + +// CHECK: define{{( dso_local)?}} noundef +// x86_64-SAME: signext +// aarch64-apple-SAME: signext +// aarch64-windows-NOT: signext +// aarch64-linux-NOT: signext +// arm-SAME: signext +// riscv-SAME: signext +// CHECK-SAME: i8 @test() + +#[no_mangle] +pub extern "C" fn test() -> Type { + Type::Type1 +} diff --git a/tests/codegen-llvm/abi-sysv64.rs b/tests/codegen-llvm/abi-sysv64.rs new file mode 100644 index 00000000000..7ade17f2bae --- /dev/null +++ b/tests/codegen-llvm/abi-sysv64.rs @@ -0,0 +1,20 @@ +// Checks if the correct annotation for the sysv64 ABI is passed to +// llvm. Also checks that the abi-sysv64 feature gate allows usage +// of the sysv64 abi. +// +//@ add-core-stubs +//@ needs-llvm-components: x86 +//@ compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu -Copt-level=0 + +#![crate_type = "lib"] +#![no_core] +#![feature(abi_x86_interrupt, no_core, lang_items)] + +extern crate minicore; +use minicore::*; + +// CHECK: define x86_64_sysvcc i64 @has_sysv64_abi +#[no_mangle] +pub extern "sysv64" fn has_sysv64_abi(a: i64) -> i64 { + a +} diff --git a/tests/codegen-llvm/abi-win64-zst.rs b/tests/codegen-llvm/abi-win64-zst.rs new file mode 100644 index 00000000000..e46f9666d42 --- /dev/null +++ b/tests/codegen-llvm/abi-win64-zst.rs @@ -0,0 +1,54 @@ +//@ add-core-stubs +//@ compile-flags: -Z merge-functions=disabled +//@ add-core-stubs + +//@ revisions: windows-gnu +//@[windows-gnu] compile-flags: --target x86_64-pc-windows-gnu +//@[windows-gnu] needs-llvm-components: x86 + +//@ revisions: windows-msvc +//@[windows-msvc] compile-flags: --target x86_64-pc-windows-msvc +//@[windows-msvc] needs-llvm-components: x86 + +// Also test what happens when using a Windows ABI on Linux. +//@ revisions: linux +//@[linux] compile-flags: --target x86_64-unknown-linux-gnu +//@[linux] needs-llvm-components: x86 + +#![feature(no_core, rustc_attrs, abi_vectorcall)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +// Make sure the argument is always passed when explicitly requesting a Windows ABI. +// Our goal here is to match clang: . + +// CHECK: define win64cc void @pass_zst_win64(ptr {{[^,]*}}) +#[no_mangle] +extern "win64" fn pass_zst_win64(_: ()) {} + +// CHECK: define x86_vectorcallcc void @pass_zst_vectorcall(ptr {{[^,]*}}) +#[no_mangle] +extern "vectorcall" fn pass_zst_vectorcall(_: ()) {} + +// windows-gnu: define void @pass_zst_fastcall(ptr {{[^,]*}}) +// windows-msvc: define void @pass_zst_fastcall(ptr {{[^,]*}}) +#[no_mangle] +#[cfg(windows)] // "fastcall" is not valid on 64bit Linux +extern "fastcall" fn pass_zst_fastcall(_: ()) {} + +// The sysv64 ABI ignores ZST. + +// CHECK: define x86_64_sysvcc void @pass_zst_sysv64() +#[no_mangle] +extern "sysv64" fn pass_zst_sysv64(_: ()) {} + +// For `extern "C"` functions, ZST are ignored on Linux put passed on Windows. + +// linux: define void @pass_zst_c() +// windows-msvc: define void @pass_zst_c(ptr {{[^,]*}}) +// windows-gnu: define void @pass_zst_c(ptr {{[^,]*}}) +#[no_mangle] +extern "C" fn pass_zst_c(_: ()) {} diff --git a/tests/codegen-llvm/abi-x86-interrupt.rs b/tests/codegen-llvm/abi-x86-interrupt.rs new file mode 100644 index 00000000000..9a1ded2c9e3 --- /dev/null +++ b/tests/codegen-llvm/abi-x86-interrupt.rs @@ -0,0 +1,18 @@ +// Checks if the correct annotation for the x86-interrupt ABI is passed to +// llvm. Also checks that the abi_x86_interrupt feature gate allows usage +// of the x86-interrupt abi. + +//@ add-core-stubs +//@ needs-llvm-components: x86 +//@ compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu -Copt-level=0 + +#![crate_type = "lib"] +#![no_core] +#![feature(abi_x86_interrupt, no_core, lang_items)] + +extern crate minicore; +use minicore::*; + +// CHECK: define x86_intrcc void @has_x86_interrupt_abi +#[no_mangle] +pub extern "x86-interrupt" fn has_x86_interrupt_abi() {} diff --git a/tests/codegen-llvm/abi-x86-sse.rs b/tests/codegen-llvm/abi-x86-sse.rs new file mode 100644 index 00000000000..68d2acfb527 --- /dev/null +++ b/tests/codegen-llvm/abi-x86-sse.rs @@ -0,0 +1,43 @@ +//@ compile-flags: -Z merge-functions=disabled + +//@ revisions: x86-64 +//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86-64] needs-llvm-components: x86 + +//@ revisions: x86-32 +//@[x86-32] compile-flags: --target i686-unknown-linux-gnu +//@[x86-32] needs-llvm-components: x86 + +//@ revisions: x86-32-nosse +//@[x86-32-nosse] compile-flags: --target i586-unknown-linux-gnu +//@[x86-32-nosse] needs-llvm-components: x86 + +#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized: MetaSized {} + +#[lang = "meta_sized"] +trait MetaSized: PointeeSized {} + +#[lang = "pointee_sized"] +trait PointeeSized {} + +#[lang = "copy"] +trait Copy {} + +// Ensure this type is passed without ptr indirection on targets that +// require SSE2. +#[repr(simd)] +pub struct Sse([f32; 4]); + +// FIXME: due to #139029 we are passing them all indirectly. +// x86-64: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}}) +// x86-32: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}}) +// x86-32-nosse: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}}) +#[no_mangle] +pub fn sse_id(x: Sse) -> Sse { + x +} diff --git a/tests/codegen-llvm/abi-x86_64_sysv.rs b/tests/codegen-llvm/abi-x86_64_sysv.rs new file mode 100644 index 00000000000..09909f994d6 --- /dev/null +++ b/tests/codegen-llvm/abi-x86_64_sysv.rs @@ -0,0 +1,29 @@ +//@ only-x86_64 + +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +pub struct S24 { + a: i8, + b: i8, + c: i8, +} + +pub struct S48 { + a: i16, + b: i16, + c: i8, +} + +// CHECK: i24 @struct_24_bits(i24 +#[no_mangle] +pub extern "sysv64" fn struct_24_bits(a: S24) -> S24 { + a +} + +// CHECK: i48 @struct_48_bits(i48 +#[no_mangle] +pub extern "sysv64" fn struct_48_bits(a: S48) -> S48 { + a +} diff --git a/tests/codegen-llvm/addr-of-mutate.rs b/tests/codegen-llvm/addr-of-mutate.rs new file mode 100644 index 00000000000..14bc4b8ab28 --- /dev/null +++ b/tests/codegen-llvm/addr-of-mutate.rs @@ -0,0 +1,33 @@ +//@ compile-flags: -C opt-level=3 -C no-prepopulate-passes + +#![crate_type = "lib"] + +// Test for the absence of `readonly` on the argument when it is mutated via `&raw const`. +// See . + +// CHECK: i8 @foo(ptr noalias{{( nocapture)?}} noundef align 1{{( captures\(none\))?}} dereferenceable(128) %x) +#[no_mangle] +pub fn foo(x: [u8; 128]) -> u8 { + let ptr = core::ptr::addr_of!(x).cast_mut(); + unsafe { + (*ptr)[0] = 1; + } + x[0] +} + +// CHECK: i1 @second(ptr noalias{{( nocapture)?}} noundef align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) +#[no_mangle] +pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { + let b_bool_ptr = core::ptr::addr_of!(a_ptr_and_b.1.1).cast_mut(); + (*b_bool_ptr) = true; + a_ptr_and_b.1.1 +} + +// If going through a deref (and there are no other mutating accesses), then `readonly` is fine. +// CHECK: i1 @third(ptr noalias{{( nocapture)?}} noundef readonly align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) +#[no_mangle] +pub unsafe fn third(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { + let b_bool_ptr = core::ptr::addr_of!((*a_ptr_and_b.0).1).cast_mut(); + (*b_bool_ptr) = true; + a_ptr_and_b.1.1 +} diff --git a/tests/codegen-llvm/adjustments.rs b/tests/codegen-llvm/adjustments.rs new file mode 100644 index 00000000000..7f7831def08 --- /dev/null +++ b/tests/codegen-llvm/adjustments.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 + +#![crate_type = "lib"] + +// Hack to get the correct size for the length part in slices +// CHECK: @helper([[USIZE:i[0-9]+]] %_1) +#[no_mangle] +pub fn helper(_: usize) {} + +// CHECK-LABEL: @no_op_slice_adjustment +#[no_mangle] +pub fn no_op_slice_adjustment(x: &[u8]) -> &[u8] { + // We used to generate an extra alloca and memcpy for the block's trailing expression value, so + // check that we copy directly to the return value slot + // CHECK: %0 = insertvalue { ptr, [[USIZE]] } poison, ptr %x.0, 0 + // CHECK: %1 = insertvalue { ptr, [[USIZE]] } %0, [[USIZE]] %x.1, 1 + // CHECK: ret { ptr, [[USIZE]] } %1 + { x } +} + +// CHECK-LABEL: @no_op_slice_adjustment2 +#[no_mangle] +pub fn no_op_slice_adjustment2(x: &[u8]) -> &[u8] { + // We used to generate an extra alloca and memcpy for the function's return value, so check + // that there's no memcpy (the slice is written to sret_slot element-wise) + // CHECK-NOT: call void @llvm.memcpy. + no_op_slice_adjustment(x) +} diff --git a/tests/codegen-llvm/align-byval-alignment-mismatch.rs b/tests/codegen-llvm/align-byval-alignment-mismatch.rs new file mode 100644 index 00000000000..c69fc2de9d2 --- /dev/null +++ b/tests/codegen-llvm/align-byval-alignment-mismatch.rs @@ -0,0 +1,126 @@ +// ignore-tidy-linelength +//@ add-core-stubs +//@ revisions:i686-linux x86_64-linux + +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=1 -Cpanic=abort +//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu +//@[i686-linux] needs-llvm-components: x86 +//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64-linux] needs-llvm-components: x86 + +// Tests that we correctly copy arguments into allocas when the alignment of the byval argument +// is different from the alignment of the Rust type. + +// For the following test cases: +// All of the `*_decreases_alignment` functions should codegen to a direct call, since the +// alignment is already sufficient. +// All off the `*_increases_alignment` functions should copy the argument to an alloca +// on i686-unknown-linux-gnu, since the alignment needs to be increased, and should codegen +// to a direct call on x86_64-unknown-linux-gnu, where byval alignment matches Rust alignment. + +#![feature(no_core)] +#![crate_type = "lib"] +#![no_std] +#![no_core] +#![allow(non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +// This type has align 1 in Rust, but as a byval argument on i686-linux, it will have align 4. +#[repr(C)] +#[repr(packed)] +struct Align1 { + x: u128, + y: u128, + z: u128, +} + +// This type has align 16 in Rust, but as a byval argument on i686-linux, it will have align 4. +#[repr(C)] +#[repr(align(16))] +struct Align16 { + x: u128, + y: u128, + z: u128, +} + +extern "C" { + fn extern_c_align1(x: Align1); + fn extern_c_align16(x: Align16); +} + +// CHECK-LABEL: @rust_to_c_increases_alignment +#[no_mangle] +pub unsafe fn rust_to_c_increases_alignment(x: Align1) { + // i686-linux: start: + // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca [48 x i8], align 4 + // i686-linux-NEXT: call void @llvm.lifetime.start.p0(i64 48, ptr {{.*}}[[ALLOCA]]) + // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 4 {{.*}}[[ALLOCA]], ptr {{.*}}align 1 {{.*}}%x + // i686-linux-NEXT: call void @extern_c_align1({{.+}} [[ALLOCA]]) + // i686-linux-NEXT: call void @llvm.lifetime.end.p0(i64 48, ptr {{.*}}[[ALLOCA]]) + + // x86_64-linux: start: + // x86_64-linux-NEXT: call void @extern_c_align1 + extern_c_align1(x); +} + +// CHECK-LABEL: @rust_to_c_decreases_alignment +#[no_mangle] +pub unsafe fn rust_to_c_decreases_alignment(x: Align16) { + // CHECK: start: + // CHECK-NEXT: call void @extern_c_align16 + extern_c_align16(x); +} + +extern "Rust" { + fn extern_rust_align1(x: Align1); + fn extern_rust_align16(x: Align16); +} + +// CHECK-LABEL: @c_to_rust_decreases_alignment +#[no_mangle] +pub unsafe extern "C" fn c_to_rust_decreases_alignment(x: Align1) { + // CHECK: start: + // CHECK-NEXT: call void @extern_rust_align1 + extern_rust_align1(x); +} + +// CHECK-LABEL: @c_to_rust_increases_alignment +#[no_mangle] +pub unsafe extern "C" fn c_to_rust_increases_alignment(x: Align16) { + // i686-linux: start: + // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca [48 x i8], align 16 + // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 16 {{.*}}[[ALLOCA]], ptr {{.*}}align 4 {{.*}}%0 + // i686-linux-NEXT: call void @extern_rust_align16({{.+}} [[ALLOCA]]) + + // x86_64-linux: start: + // x86_64-linux-NEXT: call void @extern_rust_align16 + extern_rust_align16(x); +} + +extern "Rust" { + fn extern_rust_ref_align1(x: &Align1); + fn extern_rust_ref_align16(x: &Align16); +} + +// CHECK-LABEL: @c_to_rust_ref_decreases_alignment +#[no_mangle] +pub unsafe extern "C" fn c_to_rust_ref_decreases_alignment(x: Align1) { + // CHECK: start: + // CHECK-NEXT: call void @extern_rust_ref_align1 + extern_rust_ref_align1(&x); +} + +// CHECK-LABEL: @c_to_rust_ref_increases_alignment +#[no_mangle] +pub unsafe extern "C" fn c_to_rust_ref_increases_alignment(x: Align16) { + // i686-linux: start: + // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca [48 x i8], align 16 + // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 16 {{.*}}[[ALLOCA]], ptr {{.*}}align 4 {{.*}}%0 + // i686-linux-NEXT: call void @extern_rust_ref_align16({{.+}} [[ALLOCA]]) + + // x86_64-linux: start: + // x86_64-linux-NEXT: call void @extern_rust_ref_align16 + extern_rust_ref_align16(&x); +} diff --git a/tests/codegen-llvm/align-byval-vector.rs b/tests/codegen-llvm/align-byval-vector.rs new file mode 100644 index 00000000000..c33b41a7bbe --- /dev/null +++ b/tests/codegen-llvm/align-byval-vector.rs @@ -0,0 +1,55 @@ +//@ add-core-stubs +//@ revisions:x86-linux x86-darwin + +//@[x86-linux] compile-flags: --target i686-unknown-linux-gnu +//@[x86-linux] needs-llvm-components: x86 +//@[x86-darwin] compile-flags: --target i686-apple-darwin +//@[x86-darwin] needs-llvm-components: x86 + +// Tests that aggregates containing vector types get their alignment increased to 16 on Darwin. + +#![feature(no_core, repr_simd, simd_ffi)] +#![crate_type = "lib"] +#![no_std] +#![no_core] +#![allow(non_camel_case_types)] + +extern crate minicore; +use minicore::*; + +#[repr(simd)] +pub struct i32x4([i32; 4]); + +#[repr(C)] +pub struct Foo { + a: i32x4, + b: i8, +} + +// This tests that we recursively check for vector types, not just at the top level. +#[repr(C)] +pub struct DoubleFoo { + one: Foo, + two: Foo, +} + +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() { + unsafe { f(Foo { a: i32x4([1, 2, 3, 4]), b: 0 }) } + + unsafe { + g(DoubleFoo { + one: Foo { a: i32x4([1, 2, 3, 4]), b: 0 }, + two: Foo { a: i32x4([1, 2, 3, 4]), b: 0 }, + }) + } +} diff --git a/tests/codegen-llvm/align-byval.rs b/tests/codegen-llvm/align-byval.rs new file mode 100644 index 00000000000..75dabd74a79 --- /dev/null +++ b/tests/codegen-llvm/align-byval.rs @@ -0,0 +1,315 @@ +// ignore-tidy-linelength +//@ add-core-stubs +//@ revisions:m68k x86_64-linux x86_64-windows i686-linux i686-windows + +//@[m68k] compile-flags: --target m68k-unknown-linux-gnu +//@[m68k] needs-llvm-components: m68k +//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64-linux] needs-llvm-components: x86 +//@[x86_64-windows] compile-flags: --target x86_64-pc-windows-msvc +//@[x86_64-windows] needs-llvm-components: x86 +//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu +//@[i686-linux] needs-llvm-components: x86 +//@[i686-windows] compile-flags: --target i686-pc-windows-msvc +//@[i686-windows] needs-llvm-components: x86 + +// Tests that `byval` alignment is properly specified (#80127). +// The only targets that use `byval` are m68k, x86-64, and x86. +// Note also that Windows mandates a by-ref ABI here, so it does not use byval. + +#![feature(no_core)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +// This struct can be represented as a pair, so it exercises the OperandValue::Pair +// codepath in `codegen_argument`. +#[repr(C)] +pub struct NaturalAlign1 { + a: i8, + b: i8, +} + +// This struct cannot be represented as an immediate, so it exercises the OperandValue::Ref +// codepath in `codegen_argument`. +#[repr(C)] +pub struct NaturalAlign2 { + a: [i16; 16], + b: i16, +} + +#[repr(C)] +#[repr(align(4))] +pub struct ForceAlign4 { + a: [i8; 16], + b: i8, +} + +// On i686-windows, this is passed on stack using `byval` +#[repr(C)] +pub struct NaturalAlign8 { + a: i64, + b: i64, + c: i64, +} + +// On i686-windows, this is passed by reference (because alignment is >4 and requested/forced), +// even though it has the exact same layout as `NaturalAlign8`! +#[repr(C)] +#[repr(align(8))] +pub struct ForceAlign8 { + a: i64, + b: i64, + c: i64, +} + +// On i686-windows, this is passed on stack, because requested alignment is <=4. +#[repr(C)] +#[repr(align(4))] +pub struct LowerFA8 { + a: i64, + b: i64, + c: i64, +} + +// On i686-windows, this is passed by reference, because it contains a field with +// requested/forced alignment. +#[repr(C)] +pub struct WrappedFA8 { + a: ForceAlign8, +} + +// On i686-windows, this has the same ABI as ForceAlign8, i.e. passed by reference. +#[repr(transparent)] +pub struct TransparentFA8 { + _0: (), + a: ForceAlign8, +} + +#[repr(C)] +#[repr(align(16))] +pub struct ForceAlign16 { + a: [i32; 16], + b: i8, +} + +// CHECK-LABEL: @call_na1 +#[no_mangle] +pub unsafe fn call_na1(x: NaturalAlign1) { + // CHECK: start: + + // m68k: [[ALLOCA:%[a-z0-9+]]] = alloca [2 x i8], align 1 + // m68k: call void @natural_align_1({{.*}}byval([2 x i8]) align 1{{.*}} [[ALLOCA]]) + + // x86_64-linux: 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]]) + + // i686-windows: [[ALLOCA:%[a-z0-9+]]] = alloca [2 x i8], align 4 + // i686-windows: call void @natural_align_1({{.*}}byval([2 x i8]) align 4{{.*}} [[ALLOCA]]) + natural_align_1(x); +} + +// CHECK-LABEL: @call_na2 +#[no_mangle] +pub unsafe fn call_na2(x: NaturalAlign2) { + // CHECK: start: + + // m68k-NEXT: call void @natural_align_2 + // x86_64-linux-NEXT: call void @natural_align_2 + // x86_64-windows-NEXT: call void @natural_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]]) + + // i686-windows: [[ALLOCA:%[0-9]+]] = alloca [34 x i8], align 4 + // i686-windows: call void @natural_align_2({{.*}}byval([34 x i8]) align 4{{.*}} [[ALLOCA]]) + natural_align_2(x); +} + +// 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); +} + +// 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{{.*}}) + + // 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{{.*}}) + + // i686-windows: declare void @natural_align_1({{.*}}byval([2 x i8]) align 4{{.*}}) + fn natural_align_1(x: NaturalAlign1); + + // m68k: 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{{.*}}) + + // 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-NOT: byval + // x86_64-windows-SAME: align 4{{.*}}) + + // i686-linux: declare 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); + + // m68k: declare void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) + + // x86_64-linux: declare void @natural_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) + + // x86_64-windows: declare 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-windows: declare void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) + fn natural_align_8(x: NaturalAlign8); + + // m68k: declare 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-windows: declare 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-windows: declare void @force_align_8( + // i686-windows-NOT: byval + // i686-windows-SAME: align 8{{.*}}) + fn force_align_8(x: ForceAlign8); + + // m68k: declare void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) + + // x86_64-linux: declare void @lower_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) + + // x86_64-windows: declare 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-windows: declare void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) + fn lower_fa8(x: LowerFA8); + + // m68k: declare void @wrapped_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) + + // x86_64-linux: declare void @wrapped_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) + + // x86_64-windows: declare 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-windows: declare void @wrapped_fa8( + // i686-windows-NOT: byval + // i686-windows-SAME: align 8{{.*}}) + fn wrapped_fa8(x: WrappedFA8); + + // m68k: declare void @transparent_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) + + // x86_64-linux: declare void @transparent_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) + + // x86_64-windows: declare 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-windows: declare void @transparent_fa8( + // i686-windows-NOT: byval + // i686-windows-SAME: align 8{{.*}}) + fn transparent_fa8(x: TransparentFA8); + + // m68k: declare 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-windows: declare 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-windows: declare void @force_align_16( + // i686-windows-NOT: byval + // i686-windows-SAME: align 16{{.*}}) + fn force_align_16(x: ForceAlign16); +} diff --git a/tests/codegen-llvm/align-enum.rs b/tests/codegen-llvm/align-enum.rs new file mode 100644 index 00000000000..e8dd95d3afb --- /dev/null +++ b/tests/codegen-llvm/align-enum.rs @@ -0,0 +1,33 @@ +//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 +// + +#![crate_type = "lib"] + +#[repr(align(64))] +pub enum Align64 { + A(u32), + B(u32), +} + +pub struct Nested64 { + a: u8, + b: Align64, + c: u16, +} + +// CHECK-LABEL: @align64 +#[no_mangle] +pub fn align64(a: u32) -> Align64 { + // CHECK: %a64 = alloca [64 x i8], align 64 + // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 64 %{{.*}}, ptr align 64 %{{.*}}, i{{[0-9]+}} 64, i1 false) + let a64 = Align64::A(a); + a64 +} + +// CHECK-LABEL: @nested64 +#[no_mangle] +pub fn nested64(a: u8, b: u32, c: u16) -> Nested64 { + // CHECK: %n64 = alloca [128 x i8], align 64 + let n64 = Nested64 { a, b: Align64::B(b), c }; + n64 +} diff --git a/tests/codegen-llvm/align-fn.rs b/tests/codegen-llvm/align-fn.rs new file mode 100644 index 00000000000..cbc24e2ae2e --- /dev/null +++ b/tests/codegen-llvm/align-fn.rs @@ -0,0 +1,143 @@ +//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 -Clink-dead-code +//@ edition: 2024 +//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) + +#![crate_type = "lib"] +// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity +#![feature(rustc_attrs)] +#![feature(fn_align)] + +// CHECK: align 16 +#[unsafe(no_mangle)] +#[rustc_align(16)] +pub fn fn_align() {} + +pub struct A; + +impl A { + // CHECK: align 16 + #[unsafe(no_mangle)] + #[rustc_align(16)] + pub fn method_align(self) {} + + // CHECK: align 16 + #[unsafe(no_mangle)] + #[rustc_align(16)] + pub fn associated_fn() {} +} + +trait T: Sized { + fn trait_fn() {} + + fn trait_method(self) {} + + #[rustc_align(8)] + fn trait_method_inherit_low(self); + + #[rustc_align(32)] + fn trait_method_inherit_high(self); + + #[rustc_align(32)] + fn trait_method_inherit_default(self) {} + + #[rustc_align(4)] + #[rustc_align(128)] + #[rustc_align(8)] + fn inherit_highest(self) {} +} + +impl T for A { + // CHECK-LABEL: trait_fn + // CHECK-SAME: align 16 + #[unsafe(no_mangle)] + #[rustc_align(16)] + fn trait_fn() {} + + // CHECK-LABEL: trait_method + // CHECK-SAME: align 16 + #[unsafe(no_mangle)] + #[rustc_align(16)] + fn trait_method(self) {} + + // The prototype's align is ignored because the align here is higher. + // CHECK-LABEL: trait_method_inherit_low + // CHECK-SAME: align 16 + #[unsafe(no_mangle)] + #[rustc_align(16)] + fn trait_method_inherit_low(self) {} + + // The prototype's align is used because it is higher. + // CHECK-LABEL: trait_method_inherit_high + // CHECK-SAME: align 32 + #[unsafe(no_mangle)] + #[rustc_align(16)] + fn trait_method_inherit_high(self) {} + + // The prototype's align inherited. + // CHECK-LABEL: trait_method_inherit_default + // CHECK-SAME: align 32 + #[unsafe(no_mangle)] + fn trait_method_inherit_default(self) {} + + // The prototype's highest align inherited. + // CHECK-LABEL: inherit_highest + // CHECK-SAME: align 128 + #[unsafe(no_mangle)] + #[rustc_align(32)] + #[rustc_align(64)] + fn inherit_highest(self) {} +} + +trait HasDefaultImpl: Sized { + // CHECK-LABEL: inherit_from_default_method + // CHECK-LABEL: inherit_from_default_method + // CHECK-SAME: align 32 + #[rustc_align(32)] + fn inherit_from_default_method(self) {} +} + +pub struct InstantiateDefaultMethods; + +impl HasDefaultImpl for InstantiateDefaultMethods {} + +// CHECK-LABEL: align_specified_twice_1 +// CHECK-SAME: align 64 +#[unsafe(no_mangle)] +#[rustc_align(32)] +#[rustc_align(64)] +pub fn align_specified_twice_1() {} + +// CHECK-LABEL: align_specified_twice_2 +// CHECK-SAME: align 128 +#[unsafe(no_mangle)] +#[rustc_align(128)] +#[rustc_align(32)] +pub fn align_specified_twice_2() {} + +// CHECK-LABEL: align_specified_twice_3 +// CHECK-SAME: align 256 +#[unsafe(no_mangle)] +#[rustc_align(32)] +#[rustc_align(256)] +pub fn align_specified_twice_3() {} + +const _: () = { + // CHECK-LABEL: align_unmangled + // CHECK-SAME: align 256 + #[unsafe(no_mangle)] + #[rustc_align(32)] + #[rustc_align(256)] + extern "C" fn align_unmangled() {} +}; + +unsafe extern "C" { + #[rustc_align(256)] + fn align_unmangled(); +} + +// FIXME also check `gen` et al +// CHECK-LABEL: async_align +// CHECK-SAME: align 64 +#[unsafe(no_mangle)] +#[rustc_align(64)] +pub async fn async_align() {} diff --git a/tests/codegen-llvm/align-offset.rs b/tests/codegen-llvm/align-offset.rs new file mode 100644 index 00000000000..21062cc0a91 --- /dev/null +++ b/tests/codegen-llvm/align-offset.rs @@ -0,0 +1,75 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @align8 +#[no_mangle] +pub fn align8(p: *const u8) -> bool { + // CHECK: ret i1 true + p.align_offset(8) < 8 +} + +#[repr(align(4))] +pub struct Align4([u8; 4]); + +// CHECK-LABEL: @align_to4 +#[no_mangle] +pub fn align_to4(x: &[u8]) -> bool { + // CHECK: ret i1 true + let (prefix, _middle, suffix) = unsafe { x.align_to::() }; + prefix.len() < 4 && suffix.len() < 4 +} + +// CHECK-LABEL: @align_offset_byte_ptr(ptr{{.+}}%ptr) +#[no_mangle] +pub fn align_offset_byte_ptr(ptr: *const u8) -> usize { + // CHECK: %[[ADDR:.+]] = ptrtoint ptr %ptr to [[USIZE:i[0-9]+]] + // CHECK: %[[UP:.+]] = add [[USIZE]] %[[ADDR]], 31 + // CHECK: %[[ALIGNED:.+]] = and [[USIZE]] %[[UP]], -32 + // CHECK: %[[OFFSET:.+]] = sub [[USIZE]] %[[ALIGNED]], %[[ADDR]] + + // Since we're offsetting a byte pointer, there's no further fixups + // CHECK-NOT: shr + // CHECK-NOT: div + // CHECK-NOT: select + + // CHECK: ret [[USIZE]] %[[OFFSET]] + ptr.align_offset(32) +} + +// CHECK-LABEL: @align_offset_word_slice(ptr{{.+}}align 4{{.+}}%slice.0 +#[no_mangle] +pub fn align_offset_word_slice(slice: &[Align4]) -> usize { + // CHECK: %[[ADDR:.+]] = ptrtoint ptr %slice.0 to [[USIZE]] + // CHECK: %[[UP:.+]] = add [[USIZE]] %[[ADDR]], 31 + // CHECK: %[[ALIGNED:.+]] = and [[USIZE]] %[[UP]], -32 + // CHECK: %[[BOFFSET:.+]] = sub [[USIZE]] %[[ALIGNED]], %[[ADDR]] + // CHECK: %[[OFFSET:.+]] = lshr exact [[USIZE]] %[[BOFFSET]], 2 + + // Slices are known to be aligned, so we don't need the "maybe -1" path + // CHECK-NOT: select + + // CHECK: ret [[USIZE]] %[[OFFSET]] + slice.as_ptr().align_offset(32) +} + +// CHECK-LABEL: @align_offset_word_ptr(ptr{{.+}}%ptr +#[no_mangle] +pub fn align_offset_word_ptr(ptr: *const Align4) -> usize { + // CHECK: %[[ADDR:.+]] = ptrtoint ptr %ptr to [[USIZE]] + // CHECK: %[[UP:.+]] = add [[USIZE]] %[[ADDR]], 31 + // CHECK: %[[ALIGNED:.+]] = and [[USIZE]] %[[UP]], -32 + // CHECK: %[[BOFFSET:.+]] = sub [[USIZE]] %[[ALIGNED]], %[[ADDR]] + + // While we can always get a *byte* offset that will work, if the original + // pointer is unaligned it might be impossible to return an *element* offset + // that will make it aligned. We want it to be a `select`, not a `br`, so + // that the assembly will be branchless. + // CHECK: %[[LOW:.+]] = and [[USIZE]] %[[ADDR]], 3 + // CHECK: %[[ORIGINAL_ALIGNED:.+]] = icmp eq [[USIZE]] %[[LOW]], 0 + // CHECK: %[[OFFSET:.+]] = lshr exact [[USIZE]] %[[BOFFSET]], 2 + // CHECK: %[[R:.+]] = select i1 %[[ORIGINAL_ALIGNED]], [[USIZE]] %[[OFFSET]], [[USIZE]] -1 + + // CHECK: ret [[USIZE]] %[[R]] + ptr.align_offset(32) +} diff --git a/tests/codegen-llvm/align-struct.rs b/tests/codegen-llvm/align-struct.rs new file mode 100644 index 00000000000..d4cc65e9158 --- /dev/null +++ b/tests/codegen-llvm/align-struct.rs @@ -0,0 +1,70 @@ +//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 +// 32bit MSVC does not align things properly so we suppress high alignment annotations (#112480) +//@ ignore-i686-pc-windows-msvc +//@ ignore-i686-pc-windows-gnu + +#![crate_type = "lib"] + +#[repr(align(64))] +pub struct Align64(i32); + +pub struct Nested64 { + a: Align64, + b: i32, + c: i32, + d: i8, +} + +// This has the extra field in B to ensure it's not ScalarPair, +// and thus that the test actually emits it via memory, not `insertvalue`. +pub enum Enum4 { + A(i32), + B(i32, i32), +} + +pub enum Enum64 { + A(Align64), + B(i32), +} + +// CHECK-LABEL: @align64 +#[no_mangle] +pub fn align64(i: i32) -> Align64 { + // CHECK: %a64 = alloca [64 x i8], align 64 + // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 64 %{{.*}}, ptr align 64 %{{.*}}, i{{[0-9]+}} 64, i1 false) + let a64 = Align64(i); + a64 +} + +// For issue 54028: make sure that we are specifying the correct alignment for fields of aligned +// structs +// CHECK-LABEL: @align64_load +#[no_mangle] +pub fn align64_load(a: Align64) -> i32 { + // CHECK: {{%.*}} = load i32, ptr {{%.*}}, align 64 + a.0 +} + +// CHECK-LABEL: @nested64 +#[no_mangle] +pub fn nested64(a: Align64, b: i32, c: i32, d: i8) -> Nested64 { + // CHECK: %n64 = alloca [128 x i8], align 64 + let n64 = Nested64 { a, b, c, d }; + n64 +} + +// CHECK-LABEL: @enum4 +#[no_mangle] +pub fn enum4(a: i32) -> Enum4 { + // CHECK: %e4 = alloca [12 x i8], align 4 + let e4 = Enum4::A(a); + e4 +} + +// CHECK-LABEL: @enum64 +#[no_mangle] +pub fn enum64(a: Align64) -> Enum64 { + // CHECK: %e64 = alloca [128 x i8], align 64 + let e64 = Enum64::A(a); + e64 +} diff --git a/tests/codegen-llvm/alloc-optimisation.rs b/tests/codegen-llvm/alloc-optimisation.rs new file mode 100644 index 00000000000..3735860d510 --- /dev/null +++ b/tests/codegen-llvm/alloc-optimisation.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +#[no_mangle] +pub fn alloc_test(data: u32) { + // CHECK-LABEL: @alloc_test + // CHECK-NEXT: start: + // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 + // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() + // CHECK-NEXT: ret void + let x = Box::new(data); + drop(x); +} diff --git a/tests/codegen-llvm/amdgpu-addrspacecast.rs b/tests/codegen-llvm/amdgpu-addrspacecast.rs new file mode 100644 index 00000000000..7fe630a7efa --- /dev/null +++ b/tests/codegen-llvm/amdgpu-addrspacecast.rs @@ -0,0 +1,18 @@ +// Check that pointers are casted to addrspace(0) before they are used + +//@ compile-flags: --crate-type=rlib --target=amdgcn-amd-amdhsa -Ctarget-cpu=gfx900 +//@ needs-llvm-components: amdgpu +//@ add-core-stubs +#![feature(no_core)] +#![no_core] + +extern crate minicore; + +// CHECK-LABEL: @ref_of_local +// CHECK: [[alloca:%[0-9]]] = alloca +// CHECK: %i = addrspacecast ptr addrspace(5) [[alloca]] to ptr +#[no_mangle] +pub fn ref_of_local(f: fn(&i32)) { + let i = 0; + f(&i); +} diff --git a/tests/codegen-llvm/array-clone.rs b/tests/codegen-llvm/array-clone.rs new file mode 100644 index 00000000000..35445174684 --- /dev/null +++ b/tests/codegen-llvm/array-clone.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @array_clone +#[no_mangle] +pub fn array_clone(a: &[u8; 2]) -> [u8; 2] { + // CHECK-NOT: getelementptr + // CHECK-NOT: load i8 + // CHECK-NOT: zext + // CHECK-NOT: shl + // CHECK: load i16 + // CHECK-NEXT: ret i16 + a.clone() +} diff --git a/tests/codegen-llvm/array-cmp.rs b/tests/codegen-llvm/array-cmp.rs new file mode 100644 index 00000000000..0d337655401 --- /dev/null +++ b/tests/codegen-llvm/array-cmp.rs @@ -0,0 +1,74 @@ +// Ensure the asm for array comparisons is properly optimized. + +//@ compile-flags: -C opt-level=2 +//@ needs-deterministic-layouts (checks depend on tuple layout) + +#![crate_type = "lib"] + +// CHECK-LABEL: @compare +// CHECK: start: +// CHECK-NEXT: ret i1 true +#[no_mangle] +pub fn compare() -> bool { + let bytes = 12.5f32.to_ne_bytes(); + bytes + == if cfg!(target_endian = "big") { + [0x41, 0x48, 0x00, 0x00] + } else { + [0x00, 0x00, 0x48, 0x41] + } +} + +// CHECK-LABEL: @array_of_tuple_le +#[no_mangle] +pub fn array_of_tuple_le(a: &[(i16, u16); 2], b: &[(i16, u16); 2]) -> bool { + // Ensure that, after all the optimizations have run, the happy path just checks + // `eq` on each corresponding pair and moves onto the next one if it is. + // Then there's a dedup'd comparison for the place that's different. + // (As opposed to, say, running a full `[su]cmp` as part of checking equality.) + + // This is written quite specifically because different library code was triggering + // along the way, so this + // has enough checks to make sure that's not happening. It doesn't need to be + // *exactly* this IR, but be careful if you ever need to update these checks. + + // CHECK: start: + // CHECK: %[[A00:.+]] = load i16, ptr %a + // CHECK: %[[B00:.+]] = load i16, ptr %b + // CHECK-NOT: cmp + // CHECK: %[[EQ00:.+]] = icmp eq i16 %[[A00]], %[[B00]] + // CHECK-NEXT: br i1 %[[EQ00]], label %[[L01:.+]], label %[[EXIT_S:.+]] + + // CHECK: [[L01]]: + // CHECK: %[[PA01:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 2 + // CHECK: %[[PB01:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 2 + // CHECK: %[[A01:.+]] = load i16, ptr %[[PA01]] + // CHECK: %[[B01:.+]] = load i16, ptr %[[PB01]] + // CHECK-NOT: cmp + // CHECK: %[[EQ01:.+]] = icmp eq i16 %[[A01]], %[[B01]] + // CHECK-NEXT: br i1 %[[EQ01]], label %[[L10:.+]], label %[[EXIT_U:.+]] + + // CHECK: [[L10]]: + // CHECK: %[[PA10:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 4 + // CHECK: %[[PB10:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 4 + // CHECK: %[[A10:.+]] = load i16, ptr %[[PA10]] + // CHECK: %[[B10:.+]] = load i16, ptr %[[PB10]] + // CHECK-NOT: cmp + // CHECK: %[[EQ10:.+]] = icmp eq i16 %[[A10]], %[[B10]] + // CHECK-NEXT: br i1 %[[EQ10]], label %[[L11:.+]], label %[[EXIT_S]] + + // CHECK: [[L11]]: + // CHECK: %[[PA11:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 6 + // CHECK: %[[PB11:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 6 + // CHECK: %[[A11:.+]] = load i16, ptr %[[PA11]] + // CHECK: %[[B11:.+]] = load i16, ptr %[[PB11]] + // CHECK-NOT: cmp + // CHECK: %[[EQ11:.+]] = icmp eq i16 %[[A11]], %[[B11]] + // CHECK-NEXT: br i1 %[[EQ11]], label %[[DONE:.+]], label %[[EXIT_U]] + + // CHECK: [[DONE]]: + // CHECK: %[[RET:.+]] = phi i1 [ %{{.+}}, %[[EXIT_S]] ], [ %{{.+}}, %[[EXIT_U]] ], [ true, %[[L11]] ] + // CHECK: ret i1 %[[RET]] + + a <= b +} diff --git a/tests/codegen-llvm/array-codegen.rs b/tests/codegen-llvm/array-codegen.rs new file mode 100644 index 00000000000..9b0c6e8c347 --- /dev/null +++ b/tests/codegen-llvm/array-codegen.rs @@ -0,0 +1,62 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes + +#![crate_type = "lib"] + +// CHECK-LABEL: @array_load +#[no_mangle] +pub fn array_load(a: &[u8; 4]) -> [u8; 4] { + // CHECK-NOT: alloca + // CHECK: %[[ALLOCA:.+]] = alloca [4 x i8], align 1 + // CHECK-NOT: alloca + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[ALLOCA]], ptr align 1 %a, {{.+}} 4, i1 false) + // CHECK: %[[TEMP:.+]] = load i32, ptr %[[ALLOCA]], align 1 + // CHECK: ret i32 %[[TEMP]] + *a +} + +// CHECK-LABEL: @array_store +#[no_mangle] +pub fn array_store(a: [u8; 4], p: &mut [u8; 4]) { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = alloca [4 x i8], [[TEMPALIGN:align [0-9]+]] + // CHECK-NOT: alloca + // CHECK: %a = alloca [4 x i8] + // CHECK-NOT: alloca + // store i32 %0, ptr %[[TEMP]] + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %a, ptr [[TEMPALIGN]] %[[TEMP]], {{.+}} 4, i1 false) + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %a, {{.+}} 4, i1 false) + *p = a; +} + +// CHECK-LABEL: @array_copy +#[no_mangle] +pub fn array_copy(a: &[u8; 4], p: &mut [u8; 4]) { + // CHECK-NOT: alloca + // CHECK: %[[LOCAL:.+]] = alloca [4 x i8], align 1 + // CHECK-NOT: alloca + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[LOCAL]], ptr align 1 %a, {{.+}} 4, i1 false) + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %[[LOCAL]], {{.+}} 4, i1 false) + *p = *a; +} + +// CHECK-LABEL: @array_copy_1_element +#[no_mangle] +pub fn array_copy_1_element(a: &[u8; 1], p: &mut [u8; 1]) { + // CHECK-NOT: alloca + // CHECK: %[[LOCAL:.+]] = alloca [1 x i8], align 1 + // CHECK-NOT: alloca + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[LOCAL]], ptr align 1 %a, {{.+}} 1, i1 false) + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %[[LOCAL]], {{.+}} 1, i1 false) + *p = *a; +} + +// CHECK-LABEL: @array_copy_2_elements +#[no_mangle] +pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) { + // CHECK-NOT: alloca + // CHECK: %[[LOCAL:.+]] = alloca [2 x i8], align 1 + // CHECK-NOT: alloca + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[LOCAL]], ptr align 1 %a, {{.+}} 2, i1 false) + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %[[LOCAL]], {{.+}} 2, i1 false) + *p = *a; +} diff --git a/tests/codegen-llvm/array-equality.rs b/tests/codegen-llvm/array-equality.rs new file mode 100644 index 00000000000..fa0475bf480 --- /dev/null +++ b/tests/codegen-llvm/array-equality.rs @@ -0,0 +1,101 @@ +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled +//@ only-x86_64 +#![crate_type = "lib"] + +// CHECK-LABEL: @array_eq_value +#[no_mangle] +pub fn array_eq_value(a: [u16; 3], b: [u16; 3]) -> bool { + // CHECK-NEXT: start: + // CHECK-NEXT: %2 = icmp eq i48 %0, %1 + // CHECK-NEXT: ret i1 %2 + a == b +} + +// CHECK-LABEL: @array_eq_ref +#[no_mangle] +pub fn array_eq_ref(a: &[u16; 3], b: &[u16; 3]) -> bool { + // CHECK: start: + // CHECK: load i48, ptr %{{.+}}, align 2 + // CHECK: load i48, ptr %{{.+}}, align 2 + // CHECK: icmp eq i48 + // CHECK-NEXT: ret + a == b +} + +// CHECK-LABEL: @array_eq_value_still_passed_by_pointer +#[no_mangle] +pub fn array_eq_value_still_passed_by_pointer(a: [u16; 9], b: [u16; 9]) -> bool { + // CHECK-NEXT: start: + // CHECK: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(ptr {{.*}} dereferenceable(18) %{{.+}}, ptr {{.*}} dereferenceable(18) %{{.+}}, i64 18) + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0 + // CHECK-NEXT: ret i1 %[[EQ]] + a == b +} + +// CHECK-LABEL: @array_eq_long +#[no_mangle] +pub fn array_eq_long(a: &[u16; 1234], b: &[u16; 1234]) -> bool { + // CHECK-NEXT: start: + // CHECK: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(ptr {{.*}} dereferenceable(2468) %{{.+}}, ptr {{.*}} dereferenceable(2468) %{{.+}}, i64 2468) + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0 + // CHECK-NEXT: ret i1 %[[EQ]] + a == b +} + +// CHECK-LABEL: @array_char_eq +#[no_mangle] +pub fn array_char_eq(a: [char; 2], b: [char; 2]) -> bool { + // CHECK-NEXT: start: + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i64 %0, %1 + // CHECK-NEXT: ret i1 %[[EQ]] + a == b +} + +// CHECK-LABEL: @array_eq_zero_short(i48 +#[no_mangle] +pub fn array_eq_zero_short(x: [u16; 3]) -> bool { + // CHECK-NEXT: start: + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i48 %0, 0 + // CHECK-NEXT: ret i1 %[[EQ]] + x == [0; 3] +} + +// CHECK-LABEL: @array_eq_none_short(i40 +#[no_mangle] +pub fn array_eq_none_short(x: [Option>; 5]) -> bool { + // CHECK-NEXT: start: + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i40 %0, 0 + // CHECK-NEXT: ret i1 %[[EQ]] + x == [None; 5] +} + +// CHECK-LABEL: @array_eq_zero_nested( +#[no_mangle] +pub fn array_eq_zero_nested(x: [[u8; 3]; 3]) -> bool { + // CHECK: %[[VAL:.+]] = load i72 + // CHECK-SAME: align 1 + // CHECK: %[[EQ:.+]] = icmp eq i72 %[[VAL]], 0 + // CHECK: ret i1 %[[EQ]] + x == [[0; 3]; 3] +} + +// CHECK-LABEL: @array_eq_zero_mid( +#[no_mangle] +pub fn array_eq_zero_mid(x: [u16; 8]) -> bool { + // CHECK-NEXT: start: + // CHECK: %[[LOAD:.+]] = load i128, + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i128 %[[LOAD]], 0 + // CHECK-NEXT: ret i1 %[[EQ]] + x == [0; 8] +} + +// CHECK-LABEL: @array_eq_zero_long( +#[no_mangle] +pub fn array_eq_zero_long(x: [u16; 1234]) -> bool { + // CHECK-NEXT: start: + // CHECK-NOT: alloca + // CHECK: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}( + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0 + // CHECK-NEXT: ret i1 %[[EQ]] + x == [0; 1234] +} diff --git a/tests/codegen-llvm/array-from_fn.rs b/tests/codegen-llvm/array-from_fn.rs new file mode 100644 index 00000000000..7202d0c67e6 --- /dev/null +++ b/tests/codegen-llvm/array-from_fn.rs @@ -0,0 +1,13 @@ +//@ revisions: NORMAL OPT +//@ [NORMAL] compile-flags: -C opt-level=0 -C debuginfo=2 +//@ [OPT] compile-flags: -C opt-level=s -C debuginfo=0 + +#![crate_type = "lib"] +#![feature(array_from_fn)] + +#[no_mangle] +pub fn iota() -> [u8; 16] { + // OPT-NOT: core..array..Guard + // NORMAL: core..array..Guard + std::array::from_fn(|i| i as _) +} diff --git a/tests/codegen-llvm/array-map.rs b/tests/codegen-llvm/array-map.rs new file mode 100644 index 00000000000..f49dddcfc20 --- /dev/null +++ b/tests/codegen-llvm/array-map.rs @@ -0,0 +1,35 @@ +//@ compile-flags: -C opt-level=3 -C target-cpu=x86-64-v3 +//@ only-x86_64 + +#![crate_type = "lib"] + +// CHECK-LABEL: @short_integer_map +#[no_mangle] +pub fn short_integer_map(x: [u32; 8]) -> [u32; 8] { + // CHECK: load <8 x i32> + // CHECK: shl <8 x i32> + // CHECK: or{{( disjoint)?}} <8 x i32> + // CHECK: store <8 x i32> + x.map(|x| 2 * x + 1) +} + +// This test is checking that LLVM can SRoA away a bunch of the overhead, +// like fully moving the iterators to registers. Notably, previous implementations +// of `map` ended up `alloca`ing the whole `array::IntoIterator`, meaning both a +// hard-to-eliminate `memcpy` and that the iteration counts needed to be written +// out to stack every iteration, even for infallible operations on `Copy` types. +// +// This is still imperfect, as there's more copies than would be ideal, +// but hopefully work like #103830 will improve that in future, +// and update this test to be stricter. +// +// CHECK-LABEL: @long_integer_map +#[no_mangle] +pub fn long_integer_map(x: [u32; 512]) -> [u32; 512] { + // CHECK: start: + // CHECK-NEXT: alloca [2048 x i8] + // CHECK-NOT: alloca + // CHECK: mul <{{[0-9]+}} x i32> + // CHECK: add <{{[0-9]+}} x i32> + x.map(|x| 13 * x + 7) +} diff --git a/tests/codegen-llvm/array-optimized.rs b/tests/codegen-llvm/array-optimized.rs new file mode 100644 index 00000000000..000163d5519 --- /dev/null +++ b/tests/codegen-llvm/array-optimized.rs @@ -0,0 +1,33 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @array_copy_1_element +#[no_mangle] +pub fn array_copy_1_element(a: &[u8; 1], p: &mut [u8; 1]) { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = load i8, ptr %a, align 1 + // CHECK: store i8 %[[TEMP]], ptr %p, align 1 + // CHECK: ret + *p = *a; +} + +// CHECK-LABEL: @array_copy_2_elements +#[no_mangle] +pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = load i16, ptr %a, align 1 + // CHECK: store i16 %[[TEMP]], ptr %p, align 1 + // CHECK: ret + *p = *a; +} + +// CHECK-LABEL: @array_copy_4_elements +#[no_mangle] +pub fn array_copy_4_elements(a: &[u8; 4], p: &mut [u8; 4]) { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = load i32, ptr %a, align 1 + // CHECK: store i32 %[[TEMP]], ptr %p, align 1 + // CHECK: ret + *p = *a; +} diff --git a/tests/codegen-llvm/array-repeat.rs b/tests/codegen-llvm/array-repeat.rs new file mode 100644 index 00000000000..4c755df9390 --- /dev/null +++ b/tests/codegen-llvm/array-repeat.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] +#![feature(array_repeat)] + +use std::array::repeat; + +// CHECK-LABEL: @byte_repeat +#[no_mangle] +fn byte_repeat(b: u8) -> [u8; 1024] { + // CHECK-NOT: alloca + // CHECK-NOT: store + // CHECK: memset + repeat(b) +} diff --git a/tests/codegen-llvm/ascii-char.rs b/tests/codegen-llvm/ascii-char.rs new file mode 100644 index 00000000000..86ec9d73afe --- /dev/null +++ b/tests/codegen-llvm/ascii-char.rs @@ -0,0 +1,36 @@ +//@ compile-flags: -C opt-level=1 + +#![crate_type = "lib"] +#![feature(ascii_char)] + +use std::ascii::Char as AsciiChar; + +// CHECK-LABEL: i8 @unwrap_digit_from_remainder(i32 +#[no_mangle] +pub fn unwrap_digit_from_remainder(v: u32) -> AsciiChar { + // CHECK-NOT: icmp + // CHECK-NOT: panic + + // CHECK: %[[R:.+]] = urem i32 %v, 10 + // CHECK-NEXT: %[[T:.+]] = trunc{{( nuw)?( nsw)?}} i32 %[[R]] to i8 + // CHECK-NEXT: %[[D:.+]] = or{{( disjoint)?}} i8 %[[T]], 48 + // CHECK-NEXT: ret i8 %[[D]] + + // CHECK-NOT: icmp + // CHECK-NOT: panic + AsciiChar::digit((v % 10) as u8).unwrap() +} + +// CHECK-LABEL: i8 @unwrap_from_masked(i8 +#[no_mangle] +pub fn unwrap_from_masked(b: u8) -> AsciiChar { + // CHECK-NOT: icmp + // CHECK-NOT: panic + + // CHECK: %[[M:.+]] = and i8 %b, 127 + // CHECK-NEXT: ret i8 %[[M]] + + // CHECK-NOT: icmp + // CHECK-NOT: panic + AsciiChar::from_u8(b & 0x7f).unwrap() +} diff --git a/tests/codegen-llvm/asm/aarch64-clobbers.rs b/tests/codegen-llvm/asm/aarch64-clobbers.rs new file mode 100644 index 00000000000..dd3ba1510b5 --- /dev/null +++ b/tests/codegen-llvm/asm/aarch64-clobbers.rs @@ -0,0 +1,47 @@ +//@ add-core-stubs +//@ revisions: aarch64 aarch64_fixed_x18 aarch64_no_x18 aarch64_reserve_x18 arm64ec +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: aarch64 +//@[aarch64_fixed_x18] compile-flags: --target aarch64-unknown-linux-gnu -Zfixed-x18 +//@[aarch64_fixed_x18] needs-llvm-components: aarch64 +//@[aarch64_no_x18] compile-flags: --target aarch64-pc-windows-msvc +//@[aarch64_no_x18] needs-llvm-components: aarch64 +// aarch64-unknown-trusty uses aarch64-unknown-unknown-musl which doesn't +// reserve x18 by default as llvm_target, and pass +reserve-x18 in target-spec. +//@[aarch64_reserve_x18] compile-flags: --target aarch64-unknown-trusty +//@[aarch64_reserve_x18] needs-llvm-components: aarch64 +//@[arm64ec] compile-flags: --target arm64ec-pc-windows-msvc +//@[arm64ec] needs-llvm-components: aarch64 +// ignore-tidy-linelength + +#![crate_type = "rlib"] +#![feature(no_core)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: @cc_clobber +// CHECK: call void asm sideeffect "", "~{cc}"() +#[no_mangle] +pub unsafe fn cc_clobber() { + asm!("", options(nostack, nomem)); +} + +// CHECK-LABEL: @no_clobber +// CHECK: call void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn no_clobber() { + asm!("", options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @clobber_abi +// aarch64: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w13},={w14},={w15},={w16},={w17},={w18},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15},={q16},={q17},={q18},={q19},={q20},={q21},={q22},={q23},={q24},={q25},={q26},={q27},={q28},={q29},={q30},={q31},~{p0},~{p1},~{p2},~{p3},~{p4},~{p5},~{p6},~{p7},~{p8},~{p9},~{p10},~{p11},~{p12},~{p13},~{p14},~{p15},~{ffr}"() +// aarch64_fixed_x18: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w13},={w14},={w15},={w16},={w17},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15},={q16},={q17},={q18},={q19},={q20},={q21},={q22},={q23},={q24},={q25},={q26},={q27},={q28},={q29},={q30},={q31},~{p0},~{p1},~{p2},~{p3},~{p4},~{p5},~{p6},~{p7},~{p8},~{p9},~{p10},~{p11},~{p12},~{p13},~{p14},~{p15},~{ffr}"() +// aarch64_no_x18: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w13},={w14},={w15},={w16},={w17},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15},={q16},={q17},={q18},={q19},={q20},={q21},={q22},={q23},={q24},={q25},={q26},={q27},={q28},={q29},={q30},={q31},~{p0},~{p1},~{p2},~{p3},~{p4},~{p5},~{p6},~{p7},~{p8},~{p9},~{p10},~{p11},~{p12},~{p13},~{p14},~{p15},~{ffr}"() +// aarch64_reserve_x18: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w13},={w14},={w15},={w16},={w17},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15},={q16},={q17},={q18},={q19},={q20},={q21},={q22},={q23},={q24},={q25},={q26},={q27},={q28},={q29},={q30},={q31},~{p0},~{p1},~{p2},~{p3},~{p4},~{p5},~{p6},~{p7},~{p8},~{p9},~{p10},~{p11},~{p12},~{p13},~{p14},~{p15},~{ffr}"() +// arm64ec: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w15},={w16},={w17},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15}"() +#[no_mangle] +pub unsafe fn clobber_abi() { + asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); +} diff --git a/tests/codegen-llvm/asm/avr-clobbers.rs b/tests/codegen-llvm/asm/avr-clobbers.rs new file mode 100644 index 00000000000..9451127bf04 --- /dev/null +++ b/tests/codegen-llvm/asm/avr-clobbers.rs @@ -0,0 +1,39 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: --target avr-none -C target-cpu=atmega328p +//@ needs-llvm-components: avr + +#![crate_type = "rlib"] +#![feature(no_core, asm_experimental_arch)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: @sreg_is_clobbered +// CHECK: void asm sideeffect "", "~{sreg}"() +#[no_mangle] +pub unsafe fn sreg_is_clobbered() { + asm!("", options(nostack, nomem)); +} + +// CHECK-LABEL: @sreg_is_not_clobbered_if_preserve_flags_is_used +// CHECK: void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn sreg_is_not_clobbered_if_preserve_flags_is_used() { + asm!("", options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @clobber_abi +// CHECK: asm sideeffect "", "={r18},={r19},={r20},={r21},={r22},={r23},={r24},={r25},={r26},={r27},={r30},={r31},~{sreg}"() +#[no_mangle] +pub unsafe fn clobber_abi() { + asm!("", clobber_abi("C"), options(nostack, nomem)); +} + +// CHECK-LABEL: @clobber_abi_with_preserved_flags +// CHECK: asm sideeffect "", "={r18},={r19},={r20},={r21},={r22},={r23},={r24},={r25},={r26},={r27},={r30},={r31}"() +#[no_mangle] +pub unsafe fn clobber_abi_with_preserved_flags() { + asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); +} diff --git a/tests/codegen-llvm/asm/bpf-clobbers.rs b/tests/codegen-llvm/asm/bpf-clobbers.rs new file mode 100644 index 00000000000..1117549b1ec --- /dev/null +++ b/tests/codegen-llvm/asm/bpf-clobbers.rs @@ -0,0 +1,31 @@ +//@ add-core-stubs +//@ compile-flags: --target bpfel-unknown-none +//@ needs-llvm-components: bpf + +#![crate_type = "rlib"] +#![feature(no_core, asm_experimental_arch)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: @flags_clobber +// CHECK: call void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn flags_clobber() { + asm!("", options(nostack, nomem)); +} + +// CHECK-LABEL: @no_clobber +// CHECK: call void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn no_clobber() { + asm!("", options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @clobber_abi +// CHECK: asm sideeffect "", "={r0},={r1},={r2},={r3},={r4},={r5}"() +#[no_mangle] +pub unsafe fn clobber_abi() { + asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); +} diff --git a/tests/codegen-llvm/asm/critical.rs b/tests/codegen-llvm/asm/critical.rs new file mode 100644 index 00000000000..0f29d7c69b4 --- /dev/null +++ b/tests/codegen-llvm/asm/critical.rs @@ -0,0 +1,36 @@ +//@ only-x86_64 +//@ compile-flags: -C no-prepopulate-passes +#![feature(asm_goto_with_outputs)] +#![crate_type = "lib"] +use std::arch::asm; + +// Regression test for #137867. Check that critical edges have been split before code generation, +// and so all stores to the asm output occur on disjoint paths without any of them jumping to +// another callbr label. +// +// CHECK-LABEL: @f( +// CHECK: [[OUT:%.*]] = callbr i32 asm +// CHECK-NEXT: to label %[[BB0:.*]] [label %[[BB1:.*]], label %[[BB2:.*]]], +// CHECK: [[BB1]]: +// CHECK-NEXT: store i32 [[OUT]], ptr %a +// CHECK-NEXT: br label %[[BBR:.*]] +// CHECK: [[BB2]]: +// CHECK-NEXT: store i32 [[OUT]], ptr %a +// CHECK-NEXT: br label %[[BBR]] +// CHECK: [[BB0]]: +// CHECK-NEXT: store i32 [[OUT]], ptr %a +// CHECK-NEXT: br label %[[BBR]] +// CHECK: [[BBR]]: +// CHECK-NEXT: [[RET:%.*]] = load i32, ptr %a +// CHECK-NEXT: ret i32 [[RET]] +#[unsafe(no_mangle)] +pub unsafe fn f(mut a: u32) -> u32 { + asm!( + "jmp {} + jmp {}", + label {}, + label {}, + inout("eax") a, + ); + a +} diff --git a/tests/codegen-llvm/asm/csky-clobbers.rs b/tests/codegen-llvm/asm/csky-clobbers.rs new file mode 100644 index 00000000000..4986d0fe56d --- /dev/null +++ b/tests/codegen-llvm/asm/csky-clobbers.rs @@ -0,0 +1,24 @@ +//@ add-core-stubs +//@ compile-flags: --target csky-unknown-linux-gnuabiv2 +//@ needs-llvm-components: csky + +#![crate_type = "rlib"] +#![feature(no_core, asm_experimental_arch)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: @flags_clobber +// CHECK: call void asm sideeffect "", "~{psr}"() +#[no_mangle] +pub unsafe fn flags_clobber() { + asm!("", options(nostack, nomem)); +} + +// CHECK-LABEL: @no_clobber +// CHECK: call void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn no_clobber() { + asm!("", options(nostack, nomem, preserves_flags)); +} diff --git a/tests/codegen-llvm/asm/foo.s b/tests/codegen-llvm/asm/foo.s new file mode 100644 index 00000000000..304d82aa0c6 --- /dev/null +++ b/tests/codegen-llvm/asm/foo.s @@ -0,0 +1,3 @@ +.global foo +foo: + jmp baz diff --git a/tests/codegen-llvm/asm/global_asm.rs b/tests/codegen-llvm/asm/global_asm.rs new file mode 100644 index 00000000000..32075daa3cf --- /dev/null +++ b/tests/codegen-llvm/asm/global_asm.rs @@ -0,0 +1,28 @@ +//@ revisions: x32 x64 +//@[x32] only-x86 +//@[x64] only-x86_64 +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +use std::arch::global_asm; + +// CHECK-LABEL: foo +// CHECK: module asm +// this regex will capture the correct unconditional branch inst. +// CHECK: module asm "{{[[:space:]]+}}jmp baz" +global_asm!( + r#" + .global foo +foo: + jmp baz +"# +); + +extern "C" { + fn foo(); +} + +// CHECK-LABEL: @baz +#[no_mangle] +pub unsafe extern "C" fn baz() {} diff --git a/tests/codegen-llvm/asm/global_asm_include.rs b/tests/codegen-llvm/asm/global_asm_include.rs new file mode 100644 index 00000000000..98be9c3e333 --- /dev/null +++ b/tests/codegen-llvm/asm/global_asm_include.rs @@ -0,0 +1,21 @@ +//@ revisions: x32 x64 +//@[x32] only-x86 +//@[x64] only-x86_64 +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +use std::arch::global_asm; + +// CHECK-LABEL: foo +// CHECK: module asm +// CHECK: module asm "{{[[:space:]]+}}jmp baz" +global_asm!(include_str!("foo.s")); + +extern "C" { + fn foo(); +} + +// CHECK-LABEL: @baz +#[no_mangle] +pub unsafe extern "C" fn baz() {} diff --git a/tests/codegen-llvm/asm/global_asm_x2.rs b/tests/codegen-llvm/asm/global_asm_x2.rs new file mode 100644 index 00000000000..9e3a00f0680 --- /dev/null +++ b/tests/codegen-llvm/asm/global_asm_x2.rs @@ -0,0 +1,47 @@ +//@ revisions: x32 x64 +//@[x32] only-x86 +//@[x64] only-x86_64 +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![no_std] + +use core::arch::global_asm; + +// CHECK-LABEL: foo +// CHECK: module asm +// CHECK: module asm "{{[[:space:]]+}}jmp baz" +// any other global_asm will be appended to this first block, so: +// CHECK-LABEL: bar +// CHECK: module asm "{{[[:space:]]+}}jmp quux" +global_asm!( + r#" + .global foo +foo: + jmp baz +"# +); + +extern "C" { + fn foo(); +} + +// CHECK-LABEL: @baz +#[no_mangle] +pub unsafe extern "C" fn baz() {} + +// no checks here; this has been appended to the first occurrence +global_asm!( + r#" + .global bar +bar: + jmp quux +"# +); + +extern "C" { + fn bar(); +} + +#[no_mangle] +pub unsafe extern "C" fn quux() {} diff --git a/tests/codegen-llvm/asm/goto.rs b/tests/codegen-llvm/asm/goto.rs new file mode 100644 index 00000000000..f68c399c920 --- /dev/null +++ b/tests/codegen-llvm/asm/goto.rs @@ -0,0 +1,63 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 + +#![crate_type = "rlib"] +#![feature(asm_goto_with_outputs)] + +use std::arch::asm; + +// CHECK-LABEL: @asm_goto +#[no_mangle] +pub unsafe fn asm_goto() { + // CHECK: callbr void asm sideeffect alignstack inteldialect " + // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]] + asm!("jmp {}", label {}); +} + +// CHECK-LABEL: @asm_goto_with_outputs +#[no_mangle] +pub unsafe fn asm_goto_with_outputs() -> u64 { + let out: u64; + // CHECK: [[RES:%[0-9]+]] = callbr i64 asm sideeffect alignstack inteldialect " + // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]] + asm!("{} /* {} */", out(reg) out, label { return 1; }); + // CHECK: [[JUMPBB]]: + // CHECK-NEXT: [[RET:%.+]] = phi i64 [ [[RES]], %[[FALLTHROUGHBB]] ], [ 1, %start ] + // CHECK-NEXT: ret i64 [[RET]] + out +} + +// CHECK-LABEL: @asm_goto_with_outputs_use_in_label +#[no_mangle] +pub unsafe fn asm_goto_with_outputs_use_in_label() -> u64 { + let out: u64; + // CHECK: [[RES:%[0-9]+]] = callbr i64 asm sideeffect alignstack inteldialect " + // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]] + asm!("{} /* {} */", out(reg) out, label { return out; }); + // CHECK: [[JUMPBB]]: + // CHECK-NEXT: [[RET:%.+]] = phi i64 [ 1, %[[FALLTHROUGHBB]] ], [ [[RES]], %start ] + // CHECK-NEXT: ret i64 [[RET]] + 1 +} + +// CHECK-LABEL: @asm_goto_noreturn +#[no_mangle] +pub unsafe fn asm_goto_noreturn() -> u64 { + // CHECK: callbr void asm sideeffect alignstack inteldialect " + // CHECK-NEXT: to label %unreachable [label %[[JUMPBB:[a-b0-9]+]]] + asm!("jmp {}", label { return 1; }, options(noreturn)); + // CHECK: [[JUMPBB]]: + // CHECK-NEXT: ret i64 1 +} + +// CHECK-LABEL: @asm_goto_noreturn_with_outputs +#[no_mangle] +pub unsafe fn asm_goto_noreturn_with_outputs() -> u64 { + let out: u64; + // CHECK: [[RES:%[0-9]+]] = callbr i64 asm sideeffect alignstack inteldialect " + // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]] + asm!("mov {}, 1", "jmp {}", out(reg) out, label { return out; }); + // CHECK: [[JUMPBB]]: + // CHECK-NEXT: ret i64 [[RES]] + out +} diff --git a/tests/codegen-llvm/asm/hexagon-clobbers.rs b/tests/codegen-llvm/asm/hexagon-clobbers.rs new file mode 100644 index 00000000000..800b8964669 --- /dev/null +++ b/tests/codegen-llvm/asm/hexagon-clobbers.rs @@ -0,0 +1,33 @@ +//@ add-core-stubs +//@ revisions: hexagon +//@[hexagon] compile-flags: --target hexagon-unknown-linux-musl +//@[hexagon] needs-llvm-components: hexagon +//@ compile-flags: -Zmerge-functions=disabled + +#![crate_type = "rlib"] +#![feature(no_core, asm_experimental_arch)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: @flags_clobber +// CHECK: call void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn flags_clobber() { + asm!("", options(nostack, nomem)); +} + +// CHECK-LABEL: @no_clobber +// CHECK: call void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn no_clobber() { + asm!("", options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @p0_clobber +// CHECK: call void asm sideeffect "", "~{p0}"() +#[no_mangle] +pub unsafe fn p0_clobber() { + asm!("", out("p0") _, options(nostack, nomem, preserves_flags)); +} diff --git a/tests/codegen-llvm/asm/may_unwind.rs b/tests/codegen-llvm/asm/may_unwind.rs new file mode 100644 index 00000000000..63cdec7584c --- /dev/null +++ b/tests/codegen-llvm/asm/may_unwind.rs @@ -0,0 +1,39 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 + +#![crate_type = "rlib"] +#![feature(asm_unwind)] + +use std::arch::asm; + +#[no_mangle] +pub extern "C" fn panicky() {} + +struct Foo; + +impl Drop for Foo { + fn drop(&mut self) { + println!(); + } +} + +// CHECK-LABEL: @asm_may_unwind +#[no_mangle] +pub unsafe fn asm_may_unwind() { + let _m = Foo; + // CHECK: invoke void asm sideeffect alignstack inteldialect unwind "" + asm!("", options(may_unwind)); +} + +// CHECK-LABEL: @asm_with_result_may_unwind +#[no_mangle] +pub unsafe fn asm_with_result_may_unwind() -> u64 { + let _m = Foo; + let res: u64; + // CHECK: [[RES:%[0-9]+]] = invoke i64 asm sideeffect alignstack inteldialect unwind + // CHECK-NEXT: to label %[[NORMALBB:[a-b0-9]+]] + asm!("mov {}, 1", out(reg) res, options(may_unwind)); + // CHECK: [[NORMALBB]]: + // CHECK: ret i64 [[RES:%[0-9]+]] + res +} diff --git a/tests/codegen-llvm/asm/maybe-uninit.rs b/tests/codegen-llvm/asm/maybe-uninit.rs new file mode 100644 index 00000000000..d76d5cb1312 --- /dev/null +++ b/tests/codegen-llvm/asm/maybe-uninit.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 + +#![crate_type = "rlib"] +#![allow(asm_sub_register)] + +use std::arch::asm; +use std::mem::MaybeUninit; + +// CHECK-LABEL: @int +#[no_mangle] +pub unsafe fn int(x: MaybeUninit) -> MaybeUninit { + let y: MaybeUninit; + asm!("/*{}{}*/", in(reg) x, out(reg) y); + y +} + +// CHECK-LABEL: @inout +#[no_mangle] +pub unsafe fn inout(mut x: i32) -> MaybeUninit { + let mut y: MaybeUninit; + asm!("/*{}*/", inout(reg) x => y); + asm!("/*{}*/", inout(reg) y => x); + asm!("/*{}*/", inlateout(reg) x => y); + asm!("/*{}*/", inlateout(reg) y => x); + y +} diff --git a/tests/codegen-llvm/asm/msp430-clobbers.rs b/tests/codegen-llvm/asm/msp430-clobbers.rs new file mode 100644 index 00000000000..2c8d29cffc4 --- /dev/null +++ b/tests/codegen-llvm/asm/msp430-clobbers.rs @@ -0,0 +1,32 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ compile-flags: --target msp430-none-elf +//@ needs-llvm-components: msp430 + +#![crate_type = "rlib"] +#![feature(no_core, asm_experimental_arch)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: @sr_clobber +// CHECK: call void asm sideeffect "", "~{sr}"() +#[no_mangle] +pub unsafe fn sr_clobber() { + asm!("", options(nostack, nomem)); +} + +// CHECK-LABEL: @no_clobber +// CHECK: call void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn no_clobber() { + asm!("", options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @clobber_abi +// CHECK: asm sideeffect "", "={r11},={r12},={r13},={r14},={r15}"() +#[no_mangle] +pub unsafe fn clobber_abi() { + asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); +} diff --git a/tests/codegen-llvm/asm/multiple-options.rs b/tests/codegen-llvm/asm/multiple-options.rs new file mode 100644 index 00000000000..4d87471a193 --- /dev/null +++ b/tests/codegen-llvm/asm/multiple-options.rs @@ -0,0 +1,54 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 + +#![crate_type = "rlib"] + +use std::arch::asm; + +// CHECK-LABEL: @pure +// CHECK-NOT: asm +// CHECK: ret void +#[no_mangle] +pub unsafe fn pure(x: i32) { + let y: i32; + asm!("", out("ax") y, in("cx") x, options(pure), options(nomem)); +} + +pub static mut VAR: i32 = 0; +pub static mut DUMMY_OUTPUT: i32 = 0; + +// CHECK-LABEL: @readonly +// CHECK: call i32 asm +// CHECK: ret i32 1 +#[no_mangle] +pub unsafe fn readonly() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly)); + VAR +} + +// CHECK-LABEL: @nomem +// CHECK-NOT: store +// CHECK: call i32 asm +// CHECK: store +// CHECK: ret i32 2 +#[no_mangle] +pub unsafe fn nomem() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(nomem)); + VAR = 2; + VAR +} + +// CHECK-LABEL: @not_nomem +// CHECK: store +// CHECK: call i32 asm +// CHECK: store +// CHECK: ret i32 2 +#[no_mangle] +pub unsafe fn not_nomem() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly)); + VAR = 2; + VAR +} diff --git a/tests/codegen-llvm/asm/options.rs b/tests/codegen-llvm/asm/options.rs new file mode 100644 index 00000000000..c087f91fd43 --- /dev/null +++ b/tests/codegen-llvm/asm/options.rs @@ -0,0 +1,104 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 + +#![crate_type = "rlib"] + +use std::arch::asm; + +// CHECK-LABEL: @pure +// CHECK-NOT: asm +// CHECK: ret void +#[no_mangle] +pub unsafe fn pure(x: i32) { + let y: i32; + asm!("", out("ax") y, in("cx") x, options(pure, nomem)); +} + +// CHECK-LABEL: @noreturn +// CHECK: call void asm +// CHECK-NEXT: unreachable +#[no_mangle] +pub unsafe fn noreturn() { + asm!("", options(noreturn)); +} + +pub static mut VAR: i32 = 0; +pub static mut DUMMY_OUTPUT: i32 = 0; + +// CHECK-LABEL: @readonly +// CHECK: call i32 asm +// CHECK: ret i32 1 +#[no_mangle] +pub unsafe fn readonly() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(pure, readonly)); + VAR +} + +// CHECK-LABEL: @not_readonly +// CHECK: call i32 asm +// CHECK: ret i32 % +#[no_mangle] +pub unsafe fn not_readonly() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options()); + VAR +} + +// CHECK-LABEL: @nomem +// CHECK-NOT: store +// CHECK: call i32 asm +// CHECK: store +// CHECK: ret i32 2 +#[no_mangle] +pub unsafe fn nomem() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(pure, nomem)); + VAR = 2; + VAR +} + +// CHECK-LABEL: @nomem_nopure +// CHECK-NOT: store +// CHECK: call i32 asm +// CHECK: store +// CHECK: ret i32 2 +#[no_mangle] +pub unsafe fn nomem_nopure() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(nomem)); + VAR = 2; + VAR +} + +// CHECK-LABEL: @not_nomem +// CHECK: store +// CHECK: call i32 asm +// CHECK: store +// CHECK: ret i32 2 +#[no_mangle] +pub unsafe fn not_nomem() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(pure, readonly)); + VAR = 2; + VAR +} + +// CHECK-LABEL: @dont_remove_nonpure +// CHECK: call void asm +// CHECK: call void asm +// CHECK: call void asm +// CHECK: ret void +#[no_mangle] +pub unsafe fn dont_remove_nonpure() { + asm!("", options()); + asm!("", options(nomem)); + asm!("", options(readonly)); +} + +// CHECK-LABEL: @raw +// CHECK: call void asm sideeffect inteldialect "{} {}", ""() +#[no_mangle] +pub unsafe fn raw() { + asm!("{} {}", options(nostack, nomem, preserves_flags, raw)); +} diff --git a/tests/codegen-llvm/asm/powerpc-clobbers.rs b/tests/codegen-llvm/asm/powerpc-clobbers.rs new file mode 100644 index 00000000000..f7fc7eea5d5 --- /dev/null +++ b/tests/codegen-llvm/asm/powerpc-clobbers.rs @@ -0,0 +1,68 @@ +//@ add-core-stubs +//@ revisions: powerpc powerpc64 powerpc64le aix64 +//@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu +//@[powerpc] needs-llvm-components: powerpc +//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu +//@[powerpc64] needs-llvm-components: powerpc +//@[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu +//@[powerpc64le] needs-llvm-components: powerpc +//@[aix64] compile-flags: --target powerpc64-ibm-aix +//@[aix64] needs-llvm-components: powerpc +// ignore-tidy-linelength + +#![crate_type = "rlib"] +#![feature(no_core, asm_experimental_arch)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: @cr_clobber +// CHECK: call void asm sideeffect "", "~{cr}"() +#[no_mangle] +pub unsafe fn cr_clobber() { + asm!("", out("cr") _, options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @cr0_clobber +// CHECK: call void asm sideeffect "", "~{cr0}"() +#[no_mangle] +pub unsafe fn cr0_clobber() { + asm!("", out("cr0") _, options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @cr5_clobber +// CHECK: call void asm sideeffect "", "~{cr5}"() +#[no_mangle] +pub unsafe fn cr5_clobber() { + asm!("", out("cr5") _, options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @xer_clobber +// CHECK: call void asm sideeffect "", "~{xer}"() +#[no_mangle] +pub unsafe fn xer_clobber() { + asm!("", out("xer") _, options(nostack, nomem, preserves_flags)); +} + +// Output format depends on the availability of altivec. +// CHECK-LABEL: @v0_clobber +// powerpc: call void asm sideeffect "", "~{v0}"() +// powerpc64: call <4 x i32> asm sideeffect "", "=&{v0}"() +// powerpc64le: call <4 x i32> asm sideeffect "", "=&{v0}"() +// aix64: call <4 x i32> asm sideeffect "", "=&{v0}"() +#[no_mangle] +pub unsafe fn v0_clobber() { + asm!("", out("v0") _, options(nostack, nomem, preserves_flags)); +} + +// Output format depends on the availability of altivec. +// CHECK-LABEL: @clobber_abi +// powerpc: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"() +// powerpc64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"() +// powerpc64le: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"() +// aix64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"() +#[no_mangle] +pub unsafe fn clobber_abi() { + asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); +} diff --git a/tests/codegen-llvm/asm/riscv-clobbers.rs b/tests/codegen-llvm/asm/riscv-clobbers.rs new file mode 100644 index 00000000000..e55b6731098 --- /dev/null +++ b/tests/codegen-llvm/asm/riscv-clobbers.rs @@ -0,0 +1,40 @@ +//@ add-core-stubs +//@ assembly-output: emit-asm +//@ revisions: rv32i rv64i rv32e +//@[rv32i] compile-flags: --target riscv32i-unknown-none-elf +//@[rv32i] needs-llvm-components: riscv +//@[rv64i] compile-flags: --target riscv64imac-unknown-none-elf +//@[rv64i] needs-llvm-components: riscv +//@[rv32e] compile-flags: --target riscv32e-unknown-none-elf +//@[rv32e] needs-llvm-components: riscv +// ignore-tidy-linelength + +#![crate_type = "rlib"] +#![feature(no_core)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: @flags_clobber +// CHECK: call void asm sideeffect "", "~{vtype},~{vl},~{vxsat},~{vxrm}"() +#[no_mangle] +pub unsafe fn flags_clobber() { + asm!("", options(nostack, nomem)); +} + +// CHECK-LABEL: @no_clobber +// CHECK: call void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn no_clobber() { + asm!("", options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @clobber_abi +// rv32i: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},={x16},={x17},={x28},={x29},={x30},={x31},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"() +// rv64i: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},={x16},={x17},={x28},={x29},={x30},={x31},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"() +// rv32e: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"() +#[no_mangle] +pub unsafe fn clobber_abi() { + asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); +} diff --git a/tests/codegen-llvm/asm/s390x-clobbers.rs b/tests/codegen-llvm/asm/s390x-clobbers.rs new file mode 100644 index 00000000000..0ba22a32abf --- /dev/null +++ b/tests/codegen-llvm/asm/s390x-clobbers.rs @@ -0,0 +1,46 @@ +//@ add-core-stubs +//@ revisions: s390x +//@[s390x] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z10 +//@[s390x] needs-llvm-components: systemz + +#![crate_type = "rlib"] +#![feature(no_core)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: @cc_clobber +// CHECK: call void asm sideeffect "", "~{cc}"() +#[no_mangle] +pub unsafe fn cc_clobber() { + asm!("", options(nostack, nomem)); +} + +// CHECK-LABEL: @no_clobber +// CHECK: call void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn no_clobber() { + asm!("", options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @a2_clobber +// CHECK: call void asm sideeffect "", "~{a2}"() +#[no_mangle] +pub unsafe fn a2_clobber() { + asm!("", out("a2") _, options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @v0_clobber +// CHECK: call void asm sideeffect "", "~{v0}"() +#[no_mangle] +pub unsafe fn v0_clobber() { + asm!("", out("v0") _, options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @clobber_abi +// CHECK: asm sideeffect "", "={r0},={r1},={r2},={r3},={r4},={r5},={r14},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31},~{a2},~{a3},~{a4},~{a5},~{a6},~{a7},~{a8},~{a9},~{a10},~{a11},~{a12},~{a13},~{a14},~{a15}"() +#[no_mangle] +pub unsafe fn clobber_abi() { + asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); +} diff --git a/tests/codegen-llvm/asm/sanitize-llvm.rs b/tests/codegen-llvm/asm/sanitize-llvm.rs new file mode 100644 index 00000000000..97a77033284 --- /dev/null +++ b/tests/codegen-llvm/asm/sanitize-llvm.rs @@ -0,0 +1,24 @@ +//@ add-core-stubs +// FIXME(nagisa): remove the flags below once all targets support `asm!`. +//@ compile-flags: --target x86_64-unknown-linux-gnu -Copt-level=0 +//@ needs-llvm-components: x86 + +// Verify we sanitize the special tokens for the LLVM inline-assembly, ensuring people won't +// inadvertently rely on the LLVM-specific syntax and features. +#![no_core] +#![feature(no_core)] +#![crate_type = "rlib"] +#![allow(named_asm_labels)] + +extern crate minicore; +use minicore::*; + +pub unsafe fn we_escape_dollar_signs() { + // CHECK: call void asm sideeffect alignstack inteldialect "banana$$:" + asm!(r"banana$:",) +} + +pub unsafe fn we_escape_escapes_too() { + // CHECK: call void asm sideeffect alignstack inteldialect "banana\{{(\\|5C)}}36:" + asm!(r"banana\36:",) +} diff --git a/tests/codegen-llvm/asm/sparc-clobbers.rs b/tests/codegen-llvm/asm/sparc-clobbers.rs new file mode 100644 index 00000000000..a71715ed94d --- /dev/null +++ b/tests/codegen-llvm/asm/sparc-clobbers.rs @@ -0,0 +1,36 @@ +//@ add-core-stubs +//@ revisions: sparc sparcv8plus sparc64 +//@[sparc] compile-flags: --target sparc-unknown-none-elf +//@[sparc] needs-llvm-components: sparc +//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu +//@[sparcv8plus] needs-llvm-components: sparc +//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparc64] needs-llvm-components: sparc + +#![crate_type = "rlib"] +#![feature(no_core, asm_experimental_arch)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: @cc_clobber +// CHECK: call void asm sideeffect "", "~{icc},~{fcc0},~{fcc1},~{fcc2},~{fcc3}"() +#[no_mangle] +pub unsafe fn cc_clobber() { + asm!("", options(nostack, nomem)); +} + +// CHECK-LABEL: @no_clobber +// CHECK: call void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn no_clobber() { + asm!("", options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @y_clobber +// CHECK: call void asm sideeffect "", "~{y}"() +#[no_mangle] +pub unsafe fn y_clobber() { + asm!("", out("y") _, options(nostack, nomem, preserves_flags)); +} diff --git a/tests/codegen-llvm/asm/x86-clobber_abi.rs b/tests/codegen-llvm/asm/x86-clobber_abi.rs new file mode 100644 index 00000000000..5b34b4e8ef3 --- /dev/null +++ b/tests/codegen-llvm/asm/x86-clobber_abi.rs @@ -0,0 +1,36 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 + +#![crate_type = "rlib"] + +use std::arch::asm; + +// CHECK-LABEL: @clobber_sysv64 +// CHECK: ={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory} +#[no_mangle] +pub unsafe fn clobber_sysv64() { + asm!("", clobber_abi("sysv64")); +} + +// CHECK-LABEL: @clobber_win64 +// CHECK: ={ax},={cx},={dx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory} +#[no_mangle] +pub unsafe fn clobber_win64() { + asm!("", clobber_abi("win64")); +} + +// CHECK-LABEL: @clobber_sysv64 +// CHECK: =&{dx},={ax},={cx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory} +#[no_mangle] +pub unsafe fn clobber_sysv64_edx() { + let foo: i32; + asm!("", out("edx") foo, clobber_abi("sysv64")); +} + +// CHECK-LABEL: @clobber_win64 +// CHECK: =&{dx},={ax},={cx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory} +#[no_mangle] +pub unsafe fn clobber_win64_edx() { + let foo: i32; + asm!("", out("edx") foo, clobber_abi("win64")); +} diff --git a/tests/codegen-llvm/asm/x86-clobbers.rs b/tests/codegen-llvm/asm/x86-clobbers.rs new file mode 100644 index 00000000000..50163b646b2 --- /dev/null +++ b/tests/codegen-llvm/asm/x86-clobbers.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 + +#![crate_type = "rlib"] + +use std::arch::asm; + +// CHECK-LABEL: @x87_clobber +// CHECK: ~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)} +#[no_mangle] +pub unsafe fn x87_clobber() { + asm!("foo", out("st") _); +} + +// CHECK-LABEL: @mmx_clobber +// CHECK: ~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)} +#[no_mangle] +pub unsafe fn mmx_clobber() { + asm!("bar", out("mm0") _, out("mm1") _); +} diff --git a/tests/codegen-llvm/asm/x86-target-clobbers.rs b/tests/codegen-llvm/asm/x86-target-clobbers.rs new file mode 100644 index 00000000000..119372491ff --- /dev/null +++ b/tests/codegen-llvm/asm/x86-target-clobbers.rs @@ -0,0 +1,29 @@ +//@ only-x86_64 +//@ revisions: base avx512 +//@ [avx512]compile-flags: -C target-feature=+avx512f + +#![crate_type = "rlib"] + +use std::arch::asm; + +// CHECK-LABEL: @amx_clobber +// base: call void asm sideeffect inteldialect "", "~{tmm0}"() +#[no_mangle] +pub unsafe fn amx_clobber() { + asm!("", out("tmm0") _, options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @avx512_clobber +// base: call void asm sideeffect inteldialect "", "~{xmm31}"() +// avx512: call float asm sideeffect inteldialect "", "=&{xmm31}"() +#[no_mangle] +pub unsafe fn avx512_clobber() { + asm!("", out("zmm31") _, options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @eax_clobber +// CHECK: call i32 asm sideeffect inteldialect "", "=&{ax}"() +#[no_mangle] +pub unsafe fn eax_clobber() { + asm!("", out("eax") _, options(nostack, nomem, preserves_flags)); +} diff --git a/tests/codegen-llvm/assign-desugar-debuginfo.rs b/tests/codegen-llvm/assign-desugar-debuginfo.rs new file mode 100644 index 00000000000..77ee8758b3b --- /dev/null +++ b/tests/codegen-llvm/assign-desugar-debuginfo.rs @@ -0,0 +1,18 @@ +//@ compile-flags: -g -Zmir-opt-level=0 + +#![crate_type = "lib"] + +#[inline(never)] +fn swizzle(a: u32, b: u32, c: u32) -> (u32, (u32, u32)) { + (b, (c, a)) +} + +pub fn work() { + let mut a = 1; + let mut b = 2; + let mut c = 3; + (a, (b, c)) = swizzle(a, b, c); + println!("{a} {b} {c}"); +} + +// CHECK-NOT: !DILocalVariable(name: "lhs", diff --git a/tests/codegen-llvm/async-closure-debug.rs b/tests/codegen-llvm/async-closure-debug.rs new file mode 100644 index 00000000000..b5b369e6e54 --- /dev/null +++ b/tests/codegen-llvm/async-closure-debug.rs @@ -0,0 +1,20 @@ +// Just make sure that async closures don't ICE. +// +//@ compile-flags: -C debuginfo=2 +//@ edition: 2018 +//@ ignore-msvc + +// CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "async_closure_test" +// CHECK-DAG: [[CLOSURE:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: [[GEN_FN]] +// CHECK-DAG: [[UPVAR:!.*]] = !DIDerivedType(tag: DW_TAG_member, name: "upvar", scope: [[CLOSURE]] + +fn async_closure_test(upvar: &str) -> impl AsyncFn() + '_ { + async move || { + let hello = String::from("hello"); + println!("{hello}, {upvar}"); + } +} + +fn main() { + let _async_closure = async_closure_test("world"); +} diff --git a/tests/codegen-llvm/async-fn-debug-awaitee-field.rs b/tests/codegen-llvm/async-fn-debug-awaitee-field.rs new file mode 100644 index 00000000000..50860c90662 --- /dev/null +++ b/tests/codegen-llvm/async-fn-debug-awaitee-field.rs @@ -0,0 +1,28 @@ +// ignore-tidy-linelength +//! This test makes sure that the coroutine field capturing the awaitee in a `.await` expression +//! is called `__awaitee` in debuginfo. This name must not be changed since debuggers and debugger +//! extensions rely on the field having this name. + +//@ revisions: MSVC NONMSVC +//@[MSVC] only-msvc +//@[NONMSVC] ignore-msvc + +//@ compile-flags: -C debuginfo=2 -Copt-level=0 +//@ edition: 2018 + +#![crate_type = "lib"] + +pub async fn async_fn_test() { + foo().await; +} + +pub async fn foo() {} + +// NONMSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[GEN_SCOPE:![0-9]*]], +// MSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$", +// NONMSVC: [[GEN_SCOPE:!.*]] = !DINamespace(name: "async_fn_test", +// CHECK: [[SUSPEND_STRUCT:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend0", scope: [[GEN]], +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__awaitee", scope: [[SUSPEND_STRUCT]], {{.*}}, baseType: [[AWAITEE_TYPE:![0-9]*]], +// NONMSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[AWAITEE_SCOPE:![0-9]*]], +// MSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$", +// NONMSVC: [[AWAITEE_SCOPE]] = !DINamespace(name: "foo", diff --git a/tests/codegen-llvm/async-fn-debug-msvc.rs b/tests/codegen-llvm/async-fn-debug-msvc.rs new file mode 100644 index 00000000000..e0c601146f8 --- /dev/null +++ b/tests/codegen-llvm/async-fn-debug-msvc.rs @@ -0,0 +1,55 @@ +// Verify debuginfo for coroutines: +// - Each variant points to the file and line of its yield point +// - The discriminants are marked artificial +// - Other fields are not marked artificial +// +// +//@ compile-flags: -C debuginfo=2 +//@ edition: 2018 +//@ only-msvc + +async fn foo() {} +async fn async_fn_test() { + foo().await; + let s = String::from("foo"); + foo().await; +} + +// FIXME: No way to reliably check the filename. + +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$", +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]], +// For brevity, we only check the struct name and members of the last variant. +// CHECK-SAME: file: [[FILE:![0-9]*]], line: 12, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 16, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 16, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 13, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 15, +// CHECK-SAME: baseType: [[VARIANT_WRAPPER:![0-9]*]] +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: [[VARIANT_WRAPPER]], file: !2, baseType: [[VARIANT:![0-9]*]], +// CHECK: [[VARIANT]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[VARIANT]] +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "tag", scope: [[GEN]], +// CHECK-NOT: flags: DIFlagArtificial + +fn main() { + let _dummy = async_fn_test(); +} diff --git a/tests/codegen-llvm/async-fn-debug.rs b/tests/codegen-llvm/async-fn-debug.rs new file mode 100644 index 00000000000..ed704c7cc8b --- /dev/null +++ b/tests/codegen-llvm/async-fn-debug.rs @@ -0,0 +1,59 @@ +// Verify debuginfo for async fn: +// - Each variant points to the file and line of its yield point +// - The discriminants are marked artificial +// - Other fields are not marked artificial +// +// +//@ compile-flags: -C debuginfo=2 +//@ edition: 2018 +//@ ignore-msvc + +async fn foo() {} +async fn async_fn_test() { + foo().await; + let s = String::from("foo"); + foo().await; +} + +// FIXME: No way to reliably check the filename. + +// CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test" +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[ASYNC_FN]] +// CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[GEN]], +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: discriminator: [[DISC:![0-9]*]] +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE:![0-9]*]], line: 12, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]], +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 16, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 16, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 13, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 15, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: [[DISC]] = !DIDerivedType(tag: DW_TAG_member, name: "__state", scope: [[GEN]], +// CHECK-SAME: flags: DIFlagArtificial + +fn main() { + let _dummy = async_fn_test(); +} diff --git a/tests/codegen-llvm/atomic-operations.rs b/tests/codegen-llvm/atomic-operations.rs new file mode 100644 index 00000000000..8771b8b2419 --- /dev/null +++ b/tests/codegen-llvm/atomic-operations.rs @@ -0,0 +1,84 @@ +// Code generation of atomic operations. +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +use std::sync::atomic::AtomicI32; +use std::sync::atomic::Ordering::*; + +// CHECK-LABEL: @compare_exchange +#[no_mangle] +pub fn compare_exchange(a: &AtomicI32) { + // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 10 monotonic monotonic + // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 11 monotonic acquire + // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 12 monotonic seq_cst + let _ = a.compare_exchange(0, 10, Relaxed, Relaxed); + let _ = a.compare_exchange(0, 11, Relaxed, Acquire); + let _ = a.compare_exchange(0, 12, Relaxed, SeqCst); + + // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 20 release monotonic + // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 21 release acquire + // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 22 release seq_cst + let _ = a.compare_exchange(0, 20, Release, Relaxed); + let _ = a.compare_exchange(0, 21, Release, Acquire); + let _ = a.compare_exchange(0, 22, Release, SeqCst); + + // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 30 acquire monotonic + // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 31 acquire acquire + // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 32 acquire seq_cst + let _ = a.compare_exchange(0, 30, Acquire, Relaxed); + let _ = a.compare_exchange(0, 31, Acquire, Acquire); + let _ = a.compare_exchange(0, 32, Acquire, SeqCst); + + // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 40 acq_rel monotonic + // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 41 acq_rel acquire + // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 42 acq_rel seq_cst + let _ = a.compare_exchange(0, 40, AcqRel, Relaxed); + let _ = a.compare_exchange(0, 41, AcqRel, Acquire); + let _ = a.compare_exchange(0, 42, AcqRel, SeqCst); + + // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 50 seq_cst monotonic + // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 51 seq_cst acquire + // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 52 seq_cst seq_cst + let _ = a.compare_exchange(0, 50, SeqCst, Relaxed); + let _ = a.compare_exchange(0, 51, SeqCst, Acquire); + let _ = a.compare_exchange(0, 52, SeqCst, SeqCst); +} + +// CHECK-LABEL: @compare_exchange_weak +#[no_mangle] +pub fn compare_exchange_weak(w: &AtomicI32) { + // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 10 monotonic monotonic + // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 11 monotonic acquire + // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 12 monotonic seq_cst + let _ = w.compare_exchange_weak(1, 10, Relaxed, Relaxed); + let _ = w.compare_exchange_weak(1, 11, Relaxed, Acquire); + let _ = w.compare_exchange_weak(1, 12, Relaxed, SeqCst); + + // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 20 release monotonic + // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 21 release acquire + // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 22 release seq_cst + let _ = w.compare_exchange_weak(1, 20, Release, Relaxed); + let _ = w.compare_exchange_weak(1, 21, Release, Acquire); + let _ = w.compare_exchange_weak(1, 22, Release, SeqCst); + + // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 30 acquire monotonic + // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 31 acquire acquire + // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 32 acquire seq_cst + let _ = w.compare_exchange_weak(1, 30, Acquire, Relaxed); + let _ = w.compare_exchange_weak(1, 31, Acquire, Acquire); + let _ = w.compare_exchange_weak(1, 32, Acquire, SeqCst); + + // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 40 acq_rel monotonic + // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 41 acq_rel acquire + // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 42 acq_rel seq_cst + let _ = w.compare_exchange_weak(1, 40, AcqRel, Relaxed); + let _ = w.compare_exchange_weak(1, 41, AcqRel, Acquire); + let _ = w.compare_exchange_weak(1, 42, AcqRel, SeqCst); + + // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 50 seq_cst monotonic + // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 51 seq_cst acquire + // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 52 seq_cst seq_cst + let _ = w.compare_exchange_weak(1, 50, SeqCst, Relaxed); + let _ = w.compare_exchange_weak(1, 51, SeqCst, Acquire); + let _ = w.compare_exchange_weak(1, 52, SeqCst, SeqCst); +} diff --git a/tests/codegen-llvm/atomicptr.rs b/tests/codegen-llvm/atomicptr.rs new file mode 100644 index 00000000000..4819af40ca2 --- /dev/null +++ b/tests/codegen-llvm/atomicptr.rs @@ -0,0 +1,36 @@ +// LLVM does not support some atomic RMW operations on pointers, so inside codegen we lower those +// to integer atomics, surrounded by casts to and from integer type. +// This test ensures that we do the round-trip correctly for AtomicPtr::fetch_byte_add, and also +// ensures that we do not have such a round-trip for AtomicPtr::swap, because LLVM supports pointer +// arguments to `atomicrmw xchg`. + +//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes +#![crate_type = "lib"] +#![feature(strict_provenance_atomic_ptr)] + +use std::ptr::without_provenance_mut; +use std::sync::atomic::AtomicPtr; +use std::sync::atomic::Ordering::Relaxed; + +// Portability hack so that we can say [[USIZE]] instead of i64/i32/i16 for usize. +// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1) +#[no_mangle] +pub fn helper(_: usize) {} + +// CHECK-LABEL: @atomicptr_fetch_byte_add +#[no_mangle] +pub fn atomicptr_fetch_byte_add(a: &AtomicPtr, v: usize) -> *mut u8 { + // CHECK: %[[INTPTR:.*]] = ptrtoint ptr %{{.*}} to [[USIZE]] + // CHECK-NEXT: %[[RET:.*]] = atomicrmw add ptr %{{.*}}, [[USIZE]] %[[INTPTR]] + // CHECK-NEXT: inttoptr [[USIZE]] %[[RET]] to ptr + a.fetch_byte_add(v, Relaxed) +} + +// CHECK-LABEL: @atomicptr_swap +#[no_mangle] +pub fn atomicptr_swap(a: &AtomicPtr, ptr: *mut u8) -> *mut u8 { + // CHECK-NOT: ptrtoint + // CHECK: atomicrmw xchg ptr %{{.*}}, ptr %{{.*}} monotonic + // CHECK-NOT: inttoptr + a.swap(ptr, Relaxed) +} diff --git a/tests/codegen-llvm/autodiff/batched.rs b/tests/codegen-llvm/autodiff/batched.rs new file mode 100644 index 00000000000..d27aed50e6c --- /dev/null +++ b/tests/codegen-llvm/autodiff/batched.rs @@ -0,0 +1,116 @@ +//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme +// +// In Enzyme, we test against a large range of LLVM versions (5+) and don't have overly many +// breakages. One benefit is that we match the IR generated by Enzyme only after running it +// through LLVM's O3 pipeline, which will remove most of the noise. +// However, our integration test could also be affected by changes in how rustc lowers MIR into +// LLVM-IR, which could cause additional noise and thus breakages. If that's the case, we should +// reduce this test to only match the first lines and the ret instructions. + +#![feature(autodiff)] + +use std::autodiff::autodiff_forward; + +#[autodiff_forward(d_square3, Dual, DualOnly)] +#[autodiff_forward(d_square2, 4, Dual, DualOnly)] +#[autodiff_forward(d_square1, 4, Dual, Dual)] +#[no_mangle] +fn square(x: &f32) -> f32 { + x * x +} + +// d_sqaure2 +// CHECK: define internal fastcc [4 x float] @fwddiffe4square(float %x.0.val, [4 x ptr] %"x'") +// CHECK-NEXT: start: +// CHECK-NEXT: %0 = extractvalue [4 x ptr] %"x'", 0 +// CHECK-NEXT: %"_2'ipl" = load float, ptr %0, align 4 +// CHECK-NEXT: %1 = extractvalue [4 x ptr] %"x'", 1 +// CHECK-NEXT: %"_2'ipl1" = load float, ptr %1, align 4 +// CHECK-NEXT: %2 = extractvalue [4 x ptr] %"x'", 2 +// CHECK-NEXT: %"_2'ipl2" = load float, ptr %2, align 4 +// CHECK-NEXT: %3 = extractvalue [4 x ptr] %"x'", 3 +// CHECK-NEXT: %"_2'ipl3" = load float, ptr %3, align 4 +// CHECK-NEXT: %4 = insertelement <4 x float> poison, float %"_2'ipl", i64 0 +// CHECK-NEXT: %5 = insertelement <4 x float> %4, float %"_2'ipl1", i64 1 +// CHECK-NEXT: %6 = insertelement <4 x float> %5, float %"_2'ipl2", i64 2 +// CHECK-NEXT: %7 = insertelement <4 x float> %6, float %"_2'ipl3", i64 3 +// CHECK-NEXT: %8 = fadd fast <4 x float> %7, %7 +// CHECK-NEXT: %9 = insertelement <4 x float> poison, float %x.0.val, i64 0 +// CHECK-NEXT: %10 = shufflevector <4 x float> %9, <4 x float> poison, <4 x i32> zeroinitializer +// CHECK-NEXT: %11 = fmul fast <4 x float> %8, %10 +// CHECK-NEXT: %12 = extractelement <4 x float> %11, i64 0 +// CHECK-NEXT: %13 = insertvalue [4 x float] undef, float %12, 0 +// CHECK-NEXT: %14 = extractelement <4 x float> %11, i64 1 +// CHECK-NEXT: %15 = insertvalue [4 x float] %13, float %14, 1 +// CHECK-NEXT: %16 = extractelement <4 x float> %11, i64 2 +// CHECK-NEXT: %17 = insertvalue [4 x float] %15, float %16, 2 +// CHECK-NEXT: %18 = extractelement <4 x float> %11, i64 3 +// CHECK-NEXT: %19 = insertvalue [4 x float] %17, float %18, 3 +// CHECK-NEXT: ret [4 x float] %19 +// CHECK-NEXT: } + +// d_square3, the extra float is the original return value (x * x) +// CHECK: define internal fastcc { float, [4 x float] } @fwddiffe4square.1(float %x.0.val, [4 x ptr] %"x'") +// CHECK-NEXT: start: +// CHECK-NEXT: %0 = extractvalue [4 x ptr] %"x'", 0 +// CHECK-NEXT: %"_2'ipl" = load float, ptr %0, align 4 +// CHECK-NEXT: %1 = extractvalue [4 x ptr] %"x'", 1 +// CHECK-NEXT: %"_2'ipl1" = load float, ptr %1, align 4 +// CHECK-NEXT: %2 = extractvalue [4 x ptr] %"x'", 2 +// CHECK-NEXT: %"_2'ipl2" = load float, ptr %2, align 4 +// CHECK-NEXT: %3 = extractvalue [4 x ptr] %"x'", 3 +// CHECK-NEXT: %"_2'ipl3" = load float, ptr %3, align 4 +// CHECK-NEXT: %_0 = fmul float %x.0.val, %x.0.val +// CHECK-NEXT: %4 = insertelement <4 x float> poison, float %"_2'ipl", i64 0 +// CHECK-NEXT: %5 = insertelement <4 x float> %4, float %"_2'ipl1", i64 1 +// CHECK-NEXT: %6 = insertelement <4 x float> %5, float %"_2'ipl2", i64 2 +// CHECK-NEXT: %7 = insertelement <4 x float> %6, float %"_2'ipl3", i64 3 +// CHECK-NEXT: %8 = fadd fast <4 x float> %7, %7 +// CHECK-NEXT: %9 = insertelement <4 x float> poison, float %x.0.val, i64 0 +// CHECK-NEXT: %10 = shufflevector <4 x float> %9, <4 x float> poison, <4 x i32> zeroinitializer +// CHECK-NEXT: %11 = fmul fast <4 x float> %8, %10 +// CHECK-NEXT: %12 = extractelement <4 x float> %11, i64 0 +// CHECK-NEXT: %13 = insertvalue [4 x float] undef, float %12, 0 +// CHECK-NEXT: %14 = extractelement <4 x float> %11, i64 1 +// CHECK-NEXT: %15 = insertvalue [4 x float] %13, float %14, 1 +// CHECK-NEXT: %16 = extractelement <4 x float> %11, i64 2 +// CHECK-NEXT: %17 = insertvalue [4 x float] %15, float %16, 2 +// CHECK-NEXT: %18 = extractelement <4 x float> %11, i64 3 +// CHECK-NEXT: %19 = insertvalue [4 x float] %17, float %18, 3 +// CHECK-NEXT: %20 = insertvalue { float, [4 x float] } undef, float %_0, 0 +// CHECK-NEXT: %21 = insertvalue { float, [4 x float] } %20, [4 x float] %19, 1 +// CHECK-NEXT: ret { float, [4 x float] } %21 +// CHECK-NEXT: } + +fn main() { + let x = std::hint::black_box(3.0); + let output = square(&x); + dbg!(&output); + assert_eq!(9.0, output); + dbg!(square(&x)); + + let mut df_dx1 = 1.0; + let mut df_dx2 = 2.0; + let mut df_dx3 = 3.0; + let mut df_dx4 = 0.0; + let [o1, o2, o3, o4] = d_square2(&x, &mut df_dx1, &mut df_dx2, &mut df_dx3, &mut df_dx4); + dbg!(o1, o2, o3, o4); + let [output2, o1, o2, o3, o4] = + d_square1(&x, &mut df_dx1, &mut df_dx2, &mut df_dx3, &mut df_dx4); + dbg!(o1, o2, o3, o4); + assert_eq!(output, output2); + assert!((6.0 - o1).abs() < 1e-10); + assert!((12.0 - o2).abs() < 1e-10); + assert!((18.0 - o3).abs() < 1e-10); + assert!((0.0 - o4).abs() < 1e-10); + assert_eq!(1.0, df_dx1); + assert_eq!(2.0, df_dx2); + assert_eq!(3.0, df_dx3); + assert_eq!(0.0, df_dx4); + assert_eq!(d_square3(&x, &mut df_dx1), 2.0 * o1); + assert_eq!(d_square3(&x, &mut df_dx2), 2.0 * o2); + assert_eq!(d_square3(&x, &mut df_dx3), 2.0 * o3); + assert_eq!(d_square3(&x, &mut df_dx4), 2.0 * o4); +} diff --git a/tests/codegen-llvm/autodiff/generic.rs b/tests/codegen-llvm/autodiff/generic.rs new file mode 100644 index 00000000000..2f674079be0 --- /dev/null +++ b/tests/codegen-llvm/autodiff/generic.rs @@ -0,0 +1,42 @@ +//@ compile-flags: -Zautodiff=Enable -Zautodiff=NoPostopt -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +fn square + Copy>(x: &T) -> T { + *x * *x +} + +// Ensure that `d_square::` code is generated even if `square::` was never called +// +// CHECK: ; generic::square +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define internal {{.*}} double +// CHECK-NEXT: start: +// CHECK-NOT: ret +// CHECK: fmul double + +// Ensure that `d_square::` code is generated +// +// CHECK: ; generic::square +// CHECK-NEXT: ; Function Attrs: {{.*}} +// CHECK-NEXT: define internal {{.*}} float +// CHECK-NEXT: start: +// CHECK-NOT: ret +// CHECK: fmul float + +fn main() { + let xf32: f32 = std::hint::black_box(3.0); + let xf64: f64 = std::hint::black_box(3.0); + + let outputf32 = square::(&xf32); + assert_eq!(9.0, outputf32); + + let mut df_dxf64: f64 = std::hint::black_box(0.0); + + let output_f64 = d_square::(&xf64, &mut df_dxf64, 1.0); + assert_eq!(6.0, df_dxf64); +} diff --git a/tests/codegen-llvm/autodiff/identical_fnc.rs b/tests/codegen-llvm/autodiff/identical_fnc.rs new file mode 100644 index 00000000000..1c25b3d09ab --- /dev/null +++ b/tests/codegen-llvm/autodiff/identical_fnc.rs @@ -0,0 +1,45 @@ +//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme +// +// Each autodiff invocation creates a new placeholder function, which we will replace on llvm-ir +// level. If a user tries to differentiate two identical functions within the same compilation unit, +// then LLVM might merge them in release mode before AD. In that case we can't rewrite one of the +// merged placeholder function anymore, and compilation would fail. We prevent this by disabling +// LLVM's merge_function pass before AD. Here we implicetely test that our solution keeps working. +// We also explicetly test that we keep running merge_function after AD, by checking for two +// identical function calls in the LLVM-IR, while having two different calls in the Rust code. +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +fn square(x: &f64) -> f64 { + x * x +} + +#[autodiff_reverse(d_square2, Duplicated, Active)] +fn square2(x: &f64) -> f64 { + x * x +} + +// CHECK:; identical_fnc::main +// CHECK-NEXT:; Function Attrs: +// CHECK-NEXT:define internal void @_ZN13identical_fnc4main17hf4dbc69c8d2f9130E() +// CHECK-NEXT:start: +// CHECK-NOT:br +// CHECK-NOT:ret +// CHECK:; call identical_fnc::d_square +// CHECK-NEXT: call fastcc void @_ZN13identical_fnc8d_square17h4c364207a2f8e06dE(double %x.val, ptr noalias noundef nonnull align 8 dereferenceable(8) %dx1) +// CHECK-NEXT:; call identical_fnc::d_square +// CHECK-NEXT: call fastcc void @_ZN13identical_fnc8d_square17h4c364207a2f8e06dE(double %x.val, ptr noalias noundef nonnull align 8 dereferenceable(8) %dx2) + +fn main() { + let x = std::hint::black_box(3.0); + let mut dx1 = std::hint::black_box(1.0); + let mut dx2 = std::hint::black_box(1.0); + let _ = d_square(&x, &mut dx1, 1.0); + let _ = d_square2(&x, &mut dx2, 1.0); + assert_eq!(dx1, 6.0); + assert_eq!(dx2, 6.0); +} diff --git a/tests/codegen-llvm/autodiff/inline.rs b/tests/codegen-llvm/autodiff/inline.rs new file mode 100644 index 00000000000..65bed170207 --- /dev/null +++ b/tests/codegen-llvm/autodiff/inline.rs @@ -0,0 +1,23 @@ +//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat -Zautodiff=NoPostopt +//@ no-prefer-dynamic +//@ needs-enzyme + +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +fn square(x: &f64) -> f64 { + x * x +} + +// CHECK: ; inline::d_square +// CHECK-NEXT: ; Function Attrs: alwaysinline +// CHECK-NOT: noinline +// CHECK-NEXT: define internal fastcc void @_ZN6inline8d_square17h021c74e92c259cdeE +fn main() { + let x = std::hint::black_box(3.0); + let mut dx1 = std::hint::black_box(1.0); + let _ = d_square(&x, &mut dx1, 1.0); + assert_eq!(dx1, 6.0); +} diff --git a/tests/codegen-llvm/autodiff/scalar.rs b/tests/codegen-llvm/autodiff/scalar.rs new file mode 100644 index 00000000000..096b4209e84 --- /dev/null +++ b/tests/codegen-llvm/autodiff/scalar.rs @@ -0,0 +1,33 @@ +//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn square(x: &f64) -> f64 { + x * x +} + +// CHECK:define internal fastcc double @diffesquare(double %x.0.val, ptr nocapture nonnull align 8 %"x'" +// CHECK-NEXT:invertstart: +// CHECK-NEXT: %_0 = fmul double %x.0.val, %x.0.val +// CHECK-NEXT: %0 = fadd fast double %x.0.val, %x.0.val +// CHECK-NEXT: %1 = load double, ptr %"x'", align 8 +// CHECK-NEXT: %2 = fadd fast double %1, %0 +// CHECK-NEXT: store double %2, ptr %"x'", align 8 +// CHECK-NEXT: ret double %_0 +// CHECK-NEXT:} + +fn main() { + let x = std::hint::black_box(3.0); + let output = square(&x); + assert_eq!(9.0, output); + + let mut df_dx = 0.0; + let output_ = d_square(&x, &mut df_dx, 1.0); + assert_eq!(output, output_); + assert_eq!(6.0, df_dx); +} diff --git a/tests/codegen-llvm/autodiff/sret.rs b/tests/codegen-llvm/autodiff/sret.rs new file mode 100644 index 00000000000..d2fa85e3e37 --- /dev/null +++ b/tests/codegen-llvm/autodiff/sret.rs @@ -0,0 +1,45 @@ +//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme + +// This test is almost identical to the scalar.rs one, +// but we intentionally add a few more floats. +// `df` would ret `{ f64, f32, f32 }`, but is lowered as an sret. +// We therefore use this test to verify some of our sret handling. + +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[no_mangle] +#[autodiff_reverse(df, Active, Active, Active)] +fn primal(x: f32, y: f32) -> f64 { + (x * x * y) as f64 +} + +// CHECK:define internal fastcc void @_ZN4sret2df17h93be4316dd8ea006E(ptr dead_on_unwind noalias nocapture noundef nonnull writable writeonly align 8 dereferenceable(16) initializes((0, 16)) %_0, float noundef %x, float noundef %y) +// CHECK-NEXT:start: +// CHECK-NEXT: %0 = tail call fastcc { double, float, float } @diffeprimal(float %x, float %y) +// CHECK-NEXT: %.elt = extractvalue { double, float, float } %0, 0 +// CHECK-NEXT: store double %.elt, ptr %_0, align 8 +// CHECK-NEXT: %_0.repack1 = getelementptr inbounds nuw i8, ptr %_0, i64 8 +// CHECK-NEXT: %.elt2 = extractvalue { double, float, float } %0, 1 +// CHECK-NEXT: store float %.elt2, ptr %_0.repack1, align 8 +// CHECK-NEXT: %_0.repack3 = getelementptr inbounds nuw i8, ptr %_0, i64 12 +// CHECK-NEXT: %.elt4 = extractvalue { double, float, float } %0, 2 +// CHECK-NEXT: store float %.elt4, ptr %_0.repack3, align 4 +// CHECK-NEXT: ret void +// CHECK-NEXT:} + +fn main() { + let x = std::hint::black_box(3.0); + let y = std::hint::black_box(2.5); + let scalar = std::hint::black_box(1.0); + let (r1, r2, r3) = df(x, y, scalar); + // 3*3*1.5 = 22.5 + assert_eq!(r1, 22.5); + // 2*x*y = 2*3*2.5 = 15.0 + assert_eq!(r2, 15.0); + // x*x*1 = 3*3 = 9 + assert_eq!(r3, 9.0); +} diff --git a/tests/codegen-llvm/autodiffv2.rs b/tests/codegen-llvm/autodiffv2.rs new file mode 100644 index 00000000000..a40d19d3be3 --- /dev/null +++ b/tests/codegen-llvm/autodiffv2.rs @@ -0,0 +1,113 @@ +//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme +// +// In Enzyme, we test against a large range of LLVM versions (5+) and don't have overly many +// breakages. One benefit is that we match the IR generated by Enzyme only after running it +// through LLVM's O3 pipeline, which will remove most of the noise. +// However, our integration test could also be affected by changes in how rustc lowers MIR into +// LLVM-IR, which could cause additional noise and thus breakages. If that's the case, we should +// reduce this test to only match the first lines and the ret instructions. +// +// The function tested here has 4 inputs and 5 outputs, so we could either call forward-mode +// autodiff 4 times, or reverse mode 5 times. Since a forward-mode call is usually faster than +// reverse mode, we prefer it here. This file also tests a new optimization (batch mode), which +// allows us to call forward-mode autodiff only once, and get all 5 outputs in a single call. +// +// We support 2 different batch modes. `d_square2` has the same interface as scalar forward-mode, +// but each shadow argument is `width` times larger (thus 16 and 20 elements here). +// `d_square3` instead takes `width` (4) shadow arguments, which are all the same size as the +// original function arguments. +// +// FIXME(autodiff): We currently can't test `d_square1` and `d_square3` in the same file, since they +// generate the same dummy functions which get merged by LLVM, breaking pieces of our pipeline which +// try to rewrite the dummy functions later. We should consider to change to pure declarations both +// in our frontend and in the llvm backend to avoid these issues. + +#![feature(autodiff)] + +use std::autodiff::autodiff; + +#[no_mangle] +//#[autodiff(d_square1, Forward, Dual, Dual)] +#[autodiff(d_square2, Forward, 4, Dualv, Dualv)] +#[autodiff(d_square3, Forward, 4, Dual, Dual)] +fn square(x: &[f32], y: &mut [f32]) { + assert!(x.len() >= 4); + assert!(y.len() >= 5); + y[0] = 4.3 * x[0] + 1.2 * x[1] + 3.4 * x[2] + 2.1 * x[3]; + y[1] = 2.3 * x[0] + 4.5 * x[1] + 1.7 * x[2] + 6.4 * x[3]; + y[2] = 1.1 * x[0] + 3.3 * x[1] + 2.5 * x[2] + 4.7 * x[3]; + y[3] = 5.2 * x[0] + 1.4 * x[1] + 2.6 * x[2] + 3.8 * x[3]; + y[4] = 1.0 * x[0] + 2.0 * x[1] + 3.0 * x[2] + 4.0 * x[3]; +} + +fn main() { + let x1 = std::hint::black_box(vec![0.0, 1.0, 2.0, 3.0]); + + let dx1 = std::hint::black_box(vec![1.0; 12]); + + let z1 = std::hint::black_box(vec![1.0, 0.0, 0.0, 0.0]); + let z2 = std::hint::black_box(vec![0.0, 1.0, 0.0, 0.0]); + let z3 = std::hint::black_box(vec![0.0, 0.0, 1.0, 0.0]); + let z4 = std::hint::black_box(vec![0.0, 0.0, 0.0, 1.0]); + + let z5 = std::hint::black_box(vec![ + 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, + ]); + + let mut y1 = std::hint::black_box(vec![0.0; 5]); + let mut y2 = std::hint::black_box(vec![0.0; 5]); + let mut y3 = std::hint::black_box(vec![0.0; 5]); + let mut y4 = std::hint::black_box(vec![0.0; 5]); + + let mut y5 = std::hint::black_box(vec![0.0; 5]); + + let mut y6 = std::hint::black_box(vec![0.0; 5]); + + let mut dy1_1 = std::hint::black_box(vec![0.0; 5]); + let mut dy1_2 = std::hint::black_box(vec![0.0; 5]); + let mut dy1_3 = std::hint::black_box(vec![0.0; 5]); + let mut dy1_4 = std::hint::black_box(vec![0.0; 5]); + + let mut dy2 = std::hint::black_box(vec![0.0; 20]); + + let mut dy3_1 = std::hint::black_box(vec![0.0; 5]); + let mut dy3_2 = std::hint::black_box(vec![0.0; 5]); + let mut dy3_3 = std::hint::black_box(vec![0.0; 5]); + let mut dy3_4 = std::hint::black_box(vec![0.0; 5]); + + // scalar. + //d_square1(&x1, &z1, &mut y1, &mut dy1_1); + //d_square1(&x1, &z2, &mut y2, &mut dy1_2); + //d_square1(&x1, &z3, &mut y3, &mut dy1_3); + //d_square1(&x1, &z4, &mut y4, &mut dy1_4); + + // assert y1 == y2 == y3 == y4 + //for i in 0..5 { + // assert_eq!(y1[i], y2[i]); + // assert_eq!(y1[i], y3[i]); + // assert_eq!(y1[i], y4[i]); + //} + + // batch mode A) + d_square2(&x1, &z5, &mut y5, &mut dy2); + + // assert y1 == y2 == y3 == y4 == y5 + //for i in 0..5 { + // assert_eq!(y1[i], y5[i]); + //} + + // batch mode B) + d_square3(&x1, &z1, &z2, &z3, &z4, &mut y6, &mut dy3_1, &mut dy3_2, &mut dy3_3, &mut dy3_4); + for i in 0..5 { + assert_eq!(y5[i], y6[i]); + } + + for i in 0..5 { + assert_eq!(dy2[0..5][i], dy3_1[i]); + assert_eq!(dy2[5..10][i], dy3_2[i]); + assert_eq!(dy2[10..15][i], dy3_3[i]); + assert_eq!(dy2[15..20][i], dy3_4[i]); + } +} diff --git a/tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt2.rs b/tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt2.rs new file mode 100644 index 00000000000..c354228acc5 --- /dev/null +++ b/tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt2.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -Copt-level=2 + +#![crate_type = "lib"] +#![no_std] + +// This test is paired with the arch-specific -opt3.rs test. + +// The code is from https://github.com/rust-lang/rust/issues/122805. +// Ensure we do not generate the shufflevector instruction +// to avoid complicating the code. + +// CHECK-LABEL: define{{.*}}void @convert( +// CHECK-NOT: shufflevector +#[no_mangle] +pub fn convert(value: [u16; 8]) -> [u8; 16] { + #[cfg(target_endian = "little")] + let bswap = u16::to_be; + #[cfg(target_endian = "big")] + let bswap = u16::to_le; + let addr16 = [ + bswap(value[0]), + bswap(value[1]), + bswap(value[2]), + bswap(value[3]), + bswap(value[4]), + bswap(value[5]), + bswap(value[6]), + bswap(value[7]), + ]; + unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) } +} diff --git a/tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt3.rs b/tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt3.rs new file mode 100644 index 00000000000..203d12005de --- /dev/null +++ b/tests/codegen-llvm/autovec/dont-shuffle-bswaps-opt3.rs @@ -0,0 +1,42 @@ +//@ revisions: AARCH64 X86_64 Z13 +//@ compile-flags: -Copt-level=3 +//@[AARCH64] only-aarch64 +//@[X86_64] only-x86_64 +//@[Z13] only-s390x +//@[Z13] compile-flags: -Ctarget-cpu=z13 + +#![crate_type = "lib"] +#![no_std] + +// This test is paired with the arch-neutral -opt2.rs test + +// The code is from https://github.com/rust-lang/rust/issues/122805. +// Ensure we do not generate the shufflevector instruction +// to avoid complicating the code. + +// CHECK-LABEL: define{{.*}}void @convert( +// CHECK-NOT: shufflevector + +// On higher opt levels, this should just be a bswap: +// CHECK: load <8 x i16> +// CHECK-NEXT: call <8 x i16> @llvm.bswap +// CHECK-NEXT: store <8 x i16> +// CHECK-NEXT: ret void +#[no_mangle] +pub fn convert(value: [u16; 8]) -> [u8; 16] { + #[cfg(target_endian = "little")] + let bswap = u16::to_be; + #[cfg(target_endian = "big")] + let bswap = u16::to_le; + let addr16 = [ + bswap(value[0]), + bswap(value[1]), + bswap(value[2]), + bswap(value[3]), + bswap(value[4]), + bswap(value[5]), + bswap(value[6]), + bswap(value[7]), + ]; + unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) } +} diff --git a/tests/codegen-llvm/autovectorize-f32x4.rs b/tests/codegen-llvm/autovectorize-f32x4.rs new file mode 100644 index 00000000000..254362842f9 --- /dev/null +++ b/tests/codegen-llvm/autovectorize-f32x4.rs @@ -0,0 +1,37 @@ +//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled +//@ only-x86_64 +#![crate_type = "lib"] + +// CHECK-LABEL: @auto_vectorize_direct +#[no_mangle] +pub fn auto_vectorize_direct(a: [f32; 4], b: [f32; 4]) -> [f32; 4] { + // CHECK: load <4 x float> + // CHECK: load <4 x float> + // CHECK: fadd <4 x float> + // CHECK: store <4 x float> + [a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]] +} + +// CHECK-LABEL: @auto_vectorize_loop +#[no_mangle] +pub fn auto_vectorize_loop(a: [f32; 4], b: [f32; 4]) -> [f32; 4] { + // CHECK: load <4 x float> + // CHECK: load <4 x float> + // CHECK: fadd <4 x float> + // CHECK: store <4 x float> + let mut c = [0.0; 4]; + for i in 0..4 { + c[i] = a[i] + b[i]; + } + c +} + +// CHECK-LABEL: @auto_vectorize_array_from_fn +#[no_mangle] +pub fn auto_vectorize_array_from_fn(a: [f32; 4], b: [f32; 4]) -> [f32; 4] { + // CHECK: load <4 x float> + // CHECK: load <4 x float> + // CHECK: fadd <4 x float> + // CHECK: store <4 x float> + std::array::from_fn(|i| a[i] + b[i]) +} diff --git a/tests/codegen-llvm/auxiliary/extern_decl.rs b/tests/codegen-llvm/auxiliary/extern_decl.rs new file mode 100644 index 00000000000..d17e77b1444 --- /dev/null +++ b/tests/codegen-llvm/auxiliary/extern_decl.rs @@ -0,0 +1,13 @@ +// Auxiliary crate that exports a function and static. Both always +// evaluate to `71`. We force mutability on the static to prevent +// it from being inlined as constant. + +#![crate_type = "lib"] + +#[no_mangle] +pub fn extern_fn() -> u8 { + unsafe { extern_static } +} + +#[no_mangle] +pub static mut extern_static: u8 = 71; diff --git a/tests/codegen-llvm/auxiliary/nounwind.rs b/tests/codegen-llvm/auxiliary/nounwind.rs new file mode 100644 index 00000000000..40f66442c6e --- /dev/null +++ b/tests/codegen-llvm/auxiliary/nounwind.rs @@ -0,0 +1,2 @@ +#[no_mangle] +pub fn bar() {} diff --git a/tests/codegen-llvm/auxiliary/thread_local_aux.rs b/tests/codegen-llvm/auxiliary/thread_local_aux.rs new file mode 100644 index 00000000000..bebaa7754dd --- /dev/null +++ b/tests/codegen-llvm/auxiliary/thread_local_aux.rs @@ -0,0 +1,5 @@ +#![crate_type = "lib"] + +use std::cell::Cell; + +thread_local!(pub static A: Cell = const { Cell::new(0) }); diff --git a/tests/codegen-llvm/avr/avr-func-addrspace.rs b/tests/codegen-llvm/avr/avr-func-addrspace.rs new file mode 100644 index 00000000000..e0192f8b45a --- /dev/null +++ b/tests/codegen-llvm/avr/avr-func-addrspace.rs @@ -0,0 +1,106 @@ +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 --target=avr-none -C target-cpu=atmega328p --crate-type=rlib -C panic=abort +//@ needs-llvm-components: avr + +// This test validates that function pointers can be stored in global variables +// and called upon. It ensures that Rust emits function pointers in the correct +// address space to LLVM so that an assertion error relating to casting is +// not triggered. +// +// It also validates that functions can be called through function pointers +// through traits. + +#![feature(no_core, lang_items, intrinsics, unboxed_closures, arbitrary_self_types)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[rustc_intrinsic] +pub unsafe fn transmute(src: Src) -> Dst; + +pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box; +pub static mut STORAGE_BAR: u32 = 12; + +fn arbitrary_black_box(ptr: &usize, _: &mut u32) -> Result<(), ()> { + let raw_ptr = ptr as *const usize; + let _v: usize = unsafe { *raw_ptr }; + loop {} +} + +#[inline(never)] +#[no_mangle] +fn call_through_fn_trait(a: &mut impl Fn<(), Output = ()>) { + (*a)() +} + +#[inline(never)] +fn update_bar_value() { + unsafe { + STORAGE_BAR = 88; + } +} + +// CHECK: define dso_local void @test(){{.+}}addrspace(1) +#[no_mangle] +pub extern "C" fn test() { + let mut buf = 7; + + // A call through the Fn trait must use address space 1. + // + // CHECK: call{{.+}}addrspace(1) void @call_through_fn_trait({{.*}}) + call_through_fn_trait(&mut update_bar_value); + + // A call through a global variable must use address space 1. + // CHECK: load {{.*}}addrspace(1){{.+}}FOO + unsafe { + STORAGE_FOO(&1, &mut buf); + } +} + +// Validate that we can codegen transmutes between data ptrs and fn ptrs. + +// CHECK: define{{.+}}ptr addrspace(1) @transmute_data_ptr_to_fn(ptr{{.*}} %x) +#[no_mangle] +pub unsafe fn transmute_data_ptr_to_fn(x: *const ()) -> fn() { + // It doesn't matter precisely how this is codegenned (through memory or an addrspacecast), + // as long as it doesn't cause a verifier error by using `bitcast`. + transmute(x) +} + +// CHECK: define{{.+}}ptr @transmute_fn_ptr_to_data(ptr addrspace(1){{.*}} %x) +#[no_mangle] +pub unsafe fn transmute_fn_ptr_to_data(x: fn()) -> *const () { + // It doesn't matter precisely how this is codegenned (through memory or an addrspacecast), + // as long as it doesn't cause a verifier error by using `bitcast`. + transmute(x) +} + +pub enum Either { + A(T), + B(U), +} + +// Previously, we would codegen this as passing/returning a scalar pair of `{ i8, ptr }`, +// with the `ptr` field representing both `&i32` and `fn()` depending on the variant. +// This is incorrect, because `fn()` should be `ptr addrspace(1)`, not `ptr`. + +// CHECK: define{{.+}}void @should_not_combine_addrspace(ptr{{.+}}sret{{.+}}%_0, ptr{{.+}}%x) +#[no_mangle] +#[inline(never)] +pub fn should_not_combine_addrspace(x: Either<&i32, fn()>) -> Either<&i32, fn()> { + x +} + +// The incorrectness described above would result in us producing (after optimizations) +// a `ptrtoint`/`inttoptr` roundtrip to convert from `ptr` to `ptr addrspace(1)`. + +// CHECK-LABEL: @call_with_fn_ptr +#[no_mangle] +pub fn call_with_fn_ptr<'a>(f: fn()) -> Either<&'a i32, fn()> { + // CHECK-NOT: ptrtoint + // CHECK-NOT: inttoptr + // CHECK: call addrspace(1) void @should_not_combine_addrspace + should_not_combine_addrspace(Either::B(f)) +} diff --git a/tests/codegen-llvm/bigint-helpers.rs b/tests/codegen-llvm/bigint-helpers.rs new file mode 100644 index 00000000000..355cccb8150 --- /dev/null +++ b/tests/codegen-llvm/bigint-helpers.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -C opt-level=3 + +#![crate_type = "lib"] +#![feature(bigint_helper_methods)] + +// CHECK-LABEL: @u32_carrying_add +#[no_mangle] +pub fn u32_carrying_add(a: u32, b: u32, c: bool) -> (u32, bool) { + // CHECK: @llvm.uadd.with.overflow.i32 + // CHECK: @llvm.uadd.with.overflow.i32 + // CHECK: or disjoint i1 + u32::carrying_add(a, b, c) +} diff --git a/tests/codegen-llvm/binary-heap-peek-mut-pop-no-panic.rs b/tests/codegen-llvm/binary-heap-peek-mut-pop-no-panic.rs new file mode 100644 index 00000000000..2c40327f624 --- /dev/null +++ b/tests/codegen-llvm/binary-heap-peek-mut-pop-no-panic.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -Copt-level=3 +//@ ignore-std-debug-assertions +#![crate_type = "lib"] + +use std::collections::binary_heap::PeekMut; + +// CHECK-LABEL: @peek_mut_pop +#[no_mangle] +pub fn peek_mut_pop(peek_mut: PeekMut) -> u32 { + // CHECK-NOT: panic + // CHECK-NOT: unwrap_failed + PeekMut::pop(peek_mut) +} diff --git a/tests/codegen-llvm/binary-search-index-no-bound-check.rs b/tests/codegen-llvm/binary-search-index-no-bound-check.rs new file mode 100644 index 00000000000..d59c0beec64 --- /dev/null +++ b/tests/codegen-llvm/binary-search-index-no-bound-check.rs @@ -0,0 +1,35 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +// Make sure no bounds checks are emitted when slicing or indexing +// with an index from `binary_search`. + +// CHECK-LABEL: @binary_search_index_no_bounds_check +#[no_mangle] +pub fn binary_search_index_no_bounds_check(s: &[u8]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + if let Ok(idx) = s.binary_search(&b'\\') { s[idx] } else { 42 } +} + +// Similarly, check that `partition_point` is known to return a valid fencepost. + +// CHECK-LABEL: @unknown_split +#[no_mangle] +pub fn unknown_split(x: &[i32], i: usize) -> (&[i32], &[i32]) { + // This just makes sure that the subsequent function is looking for the + // absence of something that might actually be there. + + // CHECK: call core::panicking::panic + x.split_at(i) +} + +// CHECK-LABEL: @partition_point_split_no_bounds_check +#[no_mangle] +pub fn partition_point_split_no_bounds_check(x: &[i32], needle: i32) -> (&[i32], &[i32]) { + // CHECK-NOT: call core::panicking::panic + let i = x.partition_point(|p| p < &needle); + x.split_at(i) +} diff --git a/tests/codegen-llvm/bool-cmp.rs b/tests/codegen-llvm/bool-cmp.rs new file mode 100644 index 00000000000..71d3411689f --- /dev/null +++ b/tests/codegen-llvm/bool-cmp.rs @@ -0,0 +1,18 @@ +// This is a test for optimal Ord trait implementation for bool. +// See for more info. + +//@ compile-flags: -C opt-level=3 + +#![crate_type = "lib"] + +use std::cmp::Ordering; + +// CHECK-LABEL: @cmp_bool +#[no_mangle] +pub fn cmp_bool(a: bool, b: bool) -> Ordering { + // LLVM 10 produces (zext a) + (sext b), but the final lowering is (zext a) - (zext b). + // CHECK: zext i1 + // CHECK: {{z|s}}ext i1 + // CHECK: {{sub|add}} nsw + a.cmp(&b) +} diff --git a/tests/codegen-llvm/bounds-checking/gep-issue-133979.rs b/tests/codegen-llvm/bounds-checking/gep-issue-133979.rs new file mode 100644 index 00000000000..876bdbfb0e1 --- /dev/null +++ b/tests/codegen-llvm/bounds-checking/gep-issue-133979.rs @@ -0,0 +1,22 @@ +//! Issue: +//! Check that bounds checking are eliminated. + +//@ compile-flags: -Copt-level=2 + +#![crate_type = "lib"] + +// CHECK-LABEL: @test( +#[no_mangle] +fn test(a: &[&[u8]]) -> u32 { + // CHECK-NOT: panic_bounds_check + a.iter() + .enumerate() + .map(|(y, b)| { + b.iter() + .enumerate() + .filter(|(_, c)| **c == b'A') + .map(|(x, _)| a[y][x] as u32) + .sum::() + }) + .sum() +} diff --git a/tests/codegen-llvm/box-default-debug-copies.rs b/tests/codegen-llvm/box-default-debug-copies.rs new file mode 100644 index 00000000000..06cc41b21c0 --- /dev/null +++ b/tests/codegen-llvm/box-default-debug-copies.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Copt-level=0 + +// Test to make sure that `>::default` does not create too many copies of `T` on the stack. +// in debug mode. This regressed in dd0620b86721ae8cae86736443acd3f72ba6fc32 to +// four `T` allocas. +// +// See https://github.com/rust-lang/rust/issues/136043 for more context. +// +// FIXME: This test only wants to ensure that there are at most two allocas of `T` created, instead +// of checking for exactly two. + +#![crate_type = "lib"] + +#[allow(dead_code)] +pub struct Thing([u8; 1000000]); + +impl Default for Thing { + fn default() -> Self { + Thing([0; 1000000]) + } +} + +// CHECK-COUNT-2: %{{.*}} = alloca {{.*}}1000000 +// CHECK-NOT: %{{.*}} = alloca {{.*}}1000000 +#[no_mangle] +pub fn box_default_single_copy() -> Box { + Box::default() +} diff --git a/tests/codegen-llvm/box-uninit-bytes.rs b/tests/codegen-llvm/box-uninit-bytes.rs new file mode 100644 index 00000000000..0cc01148595 --- /dev/null +++ b/tests/codegen-llvm/box-uninit-bytes.rs @@ -0,0 +1,46 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +use std::mem::MaybeUninit; + +// Boxing a `MaybeUninit` value should not copy junk from the stack +#[no_mangle] +pub fn box_uninitialized() -> Box> { + // CHECK-LABEL: @box_uninitialized + // CHECK-NOT: store + // CHECK-NOT: alloca + // CHECK-NOT: memcpy + // CHECK-NOT: memset + Box::new(MaybeUninit::uninit()) +} + +// https://github.com/rust-lang/rust/issues/58201 +#[no_mangle] +pub fn box_uninitialized2() -> Box> { + // CHECK-LABEL: @box_uninitialized2 + // CHECK-NOT: store + // CHECK-NOT: alloca + // CHECK-NOT: memcpy + // CHECK-NOT: memset + Box::new(MaybeUninit::uninit()) +} + +#[repr(align(1024))] +pub struct LotsaPadding(usize); + +// Boxing a value with padding should not copy junk from the stack +#[no_mangle] +pub fn box_lotsa_padding() -> Box { + // CHECK-LABEL: @box_lotsa_padding + // CHECK-NOT: alloca + // CHECK-NOT: getelementptr + // CHECK-NOT: memcpy + // CHECK-NOT: memset + Box::new(LotsaPadding(42)) +} + +// Hide the `allocalign` attribute in the declaration of __rust_alloc +// from the CHECK-NOT above, and also verify the attributes got set reasonably. +// CHECK: declare {{(dso_local )?}}noalias noundef ptr @{{.*}}__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]] + +// CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) {{(uwtable )?}}"alloc-family"="__rust_alloc" {{.*}} } diff --git a/tests/codegen-llvm/bpf-alu32.rs b/tests/codegen-llvm/bpf-alu32.rs new file mode 100644 index 00000000000..5955bf3317f --- /dev/null +++ b/tests/codegen-llvm/bpf-alu32.rs @@ -0,0 +1,11 @@ +//@ only-bpf +#![crate_type = "lib"] +#![feature(bpf_target_feature)] +#![no_std] + +#[no_mangle] +#[target_feature(enable = "alu32")] +// CHECK: define i8 @foo(i8 returned %arg) unnamed_addr #0 { +pub unsafe fn foo(arg: u8) -> u8 { + arg +} diff --git a/tests/codegen-llvm/branch-protection.rs b/tests/codegen-llvm/branch-protection.rs new file mode 100644 index 00000000000..d67e494cc0d --- /dev/null +++ b/tests/codegen-llvm/branch-protection.rs @@ -0,0 +1,94 @@ +// Test that the correct module flags are emitted with different branch protection flags. + +//@ add-core-stubs +//@ revisions: BTI PACRET LEAF BKEY PAUTHLR PAUTHLR_BKEY PAUTHLR_LEAF PAUTHLR_BTI NONE +//@ needs-llvm-components: aarch64 +//@ [BTI] compile-flags: -Z branch-protection=bti +//@ [PACRET] compile-flags: -Z branch-protection=pac-ret +//@ [LEAF] compile-flags: -Z branch-protection=pac-ret,leaf +//@ [BKEY] compile-flags: -Z branch-protection=pac-ret,b-key +//@ [PAUTHLR] compile-flags: -Z branch-protection=pac-ret,pc +//@ [PAUTHLR_BKEY] compile-flags: -Z branch-protection=pac-ret,pc,b-key +//@ [PAUTHLR_LEAF] compile-flags: -Z branch-protection=pac-ret,pc,leaf +//@ [PAUTHLR_BTI] compile-flags: -Z branch-protection=bti,pac-ret,pc +//@ compile-flags: --target aarch64-unknown-linux-gnu + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// A basic test function. +// CHECK: @test(){{.*}} [[ATTR:#[0-9]+]] { +#[no_mangle] +pub fn test() {} + +// BTI: attributes [[ATTR]] = {{.*}} "branch-target-enforcement" +// BTI: !"branch-target-enforcement", i32 1 +// BTI: !"sign-return-address", i32 0 +// BTI: !"branch-protection-pauth-lr", i32 0 +// BTI: !"sign-return-address-all", i32 0 +// BTI: !"sign-return-address-with-bkey", i32 0 + +// PACRET: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf" +// PACRET-SAME: "sign-return-address-key"="a_key" +// PACRET: !"branch-target-enforcement", i32 0 +// PACRET: !"sign-return-address", i32 1 +// PACRET: !"branch-protection-pauth-lr", i32 0 +// PACRET: !"sign-return-address-all", i32 0 +// PACRET: !"sign-return-address-with-bkey", i32 0 + +// LEAF: attributes [[ATTR]] = {{.*}} "sign-return-address"="all" +// LEAF-SAME: "sign-return-address-key"="a_key" +// LEAF: !"branch-target-enforcement", i32 0 +// LEAF: !"sign-return-address", i32 1 +// LEAF: !"branch-protection-pauth-lr", i32 0 +// LEAF: !"sign-return-address-all", i32 1 +// LEAF: !"sign-return-address-with-bkey", i32 0 + +// BKEY: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf" +// BKEY-SAME: "sign-return-address-key"="b_key" +// BKEY: !"branch-target-enforcement", i32 0 +// BKEY: !"sign-return-address", i32 1 +// BKEY: !"branch-protection-pauth-lr", i32 0 +// BKEY: !"sign-return-address-all", i32 0 +// BKEY: !"sign-return-address-with-bkey", i32 1 + +// PAUTHLR: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf" +// PAUTHLR-SAME: "sign-return-address-key"="a_key" +// PAUTHLR: !"branch-target-enforcement", i32 0 +// PAUTHLR: !"sign-return-address", i32 1 +// PAUTHLR: !"branch-protection-pauth-lr", i32 1 +// PAUTHLR: !"sign-return-address-all", i32 0 +// PAUTHLR: !"sign-return-address-with-bkey", i32 0 + +// PAUTHLR_BKEY: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf" +// PAUTHLR_BKEY-SAME: "sign-return-address-key"="b_key" +// PAUTHLR_BKEY: !"branch-target-enforcement", i32 0 +// PAUTHLR_BKEY: !"sign-return-address", i32 1 +// PAUTHLR_BKEY: !"branch-protection-pauth-lr", i32 1 +// PAUTHLR_BKEY: !"sign-return-address-all", i32 0 +// PAUTHLR_BKEY: !"sign-return-address-with-bkey", i32 1 + +// PAUTHLR_LEAF: attributes [[ATTR]] = {{.*}} "sign-return-address"="all" +// PAUTHLR_LEAF-SAME: "sign-return-address-key"="a_key" +// PAUTHLR_LEAF: !"branch-target-enforcement", i32 0 +// PAUTHLR_LEAF: !"sign-return-address", i32 1 +// PAUTHLR_LEAF: !"branch-protection-pauth-lr", i32 1 +// PAUTHLR_LEAF: !"sign-return-address-all", i32 1 +// PAUTHLR_LEAF: !"sign-return-address-with-bkey", i32 0 + +// PAUTHLR_BTI: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf" +// PAUTHLR_BTI-SAME: "sign-return-address-key"="a_key" +// PAUTHLR_BTI: !"branch-target-enforcement", i32 1 +// PAUTHLR_BTI: !"sign-return-address", i32 1 +// PAUTHLR_BTI: !"branch-protection-pauth-lr", i32 1 +// PAUTHLR_BTI: !"sign-return-address-all", i32 0 +// PAUTHLR_BTI: !"sign-return-address-with-bkey", i32 0 + +// NONE-NOT: branch-target-enforcement +// NONE-NOT: sign-return-address +// NONE-NOT: sign-return-address-all +// NONE-NOT: sign-return-address-with-bkey diff --git a/tests/codegen-llvm/call-llvm-intrinsics.rs b/tests/codegen-llvm/call-llvm-intrinsics.rs new file mode 100644 index 00000000000..dc7e0249cb6 --- /dev/null +++ b/tests/codegen-llvm/call-llvm-intrinsics.rs @@ -0,0 +1,30 @@ +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 + +//@ ignore-riscv64 +//@ ignore-loongarch64 + +#![feature(link_llvm_intrinsics)] +#![crate_type = "lib"] + +struct A; + +impl Drop for A { + fn drop(&mut self) { + println!("A"); + } +} + +extern "C" { + #[link_name = "llvm.sqrt.f32"] + fn sqrt(x: f32) -> f32; +} + +pub fn do_call() { + let _a = A; + + unsafe { + // Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them + // CHECK: call float @llvm.sqrt.f32(float 4.000000e+00 + sqrt(4.0); + } +} diff --git a/tests/codegen-llvm/call-tmps-lifetime.rs b/tests/codegen-llvm/call-tmps-lifetime.rs new file mode 100644 index 00000000000..7b7b6e17bdd --- /dev/null +++ b/tests/codegen-llvm/call-tmps-lifetime.rs @@ -0,0 +1,68 @@ +// Test that temporary allocas used for call arguments have their lifetimes described by +// intrinsics. +// +//@ add-core-stubs +//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes --crate-type=lib --target i686-unknown-linux-gnu +//@ needs-llvm-components: x86 +#![feature(no_core)] +#![no_std] +#![no_core] +extern crate minicore; +use minicore::*; + +// Const operand. Regression test for #98156. +// +// CHECK-LABEL: define void @const_indirect( +// CHECK-NEXT: start: +// CHECK-NEXT: [[B:%.*]] = alloca +// CHECK-NEXT: [[A:%.*]] = alloca +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4096, ptr [[A]]) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 {{.*}}, i32 4096, i1 false) +// CHECK-NEXT: call void %h(ptr {{.*}} [[A]]) +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4096, ptr [[A]]) +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4096, ptr [[B]]) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[B]], ptr align 4 {{.*}}, i32 4096, i1 false) +// CHECK-NEXT: call void %h(ptr {{.*}} [[B]]) +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4096, ptr [[B]]) +#[no_mangle] +pub fn const_indirect(h: extern "C" fn([u32; 1024])) { + const C: [u32; 1024] = [0; 1024]; + h(C); + h(C); +} + +#[repr(C)] +pub struct Str { + pub ptr: *const u8, + pub len: usize, +} + +// Pair of immediates. Regression test for #132014. +// +// CHECK-LABEL: define void @immediate_indirect(ptr {{.*}}%s.0, i32 {{.*}}%s.1, ptr {{.*}}%g) +// CHECK-NEXT: start: +// CHECK-NEXT: [[A:%.*]] = alloca +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[A]]) +// CHECK-NEXT: store ptr %s.0, ptr [[A]] +// CHECK-NEXT: [[B:%.]] = getelementptr inbounds i8, ptr [[A]], i32 4 +// CHECK-NEXT: store i32 %s.1, ptr [[B]] +// CHECK-NEXT: call void %g(ptr {{.*}} [[A]]) +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[A]]) +#[no_mangle] +pub fn immediate_indirect(s: Str, g: extern "C" fn(Str)) { + g(s); +} + +// Indirect argument with a higher alignment requirement than the type's. +// +// CHECK-LABEL: define void @align_indirect(ptr{{.*}} align 1{{.*}} %a, ptr{{.*}} %fun) +// CHECK-NEXT: start: +// CHECK-NEXT: [[A:%.*]] = alloca [1024 x i8], align 4 +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1024, ptr [[A]]) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 1 %a, i32 1024, i1 false) +// CHECK-NEXT: call void %fun(ptr {{.*}} [[A]]) +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1024, ptr [[A]]) +#[no_mangle] +pub fn align_indirect(a: [u8; 1024], fun: extern "C" fn([u8; 1024])) { + fun(a); +} diff --git a/tests/codegen-llvm/cast-optimized.rs b/tests/codegen-llvm/cast-optimized.rs new file mode 100644 index 00000000000..11220c4a922 --- /dev/null +++ b/tests/codegen-llvm/cast-optimized.rs @@ -0,0 +1,33 @@ +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled +#![crate_type = "lib"] + +// This tests that LLVM can optimize based on the niches in the source or +// destination types for casts. + +// CHECK-LABEL: @u32_index +#[no_mangle] +pub fn u32_index(c: u32) -> [bool; 22] { + let mut array = [false; 22]; + + let index = 32 - c.leading_zeros(); + + // CHECK: call core::panicking::panic + array[index as usize] = true; + + array +} + +// CHECK-LABEL: @char_as_u32_index +#[no_mangle] +pub fn char_as_u32_index(c: char) -> [bool; 22] { + let c = c as u32; + + let mut array = [false; 22]; + + let index = 32 - c.leading_zeros(); + + // CHECK-NOT: call core::panicking::panic + array[index as usize] = true; + + array +} diff --git a/tests/codegen-llvm/cast-target-abi.rs b/tests/codegen-llvm/cast-target-abi.rs new file mode 100644 index 00000000000..cbd49e2f022 --- /dev/null +++ b/tests/codegen-llvm/cast-target-abi.rs @@ -0,0 +1,599 @@ +// ignore-tidy-linelength +//@ add-core-stubs +//@ revisions:aarch64 loongarch64 powerpc64 sparc64 x86_64 +//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes -Zlint-llvm-ir + +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: arm +//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@[loongarch64] needs-llvm-components: loongarch +//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu +//@[powerpc64] needs-llvm-components: powerpc +//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparc64] needs-llvm-components: sparc +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64] needs-llvm-components: x86 + +// Tests that arguments with `PassMode::Cast` are handled correctly. + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +// This struct will be passed as a single `i64` or `i32`. +// This may be (if `i64)) larger than the Rust layout, which is just `{ i16, i16 }`. +#[repr(C)] +pub struct TwoU16s { + a: u16, + b: u16, +} + +// This struct will be passed as `[2 x i64]`. +// This is larger than the Rust layout. +#[repr(C)] +pub struct FiveU16s { + a: u16, + b: u16, + c: u16, + d: u16, + e: u16, +} + +// This struct will be passed as `[2 x double]`. +// This is the same as the Rust layout. +#[repr(C)] +pub struct DoubleDouble { + f: f64, + g: f64, +} + +// On loongarch, this struct will be passed as `{ double, float }`. +// This is smaller than the Rust layout, which has trailing padding (`{ f64, f32, }`) +#[repr(C)] +pub struct DoubleFloat { + f: f64, + g: f32, +} + +// On x86_64, this struct will be passed as `{ i64, i32 }`. +// The load and store instructions will access 16 bytes, so we should allocate 16 bytes. +#[repr(C)] +pub struct Three32s { + a: u32, + b: u32, + c: u32, +} + +// CHECK-LABEL: @receives_twou16s +// aarch64-SAME: ([[ABI_TYPE:i64]] {{.*}}[[ABI_VALUE:%.+]]) +// loongarch64-SAME: ([[ABI_TYPE:i64]] {{.*}}[[ABI_VALUE:%.+]]) +// powerpc64-SAME: ([[ABI_TYPE:i32]] {{.*}}[[ABI_VALUE:%.+]]) +// sparc64-SAME: ([[ABI_TYPE:i64]] {{.*}}[[ABI_VALUE:%.+]]) +// x86_64-SAME: ([[ABI_TYPE:i32]] {{.*}}[[ABI_VALUE:%.+]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn receives_twou16s(x: TwoU16s) { + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] + + // CHECK: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] + + // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) +} + +// CHECK-LABEL: @returns_twou16s +// powerpc64-SAME: sret([4 x i8]) align [[RUST_ALIGN:2]] {{.*}}[[RET_PTR:%.*]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn returns_twou16s() -> TwoU16s { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:2]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:2]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:2]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:2]] + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // sparc64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] + TwoU16s { a: 0, b: 1 } +} + +// CHECK-LABEL: @receives_fiveu16s +// aarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// loongarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// powerpc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// sparc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// x86_64-SAME: ([[ABI_TYPE:{ i64, i16 }]] {{.*}}[[ABI_VALUE:%.+]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn receives_fiveu16s(x: FiveU16s) { + // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // CHECK: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align [[RUST_ALIGN:2]] + + // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) +} + +// CHECK-LABEL: @returns_fiveu16s +// powerpc64-SAME: sret([10 x i8]) align [[RUST_ALIGN:2]] {{.*}}[[RET_PTR:%.*]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn returns_fiveu16s() -> FiveU16s { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i16 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // sparc64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] + FiveU16s { a: 0, b: 1, c: 2, d: 3, e: 4 } +} + +// CHECK-LABEL: @receives_doubledouble +// aarch64-SAME: ([[ABI_TYPE:\[2 x double\]]] {{.*}}[[ABI_VALUE:%.+]]) +// loongarch64-SAME: ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]]) +// powerpc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// sparc64-SAME: ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]]) +// x86_64-SAME: ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn receives_doubledouble(x: DoubleDouble) { + // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // CHECK: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + + // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) +} + +// CHECK-LABEL: @returns_doubledouble +// powerpc64-SAME: sret([16 x i8]) align [[RUST_ALIGN:8]] {{.*}}[[RET_PTR:%.*]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn returns_doubledouble() -> DoubleDouble { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x double\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // sparc64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] + DoubleDouble { f: 0., g: 1. } +} + +// CHECK-LABEL: @receives_three32s +// aarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// loongarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// powerpc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// sparc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// x86_64-SAME: ([[ABI_TYPE:{ i64, i32 }]] {{.*}}[[ABI_VALUE:%.+]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn receives_three32s(x: Three32s) { + // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // CHECK: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]] + + // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) +} + +// CHECK-LABEL: @returns_three32s +// powerpc64-SAME: sret([12 x i8]) align [[RUST_ALIGN:4]] {{.*}}[[RET_PTR:%.*]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn returns_three32s() -> Three32s { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i32 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // sparc64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] + Three32s { a: 0, b: 0, c: 0 } +} + +// These functions cause an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620) +#[cfg(not(target_arch = "sparc64"))] +// aarch64-LABEL: @receives_doublefloat +// loongarch64-LABEL: @receives_doublefloat +// powerpc64-LABEL: @receives_doublefloat +// x86_64-LABEL: @receives_doublefloat + +// aarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// loongarch64-SAME: ([[ABI_TYPE:{ double, float }]] {{.*}}[[ABI_VALUE:%.+]]) +// powerpc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// x86_64-SAME: ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn receives_doublefloat(x: DoubleFloat) { + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // powerpc64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + + // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // powerpc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) + // powerpc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) +} + +#[cfg(not(target_arch = "sparc64"))] +// aarch64-LABEL: @returns_doublefloat +// loongarch64-LABEL: @returns_doublefloat +// powerpc64-LABEL: @returns_doublefloat +// x86_64-LABEL: @returns_doublefloat + +// powerpc64-SAME: sret([16 x i8]) align [[RUST_ALIGN:8]] {{.*}}[[RET_PTR:%.*]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn returns_doublefloat() -> DoubleFloat { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, float }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] + DoubleFloat { f: 0., g: 0. } +} + +// CHECK-LABEL: @call_twou16s +#[no_mangle] +pub fn call_twou16s() { + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] + + // CHECK: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] + + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 4, i1 false) + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // CHECK: call void @receives_twou16s([[ABI_TYPE]] [[ABI_VALUE]]) + let x = TwoU16s { a: 1, b: 2 }; + receives_twou16s(x); +} + +// CHECK-LABEL: @return_twou16s +#[no_mangle] +pub fn return_twou16s() -> TwoU16s { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + + // powerpc64: [[RETVAL:%.+]] = alloca [4 x i8], align 2 + // powerpc64: call void @returns_twou16s(ptr {{.+}} [[RETVAL]]) + + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] + + // aarch64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] + // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] + // sparc64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] + // x86_64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] + + // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s() + // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s() + // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s() + // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i32]] @returns_twou16s() + + // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) + // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) + // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) + // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) + returns_twou16s() +} + +// CHECK-LABEL: @call_fiveu16s +#[no_mangle] +pub fn call_fiveu16s() { + // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // CHECK: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align 2 + + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 10, i1 false) + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i16 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // CHECK: call void @receives_fiveu16s([[ABI_TYPE]] [[ABI_VALUE]]) + let x = FiveU16s { a: 1, b: 2, c: 3, d: 4, e: 5 }; + receives_fiveu16s(x); +} + +// CHECK-LABEL: @return_fiveu16s +// CHECK-SAME: (ptr {{.+}} sret([10 x i8]) align [[RUST_ALIGN:2]] {{.*}}dereferenceable(10) [[RET_PTR:%.+]]) +#[no_mangle] +pub fn return_fiveu16s() -> FiveU16s { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + + // powerpc64: call void @returns_fiveu16s(ptr {{.+}} [[RET_PTR]]) + + // The other targets copy the cast ABI type to the sret pointer. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() + // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() + // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() + // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i16 }]] @returns_fiveu16s() + + // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) + // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) + // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) + // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) + returns_fiveu16s() +} + +// CHECK-LABEL: @call_doubledouble +#[no_mangle] +pub fn call_doubledouble() { + // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // CHECK: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x double\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // CHECK: call void @receives_doubledouble([[ABI_TYPE]] [[ABI_VALUE]]) + let x = DoubleDouble { f: 1., g: 2. }; + receives_doubledouble(x); +} + +// CHECK-LABEL: @return_doubledouble +#[no_mangle] +pub fn return_doubledouble() -> DoubleDouble { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + + // powerpc64: [[RETVAL:%.+]] = alloca [16 x i8], align 8 + // powerpc64: call void @returns_doubledouble(ptr {{.+}} [[RETVAL]]) + + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // sparc64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + + // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x double\]]] @returns_doubledouble() + // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble() + // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble() + // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble() + + // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + returns_doubledouble() +} + +// This test causes an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620) +#[cfg(not(target_arch = "sparc64"))] +// aarch64-LABEL: @call_doublefloat +// loongarch64-LABEL: @call_doublefloat +// powerpc64-LABEL: @call_doublefloat +// x86_64-LABEL: @call_doublefloat +#[no_mangle] +pub fn call_doublefloat() { + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // powerpc64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + + // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) + // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false) + // powerpc64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) + // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, float }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) + // loongarch64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) + // powerpc64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) + // x86_64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) + let x = DoubleFloat { f: 1., g: 2. }; + receives_doublefloat(x); +} + +// This test causes an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620) +#[cfg(not(target_arch = "sparc64"))] +// aarch64-LABEL: @return_doublefloat +// loongarch64-LABEL: @return_doublefloat +// powerpc64-LABEL: @return_doublefloat +// x86_64-LABEL: @return_doublefloat +#[no_mangle] +pub fn return_doublefloat() -> DoubleFloat { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + + // powerpc64: [[RETVAL:%.+]] = alloca [16 x i8], align 8 + // powerpc64: call void @returns_doublefloat(ptr {{.+}} [[RETVAL]]) + + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + + // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_doublefloat() + // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, float }]] @returns_doublefloat() + // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doublefloat() + + // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) + // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + returns_doublefloat() +} + +// CHECK-LABEL: @call_three32s +#[no_mangle] +pub fn call_three32s() { + // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // CHECK: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]] + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false) + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i32 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // CHECK: call void @receives_three32s([[ABI_TYPE]] [[ABI_VALUE]]) + let x = Three32s { a: 1, b: 2, c: 3 }; + receives_three32s(x); +} + +// Regression test for #75839 +// CHECK-LABEL: @return_three32s( +// CHECK-SAME: sret([12 x i8]) align [[RUST_ALIGN:4]] {{.*}}[[RUST_RETVAL:%.*]]) +#[no_mangle] +pub fn return_three32s() -> Three32s { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + + // powerpc64: call void @returns_three32s(ptr {{.+}} [[RUST_RETVAL]]) + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() + // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() + // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() + // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i32 }]] @returns_three32s() + + // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) + // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) + // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) + // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) + returns_three32s() +} diff --git a/tests/codegen-llvm/catch-unwind.rs b/tests/codegen-llvm/catch-unwind.rs new file mode 100644 index 00000000000..d1ff55bcc28 --- /dev/null +++ b/tests/codegen-llvm/catch-unwind.rs @@ -0,0 +1,32 @@ +//@ compile-flags: -Copt-level=3 + +// On x86 the closure is inlined in foo() producing something like +// define i32 @foo() [...] { +// tail call void @bar() [...] +// ret i32 0 +// } +// On riscv the closure is another function, placed before fn foo so CHECK can't +// find it +//@ ignore-riscv64 FIXME +// On s390x the closure is also in another function +//@ ignore-s390x FIXME +// On loongarch64 the closure is also in another function +//@ ignore-loongarch64 FIXME + +#![crate_type = "lib"] + +extern "C" { + fn bar(); +} + +// CHECK-LABEL: @foo +#[no_mangle] +pub unsafe fn foo() -> i32 { + // CHECK: call void @bar + // CHECK: ret i32 0 + std::panic::catch_unwind(|| { + bar(); + 0 + }) + .unwrap() +} diff --git a/tests/codegen-llvm/cdylib-external-inline-fns.rs b/tests/codegen-llvm/cdylib-external-inline-fns.rs new file mode 100644 index 00000000000..2e472ea68e8 --- /dev/null +++ b/tests/codegen-llvm/cdylib-external-inline-fns.rs @@ -0,0 +1,43 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "cdylib"] + +// CHECK: define{{( dso_local)?}} void @a() +#[no_mangle] +#[inline] +pub extern "C" fn a() {} + +// CHECK: define{{( dso_local)?}} void @b() +#[export_name = "b"] +#[inline] +pub extern "C" fn b() {} + +// CHECK: define{{( dso_local)?}} void @c() +#[no_mangle] +#[inline] +extern "C" fn c() {} + +// CHECK: define{{( dso_local)?}} void @d() +#[export_name = "d"] +#[inline] +extern "C" fn d() {} + +// CHECK: define{{( dso_local)?}} void @e() +#[no_mangle] +#[inline(always)] +pub extern "C" fn e() {} + +// CHECK: define{{( dso_local)?}} void @f() +#[export_name = "f"] +#[inline(always)] +pub extern "C" fn f() {} + +// CHECK: define{{( dso_local)?}} void @g() +#[no_mangle] +#[inline(always)] +extern "C" fn g() {} + +// CHECK: define{{( dso_local)?}} void @h() +#[export_name = "h"] +#[inline(always)] +extern "C" fn h() {} diff --git a/tests/codegen-llvm/cf-protection.rs b/tests/codegen-llvm/cf-protection.rs new file mode 100644 index 00000000000..f1349a5dcb9 --- /dev/null +++ b/tests/codegen-llvm/cf-protection.rs @@ -0,0 +1,38 @@ +// Test that the correct module flags are emitted with different control-flow protection flags. + +//@ add-core-stubs +//@ revisions: undefined none branch return full +//@ needs-llvm-components: x86 +//@ [undefined] compile-flags: +//@ [none] compile-flags: -Z cf-protection=none +//@ [branch] compile-flags: -Z cf-protection=branch +//@ [return] compile-flags: -Z cf-protection=return +//@ [full] compile-flags: -Z cf-protection=full +//@ compile-flags: --target x86_64-unknown-linux-gnu + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// A basic test function. +pub fn test() {} + +// undefined-NOT: !"cf-protection-branch" +// undefined-NOT: !"cf-protection-return" + +// none-NOT: !"cf-protection-branch" +// none-NOT: !"cf-protection-return" + +// branch-NOT: !"cf-protection-return" +// branch: !"cf-protection-branch", i32 1 +// branch-NOT: !"cf-protection-return" + +// return-NOT: !"cf-protection-branch" +// return: !"cf-protection-return", i32 1 +// return-NOT: !"cf-protection-branch" + +// full: !"cf-protection-branch", i32 1 +// full: !"cf-protection-return", i32 1 diff --git a/tests/codegen-llvm/cffi/c-variadic-copy.rs b/tests/codegen-llvm/cffi/c-variadic-copy.rs new file mode 100644 index 00000000000..4c61c4fcf68 --- /dev/null +++ b/tests/codegen-llvm/cffi/c-variadic-copy.rs @@ -0,0 +1,16 @@ +// Tests that `VaListImpl::clone` gets inlined into a call to `llvm.va_copy` + +#![crate_type = "lib"] +#![feature(c_variadic)] +#![no_std] +use core::ffi::VaList; + +extern "C" { + fn foreign_c_variadic_1(_: VaList, ...); +} + +pub unsafe extern "C" fn clone_variadic(ap: VaList) { + let mut ap2 = ap.clone(); + // CHECK: call void @llvm.va_copy + foreign_c_variadic_1(ap2.as_va_list(), 42i32); +} diff --git a/tests/codegen-llvm/cffi/c-variadic-naked.rs b/tests/codegen-llvm/cffi/c-variadic-naked.rs new file mode 100644 index 00000000000..5843628b633 --- /dev/null +++ b/tests/codegen-llvm/cffi/c-variadic-naked.rs @@ -0,0 +1,15 @@ +//@ needs-asm-support +//@ only-x86_64 + +// tests that `va_start` is not injected into naked functions + +#![crate_type = "lib"] +#![feature(c_variadic)] +#![no_std] + +#[unsafe(naked)] +pub unsafe extern "C" fn c_variadic(_: usize, _: ...) { + // CHECK-NOT: va_start + // CHECK-NOT: alloca + core::arch::naked_asm!("ret") +} diff --git a/tests/codegen-llvm/cffi/c-variadic-opt.rs b/tests/codegen-llvm/cffi/c-variadic-opt.rs new file mode 100644 index 00000000000..7e544ee7f37 --- /dev/null +++ b/tests/codegen-llvm/cffi/c-variadic-opt.rs @@ -0,0 +1,30 @@ +//@ compile-flags: -C opt-level=3 + +#![crate_type = "lib"] +#![feature(c_variadic)] +#![no_std] +use core::ffi::VaList; + +extern "C" { + fn vprintf(fmt: *const i8, ap: VaList) -> i32; +} + +// Ensure that `va_start` and `va_end` are properly injected even +// when the "spoofed" `VaListImpl` is not used. +#[no_mangle] +pub unsafe extern "C" fn c_variadic_no_use(fmt: *const i8, mut ap: ...) -> i32 { + // CHECK: call void @llvm.va_start + vprintf(fmt, ap.as_va_list()) + // CHECK: call void @llvm.va_end +} + +// Check that `VaListImpl::clone` gets inlined into a direct call to `llvm.va_copy` +#[no_mangle] +pub unsafe extern "C" fn c_variadic_clone(fmt: *const i8, mut ap: ...) -> i32 { + // CHECK: call void @llvm.va_start + let mut ap2 = ap.clone(); + // CHECK: call void @llvm.va_copy + let res = vprintf(fmt, ap2.as_va_list()); + res + // CHECK: call void @llvm.va_end +} diff --git a/tests/codegen-llvm/cffi/c-variadic.rs b/tests/codegen-llvm/cffi/c-variadic.rs new file mode 100644 index 00000000000..140d2f37f46 --- /dev/null +++ b/tests/codegen-llvm/cffi/c-variadic.rs @@ -0,0 +1,71 @@ +//@ needs-unwind +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 +// + +#![crate_type = "lib"] +#![feature(c_variadic)] +#![no_std] +use core::ffi::VaList; + +extern "C" { + fn foreign_c_variadic_0(_: i32, ...); + fn foreign_c_variadic_1(_: VaList, ...); +} + +pub unsafe extern "C" fn use_foreign_c_variadic_0() { + // Ensure that we correctly call foreign C-variadic functions. + // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM:i32( signext)?]] 0) + foreign_c_variadic_0(0); + // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42) + foreign_c_variadic_0(0, 42i32); + // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024) + foreign_c_variadic_0(0, 42i32, 1024i32); + // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024, [[PARAM]] 0) + foreign_c_variadic_0(0, 42i32, 1024i32, 0i32); +} + +// Ensure that we do not remove the `va_list` passed to the foreign function when +// removing the "spoofed" `VaListImpl` that is used by Rust defined C-variadics. +pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) { + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap) + foreign_c_variadic_1(ap); +} + +pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) { + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 42) + foreign_c_variadic_1(ap, 42i32); +} +pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) { + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42) + foreign_c_variadic_1(ap, 2i32, 42i32); +} + +pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) { + // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42, [[PARAM]] 0) + foreign_c_variadic_1(ap, 2i32, 42i32, 0i32); +} + +// Ensure that `va_start` and `va_end` are properly injected. +#[no_mangle] +pub unsafe extern "C" fn c_variadic(n: i32, mut ap: ...) -> i32 { + // CHECK: call void @llvm.va_start + let mut sum = 0; + for _ in 0..n { + sum += ap.arg::(); + } + sum + // CHECK: call void @llvm.va_end +} + +// Ensure that we generate the correct `call` signature when calling a Rust +// defined C-variadic. +pub unsafe fn test_c_variadic_call() { + // CHECK: call [[RET:(signext )?i32]] (i32, ...) @c_variadic([[PARAM]] 0) + c_variadic(0); + // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42) + c_variadic(0, 42i32); + // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024) + c_variadic(0, 42i32, 1024i32); + // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024, [[PARAM]] 0) + c_variadic(0, 42i32, 1024i32, 0i32); +} diff --git a/tests/codegen-llvm/cffi/ffi-const.rs b/tests/codegen-llvm/cffi/ffi-const.rs new file mode 100644 index 00000000000..3ea9d517ec2 --- /dev/null +++ b/tests/codegen-llvm/cffi/ffi-const.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -C no-prepopulate-passes +#![crate_type = "lib"] +#![feature(ffi_const)] + +pub fn bar() { + unsafe { foo() } +} + +extern "C" { + // CHECK-LABEL: declare{{.*}}void @foo() + // CHECK-SAME: [[ATTRS:#[0-9]+]] + // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}memory(none){{.*}} } + #[unsafe(ffi_const)] + pub fn foo(); +} diff --git a/tests/codegen-llvm/cffi/ffi-out-of-bounds-loads.rs b/tests/codegen-llvm/cffi/ffi-out-of-bounds-loads.rs new file mode 100644 index 00000000000..859386d2df8 --- /dev/null +++ b/tests/codegen-llvm/cffi/ffi-out-of-bounds-loads.rs @@ -0,0 +1,41 @@ +//@ add-core-stubs +//@ revisions: linux apple +//@ 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 +//@[apple] compile-flags: --target x86_64-apple-darwin +//@[apple] needs-llvm-components: x86 + +// Regression test for #29988 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(C)] +struct S { + f1: i32, + f2: i32, + f3: i32, +} + +extern "C" { + fn foo(s: S); +} + +// CHECK-LABEL: @test +#[no_mangle] +pub fn test() { + let s = S { f1: 1, f2: 2, f3: 3 }; + unsafe { + // CHECK: [[ALLOCA:%.+]] = alloca [16 x i8], align 8 + // CHECK: [[LOAD:%.+]] = load { i64, i32 }, ptr [[ALLOCA]], align 8 + // CHECK: call void @foo({ i64, i32 } [[LOAD]]) + foo(s); + } +} diff --git a/tests/codegen-llvm/cffi/ffi-pure.rs b/tests/codegen-llvm/cffi/ffi-pure.rs new file mode 100644 index 00000000000..a61e80ecf65 --- /dev/null +++ b/tests/codegen-llvm/cffi/ffi-pure.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -C no-prepopulate-passes +#![crate_type = "lib"] +#![feature(ffi_pure)] + +pub fn bar() { + unsafe { foo() } +} + +extern "C" { + // CHECK-LABEL: declare{{.*}}void @foo() + // CHECK-SAME: [[ATTRS:#[0-9]+]] + // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}memory(read){{.*}} } + #[unsafe(ffi_pure)] + pub fn foo(); +} diff --git a/tests/codegen-llvm/cfguard-checks.rs b/tests/codegen-llvm/cfguard-checks.rs new file mode 100644 index 00000000000..cdf6406ad61 --- /dev/null +++ b/tests/codegen-llvm/cfguard-checks.rs @@ -0,0 +1,10 @@ +//@ compile-flags: -C control-flow-guard=checks +//@ only-msvc + +#![crate_type = "lib"] + +// A basic test function. +pub fn test() {} + +// Ensure the module flag cfguard=2 is present +// CHECK: !"cfguard", i32 2 diff --git a/tests/codegen-llvm/cfguard-disabled.rs b/tests/codegen-llvm/cfguard-disabled.rs new file mode 100644 index 00000000000..90915c0f0c6 --- /dev/null +++ b/tests/codegen-llvm/cfguard-disabled.rs @@ -0,0 +1,10 @@ +//@ compile-flags: -C control-flow-guard=no +//@ only-msvc + +#![crate_type = "lib"] + +// A basic test function. +pub fn test() {} + +// Ensure the module flag cfguard is not present +// CHECK-NOT: !"cfguard" diff --git a/tests/codegen-llvm/cfguard-nochecks.rs b/tests/codegen-llvm/cfguard-nochecks.rs new file mode 100644 index 00000000000..5f386533ec1 --- /dev/null +++ b/tests/codegen-llvm/cfguard-nochecks.rs @@ -0,0 +1,10 @@ +//@ compile-flags: -C control-flow-guard=nochecks +//@ only-msvc + +#![crate_type = "lib"] + +// A basic test function. +pub fn test() {} + +// Ensure the module flag cfguard=1 is present +// CHECK: !"cfguard", i32 1 diff --git a/tests/codegen-llvm/cfguard-non-msvc.rs b/tests/codegen-llvm/cfguard-non-msvc.rs new file mode 100644 index 00000000000..1e6559aaf5d --- /dev/null +++ b/tests/codegen-llvm/cfguard-non-msvc.rs @@ -0,0 +1,10 @@ +//@ compile-flags: -C control-flow-guard +//@ ignore-msvc + +#![crate_type = "lib"] + +// A basic test function. +pub fn test() {} + +// Ensure the cfguard module flag is not added for non-MSVC targets. +// CHECK-NOT: !"cfguard" diff --git a/tests/codegen-llvm/char-ascii-branchless.rs b/tests/codegen-llvm/char-ascii-branchless.rs new file mode 100644 index 00000000000..f99066aa9aa --- /dev/null +++ b/tests/codegen-llvm/char-ascii-branchless.rs @@ -0,0 +1,47 @@ +// Checks that these functions are branchless. +// +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @is_ascii_alphanumeric_char +#[no_mangle] +pub fn is_ascii_alphanumeric_char(x: char) -> bool { + // CHECK-NOT: br + x.is_ascii_alphanumeric() +} + +// CHECK-LABEL: @is_ascii_alphanumeric_u8 +#[no_mangle] +pub fn is_ascii_alphanumeric_u8(x: u8) -> bool { + // CHECK-NOT: br + x.is_ascii_alphanumeric() +} + +// CHECK-LABEL: @is_ascii_hexdigit_char +#[no_mangle] +pub fn is_ascii_hexdigit_char(x: char) -> bool { + // CHECK-NOT: br + x.is_ascii_hexdigit() +} + +// CHECK-LABEL: @is_ascii_hexdigit_u8 +#[no_mangle] +pub fn is_ascii_hexdigit_u8(x: u8) -> bool { + // CHECK-NOT: br + x.is_ascii_hexdigit() +} + +// CHECK-LABEL: @is_ascii_punctuation_char +#[no_mangle] +pub fn is_ascii_punctuation_char(x: char) -> bool { + // CHECK-NOT: br + x.is_ascii_punctuation() +} + +// CHECK-LABEL: @is_ascii_punctuation_u8 +#[no_mangle] +pub fn is_ascii_punctuation_u8(x: u8) -> bool { + // CHECK-NOT: br + x.is_ascii_punctuation() +} diff --git a/tests/codegen-llvm/char-escape-debug-no-bounds-check.rs b/tests/codegen-llvm/char-escape-debug-no-bounds-check.rs new file mode 100644 index 00000000000..cfde46045e5 --- /dev/null +++ b/tests/codegen-llvm/char-escape-debug-no-bounds-check.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +use std::char::EscapeDebug; + +// Make sure no bounds checks are emitted when escaping a character. + +// CHECK-LABEL: @char_escape_debug_no_bounds_check +#[no_mangle] +pub fn char_escape_debug_no_bounds_check(c: char) -> EscapeDebug { + // CHECK-NOT: panic + // CHECK-NOT: panic_bounds_check + c.escape_debug() +} diff --git a/tests/codegen-llvm/checked_ilog.rs b/tests/codegen-llvm/checked_ilog.rs new file mode 100644 index 00000000000..e340a45b6a9 --- /dev/null +++ b/tests/codegen-llvm/checked_ilog.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// Ensure that when val < base, we do not divide or multiply. + +// CHECK-LABEL: @checked_ilog +// CHECK-SAME: (i16{{.*}} %val, i16{{.*}} %base) +#[no_mangle] +pub fn checked_ilog(val: u16, base: u16) -> Option { + // CHECK-NOT: udiv + // CHECK-NOT: mul + // CHECK: %[[IS_LESS:.+]] = icmp ult i16 %val, %base + // CHECK-NEXT: br i1 %[[IS_LESS]], label %[[TRUE:.+]], label %[[FALSE:.+]] + // CHECK: [[TRUE]]: + // CHECK-NOT: udiv + // CHECK-NOT: mul + // CHECK: ret { i32, i32 } + val.checked_ilog(base) +} diff --git a/tests/codegen-llvm/checked_math.rs b/tests/codegen-llvm/checked_math.rs new file mode 100644 index 00000000000..66667c69488 --- /dev/null +++ b/tests/codegen-llvm/checked_math.rs @@ -0,0 +1,100 @@ +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled + +#![crate_type = "lib"] +#![feature(unchecked_shifts)] + +// Because the result of something like `u32::checked_sub` can only be used if it +// didn't overflow, make sure that LLVM actually knows that in optimized builds. +// Thanks to poison semantics, this doesn't even need branches. + +// CHECK-LABEL: @checked_sub_unsigned +// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b) +#[no_mangle] +pub fn checked_sub_unsigned(a: u16, b: u16) -> Option { + // CHECK-DAG: %[[IS_SOME:.+]] = icmp uge i16 %a, %b + // CHECK-DAG: %[[DIFF_P:.+]] = sub nuw i16 %a, %b + // CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i16 + // CHECK-DAG: %[[DIFF_U:.+]] = select i1 %[[IS_SOME]], i16 %[[DIFF_P]], i16 undef + + // CHECK: %[[R0:.+]] = insertvalue { i16, i16 } poison, i16 %[[DISCR]], 0 + // CHECK: %[[R1:.+]] = insertvalue { i16, i16 } %[[R0]], i16 %[[DIFF_U]], 1 + // CHECK: ret { i16, i16 } %[[R1]] + a.checked_sub(b) +} + +// Note that `shl` and `shr` in LLVM are already unchecked. So rather than +// looking for no-wrap flags, we just need there to not be any masking. + +// CHECK-LABEL: @checked_shl_unsigned +// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) +#[no_mangle] +pub fn checked_shl_unsigned(a: u32, b: u32) -> Option { + // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 + // CHECK-DAG: %[[SHIFTED_P:.+]] = shl i32 %a, %b + // CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32 + // CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef + + // CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0 + // CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1 + // CHECK: ret { i32, i32 } %[[R1]] + a.checked_shl(b) +} + +// CHECK-LABEL: @checked_shr_unsigned +// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) +#[no_mangle] +pub fn checked_shr_unsigned(a: u32, b: u32) -> Option { + // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 + // CHECK-DAG: %[[SHIFTED_P:.+]] = lshr i32 %a, %b + // CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32 + // CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef + + // CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0 + // CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1 + // CHECK: ret { i32, i32 } %[[R1]] + a.checked_shr(b) +} + +// CHECK-LABEL: @checked_shl_signed +// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) +#[no_mangle] +pub fn checked_shl_signed(a: i32, b: u32) -> Option { + // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 + // CHECK-DAG: %[[SHIFTED_P:.+]] = shl i32 %a, %b + // CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32 + // CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef + + // CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0 + // CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1 + // CHECK: ret { i32, i32 } %[[R1]] + a.checked_shl(b) +} + +// CHECK-LABEL: @checked_shr_signed +// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) +#[no_mangle] +pub fn checked_shr_signed(a: i32, b: u32) -> Option { + // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 + // CHECK-DAG: %[[SHIFTED_P:.+]] = ashr i32 %a, %b + // CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32 + // CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef + + // CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0 + // CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1 + // CHECK: ret { i32, i32 } %[[R1]] + a.checked_shr(b) +} + +// CHECK-LABEL: @checked_add_one_unwrap_unsigned +// CHECK-SAME: (i32{{.*}} %x) +#[no_mangle] +pub fn checked_add_one_unwrap_unsigned(x: u32) -> u32 { + // CHECK: %[[IS_MAX:.+]] = icmp eq i32 %x, -1 + // CHECK: br i1 %[[IS_MAX]], label %[[NONE_BB:.+]], label %[[SOME_BB:.+]], + // CHECK: [[SOME_BB]]: + // CHECK: %[[R:.+]] = add nuw i32 %x, 1 + // CHECK: ret i32 %[[R]] + // CHECK: [[NONE_BB]]: + // CHECK: call {{.+}}unwrap_failed + x.checked_add(1).unwrap() +} diff --git a/tests/codegen-llvm/clone-shims.rs b/tests/codegen-llvm/clone-shims.rs new file mode 100644 index 00000000000..06c959f9ee7 --- /dev/null +++ b/tests/codegen-llvm/clone-shims.rs @@ -0,0 +1,15 @@ +// Clone shims for aggregates are generated by just calling the Clone shims for all their members. +// Those calls generate a lot of unnecessary IR if the members are Copy. This test ensures that we +// optimize away those inner calls without needing to inline them. + +//@ compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0 -Zinline-mir=no +#![crate_type = "lib"] + +pub type Test = (i32, i32, *const i32); +pub static TEST: fn(&Test) -> Test = ::clone; + +// CHECK-NOT: call ::clone +// CHECK-NOT: call <*const i32 as core::clone::Clone>::clone +// CHECK: ; <(i32, i32, *const i32) as core::clone::Clone>::clone +// CHECK-NOT: call ::clone +// CHECK-NOT: call <*const i32 as core::clone::Clone>::clone diff --git a/tests/codegen-llvm/clone_as_copy.rs b/tests/codegen-llvm/clone_as_copy.rs new file mode 100644 index 00000000000..ef834ef5912 --- /dev/null +++ b/tests/codegen-llvm/clone_as_copy.rs @@ -0,0 +1,40 @@ +//@ revisions: DEBUGINFO NODEBUGINFO +//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes +//@ [DEBUGINFO] compile-flags: -Cdebuginfo=full + +// From https://github.com/rust-lang/rust/issues/128081. +// Ensure that we only generate a memcpy instruction. + +#![crate_type = "lib"] + +#[derive(Clone)] +struct SubCloneAndCopy { + v1: u32, + v2: u32, +} + +#[derive(Clone)] +struct CloneOnly { + v1: u8, + v2: u8, + v3: u8, + v4: u8, + v5: u8, + v6: u8, + v7: u8, + v8: u8, + v9: u8, + v_sub: SubCloneAndCopy, + v_large: [u8; 256], +} + +// CHECK-LABEL: define {{.*}}@clone_only( +#[no_mangle] +pub fn clone_only(v: &CloneOnly) -> CloneOnly { + // CHECK-NOT: call {{.*}}clone + // CHECK-NOT: store i8 + // CHECK-NOT: store i32 + // CHECK: call void @llvm.memcpy + // CHECK-NEXT: ret void + v.clone() +} diff --git a/tests/codegen-llvm/codemodels.rs b/tests/codegen-llvm/codemodels.rs new file mode 100644 index 00000000000..06d2eade78a --- /dev/null +++ b/tests/codegen-llvm/codemodels.rs @@ -0,0 +1,20 @@ +//@ only-x86_64 + +//@ revisions: NOMODEL MODEL-SMALL MODEL-KERNEL MODEL-MEDIUM MODEL-LARGE +//@[NOMODEL] compile-flags: +//@[MODEL-SMALL] compile-flags: -C code-model=small +//@[MODEL-KERNEL] compile-flags: -C code-model=kernel +//@[MODEL-MEDIUM] compile-flags: -C code-model=medium +//@[MODEL-LARGE] compile-flags: -C code-model=large + +#![crate_type = "lib"] + +// MODEL-SMALL: !llvm.module.flags = !{{{.*}}} +// MODEL-SMALL: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 1} +// MODEL-KERNEL: !llvm.module.flags = !{{{.*}}} +// MODEL-KERNEL: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 2} +// MODEL-MEDIUM: !llvm.module.flags = !{{{.*}}} +// MODEL-MEDIUM: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 3} +// MODEL-LARGE: !llvm.module.flags = !{{{.*}}} +// MODEL-LARGE: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 4} +// NOMODEL-NOT: Code Model diff --git a/tests/codegen-llvm/coercions.rs b/tests/codegen-llvm/coercions.rs new file mode 100644 index 00000000000..63c1742c639 --- /dev/null +++ b/tests/codegen-llvm/coercions.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +static X: i32 = 5; + +// CHECK-LABEL: @raw_ptr_to_raw_ptr_noop +// CHECK-NOT: alloca +#[no_mangle] +pub fn raw_ptr_to_raw_ptr_noop() -> *const i32 { + &X as *const i32 +} + +// CHECK-LABEL: @reference_to_raw_ptr_noop +// CHECK-NOT: alloca +#[no_mangle] +pub fn reference_to_raw_ptr_noop() -> *const i32 { + &X +} diff --git a/tests/codegen-llvm/cold-call-declare-and-call.rs b/tests/codegen-llvm/cold-call-declare-and-call.rs new file mode 100644 index 00000000000..b18565ee6c3 --- /dev/null +++ b/tests/codegen-llvm/cold-call-declare-and-call.rs @@ -0,0 +1,27 @@ +//@ revisions: NORMAL WIN +//@ compile-flags: -C no-prepopulate-passes +//@[NORMAL] ignore-windows +//@[WIN] only-windows +//@[WIN] only-x86_64 + +#![crate_type = "lib"] +#![feature(rust_cold_cc)] + +// wasm marks the definition as `dso_local`, so allow that as optional. + +// NORMAL: define{{( dso_local)?}} preserve_mostcc void @this_should_never_happen(i16 +// NORMAL: call preserve_mostcc void @this_should_never_happen(i16 + +// See the comment in `Target::adjust_abi` for why this differs + +// WIN: define void @this_should_never_happen(i16 +// WIN: call void @this_should_never_happen(i16 + +#[no_mangle] +pub extern "rust-cold" fn this_should_never_happen(x: u16) {} + +pub fn do_things(x: u16) { + if x == 12345 { + this_should_never_happen(54321); + } +} diff --git a/tests/codegen-llvm/common_prim_int_ptr.rs b/tests/codegen-llvm/common_prim_int_ptr.rs new file mode 100644 index 00000000000..53716adccbf --- /dev/null +++ b/tests/codegen-llvm/common_prim_int_ptr.rs @@ -0,0 +1,51 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +// Tests that codegen works properly when enums like `Result>` +// are represented as `{ u64, ptr }`, i.e., for `Ok(123)`, `123` is stored +// as a pointer. + +// CHECK-LABEL: @insert_int +#[no_mangle] +pub fn insert_int(x: usize) -> Result> { + // CHECK: start: + // CHECK-NEXT: %[[WO_PROV:.+]] = getelementptr i8, ptr null, [[USIZE:i[0-9]+]] %x + // CHECK-NEXT: %[[R:.+]] = insertvalue { [[USIZE]], ptr } { [[USIZE]] 0, ptr poison }, ptr %[[WO_PROV]], 1 + // CHECK-NEXT: ret { [[USIZE]], ptr } %[[R]] + Ok(x) +} + +// CHECK-LABEL: @insert_box +#[no_mangle] +pub fn insert_box(x: Box<()>) -> Result> { + // CHECK: start: + // CHECK-NEXT: insertvalue { i{{[0-9]+}}, ptr } + // CHECK-NEXT: ret + Err(x) +} + +// CHECK-LABEL: @extract_int +// CHECK-NOT: nonnull +// CHECK-SAME: (i{{[0-9]+}} {{[^%]+}} [[DISCRIMINANT:%[0-9]+]], ptr {{[^,]+}} [[PAYLOAD:%[0-9]+]]) +#[no_mangle] +pub unsafe fn extract_int(x: Result>) -> usize { + // CHECK: [[TEMP:%.+]] = ptrtoint ptr [[PAYLOAD]] to [[USIZE:i[0-9]+]] + // CHECK: ret [[USIZE]] [[TEMP]] + match x { + Ok(v) => v, + Err(_) => std::intrinsics::unreachable(), + } +} + +// CHECK-LABEL: @extract_box +// CHECK-SAME: (i{{[0-9]+}} {{[^%]+}} [[DISCRIMINANT:%[0-9]+]], ptr {{[^%]+}} [[PAYLOAD:%[0-9]+]]) +#[no_mangle] +pub unsafe fn extract_box(x: Result>) -> Box { + // CHECK: ret ptr [[PAYLOAD]] + match x { + Ok(_) => std::intrinsics::unreachable(), + Err(e) => e, + } +} diff --git a/tests/codegen-llvm/comparison-operators-2-struct.rs b/tests/codegen-llvm/comparison-operators-2-struct.rs new file mode 100644 index 00000000000..e179066ebfd --- /dev/null +++ b/tests/codegen-llvm/comparison-operators-2-struct.rs @@ -0,0 +1,61 @@ +//@ compile-flags: -C opt-level=1 +//@ min-llvm-version: 20 + +// The `derive(PartialOrd)` for a 2-field type doesn't override `lt`/`le`/`gt`/`ge`. +// This double-checks that the `Option` intermediate values used +// in the operators for such a type all optimize away. + +#![crate_type = "lib"] + +use std::cmp::Ordering; + +#[derive(PartialOrd, PartialEq)] +pub struct Foo(i32, u32); + +// CHECK-LABEL: @check_lt( +// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]]) +#[no_mangle] +pub fn check_lt(a: Foo, b: Foo) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]] + // CHECK-DAG: %[[R0:.+]] = icmp slt i32 %[[A0]], %[[B0]] + // CHECK-DAG: %[[R1:.+]] = icmp ult i32 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]] + // CHECK-NEXT: ret i1 %[[R]] + a < b +} + +// CHECK-LABEL: @check_le( +// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]]) +#[no_mangle] +pub fn check_le(a: Foo, b: Foo) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]] + // CHECK-DAG: %[[R0:.+]] = icmp sle i32 %[[A0]], %[[B0]] + // CHECK-DAG: %[[R1:.+]] = icmp ule i32 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]] + // CHECK-NEXT: ret i1 %[[R]] + a <= b +} + +// CHECK-LABEL: @check_gt( +// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]]) +#[no_mangle] +pub fn check_gt(a: Foo, b: Foo) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]] + // CHECK-DAG: %[[R0:.+]] = icmp sgt i32 %[[A0]], %[[B0]] + // CHECK-DAG: %[[R1:.+]] = icmp ugt i32 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]] + // CHECK-NEXT: ret i1 %[[R]] + a > b +} + +// CHECK-LABEL: @check_ge( +// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]]) +#[no_mangle] +pub fn check_ge(a: Foo, b: Foo) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]] + // CHECK-DAG: %[[R0:.+]] = icmp sge i32 %[[A0]], %[[B0]] + // CHECK-DAG: %[[R1:.+]] = icmp uge i32 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]] + // CHECK-NEXT: ret i1 %[[R]] + a >= b +} diff --git a/tests/codegen-llvm/comparison-operators-2-tuple.rs b/tests/codegen-llvm/comparison-operators-2-tuple.rs new file mode 100644 index 00000000000..6a7e489c82d --- /dev/null +++ b/tests/codegen-llvm/comparison-operators-2-tuple.rs @@ -0,0 +1,117 @@ +//@ compile-flags: -C opt-level=1 -Z merge-functions=disabled +//@ min-llvm-version: 20 + +#![crate_type = "lib"] + +use std::cmp::Ordering; + +type TwoTuple = (i16, u16); + +// +// The operators are all overridden directly, so should optimize easily. +// +// slt-vs-sle and sgt-vs-sge don't matter because they're only used in the side +// of the select where we know the values are not equal, and thus the tests +// use a regex to allow either, since unimportant changes to the implementation +// sometimes result in changing what LLVM decides to emit for this. +// + +// CHECK-LABEL: @check_lt_direct +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_lt_direct(a: TwoTuple, b: TwoTuple) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP0:.+]] = icmp {{slt|sle}} i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP1:.+]] = icmp ult i16 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // CHECK: ret i1 %[[R]] + a < b +} + +// CHECK-LABEL: @check_le_direct +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_le_direct(a: TwoTuple, b: TwoTuple) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP0:.+]] = icmp {{slt|sle}} i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP1:.+]] = icmp ule i16 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // CHECK: ret i1 %[[R]] + a <= b +} + +// CHECK-LABEL: @check_gt_direct +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_gt_direct(a: TwoTuple, b: TwoTuple) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP0:.+]] = icmp {{sgt|sge}} i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP1:.+]] = icmp ugt i16 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // CHECK: ret i1 %[[R]] + a > b +} + +// CHECK-LABEL: @check_ge_direct +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_ge_direct(a: TwoTuple, b: TwoTuple) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP0:.+]] = icmp {{sgt|sge}} i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP1:.+]] = icmp uge i16 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // CHECK: ret i1 %[[R]] + a >= b +} + +// +// These used to not optimize as well, but thanks to LLVM 20 they work now 🎉 +// + +// CHECK-LABEL: @check_lt_via_cmp +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_lt_via_cmp(a: TwoTuple, b: TwoTuple) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP0:.+]] = icmp slt i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP1:.+]] = icmp ult i16 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // CHECK: ret i1 %[[R]] + Ord::cmp(&a, &b).is_lt() +} + +// CHECK-LABEL: @check_le_via_cmp +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_le_via_cmp(a: TwoTuple, b: TwoTuple) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP0:.+]] = icmp sle i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP1:.+]] = icmp ule i16 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // CHECK: ret i1 %[[R]] + Ord::cmp(&a, &b).is_le() +} + +// CHECK-LABEL: @check_gt_via_cmp +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_gt_via_cmp(a: TwoTuple, b: TwoTuple) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP0:.+]] = icmp sgt i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP1:.+]] = icmp ugt i16 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // CHECK: ret i1 %[[R]] + Ord::cmp(&a, &b).is_gt() +} + +// CHECK-LABEL: @check_ge_via_cmp +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_ge_via_cmp(a: TwoTuple, b: TwoTuple) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP0:.+]] = icmp sge i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP1:.+]] = icmp uge i16 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // CHECK: ret i1 %[[R]] + Ord::cmp(&a, &b).is_ge() +} diff --git a/tests/codegen-llvm/comparison-operators-newtype.rs b/tests/codegen-llvm/comparison-operators-newtype.rs new file mode 100644 index 00000000000..acce0cb5946 --- /dev/null +++ b/tests/codegen-llvm/comparison-operators-newtype.rs @@ -0,0 +1,48 @@ +// The `derive(PartialOrd)` for a newtype doesn't override `lt`/`le`/`gt`/`ge`. +// This double-checks that the `Option` intermediate values used +// in the operators for such a type all optimize away. + +//@ compile-flags: -C opt-level=1 + +#![crate_type = "lib"] + +use std::cmp::Ordering; + +#[derive(PartialOrd, PartialEq)] +pub struct Foo(u16); + +// CHECK-LABEL: @check_lt +// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) +#[no_mangle] +pub fn check_lt(a: Foo, b: Foo) -> bool { + // CHECK: %[[R:.+]] = icmp ult i16 %[[A]], %[[B]] + // CHECK-NEXT: ret i1 %[[R]] + a < b +} + +// CHECK-LABEL: @check_le +// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) +#[no_mangle] +pub fn check_le(a: Foo, b: Foo) -> bool { + // CHECK: %[[R:.+]] = icmp ule i16 %[[A]], %[[B]] + // CHECK-NEXT: ret i1 %[[R]] + a <= b +} + +// CHECK-LABEL: @check_gt +// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) +#[no_mangle] +pub fn check_gt(a: Foo, b: Foo) -> bool { + // CHECK: %[[R:.+]] = icmp ugt i16 %[[A]], %[[B]] + // CHECK-NEXT: ret i1 %[[R]] + a > b +} + +// CHECK-LABEL: @check_ge +// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) +#[no_mangle] +pub fn check_ge(a: Foo, b: Foo) -> bool { + // CHECK: %[[R:.+]] = icmp uge i16 %[[A]], %[[B]] + // CHECK-NEXT: ret i1 %[[R]] + a >= b +} diff --git a/tests/codegen-llvm/compiletest-self-test/minicore-smoke-test.rs b/tests/codegen-llvm/compiletest-self-test/minicore-smoke-test.rs new file mode 100644 index 00000000000..9dd1bf29c6c --- /dev/null +++ b/tests/codegen-llvm/compiletest-self-test/minicore-smoke-test.rs @@ -0,0 +1,20 @@ +//! Basic smoke test for `minicore` test auxiliary. + +//@ add-core-stubs +//@ compile-flags: --target=x86_64-unknown-linux-gnu +//@ needs-llvm-components: x86 + +#![crate_type = "lib"] +#![feature(no_core)] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +struct Meow; +impl Copy for Meow {} + +// CHECK-LABEL: meow +#[no_mangle] +fn meow() {} diff --git a/tests/codegen-llvm/const-array.rs b/tests/codegen-llvm/const-array.rs new file mode 100644 index 00000000000..b3df76c3d8e --- /dev/null +++ b/tests/codegen-llvm/const-array.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +const LUT: [u8; 4] = [1, 1, 1, 1]; + +// CHECK-LABEL: @decode +#[no_mangle] +pub fn decode(i: u8) -> u8 { + // CHECK: start: + // CHECK-NEXT: icmp + // CHECK-NEXT: select + // CHECK-NEXT: ret + if i < 4 { LUT[i as usize] } else { 2 } +} diff --git a/tests/codegen-llvm/const-vector.rs b/tests/codegen-llvm/const-vector.rs new file mode 100644 index 00000000000..a2249f4fff7 --- /dev/null +++ b/tests/codegen-llvm/const-vector.rs @@ -0,0 +1,78 @@ +//@ revisions: OPT0 OPT0_S390X +//@ [OPT0] ignore-s390x +//@ [OPT0_S390X] only-s390x +//@ [OPT0] compile-flags: -C no-prepopulate-passes -Copt-level=0 +//@ [OPT0_S390X] compile-flags: -C no-prepopulate-passes -Copt-level=0 -C target-cpu=z13 + +// This test checks that constants of SIMD type are passed as immediate vectors. +// We ensure that both vector representations (struct with fields and struct wrapping array) work. +#![crate_type = "lib"] +#![feature(abi_unadjusted)] +#![feature(const_trait_impl)] +#![feature(repr_simd)] +#![feature(rustc_attrs)] +#![feature(simd_ffi)] +#![feature(arm_target_feature)] +#![feature(mips_target_feature)] +#![allow(non_camel_case_types)] + +#[path = "../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::{PackedSimd as Simd, f32x2, i8x2}; + +// The following functions are required for the tests to ensure +// that they are called with a const vector + +extern "unadjusted" { + fn test_i8x2(a: i8x2); + fn test_i8x2_two_args(a: i8x2, b: i8x2); + fn test_i8x2_mixed_args(a: i8x2, c: i32, b: i8x2); + fn test_i8x2_arr(a: i8x2); + fn test_f32x2(a: f32x2); + fn test_f32x2_arr(a: f32x2); + fn test_simd(a: Simd); + fn test_simd_unaligned(a: Simd); +} + +// Ensure the packed variant of the simd struct does not become a const vector +// if the size is not a power of 2 +// CHECK: %"minisimd::PackedSimd" = type { [3 x i32] } + +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +pub fn do_call() { + unsafe { + // CHECK: call void @test_i8x2(<2 x i8> + test_i8x2(const { i8x2::from_array([32, 64]) }); + + // CHECK: call void @test_i8x2_two_args(<2 x i8> , <2 x i8> + test_i8x2_two_args( + const { i8x2::from_array([32, 64]) }, + const { i8x2::from_array([8, 16]) }, + ); + + // CHECK: call void @test_i8x2_mixed_args(<2 x i8> , i32 43, <2 x i8> + test_i8x2_mixed_args( + const { i8x2::from_array([32, 64]) }, + 43, + const { i8x2::from_array([8, 16]) }, + ); + + // CHECK: call void @test_i8x2_arr(<2 x i8> + test_i8x2_arr(const { i8x2::from_array([32, 64]) }); + + // CHECK: call void @test_f32x2(<2 x float> + test_f32x2(const { f32x2::from_array([0.32, 0.64]) }); + + // CHECK: void @test_f32x2_arr(<2 x float> + test_f32x2_arr(const { f32x2::from_array([0.32, 0.64]) }); + + // CHECK: call void @test_simd(<4 x i32> + test_simd(const { Simd::([2, 4, 6, 8]) }); + + // CHECK: call void @test_simd_unaligned(%"minisimd::PackedSimd" %1 + test_simd_unaligned(const { Simd::([2, 4, 6]) }); + } +} diff --git a/tests/codegen-llvm/const_scalar_pair.rs b/tests/codegen-llvm/const_scalar_pair.rs new file mode 100644 index 00000000000..f142896c31f --- /dev/null +++ b/tests/codegen-llvm/const_scalar_pair.rs @@ -0,0 +1,8 @@ +//@ compile-flags: --crate-type=lib -Copt-level=0 -Zmir-opt-level=0 -C debuginfo=2 + +// Test that we don't generate a memory allocation for the constant +// and read the fields from that, but instead just create the value pair directly. +pub fn foo() -> (i32, i32) { + // CHECK: ret { i32, i32 } { i32 1, i32 2 } + const { (1, 2) } +} diff --git a/tests/codegen-llvm/constant-branch.rs b/tests/codegen-llvm/constant-branch.rs new file mode 100644 index 00000000000..8fc8fb4f57a --- /dev/null +++ b/tests/codegen-llvm/constant-branch.rs @@ -0,0 +1,49 @@ +//@ compile-flags: -Zmir-opt-level=0 -C no-prepopulate-passes -Copt-level=0 +// make sure that branching on a constant does not emit a conditional +// branch or a switch + +#![crate_type = "lib"] + +// CHECK-LABEL: @if_bool +#[no_mangle] +pub fn if_bool() { + // CHECK-NOT: br i1 + // CHECK-NOT: switch + _ = if true { 0 } else { 1 }; + + _ = if false { 0 } else { 1 }; +} + +// CHECK-LABEL: @if_constant_int_eq +#[no_mangle] +pub fn if_constant_int_eq() { + // CHECK-NOT: br i1 + // CHECK-NOT: switch + let val = 0; + _ = if val == 0 { 0 } else { 1 }; + + // CHECK: br label %{{.+}} + _ = if val == 1 { 0 } else { 1 }; +} + +// CHECK-LABEL: @if_constant_match +#[no_mangle] +pub fn if_constant_match() { + // CHECK-NOT: br i1 + // CHECK-NOT: switch + _ = match 1 { + 1 => 2, + 2 => 3, + _ => 4, + }; + + _ = match 1 { + 2 => 3, + _ => 4, + }; + + _ = match -1 { + -1 => 1, + _ => 0, + } +} diff --git a/tests/codegen-llvm/consts.rs b/tests/codegen-llvm/consts.rs new file mode 100644 index 00000000000..42ce7679d1a --- /dev/null +++ b/tests/codegen-llvm/consts.rs @@ -0,0 +1,55 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +// Below, these constants are defined as enum variants that by itself would +// have a lower alignment than the enum type. Ensure that we mark them +// correctly with the higher alignment of the enum. + +// CHECK: @STATIC = {{.*}}, align 4 + +// This checks the constants from inline_enum_const +// CHECK: @alloc_[[INLINE_ENUM_HASH:[a-f0-9]{32}]] = {{.*}}, align 2 + +// This checks the constants from {low,high}_align_const, they share the same +// constant, but the alignment differs, so the higher one should be used +// CHECK: [[LOW_HIGH:@alloc_[a-f0-9]{32}]] = {{.*}}, align 4 + +#[derive(Copy, Clone)] +// repr(i16) is required for the {low,high}_align_const test +#[repr(i16)] +pub enum E { + A(A), + B(B), +} + +#[no_mangle] +pub static STATIC: E = E::A(0); + +// CHECK-LABEL: @static_enum_const +#[no_mangle] +pub fn static_enum_const() -> E { + STATIC +} + +// CHECK-LABEL: @inline_enum_const +#[no_mangle] +pub fn inline_enum_const() -> E { + *&E::A(0) +} + +// CHECK-LABEL: @low_align_const +#[no_mangle] +pub fn low_align_const() -> E { + // Check that low_align_const and high_align_const use the same constant + // CHECK: memcpy.{{.+}}(ptr align 2 %_0, ptr align 2 {{.*}}[[LOW_HIGH]]{{.*}}, i{{(32|64)}} 8, i1 false) + *&E::A(0) +} + +// CHECK-LABEL: @high_align_const +#[no_mangle] +pub fn high_align_const() -> E { + // Check that low_align_const and high_align_const use the same constant + // CHECK: memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[LOW_HIGH]]{{.*}}, i{{(32|64)}} 8, i1 false) + *&E::A(0) +} diff --git a/tests/codegen-llvm/coroutine-debug-msvc.rs b/tests/codegen-llvm/coroutine-debug-msvc.rs new file mode 100644 index 00000000000..9e2ec3ea28a --- /dev/null +++ b/tests/codegen-llvm/coroutine-debug-msvc.rs @@ -0,0 +1,60 @@ +// Verify debuginfo for coroutines: +// - Each variant points to the file and line of its yield point +// - The discriminants are marked artificial +// - Other fields are not marked artificial +// +// +//@ compile-flags: -C debuginfo=2 +//@ only-msvc + +#![feature(coroutines, coroutine_trait)] +use std::ops::Coroutine; + +fn coroutine_test() -> impl Coroutine { + #[coroutine] + || { + yield 0; + let s = String::from("foo"); + yield 1; + } +} + +// FIXME: No way to reliably check the filename. + +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$" +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]], +// For brevity, we only check the struct name and members of the last variant. +// CHECK-SAME: file: [[FILE:![0-9]*]], line: 15, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 19, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 19, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 16, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 18, +// CHECK-SAME: baseType: [[VARIANT_WRAPPER:![0-9]*]] +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: [[VARIANT_WRAPPER]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Variant4", scope: [[GEN]], +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "value", scope: [[VARIANT_WRAPPER]], {{.*}}, baseType: [[VARIANT:![0-9]*]], +// CHECK: [[VARIANT]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[VARIANT]] +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "tag", scope: [[GEN]], +// CHECK-NOT: flags: DIFlagArtificial + +fn main() { + let _dummy = coroutine_test(); +} diff --git a/tests/codegen-llvm/coroutine-debug.rs b/tests/codegen-llvm/coroutine-debug.rs new file mode 100644 index 00000000000..ff62e9709b4 --- /dev/null +++ b/tests/codegen-llvm/coroutine-debug.rs @@ -0,0 +1,64 @@ +// Verify debuginfo for coroutines: +// - Each variant points to the file and line of its yield point +// - The discriminants are marked artificial +// - Other fields are not marked artificial +// +// +//@ compile-flags: -C debuginfo=2 +//@ edition: 2018 +//@ ignore-msvc + +#![feature(coroutines, coroutine_trait)] +use std::ops::Coroutine; + +fn coroutine_test() -> impl Coroutine { + #[coroutine] + || { + yield 0; + let s = String::from("foo"); + yield 1; + } +} + +// FIXME: No way to reliably check the filename. + +// CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "coroutine_test" +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{coroutine_env#0}", scope: [[GEN_FN]] +// CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[GEN]], +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: discriminator: [[DISC:![0-9]*]] +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE:![0-9]*]], line: 16, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]], +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 20, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 20, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 17, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 19, +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: [[DISC]] = !DIDerivedType(tag: DW_TAG_member, name: "__state", scope: [[GEN]], +// CHECK-SAME: flags: DIFlagArtificial + +fn main() { + let _dummy = coroutine_test(); +} diff --git a/tests/codegen-llvm/cross-crate-inlining/always-inline.rs b/tests/codegen-llvm/cross-crate-inlining/always-inline.rs new file mode 100644 index 00000000000..df28b3fe197 --- /dev/null +++ b/tests/codegen-llvm/cross-crate-inlining/always-inline.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -Copt-level=3 +//@ aux-build:always.rs + +#![crate_type = "lib"] + +extern crate always; + +// Check that we inline a cross-crate call, even though it isn't a leaf +#[no_mangle] +pub fn outer() -> String { + // CHECK-NOT: call {{.*}}stem_fn + always::stem_fn() +} diff --git a/tests/codegen-llvm/cross-crate-inlining/auxiliary/always.rs b/tests/codegen-llvm/cross-crate-inlining/auxiliary/always.rs new file mode 100644 index 00000000000..6ee3f81e3c8 --- /dev/null +++ b/tests/codegen-llvm/cross-crate-inlining/auxiliary/always.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -Copt-level=3 -Zcross-crate-inline-threshold=always + +#![crate_type = "lib"] + +// This function *looks* like it contains a call, but that call will be optimized out by MIR +// optimizations. +pub fn leaf_fn() -> String { + String::new() +} + +// This function contains a call, even after MIR optimizations. It is only eligible for +// cross-crate-inlining with "always". +pub fn stem_fn() -> String { + inner() +} + +#[inline(never)] +fn inner() -> String { + String::from("test") +} diff --git a/tests/codegen-llvm/cross-crate-inlining/auxiliary/leaf.rs b/tests/codegen-llvm/cross-crate-inlining/auxiliary/leaf.rs new file mode 100644 index 00000000000..d059a3d0a73 --- /dev/null +++ b/tests/codegen-llvm/cross-crate-inlining/auxiliary/leaf.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// This function *looks* like it contains a call, but that call will be optimized out by MIR +// optimizations. +pub fn leaf_fn() -> String { + String::new() +} + +// This function contains a call, even after MIR optimizations. It is only eligible for +// cross-crate-inlining with "always". +pub fn stem_fn() -> String { + inner() +} + +#[inline(never)] +fn inner() -> String { + String::from("test") +} diff --git a/tests/codegen-llvm/cross-crate-inlining/auxiliary/never.rs b/tests/codegen-llvm/cross-crate-inlining/auxiliary/never.rs new file mode 100644 index 00000000000..55c90809ec1 --- /dev/null +++ b/tests/codegen-llvm/cross-crate-inlining/auxiliary/never.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -Copt-level=3 -Zcross-crate-inline-threshold=never + +#![crate_type = "lib"] + +// This function *looks* like it contains a call, but that call will be optimized out by MIR +// optimizations. +pub fn leaf_fn() -> String { + String::new() +} + +// This function contains a call, even after MIR optimizations. It is only eligible for +// cross-crate-inlining with "always". +pub fn stem_fn() -> String { + inner() +} + +#[inline(never)] +fn inner() -> String { + String::from("test") +} diff --git a/tests/codegen-llvm/cross-crate-inlining/leaf-inlining.rs b/tests/codegen-llvm/cross-crate-inlining/leaf-inlining.rs new file mode 100644 index 00000000000..37132312ca9 --- /dev/null +++ b/tests/codegen-llvm/cross-crate-inlining/leaf-inlining.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -Copt-level=3 -Zcross-crate-inline-threshold=yes +//@ aux-build:leaf.rs + +#![crate_type = "lib"] + +extern crate leaf; + +// Check that we inline a leaf cross-crate call +#[no_mangle] +pub fn leaf_outer() -> String { + // CHECK-NOT: call {{.*}}leaf_fn + leaf::leaf_fn() +} + +// Check that we do not inline a non-leaf cross-crate call +#[no_mangle] +pub fn stem_outer() -> String { + // CHECK: call {{.*}}stem_fn + leaf::stem_fn() +} diff --git a/tests/codegen-llvm/cross-crate-inlining/never-inline.rs b/tests/codegen-llvm/cross-crate-inlining/never-inline.rs new file mode 100644 index 00000000000..759f65d9d42 --- /dev/null +++ b/tests/codegen-llvm/cross-crate-inlining/never-inline.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -Copt-level=3 +//@ aux-build:never.rs + +#![crate_type = "lib"] + +extern crate never; + +// Check that we do not inline a cross-crate call, even though it is a leaf +#[no_mangle] +pub fn outer() -> String { + // CHECK: call {{.*}}leaf_fn + never::leaf_fn() +} diff --git a/tests/codegen-llvm/dealloc-no-unwind.rs b/tests/codegen-llvm/dealloc-no-unwind.rs new file mode 100644 index 00000000000..68597817d6f --- /dev/null +++ b/tests/codegen-llvm/dealloc-no-unwind.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +struct A; + +impl Drop for A { + fn drop(&mut self) { + extern "C" { + fn foo(); + } + unsafe { + foo(); + } + } +} + +#[no_mangle] +pub fn a(a: Box) { + // CHECK-LABEL: define{{.*}}void @a + // CHECK: call void @{{.*}}__rust_dealloc + // CHECK-NEXT: call void @foo + let _a = A; + drop(a); +} diff --git a/tests/codegen-llvm/debug-accessibility/crate-enum.rs b/tests/codegen-llvm/debug-accessibility/crate-enum.rs new file mode 100644 index 00000000000..9ad5a6fd0ff --- /dev/null +++ b/tests/codegen-llvm/debug-accessibility/crate-enum.rs @@ -0,0 +1,28 @@ +// ignore-tidy-linelength +//! Checks that visibility information is present in the debuginfo for crate-visibility enums. + +//@ revisions: MSVC NONMSVC +//@[MSVC] only-msvc +//@[NONMSVC] ignore-msvc + +//@ compile-flags: -C debuginfo=2 + +mod module { + use std::hint::black_box; + + pub(crate) enum CrateFooEnum { + A, + B(u32), + C { x: u32 }, + } + + // NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "CrateFooEnum"{{.*}}flags: DIFlagProtected{{.*}}) + // MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$"{{.*}}flags: DIFlagProtected{{.*}}) + pub fn use_everything() { + black_box(CrateFooEnum::A); + } +} + +fn main() { + module::use_everything(); +} diff --git a/tests/codegen-llvm/debug-accessibility/crate-struct.rs b/tests/codegen-llvm/debug-accessibility/crate-struct.rs new file mode 100644 index 00000000000..73a8ce852ed --- /dev/null +++ b/tests/codegen-llvm/debug-accessibility/crate-struct.rs @@ -0,0 +1,23 @@ +//@ compile-flags: -C debuginfo=2 + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for crate-visibility structs. + +mod module { + use std::hint::black_box; + + pub(crate) struct CrateFooStruct { + x: u32, + } + + // CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "CrateFooStruct"{{.*}}flags: DIFlagProtected{{.*}}) + + pub fn use_everything() { + black_box(CrateFooStruct { x: 2 }); + } +} + +fn main() { + module::use_everything(); +} diff --git a/tests/codegen-llvm/debug-accessibility/private-enum.rs b/tests/codegen-llvm/debug-accessibility/private-enum.rs new file mode 100644 index 00000000000..002336c03b3 --- /dev/null +++ b/tests/codegen-llvm/debug-accessibility/private-enum.rs @@ -0,0 +1,22 @@ +// ignore-tidy-linelength +//! Checks that visibility information is present in the debuginfo for private enums. + +//@ revisions: MSVC NONMSVC +//@[MSVC] only-msvc +//@[NONMSVC] ignore-msvc +//@ compile-flags: -C debuginfo=2 + +use std::hint::black_box; + +enum PrivateFooEnum { + A, + B(u32), + C { x: u32 }, +} + +// NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PrivateFooEnum"{{.*}}flags: DIFlagPrivate{{.*}}) +// MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$"{{.*}}flags: DIFlagPrivate{{.*}}) + +fn main() { + black_box(PrivateFooEnum::A); +} diff --git a/tests/codegen-llvm/debug-accessibility/private-struct.rs b/tests/codegen-llvm/debug-accessibility/private-struct.rs new file mode 100644 index 00000000000..488a680e81c --- /dev/null +++ b/tests/codegen-llvm/debug-accessibility/private-struct.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -C debuginfo=2 + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for private structs. + +use std::hint::black_box; + +struct PrivateFooStruct { + x: u32, +} + +// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PrivateFooStruct"{{.*}}flags: DIFlagPrivate{{.*}}) + +fn main() { + black_box(PrivateFooStruct { x: 1 }); +} diff --git a/tests/codegen-llvm/debug-accessibility/public-enum.rs b/tests/codegen-llvm/debug-accessibility/public-enum.rs new file mode 100644 index 00000000000..e5cd1ab7350 --- /dev/null +++ b/tests/codegen-llvm/debug-accessibility/public-enum.rs @@ -0,0 +1,23 @@ +// ignore-tidy-linelength +//! Checks that visibility information is present in the debuginfo for types and their fields. + +//@ revisions: MSVC NONMSVC +//@[MSVC] only-msvc +//@[NONMSVC] ignore-msvc + +//@ compile-flags: -C debuginfo=2 + +use std::hint::black_box; + +pub enum PublicFooEnum { + A, + B(u32), + C { x: u32 }, +} + +// NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PublicFooEnum"{{.*}}flags: DIFlagPublic{{.*}}) +// MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$"{{.*}}flags: DIFlagPublic{{.*}}) + +fn main() { + black_box(PublicFooEnum::A); +} diff --git a/tests/codegen-llvm/debug-accessibility/public-struct.rs b/tests/codegen-llvm/debug-accessibility/public-struct.rs new file mode 100644 index 00000000000..8b2a53f993c --- /dev/null +++ b/tests/codegen-llvm/debug-accessibility/public-struct.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -C debuginfo=2 + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for public structs. + +use std::hint::black_box; + +pub struct PublicFooStruct { + x: u32, +} + +// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PublicFooStruct"{{.*}}flags: DIFlagPublic{{.*}}) + +fn main() { + black_box(PublicFooStruct { x: 4 }); +} diff --git a/tests/codegen-llvm/debug-accessibility/struct-fields.rs b/tests/codegen-llvm/debug-accessibility/struct-fields.rs new file mode 100644 index 00000000000..f68bb3438be --- /dev/null +++ b/tests/codegen-llvm/debug-accessibility/struct-fields.rs @@ -0,0 +1,30 @@ +//@ compile-flags: -C debuginfo=2 + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for struct fields. + +mod module { + use std::hint::black_box; + + struct StructFields { + a: u32, + pub(crate) b: u32, + pub(super) c: u32, + pub d: u32, + } + + // CHECK: [[StructFields:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "StructFields"{{.*}}flags: DIFlagPrivate{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: [[StructFields]]{{.*}}flags: DIFlagPrivate{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: [[StructFields]]{{.*}}flags: DIFlagProtected{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: [[StructFields]]{{.*}}flags: DIFlagProtected{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: [[StructFields]]{{.*}}flags: DIFlagPublic{{.*}}) + + pub fn use_everything() { + black_box(StructFields { a: 1, b: 2, c: 3, d: 4 }); + } +} + +fn main() { + module::use_everything(); +} diff --git a/tests/codegen-llvm/debug-accessibility/super-enum.rs b/tests/codegen-llvm/debug-accessibility/super-enum.rs new file mode 100644 index 00000000000..8e34d8be01f --- /dev/null +++ b/tests/codegen-llvm/debug-accessibility/super-enum.rs @@ -0,0 +1,28 @@ +// ignore-tidy-linelength +//! Checks that visibility information is present in the debuginfo for super-visibility enums. + +//@ revisions: MSVC NONMSVC +//@[MSVC] only-msvc +//@[NONMSVC] ignore-msvc +//@ compile-flags: -C debuginfo=2 + +mod module { + use std::hint::black_box; + + pub(super) enum SuperFooEnum { + A, + B(u32), + C { x: u32 }, + } + + // NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "SuperFooEnum"{{.*}}flags: DIFlagProtected{{.*}}) + // MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$"{{.*}}flags: DIFlagProtected{{.*}}) + + pub fn use_everything() { + black_box(SuperFooEnum::A); + } +} + +fn main() { + module::use_everything(); +} diff --git a/tests/codegen-llvm/debug-accessibility/super-struct.rs b/tests/codegen-llvm/debug-accessibility/super-struct.rs new file mode 100644 index 00000000000..63954bfb203 --- /dev/null +++ b/tests/codegen-llvm/debug-accessibility/super-struct.rs @@ -0,0 +1,23 @@ +//@ compile-flags: -C debuginfo=2 + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for super-visibility structs. + +mod module { + use std::hint::black_box; + + pub(super) struct SuperFooStruct { + x: u32, + } + + // CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "SuperFooStruct"{{.*}}flags: DIFlagProtected{{.*}}) + + pub fn use_everything() { + black_box(SuperFooStruct { x: 3 }); + } +} + +fn main() { + module::use_everything(); +} diff --git a/tests/codegen-llvm/debug-accessibility/tuple-fields.rs b/tests/codegen-llvm/debug-accessibility/tuple-fields.rs new file mode 100644 index 00000000000..feec6e9eb41 --- /dev/null +++ b/tests/codegen-llvm/debug-accessibility/tuple-fields.rs @@ -0,0 +1,24 @@ +//@ compile-flags: -C debuginfo=2 + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for tuple struct fields. + +mod module { + use std::hint::black_box; + + struct TupleFields(u32, pub(crate) u32, pub(super) u32, pub u32); + + // CHECK: [[TupleFields:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "TupleFields"{{.*}}flags: DIFlagPrivate{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__0", scope: [[TupleFields]]{{.*}}flags: DIFlagPrivate{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__1", scope: [[TupleFields]]{{.*}}flags: DIFlagProtected{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__2", scope: [[TupleFields]]{{.*}}flags: DIFlagProtected{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__3", scope: [[TupleFields]]{{.*}}flags: DIFlagPublic{{.*}}) + pub fn use_everything() { + black_box(TupleFields(1, 2, 3, 4)); + } +} + +fn main() { + module::use_everything(); +} diff --git a/tests/codegen-llvm/debug-alignment.rs b/tests/codegen-llvm/debug-alignment.rs new file mode 100644 index 00000000000..02fe05832a3 --- /dev/null +++ b/tests/codegen-llvm/debug-alignment.rs @@ -0,0 +1,8 @@ +// Verifies that DWARF alignment is specified properly. +// +//@ compile-flags: -C debuginfo=2 +#![crate_type = "lib"] + +// CHECK: !DIGlobalVariable +// CHECK: align: 32 +pub static A: u32 = 1; diff --git a/tests/codegen-llvm/debug-column-msvc.rs b/tests/codegen-llvm/debug-column-msvc.rs new file mode 100644 index 00000000000..39f77f41329 --- /dev/null +++ b/tests/codegen-llvm/debug-column-msvc.rs @@ -0,0 +1,16 @@ +// Verify that no column information is emitted for MSVC targets +// +//@ only-msvc +//@ compile-flags: -C debuginfo=2 + +// CHECK-NOT: !DILexicalBlock({{.*}}column: {{.*}}) +// CHECK-NOT: !DILocation({{.*}}column: {{.*}}) + +pub fn add(a: u32, b: u32) -> u32 { + a + b +} + +fn main() { + let c = add(1, 2); + println!("{}", c); +} diff --git a/tests/codegen-llvm/debug-column.rs b/tests/codegen-llvm/debug-column.rs new file mode 100644 index 00000000000..2aa0a8a864c --- /dev/null +++ b/tests/codegen-llvm/debug-column.rs @@ -0,0 +1,25 @@ +// Verify that debuginfo column numbers are 1-based byte offsets. +// +//@ ignore-msvc +//@ compile-flags: -C debuginfo=2 + +#[rustfmt::skip] +fn main() { + unsafe { + // Column numbers are 1-based. Regression test for #65437. + // CHECK: call void @giraffe(){{( #[0-9]+)?}}, !dbg [[A:!.*]] + giraffe(); + + // Column numbers use byte offests. Regression test for #67360 + // CHECK: call void @turtle(){{( #[0-9]+)?}}, !dbg [[B:!.*]] +/* ż */ turtle(); + + // CHECK: [[A]] = !DILocation(line: 11, column: 9, + // CHECK: [[B]] = !DILocation(line: 15, column: 10, + } +} + +extern "C" { + fn giraffe(); + fn turtle(); +} diff --git a/tests/codegen-llvm/debug-compile-unit-path.rs b/tests/codegen-llvm/debug-compile-unit-path.rs new file mode 100644 index 00000000000..6131d9d7351 --- /dev/null +++ b/tests/codegen-llvm/debug-compile-unit-path.rs @@ -0,0 +1,9 @@ +//@ compile-flags: -g --remap-path-prefix={{cwd}}=/cwd/ --remap-path-prefix={{src-base}}=/base/ +// +// +// Ensure that we remap the compile unit directory and that we set it to the compilers current +// working directory and not something else. +#![crate_type = "rlib"] + +// CHECK-DAG: [[FILE:![0-9]*]] = !DIFile(filename: "/base/debug-compile-unit-path.rs{{.*}}", directory: "/cwd/") +// CHECK-DAG: {{![0-9]*}} = distinct !DICompileUnit({{.*}}file: [[FILE]] diff --git a/tests/codegen-llvm/debug-fndef-size.rs b/tests/codegen-llvm/debug-fndef-size.rs new file mode 100644 index 00000000000..8f716c34e7b --- /dev/null +++ b/tests/codegen-llvm/debug-fndef-size.rs @@ -0,0 +1,20 @@ +// Verify that `i32::cmp` FnDef type is declared with a size of 0 and an +// alignment of 8 bits (1 byte) in LLVM debuginfo. + +//@ compile-flags: -Copt-level=3 -g -Cno-prepopulate-passes +//@ ignore-msvc the types are mangled differently + +use std::cmp::Ordering; + +fn foo Ordering>(v1: i32, v2: i32, compare: F) -> Ordering { + compare(&v1, &v2) +} + +pub fn main() { + foo(0, 1, i32::cmp); +} + +// CHECK: %compare.dbg.spill = alloca [0 x i8], align 1 +// CHECK: dbg{{.}}declare({{(metadata )?}}ptr %compare.dbg.spill, {{(metadata )?}}![[VAR:.*]], {{(metadata )?}}!DIExpression() +// CHECK: ![[TYPE:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "fn(&i32, &i32) -> core::cmp::Ordering", baseType: !{{.*}}, align: 8, dwarfAddressSpace: {{.*}}) +// CHECK: ![[VAR]] = !DILocalVariable(name: "compare", scope: !{{.*}}, file: !{{.*}}, line: {{.*}}, type: ![[TYPE]], align: 8) diff --git a/tests/codegen-llvm/debug-limited.rs b/tests/codegen-llvm/debug-limited.rs new file mode 100644 index 00000000000..89a4ef0ca90 --- /dev/null +++ b/tests/codegen-llvm/debug-limited.rs @@ -0,0 +1,27 @@ +// Verify that the limited debuginfo option emits llvm's FullDebugInfo, but no type info. +// +//@ compile-flags: -C debuginfo=limited + +#[repr(C)] +struct StructType { + a: i64, + b: i32, +} + +extern "C" { + fn creator() -> *mut StructType; + fn save(p: *const StructType); +} + +fn main() { + unsafe { + let value: &mut StructType = &mut *creator(); + value.a = 7; + save(value as *const StructType) + } +} + +// CHECK: !DICompileUnit +// CHECK: emissionKind: FullDebug +// CHECK: !DILocation +// CHECK-NOT: !DIBasicType diff --git a/tests/codegen-llvm/debug-line-directives-only.rs b/tests/codegen-llvm/debug-line-directives-only.rs new file mode 100644 index 00000000000..709c8789bf8 --- /dev/null +++ b/tests/codegen-llvm/debug-line-directives-only.rs @@ -0,0 +1,27 @@ +// Verify that the only debuginfo generated are the line directives. +// +//@ compile-flags: -C debuginfo=line-directives-only + +#[repr(C)] +struct StructType { + a: i64, + b: i32, +} + +extern "C" { + fn creator() -> *mut StructType; + fn save(p: *const StructType); +} + +fn main() { + unsafe { + let value: &mut StructType = &mut *creator(); + value.a = 7; + save(value as *const StructType) + } +} + +// CHECK: !DICompileUnit +// CHECK: emissionKind: DebugDirectivesOnly +// CHECK: !DILocation +// CHECK-NOT: !DIBasicType diff --git a/tests/codegen-llvm/debug-line-tables-only.rs b/tests/codegen-llvm/debug-line-tables-only.rs new file mode 100644 index 00000000000..d50bffe6e60 --- /dev/null +++ b/tests/codegen-llvm/debug-line-tables-only.rs @@ -0,0 +1,27 @@ +// Verify that the only debuginfo generated are the line tables. +// +//@ compile-flags: -C debuginfo=line-tables-only + +#[repr(C)] +struct StructType { + a: i64, + b: i32, +} + +extern "C" { + fn creator() -> *mut StructType; + fn save(p: *const StructType); +} + +fn main() { + unsafe { + let value: &mut StructType = &mut *creator(); + value.a = 7; + save(value as *const StructType) + } +} + +// CHECK: !DICompileUnit +// CHECK: emissionKind: LineTablesOnly +// CHECK: !DILocation +// CHECK-NOT: !DIBasicType diff --git a/tests/codegen-llvm/debug-linkage-name.rs b/tests/codegen-llvm/debug-linkage-name.rs new file mode 100644 index 00000000000..e706040f331 --- /dev/null +++ b/tests/codegen-llvm/debug-linkage-name.rs @@ -0,0 +1,42 @@ +// Verifies that linkage name is omitted when it is +// the same as variable / function name. +// +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 +//@ compile-flags: -C debuginfo=2 -Copt-level=0 +#![crate_type = "lib"] + +pub mod xyz { + // CHECK: !DIGlobalVariable(name: "A", + // CHECK: linkageName: + // CHECK-SAME: line: 12, + pub static A: u32 = 1; + + // CHECK: !DIGlobalVariable(name: "B", + // CHECK-NOT: linkageName: + // CHECK-SAME: line: 18, + #[no_mangle] + pub static B: u32 = 2; + + // CHECK: !DIGlobalVariable(name: "C", + // CHECK-NOT: linkageName: + // CHECK-SAME: line: 24, + #[export_name = "C"] + pub static C: u32 = 2; + + // CHECK: !DISubprogram(name: "e", + // CHECK: linkageName: + // CHECK-SAME: line: 29, + pub extern "C" fn e() {} + + // CHECK: !DISubprogram(name: "f", + // CHECK-NOT: linkageName: + // CHECK-SAME: line: 35, + #[no_mangle] + pub extern "C" fn f() {} + + // CHECK: !DISubprogram(name: "g", + // CHECK-NOT: linkageName: + // CHECK-SAME: line: 41, + #[export_name = "g"] + pub extern "C" fn g() {} +} diff --git a/tests/codegen-llvm/debug-vtable.rs b/tests/codegen-llvm/debug-vtable.rs new file mode 100644 index 00000000000..8a7b1cc3c4b --- /dev/null +++ b/tests/codegen-llvm/debug-vtable.rs @@ -0,0 +1,117 @@ +// ignore-tidy-linelength +//! This test checks the debuginfo for the expected 3 vtables is generated for correct names and +//! number of entries. + +//@ revisions: MSVC NONMSVC +//@[MSVC] only-msvc +//@[NONMSVC] ignore-msvc + +// Use the v0 symbol mangling scheme to codegen order independent of rustc version. +// Unnamed items like shims are generated in lexicographical order of their symbol name and in the +// legacy mangling scheme rustc version and generic parameters are both hashed into a single part +// of the name, thus randomizing item order with respect to rustc version. + +//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0 + +// Make sure that vtables don't have the unnamed_addr attribute when debuginfo is enabled. +// This helps debuggers more reliably map from dyn pointer to concrete type. +// CHECK: @vtable.2 = private constant [ +// CHECK: @vtable.3 = private constant <{ +// CHECK: @vtable.4 = private constant <{ + +// NONMSVC: ![[USIZE:[0-9]+]] = !DIBasicType(name: "usize" +// MSVC: ![[USIZE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "usize" +// NONMSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()" +// MSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$ >" + +// NONMSVC: !DIGlobalVariable(name: "::{vtable}" +// MSVC: !DIGlobalVariable(name: "impl$::vtable$" + +// NONMSVC: ![[VTABLE_TY0:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "::{vtable_type}", {{.*}} size: {{320|160}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}} vtableHolder: ![[FOO_TYPE:[0-9]+]], +// MSVC: ![[VTABLE_TY0:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$::vtable_type$", {{.*}} size: {{320|160}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}} vtableHolder: ![[FOO_TYPE:[0-9]+]], +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method3", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{192|96}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method4", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{256|128}}) +// CHECK: ![[FOO_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", + +// NONMSVC: !DIGlobalVariable(name: ">::{vtable}" +// MSVC: !DIGlobalVariable(name: "impl$ >::vtable$" + +// NONMSVC: ![[VTABLE_TY1:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: ">::{vtable_type}", {{.*}}, size: {{256|128}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]], +// MSVC: ![[VTABLE_TY1:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$ >::vtable_type$", {{.*}}, size: {{256|128}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]], +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method3", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{192|96}}) + +// NONMSVC: !DIGlobalVariable(name: "::{vtable}" +// MSVC: !DIGlobalVariable(name: "impl$::vtable$" + +// NONMSVC: ![[VTABLE_TY2:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "::{vtable_type}", {{.*}}, size: {{192|96}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]], +// MSVC: ![[VTABLE_TY2:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$::vtable_type$", {{.*}}, size: {{192|96}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]], +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}}) + +// NONMSVC: !DIGlobalVariable(name: ">)>>::{vtable}" +// MSVC: !DIGlobalVariable(name: "impl$,assoc$ > > > > > > > > >::vtable$" + +// NONMSVC: !DIGlobalVariable(name: " as core::ops::function::FnOnce<()>>::{vtable}" +// MSVC: !DIGlobalVariable(name: "impl$, core::ops::function::FnOnce > >::vtable$ + +// NONMSVC: !DIGlobalVariable(name: " as core::ops::function::FnOnce<()>>::{vtable}" +// MSVC: !DIGlobalVariable(name: "impl$, core::ops::function::FnOnce > >::vtable$ + +#![crate_type = "lib"] + +// Force emission for debuginfo for usize and *const() early.. +pub static mut XYZ: Option<(usize, *const ())> = None; + +pub struct Foo; + +pub trait SomeTrait { + fn method1(&self) -> u32; + fn method2(&self) -> u32; +} + +impl SomeTrait for Foo { + fn method1(&self) -> u32 { + 1 + } + fn method2(&self) -> u32 { + 2 + } +} + +pub trait SomeTraitWithGenerics { + fn method1(&self) -> (T, U); +} + +impl SomeTraitWithGenerics for Foo { + fn method1(&self) -> (u64, i8) { + (1, 2) + } +} + +pub fn foo(x: &Foo) -> (u32, (u64, i8), &dyn Send) { + let y: &dyn SomeTrait = x; + let z: &dyn SomeTraitWithGenerics = x; + (y.method1(), z.method1(), x as &dyn Send) +} + +// Constructing the debuginfo name for the FnOnce vtable below initially caused an ICE on MSVC +// because the trait type contains a late bound region that needed to be erased before the type +// layout for the niche enum `Option<&dyn Fn()>` could be computed. +pub fn bar() -> Box)> { + Box::new(|_x: Option<&dyn Fn()>| {}) +} + +fn generic_closure(x: T) -> Box T> { + Box::new(move || x) +} + +pub fn instantiate_generic_closures() -> (Box u32>, Box bool>) { + (generic_closure(1u32), generic_closure(false)) +} diff --git a/tests/codegen-llvm/debuginfo-constant-locals.rs b/tests/codegen-llvm/debuginfo-constant-locals.rs new file mode 100644 index 00000000000..580c69c05a5 --- /dev/null +++ b/tests/codegen-llvm/debuginfo-constant-locals.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -g -Copt-level=3 + +// Check that simple constant values are preserved in debuginfo across both MIR opts and LLVM opts + +#![crate_type = "lib"] + +#[no_mangle] +pub fn check_it() { + let a = 1; + let b = 42; + + foo(a + b); +} + +#[inline(never)] +fn foo(x: i32) { + std::process::exit(x); +} + +// CHECK-LABEL: @check_it +// CHECK: dbg{{.}}value({{(metadata )?}}i32 1, {{(metadata )?}}![[a_metadata:[0-9]+]], {{(metadata )?}}!DIExpression() +// CHECK: dbg{{.}}value({{(metadata )?}}i32 42, {{(metadata )?}}![[b_metadata:[0-9]+]], {{(metadata )?}}!DIExpression() + +// CHECK: ![[a_metadata]] = !DILocalVariable(name: "a" +// CHECK-SAME: line: 9 + +// CHECK: ![[b_metadata]] = !DILocalVariable(name: "b" +// CHECK-SAME: line: 10 diff --git a/tests/codegen-llvm/debuginfo-generic-closure-env-names.rs b/tests/codegen-llvm/debuginfo-generic-closure-env-names.rs new file mode 100644 index 00000000000..64bc58e1df7 --- /dev/null +++ b/tests/codegen-llvm/debuginfo-generic-closure-env-names.rs @@ -0,0 +1,90 @@ +// ignore-tidy-linelength +//! This test checks that we get proper type names for closure environments and +//! async-fn environments in debuginfo, especially making sure that generic arguments +//! of the enclosing functions don't get lost. +//! +//! Unfortunately, the order that debuginfo gets emitted into LLVM IR becomes a bit hard +//! to predict once async fns are involved, so DAG allows any order. +//! +//! Note that the test does not check async-fns when targeting MSVC because debuginfo for +//! those does not follow the enum-fallback encoding yet and thus is incomplete. + +//@ revisions: MSVC NONMSVC +//@[MSVC] only-msvc +//@[NONMSVC] ignore-msvc + +// Use the v0 symbol mangling scheme to codegen order independent of rustc version. +// Unnamed items like shims are generated in lexicographical order of their symbol name and in the +// legacy mangling scheme rustc version and generic parameters are both hashed into a single part +// of the name, thus randomizing item order with respect to rustc version. + +//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0 +//@ edition: 2021 + +// non_generic_closure() +// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[non_generic_closure_NAMESPACE:[0-9]+]], +// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[non_generic_closure_NAMESPACE:[0-9]+]], +// CHECK: ![[non_generic_closure_NAMESPACE]] = !DINamespace(name: "non_generic_closure" + +// CHECK: ![[function_containing_closure_NAMESPACE:[0-9]+]] = !DINamespace(name: "function_containing_closure" +// CHECK: ![[generic_async_function_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_function" +// CHECK: ![[generic_async_block_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_block" + +// function_containing_closure() +// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[function_containing_closure_NAMESPACE]] +// MSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[function_containing_closure_NAMESPACE]] + +// generic_async_function() +// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: ![[generic_async_function_NAMESPACE]] + +// generic_async_function() +// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: ![[generic_async_function_NAMESPACE]] + +// generic_async_block() +// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}", scope: ![[generic_async_block_NAMESPACE]] + +// generic_async_block() +// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}", scope: ![[generic_async_block_NAMESPACE]] + +// function_containing_closure() +// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[function_containing_closure_NAMESPACE]] +// MSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[function_containing_closure_NAMESPACE]] + +#![crate_type = "lib"] +use std::future::Future; + +pub struct Foo; + +pub fn non_generic_closure(x: Foo) -> Box Foo> { + return Box::new(move || x); +} + +fn function_containing_closure(x: T) -> impl FnOnce() -> T { + // This static only exists to trigger generating the namespace debuginfo for + // `function_containing_closure` at a predictable, early point, which makes + // writing the FileCheck tests above simpler. + static _X: u8 = 0; + + return move || x; +} + +async fn generic_async_function(x: T) -> T { + static _X: u8 = 0; // Same as above + x +} + +fn generic_async_block(x: T) -> impl Future { + static _X: u8 = 0; // Same as above + async move { x } +} + +pub fn instantiate_generics() { + let _closure_u32 = function_containing_closure(7u32); + let _closure_foo = function_containing_closure(Foo); + + let _async_fn_u32 = generic_async_function(42u32); + let _async_fn_foo = generic_async_function(Foo); + + let _async_block_u32 = generic_async_block(64u32); + let _async_block_foo = generic_async_block(Foo); +} diff --git a/tests/codegen-llvm/debuginfo-inline-callsite-location.rs b/tests/codegen-llvm/debuginfo-inline-callsite-location.rs new file mode 100644 index 00000000000..59ade52ad32 --- /dev/null +++ b/tests/codegen-llvm/debuginfo-inline-callsite-location.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -g -Copt-level=3 -C panic=abort + +// Check that each inline call site for the same function uses the same "sub-program" so that LLVM +// can correctly merge the debug info if it merges the inlined code (e.g., for merging of tail +// calls to panic. + +// CHECK: tail call void @{{[A-Za-z0-9_]+4core6option13unwrap_failed}} +// CHECK-SAME: !dbg ![[#first_dbg:]] +// CHECK: tail call void @{{[A-Za-z0-9_]+4core6option13unwrap_failed}} +// CHECK-SAME: !dbg ![[#second_dbg:]] + +// CHECK-DAG: ![[#func_scope:]] = distinct !DISubprogram(name: "unwrap" +// CHECK-DAG: ![[#]] = !DILocalVariable(name: "self",{{( arg: 1,)?}} scope: ![[#func_scope]] +// CHECK: ![[#first_dbg]] = !DILocation(line: [[#]] +// CHECK-SAME: scope: ![[#func_scope]], inlinedAt: ![[#]]) +// CHECK: ![[#second_dbg]] = !DILocation(line: [[#]] +// CHECK-SAME: scope: ![[#func_scope]], inlinedAt: ![[#]]) + +#![crate_type = "lib"] + +#[no_mangle] +extern "C" fn add_numbers(x: &Option, y: &Option) -> i32 { + let x1 = x.unwrap(); + let y1 = y.unwrap(); + + x1 + y1 +} diff --git a/tests/codegen-llvm/debuginfo-proc-macro/auxiliary/macro_def.rs b/tests/codegen-llvm/debuginfo-proc-macro/auxiliary/macro_def.rs new file mode 100644 index 00000000000..c0691b23275 --- /dev/null +++ b/tests/codegen-llvm/debuginfo-proc-macro/auxiliary/macro_def.rs @@ -0,0 +1,7 @@ +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro] +pub fn square_twice(_item: TokenStream) -> TokenStream { + "(square(env::vars().count() as i32), square(env::vars().count() as i32))".parse().unwrap() +} diff --git a/tests/codegen-llvm/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs b/tests/codegen-llvm/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs new file mode 100644 index 00000000000..7530689d574 --- /dev/null +++ b/tests/codegen-llvm/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs @@ -0,0 +1,52 @@ +//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Zmir-enable-passes=+Inline +// MSVC is different because of the individual allocas. +//@ ignore-msvc + +//@ proc-macro: macro_def.rs + +// Find the variable. +// CHECK-DAG: ![[#var_dbg:]] = !DILocalVariable(name: "n",{{( arg: 1,)?}} scope: ![[#var_scope:]] + +// Find both dbg_declares. These will proceed the variable metadata, of course, so we're looking +// backwards. +// CHECK-DAG: dbg_declare(ptr %n.dbg.spill{{[0-9]}}, ![[#var_dbg]], !DIExpression(), ![[#var_loc2:]]) +// CHECK-DAG: dbg_declare(ptr %n.dbg.spill, ![[#var_dbg]], !DIExpression(), ![[#var_loc1:]]) + +// Find the first location definition, looking forwards again. +// CHECK: ![[#var_loc1]] = !DILocation +// CHECK-SAME: scope: ![[#var_scope:]], inlinedAt: ![[#var_inlinedAt1:]] + +// Find the first location's inlinedAt +// NB: If we fail here it's *probably* because we failed to produce two +// different locations and ended up reusing an earlier one. +// CHECK: ![[#var_inlinedAt1]] = !DILocation +// CHECK-SAME: scope: ![[var_inlinedAt1_scope:]] + +// Find the second location definition, still looking forwards. +// NB: If we failed to produce two different locations, the test will +// definitely fail by this point (if it hasn't already) because we won't +// be able to find the same line again. +// CHECK: ![[#var_loc2]] = !DILocation +// CHECK-SAME: scope: ![[#var_scope]], inlinedAt: ![[#var_inlinedAt2:]] + +// Find the second location's inlinedAt. +// CHECK: ![[#var_inlinedAt2]] = !DILocation +// CHECK-SAME: scope: ![[#var_inlinedAt2_scope:]] + +// Finally, check that a discriminator was emitted for the second scope. +// FIXMEkhuey ideally we would check that *either* scope has a discriminator +// but I don't know that it's possible to check that with FileCheck. +// CHECK: ![[#var_inlinedAt2_scope]] = !DILexicalBlockFile +// CHECK-SAME: discriminator: [[#]] +extern crate macro_def; + +use std::env; + +fn square(n: i32) -> i32 { + n * n +} + +fn main() { + let (z1, z2) = macro_def::square_twice!(); + println!("{z1} == {z2}"); +} diff --git a/tests/codegen-llvm/deduced-param-attrs.rs b/tests/codegen-llvm/deduced-param-attrs.rs new file mode 100644 index 00000000000..34504c80fad --- /dev/null +++ b/tests/codegen-llvm/deduced-param-attrs.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] +#![allow(internal_features)] +#![feature(unsized_fn_params)] + +use std::cell::Cell; +use std::hint; + +// Check to make sure that we can deduce the `readonly` attribute from function bodies for +// parameters passed indirectly. + +pub struct BigStruct { + blah: [i32; 1024], +} + +pub struct BigCellContainer { + blah: [Cell; 1024], +} + +// The by-value parameter for this big struct can be marked readonly. +// +// CHECK: @use_big_struct_immutably({{.*}} readonly {{.*}} %big_struct) +#[no_mangle] +pub fn use_big_struct_immutably(big_struct: BigStruct) { + hint::black_box(&big_struct); +} + +// The by-value parameter for this big struct can't be marked readonly, because we mutate it. +// +// CHECK-NOT: @use_big_struct_mutably({{.*}} readonly {{.*}} %big_struct) +#[no_mangle] +pub fn use_big_struct_mutably(mut big_struct: BigStruct) { + big_struct.blah[987] = 654; + hint::black_box(&big_struct); +} + +// The by-value parameter for this big struct can't be marked readonly, because it contains +// UnsafeCell. +// +// CHECK-NOT: @use_big_cell_container({{.*}} readonly {{.*}} %big_cell_container) +#[no_mangle] +pub fn use_big_cell_container(big_cell_container: BigCellContainer) { + hint::black_box(&big_cell_container); +} + +// Make sure that we don't mistakenly mark a big struct as `readonly` when passed through a generic +// type parameter if it contains UnsafeCell. +// +// CHECK-NOT: @use_something({{.*}} readonly {{.*}} %something) +#[no_mangle] +#[inline(never)] +pub fn use_something(something: T) { + hint::black_box(&something); +} + +#[no_mangle] +pub fn forward_big_cell_container(big_cell_container: BigCellContainer) { + use_something(big_cell_container) +} diff --git a/tests/codegen-llvm/default-requires-uwtable.rs b/tests/codegen-llvm/default-requires-uwtable.rs new file mode 100644 index 00000000000..54a6e171db6 --- /dev/null +++ b/tests/codegen-llvm/default-requires-uwtable.rs @@ -0,0 +1,17 @@ +//@ add-core-stubs +//@ revisions: WINDOWS_ ANDROID_ +//@ compile-flags: -C panic=abort -Copt-level=0 +//@ [WINDOWS_] compile-flags: --target=x86_64-pc-windows-msvc +//@ [WINDOWS_] needs-llvm-components: x86 +//@ [ANDROID_] compile-flags: --target=armv7-linux-androideabi +//@ [ANDROID_] needs-llvm-components: arm + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK: attributes #{{.*}} uwtable +pub fn foo() {} diff --git a/tests/codegen-llvm/default-visibility.rs b/tests/codegen-llvm/default-visibility.rs new file mode 100644 index 00000000000..88ff9fee254 --- /dev/null +++ b/tests/codegen-llvm/default-visibility.rs @@ -0,0 +1,49 @@ +// Verifies that `Session::default_visibility` is affected when using the related cmdline +// flag. This is a regression test for https://github.com/rust-lang/compiler-team/issues/782. See +// also https://github.com/rust-lang/rust/issues/73295 and +// https://github.com/rust-lang/rust/issues/37530. + +//@ revisions:DEFAULT HIDDEN PROTECTED INTERPOSABLE +//@[HIDDEN] compile-flags: -Zdefault-visibility=hidden +//@[PROTECTED] compile-flags: -Zdefault-visibility=protected +//@[INTERPOSABLE] compile-flags: -Zdefault-visibility=interposable + +// The test scenario is specifically about visibility of symbols exported out of dynamically linked +// libraries. +#![crate_type = "dylib"] + +// The test scenario needs to use a Rust-public, but non-explicitly-exported symbol +// (e.g. the test doesn't use `#[no_mangle]`, because currently it implies that +// the symbol should be exported; we don't want that - we want to test the *default* +// export setting instead). +#[used] +pub static tested_symbol: [u8; 6] = *b"foobar"; + +// Exact LLVM IR differs depending on the target triple (e.g. `hidden constant` +// vs `internal constant` vs `constant`). Because of this, we only apply the +// specific test expectations below to one specific target triple. If needed, +// additional targets can be covered by adding copies of this test file with +// a different `only-X` directive. +// +//@ only-x86_64-unknown-linux-gnu + +// HIDDEN: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = hidden constant +// PROTECTED: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = protected constant +// INTERPOSABLE: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant +// DEFAULT: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant + +pub fn do_memcmp(left: &[u8], right: &[u8]) -> i32 { + left.cmp(right) as i32 +} + +// CHECK: define {{.*}} @{{.*}}do_memcmp{{.*}} { +// CHECK: } + +// `do_memcmp` should invoke core::intrinsic::compare_bytes which emits a call +// to the C symbol `memcmp` (at least on x86_64-unknown-linux-gnu). This symbol +// should *not* be declared hidden or protected. + +// HIDDEN: declare i32 @memcmp +// PROTECTED: declare i32 @memcmp +// INTERPOSABLE: declare i32 @memcmp +// DEFAULT: declare i32 @memcmp diff --git a/tests/codegen-llvm/direct-access-external-data.rs b/tests/codegen-llvm/direct-access-external-data.rs new file mode 100644 index 00000000000..5b2ff41ef05 --- /dev/null +++ b/tests/codegen-llvm/direct-access-external-data.rs @@ -0,0 +1,21 @@ +//@ only-loongarch64-unknown-linux-gnu + +//@ revisions: DEFAULT DIRECT INDIRECT +//@ [DEFAULT] compile-flags: -C relocation-model=static +//@ [DIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=yes +//@ [INDIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=no + +#![crate_type = "rlib"] + +// DEFAULT: @VAR = external {{.*}} global i32 +// DIRECT: @VAR = external dso_local {{.*}} global i32 +// INDIRECT: @VAR = external {{.*}} global i32 + +extern "C" { + static VAR: i32; +} + +#[no_mangle] +pub fn get() -> i32 { + unsafe { VAR } +} diff --git a/tests/codegen-llvm/dllimports/auxiliary/dummy.rs b/tests/codegen-llvm/dllimports/auxiliary/dummy.rs new file mode 100644 index 00000000000..ab3dbc6a300 --- /dev/null +++ b/tests/codegen-llvm/dllimports/auxiliary/dummy.rs @@ -0,0 +1,6 @@ +//@ no-prefer-dynamic +#![crate_type = "staticlib"] + +// Since codegen tests don't actually perform linking, this library doesn't need to export +// any symbols. It's here just to satisfy the compiler looking for a .lib file when processing +// #[link(...)] attributes in wrapper.rs. diff --git a/tests/codegen-llvm/dllimports/auxiliary/wrapper.rs b/tests/codegen-llvm/dllimports/auxiliary/wrapper.rs new file mode 100644 index 00000000000..00a29f7ee7e --- /dev/null +++ b/tests/codegen-llvm/dllimports/auxiliary/wrapper.rs @@ -0,0 +1,14 @@ +//@ no-prefer-dynamic +#![crate_type = "rlib"] + +#[link(name = "dummy", kind = "dylib")] +extern "C" { + pub fn dylib_func2(x: i32) -> i32; + pub static dylib_global2: i32; +} + +#[link(name = "dummy", kind = "static")] +extern "C" { + pub fn static_func2(x: i32) -> i32; + pub static static_global2: i32; +} diff --git a/tests/codegen-llvm/dllimports/main.rs b/tests/codegen-llvm/dllimports/main.rs new file mode 100644 index 00000000000..93d350a2238 --- /dev/null +++ b/tests/codegen-llvm/dllimports/main.rs @@ -0,0 +1,43 @@ +// This test is for *-windows-msvc only. +//@ only-windows +//@ ignore-gnu + +//@ aux-build:dummy.rs +//@ aux-build:wrapper.rs + +extern crate wrapper; + +// Check that external symbols coming from foreign dylibs are adorned with 'dllimport', +// whereas symbols coming from foreign staticlibs are not. (RFC-1717) + +// CHECK: @dylib_global1 = external dllimport local_unnamed_addr global i32 +// CHECK: @dylib_global2 = external dllimport local_unnamed_addr global i32 +// CHECK: @static_global1 = external local_unnamed_addr global i32 +// CHECK: @static_global2 = external local_unnamed_addr global i32 + +// CHECK: declare dllimport noundef i32 @dylib_func1(i32 noundef) +// CHECK: declare dllimport noundef i32 @dylib_func2(i32 noundef) +// CHECK: declare noundef i32 @static_func1(i32 noundef) +// CHECK: declare noundef i32 @static_func2(i32 noundef) + +#[link(name = "dummy", kind = "dylib")] +extern "C" { + pub fn dylib_func1(x: i32) -> i32; + pub static dylib_global1: i32; +} + +#[link(name = "dummy", kind = "static")] +extern "C" { + pub fn static_func1(x: i32) -> i32; + pub static static_global1: i32; +} + +fn main() { + unsafe { + dylib_func1(dylib_global1); + wrapper::dylib_func2(wrapper::dylib_global2); + + static_func1(static_global1); + wrapper::static_func2(wrapper::static_global2); + } +} diff --git a/tests/codegen-llvm/dont_codegen_private_const_fn_only_used_in_const_eval.rs b/tests/codegen-llvm/dont_codegen_private_const_fn_only_used_in_const_eval.rs new file mode 100644 index 00000000000..df50b4af809 --- /dev/null +++ b/tests/codegen-llvm/dont_codegen_private_const_fn_only_used_in_const_eval.rs @@ -0,0 +1,27 @@ +//! This test checks that we do not monomorphize functions that are only +//! used to evaluate static items, but never used in runtime code. + +//@compile-flags: --crate-type=lib -Copt-level=0 + +#![feature(generic_const_items)] + +const fn foo() {} + +pub static FOO: () = foo(); + +// CHECK-NOT: define{{.*}}foo{{.*}} + +const fn bar() {} + +pub const BAR: () = bar(); + +// CHECK-NOT: define{{.*}}bar{{.*}} + +const fn baz() {} + +#[rustfmt::skip] +pub const BAZ: () = if C { + baz() +}; + +// CHECK: define{{.*}}baz{{.*}} diff --git a/tests/codegen-llvm/drop-in-place-noalias.rs b/tests/codegen-llvm/drop-in-place-noalias.rs new file mode 100644 index 00000000000..bff2f52781f --- /dev/null +++ b/tests/codegen-llvm/drop-in-place-noalias.rs @@ -0,0 +1,38 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes + +// Tests that the compiler can apply `noalias` and other &mut attributes to `drop_in_place`. +// Note that non-Unpin types should not get `noalias`, matching &mut behavior. + +#![crate_type = "lib"] + +use std::marker::PhantomPinned; + +// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructUnpin{{.*}}(ptr noalias noundef align 4 dereferenceable(12) %{{.+}}) + +// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructNotUnpin{{.*}}(ptr noundef nonnull align 4 %{{.+}}) + +pub struct StructUnpin { + a: i32, + b: i32, + c: i32, +} + +impl Drop for StructUnpin { + fn drop(&mut self) {} +} + +pub struct StructNotUnpin { + a: i32, + b: i32, + c: i32, + p: PhantomPinned, +} + +impl Drop for StructNotUnpin { + fn drop(&mut self) {} +} + +pub unsafe fn main(x: StructUnpin, y: StructNotUnpin) { + drop(x); + drop(y); +} diff --git a/tests/codegen-llvm/drop.rs b/tests/codegen-llvm/drop.rs new file mode 100644 index 00000000000..b22a8ef27d2 --- /dev/null +++ b/tests/codegen-llvm/drop.rs @@ -0,0 +1,36 @@ +//@ needs-unwind - this test verifies the amount of drop calls when unwinding is used +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +struct SomeUniqueName; + +impl Drop for SomeUniqueName { + #[inline(never)] + fn drop(&mut self) {} +} + +#[inline(never)] +pub fn possibly_unwinding() {} + +// CHECK-LABEL: @droppy +#[no_mangle] +pub fn droppy() { + // Check that there are exactly 6 drop calls. The cleanups for the unwinding should be reused, + // so that's one new drop call per call to possibly_unwinding(), and finally 3 drop calls for + // the regular function exit. We used to have problems with quadratic growths of drop calls in + // such functions. + // FIXME(eddyb) the `void @` forces a match on the instruction, instead of the + // comment, that's `; call core::ptr::drop_in_place::` + // for the `v0` mangling, should switch to matching on that once `legacy` is gone. + // CHECK-COUNT-6: {{(call|invoke) void @.*}}drop_in_place{{.*}}SomeUniqueName + // CHECK-NOT: {{(call|invoke) void @.*}}drop_in_place{{.*}}SomeUniqueName + // The next line checks for the } that ends the function definition + // CHECK-LABEL: {{^[}]}} + let _s = SomeUniqueName; + possibly_unwinding(); + let _s = SomeUniqueName; + possibly_unwinding(); + let _s = SomeUniqueName; + possibly_unwinding(); +} diff --git a/tests/codegen-llvm/dst-offset.rs b/tests/codegen-llvm/dst-offset.rs new file mode 100644 index 00000000000..2cf5fa9fac6 --- /dev/null +++ b/tests/codegen-llvm/dst-offset.rs @@ -0,0 +1,84 @@ +//! This file tests that we correctly generate GEP instructions for DST +//! field offsets. +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 + +#![crate_type = "lib"] +#![feature(extern_types, sized_hierarchy)] + +use std::marker::PointeeSized; +use std::ptr::addr_of; + +// Hack to get the correct type for usize +// CHECK: @helper([[USIZE:i[0-9]+]] %_1) +#[no_mangle] +pub fn helper(_: usize) {} + +struct Dst { + x: u32, + y: u8, + z: T, +} + +// CHECK: @dst_dyn_trait_offset(ptr align {{[0-9]+}} [[DATA_PTR:%.+]], ptr align {{[0-9]+}} [[VTABLE_PTR:%.+]]) +#[no_mangle] +pub fn dst_dyn_trait_offset(s: &Dst) -> &dyn Drop { + // The alignment of dyn trait is unknown, so we compute the offset based on align from the + // vtable. + + // CHECK: [[SIZE_PTR:%[0-9]+]] = getelementptr inbounds i8, ptr [[VTABLE_PTR]] + // CHECK: load [[USIZE]], ptr [[SIZE_PTR]] + // CHECK: [[ALIGN_PTR:%[0-9]+]] = getelementptr inbounds i8, ptr [[VTABLE_PTR]] + // CHECK: load [[USIZE]], ptr [[ALIGN_PTR]] + + // CHECK: getelementptr inbounds i8, ptr [[DATA_PTR]] + // CHECK-NEXT: insertvalue + // CHECK-NEXT: insertvalue + // CHECK-NEXT: ret + &s.z +} + +// CHECK-LABEL: @dst_slice_offset +#[no_mangle] +pub fn dst_slice_offset(s: &Dst<[u16]>) -> &[u16] { + // The alignment of [u16] is known, so we generate a GEP directly. + + // CHECK: start: + // CHECK-NEXT: getelementptr inbounds i8, {{.+}}, [[USIZE]] 6 + // CHECK-NEXT: insertvalue + // CHECK-NEXT: insertvalue + // CHECK-NEXT: ret + &s.z +} + +#[repr(packed)] +struct PackedDstSlice { + x: u32, + y: u8, + z: [u16], +} + +// CHECK-LABEL: @packed_dst_slice_offset +#[no_mangle] +pub fn packed_dst_slice_offset(s: &PackedDstSlice) -> *const [u16] { + // The alignment of [u16] is known, so we generate a GEP directly. + + // CHECK: start: + // CHECK-NEXT: getelementptr inbounds i8, {{.+}}, [[USIZE]] 5 + // CHECK-NEXT: insertvalue + // CHECK-NEXT: insertvalue + // CHECK-NEXT: ret + addr_of!(s.z) +} + +extern "C" { + pub type Extern; +} + +// CHECK-LABEL: @dst_extern +#[no_mangle] +pub fn dst_extern(s: &Dst) -> &Extern { + // Computing the alignment of an extern type is currently unsupported and just panics. + + // CHECK: call void @{{.+}}panic + &s.z +} diff --git a/tests/codegen-llvm/dst-vtable-align-nonzero.rs b/tests/codegen-llvm/dst-vtable-align-nonzero.rs new file mode 100644 index 00000000000..1404bd64f50 --- /dev/null +++ b/tests/codegen-llvm/dst-vtable-align-nonzero.rs @@ -0,0 +1,67 @@ +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +// This test checks that we annotate alignment loads from vtables with nonzero range metadata, +// and that this allows LLVM to eliminate redundant `align >= 1` checks. + +pub trait Trait { + fn f(&self); +} + +pub struct WrapperWithAlign1 { + x: u8, + y: T, +} + +pub struct WrapperWithAlign2 { + x: u16, + y: T, +} + +pub struct Struct { + _field: i8, + dst: W, +} + +// CHECK-LABEL: @eliminates_runtime_check_when_align_1 +#[no_mangle] +pub fn eliminates_runtime_check_when_align_1( + x: &Struct>, +) -> &WrapperWithAlign1 { + // CHECK: load [[USIZE:i[0-9]+]], {{.+}} !range [[RANGE_META:![0-9]+]] + // CHECK-NOT: llvm.umax + // CHECK-NOT: icmp + // CHECK-NOT: select + // CHECK: ret + &x.dst +} + +// CHECK-LABEL: @does_not_eliminate_runtime_check_when_align_2 +#[no_mangle] +pub fn does_not_eliminate_runtime_check_when_align_2( + x: &Struct>, +) -> &WrapperWithAlign2 { + // CHECK: [[X0:%[0-9]+]] = load [[USIZE]], {{.+}} !range [[RANGE_META]] + // CHECK: {{icmp|llvm.umax}} + // CHECK: ret + &x.dst +} + +// CHECK-LABEL: @align_load_from_align_of_val +#[no_mangle] +pub fn align_load_from_align_of_val(x: &dyn Trait) -> usize { + // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]] + core::mem::align_of_val(x) +} + +// CHECK-LABEL: @align_load_from_vtable_align_intrinsic +#[no_mangle] +pub unsafe fn align_load_from_vtable_align_intrinsic(x: &dyn Trait) -> usize { + let (data, vtable): (*const (), *const ()) = core::mem::transmute(x); + // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]] + core::intrinsics::vtable_align(vtable) +} + +// CHECK: [[RANGE_META]] = !{[[USIZE]] 1, [[USIZE]] 0} diff --git a/tests/codegen-llvm/dst-vtable-size-range.rs b/tests/codegen-llvm/dst-vtable-size-range.rs new file mode 100644 index 00000000000..670f5e8d553 --- /dev/null +++ b/tests/codegen-llvm/dst-vtable-size-range.rs @@ -0,0 +1,35 @@ +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +// Check that we annotate size loads from vtables with 0..(isize::MAX + 1) range metadata. + +pub trait Trait { + fn f(&self); +} + +// Note that rustc uses inclusive bounds, but LLVM uses exclusive bounds for range metadata. +// CHECK-LABEL: @generate_exclusive_bound +#[no_mangle] +pub fn generate_exclusive_bound() -> usize { + // CHECK: ret [[USIZE:i[0-9]+]] [[EXCLUSIVE_BOUND:[-0-9]+]] + isize::MAX as usize + 1 +} + +// CHECK-LABEL: @size_load_from_size_of_val +#[no_mangle] +pub fn size_load_from_size_of_val(x: &dyn Trait) -> usize { + // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META:![0-9]+]] + core::mem::size_of_val(x) +} + +// CHECK-LABEL: @size_load_from_vtable_size_intrinsic +#[no_mangle] +pub unsafe fn size_load_from_vtable_size_intrinsic(x: &dyn Trait) -> usize { + let (data, vtable): (*const (), *const ()) = core::mem::transmute(x); + // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]] + core::intrinsics::vtable_size(vtable) +} + +// CHECK: [[RANGE_META]] = !{[[USIZE]] 0, [[USIZE]] [[EXCLUSIVE_BOUND]]} diff --git a/tests/codegen-llvm/ehcontguard_disabled.rs b/tests/codegen-llvm/ehcontguard_disabled.rs new file mode 100644 index 00000000000..9efb2721b3e --- /dev/null +++ b/tests/codegen-llvm/ehcontguard_disabled.rs @@ -0,0 +1,9 @@ +//@ compile-flags: + +#![crate_type = "lib"] + +// A basic test function. +pub fn test() {} + +// Ensure the module flag ehcontguard is not present +// CHECK-NOT: !"ehcontguard" diff --git a/tests/codegen-llvm/ehcontguard_enabled.rs b/tests/codegen-llvm/ehcontguard_enabled.rs new file mode 100644 index 00000000000..ecc5512fd5d --- /dev/null +++ b/tests/codegen-llvm/ehcontguard_enabled.rs @@ -0,0 +1,9 @@ +//@ compile-flags: -Z ehcont-guard + +#![crate_type = "lib"] + +// A basic test function. +pub fn test() {} + +// Ensure the module flag ehcontguard=1 is present +// CHECK: !"ehcontguard", i32 1 diff --git a/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs b/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs new file mode 100644 index 00000000000..f43869cf218 --- /dev/null +++ b/tests/codegen-llvm/emscripten-catch-unwind-js-eh.rs @@ -0,0 +1,71 @@ +//@ compile-flags: -Copt-level=3 --target wasm32-unknown-emscripten +//@ needs-llvm-components: webassembly + +// Emscripten has its own unique implementation of catch_unwind (in `codegen_emcc_try`), +// make sure it generates something reasonable. + +#![feature(no_core, lang_items, intrinsics, rustc_attrs)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} +#[lang = "freeze"] +trait Freeze {} +#[lang = "copy"] +trait Copy {} + +impl Copy for *mut T {} + +#[rustc_intrinsic] +fn size_of() -> usize { + loop {} +} + +#[rustc_intrinsic] +unsafe fn catch_unwind( + try_fn: fn(_: *mut u8), + data: *mut u8, + catch_fn: fn(_: *mut u8, _: *mut u8), +) -> i32; + +// CHECK-LABEL: @ptr_size +#[no_mangle] +pub fn ptr_size() -> usize { + // CHECK: ret [[PTR_SIZE:.*]] + size_of::<*mut u8>() +} + +// CHECK-LABEL: @test_catch_unwind +#[no_mangle] +pub unsafe fn test_catch_unwind( + try_fn: fn(_: *mut u8), + data: *mut u8, + catch_fn: fn(_: *mut u8, _: *mut u8), +) -> i32 { + // CHECK: start: + // CHECK: [[ALLOCA:%.*]] = alloca + + // CHECK: catch.i: + // CHECK: [[LANDINGPAD:%.*]] = landingpad + // CHECK: [[EXCEPTION:%.*]] = extractvalue {{.*}} [[LANDINGPAD]], 0 + // CHECK: [[SELECTOR:%.*]] = extractvalue {{.*}} [[LANDINGPAD]], 1 + + // CHECK: [[IS_RUST_EXN:%.*]] = icmp eq {{.*}}[[SELECTOR]] + // CHECK: [[IS_RUST_EXN_I8:%.*]] = zext i1 [[IS_RUST_EXN]] to i8 + + // CHECK: store ptr [[EXCEPTION]], ptr [[ALLOCA]] + // CHECK: [[IS_RUST_SLOT:%.*]] = getelementptr inbounds{{( nuw)?}} i8, ptr [[ALLOCA]], [[PTR_SIZE]] + // CHECK: store i8 [[IS_RUST_EXN_I8]], ptr [[IS_RUST_SLOT]] + + // CHECK: call void %catch_fn(ptr %data, ptr nonnull [[ALLOCA]]) + + catch_unwind(try_fn, data, catch_fn) +} diff --git a/tests/codegen-llvm/emscripten-catch-unwind-wasm-eh.rs b/tests/codegen-llvm/emscripten-catch-unwind-wasm-eh.rs new file mode 100644 index 00000000000..b0750d52268 --- /dev/null +++ b/tests/codegen-llvm/emscripten-catch-unwind-wasm-eh.rs @@ -0,0 +1,69 @@ +//@ compile-flags: -Copt-level=3 --target wasm32-unknown-emscripten -Z emscripten-wasm-eh +//@ needs-llvm-components: webassembly + +// Emscripten catch_unwind using wasm exceptions + +#![feature(no_core, lang_items, intrinsics, rustc_attrs)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} +#[lang = "freeze"] +trait Freeze {} +#[lang = "copy"] +trait Copy {} + +impl Copy for *mut T {} + +#[rustc_intrinsic] +fn size_of() -> usize { + loop {} +} +#[rustc_intrinsic] +unsafe fn catch_unwind( + try_fn: fn(_: *mut u8), + data: *mut u8, + catch_fn: fn(_: *mut u8, _: *mut u8), +) -> i32; + +// CHECK-LABEL: @ptr_size +#[no_mangle] +pub fn ptr_size() -> usize { + // CHECK: ret [[PTR_SIZE:.*]] + size_of::<*mut u8>() +} + +// CHECK-LABEL: @test_catch_unwind +#[no_mangle] +pub unsafe fn test_catch_unwind( + try_fn: fn(_: *mut u8), + data: *mut u8, + catch_fn: fn(_: *mut u8, _: *mut u8), +) -> i32 { + // CHECK: start: + // CHECK: invoke void %try_fn(ptr %data) + // CHECK: to label %__rust_try.exit unwind label %catchswitch.i + // CHECK: catchswitch.i: ; preds = %start + // CHECK: %catchswitch1.i = catchswitch within none [label %catchpad.i] unwind to caller + + // CHECK: catchpad.i: ; preds = %catchswitch.i + // CHECK: %catchpad2.i = catchpad within %catchswitch1.i [ptr null] + // CHECK: %0 = tail call ptr @llvm.wasm.get.exception(token %catchpad2.i) + // CHECK: %1 = tail call i32 @llvm.wasm.get.ehselector(token %catchpad2.i) + // CHECK: call void %catch_fn(ptr %data, ptr %0) [ "funclet"(token %catchpad2.i) ] + // CHECK: catchret from %catchpad2.i to label %__rust_try.exit + + // CHECK: __rust_try.exit: ; preds = %start, %catchpad.i + // CHECK: %common.ret.op.i = phi i32 [ 0, %start ], [ 1, %catchpad.i ] + // CHECK: ret i32 %common.ret.op.i + + catch_unwind(try_fn, data, catch_fn) +} diff --git a/tests/codegen-llvm/enable-lto-unit-splitting.rs b/tests/codegen-llvm/enable-lto-unit-splitting.rs new file mode 100644 index 00000000000..51c2671bc4e --- /dev/null +++ b/tests/codegen-llvm/enable-lto-unit-splitting.rs @@ -0,0 +1,9 @@ +// Verifies that "EnableSplitLTOUnit" module flag is added. +// +//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsplit-lto-unit + +#![crate_type = "lib"] + +pub fn foo() {} + +// CHECK: !{{[0-9]+}} = !{i32 4, !"EnableSplitLTOUnit", i32 1} diff --git a/tests/codegen-llvm/enum/enum-aggregate.rs b/tests/codegen-llvm/enum/enum-aggregate.rs new file mode 100644 index 00000000000..0161e5f3fa1 --- /dev/null +++ b/tests/codegen-llvm/enum/enum-aggregate.rs @@ -0,0 +1,126 @@ +//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes +//@ min-llvm-version: 19 +//@ only-64bit + +#![crate_type = "lib"] + +use std::cmp::Ordering; +use std::num::NonZero; +use std::ptr::NonNull; + +#[no_mangle] +fn make_some_bool(x: bool) -> Option { + // CHECK-LABEL: i8 @make_some_bool(i1 zeroext %x) + // CHECK-NEXT: start: + // CHECK-NEXT: %[[WIDER:.+]] = zext i1 %x to i8 + // CHECK-NEXT: ret i8 %[[WIDER]] + Some(x) +} + +#[no_mangle] +fn make_none_bool() -> Option { + // CHECK-LABEL: i8 @make_none_bool() + // CHECK-NEXT: start: + // CHECK-NEXT: ret i8 2 + None +} + +#[no_mangle] +fn make_some_ordering(x: Ordering) -> Option { + // CHECK-LABEL: i8 @make_some_ordering(i8 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: ret i8 %x + Some(x) +} + +#[no_mangle] +fn make_some_u16(x: u16) -> Option { + // CHECK-LABEL: { i16, i16 } @make_some_u16(i16 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: %0 = insertvalue { i16, i16 } { i16 1, i16 poison }, i16 %x, 1 + // CHECK-NEXT: ret { i16, i16 } %0 + Some(x) +} + +#[no_mangle] +fn make_none_u16() -> Option { + // CHECK-LABEL: { i16, i16 } @make_none_u16() + // CHECK-NEXT: start: + // CHECK-NEXT: ret { i16, i16 } { i16 0, i16 undef } + None +} + +#[no_mangle] +fn make_some_nzu32(x: NonZero) -> Option> { + // CHECK-LABEL: i32 @make_some_nzu32(i32 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: ret i32 %x + Some(x) +} + +#[no_mangle] +fn make_ok_ptr(x: NonNull) -> Result, usize> { + // CHECK-LABEL: { i64, ptr } @make_ok_ptr(ptr %x) + // CHECK-NEXT: start: + // CHECK-NEXT: %0 = insertvalue { i64, ptr } { i64 0, ptr poison }, ptr %x, 1 + // CHECK-NEXT: ret { i64, ptr } %0 + Ok(x) +} + +#[no_mangle] +fn make_ok_int(x: usize) -> Result> { + // CHECK-LABEL: { i64, ptr } @make_ok_int(i64 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: %[[NOPROV:.+]] = getelementptr i8, ptr null, i64 %x + // CHECK-NEXT: %[[R:.+]] = insertvalue { i64, ptr } { i64 0, ptr poison }, ptr %[[NOPROV]], 1 + // CHECK-NEXT: ret { i64, ptr } %[[R]] + Ok(x) +} + +#[no_mangle] +fn make_some_ref(x: &u16) -> Option<&u16> { + // CHECK-LABEL: ptr @make_some_ref(ptr align 2 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: ret ptr %x + Some(x) +} + +#[no_mangle] +fn make_none_ref<'a>() -> Option<&'a u16> { + // CHECK-LABEL: ptr @make_none_ref() + // CHECK-NEXT: start: + // CHECK-NEXT: ret ptr null + None +} + +#[inline(never)] +fn make_err_generic(e: E) -> Result { + // CHECK-LABEL: define{{.+}}make_err_generic + // CHECK-NEXT: start: + // CHECK-NEXT: call void @llvm.trap() + // CHECK-NEXT: ret i32 poison + Err(e) +} + +#[no_mangle] +fn make_uninhabited_err_indirectly(n: Never) -> Result { + // CHECK-LABEL: i32 @make_uninhabited_err_indirectly() + // CHECK-NEXT: start: + // CHECK-NEXT: call{{.+}}make_err_generic + make_err_generic(n) +} + +#[no_mangle] +fn make_fully_uninhabited_result(v: u32, n: Never) -> Result<(u32, Never), (Never, u32)> { + // Actually reaching this would be UB, so we don't actually build a result. + + // CHECK-LABEL: { i32, i32 } @make_fully_uninhabited_result(i32 %v) + // CHECK-NEXT: start: + // CHECK-NEXT: call void @llvm.trap() + // CHECK-NEXT: call void @llvm.trap() + // CHECK-NEXT: call void @llvm.trap() + // CHECK-NEXT: unreachable + Ok((v, n)) +} + +enum Never {} diff --git a/tests/codegen-llvm/enum/enum-bounds-check-derived-idx.rs b/tests/codegen-llvm/enum/enum-bounds-check-derived-idx.rs new file mode 100644 index 00000000000..a5785f4addf --- /dev/null +++ b/tests/codegen-llvm/enum/enum-bounds-check-derived-idx.rs @@ -0,0 +1,24 @@ +// This test checks an optimization that is not guaranteed to work. This test case should not block +// a future LLVM update. +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +pub enum Bar { + A = 1, + B = 3, +} + +// CHECK-LABEL: @lookup_inc +#[no_mangle] +pub fn lookup_inc(buf: &[u8; 5], f: Bar) -> u8 { + // CHECK-NOT: panic_bounds_check + buf[f as usize + 1] +} + +// CHECK-LABEL: @lookup_dec +#[no_mangle] +pub fn lookup_dec(buf: &[u8; 5], f: Bar) -> u8 { + // CHECK-NOT: panic_bounds_check + buf[f as usize - 1] +} diff --git a/tests/codegen-llvm/enum/enum-bounds-check-issue-13926.rs b/tests/codegen-llvm/enum/enum-bounds-check-issue-13926.rs new file mode 100644 index 00000000000..6e8e5035b0d --- /dev/null +++ b/tests/codegen-llvm/enum/enum-bounds-check-issue-13926.rs @@ -0,0 +1,18 @@ +// This test checks an optimization that is not guaranteed to work. This test case should not block +// a future LLVM update. +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[repr(u8)] +pub enum Exception { + Low = 5, + High = 10, +} + +// CHECK-LABEL: @access +#[no_mangle] +pub fn access(array: &[usize; 12], exc: Exception) -> usize { + // CHECK-NOT: panic_bounds_check + array[(exc as u8 - 4) as usize] +} diff --git a/tests/codegen-llvm/enum/enum-bounds-check-issue-82871.rs b/tests/codegen-llvm/enum/enum-bounds-check-issue-82871.rs new file mode 100644 index 00000000000..3b8a146838a --- /dev/null +++ b/tests/codegen-llvm/enum/enum-bounds-check-issue-82871.rs @@ -0,0 +1,18 @@ +//@ compile-flags: -C opt-level=0 + +#![crate_type = "lib"] + +#[repr(C)] +pub enum E { + A, +} + +// CHECK-LABEL: @index +#[no_mangle] +pub fn index(x: &[u32; 3], ind: E) -> u32 { + // Canary: we should be able to optimize out the bounds check, but we need + // to track the range of the discriminant result in order to be able to do that. + // oli-obk tried to add that, but that caused miscompilations all over the place. + // CHECK: panic_bounds_check + x[ind as usize] +} diff --git a/tests/codegen-llvm/enum/enum-bounds-check.rs b/tests/codegen-llvm/enum/enum-bounds-check.rs new file mode 100644 index 00000000000..5362598ca7c --- /dev/null +++ b/tests/codegen-llvm/enum/enum-bounds-check.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +pub enum Foo { + A, + B, +} + +// CHECK-LABEL: @lookup +#[no_mangle] +pub fn lookup(buf: &[u8; 2], f: Foo) -> u8 { + // CHECK-NOT: panic_bounds_check + buf[f as usize] +} + +pub enum Bar { + A = 2, + B = 3, +} + +// CHECK-LABEL: @lookup_unmodified +#[no_mangle] +pub fn lookup_unmodified(buf: &[u8; 5], f: Bar) -> u8 { + // CHECK-NOT: panic_bounds_check + buf[f as usize] +} diff --git a/tests/codegen-llvm/enum/enum-debug-clike.rs b/tests/codegen-llvm/enum/enum-debug-clike.rs new file mode 100644 index 00000000000..89c803cce5e --- /dev/null +++ b/tests/codegen-llvm/enum/enum-debug-clike.rs @@ -0,0 +1,28 @@ +// This tests that debug info for "c-like" enums is properly emitted. +// This is ignored for the fallback mode on MSVC due to problems with PDB. + +// +//@ ignore-msvc +//@ ignore-wasi wasi codegens the main symbol differently + +//@ compile-flags: -g -C no-prepopulate-passes + +// CHECK-LABEL: @main +// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_enumeration_type,{{.*}}name: "E",{{.*}}flags: DIFlagEnumClass,{{.*}} +// CHECK: {{.*}}DIEnumerator{{.*}}name: "A",{{.*}}value: {{[0-9].*}} +// CHECK: {{.*}}DIEnumerator{{.*}}name: "B",{{.*}}value: {{[0-9].*}} +// CHECK: {{.*}}DIEnumerator{{.*}}name: "C",{{.*}}value: {{[0-9].*}} + +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(unused_assignments)] + +enum E { + A, + B, + C, +} + +pub fn main() { + let e = E::C; +} diff --git a/tests/codegen-llvm/enum/enum-debug-niche-2.rs b/tests/codegen-llvm/enum/enum-debug-niche-2.rs new file mode 100644 index 00000000000..80a4081f15b --- /dev/null +++ b/tests/codegen-llvm/enum/enum-debug-niche-2.rs @@ -0,0 +1,47 @@ +//! This tests that optimized enum debug info accurately reflects the enum layout. +//! This is ignored for the fallback mode on MSVC due to problems with PDB. +//! +//@ compile-flags: -g -C no-prepopulate-passes +//@ ignore-msvc +// +// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}size: 32,{{.*}} +// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Placeholder",{{.*}}extraData: i32 -1{{[,)].*}} +// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Error",{{.*}}extraData: i32 0{{[,)].*}} +#![feature(never_type)] + +#[derive(Copy, Clone)] +pub struct Entity { + private: std::num::NonZero, +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Declaration; + +impl TypeFamily for Declaration { + type Base = Base; + type Placeholder = !; + + fn intern_base_data(_: BaseKind) {} +} + +#[derive(Copy, Clone)] +pub struct Base; + +pub trait TypeFamily: Copy + 'static { + type Base: Copy; + type Placeholder: Copy; + + fn intern_base_data(_: BaseKind); +} + +#[derive(Copy, Clone)] +pub enum BaseKind { + Named(Entity), + Placeholder(F::Placeholder), + Error, +} + +pub fn main() { + let x = BaseKind::Error::; + let y = 7; +} diff --git a/tests/codegen-llvm/enum/enum-debug-niche.rs b/tests/codegen-llvm/enum/enum-debug-niche.rs new file mode 100644 index 00000000000..59e8b8a78b4 --- /dev/null +++ b/tests/codegen-llvm/enum/enum-debug-niche.rs @@ -0,0 +1,35 @@ +// This tests that optimized enum debug info accurately reflects the enum layout. +// This is ignored for the fallback mode on MSVC due to problems with PDB. + +//@ ignore-msvc +//@ ignore-wasi wasi codegens the main symbol differently + +//@ compile-flags: -g -C no-prepopulate-passes + +// CHECK-LABEL: @main +// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}discriminator:{{.*}} +// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "A",{{.*}}extraData:{{.*}} +// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "A",{{.*}} +// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "B",{{.*}}extraData:{{.*}} +// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "B",{{.*}} +// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "C",{{.*}}extraData:{{.*}} +// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "C",{{.*}} +// CHECK-NOT: {{.*}}DIDerivedType{{.*}}name: "D",{{.*}}extraData:{{.*}} +// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "D",{{.*}} +// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "D",{{.*}} +// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}flags: DIFlagArtificial{{.*}} + +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(unused_assignments)] + +enum E { + A, + B, + C, + D(bool), +} + +pub fn main() { + let e = E::D(true); +} diff --git a/tests/codegen-llvm/enum/enum-debug-tagged.rs b/tests/codegen-llvm/enum/enum-debug-tagged.rs new file mode 100644 index 00000000000..e8f147665b0 --- /dev/null +++ b/tests/codegen-llvm/enum/enum-debug-tagged.rs @@ -0,0 +1,31 @@ +// This tests that debug info for tagged (ordinary) enums is properly emitted. +// This is ignored for the fallback mode on MSVC due to problems with PDB. + +//@ ignore-msvc +//@ ignore-wasi wasi codegens the main symbol differently + +//@ compile-flags: -g -C no-prepopulate-passes + +// CHECK-LABEL: @main +// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "E",{{.*}} +// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}discriminator:{{.*}} +// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "A",{{.*}}extraData:{{.*}} +// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "A",{{.*}} +// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "__0",{{.*}} +// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "B",{{.*}}extraData:{{.*}} +// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "B",{{.*}} +// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "__0",{{.*}} +// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}flags: DIFlagArtificial{{.*}} + +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(unused_assignments)] + +enum E { + A(u32), + B(u32), +} + +pub fn main() { + let e = E::A(23); +} diff --git a/tests/codegen-llvm/enum/enum-discriminant-eq.rs b/tests/codegen-llvm/enum/enum-discriminant-eq.rs new file mode 100644 index 00000000000..0494c5f551b --- /dev/null +++ b/tests/codegen-llvm/enum/enum-discriminant-eq.rs @@ -0,0 +1,223 @@ +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled +//@ min-llvm-version: 20 +//@ only-64bit + +// The `derive(PartialEq)` on enums with field-less variants compares discriminants, +// so make sure we emit that in some reasonable way. + +#![crate_type = "lib"] +#![feature(ascii_char)] +#![feature(core_intrinsics)] +#![feature(repr128)] + +use std::ascii::Char as AC; +use std::cmp::Ordering; +use std::intrinsics::discriminant_value; +use std::num::NonZero; + +// A type that's bigger than `isize`, unlike the usual cases that have small tags. +#[repr(u128)] +pub enum Giant { + Two = 2, + Three = 3, + Four = 4, +} + +#[unsafe(no_mangle)] +pub fn opt_bool_eq_discr(a: Option, b: Option) -> bool { + // CHECK-LABEL: @opt_bool_eq_discr( + // CHECK: %[[A:.+]] = icmp ne i8 %a, 2 + // CHECK: %[[B:.+]] = icmp eq i8 %b, 2 + // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] + // CHECK: ret i1 %[[R]] + + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn opt_ord_eq_discr(a: Option, b: Option) -> bool { + // CHECK-LABEL: @opt_ord_eq_discr( + // CHECK: %[[A:.+]] = icmp ne i8 %a, 2 + // CHECK: %[[B:.+]] = icmp eq i8 %b, 2 + // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] + // CHECK: ret i1 %[[R]] + + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn opt_nz32_eq_discr(a: Option>, b: Option>) -> bool { + // CHECK-LABEL: @opt_nz32_eq_discr( + // CHECK: %[[A:.+]] = icmp ne i32 %a, 0 + // CHECK: %[[B:.+]] = icmp eq i32 %b, 0 + // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] + // CHECK: ret i1 %[[R]] + + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn opt_ac_eq_discr(a: Option, b: Option) -> bool { + // CHECK-LABEL: @opt_ac_eq_discr( + // CHECK: %[[A:.+]] = icmp ne i8 %a, -128 + // CHECK: %[[B:.+]] = icmp eq i8 %b, -128 + // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] + // CHECK: ret i1 %[[R]] + + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn opt_giant_eq_discr(a: Option, b: Option) -> bool { + // CHECK-LABEL: @opt_giant_eq_discr( + // CHECK: %[[A:.+]] = icmp ne i128 %a, 1 + // CHECK: %[[B:.+]] = icmp eq i128 %b, 1 + // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] + // CHECK: ret i1 %[[R]] + + discriminant_value(&a) == discriminant_value(&b) +} + +pub enum Mid { + Before, + Thing(T), + After, +} + +#[unsafe(no_mangle)] +pub fn mid_bool_eq_discr(a: Mid, b: Mid) -> bool { + // CHECK-LABEL: @mid_bool_eq_discr( + + // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2 + // CHECK: %[[A_IS_NICHE:.+]] = icmp samesign ugt i8 %a, 1 + // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) + // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 + + // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2 + // CHECK: %[[B_IS_NICHE:.+]] = icmp samesign ugt i8 %b, 1 + // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) + // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 + + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn mid_ord_eq_discr(a: Mid, b: Mid) -> bool { + // CHECK-LABEL: @mid_ord_eq_discr( + + // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2 + // CHECK: %[[A_IS_NICHE:.+]] = icmp sgt i8 %a, 1 + // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) + // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 + + // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2 + // CHECK: %[[B_IS_NICHE:.+]] = icmp sgt i8 %b, 1 + // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) + // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 + + // CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]] + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn mid_nz32_eq_discr(a: Mid>, b: Mid>) -> bool { + // CHECK-LABEL: @mid_nz32_eq_discr( + // CHECK: %[[R:.+]] = icmp eq i32 %a.0, %b.0 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == discriminant_value(&b) +} + +#[unsafe(no_mangle)] +pub fn mid_ac_eq_discr(a: Mid, b: Mid) -> bool { + // CHECK-LABEL: @mid_ac_eq_discr( + + // CHECK: %[[A_REL_DISCR:.+]] = xor i8 %a, -128 + // CHECK: %[[A_IS_NICHE:.+]] = icmp slt i8 %a, 0 + // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %a, -127 + // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) + // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 + + // CHECK: %[[B_REL_DISCR:.+]] = xor i8 %b, -128 + // CHECK: %[[B_IS_NICHE:.+]] = icmp slt i8 %b, 0 + // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %b, -127 + // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) + // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 + + // CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]] + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == discriminant_value(&b) +} + +// FIXME: This should be improved once our LLVM fork picks up the fix for +// +#[unsafe(no_mangle)] +pub fn mid_giant_eq_discr(a: Mid, b: Mid) -> bool { + // CHECK-LABEL: @mid_giant_eq_discr( + + // CHECK: %[[A_TRUNC:.+]] = trunc nuw nsw i128 %a to i64 + // CHECK: %[[A_REL_DISCR:.+]] = add nsw i64 %[[A_TRUNC]], -5 + // CHECK: %[[A_IS_NICHE:.+]] = icmp samesign ugt i128 %a, 4 + // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i64 %[[A_REL_DISCR]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) + // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i64 %[[A_REL_DISCR]], i64 1 + + // CHECK: %[[B_TRUNC:.+]] = trunc nuw nsw i128 %b to i64 + // CHECK: %[[B_REL_DISCR:.+]] = add nsw i64 %[[B_TRUNC]], -5 + // CHECK: %[[B_IS_NICHE:.+]] = icmp samesign ugt i128 %b, 4 + // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i64 %[[B_REL_DISCR]], 1 + // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) + // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i64 %[[B_REL_DISCR]], i64 1 + + // CHECK: %[[R:.+]] = icmp eq i64 %[[A_DISCR]], %[[B_DISCR]] + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == discriminant_value(&b) +} + +// In niche-encoded enums, testing for the untagged variant should optimize to a +// straight-forward comparison looking for the natural range of the payload value. + +#[unsafe(no_mangle)] +pub fn mid_bool_is_thing(a: Mid) -> bool { + // CHECK-LABEL: @mid_bool_is_thing( + // CHECK: %[[R:.+]] = icmp samesign ult i8 %a, 2 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == 1 +} + +#[unsafe(no_mangle)] +pub fn mid_ord_is_thing(a: Mid) -> bool { + // CHECK-LABEL: @mid_ord_is_thing( + // CHECK: %[[R:.+]] = icmp slt i8 %a, 2 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == 1 +} + +#[unsafe(no_mangle)] +pub fn mid_nz32_is_thing(a: Mid>) -> bool { + // CHECK-LABEL: @mid_nz32_is_thing( + // CHECK: %[[R:.+]] = icmp eq i32 %a.0, 1 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == 1 +} + +#[unsafe(no_mangle)] +pub fn mid_ac_is_thing(a: Mid) -> bool { + // CHECK-LABEL: @mid_ac_is_thing( + // CHECK: %[[R:.+]] = icmp sgt i8 %a, -1 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == 1 +} + +#[unsafe(no_mangle)] +pub fn mid_giant_is_thing(a: Mid) -> bool { + // CHECK-LABEL: @mid_giant_is_thing( + // CHECK: %[[R:.+]] = icmp samesign ult i128 %a, 5 + // CHECK: ret i1 %[[R]] + discriminant_value(&a) == 1 +} diff --git a/tests/codegen-llvm/enum/enum-discriminant-value.rs b/tests/codegen-llvm/enum/enum-discriminant-value.rs new file mode 100644 index 00000000000..d6b0c6d6c10 --- /dev/null +++ b/tests/codegen-llvm/enum/enum-discriminant-value.rs @@ -0,0 +1,27 @@ +// Verify that DIEnumerator uses isUnsigned flag when appropriate. +// +//@ compile-flags: -g -C no-prepopulate-passes + +#[repr(i64)] +pub enum I64 { + I64Min = i64::MIN, + I64Max = i64::MAX, +} + +#[repr(u64)] +pub enum U64 { + U64Min = u64::MIN, + U64Max = u64::MAX, +} + +fn main() { + let _a = I64::I64Min; + let _b = I64::I64Max; + let _c = U64::U64Min; + let _d = U64::U64Max; +} + +// CHECK: !DIEnumerator(name: "I64Min", value: -9223372036854775808) +// CHECK: !DIEnumerator(name: "I64Max", value: 9223372036854775807) +// CHECK: !DIEnumerator(name: "U64Min", value: 0, isUnsigned: true) +// CHECK: !DIEnumerator(name: "U64Max", value: 18446744073709551615, isUnsigned: true) diff --git a/tests/codegen-llvm/enum/enum-early-otherwise-branch.rs b/tests/codegen-llvm/enum/enum-early-otherwise-branch.rs new file mode 100644 index 00000000000..8d39d8e9b74 --- /dev/null +++ b/tests/codegen-llvm/enum/enum-early-otherwise-branch.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +pub enum Enum { + A(u32), + B(u32), + C(u32), +} + +#[no_mangle] +pub fn foo(lhs: &Enum, rhs: &Enum) -> bool { + // CHECK-LABEL: define{{.*}}i1 @foo( + // CHECK-NOT: switch + // CHECK-NOT: br + // CHECK: [[SELECT:%.*]] = select + // CHECK-NEXT: ret i1 [[SELECT]] + // CHECK-NEXT: } + match (lhs, rhs) { + (Enum::A(lhs), Enum::A(rhs)) => lhs == rhs, + (Enum::B(lhs), Enum::B(rhs)) => lhs == rhs, + (Enum::C(lhs), Enum::C(rhs)) => lhs == rhs, + _ => false, + } +} diff --git a/tests/codegen-llvm/enum/enum-match.rs b/tests/codegen-llvm/enum/enum-match.rs new file mode 100644 index 00000000000..57db44ec74e --- /dev/null +++ b/tests/codegen-llvm/enum/enum-match.rs @@ -0,0 +1,779 @@ +//@ compile-flags: -Copt-level=1 +//@ only-64bit + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +// Check each of the 3 cases for `codegen_get_discr`. + +// FIXME: once our min-bar LLVM has `range` attributes, update the various +// tests here to no longer have the `range`s and `nsw`s as optional. + +// Case 0: One tagged variant. +pub enum Enum0 { + A(bool), + B, +} + +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match0(i8{{.+}}%0) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[IS_B:.+]] = icmp eq i8 %0, 2 +// CHECK-NEXT: %[[TRUNC:.+]] = and i8 %0, 1 +// CHECK-NEXT: %[[R:.+]] = select i1 %[[IS_B]], i8 13, i8 %[[TRUNC]] +// CHECK-NEXT: ret i8 %[[R]] +#[no_mangle] +pub fn match0(e: Enum0) -> u8 { + use Enum0::*; + match e { + A(b) => b as u8, + B => 13, + } +} + +// Case 1: Niche values are on a boundary for `range`. +pub enum Enum1 { + A(bool), + B, + C, +} + +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1(i8{{.+}}%0) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 +// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp{{( samesign)?}} ugt i8 %0, 1 +// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1 +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0 +// CHECK-NEXT: switch i64 %[[DISCR]] +#[no_mangle] +pub fn match1(e: Enum1) -> u8 { + use Enum1::*; + match e { + A(b) => b as u8, + B => 13, + C => 100, + } +} + +// Case 2: Special cases don't apply. +#[rustfmt::skip] +pub enum X { + _2=2, _3, _4, _5, _6, _7, _8, _9, _10, _11, + _12, _13, _14, _15, _16, _17, _18, _19, _20, + _21, _22, _23, _24, _25, _26, _27, _28, _29, + _30, _31, _32, _33, _34, _35, _36, _37, _38, + _39, _40, _41, _42, _43, _44, _45, _46, _47, + _48, _49, _50, _51, _52, _53, _54, _55, _56, + _57, _58, _59, _60, _61, _62, _63, _64, _65, + _66, _67, _68, _69, _70, _71, _72, _73, _74, + _75, _76, _77, _78, _79, _80, _81, _82, _83, + _84, _85, _86, _87, _88, _89, _90, _91, _92, + _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, + _110, _111, _112, _113, _114, _115, _116, _117, + _118, _119, _120, _121, _122, _123, _124, _125, + _126, _127, _128, _129, _130, _131, _132, _133, + _134, _135, _136, _137, _138, _139, _140, _141, + _142, _143, _144, _145, _146, _147, _148, _149, + _150, _151, _152, _153, _154, _155, _156, _157, + _158, _159, _160, _161, _162, _163, _164, _165, + _166, _167, _168, _169, _170, _171, _172, _173, + _174, _175, _176, _177, _178, _179, _180, _181, + _182, _183, _184, _185, _186, _187, _188, _189, + _190, _191, _192, _193, _194, _195, _196, _197, + _198, _199, _200, _201, _202, _203, _204, _205, + _206, _207, _208, _209, _210, _211, _212, _213, + _214, _215, _216, _217, _218, _219, _220, _221, + _222, _223, _224, _225, _226, _227, _228, _229, + _230, _231, _232, _233, _234, _235, _236, _237, + _238, _239, _240, _241, _242, _243, _244, _245, + _246, _247, _248, _249, _250, _251, _252, _253, +} + +pub enum Enum2 { + A(X), + B, + C, + D, + E, +} + +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, -?[0-9]+\))?}} i8 @match2(i8{{.+}}%0) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %0, 2 +// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 4 +// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1 +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0 +// CHECK-NEXT: switch i64 %[[DISCR]] +#[no_mangle] +pub fn match2(e: Enum2) -> u8 { + use Enum2::*; + match e { + A(b) => b as u8, + B => 13, + C => 100, + D => 200, + E => 250, + } +} + +// And make sure it works even if the niched scalar is a pointer. +// (For example, that we don't try to `sub` on pointers.) + +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i16 -?[0-9]+, -?[0-9]+\))?}} i16 @match3(ptr{{.+}}%0) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[IS_NULL:.+]] = icmp eq ptr %0, null +// CHECK-NEXT: br i1 %[[IS_NULL]] +#[no_mangle] +pub fn match3(e: Option<&u8>) -> i16 { + match e { + Some(r) => *r as _, + None => -1, + } +} + +// If the untagged variant is in the middle, there's an impossible value that's +// not reflected in the `range` parameter attribute, so we assume it away. + +#[derive(PartialEq)] +pub enum MiddleNiche { + A, + B, + C(bool), + D, + E, +} + +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 -?[0-9]+, -?[0-9]+\))?}} i8 @match4(i8{{.+}}%0) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 +// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2 +// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) +// CHECK-NEXT: %[[NOT_NICHE:.+]] = icmp{{( samesign)?}} ult i8 %0, 2 +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[NOT_NICHE]], i8 2, i8 %[[REL_VAR]] +// CHECK-NEXT: switch i8 %[[DISCR]] +#[no_mangle] +pub fn match4(e: MiddleNiche) -> u8 { + use MiddleNiche::*; + match e { + A => 13, + B => 100, + C(b) => b as u8, + D => 200, + E => 250, + } +} + +// CHECK-LABEL: define{{.+}}i1 @match4_is_c(i8{{.+}}%e) +// CHECK-NEXT: start +// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %e, 4 +// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) +// CHECK-NEXT: %[[IS_C:.+]] = icmp{{( samesign)?}} ult i8 %e, 2 +// CHECK-NEXT: ret i1 %[[IS_C]] +#[no_mangle] +pub fn match4_is_c(e: MiddleNiche) -> bool { + // Before #139098, this couldn't optimize out the `select` because it looked + // like it was possible for a `2` to be produced on both sides. + + std::intrinsics::discriminant_value(&e) == 2 +} + +// You have to do something pretty obnoxious to get a variant index that doesn't +// fit in the tag size, but it's possible + +pub enum Never {} + +pub enum HugeVariantIndex { + V000(Never), + V001(Never), + V002(Never), + V003(Never), + V004(Never), + V005(Never), + V006(Never), + V007(Never), + V008(Never), + V009(Never), + V010(Never), + V011(Never), + V012(Never), + V013(Never), + V014(Never), + V015(Never), + V016(Never), + V017(Never), + V018(Never), + V019(Never), + V020(Never), + V021(Never), + V022(Never), + V023(Never), + V024(Never), + V025(Never), + V026(Never), + V027(Never), + V028(Never), + V029(Never), + V030(Never), + V031(Never), + V032(Never), + V033(Never), + V034(Never), + V035(Never), + V036(Never), + V037(Never), + V038(Never), + V039(Never), + V040(Never), + V041(Never), + V042(Never), + V043(Never), + V044(Never), + V045(Never), + V046(Never), + V047(Never), + V048(Never), + V049(Never), + V050(Never), + V051(Never), + V052(Never), + V053(Never), + V054(Never), + V055(Never), + V056(Never), + V057(Never), + V058(Never), + V059(Never), + V060(Never), + V061(Never), + V062(Never), + V063(Never), + V064(Never), + V065(Never), + V066(Never), + V067(Never), + V068(Never), + V069(Never), + V070(Never), + V071(Never), + V072(Never), + V073(Never), + V074(Never), + V075(Never), + V076(Never), + V077(Never), + V078(Never), + V079(Never), + V080(Never), + V081(Never), + V082(Never), + V083(Never), + V084(Never), + V085(Never), + V086(Never), + V087(Never), + V088(Never), + V089(Never), + V090(Never), + V091(Never), + V092(Never), + V093(Never), + V094(Never), + V095(Never), + V096(Never), + V097(Never), + V098(Never), + V099(Never), + V100(Never), + V101(Never), + V102(Never), + V103(Never), + V104(Never), + V105(Never), + V106(Never), + V107(Never), + V108(Never), + V109(Never), + V110(Never), + V111(Never), + V112(Never), + V113(Never), + V114(Never), + V115(Never), + V116(Never), + V117(Never), + V118(Never), + V119(Never), + V120(Never), + V121(Never), + V122(Never), + V123(Never), + V124(Never), + V125(Never), + V126(Never), + V127(Never), + V128(Never), + V129(Never), + V130(Never), + V131(Never), + V132(Never), + V133(Never), + V134(Never), + V135(Never), + V136(Never), + V137(Never), + V138(Never), + V139(Never), + V140(Never), + V141(Never), + V142(Never), + V143(Never), + V144(Never), + V145(Never), + V146(Never), + V147(Never), + V148(Never), + V149(Never), + V150(Never), + V151(Never), + V152(Never), + V153(Never), + V154(Never), + V155(Never), + V156(Never), + V157(Never), + V158(Never), + V159(Never), + V160(Never), + V161(Never), + V162(Never), + V163(Never), + V164(Never), + V165(Never), + V166(Never), + V167(Never), + V168(Never), + V169(Never), + V170(Never), + V171(Never), + V172(Never), + V173(Never), + V174(Never), + V175(Never), + V176(Never), + V177(Never), + V178(Never), + V179(Never), + V180(Never), + V181(Never), + V182(Never), + V183(Never), + V184(Never), + V185(Never), + V186(Never), + V187(Never), + V188(Never), + V189(Never), + V190(Never), + V191(Never), + V192(Never), + V193(Never), + V194(Never), + V195(Never), + V196(Never), + V197(Never), + V198(Never), + V199(Never), + V200(Never), + V201(Never), + V202(Never), + V203(Never), + V204(Never), + V205(Never), + V206(Never), + V207(Never), + V208(Never), + V209(Never), + V210(Never), + V211(Never), + V212(Never), + V213(Never), + V214(Never), + V215(Never), + V216(Never), + V217(Never), + V218(Never), + V219(Never), + V220(Never), + V221(Never), + V222(Never), + V223(Never), + V224(Never), + V225(Never), + V226(Never), + V227(Never), + V228(Never), + V229(Never), + V230(Never), + V231(Never), + V232(Never), + V233(Never), + V234(Never), + V235(Never), + V236(Never), + V237(Never), + V238(Never), + V239(Never), + V240(Never), + V241(Never), + V242(Never), + V243(Never), + V244(Never), + V245(Never), + V246(Never), + V247(Never), + V248(Never), + V249(Never), + V250(Never), + V251(Never), + V252(Never), + V253(Never), + V254(Never), + V255(Never), + V256(Never), + + Possible257, + Bool258(bool), + Possible259, +} + +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match5(i8{{.+}}%0) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 +// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp{{( samesign)?}} ugt i8 %0, 1 +// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 257 +// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i64 %[[NICHE_DISCR]], 258 +// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 258 +// CHECK-NEXT: switch i64 %[[DISCR]], +// CHECK-NEXT: i64 257, +// CHECK-NEXT: i64 258, +// CHECK-NEXT: i64 259, +#[no_mangle] +pub fn match5(e: HugeVariantIndex) -> u8 { + use HugeVariantIndex::*; + match e { + Possible257 => 13, + Bool258(b) => b as u8, + Possible259 => 100, + } +} + +// Make an enum where the niche tags wrap both as signed and as unsigned, to hit +// the most-fallback case where there's just nothing smart to do. + +pub enum E10Through65 { + D10 = 10, + D11 = 11, + D12 = 12, + D13 = 13, + D14 = 14, + D15 = 15, + D16 = 16, + D17 = 17, + D18 = 18, + D19 = 19, + D20 = 20, + D21 = 21, + D22 = 22, + D23 = 23, + D24 = 24, + D25 = 25, + D26 = 26, + D27 = 27, + D28 = 28, + D29 = 29, + D30 = 30, + D31 = 31, + D32 = 32, + D33 = 33, + D34 = 34, + D35 = 35, + D36 = 36, + D37 = 37, + D38 = 38, + D39 = 39, + D40 = 40, + D41 = 41, + D42 = 42, + D43 = 43, + D44 = 44, + D45 = 45, + D46 = 46, + D47 = 47, + D48 = 48, + D49 = 49, + D50 = 50, + D51 = 51, + D52 = 52, + D53 = 53, + D54 = 54, + D55 = 55, + D56 = 56, + D57 = 57, + D58 = 58, + D59 = 59, + D60 = 60, + D61 = 61, + D62 = 62, + D63 = 63, + D64 = 64, + D65 = 65, +} + +pub enum Tricky { + Untagged(E10Through65), + V001, + V002, + V003, + V004, + V005, + V006, + V007, + V008, + V009, + V010, + V011, + V012, + V013, + V014, + V015, + V016, + V017, + V018, + V019, + V020, + V021, + V022, + V023, + V024, + V025, + V026, + V027, + V028, + V029, + V030, + V031, + V032, + V033, + V034, + V035, + V036, + V037, + V038, + V039, + V040, + V041, + V042, + V043, + V044, + V045, + V046, + V047, + V048, + V049, + V050, + V051, + V052, + V053, + V054, + V055, + V056, + V057, + V058, + V059, + V060, + V061, + V062, + V063, + V064, + V065, + V066, + V067, + V068, + V069, + V070, + V071, + V072, + V073, + V074, + V075, + V076, + V077, + V078, + V079, + V080, + V081, + V082, + V083, + V084, + V085, + V086, + V087, + V088, + V089, + V090, + V091, + V092, + V093, + V094, + V095, + V096, + V097, + V098, + V099, + V100, + V101, + V102, + V103, + V104, + V105, + V106, + V107, + V108, + V109, + V110, + V111, + V112, + V113, + V114, + V115, + V116, + V117, + V118, + V119, + V120, + V121, + V122, + V123, + V124, + V125, + V126, + V127, + V128, + V129, + V130, + V131, + V132, + V133, + V134, + V135, + V136, + V137, + V138, + V139, + V140, + V141, + V142, + V143, + V144, + V145, + V146, + V147, + V148, + V149, + V150, + V151, + V152, + V153, + V154, + V155, + V156, + V157, + V158, + V159, + V160, + V161, + V162, + V163, + V164, + V165, + V166, + V167, + V168, + V169, + V170, + V171, + V172, + V173, + V174, + V175, + V176, + V177, + V178, + V179, + V180, + V181, + V182, + V183, + V184, + V185, + V186, + V187, + V188, + V189, + V190, + V191, + V192, + V193, + V194, + V195, + V196, + V197, + V198, + V199, + V200, +} + +const _: () = assert!(std::intrinsics::discriminant_value(&Tricky::V100) == 100); + +// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @discriminant6(i8 noundef %e) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %e, -66 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], -56 +// CHECK-NEXT: %[[TAGGED_DISCR:.+]] = add i8 %e, -65 +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i8 %[[TAGGED_DISCR]], i8 0 +// CHECK-NEXT: ret i8 %[[DISCR]] +#[no_mangle] +pub fn discriminant6(e: Tricky) -> u8 { + std::intrinsics::discriminant_value(&e) as _ +} + +// Case from , +// where sign-extension is important. + +pub enum OpenResult { + Ok(()), + Err(()), + TransportErr(TransportErr), +} + +#[repr(i32)] +pub enum TransportErr { + UnknownMethod = -2, +} + +#[no_mangle] +pub fn match7(result: OpenResult) -> u8 { + // CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match7(i32{{.+}}%result) + // CHECK-NEXT: start: + // CHECK-NEXT: %[[NOT_OK:.+]] = icmp ne i32 %result, -1 + // CHECK-NEXT: %[[RET:.+]] = zext i1 %[[NOT_OK]] to i8 + // CHECK-NEXT: ret i8 %[[RET]] + match result { + OpenResult::Ok(()) => 0, + _ => 1, + } +} diff --git a/tests/codegen-llvm/enum/enum-two-variants-match.rs b/tests/codegen-llvm/enum/enum-two-variants-match.rs new file mode 100644 index 00000000000..12d9edc4d62 --- /dev/null +++ b/tests/codegen-llvm/enum/enum-two-variants-match.rs @@ -0,0 +1,130 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes +//@ only-64bit (because these discriminants are isize) + +#![crate_type = "lib"] + +// This directly tests what we emit for these matches, rather than what happens +// after optimization, so it doesn't need to worry about extra flags on the +// instructions and is less susceptible to being broken on LLVM updates. + +// CHECK-LABEL: @option_match +#[no_mangle] +pub fn option_match(x: Option) -> u16 { + // CHECK-NOT: %x = alloca + // CHECK: %[[OUT:.+]] = alloca [2 x i8] + // CHECK-NOT: %x = alloca + + // CHECK: %[[DISCR:.+]] = zext i32 %x.0 to i64 + // CHECK: %[[COND:.+]] = trunc nuw i64 %[[DISCR]] to i1 + // CHECK: br i1 %[[COND]], label %[[TRUE:[a-z0-9]+]], label %[[FALSE:[a-z0-9]+]] + + // CHECK: [[TRUE]]: + // CHECK: store i16 13, ptr %[[OUT]] + + // CHECK: [[FALSE]]: + // CHECK: store i16 42, ptr %[[OUT]] + + // CHECK: %[[RET:.+]] = load i16, ptr %[[OUT]] + // CHECK: ret i16 %[[RET]] + match x { + Some(_) => 13, + None => 42, + } +} + +// CHECK-LABEL: @result_match +#[no_mangle] +pub fn result_match(x: Result) -> u16 { + // CHECK-NOT: %x = alloca + // CHECK: %[[OUT:.+]] = alloca [2 x i8] + // CHECK-NOT: %x = alloca + + // CHECK: %[[COND:.+]] = trunc nuw i64 %x.0 to i1 + // CHECK: br i1 %[[COND]], label %[[TRUE:[a-z0-9]+]], label %[[FALSE:[a-z0-9]+]] + + // CHECK: [[TRUE]]: + // CHECK: store i16 13, ptr %[[OUT]] + + // CHECK: [[FALSE]]: + // CHECK: store i16 42, ptr %[[OUT]] + + // CHECK: %[[RET:.+]] = load i16, ptr %[[OUT]] + // CHECK: ret i16 %[[RET]] + match x { + Err(_) => 13, + Ok(_) => 42, + } +} + +// CHECK-LABEL: @option_bool_match( +#[no_mangle] +pub fn option_bool_match(x: Option) -> char { + // CHECK: %[[RAW:.+]] = load i8, ptr %x + // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %[[RAW]], 2 + // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1 + // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1 + // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]] + + // CHECK: [[BB_SOME]]: + // CHECK: %[[FIELD:.+]] = load i8, ptr %x + // CHECK: %[[FIELD_T:.+]] = trunc nuw i8 %[[FIELD]] to i1 + // CHECK: br i1 %[[FIELD_T]] + match x { + None => 'n', + Some(false) => 'f', + Some(true) => 't', + } +} + +use std::cmp::Ordering::{self, *}; +// CHECK-LABEL: @option_ordering_match( +#[no_mangle] +pub fn option_ordering_match(x: Option) -> char { + // CHECK: %[[RAW:.+]] = load i8, ptr %x + // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %[[RAW]], 2 + // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1 + // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1 + // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]] + + // CHECK: [[BB_SOME]]: + // CHECK: %[[FIELD:.+]] = load i8, ptr %x + // CHECK: switch i8 %[[FIELD]], label %[[UNREACHABLE:.+]] [ + // CHECK-NEXT: i8 -1, label + // CHECK-NEXT: i8 0, label + // CHECK-NEXT: i8 1, label + // CHECK-NEXT: ] + + // CHECK: [[UNREACHABLE]]: + // CHECK-NEXT: unreachable + match x { + None => '?', + Some(Less) => '<', + Some(Equal) => '=', + Some(Greater) => '>', + } +} + +// CHECK-LABEL: @option_nonzero_match( +#[no_mangle] +pub fn option_nonzero_match(x: Option>) -> u16 { + // CHECK: %[[OUT:.+]] = alloca [2 x i8] + + // CHECK: %[[IS_NONE:.+]] = icmp eq i16 %x, 0 + // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1 + // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1 + // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]] + + // CHECK: [[BB_SOME]]: + // CHECK: store i16 987, ptr %[[OUT]] + + // CHECK: [[BB_NONE]]: + // CHECK: store i16 123, ptr %[[OUT]] + + // CHECK: %[[RET:.+]] = load i16, ptr %[[OUT]] + // CHECK: ret i16 %[[RET]] + + match x { + None => 123, + Some(_) => 987, + } +} diff --git a/tests/codegen-llvm/enum/enum-u128.rs b/tests/codegen-llvm/enum/enum-u128.rs new file mode 100644 index 00000000000..2676669f3e3 --- /dev/null +++ b/tests/codegen-llvm/enum/enum-u128.rs @@ -0,0 +1,25 @@ +// This tests that debug info for "c-like" 128bit enums is properly emitted. +// This is ignored for the fallback mode on MSVC due to problems with PDB. + +// +//@ ignore-msvc +//@ ignore-wasi wasi codegens the main symbol differently + +//@ compile-flags: -g -C no-prepopulate-passes + +// CHECK-LABEL: @main +// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_enumeration_type,{{.*}}name: "Foo",{{.*}}flags: DIFlagEnumClass,{{.*}} +// CHECK: {{.*}}DIEnumerator{{.*}}name: "Lo",{{.*}}value: 0,{{.*}} +// CHECK: {{.*}}DIEnumerator{{.*}}name: "Hi",{{.*}}value: 18446744073709551616,{{.*}} +// CHECK: {{.*}}DIEnumerator{{.*}}name: "Bar",{{.*}}value: 18446745000000000123,{{.*}} + +#[repr(u128)] +pub enum Foo { + Lo, + Hi = 1 << 64, + Bar = 18_446_745_000_000_000_123, +} + +pub fn main() { + let foo = Foo::Bar; +} diff --git a/tests/codegen-llvm/enum/unreachable_enum_default_branch.rs b/tests/codegen-llvm/enum/unreachable_enum_default_branch.rs new file mode 100644 index 00000000000..55b165fc111 --- /dev/null +++ b/tests/codegen-llvm/enum/unreachable_enum_default_branch.rs @@ -0,0 +1,40 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Int(u32); + +const A: Int = Int(201); +const B: Int = Int(270); +const C: Int = Int(153); + +// The code is from https://github.com/rust-lang/rust/issues/119520. +// This code will basically turn into `matches!(x.partial_cmp(&A), Some(Greater | Equal))`. +// The otherwise branch must be `Less`. +// CHECK-LABEL: @implicit_match( +// CHECK-SAME: [[TMP0:%.*]]) +// CHECK-NEXT: start: +// CHECK-NEXT: [[TMP1:%.*]] = add i32 [[TMP0]], -201 +// CHECK-NEXT: icmp ult i32 [[TMP1]], 70 +// CHECK-NEXT: icmp eq i32 [[TMP0]], 153 +// CHECK-NEXT: [[SPEC_SELECT:%.*]] = or i1 +// CHECK-NEXT: ret i1 [[SPEC_SELECT]] +#[no_mangle] +pub fn implicit_match(x: Int) -> bool { + (x >= A && x <= B) || x == C +} + +// The code is from https://github.com/rust-lang/rust/issues/110097. +// We expect it to generate the same optimized code as a full match. +// CHECK-LABEL: @if_let( +// CHECK: start: +// CHECK-NOT: zext +// CHECK: select +// CHECK-NEXT: insertvalue +// CHECK-NEXT: insertvalue +// CHECK-NEXT: ret +#[no_mangle] +pub fn if_let(val: Result) -> Result { + if let Ok(x) = val { Ok(x * 2) } else { Err(()) } +} diff --git a/tests/codegen-llvm/ergonomic-clones/closure.rs b/tests/codegen-llvm/ergonomic-clones/closure.rs new file mode 100644 index 00000000000..b6fc8172641 --- /dev/null +++ b/tests/codegen-llvm/ergonomic-clones/closure.rs @@ -0,0 +1,55 @@ +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -Zmir-opt-level=0 + +#![crate_type = "lib"] + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +use std::clone::UseCloned; + +pub fn ergonomic_clone_closure_move() -> String { + let s = String::from("hi"); + + // CHECK-NOT: ; call core::clone::impls::::clone + let cl = use || s; + cl() +} + +#[derive(Clone)] +struct Foo; + +impl UseCloned for Foo {} + +pub fn ergonomic_clone_closure_use_cloned() -> Foo { + let f = Foo; + + // CHECK: ; call ::clone + let f1 = use || f; + + // CHECK: ; call ::clone + let f2 = use || f; + + f +} + +pub fn ergonomic_clone_closure_copy() -> i32 { + let i = 1; + + // CHECK-NOT: ; call core::clone::impls::::clone + let i1 = use || i; + + // CHECK-NOT: ; call core::clone::impls::::clone + let i2 = use || i; + + i +} + +pub fn ergonomic_clone_closure_use_cloned_generics(f: T) -> T { + // CHECK-NOT: ; call core::clone::impls::::clone + let f1 = use || f; + + // CHECK-NOT: ; call core::clone::impls::::clone + let f2 = use || f; + + f +} diff --git a/tests/codegen-llvm/error-provide.rs b/tests/codegen-llvm/error-provide.rs new file mode 100644 index 00000000000..7f091e34359 --- /dev/null +++ b/tests/codegen-llvm/error-provide.rs @@ -0,0 +1,50 @@ +// Codegen test for #126242 + +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] +#![feature(error_generic_member_access)] +use std::error::Request; +use std::fmt; + +#[derive(Debug)] +struct MyBacktrace1 {} + +#[derive(Debug)] +struct MyBacktrace2 {} + +#[derive(Debug)] +struct MyBacktrace3 {} + +#[derive(Debug)] +struct MyError { + backtrace1: MyBacktrace1, + backtrace2: MyBacktrace2, + backtrace3: MyBacktrace3, + other: MyBacktrace3, +} + +impl fmt::Display for MyError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Example Error") + } +} + +impl std::error::Error for MyError { + // CHECK-LABEL: @provide + #[no_mangle] + fn provide<'a>(&'a self, request: &mut Request<'a>) { + // LLVM should be able to optimize multiple .provide_* calls into a switch table + // and eliminate redundant ones, rather than compare one-by-one. + + // CHECK-NEXT: start: + // CHECK-NEXT: %[[SCRUTINEE:[^ ]+]] = load i128, ptr + // CHECK-NEXT: switch i128 %[[SCRUTINEE]], label %{{.*}} [ + // CHECK-COUNT-3: i128 {{.*}}, label %{{.*}} + // CHECK-NEXT: ] + request + .provide_ref::(&self.backtrace1) + .provide_ref::(&self.other) + .provide_ref::(&self.backtrace2) + .provide_ref::(&self.backtrace3); + } +} diff --git a/tests/codegen-llvm/export-no-mangle.rs b/tests/codegen-llvm/export-no-mangle.rs new file mode 100644 index 00000000000..5040684f52e --- /dev/null +++ b/tests/codegen-llvm/export-no-mangle.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +mod private { + // CHECK: @FOO = + #[no_mangle] + pub static FOO: u32 = 3; + + // CHECK: @BAR = + #[export_name = "BAR"] + static BAR: u32 = 3; + + // CHECK: void @a() + #[no_mangle] + pub extern "C" fn a() {} + + // CHECK: void @b() + #[export_name = "b"] + extern "C" fn b() {} + + // CHECK: void @c() + #[export_name = "c"] + #[inline] + extern "C" fn c() {} + + // CHECK: void @d() + #[export_name = "d"] + #[inline(always)] + extern "C" fn d() {} +} diff --git a/tests/codegen-llvm/external-no-mangle-fns.rs b/tests/codegen-llvm/external-no-mangle-fns.rs new file mode 100644 index 00000000000..35ab0fd7909 --- /dev/null +++ b/tests/codegen-llvm/external-no-mangle-fns.rs @@ -0,0 +1,75 @@ +//@ compile-flags: -C no-prepopulate-passes +// `#[no_mangle]`d functions always have external linkage, i.e., no `internal` in their `define`s + +#![crate_type = "lib"] +#![no_std] + +// CHECK: define{{( dso_local)?}} void @a() +#[no_mangle] +fn a() {} + +// CHECK: define{{( dso_local)?}} void @b() +#[no_mangle] +pub fn b() {} + +mod private { + // CHECK: define{{( dso_local)?}} void @c() + #[no_mangle] + fn c() {} + + // CHECK: define{{( dso_local)?}} void @d() + #[no_mangle] + pub fn d() {} +} + +const HIDDEN: () = { + // CHECK: define{{( dso_local)?}} void @e() + #[no_mangle] + fn e() {} + + // CHECK: define{{( dso_local)?}} void @f() + #[no_mangle] + pub fn f() {} +}; + +// The surrounding item should not accidentally become external +// CHECK-LABEL: ; external_no_mangle_fns::x +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define internal +#[inline(never)] +fn x() { + // CHECK: define{{( dso_local)?}} void @g() + #[no_mangle] + fn g() { + x(); + } + + // CHECK: define{{( dso_local)?}} void @h() + #[no_mangle] + pub fn h() {} + + // side effect to keep `x` around + unsafe { + core::ptr::read_volatile(&42); + } +} + +// CHECK: define{{( dso_local)?}} void @i() +#[no_mangle] +#[inline] +fn i() {} + +// CHECK: define{{( dso_local)?}} void @j() +#[no_mangle] +#[inline] +pub fn j() {} + +// CHECK: define{{( dso_local)?}} void @k() +#[no_mangle] +#[inline(always)] +fn k() {} + +// CHECK: define{{( dso_local)?}} void @l() +#[no_mangle] +#[inline(always)] +pub fn l() {} diff --git a/tests/codegen-llvm/external-no-mangle-statics.rs b/tests/codegen-llvm/external-no-mangle-statics.rs new file mode 100644 index 00000000000..49f42ee977d --- /dev/null +++ b/tests/codegen-llvm/external-no-mangle-statics.rs @@ -0,0 +1,77 @@ +//@ revisions: lib staticlib +//@ ignore-emscripten default visibility is hidden +//@ compile-flags: -Copt-level=3 +//@ [lib] compile-flags: --crate-type lib +//@ [staticlib] compile-flags: --crate-type staticlib +// `#[no_mangle]`d static variables always have external linkage, i.e., no `internal` in their +// definitions + +// CHECK-DAG: @A = {{(dso_local )?}}local_unnamed_addr constant +#[no_mangle] +static A: u8 = 0; + +// CHECK-DAG: @B = {{(dso_local )?}}local_unnamed_addr global +#[no_mangle] +static mut B: u8 = 0; + +// CHECK-DAG: @C = {{(dso_local )?}}local_unnamed_addr constant +#[no_mangle] +pub static C: u8 = 0; + +// CHECK-DAG: @D = {{(dso_local )?}}local_unnamed_addr global +#[no_mangle] +pub static mut D: u8 = 0; + +mod private { + // CHECK-DAG: @E = {{(dso_local )?}}local_unnamed_addr constant + #[no_mangle] + static E: u8 = 0; + + // CHECK-DAG: @F = {{(dso_local )?}}local_unnamed_addr global + #[no_mangle] + static mut F: u8 = 0; + + // CHECK-DAG: @G = {{(dso_local )?}}local_unnamed_addr constant + #[no_mangle] + pub static G: u8 = 0; + + // CHECK-DAG: @H = {{(dso_local )?}}local_unnamed_addr global + #[no_mangle] + pub static mut H: u8 = 0; +} + +const HIDDEN: () = { + // CHECK-DAG: @I = {{(dso_local )?}}local_unnamed_addr constant + #[no_mangle] + static I: u8 = 0; + + // CHECK-DAG: @J = {{(dso_local )?}}local_unnamed_addr global + #[no_mangle] + static mut J: u8 = 0; + + // CHECK-DAG: @K = {{(dso_local )?}}local_unnamed_addr constant + #[no_mangle] + pub static K: u8 = 0; + + // CHECK-DAG: @L = {{(dso_local )?}}local_unnamed_addr global + #[no_mangle] + pub static mut L: u8 = 0; +}; + +fn x() { + // CHECK-DAG: @M = {{(dso_local )?}}local_unnamed_addr constant + #[no_mangle] + static M: fn() = x; + + // CHECK-DAG: @N = {{(dso_local )?}}local_unnamed_addr global + #[no_mangle] + static mut N: u8 = 0; + + // CHECK-DAG: @O = {{(dso_local )?}}local_unnamed_addr constant + #[no_mangle] + pub static O: u8 = 0; + + // CHECK-DAG: @P = {{(dso_local )?}}local_unnamed_addr global + #[no_mangle] + pub static mut P: u8 = 0; +} diff --git a/tests/codegen-llvm/f128-wasm32-callconv.rs b/tests/codegen-llvm/f128-wasm32-callconv.rs new file mode 100644 index 00000000000..7dccbda18f1 --- /dev/null +++ b/tests/codegen-llvm/f128-wasm32-callconv.rs @@ -0,0 +1,49 @@ +//! Verify that Rust implements the expected calling convention for `f128` + +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 --target wasm32-wasip1 +//@ needs-llvm-components: webassembly + +#![crate_type = "lib"] +#![no_std] +#![no_core] +#![feature(no_core, lang_items, f128)] + +extern crate minicore; + +extern "C" { + fn extern_call(arg0: f128); + fn extern_ret() -> f128; +} + +#[no_mangle] +pub extern "C" fn pass(_arg0: u32, arg1: f128) { + // CHECK-LABEL: @pass( + // an f128 is passed via registers + // CHECK-SAME: fp128 noundef %arg1 + // CHECK: call void @extern_call + unsafe { extern_call(arg1) }; +} + +// Check that we produce the correct return ABI +#[no_mangle] +pub extern "C" fn ret(_arg0: u32, arg1: f128) -> f128 { + // CHECK-LABEL: @ret( + // but an f128 is returned via the stack + // CHECK-SAME: sret + // CHECK: store fp128 %arg1 + // CHECK-NEXT: ret void + arg1 +} + +// Check that we consume the correct return ABI +#[no_mangle] +pub extern "C" fn forward(dst: *mut f128) { + // CHECK-LABEL: @forward + // CHECK-SAME: ptr{{.*}} %dst) + // without optimizatons, an intermediate alloca is used + // CHECK: call void @extern_ret + // CHECK: store fp128 + // CHECK: ret void + unsafe { *dst = extern_ret() }; +} diff --git a/tests/codegen-llvm/fastcall-inreg.rs b/tests/codegen-llvm/fastcall-inreg.rs new file mode 100644 index 00000000000..066943d6e7e --- /dev/null +++ b/tests/codegen-llvm/fastcall-inreg.rs @@ -0,0 +1,40 @@ +// Checks if the "fastcall" calling convention marks function arguments +// as "inreg" like the C/C++ compilers for the platforms. +// x86 only. + +//@ add-core-stubs +//@ compile-flags: --target i686-unknown-linux-gnu -Cno-prepopulate-passes -Copt-level=3 +//@ needs-llvm-components: x86 + +#![crate_type = "lib"] +#![no_core] +#![feature(no_core, lang_items)] + +extern crate minicore; +use minicore::*; + +pub mod tests { + // CHECK: @f1(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) + #[no_mangle] + pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {} + + // CHECK: @f2(ptr inreg noundef %_1, ptr inreg noundef %_2, ptr noundef %_3) + #[no_mangle] + pub extern "fastcall" fn f2(_: *const i32, _: *const i32, _: *const i32) {} + + // CHECK: @f3(float noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3, i32 noundef %_4) + #[no_mangle] + pub extern "fastcall" fn f3(_: f32, _: i32, _: i32, _: i32) {} + + // CHECK: @f4(i32 inreg noundef %_1, float noundef %_2, i32 inreg noundef %_3, i32 noundef %_4) + #[no_mangle] + pub extern "fastcall" fn f4(_: i32, _: f32, _: i32, _: i32) {} + + // CHECK: @f5(i64 noundef %_1, i32 noundef %_2) + #[no_mangle] + pub extern "fastcall" fn f5(_: i64, _: i32) {} + + // CHECK: @f6(i1 inreg noundef zeroext %_1, i32 inreg noundef %_2, i32 noundef %_3) + #[no_mangle] + pub extern "fastcall" fn f6(_: bool, _: i32, _: i32) {} +} diff --git a/tests/codegen-llvm/fatptr.rs b/tests/codegen-llvm/fatptr.rs new file mode 100644 index 00000000000..041807202b8 --- /dev/null +++ b/tests/codegen-llvm/fatptr.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +pub trait T {} + +// CHECK-LABEL: @copy_fat_ptr +#[no_mangle] +pub fn copy_fat_ptr(x: &T) { + // CHECK-NOT: extractvalue + let x2 = x; +} diff --git a/tests/codegen-llvm/fewer-names.rs b/tests/codegen-llvm/fewer-names.rs new file mode 100644 index 00000000000..ff7a916b619 --- /dev/null +++ b/tests/codegen-llvm/fewer-names.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -Coverflow-checks=no -Copt-level=3 +//@ revisions: YES NO +//@ [YES]compile-flags: -Zfewer-names=yes +//@ [NO] compile-flags: -Zfewer-names=no +#![crate_type = "lib"] + +#[no_mangle] +pub fn sum(x: u32, y: u32) -> u32 { + // YES-LABEL: define{{.*}}i32 @sum(i32{{.*}} %0, i32{{.*}} %1) + // YES-NEXT: %3 = add i32 %1, %0 + // YES-NEXT: ret i32 %3 + + // NO-LABEL: define{{.*}}i32 @sum(i32{{.*}} %x, i32{{.*}} %y) + // NO-NEXT: start: + // NO-NEXT: %z = add i32 %y, %x + // NO-NEXT: ret i32 %z + let z = x + y; + z +} diff --git a/tests/codegen-llvm/fixed-x18.rs b/tests/codegen-llvm/fixed-x18.rs new file mode 100644 index 00000000000..a5767cfa456 --- /dev/null +++ b/tests/codegen-llvm/fixed-x18.rs @@ -0,0 +1,23 @@ +// Test that the `reserve-x18` target feature is (not) emitted when +// the `-Zfixed-x18` flag is (not) set. + +//@ add-core-stubs +//@ revisions: unset set +//@ needs-llvm-components: aarch64 +//@ compile-flags: --target aarch64-unknown-none +//@ [set] compile-flags: -Zfixed-x18 + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + + // unset-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+reserve-x18{{.*}} } + // set: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+reserve-x18{{.*}} } +} diff --git a/tests/codegen-llvm/float/algebraic.rs b/tests/codegen-llvm/float/algebraic.rs new file mode 100644 index 00000000000..818a4bcdfe3 --- /dev/null +++ b/tests/codegen-llvm/float/algebraic.rs @@ -0,0 +1,149 @@ +// Verify that algebraic intrinsics generate the correct LLVM calls + +// Ensure operations get inlined +//@ compile-flags: -Copt-level=1 + +#![crate_type = "lib"] +#![feature(f16)] +#![feature(f128)] +#![feature(float_algebraic)] + +// CHECK-LABEL: @f16_algebraic_add +#[no_mangle] +pub fn f16_algebraic_add(a: f16, b: f16) -> f16 { + // CHECK: fadd reassoc nsz arcp contract half %{{.+}}, %{{.+}} + a.algebraic_add(b) +} + +// CHECK-LABEL: @f16_algebraic_sub +#[no_mangle] +pub fn f16_algebraic_sub(a: f16, b: f16) -> f16 { + // CHECK: fsub reassoc nsz arcp contract half %{{.+}}, %{{.+}} + a.algebraic_sub(b) +} + +// CHECK-LABEL: @f16_algebraic_mul +#[no_mangle] +pub fn f16_algebraic_mul(a: f16, b: f16) -> f16 { + // CHECK: fmul reassoc nsz arcp contract half %{{.+}}, %{{.+}} + a.algebraic_mul(b) +} + +// CHECK-LABEL: @f16_algebraic_div +#[no_mangle] +pub fn f16_algebraic_div(a: f16, b: f16) -> f16 { + // CHECK: fdiv reassoc nsz arcp contract half %{{.+}}, %{{.+}} + a.algebraic_div(b) +} + +// CHECK-LABEL: @f16_algebraic_rem +#[no_mangle] +pub fn f16_algebraic_rem(a: f16, b: f16) -> f16 { + // CHECK: frem reassoc nsz arcp contract half %{{.+}}, %{{.+}} + a.algebraic_rem(b) +} + +// CHECK-LABEL: @f32_algebraic_add +#[no_mangle] +pub fn f32_algebraic_add(a: f32, b: f32) -> f32 { + // CHECK: fadd reassoc nsz arcp contract float %{{.+}}, %{{.+}} + a.algebraic_add(b) +} + +// CHECK-LABEL: @f32_algebraic_sub +#[no_mangle] +pub fn f32_algebraic_sub(a: f32, b: f32) -> f32 { + // CHECK: fsub reassoc nsz arcp contract float %{{.+}}, %{{.+}} + a.algebraic_sub(b) +} + +// CHECK-LABEL: @f32_algebraic_mul +#[no_mangle] +pub fn f32_algebraic_mul(a: f32, b: f32) -> f32 { + // CHECK: fmul reassoc nsz arcp contract float %{{.+}}, %{{.+}} + a.algebraic_mul(b) +} + +// CHECK-LABEL: @f32_algebraic_div +#[no_mangle] +pub fn f32_algebraic_div(a: f32, b: f32) -> f32 { + // CHECK: fdiv reassoc nsz arcp contract float %{{.+}}, %{{.+}} + a.algebraic_div(b) +} + +// CHECK-LABEL: @f32_algebraic_rem +#[no_mangle] +pub fn f32_algebraic_rem(a: f32, b: f32) -> f32 { + // CHECK: frem reassoc nsz arcp contract float %{{.+}}, %{{.+}} + a.algebraic_rem(b) +} + +// CHECK-LABEL: @f64_algebraic_add +#[no_mangle] +pub fn f64_algebraic_add(a: f64, b: f64) -> f64 { + // CHECK: fadd reassoc nsz arcp contract double %{{.+}}, %{{.+}} + a.algebraic_add(b) +} + +// CHECK-LABEL: @f64_algebraic_sub +#[no_mangle] +pub fn f64_algebraic_sub(a: f64, b: f64) -> f64 { + // CHECK: fsub reassoc nsz arcp contract double %{{.+}}, %{{.+}} + a.algebraic_sub(b) +} + +// CHECK-LABEL: @f64_algebraic_mul +#[no_mangle] +pub fn f64_algebraic_mul(a: f64, b: f64) -> f64 { + // CHECK: fmul reassoc nsz arcp contract double %{{.+}}, %{{.+}} + a.algebraic_mul(b) +} + +// CHECK-LABEL: @f64_algebraic_div +#[no_mangle] +pub fn f64_algebraic_div(a: f64, b: f64) -> f64 { + // CHECK: fdiv reassoc nsz arcp contract double %{{.+}}, %{{.+}} + a.algebraic_div(b) +} + +// CHECK-LABEL: @f64_algebraic_rem +#[no_mangle] +pub fn f64_algebraic_rem(a: f64, b: f64) -> f64 { + // CHECK: frem reassoc nsz arcp contract double %{{.+}}, %{{.+}} + a.algebraic_rem(b) +} + +// CHECK-LABEL: @f128_algebraic_add +#[no_mangle] +pub fn f128_algebraic_add(a: f128, b: f128) -> f128 { + // CHECK: fadd reassoc nsz arcp contract fp128 %{{.+}}, %{{.+}} + a.algebraic_add(b) +} + +// CHECK-LABEL: @f128_algebraic_sub +#[no_mangle] +pub fn f128_algebraic_sub(a: f128, b: f128) -> f128 { + // CHECK: fsub reassoc nsz arcp contract fp128 %{{.+}}, %{{.+}} + a.algebraic_sub(b) +} + +// CHECK-LABEL: @f128_algebraic_mul +#[no_mangle] +pub fn f128_algebraic_mul(a: f128, b: f128) -> f128 { + // CHECK: fmul reassoc nsz arcp contract fp128 %{{.+}}, %{{.+}} + a.algebraic_mul(b) +} + +// CHECK-LABEL: @f128_algebraic_div +#[no_mangle] +pub fn f128_algebraic_div(a: f128, b: f128) -> f128 { + // CHECK: fdiv reassoc nsz arcp contract fp128 %{{.+}}, %{{.+}} + a.algebraic_div(b) +} + +// CHECK-LABEL: @f128_algebraic_rem +#[no_mangle] +pub fn f128_algebraic_rem(a: f128, b: f128) -> f128 { + // CHECK: frem reassoc nsz arcp contract fp128 %{{.+}}, %{{.+}} + a.algebraic_rem(b) +} diff --git a/tests/codegen-llvm/float/f128.rs b/tests/codegen-llvm/float/f128.rs new file mode 100644 index 00000000000..d87bab1172a --- /dev/null +++ b/tests/codegen-llvm/float/f128.rs @@ -0,0 +1,441 @@ +// 32-bit x86 returns float types differently to avoid the x87 stack. +// 32-bit systems will return 128bit values using a return area pointer. +// Emscripten aligns f128 to 8 bytes, not 16. +//@ revisions: x86-sse x86-nosse bit32 bit64 emscripten +//@[x86-sse] only-x86 +//@[x86-sse] only-rustc_abi-x86-sse2 +//@[x86-nosse] only-x86 +//@[x86-nosse] ignore-rustc_abi-x86-sse2 +//@[bit32] ignore-x86 +//@[bit32] ignore-emscripten +//@[bit32] only-32bit +//@[bit64] ignore-x86 +//@[bit64] ignore-emscripten +//@[bit64] only-64bit +//@[emscripten] only-emscripten + +// Verify that our intrinsics generate the correct LLVM calls for f128 + +#![crate_type = "lib"] +#![feature(f128)] +#![feature(f16)] +#![feature(core_intrinsics)] + +// CHECK-LABEL: i1 @f128_eq( +#[no_mangle] +pub fn f128_eq(a: f128, b: f128) -> bool { + // CHECK: fcmp oeq fp128 %{{.+}}, %{{.+}} + a == b +} + +// CHECK-LABEL: i1 @f128_ne( +#[no_mangle] +pub fn f128_ne(a: f128, b: f128) -> bool { + // CHECK: fcmp une fp128 %{{.+}}, %{{.+}} + a != b +} + +// CHECK-LABEL: i1 @f128_gt( +#[no_mangle] +pub fn f128_gt(a: f128, b: f128) -> bool { + // CHECK: fcmp ogt fp128 %{{.+}}, %{{.+}} + a > b +} + +// CHECK-LABEL: i1 @f128_ge( +#[no_mangle] +pub fn f128_ge(a: f128, b: f128) -> bool { + // CHECK: fcmp oge fp128 %{{.+}}, %{{.+}} + a >= b +} + +// CHECK-LABEL: i1 @f128_lt( +#[no_mangle] +pub fn f128_lt(a: f128, b: f128) -> bool { + // CHECK: fcmp olt fp128 %{{.+}}, %{{.+}} + a < b +} + +// CHECK-LABEL: i1 @f128_le( +#[no_mangle] +pub fn f128_le(a: f128, b: f128) -> bool { + // CHECK: fcmp ole fp128 %{{.+}}, %{{.+}} + a <= b +} + +// x86-nosse-LABEL: void @f128_neg({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f128_neg(fp128 +// bit32-LABEL: void @f128_neg({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @f128_neg( +// emscripten-LABEL: void @f128_neg({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn f128_neg(a: f128) -> f128 { + // CHECK: fneg fp128 + -a +} + +// x86-nosse-LABEL: void @f128_add({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f128_add(fp128 +// bit32-LABEL: void @f128_add({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @f128_add( +// emscripten-LABEL: void @f128_add({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn f128_add(a: f128, b: f128) -> f128 { + // CHECK: fadd fp128 %{{.+}}, %{{.+}} + a + b +} + +// x86-nosse-LABEL: void @f128_sub({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f128_sub(fp128 +// bit32-LABEL: void @f128_sub({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @f128_sub( +// emscripten-LABEL: void @f128_sub({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn f128_sub(a: f128, b: f128) -> f128 { + // CHECK: fsub fp128 %{{.+}}, %{{.+}} + a - b +} + +// x86-nosse-LABEL: void @f128_mul({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f128_mul(fp128 +// bit32-LABEL: void @f128_mul({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @f128_mul( +// emscripten-LABEL: void @f128_mul({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn f128_mul(a: f128, b: f128) -> f128 { + // CHECK: fmul fp128 %{{.+}}, %{{.+}} + a * b +} + +// x86-nosse-LABEL: void @f128_div({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f128_div(fp128 +// bit32-LABEL: void @f128_div({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @f128_div( +// emscripten-LABEL: void @f128_div({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn f128_div(a: f128, b: f128) -> f128 { + // CHECK: fdiv fp128 %{{.+}}, %{{.+}} + a / b +} + +// x86-nosse-LABEL: void @f128_rem({{.*}}sret([16 x i8]) +// x86-sse-LABEL: <16 x i8> @f128_rem(fp128 +// bit32-LABEL: void @f128_rem({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @f128_rem( +// emscripten-LABEL: void @f128_rem({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn f128_rem(a: f128, b: f128) -> f128 { + // CHECK: frem fp128 %{{.+}}, %{{.+}} + a % b +} + +// CHECK-LABEL: void @f128_add_assign( +#[no_mangle] +pub fn f128_add_assign(a: &mut f128, b: f128) { + // CHECK: fadd fp128 %{{.+}}, %{{.+}} + // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} + *a += b; +} + +// CHECK-LABEL: void @f128_sub_assign( +#[no_mangle] +pub fn f128_sub_assign(a: &mut f128, b: f128) { + // CHECK: fsub fp128 %{{.+}}, %{{.+}} + // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} + *a -= b; +} + +// CHECK-LABEL: void @f128_mul_assign( +#[no_mangle] +pub fn f128_mul_assign(a: &mut f128, b: f128) { + // CHECK: fmul fp128 %{{.+}}, %{{.+}} + // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} + *a *= b +} + +// CHECK-LABEL: void @f128_div_assign( +#[no_mangle] +pub fn f128_div_assign(a: &mut f128, b: f128) { + // CHECK: fdiv fp128 %{{.+}}, %{{.+}} + // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} + *a /= b +} + +// CHECK-LABEL: void @f128_rem_assign( +#[no_mangle] +pub fn f128_rem_assign(a: &mut f128, b: f128) { + // CHECK: frem fp128 %{{.+}}, %{{.+}} + // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} + *a %= b +} + +/* float to float conversions */ + +// x86-sse-LABEL: <2 x i8> @f128_as_f16( +// x86-nosse-LABEL: i16 @f128_as_f16( +// bits32-LABEL: half @f128_as_f16( +// bits64-LABEL: half @f128_as_f16( +#[no_mangle] +pub fn f128_as_f16(a: f128) -> f16 { + // CHECK: fptrunc fp128 %{{.+}} to half + a as f16 +} + +// x86-sse-LABEL: <4 x i8> @f128_as_f32( +// x86-nosse-LABEL: i32 @f128_as_f32( +// bit32-LABEL: float @f128_as_f32( +// bit64-LABEL: float @f128_as_f32( +// emscripten-LABEL: float @f128_as_f32( +#[no_mangle] +pub fn f128_as_f32(a: f128) -> f32 { + // CHECK: fptrunc fp128 %{{.+}} to float + a as f32 +} + +// x86-sse-LABEL: <8 x i8> @f128_as_f64( +// x86-nosse-LABEL: void @f128_as_f64({{.*}}sret([8 x i8]) +// bit32-LABEL: double @f128_as_f64( +// bit64-LABEL: double @f128_as_f64( +// emscripten-LABEL: double @f128_as_f64( +#[no_mangle] +pub fn f128_as_f64(a: f128) -> f64 { + // CHECK: fptrunc fp128 %{{.+}} to double + a as f64 +} + +// x86-sse-LABEL: <16 x i8> @f128_as_self( +// x86-nosse-LABEL: void @f128_as_self({{.*}}sret([16 x i8]) +// bit32-LABEL: void @f128_as_self({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @f128_as_self( +// emscripten-LABEL: void @f128_as_self({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn f128_as_self(a: f128) -> f128 { + // x86: store fp128 %a, ptr %_0, align 16 + // bit32: store fp128 %a, ptr %_0, align 16 + // bit64: ret fp128 %{{.+}} + // emscripten: store fp128 %a, ptr %_0, align 8 + a as f128 +} + +// x86-sse-LABEL: <16 x i8> @f16_as_f128( +// x86-nosse-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @f16_as_f128( +// emscripten-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn f16_as_f128(a: f16) -> f128 { + // CHECK: fpext half %{{.+}} to fp128 + a as f128 +} + +// x86-sse-LABEL: <16 x i8> @f32_as_f128( +// x86-nosse-LABEL: void @f32_as_f128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @f32_as_f128({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @f32_as_f128( +// emscripten-LABEL: void @f32_as_f128({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn f32_as_f128(a: f32) -> f128 { + // CHECK: fpext float %{{.+}} to fp128 + a as f128 +} + +// x86-sse-LABEL: <16 x i8> @f64_as_f128( +// x86-nosse-LABEL: void @f64_as_f128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @f64_as_f128({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @f64_as_f128( +// emscripten-LABEL: void @f64_as_f128({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn f64_as_f128(a: f64) -> f128 { + // CHECK: fpext double %{{.+}} to fp128 + a as f128 +} + +/* float to int conversions */ + +// CHECK-LABEL: i8 @f128_as_u8( +#[no_mangle] +pub fn f128_as_u8(a: f128) -> u8 { + // CHECK: call i8 @llvm.fptoui.sat.i8.f128(fp128 %{{.+}}) + a as u8 +} + +#[no_mangle] +pub fn f128_as_u16(a: f128) -> u16 { + // CHECK: call i16 @llvm.fptoui.sat.i16.f128(fp128 %{{.+}}) + a as u16 +} + +// CHECK-LABEL: i32 @f128_as_u32( +#[no_mangle] +pub fn f128_as_u32(a: f128) -> u32 { + // CHECK: call i32 @llvm.fptoui.sat.i32.f128(fp128 %{{.+}}) + a as u32 +} + +// CHECK-LABEL: i64 @f128_as_u64( +#[no_mangle] +pub fn f128_as_u64(a: f128) -> u64 { + // CHECK: call i64 @llvm.fptoui.sat.i64.f128(fp128 %{{.+}}) + a as u64 +} + +// x86-sse-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) +// x86-nosse-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) +// bit64-LABEL: i128 @f128_as_u128( +// emscripten-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn f128_as_u128(a: f128) -> u128 { + // CHECK: call i128 @llvm.fptoui.sat.i128.f128(fp128 %{{.+}}) + a as u128 +} + +// CHECK-LABEL: i8 @f128_as_i8( +#[no_mangle] +pub fn f128_as_i8(a: f128) -> i8 { + // CHECK: call i8 @llvm.fptosi.sat.i8.f128(fp128 %{{.+}}) + a as i8 +} + +// CHECK-LABEL: i16 @f128_as_i16( +#[no_mangle] +pub fn f128_as_i16(a: f128) -> i16 { + // CHECK: call i16 @llvm.fptosi.sat.i16.f128(fp128 %{{.+}}) + a as i16 +} +// CHECK-LABEL: i32 @f128_as_i32( +#[no_mangle] +pub fn f128_as_i32(a: f128) -> i32 { + // CHECK: call i32 @llvm.fptosi.sat.i32.f128(fp128 %{{.+}}) + a as i32 +} + +// CHECK-LABEL: i64 @f128_as_i64( +#[no_mangle] +pub fn f128_as_i64(a: f128) -> i64 { + // CHECK: call i64 @llvm.fptosi.sat.i64.f128(fp128 %{{.+}}) + a as i64 +} + +// x86-sse-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) +// x86-nosse-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) +// bit64-LABEL: i128 @f128_as_i128( +// emscripten-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn f128_as_i128(a: f128) -> i128 { + // CHECK: call i128 @llvm.fptosi.sat.i128.f128(fp128 %{{.+}}) + a as i128 +} + +/* int to float conversions */ + +// x86-sse-LABEL: <16 x i8> @u8_as_f128( +// x86-nosse-LABEL: void @u8_as_f128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @u8_as_f128({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @u8_as_f128( +// emscripten-LABEL: void @u8_as_f128({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn u8_as_f128(a: u8) -> f128 { + // CHECK: uitofp i8 %{{.+}} to fp128 + a as f128 +} + +// x86-sse-LABEL: <16 x i8> @u16_as_f128( +// x86-nosse-LABEL: void @u16_as_f128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @u16_as_f128({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @u16_as_f128( +// emscripten-LABEL: void @u16_as_f128({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn u16_as_f128(a: u16) -> f128 { + // CHECK: uitofp i16 %{{.+}} to fp128 + a as f128 +} + +// x86-sse-LABEL: <16 x i8> @u32_as_f128( +// x86-nosse-LABEL: void @u32_as_f128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @u32_as_f128({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @u32_as_f128( +// emscripten-LABEL: void @u32_as_f128({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn u32_as_f128(a: u32) -> f128 { + // CHECK: uitofp i32 %{{.+}} to fp128 + a as f128 +} + +// x86-sse-LABEL: <16 x i8> @u64_as_f128( +// x86-nosse-LABEL: void @u64_as_f128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @u64_as_f128({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @u64_as_f128( +// emscripten-LABEL: void @u64_as_f128({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn u64_as_f128(a: u64) -> f128 { + // CHECK: uitofp i64 %{{.+}} to fp128 + a as f128 +} + +// x86-sse-LABEL: <16 x i8> @u128_as_f128( +// x86-nosse-LABEL: void @u128_as_f128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @u128_as_f128({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @u128_as_f128( +// emscripten-LABEL: void @u128_as_f128({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn u128_as_f128(a: u128) -> f128 { + // CHECK: uitofp i128 %{{.+}} to fp128 + a as f128 +} + +// x86-sse-LABEL: <16 x i8> @i8_as_f128( +// x86-nosse-LABEL: void @i8_as_f128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @i8_as_f128({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @i8_as_f128( +// emscripten-LABEL: void @i8_as_f128({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn i8_as_f128(a: i8) -> f128 { + // CHECK: sitofp i8 %{{.+}} to fp128 + a as f128 +} + +// x86-sse-LABEL: <16 x i8> @i16_as_f128( +// x86-nosse-LABEL: void @i16_as_f128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @i16_as_f128({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @i16_as_f128( +// emscripten-LABEL: void @i16_as_f128({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn i16_as_f128(a: i16) -> f128 { + // CHECK: sitofp i16 %{{.+}} to fp128 + a as f128 +} + +// x86-sse-LABEL: <16 x i8> @i32_as_f128( +// x86-nosse-LABEL: void @i32_as_f128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @i32_as_f128({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @i32_as_f128( +// emscripten-LABEL: void @i32_as_f128({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn i32_as_f128(a: i32) -> f128 { + // CHECK: sitofp i32 %{{.+}} to fp128 + a as f128 +} + +// x86-sse-LABEL: <16 x i8> @i64_as_f128( +// x86-nosse-LABEL: void @i64_as_f128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @i64_as_f128({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @i64_as_f128( +// emscripten-LABEL: void @i64_as_f128({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn i64_as_f128(a: i64) -> f128 { + // CHECK: sitofp i64 %{{.+}} to fp128 + a as f128 +} + +// x86-sse-LABEL: <16 x i8> @i128_as_f128( +// x86-nosse-LABEL: void @i128_as_f128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @i128_as_f128({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @i128_as_f128( +// emscripten-LABEL: void @i128_as_f128({{.*}}sret([16 x i8]) +#[no_mangle] +pub fn i128_as_f128(a: i128) -> f128 { + // CHECK: sitofp i128 %{{.+}} to fp128 + a as f128 +} diff --git a/tests/codegen-llvm/float/f16-f128-inline.rs b/tests/codegen-llvm/float/f16-f128-inline.rs new file mode 100644 index 00000000000..aa2c38c209e --- /dev/null +++ b/tests/codegen-llvm/float/f16-f128-inline.rs @@ -0,0 +1,29 @@ +//@ revisions: default nopt +//@[nopt] compile-flags: -Copt-level=0 -Zcross-crate-inline-threshold=never -Zmir-opt-level=0 -Cno-prepopulate-passes + +// Ensure that functions using `f16` and `f128` are always inlined to avoid crashes +// when the backend does not support these types. + +#![crate_type = "lib"] +#![feature(f128)] +#![feature(f16)] + +pub fn f16_arg(_a: f16) { + // CHECK-NOT: f16_arg + todo!() +} + +pub fn f16_ret() -> f16 { + // CHECK-NOT: f16_ret + todo!() +} + +pub fn f128_arg(_a: f128) { + // CHECK-NOT: f128_arg + todo!() +} + +pub fn f128_ret() -> f128 { + // CHECK-NOT: f128_ret + todo!() +} diff --git a/tests/codegen-llvm/float/f16.rs b/tests/codegen-llvm/float/f16.rs new file mode 100644 index 00000000000..0c40606ad8a --- /dev/null +++ b/tests/codegen-llvm/float/f16.rs @@ -0,0 +1,364 @@ +// 32-bit x86 returns float types differently to avoid the x87 stack. +// 32-bit systems will return 128bit values using a return area pointer. +//@ revisions: x86-sse x86-nosse bit32 bit64 +//@[x86-sse] only-x86 +//@[x86-sse] only-rustc_abi-x86-sse2 +//@[x86-nosse] only-x86 +//@[x86-nosse] ignore-rustc_abi-x86-sse2 +//@[bit32] ignore-x86 +//@[bit32] only-32bit +//@[bit64] ignore-x86 +//@[bit64] only-64bit + +// Verify that our intrinsics generate the correct LLVM calls for f16 + +#![crate_type = "lib"] +#![feature(f128)] +#![feature(f16)] +#![feature(core_intrinsics)] + +/* arithmetic */ + +// CHECK-LABEL: i1 @f16_eq( +#[no_mangle] +pub fn f16_eq(a: f16, b: f16) -> bool { + // CHECK: fcmp oeq half %{{.+}}, %{{.+}} + a == b +} + +// CHECK-LABEL: i1 @f16_ne( +#[no_mangle] +pub fn f16_ne(a: f16, b: f16) -> bool { + // CHECK: fcmp une half %{{.+}}, %{{.+}} + a != b +} + +// CHECK-LABEL: i1 @f16_gt( +#[no_mangle] +pub fn f16_gt(a: f16, b: f16) -> bool { + // CHECK: fcmp ogt half %{{.+}}, %{{.+}} + a > b +} + +// CHECK-LABEL: i1 @f16_ge( +#[no_mangle] +pub fn f16_ge(a: f16, b: f16) -> bool { + // CHECK: fcmp oge half %{{.+}}, %{{.+}} + a >= b +} + +// CHECK-LABEL: i1 @f16_lt( +#[no_mangle] +pub fn f16_lt(a: f16, b: f16) -> bool { + // CHECK: fcmp olt half %{{.+}}, %{{.+}} + a < b +} + +// CHECK-LABEL: i1 @f16_le( +#[no_mangle] +pub fn f16_le(a: f16, b: f16) -> bool { + // CHECK: fcmp ole half %{{.+}}, %{{.+}} + a <= b +} + +// This is where we check the argument and return ABI for f16. +// bit32-LABEL: half @f16_neg(half +// bit64-LABEL: half @f16_neg(half +// x86-sse-LABEL: <2 x i8> @f16_neg(half +// x86-nosse-LABEL: i16 @f16_neg(half +#[no_mangle] +pub fn f16_neg(a: f16) -> f16 { + // CHECK: fneg half %{{.+}} + -a +} + +// CHECK-LABEL: @f16_add +#[no_mangle] +pub fn f16_add(a: f16, b: f16) -> f16 { + // CHECK: fadd half %{{.+}}, %{{.+}} + a + b +} + +// CHECK-LABEL: @f16_sub +#[no_mangle] +pub fn f16_sub(a: f16, b: f16) -> f16 { + // CHECK: fsub half %{{.+}}, %{{.+}} + a - b +} + +// CHECK-LABEL: @f16_mul +#[no_mangle] +pub fn f16_mul(a: f16, b: f16) -> f16 { + // CHECK: fmul half %{{.+}}, %{{.+}} + a * b +} + +// CHECK-LABEL: @f16_div +#[no_mangle] +pub fn f16_div(a: f16, b: f16) -> f16 { + // CHECK: fdiv half %{{.+}}, %{{.+}} + a / b +} + +// CHECK-LABEL: @f16_rem +#[no_mangle] +pub fn f16_rem(a: f16, b: f16) -> f16 { + // CHECK: frem half %{{.+}}, %{{.+}} + a % b +} + +// CHECK-LABEL: void @f16_add_assign( +#[no_mangle] +pub fn f16_add_assign(a: &mut f16, b: f16) { + // CHECK: fadd half %{{.+}}, %{{.+}} + // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} + *a += b; +} + +// CHECK-LABEL: void @f16_sub_assign( +#[no_mangle] +pub fn f16_sub_assign(a: &mut f16, b: f16) { + // CHECK: fsub half %{{.+}}, %{{.+}} + // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} + *a -= b; +} + +// CHECK-LABEL: void @f16_mul_assign( +#[no_mangle] +pub fn f16_mul_assign(a: &mut f16, b: f16) { + // CHECK: fmul half %{{.+}}, %{{.+}} + // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} + *a *= b; +} + +// CHECK-LABEL: void @f16_div_assign( +#[no_mangle] +pub fn f16_div_assign(a: &mut f16, b: f16) { + // CHECK: fdiv half %{{.+}}, %{{.+}} + // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} + *a /= b; +} + +// CHECK-LABEL: void @f16_rem_assign( +#[no_mangle] +pub fn f16_rem_assign(a: &mut f16, b: f16) { + // CHECK: frem half %{{.+}}, %{{.+}} + // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} + *a %= b; +} + +/* float to float conversions */ + +// bit32-LABEL: half @f16_as_self( +// bit64-LABEL: half @f16_as_self( +// x86-sse-LABEL: <2 x i8> @f16_as_self( +// x86-nosse-LABEL: i16 @f16_as_self( +#[no_mangle] +pub fn f16_as_self(a: f16) -> f16 { + // bit32-CHECK: ret half %{{.+}} + // bit64-CHECK: ret half %{{.+}} + // x86-sse-CHECK: bitcast half + // x86-nosse-CHECK: bitcast half + // x86-sse-CHECK: ret i16 + // x86-nosse-CHECK: ret i16 + a as f16 +} + +// x86-sse-LABEL: <4 x i8> @f16_as_f32( +// x86-nosse-LABEL: i32 @f16_as_f32( +// bit32-LABEL: float @f16_as_f32( +// bit64-LABEL: float @f16_as_f32( +#[no_mangle] +pub fn f16_as_f32(a: f16) -> f32 { + // CHECK: fpext half %{{.+}} to float + a as f32 +} + +// x86-sse-LABEL: <8 x i8> @f16_as_f64( +// x86-nosse-LABEL: void @f16_as_f64({{.*}}sret([8 x i8]) +// bit32-LABEL: double @f16_as_f64( +// bit64-LABEL: double @f16_as_f64( +#[no_mangle] +pub fn f16_as_f64(a: f16) -> f64 { + // CHECK: fpext half %{{.+}} to double + a as f64 +} + +// x86-sse-LABEL: <16 x i8> @f16_as_f128( +// x86-nosse-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) +// bit64-LABEL: fp128 @f16_as_f128( +#[no_mangle] +pub fn f16_as_f128(a: f16) -> f128 { + // CHECK: fpext half %{{.+}} to fp128 + a as f128 +} + +// CHECK-LABEL: @f32_as_f16 +#[no_mangle] +pub fn f32_as_f16(a: f32) -> f16 { + // CHECK: fptrunc float %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: @f64_as_f16 +#[no_mangle] +pub fn f64_as_f16(a: f64) -> f16 { + // CHECK: fptrunc double %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: @f128_as_f16 +#[no_mangle] +pub fn f128_as_f16(a: f128) -> f16 { + // CHECK: fptrunc fp128 %{{.+}} to half + a as f16 +} + +/* float to int conversions */ + +// CHECK-LABEL: i8 @f16_as_u8( +#[no_mangle] +pub fn f16_as_u8(a: f16) -> u8 { + // CHECK: call i8 @llvm.fptoui.sat.i8.f16(half %{{.+}}) + a as u8 +} + +#[no_mangle] +pub fn f16_as_u16(a: f16) -> u16 { + // CHECK: call i16 @llvm.fptoui.sat.i16.f16(half %{{.+}}) + a as u16 +} + +// CHECK-LABEL: i32 @f16_as_u32( +#[no_mangle] +pub fn f16_as_u32(a: f16) -> u32 { + // CHECK: call i32 @llvm.fptoui.sat.i32.f16(half %{{.+}}) + a as u32 +} + +// CHECK-LABEL: i64 @f16_as_u64( +#[no_mangle] +pub fn f16_as_u64(a: f16) -> u64 { + // CHECK: call i64 @llvm.fptoui.sat.i64.f16(half %{{.+}}) + a as u64 +} + +// x86-sse-LABEL: void @f16_as_u128({{.*}}sret([16 x i8]) +// x86-nosse-LABEL: void @f16_as_u128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @f16_as_u128({{.*}}sret([16 x i8]) +// bit64-LABEL: i128 @f16_as_u128( +#[no_mangle] +pub fn f16_as_u128(a: f16) -> u128 { + // CHECK: call i128 @llvm.fptoui.sat.i128.f16(half %{{.+}}) + a as u128 +} + +// CHECK-LABEL: i8 @f16_as_i8( +#[no_mangle] +pub fn f16_as_i8(a: f16) -> i8 { + // CHECK: call i8 @llvm.fptosi.sat.i8.f16(half %{{.+}}) + a as i8 +} + +// CHECK-LABEL: i16 @f16_as_i16( +#[no_mangle] +pub fn f16_as_i16(a: f16) -> i16 { + // CHECK: call i16 @llvm.fptosi.sat.i16.f16(half %{{.+}}) + a as i16 +} +// CHECK-LABEL: i32 @f16_as_i32( +#[no_mangle] +pub fn f16_as_i32(a: f16) -> i32 { + // CHECK: call i32 @llvm.fptosi.sat.i32.f16(half %{{.+}}) + a as i32 +} + +// CHECK-LABEL: i64 @f16_as_i64( +#[no_mangle] +pub fn f16_as_i64(a: f16) -> i64 { + // CHECK: call i64 @llvm.fptosi.sat.i64.f16(half %{{.+}}) + a as i64 +} + +// x86-sse-LABEL: void @f16_as_i128({{.*}}sret([16 x i8]) +// x86-nosse-LABEL: void @f16_as_i128({{.*}}sret([16 x i8]) +// bit32-LABEL: void @f16_as_i128({{.*}}sret([16 x i8]) +// bit64-LABEL: i128 @f16_as_i128( +#[no_mangle] +pub fn f16_as_i128(a: f16) -> i128 { + // CHECK: call i128 @llvm.fptosi.sat.i128.f16(half %{{.+}}) + a as i128 +} + +/* int to float conversions */ + +// CHECK-LABEL: @u8_as_f16 +#[no_mangle] +pub fn u8_as_f16(a: u8) -> f16 { + // CHECK: uitofp i8 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: @u16_as_f16 +#[no_mangle] +pub fn u16_as_f16(a: u16) -> f16 { + // CHECK: uitofp i16 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: @u32_as_f16 +#[no_mangle] +pub fn u32_as_f16(a: u32) -> f16 { + // CHECK: uitofp i32 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: @u64_as_f16 +#[no_mangle] +pub fn u64_as_f16(a: u64) -> f16 { + // CHECK: uitofp i64 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: @u128_as_f16 +#[no_mangle] +pub fn u128_as_f16(a: u128) -> f16 { + // CHECK: uitofp i128 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: @i8_as_f16 +#[no_mangle] +pub fn i8_as_f16(a: i8) -> f16 { + // CHECK: sitofp i8 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: @i16_as_f16 +#[no_mangle] +pub fn i16_as_f16(a: i16) -> f16 { + // CHECK: sitofp i16 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: @i32_as_f16 +#[no_mangle] +pub fn i32_as_f16(a: i32) -> f16 { + // CHECK: sitofp i32 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: @i64_as_f16 +#[no_mangle] +pub fn i64_as_f16(a: i64) -> f16 { + // CHECK: sitofp i64 %{{.+}} to half + a as f16 +} + +// CHECK-LABEL: @i128_as_f16 +#[no_mangle] +pub fn i128_as_f16(a: i128) -> f16 { + // CHECK: sitofp i128 %{{.+}} to half + a as f16 +} diff --git a/tests/codegen-llvm/float_math.rs b/tests/codegen-llvm/float_math.rs new file mode 100644 index 00000000000..9a1e0b4d2d0 --- /dev/null +++ b/tests/codegen-llvm/float_math.rs @@ -0,0 +1,87 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::{ + fadd_algebraic, fadd_fast, fdiv_algebraic, fdiv_fast, fmul_algebraic, fmul_fast, + frem_algebraic, frem_fast, fsub_algebraic, fsub_fast, +}; + +// CHECK-LABEL: @add +#[no_mangle] +pub fn add(x: f32, y: f32) -> f32 { + // CHECK: fadd float + // CHECK-NOT: fast + x + y +} + +// CHECK-LABEL: @test_fadd_algebraic +#[no_mangle] +pub fn test_fadd_algebraic(x: f32, y: f32) -> f32 { + // CHECK: fadd reassoc nsz arcp contract float %x, %y + fadd_algebraic(x, y) +} + +// CHECK-LABEL: @test_fsub_algebraic +#[no_mangle] +pub fn test_fsub_algebraic(x: f32, y: f32) -> f32 { + // CHECK: fsub reassoc nsz arcp contract float %x, %y + fsub_algebraic(x, y) +} + +// CHECK-LABEL: @test_fmul_algebraic +#[no_mangle] +pub fn test_fmul_algebraic(x: f32, y: f32) -> f32 { + // CHECK: fmul reassoc nsz arcp contract float %x, %y + fmul_algebraic(x, y) +} + +// CHECK-LABEL: @test_fdiv_algebraic +#[no_mangle] +pub fn test_fdiv_algebraic(x: f32, y: f32) -> f32 { + // CHECK: fdiv reassoc nsz arcp contract float %x, %y + fdiv_algebraic(x, y) +} + +// CHECK-LABEL: @test_frem_algebraic +#[no_mangle] +pub fn test_frem_algebraic(x: f32, y: f32) -> f32 { + // CHECK: frem reassoc nsz arcp contract float %x, %y + frem_algebraic(x, y) +} + +// CHECK-LABEL: @test_fadd_fast +#[no_mangle] +pub fn test_fadd_fast(x: f32, y: f32) -> f32 { + // CHECK: fadd fast float %x, %y + unsafe { fadd_fast(x, y) } +} + +// CHECK-LABEL: @test_fsub_fast +#[no_mangle] +pub fn test_fsub_fast(x: f32, y: f32) -> f32 { + // CHECK: fsub fast float %x, %y + unsafe { fsub_fast(x, y) } +} + +// CHECK-LABEL: @test_fmul_fast +#[no_mangle] +pub fn test_fmul_fast(x: f32, y: f32) -> f32 { + // CHECK: fmul fast float %x, %y + unsafe { fmul_fast(x, y) } +} + +// CHECK-LABEL: @test_fdiv_fast +#[no_mangle] +pub fn test_fdiv_fast(x: f32, y: f32) -> f32 { + // CHECK: fdiv fast float %x, %y + unsafe { fdiv_fast(x, y) } +} + +// CHECK-LABEL: @test_frem_fast +#[no_mangle] +pub fn test_frem_fast(x: f32, y: f32) -> f32 { + // CHECK: frem fast float %x, %y + unsafe { frem_fast(x, y) } +} diff --git a/tests/codegen-llvm/fn-impl-trait-self.rs b/tests/codegen-llvm/fn-impl-trait-self.rs new file mode 100644 index 00000000000..5799d23b5a0 --- /dev/null +++ b/tests/codegen-llvm/fn-impl-trait-self.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -g +//@ ignore-wasi wasi codegens the main symbol differently +// +// CHECK-LABEL: @main +// MSVC: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "recursive_type$ (*)()",{{.*}} +// NONMSVC: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "fn() -> ",{{.*}} +// +// CHECK: {{.*}}DISubroutineType{{.*}} +// CHECK: {{.*}}DIBasicType(name: "", size: {{32|64}}, encoding: DW_ATE_unsigned) + +pub fn foo() -> impl Copy { + foo +} + +fn main() { + let my_res = foo(); +} diff --git a/tests/codegen-llvm/fn-parameters-on-different-lines-debuginfo.rs b/tests/codegen-llvm/fn-parameters-on-different-lines-debuginfo.rs new file mode 100644 index 00000000000..2097567f322 --- /dev/null +++ b/tests/codegen-llvm/fn-parameters-on-different-lines-debuginfo.rs @@ -0,0 +1,22 @@ +//! Make sure that line debuginfo of function parameters are correct even if +//! they are not on the same line. Regression test for +// . + +//@ compile-flags: -g -Copt-level=0 + +#[rustfmt::skip] // Having parameters on different lines is crucial for this test. +pub fn foo( + x_parameter_not_in_std: i32, + y_parameter_not_in_std: i32, +) -> i32 { + x_parameter_not_in_std + y_parameter_not_in_std +} + +fn main() { + foo(42, 43); // Ensure `wasm32-wasip1` keeps `foo()` (even if `-Copt-level=0`) +} + +// CHECK: !DILocalVariable(name: "x_parameter_not_in_std", arg: 1, +// CHECK-SAME: line: 9 +// CHECK: !DILocalVariable(name: "y_parameter_not_in_std", arg: 2, +// CHECK-SAME: line: 10 diff --git a/tests/codegen-llvm/force-frame-pointers.rs b/tests/codegen-llvm/force-frame-pointers.rs new file mode 100644 index 00000000000..88c918945d6 --- /dev/null +++ b/tests/codegen-llvm/force-frame-pointers.rs @@ -0,0 +1,18 @@ +//@ revisions: Always NonLeaf +//@ [Always] compile-flags: -Cforce-frame-pointers=yes +//@ [NonLeaf] compile-flags: -Cforce-frame-pointers=non-leaf +//@ compile-flags: -Zunstable-options +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 +//@ [NonLeaf] ignore-illumos +//@ [NonLeaf] ignore-openbsd +//@ [NonLeaf] ignore-x86 +//@ [NonLeaf] ignore-x86_64-apple-darwin +//@ [NonLeaf] ignore-windows-gnu +//@ [NonLeaf] ignore-thumb +// result is platform-dependent based on platform's frame pointer settings + +#![crate_type = "lib"] + +// Always: attributes #{{.*}} "frame-pointer"="all" +// NonLeaf: attributes #{{.*}} "frame-pointer"="non-leaf" +pub fn foo() {} diff --git a/tests/codegen-llvm/force-no-unwind-tables.rs b/tests/codegen-llvm/force-no-unwind-tables.rs new file mode 100644 index 00000000000..1de5e0858e0 --- /dev/null +++ b/tests/codegen-llvm/force-no-unwind-tables.rs @@ -0,0 +1,11 @@ +//@ compile-flags: -C no-prepopulate-passes -C panic=abort -C force-unwind-tables=n +//@ ignore-windows: unwind tables are required for panics on Windows + +#![crate_type = "lib"] + +// CHECK-LABEL: define{{.*}}void @foo +// CHECK-NOT: attributes #{{.*}} uwtable +#[no_mangle] +fn foo() { + panic!(); +} diff --git a/tests/codegen-llvm/force-unwind-tables.rs b/tests/codegen-llvm/force-unwind-tables.rs new file mode 100644 index 00000000000..a2ef8a10454 --- /dev/null +++ b/tests/codegen-llvm/force-unwind-tables.rs @@ -0,0 +1,6 @@ +//@ compile-flags: -C no-prepopulate-passes -C force-unwind-tables=y -Copt-level=0 + +#![crate_type = "lib"] + +// CHECK: attributes #{{.*}} uwtable +pub fn foo() {} diff --git a/tests/codegen-llvm/frame-pointer-cli-control.rs b/tests/codegen-llvm/frame-pointer-cli-control.rs new file mode 100644 index 00000000000..a65dd132763 --- /dev/null +++ b/tests/codegen-llvm/frame-pointer-cli-control.rs @@ -0,0 +1,61 @@ +//@ add-core-stubs +//@ compile-flags: --crate-type=rlib -Copt-level=0 +//@ revisions: force-on aarch64-apple aarch64-apple-on aarch64-apple-off +//@ [force-on] compile-flags: -Cforce-frame-pointers=on +//@ [aarch64-apple] needs-llvm-components: aarch64 +//@ [aarch64-apple] compile-flags: --target=aarch64-apple-darwin +//@ [aarch64-apple-on] needs-llvm-components: aarch64 +//@ [aarch64-apple-on] compile-flags: --target=aarch64-apple-darwin -Cforce-frame-pointers=on +//@ [aarch64-apple-off] needs-llvm-components: aarch64 +//@ [aarch64-apple-off] compile-flags: --target=aarch64-apple-darwin -Cforce-frame-pointers=off +/*! + +Tests the extent to which frame pointers can be controlled by the CLI. +The behavior of our frame pointer options, at present, is an irreversible ratchet, where +a "weaker" option that allows omitting frame pointers may be overridden by the target demanding +that all code (or all non-leaf code, more often) must be compiled with frame pointers. +This was discussed on 2025-05-22 in the T-compiler meeting and accepted as an intentional change, +ratifying the prior decisions by compiler contributors and reviewers as correct, +though it was also acknowledged that the flag allows somewhat confusing inputs. + +We find aarch64-apple-darwin useful because of its icy-clear policy regarding frame pointers, +e.g. says: + +* The frame pointer register (x29) must always address a valid frame record. Some functions — + such as leaf functions or tail calls — may opt not to create an entry in this list. + As a result, stack traces are always meaningful, even without debug information. + +Many Rust fn, if externally visible, may be expected to follow target ABI by tools or asm code! +This can make it a problem to generate ABI-incorrect code, which may mean "with frame pointers". +For this and other reasons, `-Cforce-frame-pointers=off` cannot override the target definition. +This can cause some confusion because it is "reverse polarity" relative to C compilers, which have +commands like `-fomit-frame-pointer`, `-fomit-leaf-frame-pointer`, or `-fno-omit-frame-pointer`! + +Specific cases where platforms or tools rely on frame pointers for sound or correct unwinding: +- illumos: +- aarch64-windows: +- aarch64-linux: +- dtrace (freebsd and openbsd): +- openbsd: +- i686-msvc +- i686-mingw: +*/ +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; + +// CHECK: i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] { +#[no_mangle] +pub fn peach(x: u32) -> u32 { + x +} + +// CHECK: attributes [[PEACH_ATTRS]] = { +// force-on-SAME: {{.*}}"frame-pointer"="all" +// aarch64-apple-SAME: {{.*}}"frame-pointer"="non-leaf" +// aarch64-apple-on-SAME: {{.*}}"frame-pointer"="all" +// +// yes, we are testing this doesn't do anything: +// aarch64-apple-off-SAME: {{.*}}"frame-pointer"="non-leaf" +// CHECK-SAME: } diff --git a/tests/codegen-llvm/frame-pointer.rs b/tests/codegen-llvm/frame-pointer.rs new file mode 100644 index 00000000000..23989653fa8 --- /dev/null +++ b/tests/codegen-llvm/frame-pointer.rs @@ -0,0 +1,35 @@ +//@ add-core-stubs +//@ compile-flags: --crate-type=rlib -Copt-level=0 +//@ revisions: aarch64-apple aarch64-linux force x64-apple x64-linux +//@ [aarch64-apple] needs-llvm-components: aarch64 +//@ [aarch64-apple] compile-flags: --target=aarch64-apple-darwin +//@ [aarch64-linux] needs-llvm-components: aarch64 +//@ [aarch64-linux] compile-flags: --target=aarch64-unknown-linux-gnu +//@ [force] needs-llvm-components: x86 +//@ [force] compile-flags: --target=x86_64-unknown-linux-gnu -Cforce-frame-pointers=yes +//@ [x64-apple] needs-llvm-components: x86 +//@ [x64-apple] compile-flags: --target=x86_64-apple-darwin +//@ [x64-linux] needs-llvm-components: x86 +//@ [x64-linux] compile-flags: --target=x86_64-unknown-linux-gnu + +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK: define i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] { +#[no_mangle] +pub fn peach(x: u32) -> u32 { + x +} + +// CHECK: attributes [[PEACH_ATTRS]] = { +// x64-linux-NOT: {{.*}}"frame-pointer"{{.*}} +// x64-apple-SAME: {{.*}}"frame-pointer"="all" +// force-SAME: {{.*}}"frame-pointer"="all" +// +// AAPCS64 demands frame pointers: +// aarch64-linux-SAME: {{.*}}"frame-pointer"="non-leaf" +// aarch64-apple-SAME: {{.*}}"frame-pointer"="non-leaf" +// CHECK-SAME: } diff --git a/tests/codegen-llvm/function-arguments-noopt.rs b/tests/codegen-llvm/function-arguments-noopt.rs new file mode 100644 index 00000000000..c80f119696d --- /dev/null +++ b/tests/codegen-llvm/function-arguments-noopt.rs @@ -0,0 +1,69 @@ +//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes + +// This test checks that arguments/returns in opt-level=0 builds, +// while lacking attributes used for optimization, still have ABI-affecting attributes. + +#![crate_type = "lib"] +#![feature(rustc_attrs)] + +pub struct S { + _field: [i32; 8], +} + +// CHECK: zeroext i1 @boolean(i1 zeroext %x) +#[no_mangle] +pub fn boolean(x: bool) -> bool { + x +} + +// CHECK-LABEL: @boolean_call +#[no_mangle] +pub fn boolean_call(x: bool, f: fn(bool) -> bool) -> bool { + // CHECK: call zeroext i1 %f(i1 zeroext %x) + f(x) +} + +// CHECK: align 4 ptr @borrow(ptr align 4 %x) +#[no_mangle] +pub fn borrow(x: &i32) -> &i32 { + x +} + +// CHECK: align 4 ptr @borrow_mut(ptr align 4 %x) +#[no_mangle] +pub fn borrow_mut(x: &mut i32) -> &mut i32 { + x +} + +// CHECK-LABEL: @borrow_call +#[no_mangle] +pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 { + // CHECK: call align 4 ptr %f(ptr align 4 %x) + f(x) +} + +// CHECK: void @struct_(ptr sret([32 x i8]) align 4{{( %_0)?}}, ptr align 4 %x) +#[no_mangle] +pub fn struct_(x: S) -> S { + x +} + +// CHECK-LABEL: @struct_call +#[no_mangle] +pub fn struct_call(x: S, f: fn(S) -> S) -> S { + // CHECK: call void %f(ptr sret([32 x i8]) align 4{{( %_0)?}}, ptr align 4 %{{.+}}) + f(x) +} + +// CHECK: { i1, i8 } @enum_(i1 zeroext %x.0, i8 %x.1) +#[no_mangle] +pub fn enum_(x: Option) -> Option { + x +} + +// CHECK-LABEL: @enum_call +#[no_mangle] +pub fn enum_call(x: Option, f: fn(Option) -> Option) -> Option { + // CHECK: call { i1, i8 } %f(i1 zeroext %x.0, i8 %x.1) + f(x) +} diff --git a/tests/codegen-llvm/function-arguments.rs b/tests/codegen-llvm/function-arguments.rs new file mode 100644 index 00000000000..c8cd8526ae5 --- /dev/null +++ b/tests/codegen-llvm/function-arguments.rs @@ -0,0 +1,278 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes +#![crate_type = "lib"] +#![feature(rustc_attrs)] +#![feature(allocator_api)] + +use std::marker::PhantomPinned; +use std::mem::MaybeUninit; +use std::num::NonZero; +use std::ptr::NonNull; + +pub struct S { + _field: [i32; 8], +} + +pub struct UnsafeInner { + _field: std::cell::UnsafeCell, +} + +pub struct NotUnpin { + _field: i32, + _marker: PhantomPinned, +} + +pub enum MyBool { + True, + False, +} + +// CHECK: noundef zeroext i1 @boolean(i1 noundef zeroext %x) +#[no_mangle] +pub fn boolean(x: bool) -> bool { + x +} + +// CHECK: i8 @maybeuninit_boolean(i8{{.*}} %x) +#[no_mangle] +pub fn maybeuninit_boolean(x: MaybeUninit) -> MaybeUninit { + x +} + +// CHECK: noundef zeroext i1 @enum_bool(i1 noundef zeroext %x) +#[no_mangle] +pub fn enum_bool(x: MyBool) -> MyBool { + x +} + +// CHECK: i8 @maybeuninit_enum_bool(i8{{.*}} %x) +#[no_mangle] +pub fn maybeuninit_enum_bool(x: MaybeUninit) -> MaybeUninit { + x +} + +// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32{{.*}}{{( range\(i32 0, 1114112\))?}} %x) +#[no_mangle] +pub fn char(x: char) -> char { + x +} + +// CHECK: i32 @maybeuninit_char(i32{{.*}} %x) +#[no_mangle] +pub fn maybeuninit_char(x: MaybeUninit) -> MaybeUninit { + x +} + +// CHECK: noundef i64 @int(i64 noundef %x) +#[no_mangle] +pub fn int(x: u64) -> u64 { + x +} + +// CHECK: noundef{{( range\(i64 1, 0\))?}} i64 @nonzero_int(i64 noundef{{( range\(i64 1, 0\))?}} %x) +#[no_mangle] +pub fn nonzero_int(x: NonZero) -> NonZero { + x +} + +// CHECK: noundef i64 @option_nonzero_int(i64 noundef %x) +#[no_mangle] +pub fn option_nonzero_int(x: Option>) -> Option> { + x +} + +// CHECK: @readonly_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1) +// FIXME #25759 This should also have `nocapture` +#[no_mangle] +pub fn readonly_borrow(_: &i32) {} + +// CHECK: noundef align 4 dereferenceable(4) ptr @readonly_borrow_ret() +#[no_mangle] +pub fn readonly_borrow_ret() -> &'static i32 { + loop {} +} + +// CHECK: @static_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1) +// static borrow may be captured +#[no_mangle] +pub fn static_borrow(_: &'static i32) {} + +// CHECK: @named_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1) +// borrow with named lifetime may be captured +#[no_mangle] +pub fn named_borrow<'r>(_: &'r i32) {} + +// CHECK: @unsafe_borrow(ptr noundef nonnull align 2 %_1) +// unsafe interior means this isn't actually readonly and there may be aliases ... +#[no_mangle] +pub fn unsafe_borrow(_: &UnsafeInner) {} + +// CHECK: @mutable_unsafe_borrow(ptr noalias noundef align 2 dereferenceable(2) %_1) +// ... unless this is a mutable borrow, those never alias +#[no_mangle] +pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {} + +// CHECK: @mutable_borrow(ptr noalias noundef align 4 dereferenceable(4) %_1) +// FIXME #25759 This should also have `nocapture` +#[no_mangle] +pub fn mutable_borrow(_: &mut i32) {} + +// CHECK: noundef align 4 dereferenceable(4) ptr @mutable_borrow_ret() +#[no_mangle] +pub fn mutable_borrow_ret() -> &'static mut i32 { + loop {} +} + +#[no_mangle] +// CHECK: @mutable_notunpin_borrow(ptr noundef nonnull align 4 %_1) +// This one is *not* `noalias` because it might be self-referential. +// It is also not `dereferenceable` due to +// . +pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {} + +// CHECK: @notunpin_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1) +// But `&NotUnpin` behaves perfectly normal. +#[no_mangle] +pub fn notunpin_borrow(_: &NotUnpin) {} + +// CHECK: @indirect_struct(ptr noalias{{( nocapture)?}} noundef readonly align 4{{( captures\(none\))?}} dereferenceable(32) %_1) +#[no_mangle] +pub fn indirect_struct(_: S) {} + +// CHECK: @borrowed_struct(ptr noalias noundef readonly align 4 dereferenceable(32) %_1) +// FIXME #25759 This should also have `nocapture` +#[no_mangle] +pub fn borrowed_struct(_: &S) {} + +// CHECK: @option_borrow(ptr noalias noundef readonly align 4 dereferenceable_or_null(4) %_x) +#[no_mangle] +pub fn option_borrow(_x: Option<&i32>) {} + +// CHECK: @option_borrow_mut(ptr noalias noundef align 4 dereferenceable_or_null(4) %_x) +#[no_mangle] +pub fn option_borrow_mut(_x: Option<&mut i32>) {} + +// Function that must NOT have `dereferenceable` or `align`. +#[rustc_layout_scalar_valid_range_start(16)] +pub struct RestrictedAddress(&'static i16); +enum E { + A(RestrictedAddress), + B, + C, +} +// If the `nonnull` ever goes missing, you might have to tweak the +// scalar_valid_range on `RestrictedAddress` to get it back. You +// might even have to add a `rustc_layout_scalar_valid_range_end`. +// CHECK: @nonnull_and_nondereferenceable(ptr noundef nonnull %_x) +#[no_mangle] +pub fn nonnull_and_nondereferenceable(_x: E) {} + +// CHECK: @raw_struct(ptr noundef %_1) +#[no_mangle] +pub fn raw_struct(_: *const S) {} + +// CHECK: @raw_option_nonnull_struct(ptr noundef %_1) +#[no_mangle] +pub fn raw_option_nonnull_struct(_: Option>) {} + +// `Box` can get deallocated during execution of the function, so it should +// not get `dereferenceable`. +// CHECK: noundef nonnull align 4 ptr @_box(ptr noalias noundef nonnull align 4 %x) +#[no_mangle] +pub fn _box(x: Box) -> Box { + x +} + +// With a custom allocator, it should *not* have `noalias`. (See +// for why.) The second argument is the allocator, +// which is a reference here that still carries `noalias` as usual. +// CHECK: @_box_custom(ptr noundef nonnull align 4 %x.0, ptr noalias noundef nonnull readonly align 1 %x.1) +#[no_mangle] +pub fn _box_custom(x: Box) { + drop(x) +} + +// CHECK: noundef nonnull align 4 ptr @notunpin_box(ptr noundef nonnull align 4 %x) +#[no_mangle] +pub fn notunpin_box(x: Box) -> Box { + x +} + +// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias{{( nocapture)?}} noundef{{( writable)?}} sret([32 x i8]) align 4{{( captures\(none\))?}} dereferenceable(32){{( %_0)?}}) +#[no_mangle] +pub fn struct_return() -> S { + S { _field: [0, 0, 0, 0, 0, 0, 0, 0] } +} + +// Hack to get the correct size for the length part in slices +// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1) +#[no_mangle] +pub fn helper(_: usize) {} + +// CHECK: @slice(ptr noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1) +// FIXME #25759 This should also have `nocapture` +#[no_mangle] +pub fn slice(_: &[u8]) {} + +// CHECK: @mutable_slice(ptr noalias noundef nonnull align 1 %_1.0, [[USIZE]] noundef %_1.1) +// FIXME #25759 This should also have `nocapture` +#[no_mangle] +pub fn mutable_slice(_: &mut [u8]) {} + +// CHECK: @unsafe_slice(ptr noundef nonnull align 2 %_1.0, [[USIZE]] noundef %_1.1) +// unsafe interior means this isn't actually readonly and there may be aliases ... +#[no_mangle] +pub fn unsafe_slice(_: &[UnsafeInner]) {} + +// CHECK: @raw_slice(ptr noundef %_1.0, [[USIZE]] noundef %_1.1) +#[no_mangle] +pub fn raw_slice(_: *const [u8]) {} + +// CHECK: @str(ptr noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1) +// FIXME #25759 This should also have `nocapture` +#[no_mangle] +pub fn str(_: &[u8]) {} + +// CHECK: @trait_borrow(ptr noundef nonnull align 1 %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1) +// FIXME #25759 This should also have `nocapture` +#[no_mangle] +pub fn trait_borrow(_: &dyn Drop) {} + +// CHECK: @option_trait_borrow(ptr noundef align 1 %x.0, ptr %x.1) +#[no_mangle] +pub fn option_trait_borrow(x: Option<&dyn Drop>) {} + +// CHECK: @option_trait_borrow_mut(ptr noundef align 1 %x.0, ptr %x.1) +#[no_mangle] +pub fn option_trait_borrow_mut(x: Option<&mut dyn Drop>) {} + +// CHECK: @trait_raw(ptr noundef %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1) +#[no_mangle] +pub fn trait_raw(_: *const dyn Drop) {} + +// CHECK: @trait_box(ptr noalias noundef nonnull align 1{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}}) +#[no_mangle] +pub fn trait_box(_: Box) {} + +// CHECK: { ptr, ptr } @trait_option(ptr noalias noundef align 1 %x.0, ptr %x.1) +#[no_mangle] +pub fn trait_option(x: Option>) -> Option> { + x +} + +// CHECK: { ptr, [[USIZE]] } @return_slice(ptr noalias noundef nonnull readonly align 2 %x.0, [[USIZE]] noundef %x.1) +#[no_mangle] +pub fn return_slice(x: &[u16]) -> &[u16] { + x +} + +// CHECK: { i16, i16 } @enum_id_1(i16 noundef{{( range\(i16 0, 3\))?}} %x.0, i16 %x.1) +#[no_mangle] +pub fn enum_id_1(x: Option>) -> Option> { + x +} + +// CHECK: { i1, i8 } @enum_id_2(i1 noundef zeroext %x.0, i8 %x.1) +#[no_mangle] +pub fn enum_id_2(x: Option) -> Option { + x +} diff --git a/tests/codegen-llvm/function-return.rs b/tests/codegen-llvm/function-return.rs new file mode 100644 index 00000000000..4127f516038 --- /dev/null +++ b/tests/codegen-llvm/function-return.rs @@ -0,0 +1,35 @@ +// Test that the `fn_ret_thunk_extern` function attribute is (not) emitted when +// the `-Zfunction-return={keep,thunk-extern}` flag is (not) set. + +//@ add-core-stubs +//@ revisions: unset keep thunk-extern keep-thunk-extern thunk-extern-keep +//@ needs-llvm-components: x86 +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ [keep] compile-flags: -Zfunction-return=keep +//@ [thunk-extern] compile-flags: -Zfunction-return=thunk-extern +//@ [keep-thunk-extern] compile-flags: -Zfunction-return=keep -Zfunction-return=thunk-extern +//@ [thunk-extern-keep] compile-flags: -Zfunction-return=thunk-extern -Zfunction-return=keep + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + + // unset-NOT: fn_ret_thunk_extern + // keep-NOT: fn_ret_thunk_extern + // thunk-extern: attributes #0 = { {{.*}}fn_ret_thunk_extern{{.*}} } + // keep-thunk-extern: attributes #0 = { {{.*}}fn_ret_thunk_extern{{.*}} } + // thunk-extern-keep-NOT: fn_ret_thunk_extern +} + +// unset-NOT: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} +// keep-NOT: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} +// thunk-extern: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} +// keep-thunk-extern: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} +// thunk-extern-keep-NOT: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} diff --git a/tests/codegen-llvm/gdb_debug_script_load.rs b/tests/codegen-llvm/gdb_debug_script_load.rs new file mode 100644 index 00000000000..3e92eba10b1 --- /dev/null +++ b/tests/codegen-llvm/gdb_debug_script_load.rs @@ -0,0 +1,37 @@ +// +//@ ignore-windows +//@ ignore-apple +//@ ignore-wasm +//@ ignore-emscripten + +//@ compile-flags: -g -C no-prepopulate-passes -Cpanic=abort + +#![feature(lang_items)] +#![no_std] + +#[panic_handler] +fn panic_handler(_: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[no_mangle] +extern "C" fn rust_eh_personality() { + loop {} +} + +// Needs rustc to generate `main` as that's where the magic load is inserted. +// IOW, we cannot write this test with `#![no_main]`. +// CHECK-LABEL: @main +// CHECK: load volatile i8, {{.+}} @__rustc_debug_gdb_scripts_section__ + +#[lang = "start"] +fn lang_start( + _main: fn() -> T, + _argc: isize, + _argv: *const *const u8, + _sigpipe: u8, +) -> isize { + return 0; +} + +fn main() {} diff --git a/tests/codegen-llvm/generic-debug.rs b/tests/codegen-llvm/generic-debug.rs new file mode 100644 index 00000000000..0ad0b074657 --- /dev/null +++ b/tests/codegen-llvm/generic-debug.rs @@ -0,0 +1,17 @@ +//@ ignore-wasi wasi codegens the main symbol differently + +//@ compile-flags: -g -C no-prepopulate-passes + +// CHECK-LABEL: @main +// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "Generic",{{.*}} +// CHECK: {{.*}}DITemplateTypeParameter{{.*}}name: "Type",{{.*}} + +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(unused_assignments)] + +pub struct Generic(Type); + +fn main() { + let generic = Generic(10); +} diff --git a/tests/codegen-llvm/gep-index.rs b/tests/codegen-llvm/gep-index.rs new file mode 100644 index 00000000000..bfb2511af87 --- /dev/null +++ b/tests/codegen-llvm/gep-index.rs @@ -0,0 +1,37 @@ +//! Check that index and offset use the same getelementptr format. + +//@ revisions: NO-OPT OPT +//@[NO-OPT] compile-flags: -Copt-level=0 +//@[OPT] compile-flags: -Copt-level=1 + +#![crate_type = "lib"] + +struct Foo(i32, i32); + +// CHECK-LABEL: @index_on_struct( +#[no_mangle] +fn index_on_struct(a: &[Foo], index: usize) -> &Foo { + // CHECK: getelementptr inbounds{{( nuw)?}} %Foo, ptr %a.0, {{i64|i32}} %index + &a[index] +} + +// CHECK-LABEL: @offset_on_struct( +#[no_mangle] +fn offset_on_struct(a: *const Foo, index: usize) -> *const Foo { + // CHECK: getelementptr inbounds{{( nuw)?}} %Foo, ptr %a, {{i64|i32}} %index + unsafe { a.add(index) } +} + +// CHECK-LABEL: @index_on_i32( +#[no_mangle] +fn index_on_i32(a: &[i32], index: usize) -> &i32 { + // CHECK: getelementptr inbounds{{( nuw)?}} i32, ptr %a.0, {{i64|i32}} %index + &a[index] +} + +// CHECK-LABEL: @offset_on_i32( +#[no_mangle] +fn offset_on_i32(a: *const i32, index: usize) -> *const i32 { + // CHECK: getelementptr inbounds{{( nuw)?}} i32, ptr %a, {{i64|i32}} %index + unsafe { a.add(index) } +} diff --git a/tests/codegen-llvm/gpu-kernel-abi.rs b/tests/codegen-llvm/gpu-kernel-abi.rs new file mode 100644 index 00000000000..8ac376d9338 --- /dev/null +++ b/tests/codegen-llvm/gpu-kernel-abi.rs @@ -0,0 +1,15 @@ +// Checks that the gpu-kernel calling convention correctly translates to LLVM calling conventions. + +//@ add-core-stubs +//@ revisions: nvptx +//@ [nvptx] compile-flags: --crate-type=rlib --target=nvptx64-nvidia-cuda +//@ [nvptx] needs-llvm-components: nvptx +#![feature(no_core, lang_items, abi_gpu_kernel)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// nvptx: define ptx_kernel void @fun(i32 +#[no_mangle] +pub extern "gpu-kernel" fn fun(_: i32) {} diff --git a/tests/codegen-llvm/gpu_offload/gpu_host.rs b/tests/codegen-llvm/gpu_offload/gpu_host.rs new file mode 100644 index 00000000000..513e27426bc --- /dev/null +++ b/tests/codegen-llvm/gpu_offload/gpu_host.rs @@ -0,0 +1,80 @@ +//@ compile-flags: -Zoffload=Enable -Zunstable-options -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme + +// This test is verifying that we generate __tgt_target_data_*_mapper before and after a call to the +// kernel_1. Better documentation to what each global or variable means is available in the gpu +// offlaod code, or the LLVM offload documentation. This code does not launch any GPU kernels yet, +// and will be rewritten once a proper offload frontend has landed. +// +// We currently only handle memory transfer for specific calls to functions named `kernel_{num}`, +// when inside of a function called main. This, too, is a temporary workaround for not having a +// frontend. + +#![no_main] + +#[unsafe(no_mangle)] +fn main() { + let mut x = [3.0; 256]; + kernel_1(&mut x); + core::hint::black_box(&x); +} + +// CHECK: %struct.__tgt_offload_entry = type { i64, i16, i16, i32, ptr, ptr, i64, i64, ptr } +// CHECK: %struct.__tgt_kernel_arguments = type { i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, i64, i64, [3 x i32], [3 x i32], i32 } +// CHECK: %struct.ident_t = type { i32, i32, i32, i32, ptr } +// CHECK: %struct.__tgt_bin_desc = type { i32, ptr, ptr, ptr } + +// CHECK: @.offload_sizes.1 = private unnamed_addr constant [1 x i64] [i64 1024] +// CHECK: @.offload_maptypes.1 = private unnamed_addr constant [1 x i64] [i64 3] +// CHECK: @.kernel_1.region_id = weak unnamed_addr constant i8 0 +// CHECK: @.offloading.entry_name.1 = internal unnamed_addr constant [9 x i8] c"kernel_1\00", section ".llvm.rodata.offloading", align 1 +// CHECK: @.offloading.entry.kernel_1 = weak constant %struct.__tgt_offload_entry { i64 0, i16 1, i16 1, i32 0, ptr @.kernel_1.region_id, ptr @.offloading.entry_name.1, i64 0, i64 0, ptr null }, section ".omp_offloading_entries", align 1 +// CHECK: @my_struct_global2 = external global %struct.__tgt_kernel_arguments +// CHECK: @0 = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00", align 1 +// CHECK: @1 = private unnamed_addr constant %struct.ident_t { i32 0, i32 2, i32 0, i32 22, ptr @0 }, align 8 + +// CHECK: Function Attrs: +// CHECK-NEXT: define{{( dso_local)?}} void @main() +// CHECK-NEXT: start: +// CHECK-NEXT: %0 = alloca [8 x i8], align 8 +// CHECK-NEXT: %x = alloca [1024 x i8], align 16 +// CHECK-NEXT: %EmptyDesc = alloca %struct.__tgt_bin_desc, align 8 +// CHECK-NEXT: %.offload_baseptrs = alloca [1 x ptr], align 8 +// CHECK-NEXT: %.offload_ptrs = alloca [1 x ptr], align 8 +// CHECK-NEXT: %.offload_sizes = alloca [1 x i64], align 8 +// CHECK-NEXT: %x.addr = alloca ptr, align 8 +// CHECK-NEXT: store ptr %x, ptr %x.addr, align 8 +// CHECK-NEXT: %1 = load ptr, ptr %x.addr, align 8 +// CHECK-NEXT: %2 = getelementptr inbounds float, ptr %1, i32 0 +// CHECK: call void @llvm.memset.p0.i64(ptr align 8 %EmptyDesc, i8 0, i64 32, i1 false) +// CHECK-NEXT: call void @__tgt_register_lib(ptr %EmptyDesc) +// CHECK-NEXT: call void @__tgt_init_all_rtls() +// CHECK-NEXT: %3 = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// CHECK-NEXT: store ptr %1, ptr %3, align 8 +// CHECK-NEXT: %4 = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// CHECK-NEXT: store ptr %2, ptr %4, align 8 +// CHECK-NEXT: %5 = getelementptr inbounds [1 x i64], ptr %.offload_sizes, i32 0, i32 0 +// CHECK-NEXT: store i64 1024, ptr %5, align 8 +// CHECK-NEXT: %6 = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// CHECK-NEXT: %7 = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// CHECK-NEXT: %8 = getelementptr inbounds [1 x i64], ptr %.offload_sizes, i32 0, i32 0 +// CHECK-NEXT: call void @__tgt_target_data_begin_mapper(ptr @1, i64 -1, i32 1, ptr %6, ptr %7, ptr %8, ptr @.offload_maptypes.1, ptr null, ptr null) +// CHECK-NEXT: call void @kernel_1(ptr noalias noundef nonnull align 4 dereferenceable(1024) %x) +// CHECK-NEXT: %9 = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// CHECK-NEXT: %10 = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// CHECK-NEXT: %11 = getelementptr inbounds [1 x i64], ptr %.offload_sizes, i32 0, i32 0 +// CHECK-NEXT: call void @__tgt_target_data_end_mapper(ptr @1, i64 -1, i32 1, ptr %9, ptr %10, ptr %11, ptr @.offload_maptypes.1, ptr null, ptr null) +// CHECK-NEXT: call void @__tgt_unregister_lib(ptr %EmptyDesc) +// CHECK: store ptr %x, ptr %0, align 8 +// CHECK-NEXT: call void asm sideeffect "", "r,~{memory}"(ptr nonnull %0) +// CHECK: ret void +// CHECK-NEXT: } + +#[unsafe(no_mangle)] +#[inline(never)] +pub fn kernel_1(x: &mut [f32; 256]) { + for i in 0..256 { + x[i] = 21.0; + } +} diff --git a/tests/codegen-llvm/hint/cold_path.rs b/tests/codegen-llvm/hint/cold_path.rs new file mode 100644 index 00000000000..149abe474f6 --- /dev/null +++ b/tests/codegen-llvm/hint/cold_path.rs @@ -0,0 +1,54 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] +#![feature(cold_path)] + +use std::hint::cold_path; + +#[inline(never)] +#[no_mangle] +pub fn path_a() { + println!("path a"); +} + +#[inline(never)] +#[no_mangle] +pub fn path_b() { + println!("path b"); +} + +#[no_mangle] +pub fn test1(x: bool) { + if x { + path_a(); + } else { + cold_path(); + path_b(); + } + + // CHECK-LABEL: @test1( + // CHECK: br i1 %x, label %bb1, label %bb2, !prof ![[NUM:[0-9]+]] + // CHECK: bb2: + // CHECK: path_b + // CHECK: bb1: + // CHECK: path_a +} + +#[no_mangle] +pub fn test2(x: i32) { + match x > 0 { + true => path_a(), + false => { + cold_path(); + path_b() + } + } + + // CHECK-LABEL: @test2( + // CHECK: br i1 %_2, label %bb2, label %bb1, !prof ![[NUM]] + // CHECK: bb1: + // CHECK: path_b + // CHECK: bb2: + // CHECK: path_a +} + +// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1} diff --git a/tests/codegen-llvm/hint/likely.rs b/tests/codegen-llvm/hint/likely.rs new file mode 100644 index 00000000000..75f9e7aae36 --- /dev/null +++ b/tests/codegen-llvm/hint/likely.rs @@ -0,0 +1,81 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] +#![feature(likely_unlikely)] + +use std::hint::likely; + +#[inline(never)] +#[no_mangle] +pub fn path_a() { + println!("path a"); +} + +#[inline(never)] +#[no_mangle] +pub fn path_b() { + println!("path b"); +} + +#[no_mangle] +pub fn test1(x: bool) { + if likely(x) { + path_a(); + } else { + path_b(); + } + + // CHECK-LABEL: @test1( + // CHECK: br i1 %x, label %bb2, label %bb3, !prof ![[NUM:[0-9]+]] + // CHECK: bb3: + // CHECK: path_b + // CHECK: bb2: + // CHECK: path_a +} + +#[no_mangle] +pub fn test2(x: i32) { + match likely(x > 0) { + true => path_a(), + false => path_b(), + } + + // CHECK-LABEL: @test2( + // CHECK: br i1 %_2, label %bb2, label %bb3, !prof ![[NUM]] + // CHECK: bb3: + // CHECK: path_b + // CHECK: bb2: + // CHECK: path_a +} + +#[no_mangle] +pub fn test3(x: i8) { + match likely(x < 7) { + true => path_a(), + _ => path_b(), + } + + // CHECK-LABEL: @test3( + // CHECK: br i1 %_2, label %bb2, label %bb3, !prof ![[NUM]] + // CHECK: bb3: + // CHECK: path_b + // CHECK: bb2: + // CHECK: path_a +} + +#[no_mangle] +pub fn test4(x: u64) { + match likely(x != 33) { + false => path_a(), + _ => path_b(), + } + + // CHECK-LABEL: @test4( + // CHECK: br i1 %0, label %bb3, label %bb2, !prof ![[NUM2:[0-9]+]] + // CHECK: bb3: + // CHECK: path_a + // CHECK: bb2: + // CHECK: path_b +} + +// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1} +// CHECK: ![[NUM2]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000} diff --git a/tests/codegen-llvm/hint/unlikely.rs b/tests/codegen-llvm/hint/unlikely.rs new file mode 100644 index 00000000000..248b1e2537e --- /dev/null +++ b/tests/codegen-llvm/hint/unlikely.rs @@ -0,0 +1,80 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] +#![feature(likely_unlikely)] + +use std::hint::unlikely; + +#[inline(never)] +#[no_mangle] +pub fn path_a() { + println!("path a"); +} + +#[inline(never)] +#[no_mangle] +pub fn path_b() { + println!("path b"); +} + +#[no_mangle] +pub fn test1(x: bool) { + if unlikely(x) { + path_a(); + } else { + path_b(); + } + + // CHECK-LABEL: @test1( + // CHECK: br i1 %x, label %bb2, label %bb4, !prof ![[NUM:[0-9]+]] + // CHECK: bb4: + // CHECK: path_b + // CHECK: bb2: + // CHECK: path_a +} + +#[no_mangle] +pub fn test2(x: i32) { + match unlikely(x > 0) { + true => path_a(), + false => path_b(), + } + + // CHECK-LABEL: @test2( + // CHECK: br i1 %_2, label %bb2, label %bb4, !prof ![[NUM]] + // CHECK: bb4: + // CHECK: path_b + // CHECK: bb2: + // CHECK: path_a +} + +#[no_mangle] +pub fn test3(x: i8) { + match unlikely(x < 7) { + true => path_a(), + _ => path_b(), + } + + // CHECK-LABEL: @test3( + // CHECK: br i1 %_2, label %bb2, label %bb4, !prof ![[NUM]] + // CHECK: bb4: + // CHECK: path_b + // CHECK: bb2: + // CHECK: path_a +} + +#[no_mangle] +pub fn test4(x: u64) { + match unlikely(x != 33) { + false => path_a(), + _ => path_b(), + } + + // CHECK-LABEL: @test4( + // CHECK: br i1 %0, label %bb4, label %bb2, !prof ![[NUM2:[0-9]+]] + // CHECK: bb4: + // CHECK: path_a + // CHECK: bb2: + // CHECK: path_b +} + +// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000} diff --git a/tests/codegen-llvm/i128-wasm32-callconv.rs b/tests/codegen-llvm/i128-wasm32-callconv.rs new file mode 100644 index 00000000000..9d73d270ef3 --- /dev/null +++ b/tests/codegen-llvm/i128-wasm32-callconv.rs @@ -0,0 +1,49 @@ +//! Verify that Rust implements the expected calling convention for `i128`/`u128`. + +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 --target wasm32-wasip1 +//@ needs-llvm-components: webassembly + +#![crate_type = "lib"] +#![no_std] +#![no_core] +#![feature(no_core, lang_items)] + +extern crate minicore; + +extern "C" { + fn extern_call(arg0: i128); + fn extern_ret() -> i128; +} + +#[no_mangle] +pub extern "C" fn pass(_arg0: u32, arg1: i128) { + // CHECK-LABEL: @pass( + // an i128 is passed via registers + // CHECK-SAME: i128 noundef %arg1 + // CHECK: call void @extern_call + unsafe { extern_call(arg1) }; +} + +// Check that we produce the correct return ABI +#[no_mangle] +pub extern "C" fn ret(_arg0: u32, arg1: i128) -> i128 { + // CHECK-LABEL: @ret( + // but an i128 is returned via the stack + // CHECK-SAME: sret + // CHECK: store i128 %arg1 + // CHECK-NEXT: ret void + arg1 +} + +// Check that we consume the correct return ABI +#[no_mangle] +pub extern "C" fn forward(dst: *mut i128) { + // CHECK-LABEL: @forward + // CHECK-SAME: ptr{{.*}} %dst) + // without optimizatons, an intermediate alloca is used + // CHECK: call void @extern_ret + // CHECK: store i128 + // CHECK: ret void + unsafe { *dst = extern_ret() }; +} diff --git a/tests/codegen-llvm/i128-x86-align.rs b/tests/codegen-llvm/i128-x86-align.rs new file mode 100644 index 00000000000..75802b0c505 --- /dev/null +++ b/tests/codegen-llvm/i128-x86-align.rs @@ -0,0 +1,105 @@ +//@ only-x86_64 +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes --crate-type=lib + +// On LLVM 17 and earlier LLVM's own data layout specifies that i128 has 8 byte alignment, +// while rustc wants it to have 16 byte alignment. This test checks that we handle this +// correctly. + +// CHECK: %ScalarPair = type { i32, [3 x i32], i128 } + +#![feature(core_intrinsics)] + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct ScalarPair { + a: i32, + b: i128, +} + +#[no_mangle] +pub fn load(x: &ScalarPair) -> ScalarPair { + // CHECK-LABEL: @load( + // CHECK-SAME: sret([32 x i8]) align 16 + // CHECK-SAME: dereferenceable(32) %_0, + // CHECK-SAME: align 16 + // CHECK-SAME: dereferenceable(32) %x + // CHECK: [[A:%.*]] = load i32, ptr %x, align 16 + // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16 + // CHECK-NEXT: [[B:%.*]] = load i128, ptr [[GEP]], align 16 + // CHECK-NEXT: store i32 [[A]], ptr %_0, align 16 + // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %_0, i64 16 + // CHECK-NEXT: store i128 [[B]], ptr [[GEP]], align 16 + // CHECK-NEXT: ret void + *x +} + +#[no_mangle] +pub fn store(x: &mut ScalarPair) { + // CHECK-LABEL: @store( + // CHECK-SAME: align 16 + // CHECK-SAME: dereferenceable(32) %x + // CHECK: store i32 1, ptr %x, align 16 + // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16 + // CHECK-NEXT: store i128 2, ptr [[GEP]], align 16 + *x = ScalarPair { a: 1, b: 2 }; +} + +#[no_mangle] +pub fn alloca() { + // CHECK-LABEL: @alloca( + // CHECK: [[X:%.*]] = alloca [32 x i8], align 16 + // CHECK: store i32 1, ptr %x, align 16 + // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16 + // CHECK-NEXT: store i128 2, ptr [[GEP]], align 16 + let mut x = ScalarPair { a: 1, b: 2 }; + store(&mut x); +} + +#[no_mangle] +pub fn load_volatile(x: &ScalarPair) -> ScalarPair { + // CHECK-LABEL: @load_volatile( + // CHECK-SAME: sret([32 x i8]) align 16 + // CHECK-SAME: dereferenceable(32) %_0, + // CHECK-SAME: align 16 + // CHECK-SAME: dereferenceable(32) %x + // CHECK: [[LOAD:%.*]] = load volatile %ScalarPair, ptr %x, align 16 + // CHECK-NEXT: store %ScalarPair [[LOAD]], ptr %_0, align 16 + // CHECK-NEXT: ret void + unsafe { std::intrinsics::volatile_load(x) } +} + +#[no_mangle] +pub fn transmute(x: ScalarPair) -> (std::mem::MaybeUninit, i128) { + // CHECK-LABEL: @transmute( + // CHECK-SAME: sret([32 x i8]) align 16 + // CHECK-SAME: dereferenceable(32) %_0, + // CHECK-SAME: i32 noundef %x.0, i128 noundef %x.1 + // CHECK: store i32 %x.0, ptr %_0, align 16 + // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %_0, i64 16 + // CHECK-NEXT: store i128 %x.1, ptr [[GEP]], align 16 + // CHECK-NEXT: ret void + unsafe { std::mem::transmute(x) } +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct Struct { + a: i32, + b: i32, + c: i128, +} + +#[no_mangle] +pub fn store_struct(x: &mut Struct) { + // CHECK-LABEL: @store_struct( + // CHECK-SAME: align 16 + // CHECK-SAME: dereferenceable(32) %x + // CHECK: [[TMP:%.*]] = alloca [32 x i8], align 16 + // CHECK: store i32 1, ptr [[TMP]], align 16 + // CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 4 + // CHECK-NEXT: store i32 2, ptr [[GEP1]], align 4 + // CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 16 + // CHECK-NEXT: store i128 3, ptr [[GEP2]], align 16 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 16 %x, ptr align 16 [[TMP]], i64 32, i1 false) + *x = Struct { a: 1, b: 2, c: 3 }; +} diff --git a/tests/codegen-llvm/i128-x86-callconv.rs b/tests/codegen-llvm/i128-x86-callconv.rs new file mode 100644 index 00000000000..41c30c09c1a --- /dev/null +++ b/tests/codegen-llvm/i128-x86-callconv.rs @@ -0,0 +1,87 @@ +//! Verify that Rust implements the expected calling convention for `i128`/`u128`. + +// Eliminate intermediate instructions during `nop` tests +//@ compile-flags: -Copt-level=1 + +//@ add-core-stubs +//@ revisions: MSVC MINGW softfloat +//@ [MSVC] needs-llvm-components: x86 +//@ [MSVC] compile-flags: --target x86_64-pc-windows-msvc +// Use `WIN` as a common prefix for MSVC and MINGW but *not* the softfloat test. +//@ [MSVC] filecheck-flags: --check-prefix=WIN +//@ [MINGW] needs-llvm-components: x86 +//@ [MINGW] compile-flags: --target x86_64-pc-windows-gnu +//@ [MINGW] filecheck-flags: --check-prefix=WIN +// The `x86_64-unknown-uefi` target also uses the Windows calling convention, +// but does not have SSE registers available. +//@ [softfloat] needs-llvm-components: x86 +//@ [softfloat] compile-flags: --target x86_64-unknown-uefi + +#![crate_type = "lib"] +#![no_std] +#![no_core] +#![feature(no_core, lang_items)] + +extern crate minicore; + +extern "C" { + fn extern_call(arg0: i128); + fn extern_ret() -> i128; +} + +#[no_mangle] +pub extern "C" fn pass(_arg0: u32, arg1: i128) { + // CHECK-LABEL: @pass( + // i128 is passed indirectly on Windows. It should load the pointer to the stack and pass + // a pointer to that allocation. The softfloat ABI works the same. + // CHECK-SAME: %_arg0, ptr{{.*}} %arg1) + // CHECK: [[PASS:%[_0-9]+]] = alloca [16 x i8], align 16 + // CHECK: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1 + // CHECK: store i128 [[LOADED]], ptr [[PASS]] + // CHECK: call void @extern_call + unsafe { extern_call(arg1) }; +} + +// Check that we produce the correct return ABI +#[no_mangle] +pub extern "C" fn ret(_arg0: u32, arg1: i128) -> i128 { + // WIN-LABEL: @ret( + // i128 is returned in xmm0 on Windows + // FIXME(#134288): This may change for the `-msvc` targets in the future. + // WIN-SAME: i32{{.*}} %_arg0, ptr{{.*}} %arg1) + // WIN: [[LOADED:%[_0-9]+]] = load <16 x i8>, ptr %arg1 + // WIN-NEXT: ret <16 x i8> [[LOADED]] + // The softfloat ABI returns this indirectly. + // softfloat-LABEL: i128 @ret(i32{{.*}} %_arg0, ptr{{.*}} %arg1) + arg1 +} + +// Check that we consume the correct return ABI +#[no_mangle] +pub extern "C" fn forward(dst: *mut i128) { + // CHECK-LABEL: @forward + // WIN-SAME: ptr{{.*}} %dst) + // WIN: [[RETURNED:%[_0-9]+]] = tail call <16 x i8> @extern_ret() + // WIN: store <16 x i8> [[RETURNED]], ptr %dst + // WIN: ret void + // softfloat: [[RETURNED:%[_0-9]+]] = tail call {{.*}}i128 @extern_ret() + unsafe { *dst = extern_ret() }; +} + +#[repr(C)] +struct RetAggregate { + a: i32, + b: i128, +} + +#[no_mangle] +pub extern "C" fn ret_aggregate(_arg0: u32, arg1: i128) -> RetAggregate { + // CHECK-LABEL: @ret_aggregate( + // Aggregates should also be returned indirectly + // CHECK-SAME: ptr{{.*}}sret([32 x i8]){{.*}}[[RET:%[_0-9]+]], i32{{.*}}%_arg0, ptr{{.*}}%arg1) + // CHECK: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1 + // CHECK: [[GEP:%[_0-9]+]] = getelementptr{{.*}}, ptr [[RET]] + // CHECK: store i128 [[LOADED]], ptr [[GEP]] + // CHECK: ret void + RetAggregate { a: 1, b: arg1 } +} diff --git a/tests/codegen-llvm/infallible-unwrap-in-opt-z.rs b/tests/codegen-llvm/infallible-unwrap-in-opt-z.rs new file mode 100644 index 00000000000..c2297c58e77 --- /dev/null +++ b/tests/codegen-llvm/infallible-unwrap-in-opt-z.rs @@ -0,0 +1,26 @@ +//@ compile-flags: -C opt-level=z +//@ edition: 2021 + +#![crate_type = "lib"] + +// From + +// CHECK-LABEL: @read_up_to_8( +#[no_mangle] +pub fn read_up_to_8(buf: &[u8]) -> u64 { + // CHECK-NOT: unwrap_failed + if buf.len() < 4 { + // actual instance has more code. + return 0; + } + let lo = u32::from_le_bytes(buf[..4].try_into().unwrap()) as u64; + let hi = u32::from_le_bytes(buf[buf.len() - 4..][..4].try_into().unwrap()) as u64; + lo | (hi << 8 * (buf.len() as u64 - 4)) +} + +// CHECK-LABEL: @checking_unwrap_expectation( +#[no_mangle] +pub fn checking_unwrap_expectation(buf: &[u8]) -> &[u8; 4] { + // CHECK: call void @{{.*core6result13unwrap_failed}} + buf.try_into().unwrap() +} diff --git a/tests/codegen-llvm/inherit_overflow.rs b/tests/codegen-llvm/inherit_overflow.rs new file mode 100644 index 00000000000..e4a5ef39fc5 --- /dev/null +++ b/tests/codegen-llvm/inherit_overflow.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Zmir-enable-passes=+Inline,+GVN --crate-type lib +//@ revisions: ASSERT NOASSERT +//@[ASSERT] compile-flags: -Coverflow-checks=on +//@[NOASSERT] compile-flags: -Coverflow-checks=off + +// CHECK-LABEL: define{{.*}} @assertion +// ASSERT: call void @{{.*4core9panicking11panic_const24panic_const_add_overflow}} +// NOASSERT: ret i8 0 +#[no_mangle] +pub fn assertion() -> u8 { + // Optimized MIR will replace this `CheckedBinaryOp` by `const (0, true)`. + // Verify that codegen does or does not emit the panic. + ::add(255, 1) +} diff --git a/tests/codegen-llvm/inline-always-works-always.rs b/tests/codegen-llvm/inline-always-works-always.rs new file mode 100644 index 00000000000..07200fd9e37 --- /dev/null +++ b/tests/codegen-llvm/inline-always-works-always.rs @@ -0,0 +1,21 @@ +//@ revisions: NO-OPT SIZE-OPT SPEED-OPT +//@[NO-OPT] compile-flags: -Copt-level=0 +//@[SIZE-OPT] compile-flags: -Copt-level=s +//@[SPEED-OPT] compile-flags: -Copt-level=3 + +#![crate_type = "rlib"] + +#[no_mangle] +#[inline(always)] +pub extern "C" fn callee() -> u32 { + 4 + 4 +} + +// CHECK-LABEL: caller +// SIZE-OPT: ret i32 8 +// SPEED-OPT: ret i32 8 +// NO-OPT: ret i32 8 +#[no_mangle] +pub extern "C" fn caller() -> u32 { + callee() +} diff --git a/tests/codegen-llvm/inline-debuginfo.rs b/tests/codegen-llvm/inline-debuginfo.rs new file mode 100644 index 00000000000..1e1c9037f5c --- /dev/null +++ b/tests/codegen-llvm/inline-debuginfo.rs @@ -0,0 +1,17 @@ +#![crate_type = "rlib"] +//@ compile-flags: -Copt-level=3 -g +// + +#[no_mangle] +#[inline(always)] +pub extern "C" fn callee(x: u32) -> u32 { + x + 4 +} + +// CHECK-LABEL: caller +// CHECK: dbg{{.}}value({{(metadata )?}}i32 %y, {{(metadata )?}}!{{.*}}, {{(metadata )?}}!DIExpression(DW_OP_constu, 3, DW_OP_minus, DW_OP_stack_value){{.*}} [[A:![0-9]+]] +// CHECK: [[A]] = !DILocation(line: {{.*}}, scope: {{.*}}, inlinedAt: {{.*}}) +#[no_mangle] +pub extern "C" fn caller(y: u32) -> u32 { + callee(y - 3) +} diff --git a/tests/codegen-llvm/inline-function-args-debug-info.rs b/tests/codegen-llvm/inline-function-args-debug-info.rs new file mode 100644 index 00000000000..c31419cb914 --- /dev/null +++ b/tests/codegen-llvm/inline-function-args-debug-info.rs @@ -0,0 +1,23 @@ +// This test checks that debug information includes function argument indexes even if the function +// gets inlined by MIR inlining. Without function argument indexes, `info args` in gdb won't show +// arguments and their values for the current function. + +//@ compile-flags: -Zinline-mir=yes -Cdebuginfo=2 +//@ edition: 2021 + +#![crate_type = "lib"] + +#[inline(never)] +pub fn outer_function(x: usize, y: usize) -> usize { + inner_function(x, y) + 1 +} + +#[inline] +fn inner_function(aaaa: usize, bbbb: usize) -> usize { + // CHECK: !DILocalVariable(name: "aaaa", arg: 1 + // CHECK-SAME: line: 16 + // CHECK-NOT: !DILexicalBlock( + // CHECK: !DILocalVariable(name: "bbbb", arg: 2 + // CHECK-SAME: line: 16 + aaaa + bbbb +} diff --git a/tests/codegen-llvm/inline-hint.rs b/tests/codegen-llvm/inline-hint.rs new file mode 100644 index 00000000000..3d46885d5a2 --- /dev/null +++ b/tests/codegen-llvm/inline-hint.rs @@ -0,0 +1,31 @@ +// Checks that closures, constructors, and shims except +// for a drop glue receive inline hint by default. +// +//@ compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0 -Zinline-mir=no +#![crate_type = "lib"] + +pub fn f() { + let a = A; + let b = (0i32, 1i32, 2i32, 3 as *const i32); + let c = || {}; + + a(String::new(), String::new()); + b.clone(); + c(); +} + +struct A(String, String); + +// CHECK: ; core::ptr::drop_in_place:: +// CHECK-NEXT: ; Function Attrs: +// CHECK-NOT: inlinehint +// CHECK-SAME: {{$}} + +// CHECK: ; <(i32, i32, i32, *const i{{16|32|64}}) as core::clone::Clone>::clone +// CHECK-NEXT: ; Function Attrs: inlinehint + +// CHECK: ; inline_hint::f::{closure#0} +// CHECK-NEXT: ; Function Attrs: inlinehint + +// CHECK: ; inline_hint::A +// CHECK-NEXT: ; Function Attrs: inlinehint diff --git a/tests/codegen-llvm/instrument-coverage/instrument-coverage-off.rs b/tests/codegen-llvm/instrument-coverage/instrument-coverage-off.rs new file mode 100644 index 00000000000..e44d6c65874 --- /dev/null +++ b/tests/codegen-llvm/instrument-coverage/instrument-coverage-off.rs @@ -0,0 +1,21 @@ +// Test that `-Cinstrument-coverage=off` does not add coverage instrumentation to LLVM IR. + +//@ compile-flags: -Zno-profiler-runtime +//@ revisions: n no off false_ zero +//@ [n] compile-flags: -Cinstrument-coverage=n +//@ [no] compile-flags: -Cinstrument-coverage=no +//@ [off] compile-flags: -Cinstrument-coverage=off +//@ [false_] compile-flags: -Cinstrument-coverage=false +//@ [zero] compile-flags: -Cinstrument-coverage=0 + +// CHECK-NOT: __llvm_profile_filename +// CHECK-NOT: __llvm_coverage_mapping + +#![crate_type = "lib"] + +#[inline(never)] +fn some_function() {} + +pub fn some_other_function() { + some_function(); +} diff --git a/tests/codegen-llvm/instrument-coverage/instrument-coverage.rs b/tests/codegen-llvm/instrument-coverage/instrument-coverage.rs new file mode 100644 index 00000000000..23d23651c72 --- /dev/null +++ b/tests/codegen-llvm/instrument-coverage/instrument-coverage.rs @@ -0,0 +1,22 @@ +// Test that `-Cinstrument-coverage` creates expected __llvm_profile_filename symbol in LLVM IR. + +//@ compile-flags: -Zno-profiler-runtime +//@ revisions: default y yes on true_ all +//@ [default] compile-flags: -Cinstrument-coverage +//@ [y] compile-flags: -Cinstrument-coverage=y +//@ [yes] compile-flags: -Cinstrument-coverage=yes +//@ [on] compile-flags: -Cinstrument-coverage=on +//@ [true_] compile-flags: -Cinstrument-coverage=true +//@ [all] compile-flags: -Cinstrument-coverage=all + +// CHECK-DAG: @__llvm_coverage_mapping +// CHECK-DAG: @__llvm_profile_filename = {{.*}}"default_%m_%p.profraw\00"{{.*}} + +#![crate_type = "lib"] + +#[inline(never)] +fn some_function() {} + +pub fn some_other_function() { + some_function(); +} diff --git a/tests/codegen-llvm/instrument-coverage/testprog.rs b/tests/codegen-llvm/instrument-coverage/testprog.rs new file mode 100644 index 00000000000..9e918499d57 --- /dev/null +++ b/tests/codegen-llvm/instrument-coverage/testprog.rs @@ -0,0 +1,118 @@ +//@ edition: 2021 +//@ compile-flags: -Zno-profiler-runtime +//@ compile-flags: -Cinstrument-coverage -Copt-level=0 +//@ revisions: LINUX DARWIN WIN + +//@ [LINUX] only-linux +//@ [LINUX] filecheck-flags: -DINSTR_PROF_DATA=__llvm_prf_data +//@ [LINUX] filecheck-flags: -DINSTR_PROF_NAME=__llvm_prf_names +//@ [LINUX] filecheck-flags: -DINSTR_PROF_CNTS=__llvm_prf_cnts +//@ [LINUX] filecheck-flags: -DINSTR_PROF_COVMAP=__llvm_covmap +//@ [LINUX] filecheck-flags: -DINSTR_PROF_COVFUN=__llvm_covfun +//@ [LINUX] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat' + +//@ [DARWIN] only-apple +//@ [DARWIN] filecheck-flags: -DINSTR_PROF_DATA=__DATA,__llvm_prf_data,regular,live_support +//@ [DARWIN] filecheck-flags: -DINSTR_PROF_NAME=__DATA,__llvm_prf_names +//@ [DARWIN] filecheck-flags: -DINSTR_PROF_CNTS=__DATA,__llvm_prf_cnts +//@ [DARWIN] filecheck-flags: -DINSTR_PROF_COVMAP=__LLVM_COV,__llvm_covmap +//@ [DARWIN] filecheck-flags: -DINSTR_PROF_COVFUN=__LLVM_COV,__llvm_covfun +//@ [DARWIN] filecheck-flags: -DCOMDAT_IF_SUPPORTED= + +//@ [WIN] only-windows +//@ [WIN] filecheck-flags: -DINSTR_PROF_DATA=.lprfd$M +//@ [WIN] filecheck-flags: -DINSTR_PROF_NAME=.lprfn$M +//@ [WIN] filecheck-flags: -DINSTR_PROF_CNTS=.lprfc$M +//@ [WIN] filecheck-flags: -DINSTR_PROF_COVMAP=.lcovmap$M +//@ [WIN] filecheck-flags: -DINSTR_PROF_COVFUN=.lcovfun$M +//@ [WIN] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat' + +// ignore-tidy-linelength + +pub fn will_be_called() -> &'static str { + let val = "called"; + println!("{}", val); + val +} + +pub fn will_not_be_called() -> bool { + println!("should not have been called"); + false +} + +pub fn print(left: &str, value: T, right: &str) +where + T: std::fmt::Display, +{ + println!("{}{}{}", left, value, right); +} + +pub fn wrap_with(inner: T, should_wrap: bool, wrapper: F) +where + F: FnOnce(&T), +{ + if should_wrap { + wrapper(&inner) + } +} + +fn main() { + let less = 1; + let more = 100; + + if less < more { + wrap_with(will_be_called(), less < more, |inner| print(" ***", inner, "*** ")); + wrap_with(will_be_called(), more < less, |inner| print(" ***", inner, "*** ")); + } else { + wrap_with(will_not_be_called(), true, |inner| print("wrapped result is: ", inner, "")); + } +} + +// Check for metadata, variables, declarations, and function definitions injected +// into LLVM IR when compiling with -Cinstrument-coverage. + +// WIN: $__llvm_profile_runtime_user = comdat any + +// CHECK-DAG: @__llvm_coverage_mapping = private constant {{.*}}, section "[[INSTR_PROF_COVMAP]]", align 8 + +// CHECK-DAG: @__covrec_{{[A-F0-9]+}}u = linkonce_odr hidden constant {{.*}}, section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8 + +// WIN: @__llvm_profile_runtime = external{{.*}}global i32 + +// CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global +// CHECK-SAME: section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8 + +// CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global +// CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called +// CHECK-SAME: section "[[INSTR_PROF_DATA]]"{{.*}}, align 8 + +// CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global +// CHECK-SAME: section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8 + +// CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global +// CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main +// CHECK-SAME: section "[[INSTR_PROF_DATA]]"{{.*}}, align 8 + +// CHECK: @__llvm_prf_nm = private constant +// CHECK-SAME: section "[[INSTR_PROF_NAME]]", align 1 + +// CHECK: @llvm.used = appending global +// CHECK-SAME: @__llvm_coverage_mapping +// CHECK-SAME: @__llvm_prf_nm +// CHECK-SAME: section "llvm.metadata" + +// CHECK: define internal { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} { +// CHECK-NEXT: start: +// CHECK-NOT: define internal +// CHECK: atomicrmw add ptr +// CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called, + +// CHECK: declare void @llvm.instrprof.increment(ptr, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]] + +// WIN: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat { +// WIN-NEXT: %1 = load i32, ptr @__llvm_profile_runtime +// WIN-NEXT: ret i32 %1 +// WIN-NEXT: } + +// CHECK: attributes #[[LLVM_INSTRPROF_INCREMENT_ATTR]] = { nounwind } +// WIN: attributes #[[LLVM_PROFILE_RUNTIME_USER_ATTR]] = { noinline } diff --git a/tests/codegen-llvm/instrument-mcount.rs b/tests/codegen-llvm/instrument-mcount.rs new file mode 100644 index 00000000000..8c97535d4a8 --- /dev/null +++ b/tests/codegen-llvm/instrument-mcount.rs @@ -0,0 +1,7 @@ +// +//@ compile-flags: -Z instrument-mcount -Copt-level=0 + +#![crate_type = "lib"] + +// CHECK: attributes #{{.*}} "frame-pointer"="all" "instrument-function-entry-inlined"="{{.*}}mcount{{.*}}" +pub fn foo() {} diff --git a/tests/codegen-llvm/instrument-xray/basic.rs b/tests/codegen-llvm/instrument-xray/basic.rs new file mode 100644 index 00000000000..7aaebf41e36 --- /dev/null +++ b/tests/codegen-llvm/instrument-xray/basic.rs @@ -0,0 +1,9 @@ +// Checks that `-Z instrument-xray` produces expected instrumentation. +// +//@ needs-xray +//@ compile-flags: -Z instrument-xray=always -Copt-level=0 + +#![crate_type = "lib"] + +// CHECK: attributes #{{.*}} "function-instrument"="xray-always" +pub fn function() {} diff --git a/tests/codegen-llvm/instrument-xray/options-combine.rs b/tests/codegen-llvm/instrument-xray/options-combine.rs new file mode 100644 index 00000000000..d1e3b78e6b2 --- /dev/null +++ b/tests/codegen-llvm/instrument-xray/options-combine.rs @@ -0,0 +1,12 @@ +// Checks that `-Z instrument-xray` options can be specified multiple times. +// +//@ needs-xray +//@ compile-flags: -Z instrument-xray=skip-exit -Copt-level=0 +//@ compile-flags: -Z instrument-xray=instruction-threshold=123 -Copt-level=0 +//@ compile-flags: -Z instrument-xray=instruction-threshold=456 -Copt-level=0 + +#![crate_type = "lib"] + +// CHECK: attributes #{{.*}} "xray-instruction-threshold"="456" "xray-skip-exit" +// CHECK-NOT: attributes #{{.*}} "xray-instruction-threshold"="123" +pub fn function() {} diff --git a/tests/codegen-llvm/instrument-xray/options-override.rs b/tests/codegen-llvm/instrument-xray/options-override.rs new file mode 100644 index 00000000000..428fb723edb --- /dev/null +++ b/tests/codegen-llvm/instrument-xray/options-override.rs @@ -0,0 +1,11 @@ +// Checks that the last `-Z instrument-xray` option wins. +// +//@ needs-xray +//@ compile-flags: -Z instrument-xray=always -Copt-level=0 +//@ compile-flags: -Z instrument-xray=never -Copt-level=0 + +#![crate_type = "lib"] + +// CHECK: attributes #{{.*}} "function-instrument"="xray-never" +// CHECK-NOT: attributes #{{.*}} "function-instrument"="xray-always" +pub fn function() {} diff --git a/tests/codegen-llvm/integer-cmp.rs b/tests/codegen-llvm/integer-cmp.rs new file mode 100644 index 00000000000..812fa8e4a42 --- /dev/null +++ b/tests/codegen-llvm/integer-cmp.rs @@ -0,0 +1,62 @@ +// This is test for more optimal Ord implementation for integers. +// See for more info. + +//@ revisions: llvm-pre-20 llvm-20 +//@ [llvm-20] min-llvm-version: 20 +//@ [llvm-pre-20] max-llvm-major-version: 19 +//@ compile-flags: -C opt-level=3 -Zmerge-functions=disabled + +#![crate_type = "lib"] + +use std::cmp::Ordering; + +// CHECK-LABEL: @cmp_signed +#[no_mangle] +pub fn cmp_signed(a: i64, b: i64) -> Ordering { + // llvm-20: call{{.*}} i8 @llvm.scmp.i8.i64 + // llvm-pre-20: icmp slt + // llvm-pre-20: icmp ne + // llvm-pre-20: zext i1 + // llvm-pre-20: select i1 + a.cmp(&b) +} + +// CHECK-LABEL: @cmp_unsigned +#[no_mangle] +pub fn cmp_unsigned(a: u32, b: u32) -> Ordering { + // llvm-20: call{{.*}} i8 @llvm.ucmp.i8.i32 + // llvm-pre-20: icmp ult + // llvm-pre-20: icmp ne + // llvm-pre-20: zext i1 + // llvm-pre-20: select i1 + a.cmp(&b) +} + +// CHECK-LABEL: @cmp_char +#[no_mangle] +pub fn cmp_char(a: char, b: char) -> Ordering { + // llvm-20: call{{.*}} i8 @llvm.ucmp.i8.i32 + // llvm-pre-20: icmp ult + // llvm-pre-20: icmp ne + // llvm-pre-20: zext i1 + // llvm-pre-20: select i1 + a.cmp(&b) +} + +// CHECK-LABEL: @cmp_tuple +#[no_mangle] +pub fn cmp_tuple(a: (i16, u16), b: (i16, u16)) -> Ordering { + // llvm-20-DAG: call{{.*}} i8 @llvm.ucmp.i8.i16 + // llvm-20-DAG: call{{.*}} i8 @llvm.scmp.i8.i16 + // llvm-20: ret i8 + // llvm-pre-20: icmp slt + // llvm-pre-20: icmp ne + // llvm-pre-20: zext i1 + // llvm-pre-20: select i1 + // llvm-pre-20: icmp ult + // llvm-pre-20: icmp ne + // llvm-pre-20: zext i1 + // llvm-pre-20: select i1 + // llvm-pre-20: select i1 + a.cmp(&b) +} diff --git a/tests/codegen-llvm/integer-overflow.rs b/tests/codegen-llvm/integer-overflow.rs new file mode 100644 index 00000000000..80362247a86 --- /dev/null +++ b/tests/codegen-llvm/integer-overflow.rs @@ -0,0 +1,24 @@ +//@ compile-flags: -Copt-level=3 -C overflow-checks=on + +#![crate_type = "lib"] + +pub struct S1<'a> { + data: &'a [u8], + position: usize, +} + +// CHECK-LABEL: @slice_no_index_order +#[no_mangle] +pub fn slice_no_index_order<'a>(s: &'a mut S1, n: usize) -> &'a [u8] { + // CHECK-NOT: slice_index_order_fail + let d = &s.data[s.position..s.position + n]; + s.position += n; + return d; +} + +// CHECK-LABEL: @test_check +#[no_mangle] +pub fn test_check<'a>(s: &'a mut S1, x: usize, y: usize) -> &'a [u8] { + // CHECK: slice_index_order_fail + &s.data[x..y] +} diff --git a/tests/codegen-llvm/internalize-closures.rs b/tests/codegen-llvm/internalize-closures.rs new file mode 100644 index 00000000000..f226ea6faac --- /dev/null +++ b/tests/codegen-llvm/internalize-closures.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 + +pub fn main() { + // We want to make sure that closures get 'internal' linkage instead of + // 'weak_odr' when they are not shared between codegen units + // FIXME(eddyb) `legacy` mangling uses `{{closure}}`, while `v0` + // uses `{closure#0}`, switch to the latter once `legacy` is gone. + // CHECK-LABEL: ; internalize_closures::main::{{.*}}closure + // CHECK-NEXT: ; Function Attrs: + // CHECK-NEXT: define internal + let c = |x: i32| x + 1; + let _ = c(1); +} diff --git a/tests/codegen-llvm/intrinsic-no-unnamed-attr.rs b/tests/codegen-llvm/intrinsic-no-unnamed-attr.rs new file mode 100644 index 00000000000..4bec579831d --- /dev/null +++ b/tests/codegen-llvm/intrinsic-no-unnamed-attr.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![feature(core_intrinsics)] + +use std::intrinsics::sqrtf32; + +// CHECK: @llvm.sqrt.f32(float) #{{[0-9]*}} + +fn main() { + unsafe { + sqrtf32(0.0f32); + } +} diff --git a/tests/codegen-llvm/intrinsics/aggregate-thin-pointer.rs b/tests/codegen-llvm/intrinsics/aggregate-thin-pointer.rs new file mode 100644 index 00000000000..bd590ce9180 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/aggregate-thin-pointer.rs @@ -0,0 +1,23 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z mir-enable-passes=-InstSimplify +//@ only-64bit (so I don't need to worry about usize) + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::aggregate_raw_ptr; + +// InstSimplify replaces these with casts if it can, which means they're almost +// never seen in codegen, but PR#121571 found a way, so add a test for it. + +#[inline(never)] +pub fn opaque(_p: &*const i32) {} + +// CHECK-LABEL: @thin_ptr_via_aggregate( +#[no_mangle] +pub unsafe fn thin_ptr_via_aggregate(p: *const ()) { + // CHECK: %mem = alloca + // CHECK: store ptr %p, ptr %mem + // CHECK: call {{.+}}aggregate_thin_pointer{{.+}} %mem) + let mem = aggregate_raw_ptr(p, ()); + opaque(&mem); +} diff --git a/tests/codegen-llvm/intrinsics/carrying_mul_add.rs b/tests/codegen-llvm/intrinsics/carrying_mul_add.rs new file mode 100644 index 00000000000..21fb49a3786 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/carrying_mul_add.rs @@ -0,0 +1,136 @@ +//@ revisions: RAW OPT +//@ compile-flags: -C opt-level=1 +//@[RAW] compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] +#![feature(core_intrinsics_fallbacks)] + +// Note that LLVM seems to sometimes permute the order of arguments to mul and add, +// so these tests don't check the arguments in the optimized revision. + +use std::intrinsics::{carrying_mul_add, fallback}; + +// The fallbacks are emitted even when they're never used, but optimize out. + +// RAW: wide_mul_u128 +// OPT-NOT: wide_mul_u128 + +// CHECK-LABEL: @cma_u8 +#[no_mangle] +pub unsafe fn cma_u8(a: u8, b: u8, c: u8, d: u8) -> (u8, u8) { + // CHECK: [[A:%.+]] = zext i8 %a to i16 + // CHECK: [[B:%.+]] = zext i8 %b to i16 + // CHECK: [[C:%.+]] = zext i8 %c to i16 + // CHECK: [[D:%.+]] = zext i8 %d to i16 + // CHECK: [[AB:%.+]] = mul nuw i16 + // RAW-SAME: [[A]], [[B]] + // CHECK: [[ABC:%.+]] = add nuw i16 + // RAW-SAME: [[AB]], [[C]] + // CHECK: [[ABCD:%.+]] = add nuw i16 + // RAW-SAME: [[ABC]], [[D]] + // CHECK: [[LOW:%.+]] = trunc i16 [[ABCD]] to i8 + // CHECK: [[HIGHW:%.+]] = lshr i16 [[ABCD]], 8 + // RAW: [[HIGH:%.+]] = trunc i16 [[HIGHW]] to i8 + // OPT: [[HIGH:%.+]] = trunc nuw i16 [[HIGHW]] to i8 + // CHECK: [[PAIR0:%.+]] = insertvalue { i8, i8 } poison, i8 [[LOW]], 0 + // CHECK: [[PAIR1:%.+]] = insertvalue { i8, i8 } [[PAIR0]], i8 [[HIGH]], 1 + // OPT: ret { i8, i8 } [[PAIR1]] + carrying_mul_add(a, b, c, d) +} + +// CHECK-LABEL: @cma_u32 +#[no_mangle] +pub unsafe fn cma_u32(a: u32, b: u32, c: u32, d: u32) -> (u32, u32) { + // CHECK: [[A:%.+]] = zext i32 %a to i64 + // CHECK: [[B:%.+]] = zext i32 %b to i64 + // CHECK: [[C:%.+]] = zext i32 %c to i64 + // CHECK: [[D:%.+]] = zext i32 %d to i64 + // CHECK: [[AB:%.+]] = mul nuw i64 + // RAW-SAME: [[A]], [[B]] + // CHECK: [[ABC:%.+]] = add nuw i64 + // RAW-SAME: [[AB]], [[C]] + // CHECK: [[ABCD:%.+]] = add nuw i64 + // RAW-SAME: [[ABC]], [[D]] + // CHECK: [[LOW:%.+]] = trunc i64 [[ABCD]] to i32 + // CHECK: [[HIGHW:%.+]] = lshr i64 [[ABCD]], 32 + // RAW: [[HIGH:%.+]] = trunc i64 [[HIGHW]] to i32 + // OPT: [[HIGH:%.+]] = trunc nuw i64 [[HIGHW]] to i32 + // CHECK: [[PAIR0:%.+]] = insertvalue { i32, i32 } poison, i32 [[LOW]], 0 + // CHECK: [[PAIR1:%.+]] = insertvalue { i32, i32 } [[PAIR0]], i32 [[HIGH]], 1 + // OPT: ret { i32, i32 } [[PAIR1]] + carrying_mul_add(a, b, c, d) +} + +// CHECK-LABEL: @cma_u128 +// CHECK-SAME: sret{{.+}}dereferenceable(32){{.+}}%_0,{{.+}}%a,{{.+}}%b,{{.+}}%c,{{.+}}%d +#[no_mangle] +pub unsafe fn cma_u128(a: u128, b: u128, c: u128, d: u128) -> (u128, u128) { + // CHECK: [[A:%.+]] = zext i128 %a to i256 + // CHECK: [[B:%.+]] = zext i128 %b to i256 + // CHECK: [[C:%.+]] = zext i128 %c to i256 + // CHECK: [[D:%.+]] = zext i128 %d to i256 + // CHECK: [[AB:%.+]] = mul nuw i256 + // RAW-SAME: [[A]], [[B]] + // CHECK: [[ABC:%.+]] = add nuw i256 + // RAW-SAME: [[AB]], [[C]] + // CHECK: [[ABCD:%.+]] = add nuw i256 + // RAW-SAME: [[ABC]], [[D]] + // CHECK: [[LOW:%.+]] = trunc i256 [[ABCD]] to i128 + // CHECK: [[HIGHW:%.+]] = lshr i256 [[ABCD]], 128 + // RAW: [[HIGH:%.+]] = trunc i256 [[HIGHW]] to i128 + // OPT: [[HIGH:%.+]] = trunc nuw i256 [[HIGHW]] to i128 + // RAW: [[PAIR0:%.+]] = insertvalue { i128, i128 } poison, i128 [[LOW]], 0 + // RAW: [[PAIR1:%.+]] = insertvalue { i128, i128 } [[PAIR0]], i128 [[HIGH]], 1 + // OPT: store i128 [[LOW]], ptr %_0 + // OPT: [[P1:%.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %_0, {{i32|i64}} 16 + // OPT: store i128 [[HIGH]], ptr [[P1]] + // CHECK: ret void + carrying_mul_add(a, b, c, d) +} + +// CHECK-LABEL: @cma_i128 +// CHECK-SAME: sret{{.+}}dereferenceable(32){{.+}}%_0,{{.+}}%a,{{.+}}%b,{{.+}}%c,{{.+}}%d +#[no_mangle] +pub unsafe fn cma_i128(a: i128, b: i128, c: i128, d: i128) -> (u128, i128) { + // CHECK: [[A:%.+]] = sext i128 %a to i256 + // CHECK: [[B:%.+]] = sext i128 %b to i256 + // CHECK: [[C:%.+]] = sext i128 %c to i256 + // CHECK: [[D:%.+]] = sext i128 %d to i256 + // CHECK: [[AB:%.+]] = mul nsw i256 + // RAW-SAME: [[A]], [[B]] + // CHECK: [[ABC:%.+]] = add nsw i256 + // RAW-SAME: [[AB]], [[C]] + // CHECK: [[ABCD:%.+]] = add nsw i256 + // RAW-SAME: [[ABC]], [[D]] + // CHECK: [[LOW:%.+]] = trunc i256 [[ABCD]] to i128 + // CHECK: [[HIGHW:%.+]] = lshr i256 [[ABCD]], 128 + // RAW: [[HIGH:%.+]] = trunc i256 [[HIGHW]] to i128 + // OPT: [[HIGH:%.+]] = trunc nuw i256 [[HIGHW]] to i128 + // RAW: [[PAIR0:%.+]] = insertvalue { i128, i128 } poison, i128 [[LOW]], 0 + // RAW: [[PAIR1:%.+]] = insertvalue { i128, i128 } [[PAIR0]], i128 [[HIGH]], 1 + // OPT: store i128 [[LOW]], ptr %_0 + // OPT: [[P1:%.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %_0, {{i32|i64}} 16 + // OPT: store i128 [[HIGH]], ptr [[P1]] + // CHECK: ret void + carrying_mul_add(a, b, c, d) +} + +// CHECK-LABEL: @fallback_cma_u32 +#[no_mangle] +pub unsafe fn fallback_cma_u32(a: u32, b: u32, c: u32, d: u32) -> (u32, u32) { + // OPT-DAG: [[A:%.+]] = zext i32 %a to i64 + // OPT-DAG: [[B:%.+]] = zext i32 %b to i64 + // OPT-DAG: [[AB:%.+]] = mul nuw i64 + // OPT-DAG: [[C:%.+]] = zext i32 %c to i64 + // OPT-DAG: [[ABC:%.+]] = add nuw i64{{.+}}[[C]] + // OPT-DAG: [[D:%.+]] = zext i32 %d to i64 + // OPT-DAG: [[ABCD:%.+]] = add nuw i64{{.+}}[[D]] + // OPT-DAG: [[LOW:%.+]] = trunc i64 [[ABCD]] to i32 + // OPT-DAG: [[HIGHW:%.+]] = lshr i64 [[ABCD]], 32 + // OPT-DAG: [[HIGH:%.+]] = trunc nuw i64 [[HIGHW]] to i32 + // OPT-DAG: [[PAIR0:%.+]] = insertvalue { i32, i32 } poison, i32 [[LOW]], 0 + // OPT-DAG: [[PAIR1:%.+]] = insertvalue { i32, i32 } [[PAIR0]], i32 [[HIGH]], 1 + // OPT-DAG: ret { i32, i32 } [[PAIR1]] + fallback::CarryingMulAdd::carrying_mul_add(a, b, c, d) +} diff --git a/tests/codegen-llvm/intrinsics/cold_path.rs b/tests/codegen-llvm/intrinsics/cold_path.rs new file mode 100644 index 00000000000..fd75324b671 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/cold_path.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::cold_path; + +#[no_mangle] +pub fn test_cold_path(x: bool) { + cold_path(); +} + +// CHECK-LABEL: @test_cold_path( +// CHECK-NOT: cold_path diff --git a/tests/codegen-llvm/intrinsics/cold_path2.rs b/tests/codegen-llvm/intrinsics/cold_path2.rs new file mode 100644 index 00000000000..0891c878fd9 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/cold_path2.rs @@ -0,0 +1,37 @@ +//@ compile-flags: -O +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::cold_path; + +#[inline(never)] +#[no_mangle] +pub fn path_a() { + println!("path a"); +} + +#[inline(never)] +#[no_mangle] +pub fn path_b() { + println!("path b"); +} + +#[no_mangle] +pub fn test(x: Option) { + if let Some(_) = x { + path_a(); + } else { + cold_path(); + path_b(); + } + + // CHECK-LABEL: void @test(i8{{.+}}%x) + // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %x, 2 + // CHECK: br i1 %[[IS_NONE]], label %bb2, label %bb1, !prof ![[NUM:[0-9]+]] + // CHECK: bb1: + // CHECK: path_a + // CHECK: bb2: + // CHECK: path_b +} + +// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000} diff --git a/tests/codegen-llvm/intrinsics/cold_path3.rs b/tests/codegen-llvm/intrinsics/cold_path3.rs new file mode 100644 index 00000000000..bf3347de665 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/cold_path3.rs @@ -0,0 +1,87 @@ +//@ compile-flags: -O +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::cold_path; + +#[inline(never)] +#[no_mangle] +pub fn path_a() { + println!("path a"); +} + +#[inline(never)] +#[no_mangle] +pub fn path_b() { + println!("path b"); +} + +#[inline(never)] +#[no_mangle] +pub fn path_c() { + println!("path c"); +} + +#[inline(never)] +#[no_mangle] +pub fn path_d() { + println!("path d"); +} + +#[no_mangle] +pub fn test(x: Option) { + match x { + Some(0) => path_a(), + Some(1) => { + cold_path(); + path_b() + } + Some(2) => path_c(), + Some(3) => { + cold_path(); + path_d() + } + _ => path_a(), + } + + // CHECK-LABEL: @test( + // CHECK: switch i32 %1, label %bb1 [ + // CHECK: i32 0, label %bb6 + // CHECK: i32 1, label %bb5 + // CHECK: i32 2, label %bb4 + // CHECK: i32 3, label %bb3 + // CHECK: ], !prof ![[NUM1:[0-9]+]] +} + +#[no_mangle] +pub fn test2(x: Option) { + match x { + Some(10) => path_a(), + Some(11) => { + cold_path(); + path_b() + } + Some(12) => { + unsafe { core::intrinsics::unreachable() }; + path_c() + } + Some(13) => { + cold_path(); + path_d() + } + _ => { + cold_path(); + path_a() + } + } + + // CHECK-LABEL: @test2( + // CHECK: switch i32 %1, label %bb1 [ + // CHECK: i32 10, label %bb5 + // CHECK: i32 11, label %bb4 + // CHECK: i32 13, label %bb3 + // CHECK: ], !prof ![[NUM2:[0-9]+]] +} + +// CHECK: ![[NUM1]] = !{!"branch_weights", i32 2000, i32 2000, i32 1, i32 2000, i32 1} +// CHECK: ![[NUM2]] = !{!"branch_weights", i32 1, i32 2000, i32 1, i32 1} diff --git a/tests/codegen-llvm/intrinsics/compare_bytes.rs b/tests/codegen-llvm/intrinsics/compare_bytes.rs new file mode 100644 index 00000000000..3ab0e4e97e0 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/compare_bytes.rs @@ -0,0 +1,34 @@ +//@ revisions: INT32 INT16 +//@ compile-flags: -Copt-level=3 +//@ [INT32] ignore-16bit +//@ [INT16] only-16bit + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::compare_bytes; + +#[no_mangle] +// CHECK-LABEL: @bytes_cmp( +pub unsafe fn bytes_cmp(a: *const u8, b: *const u8, n: usize) -> i32 { + // INT32: %[[TEMP:.+]] = tail call i32 @memcmp(ptr %a, ptr %b, {{i32|i64}} %n) + // INT32-NOT: sext + // INT32: ret i32 %[[TEMP]] + + // INT16: %[[TEMP1:.+]] = tail call i16 @memcmp(ptr %a, ptr %b, i16 %n) + // INT16: %[[TEMP2:.+]] = sext i16 %[[TEMP1]] to i32 + // INT16: ret i32 %[[TEMP2]] + compare_bytes(a, b, n) +} + +// Ensure that, even though there's an `sext` emitted by the intrinsic, +// that doesn't end up pessiming checks against zero. +#[no_mangle] +// CHECK-LABEL: @bytes_eq( +pub unsafe fn bytes_eq(a: *const u8, b: *const u8, n: usize) -> bool { + // CHECK: call {{.+}} @{{bcmp|memcmp}}(ptr %a, ptr %b, {{i16|i32|i64}} %n) + // CHECK-NOT: sext + // INT32: icmp eq i32 + // INT16: icmp eq i16 + compare_bytes(a, b, n) == 0_i32 +} diff --git a/tests/codegen-llvm/intrinsics/const_eval_select.rs b/tests/codegen-llvm/intrinsics/const_eval_select.rs new file mode 100644 index 00000000000..baa985b00cd --- /dev/null +++ b/tests/codegen-llvm/intrinsics/const_eval_select.rs @@ -0,0 +1,22 @@ +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 + +#![crate_type = "lib"] +#![feature(const_eval_select)] +#![feature(core_intrinsics)] + +use std::intrinsics::const_eval_select; + +const fn foo(_: i32) -> i32 { + 1 +} + +#[no_mangle] +pub fn hi(n: i32) -> i32 { + n +} + +#[no_mangle] +pub unsafe fn hey() { + // CHECK: call i32 @hi(i32 + const_eval_select((42,), foo, hi); +} diff --git a/tests/codegen-llvm/intrinsics/ctlz.rs b/tests/codegen-llvm/intrinsics/ctlz.rs new file mode 100644 index 00000000000..0d54d21ce12 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/ctlz.rs @@ -0,0 +1,56 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::{ctlz, ctlz_nonzero}; + +// CHECK-LABEL: @ctlz_u16 +#[no_mangle] +pub unsafe fn ctlz_u16(x: u16) -> u32 { + // CHECK: %[[tmp:.*]] = call i16 @llvm.ctlz.i16(i16 %x, i1 false) + // CHECK: zext i16 %[[tmp]] to i32 + ctlz(x) +} + +// CHECK-LABEL: @ctlz_nzu16 +#[no_mangle] +pub unsafe fn ctlz_nzu16(x: u16) -> u32 { + // CHECK: %[[tmp:.*]] = call i16 @llvm.ctlz.i16(i16 %x, i1 true) + // CHECK: zext i16 %[[tmp]] to i32 + ctlz_nonzero(x) +} + +// CHECK-LABEL: @ctlz_u32 +#[no_mangle] +pub unsafe fn ctlz_u32(x: u32) -> u32 { + // CHECK: call i32 @llvm.ctlz.i32(i32 %x, i1 false) + // CHECK-NOT: zext + // CHECK-NOT: trunc + ctlz(x) +} + +// CHECK-LABEL: @ctlz_nzu32 +#[no_mangle] +pub unsafe fn ctlz_nzu32(x: u32) -> u32 { + // CHECK: call i32 @llvm.ctlz.i32(i32 %x, i1 true) + // CHECK-NOT: zext + // CHECK-NOT: trunc + ctlz_nonzero(x) +} + +// CHECK-LABEL: @ctlz_u64 +#[no_mangle] +pub unsafe fn ctlz_u64(x: u64) -> u32 { + // CHECK: %[[tmp:.*]] = call i64 @llvm.ctlz.i64(i64 %x, i1 false) + // CHECK: trunc i64 %[[tmp]] to i32 + ctlz(x) +} + +// CHECK-LABEL: @ctlz_nzu64 +#[no_mangle] +pub unsafe fn ctlz_nzu64(x: u64) -> u32 { + // CHECK: %[[tmp:.*]] = call i64 @llvm.ctlz.i64(i64 %x, i1 true) + // CHECK: trunc i64 %[[tmp]] to i32 + ctlz_nonzero(x) +} diff --git a/tests/codegen-llvm/intrinsics/ctpop.rs b/tests/codegen-llvm/intrinsics/ctpop.rs new file mode 100644 index 00000000000..f4043325de9 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/ctpop.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::ctpop; + +// CHECK-LABEL: @ctpop_u16 +#[no_mangle] +pub unsafe fn ctpop_u16(x: u16) -> u32 { + // CHECK: %[[tmp:.*]] = call i16 @llvm.ctpop.i16(i16 %x) + // CHECK: zext i16 %[[tmp]] to i32 + ctpop(x) +} + +// CHECK-LABEL: @ctpop_u32 +#[no_mangle] +pub unsafe fn ctpop_u32(x: u32) -> u32 { + // CHECK: call i32 @llvm.ctpop.i32(i32 %x) + // CHECK-NOT: zext + // CHECK-NOT: trunc + ctpop(x) +} + +// CHECK-LABEL: @ctpop_u64 +#[no_mangle] +pub unsafe fn ctpop_u64(x: u64) -> u32 { + // CHECK: %[[tmp:.*]] = call i64 @llvm.ctpop.i64(i64 %x) + // CHECK: trunc i64 %[[tmp]] to i32 + ctpop(x) +} diff --git a/tests/codegen-llvm/intrinsics/disjoint_bitor.rs b/tests/codegen-llvm/intrinsics/disjoint_bitor.rs new file mode 100644 index 00000000000..fc45439ee0b --- /dev/null +++ b/tests/codegen-llvm/intrinsics/disjoint_bitor.rs @@ -0,0 +1,30 @@ +//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::disjoint_bitor; + +// CHECK-LABEL: @disjoint_bitor_signed +#[no_mangle] +pub unsafe fn disjoint_bitor_signed(x: i32, y: i32) -> i32 { + // CHECK: or disjoint i32 %x, %y + disjoint_bitor(x, y) +} + +// CHECK-LABEL: @disjoint_bitor_unsigned +#[no_mangle] +pub unsafe fn disjoint_bitor_unsigned(x: u64, y: u64) -> u64 { + // CHECK: or disjoint i64 %x, %y + disjoint_bitor(x, y) +} + +// CHECK-LABEL: @disjoint_bitor_literal +#[no_mangle] +pub unsafe fn disjoint_bitor_literal() -> u8 { + // This is a separate check because even without any passes, + // LLVM will fold so it's not an instruction, which can assert in LLVM. + + // CHECK: store i8 3 + disjoint_bitor(1, 2) +} diff --git a/tests/codegen-llvm/intrinsics/exact_div.rs b/tests/codegen-llvm/intrinsics/exact_div.rs new file mode 100644 index 00000000000..dc625ba7fe4 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/exact_div.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::exact_div; + +// CHECK-LABEL: @exact_sdiv +#[no_mangle] +pub unsafe fn exact_sdiv(x: i32, y: i32) -> i32 { + // CHECK: sdiv exact + exact_div(x, y) +} + +// CHECK-LABEL: @exact_udiv +#[no_mangle] +pub unsafe fn exact_udiv(x: u32, y: u32) -> u32 { + // CHECK: udiv exact + exact_div(x, y) +} diff --git a/tests/codegen-llvm/intrinsics/likely.rs b/tests/codegen-llvm/intrinsics/likely.rs new file mode 100644 index 00000000000..c5e3c466f45 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/likely.rs @@ -0,0 +1,35 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::likely; + +#[inline(never)] +#[no_mangle] +pub fn path_a() { + println!("path a"); +} + +#[inline(never)] +#[no_mangle] +pub fn path_b() { + println!("path b"); +} + +#[no_mangle] +pub fn test_likely(x: bool) { + if likely(x) { + path_a(); + } else { + path_b(); + } +} + +// CHECK-LABEL: @test_likely( +// CHECK: br i1 %x, label %bb2, label %bb3, !prof ![[NUM:[0-9]+]] +// CHECK: bb3: +// CHECK-NOT: cold_path +// CHECK: path_b +// CHECK: bb2: +// CHECK: path_a +// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1} diff --git a/tests/codegen-llvm/intrinsics/likely_assert.rs b/tests/codegen-llvm/intrinsics/likely_assert.rs new file mode 100644 index 00000000000..87ffb4ee3fb --- /dev/null +++ b/tests/codegen-llvm/intrinsics/likely_assert.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +#[no_mangle] +pub fn test_assert(x: bool) { + assert!(x); +} + +// check that assert! emits branch weights + +// CHECK-LABEL: @test_assert( +// CHECK: br i1 %x, label %bb2, label %bb1, !prof ![[NUM:[0-9]+]] +// CHECK: bb1: +// CHECK: panic +// CHECK: bb2: +// CHECK: ret void +// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1} diff --git a/tests/codegen-llvm/intrinsics/mask.rs b/tests/codegen-llvm/intrinsics/mask.rs new file mode 100644 index 00000000000..5344274678c --- /dev/null +++ b/tests/codegen-llvm/intrinsics/mask.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Copt-level=0 +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +// CHECK-LABEL: @mask_ptr +// CHECK-SAME: [[WORD:i[0-9]+]] %mask +#[no_mangle] +pub fn mask_ptr(ptr: *const u16, mask: usize) -> *const u16 { + // CHECK: call + // CHECK-SAME: @llvm.ptrmask.{{p0|p0i8}}.[[WORD]](ptr {{%ptr|%1}}, [[WORD]] %mask) + core::intrinsics::ptr_mask(ptr, mask) +} diff --git a/tests/codegen-llvm/intrinsics/nontemporal.rs b/tests/codegen-llvm/intrinsics/nontemporal.rs new file mode 100644 index 00000000000..a151d4bd297 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/nontemporal.rs @@ -0,0 +1,32 @@ +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 +//@revisions: with_nontemporal without_nontemporal +//@[with_nontemporal] compile-flags: --target aarch64-unknown-linux-gnu +//@[with_nontemporal] needs-llvm-components: aarch64 +//@[without_nontemporal] compile-flags: --target x86_64-unknown-linux-gnu +//@[without_nontemporal] needs-llvm-components: x86 + +// Ensure that we *do* emit the `!nontemporal` flag on architectures where it +// is well-behaved, but do *not* emit it on architectures where it is ill-behaved. +// For more context, see and +// . + +#![feature(no_core, lang_items, intrinsics)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +#[rustc_intrinsic] +pub unsafe fn nontemporal_store(ptr: *mut T, val: T); + +#[no_mangle] +pub fn a(a: &mut u32, b: u32) { + // CHECK-LABEL: define{{.*}}void @a + // with_nontemporal: store i32 %b, ptr %a, align 4, !nontemporal + // without_nontemporal-NOT: nontemporal + unsafe { + nontemporal_store(a, b); + } +} diff --git a/tests/codegen-llvm/intrinsics/offset.rs b/tests/codegen-llvm/intrinsics/offset.rs new file mode 100644 index 00000000000..cf0c7c7ac7d --- /dev/null +++ b/tests/codegen-llvm/intrinsics/offset.rs @@ -0,0 +1,33 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::offset; + +// CHECK-LABEL: ptr @offset_zst +// CHECK-SAME: (ptr noundef %p, [[SIZE:i[0-9]+]] noundef %d) +#[no_mangle] +pub unsafe fn offset_zst(p: *const (), d: usize) -> *const () { + // CHECK-NOT: getelementptr + // CHECK: ret ptr %p + offset(p, d) +} + +// CHECK-LABEL: ptr @offset_isize +// CHECK-SAME: (ptr noundef %p, [[SIZE]] noundef %d) +#[no_mangle] +pub unsafe fn offset_isize(p: *const u32, d: isize) -> *const u32 { + // CHECK: %[[R:.*]] = getelementptr inbounds i32, ptr %p, [[SIZE]] %d + // CHECK-NEXT: ret ptr %[[R]] + offset(p, d) +} + +// CHECK-LABEL: ptr @offset_usize +// CHECK-SAME: (ptr noundef %p, [[SIZE]] noundef %d) +#[no_mangle] +pub unsafe fn offset_usize(p: *const u64, d: usize) -> *const u64 { + // CHECK: %[[R:.*]] = getelementptr inbounds{{( nuw)?}} i64, ptr %p, [[SIZE]] %d + // CHECK-NEXT: ret ptr %[[R]] + offset(p, d) +} diff --git a/tests/codegen-llvm/intrinsics/offset_from.rs b/tests/codegen-llvm/intrinsics/offset_from.rs new file mode 100644 index 00000000000..ef1a77ef184 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/offset_from.rs @@ -0,0 +1,36 @@ +//@ compile-flags: -C opt-level=1 +//@ only-64bit (because we're using [ui]size) + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +//! Basic optimizations are enabled because otherwise `x86_64-gnu-nopt` had an alloca. +//! Uses a type with non-power-of-two size to avoid normalizations to shifts. + +use std::intrinsics::*; + +type RGB = [u8; 3]; + +// CHECK-LABEL: @offset_from_odd_size +#[no_mangle] +pub unsafe fn offset_from_odd_size(a: *const RGB, b: *const RGB) -> isize { + // CHECK: start + // CHECK-NEXT: ptrtoint + // CHECK-NEXT: ptrtoint + // CHECK-NEXT: sub i64 + // CHECK-NEXT: sdiv exact i64 %{{[0-9]+}}, 3 + // CHECK-NEXT: ret i64 + ptr_offset_from(a, b) +} + +// CHECK-LABEL: @offset_from_unsigned_odd_size +#[no_mangle] +pub unsafe fn offset_from_unsigned_odd_size(a: *const RGB, b: *const RGB) -> usize { + // CHECK: start + // CHECK-NEXT: ptrtoint + // CHECK-NEXT: ptrtoint + // CHECK-NEXT: sub nuw i64 + // CHECK-NEXT: udiv exact i64 %{{[0-9]+}}, 3 + // CHECK-NEXT: ret i64 + ptr_offset_from_unsigned(a, b) +} diff --git a/tests/codegen-llvm/intrinsics/prefetch.rs b/tests/codegen-llvm/intrinsics/prefetch.rs new file mode 100644 index 00000000000..3f9f21c85cb --- /dev/null +++ b/tests/codegen-llvm/intrinsics/prefetch.rs @@ -0,0 +1,64 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::{ + prefetch_read_data, prefetch_read_instruction, prefetch_write_data, prefetch_write_instruction, +}; + +#[no_mangle] +pub fn check_prefetch_read_data(data: &[i8]) { + unsafe { + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 0, i32 1) + prefetch_read_data(data.as_ptr(), 0); + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 1, i32 1) + prefetch_read_data(data.as_ptr(), 1); + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 2, i32 1) + prefetch_read_data(data.as_ptr(), 2); + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 3, i32 1) + prefetch_read_data(data.as_ptr(), 3); + } +} + +#[no_mangle] +pub fn check_prefetch_write_data(data: &[i8]) { + unsafe { + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 0, i32 1) + prefetch_write_data(data.as_ptr(), 0); + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 1, i32 1) + prefetch_write_data(data.as_ptr(), 1); + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 2, i32 1) + prefetch_write_data(data.as_ptr(), 2); + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 3, i32 1) + prefetch_write_data(data.as_ptr(), 3); + } +} + +#[no_mangle] +pub fn check_prefetch_read_instruction(data: &[i8]) { + unsafe { + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 0, i32 0) + prefetch_read_instruction(data.as_ptr(), 0); + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 1, i32 0) + prefetch_read_instruction(data.as_ptr(), 1); + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 2, i32 0) + prefetch_read_instruction(data.as_ptr(), 2); + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 3, i32 0) + prefetch_read_instruction(data.as_ptr(), 3); + } +} + +#[no_mangle] +pub fn check_prefetch_write_instruction(data: &[i8]) { + unsafe { + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 0, i32 0) + prefetch_write_instruction(data.as_ptr(), 0); + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 1, i32 0) + prefetch_write_instruction(data.as_ptr(), 1); + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 2, i32 0) + prefetch_write_instruction(data.as_ptr(), 2); + // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 3, i32 0) + prefetch_write_instruction(data.as_ptr(), 3); + } +} diff --git a/tests/codegen-llvm/intrinsics/ptr_metadata.rs b/tests/codegen-llvm/intrinsics/ptr_metadata.rs new file mode 100644 index 00000000000..044dbc20486 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/ptr_metadata.rs @@ -0,0 +1,36 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z inline-mir +//@ only-64bit (so I don't need to worry about usize) + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::ptr_metadata; + +// CHECK-LABEL: @thin_metadata( +#[no_mangle] +pub fn thin_metadata(p: *const ()) { + // CHECK: start + // CHECK-NEXT: ret void + ptr_metadata(p) +} + +// CHECK-LABEL: @slice_metadata( +#[no_mangle] +pub fn slice_metadata(p: *const [u8]) -> usize { + // CHECK: start + // CHECK-NEXT: ret i64 %p.1 + ptr_metadata(p) +} + +// CHECK-LABEL: @dyn_byte_offset( +#[no_mangle] +pub unsafe fn dyn_byte_offset( + p: *const dyn std::fmt::Debug, + n: usize, +) -> *const dyn std::fmt::Debug { + // CHECK: %[[Q:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %p.0, i64 %n + // CHECK: %[[TEMP1:.+]] = insertvalue { ptr, ptr } poison, ptr %[[Q]], 0 + // CHECK: %[[TEMP2:.+]] = insertvalue { ptr, ptr } %[[TEMP1]], ptr %p.1, 1 + // CHECK: ret { ptr, ptr } %[[TEMP2]] + p.byte_add(n) +} diff --git a/tests/codegen-llvm/intrinsics/rotate_left.rs b/tests/codegen-llvm/intrinsics/rotate_left.rs new file mode 100644 index 00000000000..4f6c5cbaed6 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/rotate_left.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::rotate_left; + +// CHECK-LABEL: @rotate_left_u16 +#[no_mangle] +pub unsafe fn rotate_left_u16(x: u16, shift: u32) -> u16 { + // CHECK: %[[tmp:.*]] = trunc i32 %shift to i16 + // CHECK: call i16 @llvm.fshl.i16(i16 %x, i16 %x, i16 %[[tmp]]) + rotate_left(x, shift) +} + +// CHECK-LABEL: @rotate_left_u32 +#[no_mangle] +pub unsafe fn rotate_left_u32(x: u32, shift: u32) -> u32 { + // CHECK-NOT: trunc + // CHECK-NOT: zext + // CHECK: call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 %shift) + rotate_left(x, shift) +} + +// CHECK-LABEL: @rotate_left_u64 +#[no_mangle] +pub unsafe fn rotate_left_u64(x: u64, shift: u32) -> u64 { + // CHECK: %[[tmp:.*]] = zext i32 %shift to i64 + // CHECK: call i64 @llvm.fshl.i64(i64 %x, i64 %x, i64 %[[tmp]]) + rotate_left(x, shift) +} diff --git a/tests/codegen-llvm/intrinsics/rustc_intrinsic_must_be_overridden.rs b/tests/codegen-llvm/intrinsics/rustc_intrinsic_must_be_overridden.rs new file mode 100644 index 00000000000..b41e441d309 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/rustc_intrinsic_must_be_overridden.rs @@ -0,0 +1,14 @@ +//@ revisions: OPT0 OPT1 +//@ [OPT0] compile-flags: -Copt-level=0 +//@ [OPT1] compile-flags: -Copt-level=1 +//@ compile-flags: -Cno-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +// CHECK-NOT: core::intrinsics::size_of_val + +#[no_mangle] +pub unsafe fn size_of_val(ptr: *const i32) -> usize { + core::intrinsics::size_of_val(ptr) +} diff --git a/tests/codegen-llvm/intrinsics/select_unpredictable.rs b/tests/codegen-llvm/intrinsics/select_unpredictable.rs new file mode 100644 index 00000000000..ad7120c6fb8 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/select_unpredictable.rs @@ -0,0 +1,71 @@ +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled + +#![feature(core_intrinsics)] +#![crate_type = "lib"] + +/* Test the intrinsic */ + +#[no_mangle] +pub fn test_int(p: bool, a: u64, b: u64) -> u64 { + // CHECK-LABEL: define{{.*}} @test_int + // CHECK: select i1 %p, i64 %a, i64 %b, !unpredictable + core::intrinsics::select_unpredictable(p, a, b) +} + +#[no_mangle] +pub fn test_pair(p: bool, a: (u64, u64), b: (u64, u64)) -> (u64, u64) { + // CHECK-LABEL: define{{.*}} @test_pair + // CHECK: select i1 %p, {{.*}}, !unpredictable + core::intrinsics::select_unpredictable(p, a, b) +} + +struct Large { + e: [u64; 100], +} + +#[no_mangle] +pub fn test_struct(p: bool, a: Large, b: Large) -> Large { + // CHECK-LABEL: define{{.*}} @test_struct + // CHECK: select i1 %p, {{.*}}, !unpredictable + core::intrinsics::select_unpredictable(p, a, b) +} + +// ZSTs should not need a `select` expression. +#[no_mangle] +pub fn test_zst(p: bool, a: (), b: ()) -> () { + // CHECK-LABEL: define{{.*}} @test_zst + // CHECK-NEXT: start: + // CHECK-NEXT: ret void + core::intrinsics::select_unpredictable(p, a, b) +} + +/* Test the user-facing version */ + +#[no_mangle] +pub fn test_int2(p: bool, a: u64, b: u64) -> u64 { + // CHECK-LABEL: define{{.*}} @test_int2 + // CHECK: select i1 %p, i64 %a, i64 %b, !unpredictable + core::hint::select_unpredictable(p, a, b) +} + +#[no_mangle] +pub fn test_pair2(p: bool, a: (u64, u64), b: (u64, u64)) -> (u64, u64) { + // CHECK-LABEL: define{{.*}} @test_pair2 + // CHECK: select i1 %p, {{.*}}, !unpredictable + core::hint::select_unpredictable(p, a, b) +} + +#[no_mangle] +pub fn test_struct2(p: bool, a: Large, b: Large) -> Large { + // CHECK-LABEL: define{{.*}} @test_struct2 + // CHECK: select i1 %p, {{.*}}, !unpredictable + core::hint::select_unpredictable(p, a, b) +} + +#[no_mangle] +pub fn test_zst2(p: bool, a: (), b: ()) -> () { + // CHECK-LABEL: define{{.*}} @test_zst2 + // CHECK-NEXT: start: + // CHECK-NEXT: ret void + core::hint::select_unpredictable(p, a, b) +} diff --git a/tests/codegen-llvm/intrinsics/three_way_compare.rs b/tests/codegen-llvm/intrinsics/three_way_compare.rs new file mode 100644 index 00000000000..95fcb636f7c --- /dev/null +++ b/tests/codegen-llvm/intrinsics/three_way_compare.rs @@ -0,0 +1,28 @@ +//@ revisions: DEBUG OPTIM +//@ [DEBUG] compile-flags: -C opt-level=0 +//@ [OPTIM] compile-flags: -C opt-level=3 +//@ compile-flags: -C no-prepopulate-passes +//@ min-llvm-version: 20 + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::three_way_compare; + +#[no_mangle] +// CHECK-LABEL: @signed_cmp +// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b) +pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering { + // CHECK: %[[CMP:.+]] = call i8 @llvm.scmp.i8.i16(i16 %a, i16 %b) + // CHECK-NEXT: ret i8 %[[CMP]] + three_way_compare(a, b) +} + +#[no_mangle] +// CHECK-LABEL: @unsigned_cmp +// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b) +pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering { + // CHECK: %[[CMP:.+]] = call i8 @llvm.ucmp.i8.i16(i16 %a, i16 %b) + // CHECK-NEXT: ret i8 %[[CMP]] + three_way_compare(a, b) +} diff --git a/tests/codegen-llvm/intrinsics/transmute-niched.rs b/tests/codegen-llvm/intrinsics/transmute-niched.rs new file mode 100644 index 00000000000..8ff5cc8ee4f --- /dev/null +++ b/tests/codegen-llvm/intrinsics/transmute-niched.rs @@ -0,0 +1,223 @@ +//@ revisions: OPT DBG +//@ [OPT] compile-flags: -C opt-level=3 -C no-prepopulate-passes +//@ [DBG] compile-flags: -C opt-level=0 -C no-prepopulate-passes +//@ only-64bit (so I don't need to worry about usize) +#![crate_type = "lib"] + +use std::mem::transmute; +use std::num::NonZero; +use std::ptr::NonNull; + +#[repr(u8)] +pub enum SmallEnum { + A = 10, + B = 11, + C = 12, +} + +// CHECK-LABEL: @check_to_enum( +#[no_mangle] +pub unsafe fn check_to_enum(x: i8) -> SmallEnum { + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = sub i8 %x, 10 + // OPT: %1 = icmp ule i8 %0, 2 + // OPT: call void @llvm.assume(i1 %1) + // CHECK-NOT: icmp + // CHECK-NOT: assume + // CHECK: ret i8 %x + + transmute(x) +} + +// CHECK-LABEL: @check_from_enum( +#[no_mangle] +pub unsafe fn check_from_enum(x: SmallEnum) -> i8 { + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = sub i8 %x, 10 + // OPT: %1 = icmp ule i8 %0, 2 + // OPT: call void @llvm.assume(i1 %1) + // CHECK-NOT: icmp + // CHECK-NOT: assume + // CHECK: ret i8 %x + + transmute(x) +} + +// CHECK-LABEL: @check_to_ordering( +#[no_mangle] +pub unsafe fn check_to_ordering(x: u8) -> std::cmp::Ordering { + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = sub i8 %x, -1 + // OPT: %1 = icmp ule i8 %0, 2 + // OPT: call void @llvm.assume(i1 %1) + // CHECK-NOT: icmp + // CHECK-NOT: assume + // CHECK: ret i8 %x + + transmute(x) +} + +// CHECK-LABEL: @check_from_ordering( +#[no_mangle] +pub unsafe fn check_from_ordering(x: std::cmp::Ordering) -> u8 { + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = sub i8 %x, -1 + // OPT: %1 = icmp ule i8 %0, 2 + // OPT: call void @llvm.assume(i1 %1) + // CHECK-NOT: icmp + // CHECK-NOT: assume + // CHECK: ret i8 %x + + transmute(x) +} + +#[repr(i32)] +pub enum Minus100ToPlus100 { + A = -100, + B = -90, + C = -80, + D = -70, + E = -60, + F = -50, + G = -40, + H = -30, + I = -20, + J = -10, + K = 0, + L = 10, + M = 20, + N = 30, + O = 40, + P = 50, + Q = 60, + R = 70, + S = 80, + T = 90, + U = 100, +} + +// CHECK-LABEL: @check_enum_from_char( +#[no_mangle] +pub unsafe fn check_enum_from_char(x: char) -> Minus100ToPlus100 { + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = icmp ule i32 %x, 1114111 + // OPT: call void @llvm.assume(i1 %0) + // OPT: %1 = sub i32 %x, -100 + // OPT: %2 = icmp ule i32 %1, 200 + // OPT: call void @llvm.assume(i1 %2) + // CHECK-NOT: icmp + // CHECK-NOT: assume + // CHECK: ret i32 %x + + transmute(x) +} + +// CHECK-LABEL: @check_enum_to_char( +#[no_mangle] +pub unsafe fn check_enum_to_char(x: Minus100ToPlus100) -> char { + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = sub i32 %x, -100 + // OPT: %1 = icmp ule i32 %0, 200 + // OPT: call void @llvm.assume(i1 %1) + // OPT: %2 = icmp ule i32 %x, 1114111 + // OPT: call void @llvm.assume(i1 %2) + // CHECK-NOT: icmp + // CHECK-NOT: assume + // CHECK: ret i32 %x + + transmute(x) +} + +// CHECK-LABEL: @check_swap_pair( +#[no_mangle] +pub unsafe fn check_swap_pair(x: (char, NonZero)) -> (NonZero, char) { + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = icmp ule i32 %x.0, 1114111 + // OPT: call void @llvm.assume(i1 %0) + // OPT: %1 = sub i32 %x.0, 1 + // OPT: %2 = icmp ule i32 %1, -2 + // OPT: call void @llvm.assume(i1 %2) + // OPT: %3 = sub i32 %x.1, 1 + // OPT: %4 = icmp ule i32 %3, -2 + // OPT: call void @llvm.assume(i1 %4) + // OPT: %5 = icmp ule i32 %x.1, 1114111 + // OPT: call void @llvm.assume(i1 %5) + // CHECK-NOT: icmp + // CHECK-NOT: assume + // CHECK: %[[P1:.+]] = insertvalue { i32, i32 } poison, i32 %x.0, 0 + // CHECK: %[[P2:.+]] = insertvalue { i32, i32 } %[[P1]], i32 %x.1, 1 + // CHECK: ret { i32, i32 } %[[P2]] + + transmute(x) +} + +// CHECK-LABEL: @check_bool_from_ordering( +#[no_mangle] +pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool { + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = sub i8 %x, -1 + // OPT: %1 = icmp ule i8 %0, 2 + // OPT: call void @llvm.assume(i1 %1) + // OPT: %2 = icmp ule i8 %x, 1 + // OPT: call void @llvm.assume(i1 %2) + // CHECK-NOT: icmp + // CHECK-NOT: assume + // CHECK: %[[R:.+]] = trunc{{( nuw)?}} i8 %x to i1 + // CHECK: ret i1 %[[R]] + + transmute(x) +} + +// CHECK-LABEL: @check_bool_to_ordering( +#[no_mangle] +pub unsafe fn check_bool_to_ordering(x: bool) -> std::cmp::Ordering { + // CHECK: %_0 = zext i1 %x to i8 + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = icmp ule i8 %_0, 1 + // OPT: call void @llvm.assume(i1 %0) + // OPT: %1 = sub i8 %_0, -1 + // OPT: %2 = icmp ule i8 %1, 2 + // OPT: call void @llvm.assume(i1 %2) + // CHECK-NOT: icmp + // CHECK-NOT: assume + // CHECK: ret i8 %_0 + + transmute(x) +} + +// CHECK-LABEL: @check_nonnull_to_ptr( +#[no_mangle] +pub unsafe fn check_nonnull_to_ptr(x: NonNull) -> *const u8 { + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = icmp ne ptr %x, null + // OPT: call void @llvm.assume(i1 %0) + // CHECK-NOT: icmp + // CHECK-NOT: assume + // CHECK: ret ptr %x + + transmute(x) +} + +// CHECK-LABEL: @check_ptr_to_nonnull( +#[no_mangle] +pub unsafe fn check_ptr_to_nonnull(x: *const u8) -> NonNull { + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = icmp ne ptr %x, null + // OPT: call void @llvm.assume(i1 %0) + // CHECK-NOT: icmp + // CHECK-NOT: assume + // CHECK: ret ptr %x + + transmute(x) +} diff --git a/tests/codegen-llvm/intrinsics/transmute-x64.rs b/tests/codegen-llvm/intrinsics/transmute-x64.rs new file mode 100644 index 00000000000..8c9480ab091 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/transmute-x64.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes +//@ only-x86_64 (it's using arch-specific types) + +#![crate_type = "lib"] + +use std::arch::x86_64::{__m128, __m128i, __m256i}; +use std::mem::transmute; + +// CHECK-LABEL: @check_sse_pair_to_avx( +#[no_mangle] +pub unsafe fn check_sse_pair_to_avx(x: (__m128i, __m128i)) -> __m256i { + // CHECK: start: + // CHECK-NOT: alloca + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 32 %_0, ptr align 16 %x, i64 32, i1 false) + // CHECK-NEXT: ret void + transmute(x) +} + +// CHECK-LABEL: @check_sse_pair_from_avx( +#[no_mangle] +pub unsafe fn check_sse_pair_from_avx(x: __m256i) -> (__m128i, __m128i) { + // CHECK: start: + // CHECK-NOT: alloca + // CHECK-NEXT: %[[TEMP:.+]] = load <4 x i64>, ptr %x, align 32 + // CHECK-NEXT: store <4 x i64> %[[TEMP]], ptr %_0, align 16 + // CHECK-NEXT: ret void + transmute(x) +} diff --git a/tests/codegen-llvm/intrinsics/transmute.rs b/tests/codegen-llvm/intrinsics/transmute.rs new file mode 100644 index 00000000000..c9a1cd58af3 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/transmute.rs @@ -0,0 +1,497 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes +//@ only-64bit (so I don't need to worry about usize) + +#![crate_type = "lib"] +#![feature(core_intrinsics)] +#![feature(custom_mir)] +#![allow(unreachable_code)] + +// Some of these need custom MIR to not get removed by MIR optimizations. +use std::intrinsics::mir::*; +use std::intrinsics::{transmute, transmute_unchecked}; +use std::mem::MaybeUninit; +use std::num::NonZero; + +pub enum ZstNever {} + +#[repr(align(2))] +pub struct BigNever(ZstNever, u16, ZstNever); + +#[repr(align(8))] +pub struct Scalar64(i64); + +#[repr(C, align(4))] +pub struct Aggregate64(u16, u8, i8, f32); + +#[repr(C)] +pub struct Aggregate8(u8); + +// CHECK-LABEL: @check_bigger_size( +#[no_mangle] +pub unsafe fn check_bigger_size(x: u16) -> u32 { + // CHECK: store i1 true, ptr poison, align 1 + transmute_unchecked(x) +} + +// CHECK-LABEL: @check_smaller_size( +#[no_mangle] +pub unsafe fn check_smaller_size(x: u32) -> u16 { + // CHECK: store i1 true, ptr poison, align 1 + transmute_unchecked(x) +} + +// CHECK-LABEL: @check_smaller_array( +#[no_mangle] +pub unsafe fn check_smaller_array(x: [u32; 7]) -> [u32; 3] { + // CHECK: store i1 true, ptr poison, align 1 + transmute_unchecked(x) +} + +// CHECK-LABEL: @check_bigger_array( +#[no_mangle] +pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] { + // CHECK: store i1 true, ptr poison, align 1 + transmute_unchecked(x) +} + +// CHECK-LABEL: @check_to_empty_array( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] { + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void + mir! { + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_from_empty_array( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] { + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void + mir! { + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_to_uninhabited( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub unsafe fn check_to_uninhabited(x: u16) { + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void + mir! { + let temp: BigNever; + { + temp = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_from_uninhabited( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 { + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret i16 poison + mir! { + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_intermediate_passthrough( +#[no_mangle] +pub unsafe fn check_intermediate_passthrough(x: u32) -> i32 { + // CHECK: start + // CHECK: %[[TMP:.+]] = add i32 1, %x + // CHECK: %[[RET:.+]] = add i32 %[[TMP]], 1 + // CHECK: ret i32 %[[RET]] + unsafe { transmute::(1 + x) + 1 } +} + +// CHECK-LABEL: @check_nop_pair( +#[no_mangle] +pub unsafe fn check_nop_pair(x: (u8, i8)) -> (i8, u8) { + // CHECK-NOT: alloca + // CHECK: %0 = insertvalue { i8, i8 } poison, i8 %x.0, 0 + // CHECK: %1 = insertvalue { i8, i8 } %0, i8 %x.1, 1 + // CHECK: ret { i8, i8 } %1 + unsafe { transmute(x) } +} + +// CHECK-LABEL: @check_to_newtype( +#[no_mangle] +pub unsafe fn check_to_newtype(x: u64) -> Scalar64 { + // CHECK-NOT: alloca + // CHECK: ret i64 %x + transmute(x) +} + +// CHECK-LABEL: @check_from_newtype( +#[no_mangle] +pub unsafe fn check_from_newtype(x: Scalar64) -> u64 { + // CHECK-NOT: alloca + // CHECK: ret i64 %x + transmute(x) +} + +// CHECK-LABEL: @check_aggregate_to_bool( +#[no_mangle] +pub unsafe fn check_aggregate_to_bool(x: Aggregate8) -> bool { + // CHECK: %x = alloca [1 x i8], align 1 + // CHECK: %[[BYTE:.+]] = load i8, ptr %x, align 1 + // CHECK: %[[BOOL:.+]] = trunc nuw i8 %[[BYTE]] to i1 + // CHECK: ret i1 %[[BOOL]] + transmute(x) +} + +// CHECK-LABEL: @check_aggregate_from_bool( +#[no_mangle] +pub unsafe fn check_aggregate_from_bool(x: bool) -> Aggregate8 { + // CHECK: %_0 = alloca [1 x i8], align 1 + // CHECK: %[[BYTE:.+]] = zext i1 %x to i8 + // CHECK: store i8 %[[BYTE]], ptr %_0, align 1 + transmute(x) +} + +// CHECK-LABEL: @check_byte_to_bool( +#[no_mangle] +pub unsafe fn check_byte_to_bool(x: u8) -> bool { + // CHECK-NOT: alloca + // CHECK: %[[R:.+]] = trunc nuw i8 %x to i1 + // CHECK: ret i1 %[[R]] + transmute(x) +} + +// CHECK-LABEL: @check_byte_from_bool( +#[no_mangle] +pub unsafe fn check_byte_from_bool(x: bool) -> u8 { + // CHECK-NOT: alloca + // CHECK: %[[R:.+]] = zext i1 %x to i8 + // CHECK: ret i8 %[[R:.+]] + transmute(x) +} + +// CHECK-LABEL: @check_to_pair( +#[no_mangle] +pub unsafe fn check_to_pair(x: u64) -> Option { + // CHECK: %_0 = alloca [8 x i8], align 4 + // CHECK: store i64 %x, ptr %_0, align 4 + transmute(x) +} + +// CHECK-LABEL: @check_from_pair( +#[no_mangle] +pub unsafe fn check_from_pair(x: Option) -> u64 { + // The two arguments are of types that are only 4-aligned, but they're + // immediates so we can write using the destination alloca's alignment. + const { assert!(std::mem::align_of::>() == 4) }; + + // CHECK: %_0 = alloca [8 x i8], align 8 + // CHECK: store i32 %x.0, ptr %_0, align 8 + // CHECK: store i32 %x.1, ptr %0, align 4 + // CHECK: %[[R:.+]] = load i64, ptr %_0, align 8 + // CHECK: ret i64 %[[R]] + transmute(x) +} + +// CHECK-LABEL: @check_to_float( +#[no_mangle] +pub unsafe fn check_to_float(x: u32) -> f32 { + // CHECK-NOT: alloca + // CHECK: %_0 = bitcast i32 %x to float + // CHECK: ret float %_0 + transmute(x) +} + +// CHECK-LABEL: @check_from_float( +#[no_mangle] +pub unsafe fn check_from_float(x: f32) -> u32 { + // CHECK-NOT: alloca + // CHECK: %_0 = bitcast float %x to i32 + // CHECK: ret i32 %_0 + transmute(x) +} + +// CHECK-LABEL: @check_to_bytes( +#[no_mangle] +pub unsafe fn check_to_bytes(x: u32) -> [u8; 4] { + // CHECK: %_0 = alloca [4 x i8], align 1 + // CHECK: store i32 %x, ptr %_0, align 1 + transmute(x) +} + +// CHECK-LABEL: @check_from_bytes( +#[no_mangle] +pub unsafe fn check_from_bytes(x: [u8; 4]) -> u32 { + // CHECK: %x = alloca [4 x i8], align 1 + // CHECK: %[[VAL:.+]] = load i32, ptr %x, align 1 + // CHECK: ret i32 %[[VAL]] + transmute(x) +} + +// CHECK-LABEL: @check_to_aggregate( +#[no_mangle] +pub unsafe fn check_to_aggregate(x: u64) -> Aggregate64 { + // CHECK: %_0 = alloca [8 x i8], align 4 + // CHECK: store i64 %x, ptr %_0, align 4 + // CHECK: %0 = load i64, ptr %_0, align 4 + // CHECK: ret i64 %0 + transmute(x) +} + +// CHECK-LABEL: @check_from_aggregate( +#[no_mangle] +pub unsafe fn check_from_aggregate(x: Aggregate64) -> u64 { + // CHECK: %x = alloca [8 x i8], align 4 + // CHECK: %[[VAL:.+]] = load i64, ptr %x, align 4 + // CHECK: ret i64 %[[VAL]] + transmute(x) +} + +// CHECK-LABEL: @check_long_array_less_aligned( +#[no_mangle] +pub unsafe fn check_long_array_less_aligned(x: [u64; 100]) -> [u16; 400] { + // CHECK-NEXT: start + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 2 %_0, ptr align 8 %x, i64 800, i1 false) + // CHECK-NEXT: ret void + transmute(x) +} + +// CHECK-LABEL: @check_long_array_more_aligned( +#[no_mangle] +pub unsafe fn check_long_array_more_aligned(x: [u8; 100]) -> [u32; 25] { + // CHECK-NEXT: start + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %_0, ptr align 1 %x, i64 100, i1 false) + // CHECK-NEXT: ret void + transmute(x) +} + +// CHECK-LABEL: @check_pair_with_bool( +#[no_mangle] +pub unsafe fn check_pair_with_bool(x: (u8, bool)) -> (bool, i8) { + // CHECK-NOT: alloca + // CHECK: trunc nuw i8 %x.0 to i1 + // CHECK: zext i1 %x.1 to i8 + transmute(x) +} + +// CHECK-LABEL: @check_float_to_pointer( +#[no_mangle] +pub unsafe fn check_float_to_pointer(x: f64) -> *const () { + // CHECK-NOT: alloca + // CHECK: %0 = bitcast double %x to i64 + // CHECK: %_0 = getelementptr i8, ptr null, i64 %0 + // CHECK: ret ptr %_0 + transmute(x) +} + +// CHECK-LABEL: @check_float_from_pointer( +#[no_mangle] +pub unsafe fn check_float_from_pointer(x: *const ()) -> f64 { + // CHECK-NOT: alloca + // CHECK: %0 = ptrtoint ptr %x to i64 + // CHECK: %_0 = bitcast i64 %0 to double + // CHECK: ret double %_0 + transmute(x) +} + +// CHECK-LABEL: @check_array_to_pair( +#[no_mangle] +pub unsafe fn check_array_to_pair(x: [u8; 16]) -> (i64, u64) { + // CHECK-NOT: alloca + // CHECK: %[[FST:.+]] = load i64, ptr %{{.+}}, align 1, !noundef ! + // CHECK: %[[SND:.+]] = load i64, ptr %{{.+}}, align 1, !noundef ! + // CHECK: %[[PAIR0:.+]] = insertvalue { i64, i64 } poison, i64 %[[FST]], 0 + // CHECK: %[[PAIR01:.+]] = insertvalue { i64, i64 } %[[PAIR0]], i64 %[[SND]], 1 + // CHECK: ret { i64, i64 } %[[PAIR01]] + transmute(x) +} + +// CHECK-LABEL: @check_pair_to_array( +#[no_mangle] +pub unsafe fn check_pair_to_array(x: (i64, u64)) -> [u8; 16] { + // CHECK-NOT: alloca + // CHECK: store i64 %x.0, ptr %{{.+}}, align 1 + // CHECK: store i64 %x.1, ptr %{{.+}}, align 1 + transmute(x) +} + +// CHECK-LABEL: @check_heterogeneous_integer_pair( +#[no_mangle] +pub unsafe fn check_heterogeneous_integer_pair(x: (i32, bool)) -> (bool, u32) { + // CHECK: store i32 %x.0 + // CHECK: %[[WIDER:.+]] = zext i1 %x.1 to i8 + // CHECK: store i8 %[[WIDER]] + + // CHECK: %[[BYTE:.+]] = load i8 + // CHECK: trunc nuw i8 %[[BYTE:.+]] to i1 + // CHECK: load i32 + transmute(x) +} + +// CHECK-LABEL: @check_heterogeneous_float_pair( +#[no_mangle] +pub unsafe fn check_heterogeneous_float_pair(x: (f64, f32)) -> (f32, f64) { + // CHECK: store double %x.0 + // CHECK: store float %x.1 + // CHECK: %[[A:.+]] = load float + // CHECK: %[[B:.+]] = load double + // CHECK: %[[P:.+]] = insertvalue { float, double } poison, float %[[A]], 0 + // CHECK: insertvalue { float, double } %[[P]], double %[[B]], 1 + transmute(x) +} + +// CHECK-LABEL: @check_issue_110005( +#[no_mangle] +pub unsafe fn check_issue_110005(x: (usize, bool)) -> Option> { + // CHECK: store i64 %x.0 + // CHECK: %[[WIDER:.+]] = zext i1 %x.1 to i8 + // CHECK: store i8 %[[WIDER]] + // CHECK: load ptr + // CHECK: load i64 + transmute(x) +} + +// CHECK-LABEL: @check_pair_to_dst_ref( +#[no_mangle] +pub unsafe fn check_pair_to_dst_ref<'a>(x: (usize, usize)) -> &'a [u8] { + // CHECK: %_0.0 = getelementptr i8, ptr null, i64 %x.0 + // CHECK: %0 = icmp ne ptr %_0.0, null + // CHECK: call void @llvm.assume(i1 %0) + // CHECK: %1 = insertvalue { ptr, i64 } poison, ptr %_0.0, 0 + // CHECK: %2 = insertvalue { ptr, i64 } %1, i64 %x.1, 1 + // CHECK: ret { ptr, i64 } %2 + transmute(x) +} + +// CHECK-LABEL: @check_issue_109992( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub unsafe fn check_issue_109992(x: ()) -> [(); 1] { + // This uses custom MIR to avoid MIR optimizations having removed ZST ops. + + // CHECK: start + // CHECK-NEXT: ret void + mir! { + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_unit_to_never( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub unsafe fn check_unit_to_never(x: ()) { + // This uses custom MIR to avoid MIR optimizations having removed ZST ops. + + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void + mir! { + let temp: ZstNever; + { + temp = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_unit_from_never( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub unsafe fn check_unit_from_never(x: ZstNever) -> () { + // This uses custom MIR to avoid MIR optimizations having removed ZST ops. + + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void + mir! { + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_maybe_uninit_pair(i16 %x.0, i64 %x.1) +#[no_mangle] +pub unsafe fn check_maybe_uninit_pair( + x: (MaybeUninit, MaybeUninit), +) -> (MaybeUninit, MaybeUninit) { + // Thanks to `MaybeUninit` this is actually defined behaviour, + // unlike the examples above with pairs of primitives. + + // CHECK: store i16 %x.0 + // CHECK: store i64 %x.1 + // CHECK: load i64 + // CHECK-NOT: noundef + // CHECK: load i16 + // CHECK-NOT: noundef + // CHECK: ret { i64, i16 } + transmute(x) +} + +#[repr(align(8))] +pub struct HighAlignScalar(u8); + +// CHECK-LABEL: @check_to_overalign( +#[no_mangle] +pub unsafe fn check_to_overalign(x: u64) -> HighAlignScalar { + // CHECK: %_0 = alloca [8 x i8], align 8 + // CHECK: store i64 %x, ptr %_0, align 8 + // CHECK: %0 = load i64, ptr %_0, align 8 + // CHECK: ret i64 %0 + transmute(x) +} + +// CHECK-LABEL: @check_from_overalign( +#[no_mangle] +pub unsafe fn check_from_overalign(x: HighAlignScalar) -> u64 { + // CHECK: %x = alloca [8 x i8], align 8 + // CHECK: %[[VAL:.+]] = load i64, ptr %x, align 8 + // CHECK: ret i64 %[[VAL]] + transmute(x) +} + +#[repr(transparent)] +struct Level1(std::num::NonZero); +#[repr(transparent)] +struct Level2(Level1); +#[repr(transparent)] +struct Level3(Level2); + +// CHECK-LABEL: @repeatedly_transparent_transmute +// CHECK-SAME: (i32{{.+}}%[[ARG:[^)]+]]) +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub unsafe fn repeatedly_transparent_transmute(x: NonZero) -> Level3 { + // CHECK: start + // CHECK-NEXT: ret i32 %[[ARG]] + mir! { + { + let A = CastTransmute::, Level1>(x); + let B = CastTransmute::(A); + RET = CastTransmute::(B); + Return() + } + } +} diff --git a/tests/codegen-llvm/intrinsics/typed_swap.rs b/tests/codegen-llvm/intrinsics/typed_swap.rs new file mode 100644 index 00000000000..6b55078407a --- /dev/null +++ b/tests/codegen-llvm/intrinsics/typed_swap.rs @@ -0,0 +1,77 @@ +//@ revisions: OPT0 OPT3 +//@ [OPT0] compile-flags: -Copt-level=0 +//@ [OPT3] compile-flags: -Copt-level=3 +//@ compile-flags: -C no-prepopulate-passes +//@ only-64bit (so I don't need to worry about usize) +// ignore-tidy-linelength (the memcpy calls get long) + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::typed_swap_nonoverlapping; + +// CHECK-LABEL: @swap_unit( +#[no_mangle] +pub unsafe fn swap_unit(x: &mut (), y: &mut ()) { + // CHECK: start + // CHECK-NEXT: ret void + typed_swap_nonoverlapping(x, y) +} + +// CHECK-LABEL: @swap_i32( +#[no_mangle] +pub unsafe fn swap_i32(x: &mut i32, y: &mut i32) { + // CHECK-NOT: alloca + + // CHECK: %[[TEMP:.+]] = load i32, ptr %x, align 4 + // OPT3-SAME: !noundef + // OPT0: %[[TEMP2:.+]] = load i32, ptr %y, align 4 + // OPT0: store i32 %[[TEMP2]], ptr %x, align 4 + // OPT0-NOT: memcpy + // OPT3-NOT: load + // OPT3: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 4, i1 false) + // CHECK: store i32 %[[TEMP]], ptr %y, align 4 + // CHECK: ret void + typed_swap_nonoverlapping(x, y) +} + +// CHECK-LABEL: @swap_pair( +#[no_mangle] +pub unsafe fn swap_pair(x: &mut (i32, u32), y: &mut (i32, u32)) { + // CHECK-NOT: alloca + + // CHECK: load i32 + // OPT3-SAME: !noundef + // CHECK: load i32 + // OPT3-SAME: !noundef + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 8, i1 false) + // CHECK: store i32 + // CHECK: store i32 + typed_swap_nonoverlapping(x, y) +} + +// CHECK-LABEL: @swap_str( +#[no_mangle] +pub unsafe fn swap_str<'a>(x: &mut &'a str, y: &mut &'a str) { + // CHECK-NOT: alloca + + // CHECK: load ptr + // OPT3-SAME: !nonnull + // OPT3-SAME: !noundef + // CHECK: load i64 + // OPT3-SAME: !noundef + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %x, ptr align 8 %y, i64 16, i1 false) + // CHECK: store ptr + // CHECK: store i64 + typed_swap_nonoverlapping(x, y) +} + +// OPT0-LABEL: @swap_string( +#[no_mangle] +pub unsafe fn swap_string(x: &mut String, y: &mut String) { + // OPT0: %[[TEMP:.+]] = alloca {{.+}}, align 8 + // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[TEMP]], ptr align 8 %x, i64 24, i1 false) + // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %x, ptr align 8 %y, i64 24, i1 false) + // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %y, ptr align 8 %[[TEMP]], i64 24, i1 false) + typed_swap_nonoverlapping(x, y) +} diff --git a/tests/codegen-llvm/intrinsics/unchecked_math.rs b/tests/codegen-llvm/intrinsics/unchecked_math.rs new file mode 100644 index 00000000000..419c120ede9 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/unchecked_math.rs @@ -0,0 +1,46 @@ +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +// CHECK-LABEL: @unchecked_add_signed +#[no_mangle] +pub unsafe fn unchecked_add_signed(a: i32, b: i32) -> i32 { + // CHECK: add nsw + unchecked_add(a, b) +} + +// CHECK-LABEL: @unchecked_add_unsigned +#[no_mangle] +pub unsafe fn unchecked_add_unsigned(a: u32, b: u32) -> u32 { + // CHECK: add nuw + unchecked_add(a, b) +} + +// CHECK-LABEL: @unchecked_sub_signed +#[no_mangle] +pub unsafe fn unchecked_sub_signed(a: i32, b: i32) -> i32 { + // CHECK: sub nsw + unchecked_sub(a, b) +} + +// CHECK-LABEL: @unchecked_sub_unsigned +#[no_mangle] +pub unsafe fn unchecked_sub_unsigned(a: u32, b: u32) -> u32 { + // CHECK: sub nuw + unchecked_sub(a, b) +} + +// CHECK-LABEL: @unchecked_mul_signed +#[no_mangle] +pub unsafe fn unchecked_mul_signed(a: i32, b: i32) -> i32 { + // CHECK: mul nsw + unchecked_mul(a, b) +} + +// CHECK-LABEL: @unchecked_mul_unsigned +#[no_mangle] +pub unsafe fn unchecked_mul_unsigned(a: u32, b: u32) -> u32 { + // CHECK: mul nuw + unchecked_mul(a, b) +} diff --git a/tests/codegen-llvm/intrinsics/unlikely.rs b/tests/codegen-llvm/intrinsics/unlikely.rs new file mode 100644 index 00000000000..90ebf070d27 --- /dev/null +++ b/tests/codegen-llvm/intrinsics/unlikely.rs @@ -0,0 +1,35 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::unlikely; + +#[inline(never)] +#[no_mangle] +pub fn path_a() { + println!("path a"); +} + +#[inline(never)] +#[no_mangle] +pub fn path_b() { + println!("path b"); +} + +#[no_mangle] +pub fn test_unlikely(x: bool) { + if unlikely(x) { + path_a(); + } else { + path_b(); + } +} + +// CHECK-LABEL: @test_unlikely( +// CHECK: br i1 %x, label %bb2, label %bb4, !prof ![[NUM:[0-9]+]] +// CHECK: bb4: +// CHECK: path_b +// CHECK: bb2: +// CHECK-NOT: cold_path +// CHECK: path_a +// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000} diff --git a/tests/codegen-llvm/intrinsics/volatile.rs b/tests/codegen-llvm/intrinsics/volatile.rs new file mode 100644 index 00000000000..2dea5ecb2ca --- /dev/null +++ b/tests/codegen-llvm/intrinsics/volatile.rs @@ -0,0 +1,55 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics; + +// CHECK-LABEL: @volatile_copy_memory +#[no_mangle] +pub unsafe fn volatile_copy_memory(a: *mut u8, b: *const u8) { + // CHECK: llvm.memmove.{{\w*(.*true)}} + intrinsics::volatile_copy_memory(a, b, 1) +} + +// CHECK-LABEL: @volatile_copy_nonoverlapping_memory +#[no_mangle] +pub unsafe fn volatile_copy_nonoverlapping_memory(a: *mut u8, b: *const u8) { + // CHECK: llvm.memcpy.{{\w*(.*true)}} + intrinsics::volatile_copy_nonoverlapping_memory(a, b, 1) +} + +// CHECK-LABEL: @volatile_set_memory +#[no_mangle] +pub unsafe fn volatile_set_memory(a: *mut u8, b: u8) { + // CHECK: llvm.memset.{{\w*(.*true)}} + intrinsics::volatile_set_memory(a, b, 1) +} + +// CHECK-LABEL: @volatile_load +#[no_mangle] +pub unsafe fn volatile_load(a: *const u8) -> u8 { + // CHECK: load volatile + intrinsics::volatile_load(a) +} + +// CHECK-LABEL: @volatile_store +#[no_mangle] +pub unsafe fn volatile_store(a: *mut u8, b: u8) { + // CHECK: store volatile + intrinsics::volatile_store(a, b) +} + +// CHECK-LABEL: @unaligned_volatile_load +#[no_mangle] +pub unsafe fn unaligned_volatile_load(a: *const u8) -> u8 { + // CHECK: load volatile + intrinsics::unaligned_volatile_load(a) +} + +// CHECK-LABEL: @unaligned_volatile_store +#[no_mangle] +pub unsafe fn unaligned_volatile_store(a: *mut u8, b: u8) { + // CHECK: store volatile + intrinsics::unaligned_volatile_store(a, b) +} diff --git a/tests/codegen-llvm/intrinsics/volatile_order.rs b/tests/codegen-llvm/intrinsics/volatile_order.rs new file mode 100644 index 00000000000..99469831a6c --- /dev/null +++ b/tests/codegen-llvm/intrinsics/volatile_order.rs @@ -0,0 +1,18 @@ +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +pub unsafe fn test_volatile_order() { + let mut a: Box = Box::new(0); + // CHECK: load volatile + let x = volatile_load(&*a); + // CHECK: load volatile + let x = volatile_load(&*a); + // CHECK: store volatile + volatile_store(&mut *a, 12); + // CHECK: store volatile + unaligned_volatile_store(&mut *a, 12); + // CHECK: llvm.memset.p0 + volatile_set_memory(&mut *a, 12, 1) +} diff --git a/tests/codegen-llvm/is_val_statically_known.rs b/tests/codegen-llvm/is_val_statically_known.rs new file mode 100644 index 00000000000..8119d3a3bf6 --- /dev/null +++ b/tests/codegen-llvm/is_val_statically_known.rs @@ -0,0 +1,163 @@ +//@ compile-flags: --crate-type=lib -Zmerge-functions=disabled -Copt-level=3 + +#![feature(core_intrinsics)] +#![feature(f16, f128)] + +use std::intrinsics::is_val_statically_known; + +pub struct A(u32); +pub enum B { + Ye(u32), +} + +#[inline] +pub fn _u32(a: u32) -> i32 { + if is_val_statically_known(a) { 1 } else { 0 } +} + +// CHECK-LABEL: @_u32_true( +#[no_mangle] +pub fn _u32_true() -> i32 { + // CHECK: ret i32 1 + _u32(1) +} + +// CHECK-LABEL: @_u32_false( +#[no_mangle] +pub fn _u32_false(a: u32) -> i32 { + // CHECK: ret i32 0 + _u32(a) +} + +#[inline] +pub fn _bool(b: bool) -> i32 { + if is_val_statically_known(b) { 3 } else { 2 } +} + +// CHECK-LABEL: @_bool_true( +#[no_mangle] +pub fn _bool_true() -> i32 { + // CHECK: ret i32 3 + _bool(true) +} + +// CHECK-LABEL: @_bool_false( +#[no_mangle] +pub fn _bool_false(b: bool) -> i32 { + // CHECK: ret i32 2 + _bool(b) +} + +#[inline] +pub fn _iref(a: &u8) -> i32 { + if is_val_statically_known(a) { 5 } else { 4 } +} + +// CHECK-LABEL: @_iref_borrow( +#[no_mangle] +pub fn _iref_borrow() -> i32 { + // CHECK: ret i32 4 + _iref(&0) +} + +// CHECK-LABEL: @_iref_arg( +#[no_mangle] +pub fn _iref_arg(a: &u8) -> i32 { + // CHECK: ret i32 4 + _iref(a) +} + +#[inline] +pub fn _slice_ref(a: &[u8]) -> i32 { + if is_val_statically_known(a) { 7 } else { 6 } +} + +// CHECK-LABEL: @_slice_ref_borrow( +#[no_mangle] +pub fn _slice_ref_borrow() -> i32 { + // CHECK: ret i32 6 + _slice_ref(&[0; 3]) +} + +// CHECK-LABEL: @_slice_ref_arg( +#[no_mangle] +pub fn _slice_ref_arg(a: &[u8]) -> i32 { + // CHECK: ret i32 6 + _slice_ref(a) +} + +#[inline] +pub fn _f16(a: f16) -> i32 { + if is_val_statically_known(a) { 1 } else { 0 } +} + +// CHECK-LABEL: @_f16_true( +#[no_mangle] +pub fn _f16_true() -> i32 { + // CHECK: ret i32 1 + _f16(1.0) +} + +// CHECK-LABEL: @_f16_false( +#[no_mangle] +pub fn _f16_false(a: f16) -> i32 { + // CHECK: ret i32 0 + _f16(a) +} + +#[inline] +pub fn _f32(a: f32) -> i32 { + if is_val_statically_known(a) { 1 } else { 0 } +} + +// CHECK-LABEL: @_f32_true( +#[no_mangle] +pub fn _f32_true() -> i32 { + // CHECK: ret i32 1 + _f32(1.0) +} + +// CHECK-LABEL: @_f32_false( +#[no_mangle] +pub fn _f32_false(a: f32) -> i32 { + // CHECK: ret i32 0 + _f32(a) +} + +#[inline] +pub fn _f64(a: f64) -> i32 { + if is_val_statically_known(a) { 1 } else { 0 } +} + +// CHECK-LABEL: @_f64_true( +#[no_mangle] +pub fn _f64_true() -> i32 { + // CHECK: ret i32 1 + _f64(1.0) +} + +// CHECK-LABEL: @_f64_false( +#[no_mangle] +pub fn _f64_false(a: f64) -> i32 { + // CHECK: ret i32 0 + _f64(a) +} + +#[inline] +pub fn _f128(a: f128) -> i32 { + if is_val_statically_known(a) { 1 } else { 0 } +} + +// CHECK-LABEL: @_f128_true( +#[no_mangle] +pub fn _f128_true() -> i32 { + // CHECK: ret i32 1 + _f128(1.0) +} + +// CHECK-LABEL: @_f128_false( +#[no_mangle] +pub fn _f128_false(a: f128) -> i32 { + // CHECK: ret i32 0 + _f128(a) +} diff --git a/tests/codegen-llvm/issue-97217.rs b/tests/codegen-llvm/issue-97217.rs new file mode 100644 index 00000000000..ef9acc5fc93 --- /dev/null +++ b/tests/codegen-llvm/issue-97217.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -C opt-level=3 +#![crate_type = "lib"] + +// Regression test for issue 97217 (the following should result in no allocations) + +// CHECK-LABEL: @issue97217 +#[no_mangle] +pub fn issue97217() -> i32 { + // drop_in_place should be inlined and never appear + // CHECK-NOT: drop_in_place + + // __rust_alloc should be optimized out + // CHECK-NOT: __rust_alloc + + let v1 = vec![5, 6, 7]; + let v1_iter = v1.iter(); + let total: i32 = v1_iter.sum(); + println!("{}", total); + total +} diff --git a/tests/codegen-llvm/issues/issue-101048.rs b/tests/codegen-llvm/issues/issue-101048.rs new file mode 100644 index 00000000000..cfe65e758fd --- /dev/null +++ b/tests/codegen-llvm/issues/issue-101048.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn all_zero(data: &[u64]) -> bool { + // CHECK-LABEL: @all_zero( + // CHECK: [[PHI:%.*]] = phi i1 + // CHECK-NOT: phi i8 + // CHECK-NOT: zext + data.iter().copied().fold(true, |acc, x| acc & (x == 0)) +} diff --git a/tests/codegen-llvm/issues/issue-101082.rs b/tests/codegen-llvm/issues/issue-101082.rs new file mode 100644 index 00000000000..8d15921ddb4 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-101082.rs @@ -0,0 +1,42 @@ +//@ compile-flags: -Copt-level=3 +//@ revisions: host x86-64 x86-64-v3 +//@ min-llvm-version: 20 + +//@[host] ignore-x86_64 + +// Set the base cpu explicitly, in case the default has been changed. +//@[x86-64] only-x86_64 +//@[x86-64] compile-flags: -Ctarget-cpu=x86-64 + +// FIXME(cuviper) x86-64-v3 in particular regressed in #131563, and the workaround +// at the time still sometimes fails, so only verify it for the power-of-two size +// - https://github.com/llvm/llvm-project/issues/134735 +//@[x86-64-v3] only-x86_64 +//@[x86-64-v3] min-llvm-version: 21 +//@[x86-64-v3] compile-flags: -Ctarget-cpu=x86-64-v3 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test() -> usize { + // CHECK-LABEL: @test( + // CHECK: ret {{i64|i32}} 165 + let values = [23, 16, 54, 3, 60, 9]; + let mut acc = 0; + for item in values { + acc += item; + } + acc +} + +#[no_mangle] +pub fn test_eight() -> usize { + // CHECK-LABEL: @test_eight( + // CHECK: ret {{i64|i32}} 220 + let values = [23, 16, 54, 3, 60, 9, 13, 42]; + let mut acc = 0; + for item in values { + acc += item; + } + acc +} diff --git a/tests/codegen-llvm/issues/issue-101814.rs b/tests/codegen-llvm/issues/issue-101814.rs new file mode 100644 index 00000000000..668ec8476e8 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-101814.rs @@ -0,0 +1,18 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test(a: [i32; 10]) -> i32 { + // CHECK-LABEL: @test( + // CHECK: [[L1:%.+]] = load i32 + // CHECK: [[L2:%.+]] = load i32 + // CHECK: [[R:%.+]] = add i32 [[L1]], [[L2]] + // CHECK: ret i32 [[R]] + let mut sum = 0; + for v in a.iter().skip(8) { + sum += v; + } + + sum +} diff --git a/tests/codegen-llvm/issues/issue-103132.rs b/tests/codegen-llvm/issues/issue-103132.rs new file mode 100644 index 00000000000..623cab92806 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-103132.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Copt-level=3 -C overflow-checks + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test(arr: &[u8], weight: u32) { + // CHECK-LABEL: @test( + // CHECK-NOT: panic + let weight = weight.min(256 * 256 * 256); + + for x in arr { + assert!(weight <= 256 * 256 * 256); + let result = *x as u32 * weight; + } +} diff --git a/tests/codegen-llvm/issues/issue-103285-ptr-addr-overflow-check.rs b/tests/codegen-llvm/issues/issue-103285-ptr-addr-overflow-check.rs new file mode 100644 index 00000000000..3ada5412e83 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-103285-ptr-addr-overflow-check.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Copt-level=3 -C debug-assertions=yes + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test(src: *const u8, dst: *const u8) -> usize { + // CHECK-LABEL: @test( + // CHECK-NOT: panic + let src_usize = src.addr(); + let dst_usize = dst.addr(); + if src_usize > dst_usize { + return src_usize - dst_usize; + } + return 0; +} diff --git a/tests/codegen-llvm/issues/issue-103327.rs b/tests/codegen-llvm/issues/issue-103327.rs new file mode 100644 index 00000000000..4de3cfd12a0 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-103327.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test(a: i32, b: i32) -> bool { + // CHECK-LABEL: @test( + // CHECK: ret i1 true + let c1 = (a >= 0) && (a <= 10); + let c2 = (b >= 0) && (b <= 20); + + if c1 & c2 { a + 100 != b } else { true } +} diff --git a/tests/codegen-llvm/issues/issue-103840.rs b/tests/codegen-llvm/issues/issue-103840.rs new file mode 100644 index 00000000000..c6c5098bdd0 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-103840.rs @@ -0,0 +1,9 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +pub fn foo(t: &mut Vec) { + // CHECK-NOT: __rust_dealloc + let mut taken = std::mem::take(t); + taken.pop(); + *t = taken; +} diff --git a/tests/codegen-llvm/issues/issue-105386-ub-in-debuginfo.rs b/tests/codegen-llvm/issues/issue-105386-ub-in-debuginfo.rs new file mode 100644 index 00000000000..848aa910b58 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-105386-ub-in-debuginfo.rs @@ -0,0 +1,24 @@ +//@ compile-flags: --crate-type=lib -Copt-level=3 -Cdebuginfo=2 -Cno-prepopulate-passes -Zmir-enable-passes=-ScalarReplacementOfAggregates +// MIR SROA will decompose the closure +#![feature(stmt_expr_attributes)] + +pub struct S([usize; 8]); + +#[no_mangle] +pub fn outer_function(x: S, y: S) -> usize { + (#[inline(always)] + || { + let _z = x; + y.0[0] + })() +} + +// Check that we do not attempt to load from the spilled arg before it is assigned to +// when generating debuginfo. +// CHECK-LABEL: @outer_function +// CHECK: [[spill:%.*]] = alloca +// CHECK-NOT: [[ptr_tmp:%.*]] = getelementptr inbounds i8, ptr [[spill]] +// CHECK-NOT: [[load:%.*]] = load ptr, ptr +// CHECK: call void @llvm.lifetime.start{{.*}}({{.*}}, ptr [[spill]]) +// CHECK: [[inner:%.*]] = getelementptr inbounds i8, ptr [[spill]] +// CHECK: call void @llvm.memcpy{{.*}}(ptr {{align .*}} [[inner]], ptr {{align .*}} %x diff --git a/tests/codegen-llvm/issues/issue-106369.rs b/tests/codegen-llvm/issues/issue-106369.rs new file mode 100644 index 00000000000..3583d20c9fa --- /dev/null +++ b/tests/codegen-llvm/issues/issue-106369.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// From + +// CHECK-LABEL: @issue_106369( +#[no_mangle] +pub unsafe fn issue_106369(ptr: *const &i32) -> bool { + // CHECK-NOT: icmp + // CHECK: ret i1 true + // CHECK-NOT: icmp + Some(std::ptr::read(ptr)).is_some() +} diff --git a/tests/codegen-llvm/issues/issue-107681-unwrap_unchecked.rs b/tests/codegen-llvm/issues/issue-107681-unwrap_unchecked.rs new file mode 100644 index 00000000000..69aefc6b1fb --- /dev/null +++ b/tests/codegen-llvm/issues/issue-107681-unwrap_unchecked.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -Copt-level=3 + +// Test for #107681. +// Make sure we don't create `br` or `select` instructions. + +#![crate_type = "lib"] + +use std::iter::Copied; +use std::slice::Iter; + +#[no_mangle] +pub unsafe fn foo(x: &mut Copied>) -> u32 { + // CHECK-LABEL: @foo( + // CHECK-NOT: br + // CHECK-NOT: select + // CHECK: [[RET:%.*]] = load i32, ptr + // CHECK-NEXT: ret i32 [[RET]] + x.next().unwrap_unchecked() +} diff --git a/tests/codegen-llvm/issues/issue-108395-branchy-bool-match.rs b/tests/codegen-llvm/issues/issue-108395-branchy-bool-match.rs new file mode 100644 index 00000000000..96387e791b0 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-108395-branchy-bool-match.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled +//! Test for . Check that +//! matching on two bools with wildcards does not produce branches. +#![crate_type = "lib"] + +// CHECK-LABEL: @wildcard( +#[no_mangle] +pub fn wildcard(a: u16, b: u16, v: u16) -> u16 { + // CHECK-NOT: br + match (a == v, b == v) { + (true, false) => 0, + (false, true) => u16::MAX, + _ => 1 << 15, // half + } +} + +// CHECK-LABEL: @exhaustive( +#[no_mangle] +pub fn exhaustive(a: u16, b: u16, v: u16) -> u16 { + // CHECK-NOT: br + match (a == v, b == v) { + (true, false) => 0, + (false, true) => u16::MAX, + (true, true) => 1 << 15, + (false, false) => 1 << 15, + } +} diff --git a/tests/codegen-llvm/issues/issue-109328-split_first.rs b/tests/codegen-llvm/issues/issue-109328-split_first.rs new file mode 100644 index 00000000000..26235edfc19 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-109328-split_first.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @foo +// CHECK-NEXT: {{.*}}: +// CHECK-NEXT: getelementptr inbounds +// CHECK-NEXT: load [[TYPE:i(32|64)]] +// CHECK-NEXT: icmp eq [[TYPE]] +// CHECK-NEXT: br i1 +#[no_mangle] +pub fn foo(input: &mut &[u64]) -> Option { + let (first, rest) = input.split_first()?; + *input = rest; + Some(*first) +} diff --git a/tests/codegen-llvm/issues/issue-110797-enum-jump-same.rs b/tests/codegen-llvm/issues/issue-110797-enum-jump-same.rs new file mode 100644 index 00000000000..b5f7c08795b --- /dev/null +++ b/tests/codegen-llvm/issues/issue-110797-enum-jump-same.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +pub enum K { + A(Box<[i32]>), + B(Box<[u8]>), + C(Box<[String]>), + D(Box<[u16]>), +} + +// CHECK-LABEL: @get_len +// CHECK-NEXT: {{.*}}: +// CHECK-NEXT: getelementptr inbounds +// CHECK-NEXT: load [[TYPE:i(32|64)]] +// CHECK-NEXT: ret [[TYPE]] +#[no_mangle] +pub fn get_len(arg: &K) -> usize { + match arg { + K::A(ref lst) => lst.len(), + K::B(ref lst) => lst.len(), + K::C(ref lst) => lst.len(), + K::D(ref lst) => lst.len(), + } +} diff --git a/tests/codegen-llvm/issues/issue-111603.rs b/tests/codegen-llvm/issues/issue-111603.rs new file mode 100644 index 00000000000..2ba5a3f876a --- /dev/null +++ b/tests/codegen-llvm/issues/issue-111603.rs @@ -0,0 +1,40 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] +#![feature(get_mut_unchecked, new_uninit)] + +use std::sync::Arc; + +// CHECK-LABEL: @new_from_array +#[no_mangle] +pub fn new_from_array(x: u64) -> Arc<[u64]> { + // Ensure that we only generate one alloca for the array. + + // CHECK: alloca + // CHECK-SAME: [8000 x i8] + // CHECK-NOT: alloca + let array = [x; 1000]; + Arc::new(array) +} + +// CHECK-LABEL: @new_uninit +#[no_mangle] +pub fn new_uninit(x: u64) -> Arc<[u64; 1000]> { + // CHECK: call alloc::sync::arcinner_layout_for_value_layout + // CHECK-NOT: call alloc::sync::arcinner_layout_for_value_layout + let mut arc = Arc::new_uninit(); + unsafe { Arc::get_mut_unchecked(&mut arc) }.write([x; 1000]); + unsafe { arc.assume_init() } +} + +// CHECK-LABEL: @new_uninit_slice +#[no_mangle] +pub fn new_uninit_slice(x: u64) -> Arc<[u64]> { + // CHECK: call alloc::sync::arcinner_layout_for_value_layout + // CHECK-NOT: call alloc::sync::arcinner_layout_for_value_layout + let mut arc = Arc::new_uninit_slice(1000); + for elem in unsafe { Arc::get_mut_unchecked(&mut arc) } { + elem.write(x); + } + unsafe { arc.assume_init() } +} diff --git a/tests/codegen-llvm/issues/issue-112509-slice-get-andthen-get.rs b/tests/codegen-llvm/issues/issue-112509-slice-get-andthen-get.rs new file mode 100644 index 00000000000..3909b203d08 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-112509-slice-get-andthen-get.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +// CHECK-LABEL: @write_u8_variant_a +// CHECK-NEXT: {{.*}}: +// CHECK-NEXT: icmp ugt +// CHECK-NEXT: getelementptr +// CHECK-NEXT: select i1 {{.+}} null +// CHECK-NEXT: insertvalue +// CHECK-NEXT: insertvalue +// CHECK-NEXT: ret +#[no_mangle] +pub fn write_u8_variant_a(bytes: &mut [u8], buf: u8, offset: usize) -> Option<&mut [u8]> { + let buf = buf.to_le_bytes(); + bytes.get_mut(offset..).and_then(|bytes| bytes.get_mut(..buf.len())) +} diff --git a/tests/codegen-llvm/issues/issue-113757-bounds-check-after-cmp-max.rs b/tests/codegen-llvm/issues/issue-113757-bounds-check-after-cmp-max.rs new file mode 100644 index 00000000000..d495adf9980 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-113757-bounds-check-after-cmp-max.rs @@ -0,0 +1,18 @@ +// in Rust 1.73, -O and opt-level=3 optimizes differently +//@ compile-flags: -C opt-level=3 +#![crate_type = "lib"] + +use std::cmp::max; + +// CHECK-LABEL: @foo +// CHECK-NOT: slice_start_index_len_fail +// CHECK-NOT: unreachable +#[no_mangle] +pub fn foo(v: &mut Vec, size: usize) -> Option<&mut [u8]> { + if v.len() > max(1, size) { + let start = v.len() - size; + Some(&mut v[start..]) + } else { + None + } +} diff --git a/tests/codegen-llvm/issues/issue-114312.rs b/tests/codegen-llvm/issues/issue-114312.rs new file mode 100644 index 00000000000..61355dd5873 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-114312.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64-unknown-linux-gnu + +// We want to check that this function does not mis-optimize to loop jumping. + +#![crate_type = "lib"] + +#[repr(C)] +pub enum Expr { + Sum, + // must have more than usize data + Sub(usize, u8), +} + +#[no_mangle] +pub extern "C" fn issue_114312(expr: Expr) { + // CHECK-LABEL: @issue_114312( + // CHECK-SAME: byval + // CHECK-NEXT: start: + // CHECK-NEXT: ret void + match expr { + Expr::Sum => {} + Expr::Sub(_, _) => issue_114312(Expr::Sum), + } +} diff --git a/tests/codegen-llvm/issues/issue-115385-llvm-jump-threading.rs b/tests/codegen-llvm/issues/issue-115385-llvm-jump-threading.rs new file mode 100644 index 00000000000..8cabd94f202 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-115385-llvm-jump-threading.rs @@ -0,0 +1,46 @@ +//@ compile-flags: -Copt-level=3 -Ccodegen-units=1 + +#![crate_type = "lib"] + +#[repr(i64)] +pub enum Boolean { + False = 0, + True = 1, +} + +impl Clone for Boolean { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for Boolean {} + +extern "C" { + fn set_value(foo: *mut i64); + fn bar(); +} + +pub fn foo(x: bool) { + let mut foo = core::mem::MaybeUninit::::uninit(); + unsafe { + set_value(foo.as_mut_ptr()); + } + + if x { + let l1 = unsafe { *foo.as_mut_ptr().cast::() }; + if matches!(l1, Boolean::False) { + unsafe { + *foo.as_mut_ptr() = 0; + } + } + } + + let l2 = unsafe { *foo.as_mut_ptr() }; + if l2 == 2 { + // CHECK: call void @bar + unsafe { + bar(); + } + } +} diff --git a/tests/codegen-llvm/issues/issue-116878.rs b/tests/codegen-llvm/issues/issue-116878.rs new file mode 100644 index 00000000000..daf46c8bb55 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-116878.rs @@ -0,0 +1,11 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +/// Make sure no bounds checks are emitted after a `get_unchecked`. +// CHECK-LABEL: @unchecked_slice_no_bounds_check +#[no_mangle] +pub unsafe fn unchecked_slice_no_bounds_check(s: &[u8]) -> u8 { + let a = *s.get_unchecked(1); + // CHECK-NOT: panic_bounds_check + a + s[0] +} diff --git a/tests/codegen-llvm/issues/issue-118306.rs b/tests/codegen-llvm/issues/issue-118306.rs new file mode 100644 index 00000000000..f12dc7cdfe2 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-118306.rs @@ -0,0 +1,22 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 + +// Test for #118306. +// Make sure we don't create `br` or `select` instructions. + +#![crate_type = "lib"] + +#[no_mangle] +pub fn branchy(input: u64) -> u64 { + // CHECK-LABEL: @branchy( + // CHECK-NEXT: start: + // CHECK-NEXT: [[_2:%.*]] = and i64 [[INPUT:%.*]], 3 + // CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds{{( nuw)?}} [4 x i64], ptr @switch.table.branchy, i64 0, i64 [[_2]] + // CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i64, ptr [[SWITCH_GEP]] + // CHECK-NEXT: ret i64 [[SWITCH_LOAD]] + match input % 4 { + 1 | 2 => 1, + 3 => 2, + _ => 0, + } +} diff --git a/tests/codegen-llvm/issues/issue-118392.rs b/tests/codegen-llvm/issues/issue-118392.rs new file mode 100644 index 00000000000..07de8d9b237 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-118392.rs @@ -0,0 +1,10 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +// CHECK-LABEL: @div2 +// CHECK: ashr i32 %a, 1 +// CHECK-NEXT: ret i32 +#[no_mangle] +pub fn div2(a: i32) -> i32 { + a.div_euclid(2) +} diff --git a/tests/codegen-llvm/issues/issue-119422.rs b/tests/codegen-llvm/issues/issue-119422.rs new file mode 100644 index 00000000000..17ae71605b5 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-119422.rs @@ -0,0 +1,83 @@ +//! This test checks that compiler don't generate useless compares to zeros +//! for `NonZero` integer types. +//! +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled +//@ edition: 2021 +//@ only-64bit (because the LLVM type of i64 for usize shows up) +#![crate_type = "lib"] + +use core::num::NonZero; +use core::ptr::NonNull; + +// CHECK-LABEL: @check_non_null +#[no_mangle] +pub fn check_non_null(x: NonNull) -> bool { + // CHECK: ret i1 false + x.as_ptr().is_null() +} + +// CHECK-LABEL: @equals_zero_is_false_u8 +#[no_mangle] +pub fn equals_zero_is_false_u8(x: NonZero) -> bool { + // CHECK-NOT: br + // CHECK: ret i1 false + // CHECK-NOT: br + x.get() == 0 +} + +// CHECK-LABEL: @not_equals_zero_is_true_u8 +#[no_mangle] +pub fn not_equals_zero_is_true_u8(x: NonZero) -> bool { + // CHECK-NOT: br + // CHECK: ret i1 true + // CHECK-NOT: br + x.get() != 0 +} + +// CHECK-LABEL: @equals_zero_is_false_i8 +#[no_mangle] +pub fn equals_zero_is_false_i8(x: NonZero) -> bool { + // CHECK-NOT: br + // CHECK: ret i1 false + // CHECK-NOT: br + x.get() == 0 +} + +// CHECK-LABEL: @not_equals_zero_is_true_i8 +#[no_mangle] +pub fn not_equals_zero_is_true_i8(x: NonZero) -> bool { + // CHECK-NOT: br + // CHECK: ret i1 true + // CHECK-NOT: br + x.get() != 0 +} + +// CHECK-LABEL: @usize_try_from_u32 +#[no_mangle] +pub fn usize_try_from_u32(x: NonZero) -> NonZero { + // CHECK-NOT: br + // CHECK: zext i32 %{{.*}} to i64 + // CHECK-NOT: br + // CHECK: ret i64 + x.try_into().unwrap() +} + +// CHECK-LABEL: @isize_try_from_i32 +#[no_mangle] +pub fn isize_try_from_i32(x: NonZero) -> NonZero { + // CHECK-NOT: br + // CHECK: sext i32 %{{.*}} to i64 + // CHECK-NOT: br + // CHECK: ret i64 + x.try_into().unwrap() +} + +// CHECK-LABEL: @u64_from_nonzero_is_not_zero +#[no_mangle] +pub fn u64_from_nonzero_is_not_zero(x: NonZero) -> bool { + // CHECK-NOT: br + // CHECK: ret i1 false + // CHECK-NOT: br + let v: u64 = x.into(); + v == 0 +} diff --git a/tests/codegen-llvm/issues/issue-121719-common-field-offset.rs b/tests/codegen-llvm/issues/issue-121719-common-field-offset.rs new file mode 100644 index 00000000000..9f5f44e0375 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-121719-common-field-offset.rs @@ -0,0 +1,44 @@ +//! This test checks that match branches which all access a field +//! at the same offset are merged together. +//! +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +#[repr(C)] +pub struct A { + x: f64, + y: u64, +} +#[repr(C)] +pub struct B { + x: f64, + y: u32, +} +#[repr(C)] +pub struct C { + x: f64, + y: u16, +} +#[repr(C)] +pub struct D { + x: f64, + y: u8, +} + +pub enum E { + A(A), + B(B), + C(C), + D(D), +} + +// CHECK-LABEL: @match_on_e +#[no_mangle] +pub fn match_on_e(e: &E) -> &f64 { + // CHECK: start: + // CHECK-NEXT: getelementptr + // CHECK-NEXT: ret + match e { + E::A(A { x, .. }) | E::B(B { x, .. }) | E::C(C { x, .. }) | E::D(D { x, .. }) => x, + } +} diff --git a/tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs b/tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs new file mode 100644 index 00000000000..853a1ff36b1 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs @@ -0,0 +1,43 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// The bug here was that it was loading and storing the whole value. +// It's ok for it to load the discriminant, +// to preserve the UB from `unreachable_unchecked`, +// but it better only store the constant discriminant of `B`. + +pub enum State { + A([u8; 753]), + B([u8; 753]), +} + +// CHECK-LABEL: @update +#[no_mangle] +pub unsafe fn update(s: *mut State) { + // CHECK-NOT: alloca + + // CHECK-NOT: load + // CHECK-NOT: store + // CHECK-NOT: memcpy + // CHECK-NOT: 75{{3|4}} + + // CHECK: %[[TAG:.+]] = load i8, ptr %s, align 1 + // CHECK-NEXT: trunc nuw i8 %[[TAG]] to i1 + + // CHECK-NOT: load + // CHECK-NOT: store + // CHECK-NOT: memcpy + // CHECK-NOT: 75{{3|4}} + + // CHECK: store i8 1, ptr %s, align 1 + + // CHECK-NOT: load + // CHECK-NOT: store + // CHECK-NOT: memcpy + // CHECK-NOT: 75{{3|4}} + + // CHECK: ret + let State::A(v) = s.read() else { std::hint::unreachable_unchecked() }; + s.write(State::B(v)); +} diff --git a/tests/codegen-llvm/issues/issue-123712-str-to-lower-autovectorization.rs b/tests/codegen-llvm/issues/issue-123712-str-to-lower-autovectorization.rs new file mode 100644 index 00000000000..11ee10e8cc3 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-123712-str-to-lower-autovectorization.rs @@ -0,0 +1,23 @@ +//@ only-x86_64 +//@ compile-flags: -C opt-level=3 +#![crate_type = "lib"] +#![no_std] +#![feature(str_internals)] + +extern crate alloc; + +/// Ensure that the ascii-prefix loop for `str::to_lowercase` and `str::to_uppercase` uses vector +/// instructions. +/// +/// The llvm ir should be the same for all targets that support some form of simd. Only targets +/// without any simd instructions would see scalarized ir. +/// Unfortunately, there is no `only-simd` directive to only run this test on only such platforms, +/// and using test revisions would still require the core libraries for all platforms. +// CHECK-LABEL: @lower_while_ascii +// CHECK: [[A:%[0-9]]] = load <16 x i8> +// CHECK-NEXT: [[B:%[0-9]]] = icmp slt <16 x i8> [[A]], zeroinitializer +// CHECK-NEXT: [[C:%[0-9]]] = bitcast <16 x i1> [[B]] to i16 +#[no_mangle] +pub fn lower_while_ascii(s: &str) -> (alloc::string::String, &str) { + alloc::str::convert_while_ascii(s, u8::to_ascii_lowercase) +} diff --git a/tests/codegen-llvm/issues/issue-126585.rs b/tests/codegen-llvm/issues/issue-126585.rs new file mode 100644 index 00000000000..466dab64cdc --- /dev/null +++ b/tests/codegen-llvm/issues/issue-126585.rs @@ -0,0 +1,23 @@ +//@ compile-flags: -Copt-level=s +//@ only-x86_64 + +// Test for #126585. +// Ensure that this IR doesn't have extra undef phi input, which also guarantees that this asm +// doesn't have subsequent labels and unnecessary `jmp` instructions. + +#![crate_type = "lib"] + +#[no_mangle] +fn checked_div_round(a: u64, b: u64) -> Option { + // CHECK-LABEL: @checked_div_round + // CHECK: phi + // CHECK-NOT: undef + // CHECK: phi + // CHECK-NOT: undef + match b { + 0 => None, + 1 => Some(a), + // `a / b` is computable and `(a % b) * 2` can not overflow since `b >= 2`. + b => Some(a / b + if (a % b) * 2 >= b { 1 } else { 0 }), + } +} diff --git a/tests/codegen-llvm/issues/issue-129795.rs b/tests/codegen-llvm/issues/issue-129795.rs new file mode 100644 index 00000000000..dc64ee35c97 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-129795.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Copt-level=3 +//@ min-llvm-version: 20 +#![crate_type = "lib"] + +// Ensure that a modulo operation with an operand that is known to be +// a power-of-two is properly optimized. + +// CHECK-LABEL: @modulo_with_power_of_two_divisor +// CHECK: add i64 %divisor, -1 +// CHECK-NEXT: and i64 +// CHECK-NEXT: ret i64 +#[no_mangle] +pub fn modulo_with_power_of_two_divisor(dividend: u64, divisor: u64) -> u64 { + assert!(divisor.is_power_of_two()); + // should be optimized to (dividend & (divisor - 1)) + dividend % divisor +} diff --git a/tests/codegen-llvm/issues/issue-13018.rs b/tests/codegen-llvm/issues/issue-13018.rs new file mode 100644 index 00000000000..8040018b931 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-13018.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Copt-level=3 + +// A drop([...].clone()) sequence on an Rc should be a no-op +// In particular, no call to __rust_dealloc should be emitted +// +// We use a cdylib since it's a leaf unit for Rust purposes, so doesn't codegen -Zshare-generics +// code. +#![crate_type = "cdylib"] +use std::rc::Rc; + +pub fn foo(t: &Rc>) { + // CHECK-NOT: __rust_dealloc + drop(t.clone()); +} diff --git a/tests/codegen-llvm/issues/issue-136329-optnone-noinline.rs b/tests/codegen-llvm/issues/issue-136329-optnone-noinline.rs new file mode 100644 index 00000000000..57c9e47a499 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-136329-optnone-noinline.rs @@ -0,0 +1,21 @@ +//! Ensure that `#[optimize(none)]` functions are never inlined + +//@ compile-flags: -Copt-level=3 + +#![feature(optimize_attribute)] + +#[optimize(none)] +pub fn foo() { + let _x = 123; +} + +// CHECK-LABEL: define{{.*}}void @bar +// CHECK: start: +// CHECK: {{.*}}call {{.*}}void +// CHECK: ret void +#[no_mangle] +pub fn bar() { + foo(); +} + +fn main() {} diff --git a/tests/codegen-llvm/issues/issue-15953.rs b/tests/codegen-llvm/issues/issue-15953.rs new file mode 100644 index 00000000000..70e597ac1dd --- /dev/null +++ b/tests/codegen-llvm/issues/issue-15953.rs @@ -0,0 +1,29 @@ +// Test that llvm generates `memcpy` for moving a value +// inside a function and moving an argument. + +struct Foo { + x: Vec, +} + +#[inline(never)] +#[no_mangle] +// CHECK: memcpy +fn interior(x: Vec) -> Vec { + let Foo { x } = Foo { x }; + x +} + +#[inline(never)] +#[no_mangle] +// CHECK: memcpy +fn exterior(x: Vec) -> Vec { + x +} + +fn main() { + let x = interior(Vec::new()); + println!("{:?}", x); + + let x = exterior(Vec::new()); + println!("{:?}", x); +} diff --git a/tests/codegen-llvm/issues/issue-27130.rs b/tests/codegen-llvm/issues/issue-27130.rs new file mode 100644 index 00000000000..594e02af097 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-27130.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @trim_in_place +#[no_mangle] +pub fn trim_in_place(a: &mut &[u8]) { + while a.first() == Some(&42) { + // CHECK-NOT: slice_index_order_fail + *a = &a[1..]; + } +} + +// CHECK-LABEL: @trim_in_place2 +#[no_mangle] +pub fn trim_in_place2(a: &mut &[u8]) { + while let Some(&42) = a.first() { + // CHECK-NOT: slice_index_order_fail + *a = &a[2..]; + } +} diff --git a/tests/codegen-llvm/issues/issue-32031.rs b/tests/codegen-llvm/issues/issue-32031.rs new file mode 100644 index 00000000000..559e8d947fb --- /dev/null +++ b/tests/codegen-llvm/issues/issue-32031.rs @@ -0,0 +1,29 @@ +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 +// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack. +//@ revisions: x86 other +//@[x86] only-rustc_abi-x86-sse2 +//@[other] ignore-x86 + +#![crate_type = "lib"] + +#[no_mangle] +pub struct F32(f32); + +// other: define{{.*}}float @add_newtype_f32(float %a, float %b) +// x86: define{{.*}}<4 x i8> @add_newtype_f32(float %a, float %b) +#[inline(never)] +#[no_mangle] +pub fn add_newtype_f32(a: F32, b: F32) -> F32 { + F32(a.0 + b.0) +} + +#[no_mangle] +pub struct F64(f64); + +// other: define{{.*}}double @add_newtype_f64(double %a, double %b) +// x86: define{{.*}}<8 x i8> @add_newtype_f64(double %a, double %b) +#[inline(never)] +#[no_mangle] +pub fn add_newtype_f64(a: F64, b: F64) -> F64 { + F64(a.0 + b.0) +} diff --git a/tests/codegen-llvm/issues/issue-32364.rs b/tests/codegen-llvm/issues/issue-32364.rs new file mode 100644 index 00000000000..016981d1947 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-32364.rs @@ -0,0 +1,17 @@ +// Test that `extern "stdcall"` is properly translated. + +//@ only-x86 + +//@ compile-flags: -C no-prepopulate-passes + +struct Foo; + +impl Foo { + // CHECK: define internal x86_stdcallcc void @{{.*}}foo{{.*}}() + #[inline(never)] + pub extern "stdcall" fn foo() {} +} + +fn main() { + Foo::foo::(); +} diff --git a/tests/codegen-llvm/issues/issue-34634.rs b/tests/codegen-llvm/issues/issue-34634.rs new file mode 100644 index 00000000000..d32fa97ec38 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-34634.rs @@ -0,0 +1,16 @@ +// Test that `wrapping_div` only checks divisor once. +// This test checks that there is only a single compare against -1 and -1 is not present as a +// switch case (the second check present until rustc 1.12). +// This test also verifies that a single panic call is generated (for the division by zero case). + +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +// CHECK-LABEL: @f +#[no_mangle] +pub fn f(x: i32, y: i32) -> i32 { + // CHECK-COUNT-1: icmp eq i32 %y, -1 + // CHECK-COUNT-1: panic + // CHECK-NOT: i32 -1, label + x.wrapping_div(y) +} diff --git a/tests/codegen-llvm/issues/issue-34947-pow-i32.rs b/tests/codegen-llvm/issues/issue-34947-pow-i32.rs new file mode 100644 index 00000000000..b4750cd35bc --- /dev/null +++ b/tests/codegen-llvm/issues/issue-34947-pow-i32.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @issue_34947 +#[no_mangle] +pub fn issue_34947(x: i32) -> i32 { + // CHECK: mul + // CHECK-NEXT: mul + // CHECK-NEXT: mul + // CHECK-NEXT: ret + x.pow(5) +} diff --git a/tests/codegen-llvm/issues/issue-36010-some-box-is_some.rs b/tests/codegen-llvm/issues/issue-36010-some-box-is_some.rs new file mode 100644 index 00000000000..c9a8262162d --- /dev/null +++ b/tests/codegen-llvm/issues/issue-36010-some-box-is_some.rs @@ -0,0 +1,28 @@ +#![crate_type = "lib"] + +//@ compile-flags: -Copt-level=3 + +use std::mem; + +fn foo(a: &mut T, b: T) -> bool { + let b = Some(mem::replace(a, b)); + let ret = b.is_some(); + mem::forget(b); + return ret; +} + +// CHECK-LABEL: @foo_u32 +// CHECK: store i32 +// CHECK-NEXT: ret i1 true +#[no_mangle] +pub fn foo_u32(a: &mut u32, b: u32) -> bool { + foo(a, b) +} + +// CHECK-LABEL: @foo_box +// CHECK: store ptr +// CHECK-NEXT: ret i1 true +#[no_mangle] +pub fn foo_box(a: &mut Box, b: Box) -> bool { + foo(a, b) +} diff --git a/tests/codegen-llvm/issues/issue-37945.rs b/tests/codegen-llvm/issues/issue-37945.rs new file mode 100644 index 00000000000..23d0eab8ae4 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-37945.rs @@ -0,0 +1,34 @@ +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled +//@ ignore-32bit LLVM has a bug with them + +// Check that LLVM understands that `Iter` pointer is not null. Issue #37945. + +#![crate_type = "lib"] + +use std::slice::Iter; + +#[no_mangle] +pub fn is_empty_1(xs: Iter) -> bool { + // CHECK-LABEL: @is_empty_1( + // CHECK-NEXT: start: + // CHECK-NEXT: [[A:%.*]] = icmp ne ptr {{%xs.0|%xs.1}}, null + // CHECK-NEXT: tail call void @llvm.assume(i1 [[A]]) + // The order between %xs.0 and %xs.1 on the next line doesn't matter + // and different LLVM versions produce different order. + // CHECK-NEXT: [[B:%.*]] = icmp eq ptr {{%xs.0, %xs.1|%xs.1, %xs.0}} + // CHECK-NEXT: ret i1 [[B:%.*]] + { xs }.next().is_none() +} + +#[no_mangle] +pub fn is_empty_2(xs: Iter) -> bool { + // CHECK-LABEL: @is_empty_2 + // CHECK-NEXT: start: + // CHECK-NEXT: [[C:%.*]] = icmp ne ptr {{%xs.0|%xs.1}}, null + // CHECK-NEXT: tail call void @llvm.assume(i1 [[C]]) + // The order between %xs.0 and %xs.1 on the next line doesn't matter + // and different LLVM versions produce different order. + // CHECK-NEXT: [[D:%.*]] = icmp eq ptr {{%xs.0, %xs.1|%xs.1, %xs.0}} + // CHECK-NEXT: ret i1 [[D:%.*]] + xs.map(|&x| x).next().is_none() +} diff --git a/tests/codegen-llvm/issues/issue-45222.rs b/tests/codegen-llvm/issues/issue-45222.rs new file mode 100644 index 00000000000..0201363c41a --- /dev/null +++ b/tests/codegen-llvm/issues/issue-45222.rs @@ -0,0 +1,62 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// verify that LLVM recognizes a loop involving 0..=n and will const-fold it. + +// Example from original issue #45222 + +fn foo2(n: u64) -> u64 { + let mut count = 0; + for _ in 0..n { + for j in (0..=n).rev() { + count += j; + } + } + count +} + +// CHECK-LABEL: @check_foo2 +#[no_mangle] +pub fn check_foo2() -> u64 { + // CHECK: ret i64 500005000000000 + foo2(100000) +} + +// Simplified example of #45222 +// +// Temporarily disabled in #68835 to fix a soundness hole. +// +// fn triangle_inc(n: u64) -> u64 { +// let mut count = 0; +// for j in 0 ..= n { +// count += j; +// } +// count +// } +// +// // COMMENTEDCHECK-LABEL: @check_triangle_inc +// #[no_mangle] +// pub fn check_triangle_inc() -> u64 { +// // COMMENTEDCHECK: ret i64 5000050000 +// triangle_inc(100000) +// } + +// Demo in #48012 + +fn foo3r(n: u64) -> u64 { + let mut count = 0; + (0..n).for_each(|_| { + (0..=n).rev().for_each(|j| { + count += j; + }) + }); + count +} + +// CHECK-LABEL: @check_foo3r +#[no_mangle] +pub fn check_foo3r() -> u64 { + // CHECK: ret i64 500050000000 + foo3r(10000) +} diff --git a/tests/codegen-llvm/issues/issue-45466.rs b/tests/codegen-llvm/issues/issue-45466.rs new file mode 100644 index 00000000000..164a27ef5d4 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-45466.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "rlib"] + +// CHECK-LABEL: @memzero +// CHECK-NOT: store +// CHECK: call void @llvm.memset +// CHECK-NOT: store +#[no_mangle] +pub fn memzero(data: &mut [u8]) { + for i in 0..data.len() { + data[i] = 0; + } +} diff --git a/tests/codegen-llvm/issues/issue-45964-bounds-check-slice-pos.rs b/tests/codegen-llvm/issues/issue-45964-bounds-check-slice-pos.rs new file mode 100644 index 00000000000..a48bb2a1ccf --- /dev/null +++ b/tests/codegen-llvm/issues/issue-45964-bounds-check-slice-pos.rs @@ -0,0 +1,38 @@ +// This test case checks that slice::{r}position functions do not +// prevent optimizing away bounds checks + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "rlib"] + +// CHECK-LABEL: @test +#[no_mangle] +pub fn test(y: &[u32], x: &u32, z: &u32) -> bool { + let result = match y.iter().position(|a| a == x) { + Some(p) => Ok(p), + None => Err(()), + }; + + if let Ok(p) = result { + // CHECK-NOT: panic + y[p] == *z + } else { + false + } +} + +// CHECK-LABEL: @rtest +#[no_mangle] +pub fn rtest(y: &[u32], x: &u32, z: &u32) -> bool { + let result = match y.iter().rposition(|a| a == x) { + Some(p) => Ok(p), + None => Err(()), + }; + + if let Ok(p) = result { + // CHECK-NOT: panic + y[p] == *z + } else { + false + } +} diff --git a/tests/codegen-llvm/issues/issue-47278.rs b/tests/codegen-llvm/issues/issue-47278.rs new file mode 100644 index 00000000000..4f0a5bdf36f --- /dev/null +++ b/tests/codegen-llvm/issues/issue-47278.rs @@ -0,0 +1,11 @@ +// -C no-prepopulate-passes +#![crate_type = "staticlib"] + +#[repr(C)] +pub struct Foo(u64); + +// CHECK: define {{.*}} @foo( +#[no_mangle] +pub extern "C" fn foo(_: Foo) -> Foo { + loop {} +} diff --git a/tests/codegen-llvm/issues/issue-47442.rs b/tests/codegen-llvm/issues/issue-47442.rs new file mode 100644 index 00000000000..445234e55ad --- /dev/null +++ b/tests/codegen-llvm/issues/issue-47442.rs @@ -0,0 +1,22 @@ +// check that we don't emit unneeded `resume` cleanup blocks for every +// destructor. + +// CHECK-NOT: Unwind + +#![feature(test)] +#![crate_type = "rlib"] + +extern crate test; + +struct Foo {} + +impl Drop for Foo { + fn drop(&mut self) { + test::black_box(()); + } +} + +#[no_mangle] +pub fn foo() { + let _foo = Foo {}; +} diff --git a/tests/codegen-llvm/issues/issue-56267-2.rs b/tests/codegen-llvm/issues/issue-56267-2.rs new file mode 100644 index 00000000000..98e3732777e --- /dev/null +++ b/tests/codegen-llvm/issues/issue-56267-2.rs @@ -0,0 +1,18 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "rlib"] + +#[allow(dead_code)] +pub struct Foo { + foo: u64, + bar: T, +} + +// The load from bar.1 should have alignment 4. Not checking +// other loads here, as the alignment will be platform-dependent. + +// CHECK: %{{.+}} = load i32, ptr %{{.+}}, align 4 +#[no_mangle] +pub fn test(x: Foo<(i32, i32)>) -> (i32, i32) { + x.bar +} diff --git a/tests/codegen-llvm/issues/issue-56267.rs b/tests/codegen-llvm/issues/issue-56267.rs new file mode 100644 index 00000000000..cabcc298482 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-56267.rs @@ -0,0 +1,18 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "rlib"] + +#[allow(dead_code)] +pub struct Foo { + foo: u64, + bar: T, +} + +// The store writing to bar.1 should have alignment 4. Not checking +// other stores here, as the alignment will be platform-dependent. + +// CHECK: store i32 [[TMP1:%.+]], ptr [[TMP2:%.+]], align 4 +#[no_mangle] +pub fn test(x: (i32, i32)) -> Foo<(i32, i32)> { + Foo { foo: 0, bar: x } +} diff --git a/tests/codegen-llvm/issues/issue-56927.rs b/tests/codegen-llvm/issues/issue-56927.rs new file mode 100644 index 00000000000..415ef073e03 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-56927.rs @@ -0,0 +1,46 @@ +//@ compile-flags: -C no-prepopulate-passes +// 32bit MSVC does not align things properly so we suppress high alignment annotations (#112480) +//@ ignore-i686-pc-windows-msvc +//@ ignore-i686-pc-windows-gnu + +#![crate_type = "rlib"] + +#[repr(align(16))] +pub struct S { + arr: [u32; 4], +} + +// CHECK-LABEL: @test1 +// CHECK: store i32 0, ptr %{{.+}}, align 16 +// CHECK: store i32 1, ptr %{{.+}}, align 4 +// CHECK: store i32 2, ptr %{{.+}}, align 8 +// CHECK: store i32 3, ptr %{{.+}}, align 4 +#[no_mangle] +pub fn test1(s: &mut S) { + s.arr[0] = 0; + s.arr[1] = 1; + s.arr[2] = 2; + s.arr[3] = 3; +} + +// CHECK-LABEL: @test2 +// CHECK: store i32 4, ptr %{{.+}}, align 4 +#[allow(unconditional_panic)] +#[no_mangle] +pub fn test2(s: &mut S) { + s.arr[usize::MAX / 4 + 1] = 4; +} + +// CHECK-LABEL: @test3 +// CHECK: store i32 5, ptr %{{.+}}, align 4 +#[no_mangle] +pub fn test3(s: &mut S, i: usize) { + s.arr[i] = 5; +} + +// CHECK-LABEL: @test4 +// CHECK: store i32 6, ptr %{{.+}}, align 4 +#[no_mangle] +pub fn test4(s: &mut S) { + s.arr = [6; 4]; +} diff --git a/tests/codegen-llvm/issues/issue-58881.rs b/tests/codegen-llvm/issues/issue-58881.rs new file mode 100644 index 00000000000..ba6285f3972 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-58881.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 +// +//@ only-x86_64 + +#![crate_type = "lib"] + +extern "C" { + fn variadic_fn(_: i32, ...); +} + +#[repr(C)] +struct Foo(u8); +#[repr(C)] +struct Bar(u64, u64, u64); + +// Ensure that emit arguments of the correct type. +pub unsafe fn test_call_variadic() { + // CHECK: call void (i32, ...) @variadic_fn(i32 0, i8 {{.*}}, ptr {{.*}}) + variadic_fn(0, Foo(0), Bar(0, 0, 0)) +} diff --git a/tests/codegen-llvm/issues/issue-59352.rs b/tests/codegen-llvm/issues/issue-59352.rs new file mode 100644 index 00000000000..cb4383d4a30 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-59352.rs @@ -0,0 +1,18 @@ +// This test is a mirror of mir-opt/issues/issue-59352.rs. The LLVM inliner doesn't inline +// `char::method::is_digit()` and `char::method::to_digit()`, probably because of their size. +// +// Currently, the MIR optimizer isn't capable of removing the unreachable panic in this test case. +// Once the optimizer can do that, mir-opt/issues/issue-59352.rs will need to be updated and this +// test case should be removed as it will become redundant. + +// mir-opt-level=3 enables inlining and enables LLVM to optimize away the unreachable panic call. +//@ compile-flags: -Copt-level=3 -Z mir-opt-level=3 + +#![crate_type = "rlib"] + +// CHECK-LABEL: @num_to_digit +#[no_mangle] +pub fn num_to_digit(num: char) -> u32 { + // CHECK-NOT: panic + if num.is_digit(8) { num.to_digit(8).unwrap() } else { 0 } +} diff --git a/tests/codegen-llvm/issues/issue-64219-fn-ptr-call-returning-never-is-noreturn.rs b/tests/codegen-llvm/issues/issue-64219-fn-ptr-call-returning-never-is-noreturn.rs new file mode 100644 index 00000000000..86d020e1751 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-64219-fn-ptr-call-returning-never-is-noreturn.rs @@ -0,0 +1,19 @@ +//! Test for https://github.com/rust-lang/rust/issues/64219 +//! Check if `noreturn` attribute is applied on calls to +//! function pointers returning `!` (never type). + +#![crate_type = "lib"] + +extern "C" { + static FOO: fn() -> !; +} + +// CHECK-LABEL: @foo +#[no_mangle] +pub unsafe fn foo() { + // CHECK: call + // CHECK-SAME: [[NUM:#[0-9]+$]] + FOO(); +} + +// CHECK: attributes [[NUM]] = {{{.*}} noreturn {{.*}}} diff --git a/tests/codegen-llvm/issues/issue-68667-unwrap-combinators.rs b/tests/codegen-llvm/issues/issue-68667-unwrap-combinators.rs new file mode 100644 index 00000000000..7f4a32109fe --- /dev/null +++ b/tests/codegen-llvm/issues/issue-68667-unwrap-combinators.rs @@ -0,0 +1,15 @@ +#![crate_type = "lib"] + +//@ compile-flags: -Copt-level=3 + +// MIR inlining now optimizes this code. + +// CHECK-LABEL: @unwrap_combinators +// CHECK: {{icmp|trunc}} +// CHECK-NEXT: icmp +// CHECK-NEXT: select i1 +// CHECK-NEXT: ret i1 +#[no_mangle] +pub fn unwrap_combinators(a: Option, b: i32) -> bool { + a.map(|t| t >= b).unwrap_or(false) +} diff --git a/tests/codegen-llvm/issues/issue-69101-bounds-check.rs b/tests/codegen-llvm/issues/issue-69101-bounds-check.rs new file mode 100644 index 00000000000..953b79aa263 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-69101-bounds-check.rs @@ -0,0 +1,42 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +// Make sure no bounds checks are emitted in the loop when upfront slicing +// ensures that the slices are big enough. +// In particular, bounds checks were not always optimized out if the upfront +// check was for a greater len than the loop requires. +// (i.e. `already_sliced_no_bounds_check` was not always optimized even when +// `already_sliced_no_bounds_check_exact` was) +// CHECK-LABEL: @already_sliced_no_bounds_check +#[no_mangle] +pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) { + // CHECK: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + let _ = (&a[..2048], &b[..2048], &mut c[..2048]); + for i in 0..1024 { + c[i] = a[i] ^ b[i]; + } +} + +// CHECK-LABEL: @already_sliced_no_bounds_check_exact +#[no_mangle] +pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) { + // CHECK: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + let _ = (&a[..1024], &b[..1024], &mut c[..1024]); + for i in 0..1024 { + c[i] = a[i] ^ b[i]; + } +} + +// Make sure we're checking for the right thing: there can be a panic if the slice is too small. +// CHECK-LABEL: @already_sliced_bounds_check +#[no_mangle] +pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) { + // CHECK: slice_end_index_len_fail + // CHECK: panic_bounds_check + let _ = (&a[..1023], &b[..2048], &mut c[..2048]); + for i in 0..1024 { + c[i] = a[i] ^ b[i]; + } +} diff --git a/tests/codegen-llvm/issues/issue-73031.rs b/tests/codegen-llvm/issues/issue-73031.rs new file mode 100644 index 00000000000..80dea9b5bc2 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-73031.rs @@ -0,0 +1,22 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +// Test that LLVM can eliminate the unreachable `All::None` branch. + +pub enum All { + None, + Foo, + Bar, +} + +// CHECK-LABEL: @issue_73031 +#[no_mangle] +pub fn issue_73031(a: &mut All, q: i32) -> i32 { + *a = if q == 5 { All::Foo } else { All::Bar }; + match *a { + // CHECK-NOT: panic + All::None => panic!(), + All::Foo => 1, + All::Bar => 2, + } +} diff --git a/tests/codegen-llvm/issues/issue-73258.rs b/tests/codegen-llvm/issues/issue-73258.rs new file mode 100644 index 00000000000..936a7554496 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-73258.rs @@ -0,0 +1,40 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// Adapted from + +#[derive(Clone, Copy)] +#[repr(u8)] +pub enum Foo { + A, + B, + C, + D, +} + +// CHECK-LABEL: @issue_73258( +#[no_mangle] +pub unsafe fn issue_73258(ptr: *const Foo) -> Foo { + // CHECK-NOT: icmp + // CHECK-NOT: call + // CHECK-NOT: br + // CHECK-NOT: select + + // CHECK: %[[R:.+]] = load i8 + // CHECK-SAME: !range ! + + // CHECK-NOT: icmp + // CHECK-NOT: call + // CHECK-NOT: br + // CHECK-NOT: select + + // CHECK: ret i8 %[[R]] + + // CHECK-NOT: icmp + // CHECK-NOT: call + // CHECK-NOT: br + // CHECK-NOT: select + let k: Option = Some(ptr.read()); + return k.unwrap(); +} diff --git a/tests/codegen-llvm/issues/issue-73338-effecient-cmp.rs b/tests/codegen-llvm/issues/issue-73338-effecient-cmp.rs new file mode 100644 index 00000000000..71641a5457b --- /dev/null +++ b/tests/codegen-llvm/issues/issue-73338-effecient-cmp.rs @@ -0,0 +1,39 @@ +// This test checks that comparison operation +// generated by #[derive(PartialOrd)] +// doesn't contain jumps for C enums + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[repr(u32)] +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd)] +pub enum Foo { + Zero, + One, + Two, +} + +#[no_mangle] +pub fn compare_less(a: Foo, b: Foo) -> bool { + // CHECK-NOT: br {{.*}} + a < b +} + +#[no_mangle] +pub fn compare_le(a: Foo, b: Foo) -> bool { + // CHECK-NOT: br {{.*}} + a <= b +} + +#[no_mangle] +pub fn compare_ge(a: Foo, b: Foo) -> bool { + // CHECK-NOT: br {{.*}} + a >= b +} + +#[no_mangle] +pub fn compare_greater(a: Foo, b: Foo) -> bool { + // CHECK-NOT: br {{.*}} + a > b +} diff --git a/tests/codegen-llvm/issues/issue-73396-bounds-check-after-position.rs b/tests/codegen-llvm/issues/issue-73396-bounds-check-after-position.rs new file mode 100644 index 00000000000..1e2c25babe0 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-73396-bounds-check-after-position.rs @@ -0,0 +1,70 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +// Make sure no bounds checks are emitted when slicing or indexing +// with an index from `position()` or `rposition()`. + +// CHECK-LABEL: @position_slice_to_no_bounds_check +#[no_mangle] +pub fn position_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: unreachable + if let Some(idx) = s.iter().position(|b| *b == b'\\') { &s[..idx] } else { s } +} + +// CHECK-LABEL: @position_slice_from_no_bounds_check +#[no_mangle] +pub fn position_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: unreachable + if let Some(idx) = s.iter().position(|b| *b == b'\\') { &s[idx..] } else { s } +} + +// CHECK-LABEL: @position_index_no_bounds_check +#[no_mangle] +pub fn position_index_no_bounds_check(s: &[u8]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: unreachable + if let Some(idx) = s.iter().position(|b| *b == b'\\') { s[idx] } else { 42 } +} +// CHECK-LABEL: @rposition_slice_to_no_bounds_check +#[no_mangle] +pub fn rposition_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: unreachable + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { &s[..idx] } else { s } +} + +// CHECK-LABEL: @rposition_slice_from_no_bounds_check +#[no_mangle] +pub fn rposition_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: unreachable + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { &s[idx..] } else { s } +} + +// CHECK-LABEL: @rposition_index_no_bounds_check +#[no_mangle] +pub fn rposition_index_no_bounds_check(s: &[u8]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: unreachable + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { s[idx] } else { 42 } +} diff --git a/tests/codegen-llvm/issues/issue-73827-bounds-check-index-in-subexpr.rs b/tests/codegen-llvm/issues/issue-73827-bounds-check-index-in-subexpr.rs new file mode 100644 index 00000000000..e9dd0d1bf23 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-73827-bounds-check-index-in-subexpr.rs @@ -0,0 +1,17 @@ +// This test checks that bounds checks are elided when +// index is part of a (x | y) < C style condition + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @get +#[no_mangle] +pub fn get(array: &[u8; 8], x: usize, y: usize) -> u8 { + if x > 7 || y > 7 { + 0 + } else { + // CHECK-NOT: panic_bounds_check + array[y] + } +} diff --git a/tests/codegen-llvm/issues/issue-74938-array-split-at.rs b/tests/codegen-llvm/issues/issue-74938-array-split-at.rs new file mode 100644 index 00000000000..9d3e23d642b --- /dev/null +++ b/tests/codegen-llvm/issues/issue-74938-array-split-at.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +const N: usize = 3; +pub type T = u8; + +// CHECK-LABEL: @split_multiple +// CHECK-NOT: unreachable +#[no_mangle] +pub fn split_multiple(slice: &[T]) -> (&[T], &[T]) { + let len = slice.len() / N; + slice.split_at(len * N) +} diff --git a/tests/codegen-llvm/issues/issue-75525-bounds-checks.rs b/tests/codegen-llvm/issues/issue-75525-bounds-checks.rs new file mode 100644 index 00000000000..5dfbd350010 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-75525-bounds-checks.rs @@ -0,0 +1,26 @@ +// Regression test for #75525, verifies that no bounds checks are generated. + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @f0 +// CHECK-NOT: panic +#[no_mangle] +pub fn f0(idx: usize, buf: &[u8; 10]) -> u8 { + if idx < 8 { buf[idx + 1] } else { 0 } +} + +// CHECK-LABEL: @f1 +// CHECK-NOT: panic +#[no_mangle] +pub fn f1(idx: usize, buf: &[u8; 10]) -> u8 { + if idx > 5 && idx < 8 { buf[idx - 1] } else { 0 } +} + +// CHECK-LABEL: @f2 +// CHECK-NOT: panic +#[no_mangle] +pub fn f2(idx: usize, buf: &[u8; 10]) -> u8 { + if idx > 5 && idx < 8 { buf[idx] } else { 0 } +} diff --git a/tests/codegen-llvm/issues/issue-75546.rs b/tests/codegen-llvm/issues/issue-75546.rs new file mode 100644 index 00000000000..1e1e6543a88 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-75546.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +// Test that LLVM can eliminate the impossible `i == 0` check. + +// CHECK-LABEL: @issue_75546 +#[no_mangle] +pub fn issue_75546() { + let mut i = 1u32; + while i < u32::MAX { + // CHECK-NOT: panic + if i == 0 { + panic!(); + } + i += 1; + } +} diff --git a/tests/codegen-llvm/issues/issue-75659.rs b/tests/codegen-llvm/issues/issue-75659.rs new file mode 100644 index 00000000000..0960bfdb6b0 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-75659.rs @@ -0,0 +1,63 @@ +// This test checks that the call to memchr/slice_contains is optimized away +// when searching in small slices. + +//@ compile-flags: -Copt-level=3 -Zinline-mir=false +//@ only-x86_64 + +#![crate_type = "lib"] + +// CHECK-LABEL: @foo1 +#[no_mangle] +pub fn foo1(x: u8, data: &[u8; 1]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo2 +#[no_mangle] +pub fn foo2(x: u8, data: &[u8; 2]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo3 +#[no_mangle] +pub fn foo3(x: u8, data: &[u8; 3]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo4 +#[no_mangle] +pub fn foo4(x: u8, data: &[u8; 4]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo8 +#[no_mangle] +pub fn foo8(x: u8, data: &[u8; 8]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo8_i8 +#[no_mangle] +pub fn foo8_i8(x: i8, data: &[i8; 8]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + !data.contains(&x) +} + +// Check that the general case isn't inlined +// CHECK-LABEL: @foo80 +#[no_mangle] +pub fn foo80(x: u8, data: &[u8; 80]) -> bool { + // CHECK: call core::slice::memchr + data.contains(&x) +} diff --git a/tests/codegen-llvm/issues/issue-75978.rs b/tests/codegen-llvm/issues/issue-75978.rs new file mode 100644 index 00000000000..f4b0bc36329 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-75978.rs @@ -0,0 +1,18 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test() -> u32 { + // CHECK-LABEL: @test( + // CHECK: ret i32 13 + let s = [1, 2, 3, 4, 5, 6, 7]; + + let mut iter = s.iter(); + let mut sum = 0; + while let Some(_) = iter.next() { + sum += iter.next().map_or(1, |&x| x) + } + + sum +} diff --git a/tests/codegen-llvm/issues/issue-77812.rs b/tests/codegen-llvm/issues/issue-77812.rs new file mode 100644 index 00000000000..09e2376c30d --- /dev/null +++ b/tests/codegen-llvm/issues/issue-77812.rs @@ -0,0 +1,32 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +// Test that LLVM can eliminate the unreachable `Variant::Zero` branch. + +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum Variant { + Zero, + One, + Two, +} + +extern "C" { + fn exf1(); + fn exf2(); +} + +pub static mut GLOBAL: Variant = Variant::Zero; + +// CHECK-LABEL: @issue_77812 +#[no_mangle] +pub unsafe fn issue_77812() { + let g = GLOBAL; + if g != Variant::Zero { + match g { + Variant::One => exf1(), + Variant::Two => exf2(), + // CHECK-NOT: panic + Variant::Zero => panic!(), + } + } +} diff --git a/tests/codegen-llvm/issues/issue-84268.rs b/tests/codegen-llvm/issues/issue-84268.rs new file mode 100644 index 00000000000..1dc55a909ad --- /dev/null +++ b/tests/codegen-llvm/issues/issue-84268.rs @@ -0,0 +1,18 @@ +//@ compile-flags: -Copt-level=3 --crate-type=rlib +#![feature(core_intrinsics, repr_simd)] + +use std::intrinsics::simd::{simd_eq, simd_fabs}; + +#[repr(simd)] +pub struct V([f32; 4]); + +#[repr(simd)] +pub struct M([i32; 4]); + +#[no_mangle] +// CHECK-LABEL: @is_infinite +pub fn is_infinite(v: V) -> M { + // CHECK: fabs + // CHECK: cmp oeq + unsafe { simd_eq(simd_fabs(v), V([f32::INFINITY; 4])) } +} diff --git a/tests/codegen-llvm/issues/issue-85872-multiple-reverse.rs b/tests/codegen-llvm/issues/issue-85872-multiple-reverse.rs new file mode 100644 index 00000000000..6f566ddee6b --- /dev/null +++ b/tests/codegen-llvm/issues/issue-85872-multiple-reverse.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn u16_be_to_arch(mut data: [u8; 2]) -> [u8; 2] { + // CHECK-LABEL: @u16_be_to_arch + // CHECK: @llvm.bswap.i16 + data.reverse(); + data +} + +#[no_mangle] +pub fn u32_be_to_arch(mut data: [u8; 4]) -> [u8; 4] { + // CHECK-LABEL: @u32_be_to_arch + // CHECK: @llvm.bswap.i32 + data.reverse(); + data +} diff --git a/tests/codegen-llvm/issues/issue-86106.rs b/tests/codegen-llvm/issues/issue-86106.rs new file mode 100644 index 00000000000..8d1ce116d26 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-86106.rs @@ -0,0 +1,63 @@ +//@ only-64bit llvm appears to use stores instead of memset on 32bit +//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled +//@ needs-deterministic-layouts + +// The below two functions ensure that both `String::new()` and `"".to_string()` +// produce the identical code. + +#![crate_type = "lib"] + +// CHECK-LABEL: define {{(dso_local )?}}void @string_new +#[no_mangle] +pub fn string_new() -> String { + // CHECK-NOT: load i8 + // CHECK: store i{{32|64}} + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store ptr + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store i{{32|64}} + // CHECK-NEXT: ret void + String::new() +} + +// CHECK-LABEL: define {{(dso_local )?}}void @empty_to_string +#[no_mangle] +pub fn empty_to_string() -> String { + // CHECK-NOT: load i8 + // CHECK: store i{{32|64}} + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store ptr + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store i{{32|64}} + // CHECK-NEXT: ret void + "".to_string() +} + +// The below two functions ensure that both `vec![]` and `vec![].clone()` +// produce the identical code. + +// CHECK-LABEL: @empty_vec +#[no_mangle] +pub fn empty_vec() -> Vec { + // CHECK: store i{{32|64}} + // CHECK-NOT: load i8 + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store ptr + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store i{{32|64}} + // CHECK-NEXT: ret void + vec![] +} + +// CHECK-LABEL: @empty_vec_clone +#[no_mangle] +pub fn empty_vec_clone() -> Vec { + // CHECK: store i{{32|64}} + // CHECK-NOT: load i8 + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store ptr + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store i{{32|64}} + // CHECK-NEXT: ret void + vec![].clone() +} diff --git a/tests/codegen-llvm/issues/issue-86109-eliminate-div-by-zero-check.rs b/tests/codegen-llvm/issues/issue-86109-eliminate-div-by-zero-check.rs new file mode 100644 index 00000000000..345c09738b6 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-86109-eliminate-div-by-zero-check.rs @@ -0,0 +1,26 @@ +//@ compile-flags: -Copt-level=3 +//! Test for https://github.com/rust-lang/rust/issues/86109 +//! Check LLVM can eliminate the impossible division by zero check by +//! ensuring there is no call (to panic) instruction. +//! +//! This has been fixed since `rustc 1.70.0`. + +#![crate_type = "lib"] + +type T = i16; + +// CHECK-LABEL: @foo +#[no_mangle] +pub fn foo(start: T) -> T { + // CHECK-NOT: panic + if start <= 0 { + return 0; + } + let mut count = 0; + for i in start..10_000 { + if 752 % i != 0 { + count += 1; + } + } + count +} diff --git a/tests/codegen-llvm/issues/issue-93036-assert-index.rs b/tests/codegen-llvm/issues/issue-93036-assert-index.rs new file mode 100644 index 00000000000..46f45c2f06e --- /dev/null +++ b/tests/codegen-llvm/issues/issue-93036-assert-index.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[no_mangle] +// CHECK-LABEL: @foo +// CHECK-NOT: unreachable +pub fn foo(arr: &mut [u32]) { + for i in 0..arr.len() { + for j in 0..i { + assert!(j < arr.len()); + } + } +} diff --git a/tests/codegen-llvm/issues/issue-96274.rs b/tests/codegen-llvm/issues/issue-96274.rs new file mode 100644 index 00000000000..2425ec53e4e --- /dev/null +++ b/tests/codegen-llvm/issues/issue-96274.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +use std::mem::MaybeUninit; + +pub fn maybe_uninit() -> [MaybeUninit; 3000] { + // CHECK-NOT: memset + [MaybeUninit::uninit(); 3000] +} + +pub fn maybe_uninit_const() -> [MaybeUninit; 8192] { + // CHECK-NOT: memset + [const { MaybeUninit::uninit() }; 8192] +} diff --git a/tests/codegen-llvm/issues/issue-96497-slice-size-nowrap.rs b/tests/codegen-llvm/issues/issue-96497-slice-size-nowrap.rs new file mode 100644 index 00000000000..7b3a20a295e --- /dev/null +++ b/tests/codegen-llvm/issues/issue-96497-slice-size-nowrap.rs @@ -0,0 +1,38 @@ +// This test case checks that LLVM is aware that computing the size of a slice cannot wrap. +// The possibility of wrapping results in an additional branch when dropping boxed slices +// in some situations, see https://github.com/rust-lang/rust/issues/96497#issuecomment-1112865218 + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @simple_size_of_nowrap +#[no_mangle] +pub fn simple_size_of_nowrap(x: &[u32]) -> usize { + // Make sure the shift used to compute the size has a nowrap flag. + + // CHECK: [[A:%.*]] = shl nuw nsw {{.*}}, 2 + // CHECK-NEXT: ret {{.*}} [[A]] + core::mem::size_of_val(x) +} + +// CHECK-LABEL: @drop_write +#[no_mangle] +pub fn drop_write(mut x: Box<[u32]>) { + // Check that this write is optimized out. + // This depends on the size calculation not wrapping, + // since otherwise LLVM can't tell that the memory is always deallocated if the slice len > 0. + + // CHECK-NOT: store i32 42 + x[1] = 42; +} + +// CHECK-LABEL: @slice_size_plus_2 +#[no_mangle] +pub fn slice_size_plus_2(x: &[u16]) -> usize { + // Before #136575 this didn't get the `nuw` in the add. + + // CHECK: [[BYTES:%.+]] = shl nuw nsw {{i16|i32|i64}} %x.1, 1 + // CHECK: = add nuw {{i16|i32|i64}} [[BYTES]], 2 + core::mem::size_of_val(x) + 2 +} diff --git a/tests/codegen-llvm/issues/issue-98294-get-mut-copy-from-slice-opt.rs b/tests/codegen-llvm/issues/issue-98294-get-mut-copy-from-slice-opt.rs new file mode 100644 index 00000000000..76adcf9fd45 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-98294-get-mut-copy-from-slice-opt.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// There should be no calls to panic / len_mismatch_fail. + +#[no_mangle] +pub fn test(a: &mut [u8], offset: usize, bytes: &[u8]) { + // CHECK-LABEL: @test( + // CHECK-NOT: call + // CHECK: call void @llvm.memcpy + // CHECK-NOT: call + // CHECK: } + if let Some(dst) = a.get_mut(offset..offset + bytes.len()) { + dst.copy_from_slice(bytes); + } +} diff --git a/tests/codegen-llvm/issues/issue-98678-async.rs b/tests/codegen-llvm/issues/issue-98678-async.rs new file mode 100644 index 00000000000..3dd06bb5194 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-98678-async.rs @@ -0,0 +1,27 @@ +// ignore-tidy-linelength +//! This test verifies the accuracy of emitted file and line debuginfo metadata for async blocks and +//! async functions. + +//@ revisions: MSVC NONMSVC +//@[MSVC] only-msvc +//@[NONMSVC] ignore-msvc +//@ edition:2021 +//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true + +// NONMSVC-DAG: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-async.rs{{".*}}) +// MSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-async.rs{{".*}}) + +// NONMSVC-DAG: !DISubprogram(name: "foo",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], +// MSVC-DAG: !DISubprogram(name: "foo",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], +pub async fn foo() -> u8 { + 5 +} + +pub fn bar() -> impl std::future::Future { + // NONMSVC: !DICompositeType({{.*"}}{async_block_env#0}{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], + // MSVC-DAG: !DICompositeType({{.*"}}enum2${{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], + async { + let x: u8 = foo().await; + x + 5 + } +} diff --git a/tests/codegen-llvm/issues/issue-98678-closure-coroutine.rs b/tests/codegen-llvm/issues/issue-98678-closure-coroutine.rs new file mode 100644 index 00000000000..8763bcb799d --- /dev/null +++ b/tests/codegen-llvm/issues/issue-98678-closure-coroutine.rs @@ -0,0 +1,25 @@ +// ignore-tidy-linelength +//! This test verifies the accuracy of emitted file and line debuginfo metadata for closures and +//! coroutines. + +#![feature(coroutines, stmt_expr_attributes)] + +//@ revisions: MSVC NONMSVC +//@[MSVC] only-msvc +//@[NONMSVC] ignore-msvc +//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true + +// NONMSVC-DAG: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-closure-coroutine.rs{{".*}}) +// MSVC-DAG: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-closure-coroutine.rs{{".*}}) + +pub fn foo() { + // NONMSVC-DAG: !DICompositeType({{.*"}}{closure_env#0}{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], + // MSVC-DAG: !DICompositeType({{.*"}}closure_env$0{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], + let closure = |x| x; + closure(0); + + // NONMSVC-DAG: !DICompositeType({{.*"[{]}}coroutine_env#1{{[}]".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 3]], + // MSVC-DAG: !DICompositeType({{.*".*foo::}}coroutine_env$1>{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], + let _coroutine = #[coroutine] + || yield 1; +} diff --git a/tests/codegen-llvm/issues/issue-98678-enum.rs b/tests/codegen-llvm/issues/issue-98678-enum.rs new file mode 100644 index 00000000000..87bf8797293 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-98678-enum.rs @@ -0,0 +1,42 @@ +// ignore-tidy-linelength +//! This test verifies the accuracy of emitted file and line debuginfo metadata enums. + +//@ revisions: MSVC NONMSVC +//@[MSVC] only-msvc +//@[NONMSVC] ignore-msvc +//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true + +// NONMSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-enum.rs{{".*}}) +// MSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-enum.rs{{".*}}) + +// NONMSVC: !DICompositeType({{.*"}}SingleCase{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], +// MSVC: !DICompositeType({{.*"}}enum2${{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], +pub enum SingleCase { + // NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "One",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], + // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "One",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], + One, +} + +// NONMSVC: !DICompositeType({{.*"}}MultipleDataCases{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], +// MSVC: !DICompositeType({{.*"}}enum2${{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], +pub enum MultipleDataCases { + // NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Case1",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], + // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Case1",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], + Case1(u32), + // NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Case2",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], + // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Case2",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], + Case2(i64), +} + +// NONMSVC: !DICompositeType({{.*"}}NicheLayout{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], +// MSVC: !DICompositeType({{.*"}}enum2${{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], +pub enum NicheLayout { + // NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Something",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], + // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Something",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], + Something(&'static u32), + // NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Nothing",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], + // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Nothing",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], + Nothing, +} + +pub fn foo(_: SingleCase, _: MultipleDataCases, _: NicheLayout) {} diff --git a/tests/codegen-llvm/issues/issue-98678-struct-union.rs b/tests/codegen-llvm/issues/issue-98678-struct-union.rs new file mode 100644 index 00000000000..a83a585a433 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-98678-struct-union.rs @@ -0,0 +1,27 @@ +// ignore-tidy-linelength +//! This test verifies the accuracy of emitted file and line debuginfo metadata for structs and +//! unions. + +//@ revisions: MSVC NONMSVC +//@[MSVC] only-msvc +//@[NONMSVC] ignore-msvc +//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true + +// NONMSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-struct-union.rs{{".*}}) +// MSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-struct-union.rs{{".*}}) + +// CHECK: !DICompositeType({{.*"}}MyType{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], +pub struct MyType { + // CHECK: !DIDerivedType({{.*"}}i{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], + i: i32, +} + +// CHECK: !DICompositeType({{.*"}}MyUnion{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], +pub union MyUnion { + // CHECK: !DIDerivedType({{.*"}}i{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], + i: i32, + // CHECK: !DIDerivedType({{.*"}}f{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], + f: f32, +} + +pub fn foo(_: MyType, _: MyUnion) {} diff --git a/tests/codegen-llvm/issues/issue-99960.rs b/tests/codegen-llvm/issues/issue-99960.rs new file mode 100644 index 00000000000..571a9be967d --- /dev/null +++ b/tests/codegen-llvm/issues/issue-99960.rs @@ -0,0 +1,10 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test(dividend: i64, divisor: i64) -> Option { + // CHECK-LABEL: @test( + // CHECK-NOT: panic + if dividend > i64::min_value() && divisor != 0 { Some(dividend / divisor) } else { None } +} diff --git a/tests/codegen-llvm/issues/looping-over-ne-bytes-133528.rs b/tests/codegen-llvm/issues/looping-over-ne-bytes-133528.rs new file mode 100644 index 00000000000..35acf765d69 --- /dev/null +++ b/tests/codegen-llvm/issues/looping-over-ne-bytes-133528.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Copt-level=3 +//@ min-llvm-version: 20 +#![crate_type = "lib"] + +/// Ensure the function is properly optimized +/// In the issue #133528, the function was not getting optimized +/// whereas, a version with `bytes` wrapped into a `black_box` was optimized +/// It was probably a LLVM bug that was fixed in LLVM 20 + +// CHECK-LABEL: @looping_over_ne_bytes +// CHECK: icmp eq i64 %input, -1 +// CHECK-NEXT: ret i1 +#[no_mangle] +fn looping_over_ne_bytes(input: u64) -> bool { + let bytes = input.to_ne_bytes(); + bytes.iter().all(|x| *x == !0) +} diff --git a/tests/codegen-llvm/issues/str-to-string-128690.rs b/tests/codegen-llvm/issues/str-to-string-128690.rs new file mode 100644 index 00000000000..d9e69764be2 --- /dev/null +++ b/tests/codegen-llvm/issues/str-to-string-128690.rs @@ -0,0 +1,38 @@ +//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled +#![crate_type = "lib"] + +//! Make sure str::to_string is specialized not to use fmt machinery. +//! +//! Note that the `CHECK-NOT`s here try to match on calls to functions under `core::fmt`. + +// CHECK-LABEL: define {{(dso_local )?}}void @one_ref +#[no_mangle] +pub fn one_ref(input: &str) -> String { + // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}} + input.to_string() +} + +// CHECK-LABEL: define {{(dso_local )?}}void @two_ref +#[no_mangle] +pub fn two_ref(input: &&str) -> String { + // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}} + input.to_string() +} + +// CHECK-LABEL: define {{(dso_local )?}}void @thirteen_ref +#[no_mangle] +pub fn thirteen_ref(input: &&&&&&&&&&&&&str) -> String { + // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}} + input.to_string() +} + +// This is a known performance cliff because of the macro-generated +// specialized impl. If this test suddenly starts failing, +// consider removing the `to_string_str!` macro in `alloc/str/string.rs`. +// +// CHECK-LABEL: define {{(dso_local )?}}void @fourteen_ref +#[no_mangle] +pub fn fourteen_ref(input: &&&&&&&&&&&&&&str) -> String { + // CHECK: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}} + input.to_string() +} diff --git a/tests/codegen-llvm/iter-repeat-n-trivial-drop.rs b/tests/codegen-llvm/iter-repeat-n-trivial-drop.rs new file mode 100644 index 00000000000..28173530324 --- /dev/null +++ b/tests/codegen-llvm/iter-repeat-n-trivial-drop.rs @@ -0,0 +1,70 @@ +//@ compile-flags: -C opt-level=3 +//@ only-x86_64 +//@ needs-deterministic-layouts + +#![crate_type = "lib"] +#![feature(iter_repeat_n)] +#![feature(array_repeat)] + +#[derive(Clone)] +pub struct NotCopy(u16); + +impl Drop for NotCopy { + fn drop(&mut self) {} +} + +// For a type where `Drop::drop` doesn't do anything observable and a clone is the +// same as a move, make sure that the extra case for the last item disappears. + +#[no_mangle] +// CHECK-LABEL: @iter_repeat_n_next +pub fn iter_repeat_n_next(it: &mut std::iter::RepeatN) -> Option { + // CHECK-NEXT: start: + // CHECK-NOT: br + // CHECK: %[[COUNT:.+]] = load i64 + // CHECK-NEXT: %[[COUNT_ZERO:.+]] = icmp eq i64 %[[COUNT]], 0 + // CHECK-NEXT: br i1 %[[COUNT_ZERO]], label %[[EMPTY:.+]], label %[[NOT_EMPTY:.+]] + + // CHECK: [[NOT_EMPTY]]: + // CHECK-NOT: br + // CHECK: %[[DEC:.+]] = add i64 %[[COUNT]], -1 + // CHECK-NEXT: %[[VAL:.+]] = load i16 + // CHECK-NEXT: store i64 %[[DEC]] + // CHECK-NEXT: br label %[[EMPTY]] + + // CHECK: [[EMPTY]]: + // CHECK-NOT: br + // CHECK: phi i16 + // CHECK-SAME: [ %[[VAL]], %[[NOT_EMPTY]] ] + // CHECK-NOT: br + // CHECK: ret + + it.next() +} + +// And as a result, using the iterator can optimize without special cases for +// the last iteration, like `memset`ing all the items in one call. + +#[no_mangle] +// CHECK-LABEL: @vec_extend_via_iter_repeat_n +pub fn vec_extend_via_iter_repeat_n() -> Vec { + // CHECK: %[[ADDR:.+]] = tail call {{(noalias )?}}noundef dereferenceable_or_null(1234) ptr @{{.*}}__rust_alloc(i64 noundef {{(range\(i64 1, 0\) )?}}1234, i64 noundef {{(range\(i64 1, -9223372036854775807\) )?}}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; + let mut v = Vec::with_capacity(n); + v.extend(std::iter::repeat_n(42_u8, n)); + v +} + +// Array repeat uses `RepeatN::next_unchecked` internally, +// so also check that the distinction disappears there. + +#[no_mangle] +// CHECK-LABEL: @array_repeat_not_copy +pub unsafe fn array_repeat_not_copy(item: NotCopy) -> [NotCopy; 8] { + // CHECK: insertelement {{.+}} i16 %item + // CHECK: shufflevector <8 x i16> {{.+}} zeroinitializer + // CHECK: store <8 x i16> + std::array::repeat(item) +} diff --git a/tests/codegen-llvm/layout-size-checks.rs b/tests/codegen-llvm/layout-size-checks.rs new file mode 100644 index 00000000000..d64a7055e0b --- /dev/null +++ b/tests/codegen-llvm/layout-size-checks.rs @@ -0,0 +1,30 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 + +#![crate_type = "lib"] + +use std::alloc::Layout; + +type RGB48 = [u16; 3]; + +// CHECK-LABEL: @layout_array_rgb48 +#[no_mangle] +pub fn layout_array_rgb48(n: usize) -> Layout { + // CHECK-NOT: llvm.umul.with.overflow.i64 + // CHECK: icmp ugt i64 %n, 1537228672809129301 + // CHECK-NOT: llvm.umul.with.overflow.i64 + // CHECK: mul nuw nsw i64 %n, 6 + // CHECK-NOT: llvm.umul.with.overflow.i64 + Layout::array::(n).unwrap() +} + +// CHECK-LABEL: @layout_array_i32 +#[no_mangle] +pub fn layout_array_i32(n: usize) -> Layout { + // CHECK-NOT: llvm.umul.with.overflow.i64 + // CHECK: icmp ugt i64 %n, 2305843009213693951 + // CHECK-NOT: llvm.umul.with.overflow.i64 + // CHECK: shl nuw nsw i64 %n, 2 + // CHECK-NOT: llvm.umul.with.overflow.i64 + Layout::array::(n).unwrap() +} diff --git a/tests/codegen-llvm/lib-optimizations/iter-sum.rs b/tests/codegen-llvm/lib-optimizations/iter-sum.rs new file mode 100644 index 00000000000..a054ffffe74 --- /dev/null +++ b/tests/codegen-llvm/lib-optimizations/iter-sum.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 (vectorization varies between architectures) +#![crate_type = "lib"] + +// Ensure that slice + take + sum gets vectorized. +// Currently this relies on the slice::Iter::try_fold implementation +// CHECK-LABEL: @slice_take_sum +#[no_mangle] +pub fn slice_take_sum(s: &[u64], l: usize) -> u64 { + // CHECK: vector.body: + // CHECK: ret + s.iter().take(l).sum() +} diff --git a/tests/codegen-llvm/lib-optimizations/slice_rotate.rs b/tests/codegen-llvm/lib-optimizations/slice_rotate.rs new file mode 100644 index 00000000000..aa4bb3b528c --- /dev/null +++ b/tests/codegen-llvm/lib-optimizations/slice_rotate.rs @@ -0,0 +1,30 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// Ensure that the simple case of rotating by a constant 1 optimizes to the obvious thing + +// CHECK-LABEL: @rotate_left_by_one +#[no_mangle] +pub fn rotate_left_by_one(slice: &mut [i32]) { + // CHECK-NOT: phi + // CHECK-NOT: call + // CHECK-NOT: load + // CHECK-NOT: store + // CHECK-NOT: getelementptr + // CHECK: %[[END:.+]] = getelementptr + // CHECK-NEXT: %[[DIM:.+]] = getelementptr + // CHECK-NEXT: %[[LAST:.+]] = load + // CHECK-NEXT: %[[FIRST:.+]] = shl + // CHECK-NEXT: call void @llvm.memmove + // CHECK-NEXT: store i32 %[[LAST]], ptr %[[DIM:.+]] + // CHECK-NOT: phi + // CHECK-NOT: call + // CHECK-NOT: load + // CHECK-NOT: store + // CHECK-NOT: getelementptr + // CHECK: ret void + if !slice.is_empty() { + slice.rotate_left(1); + } +} diff --git a/tests/codegen-llvm/lifetime_start_end.rs b/tests/codegen-llvm/lifetime_start_end.rs new file mode 100644 index 00000000000..0639e7640aa --- /dev/null +++ b/tests/codegen-llvm/lifetime_start_end.rs @@ -0,0 +1,34 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Zmir-opt-level=0 + +#![crate_type = "lib"] + +// CHECK-LABEL: @test +#[no_mangle] +pub fn test() { + let a = 0u8; + &a; // keep variable in an alloca + + // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, ptr %a) + + { + let b = &Some(a); + &b; // keep variable in an alloca + + // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, {{.*}}) + + // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, {{.*}}) + + // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, {{.*}}) + + // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, {{.*}}) + } + + let c = 1u8; + &c; // keep variable in an alloca + + // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, ptr %c) + + // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, ptr %c) + + // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, ptr %a) +} diff --git a/tests/codegen-llvm/link-dead-code.rs b/tests/codegen-llvm/link-dead-code.rs new file mode 100644 index 00000000000..93e1d84d9c7 --- /dev/null +++ b/tests/codegen-llvm/link-dead-code.rs @@ -0,0 +1,28 @@ +//@ compile-flags:-Clink-dead-code + +#![crate_type = "rlib"] + +// This test makes sure that, when -Clink-dead-code is specified, we generate +// code for functions that would otherwise be skipped. + +// CHECK-LABEL: ; link_dead_code::const_fn +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define hidden +const fn const_fn() -> i32 { + 1 +} + +// CHECK-LABEL: ; link_dead_code::inline_fn +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define hidden +#[inline] +fn inline_fn() -> i32 { + 2 +} + +// CHECK-LABEL: ; link_dead_code::private_fn +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define hidden +fn private_fn() -> i32 { + 3 +} diff --git a/tests/codegen-llvm/link_section.rs b/tests/codegen-llvm/link_section.rs new file mode 100644 index 00000000000..f62f6948079 --- /dev/null +++ b/tests/codegen-llvm/link_section.rs @@ -0,0 +1,35 @@ +//@ ignore-wasm32 custom sections work differently on wasm +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +// CHECK: @VAR1 = {{(dso_local )?}}constant [4 x i8] c"\01\00\00\00", section ".test_one" +#[no_mangle] +#[link_section = ".test_one"] +#[cfg(target_endian = "little")] +pub static VAR1: u32 = 1; + +#[no_mangle] +#[link_section = ".test_one"] +#[cfg(target_endian = "big")] +pub static VAR1: u32 = 0x01000000; + +pub enum E { + A(u32), + B(f32), +} + +// CHECK: @VAR2 = {{(dso_local )?}}constant {{.*}}, section ".test_two" +#[no_mangle] +#[link_section = ".test_two"] +pub static VAR2: E = E::A(666); + +// CHECK: @VAR3 = {{(dso_local )?}}constant {{.*}}, section ".test_three" +#[no_mangle] +#[link_section = ".test_three"] +pub static VAR3: E = E::B(1.); + +// CHECK: define {{(dso_local )?}}void @fn1() {{.*}} section ".test_four" { +#[no_mangle] +#[link_section = ".test_four"] +pub fn fn1() {} diff --git a/tests/codegen-llvm/llvm-ident.rs b/tests/codegen-llvm/llvm-ident.rs new file mode 100644 index 00000000000..923e99bb282 --- /dev/null +++ b/tests/codegen-llvm/llvm-ident.rs @@ -0,0 +1,15 @@ +// Verifies that the `!llvm.ident` named metadata is emitted. +// +//@ revisions: NONE OPT DEBUG +// +//@ [OPT] compile-flags: -Copt-level=2 +//@ [DEBUG] compile-flags: -Cdebuginfo=2 + +// The named metadata should contain a single metadata node (see +// `LLVMRustPrepareThinLTOImport` for details). +// CHECK: !llvm.ident = !{![[ID:[0-9]+]]} + +// In addition, check that the metadata node has the expected content. +// CHECK: ![[ID]] = !{!"rustc version 1.{{.*}}"} + +fn main() {} diff --git a/tests/codegen-llvm/llvm_module_flags.rs b/tests/codegen-llvm/llvm_module_flags.rs new file mode 100644 index 00000000000..d3fae0c3927 --- /dev/null +++ b/tests/codegen-llvm/llvm_module_flags.rs @@ -0,0 +1,7 @@ +// Test for -Z llvm_module_flags +//@ compile-flags: -Z llvm_module_flag=foo:u32:123:error -Z llvm_module_flag=bar:u32:42:max + +fn main() {} + +// CHECK: !{i32 1, !"foo", i32 123} +// CHECK: !{i32 7, !"bar", i32 42} diff --git a/tests/codegen-llvm/loads.rs b/tests/codegen-llvm/loads.rs new file mode 100644 index 00000000000..88d67642b72 --- /dev/null +++ b/tests/codegen-llvm/loads.rs @@ -0,0 +1,152 @@ +//@ compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 -Copt-level=3 + +#![crate_type = "lib"] + +use std::mem::MaybeUninit; +use std::num::NonZero; + +pub struct Bytes { + a: u8, + b: u8, + c: u8, + d: u8, +} + +#[derive(Copy, Clone)] +pub enum MyBool { + True, + False, +} + +#[repr(align(16))] +pub struct Align16(u128); + +// CHECK: @ptr_alignment_helper({{.*}}align [[PTR_ALIGNMENT:[0-9]+]] +#[no_mangle] +pub fn ptr_alignment_helper(x: &&()) {} + +// CHECK-LABEL: @load_ref +#[no_mangle] +pub fn load_ref<'a>(x: &&'a i32) -> &'a i32 { + // CHECK: load ptr, ptr %x, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META:[0-9]+]], !noundef !{{[0-9]+}} + *x +} + +// CHECK-LABEL: @load_ref_higher_alignment +#[no_mangle] +pub fn load_ref_higher_alignment<'a>(x: &&'a Align16) -> &'a Align16 { + // CHECK: load ptr, ptr %x, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_16_META:[0-9]+]], !noundef !{{[0-9]+}} + *x +} + +// CHECK-LABEL: @load_scalar_pair +#[no_mangle] +pub fn load_scalar_pair<'a>(x: &(&'a i32, &'a Align16)) -> (&'a i32, &'a Align16) { + // CHECK: load ptr, ptr %{{.+}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META]], !noundef !{{[0-9]+}} + // CHECK: load ptr, ptr %{{.+}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_16_META]], !noundef !{{[0-9]+}} + *x +} + +// CHECK-LABEL: @load_raw_pointer +#[no_mangle] +pub fn load_raw_pointer<'a>(x: &*const i32) -> *const i32 { + // loaded raw pointer should not have !nonnull or !align metadata + // CHECK: load ptr, ptr %x, align [[PTR_ALIGNMENT]], !noundef ![[NOUNDEF:[0-9]+]]{{$}} + *x +} + +// CHECK-LABEL: @load_box +#[no_mangle] +pub fn load_box<'a>(x: Box>) -> Box { + // CHECK: load ptr, ptr %{{.*}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META]], !noundef !{{[0-9]+}} + *x +} + +// CHECK-LABEL: @load_bool +#[no_mangle] +pub fn load_bool(x: &bool) -> bool { + // CHECK: load i8, ptr %x, align 1, !range ![[BOOL_RANGE:[0-9]+]], !noundef !{{[0-9]+}} + *x +} + +// CHECK-LABEL: @load_maybeuninit_bool +#[no_mangle] +pub fn load_maybeuninit_bool(x: &MaybeUninit) -> MaybeUninit { + // CHECK: load i8, ptr %x, align 1{{$}} + *x +} + +// CHECK-LABEL: @load_enum_bool +#[no_mangle] +pub fn load_enum_bool(x: &MyBool) -> MyBool { + // CHECK: load i8, ptr %x, align 1, !range ![[BOOL_RANGE]], !noundef !{{[0-9]+}} + *x +} + +// CHECK-LABEL: @load_maybeuninit_enum_bool +#[no_mangle] +pub fn load_maybeuninit_enum_bool(x: &MaybeUninit) -> MaybeUninit { + // CHECK: load i8, ptr %x, align 1{{$}} + *x +} + +// CHECK-LABEL: @load_int +#[no_mangle] +pub fn load_int(x: &u16) -> u16 { + // CHECK: load i16, ptr %x, align 2, !noundef ![[NOUNDEF]]{{$}} + *x +} + +// CHECK-LABEL: @load_nonzero_int +#[no_mangle] +pub fn load_nonzero_int(x: &NonZero) -> NonZero { + // CHECK: load i16, ptr %x, align 2, !range ![[NONZEROU16_RANGE:[0-9]+]], !noundef !{{[0-9]+}} + *x +} + +// CHECK-LABEL: @load_option_nonzero_int +#[no_mangle] +pub fn load_option_nonzero_int(x: &Option>) -> Option> { + // CHECK: load i16, ptr %x, align 2, !noundef ![[NOUNDEF]]{{$}} + *x +} + +// CHECK-LABEL: @borrow +#[no_mangle] +pub fn borrow(x: &i32) -> &i32 { + // CHECK: load ptr, ptr %x{{.*}}, !nonnull + &x; // keep variable in an alloca + x +} + +// CHECK-LABEL: @_box +#[no_mangle] +pub fn _box(x: Box) -> i32 { + // CHECK: load ptr, ptr %x{{.*}}, align [[PTR_ALIGNMENT]] + *x +} + +// CHECK-LABEL: small_array_alignment +// The array is loaded as i32, but its alignment is lower, go with 1 byte to avoid target +// dependent alignment +#[no_mangle] +pub fn small_array_alignment(x: [i8; 4]) -> [i8; 4] { + // CHECK: [[VAR:%[0-9]+]] = load i32, ptr %{{.*}}, align 1 + // CHECK: ret i32 [[VAR]] + x +} + +// CHECK-LABEL: small_struct_alignment +// The struct is loaded as i32, but its alignment is lower, go with 1 byte to avoid target +// dependent alignment +#[no_mangle] +pub fn small_struct_alignment(x: Bytes) -> Bytes { + // CHECK: [[VAR:%[0-9]+]] = load i32, ptr %{{.*}}, align 1 + // CHECK: ret i32 [[VAR]] + x +} + +// CHECK-DAG: ![[BOOL_RANGE]] = !{i8 0, i8 2} +// CHECK-DAG: ![[NONZEROU16_RANGE]] = !{i16 1, i16 0} +// CHECK-DAG: ![[ALIGN_4_META]] = !{i64 4} +// CHECK-DAG: ![[ALIGN_16_META]] = !{i64 16} diff --git a/tests/codegen-llvm/local-generics-in-exe-internalized.rs b/tests/codegen-llvm/local-generics-in-exe-internalized.rs new file mode 100644 index 00000000000..8dbc41382b5 --- /dev/null +++ b/tests/codegen-llvm/local-generics-in-exe-internalized.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -C no-prepopulate-passes -Zshare-generics=yes -Zinline-mir=no + +// Check that local generics are internalized if they are in the same CGU + +// CHECK-LABEL: ; local_generics_in_exe_internalized::foo +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define internal +pub fn foo(x: T, y: T) -> (T, T) { + (x, y) +} + +fn main() { + let _ = foo(0u8, 1u8); +} diff --git a/tests/codegen-llvm/loongarch-abi/call-llvm-intrinsics.rs b/tests/codegen-llvm/loongarch-abi/call-llvm-intrinsics.rs new file mode 100644 index 00000000000..9a50f7b8e3a --- /dev/null +++ b/tests/codegen-llvm/loongarch-abi/call-llvm-intrinsics.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -C no-prepopulate-passes + +//@ only-loongarch64 + +#![feature(link_llvm_intrinsics)] +#![crate_type = "lib"] + +struct A; + +impl Drop for A { + fn drop(&mut self) { + println!("A"); + } +} + +extern "C" { + #[link_name = "llvm.sqrt.f32"] + fn sqrt(x: f32) -> f32; +} + +pub fn do_call() { + let _a = A; + + unsafe { + // Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them + // CHECK: store float 4.000000e+00, ptr %{{.}}, align 4 + // CHECK: load float, ptr %{{.}}, align 4 + // CHECK: call float @llvm.sqrt.f32(float %{{.}} + sqrt(4.0); + } +} diff --git a/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs b/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs new file mode 100644 index 00000000000..93c8d60930b --- /dev/null +++ b/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs @@ -0,0 +1,299 @@ +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes --target loongarch64-unknown-linux-gnu +//@ needs-llvm-components: loongarch + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK: define void @f_fpr_tracking(double %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, i8 noundef zeroext %i) +#[no_mangle] +pub extern "C" fn f_fpr_tracking( + a: f64, + b: f64, + c: f64, + d: f64, + e: f64, + f: f64, + g: f64, + h: f64, + i: u8, +) { +} + +#[repr(C)] +pub struct Double { + f: f64, +} + +#[repr(C)] +pub struct DoubleDouble { + f: f64, + g: f64, +} + +#[repr(C)] +pub struct DoubleFloat { + f: f64, + g: f32, +} + +// CHECK: define void @f_double_s_arg(double %0) +#[no_mangle] +pub extern "C" fn f_double_s_arg(a: Double) {} + +// CHECK: define double @f_ret_double_s() +#[no_mangle] +pub extern "C" fn f_ret_double_s() -> Double { + Double { f: 1. } +} + +// CHECK: define void @f_double_double_s_arg({ double, double } %0) +#[no_mangle] +pub extern "C" fn f_double_double_s_arg(a: DoubleDouble) {} + +// CHECK: define { double, double } @f_ret_double_double_s() +#[no_mangle] +pub extern "C" fn f_ret_double_double_s() -> DoubleDouble { + DoubleDouble { f: 1., g: 2. } +} + +// CHECK: define void @f_double_float_s_arg({ double, float } %0) +#[no_mangle] +pub extern "C" fn f_double_float_s_arg(a: DoubleFloat) {} + +// CHECK: define { double, float } @f_ret_double_float_s() +#[no_mangle] +pub extern "C" fn f_ret_double_float_s() -> DoubleFloat { + DoubleFloat { f: 1., g: 2. } +} + +// CHECK: define void @f_double_double_s_arg_insufficient_fprs(double %0, double %1, double %2, double %3, double %4, double %5, double %6, [2 x i64] %7) +#[no_mangle] +pub extern "C" fn f_double_double_s_arg_insufficient_fprs( + a: f64, + b: f64, + c: f64, + d: f64, + e: f64, + f: f64, + g: f64, + h: DoubleDouble, +) { +} + +#[repr(C)] +pub struct DoubleInt8 { + f: f64, + i: i8, +} + +#[repr(C)] +pub struct DoubleUInt8 { + f: f64, + i: u8, +} + +#[repr(C)] +pub struct DoubleInt32 { + f: f64, + i: i32, +} + +#[repr(C)] +pub struct DoubleInt64 { + f: f64, + i: i64, +} + +// CHECK: define void @f_double_int8_s_arg({ double, i8 } %0) +#[no_mangle] +pub extern "C" fn f_double_int8_s_arg(a: DoubleInt8) {} + +// CHECK: define { double, i8 } @f_ret_double_int8_s() +#[no_mangle] +pub extern "C" fn f_ret_double_int8_s() -> DoubleInt8 { + DoubleInt8 { f: 1., i: 2 } +} + +// CHECK: define void @f_double_int32_s_arg({ double, i32 } %0) +#[no_mangle] +pub extern "C" fn f_double_int32_s_arg(a: DoubleInt32) {} + +// CHECK: define { double, i32 } @f_ret_double_int32_s() +#[no_mangle] +pub extern "C" fn f_ret_double_int32_s() -> DoubleInt32 { + DoubleInt32 { f: 1., i: 2 } +} + +// CHECK: define void @f_double_uint8_s_arg({ double, i8 } %0) +#[no_mangle] +pub extern "C" fn f_double_uint8_s_arg(a: DoubleUInt8) {} + +// CHECK: define { double, i8 } @f_ret_double_uint8_s() +#[no_mangle] +pub extern "C" fn f_ret_double_uint8_s() -> DoubleUInt8 { + DoubleUInt8 { f: 1., i: 2 } +} + +// CHECK: define void @f_double_int64_s_arg({ double, i64 } %0) +#[no_mangle] +pub extern "C" fn f_double_int64_s_arg(a: DoubleInt64) {} + +// CHECK: define { double, i64 } @f_ret_double_int64_s() +#[no_mangle] +pub extern "C" fn f_ret_double_int64_s() -> DoubleInt64 { + DoubleInt64 { f: 1., i: 2 } +} + +// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 noundef signext %a, i32 noundef signext %b, i32 noundef signext %c, i32 noundef signext %d, i32 noundef signext %e, i32 noundef signext %f, i32 noundef signext %g, i32 noundef signext %h, [2 x i64] %0) +#[no_mangle] +pub extern "C" fn f_double_int8_s_arg_insufficient_gprs( + a: i32, + b: i32, + c: i32, + d: i32, + e: i32, + f: i32, + g: i32, + h: i32, + i: DoubleInt8, +) { +} + +// CHECK: define void @f_struct_double_int8_insufficient_fprs(float %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, [2 x i64] %8) +#[no_mangle] +pub extern "C" fn f_struct_double_int8_insufficient_fprs( + a: f32, + b: f64, + c: f64, + d: f64, + e: f64, + f: f64, + g: f64, + h: f64, + i: DoubleInt8, +) { +} + +#[repr(C)] +pub struct DoubleArr1 { + a: [f64; 1], +} + +// CHECK: define void @f_doublearr1_s_arg(double %0) +#[no_mangle] +pub extern "C" fn f_doublearr1_s_arg(a: DoubleArr1) {} + +// CHECK: define double @f_ret_doublearr1_s() +#[no_mangle] +pub extern "C" fn f_ret_doublearr1_s() -> DoubleArr1 { + DoubleArr1 { a: [1.] } +} + +#[repr(C)] +pub struct DoubleArr2 { + a: [f64; 2], +} + +// CHECK: define void @f_doublearr2_s_arg({ double, double } %0) +#[no_mangle] +pub extern "C" fn f_doublearr2_s_arg(a: DoubleArr2) {} + +// CHECK: define { double, double } @f_ret_doublearr2_s() +#[no_mangle] +pub extern "C" fn f_ret_doublearr2_s() -> DoubleArr2 { + DoubleArr2 { a: [1., 2.] } +} + +#[repr(C)] +pub struct Tricky1 { + f: [f64; 1], +} + +#[repr(C)] +pub struct DoubleArr2Tricky1 { + g: [Tricky1; 2], +} + +// CHECK: define void @f_doublearr2_tricky1_s_arg({ double, double } %0) +#[no_mangle] +pub extern "C" fn f_doublearr2_tricky1_s_arg(a: DoubleArr2Tricky1) {} + +// CHECK: define { double, double } @f_ret_doublearr2_tricky1_s() +#[no_mangle] +pub extern "C" fn f_ret_doublearr2_tricky1_s() -> DoubleArr2Tricky1 { + DoubleArr2Tricky1 { g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } +} + +#[repr(C)] +pub struct EmptyStruct {} + +#[repr(C)] +pub struct DoubleArr2Tricky2 { + s: EmptyStruct, + g: [Tricky1; 2], +} + +// CHECK: define void @f_doublearr2_tricky2_s_arg({ double, double } %0) +#[no_mangle] +pub extern "C" fn f_doublearr2_tricky2_s_arg(a: DoubleArr2Tricky2) {} + +// CHECK: define { double, double } @f_ret_doublearr2_tricky2_s() +#[no_mangle] +pub extern "C" fn f_ret_doublearr2_tricky2_s() -> DoubleArr2Tricky2 { + DoubleArr2Tricky2 { s: EmptyStruct {}, g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } +} + +#[repr(C)] +pub struct IntDoubleInt { + a: i32, + b: f64, + c: i32, +} + +// CHECK: define void @f_int_double_int_s_arg(ptr noalias{{( nocapture)?}} noundef align 8{{( captures\(none\))?}} dereferenceable(24) %a) +#[no_mangle] +pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {} + +// CHECK: define void @f_ret_int_double_int_s(ptr{{( dead_on_unwind)?}} noalias{{( nocapture)?}} noundef{{( writable)?}} sret([24 x i8]) align 8{{( captures\(none\))?}} dereferenceable(24) %_0) +#[no_mangle] +pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt { + IntDoubleInt { a: 1, b: 2., c: 3 } +} + +#[repr(C)] +pub struct CharCharDouble { + a: u8, + b: u8, + c: f64, +} + +// CHECK: define void @f_char_char_double_s_arg([2 x i64] %0) +#[no_mangle] +pub extern "C" fn f_char_char_double_s_arg(a: CharCharDouble) {} + +// CHECK: define [2 x i64] @f_ret_char_char_double_s() +#[no_mangle] +pub extern "C" fn f_ret_char_char_double_s() -> CharCharDouble { + CharCharDouble { a: 1, b: 2, c: 3. } +} + +#[repr(C)] +pub union DoubleU { + a: f64, +} + +// CHECK: define void @f_double_u_arg(i64 %0) +#[no_mangle] +pub extern "C" fn f_double_u_arg(a: DoubleU) {} + +// CHECK: define i64 @f_ret_double_u() +#[no_mangle] +pub extern "C" fn f_ret_double_u() -> DoubleU { + unsafe { DoubleU { a: 1. } } +} diff --git a/tests/codegen-llvm/lto-removes-invokes.rs b/tests/codegen-llvm/lto-removes-invokes.rs new file mode 100644 index 00000000000..3640bd1ab86 --- /dev/null +++ b/tests/codegen-llvm/lto-removes-invokes.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -C lto -C panic=abort -Copt-level=3 +//@ no-prefer-dynamic + +fn main() { + foo(); +} + +#[no_mangle] +#[inline(never)] +fn foo() { + let _a = Box::new(3); + bar(); + // CHECK-LABEL: define dso_local void @foo + // CHECK: call void @bar +} + +#[inline(never)] +#[no_mangle] +fn bar() { + println!("hello!"); +} diff --git a/tests/codegen-llvm/macos/i686-macosx-deployment-target.rs b/tests/codegen-llvm/macos/i686-macosx-deployment-target.rs new file mode 100644 index 00000000000..cfa91e61cb0 --- /dev/null +++ b/tests/codegen-llvm/macos/i686-macosx-deployment-target.rs @@ -0,0 +1,23 @@ +// Checks that we correctly modify the target when MACOSX_DEPLOYMENT_TARGET is set. +// See issue #60235. + +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 --target=i686-apple-darwin --crate-type=rlib +//@ needs-llvm-components: x86 +//@ rustc-env:MACOSX_DEPLOYMENT_TARGET=10.14 +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(C)] +pub struct Bool { + b: bool, +} + +// CHECK: target triple = "i686-apple-macosx10.14.0" +#[no_mangle] +pub extern "C" fn structbool() -> Bool { + Bool { b: true } +} diff --git a/tests/codegen-llvm/macos/i686-no-macosx-deployment-target.rs b/tests/codegen-llvm/macos/i686-no-macosx-deployment-target.rs new file mode 100644 index 00000000000..25ec5f6acbb --- /dev/null +++ b/tests/codegen-llvm/macos/i686-no-macosx-deployment-target.rs @@ -0,0 +1,23 @@ +// Checks that we leave the target alone MACOSX_DEPLOYMENT_TARGET is unset. +// See issue #60235. + +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 --target=i686-apple-darwin --crate-type=rlib +//@ needs-llvm-components: x86 +//@ unset-rustc-env:MACOSX_DEPLOYMENT_TARGET +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(C)] +pub struct Bool { + b: bool, +} + +// CHECK: target triple = "i686-apple-macosx10.12.0" +#[no_mangle] +pub extern "C" fn structbool() -> Bool { + Bool { b: true } +} diff --git a/tests/codegen-llvm/macos/x86_64-macosx-deployment-target.rs b/tests/codegen-llvm/macos/x86_64-macosx-deployment-target.rs new file mode 100644 index 00000000000..8ea95ba0575 --- /dev/null +++ b/tests/codegen-llvm/macos/x86_64-macosx-deployment-target.rs @@ -0,0 +1,23 @@ +// Checks that we correctly modify the target when MACOSX_DEPLOYMENT_TARGET is set. +// See issue #60235. + +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 --target=x86_64-apple-darwin --crate-type=rlib +//@ needs-llvm-components: x86 +//@ rustc-env:MACOSX_DEPLOYMENT_TARGET=10.14 +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(C)] +pub struct Bool { + b: bool, +} + +// CHECK: target triple = "x86_64-apple-macosx10.14.0" +#[no_mangle] +pub extern "C" fn structbool() -> Bool { + Bool { b: true } +} diff --git a/tests/codegen-llvm/macos/x86_64-no-macosx-deployment-target.rs b/tests/codegen-llvm/macos/x86_64-no-macosx-deployment-target.rs new file mode 100644 index 00000000000..474094957ae --- /dev/null +++ b/tests/codegen-llvm/macos/x86_64-no-macosx-deployment-target.rs @@ -0,0 +1,23 @@ +// Checks that we leave the target alone when MACOSX_DEPLOYMENT_TARGET is unset. +// See issue #60235. + +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 --target=x86_64-apple-darwin --crate-type=rlib +//@ needs-llvm-components: x86 +//@ unset-rustc-env:MACOSX_DEPLOYMENT_TARGET +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(C)] +pub struct Bool { + b: bool, +} + +// CHECK: target triple = "x86_64-apple-macosx10.12.0" +#[no_mangle] +pub extern "C" fn structbool() -> Bool { + Bool { b: true } +} diff --git a/tests/codegen-llvm/mainsubprogram.rs b/tests/codegen-llvm/mainsubprogram.rs new file mode 100644 index 00000000000..ce3fe3c8608 --- /dev/null +++ b/tests/codegen-llvm/mainsubprogram.rs @@ -0,0 +1,12 @@ +// This test depends on a patch that was committed to upstream LLVM +// before 4.0, formerly backported to the Rust LLVM fork. + +//@ ignore-apple +//@ ignore-wasi + +//@ compile-flags: -g -C no-prepopulate-passes + +// CHECK-LABEL: @main +// CHECK: {{.*}}DISubprogram{{.*}}name: "main",{{.*}}DI{{(SP)?}}FlagMainSubprogram{{.*}} + +pub fn main() {} diff --git a/tests/codegen-llvm/match-optimized.rs b/tests/codegen-llvm/match-optimized.rs new file mode 100644 index 00000000000..7b409e619a8 --- /dev/null +++ b/tests/codegen-llvm/match-optimized.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=3 + +#![crate_type = "lib"] + +pub enum E { + A, + B, + C, +} + +// CHECK-LABEL: @exhaustive_match +#[no_mangle] +pub fn exhaustive_match(e: E) -> u8 { + // CHECK: switch{{.*}}, label %[[OTHERWISE:[a-zA-Z0-9_]+]] [ + // CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[A:[a-zA-Z0-9_]+]] + // CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[B:[a-zA-Z0-9_]+]] + // CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[C:[a-zA-Z0-9_]+]] + // CHECK-NEXT: ] + // CHECK: [[OTHERWISE]]: + // CHECK-NEXT: unreachable + // + // CHECK: [[A]]: + // CHECK-NEXT: store i8 0, ptr %_0, align 1 + // CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]] + // CHECK: [[B]]: + // CHECK-NEXT: store i8 1, ptr %_0, align 1 + // CHECK-NEXT: br label %[[EXIT]] + // CHECK: [[C]]: + // CHECK-NEXT: store i8 3, ptr %_0, align 1 + // CHECK-NEXT: br label %[[EXIT]] + match e { + E::A => 0, + E::B => 1, + E::C => 3, + } +} + +#[repr(u16)] +pub enum E2 { + A = 13, + B = 42, +} + +// For optimized code we produce a switch with an unreachable target as the `otherwise` so LLVM +// knows the possible values. Compare with `tests/codegen/match-unoptimized.rs`. + +// CHECK-LABEL: @exhaustive_match_2 +#[no_mangle] +pub fn exhaustive_match_2(e: E2) -> u8 { + // CHECK: switch i16 %{{.+}}, label %[[UNREACH:.+]] [ + // CHECK-NEXT: i16 13, + // CHECK-NEXT: i16 42, + // CHECK-NEXT: ] + // CHECK: [[UNREACH]]: + // CHECK-NEXT: unreachable + match e { + E2::A => 0, + E2::B => 1, + } +} diff --git a/tests/codegen-llvm/match-optimizes-away.rs b/tests/codegen-llvm/match-optimizes-away.rs new file mode 100644 index 00000000000..5e9be72a09f --- /dev/null +++ b/tests/codegen-llvm/match-optimizes-away.rs @@ -0,0 +1,41 @@ +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled +#![crate_type = "lib"] + +pub enum Three { + A, + B, + C, +} + +#[repr(u16)] +pub enum Four { + A, + B, + C, + D, +} + +#[no_mangle] +pub fn three_valued(x: Three) -> Three { + // CHECK-LABEL: i8 @three_valued(i8{{.+}}%x) + // CHECK-NEXT: {{^.*:$}} + // CHECK-NEXT: ret i8 %x + match x { + Three::A => Three::A, + Three::B => Three::B, + Three::C => Three::C, + } +} + +#[no_mangle] +pub fn four_valued(x: Four) -> Four { + // CHECK-LABEL: i16 @four_valued(i16{{.+}}%x) + // CHECK-NEXT: {{^.*:$}} + // CHECK-NEXT: ret i16 %x + match x { + Four::A => Four::A, + Four::B => Four::B, + Four::C => Four::C, + Four::D => Four::D, + } +} diff --git a/tests/codegen-llvm/match-unoptimized.rs b/tests/codegen-llvm/match-unoptimized.rs new file mode 100644 index 00000000000..3dfe78c3e16 --- /dev/null +++ b/tests/codegen-llvm/match-unoptimized.rs @@ -0,0 +1,23 @@ +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 + +#![crate_type = "lib"] + +#[repr(u16)] +pub enum E2 { + A = 13, + B = 42, +} + +// For unoptimized code we produce a `br` instead of a `switch`. Compare with +// `tests/codegen/match-optimized.rs` + +// CHECK-LABEL: @exhaustive_match_2 +#[no_mangle] +pub fn exhaustive_match_2(e: E2) -> u8 { + // CHECK: %[[CMP:.+]] = icmp eq i16 %{{.+}}, 13 + // CHECK-NEXT: br i1 %[[CMP:.+]], + match e { + E2::A => 0, + E2::B => 1, + } +} diff --git a/tests/codegen-llvm/maybeuninit-rvo.rs b/tests/codegen-llvm/maybeuninit-rvo.rs new file mode 100644 index 00000000000..097aa610f1b --- /dev/null +++ b/tests/codegen-llvm/maybeuninit-rvo.rs @@ -0,0 +1,34 @@ +//@ compile-flags: -Copt-level=3 +//@ needs-unwind +#![feature(c_unwind)] +#![crate_type = "lib"] + +pub struct Foo([u8; 1000]); + +extern "C" { + fn init(p: *mut Foo); +} + +pub fn new_from_uninit() -> Foo { + // CHECK-LABEL: new_from_uninit + // CHECK-NOT: call void @llvm.memcpy. + let mut x = std::mem::MaybeUninit::uninit(); + unsafe { + init(x.as_mut_ptr()); + x.assume_init() + } +} + +extern "C-unwind" { + fn init_unwind(p: *mut Foo); +} + +pub fn new_from_uninit_unwind() -> Foo { + // CHECK-LABEL: new_from_uninit_unwind + // CHECK-NOT: call void @llvm.memcpy. + let mut x = std::mem::MaybeUninit::uninit(); + unsafe { + init_unwind(x.as_mut_ptr()); + x.assume_init() + } +} diff --git a/tests/codegen-llvm/mem-replace-big-type.rs b/tests/codegen-llvm/mem-replace-big-type.rs new file mode 100644 index 00000000000..0b2229ba7d1 --- /dev/null +++ b/tests/codegen-llvm/mem-replace-big-type.rs @@ -0,0 +1,36 @@ +// This test ensures that `mem::replace::` only ever calls `@llvm.memcpy` +// with `size_of::()` as the size, and never goes through any wrapper that +// may e.g. multiply `size_of::()` with a variable "count" (which is only +// known to be `1` after inlining). + +//@ compile-flags: -C no-prepopulate-passes -Zinline-mir=no +//@ ignore-std-debug-assertions +// Reason: precondition checks in ptr::read make them a bad candidate for MIR inlining +//@ needs-deterministic-layouts + +#![crate_type = "lib"] + +#[repr(C, align(8))] +pub struct Big([u64; 7]); +pub fn replace_big(dst: &mut Big, src: Big) -> Big { + // Back in 1.68, this emitted six `memcpy`s. + // `read_via_copy` in 1.69 got that down to three. + // `write_via_move` and nvro get this down to the essential two. + std::mem::replace(dst, src) +} + +// NOTE(eddyb) the `CHECK-NOT`s ensure that the only calls of `@llvm.memcpy` in +// the entire output, are the direct calls we want, from `ptr::replace`. + +// CHECK-NOT: call void @llvm.memcpy + +// For a large type, we expect exactly three `memcpy`s +// CHECK-LABEL: define internal void @{{.+}}mem{{.+}}replace{{.+}}(ptr +// CHECK-SAME: sret([56 x i8]){{.+}}[[RESULT:%.+]], ptr{{.+}}%dest, ptr{{.+}}%src) +// CHECK-NOT: call void @llvm.memcpy +// CHECK: call void @llvm.memcpy.{{.+}}(ptr align 8 [[RESULT]], ptr align 8 %dest, i{{.*}} 56, i1 false) +// CHECK-NOT: call void @llvm.memcpy +// CHECK: call void @llvm.memcpy.{{.+}}(ptr align 8 %dest, ptr align 8 %src, i{{.*}} 56, i1 false) +// CHECK-NOT: call void @llvm.memcpy + +// CHECK-NOT: call void @llvm.memcpy diff --git a/tests/codegen-llvm/mem-replace-simple-type.rs b/tests/codegen-llvm/mem-replace-simple-type.rs new file mode 100644 index 00000000000..9f3c6bacb71 --- /dev/null +++ b/tests/codegen-llvm/mem-replace-simple-type.rs @@ -0,0 +1,54 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes +//@ only-x86_64 (to not worry about usize differing) +//@ ignore-std-debug-assertions +// Reason: precondition checks make mem::replace not a candidate for MIR inlining + +#![crate_type = "lib"] + +#[no_mangle] +// CHECK-LABEL: @replace_usize( +pub fn replace_usize(r: &mut usize, v: usize) -> usize { + // CHECK-NOT: alloca + // CHECK: %[[R:.+]] = load i64, ptr %r + // CHECK: store i64 %v, ptr %r + // CHECK: ret i64 %[[R]] + std::mem::replace(r, v) +} + +#[no_mangle] +// CHECK-LABEL: @replace_ref_str( +pub fn replace_ref_str<'a>(r: &mut &'a str, v: &'a str) -> &'a str { + // CHECK-NOT: alloca + // CHECK: %[[A:.+]] = load ptr + // CHECK: %[[B:.+]] = load i64 + // CHECK-NOT: store + // CHECK-NOT: load + // CHECK: store ptr + // CHECK: store i64 + // CHECK-NOT: load + // CHECK-NOT: store + // CHECK: %[[P1:.+]] = insertvalue { ptr, i64 } poison, ptr %[[A]], 0 + // CHECK: %[[P2:.+]] = insertvalue { ptr, i64 } %[[P1]], i64 %[[B]], 1 + // CHECK: ret { ptr, i64 } %[[P2]] + std::mem::replace(r, v) +} + +#[no_mangle] +// CHECK-LABEL: @replace_short_array_3( +// CHECK-SAME: ptr{{.+}}sret{{.+}}%[[RET:.+]], ptr{{.+}}%r, ptr{{.+}}%v +pub fn replace_short_array_3(r: &mut [u32; 3], v: [u32; 3]) -> [u32; 3] { + // CHECK-NOT: alloca + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[RET]], ptr align 4 %r, i64 12, i1 false) + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %r, ptr align 4 %v, i64 12, i1 false) + std::mem::replace(r, v) +} + +#[no_mangle] +// CHECK-LABEL: @replace_short_array_4( +// CHECK-SAME: ptr{{.+}}sret{{.+}}%[[RET:.+]], ptr{{.+}}%r, ptr{{.+}}%v +pub fn replace_short_array_4(r: &mut [u32; 4], v: [u32; 4]) -> [u32; 4] { + // CHECK-NOT: alloca + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[RET]], ptr align 4 %r, i64 16, i1 false) + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %r, ptr align 4 %v, i64 16, i1 false) + std::mem::replace(r, v) +} diff --git a/tests/codegen-llvm/merge-functions.rs b/tests/codegen-llvm/merge-functions.rs new file mode 100644 index 00000000000..b9d3727ce11 --- /dev/null +++ b/tests/codegen-llvm/merge-functions.rs @@ -0,0 +1,16 @@ +//@ revisions: O Os +//@[Os] compile-flags: -Copt-level=s +//@[O] compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +// CHECK: @func{{2|1}} = {{.*}}alias{{.*}}@func{{1|2}} + +#[no_mangle] +pub fn func1(c: char) -> bool { + c == 's' || c == 'm' || c == 'h' || c == 'd' || c == 'w' +} + +#[no_mangle] +pub fn func2(c: char) -> bool { + matches!(c, 's' | 'm' | 'h' | 'd' | 'w') +} diff --git a/tests/codegen-llvm/meta-filecheck/check-prefix.rs b/tests/codegen-llvm/meta-filecheck/check-prefix.rs new file mode 100644 index 00000000000..98bec68627e --- /dev/null +++ b/tests/codegen-llvm/meta-filecheck/check-prefix.rs @@ -0,0 +1,4 @@ +// Simple test that uses the default CHECK prefix and should always succeed. + +// CHECK: main +fn main() {} diff --git a/tests/codegen-llvm/meta-filecheck/filecheck-flags.rs b/tests/codegen-llvm/meta-filecheck/filecheck-flags.rs new file mode 100644 index 00000000000..8e451cf4fdc --- /dev/null +++ b/tests/codegen-llvm/meta-filecheck/filecheck-flags.rs @@ -0,0 +1,8 @@ +// Arguments provided via `filecheck-flags` should be passed to `filecheck`. + +//@ revisions: good bad +//@ [good] filecheck-flags: --check-prefix=CUSTOM +//@ [bad] should-fail + +// CUSTOM: main +fn main() {} diff --git a/tests/codegen-llvm/meta-filecheck/msvc-prefix-bad.rs b/tests/codegen-llvm/meta-filecheck/msvc-prefix-bad.rs new file mode 100644 index 00000000000..f9984c74e2a --- /dev/null +++ b/tests/codegen-llvm/meta-filecheck/msvc-prefix-bad.rs @@ -0,0 +1,7 @@ +// This is exactly like `msvc-prefix-good.rs`, except that it should always fail. + +//@ should-fail + +// MSVC: text that should not match +// NONMSVC: text that should not match +fn main() {} diff --git a/tests/codegen-llvm/meta-filecheck/no-directives.rs b/tests/codegen-llvm/meta-filecheck/no-directives.rs new file mode 100644 index 00000000000..2cab263604e --- /dev/null +++ b/tests/codegen-llvm/meta-filecheck/no-directives.rs @@ -0,0 +1,5 @@ +// A test that doesn't include any filecheck directives should fail. + +//@ should-fail + +fn main() {} diff --git a/tests/codegen-llvm/meta-filecheck/revision-prefix.rs b/tests/codegen-llvm/meta-filecheck/revision-prefix.rs new file mode 100644 index 00000000000..431066e3acc --- /dev/null +++ b/tests/codegen-llvm/meta-filecheck/revision-prefix.rs @@ -0,0 +1,8 @@ +// The current revision name is registered as a filecheck prefix. + +//@ revisions: GOOD BAD +//@ [BAD] should-fail + +// GOOD: main +// BAD: text that should not match +fn main() {} diff --git a/tests/codegen-llvm/method-declaration.rs b/tests/codegen-llvm/method-declaration.rs new file mode 100644 index 00000000000..de2f96a5151 --- /dev/null +++ b/tests/codegen-llvm/method-declaration.rs @@ -0,0 +1,26 @@ +//@ compile-flags: -g -Cno-prepopulate-passes + +// Verify that we added a declaration for a method. + +// CHECK: define{{.*}}@method{{.*}} !dbg ![[METHOD_DEF_DBG:[0-9]+]] +// CHECK: define{{.*}}@function{{.*}} !dbg ![[FUNC_DEF_DBG:[0-9]+]] + +#![crate_type = "lib"] + +// CHECK-DAG: ![[FOO_DBG:[0-9]+]] = !DICompositeType(tag: {{.*}} name: "Foo", {{.*}} identifier: +pub struct Foo; + +impl Foo { + // CHECK-DAG: ![[METHOD_DEF_DBG]] = distinct !DISubprogram(name: "method"{{.*}}, scope: ![[FOO_DBG]]{{.*}}DISPFlagDefinition{{.*}}, declaration: ![[METHOD_DECL_DBG:[0-9]+]] + // CHECK-DAG: ![[METHOD_DECL_DBG]] = !DISubprogram(name: "method"{{.*}}, scope: ![[FOO_DBG]] + #[no_mangle] + pub fn method() {} +} + +// CHECK: ![[FUNC_DEF_DBG]] = distinct !DISubprogram(name: "function" +// CHECK-NOT: declaration +// CHECK-SAME: DISPFlagDefinition +// CHECK-NOT: declaration +// CHECK-SAME: ) +#[no_mangle] +pub fn function() {} diff --git a/tests/codegen-llvm/min-function-alignment.rs b/tests/codegen-llvm/min-function-alignment.rs new file mode 100644 index 00000000000..ea5f957e81f --- /dev/null +++ b/tests/codegen-llvm/min-function-alignment.rs @@ -0,0 +1,48 @@ +//@ revisions: align16 align1024 +//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 -Clink-dead-code +//@ [align16] compile-flags: -Zmin-function-alignment=16 +//@ [align1024] compile-flags: -Zmin-function-alignment=1024 +//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) + +#![crate_type = "lib"] +// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity +#![feature(rustc_attrs)] +#![feature(fn_align)] + +// Functions without explicit alignment use the global minimum. +// +// NOTE: this function deliberately has zero (0) attributes! That is to make sure that +// `-Zmin-function-alignment` is applied regardless of whether attributes are used. +// +// CHECK-LABEL: no_explicit_align +// align16: align 16 +// align1024: align 1024 +pub fn no_explicit_align() {} + +// CHECK-LABEL: @lower_align +// align16: align 16 +// align1024: align 1024 +#[no_mangle] +#[rustc_align(8)] +pub fn lower_align() {} + +// the higher value of min-function-alignment and the align attribute wins out +// +// CHECK-LABEL: @higher_align +// align16: align 32 +// align1024: align 1024 +#[no_mangle] +#[rustc_align(32)] +pub fn higher_align() {} + +// cold functions follow the same rules as other functions +// +// in GCC, the `-falign-functions` does not apply to cold functions, but +// `-Zmin-function-alignment` applies to all functions. +// +// CHECK-LABEL: @no_explicit_align_cold +// align16: align 16 +// align1024: align 1024 +#[no_mangle] +#[cold] +pub fn no_explicit_align_cold() {} diff --git a/tests/codegen-llvm/mir-aggregate-no-alloca.rs b/tests/codegen-llvm/mir-aggregate-no-alloca.rs new file mode 100644 index 00000000000..77d367ed5da --- /dev/null +++ b/tests/codegen-llvm/mir-aggregate-no-alloca.rs @@ -0,0 +1,137 @@ +// 32-bit systems will return 128bit values using a return area pointer. +//@ revisions: bit32 bit64 +//@[bit32] only-32bit +//@[bit64] only-64bit +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z randomize-layout=no + +#![crate_type = "lib"] + +#[repr(transparent)] +pub struct Transparent32(u32); + +// CHECK: i32 @make_transparent(i32{{.*}} %x) +#[no_mangle] +pub fn make_transparent(x: u32) -> Transparent32 { + // CHECK-NOT: alloca + // CHECK: ret i32 %x + let a = Transparent32(x); + a +} + +// CHECK: i32 @make_closure(i32{{.*}} %x) +#[no_mangle] +pub fn make_closure(x: i32) -> impl Fn(i32) -> i32 { + // CHECK-NOT: alloca + // CHECK: ret i32 %x + move |y| x + y +} + +#[repr(transparent)] +pub struct TransparentPair((), (u16, u16), ()); + +// CHECK: { i16, i16 } @make_transparent_pair(i16 noundef %x.0, i16 noundef %x.1) +#[no_mangle] +pub fn make_transparent_pair(x: (u16, u16)) -> TransparentPair { + // CHECK-NOT: alloca + // CHECK: %[[TEMP0:.+]] = insertvalue { i16, i16 } poison, i16 %x.0, 0 + // CHECK: %[[TEMP1:.+]] = insertvalue { i16, i16 } %[[TEMP0]], i16 %x.1, 1 + // CHECK: ret { i16, i16 } %[[TEMP1]] + let a = TransparentPair((), x, ()); + a +} + +// CHECK-LABEL: { i32, i32 } @make_2_tuple(i32{{.*}} %x) +#[no_mangle] +pub fn make_2_tuple(x: u32) -> (u32, u32) { + // CHECK-NOT: alloca + // CHECK: %[[TEMP0:.+]] = insertvalue { i32, i32 } poison, i32 %x, 0 + // CHECK: %[[TEMP1:.+]] = insertvalue { i32, i32 } %[[TEMP0]], i32 %x, 1 + // CHECK: ret { i32, i32 } %[[TEMP1]] + let pair = (x, x); + pair +} + +// CHECK-LABEL: i8 @make_cell_of_bool(i1 noundef zeroext %b) +#[no_mangle] +pub fn make_cell_of_bool(b: bool) -> std::cell::Cell { + // CHECK: %[[BYTE:.+]] = zext i1 %b to i8 + // CHECK: ret i8 %[[BYTE]] + std::cell::Cell::new(b) +} + +// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16{{.*}} %s) +#[no_mangle] +pub fn make_cell_of_bool_and_short(b: bool, s: u16) -> std::cell::Cell<(bool, u16)> { + // CHECK-NOT: alloca + // CHECK: %[[BYTE:.+]] = zext i1 %b to i8 + // CHECK: %[[TEMP0:.+]] = insertvalue { i8, i16 } poison, i8 %[[BYTE]], 0 + // CHECK: %[[TEMP1:.+]] = insertvalue { i8, i16 } %[[TEMP0]], i16 %s, 1 + // CHECK: ret { i8, i16 } %[[TEMP1]] + std::cell::Cell::new((b, s)) +} + +// CHECK-LABEL: { i1, i1 } @make_tuple_of_bools(i1 noundef zeroext %a, i1 noundef zeroext %b) +#[no_mangle] +pub fn make_tuple_of_bools(a: bool, b: bool) -> (bool, bool) { + // CHECK-NOT: alloca + // CHECK: %[[TEMP0:.+]] = insertvalue { i1, i1 } poison, i1 %a, 0 + // CHECK: %[[TEMP1:.+]] = insertvalue { i1, i1 } %[[TEMP0]], i1 %b, 1 + // CHECK: ret { i1, i1 } %[[TEMP1]] + (a, b) +} + +pub struct Struct0(); + +// CHECK-LABEL: void @make_struct_0() +#[no_mangle] +pub fn make_struct_0() -> Struct0 { + // CHECK: ret void + let s = Struct0(); + s +} + +pub struct Struct1(i32); + +// CHECK-LABEL: i32 @make_struct_1(i32{{.*}} %a) +#[no_mangle] +pub fn make_struct_1(a: i32) -> Struct1 { + // CHECK: ret i32 %a + let s = Struct1(a); + s +} + +pub struct Struct2Asc(i16, i64); + +// bit32-LABEL: void @make_struct_2_asc({{.*}} sret({{[^,]*}}) {{.*}} %s, +// bit64-LABEL: { i64, i16 } @make_struct_2_asc( +// CHECK-SAME: i16{{.*}} %a, i64 noundef %b) +#[no_mangle] +pub fn make_struct_2_asc(a: i16, b: i64) -> Struct2Asc { + // CHECK-NOT: alloca + // bit32: %[[GEP:.+]] = getelementptr inbounds i8, ptr %s, i32 8 + // bit32: store i16 %a, ptr %[[GEP]] + // bit32: store i64 %b, ptr %s + // bit64: %[[TEMP0:.+]] = insertvalue { i64, i16 } poison, i64 %b, 0 + // bit64: %[[TEMP1:.+]] = insertvalue { i64, i16 } %[[TEMP0]], i16 %a, 1 + // bit64: ret { i64, i16 } %[[TEMP1]] + let s = Struct2Asc(a, b); + s +} + +pub struct Struct2Desc(i64, i16); + +// bit32-LABEL: void @make_struct_2_desc({{.*}} sret({{[^,]*}}) {{.*}} %s, +// bit64-LABEL: { i64, i16 } @make_struct_2_desc( +// CHECK-SAME: i64 noundef %a, i16{{.*}} %b) +#[no_mangle] +pub fn make_struct_2_desc(a: i64, b: i16) -> Struct2Desc { + // CHECK-NOT: alloca + // bit32: store i64 %a, ptr %s + // bit32: %[[GEP:.+]] = getelementptr inbounds i8, ptr %s, i32 8 + // bit32: store i16 %b, ptr %[[GEP]] + // bit64: %[[TEMP0:.+]] = insertvalue { i64, i16 } poison, i64 %a, 0 + // bit64: %[[TEMP1:.+]] = insertvalue { i64, i16 } %[[TEMP0]], i16 %b, 1 + // bit64: ret { i64, i16 } %[[TEMP1]] + let s = Struct2Desc(a, b); + s +} diff --git a/tests/codegen-llvm/mir-inlined-line-numbers.rs b/tests/codegen-llvm/mir-inlined-line-numbers.rs new file mode 100644 index 00000000000..cfe43a6cf89 --- /dev/null +++ b/tests/codegen-llvm/mir-inlined-line-numbers.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Copt-level=3 -g + +#![crate_type = "lib"] + +#[inline(always)] +fn foo() { + bar(); +} + +#[inline(never)] +#[no_mangle] +fn bar() { + panic!(); +} + +#[no_mangle] +pub fn example() { + foo(); +} + +// CHECK-LABEL: @example +// CHECK: tail call void @bar(){{( #[0-9]+)?}}, !dbg [[DBG_ID:![0-9]+]] +// CHECK: [[DBG_ID]] = !DILocation(line: 7, +// CHECK-SAME: inlinedAt: [[INLINE_ID:![0-9]+]]) +// CHECK: [[INLINE_ID]] = !DILocation(line: 18, diff --git a/tests/codegen-llvm/mir_zst_stores.rs b/tests/codegen-llvm/mir_zst_stores.rs new file mode 100644 index 00000000000..ff1d429cffd --- /dev/null +++ b/tests/codegen-llvm/mir_zst_stores.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +use std::marker::PhantomData; + +#[derive(Copy, Clone)] +struct Zst { + phantom: PhantomData, +} + +// CHECK-LABEL: @mir +// CHECK-NOT: store{{.*}}undef +#[no_mangle] +pub fn mir() { + let x = Zst { phantom: PhantomData }; + let y = (x, 0); + drop(y); + drop((0, x)); +} diff --git a/tests/codegen-llvm/move-before-nocapture-ref-arg.rs b/tests/codegen-llvm/move-before-nocapture-ref-arg.rs new file mode 100644 index 00000000000..2ebd645e1c3 --- /dev/null +++ b/tests/codegen-llvm/move-before-nocapture-ref-arg.rs @@ -0,0 +1,21 @@ +// Verify that move before the call of the function with noalias, nocapture, readonly. +// #107436 +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[repr(C)] +pub struct ThreeSlices<'a>(&'a [u32], &'a [u32], &'a [u32]); + +#[no_mangle] +pub fn sum_slices(val: ThreeSlices) -> u32 { + // CHECK-NOT: memcpy + let val = val; + sum(&val) +} + +#[no_mangle] +#[inline(never)] +pub fn sum(val: &ThreeSlices) -> u32 { + val.0.iter().sum::() + val.1.iter().sum::() + val.2.iter().sum::() +} diff --git a/tests/codegen-llvm/move-operands.rs b/tests/codegen-llvm/move-operands.rs new file mode 100644 index 00000000000..ddad231b762 --- /dev/null +++ b/tests/codegen-llvm/move-operands.rs @@ -0,0 +1,13 @@ +// Verify that optimized MIR only copies `a` once. +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes + +#![crate_type = "lib"] + +type T = [u8; 256]; + +#[no_mangle] +pub fn f(a: T, b: fn(_: T, _: T)) { + // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, {{.*}} 256, i1 false) + // CHECK-NOT: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, {{.*}} 256, i1 false) + b(a, a) +} diff --git a/tests/codegen-llvm/naked-asan.rs b/tests/codegen-llvm/naked-asan.rs new file mode 100644 index 00000000000..46218cf79d6 --- /dev/null +++ b/tests/codegen-llvm/naked-asan.rs @@ -0,0 +1,30 @@ +//@ add-core-stubs +//@ needs-llvm-components: x86 +//@ compile-flags: --target x86_64-unknown-linux-gnu -Zsanitizer=address -Ctarget-feature=-crt-static + +// Make sure we do not request sanitizers for naked functions. + +#![crate_type = "lib"] +#![feature(no_core)] +#![no_std] +#![no_core] +#![feature(abi_x86_interrupt)] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub fn caller() { + unsafe { asm!("call {}", sym page_fault_handler) } +} + +// CHECK: declare x86_intrcc void @page_fault_handler(){{.*}}#[[ATTRS:[0-9]+]] +#[unsafe(naked)] +#[no_mangle] +pub extern "x86-interrupt" fn page_fault_handler() { + naked_asm!("ud2") +} + +// CHECK: #[[ATTRS]] = +// CHECK-NOT: sanitize_address +// CHECK: !llvm.module.flags diff --git a/tests/codegen-llvm/naked-fn/aligned.rs b/tests/codegen-llvm/naked-fn/aligned.rs new file mode 100644 index 00000000000..d7281c4219a --- /dev/null +++ b/tests/codegen-llvm/naked-fn/aligned.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 +//@ needs-asm-support +//@ ignore-arm no "ret" mnemonic +//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) + +#![crate_type = "lib"] +// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity +#![feature(rustc_attrs)] +#![feature(fn_align)] + +use std::arch::naked_asm; + +// CHECK: .balign 16 +// CHECK-LABEL: naked_empty: +#[rustc_align(16)] +#[no_mangle] +#[unsafe(naked)] +pub extern "C" fn naked_empty() { + // CHECK: ret + naked_asm!("ret") +} diff --git a/tests/codegen-llvm/naked-fn/generics.rs b/tests/codegen-llvm/naked-fn/generics.rs new file mode 100644 index 00000000000..865be00d91e --- /dev/null +++ b/tests/codegen-llvm/naked-fn/generics.rs @@ -0,0 +1,111 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 + +#![crate_type = "lib"] + +use std::arch::naked_asm; + +#[no_mangle] +fn test(x: u64) { + // just making sure these symbols get used + using_const_generics::<1>(x); + using_const_generics::<2>(x); + + generic_function::(x as i64); + + let foo = Foo(x); + + foo.method(); + foo.trait_method(); +} + +// CHECK: .balign 4 +// CHECK: add rax, 2 +// CHECK: add rax, 42 + +// CHECK: .balign 4 +// CHECK: add rax, 1 +// CHECK: add rax, 42 + +#[unsafe(naked)] +pub extern "C" fn using_const_generics(x: u64) -> u64 { + const M: u64 = 42; + + naked_asm!( + "xor rax, rax", + "add rax, rdi", + "add rax, {}", + "add rax, {}", + "ret", + const N, + const M, + ) +} + +trait Invert { + fn invert(self) -> Self; +} + +impl Invert for i64 { + fn invert(self) -> Self { + -1 * self + } +} + +// CHECK: .balign 4 +// CHECK-LABEL: generic_function: +// CHECK: call +// CHECK: ret + +#[unsafe(naked)] +#[no_mangle] +pub extern "C" fn generic_function(x: i64) -> i64 { + naked_asm!( + "call {}", + "ret", + sym ::invert, + ) +} + +#[derive(Copy, Clone)] +#[repr(transparent)] +struct Foo(u64); + +// CHECK: .balign 4 +// CHECK-LABEL: method: +// CHECK: mov rax, rdi + +impl Foo { + #[unsafe(naked)] + #[no_mangle] + extern "C" fn method(self) -> u64 { + naked_asm!("mov rax, rdi", "ret") + } +} + +// CHECK: .balign 4 +// CHECK-LABEL: trait_method: +// CHECK: mov rax, rdi + +trait Bar { + extern "C" fn trait_method(self) -> u64; +} + +impl Bar for Foo { + #[unsafe(naked)] + #[no_mangle] + extern "C" fn trait_method(self) -> u64 { + naked_asm!("mov rax, rdi", "ret") + } +} + +// CHECK: .balign 4 +// CHECK-LABEL: naked_with_args_and_return: +// CHECK: lea rax, [rdi + rsi] + +// this previously ICE'd, see https://github.com/rust-lang/rust/issues/124375 +#[unsafe(naked)] +#[no_mangle] +pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { + naked_asm!("lea rax, [rdi + rsi]", "ret"); +} diff --git a/tests/codegen-llvm/naked-fn/instruction-set.rs b/tests/codegen-llvm/naked-fn/instruction-set.rs new file mode 100644 index 00000000000..67560c5aba7 --- /dev/null +++ b/tests/codegen-llvm/naked-fn/instruction-set.rs @@ -0,0 +1,53 @@ +//@ add-core-stubs +//@ revisions: arm-mode thumb-mode +//@ [arm-mode] compile-flags: --target armv5te-none-eabi +//@ [thumb-mode] compile-flags: --target thumbv5te-none-eabi +//@ [arm-mode] needs-llvm-components: arm +//@ [thumb-mode] needs-llvm-components: arm + +#![crate_type = "lib"] +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// arm-mode: .arm +// thumb-mode: .thumb +// CHECK-LABEL: test_unspecified: +// CHECK: bx lr +// CHECK: .popsection +// arm-mode: .arm +// thumb-mode: .thumb +#[no_mangle] +#[unsafe(naked)] +extern "C" fn test_unspecified() { + naked_asm!("bx lr"); +} + +// CHECK: .thumb +// CHECK: .thumb_func +// CHECK-LABEL: test_thumb: +// CHECK: bx lr +// CHECK: .popsection +// arm-mode: .arm +// thumb-mode: .thumb +#[no_mangle] +#[unsafe(naked)] +#[instruction_set(arm::t32)] +extern "C" fn test_thumb() { + naked_asm!("bx lr"); +} + +// CHECK: .arm +// CHECK-LABEL: test_arm: +// CHECK: bx lr +// CHECK: .popsection +// arm-mode: .arm +// thumb-mode: .thumb +#[no_mangle] +#[unsafe(naked)] +#[instruction_set(arm::a32)] +extern "C" fn test_arm() { + naked_asm!("bx lr"); +} diff --git a/tests/codegen-llvm/naked-fn/min-function-alignment.rs b/tests/codegen-llvm/naked-fn/min-function-alignment.rs new file mode 100644 index 00000000000..406e9334fa5 --- /dev/null +++ b/tests/codegen-llvm/naked-fn/min-function-alignment.rs @@ -0,0 +1,47 @@ +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -Zmin-function-alignment=16 +//@ needs-asm-support +//@ ignore-arm no "ret" mnemonic +//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) + +// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity +#![feature(rustc_attrs)] +#![feature(fn_align)] +#![crate_type = "lib"] + +// functions without explicit alignment use the global minimum +// +// CHECK: .balign 16 +#[no_mangle] +#[unsafe(naked)] +pub extern "C" fn naked_no_explicit_align() { + core::arch::naked_asm!("ret") +} + +// CHECK: .balign 16 +#[no_mangle] +#[rustc_align(8)] +#[unsafe(naked)] +pub extern "C" fn naked_lower_align() { + core::arch::naked_asm!("ret") +} + +// CHECK: .balign 32 +#[no_mangle] +#[rustc_align(32)] +#[unsafe(naked)] +pub extern "C" fn naked_higher_align() { + core::arch::naked_asm!("ret") +} + +// cold functions follow the same rules as other functions +// +// in GCC, the `-falign-functions` does not apply to cold functions, but +// `-Zmin-function-alignment` applies to all functions. +// +// CHECK: .balign 16 +#[no_mangle] +#[cold] +#[unsafe(naked)] +pub extern "C" fn no_explicit_align_cold() { + core::arch::naked_asm!("ret") +} diff --git a/tests/codegen-llvm/naked-fn/naked-functions.rs b/tests/codegen-llvm/naked-fn/naked-functions.rs new file mode 100644 index 00000000000..344af6eb42f --- /dev/null +++ b/tests/codegen-llvm/naked-fn/naked-functions.rs @@ -0,0 +1,165 @@ +//@ add-core-stubs +//@ revisions: linux win_x86 win_i686 macos thumb +// +//@[linux] compile-flags: --target x86_64-unknown-linux-gnu +//@[linux] needs-llvm-components: x86 +//@[win_x86] compile-flags: --target x86_64-pc-windows-gnu +//@[win_x86] needs-llvm-components: x86 +//@[win_i686] compile-flags: --target i686-pc-windows-gnu +//@[win_i686] needs-llvm-components: x86 +//@[macos] compile-flags: --target aarch64-apple-darwin +//@[macos] needs-llvm-components: arm +//@[thumb] compile-flags: --target thumbv7em-none-eabi +//@[thumb] needs-llvm-components: arm + +#![crate_type = "lib"] +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// linux,win: .intel_syntax +// +// linux: .pushsection .text.naked_empty,\22ax\22, @progbits +// macos: .pushsection __TEXT,__text,regular,pure_instructions +// win_x86: .pushsection .text.naked_empty,\22xr\22 +// win_i686: .pushsection .text._naked_empty,\22xr\22 +// thumb: .pushsection .text.naked_empty,\22ax\22, %progbits +// +// CHECK: .balign 4 +// +// linux,win,thumb: .globl naked_empty +// macos: .globl _naked_empty +// +// CHECK-NOT: .private_extern +// CHECK-NOT: .hidden +// +// linux: .type naked_empty, @function +// +// win_x86: .def naked_empty +// win_i686: .def _naked_empty +// +// win_x86,win_i686: .scl 2 +// win_x86,win_i686: .type 32 +// win_x86,win_i686: .endef +// +// thumb: .type naked_empty, %function +// thumb: .thumb +// thumb: .thumb_func +// +// CHECK-LABEL: naked_empty: +// +// linux,macos,win: ret +// thumb: bx lr +// +// CHECK: .popsection +// +// thumb: .thumb +// +// linux,win: .att_syntax + +#[no_mangle] +#[unsafe(naked)] +pub extern "C" fn naked_empty() { + #[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))] + naked_asm!("ret"); + + #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] + naked_asm!("bx lr"); +} + +// linux,win: .intel_syntax +// +// linux: .pushsection .text.naked_with_args_and_return,\22ax\22, @progbits +// macos: .pushsection __TEXT,__text,regular,pure_instructions +// win_x86: .pushsection .text.naked_with_args_and_return,\22xr\22 +// win_i686: .pushsection .text._naked_with_args_and_return,\22xr\22 +// thumb: .pushsection .text.naked_with_args_and_return,\22ax\22, %progbits +// +// CHECK: .balign 4 +// +// linux,win,thumb: .globl naked_with_args_and_return +// macos: .globl _naked_with_args_and_return +// +// CHECK-NOT: .private_extern +// CHECK-NOT: .hidden +// +// linux: .type naked_with_args_and_return, @function +// +// win_x86: .def naked_with_args_and_return +// win_i686: .def _naked_with_args_and_return +// +// win_x86,win_i686: .scl 2 +// win_x86,win_i686: .type 32 +// win_x86,win_i686: .endef +// +// thumb: .type naked_with_args_and_return, %function +// thumb: .thumb +// thumb: .thumb_func +// +// CHECK-LABEL: naked_with_args_and_return: +// +// linux, win_x86,win_i686: lea rax, [rdi + rsi] +// macos: add x0, x0, x1 +// thumb: adds r0, r0, r1 +// +// linux,macos,win: ret +// thumb: bx lr +// +// CHECK: .popsection +// +// thumb: .thumb +// +// linux,win: .att_syntax + +#[no_mangle] +#[unsafe(naked)] +pub extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { + #[cfg(any(target_os = "windows", target_os = "linux"))] + { + naked_asm!("lea rax, [rdi + rsi]", "ret") + } + + #[cfg(target_os = "macos")] + { + naked_asm!("add x0, x0, x1", "ret") + } + + #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] + { + naked_asm!("adds r0, r0, r1", "bx lr") + } +} + +// linux: .pushsection .text.some_different_name,\22ax\22, @progbits +// macos: .pushsection .text.some_different_name,regular,pure_instructions +// win_x86,win_i686: .pushsection .text.some_different_name,\22xr\22 +// thumb: .pushsection .text.some_different_name,\22ax\22, %progbits +// CHECK-LABEL: test_link_section: +#[no_mangle] +#[unsafe(naked)] +#[link_section = ".text.some_different_name"] +pub extern "C" fn test_link_section() { + #[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))] + naked_asm!("ret"); + + #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] + naked_asm!("bx lr"); +} + +// win_x86: .def fastcall_cc +// win_i686: .def @fastcall_cc@4 +// +// win_x86,win_i686: .scl 2 +// win_x86,win_i686: .type 32 +// win_x86,win_i686: .endef +// +// win_x86-LABEL: fastcall_cc: +// win_i686-LABEL: @fastcall_cc@4: +#[cfg(target_os = "windows")] +#[no_mangle] +#[unsafe(naked)] +pub extern "fastcall" fn fastcall_cc(x: i32) -> i32 { + naked_asm!("ret"); +} diff --git a/tests/codegen-llvm/no-alloca-inside-if-false.rs b/tests/codegen-llvm/no-alloca-inside-if-false.rs new file mode 100644 index 00000000000..a231c7e808a --- /dev/null +++ b/tests/codegen-llvm/no-alloca-inside-if-false.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 -Cpanic=abort +// Check that there's an alloca for the reference and the vector, but nothing else. +// We use panic=abort because unwinding panics give hint::black_box a cleanup block, which has +// another alloca. + +#![crate_type = "lib"] + +#[inline(never)] +fn test() { + // CHECK-LABEL: no_alloca_inside_if_false::test + // CHECK: start: + // CHECK-NEXT: alloca [{{12|24}} x i8] + // CHECK-NOT: alloca + if const { SIZE < 4096 } { + let arr = [0u8; SIZE]; + std::hint::black_box(&arr); + } else { + let vec = vec![0u8; SIZE]; + std::hint::black_box(&vec); + } +} + +// CHECK-LABEL: @main +#[no_mangle] +pub fn main() { + test::<8192>(); +} diff --git a/tests/codegen-llvm/no-assumes-on-casts.rs b/tests/codegen-llvm/no-assumes-on-casts.rs new file mode 100644 index 00000000000..9c00dc2c015 --- /dev/null +++ b/tests/codegen-llvm/no-assumes-on-casts.rs @@ -0,0 +1,19 @@ +#![crate_type = "lib"] + +//@ compile-flags: -Cno-prepopulate-passes + +// CHECK-LABEL: fna +#[no_mangle] +pub fn fna(a: i16) -> i32 { + a as i32 + // CHECK-NOT: assume + // CHECK: sext +} + +// CHECK-LABEL: fnb +#[no_mangle] +pub fn fnb(a: u16) -> u32 { + a as u32 + // CHECK-NOT: assume + // CHECK: zext +} diff --git a/tests/codegen-llvm/no-dllimport-w-cross-lang-lto.rs b/tests/codegen-llvm/no-dllimport-w-cross-lang-lto.rs new file mode 100644 index 00000000000..c71eddfa287 --- /dev/null +++ b/tests/codegen-llvm/no-dllimport-w-cross-lang-lto.rs @@ -0,0 +1,13 @@ +// This test makes sure that functions get annotated with the proper +// "target-cpu" attribute in LLVM. + +//@ no-prefer-dynamic +//@ only-msvc +//@ compile-flags: -C linker-plugin-lto + +#![crate_type = "rlib"] + +// CHECK-NOT: @{{.*}}__imp_{{.*}}GLOBAL{{.*}} = global i8* + +pub static GLOBAL: u32 = 0; +pub static mut GLOBAL2: u32 = 0; diff --git a/tests/codegen-llvm/no-jump-tables.rs b/tests/codegen-llvm/no-jump-tables.rs new file mode 100644 index 00000000000..e49de7e9dc1 --- /dev/null +++ b/tests/codegen-llvm/no-jump-tables.rs @@ -0,0 +1,23 @@ +// Test that the `no-jump-tables` function attribute are (not) emitted when +// the `-Zno-jump-tables` flag is (not) set. + +//@ add-core-stubs +//@ revisions: unset set +//@ needs-llvm-components: x86 +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ [set] compile-flags: -Zno-jump-tables + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + + // unset-NOT: attributes #0 = { {{.*}}"no-jump-tables"="true"{{.*}} } + // set: attributes #0 = { {{.*}}"no-jump-tables"="true"{{.*}} } +} diff --git a/tests/codegen-llvm/no-plt.rs b/tests/codegen-llvm/no-plt.rs new file mode 100644 index 00000000000..3a3546ff7c4 --- /dev/null +++ b/tests/codegen-llvm/no-plt.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -C relocation-model=pic -Z plt=no + +#![crate_type = "lib"] + +// We need a function which is normally called through the PLT. +extern "C" { + // CHECK: Function Attrs:{{.*}}nonlazybind + fn getenv(name: *const u8) -> *mut u8; +} + +// Ensure the function gets referenced. +pub unsafe fn call_through_plt() -> *mut u8 { + getenv(b"\0".as_ptr()) +} + +// Ensure intrinsics also skip the PLT +// CHECK: !"RtLibUseGOT" diff --git a/tests/codegen-llvm/no-redundant-item-monomorphization.rs b/tests/codegen-llvm/no-redundant-item-monomorphization.rs new file mode 100644 index 00000000000..466037c3770 --- /dev/null +++ b/tests/codegen-llvm/no-redundant-item-monomorphization.rs @@ -0,0 +1,33 @@ +// Test to make sure that inner functions within a polymorphic outer function +// don't get re-codegened when the outer function is monomorphized. The test +// code monomorphizes the outer functions several times, but the magic constants +// used in the inner functions should each appear only once in the generated IR. + +// issue: rust-lang/rust#7349 +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 + +// CHECK-COUNT-1: ret i32 8675309 +// CHECK-COUNT-1: ret i32 11235813 + +fn outer() { + #[allow(dead_code)] + fn inner() -> u32 { + 8675309 + } + inner(); +} + +extern "C" fn outer_foreign() { + #[allow(dead_code)] + fn inner() -> u32 { + 11235813 + } + inner(); +} + +fn main() { + outer::(); + outer::(); + outer_foreign::(); + outer_foreign::(); +} diff --git a/tests/codegen-llvm/no_builtins-at-crate.rs b/tests/codegen-llvm/no_builtins-at-crate.rs new file mode 100644 index 00000000000..ba1d31f60c3 --- /dev/null +++ b/tests/codegen-llvm/no_builtins-at-crate.rs @@ -0,0 +1,24 @@ +//@ compile-flags: -C opt-level=1 + +#![no_builtins] +#![crate_type = "lib"] + +// CHECK: define +// CHECK-SAME: @__aeabi_memcpy +// CHECK-SAME: #0 +#[no_mangle] +pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, size: usize) { + // CHECK: call + // CHECK-SAME: @memcpy( + 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-SAME: "no-builtins" diff --git a/tests/codegen-llvm/noalias-box-off.rs b/tests/codegen-llvm/noalias-box-off.rs new file mode 100644 index 00000000000..664c7950280 --- /dev/null +++ b/tests/codegen-llvm/noalias-box-off.rs @@ -0,0 +1,11 @@ +//@ compile-flags: -Copt-level=3 -Z box-noalias=no + +#![crate_type = "lib"] + +// CHECK-LABEL: @box_should_not_have_noalias_if_disabled( +// CHECK-NOT: noalias +// CHECK-SAME: %foo) +#[no_mangle] +pub fn box_should_not_have_noalias_if_disabled(foo: Box) { + drop(foo); +} diff --git a/tests/codegen-llvm/noalias-box.rs b/tests/codegen-llvm/noalias-box.rs new file mode 100644 index 00000000000..cccde775977 --- /dev/null +++ b/tests/codegen-llvm/noalias-box.rs @@ -0,0 +1,8 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @box_should_have_noalias_by_default( +// CHECK: noalias +#[no_mangle] +pub fn box_should_have_noalias_by_default(_b: Box) {} diff --git a/tests/codegen-llvm/noalias-flag.rs b/tests/codegen-llvm/noalias-flag.rs new file mode 100644 index 00000000000..67ba68ee6f8 --- /dev/null +++ b/tests/codegen-llvm/noalias-flag.rs @@ -0,0 +1,23 @@ +//@ compile-flags: -Copt-level=3 -Zmutable-noalias=no + +#![crate_type = "lib"] + +// `-Zmutable-noalias=no` should disable noalias on mut refs... + +// CHECK-LABEL: @test_mut_ref( +// CHECK-NOT: noalias +// CHECK-SAME: %x +#[no_mangle] +pub fn test_mut_ref(x: &mut i32) -> &mut i32 { + x +} + +// ...but not on shared refs + +// CHECK-LABEL: @test_ref( +// CHECK-SAME: noalias +// CHECK-SAME: %x +#[no_mangle] +pub fn test_ref(x: &i32) -> &i32 { + x +} diff --git a/tests/codegen-llvm/noalias-freeze.rs b/tests/codegen-llvm/noalias-freeze.rs new file mode 100644 index 00000000000..32c84014026 --- /dev/null +++ b/tests/codegen-llvm/noalias-freeze.rs @@ -0,0 +1,23 @@ +//@ compile-flags: -Copt-level=1 + +// References returned by a Frozen pointer type +// could be marked as "noalias", which caused miscompilation errors. +// This test runs the most minimal possible code that can reproduce this bug, +// and checks that noalias does not appear. +// See https://github.com/rust-lang/rust/issues/46239 + +#![crate_type = "lib"] + +fn project(x: &(T,)) -> &T { + &x.0 +} + +fn dummy() {} + +// CHECK-LABEL: @foo( +// CHECK-NOT: noalias +#[no_mangle] +pub fn foo() { + let f = (dummy as fn(),); + (*project(&f))(); +} diff --git a/tests/codegen-llvm/noalias-refcell.rs b/tests/codegen-llvm/noalias-refcell.rs new file mode 100644 index 00000000000..b37adf92b9c --- /dev/null +++ b/tests/codegen-llvm/noalias-refcell.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z mutable-noalias=yes + +#![crate_type = "lib"] + +use std::cell::{Ref, RefCell, RefMut}; + +// Make sure that none of the arguments get a `noalias` attribute, because +// the `RefCell` might alias writes after either `Ref`/`RefMut` is dropped. + +// CHECK-LABEL: @maybe_aliased( +// CHECK-NOT: noalias +// CHECK-SAME: %_refcell +#[no_mangle] +pub unsafe fn maybe_aliased(_: Ref<'_, i32>, _: RefMut<'_, i32>, _refcell: &RefCell) {} diff --git a/tests/codegen-llvm/noalias-rwlockreadguard.rs b/tests/codegen-llvm/noalias-rwlockreadguard.rs new file mode 100644 index 00000000000..c676dc32399 --- /dev/null +++ b/tests/codegen-llvm/noalias-rwlockreadguard.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z mutable-noalias=yes + +#![crate_type = "lib"] + +use std::sync::{RwLock, RwLockReadGuard}; + +// Make sure that `RwLockReadGuard` does not get a `noalias` attribute, because +// the `RwLock` might alias writes after it is dropped. + +// CHECK-LABEL: @maybe_aliased( +// CHECK-NOT: noalias +// CHECK-SAME: %_data +#[no_mangle] +pub unsafe fn maybe_aliased(_: RwLockReadGuard<'_, i32>, _data: &RwLock) {} diff --git a/tests/codegen-llvm/noalias-unpin.rs b/tests/codegen-llvm/noalias-unpin.rs new file mode 100644 index 00000000000..30a8b399b97 --- /dev/null +++ b/tests/codegen-llvm/noalias-unpin.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Copt-level=3 -Z mutable-noalias=yes + +#![crate_type = "lib"] + +pub struct SelfRef { + self_ref: *mut SelfRef, + _pin: std::marker::PhantomPinned, +} + +// CHECK-LABEL: @test_self_ref( +// CHECK-NOT: noalias +#[no_mangle] +pub unsafe fn test_self_ref(s: &mut SelfRef) { + (*s.self_ref).self_ref = std::ptr::null_mut(); +} diff --git a/tests/codegen-llvm/non-terminate/infinite-loop-1.rs b/tests/codegen-llvm/non-terminate/infinite-loop-1.rs new file mode 100644 index 00000000000..9eab4939aee --- /dev/null +++ b/tests/codegen-llvm/non-terminate/infinite-loop-1.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -C opt-level=3 + +#![crate_type = "lib"] + +fn infinite_loop() -> u8 { + loop {} +} + +// CHECK-LABEL: @test +#[no_mangle] +fn test() -> u8 { + // CHECK-NOT: unreachable + // CHECK: br label %{{.+}} + // CHECK-NOT: unreachable + let x = infinite_loop(); + x +} diff --git a/tests/codegen-llvm/non-terminate/infinite-loop-2.rs b/tests/codegen-llvm/non-terminate/infinite-loop-2.rs new file mode 100644 index 00000000000..da29361cc96 --- /dev/null +++ b/tests/codegen-llvm/non-terminate/infinite-loop-2.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -C opt-level=3 + +#![crate_type = "lib"] + +fn infinite_loop() -> u8 { + let i = 2; + while i > 1 {} + 1 +} + +// CHECK-LABEL: @test +#[no_mangle] +fn test() -> u8 { + // CHECK-NOT: unreachable + // CHECK: br label %{{.+}} + // CHECK-NOT: unreachable + let x = infinite_loop(); + x +} diff --git a/tests/codegen-llvm/non-terminate/infinite-recursion.rs b/tests/codegen-llvm/non-terminate/infinite-recursion.rs new file mode 100644 index 00000000000..19123639896 --- /dev/null +++ b/tests/codegen-llvm/non-terminate/infinite-recursion.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -C opt-level=3 + +#![crate_type = "lib"] +#![allow(unconditional_recursion)] + +// CHECK-LABEL: @infinite_recursion +#[no_mangle] +fn infinite_recursion() -> u8 { + // CHECK-NOT: ret i8 undef + // CHECK: br label %{{.+}} + // CHECK-NOT: ret i8 undef + infinite_recursion() +} diff --git a/tests/codegen-llvm/non-terminate/nonempty-infinite-loop.rs b/tests/codegen-llvm/non-terminate/nonempty-infinite-loop.rs new file mode 100644 index 00000000000..0db4ee61b1b --- /dev/null +++ b/tests/codegen-llvm/non-terminate/nonempty-infinite-loop.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -C opt-level=3 + +#![crate_type = "lib"] + +// Verify that we don't miscompile this even if rustc didn't apply the trivial loop detection to +// insert the sideeffect intrinsic. + +fn infinite_loop() -> u8 { + let mut x = 0; + // CHECK-NOT: sideeffect + loop { + if x == 42 { + x = 0; + } else { + x = 42; + } + } +} + +// CHECK-LABEL: @test +#[no_mangle] +fn test() -> u8 { + // CHECK-NOT: unreachable + // CHECK: br label %{{.+}} + // CHECK-NOT: unreachable + let x = infinite_loop(); + x +} diff --git a/tests/codegen-llvm/noreturn-uninhabited.rs b/tests/codegen-llvm/noreturn-uninhabited.rs new file mode 100644 index 00000000000..a10795d3f3c --- /dev/null +++ b/tests/codegen-llvm/noreturn-uninhabited.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -g -C no-prepopulate-passes + +#![crate_type = "lib"] + +#[derive(Clone, Copy)] +pub enum EmptyEnum {} + +#[no_mangle] +pub fn empty(x: &EmptyEnum) -> EmptyEnum { + // CHECK: @empty({{.*}}) unnamed_addr #0 + // CHECK-NOT: ret void + // CHECK: call void @llvm.trap() + // CHECK: unreachable + *x +} + +pub struct Foo(String, EmptyEnum); + +#[no_mangle] +pub fn foo(x: String, y: &EmptyEnum) -> Foo { + // CHECK: @foo({{.*}}) unnamed_addr #0 + // CHECK-NOT: ret %Foo + // CHECK: call void @llvm.trap() + // CHECK: unreachable + Foo(x, *y) +} + +// CHECK: attributes #0 = {{{.*}} noreturn {{.*}}} + +// CHECK: DISubprogram(name: "empty", {{.*}} DIFlagNoReturn +// CHECK: DISubprogram(name: "foo", {{.*}} DIFlagNoReturn diff --git a/tests/codegen-llvm/noreturnflag.rs b/tests/codegen-llvm/noreturnflag.rs new file mode 100644 index 00000000000..d9bb30b2703 --- /dev/null +++ b/tests/codegen-llvm/noreturnflag.rs @@ -0,0 +1,22 @@ +//@ compile-flags: -g -C no-prepopulate-passes + +#![crate_type = "lib"] + +#[no_mangle] +pub fn foo() -> ! { + // CHECK: @foo() unnamed_addr #0 + loop {} +} + +pub enum EmptyEnum {} + +#[no_mangle] +pub fn bar() -> EmptyEnum { + // CHECK: @bar() unnamed_addr #0 + loop {} +} + +// CHECK: attributes #0 = {{{.*}} noreturn {{.*}}} + +// CHECK: DISubprogram(name: "foo", {{.*}} DIFlagNoReturn +// CHECK: DISubprogram(name: "bar", {{.*}} DIFlagNoReturn diff --git a/tests/codegen-llvm/nounwind.rs b/tests/codegen-llvm/nounwind.rs new file mode 100644 index 00000000000..c910644458a --- /dev/null +++ b/tests/codegen-llvm/nounwind.rs @@ -0,0 +1,15 @@ +//@ aux-build:nounwind.rs +//@ compile-flags: -C no-prepopulate-passes -C panic=abort -C metadata=a +//@ ignore-android + +#![crate_type = "lib"] + +extern crate nounwind; + +#[no_mangle] +pub fn foo() { + nounwind::bar(); + // CHECK: @foo() unnamed_addr #0 + // CHECK: @bar() unnamed_addr #0 + // CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +} diff --git a/tests/codegen-llvm/nrvo.rs b/tests/codegen-llvm/nrvo.rs new file mode 100644 index 00000000000..7972186bfe5 --- /dev/null +++ b/tests/codegen-llvm/nrvo.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// Ensure that we do not call `memcpy` for the following function. +// `memset` and `init` should be called directly on the return pointer. +#[no_mangle] +pub fn nrvo(init: fn(&mut [u8; 4096])) -> [u8; 4096] { + // CHECK-LABEL: nrvo + // CHECK: @llvm.memset + // FIXME: turn on nrvo then check-not: @llvm.memcpy + // CHECK: ret + // CHECK-EMPTY + let mut buf = [0; 4096]; + init(&mut buf); + buf +} diff --git a/tests/codegen-llvm/optimize-attr-1.rs b/tests/codegen-llvm/optimize-attr-1.rs new file mode 100644 index 00000000000..db6bdcf9a8b --- /dev/null +++ b/tests/codegen-llvm/optimize-attr-1.rs @@ -0,0 +1,59 @@ +//@ revisions: NO-OPT SIZE-OPT SPEED-OPT +//@[NO-OPT] compile-flags: -Copt-level=0 -Ccodegen-units=1 +//@[SIZE-OPT] compile-flags: -Copt-level=s -Ccodegen-units=1 +//@[SPEED-OPT] compile-flags: -Copt-level=3 -Ccodegen-units=1 + +#![feature(optimize_attribute)] +#![crate_type = "rlib"] + +// CHECK-LABEL: define{{.*}}i32 @nothing +// CHECK-SAME: [[NOTHING_ATTRS:#[0-9]+]] +// SIZE-OPT: ret i32 4 +// SPEED-OPT: ret i32 4 +#[no_mangle] +pub fn nothing() -> i32 { + 2 + 2 +} + +// CHECK-LABEL: define{{.*}}i32 @size +// CHECK-SAME: [[SIZE_ATTRS:#[0-9]+]] +// SIZE-OPT: ret i32 6 +// SPEED-OPT: ret i32 6 +#[optimize(size)] +#[no_mangle] +pub fn size() -> i32 { + 3 + 3 +} + +// CHECK-LABEL: define{{.*}}i32 @speed +// NO-OPT-SAME: [[NOTHING_ATTRS]] +// SPEED-OPT-SAME: [[NOTHING_ATTRS]] +// SIZE-OPT-SAME: [[SPEED_ATTRS:#[0-9]+]] +// SIZE-OPT: ret i32 8 +// SPEED-OPT: ret i32 8 +#[optimize(speed)] +#[no_mangle] +pub fn speed() -> i32 { + 4 + 4 +} + +// CHECK-LABEL: define{{.*}}i32 @none +// CHECK-SAME: [[NONE_ATTRS:#[0-9]+]] +// SIZE-OPT: alloca +// SPEED-OPT: alloca +#[no_mangle] +#[optimize(none)] +pub fn none() -> i32 { + let arr = [0, 1, 2, 3, 4]; + arr[4] +} + +// NO-OPT-DAG: attributes [[SIZE_ATTRS]] = {{.*}}minsize{{.*}}optsize{{.*}} +// SPEED-OPT-DAG: attributes [[SIZE_ATTRS]] = {{.*}}minsize{{.*}}optsize{{.*}} +// SIZE-OPT-DAG: attributes [[NOTHING_ATTRS]] = {{.*}}optsize{{.*}} +// SIZE-OPT-DAG: attributes [[SIZE_ATTRS]] = {{.*}}minsize{{.*}}optsize{{.*}} +// CHECK-DAG: attributes [[NONE_ATTRS]] = {{.*}}noinline{{.*}}optnone{{.*}} + +// SIZE-OPT-DAG: attributes [[SPEED_ATTRS]] +// SIZE-OPT-NOT: minsize +// SIZE-OPT-NOT: optsize diff --git a/tests/codegen-llvm/option-as-slice.rs b/tests/codegen-llvm/option-as-slice.rs new file mode 100644 index 00000000000..39b34a2035b --- /dev/null +++ b/tests/codegen-llvm/option-as-slice.rs @@ -0,0 +1,71 @@ +//@ compile-flags: -Copt-level=3 -Z randomize-layout=no +//@ only-x86_64 +#![crate_type = "lib"] + +extern crate core; + +use core::num::NonZero; +use core::option::Option; + +// CHECK-LABEL: @u64_opt_as_slice +#[no_mangle] +pub fn u64_opt_as_slice(o: &Option) -> &[u64] { + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + // CHECK: %[[LEN:.+]] = load i64 + // CHECK-SAME: !range ![[META_U64:[0-9]+]], + // CHECK-SAME: !noundef + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %{{.+}}, 0 + // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1 + // CHECK-NEXT: ret { ptr, i64 } %[[T1]] + o.as_slice() +} + +// CHECK-LABEL: @nonzero_u64_opt_as_slice +#[no_mangle] +pub fn nonzero_u64_opt_as_slice(o: &Option>) -> &[NonZero] { + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + // CHECK: %[[NZ:.+]] = icmp ne i64 %{{.+}}, 0 + // CHECK-NEXT: %[[LEN:.+]] = zext i1 %[[NZ]] to i64 + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %o, 0 + // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1 + // CHECK-NEXT: ret { ptr, i64 } %[[T1]] + o.as_slice() +} + +// CHECK-LABEL: @u8_opt_as_slice +#[no_mangle] +pub fn u8_opt_as_slice(o: &Option) -> &[u8] { + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + // CHECK: %[[TAG:.+]] = load i8 + // CHECK-SAME: !range ![[META_U8:[0-9]+]], + // CHECK-SAME: !noundef + // CHECK: %[[LEN:.+]] = zext{{.*}} i8 %[[TAG]] to i64 + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %{{.+}}, 0 + // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1 + // CHECK-NEXT: ret { ptr, i64 } %[[T1]] + o.as_slice() +} + +// CHECK: ![[META_U64]] = !{i64 0, i64 2} +// CHECK: ![[META_U8]] = !{i8 0, i8 2} diff --git a/tests/codegen-llvm/option-niche-eq.rs b/tests/codegen-llvm/option-niche-eq.rs new file mode 100644 index 00000000000..3900cb79aa2 --- /dev/null +++ b/tests/codegen-llvm/option-niche-eq.rs @@ -0,0 +1,87 @@ +//@ revisions: REGULAR LLVM21 +//@ min-llvm-version: 20 +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled +//@ [LLVM21] min-llvm-version: 21 +#![crate_type = "lib"] + +extern crate core; +use core::cmp::Ordering; +use core::num::NonZero; +use core::ptr::NonNull; + +// CHECK-LABEL: @non_zero_eq +#[no_mangle] +pub fn non_zero_eq(l: Option>, r: Option>) -> bool { + // CHECK: start: + // CHECK-NEXT: icmp eq i32 + // CHECK-NEXT: ret i1 + l == r +} + +// CHECK-LABEL: @non_zero_signed_eq +#[no_mangle] +pub fn non_zero_signed_eq(l: Option>, r: Option>) -> bool { + // CHECK: start: + // CHECK-NEXT: icmp eq i64 + // CHECK-NEXT: ret i1 + l == r +} + +// FIXME(#49892) +// This currently relies on a manual implementation of `PartialOrd`/`Ord` for `Option` +// Once LLVM is better able to optimize this pattern, we can return to using a derive. +// CHECK-LABEL: @non_zero_ord +#[no_mangle] +pub fn non_zero_ord(a: Option>, b: Option>) -> bool { + // CHECK: start: + // CHECK-NEXT: icmp ult i32 + // CHECK-NEXT: ret i1 + a < b +} + +// CHECK-LABEL: @non_null_eq +#[no_mangle] +pub fn non_null_eq(l: Option>, r: Option>) -> bool { + // CHECK: start: + // CHECK-NEXT: icmp eq ptr + // CHECK-NEXT: ret i1 + l == r +} + +// CHECK-LABEL: @ordering_eq +#[no_mangle] +pub fn ordering_eq(l: Option, r: Option) -> bool { + // CHECK: start: + // CHECK-NEXT: icmp eq i8 + // CHECK-NEXT: ret i1 + l == r +} + +#[derive(PartialEq)] +pub enum EnumWithNiche { + A, + B, + C, + D, + E, + F, + G, +} + +// CHECK-LABEL: @niche_eq +#[no_mangle] +pub fn niche_eq(l: Option, r: Option) -> bool { + // CHECK: start: + // CHECK-NEXT: icmp eq i8 + // CHECK-NEXT: ret i1 + l == r +} + +// LLVM21-LABEL: @bool_eq +#[no_mangle] +pub fn bool_eq(l: Option, r: Option) -> bool { + // LLVM21: start: + // LLVM21-NEXT: icmp eq i8 + // LLVM21-NEXT: ret i1 + l == r +} diff --git a/tests/codegen-llvm/option-niche-unfixed/option-nonzero-eq.rs b/tests/codegen-llvm/option-niche-unfixed/option-nonzero-eq.rs new file mode 100644 index 00000000000..308856cfb7e --- /dev/null +++ b/tests/codegen-llvm/option-niche-unfixed/option-nonzero-eq.rs @@ -0,0 +1,24 @@ +//@ should-fail +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled +//! FIXME(#49892) +//! Test that the derived implementation of `PartialEq` for `Option` is not fully +//! optimized by LLVM. If this starts passing, the test and manual impl should +//! be removed. +#![crate_type = "lib"] + +use std::num::NonZero; + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum Option { + None, + Some(T), +} + +// CHECK-LABEL: @non_zero_eq +#[no_mangle] +pub fn non_zero_eq(l: Option>, r: Option>) -> bool { + // CHECK: start: + // CHECK-NEXT: icmp eq i32 + // CHECK-NEXT: ret i1 + l == r +} diff --git a/tests/codegen-llvm/overaligned-constant.rs b/tests/codegen-llvm/overaligned-constant.rs new file mode 100644 index 00000000000..0f5977880f2 --- /dev/null +++ b/tests/codegen-llvm/overaligned-constant.rs @@ -0,0 +1,35 @@ +// GVN may create indirect constants with higher alignment than their type requires. Verify that we +// do not ICE during codegen, and that the LLVM constant has the higher alignment. +// +//@ compile-flags: -Zmir-opt-level=0 -Zmir-enable-passes=+GVN +//@ compile-flags: -Cno-prepopulate-passes --crate-type=lib +//@ only-64bit + +struct S(i32); + +struct SmallStruct(f32, Option, &'static [f32]); + +// CHECK: [[const:@.*]] = private unnamed_addr constant +// CHECK-SAME: , align 8 + +#[no_mangle] +pub fn overaligned_constant() { + // CHECK-LABEL: @overaligned_constant + // CHECK: [[full:%_.*]] = alloca [32 x i8], align 8 + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[full]], ptr align 8 [[const]], i64 32, i1 false) + let mut s = S(1); + + s.0 = 3; + + // SMALL_VAL corresponds to a MIR allocation with alignment 8. + const SMALL_VAL: SmallStruct = SmallStruct(4., Some(S(1)), &[]); + + // In pre-codegen MIR: + // `a` is a scalar 4. + // `b` is an indirect constant at `SMALL_VAL`'s alloc with 0 offset. + // `c` is the empty slice. + // + // As a consequence, during codegen, we create a LLVM allocation for `SMALL_VAL`, with + // alignment 8, but only use the `Option` field, at offset 0 with alignment 4. + let SmallStruct(a, b, c) = SMALL_VAL; +} diff --git a/tests/codegen-llvm/packed.rs b/tests/codegen-llvm/packed.rs new file mode 100644 index 00000000000..6f62719282e --- /dev/null +++ b/tests/codegen-llvm/packed.rs @@ -0,0 +1,153 @@ +// +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes + +#![crate_type = "lib"] + +#[repr(packed)] +pub struct Packed1 { + dealign: u8, + data: u32, +} + +#[repr(packed(2))] +pub struct Packed2 { + dealign: u8, + data: u32, +} + +// CHECK-LABEL: @write_pkd1 +#[no_mangle] +pub fn write_pkd1(pkd: &mut Packed1) -> u32 { + // CHECK: %{{.*}} = load i32, ptr %{{.*}}, align 1 + // CHECK: store i32 42, ptr %{{.*}}, align 1 + let result = pkd.data; + pkd.data = 42; + result +} + +// CHECK-LABEL: @write_pkd2 +#[no_mangle] +pub fn write_pkd2(pkd: &mut Packed2) -> u32 { + // CHECK: %{{.*}} = load i32, ptr %{{.*}}, align 2 + // CHECK: store i32 42, ptr %{{.*}}, align 2 + let result = pkd.data; + pkd.data = 42; + result +} + +pub struct Array([i32; 8]); +#[repr(packed)] +pub struct BigPacked1 { + dealign: u8, + data: Array, +} + +#[repr(packed(2))] +pub struct BigPacked2 { + dealign: u8, + data: Array, +} + +// CHECK-LABEL: @call_pkd1 +#[no_mangle] +pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 { + // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca [32 x i8] + // CHECK: call void %{{.*}}(ptr{{( captures(none))?}} noalias{{( nocapture)?}} noundef sret{{.*}} dereferenceable(32) [[ALLOCA]]) + // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false) + // check that calls whose destination is a field of a packed struct + // go through an alloca rather than calling the function with an + // unaligned destination. + BigPacked1 { dealign: 0, data: f() } +} + +// CHECK-LABEL: @call_pkd2 +#[no_mangle] +pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 { + // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca [32 x i8] + // CHECK: call void %{{.*}}(ptr{{( captures(none))?}} noalias{{( nocapture)?}} noundef sret{{.*}} dereferenceable(32) [[ALLOCA]]) + // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 2 %{{.*}}, ptr align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false) + // check that calls whose destination is a field of a packed struct + // go through an alloca rather than calling the function with an + // unaligned destination. + BigPacked2 { dealign: 0, data: f() } +} + +// CHECK-LABEL: @write_packed_array1 +// CHECK: store i32 0, ptr %{{.+}}, align 1 +// CHECK: store i32 1, ptr %{{.+}}, align 1 +// CHECK: store i32 2, ptr %{{.+}}, align 1 +#[no_mangle] +pub fn write_packed_array1(p: &mut BigPacked1) { + p.data.0[0] = 0; + p.data.0[1] = 1; + p.data.0[2] = 2; +} + +// CHECK-LABEL: @write_packed_array2 +// CHECK: store i32 0, ptr %{{.+}}, align 2 +// CHECK: store i32 1, ptr %{{.+}}, align 2 +// CHECK: store i32 2, ptr %{{.+}}, align 2 +#[no_mangle] +pub fn write_packed_array2(p: &mut BigPacked2) { + p.data.0[0] = 0; + p.data.0[1] = 1; + p.data.0[2] = 2; +} + +// CHECK-LABEL: @repeat_packed_array1 +// CHECK: store i32 42, ptr %{{.+}}, align 1 +#[no_mangle] +pub fn repeat_packed_array1(p: &mut BigPacked1) { + p.data.0 = [42; 8]; +} + +// CHECK-LABEL: @repeat_packed_array2 +// CHECK: store i32 42, ptr %{{.+}}, align 2 +#[no_mangle] +pub fn repeat_packed_array2(p: &mut BigPacked2) { + p.data.0 = [42; 8]; +} + +#[repr(packed)] +#[derive(Copy, Clone)] +pub struct Packed1Pair(u8, u32); + +#[repr(packed(2))] +#[derive(Copy, Clone)] +pub struct Packed2Pair(u8, u32); + +// CHECK-LABEL: @pkd1_pair +#[no_mangle] +pub fn pkd1_pair(pair1: &mut Packed1Pair, pair2: &mut Packed1Pair) { + // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, i{{[0-9]+}} 5, i1 false) + *pair2 = *pair1; +} + +// CHECK-LABEL: @pkd2_pair +#[no_mangle] +pub fn pkd2_pair(pair1: &mut Packed2Pair, pair2: &mut Packed2Pair) { + // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 2 %{{.*}}, ptr align 2 %{{.*}}, i{{[0-9]+}} 6, i1 false) + *pair2 = *pair1; +} + +#[repr(packed)] +#[derive(Copy, Clone)] +pub struct Packed1NestedPair((u32, u32)); + +#[repr(packed(2))] +#[derive(Copy, Clone)] +pub struct Packed2NestedPair((u32, u32)); + +// CHECK-LABEL: @pkd1_nested_pair +#[no_mangle] +pub fn pkd1_nested_pair(pair1: &mut Packed1NestedPair, pair2: &mut Packed1NestedPair) { + // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, i{{[0-9]+}} 8, i1 false) + *pair2 = *pair1; +} + +// CHECK-LABEL: @pkd2_nested_pair +#[no_mangle] +pub fn pkd2_nested_pair(pair1: &mut Packed2NestedPair, pair2: &mut Packed2NestedPair) { + // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 2 %{{.*}}, ptr align 2 %{{.*}}, i{{[0-9]+}} 8, i1 false) + *pair2 = *pair1; +} diff --git a/tests/codegen-llvm/panic-abort-windows.rs b/tests/codegen-llvm/panic-abort-windows.rs new file mode 100644 index 00000000000..17fdd9cc726 --- /dev/null +++ b/tests/codegen-llvm/panic-abort-windows.rs @@ -0,0 +1,16 @@ +// This test is for *-windows only. +//@ only-windows + +//@ compile-flags: -C no-prepopulate-passes -C panic=abort -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK: Function Attrs: nounwind uwtable +// CHECK-NEXT: define void @normal_uwtable() +#[no_mangle] +pub fn normal_uwtable() {} + +// CHECK: Function Attrs: nounwind uwtable +// CHECK-NEXT: define void @extern_uwtable() +#[no_mangle] +pub extern "C" fn extern_uwtable() {} diff --git a/tests/codegen-llvm/panic-in-drop-abort.rs b/tests/codegen-llvm/panic-in-drop-abort.rs new file mode 100644 index 00000000000..e89170e56ed --- /dev/null +++ b/tests/codegen-llvm/panic-in-drop-abort.rs @@ -0,0 +1,57 @@ +//@ compile-flags: -Z panic-in-drop=abort -Copt-level=3 +//@ ignore-msvc + +// Ensure that unwinding code paths are eliminated from the output after +// optimization. + +// This test uses ignore-msvc, because the expected optimization does not happen on targets using +// SEH exceptions with the new LLVM pass manager anymore, see +// https://github.com/llvm/llvm-project/issues/51311. + +// CHECK-NOT: {{(call|invoke).*}}should_not_appear_in_output + +#![crate_type = "lib"] +use std::any::Any; +use std::mem::forget; + +pub struct ExternDrop; +impl Drop for ExternDrop { + #[inline(always)] + fn drop(&mut self) { + // This call may potentially unwind. + extern "Rust" { + fn extern_drop(); + } + unsafe { + extern_drop(); + } + } +} + +struct AssertNeverDrop; +impl Drop for AssertNeverDrop { + #[inline(always)] + fn drop(&mut self) { + // This call should be optimized away as unreachable. + extern "C" { + fn should_not_appear_in_output(); + } + unsafe { + should_not_appear_in_output(); + } + } +} + +#[no_mangle] +pub fn normal_drop(x: ExternDrop) { + let guard = AssertNeverDrop; + drop(x); + forget(guard); +} + +#[no_mangle] +pub fn indirect_drop(x: Box) { + let guard = AssertNeverDrop; + drop(x); + forget(guard); +} diff --git a/tests/codegen-llvm/panic-unwind-default-uwtable.rs b/tests/codegen-llvm/panic-unwind-default-uwtable.rs new file mode 100644 index 00000000000..06f616c519b --- /dev/null +++ b/tests/codegen-llvm/panic-unwind-default-uwtable.rs @@ -0,0 +1,6 @@ +//@ compile-flags: -C panic=unwind -C no-prepopulate-passes -Copt-level=0 + +#![crate_type = "lib"] + +// CHECK: attributes #{{.*}} uwtable +pub fn foo() {} diff --git a/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-both-flags.rs b/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-both-flags.rs new file mode 100644 index 00000000000..72204c78a49 --- /dev/null +++ b/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-both-flags.rs @@ -0,0 +1,64 @@ +//@ compile-flags: -Z patchable-function-entry=15,10 + +#![feature(patchable_function_entry)] +#![crate_type = "lib"] + +// This should have the default, as set by the compile flags +#[no_mangle] +pub fn fun0() {} + +// The attribute should override the compile flags +#[no_mangle] +#[patchable_function_entry(prefix_nops = 1, entry_nops = 2)] +pub fn fun1() {} + +// If we override an attribute to 0 or unset, the attribute should go away +#[no_mangle] +#[patchable_function_entry(entry_nops = 0)] +pub fn fun2() {} + +// The attribute should override the compile flags +#[no_mangle] +#[patchable_function_entry(prefix_nops = 20, entry_nops = 1)] +pub fn fun3() {} + +// The attribute should override the compile flags +#[no_mangle] +#[patchable_function_entry(prefix_nops = 2, entry_nops = 19)] +pub fn fun4() {} + +// The attribute should override patchable-function-entry to 3 and +// patchable-function-prefix to the default of 0, clearing it entirely +#[no_mangle] +#[patchable_function_entry(entry_nops = 3)] +pub fn fun5() {} + +// The attribute should override patchable-function-prefix to 4 +// and patchable-function-entry to the default of 0, clearing it entirely +#[no_mangle] +#[patchable_function_entry(prefix_nops = 4)] +pub fn fun6() {} + +// CHECK: @fun0() unnamed_addr #0 +// CHECK: @fun1() unnamed_addr #1 +// CHECK: @fun2() unnamed_addr #2 +// CHECK: @fun3() unnamed_addr #3 +// CHECK: @fun4() unnamed_addr #4 +// CHECK: @fun5() unnamed_addr #5 +// CHECK: @fun6() unnamed_addr #6 + +// CHECK: attributes #0 = { {{.*}}"patchable-function-entry"="5"{{.*}}"patchable-function-prefix"="10" {{.*}} } +// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} } + +// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-entry{{.*}} } +// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} } +// CHECK: attributes #2 = { {{.*}} } + +// CHECK: attributes #3 = { {{.*}}"patchable-function-entry"="1"{{.*}}"patchable-function-prefix"="20" {{.*}} } +// CHECK: attributes #4 = { {{.*}}"patchable-function-entry"="19"{{.*}}"patchable-function-prefix"="2" {{.*}} } + +// CHECK: attributes #5 = { {{.*}}"patchable-function-entry"="3"{{.*}} } +// CHECK-NOT: attributes #5 = { {{.*}}patchable-function-prefix{{.*}} } + +// CHECK: attributes #6 = { {{.*}}"patchable-function-prefix"="4"{{.*}} } +// CHECK-NOT: attributes #6 = { {{.*}}patchable-function-entry{{.*}} } diff --git a/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-no-flag.rs b/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-no-flag.rs new file mode 100644 index 00000000000..3a7078fe551 --- /dev/null +++ b/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-no-flag.rs @@ -0,0 +1,39 @@ +#![feature(patchable_function_entry)] +#![crate_type = "lib"] + +// No patchable function entry should be set +#[no_mangle] +pub fn fun0() {} + +// The attribute should work even without compiler flags +#[no_mangle] +#[patchable_function_entry(prefix_nops = 1, entry_nops = 2)] +pub fn fun1() {} + +// The attribute should work even without compiler flags +// and only set patchable-function-entry to 3. +#[no_mangle] +#[patchable_function_entry(entry_nops = 3)] +pub fn fun2() {} + +// The attribute should work even without compiler flags +// and only set patchable-function-prefix to 4. +#[no_mangle] +#[patchable_function_entry(prefix_nops = 4)] +pub fn fun3() {} + +// CHECK: @fun0() unnamed_addr #0 +// CHECK: @fun1() unnamed_addr #1 +// CHECK: @fun2() unnamed_addr #2 +// CHECK: @fun3() unnamed_addr #3 + +// CHECK-NOT: attributes #0 = { {{.*}}patchable-function-entry{{.*}} } +// CHECK-NOT: attributes #0 = { {{.*}}patchable-function-prefix{{.*}} } + +// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} } + +// CHECK: attributes #2 = { {{.*}}"patchable-function-entry"="3"{{.*}} } +// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} } + +// CHECK: attributes #3 = { {{.*}}"patchable-function-prefix"="4"{{.*}} } +// CHECK-NOT: attributes #3 = { {{.*}}patchable-function-entry{{.*}} } diff --git a/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-one-flag.rs b/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-one-flag.rs new file mode 100644 index 00000000000..8bdd61e461b --- /dev/null +++ b/tests/codegen-llvm/patchable-function-entry/patchable-function-entry-one-flag.rs @@ -0,0 +1,66 @@ +//@ compile-flags: -Z patchable-function-entry=15 + +#![feature(patchable_function_entry)] +#![crate_type = "lib"] + +// This should have the default, as set by the compile flags +#[no_mangle] +pub fn fun0() {} + +// The attribute should override the compile flags +#[no_mangle] +#[patchable_function_entry(prefix_nops = 1, entry_nops = 2)] +pub fn fun1() {} + +// If we override an attribute to 0 or unset, the attribute should go away +#[no_mangle] +#[patchable_function_entry(entry_nops = 0)] +pub fn fun2() {} + +// The attribute should override the compile flags +#[no_mangle] +#[patchable_function_entry(prefix_nops = 20, entry_nops = 1)] +pub fn fun3() {} + +// The attribute should override the compile flags +#[no_mangle] +#[patchable_function_entry(prefix_nops = 2, entry_nops = 19)] +pub fn fun4() {} + +// The attribute should override patchable-function-entry to 3 +// and patchable-function-prefix to the default of 0, clearing it entirely +#[no_mangle] +#[patchable_function_entry(entry_nops = 3)] +pub fn fun5() {} + +// The attribute should override patchable-function-prefix to 4 +// and patchable-function-entry to the default of 0, clearing it entirely +#[no_mangle] +#[patchable_function_entry(prefix_nops = 4)] +pub fn fun6() {} + +// CHECK: @fun0() unnamed_addr #0 +// CHECK: @fun1() unnamed_addr #1 +// CHECK: @fun2() unnamed_addr #2 +// CHECK: @fun3() unnamed_addr #3 +// CHECK: @fun4() unnamed_addr #4 +// CHECK: @fun5() unnamed_addr #5 +// CHECK: @fun6() unnamed_addr #6 + +// CHECK: attributes #0 = { {{.*}}"patchable-function-entry"="15" {{.*}} } +// CHECK-NOT: attributes #0 = { {{.*}}patchable-function-prefix{{.*}} } + +// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} } + +// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-entry{{.*}} } +// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} } +// CHECK: attributes #2 = { {{.*}} } + +// CHECK: attributes #3 = { {{.*}}"patchable-function-entry"="1"{{.*}}"patchable-function-prefix"="20" {{.*}} } +// CHECK: attributes #4 = { {{.*}}"patchable-function-entry"="19"{{.*}}"patchable-function-prefix"="2" {{.*}} } + +// CHECK: attributes #5 = { {{.*}}"patchable-function-entry"="3"{{.*}} } +// CHECK-NOT: attributes #5 = { {{.*}}patchable-function-prefix{{.*}} } + +// CHECK: attributes #6 = { {{.*}}"patchable-function-prefix"="4"{{.*}} } +// CHECK-NOT: attributes #6 = { {{.*}}patchable-function-entry{{.*}} } diff --git a/tests/codegen-llvm/pattern_type_symbols.rs b/tests/codegen-llvm/pattern_type_symbols.rs new file mode 100644 index 00000000000..e86a9ef27de --- /dev/null +++ b/tests/codegen-llvm/pattern_type_symbols.rs @@ -0,0 +1,22 @@ +//! Check that symbol names with pattern types in them are +//! different from the same symbol with the base type + +//@ compile-flags: -Csymbol-mangling-version=v0 -Copt-level=0 --crate-type=lib + +#![feature(pattern_types)] +#![feature(pattern_type_macro)] + +use std::pat::pattern_type; + +type NanoU32 = crate::pattern_type!(u32 is 0..=999_999_999); + +fn foo() {} + +pub fn bar() { + // CHECK: call pattern_type_symbols::foo:: + // CHECK: call void @_RINvC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_20pattern_type_symbols3foomEB2_ + foo::(); + // CHECK: call pattern_type_symbols::foo::<(u32, [(); 0], [(); 999999999])> + // CHECK: call void @_RINvC[[CRATE_IDENT]]_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_EEB2_ + foo::(); +} diff --git a/tests/codegen-llvm/personality_lifetimes.rs b/tests/codegen-llvm/personality_lifetimes.rs new file mode 100644 index 00000000000..cd81db63953 --- /dev/null +++ b/tests/codegen-llvm/personality_lifetimes.rs @@ -0,0 +1,32 @@ +//@ ignore-msvc +//@ needs-unwind + +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes + +#![crate_type = "lib"] + +struct S; + +impl Drop for S { + #[inline(never)] + fn drop(&mut self) {} +} + +#[inline(never)] +fn might_unwind() {} + +// CHECK-LABEL: @test +#[no_mangle] +pub fn test() { + let _s = S; + // Check that the personality slot alloca gets a lifetime start in each cleanup block, not just + // in the first one. + // CHECK: [[SLOT:%[0-9]+]] = alloca [{{[0-9]+}} x i8] + // CHECK-LABEL: cleanup: + // CHECK: call void @llvm.lifetime.start.{{.*}}({{.*}}) + // CHECK-LABEL: cleanup1: + // CHECK: call void @llvm.lifetime.start.{{.*}}({{.*}}) + might_unwind(); + let _t = S; + might_unwind(); +} diff --git a/tests/codegen-llvm/pgo-counter-bias.rs b/tests/codegen-llvm/pgo-counter-bias.rs new file mode 100644 index 00000000000..48e815dda04 --- /dev/null +++ b/tests/codegen-llvm/pgo-counter-bias.rs @@ -0,0 +1,10 @@ +// Test that __llvm_profile_counter_bias does not get internalized by lto. + +//@ ignore-apple -runtime-counter-relocation not honored on Mach-O +//@ compile-flags: -Cprofile-generate -Cllvm-args=-runtime-counter-relocation -Clto=fat +//@ compile-flags: -Zno-profiler-runtime +//@ no-prefer-dynamic + +// CHECK: @__llvm_profile_counter_bias = {{.*}}global + +pub fn main() {} diff --git a/tests/codegen-llvm/pgo-instrumentation.rs b/tests/codegen-llvm/pgo-instrumentation.rs new file mode 100644 index 00000000000..a8f12ccce1c --- /dev/null +++ b/tests/codegen-llvm/pgo-instrumentation.rs @@ -0,0 +1,20 @@ +// Test that `-Cprofile-generate` creates expected instrumentation artifacts in LLVM IR. + +//@ compile-flags: -Zno-profiler-runtime +//@ compile-flags: -Cprofile-generate -Ccodegen-units=1 + +// CHECK: @__llvm_profile_raw_version = +// CHECK-DAG: @__profc_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = {{.*}}global +// CHECK-DAG: @__profd_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = {{.*}}global +// CHECK-DAG: @__profc_{{.*}}pgo_instrumentation{{.*}}some_other_function{{.*}} = {{.*}}global +// CHECK-DAG: @__profd_{{.*}}pgo_instrumentation{{.*}}some_other_function{{.*}} = {{.*}}global +// CHECK: @__llvm_profile_filename = {{.*}}"default_%m.profraw\00"{{.*}} + +#![crate_type = "lib"] + +#[inline(never)] +fn some_function() {} + +pub fn some_other_function() { + some_function(); +} diff --git a/tests/codegen-llvm/pic-relocation-model.rs b/tests/codegen-llvm/pic-relocation-model.rs new file mode 100644 index 00000000000..a1d1678a6bd --- /dev/null +++ b/tests/codegen-llvm/pic-relocation-model.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -C relocation-model=pic -Copt-level=0 + +#![crate_type = "rlib"] + +// CHECK: define i8 @call_foreign_fn() +#[no_mangle] +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() +extern "C" { + fn foreign_fn() -> u8; +} + +// CHECK: !{i32 {{[78]}}, !"PIC Level", i32 2} diff --git a/tests/codegen-llvm/pie-relocation-model.rs b/tests/codegen-llvm/pie-relocation-model.rs new file mode 100644 index 00000000000..cb8de91ccd7 --- /dev/null +++ b/tests/codegen-llvm/pie-relocation-model.rs @@ -0,0 +1,22 @@ +//@ compile-flags: -C relocation-model=pie -Copt-level=0 +//@ only-x86_64-unknown-linux-gnu + +#![crate_type = "rlib"] + +// With PIE we know local functions cannot be interpositioned, we can mark them +// as dso_local. +// CHECK: define dso_local i8 @call_foreign_fn() +#[no_mangle] +pub fn call_foreign_fn() -> u8 { + unsafe { foreign_fn() } +} + +// 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 i8 @foreign_fn() +extern "C" { + fn foreign_fn() -> u8; +} + +// CHECK: !{i32 {{[78]}}, !"PIC Level", i32 2} +// CHECK: !{i32 7, !"PIE Level", i32 2} diff --git a/tests/codegen-llvm/placement-new.rs b/tests/codegen-llvm/placement-new.rs new file mode 100644 index 00000000000..7f7f0033bec --- /dev/null +++ b/tests/codegen-llvm/placement-new.rs @@ -0,0 +1,39 @@ +//@ compile-flags: -Copt-level=3 +//@ compile-flags: -Zmerge-functions=disabled +#![crate_type = "lib"] + +// Test to check that types with "complex" destructors, but trivial `Default` impls +// are constructed directly into the allocation in `Box::default` and `Arc::default`. + +use std::rc::Rc; +use std::sync::Arc; + +// CHECK-LABEL: @box_default_inplace +#[no_mangle] +pub fn box_default_inplace() -> Box<(String, String)> { + // CHECK-NOT: alloca + // CHECK: [[BOX:%.*]] = {{.*}}call {{.*}}__rust_alloc( + // CHECK-NOT: call void @llvm.memcpy + // CHECK: ret ptr [[BOX]] + Box::default() +} + +// CHECK-LABEL: @rc_default_inplace +#[no_mangle] +pub fn rc_default_inplace() -> Rc<(String, String)> { + // CHECK-NOT: alloca + // CHECK: [[RC:%.*]] = {{.*}}call {{.*}}__rust_alloc( + // CHECK-NOT: call void @llvm.memcpy + // CHECK: ret ptr [[RC]] + Rc::default() +} + +// CHECK-LABEL: @arc_default_inplace +#[no_mangle] +pub fn arc_default_inplace() -> Arc<(String, String)> { + // CHECK-NOT: alloca + // CHECK: [[ARC:%.*]] = {{.*}}call {{.*}}__rust_alloc( + // CHECK-NOT: call void @llvm.memcpy + // CHECK: ret ptr [[ARC]] + Arc::default() +} diff --git a/tests/codegen-llvm/powerpc64le-struct-align-128.rs b/tests/codegen-llvm/powerpc64le-struct-align-128.rs new file mode 100644 index 00000000000..c1c1ac26485 --- /dev/null +++ b/tests/codegen-llvm/powerpc64le-struct-align-128.rs @@ -0,0 +1,96 @@ +// Test that structs aligned to 128 bits are passed with the correct ABI on powerpc64le. +// This is similar to aarch64-struct-align-128.rs, but for ppc. + +//@ add-core-stubs +//@ compile-flags: --target powerpc64le-unknown-linux-gnu +//@ needs-llvm-components: powerpc + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(C)] +pub struct Align8 { + pub a: u64, + pub b: u64, +} + +#[repr(transparent)] +pub struct Transparent8 { + a: Align8, +} + +#[repr(C)] +pub struct Wrapped8 { + a: Align8, +} + +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); +} + +#[repr(C)] +#[repr(align(16))] +pub struct Align16 { + pub a: u64, + pub b: u64, +} + +#[repr(transparent)] +pub struct Transparent16 { + a: Align16, +} + +#[repr(C)] +pub struct Wrapped16 { + pub a: Align16, +} + +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); +} + +#[repr(C)] +#[repr(align(32))] +pub struct Align32 { + pub a: u64, + pub b: u64, + pub c: u64, +} + +#[repr(transparent)] +pub struct Transparent32 { + a: Align32, +} + +#[repr(C)] +pub struct Wrapped32 { + pub a: Align32, +} + +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); +} + +pub unsafe fn main( + a1: Align8, + a2: Transparent8, + a3: Wrapped8, + b1: Align16, + b2: Transparent16, + b3: Wrapped16, + c1: Align32, + c2: Transparent32, + c3: Wrapped32, +) { + test_8(a1, a2, a3); + test_16(b1, b2, b3); + test_32(c1, c2, c3); +} diff --git a/tests/codegen-llvm/precondition-checks.rs b/tests/codegen-llvm/precondition-checks.rs new file mode 100644 index 00000000000..16812ca1720 --- /dev/null +++ b/tests/codegen-llvm/precondition-checks.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 -Cdebug-assertions=no + +// This test ensures that in a debug build which turns off debug assertions, we do not monomorphize +// any of the standard library's unsafe precondition checks. +// The naive codegen of those checks contains the actual check underneath an `if false`, which +// could be optimized out if optimizations are enabled. But if we rely on optimizations to remove +// panic branches, then we can't link compiler_builtins without optimizing it, which means that +// -Zbuild-std doesn't work with -Copt-level=0. +// +// In other words, this tests for a mandatory optimization. + +#![crate_type = "lib"] + +use std::ptr::NonNull; + +// CHECK-LABEL: ; core::ptr::non_null::NonNull::new_unchecked +// CHECK-NOT: call +// CHECK: } + +// CHECK-LABEL: @nonnull_new +#[no_mangle] +pub unsafe fn nonnull_new(ptr: *mut u8) -> NonNull { + // CHECK: ; call core::ptr::non_null::NonNull::new_unchecked + unsafe { NonNull::new_unchecked(ptr) } +} diff --git a/tests/codegen-llvm/ptr-arithmetic.rs b/tests/codegen-llvm/ptr-arithmetic.rs new file mode 100644 index 00000000000..fc4441ef448 --- /dev/null +++ b/tests/codegen-llvm/ptr-arithmetic.rs @@ -0,0 +1,33 @@ +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled + +#![crate_type = "lib"] + +// CHECK-LABEL: ptr @i32_add( +// CHECK-SAME: [[WORD:i[0-9]+]] noundef %n) +#[no_mangle] +pub unsafe fn i32_add(p: *const i32, n: usize) -> *const i32 { + // CHECK: %[[TEMP:.+]] = getelementptr inbounds{{( nuw)?}} i32, ptr %p, [[WORD]] %n + // CHECK: ret ptr %[[TEMP]] + p.add(n) +} + +// Ensure we tell LLVM that the negation in `sub` can't overflow. + +// CHECK-LABEL: ptr @i32_sub( +// CHECK-SAME: [[WORD:i[0-9]+]] noundef %n) +#[no_mangle] +pub unsafe fn i32_sub(p: *const i32, n: usize) -> *const i32 { + // CHECK: %[[DELTA:.+]] = sub nsw [[WORD]] 0, %n + // CHECK: %[[TEMP:.+]] = getelementptr inbounds i32, ptr %p, [[WORD]] %[[DELTA]] + // CHECK: ret ptr %[[TEMP]] + p.sub(n) +} + +// CHECK-LABEL: ptr @i32_offset( +// CHECK-SAME: [[WORD:i[0-9]+]] noundef %d) +#[no_mangle] +pub unsafe fn i32_offset(p: *const i32, d: isize) -> *const i32 { + // CHECK: %[[TEMP:.+]] = getelementptr inbounds i32, ptr %p, [[WORD]] %d + // CHECK: ret ptr %[[TEMP]] + p.offset(d) +} diff --git a/tests/codegen-llvm/ptr-read-metadata.rs b/tests/codegen-llvm/ptr-read-metadata.rs new file mode 100644 index 00000000000..b38cfdbff88 --- /dev/null +++ b/tests/codegen-llvm/ptr-read-metadata.rs @@ -0,0 +1,94 @@ +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled + +#![crate_type = "lib"] + +// Ensure that various forms of reading pointers correctly annotate the `load`s +// with `!noundef` and `!range` metadata to enable extra optimization. + +use std::mem::MaybeUninit; + +// CHECK-LABEL: define {{(dso_local )?}}noundef i8 @copy_byte( +#[no_mangle] +pub unsafe fn copy_byte(p: *const u8) -> u8 { + // CHECK-NOT: load + // CHECK: load i8, ptr %p, align 1 + // CHECK-SAME: !noundef ! + // CHECK-NOT: load + *p +} + +// CHECK-LABEL: define {{(dso_local )?}}noundef i8 @read_byte( +#[no_mangle] +pub unsafe fn read_byte(p: *const u8) -> u8 { + // CHECK-NOT: load + // CHECK: load i8, ptr %p, align 1 + // CHECK-SAME: !noundef ! + // CHECK-NOT: load + p.read() +} + +// CHECK-LABEL: define {{(dso_local )?}}i8 @read_byte_maybe_uninit( +#[no_mangle] +pub unsafe fn read_byte_maybe_uninit(p: *const MaybeUninit) -> MaybeUninit { + // CHECK-NOT: load + // CHECK: load i8, ptr %p, align 1 + // CHECK-NOT: noundef + // CHECK-NOT: load + p.read() +} + +// CHECK-LABEL: define {{(dso_local )?}}noundef i8 @read_byte_assume_init( +#[no_mangle] +pub unsafe fn read_byte_assume_init(p: &MaybeUninit) -> u8 { + // CHECK-NOT: load + // CHECK: load i8, ptr %p, align 1 + // CHECK-SAME: !noundef ! + // CHECK-NOT: load + p.assume_init_read() +} + +// CHECK-LABEL: define {{(dso_local )?}}noundef {{(range\(.*\) )?}}i32 @copy_char( +#[no_mangle] +pub unsafe fn copy_char(p: *const char) -> char { + // CHECK-NOT: load + // CHECK: load i32, ptr %p + // CHECK-SAME: !range ![[RANGE:[0-9]+]] + // CHECK-SAME: !noundef ! + // CHECK-NOT: load + *p +} + +// CHECK-LABEL: define {{(dso_local )?}}noundef {{(range\(.*\) )?}}i32 @read_char( +#[no_mangle] +pub unsafe fn read_char(p: *const char) -> char { + // CHECK-NOT: load + // CHECK: load i32, ptr %p + // CHECK-SAME: !range ![[RANGE]] + // CHECK-SAME: !noundef ! + // CHECK-NOT: load + p.read() +} + +// CHECK-LABEL: define {{(dso_local )?}}i32 @read_char_maybe_uninit( +#[no_mangle] +pub unsafe fn read_char_maybe_uninit(p: *const MaybeUninit) -> MaybeUninit { + // CHECK-NOT: load + // CHECK: load i32, ptr %p + // CHECK-NOT: range + // CHECK-NOT: noundef + // CHECK-NOT: load + p.read() +} + +// CHECK-LABEL: define {{(dso_local )?}}noundef {{(range\(.*\) )?}}i32 @read_char_assume_init( +#[no_mangle] +pub unsafe fn read_char_assume_init(p: &MaybeUninit) -> char { + // CHECK-NOT: load + // CHECK: load i32, ptr %p + // CHECK-SAME: !range ![[RANGE]] + // CHECK-SAME: !noundef ! + // CHECK-NOT: load + p.assume_init_read() +} + +// CHECK: ![[RANGE]] = !{i32 0, i32 1114112} diff --git a/tests/codegen-llvm/range-attribute.rs b/tests/codegen-llvm/range-attribute.rs new file mode 100644 index 00000000000..b81ff9ab3e2 --- /dev/null +++ b/tests/codegen-llvm/range-attribute.rs @@ -0,0 +1,74 @@ +// Checks that range metadata gets emitted on functions result and arguments +// with scalar value. + +// 32-bit systems will return 128bit values using a return area pointer. +//@ revisions: bit32 bit64 +//@[bit32] only-32bit +//@[bit64] only-64bit +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes + +#![crate_type = "lib"] + +use std::num::NonZero; + +// Hack to get the correct size for usize +// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1) +#[no_mangle] +pub fn helper(_: usize) {} + +// bit32: void @nonzero_int({{.*}} sret([16 x i8]) {{.*}}, i128 noundef range(i128 1, 0) %x) +// bit64: noundef range(i128 1, 0) i128 @nonzero_int(i128 noundef range(i128 1, 0) %x) +#[no_mangle] +pub fn nonzero_int(x: NonZero) -> NonZero { + x +} + +// CHECK: noundef range(i8 0, 3) i8 @optional_bool(i8{{.*}} range(i8 0, 3) %x) +#[no_mangle] +pub fn optional_bool(x: Option) -> Option { + x +} + +pub enum Enum0 { + A(bool), + B, + C, +} + +// CHECK: noundef range(i8 0, 4) i8 @enum0_value(i8{{.*}} range(i8 0, 4) %x) +#[no_mangle] +pub fn enum0_value(x: Enum0) -> Enum0 { + x +} + +pub enum Enum1 { + A(u64), + B(u64), + C(u64), +} + +// bit32: void @enum1_value({{.*}} sret({{[^,]*}}) {{[^,]*}}, [[ENUM1_TYP:i[0-9]+]] +// bit64: { [[ENUM1_TYP:i[0-9]+]], i64 } @enum1_value([[ENUM1_TYP]] +// CHECK-SAME: noundef range([[ENUM1_TYP]] 0, 3) %x.0, i64 noundef %x.1) +#[no_mangle] +pub fn enum1_value(x: Enum1) -> Enum1 { + x +} + +pub enum Enum2 { + A(Enum0), + B(Enum0), + C(Enum0), +} + +// CHECK: { i8, i8 } @enum2_value(i8 noundef range(i8 0, 3) %x.0, i8 noundef %x.1) +#[no_mangle] +pub fn enum2_value(x: Enum2) -> Enum2 { + x +} + +// CHECK: noundef [[USIZE]] @takes_slice(ptr noalias noundef nonnull readonly align 4 %x.0, [[USIZE]] noundef %x.1) +#[no_mangle] +pub fn takes_slice(x: &[i32]) -> usize { + x.len() +} diff --git a/tests/codegen-llvm/range-loop.rs b/tests/codegen-llvm/range-loop.rs new file mode 100644 index 00000000000..b131beb40dd --- /dev/null +++ b/tests/codegen-llvm/range-loop.rs @@ -0,0 +1,44 @@ +//@ ignore-std-debug-assertions +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes + +#![crate_type = "lib"] + +// Ensure that MIR optimizations have cleaned things up enough that the IR we +// emit is good even without running the LLVM optimizations. + +// CHECK-NOT: define + +// CHECK-LABEL: define{{.+}}void @call_for_zero_to_n +#[no_mangle] +pub fn call_for_zero_to_n(n: u32, f: fn(u32)) { + // CHECK: start: + // CHECK-NOT: alloca + // CHECK: %[[IND:.+]] = alloca [4 x i8] + // CHECK-NEXT: %[[ALWAYS_SOME_OPTION:.+]] = alloca + // CHECK-NOT: alloca + // CHECK: store i32 0, ptr %[[IND]], + // CHECK: br label %[[HEAD:.+]] + + // CHECK: [[HEAD]]: + // CHECK: %[[T1:.+]] = load i32, ptr %[[IND]], + // CHECK: %[[NOT_DONE:.+]] = icmp ult i32 %[[T1]], %n + // CHECK: br i1 %[[NOT_DONE]], label %[[BODY:.+]], label %[[BREAK:.+]] + + // CHECK: [[BREAK]]: + // CHECK: ret void + + // CHECK: [[BODY]]: + // CHECK: %[[T2:.+]] = load i32, ptr %[[IND]], + // CHECK: %[[T3:.+]] = add nuw i32 %[[T2]], 1 + // CHECK: store i32 %[[T3]], ptr %[[IND]], + + // CHECK: store i32 %[[T2]] + // CHECK: %[[T4:.+]] = load i32 + // CHECK: call void %f(i32{{.+}}%[[T4]]) + + for i in 0..n { + f(i); + } +} + +// CHECK-NOT: define diff --git a/tests/codegen-llvm/range_to_inclusive.rs b/tests/codegen-llvm/range_to_inclusive.rs new file mode 100644 index 00000000000..6d939f40f55 --- /dev/null +++ b/tests/codegen-llvm/range_to_inclusive.rs @@ -0,0 +1,28 @@ +//! Test that `RangeTo` and `RangeToInclusive` generate identical +//! (and optimal) code; #63646 +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled +#![crate_type = "lib"] + +#[no_mangle] +// CHECK-LABEL: range_to( +pub fn range_to(a: i32, mut b: i32) -> i32 { + // CHECK: %1 = and i32 %0, %a + // CHECK-NEXT: ret i32 %1 + for _ in 0..65 { + b &= a; + } + + b +} + +#[no_mangle] +// CHECK-LABEL: range_to_inclusive( +pub fn range_to_inclusive(a: i32, mut b: i32) -> i32 { + // CHECK: %1 = and i32 %0, %a + // CHECK-NEXT: ret i32 %1 + for _ in 0..=64 { + b &= a; + } + + b +} diff --git a/tests/codegen-llvm/refs.rs b/tests/codegen-llvm/refs.rs new file mode 100644 index 00000000000..97c36295085 --- /dev/null +++ b/tests/codegen-llvm/refs.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 -Copt-level=0 + +#![crate_type = "lib"] + +// Hack to get the correct size for the length part in slices +// CHECK: @helper([[USIZE:i[0-9]+]] %_1) +#[no_mangle] +pub fn helper(_: usize) {} + +// CHECK-LABEL: @ref_dst +#[no_mangle] +pub fn ref_dst(s: &[u8]) { + // We used to generate an extra alloca and memcpy to ref the dst, so check that we copy + // directly to the alloca for "x" + // CHECK: store ptr %s.0, {{.*}} %x + // CHECK: [[X1:%[0-9]+]] = getelementptr inbounds i8, {{.*}} %x, {{i32 4|i64 8}} + // CHECK: store [[USIZE]] %s.1, {{.*}} [[X1]] + + let x = &*s; + &x; // keep variable in an alloca +} diff --git a/tests/codegen-llvm/reg-struct-return.rs b/tests/codegen-llvm/reg-struct-return.rs new file mode 100644 index 00000000000..dfc9f8c519c --- /dev/null +++ b/tests/codegen-llvm/reg-struct-return.rs @@ -0,0 +1,206 @@ +// Checks how `reg-struct-return` flag works with different calling conventions: +// Return struct with 8/16/32/64 bit size will be converted into i8/i16/i32/i64 +// (like abi_return_struct_as_int target spec). +// x86 only. + +//@ revisions: ENABLED DISABLED +//@ add-core-stubs +//@ compile-flags: --target i686-unknown-linux-gnu -Cno-prepopulate-passes -Copt-level=3 +//@ [ENABLED] compile-flags: -Zreg-struct-return +//@ needs-llvm-components: x86 + +#![crate_type = "lib"] +#![no_std] +#![no_core] +#![feature(no_core, lang_items)] + +extern crate minicore; +use minicore::*; + +#[repr(C)] +pub struct Foo { + x: u32, + y: u32, +} + +#[repr(C)] +pub struct Foo1 { + x: u32, +} + +#[repr(C)] +pub struct Foo2 { + x: bool, + y: bool, + z: i16, +} + +#[repr(C)] +pub struct Foo3 { + x: i16, + y: bool, + z: bool, +} + +#[repr(C)] +pub struct Foo4 { + x: char, + y: bool, + z: u8, +} + +#[repr(C)] +pub struct Foo5 { + x: u32, + y: u16, + z: u8, + a: bool, +} + +#[repr(C)] +pub struct FooOversize1 { + x: u32, + y: u32, + z: u32, +} + +#[repr(C)] +pub struct FooOversize2 { + f0: u16, + f1: u16, + f2: u16, + f3: u16, + f4: u16, +} + +#[repr(C)] +pub struct FooFloat1 { + x: f32, + y: f32, +} + +#[repr(C)] +pub struct FooFloat2 { + x: f64, +} + +#[repr(C)] +pub struct FooFloat3 { + x: f32, +} + +pub mod tests { + use { + Foo, Foo1, Foo2, Foo3, Foo4, Foo5, FooFloat1, FooFloat2, FooFloat3, FooOversize1, + FooOversize2, + }; + + // ENABLED: i64 @f1() + // DISABLED: void @f1(ptr {{.*}}sret + #[no_mangle] + pub extern "fastcall" fn f1() -> Foo { + Foo { x: 1, y: 2 } + } + + // CHECK: { i32, i32 } @f2() + #[no_mangle] + pub extern "Rust" fn f2() -> Foo { + Foo { x: 1, y: 2 } + } + + // ENABLED: i64 @f3() + // DISABLED: void @f3(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f3() -> Foo { + Foo { x: 1, y: 2 } + } + + // ENABLED: i64 @f4() + // DISABLED: void @f4(ptr {{.*}}sret + #[no_mangle] + pub extern "cdecl" fn f4() -> Foo { + Foo { x: 1, y: 2 } + } + + // ENABLED: i64 @f5() + // DISABLED: void @f5(ptr {{.*}}sret + #[no_mangle] + pub extern "stdcall" fn f5() -> Foo { + Foo { x: 1, y: 2 } + } + + // ENABLED: i64 @f6() + // DISABLED: void @f6(ptr {{.*}}sret + #[no_mangle] + pub extern "thiscall" fn f6() -> Foo { + Foo { x: 1, y: 2 } + } + + // ENABLED: i32 @f7() + // DISABLED: void @f7(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f7() -> Foo1 { + Foo1 { x: 1 } + } + + // ENABLED: i32 @f8() + // DISABLED: void @f8(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f8() -> Foo2 { + Foo2 { x: true, y: false, z: 5 } + } + + // ENABLED: i32 @f9() + // DISABLED: void @f9(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f9() -> Foo3 { + Foo3 { x: 5, y: false, z: true } + } + + // ENABLED: i64 @f10() + // DISABLED: void @f10(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f10() -> Foo4 { + Foo4 { x: 'x', y: true, z: 170 } + } + + // ENABLED: i64 @f11() + // DISABLED: void @f11(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f11() -> Foo5 { + Foo5 { x: 1, y: 2, z: 3, a: true } + } + + // CHECK: void @f12(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f12() -> FooOversize1 { + FooOversize1 { x: 1, y: 2, z: 3 } + } + + // CHECK: void @f13(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f13() -> FooOversize2 { + FooOversize2 { f0: 1, f1: 2, f2: 3, f3: 4, f4: 5 } + } + + // ENABLED: i64 @f14() + // DISABLED: void @f14(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f14() -> FooFloat1 { + FooFloat1 { x: 1.0, y: 1.0 } + } + + // ENABLED: double @f15() + // DISABLED: void @f15(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f15() -> FooFloat2 { + FooFloat2 { x: 1.0 } + } + + // ENABLED: float @f16() + // DISABLED: void @f16(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f16() -> FooFloat3 { + FooFloat3 { x: 1.0 } + } +} diff --git a/tests/codegen-llvm/regparm-inreg.rs b/tests/codegen-llvm/regparm-inreg.rs new file mode 100644 index 00000000000..15702804dfd --- /dev/null +++ b/tests/codegen-llvm/regparm-inreg.rs @@ -0,0 +1,125 @@ +// Checks how `regparm` flag works with different calling conventions: +// marks function arguments as "inreg" like the C/C++ compilers for the platforms. +// x86 only. + +//@ add-core-stubs +//@ compile-flags: --target i686-unknown-linux-gnu -Cno-prepopulate-passes -Copt-level=3 -Ctarget-feature=+avx +//@ needs-llvm-components: x86 + +//@ revisions:regparm0 regparm1 regparm2 regparm3 +//@[regparm0] compile-flags: -Zregparm=0 +//@[regparm1] compile-flags: -Zregparm=1 +//@[regparm2] compile-flags: -Zregparm=2 +//@[regparm3] compile-flags: -Zregparm=3 + +#![crate_type = "lib"] +#![no_core] +#![feature(no_core, lang_items, repr_simd)] + +extern crate minicore; +use minicore::*; + +pub mod tests { + // regparm doesn't work for "fastcall" calling conv (only 2 inregs) + // CHECK: @f1(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) + #[no_mangle] + pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {} + + // regparm0: @f3(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm1: @f3(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm2: @f3(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) + // regparm3: @f3(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + #[no_mangle] + pub extern "C" fn f3(_: i32, _: i32, _: i32) {} + + // regparm0: @f4(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm1: @f4(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm2: @f4(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) + // regparm3: @f4(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + #[no_mangle] + pub extern "cdecl" fn f4(_: i32, _: i32, _: i32) {} + + // regparm0: @f5(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm1: @f5(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm2: @f5(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) + // regparm3: @f5(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + #[no_mangle] + pub extern "stdcall" fn f5(_: i32, _: i32, _: i32) {} + + // regparm doesn't work for thiscall + // CHECK: @f6(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) + #[no_mangle] + pub extern "thiscall" fn f6(_: i32, _: i32, _: i32) {} + + struct S1 { + x1: i32, + } + // regparm0: @f7(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3, i32 noundef %_4) + // regparm1: @f7(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3, i32 noundef %_4) + // regparm2: @f7(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3, i32 noundef %_4) + // regparm3: @f7(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3, + // regparm3-SAME: i32 noundef %_4) + #[no_mangle] + pub extern "C" fn f7(_: i32, _: i32, _: S1, _: i32) {} + + #[repr(C)] + struct S2 { + x1: i32, + x2: i32, + } + // regparm0: @f8(i32 noundef %_1, i32 noundef %_2, ptr {{.*}} %_3, i32 noundef %_4) + // regparm1: @f8(i32 inreg noundef %_1, i32 noundef %_2, ptr {{.*}} %_3, i32 noundef %_4) + // regparm2: @f8(i32 inreg noundef %_1, i32 inreg noundef %_2, ptr {{.*}} %_3, i32 noundef %_4) + // regparm3: @f8(i32 inreg noundef %_1, i32 inreg noundef %_2, ptr {{.*}} %_3, + // regparm3-SAME: i32 inreg noundef %_4) + #[no_mangle] + pub extern "C" fn f8(_: i32, _: i32, _: S2, _: i32) {} + + // regparm0: @f9(i1 noundef zeroext %_1, i16 noundef signext %_2, i64 noundef %_3, + // regparm0-SAME: i128 noundef %_4) + // regparm1: @f9(i1 inreg noundef zeroext %_1, i16 noundef signext %_2, i64 noundef %_3, + // regparm1-SAME: i128 noundef %_4) + // regparm2: @f9(i1 inreg noundef zeroext %_1, i16 inreg noundef signext %_2, i64 noundef %_3, + // regparm2-SAME: i128 noundef %_4) + // regparm3: @f9(i1 inreg noundef zeroext %_1, i16 inreg noundef signext %_2, i64 noundef %_3, + // regparm3-SAME: i128 noundef %_4) + #[no_mangle] + pub extern "C" fn f9(_: bool, _: i16, _: i64, _: u128) {} + + // regparm0: @f10(float noundef %_1, double noundef %_2, i1 noundef zeroext %_3, + // regparm0-SAME: i16 noundef signext %_4) + // regparm1: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3, + // regparm1-SAME: i16 noundef signext %_4) + // regparm2: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3, + // regparm2-SAME: i16 inreg noundef signext %_4) + // regparm3: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3, + // regparm3-SAME: i16 inreg noundef signext %_4) + #[no_mangle] + pub extern "C" fn f10(_: f32, _: f64, _: bool, _: i16) {} + + #[allow(non_camel_case_types)] + #[repr(simd)] + pub struct __m128([f32; 4]); + + // regparm0: @f11(i32 noundef %_1, <4 x float> %_2, i32 noundef %_3, i32 noundef %_4) + // regparm1: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 noundef %_3, i32 noundef %_4) + // regparm2: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 inreg noundef %_3, + // regparm2-SAME: i32 noundef %_4) + // regparm3: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 inreg noundef %_3, + // regparm3-SAME: i32 inreg noundef %_4) + #[no_mangle] + pub extern "C" fn f11(_: i32, _: __m128, _: i32, _: i32) {} + + #[allow(non_camel_case_types)] + #[repr(simd)] + pub struct __m256([f32; 8]); + + // regparm0: @f12(i32 noundef %_1, <8 x float> %_2, i32 noundef %_3, i32 noundef %_4) + // regparm1: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 noundef %_3, i32 noundef %_4) + // regparm2: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 inreg noundef %_3, + // regparm2-SAME: i32 noundef %_4) + // regparm3: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 inreg noundef %_3, + // regparm3-SAME: i32 inreg noundef %_4) + #[no_mangle] + pub extern "C" fn f12(_: i32, _: __m256, _: i32, _: i32) {} +} diff --git a/tests/codegen-llvm/remap_path_prefix/aux_mod.rs b/tests/codegen-llvm/remap_path_prefix/aux_mod.rs new file mode 100644 index 00000000000..3217e9e51e7 --- /dev/null +++ b/tests/codegen-llvm/remap_path_prefix/aux_mod.rs @@ -0,0 +1,6 @@ +//@ ignore-auxiliary (used by `./main.rs`) + +#[inline] +pub fn some_aux_mod_function() -> i32 { + 1234 +} diff --git a/tests/codegen-llvm/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs b/tests/codegen-llvm/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs new file mode 100644 index 00000000000..7afc16ec72f --- /dev/null +++ b/tests/codegen-llvm/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs @@ -0,0 +1,8 @@ +// + +//@ compile-flags: -g --remap-path-prefix={{cwd}}=/the/aux-cwd --remap-path-prefix={{src-base}}/remap_path_prefix/auxiliary=/the/aux-src + +#[inline] +pub fn some_aux_function() -> i32 { + 1234 +} diff --git a/tests/codegen-llvm/remap_path_prefix/auxiliary/xcrate-generic.rs b/tests/codegen-llvm/remap_path_prefix/auxiliary/xcrate-generic.rs new file mode 100644 index 00000000000..9d5cdfe063b --- /dev/null +++ b/tests/codegen-llvm/remap_path_prefix/auxiliary/xcrate-generic.rs @@ -0,0 +1,8 @@ +// +//@ compile-flags: -g --remap-path-prefix={{cwd}}=/the/aux-cwd --remap-path-prefix={{src-base}}/remap_path_prefix/auxiliary=/the/aux-src + +#![crate_type = "lib"] + +pub fn foo() -> T { + T::default() +} diff --git a/tests/codegen-llvm/remap_path_prefix/issue-73167-remap-std.rs b/tests/codegen-llvm/remap_path_prefix/issue-73167-remap-std.rs new file mode 100644 index 00000000000..eb610168dd3 --- /dev/null +++ b/tests/codegen-llvm/remap_path_prefix/issue-73167-remap-std.rs @@ -0,0 +1,15 @@ +//@ ignore-windows + +//@ compile-flags: -g -C no-prepopulate-passes -Z simulate-remapped-rust-src-base=/rustc/xyz + +// Here we check that importing std will not cause real path to std source files +// to leak. If rustc was compiled with remap-debuginfo = true, this should be +// true automatically. If paths to std library hasn't been remapped, we use the +// above simulate-remapped-rust-src-base option to do it temporarily + +// CHECK: !DIFile(filename: "{{/rustc/.*/library/std/src/panic.rs}}" +fn main() { + std::thread::spawn(|| { + println!("hello"); + }); +} diff --git a/tests/codegen-llvm/remap_path_prefix/main.rs b/tests/codegen-llvm/remap_path_prefix/main.rs new file mode 100644 index 00000000000..7d17b3b67cf --- /dev/null +++ b/tests/codegen-llvm/remap_path_prefix/main.rs @@ -0,0 +1,28 @@ +//@ ignore-windows +// + +//@ compile-flags: -g -C no-prepopulate-passes --remap-path-prefix={{cwd}}=/the/cwd --remap-path-prefix={{src-base}}=/the/src -Zinline-mir=no +//@ aux-build:remap_path_prefix_aux.rs + +extern crate remap_path_prefix_aux; + +// Here we check that submodules and include files are found using the path without +// remapping. This test requires that rustc is called with an absolute path. +mod aux_mod; +include!("aux_mod.rs"); + +// Here we check that the expansion of the file!() macro is mapped. +// CHECK: @alloc_5761061597a97f66e13ef2ff92712c4b = private unnamed_addr constant [34 x i8] c"/the/src/remap_path_prefix/main.rs" +pub static FILE_PATH: &'static str = file!(); + +fn main() { + remap_path_prefix_aux::some_aux_function(); + aux_mod::some_aux_mod_function(); + some_aux_mod_function(); +} + +// Here we check that local debuginfo is mapped correctly. +// CHECK: !DIFile(filename: "/the/src/remap_path_prefix/main.rs", directory: "" + +// And here that debuginfo from other crates are expanded to absolute paths. +// CHECK: !DIFile(filename: "/the/aux-src/remap_path_prefix_aux.rs", directory: "" diff --git a/tests/codegen-llvm/remap_path_prefix/xcrate-generic.rs b/tests/codegen-llvm/remap_path_prefix/xcrate-generic.rs new file mode 100644 index 00000000000..db69b72d904 --- /dev/null +++ b/tests/codegen-llvm/remap_path_prefix/xcrate-generic.rs @@ -0,0 +1,14 @@ +//@ ignore-windows +//@ compile-flags: -g -C metadata=foo -C no-prepopulate-passes +//@ aux-build:xcrate-generic.rs + +#![crate_type = "lib"] + +extern crate xcrate_generic; + +pub fn foo() { + println!("{}", xcrate_generic::foo::()); +} + +// Here we check that local debuginfo is mapped correctly. +// CHECK: !DIFile(filename: "/the/aux-src/xcrate-generic.rs", directory: "" diff --git a/tests/codegen-llvm/repeat-operand-zero-len.rs b/tests/codegen-llvm/repeat-operand-zero-len.rs new file mode 100644 index 00000000000..b4cec42a07c --- /dev/null +++ b/tests/codegen-llvm/repeat-operand-zero-len.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes + +// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`. +// It only applies when the resulting array is a ZST, so the test is written in +// such a way as to keep MIR optimizations from seeing that fact and removing +// the local and statement altogether. (At the time of writing, no other codegen +// test hit that code path, nor did a stage 2 build of the compiler.) + +#![crate_type = "lib"] + +#[repr(transparent)] +pub struct Wrapper([T; N]); + +// CHECK-LABEL: define {{.+}}do_repeat{{.+}}(i32 noundef %x) +// CHECK-NEXT: start: +// CHECK-NOT: alloca +// CHECK-NEXT: ret void +#[inline(never)] +pub fn do_repeat(x: T) -> Wrapper { + Wrapper([x; N]) +} + +// CHECK-LABEL: @trigger_repeat_zero_len +#[no_mangle] +pub fn trigger_repeat_zero_len() -> Wrapper { + // CHECK: call void {{.+}}do_repeat{{.+}}(i32 noundef 4) + do_repeat(4) +} diff --git a/tests/codegen-llvm/repeat-operand-zst-elem.rs b/tests/codegen-llvm/repeat-operand-zst-elem.rs new file mode 100644 index 00000000000..c3637759afa --- /dev/null +++ b/tests/codegen-llvm/repeat-operand-zst-elem.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes + +// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`. +// It only applies when the resulting array is a ZST, so the test is written in +// such a way as to keep MIR optimizations from seeing that fact and removing +// the local and statement altogether. (At the time of writing, no other codegen +// test hit that code path, nor did a stage 2 build of the compiler.) + +#![crate_type = "lib"] + +#[repr(transparent)] +pub struct Wrapper([T; N]); + +// CHECK-LABEL: define {{.+}}do_repeat{{.+}}() +// CHECK-NEXT: start: +// CHECK-NOT: alloca +// CHECK-NEXT: ret void +#[inline(never)] +pub fn do_repeat(x: T) -> Wrapper { + Wrapper([x; N]) +} + +// CHECK-LABEL: @trigger_repeat_zst_elem +#[no_mangle] +pub fn trigger_repeat_zst_elem() -> Wrapper<(), 8> { + // CHECK: call void {{.+}}do_repeat{{.+}}() + do_repeat(()) +} diff --git a/tests/codegen-llvm/repeat-trusted-len.rs b/tests/codegen-llvm/repeat-trusted-len.rs new file mode 100644 index 00000000000..95379535971 --- /dev/null +++ b/tests/codegen-llvm/repeat-trusted-len.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -Copt-level=3 +// + +#![crate_type = "lib"] + +use std::iter; + +// CHECK-LABEL: @repeat_take_collect +#[no_mangle] +pub fn repeat_take_collect() -> Vec { + // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}align 1{{.*}} %{{.*}}, i8 42, i{{[0-9]+}} 100000, i1 false) + iter::repeat(42).take(100000).collect() +} + +// CHECK-LABEL: @repeat_with_take_collect +#[no_mangle] +pub fn repeat_with_take_collect() -> Vec { + // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}align 1{{.*}} %{{.*}}, i8 13, i{{[0-9]+}} 12345, i1 false) + iter::repeat_with(|| 13).take(12345).collect() +} diff --git a/tests/codegen-llvm/repr/transparent-byval-struct-ptr.rs b/tests/codegen-llvm/repr/transparent-byval-struct-ptr.rs new file mode 100644 index 00000000000..0918884144f --- /dev/null +++ b/tests/codegen-llvm/repr/transparent-byval-struct-ptr.rs @@ -0,0 +1,111 @@ +//@ add-core-stubs +//@ revisions: i686-linux i686-freebsd x64-linux x64-apple +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes + +//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu +//@[i686-linux] needs-llvm-components: x86 +//@[i686-freebsd] compile-flags: --target i686-unknown-freebsd +//@[i686-freebsd] needs-llvm-components: x86 +//@[x64-linux] compile-flags: --target x86_64-unknown-linux-gnu +//@[x64-linux] needs-llvm-components: x86 +//@[x64-apple] compile-flags: --target x86_64-apple-darwin +//@[x64-apple] needs-llvm-components: x86 + +// See ./transparent.rs +// Some platforms pass large aggregates using immediate arrays in LLVMIR +// Other platforms pass large aggregates using by-value struct pointer in LLVMIR +// Yet more platforms pass large aggregates using opaque pointer in LLVMIR +// This covers the "by-value struct pointer" case. + +#![feature(no_core, lang_items, transparent_unions)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +impl Copy for BigS {} +impl Copy for BigU {} + +#[repr(C)] +pub struct BigS([u32; 16]); + +#[repr(transparent)] +pub struct TsBigS(BigS); + +#[repr(transparent)] +pub union TuBigS { + field: BigS, +} + +#[repr(transparent)] +pub enum TeBigS { + Variant(BigS), +} + +// CHECK: define{{.*}}void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], ptr [[BIGS_ARG_ATTRS1:.*]] byval([64 x i8]) [[BIGS_ARG_ATTRS2:.*]]) +#[no_mangle] +pub extern "C" fn test_BigS(_: BigS) -> BigS { + loop {} +} + +// CHECK: define{{.*}}void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval([64 x i8]) [[BIGS_ARG_ATTRS2:.*]]) +#[no_mangle] +pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS { + loop {} +} + +// CHECK: define{{.*}}void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval([64 x i8]) [[BIGS_ARG_ATTRS2:.*]]) +#[no_mangle] +pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { + loop {} +} + +// CHECK: define{{.*}}void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval([64 x i8]) [[BIGS_ARG_ATTRS2]]) +#[no_mangle] +pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { + loop {} +} + +#[repr(C)] +pub union BigU { + foo: [u32; 16], +} + +#[repr(transparent)] +pub struct TsBigU(BigU); + +#[repr(transparent)] +pub union TuBigU { + field: BigU, +} + +#[repr(transparent)] +pub enum TeBigU { + Variant(BigU), +} + +// CHECK: define{{.*}}void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1:.*]] byval([64 x i8]) [[BIGU_ARG_ATTRS2:.*]]) +#[no_mangle] +pub extern "C" fn test_BigU(_: BigU) -> BigU { + loop {} +} + +// CHECK: define{{.*}}void @test_TsBigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval([64 x i8]) [[BIGU_ARG_ATTRS2]]) +#[no_mangle] +pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU { + loop {} +} + +// CHECK: define{{.*}}void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval([64 x i8]) [[BIGU_ARG_ATTRS2]]) +#[no_mangle] +pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU { + loop {} +} + +// CHECK: define{{.*}}void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval([64 x i8]) [[BIGU_ARG_ATTRS2]]) +#[no_mangle] +pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU { + loop {} +} diff --git a/tests/codegen-llvm/repr/transparent-imm-array.rs b/tests/codegen-llvm/repr/transparent-imm-array.rs new file mode 100644 index 00000000000..6dad0447784 --- /dev/null +++ b/tests/codegen-llvm/repr/transparent-imm-array.rs @@ -0,0 +1,116 @@ +//@ add-core-stubs +//@ revisions: arm-linux arm-android armv7-linux armv7-android mips thumb sparc +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes + +//@[arm-linux] compile-flags: --target arm-unknown-linux-gnueabi +//@[arm-linux] needs-llvm-components: arm +//@[arm-android] compile-flags: --target arm-linux-androideabi +//@[arm-android] needs-llvm-components: arm +//@[armv7-linux] compile-flags: --target armv7-unknown-linux-gnueabi +//@[armv7-linux] needs-llvm-components: arm +//@[armv7-android] compile-flags: --target armv7-linux-androideabi +//@[armv7-android] needs-llvm-components: arm +//@[mips] compile-flags: --target mips-unknown-linux-gnu +//@[mips] needs-llvm-components: mips +//@[thumb] compile-flags: --target thumbv7neon-linux-androideabi +//@[thumb] needs-llvm-components: arm +//@[sparc] compile-flags: --target sparc-unknown-linux-gnu +//@[sparc] needs-llvm-components: sparc + +// See ./transparent.rs +// Some platforms pass large aggregates using immediate arrays in LLVMIR +// Other platforms pass large aggregates using by-value struct pointer in LLVMIR +// Yet more platforms pass large aggregates using opaque pointer in LLVMIR +// This covers the "immediate array" case. + +#![feature(no_core, lang_items, transparent_unions)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; +impl Copy for BigS {} +impl Copy for BigU {} + +#[repr(C)] +pub struct BigS([u32; 16]); + +#[repr(transparent)] +pub struct TsBigS(BigS); + +#[repr(transparent)] +pub union TuBigS { + field: BigS, +} + +#[repr(transparent)] +pub enum TeBigS { + Variant(BigS), +} + +// CHECK: define void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], [16 x i32] +#[no_mangle] +pub extern "C" fn test_BigS(_: BigS) -> BigS { + loop {} +} + +// CHECK: define void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [16 x i32] +#[no_mangle] +pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS { + loop {} +} + +// CHECK: define void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [16 x i32] +#[no_mangle] +pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { + loop {} +} + +// CHECK: define void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [16 x i32] +#[no_mangle] +pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { + loop {} +} + +#[repr(C)] +pub union BigU { + foo: [u32; 16], +} + +#[repr(transparent)] +pub struct TsBigU(BigU); + +#[repr(transparent)] +pub union TuBigU { + field: BigU, +} + +#[repr(transparent)] +pub enum TeBigU { + Variant(BigU), +} + +// CHECK: define void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], [16 x i32] +#[no_mangle] +pub extern "C" fn test_BigU(_: BigU) -> BigU { + loop {} +} + +// CHECK: define void @test_TsBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [16 x i32] +#[no_mangle] +pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU { + loop {} +} + +// CHECK: define void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [16 x i32] +#[no_mangle] +pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU { + loop {} +} + +// CHECK: define void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [16 x i32] +#[no_mangle] +pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU { + loop {} +} diff --git a/tests/codegen-llvm/repr/transparent-mips64.rs b/tests/codegen-llvm/repr/transparent-mips64.rs new file mode 100644 index 00000000000..98901350154 --- /dev/null +++ b/tests/codegen-llvm/repr/transparent-mips64.rs @@ -0,0 +1,103 @@ +//@ add-core-stubs +//@ revisions: mips64 mips64el +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes + +//@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 +//@[mips64] needs-llvm-components: mips +//@[mips64el] compile-flags: --target mips64el-unknown-linux-gnuabi64 +//@[mips64el] needs-llvm-components: mips + +// See ./transparent.rs + +#![feature(no_core, lang_items, transparent_unions)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +impl Copy for BigS {} +impl Copy for BigU {} + +#[repr(C)] +pub struct BigS([u32; 16]); + +#[repr(transparent)] +pub struct TsBigS(BigS); + +#[repr(transparent)] +pub union TuBigS { + field: BigS, +} + +#[repr(transparent)] +pub enum TeBigS { + Variant(BigS), +} + +// CHECK: define void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], [8 x i64] +#[no_mangle] +pub extern "C" fn test_BigS(_: BigS) -> BigS { + loop {} +} + +// CHECK: define void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [8 x i64] +#[no_mangle] +pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS { + loop {} +} + +// CHECK: define void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [8 x i64] +#[no_mangle] +pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { + loop {} +} + +// CHECK: define void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [8 x i64] +#[no_mangle] +pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { + loop {} +} + +#[repr(C)] +pub union BigU { + foo: [u32; 16], +} + +#[repr(transparent)] +pub struct TsBigU(BigU); + +#[repr(transparent)] +pub union TuBigU { + field: BigU, +} + +#[repr(transparent)] +pub enum TeBigU { + Variant(BigU), +} + +// CHECK: define void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], [8 x i64] +#[no_mangle] +pub extern "C" fn test_BigU(_: BigU) -> BigU { + loop {} +} + +// CHECK: define void @test_TsBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [8 x i64] +#[no_mangle] +pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU { + loop {} +} + +// CHECK: define void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [8 x i64] +#[no_mangle] +pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU { + loop {} +} + +// CHECK: define void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [8 x i64] +#[no_mangle] +pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU { + loop {} +} diff --git a/tests/codegen-llvm/repr/transparent-opaque-ptr.rs b/tests/codegen-llvm/repr/transparent-opaque-ptr.rs new file mode 100644 index 00000000000..7911370c478 --- /dev/null +++ b/tests/codegen-llvm/repr/transparent-opaque-ptr.rs @@ -0,0 +1,109 @@ +//@ add-core-stubs +//@ revisions: aarch64-linux aarch64-darwin wasm32-wasip1 +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes + +//@[aarch64-linux] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64-linux] needs-llvm-components: aarch64 +//@[aarch64-darwin] compile-flags: --target aarch64-apple-darwin +//@[aarch64-darwin] needs-llvm-components: aarch64 +//@[wasm32-wasip1] compile-flags: --target wasm32-wasip1 +//@[wasm32-wasip1] needs-llvm-components: webassembly + +// See ./transparent.rs +// Some platforms pass large aggregates using immediate arrays in LLVMIR +// Other platforms pass large aggregates using by-value struct pointer in LLVMIR +// Yet more platforms pass large aggregates using opaque pointer in LLVMIR +// This covers the "opaque pointer" case. + +#![feature(no_core, lang_items, transparent_unions)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +impl Copy for BigS {} +impl Copy for BigU {} + +#[repr(C)] +pub struct BigS([u32; 16]); + +#[repr(transparent)] +pub struct TsBigS(BigS); + +#[repr(transparent)] +pub union TuBigS { + field: BigS, +} + +#[repr(transparent)] +pub enum TeBigS { + Variant(BigS), +} + +// CHECK: define{{.*}}void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], ptr [[BIGS_ARG_ATTRS1:.*]]) +#[no_mangle] +pub extern "C" fn test_BigS(_: BigS) -> BigS { + loop {} +} + +// CHECK: define{{.*}}void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]]) +#[no_mangle] +pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS { + loop {} +} + +// CHECK: define{{.*}}void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]]) +#[no_mangle] +pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { + loop {} +} + +// CHECK: define{{.*}}void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]]) +#[no_mangle] +pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { + loop {} +} + +#[repr(C)] +pub union BigU { + foo: [u32; 16], +} + +#[repr(transparent)] +pub struct TsBigU(BigU); + +#[repr(transparent)] +pub union TuBigU { + field: BigU, +} + +#[repr(transparent)] +pub enum TeBigU { + Variant(BigU), +} + +// CHECK: define{{.*}}void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1:.*]]) +#[no_mangle] +pub extern "C" fn test_BigU(_: BigU) -> BigU { + loop {} +} + +// CHECK: define{{.*}}void @test_TsBigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]]) +#[no_mangle] +pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU { + loop {} +} + +// CHECK: define{{.*}}void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]]) +#[no_mangle] +pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU { + loop {} +} + +// CHECK: define{{.*}}void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]]) +#[no_mangle] +pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU { + loop {} +} diff --git a/tests/codegen-llvm/repr/transparent-sparc64.rs b/tests/codegen-llvm/repr/transparent-sparc64.rs new file mode 100644 index 00000000000..62bfc8a5fce --- /dev/null +++ b/tests/codegen-llvm/repr/transparent-sparc64.rs @@ -0,0 +1,113 @@ +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes --target sparc64-unknown-linux-gnu +//@ needs-llvm-components: sparc + +// See ./transparent.rs + +#![feature(no_core, lang_items, transparent_unions)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; +impl Copy for BigS {} +impl Copy for BigU {} + +#[repr(C)] +pub struct BigS([u32; 16]); + +#[repr(transparent)] +pub struct TsBigS(BigS); + +#[repr(transparent)] +pub union TuBigS { + field: BigS, +} + +#[repr(transparent)] +pub enum TeBigS { + Variant(BigS), +} + +// CHECK: define{{.*}}void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_BigS(_: BigS) -> BigS { + loop {} +} + +// CHECK: define{{.*}}void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS { + loop {} +} + +// CHECK: define{{.*}}void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { + loop {} +} + +// CHECK: define{{.*}}void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { + loop {} +} + +#[repr(C)] +pub union BigU { + foo: [u32; 16], +} + +#[repr(transparent)] +pub struct TsBigU(BigU); + +#[repr(transparent)] +pub union TuBigU { + field: BigU, +} + +#[repr(transparent)] +pub enum TeBigU { + Variant(BigU), +} + +// CHECK: define{{.*}}void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_BigU(_: BigU) -> BigU { + loop {} +} + +// CHECK: define{{.*}}void @test_TsBigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU { + loop {} +} + +// CHECK: define{{.*}}void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU { + loop {} +} + +// CHECK: define{{.*}}void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU { + loop {} +} diff --git a/tests/codegen-llvm/repr/transparent-sysv64.rs b/tests/codegen-llvm/repr/transparent-sysv64.rs new file mode 100644 index 00000000000..3efc3f7c391 --- /dev/null +++ b/tests/codegen-llvm/repr/transparent-sysv64.rs @@ -0,0 +1,49 @@ +//@ add-core-stubs +//@ revisions: linux apple win +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes + +//@[linux] compile-flags: --target x86_64-unknown-linux-gnu +//@[linux] needs-llvm-components: x86 +//@[apple] compile-flags: --target x86_64-apple-darwin +//@[apple] needs-llvm-components: x86 +//@[win] compile-flags: --target x86_64-pc-windows-msvc +//@[win] needs-llvm-components: x86 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(C)] +pub struct Rgb8 { + r: u8, + g: u8, + b: u8, +} + +#[repr(transparent)] +pub struct Rgb8Wrap(Rgb8); + +// CHECK: i24 @test_Rgb8Wrap(i24{{( %0)?}}) +#[no_mangle] +pub extern "sysv64" fn test_Rgb8Wrap(_: Rgb8Wrap) -> Rgb8Wrap { + loop {} +} + +#[repr(C)] +pub union FloatBits { + float: f32, + bits: u32, +} + +#[repr(transparent)] +pub struct SmallUnion(FloatBits); + +// CHECK: i32 @test_SmallUnion(i32{{( %0)?}}) +#[no_mangle] +pub extern "sysv64" fn test_SmallUnion(_: SmallUnion) -> SmallUnion { + loop {} +} diff --git a/tests/codegen-llvm/repr/transparent.rs b/tests/codegen-llvm/repr/transparent.rs new file mode 100644 index 00000000000..29b627462a4 --- /dev/null +++ b/tests/codegen-llvm/repr/transparent.rs @@ -0,0 +1,221 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes +//@ ignore-riscv64 riscv64 has an i128 type used with test_Vector +//@ ignore-s390x s390x with default march passes vector types per reference +//@ ignore-loongarch64 see codegen/loongarch-abi for loongarch function call tests + +// This codegen test embeds assumptions about how certain "C" psABIs are handled +// so it doesn't apply to all architectures or even all OS +// For RISCV: see codegen/riscv-abi +// For LoongArch: see codegen/loongarch-abi + +#![crate_type = "lib"] +#![feature(repr_simd, transparent_unions, arm_target_feature, mips_target_feature)] + +use std::marker::PhantomData; + +#[derive(Copy, Clone)] +pub struct Zst1; +#[derive(Copy, Clone)] +pub struct Zst2(()); + +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct F32(f32); + +// CHECK: define{{.*}}float @test_F32(float noundef %_1) +#[no_mangle] +pub extern "C" fn test_F32(_: F32) -> F32 { + loop {} +} + +#[repr(transparent)] +pub struct Ptr(*mut u8); + +// CHECK: define{{.*}}ptr @test_Ptr(ptr noundef %_1) +#[no_mangle] +pub extern "C" fn test_Ptr(_: Ptr) -> Ptr { + loop {} +} + +#[repr(transparent)] +pub struct WithZst(u64, Zst1); + +// CHECK: define{{.*}}i64 @test_WithZst(i64 noundef %_1) +#[no_mangle] +pub extern "C" fn test_WithZst(_: WithZst) -> WithZst { + loop {} +} + +#[repr(transparent)] +pub struct WithZeroSizedArray(*const f32, [i8; 0]); + +// CHECK: define{{.*}}ptr @test_WithZeroSizedArray(ptr noundef %_1) +#[no_mangle] +pub extern "C" fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { + loop {} +} + +#[repr(transparent)] +pub struct Generic(T); + +// CHECK: define{{.*}}double @test_Generic(double noundef %_1) +#[no_mangle] +pub extern "C" fn test_Generic(_: Generic) -> Generic { + loop {} +} + +#[repr(transparent)] +pub struct GenericPlusZst(T, Zst2); + +#[repr(u8)] +pub enum Bool { + True, + False, + FileNotFound, +} + +// CHECK: define{{( dso_local)?}} noundef{{( zeroext)?( range\(i8 0, 3\))?}} i8 @test_Gpz(i8 noundef{{( zeroext)?( range\(i8 0, 3\))?}} %_1) +#[no_mangle] +pub extern "C" fn test_Gpz(_: GenericPlusZst) -> GenericPlusZst { + loop {} +} + +#[repr(transparent)] +pub struct LifetimePhantom<'a, T: 'a>(*const T, PhantomData<&'a T>); + +// CHECK: define{{.*}}ptr @test_LifetimePhantom(ptr noundef %_1) +#[no_mangle] +pub extern "C" fn test_LifetimePhantom(_: LifetimePhantom) -> LifetimePhantom { + loop {} +} + +// This works despite current alignment resrictions because PhantomData is always align(1) +#[repr(transparent)] +pub struct UnitPhantom { + val: T, + unit: PhantomData, +} + +pub struct Px; + +// CHECK: define{{.*}}float @test_UnitPhantom(float noundef %_1) +#[no_mangle] +pub extern "C" fn test_UnitPhantom(_: UnitPhantom) -> UnitPhantom { + loop {} +} + +#[repr(transparent)] +pub struct TwoZsts(Zst1, i8, Zst2); + +// CHECK: define{{( dso_local)?}} noundef{{( signext)?}} i8 @test_TwoZsts(i8 noundef{{( signext)?}} %_1) +#[no_mangle] +pub extern "C" fn test_TwoZsts(_: TwoZsts) -> TwoZsts { + loop {} +} + +#[repr(transparent)] +pub struct Nested1(Zst2, Generic); + +// CHECK: define{{.*}}double @test_Nested1(double noundef %_1) +#[no_mangle] +pub extern "C" fn test_Nested1(_: Nested1) -> Nested1 { + loop {} +} + +#[repr(transparent)] +pub struct Nested2(Nested1, Zst1); + +// CHECK: define{{.*}}double @test_Nested2(double noundef %_1) +#[no_mangle] +pub extern "C" fn test_Nested2(_: Nested2) -> Nested2 { + loop {} +} + +#[repr(simd)] +struct f32x4([f32; 4]); + +#[repr(transparent)] +pub struct Vector(f32x4); + +// CHECK: define{{.*}}<4 x float> @test_Vector(<4 x float> %_1) +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +pub extern "C" fn test_Vector(_: Vector) -> Vector { + loop {} +} + +trait Mirror { + type It: ?Sized; +} +impl Mirror for T { + type It = Self; +} + +#[repr(transparent)] +pub struct StructWithProjection(::It); + +// CHECK: define{{.*}}float @test_Projection(float noundef %_1) +#[no_mangle] +pub extern "C" fn test_Projection(_: StructWithProjection) -> StructWithProjection { + loop {} +} + +#[repr(transparent)] +pub enum EnumF32 { + Variant(F32), +} + +// CHECK: define{{.*}}float @test_EnumF32(float noundef %_1) +#[no_mangle] +pub extern "C" fn test_EnumF32(_: EnumF32) -> EnumF32 { + loop {} +} + +#[repr(transparent)] +pub enum EnumF32WithZsts { + Variant(Zst1, F32, Zst2), +} + +// CHECK: define{{.*}}float @test_EnumF32WithZsts(float noundef %_1) +#[no_mangle] +pub extern "C" fn test_EnumF32WithZsts(_: EnumF32WithZsts) -> EnumF32WithZsts { + loop {} +} + +#[repr(transparent)] +pub union UnionF32 { + field: F32, +} + +// CHECK: define{{.*}} float @test_UnionF32(float %_1) +#[no_mangle] +pub extern "C" fn test_UnionF32(_: UnionF32) -> UnionF32 { + loop {} +} + +#[repr(transparent)] +pub union UnionF32WithZsts { + zst1: Zst1, + field: F32, + zst2: Zst2, +} + +// CHECK: define{{.*}}float @test_UnionF32WithZsts(float %_1) +#[no_mangle] +pub extern "C" fn test_UnionF32WithZsts(_: UnionF32WithZsts) -> UnionF32WithZsts { + loop {} +} + +// All that remains to be tested are aggregates. They are tested in separate files called +// transparent-*.rs with `only-*` or `ignore-*` directives, because the expected LLVM IR +// function signatures vary so much that it's not reasonably possible to cover all of them with a +// single CHECK line. +// +// You may be wondering why we don't just compare the return types and argument types for equality +// with FileCheck regex captures. Well, rustc doesn't perform newtype unwrapping on newtypes +// containing aggregates. This is OK on all ABIs we support, but because LLVM has not gotten rid of +// pointee types yet, the IR function signature will be syntactically different (%Foo* vs +// %FooWrapper*). diff --git a/tests/codegen-llvm/retpoline.rs b/tests/codegen-llvm/retpoline.rs new file mode 100644 index 00000000000..915c2c3d797 --- /dev/null +++ b/tests/codegen-llvm/retpoline.rs @@ -0,0 +1,27 @@ +// ignore-tidy-linelength +// Test that the +// `retpoline-external-thunk`, `retpoline-indirect-branches`, `retpoline-indirect-calls` +// target features are (not) emitted when the `retpoline/retpoline-external-thunk` flag is (not) set. + +//@ add-core-stubs +//@ revisions: disabled enabled_retpoline enabled_retpoline_external_thunk +//@ needs-llvm-components: x86 +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ [enabled_retpoline] compile-flags: -Zretpoline +//@ [enabled_retpoline_external_thunk] compile-flags: -Zretpoline-external-thunk +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] +extern crate minicore; + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + + // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk{{.*}} } + // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches{{.*}} } + // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-calls{{.*}} } + + // enabled_retpoline: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} } + // enabled_retpoline_external_thunk: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk,+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} } +} diff --git a/tests/codegen-llvm/riscv-abi/call-llvm-intrinsics.rs b/tests/codegen-llvm/riscv-abi/call-llvm-intrinsics.rs new file mode 100644 index 00000000000..e72a649a530 --- /dev/null +++ b/tests/codegen-llvm/riscv-abi/call-llvm-intrinsics.rs @@ -0,0 +1,30 @@ +//@ compile-flags: -C no-prepopulate-passes + +//@ only-riscv64 + +#![feature(link_llvm_intrinsics)] +#![crate_type = "lib"] + +struct A; + +impl Drop for A { + fn drop(&mut self) { + println!("A"); + } +} + +extern "C" { + #[link_name = "llvm.sqrt.f32"] + fn sqrt(x: f32) -> f32; +} + +pub fn do_call() { + let _a = A; + + unsafe { + // Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them + // CHECK: store float 4.000000e+00, ptr %{{.}}, align 4 + // CHECK: call float @llvm.sqrt.f32(float %{{.}} + sqrt(4.0); + } +} diff --git a/tests/codegen-llvm/riscv-abi/cast-local-large-enough.rs b/tests/codegen-llvm/riscv-abi/cast-local-large-enough.rs new file mode 100644 index 00000000000..9d21d73b459 --- /dev/null +++ b/tests/codegen-llvm/riscv-abi/cast-local-large-enough.rs @@ -0,0 +1,44 @@ +//@ add-core-stubs +//@ compile-flags: -Copt-level=0 -Cdebuginfo=0 --target riscv64gc-unknown-linux-gnu +//@ needs-llvm-components: riscv + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +#[repr(C, align(64))] +struct Aligned(f64); + +#[repr(C, align(64))] +struct AlignedPair(f32, f64); + +impl Copy for Aligned {} +impl Copy for AlignedPair {} + +// CHECK-LABEL: define double @read_aligned +#[unsafe(no_mangle)] +pub extern "C" fn read_aligned(x: &Aligned) -> Aligned { + // CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false) + // CHECK-NEXT: %[[RES:.*]] = load double, ptr %[[TEMP]], align 64 + // CHECK-NEXT: ret double %[[RES]] + *x +} + +// CHECK-LABEL: define { float, double } @read_aligned_pair +#[unsafe(no_mangle)] +pub extern "C" fn read_aligned_pair(x: &AlignedPair) -> AlignedPair { + // CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false) + // CHECK-NEXT: %[[FIRST:.*]] = load float, ptr %[[TEMP]], align 64 + // CHECK-NEXT: %[[SECOND_PTR:.*]] = getelementptr inbounds i8, ptr %[[TEMP]], i64 8 + // CHECK-NEXT: %[[SECOND:.*]] = load double, ptr %[[SECOND_PTR]], align 8 + // CHECK-NEXT: %[[RES1:.*]] = insertvalue { float, double } poison, float %[[FIRST]], 0 + // CHECK-NEXT: %[[RES2:.*]] = insertvalue { float, double } %[[RES1]], double %[[SECOND]], 1 + // CHECK-NEXT: ret { float, double } %[[RES2]] + *x +} diff --git a/tests/codegen-llvm/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs b/tests/codegen-llvm/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs new file mode 100644 index 00000000000..df99f6969fc --- /dev/null +++ b/tests/codegen-llvm/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs @@ -0,0 +1,176 @@ +//@ add-core-stubs +//@ compile-flags: --target riscv64gc-unknown-linux-gnu -Copt-level=3 -C no-prepopulate-passes -C panic=abort +//@ needs-llvm-components: riscv + +#![crate_type = "lib"] +#![no_core] +#![feature(no_core, lang_items)] +#![allow(improper_ctypes)] + +extern crate minicore; +use minicore::*; + +// CHECK: define void @f_void() +#[no_mangle] +pub extern "C" fn f_void() {} + +// CHECK: define noundef zeroext i1 @f_scalar_0(i1 noundef zeroext %a) +#[no_mangle] +pub extern "C" fn f_scalar_0(a: bool) -> bool { + a +} + +// CHECK: define noundef signext i8 @f_scalar_1(i8 noundef signext %x) +#[no_mangle] +pub extern "C" fn f_scalar_1(x: i8) -> i8 { + x +} + +// CHECK: define noundef zeroext i8 @f_scalar_2(i8 noundef zeroext %x) +#[no_mangle] +pub extern "C" fn f_scalar_2(x: u8) -> u8 { + x +} + +// CHECK: define noundef signext i32 @f_scalar_3(i32 noundef signext %x) +#[no_mangle] +pub extern "C" fn f_scalar_3(x: i32) -> u32 { + x as u32 +} + +// CHECK: define noundef i64 @f_scalar_4(i64 noundef %x) +#[no_mangle] +pub extern "C" fn f_scalar_4(x: i64) -> i64 { + x +} + +// CHECK: define float @f_fp_scalar_1(float %0) +#[no_mangle] +pub extern "C" fn f_fp_scalar_1(x: f32) -> f32 { + x +} +// CHECK: define double @f_fp_scalar_2(double %0) +#[no_mangle] +pub extern "C" fn f_fp_scalar_2(x: f64) -> f64 { + x +} + +#[repr(C)] +pub struct Empty {} + +// CHECK: define void @f_agg_empty_struct() +#[no_mangle] +pub extern "C" fn f_agg_empty_struct(e: Empty) -> Empty { + e +} + +#[repr(C)] +pub struct Tiny { + a: u16, + b: u16, + c: u16, + d: u16, +} + +// CHECK: define void @f_agg_tiny(i64 %0) +#[no_mangle] +pub extern "C" fn f_agg_tiny(mut e: Tiny) {} + +// CHECK: define i64 @f_agg_tiny_ret() +#[no_mangle] +pub extern "C" fn f_agg_tiny_ret() -> Tiny { + Tiny { a: 1, b: 2, c: 3, d: 4 } +} + +#[repr(C)] +pub struct Small { + a: i64, + b: *mut i64, +} + +// CHECK: define void @f_agg_small([2 x i64] %0) +#[no_mangle] +pub extern "C" fn f_agg_small(mut x: Small) {} + +// CHECK: define [2 x i64] @f_agg_small_ret() +#[no_mangle] +pub extern "C" fn f_agg_small_ret() -> Small { + Small { a: 1, b: 0 as *mut _ } +} + +#[repr(C)] +pub struct SmallAligned { + a: i128, +} + +// CHECK: define void @f_agg_small_aligned(i128 %0) +#[no_mangle] +pub extern "C" fn f_agg_small_aligned(mut x: SmallAligned) {} + +#[repr(C)] +pub struct Large { + a: i64, + b: i64, + c: i64, + d: i64, +} + +// CHECK: define void @f_agg_large(ptr {{.*}}%x) +#[no_mangle] +pub extern "C" fn f_agg_large(mut x: Large) {} + +// CHECK: define void @f_agg_large_ret(ptr {{.*}}sret{{.*}}, i32 noundef signext %i, i8 noundef signext %j) +#[no_mangle] +pub extern "C" fn f_agg_large_ret(i: i32, j: i8) -> Large { + Large { a: 1, b: 2, c: 3, d: 4 } +} + +// CHECK: define void @f_scalar_stack_1(i64 %0, [2 x i64] %1, i128 %2, ptr {{.*}}%d, i8 noundef zeroext %e, i8 noundef signext %f, i8 noundef %g, i8 noundef %h) +#[no_mangle] +pub extern "C" fn f_scalar_stack_1( + a: Tiny, + b: Small, + c: SmallAligned, + d: Large, + e: u8, + f: i8, + g: u8, + h: i8, +) { +} + +// CHECK: define void @f_scalar_stack_2(ptr {{.*}}sret{{.*}} %_0, i64 noundef %a, i128 %0, i128 %1, i64 noundef %d, i8 noundef zeroext %e, i8 noundef %f, i8 noundef %g) +#[no_mangle] +pub extern "C" fn f_scalar_stack_2( + a: u64, + b: SmallAligned, + c: SmallAligned, + d: u64, + e: u8, + f: i8, + g: u8, +) -> Large { + Large { a: a as i64, b: e as i64, c: f as i64, d: g as i64 } +} + +extern "C" { + fn f_va_callee(_: i32, ...) -> i32; +} + +#[no_mangle] +pub unsafe extern "C" fn f_va_caller() { + // CHECK: call noundef signext i32 (i32, ...) @f_va_callee(i32 noundef signext 1, i32 noundef signext 2, i64 noundef 3, double {{.*}}, double {{.*}}, i64 {{.*}}, [2 x i64] {{.*}}, i128 {{.*}}, ptr {{.*}}) + f_va_callee( + 1, + 2i32, + 3i64, + 4.0f64, + 5.0f64, + Tiny { a: 1, b: 2, c: 3, d: 4 }, + Small { a: 10, b: 0 as *mut _ }, + SmallAligned { a: 11 }, + Large { a: 12, b: 13, c: 14, d: 15 }, + ); + // CHECK: call noundef signext i32 (i32, ...) @f_va_callee(i32 noundef signext 1, i32 noundef signext 2, i32 noundef signext 3, i32 noundef signext 4, i128 {{.*}}, i32 noundef signext 6, i32 noundef signext 7, i32 noundef 8, i32 noundef 9) + f_va_callee(1, 2i32, 3i32, 4i32, SmallAligned { a: 5 }, 6i32, 7i32, 8i32, 9i32); +} diff --git a/tests/codegen-llvm/riscv-abi/riscv64-lp64d-abi.rs b/tests/codegen-llvm/riscv-abi/riscv64-lp64d-abi.rs new file mode 100644 index 00000000000..d768ab9381a --- /dev/null +++ b/tests/codegen-llvm/riscv-abi/riscv64-lp64d-abi.rs @@ -0,0 +1,299 @@ +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes --target riscv64gc-unknown-linux-gnu +//@ needs-llvm-components: riscv + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK: define void @f_fpr_tracking(double %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, i8 noundef zeroext %i) +#[no_mangle] +pub extern "C" fn f_fpr_tracking( + a: f64, + b: f64, + c: f64, + d: f64, + e: f64, + f: f64, + g: f64, + h: f64, + i: u8, +) { +} + +#[repr(C)] +pub struct Double { + f: f64, +} + +#[repr(C)] +pub struct DoubleDouble { + f: f64, + g: f64, +} + +#[repr(C)] +pub struct DoubleFloat { + f: f64, + g: f32, +} + +// CHECK: define void @f_double_s_arg(double %0) +#[no_mangle] +pub extern "C" fn f_double_s_arg(a: Double) {} + +// CHECK: define double @f_ret_double_s() +#[no_mangle] +pub extern "C" fn f_ret_double_s() -> Double { + Double { f: 1. } +} + +// CHECK: define void @f_double_double_s_arg({ double, double } %0) +#[no_mangle] +pub extern "C" fn f_double_double_s_arg(a: DoubleDouble) {} + +// CHECK: define { double, double } @f_ret_double_double_s() +#[no_mangle] +pub extern "C" fn f_ret_double_double_s() -> DoubleDouble { + DoubleDouble { f: 1., g: 2. } +} + +// CHECK: define void @f_double_float_s_arg({ double, float } %0) +#[no_mangle] +pub extern "C" fn f_double_float_s_arg(a: DoubleFloat) {} + +// CHECK: define { double, float } @f_ret_double_float_s() +#[no_mangle] +pub extern "C" fn f_ret_double_float_s() -> DoubleFloat { + DoubleFloat { f: 1., g: 2. } +} + +// CHECK: define void @f_double_double_s_arg_insufficient_fprs(double %0, double %1, double %2, double %3, double %4, double %5, double %6, [2 x i64] %7) +#[no_mangle] +pub extern "C" fn f_double_double_s_arg_insufficient_fprs( + a: f64, + b: f64, + c: f64, + d: f64, + e: f64, + f: f64, + g: f64, + h: DoubleDouble, +) { +} + +#[repr(C)] +pub struct DoubleInt8 { + f: f64, + i: i8, +} + +#[repr(C)] +pub struct DoubleUInt8 { + f: f64, + i: u8, +} + +#[repr(C)] +pub struct DoubleInt32 { + f: f64, + i: i32, +} + +#[repr(C)] +pub struct DoubleInt64 { + f: f64, + i: i64, +} + +// CHECK: define void @f_double_int8_s_arg({ double, i8 } %0) +#[no_mangle] +pub extern "C" fn f_double_int8_s_arg(a: DoubleInt8) {} + +// CHECK: define { double, i8 } @f_ret_double_int8_s() +#[no_mangle] +pub extern "C" fn f_ret_double_int8_s() -> DoubleInt8 { + DoubleInt8 { f: 1., i: 2 } +} + +// CHECK: define void @f_double_int32_s_arg({ double, i32 } %0) +#[no_mangle] +pub extern "C" fn f_double_int32_s_arg(a: DoubleInt32) {} + +// CHECK: define { double, i32 } @f_ret_double_int32_s() +#[no_mangle] +pub extern "C" fn f_ret_double_int32_s() -> DoubleInt32 { + DoubleInt32 { f: 1., i: 2 } +} + +// CHECK: define void @f_double_uint8_s_arg({ double, i8 } %0) +#[no_mangle] +pub extern "C" fn f_double_uint8_s_arg(a: DoubleUInt8) {} + +// CHECK: define { double, i8 } @f_ret_double_uint8_s() +#[no_mangle] +pub extern "C" fn f_ret_double_uint8_s() -> DoubleUInt8 { + DoubleUInt8 { f: 1., i: 2 } +} + +// CHECK: define void @f_double_int64_s_arg({ double, i64 } %0) +#[no_mangle] +pub extern "C" fn f_double_int64_s_arg(a: DoubleInt64) {} + +// CHECK: define { double, i64 } @f_ret_double_int64_s() +#[no_mangle] +pub extern "C" fn f_ret_double_int64_s() -> DoubleInt64 { + DoubleInt64 { f: 1., i: 2 } +} + +// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 noundef signext %a, i32 noundef signext %b, i32 noundef signext %c, i32 noundef signext %d, i32 noundef signext %e, i32 noundef signext %f, i32 noundef signext %g, i32 noundef signext %h, [2 x i64] %0) +#[no_mangle] +pub extern "C" fn f_double_int8_s_arg_insufficient_gprs( + a: i32, + b: i32, + c: i32, + d: i32, + e: i32, + f: i32, + g: i32, + h: i32, + i: DoubleInt8, +) { +} + +// CHECK: define void @f_struct_double_int8_insufficient_fprs(float %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, [2 x i64] %8) +#[no_mangle] +pub extern "C" fn f_struct_double_int8_insufficient_fprs( + a: f32, + b: f64, + c: f64, + d: f64, + e: f64, + f: f64, + g: f64, + h: f64, + i: DoubleInt8, +) { +} + +#[repr(C)] +pub struct DoubleArr1 { + a: [f64; 1], +} + +// CHECK: define void @f_doublearr1_s_arg(double %0) +#[no_mangle] +pub extern "C" fn f_doublearr1_s_arg(a: DoubleArr1) {} + +// CHECK: define double @f_ret_doublearr1_s() +#[no_mangle] +pub extern "C" fn f_ret_doublearr1_s() -> DoubleArr1 { + DoubleArr1 { a: [1.] } +} + +#[repr(C)] +pub struct DoubleArr2 { + a: [f64; 2], +} + +// CHECK: define void @f_doublearr2_s_arg({ double, double } %0) +#[no_mangle] +pub extern "C" fn f_doublearr2_s_arg(a: DoubleArr2) {} + +// CHECK: define { double, double } @f_ret_doublearr2_s() +#[no_mangle] +pub extern "C" fn f_ret_doublearr2_s() -> DoubleArr2 { + DoubleArr2 { a: [1., 2.] } +} + +#[repr(C)] +pub struct Tricky1 { + f: [f64; 1], +} + +#[repr(C)] +pub struct DoubleArr2Tricky1 { + g: [Tricky1; 2], +} + +// CHECK: define void @f_doublearr2_tricky1_s_arg({ double, double } %0) +#[no_mangle] +pub extern "C" fn f_doublearr2_tricky1_s_arg(a: DoubleArr2Tricky1) {} + +// CHECK: define { double, double } @f_ret_doublearr2_tricky1_s() +#[no_mangle] +pub extern "C" fn f_ret_doublearr2_tricky1_s() -> DoubleArr2Tricky1 { + DoubleArr2Tricky1 { g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } +} + +#[repr(C)] +pub struct EmptyStruct {} + +#[repr(C)] +pub struct DoubleArr2Tricky2 { + s: EmptyStruct, + g: [Tricky1; 2], +} + +// CHECK: define void @f_doublearr2_tricky2_s_arg({ double, double } %0) +#[no_mangle] +pub extern "C" fn f_doublearr2_tricky2_s_arg(a: DoubleArr2Tricky2) {} + +// CHECK: define { double, double } @f_ret_doublearr2_tricky2_s() +#[no_mangle] +pub extern "C" fn f_ret_doublearr2_tricky2_s() -> DoubleArr2Tricky2 { + DoubleArr2Tricky2 { s: EmptyStruct {}, g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } +} + +#[repr(C)] +pub struct IntDoubleInt { + a: i32, + b: f64, + c: i32, +} + +// CHECK: define void @f_int_double_int_s_arg(ptr {{.*}} %a) +#[no_mangle] +pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {} + +// CHECK: define void @f_ret_int_double_int_s(ptr {{.*}} sret([24 x i8]) align 8 {{.*}}dereferenceable(24) %_0) +#[no_mangle] +pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt { + IntDoubleInt { a: 1, b: 2., c: 3 } +} + +#[repr(C)] +pub struct CharCharDouble { + a: u8, + b: u8, + c: f64, +} + +// CHECK: define void @f_char_char_double_s_arg([2 x i64] %0) +#[no_mangle] +pub extern "C" fn f_char_char_double_s_arg(a: CharCharDouble) {} + +// CHECK: define [2 x i64] @f_ret_char_char_double_s() +#[no_mangle] +pub extern "C" fn f_ret_char_char_double_s() -> CharCharDouble { + CharCharDouble { a: 1, b: 2, c: 3. } +} + +#[repr(C)] +pub union DoubleU { + a: f64, +} + +// CHECK: define void @f_double_u_arg(i64 %0) +#[no_mangle] +pub extern "C" fn f_double_u_arg(a: DoubleU) {} + +// CHECK: define i64 @f_ret_double_u() +#[no_mangle] +pub extern "C" fn f_ret_double_u() -> DoubleU { + unsafe { DoubleU { a: 1. } } +} diff --git a/tests/codegen-llvm/riscv-abi/riscv64-lp64f-lp64d-abi.rs b/tests/codegen-llvm/riscv-abi/riscv64-lp64f-lp64d-abi.rs new file mode 100644 index 00000000000..361f0322690 --- /dev/null +++ b/tests/codegen-llvm/riscv-abi/riscv64-lp64f-lp64d-abi.rs @@ -0,0 +1,283 @@ +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes --target riscv64gc-unknown-linux-gnu +//@ needs-llvm-components: riscv + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK: define void @f_fpr_tracking(float %0, float %1, float %2, float %3, float %4, float %5, float %6, float %7, i8 noundef zeroext %i) +#[no_mangle] +pub extern "C" fn f_fpr_tracking( + a: f32, + b: f32, + c: f32, + d: f32, + e: f32, + f: f32, + g: f32, + h: f32, + i: u8, +) { +} + +#[repr(C)] +pub struct Float { + f: f32, +} + +#[repr(C)] +pub struct FloatFloat { + f: f32, + g: f32, +} + +// CHECK: define void @f_float_s_arg(float %0) +#[no_mangle] +pub extern "C" fn f_float_s_arg(a: Float) {} + +// CHECK: define float @f_ret_float_s() +#[no_mangle] +pub extern "C" fn f_ret_float_s() -> Float { + Float { f: 1. } +} + +// CHECK: define void @f_float_float_s_arg({ float, float } %0) +#[no_mangle] +pub extern "C" fn f_float_float_s_arg(a: FloatFloat) {} + +// CHECK: define { float, float } @f_ret_float_float_s() +#[no_mangle] +pub extern "C" fn f_ret_float_float_s() -> FloatFloat { + FloatFloat { f: 1., g: 2. } +} + +// CHECK: define void @f_float_float_s_arg_insufficient_fprs(float %0, float %1, float %2, float %3, float %4, float %5, float %6, i64 %7) +#[no_mangle] +pub extern "C" fn f_float_float_s_arg_insufficient_fprs( + a: f32, + b: f32, + c: f32, + d: f32, + e: f32, + f: f32, + g: f32, + h: FloatFloat, +) { +} + +#[repr(C)] +pub struct FloatInt8 { + f: f32, + i: i8, +} + +#[repr(C)] +pub struct FloatUInt8 { + f: f32, + i: u8, +} + +#[repr(C)] +pub struct FloatInt32 { + f: f32, + i: i32, +} + +#[repr(C)] +pub struct FloatInt64 { + f: f32, + i: i64, +} + +// CHECK: define void @f_float_int8_s_arg({ float, i8 } %0) +#[no_mangle] +pub extern "C" fn f_float_int8_s_arg(a: FloatInt8) {} + +// CHECK: define { float, i8 } @f_ret_float_int8_s() +#[no_mangle] +pub extern "C" fn f_ret_float_int8_s() -> FloatInt8 { + FloatInt8 { f: 1., i: 2 } +} + +// CHECK: define void @f_float_int32_s_arg({ float, i32 } %0) +#[no_mangle] +pub extern "C" fn f_float_int32_s_arg(a: FloatInt32) {} + +// CHECK: define { float, i32 } @f_ret_float_int32_s() +#[no_mangle] +pub extern "C" fn f_ret_float_int32_s() -> FloatInt32 { + FloatInt32 { f: 1., i: 2 } +} + +// CHECK: define void @f_float_uint8_s_arg({ float, i8 } %0) +#[no_mangle] +pub extern "C" fn f_float_uint8_s_arg(a: FloatUInt8) {} + +// CHECK: define { float, i8 } @f_ret_float_uint8_s() +#[no_mangle] +pub extern "C" fn f_ret_float_uint8_s() -> FloatUInt8 { + FloatUInt8 { f: 1., i: 2 } +} + +// CHECK: define void @f_float_int64_s_arg({ float, i64 } %0) +#[no_mangle] +pub extern "C" fn f_float_int64_s_arg(a: FloatInt64) {} + +// CHECK: define { float, i64 } @f_ret_float_int64_s() +#[no_mangle] +pub extern "C" fn f_ret_float_int64_s() -> FloatInt64 { + FloatInt64 { f: 1., i: 2 } +} + +// CHECK: define void @f_float_int8_s_arg_insufficient_gprs(i32 noundef signext %a, i32 noundef signext %b, i32 noundef signext %c, i32 noundef signext %d, i32 noundef signext %e, i32 noundef signext %f, i32 noundef signext %g, i32 noundef signext %h, i64 %0) +#[no_mangle] +pub extern "C" fn f_float_int8_s_arg_insufficient_gprs( + a: i32, + b: i32, + c: i32, + d: i32, + e: i32, + f: i32, + g: i32, + h: i32, + i: FloatInt8, +) { +} + +// CHECK: define void @f_struct_float_int8_insufficient_fprs(float %0, float %1, float %2, float %3, float %4, float %5, float %6, float %7, i64 %8) +#[no_mangle] +pub extern "C" fn f_struct_float_int8_insufficient_fprs( + a: f32, + b: f32, + c: f32, + d: f32, + e: f32, + f: f32, + g: f32, + h: f32, + i: FloatInt8, +) { +} + +#[repr(C)] +pub struct FloatArr1 { + a: [f32; 1], +} + +// CHECK: define void @f_floatarr1_s_arg(float %0) +#[no_mangle] +pub extern "C" fn f_floatarr1_s_arg(a: FloatArr1) {} + +// CHECK: define float @f_ret_floatarr1_s() +#[no_mangle] +pub extern "C" fn f_ret_floatarr1_s() -> FloatArr1 { + FloatArr1 { a: [1.] } +} + +#[repr(C)] +pub struct FloatArr2 { + a: [f32; 2], +} + +// CHECK: define void @f_floatarr2_s_arg({ float, float } %0) +#[no_mangle] +pub extern "C" fn f_floatarr2_s_arg(a: FloatArr2) {} + +// CHECK: define { float, float } @f_ret_floatarr2_s() +#[no_mangle] +pub extern "C" fn f_ret_floatarr2_s() -> FloatArr2 { + FloatArr2 { a: [1., 2.] } +} + +#[repr(C)] +pub struct Tricky1 { + f: [f32; 1], +} + +#[repr(C)] +pub struct FloatArr2Tricky1 { + g: [Tricky1; 2], +} + +// CHECK: define void @f_floatarr2_tricky1_s_arg({ float, float } %0) +#[no_mangle] +pub extern "C" fn f_floatarr2_tricky1_s_arg(a: FloatArr2Tricky1) {} + +// CHECK: define { float, float } @f_ret_floatarr2_tricky1_s() +#[no_mangle] +pub extern "C" fn f_ret_floatarr2_tricky1_s() -> FloatArr2Tricky1 { + FloatArr2Tricky1 { g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } +} + +#[repr(C)] +pub struct EmptyStruct {} + +#[repr(C)] +pub struct FloatArr2Tricky2 { + s: EmptyStruct, + g: [Tricky1; 2], +} + +// CHECK: define void @f_floatarr2_tricky2_s_arg({ float, float } %0) +#[no_mangle] +pub extern "C" fn f_floatarr2_tricky2_s_arg(a: FloatArr2Tricky2) {} + +// CHECK: define { float, float } @f_ret_floatarr2_tricky2_s() +#[no_mangle] +pub extern "C" fn f_ret_floatarr2_tricky2_s() -> FloatArr2Tricky2 { + FloatArr2Tricky2 { s: EmptyStruct {}, g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } +} + +#[repr(C)] +pub struct IntFloatInt { + a: i32, + b: f32, + c: i32, +} + +// CHECK: define void @f_int_float_int_s_arg([2 x i64] %0) +#[no_mangle] +pub extern "C" fn f_int_float_int_s_arg(a: IntFloatInt) {} + +// CHECK: define [2 x i64] @f_ret_int_float_int_s() +#[no_mangle] +pub extern "C" fn f_ret_int_float_int_s() -> IntFloatInt { + IntFloatInt { a: 1, b: 2., c: 3 } +} + +#[repr(C)] +pub struct CharCharFloat { + a: u8, + b: u8, + c: f32, +} + +// CHECK: define void @f_char_char_float_s_arg(i64 %0) +#[no_mangle] +pub extern "C" fn f_char_char_float_s_arg(a: CharCharFloat) {} + +// CHECK: define i64 @f_ret_char_char_float_s() +#[no_mangle] +pub extern "C" fn f_ret_char_char_float_s() -> CharCharFloat { + CharCharFloat { a: 1, b: 2, c: 3. } +} + +#[repr(C)] +pub union FloatU { + a: f32, +} + +// CHECK: define void @f_float_u_arg(i64 %0) +#[no_mangle] +pub extern "C" fn f_float_u_arg(a: FloatU) {} + +// CHECK: define i64 @f_ret_float_u() +#[no_mangle] +pub extern "C" fn f_ret_float_u() -> FloatU { + unsafe { FloatU { a: 1. } } +} diff --git a/tests/codegen-llvm/riscv-target-abi.rs b/tests/codegen-llvm/riscv-target-abi.rs new file mode 100644 index 00000000000..d41fcb4dd84 --- /dev/null +++ b/tests/codegen-llvm/riscv-target-abi.rs @@ -0,0 +1,21 @@ +//@ add-core-stubs +//@ revisions:riscv64gc riscv32gc riscv32imac + +//@[riscv64gc] compile-flags: --target=riscv64gc-unknown-linux-gnu +//@[riscv64gc] needs-llvm-components: riscv +// riscv64gc: !{i32 1, !"target-abi", !"lp64d"} + +//@[riscv32gc] compile-flags: --target=riscv32gc-unknown-linux-musl +//@[riscv32gc] needs-llvm-components: riscv +// riscv32gc: !{i32 1, !"target-abi", !"ilp32d"} + +//@[riscv32imac] compile-flags: --target=riscv32imac-unknown-none-elf +//@[riscv32imac] needs-llvm-components: riscv +// riscv32imac: !{i32 1, !"target-abi", !"ilp32"} + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; diff --git a/tests/codegen-llvm/rust-abi-arch-specific-adjustment.rs b/tests/codegen-llvm/rust-abi-arch-specific-adjustment.rs new file mode 100644 index 00000000000..561f081c700 --- /dev/null +++ b/tests/codegen-llvm/rust-abi-arch-specific-adjustment.rs @@ -0,0 +1,111 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes +//@ revisions: riscv64 loongarch64 + +//@[riscv64] only-riscv64 +//@[riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu +//@[riscv64] needs-llvm-components: riscv + +//@[loongarch64] only-loongarch64 +//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@[loongarch64] needs-llvm-components: loongarch + +#![crate_type = "lib"] + +#[no_mangle] +// riscv64: define noundef i8 @arg_attr_u8(i8 noundef zeroext %x) +// loongarch64: define noundef i8 @arg_attr_u8(i8 noundef zeroext %x) +pub fn arg_attr_u8(x: u8) -> u8 { + x +} + +#[no_mangle] +// riscv64: define noundef i16 @arg_attr_u16(i16 noundef zeroext %x) +// loongarch64: define noundef i16 @arg_attr_u16(i16 noundef zeroext %x) +pub fn arg_attr_u16(x: u16) -> u16 { + x +} + +#[no_mangle] +// riscv64: define noundef i32 @arg_attr_u32(i32 noundef signext %x) +// loongarch64: define noundef i32 @arg_attr_u32(i32 noundef signext %x) +pub fn arg_attr_u32(x: u32) -> u32 { + x +} + +#[no_mangle] +// riscv64: define noundef i64 @arg_attr_u64(i64 noundef %x) +// loongarch64: define noundef i64 @arg_attr_u64(i64 noundef %x) +pub fn arg_attr_u64(x: u64) -> u64 { + x +} + +#[no_mangle] +// riscv64: define noundef i128 @arg_attr_u128(i128 noundef %x) +// loongarch64: define noundef i128 @arg_attr_u128(i128 noundef %x) +pub fn arg_attr_u128(x: u128) -> u128 { + x +} + +#[no_mangle] +// riscv64: define noundef i8 @arg_attr_i8(i8 noundef signext %x) +// loongarch64: define noundef i8 @arg_attr_i8(i8 noundef signext %x) +pub fn arg_attr_i8(x: i8) -> i8 { + x +} + +#[no_mangle] +// riscv64: define noundef i16 @arg_attr_i16(i16 noundef signext %x) +// loongarch64: define noundef i16 @arg_attr_i16(i16 noundef signext %x) +pub fn arg_attr_i16(x: i16) -> i16 { + x +} + +#[no_mangle] +// riscv64: define noundef i32 @arg_attr_i32(i32 noundef signext %x) +// loongarch64: define noundef i32 @arg_attr_i32(i32 noundef signext %x) +pub fn arg_attr_i32(x: i32) -> i32 { + x +} + +#[no_mangle] +// riscv64: define noundef i64 @arg_attr_i64(i64 noundef %x) +// loongarch64: define noundef i64 @arg_attr_i64(i64 noundef %x) +pub fn arg_attr_i64(x: i64) -> i64 { + x +} + +#[no_mangle] +// riscv64: define noundef i128 @arg_attr_i128(i128 noundef %x) +// loongarch64: define noundef i128 @arg_attr_i128(i128 noundef %x) +pub fn arg_attr_i128(x: i128) -> i128 { + x +} + +#[no_mangle] +// riscv64: define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x) +// loongarch64: define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x) +pub fn arg_attr_bool(x: bool) -> bool { + x +} + +#[no_mangle] +// ignore-tidy-linelength +// riscv64: define noundef{{( range\(i32 0, 1114112\))?}} i32 @arg_attr_char(i32 noundef signext{{( range\(i32 0, 1114112\))?}} %x) +// loongarch64: define noundef{{( range\(i32 0, 1114112\))?}} i32 @arg_attr_char(i32 noundef signext{{( range\(i32 0, 1114112\))?}} %x) +pub fn arg_attr_char(x: char) -> char { + x +} + +#[no_mangle] +// riscv64: define noundef float @arg_attr_f32(float noundef %x) +// loongarch64: define noundef float @arg_attr_f32(float noundef %x) +pub fn arg_attr_f32(x: f32) -> f32 { + x +} + +#[no_mangle] +// riscv64: define noundef double @arg_attr_f64(double noundef %x) +// loongarch64: define noundef double @arg_attr_f64(double noundef %x) +pub fn arg_attr_f64(x: f64) -> f64 { + x +} diff --git a/tests/codegen-llvm/s390x-simd.rs b/tests/codegen-llvm/s390x-simd.rs new file mode 100644 index 00000000000..ac39357519e --- /dev/null +++ b/tests/codegen-llvm/s390x-simd.rs @@ -0,0 +1,143 @@ +//! test that s390x vector types are passed using `PassMode::Direct` +//! see also https://github.com/rust-lang/rust/issues/135744 +//@ add-core-stubs +//@ compile-flags: --target s390x-unknown-linux-gnu -Copt-level=3 +//@ needs-llvm-components: systemz + +#![crate_type = "rlib"] +#![feature(no_core, asm_experimental_arch)] +#![feature(s390x_target_feature, simd_ffi, link_llvm_intrinsics, repr_simd)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(simd)] +struct i8x16([i8; 16]); + +#[repr(simd)] +struct i16x8([i16; 8]); + +#[repr(simd)] +struct i32x4([i32; 4]); + +#[repr(simd)] +struct i64x2([i64; 2]); + +#[repr(simd)] +struct f32x4([f32; 4]); + +#[repr(simd)] +struct f64x2([f64; 2]); + +#[allow(improper_ctypes)] +extern "C" { + #[link_name = "llvm.smax.v16i8"] + fn vmxb(a: i8x16, b: i8x16) -> i8x16; + #[link_name = "llvm.smax.v8i16"] + fn vmxh(a: i16x8, b: i16x8) -> i16x8; + #[link_name = "llvm.smax.v4i32"] + fn vmxf(a: i32x4, b: i32x4) -> i32x4; + #[link_name = "llvm.smax.v2i64"] + fn vmxg(a: i64x2, b: i64x2) -> i64x2; +} + +// CHECK-LABEL: define <16 x i8> @max_i8x16 +// CHECK-SAME: <16 x i8> %a, <16 x i8> %b +// CHECK: call <16 x i8> @llvm.smax.v16i8(<16 x i8> %a, <16 x i8> %b) +#[no_mangle] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn max_i8x16(a: i8x16, b: i8x16) -> i8x16 { + vmxb(a, b) +} + +// CHECK-LABEL: define <8 x i16> @max_i16x8 +// CHECK-SAME: <8 x i16> %a, <8 x i16> %b +// CHECK: call <8 x i16> @llvm.smax.v8i16(<8 x i16> %a, <8 x i16> %b) +#[no_mangle] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn max_i16x8(a: i16x8, b: i16x8) -> i16x8 { + vmxh(a, b) +} + +// CHECK-LABEL: define <4 x i32> @max_i32x4 +// CHECK-SAME: <4 x i32> %a, <4 x i32> %b +// CHECK: call <4 x i32> @llvm.smax.v4i32(<4 x i32> %a, <4 x i32> %b) +#[no_mangle] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn max_i32x4(a: i32x4, b: i32x4) -> i32x4 { + vmxf(a, b) +} + +// CHECK-LABEL: define <2 x i64> @max_i64x2 +// CHECK-SAME: <2 x i64> %a, <2 x i64> %b +// CHECK: call <2 x i64> @llvm.smax.v2i64(<2 x i64> %a, <2 x i64> %b) +#[no_mangle] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn max_i64x2(a: i64x2, b: i64x2) -> i64x2 { + vmxg(a, b) +} + +// CHECK-LABEL: define <4 x float> @choose_f32x4 +// CHECK-SAME: <4 x float> %a, <4 x float> %b +#[no_mangle] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn choose_f32x4(a: f32x4, b: f32x4, c: bool) -> f32x4 { + if c { a } else { b } +} + +// CHECK-LABEL: define <2 x double> @choose_f64x2 +// CHECK-SAME: <2 x double> %a, <2 x double> %b +#[no_mangle] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn choose_f64x2(a: f64x2, b: f64x2, c: bool) -> f64x2 { + if c { a } else { b } +} + +#[repr(C)] +struct Wrapper(T); + +#[no_mangle] +#[inline(never)] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn max_wrapper_i8x16(a: Wrapper, b: Wrapper) -> Wrapper { + // CHECK-LABEL: max_wrapper_i8x16 + // CHECK-SAME: sret([16 x i8]) + // CHECK-SAME: <16 x i8> + // CHECK-SAME: <16 x i8> + // CHECK: call <16 x i8> @llvm.smax.v16i8 + // CHECK-SAME: <16 x i8> + // CHECK-SAME: <16 x i8> + Wrapper(vmxb(a.0, b.0)) +} + +#[no_mangle] +#[inline(never)] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn max_wrapper_i64x2(a: Wrapper, b: Wrapper) -> Wrapper { + // CHECK-LABEL: max_wrapper_i64x2 + // CHECK-SAME: sret([16 x i8]) + // CHECK-SAME: <16 x i8> + // CHECK-SAME: <16 x i8> + // CHECK: call <2 x i64> @llvm.smax.v2i64 + // CHECK-SAME: <2 x i64> + // CHECK-SAME: <2 x i64> + Wrapper(vmxg(a.0, b.0)) +} + +#[no_mangle] +#[inline(never)] +#[target_feature(enable = "vector")] +pub unsafe extern "C" fn choose_wrapper_f64x2( + a: Wrapper, + b: Wrapper, + c: bool, +) -> Wrapper { + // CHECK-LABEL: choose_wrapper_f64x2 + // CHECK-SAME: sret([16 x i8]) + // CHECK-SAME: <16 x i8> + // CHECK-SAME: <16 x i8> + Wrapper(choose_f64x2(a.0, b.0, c)) +} + +// CHECK: declare <2 x i64> @llvm.smax.v2i64(<2 x i64>, <2 x i64>) diff --git a/tests/codegen-llvm/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs b/tests/codegen-llvm/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs new file mode 100644 index 00000000000..e1d7dc2d631 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs @@ -0,0 +1,20 @@ +//@ add-core-stubs +//@ revisions: aarch64 android +//@[aarch64] compile-flags: --target aarch64-unknown-none -Zfixed-x18 -Zsanitizer=shadow-call-stack +//@[aarch64] needs-llvm-components: aarch64 +//@[android] compile-flags: --target aarch64-linux-android -Zsanitizer=shadow-call-stack +//@[android] needs-llvm-components: aarch64 + +#![allow(internal_features)] +#![crate_type = "rlib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK: ; Function Attrs:{{.*}}shadowcallstack +#[no_mangle] +pub fn foo() {} + +// CHECK: attributes #0 = {{.*}}shadowcallstack{{.*}} diff --git a/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs b/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs new file mode 100644 index 00000000000..f319306f93f --- /dev/null +++ b/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs @@ -0,0 +1,44 @@ +// Verifies that AddressSanitizer symbols show up as expected in LLVM IR with `-Zsanitizer`. +// This is a regression test for https://github.com/rust-lang/rust/issues/113404 +// +// Notes about the `compile-flags` below: +// +// * The original issue only reproed with LTO - this is why this angle has +// extra test coverage via different `revisions` +// * To observe the failure/repro at LLVM-IR level we need to use `staticlib` +// which necessitates `-C prefer-dynamic=false` - without the latter flag, +// we would have run into "cannot prefer dynamic linking when performing LTO". +// +// The test is restricted to `only-linux`, because the sanitizer-related instrumentation is target +// specific. In particular, `___asan_globals_registered` is only used in the +// `InstrumentGlobalsELF` and `InstrumentGlobalsMachO` code paths. The `only-linux` filter is +// narrower than really needed (i.e. narrower than ELF-or-MachO), but this seems ok - having a +// linux-only regression test should be sufficient here. +// +//@ needs-sanitizer-address +//@ only-linux +// +//@ revisions:ASAN ASAN-FAT-LTO +//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static +//@[ASAN] compile-flags: +//@[ASAN-FAT-LTO] compile-flags: -Cprefer-dynamic=false -Clto=fat + +#![crate_type = "staticlib"] + +// The test below mimics `CACHED_POW10` from `library/core/src/num/flt2dec/strategy/grisu.rs` which +// (because of incorrect handling of `___asan_globals_registered` during LTO) was incorrectly +// reported as an ODR violation in https://crbug.com/1459233#c1. Before this bug was fixed, +// `___asan_globals_registered` would show up as `internal global i64` rather than `common hidden +// global i64`. (The test expectations ignore the exact type because on `arm-android` the type +// is `i32` rather than `i64`.) +// +// CHECK: @___asan_globals_registered = common hidden global +// CHECK: @__start_asan_globals = extern_weak hidden global +// CHECK: @__stop_asan_globals = extern_weak hidden global +#[no_mangle] +pub static CACHED_POW10: [(u64, i16, i16); 4] = [ + (0xe61acf033d1a45df, -1087, -308), + (0xab70fe17c79ac6ca, -1060, -300), + (0xff77b1fcbebcdc4f, -1034, -292), + (0xbe5691ef416bd60c, -1007, -284), +]; diff --git a/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs b/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs new file mode 100644 index 00000000000..22577e2a3c4 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs @@ -0,0 +1,10 @@ +// Verifies that "CFI Canonical Jump Tables" module flag is added. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi + +#![crate_type = "lib"] + +pub fn foo() {} + +// CHECK: !{{[0-9]+}} = !{i32 4, !"CFI Canonical Jump Tables", i32 1} diff --git a/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs b/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs new file mode 100644 index 00000000000..a54a6d84a80 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs @@ -0,0 +1,10 @@ +// Verifies that "cfi-normalize-integers" module flag is added. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers + +#![crate_type = "lib"] + +pub fn foo() {} + +// CHECK: !{{[0-9]+}} = !{i32 4, !"cfi-normalize-integers", i32 1} diff --git a/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs b/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs new file mode 100644 index 00000000000..283b8f26102 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs @@ -0,0 +1,10 @@ +// Verifies that "EnableSplitLTOUnit" module flag is added. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi + +#![crate_type = "lib"] + +pub fn foo() {} + +// CHECK: !{{[0-9]+}} = !{i32 4, !"EnableSplitLTOUnit", i32 1} diff --git a/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs b/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs new file mode 100644 index 00000000000..df65960dfe0 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs @@ -0,0 +1,19 @@ +// Verifies that the parent block's debug information are assigned to the inserted cfi block. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -Cdebuginfo=1 + +#![crate_type = "lib"] + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo{{.*}}!dbg !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: start: + // CHECK: [[TT:%.+]] = call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"{{[[:print:]]+}}"), !dbg !{{[0-9]+}} + // CHECK-NEXT: br i1 [[TT]], label %type_test.pass, label %type_test.fail, !dbg !{{[0-9]+}} + // CHECK: type_test.pass: ; preds = %start + // CHECK-NEXT: {{%.+}} = call i32 %f(i32{{.*}} %arg), !dbg !{{[0-9]+}} + // CHECK: type_test.fail: ; preds = %start + // CHECK-NEXT: call void @llvm.trap(), !dbg !{{[0-9]+}} + // CHECK-NEXT: unreachable, !dbg !{{[0-9]+}} + f(arg) +} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs new file mode 100644 index 00000000000..71ccdc8ca62 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs @@ -0,0 +1,18 @@ +// Verifies that pointer type membership tests for indirect calls are omitted. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 + +#![crate_type = "lib"] +#![feature(no_sanitize)] + +#[no_sanitize(cfi)] +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: emit_type_checks_attr_no_sanitize::foo + // CHECK: Function Attrs: {{.*}} + // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: start: + // CHECK-NEXT: {{%.+}} = call i32 %f(i32{{.*}} %arg) + // CHECK-NEXT: ret i32 {{%.+}} + f(arg) +} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs new file mode 100644 index 00000000000..ebc66a015df --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs @@ -0,0 +1,19 @@ +// Verifies that pointer type membership tests for indirect calls are emitted. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 + +#![crate_type = "lib"] + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: start: + // CHECK: [[TT:%.+]] = call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"{{[[:print:]]+}}") + // CHECK-NEXT: br i1 [[TT]], label %type_test.pass, label %type_test.fail + // CHECK: type_test.pass: + // CHECK-NEXT: {{%.+}} = call i32 %f(i32{{.*}} %arg) + // CHECK: type_test.fail: + // CHECK-NEXT: call void @llvm.trap() + // CHECK-NEXT: unreachable + f(arg) +} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs new file mode 100644 index 00000000000..9bc2e42db0f --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs @@ -0,0 +1,73 @@ +// Verifies that user-defined CFI encoding for types are emitted. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 + +#![crate_type = "lib"] +#![feature(cfi_encoding, extern_types)] + +#[cfi_encoding = "3Foo"] +pub struct Type1(i32); + +extern "C" { + #[cfi_encoding = "3Bar"] + type Type2; +} + +#[cfi_encoding = "3Baz"] +#[repr(transparent)] +pub struct Type3(i32); + +#[cfi_encoding = "i"] +pub struct Type4(i32); + +#[cfi_encoding = "j"] +#[repr(transparent)] +pub struct Type5(u32); + +pub fn foo0(_: Type1) {} +// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo1(_: Type1, _: Type1) {} +// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo2(_: Type1, _: Type1, _: Type1) {} +// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo3(_: *mut Type2) {} +// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo4(_: *mut Type2, _: *mut Type2) {} +// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo5(_: *mut Type2, _: *mut Type2, _: *mut Type2) {} +// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo6(_: *mut Type3) {} +// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo7(_: *mut Type3, _: *mut Type3) {} +// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo8(_: *mut Type3, _: *mut Type3, _: *mut Type3) {} +// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo9(_: Type4) {} +// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo10(_: Type4, _: Type4) {} +// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo11(_: Type4, _: Type4, _: Type4) {} +// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo12(_: Type5) {} +// CHECK: define{{.*}}foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo13(_: Type5, _: Type5) {} +// CHECK: define{{.*}}foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo14(_: Type5, _: Type5, _: Type5) {} +// CHECK: define{{.*}}foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + +// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFv3FooE"} +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFv3FooS_E"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFv3FooS_S_E"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvP3BarE"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvP3BarS0_E"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvP3BarS0_S0_E"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvP3BazE"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvP3BazS0_E"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvP3BazS0_S0_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFviE"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFviiE"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFviiiE"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvjE"} +// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvjjE"} +// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvjjjE"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs new file mode 100644 index 00000000000..9048c6a1f18 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs @@ -0,0 +1,32 @@ +// Verifies that type metadata identifiers for functions are emitted correctly +// for const generics. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 + +#![crate_type = "lib"] +#![feature(type_alias_impl_trait)] + +extern crate core; + +pub type Type1 = impl Send; + +#[define_opaque(Type1)] +pub fn foo() +where + Type1: 'static, +{ + pub struct Foo([T; N]); + let _: Type1 = Foo([0; 32]); +} + +pub fn foo1(_: Type1) {} +// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo2(_: Type1, _: Type1) {} +// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo3(_: Type1, _: Type1, _: Type1) {} +// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooIu3i32Lu5usize32EEE"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooIu3i32Lu5usize32EES2_E"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooIu3i32Lu5usize32EES2_S2_E"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs new file mode 100644 index 00000000000..8fec275fd06 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs @@ -0,0 +1,31 @@ +// Verifies that type metadata identifiers for drop functions are emitted correctly. +// +// Non needs_drop drop glue isn't codegen'd at all, so we don't try to check the IDs there. But we +// do check it's not emitted which should help catch bugs if we do start generating it again in the +// future. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static + +#![crate_type = "lib"] + +// CHECK-LABEL: define{{.*}}4core3ptr47drop_in_place$LT$dyn$u20$core..marker..Send$GT$ +// CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE") + +struct EmptyDrop; +// CHECK-NOT: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}EmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + +struct PresentDrop; + +impl Drop for PresentDrop { + fn drop(&mut self) {} + // CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}PresentDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +} + +pub fn foo() { + let _ = Box::new(EmptyDrop) as Box; + let _ = Box::new(PresentDrop) as Box; +} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs new file mode 100644 index 00000000000..7e60aafff68 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs @@ -0,0 +1,45 @@ +// Verifies that type metadata identifiers for functions are emitted correctly +// for function types. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static + +#![crate_type = "lib"] + +pub fn foo1(_: fn(i32) -> i32) {} +// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo2(_: fn(i32) -> i32, _: fn(i32) -> i32) {} +// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo3(_: fn(i32) -> i32, _: fn(i32) -> i32, _: fn(i32) -> i32) {} +// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo4(_: &dyn Fn(i32) -> i32) {} +// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo5(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) {} +// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo6(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) {} +// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo7(_: &dyn FnMut(i32) -> i32) {} +// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo8(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) {} +// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo9(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) {} +// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo10(_: &dyn FnOnce(i32) -> i32) {} +// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo11(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) {} +// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo12(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) {} +// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs new file mode 100644 index 00000000000..36d2e8c9f25 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs @@ -0,0 +1,29 @@ +// Verifies that type metadata identifiers for functions are emitted correctly +// for lifetimes/regions. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 + +#![crate_type = "lib"] +#![feature(type_alias_impl_trait)] + +extern crate core; + +pub type Type1 = impl Send; + +#[define_opaque(Type1)] +pub fn foo<'a>() +where + Type1: 'static, +{ + pub struct Foo<'a>(&'a i32); + pub struct Bar<'a, 'b>(&'a i32, &'b Foo<'b>); + let _: Type1 = Bar; +} + +pub fn foo1(_: Type1) {} +// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo2(_: Type1, _: Type1) {} +// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo3(_: Type1, _: Type1, _: Type1) {} +// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs new file mode 100644 index 00000000000..9d611777ff0 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs @@ -0,0 +1,21 @@ +// Verifies that a secondary type metadata identifier is assigned to methods with their concrete +// self so they can be used as function pointers. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static + +#![crate_type = "lib"] + +trait Trait1 { + fn foo(&self); +} + +struct Type1; + +impl Trait1 for Type1 { + fn foo(&self) {} + // CHECK: define{{.*}}3foo{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} +} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type1EE"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs new file mode 100644 index 00000000000..a8ba8db1be3 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs @@ -0,0 +1,86 @@ +// Verifies that type metadata identifiers for functions are emitted correctly +// for paths. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static + +#![crate_type = "lib"] +#![feature(type_alias_impl_trait)] + +extern crate core; + +pub type Type1 = impl Send; +pub type Type2 = impl Send; +pub type Type3 = impl Send; +pub type Type4 = impl Send; + +#[define_opaque(Type1, Type2, Type4)] +pub fn foo() { + // Type in extern path + extern "C" { + fn bar(); + } + let _: Type1 = bar; + + // Type in closure path + || { + pub struct Foo; + let _: Type2 = Foo; + }; + + // Type in const path + const { + pub struct Foo; + #[define_opaque(Type3)] + fn bar() -> Type3 { + Foo + } + }; + + // Type in impl path + struct Foo; + impl Foo { + fn bar(&self) {} + } + let _: Type4 = ::bar; +} + +// Force arguments to be passed by using a reference. Otherwise, they may end up PassMode::Ignore + +pub fn foo1(_: &Type1) {} +// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo2(_: &Type1, _: &Type1) {} +// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo3(_: &Type1, _: &Type1, _: &Type1) {} +// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo4(_: &Type2) {} +// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo5(_: &Type2, _: &Type2) {} +// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo6(_: &Type2, _: &Type2, _: &Type2) {} +// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo7(_: &Type3) {} +// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo8(_: &Type3, _: &Type3) {} +// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo9(_: &Type3, _: &Type3, _: &Type3) {} +// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo10(_: &Type4) {} +// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo11(_: &Type4, _: &Type4) {} +// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo12(_: &Type4, _: &Type4, _: &Type4) {} +// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barEE"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_E"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_S0_E"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooEE"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_E"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_S0_E"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooEE"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_S0_E"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barEE"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_E"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_S0_E"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs new file mode 100644 index 00000000000..d37bb740f55 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs @@ -0,0 +1,54 @@ +// Verifies that type metadata identifiers for functions are emitted correctly +// for pointer types. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static + +#![crate_type = "lib"] + +pub fn foo1(_: &mut i32) {} +// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo2(_: &mut i32, _: &i32) {} +// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo3(_: &mut i32, _: &i32, _: &i32) {} +// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo4(_: &i32) {} +// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo5(_: &i32, _: &mut i32) {} +// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo6(_: &i32, _: &mut i32, _: &mut i32) {} +// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo7(_: *mut i32) {} +// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo8(_: *mut i32, _: *const i32) {} +// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo9(_: *mut i32, _: *const i32, _: *const i32) {} +// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo10(_: *const i32) {} +// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo11(_: *const i32, _: *mut i32) {} +// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo12(_: *const i32, _: *mut i32, _: *mut i32) {} +// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo13(_: fn(i32) -> i32) {} +// CHECK: define{{.*}}5foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo14(_: fn(i32) -> i32, _: fn(i32) -> i32) {} +// CHECK: define{{.*}}5foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo15(_: fn(i32) -> i32, _: fn(i32) -> i32, _: fn(i32) -> i32) {} +// CHECK: define{{.*}}5foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32EE"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_E"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_S0_E"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3i32EE"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_E"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_S1_E"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPu3i32E"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPu3i32PKS_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvPu3i32PKS_S2_E"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPKu3i32E"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPKu3i32PS_E"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvPKu3i32PS_S2_E"} +// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"} +// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"} +// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs new file mode 100644 index 00000000000..7d9e4d05872 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs @@ -0,0 +1,190 @@ +// Verifies that type metadata identifiers for functions are emitted correctly +// for primitive types. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static + +#![crate_type = "lib"] + +extern crate core; +use core::ffi::*; + +pub fn foo1(_: ()) {} +// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo2(_: (), _: c_void) {} +// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo3(_: (), _: c_void, _: c_void) {} +// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo4(_: *mut ()) {} +// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo5(_: *mut (), _: *mut c_void) {} +// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo6(_: *mut (), _: *mut c_void, _: *mut c_void) {} +// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo7(_: *const ()) {} +// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo8(_: *const (), _: *const c_void) {} +// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo9(_: *const (), _: *const c_void, _: *const c_void) {} +// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo10(_: bool) {} +// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo11(_: bool, _: bool) {} +// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo12(_: bool, _: bool, _: bool) {} +// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo13(_: i8) {} +// CHECK: define{{.*}}5foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo14(_: i8, _: i8) {} +// CHECK: define{{.*}}5foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo15(_: i8, _: i8, _: i8) {} +// CHECK: define{{.*}}5foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo16(_: i16) {} +// CHECK: define{{.*}}5foo16{{.*}}!type ![[TYPE16:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo17(_: i16, _: i16) {} +// CHECK: define{{.*}}5foo17{{.*}}!type ![[TYPE17:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo18(_: i16, _: i16, _: i16) {} +// CHECK: define{{.*}}5foo18{{.*}}!type ![[TYPE18:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo19(_: i32) {} +// CHECK: define{{.*}}5foo19{{.*}}!type ![[TYPE19:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo20(_: i32, _: i32) {} +// CHECK: define{{.*}}5foo20{{.*}}!type ![[TYPE20:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo21(_: i32, _: i32, _: i32) {} +// CHECK: define{{.*}}5foo21{{.*}}!type ![[TYPE21:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo22(_: i64) {} +// CHECK: define{{.*}}5foo22{{.*}}!type ![[TYPE22:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo23(_: i64, _: i64) {} +// CHECK: define{{.*}}5foo23{{.*}}!type ![[TYPE23:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo24(_: i64, _: i64, _: i64) {} +// CHECK: define{{.*}}5foo24{{.*}}!type ![[TYPE24:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo25(_: i128) {} +// CHECK: define{{.*}}5foo25{{.*}}!type ![[TYPE25:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo26(_: i128, _: i128) {} +// CHECK: define{{.*}}5foo26{{.*}}!type ![[TYPE26:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo27(_: i128, _: i128, _: i128) {} +// CHECK: define{{.*}}5foo27{{.*}}!type ![[TYPE27:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo28(_: isize) {} +// CHECK: define{{.*}}5foo28{{.*}}!type ![[TYPE28:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo29(_: isize, _: isize) {} +// CHECK: define{{.*}}5foo29{{.*}}!type ![[TYPE29:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo30(_: isize, _: isize, _: isize) {} +// CHECK: define{{.*}}5foo30{{.*}}!type ![[TYPE30:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo31(_: u8) {} +// CHECK: define{{.*}}5foo31{{.*}}!type ![[TYPE31:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo32(_: u8, _: u8) {} +// CHECK: define{{.*}}5foo32{{.*}}!type ![[TYPE32:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo33(_: u8, _: u8, _: u8) {} +// CHECK: define{{.*}}5foo33{{.*}}!type ![[TYPE33:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo34(_: u16) {} +// CHECK: define{{.*}}5foo34{{.*}}!type ![[TYPE34:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo35(_: u16, _: u16) {} +// CHECK: define{{.*}}5foo35{{.*}}!type ![[TYPE35:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo36(_: u16, _: u16, _: u16) {} +// CHECK: define{{.*}}5foo36{{.*}}!type ![[TYPE36:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo37(_: u32) {} +// CHECK: define{{.*}}5foo37{{.*}}!type ![[TYPE37:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo38(_: u32, _: u32) {} +// CHECK: define{{.*}}5foo38{{.*}}!type ![[TYPE38:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo39(_: u32, _: u32, _: u32) {} +// CHECK: define{{.*}}5foo39{{.*}}!type ![[TYPE39:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo40(_: u64) {} +// CHECK: define{{.*}}5foo40{{.*}}!type ![[TYPE40:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo41(_: u64, _: u64) {} +// CHECK: define{{.*}}5foo41{{.*}}!type ![[TYPE41:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo42(_: u64, _: u64, _: u64) {} +// CHECK: define{{.*}}5foo42{{.*}}!type ![[TYPE42:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo43(_: u128) {} +// CHECK: define{{.*}}5foo43{{.*}}!type ![[TYPE43:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo44(_: u128, _: u128) {} +// CHECK: define{{.*}}5foo44{{.*}}!type ![[TYPE44:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo45(_: u128, _: u128, _: u128) {} +// CHECK: define{{.*}}5foo45{{.*}}!type ![[TYPE45:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo46(_: usize) {} +// CHECK: define{{.*}}5foo46{{.*}}!type ![[TYPE46:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo47(_: usize, _: usize) {} +// CHECK: define{{.*}}5foo47{{.*}}!type ![[TYPE47:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo48(_: usize, _: usize, _: usize) {} +// CHECK: define{{.*}}5foo48{{.*}}!type ![[TYPE48:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo49(_: f32) {} +// CHECK: define{{.*}}5foo49{{.*}}!type ![[TYPE49:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo50(_: f32, _: f32) {} +// CHECK: define{{.*}}5foo50{{.*}}!type ![[TYPE50:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo51(_: f32, _: f32, _: f32) {} +// CHECK: define{{.*}}5foo51{{.*}}!type ![[TYPE51:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo52(_: f64) {} +// CHECK: define{{.*}}5foo52{{.*}}!type ![[TYPE52:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo53(_: f64, _: f64) {} +// CHECK: define{{.*}}5foo53{{.*}}!type ![[TYPE53:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo54(_: f64, _: f64, _: f64) {} +// CHECK: define{{.*}}5foo54{{.*}}!type ![[TYPE54:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo55(_: char) {} +// CHECK: define{{.*}}5foo55{{.*}}!type ![[TYPE55:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo56(_: char, _: char) {} +// CHECK: define{{.*}}5foo56{{.*}}!type ![[TYPE56:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo57(_: char, _: char, _: char) {} +// CHECK: define{{.*}}5foo57{{.*}}!type ![[TYPE57:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo58(_: &str) {} +// CHECK: define{{.*}}5foo58{{.*}}!type ![[TYPE58:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo59(_: &str, _: &str) {} +// CHECK: define{{.*}}5foo59{{.*}}!type ![[TYPE59:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo60(_: &str, _: &str, _: &str) {} +// CHECK: define{{.*}}5foo60{{.*}}!type ![[TYPE60:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvE"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvPvE"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvPvS_E"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPvS_S_E"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPKvE"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPKvS0_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvPKvS0_S0_E"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvbE"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvbbE"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvbbbE"} +// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu2i8E"} +// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu2i8S_E"} +// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu2i8S_S_E"} +// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3i16E"} +// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3i16S_E"} +// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3i16S_S_E"} +// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3i32E"} +// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3i32S_E"} +// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3i32S_S_E"} +// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3i64E"} +// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3i64S_E"} +// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu3i64S_S_E"} +// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu4i128E"} +// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu4i128S_E"} +// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu4i128S_S_E"} +// CHECK: ![[TYPE28]] = !{i64 0, !"_ZTSFvu5isizeE"} +// CHECK: ![[TYPE29]] = !{i64 0, !"_ZTSFvu5isizeS_E"} +// CHECK: ![[TYPE30]] = !{i64 0, !"_ZTSFvu5isizeS_S_E"} +// CHECK: ![[TYPE31]] = !{i64 0, !"_ZTSFvu2u8E"} +// CHECK: ![[TYPE32]] = !{i64 0, !"_ZTSFvu2u8S_E"} +// CHECK: ![[TYPE33]] = !{i64 0, !"_ZTSFvu2u8S_S_E"} +// CHECK: ![[TYPE34]] = !{i64 0, !"_ZTSFvu3u16E"} +// CHECK: ![[TYPE35]] = !{i64 0, !"_ZTSFvu3u16S_E"} +// CHECK: ![[TYPE36]] = !{i64 0, !"_ZTSFvu3u16S_S_E"} +// CHECK: ![[TYPE37]] = !{i64 0, !"_ZTSFvu3u32E"} +// CHECK: ![[TYPE38]] = !{i64 0, !"_ZTSFvu3u32S_E"} +// CHECK: ![[TYPE39]] = !{i64 0, !"_ZTSFvu3u32S_S_E"} +// CHECK: ![[TYPE40]] = !{i64 0, !"_ZTSFvu3u64E"} +// CHECK: ![[TYPE41]] = !{i64 0, !"_ZTSFvu3u64S_E"} +// CHECK: ![[TYPE42]] = !{i64 0, !"_ZTSFvu3u64S_S_E"} +// CHECK: ![[TYPE43]] = !{i64 0, !"_ZTSFvu4u128E"} +// CHECK: ![[TYPE44]] = !{i64 0, !"_ZTSFvu4u128S_E"} +// CHECK: ![[TYPE45]] = !{i64 0, !"_ZTSFvu4u128S_S_E"} +// CHECK: ![[TYPE46]] = !{i64 0, !"_ZTSFvu5usizeE"} +// CHECK: ![[TYPE47]] = !{i64 0, !"_ZTSFvu5usizeS_E"} +// CHECK: ![[TYPE48]] = !{i64 0, !"_ZTSFvu5usizeS_S_E"} +// CHECK: ![[TYPE49]] = !{i64 0, !"_ZTSFvfE"} +// CHECK: ![[TYPE50]] = !{i64 0, !"_ZTSFvffE"} +// CHECK: ![[TYPE51]] = !{i64 0, !"_ZTSFvfffE"} +// CHECK: ![[TYPE52]] = !{i64 0, !"_ZTSFvdE"} +// CHECK: ![[TYPE53]] = !{i64 0, !"_ZTSFvddE"} +// CHECK: ![[TYPE54]] = !{i64 0, !"_ZTSFvdddE"} +// CHECK: ![[TYPE55]] = !{i64 0, !"_ZTSFvu4charE"} +// CHECK: ![[TYPE56]] = !{i64 0, !"_ZTSFvu4charS_E"} +// CHECK: ![[TYPE57]] = !{i64 0, !"_ZTSFvu4charS_S_E"} +// CHECK: ![[TYPE58]] = !{i64 0, !"_ZTSFvu3refIu3strEE"} +// CHECK: ![[TYPE59]] = !{i64 0, !"_ZTSFvu3refIu3strES0_E"} +// CHECK: ![[TYPE60]] = !{i64 0, !"_ZTSFvu3refIu3strES0_S0_E"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs new file mode 100644 index 00000000000..0f97c70f3f9 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs @@ -0,0 +1,79 @@ +// Verifies that type metadata identifiers for functions are emitted correctly +// for repr transparent types. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static + +#![crate_type = "lib"] + +extern crate core; +use core::ffi::*; +use std::marker::PhantomData; + +struct Foo(i32); + +// repr(transparent) user-defined type +#[repr(transparent)] +pub struct Type1 { + member1: (), + member2: PhantomData, + member3: Foo, +} + +// Self-referencing repr(transparent) user-defined type +#[repr(transparent)] +pub struct Type2<'a> { + member1: (), + member2: PhantomData, + member3: &'a Type2<'a>, +} + +pub struct Bar(i32); + +// repr(transparent) user-defined generic type +#[repr(transparent)] +pub struct Type3(T); + +// repr(transparent) wrapper which engages in self-reference +#[repr(transparent)] +pub struct Type4(Type4Helper); +#[repr(transparent)] +pub struct Type4Helper(*mut T); + +pub fn foo1(_: Type1) {} +// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo2(_: Type1, _: Type1) {} +// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo3(_: Type1, _: Type1, _: Type1) {} +// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo4(_: Type2) {} +// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo5(_: Type2, _: Type2) {} +// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo6(_: Type2, _: Type2, _: Type2) {} +// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo7(_: Type3) {} +// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo8(_: Type3, _: Type3) {} +// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo9(_: Type3, _: Type3, _: Type3) {} +// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo10(_: Type4) {} +// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo11(_: Type4, _: Type4) {} +// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo12(_: Type4, _: Type4, _: Type4) {} +// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooE"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooS_E"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooS_S_E"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIvEE"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIvES_E"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIvES_S_E"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarE"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarS_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarS_S_E"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4E"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4S0_E"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4S0_S0_E"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs new file mode 100644 index 00000000000..bdee3f47a83 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs @@ -0,0 +1,36 @@ +// Verifies that type metadata identifiers for functions are emitted correctly +// for sequence types. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static + +#![crate_type = "lib"] + +pub fn foo1(_: (i32, i32)) {} +// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo2(_: (i32, i32), _: (i32, i32)) {} +// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo3(_: (i32, i32), _: (i32, i32), _: (i32, i32)) {} +// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo4(_: [i32; 32]) {} +// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo5(_: [i32; 32], _: [i32; 32]) {} +// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo6(_: [i32; 32], _: [i32; 32], _: [i32; 32]) {} +// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo7(_: &[i32]) {} +// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo8(_: &[i32], _: &[i32]) {} +// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo9(_: &[i32], _: &[i32], _: &[i32]) {} +// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_EE"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_E"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_S0_E"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvA32u3i32E"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvA32u3i32S0_E"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvA32u3i32S0_S0_E"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EEE"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_S1_E"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs new file mode 100644 index 00000000000..55e816178f8 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs @@ -0,0 +1,175 @@ +// Verifies that type metadata identifiers for functions are emitted correctly +// for trait types. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static + +#![crate_type = "lib"] + +extern crate core; + +pub trait Trait1 { + fn foo(&self); +} + +#[derive(Clone, Copy)] +pub struct Type1; + +impl Trait1 for Type1 { + fn foo(&self) {} +} + +pub trait Trait2 { + fn bar(&self); +} + +pub struct Type2; + +impl Trait2 for Type2 { + fn bar(&self) {} +} + +pub trait Trait3 { + fn baz(&self, _: &T); +} + +pub struct Type3; + +impl Trait3 for T { + fn baz(&self, _: &U) {} +} + +pub trait Trait4<'a, T> { + type Output: 'a; + fn qux(&self, _: &T) -> Self::Output; +} + +pub struct Type4; + +impl<'a, T, U> Trait4<'a, U> for T { + type Output = &'a i32; + fn qux(&self, _: &U) -> Self::Output { + &0 + } +} + +pub trait Trait5 { + fn quux(&self, _: &[T; N]); +} + +#[derive(Copy, Clone)] +pub struct Type5; + +impl Trait5 for T { + fn quux(&self, _: &[U; N]) {} +} + +pub fn foo1(_: &dyn Send) {} +// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo2(_: &dyn Send, _: &dyn Send) {} +// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo3(_: &dyn Send, _: &dyn Send, _: &dyn Send) {} +// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo4(_: &(dyn Send + Sync)) {} +// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo5(_: &(dyn Send + Sync), _: &(dyn Sync + Send)) {} +// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo6(_: &(dyn Send + Sync), _: &(dyn Sync + Send), _: &(dyn Sync + Send)) {} +// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo7(_: &(dyn Trait1 + Send)) {} +// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo8(_: &(dyn Trait1 + Send), _: &(dyn Trait1 + Send)) {} +// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo9(_: &(dyn Trait1 + Send), _: &(dyn Trait1 + Send), _: &(dyn Trait1 + Send)) {} +// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo10(_: &(dyn Trait1 + Send + Sync)) {} +// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo11(_: &(dyn Trait1 + Send + Sync), _: &(dyn Trait1 + Sync + Send)) {} +// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo12( + _: &(dyn Trait1 + Send + Sync), + _: &(dyn Trait1 + Sync + Send), + _: &(dyn Trait1 + Sync + Send), +) { +} +// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo13(_: &dyn Trait1) {} +// CHECK: define{{.*}}5foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo14(_: &dyn Trait1, _: &dyn Trait1) {} +// CHECK: define{{.*}}5foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo15(_: &dyn Trait1, _: &dyn Trait1, _: &dyn Trait1) {} +// CHECK: define{{.*}}5foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo16(_: &dyn Trait2) {} +pub fn bar16() { + let a = Type2; + foo16(&a); +} +// CHECK: define{{.*}}5foo16{{.*}}!type ![[TYPE16:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo17(_: &dyn Trait2, _: &dyn Trait2) {} +pub fn bar17() { + let a = Type2; + foo17(&a, &a); +} +// CHECK: define{{.*}}5foo17{{.*}}!type ![[TYPE17:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo18(_: &dyn Trait2, _: &dyn Trait2, _: &dyn Trait2) {} +pub fn bar18() { + let a = Type2; + foo18(&a, &a, &a); +} +// CHECK: define{{.*}}5foo18{{.*}}!type ![[TYPE18:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo19(_: &dyn Trait3) {} +// CHECK: define{{.*}}5foo19{{.*}}!type ![[TYPE19:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo20(_: &dyn Trait3, _: &dyn Trait3) {} +// CHECK: define{{.*}}5foo20{{.*}}!type ![[TYPE20:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo21(_: &dyn Trait3, _: &dyn Trait3, _: &dyn Trait3) {} +// CHECK: define{{.*}}5foo21{{.*}}!type ![[TYPE21:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo22<'a>(_: &dyn Trait4<'a, Type4, Output = &'a i32>) {} +// CHECK: define{{.*}}5foo22{{.*}}!type ![[TYPE22:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo23<'a>( + _: &dyn Trait4<'a, Type4, Output = &'a i32>, + _: &dyn Trait4<'a, Type4, Output = &'a i32>, +) { +} +// CHECK: define{{.*}}5foo23{{.*}}!type ![[TYPE23:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo24<'a>( + _: &dyn Trait4<'a, Type4, Output = &'a i32>, + _: &dyn Trait4<'a, Type4, Output = &'a i32>, + _: &dyn Trait4<'a, Type4, Output = &'a i32>, +) { +} +// CHECK: define{{.*}}5foo24{{.*}}!type ![[TYPE24:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo25(_: &dyn Trait5) {} +// CHECK: define{{.*}}5foo25{{.*}}!type ![[TYPE25:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo26(_: &dyn Trait5, _: &dyn Trait5) {} +// CHECK: define{{.*}}5foo26{{.*}}!type ![[TYPE26:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo27(_: &dyn Trait5, _: &dyn Trait5, _: &dyn Trait5) {} +// CHECK: define{{.*}}5foo27{{.*}}!type ![[TYPE27:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + +// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"} +// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEEE"} +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"} +// FIXME(rcvalle): Enforce autotraits ordering when encoding (e.g., alphabetical order) +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEEE"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES3_E"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES3_S3_E"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES3_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES3_S3_E"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEEE"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES4_E"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES4_S4_E"} +// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEES2_E"} +// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEES2_S2_E"} +// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEES3_E"} +// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEES3_S3_E"} +// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEEE"} +// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEES3_E"} +// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEES3_S3_E"} +// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EEE"} +// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EES6_E"} +// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EES6_S6_E"} +// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEEE"} +// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEES5_E"} +// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEES5_S5_E"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs new file mode 100644 index 00000000000..c1f3ca61afe --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs @@ -0,0 +1,62 @@ +// Verifies that type metadata identifiers for functions are emitted correctly +// for user-defined types. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static + +#![crate_type = "lib"] +#![feature(extern_types)] + +pub struct Struct1 { + member1: T, +} + +pub enum Enum1 { + Variant1(T), +} + +pub union Union1 { + member1: std::mem::ManuallyDrop, +} + +extern "C" { + pub type type1; +} + +pub fn foo1(_: &Struct1) {} +// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo2(_: &Struct1, _: &Struct1) {} +// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo3(_: &Struct1, _: &Struct1, _: &Struct1) {} +// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo4(_: &Enum1) {} +// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo5(_: &Enum1, _: &Enum1) {} +// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo6(_: &Enum1, _: &Enum1, _: &Enum1) {} +// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo7(_: &Union1) {} +// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo8(_: &Union1, _: &Union1) {} +// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo9(_: &Union1, _: &Union1, _: &Union1) {} +// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo10(_: *mut type1) {} +// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo11(_: *mut type1, _: *mut type1) {} +// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo12(_: *mut type1, _: *mut type1, _: *mut type1) {} +// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}7Struct1Iu3i32EEE"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}7Struct1Iu3i32EES1_E"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}7Struct1Iu3i32EES1_S1_E"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Enum1Iu3i32EEE"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Enum1Iu3i32EES1_E"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Enum1Iu3i32EES1_S1_E"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Union1Iu3i32EEE"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Union1Iu3i32EES1_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Union1Iu3i32EES1_S1_E"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvP5type1E"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvP5type1S0_E"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvP5type1S0_S0_E"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs new file mode 100644 index 00000000000..32637b64b3e --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs @@ -0,0 +1,31 @@ +// Verifies that generalized type metadata for functions are emitted. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers + +#![crate_type = "lib"] + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo + // CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.generalized") + f(arg) +} + +pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { + // CHECK-LABEL: define{{.*}}bar + // CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.generalized") + f(arg1, arg2) +} + +pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { + // CHECK-LABEL: define{{.*}}baz + // CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.generalized") + f(arg1, arg2, arg3) +} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PKvS_E.generalized"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PKvS_S_E.generalized"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PKvS_S_S_E.generalized"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs new file mode 100644 index 00000000000..51121b0aef1 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs @@ -0,0 +1,31 @@ +// Verifies that normalized and generalized type metadata for functions are emitted. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Zsanitizer-cfi-generalize-pointers + +#![crate_type = "lib"] + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo + // CHECK-SAME: {{.*}}![[TYPE1:[0-9]+]] + // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.normalized.generalized") + f(arg) +} + +pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { + // CHECK-LABEL: define{{.*}}bar + // CHECK-SAME: {{.*}}![[TYPE2:[0-9]+]] + // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.normalized.generalized") + f(arg1, arg2) +} + +pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { + // CHECK-LABEL: define{{.*}}baz + // CHECK-SAME: {{.*}}![[TYPE3:[0-9]+]] + // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.normalized.generalized") + f(arg1, arg2, arg3) +} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PKvS_E.normalized.generalized"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PKvS_S_E.normalized.generalized"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PKvS_S_S_E.normalized.generalized"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs new file mode 100644 index 00000000000..1cfdd23006e --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs @@ -0,0 +1,31 @@ +// Verifies that normalized type metadata for functions are emitted. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers + +#![crate_type = "lib"] + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo + // CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.normalized") + f(arg) +} + +pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { + // CHECK-LABEL: define{{.*}}bar + // CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.normalized") + f(arg1, arg2) +} + +pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { + // CHECK-LABEL: define{{.*}}baz + // CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.normalized") + f(arg1, arg2, arg3) +} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PFS_S_ES_E.normalized"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_ES_S_E.normalized"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_S_ES_S_S_E.normalized"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs new file mode 100644 index 00000000000..56ab1ce4b35 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs @@ -0,0 +1,31 @@ +// Verifies that type metadata for functions are emitted. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi + +#![crate_type = "lib"] + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo + // CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E") + f(arg) +} + +pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { + // CHECK-LABEL: define{{.*}}bar + // CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E") + f(arg1, arg2) +} + +pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { + // CHECK-LABEL: define{{.*}}baz + // CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E") + f(arg1, arg2, arg3) +} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PFS_S_ES_E"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_ES_S_E"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_S_ES_S_S_E"} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs new file mode 100644 index 00000000000..0e57ce322d1 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs @@ -0,0 +1,145 @@ +// Verifies that type metadata identifiers for trait objects are emitted correctly. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Ctarget-feature=-crt-static -Zsanitizer=cfi + +#![crate_type = "lib"] + +pub trait Trait1 { + fn foo(&self); +} + +#[derive(Clone, Copy)] +pub struct Type1; + +impl Trait1 for Type1 { + fn foo(&self) {} +} + +pub trait Trait2 { + fn bar(&self); +} + +pub struct Type2; + +impl Trait2 for Type2 { + fn bar(&self) {} +} + +pub trait Trait3 { + fn baz(&self, _: &T); +} + +pub struct Type3; + +impl Trait3 for T { + fn baz(&self, _: &U) {} +} + +pub trait Trait4<'a, T> { + type Output: 'a; + fn qux(&self, _: &T) -> Self::Output; +} + +pub struct Type4; + +impl<'a, T, U> Trait4<'a, U> for T { + type Output = &'a i32; + fn qux(&self, _: &U) -> Self::Output { + &0 + } +} + +pub trait Trait5 { + fn quux(&self, _: &[T; N]); +} + +#[derive(Copy, Clone)] +pub struct Type5; + +impl Trait5 for T { + fn quux(&self, _: &[U; N]) {} +} + +pub fn foo1(a: &dyn Trait1) { + a.foo(); + // CHECK-LABEL: define{{.*}}4foo1{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE1:[[:print:]]+]]") +} + +pub fn bar1() { + let a = Type1; + let b = &a as &dyn Trait1; + b.foo(); + // CHECK-LABEL: define{{.*}}4bar1{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]") +} + +pub fn foo2(a: &dyn Trait2) { + a.bar(); + // CHECK-LABEL: define{{.*}}4foo2{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]") +} + +pub fn bar2() { + let a = Type2; + foo2(&a); + let b = &a as &dyn Trait2; + b.bar(); + // CHECK-LABEL: define{{.*}}4bar2{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]") +} + +pub fn foo3(a: &dyn Trait3) { + let b = Type3; + a.baz(&b); + // CHECK-LABEL: define{{.*}}4foo3{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]") +} + +pub fn bar3() { + let a = Type3; + foo3(&a); + let b = &a as &dyn Trait3; + b.baz(&a); + // CHECK-LABEL: define{{.*}}4bar3{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]") +} + +pub fn foo4<'a>(a: &dyn Trait4<'a, Type4, Output = &'a i32>) { + let b = Type4; + a.qux(&b); + // CHECK-LABEL: define{{.*}}4foo4{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE4:[[:print:]]+]]") +} + +pub fn bar4<'a>() { + let a = Type4; + foo4(&a); + let b = &a as &dyn Trait4<'a, Type4, Output = &'a i32>; + b.qux(&a); + // CHECK-LABEL: define{{.*}}4bar4{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE4:[[:print:]]+]]") +} + +pub fn foo5(a: &dyn Trait5) { + let b = &[Type5; 32]; + a.quux(&b); + // CHECK-LABEL: define{{.*}}4foo5{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE5:[[:print:]]+]]") +} + +pub fn bar5() { + let a = &[Type5; 32]; + foo5(&a); + let b = &a as &dyn Trait5; + b.quux(&a); + // CHECK-LABEL: define{{.*}}4bar5{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE5:[[:print:]]+]]") +} + +// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE1]]"} +// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE2]]"} +// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE3]]"} +// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE4]]"} +// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE5]]"} diff --git a/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs b/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs new file mode 100644 index 00000000000..00e9b5029af --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs @@ -0,0 +1,24 @@ +// Verifies that type metadata identifiers for for weakly-linked symbols are +// emitted correctly. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clinker-plugin-lto -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static +#![crate_type = "bin"] +#![feature(linkage)] + +unsafe extern "C" { + #[linkage = "extern_weak"] + static FOO: Option ()>; +} +// CHECK: @_rust_extern_with_linkage_FOO = internal global ptr @FOO + +fn main() { + unsafe { + if let Some(method) = FOO { + method(4.2); + // CHECK: call i1 @llvm.type.test(ptr {{%method|%0}}, metadata !"_ZTSFvdE") + } + } +} + +// CHECK: declare !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} extern_weak void @FOO(double) unnamed_addr #{{[0-9]+}} diff --git a/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs b/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs new file mode 100644 index 00000000000..57004da6f8e --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs @@ -0,0 +1,46 @@ +// Verifies that pointer types are generalized. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers -Copt-level=0 + +#![crate_type = "lib"] + +extern crate core; + +pub fn foo0(_: &mut i32) {} +// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo1(_: &mut i32, _: &mut i32) {} +// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo2(_: &mut i32, _: &mut i32, _: &mut i32) {} +// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo3(_: &i32) {} +// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo4(_: &i32, _: &i32) {} +// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo5(_: &i32, _: &i32, _: &i32) {} +// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo6(_: *mut i32) {} +// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo7(_: *mut i32, _: *mut i32) {} +// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo8(_: *mut i32, _: *mut i32, _: *mut i32) {} +// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo9(_: *const i32) {} +// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo10(_: *const i32, _: *const i32) {} +// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo11(_: *const i32, _: *const i32, _: *const i32) {} +// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} + +// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvU3mutu3refIvEE.generalized"} +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvU3mutu3refIvES0_E.generalized"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvU3mutu3refIvES0_S0_E.generalized"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIvEE.generalized"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIvES_E.generalized"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIvES_S_E.generalized"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPvE.generalized"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPvS_E.generalized"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPvS_S_E.generalized"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvPKvE.generalized"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPKvS0_E.generalized"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPKvS0_S0_E.generalized"} diff --git a/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs b/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs new file mode 100644 index 00000000000..770ee4e64e0 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs @@ -0,0 +1,46 @@ +// Verifies that integer types are normalized. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Copt-level=0 + +#![crate_type = "lib"] + +extern crate core; + +pub fn foo0(_: bool) {} +// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}} +pub fn foo1(_: bool, _: bool) {} +// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} +pub fn foo2(_: bool, _: bool, _: bool) {} +// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} +pub fn foo3(_: char) {} +// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} +pub fn foo4(_: char, _: char) {} +// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} +pub fn foo5(_: char, _: char, _: char) {} +// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} +pub fn foo6(_: isize) {} +// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} +pub fn foo7(_: isize, _: isize) {} +// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} +pub fn foo8(_: isize, _: isize, _: isize) {} +// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} +pub fn foo9(_: (), _: usize) {} +// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} +pub fn foo10(_: (), _: usize, _: usize) {} +// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} +pub fn foo11(_: (), _: usize, _: usize, _: usize) {} +// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} + +// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvu2u8E.normalized"} +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu2u8S_E.normalized"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu2u8S_S_E.normalized"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3u32E.normalized"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3u32S_E.normalized"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3u32S_S_E.normalized"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}E.normalized"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_E.normalized"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_S_E.normalized"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}E.normalized"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}S_E.normalized"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}S_S_E.normalized"} diff --git a/tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs b/tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs new file mode 100644 index 00000000000..a2d0d63cc17 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs @@ -0,0 +1,9 @@ +// Verifies that functions are instrumented. +// +//@ needs-sanitizer-dataflow +//@ compile-flags: -Copt-level=0 -Zsanitizer=dataflow + +#![crate_type = "lib"] + +pub fn foo() {} +// CHECK: define{{.*}}foo{{.*}}.dfsan diff --git a/tests/codegen-llvm/sanitizer/kasan-emits-instrumentation.rs b/tests/codegen-llvm/sanitizer/kasan-emits-instrumentation.rs new file mode 100644 index 00000000000..774c9ab53f1 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/kasan-emits-instrumentation.rs @@ -0,0 +1,41 @@ +// Verifies that `-Zsanitizer=kernel-address` emits sanitizer instrumentation. + +//@ add-core-stubs +//@ compile-flags: -Zsanitizer=kernel-address -Copt-level=0 +//@ revisions: aarch64 riscv64imac riscv64gc x86_64 +//@[aarch64] compile-flags: --target aarch64-unknown-none +//@[aarch64] needs-llvm-components: aarch64 +//@[riscv64imac] compile-flags: --target riscv64imac-unknown-none-elf +//@[riscv64imac] needs-llvm-components: riscv +//@[riscv64gc] compile-flags: --target riscv64gc-unknown-none-elf +//@[riscv64gc] needs-llvm-components: riscv +//@[x86_64] compile-flags: --target x86_64-unknown-none +//@[x86_64] needs-llvm-components: x86 + +#![crate_type = "rlib"] +#![feature(no_core, no_sanitize, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: ; kasan_emits_instrumentation::unsanitized +// CHECK-NEXT: ; Function Attrs: +// CHECK-NOT: sanitize_address +// CHECK: start: +// CHECK-NOT: call void @__asan_report_load +// CHECK: } +#[no_sanitize(address)] +pub fn unsanitized(b: &mut u8) -> u8 { + *b +} + +// CHECK-LABEL: ; kasan_emits_instrumentation::sanitized +// CHECK-NEXT: ; Function Attrs: +// CHECK: sanitize_address +// CHECK: start: +// CHECK: call void @__asan_report_load +// CHECK: } +pub fn sanitized(b: &mut u8) -> u8 { + *b +} diff --git a/tests/codegen-llvm/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs b/tests/codegen-llvm/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs new file mode 100644 index 00000000000..0be1ff19774 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs @@ -0,0 +1,20 @@ +// Verifies that "cfi-normalize-integers" module flag is added. +// +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: x86 +//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +pub fn foo() {} + +// CHECK: !{{[0-9]+}} = !{i32 4, !"cfi-normalize-integers", i32 1} diff --git a/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-arity-flag.rs b/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-arity-flag.rs new file mode 100644 index 00000000000..9a2290901d6 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-arity-flag.rs @@ -0,0 +1,19 @@ +// Verifies that "kcfi-arity" module flag is added. +// +//@ add-core-stubs +//@ revisions: x86_64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: x86 +//@ compile-flags: -Ctarget-feature=-crt-static -Cpanic=abort -Zsanitizer=kcfi -Zsanitizer-kcfi-arity +//@ min-llvm-version: 21.0.0 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +pub fn foo() {} + +// CHECK: !{{[0-9]+}} = !{i32 4, !"kcfi-arity", i32 1} diff --git a/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-flag.rs b/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-flag.rs new file mode 100644 index 00000000000..eabe0409c9a --- /dev/null +++ b/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-flag.rs @@ -0,0 +1,20 @@ +// Verifies that "kcfi" module flag is added. +// +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: x86 +//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +pub fn foo() {} + +// CHECK: !{{[0-9]+}} = !{i32 4, !"kcfi", i32 1} diff --git a/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-offset-flag.rs b/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-offset-flag.rs new file mode 100644 index 00000000000..2f18c9d84b9 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/kcfi/add-kcfi-offset-flag.rs @@ -0,0 +1,20 @@ +// Verifies that "kcfi-offset" module flag is added. +// +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: x86 +//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Z patchable-function-entry=4,3 + +#![feature(no_core, lang_items, patchable_function_entry)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +pub fn foo() {} + +// CHECK: !{{[0-9]+}} = !{i32 4, !"kcfi-offset", i32 3} diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs new file mode 100644 index 00000000000..6b40918dd3a --- /dev/null +++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs @@ -0,0 +1,27 @@ +// Verifies that KCFI operand bundles are omitted. +// +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: +//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0 + +#![crate_type = "lib"] +#![feature(no_core, no_sanitize, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_sanitize(kcfi)] +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: emit_kcfi_operand_bundle_attr_no_sanitize::foo + // CHECK: Function Attrs: {{.*}} + // CHECK-LABEL: define{{.*}}foo{{.*}}!{{|kcfi_type}} !{{[0-9]+}} + // CHECK: start: + // CHECK-NOT: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 {{[-0-9]+}}) ] + // CHECK: ret i32 {{%.+}} + f(arg) +} diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs new file mode 100644 index 00000000000..942b50deb02 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs @@ -0,0 +1,41 @@ +// Verifies that generalized KCFI type metadata for functions are emitted. +// +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: +//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Zsanitizer-cfi-generalize-pointers + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo + // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE1:[0-9]+]] + // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 233085384) ] + f(arg) +} + +pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { + // CHECK-LABEL: define{{.*}}bar + // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE2:[0-9]+]] + // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2){{.*}}[ "kcfi"(i32 435418021) ] + f(arg1, arg2) +} + +pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { + // CHECK-LABEL: define{{.*}}baz + // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE3:[0-9]+]] + // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 -1003721339) ] + f(arg1, arg2, arg3) +} + +// CHECK: ![[TYPE1]] = !{i32 -1741689296} +// CHECK: ![[TYPE2]] = !{i32 489439372} +// CHECK: ![[TYPE3]] = !{i32 2026563871} diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs new file mode 100644 index 00000000000..c89d9bdd121 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs @@ -0,0 +1,41 @@ +// Verifies that normalized and generalized KCFI type metadata for functions are emitted. +// +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: +//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers -Zsanitizer-cfi-generalize-pointers + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo + // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE1:[0-9]+]] + // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 -686570305) ] + f(arg) +} + +pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { + // CHECK-LABEL: define{{.*}}bar + // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE2:[0-9]+]] + // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2){{.*}}[ "kcfi"(i32 1281038450) ] + f(arg1, arg2) +} + +pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { + // CHECK-LABEL: define{{.*}}baz + // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE3:[0-9]+]] + // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 -1751512973) ] + f(arg1, arg2, arg3) +} + +// CHECK: ![[TYPE1]] = !{i32 975484707} +// CHECK: ![[TYPE2]] = !{i32 1658833102} +// CHECK: ![[TYPE3]] = !{i32 230429758} diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs new file mode 100644 index 00000000000..220cae1a4fa --- /dev/null +++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs @@ -0,0 +1,41 @@ +// Verifies that normalized KCFI type metadata for functions are emitted. +// +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: +//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo + // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE1:[0-9]+]] + // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 -841055669) ] + f(arg) +} + +pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { + // CHECK-LABEL: define{{.*}}bar + // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE2:[0-9]+]] + // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2){{.*}}[ "kcfi"(i32 1390819368) ] + f(arg1, arg2) +} + +pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { + // CHECK-LABEL: define{{.*}}baz + // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE3:[0-9]+]] + // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 586925835) ] + f(arg1, arg2, arg3) +} + +// CHECK: ![[TYPE1]] = !{i32 -458317079} +// CHECK: ![[TYPE2]] = !{i32 1737138182} +// CHECK: ![[TYPE3]] = !{i32 197182412} diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs new file mode 100644 index 00000000000..bb9a0005903 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs @@ -0,0 +1,41 @@ +// Verifies that KCFI type metadata for functions are emitted. +// +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: +//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0 + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo + // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE1:[0-9]+]] + // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 -1666898348) ] + f(arg) +} + +pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { + // CHECK-LABEL: define{{.*}}bar + // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE2:[0-9]+]] + // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2){{.*}}[ "kcfi"(i32 -1789026986) ] + f(arg1, arg2) +} + +pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { + // CHECK-LABEL: define{{.*}}baz + // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE3:[0-9]+]] + // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 1248878270) ] + f(arg1, arg2, arg3) +} + +// CHECK: ![[TYPE1]] = !{i32 653723426} +// CHECK: ![[TYPE2]] = !{i32 412174924} +// CHECK: ![[TYPE3]] = !{i32 -636668840} diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs new file mode 100644 index 00000000000..8b844b99142 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs @@ -0,0 +1,24 @@ +// Verifies that KCFI operand bundles are emitted. +// +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: +//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0 + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo{{.*}}!{{|kcfi_type}} !{{[0-9]+}} + // CHECK: start: + // CHECK-NEXT: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 {{[-0-9]+}}) ] + // CHECK-NEXT: ret i32 {{%.+}} + f(arg) +} diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs new file mode 100644 index 00000000000..15c107bea15 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs @@ -0,0 +1,155 @@ +// Verifies that type metadata identifiers for trait objects are emitted correctly. +// +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: +//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0 + +#![crate_type = "lib"] +#![feature(arbitrary_self_types, no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +pub trait Trait1 { + fn foo(&self); +} + +pub struct Type1; + +impl Trait1 for Type1 { + fn foo(&self) {} +} + +pub trait Trait2 { + fn bar(&self); +} + +pub struct Type2; + +impl Trait2 for Type2 { + fn bar(&self) {} +} + +pub trait Trait3 { + fn baz(&self, _: &T); +} + +pub struct Type3; + +impl Trait3 for T { + fn baz(&self, _: &U) {} +} + +pub trait Trait4<'a, T> { + type Output: 'a; + fn qux(&self, _: &T) -> Self::Output; +} + +pub struct Type4; + +impl<'a, T, U> Trait4<'a, U> for T { + type Output = &'a i32; + fn qux(&self, _: &U) -> Self::Output { + &0 + } +} + +pub trait Trait5 { + fn quux(&self, _: &[T; N]); +} + +pub struct Type5; + +impl Copy for Type5 {} + +impl Trait5 for T { + fn quux(&self, _: &[U; N]) {} +} + +pub fn foo1(a: &dyn Trait1) { + a.foo(); + // CHECK-LABEL: define{{.*}}4foo1{{.*}}!{{|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] +} + +pub fn bar1() { + let a = Type1; + let b = &a as &dyn Trait1; + b.foo(); + // CHECK-LABEL: define{{.*}}4bar1{{.*}}!{{|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] +} + +pub fn foo2(a: &dyn Trait2) { + a.bar(); + // CHECK-LABEL: define{{.*}}4foo2{{.*}}!{{|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ] +} + +pub fn bar2() { + let a = Type2; + foo2(&a); + let b = &a as &dyn Trait2; + b.bar(); + // CHECK-LABEL: define{{.*}}4bar2{{.*}}!{{|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ] +} + +pub fn foo3(a: &dyn Trait3) { + let b = Type3; + a.baz(&b); + // CHECK-LABEL: define{{.*}}4foo3{{.*}}!{{|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ] +} + +pub fn bar3() { + let a = Type3; + foo3(&a); + let b = &a as &dyn Trait3; + b.baz(&a); + // CHECK-LABEL: define{{.*}}4bar3{{.*}}!{{|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ] +} + +pub fn foo4<'a>(a: &dyn Trait4<'a, Type4, Output = &'a i32>) { + let b = Type4; + a.qux(&b); + // CHECK-LABEL: define{{.*}}4foo4{{.*}}!{{|kcfi_type}} !{{[0-9]+}} + // CHECK: call align 4 ptr %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ] +} + +pub fn bar4<'a>() { + let a = Type4; + foo4(&a); + let b = &a as &dyn Trait4<'a, Type4, Output = &'a i32>; + b.qux(&a); + // CHECK-LABEL: define{{.*}}4bar4{{.*}}!{{|kcfi_type}} !{{[0-9]+}} + // CHECK: call align 4 ptr %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ] +} + +pub fn foo5(a: &dyn Trait5) { + let b = &[Type5; 32]; + a.quux(&b); + // CHECK-LABEL: define{{.*}}4foo5{{.*}}!{{|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z](\.0)*|%_[0-9]+]}}, ptr align 1 {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ] +} + +pub fn bar5() { + let a = &[Type5; 32]; + foo5(&a); + let b = &a as &dyn Trait5; + b.quux(&a); + // CHECK-LABEL: define{{.*}}4bar5{{.*}}!{{|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z](\.0)*|%_[0-9]+]}}, ptr align 1 {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ] +} + +// CHECK: !{{[0-9]+}} = !{i32 [[TYPE1]]} +// CHECK: !{{[0-9]+}} = !{i32 [[TYPE2]]} +// CHECK: !{{[0-9]+}} = !{i32 [[TYPE3]]} +// CHECK: !{{[0-9]+}} = !{i32 [[TYPE4]]} +// CHECK: !{{[0-9]+}} = !{i32 [[TYPE5]]} diff --git a/tests/codegen-llvm/sanitizer/kcfi/naked-function.rs b/tests/codegen-llvm/sanitizer/kcfi/naked-function.rs new file mode 100644 index 00000000000..2c8cdc919b8 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/kcfi/naked-function.rs @@ -0,0 +1,47 @@ +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: x86 +//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Cno-prepopulate-passes -Copt-level=0 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +struct Thing; +trait MyTrait { + #[unsafe(naked)] + extern "C" fn my_naked_function() { + // the real function is defined + // CHECK: .globl + // CHECK-SAME: my_naked_function + naked_asm!("ret") + } +} +impl MyTrait for Thing {} + +// the shim calls the real function +// CHECK-LABEL: define +// CHECK-SAME: my_naked_function +// CHECK-SAME: reify.shim.fnptr + +// CHECK-LABEL: main +#[unsafe(no_mangle)] +pub fn main() { + // Trick the compiler into generating an indirect call. + const F: extern "C" fn() = Thing::my_naked_function; + + // main calls the shim function + // CHECK: call void + // CHECK-SAME: my_naked_function + // CHECK-SAME: reify.shim.fnptr + (F)(); +} + +// CHECK: declare !kcfi_type +// CHECK-SAME: my_naked_function diff --git a/tests/codegen-llvm/sanitizer/memory-track-origins.rs b/tests/codegen-llvm/sanitizer/memory-track-origins.rs new file mode 100644 index 00000000000..318c277e10c --- /dev/null +++ b/tests/codegen-llvm/sanitizer/memory-track-origins.rs @@ -0,0 +1,31 @@ +// Verifies that MemorySanitizer track-origins level can be controlled +// with -Zsanitizer-memory-track-origins option. +// +//@ needs-sanitizer-memory +//@ revisions:MSAN-0 MSAN-1 MSAN-2 MSAN-1-LTO MSAN-2-LTO +// +//@ compile-flags: -Zsanitizer=memory -Ctarget-feature=-crt-static +//@[MSAN-0] compile-flags: +//@[MSAN-1] compile-flags: -Zsanitizer-memory-track-origins=1 +//@[MSAN-2] compile-flags: -Zsanitizer-memory-track-origins +//@[MSAN-1-LTO] compile-flags: -Zsanitizer-memory-track-origins=1 -C lto=fat +//@[MSAN-2-LTO] compile-flags: -Zsanitizer-memory-track-origins -C lto=fat + +#![crate_type = "lib"] + +// MSAN-0-NOT: @__msan_track_origins +// MSAN-1: @__msan_track_origins = weak_odr {{.*}}constant i32 1 +// MSAN-2: @__msan_track_origins = weak_odr {{.*}}constant i32 2 +// MSAN-1-LTO: @__msan_track_origins = weak_odr {{.*}}constant i32 1 +// MSAN-2-LTO: @__msan_track_origins = weak_odr {{.*}}constant i32 2 +// +// MSAN-0-LABEL: define void @copy( +// MSAN-1-LABEL: define void @copy( +// MSAN-2-LABEL: define void @copy( +#[no_mangle] +pub fn copy(dst: &mut i32, src: &i32) { + // MSAN-0-NOT: call i32 @__msan_chain_origin( + // MSAN-1-NOT: call i32 @__msan_chain_origin( + // MSAN-2: call i32 @__msan_chain_origin( + *dst = *src; +} diff --git a/tests/codegen-llvm/sanitizer/memtag-attr-check.rs b/tests/codegen-llvm/sanitizer/memtag-attr-check.rs new file mode 100644 index 00000000000..ffe3a2322a2 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/memtag-attr-check.rs @@ -0,0 +1,12 @@ +// This tests that the sanitize_memtag attribute is +// applied when enabling the memtag sanitizer. +// +//@ needs-sanitizer-memtag +//@ compile-flags: -Zsanitizer=memtag -Ctarget-feature=+mte -Copt-level=0 + +#![crate_type = "lib"] + +// CHECK: ; Function Attrs:{{.*}}sanitize_memtag +pub fn tagged() {} + +// CHECK: attributes #0 = {{.*}}sanitize_memtag diff --git a/tests/codegen-llvm/sanitizer/no-sanitize-inlining.rs b/tests/codegen-llvm/sanitizer/no-sanitize-inlining.rs new file mode 100644 index 00000000000..4bd832d2ab1 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/no-sanitize-inlining.rs @@ -0,0 +1,31 @@ +// Verifies that no_sanitize attribute prevents inlining when +// given sanitizer is enabled, but has no effect on inlining otherwise. +// +//@ needs-sanitizer-address +//@ needs-sanitizer-leak +//@ revisions: ASAN LSAN +//@ compile-flags: -Copt-level=3 -Zmir-opt-level=4 -Ctarget-feature=-crt-static +//@[ASAN] compile-flags: -Zsanitizer=address +//@[LSAN] compile-flags: -Zsanitizer=leak + +#![crate_type = "lib"] +#![feature(no_sanitize)] + +// ASAN-LABEL: define void @test +// ASAN: call {{.*}} @random_inline +// ASAN: } +// +// LSAN-LABEL: define void @test +// LSAN-NOT: call +// LSAN: } +#[no_mangle] +pub fn test(n: &mut u32) { + random_inline(n); +} + +#[no_sanitize(address)] +#[inline] +#[no_mangle] +pub fn random_inline(n: &mut u32) { + *n = 42; +} diff --git a/tests/codegen-llvm/sanitizer/no-sanitize.rs b/tests/codegen-llvm/sanitizer/no-sanitize.rs new file mode 100644 index 00000000000..2a309f6b9c6 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/no-sanitize.rs @@ -0,0 +1,39 @@ +// Verifies that no_sanitize attribute can be used to +// selectively disable sanitizer instrumentation. +// +//@ needs-sanitizer-address +//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static -Copt-level=0 + +#![crate_type = "lib"] +#![feature(no_sanitize)] + +// CHECK: @UNSANITIZED = constant{{.*}} no_sanitize_address +// CHECK-NOT: @__asan_global_UNSANITIZED +#[no_mangle] +#[no_sanitize(address)] +pub static UNSANITIZED: u32 = 0; + +// CHECK: @__asan_global_SANITIZED +#[no_mangle] +pub static SANITIZED: u32 = 0; + +// CHECK-LABEL: ; no_sanitize::unsanitized +// CHECK-NEXT: ; Function Attrs: +// CHECK-NOT: sanitize_address +// CHECK: start: +// CHECK-NOT: call void @__asan_report_load +// CHECK: } +#[no_sanitize(address)] +pub fn unsanitized(b: &mut u8) -> u8 { + *b +} + +// CHECK-LABEL: ; no_sanitize::sanitized +// CHECK-NEXT: ; Function Attrs: +// CHECK: sanitize_address +// CHECK: start: +// CHECK: call void @__asan_report_load +// CHECK: } +pub fn sanitized(b: &mut u8) -> u8 { + *b +} diff --git a/tests/codegen-llvm/sanitizer/riscv64-shadow-call-stack.rs b/tests/codegen-llvm/sanitizer/riscv64-shadow-call-stack.rs new file mode 100644 index 00000000000..945e46218d0 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/riscv64-shadow-call-stack.rs @@ -0,0 +1,18 @@ +//@ add-core-stubs +//@ compile-flags: --target riscv64imac-unknown-none-elf -Zsanitizer=shadow-call-stack +//@ needs-llvm-components: riscv + +#![allow(internal_features)] +#![crate_type = "rlib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK: ; Function Attrs:{{.*}}shadowcallstack +// CHECK: define dso_local void @foo() unnamed_addr #0 +#[no_mangle] +pub fn foo() {} + +// CHECK: attributes #0 = {{.*}}shadowcallstack{{.*}} diff --git a/tests/codegen-llvm/sanitizer/safestack-attr-check.rs b/tests/codegen-llvm/sanitizer/safestack-attr-check.rs new file mode 100644 index 00000000000..050a60333af --- /dev/null +++ b/tests/codegen-llvm/sanitizer/safestack-attr-check.rs @@ -0,0 +1,11 @@ +// This tests that the safestack attribute is applied when enabling the safe-stack sanitizer. +// +//@ needs-sanitizer-safestack +//@ compile-flags: -Zsanitizer=safestack -Copt-level=0 + +#![crate_type = "lib"] + +// CHECK: ; Function Attrs:{{.*}}safestack +pub fn tagged() {} + +// CHECK: attributes #0 = {{.*}}safestack diff --git a/tests/codegen-llvm/sanitizer/sanitizer-recover.rs b/tests/codegen-llvm/sanitizer/sanitizer-recover.rs new file mode 100644 index 00000000000..6b659320481 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/sanitizer-recover.rs @@ -0,0 +1,50 @@ +// Verifies that AddressSanitizer and MemorySanitizer +// recovery mode can be enabled with -Zsanitizer-recover. +// +//@ needs-sanitizer-address +//@ needs-sanitizer-memory +//@ revisions:ASAN ASAN-RECOVER MSAN MSAN-RECOVER MSAN-RECOVER-LTO +//@ no-prefer-dynamic +// +//@ compile-flags: -Ctarget-feature=-crt-static +//@[ASAN] compile-flags: -Zsanitizer=address -Copt-level=0 +//@[ASAN-RECOVER] compile-flags: -Zsanitizer=address -Zsanitizer-recover=address -Copt-level=0 +//@[MSAN] compile-flags: -Zsanitizer=memory +//@[MSAN-RECOVER] compile-flags: -Zsanitizer=memory -Zsanitizer-recover=memory +//@[MSAN-RECOVER-LTO] compile-flags: -Zsanitizer=memory -Zsanitizer-recover=memory -C lto=fat +// +// MSAN-NOT: @__msan_keep_going +// MSAN-RECOVER: @__msan_keep_going = weak_odr {{.*}}constant i32 1 +// MSAN-RECOVER-LTO: @__msan_keep_going = weak_odr {{.*}}constant i32 1 + +// ASAN-LABEL: define dso_local i32 @penguin( +// ASAN: call void @__asan_report_load4(i64 %0) +// ASAN: unreachable +// ASAN: } +// +// ASAN-RECOVER-LABEL: define dso_local i32 @penguin( +// ASAN-RECOVER: call void @__asan_report_load4_noabort( +// ASAN-RECOVER-NOT: unreachable +// ASAN: } +// +// MSAN-LABEL: define dso_local noundef i32 @penguin( +// MSAN: call void @__msan_warning{{(_with_origin_noreturn\(i32 0\)|_noreturn\(\))}} +// MSAN: unreachable +// MSAN: } +// +// MSAN-RECOVER-LABEL: define dso_local noundef i32 @penguin( +// MSAN-RECOVER: call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}} +// MSAN-RECOVER-NOT: unreachable +// MSAN-RECOVER: } +// +// MSAN-RECOVER-LTO-LABEL: define dso_local noundef i32 @penguin( +// MSAN-RECOVER-LTO: call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}} +// MSAN-RECOVER-LTO-NOT: unreachable +// MSAN-RECOVER-LTO: } +// +#[no_mangle] +pub fn penguin(p: &mut i32) -> i32 { + *p +} + +fn main() {} diff --git a/tests/codegen-llvm/sanitizer/scs-attr-check.rs b/tests/codegen-llvm/sanitizer/scs-attr-check.rs new file mode 100644 index 00000000000..6f4cbc2c0a6 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/scs-attr-check.rs @@ -0,0 +1,17 @@ +// This tests that the shadowcallstack attribute is +// applied when enabling the shadow-call-stack sanitizer. +// +//@ needs-sanitizer-shadow-call-stack +//@ compile-flags: -Zsanitizer=shadow-call-stack + +#![crate_type = "lib"] +#![feature(no_sanitize)] + +// CHECK: ; sanitizer_scs_attr_check::scs +// CHECK-NEXT: ; Function Attrs:{{.*}}shadowcallstack +pub fn scs() {} + +// CHECK: ; sanitizer_scs_attr_check::no_scs +// CHECK-NOT: ; Function Attrs:{{.*}}shadowcallstack +#[no_sanitize(shadow_call_stack)] +pub fn no_scs() {} diff --git a/tests/codegen-llvm/scalar-pair-bool.rs b/tests/codegen-llvm/scalar-pair-bool.rs new file mode 100644 index 00000000000..def3b32f71a --- /dev/null +++ b/tests/codegen-llvm/scalar-pair-bool.rs @@ -0,0 +1,45 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK: define{{.*}}{ i1, i1 } @pair_bool_bool(i1 noundef zeroext %pair.0, i1 noundef zeroext %pair.1) +#[no_mangle] +pub fn pair_bool_bool(pair: (bool, bool)) -> (bool, bool) { + pair +} + +// CHECK: define{{.*}}{ i1, i32 } @pair_bool_i32(i1 noundef zeroext %pair.0, i32 noundef %pair.1) +#[no_mangle] +pub fn pair_bool_i32(pair: (bool, i32)) -> (bool, i32) { + pair +} + +// CHECK: define{{.*}}{ i32, i1 } @pair_i32_bool(i32 noundef %pair.0, i1 noundef zeroext %pair.1) +#[no_mangle] +pub fn pair_i32_bool(pair: (i32, bool)) -> (i32, bool) { + pair +} + +// CHECK: define{{.*}}{ i1, i1 } @pair_and_or(i1 noundef zeroext %_1.0, i1 noundef zeroext %_1.1) +#[no_mangle] +pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) { + // Make sure it can operate directly on the unpacked args + // (but it might not be using simple and/or instructions) + // CHECK-DAG: %_1.0 + // CHECK-DAG: %_1.1 + (a && b, a || b) +} + +// CHECK: define{{.*}}void @pair_branches(i1 noundef zeroext %_1.0, i1 noundef zeroext %_1.1) +#[no_mangle] +pub fn pair_branches((a, b): (bool, bool)) { + // Make sure it can branch directly on the unpacked bool args + // CHECK: br i1 %_1.0 + if a { + println!("Hello!"); + } + // CHECK: br i1 %_1.1 + if b { + println!("Goodbye!"); + } +} diff --git a/tests/codegen-llvm/set-discriminant-invalid.rs b/tests/codegen-llvm/set-discriminant-invalid.rs new file mode 100644 index 00000000000..dd584ef1c14 --- /dev/null +++ b/tests/codegen-llvm/set-discriminant-invalid.rs @@ -0,0 +1,34 @@ +//@ compile-flags: -C opt-level=0 +#![crate_type = "lib"] + +pub enum ApiError {} +#[allow(dead_code)] +pub struct TokioError { + b: bool, +} +pub enum Error { + Api { source: ApiError }, + Ethereum, + Tokio { source: TokioError }, +} +struct Api; +impl IntoError for Api { + type Source = ApiError; + // CHECK-LABEL: @into_error + // CHECK: llvm.trap() + // Also check the next instruction to make sure we do not match against `trap` + // elsewhere in the code. + // CHECK-NEXT: ret i8 poison + #[no_mangle] + fn into_error(self, error: Self::Source) -> Error { + Error::Api { source: error } + } +} + +pub trait IntoError { + /// The underlying error + type Source; + + /// Combine the information to produce the error + fn into_error(self, source: Self::Source) -> E; +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-abs.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-abs.rs new file mode 100644 index 00000000000..baf445d0a1b --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-abs.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_fabs; + +// CHECK-LABEL: @fabs_32x2 +#[no_mangle] +pub unsafe fn fabs_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.fabs.v2f32 + simd_fabs(a) +} + +// CHECK-LABEL: @fabs_32x4 +#[no_mangle] +pub unsafe fn fabs_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.fabs.v4f32 + simd_fabs(a) +} + +// CHECK-LABEL: @fabs_32x8 +#[no_mangle] +pub unsafe fn fabs_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.fabs.v8f32 + simd_fabs(a) +} + +// CHECK-LABEL: @fabs_32x16 +#[no_mangle] +pub unsafe fn fabs_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.fabs.v16f32 + simd_fabs(a) +} + +// CHECK-LABEL: @fabs_64x4 +#[no_mangle] +pub unsafe fn fabs_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.fabs.v4f64 + simd_fabs(a) +} + +// CHECK-LABEL: @fabs_64x2 +#[no_mangle] +pub unsafe fn fabs_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.fabs.v2f64 + simd_fabs(a) +} + +// CHECK-LABEL: @fabs_64x8 +#[no_mangle] +pub unsafe fn fabs_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.fabs.v8f64 + simd_fabs(a) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-ceil.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-ceil.rs new file mode 100644 index 00000000000..096de569274 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-ceil.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_ceil; + +// CHECK-LABEL: @ceil_32x2 +#[no_mangle] +pub unsafe fn ceil_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.ceil.v2f32 + simd_ceil(a) +} + +// CHECK-LABEL: @ceil_32x4 +#[no_mangle] +pub unsafe fn ceil_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.ceil.v4f32 + simd_ceil(a) +} + +// CHECK-LABEL: @ceil_32x8 +#[no_mangle] +pub unsafe fn ceil_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.ceil.v8f32 + simd_ceil(a) +} + +// CHECK-LABEL: @ceil_32x16 +#[no_mangle] +pub unsafe fn ceil_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.ceil.v16f32 + simd_ceil(a) +} + +// CHECK-LABEL: @ceil_64x4 +#[no_mangle] +pub unsafe fn ceil_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.ceil.v4f64 + simd_ceil(a) +} + +// CHECK-LABEL: @ceil_64x2 +#[no_mangle] +pub unsafe fn ceil_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.ceil.v2f64 + simd_ceil(a) +} + +// CHECK-LABEL: @ceil_64x8 +#[no_mangle] +pub unsafe fn ceil_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.ceil.v8f64 + simd_ceil(a) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-cos.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-cos.rs new file mode 100644 index 00000000000..5b2197924bc --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-cos.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_fcos; + +// CHECK-LABEL: @fcos_32x2 +#[no_mangle] +pub unsafe fn fcos_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.cos.v2f32 + simd_fcos(a) +} + +// CHECK-LABEL: @fcos_32x4 +#[no_mangle] +pub unsafe fn fcos_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.cos.v4f32 + simd_fcos(a) +} + +// CHECK-LABEL: @fcos_32x8 +#[no_mangle] +pub unsafe fn fcos_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.cos.v8f32 + simd_fcos(a) +} + +// CHECK-LABEL: @fcos_32x16 +#[no_mangle] +pub unsafe fn fcos_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.cos.v16f32 + simd_fcos(a) +} + +// CHECK-LABEL: @fcos_64x4 +#[no_mangle] +pub unsafe fn fcos_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.cos.v4f64 + simd_fcos(a) +} + +// CHECK-LABEL: @fcos_64x2 +#[no_mangle] +pub unsafe fn fcos_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.cos.v2f64 + simd_fcos(a) +} + +// CHECK-LABEL: @fcos_64x8 +#[no_mangle] +pub unsafe fn fcos_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.cos.v8f64 + simd_fcos(a) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp.rs new file mode 100644 index 00000000000..d4eadb36c65 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_fexp; + +// CHECK-LABEL: @exp_32x2 +#[no_mangle] +pub unsafe fn exp_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.exp.v2f32 + simd_fexp(a) +} + +// CHECK-LABEL: @exp_32x4 +#[no_mangle] +pub unsafe fn exp_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.exp.v4f32 + simd_fexp(a) +} + +// CHECK-LABEL: @exp_32x8 +#[no_mangle] +pub unsafe fn exp_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.exp.v8f32 + simd_fexp(a) +} + +// CHECK-LABEL: @exp_32x16 +#[no_mangle] +pub unsafe fn exp_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.exp.v16f32 + simd_fexp(a) +} + +// CHECK-LABEL: @exp_64x4 +#[no_mangle] +pub unsafe fn exp_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.exp.v4f64 + simd_fexp(a) +} + +// CHECK-LABEL: @exp_64x2 +#[no_mangle] +pub unsafe fn exp_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.exp.v2f64 + simd_fexp(a) +} + +// CHECK-LABEL: @exp_64x8 +#[no_mangle] +pub unsafe fn exp_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.exp.v8f64 + simd_fexp(a) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp2.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp2.rs new file mode 100644 index 00000000000..d32015b7990 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-exp2.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_fexp2; + +// CHECK-LABEL: @exp2_32x2 +#[no_mangle] +pub unsafe fn exp2_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.exp2.v2f32 + simd_fexp2(a) +} + +// CHECK-LABEL: @exp2_32x4 +#[no_mangle] +pub unsafe fn exp2_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.exp2.v4f32 + simd_fexp2(a) +} + +// CHECK-LABEL: @exp2_32x8 +#[no_mangle] +pub unsafe fn exp2_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.exp2.v8f32 + simd_fexp2(a) +} + +// CHECK-LABEL: @exp2_32x16 +#[no_mangle] +pub unsafe fn exp2_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.exp2.v16f32 + simd_fexp2(a) +} + +// CHECK-LABEL: @exp2_64x4 +#[no_mangle] +pub unsafe fn exp2_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.exp2.v4f64 + simd_fexp2(a) +} + +// CHECK-LABEL: @exp2_64x2 +#[no_mangle] +pub unsafe fn exp2_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.exp2.v2f64 + simd_fexp2(a) +} + +// CHECK-LABEL: @exp2_64x8 +#[no_mangle] +pub unsafe fn exp2_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.exp2.v8f64 + simd_fexp2(a) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-floor.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-floor.rs new file mode 100644 index 00000000000..1e1c8ce0c35 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-floor.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_floor; + +// CHECK-LABEL: @floor_32x2 +#[no_mangle] +pub unsafe fn floor_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.floor.v2f32 + simd_floor(a) +} + +// CHECK-LABEL: @floor_32x4 +#[no_mangle] +pub unsafe fn floor_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.floor.v4f32 + simd_floor(a) +} + +// CHECK-LABEL: @floor_32x8 +#[no_mangle] +pub unsafe fn floor_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.floor.v8f32 + simd_floor(a) +} + +// CHECK-LABEL: @floor_32x16 +#[no_mangle] +pub unsafe fn floor_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.floor.v16f32 + simd_floor(a) +} + +// CHECK-LABEL: @floor_64x4 +#[no_mangle] +pub unsafe fn floor_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.floor.v4f64 + simd_floor(a) +} + +// CHECK-LABEL: @floor_64x2 +#[no_mangle] +pub unsafe fn floor_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.floor.v2f64 + simd_floor(a) +} + +// CHECK-LABEL: @floor_64x8 +#[no_mangle] +pub unsafe fn floor_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.floor.v8f64 + simd_floor(a) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fma.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fma.rs new file mode 100644 index 00000000000..982077d81f9 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fma.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_fma; + +// CHECK-LABEL: @fma_32x2 +#[no_mangle] +pub unsafe fn fma_32x2(a: f32x2, b: f32x2, c: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.fma.v2f32 + simd_fma(a, b, c) +} + +// CHECK-LABEL: @fma_32x4 +#[no_mangle] +pub unsafe fn fma_32x4(a: f32x4, b: f32x4, c: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.fma.v4f32 + simd_fma(a, b, c) +} + +// CHECK-LABEL: @fma_32x8 +#[no_mangle] +pub unsafe fn fma_32x8(a: f32x8, b: f32x8, c: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.fma.v8f32 + simd_fma(a, b, c) +} + +// CHECK-LABEL: @fma_32x16 +#[no_mangle] +pub unsafe fn fma_32x16(a: f32x16, b: f32x16, c: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.fma.v16f32 + simd_fma(a, b, c) +} + +// CHECK-LABEL: @fma_64x4 +#[no_mangle] +pub unsafe fn fma_64x4(a: f64x4, b: f64x4, c: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.fma.v4f64 + simd_fma(a, b, c) +} + +// CHECK-LABEL: @fma_64x2 +#[no_mangle] +pub unsafe fn fma_64x2(a: f64x2, b: f64x2, c: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.fma.v2f64 + simd_fma(a, b, c) +} + +// CHECK-LABEL: @fma_64x8 +#[no_mangle] +pub unsafe fn fma_64x8(a: f64x8, b: f64x8, c: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.fma.v8f64 + simd_fma(a, b, c) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fsqrt.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fsqrt.rs new file mode 100644 index 00000000000..e20a591f573 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-fsqrt.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_fsqrt; + +// CHECK-LABEL: @fsqrt_32x2 +#[no_mangle] +pub unsafe fn fsqrt_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.sqrt.v2f32 + simd_fsqrt(a) +} + +// CHECK-LABEL: @fsqrt_32x4 +#[no_mangle] +pub unsafe fn fsqrt_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.sqrt.v4f32 + simd_fsqrt(a) +} + +// CHECK-LABEL: @fsqrt_32x8 +#[no_mangle] +pub unsafe fn fsqrt_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.sqrt.v8f32 + simd_fsqrt(a) +} + +// CHECK-LABEL: @fsqrt_32x16 +#[no_mangle] +pub unsafe fn fsqrt_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.sqrt.v16f32 + simd_fsqrt(a) +} + +// CHECK-LABEL: @fsqrt_64x4 +#[no_mangle] +pub unsafe fn fsqrt_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.sqrt.v4f64 + simd_fsqrt(a) +} + +// CHECK-LABEL: @fsqrt_64x2 +#[no_mangle] +pub unsafe fn fsqrt_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.sqrt.v2f64 + simd_fsqrt(a) +} + +// CHECK-LABEL: @fsqrt_64x8 +#[no_mangle] +pub unsafe fn fsqrt_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.sqrt.v8f64 + simd_fsqrt(a) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log.rs new file mode 100644 index 00000000000..bf1ffc76330 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_flog; + +// CHECK-LABEL: @log_32x2 +#[no_mangle] +pub unsafe fn log_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.log.v2f32 + simd_flog(a) +} + +// CHECK-LABEL: @log_32x4 +#[no_mangle] +pub unsafe fn log_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.log.v4f32 + simd_flog(a) +} + +// CHECK-LABEL: @log_32x8 +#[no_mangle] +pub unsafe fn log_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.log.v8f32 + simd_flog(a) +} + +// CHECK-LABEL: @log_32x16 +#[no_mangle] +pub unsafe fn log_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.log.v16f32 + simd_flog(a) +} + +// CHECK-LABEL: @log_64x4 +#[no_mangle] +pub unsafe fn log_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.log.v4f64 + simd_flog(a) +} + +// CHECK-LABEL: @log_64x2 +#[no_mangle] +pub unsafe fn log_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.log.v2f64 + simd_flog(a) +} + +// CHECK-LABEL: @log_64x8 +#[no_mangle] +pub unsafe fn log_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.log.v8f64 + simd_flog(a) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log10.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log10.rs new file mode 100644 index 00000000000..ccf484e0e41 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log10.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_flog10; + +// CHECK-LABEL: @log10_32x2 +#[no_mangle] +pub unsafe fn log10_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.log10.v2f32 + simd_flog10(a) +} + +// CHECK-LABEL: @log10_32x4 +#[no_mangle] +pub unsafe fn log10_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.log10.v4f32 + simd_flog10(a) +} + +// CHECK-LABEL: @log10_32x8 +#[no_mangle] +pub unsafe fn log10_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.log10.v8f32 + simd_flog10(a) +} + +// CHECK-LABEL: @log10_32x16 +#[no_mangle] +pub unsafe fn log10_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.log10.v16f32 + simd_flog10(a) +} + +// CHECK-LABEL: @log10_64x4 +#[no_mangle] +pub unsafe fn log10_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.log10.v4f64 + simd_flog10(a) +} + +// CHECK-LABEL: @log10_64x2 +#[no_mangle] +pub unsafe fn log10_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.log10.v2f64 + simd_flog10(a) +} + +// CHECK-LABEL: @log10_64x8 +#[no_mangle] +pub unsafe fn log10_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.log10.v8f64 + simd_flog10(a) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log2.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log2.rs new file mode 100644 index 00000000000..677d8b01e84 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-log2.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_flog2; + +// CHECK-LABEL: @log2_32x2 +#[no_mangle] +pub unsafe fn log2_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.log2.v2f32 + simd_flog2(a) +} + +// CHECK-LABEL: @log2_32x4 +#[no_mangle] +pub unsafe fn log2_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.log2.v4f32 + simd_flog2(a) +} + +// CHECK-LABEL: @log2_32x8 +#[no_mangle] +pub unsafe fn log2_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.log2.v8f32 + simd_flog2(a) +} + +// CHECK-LABEL: @log2_32x16 +#[no_mangle] +pub unsafe fn log2_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.log2.v16f32 + simd_flog2(a) +} + +// CHECK-LABEL: @log2_64x4 +#[no_mangle] +pub unsafe fn log2_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.log2.v4f64 + simd_flog2(a) +} + +// CHECK-LABEL: @log2_64x2 +#[no_mangle] +pub unsafe fn log2_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.log2.v2f64 + simd_flog2(a) +} + +// CHECK-LABEL: @log2_64x8 +#[no_mangle] +pub unsafe fn log2_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.log2.v8f64 + simd_flog2(a) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-minmax.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-minmax.rs new file mode 100644 index 00000000000..8dd464a1bff --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-minmax.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::{simd_fmax, simd_fmin}; + +// CHECK-LABEL: @fmin +#[no_mangle] +pub unsafe fn fmin(a: f32x4, b: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.minnum.v4f32 + simd_fmin(a, b) +} + +// CHECK-LABEL: @fmax +#[no_mangle] +pub unsafe fn fmax(a: f32x4, b: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.maxnum.v4f32 + simd_fmax(a, b) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-sin.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-sin.rs new file mode 100644 index 00000000000..48becc72c0b --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-sin.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_fsin; + +// CHECK-LABEL: @fsin_32x2 +#[no_mangle] +pub unsafe fn fsin_32x2(a: f32x2) -> f32x2 { + // CHECK: call <2 x float> @llvm.sin.v2f32 + simd_fsin(a) +} + +// CHECK-LABEL: @fsin_32x4 +#[no_mangle] +pub unsafe fn fsin_32x4(a: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.sin.v4f32 + simd_fsin(a) +} + +// CHECK-LABEL: @fsin_32x8 +#[no_mangle] +pub unsafe fn fsin_32x8(a: f32x8) -> f32x8 { + // CHECK: call <8 x float> @llvm.sin.v8f32 + simd_fsin(a) +} + +// CHECK-LABEL: @fsin_32x16 +#[no_mangle] +pub unsafe fn fsin_32x16(a: f32x16) -> f32x16 { + // CHECK: call <16 x float> @llvm.sin.v16f32 + simd_fsin(a) +} + +// CHECK-LABEL: @fsin_64x4 +#[no_mangle] +pub unsafe fn fsin_64x4(a: f64x4) -> f64x4 { + // CHECK: call <4 x double> @llvm.sin.v4f64 + simd_fsin(a) +} + +// CHECK-LABEL: @fsin_64x2 +#[no_mangle] +pub unsafe fn fsin_64x2(a: f64x2) -> f64x2 { + // CHECK: call <2 x double> @llvm.sin.v2f64 + simd_fsin(a) +} + +// CHECK-LABEL: @fsin_64x8 +#[no_mangle] +pub unsafe fn fsin_64x8(a: f64x8) -> f64x8 { + // CHECK: call <8 x double> @llvm.sin.v8f64 + simd_fsin(a) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs new file mode 100644 index 00000000000..06d46889715 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs @@ -0,0 +1,579 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] +#![deny(unused)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub}; + +// NOTE(eddyb) `%{{x|0}}` is used because on some targets (e.g. WASM) +// SIMD vectors are passed directly, resulting in `%x` being a vector, +// while on others they're passed indirectly, resulting in `%x` being +// a pointer to a vector, and `%0` a vector loaded from that pointer. +// This is controlled by the target spec option `simd_types_indirect`. +// The same applies to `%{{y|1}}` as well. + +// CHECK-LABEL: @sadd_i8x2 +#[no_mangle] +pub unsafe fn sadd_i8x2(x: i8x2, y: i8x2) -> i8x2 { + // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i8x4 +#[no_mangle] +pub unsafe fn sadd_i8x4(x: i8x4, y: i8x4) -> i8x4 { + // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i8x8 +#[no_mangle] +pub unsafe fn sadd_i8x8(x: i8x8, y: i8x8) -> i8x8 { + // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.sadd.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i8x16 +#[no_mangle] +pub unsafe fn sadd_i8x16(x: i8x16, y: i8x16) -> i8x16 { + // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.sadd.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i8x32 +#[no_mangle] +pub unsafe fn sadd_i8x32(x: i8x32, y: i8x32) -> i8x32 { + // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.sadd.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i8x64 +#[no_mangle] +pub unsafe fn sadd_i8x64(x: i8x64, y: i8x64) -> i8x64 { + // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.sadd.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i16x2 +#[no_mangle] +pub unsafe fn sadd_i16x2(x: i16x2, y: i16x2) -> i16x2 { + // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i16x4 +#[no_mangle] +pub unsafe fn sadd_i16x4(x: i16x4, y: i16x4) -> i16x4 { + // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i16x8 +#[no_mangle] +pub unsafe fn sadd_i16x8(x: i16x8, y: i16x8) -> i16x8 { + // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.sadd.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i16x16 +#[no_mangle] +pub unsafe fn sadd_i16x16(x: i16x16, y: i16x16) -> i16x16 { + // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.sadd.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i16x32 +#[no_mangle] +pub unsafe fn sadd_i16x32(x: i16x32, y: i16x32) -> i16x32 { + // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.sadd.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i32x2 +#[no_mangle] +pub unsafe fn sadd_i32x2(x: i32x2, y: i32x2) -> i32x2 { + // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i32x4 +#[no_mangle] +pub unsafe fn sadd_i32x4(x: i32x4, y: i32x4) -> i32x4 { + // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i32x8 +#[no_mangle] +pub unsafe fn sadd_i32x8(x: i32x8, y: i32x8) -> i32x8 { + // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i32x16 +#[no_mangle] +pub unsafe fn sadd_i32x16(x: i32x16, y: i32x16) -> i32x16 { + // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.sadd.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i64x2 +#[no_mangle] +pub unsafe fn sadd_i64x2(x: i64x2, y: i64x2) -> i64x2 { + // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.sadd.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i64x4 +#[no_mangle] +pub unsafe fn sadd_i64x4(x: i64x4, y: i64x4) -> i64x4 { + // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.sadd.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i64x8 +#[no_mangle] +pub unsafe fn sadd_i64x8(x: i64x8, y: i64x8) -> i64x8 { + // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.sadd.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i128x2 +#[no_mangle] +pub unsafe fn sadd_i128x2(x: i128x2, y: i128x2) -> i128x2 { + // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.sadd.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @sadd_i128x4 +#[no_mangle] +pub unsafe fn sadd_i128x4(x: i128x4, y: i128x4) -> i128x4 { + // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.sadd.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u8x2 +#[no_mangle] +pub unsafe fn uadd_u8x2(x: u8x2, y: u8x2) -> u8x2 { + // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u8x4 +#[no_mangle] +pub unsafe fn uadd_u8x4(x: u8x4, y: u8x4) -> u8x4 { + // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u8x8 +#[no_mangle] +pub unsafe fn uadd_u8x8(x: u8x8, y: u8x8) -> u8x8 { + // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.uadd.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u8x16 +#[no_mangle] +pub unsafe fn uadd_u8x16(x: u8x16, y: u8x16) -> u8x16 { + // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u8x32 +#[no_mangle] +pub unsafe fn uadd_u8x32(x: u8x32, y: u8x32) -> u8x32 { + // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u8x64 +#[no_mangle] +pub unsafe fn uadd_u8x64(x: u8x64, y: u8x64) -> u8x64 { + // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u16x2 +#[no_mangle] +pub unsafe fn uadd_u16x2(x: u16x2, y: u16x2) -> u16x2 { + // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u16x4 +#[no_mangle] +pub unsafe fn uadd_u16x4(x: u16x4, y: u16x4) -> u16x4 { + // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.uadd.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u16x8 +#[no_mangle] +pub unsafe fn uadd_u16x8(x: u16x8, y: u16x8) -> u16x8 { + // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u16x16 +#[no_mangle] +pub unsafe fn uadd_u16x16(x: u16x16, y: u16x16) -> u16x16 { + // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u16x32 +#[no_mangle] +pub unsafe fn uadd_u16x32(x: u16x32, y: u16x32) -> u16x32 { + // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u32x2 +#[no_mangle] +pub unsafe fn uadd_u32x2(x: u32x2, y: u32x2) -> u32x2 { + // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.uadd.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u32x4 +#[no_mangle] +pub unsafe fn uadd_u32x4(x: u32x4, y: u32x4) -> u32x4 { + // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u32x8 +#[no_mangle] +pub unsafe fn uadd_u32x8(x: u32x8, y: u32x8) -> u32x8 { + // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u32x16 +#[no_mangle] +pub unsafe fn uadd_u32x16(x: u32x16, y: u32x16) -> u32x16 { + // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.uadd.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u64x2 +#[no_mangle] +pub unsafe fn uadd_u64x2(x: u64x2, y: u64x2) -> u64x2 { + // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.uadd.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u64x4 +#[no_mangle] +pub unsafe fn uadd_u64x4(x: u64x4, y: u64x4) -> u64x4 { + // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.uadd.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u64x8 +#[no_mangle] +pub unsafe fn uadd_u64x8(x: u64x8, y: u64x8) -> u64x8 { + // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.uadd.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u128x2 +#[no_mangle] +pub unsafe fn uadd_u128x2(x: u128x2, y: u128x2) -> u128x2 { + // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.uadd.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @uadd_u128x4 +#[no_mangle] +pub unsafe fn uadd_u128x4(x: u128x4, y: u128x4) -> u128x4 { + // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.uadd.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}}) + simd_saturating_add(x, y) +} + +// CHECK-LABEL: @ssub_i8x2 +#[no_mangle] +pub unsafe fn ssub_i8x2(x: i8x2, y: i8x2) -> i8x2 { + // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i8x4 +#[no_mangle] +pub unsafe fn ssub_i8x4(x: i8x4, y: i8x4) -> i8x4 { + // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i8x8 +#[no_mangle] +pub unsafe fn ssub_i8x8(x: i8x8, y: i8x8) -> i8x8 { + // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.ssub.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i8x16 +#[no_mangle] +pub unsafe fn ssub_i8x16(x: i8x16, y: i8x16) -> i8x16 { + // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i8x32 +#[no_mangle] +pub unsafe fn ssub_i8x32(x: i8x32, y: i8x32) -> i8x32 { + // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.ssub.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i8x64 +#[no_mangle] +pub unsafe fn ssub_i8x64(x: i8x64, y: i8x64) -> i8x64 { + // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.ssub.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i16x2 +#[no_mangle] +pub unsafe fn ssub_i16x2(x: i16x2, y: i16x2) -> i16x2 { + // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i16x4 +#[no_mangle] +pub unsafe fn ssub_i16x4(x: i16x4, y: i16x4) -> i16x4 { + // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.ssub.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i16x8 +#[no_mangle] +pub unsafe fn ssub_i16x8(x: i16x8, y: i16x8) -> i16x8 { + // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i16x16 +#[no_mangle] +pub unsafe fn ssub_i16x16(x: i16x16, y: i16x16) -> i16x16 { + // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.ssub.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i16x32 +#[no_mangle] +pub unsafe fn ssub_i16x32(x: i16x32, y: i16x32) -> i16x32 { + // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.ssub.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i32x2 +#[no_mangle] +pub unsafe fn ssub_i32x2(x: i32x2, y: i32x2) -> i32x2 { + // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.ssub.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i32x4 +#[no_mangle] +pub unsafe fn ssub_i32x4(x: i32x4, y: i32x4) -> i32x4 { + // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i32x8 +#[no_mangle] +pub unsafe fn ssub_i32x8(x: i32x8, y: i32x8) -> i32x8 { + // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i32x16 +#[no_mangle] +pub unsafe fn ssub_i32x16(x: i32x16, y: i32x16) -> i32x16 { + // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.ssub.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i64x2 +#[no_mangle] +pub unsafe fn ssub_i64x2(x: i64x2, y: i64x2) -> i64x2 { + // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.ssub.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i64x4 +#[no_mangle] +pub unsafe fn ssub_i64x4(x: i64x4, y: i64x4) -> i64x4 { + // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.ssub.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i64x8 +#[no_mangle] +pub unsafe fn ssub_i64x8(x: i64x8, y: i64x8) -> i64x8 { + // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.ssub.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i128x2 +#[no_mangle] +pub unsafe fn ssub_i128x2(x: i128x2, y: i128x2) -> i128x2 { + // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.ssub.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @ssub_i128x4 +#[no_mangle] +pub unsafe fn ssub_i128x4(x: i128x4, y: i128x4) -> i128x4 { + // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.ssub.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u8x2 +#[no_mangle] +pub unsafe fn usub_u8x2(x: u8x2, y: u8x2) -> u8x2 { + // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u8x4 +#[no_mangle] +pub unsafe fn usub_u8x4(x: u8x4, y: u8x4) -> u8x4 { + // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u8x8 +#[no_mangle] +pub unsafe fn usub_u8x8(x: u8x8, y: u8x8) -> u8x8 { + // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.usub.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u8x16 +#[no_mangle] +pub unsafe fn usub_u8x16(x: u8x16, y: u8x16) -> u8x16 { + // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u8x32 +#[no_mangle] +pub unsafe fn usub_u8x32(x: u8x32, y: u8x32) -> u8x32 { + // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u8x64 +#[no_mangle] +pub unsafe fn usub_u8x64(x: u8x64, y: u8x64) -> u8x64 { + // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u16x2 +#[no_mangle] +pub unsafe fn usub_u16x2(x: u16x2, y: u16x2) -> u16x2 { + // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u16x4 +#[no_mangle] +pub unsafe fn usub_u16x4(x: u16x4, y: u16x4) -> u16x4 { + // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.usub.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u16x8 +#[no_mangle] +pub unsafe fn usub_u16x8(x: u16x8, y: u16x8) -> u16x8 { + // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.usub.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u16x16 +#[no_mangle] +pub unsafe fn usub_u16x16(x: u16x16, y: u16x16) -> u16x16 { + // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u16x32 +#[no_mangle] +pub unsafe fn usub_u16x32(x: u16x32, y: u16x32) -> u16x32 { + // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u32x2 +#[no_mangle] +pub unsafe fn usub_u32x2(x: u32x2, y: u32x2) -> u32x2 { + // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.usub.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u32x4 +#[no_mangle] +pub unsafe fn usub_u32x4(x: u32x4, y: u32x4) -> u32x4 { + // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u32x8 +#[no_mangle] +pub unsafe fn usub_u32x8(x: u32x8, y: u32x8) -> u32x8 { + // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u32x16 +#[no_mangle] +pub unsafe fn usub_u32x16(x: u32x16, y: u32x16) -> u32x16 { + // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.usub.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u64x2 +#[no_mangle] +pub unsafe fn usub_u64x2(x: u64x2, y: u64x2) -> u64x2 { + // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u64x4 +#[no_mangle] +pub unsafe fn usub_u64x4(x: u64x4, y: u64x4) -> u64x4 { + // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.usub.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u64x8 +#[no_mangle] +pub unsafe fn usub_u64x8(x: u64x8, y: u64x8) -> u64x8 { + // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.usub.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u128x2 +#[no_mangle] +pub unsafe fn usub_u128x2(x: u128x2, y: u128x2) -> u128x2 { + // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.usub.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}}) + simd_saturating_sub(x, y) +} + +// CHECK-LABEL: @usub_u128x4 +#[no_mangle] +pub unsafe fn usub_u128x4(x: u128x4, y: u128x4) -> u128x4 { + // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.usub.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}}) + simd_saturating_sub(x, y) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-bitmask.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-bitmask.rs new file mode 100644 index 00000000000..294262d8152 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-bitmask.rs @@ -0,0 +1,48 @@ +//@ compile-flags: -C no-prepopulate-passes +// + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_bitmask; + +// NOTE(eddyb) `%{{x|1}}` is used because on some targets (e.g. WASM) +// SIMD vectors are passed directly, resulting in `%x` being a vector, +// while on others they're passed indirectly, resulting in `%x` being +// a pointer to a vector, and `%1` a vector loaded from that pointer. +// This is controlled by the target spec option `simd_types_indirect`. + +// CHECK-LABEL: @bitmask_int +#[no_mangle] +pub unsafe fn bitmask_int(x: i32x2) -> u8 { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2 + // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8 + simd_bitmask(x) +} + +// CHECK-LABEL: @bitmask_uint +#[no_mangle] +pub unsafe fn bitmask_uint(x: u32x2) -> u8 { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2 + // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8 + simd_bitmask(x) +} + +// CHECK-LABEL: @bitmask_int16 +#[no_mangle] +pub unsafe fn bitmask_int16(x: i8x16) -> u16 { + // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1|2}}, {{|splat \(i8 7\)}} + // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1> + // CHECK: %{{[0-9]+}} = bitcast <16 x i1> [[B]] to i16 + // CHECK-NOT: zext + simd_bitmask(x) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-gather.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-gather.rs new file mode 100644 index 00000000000..690bfb432f9 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-gather.rs @@ -0,0 +1,55 @@ +// + +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_gather; + +pub type Vec2 = Simd; +pub type Vec4 = Simd; + +// CHECK-LABEL: @gather_f32x2 +#[no_mangle] +pub unsafe fn gather_f32x2( + pointers: Vec2<*const f32>, + mask: Vec2, + values: Vec2, +) -> Vec2 { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: call <2 x float> @llvm.masked.gather.v2f32.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]], <2 x float> {{.*}}) + simd_gather(values, pointers, mask) +} + +// CHECK-LABEL: @gather_f32x2_unsigned +#[no_mangle] +pub unsafe fn gather_f32x2_unsigned( + pointers: Vec2<*const f32>, + mask: Vec2, + values: Vec2, +) -> Vec2 { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: call <2 x float> @llvm.masked.gather.v2f32.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]], <2 x float> {{.*}}) + simd_gather(values, pointers, mask) +} + +// CHECK-LABEL: @gather_pf32x2 +#[no_mangle] +pub unsafe fn gather_pf32x2( + pointers: Vec2<*const *const f32>, + mask: Vec2, + values: Vec2<*const f32>, +) -> Vec2<*const f32> { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: call <2 x ptr> @llvm.masked.gather.v2p0.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]], <2 x ptr> {{.*}}) + simd_gather(values, pointers, mask) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-load.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-load.rs new file mode 100644 index 00000000000..fda315dc66c --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-load.rs @@ -0,0 +1,49 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_masked_load; + +pub type Vec2 = Simd; +pub type Vec4 = Simd; + +// CHECK-LABEL: @load_f32x2 +#[no_mangle] +pub unsafe fn load_f32x2(mask: Vec2, pointer: *const f32, values: Vec2) -> Vec2 { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: call <2 x float> @llvm.masked.load.v2f32.p0(ptr {{.*}}, i32 4, <2 x i1> [[B]], <2 x float> {{.*}}) + simd_masked_load(mask, pointer, values) +} + +// CHECK-LABEL: @load_f32x2_unsigned +#[no_mangle] +pub unsafe fn load_f32x2_unsigned( + mask: Vec2, + pointer: *const f32, + values: Vec2, +) -> Vec2 { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: call <2 x float> @llvm.masked.load.v2f32.p0(ptr {{.*}}, i32 4, <2 x i1> [[B]], <2 x float> {{.*}}) + simd_masked_load(mask, pointer, values) +} + +// CHECK-LABEL: @load_pf32x4 +#[no_mangle] +pub unsafe fn load_pf32x4( + mask: Vec4, + pointer: *const *const f32, + values: Vec4<*const f32>, +) -> Vec4<*const f32> { + // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1> + // CHECK: call <4 x ptr> @llvm.masked.load.v4p0.p0(ptr {{.*}}, i32 {{.*}}, <4 x i1> [[B]], <4 x ptr> {{.*}}) + simd_masked_load(mask, pointer, values) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-store.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-store.rs new file mode 100644 index 00000000000..6ca7388d464 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-masked-store.rs @@ -0,0 +1,41 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_masked_store; + +pub type Vec2 = Simd; +pub type Vec4 = Simd; + +// CHECK-LABEL: @store_f32x2 +#[no_mangle] +pub unsafe fn store_f32x2(mask: Vec2, pointer: *mut f32, values: Vec2) { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr {{.*}}, i32 4, <2 x i1> [[B]]) + simd_masked_store(mask, pointer, values) +} + +// CHECK-LABEL: @store_f32x2_unsigned +#[no_mangle] +pub unsafe fn store_f32x2_unsigned(mask: Vec2, pointer: *mut f32, values: Vec2) { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr {{.*}}, i32 4, <2 x i1> [[B]]) + simd_masked_store(mask, pointer, values) +} + +// CHECK-LABEL: @store_pf32x4 +#[no_mangle] +pub unsafe fn store_pf32x4(mask: Vec4, pointer: *mut *const f32, values: Vec4<*const f32>) { + // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1> + // CHECK: call void @llvm.masked.store.v4p0.p0(<4 x ptr> {{.*}}, ptr {{.*}}, i32 {{.*}}, <4 x i1> [[B]]) + simd_masked_store(mask, pointer, values) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-scatter.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-scatter.rs new file mode 100644 index 00000000000..743652966e1 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-scatter.rs @@ -0,0 +1,47 @@ +// + +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::simd_scatter; + +pub type Vec2 = Simd; +pub type Vec4 = Simd; + +// CHECK-LABEL: @scatter_f32x2 +#[no_mangle] +pub unsafe fn scatter_f32x2(pointers: Vec2<*mut f32>, mask: Vec2, values: Vec2) { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: call void @llvm.masked.scatter.v2f32.v2p0(<2 x float> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]] + simd_scatter(values, pointers, mask) +} + +// CHECK-LABEL: @scatter_f32x2_unsigned +#[no_mangle] +pub unsafe fn scatter_f32x2_unsigned(pointers: Vec2<*mut f32>, mask: Vec2, values: Vec2) { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: call void @llvm.masked.scatter.v2f32.v2p0(<2 x float> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]] + simd_scatter(values, pointers, mask) +} + +// CHECK-LABEL: @scatter_pf32x2 +#[no_mangle] +pub unsafe fn scatter_pf32x2( + pointers: Vec2<*mut *const f32>, + mask: Vec2, + values: Vec2<*const f32>, +) { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: call void @llvm.masked.scatter.v2p0.v2p0(<2 x ptr> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]] + simd_scatter(values, pointers, mask) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-select.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-select.rs new file mode 100644 index 00000000000..2c0bad21f44 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-generic-select.rs @@ -0,0 +1,48 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::{simd_select, simd_select_bitmask}; + +pub type b8x4 = i8x4; + +// CHECK-LABEL: @select_m8 +#[no_mangle] +pub unsafe fn select_m8(m: b8x4, a: f32x4, b: f32x4) -> f32x4 { + // CHECK: [[A:%[0-9]+]] = lshr <4 x i8> %{{.*}}, {{|splat \(i8 7\)}} + // CHECK: [[B:%[0-9]+]] = trunc <4 x i8> [[A]] to <4 x i1> + // CHECK: select <4 x i1> [[B]] + simd_select(m, a, b) +} + +// CHECK-LABEL: @select_m32 +#[no_mangle] +pub unsafe fn select_m32(m: i32x4, a: f32x4, b: f32x4) -> f32x4 { + // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> %{{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1> + // CHECK: select <4 x i1> [[B]] + simd_select(m, a, b) +} + +// CHECK-LABEL: @select_m32_unsigned +#[no_mangle] +pub unsafe fn select_m32_unsigned(m: u32x4, a: f32x4, b: f32x4) -> f32x4 { + // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> %{{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1> + // CHECK: select <4 x i1> [[B]] + simd_select(m, a, b) +} + +// CHECK-LABEL: @select_bitmask +#[no_mangle] +pub unsafe fn select_bitmask(m: i8, a: f32x8, b: f32x8) -> f32x8 { + // CHECK: [[A:%[0-9]+]] = bitcast i8 {{.*}} to <8 x i1> + // CHECK: select <8 x i1> [[A]] + simd_select_bitmask(m, a, b) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-mask-reduce.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-mask-reduce.rs new file mode 100644 index 00000000000..79f00a6ed60 --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-mask-reduce.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +#![allow(non_camel_case_types)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +use std::intrinsics::simd::{simd_reduce_all, simd_reduce_any}; + +pub type mask32x2 = Simd; +pub type mask8x16 = Simd; + +// NOTE(eddyb) `%{{x|1}}` is used because on some targets (e.g. WASM) +// SIMD vectors are passed directly, resulting in `%x` being a vector, +// while on others they're passed indirectly, resulting in `%x` being +// a pointer to a vector, and `%1` a vector loaded from that pointer. +// This is controlled by the target spec option `simd_types_indirect`. + +// CHECK-LABEL: @reduce_any_32x2 +#[no_mangle] +pub unsafe fn reduce_any_32x2(x: mask32x2) -> bool { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.or.v2i1(<2 x i1> [[B]]) + // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8 + simd_reduce_any(x) +} + +// CHECK-LABEL: @reduce_all_32x2 +#[no_mangle] +pub unsafe fn reduce_all_32x2(x: mask32x2) -> bool { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.and.v2i1(<2 x i1> [[B]]) + // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8 + simd_reduce_all(x) +} + +// CHECK-LABEL: @reduce_any_8x16 +#[no_mangle] +pub unsafe fn reduce_any_8x16(x: mask8x16) -> bool { + // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1}}, {{|splat \(i8 7\)}} + // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1> + // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.or.v16i1(<16 x i1> [[B]]) + // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8 + simd_reduce_any(x) +} + +// CHECK-LABEL: @reduce_all_8x16 +#[no_mangle] +pub unsafe fn reduce_all_8x16(x: mask8x16) -> bool { + // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1}}, {{|splat \(i8 7\)}} + // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1> + // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.and.v16i1(<16 x i1> [[B]]) + // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8 + simd_reduce_all(x) +} diff --git a/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-transmute-array.rs new file mode 100644 index 00000000000..05c2f7e1bdf --- /dev/null +++ b/tests/codegen-llvm/simd-intrinsic/simd-intrinsic-transmute-array.rs @@ -0,0 +1,58 @@ +// +//@ compile-flags: -C no-prepopulate-passes +// 32bit MSVC does not align things properly so we suppress high alignment annotations (#112480) +//@ ignore-i686-pc-windows-msvc +//@ ignore-i686-pc-windows-gnu + +#![crate_type = "lib"] +#![allow(non_camel_case_types)] +#![feature(repr_simd, core_intrinsics)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::*; + +pub type S = Simd; +pub type T = Simd; + +// CHECK-LABEL: @array_align( +#[no_mangle] +pub fn array_align() -> usize { + // CHECK: ret [[USIZE:i[0-9]+]] [[ARRAY_ALIGN:[0-9]+]] + const { std::mem::align_of::() } +} + +// CHECK-LABEL: @vector_align( +#[no_mangle] +pub fn vector_align() -> usize { + // CHECK: ret [[USIZE]] [[VECTOR_ALIGN:[0-9]+]] + const { std::mem::align_of::() } +} + +// CHECK-LABEL: @build_array_s +#[no_mangle] +pub fn build_array_s(x: [f32; 4]) -> S<4> { + // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) + Simd(x) +} + +// CHECK-LABEL: @build_array_transmute_s +#[no_mangle] +pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> { + // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) + unsafe { std::mem::transmute(x) } +} + +// CHECK-LABEL: @build_array_t +#[no_mangle] +pub fn build_array_t(x: [f32; 4]) -> T { + // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) + Simd(x) +} + +// CHECK-LABEL: @build_array_transmute_t +#[no_mangle] +pub fn build_array_transmute_t(x: [f32; 4]) -> T { + // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) + unsafe { std::mem::transmute(x) } +} diff --git a/tests/codegen-llvm/simd/aggregate-simd.rs b/tests/codegen-llvm/simd/aggregate-simd.rs new file mode 100644 index 00000000000..57a301d634c --- /dev/null +++ b/tests/codegen-llvm/simd/aggregate-simd.rs @@ -0,0 +1,102 @@ +//@ compile-flags: -C opt-level=3 -C no-prepopulate-passes +//@ only-64bit + +#![feature(core_intrinsics, repr_simd)] +#![no_std] +#![crate_type = "lib"] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use core::intrinsics::simd::{simd_add, simd_extract}; + +use minisimd::*; + +#[repr(transparent)] +pub struct Transparent(T); + +// These tests don't actually care about the add/extract, but it ensures the +// aggregated temporaries are only used in potentially-SSA ways. + +#[no_mangle] +pub fn simd_aggregate_pot(x: [u32; 4], y: [u32; 4]) -> u32 { + // CHECK-LABEL: simd_aggregate_pot + // CHECK: %a = load <4 x i32>, ptr %x, align 4 + // CHECK: %b = load <4 x i32>, ptr %y, align 4 + // CHECK: add <4 x i32> %a, %b + + unsafe { + let a = Simd(x); + let b = Simd(y); + let c = simd_add(a, b); + simd_extract(c, 1) + } +} + +#[no_mangle] +pub fn simd_aggregate_npot(x: [u32; 7], y: [u32; 7]) -> u32 { + // CHECK-LABEL: simd_aggregate_npot + // CHECK: %a = load <7 x i32>, ptr %x, align 4 + // CHECK: %b = load <7 x i32>, ptr %y, align 4 + // CHECK: add <7 x i32> %a, %b + + unsafe { + let a = Simd(x); + let b = Simd(y); + let c = simd_add(a, b); + simd_extract(c, 1) + } +} + +#[no_mangle] +pub fn packed_simd_aggregate_pot(x: [u32; 4], y: [u32; 4]) -> u32 { + // CHECK-LABEL: packed_simd_aggregate_pot + // CHECK: %a = load <4 x i32>, ptr %x, align 4 + // CHECK: %b = load <4 x i32>, ptr %y, align 4 + // CHECK: add <4 x i32> %a, %b + + unsafe { + let a = PackedSimd(x); + let b = PackedSimd(y); + let c = simd_add(a, b); + simd_extract(c, 1) + } +} + +#[no_mangle] +pub fn packed_simd_aggregate_npot(x: [u32; 7], y: [u32; 7]) -> u32 { + // CHECK-LABEL: packed_simd_aggregate_npot + // CHECK: %b = alloca [28 x i8], align 4 + // CHECK: %a = alloca [28 x i8], align 4 + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a, ptr align 4 %x, i64 28, i1 false) + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %b, ptr align 4 %y, i64 28, i1 false) + // CHECK: %[[TEMPA:.+]] = load <7 x i32>, ptr %a, align 4 + // CHECK: %[[TEMPB:.+]] = load <7 x i32>, ptr %b, align 4 + // CHECK: add <7 x i32> %[[TEMPA]], %[[TEMPB]] + + unsafe { + let a = PackedSimd(x); + let b = PackedSimd(y); + let c = simd_add(a, b); + simd_extract(c, 1) + } +} + +#[no_mangle] +pub fn transparent_simd_aggregate(x: [u32; 4]) -> u32 { + // The transparent wrapper can just use the same SSA value as its field. + // No extra processing or spilling needed. + + // CHECK-LABEL: transparent_simd_aggregate + // CHECK-NOT: alloca + // CHECK: %[[RET:.+]] = alloca [4 x i8] + // CHECK-NOT: alloca + // CHECK: %a = load <4 x i32>, ptr %x, align 4 + // CHECK: %[[TEMP:.+]] = extractelement <4 x i32> %a, i32 1 + // CHECK: store i32 %[[TEMP]], ptr %[[RET]] + + unsafe { + let a = Simd(x); + let b = Transparent(a); + simd_extract(b.0, 1) + } +} diff --git a/tests/codegen-llvm/simd/extract-insert-dyn.rs b/tests/codegen-llvm/simd/extract-insert-dyn.rs new file mode 100644 index 00000000000..729f0145314 --- /dev/null +++ b/tests/codegen-llvm/simd/extract-insert-dyn.rs @@ -0,0 +1,121 @@ +//@compile-flags: -C opt-level=3 -C no-prepopulate-passes + +#![feature( + core_intrinsics, + repr_simd, + arm_target_feature, + mips_target_feature, + s390x_target_feature +)] +#![no_std] +#![crate_type = "lib"] +#![allow(non_camel_case_types)] + +// Test that `core::intrinsics::simd::{simd_extract_dyn, simd_insert_dyn}` +// lower to an LLVM extractelement or insertelement operation. + +use core::intrinsics::simd::{simd_extract, simd_extract_dyn, simd_insert, simd_insert_dyn}; + +#[repr(simd)] +#[derive(Clone, Copy)] +pub struct u32x16([u32; 16]); + +#[repr(simd)] +#[derive(Clone, Copy)] +pub struct i8x16([i8; 16]); + +// CHECK-LABEL: dyn_simd_extract +// CHECK: extractelement <16 x i8> %x, i32 %idx +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +unsafe extern "C" fn dyn_simd_extract(x: i8x16, idx: u32) -> i8 { + simd_extract_dyn(x, idx) +} + +// CHECK-LABEL: literal_dyn_simd_extract +// CHECK: extractelement <16 x i8> %x, i32 7 +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +unsafe extern "C" fn literal_dyn_simd_extract(x: i8x16) -> i8 { + simd_extract_dyn(x, 7) +} + +// CHECK-LABEL: const_dyn_simd_extract +// CHECK: extractelement <16 x i8> %x, i32 7 +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +unsafe extern "C" fn const_dyn_simd_extract(x: i8x16) -> i8 { + simd_extract_dyn(x, const { 3 + 4 }) +} + +// CHECK-LABEL: const_simd_extract +// CHECK: extractelement <16 x i8> %x, i32 7 +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +unsafe extern "C" fn const_simd_extract(x: i8x16) -> i8 { + simd_extract(x, const { 3 + 4 }) +} + +// CHECK-LABEL: dyn_simd_insert +// CHECK: insertelement <16 x i8> %x, i8 %e, i32 %idx +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +unsafe extern "C" fn dyn_simd_insert(x: i8x16, e: i8, idx: u32) -> i8x16 { + simd_insert_dyn(x, idx, e) +} + +// CHECK-LABEL: literal_dyn_simd_insert +// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7 +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +unsafe extern "C" fn literal_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { + simd_insert_dyn(x, 7, e) +} + +// CHECK-LABEL: const_dyn_simd_insert +// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7 +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +unsafe extern "C" fn const_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { + simd_insert_dyn(x, const { 3 + 4 }, e) +} + +// CHECK-LABEL: const_simd_insert +// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7 +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +unsafe extern "C" fn const_simd_insert(x: i8x16, e: i8) -> i8x16 { + simd_insert(x, const { 3 + 4 }, e) +} diff --git a/tests/codegen-llvm/simd/packed-simd-alignment.rs b/tests/codegen-llvm/simd/packed-simd-alignment.rs new file mode 100644 index 00000000000..53e88d8e5cf --- /dev/null +++ b/tests/codegen-llvm/simd/packed-simd-alignment.rs @@ -0,0 +1,44 @@ +//@ compile-flags: -Cno-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] +// make sure that codegen emits correctly-aligned loads and stores for repr(packed, simd) types +// the alignment of a load should be no less than T, and no more than the size of the vector type +use std::intrinsics::simd as intrinsics; + +#[derive(Copy, Clone)] +#[repr(packed, simd)] +struct f32x3([f32; 3]); + +#[derive(Copy, Clone)] +#[repr(packed, simd)] +struct f32x4([f32; 4]); + +// CHECK-LABEL: load_f32x3 +#[no_mangle] +pub fn load_f32x3(floats: &f32x3) -> f32x3 { + // FIXME: Is a memcpy really the best we can do? + // CHECK: @llvm.memcpy.{{.*}}ptr align 4 {{.*}}ptr align 4 + *floats +} + +// CHECK-LABEL: load_f32x4 +#[no_mangle] +pub fn load_f32x4(floats: &f32x4) -> f32x4 { + // CHECK: load <4 x float>, ptr %{{[a-z0-9_]*}}, align {{4|8|16}} + *floats +} + +// CHECK-LABEL: add_f32x3 +#[no_mangle] +pub fn add_f32x3(x: f32x3, y: f32x3) -> f32x3 { + // CHECK: load <3 x float>, ptr %{{[a-z0-9_]*}}, align 4 + unsafe { intrinsics::simd_add(x, y) } +} + +// CHECK-LABEL: add_f32x4 +#[no_mangle] +pub fn add_f32x4(x: f32x4, y: f32x4) -> f32x4 { + // CHECK: load <4 x float>, ptr %{{[a-z0-9_]*}}, align {{4|8|16}} + unsafe { intrinsics::simd_add(x, y) } +} diff --git a/tests/codegen-llvm/simd/packed-simd.rs b/tests/codegen-llvm/simd/packed-simd.rs new file mode 100644 index 00000000000..70c03fcc955 --- /dev/null +++ b/tests/codegen-llvm/simd/packed-simd.rs @@ -0,0 +1,56 @@ +//@ revisions:opt3 noopt +//@ only-x86_64 +//@[opt3] compile-flags: -Copt-level=3 +//@[noopt] compile-flags: -Cno-prepopulate-passes + +#![crate_type = "lib"] +#![no_std] +#![feature(repr_simd, core_intrinsics)] +use core::intrinsics::simd as intrinsics; +use core::{mem, ptr}; + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use minisimd::{PackedSimd, Simd as FullSimd}; + +// Test codegen for not only "packed" but also "fully aligned" SIMD types, and conversion between +// them. A repr(packed,simd) type with 3 elements can't exceed its element alignment, whereas the +// same type as repr(simd) will instead have padding. + +// non-powers-of-two have padding and need to be expanded to full vectors +fn load(v: PackedSimd) -> FullSimd { + unsafe { + let mut tmp = mem::MaybeUninit::>::uninit(); + ptr::copy_nonoverlapping(&v as *const _, tmp.as_mut_ptr().cast(), 1); + tmp.assume_init() + } +} + +// CHECK-LABEL: square_packed_full +// CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align (8|16)]]{{[^%]*}} [[RET_VREG:%[_0-9]*]] +// CHECK-SAME: ptr{{[a-z_ ]*}} align 4 +#[no_mangle] +pub fn square_packed_full(x: PackedSimd) -> FullSimd { + // CHECK-NEXT: start + // noopt: alloca [[RET_TYPE]], [[RET_ALIGN]] + // CHECK: load <3 x float> + let x = load(x); + // CHECK: [[VREG:%[a-z0-9_]+]] = fmul <3 x float> + // CHECK-NEXT: store <3 x float> [[VREG]], ptr [[RET_VREG]], [[RET_ALIGN]] + // CHECK-NEXT: ret void + unsafe { intrinsics::simd_mul(x, x) } +} + +// CHECK-LABEL: square_packed +// CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align 4]]{{[^%]*}} [[RET_VREG:%[_0-9]*]] +// CHECK-SAME: ptr{{[a-z_ ]*}} align 4 +#[no_mangle] +pub fn square_packed(x: PackedSimd) -> PackedSimd { + // CHECK-NEXT: start + // CHECK-NEXT: load <3 x float> + // noopt-NEXT: load <3 x float> + // CHECK-NEXT: [[VREG:%[a-z0-9_]+]] = fmul <3 x float> + // CHECK-NEXT: store <3 x float> [[VREG]], ptr [[RET_VREG]], [[RET_ALIGN]] + // CHECK-NEXT: ret void + unsafe { intrinsics::simd_mul(x, x) } +} diff --git a/tests/codegen-llvm/simd/simd-wide-sum.rs b/tests/codegen-llvm/simd/simd-wide-sum.rs new file mode 100644 index 00000000000..95117b2c748 --- /dev/null +++ b/tests/codegen-llvm/simd/simd-wide-sum.rs @@ -0,0 +1,59 @@ +//@ revisions: llvm mir-opt3 +//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled +//@ edition: 2021 +//@ only-x86_64 +//@ [mir-opt3]compile-flags: -Zmir-opt-level=3 +//@ [mir-opt3]build-pass + +// mir-opt3 is a regression test for https://github.com/rust-lang/rust/issues/98016 + +#![crate_type = "lib"] +#![feature(portable_simd)] + +use std::simd::prelude::*; +const N: usize = 16; + +#[no_mangle] +// CHECK-LABEL: @wider_reduce_simd +pub fn wider_reduce_simd(x: Simd) -> u16 { + // CHECK: zext <16 x i8> + // CHECK-SAME: to <16 x i16> + // CHECK: call i16 @llvm.vector.reduce.add.v16i16(<16 x i16> + let x: Simd = x.cast(); + x.reduce_sum() +} + +#[no_mangle] +// CHECK-LABEL: @wider_reduce_loop +pub fn wider_reduce_loop(x: Simd) -> u16 { + // CHECK: zext <16 x i8> + // CHECK-SAME: to <16 x i16> + // CHECK: call i16 @llvm.vector.reduce.add.v16i16(<16 x i16> + let mut sum = 0_u16; + for i in 0..N { + sum += u16::from(x[i]); + } + sum +} + +#[no_mangle] +// CHECK-LABEL: @wider_reduce_iter +pub fn wider_reduce_iter(x: Simd) -> u16 { + // CHECK: zext <16 x i8> + // CHECK-SAME: to <16 x i16> + // CHECK: call i16 @llvm.vector.reduce.add.v16i16(<16 x i16> + x.as_array().iter().copied().map(u16::from).sum() +} + +// This iterator one is the most interesting, as it's the one +// which used to not auto-vectorize due to a suboptimality in the +// `::fold` implementation. + +#[no_mangle] +// CHECK-LABEL: @wider_reduce_into_iter +pub fn wider_reduce_into_iter(x: Simd) -> u16 { + // CHECK: zext <16 x i8> + // CHECK-SAME: to <16 x i16> + // CHECK: call i16 @llvm.vector.reduce.add.v16i16(<16 x i16> + x.to_array().into_iter().map(u16::from).sum() +} diff --git a/tests/codegen-llvm/simd/simd_arith_offset.rs b/tests/codegen-llvm/simd/simd_arith_offset.rs new file mode 100644 index 00000000000..210b4e9bb50 --- /dev/null +++ b/tests/codegen-llvm/simd/simd_arith_offset.rs @@ -0,0 +1,22 @@ +//@ compile-flags: -C no-prepopulate-passes +//@ only-64bit (because the LLVM type of i64 for usize shows up) +// + +#![crate_type = "lib"] +#![feature(repr_simd, core_intrinsics)] + +#[path = "../../auxiliary/minisimd.rs"] +mod minisimd; +use std::intrinsics::simd::simd_arith_offset; + +use minisimd::*; + +/// A vector of *const T. +pub type SimdConstPtr = Simd<*const T, LANES>; + +// CHECK-LABEL: smoke +#[no_mangle] +pub fn smoke(ptrs: SimdConstPtr, offsets: Simd) -> SimdConstPtr { + // CHECK: getelementptr i8, <8 x ptr> %0, <8 x i64> %1 + unsafe { simd_arith_offset(ptrs, offsets) } +} diff --git a/tests/codegen-llvm/simd/swap-simd-types.rs b/tests/codegen-llvm/simd/swap-simd-types.rs new file mode 100644 index 00000000000..c063cc683a6 --- /dev/null +++ b/tests/codegen-llvm/simd/swap-simd-types.rs @@ -0,0 +1,40 @@ +//@ compile-flags: -Copt-level=3 -C target-feature=+avx +//@ only-x86_64 + +#![crate_type = "lib"] + +use std::mem::swap; + +// SIMD types are highly-aligned already, so make sure the swap code leaves their +// types alone and doesn't pessimize them (such as by swapping them as `usize`s). +extern crate core; +use core::arch::x86_64::__m256; + +// CHECK-LABEL: @swap_single_m256 +#[no_mangle] +pub fn swap_single_m256(x: &mut __m256, y: &mut __m256) { + // CHECK-NOT: alloca + // CHECK: load <8 x float>{{.+}}align 32 + // CHECK: store <8 x float>{{.+}}align 32 + swap(x, y) +} + +// CHECK-LABEL: @swap_m256_slice +#[no_mangle] +pub fn swap_m256_slice(x: &mut [__m256], y: &mut [__m256]) { + // CHECK-NOT: alloca + // CHECK-COUNT-2: load <4 x i64>{{.+}}align 32 + // CHECK-COUNT-2: store <4 x i64>{{.+}}align 32 + if x.len() == y.len() { + x.swap_with_slice(y); + } +} + +// CHECK-LABEL: @swap_bytes32 +#[no_mangle] +pub fn swap_bytes32(x: &mut [u8; 32], y: &mut [u8; 32]) { + // CHECK-NOT: alloca + // CHECK-COUNT-2: load <4 x i64>{{.+}}align 1 + // CHECK-COUNT-2: store <4 x i64>{{.+}}align 1 + swap(x, y) +} diff --git a/tests/codegen-llvm/simd/unpadded-simd.rs b/tests/codegen-llvm/simd/unpadded-simd.rs new file mode 100644 index 00000000000..ef067a15702 --- /dev/null +++ b/tests/codegen-llvm/simd/unpadded-simd.rs @@ -0,0 +1,19 @@ +// Make sure that no 0-sized padding is inserted in structs and that +// structs are represented as expected by Neon intrinsics in LLVM. +// See #87254. + +#![crate_type = "lib"] +#![feature(repr_simd, abi_unadjusted)] + +#[derive(Copy, Clone)] +#[repr(simd)] +pub struct int16x4_t(pub [i16; 4]); + +#[derive(Copy, Clone)] +pub struct int16x4x2_t(pub int16x4_t, pub int16x4_t); + +// CHECK: %int16x4x2_t = type { <4 x i16>, <4 x i16> } +#[no_mangle] +extern "unadjusted" fn takes_int16x4x2_t(t: int16x4x2_t) -> int16x4x2_t { + t +} diff --git a/tests/codegen-llvm/skip-mono-inside-if-false.rs b/tests/codegen-llvm/skip-mono-inside-if-false.rs new file mode 100644 index 00000000000..8b95de99dd3 --- /dev/null +++ b/tests/codegen-llvm/skip-mono-inside-if-false.rs @@ -0,0 +1,41 @@ +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn demo_for_i32() { + generic_impl::(); +} + +// Two important things here: +// - We replace the "then" block with `unreachable` to avoid linking problems +// - We neither declare nor define the `big_impl` that said block "calls". + +// CHECK-LABEL: ; skip_mono_inside_if_false::generic_impl +// CHECK: start: +// CHECK-NEXT: br label %[[ELSE_BRANCH:bb[0-9]+]] +// CHECK: [[ELSE_BRANCH]]: +// CHECK-NEXT: call skip_mono_inside_if_false::small_impl +// CHECK: bb{{[0-9]+}}: +// CHECK-NEXT: ret void +// CHECK: bb{{[0-9+]}}: +// CHECK-NEXT: unreachable + +fn generic_impl() { + trait MagicTrait { + const IS_BIG: bool; + } + impl MagicTrait for T { + const IS_BIG: bool = std::mem::size_of::() > 10; + } + if T::IS_BIG { + big_impl::(); + } else { + small_impl::(); + } +} + +#[inline(never)] +fn small_impl() {} +#[inline(never)] +fn big_impl() {} diff --git a/tests/codegen-llvm/slice-as_chunks.rs b/tests/codegen-llvm/slice-as_chunks.rs new file mode 100644 index 00000000000..337eb8981f6 --- /dev/null +++ b/tests/codegen-llvm/slice-as_chunks.rs @@ -0,0 +1,30 @@ +//@ compile-flags: -Copt-level=3 +//@ only-64bit (because the LLVM type of i64 for usize shows up) + +#![crate_type = "lib"] + +// CHECK-LABEL: @chunks4 +#[no_mangle] +pub fn chunks4(x: &[u8]) -> &[[u8; 4]] { + // CHECK-NEXT: start: + // CHECK-NEXT: lshr i64 %x.1, 2 + // CHECK-NOT: shl + // CHECK-NOT: mul + // CHECK-NOT: udiv + // CHECK-NOT: urem + // CHECK: ret + x.as_chunks().0 +} + +// CHECK-LABEL: @chunks4_with_remainder +#[no_mangle] +pub fn chunks4_with_remainder(x: &[u8]) -> (&[[u8; 4]], &[u8]) { + // CHECK-DAG: and i64 %x.1, -4 + // CHECK-DAG: and i64 %x.1, 3 + // CHECK-DAG: lshr + // CHECK-NOT: mul + // CHECK-NOT: udiv + // CHECK-NOT: urem + // CHECK: ret + x.as_chunks() +} diff --git a/tests/codegen-llvm/slice-indexing.rs b/tests/codegen-llvm/slice-indexing.rs new file mode 100644 index 00000000000..d957ccfb5ef --- /dev/null +++ b/tests/codegen-llvm/slice-indexing.rs @@ -0,0 +1,99 @@ +//@ compile-flags: -Copt-level=3 +//@ only-64bit (because the LLVM type of i64 for usize shows up) + +#![crate_type = "lib"] + +use std::ops::Range; + +// CHECK-LABEL: @index_by_range( +#[no_mangle] +pub fn index_by_range(x: &[u16], r: Range) -> &[u16] { + // CHECK: sub nuw i64 + &x[r] +} + +// CHECK-LABEL: @get_unchecked_by_range( +#[no_mangle] +pub unsafe fn get_unchecked_by_range(x: &[u16], r: Range) -> &[u16] { + // CHECK: sub nuw i64 + x.get_unchecked(r) +} + +// CHECK-LABEL: @index_mut_by_range( +#[no_mangle] +pub fn index_mut_by_range(x: &mut [i32], r: Range) -> &mut [i32] { + // CHECK: sub nuw i64 + &mut x[r] +} + +// CHECK-LABEL: @get_unchecked_mut_by_range( +#[no_mangle] +pub unsafe fn get_unchecked_mut_by_range(x: &mut [i32], r: Range) -> &mut [i32] { + // CHECK: sub nuw i64 + x.get_unchecked_mut(r) +} + +// CHECK-LABEL: @str_index_by_range( +#[no_mangle] +pub fn str_index_by_range(x: &str, r: Range) -> &str { + // CHECK: sub nuw i64 + &x[r] +} + +// CHECK-LABEL: @str_get_unchecked_by_range( +#[no_mangle] +pub unsafe fn str_get_unchecked_by_range(x: &str, r: Range) -> &str { + // CHECK: sub nuw i64 + x.get_unchecked(r) +} + +// CHECK-LABEL: @str_index_mut_by_range( +#[no_mangle] +pub fn str_index_mut_by_range(x: &mut str, r: Range) -> &mut str { + // CHECK: sub nuw i64 + &mut x[r] +} + +// CHECK-LABEL: @str_get_unchecked_mut_by_range( +#[no_mangle] +pub unsafe fn str_get_unchecked_mut_by_range(x: &mut str, r: Range) -> &mut str { + // CHECK: sub nuw i64 + x.get_unchecked_mut(r) +} + +// CHECK-LABEL: @slice_repeated_indexing( +#[no_mangle] +pub fn slice_repeated_indexing(dst: &mut [u8], offset: usize) { + let mut i = offset; + // CHECK: panic_bounds_check + dst[i] = 1; + i += 1; + // CHECK: panic_bounds_check + dst[i] = 2; + i += 1; + // CHECK: panic_bounds_check + dst[i] = 3; + i += 1; + // CHECK: panic_bounds_check + dst[i] = 4; +} + +// CHECK-LABEL: @slice_repeated_indexing_coalesced( +#[no_mangle] +pub fn slice_repeated_indexing_coalesced(dst: &mut [u8], offset: usize) { + let mut i = offset; + if i.checked_add(4).unwrap() <= dst.len() { + // CHECK-NOT: panic_bounds_check + dst[i] = 1; + i += 1; + // CHECK-NOT: panic_bounds_check + dst[i] = 2; + i += 1; + // CHECK-NOT: panic_bounds_check + dst[i] = 3; + i += 1; + // CHECK-NOT: panic_bounds_check + dst[i] = 4; + } + // CHECK: ret +} diff --git a/tests/codegen-llvm/slice-init.rs b/tests/codegen-llvm/slice-init.rs new file mode 100644 index 00000000000..950e0b0c10d --- /dev/null +++ b/tests/codegen-llvm/slice-init.rs @@ -0,0 +1,108 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +// CHECK-LABEL: @zero_sized_elem +#[no_mangle] +pub fn zero_sized_elem() { + // CHECK-NOT: br label %repeat_loop_header{{.*}} + // CHECK-NOT: call void @llvm.memset.p0 + let x = [(); 4]; + opaque(&x); +} + +// CHECK-LABEL: @zero_len_array +#[no_mangle] +pub fn zero_len_array() { + // CHECK-NOT: br label %repeat_loop_header{{.*}} + // CHECK-NOT: call void @llvm.memset.p0 + let x = [4; 0]; + opaque(&x); +} + +// CHECK-LABEL: @byte_array +#[no_mangle] +pub fn byte_array() { + // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}, i8 7, i{{[0-9]+}} 4 + // CHECK-NOT: br label %repeat_loop_header{{.*}} + let x = [7u8; 4]; + opaque(&x); +} + +#[allow(dead_code)] +#[derive(Copy, Clone)] +enum Init { + Loop, + Memset, +} + +// CHECK-LABEL: @byte_enum_array +#[no_mangle] +pub fn byte_enum_array() { + // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}, i8 {{.*}}, i{{[0-9]+}} 4 + // CHECK-NOT: br label %repeat_loop_header{{.*}} + let x = [Init::Memset; 4]; + opaque(&x); +} + +// CHECK-LABEL: @zeroed_integer_array +#[no_mangle] +pub fn zeroed_integer_array() { + // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}, i8 0, i{{[0-9]+}} 16 + // CHECK-NOT: br label %repeat_loop_header{{.*}} + let x = [0u32; 4]; + opaque(&x); +} + +// CHECK-LABEL: @nonzero_integer_array +#[no_mangle] +pub fn nonzero_integer_array() { + // CHECK: br label %repeat_loop_header{{.*}} + // CHECK-NOT: call void @llvm.memset.p0 + let x = [0x1a_2b_3c_4d_u32; 4]; + opaque(&x); +} + +const N: usize = 100; + +// CHECK-LABEL: @u16_init_one_bytes +#[no_mangle] +pub fn u16_init_one_bytes() -> [u16; N] { + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + // CHECK: call void @llvm.memset.p0 + [const { u16::from_be_bytes([1, 1]) }; N] +} + +// FIXME: undef bytes can just be initialized with the same value as the +// defined bytes, if the defines bytes are all the same. +// CHECK-LABEL: @option_none_init +#[no_mangle] +pub fn option_none_init() -> [Option; N] { + // CHECK-NOT: select + // CHECK: br label %repeat_loop_header{{.*}} + // CHECK-NOT: switch + // CHECK: icmp + // CHECK-NOT: call void @llvm.memset.p0 + [None; N] +} + +use std::mem::MaybeUninit; + +// FIXME: This could be optimized into a memset. +// Regression test for . +#[no_mangle] +pub fn half_uninit() -> [(u128, MaybeUninit); N] { + // CHECK-NOT: select + // CHECK: br label %repeat_loop_header{{.*}} + // CHECK-NOT: switch + // CHECK: icmp + // CHECK-NOT: call void @llvm.memset.p0 + [const { (0, MaybeUninit::uninit()) }; N] +} + +// Use an opaque function to prevent rustc from removing useless drops. +#[inline(never)] +pub fn opaque(_: impl Sized) {} diff --git a/tests/codegen-llvm/slice-is-ascii.rs b/tests/codegen-llvm/slice-is-ascii.rs new file mode 100644 index 00000000000..67537c871a0 --- /dev/null +++ b/tests/codegen-llvm/slice-is-ascii.rs @@ -0,0 +1,16 @@ +//@ only-x86_64 +//@ compile-flags: -C opt-level=3 -C target-cpu=x86-64 +#![crate_type = "lib"] + +/// Check that the fast-path of `is_ascii` uses a `pmovmskb` instruction. +/// Platforms lacking an equivalent instruction use other techniques for +/// optimizing `is_ascii`. +// CHECK-LABEL: @is_ascii_autovectorized +#[no_mangle] +pub fn is_ascii_autovectorized(s: &[u8]) -> bool { + // CHECK: load <32 x i8> + // CHECK-NEXT: icmp slt <32 x i8> + // CHECK-NEXT: bitcast <32 x i1> + // CHECK-NEXT: icmp eq i32 + s.is_ascii() +} diff --git a/tests/codegen-llvm/slice-iter-fold.rs b/tests/codegen-llvm/slice-iter-fold.rs new file mode 100644 index 00000000000..55ab34661c3 --- /dev/null +++ b/tests/codegen-llvm/slice-iter-fold.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +// CHECK-LABEL: @slice_fold_to_last +#[no_mangle] +pub fn slice_fold_to_last(slice: &[i32]) -> Option<&i32> { + // CHECK-NOT: loop + // CHECK-NOT: br + // CHECK-NOT: call + // CHECK: ret + slice.iter().fold(None, |_, i| Some(i)) +} diff --git a/tests/codegen-llvm/slice-iter-len-eq-zero.rs b/tests/codegen-llvm/slice-iter-len-eq-zero.rs new file mode 100644 index 00000000000..6998d98e498 --- /dev/null +++ b/tests/codegen-llvm/slice-iter-len-eq-zero.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -Copt-level=3 +//@ needs-deterministic-layouts (opposite scalar pair orders breaks it) +#![crate_type = "lib"] + +type Demo = [u8; 3]; + +// CHECK-LABEL: @slice_iter_len_eq_zero +#[no_mangle] +pub fn slice_iter_len_eq_zero(y: std::slice::Iter<'_, Demo>) -> bool { + // CHECK-NOT: sub + // CHECK: %[[RET:.+]] = icmp eq ptr {{%y.0, %y.1|%y.1, %y.0}} + // CHECK: ret i1 %[[RET]] + y.len() == 0 +} + +// CHECK-LABEL: @slice_iter_len_eq_zero_ref +#[no_mangle] +pub fn slice_iter_len_eq_zero_ref(y: &mut std::slice::Iter<'_, Demo>) -> bool { + // CHECK-NOT: sub + // CHECK: %[[A:.+]] = load ptr + // CHECK-SAME: !nonnull + // CHECK: %[[B:.+]] = load ptr + // CHECK-SAME: !nonnull + // CHECK: %[[RET:.+]] = icmp eq ptr %[[A]], %[[B]] + // CHECK: ret i1 %[[RET]] + y.len() == 0 +} + +struct MyZST; + +// CHECK-LABEL: @slice_zst_iter_len_eq_zero +#[no_mangle] +pub fn slice_zst_iter_len_eq_zero(y: std::slice::Iter<'_, MyZST>) -> bool { + // CHECK: %[[RET:.+]] = icmp eq ptr %y.1, null + // CHECK: ret i1 %[[RET]] + y.len() == 0 +} + +// CHECK-LABEL: @slice_zst_iter_len_eq_zero_ref +#[no_mangle] +pub fn slice_zst_iter_len_eq_zero_ref(y: &mut std::slice::Iter<'_, MyZST>) -> bool { + // CHECK: %[[LEN:.+]] = load ptr + // CHECK-NOT: !nonnull + // CHECK: %[[RET:.+]] = icmp eq ptr %[[LEN]], null + // CHECK: ret i1 %[[RET]] + y.len() == 0 +} + +// CHECK-LABEL: @array_into_iter_len_eq_zero +#[no_mangle] +pub fn array_into_iter_len_eq_zero(y: std::array::IntoIter) -> bool { + // This should be able to just check that the indexes are equal, and not + // need any subtractions or comparisons to handle `start > end`. + + // CHECK-NOT: icmp + // CHECK-NOT: sub + // CHECK: %_0 = icmp eq {{i16|i32|i64}} + // CHECK: ret i1 %_0 + y.len() == 0 +} diff --git a/tests/codegen-llvm/slice-iter-nonnull.rs b/tests/codegen-llvm/slice-iter-nonnull.rs new file mode 100644 index 00000000000..87907e7ad0a --- /dev/null +++ b/tests/codegen-llvm/slice-iter-nonnull.rs @@ -0,0 +1,115 @@ +//@ compile-flags: -Copt-level=3 +//@ needs-deterministic-layouts +#![crate_type = "lib"] +#![feature(exact_size_is_empty)] + +// The slice iterator used to `assume` that the `start` pointer was non-null. +// That ought to be unneeded, though, since the type is `NonNull`, so this test +// confirms that the appropriate metadata is included to denote that. + +// It also used to `assume` the `end` pointer was non-null, but that's no longer +// needed as the code changed to read it as a `NonNull`, and thus gets the +// appropriate `!nonnull` annotations naturally. + +// CHECK-LABEL: @slice_iter_next( +#[no_mangle] +pub fn slice_iter_next<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'a u32> { + // CHECK: %[[START:.+]] = load ptr, ptr %it, + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}} + // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]] + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: icmp eq ptr %[[START]], %[[END]] + + // CHECK: store ptr{{.+}}, ptr %it, + + it.next() +} + +// CHECK-LABEL: @slice_iter_next_back( +#[no_mangle] +pub fn slice_iter_next_back<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'a u32> { + // CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}} + // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]] + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: %[[START:.+]] = load ptr, ptr %it, + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: icmp eq ptr %[[START]], %[[END]] + + // CHECK: store ptr{{.+}}, ptr %[[ENDP]], + + it.next_back() +} + +// The slice iterator `new` methods used to `assume` that the pointer is non-null, +// but passing slices already requires that, to the extent that LLVM actually +// removed the `call @llvm.assume` anyway. These tests just demonstrate that the +// attribute is there, and confirms adding the assume back doesn't do anything. + +// CHECK-LABEL: @slice_iter_new +// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef %slice.1) +#[no_mangle] +pub fn slice_iter_new(slice: &[u32]) -> std::slice::Iter<'_, u32> { + // CHECK-NOT: slice + // CHECK: %[[END:.+]] = getelementptr inbounds{{( nuw)?}} i32{{.+}} %slice.0{{.+}} %slice.1 + // CHECK-NOT: slice + // CHECK: insertvalue {{.+}} ptr %slice.0, 0 + // CHECK-NOT: slice + // CHECK: insertvalue {{.+}} ptr %[[END]], 1 + // CHECK-NOT: slice + // CHECK: } + slice.iter() +} + +// CHECK-LABEL: @slice_iter_mut_new +// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef %slice.1) +#[no_mangle] +pub fn slice_iter_mut_new(slice: &mut [u32]) -> std::slice::IterMut<'_, u32> { + // CHECK-NOT: slice + // CHECK: %[[END:.+]] = getelementptr inbounds{{( nuw)?}} i32{{.+}} %slice.0{{.+}} %slice.1 + // CHECK-NOT: slice + // CHECK: insertvalue {{.+}} ptr %slice.0, 0 + // CHECK-NOT: slice + // CHECK: insertvalue {{.+}} ptr %[[END]], 1 + // CHECK-NOT: slice + // CHECK: } + slice.iter_mut() +} + +// CHECK-LABEL: @slice_iter_is_empty +#[no_mangle] +pub fn slice_iter_is_empty(it: &std::slice::Iter<'_, u32>) -> bool { + // CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}} + // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]] + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: %[[START:.+]] = load ptr, ptr %it, + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + + // CHECK: %[[RET:.+]] = icmp eq ptr %[[START]], %[[END]] + // CHECK: ret i1 %[[RET]] + it.is_empty() +} + +// CHECK-LABEL: @slice_iter_len +#[no_mangle] +pub fn slice_iter_len(it: &std::slice::Iter<'_, u32>) -> usize { + // CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}} + // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]] + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: %[[START:.+]] = load ptr, ptr %it, + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + + // CHECK: ptrtoint + // CHECK: ptrtoint + // CHECK: sub nuw + // CHECK: lshr exact + it.len() +} diff --git a/tests/codegen-llvm/slice-last-elements-optimization.rs b/tests/codegen-llvm/slice-last-elements-optimization.rs new file mode 100644 index 00000000000..b90f91d7b17 --- /dev/null +++ b/tests/codegen-llvm/slice-last-elements-optimization.rs @@ -0,0 +1,37 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 +//@ min-llvm-version: 20 +#![crate_type = "lib"] + +// This test verifies that LLVM 20 properly optimizes the bounds check +// when accessing the last few elements of a slice with proper conditions. +// Previously, this would generate an unreachable branch to +// slice_start_index_len_fail even when the bounds check was provably safe. + +// CHECK-LABEL: @last_four_initial( +#[no_mangle] +pub fn last_four_initial(s: &[u8]) -> &[u8] { + // Previously this would generate a branch to slice_start_index_len_fail + // that is unreachable. The LLVM 20 fix should eliminate this branch. + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: unreachable + let start = if s.len() <= 4 { 0 } else { s.len() - 4 }; + &s[start..] +} + +// CHECK-LABEL: @last_four_optimized( +#[no_mangle] +pub fn last_four_optimized(s: &[u8]) -> &[u8] { + // This version was already correctly optimized before the fix in LLVM 20. + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: unreachable + if s.len() <= 4 { &s[0..] } else { &s[s.len() - 4..] } +} + +// Just to verify we're correctly checking for the right thing +// CHECK-LABEL: @test_bounds_check_happens( +#[no_mangle] +pub fn test_bounds_check_happens(s: &[u8], i: usize) -> &[u8] { + // CHECK: slice_start_index_len_fail + &s[i..] +} diff --git a/tests/codegen-llvm/slice-pointer-nonnull-unwrap.rs b/tests/codegen-llvm/slice-pointer-nonnull-unwrap.rs new file mode 100644 index 00000000000..35e4bf2c661 --- /dev/null +++ b/tests/codegen-llvm/slice-pointer-nonnull-unwrap.rs @@ -0,0 +1,18 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +use std::ptr::NonNull; + +// CHECK-LABEL: @slice_ptr_len_1 +// CHECK-NEXT: {{.*}}: +// CHECK-NEXT: ret {{i(32|64)}} %ptr.1 +#[no_mangle] +pub fn slice_ptr_len_1(ptr: *const [u8]) -> usize { + let ptr = ptr.cast_mut(); + if let Some(ptr) = NonNull::new(ptr) { + ptr.len() + } else { + // We know ptr is null, so we know ptr.wrapping_byte_add(1) is not null. + NonNull::new(ptr.wrapping_byte_add(1)).unwrap().len() + } +} diff --git a/tests/codegen-llvm/slice-position-bounds-check.rs b/tests/codegen-llvm/slice-position-bounds-check.rs new file mode 100644 index 00000000000..0d1d1d869ae --- /dev/null +++ b/tests/codegen-llvm/slice-position-bounds-check.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Copt-level=3 -C panic=abort +#![crate_type = "lib"] + +fn search(arr: &mut [T], a: &T) -> Result { + match arr.iter().position(|x| x == a) { + Some(p) => Ok(p), + None => Err(()), + } +} + +// CHECK-LABEL: @position_no_bounds_check +#[no_mangle] +pub fn position_no_bounds_check(y: &mut [u32], x: &u32, z: &u32) -> bool { + // This contains "call assume" so we cannot just rule out all calls + // CHECK-NOT: panic_bounds_check + if let Ok(p) = search(y, x) { y[p] == *z } else { false } +} + +// just to make sure that panicking really emits "panic_bounds_check" somewhere in the IR +// CHECK-LABEL: @test_check +#[no_mangle] +pub fn test_check(y: &[i32]) -> i32 { + // CHECK: panic_bounds_check + y[12] +} diff --git a/tests/codegen-llvm/slice-ref-equality.rs b/tests/codegen-llvm/slice-ref-equality.rs new file mode 100644 index 00000000000..2940378da3c --- /dev/null +++ b/tests/codegen-llvm/slice-ref-equality.rs @@ -0,0 +1,90 @@ +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled +#![crate_type = "lib"] + +use std::num::NonZero; + +// #71602 reported a simple array comparison just generating a loop. +// This was originally fixed by ensuring it generates a single bcmp, +// but we now generate it as a load+icmp instead. `is_zero_slice` was +// tweaked to still test the case of comparison against a slice, +// and `is_zero_array` tests the new array-specific behaviour. +// The optimization was then extended to short slice-to-array comparisons, +// so the first test here now has a long slice to still get the bcmp. + +// CHECK-LABEL: @is_zero_slice_long +#[no_mangle] +pub fn is_zero_slice_long(data: &[u8; 456]) -> bool { + // CHECK: %[[BCMP:.+]] = tail call i32 @{{bcmp|memcmp}}({{.+}}) + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[BCMP]], 0 + // CHECK-NEXT: ret i1 %[[EQ]] + &data[..] == [0; 456] +} + +// CHECK-LABEL: @is_zero_slice_short +#[no_mangle] +pub fn is_zero_slice_short(data: &[u8; 4]) -> bool { + // CHECK: %[[LOAD:.+]] = load i32, ptr %{{.+}}, align 1 + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[LOAD]], 0 + // CHECK-NEXT: ret i1 %[[EQ]] + &data[..] == [0; 4] +} + +// CHECK-LABEL: @is_zero_array +#[no_mangle] +pub fn is_zero_array(data: &[u8; 4]) -> bool { + // CHECK: %[[LOAD:.+]] = load i32, ptr %{{.+}}, align 1 + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[LOAD]], 0 + // CHECK-NEXT: ret i1 %[[EQ]] + *data == [0; 4] +} + +// The following test the extra specializations to make sure that slice +// equality for non-byte types also just emit a `bcmp`, not a loop. + +// CHECK-LABEL: @eq_slice_of_nested_u8( +// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1 +// CHECK-SAME: [[USIZE]] noundef %y.1 +#[no_mangle] +fn eq_slice_of_nested_u8(x: &[[u8; 3]], y: &[[u8; 3]]) -> bool { + // CHECK: icmp eq [[USIZE]] %x.1, %y.1 + // CHECK: %[[BYTES:.+]] = mul nuw nsw [[USIZE]] {{%x.1|%y.1}}, 3 + // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr + // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) + x == y +} + +// CHECK-LABEL: @eq_slice_of_i32( +// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1 +// CHECK-SAME: [[USIZE]] noundef %y.1 +#[no_mangle] +fn eq_slice_of_i32(x: &[i32], y: &[i32]) -> bool { + // CHECK: icmp eq [[USIZE]] %x.1, %y.1 + // CHECK: %[[BYTES:.+]] = shl nuw nsw [[USIZE]] {{%x.1|%y.1}}, 2 + // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr + // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) + x == y +} + +// CHECK-LABEL: @eq_slice_of_nonzero( +// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1 +// CHECK-SAME: [[USIZE]] noundef %y.1 +#[no_mangle] +fn eq_slice_of_nonzero(x: &[NonZero], y: &[NonZero]) -> bool { + // CHECK: icmp eq [[USIZE]] %x.1, %y.1 + // CHECK: %[[BYTES:.+]] = shl nuw nsw [[USIZE]] {{%x.1|%y.1}}, 2 + // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr + // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) + x == y +} + +// CHECK-LABEL: @eq_slice_of_option_of_nonzero( +// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1 +// CHECK-SAME: [[USIZE]] noundef %y.1 +#[no_mangle] +fn eq_slice_of_option_of_nonzero(x: &[Option>], y: &[Option>]) -> bool { + // CHECK: icmp eq [[USIZE]] %x.1, %y.1 + // CHECK: %[[BYTES:.+]] = shl nuw nsw [[USIZE]] {{%x.1|%y.1}}, 1 + // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr + // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) + x == y +} diff --git a/tests/codegen-llvm/slice-reverse.rs b/tests/codegen-llvm/slice-reverse.rs new file mode 100644 index 00000000000..e58d1c1d9d8 --- /dev/null +++ b/tests/codegen-llvm/slice-reverse.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 +//@ ignore-std-debug-assertions (debug assertions prevent generating shufflevector) + +#![crate_type = "lib"] + +// CHECK-LABEL: @slice_reverse_u8 +#[no_mangle] +pub fn slice_reverse_u8(slice: &mut [u8]) { + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: slice_end_index_len_fail + // CHECK: shufflevector <{{[0-9]+}} x i8> + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: slice_end_index_len_fail + slice.reverse(); +} + +// CHECK-LABEL: @slice_reverse_i32 +#[no_mangle] +pub fn slice_reverse_i32(slice: &mut [i32]) { + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: slice_end_index_len_fail + // CHECK: shufflevector <{{[0-9]+}} x i32> + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: slice_end_index_len_fail + slice.reverse(); +} diff --git a/tests/codegen-llvm/slice-split-at.rs b/tests/codegen-llvm/slice-split-at.rs new file mode 100644 index 00000000000..07018cf9c91 --- /dev/null +++ b/tests/codegen-llvm/slice-split-at.rs @@ -0,0 +1,24 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +// Check that no panic is generated in `split_at` when calculating the index for +// the tail chunk using `checked_sub`. +// +// Tests written for refactored implementations of: +// `<[T]>::{split_last_chunk, split_last_chunk_mut, last_chunk, last_chunk_mut}` + +// CHECK-LABEL: @split_at_last_chunk +#[no_mangle] +pub fn split_at_last_chunk(s: &[u8], chunk_size: usize) -> Option<(&[u8], &[u8])> { + // CHECK-NOT: panic + let Some(index) = s.len().checked_sub(chunk_size) else { return None }; + Some(s.split_at(index)) +} + +// CHECK-LABEL: @split_at_mut_last_chunk +#[no_mangle] +pub fn split_at_mut_last_chunk(s: &mut [u8], chunk_size: usize) -> Option<(&mut [u8], &mut [u8])> { + // CHECK-NOT: panic + let Some(index) = s.len().checked_sub(chunk_size) else { return None }; + Some(s.split_at_mut(index)) +} diff --git a/tests/codegen-llvm/slice-windows-no-bounds-check.rs b/tests/codegen-llvm/slice-windows-no-bounds-check.rs new file mode 100644 index 00000000000..87e89b14f06 --- /dev/null +++ b/tests/codegen-llvm/slice-windows-no-bounds-check.rs @@ -0,0 +1,32 @@ +#![crate_type = "lib"] + +//@ compile-flags: -Copt-level=3 + +use std::slice::Windows; + +// CHECK-LABEL: @naive_string_search +#[no_mangle] +pub fn naive_string_search(haystack: &str, needle: &str) -> Option { + if needle.is_empty() { + return Some(0); + } + // CHECK-NOT: panic + // CHECK-NOT: fail + haystack.as_bytes().windows(needle.len()).position(|sub| sub == needle.as_bytes()) +} + +// CHECK-LABEL: @next +#[no_mangle] +pub fn next<'a>(w: &mut Windows<'a, u32>) -> Option<&'a [u32]> { + // CHECK-NOT: panic + // CHECK-NOT: fail + w.next() +} + +// CHECK-LABEL: @next_back +#[no_mangle] +pub fn next_back<'a>(w: &mut Windows<'a, u32>) -> Option<&'a [u32]> { + // CHECK-NOT: panic + // CHECK-NOT: fail + w.next_back() +} diff --git a/tests/codegen-llvm/slice_as_from_ptr_range.rs b/tests/codegen-llvm/slice_as_from_ptr_range.rs new file mode 100644 index 00000000000..2073f05c07f --- /dev/null +++ b/tests/codegen-llvm/slice_as_from_ptr_range.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Copt-level=3 +//@ only-64bit (because we're using [ui]size) + +#![crate_type = "lib"] +#![feature(slice_from_ptr_range)] + +// This is intentionally using a non-power-of-two array length, +// as that's where the optimization differences show up + +// CHECK-LABEL: @flatten_via_ptr_range +#[no_mangle] +pub fn flatten_via_ptr_range(slice_of_arrays: &[[i32; 13]]) -> &[i32] { + // CHECK-NOT: lshr + // CHECK-NOT: udiv + // CHECK: mul nuw nsw i64 %{{.+}}, 13 + // CHECK-NOT: lshr + // CHECK-NOT: udiv + let r = slice_of_arrays.as_ptr_range(); + let r = r.start.cast()..r.end.cast(); + unsafe { core::slice::from_ptr_range(r) } +} diff --git a/tests/codegen-llvm/some-abis-do-extend-params-to-32-bits.rs b/tests/codegen-llvm/some-abis-do-extend-params-to-32-bits.rs new file mode 100644 index 00000000000..6ca6697588f --- /dev/null +++ b/tests/codegen-llvm/some-abis-do-extend-params-to-32-bits.rs @@ -0,0 +1,236 @@ +//@ add-core-stubs +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 + +//@ revisions:x86_64 i686 aarch64-apple aarch64-windows aarch64-linux arm riscv + +//@[x86_64] compile-flags: --target x86_64-unknown-uefi +//@[x86_64] needs-llvm-components: x86 +//@[i686] compile-flags: --target i686-unknown-linux-musl +//@[i686] needs-llvm-components: x86 +//@[aarch64-windows] compile-flags: --target aarch64-pc-windows-msvc +//@[aarch64-windows] needs-llvm-components: aarch64 +//@[aarch64-linux] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64-linux] needs-llvm-components: aarch64 +//@[aarch64-apple] compile-flags: --target aarch64-apple-darwin +//@[aarch64-apple] needs-llvm-components: aarch64 +//@[arm] compile-flags: --target armv7r-none-eabi +//@[arm] needs-llvm-components: arm +//@[riscv] compile-flags: --target riscv64gc-unknown-none-elf +//@[riscv] needs-llvm-components: riscv + +// See bottom of file for a corresponding C source file that is meant to yield +// equivalent declarations. +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +// The patterns in this file are written in the style of a table to make the +// uniformities and distinctions more apparent. +// +// ZERO/SIGN-EXTENDING TO 32 BITS NON-EXTENDING +// ============================== ======================= +// x86_64: void @c_arg_u8(i8 zeroext %_a) +// i686: void @c_arg_u8(i8 zeroext %_a) +// aarch64-apple: void @c_arg_u8(i8 zeroext %_a) +// aarch64-windows: void @c_arg_u8(i8 %_a) +// aarch64-linux: void @c_arg_u8(i8 %_a) +// arm: void @c_arg_u8(i8 zeroext %_a) +// riscv: void @c_arg_u8(i8 zeroext %_a) +#[no_mangle] +pub extern "C" fn c_arg_u8(_a: u8) {} + +// x86_64: void @c_arg_u16(i16 zeroext %_a) +// i686: void @c_arg_u16(i16 zeroext %_a) +// aarch64-apple: void @c_arg_u16(i16 zeroext %_a) +// aarch64-windows: void @c_arg_u16(i16 %_a) +// aarch64-linux: void @c_arg_u16(i16 %_a) +// arm: void @c_arg_u16(i16 zeroext %_a) +// riscv: void @c_arg_u16(i16 zeroext %_a) +#[no_mangle] +pub extern "C" fn c_arg_u16(_a: u16) {} + +// x86_64: void @c_arg_u32(i32 %_a) +// i686: void @c_arg_u32(i32 %_a) +// aarch64-apple: void @c_arg_u32(i32 %_a) +// aarch64-windows: void @c_arg_u32(i32 %_a) +// aarch64-linux: void @c_arg_u32(i32 %_a) +// arm: void @c_arg_u32(i32 %_a) +// riscv: void @c_arg_u32(i32 signext %_a) +#[no_mangle] +pub extern "C" fn c_arg_u32(_a: u32) {} + +// x86_64: void @c_arg_u64(i64 %_a) +// i686: void @c_arg_u64(i64 %_a) +// aarch64-apple: void @c_arg_u64(i64 %_a) +// aarch64-windows: void @c_arg_u64(i64 %_a) +// aarch64-linux: void @c_arg_u64(i64 %_a) +// arm: void @c_arg_u64(i64 %_a) +// riscv: void @c_arg_u64(i64 %_a) +#[no_mangle] +pub extern "C" fn c_arg_u64(_a: u64) {} + +// x86_64: void @c_arg_i8(i8 signext %_a) +// i686: void @c_arg_i8(i8 signext %_a) +// aarch64-apple: void @c_arg_i8(i8 signext %_a) +// aarch64-windows: void @c_arg_i8(i8 %_a) +// aarch64-linux: void @c_arg_i8(i8 %_a) +// arm: void @c_arg_i8(i8 signext %_a) +// riscv: void @c_arg_i8(i8 signext %_a) +#[no_mangle] +pub extern "C" fn c_arg_i8(_a: i8) {} + +// x86_64: void @c_arg_i16(i16 signext %_a) +// i686: void @c_arg_i16(i16 signext %_a) +// aarch64-apple: void @c_arg_i16(i16 signext %_a) +// aarch64-windows: void @c_arg_i16(i16 %_a) +// aarch64-linux: void @c_arg_i16(i16 %_a) +// arm: void @c_arg_i16(i16 signext %_a) +// riscv: void @c_arg_i16(i16 signext %_a) +#[no_mangle] +pub extern "C" fn c_arg_i16(_a: i16) {} + +// x86_64: void @c_arg_i32(i32 %_a) +// i686: void @c_arg_i32(i32 %_a) +// aarch64-apple: void @c_arg_i32(i32 %_a) +// aarch64-windows: void @c_arg_i32(i32 %_a) +// aarch64-linux: void @c_arg_i32(i32 %_a) +// arm: void @c_arg_i32(i32 %_a) +// riscv: void @c_arg_i32(i32 signext %_a) +#[no_mangle] +pub extern "C" fn c_arg_i32(_a: i32) {} + +// x86_64: void @c_arg_i64(i64 %_a) +// i686: void @c_arg_i64(i64 %_a) +// aarch64-apple: void @c_arg_i64(i64 %_a) +// aarch64-windows: void @c_arg_i64(i64 %_a) +// aarch64-linux: void @c_arg_i64(i64 %_a) +// arm: void @c_arg_i64(i64 %_a) +// riscv: void @c_arg_i64(i64 %_a) +#[no_mangle] +pub extern "C" fn c_arg_i64(_a: i64) {} + +// x86_64: zeroext i8 @c_ret_u8() +// i686: zeroext i8 @c_ret_u8() +// aarch64-apple: zeroext i8 @c_ret_u8() +// aarch64-windows: i8 @c_ret_u8() +// aarch64-linux: i8 @c_ret_u8() +// arm: zeroext i8 @c_ret_u8() +// riscv: zeroext i8 @c_ret_u8() +#[no_mangle] +pub extern "C" fn c_ret_u8() -> u8 { + 0 +} + +// x86_64: zeroext i16 @c_ret_u16() +// i686: zeroext i16 @c_ret_u16() +// aarch64-apple: zeroext i16 @c_ret_u16() +// aarch64-windows: i16 @c_ret_u16() +// aarch64-linux: i16 @c_ret_u16() +// arm: zeroext i16 @c_ret_u16() +// riscv: zeroext i16 @c_ret_u16() +#[no_mangle] +pub extern "C" fn c_ret_u16() -> u16 { + 0 +} + +// x86_64: i32 @c_ret_u32() +// i686: i32 @c_ret_u32() +// aarch64-apple: i32 @c_ret_u32() +// aarch64-windows: i32 @c_ret_u32() +// aarch64-linux: i32 @c_ret_u32() +// arm: i32 @c_ret_u32() +// riscv: signext i32 @c_ret_u32() +#[no_mangle] +pub extern "C" fn c_ret_u32() -> u32 { + 0 +} + +// x86_64: i64 @c_ret_u64() +// i686: i64 @c_ret_u64() +// aarch64-apple: i64 @c_ret_u64() +// aarch64-windows: i64 @c_ret_u64() +// aarch64-linux: i64 @c_ret_u64() +// arm: i64 @c_ret_u64() +// riscv: i64 @c_ret_u64() +#[no_mangle] +pub extern "C" fn c_ret_u64() -> u64 { + 0 +} + +// x86_64: signext i8 @c_ret_i8() +// i686: signext i8 @c_ret_i8() +// aarch64-apple: signext i8 @c_ret_i8() +// aarch64-windows: i8 @c_ret_i8() +// aarch64-linux: i8 @c_ret_i8() +// arm: signext i8 @c_ret_i8() +// riscv: signext i8 @c_ret_i8() +#[no_mangle] +pub extern "C" fn c_ret_i8() -> i8 { + 0 +} + +// x86_64: signext i16 @c_ret_i16() +// i686: signext i16 @c_ret_i16() +// aarch64-apple: signext i16 @c_ret_i16() +// aarch64-windows: i16 @c_ret_i16() +// aarch64-linux: i16 @c_ret_i16() +// arm: signext i16 @c_ret_i16() +// riscv: signext i16 @c_ret_i16() +#[no_mangle] +pub extern "C" fn c_ret_i16() -> i16 { + 0 +} + +// x86_64: i32 @c_ret_i32() +// i686: i32 @c_ret_i32() +// aarch64-apple: i32 @c_ret_i32() +// aarch64-windows: i32 @c_ret_i32() +// aarch64-linux: i32 @c_ret_i32() +// arm: i32 @c_ret_i32() +// riscv: signext i32 @c_ret_i32() +#[no_mangle] +pub extern "C" fn c_ret_i32() -> i32 { + 0 +} + +// x86_64: i64 @c_ret_i64() +// i686: i64 @c_ret_i64() +// aarch64-apple: i64 @c_ret_i64() +// aarch64-windows: i64 @c_ret_i64() +// aarch64-linux: i64 @c_ret_i64() +// arm: i64 @c_ret_i64() +// riscv: i64 @c_ret_i64() +#[no_mangle] +pub extern "C" fn c_ret_i64() -> i64 { + 0 +} + +const C_SOURCE_FILE: &'static str = r##" +#include +#include +#include + +void c_arg_u8(uint8_t _a) { } +void c_arg_u16(uint16_t _a) { } +void c_arg_u32(uint32_t _a) { } +void c_arg_u64(uint64_t _a) { } + +void c_arg_i8(int8_t _a) { } +void c_arg_i16(int16_t _a) { } +void c_arg_i32(int32_t _a) { } +void c_arg_i64(int64_t _a) { } + +uint8_t c_ret_u8() { return 0; } +uint16_t c_ret_u16() { return 0; } +uint32_t c_ret_u32() { return 0; } +uint64_t c_ret_u64() { return 0; } + +int8_t c_ret_i8() { return 0; } +int16_t c_ret_i16() { return 0; } +int32_t c_ret_i32() { return 0; } +int64_t c_ret_i64() { return 0; } +"##; diff --git a/tests/codegen-llvm/some-global-nonnull.rs b/tests/codegen-llvm/some-global-nonnull.rs new file mode 100644 index 00000000000..bb4d12e1c76 --- /dev/null +++ b/tests/codegen-llvm/some-global-nonnull.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @test +// CHECK-NEXT: start: +// CHECK-NEXT: tail call void @ext_fn0() +#[no_mangle] +pub fn test() { + test_inner(Some(inner0)); +} + +fn test_inner(f_maybe: Option) { + if let Some(f) = f_maybe { + f(); + } +} + +fn inner0() { + unsafe { ext_fn0() }; +} + +extern "C" { + fn ext_fn0(); +} diff --git a/tests/codegen-llvm/sparc-struct-abi.rs b/tests/codegen-llvm/sparc-struct-abi.rs new file mode 100644 index 00000000000..32d2c5bb0ef --- /dev/null +++ b/tests/codegen-llvm/sparc-struct-abi.rs @@ -0,0 +1,97 @@ +// Checks that we correctly codegen extern "C" functions returning structs. +// See issues #52638 and #86163. + +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 --target=sparc64-unknown-linux-gnu --crate-type=rlib +//@ needs-llvm-components: sparc +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(C)] +pub struct Bool { + b: bool, +} + +// CHECK: define{{.*}} i64 @structbool() +// CHECK-NEXT: start: +// CHECK-NEXT: ret i64 72057594037927936 +#[no_mangle] +pub extern "C" fn structbool() -> Bool { + Bool { b: true } +} + +#[repr(C)] +pub struct BoolFloat { + b: bool, + f: f32, +} + +// CHECK: define inreg { i32, float } @structboolfloat() +// CHECK-NEXT: start: +// CHECK-NEXT: ret { i32, float } { i32 16777216, float 0x40091EB860000000 } +#[no_mangle] +pub extern "C" fn structboolfloat() -> BoolFloat { + BoolFloat { b: true, f: 3.14 } +} + +// CHECK: define void @structboolfloat_input({ i32, float } inreg %0) +// CHECK-NEXT: start: +#[no_mangle] +pub extern "C" fn structboolfloat_input(a: BoolFloat) {} + +#[repr(C)] +pub struct ShortDouble { + s: i16, + d: f64, +} + +// CHECK: define { i64, double } @structshortdouble() +// CHECK-NEXT: start: +// CHECK-NEXT: ret { i64, double } { i64 34621422135410688, double 3.140000e+00 } +#[no_mangle] +pub extern "C" fn structshortdouble() -> ShortDouble { + ShortDouble { s: 123, d: 3.14 } +} + +// CHECK: define void @structshortdouble_input({ i64, double } %0) +// CHECK-NEXT: start: +#[no_mangle] +pub extern "C" fn structshortdouble_input(a: ShortDouble) {} + +#[repr(C)] +pub struct FloatLongFloat { + f: f32, + i: i64, + g: f32, +} + +// CHECK: define inreg { float, i32, i64, float, i32 } @structfloatlongfloat() +// CHECK-NEXT: start: +// CHECK-NEXT: ret { float, i32, i64, float, i32 } { float 0x3FB99999A0000000, i32 undef, i64 123, float 0x40091EB860000000, i32 undef } +#[no_mangle] +pub extern "C" fn structfloatlongfloat() -> FloatLongFloat { + FloatLongFloat { f: 0.1, i: 123, g: 3.14 } +} + +#[repr(C)] +pub struct FloatFloat { + f: f32, + g: f32, +} + +#[repr(C)] +pub struct NestedStructs { + a: FloatFloat, + b: FloatFloat, +} + +// CHECK: define inreg { float, float, float, float } @structnestestructs() +// CHECK-NEXT: start: +// CHECK-NEXT: ret { float, float, float, float } { float 0x3FB99999A0000000, float 0x3FF19999A0000000, float 0x40019999A0000000, float 0x400A666660000000 } +#[no_mangle] +pub extern "C" fn structnestestructs() -> NestedStructs { + NestedStructs { a: FloatFloat { f: 0.1, g: 1.1 }, b: FloatFloat { f: 2.2, g: 3.3 } } +} diff --git a/tests/codegen-llvm/split-lto-unit.rs b/tests/codegen-llvm/split-lto-unit.rs new file mode 100644 index 00000000000..7858a0e7b79 --- /dev/null +++ b/tests/codegen-llvm/split-lto-unit.rs @@ -0,0 +1,10 @@ +// Verifies that "EnableSplitLTOUnit" module flag is added. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsplit-lto-unit + +#![crate_type = "lib"] + +pub fn foo() {} + +// CHECK: !{{[0-9]+}} = !{i32 4, !"EnableSplitLTOUnit", i32 1} diff --git a/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-md5.rs b/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-md5.rs new file mode 100644 index 00000000000..7aec8d545dc --- /dev/null +++ b/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-md5.rs @@ -0,0 +1,6 @@ +//@ compile-flags: -g -Z src-hash-algorithm=md5 -Copt-level=0 + +#![crate_type = "lib"] + +pub fn test() {} +// CHECK: checksumkind: CSK_MD5 diff --git a/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha1.rs b/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha1.rs new file mode 100644 index 00000000000..5389c32f938 --- /dev/null +++ b/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha1.rs @@ -0,0 +1,6 @@ +//@ compile-flags: -g -Z src-hash-algorithm=sha1 -Copt-level=0 + +#![crate_type = "lib"] + +pub fn test() {} +// CHECK: checksumkind: CSK_SHA1 diff --git a/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha256.rs b/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha256.rs new file mode 100644 index 00000000000..520890c47f1 --- /dev/null +++ b/tests/codegen-llvm/src-hash-algorithm/src-hash-algorithm-sha256.rs @@ -0,0 +1,6 @@ +//@ compile-flags: -g -Z src-hash-algorithm=sha256 -Copt-level=0 + +#![crate_type = "lib"] + +pub fn test() {} +// CHECK: checksumkind: CSK_SHA256 diff --git a/tests/codegen-llvm/sroa-fragment-debuginfo.rs b/tests/codegen-llvm/sroa-fragment-debuginfo.rs new file mode 100644 index 00000000000..0413cf96894 --- /dev/null +++ b/tests/codegen-llvm/sroa-fragment-debuginfo.rs @@ -0,0 +1,46 @@ +//@ compile-flags: -g -Zmir-opt-level=0 -Zmir-enable-passes=+ScalarReplacementOfAggregates +//@ compile-flags: -Cno-prepopulate-passes +// +// Tested offsets are only correct for x86_64. +//@ only-x86_64 + +#![crate_type = "lib"] + +pub struct ExtraSlice<'input> { + slice: &'input [u8], + extra: u32, +} + +#[no_mangle] +pub fn extra(s: &[u8]) { + // CHECK: void @extra( + // CHECK: %slice.dbg.spill1 = alloca [4 x i8], + // CHECK: %slice.dbg.spill = alloca [16 x i8], + // CHECK: %s.dbg.spill = alloca [16 x i8], + // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %s.dbg.spill, {{(metadata )?}}![[S_EXTRA:.*]], {{(metadata )?}}!DIExpression() + // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %slice.dbg.spill, {{(metadata )?}}![[SLICE_EXTRA:.*]], {{(metadata )?}}!DIExpression(DW_OP_LLVM_fragment, 0, 128) + // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %slice.dbg.spill1, {{(metadata )?}}![[SLICE_EXTRA]], {{(metadata )?}}!DIExpression(DW_OP_LLVM_fragment, 128, 32) + let slice = ExtraSlice { slice: s, extra: s.len() as u32 }; +} + +struct Zst; + +pub struct ZstSlice<'input> { + slice: &'input [u8], + extra: Zst, +} + +#[no_mangle] +pub fn zst(s: &[u8]) { + // The field `extra` is a ZST. The fragment for the field `slice` encompasses the whole + // variable, so is not a fragment. In that case, the variable must have no fragment. + + // CHECK: void @zst( + // CHECK-NOT: dbg{{.}}declare({{(metadata )?}}ptr %slice.dbg.spill, {{(metadata )?}}!{}, {{(metadata )?}}!DIExpression(DW_OP_LLVM_fragment, + // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %{{.*}}, {{(metadata )?}}![[SLICE_ZST:.*]], {{(metadata )?}}!DIExpression() + // CHECK-NOT: dbg{{.}}declare({{(metadata )?}}ptr %{{.*}}, {{(metadata )?}}![[SLICE_ZST]], + let slice = ZstSlice { slice: s, extra: Zst }; +} + +// CHECK: ![[S_EXTRA]] = !DILocalVariable(name: "s", +// CHECK: ![[SLICE_EXTRA]] = !DILocalVariable(name: "slice", diff --git a/tests/codegen-llvm/sse42-implies-crc32.rs b/tests/codegen-llvm/sse42-implies-crc32.rs new file mode 100644 index 00000000000..8a9c496a3a5 --- /dev/null +++ b/tests/codegen-llvm/sse42-implies-crc32.rs @@ -0,0 +1,15 @@ +//@ only-x86_64 +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "sse4.2")] +#[no_mangle] +pub unsafe fn crc32sse(v: u8) -> u32 { + use std::arch::x86_64::*; + let out = !0u32; + _mm_crc32_u8(out, v) +} + +// CHECK: attributes #0 {{.*"target-features"=".*\+sse4.2,\+crc32.*"}} diff --git a/tests/codegen-llvm/stack-probes-inline.rs b/tests/codegen-llvm/stack-probes-inline.rs new file mode 100644 index 00000000000..746272b0994 --- /dev/null +++ b/tests/codegen-llvm/stack-probes-inline.rs @@ -0,0 +1,33 @@ +// Check the "probe-stack" attribute for targets with `StackProbeType::Inline`, +// or `StackProbeType::InlineOrCall` when running on newer LLVM. + +//@ add-core-stubs +//@ compile-flags: -C no-prepopulate-passes +//@ revisions: aarch64 powerpc powerpc64 powerpc64le s390x i686 x86_64 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: aarch64 +//@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu +//@[powerpc] needs-llvm-components: powerpc +//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu +//@[powerpc64] needs-llvm-components: powerpc +//@[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu +//@[powerpc64le] needs-llvm-components: powerpc +//@[s390x] compile-flags: --target s390x-unknown-linux-gnu +//@[s390x] needs-llvm-components: systemz +//@[i686] compile-flags: --target i686-unknown-linux-gnu +//@[i686] needs-llvm-components: x86 +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64] needs-llvm-components: x86 + +#![crate_type = "rlib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + // CHECK: attributes #0 = { {{.*}}"probe-stack"="inline-asm"{{.*}} } +} diff --git a/tests/codegen-llvm/stack-protector.rs b/tests/codegen-llvm/stack-protector.rs new file mode 100644 index 00000000000..8ab25b470cd --- /dev/null +++ b/tests/codegen-llvm/stack-protector.rs @@ -0,0 +1,34 @@ +//@ revisions: all strong basic none +//@ ignore-nvptx64 stack protector not supported +//@ [all] compile-flags: -Z stack-protector=all +//@ [strong] compile-flags: -Z stack-protector=strong +//@ [basic] compile-flags: -Z stack-protector=basic + +#![crate_type = "lib"] + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + + // all-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // all-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + // all: attributes #0 = { {{.*}}sspreq {{.*}} } + // all-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // all-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + + // strong-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // strong-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + // strong: attributes #0 = { {{.*}}sspstrong {{.*}} } + // strong-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // strong-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + + // basic-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // basic-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // basic: attributes #0 = { {{.*}}ssp {{.*}} } + // basic-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // basic-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + + // none-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // none-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // none-NOT: attributes #0 = { {{.*}}ssp {{.*}} } +} diff --git a/tests/codegen-llvm/static-relocation-model-msvc.rs b/tests/codegen-llvm/static-relocation-model-msvc.rs new file mode 100644 index 00000000000..4d30e6ec505 --- /dev/null +++ b/tests/codegen-llvm/static-relocation-model-msvc.rs @@ -0,0 +1,24 @@ +// Verify linkage of external symbols in the static relocation model on MSVC. +// +//@ compile-flags: -Copt-level=3 -C relocation-model=static +//@ aux-build: extern_decl.rs +//@ only-x86_64-pc-windows-msvc + +#![crate_type = "rlib"] + +extern crate extern_decl; + +// The `extern_decl` definitions are imported from a statically linked rust +// crate, thus they are expected to be marked `dso_local` without `dllimport`. +// +// The `access_extern()` symbol is from this compilation unit, thus we expect +// it to be marked `dso_local` as well, given the static relocation model. +// +// CHECK: @extern_static = external dso_local local_unnamed_addr global i8 +// CHECK: define dso_local noundef i8 @access_extern() {{.*}} +// CHECK: declare dso_local noundef i8 @extern_fn() {{.*}} + +#[no_mangle] +pub fn access_extern() -> u8 { + unsafe { extern_decl::extern_fn() + extern_decl::extern_static } +} diff --git a/tests/codegen-llvm/staticlib-external-inline-fns.rs b/tests/codegen-llvm/staticlib-external-inline-fns.rs new file mode 100644 index 00000000000..23316a2d9a5 --- /dev/null +++ b/tests/codegen-llvm/staticlib-external-inline-fns.rs @@ -0,0 +1,43 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "staticlib"] + +// CHECK: define{{.*}}void @a() +#[no_mangle] +#[inline] +pub extern "C" fn a() {} + +// CHECK: define{{.*}}void @b() +#[export_name = "b"] +#[inline] +pub extern "C" fn b() {} + +// CHECK: define{{.*}}void @c() +#[no_mangle] +#[inline] +extern "C" fn c() {} + +// CHECK: define{{.*}}void @d() +#[export_name = "d"] +#[inline] +extern "C" fn d() {} + +// CHECK: define{{.*}}void @e() +#[no_mangle] +#[inline(always)] +pub extern "C" fn e() {} + +// CHECK: define{{.*}}void @f() +#[export_name = "f"] +#[inline(always)] +pub extern "C" fn f() {} + +// CHECK: define{{.*}}void @g() +#[no_mangle] +#[inline(always)] +extern "C" fn g() {} + +// CHECK: define{{.*}}void @h() +#[export_name = "h"] +#[inline(always)] +extern "C" fn h() {} diff --git a/tests/codegen-llvm/step_by-overflow-checks.rs b/tests/codegen-llvm/step_by-overflow-checks.rs new file mode 100644 index 00000000000..53800e9f879 --- /dev/null +++ b/tests/codegen-llvm/step_by-overflow-checks.rs @@ -0,0 +1,26 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +use std::iter::StepBy; +use std::slice::Iter; + +// The constructor for `StepBy` ensures we can never end up needing to do zero +// checks on denominators, so check that the code isn't emitting panic paths. + +// CHECK-LABEL: @step_by_len_std +#[no_mangle] +pub fn step_by_len_std(x: &StepBy>) -> usize { + // CHECK-NOT: div_by_zero + // CHECK: udiv + // CHECK-NOT: div_by_zero + x.len() +} + +// CHECK-LABEL: @step_by_len_naive +#[no_mangle] +pub fn step_by_len_naive(x: Iter, step_minus_one: usize) -> usize { + // CHECK: udiv + // CHECK: call{{.+}}div_by_zero + x.len() / (step_minus_one + 1) +} diff --git a/tests/codegen-llvm/stores.rs b/tests/codegen-llvm/stores.rs new file mode 100644 index 00000000000..aa3090db6d3 --- /dev/null +++ b/tests/codegen-llvm/stores.rs @@ -0,0 +1,35 @@ +//@ compile-flags: -C no-prepopulate-passes +// + +#![crate_type = "lib"] + +pub struct Bytes { + a: u8, + b: u8, + c: u8, + d: u8, +} + +// CHECK-LABEL: small_array_alignment +// The array is stored as i32, but its alignment is lower, go with 1 byte to avoid target +// dependent alignment +#[no_mangle] +pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) { + // CHECK: [[TMP:%.+]] = alloca [4 x i8], align 4 + // CHECK: %y = alloca [4 x i8], align 1 + // CHECK: store i32 %0, ptr [[TMP]] + // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 {{.+}}, ptr align 4 {{.+}}, i{{[0-9]+}} 4, i1 false) + *x = y; +} + +// CHECK-LABEL: small_struct_alignment +// The struct is stored as i32, but its alignment is lower, go with 1 byte to avoid target +// dependent alignment +#[no_mangle] +pub fn small_struct_alignment(x: &mut Bytes, y: Bytes) { + // CHECK: [[TMP:%.+]] = alloca [4 x i8], align 4 + // CHECK: %y = alloca [4 x i8], align 1 + // CHECK: store i32 %0, ptr [[TMP]] + // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 {{.+}}, ptr align 4 {{.+}}, i{{[0-9]+}} 4, i1 false) + *x = y; +} diff --git a/tests/codegen-llvm/string-push.rs b/tests/codegen-llvm/string-push.rs new file mode 100644 index 00000000000..cf5f6bb1aa3 --- /dev/null +++ b/tests/codegen-llvm/string-push.rs @@ -0,0 +1,11 @@ +//! Check that `String::push` is optimized enough not to call `memcpy`. + +//@ compile-flags: -O +#![crate_type = "lib"] + +// CHECK-LABEL: @string_push_does_not_call_memcpy +#[no_mangle] +pub fn string_push_does_not_call_memcpy(s: &mut String, ch: char) { + // CHECK-NOT: call void @llvm.memcpy + s.push(ch); +} diff --git a/tests/codegen-llvm/swap-large-types.rs b/tests/codegen-llvm/swap-large-types.rs new file mode 100644 index 00000000000..08c486affd9 --- /dev/null +++ b/tests/codegen-llvm/swap-large-types.rs @@ -0,0 +1,116 @@ +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 + +#![crate_type = "lib"] + +use std::mem::swap; +use std::ptr::{copy_nonoverlapping, read, write}; + +type KeccakBuffer = [[u64; 5]; 5]; + +// A basic read+copy+write swap implementation ends up copying one of the values +// to stack for large types, which is completely unnecessary as the lack of +// overlap means we can just do whatever fits in registers at a time. + +// The tests here (after the first one showing that the problem still exists) +// are less about testing *exactly* what the codegen is, and more about testing +// 1) That things are swapped directly from one argument to the other, +// never going through stack along the way, and +// 2) That we're doing the swapping for big things using large vector types, +// rather then `i64` or `<8 x i8>` (or, even worse, `i8`) at a time. +// +// (There are separate tests for intrinsics::typed_swap_nonoverlapping that +// check that it, as an intrinsic, are emitting exactly what it should.) + +// CHECK-LABEL: @swap_basic +#[no_mangle] +pub fn swap_basic(x: &mut KeccakBuffer, y: &mut KeccakBuffer) { + // CHECK: alloca [200 x i8] + + // SAFETY: exclusive references are always valid to read/write, + // are non-overlapping, and nothing here panics so it's drop-safe. + unsafe { + let z = read(x); + copy_nonoverlapping(y, x, 1); + write(y, z); + } +} + +// CHECK-LABEL: @swap_std +#[no_mangle] +pub fn swap_std(x: &mut KeccakBuffer, y: &mut KeccakBuffer) { + // CHECK-NOT: alloca + // CHECK: load <{{2|4}} x i64> + // CHECK: store <{{2|4}} x i64> + swap(x, y) +} + +// CHECK-LABEL: @swap_slice +#[no_mangle] +pub fn swap_slice(x: &mut [KeccakBuffer], y: &mut [KeccakBuffer]) { + // CHECK-NOT: alloca + // CHECK: load <{{2|4}} x i64> + // CHECK: store <{{2|4}} x i64> + if x.len() == y.len() { + x.swap_with_slice(y); + } +} + +type OneKilobyteBuffer = [u8; 1024]; + +// CHECK-LABEL: @swap_1kb_slices +#[no_mangle] +pub fn swap_1kb_slices(x: &mut [OneKilobyteBuffer], y: &mut [OneKilobyteBuffer]) { + // CHECK-NOT: alloca + + // CHECK-NOT: load i32 + // CHECK-NOT: store i32 + // CHECK-NOT: load i16 + // CHECK-NOT: store i16 + // CHECK-NOT: load i8 + // CHECK-NOT: store i8 + + // CHECK: load <{{2|4}} x i64>{{.+}}align 1, + // CHECK: store <{{2|4}} x i64>{{.+}}align 1, + + // CHECK-NOT: load i32 + // CHECK-NOT: store i32 + // CHECK-NOT: load i16 + // CHECK-NOT: store i16 + // CHECK-NOT: load i8 + // CHECK-NOT: store i8 + + if x.len() == y.len() { + x.swap_with_slice(y); + } +} + +#[repr(align(64))] +pub struct BigButHighlyAligned([u8; 64 * 3]); + +// CHECK-LABEL: @swap_big_aligned +#[no_mangle] +pub fn swap_big_aligned(x: &mut BigButHighlyAligned, y: &mut BigButHighlyAligned) { + // CHECK-NOT: call void @llvm.memcpy + // CHECK-NOT: load i32 + // CHECK-NOT: store i32 + // CHECK-NOT: load i16 + // CHECK-NOT: store i16 + // CHECK-NOT: load i8 + // CHECK-NOT: store i8 + + // CHECK-COUNT-2: load <{{2|4}} x i64>{{.+}}align 64, + // CHECK-COUNT-2: store <{{2|4}} x i64>{{.+}}align 64, + + // CHECK-COUNT-2: load <{{2|4}} x i64>{{.+}}align 32, + // CHECK-COUNT-2: store <{{2|4}} x i64>{{.+}}align 32, + + // CHECK-NOT: load i32 + // CHECK-NOT: store i32 + // CHECK-NOT: load i16 + // CHECK-NOT: store i16 + // CHECK-NOT: load i8 + // CHECK-NOT: store i8 + // CHECK-NOT: call void @llvm.memcpy + swap(x, y) +} diff --git a/tests/codegen-llvm/swap-small-types.rs b/tests/codegen-llvm/swap-small-types.rs new file mode 100644 index 00000000000..7aa613ae9c2 --- /dev/null +++ b/tests/codegen-llvm/swap-small-types.rs @@ -0,0 +1,182 @@ +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled +//@ only-x86_64 +//@ min-llvm-version: 20 +//@ ignore-std-debug-assertions (`ptr::swap_nonoverlapping` has one which blocks some optimizations) + +#![crate_type = "lib"] + +use std::mem::swap; + +type RGB48 = [u16; 3]; + +// CHECK-LABEL: @swap_rgb48_manually( +#[no_mangle] +pub fn swap_rgb48_manually(x: &mut RGB48, y: &mut RGB48) { + // FIXME: See #115212 for why this has an alloca again + + // CHECK: alloca [6 x i8], align 2 + // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 6, i1 false) + // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 6, i1 false) + // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 6, i1 false) + + let temp = *x; + *x = *y; + *y = temp; +} + +// CHECK-LABEL: @swap_rgb48 +#[no_mangle] +pub fn swap_rgb48(x: &mut RGB48, y: &mut RGB48) { + // CHECK-NOT: alloca + + // Swapping `i48` might be cleaner in LLVM-IR here, but `i32`+`i16` isn't bad, + // and is closer to the assembly it generates anyway. + + // CHECK-NOT: load{{ }} + // CHECK: load i32{{.+}}align 2 + // CHECK-NEXT: load i32{{.+}}align 2 + // CHECK-NEXT: store i32{{.+}}align 2 + // CHECK-NEXT: store i32{{.+}}align 2 + // CHECK: load i16{{.+}}align 2 + // CHECK-NEXT: load i16{{.+}}align 2 + // CHECK-NEXT: store i16{{.+}}align 2 + // CHECK-NEXT: store i16{{.+}}align 2 + // CHECK-NOT: store{{ }} + swap(x, y) +} + +type RGBA64 = [u16; 4]; + +// CHECK-LABEL: @swap_rgba64 +#[no_mangle] +pub fn swap_rgba64(x: &mut RGBA64, y: &mut RGBA64) { + // CHECK-NOT: alloca + // CHECK-DAG: %[[XVAL:.+]] = load i64, ptr %x, align 2 + // CHECK-DAG: %[[YVAL:.+]] = load i64, ptr %y, align 2 + // CHECK-DAG: store i64 %[[YVAL]], ptr %x, align 2 + // CHECK-DAG: store i64 %[[XVAL]], ptr %y, align 2 + swap(x, y) +} + +// CHECK-LABEL: @swap_vecs +#[no_mangle] +pub fn swap_vecs(x: &mut Vec, y: &mut Vec) { + // CHECK-NOT: alloca + // There are plenty more loads and stores than just these, + // but at least one sure better be 64-bit (for size or capacity). + // CHECK: load i64 + // CHECK: load i64 + // CHECK: store i64 + // CHECK: store i64 + // CHECK: ret void + swap(x, y) +} + +// CHECK-LABEL: @swap_slices +#[no_mangle] +pub fn swap_slices<'a>(x: &mut &'a [u32], y: &mut &'a [u32]) { + // CHECK-NOT: alloca + // CHECK: load ptr + // CHECK: load i64 + // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 16, i1 false) + // CHECK: store ptr + // CHECK: store i64 + swap(x, y) +} + +type RGB24 = [u8; 3]; + +// CHECK-LABEL: @swap_rgb24_slices +#[no_mangle] +pub fn swap_rgb24_slices(x: &mut [RGB24], y: &mut [RGB24]) { + // CHECK-NOT: alloca + + // CHECK: mul nuw nsw i64 %{{x|y}}.1, 3 + + // CHECK: load <{{[0-9]+}} x i64> + // CHECK: store <{{[0-9]+}} x i64> + + // CHECK-COUNT-2: load i32 + // CHECK-COUNT-2: store i32 + // CHECK-COUNT-2: load i16 + // CHECK-COUNT-2: store i16 + // CHECK-COUNT-2: load i8 + // CHECK-COUNT-2: store i8 + if x.len() == y.len() { + x.swap_with_slice(y); + } +} + +type RGBA32 = [u8; 4]; + +// CHECK-LABEL: @swap_rgba32_slices +#[no_mangle] +pub fn swap_rgba32_slices(x: &mut [RGBA32], y: &mut [RGBA32]) { + // CHECK-NOT: alloca + + // Because the size in bytes in a multiple of 4, we can skip the smallest sizes. + + // CHECK: load <{{[0-9]+}} x i64> + // CHECK: store <{{[0-9]+}} x i64> + + // CHECK-COUNT-2: load i32 + // CHECK-COUNT-2: store i32 + + // CHECK-NOT: load i16 + // CHECK-NOT: store i16 + // CHECK-NOT: load i8 + // CHECK-NOT: store i8 + + if x.len() == y.len() { + x.swap_with_slice(y); + } +} + +// Strings have a non-power-of-two size, but have pointer alignment, +// so we swap usizes instead of dropping all the way down to bytes. +const _: () = assert!(!std::mem::size_of::().is_power_of_two()); + +// CHECK-LABEL: @swap_string_slices +#[no_mangle] +pub fn swap_string_slices(x: &mut [String], y: &mut [String]) { + // CHECK-NOT: alloca + // CHECK: load <{{[0-9]+}} x i64>{{.+}}, align 8, + // CHECK: store <{{[0-9]+}} x i64>{{.+}}, align 8, + if x.len() == y.len() { + x.swap_with_slice(y); + } +} + +#[repr(C, packed)] +pub struct Packed { + pub first: bool, + pub second: usize, +} + +// CHECK-LABEL: @swap_packed_structs +#[no_mangle] +pub fn swap_packed_structs(x: &mut Packed, y: &mut Packed) { + // CHECK-NOT: alloca + + // CHECK-NOT: load + // CHECK-NOT: store + + // CHECK: %[[A:.+]] = load i64, ptr %x, align 1, + // CHECK-NEXT: %[[B:.+]] = load i64, ptr %y, align 1, + // CHECK-NEXT: store i64 %[[B]], ptr %x, align 1, + // CHECK-NEXT: store i64 %[[A]], ptr %y, align 1, + + // CHECK-NOT: load + // CHECK-NOT: store + + // CHECK: %[[C:.+]] = load i8, ptr %[[X8:.+]], align 1, + // CHECK-NEXT: %[[D:.+]] = load i8, ptr %[[Y8:.+]], align 1, + // CHECK-NEXT: store i8 %[[D]], ptr %[[X8]], align 1, + // CHECK-NEXT: store i8 %[[C]], ptr %[[Y8]], align 1, + + // CHECK-NOT: load + // CHECK-NOT: store + + // CHECK: ret void + swap(x, y) +} diff --git a/tests/codegen-llvm/target-cpu-on-functions.rs b/tests/codegen-llvm/target-cpu-on-functions.rs new file mode 100644 index 00000000000..25c10e7ce44 --- /dev/null +++ b/tests/codegen-llvm/target-cpu-on-functions.rs @@ -0,0 +1,22 @@ +// This test makes sure that functions get annotated with the proper +// "target-cpu" attribute in LLVM. + +//@ no-prefer-dynamic +// +//@ compile-flags: -C no-prepopulate-passes -C panic=abort -C linker-plugin-lto -Cpasses=name-anon-globals + +#![crate_type = "staticlib"] + +// CHECK-LABEL: define {{.*}} @exported() {{.*}} #0 +#[no_mangle] +pub extern "C" fn exported() { + not_exported(); +} + +// CHECK-LABEL: ; target_cpu_on_functions::not_exported +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define {{.*}}() {{.*}} #1 +#[inline(never)] +fn not_exported() {} + +// CHECK: attributes #0 = {{.*}} "target-cpu"="{{.*}}" diff --git a/tests/codegen-llvm/target-feature-inline-closure.rs b/tests/codegen-llvm/target-feature-inline-closure.rs new file mode 100644 index 00000000000..5d54444f994 --- /dev/null +++ b/tests/codegen-llvm/target-feature-inline-closure.rs @@ -0,0 +1,33 @@ +//@ only-x86_64 +// Set the base cpu explicitly, in case the default has been changed. +//@ compile-flags: -Copt-level=3 -Ctarget-cpu=x86-64 + +#![crate_type = "lib"] + +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; + +// CHECK-LABEL: @with_avx +#[no_mangle] +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "avx")] +fn with_avx(x: __m256) -> __m256 { + // CHECK: fadd <8 x float> + let add = { + #[inline(always)] + |x, y| unsafe { _mm256_add_ps(x, y) } + }; + add(x, x) +} + +// CHECK-LABEL: @without_avx +#[no_mangle] +#[cfg(target_arch = "x86_64")] +unsafe fn without_avx(x: __m256) -> __m256 { + // CHECK-NOT: fadd <8 x float> + let add = { + #[inline(always)] + |x, y| unsafe { _mm256_add_ps(x, y) } + }; + add(x, x) +} diff --git a/tests/codegen-llvm/target-feature-negative-implication.rs b/tests/codegen-llvm/target-feature-negative-implication.rs new file mode 100644 index 00000000000..36cd82dd8cf --- /dev/null +++ b/tests/codegen-llvm/target-feature-negative-implication.rs @@ -0,0 +1,20 @@ +//@ add-core-stubs +//@ needs-llvm-components: x86 +//@ compile-flags: --target=x86_64-unknown-linux-gnu +//@ compile-flags: -Ctarget-feature=-avx2 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub unsafe fn banana() { + // CHECK-LABEL: @banana() + // CHECK-SAME: [[BANANAATTRS:#[0-9]+]] { +} + +// CHECK: attributes [[BANANAATTRS]] +// CHECK-SAME: -avx512 diff --git a/tests/codegen-llvm/target-feature-overrides.rs b/tests/codegen-llvm/target-feature-overrides.rs new file mode 100644 index 00000000000..63a586d388b --- /dev/null +++ b/tests/codegen-llvm/target-feature-overrides.rs @@ -0,0 +1,46 @@ +// ignore-tidy-linelength +//@ add-core-stubs +//@ revisions: COMPAT INCOMPAT +//@ needs-llvm-components: x86 +//@ compile-flags: --target=x86_64-unknown-linux-gnu -Copt-level=3 +//@ [COMPAT] compile-flags: -Ctarget-feature=+avx2 +//@ [INCOMPAT] compile-flags: -Ctarget-feature=-avx2,-avx + +// See also tests/assembly-llvm/target-feature-multiple.rs +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +extern "C" { + fn peach() -> u32; +} + +#[inline] +#[target_feature(enable = "avx")] +#[no_mangle] +pub unsafe fn apple() -> u32 { + // CHECK-LABEL: @apple() + // CHECK-SAME: [[APPLEATTRS:#[0-9]+]] { + // CHECK: {{.*}}call{{.*}}@peach + peach() +} + +// target features same as global +#[no_mangle] +pub unsafe fn banana() -> u32 { + // CHECK-LABEL: @banana() + // CHECK-SAME: [[BANANAATTRS:#[0-9]+]] { + // COMPAT: {{.*}}call{{.*}}@peach + // INCOMPAT: {{.*}}call{{.*}}@apple + apple() // Compatible for inline in COMPAT revision and can't be inlined in INCOMPAT +} + +// CHECK: attributes [[APPLEATTRS]] +// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}" +// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}},+avx{{(,\+[^,]+)*}}" +// CHECK: attributes [[BANANAATTRS]] +// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}" +// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}}" diff --git a/tests/codegen-llvm/terminating-catchpad.rs b/tests/codegen-llvm/terminating-catchpad.rs new file mode 100644 index 00000000000..a2ec19871d1 --- /dev/null +++ b/tests/codegen-llvm/terminating-catchpad.rs @@ -0,0 +1,43 @@ +//@ revisions: emscripten wasi seh +//@[emscripten] compile-flags: --target wasm32-unknown-emscripten -Z emscripten-wasm-eh +//@[wasi] compile-flags: --target wasm32-wasip1 -C panic=unwind +//@[seh] compile-flags: --target x86_64-pc-windows-msvc +//@[emscripten] needs-llvm-components: webassembly +//@[wasi] needs-llvm-components: webassembly +//@[seh] needs-llvm-components: x86 + +// Ensure a catch-all generates: +// - `catchpad ... [ptr null]` on Wasm (otherwise LLVM gets confused) +// - `catchpad ... [ptr null, i32 64, ptr null]` on Windows (otherwise we catch SEH exceptions) + +#![feature(no_core, lang_items, rustc_attrs)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} + +unsafe extern "C-unwind" { + safe fn unwinds(); +} + +#[lang = "panic_cannot_unwind"] +fn panic_cannot_unwind() -> ! { + loop {} +} + +#[no_mangle] +#[rustc_nounwind] +pub fn doesnt_unwind() { + // emscripten: %catchpad = catchpad within %catchswitch [ptr null] + // wasi: %catchpad = catchpad within %catchswitch [ptr null] + // seh: %catchpad = catchpad within %catchswitch [ptr null, i32 64, ptr null] + unwinds(); +} diff --git a/tests/codegen-llvm/thread-local.rs b/tests/codegen-llvm/thread-local.rs new file mode 100644 index 00000000000..41df8c9be1b --- /dev/null +++ b/tests/codegen-llvm/thread-local.rs @@ -0,0 +1,54 @@ +//@ compile-flags: -Copt-level=3 +//@ aux-build:thread_local_aux.rs +//@ ignore-windows FIXME(#134939) +//@ ignore-wasm globals are used instead of thread locals +//@ ignore-emscripten globals are used instead of thread locals +//@ ignore-android does not use #[thread_local] +//@ ignore-nto does not use #[thread_local] + +#![crate_type = "lib"] + +extern crate thread_local_aux as aux; + +use std::cell::Cell; + +thread_local!(static A: Cell = const { Cell::new(1) }); + +// CHECK: [[TLS_AUX:@.+]] = external thread_local{{.*}} global i64 +// CHECK: [[TLS:@.+]] = internal thread_local{{.*}} global + +// CHECK-LABEL: @get +#[no_mangle] +fn get() -> u32 { + // CHECK: [[PTR:%.+]] = tail call {{.*}} ptr @llvm.threadlocal.address.p0(ptr [[TLS]]) + // CHECK-NEXT: [[RET_0:%.+]] = load i32, ptr [[PTR]] + // CHECK-NEXT: ret i32 [[RET_0]] + A.with(|a| a.get()) +} + +// CHECK-LABEL: @set +#[no_mangle] +fn set(v: u32) { + // CHECK: [[PTR:%.+]] = tail call {{.*}} ptr @llvm.threadlocal.address.p0(ptr [[TLS]]) + // CHECK-NEXT: store i32 %0, ptr [[PTR]] + // CHECK-NEXT: ret void + A.with(|a| a.set(v)) +} + +// CHECK-LABEL: @get_aux +#[no_mangle] +fn get_aux() -> u64 { + // CHECK: [[PTR:%.+]] = tail call {{.*}} ptr @llvm.threadlocal.address.p0(ptr [[TLS_AUX]]) + // CHECK-NEXT: [[RET_1:%.+]] = load i64, ptr [[PTR]] + // CHECK-NEXT: ret i64 [[RET_1]] + aux::A.with(|a| a.get()) +} + +// CHECK-LABEL: @set_aux +#[no_mangle] +fn set_aux(v: u64) { + // CHECK: [[PTR:%.+]] = tail call {{.*}} ptr @llvm.threadlocal.address.p0(ptr [[TLS_AUX]]) + // CHECK-NEXT: store i64 %0, ptr [[PTR]] + // CHECK-NEXT: ret void + aux::A.with(|a| a.set(v)) +} diff --git a/tests/codegen-llvm/tied-features-strength.rs b/tests/codegen-llvm/tied-features-strength.rs new file mode 100644 index 00000000000..81499c070d1 --- /dev/null +++ b/tests/codegen-llvm/tied-features-strength.rs @@ -0,0 +1,34 @@ +// ignore-tidy-linelength +//@ add-core-stubs +//@ revisions: ENABLE_SVE DISABLE_SVE DISABLE_NEON ENABLE_NEON +//@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu +//@ needs-llvm-components: aarch64 + +// Rust made SVE require neon. +//@ [ENABLE_SVE] compile-flags: -C target-feature=+sve -Copt-level=0 +// ENABLE_SVE: attributes #0 +// ENABLE_SVE-SAME: +neon +// ENABLE_SVE-SAME: +sve + +// However, disabling SVE does not disable neon. +//@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0 +// DISABLE_SVE: attributes #0 +// DISABLE_SVE-NOT: -neon +// DISABLE_SVE-SAME: -sve + +// OTOH, neon fn `fp-armv8` are fully tied; toggling neon must toggle `fp-armv8` the same way. +//@ [DISABLE_NEON] compile-flags: -C target-feature=-neon -Copt-level=0 +// DISABLE_NEON: attributes #0 +// DISABLE_NEON-SAME: -neon +// DISABLE_NEON-SAME: -fp-armv8 + +//@ [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0 +// ENABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fp-armv8,?)|(\+neon,?))*}}" } + +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +pub fn test() {} diff --git a/tests/codegen-llvm/to_vec.rs b/tests/codegen-llvm/to_vec.rs new file mode 100644 index 00000000000..4f6e77188d8 --- /dev/null +++ b/tests/codegen-llvm/to_vec.rs @@ -0,0 +1,10 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @copy_to_vec +#[no_mangle] +fn copy_to_vec(s: &[u64]) -> Vec { + s.to_vec() + // CHECK: call void @llvm.memcpy +} diff --git a/tests/codegen-llvm/trailing_zeros.rs b/tests/codegen-llvm/trailing_zeros.rs new file mode 100644 index 00000000000..0816a980992 --- /dev/null +++ b/tests/codegen-llvm/trailing_zeros.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @trailing_zeros_ge +#[no_mangle] +pub fn trailing_zeros_ge(val: u32) -> bool { + // CHECK: %[[AND:.*]] = and i32 %val, 7 + // CHECK: %[[ICMP:.*]] = icmp eq i32 %[[AND]], 0 + // CHECK: ret i1 %[[ICMP]] + val.trailing_zeros() >= 3 +} + +// CHECK-LABEL: @trailing_zeros_gt +#[no_mangle] +pub fn trailing_zeros_gt(val: u64) -> bool { + // CHECK: %[[AND:.*]] = and i64 %val, 15 + // CHECK: %[[ICMP:.*]] = icmp eq i64 %[[AND]], 0 + // CHECK: ret i1 %[[ICMP]] + val.trailing_zeros() > 3 +} diff --git a/tests/codegen-llvm/transmute-optimized.rs b/tests/codegen-llvm/transmute-optimized.rs new file mode 100644 index 00000000000..477fdc6de90 --- /dev/null +++ b/tests/codegen-llvm/transmute-optimized.rs @@ -0,0 +1,120 @@ +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled +#![crate_type = "lib"] + +// This tests that LLVM can optimize based on the niches in the source or +// destination types for transmutes. + +#[repr(u32)] +pub enum AlwaysZero32 { + X = 0, +} + +// CHECK-LABEL: i32 @issue_109958(i32 +#[no_mangle] +pub fn issue_109958(x: AlwaysZero32) -> i32 { + // CHECK: ret i32 0 + unsafe { std::mem::transmute(x) } +} + +// CHECK-LABEL: i1 @reference_is_null(ptr +#[no_mangle] +pub fn reference_is_null(x: &i32) -> bool { + // CHECK: ret i1 false + let p: *const i32 = unsafe { std::mem::transmute(x) }; + p.is_null() +} + +// CHECK-LABEL: i1 @non_null_is_null(ptr +#[no_mangle] +pub fn non_null_is_null(x: std::ptr::NonNull) -> bool { + // CHECK: ret i1 false + let p: *const i32 = unsafe { std::mem::transmute(x) }; + p.is_null() +} + +// CHECK-LABEL: i1 @non_zero_is_null( +#[no_mangle] +pub fn non_zero_is_null(x: std::num::NonZero) -> bool { + // CHECK: ret i1 false + let p: *const i32 = unsafe { std::mem::transmute(x) }; + p.is_null() +} + +// CHECK-LABEL: i1 @non_null_is_zero(ptr +#[no_mangle] +pub fn non_null_is_zero(x: std::ptr::NonNull) -> bool { + // CHECK: ret i1 false + let a: isize = unsafe { std::mem::transmute(x) }; + a == 0 +} + +// CHECK-LABEL: i1 @bool_ordering_is_ge(i1 +#[no_mangle] +pub fn bool_ordering_is_ge(x: bool) -> bool { + // CHECK: ret i1 true + let y: std::cmp::Ordering = unsafe { std::mem::transmute(x) }; + y.is_ge() +} + +// CHECK-LABEL: i1 @ordering_is_ge_then_transmute_to_bool(i8 +#[no_mangle] +pub fn ordering_is_ge_then_transmute_to_bool(x: std::cmp::Ordering) -> bool { + let r = x.is_ge(); + let _: bool = unsafe { std::mem::transmute(x) }; + r +} + +// CHECK-LABEL: i32 @normal_div(i32 +#[no_mangle] +pub fn normal_div(a: u32, b: u32) -> u32 { + // CHECK: call core::panicking::panic + a / b +} + +// CHECK-LABEL: i32 @div_transmute_nonzero(i32 +#[no_mangle] +pub fn div_transmute_nonzero(a: u32, b: std::num::NonZero) -> u32 { + // CHECK-NOT: call core::panicking::panic + // CHECK: %[[R:.+]] = udiv i32 %a, %b + // CHECK-NEXT: ret i32 %[[R]] + // CHECK-NOT: call core::panicking::panic + let d: u32 = unsafe { std::mem::transmute(b) }; + a / d +} + +#[repr(i8)] +pub enum OneTwoThree { + One = 1, + Two = 2, + Three = 3, +} + +// CHECK-LABEL: i8 @ordering_transmute_onetwothree(i8 +#[no_mangle] +pub unsafe fn ordering_transmute_onetwothree(x: std::cmp::Ordering) -> OneTwoThree { + // CHECK: ret i8 1 + std::mem::transmute(x) +} + +// CHECK-LABEL: i8 @onetwothree_transmute_ordering(i8 +#[no_mangle] +pub unsafe fn onetwothree_transmute_ordering(x: OneTwoThree) -> std::cmp::Ordering { + // CHECK: ret i8 1 + std::mem::transmute(x) +} + +// CHECK-LABEL: i1 @char_is_negative(i32 +#[no_mangle] +pub fn char_is_negative(c: char) -> bool { + // CHECK: ret i1 false + let x: i32 = unsafe { std::mem::transmute(c) }; + x < 0 +} + +// CHECK-LABEL: i1 @transmute_to_char_is_negative(i32 +#[no_mangle] +pub fn transmute_to_char_is_negative(x: i32) -> bool { + // CHECK: ret i1 false + let _c: char = unsafe { std::mem::transmute(x) }; + x < 0 +} diff --git a/tests/codegen-llvm/transmute-scalar.rs b/tests/codegen-llvm/transmute-scalar.rs new file mode 100644 index 00000000000..ce1b0558b2e --- /dev/null +++ b/tests/codegen-llvm/transmute-scalar.rs @@ -0,0 +1,143 @@ +//@ add-core-stubs +//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(no_core, repr_simd, arm_target_feature, mips_target_feature, s390x_target_feature)] +#![no_core] +extern crate minicore; + +use minicore::*; + +// With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type, +// without needing to pointercast, and SRoA will turn that into a `bitcast`. +// Thus memory-to-memory transmutes don't need to generate them ourselves. + +// However, `bitcast`s and `ptrtoint`s and `inttoptr`s are still worth doing when +// that allows us to avoid the `alloca`s entirely; see `rvalue_creates_operand`. + +// CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float %x) +// CHECK: %_0 = bitcast float %x to i32 +// CHECK-NEXT: ret i32 %_0 +#[no_mangle] +pub fn f32_to_bits(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +// CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 zeroext %b) +// CHECK: %_0 = zext i1 %b to i8 +// CHECK-NEXT: ret i8 %_0 +#[no_mangle] +pub fn bool_to_byte(b: bool) -> u8 { + unsafe { mem::transmute(b) } +} + +// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte) +// CHECK: %_0 = trunc{{( nuw)?}} i8 %byte to i1 +// CHECK-NEXT: ret i1 %_0 +#[no_mangle] +pub unsafe fn byte_to_bool(byte: u8) -> bool { + mem::transmute(byte) +} + +// CHECK-LABEL: define{{.*}}ptr @ptr_to_ptr(ptr %p) +// CHECK: ret ptr %p +#[no_mangle] +pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 { + unsafe { mem::transmute(p) } +} + +// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int(ptr %p) +// CHECK: %_0 = ptrtoint ptr %p to [[USIZE]] +// CHECK-NEXT: ret [[USIZE]] %_0 +#[no_mangle] +pub fn ptr_to_int(p: *mut u16) -> usize { + unsafe { mem::transmute(p) } +} + +// CHECK: define{{.*}}ptr @int_to_ptr([[USIZE]] %i) +// CHECK: %_0 = getelementptr i8, ptr null, [[USIZE]] %i +// CHECK-NEXT: ret ptr %_0 +#[no_mangle] +pub fn int_to_ptr(i: usize) -> *mut u16 { + unsafe { mem::transmute(i) } +} + +// This is the one case where signedness matters to transmuting: +// the LLVM type is `i8` here because of `repr(i8)`, +// whereas below with the `repr(u8)` it's `i1` in LLVM instead. +#[repr(i8)] +pub enum FakeBoolSigned { + False = 0, + True = 1, +} + +// CHECK-LABEL: define{{.*}}i8 @bool_to_fake_bool_signed(i1 zeroext %b) +// CHECK: %_0 = zext i1 %b to i8 +// CHECK-NEXT: ret i8 %_0 +#[no_mangle] +pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned { + unsafe { mem::transmute(b) } +} + +// CHECK-LABEL: define{{.*}}i1 @fake_bool_signed_to_bool(i8 %b) +// CHECK: %_0 = trunc nuw i8 %b to i1 +// CHECK-NEXT: ret i1 %_0 +#[no_mangle] +pub fn fake_bool_signed_to_bool(b: FakeBoolSigned) -> bool { + unsafe { mem::transmute(b) } +} + +#[repr(u8)] +pub enum FakeBoolUnsigned { + False = 0, + True = 1, +} + +// CHECK-LABEL: define{{.*}}i1 @bool_to_fake_bool_unsigned(i1 zeroext %b) +// CHECK: ret i1 %b +#[no_mangle] +pub fn bool_to_fake_bool_unsigned(b: bool) -> FakeBoolUnsigned { + unsafe { mem::transmute(b) } +} + +// CHECK-LABEL: define{{.*}}i1 @fake_bool_unsigned_to_bool(i1 zeroext %b) +// CHECK: ret i1 %b +#[no_mangle] +pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool { + unsafe { mem::transmute(b) } +} + +#[repr(simd)] +struct S([i64; 1]); + +// CHECK-LABEL: define{{.*}}i64 @single_element_simd_to_scalar(<1 x i64> %b) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[RET:.+]] = alloca [8 x i8] +// CHECK-NEXT: store <1 x i64> %b, ptr %[[RET]] +// CHECK-NEXT: %[[TEMP:.+]] = load i64, ptr %[[RET]] +// CHECK-NEXT: ret i64 %[[TEMP]] +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +pub extern "C" fn single_element_simd_to_scalar(b: S) -> i64 { + unsafe { mem::transmute(b) } +} + +// CHECK-LABEL: define{{.*}}<1 x i64> @scalar_to_single_element_simd(i64 %b) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[RET:.+]] = alloca [8 x i8] +// CHECK-NEXT: store i64 %b, ptr %[[RET]] +// CHECK-NEXT: %[[TEMP:.+]] = load <1 x i64>, ptr %[[RET]] +// CHECK-NEXT: ret <1 x i64> %[[TEMP]] +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +pub extern "C" fn scalar_to_single_element_simd(b: i64) -> S { + unsafe { mem::transmute(b) } +} diff --git a/tests/codegen-llvm/try_question_mark_nop.rs b/tests/codegen-llvm/try_question_mark_nop.rs new file mode 100644 index 00000000000..398c9a580bc --- /dev/null +++ b/tests/codegen-llvm/try_question_mark_nop.rs @@ -0,0 +1,243 @@ +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled +//@ edition: 2021 +//@ only-x86_64 +//@ revisions: NINETEEN TWENTY +//@[NINETEEN] exact-llvm-major-version: 19 +//@[TWENTY] min-llvm-version: 20 + +#![crate_type = "lib"] +#![feature(try_blocks)] + +use std::ops::ControlFlow::{self, Break, Continue}; +use std::ptr::NonNull; + +// CHECK-LABEL: @option_nop_match_32 +#[no_mangle] +pub fn option_nop_match_32(x: Option) -> Option { + // CHECK: start: + // CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i32 %0 to i1 + + // NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %0, i32 0 + // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 [[SELECT]], 0 + // NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 %1, 1 + + // TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %1, i32 undef + // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0 + // TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 [[SELECT]], 1 + + // CHECK-NEXT: ret { i32, i32 } [[REG3]] + match x { + Some(x) => Some(x), + None => None, + } +} + +// CHECK-LABEL: @option_nop_traits_32 +#[no_mangle] +pub fn option_nop_traits_32(x: Option) -> Option { + // CHECK: start: + // TWENTY-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %0 to i1 + // TWENTY-NEXT: select i1 %[[IS_SOME]], i32 %1, i32 undef + // CHECK-NEXT: insertvalue { i32, i32 } + // CHECK-NEXT: insertvalue { i32, i32 } + // CHECK-NEXT: ret { i32, i32 } + try { x? } +} + +// CHECK-LABEL: @result_nop_match_32 +#[no_mangle] +pub fn result_nop_match_32(x: Result) -> Result { + // CHECK: start: + // CHECK-NEXT: insertvalue { i32, i32 } + // CHECK-NEXT: insertvalue { i32, i32 } + // CHECK-NEXT: ret { i32, i32 } + match x { + Ok(x) => Ok(x), + Err(x) => Err(x), + } +} + +// CHECK-LABEL: @result_nop_traits_32 +#[no_mangle] +pub fn result_nop_traits_32(x: Result) -> Result { + // CHECK: start: + // CHECK-NEXT: insertvalue { i32, i32 } + // CHECK-NEXT: insertvalue { i32, i32 } + // CHECK-NEXT: ret { i32, i32 } + try { x? } +} + +// CHECK-LABEL: @control_flow_nop_match_32 +#[no_mangle] +pub fn control_flow_nop_match_32(x: ControlFlow) -> ControlFlow { + // CHECK: start: + // CHECK-NEXT: insertvalue { i32, i32 } + // CHECK-NEXT: insertvalue { i32, i32 } + // CHECK-NEXT: ret { i32, i32 } + match x { + Continue(x) => Continue(x), + Break(x) => Break(x), + } +} + +// CHECK-LABEL: @control_flow_nop_traits_32 +#[no_mangle] +pub fn control_flow_nop_traits_32(x: ControlFlow) -> ControlFlow { + // CHECK: start: + // CHECK-NEXT: insertvalue { i32, i32 } + // CHECK-NEXT: insertvalue { i32, i32 } + // CHECK-NEXT: ret { i32, i32 } + try { x? } +} + +// CHECK-LABEL: @option_nop_match_64 +#[no_mangle] +pub fn option_nop_match_64(x: Option) -> Option { + // CHECK: start: + // CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i64 %0 to i1 + + // NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %0, i64 0 + // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 [[SELECT]], 0 + // NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 %1, 1 + + // TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %1, i64 undef + // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 %0, 0 + // TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 [[SELECT]], 1 + + // CHECK-NEXT: ret { i64, i64 } [[REG3]] + match x { + Some(x) => Some(x), + None => None, + } +} + +// CHECK-LABEL: @option_nop_traits_64 +#[no_mangle] +pub fn option_nop_traits_64(x: Option) -> Option { + // CHECK: start: + // TWENTY-NEXT: %[[TRUNC:[0-9]+]] = trunc nuw i64 %0 to i1 + // TWENTY-NEXT: %[[SEL:\.[0-9]+]] = select i1 %[[TRUNC]], i64 %1, i64 undef + // CHECK-NEXT: insertvalue { i64, i64 } + // CHECK-NEXT: insertvalue { i64, i64 } + // CHECK-NEXT: ret { i64, i64 } + try { x? } +} + +// CHECK-LABEL: @result_nop_match_64 +#[no_mangle] +pub fn result_nop_match_64(x: Result) -> Result { + // CHECK: start: + // CHECK-NEXT: insertvalue { i64, i64 } + // CHECK-NEXT: insertvalue { i64, i64 } + // CHECK-NEXT: ret { i64, i64 } + match x { + Ok(x) => Ok(x), + Err(x) => Err(x), + } +} + +// CHECK-LABEL: @result_nop_traits_64 +#[no_mangle] +pub fn result_nop_traits_64(x: Result) -> Result { + // CHECK: start: + // CHECK-NEXT: insertvalue { i64, i64 } + // CHECK-NEXT: insertvalue { i64, i64 } + // CHECK-NEXT: ret { i64, i64 } + try { x? } +} + +// CHECK-LABEL: @control_flow_nop_match_64 +#[no_mangle] +pub fn control_flow_nop_match_64(x: ControlFlow) -> ControlFlow { + // CHECK: start: + // CHECK-NEXT: insertvalue { i64, i64 } + // CHECK-NEXT: insertvalue { i64, i64 } + // CHECK-NEXT: ret { i64, i64 } + match x { + Continue(x) => Continue(x), + Break(x) => Break(x), + } +} + +// CHECK-LABEL: @control_flow_nop_traits_64 +#[no_mangle] +pub fn control_flow_nop_traits_64(x: ControlFlow) -> ControlFlow { + // CHECK: start: + // CHECK-NEXT: insertvalue { i64, i64 } + // CHECK-NEXT: insertvalue { i64, i64 } + // CHECK-NEXT: ret { i64, i64 } + try { x? } +} + +// CHECK-LABEL: @result_nop_match_128 +#[no_mangle] +pub fn result_nop_match_128(x: Result) -> Result { + // CHECK: start: + // CHECK-NEXT: store i128 + // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8 + // CHECK-NEXT: store i128 + // CHECK-NEXT: ret void + match x { + Ok(x) => Ok(x), + Err(x) => Err(x), + } +} + +// CHECK-LABEL: @result_nop_traits_128 +#[no_mangle] +pub fn result_nop_traits_128(x: Result) -> Result { + // CHECK: start: + // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8 + // CHECK-NEXT: store i128 + // CHECK-NEXT: store i128 + // CHECK-NEXT: ret void + try { x? } +} + +// CHECK-LABEL: @control_flow_nop_match_128 +#[no_mangle] +pub fn control_flow_nop_match_128(x: ControlFlow) -> ControlFlow { + // CHECK: start: + // CHECK-NEXT: store i128 + // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8 + // CHECK-NEXT: store i128 + // CHECK-NEXT: ret void + match x { + Continue(x) => Continue(x), + Break(x) => Break(x), + } +} + +// CHECK-LABEL: @control_flow_nop_traits_128 +#[no_mangle] +pub fn control_flow_nop_traits_128(x: ControlFlow) -> ControlFlow { + // CHECK: start: + // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8 + // CHECK-NEXT: store i128 + // CHECK-NEXT: store i128 + // CHECK-NEXT: ret void + try { x? } +} + +// CHECK-LABEL: @result_nop_match_ptr +#[no_mangle] +pub fn result_nop_match_ptr(x: Result>) -> Result> { + // CHECK: start: + // CHECK-NEXT: insertvalue { i{{[0-9]+}}, ptr } + // CHECK-NEXT: insertvalue { i{{[0-9]+}}, ptr } + // CHECK-NEXT: ret + match x { + Ok(x) => Ok(x), + Err(x) => Err(x), + } +} + +// CHECK-LABEL: @result_nop_traits_ptr +#[no_mangle] +pub fn result_nop_traits_ptr(x: Result>) -> Result> { + // CHECK: start: + // CHECK-NEXT: insertvalue { i{{[0-9]+}}, ptr } + // CHECK-NEXT: insertvalue { i{{[0-9]+}}, ptr } + // CHECK-NEXT: ret + try { x? } +} diff --git a/tests/codegen-llvm/tune-cpu-on-functions.rs b/tests/codegen-llvm/tune-cpu-on-functions.rs new file mode 100644 index 00000000000..f50245b797f --- /dev/null +++ b/tests/codegen-llvm/tune-cpu-on-functions.rs @@ -0,0 +1,21 @@ +// This test makes sure that functions get annotated with the proper +// "tune-cpu" attribute in LLVM. + +//@ no-prefer-dynamic +// +//@ compile-flags: -C no-prepopulate-passes -C panic=abort -C linker-plugin-lto -Cpasses=name-anon-globals -Z tune-cpu=generic -Copt-level=0 + +#![crate_type = "staticlib"] + +// CHECK-LABEL: define {{.*}} @exported() {{.*}} #0 +#[no_mangle] +pub extern "C" fn exported() { + not_exported(); +} + +// CHECK-LABEL: ; tune_cpu_on_functions::not_exported +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define {{.*}}() {{.*}} #0 +fn not_exported() {} + +// CHECK: attributes #0 = {{.*}} "tune-cpu"="{{.*}}" diff --git a/tests/codegen-llvm/tuple-layout-opt.rs b/tests/codegen-llvm/tuple-layout-opt.rs new file mode 100644 index 00000000000..5b2f65e7aa7 --- /dev/null +++ b/tests/codegen-llvm/tuple-layout-opt.rs @@ -0,0 +1,57 @@ +// 32-bit systems will return 128bit values using a return area pointer. +//@ revisions: bit32 bit64 +//@[bit32] only-32bit +//@[bit64] only-64bit +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 + +// Test that tuples get optimized layout, in particular with a ZST in the last field (#63244) + +#![crate_type = "lib"] + +type ScalarZstLast = (u128, ()); +// bit32: define {{(dso_local )?}}void @test_ScalarZstLast({{.*}} sret([16 x i8]) {{.*}}, i128 %_1) +// bit64: define {{(dso_local )?}}i128 @test_ScalarZstLast(i128 %_1) +#[no_mangle] +pub fn test_ScalarZstLast(_: ScalarZstLast) -> ScalarZstLast { + loop {} +} + +type ScalarZstFirst = ((), u128); +// bit32: define {{(dso_local )?}}void @test_ScalarZstFirst({{.*}} sret([16 x i8]) {{.*}}, i128 %_1) +// bit64: define {{(dso_local )?}}i128 @test_ScalarZstFirst(i128 %_1) +#[no_mangle] +pub fn test_ScalarZstFirst(_: ScalarZstFirst) -> ScalarZstFirst { + loop {} +} + +type ScalarPairZstLast = (u8, u128, ()); +// CHECK: define {{(dso_local )?}}void @test_ScalarPairZstLast(ptr sret({{[^,]*}}) +// CHECK-SAME: %_0, i128 %_1.0, i8 %_1.1) +#[no_mangle] +pub fn test_ScalarPairZstLast(_: ScalarPairZstLast) -> ScalarPairZstLast { + loop {} +} + +type ScalarPairZstFirst = ((), u8, u128); +// CHECK: define {{(dso_local )?}}void @test_ScalarPairZstFirst(ptr sret({{[^,]*}}) +// CHECK-SAME: %_0, i8 %_1.0, i128 %_1.1) +#[no_mangle] +pub fn test_ScalarPairZstFirst(_: ScalarPairZstFirst) -> ScalarPairZstFirst { + loop {} +} + +type ScalarPairLotsOfZsts = ((), u8, (), u128, ()); +// CHECK: define {{(dso_local )?}}void @test_ScalarPairLotsOfZsts(ptr sret({{[^,]*}}) +// CHECK-SAME: %_0, i128 %_1.0, i8 %_1.1) +#[no_mangle] +pub fn test_ScalarPairLotsOfZsts(_: ScalarPairLotsOfZsts) -> ScalarPairLotsOfZsts { + loop {} +} + +type ScalarPairLottaNesting = (((), ((), u8, (), u128, ())), ()); +// CHECK: define {{(dso_local )?}}void @test_ScalarPairLottaNesting(ptr sret({{[^,]*}}) +// CHECK-SAME: %_0, i128 %_1.0, i8 %_1.1) +#[no_mangle] +pub fn test_ScalarPairLottaNesting(_: ScalarPairLottaNesting) -> ScalarPairLottaNesting { + loop {} +} diff --git a/tests/codegen-llvm/ub-checks.rs b/tests/codegen-llvm/ub-checks.rs new file mode 100644 index 00000000000..67f5bff08d5 --- /dev/null +++ b/tests/codegen-llvm/ub-checks.rs @@ -0,0 +1,28 @@ +// With -Zub-checks=yes (enabled by default by -Cdebug-assertions=yes) we will produce a runtime +// check that the index to slice::get_unchecked is in-bounds of the slice. That is tested for by +// tests/ui/precondition-checks/out-of-bounds-get-unchecked.rs +// +// This test ensures that such a runtime check is *not* emitted when debug-assertions are enabled, +// but ub-checks are explicitly disabled. + +//@ revisions: DEBUG NOCHECKS +//@ [DEBUG] compile-flags: +//@ [NOCHECKS] compile-flags: -Zub-checks=no +//@ compile-flags: -Copt-level=3 -Cdebug-assertions=yes + +#![crate_type = "lib"] + +use std::ops::Range; + +// CHECK-LABEL: @slice_get_unchecked( +#[no_mangle] +pub unsafe fn slice_get_unchecked(x: &[i32], i: usize) -> &i32 { + // CHECK: icmp ult + // NOCHECKS: tail call void @llvm.assume + // DEBUG: br i1 + // DEBUG: call core::panicking::panic_nounwind + // DEBUG: unreachable + // CHECK: getelementptr inbounds + // CHECK: ret ptr + x.get_unchecked(i) +} diff --git a/tests/codegen-llvm/unchecked-float-casts.rs b/tests/codegen-llvm/unchecked-float-casts.rs new file mode 100644 index 00000000000..d1869abc87b --- /dev/null +++ b/tests/codegen-llvm/unchecked-float-casts.rs @@ -0,0 +1,36 @@ +// This file tests that we don't generate any code for saturation when using the +// unchecked intrinsics. + +//@ compile-flags: -C opt-level=3 +//@ ignore-wasm32 the wasm target is tested in `wasm_casts_*` + +#![crate_type = "lib"] + +// CHECK-LABEL: @f32_to_u32 +#[no_mangle] +pub fn f32_to_u32(x: f32) -> u32 { + // CHECK: fptoui + // CHECK-NOT: fcmp + // CHECK-NOT: icmp + // CHECK-NOT: select + unsafe { x.to_int_unchecked() } +} + +// CHECK-LABEL: @f32_to_i32 +#[no_mangle] +pub fn f32_to_i32(x: f32) -> i32 { + // CHECK: fptosi + // CHECK-NOT: fcmp + // CHECK-NOT: icmp + // CHECK-NOT: select + unsafe { x.to_int_unchecked() } +} + +#[no_mangle] +pub fn f64_to_u16(x: f64) -> u16 { + // CHECK: fptoui + // CHECK-NOT: fcmp + // CHECK-NOT: icmp + // CHECK-NOT: select + unsafe { x.to_int_unchecked() } +} diff --git a/tests/codegen-llvm/unchecked_shifts.rs b/tests/codegen-llvm/unchecked_shifts.rs new file mode 100644 index 00000000000..3f533718a2d --- /dev/null +++ b/tests/codegen-llvm/unchecked_shifts.rs @@ -0,0 +1,100 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes + +// This runs mir-opts to inline the standard library call, but doesn't run LLVM +// optimizations so it doesn't need to worry about them adding more flags. + +#![crate_type = "lib"] +#![feature(unchecked_shifts)] +#![feature(core_intrinsics)] + +// CHECK-LABEL: @unchecked_shl_unsigned_same +#[no_mangle] +pub unsafe fn unchecked_shl_unsigned_same(a: u32, b: u32) -> u32 { + // CHECK-NOT: assume + // CHECK-NOT: and i32 + // CHECK: shl i32 %a, %b + // CHECK-NOT: and i32 + a.unchecked_shl(b) +} + +// CHECK-LABEL: @unchecked_shl_unsigned_smaller +#[no_mangle] +pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 { + // CHECK-NOT: assume + // CHECK: %[[TRUNC:.+]] = trunc nuw i32 %b to i16 + // CHECK: shl i16 %a, %[[TRUNC]] + a.unchecked_shl(b) +} + +// CHECK-LABEL: @unchecked_shl_unsigned_bigger +#[no_mangle] +pub unsafe fn unchecked_shl_unsigned_bigger(a: u64, b: u32) -> u64 { + // CHECK-NOT: assume + // CHECK: %[[EXT:.+]] = zext i32 %b to i64 + // CHECK: shl i64 %a, %[[EXT]] + a.unchecked_shl(b) +} + +// CHECK-LABEL: @unchecked_shr_signed_same +#[no_mangle] +pub unsafe fn unchecked_shr_signed_same(a: i32, b: u32) -> i32 { + // CHECK-NOT: assume + // CHECK-NOT: and i32 + // CHECK: ashr i32 %a, %b + // CHECK-NOT: and i32 + a.unchecked_shr(b) +} + +// CHECK-LABEL: @unchecked_shr_signed_smaller +#[no_mangle] +pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 { + // CHECK-NOT: assume + // CHECK: %[[TRUNC:.+]] = trunc nuw i32 %b to i16 + // CHECK: ashr i16 %a, %[[TRUNC]] + a.unchecked_shr(b) +} + +// CHECK-LABEL: @unchecked_shr_signed_bigger +#[no_mangle] +pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 { + // CHECK-NOT: assume + // CHECK: %[[EXT:.+]] = zext i32 %b to i64 + // CHECK: ashr i64 %a, %[[EXT]] + a.unchecked_shr(b) +} + +// CHECK-LABEL: @unchecked_shr_u128_i8 +#[no_mangle] +pub unsafe fn unchecked_shr_u128_i8(a: u128, b: i8) -> u128 { + // CHECK-NOT: assume + // CHECK: %[[EXT:.+]] = zext i8 %b to i128 + // CHECK: lshr i128 %a, %[[EXT]] + std::intrinsics::unchecked_shr(a, b) +} + +// CHECK-LABEL: @unchecked_shl_i128_u8 +#[no_mangle] +pub unsafe fn unchecked_shl_i128_u8(a: i128, b: u8) -> i128 { + // CHECK-NOT: assume + // CHECK: %[[EXT:.+]] = zext i8 %b to i128 + // CHECK: shl i128 %a, %[[EXT]] + std::intrinsics::unchecked_shl(a, b) +} + +// CHECK-LABEL: @unchecked_shl_u8_i128 +#[no_mangle] +pub unsafe fn unchecked_shl_u8_i128(a: u8, b: i128) -> u8 { + // CHECK-NOT: assume + // CHECK: %[[TRUNC:.+]] = trunc nuw i128 %b to i8 + // CHECK: shl i8 %a, %[[TRUNC]] + std::intrinsics::unchecked_shl(a, b) +} + +// CHECK-LABEL: @unchecked_shr_i8_u128 +#[no_mangle] +pub unsafe fn unchecked_shr_i8_u128(a: i8, b: u128) -> i8 { + // CHECK-NOT: assume + // CHECK: %[[TRUNC:.+]] = trunc nuw i128 %b to i8 + // CHECK: ashr i8 %a, %[[TRUNC]] + std::intrinsics::unchecked_shr(a, b) +} diff --git a/tests/codegen-llvm/uninhabited-transparent-return-abi.rs b/tests/codegen-llvm/uninhabited-transparent-return-abi.rs new file mode 100644 index 00000000000..face1577c3f --- /dev/null +++ b/tests/codegen-llvm/uninhabited-transparent-return-abi.rs @@ -0,0 +1,44 @@ +//@ compile-flags: -Copt-level=3 + +// See https://github.com/rust-lang/rust/issues/135802 + +#![crate_type = "lib"] + +enum Void {} + +// Should be ABI-compatible with T, but wasn't prior to the PR adding this test. +#[repr(transparent)] +struct NoReturn(T, Void); + +// Returned by invisible reference (in most ABIs) +#[allow(dead_code)] +struct Large(u64, u64, u64); + +extern "Rust" { + fn opaque() -> NoReturn; + fn opaque_with_arg(rsi: u32) -> NoReturn; +} + +// CHECK-LABEL: @test_uninhabited_ret_by_ref +#[no_mangle] +pub fn test_uninhabited_ret_by_ref() { + // CHECK: %_1 = alloca [24 x i8], align {{8|4}} + // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %_1) + // CHECK-NEXT: call void @opaque({{.*}} sret([24 x i8]) {{.*}} %_1) #2 + // CHECK-NEXT: unreachable + unsafe { + opaque(); + } +} + +// CHECK-LABEL: @test_uninhabited_ret_by_ref_with_arg +#[no_mangle] +pub fn test_uninhabited_ret_by_ref_with_arg(rsi: u32) { + // CHECK: %_2 = alloca [24 x i8], align {{8|4}} + // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %_2) + // CHECK-NEXT: call void @opaque_with_arg({{.*}} sret([24 x i8]) {{.*}} %_2, i32 noundef %rsi) #2 + // CHECK-NEXT: unreachable + unsafe { + opaque_with_arg(rsi); + } +} diff --git a/tests/codegen-llvm/uninit-consts.rs b/tests/codegen-llvm/uninit-consts.rs new file mode 100644 index 00000000000..bde71a35c47 --- /dev/null +++ b/tests/codegen-llvm/uninit-consts.rs @@ -0,0 +1,54 @@ +//@ compile-flags: -C no-prepopulate-passes + +// Check that we use undef (and not zero) for uninitialized bytes in constants. + +#![crate_type = "lib"] + +use std::mem::MaybeUninit; + +pub struct PartiallyUninit { + x: u32, + y: MaybeUninit<[u8; 10]>, +} + +// CHECK: [[FULLY_UNINIT:@.*]] = private unnamed_addr constant [10 x i8] undef + +// CHECK: [[PARTIALLY_UNINIT:@.*]] = private unnamed_addr constant <{ [4 x i8], [12 x i8] }> <{ [4 x i8] c"{{\\EF\\BE\\AD\\DE|\\DE\\AD\\BE\\EF}}", [12 x i8] undef }>, align 4 + +// This shouldn't contain undef, since it contains more chunks +// than the default value of uninit_const_chunk_threshold. +// CHECK: [[UNINIT_PADDING_HUGE:@.*]] = private unnamed_addr constant [32768 x i8] c"{{.+}}", align 4 + +// CHECK: [[FULLY_UNINIT_HUGE:@.*]] = private unnamed_addr constant [16384 x i8] undef + +// CHECK-LABEL: @fully_uninit +#[no_mangle] +pub const fn fully_uninit() -> MaybeUninit<[u8; 10]> { + const M: MaybeUninit<[u8; 10]> = MaybeUninit::uninit(); + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %_0, ptr align 1 {{.*}}[[FULLY_UNINIT]]{{.*}}, i{{(32|64)}} 10, i1 false) + M +} + +// CHECK-LABEL: @partially_uninit +#[no_mangle] +pub const fn partially_uninit() -> PartiallyUninit { + const X: PartiallyUninit = PartiallyUninit { x: 0xdeadbeef, y: MaybeUninit::uninit() }; + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[PARTIALLY_UNINIT]]{{.*}}, i{{(32|64)}} 16, i1 false) + X +} + +// CHECK-LABEL: @uninit_padding_huge +#[no_mangle] +pub const fn uninit_padding_huge() -> [(u32, u8); 4096] { + const X: [(u32, u8); 4096] = [(123, 45); 4096]; + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[UNINIT_PADDING_HUGE]]{{.*}}, i{{(32|64)}} 32768, i1 false) + X +} + +// CHECK-LABEL: @fully_uninit_huge +#[no_mangle] +pub const fn fully_uninit_huge() -> MaybeUninit<[u32; 4096]> { + const F: MaybeUninit<[u32; 4096]> = MaybeUninit::uninit(); + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[FULLY_UNINIT_HUGE]]{{.*}}, i{{(32|64)}} 16384, i1 false) + F +} diff --git a/tests/codegen-llvm/uninit-repeat-in-aggregate.rs b/tests/codegen-llvm/uninit-repeat-in-aggregate.rs new file mode 100644 index 00000000000..0fa2eb7d56c --- /dev/null +++ b/tests/codegen-llvm/uninit-repeat-in-aggregate.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +use std::mem::MaybeUninit; + +// We need to make sure len is at offset 0, otherwise codegen needs an extra instruction +#[repr(C)] +pub struct SmallVec { + pub len: u64, + pub arr: [MaybeUninit; 24], +} + +// CHECK-LABEL: @uninit_arr_via_const +#[no_mangle] +pub fn uninit_arr_via_const() -> SmallVec { + // CHECK-NEXT: start: + // CHECK-NEXT: store i64 0, + // CHECK-NEXT: ret + SmallVec { len: 0, arr: [const { MaybeUninit::uninit() }; 24] } +} diff --git a/tests/codegen-llvm/union-abi.rs b/tests/codegen-llvm/union-abi.rs new file mode 100644 index 00000000000..28acc4de2f3 --- /dev/null +++ b/tests/codegen-llvm/union-abi.rs @@ -0,0 +1,145 @@ +//@ ignore-emscripten vectors passed directly +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes +// 32-bit x86 returns `f32` differently to avoid the x87 stack. +// 32-bit systems will return 128bit values using a return area pointer. +//@ revisions: x86-sse x86-nosse bit32 bit64 +//@[x86-sse] only-x86 +//@[x86-sse] only-rustc_abi-x86-sse2 +//@[x86-nosse] only-x86 +//@[x86-nosse] ignore-rustc_abi-x86-sse2 +//@[bit32] ignore-x86 +//@[bit32] only-32bit +//@[bit64] ignore-x86 +//@[bit64] only-64bit + +// This test that using union forward the abi of the inner type, as +// discussed in #54668 + +#![crate_type = "lib"] +#![feature(repr_simd)] + +#[derive(Copy, Clone)] +pub enum Unhab {} + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct i64x4([i64; 4]); + +#[derive(Copy, Clone)] +pub union UnionI64x4 { + a: (), + b: i64x4, +} + +// CHECK: define {{(dso_local )?}}void @test_UnionI64x4(ptr {{.*}} %_1) +#[no_mangle] +pub fn test_UnionI64x4(_: UnionI64x4) { + loop {} +} + +pub union UnionI64x4_ { + a: i64x4, + b: (), + c: i64x4, + d: Unhab, + e: ((), ()), + f: UnionI64x4, +} + +// CHECK: define {{(dso_local )?}}void @test_UnionI64x4_(ptr {{.*}} %_1) +#[no_mangle] +pub fn test_UnionI64x4_(_: UnionI64x4_) { + loop {} +} + +pub union UnionI64x4I64 { + a: i64x4, + b: i64, +} + +// CHECK: define {{(dso_local )?}}void @test_UnionI64x4I64(ptr {{.*}} %_1) +#[no_mangle] +pub fn test_UnionI64x4I64(_: UnionI64x4I64) { + loop {} +} + +pub union UnionI64x4Tuple { + a: i64x4, + b: (i64, i64, i64, i64), +} + +// CHECK: define {{(dso_local )?}}void @test_UnionI64x4Tuple(ptr {{.*}} %_1) +#[no_mangle] +pub fn test_UnionI64x4Tuple(_: UnionI64x4Tuple) { + loop {} +} + +pub union UnionF32 { + a: f32, +} + +// x86-sse: define {{(dso_local )?}}<4 x i8> @test_UnionF32(float %_1) +// x86-nosse: define {{(dso_local )?}}i32 @test_UnionF32(float %_1) +// bit32: define {{(dso_local )?}}float @test_UnionF32(float %_1) +// bit64: define {{(dso_local )?}}float @test_UnionF32(float %_1) +#[no_mangle] +pub fn test_UnionF32(_: UnionF32) -> UnionF32 { + loop {} +} + +pub union UnionF32F32 { + a: f32, + b: f32, +} + +// x86-sse: define {{(dso_local )?}}<4 x i8> @test_UnionF32F32(float %_1) +// x86-nosse: define {{(dso_local )?}}i32 @test_UnionF32F32(float %_1) +// bit32: define {{(dso_local )?}}float @test_UnionF32F32(float %_1) +// bit64: define {{(dso_local )?}}float @test_UnionF32F32(float %_1) +#[no_mangle] +pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { + loop {} +} + +pub union UnionF32U32 { + a: f32, + b: u32, +} + +// CHECK: define {{(dso_local )?}}i32 @test_UnionF32U32(i32{{( %0)?}}) +#[no_mangle] +pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { + loop {} +} + +pub union UnionU128 { + a: u128, +} +// x86-sse: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1) +// x86-nosse: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1) +// bit32: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1) +// bit64: define {{(dso_local )?}}i128 @test_UnionU128(i128 %_1) +#[no_mangle] +pub fn test_UnionU128(_: UnionU128) -> UnionU128 { + loop {} +} + +#[repr(C)] +pub union CUnionU128 { + a: u128, +} +// CHECK: define {{(dso_local )?}}void @test_CUnionU128(ptr {{.*}} %_1) +#[no_mangle] +pub fn test_CUnionU128(_: CUnionU128) { + loop {} +} + +pub union UnionBool { + b: bool, +} +// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8{{.*}} %b) +#[no_mangle] +pub fn test_UnionBool(b: UnionBool) -> bool { + unsafe { b.b } +} +// CHECK: %_0 = trunc{{( nuw)?}} i8 %b to i1 diff --git a/tests/codegen-llvm/union-aggregate.rs b/tests/codegen-llvm/union-aggregate.rs new file mode 100644 index 00000000000..aac66c5dcdd --- /dev/null +++ b/tests/codegen-llvm/union-aggregate.rs @@ -0,0 +1,108 @@ +//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes +//@ min-llvm-version: 19 +//@ only-64bit + +#![crate_type = "lib"] +#![feature(transparent_unions)] +#![feature(repr_simd)] + +#[repr(transparent)] +union MU { + uninit: (), + value: T, +} + +use std::cmp::Ordering; +use std::num::NonZero; +use std::ptr::NonNull; + +#[no_mangle] +fn make_mu_bool(x: bool) -> MU { + // CHECK-LABEL: i8 @make_mu_bool(i1 zeroext %x) + // CHECK-NEXT: start: + // CHECK-NEXT: %[[WIDER:.+]] = zext i1 %x to i8 + // CHECK-NEXT: ret i8 %[[WIDER]] + MU { value: x } +} + +#[no_mangle] +fn make_mu_bool_uninit() -> MU { + // CHECK-LABEL: i8 @make_mu_bool_uninit() + // CHECK-NEXT: start: + // CHECK-NEXT: ret i8 undef + MU { uninit: () } +} + +#[no_mangle] +fn make_mu_ref(x: &u16) -> MU<&u16> { + // CHECK-LABEL: ptr @make_mu_ref(ptr align 2 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: ret ptr %x + MU { value: x } +} + +#[no_mangle] +fn make_mu_ref_uninit<'a>() -> MU<&'a u16> { + // CHECK-LABEL: ptr @make_mu_ref_uninit() + // CHECK-NEXT: start: + // CHECK-NEXT: ret ptr undef + MU { uninit: () } +} + +#[no_mangle] +fn make_mu_str(x: &str) -> MU<&str> { + // CHECK-LABEL: { ptr, i64 } @make_mu_str(ptr align 1 %x.0, i64 %x.1) + // CHECK-NEXT: start: + // CHECK-NEXT: %0 = insertvalue { ptr, i64 } poison, ptr %x.0, 0 + // CHECK-NEXT: %1 = insertvalue { ptr, i64 } %0, i64 %x.1, 1 + // CHECK-NEXT: ret { ptr, i64 } %1 + MU { value: x } +} + +#[no_mangle] +fn make_mu_str_uninit<'a>() -> MU<&'a str> { + // CHECK-LABEL: { ptr, i64 } @make_mu_str_uninit() + // CHECK-NEXT: start: + // CHECK-NEXT: ret { ptr, i64 } undef + MU { uninit: () } +} + +#[no_mangle] +fn make_mu_pair(x: (u8, u32)) -> MU<(u8, u32)> { + // CHECK-LABEL: { i8, i32 } @make_mu_pair(i8 %x.0, i32 %x.1) + // CHECK-NEXT: start: + // CHECK-NEXT: %0 = insertvalue { i8, i32 } poison, i8 %x.0, 0 + // CHECK-NEXT: %1 = insertvalue { i8, i32 } %0, i32 %x.1, 1 + // CHECK-NEXT: ret { i8, i32 } %1 + MU { value: x } +} + +#[no_mangle] +fn make_mu_pair_uninit() -> MU<(u8, u32)> { + // CHECK-LABEL: { i8, i32 } @make_mu_pair_uninit() + // CHECK-NEXT: start: + // CHECK-NEXT: ret { i8, i32 } undef + MU { uninit: () } +} + +#[repr(simd)] +#[derive(Copy, Clone)] +struct I32X32([i32; 32]); + +#[no_mangle] +fn make_mu_simd(x: I32X32) -> MU { + // CHECK-LABEL: void @make_mu_simd(ptr{{.+}}%_0, ptr{{.+}}%x) + // CHECK-NEXT: start: + // CHECK-NEXT: %[[TEMP:.+]] = load <32 x i32>, ptr %x, + // CHECK-NEXT: store <32 x i32> %[[TEMP]], ptr %_0, + // CHECK-NEXT: ret void + MU { value: x } +} + +#[no_mangle] +fn make_mu_simd_uninit() -> MU { + // CHECK-LABEL: void @make_mu_simd_uninit(ptr{{.+}}%_0) + // CHECK-NEXT: start: + // CHECK-NEXT: ret void + MU { uninit: () } +} diff --git a/tests/codegen-llvm/unwind-abis/aapcs-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/aapcs-unwind-abi.rs new file mode 100644 index 00000000000..ecace722e0d --- /dev/null +++ b/tests/codegen-llvm/unwind-abis/aapcs-unwind-abi.rs @@ -0,0 +1,36 @@ +//@ needs-llvm-components: arm +//@ compile-flags: --target=armv7-unknown-linux-gnueabihf --crate-type=rlib -Cno-prepopulate-passes +#![no_core] +#![feature(no_core, lang_items)] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} + +// Test that `nounwind` attributes are correctly applied to exported `aapcs` and +// `aapcs-unwind` extern functions. `aapcs-unwind` functions MUST NOT have this attribute. We +// disable optimizations above to prevent LLVM from inferring the attribute. + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "aapcs" fn rust_item_that_cannot_unwind() {} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "aapcs-unwind" fn rust_item_that_can_unwind() {} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs b/tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs new file mode 100644 index 00000000000..8d2745ba2f7 --- /dev/null +++ b/tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -C panic=abort + +// Test that `nounwind` attributes are also applied to extern `C-unwind` Rust functions +// when the code is compiled with `panic=abort`. + +#![crate_type = "lib"] + +// CHECK: @rust_item_that_can_unwind() unnamed_addr [[ATTR0:#[0-9]+]] +#[no_mangle] +pub unsafe extern "C-unwind" fn rust_item_that_can_unwind() { + // Handle both legacy and v0 symbol mangling. + // CHECK: call void @{{.*core9panicking19panic_cannot_unwind}} + may_unwind(); +} + +extern "C-unwind" { + // CHECK: @may_unwind() unnamed_addr [[ATTR1:#[0-9]+]] + fn may_unwind(); +} + +// Now, make sure that the LLVM attributes for this functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes [[ATTR0]] = { {{.*}}nounwind{{.*}} } +// +// Now, check that foreign item is correctly marked without the `nounwind` attribute. +// CHECK-NOT: attributes [[ATTR1]] = { {{.*}}nounwind{{.*}} } diff --git a/tests/codegen-llvm/unwind-abis/c-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/c-unwind-abi.rs new file mode 100644 index 00000000000..46c08b5fc4f --- /dev/null +++ b/tests/codegen-llvm/unwind-abis/c-unwind-abi.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -C opt-level=0 +//@ needs-unwind + +// Test that `nounwind` attributes are correctly applied to exported `C` and `C-unwind` extern +// functions. `C-unwind` functions MUST NOT have this attribute. We disable optimizations above +// to prevent LLVM from inferring the attribute. + +#![crate_type = "lib"] + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "C" fn rust_item_that_cannot_unwind() {} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "C-unwind" fn rust_item_that_can_unwind() {} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/tests/codegen-llvm/unwind-abis/cdecl-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/cdecl-unwind-abi.rs new file mode 100644 index 00000000000..8e643d6ce49 --- /dev/null +++ b/tests/codegen-llvm/unwind-abis/cdecl-unwind-abi.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -C opt-level=0 +//@ needs-unwind + +// Test that `nounwind` attributes are correctly applied to exported `cdecl` and +// `cdecl-unwind` extern functions. `cdecl-unwind` functions MUST NOT have this attribute. We +// disable optimizations above to prevent LLVM from inferring the attribute. + +#![crate_type = "lib"] + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "cdecl" fn rust_item_that_cannot_unwind() {} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "cdecl-unwind" fn rust_item_that_can_unwind() {} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/tests/codegen-llvm/unwind-abis/fastcall-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/fastcall-unwind-abi.rs new file mode 100644 index 00000000000..7df46813ed1 --- /dev/null +++ b/tests/codegen-llvm/unwind-abis/fastcall-unwind-abi.rs @@ -0,0 +1,36 @@ +//@ needs-llvm-components: x86 +//@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes +#![no_core] +#![feature(no_core, lang_items)] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} + +// Test that `nounwind` attributes are correctly applied to exported `fastcall` and +// `fastcall-unwind` extern functions. `fastcall-unwind` functions MUST NOT have this attribute. We +// disable optimizations above to prevent LLVM from inferring the attribute. + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "fastcall" fn rust_item_that_cannot_unwind() {} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "fastcall-unwind" fn rust_item_that_can_unwind() {} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/tests/codegen-llvm/unwind-abis/nounwind-on-stable-panic-abort.rs b/tests/codegen-llvm/unwind-abis/nounwind-on-stable-panic-abort.rs new file mode 100644 index 00000000000..d27cbd60437 --- /dev/null +++ b/tests/codegen-llvm/unwind-abis/nounwind-on-stable-panic-abort.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -C opt-level=0 -Cpanic=abort + +#![crate_type = "lib"] + +// We disable optimizations to prevent LLVM from inferring the attribute. + +// CHECK: Function Attrs:{{.*}}nounwind +// CHECK-NEXT: @foo +#[no_mangle] +pub extern "C" fn foo() {} + +// CHECK: Function Attrs:{{.*}}nounwind +// CHECK-NEXT: @bar +#[no_mangle] +pub fn bar() {} diff --git a/tests/codegen-llvm/unwind-abis/nounwind.rs b/tests/codegen-llvm/unwind-abis/nounwind.rs new file mode 100644 index 00000000000..e40ed48ca73 --- /dev/null +++ b/tests/codegen-llvm/unwind-abis/nounwind.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -C opt-level=0 -Cpanic=abort +//@ needs-unwind + +#![crate_type = "lib"] + +// We disable optimizations to prevent LLVM from inferring the attribute. + +// CHECK: Function Attrs:{{.*}}nounwind +// CHECK-NEXT: @foo +#[no_mangle] +pub extern "C" fn foo() {} + +// CHECK: Function Attrs:{{.*}}nounwind +// CHECK-NEXT: @bar +#[no_mangle] +pub fn bar() {} diff --git a/tests/codegen-llvm/unwind-abis/stdcall-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/stdcall-unwind-abi.rs new file mode 100644 index 00000000000..cc06ee12549 --- /dev/null +++ b/tests/codegen-llvm/unwind-abis/stdcall-unwind-abi.rs @@ -0,0 +1,36 @@ +//@ needs-llvm-components: x86 +//@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes +#![no_core] +#![feature(no_core, lang_items)] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} + +// Test that `nounwind` attributes are correctly applied to exported `stdcall` and `stdcall-unwind` +// extern functions. `stdcall-unwind` functions MUST NOT have this attribute. We disable +// optimizations above to prevent LLVM from inferring the attribute. + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "stdcall" fn rust_item_that_cannot_unwind() {} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "stdcall-unwind" fn rust_item_that_can_unwind() {} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/tests/codegen-llvm/unwind-abis/system-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/system-unwind-abi.rs new file mode 100644 index 00000000000..5f910248346 --- /dev/null +++ b/tests/codegen-llvm/unwind-abis/system-unwind-abi.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -C opt-level=0 +//@ needs-unwind + +// Test that `nounwind` attributes are correctly applied to exported `system` and `system-unwind` +// extern functions. `system-unwind` functions MUST NOT have this attribute. We disable +// optimizations above to prevent LLVM from inferring the attribute. + +#![crate_type = "lib"] + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "system" fn rust_item_that_cannot_unwind() {} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "system-unwind" fn rust_item_that_can_unwind() {} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/tests/codegen-llvm/unwind-abis/sysv64-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/sysv64-unwind-abi.rs new file mode 100644 index 00000000000..69bfaf80b4b --- /dev/null +++ b/tests/codegen-llvm/unwind-abis/sysv64-unwind-abi.rs @@ -0,0 +1,36 @@ +//@ needs-llvm-components: x86 +//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes +#![no_core] +#![feature(no_core, lang_items)] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} + +// Test that `nounwind` attributes are correctly applied to exported `sysv64` and +// `sysv64-unwind` extern functions. `sysv64-unwind` functions MUST NOT have this attribute. We +// disable optimizations above to prevent LLVM from inferring the attribute. + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "sysv64" fn rust_item_that_cannot_unwind() {} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "sysv64-unwind" fn rust_item_that_can_unwind() {} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/tests/codegen-llvm/unwind-abis/thiscall-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/thiscall-unwind-abi.rs new file mode 100644 index 00000000000..05f6b8b70e1 --- /dev/null +++ b/tests/codegen-llvm/unwind-abis/thiscall-unwind-abi.rs @@ -0,0 +1,36 @@ +//@ needs-llvm-components: x86 +//@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes +#![no_core] +#![feature(no_core, lang_items)] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} + +// Test that `nounwind` attributes are correctly applied to exported `thiscall` and +// `thiscall-unwind` extern functions. `thiscall-unwind` functions MUST NOT have this attribute. We +// disable optimizations above to prevent LLVM from inferring the attribute. + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "thiscall" fn rust_item_that_cannot_unwind() {} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "thiscall-unwind" fn rust_item_that_can_unwind() {} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/tests/codegen-llvm/unwind-abis/vectorcall-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/vectorcall-unwind-abi.rs new file mode 100644 index 00000000000..d001a16b32a --- /dev/null +++ b/tests/codegen-llvm/unwind-abis/vectorcall-unwind-abi.rs @@ -0,0 +1,36 @@ +//@ needs-llvm-components: x86 +//@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes +#![no_core] +#![feature(no_core, lang_items, abi_vectorcall)] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} + +// Test that `nounwind` attributes are correctly applied to exported `vectorcall` and +// `vectorcall-unwind` extern functions. `vectorcall-unwind` functions MUST NOT have this attribute. +// We disable optimizations above to prevent LLVM from inferring the attribute. + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "vectorcall" fn rust_item_that_cannot_unwind() {} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "vectorcall-unwind" fn rust_item_that_can_unwind() {} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/tests/codegen-llvm/unwind-abis/win64-unwind-abi.rs b/tests/codegen-llvm/unwind-abis/win64-unwind-abi.rs new file mode 100644 index 00000000000..257f00b54e4 --- /dev/null +++ b/tests/codegen-llvm/unwind-abis/win64-unwind-abi.rs @@ -0,0 +1,36 @@ +//@ needs-llvm-components: x86 +//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes +#![no_core] +#![feature(no_core, lang_items)] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} + +// Test that `nounwind` attributes are correctly applied to exported `win64` and +// `win64-unwind` extern functions. `win64-unwind` functions MUST NOT have this attribute. We +// disable optimizations above to prevent LLVM from inferring the attribute. + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "win64" fn rust_item_that_cannot_unwind() {} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "win64-unwind" fn rust_item_that_can_unwind() {} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/tests/codegen-llvm/unwind-and-panic-abort.rs b/tests/codegen-llvm/unwind-and-panic-abort.rs new file mode 100644 index 00000000000..8efa140058a --- /dev/null +++ b/tests/codegen-llvm/unwind-and-panic-abort.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -C panic=abort + +#![crate_type = "lib"] + +extern "C-unwind" { + fn bar(); +} + +// CHECK: Function Attrs:{{.*}}nounwind +// CHECK-NEXT: define{{.*}}void @foo +// Handle both legacy and v0 symbol mangling. +// CHECK: call void @{{.*core9panicking19panic_cannot_unwind}} +#[no_mangle] +pub unsafe extern "C" fn foo() { + bar(); +} diff --git a/tests/codegen-llvm/unwind-extern-exports.rs b/tests/codegen-llvm/unwind-extern-exports.rs new file mode 100644 index 00000000000..e692fd1a547 --- /dev/null +++ b/tests/codegen-llvm/unwind-extern-exports.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -C opt-level=0 +//@ needs-unwind + +#![crate_type = "lib"] + +// Make sure these all do *not* get the attribute. +// We disable optimizations to prevent LLVM from inferring the attribute. +// CHECK-NOT: nounwind + +// "C" ABI +pub extern "C-unwind" fn foo_unwind() {} + +// "Rust" +// (`extern "Rust"` could be removed as all `fn` get it implicitly; we leave it in for clarity.) +pub fn bar() {} diff --git a/tests/codegen-llvm/unwind-extern-imports.rs b/tests/codegen-llvm/unwind-extern-imports.rs new file mode 100644 index 00000000000..dfae8aae64a --- /dev/null +++ b/tests/codegen-llvm/unwind-extern-imports.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -C no-prepopulate-passes +//@ needs-unwind + +#![crate_type = "lib"] + +extern "C" { + // CHECK: Function Attrs:{{.*}}nounwind + // CHECK-NEXT: declare{{.*}}void @extern_fn + fn extern_fn(); +} + +extern "C-unwind" { + // CHECK-NOT: nounwind + // CHECK: declare{{.*}}void @c_unwind_extern_fn + fn c_unwind_extern_fn(); +} + +pub unsafe fn force_declare() { + extern_fn(); + c_unwind_extern_fn(); +} diff --git a/tests/codegen-llvm/unwind-landingpad-cold.rs b/tests/codegen-llvm/unwind-landingpad-cold.rs new file mode 100644 index 00000000000..fb095e04650 --- /dev/null +++ b/tests/codegen-llvm/unwind-landingpad-cold.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Cno-prepopulate-passes +//@ needs-unwind +#![crate_type = "lib"] + +// This test checks that drop calls in unwind landing pads +// get the `cold` attribute. + +// CHECK-LABEL: @check_cold +// CHECK: {{(call|invoke) void .+}}drop_in_place{{.+}} [[ATTRIBUTES:#[0-9]+]] +// CHECK: attributes [[ATTRIBUTES]] = { cold } +#[no_mangle] +pub fn check_cold(f: fn(), x: Box) { + // this may unwind + f(); +} diff --git a/tests/codegen-llvm/unwind-landingpad-inline.rs b/tests/codegen-llvm/unwind-landingpad-inline.rs new file mode 100644 index 00000000000..1cf606279e6 --- /dev/null +++ b/tests/codegen-llvm/unwind-landingpad-inline.rs @@ -0,0 +1,39 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +// This test checks that we can inline drop_in_place in +// unwind landing pads. + +// Without inlining, the box pointers escape via the call to drop_in_place, +// and LLVM will not optimize out the pointer comparison. +// With inlining, everything should be optimized out. +// See https://github.com/rust-lang/rust/issues/46515 +// CHECK-LABEL: @check_no_escape_in_landingpad +// CHECK: start: +// CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 +// CHECK-NEXT: tail call void @[[NO_ALLOC_SHIM:_R.+__rust_no_alloc_shim_is_unstable_v2]]() +// CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 +// CHECK-NEXT: tail call void @[[NO_ALLOC_SHIM]]() +// CHECK-NEXT: ret void +#[no_mangle] +pub fn check_no_escape_in_landingpad(f: fn()) { + let x = &*Box::new(0); + let y = &*Box::new(0); + + if x as *const _ == y as *const _ { + f(); + } +} + +// Without inlining, the compiler can't tell that +// dropping an empty string (in a landing pad) does nothing. +// With inlining, the landing pad should be optimized out. +// See https://github.com/rust-lang/rust/issues/87055 +// CHECK-LABEL: @check_eliminate_noop_drop +// CHECK: call void %g() +// CHECK-NEXT: ret void +#[no_mangle] +pub fn check_eliminate_noop_drop(g: fn()) { + let _var = String::new(); + g(); +} diff --git a/tests/codegen-llvm/used_with_arg.rs b/tests/codegen-llvm/used_with_arg.rs new file mode 100644 index 00000000000..4515cb2aed0 --- /dev/null +++ b/tests/codegen-llvm/used_with_arg.rs @@ -0,0 +1,10 @@ +#![crate_type = "lib"] +#![feature(used_with_arg)] + +// CHECK: @llvm.used = appending global {{.*}}USED_LINKER +#[used(linker)] +static mut USED_LINKER: [usize; 1] = [0]; + +// CHECK-NEXT: @llvm.compiler.used = appending global {{.*}}USED_COMPILER +#[used(compiler)] +static mut USED_COMPILER: [usize; 1] = [0]; diff --git a/tests/codegen-llvm/var-names.rs b/tests/codegen-llvm/var-names.rs new file mode 100644 index 00000000000..40720e19761 --- /dev/null +++ b/tests/codegen-llvm/var-names.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes + +#![crate_type = "lib"] + +// CHECK-LABEL: define{{.*}}i32 @test(i32{{.*}} %a, i32{{.*}} %b) +#[no_mangle] +pub fn test(a: u32, b: u32) -> u32 { + let c = a + b; + // CHECK: %c = add i32 %a, %b + let d = c; + let e = d * a; + // CHECK-NEXT: %e = mul i32 %c, %a + e + // CHECK-NEXT: ret i32 %e +} diff --git a/tests/codegen-llvm/vec-as-ptr.rs b/tests/codegen-llvm/vec-as-ptr.rs new file mode 100644 index 00000000000..5c997802640 --- /dev/null +++ b/tests/codegen-llvm/vec-as-ptr.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled + +#![crate_type = "lib"] + +// Test that even though we return a *const u8 not a &[u8] or a NonNull, LLVM knows that this +// pointer is nonnull. +// CHECK: nonnull ptr @vec_as_ptr +#[no_mangle] +pub fn vec_as_ptr(v: &Vec) -> *const u8 { + v.as_ptr() +} + +// Test that even though we return a *const u8 not a &[u8] or a NonNull, LLVM knows that this +// pointer is nonnull. +// CHECK: nonnull ptr @vec_as_mut_ptr +#[no_mangle] +pub fn vec_as_mut_ptr(v: &mut Vec) -> *mut u8 { + v.as_mut_ptr() +} diff --git a/tests/codegen-llvm/vec-calloc.rs b/tests/codegen-llvm/vec-calloc.rs new file mode 100644 index 00000000000..d1c320ead01 --- /dev/null +++ b/tests/codegen-llvm/vec-calloc.rs @@ -0,0 +1,182 @@ +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled +//@ only-x86_64 + +#![crate_type = "lib"] + +// CHECK-LABEL: @vec_zero_bytes +#[no_mangle] +pub fn vec_zero_bytes(n: usize) -> Vec { + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + // CHECK-NOT: call {{.*}}llvm.memset + + // CHECK: call {{.*}}__rust_alloc_zeroed( + + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + // CHECK-NOT: call {{.*}}llvm.memset + + // CHECK: ret void + vec![0; n] +} + +// CHECK-LABEL: @vec_one_bytes +#[no_mangle] +pub fn vec_one_bytes(n: usize) -> Vec { + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( + + // CHECK: call {{.*}}__rust_alloc( + // CHECK: call {{.*}}llvm.memset + + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( + + // CHECK: ret void + vec![1; n] +} + +// CHECK-LABEL: @vec_zero_scalar +#[no_mangle] +pub fn vec_zero_scalar(n: usize) -> Vec { + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + + // CHECK: call {{.*}}__rust_alloc_zeroed( + + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + + // CHECK: ret void + vec![0; n] +} + +// CHECK-LABEL: @vec_one_scalar +#[no_mangle] +pub fn vec_one_scalar(n: usize) -> Vec { + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( + + // CHECK: call {{.*}}__rust_alloc( + + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( + + // CHECK: ret void + vec![1; n] +} + +// CHECK-LABEL: @vec_zero_rgb48 +#[no_mangle] +pub fn vec_zero_rgb48(n: usize) -> Vec<[u16; 3]> { + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + + // CHECK: call {{.*}}__rust_alloc_zeroed( + + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + + // CHECK: ret void + vec![[0, 0, 0]; n] +} + +// CHECK-LABEL: @vec_zero_array_16 +#[no_mangle] +pub fn vec_zero_array_16(n: usize) -> Vec<[i64; 16]> { + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + + // CHECK: call {{.*}}__rust_alloc_zeroed( + + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + + // CHECK: ret void + vec![[0_i64; 16]; n] +} + +// CHECK-LABEL: @vec_zero_tuple +#[no_mangle] +pub fn vec_zero_tuple(n: usize) -> Vec<(i16, u8, char)> { + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + + // CHECK: call {{.*}}__rust_alloc_zeroed( + + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + + // CHECK: ret void + vec![(0, 0, '\0'); n] +} + +// CHECK-LABEL: @vec_non_zero_tuple +#[no_mangle] +pub fn vec_non_zero_tuple(n: usize) -> Vec<(i16, u8, char)> { + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( + + // CHECK: call {{.*}}__rust_alloc( + + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( + + // CHECK: ret void + vec![(0, 0, 'A'); n] +} + +// CHECK-LABEL: @vec_option_bool +#[no_mangle] +pub fn vec_option_bool(n: usize) -> Vec> { + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + + // CHECK: call {{.*}}__rust_alloc_zeroed( + + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + + // CHECK: ret void + vec![Some(false); n] +} + +// CHECK-LABEL: @vec_option_i32 +#[no_mangle] +pub fn vec_option_i32(n: usize) -> Vec> { + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + + // CHECK: call {{.*}}__rust_alloc_zeroed( + + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + + // CHECK: ret void + vec![None; n] +} + +// Ensure that __rust_alloc_zeroed gets the right attributes for LLVM to optimize it away. +// CHECK: declare noalias noundef ptr @{{.*}}__rust_alloc_zeroed(i64 noundef, i64 allocalign noundef) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]] + +// CHECK-DAG: attributes [[RUST_ALLOC_ZEROED_ATTRS]] = { {{.*}} allockind("alloc,zeroed,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} } diff --git a/tests/codegen-llvm/vec-in-place.rs b/tests/codegen-llvm/vec-in-place.rs new file mode 100644 index 00000000000..a5ef8653b99 --- /dev/null +++ b/tests/codegen-llvm/vec-in-place.rs @@ -0,0 +1,161 @@ +//@ ignore-std-debug-assertions (FIXME: checks for call detect scoped noalias metadata) +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled +#![crate_type = "lib"] + +// Ensure that trivial casts of vec elements are O(1) + +pub struct Wrapper(T); + +// previously repr(C) caused the optimization to fail +#[repr(C)] +pub struct Foo { + a: u64, + b: u64, + c: u64, + d: u64, +} + +// implementing Copy exercises the TrustedRandomAccess specialization inside the in-place +// specialization +#[derive(Copy, Clone)] +pub struct Bar { + a: u64, + b: u64, + c: u64, + d: u64, +} + +// this exercises the try-fold codepath +pub struct Baz { + a: u64, + b: u64, + c: u64, + d: u64, +} + +// CHECK-LABEL: @vec_iterator_cast_primitive +#[no_mangle] +pub fn vec_iterator_cast_primitive(vec: Vec) -> Vec { + // CHECK-NOT: loop + // CHECK-NOT: call + // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) + // CHECK-NOT: loop + // CHECK-NOT: call + vec.into_iter().map(|e| e as u8).collect() +} + +// CHECK-LABEL: @vec_iterator_cast_wrapper +#[no_mangle] +pub fn vec_iterator_cast_wrapper(vec: Vec) -> Vec> { + // CHECK-NOT: loop + // CHECK-NOT: call + // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) + // CHECK-NOT: loop + // CHECK-NOT: call + vec.into_iter().map(|e| Wrapper(e)).collect() +} + +// CHECK-LABEL: @vec_iterator_cast_signed +#[no_mangle] +pub fn vec_iterator_cast_signed(vec: Vec) -> Vec { + // CHECK-NOT: and i{{[0-9]+}} %{{.*}}, {{[0-9]+}} + vec.into_iter().map(|e| u32::from_ne_bytes(e.to_ne_bytes())).collect() +} + +// CHECK-LABEL: @vec_iterator_cast_signed_nested +#[no_mangle] +pub fn vec_iterator_cast_signed_nested(vec: Vec>) -> Vec> { + // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} + // CHECK-NOT: %{{.*}} = udiv + vec.into_iter() + .map(|e| e.into_iter().map(|e| u32::from_ne_bytes(e.to_ne_bytes())).collect()) + .collect() +} + +// CHECK-LABEL: @vec_iterator_cast_unwrap +#[no_mangle] +pub fn vec_iterator_cast_unwrap(vec: Vec>) -> Vec { + // CHECK-NOT: loop + // CHECK-NOT: call + // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) + // CHECK-NOT: loop + // CHECK-NOT: call + vec.into_iter().map(|e| e.0).collect() +} + +// CHECK-LABEL: @vec_iterator_cast_aggregate +#[no_mangle] +pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec { + // CHECK-NOT: loop + // CHECK-NOT: call + // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) + // CHECK-NOT: loop + // CHECK-NOT: call + vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect() +} + +// CHECK-LABEL: @vec_iterator_cast_deaggregate_tra +#[no_mangle] +pub fn vec_iterator_cast_deaggregate_tra(vec: Vec) -> Vec<[u64; 4]> { + // CHECK-NOT: loop + // CHECK-NOT: call + // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) + // CHECK-NOT: loop + // CHECK-NOT: call + + // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4]. + // This currently is not guaranteed for repr(Rust) types, but it happens to work here and + // the UCG may add additional guarantees for homogenous types in the future that would make this + // correct. + vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect() +} + +// CHECK-LABEL: @vec_iterator_cast_deaggregate_fold +#[no_mangle] +pub fn vec_iterator_cast_deaggregate_fold(vec: Vec) -> Vec<[u64; 4]> { + // CHECK-NOT: loop + // CHECK-NOT: call + // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) + // CHECK-NOT: loop + // CHECK-NOT: call + + // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4]. + // This currently is not guaranteed for repr(Rust) types, but it happens to work here and + // the UCG may add additional guarantees for homogenous types in the future that would make this + // correct. + vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect() +} + +// CHECK-LABEL: @vec_iterator_cast_unwrap_drop +#[no_mangle] +pub fn vec_iterator_cast_unwrap_drop(vec: Vec>) -> Vec { + // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} + // CHECK-NOT: %{{.*}} = mul + // CHECK-NOT: %{{.*}} = udiv + // CHECK: call + // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) + // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} + // CHECK-NOT: call + // CHECK-NOT: %{{.*}} = mul + // CHECK-NOT: %{{.*}} = udiv + // CHECK: ret void + + vec.into_iter().map(|Wrapper(e)| e).collect() +} + +// CHECK-LABEL: @vec_iterator_cast_wrap_drop +#[no_mangle] +pub fn vec_iterator_cast_wrap_drop(vec: Vec) -> Vec> { + // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} + // CHECK-NOT: %{{.*}} = mul + // CHECK-NOT: %{{.*}} = udiv + // CHECK: call + // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) + // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} + // CHECK-NOT: call + // CHECK-NOT: %{{.*}} = mul + // CHECK-NOT: %{{.*}} = udiv + // CHECK: ret void + + vec.into_iter().map(Wrapper).collect() +} diff --git a/tests/codegen-llvm/vec-iter-collect-len.rs b/tests/codegen-llvm/vec-iter-collect-len.rs new file mode 100644 index 00000000000..807548ef883 --- /dev/null +++ b/tests/codegen-llvm/vec-iter-collect-len.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +#[no_mangle] +pub fn get_len() -> usize { + // CHECK-LABEL: @get_len + // CHECK-NEXT: start: + // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 + // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() + // CHECK-NEXT: ret i{{[0-9]+}} 3 + [1, 2, 3].iter().collect::>().len() +} diff --git a/tests/codegen-llvm/vec-iter.rs b/tests/codegen-llvm/vec-iter.rs new file mode 100644 index 00000000000..4ed00d2d34f --- /dev/null +++ b/tests/codegen-llvm/vec-iter.rs @@ -0,0 +1,58 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] +#![feature(exact_size_is_empty)] + +use std::vec; + +// CHECK-LABEL: @vec_iter_len_nonnull +#[no_mangle] +pub fn vec_iter_len_nonnull(it: &vec::IntoIter) -> usize { + // CHECK: load ptr + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: load ptr + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: sub nuw + // CHECK: ret + it.len() +} + +// CHECK-LABEL: @vec_iter_is_empty_nonnull +#[no_mangle] +pub fn vec_iter_is_empty_nonnull(it: &vec::IntoIter) -> bool { + // CHECK: load ptr + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: load ptr + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: ret + it.is_empty() +} + +// CHECK-LABEL: @vec_iter_next_nonnull +#[no_mangle] +pub fn vec_iter_next_nonnull(it: &mut vec::IntoIter) -> Option { + // CHECK: load ptr + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: load ptr + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: ret + it.next() +} + +// CHECK-LABEL: @vec_iter_next_back_nonnull +#[no_mangle] +pub fn vec_iter_next_back_nonnull(it: &mut vec::IntoIter) -> Option { + // CHECK: load ptr + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: load ptr + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: ret + it.next_back() +} diff --git a/tests/codegen-llvm/vec-len-invariant.rs b/tests/codegen-llvm/vec-len-invariant.rs new file mode 100644 index 00000000000..033181c2bfb --- /dev/null +++ b/tests/codegen-llvm/vec-len-invariant.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -Copt-level=3 +//@ only-64bit +// +// This test confirms that we do not reload the length of a Vec after growing it in push. + +#![crate_type = "lib"] + +// CHECK-LABEL: @should_load_once +#[no_mangle] +pub fn should_load_once(v: &mut Vec) { + // CHECK: load i64 + // CHECK: call {{.*}}grow_one + // CHECK-NOT: load i64 + // CHECK: add {{.*}}, 1 + v.push(1); +} diff --git a/tests/codegen-llvm/vec-optimizes-away.rs b/tests/codegen-llvm/vec-optimizes-away.rs new file mode 100644 index 00000000000..93b55454b10 --- /dev/null +++ b/tests/codegen-llvm/vec-optimizes-away.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +#[no_mangle] +pub fn sum_me() -> i32 { + // CHECK-LABEL: @sum_me + // CHECK-NEXT: {{^.*:$}} + // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 + // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() + // CHECK-NEXT: ret i32 6 + vec![1, 2, 3].iter().sum::() +} diff --git a/tests/codegen-llvm/vec-reserve-extend.rs b/tests/codegen-llvm/vec-reserve-extend.rs new file mode 100644 index 00000000000..4d3f23ccecf --- /dev/null +++ b/tests/codegen-llvm/vec-reserve-extend.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @should_reserve_once +#[no_mangle] +pub fn should_reserve_once(v: &mut Vec) { + // CHECK: tail call void @llvm.assume + v.try_reserve(3).unwrap(); + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}do_reserve_and_handle + // CHECK-NOT: call {{.*}}__rust_alloc( + v.extend([1, 2, 3]); +} diff --git a/tests/codegen-llvm/vec-shrink-panik.rs b/tests/codegen-llvm/vec-shrink-panik.rs new file mode 100644 index 00000000000..23dd300d48c --- /dev/null +++ b/tests/codegen-llvm/vec-shrink-panik.rs @@ -0,0 +1,31 @@ +// LLVM 17 realizes double panic is not possible and doesn't generate calls +// to panic_cannot_unwind. +//@ compile-flags: -Copt-level=3 +//@ ignore-std-debug-assertions (plain old debug assertions) +//@ needs-unwind +#![crate_type = "lib"] +#![feature(shrink_to)] + +// Make sure that `Vec::shrink_to_fit` never emits panics via `RawVec::shrink_to_fit`, +// "Tried to shrink to a larger capacity", because the length is *always* <= capacity. + +// CHECK-LABEL: @shrink_to_fit +#[no_mangle] +pub fn shrink_to_fit(vec: &mut Vec) { + // CHECK-NOT: panic + vec.shrink_to_fit(); +} + +// CHECK-LABEL: @issue71861 +#[no_mangle] +pub fn issue71861(vec: Vec) -> Box<[u32]> { + // CHECK-NOT: panic + vec.into_boxed_slice() +} + +// CHECK-LABEL: @issue75636 +#[no_mangle] +pub fn issue75636<'a>(iter: &[&'a str]) -> Box<[&'a str]> { + // CHECK-NOT: panic + iter.iter().copied().collect() +} diff --git a/tests/codegen-llvm/vec-with-capacity.rs b/tests/codegen-llvm/vec-with-capacity.rs new file mode 100644 index 00000000000..777bbcc4fcb --- /dev/null +++ b/tests/codegen-llvm/vec-with-capacity.rs @@ -0,0 +1,35 @@ +//@ compile-flags: -Copt-level=3 +//@ ignore-std-debug-assertions +// (with debug assertions turned on, `assert_unchecked` generates a real assertion) + +#![crate_type = "lib"] +#![feature(try_with_capacity)] + +// CHECK-LABEL: @with_capacity_does_not_grow1 +#[no_mangle] +pub fn with_capacity_does_not_grow1() -> Vec { + let v = Vec::with_capacity(1234); + // CHECK: call {{.*}}__rust_alloc( + // CHECK-NOT: call {{.*}}__rust_realloc + // CHECK-NOT: call {{.*}}capacity_overflow + // CHECK-NOT: call {{.*}}finish_grow + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: memcpy + // CHECK-NOT: memset + v +} + +// CHECK-LABEL: @try_with_capacity_does_not_grow2 +#[no_mangle] +pub fn try_with_capacity_does_not_grow2() -> Option>> { + let v = Vec::try_with_capacity(1234).ok()?; + // CHECK: call {{.*}}__rust_alloc( + // CHECK-NOT: call {{.*}}__rust_realloc + // CHECK-NOT: call {{.*}}capacity_overflow + // CHECK-NOT: call {{.*}}finish_grow + // CHECK-NOT: call {{.*}}handle_alloc_error + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: memcpy + // CHECK-NOT: memset + Some(v) +} diff --git a/tests/codegen-llvm/vec_pop_push_noop.rs b/tests/codegen-llvm/vec_pop_push_noop.rs new file mode 100644 index 00000000000..3e375219fe0 --- /dev/null +++ b/tests/codegen-llvm/vec_pop_push_noop.rs @@ -0,0 +1,24 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[no_mangle] +// CHECK-LABEL: @noop( +pub fn noop(v: &mut Vec) { + // CHECK-NOT: grow_one + // CHECK-NOT: call + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow_one + // CHECK-NOT: call + // CHECK: {{ret|[}]}} + if let Some(x) = v.pop() { + v.push(x) + } +} + +#[no_mangle] +// CHECK-LABEL: @push_byte( +pub fn push_byte(v: &mut Vec) { + // CHECK: call {{.*}}grow_one + v.push(3); +} diff --git a/tests/codegen-llvm/vecdeque-drain.rs b/tests/codegen-llvm/vecdeque-drain.rs new file mode 100644 index 00000000000..a5e5da65013 --- /dev/null +++ b/tests/codegen-llvm/vecdeque-drain.rs @@ -0,0 +1,70 @@ +// Check that draining at the front or back doesn't copy memory. + +//@ compile-flags: -Copt-level=3 +//@ needs-deterministic-layouts +//@ ignore-std-debug-assertions (FIXME: checks for call detect scoped noalias metadata) + +#![crate_type = "lib"] + +use std::collections::VecDeque; + +// CHECK-LABEL: @clear +// CHECK-NOT: call +// CHECK-NOT: br +// CHECK: getelementptr inbounds +// CHECK-NEXT: {{call void @llvm.memset|store}} +// CHECK-NEXT: ret void +#[no_mangle] +pub fn clear(v: &mut VecDeque) { + v.drain(..); +} + +// CHECK-LABEL: @truncate +// CHECK-NOT: call +// CHECK: br +// CHECK-NOT: call +// CHECK: br +// CHECK-NOT: call +// CHECK: br +// CHECK-NOT: call +// CHECK: br +// CHECK-NOT: call +// CHECK-NOT: br +// CHECK: ret void +#[no_mangle] +pub fn truncate(v: &mut VecDeque, n: usize) { + if n < v.len() { + v.drain(n..); + } +} + +// CHECK-LABEL: @advance +// CHECK-NOT: call +// CHECK: br +// CHECK-NOT: call +// CHECK: br +// CHECK-NOT: call +// CHECK: br +// CHECK-NOT: call +// CHECK: br +// CHECK-NOT: call +// CHECK: br +// CHECK-NOT: call +// CHECK-NOT: br +// CHECK: ret void +#[no_mangle] +pub fn advance(v: &mut VecDeque, n: usize) { + if n < v.len() { + v.drain(..n); + } else { + v.clear(); + } +} + +// CHECK-LABEL: @remove +// CHECK: call +// CHECK: ret void +#[no_mangle] +pub fn remove(v: &mut VecDeque, a: usize, b: usize) { + v.drain(a..b); +} diff --git a/tests/codegen-llvm/vecdeque-nonempty-get-no-panic.rs b/tests/codegen-llvm/vecdeque-nonempty-get-no-panic.rs new file mode 100644 index 00000000000..1f886b096bb --- /dev/null +++ b/tests/codegen-llvm/vecdeque-nonempty-get-no-panic.rs @@ -0,0 +1,16 @@ +// Guards against regression for optimization discussed in issue #80836 + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +use std::collections::VecDeque; + +// CHECK-LABEL: @front +// CHECK: ret void +#[no_mangle] +pub fn front(v: VecDeque) { + if !v.is_empty() { + v.get(0).unwrap(); + } +} diff --git a/tests/codegen-llvm/vecdeque_no_panic.rs b/tests/codegen-llvm/vecdeque_no_panic.rs new file mode 100644 index 00000000000..3166842afca --- /dev/null +++ b/tests/codegen-llvm/vecdeque_no_panic.rs @@ -0,0 +1,19 @@ +// This test checks that `VecDeque::front[_mut]()` and `VecDeque::back[_mut]()` can't panic. + +//@ compile-flags: -Copt-level=3 +//@ ignore-std-debug-assertions (plain old debug assertions) + +#![crate_type = "lib"] + +use std::collections::VecDeque; + +// CHECK-LABEL: @dont_panic +#[no_mangle] +pub fn dont_panic(v: &mut VecDeque) { + // CHECK-NOT: expect + // CHECK-NOT: panic + v.front(); + v.front_mut(); + v.back(); + v.back_mut(); +} diff --git a/tests/codegen-llvm/vecdeque_pop_push.rs b/tests/codegen-llvm/vecdeque_pop_push.rs new file mode 100644 index 00000000000..5afa1b2248b --- /dev/null +++ b/tests/codegen-llvm/vecdeque_pop_push.rs @@ -0,0 +1,67 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +use std::collections::VecDeque; + +#[no_mangle] +// CHECK-LABEL: @noop_back( +pub fn noop_back(v: &mut VecDeque) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_back() { + v.push_back(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @noop_front( +pub fn noop_front(v: &mut VecDeque) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_front() { + v.push_front(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @move_byte_front_to_back( +pub fn move_byte_front_to_back(v: &mut VecDeque) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_front() { + v.push_back(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @move_byte_back_to_front( +pub fn move_byte_back_to_front(v: &mut VecDeque) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_back() { + v.push_front(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @push_back_byte( +pub fn push_back_byte(v: &mut VecDeque) { + // CHECK: call {{.*}}grow + v.push_back(3); +} + +#[no_mangle] +// CHECK-LABEL: @push_front_byte( +pub fn push_front_byte(v: &mut VecDeque) { + // CHECK: call {{.*}}grow + v.push_front(3); +} diff --git a/tests/codegen-llvm/virtual-call-attrs-issue-137646.rs b/tests/codegen-llvm/virtual-call-attrs-issue-137646.rs new file mode 100644 index 00000000000..5e453947f27 --- /dev/null +++ b/tests/codegen-llvm/virtual-call-attrs-issue-137646.rs @@ -0,0 +1,37 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/137646. +//! Since we don't know the exact implementation of the virtual call, +//! it might write to parameters, we can't infer the readonly attribute. +//@ compile-flags: -C opt-level=3 -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(rustc_attrs)] + +pub trait Trait { + #[rustc_nounwind] + fn m(&self, _: (i32, i32, i32)) {} +} + +#[no_mangle] +pub fn foo(trait_: &dyn Trait) { + // CHECK-LABEL: @foo( + // CHECK: call void + // CHECK-NOT: readonly + trait_.m((1, 1, 1)); +} + +#[no_mangle] +#[rustc_nounwind] +pub fn foo_nounwind(trait_: &dyn Trait) { + // CHECK-LABEL: @foo_nounwind( + // FIXME: Here should be invoke. + // COM: CHECK: invoke + trait_.m((1, 1, 1)); +} + +#[no_mangle] +pub extern "C" fn c_nounwind(trait_: &dyn Trait) { + // CHECK-LABEL: @c_nounwind( + // FIXME: Here should be invoke. + // COM: CHECK: invoke + trait_.m((1, 1, 1)); +} diff --git a/tests/codegen-llvm/virtual-function-elimination-32bit.rs b/tests/codegen-llvm/virtual-function-elimination-32bit.rs new file mode 100644 index 00000000000..c9919cecccf --- /dev/null +++ b/tests/codegen-llvm/virtual-function-elimination-32bit.rs @@ -0,0 +1,35 @@ +//@ compile-flags: -Zvirtual-function-elimination -Clto -Copt-level=3 -Csymbol-mangling-version=v0 +//@ ignore-64bit + +// CHECK: @vtable.0 = {{.*}}, !type ![[TYPE0:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]] + +#![crate_type = "lib"] + +trait T { + // CHECK-LABEL: ; ::used + fn used(&self) -> i32 { + 1 + } + // CHECK-LABEL-NOT: {{.*}}::unused + fn unused(&self) -> i32 { + 2 + } +} + +#[derive(Copy, Clone)] +struct S; + +impl T for S {} + +fn taking_t(t: &dyn T) -> i32 { + // CHECK: @llvm.type.checked.load({{.*}}, i32 12, metadata !"[[MANGLED_TYPE0:[0-9a-zA-Z_]+]]") + t.used() +} + +pub fn main() { + let s = S; + taking_t(&s); +} + +// CHECK: ![[TYPE0]] = !{i32 0, !"[[MANGLED_TYPE0]]"} +// CHECK: ![[VCALL_VIS0]] = !{i64 2} diff --git a/tests/codegen-llvm/virtual-function-elimination.rs b/tests/codegen-llvm/virtual-function-elimination.rs new file mode 100644 index 00000000000..26604478c11 --- /dev/null +++ b/tests/codegen-llvm/virtual-function-elimination.rs @@ -0,0 +1,98 @@ +//@ compile-flags: -Zvirtual-function-elimination -Clto -Copt-level=3 -Csymbol-mangling-version=v0 +//@ ignore-32bit + +// CHECK: @vtable.0 = {{.*}}, !type ![[TYPE0:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]] +// CHECK: @vtable.1 = {{.*}}, !type ![[TYPE1:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]] +// CHECK: @vtable.2 = {{.*}}, !type ![[TYPE2:[0-9]+]], !vcall_visibility ![[VCALL_VIS2:[0-9]+]] + +#![crate_type = "lib"] + +use std::rc::Rc; + +trait T { + // CHECK-LABEL: ; ::used + fn used(&self) -> i32 { + 1 + } + // CHECK-LABEL: ; ::used_through_sub_trait + fn used_through_sub_trait(&self) -> i32 { + 3 + } + // CHECK-LABEL: ; ::by_rc + fn by_rc(self: Rc) -> i32 { + self.used() + self.used() + } + // CHECK-LABEL-NOT: {{.*}}::unused + fn unused(&self) -> i32 { + 2 + } + // CHECK-LABEL-NOT: {{.*}}::by_rc_unused + fn by_rc_unused(self: Rc) -> i32 { + self.by_rc() + } +} + +trait U: T { + // CHECK-LABEL: ; ::subtrait_used + fn subtrait_used(&self) -> i32 { + 4 + } + // CHECK-LABEL-NOT: {{.*}}::subtrait_unused + fn subtrait_unused(&self) -> i32 { + 5 + } +} + +pub trait V { + // CHECK-LABEL: ; ::public_function + fn public_function(&self) -> i32; +} + +#[derive(Copy, Clone)] +struct S; + +impl T for S {} + +impl U for S {} + +impl V for S { + fn public_function(&self) -> i32 { + 6 + } +} + +fn taking_t(t: &dyn T) -> i32 { + // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"[[MANGLED_TYPE0:[0-9a-zA-Z_]+]]") + t.used() +} + +fn taking_rc_t(t: Rc) -> i32 { + // CHECK: @llvm.type.checked.load({{.*}}, i32 40, metadata !"[[MANGLED_TYPE0:[0-9a-zA-Z_]+]]") + t.by_rc() +} + +fn taking_u(u: &dyn U) -> i32 { + // CHECK: @llvm.type.checked.load({{.*}}, i32 64, metadata !"[[MANGLED_TYPE1:[0-9a-zA-Z_]+]]") + // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"[[MANGLED_TYPE1:[0-9a-zA-Z_]+]]") + // CHECK: @llvm.type.checked.load({{.*}}, i32 32, metadata !"[[MANGLED_TYPE1:[0-9a-zA-Z_]+]]") + u.subtrait_used() + u.used() + u.used_through_sub_trait() +} + +pub fn taking_v(v: &dyn V) -> i32 { + // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"NtC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_28virtual_function_elimination1V") + v.public_function() +} + +pub fn main() { + let s = S; + taking_t(&s); + taking_rc_t(Rc::new(s)); + taking_u(&s); + taking_v(&s); +} + +// CHECK: ![[TYPE0]] = !{i64 0, !"[[MANGLED_TYPE0]]"} +// CHECK: ![[VCALL_VIS0]] = !{i64 2} +// CHECK: ![[TYPE1]] = !{i64 0, !"[[MANGLED_TYPE1]]"} +// CHECK: ![[TYPE2]] = !{i64 0, !"NtC[[CRATE_IDENT]]_28virtual_function_elimination1V"} +// CHECK: ![[VCALL_VIS2]] = !{i64 1} diff --git a/tests/codegen-llvm/vtable-loads.rs b/tests/codegen-llvm/vtable-loads.rs new file mode 100644 index 00000000000..aa103ec6f7c --- /dev/null +++ b/tests/codegen-llvm/vtable-loads.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @loop_skips_vtable_load +#[no_mangle] +pub fn loop_skips_vtable_load(x: &dyn Fn()) { + // CHECK: load ptr, ptr %0{{.*}}, !invariant.load + // CHECK-NEXT: tail call void %1 + // CHECK-NOT: load ptr + x(); + for _ in 0..100 { + // CHECK: tail call void %1 + x(); + } +} diff --git a/tests/codegen-llvm/vtable-upcast.rs b/tests/codegen-llvm/vtable-upcast.rs new file mode 100644 index 00000000000..9e13e8dd68a --- /dev/null +++ b/tests/codegen-llvm/vtable-upcast.rs @@ -0,0 +1,84 @@ +//! This file tests that we correctly generate GEP instructions for vtable upcasting. +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 + +#![crate_type = "lib"] + +pub trait Base { + fn base(&self); +} + +pub trait A: Base { + fn a(&self); +} + +pub trait B: Base { + fn b(&self); +} + +pub trait Diamond: A + B { + fn diamond(&self); +} + +// CHECK-LABEL: upcast_a_to_base +#[no_mangle] +pub fn upcast_a_to_base(x: &dyn A) -> &dyn Base { + // Requires no adjustment, since its vtable is extended from `Base`. + + // CHECK: start: + // CHECK-NEXT: insertvalue + // CHECK-NEXT: insertvalue + // CHECK-NEXT: ret + x as &dyn Base +} + +// CHECK-LABEL: upcast_b_to_base +#[no_mangle] +pub fn upcast_b_to_base(x: &dyn B) -> &dyn Base { + // Requires no adjustment, since its vtable is extended from `Base`. + + // CHECK: start: + // CHECK-NEXT: insertvalue + // CHECK-NEXT: insertvalue + // CHECK-NEXT: ret + x as &dyn Base +} + +// CHECK-LABEL: upcast_diamond_to_a +#[no_mangle] +pub fn upcast_diamond_to_a(x: &dyn Diamond) -> &dyn A { + // Requires no adjustment, since its vtable is extended from `A` (as the first supertrait). + + // CHECK: start: + // CHECK-NEXT: insertvalue + // CHECK-NEXT: insertvalue + // CHECK-NEXT: ret + x as &dyn A +} + +// CHECK-LABEL: upcast_diamond_to_b +// CHECK-SAME: (ptr align {{[0-9]+}} [[DATA_PTR:%.+]], ptr align {{[0-9]+}} [[VTABLE_PTR:%.+]]) +#[no_mangle] +pub fn upcast_diamond_to_b(x: &dyn Diamond) -> &dyn B { + // Requires adjustment, since it's a non-first supertrait. + + // CHECK: start: + // CHECK-NEXT: [[UPCAST_SLOT_PTR:%.+]] = getelementptr inbounds i8, ptr [[VTABLE_PTR]] + // CHECK-NEXT: [[UPCAST_VTABLE_PTR:%.+]] = load ptr, ptr [[UPCAST_SLOT_PTR]] + // CHECK-NEXT: [[FAT_PTR_1:%.+]] = insertvalue { ptr, ptr } poison, ptr [[DATA_PTR]], 0 + // CHECK-NEXT: [[FAT_PTR_2:%.+]] = insertvalue { ptr, ptr } [[FAT_PTR_1]], ptr [[UPCAST_VTABLE_PTR]], 1 + // CHECK-NEXT: ret { ptr, ptr } [[FAT_PTR_2]] + x as &dyn B +} + +// CHECK-LABEL: upcast_diamond_to_b +#[no_mangle] +pub fn upcast_diamond_to_base(x: &dyn Diamond) -> &dyn Base { + // Requires no adjustment, since `Base` is the first supertrait of `A`, + // which is the first supertrait of `Diamond`. + + // CHECK: start: + // CHECK-NEXT: insertvalue + // CHECK-NEXT: insertvalue + // CHECK-NEXT: ret + x as &dyn Base +} diff --git a/tests/codegen-llvm/wasm_casts_trapping.rs b/tests/codegen-llvm/wasm_casts_trapping.rs new file mode 100644 index 00000000000..0908acd85fc --- /dev/null +++ b/tests/codegen-llvm/wasm_casts_trapping.rs @@ -0,0 +1,157 @@ +//@ only-wasm32 +//@ compile-flags: -C target-feature=-nontrapping-fptoint +#![crate_type = "lib"] + +// CHECK-LABEL: @cast_f64_i64 +#[no_mangle] +pub fn cast_f64_i64(a: f64) -> i64 { + // CHECK-NOT: fptosi double {{.*}} to i64 + // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i64.f64{{.*}} + a as _ +} + +// CHECK-LABEL: @cast_f64_i32 +#[no_mangle] +pub fn cast_f64_i32(a: f64) -> i32 { + // CHECK-NOT: fptosi double {{.*}} to i32 + // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i32.f64{{.*}} + a as _ +} + +// CHECK-LABEL: @cast_f32_i64 +#[no_mangle] +pub fn cast_f32_i64(a: f32) -> i64 { + // CHECK-NOT: fptosi float {{.*}} to i64 + // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i64.f32{{.*}} + a as _ +} + +// CHECK-LABEL: @cast_f32_i32 +#[no_mangle] +pub fn cast_f32_i32(a: f32) -> i32 { + // CHECK-NOT: fptosi float {{.*}} to i32 + // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i32.f32{{.*}} + a as _ +} + +// CHECK-LABEL: @cast_f64_u64 +#[no_mangle] +pub fn cast_f64_u64(a: f64) -> u64 { + // CHECK-NOT: fptoui double {{.*}} to i64 + // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i64.f64{{.*}} + a as _ +} + +// CHECK-LABEL: @cast_f64_u32 +#[no_mangle] +pub fn cast_f64_u32(a: f64) -> u32 { + // CHECK-NOT: fptoui double {{.*}} to i32 + // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i32.f64{{.*}} + a as _ +} + +// CHECK-LABEL: @cast_f32_u64 +#[no_mangle] +pub fn cast_f32_u64(a: f32) -> u64 { + // CHECK-NOT: fptoui float {{.*}} to i64 + // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i64.f32{{.*}} + a as _ +} + +// CHECK-LABEL: @cast_f32_u32 +#[no_mangle] +pub fn cast_f32_u32(a: f32) -> u32 { + // CHECK-NOT: fptoui float {{.*}} to i32 + // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i32.f32{{.*}} + a as _ +} + +// CHECK-LABEL: @cast_f32_u8 +#[no_mangle] +pub fn cast_f32_u8(a: f32) -> u8 { + // CHECK-NOT: fptoui float {{.*}} to i8 + // CHECK-NOT: select i1 {{.*}}, i8 {{.*}}, i8 {{.*}} + // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i8.f32{{.*}} + a as _ +} + +// CHECK-LABEL: @cast_unchecked_f64_i64 +#[no_mangle] +pub unsafe fn cast_unchecked_f64_i64(a: f64) -> i64 { + // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}} + // CHECK-NEXT: ret i64 {{.*}} + a.to_int_unchecked() +} + +// CHECK-LABEL: @cast_unchecked_f64_i32 +#[no_mangle] +pub unsafe fn cast_unchecked_f64_i32(a: f64) -> i32 { + // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}} + // CHECK-NEXT: ret i32 {{.*}} + a.to_int_unchecked() +} + +// CHECK-LABEL: @cast_unchecked_f32_i64 +#[no_mangle] +pub unsafe fn cast_unchecked_f32_i64(a: f32) -> i64 { + // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}} + // CHECK-NEXT: ret i64 {{.*}} + a.to_int_unchecked() +} + +// CHECK-LABEL: @cast_unchecked_f32_i32 +#[no_mangle] +pub unsafe fn cast_unchecked_f32_i32(a: f32) -> i32 { + // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}} + // CHECK-NEXT: ret i32 {{.*}} + a.to_int_unchecked() +} + +// CHECK-LABEL: @cast_unchecked_f64_u64 +#[no_mangle] +pub unsafe fn cast_unchecked_f64_u64(a: f64) -> u64 { + // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}} + // CHECK-NEXT: ret i64 {{.*}} + a.to_int_unchecked() +} + +// CHECK-LABEL: @cast_unchecked_f64_u32 +#[no_mangle] +pub unsafe fn cast_unchecked_f64_u32(a: f64) -> u32 { + // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}} + // CHECK-NEXT: ret i32 {{.*}} + a.to_int_unchecked() +} + +// CHECK-LABEL: @cast_unchecked_f32_u64 +#[no_mangle] +pub unsafe fn cast_unchecked_f32_u64(a: f32) -> u64 { + // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}} + // CHECK-NEXT: ret i64 {{.*}} + a.to_int_unchecked() +} + +// CHECK-LABEL: @cast_unchecked_f32_u32 +#[no_mangle] +pub unsafe fn cast_unchecked_f32_u32(a: f32) -> u32 { + // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}} + // CHECK-NEXT: ret i32 {{.*}} + a.to_int_unchecked() +} + +// CHECK-LABEL: @cast_unchecked_f32_u8 +#[no_mangle] +pub unsafe fn cast_unchecked_f32_u8(a: f32) -> u8 { + // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} + // CHECK: fptoui float {{.*}} to i8 + // CHECK-NEXT: ret i8 {{.*}} + a.to_int_unchecked() +} diff --git a/tests/codegen-llvm/wasm_exceptions.rs b/tests/codegen-llvm/wasm_exceptions.rs new file mode 100644 index 00000000000..07b8ae6e9d7 --- /dev/null +++ b/tests/codegen-llvm/wasm_exceptions.rs @@ -0,0 +1,59 @@ +//@ only-wasm32 +//@ compile-flags: -C panic=unwind -Z emscripten-wasm-eh + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +extern "C-unwind" { + fn may_panic(); +} + +extern "C" { + fn log_number(number: usize); +} + +struct LogOnDrop; + +impl Drop for LogOnDrop { + fn drop(&mut self) { + unsafe { + log_number(0); + } + } +} + +// CHECK-LABEL: @test_cleanup() {{.*}} @__gxx_wasm_personality_v0 +#[no_mangle] +pub fn test_cleanup() { + let _log_on_drop = LogOnDrop; + unsafe { + may_panic(); + } + + // CHECK-NOT: call + // CHECK: invoke void @may_panic() + // CHECK: %cleanuppad = cleanuppad within none [] +} + +// CHECK-LABEL: @test_rtry() {{.*}} @__gxx_wasm_personality_v0 +#[no_mangle] +pub fn test_rtry() { + unsafe { + core::intrinsics::catch_unwind( + |_| { + may_panic(); + }, + core::ptr::null_mut(), + |data, exception| { + log_number(data as usize); + log_number(exception as usize); + }, + ); + } + + // CHECK-NOT: call + // CHECK: invoke void @may_panic() + // CHECK: {{.*}} = catchswitch within none [label {{.*}}] unwind to caller + // CHECK: {{.*}} = catchpad within {{.*}} [ptr null] + // CHECK: catchret +} diff --git a/tests/codegen-llvm/zip.rs b/tests/codegen-llvm/zip.rs new file mode 100644 index 00000000000..38ecf7c15c6 --- /dev/null +++ b/tests/codegen-llvm/zip.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @zip_copy +#[no_mangle] +pub fn zip_copy(xs: &[u8], ys: &mut [u8]) { + // CHECK: memcpy + for (x, y) in xs.iter().zip(ys) { + *y = *x; + } +} + +// CHECK-LABEL: @zip_copy_mapped +#[no_mangle] +pub fn zip_copy_mapped(xs: &[u8], ys: &mut [u8]) { + // CHECK: memcpy + for (x, y) in xs.iter().map(|&x| x).zip(ys) { + *y = x; + } +} diff --git a/tests/codegen-llvm/zst-offset.rs b/tests/codegen-llvm/zst-offset.rs new file mode 100644 index 00000000000..475394a8815 --- /dev/null +++ b/tests/codegen-llvm/zst-offset.rs @@ -0,0 +1,42 @@ +//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 + +#![crate_type = "lib"] +#![feature(repr_simd)] + +// Hack to get the correct size for the length part in slices +// CHECK: @helper([[USIZE:i[0-9]+]] %_1) +#[no_mangle] +pub fn helper(_: usize) {} + +// Check that we correctly generate a GEP for a ZST that is not included in Scalar layout +// CHECK-LABEL: @scalar_layout +#[no_mangle] +pub fn scalar_layout(s: &(u64, ())) { + // CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 8 + let x = &s.1; + witness(&x); // keep variable in an alloca +} + +// Check that we correctly generate a GEP for a ZST that is not included in ScalarPair layout +// CHECK-LABEL: @scalarpair_layout +#[no_mangle] +pub fn scalarpair_layout(s: &(u64, u32, ())) { + // CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 12 + let x = &s.2; + witness(&x); // keep variable in an alloca +} + +#[repr(simd)] +pub struct U64x4([u64; 4]); + +// Check that we correctly generate a GEP for a ZST that is not included in Vector layout +// CHECK-LABEL: @vector_layout +#[no_mangle] +pub fn vector_layout(s: &(U64x4, ())) { + // CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 32 + let x = &s.1; + witness(&x); // keep variable in an alloca +} + +#[inline(never)] +fn witness(_: &impl Sized) {} diff --git a/tests/codegen/README.md b/tests/codegen/README.md deleted file mode 100644 index 8f2daaafcc7..00000000000 --- a/tests/codegen/README.md +++ /dev/null @@ -1,24 +0,0 @@ -The files here use the LLVM FileCheck framework, documented at -. - -One extension worth noting is the use of revisions as custom prefixes for -FileCheck. If your codegen test has different behavior based on the chosen -target or different compiler flags that you want to exercise, you can use a -revisions annotation, like so: - -```rust -// revisions: aaa bbb -// [bbb] compile-flags: --flags-for-bbb -``` - -After specifying those variations, you can write different expected, or -explicitly *unexpected* output by using `-SAME:` and `-NOT:`, -like so: - -```rust -// CHECK: expected code -// aaa-SAME: emitted-only-for-aaa -// aaa-NOT: emitted-only-for-bbb -// bbb-NOT: emitted-only-for-aaa -// bbb-SAME: emitted-only-for-bbb -``` diff --git a/tests/codegen/aarch64-softfloat.rs b/tests/codegen/aarch64-softfloat.rs deleted file mode 100644 index 4f5366e047f..00000000000 --- a/tests/codegen/aarch64-softfloat.rs +++ /dev/null @@ -1,45 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: --target aarch64-unknown-none-softfloat -Zmerge-functions=disabled -//@ needs-llvm-components: aarch64 -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK: i64 @pass_f64_C(i64 {{[^,]*}}) -#[no_mangle] -extern "C" fn pass_f64_C(x: f64) -> f64 { - x -} - -// CHECK: i64 @pass_f32_pair_C(i64 {{[^,]*}}) -#[no_mangle] -extern "C" fn pass_f32_pair_C(x: (f32, f32)) -> (f32, f32) { - x -} - -// CHECK: [2 x i64] @pass_f64_pair_C([2 x i64] {{[^,]*}}) -#[no_mangle] -extern "C" fn pass_f64_pair_C(x: (f64, f64)) -> (f64, f64) { - x -} - -// CHECK: i64 @pass_f64_Rust(i64 {{[^,]*}}) -#[no_mangle] -fn pass_f64_Rust(x: f64) -> f64 { - x -} - -// CHECK: i64 @pass_f32_pair_Rust(i64 {{[^,]*}}) -#[no_mangle] -fn pass_f32_pair_Rust(x: (f32, f32)) -> (f32, f32) { - x -} - -// CHECK: void @pass_f64_pair_Rust(ptr {{.*}}%{{[^ ]+}}, ptr {{.*}}%{{[^ ]+}}) -#[no_mangle] -fn pass_f64_pair_Rust(x: (f64, f64)) -> (f64, f64) { - x -} diff --git a/tests/codegen/aarch64-struct-align-128.rs b/tests/codegen/aarch64-struct-align-128.rs deleted file mode 100644 index ba1d19680f4..00000000000 --- a/tests/codegen/aarch64-struct-align-128.rs +++ /dev/null @@ -1,145 +0,0 @@ -// Test that structs aligned to 128 bits are passed with the correct ABI on aarch64. - -//@ add-core-stubs -//@ revisions: linux darwin win -//@[linux] compile-flags: --target aarch64-unknown-linux-gnu -//@[darwin] compile-flags: --target aarch64-apple-darwin -//@[win] compile-flags: --target aarch64-pc-windows-msvc -//@[linux] needs-llvm-components: aarch64 -//@[darwin] needs-llvm-components: aarch64 -//@[win] needs-llvm-components: aarch64 - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -// Passed as `[i64 x 2]`, since it's an aggregate with size <= 128 bits, align < 128 bits. -#[repr(C)] -pub struct Align8 { - pub a: u64, - pub b: u64, -} - -// repr(transparent), so same as above. -#[repr(transparent)] -pub struct Transparent8 { - a: Align8, -} - -// Passed as `[i64 x 2]`, since it's an aggregate with size <= 128 bits, align < 128 bits. -#[repr(C)] -pub struct Wrapped8 { - a: Align8, -} - -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); -} - -// 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]`. -#[repr(C)] -#[repr(align(16))] -pub struct Align16 { - pub a: u64, - pub b: u64, -} - -// repr(transparent), so same as above. -#[repr(transparent)] -pub struct Transparent16 { - a: Align16, -} - -// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits. -// On Linux, the "unadjustedness" doesn't recurse into fields, so this is passed as `i128`. -#[repr(C)] -pub struct Wrapped16 { - pub a: Align16, -} - -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); -} - -// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits. -#[repr(C)] -pub struct I128 { - pub a: i128, -} - -// repr(transparent), so same as above. -#[repr(transparent)] -pub struct TransparentI128 { - a: I128, -} - -// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits. -#[repr(C)] -pub struct WrappedI128 { - pub a: I128, -} - -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); -} - -// 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)] -#[repr(packed)] -pub struct Packed { - pub a: i128, -} - -// repr(transparent), so same as above. -#[repr(transparent)] -pub struct TransparentPacked { - a: Packed, -} - -// Passed as `[2 x i64]`, since it's an aggregate with size <= 128 bits, align < 128 bits. -#[repr(C)] -pub struct WrappedPacked { - pub a: Packed, -} - -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); -} - -pub unsafe fn main( - a1: Align8, - a2: Transparent8, - a3: Wrapped8, - b1: Align16, - b2: Transparent16, - b3: Wrapped16, - c1: I128, - c2: TransparentI128, - c3: WrappedI128, - d1: Packed, - d2: TransparentPacked, - d3: WrappedPacked, -) { - test_8(a1, a2, a3); - test_16(b1, b2, b3); - test_i128(c1, c2, c3); - test_packed(d1, d2, d3); -} diff --git a/tests/codegen/abi-efiapi.rs b/tests/codegen/abi-efiapi.rs deleted file mode 100644 index 1736f0daf0f..00000000000 --- a/tests/codegen/abi-efiapi.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Checks if the correct annotation for the efiapi ABI is passed to llvm. - -//@ add-core-stubs -//@ revisions:x86_64 i686 aarch64 arm riscv -//@[x86_64] compile-flags: --target x86_64-unknown-uefi -//@[x86_64] needs-llvm-components: aarch64 arm riscv -//@[i686] compile-flags: --target i686-unknown-linux-musl -//@[i686] needs-llvm-components: aarch64 arm riscv -//@[aarch64] compile-flags: --target aarch64-unknown-none -//@[aarch64] needs-llvm-components: aarch64 arm riscv -//@[arm] compile-flags: --target armv7r-none-eabi -//@[arm] needs-llvm-components: aarch64 arm riscv -//@[riscv] compile-flags: --target riscv64gc-unknown-none-elf -//@[riscv] needs-llvm-components: aarch64 arm riscv -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -//x86_64: define win64cc void @has_efiapi -//i686: define void @has_efiapi -//aarch64: define dso_local void @has_efiapi -//arm: define dso_local arm_aapcscc void @has_efiapi -//riscv: define dso_local void @has_efiapi -#[no_mangle] -pub extern "efiapi" fn has_efiapi() {} diff --git a/tests/codegen/abi-main-signature-16bit-c-int.rs b/tests/codegen/abi-main-signature-16bit-c-int.rs deleted file mode 100644 index d44b80475e4..00000000000 --- a/tests/codegen/abi-main-signature-16bit-c-int.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Checks the signature of the implicitly generated native main() -// entry point. It must match C's `int main(int, char **)`. - -// This test is for targets with 16bit c_int only. -//@ revisions: avr msp -//@[avr] only-avr -//@[msp] only-msp430 - -fn main() {} - -// CHECK: define i16 @main(i16, i8**) diff --git a/tests/codegen/abi-main-signature-32bit-c-int.rs b/tests/codegen/abi-main-signature-32bit-c-int.rs deleted file mode 100644 index ce475adde44..00000000000 --- a/tests/codegen/abi-main-signature-32bit-c-int.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Checks the signature of the implicitly generated native main() -// entry point. It must match C's `int main(int, char **)`. - -// This test is for targets with 32bit c_int only. -//@ ignore-msp430 -//@ ignore-avr -//@ ignore-wasi wasi codegens the main symbol differently - -fn main() {} - -// CHECK: define{{( hidden| noundef)*}} i32 @main(i32{{( %0)?}}, ptr{{( %1)?}}) diff --git a/tests/codegen/abi-repr-ext.rs b/tests/codegen/abi-repr-ext.rs deleted file mode 100644 index 1da28a94d9d..00000000000 --- a/tests/codegen/abi-repr-ext.rs +++ /dev/null @@ -1,56 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: -Copt-level=3 - -//@ revisions:x86_64 i686 aarch64-apple aarch64-windows aarch64-linux arm riscv - -//@[x86_64] compile-flags: --target x86_64-unknown-uefi -//@[x86_64] needs-llvm-components: x86 -//@[i686] compile-flags: --target i686-unknown-linux-musl -//@[i686] needs-llvm-components: x86 -//@[aarch64-windows] compile-flags: --target aarch64-pc-windows-msvc -//@[aarch64-windows] needs-llvm-components: aarch64 -//@[aarch64-linux] compile-flags: --target aarch64-unknown-linux-gnu -//@[aarch64-linux] needs-llvm-components: aarch64 -//@[aarch64-apple] compile-flags: --target aarch64-apple-darwin -//@[aarch64-apple] needs-llvm-components: aarch64 -//@[arm] compile-flags: --target armv7r-none-eabi -//@[arm] needs-llvm-components: arm -//@[riscv] compile-flags: --target riscv64gc-unknown-none-elf -//@[riscv] needs-llvm-components: riscv - -// See bottom of file for a corresponding C source file that is meant to yield -// equivalent declarations. -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[repr(i8)] -pub enum Type { - Type1 = 0, - Type2 = 1, -} - -// To accommodate rust#97800, one might consider writing the below as: -// -// `define{{( dso_local)?}} noundef{{( signext)?}} i8 @test()` -// -// but based on rust#80556, it seems important to actually check for the -// presence of the `signext` for those targets where we expect it. - -// CHECK: define{{( dso_local)?}} noundef -// x86_64-SAME: signext -// aarch64-apple-SAME: signext -// aarch64-windows-NOT: signext -// aarch64-linux-NOT: signext -// arm-SAME: signext -// riscv-SAME: signext -// CHECK-SAME: i8 @test() - -#[no_mangle] -pub extern "C" fn test() -> Type { - Type::Type1 -} diff --git a/tests/codegen/abi-sysv64.rs b/tests/codegen/abi-sysv64.rs deleted file mode 100644 index 7ade17f2bae..00000000000 --- a/tests/codegen/abi-sysv64.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Checks if the correct annotation for the sysv64 ABI is passed to -// llvm. Also checks that the abi-sysv64 feature gate allows usage -// of the sysv64 abi. -// -//@ add-core-stubs -//@ needs-llvm-components: x86 -//@ compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu -Copt-level=0 - -#![crate_type = "lib"] -#![no_core] -#![feature(abi_x86_interrupt, no_core, lang_items)] - -extern crate minicore; -use minicore::*; - -// CHECK: define x86_64_sysvcc i64 @has_sysv64_abi -#[no_mangle] -pub extern "sysv64" fn has_sysv64_abi(a: i64) -> i64 { - a -} diff --git a/tests/codegen/abi-win64-zst.rs b/tests/codegen/abi-win64-zst.rs deleted file mode 100644 index e46f9666d42..00000000000 --- a/tests/codegen/abi-win64-zst.rs +++ /dev/null @@ -1,54 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: -Z merge-functions=disabled -//@ add-core-stubs - -//@ revisions: windows-gnu -//@[windows-gnu] compile-flags: --target x86_64-pc-windows-gnu -//@[windows-gnu] needs-llvm-components: x86 - -//@ revisions: windows-msvc -//@[windows-msvc] compile-flags: --target x86_64-pc-windows-msvc -//@[windows-msvc] needs-llvm-components: x86 - -// Also test what happens when using a Windows ABI on Linux. -//@ revisions: linux -//@[linux] compile-flags: --target x86_64-unknown-linux-gnu -//@[linux] needs-llvm-components: x86 - -#![feature(no_core, rustc_attrs, abi_vectorcall)] -#![no_core] -#![crate_type = "lib"] - -extern crate minicore; -use minicore::*; - -// Make sure the argument is always passed when explicitly requesting a Windows ABI. -// Our goal here is to match clang: . - -// CHECK: define win64cc void @pass_zst_win64(ptr {{[^,]*}}) -#[no_mangle] -extern "win64" fn pass_zst_win64(_: ()) {} - -// CHECK: define x86_vectorcallcc void @pass_zst_vectorcall(ptr {{[^,]*}}) -#[no_mangle] -extern "vectorcall" fn pass_zst_vectorcall(_: ()) {} - -// windows-gnu: define void @pass_zst_fastcall(ptr {{[^,]*}}) -// windows-msvc: define void @pass_zst_fastcall(ptr {{[^,]*}}) -#[no_mangle] -#[cfg(windows)] // "fastcall" is not valid on 64bit Linux -extern "fastcall" fn pass_zst_fastcall(_: ()) {} - -// The sysv64 ABI ignores ZST. - -// CHECK: define x86_64_sysvcc void @pass_zst_sysv64() -#[no_mangle] -extern "sysv64" fn pass_zst_sysv64(_: ()) {} - -// For `extern "C"` functions, ZST are ignored on Linux put passed on Windows. - -// linux: define void @pass_zst_c() -// windows-msvc: define void @pass_zst_c(ptr {{[^,]*}}) -// windows-gnu: define void @pass_zst_c(ptr {{[^,]*}}) -#[no_mangle] -extern "C" fn pass_zst_c(_: ()) {} diff --git a/tests/codegen/abi-x86-interrupt.rs b/tests/codegen/abi-x86-interrupt.rs deleted file mode 100644 index 9a1ded2c9e3..00000000000 --- a/tests/codegen/abi-x86-interrupt.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Checks if the correct annotation for the x86-interrupt ABI is passed to -// llvm. Also checks that the abi_x86_interrupt feature gate allows usage -// of the x86-interrupt abi. - -//@ add-core-stubs -//@ needs-llvm-components: x86 -//@ compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu -Copt-level=0 - -#![crate_type = "lib"] -#![no_core] -#![feature(abi_x86_interrupt, no_core, lang_items)] - -extern crate minicore; -use minicore::*; - -// CHECK: define x86_intrcc void @has_x86_interrupt_abi -#[no_mangle] -pub extern "x86-interrupt" fn has_x86_interrupt_abi() {} diff --git a/tests/codegen/abi-x86-sse.rs b/tests/codegen/abi-x86-sse.rs deleted file mode 100644 index 68d2acfb527..00000000000 --- a/tests/codegen/abi-x86-sse.rs +++ /dev/null @@ -1,43 +0,0 @@ -//@ compile-flags: -Z merge-functions=disabled - -//@ revisions: x86-64 -//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu -//@[x86-64] needs-llvm-components: x86 - -//@ revisions: x86-32 -//@[x86-32] compile-flags: --target i686-unknown-linux-gnu -//@[x86-32] needs-llvm-components: x86 - -//@ revisions: x86-32-nosse -//@[x86-32-nosse] compile-flags: --target i586-unknown-linux-gnu -//@[x86-32-nosse] needs-llvm-components: x86 - -#![feature(no_core, lang_items, rustc_attrs, repr_simd)] -#![no_core] -#![crate_type = "lib"] - -#[lang = "sized"] -trait Sized: MetaSized {} - -#[lang = "meta_sized"] -trait MetaSized: PointeeSized {} - -#[lang = "pointee_sized"] -trait PointeeSized {} - -#[lang = "copy"] -trait Copy {} - -// Ensure this type is passed without ptr indirection on targets that -// require SSE2. -#[repr(simd)] -pub struct Sse([f32; 4]); - -// FIXME: due to #139029 we are passing them all indirectly. -// x86-64: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}}) -// x86-32: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}}) -// x86-32-nosse: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}}) -#[no_mangle] -pub fn sse_id(x: Sse) -> Sse { - x -} diff --git a/tests/codegen/abi-x86_64_sysv.rs b/tests/codegen/abi-x86_64_sysv.rs deleted file mode 100644 index 09909f994d6..00000000000 --- a/tests/codegen/abi-x86_64_sysv.rs +++ /dev/null @@ -1,29 +0,0 @@ -//@ only-x86_64 - -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] - -pub struct S24 { - a: i8, - b: i8, - c: i8, -} - -pub struct S48 { - a: i16, - b: i16, - c: i8, -} - -// CHECK: i24 @struct_24_bits(i24 -#[no_mangle] -pub extern "sysv64" fn struct_24_bits(a: S24) -> S24 { - a -} - -// CHECK: i48 @struct_48_bits(i48 -#[no_mangle] -pub extern "sysv64" fn struct_48_bits(a: S48) -> S48 { - a -} diff --git a/tests/codegen/addr-of-mutate.rs b/tests/codegen/addr-of-mutate.rs deleted file mode 100644 index 14bc4b8ab28..00000000000 --- a/tests/codegen/addr-of-mutate.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@ compile-flags: -C opt-level=3 -C no-prepopulate-passes - -#![crate_type = "lib"] - -// Test for the absence of `readonly` on the argument when it is mutated via `&raw const`. -// See . - -// CHECK: i8 @foo(ptr noalias{{( nocapture)?}} noundef align 1{{( captures\(none\))?}} dereferenceable(128) %x) -#[no_mangle] -pub fn foo(x: [u8; 128]) -> u8 { - let ptr = core::ptr::addr_of!(x).cast_mut(); - unsafe { - (*ptr)[0] = 1; - } - x[0] -} - -// CHECK: i1 @second(ptr noalias{{( nocapture)?}} noundef align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) -#[no_mangle] -pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { - let b_bool_ptr = core::ptr::addr_of!(a_ptr_and_b.1.1).cast_mut(); - (*b_bool_ptr) = true; - a_ptr_and_b.1.1 -} - -// If going through a deref (and there are no other mutating accesses), then `readonly` is fine. -// CHECK: i1 @third(ptr noalias{{( nocapture)?}} noundef readonly align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) -#[no_mangle] -pub unsafe fn third(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { - let b_bool_ptr = core::ptr::addr_of!((*a_ptr_and_b.0).1).cast_mut(); - (*b_bool_ptr) = true; - a_ptr_and_b.1.1 -} diff --git a/tests/codegen/adjustments.rs b/tests/codegen/adjustments.rs deleted file mode 100644 index 7f7831def08..00000000000 --- a/tests/codegen/adjustments.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 - -#![crate_type = "lib"] - -// Hack to get the correct size for the length part in slices -// CHECK: @helper([[USIZE:i[0-9]+]] %_1) -#[no_mangle] -pub fn helper(_: usize) {} - -// CHECK-LABEL: @no_op_slice_adjustment -#[no_mangle] -pub fn no_op_slice_adjustment(x: &[u8]) -> &[u8] { - // We used to generate an extra alloca and memcpy for the block's trailing expression value, so - // check that we copy directly to the return value slot - // CHECK: %0 = insertvalue { ptr, [[USIZE]] } poison, ptr %x.0, 0 - // CHECK: %1 = insertvalue { ptr, [[USIZE]] } %0, [[USIZE]] %x.1, 1 - // CHECK: ret { ptr, [[USIZE]] } %1 - { x } -} - -// CHECK-LABEL: @no_op_slice_adjustment2 -#[no_mangle] -pub fn no_op_slice_adjustment2(x: &[u8]) -> &[u8] { - // We used to generate an extra alloca and memcpy for the function's return value, so check - // that there's no memcpy (the slice is written to sret_slot element-wise) - // CHECK-NOT: call void @llvm.memcpy. - no_op_slice_adjustment(x) -} diff --git a/tests/codegen/align-byval-alignment-mismatch.rs b/tests/codegen/align-byval-alignment-mismatch.rs deleted file mode 100644 index c69fc2de9d2..00000000000 --- a/tests/codegen/align-byval-alignment-mismatch.rs +++ /dev/null @@ -1,126 +0,0 @@ -// ignore-tidy-linelength -//@ add-core-stubs -//@ revisions:i686-linux x86_64-linux - -//@ compile-flags: -Cno-prepopulate-passes -Copt-level=1 -Cpanic=abort -//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu -//@[i686-linux] needs-llvm-components: x86 -//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu -//@[x86_64-linux] needs-llvm-components: x86 - -// Tests that we correctly copy arguments into allocas when the alignment of the byval argument -// is different from the alignment of the Rust type. - -// For the following test cases: -// All of the `*_decreases_alignment` functions should codegen to a direct call, since the -// alignment is already sufficient. -// All off the `*_increases_alignment` functions should copy the argument to an alloca -// on i686-unknown-linux-gnu, since the alignment needs to be increased, and should codegen -// to a direct call on x86_64-unknown-linux-gnu, where byval alignment matches Rust alignment. - -#![feature(no_core)] -#![crate_type = "lib"] -#![no_std] -#![no_core] -#![allow(non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -// This type has align 1 in Rust, but as a byval argument on i686-linux, it will have align 4. -#[repr(C)] -#[repr(packed)] -struct Align1 { - x: u128, - y: u128, - z: u128, -} - -// This type has align 16 in Rust, but as a byval argument on i686-linux, it will have align 4. -#[repr(C)] -#[repr(align(16))] -struct Align16 { - x: u128, - y: u128, - z: u128, -} - -extern "C" { - fn extern_c_align1(x: Align1); - fn extern_c_align16(x: Align16); -} - -// CHECK-LABEL: @rust_to_c_increases_alignment -#[no_mangle] -pub unsafe fn rust_to_c_increases_alignment(x: Align1) { - // i686-linux: start: - // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca [48 x i8], align 4 - // i686-linux-NEXT: call void @llvm.lifetime.start.p0(i64 48, ptr {{.*}}[[ALLOCA]]) - // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 4 {{.*}}[[ALLOCA]], ptr {{.*}}align 1 {{.*}}%x - // i686-linux-NEXT: call void @extern_c_align1({{.+}} [[ALLOCA]]) - // i686-linux-NEXT: call void @llvm.lifetime.end.p0(i64 48, ptr {{.*}}[[ALLOCA]]) - - // x86_64-linux: start: - // x86_64-linux-NEXT: call void @extern_c_align1 - extern_c_align1(x); -} - -// CHECK-LABEL: @rust_to_c_decreases_alignment -#[no_mangle] -pub unsafe fn rust_to_c_decreases_alignment(x: Align16) { - // CHECK: start: - // CHECK-NEXT: call void @extern_c_align16 - extern_c_align16(x); -} - -extern "Rust" { - fn extern_rust_align1(x: Align1); - fn extern_rust_align16(x: Align16); -} - -// CHECK-LABEL: @c_to_rust_decreases_alignment -#[no_mangle] -pub unsafe extern "C" fn c_to_rust_decreases_alignment(x: Align1) { - // CHECK: start: - // CHECK-NEXT: call void @extern_rust_align1 - extern_rust_align1(x); -} - -// CHECK-LABEL: @c_to_rust_increases_alignment -#[no_mangle] -pub unsafe extern "C" fn c_to_rust_increases_alignment(x: Align16) { - // i686-linux: start: - // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca [48 x i8], align 16 - // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 16 {{.*}}[[ALLOCA]], ptr {{.*}}align 4 {{.*}}%0 - // i686-linux-NEXT: call void @extern_rust_align16({{.+}} [[ALLOCA]]) - - // x86_64-linux: start: - // x86_64-linux-NEXT: call void @extern_rust_align16 - extern_rust_align16(x); -} - -extern "Rust" { - fn extern_rust_ref_align1(x: &Align1); - fn extern_rust_ref_align16(x: &Align16); -} - -// CHECK-LABEL: @c_to_rust_ref_decreases_alignment -#[no_mangle] -pub unsafe extern "C" fn c_to_rust_ref_decreases_alignment(x: Align1) { - // CHECK: start: - // CHECK-NEXT: call void @extern_rust_ref_align1 - extern_rust_ref_align1(&x); -} - -// CHECK-LABEL: @c_to_rust_ref_increases_alignment -#[no_mangle] -pub unsafe extern "C" fn c_to_rust_ref_increases_alignment(x: Align16) { - // i686-linux: start: - // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca [48 x i8], align 16 - // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 16 {{.*}}[[ALLOCA]], ptr {{.*}}align 4 {{.*}}%0 - // i686-linux-NEXT: call void @extern_rust_ref_align16({{.+}} [[ALLOCA]]) - - // x86_64-linux: start: - // x86_64-linux-NEXT: call void @extern_rust_ref_align16 - extern_rust_ref_align16(&x); -} diff --git a/tests/codegen/align-byval-vector.rs b/tests/codegen/align-byval-vector.rs deleted file mode 100644 index c33b41a7bbe..00000000000 --- a/tests/codegen/align-byval-vector.rs +++ /dev/null @@ -1,55 +0,0 @@ -//@ add-core-stubs -//@ revisions:x86-linux x86-darwin - -//@[x86-linux] compile-flags: --target i686-unknown-linux-gnu -//@[x86-linux] needs-llvm-components: x86 -//@[x86-darwin] compile-flags: --target i686-apple-darwin -//@[x86-darwin] needs-llvm-components: x86 - -// Tests that aggregates containing vector types get their alignment increased to 16 on Darwin. - -#![feature(no_core, repr_simd, simd_ffi)] -#![crate_type = "lib"] -#![no_std] -#![no_core] -#![allow(non_camel_case_types)] - -extern crate minicore; -use minicore::*; - -#[repr(simd)] -pub struct i32x4([i32; 4]); - -#[repr(C)] -pub struct Foo { - a: i32x4, - b: i8, -} - -// This tests that we recursively check for vector types, not just at the top level. -#[repr(C)] -pub struct DoubleFoo { - one: Foo, - two: Foo, -} - -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() { - unsafe { f(Foo { a: i32x4([1, 2, 3, 4]), b: 0 }) } - - unsafe { - g(DoubleFoo { - one: Foo { a: i32x4([1, 2, 3, 4]), b: 0 }, - two: Foo { a: i32x4([1, 2, 3, 4]), b: 0 }, - }) - } -} diff --git a/tests/codegen/align-byval.rs b/tests/codegen/align-byval.rs deleted file mode 100644 index 75dabd74a79..00000000000 --- a/tests/codegen/align-byval.rs +++ /dev/null @@ -1,315 +0,0 @@ -// ignore-tidy-linelength -//@ add-core-stubs -//@ revisions:m68k x86_64-linux x86_64-windows i686-linux i686-windows - -//@[m68k] compile-flags: --target m68k-unknown-linux-gnu -//@[m68k] needs-llvm-components: m68k -//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu -//@[x86_64-linux] needs-llvm-components: x86 -//@[x86_64-windows] compile-flags: --target x86_64-pc-windows-msvc -//@[x86_64-windows] needs-llvm-components: x86 -//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu -//@[i686-linux] needs-llvm-components: x86 -//@[i686-windows] compile-flags: --target i686-pc-windows-msvc -//@[i686-windows] needs-llvm-components: x86 - -// Tests that `byval` alignment is properly specified (#80127). -// The only targets that use `byval` are m68k, x86-64, and x86. -// Note also that Windows mandates a by-ref ABI here, so it does not use byval. - -#![feature(no_core)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; - -// This struct can be represented as a pair, so it exercises the OperandValue::Pair -// codepath in `codegen_argument`. -#[repr(C)] -pub struct NaturalAlign1 { - a: i8, - b: i8, -} - -// This struct cannot be represented as an immediate, so it exercises the OperandValue::Ref -// codepath in `codegen_argument`. -#[repr(C)] -pub struct NaturalAlign2 { - a: [i16; 16], - b: i16, -} - -#[repr(C)] -#[repr(align(4))] -pub struct ForceAlign4 { - a: [i8; 16], - b: i8, -} - -// On i686-windows, this is passed on stack using `byval` -#[repr(C)] -pub struct NaturalAlign8 { - a: i64, - b: i64, - c: i64, -} - -// On i686-windows, this is passed by reference (because alignment is >4 and requested/forced), -// even though it has the exact same layout as `NaturalAlign8`! -#[repr(C)] -#[repr(align(8))] -pub struct ForceAlign8 { - a: i64, - b: i64, - c: i64, -} - -// On i686-windows, this is passed on stack, because requested alignment is <=4. -#[repr(C)] -#[repr(align(4))] -pub struct LowerFA8 { - a: i64, - b: i64, - c: i64, -} - -// On i686-windows, this is passed by reference, because it contains a field with -// requested/forced alignment. -#[repr(C)] -pub struct WrappedFA8 { - a: ForceAlign8, -} - -// On i686-windows, this has the same ABI as ForceAlign8, i.e. passed by reference. -#[repr(transparent)] -pub struct TransparentFA8 { - _0: (), - a: ForceAlign8, -} - -#[repr(C)] -#[repr(align(16))] -pub struct ForceAlign16 { - a: [i32; 16], - b: i8, -} - -// CHECK-LABEL: @call_na1 -#[no_mangle] -pub unsafe fn call_na1(x: NaturalAlign1) { - // CHECK: start: - - // m68k: [[ALLOCA:%[a-z0-9+]]] = alloca [2 x i8], align 1 - // m68k: call void @natural_align_1({{.*}}byval([2 x i8]) align 1{{.*}} [[ALLOCA]]) - - // x86_64-linux: 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]]) - - // i686-windows: [[ALLOCA:%[a-z0-9+]]] = alloca [2 x i8], align 4 - // i686-windows: call void @natural_align_1({{.*}}byval([2 x i8]) align 4{{.*}} [[ALLOCA]]) - natural_align_1(x); -} - -// CHECK-LABEL: @call_na2 -#[no_mangle] -pub unsafe fn call_na2(x: NaturalAlign2) { - // CHECK: start: - - // m68k-NEXT: call void @natural_align_2 - // x86_64-linux-NEXT: call void @natural_align_2 - // x86_64-windows-NEXT: call void @natural_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]]) - - // i686-windows: [[ALLOCA:%[0-9]+]] = alloca [34 x i8], align 4 - // i686-windows: call void @natural_align_2({{.*}}byval([34 x i8]) align 4{{.*}} [[ALLOCA]]) - natural_align_2(x); -} - -// 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); -} - -// 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{{.*}}) - - // 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{{.*}}) - - // i686-windows: declare void @natural_align_1({{.*}}byval([2 x i8]) align 4{{.*}}) - fn natural_align_1(x: NaturalAlign1); - - // m68k: 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{{.*}}) - - // 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-NOT: byval - // x86_64-windows-SAME: align 4{{.*}}) - - // i686-linux: declare 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); - - // m68k: declare void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) - - // x86_64-linux: declare void @natural_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) - - // x86_64-windows: declare 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-windows: declare void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) - fn natural_align_8(x: NaturalAlign8); - - // m68k: declare 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-windows: declare 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-windows: declare void @force_align_8( - // i686-windows-NOT: byval - // i686-windows-SAME: align 8{{.*}}) - fn force_align_8(x: ForceAlign8); - - // m68k: declare void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) - - // x86_64-linux: declare void @lower_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - - // x86_64-windows: declare 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-windows: declare void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) - fn lower_fa8(x: LowerFA8); - - // m68k: declare void @wrapped_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - - // x86_64-linux: declare void @wrapped_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - - // x86_64-windows: declare 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-windows: declare void @wrapped_fa8( - // i686-windows-NOT: byval - // i686-windows-SAME: align 8{{.*}}) - fn wrapped_fa8(x: WrappedFA8); - - // m68k: declare void @transparent_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - - // x86_64-linux: declare void @transparent_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - - // x86_64-windows: declare 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-windows: declare void @transparent_fa8( - // i686-windows-NOT: byval - // i686-windows-SAME: align 8{{.*}}) - fn transparent_fa8(x: TransparentFA8); - - // m68k: declare 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-windows: declare 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-windows: declare void @force_align_16( - // i686-windows-NOT: byval - // i686-windows-SAME: align 16{{.*}}) - fn force_align_16(x: ForceAlign16); -} diff --git a/tests/codegen/align-enum.rs b/tests/codegen/align-enum.rs deleted file mode 100644 index e8dd95d3afb..00000000000 --- a/tests/codegen/align-enum.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 -// - -#![crate_type = "lib"] - -#[repr(align(64))] -pub enum Align64 { - A(u32), - B(u32), -} - -pub struct Nested64 { - a: u8, - b: Align64, - c: u16, -} - -// CHECK-LABEL: @align64 -#[no_mangle] -pub fn align64(a: u32) -> Align64 { - // CHECK: %a64 = alloca [64 x i8], align 64 - // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 64 %{{.*}}, ptr align 64 %{{.*}}, i{{[0-9]+}} 64, i1 false) - let a64 = Align64::A(a); - a64 -} - -// CHECK-LABEL: @nested64 -#[no_mangle] -pub fn nested64(a: u8, b: u32, c: u16) -> Nested64 { - // CHECK: %n64 = alloca [128 x i8], align 64 - let n64 = Nested64 { a, b: Align64::B(b), c }; - n64 -} diff --git a/tests/codegen/align-fn.rs b/tests/codegen/align-fn.rs deleted file mode 100644 index cbc24e2ae2e..00000000000 --- a/tests/codegen/align-fn.rs +++ /dev/null @@ -1,143 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 -Clink-dead-code -//@ edition: 2024 -//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) - -#![crate_type = "lib"] -// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity -#![feature(rustc_attrs)] -#![feature(fn_align)] - -// CHECK: align 16 -#[unsafe(no_mangle)] -#[rustc_align(16)] -pub fn fn_align() {} - -pub struct A; - -impl A { - // CHECK: align 16 - #[unsafe(no_mangle)] - #[rustc_align(16)] - pub fn method_align(self) {} - - // CHECK: align 16 - #[unsafe(no_mangle)] - #[rustc_align(16)] - pub fn associated_fn() {} -} - -trait T: Sized { - fn trait_fn() {} - - fn trait_method(self) {} - - #[rustc_align(8)] - fn trait_method_inherit_low(self); - - #[rustc_align(32)] - fn trait_method_inherit_high(self); - - #[rustc_align(32)] - fn trait_method_inherit_default(self) {} - - #[rustc_align(4)] - #[rustc_align(128)] - #[rustc_align(8)] - fn inherit_highest(self) {} -} - -impl T for A { - // CHECK-LABEL: trait_fn - // CHECK-SAME: align 16 - #[unsafe(no_mangle)] - #[rustc_align(16)] - fn trait_fn() {} - - // CHECK-LABEL: trait_method - // CHECK-SAME: align 16 - #[unsafe(no_mangle)] - #[rustc_align(16)] - fn trait_method(self) {} - - // The prototype's align is ignored because the align here is higher. - // CHECK-LABEL: trait_method_inherit_low - // CHECK-SAME: align 16 - #[unsafe(no_mangle)] - #[rustc_align(16)] - fn trait_method_inherit_low(self) {} - - // The prototype's align is used because it is higher. - // CHECK-LABEL: trait_method_inherit_high - // CHECK-SAME: align 32 - #[unsafe(no_mangle)] - #[rustc_align(16)] - fn trait_method_inherit_high(self) {} - - // The prototype's align inherited. - // CHECK-LABEL: trait_method_inherit_default - // CHECK-SAME: align 32 - #[unsafe(no_mangle)] - fn trait_method_inherit_default(self) {} - - // The prototype's highest align inherited. - // CHECK-LABEL: inherit_highest - // CHECK-SAME: align 128 - #[unsafe(no_mangle)] - #[rustc_align(32)] - #[rustc_align(64)] - fn inherit_highest(self) {} -} - -trait HasDefaultImpl: Sized { - // CHECK-LABEL: inherit_from_default_method - // CHECK-LABEL: inherit_from_default_method - // CHECK-SAME: align 32 - #[rustc_align(32)] - fn inherit_from_default_method(self) {} -} - -pub struct InstantiateDefaultMethods; - -impl HasDefaultImpl for InstantiateDefaultMethods {} - -// CHECK-LABEL: align_specified_twice_1 -// CHECK-SAME: align 64 -#[unsafe(no_mangle)] -#[rustc_align(32)] -#[rustc_align(64)] -pub fn align_specified_twice_1() {} - -// CHECK-LABEL: align_specified_twice_2 -// CHECK-SAME: align 128 -#[unsafe(no_mangle)] -#[rustc_align(128)] -#[rustc_align(32)] -pub fn align_specified_twice_2() {} - -// CHECK-LABEL: align_specified_twice_3 -// CHECK-SAME: align 256 -#[unsafe(no_mangle)] -#[rustc_align(32)] -#[rustc_align(256)] -pub fn align_specified_twice_3() {} - -const _: () = { - // CHECK-LABEL: align_unmangled - // CHECK-SAME: align 256 - #[unsafe(no_mangle)] - #[rustc_align(32)] - #[rustc_align(256)] - extern "C" fn align_unmangled() {} -}; - -unsafe extern "C" { - #[rustc_align(256)] - fn align_unmangled(); -} - -// FIXME also check `gen` et al -// CHECK-LABEL: async_align -// CHECK-SAME: align 64 -#[unsafe(no_mangle)] -#[rustc_align(64)] -pub async fn async_align() {} diff --git a/tests/codegen/align-offset.rs b/tests/codegen/align-offset.rs deleted file mode 100644 index 21062cc0a91..00000000000 --- a/tests/codegen/align-offset.rs +++ /dev/null @@ -1,75 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @align8 -#[no_mangle] -pub fn align8(p: *const u8) -> bool { - // CHECK: ret i1 true - p.align_offset(8) < 8 -} - -#[repr(align(4))] -pub struct Align4([u8; 4]); - -// CHECK-LABEL: @align_to4 -#[no_mangle] -pub fn align_to4(x: &[u8]) -> bool { - // CHECK: ret i1 true - let (prefix, _middle, suffix) = unsafe { x.align_to::() }; - prefix.len() < 4 && suffix.len() < 4 -} - -// CHECK-LABEL: @align_offset_byte_ptr(ptr{{.+}}%ptr) -#[no_mangle] -pub fn align_offset_byte_ptr(ptr: *const u8) -> usize { - // CHECK: %[[ADDR:.+]] = ptrtoint ptr %ptr to [[USIZE:i[0-9]+]] - // CHECK: %[[UP:.+]] = add [[USIZE]] %[[ADDR]], 31 - // CHECK: %[[ALIGNED:.+]] = and [[USIZE]] %[[UP]], -32 - // CHECK: %[[OFFSET:.+]] = sub [[USIZE]] %[[ALIGNED]], %[[ADDR]] - - // Since we're offsetting a byte pointer, there's no further fixups - // CHECK-NOT: shr - // CHECK-NOT: div - // CHECK-NOT: select - - // CHECK: ret [[USIZE]] %[[OFFSET]] - ptr.align_offset(32) -} - -// CHECK-LABEL: @align_offset_word_slice(ptr{{.+}}align 4{{.+}}%slice.0 -#[no_mangle] -pub fn align_offset_word_slice(slice: &[Align4]) -> usize { - // CHECK: %[[ADDR:.+]] = ptrtoint ptr %slice.0 to [[USIZE]] - // CHECK: %[[UP:.+]] = add [[USIZE]] %[[ADDR]], 31 - // CHECK: %[[ALIGNED:.+]] = and [[USIZE]] %[[UP]], -32 - // CHECK: %[[BOFFSET:.+]] = sub [[USIZE]] %[[ALIGNED]], %[[ADDR]] - // CHECK: %[[OFFSET:.+]] = lshr exact [[USIZE]] %[[BOFFSET]], 2 - - // Slices are known to be aligned, so we don't need the "maybe -1" path - // CHECK-NOT: select - - // CHECK: ret [[USIZE]] %[[OFFSET]] - slice.as_ptr().align_offset(32) -} - -// CHECK-LABEL: @align_offset_word_ptr(ptr{{.+}}%ptr -#[no_mangle] -pub fn align_offset_word_ptr(ptr: *const Align4) -> usize { - // CHECK: %[[ADDR:.+]] = ptrtoint ptr %ptr to [[USIZE]] - // CHECK: %[[UP:.+]] = add [[USIZE]] %[[ADDR]], 31 - // CHECK: %[[ALIGNED:.+]] = and [[USIZE]] %[[UP]], -32 - // CHECK: %[[BOFFSET:.+]] = sub [[USIZE]] %[[ALIGNED]], %[[ADDR]] - - // While we can always get a *byte* offset that will work, if the original - // pointer is unaligned it might be impossible to return an *element* offset - // that will make it aligned. We want it to be a `select`, not a `br`, so - // that the assembly will be branchless. - // CHECK: %[[LOW:.+]] = and [[USIZE]] %[[ADDR]], 3 - // CHECK: %[[ORIGINAL_ALIGNED:.+]] = icmp eq [[USIZE]] %[[LOW]], 0 - // CHECK: %[[OFFSET:.+]] = lshr exact [[USIZE]] %[[BOFFSET]], 2 - // CHECK: %[[R:.+]] = select i1 %[[ORIGINAL_ALIGNED]], [[USIZE]] %[[OFFSET]], [[USIZE]] -1 - - // CHECK: ret [[USIZE]] %[[R]] - ptr.align_offset(32) -} diff --git a/tests/codegen/align-struct.rs b/tests/codegen/align-struct.rs deleted file mode 100644 index d4cc65e9158..00000000000 --- a/tests/codegen/align-struct.rs +++ /dev/null @@ -1,70 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 -// 32bit MSVC does not align things properly so we suppress high alignment annotations (#112480) -//@ ignore-i686-pc-windows-msvc -//@ ignore-i686-pc-windows-gnu - -#![crate_type = "lib"] - -#[repr(align(64))] -pub struct Align64(i32); - -pub struct Nested64 { - a: Align64, - b: i32, - c: i32, - d: i8, -} - -// This has the extra field in B to ensure it's not ScalarPair, -// and thus that the test actually emits it via memory, not `insertvalue`. -pub enum Enum4 { - A(i32), - B(i32, i32), -} - -pub enum Enum64 { - A(Align64), - B(i32), -} - -// CHECK-LABEL: @align64 -#[no_mangle] -pub fn align64(i: i32) -> Align64 { - // CHECK: %a64 = alloca [64 x i8], align 64 - // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 64 %{{.*}}, ptr align 64 %{{.*}}, i{{[0-9]+}} 64, i1 false) - let a64 = Align64(i); - a64 -} - -// For issue 54028: make sure that we are specifying the correct alignment for fields of aligned -// structs -// CHECK-LABEL: @align64_load -#[no_mangle] -pub fn align64_load(a: Align64) -> i32 { - // CHECK: {{%.*}} = load i32, ptr {{%.*}}, align 64 - a.0 -} - -// CHECK-LABEL: @nested64 -#[no_mangle] -pub fn nested64(a: Align64, b: i32, c: i32, d: i8) -> Nested64 { - // CHECK: %n64 = alloca [128 x i8], align 64 - let n64 = Nested64 { a, b, c, d }; - n64 -} - -// CHECK-LABEL: @enum4 -#[no_mangle] -pub fn enum4(a: i32) -> Enum4 { - // CHECK: %e4 = alloca [12 x i8], align 4 - let e4 = Enum4::A(a); - e4 -} - -// CHECK-LABEL: @enum64 -#[no_mangle] -pub fn enum64(a: Align64) -> Enum64 { - // CHECK: %e64 = alloca [128 x i8], align 64 - let e64 = Enum64::A(a); - e64 -} diff --git a/tests/codegen/alloc-optimisation.rs b/tests/codegen/alloc-optimisation.rs deleted file mode 100644 index 3735860d510..00000000000 --- a/tests/codegen/alloc-optimisation.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -#[no_mangle] -pub fn alloc_test(data: u32) { - // CHECK-LABEL: @alloc_test - // CHECK-NEXT: start: - // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 - // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() - // CHECK-NEXT: ret void - let x = Box::new(data); - drop(x); -} diff --git a/tests/codegen/amdgpu-addrspacecast.rs b/tests/codegen/amdgpu-addrspacecast.rs deleted file mode 100644 index 7fe630a7efa..00000000000 --- a/tests/codegen/amdgpu-addrspacecast.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Check that pointers are casted to addrspace(0) before they are used - -//@ compile-flags: --crate-type=rlib --target=amdgcn-amd-amdhsa -Ctarget-cpu=gfx900 -//@ needs-llvm-components: amdgpu -//@ add-core-stubs -#![feature(no_core)] -#![no_core] - -extern crate minicore; - -// CHECK-LABEL: @ref_of_local -// CHECK: [[alloca:%[0-9]]] = alloca -// CHECK: %i = addrspacecast ptr addrspace(5) [[alloca]] to ptr -#[no_mangle] -pub fn ref_of_local(f: fn(&i32)) { - let i = 0; - f(&i); -} diff --git a/tests/codegen/array-clone.rs b/tests/codegen/array-clone.rs deleted file mode 100644 index 35445174684..00000000000 --- a/tests/codegen/array-clone.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @array_clone -#[no_mangle] -pub fn array_clone(a: &[u8; 2]) -> [u8; 2] { - // CHECK-NOT: getelementptr - // CHECK-NOT: load i8 - // CHECK-NOT: zext - // CHECK-NOT: shl - // CHECK: load i16 - // CHECK-NEXT: ret i16 - a.clone() -} diff --git a/tests/codegen/array-cmp.rs b/tests/codegen/array-cmp.rs deleted file mode 100644 index 0d337655401..00000000000 --- a/tests/codegen/array-cmp.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Ensure the asm for array comparisons is properly optimized. - -//@ compile-flags: -C opt-level=2 -//@ needs-deterministic-layouts (checks depend on tuple layout) - -#![crate_type = "lib"] - -// CHECK-LABEL: @compare -// CHECK: start: -// CHECK-NEXT: ret i1 true -#[no_mangle] -pub fn compare() -> bool { - let bytes = 12.5f32.to_ne_bytes(); - bytes - == if cfg!(target_endian = "big") { - [0x41, 0x48, 0x00, 0x00] - } else { - [0x00, 0x00, 0x48, 0x41] - } -} - -// CHECK-LABEL: @array_of_tuple_le -#[no_mangle] -pub fn array_of_tuple_le(a: &[(i16, u16); 2], b: &[(i16, u16); 2]) -> bool { - // Ensure that, after all the optimizations have run, the happy path just checks - // `eq` on each corresponding pair and moves onto the next one if it is. - // Then there's a dedup'd comparison for the place that's different. - // (As opposed to, say, running a full `[su]cmp` as part of checking equality.) - - // This is written quite specifically because different library code was triggering - // along the way, so this - // has enough checks to make sure that's not happening. It doesn't need to be - // *exactly* this IR, but be careful if you ever need to update these checks. - - // CHECK: start: - // CHECK: %[[A00:.+]] = load i16, ptr %a - // CHECK: %[[B00:.+]] = load i16, ptr %b - // CHECK-NOT: cmp - // CHECK: %[[EQ00:.+]] = icmp eq i16 %[[A00]], %[[B00]] - // CHECK-NEXT: br i1 %[[EQ00]], label %[[L01:.+]], label %[[EXIT_S:.+]] - - // CHECK: [[L01]]: - // CHECK: %[[PA01:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 2 - // CHECK: %[[PB01:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 2 - // CHECK: %[[A01:.+]] = load i16, ptr %[[PA01]] - // CHECK: %[[B01:.+]] = load i16, ptr %[[PB01]] - // CHECK-NOT: cmp - // CHECK: %[[EQ01:.+]] = icmp eq i16 %[[A01]], %[[B01]] - // CHECK-NEXT: br i1 %[[EQ01]], label %[[L10:.+]], label %[[EXIT_U:.+]] - - // CHECK: [[L10]]: - // CHECK: %[[PA10:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 4 - // CHECK: %[[PB10:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 4 - // CHECK: %[[A10:.+]] = load i16, ptr %[[PA10]] - // CHECK: %[[B10:.+]] = load i16, ptr %[[PB10]] - // CHECK-NOT: cmp - // CHECK: %[[EQ10:.+]] = icmp eq i16 %[[A10]], %[[B10]] - // CHECK-NEXT: br i1 %[[EQ10]], label %[[L11:.+]], label %[[EXIT_S]] - - // CHECK: [[L11]]: - // CHECK: %[[PA11:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 6 - // CHECK: %[[PB11:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 6 - // CHECK: %[[A11:.+]] = load i16, ptr %[[PA11]] - // CHECK: %[[B11:.+]] = load i16, ptr %[[PB11]] - // CHECK-NOT: cmp - // CHECK: %[[EQ11:.+]] = icmp eq i16 %[[A11]], %[[B11]] - // CHECK-NEXT: br i1 %[[EQ11]], label %[[DONE:.+]], label %[[EXIT_U]] - - // CHECK: [[DONE]]: - // CHECK: %[[RET:.+]] = phi i1 [ %{{.+}}, %[[EXIT_S]] ], [ %{{.+}}, %[[EXIT_U]] ], [ true, %[[L11]] ] - // CHECK: ret i1 %[[RET]] - - a <= b -} diff --git a/tests/codegen/array-codegen.rs b/tests/codegen/array-codegen.rs deleted file mode 100644 index 9b0c6e8c347..00000000000 --- a/tests/codegen/array-codegen.rs +++ /dev/null @@ -1,62 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes - -#![crate_type = "lib"] - -// CHECK-LABEL: @array_load -#[no_mangle] -pub fn array_load(a: &[u8; 4]) -> [u8; 4] { - // CHECK-NOT: alloca - // CHECK: %[[ALLOCA:.+]] = alloca [4 x i8], align 1 - // CHECK-NOT: alloca - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[ALLOCA]], ptr align 1 %a, {{.+}} 4, i1 false) - // CHECK: %[[TEMP:.+]] = load i32, ptr %[[ALLOCA]], align 1 - // CHECK: ret i32 %[[TEMP]] - *a -} - -// CHECK-LABEL: @array_store -#[no_mangle] -pub fn array_store(a: [u8; 4], p: &mut [u8; 4]) { - // CHECK-NOT: alloca - // CHECK: %[[TEMP:.+]] = alloca [4 x i8], [[TEMPALIGN:align [0-9]+]] - // CHECK-NOT: alloca - // CHECK: %a = alloca [4 x i8] - // CHECK-NOT: alloca - // store i32 %0, ptr %[[TEMP]] - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %a, ptr [[TEMPALIGN]] %[[TEMP]], {{.+}} 4, i1 false) - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %a, {{.+}} 4, i1 false) - *p = a; -} - -// CHECK-LABEL: @array_copy -#[no_mangle] -pub fn array_copy(a: &[u8; 4], p: &mut [u8; 4]) { - // CHECK-NOT: alloca - // CHECK: %[[LOCAL:.+]] = alloca [4 x i8], align 1 - // CHECK-NOT: alloca - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[LOCAL]], ptr align 1 %a, {{.+}} 4, i1 false) - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %[[LOCAL]], {{.+}} 4, i1 false) - *p = *a; -} - -// CHECK-LABEL: @array_copy_1_element -#[no_mangle] -pub fn array_copy_1_element(a: &[u8; 1], p: &mut [u8; 1]) { - // CHECK-NOT: alloca - // CHECK: %[[LOCAL:.+]] = alloca [1 x i8], align 1 - // CHECK-NOT: alloca - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[LOCAL]], ptr align 1 %a, {{.+}} 1, i1 false) - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %[[LOCAL]], {{.+}} 1, i1 false) - *p = *a; -} - -// CHECK-LABEL: @array_copy_2_elements -#[no_mangle] -pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) { - // CHECK-NOT: alloca - // CHECK: %[[LOCAL:.+]] = alloca [2 x i8], align 1 - // CHECK-NOT: alloca - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[LOCAL]], ptr align 1 %a, {{.+}} 2, i1 false) - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %[[LOCAL]], {{.+}} 2, i1 false) - *p = *a; -} diff --git a/tests/codegen/array-equality.rs b/tests/codegen/array-equality.rs deleted file mode 100644 index fa0475bf480..00000000000 --- a/tests/codegen/array-equality.rs +++ /dev/null @@ -1,101 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled -//@ only-x86_64 -#![crate_type = "lib"] - -// CHECK-LABEL: @array_eq_value -#[no_mangle] -pub fn array_eq_value(a: [u16; 3], b: [u16; 3]) -> bool { - // CHECK-NEXT: start: - // CHECK-NEXT: %2 = icmp eq i48 %0, %1 - // CHECK-NEXT: ret i1 %2 - a == b -} - -// CHECK-LABEL: @array_eq_ref -#[no_mangle] -pub fn array_eq_ref(a: &[u16; 3], b: &[u16; 3]) -> bool { - // CHECK: start: - // CHECK: load i48, ptr %{{.+}}, align 2 - // CHECK: load i48, ptr %{{.+}}, align 2 - // CHECK: icmp eq i48 - // CHECK-NEXT: ret - a == b -} - -// CHECK-LABEL: @array_eq_value_still_passed_by_pointer -#[no_mangle] -pub fn array_eq_value_still_passed_by_pointer(a: [u16; 9], b: [u16; 9]) -> bool { - // CHECK-NEXT: start: - // CHECK: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(ptr {{.*}} dereferenceable(18) %{{.+}}, ptr {{.*}} dereferenceable(18) %{{.+}}, i64 18) - // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0 - // CHECK-NEXT: ret i1 %[[EQ]] - a == b -} - -// CHECK-LABEL: @array_eq_long -#[no_mangle] -pub fn array_eq_long(a: &[u16; 1234], b: &[u16; 1234]) -> bool { - // CHECK-NEXT: start: - // CHECK: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(ptr {{.*}} dereferenceable(2468) %{{.+}}, ptr {{.*}} dereferenceable(2468) %{{.+}}, i64 2468) - // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0 - // CHECK-NEXT: ret i1 %[[EQ]] - a == b -} - -// CHECK-LABEL: @array_char_eq -#[no_mangle] -pub fn array_char_eq(a: [char; 2], b: [char; 2]) -> bool { - // CHECK-NEXT: start: - // CHECK-NEXT: %[[EQ:.+]] = icmp eq i64 %0, %1 - // CHECK-NEXT: ret i1 %[[EQ]] - a == b -} - -// CHECK-LABEL: @array_eq_zero_short(i48 -#[no_mangle] -pub fn array_eq_zero_short(x: [u16; 3]) -> bool { - // CHECK-NEXT: start: - // CHECK-NEXT: %[[EQ:.+]] = icmp eq i48 %0, 0 - // CHECK-NEXT: ret i1 %[[EQ]] - x == [0; 3] -} - -// CHECK-LABEL: @array_eq_none_short(i40 -#[no_mangle] -pub fn array_eq_none_short(x: [Option>; 5]) -> bool { - // CHECK-NEXT: start: - // CHECK-NEXT: %[[EQ:.+]] = icmp eq i40 %0, 0 - // CHECK-NEXT: ret i1 %[[EQ]] - x == [None; 5] -} - -// CHECK-LABEL: @array_eq_zero_nested( -#[no_mangle] -pub fn array_eq_zero_nested(x: [[u8; 3]; 3]) -> bool { - // CHECK: %[[VAL:.+]] = load i72 - // CHECK-SAME: align 1 - // CHECK: %[[EQ:.+]] = icmp eq i72 %[[VAL]], 0 - // CHECK: ret i1 %[[EQ]] - x == [[0; 3]; 3] -} - -// CHECK-LABEL: @array_eq_zero_mid( -#[no_mangle] -pub fn array_eq_zero_mid(x: [u16; 8]) -> bool { - // CHECK-NEXT: start: - // CHECK: %[[LOAD:.+]] = load i128, - // CHECK-NEXT: %[[EQ:.+]] = icmp eq i128 %[[LOAD]], 0 - // CHECK-NEXT: ret i1 %[[EQ]] - x == [0; 8] -} - -// CHECK-LABEL: @array_eq_zero_long( -#[no_mangle] -pub fn array_eq_zero_long(x: [u16; 1234]) -> bool { - // CHECK-NEXT: start: - // CHECK-NOT: alloca - // CHECK: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}( - // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0 - // CHECK-NEXT: ret i1 %[[EQ]] - x == [0; 1234] -} diff --git a/tests/codegen/array-from_fn.rs b/tests/codegen/array-from_fn.rs deleted file mode 100644 index 7202d0c67e6..00000000000 --- a/tests/codegen/array-from_fn.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ revisions: NORMAL OPT -//@ [NORMAL] compile-flags: -C opt-level=0 -C debuginfo=2 -//@ [OPT] compile-flags: -C opt-level=s -C debuginfo=0 - -#![crate_type = "lib"] -#![feature(array_from_fn)] - -#[no_mangle] -pub fn iota() -> [u8; 16] { - // OPT-NOT: core..array..Guard - // NORMAL: core..array..Guard - std::array::from_fn(|i| i as _) -} diff --git a/tests/codegen/array-map.rs b/tests/codegen/array-map.rs deleted file mode 100644 index f49dddcfc20..00000000000 --- a/tests/codegen/array-map.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@ compile-flags: -C opt-level=3 -C target-cpu=x86-64-v3 -//@ only-x86_64 - -#![crate_type = "lib"] - -// CHECK-LABEL: @short_integer_map -#[no_mangle] -pub fn short_integer_map(x: [u32; 8]) -> [u32; 8] { - // CHECK: load <8 x i32> - // CHECK: shl <8 x i32> - // CHECK: or{{( disjoint)?}} <8 x i32> - // CHECK: store <8 x i32> - x.map(|x| 2 * x + 1) -} - -// This test is checking that LLVM can SRoA away a bunch of the overhead, -// like fully moving the iterators to registers. Notably, previous implementations -// of `map` ended up `alloca`ing the whole `array::IntoIterator`, meaning both a -// hard-to-eliminate `memcpy` and that the iteration counts needed to be written -// out to stack every iteration, even for infallible operations on `Copy` types. -// -// This is still imperfect, as there's more copies than would be ideal, -// but hopefully work like #103830 will improve that in future, -// and update this test to be stricter. -// -// CHECK-LABEL: @long_integer_map -#[no_mangle] -pub fn long_integer_map(x: [u32; 512]) -> [u32; 512] { - // CHECK: start: - // CHECK-NEXT: alloca [2048 x i8] - // CHECK-NOT: alloca - // CHECK: mul <{{[0-9]+}} x i32> - // CHECK: add <{{[0-9]+}} x i32> - x.map(|x| 13 * x + 7) -} diff --git a/tests/codegen/array-optimized.rs b/tests/codegen/array-optimized.rs deleted file mode 100644 index 000163d5519..00000000000 --- a/tests/codegen/array-optimized.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @array_copy_1_element -#[no_mangle] -pub fn array_copy_1_element(a: &[u8; 1], p: &mut [u8; 1]) { - // CHECK-NOT: alloca - // CHECK: %[[TEMP:.+]] = load i8, ptr %a, align 1 - // CHECK: store i8 %[[TEMP]], ptr %p, align 1 - // CHECK: ret - *p = *a; -} - -// CHECK-LABEL: @array_copy_2_elements -#[no_mangle] -pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) { - // CHECK-NOT: alloca - // CHECK: %[[TEMP:.+]] = load i16, ptr %a, align 1 - // CHECK: store i16 %[[TEMP]], ptr %p, align 1 - // CHECK: ret - *p = *a; -} - -// CHECK-LABEL: @array_copy_4_elements -#[no_mangle] -pub fn array_copy_4_elements(a: &[u8; 4], p: &mut [u8; 4]) { - // CHECK-NOT: alloca - // CHECK: %[[TEMP:.+]] = load i32, ptr %a, align 1 - // CHECK: store i32 %[[TEMP]], ptr %p, align 1 - // CHECK: ret - *p = *a; -} diff --git a/tests/codegen/array-repeat.rs b/tests/codegen/array-repeat.rs deleted file mode 100644 index 4c755df9390..00000000000 --- a/tests/codegen/array-repeat.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] -#![feature(array_repeat)] - -use std::array::repeat; - -// CHECK-LABEL: @byte_repeat -#[no_mangle] -fn byte_repeat(b: u8) -> [u8; 1024] { - // CHECK-NOT: alloca - // CHECK-NOT: store - // CHECK: memset - repeat(b) -} diff --git a/tests/codegen/ascii-char.rs b/tests/codegen/ascii-char.rs deleted file mode 100644 index 86ec9d73afe..00000000000 --- a/tests/codegen/ascii-char.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ compile-flags: -C opt-level=1 - -#![crate_type = "lib"] -#![feature(ascii_char)] - -use std::ascii::Char as AsciiChar; - -// CHECK-LABEL: i8 @unwrap_digit_from_remainder(i32 -#[no_mangle] -pub fn unwrap_digit_from_remainder(v: u32) -> AsciiChar { - // CHECK-NOT: icmp - // CHECK-NOT: panic - - // CHECK: %[[R:.+]] = urem i32 %v, 10 - // CHECK-NEXT: %[[T:.+]] = trunc{{( nuw)?( nsw)?}} i32 %[[R]] to i8 - // CHECK-NEXT: %[[D:.+]] = or{{( disjoint)?}} i8 %[[T]], 48 - // CHECK-NEXT: ret i8 %[[D]] - - // CHECK-NOT: icmp - // CHECK-NOT: panic - AsciiChar::digit((v % 10) as u8).unwrap() -} - -// CHECK-LABEL: i8 @unwrap_from_masked(i8 -#[no_mangle] -pub fn unwrap_from_masked(b: u8) -> AsciiChar { - // CHECK-NOT: icmp - // CHECK-NOT: panic - - // CHECK: %[[M:.+]] = and i8 %b, 127 - // CHECK-NEXT: ret i8 %[[M]] - - // CHECK-NOT: icmp - // CHECK-NOT: panic - AsciiChar::from_u8(b & 0x7f).unwrap() -} diff --git a/tests/codegen/asm/aarch64-clobbers.rs b/tests/codegen/asm/aarch64-clobbers.rs deleted file mode 100644 index dd3ba1510b5..00000000000 --- a/tests/codegen/asm/aarch64-clobbers.rs +++ /dev/null @@ -1,47 +0,0 @@ -//@ add-core-stubs -//@ revisions: aarch64 aarch64_fixed_x18 aarch64_no_x18 aarch64_reserve_x18 arm64ec -//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu -//@[aarch64] needs-llvm-components: aarch64 -//@[aarch64_fixed_x18] compile-flags: --target aarch64-unknown-linux-gnu -Zfixed-x18 -//@[aarch64_fixed_x18] needs-llvm-components: aarch64 -//@[aarch64_no_x18] compile-flags: --target aarch64-pc-windows-msvc -//@[aarch64_no_x18] needs-llvm-components: aarch64 -// aarch64-unknown-trusty uses aarch64-unknown-unknown-musl which doesn't -// reserve x18 by default as llvm_target, and pass +reserve-x18 in target-spec. -//@[aarch64_reserve_x18] compile-flags: --target aarch64-unknown-trusty -//@[aarch64_reserve_x18] needs-llvm-components: aarch64 -//@[arm64ec] compile-flags: --target arm64ec-pc-windows-msvc -//@[arm64ec] needs-llvm-components: aarch64 -// ignore-tidy-linelength - -#![crate_type = "rlib"] -#![feature(no_core)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: @cc_clobber -// CHECK: call void asm sideeffect "", "~{cc}"() -#[no_mangle] -pub unsafe fn cc_clobber() { - asm!("", options(nostack, nomem)); -} - -// CHECK-LABEL: @no_clobber -// CHECK: call void asm sideeffect "", ""() -#[no_mangle] -pub unsafe fn no_clobber() { - asm!("", options(nostack, nomem, preserves_flags)); -} - -// CHECK-LABEL: @clobber_abi -// aarch64: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w13},={w14},={w15},={w16},={w17},={w18},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15},={q16},={q17},={q18},={q19},={q20},={q21},={q22},={q23},={q24},={q25},={q26},={q27},={q28},={q29},={q30},={q31},~{p0},~{p1},~{p2},~{p3},~{p4},~{p5},~{p6},~{p7},~{p8},~{p9},~{p10},~{p11},~{p12},~{p13},~{p14},~{p15},~{ffr}"() -// aarch64_fixed_x18: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w13},={w14},={w15},={w16},={w17},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15},={q16},={q17},={q18},={q19},={q20},={q21},={q22},={q23},={q24},={q25},={q26},={q27},={q28},={q29},={q30},={q31},~{p0},~{p1},~{p2},~{p3},~{p4},~{p5},~{p6},~{p7},~{p8},~{p9},~{p10},~{p11},~{p12},~{p13},~{p14},~{p15},~{ffr}"() -// aarch64_no_x18: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w13},={w14},={w15},={w16},={w17},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15},={q16},={q17},={q18},={q19},={q20},={q21},={q22},={q23},={q24},={q25},={q26},={q27},={q28},={q29},={q30},={q31},~{p0},~{p1},~{p2},~{p3},~{p4},~{p5},~{p6},~{p7},~{p8},~{p9},~{p10},~{p11},~{p12},~{p13},~{p14},~{p15},~{ffr}"() -// aarch64_reserve_x18: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w13},={w14},={w15},={w16},={w17},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15},={q16},={q17},={q18},={q19},={q20},={q21},={q22},={q23},={q24},={q25},={q26},={q27},={q28},={q29},={q30},={q31},~{p0},~{p1},~{p2},~{p3},~{p4},~{p5},~{p6},~{p7},~{p8},~{p9},~{p10},~{p11},~{p12},~{p13},~{p14},~{p15},~{ffr}"() -// arm64ec: asm sideeffect "", "={w0},={w1},={w2},={w3},={w4},={w5},={w6},={w7},={w8},={w9},={w10},={w11},={w12},={w15},={w16},={w17},={w30},={q0},={q1},={q2},={q3},={q4},={q5},={q6},={q7},={q8},={q9},={q10},={q11},={q12},={q13},={q14},={q15}"() -#[no_mangle] -pub unsafe fn clobber_abi() { - asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); -} diff --git a/tests/codegen/asm/avr-clobbers.rs b/tests/codegen/asm/avr-clobbers.rs deleted file mode 100644 index 9451127bf04..00000000000 --- a/tests/codegen/asm/avr-clobbers.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: --target avr-none -C target-cpu=atmega328p -//@ needs-llvm-components: avr - -#![crate_type = "rlib"] -#![feature(no_core, asm_experimental_arch)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: @sreg_is_clobbered -// CHECK: void asm sideeffect "", "~{sreg}"() -#[no_mangle] -pub unsafe fn sreg_is_clobbered() { - asm!("", options(nostack, nomem)); -} - -// CHECK-LABEL: @sreg_is_not_clobbered_if_preserve_flags_is_used -// CHECK: void asm sideeffect "", ""() -#[no_mangle] -pub unsafe fn sreg_is_not_clobbered_if_preserve_flags_is_used() { - asm!("", options(nostack, nomem, preserves_flags)); -} - -// CHECK-LABEL: @clobber_abi -// CHECK: asm sideeffect "", "={r18},={r19},={r20},={r21},={r22},={r23},={r24},={r25},={r26},={r27},={r30},={r31},~{sreg}"() -#[no_mangle] -pub unsafe fn clobber_abi() { - asm!("", clobber_abi("C"), options(nostack, nomem)); -} - -// CHECK-LABEL: @clobber_abi_with_preserved_flags -// CHECK: asm sideeffect "", "={r18},={r19},={r20},={r21},={r22},={r23},={r24},={r25},={r26},={r27},={r30},={r31}"() -#[no_mangle] -pub unsafe fn clobber_abi_with_preserved_flags() { - asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); -} diff --git a/tests/codegen/asm/bpf-clobbers.rs b/tests/codegen/asm/bpf-clobbers.rs deleted file mode 100644 index 1117549b1ec..00000000000 --- a/tests/codegen/asm/bpf-clobbers.rs +++ /dev/null @@ -1,31 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: --target bpfel-unknown-none -//@ needs-llvm-components: bpf - -#![crate_type = "rlib"] -#![feature(no_core, asm_experimental_arch)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: @flags_clobber -// CHECK: call void asm sideeffect "", ""() -#[no_mangle] -pub unsafe fn flags_clobber() { - asm!("", options(nostack, nomem)); -} - -// CHECK-LABEL: @no_clobber -// CHECK: call void asm sideeffect "", ""() -#[no_mangle] -pub unsafe fn no_clobber() { - asm!("", options(nostack, nomem, preserves_flags)); -} - -// CHECK-LABEL: @clobber_abi -// CHECK: asm sideeffect "", "={r0},={r1},={r2},={r3},={r4},={r5}"() -#[no_mangle] -pub unsafe fn clobber_abi() { - asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); -} diff --git a/tests/codegen/asm/critical.rs b/tests/codegen/asm/critical.rs deleted file mode 100644 index 0f29d7c69b4..00000000000 --- a/tests/codegen/asm/critical.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ only-x86_64 -//@ compile-flags: -C no-prepopulate-passes -#![feature(asm_goto_with_outputs)] -#![crate_type = "lib"] -use std::arch::asm; - -// Regression test for #137867. Check that critical edges have been split before code generation, -// and so all stores to the asm output occur on disjoint paths without any of them jumping to -// another callbr label. -// -// CHECK-LABEL: @f( -// CHECK: [[OUT:%.*]] = callbr i32 asm -// CHECK-NEXT: to label %[[BB0:.*]] [label %[[BB1:.*]], label %[[BB2:.*]]], -// CHECK: [[BB1]]: -// CHECK-NEXT: store i32 [[OUT]], ptr %a -// CHECK-NEXT: br label %[[BBR:.*]] -// CHECK: [[BB2]]: -// CHECK-NEXT: store i32 [[OUT]], ptr %a -// CHECK-NEXT: br label %[[BBR]] -// CHECK: [[BB0]]: -// CHECK-NEXT: store i32 [[OUT]], ptr %a -// CHECK-NEXT: br label %[[BBR]] -// CHECK: [[BBR]]: -// CHECK-NEXT: [[RET:%.*]] = load i32, ptr %a -// CHECK-NEXT: ret i32 [[RET]] -#[unsafe(no_mangle)] -pub unsafe fn f(mut a: u32) -> u32 { - asm!( - "jmp {} - jmp {}", - label {}, - label {}, - inout("eax") a, - ); - a -} diff --git a/tests/codegen/asm/csky-clobbers.rs b/tests/codegen/asm/csky-clobbers.rs deleted file mode 100644 index 4986d0fe56d..00000000000 --- a/tests/codegen/asm/csky-clobbers.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: --target csky-unknown-linux-gnuabiv2 -//@ needs-llvm-components: csky - -#![crate_type = "rlib"] -#![feature(no_core, asm_experimental_arch)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: @flags_clobber -// CHECK: call void asm sideeffect "", "~{psr}"() -#[no_mangle] -pub unsafe fn flags_clobber() { - asm!("", options(nostack, nomem)); -} - -// CHECK-LABEL: @no_clobber -// CHECK: call void asm sideeffect "", ""() -#[no_mangle] -pub unsafe fn no_clobber() { - asm!("", options(nostack, nomem, preserves_flags)); -} diff --git a/tests/codegen/asm/foo.s b/tests/codegen/asm/foo.s deleted file mode 100644 index 304d82aa0c6..00000000000 --- a/tests/codegen/asm/foo.s +++ /dev/null @@ -1,3 +0,0 @@ -.global foo -foo: - jmp baz diff --git a/tests/codegen/asm/global_asm.rs b/tests/codegen/asm/global_asm.rs deleted file mode 100644 index 32075daa3cf..00000000000 --- a/tests/codegen/asm/global_asm.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ revisions: x32 x64 -//@[x32] only-x86 -//@[x64] only-x86_64 -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] - -use std::arch::global_asm; - -// CHECK-LABEL: foo -// CHECK: module asm -// this regex will capture the correct unconditional branch inst. -// CHECK: module asm "{{[[:space:]]+}}jmp baz" -global_asm!( - r#" - .global foo -foo: - jmp baz -"# -); - -extern "C" { - fn foo(); -} - -// CHECK-LABEL: @baz -#[no_mangle] -pub unsafe extern "C" fn baz() {} diff --git a/tests/codegen/asm/global_asm_include.rs b/tests/codegen/asm/global_asm_include.rs deleted file mode 100644 index 98be9c3e333..00000000000 --- a/tests/codegen/asm/global_asm_include.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ revisions: x32 x64 -//@[x32] only-x86 -//@[x64] only-x86_64 -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] - -use std::arch::global_asm; - -// CHECK-LABEL: foo -// CHECK: module asm -// CHECK: module asm "{{[[:space:]]+}}jmp baz" -global_asm!(include_str!("foo.s")); - -extern "C" { - fn foo(); -} - -// CHECK-LABEL: @baz -#[no_mangle] -pub unsafe extern "C" fn baz() {} diff --git a/tests/codegen/asm/global_asm_x2.rs b/tests/codegen/asm/global_asm_x2.rs deleted file mode 100644 index 9e3a00f0680..00000000000 --- a/tests/codegen/asm/global_asm_x2.rs +++ /dev/null @@ -1,47 +0,0 @@ -//@ revisions: x32 x64 -//@[x32] only-x86 -//@[x64] only-x86_64 -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![no_std] - -use core::arch::global_asm; - -// CHECK-LABEL: foo -// CHECK: module asm -// CHECK: module asm "{{[[:space:]]+}}jmp baz" -// any other global_asm will be appended to this first block, so: -// CHECK-LABEL: bar -// CHECK: module asm "{{[[:space:]]+}}jmp quux" -global_asm!( - r#" - .global foo -foo: - jmp baz -"# -); - -extern "C" { - fn foo(); -} - -// CHECK-LABEL: @baz -#[no_mangle] -pub unsafe extern "C" fn baz() {} - -// no checks here; this has been appended to the first occurrence -global_asm!( - r#" - .global bar -bar: - jmp quux -"# -); - -extern "C" { - fn bar(); -} - -#[no_mangle] -pub unsafe extern "C" fn quux() {} diff --git a/tests/codegen/asm/goto.rs b/tests/codegen/asm/goto.rs deleted file mode 100644 index f68c399c920..00000000000 --- a/tests/codegen/asm/goto.rs +++ /dev/null @@ -1,63 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-x86_64 - -#![crate_type = "rlib"] -#![feature(asm_goto_with_outputs)] - -use std::arch::asm; - -// CHECK-LABEL: @asm_goto -#[no_mangle] -pub unsafe fn asm_goto() { - // CHECK: callbr void asm sideeffect alignstack inteldialect " - // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]] - asm!("jmp {}", label {}); -} - -// CHECK-LABEL: @asm_goto_with_outputs -#[no_mangle] -pub unsafe fn asm_goto_with_outputs() -> u64 { - let out: u64; - // CHECK: [[RES:%[0-9]+]] = callbr i64 asm sideeffect alignstack inteldialect " - // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]] - asm!("{} /* {} */", out(reg) out, label { return 1; }); - // CHECK: [[JUMPBB]]: - // CHECK-NEXT: [[RET:%.+]] = phi i64 [ [[RES]], %[[FALLTHROUGHBB]] ], [ 1, %start ] - // CHECK-NEXT: ret i64 [[RET]] - out -} - -// CHECK-LABEL: @asm_goto_with_outputs_use_in_label -#[no_mangle] -pub unsafe fn asm_goto_with_outputs_use_in_label() -> u64 { - let out: u64; - // CHECK: [[RES:%[0-9]+]] = callbr i64 asm sideeffect alignstack inteldialect " - // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]] - asm!("{} /* {} */", out(reg) out, label { return out; }); - // CHECK: [[JUMPBB]]: - // CHECK-NEXT: [[RET:%.+]] = phi i64 [ 1, %[[FALLTHROUGHBB]] ], [ [[RES]], %start ] - // CHECK-NEXT: ret i64 [[RET]] - 1 -} - -// CHECK-LABEL: @asm_goto_noreturn -#[no_mangle] -pub unsafe fn asm_goto_noreturn() -> u64 { - // CHECK: callbr void asm sideeffect alignstack inteldialect " - // CHECK-NEXT: to label %unreachable [label %[[JUMPBB:[a-b0-9]+]]] - asm!("jmp {}", label { return 1; }, options(noreturn)); - // CHECK: [[JUMPBB]]: - // CHECK-NEXT: ret i64 1 -} - -// CHECK-LABEL: @asm_goto_noreturn_with_outputs -#[no_mangle] -pub unsafe fn asm_goto_noreturn_with_outputs() -> u64 { - let out: u64; - // CHECK: [[RES:%[0-9]+]] = callbr i64 asm sideeffect alignstack inteldialect " - // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]] - asm!("mov {}, 1", "jmp {}", out(reg) out, label { return out; }); - // CHECK: [[JUMPBB]]: - // CHECK-NEXT: ret i64 [[RES]] - out -} diff --git a/tests/codegen/asm/hexagon-clobbers.rs b/tests/codegen/asm/hexagon-clobbers.rs deleted file mode 100644 index 800b8964669..00000000000 --- a/tests/codegen/asm/hexagon-clobbers.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@ add-core-stubs -//@ revisions: hexagon -//@[hexagon] compile-flags: --target hexagon-unknown-linux-musl -//@[hexagon] needs-llvm-components: hexagon -//@ compile-flags: -Zmerge-functions=disabled - -#![crate_type = "rlib"] -#![feature(no_core, asm_experimental_arch)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: @flags_clobber -// CHECK: call void asm sideeffect "", ""() -#[no_mangle] -pub unsafe fn flags_clobber() { - asm!("", options(nostack, nomem)); -} - -// CHECK-LABEL: @no_clobber -// CHECK: call void asm sideeffect "", ""() -#[no_mangle] -pub unsafe fn no_clobber() { - asm!("", options(nostack, nomem, preserves_flags)); -} - -// CHECK-LABEL: @p0_clobber -// CHECK: call void asm sideeffect "", "~{p0}"() -#[no_mangle] -pub unsafe fn p0_clobber() { - asm!("", out("p0") _, options(nostack, nomem, preserves_flags)); -} diff --git a/tests/codegen/asm/may_unwind.rs b/tests/codegen/asm/may_unwind.rs deleted file mode 100644 index 63cdec7584c..00000000000 --- a/tests/codegen/asm/may_unwind.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-x86_64 - -#![crate_type = "rlib"] -#![feature(asm_unwind)] - -use std::arch::asm; - -#[no_mangle] -pub extern "C" fn panicky() {} - -struct Foo; - -impl Drop for Foo { - fn drop(&mut self) { - println!(); - } -} - -// CHECK-LABEL: @asm_may_unwind -#[no_mangle] -pub unsafe fn asm_may_unwind() { - let _m = Foo; - // CHECK: invoke void asm sideeffect alignstack inteldialect unwind "" - asm!("", options(may_unwind)); -} - -// CHECK-LABEL: @asm_with_result_may_unwind -#[no_mangle] -pub unsafe fn asm_with_result_may_unwind() -> u64 { - let _m = Foo; - let res: u64; - // CHECK: [[RES:%[0-9]+]] = invoke i64 asm sideeffect alignstack inteldialect unwind - // CHECK-NEXT: to label %[[NORMALBB:[a-b0-9]+]] - asm!("mov {}, 1", out(reg) res, options(may_unwind)); - // CHECK: [[NORMALBB]]: - // CHECK: ret i64 [[RES:%[0-9]+]] - res -} diff --git a/tests/codegen/asm/maybe-uninit.rs b/tests/codegen/asm/maybe-uninit.rs deleted file mode 100644 index d76d5cb1312..00000000000 --- a/tests/codegen/asm/maybe-uninit.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-x86_64 - -#![crate_type = "rlib"] -#![allow(asm_sub_register)] - -use std::arch::asm; -use std::mem::MaybeUninit; - -// CHECK-LABEL: @int -#[no_mangle] -pub unsafe fn int(x: MaybeUninit) -> MaybeUninit { - let y: MaybeUninit; - asm!("/*{}{}*/", in(reg) x, out(reg) y); - y -} - -// CHECK-LABEL: @inout -#[no_mangle] -pub unsafe fn inout(mut x: i32) -> MaybeUninit { - let mut y: MaybeUninit; - asm!("/*{}*/", inout(reg) x => y); - asm!("/*{}*/", inout(reg) y => x); - asm!("/*{}*/", inlateout(reg) x => y); - asm!("/*{}*/", inlateout(reg) y => x); - y -} diff --git a/tests/codegen/asm/msp430-clobbers.rs b/tests/codegen/asm/msp430-clobbers.rs deleted file mode 100644 index 2c8d29cffc4..00000000000 --- a/tests/codegen/asm/msp430-clobbers.rs +++ /dev/null @@ -1,32 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ compile-flags: --target msp430-none-elf -//@ needs-llvm-components: msp430 - -#![crate_type = "rlib"] -#![feature(no_core, asm_experimental_arch)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: @sr_clobber -// CHECK: call void asm sideeffect "", "~{sr}"() -#[no_mangle] -pub unsafe fn sr_clobber() { - asm!("", options(nostack, nomem)); -} - -// CHECK-LABEL: @no_clobber -// CHECK: call void asm sideeffect "", ""() -#[no_mangle] -pub unsafe fn no_clobber() { - asm!("", options(nostack, nomem, preserves_flags)); -} - -// CHECK-LABEL: @clobber_abi -// CHECK: asm sideeffect "", "={r11},={r12},={r13},={r14},={r15}"() -#[no_mangle] -pub unsafe fn clobber_abi() { - asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); -} diff --git a/tests/codegen/asm/multiple-options.rs b/tests/codegen/asm/multiple-options.rs deleted file mode 100644 index 4d87471a193..00000000000 --- a/tests/codegen/asm/multiple-options.rs +++ /dev/null @@ -1,54 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-x86_64 - -#![crate_type = "rlib"] - -use std::arch::asm; - -// CHECK-LABEL: @pure -// CHECK-NOT: asm -// CHECK: ret void -#[no_mangle] -pub unsafe fn pure(x: i32) { - let y: i32; - asm!("", out("ax") y, in("cx") x, options(pure), options(nomem)); -} - -pub static mut VAR: i32 = 0; -pub static mut DUMMY_OUTPUT: i32 = 0; - -// CHECK-LABEL: @readonly -// CHECK: call i32 asm -// CHECK: ret i32 1 -#[no_mangle] -pub unsafe fn readonly() -> i32 { - VAR = 1; - asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly)); - VAR -} - -// CHECK-LABEL: @nomem -// CHECK-NOT: store -// CHECK: call i32 asm -// CHECK: store -// CHECK: ret i32 2 -#[no_mangle] -pub unsafe fn nomem() -> i32 { - VAR = 1; - asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(nomem)); - VAR = 2; - VAR -} - -// CHECK-LABEL: @not_nomem -// CHECK: store -// CHECK: call i32 asm -// CHECK: store -// CHECK: ret i32 2 -#[no_mangle] -pub unsafe fn not_nomem() -> i32 { - VAR = 1; - asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly)); - VAR = 2; - VAR -} diff --git a/tests/codegen/asm/options.rs b/tests/codegen/asm/options.rs deleted file mode 100644 index c087f91fd43..00000000000 --- a/tests/codegen/asm/options.rs +++ /dev/null @@ -1,104 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-x86_64 - -#![crate_type = "rlib"] - -use std::arch::asm; - -// CHECK-LABEL: @pure -// CHECK-NOT: asm -// CHECK: ret void -#[no_mangle] -pub unsafe fn pure(x: i32) { - let y: i32; - asm!("", out("ax") y, in("cx") x, options(pure, nomem)); -} - -// CHECK-LABEL: @noreturn -// CHECK: call void asm -// CHECK-NEXT: unreachable -#[no_mangle] -pub unsafe fn noreturn() { - asm!("", options(noreturn)); -} - -pub static mut VAR: i32 = 0; -pub static mut DUMMY_OUTPUT: i32 = 0; - -// CHECK-LABEL: @readonly -// CHECK: call i32 asm -// CHECK: ret i32 1 -#[no_mangle] -pub unsafe fn readonly() -> i32 { - VAR = 1; - asm!("", out("ax") DUMMY_OUTPUT, options(pure, readonly)); - VAR -} - -// CHECK-LABEL: @not_readonly -// CHECK: call i32 asm -// CHECK: ret i32 % -#[no_mangle] -pub unsafe fn not_readonly() -> i32 { - VAR = 1; - asm!("", out("ax") DUMMY_OUTPUT, options()); - VAR -} - -// CHECK-LABEL: @nomem -// CHECK-NOT: store -// CHECK: call i32 asm -// CHECK: store -// CHECK: ret i32 2 -#[no_mangle] -pub unsafe fn nomem() -> i32 { - VAR = 1; - asm!("", out("ax") DUMMY_OUTPUT, options(pure, nomem)); - VAR = 2; - VAR -} - -// CHECK-LABEL: @nomem_nopure -// CHECK-NOT: store -// CHECK: call i32 asm -// CHECK: store -// CHECK: ret i32 2 -#[no_mangle] -pub unsafe fn nomem_nopure() -> i32 { - VAR = 1; - asm!("", out("ax") DUMMY_OUTPUT, options(nomem)); - VAR = 2; - VAR -} - -// CHECK-LABEL: @not_nomem -// CHECK: store -// CHECK: call i32 asm -// CHECK: store -// CHECK: ret i32 2 -#[no_mangle] -pub unsafe fn not_nomem() -> i32 { - VAR = 1; - asm!("", out("ax") DUMMY_OUTPUT, options(pure, readonly)); - VAR = 2; - VAR -} - -// CHECK-LABEL: @dont_remove_nonpure -// CHECK: call void asm -// CHECK: call void asm -// CHECK: call void asm -// CHECK: ret void -#[no_mangle] -pub unsafe fn dont_remove_nonpure() { - asm!("", options()); - asm!("", options(nomem)); - asm!("", options(readonly)); -} - -// CHECK-LABEL: @raw -// CHECK: call void asm sideeffect inteldialect "{} {}", ""() -#[no_mangle] -pub unsafe fn raw() { - asm!("{} {}", options(nostack, nomem, preserves_flags, raw)); -} diff --git a/tests/codegen/asm/powerpc-clobbers.rs b/tests/codegen/asm/powerpc-clobbers.rs deleted file mode 100644 index f7fc7eea5d5..00000000000 --- a/tests/codegen/asm/powerpc-clobbers.rs +++ /dev/null @@ -1,68 +0,0 @@ -//@ add-core-stubs -//@ revisions: powerpc powerpc64 powerpc64le aix64 -//@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu -//@[powerpc] needs-llvm-components: powerpc -//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu -//@[powerpc64] needs-llvm-components: powerpc -//@[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu -//@[powerpc64le] needs-llvm-components: powerpc -//@[aix64] compile-flags: --target powerpc64-ibm-aix -//@[aix64] needs-llvm-components: powerpc -// ignore-tidy-linelength - -#![crate_type = "rlib"] -#![feature(no_core, asm_experimental_arch)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: @cr_clobber -// CHECK: call void asm sideeffect "", "~{cr}"() -#[no_mangle] -pub unsafe fn cr_clobber() { - asm!("", out("cr") _, options(nostack, nomem, preserves_flags)); -} - -// CHECK-LABEL: @cr0_clobber -// CHECK: call void asm sideeffect "", "~{cr0}"() -#[no_mangle] -pub unsafe fn cr0_clobber() { - asm!("", out("cr0") _, options(nostack, nomem, preserves_flags)); -} - -// CHECK-LABEL: @cr5_clobber -// CHECK: call void asm sideeffect "", "~{cr5}"() -#[no_mangle] -pub unsafe fn cr5_clobber() { - asm!("", out("cr5") _, options(nostack, nomem, preserves_flags)); -} - -// CHECK-LABEL: @xer_clobber -// CHECK: call void asm sideeffect "", "~{xer}"() -#[no_mangle] -pub unsafe fn xer_clobber() { - asm!("", out("xer") _, options(nostack, nomem, preserves_flags)); -} - -// Output format depends on the availability of altivec. -// CHECK-LABEL: @v0_clobber -// powerpc: call void asm sideeffect "", "~{v0}"() -// powerpc64: call <4 x i32> asm sideeffect "", "=&{v0}"() -// powerpc64le: call <4 x i32> asm sideeffect "", "=&{v0}"() -// aix64: call <4 x i32> asm sideeffect "", "=&{v0}"() -#[no_mangle] -pub unsafe fn v0_clobber() { - asm!("", out("v0") _, options(nostack, nomem, preserves_flags)); -} - -// Output format depends on the availability of altivec. -// CHECK-LABEL: @clobber_abi -// powerpc: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"() -// powerpc64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"() -// powerpc64le: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"() -// aix64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"() -#[no_mangle] -pub unsafe fn clobber_abi() { - asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); -} diff --git a/tests/codegen/asm/riscv-clobbers.rs b/tests/codegen/asm/riscv-clobbers.rs deleted file mode 100644 index e55b6731098..00000000000 --- a/tests/codegen/asm/riscv-clobbers.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@ add-core-stubs -//@ assembly-output: emit-asm -//@ revisions: rv32i rv64i rv32e -//@[rv32i] compile-flags: --target riscv32i-unknown-none-elf -//@[rv32i] needs-llvm-components: riscv -//@[rv64i] compile-flags: --target riscv64imac-unknown-none-elf -//@[rv64i] needs-llvm-components: riscv -//@[rv32e] compile-flags: --target riscv32e-unknown-none-elf -//@[rv32e] needs-llvm-components: riscv -// ignore-tidy-linelength - -#![crate_type = "rlib"] -#![feature(no_core)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: @flags_clobber -// CHECK: call void asm sideeffect "", "~{vtype},~{vl},~{vxsat},~{vxrm}"() -#[no_mangle] -pub unsafe fn flags_clobber() { - asm!("", options(nostack, nomem)); -} - -// CHECK-LABEL: @no_clobber -// CHECK: call void asm sideeffect "", ""() -#[no_mangle] -pub unsafe fn no_clobber() { - asm!("", options(nostack, nomem, preserves_flags)); -} - -// CHECK-LABEL: @clobber_abi -// rv32i: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},={x16},={x17},={x28},={x29},={x30},={x31},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"() -// rv64i: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},={x16},={x17},={x28},={x29},={x30},={x31},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"() -// rv32e: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"() -#[no_mangle] -pub unsafe fn clobber_abi() { - asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); -} diff --git a/tests/codegen/asm/s390x-clobbers.rs b/tests/codegen/asm/s390x-clobbers.rs deleted file mode 100644 index 0ba22a32abf..00000000000 --- a/tests/codegen/asm/s390x-clobbers.rs +++ /dev/null @@ -1,46 +0,0 @@ -//@ add-core-stubs -//@ revisions: s390x -//@[s390x] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z10 -//@[s390x] needs-llvm-components: systemz - -#![crate_type = "rlib"] -#![feature(no_core)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: @cc_clobber -// CHECK: call void asm sideeffect "", "~{cc}"() -#[no_mangle] -pub unsafe fn cc_clobber() { - asm!("", options(nostack, nomem)); -} - -// CHECK-LABEL: @no_clobber -// CHECK: call void asm sideeffect "", ""() -#[no_mangle] -pub unsafe fn no_clobber() { - asm!("", options(nostack, nomem, preserves_flags)); -} - -// CHECK-LABEL: @a2_clobber -// CHECK: call void asm sideeffect "", "~{a2}"() -#[no_mangle] -pub unsafe fn a2_clobber() { - asm!("", out("a2") _, options(nostack, nomem, preserves_flags)); -} - -// CHECK-LABEL: @v0_clobber -// CHECK: call void asm sideeffect "", "~{v0}"() -#[no_mangle] -pub unsafe fn v0_clobber() { - asm!("", out("v0") _, options(nostack, nomem, preserves_flags)); -} - -// CHECK-LABEL: @clobber_abi -// CHECK: asm sideeffect "", "={r0},={r1},={r2},={r3},={r4},={r5},={r14},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31},~{a2},~{a3},~{a4},~{a5},~{a6},~{a7},~{a8},~{a9},~{a10},~{a11},~{a12},~{a13},~{a14},~{a15}"() -#[no_mangle] -pub unsafe fn clobber_abi() { - asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); -} diff --git a/tests/codegen/asm/sanitize-llvm.rs b/tests/codegen/asm/sanitize-llvm.rs deleted file mode 100644 index 97a77033284..00000000000 --- a/tests/codegen/asm/sanitize-llvm.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ add-core-stubs -// FIXME(nagisa): remove the flags below once all targets support `asm!`. -//@ compile-flags: --target x86_64-unknown-linux-gnu -Copt-level=0 -//@ needs-llvm-components: x86 - -// Verify we sanitize the special tokens for the LLVM inline-assembly, ensuring people won't -// inadvertently rely on the LLVM-specific syntax and features. -#![no_core] -#![feature(no_core)] -#![crate_type = "rlib"] -#![allow(named_asm_labels)] - -extern crate minicore; -use minicore::*; - -pub unsafe fn we_escape_dollar_signs() { - // CHECK: call void asm sideeffect alignstack inteldialect "banana$$:" - asm!(r"banana$:",) -} - -pub unsafe fn we_escape_escapes_too() { - // CHECK: call void asm sideeffect alignstack inteldialect "banana\{{(\\|5C)}}36:" - asm!(r"banana\36:",) -} diff --git a/tests/codegen/asm/sparc-clobbers.rs b/tests/codegen/asm/sparc-clobbers.rs deleted file mode 100644 index a71715ed94d..00000000000 --- a/tests/codegen/asm/sparc-clobbers.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ add-core-stubs -//@ revisions: sparc sparcv8plus sparc64 -//@[sparc] compile-flags: --target sparc-unknown-none-elf -//@[sparc] needs-llvm-components: sparc -//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu -//@[sparcv8plus] needs-llvm-components: sparc -//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu -//@[sparc64] needs-llvm-components: sparc - -#![crate_type = "rlib"] -#![feature(no_core, asm_experimental_arch)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: @cc_clobber -// CHECK: call void asm sideeffect "", "~{icc},~{fcc0},~{fcc1},~{fcc2},~{fcc3}"() -#[no_mangle] -pub unsafe fn cc_clobber() { - asm!("", options(nostack, nomem)); -} - -// CHECK-LABEL: @no_clobber -// CHECK: call void asm sideeffect "", ""() -#[no_mangle] -pub unsafe fn no_clobber() { - asm!("", options(nostack, nomem, preserves_flags)); -} - -// CHECK-LABEL: @y_clobber -// CHECK: call void asm sideeffect "", "~{y}"() -#[no_mangle] -pub unsafe fn y_clobber() { - asm!("", out("y") _, options(nostack, nomem, preserves_flags)); -} diff --git a/tests/codegen/asm/x86-clobber_abi.rs b/tests/codegen/asm/x86-clobber_abi.rs deleted file mode 100644 index 5b34b4e8ef3..00000000000 --- a/tests/codegen/asm/x86-clobber_abi.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-x86_64 - -#![crate_type = "rlib"] - -use std::arch::asm; - -// CHECK-LABEL: @clobber_sysv64 -// CHECK: ={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory} -#[no_mangle] -pub unsafe fn clobber_sysv64() { - asm!("", clobber_abi("sysv64")); -} - -// CHECK-LABEL: @clobber_win64 -// CHECK: ={ax},={cx},={dx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory} -#[no_mangle] -pub unsafe fn clobber_win64() { - asm!("", clobber_abi("win64")); -} - -// CHECK-LABEL: @clobber_sysv64 -// CHECK: =&{dx},={ax},={cx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory} -#[no_mangle] -pub unsafe fn clobber_sysv64_edx() { - let foo: i32; - asm!("", out("edx") foo, clobber_abi("sysv64")); -} - -// CHECK-LABEL: @clobber_win64 -// CHECK: =&{dx},={ax},={cx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory} -#[no_mangle] -pub unsafe fn clobber_win64_edx() { - let foo: i32; - asm!("", out("edx") foo, clobber_abi("win64")); -} diff --git a/tests/codegen/asm/x86-clobbers.rs b/tests/codegen/asm/x86-clobbers.rs deleted file mode 100644 index 50163b646b2..00000000000 --- a/tests/codegen/asm/x86-clobbers.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-x86_64 - -#![crate_type = "rlib"] - -use std::arch::asm; - -// CHECK-LABEL: @x87_clobber -// CHECK: ~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)} -#[no_mangle] -pub unsafe fn x87_clobber() { - asm!("foo", out("st") _); -} - -// CHECK-LABEL: @mmx_clobber -// CHECK: ~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)} -#[no_mangle] -pub unsafe fn mmx_clobber() { - asm!("bar", out("mm0") _, out("mm1") _); -} diff --git a/tests/codegen/asm/x86-target-clobbers.rs b/tests/codegen/asm/x86-target-clobbers.rs deleted file mode 100644 index 119372491ff..00000000000 --- a/tests/codegen/asm/x86-target-clobbers.rs +++ /dev/null @@ -1,29 +0,0 @@ -//@ only-x86_64 -//@ revisions: base avx512 -//@ [avx512]compile-flags: -C target-feature=+avx512f - -#![crate_type = "rlib"] - -use std::arch::asm; - -// CHECK-LABEL: @amx_clobber -// base: call void asm sideeffect inteldialect "", "~{tmm0}"() -#[no_mangle] -pub unsafe fn amx_clobber() { - asm!("", out("tmm0") _, options(nostack, nomem, preserves_flags)); -} - -// CHECK-LABEL: @avx512_clobber -// base: call void asm sideeffect inteldialect "", "~{xmm31}"() -// avx512: call float asm sideeffect inteldialect "", "=&{xmm31}"() -#[no_mangle] -pub unsafe fn avx512_clobber() { - asm!("", out("zmm31") _, options(nostack, nomem, preserves_flags)); -} - -// CHECK-LABEL: @eax_clobber -// CHECK: call i32 asm sideeffect inteldialect "", "=&{ax}"() -#[no_mangle] -pub unsafe fn eax_clobber() { - asm!("", out("eax") _, options(nostack, nomem, preserves_flags)); -} diff --git a/tests/codegen/assign-desugar-debuginfo.rs b/tests/codegen/assign-desugar-debuginfo.rs deleted file mode 100644 index 77ee8758b3b..00000000000 --- a/tests/codegen/assign-desugar-debuginfo.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ compile-flags: -g -Zmir-opt-level=0 - -#![crate_type = "lib"] - -#[inline(never)] -fn swizzle(a: u32, b: u32, c: u32) -> (u32, (u32, u32)) { - (b, (c, a)) -} - -pub fn work() { - let mut a = 1; - let mut b = 2; - let mut c = 3; - (a, (b, c)) = swizzle(a, b, c); - println!("{a} {b} {c}"); -} - -// CHECK-NOT: !DILocalVariable(name: "lhs", diff --git a/tests/codegen/async-closure-debug.rs b/tests/codegen/async-closure-debug.rs deleted file mode 100644 index b5b369e6e54..00000000000 --- a/tests/codegen/async-closure-debug.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Just make sure that async closures don't ICE. -// -//@ compile-flags: -C debuginfo=2 -//@ edition: 2018 -//@ ignore-msvc - -// CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "async_closure_test" -// CHECK-DAG: [[CLOSURE:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: [[GEN_FN]] -// CHECK-DAG: [[UPVAR:!.*]] = !DIDerivedType(tag: DW_TAG_member, name: "upvar", scope: [[CLOSURE]] - -fn async_closure_test(upvar: &str) -> impl AsyncFn() + '_ { - async move || { - let hello = String::from("hello"); - println!("{hello}, {upvar}"); - } -} - -fn main() { - let _async_closure = async_closure_test("world"); -} diff --git a/tests/codegen/async-fn-debug-awaitee-field.rs b/tests/codegen/async-fn-debug-awaitee-field.rs deleted file mode 100644 index 50860c90662..00000000000 --- a/tests/codegen/async-fn-debug-awaitee-field.rs +++ /dev/null @@ -1,28 +0,0 @@ -// ignore-tidy-linelength -//! This test makes sure that the coroutine field capturing the awaitee in a `.await` expression -//! is called `__awaitee` in debuginfo. This name must not be changed since debuggers and debugger -//! extensions rely on the field having this name. - -//@ revisions: MSVC NONMSVC -//@[MSVC] only-msvc -//@[NONMSVC] ignore-msvc - -//@ compile-flags: -C debuginfo=2 -Copt-level=0 -//@ edition: 2018 - -#![crate_type = "lib"] - -pub async fn async_fn_test() { - foo().await; -} - -pub async fn foo() {} - -// NONMSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[GEN_SCOPE:![0-9]*]], -// MSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$", -// NONMSVC: [[GEN_SCOPE:!.*]] = !DINamespace(name: "async_fn_test", -// CHECK: [[SUSPEND_STRUCT:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend0", scope: [[GEN]], -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__awaitee", scope: [[SUSPEND_STRUCT]], {{.*}}, baseType: [[AWAITEE_TYPE:![0-9]*]], -// NONMSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[AWAITEE_SCOPE:![0-9]*]], -// MSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$", -// NONMSVC: [[AWAITEE_SCOPE]] = !DINamespace(name: "foo", diff --git a/tests/codegen/async-fn-debug-msvc.rs b/tests/codegen/async-fn-debug-msvc.rs deleted file mode 100644 index e0c601146f8..00000000000 --- a/tests/codegen/async-fn-debug-msvc.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Verify debuginfo for coroutines: -// - Each variant points to the file and line of its yield point -// - The discriminants are marked artificial -// - Other fields are not marked artificial -// -// -//@ compile-flags: -C debuginfo=2 -//@ edition: 2018 -//@ only-msvc - -async fn foo() {} -async fn async_fn_test() { - foo().await; - let s = String::from("foo"); - foo().await; -} - -// FIXME: No way to reliably check the filename. - -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$", -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]], -// For brevity, we only check the struct name and members of the last variant. -// CHECK-SAME: file: [[FILE:![0-9]*]], line: 12, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]], -// CHECK-SAME: file: [[FILE]], line: 16, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]], -// CHECK-SAME: file: [[FILE]], line: 16, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]], -// CHECK-SAME: file: [[FILE]], line: 13, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]], -// CHECK-SAME: file: [[FILE]], line: 15, -// CHECK-SAME: baseType: [[VARIANT_WRAPPER:![0-9]*]] -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: [[VARIANT_WRAPPER]], file: !2, baseType: [[VARIANT:![0-9]*]], -// CHECK: [[VARIANT]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[VARIANT]] -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "tag", scope: [[GEN]], -// CHECK-NOT: flags: DIFlagArtificial - -fn main() { - let _dummy = async_fn_test(); -} diff --git a/tests/codegen/async-fn-debug.rs b/tests/codegen/async-fn-debug.rs deleted file mode 100644 index ed704c7cc8b..00000000000 --- a/tests/codegen/async-fn-debug.rs +++ /dev/null @@ -1,59 +0,0 @@ -// Verify debuginfo for async fn: -// - Each variant points to the file and line of its yield point -// - The discriminants are marked artificial -// - Other fields are not marked artificial -// -// -//@ compile-flags: -C debuginfo=2 -//@ edition: 2018 -//@ ignore-msvc - -async fn foo() {} -async fn async_fn_test() { - foo().await; - let s = String::from("foo"); - foo().await; -} - -// FIXME: No way to reliably check the filename. - -// CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[ASYNC_FN]] -// CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[GEN]], -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: discriminator: [[DISC:![0-9]*]] -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE:![0-9]*]], line: 12, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]], -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 16, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 16, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 13, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 15, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: [[DISC]] = !DIDerivedType(tag: DW_TAG_member, name: "__state", scope: [[GEN]], -// CHECK-SAME: flags: DIFlagArtificial - -fn main() { - let _dummy = async_fn_test(); -} diff --git a/tests/codegen/atomic-operations.rs b/tests/codegen/atomic-operations.rs deleted file mode 100644 index 8771b8b2419..00000000000 --- a/tests/codegen/atomic-operations.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Code generation of atomic operations. -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -use std::sync::atomic::AtomicI32; -use std::sync::atomic::Ordering::*; - -// CHECK-LABEL: @compare_exchange -#[no_mangle] -pub fn compare_exchange(a: &AtomicI32) { - // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 10 monotonic monotonic - // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 11 monotonic acquire - // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 12 monotonic seq_cst - let _ = a.compare_exchange(0, 10, Relaxed, Relaxed); - let _ = a.compare_exchange(0, 11, Relaxed, Acquire); - let _ = a.compare_exchange(0, 12, Relaxed, SeqCst); - - // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 20 release monotonic - // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 21 release acquire - // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 22 release seq_cst - let _ = a.compare_exchange(0, 20, Release, Relaxed); - let _ = a.compare_exchange(0, 21, Release, Acquire); - let _ = a.compare_exchange(0, 22, Release, SeqCst); - - // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 30 acquire monotonic - // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 31 acquire acquire - // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 32 acquire seq_cst - let _ = a.compare_exchange(0, 30, Acquire, Relaxed); - let _ = a.compare_exchange(0, 31, Acquire, Acquire); - let _ = a.compare_exchange(0, 32, Acquire, SeqCst); - - // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 40 acq_rel monotonic - // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 41 acq_rel acquire - // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 42 acq_rel seq_cst - let _ = a.compare_exchange(0, 40, AcqRel, Relaxed); - let _ = a.compare_exchange(0, 41, AcqRel, Acquire); - let _ = a.compare_exchange(0, 42, AcqRel, SeqCst); - - // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 50 seq_cst monotonic - // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 51 seq_cst acquire - // CHECK: cmpxchg ptr %{{.*}}, i32 0, i32 52 seq_cst seq_cst - let _ = a.compare_exchange(0, 50, SeqCst, Relaxed); - let _ = a.compare_exchange(0, 51, SeqCst, Acquire); - let _ = a.compare_exchange(0, 52, SeqCst, SeqCst); -} - -// CHECK-LABEL: @compare_exchange_weak -#[no_mangle] -pub fn compare_exchange_weak(w: &AtomicI32) { - // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 10 monotonic monotonic - // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 11 monotonic acquire - // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 12 monotonic seq_cst - let _ = w.compare_exchange_weak(1, 10, Relaxed, Relaxed); - let _ = w.compare_exchange_weak(1, 11, Relaxed, Acquire); - let _ = w.compare_exchange_weak(1, 12, Relaxed, SeqCst); - - // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 20 release monotonic - // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 21 release acquire - // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 22 release seq_cst - let _ = w.compare_exchange_weak(1, 20, Release, Relaxed); - let _ = w.compare_exchange_weak(1, 21, Release, Acquire); - let _ = w.compare_exchange_weak(1, 22, Release, SeqCst); - - // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 30 acquire monotonic - // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 31 acquire acquire - // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 32 acquire seq_cst - let _ = w.compare_exchange_weak(1, 30, Acquire, Relaxed); - let _ = w.compare_exchange_weak(1, 31, Acquire, Acquire); - let _ = w.compare_exchange_weak(1, 32, Acquire, SeqCst); - - // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 40 acq_rel monotonic - // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 41 acq_rel acquire - // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 42 acq_rel seq_cst - let _ = w.compare_exchange_weak(1, 40, AcqRel, Relaxed); - let _ = w.compare_exchange_weak(1, 41, AcqRel, Acquire); - let _ = w.compare_exchange_weak(1, 42, AcqRel, SeqCst); - - // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 50 seq_cst monotonic - // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 51 seq_cst acquire - // CHECK: cmpxchg weak ptr %{{.*}}, i32 1, i32 52 seq_cst seq_cst - let _ = w.compare_exchange_weak(1, 50, SeqCst, Relaxed); - let _ = w.compare_exchange_weak(1, 51, SeqCst, Acquire); - let _ = w.compare_exchange_weak(1, 52, SeqCst, SeqCst); -} diff --git a/tests/codegen/atomicptr.rs b/tests/codegen/atomicptr.rs deleted file mode 100644 index 4819af40ca2..00000000000 --- a/tests/codegen/atomicptr.rs +++ /dev/null @@ -1,36 +0,0 @@ -// LLVM does not support some atomic RMW operations on pointers, so inside codegen we lower those -// to integer atomics, surrounded by casts to and from integer type. -// This test ensures that we do the round-trip correctly for AtomicPtr::fetch_byte_add, and also -// ensures that we do not have such a round-trip for AtomicPtr::swap, because LLVM supports pointer -// arguments to `atomicrmw xchg`. - -//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes -#![crate_type = "lib"] -#![feature(strict_provenance_atomic_ptr)] - -use std::ptr::without_provenance_mut; -use std::sync::atomic::AtomicPtr; -use std::sync::atomic::Ordering::Relaxed; - -// Portability hack so that we can say [[USIZE]] instead of i64/i32/i16 for usize. -// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1) -#[no_mangle] -pub fn helper(_: usize) {} - -// CHECK-LABEL: @atomicptr_fetch_byte_add -#[no_mangle] -pub fn atomicptr_fetch_byte_add(a: &AtomicPtr, v: usize) -> *mut u8 { - // CHECK: %[[INTPTR:.*]] = ptrtoint ptr %{{.*}} to [[USIZE]] - // CHECK-NEXT: %[[RET:.*]] = atomicrmw add ptr %{{.*}}, [[USIZE]] %[[INTPTR]] - // CHECK-NEXT: inttoptr [[USIZE]] %[[RET]] to ptr - a.fetch_byte_add(v, Relaxed) -} - -// CHECK-LABEL: @atomicptr_swap -#[no_mangle] -pub fn atomicptr_swap(a: &AtomicPtr, ptr: *mut u8) -> *mut u8 { - // CHECK-NOT: ptrtoint - // CHECK: atomicrmw xchg ptr %{{.*}}, ptr %{{.*}} monotonic - // CHECK-NOT: inttoptr - a.swap(ptr, Relaxed) -} diff --git a/tests/codegen/autodiff/batched.rs b/tests/codegen/autodiff/batched.rs deleted file mode 100644 index d27aed50e6c..00000000000 --- a/tests/codegen/autodiff/batched.rs +++ /dev/null @@ -1,116 +0,0 @@ -//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat -//@ no-prefer-dynamic -//@ needs-enzyme -// -// In Enzyme, we test against a large range of LLVM versions (5+) and don't have overly many -// breakages. One benefit is that we match the IR generated by Enzyme only after running it -// through LLVM's O3 pipeline, which will remove most of the noise. -// However, our integration test could also be affected by changes in how rustc lowers MIR into -// LLVM-IR, which could cause additional noise and thus breakages. If that's the case, we should -// reduce this test to only match the first lines and the ret instructions. - -#![feature(autodiff)] - -use std::autodiff::autodiff_forward; - -#[autodiff_forward(d_square3, Dual, DualOnly)] -#[autodiff_forward(d_square2, 4, Dual, DualOnly)] -#[autodiff_forward(d_square1, 4, Dual, Dual)] -#[no_mangle] -fn square(x: &f32) -> f32 { - x * x -} - -// d_sqaure2 -// CHECK: define internal fastcc [4 x float] @fwddiffe4square(float %x.0.val, [4 x ptr] %"x'") -// CHECK-NEXT: start: -// CHECK-NEXT: %0 = extractvalue [4 x ptr] %"x'", 0 -// CHECK-NEXT: %"_2'ipl" = load float, ptr %0, align 4 -// CHECK-NEXT: %1 = extractvalue [4 x ptr] %"x'", 1 -// CHECK-NEXT: %"_2'ipl1" = load float, ptr %1, align 4 -// CHECK-NEXT: %2 = extractvalue [4 x ptr] %"x'", 2 -// CHECK-NEXT: %"_2'ipl2" = load float, ptr %2, align 4 -// CHECK-NEXT: %3 = extractvalue [4 x ptr] %"x'", 3 -// CHECK-NEXT: %"_2'ipl3" = load float, ptr %3, align 4 -// CHECK-NEXT: %4 = insertelement <4 x float> poison, float %"_2'ipl", i64 0 -// CHECK-NEXT: %5 = insertelement <4 x float> %4, float %"_2'ipl1", i64 1 -// CHECK-NEXT: %6 = insertelement <4 x float> %5, float %"_2'ipl2", i64 2 -// CHECK-NEXT: %7 = insertelement <4 x float> %6, float %"_2'ipl3", i64 3 -// CHECK-NEXT: %8 = fadd fast <4 x float> %7, %7 -// CHECK-NEXT: %9 = insertelement <4 x float> poison, float %x.0.val, i64 0 -// CHECK-NEXT: %10 = shufflevector <4 x float> %9, <4 x float> poison, <4 x i32> zeroinitializer -// CHECK-NEXT: %11 = fmul fast <4 x float> %8, %10 -// CHECK-NEXT: %12 = extractelement <4 x float> %11, i64 0 -// CHECK-NEXT: %13 = insertvalue [4 x float] undef, float %12, 0 -// CHECK-NEXT: %14 = extractelement <4 x float> %11, i64 1 -// CHECK-NEXT: %15 = insertvalue [4 x float] %13, float %14, 1 -// CHECK-NEXT: %16 = extractelement <4 x float> %11, i64 2 -// CHECK-NEXT: %17 = insertvalue [4 x float] %15, float %16, 2 -// CHECK-NEXT: %18 = extractelement <4 x float> %11, i64 3 -// CHECK-NEXT: %19 = insertvalue [4 x float] %17, float %18, 3 -// CHECK-NEXT: ret [4 x float] %19 -// CHECK-NEXT: } - -// d_square3, the extra float is the original return value (x * x) -// CHECK: define internal fastcc { float, [4 x float] } @fwddiffe4square.1(float %x.0.val, [4 x ptr] %"x'") -// CHECK-NEXT: start: -// CHECK-NEXT: %0 = extractvalue [4 x ptr] %"x'", 0 -// CHECK-NEXT: %"_2'ipl" = load float, ptr %0, align 4 -// CHECK-NEXT: %1 = extractvalue [4 x ptr] %"x'", 1 -// CHECK-NEXT: %"_2'ipl1" = load float, ptr %1, align 4 -// CHECK-NEXT: %2 = extractvalue [4 x ptr] %"x'", 2 -// CHECK-NEXT: %"_2'ipl2" = load float, ptr %2, align 4 -// CHECK-NEXT: %3 = extractvalue [4 x ptr] %"x'", 3 -// CHECK-NEXT: %"_2'ipl3" = load float, ptr %3, align 4 -// CHECK-NEXT: %_0 = fmul float %x.0.val, %x.0.val -// CHECK-NEXT: %4 = insertelement <4 x float> poison, float %"_2'ipl", i64 0 -// CHECK-NEXT: %5 = insertelement <4 x float> %4, float %"_2'ipl1", i64 1 -// CHECK-NEXT: %6 = insertelement <4 x float> %5, float %"_2'ipl2", i64 2 -// CHECK-NEXT: %7 = insertelement <4 x float> %6, float %"_2'ipl3", i64 3 -// CHECK-NEXT: %8 = fadd fast <4 x float> %7, %7 -// CHECK-NEXT: %9 = insertelement <4 x float> poison, float %x.0.val, i64 0 -// CHECK-NEXT: %10 = shufflevector <4 x float> %9, <4 x float> poison, <4 x i32> zeroinitializer -// CHECK-NEXT: %11 = fmul fast <4 x float> %8, %10 -// CHECK-NEXT: %12 = extractelement <4 x float> %11, i64 0 -// CHECK-NEXT: %13 = insertvalue [4 x float] undef, float %12, 0 -// CHECK-NEXT: %14 = extractelement <4 x float> %11, i64 1 -// CHECK-NEXT: %15 = insertvalue [4 x float] %13, float %14, 1 -// CHECK-NEXT: %16 = extractelement <4 x float> %11, i64 2 -// CHECK-NEXT: %17 = insertvalue [4 x float] %15, float %16, 2 -// CHECK-NEXT: %18 = extractelement <4 x float> %11, i64 3 -// CHECK-NEXT: %19 = insertvalue [4 x float] %17, float %18, 3 -// CHECK-NEXT: %20 = insertvalue { float, [4 x float] } undef, float %_0, 0 -// CHECK-NEXT: %21 = insertvalue { float, [4 x float] } %20, [4 x float] %19, 1 -// CHECK-NEXT: ret { float, [4 x float] } %21 -// CHECK-NEXT: } - -fn main() { - let x = std::hint::black_box(3.0); - let output = square(&x); - dbg!(&output); - assert_eq!(9.0, output); - dbg!(square(&x)); - - let mut df_dx1 = 1.0; - let mut df_dx2 = 2.0; - let mut df_dx3 = 3.0; - let mut df_dx4 = 0.0; - let [o1, o2, o3, o4] = d_square2(&x, &mut df_dx1, &mut df_dx2, &mut df_dx3, &mut df_dx4); - dbg!(o1, o2, o3, o4); - let [output2, o1, o2, o3, o4] = - d_square1(&x, &mut df_dx1, &mut df_dx2, &mut df_dx3, &mut df_dx4); - dbg!(o1, o2, o3, o4); - assert_eq!(output, output2); - assert!((6.0 - o1).abs() < 1e-10); - assert!((12.0 - o2).abs() < 1e-10); - assert!((18.0 - o3).abs() < 1e-10); - assert!((0.0 - o4).abs() < 1e-10); - assert_eq!(1.0, df_dx1); - assert_eq!(2.0, df_dx2); - assert_eq!(3.0, df_dx3); - assert_eq!(0.0, df_dx4); - assert_eq!(d_square3(&x, &mut df_dx1), 2.0 * o1); - assert_eq!(d_square3(&x, &mut df_dx2), 2.0 * o2); - assert_eq!(d_square3(&x, &mut df_dx3), 2.0 * o3); - assert_eq!(d_square3(&x, &mut df_dx4), 2.0 * o4); -} diff --git a/tests/codegen/autodiff/generic.rs b/tests/codegen/autodiff/generic.rs deleted file mode 100644 index 2f674079be0..00000000000 --- a/tests/codegen/autodiff/generic.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@ compile-flags: -Zautodiff=Enable -Zautodiff=NoPostopt -C opt-level=3 -Clto=fat -//@ no-prefer-dynamic -//@ needs-enzyme -#![feature(autodiff)] - -use std::autodiff::autodiff_reverse; - -#[autodiff_reverse(d_square, Duplicated, Active)] -fn square + Copy>(x: &T) -> T { - *x * *x -} - -// Ensure that `d_square::` code is generated even if `square::` was never called -// -// CHECK: ; generic::square -// CHECK-NEXT: ; Function Attrs: -// CHECK-NEXT: define internal {{.*}} double -// CHECK-NEXT: start: -// CHECK-NOT: ret -// CHECK: fmul double - -// Ensure that `d_square::` code is generated -// -// CHECK: ; generic::square -// CHECK-NEXT: ; Function Attrs: {{.*}} -// CHECK-NEXT: define internal {{.*}} float -// CHECK-NEXT: start: -// CHECK-NOT: ret -// CHECK: fmul float - -fn main() { - let xf32: f32 = std::hint::black_box(3.0); - let xf64: f64 = std::hint::black_box(3.0); - - let outputf32 = square::(&xf32); - assert_eq!(9.0, outputf32); - - let mut df_dxf64: f64 = std::hint::black_box(0.0); - - let output_f64 = d_square::(&xf64, &mut df_dxf64, 1.0); - assert_eq!(6.0, df_dxf64); -} diff --git a/tests/codegen/autodiff/identical_fnc.rs b/tests/codegen/autodiff/identical_fnc.rs deleted file mode 100644 index 1c25b3d09ab..00000000000 --- a/tests/codegen/autodiff/identical_fnc.rs +++ /dev/null @@ -1,45 +0,0 @@ -//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat -//@ no-prefer-dynamic -//@ needs-enzyme -// -// Each autodiff invocation creates a new placeholder function, which we will replace on llvm-ir -// level. If a user tries to differentiate two identical functions within the same compilation unit, -// then LLVM might merge them in release mode before AD. In that case we can't rewrite one of the -// merged placeholder function anymore, and compilation would fail. We prevent this by disabling -// LLVM's merge_function pass before AD. Here we implicetely test that our solution keeps working. -// We also explicetly test that we keep running merge_function after AD, by checking for two -// identical function calls in the LLVM-IR, while having two different calls in the Rust code. -#![feature(autodiff)] - -use std::autodiff::autodiff_reverse; - -#[autodiff_reverse(d_square, Duplicated, Active)] -fn square(x: &f64) -> f64 { - x * x -} - -#[autodiff_reverse(d_square2, Duplicated, Active)] -fn square2(x: &f64) -> f64 { - x * x -} - -// CHECK:; identical_fnc::main -// CHECK-NEXT:; Function Attrs: -// CHECK-NEXT:define internal void @_ZN13identical_fnc4main17hf4dbc69c8d2f9130E() -// CHECK-NEXT:start: -// CHECK-NOT:br -// CHECK-NOT:ret -// CHECK:; call identical_fnc::d_square -// CHECK-NEXT: call fastcc void @_ZN13identical_fnc8d_square17h4c364207a2f8e06dE(double %x.val, ptr noalias noundef nonnull align 8 dereferenceable(8) %dx1) -// CHECK-NEXT:; call identical_fnc::d_square -// CHECK-NEXT: call fastcc void @_ZN13identical_fnc8d_square17h4c364207a2f8e06dE(double %x.val, ptr noalias noundef nonnull align 8 dereferenceable(8) %dx2) - -fn main() { - let x = std::hint::black_box(3.0); - let mut dx1 = std::hint::black_box(1.0); - let mut dx2 = std::hint::black_box(1.0); - let _ = d_square(&x, &mut dx1, 1.0); - let _ = d_square2(&x, &mut dx2, 1.0); - assert_eq!(dx1, 6.0); - assert_eq!(dx2, 6.0); -} diff --git a/tests/codegen/autodiff/inline.rs b/tests/codegen/autodiff/inline.rs deleted file mode 100644 index 65bed170207..00000000000 --- a/tests/codegen/autodiff/inline.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat -Zautodiff=NoPostopt -//@ no-prefer-dynamic -//@ needs-enzyme - -#![feature(autodiff)] - -use std::autodiff::autodiff_reverse; - -#[autodiff_reverse(d_square, Duplicated, Active)] -fn square(x: &f64) -> f64 { - x * x -} - -// CHECK: ; inline::d_square -// CHECK-NEXT: ; Function Attrs: alwaysinline -// CHECK-NOT: noinline -// CHECK-NEXT: define internal fastcc void @_ZN6inline8d_square17h021c74e92c259cdeE -fn main() { - let x = std::hint::black_box(3.0); - let mut dx1 = std::hint::black_box(1.0); - let _ = d_square(&x, &mut dx1, 1.0); - assert_eq!(dx1, 6.0); -} diff --git a/tests/codegen/autodiff/scalar.rs b/tests/codegen/autodiff/scalar.rs deleted file mode 100644 index 096b4209e84..00000000000 --- a/tests/codegen/autodiff/scalar.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat -//@ no-prefer-dynamic -//@ needs-enzyme -#![feature(autodiff)] - -use std::autodiff::autodiff_reverse; - -#[autodiff_reverse(d_square, Duplicated, Active)] -#[no_mangle] -fn square(x: &f64) -> f64 { - x * x -} - -// CHECK:define internal fastcc double @diffesquare(double %x.0.val, ptr nocapture nonnull align 8 %"x'" -// CHECK-NEXT:invertstart: -// CHECK-NEXT: %_0 = fmul double %x.0.val, %x.0.val -// CHECK-NEXT: %0 = fadd fast double %x.0.val, %x.0.val -// CHECK-NEXT: %1 = load double, ptr %"x'", align 8 -// CHECK-NEXT: %2 = fadd fast double %1, %0 -// CHECK-NEXT: store double %2, ptr %"x'", align 8 -// CHECK-NEXT: ret double %_0 -// CHECK-NEXT:} - -fn main() { - let x = std::hint::black_box(3.0); - let output = square(&x); - assert_eq!(9.0, output); - - let mut df_dx = 0.0; - let output_ = d_square(&x, &mut df_dx, 1.0); - assert_eq!(output, output_); - assert_eq!(6.0, df_dx); -} diff --git a/tests/codegen/autodiff/sret.rs b/tests/codegen/autodiff/sret.rs deleted file mode 100644 index d2fa85e3e37..00000000000 --- a/tests/codegen/autodiff/sret.rs +++ /dev/null @@ -1,45 +0,0 @@ -//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat -//@ no-prefer-dynamic -//@ needs-enzyme - -// This test is almost identical to the scalar.rs one, -// but we intentionally add a few more floats. -// `df` would ret `{ f64, f32, f32 }`, but is lowered as an sret. -// We therefore use this test to verify some of our sret handling. - -#![feature(autodiff)] - -use std::autodiff::autodiff_reverse; - -#[no_mangle] -#[autodiff_reverse(df, Active, Active, Active)] -fn primal(x: f32, y: f32) -> f64 { - (x * x * y) as f64 -} - -// CHECK:define internal fastcc void @_ZN4sret2df17h93be4316dd8ea006E(ptr dead_on_unwind noalias nocapture noundef nonnull writable writeonly align 8 dereferenceable(16) initializes((0, 16)) %_0, float noundef %x, float noundef %y) -// CHECK-NEXT:start: -// CHECK-NEXT: %0 = tail call fastcc { double, float, float } @diffeprimal(float %x, float %y) -// CHECK-NEXT: %.elt = extractvalue { double, float, float } %0, 0 -// CHECK-NEXT: store double %.elt, ptr %_0, align 8 -// CHECK-NEXT: %_0.repack1 = getelementptr inbounds nuw i8, ptr %_0, i64 8 -// CHECK-NEXT: %.elt2 = extractvalue { double, float, float } %0, 1 -// CHECK-NEXT: store float %.elt2, ptr %_0.repack1, align 8 -// CHECK-NEXT: %_0.repack3 = getelementptr inbounds nuw i8, ptr %_0, i64 12 -// CHECK-NEXT: %.elt4 = extractvalue { double, float, float } %0, 2 -// CHECK-NEXT: store float %.elt4, ptr %_0.repack3, align 4 -// CHECK-NEXT: ret void -// CHECK-NEXT:} - -fn main() { - let x = std::hint::black_box(3.0); - let y = std::hint::black_box(2.5); - let scalar = std::hint::black_box(1.0); - let (r1, r2, r3) = df(x, y, scalar); - // 3*3*1.5 = 22.5 - assert_eq!(r1, 22.5); - // 2*x*y = 2*3*2.5 = 15.0 - assert_eq!(r2, 15.0); - // x*x*1 = 3*3 = 9 - assert_eq!(r3, 9.0); -} diff --git a/tests/codegen/autodiffv2.rs b/tests/codegen/autodiffv2.rs deleted file mode 100644 index a40d19d3be3..00000000000 --- a/tests/codegen/autodiffv2.rs +++ /dev/null @@ -1,113 +0,0 @@ -//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat -//@ no-prefer-dynamic -//@ needs-enzyme -// -// In Enzyme, we test against a large range of LLVM versions (5+) and don't have overly many -// breakages. One benefit is that we match the IR generated by Enzyme only after running it -// through LLVM's O3 pipeline, which will remove most of the noise. -// However, our integration test could also be affected by changes in how rustc lowers MIR into -// LLVM-IR, which could cause additional noise and thus breakages. If that's the case, we should -// reduce this test to only match the first lines and the ret instructions. -// -// The function tested here has 4 inputs and 5 outputs, so we could either call forward-mode -// autodiff 4 times, or reverse mode 5 times. Since a forward-mode call is usually faster than -// reverse mode, we prefer it here. This file also tests a new optimization (batch mode), which -// allows us to call forward-mode autodiff only once, and get all 5 outputs in a single call. -// -// We support 2 different batch modes. `d_square2` has the same interface as scalar forward-mode, -// but each shadow argument is `width` times larger (thus 16 and 20 elements here). -// `d_square3` instead takes `width` (4) shadow arguments, which are all the same size as the -// original function arguments. -// -// FIXME(autodiff): We currently can't test `d_square1` and `d_square3` in the same file, since they -// generate the same dummy functions which get merged by LLVM, breaking pieces of our pipeline which -// try to rewrite the dummy functions later. We should consider to change to pure declarations both -// in our frontend and in the llvm backend to avoid these issues. - -#![feature(autodiff)] - -use std::autodiff::autodiff; - -#[no_mangle] -//#[autodiff(d_square1, Forward, Dual, Dual)] -#[autodiff(d_square2, Forward, 4, Dualv, Dualv)] -#[autodiff(d_square3, Forward, 4, Dual, Dual)] -fn square(x: &[f32], y: &mut [f32]) { - assert!(x.len() >= 4); - assert!(y.len() >= 5); - y[0] = 4.3 * x[0] + 1.2 * x[1] + 3.4 * x[2] + 2.1 * x[3]; - y[1] = 2.3 * x[0] + 4.5 * x[1] + 1.7 * x[2] + 6.4 * x[3]; - y[2] = 1.1 * x[0] + 3.3 * x[1] + 2.5 * x[2] + 4.7 * x[3]; - y[3] = 5.2 * x[0] + 1.4 * x[1] + 2.6 * x[2] + 3.8 * x[3]; - y[4] = 1.0 * x[0] + 2.0 * x[1] + 3.0 * x[2] + 4.0 * x[3]; -} - -fn main() { - let x1 = std::hint::black_box(vec![0.0, 1.0, 2.0, 3.0]); - - let dx1 = std::hint::black_box(vec![1.0; 12]); - - let z1 = std::hint::black_box(vec![1.0, 0.0, 0.0, 0.0]); - let z2 = std::hint::black_box(vec![0.0, 1.0, 0.0, 0.0]); - let z3 = std::hint::black_box(vec![0.0, 0.0, 1.0, 0.0]); - let z4 = std::hint::black_box(vec![0.0, 0.0, 0.0, 1.0]); - - let z5 = std::hint::black_box(vec![ - 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, - ]); - - let mut y1 = std::hint::black_box(vec![0.0; 5]); - let mut y2 = std::hint::black_box(vec![0.0; 5]); - let mut y3 = std::hint::black_box(vec![0.0; 5]); - let mut y4 = std::hint::black_box(vec![0.0; 5]); - - let mut y5 = std::hint::black_box(vec![0.0; 5]); - - let mut y6 = std::hint::black_box(vec![0.0; 5]); - - let mut dy1_1 = std::hint::black_box(vec![0.0; 5]); - let mut dy1_2 = std::hint::black_box(vec![0.0; 5]); - let mut dy1_3 = std::hint::black_box(vec![0.0; 5]); - let mut dy1_4 = std::hint::black_box(vec![0.0; 5]); - - let mut dy2 = std::hint::black_box(vec![0.0; 20]); - - let mut dy3_1 = std::hint::black_box(vec![0.0; 5]); - let mut dy3_2 = std::hint::black_box(vec![0.0; 5]); - let mut dy3_3 = std::hint::black_box(vec![0.0; 5]); - let mut dy3_4 = std::hint::black_box(vec![0.0; 5]); - - // scalar. - //d_square1(&x1, &z1, &mut y1, &mut dy1_1); - //d_square1(&x1, &z2, &mut y2, &mut dy1_2); - //d_square1(&x1, &z3, &mut y3, &mut dy1_3); - //d_square1(&x1, &z4, &mut y4, &mut dy1_4); - - // assert y1 == y2 == y3 == y4 - //for i in 0..5 { - // assert_eq!(y1[i], y2[i]); - // assert_eq!(y1[i], y3[i]); - // assert_eq!(y1[i], y4[i]); - //} - - // batch mode A) - d_square2(&x1, &z5, &mut y5, &mut dy2); - - // assert y1 == y2 == y3 == y4 == y5 - //for i in 0..5 { - // assert_eq!(y1[i], y5[i]); - //} - - // batch mode B) - d_square3(&x1, &z1, &z2, &z3, &z4, &mut y6, &mut dy3_1, &mut dy3_2, &mut dy3_3, &mut dy3_4); - for i in 0..5 { - assert_eq!(y5[i], y6[i]); - } - - for i in 0..5 { - assert_eq!(dy2[0..5][i], dy3_1[i]); - assert_eq!(dy2[5..10][i], dy3_2[i]); - assert_eq!(dy2[10..15][i], dy3_3[i]); - assert_eq!(dy2[15..20][i], dy3_4[i]); - } -} diff --git a/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs deleted file mode 100644 index c354228acc5..00000000000 --- a/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs +++ /dev/null @@ -1,31 +0,0 @@ -//@ compile-flags: -Copt-level=2 - -#![crate_type = "lib"] -#![no_std] - -// This test is paired with the arch-specific -opt3.rs test. - -// The code is from https://github.com/rust-lang/rust/issues/122805. -// Ensure we do not generate the shufflevector instruction -// to avoid complicating the code. - -// CHECK-LABEL: define{{.*}}void @convert( -// CHECK-NOT: shufflevector -#[no_mangle] -pub fn convert(value: [u16; 8]) -> [u8; 16] { - #[cfg(target_endian = "little")] - let bswap = u16::to_be; - #[cfg(target_endian = "big")] - let bswap = u16::to_le; - let addr16 = [ - bswap(value[0]), - bswap(value[1]), - bswap(value[2]), - bswap(value[3]), - bswap(value[4]), - bswap(value[5]), - bswap(value[6]), - bswap(value[7]), - ]; - unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) } -} diff --git a/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs deleted file mode 100644 index 203d12005de..00000000000 --- a/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@ revisions: AARCH64 X86_64 Z13 -//@ compile-flags: -Copt-level=3 -//@[AARCH64] only-aarch64 -//@[X86_64] only-x86_64 -//@[Z13] only-s390x -//@[Z13] compile-flags: -Ctarget-cpu=z13 - -#![crate_type = "lib"] -#![no_std] - -// This test is paired with the arch-neutral -opt2.rs test - -// The code is from https://github.com/rust-lang/rust/issues/122805. -// Ensure we do not generate the shufflevector instruction -// to avoid complicating the code. - -// CHECK-LABEL: define{{.*}}void @convert( -// CHECK-NOT: shufflevector - -// On higher opt levels, this should just be a bswap: -// CHECK: load <8 x i16> -// CHECK-NEXT: call <8 x i16> @llvm.bswap -// CHECK-NEXT: store <8 x i16> -// CHECK-NEXT: ret void -#[no_mangle] -pub fn convert(value: [u16; 8]) -> [u8; 16] { - #[cfg(target_endian = "little")] - let bswap = u16::to_be; - #[cfg(target_endian = "big")] - let bswap = u16::to_le; - let addr16 = [ - bswap(value[0]), - bswap(value[1]), - bswap(value[2]), - bswap(value[3]), - bswap(value[4]), - bswap(value[5]), - bswap(value[6]), - bswap(value[7]), - ]; - unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) } -} diff --git a/tests/codegen/autovectorize-f32x4.rs b/tests/codegen/autovectorize-f32x4.rs deleted file mode 100644 index 254362842f9..00000000000 --- a/tests/codegen/autovectorize-f32x4.rs +++ /dev/null @@ -1,37 +0,0 @@ -//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled -//@ only-x86_64 -#![crate_type = "lib"] - -// CHECK-LABEL: @auto_vectorize_direct -#[no_mangle] -pub fn auto_vectorize_direct(a: [f32; 4], b: [f32; 4]) -> [f32; 4] { - // CHECK: load <4 x float> - // CHECK: load <4 x float> - // CHECK: fadd <4 x float> - // CHECK: store <4 x float> - [a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]] -} - -// CHECK-LABEL: @auto_vectorize_loop -#[no_mangle] -pub fn auto_vectorize_loop(a: [f32; 4], b: [f32; 4]) -> [f32; 4] { - // CHECK: load <4 x float> - // CHECK: load <4 x float> - // CHECK: fadd <4 x float> - // CHECK: store <4 x float> - let mut c = [0.0; 4]; - for i in 0..4 { - c[i] = a[i] + b[i]; - } - c -} - -// CHECK-LABEL: @auto_vectorize_array_from_fn -#[no_mangle] -pub fn auto_vectorize_array_from_fn(a: [f32; 4], b: [f32; 4]) -> [f32; 4] { - // CHECK: load <4 x float> - // CHECK: load <4 x float> - // CHECK: fadd <4 x float> - // CHECK: store <4 x float> - std::array::from_fn(|i| a[i] + b[i]) -} diff --git a/tests/codegen/auxiliary/extern_decl.rs b/tests/codegen/auxiliary/extern_decl.rs deleted file mode 100644 index d17e77b1444..00000000000 --- a/tests/codegen/auxiliary/extern_decl.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Auxiliary crate that exports a function and static. Both always -// evaluate to `71`. We force mutability on the static to prevent -// it from being inlined as constant. - -#![crate_type = "lib"] - -#[no_mangle] -pub fn extern_fn() -> u8 { - unsafe { extern_static } -} - -#[no_mangle] -pub static mut extern_static: u8 = 71; diff --git a/tests/codegen/auxiliary/nounwind.rs b/tests/codegen/auxiliary/nounwind.rs deleted file mode 100644 index 40f66442c6e..00000000000 --- a/tests/codegen/auxiliary/nounwind.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[no_mangle] -pub fn bar() {} diff --git a/tests/codegen/auxiliary/thread_local_aux.rs b/tests/codegen/auxiliary/thread_local_aux.rs deleted file mode 100644 index bebaa7754dd..00000000000 --- a/tests/codegen/auxiliary/thread_local_aux.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![crate_type = "lib"] - -use std::cell::Cell; - -thread_local!(pub static A: Cell = const { Cell::new(0) }); diff --git a/tests/codegen/avr/avr-func-addrspace.rs b/tests/codegen/avr/avr-func-addrspace.rs deleted file mode 100644 index e0192f8b45a..00000000000 --- a/tests/codegen/avr/avr-func-addrspace.rs +++ /dev/null @@ -1,106 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: -Copt-level=3 --target=avr-none -C target-cpu=atmega328p --crate-type=rlib -C panic=abort -//@ needs-llvm-components: avr - -// This test validates that function pointers can be stored in global variables -// and called upon. It ensures that Rust emits function pointers in the correct -// address space to LLVM so that an assertion error relating to casting is -// not triggered. -// -// It also validates that functions can be called through function pointers -// through traits. - -#![feature(no_core, lang_items, intrinsics, unboxed_closures, arbitrary_self_types)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[rustc_intrinsic] -pub unsafe fn transmute(src: Src) -> Dst; - -pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box; -pub static mut STORAGE_BAR: u32 = 12; - -fn arbitrary_black_box(ptr: &usize, _: &mut u32) -> Result<(), ()> { - let raw_ptr = ptr as *const usize; - let _v: usize = unsafe { *raw_ptr }; - loop {} -} - -#[inline(never)] -#[no_mangle] -fn call_through_fn_trait(a: &mut impl Fn<(), Output = ()>) { - (*a)() -} - -#[inline(never)] -fn update_bar_value() { - unsafe { - STORAGE_BAR = 88; - } -} - -// CHECK: define dso_local void @test(){{.+}}addrspace(1) -#[no_mangle] -pub extern "C" fn test() { - let mut buf = 7; - - // A call through the Fn trait must use address space 1. - // - // CHECK: call{{.+}}addrspace(1) void @call_through_fn_trait({{.*}}) - call_through_fn_trait(&mut update_bar_value); - - // A call through a global variable must use address space 1. - // CHECK: load {{.*}}addrspace(1){{.+}}FOO - unsafe { - STORAGE_FOO(&1, &mut buf); - } -} - -// Validate that we can codegen transmutes between data ptrs and fn ptrs. - -// CHECK: define{{.+}}ptr addrspace(1) @transmute_data_ptr_to_fn(ptr{{.*}} %x) -#[no_mangle] -pub unsafe fn transmute_data_ptr_to_fn(x: *const ()) -> fn() { - // It doesn't matter precisely how this is codegenned (through memory or an addrspacecast), - // as long as it doesn't cause a verifier error by using `bitcast`. - transmute(x) -} - -// CHECK: define{{.+}}ptr @transmute_fn_ptr_to_data(ptr addrspace(1){{.*}} %x) -#[no_mangle] -pub unsafe fn transmute_fn_ptr_to_data(x: fn()) -> *const () { - // It doesn't matter precisely how this is codegenned (through memory or an addrspacecast), - // as long as it doesn't cause a verifier error by using `bitcast`. - transmute(x) -} - -pub enum Either { - A(T), - B(U), -} - -// Previously, we would codegen this as passing/returning a scalar pair of `{ i8, ptr }`, -// with the `ptr` field representing both `&i32` and `fn()` depending on the variant. -// This is incorrect, because `fn()` should be `ptr addrspace(1)`, not `ptr`. - -// CHECK: define{{.+}}void @should_not_combine_addrspace(ptr{{.+}}sret{{.+}}%_0, ptr{{.+}}%x) -#[no_mangle] -#[inline(never)] -pub fn should_not_combine_addrspace(x: Either<&i32, fn()>) -> Either<&i32, fn()> { - x -} - -// The incorrectness described above would result in us producing (after optimizations) -// a `ptrtoint`/`inttoptr` roundtrip to convert from `ptr` to `ptr addrspace(1)`. - -// CHECK-LABEL: @call_with_fn_ptr -#[no_mangle] -pub fn call_with_fn_ptr<'a>(f: fn()) -> Either<&'a i32, fn()> { - // CHECK-NOT: ptrtoint - // CHECK-NOT: inttoptr - // CHECK: call addrspace(1) void @should_not_combine_addrspace - should_not_combine_addrspace(Either::B(f)) -} diff --git a/tests/codegen/bigint-helpers.rs b/tests/codegen/bigint-helpers.rs deleted file mode 100644 index 355cccb8150..00000000000 --- a/tests/codegen/bigint-helpers.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ compile-flags: -C opt-level=3 - -#![crate_type = "lib"] -#![feature(bigint_helper_methods)] - -// CHECK-LABEL: @u32_carrying_add -#[no_mangle] -pub fn u32_carrying_add(a: u32, b: u32, c: bool) -> (u32, bool) { - // CHECK: @llvm.uadd.with.overflow.i32 - // CHECK: @llvm.uadd.with.overflow.i32 - // CHECK: or disjoint i1 - u32::carrying_add(a, b, c) -} diff --git a/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs b/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs deleted file mode 100644 index 2c40327f624..00000000000 --- a/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ ignore-std-debug-assertions -#![crate_type = "lib"] - -use std::collections::binary_heap::PeekMut; - -// CHECK-LABEL: @peek_mut_pop -#[no_mangle] -pub fn peek_mut_pop(peek_mut: PeekMut) -> u32 { - // CHECK-NOT: panic - // CHECK-NOT: unwrap_failed - PeekMut::pop(peek_mut) -} diff --git a/tests/codegen/binary-search-index-no-bound-check.rs b/tests/codegen/binary-search-index-no-bound-check.rs deleted file mode 100644 index d59c0beec64..00000000000 --- a/tests/codegen/binary-search-index-no-bound-check.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -// Make sure no bounds checks are emitted when slicing or indexing -// with an index from `binary_search`. - -// CHECK-LABEL: @binary_search_index_no_bounds_check -#[no_mangle] -pub fn binary_search_index_no_bounds_check(s: &[u8]) -> u8 { - // CHECK-NOT: panic - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: slice_end_index_len_fail - // CHECK-NOT: panic_bounds_check - if let Ok(idx) = s.binary_search(&b'\\') { s[idx] } else { 42 } -} - -// Similarly, check that `partition_point` is known to return a valid fencepost. - -// CHECK-LABEL: @unknown_split -#[no_mangle] -pub fn unknown_split(x: &[i32], i: usize) -> (&[i32], &[i32]) { - // This just makes sure that the subsequent function is looking for the - // absence of something that might actually be there. - - // CHECK: call core::panicking::panic - x.split_at(i) -} - -// CHECK-LABEL: @partition_point_split_no_bounds_check -#[no_mangle] -pub fn partition_point_split_no_bounds_check(x: &[i32], needle: i32) -> (&[i32], &[i32]) { - // CHECK-NOT: call core::panicking::panic - let i = x.partition_point(|p| p < &needle); - x.split_at(i) -} diff --git a/tests/codegen/bool-cmp.rs b/tests/codegen/bool-cmp.rs deleted file mode 100644 index 71d3411689f..00000000000 --- a/tests/codegen/bool-cmp.rs +++ /dev/null @@ -1,18 +0,0 @@ -// This is a test for optimal Ord trait implementation for bool. -// See for more info. - -//@ compile-flags: -C opt-level=3 - -#![crate_type = "lib"] - -use std::cmp::Ordering; - -// CHECK-LABEL: @cmp_bool -#[no_mangle] -pub fn cmp_bool(a: bool, b: bool) -> Ordering { - // LLVM 10 produces (zext a) + (sext b), but the final lowering is (zext a) - (zext b). - // CHECK: zext i1 - // CHECK: {{z|s}}ext i1 - // CHECK: {{sub|add}} nsw - a.cmp(&b) -} diff --git a/tests/codegen/bounds-checking/gep-issue-133979.rs b/tests/codegen/bounds-checking/gep-issue-133979.rs deleted file mode 100644 index 876bdbfb0e1..00000000000 --- a/tests/codegen/bounds-checking/gep-issue-133979.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! Issue: -//! Check that bounds checking are eliminated. - -//@ compile-flags: -Copt-level=2 - -#![crate_type = "lib"] - -// CHECK-LABEL: @test( -#[no_mangle] -fn test(a: &[&[u8]]) -> u32 { - // CHECK-NOT: panic_bounds_check - a.iter() - .enumerate() - .map(|(y, b)| { - b.iter() - .enumerate() - .filter(|(_, c)| **c == b'A') - .map(|(x, _)| a[y][x] as u32) - .sum::() - }) - .sum() -} diff --git a/tests/codegen/box-default-debug-copies.rs b/tests/codegen/box-default-debug-copies.rs deleted file mode 100644 index 06cc41b21c0..00000000000 --- a/tests/codegen/box-default-debug-copies.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ compile-flags: -Copt-level=0 - -// Test to make sure that `>::default` does not create too many copies of `T` on the stack. -// in debug mode. This regressed in dd0620b86721ae8cae86736443acd3f72ba6fc32 to -// four `T` allocas. -// -// See https://github.com/rust-lang/rust/issues/136043 for more context. -// -// FIXME: This test only wants to ensure that there are at most two allocas of `T` created, instead -// of checking for exactly two. - -#![crate_type = "lib"] - -#[allow(dead_code)] -pub struct Thing([u8; 1000000]); - -impl Default for Thing { - fn default() -> Self { - Thing([0; 1000000]) - } -} - -// CHECK-COUNT-2: %{{.*}} = alloca {{.*}}1000000 -// CHECK-NOT: %{{.*}} = alloca {{.*}}1000000 -#[no_mangle] -pub fn box_default_single_copy() -> Box { - Box::default() -} diff --git a/tests/codegen/box-uninit-bytes.rs b/tests/codegen/box-uninit-bytes.rs deleted file mode 100644 index 0cc01148595..00000000000 --- a/tests/codegen/box-uninit-bytes.rs +++ /dev/null @@ -1,46 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -use std::mem::MaybeUninit; - -// Boxing a `MaybeUninit` value should not copy junk from the stack -#[no_mangle] -pub fn box_uninitialized() -> Box> { - // CHECK-LABEL: @box_uninitialized - // CHECK-NOT: store - // CHECK-NOT: alloca - // CHECK-NOT: memcpy - // CHECK-NOT: memset - Box::new(MaybeUninit::uninit()) -} - -// https://github.com/rust-lang/rust/issues/58201 -#[no_mangle] -pub fn box_uninitialized2() -> Box> { - // CHECK-LABEL: @box_uninitialized2 - // CHECK-NOT: store - // CHECK-NOT: alloca - // CHECK-NOT: memcpy - // CHECK-NOT: memset - Box::new(MaybeUninit::uninit()) -} - -#[repr(align(1024))] -pub struct LotsaPadding(usize); - -// Boxing a value with padding should not copy junk from the stack -#[no_mangle] -pub fn box_lotsa_padding() -> Box { - // CHECK-LABEL: @box_lotsa_padding - // CHECK-NOT: alloca - // CHECK-NOT: getelementptr - // CHECK-NOT: memcpy - // CHECK-NOT: memset - Box::new(LotsaPadding(42)) -} - -// Hide the `allocalign` attribute in the declaration of __rust_alloc -// from the CHECK-NOT above, and also verify the attributes got set reasonably. -// CHECK: declare {{(dso_local )?}}noalias noundef ptr @{{.*}}__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]] - -// CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) {{(uwtable )?}}"alloc-family"="__rust_alloc" {{.*}} } diff --git a/tests/codegen/bpf-alu32.rs b/tests/codegen/bpf-alu32.rs deleted file mode 100644 index 5955bf3317f..00000000000 --- a/tests/codegen/bpf-alu32.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ only-bpf -#![crate_type = "lib"] -#![feature(bpf_target_feature)] -#![no_std] - -#[no_mangle] -#[target_feature(enable = "alu32")] -// CHECK: define i8 @foo(i8 returned %arg) unnamed_addr #0 { -pub unsafe fn foo(arg: u8) -> u8 { - arg -} diff --git a/tests/codegen/branch-protection.rs b/tests/codegen/branch-protection.rs deleted file mode 100644 index d67e494cc0d..00000000000 --- a/tests/codegen/branch-protection.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Test that the correct module flags are emitted with different branch protection flags. - -//@ add-core-stubs -//@ revisions: BTI PACRET LEAF BKEY PAUTHLR PAUTHLR_BKEY PAUTHLR_LEAF PAUTHLR_BTI NONE -//@ needs-llvm-components: aarch64 -//@ [BTI] compile-flags: -Z branch-protection=bti -//@ [PACRET] compile-flags: -Z branch-protection=pac-ret -//@ [LEAF] compile-flags: -Z branch-protection=pac-ret,leaf -//@ [BKEY] compile-flags: -Z branch-protection=pac-ret,b-key -//@ [PAUTHLR] compile-flags: -Z branch-protection=pac-ret,pc -//@ [PAUTHLR_BKEY] compile-flags: -Z branch-protection=pac-ret,pc,b-key -//@ [PAUTHLR_LEAF] compile-flags: -Z branch-protection=pac-ret,pc,leaf -//@ [PAUTHLR_BTI] compile-flags: -Z branch-protection=bti,pac-ret,pc -//@ compile-flags: --target aarch64-unknown-linux-gnu - -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// A basic test function. -// CHECK: @test(){{.*}} [[ATTR:#[0-9]+]] { -#[no_mangle] -pub fn test() {} - -// BTI: attributes [[ATTR]] = {{.*}} "branch-target-enforcement" -// BTI: !"branch-target-enforcement", i32 1 -// BTI: !"sign-return-address", i32 0 -// BTI: !"branch-protection-pauth-lr", i32 0 -// BTI: !"sign-return-address-all", i32 0 -// BTI: !"sign-return-address-with-bkey", i32 0 - -// PACRET: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf" -// PACRET-SAME: "sign-return-address-key"="a_key" -// PACRET: !"branch-target-enforcement", i32 0 -// PACRET: !"sign-return-address", i32 1 -// PACRET: !"branch-protection-pauth-lr", i32 0 -// PACRET: !"sign-return-address-all", i32 0 -// PACRET: !"sign-return-address-with-bkey", i32 0 - -// LEAF: attributes [[ATTR]] = {{.*}} "sign-return-address"="all" -// LEAF-SAME: "sign-return-address-key"="a_key" -// LEAF: !"branch-target-enforcement", i32 0 -// LEAF: !"sign-return-address", i32 1 -// LEAF: !"branch-protection-pauth-lr", i32 0 -// LEAF: !"sign-return-address-all", i32 1 -// LEAF: !"sign-return-address-with-bkey", i32 0 - -// BKEY: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf" -// BKEY-SAME: "sign-return-address-key"="b_key" -// BKEY: !"branch-target-enforcement", i32 0 -// BKEY: !"sign-return-address", i32 1 -// BKEY: !"branch-protection-pauth-lr", i32 0 -// BKEY: !"sign-return-address-all", i32 0 -// BKEY: !"sign-return-address-with-bkey", i32 1 - -// PAUTHLR: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf" -// PAUTHLR-SAME: "sign-return-address-key"="a_key" -// PAUTHLR: !"branch-target-enforcement", i32 0 -// PAUTHLR: !"sign-return-address", i32 1 -// PAUTHLR: !"branch-protection-pauth-lr", i32 1 -// PAUTHLR: !"sign-return-address-all", i32 0 -// PAUTHLR: !"sign-return-address-with-bkey", i32 0 - -// PAUTHLR_BKEY: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf" -// PAUTHLR_BKEY-SAME: "sign-return-address-key"="b_key" -// PAUTHLR_BKEY: !"branch-target-enforcement", i32 0 -// PAUTHLR_BKEY: !"sign-return-address", i32 1 -// PAUTHLR_BKEY: !"branch-protection-pauth-lr", i32 1 -// PAUTHLR_BKEY: !"sign-return-address-all", i32 0 -// PAUTHLR_BKEY: !"sign-return-address-with-bkey", i32 1 - -// PAUTHLR_LEAF: attributes [[ATTR]] = {{.*}} "sign-return-address"="all" -// PAUTHLR_LEAF-SAME: "sign-return-address-key"="a_key" -// PAUTHLR_LEAF: !"branch-target-enforcement", i32 0 -// PAUTHLR_LEAF: !"sign-return-address", i32 1 -// PAUTHLR_LEAF: !"branch-protection-pauth-lr", i32 1 -// PAUTHLR_LEAF: !"sign-return-address-all", i32 1 -// PAUTHLR_LEAF: !"sign-return-address-with-bkey", i32 0 - -// PAUTHLR_BTI: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf" -// PAUTHLR_BTI-SAME: "sign-return-address-key"="a_key" -// PAUTHLR_BTI: !"branch-target-enforcement", i32 1 -// PAUTHLR_BTI: !"sign-return-address", i32 1 -// PAUTHLR_BTI: !"branch-protection-pauth-lr", i32 1 -// PAUTHLR_BTI: !"sign-return-address-all", i32 0 -// PAUTHLR_BTI: !"sign-return-address-with-bkey", i32 0 - -// NONE-NOT: branch-target-enforcement -// NONE-NOT: sign-return-address -// NONE-NOT: sign-return-address-all -// NONE-NOT: sign-return-address-with-bkey diff --git a/tests/codegen/call-llvm-intrinsics.rs b/tests/codegen/call-llvm-intrinsics.rs deleted file mode 100644 index dc7e0249cb6..00000000000 --- a/tests/codegen/call-llvm-intrinsics.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 - -//@ ignore-riscv64 -//@ ignore-loongarch64 - -#![feature(link_llvm_intrinsics)] -#![crate_type = "lib"] - -struct A; - -impl Drop for A { - fn drop(&mut self) { - println!("A"); - } -} - -extern "C" { - #[link_name = "llvm.sqrt.f32"] - fn sqrt(x: f32) -> f32; -} - -pub fn do_call() { - let _a = A; - - unsafe { - // Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them - // CHECK: call float @llvm.sqrt.f32(float 4.000000e+00 - sqrt(4.0); - } -} diff --git a/tests/codegen/call-tmps-lifetime.rs b/tests/codegen/call-tmps-lifetime.rs deleted file mode 100644 index 7b7b6e17bdd..00000000000 --- a/tests/codegen/call-tmps-lifetime.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Test that temporary allocas used for call arguments have their lifetimes described by -// intrinsics. -// -//@ add-core-stubs -//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes --crate-type=lib --target i686-unknown-linux-gnu -//@ needs-llvm-components: x86 -#![feature(no_core)] -#![no_std] -#![no_core] -extern crate minicore; -use minicore::*; - -// Const operand. Regression test for #98156. -// -// CHECK-LABEL: define void @const_indirect( -// CHECK-NEXT: start: -// CHECK-NEXT: [[B:%.*]] = alloca -// CHECK-NEXT: [[A:%.*]] = alloca -// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4096, ptr [[A]]) -// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 {{.*}}, i32 4096, i1 false) -// CHECK-NEXT: call void %h(ptr {{.*}} [[A]]) -// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4096, ptr [[A]]) -// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4096, ptr [[B]]) -// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[B]], ptr align 4 {{.*}}, i32 4096, i1 false) -// CHECK-NEXT: call void %h(ptr {{.*}} [[B]]) -// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4096, ptr [[B]]) -#[no_mangle] -pub fn const_indirect(h: extern "C" fn([u32; 1024])) { - const C: [u32; 1024] = [0; 1024]; - h(C); - h(C); -} - -#[repr(C)] -pub struct Str { - pub ptr: *const u8, - pub len: usize, -} - -// Pair of immediates. Regression test for #132014. -// -// CHECK-LABEL: define void @immediate_indirect(ptr {{.*}}%s.0, i32 {{.*}}%s.1, ptr {{.*}}%g) -// CHECK-NEXT: start: -// CHECK-NEXT: [[A:%.*]] = alloca -// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[A]]) -// CHECK-NEXT: store ptr %s.0, ptr [[A]] -// CHECK-NEXT: [[B:%.]] = getelementptr inbounds i8, ptr [[A]], i32 4 -// CHECK-NEXT: store i32 %s.1, ptr [[B]] -// CHECK-NEXT: call void %g(ptr {{.*}} [[A]]) -// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[A]]) -#[no_mangle] -pub fn immediate_indirect(s: Str, g: extern "C" fn(Str)) { - g(s); -} - -// Indirect argument with a higher alignment requirement than the type's. -// -// CHECK-LABEL: define void @align_indirect(ptr{{.*}} align 1{{.*}} %a, ptr{{.*}} %fun) -// CHECK-NEXT: start: -// CHECK-NEXT: [[A:%.*]] = alloca [1024 x i8], align 4 -// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1024, ptr [[A]]) -// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 1 %a, i32 1024, i1 false) -// CHECK-NEXT: call void %fun(ptr {{.*}} [[A]]) -// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1024, ptr [[A]]) -#[no_mangle] -pub fn align_indirect(a: [u8; 1024], fun: extern "C" fn([u8; 1024])) { - fun(a); -} diff --git a/tests/codegen/cast-optimized.rs b/tests/codegen/cast-optimized.rs deleted file mode 100644 index 11220c4a922..00000000000 --- a/tests/codegen/cast-optimized.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled -#![crate_type = "lib"] - -// This tests that LLVM can optimize based on the niches in the source or -// destination types for casts. - -// CHECK-LABEL: @u32_index -#[no_mangle] -pub fn u32_index(c: u32) -> [bool; 22] { - let mut array = [false; 22]; - - let index = 32 - c.leading_zeros(); - - // CHECK: call core::panicking::panic - array[index as usize] = true; - - array -} - -// CHECK-LABEL: @char_as_u32_index -#[no_mangle] -pub fn char_as_u32_index(c: char) -> [bool; 22] { - let c = c as u32; - - let mut array = [false; 22]; - - let index = 32 - c.leading_zeros(); - - // CHECK-NOT: call core::panicking::panic - array[index as usize] = true; - - array -} diff --git a/tests/codegen/cast-target-abi.rs b/tests/codegen/cast-target-abi.rs deleted file mode 100644 index cbd49e2f022..00000000000 --- a/tests/codegen/cast-target-abi.rs +++ /dev/null @@ -1,599 +0,0 @@ -// ignore-tidy-linelength -//@ add-core-stubs -//@ revisions:aarch64 loongarch64 powerpc64 sparc64 x86_64 -//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes -Zlint-llvm-ir - -//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu -//@[aarch64] needs-llvm-components: arm -//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu -//@[loongarch64] needs-llvm-components: loongarch -//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu -//@[powerpc64] needs-llvm-components: powerpc -//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu -//@[sparc64] needs-llvm-components: sparc -//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu -//@[x86_64] needs-llvm-components: x86 - -// Tests that arguments with `PassMode::Cast` are handled correctly. - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; - -// This struct will be passed as a single `i64` or `i32`. -// This may be (if `i64)) larger than the Rust layout, which is just `{ i16, i16 }`. -#[repr(C)] -pub struct TwoU16s { - a: u16, - b: u16, -} - -// This struct will be passed as `[2 x i64]`. -// This is larger than the Rust layout. -#[repr(C)] -pub struct FiveU16s { - a: u16, - b: u16, - c: u16, - d: u16, - e: u16, -} - -// This struct will be passed as `[2 x double]`. -// This is the same as the Rust layout. -#[repr(C)] -pub struct DoubleDouble { - f: f64, - g: f64, -} - -// On loongarch, this struct will be passed as `{ double, float }`. -// This is smaller than the Rust layout, which has trailing padding (`{ f64, f32, }`) -#[repr(C)] -pub struct DoubleFloat { - f: f64, - g: f32, -} - -// On x86_64, this struct will be passed as `{ i64, i32 }`. -// The load and store instructions will access 16 bytes, so we should allocate 16 bytes. -#[repr(C)] -pub struct Three32s { - a: u32, - b: u32, - c: u32, -} - -// CHECK-LABEL: @receives_twou16s -// aarch64-SAME: ([[ABI_TYPE:i64]] {{.*}}[[ABI_VALUE:%.+]]) -// loongarch64-SAME: ([[ABI_TYPE:i64]] {{.*}}[[ABI_VALUE:%.+]]) -// powerpc64-SAME: ([[ABI_TYPE:i32]] {{.*}}[[ABI_VALUE:%.+]]) -// sparc64-SAME: ([[ABI_TYPE:i64]] {{.*}}[[ABI_VALUE:%.+]]) -// x86_64-SAME: ([[ABI_TYPE:i32]] {{.*}}[[ABI_VALUE:%.+]]) -#[no_mangle] -#[inline(never)] -pub extern "C" fn receives_twou16s(x: TwoU16s) { - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] - - // CHECK: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] - - // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) -} - -// CHECK-LABEL: @returns_twou16s -// powerpc64-SAME: sret([4 x i8]) align [[RUST_ALIGN:2]] {{.*}}[[RET_PTR:%.*]]) -#[no_mangle] -#[inline(never)] -pub extern "C" fn returns_twou16s() -> TwoU16s { - // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. - // The other targets copy the cast ABI type to an alloca. - - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:2]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:2]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:2]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:2]] - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // sparc64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] - TwoU16s { a: 0, b: 1 } -} - -// CHECK-LABEL: @receives_fiveu16s -// aarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) -// loongarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) -// powerpc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) -// sparc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) -// x86_64-SAME: ([[ABI_TYPE:{ i64, i16 }]] {{.*}}[[ABI_VALUE:%.+]]) -#[no_mangle] -#[inline(never)] -pub extern "C" fn receives_fiveu16s(x: FiveU16s) { - // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // CHECK: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align [[RUST_ALIGN:2]] - - // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) -} - -// CHECK-LABEL: @returns_fiveu16s -// powerpc64-SAME: sret([10 x i8]) align [[RUST_ALIGN:2]] {{.*}}[[RET_PTR:%.*]]) -#[no_mangle] -#[inline(never)] -pub extern "C" fn returns_fiveu16s() -> FiveU16s { - // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. - // The other targets copy the cast ABI type to an alloca. - - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i16 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // sparc64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] - FiveU16s { a: 0, b: 1, c: 2, d: 3, e: 4 } -} - -// CHECK-LABEL: @receives_doubledouble -// aarch64-SAME: ([[ABI_TYPE:\[2 x double\]]] {{.*}}[[ABI_VALUE:%.+]]) -// loongarch64-SAME: ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]]) -// powerpc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) -// sparc64-SAME: ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]]) -// x86_64-SAME: ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]]) -#[no_mangle] -#[inline(never)] -pub extern "C" fn receives_doubledouble(x: DoubleDouble) { - // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // CHECK: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - - // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) -} - -// CHECK-LABEL: @returns_doubledouble -// powerpc64-SAME: sret([16 x i8]) align [[RUST_ALIGN:8]] {{.*}}[[RET_PTR:%.*]]) -#[no_mangle] -#[inline(never)] -pub extern "C" fn returns_doubledouble() -> DoubleDouble { - // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. - // The other targets copy the cast ABI type to an alloca. - - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x double\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // sparc64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] - DoubleDouble { f: 0., g: 1. } -} - -// CHECK-LABEL: @receives_three32s -// aarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) -// loongarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) -// powerpc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) -// sparc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) -// x86_64-SAME: ([[ABI_TYPE:{ i64, i32 }]] {{.*}}[[ABI_VALUE:%.+]]) -#[no_mangle] -#[inline(never)] -pub extern "C" fn receives_three32s(x: Three32s) { - // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // CHECK: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]] - - // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) -} - -// CHECK-LABEL: @returns_three32s -// powerpc64-SAME: sret([12 x i8]) align [[RUST_ALIGN:4]] {{.*}}[[RET_PTR:%.*]]) -#[no_mangle] -#[inline(never)] -pub extern "C" fn returns_three32s() -> Three32s { - // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. - // The other targets copy the cast ABI type to an alloca. - - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i32 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // sparc64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] - Three32s { a: 0, b: 0, c: 0 } -} - -// These functions cause an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620) -#[cfg(not(target_arch = "sparc64"))] -// aarch64-LABEL: @receives_doublefloat -// loongarch64-LABEL: @receives_doublefloat -// powerpc64-LABEL: @receives_doublefloat -// x86_64-LABEL: @receives_doublefloat - -// aarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) -// loongarch64-SAME: ([[ABI_TYPE:{ double, float }]] {{.*}}[[ABI_VALUE:%.+]]) -// powerpc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) -// x86_64-SAME: ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]]) -#[no_mangle] -#[inline(never)] -pub extern "C" fn receives_doublefloat(x: DoubleFloat) { - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // powerpc64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - - // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // powerpc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) - // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) - // powerpc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) - // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) -} - -#[cfg(not(target_arch = "sparc64"))] -// aarch64-LABEL: @returns_doublefloat -// loongarch64-LABEL: @returns_doublefloat -// powerpc64-LABEL: @returns_doublefloat -// x86_64-LABEL: @returns_doublefloat - -// powerpc64-SAME: sret([16 x i8]) align [[RUST_ALIGN:8]] {{.*}}[[RET_PTR:%.*]]) -#[no_mangle] -#[inline(never)] -pub extern "C" fn returns_doublefloat() -> DoubleFloat { - // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. - // The other targets copy the cast ABI type to an alloca. - - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, float }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] - DoubleFloat { f: 0., g: 0. } -} - -// CHECK-LABEL: @call_twou16s -#[no_mangle] -pub fn call_twou16s() { - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] - - // CHECK: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] - - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 4, i1 false) - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @receives_twou16s([[ABI_TYPE]] [[ABI_VALUE]]) - let x = TwoU16s { a: 1, b: 2 }; - receives_twou16s(x); -} - -// CHECK-LABEL: @return_twou16s -#[no_mangle] -pub fn return_twou16s() -> TwoU16s { - // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. - - // powerpc64: [[RETVAL:%.+]] = alloca [4 x i8], align 2 - // powerpc64: call void @returns_twou16s(ptr {{.+}} [[RETVAL]]) - - // The other targets copy the cast ABI type to an alloca. - - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] - - // aarch64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] - // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] - // sparc64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] - // x86_64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] - - // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s() - // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s() - // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s() - // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i32]] @returns_twou16s() - - // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) - // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) - // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) - // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) - returns_twou16s() -} - -// CHECK-LABEL: @call_fiveu16s -#[no_mangle] -pub fn call_fiveu16s() { - // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // CHECK: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align 2 - - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 10, i1 false) - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i16 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @receives_fiveu16s([[ABI_TYPE]] [[ABI_VALUE]]) - let x = FiveU16s { a: 1, b: 2, c: 3, d: 4, e: 5 }; - receives_fiveu16s(x); -} - -// CHECK-LABEL: @return_fiveu16s -// CHECK-SAME: (ptr {{.+}} sret([10 x i8]) align [[RUST_ALIGN:2]] {{.*}}dereferenceable(10) [[RET_PTR:%.+]]) -#[no_mangle] -pub fn return_fiveu16s() -> FiveU16s { - // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. - - // powerpc64: call void @returns_fiveu16s(ptr {{.+}} [[RET_PTR]]) - - // The other targets copy the cast ABI type to the sret pointer. - - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() - // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() - // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() - // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i16 }]] @returns_fiveu16s() - - // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) - // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) - // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) - // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) - returns_fiveu16s() -} - -// CHECK-LABEL: @call_doubledouble -#[no_mangle] -pub fn call_doubledouble() { - // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // CHECK: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x double\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @receives_doubledouble([[ABI_TYPE]] [[ABI_VALUE]]) - let x = DoubleDouble { f: 1., g: 2. }; - receives_doubledouble(x); -} - -// CHECK-LABEL: @return_doubledouble -#[no_mangle] -pub fn return_doubledouble() -> DoubleDouble { - // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. - - // powerpc64: [[RETVAL:%.+]] = alloca [16 x i8], align 8 - // powerpc64: call void @returns_doubledouble(ptr {{.+}} [[RETVAL]]) - - // The other targets copy the cast ABI type to an alloca. - - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // sparc64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - - // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x double\]]] @returns_doubledouble() - // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble() - // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble() - // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble() - - // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) - // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) - // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) - // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) - returns_doubledouble() -} - -// This test causes an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620) -#[cfg(not(target_arch = "sparc64"))] -// aarch64-LABEL: @call_doublefloat -// loongarch64-LABEL: @call_doublefloat -// powerpc64-LABEL: @call_doublefloat -// x86_64-LABEL: @call_doublefloat -#[no_mangle] -pub fn call_doublefloat() { - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // powerpc64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - - // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) - // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false) - // powerpc64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) - // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, float }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) - // loongarch64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) - // powerpc64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) - // x86_64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) - let x = DoubleFloat { f: 1., g: 2. }; - receives_doublefloat(x); -} - -// This test causes an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620) -#[cfg(not(target_arch = "sparc64"))] -// aarch64-LABEL: @return_doublefloat -// loongarch64-LABEL: @return_doublefloat -// powerpc64-LABEL: @return_doublefloat -// x86_64-LABEL: @return_doublefloat -#[no_mangle] -pub fn return_doublefloat() -> DoubleFloat { - // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. - - // powerpc64: [[RETVAL:%.+]] = alloca [16 x i8], align 8 - // powerpc64: call void @returns_doublefloat(ptr {{.+}} [[RETVAL]]) - - // The other targets copy the cast ABI type to an alloca. - - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - - // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_doublefloat() - // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, float }]] @returns_doublefloat() - // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doublefloat() - - // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) - // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) - // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) - returns_doublefloat() -} - -// CHECK-LABEL: @call_three32s -#[no_mangle] -pub fn call_three32s() { - // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // CHECK: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]] - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false) - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i32 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @receives_three32s([[ABI_TYPE]] [[ABI_VALUE]]) - let x = Three32s { a: 1, b: 2, c: 3 }; - receives_three32s(x); -} - -// Regression test for #75839 -// CHECK-LABEL: @return_three32s( -// CHECK-SAME: sret([12 x i8]) align [[RUST_ALIGN:4]] {{.*}}[[RUST_RETVAL:%.*]]) -#[no_mangle] -pub fn return_three32s() -> Three32s { - // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. - - // powerpc64: call void @returns_three32s(ptr {{.+}} [[RUST_RETVAL]]) - - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() - // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() - // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() - // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i32 }]] @returns_three32s() - - // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) - // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) - // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) - // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) - returns_three32s() -} diff --git a/tests/codegen/catch-unwind.rs b/tests/codegen/catch-unwind.rs deleted file mode 100644 index d1ff55bcc28..00000000000 --- a/tests/codegen/catch-unwind.rs +++ /dev/null @@ -1,32 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -// On x86 the closure is inlined in foo() producing something like -// define i32 @foo() [...] { -// tail call void @bar() [...] -// ret i32 0 -// } -// On riscv the closure is another function, placed before fn foo so CHECK can't -// find it -//@ ignore-riscv64 FIXME -// On s390x the closure is also in another function -//@ ignore-s390x FIXME -// On loongarch64 the closure is also in another function -//@ ignore-loongarch64 FIXME - -#![crate_type = "lib"] - -extern "C" { - fn bar(); -} - -// CHECK-LABEL: @foo -#[no_mangle] -pub unsafe fn foo() -> i32 { - // CHECK: call void @bar - // CHECK: ret i32 0 - std::panic::catch_unwind(|| { - bar(); - 0 - }) - .unwrap() -} diff --git a/tests/codegen/cdylib-external-inline-fns.rs b/tests/codegen/cdylib-external-inline-fns.rs deleted file mode 100644 index 2e472ea68e8..00000000000 --- a/tests/codegen/cdylib-external-inline-fns.rs +++ /dev/null @@ -1,43 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "cdylib"] - -// CHECK: define{{( dso_local)?}} void @a() -#[no_mangle] -#[inline] -pub extern "C" fn a() {} - -// CHECK: define{{( dso_local)?}} void @b() -#[export_name = "b"] -#[inline] -pub extern "C" fn b() {} - -// CHECK: define{{( dso_local)?}} void @c() -#[no_mangle] -#[inline] -extern "C" fn c() {} - -// CHECK: define{{( dso_local)?}} void @d() -#[export_name = "d"] -#[inline] -extern "C" fn d() {} - -// CHECK: define{{( dso_local)?}} void @e() -#[no_mangle] -#[inline(always)] -pub extern "C" fn e() {} - -// CHECK: define{{( dso_local)?}} void @f() -#[export_name = "f"] -#[inline(always)] -pub extern "C" fn f() {} - -// CHECK: define{{( dso_local)?}} void @g() -#[no_mangle] -#[inline(always)] -extern "C" fn g() {} - -// CHECK: define{{( dso_local)?}} void @h() -#[export_name = "h"] -#[inline(always)] -extern "C" fn h() {} diff --git a/tests/codegen/cf-protection.rs b/tests/codegen/cf-protection.rs deleted file mode 100644 index f1349a5dcb9..00000000000 --- a/tests/codegen/cf-protection.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Test that the correct module flags are emitted with different control-flow protection flags. - -//@ add-core-stubs -//@ revisions: undefined none branch return full -//@ needs-llvm-components: x86 -//@ [undefined] compile-flags: -//@ [none] compile-flags: -Z cf-protection=none -//@ [branch] compile-flags: -Z cf-protection=branch -//@ [return] compile-flags: -Z cf-protection=return -//@ [full] compile-flags: -Z cf-protection=full -//@ compile-flags: --target x86_64-unknown-linux-gnu - -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// A basic test function. -pub fn test() {} - -// undefined-NOT: !"cf-protection-branch" -// undefined-NOT: !"cf-protection-return" - -// none-NOT: !"cf-protection-branch" -// none-NOT: !"cf-protection-return" - -// branch-NOT: !"cf-protection-return" -// branch: !"cf-protection-branch", i32 1 -// branch-NOT: !"cf-protection-return" - -// return-NOT: !"cf-protection-branch" -// return: !"cf-protection-return", i32 1 -// return-NOT: !"cf-protection-branch" - -// full: !"cf-protection-branch", i32 1 -// full: !"cf-protection-return", i32 1 diff --git a/tests/codegen/cffi/c-variadic-copy.rs b/tests/codegen/cffi/c-variadic-copy.rs deleted file mode 100644 index 4c61c4fcf68..00000000000 --- a/tests/codegen/cffi/c-variadic-copy.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Tests that `VaListImpl::clone` gets inlined into a call to `llvm.va_copy` - -#![crate_type = "lib"] -#![feature(c_variadic)] -#![no_std] -use core::ffi::VaList; - -extern "C" { - fn foreign_c_variadic_1(_: VaList, ...); -} - -pub unsafe extern "C" fn clone_variadic(ap: VaList) { - let mut ap2 = ap.clone(); - // CHECK: call void @llvm.va_copy - foreign_c_variadic_1(ap2.as_va_list(), 42i32); -} diff --git a/tests/codegen/cffi/c-variadic-naked.rs b/tests/codegen/cffi/c-variadic-naked.rs deleted file mode 100644 index 5843628b633..00000000000 --- a/tests/codegen/cffi/c-variadic-naked.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ needs-asm-support -//@ only-x86_64 - -// tests that `va_start` is not injected into naked functions - -#![crate_type = "lib"] -#![feature(c_variadic)] -#![no_std] - -#[unsafe(naked)] -pub unsafe extern "C" fn c_variadic(_: usize, _: ...) { - // CHECK-NOT: va_start - // CHECK-NOT: alloca - core::arch::naked_asm!("ret") -} diff --git a/tests/codegen/cffi/c-variadic-opt.rs b/tests/codegen/cffi/c-variadic-opt.rs deleted file mode 100644 index 7e544ee7f37..00000000000 --- a/tests/codegen/cffi/c-variadic-opt.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@ compile-flags: -C opt-level=3 - -#![crate_type = "lib"] -#![feature(c_variadic)] -#![no_std] -use core::ffi::VaList; - -extern "C" { - fn vprintf(fmt: *const i8, ap: VaList) -> i32; -} - -// Ensure that `va_start` and `va_end` are properly injected even -// when the "spoofed" `VaListImpl` is not used. -#[no_mangle] -pub unsafe extern "C" fn c_variadic_no_use(fmt: *const i8, mut ap: ...) -> i32 { - // CHECK: call void @llvm.va_start - vprintf(fmt, ap.as_va_list()) - // CHECK: call void @llvm.va_end -} - -// Check that `VaListImpl::clone` gets inlined into a direct call to `llvm.va_copy` -#[no_mangle] -pub unsafe extern "C" fn c_variadic_clone(fmt: *const i8, mut ap: ...) -> i32 { - // CHECK: call void @llvm.va_start - let mut ap2 = ap.clone(); - // CHECK: call void @llvm.va_copy - let res = vprintf(fmt, ap2.as_va_list()); - res - // CHECK: call void @llvm.va_end -} diff --git a/tests/codegen/cffi/c-variadic.rs b/tests/codegen/cffi/c-variadic.rs deleted file mode 100644 index 140d2f37f46..00000000000 --- a/tests/codegen/cffi/c-variadic.rs +++ /dev/null @@ -1,71 +0,0 @@ -//@ needs-unwind -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -// - -#![crate_type = "lib"] -#![feature(c_variadic)] -#![no_std] -use core::ffi::VaList; - -extern "C" { - fn foreign_c_variadic_0(_: i32, ...); - fn foreign_c_variadic_1(_: VaList, ...); -} - -pub unsafe extern "C" fn use_foreign_c_variadic_0() { - // Ensure that we correctly call foreign C-variadic functions. - // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM:i32( signext)?]] 0) - foreign_c_variadic_0(0); - // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42) - foreign_c_variadic_0(0, 42i32); - // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024) - foreign_c_variadic_0(0, 42i32, 1024i32); - // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024, [[PARAM]] 0) - foreign_c_variadic_0(0, 42i32, 1024i32, 0i32); -} - -// Ensure that we do not remove the `va_list` passed to the foreign function when -// removing the "spoofed" `VaListImpl` that is used by Rust defined C-variadics. -pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap) - foreign_c_variadic_1(ap); -} - -pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 42) - foreign_c_variadic_1(ap, 42i32); -} -pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42) - foreign_c_variadic_1(ap, 2i32, 42i32); -} - -pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) { - // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42, [[PARAM]] 0) - foreign_c_variadic_1(ap, 2i32, 42i32, 0i32); -} - -// Ensure that `va_start` and `va_end` are properly injected. -#[no_mangle] -pub unsafe extern "C" fn c_variadic(n: i32, mut ap: ...) -> i32 { - // CHECK: call void @llvm.va_start - let mut sum = 0; - for _ in 0..n { - sum += ap.arg::(); - } - sum - // CHECK: call void @llvm.va_end -} - -// Ensure that we generate the correct `call` signature when calling a Rust -// defined C-variadic. -pub unsafe fn test_c_variadic_call() { - // CHECK: call [[RET:(signext )?i32]] (i32, ...) @c_variadic([[PARAM]] 0) - c_variadic(0); - // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42) - c_variadic(0, 42i32); - // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024) - c_variadic(0, 42i32, 1024i32); - // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024, [[PARAM]] 0) - c_variadic(0, 42i32, 1024i32, 0i32); -} diff --git a/tests/codegen/cffi/ffi-const.rs b/tests/codegen/cffi/ffi-const.rs deleted file mode 100644 index 3ea9d517ec2..00000000000 --- a/tests/codegen/cffi/ffi-const.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -#![crate_type = "lib"] -#![feature(ffi_const)] - -pub fn bar() { - unsafe { foo() } -} - -extern "C" { - // CHECK-LABEL: declare{{.*}}void @foo() - // CHECK-SAME: [[ATTRS:#[0-9]+]] - // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}memory(none){{.*}} } - #[unsafe(ffi_const)] - pub fn foo(); -} diff --git a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs deleted file mode 100644 index 859386d2df8..00000000000 --- a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs +++ /dev/null @@ -1,41 +0,0 @@ -//@ add-core-stubs -//@ revisions: linux apple -//@ 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 -//@[apple] compile-flags: --target x86_64-apple-darwin -//@[apple] needs-llvm-components: x86 - -// Regression test for #29988 - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[repr(C)] -struct S { - f1: i32, - f2: i32, - f3: i32, -} - -extern "C" { - fn foo(s: S); -} - -// CHECK-LABEL: @test -#[no_mangle] -pub fn test() { - let s = S { f1: 1, f2: 2, f3: 3 }; - unsafe { - // CHECK: [[ALLOCA:%.+]] = alloca [16 x i8], align 8 - // CHECK: [[LOAD:%.+]] = load { i64, i32 }, ptr [[ALLOCA]], align 8 - // CHECK: call void @foo({ i64, i32 } [[LOAD]]) - foo(s); - } -} diff --git a/tests/codegen/cffi/ffi-pure.rs b/tests/codegen/cffi/ffi-pure.rs deleted file mode 100644 index a61e80ecf65..00000000000 --- a/tests/codegen/cffi/ffi-pure.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -#![crate_type = "lib"] -#![feature(ffi_pure)] - -pub fn bar() { - unsafe { foo() } -} - -extern "C" { - // CHECK-LABEL: declare{{.*}}void @foo() - // CHECK-SAME: [[ATTRS:#[0-9]+]] - // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}memory(read){{.*}} } - #[unsafe(ffi_pure)] - pub fn foo(); -} diff --git a/tests/codegen/cfguard-checks.rs b/tests/codegen/cfguard-checks.rs deleted file mode 100644 index cdf6406ad61..00000000000 --- a/tests/codegen/cfguard-checks.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ compile-flags: -C control-flow-guard=checks -//@ only-msvc - -#![crate_type = "lib"] - -// A basic test function. -pub fn test() {} - -// Ensure the module flag cfguard=2 is present -// CHECK: !"cfguard", i32 2 diff --git a/tests/codegen/cfguard-disabled.rs b/tests/codegen/cfguard-disabled.rs deleted file mode 100644 index 90915c0f0c6..00000000000 --- a/tests/codegen/cfguard-disabled.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ compile-flags: -C control-flow-guard=no -//@ only-msvc - -#![crate_type = "lib"] - -// A basic test function. -pub fn test() {} - -// Ensure the module flag cfguard is not present -// CHECK-NOT: !"cfguard" diff --git a/tests/codegen/cfguard-nochecks.rs b/tests/codegen/cfguard-nochecks.rs deleted file mode 100644 index 5f386533ec1..00000000000 --- a/tests/codegen/cfguard-nochecks.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ compile-flags: -C control-flow-guard=nochecks -//@ only-msvc - -#![crate_type = "lib"] - -// A basic test function. -pub fn test() {} - -// Ensure the module flag cfguard=1 is present -// CHECK: !"cfguard", i32 1 diff --git a/tests/codegen/cfguard-non-msvc.rs b/tests/codegen/cfguard-non-msvc.rs deleted file mode 100644 index 1e6559aaf5d..00000000000 --- a/tests/codegen/cfguard-non-msvc.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ compile-flags: -C control-flow-guard -//@ ignore-msvc - -#![crate_type = "lib"] - -// A basic test function. -pub fn test() {} - -// Ensure the cfguard module flag is not added for non-MSVC targets. -// CHECK-NOT: !"cfguard" diff --git a/tests/codegen/char-ascii-branchless.rs b/tests/codegen/char-ascii-branchless.rs deleted file mode 100644 index f99066aa9aa..00000000000 --- a/tests/codegen/char-ascii-branchless.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Checks that these functions are branchless. -// -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @is_ascii_alphanumeric_char -#[no_mangle] -pub fn is_ascii_alphanumeric_char(x: char) -> bool { - // CHECK-NOT: br - x.is_ascii_alphanumeric() -} - -// CHECK-LABEL: @is_ascii_alphanumeric_u8 -#[no_mangle] -pub fn is_ascii_alphanumeric_u8(x: u8) -> bool { - // CHECK-NOT: br - x.is_ascii_alphanumeric() -} - -// CHECK-LABEL: @is_ascii_hexdigit_char -#[no_mangle] -pub fn is_ascii_hexdigit_char(x: char) -> bool { - // CHECK-NOT: br - x.is_ascii_hexdigit() -} - -// CHECK-LABEL: @is_ascii_hexdigit_u8 -#[no_mangle] -pub fn is_ascii_hexdigit_u8(x: u8) -> bool { - // CHECK-NOT: br - x.is_ascii_hexdigit() -} - -// CHECK-LABEL: @is_ascii_punctuation_char -#[no_mangle] -pub fn is_ascii_punctuation_char(x: char) -> bool { - // CHECK-NOT: br - x.is_ascii_punctuation() -} - -// CHECK-LABEL: @is_ascii_punctuation_u8 -#[no_mangle] -pub fn is_ascii_punctuation_u8(x: u8) -> bool { - // CHECK-NOT: br - x.is_ascii_punctuation() -} diff --git a/tests/codegen/char-escape-debug-no-bounds-check.rs b/tests/codegen/char-escape-debug-no-bounds-check.rs deleted file mode 100644 index cfde46045e5..00000000000 --- a/tests/codegen/char-escape-debug-no-bounds-check.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -use std::char::EscapeDebug; - -// Make sure no bounds checks are emitted when escaping a character. - -// CHECK-LABEL: @char_escape_debug_no_bounds_check -#[no_mangle] -pub fn char_escape_debug_no_bounds_check(c: char) -> EscapeDebug { - // CHECK-NOT: panic - // CHECK-NOT: panic_bounds_check - c.escape_debug() -} diff --git a/tests/codegen/checked_ilog.rs b/tests/codegen/checked_ilog.rs deleted file mode 100644 index e340a45b6a9..00000000000 --- a/tests/codegen/checked_ilog.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// Ensure that when val < base, we do not divide or multiply. - -// CHECK-LABEL: @checked_ilog -// CHECK-SAME: (i16{{.*}} %val, i16{{.*}} %base) -#[no_mangle] -pub fn checked_ilog(val: u16, base: u16) -> Option { - // CHECK-NOT: udiv - // CHECK-NOT: mul - // CHECK: %[[IS_LESS:.+]] = icmp ult i16 %val, %base - // CHECK-NEXT: br i1 %[[IS_LESS]], label %[[TRUE:.+]], label %[[FALSE:.+]] - // CHECK: [[TRUE]]: - // CHECK-NOT: udiv - // CHECK-NOT: mul - // CHECK: ret { i32, i32 } - val.checked_ilog(base) -} diff --git a/tests/codegen/checked_math.rs b/tests/codegen/checked_math.rs deleted file mode 100644 index 66667c69488..00000000000 --- a/tests/codegen/checked_math.rs +++ /dev/null @@ -1,100 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled - -#![crate_type = "lib"] -#![feature(unchecked_shifts)] - -// Because the result of something like `u32::checked_sub` can only be used if it -// didn't overflow, make sure that LLVM actually knows that in optimized builds. -// Thanks to poison semantics, this doesn't even need branches. - -// CHECK-LABEL: @checked_sub_unsigned -// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b) -#[no_mangle] -pub fn checked_sub_unsigned(a: u16, b: u16) -> Option { - // CHECK-DAG: %[[IS_SOME:.+]] = icmp uge i16 %a, %b - // CHECK-DAG: %[[DIFF_P:.+]] = sub nuw i16 %a, %b - // CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i16 - // CHECK-DAG: %[[DIFF_U:.+]] = select i1 %[[IS_SOME]], i16 %[[DIFF_P]], i16 undef - - // CHECK: %[[R0:.+]] = insertvalue { i16, i16 } poison, i16 %[[DISCR]], 0 - // CHECK: %[[R1:.+]] = insertvalue { i16, i16 } %[[R0]], i16 %[[DIFF_U]], 1 - // CHECK: ret { i16, i16 } %[[R1]] - a.checked_sub(b) -} - -// Note that `shl` and `shr` in LLVM are already unchecked. So rather than -// looking for no-wrap flags, we just need there to not be any masking. - -// CHECK-LABEL: @checked_shl_unsigned -// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) -#[no_mangle] -pub fn checked_shl_unsigned(a: u32, b: u32) -> Option { - // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 - // CHECK-DAG: %[[SHIFTED_P:.+]] = shl i32 %a, %b - // CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32 - // CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef - - // CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0 - // CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1 - // CHECK: ret { i32, i32 } %[[R1]] - a.checked_shl(b) -} - -// CHECK-LABEL: @checked_shr_unsigned -// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) -#[no_mangle] -pub fn checked_shr_unsigned(a: u32, b: u32) -> Option { - // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 - // CHECK-DAG: %[[SHIFTED_P:.+]] = lshr i32 %a, %b - // CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32 - // CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef - - // CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0 - // CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1 - // CHECK: ret { i32, i32 } %[[R1]] - a.checked_shr(b) -} - -// CHECK-LABEL: @checked_shl_signed -// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) -#[no_mangle] -pub fn checked_shl_signed(a: i32, b: u32) -> Option { - // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 - // CHECK-DAG: %[[SHIFTED_P:.+]] = shl i32 %a, %b - // CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32 - // CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef - - // CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0 - // CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1 - // CHECK: ret { i32, i32 } %[[R1]] - a.checked_shl(b) -} - -// CHECK-LABEL: @checked_shr_signed -// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) -#[no_mangle] -pub fn checked_shr_signed(a: i32, b: u32) -> Option { - // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 - // CHECK-DAG: %[[SHIFTED_P:.+]] = ashr i32 %a, %b - // CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32 - // CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef - - // CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0 - // CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1 - // CHECK: ret { i32, i32 } %[[R1]] - a.checked_shr(b) -} - -// CHECK-LABEL: @checked_add_one_unwrap_unsigned -// CHECK-SAME: (i32{{.*}} %x) -#[no_mangle] -pub fn checked_add_one_unwrap_unsigned(x: u32) -> u32 { - // CHECK: %[[IS_MAX:.+]] = icmp eq i32 %x, -1 - // CHECK: br i1 %[[IS_MAX]], label %[[NONE_BB:.+]], label %[[SOME_BB:.+]], - // CHECK: [[SOME_BB]]: - // CHECK: %[[R:.+]] = add nuw i32 %x, 1 - // CHECK: ret i32 %[[R]] - // CHECK: [[NONE_BB]]: - // CHECK: call {{.+}}unwrap_failed - x.checked_add(1).unwrap() -} diff --git a/tests/codegen/clone-shims.rs b/tests/codegen/clone-shims.rs deleted file mode 100644 index 06c959f9ee7..00000000000 --- a/tests/codegen/clone-shims.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Clone shims for aggregates are generated by just calling the Clone shims for all their members. -// Those calls generate a lot of unnecessary IR if the members are Copy. This test ensures that we -// optimize away those inner calls without needing to inline them. - -//@ compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0 -Zinline-mir=no -#![crate_type = "lib"] - -pub type Test = (i32, i32, *const i32); -pub static TEST: fn(&Test) -> Test = ::clone; - -// CHECK-NOT: call ::clone -// CHECK-NOT: call <*const i32 as core::clone::Clone>::clone -// CHECK: ; <(i32, i32, *const i32) as core::clone::Clone>::clone -// CHECK-NOT: call ::clone -// CHECK-NOT: call <*const i32 as core::clone::Clone>::clone diff --git a/tests/codegen/clone_as_copy.rs b/tests/codegen/clone_as_copy.rs deleted file mode 100644 index ef834ef5912..00000000000 --- a/tests/codegen/clone_as_copy.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@ revisions: DEBUGINFO NODEBUGINFO -//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes -//@ [DEBUGINFO] compile-flags: -Cdebuginfo=full - -// From https://github.com/rust-lang/rust/issues/128081. -// Ensure that we only generate a memcpy instruction. - -#![crate_type = "lib"] - -#[derive(Clone)] -struct SubCloneAndCopy { - v1: u32, - v2: u32, -} - -#[derive(Clone)] -struct CloneOnly { - v1: u8, - v2: u8, - v3: u8, - v4: u8, - v5: u8, - v6: u8, - v7: u8, - v8: u8, - v9: u8, - v_sub: SubCloneAndCopy, - v_large: [u8; 256], -} - -// CHECK-LABEL: define {{.*}}@clone_only( -#[no_mangle] -pub fn clone_only(v: &CloneOnly) -> CloneOnly { - // CHECK-NOT: call {{.*}}clone - // CHECK-NOT: store i8 - // CHECK-NOT: store i32 - // CHECK: call void @llvm.memcpy - // CHECK-NEXT: ret void - v.clone() -} diff --git a/tests/codegen/codemodels.rs b/tests/codegen/codemodels.rs deleted file mode 100644 index 06d2eade78a..00000000000 --- a/tests/codegen/codemodels.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ only-x86_64 - -//@ revisions: NOMODEL MODEL-SMALL MODEL-KERNEL MODEL-MEDIUM MODEL-LARGE -//@[NOMODEL] compile-flags: -//@[MODEL-SMALL] compile-flags: -C code-model=small -//@[MODEL-KERNEL] compile-flags: -C code-model=kernel -//@[MODEL-MEDIUM] compile-flags: -C code-model=medium -//@[MODEL-LARGE] compile-flags: -C code-model=large - -#![crate_type = "lib"] - -// MODEL-SMALL: !llvm.module.flags = !{{{.*}}} -// MODEL-SMALL: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 1} -// MODEL-KERNEL: !llvm.module.flags = !{{{.*}}} -// MODEL-KERNEL: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 2} -// MODEL-MEDIUM: !llvm.module.flags = !{{{.*}}} -// MODEL-MEDIUM: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 3} -// MODEL-LARGE: !llvm.module.flags = !{{{.*}}} -// MODEL-LARGE: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 4} -// NOMODEL-NOT: Code Model diff --git a/tests/codegen/coercions.rs b/tests/codegen/coercions.rs deleted file mode 100644 index 63c1742c639..00000000000 --- a/tests/codegen/coercions.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] - -static X: i32 = 5; - -// CHECK-LABEL: @raw_ptr_to_raw_ptr_noop -// CHECK-NOT: alloca -#[no_mangle] -pub fn raw_ptr_to_raw_ptr_noop() -> *const i32 { - &X as *const i32 -} - -// CHECK-LABEL: @reference_to_raw_ptr_noop -// CHECK-NOT: alloca -#[no_mangle] -pub fn reference_to_raw_ptr_noop() -> *const i32 { - &X -} diff --git a/tests/codegen/cold-call-declare-and-call.rs b/tests/codegen/cold-call-declare-and-call.rs deleted file mode 100644 index b18565ee6c3..00000000000 --- a/tests/codegen/cold-call-declare-and-call.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ revisions: NORMAL WIN -//@ compile-flags: -C no-prepopulate-passes -//@[NORMAL] ignore-windows -//@[WIN] only-windows -//@[WIN] only-x86_64 - -#![crate_type = "lib"] -#![feature(rust_cold_cc)] - -// wasm marks the definition as `dso_local`, so allow that as optional. - -// NORMAL: define{{( dso_local)?}} preserve_mostcc void @this_should_never_happen(i16 -// NORMAL: call preserve_mostcc void @this_should_never_happen(i16 - -// See the comment in `Target::adjust_abi` for why this differs - -// WIN: define void @this_should_never_happen(i16 -// WIN: call void @this_should_never_happen(i16 - -#[no_mangle] -pub extern "rust-cold" fn this_should_never_happen(x: u16) {} - -pub fn do_things(x: u16) { - if x == 12345 { - this_should_never_happen(54321); - } -} diff --git a/tests/codegen/common_prim_int_ptr.rs b/tests/codegen/common_prim_int_ptr.rs deleted file mode 100644 index 53716adccbf..00000000000 --- a/tests/codegen/common_prim_int_ptr.rs +++ /dev/null @@ -1,51 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -// Tests that codegen works properly when enums like `Result>` -// are represented as `{ u64, ptr }`, i.e., for `Ok(123)`, `123` is stored -// as a pointer. - -// CHECK-LABEL: @insert_int -#[no_mangle] -pub fn insert_int(x: usize) -> Result> { - // CHECK: start: - // CHECK-NEXT: %[[WO_PROV:.+]] = getelementptr i8, ptr null, [[USIZE:i[0-9]+]] %x - // CHECK-NEXT: %[[R:.+]] = insertvalue { [[USIZE]], ptr } { [[USIZE]] 0, ptr poison }, ptr %[[WO_PROV]], 1 - // CHECK-NEXT: ret { [[USIZE]], ptr } %[[R]] - Ok(x) -} - -// CHECK-LABEL: @insert_box -#[no_mangle] -pub fn insert_box(x: Box<()>) -> Result> { - // CHECK: start: - // CHECK-NEXT: insertvalue { i{{[0-9]+}}, ptr } - // CHECK-NEXT: ret - Err(x) -} - -// CHECK-LABEL: @extract_int -// CHECK-NOT: nonnull -// CHECK-SAME: (i{{[0-9]+}} {{[^%]+}} [[DISCRIMINANT:%[0-9]+]], ptr {{[^,]+}} [[PAYLOAD:%[0-9]+]]) -#[no_mangle] -pub unsafe fn extract_int(x: Result>) -> usize { - // CHECK: [[TEMP:%.+]] = ptrtoint ptr [[PAYLOAD]] to [[USIZE:i[0-9]+]] - // CHECK: ret [[USIZE]] [[TEMP]] - match x { - Ok(v) => v, - Err(_) => std::intrinsics::unreachable(), - } -} - -// CHECK-LABEL: @extract_box -// CHECK-SAME: (i{{[0-9]+}} {{[^%]+}} [[DISCRIMINANT:%[0-9]+]], ptr {{[^%]+}} [[PAYLOAD:%[0-9]+]]) -#[no_mangle] -pub unsafe fn extract_box(x: Result>) -> Box { - // CHECK: ret ptr [[PAYLOAD]] - match x { - Ok(_) => std::intrinsics::unreachable(), - Err(e) => e, - } -} diff --git a/tests/codegen/comparison-operators-2-struct.rs b/tests/codegen/comparison-operators-2-struct.rs deleted file mode 100644 index e179066ebfd..00000000000 --- a/tests/codegen/comparison-operators-2-struct.rs +++ /dev/null @@ -1,61 +0,0 @@ -//@ compile-flags: -C opt-level=1 -//@ min-llvm-version: 20 - -// The `derive(PartialOrd)` for a 2-field type doesn't override `lt`/`le`/`gt`/`ge`. -// This double-checks that the `Option` intermediate values used -// in the operators for such a type all optimize away. - -#![crate_type = "lib"] - -use std::cmp::Ordering; - -#[derive(PartialOrd, PartialEq)] -pub struct Foo(i32, u32); - -// CHECK-LABEL: @check_lt( -// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]]) -#[no_mangle] -pub fn check_lt(a: Foo, b: Foo) -> bool { - // CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]] - // CHECK-DAG: %[[R0:.+]] = icmp slt i32 %[[A0]], %[[B0]] - // CHECK-DAG: %[[R1:.+]] = icmp ult i32 %[[A1]], %[[B1]] - // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]] - // CHECK-NEXT: ret i1 %[[R]] - a < b -} - -// CHECK-LABEL: @check_le( -// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]]) -#[no_mangle] -pub fn check_le(a: Foo, b: Foo) -> bool { - // CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]] - // CHECK-DAG: %[[R0:.+]] = icmp sle i32 %[[A0]], %[[B0]] - // CHECK-DAG: %[[R1:.+]] = icmp ule i32 %[[A1]], %[[B1]] - // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]] - // CHECK-NEXT: ret i1 %[[R]] - a <= b -} - -// CHECK-LABEL: @check_gt( -// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]]) -#[no_mangle] -pub fn check_gt(a: Foo, b: Foo) -> bool { - // CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]] - // CHECK-DAG: %[[R0:.+]] = icmp sgt i32 %[[A0]], %[[B0]] - // CHECK-DAG: %[[R1:.+]] = icmp ugt i32 %[[A1]], %[[B1]] - // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]] - // CHECK-NEXT: ret i1 %[[R]] - a > b -} - -// CHECK-LABEL: @check_ge( -// CHECK-SAME: i32{{.+}}%[[A0:.+]], i32{{.+}}%[[A1:.+]], i32{{.+}}%[[B0:.+]], i32{{.+}}%[[B1:.+]]) -#[no_mangle] -pub fn check_ge(a: Foo, b: Foo) -> bool { - // CHECK-DAG: %[[EQ:.+]] = icmp eq i32 %[[A0]], %[[B0]] - // CHECK-DAG: %[[R0:.+]] = icmp sge i32 %[[A0]], %[[B0]] - // CHECK-DAG: %[[R1:.+]] = icmp uge i32 %[[A1]], %[[B1]] - // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[R1]], i1 %[[R0]] - // CHECK-NEXT: ret i1 %[[R]] - a >= b -} diff --git a/tests/codegen/comparison-operators-2-tuple.rs b/tests/codegen/comparison-operators-2-tuple.rs deleted file mode 100644 index 6a7e489c82d..00000000000 --- a/tests/codegen/comparison-operators-2-tuple.rs +++ /dev/null @@ -1,117 +0,0 @@ -//@ compile-flags: -C opt-level=1 -Z merge-functions=disabled -//@ min-llvm-version: 20 - -#![crate_type = "lib"] - -use std::cmp::Ordering; - -type TwoTuple = (i16, u16); - -// -// The operators are all overridden directly, so should optimize easily. -// -// slt-vs-sle and sgt-vs-sge don't matter because they're only used in the side -// of the select where we know the values are not equal, and thus the tests -// use a regex to allow either, since unimportant changes to the implementation -// sometimes result in changing what LLVM decides to emit for this. -// - -// CHECK-LABEL: @check_lt_direct -// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) -#[no_mangle] -pub fn check_lt_direct(a: TwoTuple, b: TwoTuple) -> bool { - // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP0:.+]] = icmp {{slt|sle}} i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP1:.+]] = icmp ult i16 %[[A1]], %[[B1]] - // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] - // CHECK: ret i1 %[[R]] - a < b -} - -// CHECK-LABEL: @check_le_direct -// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) -#[no_mangle] -pub fn check_le_direct(a: TwoTuple, b: TwoTuple) -> bool { - // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP0:.+]] = icmp {{slt|sle}} i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP1:.+]] = icmp ule i16 %[[A1]], %[[B1]] - // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] - // CHECK: ret i1 %[[R]] - a <= b -} - -// CHECK-LABEL: @check_gt_direct -// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) -#[no_mangle] -pub fn check_gt_direct(a: TwoTuple, b: TwoTuple) -> bool { - // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP0:.+]] = icmp {{sgt|sge}} i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP1:.+]] = icmp ugt i16 %[[A1]], %[[B1]] - // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] - // CHECK: ret i1 %[[R]] - a > b -} - -// CHECK-LABEL: @check_ge_direct -// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) -#[no_mangle] -pub fn check_ge_direct(a: TwoTuple, b: TwoTuple) -> bool { - // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP0:.+]] = icmp {{sgt|sge}} i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP1:.+]] = icmp uge i16 %[[A1]], %[[B1]] - // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] - // CHECK: ret i1 %[[R]] - a >= b -} - -// -// These used to not optimize as well, but thanks to LLVM 20 they work now 🎉 -// - -// CHECK-LABEL: @check_lt_via_cmp -// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) -#[no_mangle] -pub fn check_lt_via_cmp(a: TwoTuple, b: TwoTuple) -> bool { - // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP0:.+]] = icmp slt i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP1:.+]] = icmp ult i16 %[[A1]], %[[B1]] - // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] - // CHECK: ret i1 %[[R]] - Ord::cmp(&a, &b).is_lt() -} - -// CHECK-LABEL: @check_le_via_cmp -// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) -#[no_mangle] -pub fn check_le_via_cmp(a: TwoTuple, b: TwoTuple) -> bool { - // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP0:.+]] = icmp sle i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP1:.+]] = icmp ule i16 %[[A1]], %[[B1]] - // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] - // CHECK: ret i1 %[[R]] - Ord::cmp(&a, &b).is_le() -} - -// CHECK-LABEL: @check_gt_via_cmp -// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) -#[no_mangle] -pub fn check_gt_via_cmp(a: TwoTuple, b: TwoTuple) -> bool { - // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP0:.+]] = icmp sgt i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP1:.+]] = icmp ugt i16 %[[A1]], %[[B1]] - // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] - // CHECK: ret i1 %[[R]] - Ord::cmp(&a, &b).is_gt() -} - -// CHECK-LABEL: @check_ge_via_cmp -// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) -#[no_mangle] -pub fn check_ge_via_cmp(a: TwoTuple, b: TwoTuple) -> bool { - // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP0:.+]] = icmp sge i16 %[[A0]], %[[B0]] - // CHECK-DAG: %[[CMP1:.+]] = icmp uge i16 %[[A1]], %[[B1]] - // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] - // CHECK: ret i1 %[[R]] - Ord::cmp(&a, &b).is_ge() -} diff --git a/tests/codegen/comparison-operators-newtype.rs b/tests/codegen/comparison-operators-newtype.rs deleted file mode 100644 index acce0cb5946..00000000000 --- a/tests/codegen/comparison-operators-newtype.rs +++ /dev/null @@ -1,48 +0,0 @@ -// The `derive(PartialOrd)` for a newtype doesn't override `lt`/`le`/`gt`/`ge`. -// This double-checks that the `Option` intermediate values used -// in the operators for such a type all optimize away. - -//@ compile-flags: -C opt-level=1 - -#![crate_type = "lib"] - -use std::cmp::Ordering; - -#[derive(PartialOrd, PartialEq)] -pub struct Foo(u16); - -// CHECK-LABEL: @check_lt -// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) -#[no_mangle] -pub fn check_lt(a: Foo, b: Foo) -> bool { - // CHECK: %[[R:.+]] = icmp ult i16 %[[A]], %[[B]] - // CHECK-NEXT: ret i1 %[[R]] - a < b -} - -// CHECK-LABEL: @check_le -// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) -#[no_mangle] -pub fn check_le(a: Foo, b: Foo) -> bool { - // CHECK: %[[R:.+]] = icmp ule i16 %[[A]], %[[B]] - // CHECK-NEXT: ret i1 %[[R]] - a <= b -} - -// CHECK-LABEL: @check_gt -// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) -#[no_mangle] -pub fn check_gt(a: Foo, b: Foo) -> bool { - // CHECK: %[[R:.+]] = icmp ugt i16 %[[A]], %[[B]] - // CHECK-NEXT: ret i1 %[[R]] - a > b -} - -// CHECK-LABEL: @check_ge -// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) -#[no_mangle] -pub fn check_ge(a: Foo, b: Foo) -> bool { - // CHECK: %[[R:.+]] = icmp uge i16 %[[A]], %[[B]] - // CHECK-NEXT: ret i1 %[[R]] - a >= b -} diff --git a/tests/codegen/compiletest-self-test/minicore-smoke-test.rs b/tests/codegen/compiletest-self-test/minicore-smoke-test.rs deleted file mode 100644 index 9dd1bf29c6c..00000000000 --- a/tests/codegen/compiletest-self-test/minicore-smoke-test.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! Basic smoke test for `minicore` test auxiliary. - -//@ add-core-stubs -//@ compile-flags: --target=x86_64-unknown-linux-gnu -//@ needs-llvm-components: x86 - -#![crate_type = "lib"] -#![feature(no_core)] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; - -struct Meow; -impl Copy for Meow {} - -// CHECK-LABEL: meow -#[no_mangle] -fn meow() {} diff --git a/tests/codegen/const-array.rs b/tests/codegen/const-array.rs deleted file mode 100644 index b3df76c3d8e..00000000000 --- a/tests/codegen/const-array.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -const LUT: [u8; 4] = [1, 1, 1, 1]; - -// CHECK-LABEL: @decode -#[no_mangle] -pub fn decode(i: u8) -> u8 { - // CHECK: start: - // CHECK-NEXT: icmp - // CHECK-NEXT: select - // CHECK-NEXT: ret - if i < 4 { LUT[i as usize] } else { 2 } -} diff --git a/tests/codegen/const-vector.rs b/tests/codegen/const-vector.rs deleted file mode 100644 index a2249f4fff7..00000000000 --- a/tests/codegen/const-vector.rs +++ /dev/null @@ -1,78 +0,0 @@ -//@ revisions: OPT0 OPT0_S390X -//@ [OPT0] ignore-s390x -//@ [OPT0_S390X] only-s390x -//@ [OPT0] compile-flags: -C no-prepopulate-passes -Copt-level=0 -//@ [OPT0_S390X] compile-flags: -C no-prepopulate-passes -Copt-level=0 -C target-cpu=z13 - -// This test checks that constants of SIMD type are passed as immediate vectors. -// We ensure that both vector representations (struct with fields and struct wrapping array) work. -#![crate_type = "lib"] -#![feature(abi_unadjusted)] -#![feature(const_trait_impl)] -#![feature(repr_simd)] -#![feature(rustc_attrs)] -#![feature(simd_ffi)] -#![feature(arm_target_feature)] -#![feature(mips_target_feature)] -#![allow(non_camel_case_types)] - -#[path = "../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::{PackedSimd as Simd, f32x2, i8x2}; - -// The following functions are required for the tests to ensure -// that they are called with a const vector - -extern "unadjusted" { - fn test_i8x2(a: i8x2); - fn test_i8x2_two_args(a: i8x2, b: i8x2); - fn test_i8x2_mixed_args(a: i8x2, c: i32, b: i8x2); - fn test_i8x2_arr(a: i8x2); - fn test_f32x2(a: f32x2); - fn test_f32x2_arr(a: f32x2); - fn test_simd(a: Simd); - fn test_simd_unaligned(a: Simd); -} - -// Ensure the packed variant of the simd struct does not become a const vector -// if the size is not a power of 2 -// CHECK: %"minisimd::PackedSimd" = type { [3 x i32] } - -#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] -#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] -#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] -#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] -pub fn do_call() { - unsafe { - // CHECK: call void @test_i8x2(<2 x i8> - test_i8x2(const { i8x2::from_array([32, 64]) }); - - // CHECK: call void @test_i8x2_two_args(<2 x i8> , <2 x i8> - test_i8x2_two_args( - const { i8x2::from_array([32, 64]) }, - const { i8x2::from_array([8, 16]) }, - ); - - // CHECK: call void @test_i8x2_mixed_args(<2 x i8> , i32 43, <2 x i8> - test_i8x2_mixed_args( - const { i8x2::from_array([32, 64]) }, - 43, - const { i8x2::from_array([8, 16]) }, - ); - - // CHECK: call void @test_i8x2_arr(<2 x i8> - test_i8x2_arr(const { i8x2::from_array([32, 64]) }); - - // CHECK: call void @test_f32x2(<2 x float> - test_f32x2(const { f32x2::from_array([0.32, 0.64]) }); - - // CHECK: void @test_f32x2_arr(<2 x float> - test_f32x2_arr(const { f32x2::from_array([0.32, 0.64]) }); - - // CHECK: call void @test_simd(<4 x i32> - test_simd(const { Simd::([2, 4, 6, 8]) }); - - // CHECK: call void @test_simd_unaligned(%"minisimd::PackedSimd" %1 - test_simd_unaligned(const { Simd::([2, 4, 6]) }); - } -} diff --git a/tests/codegen/const_scalar_pair.rs b/tests/codegen/const_scalar_pair.rs deleted file mode 100644 index f142896c31f..00000000000 --- a/tests/codegen/const_scalar_pair.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ compile-flags: --crate-type=lib -Copt-level=0 -Zmir-opt-level=0 -C debuginfo=2 - -// Test that we don't generate a memory allocation for the constant -// and read the fields from that, but instead just create the value pair directly. -pub fn foo() -> (i32, i32) { - // CHECK: ret { i32, i32 } { i32 1, i32 2 } - const { (1, 2) } -} diff --git a/tests/codegen/constant-branch.rs b/tests/codegen/constant-branch.rs deleted file mode 100644 index 8fc8fb4f57a..00000000000 --- a/tests/codegen/constant-branch.rs +++ /dev/null @@ -1,49 +0,0 @@ -//@ compile-flags: -Zmir-opt-level=0 -C no-prepopulate-passes -Copt-level=0 -// make sure that branching on a constant does not emit a conditional -// branch or a switch - -#![crate_type = "lib"] - -// CHECK-LABEL: @if_bool -#[no_mangle] -pub fn if_bool() { - // CHECK-NOT: br i1 - // CHECK-NOT: switch - _ = if true { 0 } else { 1 }; - - _ = if false { 0 } else { 1 }; -} - -// CHECK-LABEL: @if_constant_int_eq -#[no_mangle] -pub fn if_constant_int_eq() { - // CHECK-NOT: br i1 - // CHECK-NOT: switch - let val = 0; - _ = if val == 0 { 0 } else { 1 }; - - // CHECK: br label %{{.+}} - _ = if val == 1 { 0 } else { 1 }; -} - -// CHECK-LABEL: @if_constant_match -#[no_mangle] -pub fn if_constant_match() { - // CHECK-NOT: br i1 - // CHECK-NOT: switch - _ = match 1 { - 1 => 2, - 2 => 3, - _ => 4, - }; - - _ = match 1 { - 2 => 3, - _ => 4, - }; - - _ = match -1 { - -1 => 1, - _ => 0, - } -} diff --git a/tests/codegen/consts.rs b/tests/codegen/consts.rs deleted file mode 100644 index 42ce7679d1a..00000000000 --- a/tests/codegen/consts.rs +++ /dev/null @@ -1,55 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] - -// Below, these constants are defined as enum variants that by itself would -// have a lower alignment than the enum type. Ensure that we mark them -// correctly with the higher alignment of the enum. - -// CHECK: @STATIC = {{.*}}, align 4 - -// This checks the constants from inline_enum_const -// CHECK: @alloc_[[INLINE_ENUM_HASH:[a-f0-9]{32}]] = {{.*}}, align 2 - -// This checks the constants from {low,high}_align_const, they share the same -// constant, but the alignment differs, so the higher one should be used -// CHECK: [[LOW_HIGH:@alloc_[a-f0-9]{32}]] = {{.*}}, align 4 - -#[derive(Copy, Clone)] -// repr(i16) is required for the {low,high}_align_const test -#[repr(i16)] -pub enum E { - A(A), - B(B), -} - -#[no_mangle] -pub static STATIC: E = E::A(0); - -// CHECK-LABEL: @static_enum_const -#[no_mangle] -pub fn static_enum_const() -> E { - STATIC -} - -// CHECK-LABEL: @inline_enum_const -#[no_mangle] -pub fn inline_enum_const() -> E { - *&E::A(0) -} - -// CHECK-LABEL: @low_align_const -#[no_mangle] -pub fn low_align_const() -> E { - // Check that low_align_const and high_align_const use the same constant - // CHECK: memcpy.{{.+}}(ptr align 2 %_0, ptr align 2 {{.*}}[[LOW_HIGH]]{{.*}}, i{{(32|64)}} 8, i1 false) - *&E::A(0) -} - -// CHECK-LABEL: @high_align_const -#[no_mangle] -pub fn high_align_const() -> E { - // Check that low_align_const and high_align_const use the same constant - // CHECK: memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[LOW_HIGH]]{{.*}}, i{{(32|64)}} 8, i1 false) - *&E::A(0) -} diff --git a/tests/codegen/coroutine-debug-msvc.rs b/tests/codegen/coroutine-debug-msvc.rs deleted file mode 100644 index 9e2ec3ea28a..00000000000 --- a/tests/codegen/coroutine-debug-msvc.rs +++ /dev/null @@ -1,60 +0,0 @@ -// Verify debuginfo for coroutines: -// - Each variant points to the file and line of its yield point -// - The discriminants are marked artificial -// - Other fields are not marked artificial -// -// -//@ compile-flags: -C debuginfo=2 -//@ only-msvc - -#![feature(coroutines, coroutine_trait)] -use std::ops::Coroutine; - -fn coroutine_test() -> impl Coroutine { - #[coroutine] - || { - yield 0; - let s = String::from("foo"); - yield 1; - } -} - -// FIXME: No way to reliably check the filename. - -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$" -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]], -// For brevity, we only check the struct name and members of the last variant. -// CHECK-SAME: file: [[FILE:![0-9]*]], line: 15, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]], -// CHECK-SAME: file: [[FILE]], line: 19, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]], -// CHECK-SAME: file: [[FILE]], line: 19, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]], -// CHECK-SAME: file: [[FILE]], line: 16, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]], -// CHECK-SAME: file: [[FILE]], line: 18, -// CHECK-SAME: baseType: [[VARIANT_WRAPPER:![0-9]*]] -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: [[VARIANT_WRAPPER]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Variant4", scope: [[GEN]], -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "value", scope: [[VARIANT_WRAPPER]], {{.*}}, baseType: [[VARIANT:![0-9]*]], -// CHECK: [[VARIANT]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[VARIANT]] -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "tag", scope: [[GEN]], -// CHECK-NOT: flags: DIFlagArtificial - -fn main() { - let _dummy = coroutine_test(); -} diff --git a/tests/codegen/coroutine-debug.rs b/tests/codegen/coroutine-debug.rs deleted file mode 100644 index ff62e9709b4..00000000000 --- a/tests/codegen/coroutine-debug.rs +++ /dev/null @@ -1,64 +0,0 @@ -// Verify debuginfo for coroutines: -// - Each variant points to the file and line of its yield point -// - The discriminants are marked artificial -// - Other fields are not marked artificial -// -// -//@ compile-flags: -C debuginfo=2 -//@ edition: 2018 -//@ ignore-msvc - -#![feature(coroutines, coroutine_trait)] -use std::ops::Coroutine; - -fn coroutine_test() -> impl Coroutine { - #[coroutine] - || { - yield 0; - let s = String::from("foo"); - yield 1; - } -} - -// FIXME: No way to reliably check the filename. - -// CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "coroutine_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{coroutine_env#0}", scope: [[GEN_FN]] -// CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[GEN]], -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: discriminator: [[DISC:![0-9]*]] -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE:![0-9]*]], line: 16, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]], -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 20, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 20, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 17, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 19, -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] -// CHECK-NOT: flags: DIFlagArtificial -// CHECK-SAME: ) -// CHECK: [[DISC]] = !DIDerivedType(tag: DW_TAG_member, name: "__state", scope: [[GEN]], -// CHECK-SAME: flags: DIFlagArtificial - -fn main() { - let _dummy = coroutine_test(); -} diff --git a/tests/codegen/cross-crate-inlining/always-inline.rs b/tests/codegen/cross-crate-inlining/always-inline.rs deleted file mode 100644 index df28b3fe197..00000000000 --- a/tests/codegen/cross-crate-inlining/always-inline.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ aux-build:always.rs - -#![crate_type = "lib"] - -extern crate always; - -// Check that we inline a cross-crate call, even though it isn't a leaf -#[no_mangle] -pub fn outer() -> String { - // CHECK-NOT: call {{.*}}stem_fn - always::stem_fn() -} diff --git a/tests/codegen/cross-crate-inlining/auxiliary/always.rs b/tests/codegen/cross-crate-inlining/auxiliary/always.rs deleted file mode 100644 index 6ee3f81e3c8..00000000000 --- a/tests/codegen/cross-crate-inlining/auxiliary/always.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Zcross-crate-inline-threshold=always - -#![crate_type = "lib"] - -// This function *looks* like it contains a call, but that call will be optimized out by MIR -// optimizations. -pub fn leaf_fn() -> String { - String::new() -} - -// This function contains a call, even after MIR optimizations. It is only eligible for -// cross-crate-inlining with "always". -pub fn stem_fn() -> String { - inner() -} - -#[inline(never)] -fn inner() -> String { - String::from("test") -} diff --git a/tests/codegen/cross-crate-inlining/auxiliary/leaf.rs b/tests/codegen/cross-crate-inlining/auxiliary/leaf.rs deleted file mode 100644 index d059a3d0a73..00000000000 --- a/tests/codegen/cross-crate-inlining/auxiliary/leaf.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// This function *looks* like it contains a call, but that call will be optimized out by MIR -// optimizations. -pub fn leaf_fn() -> String { - String::new() -} - -// This function contains a call, even after MIR optimizations. It is only eligible for -// cross-crate-inlining with "always". -pub fn stem_fn() -> String { - inner() -} - -#[inline(never)] -fn inner() -> String { - String::from("test") -} diff --git a/tests/codegen/cross-crate-inlining/auxiliary/never.rs b/tests/codegen/cross-crate-inlining/auxiliary/never.rs deleted file mode 100644 index 55c90809ec1..00000000000 --- a/tests/codegen/cross-crate-inlining/auxiliary/never.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Zcross-crate-inline-threshold=never - -#![crate_type = "lib"] - -// This function *looks* like it contains a call, but that call will be optimized out by MIR -// optimizations. -pub fn leaf_fn() -> String { - String::new() -} - -// This function contains a call, even after MIR optimizations. It is only eligible for -// cross-crate-inlining with "always". -pub fn stem_fn() -> String { - inner() -} - -#[inline(never)] -fn inner() -> String { - String::from("test") -} diff --git a/tests/codegen/cross-crate-inlining/leaf-inlining.rs b/tests/codegen/cross-crate-inlining/leaf-inlining.rs deleted file mode 100644 index 37132312ca9..00000000000 --- a/tests/codegen/cross-crate-inlining/leaf-inlining.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Zcross-crate-inline-threshold=yes -//@ aux-build:leaf.rs - -#![crate_type = "lib"] - -extern crate leaf; - -// Check that we inline a leaf cross-crate call -#[no_mangle] -pub fn leaf_outer() -> String { - // CHECK-NOT: call {{.*}}leaf_fn - leaf::leaf_fn() -} - -// Check that we do not inline a non-leaf cross-crate call -#[no_mangle] -pub fn stem_outer() -> String { - // CHECK: call {{.*}}stem_fn - leaf::stem_fn() -} diff --git a/tests/codegen/cross-crate-inlining/never-inline.rs b/tests/codegen/cross-crate-inlining/never-inline.rs deleted file mode 100644 index 759f65d9d42..00000000000 --- a/tests/codegen/cross-crate-inlining/never-inline.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ aux-build:never.rs - -#![crate_type = "lib"] - -extern crate never; - -// Check that we do not inline a cross-crate call, even though it is a leaf -#[no_mangle] -pub fn outer() -> String { - // CHECK: call {{.*}}leaf_fn - never::leaf_fn() -} diff --git a/tests/codegen/dealloc-no-unwind.rs b/tests/codegen/dealloc-no-unwind.rs deleted file mode 100644 index 68597817d6f..00000000000 --- a/tests/codegen/dealloc-no-unwind.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -struct A; - -impl Drop for A { - fn drop(&mut self) { - extern "C" { - fn foo(); - } - unsafe { - foo(); - } - } -} - -#[no_mangle] -pub fn a(a: Box) { - // CHECK-LABEL: define{{.*}}void @a - // CHECK: call void @{{.*}}__rust_dealloc - // CHECK-NEXT: call void @foo - let _a = A; - drop(a); -} diff --git a/tests/codegen/debug-accessibility/crate-enum.rs b/tests/codegen/debug-accessibility/crate-enum.rs deleted file mode 100644 index 9ad5a6fd0ff..00000000000 --- a/tests/codegen/debug-accessibility/crate-enum.rs +++ /dev/null @@ -1,28 +0,0 @@ -// ignore-tidy-linelength -//! Checks that visibility information is present in the debuginfo for crate-visibility enums. - -//@ revisions: MSVC NONMSVC -//@[MSVC] only-msvc -//@[NONMSVC] ignore-msvc - -//@ compile-flags: -C debuginfo=2 - -mod module { - use std::hint::black_box; - - pub(crate) enum CrateFooEnum { - A, - B(u32), - C { x: u32 }, - } - - // NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "CrateFooEnum"{{.*}}flags: DIFlagProtected{{.*}}) - // MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$"{{.*}}flags: DIFlagProtected{{.*}}) - pub fn use_everything() { - black_box(CrateFooEnum::A); - } -} - -fn main() { - module::use_everything(); -} diff --git a/tests/codegen/debug-accessibility/crate-struct.rs b/tests/codegen/debug-accessibility/crate-struct.rs deleted file mode 100644 index 73a8ce852ed..00000000000 --- a/tests/codegen/debug-accessibility/crate-struct.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ compile-flags: -C debuginfo=2 - -#![allow(dead_code)] - -// Checks that visibility information is present in the debuginfo for crate-visibility structs. - -mod module { - use std::hint::black_box; - - pub(crate) struct CrateFooStruct { - x: u32, - } - - // CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "CrateFooStruct"{{.*}}flags: DIFlagProtected{{.*}}) - - pub fn use_everything() { - black_box(CrateFooStruct { x: 2 }); - } -} - -fn main() { - module::use_everything(); -} diff --git a/tests/codegen/debug-accessibility/private-enum.rs b/tests/codegen/debug-accessibility/private-enum.rs deleted file mode 100644 index 002336c03b3..00000000000 --- a/tests/codegen/debug-accessibility/private-enum.rs +++ /dev/null @@ -1,22 +0,0 @@ -// ignore-tidy-linelength -//! Checks that visibility information is present in the debuginfo for private enums. - -//@ revisions: MSVC NONMSVC -//@[MSVC] only-msvc -//@[NONMSVC] ignore-msvc -//@ compile-flags: -C debuginfo=2 - -use std::hint::black_box; - -enum PrivateFooEnum { - A, - B(u32), - C { x: u32 }, -} - -// NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PrivateFooEnum"{{.*}}flags: DIFlagPrivate{{.*}}) -// MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$"{{.*}}flags: DIFlagPrivate{{.*}}) - -fn main() { - black_box(PrivateFooEnum::A); -} diff --git a/tests/codegen/debug-accessibility/private-struct.rs b/tests/codegen/debug-accessibility/private-struct.rs deleted file mode 100644 index 488a680e81c..00000000000 --- a/tests/codegen/debug-accessibility/private-struct.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ compile-flags: -C debuginfo=2 - -#![allow(dead_code)] - -// Checks that visibility information is present in the debuginfo for private structs. - -use std::hint::black_box; - -struct PrivateFooStruct { - x: u32, -} - -// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PrivateFooStruct"{{.*}}flags: DIFlagPrivate{{.*}}) - -fn main() { - black_box(PrivateFooStruct { x: 1 }); -} diff --git a/tests/codegen/debug-accessibility/public-enum.rs b/tests/codegen/debug-accessibility/public-enum.rs deleted file mode 100644 index e5cd1ab7350..00000000000 --- a/tests/codegen/debug-accessibility/public-enum.rs +++ /dev/null @@ -1,23 +0,0 @@ -// ignore-tidy-linelength -//! Checks that visibility information is present in the debuginfo for types and their fields. - -//@ revisions: MSVC NONMSVC -//@[MSVC] only-msvc -//@[NONMSVC] ignore-msvc - -//@ compile-flags: -C debuginfo=2 - -use std::hint::black_box; - -pub enum PublicFooEnum { - A, - B(u32), - C { x: u32 }, -} - -// NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PublicFooEnum"{{.*}}flags: DIFlagPublic{{.*}}) -// MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$"{{.*}}flags: DIFlagPublic{{.*}}) - -fn main() { - black_box(PublicFooEnum::A); -} diff --git a/tests/codegen/debug-accessibility/public-struct.rs b/tests/codegen/debug-accessibility/public-struct.rs deleted file mode 100644 index 8b2a53f993c..00000000000 --- a/tests/codegen/debug-accessibility/public-struct.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ compile-flags: -C debuginfo=2 - -#![allow(dead_code)] - -// Checks that visibility information is present in the debuginfo for public structs. - -use std::hint::black_box; - -pub struct PublicFooStruct { - x: u32, -} - -// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PublicFooStruct"{{.*}}flags: DIFlagPublic{{.*}}) - -fn main() { - black_box(PublicFooStruct { x: 4 }); -} diff --git a/tests/codegen/debug-accessibility/struct-fields.rs b/tests/codegen/debug-accessibility/struct-fields.rs deleted file mode 100644 index f68bb3438be..00000000000 --- a/tests/codegen/debug-accessibility/struct-fields.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@ compile-flags: -C debuginfo=2 - -#![allow(dead_code)] - -// Checks that visibility information is present in the debuginfo for struct fields. - -mod module { - use std::hint::black_box; - - struct StructFields { - a: u32, - pub(crate) b: u32, - pub(super) c: u32, - pub d: u32, - } - - // CHECK: [[StructFields:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "StructFields"{{.*}}flags: DIFlagPrivate{{.*}}) - // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: [[StructFields]]{{.*}}flags: DIFlagPrivate{{.*}}) - // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: [[StructFields]]{{.*}}flags: DIFlagProtected{{.*}}) - // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: [[StructFields]]{{.*}}flags: DIFlagProtected{{.*}}) - // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: [[StructFields]]{{.*}}flags: DIFlagPublic{{.*}}) - - pub fn use_everything() { - black_box(StructFields { a: 1, b: 2, c: 3, d: 4 }); - } -} - -fn main() { - module::use_everything(); -} diff --git a/tests/codegen/debug-accessibility/super-enum.rs b/tests/codegen/debug-accessibility/super-enum.rs deleted file mode 100644 index 8e34d8be01f..00000000000 --- a/tests/codegen/debug-accessibility/super-enum.rs +++ /dev/null @@ -1,28 +0,0 @@ -// ignore-tidy-linelength -//! Checks that visibility information is present in the debuginfo for super-visibility enums. - -//@ revisions: MSVC NONMSVC -//@[MSVC] only-msvc -//@[NONMSVC] ignore-msvc -//@ compile-flags: -C debuginfo=2 - -mod module { - use std::hint::black_box; - - pub(super) enum SuperFooEnum { - A, - B(u32), - C { x: u32 }, - } - - // NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "SuperFooEnum"{{.*}}flags: DIFlagProtected{{.*}}) - // MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$"{{.*}}flags: DIFlagProtected{{.*}}) - - pub fn use_everything() { - black_box(SuperFooEnum::A); - } -} - -fn main() { - module::use_everything(); -} diff --git a/tests/codegen/debug-accessibility/super-struct.rs b/tests/codegen/debug-accessibility/super-struct.rs deleted file mode 100644 index 63954bfb203..00000000000 --- a/tests/codegen/debug-accessibility/super-struct.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ compile-flags: -C debuginfo=2 - -#![allow(dead_code)] - -// Checks that visibility information is present in the debuginfo for super-visibility structs. - -mod module { - use std::hint::black_box; - - pub(super) struct SuperFooStruct { - x: u32, - } - - // CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "SuperFooStruct"{{.*}}flags: DIFlagProtected{{.*}}) - - pub fn use_everything() { - black_box(SuperFooStruct { x: 3 }); - } -} - -fn main() { - module::use_everything(); -} diff --git a/tests/codegen/debug-accessibility/tuple-fields.rs b/tests/codegen/debug-accessibility/tuple-fields.rs deleted file mode 100644 index feec6e9eb41..00000000000 --- a/tests/codegen/debug-accessibility/tuple-fields.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ compile-flags: -C debuginfo=2 - -#![allow(dead_code)] - -// Checks that visibility information is present in the debuginfo for tuple struct fields. - -mod module { - use std::hint::black_box; - - struct TupleFields(u32, pub(crate) u32, pub(super) u32, pub u32); - - // CHECK: [[TupleFields:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "TupleFields"{{.*}}flags: DIFlagPrivate{{.*}}) - // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__0", scope: [[TupleFields]]{{.*}}flags: DIFlagPrivate{{.*}}) - // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__1", scope: [[TupleFields]]{{.*}}flags: DIFlagProtected{{.*}}) - // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__2", scope: [[TupleFields]]{{.*}}flags: DIFlagProtected{{.*}}) - // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__3", scope: [[TupleFields]]{{.*}}flags: DIFlagPublic{{.*}}) - pub fn use_everything() { - black_box(TupleFields(1, 2, 3, 4)); - } -} - -fn main() { - module::use_everything(); -} diff --git a/tests/codegen/debug-alignment.rs b/tests/codegen/debug-alignment.rs deleted file mode 100644 index 02fe05832a3..00000000000 --- a/tests/codegen/debug-alignment.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Verifies that DWARF alignment is specified properly. -// -//@ compile-flags: -C debuginfo=2 -#![crate_type = "lib"] - -// CHECK: !DIGlobalVariable -// CHECK: align: 32 -pub static A: u32 = 1; diff --git a/tests/codegen/debug-column-msvc.rs b/tests/codegen/debug-column-msvc.rs deleted file mode 100644 index 39f77f41329..00000000000 --- a/tests/codegen/debug-column-msvc.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Verify that no column information is emitted for MSVC targets -// -//@ only-msvc -//@ compile-flags: -C debuginfo=2 - -// CHECK-NOT: !DILexicalBlock({{.*}}column: {{.*}}) -// CHECK-NOT: !DILocation({{.*}}column: {{.*}}) - -pub fn add(a: u32, b: u32) -> u32 { - a + b -} - -fn main() { - let c = add(1, 2); - println!("{}", c); -} diff --git a/tests/codegen/debug-column.rs b/tests/codegen/debug-column.rs deleted file mode 100644 index 2aa0a8a864c..00000000000 --- a/tests/codegen/debug-column.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Verify that debuginfo column numbers are 1-based byte offsets. -// -//@ ignore-msvc -//@ compile-flags: -C debuginfo=2 - -#[rustfmt::skip] -fn main() { - unsafe { - // Column numbers are 1-based. Regression test for #65437. - // CHECK: call void @giraffe(){{( #[0-9]+)?}}, !dbg [[A:!.*]] - giraffe(); - - // Column numbers use byte offests. Regression test for #67360 - // CHECK: call void @turtle(){{( #[0-9]+)?}}, !dbg [[B:!.*]] -/* ż */ turtle(); - - // CHECK: [[A]] = !DILocation(line: 11, column: 9, - // CHECK: [[B]] = !DILocation(line: 15, column: 10, - } -} - -extern "C" { - fn giraffe(); - fn turtle(); -} diff --git a/tests/codegen/debug-compile-unit-path.rs b/tests/codegen/debug-compile-unit-path.rs deleted file mode 100644 index 6131d9d7351..00000000000 --- a/tests/codegen/debug-compile-unit-path.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ compile-flags: -g --remap-path-prefix={{cwd}}=/cwd/ --remap-path-prefix={{src-base}}=/base/ -// -// -// Ensure that we remap the compile unit directory and that we set it to the compilers current -// working directory and not something else. -#![crate_type = "rlib"] - -// CHECK-DAG: [[FILE:![0-9]*]] = !DIFile(filename: "/base/debug-compile-unit-path.rs{{.*}}", directory: "/cwd/") -// CHECK-DAG: {{![0-9]*}} = distinct !DICompileUnit({{.*}}file: [[FILE]] diff --git a/tests/codegen/debug-fndef-size.rs b/tests/codegen/debug-fndef-size.rs deleted file mode 100644 index 8f716c34e7b..00000000000 --- a/tests/codegen/debug-fndef-size.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Verify that `i32::cmp` FnDef type is declared with a size of 0 and an -// alignment of 8 bits (1 byte) in LLVM debuginfo. - -//@ compile-flags: -Copt-level=3 -g -Cno-prepopulate-passes -//@ ignore-msvc the types are mangled differently - -use std::cmp::Ordering; - -fn foo Ordering>(v1: i32, v2: i32, compare: F) -> Ordering { - compare(&v1, &v2) -} - -pub fn main() { - foo(0, 1, i32::cmp); -} - -// CHECK: %compare.dbg.spill = alloca [0 x i8], align 1 -// CHECK: dbg{{.}}declare({{(metadata )?}}ptr %compare.dbg.spill, {{(metadata )?}}![[VAR:.*]], {{(metadata )?}}!DIExpression() -// CHECK: ![[TYPE:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "fn(&i32, &i32) -> core::cmp::Ordering", baseType: !{{.*}}, align: 8, dwarfAddressSpace: {{.*}}) -// CHECK: ![[VAR]] = !DILocalVariable(name: "compare", scope: !{{.*}}, file: !{{.*}}, line: {{.*}}, type: ![[TYPE]], align: 8) diff --git a/tests/codegen/debug-limited.rs b/tests/codegen/debug-limited.rs deleted file mode 100644 index 89a4ef0ca90..00000000000 --- a/tests/codegen/debug-limited.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Verify that the limited debuginfo option emits llvm's FullDebugInfo, but no type info. -// -//@ compile-flags: -C debuginfo=limited - -#[repr(C)] -struct StructType { - a: i64, - b: i32, -} - -extern "C" { - fn creator() -> *mut StructType; - fn save(p: *const StructType); -} - -fn main() { - unsafe { - let value: &mut StructType = &mut *creator(); - value.a = 7; - save(value as *const StructType) - } -} - -// CHECK: !DICompileUnit -// CHECK: emissionKind: FullDebug -// CHECK: !DILocation -// CHECK-NOT: !DIBasicType diff --git a/tests/codegen/debug-line-directives-only.rs b/tests/codegen/debug-line-directives-only.rs deleted file mode 100644 index 709c8789bf8..00000000000 --- a/tests/codegen/debug-line-directives-only.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Verify that the only debuginfo generated are the line directives. -// -//@ compile-flags: -C debuginfo=line-directives-only - -#[repr(C)] -struct StructType { - a: i64, - b: i32, -} - -extern "C" { - fn creator() -> *mut StructType; - fn save(p: *const StructType); -} - -fn main() { - unsafe { - let value: &mut StructType = &mut *creator(); - value.a = 7; - save(value as *const StructType) - } -} - -// CHECK: !DICompileUnit -// CHECK: emissionKind: DebugDirectivesOnly -// CHECK: !DILocation -// CHECK-NOT: !DIBasicType diff --git a/tests/codegen/debug-line-tables-only.rs b/tests/codegen/debug-line-tables-only.rs deleted file mode 100644 index d50bffe6e60..00000000000 --- a/tests/codegen/debug-line-tables-only.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Verify that the only debuginfo generated are the line tables. -// -//@ compile-flags: -C debuginfo=line-tables-only - -#[repr(C)] -struct StructType { - a: i64, - b: i32, -} - -extern "C" { - fn creator() -> *mut StructType; - fn save(p: *const StructType); -} - -fn main() { - unsafe { - let value: &mut StructType = &mut *creator(); - value.a = 7; - save(value as *const StructType) - } -} - -// CHECK: !DICompileUnit -// CHECK: emissionKind: LineTablesOnly -// CHECK: !DILocation -// CHECK-NOT: !DIBasicType diff --git a/tests/codegen/debug-linkage-name.rs b/tests/codegen/debug-linkage-name.rs deleted file mode 100644 index e706040f331..00000000000 --- a/tests/codegen/debug-linkage-name.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Verifies that linkage name is omitted when it is -// the same as variable / function name. -// -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -//@ compile-flags: -C debuginfo=2 -Copt-level=0 -#![crate_type = "lib"] - -pub mod xyz { - // CHECK: !DIGlobalVariable(name: "A", - // CHECK: linkageName: - // CHECK-SAME: line: 12, - pub static A: u32 = 1; - - // CHECK: !DIGlobalVariable(name: "B", - // CHECK-NOT: linkageName: - // CHECK-SAME: line: 18, - #[no_mangle] - pub static B: u32 = 2; - - // CHECK: !DIGlobalVariable(name: "C", - // CHECK-NOT: linkageName: - // CHECK-SAME: line: 24, - #[export_name = "C"] - pub static C: u32 = 2; - - // CHECK: !DISubprogram(name: "e", - // CHECK: linkageName: - // CHECK-SAME: line: 29, - pub extern "C" fn e() {} - - // CHECK: !DISubprogram(name: "f", - // CHECK-NOT: linkageName: - // CHECK-SAME: line: 35, - #[no_mangle] - pub extern "C" fn f() {} - - // CHECK: !DISubprogram(name: "g", - // CHECK-NOT: linkageName: - // CHECK-SAME: line: 41, - #[export_name = "g"] - pub extern "C" fn g() {} -} diff --git a/tests/codegen/debug-vtable.rs b/tests/codegen/debug-vtable.rs deleted file mode 100644 index 8a7b1cc3c4b..00000000000 --- a/tests/codegen/debug-vtable.rs +++ /dev/null @@ -1,117 +0,0 @@ -// ignore-tidy-linelength -//! This test checks the debuginfo for the expected 3 vtables is generated for correct names and -//! number of entries. - -//@ revisions: MSVC NONMSVC -//@[MSVC] only-msvc -//@[NONMSVC] ignore-msvc - -// Use the v0 symbol mangling scheme to codegen order independent of rustc version. -// Unnamed items like shims are generated in lexicographical order of their symbol name and in the -// legacy mangling scheme rustc version and generic parameters are both hashed into a single part -// of the name, thus randomizing item order with respect to rustc version. - -//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0 - -// Make sure that vtables don't have the unnamed_addr attribute when debuginfo is enabled. -// This helps debuggers more reliably map from dyn pointer to concrete type. -// CHECK: @vtable.2 = private constant [ -// CHECK: @vtable.3 = private constant <{ -// CHECK: @vtable.4 = private constant <{ - -// NONMSVC: ![[USIZE:[0-9]+]] = !DIBasicType(name: "usize" -// MSVC: ![[USIZE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "usize" -// NONMSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()" -// MSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$ >" - -// NONMSVC: !DIGlobalVariable(name: "::{vtable}" -// MSVC: !DIGlobalVariable(name: "impl$::vtable$" - -// NONMSVC: ![[VTABLE_TY0:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "::{vtable_type}", {{.*}} size: {{320|160}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}} vtableHolder: ![[FOO_TYPE:[0-9]+]], -// MSVC: ![[VTABLE_TY0:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$::vtable_type$", {{.*}} size: {{320|160}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}} vtableHolder: ![[FOO_TYPE:[0-9]+]], -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}) -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}}) -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}}) -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method3", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{192|96}}) -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method4", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{256|128}}) -// CHECK: ![[FOO_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", - -// NONMSVC: !DIGlobalVariable(name: ">::{vtable}" -// MSVC: !DIGlobalVariable(name: "impl$ >::vtable$" - -// NONMSVC: ![[VTABLE_TY1:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: ">::{vtable_type}", {{.*}}, size: {{256|128}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]], -// MSVC: ![[VTABLE_TY1:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$ >::vtable_type$", {{.*}}, size: {{256|128}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]], -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}) -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}}) -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}}) -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method3", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{192|96}}) - -// NONMSVC: !DIGlobalVariable(name: "::{vtable}" -// MSVC: !DIGlobalVariable(name: "impl$::vtable$" - -// NONMSVC: ![[VTABLE_TY2:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "::{vtable_type}", {{.*}}, size: {{192|96}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]], -// MSVC: ![[VTABLE_TY2:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$::vtable_type$", {{.*}}, size: {{192|96}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]], -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}) -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}}) -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}}) - -// NONMSVC: !DIGlobalVariable(name: ">)>>::{vtable}" -// MSVC: !DIGlobalVariable(name: "impl$,assoc$ > > > > > > > > >::vtable$" - -// NONMSVC: !DIGlobalVariable(name: " as core::ops::function::FnOnce<()>>::{vtable}" -// MSVC: !DIGlobalVariable(name: "impl$, core::ops::function::FnOnce > >::vtable$ - -// NONMSVC: !DIGlobalVariable(name: " as core::ops::function::FnOnce<()>>::{vtable}" -// MSVC: !DIGlobalVariable(name: "impl$, core::ops::function::FnOnce > >::vtable$ - -#![crate_type = "lib"] - -// Force emission for debuginfo for usize and *const() early.. -pub static mut XYZ: Option<(usize, *const ())> = None; - -pub struct Foo; - -pub trait SomeTrait { - fn method1(&self) -> u32; - fn method2(&self) -> u32; -} - -impl SomeTrait for Foo { - fn method1(&self) -> u32 { - 1 - } - fn method2(&self) -> u32 { - 2 - } -} - -pub trait SomeTraitWithGenerics { - fn method1(&self) -> (T, U); -} - -impl SomeTraitWithGenerics for Foo { - fn method1(&self) -> (u64, i8) { - (1, 2) - } -} - -pub fn foo(x: &Foo) -> (u32, (u64, i8), &dyn Send) { - let y: &dyn SomeTrait = x; - let z: &dyn SomeTraitWithGenerics = x; - (y.method1(), z.method1(), x as &dyn Send) -} - -// Constructing the debuginfo name for the FnOnce vtable below initially caused an ICE on MSVC -// because the trait type contains a late bound region that needed to be erased before the type -// layout for the niche enum `Option<&dyn Fn()>` could be computed. -pub fn bar() -> Box)> { - Box::new(|_x: Option<&dyn Fn()>| {}) -} - -fn generic_closure(x: T) -> Box T> { - Box::new(move || x) -} - -pub fn instantiate_generic_closures() -> (Box u32>, Box bool>) { - (generic_closure(1u32), generic_closure(false)) -} diff --git a/tests/codegen/debuginfo-constant-locals.rs b/tests/codegen/debuginfo-constant-locals.rs deleted file mode 100644 index 580c69c05a5..00000000000 --- a/tests/codegen/debuginfo-constant-locals.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ compile-flags: -g -Copt-level=3 - -// Check that simple constant values are preserved in debuginfo across both MIR opts and LLVM opts - -#![crate_type = "lib"] - -#[no_mangle] -pub fn check_it() { - let a = 1; - let b = 42; - - foo(a + b); -} - -#[inline(never)] -fn foo(x: i32) { - std::process::exit(x); -} - -// CHECK-LABEL: @check_it -// CHECK: dbg{{.}}value({{(metadata )?}}i32 1, {{(metadata )?}}![[a_metadata:[0-9]+]], {{(metadata )?}}!DIExpression() -// CHECK: dbg{{.}}value({{(metadata )?}}i32 42, {{(metadata )?}}![[b_metadata:[0-9]+]], {{(metadata )?}}!DIExpression() - -// CHECK: ![[a_metadata]] = !DILocalVariable(name: "a" -// CHECK-SAME: line: 9 - -// CHECK: ![[b_metadata]] = !DILocalVariable(name: "b" -// CHECK-SAME: line: 10 diff --git a/tests/codegen/debuginfo-generic-closure-env-names.rs b/tests/codegen/debuginfo-generic-closure-env-names.rs deleted file mode 100644 index 64bc58e1df7..00000000000 --- a/tests/codegen/debuginfo-generic-closure-env-names.rs +++ /dev/null @@ -1,90 +0,0 @@ -// ignore-tidy-linelength -//! This test checks that we get proper type names for closure environments and -//! async-fn environments in debuginfo, especially making sure that generic arguments -//! of the enclosing functions don't get lost. -//! -//! Unfortunately, the order that debuginfo gets emitted into LLVM IR becomes a bit hard -//! to predict once async fns are involved, so DAG allows any order. -//! -//! Note that the test does not check async-fns when targeting MSVC because debuginfo for -//! those does not follow the enum-fallback encoding yet and thus is incomplete. - -//@ revisions: MSVC NONMSVC -//@[MSVC] only-msvc -//@[NONMSVC] ignore-msvc - -// Use the v0 symbol mangling scheme to codegen order independent of rustc version. -// Unnamed items like shims are generated in lexicographical order of their symbol name and in the -// legacy mangling scheme rustc version and generic parameters are both hashed into a single part -// of the name, thus randomizing item order with respect to rustc version. - -//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0 -//@ edition: 2021 - -// non_generic_closure() -// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[non_generic_closure_NAMESPACE:[0-9]+]], -// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[non_generic_closure_NAMESPACE:[0-9]+]], -// CHECK: ![[non_generic_closure_NAMESPACE]] = !DINamespace(name: "non_generic_closure" - -// CHECK: ![[function_containing_closure_NAMESPACE:[0-9]+]] = !DINamespace(name: "function_containing_closure" -// CHECK: ![[generic_async_function_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_function" -// CHECK: ![[generic_async_block_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_block" - -// function_containing_closure() -// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[function_containing_closure_NAMESPACE]] -// MSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[function_containing_closure_NAMESPACE]] - -// generic_async_function() -// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: ![[generic_async_function_NAMESPACE]] - -// generic_async_function() -// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: ![[generic_async_function_NAMESPACE]] - -// generic_async_block() -// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}", scope: ![[generic_async_block_NAMESPACE]] - -// generic_async_block() -// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}", scope: ![[generic_async_block_NAMESPACE]] - -// function_containing_closure() -// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[function_containing_closure_NAMESPACE]] -// MSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[function_containing_closure_NAMESPACE]] - -#![crate_type = "lib"] -use std::future::Future; - -pub struct Foo; - -pub fn non_generic_closure(x: Foo) -> Box Foo> { - return Box::new(move || x); -} - -fn function_containing_closure(x: T) -> impl FnOnce() -> T { - // This static only exists to trigger generating the namespace debuginfo for - // `function_containing_closure` at a predictable, early point, which makes - // writing the FileCheck tests above simpler. - static _X: u8 = 0; - - return move || x; -} - -async fn generic_async_function(x: T) -> T { - static _X: u8 = 0; // Same as above - x -} - -fn generic_async_block(x: T) -> impl Future { - static _X: u8 = 0; // Same as above - async move { x } -} - -pub fn instantiate_generics() { - let _closure_u32 = function_containing_closure(7u32); - let _closure_foo = function_containing_closure(Foo); - - let _async_fn_u32 = generic_async_function(42u32); - let _async_fn_foo = generic_async_function(Foo); - - let _async_block_u32 = generic_async_block(64u32); - let _async_block_foo = generic_async_block(Foo); -} diff --git a/tests/codegen/debuginfo-inline-callsite-location.rs b/tests/codegen/debuginfo-inline-callsite-location.rs deleted file mode 100644 index 59ade52ad32..00000000000 --- a/tests/codegen/debuginfo-inline-callsite-location.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ compile-flags: -g -Copt-level=3 -C panic=abort - -// Check that each inline call site for the same function uses the same "sub-program" so that LLVM -// can correctly merge the debug info if it merges the inlined code (e.g., for merging of tail -// calls to panic. - -// CHECK: tail call void @{{[A-Za-z0-9_]+4core6option13unwrap_failed}} -// CHECK-SAME: !dbg ![[#first_dbg:]] -// CHECK: tail call void @{{[A-Za-z0-9_]+4core6option13unwrap_failed}} -// CHECK-SAME: !dbg ![[#second_dbg:]] - -// CHECK-DAG: ![[#func_scope:]] = distinct !DISubprogram(name: "unwrap" -// CHECK-DAG: ![[#]] = !DILocalVariable(name: "self",{{( arg: 1,)?}} scope: ![[#func_scope]] -// CHECK: ![[#first_dbg]] = !DILocation(line: [[#]] -// CHECK-SAME: scope: ![[#func_scope]], inlinedAt: ![[#]]) -// CHECK: ![[#second_dbg]] = !DILocation(line: [[#]] -// CHECK-SAME: scope: ![[#func_scope]], inlinedAt: ![[#]]) - -#![crate_type = "lib"] - -#[no_mangle] -extern "C" fn add_numbers(x: &Option, y: &Option) -> i32 { - let x1 = x.unwrap(); - let y1 = y.unwrap(); - - x1 + y1 -} diff --git a/tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs b/tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs deleted file mode 100644 index c0691b23275..00000000000 --- a/tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs +++ /dev/null @@ -1,7 +0,0 @@ -extern crate proc_macro; -use proc_macro::*; - -#[proc_macro] -pub fn square_twice(_item: TokenStream) -> TokenStream { - "(square(env::vars().count() as i32), square(env::vars().count() as i32))".parse().unwrap() -} diff --git a/tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs b/tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs deleted file mode 100644 index 7530689d574..00000000000 --- a/tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs +++ /dev/null @@ -1,52 +0,0 @@ -//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Zmir-enable-passes=+Inline -// MSVC is different because of the individual allocas. -//@ ignore-msvc - -//@ proc-macro: macro_def.rs - -// Find the variable. -// CHECK-DAG: ![[#var_dbg:]] = !DILocalVariable(name: "n",{{( arg: 1,)?}} scope: ![[#var_scope:]] - -// Find both dbg_declares. These will proceed the variable metadata, of course, so we're looking -// backwards. -// CHECK-DAG: dbg_declare(ptr %n.dbg.spill{{[0-9]}}, ![[#var_dbg]], !DIExpression(), ![[#var_loc2:]]) -// CHECK-DAG: dbg_declare(ptr %n.dbg.spill, ![[#var_dbg]], !DIExpression(), ![[#var_loc1:]]) - -// Find the first location definition, looking forwards again. -// CHECK: ![[#var_loc1]] = !DILocation -// CHECK-SAME: scope: ![[#var_scope:]], inlinedAt: ![[#var_inlinedAt1:]] - -// Find the first location's inlinedAt -// NB: If we fail here it's *probably* because we failed to produce two -// different locations and ended up reusing an earlier one. -// CHECK: ![[#var_inlinedAt1]] = !DILocation -// CHECK-SAME: scope: ![[var_inlinedAt1_scope:]] - -// Find the second location definition, still looking forwards. -// NB: If we failed to produce two different locations, the test will -// definitely fail by this point (if it hasn't already) because we won't -// be able to find the same line again. -// CHECK: ![[#var_loc2]] = !DILocation -// CHECK-SAME: scope: ![[#var_scope]], inlinedAt: ![[#var_inlinedAt2:]] - -// Find the second location's inlinedAt. -// CHECK: ![[#var_inlinedAt2]] = !DILocation -// CHECK-SAME: scope: ![[#var_inlinedAt2_scope:]] - -// Finally, check that a discriminator was emitted for the second scope. -// FIXMEkhuey ideally we would check that *either* scope has a discriminator -// but I don't know that it's possible to check that with FileCheck. -// CHECK: ![[#var_inlinedAt2_scope]] = !DILexicalBlockFile -// CHECK-SAME: discriminator: [[#]] -extern crate macro_def; - -use std::env; - -fn square(n: i32) -> i32 { - n * n -} - -fn main() { - let (z1, z2) = macro_def::square_twice!(); - println!("{z1} == {z2}"); -} diff --git a/tests/codegen/deduced-param-attrs.rs b/tests/codegen/deduced-param-attrs.rs deleted file mode 100644 index 34504c80fad..00000000000 --- a/tests/codegen/deduced-param-attrs.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] -#![allow(internal_features)] -#![feature(unsized_fn_params)] - -use std::cell::Cell; -use std::hint; - -// Check to make sure that we can deduce the `readonly` attribute from function bodies for -// parameters passed indirectly. - -pub struct BigStruct { - blah: [i32; 1024], -} - -pub struct BigCellContainer { - blah: [Cell; 1024], -} - -// The by-value parameter for this big struct can be marked readonly. -// -// CHECK: @use_big_struct_immutably({{.*}} readonly {{.*}} %big_struct) -#[no_mangle] -pub fn use_big_struct_immutably(big_struct: BigStruct) { - hint::black_box(&big_struct); -} - -// The by-value parameter for this big struct can't be marked readonly, because we mutate it. -// -// CHECK-NOT: @use_big_struct_mutably({{.*}} readonly {{.*}} %big_struct) -#[no_mangle] -pub fn use_big_struct_mutably(mut big_struct: BigStruct) { - big_struct.blah[987] = 654; - hint::black_box(&big_struct); -} - -// The by-value parameter for this big struct can't be marked readonly, because it contains -// UnsafeCell. -// -// CHECK-NOT: @use_big_cell_container({{.*}} readonly {{.*}} %big_cell_container) -#[no_mangle] -pub fn use_big_cell_container(big_cell_container: BigCellContainer) { - hint::black_box(&big_cell_container); -} - -// Make sure that we don't mistakenly mark a big struct as `readonly` when passed through a generic -// type parameter if it contains UnsafeCell. -// -// CHECK-NOT: @use_something({{.*}} readonly {{.*}} %something) -#[no_mangle] -#[inline(never)] -pub fn use_something(something: T) { - hint::black_box(&something); -} - -#[no_mangle] -pub fn forward_big_cell_container(big_cell_container: BigCellContainer) { - use_something(big_cell_container) -} diff --git a/tests/codegen/default-requires-uwtable.rs b/tests/codegen/default-requires-uwtable.rs deleted file mode 100644 index 54a6e171db6..00000000000 --- a/tests/codegen/default-requires-uwtable.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ add-core-stubs -//@ revisions: WINDOWS_ ANDROID_ -//@ compile-flags: -C panic=abort -Copt-level=0 -//@ [WINDOWS_] compile-flags: --target=x86_64-pc-windows-msvc -//@ [WINDOWS_] needs-llvm-components: x86 -//@ [ANDROID_] compile-flags: --target=armv7-linux-androideabi -//@ [ANDROID_] needs-llvm-components: arm - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK: attributes #{{.*}} uwtable -pub fn foo() {} diff --git a/tests/codegen/default-visibility.rs b/tests/codegen/default-visibility.rs deleted file mode 100644 index 88ff9fee254..00000000000 --- a/tests/codegen/default-visibility.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Verifies that `Session::default_visibility` is affected when using the related cmdline -// flag. This is a regression test for https://github.com/rust-lang/compiler-team/issues/782. See -// also https://github.com/rust-lang/rust/issues/73295 and -// https://github.com/rust-lang/rust/issues/37530. - -//@ revisions:DEFAULT HIDDEN PROTECTED INTERPOSABLE -//@[HIDDEN] compile-flags: -Zdefault-visibility=hidden -//@[PROTECTED] compile-flags: -Zdefault-visibility=protected -//@[INTERPOSABLE] compile-flags: -Zdefault-visibility=interposable - -// The test scenario is specifically about visibility of symbols exported out of dynamically linked -// libraries. -#![crate_type = "dylib"] - -// The test scenario needs to use a Rust-public, but non-explicitly-exported symbol -// (e.g. the test doesn't use `#[no_mangle]`, because currently it implies that -// the symbol should be exported; we don't want that - we want to test the *default* -// export setting instead). -#[used] -pub static tested_symbol: [u8; 6] = *b"foobar"; - -// Exact LLVM IR differs depending on the target triple (e.g. `hidden constant` -// vs `internal constant` vs `constant`). Because of this, we only apply the -// specific test expectations below to one specific target triple. If needed, -// additional targets can be covered by adding copies of this test file with -// a different `only-X` directive. -// -//@ only-x86_64-unknown-linux-gnu - -// HIDDEN: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = hidden constant -// PROTECTED: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = protected constant -// INTERPOSABLE: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant -// DEFAULT: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant - -pub fn do_memcmp(left: &[u8], right: &[u8]) -> i32 { - left.cmp(right) as i32 -} - -// CHECK: define {{.*}} @{{.*}}do_memcmp{{.*}} { -// CHECK: } - -// `do_memcmp` should invoke core::intrinsic::compare_bytes which emits a call -// to the C symbol `memcmp` (at least on x86_64-unknown-linux-gnu). This symbol -// should *not* be declared hidden or protected. - -// HIDDEN: declare i32 @memcmp -// PROTECTED: declare i32 @memcmp -// INTERPOSABLE: declare i32 @memcmp -// DEFAULT: declare i32 @memcmp diff --git a/tests/codegen/direct-access-external-data.rs b/tests/codegen/direct-access-external-data.rs deleted file mode 100644 index 5b2ff41ef05..00000000000 --- a/tests/codegen/direct-access-external-data.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ only-loongarch64-unknown-linux-gnu - -//@ revisions: DEFAULT DIRECT INDIRECT -//@ [DEFAULT] compile-flags: -C relocation-model=static -//@ [DIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=yes -//@ [INDIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=no - -#![crate_type = "rlib"] - -// DEFAULT: @VAR = external {{.*}} global i32 -// DIRECT: @VAR = external dso_local {{.*}} global i32 -// INDIRECT: @VAR = external {{.*}} global i32 - -extern "C" { - static VAR: i32; -} - -#[no_mangle] -pub fn get() -> i32 { - unsafe { VAR } -} diff --git a/tests/codegen/dllimports/auxiliary/dummy.rs b/tests/codegen/dllimports/auxiliary/dummy.rs deleted file mode 100644 index ab3dbc6a300..00000000000 --- a/tests/codegen/dllimports/auxiliary/dummy.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ no-prefer-dynamic -#![crate_type = "staticlib"] - -// Since codegen tests don't actually perform linking, this library doesn't need to export -// any symbols. It's here just to satisfy the compiler looking for a .lib file when processing -// #[link(...)] attributes in wrapper.rs. diff --git a/tests/codegen/dllimports/auxiliary/wrapper.rs b/tests/codegen/dllimports/auxiliary/wrapper.rs deleted file mode 100644 index 00a29f7ee7e..00000000000 --- a/tests/codegen/dllimports/auxiliary/wrapper.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ no-prefer-dynamic -#![crate_type = "rlib"] - -#[link(name = "dummy", kind = "dylib")] -extern "C" { - pub fn dylib_func2(x: i32) -> i32; - pub static dylib_global2: i32; -} - -#[link(name = "dummy", kind = "static")] -extern "C" { - pub fn static_func2(x: i32) -> i32; - pub static static_global2: i32; -} diff --git a/tests/codegen/dllimports/main.rs b/tests/codegen/dllimports/main.rs deleted file mode 100644 index 93d350a2238..00000000000 --- a/tests/codegen/dllimports/main.rs +++ /dev/null @@ -1,43 +0,0 @@ -// This test is for *-windows-msvc only. -//@ only-windows -//@ ignore-gnu - -//@ aux-build:dummy.rs -//@ aux-build:wrapper.rs - -extern crate wrapper; - -// Check that external symbols coming from foreign dylibs are adorned with 'dllimport', -// whereas symbols coming from foreign staticlibs are not. (RFC-1717) - -// CHECK: @dylib_global1 = external dllimport local_unnamed_addr global i32 -// CHECK: @dylib_global2 = external dllimport local_unnamed_addr global i32 -// CHECK: @static_global1 = external local_unnamed_addr global i32 -// CHECK: @static_global2 = external local_unnamed_addr global i32 - -// CHECK: declare dllimport noundef i32 @dylib_func1(i32 noundef) -// CHECK: declare dllimport noundef i32 @dylib_func2(i32 noundef) -// CHECK: declare noundef i32 @static_func1(i32 noundef) -// CHECK: declare noundef i32 @static_func2(i32 noundef) - -#[link(name = "dummy", kind = "dylib")] -extern "C" { - pub fn dylib_func1(x: i32) -> i32; - pub static dylib_global1: i32; -} - -#[link(name = "dummy", kind = "static")] -extern "C" { - pub fn static_func1(x: i32) -> i32; - pub static static_global1: i32; -} - -fn main() { - unsafe { - dylib_func1(dylib_global1); - wrapper::dylib_func2(wrapper::dylib_global2); - - static_func1(static_global1); - wrapper::static_func2(wrapper::static_global2); - } -} diff --git a/tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs b/tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs deleted file mode 100644 index df50b4af809..00000000000 --- a/tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! This test checks that we do not monomorphize functions that are only -//! used to evaluate static items, but never used in runtime code. - -//@compile-flags: --crate-type=lib -Copt-level=0 - -#![feature(generic_const_items)] - -const fn foo() {} - -pub static FOO: () = foo(); - -// CHECK-NOT: define{{.*}}foo{{.*}} - -const fn bar() {} - -pub const BAR: () = bar(); - -// CHECK-NOT: define{{.*}}bar{{.*}} - -const fn baz() {} - -#[rustfmt::skip] -pub const BAZ: () = if C { - baz() -}; - -// CHECK: define{{.*}}baz{{.*}} diff --git a/tests/codegen/drop-in-place-noalias.rs b/tests/codegen/drop-in-place-noalias.rs deleted file mode 100644 index bff2f52781f..00000000000 --- a/tests/codegen/drop-in-place-noalias.rs +++ /dev/null @@ -1,38 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes - -// Tests that the compiler can apply `noalias` and other &mut attributes to `drop_in_place`. -// Note that non-Unpin types should not get `noalias`, matching &mut behavior. - -#![crate_type = "lib"] - -use std::marker::PhantomPinned; - -// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructUnpin{{.*}}(ptr noalias noundef align 4 dereferenceable(12) %{{.+}}) - -// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructNotUnpin{{.*}}(ptr noundef nonnull align 4 %{{.+}}) - -pub struct StructUnpin { - a: i32, - b: i32, - c: i32, -} - -impl Drop for StructUnpin { - fn drop(&mut self) {} -} - -pub struct StructNotUnpin { - a: i32, - b: i32, - c: i32, - p: PhantomPinned, -} - -impl Drop for StructNotUnpin { - fn drop(&mut self) {} -} - -pub unsafe fn main(x: StructUnpin, y: StructNotUnpin) { - drop(x); - drop(y); -} diff --git a/tests/codegen/drop.rs b/tests/codegen/drop.rs deleted file mode 100644 index b22a8ef27d2..00000000000 --- a/tests/codegen/drop.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ needs-unwind - this test verifies the amount of drop calls when unwinding is used -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] - -struct SomeUniqueName; - -impl Drop for SomeUniqueName { - #[inline(never)] - fn drop(&mut self) {} -} - -#[inline(never)] -pub fn possibly_unwinding() {} - -// CHECK-LABEL: @droppy -#[no_mangle] -pub fn droppy() { - // Check that there are exactly 6 drop calls. The cleanups for the unwinding should be reused, - // so that's one new drop call per call to possibly_unwinding(), and finally 3 drop calls for - // the regular function exit. We used to have problems with quadratic growths of drop calls in - // such functions. - // FIXME(eddyb) the `void @` forces a match on the instruction, instead of the - // comment, that's `; call core::ptr::drop_in_place::` - // for the `v0` mangling, should switch to matching on that once `legacy` is gone. - // CHECK-COUNT-6: {{(call|invoke) void @.*}}drop_in_place{{.*}}SomeUniqueName - // CHECK-NOT: {{(call|invoke) void @.*}}drop_in_place{{.*}}SomeUniqueName - // The next line checks for the } that ends the function definition - // CHECK-LABEL: {{^[}]}} - let _s = SomeUniqueName; - possibly_unwinding(); - let _s = SomeUniqueName; - possibly_unwinding(); - let _s = SomeUniqueName; - possibly_unwinding(); -} diff --git a/tests/codegen/dst-offset.rs b/tests/codegen/dst-offset.rs deleted file mode 100644 index 2cf5fa9fac6..00000000000 --- a/tests/codegen/dst-offset.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! This file tests that we correctly generate GEP instructions for DST -//! field offsets. -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 - -#![crate_type = "lib"] -#![feature(extern_types, sized_hierarchy)] - -use std::marker::PointeeSized; -use std::ptr::addr_of; - -// Hack to get the correct type for usize -// CHECK: @helper([[USIZE:i[0-9]+]] %_1) -#[no_mangle] -pub fn helper(_: usize) {} - -struct Dst { - x: u32, - y: u8, - z: T, -} - -// CHECK: @dst_dyn_trait_offset(ptr align {{[0-9]+}} [[DATA_PTR:%.+]], ptr align {{[0-9]+}} [[VTABLE_PTR:%.+]]) -#[no_mangle] -pub fn dst_dyn_trait_offset(s: &Dst) -> &dyn Drop { - // The alignment of dyn trait is unknown, so we compute the offset based on align from the - // vtable. - - // CHECK: [[SIZE_PTR:%[0-9]+]] = getelementptr inbounds i8, ptr [[VTABLE_PTR]] - // CHECK: load [[USIZE]], ptr [[SIZE_PTR]] - // CHECK: [[ALIGN_PTR:%[0-9]+]] = getelementptr inbounds i8, ptr [[VTABLE_PTR]] - // CHECK: load [[USIZE]], ptr [[ALIGN_PTR]] - - // CHECK: getelementptr inbounds i8, ptr [[DATA_PTR]] - // CHECK-NEXT: insertvalue - // CHECK-NEXT: insertvalue - // CHECK-NEXT: ret - &s.z -} - -// CHECK-LABEL: @dst_slice_offset -#[no_mangle] -pub fn dst_slice_offset(s: &Dst<[u16]>) -> &[u16] { - // The alignment of [u16] is known, so we generate a GEP directly. - - // CHECK: start: - // CHECK-NEXT: getelementptr inbounds i8, {{.+}}, [[USIZE]] 6 - // CHECK-NEXT: insertvalue - // CHECK-NEXT: insertvalue - // CHECK-NEXT: ret - &s.z -} - -#[repr(packed)] -struct PackedDstSlice { - x: u32, - y: u8, - z: [u16], -} - -// CHECK-LABEL: @packed_dst_slice_offset -#[no_mangle] -pub fn packed_dst_slice_offset(s: &PackedDstSlice) -> *const [u16] { - // The alignment of [u16] is known, so we generate a GEP directly. - - // CHECK: start: - // CHECK-NEXT: getelementptr inbounds i8, {{.+}}, [[USIZE]] 5 - // CHECK-NEXT: insertvalue - // CHECK-NEXT: insertvalue - // CHECK-NEXT: ret - addr_of!(s.z) -} - -extern "C" { - pub type Extern; -} - -// CHECK-LABEL: @dst_extern -#[no_mangle] -pub fn dst_extern(s: &Dst) -> &Extern { - // Computing the alignment of an extern type is currently unsupported and just panics. - - // CHECK: call void @{{.+}}panic - &s.z -} diff --git a/tests/codegen/dst-vtable-align-nonzero.rs b/tests/codegen/dst-vtable-align-nonzero.rs deleted file mode 100644 index 1404bd64f50..00000000000 --- a/tests/codegen/dst-vtable-align-nonzero.rs +++ /dev/null @@ -1,67 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -// This test checks that we annotate alignment loads from vtables with nonzero range metadata, -// and that this allows LLVM to eliminate redundant `align >= 1` checks. - -pub trait Trait { - fn f(&self); -} - -pub struct WrapperWithAlign1 { - x: u8, - y: T, -} - -pub struct WrapperWithAlign2 { - x: u16, - y: T, -} - -pub struct Struct { - _field: i8, - dst: W, -} - -// CHECK-LABEL: @eliminates_runtime_check_when_align_1 -#[no_mangle] -pub fn eliminates_runtime_check_when_align_1( - x: &Struct>, -) -> &WrapperWithAlign1 { - // CHECK: load [[USIZE:i[0-9]+]], {{.+}} !range [[RANGE_META:![0-9]+]] - // CHECK-NOT: llvm.umax - // CHECK-NOT: icmp - // CHECK-NOT: select - // CHECK: ret - &x.dst -} - -// CHECK-LABEL: @does_not_eliminate_runtime_check_when_align_2 -#[no_mangle] -pub fn does_not_eliminate_runtime_check_when_align_2( - x: &Struct>, -) -> &WrapperWithAlign2 { - // CHECK: [[X0:%[0-9]+]] = load [[USIZE]], {{.+}} !range [[RANGE_META]] - // CHECK: {{icmp|llvm.umax}} - // CHECK: ret - &x.dst -} - -// CHECK-LABEL: @align_load_from_align_of_val -#[no_mangle] -pub fn align_load_from_align_of_val(x: &dyn Trait) -> usize { - // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]] - core::mem::align_of_val(x) -} - -// CHECK-LABEL: @align_load_from_vtable_align_intrinsic -#[no_mangle] -pub unsafe fn align_load_from_vtable_align_intrinsic(x: &dyn Trait) -> usize { - let (data, vtable): (*const (), *const ()) = core::mem::transmute(x); - // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]] - core::intrinsics::vtable_align(vtable) -} - -// CHECK: [[RANGE_META]] = !{[[USIZE]] 1, [[USIZE]] 0} diff --git a/tests/codegen/dst-vtable-size-range.rs b/tests/codegen/dst-vtable-size-range.rs deleted file mode 100644 index 670f5e8d553..00000000000 --- a/tests/codegen/dst-vtable-size-range.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -// Check that we annotate size loads from vtables with 0..(isize::MAX + 1) range metadata. - -pub trait Trait { - fn f(&self); -} - -// Note that rustc uses inclusive bounds, but LLVM uses exclusive bounds for range metadata. -// CHECK-LABEL: @generate_exclusive_bound -#[no_mangle] -pub fn generate_exclusive_bound() -> usize { - // CHECK: ret [[USIZE:i[0-9]+]] [[EXCLUSIVE_BOUND:[-0-9]+]] - isize::MAX as usize + 1 -} - -// CHECK-LABEL: @size_load_from_size_of_val -#[no_mangle] -pub fn size_load_from_size_of_val(x: &dyn Trait) -> usize { - // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META:![0-9]+]] - core::mem::size_of_val(x) -} - -// CHECK-LABEL: @size_load_from_vtable_size_intrinsic -#[no_mangle] -pub unsafe fn size_load_from_vtable_size_intrinsic(x: &dyn Trait) -> usize { - let (data, vtable): (*const (), *const ()) = core::mem::transmute(x); - // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]] - core::intrinsics::vtable_size(vtable) -} - -// CHECK: [[RANGE_META]] = !{[[USIZE]] 0, [[USIZE]] [[EXCLUSIVE_BOUND]]} diff --git a/tests/codegen/ehcontguard_disabled.rs b/tests/codegen/ehcontguard_disabled.rs deleted file mode 100644 index 9efb2721b3e..00000000000 --- a/tests/codegen/ehcontguard_disabled.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ compile-flags: - -#![crate_type = "lib"] - -// A basic test function. -pub fn test() {} - -// Ensure the module flag ehcontguard is not present -// CHECK-NOT: !"ehcontguard" diff --git a/tests/codegen/ehcontguard_enabled.rs b/tests/codegen/ehcontguard_enabled.rs deleted file mode 100644 index ecc5512fd5d..00000000000 --- a/tests/codegen/ehcontguard_enabled.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ compile-flags: -Z ehcont-guard - -#![crate_type = "lib"] - -// A basic test function. -pub fn test() {} - -// Ensure the module flag ehcontguard=1 is present -// CHECK: !"ehcontguard", i32 1 diff --git a/tests/codegen/emscripten-catch-unwind-js-eh.rs b/tests/codegen/emscripten-catch-unwind-js-eh.rs deleted file mode 100644 index f43869cf218..00000000000 --- a/tests/codegen/emscripten-catch-unwind-js-eh.rs +++ /dev/null @@ -1,71 +0,0 @@ -//@ compile-flags: -Copt-level=3 --target wasm32-unknown-emscripten -//@ needs-llvm-components: webassembly - -// Emscripten has its own unique implementation of catch_unwind (in `codegen_emcc_try`), -// make sure it generates something reasonable. - -#![feature(no_core, lang_items, intrinsics, rustc_attrs)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} -#[lang = "freeze"] -trait Freeze {} -#[lang = "copy"] -trait Copy {} - -impl Copy for *mut T {} - -#[rustc_intrinsic] -fn size_of() -> usize { - loop {} -} - -#[rustc_intrinsic] -unsafe fn catch_unwind( - try_fn: fn(_: *mut u8), - data: *mut u8, - catch_fn: fn(_: *mut u8, _: *mut u8), -) -> i32; - -// CHECK-LABEL: @ptr_size -#[no_mangle] -pub fn ptr_size() -> usize { - // CHECK: ret [[PTR_SIZE:.*]] - size_of::<*mut u8>() -} - -// CHECK-LABEL: @test_catch_unwind -#[no_mangle] -pub unsafe fn test_catch_unwind( - try_fn: fn(_: *mut u8), - data: *mut u8, - catch_fn: fn(_: *mut u8, _: *mut u8), -) -> i32 { - // CHECK: start: - // CHECK: [[ALLOCA:%.*]] = alloca - - // CHECK: catch.i: - // CHECK: [[LANDINGPAD:%.*]] = landingpad - // CHECK: [[EXCEPTION:%.*]] = extractvalue {{.*}} [[LANDINGPAD]], 0 - // CHECK: [[SELECTOR:%.*]] = extractvalue {{.*}} [[LANDINGPAD]], 1 - - // CHECK: [[IS_RUST_EXN:%.*]] = icmp eq {{.*}}[[SELECTOR]] - // CHECK: [[IS_RUST_EXN_I8:%.*]] = zext i1 [[IS_RUST_EXN]] to i8 - - // CHECK: store ptr [[EXCEPTION]], ptr [[ALLOCA]] - // CHECK: [[IS_RUST_SLOT:%.*]] = getelementptr inbounds{{( nuw)?}} i8, ptr [[ALLOCA]], [[PTR_SIZE]] - // CHECK: store i8 [[IS_RUST_EXN_I8]], ptr [[IS_RUST_SLOT]] - - // CHECK: call void %catch_fn(ptr %data, ptr nonnull [[ALLOCA]]) - - catch_unwind(try_fn, data, catch_fn) -} diff --git a/tests/codegen/emscripten-catch-unwind-wasm-eh.rs b/tests/codegen/emscripten-catch-unwind-wasm-eh.rs deleted file mode 100644 index b0750d52268..00000000000 --- a/tests/codegen/emscripten-catch-unwind-wasm-eh.rs +++ /dev/null @@ -1,69 +0,0 @@ -//@ compile-flags: -Copt-level=3 --target wasm32-unknown-emscripten -Z emscripten-wasm-eh -//@ needs-llvm-components: webassembly - -// Emscripten catch_unwind using wasm exceptions - -#![feature(no_core, lang_items, intrinsics, rustc_attrs)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} -#[lang = "freeze"] -trait Freeze {} -#[lang = "copy"] -trait Copy {} - -impl Copy for *mut T {} - -#[rustc_intrinsic] -fn size_of() -> usize { - loop {} -} -#[rustc_intrinsic] -unsafe fn catch_unwind( - try_fn: fn(_: *mut u8), - data: *mut u8, - catch_fn: fn(_: *mut u8, _: *mut u8), -) -> i32; - -// CHECK-LABEL: @ptr_size -#[no_mangle] -pub fn ptr_size() -> usize { - // CHECK: ret [[PTR_SIZE:.*]] - size_of::<*mut u8>() -} - -// CHECK-LABEL: @test_catch_unwind -#[no_mangle] -pub unsafe fn test_catch_unwind( - try_fn: fn(_: *mut u8), - data: *mut u8, - catch_fn: fn(_: *mut u8, _: *mut u8), -) -> i32 { - // CHECK: start: - // CHECK: invoke void %try_fn(ptr %data) - // CHECK: to label %__rust_try.exit unwind label %catchswitch.i - // CHECK: catchswitch.i: ; preds = %start - // CHECK: %catchswitch1.i = catchswitch within none [label %catchpad.i] unwind to caller - - // CHECK: catchpad.i: ; preds = %catchswitch.i - // CHECK: %catchpad2.i = catchpad within %catchswitch1.i [ptr null] - // CHECK: %0 = tail call ptr @llvm.wasm.get.exception(token %catchpad2.i) - // CHECK: %1 = tail call i32 @llvm.wasm.get.ehselector(token %catchpad2.i) - // CHECK: call void %catch_fn(ptr %data, ptr %0) [ "funclet"(token %catchpad2.i) ] - // CHECK: catchret from %catchpad2.i to label %__rust_try.exit - - // CHECK: __rust_try.exit: ; preds = %start, %catchpad.i - // CHECK: %common.ret.op.i = phi i32 [ 0, %start ], [ 1, %catchpad.i ] - // CHECK: ret i32 %common.ret.op.i - - catch_unwind(try_fn, data, catch_fn) -} diff --git a/tests/codegen/enable-lto-unit-splitting.rs b/tests/codegen/enable-lto-unit-splitting.rs deleted file mode 100644 index 51c2671bc4e..00000000000 --- a/tests/codegen/enable-lto-unit-splitting.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Verifies that "EnableSplitLTOUnit" module flag is added. -// -//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsplit-lto-unit - -#![crate_type = "lib"] - -pub fn foo() {} - -// CHECK: !{{[0-9]+}} = !{i32 4, !"EnableSplitLTOUnit", i32 1} diff --git a/tests/codegen/enum/enum-aggregate.rs b/tests/codegen/enum/enum-aggregate.rs deleted file mode 100644 index 0161e5f3fa1..00000000000 --- a/tests/codegen/enum/enum-aggregate.rs +++ /dev/null @@ -1,126 +0,0 @@ -//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes -//@ min-llvm-version: 19 -//@ only-64bit - -#![crate_type = "lib"] - -use std::cmp::Ordering; -use std::num::NonZero; -use std::ptr::NonNull; - -#[no_mangle] -fn make_some_bool(x: bool) -> Option { - // CHECK-LABEL: i8 @make_some_bool(i1 zeroext %x) - // CHECK-NEXT: start: - // CHECK-NEXT: %[[WIDER:.+]] = zext i1 %x to i8 - // CHECK-NEXT: ret i8 %[[WIDER]] - Some(x) -} - -#[no_mangle] -fn make_none_bool() -> Option { - // CHECK-LABEL: i8 @make_none_bool() - // CHECK-NEXT: start: - // CHECK-NEXT: ret i8 2 - None -} - -#[no_mangle] -fn make_some_ordering(x: Ordering) -> Option { - // CHECK-LABEL: i8 @make_some_ordering(i8 %x) - // CHECK-NEXT: start: - // CHECK-NEXT: ret i8 %x - Some(x) -} - -#[no_mangle] -fn make_some_u16(x: u16) -> Option { - // CHECK-LABEL: { i16, i16 } @make_some_u16(i16 %x) - // CHECK-NEXT: start: - // CHECK-NEXT: %0 = insertvalue { i16, i16 } { i16 1, i16 poison }, i16 %x, 1 - // CHECK-NEXT: ret { i16, i16 } %0 - Some(x) -} - -#[no_mangle] -fn make_none_u16() -> Option { - // CHECK-LABEL: { i16, i16 } @make_none_u16() - // CHECK-NEXT: start: - // CHECK-NEXT: ret { i16, i16 } { i16 0, i16 undef } - None -} - -#[no_mangle] -fn make_some_nzu32(x: NonZero) -> Option> { - // CHECK-LABEL: i32 @make_some_nzu32(i32 %x) - // CHECK-NEXT: start: - // CHECK-NEXT: ret i32 %x - Some(x) -} - -#[no_mangle] -fn make_ok_ptr(x: NonNull) -> Result, usize> { - // CHECK-LABEL: { i64, ptr } @make_ok_ptr(ptr %x) - // CHECK-NEXT: start: - // CHECK-NEXT: %0 = insertvalue { i64, ptr } { i64 0, ptr poison }, ptr %x, 1 - // CHECK-NEXT: ret { i64, ptr } %0 - Ok(x) -} - -#[no_mangle] -fn make_ok_int(x: usize) -> Result> { - // CHECK-LABEL: { i64, ptr } @make_ok_int(i64 %x) - // CHECK-NEXT: start: - // CHECK-NEXT: %[[NOPROV:.+]] = getelementptr i8, ptr null, i64 %x - // CHECK-NEXT: %[[R:.+]] = insertvalue { i64, ptr } { i64 0, ptr poison }, ptr %[[NOPROV]], 1 - // CHECK-NEXT: ret { i64, ptr } %[[R]] - Ok(x) -} - -#[no_mangle] -fn make_some_ref(x: &u16) -> Option<&u16> { - // CHECK-LABEL: ptr @make_some_ref(ptr align 2 %x) - // CHECK-NEXT: start: - // CHECK-NEXT: ret ptr %x - Some(x) -} - -#[no_mangle] -fn make_none_ref<'a>() -> Option<&'a u16> { - // CHECK-LABEL: ptr @make_none_ref() - // CHECK-NEXT: start: - // CHECK-NEXT: ret ptr null - None -} - -#[inline(never)] -fn make_err_generic(e: E) -> Result { - // CHECK-LABEL: define{{.+}}make_err_generic - // CHECK-NEXT: start: - // CHECK-NEXT: call void @llvm.trap() - // CHECK-NEXT: ret i32 poison - Err(e) -} - -#[no_mangle] -fn make_uninhabited_err_indirectly(n: Never) -> Result { - // CHECK-LABEL: i32 @make_uninhabited_err_indirectly() - // CHECK-NEXT: start: - // CHECK-NEXT: call{{.+}}make_err_generic - make_err_generic(n) -} - -#[no_mangle] -fn make_fully_uninhabited_result(v: u32, n: Never) -> Result<(u32, Never), (Never, u32)> { - // Actually reaching this would be UB, so we don't actually build a result. - - // CHECK-LABEL: { i32, i32 } @make_fully_uninhabited_result(i32 %v) - // CHECK-NEXT: start: - // CHECK-NEXT: call void @llvm.trap() - // CHECK-NEXT: call void @llvm.trap() - // CHECK-NEXT: call void @llvm.trap() - // CHECK-NEXT: unreachable - Ok((v, n)) -} - -enum Never {} diff --git a/tests/codegen/enum/enum-bounds-check-derived-idx.rs b/tests/codegen/enum/enum-bounds-check-derived-idx.rs deleted file mode 100644 index a5785f4addf..00000000000 --- a/tests/codegen/enum/enum-bounds-check-derived-idx.rs +++ /dev/null @@ -1,24 +0,0 @@ -// This test checks an optimization that is not guaranteed to work. This test case should not block -// a future LLVM update. -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -pub enum Bar { - A = 1, - B = 3, -} - -// CHECK-LABEL: @lookup_inc -#[no_mangle] -pub fn lookup_inc(buf: &[u8; 5], f: Bar) -> u8 { - // CHECK-NOT: panic_bounds_check - buf[f as usize + 1] -} - -// CHECK-LABEL: @lookup_dec -#[no_mangle] -pub fn lookup_dec(buf: &[u8; 5], f: Bar) -> u8 { - // CHECK-NOT: panic_bounds_check - buf[f as usize - 1] -} diff --git a/tests/codegen/enum/enum-bounds-check-issue-13926.rs b/tests/codegen/enum/enum-bounds-check-issue-13926.rs deleted file mode 100644 index 6e8e5035b0d..00000000000 --- a/tests/codegen/enum/enum-bounds-check-issue-13926.rs +++ /dev/null @@ -1,18 +0,0 @@ -// This test checks an optimization that is not guaranteed to work. This test case should not block -// a future LLVM update. -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -#[repr(u8)] -pub enum Exception { - Low = 5, - High = 10, -} - -// CHECK-LABEL: @access -#[no_mangle] -pub fn access(array: &[usize; 12], exc: Exception) -> usize { - // CHECK-NOT: panic_bounds_check - array[(exc as u8 - 4) as usize] -} diff --git a/tests/codegen/enum/enum-bounds-check-issue-82871.rs b/tests/codegen/enum/enum-bounds-check-issue-82871.rs deleted file mode 100644 index 3b8a146838a..00000000000 --- a/tests/codegen/enum/enum-bounds-check-issue-82871.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ compile-flags: -C opt-level=0 - -#![crate_type = "lib"] - -#[repr(C)] -pub enum E { - A, -} - -// CHECK-LABEL: @index -#[no_mangle] -pub fn index(x: &[u32; 3], ind: E) -> u32 { - // Canary: we should be able to optimize out the bounds check, but we need - // to track the range of the discriminant result in order to be able to do that. - // oli-obk tried to add that, but that caused miscompilations all over the place. - // CHECK: panic_bounds_check - x[ind as usize] -} diff --git a/tests/codegen/enum/enum-bounds-check.rs b/tests/codegen/enum/enum-bounds-check.rs deleted file mode 100644 index 5362598ca7c..00000000000 --- a/tests/codegen/enum/enum-bounds-check.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -pub enum Foo { - A, - B, -} - -// CHECK-LABEL: @lookup -#[no_mangle] -pub fn lookup(buf: &[u8; 2], f: Foo) -> u8 { - // CHECK-NOT: panic_bounds_check - buf[f as usize] -} - -pub enum Bar { - A = 2, - B = 3, -} - -// CHECK-LABEL: @lookup_unmodified -#[no_mangle] -pub fn lookup_unmodified(buf: &[u8; 5], f: Bar) -> u8 { - // CHECK-NOT: panic_bounds_check - buf[f as usize] -} diff --git a/tests/codegen/enum/enum-debug-clike.rs b/tests/codegen/enum/enum-debug-clike.rs deleted file mode 100644 index 89c803cce5e..00000000000 --- a/tests/codegen/enum/enum-debug-clike.rs +++ /dev/null @@ -1,28 +0,0 @@ -// This tests that debug info for "c-like" enums is properly emitted. -// This is ignored for the fallback mode on MSVC due to problems with PDB. - -// -//@ ignore-msvc -//@ ignore-wasi wasi codegens the main symbol differently - -//@ compile-flags: -g -C no-prepopulate-passes - -// CHECK-LABEL: @main -// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_enumeration_type,{{.*}}name: "E",{{.*}}flags: DIFlagEnumClass,{{.*}} -// CHECK: {{.*}}DIEnumerator{{.*}}name: "A",{{.*}}value: {{[0-9].*}} -// CHECK: {{.*}}DIEnumerator{{.*}}name: "B",{{.*}}value: {{[0-9].*}} -// CHECK: {{.*}}DIEnumerator{{.*}}name: "C",{{.*}}value: {{[0-9].*}} - -#![allow(dead_code)] -#![allow(unused_variables)] -#![allow(unused_assignments)] - -enum E { - A, - B, - C, -} - -pub fn main() { - let e = E::C; -} diff --git a/tests/codegen/enum/enum-debug-niche-2.rs b/tests/codegen/enum/enum-debug-niche-2.rs deleted file mode 100644 index 80a4081f15b..00000000000 --- a/tests/codegen/enum/enum-debug-niche-2.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! This tests that optimized enum debug info accurately reflects the enum layout. -//! This is ignored for the fallback mode on MSVC due to problems with PDB. -//! -//@ compile-flags: -g -C no-prepopulate-passes -//@ ignore-msvc -// -// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}size: 32,{{.*}} -// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Placeholder",{{.*}}extraData: i32 -1{{[,)].*}} -// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Error",{{.*}}extraData: i32 0{{[,)].*}} -#![feature(never_type)] - -#[derive(Copy, Clone)] -pub struct Entity { - private: std::num::NonZero, -} - -#[derive(Copy, Clone, PartialEq, Eq)] -pub struct Declaration; - -impl TypeFamily for Declaration { - type Base = Base; - type Placeholder = !; - - fn intern_base_data(_: BaseKind) {} -} - -#[derive(Copy, Clone)] -pub struct Base; - -pub trait TypeFamily: Copy + 'static { - type Base: Copy; - type Placeholder: Copy; - - fn intern_base_data(_: BaseKind); -} - -#[derive(Copy, Clone)] -pub enum BaseKind { - Named(Entity), - Placeholder(F::Placeholder), - Error, -} - -pub fn main() { - let x = BaseKind::Error::; - let y = 7; -} diff --git a/tests/codegen/enum/enum-debug-niche.rs b/tests/codegen/enum/enum-debug-niche.rs deleted file mode 100644 index 59e8b8a78b4..00000000000 --- a/tests/codegen/enum/enum-debug-niche.rs +++ /dev/null @@ -1,35 +0,0 @@ -// This tests that optimized enum debug info accurately reflects the enum layout. -// This is ignored for the fallback mode on MSVC due to problems with PDB. - -//@ ignore-msvc -//@ ignore-wasi wasi codegens the main symbol differently - -//@ compile-flags: -g -C no-prepopulate-passes - -// CHECK-LABEL: @main -// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}discriminator:{{.*}} -// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "A",{{.*}}extraData:{{.*}} -// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "A",{{.*}} -// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "B",{{.*}}extraData:{{.*}} -// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "B",{{.*}} -// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "C",{{.*}}extraData:{{.*}} -// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "C",{{.*}} -// CHECK-NOT: {{.*}}DIDerivedType{{.*}}name: "D",{{.*}}extraData:{{.*}} -// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "D",{{.*}} -// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "D",{{.*}} -// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}flags: DIFlagArtificial{{.*}} - -#![allow(dead_code)] -#![allow(unused_variables)] -#![allow(unused_assignments)] - -enum E { - A, - B, - C, - D(bool), -} - -pub fn main() { - let e = E::D(true); -} diff --git a/tests/codegen/enum/enum-debug-tagged.rs b/tests/codegen/enum/enum-debug-tagged.rs deleted file mode 100644 index e8f147665b0..00000000000 --- a/tests/codegen/enum/enum-debug-tagged.rs +++ /dev/null @@ -1,31 +0,0 @@ -// This tests that debug info for tagged (ordinary) enums is properly emitted. -// This is ignored for the fallback mode on MSVC due to problems with PDB. - -//@ ignore-msvc -//@ ignore-wasi wasi codegens the main symbol differently - -//@ compile-flags: -g -C no-prepopulate-passes - -// CHECK-LABEL: @main -// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "E",{{.*}} -// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}discriminator:{{.*}} -// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "A",{{.*}}extraData:{{.*}} -// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "A",{{.*}} -// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "__0",{{.*}} -// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "B",{{.*}}extraData:{{.*}} -// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "B",{{.*}} -// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "__0",{{.*}} -// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}flags: DIFlagArtificial{{.*}} - -#![allow(dead_code)] -#![allow(unused_variables)] -#![allow(unused_assignments)] - -enum E { - A(u32), - B(u32), -} - -pub fn main() { - let e = E::A(23); -} diff --git a/tests/codegen/enum/enum-discriminant-eq.rs b/tests/codegen/enum/enum-discriminant-eq.rs deleted file mode 100644 index 0494c5f551b..00000000000 --- a/tests/codegen/enum/enum-discriminant-eq.rs +++ /dev/null @@ -1,223 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled -//@ min-llvm-version: 20 -//@ only-64bit - -// The `derive(PartialEq)` on enums with field-less variants compares discriminants, -// so make sure we emit that in some reasonable way. - -#![crate_type = "lib"] -#![feature(ascii_char)] -#![feature(core_intrinsics)] -#![feature(repr128)] - -use std::ascii::Char as AC; -use std::cmp::Ordering; -use std::intrinsics::discriminant_value; -use std::num::NonZero; - -// A type that's bigger than `isize`, unlike the usual cases that have small tags. -#[repr(u128)] -pub enum Giant { - Two = 2, - Three = 3, - Four = 4, -} - -#[unsafe(no_mangle)] -pub fn opt_bool_eq_discr(a: Option, b: Option) -> bool { - // CHECK-LABEL: @opt_bool_eq_discr( - // CHECK: %[[A:.+]] = icmp ne i8 %a, 2 - // CHECK: %[[B:.+]] = icmp eq i8 %b, 2 - // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] - // CHECK: ret i1 %[[R]] - - discriminant_value(&a) == discriminant_value(&b) -} - -#[unsafe(no_mangle)] -pub fn opt_ord_eq_discr(a: Option, b: Option) -> bool { - // CHECK-LABEL: @opt_ord_eq_discr( - // CHECK: %[[A:.+]] = icmp ne i8 %a, 2 - // CHECK: %[[B:.+]] = icmp eq i8 %b, 2 - // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] - // CHECK: ret i1 %[[R]] - - discriminant_value(&a) == discriminant_value(&b) -} - -#[unsafe(no_mangle)] -pub fn opt_nz32_eq_discr(a: Option>, b: Option>) -> bool { - // CHECK-LABEL: @opt_nz32_eq_discr( - // CHECK: %[[A:.+]] = icmp ne i32 %a, 0 - // CHECK: %[[B:.+]] = icmp eq i32 %b, 0 - // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] - // CHECK: ret i1 %[[R]] - - discriminant_value(&a) == discriminant_value(&b) -} - -#[unsafe(no_mangle)] -pub fn opt_ac_eq_discr(a: Option, b: Option) -> bool { - // CHECK-LABEL: @opt_ac_eq_discr( - // CHECK: %[[A:.+]] = icmp ne i8 %a, -128 - // CHECK: %[[B:.+]] = icmp eq i8 %b, -128 - // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] - // CHECK: ret i1 %[[R]] - - discriminant_value(&a) == discriminant_value(&b) -} - -#[unsafe(no_mangle)] -pub fn opt_giant_eq_discr(a: Option, b: Option) -> bool { - // CHECK-LABEL: @opt_giant_eq_discr( - // CHECK: %[[A:.+]] = icmp ne i128 %a, 1 - // CHECK: %[[B:.+]] = icmp eq i128 %b, 1 - // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]] - // CHECK: ret i1 %[[R]] - - discriminant_value(&a) == discriminant_value(&b) -} - -pub enum Mid { - Before, - Thing(T), - After, -} - -#[unsafe(no_mangle)] -pub fn mid_bool_eq_discr(a: Mid, b: Mid) -> bool { - // CHECK-LABEL: @mid_bool_eq_discr( - - // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2 - // CHECK: %[[A_IS_NICHE:.+]] = icmp samesign ugt i8 %a, 1 - // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1 - // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) - // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 - - // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2 - // CHECK: %[[B_IS_NICHE:.+]] = icmp samesign ugt i8 %b, 1 - // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1 - // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) - // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 - - // CHECK: ret i1 %[[R]] - discriminant_value(&a) == discriminant_value(&b) -} - -#[unsafe(no_mangle)] -pub fn mid_ord_eq_discr(a: Mid, b: Mid) -> bool { - // CHECK-LABEL: @mid_ord_eq_discr( - - // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2 - // CHECK: %[[A_IS_NICHE:.+]] = icmp sgt i8 %a, 1 - // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1 - // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) - // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 - - // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2 - // CHECK: %[[B_IS_NICHE:.+]] = icmp sgt i8 %b, 1 - // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1 - // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) - // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 - - // CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]] - // CHECK: ret i1 %[[R]] - discriminant_value(&a) == discriminant_value(&b) -} - -#[unsafe(no_mangle)] -pub fn mid_nz32_eq_discr(a: Mid>, b: Mid>) -> bool { - // CHECK-LABEL: @mid_nz32_eq_discr( - // CHECK: %[[R:.+]] = icmp eq i32 %a.0, %b.0 - // CHECK: ret i1 %[[R]] - discriminant_value(&a) == discriminant_value(&b) -} - -#[unsafe(no_mangle)] -pub fn mid_ac_eq_discr(a: Mid, b: Mid) -> bool { - // CHECK-LABEL: @mid_ac_eq_discr( - - // CHECK: %[[A_REL_DISCR:.+]] = xor i8 %a, -128 - // CHECK: %[[A_IS_NICHE:.+]] = icmp slt i8 %a, 0 - // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %a, -127 - // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) - // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1 - - // CHECK: %[[B_REL_DISCR:.+]] = xor i8 %b, -128 - // CHECK: %[[B_IS_NICHE:.+]] = icmp slt i8 %b, 0 - // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %b, -127 - // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) - // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1 - - // CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]] - // CHECK: ret i1 %[[R]] - discriminant_value(&a) == discriminant_value(&b) -} - -// FIXME: This should be improved once our LLVM fork picks up the fix for -// -#[unsafe(no_mangle)] -pub fn mid_giant_eq_discr(a: Mid, b: Mid) -> bool { - // CHECK-LABEL: @mid_giant_eq_discr( - - // CHECK: %[[A_TRUNC:.+]] = trunc nuw nsw i128 %a to i64 - // CHECK: %[[A_REL_DISCR:.+]] = add nsw i64 %[[A_TRUNC]], -5 - // CHECK: %[[A_IS_NICHE:.+]] = icmp samesign ugt i128 %a, 4 - // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i64 %[[A_REL_DISCR]], 1 - // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]]) - // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i64 %[[A_REL_DISCR]], i64 1 - - // CHECK: %[[B_TRUNC:.+]] = trunc nuw nsw i128 %b to i64 - // CHECK: %[[B_REL_DISCR:.+]] = add nsw i64 %[[B_TRUNC]], -5 - // CHECK: %[[B_IS_NICHE:.+]] = icmp samesign ugt i128 %b, 4 - // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i64 %[[B_REL_DISCR]], 1 - // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]]) - // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i64 %[[B_REL_DISCR]], i64 1 - - // CHECK: %[[R:.+]] = icmp eq i64 %[[A_DISCR]], %[[B_DISCR]] - // CHECK: ret i1 %[[R]] - discriminant_value(&a) == discriminant_value(&b) -} - -// In niche-encoded enums, testing for the untagged variant should optimize to a -// straight-forward comparison looking for the natural range of the payload value. - -#[unsafe(no_mangle)] -pub fn mid_bool_is_thing(a: Mid) -> bool { - // CHECK-LABEL: @mid_bool_is_thing( - // CHECK: %[[R:.+]] = icmp samesign ult i8 %a, 2 - // CHECK: ret i1 %[[R]] - discriminant_value(&a) == 1 -} - -#[unsafe(no_mangle)] -pub fn mid_ord_is_thing(a: Mid) -> bool { - // CHECK-LABEL: @mid_ord_is_thing( - // CHECK: %[[R:.+]] = icmp slt i8 %a, 2 - // CHECK: ret i1 %[[R]] - discriminant_value(&a) == 1 -} - -#[unsafe(no_mangle)] -pub fn mid_nz32_is_thing(a: Mid>) -> bool { - // CHECK-LABEL: @mid_nz32_is_thing( - // CHECK: %[[R:.+]] = icmp eq i32 %a.0, 1 - // CHECK: ret i1 %[[R]] - discriminant_value(&a) == 1 -} - -#[unsafe(no_mangle)] -pub fn mid_ac_is_thing(a: Mid) -> bool { - // CHECK-LABEL: @mid_ac_is_thing( - // CHECK: %[[R:.+]] = icmp sgt i8 %a, -1 - // CHECK: ret i1 %[[R]] - discriminant_value(&a) == 1 -} - -#[unsafe(no_mangle)] -pub fn mid_giant_is_thing(a: Mid) -> bool { - // CHECK-LABEL: @mid_giant_is_thing( - // CHECK: %[[R:.+]] = icmp samesign ult i128 %a, 5 - // CHECK: ret i1 %[[R]] - discriminant_value(&a) == 1 -} diff --git a/tests/codegen/enum/enum-discriminant-value.rs b/tests/codegen/enum/enum-discriminant-value.rs deleted file mode 100644 index d6b0c6d6c10..00000000000 --- a/tests/codegen/enum/enum-discriminant-value.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Verify that DIEnumerator uses isUnsigned flag when appropriate. -// -//@ compile-flags: -g -C no-prepopulate-passes - -#[repr(i64)] -pub enum I64 { - I64Min = i64::MIN, - I64Max = i64::MAX, -} - -#[repr(u64)] -pub enum U64 { - U64Min = u64::MIN, - U64Max = u64::MAX, -} - -fn main() { - let _a = I64::I64Min; - let _b = I64::I64Max; - let _c = U64::U64Min; - let _d = U64::U64Max; -} - -// CHECK: !DIEnumerator(name: "I64Min", value: -9223372036854775808) -// CHECK: !DIEnumerator(name: "I64Max", value: 9223372036854775807) -// CHECK: !DIEnumerator(name: "U64Min", value: 0, isUnsigned: true) -// CHECK: !DIEnumerator(name: "U64Max", value: 18446744073709551615, isUnsigned: true) diff --git a/tests/codegen/enum/enum-early-otherwise-branch.rs b/tests/codegen/enum/enum-early-otherwise-branch.rs deleted file mode 100644 index 8d39d8e9b74..00000000000 --- a/tests/codegen/enum/enum-early-otherwise-branch.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -pub enum Enum { - A(u32), - B(u32), - C(u32), -} - -#[no_mangle] -pub fn foo(lhs: &Enum, rhs: &Enum) -> bool { - // CHECK-LABEL: define{{.*}}i1 @foo( - // CHECK-NOT: switch - // CHECK-NOT: br - // CHECK: [[SELECT:%.*]] = select - // CHECK-NEXT: ret i1 [[SELECT]] - // CHECK-NEXT: } - match (lhs, rhs) { - (Enum::A(lhs), Enum::A(rhs)) => lhs == rhs, - (Enum::B(lhs), Enum::B(rhs)) => lhs == rhs, - (Enum::C(lhs), Enum::C(rhs)) => lhs == rhs, - _ => false, - } -} diff --git a/tests/codegen/enum/enum-match.rs b/tests/codegen/enum/enum-match.rs deleted file mode 100644 index 57db44ec74e..00000000000 --- a/tests/codegen/enum/enum-match.rs +++ /dev/null @@ -1,779 +0,0 @@ -//@ compile-flags: -Copt-level=1 -//@ only-64bit - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -// Check each of the 3 cases for `codegen_get_discr`. - -// FIXME: once our min-bar LLVM has `range` attributes, update the various -// tests here to no longer have the `range`s and `nsw`s as optional. - -// Case 0: One tagged variant. -pub enum Enum0 { - A(bool), - B, -} - -// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match0(i8{{.+}}%0) -// CHECK-NEXT: start: -// CHECK-NEXT: %[[IS_B:.+]] = icmp eq i8 %0, 2 -// CHECK-NEXT: %[[TRUNC:.+]] = and i8 %0, 1 -// CHECK-NEXT: %[[R:.+]] = select i1 %[[IS_B]], i8 13, i8 %[[TRUNC]] -// CHECK-NEXT: ret i8 %[[R]] -#[no_mangle] -pub fn match0(e: Enum0) -> u8 { - use Enum0::*; - match e { - A(b) => b as u8, - B => 13, - } -} - -// Case 1: Niche values are on a boundary for `range`. -pub enum Enum1 { - A(bool), - B, - C, -} - -// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1(i8{{.+}}%0) -// CHECK-NEXT: start: -// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 -// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 -// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp{{( samesign)?}} ugt i8 %0, 1 -// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1 -// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0 -// CHECK-NEXT: switch i64 %[[DISCR]] -#[no_mangle] -pub fn match1(e: Enum1) -> u8 { - use Enum1::*; - match e { - A(b) => b as u8, - B => 13, - C => 100, - } -} - -// Case 2: Special cases don't apply. -#[rustfmt::skip] -pub enum X { - _2=2, _3, _4, _5, _6, _7, _8, _9, _10, _11, - _12, _13, _14, _15, _16, _17, _18, _19, _20, - _21, _22, _23, _24, _25, _26, _27, _28, _29, - _30, _31, _32, _33, _34, _35, _36, _37, _38, - _39, _40, _41, _42, _43, _44, _45, _46, _47, - _48, _49, _50, _51, _52, _53, _54, _55, _56, - _57, _58, _59, _60, _61, _62, _63, _64, _65, - _66, _67, _68, _69, _70, _71, _72, _73, _74, - _75, _76, _77, _78, _79, _80, _81, _82, _83, - _84, _85, _86, _87, _88, _89, _90, _91, _92, - _93, _94, _95, _96, _97, _98, _99, _100, _101, - _102, _103, _104, _105, _106, _107, _108, _109, - _110, _111, _112, _113, _114, _115, _116, _117, - _118, _119, _120, _121, _122, _123, _124, _125, - _126, _127, _128, _129, _130, _131, _132, _133, - _134, _135, _136, _137, _138, _139, _140, _141, - _142, _143, _144, _145, _146, _147, _148, _149, - _150, _151, _152, _153, _154, _155, _156, _157, - _158, _159, _160, _161, _162, _163, _164, _165, - _166, _167, _168, _169, _170, _171, _172, _173, - _174, _175, _176, _177, _178, _179, _180, _181, - _182, _183, _184, _185, _186, _187, _188, _189, - _190, _191, _192, _193, _194, _195, _196, _197, - _198, _199, _200, _201, _202, _203, _204, _205, - _206, _207, _208, _209, _210, _211, _212, _213, - _214, _215, _216, _217, _218, _219, _220, _221, - _222, _223, _224, _225, _226, _227, _228, _229, - _230, _231, _232, _233, _234, _235, _236, _237, - _238, _239, _240, _241, _242, _243, _244, _245, - _246, _247, _248, _249, _250, _251, _252, _253, -} - -pub enum Enum2 { - A(X), - B, - C, - D, - E, -} - -// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, -?[0-9]+\))?}} i8 @match2(i8{{.+}}%0) -// CHECK-NEXT: start: -// CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %0, 2 -// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 -// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 4 -// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1 -// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0 -// CHECK-NEXT: switch i64 %[[DISCR]] -#[no_mangle] -pub fn match2(e: Enum2) -> u8 { - use Enum2::*; - match e { - A(b) => b as u8, - B => 13, - C => 100, - D => 200, - E => 250, - } -} - -// And make sure it works even if the niched scalar is a pointer. -// (For example, that we don't try to `sub` on pointers.) - -// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i16 -?[0-9]+, -?[0-9]+\))?}} i16 @match3(ptr{{.+}}%0) -// CHECK-NEXT: start: -// CHECK-NEXT: %[[IS_NULL:.+]] = icmp eq ptr %0, null -// CHECK-NEXT: br i1 %[[IS_NULL]] -#[no_mangle] -pub fn match3(e: Option<&u8>) -> i16 { - match e { - Some(r) => *r as _, - None => -1, - } -} - -// If the untagged variant is in the middle, there's an impossible value that's -// not reflected in the `range` parameter attribute, so we assume it away. - -#[derive(PartialEq)] -pub enum MiddleNiche { - A, - B, - C(bool), - D, - E, -} - -// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 -?[0-9]+, -?[0-9]+\))?}} i8 @match4(i8{{.+}}%0) -// CHECK-NEXT: start: -// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 -// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2 -// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) -// CHECK-NEXT: %[[NOT_NICHE:.+]] = icmp{{( samesign)?}} ult i8 %0, 2 -// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[NOT_NICHE]], i8 2, i8 %[[REL_VAR]] -// CHECK-NEXT: switch i8 %[[DISCR]] -#[no_mangle] -pub fn match4(e: MiddleNiche) -> u8 { - use MiddleNiche::*; - match e { - A => 13, - B => 100, - C(b) => b as u8, - D => 200, - E => 250, - } -} - -// CHECK-LABEL: define{{.+}}i1 @match4_is_c(i8{{.+}}%e) -// CHECK-NEXT: start -// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %e, 4 -// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) -// CHECK-NEXT: %[[IS_C:.+]] = icmp{{( samesign)?}} ult i8 %e, 2 -// CHECK-NEXT: ret i1 %[[IS_C]] -#[no_mangle] -pub fn match4_is_c(e: MiddleNiche) -> bool { - // Before #139098, this couldn't optimize out the `select` because it looked - // like it was possible for a `2` to be produced on both sides. - - std::intrinsics::discriminant_value(&e) == 2 -} - -// You have to do something pretty obnoxious to get a variant index that doesn't -// fit in the tag size, but it's possible - -pub enum Never {} - -pub enum HugeVariantIndex { - V000(Never), - V001(Never), - V002(Never), - V003(Never), - V004(Never), - V005(Never), - V006(Never), - V007(Never), - V008(Never), - V009(Never), - V010(Never), - V011(Never), - V012(Never), - V013(Never), - V014(Never), - V015(Never), - V016(Never), - V017(Never), - V018(Never), - V019(Never), - V020(Never), - V021(Never), - V022(Never), - V023(Never), - V024(Never), - V025(Never), - V026(Never), - V027(Never), - V028(Never), - V029(Never), - V030(Never), - V031(Never), - V032(Never), - V033(Never), - V034(Never), - V035(Never), - V036(Never), - V037(Never), - V038(Never), - V039(Never), - V040(Never), - V041(Never), - V042(Never), - V043(Never), - V044(Never), - V045(Never), - V046(Never), - V047(Never), - V048(Never), - V049(Never), - V050(Never), - V051(Never), - V052(Never), - V053(Never), - V054(Never), - V055(Never), - V056(Never), - V057(Never), - V058(Never), - V059(Never), - V060(Never), - V061(Never), - V062(Never), - V063(Never), - V064(Never), - V065(Never), - V066(Never), - V067(Never), - V068(Never), - V069(Never), - V070(Never), - V071(Never), - V072(Never), - V073(Never), - V074(Never), - V075(Never), - V076(Never), - V077(Never), - V078(Never), - V079(Never), - V080(Never), - V081(Never), - V082(Never), - V083(Never), - V084(Never), - V085(Never), - V086(Never), - V087(Never), - V088(Never), - V089(Never), - V090(Never), - V091(Never), - V092(Never), - V093(Never), - V094(Never), - V095(Never), - V096(Never), - V097(Never), - V098(Never), - V099(Never), - V100(Never), - V101(Never), - V102(Never), - V103(Never), - V104(Never), - V105(Never), - V106(Never), - V107(Never), - V108(Never), - V109(Never), - V110(Never), - V111(Never), - V112(Never), - V113(Never), - V114(Never), - V115(Never), - V116(Never), - V117(Never), - V118(Never), - V119(Never), - V120(Never), - V121(Never), - V122(Never), - V123(Never), - V124(Never), - V125(Never), - V126(Never), - V127(Never), - V128(Never), - V129(Never), - V130(Never), - V131(Never), - V132(Never), - V133(Never), - V134(Never), - V135(Never), - V136(Never), - V137(Never), - V138(Never), - V139(Never), - V140(Never), - V141(Never), - V142(Never), - V143(Never), - V144(Never), - V145(Never), - V146(Never), - V147(Never), - V148(Never), - V149(Never), - V150(Never), - V151(Never), - V152(Never), - V153(Never), - V154(Never), - V155(Never), - V156(Never), - V157(Never), - V158(Never), - V159(Never), - V160(Never), - V161(Never), - V162(Never), - V163(Never), - V164(Never), - V165(Never), - V166(Never), - V167(Never), - V168(Never), - V169(Never), - V170(Never), - V171(Never), - V172(Never), - V173(Never), - V174(Never), - V175(Never), - V176(Never), - V177(Never), - V178(Never), - V179(Never), - V180(Never), - V181(Never), - V182(Never), - V183(Never), - V184(Never), - V185(Never), - V186(Never), - V187(Never), - V188(Never), - V189(Never), - V190(Never), - V191(Never), - V192(Never), - V193(Never), - V194(Never), - V195(Never), - V196(Never), - V197(Never), - V198(Never), - V199(Never), - V200(Never), - V201(Never), - V202(Never), - V203(Never), - V204(Never), - V205(Never), - V206(Never), - V207(Never), - V208(Never), - V209(Never), - V210(Never), - V211(Never), - V212(Never), - V213(Never), - V214(Never), - V215(Never), - V216(Never), - V217(Never), - V218(Never), - V219(Never), - V220(Never), - V221(Never), - V222(Never), - V223(Never), - V224(Never), - V225(Never), - V226(Never), - V227(Never), - V228(Never), - V229(Never), - V230(Never), - V231(Never), - V232(Never), - V233(Never), - V234(Never), - V235(Never), - V236(Never), - V237(Never), - V238(Never), - V239(Never), - V240(Never), - V241(Never), - V242(Never), - V243(Never), - V244(Never), - V245(Never), - V246(Never), - V247(Never), - V248(Never), - V249(Never), - V250(Never), - V251(Never), - V252(Never), - V253(Never), - V254(Never), - V255(Never), - V256(Never), - - Possible257, - Bool258(bool), - Possible259, -} - -// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match5(i8{{.+}}%0) -// CHECK-NEXT: start: -// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 -// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 -// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp{{( samesign)?}} ugt i8 %0, 1 -// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 257 -// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i64 %[[NICHE_DISCR]], 258 -// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) -// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 258 -// CHECK-NEXT: switch i64 %[[DISCR]], -// CHECK-NEXT: i64 257, -// CHECK-NEXT: i64 258, -// CHECK-NEXT: i64 259, -#[no_mangle] -pub fn match5(e: HugeVariantIndex) -> u8 { - use HugeVariantIndex::*; - match e { - Possible257 => 13, - Bool258(b) => b as u8, - Possible259 => 100, - } -} - -// Make an enum where the niche tags wrap both as signed and as unsigned, to hit -// the most-fallback case where there's just nothing smart to do. - -pub enum E10Through65 { - D10 = 10, - D11 = 11, - D12 = 12, - D13 = 13, - D14 = 14, - D15 = 15, - D16 = 16, - D17 = 17, - D18 = 18, - D19 = 19, - D20 = 20, - D21 = 21, - D22 = 22, - D23 = 23, - D24 = 24, - D25 = 25, - D26 = 26, - D27 = 27, - D28 = 28, - D29 = 29, - D30 = 30, - D31 = 31, - D32 = 32, - D33 = 33, - D34 = 34, - D35 = 35, - D36 = 36, - D37 = 37, - D38 = 38, - D39 = 39, - D40 = 40, - D41 = 41, - D42 = 42, - D43 = 43, - D44 = 44, - D45 = 45, - D46 = 46, - D47 = 47, - D48 = 48, - D49 = 49, - D50 = 50, - D51 = 51, - D52 = 52, - D53 = 53, - D54 = 54, - D55 = 55, - D56 = 56, - D57 = 57, - D58 = 58, - D59 = 59, - D60 = 60, - D61 = 61, - D62 = 62, - D63 = 63, - D64 = 64, - D65 = 65, -} - -pub enum Tricky { - Untagged(E10Through65), - V001, - V002, - V003, - V004, - V005, - V006, - V007, - V008, - V009, - V010, - V011, - V012, - V013, - V014, - V015, - V016, - V017, - V018, - V019, - V020, - V021, - V022, - V023, - V024, - V025, - V026, - V027, - V028, - V029, - V030, - V031, - V032, - V033, - V034, - V035, - V036, - V037, - V038, - V039, - V040, - V041, - V042, - V043, - V044, - V045, - V046, - V047, - V048, - V049, - V050, - V051, - V052, - V053, - V054, - V055, - V056, - V057, - V058, - V059, - V060, - V061, - V062, - V063, - V064, - V065, - V066, - V067, - V068, - V069, - V070, - V071, - V072, - V073, - V074, - V075, - V076, - V077, - V078, - V079, - V080, - V081, - V082, - V083, - V084, - V085, - V086, - V087, - V088, - V089, - V090, - V091, - V092, - V093, - V094, - V095, - V096, - V097, - V098, - V099, - V100, - V101, - V102, - V103, - V104, - V105, - V106, - V107, - V108, - V109, - V110, - V111, - V112, - V113, - V114, - V115, - V116, - V117, - V118, - V119, - V120, - V121, - V122, - V123, - V124, - V125, - V126, - V127, - V128, - V129, - V130, - V131, - V132, - V133, - V134, - V135, - V136, - V137, - V138, - V139, - V140, - V141, - V142, - V143, - V144, - V145, - V146, - V147, - V148, - V149, - V150, - V151, - V152, - V153, - V154, - V155, - V156, - V157, - V158, - V159, - V160, - V161, - V162, - V163, - V164, - V165, - V166, - V167, - V168, - V169, - V170, - V171, - V172, - V173, - V174, - V175, - V176, - V177, - V178, - V179, - V180, - V181, - V182, - V183, - V184, - V185, - V186, - V187, - V188, - V189, - V190, - V191, - V192, - V193, - V194, - V195, - V196, - V197, - V198, - V199, - V200, -} - -const _: () = assert!(std::intrinsics::discriminant_value(&Tricky::V100) == 100); - -// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @discriminant6(i8 noundef %e) -// CHECK-NEXT: start: -// CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %e, -66 -// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], -56 -// CHECK-NEXT: %[[TAGGED_DISCR:.+]] = add i8 %e, -65 -// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i8 %[[TAGGED_DISCR]], i8 0 -// CHECK-NEXT: ret i8 %[[DISCR]] -#[no_mangle] -pub fn discriminant6(e: Tricky) -> u8 { - std::intrinsics::discriminant_value(&e) as _ -} - -// Case from , -// where sign-extension is important. - -pub enum OpenResult { - Ok(()), - Err(()), - TransportErr(TransportErr), -} - -#[repr(i32)] -pub enum TransportErr { - UnknownMethod = -2, -} - -#[no_mangle] -pub fn match7(result: OpenResult) -> u8 { - // CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match7(i32{{.+}}%result) - // CHECK-NEXT: start: - // CHECK-NEXT: %[[NOT_OK:.+]] = icmp ne i32 %result, -1 - // CHECK-NEXT: %[[RET:.+]] = zext i1 %[[NOT_OK]] to i8 - // CHECK-NEXT: ret i8 %[[RET]] - match result { - OpenResult::Ok(()) => 0, - _ => 1, - } -} diff --git a/tests/codegen/enum/enum-two-variants-match.rs b/tests/codegen/enum/enum-two-variants-match.rs deleted file mode 100644 index 12d9edc4d62..00000000000 --- a/tests/codegen/enum/enum-two-variants-match.rs +++ /dev/null @@ -1,130 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -//@ only-64bit (because these discriminants are isize) - -#![crate_type = "lib"] - -// This directly tests what we emit for these matches, rather than what happens -// after optimization, so it doesn't need to worry about extra flags on the -// instructions and is less susceptible to being broken on LLVM updates. - -// CHECK-LABEL: @option_match -#[no_mangle] -pub fn option_match(x: Option) -> u16 { - // CHECK-NOT: %x = alloca - // CHECK: %[[OUT:.+]] = alloca [2 x i8] - // CHECK-NOT: %x = alloca - - // CHECK: %[[DISCR:.+]] = zext i32 %x.0 to i64 - // CHECK: %[[COND:.+]] = trunc nuw i64 %[[DISCR]] to i1 - // CHECK: br i1 %[[COND]], label %[[TRUE:[a-z0-9]+]], label %[[FALSE:[a-z0-9]+]] - - // CHECK: [[TRUE]]: - // CHECK: store i16 13, ptr %[[OUT]] - - // CHECK: [[FALSE]]: - // CHECK: store i16 42, ptr %[[OUT]] - - // CHECK: %[[RET:.+]] = load i16, ptr %[[OUT]] - // CHECK: ret i16 %[[RET]] - match x { - Some(_) => 13, - None => 42, - } -} - -// CHECK-LABEL: @result_match -#[no_mangle] -pub fn result_match(x: Result) -> u16 { - // CHECK-NOT: %x = alloca - // CHECK: %[[OUT:.+]] = alloca [2 x i8] - // CHECK-NOT: %x = alloca - - // CHECK: %[[COND:.+]] = trunc nuw i64 %x.0 to i1 - // CHECK: br i1 %[[COND]], label %[[TRUE:[a-z0-9]+]], label %[[FALSE:[a-z0-9]+]] - - // CHECK: [[TRUE]]: - // CHECK: store i16 13, ptr %[[OUT]] - - // CHECK: [[FALSE]]: - // CHECK: store i16 42, ptr %[[OUT]] - - // CHECK: %[[RET:.+]] = load i16, ptr %[[OUT]] - // CHECK: ret i16 %[[RET]] - match x { - Err(_) => 13, - Ok(_) => 42, - } -} - -// CHECK-LABEL: @option_bool_match( -#[no_mangle] -pub fn option_bool_match(x: Option) -> char { - // CHECK: %[[RAW:.+]] = load i8, ptr %x - // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %[[RAW]], 2 - // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1 - // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1 - // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]] - - // CHECK: [[BB_SOME]]: - // CHECK: %[[FIELD:.+]] = load i8, ptr %x - // CHECK: %[[FIELD_T:.+]] = trunc nuw i8 %[[FIELD]] to i1 - // CHECK: br i1 %[[FIELD_T]] - match x { - None => 'n', - Some(false) => 'f', - Some(true) => 't', - } -} - -use std::cmp::Ordering::{self, *}; -// CHECK-LABEL: @option_ordering_match( -#[no_mangle] -pub fn option_ordering_match(x: Option) -> char { - // CHECK: %[[RAW:.+]] = load i8, ptr %x - // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %[[RAW]], 2 - // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1 - // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1 - // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]] - - // CHECK: [[BB_SOME]]: - // CHECK: %[[FIELD:.+]] = load i8, ptr %x - // CHECK: switch i8 %[[FIELD]], label %[[UNREACHABLE:.+]] [ - // CHECK-NEXT: i8 -1, label - // CHECK-NEXT: i8 0, label - // CHECK-NEXT: i8 1, label - // CHECK-NEXT: ] - - // CHECK: [[UNREACHABLE]]: - // CHECK-NEXT: unreachable - match x { - None => '?', - Some(Less) => '<', - Some(Equal) => '=', - Some(Greater) => '>', - } -} - -// CHECK-LABEL: @option_nonzero_match( -#[no_mangle] -pub fn option_nonzero_match(x: Option>) -> u16 { - // CHECK: %[[OUT:.+]] = alloca [2 x i8] - - // CHECK: %[[IS_NONE:.+]] = icmp eq i16 %x, 0 - // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1 - // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1 - // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]] - - // CHECK: [[BB_SOME]]: - // CHECK: store i16 987, ptr %[[OUT]] - - // CHECK: [[BB_NONE]]: - // CHECK: store i16 123, ptr %[[OUT]] - - // CHECK: %[[RET:.+]] = load i16, ptr %[[OUT]] - // CHECK: ret i16 %[[RET]] - - match x { - None => 123, - Some(_) => 987, - } -} diff --git a/tests/codegen/enum/enum-u128.rs b/tests/codegen/enum/enum-u128.rs deleted file mode 100644 index 2676669f3e3..00000000000 --- a/tests/codegen/enum/enum-u128.rs +++ /dev/null @@ -1,25 +0,0 @@ -// This tests that debug info for "c-like" 128bit enums is properly emitted. -// This is ignored for the fallback mode on MSVC due to problems with PDB. - -// -//@ ignore-msvc -//@ ignore-wasi wasi codegens the main symbol differently - -//@ compile-flags: -g -C no-prepopulate-passes - -// CHECK-LABEL: @main -// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_enumeration_type,{{.*}}name: "Foo",{{.*}}flags: DIFlagEnumClass,{{.*}} -// CHECK: {{.*}}DIEnumerator{{.*}}name: "Lo",{{.*}}value: 0,{{.*}} -// CHECK: {{.*}}DIEnumerator{{.*}}name: "Hi",{{.*}}value: 18446744073709551616,{{.*}} -// CHECK: {{.*}}DIEnumerator{{.*}}name: "Bar",{{.*}}value: 18446745000000000123,{{.*}} - -#[repr(u128)] -pub enum Foo { - Lo, - Hi = 1 << 64, - Bar = 18_446_745_000_000_000_123, -} - -pub fn main() { - let foo = Foo::Bar; -} diff --git a/tests/codegen/enum/unreachable_enum_default_branch.rs b/tests/codegen/enum/unreachable_enum_default_branch.rs deleted file mode 100644 index 55b165fc111..00000000000 --- a/tests/codegen/enum/unreachable_enum_default_branch.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct Int(u32); - -const A: Int = Int(201); -const B: Int = Int(270); -const C: Int = Int(153); - -// The code is from https://github.com/rust-lang/rust/issues/119520. -// This code will basically turn into `matches!(x.partial_cmp(&A), Some(Greater | Equal))`. -// The otherwise branch must be `Less`. -// CHECK-LABEL: @implicit_match( -// CHECK-SAME: [[TMP0:%.*]]) -// CHECK-NEXT: start: -// CHECK-NEXT: [[TMP1:%.*]] = add i32 [[TMP0]], -201 -// CHECK-NEXT: icmp ult i32 [[TMP1]], 70 -// CHECK-NEXT: icmp eq i32 [[TMP0]], 153 -// CHECK-NEXT: [[SPEC_SELECT:%.*]] = or i1 -// CHECK-NEXT: ret i1 [[SPEC_SELECT]] -#[no_mangle] -pub fn implicit_match(x: Int) -> bool { - (x >= A && x <= B) || x == C -} - -// The code is from https://github.com/rust-lang/rust/issues/110097. -// We expect it to generate the same optimized code as a full match. -// CHECK-LABEL: @if_let( -// CHECK: start: -// CHECK-NOT: zext -// CHECK: select -// CHECK-NEXT: insertvalue -// CHECK-NEXT: insertvalue -// CHECK-NEXT: ret -#[no_mangle] -pub fn if_let(val: Result) -> Result { - if let Ok(x) = val { Ok(x * 2) } else { Err(()) } -} diff --git a/tests/codegen/ergonomic-clones/closure.rs b/tests/codegen/ergonomic-clones/closure.rs deleted file mode 100644 index b6fc8172641..00000000000 --- a/tests/codegen/ergonomic-clones/closure.rs +++ /dev/null @@ -1,55 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -Zmir-opt-level=0 - -#![crate_type = "lib"] - -#![feature(ergonomic_clones)] -#![allow(incomplete_features)] - -use std::clone::UseCloned; - -pub fn ergonomic_clone_closure_move() -> String { - let s = String::from("hi"); - - // CHECK-NOT: ; call core::clone::impls::::clone - let cl = use || s; - cl() -} - -#[derive(Clone)] -struct Foo; - -impl UseCloned for Foo {} - -pub fn ergonomic_clone_closure_use_cloned() -> Foo { - let f = Foo; - - // CHECK: ; call ::clone - let f1 = use || f; - - // CHECK: ; call ::clone - let f2 = use || f; - - f -} - -pub fn ergonomic_clone_closure_copy() -> i32 { - let i = 1; - - // CHECK-NOT: ; call core::clone::impls::::clone - let i1 = use || i; - - // CHECK-NOT: ; call core::clone::impls::::clone - let i2 = use || i; - - i -} - -pub fn ergonomic_clone_closure_use_cloned_generics(f: T) -> T { - // CHECK-NOT: ; call core::clone::impls::::clone - let f1 = use || f; - - // CHECK-NOT: ; call core::clone::impls::::clone - let f2 = use || f; - - f -} diff --git a/tests/codegen/error-provide.rs b/tests/codegen/error-provide.rs deleted file mode 100644 index 7f091e34359..00000000000 --- a/tests/codegen/error-provide.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Codegen test for #126242 - -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] -#![feature(error_generic_member_access)] -use std::error::Request; -use std::fmt; - -#[derive(Debug)] -struct MyBacktrace1 {} - -#[derive(Debug)] -struct MyBacktrace2 {} - -#[derive(Debug)] -struct MyBacktrace3 {} - -#[derive(Debug)] -struct MyError { - backtrace1: MyBacktrace1, - backtrace2: MyBacktrace2, - backtrace3: MyBacktrace3, - other: MyBacktrace3, -} - -impl fmt::Display for MyError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Example Error") - } -} - -impl std::error::Error for MyError { - // CHECK-LABEL: @provide - #[no_mangle] - fn provide<'a>(&'a self, request: &mut Request<'a>) { - // LLVM should be able to optimize multiple .provide_* calls into a switch table - // and eliminate redundant ones, rather than compare one-by-one. - - // CHECK-NEXT: start: - // CHECK-NEXT: %[[SCRUTINEE:[^ ]+]] = load i128, ptr - // CHECK-NEXT: switch i128 %[[SCRUTINEE]], label %{{.*}} [ - // CHECK-COUNT-3: i128 {{.*}}, label %{{.*}} - // CHECK-NEXT: ] - request - .provide_ref::(&self.backtrace1) - .provide_ref::(&self.other) - .provide_ref::(&self.backtrace2) - .provide_ref::(&self.backtrace3); - } -} diff --git a/tests/codegen/export-no-mangle.rs b/tests/codegen/export-no-mangle.rs deleted file mode 100644 index 5040684f52e..00000000000 --- a/tests/codegen/export-no-mangle.rs +++ /dev/null @@ -1,31 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] - -mod private { - // CHECK: @FOO = - #[no_mangle] - pub static FOO: u32 = 3; - - // CHECK: @BAR = - #[export_name = "BAR"] - static BAR: u32 = 3; - - // CHECK: void @a() - #[no_mangle] - pub extern "C" fn a() {} - - // CHECK: void @b() - #[export_name = "b"] - extern "C" fn b() {} - - // CHECK: void @c() - #[export_name = "c"] - #[inline] - extern "C" fn c() {} - - // CHECK: void @d() - #[export_name = "d"] - #[inline(always)] - extern "C" fn d() {} -} diff --git a/tests/codegen/external-no-mangle-fns.rs b/tests/codegen/external-no-mangle-fns.rs deleted file mode 100644 index 35ab0fd7909..00000000000 --- a/tests/codegen/external-no-mangle-fns.rs +++ /dev/null @@ -1,75 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -// `#[no_mangle]`d functions always have external linkage, i.e., no `internal` in their `define`s - -#![crate_type = "lib"] -#![no_std] - -// CHECK: define{{( dso_local)?}} void @a() -#[no_mangle] -fn a() {} - -// CHECK: define{{( dso_local)?}} void @b() -#[no_mangle] -pub fn b() {} - -mod private { - // CHECK: define{{( dso_local)?}} void @c() - #[no_mangle] - fn c() {} - - // CHECK: define{{( dso_local)?}} void @d() - #[no_mangle] - pub fn d() {} -} - -const HIDDEN: () = { - // CHECK: define{{( dso_local)?}} void @e() - #[no_mangle] - fn e() {} - - // CHECK: define{{( dso_local)?}} void @f() - #[no_mangle] - pub fn f() {} -}; - -// The surrounding item should not accidentally become external -// CHECK-LABEL: ; external_no_mangle_fns::x -// CHECK-NEXT: ; Function Attrs: -// CHECK-NEXT: define internal -#[inline(never)] -fn x() { - // CHECK: define{{( dso_local)?}} void @g() - #[no_mangle] - fn g() { - x(); - } - - // CHECK: define{{( dso_local)?}} void @h() - #[no_mangle] - pub fn h() {} - - // side effect to keep `x` around - unsafe { - core::ptr::read_volatile(&42); - } -} - -// CHECK: define{{( dso_local)?}} void @i() -#[no_mangle] -#[inline] -fn i() {} - -// CHECK: define{{( dso_local)?}} void @j() -#[no_mangle] -#[inline] -pub fn j() {} - -// CHECK: define{{( dso_local)?}} void @k() -#[no_mangle] -#[inline(always)] -fn k() {} - -// CHECK: define{{( dso_local)?}} void @l() -#[no_mangle] -#[inline(always)] -pub fn l() {} diff --git a/tests/codegen/external-no-mangle-statics.rs b/tests/codegen/external-no-mangle-statics.rs deleted file mode 100644 index 49f42ee977d..00000000000 --- a/tests/codegen/external-no-mangle-statics.rs +++ /dev/null @@ -1,77 +0,0 @@ -//@ revisions: lib staticlib -//@ ignore-emscripten default visibility is hidden -//@ compile-flags: -Copt-level=3 -//@ [lib] compile-flags: --crate-type lib -//@ [staticlib] compile-flags: --crate-type staticlib -// `#[no_mangle]`d static variables always have external linkage, i.e., no `internal` in their -// definitions - -// CHECK-DAG: @A = {{(dso_local )?}}local_unnamed_addr constant -#[no_mangle] -static A: u8 = 0; - -// CHECK-DAG: @B = {{(dso_local )?}}local_unnamed_addr global -#[no_mangle] -static mut B: u8 = 0; - -// CHECK-DAG: @C = {{(dso_local )?}}local_unnamed_addr constant -#[no_mangle] -pub static C: u8 = 0; - -// CHECK-DAG: @D = {{(dso_local )?}}local_unnamed_addr global -#[no_mangle] -pub static mut D: u8 = 0; - -mod private { - // CHECK-DAG: @E = {{(dso_local )?}}local_unnamed_addr constant - #[no_mangle] - static E: u8 = 0; - - // CHECK-DAG: @F = {{(dso_local )?}}local_unnamed_addr global - #[no_mangle] - static mut F: u8 = 0; - - // CHECK-DAG: @G = {{(dso_local )?}}local_unnamed_addr constant - #[no_mangle] - pub static G: u8 = 0; - - // CHECK-DAG: @H = {{(dso_local )?}}local_unnamed_addr global - #[no_mangle] - pub static mut H: u8 = 0; -} - -const HIDDEN: () = { - // CHECK-DAG: @I = {{(dso_local )?}}local_unnamed_addr constant - #[no_mangle] - static I: u8 = 0; - - // CHECK-DAG: @J = {{(dso_local )?}}local_unnamed_addr global - #[no_mangle] - static mut J: u8 = 0; - - // CHECK-DAG: @K = {{(dso_local )?}}local_unnamed_addr constant - #[no_mangle] - pub static K: u8 = 0; - - // CHECK-DAG: @L = {{(dso_local )?}}local_unnamed_addr global - #[no_mangle] - pub static mut L: u8 = 0; -}; - -fn x() { - // CHECK-DAG: @M = {{(dso_local )?}}local_unnamed_addr constant - #[no_mangle] - static M: fn() = x; - - // CHECK-DAG: @N = {{(dso_local )?}}local_unnamed_addr global - #[no_mangle] - static mut N: u8 = 0; - - // CHECK-DAG: @O = {{(dso_local )?}}local_unnamed_addr constant - #[no_mangle] - pub static O: u8 = 0; - - // CHECK-DAG: @P = {{(dso_local )?}}local_unnamed_addr global - #[no_mangle] - pub static mut P: u8 = 0; -} diff --git a/tests/codegen/f128-wasm32-callconv.rs b/tests/codegen/f128-wasm32-callconv.rs deleted file mode 100644 index 7dccbda18f1..00000000000 --- a/tests/codegen/f128-wasm32-callconv.rs +++ /dev/null @@ -1,49 +0,0 @@ -//! Verify that Rust implements the expected calling convention for `f128` - -//@ add-core-stubs -//@ compile-flags: -Copt-level=3 --target wasm32-wasip1 -//@ needs-llvm-components: webassembly - -#![crate_type = "lib"] -#![no_std] -#![no_core] -#![feature(no_core, lang_items, f128)] - -extern crate minicore; - -extern "C" { - fn extern_call(arg0: f128); - fn extern_ret() -> f128; -} - -#[no_mangle] -pub extern "C" fn pass(_arg0: u32, arg1: f128) { - // CHECK-LABEL: @pass( - // an f128 is passed via registers - // CHECK-SAME: fp128 noundef %arg1 - // CHECK: call void @extern_call - unsafe { extern_call(arg1) }; -} - -// Check that we produce the correct return ABI -#[no_mangle] -pub extern "C" fn ret(_arg0: u32, arg1: f128) -> f128 { - // CHECK-LABEL: @ret( - // but an f128 is returned via the stack - // CHECK-SAME: sret - // CHECK: store fp128 %arg1 - // CHECK-NEXT: ret void - arg1 -} - -// Check that we consume the correct return ABI -#[no_mangle] -pub extern "C" fn forward(dst: *mut f128) { - // CHECK-LABEL: @forward - // CHECK-SAME: ptr{{.*}} %dst) - // without optimizatons, an intermediate alloca is used - // CHECK: call void @extern_ret - // CHECK: store fp128 - // CHECK: ret void - unsafe { *dst = extern_ret() }; -} diff --git a/tests/codegen/fastcall-inreg.rs b/tests/codegen/fastcall-inreg.rs deleted file mode 100644 index 066943d6e7e..00000000000 --- a/tests/codegen/fastcall-inreg.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Checks if the "fastcall" calling convention marks function arguments -// as "inreg" like the C/C++ compilers for the platforms. -// x86 only. - -//@ add-core-stubs -//@ compile-flags: --target i686-unknown-linux-gnu -Cno-prepopulate-passes -Copt-level=3 -//@ needs-llvm-components: x86 - -#![crate_type = "lib"] -#![no_core] -#![feature(no_core, lang_items)] - -extern crate minicore; -use minicore::*; - -pub mod tests { - // CHECK: @f1(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) - #[no_mangle] - pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {} - - // CHECK: @f2(ptr inreg noundef %_1, ptr inreg noundef %_2, ptr noundef %_3) - #[no_mangle] - pub extern "fastcall" fn f2(_: *const i32, _: *const i32, _: *const i32) {} - - // CHECK: @f3(float noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3, i32 noundef %_4) - #[no_mangle] - pub extern "fastcall" fn f3(_: f32, _: i32, _: i32, _: i32) {} - - // CHECK: @f4(i32 inreg noundef %_1, float noundef %_2, i32 inreg noundef %_3, i32 noundef %_4) - #[no_mangle] - pub extern "fastcall" fn f4(_: i32, _: f32, _: i32, _: i32) {} - - // CHECK: @f5(i64 noundef %_1, i32 noundef %_2) - #[no_mangle] - pub extern "fastcall" fn f5(_: i64, _: i32) {} - - // CHECK: @f6(i1 inreg noundef zeroext %_1, i32 inreg noundef %_2, i32 noundef %_3) - #[no_mangle] - pub extern "fastcall" fn f6(_: bool, _: i32, _: i32) {} -} diff --git a/tests/codegen/fatptr.rs b/tests/codegen/fatptr.rs deleted file mode 100644 index 041807202b8..00000000000 --- a/tests/codegen/fatptr.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] - -pub trait T {} - -// CHECK-LABEL: @copy_fat_ptr -#[no_mangle] -pub fn copy_fat_ptr(x: &T) { - // CHECK-NOT: extractvalue - let x2 = x; -} diff --git a/tests/codegen/fewer-names.rs b/tests/codegen/fewer-names.rs deleted file mode 100644 index ff7a916b619..00000000000 --- a/tests/codegen/fewer-names.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ compile-flags: -Coverflow-checks=no -Copt-level=3 -//@ revisions: YES NO -//@ [YES]compile-flags: -Zfewer-names=yes -//@ [NO] compile-flags: -Zfewer-names=no -#![crate_type = "lib"] - -#[no_mangle] -pub fn sum(x: u32, y: u32) -> u32 { - // YES-LABEL: define{{.*}}i32 @sum(i32{{.*}} %0, i32{{.*}} %1) - // YES-NEXT: %3 = add i32 %1, %0 - // YES-NEXT: ret i32 %3 - - // NO-LABEL: define{{.*}}i32 @sum(i32{{.*}} %x, i32{{.*}} %y) - // NO-NEXT: start: - // NO-NEXT: %z = add i32 %y, %x - // NO-NEXT: ret i32 %z - let z = x + y; - z -} diff --git a/tests/codegen/fixed-x18.rs b/tests/codegen/fixed-x18.rs deleted file mode 100644 index a5767cfa456..00000000000 --- a/tests/codegen/fixed-x18.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Test that the `reserve-x18` target feature is (not) emitted when -// the `-Zfixed-x18` flag is (not) set. - -//@ add-core-stubs -//@ revisions: unset set -//@ needs-llvm-components: aarch64 -//@ compile-flags: --target aarch64-unknown-none -//@ [set] compile-flags: -Zfixed-x18 - -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[no_mangle] -pub fn foo() { - // CHECK: @foo() unnamed_addr #0 - - // unset-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+reserve-x18{{.*}} } - // set: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+reserve-x18{{.*}} } -} diff --git a/tests/codegen/float/algebraic.rs b/tests/codegen/float/algebraic.rs deleted file mode 100644 index 818a4bcdfe3..00000000000 --- a/tests/codegen/float/algebraic.rs +++ /dev/null @@ -1,149 +0,0 @@ -// Verify that algebraic intrinsics generate the correct LLVM calls - -// Ensure operations get inlined -//@ compile-flags: -Copt-level=1 - -#![crate_type = "lib"] -#![feature(f16)] -#![feature(f128)] -#![feature(float_algebraic)] - -// CHECK-LABEL: @f16_algebraic_add -#[no_mangle] -pub fn f16_algebraic_add(a: f16, b: f16) -> f16 { - // CHECK: fadd reassoc nsz arcp contract half %{{.+}}, %{{.+}} - a.algebraic_add(b) -} - -// CHECK-LABEL: @f16_algebraic_sub -#[no_mangle] -pub fn f16_algebraic_sub(a: f16, b: f16) -> f16 { - // CHECK: fsub reassoc nsz arcp contract half %{{.+}}, %{{.+}} - a.algebraic_sub(b) -} - -// CHECK-LABEL: @f16_algebraic_mul -#[no_mangle] -pub fn f16_algebraic_mul(a: f16, b: f16) -> f16 { - // CHECK: fmul reassoc nsz arcp contract half %{{.+}}, %{{.+}} - a.algebraic_mul(b) -} - -// CHECK-LABEL: @f16_algebraic_div -#[no_mangle] -pub fn f16_algebraic_div(a: f16, b: f16) -> f16 { - // CHECK: fdiv reassoc nsz arcp contract half %{{.+}}, %{{.+}} - a.algebraic_div(b) -} - -// CHECK-LABEL: @f16_algebraic_rem -#[no_mangle] -pub fn f16_algebraic_rem(a: f16, b: f16) -> f16 { - // CHECK: frem reassoc nsz arcp contract half %{{.+}}, %{{.+}} - a.algebraic_rem(b) -} - -// CHECK-LABEL: @f32_algebraic_add -#[no_mangle] -pub fn f32_algebraic_add(a: f32, b: f32) -> f32 { - // CHECK: fadd reassoc nsz arcp contract float %{{.+}}, %{{.+}} - a.algebraic_add(b) -} - -// CHECK-LABEL: @f32_algebraic_sub -#[no_mangle] -pub fn f32_algebraic_sub(a: f32, b: f32) -> f32 { - // CHECK: fsub reassoc nsz arcp contract float %{{.+}}, %{{.+}} - a.algebraic_sub(b) -} - -// CHECK-LABEL: @f32_algebraic_mul -#[no_mangle] -pub fn f32_algebraic_mul(a: f32, b: f32) -> f32 { - // CHECK: fmul reassoc nsz arcp contract float %{{.+}}, %{{.+}} - a.algebraic_mul(b) -} - -// CHECK-LABEL: @f32_algebraic_div -#[no_mangle] -pub fn f32_algebraic_div(a: f32, b: f32) -> f32 { - // CHECK: fdiv reassoc nsz arcp contract float %{{.+}}, %{{.+}} - a.algebraic_div(b) -} - -// CHECK-LABEL: @f32_algebraic_rem -#[no_mangle] -pub fn f32_algebraic_rem(a: f32, b: f32) -> f32 { - // CHECK: frem reassoc nsz arcp contract float %{{.+}}, %{{.+}} - a.algebraic_rem(b) -} - -// CHECK-LABEL: @f64_algebraic_add -#[no_mangle] -pub fn f64_algebraic_add(a: f64, b: f64) -> f64 { - // CHECK: fadd reassoc nsz arcp contract double %{{.+}}, %{{.+}} - a.algebraic_add(b) -} - -// CHECK-LABEL: @f64_algebraic_sub -#[no_mangle] -pub fn f64_algebraic_sub(a: f64, b: f64) -> f64 { - // CHECK: fsub reassoc nsz arcp contract double %{{.+}}, %{{.+}} - a.algebraic_sub(b) -} - -// CHECK-LABEL: @f64_algebraic_mul -#[no_mangle] -pub fn f64_algebraic_mul(a: f64, b: f64) -> f64 { - // CHECK: fmul reassoc nsz arcp contract double %{{.+}}, %{{.+}} - a.algebraic_mul(b) -} - -// CHECK-LABEL: @f64_algebraic_div -#[no_mangle] -pub fn f64_algebraic_div(a: f64, b: f64) -> f64 { - // CHECK: fdiv reassoc nsz arcp contract double %{{.+}}, %{{.+}} - a.algebraic_div(b) -} - -// CHECK-LABEL: @f64_algebraic_rem -#[no_mangle] -pub fn f64_algebraic_rem(a: f64, b: f64) -> f64 { - // CHECK: frem reassoc nsz arcp contract double %{{.+}}, %{{.+}} - a.algebraic_rem(b) -} - -// CHECK-LABEL: @f128_algebraic_add -#[no_mangle] -pub fn f128_algebraic_add(a: f128, b: f128) -> f128 { - // CHECK: fadd reassoc nsz arcp contract fp128 %{{.+}}, %{{.+}} - a.algebraic_add(b) -} - -// CHECK-LABEL: @f128_algebraic_sub -#[no_mangle] -pub fn f128_algebraic_sub(a: f128, b: f128) -> f128 { - // CHECK: fsub reassoc nsz arcp contract fp128 %{{.+}}, %{{.+}} - a.algebraic_sub(b) -} - -// CHECK-LABEL: @f128_algebraic_mul -#[no_mangle] -pub fn f128_algebraic_mul(a: f128, b: f128) -> f128 { - // CHECK: fmul reassoc nsz arcp contract fp128 %{{.+}}, %{{.+}} - a.algebraic_mul(b) -} - -// CHECK-LABEL: @f128_algebraic_div -#[no_mangle] -pub fn f128_algebraic_div(a: f128, b: f128) -> f128 { - // CHECK: fdiv reassoc nsz arcp contract fp128 %{{.+}}, %{{.+}} - a.algebraic_div(b) -} - -// CHECK-LABEL: @f128_algebraic_rem -#[no_mangle] -pub fn f128_algebraic_rem(a: f128, b: f128) -> f128 { - // CHECK: frem reassoc nsz arcp contract fp128 %{{.+}}, %{{.+}} - a.algebraic_rem(b) -} diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs deleted file mode 100644 index d87bab1172a..00000000000 --- a/tests/codegen/float/f128.rs +++ /dev/null @@ -1,441 +0,0 @@ -// 32-bit x86 returns float types differently to avoid the x87 stack. -// 32-bit systems will return 128bit values using a return area pointer. -// Emscripten aligns f128 to 8 bytes, not 16. -//@ revisions: x86-sse x86-nosse bit32 bit64 emscripten -//@[x86-sse] only-x86 -//@[x86-sse] only-rustc_abi-x86-sse2 -//@[x86-nosse] only-x86 -//@[x86-nosse] ignore-rustc_abi-x86-sse2 -//@[bit32] ignore-x86 -//@[bit32] ignore-emscripten -//@[bit32] only-32bit -//@[bit64] ignore-x86 -//@[bit64] ignore-emscripten -//@[bit64] only-64bit -//@[emscripten] only-emscripten - -// Verify that our intrinsics generate the correct LLVM calls for f128 - -#![crate_type = "lib"] -#![feature(f128)] -#![feature(f16)] -#![feature(core_intrinsics)] - -// CHECK-LABEL: i1 @f128_eq( -#[no_mangle] -pub fn f128_eq(a: f128, b: f128) -> bool { - // CHECK: fcmp oeq fp128 %{{.+}}, %{{.+}} - a == b -} - -// CHECK-LABEL: i1 @f128_ne( -#[no_mangle] -pub fn f128_ne(a: f128, b: f128) -> bool { - // CHECK: fcmp une fp128 %{{.+}}, %{{.+}} - a != b -} - -// CHECK-LABEL: i1 @f128_gt( -#[no_mangle] -pub fn f128_gt(a: f128, b: f128) -> bool { - // CHECK: fcmp ogt fp128 %{{.+}}, %{{.+}} - a > b -} - -// CHECK-LABEL: i1 @f128_ge( -#[no_mangle] -pub fn f128_ge(a: f128, b: f128) -> bool { - // CHECK: fcmp oge fp128 %{{.+}}, %{{.+}} - a >= b -} - -// CHECK-LABEL: i1 @f128_lt( -#[no_mangle] -pub fn f128_lt(a: f128, b: f128) -> bool { - // CHECK: fcmp olt fp128 %{{.+}}, %{{.+}} - a < b -} - -// CHECK-LABEL: i1 @f128_le( -#[no_mangle] -pub fn f128_le(a: f128, b: f128) -> bool { - // CHECK: fcmp ole fp128 %{{.+}}, %{{.+}} - a <= b -} - -// x86-nosse-LABEL: void @f128_neg({{.*}}sret([16 x i8]) -// x86-sse-LABEL: <16 x i8> @f128_neg(fp128 -// bit32-LABEL: void @f128_neg({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @f128_neg( -// emscripten-LABEL: void @f128_neg({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn f128_neg(a: f128) -> f128 { - // CHECK: fneg fp128 - -a -} - -// x86-nosse-LABEL: void @f128_add({{.*}}sret([16 x i8]) -// x86-sse-LABEL: <16 x i8> @f128_add(fp128 -// bit32-LABEL: void @f128_add({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @f128_add( -// emscripten-LABEL: void @f128_add({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn f128_add(a: f128, b: f128) -> f128 { - // CHECK: fadd fp128 %{{.+}}, %{{.+}} - a + b -} - -// x86-nosse-LABEL: void @f128_sub({{.*}}sret([16 x i8]) -// x86-sse-LABEL: <16 x i8> @f128_sub(fp128 -// bit32-LABEL: void @f128_sub({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @f128_sub( -// emscripten-LABEL: void @f128_sub({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn f128_sub(a: f128, b: f128) -> f128 { - // CHECK: fsub fp128 %{{.+}}, %{{.+}} - a - b -} - -// x86-nosse-LABEL: void @f128_mul({{.*}}sret([16 x i8]) -// x86-sse-LABEL: <16 x i8> @f128_mul(fp128 -// bit32-LABEL: void @f128_mul({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @f128_mul( -// emscripten-LABEL: void @f128_mul({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn f128_mul(a: f128, b: f128) -> f128 { - // CHECK: fmul fp128 %{{.+}}, %{{.+}} - a * b -} - -// x86-nosse-LABEL: void @f128_div({{.*}}sret([16 x i8]) -// x86-sse-LABEL: <16 x i8> @f128_div(fp128 -// bit32-LABEL: void @f128_div({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @f128_div( -// emscripten-LABEL: void @f128_div({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn f128_div(a: f128, b: f128) -> f128 { - // CHECK: fdiv fp128 %{{.+}}, %{{.+}} - a / b -} - -// x86-nosse-LABEL: void @f128_rem({{.*}}sret([16 x i8]) -// x86-sse-LABEL: <16 x i8> @f128_rem(fp128 -// bit32-LABEL: void @f128_rem({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @f128_rem( -// emscripten-LABEL: void @f128_rem({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn f128_rem(a: f128, b: f128) -> f128 { - // CHECK: frem fp128 %{{.+}}, %{{.+}} - a % b -} - -// CHECK-LABEL: void @f128_add_assign( -#[no_mangle] -pub fn f128_add_assign(a: &mut f128, b: f128) { - // CHECK: fadd fp128 %{{.+}}, %{{.+}} - // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} - *a += b; -} - -// CHECK-LABEL: void @f128_sub_assign( -#[no_mangle] -pub fn f128_sub_assign(a: &mut f128, b: f128) { - // CHECK: fsub fp128 %{{.+}}, %{{.+}} - // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} - *a -= b; -} - -// CHECK-LABEL: void @f128_mul_assign( -#[no_mangle] -pub fn f128_mul_assign(a: &mut f128, b: f128) { - // CHECK: fmul fp128 %{{.+}}, %{{.+}} - // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} - *a *= b -} - -// CHECK-LABEL: void @f128_div_assign( -#[no_mangle] -pub fn f128_div_assign(a: &mut f128, b: f128) { - // CHECK: fdiv fp128 %{{.+}}, %{{.+}} - // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} - *a /= b -} - -// CHECK-LABEL: void @f128_rem_assign( -#[no_mangle] -pub fn f128_rem_assign(a: &mut f128, b: f128) { - // CHECK: frem fp128 %{{.+}}, %{{.+}} - // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} - *a %= b -} - -/* float to float conversions */ - -// x86-sse-LABEL: <2 x i8> @f128_as_f16( -// x86-nosse-LABEL: i16 @f128_as_f16( -// bits32-LABEL: half @f128_as_f16( -// bits64-LABEL: half @f128_as_f16( -#[no_mangle] -pub fn f128_as_f16(a: f128) -> f16 { - // CHECK: fptrunc fp128 %{{.+}} to half - a as f16 -} - -// x86-sse-LABEL: <4 x i8> @f128_as_f32( -// x86-nosse-LABEL: i32 @f128_as_f32( -// bit32-LABEL: float @f128_as_f32( -// bit64-LABEL: float @f128_as_f32( -// emscripten-LABEL: float @f128_as_f32( -#[no_mangle] -pub fn f128_as_f32(a: f128) -> f32 { - // CHECK: fptrunc fp128 %{{.+}} to float - a as f32 -} - -// x86-sse-LABEL: <8 x i8> @f128_as_f64( -// x86-nosse-LABEL: void @f128_as_f64({{.*}}sret([8 x i8]) -// bit32-LABEL: double @f128_as_f64( -// bit64-LABEL: double @f128_as_f64( -// emscripten-LABEL: double @f128_as_f64( -#[no_mangle] -pub fn f128_as_f64(a: f128) -> f64 { - // CHECK: fptrunc fp128 %{{.+}} to double - a as f64 -} - -// x86-sse-LABEL: <16 x i8> @f128_as_self( -// x86-nosse-LABEL: void @f128_as_self({{.*}}sret([16 x i8]) -// bit32-LABEL: void @f128_as_self({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @f128_as_self( -// emscripten-LABEL: void @f128_as_self({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn f128_as_self(a: f128) -> f128 { - // x86: store fp128 %a, ptr %_0, align 16 - // bit32: store fp128 %a, ptr %_0, align 16 - // bit64: ret fp128 %{{.+}} - // emscripten: store fp128 %a, ptr %_0, align 8 - a as f128 -} - -// x86-sse-LABEL: <16 x i8> @f16_as_f128( -// x86-nosse-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @f16_as_f128( -// emscripten-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn f16_as_f128(a: f16) -> f128 { - // CHECK: fpext half %{{.+}} to fp128 - a as f128 -} - -// x86-sse-LABEL: <16 x i8> @f32_as_f128( -// x86-nosse-LABEL: void @f32_as_f128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @f32_as_f128({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @f32_as_f128( -// emscripten-LABEL: void @f32_as_f128({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn f32_as_f128(a: f32) -> f128 { - // CHECK: fpext float %{{.+}} to fp128 - a as f128 -} - -// x86-sse-LABEL: <16 x i8> @f64_as_f128( -// x86-nosse-LABEL: void @f64_as_f128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @f64_as_f128({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @f64_as_f128( -// emscripten-LABEL: void @f64_as_f128({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn f64_as_f128(a: f64) -> f128 { - // CHECK: fpext double %{{.+}} to fp128 - a as f128 -} - -/* float to int conversions */ - -// CHECK-LABEL: i8 @f128_as_u8( -#[no_mangle] -pub fn f128_as_u8(a: f128) -> u8 { - // CHECK: call i8 @llvm.fptoui.sat.i8.f128(fp128 %{{.+}}) - a as u8 -} - -#[no_mangle] -pub fn f128_as_u16(a: f128) -> u16 { - // CHECK: call i16 @llvm.fptoui.sat.i16.f128(fp128 %{{.+}}) - a as u16 -} - -// CHECK-LABEL: i32 @f128_as_u32( -#[no_mangle] -pub fn f128_as_u32(a: f128) -> u32 { - // CHECK: call i32 @llvm.fptoui.sat.i32.f128(fp128 %{{.+}}) - a as u32 -} - -// CHECK-LABEL: i64 @f128_as_u64( -#[no_mangle] -pub fn f128_as_u64(a: f128) -> u64 { - // CHECK: call i64 @llvm.fptoui.sat.i64.f128(fp128 %{{.+}}) - a as u64 -} - -// x86-sse-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) -// x86-nosse-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) -// bit64-LABEL: i128 @f128_as_u128( -// emscripten-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn f128_as_u128(a: f128) -> u128 { - // CHECK: call i128 @llvm.fptoui.sat.i128.f128(fp128 %{{.+}}) - a as u128 -} - -// CHECK-LABEL: i8 @f128_as_i8( -#[no_mangle] -pub fn f128_as_i8(a: f128) -> i8 { - // CHECK: call i8 @llvm.fptosi.sat.i8.f128(fp128 %{{.+}}) - a as i8 -} - -// CHECK-LABEL: i16 @f128_as_i16( -#[no_mangle] -pub fn f128_as_i16(a: f128) -> i16 { - // CHECK: call i16 @llvm.fptosi.sat.i16.f128(fp128 %{{.+}}) - a as i16 -} -// CHECK-LABEL: i32 @f128_as_i32( -#[no_mangle] -pub fn f128_as_i32(a: f128) -> i32 { - // CHECK: call i32 @llvm.fptosi.sat.i32.f128(fp128 %{{.+}}) - a as i32 -} - -// CHECK-LABEL: i64 @f128_as_i64( -#[no_mangle] -pub fn f128_as_i64(a: f128) -> i64 { - // CHECK: call i64 @llvm.fptosi.sat.i64.f128(fp128 %{{.+}}) - a as i64 -} - -// x86-sse-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) -// x86-nosse-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) -// bit64-LABEL: i128 @f128_as_i128( -// emscripten-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn f128_as_i128(a: f128) -> i128 { - // CHECK: call i128 @llvm.fptosi.sat.i128.f128(fp128 %{{.+}}) - a as i128 -} - -/* int to float conversions */ - -// x86-sse-LABEL: <16 x i8> @u8_as_f128( -// x86-nosse-LABEL: void @u8_as_f128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @u8_as_f128({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @u8_as_f128( -// emscripten-LABEL: void @u8_as_f128({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn u8_as_f128(a: u8) -> f128 { - // CHECK: uitofp i8 %{{.+}} to fp128 - a as f128 -} - -// x86-sse-LABEL: <16 x i8> @u16_as_f128( -// x86-nosse-LABEL: void @u16_as_f128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @u16_as_f128({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @u16_as_f128( -// emscripten-LABEL: void @u16_as_f128({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn u16_as_f128(a: u16) -> f128 { - // CHECK: uitofp i16 %{{.+}} to fp128 - a as f128 -} - -// x86-sse-LABEL: <16 x i8> @u32_as_f128( -// x86-nosse-LABEL: void @u32_as_f128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @u32_as_f128({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @u32_as_f128( -// emscripten-LABEL: void @u32_as_f128({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn u32_as_f128(a: u32) -> f128 { - // CHECK: uitofp i32 %{{.+}} to fp128 - a as f128 -} - -// x86-sse-LABEL: <16 x i8> @u64_as_f128( -// x86-nosse-LABEL: void @u64_as_f128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @u64_as_f128({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @u64_as_f128( -// emscripten-LABEL: void @u64_as_f128({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn u64_as_f128(a: u64) -> f128 { - // CHECK: uitofp i64 %{{.+}} to fp128 - a as f128 -} - -// x86-sse-LABEL: <16 x i8> @u128_as_f128( -// x86-nosse-LABEL: void @u128_as_f128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @u128_as_f128({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @u128_as_f128( -// emscripten-LABEL: void @u128_as_f128({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn u128_as_f128(a: u128) -> f128 { - // CHECK: uitofp i128 %{{.+}} to fp128 - a as f128 -} - -// x86-sse-LABEL: <16 x i8> @i8_as_f128( -// x86-nosse-LABEL: void @i8_as_f128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @i8_as_f128({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @i8_as_f128( -// emscripten-LABEL: void @i8_as_f128({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn i8_as_f128(a: i8) -> f128 { - // CHECK: sitofp i8 %{{.+}} to fp128 - a as f128 -} - -// x86-sse-LABEL: <16 x i8> @i16_as_f128( -// x86-nosse-LABEL: void @i16_as_f128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @i16_as_f128({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @i16_as_f128( -// emscripten-LABEL: void @i16_as_f128({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn i16_as_f128(a: i16) -> f128 { - // CHECK: sitofp i16 %{{.+}} to fp128 - a as f128 -} - -// x86-sse-LABEL: <16 x i8> @i32_as_f128( -// x86-nosse-LABEL: void @i32_as_f128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @i32_as_f128({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @i32_as_f128( -// emscripten-LABEL: void @i32_as_f128({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn i32_as_f128(a: i32) -> f128 { - // CHECK: sitofp i32 %{{.+}} to fp128 - a as f128 -} - -// x86-sse-LABEL: <16 x i8> @i64_as_f128( -// x86-nosse-LABEL: void @i64_as_f128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @i64_as_f128({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @i64_as_f128( -// emscripten-LABEL: void @i64_as_f128({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn i64_as_f128(a: i64) -> f128 { - // CHECK: sitofp i64 %{{.+}} to fp128 - a as f128 -} - -// x86-sse-LABEL: <16 x i8> @i128_as_f128( -// x86-nosse-LABEL: void @i128_as_f128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @i128_as_f128({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @i128_as_f128( -// emscripten-LABEL: void @i128_as_f128({{.*}}sret([16 x i8]) -#[no_mangle] -pub fn i128_as_f128(a: i128) -> f128 { - // CHECK: sitofp i128 %{{.+}} to fp128 - a as f128 -} diff --git a/tests/codegen/float/f16-f128-inline.rs b/tests/codegen/float/f16-f128-inline.rs deleted file mode 100644 index aa2c38c209e..00000000000 --- a/tests/codegen/float/f16-f128-inline.rs +++ /dev/null @@ -1,29 +0,0 @@ -//@ revisions: default nopt -//@[nopt] compile-flags: -Copt-level=0 -Zcross-crate-inline-threshold=never -Zmir-opt-level=0 -Cno-prepopulate-passes - -// Ensure that functions using `f16` and `f128` are always inlined to avoid crashes -// when the backend does not support these types. - -#![crate_type = "lib"] -#![feature(f128)] -#![feature(f16)] - -pub fn f16_arg(_a: f16) { - // CHECK-NOT: f16_arg - todo!() -} - -pub fn f16_ret() -> f16 { - // CHECK-NOT: f16_ret - todo!() -} - -pub fn f128_arg(_a: f128) { - // CHECK-NOT: f128_arg - todo!() -} - -pub fn f128_ret() -> f128 { - // CHECK-NOT: f128_ret - todo!() -} diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs deleted file mode 100644 index 0c40606ad8a..00000000000 --- a/tests/codegen/float/f16.rs +++ /dev/null @@ -1,364 +0,0 @@ -// 32-bit x86 returns float types differently to avoid the x87 stack. -// 32-bit systems will return 128bit values using a return area pointer. -//@ revisions: x86-sse x86-nosse bit32 bit64 -//@[x86-sse] only-x86 -//@[x86-sse] only-rustc_abi-x86-sse2 -//@[x86-nosse] only-x86 -//@[x86-nosse] ignore-rustc_abi-x86-sse2 -//@[bit32] ignore-x86 -//@[bit32] only-32bit -//@[bit64] ignore-x86 -//@[bit64] only-64bit - -// Verify that our intrinsics generate the correct LLVM calls for f16 - -#![crate_type = "lib"] -#![feature(f128)] -#![feature(f16)] -#![feature(core_intrinsics)] - -/* arithmetic */ - -// CHECK-LABEL: i1 @f16_eq( -#[no_mangle] -pub fn f16_eq(a: f16, b: f16) -> bool { - // CHECK: fcmp oeq half %{{.+}}, %{{.+}} - a == b -} - -// CHECK-LABEL: i1 @f16_ne( -#[no_mangle] -pub fn f16_ne(a: f16, b: f16) -> bool { - // CHECK: fcmp une half %{{.+}}, %{{.+}} - a != b -} - -// CHECK-LABEL: i1 @f16_gt( -#[no_mangle] -pub fn f16_gt(a: f16, b: f16) -> bool { - // CHECK: fcmp ogt half %{{.+}}, %{{.+}} - a > b -} - -// CHECK-LABEL: i1 @f16_ge( -#[no_mangle] -pub fn f16_ge(a: f16, b: f16) -> bool { - // CHECK: fcmp oge half %{{.+}}, %{{.+}} - a >= b -} - -// CHECK-LABEL: i1 @f16_lt( -#[no_mangle] -pub fn f16_lt(a: f16, b: f16) -> bool { - // CHECK: fcmp olt half %{{.+}}, %{{.+}} - a < b -} - -// CHECK-LABEL: i1 @f16_le( -#[no_mangle] -pub fn f16_le(a: f16, b: f16) -> bool { - // CHECK: fcmp ole half %{{.+}}, %{{.+}} - a <= b -} - -// This is where we check the argument and return ABI for f16. -// bit32-LABEL: half @f16_neg(half -// bit64-LABEL: half @f16_neg(half -// x86-sse-LABEL: <2 x i8> @f16_neg(half -// x86-nosse-LABEL: i16 @f16_neg(half -#[no_mangle] -pub fn f16_neg(a: f16) -> f16 { - // CHECK: fneg half %{{.+}} - -a -} - -// CHECK-LABEL: @f16_add -#[no_mangle] -pub fn f16_add(a: f16, b: f16) -> f16 { - // CHECK: fadd half %{{.+}}, %{{.+}} - a + b -} - -// CHECK-LABEL: @f16_sub -#[no_mangle] -pub fn f16_sub(a: f16, b: f16) -> f16 { - // CHECK: fsub half %{{.+}}, %{{.+}} - a - b -} - -// CHECK-LABEL: @f16_mul -#[no_mangle] -pub fn f16_mul(a: f16, b: f16) -> f16 { - // CHECK: fmul half %{{.+}}, %{{.+}} - a * b -} - -// CHECK-LABEL: @f16_div -#[no_mangle] -pub fn f16_div(a: f16, b: f16) -> f16 { - // CHECK: fdiv half %{{.+}}, %{{.+}} - a / b -} - -// CHECK-LABEL: @f16_rem -#[no_mangle] -pub fn f16_rem(a: f16, b: f16) -> f16 { - // CHECK: frem half %{{.+}}, %{{.+}} - a % b -} - -// CHECK-LABEL: void @f16_add_assign( -#[no_mangle] -pub fn f16_add_assign(a: &mut f16, b: f16) { - // CHECK: fadd half %{{.+}}, %{{.+}} - // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} - *a += b; -} - -// CHECK-LABEL: void @f16_sub_assign( -#[no_mangle] -pub fn f16_sub_assign(a: &mut f16, b: f16) { - // CHECK: fsub half %{{.+}}, %{{.+}} - // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} - *a -= b; -} - -// CHECK-LABEL: void @f16_mul_assign( -#[no_mangle] -pub fn f16_mul_assign(a: &mut f16, b: f16) { - // CHECK: fmul half %{{.+}}, %{{.+}} - // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} - *a *= b; -} - -// CHECK-LABEL: void @f16_div_assign( -#[no_mangle] -pub fn f16_div_assign(a: &mut f16, b: f16) { - // CHECK: fdiv half %{{.+}}, %{{.+}} - // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} - *a /= b; -} - -// CHECK-LABEL: void @f16_rem_assign( -#[no_mangle] -pub fn f16_rem_assign(a: &mut f16, b: f16) { - // CHECK: frem half %{{.+}}, %{{.+}} - // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} - *a %= b; -} - -/* float to float conversions */ - -// bit32-LABEL: half @f16_as_self( -// bit64-LABEL: half @f16_as_self( -// x86-sse-LABEL: <2 x i8> @f16_as_self( -// x86-nosse-LABEL: i16 @f16_as_self( -#[no_mangle] -pub fn f16_as_self(a: f16) -> f16 { - // bit32-CHECK: ret half %{{.+}} - // bit64-CHECK: ret half %{{.+}} - // x86-sse-CHECK: bitcast half - // x86-nosse-CHECK: bitcast half - // x86-sse-CHECK: ret i16 - // x86-nosse-CHECK: ret i16 - a as f16 -} - -// x86-sse-LABEL: <4 x i8> @f16_as_f32( -// x86-nosse-LABEL: i32 @f16_as_f32( -// bit32-LABEL: float @f16_as_f32( -// bit64-LABEL: float @f16_as_f32( -#[no_mangle] -pub fn f16_as_f32(a: f16) -> f32 { - // CHECK: fpext half %{{.+}} to float - a as f32 -} - -// x86-sse-LABEL: <8 x i8> @f16_as_f64( -// x86-nosse-LABEL: void @f16_as_f64({{.*}}sret([8 x i8]) -// bit32-LABEL: double @f16_as_f64( -// bit64-LABEL: double @f16_as_f64( -#[no_mangle] -pub fn f16_as_f64(a: f16) -> f64 { - // CHECK: fpext half %{{.+}} to double - a as f64 -} - -// x86-sse-LABEL: <16 x i8> @f16_as_f128( -// x86-nosse-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) -// bit64-LABEL: fp128 @f16_as_f128( -#[no_mangle] -pub fn f16_as_f128(a: f16) -> f128 { - // CHECK: fpext half %{{.+}} to fp128 - a as f128 -} - -// CHECK-LABEL: @f32_as_f16 -#[no_mangle] -pub fn f32_as_f16(a: f32) -> f16 { - // CHECK: fptrunc float %{{.+}} to half - a as f16 -} - -// CHECK-LABEL: @f64_as_f16 -#[no_mangle] -pub fn f64_as_f16(a: f64) -> f16 { - // CHECK: fptrunc double %{{.+}} to half - a as f16 -} - -// CHECK-LABEL: @f128_as_f16 -#[no_mangle] -pub fn f128_as_f16(a: f128) -> f16 { - // CHECK: fptrunc fp128 %{{.+}} to half - a as f16 -} - -/* float to int conversions */ - -// CHECK-LABEL: i8 @f16_as_u8( -#[no_mangle] -pub fn f16_as_u8(a: f16) -> u8 { - // CHECK: call i8 @llvm.fptoui.sat.i8.f16(half %{{.+}}) - a as u8 -} - -#[no_mangle] -pub fn f16_as_u16(a: f16) -> u16 { - // CHECK: call i16 @llvm.fptoui.sat.i16.f16(half %{{.+}}) - a as u16 -} - -// CHECK-LABEL: i32 @f16_as_u32( -#[no_mangle] -pub fn f16_as_u32(a: f16) -> u32 { - // CHECK: call i32 @llvm.fptoui.sat.i32.f16(half %{{.+}}) - a as u32 -} - -// CHECK-LABEL: i64 @f16_as_u64( -#[no_mangle] -pub fn f16_as_u64(a: f16) -> u64 { - // CHECK: call i64 @llvm.fptoui.sat.i64.f16(half %{{.+}}) - a as u64 -} - -// x86-sse-LABEL: void @f16_as_u128({{.*}}sret([16 x i8]) -// x86-nosse-LABEL: void @f16_as_u128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @f16_as_u128({{.*}}sret([16 x i8]) -// bit64-LABEL: i128 @f16_as_u128( -#[no_mangle] -pub fn f16_as_u128(a: f16) -> u128 { - // CHECK: call i128 @llvm.fptoui.sat.i128.f16(half %{{.+}}) - a as u128 -} - -// CHECK-LABEL: i8 @f16_as_i8( -#[no_mangle] -pub fn f16_as_i8(a: f16) -> i8 { - // CHECK: call i8 @llvm.fptosi.sat.i8.f16(half %{{.+}}) - a as i8 -} - -// CHECK-LABEL: i16 @f16_as_i16( -#[no_mangle] -pub fn f16_as_i16(a: f16) -> i16 { - // CHECK: call i16 @llvm.fptosi.sat.i16.f16(half %{{.+}}) - a as i16 -} -// CHECK-LABEL: i32 @f16_as_i32( -#[no_mangle] -pub fn f16_as_i32(a: f16) -> i32 { - // CHECK: call i32 @llvm.fptosi.sat.i32.f16(half %{{.+}}) - a as i32 -} - -// CHECK-LABEL: i64 @f16_as_i64( -#[no_mangle] -pub fn f16_as_i64(a: f16) -> i64 { - // CHECK: call i64 @llvm.fptosi.sat.i64.f16(half %{{.+}}) - a as i64 -} - -// x86-sse-LABEL: void @f16_as_i128({{.*}}sret([16 x i8]) -// x86-nosse-LABEL: void @f16_as_i128({{.*}}sret([16 x i8]) -// bit32-LABEL: void @f16_as_i128({{.*}}sret([16 x i8]) -// bit64-LABEL: i128 @f16_as_i128( -#[no_mangle] -pub fn f16_as_i128(a: f16) -> i128 { - // CHECK: call i128 @llvm.fptosi.sat.i128.f16(half %{{.+}}) - a as i128 -} - -/* int to float conversions */ - -// CHECK-LABEL: @u8_as_f16 -#[no_mangle] -pub fn u8_as_f16(a: u8) -> f16 { - // CHECK: uitofp i8 %{{.+}} to half - a as f16 -} - -// CHECK-LABEL: @u16_as_f16 -#[no_mangle] -pub fn u16_as_f16(a: u16) -> f16 { - // CHECK: uitofp i16 %{{.+}} to half - a as f16 -} - -// CHECK-LABEL: @u32_as_f16 -#[no_mangle] -pub fn u32_as_f16(a: u32) -> f16 { - // CHECK: uitofp i32 %{{.+}} to half - a as f16 -} - -// CHECK-LABEL: @u64_as_f16 -#[no_mangle] -pub fn u64_as_f16(a: u64) -> f16 { - // CHECK: uitofp i64 %{{.+}} to half - a as f16 -} - -// CHECK-LABEL: @u128_as_f16 -#[no_mangle] -pub fn u128_as_f16(a: u128) -> f16 { - // CHECK: uitofp i128 %{{.+}} to half - a as f16 -} - -// CHECK-LABEL: @i8_as_f16 -#[no_mangle] -pub fn i8_as_f16(a: i8) -> f16 { - // CHECK: sitofp i8 %{{.+}} to half - a as f16 -} - -// CHECK-LABEL: @i16_as_f16 -#[no_mangle] -pub fn i16_as_f16(a: i16) -> f16 { - // CHECK: sitofp i16 %{{.+}} to half - a as f16 -} - -// CHECK-LABEL: @i32_as_f16 -#[no_mangle] -pub fn i32_as_f16(a: i32) -> f16 { - // CHECK: sitofp i32 %{{.+}} to half - a as f16 -} - -// CHECK-LABEL: @i64_as_f16 -#[no_mangle] -pub fn i64_as_f16(a: i64) -> f16 { - // CHECK: sitofp i64 %{{.+}} to half - a as f16 -} - -// CHECK-LABEL: @i128_as_f16 -#[no_mangle] -pub fn i128_as_f16(a: i128) -> f16 { - // CHECK: sitofp i128 %{{.+}} to half - a as f16 -} diff --git a/tests/codegen/float_math.rs b/tests/codegen/float_math.rs deleted file mode 100644 index 9a1e0b4d2d0..00000000000 --- a/tests/codegen/float_math.rs +++ /dev/null @@ -1,87 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::{ - fadd_algebraic, fadd_fast, fdiv_algebraic, fdiv_fast, fmul_algebraic, fmul_fast, - frem_algebraic, frem_fast, fsub_algebraic, fsub_fast, -}; - -// CHECK-LABEL: @add -#[no_mangle] -pub fn add(x: f32, y: f32) -> f32 { - // CHECK: fadd float - // CHECK-NOT: fast - x + y -} - -// CHECK-LABEL: @test_fadd_algebraic -#[no_mangle] -pub fn test_fadd_algebraic(x: f32, y: f32) -> f32 { - // CHECK: fadd reassoc nsz arcp contract float %x, %y - fadd_algebraic(x, y) -} - -// CHECK-LABEL: @test_fsub_algebraic -#[no_mangle] -pub fn test_fsub_algebraic(x: f32, y: f32) -> f32 { - // CHECK: fsub reassoc nsz arcp contract float %x, %y - fsub_algebraic(x, y) -} - -// CHECK-LABEL: @test_fmul_algebraic -#[no_mangle] -pub fn test_fmul_algebraic(x: f32, y: f32) -> f32 { - // CHECK: fmul reassoc nsz arcp contract float %x, %y - fmul_algebraic(x, y) -} - -// CHECK-LABEL: @test_fdiv_algebraic -#[no_mangle] -pub fn test_fdiv_algebraic(x: f32, y: f32) -> f32 { - // CHECK: fdiv reassoc nsz arcp contract float %x, %y - fdiv_algebraic(x, y) -} - -// CHECK-LABEL: @test_frem_algebraic -#[no_mangle] -pub fn test_frem_algebraic(x: f32, y: f32) -> f32 { - // CHECK: frem reassoc nsz arcp contract float %x, %y - frem_algebraic(x, y) -} - -// CHECK-LABEL: @test_fadd_fast -#[no_mangle] -pub fn test_fadd_fast(x: f32, y: f32) -> f32 { - // CHECK: fadd fast float %x, %y - unsafe { fadd_fast(x, y) } -} - -// CHECK-LABEL: @test_fsub_fast -#[no_mangle] -pub fn test_fsub_fast(x: f32, y: f32) -> f32 { - // CHECK: fsub fast float %x, %y - unsafe { fsub_fast(x, y) } -} - -// CHECK-LABEL: @test_fmul_fast -#[no_mangle] -pub fn test_fmul_fast(x: f32, y: f32) -> f32 { - // CHECK: fmul fast float %x, %y - unsafe { fmul_fast(x, y) } -} - -// CHECK-LABEL: @test_fdiv_fast -#[no_mangle] -pub fn test_fdiv_fast(x: f32, y: f32) -> f32 { - // CHECK: fdiv fast float %x, %y - unsafe { fdiv_fast(x, y) } -} - -// CHECK-LABEL: @test_frem_fast -#[no_mangle] -pub fn test_frem_fast(x: f32, y: f32) -> f32 { - // CHECK: frem fast float %x, %y - unsafe { frem_fast(x, y) } -} diff --git a/tests/codegen/fn-impl-trait-self.rs b/tests/codegen/fn-impl-trait-self.rs deleted file mode 100644 index 5799d23b5a0..00000000000 --- a/tests/codegen/fn-impl-trait-self.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ compile-flags: -g -//@ ignore-wasi wasi codegens the main symbol differently -// -// CHECK-LABEL: @main -// MSVC: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "recursive_type$ (*)()",{{.*}} -// NONMSVC: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "fn() -> ",{{.*}} -// -// CHECK: {{.*}}DISubroutineType{{.*}} -// CHECK: {{.*}}DIBasicType(name: "", size: {{32|64}}, encoding: DW_ATE_unsigned) - -pub fn foo() -> impl Copy { - foo -} - -fn main() { - let my_res = foo(); -} diff --git a/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs b/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs deleted file mode 100644 index 2097567f322..00000000000 --- a/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! Make sure that line debuginfo of function parameters are correct even if -//! they are not on the same line. Regression test for -// . - -//@ compile-flags: -g -Copt-level=0 - -#[rustfmt::skip] // Having parameters on different lines is crucial for this test. -pub fn foo( - x_parameter_not_in_std: i32, - y_parameter_not_in_std: i32, -) -> i32 { - x_parameter_not_in_std + y_parameter_not_in_std -} - -fn main() { - foo(42, 43); // Ensure `wasm32-wasip1` keeps `foo()` (even if `-Copt-level=0`) -} - -// CHECK: !DILocalVariable(name: "x_parameter_not_in_std", arg: 1, -// CHECK-SAME: line: 9 -// CHECK: !DILocalVariable(name: "y_parameter_not_in_std", arg: 2, -// CHECK-SAME: line: 10 diff --git a/tests/codegen/force-frame-pointers.rs b/tests/codegen/force-frame-pointers.rs deleted file mode 100644 index 88c918945d6..00000000000 --- a/tests/codegen/force-frame-pointers.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ revisions: Always NonLeaf -//@ [Always] compile-flags: -Cforce-frame-pointers=yes -//@ [NonLeaf] compile-flags: -Cforce-frame-pointers=non-leaf -//@ compile-flags: -Zunstable-options -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -//@ [NonLeaf] ignore-illumos -//@ [NonLeaf] ignore-openbsd -//@ [NonLeaf] ignore-x86 -//@ [NonLeaf] ignore-x86_64-apple-darwin -//@ [NonLeaf] ignore-windows-gnu -//@ [NonLeaf] ignore-thumb -// result is platform-dependent based on platform's frame pointer settings - -#![crate_type = "lib"] - -// Always: attributes #{{.*}} "frame-pointer"="all" -// NonLeaf: attributes #{{.*}} "frame-pointer"="non-leaf" -pub fn foo() {} diff --git a/tests/codegen/force-no-unwind-tables.rs b/tests/codegen/force-no-unwind-tables.rs deleted file mode 100644 index 1de5e0858e0..00000000000 --- a/tests/codegen/force-no-unwind-tables.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -C panic=abort -C force-unwind-tables=n -//@ ignore-windows: unwind tables are required for panics on Windows - -#![crate_type = "lib"] - -// CHECK-LABEL: define{{.*}}void @foo -// CHECK-NOT: attributes #{{.*}} uwtable -#[no_mangle] -fn foo() { - panic!(); -} diff --git a/tests/codegen/force-unwind-tables.rs b/tests/codegen/force-unwind-tables.rs deleted file mode 100644 index a2ef8a10454..00000000000 --- a/tests/codegen/force-unwind-tables.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -C force-unwind-tables=y -Copt-level=0 - -#![crate_type = "lib"] - -// CHECK: attributes #{{.*}} uwtable -pub fn foo() {} diff --git a/tests/codegen/frame-pointer-cli-control.rs b/tests/codegen/frame-pointer-cli-control.rs deleted file mode 100644 index a65dd132763..00000000000 --- a/tests/codegen/frame-pointer-cli-control.rs +++ /dev/null @@ -1,61 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: --crate-type=rlib -Copt-level=0 -//@ revisions: force-on aarch64-apple aarch64-apple-on aarch64-apple-off -//@ [force-on] compile-flags: -Cforce-frame-pointers=on -//@ [aarch64-apple] needs-llvm-components: aarch64 -//@ [aarch64-apple] compile-flags: --target=aarch64-apple-darwin -//@ [aarch64-apple-on] needs-llvm-components: aarch64 -//@ [aarch64-apple-on] compile-flags: --target=aarch64-apple-darwin -Cforce-frame-pointers=on -//@ [aarch64-apple-off] needs-llvm-components: aarch64 -//@ [aarch64-apple-off] compile-flags: --target=aarch64-apple-darwin -Cforce-frame-pointers=off -/*! - -Tests the extent to which frame pointers can be controlled by the CLI. -The behavior of our frame pointer options, at present, is an irreversible ratchet, where -a "weaker" option that allows omitting frame pointers may be overridden by the target demanding -that all code (or all non-leaf code, more often) must be compiled with frame pointers. -This was discussed on 2025-05-22 in the T-compiler meeting and accepted as an intentional change, -ratifying the prior decisions by compiler contributors and reviewers as correct, -though it was also acknowledged that the flag allows somewhat confusing inputs. - -We find aarch64-apple-darwin useful because of its icy-clear policy regarding frame pointers, -e.g. says: - -* The frame pointer register (x29) must always address a valid frame record. Some functions — - such as leaf functions or tail calls — may opt not to create an entry in this list. - As a result, stack traces are always meaningful, even without debug information. - -Many Rust fn, if externally visible, may be expected to follow target ABI by tools or asm code! -This can make it a problem to generate ABI-incorrect code, which may mean "with frame pointers". -For this and other reasons, `-Cforce-frame-pointers=off` cannot override the target definition. -This can cause some confusion because it is "reverse polarity" relative to C compilers, which have -commands like `-fomit-frame-pointer`, `-fomit-leaf-frame-pointer`, or `-fno-omit-frame-pointer`! - -Specific cases where platforms or tools rely on frame pointers for sound or correct unwinding: -- illumos: -- aarch64-windows: -- aarch64-linux: -- dtrace (freebsd and openbsd): -- openbsd: -- i686-msvc -- i686-mingw: -*/ -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; - -// CHECK: i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] { -#[no_mangle] -pub fn peach(x: u32) -> u32 { - x -} - -// CHECK: attributes [[PEACH_ATTRS]] = { -// force-on-SAME: {{.*}}"frame-pointer"="all" -// aarch64-apple-SAME: {{.*}}"frame-pointer"="non-leaf" -// aarch64-apple-on-SAME: {{.*}}"frame-pointer"="all" -// -// yes, we are testing this doesn't do anything: -// aarch64-apple-off-SAME: {{.*}}"frame-pointer"="non-leaf" -// CHECK-SAME: } diff --git a/tests/codegen/frame-pointer.rs b/tests/codegen/frame-pointer.rs deleted file mode 100644 index 23989653fa8..00000000000 --- a/tests/codegen/frame-pointer.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: --crate-type=rlib -Copt-level=0 -//@ revisions: aarch64-apple aarch64-linux force x64-apple x64-linux -//@ [aarch64-apple] needs-llvm-components: aarch64 -//@ [aarch64-apple] compile-flags: --target=aarch64-apple-darwin -//@ [aarch64-linux] needs-llvm-components: aarch64 -//@ [aarch64-linux] compile-flags: --target=aarch64-unknown-linux-gnu -//@ [force] needs-llvm-components: x86 -//@ [force] compile-flags: --target=x86_64-unknown-linux-gnu -Cforce-frame-pointers=yes -//@ [x64-apple] needs-llvm-components: x86 -//@ [x64-apple] compile-flags: --target=x86_64-apple-darwin -//@ [x64-linux] needs-llvm-components: x86 -//@ [x64-linux] compile-flags: --target=x86_64-unknown-linux-gnu - -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK: define i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] { -#[no_mangle] -pub fn peach(x: u32) -> u32 { - x -} - -// CHECK: attributes [[PEACH_ATTRS]] = { -// x64-linux-NOT: {{.*}}"frame-pointer"{{.*}} -// x64-apple-SAME: {{.*}}"frame-pointer"="all" -// force-SAME: {{.*}}"frame-pointer"="all" -// -// AAPCS64 demands frame pointers: -// aarch64-linux-SAME: {{.*}}"frame-pointer"="non-leaf" -// aarch64-apple-SAME: {{.*}}"frame-pointer"="non-leaf" -// CHECK-SAME: } diff --git a/tests/codegen/function-arguments-noopt.rs b/tests/codegen/function-arguments-noopt.rs deleted file mode 100644 index c80f119696d..00000000000 --- a/tests/codegen/function-arguments-noopt.rs +++ /dev/null @@ -1,69 +0,0 @@ -//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes - -// This test checks that arguments/returns in opt-level=0 builds, -// while lacking attributes used for optimization, still have ABI-affecting attributes. - -#![crate_type = "lib"] -#![feature(rustc_attrs)] - -pub struct S { - _field: [i32; 8], -} - -// CHECK: zeroext i1 @boolean(i1 zeroext %x) -#[no_mangle] -pub fn boolean(x: bool) -> bool { - x -} - -// CHECK-LABEL: @boolean_call -#[no_mangle] -pub fn boolean_call(x: bool, f: fn(bool) -> bool) -> bool { - // CHECK: call zeroext i1 %f(i1 zeroext %x) - f(x) -} - -// CHECK: align 4 ptr @borrow(ptr align 4 %x) -#[no_mangle] -pub fn borrow(x: &i32) -> &i32 { - x -} - -// CHECK: align 4 ptr @borrow_mut(ptr align 4 %x) -#[no_mangle] -pub fn borrow_mut(x: &mut i32) -> &mut i32 { - x -} - -// CHECK-LABEL: @borrow_call -#[no_mangle] -pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 { - // CHECK: call align 4 ptr %f(ptr align 4 %x) - f(x) -} - -// CHECK: void @struct_(ptr sret([32 x i8]) align 4{{( %_0)?}}, ptr align 4 %x) -#[no_mangle] -pub fn struct_(x: S) -> S { - x -} - -// CHECK-LABEL: @struct_call -#[no_mangle] -pub fn struct_call(x: S, f: fn(S) -> S) -> S { - // CHECK: call void %f(ptr sret([32 x i8]) align 4{{( %_0)?}}, ptr align 4 %{{.+}}) - f(x) -} - -// CHECK: { i1, i8 } @enum_(i1 zeroext %x.0, i8 %x.1) -#[no_mangle] -pub fn enum_(x: Option) -> Option { - x -} - -// CHECK-LABEL: @enum_call -#[no_mangle] -pub fn enum_call(x: Option, f: fn(Option) -> Option) -> Option { - // CHECK: call { i1, i8 } %f(i1 zeroext %x.0, i8 %x.1) - f(x) -} diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs deleted file mode 100644 index c8cd8526ae5..00000000000 --- a/tests/codegen/function-arguments.rs +++ /dev/null @@ -1,278 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -#![crate_type = "lib"] -#![feature(rustc_attrs)] -#![feature(allocator_api)] - -use std::marker::PhantomPinned; -use std::mem::MaybeUninit; -use std::num::NonZero; -use std::ptr::NonNull; - -pub struct S { - _field: [i32; 8], -} - -pub struct UnsafeInner { - _field: std::cell::UnsafeCell, -} - -pub struct NotUnpin { - _field: i32, - _marker: PhantomPinned, -} - -pub enum MyBool { - True, - False, -} - -// CHECK: noundef zeroext i1 @boolean(i1 noundef zeroext %x) -#[no_mangle] -pub fn boolean(x: bool) -> bool { - x -} - -// CHECK: i8 @maybeuninit_boolean(i8{{.*}} %x) -#[no_mangle] -pub fn maybeuninit_boolean(x: MaybeUninit) -> MaybeUninit { - x -} - -// CHECK: noundef zeroext i1 @enum_bool(i1 noundef zeroext %x) -#[no_mangle] -pub fn enum_bool(x: MyBool) -> MyBool { - x -} - -// CHECK: i8 @maybeuninit_enum_bool(i8{{.*}} %x) -#[no_mangle] -pub fn maybeuninit_enum_bool(x: MaybeUninit) -> MaybeUninit { - x -} - -// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32{{.*}}{{( range\(i32 0, 1114112\))?}} %x) -#[no_mangle] -pub fn char(x: char) -> char { - x -} - -// CHECK: i32 @maybeuninit_char(i32{{.*}} %x) -#[no_mangle] -pub fn maybeuninit_char(x: MaybeUninit) -> MaybeUninit { - x -} - -// CHECK: noundef i64 @int(i64 noundef %x) -#[no_mangle] -pub fn int(x: u64) -> u64 { - x -} - -// CHECK: noundef{{( range\(i64 1, 0\))?}} i64 @nonzero_int(i64 noundef{{( range\(i64 1, 0\))?}} %x) -#[no_mangle] -pub fn nonzero_int(x: NonZero) -> NonZero { - x -} - -// CHECK: noundef i64 @option_nonzero_int(i64 noundef %x) -#[no_mangle] -pub fn option_nonzero_int(x: Option>) -> Option> { - x -} - -// CHECK: @readonly_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1) -// FIXME #25759 This should also have `nocapture` -#[no_mangle] -pub fn readonly_borrow(_: &i32) {} - -// CHECK: noundef align 4 dereferenceable(4) ptr @readonly_borrow_ret() -#[no_mangle] -pub fn readonly_borrow_ret() -> &'static i32 { - loop {} -} - -// CHECK: @static_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1) -// static borrow may be captured -#[no_mangle] -pub fn static_borrow(_: &'static i32) {} - -// CHECK: @named_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1) -// borrow with named lifetime may be captured -#[no_mangle] -pub fn named_borrow<'r>(_: &'r i32) {} - -// CHECK: @unsafe_borrow(ptr noundef nonnull align 2 %_1) -// unsafe interior means this isn't actually readonly and there may be aliases ... -#[no_mangle] -pub fn unsafe_borrow(_: &UnsafeInner) {} - -// CHECK: @mutable_unsafe_borrow(ptr noalias noundef align 2 dereferenceable(2) %_1) -// ... unless this is a mutable borrow, those never alias -#[no_mangle] -pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {} - -// CHECK: @mutable_borrow(ptr noalias noundef align 4 dereferenceable(4) %_1) -// FIXME #25759 This should also have `nocapture` -#[no_mangle] -pub fn mutable_borrow(_: &mut i32) {} - -// CHECK: noundef align 4 dereferenceable(4) ptr @mutable_borrow_ret() -#[no_mangle] -pub fn mutable_borrow_ret() -> &'static mut i32 { - loop {} -} - -#[no_mangle] -// CHECK: @mutable_notunpin_borrow(ptr noundef nonnull align 4 %_1) -// This one is *not* `noalias` because it might be self-referential. -// It is also not `dereferenceable` due to -// . -pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {} - -// CHECK: @notunpin_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1) -// But `&NotUnpin` behaves perfectly normal. -#[no_mangle] -pub fn notunpin_borrow(_: &NotUnpin) {} - -// CHECK: @indirect_struct(ptr noalias{{( nocapture)?}} noundef readonly align 4{{( captures\(none\))?}} dereferenceable(32) %_1) -#[no_mangle] -pub fn indirect_struct(_: S) {} - -// CHECK: @borrowed_struct(ptr noalias noundef readonly align 4 dereferenceable(32) %_1) -// FIXME #25759 This should also have `nocapture` -#[no_mangle] -pub fn borrowed_struct(_: &S) {} - -// CHECK: @option_borrow(ptr noalias noundef readonly align 4 dereferenceable_or_null(4) %_x) -#[no_mangle] -pub fn option_borrow(_x: Option<&i32>) {} - -// CHECK: @option_borrow_mut(ptr noalias noundef align 4 dereferenceable_or_null(4) %_x) -#[no_mangle] -pub fn option_borrow_mut(_x: Option<&mut i32>) {} - -// Function that must NOT have `dereferenceable` or `align`. -#[rustc_layout_scalar_valid_range_start(16)] -pub struct RestrictedAddress(&'static i16); -enum E { - A(RestrictedAddress), - B, - C, -} -// If the `nonnull` ever goes missing, you might have to tweak the -// scalar_valid_range on `RestrictedAddress` to get it back. You -// might even have to add a `rustc_layout_scalar_valid_range_end`. -// CHECK: @nonnull_and_nondereferenceable(ptr noundef nonnull %_x) -#[no_mangle] -pub fn nonnull_and_nondereferenceable(_x: E) {} - -// CHECK: @raw_struct(ptr noundef %_1) -#[no_mangle] -pub fn raw_struct(_: *const S) {} - -// CHECK: @raw_option_nonnull_struct(ptr noundef %_1) -#[no_mangle] -pub fn raw_option_nonnull_struct(_: Option>) {} - -// `Box` can get deallocated during execution of the function, so it should -// not get `dereferenceable`. -// CHECK: noundef nonnull align 4 ptr @_box(ptr noalias noundef nonnull align 4 %x) -#[no_mangle] -pub fn _box(x: Box) -> Box { - x -} - -// With a custom allocator, it should *not* have `noalias`. (See -// for why.) The second argument is the allocator, -// which is a reference here that still carries `noalias` as usual. -// CHECK: @_box_custom(ptr noundef nonnull align 4 %x.0, ptr noalias noundef nonnull readonly align 1 %x.1) -#[no_mangle] -pub fn _box_custom(x: Box) { - drop(x) -} - -// CHECK: noundef nonnull align 4 ptr @notunpin_box(ptr noundef nonnull align 4 %x) -#[no_mangle] -pub fn notunpin_box(x: Box) -> Box { - x -} - -// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias{{( nocapture)?}} noundef{{( writable)?}} sret([32 x i8]) align 4{{( captures\(none\))?}} dereferenceable(32){{( %_0)?}}) -#[no_mangle] -pub fn struct_return() -> S { - S { _field: [0, 0, 0, 0, 0, 0, 0, 0] } -} - -// Hack to get the correct size for the length part in slices -// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1) -#[no_mangle] -pub fn helper(_: usize) {} - -// CHECK: @slice(ptr noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1) -// FIXME #25759 This should also have `nocapture` -#[no_mangle] -pub fn slice(_: &[u8]) {} - -// CHECK: @mutable_slice(ptr noalias noundef nonnull align 1 %_1.0, [[USIZE]] noundef %_1.1) -// FIXME #25759 This should also have `nocapture` -#[no_mangle] -pub fn mutable_slice(_: &mut [u8]) {} - -// CHECK: @unsafe_slice(ptr noundef nonnull align 2 %_1.0, [[USIZE]] noundef %_1.1) -// unsafe interior means this isn't actually readonly and there may be aliases ... -#[no_mangle] -pub fn unsafe_slice(_: &[UnsafeInner]) {} - -// CHECK: @raw_slice(ptr noundef %_1.0, [[USIZE]] noundef %_1.1) -#[no_mangle] -pub fn raw_slice(_: *const [u8]) {} - -// CHECK: @str(ptr noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1) -// FIXME #25759 This should also have `nocapture` -#[no_mangle] -pub fn str(_: &[u8]) {} - -// CHECK: @trait_borrow(ptr noundef nonnull align 1 %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1) -// FIXME #25759 This should also have `nocapture` -#[no_mangle] -pub fn trait_borrow(_: &dyn Drop) {} - -// CHECK: @option_trait_borrow(ptr noundef align 1 %x.0, ptr %x.1) -#[no_mangle] -pub fn option_trait_borrow(x: Option<&dyn Drop>) {} - -// CHECK: @option_trait_borrow_mut(ptr noundef align 1 %x.0, ptr %x.1) -#[no_mangle] -pub fn option_trait_borrow_mut(x: Option<&mut dyn Drop>) {} - -// CHECK: @trait_raw(ptr noundef %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1) -#[no_mangle] -pub fn trait_raw(_: *const dyn Drop) {} - -// CHECK: @trait_box(ptr noalias noundef nonnull align 1{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}}) -#[no_mangle] -pub fn trait_box(_: Box) {} - -// CHECK: { ptr, ptr } @trait_option(ptr noalias noundef align 1 %x.0, ptr %x.1) -#[no_mangle] -pub fn trait_option(x: Option>) -> Option> { - x -} - -// CHECK: { ptr, [[USIZE]] } @return_slice(ptr noalias noundef nonnull readonly align 2 %x.0, [[USIZE]] noundef %x.1) -#[no_mangle] -pub fn return_slice(x: &[u16]) -> &[u16] { - x -} - -// CHECK: { i16, i16 } @enum_id_1(i16 noundef{{( range\(i16 0, 3\))?}} %x.0, i16 %x.1) -#[no_mangle] -pub fn enum_id_1(x: Option>) -> Option> { - x -} - -// CHECK: { i1, i8 } @enum_id_2(i1 noundef zeroext %x.0, i8 %x.1) -#[no_mangle] -pub fn enum_id_2(x: Option) -> Option { - x -} diff --git a/tests/codegen/function-return.rs b/tests/codegen/function-return.rs deleted file mode 100644 index 4127f516038..00000000000 --- a/tests/codegen/function-return.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Test that the `fn_ret_thunk_extern` function attribute is (not) emitted when -// the `-Zfunction-return={keep,thunk-extern}` flag is (not) set. - -//@ add-core-stubs -//@ revisions: unset keep thunk-extern keep-thunk-extern thunk-extern-keep -//@ needs-llvm-components: x86 -//@ compile-flags: --target x86_64-unknown-linux-gnu -//@ [keep] compile-flags: -Zfunction-return=keep -//@ [thunk-extern] compile-flags: -Zfunction-return=thunk-extern -//@ [keep-thunk-extern] compile-flags: -Zfunction-return=keep -Zfunction-return=thunk-extern -//@ [thunk-extern-keep] compile-flags: -Zfunction-return=thunk-extern -Zfunction-return=keep - -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[no_mangle] -pub fn foo() { - // CHECK: @foo() unnamed_addr #0 - - // unset-NOT: fn_ret_thunk_extern - // keep-NOT: fn_ret_thunk_extern - // thunk-extern: attributes #0 = { {{.*}}fn_ret_thunk_extern{{.*}} } - // keep-thunk-extern: attributes #0 = { {{.*}}fn_ret_thunk_extern{{.*}} } - // thunk-extern-keep-NOT: fn_ret_thunk_extern -} - -// unset-NOT: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} -// keep-NOT: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} -// thunk-extern: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} -// keep-thunk-extern: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} -// thunk-extern-keep-NOT: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} diff --git a/tests/codegen/gdb_debug_script_load.rs b/tests/codegen/gdb_debug_script_load.rs deleted file mode 100644 index 3e92eba10b1..00000000000 --- a/tests/codegen/gdb_debug_script_load.rs +++ /dev/null @@ -1,37 +0,0 @@ -// -//@ ignore-windows -//@ ignore-apple -//@ ignore-wasm -//@ ignore-emscripten - -//@ compile-flags: -g -C no-prepopulate-passes -Cpanic=abort - -#![feature(lang_items)] -#![no_std] - -#[panic_handler] -fn panic_handler(_: &core::panic::PanicInfo) -> ! { - loop {} -} - -#[no_mangle] -extern "C" fn rust_eh_personality() { - loop {} -} - -// Needs rustc to generate `main` as that's where the magic load is inserted. -// IOW, we cannot write this test with `#![no_main]`. -// CHECK-LABEL: @main -// CHECK: load volatile i8, {{.+}} @__rustc_debug_gdb_scripts_section__ - -#[lang = "start"] -fn lang_start( - _main: fn() -> T, - _argc: isize, - _argv: *const *const u8, - _sigpipe: u8, -) -> isize { - return 0; -} - -fn main() {} diff --git a/tests/codegen/generic-debug.rs b/tests/codegen/generic-debug.rs deleted file mode 100644 index 0ad0b074657..00000000000 --- a/tests/codegen/generic-debug.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ ignore-wasi wasi codegens the main symbol differently - -//@ compile-flags: -g -C no-prepopulate-passes - -// CHECK-LABEL: @main -// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_structure_type,{{.*}}name: "Generic",{{.*}} -// CHECK: {{.*}}DITemplateTypeParameter{{.*}}name: "Type",{{.*}} - -#![allow(dead_code)] -#![allow(unused_variables)] -#![allow(unused_assignments)] - -pub struct Generic(Type); - -fn main() { - let generic = Generic(10); -} diff --git a/tests/codegen/gep-index.rs b/tests/codegen/gep-index.rs deleted file mode 100644 index bfb2511af87..00000000000 --- a/tests/codegen/gep-index.rs +++ /dev/null @@ -1,37 +0,0 @@ -//! Check that index and offset use the same getelementptr format. - -//@ revisions: NO-OPT OPT -//@[NO-OPT] compile-flags: -Copt-level=0 -//@[OPT] compile-flags: -Copt-level=1 - -#![crate_type = "lib"] - -struct Foo(i32, i32); - -// CHECK-LABEL: @index_on_struct( -#[no_mangle] -fn index_on_struct(a: &[Foo], index: usize) -> &Foo { - // CHECK: getelementptr inbounds{{( nuw)?}} %Foo, ptr %a.0, {{i64|i32}} %index - &a[index] -} - -// CHECK-LABEL: @offset_on_struct( -#[no_mangle] -fn offset_on_struct(a: *const Foo, index: usize) -> *const Foo { - // CHECK: getelementptr inbounds{{( nuw)?}} %Foo, ptr %a, {{i64|i32}} %index - unsafe { a.add(index) } -} - -// CHECK-LABEL: @index_on_i32( -#[no_mangle] -fn index_on_i32(a: &[i32], index: usize) -> &i32 { - // CHECK: getelementptr inbounds{{( nuw)?}} i32, ptr %a.0, {{i64|i32}} %index - &a[index] -} - -// CHECK-LABEL: @offset_on_i32( -#[no_mangle] -fn offset_on_i32(a: *const i32, index: usize) -> *const i32 { - // CHECK: getelementptr inbounds{{( nuw)?}} i32, ptr %a, {{i64|i32}} %index - unsafe { a.add(index) } -} diff --git a/tests/codegen/gpu-kernel-abi.rs b/tests/codegen/gpu-kernel-abi.rs deleted file mode 100644 index 8ac376d9338..00000000000 --- a/tests/codegen/gpu-kernel-abi.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Checks that the gpu-kernel calling convention correctly translates to LLVM calling conventions. - -//@ add-core-stubs -//@ revisions: nvptx -//@ [nvptx] compile-flags: --crate-type=rlib --target=nvptx64-nvidia-cuda -//@ [nvptx] needs-llvm-components: nvptx -#![feature(no_core, lang_items, abi_gpu_kernel)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// nvptx: define ptx_kernel void @fun(i32 -#[no_mangle] -pub extern "gpu-kernel" fn fun(_: i32) {} diff --git a/tests/codegen/gpu_offload/gpu_host.rs b/tests/codegen/gpu_offload/gpu_host.rs deleted file mode 100644 index 513e27426bc..00000000000 --- a/tests/codegen/gpu_offload/gpu_host.rs +++ /dev/null @@ -1,80 +0,0 @@ -//@ compile-flags: -Zoffload=Enable -Zunstable-options -C opt-level=3 -Clto=fat -//@ no-prefer-dynamic -//@ needs-enzyme - -// This test is verifying that we generate __tgt_target_data_*_mapper before and after a call to the -// kernel_1. Better documentation to what each global or variable means is available in the gpu -// offlaod code, or the LLVM offload documentation. This code does not launch any GPU kernels yet, -// and will be rewritten once a proper offload frontend has landed. -// -// We currently only handle memory transfer for specific calls to functions named `kernel_{num}`, -// when inside of a function called main. This, too, is a temporary workaround for not having a -// frontend. - -#![no_main] - -#[unsafe(no_mangle)] -fn main() { - let mut x = [3.0; 256]; - kernel_1(&mut x); - core::hint::black_box(&x); -} - -// CHECK: %struct.__tgt_offload_entry = type { i64, i16, i16, i32, ptr, ptr, i64, i64, ptr } -// CHECK: %struct.__tgt_kernel_arguments = type { i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, i64, i64, [3 x i32], [3 x i32], i32 } -// CHECK: %struct.ident_t = type { i32, i32, i32, i32, ptr } -// CHECK: %struct.__tgt_bin_desc = type { i32, ptr, ptr, ptr } - -// CHECK: @.offload_sizes.1 = private unnamed_addr constant [1 x i64] [i64 1024] -// CHECK: @.offload_maptypes.1 = private unnamed_addr constant [1 x i64] [i64 3] -// CHECK: @.kernel_1.region_id = weak unnamed_addr constant i8 0 -// CHECK: @.offloading.entry_name.1 = internal unnamed_addr constant [9 x i8] c"kernel_1\00", section ".llvm.rodata.offloading", align 1 -// CHECK: @.offloading.entry.kernel_1 = weak constant %struct.__tgt_offload_entry { i64 0, i16 1, i16 1, i32 0, ptr @.kernel_1.region_id, ptr @.offloading.entry_name.1, i64 0, i64 0, ptr null }, section ".omp_offloading_entries", align 1 -// CHECK: @my_struct_global2 = external global %struct.__tgt_kernel_arguments -// CHECK: @0 = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00", align 1 -// CHECK: @1 = private unnamed_addr constant %struct.ident_t { i32 0, i32 2, i32 0, i32 22, ptr @0 }, align 8 - -// CHECK: Function Attrs: -// CHECK-NEXT: define{{( dso_local)?}} void @main() -// CHECK-NEXT: start: -// CHECK-NEXT: %0 = alloca [8 x i8], align 8 -// CHECK-NEXT: %x = alloca [1024 x i8], align 16 -// CHECK-NEXT: %EmptyDesc = alloca %struct.__tgt_bin_desc, align 8 -// CHECK-NEXT: %.offload_baseptrs = alloca [1 x ptr], align 8 -// CHECK-NEXT: %.offload_ptrs = alloca [1 x ptr], align 8 -// CHECK-NEXT: %.offload_sizes = alloca [1 x i64], align 8 -// CHECK-NEXT: %x.addr = alloca ptr, align 8 -// CHECK-NEXT: store ptr %x, ptr %x.addr, align 8 -// CHECK-NEXT: %1 = load ptr, ptr %x.addr, align 8 -// CHECK-NEXT: %2 = getelementptr inbounds float, ptr %1, i32 0 -// CHECK: call void @llvm.memset.p0.i64(ptr align 8 %EmptyDesc, i8 0, i64 32, i1 false) -// CHECK-NEXT: call void @__tgt_register_lib(ptr %EmptyDesc) -// CHECK-NEXT: call void @__tgt_init_all_rtls() -// CHECK-NEXT: %3 = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 -// CHECK-NEXT: store ptr %1, ptr %3, align 8 -// CHECK-NEXT: %4 = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0 -// CHECK-NEXT: store ptr %2, ptr %4, align 8 -// CHECK-NEXT: %5 = getelementptr inbounds [1 x i64], ptr %.offload_sizes, i32 0, i32 0 -// CHECK-NEXT: store i64 1024, ptr %5, align 8 -// CHECK-NEXT: %6 = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 -// CHECK-NEXT: %7 = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0 -// CHECK-NEXT: %8 = getelementptr inbounds [1 x i64], ptr %.offload_sizes, i32 0, i32 0 -// CHECK-NEXT: call void @__tgt_target_data_begin_mapper(ptr @1, i64 -1, i32 1, ptr %6, ptr %7, ptr %8, ptr @.offload_maptypes.1, ptr null, ptr null) -// CHECK-NEXT: call void @kernel_1(ptr noalias noundef nonnull align 4 dereferenceable(1024) %x) -// CHECK-NEXT: %9 = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 -// CHECK-NEXT: %10 = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0 -// CHECK-NEXT: %11 = getelementptr inbounds [1 x i64], ptr %.offload_sizes, i32 0, i32 0 -// CHECK-NEXT: call void @__tgt_target_data_end_mapper(ptr @1, i64 -1, i32 1, ptr %9, ptr %10, ptr %11, ptr @.offload_maptypes.1, ptr null, ptr null) -// CHECK-NEXT: call void @__tgt_unregister_lib(ptr %EmptyDesc) -// CHECK: store ptr %x, ptr %0, align 8 -// CHECK-NEXT: call void asm sideeffect "", "r,~{memory}"(ptr nonnull %0) -// CHECK: ret void -// CHECK-NEXT: } - -#[unsafe(no_mangle)] -#[inline(never)] -pub fn kernel_1(x: &mut [f32; 256]) { - for i in 0..256 { - x[i] = 21.0; - } -} diff --git a/tests/codegen/hint/cold_path.rs b/tests/codegen/hint/cold_path.rs deleted file mode 100644 index 149abe474f6..00000000000 --- a/tests/codegen/hint/cold_path.rs +++ /dev/null @@ -1,54 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] -#![feature(cold_path)] - -use std::hint::cold_path; - -#[inline(never)] -#[no_mangle] -pub fn path_a() { - println!("path a"); -} - -#[inline(never)] -#[no_mangle] -pub fn path_b() { - println!("path b"); -} - -#[no_mangle] -pub fn test1(x: bool) { - if x { - path_a(); - } else { - cold_path(); - path_b(); - } - - // CHECK-LABEL: @test1( - // CHECK: br i1 %x, label %bb1, label %bb2, !prof ![[NUM:[0-9]+]] - // CHECK: bb2: - // CHECK: path_b - // CHECK: bb1: - // CHECK: path_a -} - -#[no_mangle] -pub fn test2(x: i32) { - match x > 0 { - true => path_a(), - false => { - cold_path(); - path_b() - } - } - - // CHECK-LABEL: @test2( - // CHECK: br i1 %_2, label %bb2, label %bb1, !prof ![[NUM]] - // CHECK: bb1: - // CHECK: path_b - // CHECK: bb2: - // CHECK: path_a -} - -// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1} diff --git a/tests/codegen/hint/likely.rs b/tests/codegen/hint/likely.rs deleted file mode 100644 index 75f9e7aae36..00000000000 --- a/tests/codegen/hint/likely.rs +++ /dev/null @@ -1,81 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] -#![feature(likely_unlikely)] - -use std::hint::likely; - -#[inline(never)] -#[no_mangle] -pub fn path_a() { - println!("path a"); -} - -#[inline(never)] -#[no_mangle] -pub fn path_b() { - println!("path b"); -} - -#[no_mangle] -pub fn test1(x: bool) { - if likely(x) { - path_a(); - } else { - path_b(); - } - - // CHECK-LABEL: @test1( - // CHECK: br i1 %x, label %bb2, label %bb3, !prof ![[NUM:[0-9]+]] - // CHECK: bb3: - // CHECK: path_b - // CHECK: bb2: - // CHECK: path_a -} - -#[no_mangle] -pub fn test2(x: i32) { - match likely(x > 0) { - true => path_a(), - false => path_b(), - } - - // CHECK-LABEL: @test2( - // CHECK: br i1 %_2, label %bb2, label %bb3, !prof ![[NUM]] - // CHECK: bb3: - // CHECK: path_b - // CHECK: bb2: - // CHECK: path_a -} - -#[no_mangle] -pub fn test3(x: i8) { - match likely(x < 7) { - true => path_a(), - _ => path_b(), - } - - // CHECK-LABEL: @test3( - // CHECK: br i1 %_2, label %bb2, label %bb3, !prof ![[NUM]] - // CHECK: bb3: - // CHECK: path_b - // CHECK: bb2: - // CHECK: path_a -} - -#[no_mangle] -pub fn test4(x: u64) { - match likely(x != 33) { - false => path_a(), - _ => path_b(), - } - - // CHECK-LABEL: @test4( - // CHECK: br i1 %0, label %bb3, label %bb2, !prof ![[NUM2:[0-9]+]] - // CHECK: bb3: - // CHECK: path_a - // CHECK: bb2: - // CHECK: path_b -} - -// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1} -// CHECK: ![[NUM2]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000} diff --git a/tests/codegen/hint/unlikely.rs b/tests/codegen/hint/unlikely.rs deleted file mode 100644 index 248b1e2537e..00000000000 --- a/tests/codegen/hint/unlikely.rs +++ /dev/null @@ -1,80 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] -#![feature(likely_unlikely)] - -use std::hint::unlikely; - -#[inline(never)] -#[no_mangle] -pub fn path_a() { - println!("path a"); -} - -#[inline(never)] -#[no_mangle] -pub fn path_b() { - println!("path b"); -} - -#[no_mangle] -pub fn test1(x: bool) { - if unlikely(x) { - path_a(); - } else { - path_b(); - } - - // CHECK-LABEL: @test1( - // CHECK: br i1 %x, label %bb2, label %bb4, !prof ![[NUM:[0-9]+]] - // CHECK: bb4: - // CHECK: path_b - // CHECK: bb2: - // CHECK: path_a -} - -#[no_mangle] -pub fn test2(x: i32) { - match unlikely(x > 0) { - true => path_a(), - false => path_b(), - } - - // CHECK-LABEL: @test2( - // CHECK: br i1 %_2, label %bb2, label %bb4, !prof ![[NUM]] - // CHECK: bb4: - // CHECK: path_b - // CHECK: bb2: - // CHECK: path_a -} - -#[no_mangle] -pub fn test3(x: i8) { - match unlikely(x < 7) { - true => path_a(), - _ => path_b(), - } - - // CHECK-LABEL: @test3( - // CHECK: br i1 %_2, label %bb2, label %bb4, !prof ![[NUM]] - // CHECK: bb4: - // CHECK: path_b - // CHECK: bb2: - // CHECK: path_a -} - -#[no_mangle] -pub fn test4(x: u64) { - match unlikely(x != 33) { - false => path_a(), - _ => path_b(), - } - - // CHECK-LABEL: @test4( - // CHECK: br i1 %0, label %bb4, label %bb2, !prof ![[NUM2:[0-9]+]] - // CHECK: bb4: - // CHECK: path_a - // CHECK: bb2: - // CHECK: path_b -} - -// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000} diff --git a/tests/codegen/i128-wasm32-callconv.rs b/tests/codegen/i128-wasm32-callconv.rs deleted file mode 100644 index 9d73d270ef3..00000000000 --- a/tests/codegen/i128-wasm32-callconv.rs +++ /dev/null @@ -1,49 +0,0 @@ -//! Verify that Rust implements the expected calling convention for `i128`/`u128`. - -//@ add-core-stubs -//@ compile-flags: -Copt-level=3 --target wasm32-wasip1 -//@ needs-llvm-components: webassembly - -#![crate_type = "lib"] -#![no_std] -#![no_core] -#![feature(no_core, lang_items)] - -extern crate minicore; - -extern "C" { - fn extern_call(arg0: i128); - fn extern_ret() -> i128; -} - -#[no_mangle] -pub extern "C" fn pass(_arg0: u32, arg1: i128) { - // CHECK-LABEL: @pass( - // an i128 is passed via registers - // CHECK-SAME: i128 noundef %arg1 - // CHECK: call void @extern_call - unsafe { extern_call(arg1) }; -} - -// Check that we produce the correct return ABI -#[no_mangle] -pub extern "C" fn ret(_arg0: u32, arg1: i128) -> i128 { - // CHECK-LABEL: @ret( - // but an i128 is returned via the stack - // CHECK-SAME: sret - // CHECK: store i128 %arg1 - // CHECK-NEXT: ret void - arg1 -} - -// Check that we consume the correct return ABI -#[no_mangle] -pub extern "C" fn forward(dst: *mut i128) { - // CHECK-LABEL: @forward - // CHECK-SAME: ptr{{.*}} %dst) - // without optimizatons, an intermediate alloca is used - // CHECK: call void @extern_ret - // CHECK: store i128 - // CHECK: ret void - unsafe { *dst = extern_ret() }; -} diff --git a/tests/codegen/i128-x86-align.rs b/tests/codegen/i128-x86-align.rs deleted file mode 100644 index 75802b0c505..00000000000 --- a/tests/codegen/i128-x86-align.rs +++ /dev/null @@ -1,105 +0,0 @@ -//@ only-x86_64 -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes --crate-type=lib - -// On LLVM 17 and earlier LLVM's own data layout specifies that i128 has 8 byte alignment, -// while rustc wants it to have 16 byte alignment. This test checks that we handle this -// correctly. - -// CHECK: %ScalarPair = type { i32, [3 x i32], i128 } - -#![feature(core_intrinsics)] - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct ScalarPair { - a: i32, - b: i128, -} - -#[no_mangle] -pub fn load(x: &ScalarPair) -> ScalarPair { - // CHECK-LABEL: @load( - // CHECK-SAME: sret([32 x i8]) align 16 - // CHECK-SAME: dereferenceable(32) %_0, - // CHECK-SAME: align 16 - // CHECK-SAME: dereferenceable(32) %x - // CHECK: [[A:%.*]] = load i32, ptr %x, align 16 - // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16 - // CHECK-NEXT: [[B:%.*]] = load i128, ptr [[GEP]], align 16 - // CHECK-NEXT: store i32 [[A]], ptr %_0, align 16 - // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %_0, i64 16 - // CHECK-NEXT: store i128 [[B]], ptr [[GEP]], align 16 - // CHECK-NEXT: ret void - *x -} - -#[no_mangle] -pub fn store(x: &mut ScalarPair) { - // CHECK-LABEL: @store( - // CHECK-SAME: align 16 - // CHECK-SAME: dereferenceable(32) %x - // CHECK: store i32 1, ptr %x, align 16 - // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16 - // CHECK-NEXT: store i128 2, ptr [[GEP]], align 16 - *x = ScalarPair { a: 1, b: 2 }; -} - -#[no_mangle] -pub fn alloca() { - // CHECK-LABEL: @alloca( - // CHECK: [[X:%.*]] = alloca [32 x i8], align 16 - // CHECK: store i32 1, ptr %x, align 16 - // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16 - // CHECK-NEXT: store i128 2, ptr [[GEP]], align 16 - let mut x = ScalarPair { a: 1, b: 2 }; - store(&mut x); -} - -#[no_mangle] -pub fn load_volatile(x: &ScalarPair) -> ScalarPair { - // CHECK-LABEL: @load_volatile( - // CHECK-SAME: sret([32 x i8]) align 16 - // CHECK-SAME: dereferenceable(32) %_0, - // CHECK-SAME: align 16 - // CHECK-SAME: dereferenceable(32) %x - // CHECK: [[LOAD:%.*]] = load volatile %ScalarPair, ptr %x, align 16 - // CHECK-NEXT: store %ScalarPair [[LOAD]], ptr %_0, align 16 - // CHECK-NEXT: ret void - unsafe { std::intrinsics::volatile_load(x) } -} - -#[no_mangle] -pub fn transmute(x: ScalarPair) -> (std::mem::MaybeUninit, i128) { - // CHECK-LABEL: @transmute( - // CHECK-SAME: sret([32 x i8]) align 16 - // CHECK-SAME: dereferenceable(32) %_0, - // CHECK-SAME: i32 noundef %x.0, i128 noundef %x.1 - // CHECK: store i32 %x.0, ptr %_0, align 16 - // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %_0, i64 16 - // CHECK-NEXT: store i128 %x.1, ptr [[GEP]], align 16 - // CHECK-NEXT: ret void - unsafe { std::mem::transmute(x) } -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct Struct { - a: i32, - b: i32, - c: i128, -} - -#[no_mangle] -pub fn store_struct(x: &mut Struct) { - // CHECK-LABEL: @store_struct( - // CHECK-SAME: align 16 - // CHECK-SAME: dereferenceable(32) %x - // CHECK: [[TMP:%.*]] = alloca [32 x i8], align 16 - // CHECK: store i32 1, ptr [[TMP]], align 16 - // CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 4 - // CHECK-NEXT: store i32 2, ptr [[GEP1]], align 4 - // CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 16 - // CHECK-NEXT: store i128 3, ptr [[GEP2]], align 16 - // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 16 %x, ptr align 16 [[TMP]], i64 32, i1 false) - *x = Struct { a: 1, b: 2, c: 3 }; -} diff --git a/tests/codegen/i128-x86-callconv.rs b/tests/codegen/i128-x86-callconv.rs deleted file mode 100644 index 41c30c09c1a..00000000000 --- a/tests/codegen/i128-x86-callconv.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! Verify that Rust implements the expected calling convention for `i128`/`u128`. - -// Eliminate intermediate instructions during `nop` tests -//@ compile-flags: -Copt-level=1 - -//@ add-core-stubs -//@ revisions: MSVC MINGW softfloat -//@ [MSVC] needs-llvm-components: x86 -//@ [MSVC] compile-flags: --target x86_64-pc-windows-msvc -// Use `WIN` as a common prefix for MSVC and MINGW but *not* the softfloat test. -//@ [MSVC] filecheck-flags: --check-prefix=WIN -//@ [MINGW] needs-llvm-components: x86 -//@ [MINGW] compile-flags: --target x86_64-pc-windows-gnu -//@ [MINGW] filecheck-flags: --check-prefix=WIN -// The `x86_64-unknown-uefi` target also uses the Windows calling convention, -// but does not have SSE registers available. -//@ [softfloat] needs-llvm-components: x86 -//@ [softfloat] compile-flags: --target x86_64-unknown-uefi - -#![crate_type = "lib"] -#![no_std] -#![no_core] -#![feature(no_core, lang_items)] - -extern crate minicore; - -extern "C" { - fn extern_call(arg0: i128); - fn extern_ret() -> i128; -} - -#[no_mangle] -pub extern "C" fn pass(_arg0: u32, arg1: i128) { - // CHECK-LABEL: @pass( - // i128 is passed indirectly on Windows. It should load the pointer to the stack and pass - // a pointer to that allocation. The softfloat ABI works the same. - // CHECK-SAME: %_arg0, ptr{{.*}} %arg1) - // CHECK: [[PASS:%[_0-9]+]] = alloca [16 x i8], align 16 - // CHECK: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1 - // CHECK: store i128 [[LOADED]], ptr [[PASS]] - // CHECK: call void @extern_call - unsafe { extern_call(arg1) }; -} - -// Check that we produce the correct return ABI -#[no_mangle] -pub extern "C" fn ret(_arg0: u32, arg1: i128) -> i128 { - // WIN-LABEL: @ret( - // i128 is returned in xmm0 on Windows - // FIXME(#134288): This may change for the `-msvc` targets in the future. - // WIN-SAME: i32{{.*}} %_arg0, ptr{{.*}} %arg1) - // WIN: [[LOADED:%[_0-9]+]] = load <16 x i8>, ptr %arg1 - // WIN-NEXT: ret <16 x i8> [[LOADED]] - // The softfloat ABI returns this indirectly. - // softfloat-LABEL: i128 @ret(i32{{.*}} %_arg0, ptr{{.*}} %arg1) - arg1 -} - -// Check that we consume the correct return ABI -#[no_mangle] -pub extern "C" fn forward(dst: *mut i128) { - // CHECK-LABEL: @forward - // WIN-SAME: ptr{{.*}} %dst) - // WIN: [[RETURNED:%[_0-9]+]] = tail call <16 x i8> @extern_ret() - // WIN: store <16 x i8> [[RETURNED]], ptr %dst - // WIN: ret void - // softfloat: [[RETURNED:%[_0-9]+]] = tail call {{.*}}i128 @extern_ret() - unsafe { *dst = extern_ret() }; -} - -#[repr(C)] -struct RetAggregate { - a: i32, - b: i128, -} - -#[no_mangle] -pub extern "C" fn ret_aggregate(_arg0: u32, arg1: i128) -> RetAggregate { - // CHECK-LABEL: @ret_aggregate( - // Aggregates should also be returned indirectly - // CHECK-SAME: ptr{{.*}}sret([32 x i8]){{.*}}[[RET:%[_0-9]+]], i32{{.*}}%_arg0, ptr{{.*}}%arg1) - // CHECK: [[LOADED:%[_0-9]+]] = load i128, ptr %arg1 - // CHECK: [[GEP:%[_0-9]+]] = getelementptr{{.*}}, ptr [[RET]] - // CHECK: store i128 [[LOADED]], ptr [[GEP]] - // CHECK: ret void - RetAggregate { a: 1, b: arg1 } -} diff --git a/tests/codegen/infallible-unwrap-in-opt-z.rs b/tests/codegen/infallible-unwrap-in-opt-z.rs deleted file mode 100644 index c2297c58e77..00000000000 --- a/tests/codegen/infallible-unwrap-in-opt-z.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ compile-flags: -C opt-level=z -//@ edition: 2021 - -#![crate_type = "lib"] - -// From - -// CHECK-LABEL: @read_up_to_8( -#[no_mangle] -pub fn read_up_to_8(buf: &[u8]) -> u64 { - // CHECK-NOT: unwrap_failed - if buf.len() < 4 { - // actual instance has more code. - return 0; - } - let lo = u32::from_le_bytes(buf[..4].try_into().unwrap()) as u64; - let hi = u32::from_le_bytes(buf[buf.len() - 4..][..4].try_into().unwrap()) as u64; - lo | (hi << 8 * (buf.len() as u64 - 4)) -} - -// CHECK-LABEL: @checking_unwrap_expectation( -#[no_mangle] -pub fn checking_unwrap_expectation(buf: &[u8]) -> &[u8; 4] { - // CHECK: call void @{{.*core6result13unwrap_failed}} - buf.try_into().unwrap() -} diff --git a/tests/codegen/inherit_overflow.rs b/tests/codegen/inherit_overflow.rs deleted file mode 100644 index e4a5ef39fc5..00000000000 --- a/tests/codegen/inherit_overflow.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ compile-flags: -Zmir-enable-passes=+Inline,+GVN --crate-type lib -//@ revisions: ASSERT NOASSERT -//@[ASSERT] compile-flags: -Coverflow-checks=on -//@[NOASSERT] compile-flags: -Coverflow-checks=off - -// CHECK-LABEL: define{{.*}} @assertion -// ASSERT: call void @{{.*4core9panicking11panic_const24panic_const_add_overflow}} -// NOASSERT: ret i8 0 -#[no_mangle] -pub fn assertion() -> u8 { - // Optimized MIR will replace this `CheckedBinaryOp` by `const (0, true)`. - // Verify that codegen does or does not emit the panic. - ::add(255, 1) -} diff --git a/tests/codegen/inline-always-works-always.rs b/tests/codegen/inline-always-works-always.rs deleted file mode 100644 index 07200fd9e37..00000000000 --- a/tests/codegen/inline-always-works-always.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ revisions: NO-OPT SIZE-OPT SPEED-OPT -//@[NO-OPT] compile-flags: -Copt-level=0 -//@[SIZE-OPT] compile-flags: -Copt-level=s -//@[SPEED-OPT] compile-flags: -Copt-level=3 - -#![crate_type = "rlib"] - -#[no_mangle] -#[inline(always)] -pub extern "C" fn callee() -> u32 { - 4 + 4 -} - -// CHECK-LABEL: caller -// SIZE-OPT: ret i32 8 -// SPEED-OPT: ret i32 8 -// NO-OPT: ret i32 8 -#[no_mangle] -pub extern "C" fn caller() -> u32 { - callee() -} diff --git a/tests/codegen/inline-debuginfo.rs b/tests/codegen/inline-debuginfo.rs deleted file mode 100644 index 1e1c9037f5c..00000000000 --- a/tests/codegen/inline-debuginfo.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![crate_type = "rlib"] -//@ compile-flags: -Copt-level=3 -g -// - -#[no_mangle] -#[inline(always)] -pub extern "C" fn callee(x: u32) -> u32 { - x + 4 -} - -// CHECK-LABEL: caller -// CHECK: dbg{{.}}value({{(metadata )?}}i32 %y, {{(metadata )?}}!{{.*}}, {{(metadata )?}}!DIExpression(DW_OP_constu, 3, DW_OP_minus, DW_OP_stack_value){{.*}} [[A:![0-9]+]] -// CHECK: [[A]] = !DILocation(line: {{.*}}, scope: {{.*}}, inlinedAt: {{.*}}) -#[no_mangle] -pub extern "C" fn caller(y: u32) -> u32 { - callee(y - 3) -} diff --git a/tests/codegen/inline-function-args-debug-info.rs b/tests/codegen/inline-function-args-debug-info.rs deleted file mode 100644 index c31419cb914..00000000000 --- a/tests/codegen/inline-function-args-debug-info.rs +++ /dev/null @@ -1,23 +0,0 @@ -// This test checks that debug information includes function argument indexes even if the function -// gets inlined by MIR inlining. Without function argument indexes, `info args` in gdb won't show -// arguments and their values for the current function. - -//@ compile-flags: -Zinline-mir=yes -Cdebuginfo=2 -//@ edition: 2021 - -#![crate_type = "lib"] - -#[inline(never)] -pub fn outer_function(x: usize, y: usize) -> usize { - inner_function(x, y) + 1 -} - -#[inline] -fn inner_function(aaaa: usize, bbbb: usize) -> usize { - // CHECK: !DILocalVariable(name: "aaaa", arg: 1 - // CHECK-SAME: line: 16 - // CHECK-NOT: !DILexicalBlock( - // CHECK: !DILocalVariable(name: "bbbb", arg: 2 - // CHECK-SAME: line: 16 - aaaa + bbbb -} diff --git a/tests/codegen/inline-hint.rs b/tests/codegen/inline-hint.rs deleted file mode 100644 index 3d46885d5a2..00000000000 --- a/tests/codegen/inline-hint.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Checks that closures, constructors, and shims except -// for a drop glue receive inline hint by default. -// -//@ compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0 -Zinline-mir=no -#![crate_type = "lib"] - -pub fn f() { - let a = A; - let b = (0i32, 1i32, 2i32, 3 as *const i32); - let c = || {}; - - a(String::new(), String::new()); - b.clone(); - c(); -} - -struct A(String, String); - -// CHECK: ; core::ptr::drop_in_place:: -// CHECK-NEXT: ; Function Attrs: -// CHECK-NOT: inlinehint -// CHECK-SAME: {{$}} - -// CHECK: ; <(i32, i32, i32, *const i{{16|32|64}}) as core::clone::Clone>::clone -// CHECK-NEXT: ; Function Attrs: inlinehint - -// CHECK: ; inline_hint::f::{closure#0} -// CHECK-NEXT: ; Function Attrs: inlinehint - -// CHECK: ; inline_hint::A -// CHECK-NEXT: ; Function Attrs: inlinehint diff --git a/tests/codegen/instrument-coverage/instrument-coverage-off.rs b/tests/codegen/instrument-coverage/instrument-coverage-off.rs deleted file mode 100644 index e44d6c65874..00000000000 --- a/tests/codegen/instrument-coverage/instrument-coverage-off.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Test that `-Cinstrument-coverage=off` does not add coverage instrumentation to LLVM IR. - -//@ compile-flags: -Zno-profiler-runtime -//@ revisions: n no off false_ zero -//@ [n] compile-flags: -Cinstrument-coverage=n -//@ [no] compile-flags: -Cinstrument-coverage=no -//@ [off] compile-flags: -Cinstrument-coverage=off -//@ [false_] compile-flags: -Cinstrument-coverage=false -//@ [zero] compile-flags: -Cinstrument-coverage=0 - -// CHECK-NOT: __llvm_profile_filename -// CHECK-NOT: __llvm_coverage_mapping - -#![crate_type = "lib"] - -#[inline(never)] -fn some_function() {} - -pub fn some_other_function() { - some_function(); -} diff --git a/tests/codegen/instrument-coverage/instrument-coverage.rs b/tests/codegen/instrument-coverage/instrument-coverage.rs deleted file mode 100644 index 23d23651c72..00000000000 --- a/tests/codegen/instrument-coverage/instrument-coverage.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Test that `-Cinstrument-coverage` creates expected __llvm_profile_filename symbol in LLVM IR. - -//@ compile-flags: -Zno-profiler-runtime -//@ revisions: default y yes on true_ all -//@ [default] compile-flags: -Cinstrument-coverage -//@ [y] compile-flags: -Cinstrument-coverage=y -//@ [yes] compile-flags: -Cinstrument-coverage=yes -//@ [on] compile-flags: -Cinstrument-coverage=on -//@ [true_] compile-flags: -Cinstrument-coverage=true -//@ [all] compile-flags: -Cinstrument-coverage=all - -// CHECK-DAG: @__llvm_coverage_mapping -// CHECK-DAG: @__llvm_profile_filename = {{.*}}"default_%m_%p.profraw\00"{{.*}} - -#![crate_type = "lib"] - -#[inline(never)] -fn some_function() {} - -pub fn some_other_function() { - some_function(); -} diff --git a/tests/codegen/instrument-coverage/testprog.rs b/tests/codegen/instrument-coverage/testprog.rs deleted file mode 100644 index 9e918499d57..00000000000 --- a/tests/codegen/instrument-coverage/testprog.rs +++ /dev/null @@ -1,118 +0,0 @@ -//@ edition: 2021 -//@ compile-flags: -Zno-profiler-runtime -//@ compile-flags: -Cinstrument-coverage -Copt-level=0 -//@ revisions: LINUX DARWIN WIN - -//@ [LINUX] only-linux -//@ [LINUX] filecheck-flags: -DINSTR_PROF_DATA=__llvm_prf_data -//@ [LINUX] filecheck-flags: -DINSTR_PROF_NAME=__llvm_prf_names -//@ [LINUX] filecheck-flags: -DINSTR_PROF_CNTS=__llvm_prf_cnts -//@ [LINUX] filecheck-flags: -DINSTR_PROF_COVMAP=__llvm_covmap -//@ [LINUX] filecheck-flags: -DINSTR_PROF_COVFUN=__llvm_covfun -//@ [LINUX] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat' - -//@ [DARWIN] only-apple -//@ [DARWIN] filecheck-flags: -DINSTR_PROF_DATA=__DATA,__llvm_prf_data,regular,live_support -//@ [DARWIN] filecheck-flags: -DINSTR_PROF_NAME=__DATA,__llvm_prf_names -//@ [DARWIN] filecheck-flags: -DINSTR_PROF_CNTS=__DATA,__llvm_prf_cnts -//@ [DARWIN] filecheck-flags: -DINSTR_PROF_COVMAP=__LLVM_COV,__llvm_covmap -//@ [DARWIN] filecheck-flags: -DINSTR_PROF_COVFUN=__LLVM_COV,__llvm_covfun -//@ [DARWIN] filecheck-flags: -DCOMDAT_IF_SUPPORTED= - -//@ [WIN] only-windows -//@ [WIN] filecheck-flags: -DINSTR_PROF_DATA=.lprfd$M -//@ [WIN] filecheck-flags: -DINSTR_PROF_NAME=.lprfn$M -//@ [WIN] filecheck-flags: -DINSTR_PROF_CNTS=.lprfc$M -//@ [WIN] filecheck-flags: -DINSTR_PROF_COVMAP=.lcovmap$M -//@ [WIN] filecheck-flags: -DINSTR_PROF_COVFUN=.lcovfun$M -//@ [WIN] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat' - -// ignore-tidy-linelength - -pub fn will_be_called() -> &'static str { - let val = "called"; - println!("{}", val); - val -} - -pub fn will_not_be_called() -> bool { - println!("should not have been called"); - false -} - -pub fn print(left: &str, value: T, right: &str) -where - T: std::fmt::Display, -{ - println!("{}{}{}", left, value, right); -} - -pub fn wrap_with(inner: T, should_wrap: bool, wrapper: F) -where - F: FnOnce(&T), -{ - if should_wrap { - wrapper(&inner) - } -} - -fn main() { - let less = 1; - let more = 100; - - if less < more { - wrap_with(will_be_called(), less < more, |inner| print(" ***", inner, "*** ")); - wrap_with(will_be_called(), more < less, |inner| print(" ***", inner, "*** ")); - } else { - wrap_with(will_not_be_called(), true, |inner| print("wrapped result is: ", inner, "")); - } -} - -// Check for metadata, variables, declarations, and function definitions injected -// into LLVM IR when compiling with -Cinstrument-coverage. - -// WIN: $__llvm_profile_runtime_user = comdat any - -// CHECK-DAG: @__llvm_coverage_mapping = private constant {{.*}}, section "[[INSTR_PROF_COVMAP]]", align 8 - -// CHECK-DAG: @__covrec_{{[A-F0-9]+}}u = linkonce_odr hidden constant {{.*}}, section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8 - -// WIN: @__llvm_profile_runtime = external{{.*}}global i32 - -// CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global -// CHECK-SAME: section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8 - -// CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global -// CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called -// CHECK-SAME: section "[[INSTR_PROF_DATA]]"{{.*}}, align 8 - -// CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global -// CHECK-SAME: section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8 - -// CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global -// CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main -// CHECK-SAME: section "[[INSTR_PROF_DATA]]"{{.*}}, align 8 - -// CHECK: @__llvm_prf_nm = private constant -// CHECK-SAME: section "[[INSTR_PROF_NAME]]", align 1 - -// CHECK: @llvm.used = appending global -// CHECK-SAME: @__llvm_coverage_mapping -// CHECK-SAME: @__llvm_prf_nm -// CHECK-SAME: section "llvm.metadata" - -// CHECK: define internal { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} { -// CHECK-NEXT: start: -// CHECK-NOT: define internal -// CHECK: atomicrmw add ptr -// CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called, - -// CHECK: declare void @llvm.instrprof.increment(ptr, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]] - -// WIN: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat { -// WIN-NEXT: %1 = load i32, ptr @__llvm_profile_runtime -// WIN-NEXT: ret i32 %1 -// WIN-NEXT: } - -// CHECK: attributes #[[LLVM_INSTRPROF_INCREMENT_ATTR]] = { nounwind } -// WIN: attributes #[[LLVM_PROFILE_RUNTIME_USER_ATTR]] = { noinline } diff --git a/tests/codegen/instrument-mcount.rs b/tests/codegen/instrument-mcount.rs deleted file mode 100644 index 8c97535d4a8..00000000000 --- a/tests/codegen/instrument-mcount.rs +++ /dev/null @@ -1,7 +0,0 @@ -// -//@ compile-flags: -Z instrument-mcount -Copt-level=0 - -#![crate_type = "lib"] - -// CHECK: attributes #{{.*}} "frame-pointer"="all" "instrument-function-entry-inlined"="{{.*}}mcount{{.*}}" -pub fn foo() {} diff --git a/tests/codegen/instrument-xray/basic.rs b/tests/codegen/instrument-xray/basic.rs deleted file mode 100644 index 7aaebf41e36..00000000000 --- a/tests/codegen/instrument-xray/basic.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Checks that `-Z instrument-xray` produces expected instrumentation. -// -//@ needs-xray -//@ compile-flags: -Z instrument-xray=always -Copt-level=0 - -#![crate_type = "lib"] - -// CHECK: attributes #{{.*}} "function-instrument"="xray-always" -pub fn function() {} diff --git a/tests/codegen/instrument-xray/options-combine.rs b/tests/codegen/instrument-xray/options-combine.rs deleted file mode 100644 index d1e3b78e6b2..00000000000 --- a/tests/codegen/instrument-xray/options-combine.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Checks that `-Z instrument-xray` options can be specified multiple times. -// -//@ needs-xray -//@ compile-flags: -Z instrument-xray=skip-exit -Copt-level=0 -//@ compile-flags: -Z instrument-xray=instruction-threshold=123 -Copt-level=0 -//@ compile-flags: -Z instrument-xray=instruction-threshold=456 -Copt-level=0 - -#![crate_type = "lib"] - -// CHECK: attributes #{{.*}} "xray-instruction-threshold"="456" "xray-skip-exit" -// CHECK-NOT: attributes #{{.*}} "xray-instruction-threshold"="123" -pub fn function() {} diff --git a/tests/codegen/instrument-xray/options-override.rs b/tests/codegen/instrument-xray/options-override.rs deleted file mode 100644 index 428fb723edb..00000000000 --- a/tests/codegen/instrument-xray/options-override.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Checks that the last `-Z instrument-xray` option wins. -// -//@ needs-xray -//@ compile-flags: -Z instrument-xray=always -Copt-level=0 -//@ compile-flags: -Z instrument-xray=never -Copt-level=0 - -#![crate_type = "lib"] - -// CHECK: attributes #{{.*}} "function-instrument"="xray-never" -// CHECK-NOT: attributes #{{.*}} "function-instrument"="xray-always" -pub fn function() {} diff --git a/tests/codegen/integer-cmp.rs b/tests/codegen/integer-cmp.rs deleted file mode 100644 index 812fa8e4a42..00000000000 --- a/tests/codegen/integer-cmp.rs +++ /dev/null @@ -1,62 +0,0 @@ -// This is test for more optimal Ord implementation for integers. -// See for more info. - -//@ revisions: llvm-pre-20 llvm-20 -//@ [llvm-20] min-llvm-version: 20 -//@ [llvm-pre-20] max-llvm-major-version: 19 -//@ compile-flags: -C opt-level=3 -Zmerge-functions=disabled - -#![crate_type = "lib"] - -use std::cmp::Ordering; - -// CHECK-LABEL: @cmp_signed -#[no_mangle] -pub fn cmp_signed(a: i64, b: i64) -> Ordering { - // llvm-20: call{{.*}} i8 @llvm.scmp.i8.i64 - // llvm-pre-20: icmp slt - // llvm-pre-20: icmp ne - // llvm-pre-20: zext i1 - // llvm-pre-20: select i1 - a.cmp(&b) -} - -// CHECK-LABEL: @cmp_unsigned -#[no_mangle] -pub fn cmp_unsigned(a: u32, b: u32) -> Ordering { - // llvm-20: call{{.*}} i8 @llvm.ucmp.i8.i32 - // llvm-pre-20: icmp ult - // llvm-pre-20: icmp ne - // llvm-pre-20: zext i1 - // llvm-pre-20: select i1 - a.cmp(&b) -} - -// CHECK-LABEL: @cmp_char -#[no_mangle] -pub fn cmp_char(a: char, b: char) -> Ordering { - // llvm-20: call{{.*}} i8 @llvm.ucmp.i8.i32 - // llvm-pre-20: icmp ult - // llvm-pre-20: icmp ne - // llvm-pre-20: zext i1 - // llvm-pre-20: select i1 - a.cmp(&b) -} - -// CHECK-LABEL: @cmp_tuple -#[no_mangle] -pub fn cmp_tuple(a: (i16, u16), b: (i16, u16)) -> Ordering { - // llvm-20-DAG: call{{.*}} i8 @llvm.ucmp.i8.i16 - // llvm-20-DAG: call{{.*}} i8 @llvm.scmp.i8.i16 - // llvm-20: ret i8 - // llvm-pre-20: icmp slt - // llvm-pre-20: icmp ne - // llvm-pre-20: zext i1 - // llvm-pre-20: select i1 - // llvm-pre-20: icmp ult - // llvm-pre-20: icmp ne - // llvm-pre-20: zext i1 - // llvm-pre-20: select i1 - // llvm-pre-20: select i1 - a.cmp(&b) -} diff --git a/tests/codegen/integer-overflow.rs b/tests/codegen/integer-overflow.rs deleted file mode 100644 index 80362247a86..00000000000 --- a/tests/codegen/integer-overflow.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C overflow-checks=on - -#![crate_type = "lib"] - -pub struct S1<'a> { - data: &'a [u8], - position: usize, -} - -// CHECK-LABEL: @slice_no_index_order -#[no_mangle] -pub fn slice_no_index_order<'a>(s: &'a mut S1, n: usize) -> &'a [u8] { - // CHECK-NOT: slice_index_order_fail - let d = &s.data[s.position..s.position + n]; - s.position += n; - return d; -} - -// CHECK-LABEL: @test_check -#[no_mangle] -pub fn test_check<'a>(s: &'a mut S1, x: usize, y: usize) -> &'a [u8] { - // CHECK: slice_index_order_fail - &s.data[x..y] -} diff --git a/tests/codegen/internalize-closures.rs b/tests/codegen/internalize-closures.rs deleted file mode 100644 index f226ea6faac..00000000000 --- a/tests/codegen/internalize-closures.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 - -pub fn main() { - // We want to make sure that closures get 'internal' linkage instead of - // 'weak_odr' when they are not shared between codegen units - // FIXME(eddyb) `legacy` mangling uses `{{closure}}`, while `v0` - // uses `{closure#0}`, switch to the latter once `legacy` is gone. - // CHECK-LABEL: ; internalize_closures::main::{{.*}}closure - // CHECK-NEXT: ; Function Attrs: - // CHECK-NEXT: define internal - let c = |x: i32| x + 1; - let _ = c(1); -} diff --git a/tests/codegen/intrinsic-no-unnamed-attr.rs b/tests/codegen/intrinsic-no-unnamed-attr.rs deleted file mode 100644 index 4bec579831d..00000000000 --- a/tests/codegen/intrinsic-no-unnamed-attr.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![feature(core_intrinsics)] - -use std::intrinsics::sqrtf32; - -// CHECK: @llvm.sqrt.f32(float) #{{[0-9]*}} - -fn main() { - unsafe { - sqrtf32(0.0f32); - } -} diff --git a/tests/codegen/intrinsics/aggregate-thin-pointer.rs b/tests/codegen/intrinsics/aggregate-thin-pointer.rs deleted file mode 100644 index bd590ce9180..00000000000 --- a/tests/codegen/intrinsics/aggregate-thin-pointer.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z mir-enable-passes=-InstSimplify -//@ only-64bit (so I don't need to worry about usize) - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::aggregate_raw_ptr; - -// InstSimplify replaces these with casts if it can, which means they're almost -// never seen in codegen, but PR#121571 found a way, so add a test for it. - -#[inline(never)] -pub fn opaque(_p: &*const i32) {} - -// CHECK-LABEL: @thin_ptr_via_aggregate( -#[no_mangle] -pub unsafe fn thin_ptr_via_aggregate(p: *const ()) { - // CHECK: %mem = alloca - // CHECK: store ptr %p, ptr %mem - // CHECK: call {{.+}}aggregate_thin_pointer{{.+}} %mem) - let mem = aggregate_raw_ptr(p, ()); - opaque(&mem); -} diff --git a/tests/codegen/intrinsics/carrying_mul_add.rs b/tests/codegen/intrinsics/carrying_mul_add.rs deleted file mode 100644 index 21fb49a3786..00000000000 --- a/tests/codegen/intrinsics/carrying_mul_add.rs +++ /dev/null @@ -1,136 +0,0 @@ -//@ revisions: RAW OPT -//@ compile-flags: -C opt-level=1 -//@[RAW] compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(core_intrinsics)] -#![feature(core_intrinsics_fallbacks)] - -// Note that LLVM seems to sometimes permute the order of arguments to mul and add, -// so these tests don't check the arguments in the optimized revision. - -use std::intrinsics::{carrying_mul_add, fallback}; - -// The fallbacks are emitted even when they're never used, but optimize out. - -// RAW: wide_mul_u128 -// OPT-NOT: wide_mul_u128 - -// CHECK-LABEL: @cma_u8 -#[no_mangle] -pub unsafe fn cma_u8(a: u8, b: u8, c: u8, d: u8) -> (u8, u8) { - // CHECK: [[A:%.+]] = zext i8 %a to i16 - // CHECK: [[B:%.+]] = zext i8 %b to i16 - // CHECK: [[C:%.+]] = zext i8 %c to i16 - // CHECK: [[D:%.+]] = zext i8 %d to i16 - // CHECK: [[AB:%.+]] = mul nuw i16 - // RAW-SAME: [[A]], [[B]] - // CHECK: [[ABC:%.+]] = add nuw i16 - // RAW-SAME: [[AB]], [[C]] - // CHECK: [[ABCD:%.+]] = add nuw i16 - // RAW-SAME: [[ABC]], [[D]] - // CHECK: [[LOW:%.+]] = trunc i16 [[ABCD]] to i8 - // CHECK: [[HIGHW:%.+]] = lshr i16 [[ABCD]], 8 - // RAW: [[HIGH:%.+]] = trunc i16 [[HIGHW]] to i8 - // OPT: [[HIGH:%.+]] = trunc nuw i16 [[HIGHW]] to i8 - // CHECK: [[PAIR0:%.+]] = insertvalue { i8, i8 } poison, i8 [[LOW]], 0 - // CHECK: [[PAIR1:%.+]] = insertvalue { i8, i8 } [[PAIR0]], i8 [[HIGH]], 1 - // OPT: ret { i8, i8 } [[PAIR1]] - carrying_mul_add(a, b, c, d) -} - -// CHECK-LABEL: @cma_u32 -#[no_mangle] -pub unsafe fn cma_u32(a: u32, b: u32, c: u32, d: u32) -> (u32, u32) { - // CHECK: [[A:%.+]] = zext i32 %a to i64 - // CHECK: [[B:%.+]] = zext i32 %b to i64 - // CHECK: [[C:%.+]] = zext i32 %c to i64 - // CHECK: [[D:%.+]] = zext i32 %d to i64 - // CHECK: [[AB:%.+]] = mul nuw i64 - // RAW-SAME: [[A]], [[B]] - // CHECK: [[ABC:%.+]] = add nuw i64 - // RAW-SAME: [[AB]], [[C]] - // CHECK: [[ABCD:%.+]] = add nuw i64 - // RAW-SAME: [[ABC]], [[D]] - // CHECK: [[LOW:%.+]] = trunc i64 [[ABCD]] to i32 - // CHECK: [[HIGHW:%.+]] = lshr i64 [[ABCD]], 32 - // RAW: [[HIGH:%.+]] = trunc i64 [[HIGHW]] to i32 - // OPT: [[HIGH:%.+]] = trunc nuw i64 [[HIGHW]] to i32 - // CHECK: [[PAIR0:%.+]] = insertvalue { i32, i32 } poison, i32 [[LOW]], 0 - // CHECK: [[PAIR1:%.+]] = insertvalue { i32, i32 } [[PAIR0]], i32 [[HIGH]], 1 - // OPT: ret { i32, i32 } [[PAIR1]] - carrying_mul_add(a, b, c, d) -} - -// CHECK-LABEL: @cma_u128 -// CHECK-SAME: sret{{.+}}dereferenceable(32){{.+}}%_0,{{.+}}%a,{{.+}}%b,{{.+}}%c,{{.+}}%d -#[no_mangle] -pub unsafe fn cma_u128(a: u128, b: u128, c: u128, d: u128) -> (u128, u128) { - // CHECK: [[A:%.+]] = zext i128 %a to i256 - // CHECK: [[B:%.+]] = zext i128 %b to i256 - // CHECK: [[C:%.+]] = zext i128 %c to i256 - // CHECK: [[D:%.+]] = zext i128 %d to i256 - // CHECK: [[AB:%.+]] = mul nuw i256 - // RAW-SAME: [[A]], [[B]] - // CHECK: [[ABC:%.+]] = add nuw i256 - // RAW-SAME: [[AB]], [[C]] - // CHECK: [[ABCD:%.+]] = add nuw i256 - // RAW-SAME: [[ABC]], [[D]] - // CHECK: [[LOW:%.+]] = trunc i256 [[ABCD]] to i128 - // CHECK: [[HIGHW:%.+]] = lshr i256 [[ABCD]], 128 - // RAW: [[HIGH:%.+]] = trunc i256 [[HIGHW]] to i128 - // OPT: [[HIGH:%.+]] = trunc nuw i256 [[HIGHW]] to i128 - // RAW: [[PAIR0:%.+]] = insertvalue { i128, i128 } poison, i128 [[LOW]], 0 - // RAW: [[PAIR1:%.+]] = insertvalue { i128, i128 } [[PAIR0]], i128 [[HIGH]], 1 - // OPT: store i128 [[LOW]], ptr %_0 - // OPT: [[P1:%.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %_0, {{i32|i64}} 16 - // OPT: store i128 [[HIGH]], ptr [[P1]] - // CHECK: ret void - carrying_mul_add(a, b, c, d) -} - -// CHECK-LABEL: @cma_i128 -// CHECK-SAME: sret{{.+}}dereferenceable(32){{.+}}%_0,{{.+}}%a,{{.+}}%b,{{.+}}%c,{{.+}}%d -#[no_mangle] -pub unsafe fn cma_i128(a: i128, b: i128, c: i128, d: i128) -> (u128, i128) { - // CHECK: [[A:%.+]] = sext i128 %a to i256 - // CHECK: [[B:%.+]] = sext i128 %b to i256 - // CHECK: [[C:%.+]] = sext i128 %c to i256 - // CHECK: [[D:%.+]] = sext i128 %d to i256 - // CHECK: [[AB:%.+]] = mul nsw i256 - // RAW-SAME: [[A]], [[B]] - // CHECK: [[ABC:%.+]] = add nsw i256 - // RAW-SAME: [[AB]], [[C]] - // CHECK: [[ABCD:%.+]] = add nsw i256 - // RAW-SAME: [[ABC]], [[D]] - // CHECK: [[LOW:%.+]] = trunc i256 [[ABCD]] to i128 - // CHECK: [[HIGHW:%.+]] = lshr i256 [[ABCD]], 128 - // RAW: [[HIGH:%.+]] = trunc i256 [[HIGHW]] to i128 - // OPT: [[HIGH:%.+]] = trunc nuw i256 [[HIGHW]] to i128 - // RAW: [[PAIR0:%.+]] = insertvalue { i128, i128 } poison, i128 [[LOW]], 0 - // RAW: [[PAIR1:%.+]] = insertvalue { i128, i128 } [[PAIR0]], i128 [[HIGH]], 1 - // OPT: store i128 [[LOW]], ptr %_0 - // OPT: [[P1:%.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %_0, {{i32|i64}} 16 - // OPT: store i128 [[HIGH]], ptr [[P1]] - // CHECK: ret void - carrying_mul_add(a, b, c, d) -} - -// CHECK-LABEL: @fallback_cma_u32 -#[no_mangle] -pub unsafe fn fallback_cma_u32(a: u32, b: u32, c: u32, d: u32) -> (u32, u32) { - // OPT-DAG: [[A:%.+]] = zext i32 %a to i64 - // OPT-DAG: [[B:%.+]] = zext i32 %b to i64 - // OPT-DAG: [[AB:%.+]] = mul nuw i64 - // OPT-DAG: [[C:%.+]] = zext i32 %c to i64 - // OPT-DAG: [[ABC:%.+]] = add nuw i64{{.+}}[[C]] - // OPT-DAG: [[D:%.+]] = zext i32 %d to i64 - // OPT-DAG: [[ABCD:%.+]] = add nuw i64{{.+}}[[D]] - // OPT-DAG: [[LOW:%.+]] = trunc i64 [[ABCD]] to i32 - // OPT-DAG: [[HIGHW:%.+]] = lshr i64 [[ABCD]], 32 - // OPT-DAG: [[HIGH:%.+]] = trunc nuw i64 [[HIGHW]] to i32 - // OPT-DAG: [[PAIR0:%.+]] = insertvalue { i32, i32 } poison, i32 [[LOW]], 0 - // OPT-DAG: [[PAIR1:%.+]] = insertvalue { i32, i32 } [[PAIR0]], i32 [[HIGH]], 1 - // OPT-DAG: ret { i32, i32 } [[PAIR1]] - fallback::CarryingMulAdd::carrying_mul_add(a, b, c, d) -} diff --git a/tests/codegen/intrinsics/cold_path.rs b/tests/codegen/intrinsics/cold_path.rs deleted file mode 100644 index fd75324b671..00000000000 --- a/tests/codegen/intrinsics/cold_path.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::cold_path; - -#[no_mangle] -pub fn test_cold_path(x: bool) { - cold_path(); -} - -// CHECK-LABEL: @test_cold_path( -// CHECK-NOT: cold_path diff --git a/tests/codegen/intrinsics/cold_path2.rs b/tests/codegen/intrinsics/cold_path2.rs deleted file mode 100644 index 0891c878fd9..00000000000 --- a/tests/codegen/intrinsics/cold_path2.rs +++ /dev/null @@ -1,37 +0,0 @@ -//@ compile-flags: -O -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::cold_path; - -#[inline(never)] -#[no_mangle] -pub fn path_a() { - println!("path a"); -} - -#[inline(never)] -#[no_mangle] -pub fn path_b() { - println!("path b"); -} - -#[no_mangle] -pub fn test(x: Option) { - if let Some(_) = x { - path_a(); - } else { - cold_path(); - path_b(); - } - - // CHECK-LABEL: void @test(i8{{.+}}%x) - // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %x, 2 - // CHECK: br i1 %[[IS_NONE]], label %bb2, label %bb1, !prof ![[NUM:[0-9]+]] - // CHECK: bb1: - // CHECK: path_a - // CHECK: bb2: - // CHECK: path_b -} - -// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000} diff --git a/tests/codegen/intrinsics/cold_path3.rs b/tests/codegen/intrinsics/cold_path3.rs deleted file mode 100644 index bf3347de665..00000000000 --- a/tests/codegen/intrinsics/cold_path3.rs +++ /dev/null @@ -1,87 +0,0 @@ -//@ compile-flags: -O -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::cold_path; - -#[inline(never)] -#[no_mangle] -pub fn path_a() { - println!("path a"); -} - -#[inline(never)] -#[no_mangle] -pub fn path_b() { - println!("path b"); -} - -#[inline(never)] -#[no_mangle] -pub fn path_c() { - println!("path c"); -} - -#[inline(never)] -#[no_mangle] -pub fn path_d() { - println!("path d"); -} - -#[no_mangle] -pub fn test(x: Option) { - match x { - Some(0) => path_a(), - Some(1) => { - cold_path(); - path_b() - } - Some(2) => path_c(), - Some(3) => { - cold_path(); - path_d() - } - _ => path_a(), - } - - // CHECK-LABEL: @test( - // CHECK: switch i32 %1, label %bb1 [ - // CHECK: i32 0, label %bb6 - // CHECK: i32 1, label %bb5 - // CHECK: i32 2, label %bb4 - // CHECK: i32 3, label %bb3 - // CHECK: ], !prof ![[NUM1:[0-9]+]] -} - -#[no_mangle] -pub fn test2(x: Option) { - match x { - Some(10) => path_a(), - Some(11) => { - cold_path(); - path_b() - } - Some(12) => { - unsafe { core::intrinsics::unreachable() }; - path_c() - } - Some(13) => { - cold_path(); - path_d() - } - _ => { - cold_path(); - path_a() - } - } - - // CHECK-LABEL: @test2( - // CHECK: switch i32 %1, label %bb1 [ - // CHECK: i32 10, label %bb5 - // CHECK: i32 11, label %bb4 - // CHECK: i32 13, label %bb3 - // CHECK: ], !prof ![[NUM2:[0-9]+]] -} - -// CHECK: ![[NUM1]] = !{!"branch_weights", i32 2000, i32 2000, i32 1, i32 2000, i32 1} -// CHECK: ![[NUM2]] = !{!"branch_weights", i32 1, i32 2000, i32 1, i32 1} diff --git a/tests/codegen/intrinsics/compare_bytes.rs b/tests/codegen/intrinsics/compare_bytes.rs deleted file mode 100644 index 3ab0e4e97e0..00000000000 --- a/tests/codegen/intrinsics/compare_bytes.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@ revisions: INT32 INT16 -//@ compile-flags: -Copt-level=3 -//@ [INT32] ignore-16bit -//@ [INT16] only-16bit - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::compare_bytes; - -#[no_mangle] -// CHECK-LABEL: @bytes_cmp( -pub unsafe fn bytes_cmp(a: *const u8, b: *const u8, n: usize) -> i32 { - // INT32: %[[TEMP:.+]] = tail call i32 @memcmp(ptr %a, ptr %b, {{i32|i64}} %n) - // INT32-NOT: sext - // INT32: ret i32 %[[TEMP]] - - // INT16: %[[TEMP1:.+]] = tail call i16 @memcmp(ptr %a, ptr %b, i16 %n) - // INT16: %[[TEMP2:.+]] = sext i16 %[[TEMP1]] to i32 - // INT16: ret i32 %[[TEMP2]] - compare_bytes(a, b, n) -} - -// Ensure that, even though there's an `sext` emitted by the intrinsic, -// that doesn't end up pessiming checks against zero. -#[no_mangle] -// CHECK-LABEL: @bytes_eq( -pub unsafe fn bytes_eq(a: *const u8, b: *const u8, n: usize) -> bool { - // CHECK: call {{.+}} @{{bcmp|memcmp}}(ptr %a, ptr %b, {{i16|i32|i64}} %n) - // CHECK-NOT: sext - // INT32: icmp eq i32 - // INT16: icmp eq i16 - compare_bytes(a, b, n) == 0_i32 -} diff --git a/tests/codegen/intrinsics/const_eval_select.rs b/tests/codegen/intrinsics/const_eval_select.rs deleted file mode 100644 index baa985b00cd..00000000000 --- a/tests/codegen/intrinsics/const_eval_select.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 - -#![crate_type = "lib"] -#![feature(const_eval_select)] -#![feature(core_intrinsics)] - -use std::intrinsics::const_eval_select; - -const fn foo(_: i32) -> i32 { - 1 -} - -#[no_mangle] -pub fn hi(n: i32) -> i32 { - n -} - -#[no_mangle] -pub unsafe fn hey() { - // CHECK: call i32 @hi(i32 - const_eval_select((42,), foo, hi); -} diff --git a/tests/codegen/intrinsics/ctlz.rs b/tests/codegen/intrinsics/ctlz.rs deleted file mode 100644 index 0d54d21ce12..00000000000 --- a/tests/codegen/intrinsics/ctlz.rs +++ /dev/null @@ -1,56 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::{ctlz, ctlz_nonzero}; - -// CHECK-LABEL: @ctlz_u16 -#[no_mangle] -pub unsafe fn ctlz_u16(x: u16) -> u32 { - // CHECK: %[[tmp:.*]] = call i16 @llvm.ctlz.i16(i16 %x, i1 false) - // CHECK: zext i16 %[[tmp]] to i32 - ctlz(x) -} - -// CHECK-LABEL: @ctlz_nzu16 -#[no_mangle] -pub unsafe fn ctlz_nzu16(x: u16) -> u32 { - // CHECK: %[[tmp:.*]] = call i16 @llvm.ctlz.i16(i16 %x, i1 true) - // CHECK: zext i16 %[[tmp]] to i32 - ctlz_nonzero(x) -} - -// CHECK-LABEL: @ctlz_u32 -#[no_mangle] -pub unsafe fn ctlz_u32(x: u32) -> u32 { - // CHECK: call i32 @llvm.ctlz.i32(i32 %x, i1 false) - // CHECK-NOT: zext - // CHECK-NOT: trunc - ctlz(x) -} - -// CHECK-LABEL: @ctlz_nzu32 -#[no_mangle] -pub unsafe fn ctlz_nzu32(x: u32) -> u32 { - // CHECK: call i32 @llvm.ctlz.i32(i32 %x, i1 true) - // CHECK-NOT: zext - // CHECK-NOT: trunc - ctlz_nonzero(x) -} - -// CHECK-LABEL: @ctlz_u64 -#[no_mangle] -pub unsafe fn ctlz_u64(x: u64) -> u32 { - // CHECK: %[[tmp:.*]] = call i64 @llvm.ctlz.i64(i64 %x, i1 false) - // CHECK: trunc i64 %[[tmp]] to i32 - ctlz(x) -} - -// CHECK-LABEL: @ctlz_nzu64 -#[no_mangle] -pub unsafe fn ctlz_nzu64(x: u64) -> u32 { - // CHECK: %[[tmp:.*]] = call i64 @llvm.ctlz.i64(i64 %x, i1 true) - // CHECK: trunc i64 %[[tmp]] to i32 - ctlz_nonzero(x) -} diff --git a/tests/codegen/intrinsics/ctpop.rs b/tests/codegen/intrinsics/ctpop.rs deleted file mode 100644 index f4043325de9..00000000000 --- a/tests/codegen/intrinsics/ctpop.rs +++ /dev/null @@ -1,31 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::ctpop; - -// CHECK-LABEL: @ctpop_u16 -#[no_mangle] -pub unsafe fn ctpop_u16(x: u16) -> u32 { - // CHECK: %[[tmp:.*]] = call i16 @llvm.ctpop.i16(i16 %x) - // CHECK: zext i16 %[[tmp]] to i32 - ctpop(x) -} - -// CHECK-LABEL: @ctpop_u32 -#[no_mangle] -pub unsafe fn ctpop_u32(x: u32) -> u32 { - // CHECK: call i32 @llvm.ctpop.i32(i32 %x) - // CHECK-NOT: zext - // CHECK-NOT: trunc - ctpop(x) -} - -// CHECK-LABEL: @ctpop_u64 -#[no_mangle] -pub unsafe fn ctpop_u64(x: u64) -> u32 { - // CHECK: %[[tmp:.*]] = call i64 @llvm.ctpop.i64(i64 %x) - // CHECK: trunc i64 %[[tmp]] to i32 - ctpop(x) -} diff --git a/tests/codegen/intrinsics/disjoint_bitor.rs b/tests/codegen/intrinsics/disjoint_bitor.rs deleted file mode 100644 index fc45439ee0b..00000000000 --- a/tests/codegen/intrinsics/disjoint_bitor.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::disjoint_bitor; - -// CHECK-LABEL: @disjoint_bitor_signed -#[no_mangle] -pub unsafe fn disjoint_bitor_signed(x: i32, y: i32) -> i32 { - // CHECK: or disjoint i32 %x, %y - disjoint_bitor(x, y) -} - -// CHECK-LABEL: @disjoint_bitor_unsigned -#[no_mangle] -pub unsafe fn disjoint_bitor_unsigned(x: u64, y: u64) -> u64 { - // CHECK: or disjoint i64 %x, %y - disjoint_bitor(x, y) -} - -// CHECK-LABEL: @disjoint_bitor_literal -#[no_mangle] -pub unsafe fn disjoint_bitor_literal() -> u8 { - // This is a separate check because even without any passes, - // LLVM will fold so it's not an instruction, which can assert in LLVM. - - // CHECK: store i8 3 - disjoint_bitor(1, 2) -} diff --git a/tests/codegen/intrinsics/exact_div.rs b/tests/codegen/intrinsics/exact_div.rs deleted file mode 100644 index dc625ba7fe4..00000000000 --- a/tests/codegen/intrinsics/exact_div.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::exact_div; - -// CHECK-LABEL: @exact_sdiv -#[no_mangle] -pub unsafe fn exact_sdiv(x: i32, y: i32) -> i32 { - // CHECK: sdiv exact - exact_div(x, y) -} - -// CHECK-LABEL: @exact_udiv -#[no_mangle] -pub unsafe fn exact_udiv(x: u32, y: u32) -> u32 { - // CHECK: udiv exact - exact_div(x, y) -} diff --git a/tests/codegen/intrinsics/likely.rs b/tests/codegen/intrinsics/likely.rs deleted file mode 100644 index c5e3c466f45..00000000000 --- a/tests/codegen/intrinsics/likely.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::likely; - -#[inline(never)] -#[no_mangle] -pub fn path_a() { - println!("path a"); -} - -#[inline(never)] -#[no_mangle] -pub fn path_b() { - println!("path b"); -} - -#[no_mangle] -pub fn test_likely(x: bool) { - if likely(x) { - path_a(); - } else { - path_b(); - } -} - -// CHECK-LABEL: @test_likely( -// CHECK: br i1 %x, label %bb2, label %bb3, !prof ![[NUM:[0-9]+]] -// CHECK: bb3: -// CHECK-NOT: cold_path -// CHECK: path_b -// CHECK: bb2: -// CHECK: path_a -// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1} diff --git a/tests/codegen/intrinsics/likely_assert.rs b/tests/codegen/intrinsics/likely_assert.rs deleted file mode 100644 index 87ffb4ee3fb..00000000000 --- a/tests/codegen/intrinsics/likely_assert.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -#[no_mangle] -pub fn test_assert(x: bool) { - assert!(x); -} - -// check that assert! emits branch weights - -// CHECK-LABEL: @test_assert( -// CHECK: br i1 %x, label %bb2, label %bb1, !prof ![[NUM:[0-9]+]] -// CHECK: bb1: -// CHECK: panic -// CHECK: bb2: -// CHECK: ret void -// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1} diff --git a/tests/codegen/intrinsics/mask.rs b/tests/codegen/intrinsics/mask.rs deleted file mode 100644 index 5344274678c..00000000000 --- a/tests/codegen/intrinsics/mask.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ compile-flags: -Copt-level=0 -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -// CHECK-LABEL: @mask_ptr -// CHECK-SAME: [[WORD:i[0-9]+]] %mask -#[no_mangle] -pub fn mask_ptr(ptr: *const u16, mask: usize) -> *const u16 { - // CHECK: call - // CHECK-SAME: @llvm.ptrmask.{{p0|p0i8}}.[[WORD]](ptr {{%ptr|%1}}, [[WORD]] %mask) - core::intrinsics::ptr_mask(ptr, mask) -} diff --git a/tests/codegen/intrinsics/nontemporal.rs b/tests/codegen/intrinsics/nontemporal.rs deleted file mode 100644 index a151d4bd297..00000000000 --- a/tests/codegen/intrinsics/nontemporal.rs +++ /dev/null @@ -1,32 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: -Copt-level=3 -//@revisions: with_nontemporal without_nontemporal -//@[with_nontemporal] compile-flags: --target aarch64-unknown-linux-gnu -//@[with_nontemporal] needs-llvm-components: aarch64 -//@[without_nontemporal] compile-flags: --target x86_64-unknown-linux-gnu -//@[without_nontemporal] needs-llvm-components: x86 - -// Ensure that we *do* emit the `!nontemporal` flag on architectures where it -// is well-behaved, but do *not* emit it on architectures where it is ill-behaved. -// For more context, see and -// . - -#![feature(no_core, lang_items, intrinsics)] -#![no_core] -#![crate_type = "lib"] - -extern crate minicore; -use minicore::*; - -#[rustc_intrinsic] -pub unsafe fn nontemporal_store(ptr: *mut T, val: T); - -#[no_mangle] -pub fn a(a: &mut u32, b: u32) { - // CHECK-LABEL: define{{.*}}void @a - // with_nontemporal: store i32 %b, ptr %a, align 4, !nontemporal - // without_nontemporal-NOT: nontemporal - unsafe { - nontemporal_store(a, b); - } -} diff --git a/tests/codegen/intrinsics/offset.rs b/tests/codegen/intrinsics/offset.rs deleted file mode 100644 index cf0c7c7ac7d..00000000000 --- a/tests/codegen/intrinsics/offset.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::offset; - -// CHECK-LABEL: ptr @offset_zst -// CHECK-SAME: (ptr noundef %p, [[SIZE:i[0-9]+]] noundef %d) -#[no_mangle] -pub unsafe fn offset_zst(p: *const (), d: usize) -> *const () { - // CHECK-NOT: getelementptr - // CHECK: ret ptr %p - offset(p, d) -} - -// CHECK-LABEL: ptr @offset_isize -// CHECK-SAME: (ptr noundef %p, [[SIZE]] noundef %d) -#[no_mangle] -pub unsafe fn offset_isize(p: *const u32, d: isize) -> *const u32 { - // CHECK: %[[R:.*]] = getelementptr inbounds i32, ptr %p, [[SIZE]] %d - // CHECK-NEXT: ret ptr %[[R]] - offset(p, d) -} - -// CHECK-LABEL: ptr @offset_usize -// CHECK-SAME: (ptr noundef %p, [[SIZE]] noundef %d) -#[no_mangle] -pub unsafe fn offset_usize(p: *const u64, d: usize) -> *const u64 { - // CHECK: %[[R:.*]] = getelementptr inbounds{{( nuw)?}} i64, ptr %p, [[SIZE]] %d - // CHECK-NEXT: ret ptr %[[R]] - offset(p, d) -} diff --git a/tests/codegen/intrinsics/offset_from.rs b/tests/codegen/intrinsics/offset_from.rs deleted file mode 100644 index ef1a77ef184..00000000000 --- a/tests/codegen/intrinsics/offset_from.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ compile-flags: -C opt-level=1 -//@ only-64bit (because we're using [ui]size) - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -//! Basic optimizations are enabled because otherwise `x86_64-gnu-nopt` had an alloca. -//! Uses a type with non-power-of-two size to avoid normalizations to shifts. - -use std::intrinsics::*; - -type RGB = [u8; 3]; - -// CHECK-LABEL: @offset_from_odd_size -#[no_mangle] -pub unsafe fn offset_from_odd_size(a: *const RGB, b: *const RGB) -> isize { - // CHECK: start - // CHECK-NEXT: ptrtoint - // CHECK-NEXT: ptrtoint - // CHECK-NEXT: sub i64 - // CHECK-NEXT: sdiv exact i64 %{{[0-9]+}}, 3 - // CHECK-NEXT: ret i64 - ptr_offset_from(a, b) -} - -// CHECK-LABEL: @offset_from_unsigned_odd_size -#[no_mangle] -pub unsafe fn offset_from_unsigned_odd_size(a: *const RGB, b: *const RGB) -> usize { - // CHECK: start - // CHECK-NEXT: ptrtoint - // CHECK-NEXT: ptrtoint - // CHECK-NEXT: sub nuw i64 - // CHECK-NEXT: udiv exact i64 %{{[0-9]+}}, 3 - // CHECK-NEXT: ret i64 - ptr_offset_from_unsigned(a, b) -} diff --git a/tests/codegen/intrinsics/prefetch.rs b/tests/codegen/intrinsics/prefetch.rs deleted file mode 100644 index 3f9f21c85cb..00000000000 --- a/tests/codegen/intrinsics/prefetch.rs +++ /dev/null @@ -1,64 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::{ - prefetch_read_data, prefetch_read_instruction, prefetch_write_data, prefetch_write_instruction, -}; - -#[no_mangle] -pub fn check_prefetch_read_data(data: &[i8]) { - unsafe { - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 0, i32 1) - prefetch_read_data(data.as_ptr(), 0); - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 1, i32 1) - prefetch_read_data(data.as_ptr(), 1); - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 2, i32 1) - prefetch_read_data(data.as_ptr(), 2); - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 3, i32 1) - prefetch_read_data(data.as_ptr(), 3); - } -} - -#[no_mangle] -pub fn check_prefetch_write_data(data: &[i8]) { - unsafe { - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 0, i32 1) - prefetch_write_data(data.as_ptr(), 0); - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 1, i32 1) - prefetch_write_data(data.as_ptr(), 1); - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 2, i32 1) - prefetch_write_data(data.as_ptr(), 2); - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 3, i32 1) - prefetch_write_data(data.as_ptr(), 3); - } -} - -#[no_mangle] -pub fn check_prefetch_read_instruction(data: &[i8]) { - unsafe { - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 0, i32 0) - prefetch_read_instruction(data.as_ptr(), 0); - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 1, i32 0) - prefetch_read_instruction(data.as_ptr(), 1); - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 2, i32 0) - prefetch_read_instruction(data.as_ptr(), 2); - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 3, i32 0) - prefetch_read_instruction(data.as_ptr(), 3); - } -} - -#[no_mangle] -pub fn check_prefetch_write_instruction(data: &[i8]) { - unsafe { - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 0, i32 0) - prefetch_write_instruction(data.as_ptr(), 0); - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 1, i32 0) - prefetch_write_instruction(data.as_ptr(), 1); - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 2, i32 0) - prefetch_write_instruction(data.as_ptr(), 2); - // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 3, i32 0) - prefetch_write_instruction(data.as_ptr(), 3); - } -} diff --git a/tests/codegen/intrinsics/ptr_metadata.rs b/tests/codegen/intrinsics/ptr_metadata.rs deleted file mode 100644 index 044dbc20486..00000000000 --- a/tests/codegen/intrinsics/ptr_metadata.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z inline-mir -//@ only-64bit (so I don't need to worry about usize) - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::ptr_metadata; - -// CHECK-LABEL: @thin_metadata( -#[no_mangle] -pub fn thin_metadata(p: *const ()) { - // CHECK: start - // CHECK-NEXT: ret void - ptr_metadata(p) -} - -// CHECK-LABEL: @slice_metadata( -#[no_mangle] -pub fn slice_metadata(p: *const [u8]) -> usize { - // CHECK: start - // CHECK-NEXT: ret i64 %p.1 - ptr_metadata(p) -} - -// CHECK-LABEL: @dyn_byte_offset( -#[no_mangle] -pub unsafe fn dyn_byte_offset( - p: *const dyn std::fmt::Debug, - n: usize, -) -> *const dyn std::fmt::Debug { - // CHECK: %[[Q:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %p.0, i64 %n - // CHECK: %[[TEMP1:.+]] = insertvalue { ptr, ptr } poison, ptr %[[Q]], 0 - // CHECK: %[[TEMP2:.+]] = insertvalue { ptr, ptr } %[[TEMP1]], ptr %p.1, 1 - // CHECK: ret { ptr, ptr } %[[TEMP2]] - p.byte_add(n) -} diff --git a/tests/codegen/intrinsics/rotate_left.rs b/tests/codegen/intrinsics/rotate_left.rs deleted file mode 100644 index 4f6c5cbaed6..00000000000 --- a/tests/codegen/intrinsics/rotate_left.rs +++ /dev/null @@ -1,31 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::rotate_left; - -// CHECK-LABEL: @rotate_left_u16 -#[no_mangle] -pub unsafe fn rotate_left_u16(x: u16, shift: u32) -> u16 { - // CHECK: %[[tmp:.*]] = trunc i32 %shift to i16 - // CHECK: call i16 @llvm.fshl.i16(i16 %x, i16 %x, i16 %[[tmp]]) - rotate_left(x, shift) -} - -// CHECK-LABEL: @rotate_left_u32 -#[no_mangle] -pub unsafe fn rotate_left_u32(x: u32, shift: u32) -> u32 { - // CHECK-NOT: trunc - // CHECK-NOT: zext - // CHECK: call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 %shift) - rotate_left(x, shift) -} - -// CHECK-LABEL: @rotate_left_u64 -#[no_mangle] -pub unsafe fn rotate_left_u64(x: u64, shift: u32) -> u64 { - // CHECK: %[[tmp:.*]] = zext i32 %shift to i64 - // CHECK: call i64 @llvm.fshl.i64(i64 %x, i64 %x, i64 %[[tmp]]) - rotate_left(x, shift) -} diff --git a/tests/codegen/intrinsics/rustc_intrinsic_must_be_overridden.rs b/tests/codegen/intrinsics/rustc_intrinsic_must_be_overridden.rs deleted file mode 100644 index b41e441d309..00000000000 --- a/tests/codegen/intrinsics/rustc_intrinsic_must_be_overridden.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ revisions: OPT0 OPT1 -//@ [OPT0] compile-flags: -Copt-level=0 -//@ [OPT1] compile-flags: -Copt-level=1 -//@ compile-flags: -Cno-prepopulate-passes - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -// CHECK-NOT: core::intrinsics::size_of_val - -#[no_mangle] -pub unsafe fn size_of_val(ptr: *const i32) -> usize { - core::intrinsics::size_of_val(ptr) -} diff --git a/tests/codegen/intrinsics/select_unpredictable.rs b/tests/codegen/intrinsics/select_unpredictable.rs deleted file mode 100644 index ad7120c6fb8..00000000000 --- a/tests/codegen/intrinsics/select_unpredictable.rs +++ /dev/null @@ -1,71 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled - -#![feature(core_intrinsics)] -#![crate_type = "lib"] - -/* Test the intrinsic */ - -#[no_mangle] -pub fn test_int(p: bool, a: u64, b: u64) -> u64 { - // CHECK-LABEL: define{{.*}} @test_int - // CHECK: select i1 %p, i64 %a, i64 %b, !unpredictable - core::intrinsics::select_unpredictable(p, a, b) -} - -#[no_mangle] -pub fn test_pair(p: bool, a: (u64, u64), b: (u64, u64)) -> (u64, u64) { - // CHECK-LABEL: define{{.*}} @test_pair - // CHECK: select i1 %p, {{.*}}, !unpredictable - core::intrinsics::select_unpredictable(p, a, b) -} - -struct Large { - e: [u64; 100], -} - -#[no_mangle] -pub fn test_struct(p: bool, a: Large, b: Large) -> Large { - // CHECK-LABEL: define{{.*}} @test_struct - // CHECK: select i1 %p, {{.*}}, !unpredictable - core::intrinsics::select_unpredictable(p, a, b) -} - -// ZSTs should not need a `select` expression. -#[no_mangle] -pub fn test_zst(p: bool, a: (), b: ()) -> () { - // CHECK-LABEL: define{{.*}} @test_zst - // CHECK-NEXT: start: - // CHECK-NEXT: ret void - core::intrinsics::select_unpredictable(p, a, b) -} - -/* Test the user-facing version */ - -#[no_mangle] -pub fn test_int2(p: bool, a: u64, b: u64) -> u64 { - // CHECK-LABEL: define{{.*}} @test_int2 - // CHECK: select i1 %p, i64 %a, i64 %b, !unpredictable - core::hint::select_unpredictable(p, a, b) -} - -#[no_mangle] -pub fn test_pair2(p: bool, a: (u64, u64), b: (u64, u64)) -> (u64, u64) { - // CHECK-LABEL: define{{.*}} @test_pair2 - // CHECK: select i1 %p, {{.*}}, !unpredictable - core::hint::select_unpredictable(p, a, b) -} - -#[no_mangle] -pub fn test_struct2(p: bool, a: Large, b: Large) -> Large { - // CHECK-LABEL: define{{.*}} @test_struct2 - // CHECK: select i1 %p, {{.*}}, !unpredictable - core::hint::select_unpredictable(p, a, b) -} - -#[no_mangle] -pub fn test_zst2(p: bool, a: (), b: ()) -> () { - // CHECK-LABEL: define{{.*}} @test_zst2 - // CHECK-NEXT: start: - // CHECK-NEXT: ret void - core::hint::select_unpredictable(p, a, b) -} diff --git a/tests/codegen/intrinsics/three_way_compare.rs b/tests/codegen/intrinsics/three_way_compare.rs deleted file mode 100644 index 95fcb636f7c..00000000000 --- a/tests/codegen/intrinsics/three_way_compare.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ revisions: DEBUG OPTIM -//@ [DEBUG] compile-flags: -C opt-level=0 -//@ [OPTIM] compile-flags: -C opt-level=3 -//@ compile-flags: -C no-prepopulate-passes -//@ min-llvm-version: 20 - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::three_way_compare; - -#[no_mangle] -// CHECK-LABEL: @signed_cmp -// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b) -pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering { - // CHECK: %[[CMP:.+]] = call i8 @llvm.scmp.i8.i16(i16 %a, i16 %b) - // CHECK-NEXT: ret i8 %[[CMP]] - three_way_compare(a, b) -} - -#[no_mangle] -// CHECK-LABEL: @unsigned_cmp -// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b) -pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering { - // CHECK: %[[CMP:.+]] = call i8 @llvm.ucmp.i8.i16(i16 %a, i16 %b) - // CHECK-NEXT: ret i8 %[[CMP]] - three_way_compare(a, b) -} diff --git a/tests/codegen/intrinsics/transmute-niched.rs b/tests/codegen/intrinsics/transmute-niched.rs deleted file mode 100644 index 8ff5cc8ee4f..00000000000 --- a/tests/codegen/intrinsics/transmute-niched.rs +++ /dev/null @@ -1,223 +0,0 @@ -//@ revisions: OPT DBG -//@ [OPT] compile-flags: -C opt-level=3 -C no-prepopulate-passes -//@ [DBG] compile-flags: -C opt-level=0 -C no-prepopulate-passes -//@ only-64bit (so I don't need to worry about usize) -#![crate_type = "lib"] - -use std::mem::transmute; -use std::num::NonZero; -use std::ptr::NonNull; - -#[repr(u8)] -pub enum SmallEnum { - A = 10, - B = 11, - C = 12, -} - -// CHECK-LABEL: @check_to_enum( -#[no_mangle] -pub unsafe fn check_to_enum(x: i8) -> SmallEnum { - // CHECK-NOT: icmp - // CHECK-NOT: assume - // OPT: %0 = sub i8 %x, 10 - // OPT: %1 = icmp ule i8 %0, 2 - // OPT: call void @llvm.assume(i1 %1) - // CHECK-NOT: icmp - // CHECK-NOT: assume - // CHECK: ret i8 %x - - transmute(x) -} - -// CHECK-LABEL: @check_from_enum( -#[no_mangle] -pub unsafe fn check_from_enum(x: SmallEnum) -> i8 { - // CHECK-NOT: icmp - // CHECK-NOT: assume - // OPT: %0 = sub i8 %x, 10 - // OPT: %1 = icmp ule i8 %0, 2 - // OPT: call void @llvm.assume(i1 %1) - // CHECK-NOT: icmp - // CHECK-NOT: assume - // CHECK: ret i8 %x - - transmute(x) -} - -// CHECK-LABEL: @check_to_ordering( -#[no_mangle] -pub unsafe fn check_to_ordering(x: u8) -> std::cmp::Ordering { - // CHECK-NOT: icmp - // CHECK-NOT: assume - // OPT: %0 = sub i8 %x, -1 - // OPT: %1 = icmp ule i8 %0, 2 - // OPT: call void @llvm.assume(i1 %1) - // CHECK-NOT: icmp - // CHECK-NOT: assume - // CHECK: ret i8 %x - - transmute(x) -} - -// CHECK-LABEL: @check_from_ordering( -#[no_mangle] -pub unsafe fn check_from_ordering(x: std::cmp::Ordering) -> u8 { - // CHECK-NOT: icmp - // CHECK-NOT: assume - // OPT: %0 = sub i8 %x, -1 - // OPT: %1 = icmp ule i8 %0, 2 - // OPT: call void @llvm.assume(i1 %1) - // CHECK-NOT: icmp - // CHECK-NOT: assume - // CHECK: ret i8 %x - - transmute(x) -} - -#[repr(i32)] -pub enum Minus100ToPlus100 { - A = -100, - B = -90, - C = -80, - D = -70, - E = -60, - F = -50, - G = -40, - H = -30, - I = -20, - J = -10, - K = 0, - L = 10, - M = 20, - N = 30, - O = 40, - P = 50, - Q = 60, - R = 70, - S = 80, - T = 90, - U = 100, -} - -// CHECK-LABEL: @check_enum_from_char( -#[no_mangle] -pub unsafe fn check_enum_from_char(x: char) -> Minus100ToPlus100 { - // CHECK-NOT: icmp - // CHECK-NOT: assume - // OPT: %0 = icmp ule i32 %x, 1114111 - // OPT: call void @llvm.assume(i1 %0) - // OPT: %1 = sub i32 %x, -100 - // OPT: %2 = icmp ule i32 %1, 200 - // OPT: call void @llvm.assume(i1 %2) - // CHECK-NOT: icmp - // CHECK-NOT: assume - // CHECK: ret i32 %x - - transmute(x) -} - -// CHECK-LABEL: @check_enum_to_char( -#[no_mangle] -pub unsafe fn check_enum_to_char(x: Minus100ToPlus100) -> char { - // CHECK-NOT: icmp - // CHECK-NOT: assume - // OPT: %0 = sub i32 %x, -100 - // OPT: %1 = icmp ule i32 %0, 200 - // OPT: call void @llvm.assume(i1 %1) - // OPT: %2 = icmp ule i32 %x, 1114111 - // OPT: call void @llvm.assume(i1 %2) - // CHECK-NOT: icmp - // CHECK-NOT: assume - // CHECK: ret i32 %x - - transmute(x) -} - -// CHECK-LABEL: @check_swap_pair( -#[no_mangle] -pub unsafe fn check_swap_pair(x: (char, NonZero)) -> (NonZero, char) { - // CHECK-NOT: icmp - // CHECK-NOT: assume - // OPT: %0 = icmp ule i32 %x.0, 1114111 - // OPT: call void @llvm.assume(i1 %0) - // OPT: %1 = sub i32 %x.0, 1 - // OPT: %2 = icmp ule i32 %1, -2 - // OPT: call void @llvm.assume(i1 %2) - // OPT: %3 = sub i32 %x.1, 1 - // OPT: %4 = icmp ule i32 %3, -2 - // OPT: call void @llvm.assume(i1 %4) - // OPT: %5 = icmp ule i32 %x.1, 1114111 - // OPT: call void @llvm.assume(i1 %5) - // CHECK-NOT: icmp - // CHECK-NOT: assume - // CHECK: %[[P1:.+]] = insertvalue { i32, i32 } poison, i32 %x.0, 0 - // CHECK: %[[P2:.+]] = insertvalue { i32, i32 } %[[P1]], i32 %x.1, 1 - // CHECK: ret { i32, i32 } %[[P2]] - - transmute(x) -} - -// CHECK-LABEL: @check_bool_from_ordering( -#[no_mangle] -pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool { - // CHECK-NOT: icmp - // CHECK-NOT: assume - // OPT: %0 = sub i8 %x, -1 - // OPT: %1 = icmp ule i8 %0, 2 - // OPT: call void @llvm.assume(i1 %1) - // OPT: %2 = icmp ule i8 %x, 1 - // OPT: call void @llvm.assume(i1 %2) - // CHECK-NOT: icmp - // CHECK-NOT: assume - // CHECK: %[[R:.+]] = trunc{{( nuw)?}} i8 %x to i1 - // CHECK: ret i1 %[[R]] - - transmute(x) -} - -// CHECK-LABEL: @check_bool_to_ordering( -#[no_mangle] -pub unsafe fn check_bool_to_ordering(x: bool) -> std::cmp::Ordering { - // CHECK: %_0 = zext i1 %x to i8 - // CHECK-NOT: icmp - // CHECK-NOT: assume - // OPT: %0 = icmp ule i8 %_0, 1 - // OPT: call void @llvm.assume(i1 %0) - // OPT: %1 = sub i8 %_0, -1 - // OPT: %2 = icmp ule i8 %1, 2 - // OPT: call void @llvm.assume(i1 %2) - // CHECK-NOT: icmp - // CHECK-NOT: assume - // CHECK: ret i8 %_0 - - transmute(x) -} - -// CHECK-LABEL: @check_nonnull_to_ptr( -#[no_mangle] -pub unsafe fn check_nonnull_to_ptr(x: NonNull) -> *const u8 { - // CHECK-NOT: icmp - // CHECK-NOT: assume - // OPT: %0 = icmp ne ptr %x, null - // OPT: call void @llvm.assume(i1 %0) - // CHECK-NOT: icmp - // CHECK-NOT: assume - // CHECK: ret ptr %x - - transmute(x) -} - -// CHECK-LABEL: @check_ptr_to_nonnull( -#[no_mangle] -pub unsafe fn check_ptr_to_nonnull(x: *const u8) -> NonNull { - // CHECK-NOT: icmp - // CHECK-NOT: assume - // OPT: %0 = icmp ne ptr %x, null - // OPT: call void @llvm.assume(i1 %0) - // CHECK-NOT: icmp - // CHECK-NOT: assume - // CHECK: ret ptr %x - - transmute(x) -} diff --git a/tests/codegen/intrinsics/transmute-x64.rs b/tests/codegen/intrinsics/transmute-x64.rs deleted file mode 100644 index 8c9480ab091..00000000000 --- a/tests/codegen/intrinsics/transmute-x64.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -//@ only-x86_64 (it's using arch-specific types) - -#![crate_type = "lib"] - -use std::arch::x86_64::{__m128, __m128i, __m256i}; -use std::mem::transmute; - -// CHECK-LABEL: @check_sse_pair_to_avx( -#[no_mangle] -pub unsafe fn check_sse_pair_to_avx(x: (__m128i, __m128i)) -> __m256i { - // CHECK: start: - // CHECK-NOT: alloca - // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 32 %_0, ptr align 16 %x, i64 32, i1 false) - // CHECK-NEXT: ret void - transmute(x) -} - -// CHECK-LABEL: @check_sse_pair_from_avx( -#[no_mangle] -pub unsafe fn check_sse_pair_from_avx(x: __m256i) -> (__m128i, __m128i) { - // CHECK: start: - // CHECK-NOT: alloca - // CHECK-NEXT: %[[TEMP:.+]] = load <4 x i64>, ptr %x, align 32 - // CHECK-NEXT: store <4 x i64> %[[TEMP]], ptr %_0, align 16 - // CHECK-NEXT: ret void - transmute(x) -} diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs deleted file mode 100644 index c9a1cd58af3..00000000000 --- a/tests/codegen/intrinsics/transmute.rs +++ /dev/null @@ -1,497 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -//@ only-64bit (so I don't need to worry about usize) - -#![crate_type = "lib"] -#![feature(core_intrinsics)] -#![feature(custom_mir)] -#![allow(unreachable_code)] - -// Some of these need custom MIR to not get removed by MIR optimizations. -use std::intrinsics::mir::*; -use std::intrinsics::{transmute, transmute_unchecked}; -use std::mem::MaybeUninit; -use std::num::NonZero; - -pub enum ZstNever {} - -#[repr(align(2))] -pub struct BigNever(ZstNever, u16, ZstNever); - -#[repr(align(8))] -pub struct Scalar64(i64); - -#[repr(C, align(4))] -pub struct Aggregate64(u16, u8, i8, f32); - -#[repr(C)] -pub struct Aggregate8(u8); - -// CHECK-LABEL: @check_bigger_size( -#[no_mangle] -pub unsafe fn check_bigger_size(x: u16) -> u32 { - // CHECK: store i1 true, ptr poison, align 1 - transmute_unchecked(x) -} - -// CHECK-LABEL: @check_smaller_size( -#[no_mangle] -pub unsafe fn check_smaller_size(x: u32) -> u16 { - // CHECK: store i1 true, ptr poison, align 1 - transmute_unchecked(x) -} - -// CHECK-LABEL: @check_smaller_array( -#[no_mangle] -pub unsafe fn check_smaller_array(x: [u32; 7]) -> [u32; 3] { - // CHECK: store i1 true, ptr poison, align 1 - transmute_unchecked(x) -} - -// CHECK-LABEL: @check_bigger_array( -#[no_mangle] -pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] { - // CHECK: store i1 true, ptr poison, align 1 - transmute_unchecked(x) -} - -// CHECK-LABEL: @check_to_empty_array( -#[no_mangle] -#[custom_mir(dialect = "runtime", phase = "optimized")] -pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] { - // CHECK: start - // CHECK-NEXT: store i1 true, ptr poison, align 1 - // CHECK-NEXT: ret void - mir! { - { - RET = CastTransmute(x); - Return() - } - } -} - -// CHECK-LABEL: @check_from_empty_array( -#[no_mangle] -#[custom_mir(dialect = "runtime", phase = "optimized")] -pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] { - // CHECK: start - // CHECK-NEXT: store i1 true, ptr poison, align 1 - // CHECK-NEXT: ret void - mir! { - { - RET = CastTransmute(x); - Return() - } - } -} - -// CHECK-LABEL: @check_to_uninhabited( -#[no_mangle] -#[custom_mir(dialect = "runtime", phase = "optimized")] -pub unsafe fn check_to_uninhabited(x: u16) { - // CHECK: start - // CHECK-NEXT: store i1 true, ptr poison, align 1 - // CHECK-NEXT: ret void - mir! { - let temp: BigNever; - { - temp = CastTransmute(x); - Return() - } - } -} - -// CHECK-LABEL: @check_from_uninhabited( -#[no_mangle] -#[custom_mir(dialect = "runtime", phase = "optimized")] -pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 { - // CHECK: start - // CHECK-NEXT: store i1 true, ptr poison, align 1 - // CHECK-NEXT: ret i16 poison - mir! { - { - RET = CastTransmute(x); - Return() - } - } -} - -// CHECK-LABEL: @check_intermediate_passthrough( -#[no_mangle] -pub unsafe fn check_intermediate_passthrough(x: u32) -> i32 { - // CHECK: start - // CHECK: %[[TMP:.+]] = add i32 1, %x - // CHECK: %[[RET:.+]] = add i32 %[[TMP]], 1 - // CHECK: ret i32 %[[RET]] - unsafe { transmute::(1 + x) + 1 } -} - -// CHECK-LABEL: @check_nop_pair( -#[no_mangle] -pub unsafe fn check_nop_pair(x: (u8, i8)) -> (i8, u8) { - // CHECK-NOT: alloca - // CHECK: %0 = insertvalue { i8, i8 } poison, i8 %x.0, 0 - // CHECK: %1 = insertvalue { i8, i8 } %0, i8 %x.1, 1 - // CHECK: ret { i8, i8 } %1 - unsafe { transmute(x) } -} - -// CHECK-LABEL: @check_to_newtype( -#[no_mangle] -pub unsafe fn check_to_newtype(x: u64) -> Scalar64 { - // CHECK-NOT: alloca - // CHECK: ret i64 %x - transmute(x) -} - -// CHECK-LABEL: @check_from_newtype( -#[no_mangle] -pub unsafe fn check_from_newtype(x: Scalar64) -> u64 { - // CHECK-NOT: alloca - // CHECK: ret i64 %x - transmute(x) -} - -// CHECK-LABEL: @check_aggregate_to_bool( -#[no_mangle] -pub unsafe fn check_aggregate_to_bool(x: Aggregate8) -> bool { - // CHECK: %x = alloca [1 x i8], align 1 - // CHECK: %[[BYTE:.+]] = load i8, ptr %x, align 1 - // CHECK: %[[BOOL:.+]] = trunc nuw i8 %[[BYTE]] to i1 - // CHECK: ret i1 %[[BOOL]] - transmute(x) -} - -// CHECK-LABEL: @check_aggregate_from_bool( -#[no_mangle] -pub unsafe fn check_aggregate_from_bool(x: bool) -> Aggregate8 { - // CHECK: %_0 = alloca [1 x i8], align 1 - // CHECK: %[[BYTE:.+]] = zext i1 %x to i8 - // CHECK: store i8 %[[BYTE]], ptr %_0, align 1 - transmute(x) -} - -// CHECK-LABEL: @check_byte_to_bool( -#[no_mangle] -pub unsafe fn check_byte_to_bool(x: u8) -> bool { - // CHECK-NOT: alloca - // CHECK: %[[R:.+]] = trunc nuw i8 %x to i1 - // CHECK: ret i1 %[[R]] - transmute(x) -} - -// CHECK-LABEL: @check_byte_from_bool( -#[no_mangle] -pub unsafe fn check_byte_from_bool(x: bool) -> u8 { - // CHECK-NOT: alloca - // CHECK: %[[R:.+]] = zext i1 %x to i8 - // CHECK: ret i8 %[[R:.+]] - transmute(x) -} - -// CHECK-LABEL: @check_to_pair( -#[no_mangle] -pub unsafe fn check_to_pair(x: u64) -> Option { - // CHECK: %_0 = alloca [8 x i8], align 4 - // CHECK: store i64 %x, ptr %_0, align 4 - transmute(x) -} - -// CHECK-LABEL: @check_from_pair( -#[no_mangle] -pub unsafe fn check_from_pair(x: Option) -> u64 { - // The two arguments are of types that are only 4-aligned, but they're - // immediates so we can write using the destination alloca's alignment. - const { assert!(std::mem::align_of::>() == 4) }; - - // CHECK: %_0 = alloca [8 x i8], align 8 - // CHECK: store i32 %x.0, ptr %_0, align 8 - // CHECK: store i32 %x.1, ptr %0, align 4 - // CHECK: %[[R:.+]] = load i64, ptr %_0, align 8 - // CHECK: ret i64 %[[R]] - transmute(x) -} - -// CHECK-LABEL: @check_to_float( -#[no_mangle] -pub unsafe fn check_to_float(x: u32) -> f32 { - // CHECK-NOT: alloca - // CHECK: %_0 = bitcast i32 %x to float - // CHECK: ret float %_0 - transmute(x) -} - -// CHECK-LABEL: @check_from_float( -#[no_mangle] -pub unsafe fn check_from_float(x: f32) -> u32 { - // CHECK-NOT: alloca - // CHECK: %_0 = bitcast float %x to i32 - // CHECK: ret i32 %_0 - transmute(x) -} - -// CHECK-LABEL: @check_to_bytes( -#[no_mangle] -pub unsafe fn check_to_bytes(x: u32) -> [u8; 4] { - // CHECK: %_0 = alloca [4 x i8], align 1 - // CHECK: store i32 %x, ptr %_0, align 1 - transmute(x) -} - -// CHECK-LABEL: @check_from_bytes( -#[no_mangle] -pub unsafe fn check_from_bytes(x: [u8; 4]) -> u32 { - // CHECK: %x = alloca [4 x i8], align 1 - // CHECK: %[[VAL:.+]] = load i32, ptr %x, align 1 - // CHECK: ret i32 %[[VAL]] - transmute(x) -} - -// CHECK-LABEL: @check_to_aggregate( -#[no_mangle] -pub unsafe fn check_to_aggregate(x: u64) -> Aggregate64 { - // CHECK: %_0 = alloca [8 x i8], align 4 - // CHECK: store i64 %x, ptr %_0, align 4 - // CHECK: %0 = load i64, ptr %_0, align 4 - // CHECK: ret i64 %0 - transmute(x) -} - -// CHECK-LABEL: @check_from_aggregate( -#[no_mangle] -pub unsafe fn check_from_aggregate(x: Aggregate64) -> u64 { - // CHECK: %x = alloca [8 x i8], align 4 - // CHECK: %[[VAL:.+]] = load i64, ptr %x, align 4 - // CHECK: ret i64 %[[VAL]] - transmute(x) -} - -// CHECK-LABEL: @check_long_array_less_aligned( -#[no_mangle] -pub unsafe fn check_long_array_less_aligned(x: [u64; 100]) -> [u16; 400] { - // CHECK-NEXT: start - // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 2 %_0, ptr align 8 %x, i64 800, i1 false) - // CHECK-NEXT: ret void - transmute(x) -} - -// CHECK-LABEL: @check_long_array_more_aligned( -#[no_mangle] -pub unsafe fn check_long_array_more_aligned(x: [u8; 100]) -> [u32; 25] { - // CHECK-NEXT: start - // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %_0, ptr align 1 %x, i64 100, i1 false) - // CHECK-NEXT: ret void - transmute(x) -} - -// CHECK-LABEL: @check_pair_with_bool( -#[no_mangle] -pub unsafe fn check_pair_with_bool(x: (u8, bool)) -> (bool, i8) { - // CHECK-NOT: alloca - // CHECK: trunc nuw i8 %x.0 to i1 - // CHECK: zext i1 %x.1 to i8 - transmute(x) -} - -// CHECK-LABEL: @check_float_to_pointer( -#[no_mangle] -pub unsafe fn check_float_to_pointer(x: f64) -> *const () { - // CHECK-NOT: alloca - // CHECK: %0 = bitcast double %x to i64 - // CHECK: %_0 = getelementptr i8, ptr null, i64 %0 - // CHECK: ret ptr %_0 - transmute(x) -} - -// CHECK-LABEL: @check_float_from_pointer( -#[no_mangle] -pub unsafe fn check_float_from_pointer(x: *const ()) -> f64 { - // CHECK-NOT: alloca - // CHECK: %0 = ptrtoint ptr %x to i64 - // CHECK: %_0 = bitcast i64 %0 to double - // CHECK: ret double %_0 - transmute(x) -} - -// CHECK-LABEL: @check_array_to_pair( -#[no_mangle] -pub unsafe fn check_array_to_pair(x: [u8; 16]) -> (i64, u64) { - // CHECK-NOT: alloca - // CHECK: %[[FST:.+]] = load i64, ptr %{{.+}}, align 1, !noundef ! - // CHECK: %[[SND:.+]] = load i64, ptr %{{.+}}, align 1, !noundef ! - // CHECK: %[[PAIR0:.+]] = insertvalue { i64, i64 } poison, i64 %[[FST]], 0 - // CHECK: %[[PAIR01:.+]] = insertvalue { i64, i64 } %[[PAIR0]], i64 %[[SND]], 1 - // CHECK: ret { i64, i64 } %[[PAIR01]] - transmute(x) -} - -// CHECK-LABEL: @check_pair_to_array( -#[no_mangle] -pub unsafe fn check_pair_to_array(x: (i64, u64)) -> [u8; 16] { - // CHECK-NOT: alloca - // CHECK: store i64 %x.0, ptr %{{.+}}, align 1 - // CHECK: store i64 %x.1, ptr %{{.+}}, align 1 - transmute(x) -} - -// CHECK-LABEL: @check_heterogeneous_integer_pair( -#[no_mangle] -pub unsafe fn check_heterogeneous_integer_pair(x: (i32, bool)) -> (bool, u32) { - // CHECK: store i32 %x.0 - // CHECK: %[[WIDER:.+]] = zext i1 %x.1 to i8 - // CHECK: store i8 %[[WIDER]] - - // CHECK: %[[BYTE:.+]] = load i8 - // CHECK: trunc nuw i8 %[[BYTE:.+]] to i1 - // CHECK: load i32 - transmute(x) -} - -// CHECK-LABEL: @check_heterogeneous_float_pair( -#[no_mangle] -pub unsafe fn check_heterogeneous_float_pair(x: (f64, f32)) -> (f32, f64) { - // CHECK: store double %x.0 - // CHECK: store float %x.1 - // CHECK: %[[A:.+]] = load float - // CHECK: %[[B:.+]] = load double - // CHECK: %[[P:.+]] = insertvalue { float, double } poison, float %[[A]], 0 - // CHECK: insertvalue { float, double } %[[P]], double %[[B]], 1 - transmute(x) -} - -// CHECK-LABEL: @check_issue_110005( -#[no_mangle] -pub unsafe fn check_issue_110005(x: (usize, bool)) -> Option> { - // CHECK: store i64 %x.0 - // CHECK: %[[WIDER:.+]] = zext i1 %x.1 to i8 - // CHECK: store i8 %[[WIDER]] - // CHECK: load ptr - // CHECK: load i64 - transmute(x) -} - -// CHECK-LABEL: @check_pair_to_dst_ref( -#[no_mangle] -pub unsafe fn check_pair_to_dst_ref<'a>(x: (usize, usize)) -> &'a [u8] { - // CHECK: %_0.0 = getelementptr i8, ptr null, i64 %x.0 - // CHECK: %0 = icmp ne ptr %_0.0, null - // CHECK: call void @llvm.assume(i1 %0) - // CHECK: %1 = insertvalue { ptr, i64 } poison, ptr %_0.0, 0 - // CHECK: %2 = insertvalue { ptr, i64 } %1, i64 %x.1, 1 - // CHECK: ret { ptr, i64 } %2 - transmute(x) -} - -// CHECK-LABEL: @check_issue_109992( -#[no_mangle] -#[custom_mir(dialect = "runtime", phase = "optimized")] -pub unsafe fn check_issue_109992(x: ()) -> [(); 1] { - // This uses custom MIR to avoid MIR optimizations having removed ZST ops. - - // CHECK: start - // CHECK-NEXT: ret void - mir! { - { - RET = CastTransmute(x); - Return() - } - } -} - -// CHECK-LABEL: @check_unit_to_never( -#[no_mangle] -#[custom_mir(dialect = "runtime", phase = "optimized")] -pub unsafe fn check_unit_to_never(x: ()) { - // This uses custom MIR to avoid MIR optimizations having removed ZST ops. - - // CHECK: start - // CHECK-NEXT: store i1 true, ptr poison, align 1 - // CHECK-NEXT: ret void - mir! { - let temp: ZstNever; - { - temp = CastTransmute(x); - Return() - } - } -} - -// CHECK-LABEL: @check_unit_from_never( -#[no_mangle] -#[custom_mir(dialect = "runtime", phase = "optimized")] -pub unsafe fn check_unit_from_never(x: ZstNever) -> () { - // This uses custom MIR to avoid MIR optimizations having removed ZST ops. - - // CHECK: start - // CHECK-NEXT: store i1 true, ptr poison, align 1 - // CHECK-NEXT: ret void - mir! { - { - RET = CastTransmute(x); - Return() - } - } -} - -// CHECK-LABEL: @check_maybe_uninit_pair(i16 %x.0, i64 %x.1) -#[no_mangle] -pub unsafe fn check_maybe_uninit_pair( - x: (MaybeUninit, MaybeUninit), -) -> (MaybeUninit, MaybeUninit) { - // Thanks to `MaybeUninit` this is actually defined behaviour, - // unlike the examples above with pairs of primitives. - - // CHECK: store i16 %x.0 - // CHECK: store i64 %x.1 - // CHECK: load i64 - // CHECK-NOT: noundef - // CHECK: load i16 - // CHECK-NOT: noundef - // CHECK: ret { i64, i16 } - transmute(x) -} - -#[repr(align(8))] -pub struct HighAlignScalar(u8); - -// CHECK-LABEL: @check_to_overalign( -#[no_mangle] -pub unsafe fn check_to_overalign(x: u64) -> HighAlignScalar { - // CHECK: %_0 = alloca [8 x i8], align 8 - // CHECK: store i64 %x, ptr %_0, align 8 - // CHECK: %0 = load i64, ptr %_0, align 8 - // CHECK: ret i64 %0 - transmute(x) -} - -// CHECK-LABEL: @check_from_overalign( -#[no_mangle] -pub unsafe fn check_from_overalign(x: HighAlignScalar) -> u64 { - // CHECK: %x = alloca [8 x i8], align 8 - // CHECK: %[[VAL:.+]] = load i64, ptr %x, align 8 - // CHECK: ret i64 %[[VAL]] - transmute(x) -} - -#[repr(transparent)] -struct Level1(std::num::NonZero); -#[repr(transparent)] -struct Level2(Level1); -#[repr(transparent)] -struct Level3(Level2); - -// CHECK-LABEL: @repeatedly_transparent_transmute -// CHECK-SAME: (i32{{.+}}%[[ARG:[^)]+]]) -#[no_mangle] -#[custom_mir(dialect = "runtime", phase = "optimized")] -pub unsafe fn repeatedly_transparent_transmute(x: NonZero) -> Level3 { - // CHECK: start - // CHECK-NEXT: ret i32 %[[ARG]] - mir! { - { - let A = CastTransmute::, Level1>(x); - let B = CastTransmute::(A); - RET = CastTransmute::(B); - Return() - } - } -} diff --git a/tests/codegen/intrinsics/typed_swap.rs b/tests/codegen/intrinsics/typed_swap.rs deleted file mode 100644 index 6b55078407a..00000000000 --- a/tests/codegen/intrinsics/typed_swap.rs +++ /dev/null @@ -1,77 +0,0 @@ -//@ revisions: OPT0 OPT3 -//@ [OPT0] compile-flags: -Copt-level=0 -//@ [OPT3] compile-flags: -Copt-level=3 -//@ compile-flags: -C no-prepopulate-passes -//@ only-64bit (so I don't need to worry about usize) -// ignore-tidy-linelength (the memcpy calls get long) - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::typed_swap_nonoverlapping; - -// CHECK-LABEL: @swap_unit( -#[no_mangle] -pub unsafe fn swap_unit(x: &mut (), y: &mut ()) { - // CHECK: start - // CHECK-NEXT: ret void - typed_swap_nonoverlapping(x, y) -} - -// CHECK-LABEL: @swap_i32( -#[no_mangle] -pub unsafe fn swap_i32(x: &mut i32, y: &mut i32) { - // CHECK-NOT: alloca - - // CHECK: %[[TEMP:.+]] = load i32, ptr %x, align 4 - // OPT3-SAME: !noundef - // OPT0: %[[TEMP2:.+]] = load i32, ptr %y, align 4 - // OPT0: store i32 %[[TEMP2]], ptr %x, align 4 - // OPT0-NOT: memcpy - // OPT3-NOT: load - // OPT3: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 4, i1 false) - // CHECK: store i32 %[[TEMP]], ptr %y, align 4 - // CHECK: ret void - typed_swap_nonoverlapping(x, y) -} - -// CHECK-LABEL: @swap_pair( -#[no_mangle] -pub unsafe fn swap_pair(x: &mut (i32, u32), y: &mut (i32, u32)) { - // CHECK-NOT: alloca - - // CHECK: load i32 - // OPT3-SAME: !noundef - // CHECK: load i32 - // OPT3-SAME: !noundef - // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 8, i1 false) - // CHECK: store i32 - // CHECK: store i32 - typed_swap_nonoverlapping(x, y) -} - -// CHECK-LABEL: @swap_str( -#[no_mangle] -pub unsafe fn swap_str<'a>(x: &mut &'a str, y: &mut &'a str) { - // CHECK-NOT: alloca - - // CHECK: load ptr - // OPT3-SAME: !nonnull - // OPT3-SAME: !noundef - // CHECK: load i64 - // OPT3-SAME: !noundef - // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %x, ptr align 8 %y, i64 16, i1 false) - // CHECK: store ptr - // CHECK: store i64 - typed_swap_nonoverlapping(x, y) -} - -// OPT0-LABEL: @swap_string( -#[no_mangle] -pub unsafe fn swap_string(x: &mut String, y: &mut String) { - // OPT0: %[[TEMP:.+]] = alloca {{.+}}, align 8 - // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[TEMP]], ptr align 8 %x, i64 24, i1 false) - // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %x, ptr align 8 %y, i64 24, i1 false) - // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %y, ptr align 8 %[[TEMP]], i64 24, i1 false) - typed_swap_nonoverlapping(x, y) -} diff --git a/tests/codegen/intrinsics/unchecked_math.rs b/tests/codegen/intrinsics/unchecked_math.rs deleted file mode 100644 index 419c120ede9..00000000000 --- a/tests/codegen/intrinsics/unchecked_math.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::*; - -// CHECK-LABEL: @unchecked_add_signed -#[no_mangle] -pub unsafe fn unchecked_add_signed(a: i32, b: i32) -> i32 { - // CHECK: add nsw - unchecked_add(a, b) -} - -// CHECK-LABEL: @unchecked_add_unsigned -#[no_mangle] -pub unsafe fn unchecked_add_unsigned(a: u32, b: u32) -> u32 { - // CHECK: add nuw - unchecked_add(a, b) -} - -// CHECK-LABEL: @unchecked_sub_signed -#[no_mangle] -pub unsafe fn unchecked_sub_signed(a: i32, b: i32) -> i32 { - // CHECK: sub nsw - unchecked_sub(a, b) -} - -// CHECK-LABEL: @unchecked_sub_unsigned -#[no_mangle] -pub unsafe fn unchecked_sub_unsigned(a: u32, b: u32) -> u32 { - // CHECK: sub nuw - unchecked_sub(a, b) -} - -// CHECK-LABEL: @unchecked_mul_signed -#[no_mangle] -pub unsafe fn unchecked_mul_signed(a: i32, b: i32) -> i32 { - // CHECK: mul nsw - unchecked_mul(a, b) -} - -// CHECK-LABEL: @unchecked_mul_unsigned -#[no_mangle] -pub unsafe fn unchecked_mul_unsigned(a: u32, b: u32) -> u32 { - // CHECK: mul nuw - unchecked_mul(a, b) -} diff --git a/tests/codegen/intrinsics/unlikely.rs b/tests/codegen/intrinsics/unlikely.rs deleted file mode 100644 index 90ebf070d27..00000000000 --- a/tests/codegen/intrinsics/unlikely.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::unlikely; - -#[inline(never)] -#[no_mangle] -pub fn path_a() { - println!("path a"); -} - -#[inline(never)] -#[no_mangle] -pub fn path_b() { - println!("path b"); -} - -#[no_mangle] -pub fn test_unlikely(x: bool) { - if unlikely(x) { - path_a(); - } else { - path_b(); - } -} - -// CHECK-LABEL: @test_unlikely( -// CHECK: br i1 %x, label %bb2, label %bb4, !prof ![[NUM:[0-9]+]] -// CHECK: bb4: -// CHECK: path_b -// CHECK: bb2: -// CHECK-NOT: cold_path -// CHECK: path_a -// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000} diff --git a/tests/codegen/intrinsics/volatile.rs b/tests/codegen/intrinsics/volatile.rs deleted file mode 100644 index 2dea5ecb2ca..00000000000 --- a/tests/codegen/intrinsics/volatile.rs +++ /dev/null @@ -1,55 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics; - -// CHECK-LABEL: @volatile_copy_memory -#[no_mangle] -pub unsafe fn volatile_copy_memory(a: *mut u8, b: *const u8) { - // CHECK: llvm.memmove.{{\w*(.*true)}} - intrinsics::volatile_copy_memory(a, b, 1) -} - -// CHECK-LABEL: @volatile_copy_nonoverlapping_memory -#[no_mangle] -pub unsafe fn volatile_copy_nonoverlapping_memory(a: *mut u8, b: *const u8) { - // CHECK: llvm.memcpy.{{\w*(.*true)}} - intrinsics::volatile_copy_nonoverlapping_memory(a, b, 1) -} - -// CHECK-LABEL: @volatile_set_memory -#[no_mangle] -pub unsafe fn volatile_set_memory(a: *mut u8, b: u8) { - // CHECK: llvm.memset.{{\w*(.*true)}} - intrinsics::volatile_set_memory(a, b, 1) -} - -// CHECK-LABEL: @volatile_load -#[no_mangle] -pub unsafe fn volatile_load(a: *const u8) -> u8 { - // CHECK: load volatile - intrinsics::volatile_load(a) -} - -// CHECK-LABEL: @volatile_store -#[no_mangle] -pub unsafe fn volatile_store(a: *mut u8, b: u8) { - // CHECK: store volatile - intrinsics::volatile_store(a, b) -} - -// CHECK-LABEL: @unaligned_volatile_load -#[no_mangle] -pub unsafe fn unaligned_volatile_load(a: *const u8) -> u8 { - // CHECK: load volatile - intrinsics::unaligned_volatile_load(a) -} - -// CHECK-LABEL: @unaligned_volatile_store -#[no_mangle] -pub unsafe fn unaligned_volatile_store(a: *mut u8, b: u8) { - // CHECK: store volatile - intrinsics::unaligned_volatile_store(a, b) -} diff --git a/tests/codegen/intrinsics/volatile_order.rs b/tests/codegen/intrinsics/volatile_order.rs deleted file mode 100644 index 99469831a6c..00000000000 --- a/tests/codegen/intrinsics/volatile_order.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -use std::intrinsics::*; - -pub unsafe fn test_volatile_order() { - let mut a: Box = Box::new(0); - // CHECK: load volatile - let x = volatile_load(&*a); - // CHECK: load volatile - let x = volatile_load(&*a); - // CHECK: store volatile - volatile_store(&mut *a, 12); - // CHECK: store volatile - unaligned_volatile_store(&mut *a, 12); - // CHECK: llvm.memset.p0 - volatile_set_memory(&mut *a, 12, 1) -} diff --git a/tests/codegen/is_val_statically_known.rs b/tests/codegen/is_val_statically_known.rs deleted file mode 100644 index 8119d3a3bf6..00000000000 --- a/tests/codegen/is_val_statically_known.rs +++ /dev/null @@ -1,163 +0,0 @@ -//@ compile-flags: --crate-type=lib -Zmerge-functions=disabled -Copt-level=3 - -#![feature(core_intrinsics)] -#![feature(f16, f128)] - -use std::intrinsics::is_val_statically_known; - -pub struct A(u32); -pub enum B { - Ye(u32), -} - -#[inline] -pub fn _u32(a: u32) -> i32 { - if is_val_statically_known(a) { 1 } else { 0 } -} - -// CHECK-LABEL: @_u32_true( -#[no_mangle] -pub fn _u32_true() -> i32 { - // CHECK: ret i32 1 - _u32(1) -} - -// CHECK-LABEL: @_u32_false( -#[no_mangle] -pub fn _u32_false(a: u32) -> i32 { - // CHECK: ret i32 0 - _u32(a) -} - -#[inline] -pub fn _bool(b: bool) -> i32 { - if is_val_statically_known(b) { 3 } else { 2 } -} - -// CHECK-LABEL: @_bool_true( -#[no_mangle] -pub fn _bool_true() -> i32 { - // CHECK: ret i32 3 - _bool(true) -} - -// CHECK-LABEL: @_bool_false( -#[no_mangle] -pub fn _bool_false(b: bool) -> i32 { - // CHECK: ret i32 2 - _bool(b) -} - -#[inline] -pub fn _iref(a: &u8) -> i32 { - if is_val_statically_known(a) { 5 } else { 4 } -} - -// CHECK-LABEL: @_iref_borrow( -#[no_mangle] -pub fn _iref_borrow() -> i32 { - // CHECK: ret i32 4 - _iref(&0) -} - -// CHECK-LABEL: @_iref_arg( -#[no_mangle] -pub fn _iref_arg(a: &u8) -> i32 { - // CHECK: ret i32 4 - _iref(a) -} - -#[inline] -pub fn _slice_ref(a: &[u8]) -> i32 { - if is_val_statically_known(a) { 7 } else { 6 } -} - -// CHECK-LABEL: @_slice_ref_borrow( -#[no_mangle] -pub fn _slice_ref_borrow() -> i32 { - // CHECK: ret i32 6 - _slice_ref(&[0; 3]) -} - -// CHECK-LABEL: @_slice_ref_arg( -#[no_mangle] -pub fn _slice_ref_arg(a: &[u8]) -> i32 { - // CHECK: ret i32 6 - _slice_ref(a) -} - -#[inline] -pub fn _f16(a: f16) -> i32 { - if is_val_statically_known(a) { 1 } else { 0 } -} - -// CHECK-LABEL: @_f16_true( -#[no_mangle] -pub fn _f16_true() -> i32 { - // CHECK: ret i32 1 - _f16(1.0) -} - -// CHECK-LABEL: @_f16_false( -#[no_mangle] -pub fn _f16_false(a: f16) -> i32 { - // CHECK: ret i32 0 - _f16(a) -} - -#[inline] -pub fn _f32(a: f32) -> i32 { - if is_val_statically_known(a) { 1 } else { 0 } -} - -// CHECK-LABEL: @_f32_true( -#[no_mangle] -pub fn _f32_true() -> i32 { - // CHECK: ret i32 1 - _f32(1.0) -} - -// CHECK-LABEL: @_f32_false( -#[no_mangle] -pub fn _f32_false(a: f32) -> i32 { - // CHECK: ret i32 0 - _f32(a) -} - -#[inline] -pub fn _f64(a: f64) -> i32 { - if is_val_statically_known(a) { 1 } else { 0 } -} - -// CHECK-LABEL: @_f64_true( -#[no_mangle] -pub fn _f64_true() -> i32 { - // CHECK: ret i32 1 - _f64(1.0) -} - -// CHECK-LABEL: @_f64_false( -#[no_mangle] -pub fn _f64_false(a: f64) -> i32 { - // CHECK: ret i32 0 - _f64(a) -} - -#[inline] -pub fn _f128(a: f128) -> i32 { - if is_val_statically_known(a) { 1 } else { 0 } -} - -// CHECK-LABEL: @_f128_true( -#[no_mangle] -pub fn _f128_true() -> i32 { - // CHECK: ret i32 1 - _f128(1.0) -} - -// CHECK-LABEL: @_f128_false( -#[no_mangle] -pub fn _f128_false(a: f128) -> i32 { - // CHECK: ret i32 0 - _f128(a) -} diff --git a/tests/codegen/issue-97217.rs b/tests/codegen/issue-97217.rs deleted file mode 100644 index ef9acc5fc93..00000000000 --- a/tests/codegen/issue-97217.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ compile-flags: -C opt-level=3 -#![crate_type = "lib"] - -// Regression test for issue 97217 (the following should result in no allocations) - -// CHECK-LABEL: @issue97217 -#[no_mangle] -pub fn issue97217() -> i32 { - // drop_in_place should be inlined and never appear - // CHECK-NOT: drop_in_place - - // __rust_alloc should be optimized out - // CHECK-NOT: __rust_alloc - - let v1 = vec![5, 6, 7]; - let v1_iter = v1.iter(); - let total: i32 = v1_iter.sum(); - println!("{}", total); - total -} diff --git a/tests/codegen/issues/issue-101048.rs b/tests/codegen/issues/issue-101048.rs deleted file mode 100644 index cfe65e758fd..00000000000 --- a/tests/codegen/issues/issue-101048.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -#[no_mangle] -pub fn all_zero(data: &[u64]) -> bool { - // CHECK-LABEL: @all_zero( - // CHECK: [[PHI:%.*]] = phi i1 - // CHECK-NOT: phi i8 - // CHECK-NOT: zext - data.iter().copied().fold(true, |acc, x| acc & (x == 0)) -} diff --git a/tests/codegen/issues/issue-101082.rs b/tests/codegen/issues/issue-101082.rs deleted file mode 100644 index 8d15921ddb4..00000000000 --- a/tests/codegen/issues/issue-101082.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ revisions: host x86-64 x86-64-v3 -//@ min-llvm-version: 20 - -//@[host] ignore-x86_64 - -// Set the base cpu explicitly, in case the default has been changed. -//@[x86-64] only-x86_64 -//@[x86-64] compile-flags: -Ctarget-cpu=x86-64 - -// FIXME(cuviper) x86-64-v3 in particular regressed in #131563, and the workaround -// at the time still sometimes fails, so only verify it for the power-of-two size -// - https://github.com/llvm/llvm-project/issues/134735 -//@[x86-64-v3] only-x86_64 -//@[x86-64-v3] min-llvm-version: 21 -//@[x86-64-v3] compile-flags: -Ctarget-cpu=x86-64-v3 - -#![crate_type = "lib"] - -#[no_mangle] -pub fn test() -> usize { - // CHECK-LABEL: @test( - // CHECK: ret {{i64|i32}} 165 - let values = [23, 16, 54, 3, 60, 9]; - let mut acc = 0; - for item in values { - acc += item; - } - acc -} - -#[no_mangle] -pub fn test_eight() -> usize { - // CHECK-LABEL: @test_eight( - // CHECK: ret {{i64|i32}} 220 - let values = [23, 16, 54, 3, 60, 9, 13, 42]; - let mut acc = 0; - for item in values { - acc += item; - } - acc -} diff --git a/tests/codegen/issues/issue-101814.rs b/tests/codegen/issues/issue-101814.rs deleted file mode 100644 index 668ec8476e8..00000000000 --- a/tests/codegen/issues/issue-101814.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -#[no_mangle] -pub fn test(a: [i32; 10]) -> i32 { - // CHECK-LABEL: @test( - // CHECK: [[L1:%.+]] = load i32 - // CHECK: [[L2:%.+]] = load i32 - // CHECK: [[R:%.+]] = add i32 [[L1]], [[L2]] - // CHECK: ret i32 [[R]] - let mut sum = 0; - for v in a.iter().skip(8) { - sum += v; - } - - sum -} diff --git a/tests/codegen/issues/issue-103132.rs b/tests/codegen/issues/issue-103132.rs deleted file mode 100644 index 623cab92806..00000000000 --- a/tests/codegen/issues/issue-103132.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C overflow-checks - -#![crate_type = "lib"] - -#[no_mangle] -pub fn test(arr: &[u8], weight: u32) { - // CHECK-LABEL: @test( - // CHECK-NOT: panic - let weight = weight.min(256 * 256 * 256); - - for x in arr { - assert!(weight <= 256 * 256 * 256); - let result = *x as u32 * weight; - } -} diff --git a/tests/codegen/issues/issue-103285-ptr-addr-overflow-check.rs b/tests/codegen/issues/issue-103285-ptr-addr-overflow-check.rs deleted file mode 100644 index 3ada5412e83..00000000000 --- a/tests/codegen/issues/issue-103285-ptr-addr-overflow-check.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C debug-assertions=yes - -#![crate_type = "lib"] - -#[no_mangle] -pub fn test(src: *const u8, dst: *const u8) -> usize { - // CHECK-LABEL: @test( - // CHECK-NOT: panic - let src_usize = src.addr(); - let dst_usize = dst.addr(); - if src_usize > dst_usize { - return src_usize - dst_usize; - } - return 0; -} diff --git a/tests/codegen/issues/issue-103327.rs b/tests/codegen/issues/issue-103327.rs deleted file mode 100644 index 4de3cfd12a0..00000000000 --- a/tests/codegen/issues/issue-103327.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -#[no_mangle] -pub fn test(a: i32, b: i32) -> bool { - // CHECK-LABEL: @test( - // CHECK: ret i1 true - let c1 = (a >= 0) && (a <= 10); - let c2 = (b >= 0) && (b <= 20); - - if c1 & c2 { a + 100 != b } else { true } -} diff --git a/tests/codegen/issues/issue-103840.rs b/tests/codegen/issues/issue-103840.rs deleted file mode 100644 index c6c5098bdd0..00000000000 --- a/tests/codegen/issues/issue-103840.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -pub fn foo(t: &mut Vec) { - // CHECK-NOT: __rust_dealloc - let mut taken = std::mem::take(t); - taken.pop(); - *t = taken; -} diff --git a/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs b/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs deleted file mode 100644 index 848aa910b58..00000000000 --- a/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ compile-flags: --crate-type=lib -Copt-level=3 -Cdebuginfo=2 -Cno-prepopulate-passes -Zmir-enable-passes=-ScalarReplacementOfAggregates -// MIR SROA will decompose the closure -#![feature(stmt_expr_attributes)] - -pub struct S([usize; 8]); - -#[no_mangle] -pub fn outer_function(x: S, y: S) -> usize { - (#[inline(always)] - || { - let _z = x; - y.0[0] - })() -} - -// Check that we do not attempt to load from the spilled arg before it is assigned to -// when generating debuginfo. -// CHECK-LABEL: @outer_function -// CHECK: [[spill:%.*]] = alloca -// CHECK-NOT: [[ptr_tmp:%.*]] = getelementptr inbounds i8, ptr [[spill]] -// CHECK-NOT: [[load:%.*]] = load ptr, ptr -// CHECK: call void @llvm.lifetime.start{{.*}}({{.*}}, ptr [[spill]]) -// CHECK: [[inner:%.*]] = getelementptr inbounds i8, ptr [[spill]] -// CHECK: call void @llvm.memcpy{{.*}}(ptr {{align .*}} [[inner]], ptr {{align .*}} %x diff --git a/tests/codegen/issues/issue-106369.rs b/tests/codegen/issues/issue-106369.rs deleted file mode 100644 index 3583d20c9fa..00000000000 --- a/tests/codegen/issues/issue-106369.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// From - -// CHECK-LABEL: @issue_106369( -#[no_mangle] -pub unsafe fn issue_106369(ptr: *const &i32) -> bool { - // CHECK-NOT: icmp - // CHECK: ret i1 true - // CHECK-NOT: icmp - Some(std::ptr::read(ptr)).is_some() -} diff --git a/tests/codegen/issues/issue-107681-unwrap_unchecked.rs b/tests/codegen/issues/issue-107681-unwrap_unchecked.rs deleted file mode 100644 index 69aefc6b1fb..00000000000 --- a/tests/codegen/issues/issue-107681-unwrap_unchecked.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -// Test for #107681. -// Make sure we don't create `br` or `select` instructions. - -#![crate_type = "lib"] - -use std::iter::Copied; -use std::slice::Iter; - -#[no_mangle] -pub unsafe fn foo(x: &mut Copied>) -> u32 { - // CHECK-LABEL: @foo( - // CHECK-NOT: br - // CHECK-NOT: select - // CHECK: [[RET:%.*]] = load i32, ptr - // CHECK-NEXT: ret i32 [[RET]] - x.next().unwrap_unchecked() -} diff --git a/tests/codegen/issues/issue-108395-branchy-bool-match.rs b/tests/codegen/issues/issue-108395-branchy-bool-match.rs deleted file mode 100644 index 96387e791b0..00000000000 --- a/tests/codegen/issues/issue-108395-branchy-bool-match.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled -//! Test for . Check that -//! matching on two bools with wildcards does not produce branches. -#![crate_type = "lib"] - -// CHECK-LABEL: @wildcard( -#[no_mangle] -pub fn wildcard(a: u16, b: u16, v: u16) -> u16 { - // CHECK-NOT: br - match (a == v, b == v) { - (true, false) => 0, - (false, true) => u16::MAX, - _ => 1 << 15, // half - } -} - -// CHECK-LABEL: @exhaustive( -#[no_mangle] -pub fn exhaustive(a: u16, b: u16, v: u16) -> u16 { - // CHECK-NOT: br - match (a == v, b == v) { - (true, false) => 0, - (false, true) => u16::MAX, - (true, true) => 1 << 15, - (false, false) => 1 << 15, - } -} diff --git a/tests/codegen/issues/issue-109328-split_first.rs b/tests/codegen/issues/issue-109328-split_first.rs deleted file mode 100644 index 26235edfc19..00000000000 --- a/tests/codegen/issues/issue-109328-split_first.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @foo -// CHECK-NEXT: {{.*}}: -// CHECK-NEXT: getelementptr inbounds -// CHECK-NEXT: load [[TYPE:i(32|64)]] -// CHECK-NEXT: icmp eq [[TYPE]] -// CHECK-NEXT: br i1 -#[no_mangle] -pub fn foo(input: &mut &[u64]) -> Option { - let (first, rest) = input.split_first()?; - *input = rest; - Some(*first) -} diff --git a/tests/codegen/issues/issue-110797-enum-jump-same.rs b/tests/codegen/issues/issue-110797-enum-jump-same.rs deleted file mode 100644 index b5f7c08795b..00000000000 --- a/tests/codegen/issues/issue-110797-enum-jump-same.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -pub enum K { - A(Box<[i32]>), - B(Box<[u8]>), - C(Box<[String]>), - D(Box<[u16]>), -} - -// CHECK-LABEL: @get_len -// CHECK-NEXT: {{.*}}: -// CHECK-NEXT: getelementptr inbounds -// CHECK-NEXT: load [[TYPE:i(32|64)]] -// CHECK-NEXT: ret [[TYPE]] -#[no_mangle] -pub fn get_len(arg: &K) -> usize { - match arg { - K::A(ref lst) => lst.len(), - K::B(ref lst) => lst.len(), - K::C(ref lst) => lst.len(), - K::D(ref lst) => lst.len(), - } -} diff --git a/tests/codegen/issues/issue-111603.rs b/tests/codegen/issues/issue-111603.rs deleted file mode 100644 index 2ba5a3f876a..00000000000 --- a/tests/codegen/issues/issue-111603.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] -#![feature(get_mut_unchecked, new_uninit)] - -use std::sync::Arc; - -// CHECK-LABEL: @new_from_array -#[no_mangle] -pub fn new_from_array(x: u64) -> Arc<[u64]> { - // Ensure that we only generate one alloca for the array. - - // CHECK: alloca - // CHECK-SAME: [8000 x i8] - // CHECK-NOT: alloca - let array = [x; 1000]; - Arc::new(array) -} - -// CHECK-LABEL: @new_uninit -#[no_mangle] -pub fn new_uninit(x: u64) -> Arc<[u64; 1000]> { - // CHECK: call alloc::sync::arcinner_layout_for_value_layout - // CHECK-NOT: call alloc::sync::arcinner_layout_for_value_layout - let mut arc = Arc::new_uninit(); - unsafe { Arc::get_mut_unchecked(&mut arc) }.write([x; 1000]); - unsafe { arc.assume_init() } -} - -// CHECK-LABEL: @new_uninit_slice -#[no_mangle] -pub fn new_uninit_slice(x: u64) -> Arc<[u64]> { - // CHECK: call alloc::sync::arcinner_layout_for_value_layout - // CHECK-NOT: call alloc::sync::arcinner_layout_for_value_layout - let mut arc = Arc::new_uninit_slice(1000); - for elem in unsafe { Arc::get_mut_unchecked(&mut arc) } { - elem.write(x); - } - unsafe { arc.assume_init() } -} diff --git a/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs b/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs deleted file mode 100644 index 3909b203d08..00000000000 --- a/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -// CHECK-LABEL: @write_u8_variant_a -// CHECK-NEXT: {{.*}}: -// CHECK-NEXT: icmp ugt -// CHECK-NEXT: getelementptr -// CHECK-NEXT: select i1 {{.+}} null -// CHECK-NEXT: insertvalue -// CHECK-NEXT: insertvalue -// CHECK-NEXT: ret -#[no_mangle] -pub fn write_u8_variant_a(bytes: &mut [u8], buf: u8, offset: usize) -> Option<&mut [u8]> { - let buf = buf.to_le_bytes(); - bytes.get_mut(offset..).and_then(|bytes| bytes.get_mut(..buf.len())) -} diff --git a/tests/codegen/issues/issue-113757-bounds-check-after-cmp-max.rs b/tests/codegen/issues/issue-113757-bounds-check-after-cmp-max.rs deleted file mode 100644 index d495adf9980..00000000000 --- a/tests/codegen/issues/issue-113757-bounds-check-after-cmp-max.rs +++ /dev/null @@ -1,18 +0,0 @@ -// in Rust 1.73, -O and opt-level=3 optimizes differently -//@ compile-flags: -C opt-level=3 -#![crate_type = "lib"] - -use std::cmp::max; - -// CHECK-LABEL: @foo -// CHECK-NOT: slice_start_index_len_fail -// CHECK-NOT: unreachable -#[no_mangle] -pub fn foo(v: &mut Vec, size: usize) -> Option<&mut [u8]> { - if v.len() > max(1, size) { - let start = v.len() - size; - Some(&mut v[start..]) - } else { - None - } -} diff --git a/tests/codegen/issues/issue-114312.rs b/tests/codegen/issues/issue-114312.rs deleted file mode 100644 index 61355dd5873..00000000000 --- a/tests/codegen/issues/issue-114312.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-x86_64-unknown-linux-gnu - -// We want to check that this function does not mis-optimize to loop jumping. - -#![crate_type = "lib"] - -#[repr(C)] -pub enum Expr { - Sum, - // must have more than usize data - Sub(usize, u8), -} - -#[no_mangle] -pub extern "C" fn issue_114312(expr: Expr) { - // CHECK-LABEL: @issue_114312( - // CHECK-SAME: byval - // CHECK-NEXT: start: - // CHECK-NEXT: ret void - match expr { - Expr::Sum => {} - Expr::Sub(_, _) => issue_114312(Expr::Sum), - } -} diff --git a/tests/codegen/issues/issue-115385-llvm-jump-threading.rs b/tests/codegen/issues/issue-115385-llvm-jump-threading.rs deleted file mode 100644 index 8cabd94f202..00000000000 --- a/tests/codegen/issues/issue-115385-llvm-jump-threading.rs +++ /dev/null @@ -1,46 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Ccodegen-units=1 - -#![crate_type = "lib"] - -#[repr(i64)] -pub enum Boolean { - False = 0, - True = 1, -} - -impl Clone for Boolean { - fn clone(&self) -> Self { - *self - } -} - -impl Copy for Boolean {} - -extern "C" { - fn set_value(foo: *mut i64); - fn bar(); -} - -pub fn foo(x: bool) { - let mut foo = core::mem::MaybeUninit::::uninit(); - unsafe { - set_value(foo.as_mut_ptr()); - } - - if x { - let l1 = unsafe { *foo.as_mut_ptr().cast::() }; - if matches!(l1, Boolean::False) { - unsafe { - *foo.as_mut_ptr() = 0; - } - } - } - - let l2 = unsafe { *foo.as_mut_ptr() }; - if l2 == 2 { - // CHECK: call void @bar - unsafe { - bar(); - } - } -} diff --git a/tests/codegen/issues/issue-116878.rs b/tests/codegen/issues/issue-116878.rs deleted file mode 100644 index daf46c8bb55..00000000000 --- a/tests/codegen/issues/issue-116878.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -/// Make sure no bounds checks are emitted after a `get_unchecked`. -// CHECK-LABEL: @unchecked_slice_no_bounds_check -#[no_mangle] -pub unsafe fn unchecked_slice_no_bounds_check(s: &[u8]) -> u8 { - let a = *s.get_unchecked(1); - // CHECK-NOT: panic_bounds_check - a + s[0] -} diff --git a/tests/codegen/issues/issue-118306.rs b/tests/codegen/issues/issue-118306.rs deleted file mode 100644 index f12dc7cdfe2..00000000000 --- a/tests/codegen/issues/issue-118306.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-x86_64 - -// Test for #118306. -// Make sure we don't create `br` or `select` instructions. - -#![crate_type = "lib"] - -#[no_mangle] -pub fn branchy(input: u64) -> u64 { - // CHECK-LABEL: @branchy( - // CHECK-NEXT: start: - // CHECK-NEXT: [[_2:%.*]] = and i64 [[INPUT:%.*]], 3 - // CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds{{( nuw)?}} [4 x i64], ptr @switch.table.branchy, i64 0, i64 [[_2]] - // CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i64, ptr [[SWITCH_GEP]] - // CHECK-NEXT: ret i64 [[SWITCH_LOAD]] - match input % 4 { - 1 | 2 => 1, - 3 => 2, - _ => 0, - } -} diff --git a/tests/codegen/issues/issue-118392.rs b/tests/codegen/issues/issue-118392.rs deleted file mode 100644 index 07de8d9b237..00000000000 --- a/tests/codegen/issues/issue-118392.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -// CHECK-LABEL: @div2 -// CHECK: ashr i32 %a, 1 -// CHECK-NEXT: ret i32 -#[no_mangle] -pub fn div2(a: i32) -> i32 { - a.div_euclid(2) -} diff --git a/tests/codegen/issues/issue-119422.rs b/tests/codegen/issues/issue-119422.rs deleted file mode 100644 index 17ae71605b5..00000000000 --- a/tests/codegen/issues/issue-119422.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! This test checks that compiler don't generate useless compares to zeros -//! for `NonZero` integer types. -//! -//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled -//@ edition: 2021 -//@ only-64bit (because the LLVM type of i64 for usize shows up) -#![crate_type = "lib"] - -use core::num::NonZero; -use core::ptr::NonNull; - -// CHECK-LABEL: @check_non_null -#[no_mangle] -pub fn check_non_null(x: NonNull) -> bool { - // CHECK: ret i1 false - x.as_ptr().is_null() -} - -// CHECK-LABEL: @equals_zero_is_false_u8 -#[no_mangle] -pub fn equals_zero_is_false_u8(x: NonZero) -> bool { - // CHECK-NOT: br - // CHECK: ret i1 false - // CHECK-NOT: br - x.get() == 0 -} - -// CHECK-LABEL: @not_equals_zero_is_true_u8 -#[no_mangle] -pub fn not_equals_zero_is_true_u8(x: NonZero) -> bool { - // CHECK-NOT: br - // CHECK: ret i1 true - // CHECK-NOT: br - x.get() != 0 -} - -// CHECK-LABEL: @equals_zero_is_false_i8 -#[no_mangle] -pub fn equals_zero_is_false_i8(x: NonZero) -> bool { - // CHECK-NOT: br - // CHECK: ret i1 false - // CHECK-NOT: br - x.get() == 0 -} - -// CHECK-LABEL: @not_equals_zero_is_true_i8 -#[no_mangle] -pub fn not_equals_zero_is_true_i8(x: NonZero) -> bool { - // CHECK-NOT: br - // CHECK: ret i1 true - // CHECK-NOT: br - x.get() != 0 -} - -// CHECK-LABEL: @usize_try_from_u32 -#[no_mangle] -pub fn usize_try_from_u32(x: NonZero) -> NonZero { - // CHECK-NOT: br - // CHECK: zext i32 %{{.*}} to i64 - // CHECK-NOT: br - // CHECK: ret i64 - x.try_into().unwrap() -} - -// CHECK-LABEL: @isize_try_from_i32 -#[no_mangle] -pub fn isize_try_from_i32(x: NonZero) -> NonZero { - // CHECK-NOT: br - // CHECK: sext i32 %{{.*}} to i64 - // CHECK-NOT: br - // CHECK: ret i64 - x.try_into().unwrap() -} - -// CHECK-LABEL: @u64_from_nonzero_is_not_zero -#[no_mangle] -pub fn u64_from_nonzero_is_not_zero(x: NonZero) -> bool { - // CHECK-NOT: br - // CHECK: ret i1 false - // CHECK-NOT: br - let v: u64 = x.into(); - v == 0 -} diff --git a/tests/codegen/issues/issue-121719-common-field-offset.rs b/tests/codegen/issues/issue-121719-common-field-offset.rs deleted file mode 100644 index 9f5f44e0375..00000000000 --- a/tests/codegen/issues/issue-121719-common-field-offset.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! This test checks that match branches which all access a field -//! at the same offset are merged together. -//! -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -#[repr(C)] -pub struct A { - x: f64, - y: u64, -} -#[repr(C)] -pub struct B { - x: f64, - y: u32, -} -#[repr(C)] -pub struct C { - x: f64, - y: u16, -} -#[repr(C)] -pub struct D { - x: f64, - y: u8, -} - -pub enum E { - A(A), - B(B), - C(C), - D(D), -} - -// CHECK-LABEL: @match_on_e -#[no_mangle] -pub fn match_on_e(e: &E) -> &f64 { - // CHECK: start: - // CHECK-NEXT: getelementptr - // CHECK-NEXT: ret - match e { - E::A(A { x, .. }) | E::B(B { x, .. }) | E::C(C { x, .. }) | E::D(D { x, .. }) => x, - } -} diff --git a/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs b/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs deleted file mode 100644 index 853a1ff36b1..00000000000 --- a/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs +++ /dev/null @@ -1,43 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// The bug here was that it was loading and storing the whole value. -// It's ok for it to load the discriminant, -// to preserve the UB from `unreachable_unchecked`, -// but it better only store the constant discriminant of `B`. - -pub enum State { - A([u8; 753]), - B([u8; 753]), -} - -// CHECK-LABEL: @update -#[no_mangle] -pub unsafe fn update(s: *mut State) { - // CHECK-NOT: alloca - - // CHECK-NOT: load - // CHECK-NOT: store - // CHECK-NOT: memcpy - // CHECK-NOT: 75{{3|4}} - - // CHECK: %[[TAG:.+]] = load i8, ptr %s, align 1 - // CHECK-NEXT: trunc nuw i8 %[[TAG]] to i1 - - // CHECK-NOT: load - // CHECK-NOT: store - // CHECK-NOT: memcpy - // CHECK-NOT: 75{{3|4}} - - // CHECK: store i8 1, ptr %s, align 1 - - // CHECK-NOT: load - // CHECK-NOT: store - // CHECK-NOT: memcpy - // CHECK-NOT: 75{{3|4}} - - // CHECK: ret - let State::A(v) = s.read() else { std::hint::unreachable_unchecked() }; - s.write(State::B(v)); -} diff --git a/tests/codegen/issues/issue-123712-str-to-lower-autovectorization.rs b/tests/codegen/issues/issue-123712-str-to-lower-autovectorization.rs deleted file mode 100644 index 11ee10e8cc3..00000000000 --- a/tests/codegen/issues/issue-123712-str-to-lower-autovectorization.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ only-x86_64 -//@ compile-flags: -C opt-level=3 -#![crate_type = "lib"] -#![no_std] -#![feature(str_internals)] - -extern crate alloc; - -/// Ensure that the ascii-prefix loop for `str::to_lowercase` and `str::to_uppercase` uses vector -/// instructions. -/// -/// The llvm ir should be the same for all targets that support some form of simd. Only targets -/// without any simd instructions would see scalarized ir. -/// Unfortunately, there is no `only-simd` directive to only run this test on only such platforms, -/// and using test revisions would still require the core libraries for all platforms. -// CHECK-LABEL: @lower_while_ascii -// CHECK: [[A:%[0-9]]] = load <16 x i8> -// CHECK-NEXT: [[B:%[0-9]]] = icmp slt <16 x i8> [[A]], zeroinitializer -// CHECK-NEXT: [[C:%[0-9]]] = bitcast <16 x i1> [[B]] to i16 -#[no_mangle] -pub fn lower_while_ascii(s: &str) -> (alloc::string::String, &str) { - alloc::str::convert_while_ascii(s, u8::to_ascii_lowercase) -} diff --git a/tests/codegen/issues/issue-126585.rs b/tests/codegen/issues/issue-126585.rs deleted file mode 100644 index 466dab64cdc..00000000000 --- a/tests/codegen/issues/issue-126585.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ compile-flags: -Copt-level=s -//@ only-x86_64 - -// Test for #126585. -// Ensure that this IR doesn't have extra undef phi input, which also guarantees that this asm -// doesn't have subsequent labels and unnecessary `jmp` instructions. - -#![crate_type = "lib"] - -#[no_mangle] -fn checked_div_round(a: u64, b: u64) -> Option { - // CHECK-LABEL: @checked_div_round - // CHECK: phi - // CHECK-NOT: undef - // CHECK: phi - // CHECK-NOT: undef - match b { - 0 => None, - 1 => Some(a), - // `a / b` is computable and `(a % b) * 2` can not overflow since `b >= 2`. - b => Some(a / b + if (a % b) * 2 >= b { 1 } else { 0 }), - } -} diff --git a/tests/codegen/issues/issue-129795.rs b/tests/codegen/issues/issue-129795.rs deleted file mode 100644 index dc64ee35c97..00000000000 --- a/tests/codegen/issues/issue-129795.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ min-llvm-version: 20 -#![crate_type = "lib"] - -// Ensure that a modulo operation with an operand that is known to be -// a power-of-two is properly optimized. - -// CHECK-LABEL: @modulo_with_power_of_two_divisor -// CHECK: add i64 %divisor, -1 -// CHECK-NEXT: and i64 -// CHECK-NEXT: ret i64 -#[no_mangle] -pub fn modulo_with_power_of_two_divisor(dividend: u64, divisor: u64) -> u64 { - assert!(divisor.is_power_of_two()); - // should be optimized to (dividend & (divisor - 1)) - dividend % divisor -} diff --git a/tests/codegen/issues/issue-13018.rs b/tests/codegen/issues/issue-13018.rs deleted file mode 100644 index 8040018b931..00000000000 --- a/tests/codegen/issues/issue-13018.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -// A drop([...].clone()) sequence on an Rc should be a no-op -// In particular, no call to __rust_dealloc should be emitted -// -// We use a cdylib since it's a leaf unit for Rust purposes, so doesn't codegen -Zshare-generics -// code. -#![crate_type = "cdylib"] -use std::rc::Rc; - -pub fn foo(t: &Rc>) { - // CHECK-NOT: __rust_dealloc - drop(t.clone()); -} diff --git a/tests/codegen/issues/issue-136329-optnone-noinline.rs b/tests/codegen/issues/issue-136329-optnone-noinline.rs deleted file mode 100644 index 57c9e47a499..00000000000 --- a/tests/codegen/issues/issue-136329-optnone-noinline.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! Ensure that `#[optimize(none)]` functions are never inlined - -//@ compile-flags: -Copt-level=3 - -#![feature(optimize_attribute)] - -#[optimize(none)] -pub fn foo() { - let _x = 123; -} - -// CHECK-LABEL: define{{.*}}void @bar -// CHECK: start: -// CHECK: {{.*}}call {{.*}}void -// CHECK: ret void -#[no_mangle] -pub fn bar() { - foo(); -} - -fn main() {} diff --git a/tests/codegen/issues/issue-15953.rs b/tests/codegen/issues/issue-15953.rs deleted file mode 100644 index 70e597ac1dd..00000000000 --- a/tests/codegen/issues/issue-15953.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Test that llvm generates `memcpy` for moving a value -// inside a function and moving an argument. - -struct Foo { - x: Vec, -} - -#[inline(never)] -#[no_mangle] -// CHECK: memcpy -fn interior(x: Vec) -> Vec { - let Foo { x } = Foo { x }; - x -} - -#[inline(never)] -#[no_mangle] -// CHECK: memcpy -fn exterior(x: Vec) -> Vec { - x -} - -fn main() { - let x = interior(Vec::new()); - println!("{:?}", x); - - let x = exterior(Vec::new()); - println!("{:?}", x); -} diff --git a/tests/codegen/issues/issue-27130.rs b/tests/codegen/issues/issue-27130.rs deleted file mode 100644 index 594e02af097..00000000000 --- a/tests/codegen/issues/issue-27130.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @trim_in_place -#[no_mangle] -pub fn trim_in_place(a: &mut &[u8]) { - while a.first() == Some(&42) { - // CHECK-NOT: slice_index_order_fail - *a = &a[1..]; - } -} - -// CHECK-LABEL: @trim_in_place2 -#[no_mangle] -pub fn trim_in_place2(a: &mut &[u8]) { - while let Some(&42) = a.first() { - // CHECK-NOT: slice_index_order_fail - *a = &a[2..]; - } -} diff --git a/tests/codegen/issues/issue-32031.rs b/tests/codegen/issues/issue-32031.rs deleted file mode 100644 index 559e8d947fb..00000000000 --- a/tests/codegen/issues/issue-32031.rs +++ /dev/null @@ -1,29 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack. -//@ revisions: x86 other -//@[x86] only-rustc_abi-x86-sse2 -//@[other] ignore-x86 - -#![crate_type = "lib"] - -#[no_mangle] -pub struct F32(f32); - -// other: define{{.*}}float @add_newtype_f32(float %a, float %b) -// x86: define{{.*}}<4 x i8> @add_newtype_f32(float %a, float %b) -#[inline(never)] -#[no_mangle] -pub fn add_newtype_f32(a: F32, b: F32) -> F32 { - F32(a.0 + b.0) -} - -#[no_mangle] -pub struct F64(f64); - -// other: define{{.*}}double @add_newtype_f64(double %a, double %b) -// x86: define{{.*}}<8 x i8> @add_newtype_f64(double %a, double %b) -#[inline(never)] -#[no_mangle] -pub fn add_newtype_f64(a: F64, b: F64) -> F64 { - F64(a.0 + b.0) -} diff --git a/tests/codegen/issues/issue-32364.rs b/tests/codegen/issues/issue-32364.rs deleted file mode 100644 index 016981d1947..00000000000 --- a/tests/codegen/issues/issue-32364.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Test that `extern "stdcall"` is properly translated. - -//@ only-x86 - -//@ compile-flags: -C no-prepopulate-passes - -struct Foo; - -impl Foo { - // CHECK: define internal x86_stdcallcc void @{{.*}}foo{{.*}}() - #[inline(never)] - pub extern "stdcall" fn foo() {} -} - -fn main() { - Foo::foo::(); -} diff --git a/tests/codegen/issues/issue-34634.rs b/tests/codegen/issues/issue-34634.rs deleted file mode 100644 index d32fa97ec38..00000000000 --- a/tests/codegen/issues/issue-34634.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Test that `wrapping_div` only checks divisor once. -// This test checks that there is only a single compare against -1 and -1 is not present as a -// switch case (the second check present until rustc 1.12). -// This test also verifies that a single panic call is generated (for the division by zero case). - -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -// CHECK-LABEL: @f -#[no_mangle] -pub fn f(x: i32, y: i32) -> i32 { - // CHECK-COUNT-1: icmp eq i32 %y, -1 - // CHECK-COUNT-1: panic - // CHECK-NOT: i32 -1, label - x.wrapping_div(y) -} diff --git a/tests/codegen/issues/issue-34947-pow-i32.rs b/tests/codegen/issues/issue-34947-pow-i32.rs deleted file mode 100644 index b4750cd35bc..00000000000 --- a/tests/codegen/issues/issue-34947-pow-i32.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @issue_34947 -#[no_mangle] -pub fn issue_34947(x: i32) -> i32 { - // CHECK: mul - // CHECK-NEXT: mul - // CHECK-NEXT: mul - // CHECK-NEXT: ret - x.pow(5) -} diff --git a/tests/codegen/issues/issue-36010-some-box-is_some.rs b/tests/codegen/issues/issue-36010-some-box-is_some.rs deleted file mode 100644 index c9a8262162d..00000000000 --- a/tests/codegen/issues/issue-36010-some-box-is_some.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![crate_type = "lib"] - -//@ compile-flags: -Copt-level=3 - -use std::mem; - -fn foo(a: &mut T, b: T) -> bool { - let b = Some(mem::replace(a, b)); - let ret = b.is_some(); - mem::forget(b); - return ret; -} - -// CHECK-LABEL: @foo_u32 -// CHECK: store i32 -// CHECK-NEXT: ret i1 true -#[no_mangle] -pub fn foo_u32(a: &mut u32, b: u32) -> bool { - foo(a, b) -} - -// CHECK-LABEL: @foo_box -// CHECK: store ptr -// CHECK-NEXT: ret i1 true -#[no_mangle] -pub fn foo_box(a: &mut Box, b: Box) -> bool { - foo(a, b) -} diff --git a/tests/codegen/issues/issue-37945.rs b/tests/codegen/issues/issue-37945.rs deleted file mode 100644 index 23d0eab8ae4..00000000000 --- a/tests/codegen/issues/issue-37945.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled -//@ ignore-32bit LLVM has a bug with them - -// Check that LLVM understands that `Iter` pointer is not null. Issue #37945. - -#![crate_type = "lib"] - -use std::slice::Iter; - -#[no_mangle] -pub fn is_empty_1(xs: Iter) -> bool { - // CHECK-LABEL: @is_empty_1( - // CHECK-NEXT: start: - // CHECK-NEXT: [[A:%.*]] = icmp ne ptr {{%xs.0|%xs.1}}, null - // CHECK-NEXT: tail call void @llvm.assume(i1 [[A]]) - // The order between %xs.0 and %xs.1 on the next line doesn't matter - // and different LLVM versions produce different order. - // CHECK-NEXT: [[B:%.*]] = icmp eq ptr {{%xs.0, %xs.1|%xs.1, %xs.0}} - // CHECK-NEXT: ret i1 [[B:%.*]] - { xs }.next().is_none() -} - -#[no_mangle] -pub fn is_empty_2(xs: Iter) -> bool { - // CHECK-LABEL: @is_empty_2 - // CHECK-NEXT: start: - // CHECK-NEXT: [[C:%.*]] = icmp ne ptr {{%xs.0|%xs.1}}, null - // CHECK-NEXT: tail call void @llvm.assume(i1 [[C]]) - // The order between %xs.0 and %xs.1 on the next line doesn't matter - // and different LLVM versions produce different order. - // CHECK-NEXT: [[D:%.*]] = icmp eq ptr {{%xs.0, %xs.1|%xs.1, %xs.0}} - // CHECK-NEXT: ret i1 [[D:%.*]] - xs.map(|&x| x).next().is_none() -} diff --git a/tests/codegen/issues/issue-45222.rs b/tests/codegen/issues/issue-45222.rs deleted file mode 100644 index 0201363c41a..00000000000 --- a/tests/codegen/issues/issue-45222.rs +++ /dev/null @@ -1,62 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// verify that LLVM recognizes a loop involving 0..=n and will const-fold it. - -// Example from original issue #45222 - -fn foo2(n: u64) -> u64 { - let mut count = 0; - for _ in 0..n { - for j in (0..=n).rev() { - count += j; - } - } - count -} - -// CHECK-LABEL: @check_foo2 -#[no_mangle] -pub fn check_foo2() -> u64 { - // CHECK: ret i64 500005000000000 - foo2(100000) -} - -// Simplified example of #45222 -// -// Temporarily disabled in #68835 to fix a soundness hole. -// -// fn triangle_inc(n: u64) -> u64 { -// let mut count = 0; -// for j in 0 ..= n { -// count += j; -// } -// count -// } -// -// // COMMENTEDCHECK-LABEL: @check_triangle_inc -// #[no_mangle] -// pub fn check_triangle_inc() -> u64 { -// // COMMENTEDCHECK: ret i64 5000050000 -// triangle_inc(100000) -// } - -// Demo in #48012 - -fn foo3r(n: u64) -> u64 { - let mut count = 0; - (0..n).for_each(|_| { - (0..=n).rev().for_each(|j| { - count += j; - }) - }); - count -} - -// CHECK-LABEL: @check_foo3r -#[no_mangle] -pub fn check_foo3r() -> u64 { - // CHECK: ret i64 500050000000 - foo3r(10000) -} diff --git a/tests/codegen/issues/issue-45466.rs b/tests/codegen/issues/issue-45466.rs deleted file mode 100644 index 164a27ef5d4..00000000000 --- a/tests/codegen/issues/issue-45466.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "rlib"] - -// CHECK-LABEL: @memzero -// CHECK-NOT: store -// CHECK: call void @llvm.memset -// CHECK-NOT: store -#[no_mangle] -pub fn memzero(data: &mut [u8]) { - for i in 0..data.len() { - data[i] = 0; - } -} diff --git a/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs b/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs deleted file mode 100644 index a48bb2a1ccf..00000000000 --- a/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs +++ /dev/null @@ -1,38 +0,0 @@ -// This test case checks that slice::{r}position functions do not -// prevent optimizing away bounds checks - -//@ compile-flags: -Copt-level=3 - -#![crate_type = "rlib"] - -// CHECK-LABEL: @test -#[no_mangle] -pub fn test(y: &[u32], x: &u32, z: &u32) -> bool { - let result = match y.iter().position(|a| a == x) { - Some(p) => Ok(p), - None => Err(()), - }; - - if let Ok(p) = result { - // CHECK-NOT: panic - y[p] == *z - } else { - false - } -} - -// CHECK-LABEL: @rtest -#[no_mangle] -pub fn rtest(y: &[u32], x: &u32, z: &u32) -> bool { - let result = match y.iter().rposition(|a| a == x) { - Some(p) => Ok(p), - None => Err(()), - }; - - if let Ok(p) = result { - // CHECK-NOT: panic - y[p] == *z - } else { - false - } -} diff --git a/tests/codegen/issues/issue-47278.rs b/tests/codegen/issues/issue-47278.rs deleted file mode 100644 index 4f0a5bdf36f..00000000000 --- a/tests/codegen/issues/issue-47278.rs +++ /dev/null @@ -1,11 +0,0 @@ -// -C no-prepopulate-passes -#![crate_type = "staticlib"] - -#[repr(C)] -pub struct Foo(u64); - -// CHECK: define {{.*}} @foo( -#[no_mangle] -pub extern "C" fn foo(_: Foo) -> Foo { - loop {} -} diff --git a/tests/codegen/issues/issue-47442.rs b/tests/codegen/issues/issue-47442.rs deleted file mode 100644 index 445234e55ad..00000000000 --- a/tests/codegen/issues/issue-47442.rs +++ /dev/null @@ -1,22 +0,0 @@ -// check that we don't emit unneeded `resume` cleanup blocks for every -// destructor. - -// CHECK-NOT: Unwind - -#![feature(test)] -#![crate_type = "rlib"] - -extern crate test; - -struct Foo {} - -impl Drop for Foo { - fn drop(&mut self) { - test::black_box(()); - } -} - -#[no_mangle] -pub fn foo() { - let _foo = Foo {}; -} diff --git a/tests/codegen/issues/issue-56267-2.rs b/tests/codegen/issues/issue-56267-2.rs deleted file mode 100644 index 98e3732777e..00000000000 --- a/tests/codegen/issues/issue-56267-2.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "rlib"] - -#[allow(dead_code)] -pub struct Foo { - foo: u64, - bar: T, -} - -// The load from bar.1 should have alignment 4. Not checking -// other loads here, as the alignment will be platform-dependent. - -// CHECK: %{{.+}} = load i32, ptr %{{.+}}, align 4 -#[no_mangle] -pub fn test(x: Foo<(i32, i32)>) -> (i32, i32) { - x.bar -} diff --git a/tests/codegen/issues/issue-56267.rs b/tests/codegen/issues/issue-56267.rs deleted file mode 100644 index cabcc298482..00000000000 --- a/tests/codegen/issues/issue-56267.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "rlib"] - -#[allow(dead_code)] -pub struct Foo { - foo: u64, - bar: T, -} - -// The store writing to bar.1 should have alignment 4. Not checking -// other stores here, as the alignment will be platform-dependent. - -// CHECK: store i32 [[TMP1:%.+]], ptr [[TMP2:%.+]], align 4 -#[no_mangle] -pub fn test(x: (i32, i32)) -> Foo<(i32, i32)> { - Foo { foo: 0, bar: x } -} diff --git a/tests/codegen/issues/issue-56927.rs b/tests/codegen/issues/issue-56927.rs deleted file mode 100644 index 415ef073e03..00000000000 --- a/tests/codegen/issues/issue-56927.rs +++ /dev/null @@ -1,46 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -// 32bit MSVC does not align things properly so we suppress high alignment annotations (#112480) -//@ ignore-i686-pc-windows-msvc -//@ ignore-i686-pc-windows-gnu - -#![crate_type = "rlib"] - -#[repr(align(16))] -pub struct S { - arr: [u32; 4], -} - -// CHECK-LABEL: @test1 -// CHECK: store i32 0, ptr %{{.+}}, align 16 -// CHECK: store i32 1, ptr %{{.+}}, align 4 -// CHECK: store i32 2, ptr %{{.+}}, align 8 -// CHECK: store i32 3, ptr %{{.+}}, align 4 -#[no_mangle] -pub fn test1(s: &mut S) { - s.arr[0] = 0; - s.arr[1] = 1; - s.arr[2] = 2; - s.arr[3] = 3; -} - -// CHECK-LABEL: @test2 -// CHECK: store i32 4, ptr %{{.+}}, align 4 -#[allow(unconditional_panic)] -#[no_mangle] -pub fn test2(s: &mut S) { - s.arr[usize::MAX / 4 + 1] = 4; -} - -// CHECK-LABEL: @test3 -// CHECK: store i32 5, ptr %{{.+}}, align 4 -#[no_mangle] -pub fn test3(s: &mut S, i: usize) { - s.arr[i] = 5; -} - -// CHECK-LABEL: @test4 -// CHECK: store i32 6, ptr %{{.+}}, align 4 -#[no_mangle] -pub fn test4(s: &mut S) { - s.arr = [6; 4]; -} diff --git a/tests/codegen/issues/issue-58881.rs b/tests/codegen/issues/issue-58881.rs deleted file mode 100644 index ba6285f3972..00000000000 --- a/tests/codegen/issues/issue-58881.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -// -//@ only-x86_64 - -#![crate_type = "lib"] - -extern "C" { - fn variadic_fn(_: i32, ...); -} - -#[repr(C)] -struct Foo(u8); -#[repr(C)] -struct Bar(u64, u64, u64); - -// Ensure that emit arguments of the correct type. -pub unsafe fn test_call_variadic() { - // CHECK: call void (i32, ...) @variadic_fn(i32 0, i8 {{.*}}, ptr {{.*}}) - variadic_fn(0, Foo(0), Bar(0, 0, 0)) -} diff --git a/tests/codegen/issues/issue-59352.rs b/tests/codegen/issues/issue-59352.rs deleted file mode 100644 index cb4383d4a30..00000000000 --- a/tests/codegen/issues/issue-59352.rs +++ /dev/null @@ -1,18 +0,0 @@ -// This test is a mirror of mir-opt/issues/issue-59352.rs. The LLVM inliner doesn't inline -// `char::method::is_digit()` and `char::method::to_digit()`, probably because of their size. -// -// Currently, the MIR optimizer isn't capable of removing the unreachable panic in this test case. -// Once the optimizer can do that, mir-opt/issues/issue-59352.rs will need to be updated and this -// test case should be removed as it will become redundant. - -// mir-opt-level=3 enables inlining and enables LLVM to optimize away the unreachable panic call. -//@ compile-flags: -Copt-level=3 -Z mir-opt-level=3 - -#![crate_type = "rlib"] - -// CHECK-LABEL: @num_to_digit -#[no_mangle] -pub fn num_to_digit(num: char) -> u32 { - // CHECK-NOT: panic - if num.is_digit(8) { num.to_digit(8).unwrap() } else { 0 } -} diff --git a/tests/codegen/issues/issue-64219-fn-ptr-call-returning-never-is-noreturn.rs b/tests/codegen/issues/issue-64219-fn-ptr-call-returning-never-is-noreturn.rs deleted file mode 100644 index 86d020e1751..00000000000 --- a/tests/codegen/issues/issue-64219-fn-ptr-call-returning-never-is-noreturn.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Test for https://github.com/rust-lang/rust/issues/64219 -//! Check if `noreturn` attribute is applied on calls to -//! function pointers returning `!` (never type). - -#![crate_type = "lib"] - -extern "C" { - static FOO: fn() -> !; -} - -// CHECK-LABEL: @foo -#[no_mangle] -pub unsafe fn foo() { - // CHECK: call - // CHECK-SAME: [[NUM:#[0-9]+$]] - FOO(); -} - -// CHECK: attributes [[NUM]] = {{{.*}} noreturn {{.*}}} diff --git a/tests/codegen/issues/issue-68667-unwrap-combinators.rs b/tests/codegen/issues/issue-68667-unwrap-combinators.rs deleted file mode 100644 index 7f4a32109fe..00000000000 --- a/tests/codegen/issues/issue-68667-unwrap-combinators.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![crate_type = "lib"] - -//@ compile-flags: -Copt-level=3 - -// MIR inlining now optimizes this code. - -// CHECK-LABEL: @unwrap_combinators -// CHECK: {{icmp|trunc}} -// CHECK-NEXT: icmp -// CHECK-NEXT: select i1 -// CHECK-NEXT: ret i1 -#[no_mangle] -pub fn unwrap_combinators(a: Option, b: i32) -> bool { - a.map(|t| t >= b).unwrap_or(false) -} diff --git a/tests/codegen/issues/issue-69101-bounds-check.rs b/tests/codegen/issues/issue-69101-bounds-check.rs deleted file mode 100644 index 953b79aa263..00000000000 --- a/tests/codegen/issues/issue-69101-bounds-check.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -// Make sure no bounds checks are emitted in the loop when upfront slicing -// ensures that the slices are big enough. -// In particular, bounds checks were not always optimized out if the upfront -// check was for a greater len than the loop requires. -// (i.e. `already_sliced_no_bounds_check` was not always optimized even when -// `already_sliced_no_bounds_check_exact` was) -// CHECK-LABEL: @already_sliced_no_bounds_check -#[no_mangle] -pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) { - // CHECK: slice_end_index_len_fail - // CHECK-NOT: panic_bounds_check - let _ = (&a[..2048], &b[..2048], &mut c[..2048]); - for i in 0..1024 { - c[i] = a[i] ^ b[i]; - } -} - -// CHECK-LABEL: @already_sliced_no_bounds_check_exact -#[no_mangle] -pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) { - // CHECK: slice_end_index_len_fail - // CHECK-NOT: panic_bounds_check - let _ = (&a[..1024], &b[..1024], &mut c[..1024]); - for i in 0..1024 { - c[i] = a[i] ^ b[i]; - } -} - -// Make sure we're checking for the right thing: there can be a panic if the slice is too small. -// CHECK-LABEL: @already_sliced_bounds_check -#[no_mangle] -pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) { - // CHECK: slice_end_index_len_fail - // CHECK: panic_bounds_check - let _ = (&a[..1023], &b[..2048], &mut c[..2048]); - for i in 0..1024 { - c[i] = a[i] ^ b[i]; - } -} diff --git a/tests/codegen/issues/issue-73031.rs b/tests/codegen/issues/issue-73031.rs deleted file mode 100644 index 80dea9b5bc2..00000000000 --- a/tests/codegen/issues/issue-73031.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -// Test that LLVM can eliminate the unreachable `All::None` branch. - -pub enum All { - None, - Foo, - Bar, -} - -// CHECK-LABEL: @issue_73031 -#[no_mangle] -pub fn issue_73031(a: &mut All, q: i32) -> i32 { - *a = if q == 5 { All::Foo } else { All::Bar }; - match *a { - // CHECK-NOT: panic - All::None => panic!(), - All::Foo => 1, - All::Bar => 2, - } -} diff --git a/tests/codegen/issues/issue-73258.rs b/tests/codegen/issues/issue-73258.rs deleted file mode 100644 index 936a7554496..00000000000 --- a/tests/codegen/issues/issue-73258.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// Adapted from - -#[derive(Clone, Copy)] -#[repr(u8)] -pub enum Foo { - A, - B, - C, - D, -} - -// CHECK-LABEL: @issue_73258( -#[no_mangle] -pub unsafe fn issue_73258(ptr: *const Foo) -> Foo { - // CHECK-NOT: icmp - // CHECK-NOT: call - // CHECK-NOT: br - // CHECK-NOT: select - - // CHECK: %[[R:.+]] = load i8 - // CHECK-SAME: !range ! - - // CHECK-NOT: icmp - // CHECK-NOT: call - // CHECK-NOT: br - // CHECK-NOT: select - - // CHECK: ret i8 %[[R]] - - // CHECK-NOT: icmp - // CHECK-NOT: call - // CHECK-NOT: br - // CHECK-NOT: select - let k: Option = Some(ptr.read()); - return k.unwrap(); -} diff --git a/tests/codegen/issues/issue-73338-effecient-cmp.rs b/tests/codegen/issues/issue-73338-effecient-cmp.rs deleted file mode 100644 index 71641a5457b..00000000000 --- a/tests/codegen/issues/issue-73338-effecient-cmp.rs +++ /dev/null @@ -1,39 +0,0 @@ -// This test checks that comparison operation -// generated by #[derive(PartialOrd)] -// doesn't contain jumps for C enums - -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -#[repr(u32)] -#[derive(Copy, Clone, Eq, PartialEq, PartialOrd)] -pub enum Foo { - Zero, - One, - Two, -} - -#[no_mangle] -pub fn compare_less(a: Foo, b: Foo) -> bool { - // CHECK-NOT: br {{.*}} - a < b -} - -#[no_mangle] -pub fn compare_le(a: Foo, b: Foo) -> bool { - // CHECK-NOT: br {{.*}} - a <= b -} - -#[no_mangle] -pub fn compare_ge(a: Foo, b: Foo) -> bool { - // CHECK-NOT: br {{.*}} - a >= b -} - -#[no_mangle] -pub fn compare_greater(a: Foo, b: Foo) -> bool { - // CHECK-NOT: br {{.*}} - a > b -} diff --git a/tests/codegen/issues/issue-73396-bounds-check-after-position.rs b/tests/codegen/issues/issue-73396-bounds-check-after-position.rs deleted file mode 100644 index 1e2c25babe0..00000000000 --- a/tests/codegen/issues/issue-73396-bounds-check-after-position.rs +++ /dev/null @@ -1,70 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -// Make sure no bounds checks are emitted when slicing or indexing -// with an index from `position()` or `rposition()`. - -// CHECK-LABEL: @position_slice_to_no_bounds_check -#[no_mangle] -pub fn position_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { - // CHECK-NOT: panic - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: slice_end_index_len_fail - // CHECK-NOT: panic_bounds_check - // CHECK-NOT: unreachable - if let Some(idx) = s.iter().position(|b| *b == b'\\') { &s[..idx] } else { s } -} - -// CHECK-LABEL: @position_slice_from_no_bounds_check -#[no_mangle] -pub fn position_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { - // CHECK-NOT: panic - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: slice_end_index_len_fail - // CHECK-NOT: panic_bounds_check - // CHECK-NOT: unreachable - if let Some(idx) = s.iter().position(|b| *b == b'\\') { &s[idx..] } else { s } -} - -// CHECK-LABEL: @position_index_no_bounds_check -#[no_mangle] -pub fn position_index_no_bounds_check(s: &[u8]) -> u8 { - // CHECK-NOT: panic - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: slice_end_index_len_fail - // CHECK-NOT: panic_bounds_check - // CHECK-NOT: unreachable - if let Some(idx) = s.iter().position(|b| *b == b'\\') { s[idx] } else { 42 } -} -// CHECK-LABEL: @rposition_slice_to_no_bounds_check -#[no_mangle] -pub fn rposition_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { - // CHECK-NOT: panic - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: slice_end_index_len_fail - // CHECK-NOT: panic_bounds_check - // CHECK-NOT: unreachable - if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { &s[..idx] } else { s } -} - -// CHECK-LABEL: @rposition_slice_from_no_bounds_check -#[no_mangle] -pub fn rposition_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { - // CHECK-NOT: panic - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: slice_end_index_len_fail - // CHECK-NOT: panic_bounds_check - // CHECK-NOT: unreachable - if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { &s[idx..] } else { s } -} - -// CHECK-LABEL: @rposition_index_no_bounds_check -#[no_mangle] -pub fn rposition_index_no_bounds_check(s: &[u8]) -> u8 { - // CHECK-NOT: panic - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: slice_end_index_len_fail - // CHECK-NOT: panic_bounds_check - // CHECK-NOT: unreachable - if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { s[idx] } else { 42 } -} diff --git a/tests/codegen/issues/issue-73827-bounds-check-index-in-subexpr.rs b/tests/codegen/issues/issue-73827-bounds-check-index-in-subexpr.rs deleted file mode 100644 index e9dd0d1bf23..00000000000 --- a/tests/codegen/issues/issue-73827-bounds-check-index-in-subexpr.rs +++ /dev/null @@ -1,17 +0,0 @@ -// This test checks that bounds checks are elided when -// index is part of a (x | y) < C style condition - -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @get -#[no_mangle] -pub fn get(array: &[u8; 8], x: usize, y: usize) -> u8 { - if x > 7 || y > 7 { - 0 - } else { - // CHECK-NOT: panic_bounds_check - array[y] - } -} diff --git a/tests/codegen/issues/issue-74938-array-split-at.rs b/tests/codegen/issues/issue-74938-array-split-at.rs deleted file mode 100644 index 9d3e23d642b..00000000000 --- a/tests/codegen/issues/issue-74938-array-split-at.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -const N: usize = 3; -pub type T = u8; - -// CHECK-LABEL: @split_multiple -// CHECK-NOT: unreachable -#[no_mangle] -pub fn split_multiple(slice: &[T]) -> (&[T], &[T]) { - let len = slice.len() / N; - slice.split_at(len * N) -} diff --git a/tests/codegen/issues/issue-75525-bounds-checks.rs b/tests/codegen/issues/issue-75525-bounds-checks.rs deleted file mode 100644 index 5dfbd350010..00000000000 --- a/tests/codegen/issues/issue-75525-bounds-checks.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Regression test for #75525, verifies that no bounds checks are generated. - -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @f0 -// CHECK-NOT: panic -#[no_mangle] -pub fn f0(idx: usize, buf: &[u8; 10]) -> u8 { - if idx < 8 { buf[idx + 1] } else { 0 } -} - -// CHECK-LABEL: @f1 -// CHECK-NOT: panic -#[no_mangle] -pub fn f1(idx: usize, buf: &[u8; 10]) -> u8 { - if idx > 5 && idx < 8 { buf[idx - 1] } else { 0 } -} - -// CHECK-LABEL: @f2 -// CHECK-NOT: panic -#[no_mangle] -pub fn f2(idx: usize, buf: &[u8; 10]) -> u8 { - if idx > 5 && idx < 8 { buf[idx] } else { 0 } -} diff --git a/tests/codegen/issues/issue-75546.rs b/tests/codegen/issues/issue-75546.rs deleted file mode 100644 index 1e1e6543a88..00000000000 --- a/tests/codegen/issues/issue-75546.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -// Test that LLVM can eliminate the impossible `i == 0` check. - -// CHECK-LABEL: @issue_75546 -#[no_mangle] -pub fn issue_75546() { - let mut i = 1u32; - while i < u32::MAX { - // CHECK-NOT: panic - if i == 0 { - panic!(); - } - i += 1; - } -} diff --git a/tests/codegen/issues/issue-75659.rs b/tests/codegen/issues/issue-75659.rs deleted file mode 100644 index 0960bfdb6b0..00000000000 --- a/tests/codegen/issues/issue-75659.rs +++ /dev/null @@ -1,63 +0,0 @@ -// This test checks that the call to memchr/slice_contains is optimized away -// when searching in small slices. - -//@ compile-flags: -Copt-level=3 -Zinline-mir=false -//@ only-x86_64 - -#![crate_type = "lib"] - -// CHECK-LABEL: @foo1 -#[no_mangle] -pub fn foo1(x: u8, data: &[u8; 1]) -> bool { - // CHECK-NOT: memchr - // CHECK-NOT: slice_contains - data.contains(&x) -} - -// CHECK-LABEL: @foo2 -#[no_mangle] -pub fn foo2(x: u8, data: &[u8; 2]) -> bool { - // CHECK-NOT: memchr - // CHECK-NOT: slice_contains - data.contains(&x) -} - -// CHECK-LABEL: @foo3 -#[no_mangle] -pub fn foo3(x: u8, data: &[u8; 3]) -> bool { - // CHECK-NOT: memchr - // CHECK-NOT: slice_contains - data.contains(&x) -} - -// CHECK-LABEL: @foo4 -#[no_mangle] -pub fn foo4(x: u8, data: &[u8; 4]) -> bool { - // CHECK-NOT: memchr - // CHECK-NOT: slice_contains - data.contains(&x) -} - -// CHECK-LABEL: @foo8 -#[no_mangle] -pub fn foo8(x: u8, data: &[u8; 8]) -> bool { - // CHECK-NOT: memchr - // CHECK-NOT: slice_contains - data.contains(&x) -} - -// CHECK-LABEL: @foo8_i8 -#[no_mangle] -pub fn foo8_i8(x: i8, data: &[i8; 8]) -> bool { - // CHECK-NOT: memchr - // CHECK-NOT: slice_contains - !data.contains(&x) -} - -// Check that the general case isn't inlined -// CHECK-LABEL: @foo80 -#[no_mangle] -pub fn foo80(x: u8, data: &[u8; 80]) -> bool { - // CHECK: call core::slice::memchr - data.contains(&x) -} diff --git a/tests/codegen/issues/issue-75978.rs b/tests/codegen/issues/issue-75978.rs deleted file mode 100644 index f4b0bc36329..00000000000 --- a/tests/codegen/issues/issue-75978.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -#[no_mangle] -pub fn test() -> u32 { - // CHECK-LABEL: @test( - // CHECK: ret i32 13 - let s = [1, 2, 3, 4, 5, 6, 7]; - - let mut iter = s.iter(); - let mut sum = 0; - while let Some(_) = iter.next() { - sum += iter.next().map_or(1, |&x| x) - } - - sum -} diff --git a/tests/codegen/issues/issue-77812.rs b/tests/codegen/issues/issue-77812.rs deleted file mode 100644 index 09e2376c30d..00000000000 --- a/tests/codegen/issues/issue-77812.rs +++ /dev/null @@ -1,32 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -// Test that LLVM can eliminate the unreachable `Variant::Zero` branch. - -#[derive(Copy, Clone, Eq, PartialEq)] -pub enum Variant { - Zero, - One, - Two, -} - -extern "C" { - fn exf1(); - fn exf2(); -} - -pub static mut GLOBAL: Variant = Variant::Zero; - -// CHECK-LABEL: @issue_77812 -#[no_mangle] -pub unsafe fn issue_77812() { - let g = GLOBAL; - if g != Variant::Zero { - match g { - Variant::One => exf1(), - Variant::Two => exf2(), - // CHECK-NOT: panic - Variant::Zero => panic!(), - } - } -} diff --git a/tests/codegen/issues/issue-84268.rs b/tests/codegen/issues/issue-84268.rs deleted file mode 100644 index 1dc55a909ad..00000000000 --- a/tests/codegen/issues/issue-84268.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ compile-flags: -Copt-level=3 --crate-type=rlib -#![feature(core_intrinsics, repr_simd)] - -use std::intrinsics::simd::{simd_eq, simd_fabs}; - -#[repr(simd)] -pub struct V([f32; 4]); - -#[repr(simd)] -pub struct M([i32; 4]); - -#[no_mangle] -// CHECK-LABEL: @is_infinite -pub fn is_infinite(v: V) -> M { - // CHECK: fabs - // CHECK: cmp oeq - unsafe { simd_eq(simd_fabs(v), V([f32::INFINITY; 4])) } -} diff --git a/tests/codegen/issues/issue-85872-multiple-reverse.rs b/tests/codegen/issues/issue-85872-multiple-reverse.rs deleted file mode 100644 index 6f566ddee6b..00000000000 --- a/tests/codegen/issues/issue-85872-multiple-reverse.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -#[no_mangle] -pub fn u16_be_to_arch(mut data: [u8; 2]) -> [u8; 2] { - // CHECK-LABEL: @u16_be_to_arch - // CHECK: @llvm.bswap.i16 - data.reverse(); - data -} - -#[no_mangle] -pub fn u32_be_to_arch(mut data: [u8; 4]) -> [u8; 4] { - // CHECK-LABEL: @u32_be_to_arch - // CHECK: @llvm.bswap.i32 - data.reverse(); - data -} diff --git a/tests/codegen/issues/issue-86106.rs b/tests/codegen/issues/issue-86106.rs deleted file mode 100644 index 8d1ce116d26..00000000000 --- a/tests/codegen/issues/issue-86106.rs +++ /dev/null @@ -1,63 +0,0 @@ -//@ only-64bit llvm appears to use stores instead of memset on 32bit -//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled -//@ needs-deterministic-layouts - -// The below two functions ensure that both `String::new()` and `"".to_string()` -// produce the identical code. - -#![crate_type = "lib"] - -// CHECK-LABEL: define {{(dso_local )?}}void @string_new -#[no_mangle] -pub fn string_new() -> String { - // CHECK-NOT: load i8 - // CHECK: store i{{32|64}} - // CHECK-NEXT: getelementptr - // CHECK-NEXT: store ptr - // CHECK-NEXT: getelementptr - // CHECK-NEXT: store i{{32|64}} - // CHECK-NEXT: ret void - String::new() -} - -// CHECK-LABEL: define {{(dso_local )?}}void @empty_to_string -#[no_mangle] -pub fn empty_to_string() -> String { - // CHECK-NOT: load i8 - // CHECK: store i{{32|64}} - // CHECK-NEXT: getelementptr - // CHECK-NEXT: store ptr - // CHECK-NEXT: getelementptr - // CHECK-NEXT: store i{{32|64}} - // CHECK-NEXT: ret void - "".to_string() -} - -// The below two functions ensure that both `vec![]` and `vec![].clone()` -// produce the identical code. - -// CHECK-LABEL: @empty_vec -#[no_mangle] -pub fn empty_vec() -> Vec { - // CHECK: store i{{32|64}} - // CHECK-NOT: load i8 - // CHECK-NEXT: getelementptr - // CHECK-NEXT: store ptr - // CHECK-NEXT: getelementptr - // CHECK-NEXT: store i{{32|64}} - // CHECK-NEXT: ret void - vec![] -} - -// CHECK-LABEL: @empty_vec_clone -#[no_mangle] -pub fn empty_vec_clone() -> Vec { - // CHECK: store i{{32|64}} - // CHECK-NOT: load i8 - // CHECK-NEXT: getelementptr - // CHECK-NEXT: store ptr - // CHECK-NEXT: getelementptr - // CHECK-NEXT: store i{{32|64}} - // CHECK-NEXT: ret void - vec![].clone() -} diff --git a/tests/codegen/issues/issue-86109-eliminate-div-by-zero-check.rs b/tests/codegen/issues/issue-86109-eliminate-div-by-zero-check.rs deleted file mode 100644 index 345c09738b6..00000000000 --- a/tests/codegen/issues/issue-86109-eliminate-div-by-zero-check.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//! Test for https://github.com/rust-lang/rust/issues/86109 -//! Check LLVM can eliminate the impossible division by zero check by -//! ensuring there is no call (to panic) instruction. -//! -//! This has been fixed since `rustc 1.70.0`. - -#![crate_type = "lib"] - -type T = i16; - -// CHECK-LABEL: @foo -#[no_mangle] -pub fn foo(start: T) -> T { - // CHECK-NOT: panic - if start <= 0 { - return 0; - } - let mut count = 0; - for i in start..10_000 { - if 752 % i != 0 { - count += 1; - } - } - count -} diff --git a/tests/codegen/issues/issue-93036-assert-index.rs b/tests/codegen/issues/issue-93036-assert-index.rs deleted file mode 100644 index 46f45c2f06e..00000000000 --- a/tests/codegen/issues/issue-93036-assert-index.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -#[no_mangle] -// CHECK-LABEL: @foo -// CHECK-NOT: unreachable -pub fn foo(arr: &mut [u32]) { - for i in 0..arr.len() { - for j in 0..i { - assert!(j < arr.len()); - } - } -} diff --git a/tests/codegen/issues/issue-96274.rs b/tests/codegen/issues/issue-96274.rs deleted file mode 100644 index 2425ec53e4e..00000000000 --- a/tests/codegen/issues/issue-96274.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -use std::mem::MaybeUninit; - -pub fn maybe_uninit() -> [MaybeUninit; 3000] { - // CHECK-NOT: memset - [MaybeUninit::uninit(); 3000] -} - -pub fn maybe_uninit_const() -> [MaybeUninit; 8192] { - // CHECK-NOT: memset - [const { MaybeUninit::uninit() }; 8192] -} diff --git a/tests/codegen/issues/issue-96497-slice-size-nowrap.rs b/tests/codegen/issues/issue-96497-slice-size-nowrap.rs deleted file mode 100644 index 7b3a20a295e..00000000000 --- a/tests/codegen/issues/issue-96497-slice-size-nowrap.rs +++ /dev/null @@ -1,38 +0,0 @@ -// This test case checks that LLVM is aware that computing the size of a slice cannot wrap. -// The possibility of wrapping results in an additional branch when dropping boxed slices -// in some situations, see https://github.com/rust-lang/rust/issues/96497#issuecomment-1112865218 - -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @simple_size_of_nowrap -#[no_mangle] -pub fn simple_size_of_nowrap(x: &[u32]) -> usize { - // Make sure the shift used to compute the size has a nowrap flag. - - // CHECK: [[A:%.*]] = shl nuw nsw {{.*}}, 2 - // CHECK-NEXT: ret {{.*}} [[A]] - core::mem::size_of_val(x) -} - -// CHECK-LABEL: @drop_write -#[no_mangle] -pub fn drop_write(mut x: Box<[u32]>) { - // Check that this write is optimized out. - // This depends on the size calculation not wrapping, - // since otherwise LLVM can't tell that the memory is always deallocated if the slice len > 0. - - // CHECK-NOT: store i32 42 - x[1] = 42; -} - -// CHECK-LABEL: @slice_size_plus_2 -#[no_mangle] -pub fn slice_size_plus_2(x: &[u16]) -> usize { - // Before #136575 this didn't get the `nuw` in the add. - - // CHECK: [[BYTES:%.+]] = shl nuw nsw {{i16|i32|i64}} %x.1, 1 - // CHECK: = add nuw {{i16|i32|i64}} [[BYTES]], 2 - core::mem::size_of_val(x) + 2 -} diff --git a/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs b/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs deleted file mode 100644 index 76adcf9fd45..00000000000 --- a/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// There should be no calls to panic / len_mismatch_fail. - -#[no_mangle] -pub fn test(a: &mut [u8], offset: usize, bytes: &[u8]) { - // CHECK-LABEL: @test( - // CHECK-NOT: call - // CHECK: call void @llvm.memcpy - // CHECK-NOT: call - // CHECK: } - if let Some(dst) = a.get_mut(offset..offset + bytes.len()) { - dst.copy_from_slice(bytes); - } -} diff --git a/tests/codegen/issues/issue-98678-async.rs b/tests/codegen/issues/issue-98678-async.rs deleted file mode 100644 index 3dd06bb5194..00000000000 --- a/tests/codegen/issues/issue-98678-async.rs +++ /dev/null @@ -1,27 +0,0 @@ -// ignore-tidy-linelength -//! This test verifies the accuracy of emitted file and line debuginfo metadata for async blocks and -//! async functions. - -//@ revisions: MSVC NONMSVC -//@[MSVC] only-msvc -//@[NONMSVC] ignore-msvc -//@ edition:2021 -//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true - -// NONMSVC-DAG: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-async.rs{{".*}}) -// MSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-async.rs{{".*}}) - -// NONMSVC-DAG: !DISubprogram(name: "foo",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], -// MSVC-DAG: !DISubprogram(name: "foo",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], -pub async fn foo() -> u8 { - 5 -} - -pub fn bar() -> impl std::future::Future { - // NONMSVC: !DICompositeType({{.*"}}{async_block_env#0}{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], - // MSVC-DAG: !DICompositeType({{.*"}}enum2${{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], - async { - let x: u8 = foo().await; - x + 5 - } -} diff --git a/tests/codegen/issues/issue-98678-closure-coroutine.rs b/tests/codegen/issues/issue-98678-closure-coroutine.rs deleted file mode 100644 index 8763bcb799d..00000000000 --- a/tests/codegen/issues/issue-98678-closure-coroutine.rs +++ /dev/null @@ -1,25 +0,0 @@ -// ignore-tidy-linelength -//! This test verifies the accuracy of emitted file and line debuginfo metadata for closures and -//! coroutines. - -#![feature(coroutines, stmt_expr_attributes)] - -//@ revisions: MSVC NONMSVC -//@[MSVC] only-msvc -//@[NONMSVC] ignore-msvc -//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true - -// NONMSVC-DAG: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-closure-coroutine.rs{{".*}}) -// MSVC-DAG: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-closure-coroutine.rs{{".*}}) - -pub fn foo() { - // NONMSVC-DAG: !DICompositeType({{.*"}}{closure_env#0}{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], - // MSVC-DAG: !DICompositeType({{.*"}}closure_env$0{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], - let closure = |x| x; - closure(0); - - // NONMSVC-DAG: !DICompositeType({{.*"[{]}}coroutine_env#1{{[}]".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 3]], - // MSVC-DAG: !DICompositeType({{.*".*foo::}}coroutine_env$1>{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], - let _coroutine = #[coroutine] - || yield 1; -} diff --git a/tests/codegen/issues/issue-98678-enum.rs b/tests/codegen/issues/issue-98678-enum.rs deleted file mode 100644 index 87bf8797293..00000000000 --- a/tests/codegen/issues/issue-98678-enum.rs +++ /dev/null @@ -1,42 +0,0 @@ -// ignore-tidy-linelength -//! This test verifies the accuracy of emitted file and line debuginfo metadata enums. - -//@ revisions: MSVC NONMSVC -//@[MSVC] only-msvc -//@[NONMSVC] ignore-msvc -//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true - -// NONMSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-enum.rs{{".*}}) -// MSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-enum.rs{{".*}}) - -// NONMSVC: !DICompositeType({{.*"}}SingleCase{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], -// MSVC: !DICompositeType({{.*"}}enum2${{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], -pub enum SingleCase { - // NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "One",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], - // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "One",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], - One, -} - -// NONMSVC: !DICompositeType({{.*"}}MultipleDataCases{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], -// MSVC: !DICompositeType({{.*"}}enum2${{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], -pub enum MultipleDataCases { - // NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Case1",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], - // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Case1",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], - Case1(u32), - // NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Case2",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], - // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Case2",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], - Case2(i64), -} - -// NONMSVC: !DICompositeType({{.*"}}NicheLayout{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], -// MSVC: !DICompositeType({{.*"}}enum2${{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], -pub enum NicheLayout { - // NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Something",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], - // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Something",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], - Something(&'static u32), - // NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Nothing",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]], - // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Nothing",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], - Nothing, -} - -pub fn foo(_: SingleCase, _: MultipleDataCases, _: NicheLayout) {} diff --git a/tests/codegen/issues/issue-98678-struct-union.rs b/tests/codegen/issues/issue-98678-struct-union.rs deleted file mode 100644 index a83a585a433..00000000000 --- a/tests/codegen/issues/issue-98678-struct-union.rs +++ /dev/null @@ -1,27 +0,0 @@ -// ignore-tidy-linelength -//! This test verifies the accuracy of emitted file and line debuginfo metadata for structs and -//! unions. - -//@ revisions: MSVC NONMSVC -//@[MSVC] only-msvc -//@[NONMSVC] ignore-msvc -//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true - -// NONMSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-struct-union.rs{{".*}}) -// MSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-struct-union.rs{{".*}}) - -// CHECK: !DICompositeType({{.*"}}MyType{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], -pub struct MyType { - // CHECK: !DIDerivedType({{.*"}}i{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], - i: i32, -} - -// CHECK: !DICompositeType({{.*"}}MyUnion{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], -pub union MyUnion { - // CHECK: !DIDerivedType({{.*"}}i{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], - i: i32, - // CHECK: !DIDerivedType({{.*"}}f{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]], - f: f32, -} - -pub fn foo(_: MyType, _: MyUnion) {} diff --git a/tests/codegen/issues/issue-99960.rs b/tests/codegen/issues/issue-99960.rs deleted file mode 100644 index 571a9be967d..00000000000 --- a/tests/codegen/issues/issue-99960.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -#[no_mangle] -pub fn test(dividend: i64, divisor: i64) -> Option { - // CHECK-LABEL: @test( - // CHECK-NOT: panic - if dividend > i64::min_value() && divisor != 0 { Some(dividend / divisor) } else { None } -} diff --git a/tests/codegen/issues/looping-over-ne-bytes-133528.rs b/tests/codegen/issues/looping-over-ne-bytes-133528.rs deleted file mode 100644 index 35acf765d69..00000000000 --- a/tests/codegen/issues/looping-over-ne-bytes-133528.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ min-llvm-version: 20 -#![crate_type = "lib"] - -/// Ensure the function is properly optimized -/// In the issue #133528, the function was not getting optimized -/// whereas, a version with `bytes` wrapped into a `black_box` was optimized -/// It was probably a LLVM bug that was fixed in LLVM 20 - -// CHECK-LABEL: @looping_over_ne_bytes -// CHECK: icmp eq i64 %input, -1 -// CHECK-NEXT: ret i1 -#[no_mangle] -fn looping_over_ne_bytes(input: u64) -> bool { - let bytes = input.to_ne_bytes(); - bytes.iter().all(|x| *x == !0) -} diff --git a/tests/codegen/issues/str-to-string-128690.rs b/tests/codegen/issues/str-to-string-128690.rs deleted file mode 100644 index d9e69764be2..00000000000 --- a/tests/codegen/issues/str-to-string-128690.rs +++ /dev/null @@ -1,38 +0,0 @@ -//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled -#![crate_type = "lib"] - -//! Make sure str::to_string is specialized not to use fmt machinery. -//! -//! Note that the `CHECK-NOT`s here try to match on calls to functions under `core::fmt`. - -// CHECK-LABEL: define {{(dso_local )?}}void @one_ref -#[no_mangle] -pub fn one_ref(input: &str) -> String { - // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}} - input.to_string() -} - -// CHECK-LABEL: define {{(dso_local )?}}void @two_ref -#[no_mangle] -pub fn two_ref(input: &&str) -> String { - // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}} - input.to_string() -} - -// CHECK-LABEL: define {{(dso_local )?}}void @thirteen_ref -#[no_mangle] -pub fn thirteen_ref(input: &&&&&&&&&&&&&str) -> String { - // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}} - input.to_string() -} - -// This is a known performance cliff because of the macro-generated -// specialized impl. If this test suddenly starts failing, -// consider removing the `to_string_str!` macro in `alloc/str/string.rs`. -// -// CHECK-LABEL: define {{(dso_local )?}}void @fourteen_ref -#[no_mangle] -pub fn fourteen_ref(input: &&&&&&&&&&&&&&str) -> String { - // CHECK: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}} - input.to_string() -} diff --git a/tests/codegen/iter-repeat-n-trivial-drop.rs b/tests/codegen/iter-repeat-n-trivial-drop.rs deleted file mode 100644 index 28173530324..00000000000 --- a/tests/codegen/iter-repeat-n-trivial-drop.rs +++ /dev/null @@ -1,70 +0,0 @@ -//@ compile-flags: -C opt-level=3 -//@ only-x86_64 -//@ needs-deterministic-layouts - -#![crate_type = "lib"] -#![feature(iter_repeat_n)] -#![feature(array_repeat)] - -#[derive(Clone)] -pub struct NotCopy(u16); - -impl Drop for NotCopy { - fn drop(&mut self) {} -} - -// For a type where `Drop::drop` doesn't do anything observable and a clone is the -// same as a move, make sure that the extra case for the last item disappears. - -#[no_mangle] -// CHECK-LABEL: @iter_repeat_n_next -pub fn iter_repeat_n_next(it: &mut std::iter::RepeatN) -> Option { - // CHECK-NEXT: start: - // CHECK-NOT: br - // CHECK: %[[COUNT:.+]] = load i64 - // CHECK-NEXT: %[[COUNT_ZERO:.+]] = icmp eq i64 %[[COUNT]], 0 - // CHECK-NEXT: br i1 %[[COUNT_ZERO]], label %[[EMPTY:.+]], label %[[NOT_EMPTY:.+]] - - // CHECK: [[NOT_EMPTY]]: - // CHECK-NOT: br - // CHECK: %[[DEC:.+]] = add i64 %[[COUNT]], -1 - // CHECK-NEXT: %[[VAL:.+]] = load i16 - // CHECK-NEXT: store i64 %[[DEC]] - // CHECK-NEXT: br label %[[EMPTY]] - - // CHECK: [[EMPTY]]: - // CHECK-NOT: br - // CHECK: phi i16 - // CHECK-SAME: [ %[[VAL]], %[[NOT_EMPTY]] ] - // CHECK-NOT: br - // CHECK: ret - - it.next() -} - -// And as a result, using the iterator can optimize without special cases for -// the last iteration, like `memset`ing all the items in one call. - -#[no_mangle] -// CHECK-LABEL: @vec_extend_via_iter_repeat_n -pub fn vec_extend_via_iter_repeat_n() -> Vec { - // CHECK: %[[ADDR:.+]] = tail call {{(noalias )?}}noundef dereferenceable_or_null(1234) ptr @{{.*}}__rust_alloc(i64 noundef {{(range\(i64 1, 0\) )?}}1234, i64 noundef {{(range\(i64 1, -9223372036854775807\) )?}}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; - let mut v = Vec::with_capacity(n); - v.extend(std::iter::repeat_n(42_u8, n)); - v -} - -// Array repeat uses `RepeatN::next_unchecked` internally, -// so also check that the distinction disappears there. - -#[no_mangle] -// CHECK-LABEL: @array_repeat_not_copy -pub unsafe fn array_repeat_not_copy(item: NotCopy) -> [NotCopy; 8] { - // CHECK: insertelement {{.+}} i16 %item - // CHECK: shufflevector <8 x i16> {{.+}} zeroinitializer - // CHECK: store <8 x i16> - std::array::repeat(item) -} diff --git a/tests/codegen/layout-size-checks.rs b/tests/codegen/layout-size-checks.rs deleted file mode 100644 index d64a7055e0b..00000000000 --- a/tests/codegen/layout-size-checks.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-x86_64 - -#![crate_type = "lib"] - -use std::alloc::Layout; - -type RGB48 = [u16; 3]; - -// CHECK-LABEL: @layout_array_rgb48 -#[no_mangle] -pub fn layout_array_rgb48(n: usize) -> Layout { - // CHECK-NOT: llvm.umul.with.overflow.i64 - // CHECK: icmp ugt i64 %n, 1537228672809129301 - // CHECK-NOT: llvm.umul.with.overflow.i64 - // CHECK: mul nuw nsw i64 %n, 6 - // CHECK-NOT: llvm.umul.with.overflow.i64 - Layout::array::(n).unwrap() -} - -// CHECK-LABEL: @layout_array_i32 -#[no_mangle] -pub fn layout_array_i32(n: usize) -> Layout { - // CHECK-NOT: llvm.umul.with.overflow.i64 - // CHECK: icmp ugt i64 %n, 2305843009213693951 - // CHECK-NOT: llvm.umul.with.overflow.i64 - // CHECK: shl nuw nsw i64 %n, 2 - // CHECK-NOT: llvm.umul.with.overflow.i64 - Layout::array::(n).unwrap() -} diff --git a/tests/codegen/lib-optimizations/iter-sum.rs b/tests/codegen/lib-optimizations/iter-sum.rs deleted file mode 100644 index a054ffffe74..00000000000 --- a/tests/codegen/lib-optimizations/iter-sum.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-x86_64 (vectorization varies between architectures) -#![crate_type = "lib"] - -// Ensure that slice + take + sum gets vectorized. -// Currently this relies on the slice::Iter::try_fold implementation -// CHECK-LABEL: @slice_take_sum -#[no_mangle] -pub fn slice_take_sum(s: &[u64], l: usize) -> u64 { - // CHECK: vector.body: - // CHECK: ret - s.iter().take(l).sum() -} diff --git a/tests/codegen/lib-optimizations/slice_rotate.rs b/tests/codegen/lib-optimizations/slice_rotate.rs deleted file mode 100644 index aa4bb3b528c..00000000000 --- a/tests/codegen/lib-optimizations/slice_rotate.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// Ensure that the simple case of rotating by a constant 1 optimizes to the obvious thing - -// CHECK-LABEL: @rotate_left_by_one -#[no_mangle] -pub fn rotate_left_by_one(slice: &mut [i32]) { - // CHECK-NOT: phi - // CHECK-NOT: call - // CHECK-NOT: load - // CHECK-NOT: store - // CHECK-NOT: getelementptr - // CHECK: %[[END:.+]] = getelementptr - // CHECK-NEXT: %[[DIM:.+]] = getelementptr - // CHECK-NEXT: %[[LAST:.+]] = load - // CHECK-NEXT: %[[FIRST:.+]] = shl - // CHECK-NEXT: call void @llvm.memmove - // CHECK-NEXT: store i32 %[[LAST]], ptr %[[DIM:.+]] - // CHECK-NOT: phi - // CHECK-NOT: call - // CHECK-NOT: load - // CHECK-NOT: store - // CHECK-NOT: getelementptr - // CHECK: ret void - if !slice.is_empty() { - slice.rotate_left(1); - } -} diff --git a/tests/codegen/lifetime_start_end.rs b/tests/codegen/lifetime_start_end.rs deleted file mode 100644 index 0639e7640aa..00000000000 --- a/tests/codegen/lifetime_start_end.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Zmir-opt-level=0 - -#![crate_type = "lib"] - -// CHECK-LABEL: @test -#[no_mangle] -pub fn test() { - let a = 0u8; - &a; // keep variable in an alloca - - // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, ptr %a) - - { - let b = &Some(a); - &b; // keep variable in an alloca - - // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, {{.*}}) - - // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, {{.*}}) - - // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, {{.*}}) - - // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, {{.*}}) - } - - let c = 1u8; - &c; // keep variable in an alloca - - // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, ptr %c) - - // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, ptr %c) - - // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, ptr %a) -} diff --git a/tests/codegen/link-dead-code.rs b/tests/codegen/link-dead-code.rs deleted file mode 100644 index 93e1d84d9c7..00000000000 --- a/tests/codegen/link-dead-code.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ compile-flags:-Clink-dead-code - -#![crate_type = "rlib"] - -// This test makes sure that, when -Clink-dead-code is specified, we generate -// code for functions that would otherwise be skipped. - -// CHECK-LABEL: ; link_dead_code::const_fn -// CHECK-NEXT: ; Function Attrs: -// CHECK-NEXT: define hidden -const fn const_fn() -> i32 { - 1 -} - -// CHECK-LABEL: ; link_dead_code::inline_fn -// CHECK-NEXT: ; Function Attrs: -// CHECK-NEXT: define hidden -#[inline] -fn inline_fn() -> i32 { - 2 -} - -// CHECK-LABEL: ; link_dead_code::private_fn -// CHECK-NEXT: ; Function Attrs: -// CHECK-NEXT: define hidden -fn private_fn() -> i32 { - 3 -} diff --git a/tests/codegen/link_section.rs b/tests/codegen/link_section.rs deleted file mode 100644 index f62f6948079..00000000000 --- a/tests/codegen/link_section.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@ ignore-wasm32 custom sections work differently on wasm -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] - -// CHECK: @VAR1 = {{(dso_local )?}}constant [4 x i8] c"\01\00\00\00", section ".test_one" -#[no_mangle] -#[link_section = ".test_one"] -#[cfg(target_endian = "little")] -pub static VAR1: u32 = 1; - -#[no_mangle] -#[link_section = ".test_one"] -#[cfg(target_endian = "big")] -pub static VAR1: u32 = 0x01000000; - -pub enum E { - A(u32), - B(f32), -} - -// CHECK: @VAR2 = {{(dso_local )?}}constant {{.*}}, section ".test_two" -#[no_mangle] -#[link_section = ".test_two"] -pub static VAR2: E = E::A(666); - -// CHECK: @VAR3 = {{(dso_local )?}}constant {{.*}}, section ".test_three" -#[no_mangle] -#[link_section = ".test_three"] -pub static VAR3: E = E::B(1.); - -// CHECK: define {{(dso_local )?}}void @fn1() {{.*}} section ".test_four" { -#[no_mangle] -#[link_section = ".test_four"] -pub fn fn1() {} diff --git a/tests/codegen/llvm-ident.rs b/tests/codegen/llvm-ident.rs deleted file mode 100644 index 923e99bb282..00000000000 --- a/tests/codegen/llvm-ident.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Verifies that the `!llvm.ident` named metadata is emitted. -// -//@ revisions: NONE OPT DEBUG -// -//@ [OPT] compile-flags: -Copt-level=2 -//@ [DEBUG] compile-flags: -Cdebuginfo=2 - -// The named metadata should contain a single metadata node (see -// `LLVMRustPrepareThinLTOImport` for details). -// CHECK: !llvm.ident = !{![[ID:[0-9]+]]} - -// In addition, check that the metadata node has the expected content. -// CHECK: ![[ID]] = !{!"rustc version 1.{{.*}}"} - -fn main() {} diff --git a/tests/codegen/llvm_module_flags.rs b/tests/codegen/llvm_module_flags.rs deleted file mode 100644 index d3fae0c3927..00000000000 --- a/tests/codegen/llvm_module_flags.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Test for -Z llvm_module_flags -//@ compile-flags: -Z llvm_module_flag=foo:u32:123:error -Z llvm_module_flag=bar:u32:42:max - -fn main() {} - -// CHECK: !{i32 1, !"foo", i32 123} -// CHECK: !{i32 7, !"bar", i32 42} diff --git a/tests/codegen/loads.rs b/tests/codegen/loads.rs deleted file mode 100644 index 88d67642b72..00000000000 --- a/tests/codegen/loads.rs +++ /dev/null @@ -1,152 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 -Copt-level=3 - -#![crate_type = "lib"] - -use std::mem::MaybeUninit; -use std::num::NonZero; - -pub struct Bytes { - a: u8, - b: u8, - c: u8, - d: u8, -} - -#[derive(Copy, Clone)] -pub enum MyBool { - True, - False, -} - -#[repr(align(16))] -pub struct Align16(u128); - -// CHECK: @ptr_alignment_helper({{.*}}align [[PTR_ALIGNMENT:[0-9]+]] -#[no_mangle] -pub fn ptr_alignment_helper(x: &&()) {} - -// CHECK-LABEL: @load_ref -#[no_mangle] -pub fn load_ref<'a>(x: &&'a i32) -> &'a i32 { - // CHECK: load ptr, ptr %x, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META:[0-9]+]], !noundef !{{[0-9]+}} - *x -} - -// CHECK-LABEL: @load_ref_higher_alignment -#[no_mangle] -pub fn load_ref_higher_alignment<'a>(x: &&'a Align16) -> &'a Align16 { - // CHECK: load ptr, ptr %x, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_16_META:[0-9]+]], !noundef !{{[0-9]+}} - *x -} - -// CHECK-LABEL: @load_scalar_pair -#[no_mangle] -pub fn load_scalar_pair<'a>(x: &(&'a i32, &'a Align16)) -> (&'a i32, &'a Align16) { - // CHECK: load ptr, ptr %{{.+}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META]], !noundef !{{[0-9]+}} - // CHECK: load ptr, ptr %{{.+}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_16_META]], !noundef !{{[0-9]+}} - *x -} - -// CHECK-LABEL: @load_raw_pointer -#[no_mangle] -pub fn load_raw_pointer<'a>(x: &*const i32) -> *const i32 { - // loaded raw pointer should not have !nonnull or !align metadata - // CHECK: load ptr, ptr %x, align [[PTR_ALIGNMENT]], !noundef ![[NOUNDEF:[0-9]+]]{{$}} - *x -} - -// CHECK-LABEL: @load_box -#[no_mangle] -pub fn load_box<'a>(x: Box>) -> Box { - // CHECK: load ptr, ptr %{{.*}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META]], !noundef !{{[0-9]+}} - *x -} - -// CHECK-LABEL: @load_bool -#[no_mangle] -pub fn load_bool(x: &bool) -> bool { - // CHECK: load i8, ptr %x, align 1, !range ![[BOOL_RANGE:[0-9]+]], !noundef !{{[0-9]+}} - *x -} - -// CHECK-LABEL: @load_maybeuninit_bool -#[no_mangle] -pub fn load_maybeuninit_bool(x: &MaybeUninit) -> MaybeUninit { - // CHECK: load i8, ptr %x, align 1{{$}} - *x -} - -// CHECK-LABEL: @load_enum_bool -#[no_mangle] -pub fn load_enum_bool(x: &MyBool) -> MyBool { - // CHECK: load i8, ptr %x, align 1, !range ![[BOOL_RANGE]], !noundef !{{[0-9]+}} - *x -} - -// CHECK-LABEL: @load_maybeuninit_enum_bool -#[no_mangle] -pub fn load_maybeuninit_enum_bool(x: &MaybeUninit) -> MaybeUninit { - // CHECK: load i8, ptr %x, align 1{{$}} - *x -} - -// CHECK-LABEL: @load_int -#[no_mangle] -pub fn load_int(x: &u16) -> u16 { - // CHECK: load i16, ptr %x, align 2, !noundef ![[NOUNDEF]]{{$}} - *x -} - -// CHECK-LABEL: @load_nonzero_int -#[no_mangle] -pub fn load_nonzero_int(x: &NonZero) -> NonZero { - // CHECK: load i16, ptr %x, align 2, !range ![[NONZEROU16_RANGE:[0-9]+]], !noundef !{{[0-9]+}} - *x -} - -// CHECK-LABEL: @load_option_nonzero_int -#[no_mangle] -pub fn load_option_nonzero_int(x: &Option>) -> Option> { - // CHECK: load i16, ptr %x, align 2, !noundef ![[NOUNDEF]]{{$}} - *x -} - -// CHECK-LABEL: @borrow -#[no_mangle] -pub fn borrow(x: &i32) -> &i32 { - // CHECK: load ptr, ptr %x{{.*}}, !nonnull - &x; // keep variable in an alloca - x -} - -// CHECK-LABEL: @_box -#[no_mangle] -pub fn _box(x: Box) -> i32 { - // CHECK: load ptr, ptr %x{{.*}}, align [[PTR_ALIGNMENT]] - *x -} - -// CHECK-LABEL: small_array_alignment -// The array is loaded as i32, but its alignment is lower, go with 1 byte to avoid target -// dependent alignment -#[no_mangle] -pub fn small_array_alignment(x: [i8; 4]) -> [i8; 4] { - // CHECK: [[VAR:%[0-9]+]] = load i32, ptr %{{.*}}, align 1 - // CHECK: ret i32 [[VAR]] - x -} - -// CHECK-LABEL: small_struct_alignment -// The struct is loaded as i32, but its alignment is lower, go with 1 byte to avoid target -// dependent alignment -#[no_mangle] -pub fn small_struct_alignment(x: Bytes) -> Bytes { - // CHECK: [[VAR:%[0-9]+]] = load i32, ptr %{{.*}}, align 1 - // CHECK: ret i32 [[VAR]] - x -} - -// CHECK-DAG: ![[BOOL_RANGE]] = !{i8 0, i8 2} -// CHECK-DAG: ![[NONZEROU16_RANGE]] = !{i16 1, i16 0} -// CHECK-DAG: ![[ALIGN_4_META]] = !{i64 4} -// CHECK-DAG: ![[ALIGN_16_META]] = !{i64 16} diff --git a/tests/codegen/local-generics-in-exe-internalized.rs b/tests/codegen/local-generics-in-exe-internalized.rs deleted file mode 100644 index 8dbc41382b5..00000000000 --- a/tests/codegen/local-generics-in-exe-internalized.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Zshare-generics=yes -Zinline-mir=no - -// Check that local generics are internalized if they are in the same CGU - -// CHECK-LABEL: ; local_generics_in_exe_internalized::foo -// CHECK-NEXT: ; Function Attrs: -// CHECK-NEXT: define internal -pub fn foo(x: T, y: T) -> (T, T) { - (x, y) -} - -fn main() { - let _ = foo(0u8, 1u8); -} diff --git a/tests/codegen/loongarch-abi/call-llvm-intrinsics.rs b/tests/codegen/loongarch-abi/call-llvm-intrinsics.rs deleted file mode 100644 index 9a50f7b8e3a..00000000000 --- a/tests/codegen/loongarch-abi/call-llvm-intrinsics.rs +++ /dev/null @@ -1,31 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -//@ only-loongarch64 - -#![feature(link_llvm_intrinsics)] -#![crate_type = "lib"] - -struct A; - -impl Drop for A { - fn drop(&mut self) { - println!("A"); - } -} - -extern "C" { - #[link_name = "llvm.sqrt.f32"] - fn sqrt(x: f32) -> f32; -} - -pub fn do_call() { - let _a = A; - - unsafe { - // Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them - // CHECK: store float 4.000000e+00, ptr %{{.}}, align 4 - // CHECK: load float, ptr %{{.}}, align 4 - // CHECK: call float @llvm.sqrt.f32(float %{{.}} - sqrt(4.0); - } -} diff --git a/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs b/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs deleted file mode 100644 index 93c8d60930b..00000000000 --- a/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs +++ /dev/null @@ -1,299 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes --target loongarch64-unknown-linux-gnu -//@ needs-llvm-components: loongarch - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK: define void @f_fpr_tracking(double %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, i8 noundef zeroext %i) -#[no_mangle] -pub extern "C" fn f_fpr_tracking( - a: f64, - b: f64, - c: f64, - d: f64, - e: f64, - f: f64, - g: f64, - h: f64, - i: u8, -) { -} - -#[repr(C)] -pub struct Double { - f: f64, -} - -#[repr(C)] -pub struct DoubleDouble { - f: f64, - g: f64, -} - -#[repr(C)] -pub struct DoubleFloat { - f: f64, - g: f32, -} - -// CHECK: define void @f_double_s_arg(double %0) -#[no_mangle] -pub extern "C" fn f_double_s_arg(a: Double) {} - -// CHECK: define double @f_ret_double_s() -#[no_mangle] -pub extern "C" fn f_ret_double_s() -> Double { - Double { f: 1. } -} - -// CHECK: define void @f_double_double_s_arg({ double, double } %0) -#[no_mangle] -pub extern "C" fn f_double_double_s_arg(a: DoubleDouble) {} - -// CHECK: define { double, double } @f_ret_double_double_s() -#[no_mangle] -pub extern "C" fn f_ret_double_double_s() -> DoubleDouble { - DoubleDouble { f: 1., g: 2. } -} - -// CHECK: define void @f_double_float_s_arg({ double, float } %0) -#[no_mangle] -pub extern "C" fn f_double_float_s_arg(a: DoubleFloat) {} - -// CHECK: define { double, float } @f_ret_double_float_s() -#[no_mangle] -pub extern "C" fn f_ret_double_float_s() -> DoubleFloat { - DoubleFloat { f: 1., g: 2. } -} - -// CHECK: define void @f_double_double_s_arg_insufficient_fprs(double %0, double %1, double %2, double %3, double %4, double %5, double %6, [2 x i64] %7) -#[no_mangle] -pub extern "C" fn f_double_double_s_arg_insufficient_fprs( - a: f64, - b: f64, - c: f64, - d: f64, - e: f64, - f: f64, - g: f64, - h: DoubleDouble, -) { -} - -#[repr(C)] -pub struct DoubleInt8 { - f: f64, - i: i8, -} - -#[repr(C)] -pub struct DoubleUInt8 { - f: f64, - i: u8, -} - -#[repr(C)] -pub struct DoubleInt32 { - f: f64, - i: i32, -} - -#[repr(C)] -pub struct DoubleInt64 { - f: f64, - i: i64, -} - -// CHECK: define void @f_double_int8_s_arg({ double, i8 } %0) -#[no_mangle] -pub extern "C" fn f_double_int8_s_arg(a: DoubleInt8) {} - -// CHECK: define { double, i8 } @f_ret_double_int8_s() -#[no_mangle] -pub extern "C" fn f_ret_double_int8_s() -> DoubleInt8 { - DoubleInt8 { f: 1., i: 2 } -} - -// CHECK: define void @f_double_int32_s_arg({ double, i32 } %0) -#[no_mangle] -pub extern "C" fn f_double_int32_s_arg(a: DoubleInt32) {} - -// CHECK: define { double, i32 } @f_ret_double_int32_s() -#[no_mangle] -pub extern "C" fn f_ret_double_int32_s() -> DoubleInt32 { - DoubleInt32 { f: 1., i: 2 } -} - -// CHECK: define void @f_double_uint8_s_arg({ double, i8 } %0) -#[no_mangle] -pub extern "C" fn f_double_uint8_s_arg(a: DoubleUInt8) {} - -// CHECK: define { double, i8 } @f_ret_double_uint8_s() -#[no_mangle] -pub extern "C" fn f_ret_double_uint8_s() -> DoubleUInt8 { - DoubleUInt8 { f: 1., i: 2 } -} - -// CHECK: define void @f_double_int64_s_arg({ double, i64 } %0) -#[no_mangle] -pub extern "C" fn f_double_int64_s_arg(a: DoubleInt64) {} - -// CHECK: define { double, i64 } @f_ret_double_int64_s() -#[no_mangle] -pub extern "C" fn f_ret_double_int64_s() -> DoubleInt64 { - DoubleInt64 { f: 1., i: 2 } -} - -// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 noundef signext %a, i32 noundef signext %b, i32 noundef signext %c, i32 noundef signext %d, i32 noundef signext %e, i32 noundef signext %f, i32 noundef signext %g, i32 noundef signext %h, [2 x i64] %0) -#[no_mangle] -pub extern "C" fn f_double_int8_s_arg_insufficient_gprs( - a: i32, - b: i32, - c: i32, - d: i32, - e: i32, - f: i32, - g: i32, - h: i32, - i: DoubleInt8, -) { -} - -// CHECK: define void @f_struct_double_int8_insufficient_fprs(float %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, [2 x i64] %8) -#[no_mangle] -pub extern "C" fn f_struct_double_int8_insufficient_fprs( - a: f32, - b: f64, - c: f64, - d: f64, - e: f64, - f: f64, - g: f64, - h: f64, - i: DoubleInt8, -) { -} - -#[repr(C)] -pub struct DoubleArr1 { - a: [f64; 1], -} - -// CHECK: define void @f_doublearr1_s_arg(double %0) -#[no_mangle] -pub extern "C" fn f_doublearr1_s_arg(a: DoubleArr1) {} - -// CHECK: define double @f_ret_doublearr1_s() -#[no_mangle] -pub extern "C" fn f_ret_doublearr1_s() -> DoubleArr1 { - DoubleArr1 { a: [1.] } -} - -#[repr(C)] -pub struct DoubleArr2 { - a: [f64; 2], -} - -// CHECK: define void @f_doublearr2_s_arg({ double, double } %0) -#[no_mangle] -pub extern "C" fn f_doublearr2_s_arg(a: DoubleArr2) {} - -// CHECK: define { double, double } @f_ret_doublearr2_s() -#[no_mangle] -pub extern "C" fn f_ret_doublearr2_s() -> DoubleArr2 { - DoubleArr2 { a: [1., 2.] } -} - -#[repr(C)] -pub struct Tricky1 { - f: [f64; 1], -} - -#[repr(C)] -pub struct DoubleArr2Tricky1 { - g: [Tricky1; 2], -} - -// CHECK: define void @f_doublearr2_tricky1_s_arg({ double, double } %0) -#[no_mangle] -pub extern "C" fn f_doublearr2_tricky1_s_arg(a: DoubleArr2Tricky1) {} - -// CHECK: define { double, double } @f_ret_doublearr2_tricky1_s() -#[no_mangle] -pub extern "C" fn f_ret_doublearr2_tricky1_s() -> DoubleArr2Tricky1 { - DoubleArr2Tricky1 { g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } -} - -#[repr(C)] -pub struct EmptyStruct {} - -#[repr(C)] -pub struct DoubleArr2Tricky2 { - s: EmptyStruct, - g: [Tricky1; 2], -} - -// CHECK: define void @f_doublearr2_tricky2_s_arg({ double, double } %0) -#[no_mangle] -pub extern "C" fn f_doublearr2_tricky2_s_arg(a: DoubleArr2Tricky2) {} - -// CHECK: define { double, double } @f_ret_doublearr2_tricky2_s() -#[no_mangle] -pub extern "C" fn f_ret_doublearr2_tricky2_s() -> DoubleArr2Tricky2 { - DoubleArr2Tricky2 { s: EmptyStruct {}, g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } -} - -#[repr(C)] -pub struct IntDoubleInt { - a: i32, - b: f64, - c: i32, -} - -// CHECK: define void @f_int_double_int_s_arg(ptr noalias{{( nocapture)?}} noundef align 8{{( captures\(none\))?}} dereferenceable(24) %a) -#[no_mangle] -pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {} - -// CHECK: define void @f_ret_int_double_int_s(ptr{{( dead_on_unwind)?}} noalias{{( nocapture)?}} noundef{{( writable)?}} sret([24 x i8]) align 8{{( captures\(none\))?}} dereferenceable(24) %_0) -#[no_mangle] -pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt { - IntDoubleInt { a: 1, b: 2., c: 3 } -} - -#[repr(C)] -pub struct CharCharDouble { - a: u8, - b: u8, - c: f64, -} - -// CHECK: define void @f_char_char_double_s_arg([2 x i64] %0) -#[no_mangle] -pub extern "C" fn f_char_char_double_s_arg(a: CharCharDouble) {} - -// CHECK: define [2 x i64] @f_ret_char_char_double_s() -#[no_mangle] -pub extern "C" fn f_ret_char_char_double_s() -> CharCharDouble { - CharCharDouble { a: 1, b: 2, c: 3. } -} - -#[repr(C)] -pub union DoubleU { - a: f64, -} - -// CHECK: define void @f_double_u_arg(i64 %0) -#[no_mangle] -pub extern "C" fn f_double_u_arg(a: DoubleU) {} - -// CHECK: define i64 @f_ret_double_u() -#[no_mangle] -pub extern "C" fn f_ret_double_u() -> DoubleU { - unsafe { DoubleU { a: 1. } } -} diff --git a/tests/codegen/lto-removes-invokes.rs b/tests/codegen/lto-removes-invokes.rs deleted file mode 100644 index 3640bd1ab86..00000000000 --- a/tests/codegen/lto-removes-invokes.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ compile-flags: -C lto -C panic=abort -Copt-level=3 -//@ no-prefer-dynamic - -fn main() { - foo(); -} - -#[no_mangle] -#[inline(never)] -fn foo() { - let _a = Box::new(3); - bar(); - // CHECK-LABEL: define dso_local void @foo - // CHECK: call void @bar -} - -#[inline(never)] -#[no_mangle] -fn bar() { - println!("hello!"); -} diff --git a/tests/codegen/macos/i686-macosx-deployment-target.rs b/tests/codegen/macos/i686-macosx-deployment-target.rs deleted file mode 100644 index cfa91e61cb0..00000000000 --- a/tests/codegen/macos/i686-macosx-deployment-target.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Checks that we correctly modify the target when MACOSX_DEPLOYMENT_TARGET is set. -// See issue #60235. - -//@ add-core-stubs -//@ compile-flags: -Copt-level=3 --target=i686-apple-darwin --crate-type=rlib -//@ needs-llvm-components: x86 -//@ rustc-env:MACOSX_DEPLOYMENT_TARGET=10.14 -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[repr(C)] -pub struct Bool { - b: bool, -} - -// CHECK: target triple = "i686-apple-macosx10.14.0" -#[no_mangle] -pub extern "C" fn structbool() -> Bool { - Bool { b: true } -} diff --git a/tests/codegen/macos/i686-no-macosx-deployment-target.rs b/tests/codegen/macos/i686-no-macosx-deployment-target.rs deleted file mode 100644 index 25ec5f6acbb..00000000000 --- a/tests/codegen/macos/i686-no-macosx-deployment-target.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Checks that we leave the target alone MACOSX_DEPLOYMENT_TARGET is unset. -// See issue #60235. - -//@ add-core-stubs -//@ compile-flags: -Copt-level=3 --target=i686-apple-darwin --crate-type=rlib -//@ needs-llvm-components: x86 -//@ unset-rustc-env:MACOSX_DEPLOYMENT_TARGET -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[repr(C)] -pub struct Bool { - b: bool, -} - -// CHECK: target triple = "i686-apple-macosx10.12.0" -#[no_mangle] -pub extern "C" fn structbool() -> Bool { - Bool { b: true } -} diff --git a/tests/codegen/macos/x86_64-macosx-deployment-target.rs b/tests/codegen/macos/x86_64-macosx-deployment-target.rs deleted file mode 100644 index 8ea95ba0575..00000000000 --- a/tests/codegen/macos/x86_64-macosx-deployment-target.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Checks that we correctly modify the target when MACOSX_DEPLOYMENT_TARGET is set. -// See issue #60235. - -//@ add-core-stubs -//@ compile-flags: -Copt-level=3 --target=x86_64-apple-darwin --crate-type=rlib -//@ needs-llvm-components: x86 -//@ rustc-env:MACOSX_DEPLOYMENT_TARGET=10.14 -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[repr(C)] -pub struct Bool { - b: bool, -} - -// CHECK: target triple = "x86_64-apple-macosx10.14.0" -#[no_mangle] -pub extern "C" fn structbool() -> Bool { - Bool { b: true } -} diff --git a/tests/codegen/macos/x86_64-no-macosx-deployment-target.rs b/tests/codegen/macos/x86_64-no-macosx-deployment-target.rs deleted file mode 100644 index 474094957ae..00000000000 --- a/tests/codegen/macos/x86_64-no-macosx-deployment-target.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Checks that we leave the target alone when MACOSX_DEPLOYMENT_TARGET is unset. -// See issue #60235. - -//@ add-core-stubs -//@ compile-flags: -Copt-level=3 --target=x86_64-apple-darwin --crate-type=rlib -//@ needs-llvm-components: x86 -//@ unset-rustc-env:MACOSX_DEPLOYMENT_TARGET -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[repr(C)] -pub struct Bool { - b: bool, -} - -// CHECK: target triple = "x86_64-apple-macosx10.12.0" -#[no_mangle] -pub extern "C" fn structbool() -> Bool { - Bool { b: true } -} diff --git a/tests/codegen/mainsubprogram.rs b/tests/codegen/mainsubprogram.rs deleted file mode 100644 index ce3fe3c8608..00000000000 --- a/tests/codegen/mainsubprogram.rs +++ /dev/null @@ -1,12 +0,0 @@ -// This test depends on a patch that was committed to upstream LLVM -// before 4.0, formerly backported to the Rust LLVM fork. - -//@ ignore-apple -//@ ignore-wasi - -//@ compile-flags: -g -C no-prepopulate-passes - -// CHECK-LABEL: @main -// CHECK: {{.*}}DISubprogram{{.*}}name: "main",{{.*}}DI{{(SP)?}}FlagMainSubprogram{{.*}} - -pub fn main() {} diff --git a/tests/codegen/match-optimized.rs b/tests/codegen/match-optimized.rs deleted file mode 100644 index 7b409e619a8..00000000000 --- a/tests/codegen/match-optimized.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -Cno-prepopulate-passes -Copt-level=3 - -#![crate_type = "lib"] - -pub enum E { - A, - B, - C, -} - -// CHECK-LABEL: @exhaustive_match -#[no_mangle] -pub fn exhaustive_match(e: E) -> u8 { - // CHECK: switch{{.*}}, label %[[OTHERWISE:[a-zA-Z0-9_]+]] [ - // CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[A:[a-zA-Z0-9_]+]] - // CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[B:[a-zA-Z0-9_]+]] - // CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[C:[a-zA-Z0-9_]+]] - // CHECK-NEXT: ] - // CHECK: [[OTHERWISE]]: - // CHECK-NEXT: unreachable - // - // CHECK: [[A]]: - // CHECK-NEXT: store i8 0, ptr %_0, align 1 - // CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]] - // CHECK: [[B]]: - // CHECK-NEXT: store i8 1, ptr %_0, align 1 - // CHECK-NEXT: br label %[[EXIT]] - // CHECK: [[C]]: - // CHECK-NEXT: store i8 3, ptr %_0, align 1 - // CHECK-NEXT: br label %[[EXIT]] - match e { - E::A => 0, - E::B => 1, - E::C => 3, - } -} - -#[repr(u16)] -pub enum E2 { - A = 13, - B = 42, -} - -// For optimized code we produce a switch with an unreachable target as the `otherwise` so LLVM -// knows the possible values. Compare with `tests/codegen/match-unoptimized.rs`. - -// CHECK-LABEL: @exhaustive_match_2 -#[no_mangle] -pub fn exhaustive_match_2(e: E2) -> u8 { - // CHECK: switch i16 %{{.+}}, label %[[UNREACH:.+]] [ - // CHECK-NEXT: i16 13, - // CHECK-NEXT: i16 42, - // CHECK-NEXT: ] - // CHECK: [[UNREACH]]: - // CHECK-NEXT: unreachable - match e { - E2::A => 0, - E2::B => 1, - } -} diff --git a/tests/codegen/match-optimizes-away.rs b/tests/codegen/match-optimizes-away.rs deleted file mode 100644 index 5e9be72a09f..00000000000 --- a/tests/codegen/match-optimizes-away.rs +++ /dev/null @@ -1,41 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled -#![crate_type = "lib"] - -pub enum Three { - A, - B, - C, -} - -#[repr(u16)] -pub enum Four { - A, - B, - C, - D, -} - -#[no_mangle] -pub fn three_valued(x: Three) -> Three { - // CHECK-LABEL: i8 @three_valued(i8{{.+}}%x) - // CHECK-NEXT: {{^.*:$}} - // CHECK-NEXT: ret i8 %x - match x { - Three::A => Three::A, - Three::B => Three::B, - Three::C => Three::C, - } -} - -#[no_mangle] -pub fn four_valued(x: Four) -> Four { - // CHECK-LABEL: i16 @four_valued(i16{{.+}}%x) - // CHECK-NEXT: {{^.*:$}} - // CHECK-NEXT: ret i16 %x - match x { - Four::A => Four::A, - Four::B => Four::B, - Four::C => Four::C, - Four::D => Four::D, - } -} diff --git a/tests/codegen/match-unoptimized.rs b/tests/codegen/match-unoptimized.rs deleted file mode 100644 index 3dfe78c3e16..00000000000 --- a/tests/codegen/match-unoptimized.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 - -#![crate_type = "lib"] - -#[repr(u16)] -pub enum E2 { - A = 13, - B = 42, -} - -// For unoptimized code we produce a `br` instead of a `switch`. Compare with -// `tests/codegen/match-optimized.rs` - -// CHECK-LABEL: @exhaustive_match_2 -#[no_mangle] -pub fn exhaustive_match_2(e: E2) -> u8 { - // CHECK: %[[CMP:.+]] = icmp eq i16 %{{.+}}, 13 - // CHECK-NEXT: br i1 %[[CMP:.+]], - match e { - E2::A => 0, - E2::B => 1, - } -} diff --git a/tests/codegen/maybeuninit-rvo.rs b/tests/codegen/maybeuninit-rvo.rs deleted file mode 100644 index 097aa610f1b..00000000000 --- a/tests/codegen/maybeuninit-rvo.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ needs-unwind -#![feature(c_unwind)] -#![crate_type = "lib"] - -pub struct Foo([u8; 1000]); - -extern "C" { - fn init(p: *mut Foo); -} - -pub fn new_from_uninit() -> Foo { - // CHECK-LABEL: new_from_uninit - // CHECK-NOT: call void @llvm.memcpy. - let mut x = std::mem::MaybeUninit::uninit(); - unsafe { - init(x.as_mut_ptr()); - x.assume_init() - } -} - -extern "C-unwind" { - fn init_unwind(p: *mut Foo); -} - -pub fn new_from_uninit_unwind() -> Foo { - // CHECK-LABEL: new_from_uninit_unwind - // CHECK-NOT: call void @llvm.memcpy. - let mut x = std::mem::MaybeUninit::uninit(); - unsafe { - init_unwind(x.as_mut_ptr()); - x.assume_init() - } -} diff --git a/tests/codegen/mem-replace-big-type.rs b/tests/codegen/mem-replace-big-type.rs deleted file mode 100644 index 0b2229ba7d1..00000000000 --- a/tests/codegen/mem-replace-big-type.rs +++ /dev/null @@ -1,36 +0,0 @@ -// This test ensures that `mem::replace::` only ever calls `@llvm.memcpy` -// with `size_of::()` as the size, and never goes through any wrapper that -// may e.g. multiply `size_of::()` with a variable "count" (which is only -// known to be `1` after inlining). - -//@ compile-flags: -C no-prepopulate-passes -Zinline-mir=no -//@ ignore-std-debug-assertions -// Reason: precondition checks in ptr::read make them a bad candidate for MIR inlining -//@ needs-deterministic-layouts - -#![crate_type = "lib"] - -#[repr(C, align(8))] -pub struct Big([u64; 7]); -pub fn replace_big(dst: &mut Big, src: Big) -> Big { - // Back in 1.68, this emitted six `memcpy`s. - // `read_via_copy` in 1.69 got that down to three. - // `write_via_move` and nvro get this down to the essential two. - std::mem::replace(dst, src) -} - -// NOTE(eddyb) the `CHECK-NOT`s ensure that the only calls of `@llvm.memcpy` in -// the entire output, are the direct calls we want, from `ptr::replace`. - -// CHECK-NOT: call void @llvm.memcpy - -// For a large type, we expect exactly three `memcpy`s -// CHECK-LABEL: define internal void @{{.+}}mem{{.+}}replace{{.+}}(ptr -// CHECK-SAME: sret([56 x i8]){{.+}}[[RESULT:%.+]], ptr{{.+}}%dest, ptr{{.+}}%src) -// CHECK-NOT: call void @llvm.memcpy -// CHECK: call void @llvm.memcpy.{{.+}}(ptr align 8 [[RESULT]], ptr align 8 %dest, i{{.*}} 56, i1 false) -// CHECK-NOT: call void @llvm.memcpy -// CHECK: call void @llvm.memcpy.{{.+}}(ptr align 8 %dest, ptr align 8 %src, i{{.*}} 56, i1 false) -// CHECK-NOT: call void @llvm.memcpy - -// CHECK-NOT: call void @llvm.memcpy diff --git a/tests/codegen/mem-replace-simple-type.rs b/tests/codegen/mem-replace-simple-type.rs deleted file mode 100644 index 9f3c6bacb71..00000000000 --- a/tests/codegen/mem-replace-simple-type.rs +++ /dev/null @@ -1,54 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -//@ only-x86_64 (to not worry about usize differing) -//@ ignore-std-debug-assertions -// Reason: precondition checks make mem::replace not a candidate for MIR inlining - -#![crate_type = "lib"] - -#[no_mangle] -// CHECK-LABEL: @replace_usize( -pub fn replace_usize(r: &mut usize, v: usize) -> usize { - // CHECK-NOT: alloca - // CHECK: %[[R:.+]] = load i64, ptr %r - // CHECK: store i64 %v, ptr %r - // CHECK: ret i64 %[[R]] - std::mem::replace(r, v) -} - -#[no_mangle] -// CHECK-LABEL: @replace_ref_str( -pub fn replace_ref_str<'a>(r: &mut &'a str, v: &'a str) -> &'a str { - // CHECK-NOT: alloca - // CHECK: %[[A:.+]] = load ptr - // CHECK: %[[B:.+]] = load i64 - // CHECK-NOT: store - // CHECK-NOT: load - // CHECK: store ptr - // CHECK: store i64 - // CHECK-NOT: load - // CHECK-NOT: store - // CHECK: %[[P1:.+]] = insertvalue { ptr, i64 } poison, ptr %[[A]], 0 - // CHECK: %[[P2:.+]] = insertvalue { ptr, i64 } %[[P1]], i64 %[[B]], 1 - // CHECK: ret { ptr, i64 } %[[P2]] - std::mem::replace(r, v) -} - -#[no_mangle] -// CHECK-LABEL: @replace_short_array_3( -// CHECK-SAME: ptr{{.+}}sret{{.+}}%[[RET:.+]], ptr{{.+}}%r, ptr{{.+}}%v -pub fn replace_short_array_3(r: &mut [u32; 3], v: [u32; 3]) -> [u32; 3] { - // CHECK-NOT: alloca - // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[RET]], ptr align 4 %r, i64 12, i1 false) - // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %r, ptr align 4 %v, i64 12, i1 false) - std::mem::replace(r, v) -} - -#[no_mangle] -// CHECK-LABEL: @replace_short_array_4( -// CHECK-SAME: ptr{{.+}}sret{{.+}}%[[RET:.+]], ptr{{.+}}%r, ptr{{.+}}%v -pub fn replace_short_array_4(r: &mut [u32; 4], v: [u32; 4]) -> [u32; 4] { - // CHECK-NOT: alloca - // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[RET]], ptr align 4 %r, i64 16, i1 false) - // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %r, ptr align 4 %v, i64 16, i1 false) - std::mem::replace(r, v) -} diff --git a/tests/codegen/merge-functions.rs b/tests/codegen/merge-functions.rs deleted file mode 100644 index b9d3727ce11..00000000000 --- a/tests/codegen/merge-functions.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ revisions: O Os -//@[Os] compile-flags: -Copt-level=s -//@[O] compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -// CHECK: @func{{2|1}} = {{.*}}alias{{.*}}@func{{1|2}} - -#[no_mangle] -pub fn func1(c: char) -> bool { - c == 's' || c == 'm' || c == 'h' || c == 'd' || c == 'w' -} - -#[no_mangle] -pub fn func2(c: char) -> bool { - matches!(c, 's' | 'm' | 'h' | 'd' | 'w') -} diff --git a/tests/codegen/meta-filecheck/check-prefix.rs b/tests/codegen/meta-filecheck/check-prefix.rs deleted file mode 100644 index 98bec68627e..00000000000 --- a/tests/codegen/meta-filecheck/check-prefix.rs +++ /dev/null @@ -1,4 +0,0 @@ -// Simple test that uses the default CHECK prefix and should always succeed. - -// CHECK: main -fn main() {} diff --git a/tests/codegen/meta-filecheck/filecheck-flags.rs b/tests/codegen/meta-filecheck/filecheck-flags.rs deleted file mode 100644 index 8e451cf4fdc..00000000000 --- a/tests/codegen/meta-filecheck/filecheck-flags.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Arguments provided via `filecheck-flags` should be passed to `filecheck`. - -//@ revisions: good bad -//@ [good] filecheck-flags: --check-prefix=CUSTOM -//@ [bad] should-fail - -// CUSTOM: main -fn main() {} diff --git a/tests/codegen/meta-filecheck/msvc-prefix-bad.rs b/tests/codegen/meta-filecheck/msvc-prefix-bad.rs deleted file mode 100644 index f9984c74e2a..00000000000 --- a/tests/codegen/meta-filecheck/msvc-prefix-bad.rs +++ /dev/null @@ -1,7 +0,0 @@ -// This is exactly like `msvc-prefix-good.rs`, except that it should always fail. - -//@ should-fail - -// MSVC: text that should not match -// NONMSVC: text that should not match -fn main() {} diff --git a/tests/codegen/meta-filecheck/no-directives.rs b/tests/codegen/meta-filecheck/no-directives.rs deleted file mode 100644 index 2cab263604e..00000000000 --- a/tests/codegen/meta-filecheck/no-directives.rs +++ /dev/null @@ -1,5 +0,0 @@ -// A test that doesn't include any filecheck directives should fail. - -//@ should-fail - -fn main() {} diff --git a/tests/codegen/meta-filecheck/revision-prefix.rs b/tests/codegen/meta-filecheck/revision-prefix.rs deleted file mode 100644 index 431066e3acc..00000000000 --- a/tests/codegen/meta-filecheck/revision-prefix.rs +++ /dev/null @@ -1,8 +0,0 @@ -// The current revision name is registered as a filecheck prefix. - -//@ revisions: GOOD BAD -//@ [BAD] should-fail - -// GOOD: main -// BAD: text that should not match -fn main() {} diff --git a/tests/codegen/method-declaration.rs b/tests/codegen/method-declaration.rs deleted file mode 100644 index de2f96a5151..00000000000 --- a/tests/codegen/method-declaration.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ compile-flags: -g -Cno-prepopulate-passes - -// Verify that we added a declaration for a method. - -// CHECK: define{{.*}}@method{{.*}} !dbg ![[METHOD_DEF_DBG:[0-9]+]] -// CHECK: define{{.*}}@function{{.*}} !dbg ![[FUNC_DEF_DBG:[0-9]+]] - -#![crate_type = "lib"] - -// CHECK-DAG: ![[FOO_DBG:[0-9]+]] = !DICompositeType(tag: {{.*}} name: "Foo", {{.*}} identifier: -pub struct Foo; - -impl Foo { - // CHECK-DAG: ![[METHOD_DEF_DBG]] = distinct !DISubprogram(name: "method"{{.*}}, scope: ![[FOO_DBG]]{{.*}}DISPFlagDefinition{{.*}}, declaration: ![[METHOD_DECL_DBG:[0-9]+]] - // CHECK-DAG: ![[METHOD_DECL_DBG]] = !DISubprogram(name: "method"{{.*}}, scope: ![[FOO_DBG]] - #[no_mangle] - pub fn method() {} -} - -// CHECK: ![[FUNC_DEF_DBG]] = distinct !DISubprogram(name: "function" -// CHECK-NOT: declaration -// CHECK-SAME: DISPFlagDefinition -// CHECK-NOT: declaration -// CHECK-SAME: ) -#[no_mangle] -pub fn function() {} diff --git a/tests/codegen/min-function-alignment.rs b/tests/codegen/min-function-alignment.rs deleted file mode 100644 index ea5f957e81f..00000000000 --- a/tests/codegen/min-function-alignment.rs +++ /dev/null @@ -1,48 +0,0 @@ -//@ revisions: align16 align1024 -//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 -Clink-dead-code -//@ [align16] compile-flags: -Zmin-function-alignment=16 -//@ [align1024] compile-flags: -Zmin-function-alignment=1024 -//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) - -#![crate_type = "lib"] -// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity -#![feature(rustc_attrs)] -#![feature(fn_align)] - -// Functions without explicit alignment use the global minimum. -// -// NOTE: this function deliberately has zero (0) attributes! That is to make sure that -// `-Zmin-function-alignment` is applied regardless of whether attributes are used. -// -// CHECK-LABEL: no_explicit_align -// align16: align 16 -// align1024: align 1024 -pub fn no_explicit_align() {} - -// CHECK-LABEL: @lower_align -// align16: align 16 -// align1024: align 1024 -#[no_mangle] -#[rustc_align(8)] -pub fn lower_align() {} - -// the higher value of min-function-alignment and the align attribute wins out -// -// CHECK-LABEL: @higher_align -// align16: align 32 -// align1024: align 1024 -#[no_mangle] -#[rustc_align(32)] -pub fn higher_align() {} - -// cold functions follow the same rules as other functions -// -// in GCC, the `-falign-functions` does not apply to cold functions, but -// `-Zmin-function-alignment` applies to all functions. -// -// CHECK-LABEL: @no_explicit_align_cold -// align16: align 16 -// align1024: align 1024 -#[no_mangle] -#[cold] -pub fn no_explicit_align_cold() {} diff --git a/tests/codegen/mir-aggregate-no-alloca.rs b/tests/codegen/mir-aggregate-no-alloca.rs deleted file mode 100644 index 77d367ed5da..00000000000 --- a/tests/codegen/mir-aggregate-no-alloca.rs +++ /dev/null @@ -1,137 +0,0 @@ -// 32-bit systems will return 128bit values using a return area pointer. -//@ revisions: bit32 bit64 -//@[bit32] only-32bit -//@[bit64] only-64bit -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z randomize-layout=no - -#![crate_type = "lib"] - -#[repr(transparent)] -pub struct Transparent32(u32); - -// CHECK: i32 @make_transparent(i32{{.*}} %x) -#[no_mangle] -pub fn make_transparent(x: u32) -> Transparent32 { - // CHECK-NOT: alloca - // CHECK: ret i32 %x - let a = Transparent32(x); - a -} - -// CHECK: i32 @make_closure(i32{{.*}} %x) -#[no_mangle] -pub fn make_closure(x: i32) -> impl Fn(i32) -> i32 { - // CHECK-NOT: alloca - // CHECK: ret i32 %x - move |y| x + y -} - -#[repr(transparent)] -pub struct TransparentPair((), (u16, u16), ()); - -// CHECK: { i16, i16 } @make_transparent_pair(i16 noundef %x.0, i16 noundef %x.1) -#[no_mangle] -pub fn make_transparent_pair(x: (u16, u16)) -> TransparentPair { - // CHECK-NOT: alloca - // CHECK: %[[TEMP0:.+]] = insertvalue { i16, i16 } poison, i16 %x.0, 0 - // CHECK: %[[TEMP1:.+]] = insertvalue { i16, i16 } %[[TEMP0]], i16 %x.1, 1 - // CHECK: ret { i16, i16 } %[[TEMP1]] - let a = TransparentPair((), x, ()); - a -} - -// CHECK-LABEL: { i32, i32 } @make_2_tuple(i32{{.*}} %x) -#[no_mangle] -pub fn make_2_tuple(x: u32) -> (u32, u32) { - // CHECK-NOT: alloca - // CHECK: %[[TEMP0:.+]] = insertvalue { i32, i32 } poison, i32 %x, 0 - // CHECK: %[[TEMP1:.+]] = insertvalue { i32, i32 } %[[TEMP0]], i32 %x, 1 - // CHECK: ret { i32, i32 } %[[TEMP1]] - let pair = (x, x); - pair -} - -// CHECK-LABEL: i8 @make_cell_of_bool(i1 noundef zeroext %b) -#[no_mangle] -pub fn make_cell_of_bool(b: bool) -> std::cell::Cell { - // CHECK: %[[BYTE:.+]] = zext i1 %b to i8 - // CHECK: ret i8 %[[BYTE]] - std::cell::Cell::new(b) -} - -// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16{{.*}} %s) -#[no_mangle] -pub fn make_cell_of_bool_and_short(b: bool, s: u16) -> std::cell::Cell<(bool, u16)> { - // CHECK-NOT: alloca - // CHECK: %[[BYTE:.+]] = zext i1 %b to i8 - // CHECK: %[[TEMP0:.+]] = insertvalue { i8, i16 } poison, i8 %[[BYTE]], 0 - // CHECK: %[[TEMP1:.+]] = insertvalue { i8, i16 } %[[TEMP0]], i16 %s, 1 - // CHECK: ret { i8, i16 } %[[TEMP1]] - std::cell::Cell::new((b, s)) -} - -// CHECK-LABEL: { i1, i1 } @make_tuple_of_bools(i1 noundef zeroext %a, i1 noundef zeroext %b) -#[no_mangle] -pub fn make_tuple_of_bools(a: bool, b: bool) -> (bool, bool) { - // CHECK-NOT: alloca - // CHECK: %[[TEMP0:.+]] = insertvalue { i1, i1 } poison, i1 %a, 0 - // CHECK: %[[TEMP1:.+]] = insertvalue { i1, i1 } %[[TEMP0]], i1 %b, 1 - // CHECK: ret { i1, i1 } %[[TEMP1]] - (a, b) -} - -pub struct Struct0(); - -// CHECK-LABEL: void @make_struct_0() -#[no_mangle] -pub fn make_struct_0() -> Struct0 { - // CHECK: ret void - let s = Struct0(); - s -} - -pub struct Struct1(i32); - -// CHECK-LABEL: i32 @make_struct_1(i32{{.*}} %a) -#[no_mangle] -pub fn make_struct_1(a: i32) -> Struct1 { - // CHECK: ret i32 %a - let s = Struct1(a); - s -} - -pub struct Struct2Asc(i16, i64); - -// bit32-LABEL: void @make_struct_2_asc({{.*}} sret({{[^,]*}}) {{.*}} %s, -// bit64-LABEL: { i64, i16 } @make_struct_2_asc( -// CHECK-SAME: i16{{.*}} %a, i64 noundef %b) -#[no_mangle] -pub fn make_struct_2_asc(a: i16, b: i64) -> Struct2Asc { - // CHECK-NOT: alloca - // bit32: %[[GEP:.+]] = getelementptr inbounds i8, ptr %s, i32 8 - // bit32: store i16 %a, ptr %[[GEP]] - // bit32: store i64 %b, ptr %s - // bit64: %[[TEMP0:.+]] = insertvalue { i64, i16 } poison, i64 %b, 0 - // bit64: %[[TEMP1:.+]] = insertvalue { i64, i16 } %[[TEMP0]], i16 %a, 1 - // bit64: ret { i64, i16 } %[[TEMP1]] - let s = Struct2Asc(a, b); - s -} - -pub struct Struct2Desc(i64, i16); - -// bit32-LABEL: void @make_struct_2_desc({{.*}} sret({{[^,]*}}) {{.*}} %s, -// bit64-LABEL: { i64, i16 } @make_struct_2_desc( -// CHECK-SAME: i64 noundef %a, i16{{.*}} %b) -#[no_mangle] -pub fn make_struct_2_desc(a: i64, b: i16) -> Struct2Desc { - // CHECK-NOT: alloca - // bit32: store i64 %a, ptr %s - // bit32: %[[GEP:.+]] = getelementptr inbounds i8, ptr %s, i32 8 - // bit32: store i16 %b, ptr %[[GEP]] - // bit64: %[[TEMP0:.+]] = insertvalue { i64, i16 } poison, i64 %a, 0 - // bit64: %[[TEMP1:.+]] = insertvalue { i64, i16 } %[[TEMP0]], i16 %b, 1 - // bit64: ret { i64, i16 } %[[TEMP1]] - let s = Struct2Desc(a, b); - s -} diff --git a/tests/codegen/mir-inlined-line-numbers.rs b/tests/codegen/mir-inlined-line-numbers.rs deleted file mode 100644 index cfe43a6cf89..00000000000 --- a/tests/codegen/mir-inlined-line-numbers.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ compile-flags: -Copt-level=3 -g - -#![crate_type = "lib"] - -#[inline(always)] -fn foo() { - bar(); -} - -#[inline(never)] -#[no_mangle] -fn bar() { - panic!(); -} - -#[no_mangle] -pub fn example() { - foo(); -} - -// CHECK-LABEL: @example -// CHECK: tail call void @bar(){{( #[0-9]+)?}}, !dbg [[DBG_ID:![0-9]+]] -// CHECK: [[DBG_ID]] = !DILocation(line: 7, -// CHECK-SAME: inlinedAt: [[INLINE_ID:![0-9]+]]) -// CHECK: [[INLINE_ID]] = !DILocation(line: 18, diff --git a/tests/codegen/mir_zst_stores.rs b/tests/codegen/mir_zst_stores.rs deleted file mode 100644 index ff1d429cffd..00000000000 --- a/tests/codegen/mir_zst_stores.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -use std::marker::PhantomData; - -#[derive(Copy, Clone)] -struct Zst { - phantom: PhantomData, -} - -// CHECK-LABEL: @mir -// CHECK-NOT: store{{.*}}undef -#[no_mangle] -pub fn mir() { - let x = Zst { phantom: PhantomData }; - let y = (x, 0); - drop(y); - drop((0, x)); -} diff --git a/tests/codegen/move-before-nocapture-ref-arg.rs b/tests/codegen/move-before-nocapture-ref-arg.rs deleted file mode 100644 index 2ebd645e1c3..00000000000 --- a/tests/codegen/move-before-nocapture-ref-arg.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Verify that move before the call of the function with noalias, nocapture, readonly. -// #107436 -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -#[repr(C)] -pub struct ThreeSlices<'a>(&'a [u32], &'a [u32], &'a [u32]); - -#[no_mangle] -pub fn sum_slices(val: ThreeSlices) -> u32 { - // CHECK-NOT: memcpy - let val = val; - sum(&val) -} - -#[no_mangle] -#[inline(never)] -pub fn sum(val: &ThreeSlices) -> u32 { - val.0.iter().sum::() + val.1.iter().sum::() + val.2.iter().sum::() -} diff --git a/tests/codegen/move-operands.rs b/tests/codegen/move-operands.rs deleted file mode 100644 index ddad231b762..00000000000 --- a/tests/codegen/move-operands.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Verify that optimized MIR only copies `a` once. -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes - -#![crate_type = "lib"] - -type T = [u8; 256]; - -#[no_mangle] -pub fn f(a: T, b: fn(_: T, _: T)) { - // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, {{.*}} 256, i1 false) - // CHECK-NOT: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, {{.*}} 256, i1 false) - b(a, a) -} diff --git a/tests/codegen/naked-asan.rs b/tests/codegen/naked-asan.rs deleted file mode 100644 index 46218cf79d6..00000000000 --- a/tests/codegen/naked-asan.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@ add-core-stubs -//@ needs-llvm-components: x86 -//@ compile-flags: --target x86_64-unknown-linux-gnu -Zsanitizer=address -Ctarget-feature=-crt-static - -// Make sure we do not request sanitizers for naked functions. - -#![crate_type = "lib"] -#![feature(no_core)] -#![no_std] -#![no_core] -#![feature(abi_x86_interrupt)] - -extern crate minicore; -use minicore::*; - -#[no_mangle] -pub fn caller() { - unsafe { asm!("call {}", sym page_fault_handler) } -} - -// CHECK: declare x86_intrcc void @page_fault_handler(){{.*}}#[[ATTRS:[0-9]+]] -#[unsafe(naked)] -#[no_mangle] -pub extern "x86-interrupt" fn page_fault_handler() { - naked_asm!("ud2") -} - -// CHECK: #[[ATTRS]] = -// CHECK-NOT: sanitize_address -// CHECK: !llvm.module.flags diff --git a/tests/codegen/naked-fn/aligned.rs b/tests/codegen/naked-fn/aligned.rs deleted file mode 100644 index d7281c4219a..00000000000 --- a/tests/codegen/naked-fn/aligned.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -//@ needs-asm-support -//@ ignore-arm no "ret" mnemonic -//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) - -#![crate_type = "lib"] -// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity -#![feature(rustc_attrs)] -#![feature(fn_align)] - -use std::arch::naked_asm; - -// CHECK: .balign 16 -// CHECK-LABEL: naked_empty: -#[rustc_align(16)] -#[no_mangle] -#[unsafe(naked)] -pub extern "C" fn naked_empty() { - // CHECK: ret - naked_asm!("ret") -} diff --git a/tests/codegen/naked-fn/generics.rs b/tests/codegen/naked-fn/generics.rs deleted file mode 100644 index 865be00d91e..00000000000 --- a/tests/codegen/naked-fn/generics.rs +++ /dev/null @@ -1,111 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-x86_64 - -#![crate_type = "lib"] - -use std::arch::naked_asm; - -#[no_mangle] -fn test(x: u64) { - // just making sure these symbols get used - using_const_generics::<1>(x); - using_const_generics::<2>(x); - - generic_function::(x as i64); - - let foo = Foo(x); - - foo.method(); - foo.trait_method(); -} - -// CHECK: .balign 4 -// CHECK: add rax, 2 -// CHECK: add rax, 42 - -// CHECK: .balign 4 -// CHECK: add rax, 1 -// CHECK: add rax, 42 - -#[unsafe(naked)] -pub extern "C" fn using_const_generics(x: u64) -> u64 { - const M: u64 = 42; - - naked_asm!( - "xor rax, rax", - "add rax, rdi", - "add rax, {}", - "add rax, {}", - "ret", - const N, - const M, - ) -} - -trait Invert { - fn invert(self) -> Self; -} - -impl Invert for i64 { - fn invert(self) -> Self { - -1 * self - } -} - -// CHECK: .balign 4 -// CHECK-LABEL: generic_function: -// CHECK: call -// CHECK: ret - -#[unsafe(naked)] -#[no_mangle] -pub extern "C" fn generic_function(x: i64) -> i64 { - naked_asm!( - "call {}", - "ret", - sym ::invert, - ) -} - -#[derive(Copy, Clone)] -#[repr(transparent)] -struct Foo(u64); - -// CHECK: .balign 4 -// CHECK-LABEL: method: -// CHECK: mov rax, rdi - -impl Foo { - #[unsafe(naked)] - #[no_mangle] - extern "C" fn method(self) -> u64 { - naked_asm!("mov rax, rdi", "ret") - } -} - -// CHECK: .balign 4 -// CHECK-LABEL: trait_method: -// CHECK: mov rax, rdi - -trait Bar { - extern "C" fn trait_method(self) -> u64; -} - -impl Bar for Foo { - #[unsafe(naked)] - #[no_mangle] - extern "C" fn trait_method(self) -> u64 { - naked_asm!("mov rax, rdi", "ret") - } -} - -// CHECK: .balign 4 -// CHECK-LABEL: naked_with_args_and_return: -// CHECK: lea rax, [rdi + rsi] - -// this previously ICE'd, see https://github.com/rust-lang/rust/issues/124375 -#[unsafe(naked)] -#[no_mangle] -pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { - naked_asm!("lea rax, [rdi + rsi]", "ret"); -} diff --git a/tests/codegen/naked-fn/instruction-set.rs b/tests/codegen/naked-fn/instruction-set.rs deleted file mode 100644 index 67560c5aba7..00000000000 --- a/tests/codegen/naked-fn/instruction-set.rs +++ /dev/null @@ -1,53 +0,0 @@ -//@ add-core-stubs -//@ revisions: arm-mode thumb-mode -//@ [arm-mode] compile-flags: --target armv5te-none-eabi -//@ [thumb-mode] compile-flags: --target thumbv5te-none-eabi -//@ [arm-mode] needs-llvm-components: arm -//@ [thumb-mode] needs-llvm-components: arm - -#![crate_type = "lib"] -#![feature(no_core, lang_items, rustc_attrs)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// arm-mode: .arm -// thumb-mode: .thumb -// CHECK-LABEL: test_unspecified: -// CHECK: bx lr -// CHECK: .popsection -// arm-mode: .arm -// thumb-mode: .thumb -#[no_mangle] -#[unsafe(naked)] -extern "C" fn test_unspecified() { - naked_asm!("bx lr"); -} - -// CHECK: .thumb -// CHECK: .thumb_func -// CHECK-LABEL: test_thumb: -// CHECK: bx lr -// CHECK: .popsection -// arm-mode: .arm -// thumb-mode: .thumb -#[no_mangle] -#[unsafe(naked)] -#[instruction_set(arm::t32)] -extern "C" fn test_thumb() { - naked_asm!("bx lr"); -} - -// CHECK: .arm -// CHECK-LABEL: test_arm: -// CHECK: bx lr -// CHECK: .popsection -// arm-mode: .arm -// thumb-mode: .thumb -#[no_mangle] -#[unsafe(naked)] -#[instruction_set(arm::a32)] -extern "C" fn test_arm() { - naked_asm!("bx lr"); -} diff --git a/tests/codegen/naked-fn/min-function-alignment.rs b/tests/codegen/naked-fn/min-function-alignment.rs deleted file mode 100644 index 406e9334fa5..00000000000 --- a/tests/codegen/naked-fn/min-function-alignment.rs +++ /dev/null @@ -1,47 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -Zmin-function-alignment=16 -//@ needs-asm-support -//@ ignore-arm no "ret" mnemonic -//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) - -// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity -#![feature(rustc_attrs)] -#![feature(fn_align)] -#![crate_type = "lib"] - -// functions without explicit alignment use the global minimum -// -// CHECK: .balign 16 -#[no_mangle] -#[unsafe(naked)] -pub extern "C" fn naked_no_explicit_align() { - core::arch::naked_asm!("ret") -} - -// CHECK: .balign 16 -#[no_mangle] -#[rustc_align(8)] -#[unsafe(naked)] -pub extern "C" fn naked_lower_align() { - core::arch::naked_asm!("ret") -} - -// CHECK: .balign 32 -#[no_mangle] -#[rustc_align(32)] -#[unsafe(naked)] -pub extern "C" fn naked_higher_align() { - core::arch::naked_asm!("ret") -} - -// cold functions follow the same rules as other functions -// -// in GCC, the `-falign-functions` does not apply to cold functions, but -// `-Zmin-function-alignment` applies to all functions. -// -// CHECK: .balign 16 -#[no_mangle] -#[cold] -#[unsafe(naked)] -pub extern "C" fn no_explicit_align_cold() { - core::arch::naked_asm!("ret") -} diff --git a/tests/codegen/naked-fn/naked-functions.rs b/tests/codegen/naked-fn/naked-functions.rs deleted file mode 100644 index 344af6eb42f..00000000000 --- a/tests/codegen/naked-fn/naked-functions.rs +++ /dev/null @@ -1,165 +0,0 @@ -//@ add-core-stubs -//@ revisions: linux win_x86 win_i686 macos thumb -// -//@[linux] compile-flags: --target x86_64-unknown-linux-gnu -//@[linux] needs-llvm-components: x86 -//@[win_x86] compile-flags: --target x86_64-pc-windows-gnu -//@[win_x86] needs-llvm-components: x86 -//@[win_i686] compile-flags: --target i686-pc-windows-gnu -//@[win_i686] needs-llvm-components: x86 -//@[macos] compile-flags: --target aarch64-apple-darwin -//@[macos] needs-llvm-components: arm -//@[thumb] compile-flags: --target thumbv7em-none-eabi -//@[thumb] needs-llvm-components: arm - -#![crate_type = "lib"] -#![feature(no_core, lang_items, rustc_attrs)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// linux,win: .intel_syntax -// -// linux: .pushsection .text.naked_empty,\22ax\22, @progbits -// macos: .pushsection __TEXT,__text,regular,pure_instructions -// win_x86: .pushsection .text.naked_empty,\22xr\22 -// win_i686: .pushsection .text._naked_empty,\22xr\22 -// thumb: .pushsection .text.naked_empty,\22ax\22, %progbits -// -// CHECK: .balign 4 -// -// linux,win,thumb: .globl naked_empty -// macos: .globl _naked_empty -// -// CHECK-NOT: .private_extern -// CHECK-NOT: .hidden -// -// linux: .type naked_empty, @function -// -// win_x86: .def naked_empty -// win_i686: .def _naked_empty -// -// win_x86,win_i686: .scl 2 -// win_x86,win_i686: .type 32 -// win_x86,win_i686: .endef -// -// thumb: .type naked_empty, %function -// thumb: .thumb -// thumb: .thumb_func -// -// CHECK-LABEL: naked_empty: -// -// linux,macos,win: ret -// thumb: bx lr -// -// CHECK: .popsection -// -// thumb: .thumb -// -// linux,win: .att_syntax - -#[no_mangle] -#[unsafe(naked)] -pub extern "C" fn naked_empty() { - #[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))] - naked_asm!("ret"); - - #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] - naked_asm!("bx lr"); -} - -// linux,win: .intel_syntax -// -// linux: .pushsection .text.naked_with_args_and_return,\22ax\22, @progbits -// macos: .pushsection __TEXT,__text,regular,pure_instructions -// win_x86: .pushsection .text.naked_with_args_and_return,\22xr\22 -// win_i686: .pushsection .text._naked_with_args_and_return,\22xr\22 -// thumb: .pushsection .text.naked_with_args_and_return,\22ax\22, %progbits -// -// CHECK: .balign 4 -// -// linux,win,thumb: .globl naked_with_args_and_return -// macos: .globl _naked_with_args_and_return -// -// CHECK-NOT: .private_extern -// CHECK-NOT: .hidden -// -// linux: .type naked_with_args_and_return, @function -// -// win_x86: .def naked_with_args_and_return -// win_i686: .def _naked_with_args_and_return -// -// win_x86,win_i686: .scl 2 -// win_x86,win_i686: .type 32 -// win_x86,win_i686: .endef -// -// thumb: .type naked_with_args_and_return, %function -// thumb: .thumb -// thumb: .thumb_func -// -// CHECK-LABEL: naked_with_args_and_return: -// -// linux, win_x86,win_i686: lea rax, [rdi + rsi] -// macos: add x0, x0, x1 -// thumb: adds r0, r0, r1 -// -// linux,macos,win: ret -// thumb: bx lr -// -// CHECK: .popsection -// -// thumb: .thumb -// -// linux,win: .att_syntax - -#[no_mangle] -#[unsafe(naked)] -pub extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { - #[cfg(any(target_os = "windows", target_os = "linux"))] - { - naked_asm!("lea rax, [rdi + rsi]", "ret") - } - - #[cfg(target_os = "macos")] - { - naked_asm!("add x0, x0, x1", "ret") - } - - #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] - { - naked_asm!("adds r0, r0, r1", "bx lr") - } -} - -// linux: .pushsection .text.some_different_name,\22ax\22, @progbits -// macos: .pushsection .text.some_different_name,regular,pure_instructions -// win_x86,win_i686: .pushsection .text.some_different_name,\22xr\22 -// thumb: .pushsection .text.some_different_name,\22ax\22, %progbits -// CHECK-LABEL: test_link_section: -#[no_mangle] -#[unsafe(naked)] -#[link_section = ".text.some_different_name"] -pub extern "C" fn test_link_section() { - #[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))] - naked_asm!("ret"); - - #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] - naked_asm!("bx lr"); -} - -// win_x86: .def fastcall_cc -// win_i686: .def @fastcall_cc@4 -// -// win_x86,win_i686: .scl 2 -// win_x86,win_i686: .type 32 -// win_x86,win_i686: .endef -// -// win_x86-LABEL: fastcall_cc: -// win_i686-LABEL: @fastcall_cc@4: -#[cfg(target_os = "windows")] -#[no_mangle] -#[unsafe(naked)] -pub extern "fastcall" fn fastcall_cc(x: i32) -> i32 { - naked_asm!("ret"); -} diff --git a/tests/codegen/no-alloca-inside-if-false.rs b/tests/codegen/no-alloca-inside-if-false.rs deleted file mode 100644 index a231c7e808a..00000000000 --- a/tests/codegen/no-alloca-inside-if-false.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 -Cpanic=abort -// Check that there's an alloca for the reference and the vector, but nothing else. -// We use panic=abort because unwinding panics give hint::black_box a cleanup block, which has -// another alloca. - -#![crate_type = "lib"] - -#[inline(never)] -fn test() { - // CHECK-LABEL: no_alloca_inside_if_false::test - // CHECK: start: - // CHECK-NEXT: alloca [{{12|24}} x i8] - // CHECK-NOT: alloca - if const { SIZE < 4096 } { - let arr = [0u8; SIZE]; - std::hint::black_box(&arr); - } else { - let vec = vec![0u8; SIZE]; - std::hint::black_box(&vec); - } -} - -// CHECK-LABEL: @main -#[no_mangle] -pub fn main() { - test::<8192>(); -} diff --git a/tests/codegen/no-assumes-on-casts.rs b/tests/codegen/no-assumes-on-casts.rs deleted file mode 100644 index 9c00dc2c015..00000000000 --- a/tests/codegen/no-assumes-on-casts.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![crate_type = "lib"] - -//@ compile-flags: -Cno-prepopulate-passes - -// CHECK-LABEL: fna -#[no_mangle] -pub fn fna(a: i16) -> i32 { - a as i32 - // CHECK-NOT: assume - // CHECK: sext -} - -// CHECK-LABEL: fnb -#[no_mangle] -pub fn fnb(a: u16) -> u32 { - a as u32 - // CHECK-NOT: assume - // CHECK: zext -} diff --git a/tests/codegen/no-dllimport-w-cross-lang-lto.rs b/tests/codegen/no-dllimport-w-cross-lang-lto.rs deleted file mode 100644 index c71eddfa287..00000000000 --- a/tests/codegen/no-dllimport-w-cross-lang-lto.rs +++ /dev/null @@ -1,13 +0,0 @@ -// This test makes sure that functions get annotated with the proper -// "target-cpu" attribute in LLVM. - -//@ no-prefer-dynamic -//@ only-msvc -//@ compile-flags: -C linker-plugin-lto - -#![crate_type = "rlib"] - -// CHECK-NOT: @{{.*}}__imp_{{.*}}GLOBAL{{.*}} = global i8* - -pub static GLOBAL: u32 = 0; -pub static mut GLOBAL2: u32 = 0; diff --git a/tests/codegen/no-jump-tables.rs b/tests/codegen/no-jump-tables.rs deleted file mode 100644 index e49de7e9dc1..00000000000 --- a/tests/codegen/no-jump-tables.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Test that the `no-jump-tables` function attribute are (not) emitted when -// the `-Zno-jump-tables` flag is (not) set. - -//@ add-core-stubs -//@ revisions: unset set -//@ needs-llvm-components: x86 -//@ compile-flags: --target x86_64-unknown-linux-gnu -//@ [set] compile-flags: -Zno-jump-tables - -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[no_mangle] -pub fn foo() { - // CHECK: @foo() unnamed_addr #0 - - // unset-NOT: attributes #0 = { {{.*}}"no-jump-tables"="true"{{.*}} } - // set: attributes #0 = { {{.*}}"no-jump-tables"="true"{{.*}} } -} diff --git a/tests/codegen/no-plt.rs b/tests/codegen/no-plt.rs deleted file mode 100644 index 3a3546ff7c4..00000000000 --- a/tests/codegen/no-plt.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ compile-flags: -C relocation-model=pic -Z plt=no - -#![crate_type = "lib"] - -// We need a function which is normally called through the PLT. -extern "C" { - // CHECK: Function Attrs:{{.*}}nonlazybind - fn getenv(name: *const u8) -> *mut u8; -} - -// Ensure the function gets referenced. -pub unsafe fn call_through_plt() -> *mut u8 { - getenv(b"\0".as_ptr()) -} - -// Ensure intrinsics also skip the PLT -// CHECK: !"RtLibUseGOT" diff --git a/tests/codegen/no-redundant-item-monomorphization.rs b/tests/codegen/no-redundant-item-monomorphization.rs deleted file mode 100644 index 466037c3770..00000000000 --- a/tests/codegen/no-redundant-item-monomorphization.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Test to make sure that inner functions within a polymorphic outer function -// don't get re-codegened when the outer function is monomorphized. The test -// code monomorphizes the outer functions several times, but the magic constants -// used in the inner functions should each appear only once in the generated IR. - -// issue: rust-lang/rust#7349 -//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 - -// CHECK-COUNT-1: ret i32 8675309 -// CHECK-COUNT-1: ret i32 11235813 - -fn outer() { - #[allow(dead_code)] - fn inner() -> u32 { - 8675309 - } - inner(); -} - -extern "C" fn outer_foreign() { - #[allow(dead_code)] - fn inner() -> u32 { - 11235813 - } - inner(); -} - -fn main() { - outer::(); - outer::(); - outer_foreign::(); - outer_foreign::(); -} diff --git a/tests/codegen/no_builtins-at-crate.rs b/tests/codegen/no_builtins-at-crate.rs deleted file mode 100644 index ba1d31f60c3..00000000000 --- a/tests/codegen/no_builtins-at-crate.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ compile-flags: -C opt-level=1 - -#![no_builtins] -#![crate_type = "lib"] - -// CHECK: define -// CHECK-SAME: @__aeabi_memcpy -// CHECK-SAME: #0 -#[no_mangle] -pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, size: usize) { - // CHECK: call - // CHECK-SAME: @memcpy( - 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-SAME: "no-builtins" diff --git a/tests/codegen/noalias-box-off.rs b/tests/codegen/noalias-box-off.rs deleted file mode 100644 index 664c7950280..00000000000 --- a/tests/codegen/noalias-box-off.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Z box-noalias=no - -#![crate_type = "lib"] - -// CHECK-LABEL: @box_should_not_have_noalias_if_disabled( -// CHECK-NOT: noalias -// CHECK-SAME: %foo) -#[no_mangle] -pub fn box_should_not_have_noalias_if_disabled(foo: Box) { - drop(foo); -} diff --git a/tests/codegen/noalias-box.rs b/tests/codegen/noalias-box.rs deleted file mode 100644 index cccde775977..00000000000 --- a/tests/codegen/noalias-box.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @box_should_have_noalias_by_default( -// CHECK: noalias -#[no_mangle] -pub fn box_should_have_noalias_by_default(_b: Box) {} diff --git a/tests/codegen/noalias-flag.rs b/tests/codegen/noalias-flag.rs deleted file mode 100644 index 67ba68ee6f8..00000000000 --- a/tests/codegen/noalias-flag.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Zmutable-noalias=no - -#![crate_type = "lib"] - -// `-Zmutable-noalias=no` should disable noalias on mut refs... - -// CHECK-LABEL: @test_mut_ref( -// CHECK-NOT: noalias -// CHECK-SAME: %x -#[no_mangle] -pub fn test_mut_ref(x: &mut i32) -> &mut i32 { - x -} - -// ...but not on shared refs - -// CHECK-LABEL: @test_ref( -// CHECK-SAME: noalias -// CHECK-SAME: %x -#[no_mangle] -pub fn test_ref(x: &i32) -> &i32 { - x -} diff --git a/tests/codegen/noalias-freeze.rs b/tests/codegen/noalias-freeze.rs deleted file mode 100644 index 32c84014026..00000000000 --- a/tests/codegen/noalias-freeze.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ compile-flags: -Copt-level=1 - -// References returned by a Frozen pointer type -// could be marked as "noalias", which caused miscompilation errors. -// This test runs the most minimal possible code that can reproduce this bug, -// and checks that noalias does not appear. -// See https://github.com/rust-lang/rust/issues/46239 - -#![crate_type = "lib"] - -fn project(x: &(T,)) -> &T { - &x.0 -} - -fn dummy() {} - -// CHECK-LABEL: @foo( -// CHECK-NOT: noalias -#[no_mangle] -pub fn foo() { - let f = (dummy as fn(),); - (*project(&f))(); -} diff --git a/tests/codegen/noalias-refcell.rs b/tests/codegen/noalias-refcell.rs deleted file mode 100644 index b37adf92b9c..00000000000 --- a/tests/codegen/noalias-refcell.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z mutable-noalias=yes - -#![crate_type = "lib"] - -use std::cell::{Ref, RefCell, RefMut}; - -// Make sure that none of the arguments get a `noalias` attribute, because -// the `RefCell` might alias writes after either `Ref`/`RefMut` is dropped. - -// CHECK-LABEL: @maybe_aliased( -// CHECK-NOT: noalias -// CHECK-SAME: %_refcell -#[no_mangle] -pub unsafe fn maybe_aliased(_: Ref<'_, i32>, _: RefMut<'_, i32>, _refcell: &RefCell) {} diff --git a/tests/codegen/noalias-rwlockreadguard.rs b/tests/codegen/noalias-rwlockreadguard.rs deleted file mode 100644 index c676dc32399..00000000000 --- a/tests/codegen/noalias-rwlockreadguard.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z mutable-noalias=yes - -#![crate_type = "lib"] - -use std::sync::{RwLock, RwLockReadGuard}; - -// Make sure that `RwLockReadGuard` does not get a `noalias` attribute, because -// the `RwLock` might alias writes after it is dropped. - -// CHECK-LABEL: @maybe_aliased( -// CHECK-NOT: noalias -// CHECK-SAME: %_data -#[no_mangle] -pub unsafe fn maybe_aliased(_: RwLockReadGuard<'_, i32>, _data: &RwLock) {} diff --git a/tests/codegen/noalias-unpin.rs b/tests/codegen/noalias-unpin.rs deleted file mode 100644 index 30a8b399b97..00000000000 --- a/tests/codegen/noalias-unpin.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Z mutable-noalias=yes - -#![crate_type = "lib"] - -pub struct SelfRef { - self_ref: *mut SelfRef, - _pin: std::marker::PhantomPinned, -} - -// CHECK-LABEL: @test_self_ref( -// CHECK-NOT: noalias -#[no_mangle] -pub unsafe fn test_self_ref(s: &mut SelfRef) { - (*s.self_ref).self_ref = std::ptr::null_mut(); -} diff --git a/tests/codegen/non-terminate/infinite-loop-1.rs b/tests/codegen/non-terminate/infinite-loop-1.rs deleted file mode 100644 index 9eab4939aee..00000000000 --- a/tests/codegen/non-terminate/infinite-loop-1.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ compile-flags: -C opt-level=3 - -#![crate_type = "lib"] - -fn infinite_loop() -> u8 { - loop {} -} - -// CHECK-LABEL: @test -#[no_mangle] -fn test() -> u8 { - // CHECK-NOT: unreachable - // CHECK: br label %{{.+}} - // CHECK-NOT: unreachable - let x = infinite_loop(); - x -} diff --git a/tests/codegen/non-terminate/infinite-loop-2.rs b/tests/codegen/non-terminate/infinite-loop-2.rs deleted file mode 100644 index da29361cc96..00000000000 --- a/tests/codegen/non-terminate/infinite-loop-2.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ compile-flags: -C opt-level=3 - -#![crate_type = "lib"] - -fn infinite_loop() -> u8 { - let i = 2; - while i > 1 {} - 1 -} - -// CHECK-LABEL: @test -#[no_mangle] -fn test() -> u8 { - // CHECK-NOT: unreachable - // CHECK: br label %{{.+}} - // CHECK-NOT: unreachable - let x = infinite_loop(); - x -} diff --git a/tests/codegen/non-terminate/infinite-recursion.rs b/tests/codegen/non-terminate/infinite-recursion.rs deleted file mode 100644 index 19123639896..00000000000 --- a/tests/codegen/non-terminate/infinite-recursion.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ compile-flags: -C opt-level=3 - -#![crate_type = "lib"] -#![allow(unconditional_recursion)] - -// CHECK-LABEL: @infinite_recursion -#[no_mangle] -fn infinite_recursion() -> u8 { - // CHECK-NOT: ret i8 undef - // CHECK: br label %{{.+}} - // CHECK-NOT: ret i8 undef - infinite_recursion() -} diff --git a/tests/codegen/non-terminate/nonempty-infinite-loop.rs b/tests/codegen/non-terminate/nonempty-infinite-loop.rs deleted file mode 100644 index 0db4ee61b1b..00000000000 --- a/tests/codegen/non-terminate/nonempty-infinite-loop.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ compile-flags: -C opt-level=3 - -#![crate_type = "lib"] - -// Verify that we don't miscompile this even if rustc didn't apply the trivial loop detection to -// insert the sideeffect intrinsic. - -fn infinite_loop() -> u8 { - let mut x = 0; - // CHECK-NOT: sideeffect - loop { - if x == 42 { - x = 0; - } else { - x = 42; - } - } -} - -// CHECK-LABEL: @test -#[no_mangle] -fn test() -> u8 { - // CHECK-NOT: unreachable - // CHECK: br label %{{.+}} - // CHECK-NOT: unreachable - let x = infinite_loop(); - x -} diff --git a/tests/codegen/noreturn-uninhabited.rs b/tests/codegen/noreturn-uninhabited.rs deleted file mode 100644 index a10795d3f3c..00000000000 --- a/tests/codegen/noreturn-uninhabited.rs +++ /dev/null @@ -1,31 +0,0 @@ -//@ compile-flags: -g -C no-prepopulate-passes - -#![crate_type = "lib"] - -#[derive(Clone, Copy)] -pub enum EmptyEnum {} - -#[no_mangle] -pub fn empty(x: &EmptyEnum) -> EmptyEnum { - // CHECK: @empty({{.*}}) unnamed_addr #0 - // CHECK-NOT: ret void - // CHECK: call void @llvm.trap() - // CHECK: unreachable - *x -} - -pub struct Foo(String, EmptyEnum); - -#[no_mangle] -pub fn foo(x: String, y: &EmptyEnum) -> Foo { - // CHECK: @foo({{.*}}) unnamed_addr #0 - // CHECK-NOT: ret %Foo - // CHECK: call void @llvm.trap() - // CHECK: unreachable - Foo(x, *y) -} - -// CHECK: attributes #0 = {{{.*}} noreturn {{.*}}} - -// CHECK: DISubprogram(name: "empty", {{.*}} DIFlagNoReturn -// CHECK: DISubprogram(name: "foo", {{.*}} DIFlagNoReturn diff --git a/tests/codegen/noreturnflag.rs b/tests/codegen/noreturnflag.rs deleted file mode 100644 index d9bb30b2703..00000000000 --- a/tests/codegen/noreturnflag.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ compile-flags: -g -C no-prepopulate-passes - -#![crate_type = "lib"] - -#[no_mangle] -pub fn foo() -> ! { - // CHECK: @foo() unnamed_addr #0 - loop {} -} - -pub enum EmptyEnum {} - -#[no_mangle] -pub fn bar() -> EmptyEnum { - // CHECK: @bar() unnamed_addr #0 - loop {} -} - -// CHECK: attributes #0 = {{{.*}} noreturn {{.*}}} - -// CHECK: DISubprogram(name: "foo", {{.*}} DIFlagNoReturn -// CHECK: DISubprogram(name: "bar", {{.*}} DIFlagNoReturn diff --git a/tests/codegen/nounwind.rs b/tests/codegen/nounwind.rs deleted file mode 100644 index c910644458a..00000000000 --- a/tests/codegen/nounwind.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ aux-build:nounwind.rs -//@ compile-flags: -C no-prepopulate-passes -C panic=abort -C metadata=a -//@ ignore-android - -#![crate_type = "lib"] - -extern crate nounwind; - -#[no_mangle] -pub fn foo() { - nounwind::bar(); - // CHECK: @foo() unnamed_addr #0 - // CHECK: @bar() unnamed_addr #0 - // CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } -} diff --git a/tests/codegen/nrvo.rs b/tests/codegen/nrvo.rs deleted file mode 100644 index 7972186bfe5..00000000000 --- a/tests/codegen/nrvo.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// Ensure that we do not call `memcpy` for the following function. -// `memset` and `init` should be called directly on the return pointer. -#[no_mangle] -pub fn nrvo(init: fn(&mut [u8; 4096])) -> [u8; 4096] { - // CHECK-LABEL: nrvo - // CHECK: @llvm.memset - // FIXME: turn on nrvo then check-not: @llvm.memcpy - // CHECK: ret - // CHECK-EMPTY - let mut buf = [0; 4096]; - init(&mut buf); - buf -} diff --git a/tests/codegen/optimize-attr-1.rs b/tests/codegen/optimize-attr-1.rs deleted file mode 100644 index db6bdcf9a8b..00000000000 --- a/tests/codegen/optimize-attr-1.rs +++ /dev/null @@ -1,59 +0,0 @@ -//@ revisions: NO-OPT SIZE-OPT SPEED-OPT -//@[NO-OPT] compile-flags: -Copt-level=0 -Ccodegen-units=1 -//@[SIZE-OPT] compile-flags: -Copt-level=s -Ccodegen-units=1 -//@[SPEED-OPT] compile-flags: -Copt-level=3 -Ccodegen-units=1 - -#![feature(optimize_attribute)] -#![crate_type = "rlib"] - -// CHECK-LABEL: define{{.*}}i32 @nothing -// CHECK-SAME: [[NOTHING_ATTRS:#[0-9]+]] -// SIZE-OPT: ret i32 4 -// SPEED-OPT: ret i32 4 -#[no_mangle] -pub fn nothing() -> i32 { - 2 + 2 -} - -// CHECK-LABEL: define{{.*}}i32 @size -// CHECK-SAME: [[SIZE_ATTRS:#[0-9]+]] -// SIZE-OPT: ret i32 6 -// SPEED-OPT: ret i32 6 -#[optimize(size)] -#[no_mangle] -pub fn size() -> i32 { - 3 + 3 -} - -// CHECK-LABEL: define{{.*}}i32 @speed -// NO-OPT-SAME: [[NOTHING_ATTRS]] -// SPEED-OPT-SAME: [[NOTHING_ATTRS]] -// SIZE-OPT-SAME: [[SPEED_ATTRS:#[0-9]+]] -// SIZE-OPT: ret i32 8 -// SPEED-OPT: ret i32 8 -#[optimize(speed)] -#[no_mangle] -pub fn speed() -> i32 { - 4 + 4 -} - -// CHECK-LABEL: define{{.*}}i32 @none -// CHECK-SAME: [[NONE_ATTRS:#[0-9]+]] -// SIZE-OPT: alloca -// SPEED-OPT: alloca -#[no_mangle] -#[optimize(none)] -pub fn none() -> i32 { - let arr = [0, 1, 2, 3, 4]; - arr[4] -} - -// NO-OPT-DAG: attributes [[SIZE_ATTRS]] = {{.*}}minsize{{.*}}optsize{{.*}} -// SPEED-OPT-DAG: attributes [[SIZE_ATTRS]] = {{.*}}minsize{{.*}}optsize{{.*}} -// SIZE-OPT-DAG: attributes [[NOTHING_ATTRS]] = {{.*}}optsize{{.*}} -// SIZE-OPT-DAG: attributes [[SIZE_ATTRS]] = {{.*}}minsize{{.*}}optsize{{.*}} -// CHECK-DAG: attributes [[NONE_ATTRS]] = {{.*}}noinline{{.*}}optnone{{.*}} - -// SIZE-OPT-DAG: attributes [[SPEED_ATTRS]] -// SIZE-OPT-NOT: minsize -// SIZE-OPT-NOT: optsize diff --git a/tests/codegen/option-as-slice.rs b/tests/codegen/option-as-slice.rs deleted file mode 100644 index 39b34a2035b..00000000000 --- a/tests/codegen/option-as-slice.rs +++ /dev/null @@ -1,71 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Z randomize-layout=no -//@ only-x86_64 -#![crate_type = "lib"] - -extern crate core; - -use core::num::NonZero; -use core::option::Option; - -// CHECK-LABEL: @u64_opt_as_slice -#[no_mangle] -pub fn u64_opt_as_slice(o: &Option) -> &[u64] { - // CHECK-NOT: select - // CHECK-NOT: br - // CHECK-NOT: switch - // CHECK-NOT: icmp - // CHECK: %[[LEN:.+]] = load i64 - // CHECK-SAME: !range ![[META_U64:[0-9]+]], - // CHECK-SAME: !noundef - // CHECK-NOT: select - // CHECK-NOT: br - // CHECK-NOT: switch - // CHECK-NOT: icmp - // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %{{.+}}, 0 - // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1 - // CHECK-NEXT: ret { ptr, i64 } %[[T1]] - o.as_slice() -} - -// CHECK-LABEL: @nonzero_u64_opt_as_slice -#[no_mangle] -pub fn nonzero_u64_opt_as_slice(o: &Option>) -> &[NonZero] { - // CHECK-NOT: select - // CHECK-NOT: br - // CHECK-NOT: switch - // CHECK-NOT: icmp - // CHECK: %[[NZ:.+]] = icmp ne i64 %{{.+}}, 0 - // CHECK-NEXT: %[[LEN:.+]] = zext i1 %[[NZ]] to i64 - // CHECK-NOT: select - // CHECK-NOT: br - // CHECK-NOT: switch - // CHECK-NOT: icmp - // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %o, 0 - // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1 - // CHECK-NEXT: ret { ptr, i64 } %[[T1]] - o.as_slice() -} - -// CHECK-LABEL: @u8_opt_as_slice -#[no_mangle] -pub fn u8_opt_as_slice(o: &Option) -> &[u8] { - // CHECK-NOT: select - // CHECK-NOT: br - // CHECK-NOT: switch - // CHECK-NOT: icmp - // CHECK: %[[TAG:.+]] = load i8 - // CHECK-SAME: !range ![[META_U8:[0-9]+]], - // CHECK-SAME: !noundef - // CHECK: %[[LEN:.+]] = zext{{.*}} i8 %[[TAG]] to i64 - // CHECK-NOT: select - // CHECK-NOT: br - // CHECK-NOT: switch - // CHECK-NOT: icmp - // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %{{.+}}, 0 - // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1 - // CHECK-NEXT: ret { ptr, i64 } %[[T1]] - o.as_slice() -} - -// CHECK: ![[META_U64]] = !{i64 0, i64 2} -// CHECK: ![[META_U8]] = !{i8 0, i8 2} diff --git a/tests/codegen/option-niche-eq.rs b/tests/codegen/option-niche-eq.rs deleted file mode 100644 index 3900cb79aa2..00000000000 --- a/tests/codegen/option-niche-eq.rs +++ /dev/null @@ -1,87 +0,0 @@ -//@ revisions: REGULAR LLVM21 -//@ min-llvm-version: 20 -//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled -//@ [LLVM21] min-llvm-version: 21 -#![crate_type = "lib"] - -extern crate core; -use core::cmp::Ordering; -use core::num::NonZero; -use core::ptr::NonNull; - -// CHECK-LABEL: @non_zero_eq -#[no_mangle] -pub fn non_zero_eq(l: Option>, r: Option>) -> bool { - // CHECK: start: - // CHECK-NEXT: icmp eq i32 - // CHECK-NEXT: ret i1 - l == r -} - -// CHECK-LABEL: @non_zero_signed_eq -#[no_mangle] -pub fn non_zero_signed_eq(l: Option>, r: Option>) -> bool { - // CHECK: start: - // CHECK-NEXT: icmp eq i64 - // CHECK-NEXT: ret i1 - l == r -} - -// FIXME(#49892) -// This currently relies on a manual implementation of `PartialOrd`/`Ord` for `Option` -// Once LLVM is better able to optimize this pattern, we can return to using a derive. -// CHECK-LABEL: @non_zero_ord -#[no_mangle] -pub fn non_zero_ord(a: Option>, b: Option>) -> bool { - // CHECK: start: - // CHECK-NEXT: icmp ult i32 - // CHECK-NEXT: ret i1 - a < b -} - -// CHECK-LABEL: @non_null_eq -#[no_mangle] -pub fn non_null_eq(l: Option>, r: Option>) -> bool { - // CHECK: start: - // CHECK-NEXT: icmp eq ptr - // CHECK-NEXT: ret i1 - l == r -} - -// CHECK-LABEL: @ordering_eq -#[no_mangle] -pub fn ordering_eq(l: Option, r: Option) -> bool { - // CHECK: start: - // CHECK-NEXT: icmp eq i8 - // CHECK-NEXT: ret i1 - l == r -} - -#[derive(PartialEq)] -pub enum EnumWithNiche { - A, - B, - C, - D, - E, - F, - G, -} - -// CHECK-LABEL: @niche_eq -#[no_mangle] -pub fn niche_eq(l: Option, r: Option) -> bool { - // CHECK: start: - // CHECK-NEXT: icmp eq i8 - // CHECK-NEXT: ret i1 - l == r -} - -// LLVM21-LABEL: @bool_eq -#[no_mangle] -pub fn bool_eq(l: Option, r: Option) -> bool { - // LLVM21: start: - // LLVM21-NEXT: icmp eq i8 - // LLVM21-NEXT: ret i1 - l == r -} diff --git a/tests/codegen/option-niche-unfixed/option-nonzero-eq.rs b/tests/codegen/option-niche-unfixed/option-nonzero-eq.rs deleted file mode 100644 index 308856cfb7e..00000000000 --- a/tests/codegen/option-niche-unfixed/option-nonzero-eq.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ should-fail -//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled -//! FIXME(#49892) -//! Test that the derived implementation of `PartialEq` for `Option` is not fully -//! optimized by LLVM. If this starts passing, the test and manual impl should -//! be removed. -#![crate_type = "lib"] - -use std::num::NonZero; - -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum Option { - None, - Some(T), -} - -// CHECK-LABEL: @non_zero_eq -#[no_mangle] -pub fn non_zero_eq(l: Option>, r: Option>) -> bool { - // CHECK: start: - // CHECK-NEXT: icmp eq i32 - // CHECK-NEXT: ret i1 - l == r -} diff --git a/tests/codegen/overaligned-constant.rs b/tests/codegen/overaligned-constant.rs deleted file mode 100644 index 0f5977880f2..00000000000 --- a/tests/codegen/overaligned-constant.rs +++ /dev/null @@ -1,35 +0,0 @@ -// GVN may create indirect constants with higher alignment than their type requires. Verify that we -// do not ICE during codegen, and that the LLVM constant has the higher alignment. -// -//@ compile-flags: -Zmir-opt-level=0 -Zmir-enable-passes=+GVN -//@ compile-flags: -Cno-prepopulate-passes --crate-type=lib -//@ only-64bit - -struct S(i32); - -struct SmallStruct(f32, Option, &'static [f32]); - -// CHECK: [[const:@.*]] = private unnamed_addr constant -// CHECK-SAME: , align 8 - -#[no_mangle] -pub fn overaligned_constant() { - // CHECK-LABEL: @overaligned_constant - // CHECK: [[full:%_.*]] = alloca [32 x i8], align 8 - // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[full]], ptr align 8 [[const]], i64 32, i1 false) - let mut s = S(1); - - s.0 = 3; - - // SMALL_VAL corresponds to a MIR allocation with alignment 8. - const SMALL_VAL: SmallStruct = SmallStruct(4., Some(S(1)), &[]); - - // In pre-codegen MIR: - // `a` is a scalar 4. - // `b` is an indirect constant at `SMALL_VAL`'s alloc with 0 offset. - // `c` is the empty slice. - // - // As a consequence, during codegen, we create a LLVM allocation for `SMALL_VAL`, with - // alignment 8, but only use the `Option` field, at offset 0 with alignment 4. - let SmallStruct(a, b, c) = SMALL_VAL; -} diff --git a/tests/codegen/packed.rs b/tests/codegen/packed.rs deleted file mode 100644 index 6f62719282e..00000000000 --- a/tests/codegen/packed.rs +++ /dev/null @@ -1,153 +0,0 @@ -// -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes - -#![crate_type = "lib"] - -#[repr(packed)] -pub struct Packed1 { - dealign: u8, - data: u32, -} - -#[repr(packed(2))] -pub struct Packed2 { - dealign: u8, - data: u32, -} - -// CHECK-LABEL: @write_pkd1 -#[no_mangle] -pub fn write_pkd1(pkd: &mut Packed1) -> u32 { - // CHECK: %{{.*}} = load i32, ptr %{{.*}}, align 1 - // CHECK: store i32 42, ptr %{{.*}}, align 1 - let result = pkd.data; - pkd.data = 42; - result -} - -// CHECK-LABEL: @write_pkd2 -#[no_mangle] -pub fn write_pkd2(pkd: &mut Packed2) -> u32 { - // CHECK: %{{.*}} = load i32, ptr %{{.*}}, align 2 - // CHECK: store i32 42, ptr %{{.*}}, align 2 - let result = pkd.data; - pkd.data = 42; - result -} - -pub struct Array([i32; 8]); -#[repr(packed)] -pub struct BigPacked1 { - dealign: u8, - data: Array, -} - -#[repr(packed(2))] -pub struct BigPacked2 { - dealign: u8, - data: Array, -} - -// CHECK-LABEL: @call_pkd1 -#[no_mangle] -pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 { - // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca [32 x i8] - // CHECK: call void %{{.*}}(ptr{{( captures(none))?}} noalias{{( nocapture)?}} noundef sret{{.*}} dereferenceable(32) [[ALLOCA]]) - // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false) - // check that calls whose destination is a field of a packed struct - // go through an alloca rather than calling the function with an - // unaligned destination. - BigPacked1 { dealign: 0, data: f() } -} - -// CHECK-LABEL: @call_pkd2 -#[no_mangle] -pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 { - // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca [32 x i8] - // CHECK: call void %{{.*}}(ptr{{( captures(none))?}} noalias{{( nocapture)?}} noundef sret{{.*}} dereferenceable(32) [[ALLOCA]]) - // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 2 %{{.*}}, ptr align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false) - // check that calls whose destination is a field of a packed struct - // go through an alloca rather than calling the function with an - // unaligned destination. - BigPacked2 { dealign: 0, data: f() } -} - -// CHECK-LABEL: @write_packed_array1 -// CHECK: store i32 0, ptr %{{.+}}, align 1 -// CHECK: store i32 1, ptr %{{.+}}, align 1 -// CHECK: store i32 2, ptr %{{.+}}, align 1 -#[no_mangle] -pub fn write_packed_array1(p: &mut BigPacked1) { - p.data.0[0] = 0; - p.data.0[1] = 1; - p.data.0[2] = 2; -} - -// CHECK-LABEL: @write_packed_array2 -// CHECK: store i32 0, ptr %{{.+}}, align 2 -// CHECK: store i32 1, ptr %{{.+}}, align 2 -// CHECK: store i32 2, ptr %{{.+}}, align 2 -#[no_mangle] -pub fn write_packed_array2(p: &mut BigPacked2) { - p.data.0[0] = 0; - p.data.0[1] = 1; - p.data.0[2] = 2; -} - -// CHECK-LABEL: @repeat_packed_array1 -// CHECK: store i32 42, ptr %{{.+}}, align 1 -#[no_mangle] -pub fn repeat_packed_array1(p: &mut BigPacked1) { - p.data.0 = [42; 8]; -} - -// CHECK-LABEL: @repeat_packed_array2 -// CHECK: store i32 42, ptr %{{.+}}, align 2 -#[no_mangle] -pub fn repeat_packed_array2(p: &mut BigPacked2) { - p.data.0 = [42; 8]; -} - -#[repr(packed)] -#[derive(Copy, Clone)] -pub struct Packed1Pair(u8, u32); - -#[repr(packed(2))] -#[derive(Copy, Clone)] -pub struct Packed2Pair(u8, u32); - -// CHECK-LABEL: @pkd1_pair -#[no_mangle] -pub fn pkd1_pair(pair1: &mut Packed1Pair, pair2: &mut Packed1Pair) { - // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, i{{[0-9]+}} 5, i1 false) - *pair2 = *pair1; -} - -// CHECK-LABEL: @pkd2_pair -#[no_mangle] -pub fn pkd2_pair(pair1: &mut Packed2Pair, pair2: &mut Packed2Pair) { - // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 2 %{{.*}}, ptr align 2 %{{.*}}, i{{[0-9]+}} 6, i1 false) - *pair2 = *pair1; -} - -#[repr(packed)] -#[derive(Copy, Clone)] -pub struct Packed1NestedPair((u32, u32)); - -#[repr(packed(2))] -#[derive(Copy, Clone)] -pub struct Packed2NestedPair((u32, u32)); - -// CHECK-LABEL: @pkd1_nested_pair -#[no_mangle] -pub fn pkd1_nested_pair(pair1: &mut Packed1NestedPair, pair2: &mut Packed1NestedPair) { - // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 1 %{{.*}}, i{{[0-9]+}} 8, i1 false) - *pair2 = *pair1; -} - -// CHECK-LABEL: @pkd2_nested_pair -#[no_mangle] -pub fn pkd2_nested_pair(pair1: &mut Packed2NestedPair, pair2: &mut Packed2NestedPair) { - // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 2 %{{.*}}, ptr align 2 %{{.*}}, i{{[0-9]+}} 8, i1 false) - *pair2 = *pair1; -} diff --git a/tests/codegen/panic-abort-windows.rs b/tests/codegen/panic-abort-windows.rs deleted file mode 100644 index 17fdd9cc726..00000000000 --- a/tests/codegen/panic-abort-windows.rs +++ /dev/null @@ -1,16 +0,0 @@ -// This test is for *-windows only. -//@ only-windows - -//@ compile-flags: -C no-prepopulate-passes -C panic=abort -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK: Function Attrs: nounwind uwtable -// CHECK-NEXT: define void @normal_uwtable() -#[no_mangle] -pub fn normal_uwtable() {} - -// CHECK: Function Attrs: nounwind uwtable -// CHECK-NEXT: define void @extern_uwtable() -#[no_mangle] -pub extern "C" fn extern_uwtable() {} diff --git a/tests/codegen/panic-in-drop-abort.rs b/tests/codegen/panic-in-drop-abort.rs deleted file mode 100644 index e89170e56ed..00000000000 --- a/tests/codegen/panic-in-drop-abort.rs +++ /dev/null @@ -1,57 +0,0 @@ -//@ compile-flags: -Z panic-in-drop=abort -Copt-level=3 -//@ ignore-msvc - -// Ensure that unwinding code paths are eliminated from the output after -// optimization. - -// This test uses ignore-msvc, because the expected optimization does not happen on targets using -// SEH exceptions with the new LLVM pass manager anymore, see -// https://github.com/llvm/llvm-project/issues/51311. - -// CHECK-NOT: {{(call|invoke).*}}should_not_appear_in_output - -#![crate_type = "lib"] -use std::any::Any; -use std::mem::forget; - -pub struct ExternDrop; -impl Drop for ExternDrop { - #[inline(always)] - fn drop(&mut self) { - // This call may potentially unwind. - extern "Rust" { - fn extern_drop(); - } - unsafe { - extern_drop(); - } - } -} - -struct AssertNeverDrop; -impl Drop for AssertNeverDrop { - #[inline(always)] - fn drop(&mut self) { - // This call should be optimized away as unreachable. - extern "C" { - fn should_not_appear_in_output(); - } - unsafe { - should_not_appear_in_output(); - } - } -} - -#[no_mangle] -pub fn normal_drop(x: ExternDrop) { - let guard = AssertNeverDrop; - drop(x); - forget(guard); -} - -#[no_mangle] -pub fn indirect_drop(x: Box) { - let guard = AssertNeverDrop; - drop(x); - forget(guard); -} diff --git a/tests/codegen/panic-unwind-default-uwtable.rs b/tests/codegen/panic-unwind-default-uwtable.rs deleted file mode 100644 index 06f616c519b..00000000000 --- a/tests/codegen/panic-unwind-default-uwtable.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ compile-flags: -C panic=unwind -C no-prepopulate-passes -Copt-level=0 - -#![crate_type = "lib"] - -// CHECK: attributes #{{.*}} uwtable -pub fn foo() {} diff --git a/tests/codegen/patchable-function-entry/patchable-function-entry-both-flags.rs b/tests/codegen/patchable-function-entry/patchable-function-entry-both-flags.rs deleted file mode 100644 index 72204c78a49..00000000000 --- a/tests/codegen/patchable-function-entry/patchable-function-entry-both-flags.rs +++ /dev/null @@ -1,64 +0,0 @@ -//@ compile-flags: -Z patchable-function-entry=15,10 - -#![feature(patchable_function_entry)] -#![crate_type = "lib"] - -// This should have the default, as set by the compile flags -#[no_mangle] -pub fn fun0() {} - -// The attribute should override the compile flags -#[no_mangle] -#[patchable_function_entry(prefix_nops = 1, entry_nops = 2)] -pub fn fun1() {} - -// If we override an attribute to 0 or unset, the attribute should go away -#[no_mangle] -#[patchable_function_entry(entry_nops = 0)] -pub fn fun2() {} - -// The attribute should override the compile flags -#[no_mangle] -#[patchable_function_entry(prefix_nops = 20, entry_nops = 1)] -pub fn fun3() {} - -// The attribute should override the compile flags -#[no_mangle] -#[patchable_function_entry(prefix_nops = 2, entry_nops = 19)] -pub fn fun4() {} - -// The attribute should override patchable-function-entry to 3 and -// patchable-function-prefix to the default of 0, clearing it entirely -#[no_mangle] -#[patchable_function_entry(entry_nops = 3)] -pub fn fun5() {} - -// The attribute should override patchable-function-prefix to 4 -// and patchable-function-entry to the default of 0, clearing it entirely -#[no_mangle] -#[patchable_function_entry(prefix_nops = 4)] -pub fn fun6() {} - -// CHECK: @fun0() unnamed_addr #0 -// CHECK: @fun1() unnamed_addr #1 -// CHECK: @fun2() unnamed_addr #2 -// CHECK: @fun3() unnamed_addr #3 -// CHECK: @fun4() unnamed_addr #4 -// CHECK: @fun5() unnamed_addr #5 -// CHECK: @fun6() unnamed_addr #6 - -// CHECK: attributes #0 = { {{.*}}"patchable-function-entry"="5"{{.*}}"patchable-function-prefix"="10" {{.*}} } -// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} } - -// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-entry{{.*}} } -// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} } -// CHECK: attributes #2 = { {{.*}} } - -// CHECK: attributes #3 = { {{.*}}"patchable-function-entry"="1"{{.*}}"patchable-function-prefix"="20" {{.*}} } -// CHECK: attributes #4 = { {{.*}}"patchable-function-entry"="19"{{.*}}"patchable-function-prefix"="2" {{.*}} } - -// CHECK: attributes #5 = { {{.*}}"patchable-function-entry"="3"{{.*}} } -// CHECK-NOT: attributes #5 = { {{.*}}patchable-function-prefix{{.*}} } - -// CHECK: attributes #6 = { {{.*}}"patchable-function-prefix"="4"{{.*}} } -// CHECK-NOT: attributes #6 = { {{.*}}patchable-function-entry{{.*}} } diff --git a/tests/codegen/patchable-function-entry/patchable-function-entry-no-flag.rs b/tests/codegen/patchable-function-entry/patchable-function-entry-no-flag.rs deleted file mode 100644 index 3a7078fe551..00000000000 --- a/tests/codegen/patchable-function-entry/patchable-function-entry-no-flag.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![feature(patchable_function_entry)] -#![crate_type = "lib"] - -// No patchable function entry should be set -#[no_mangle] -pub fn fun0() {} - -// The attribute should work even without compiler flags -#[no_mangle] -#[patchable_function_entry(prefix_nops = 1, entry_nops = 2)] -pub fn fun1() {} - -// The attribute should work even without compiler flags -// and only set patchable-function-entry to 3. -#[no_mangle] -#[patchable_function_entry(entry_nops = 3)] -pub fn fun2() {} - -// The attribute should work even without compiler flags -// and only set patchable-function-prefix to 4. -#[no_mangle] -#[patchable_function_entry(prefix_nops = 4)] -pub fn fun3() {} - -// CHECK: @fun0() unnamed_addr #0 -// CHECK: @fun1() unnamed_addr #1 -// CHECK: @fun2() unnamed_addr #2 -// CHECK: @fun3() unnamed_addr #3 - -// CHECK-NOT: attributes #0 = { {{.*}}patchable-function-entry{{.*}} } -// CHECK-NOT: attributes #0 = { {{.*}}patchable-function-prefix{{.*}} } - -// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} } - -// CHECK: attributes #2 = { {{.*}}"patchable-function-entry"="3"{{.*}} } -// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} } - -// CHECK: attributes #3 = { {{.*}}"patchable-function-prefix"="4"{{.*}} } -// CHECK-NOT: attributes #3 = { {{.*}}patchable-function-entry{{.*}} } diff --git a/tests/codegen/patchable-function-entry/patchable-function-entry-one-flag.rs b/tests/codegen/patchable-function-entry/patchable-function-entry-one-flag.rs deleted file mode 100644 index 8bdd61e461b..00000000000 --- a/tests/codegen/patchable-function-entry/patchable-function-entry-one-flag.rs +++ /dev/null @@ -1,66 +0,0 @@ -//@ compile-flags: -Z patchable-function-entry=15 - -#![feature(patchable_function_entry)] -#![crate_type = "lib"] - -// This should have the default, as set by the compile flags -#[no_mangle] -pub fn fun0() {} - -// The attribute should override the compile flags -#[no_mangle] -#[patchable_function_entry(prefix_nops = 1, entry_nops = 2)] -pub fn fun1() {} - -// If we override an attribute to 0 or unset, the attribute should go away -#[no_mangle] -#[patchable_function_entry(entry_nops = 0)] -pub fn fun2() {} - -// The attribute should override the compile flags -#[no_mangle] -#[patchable_function_entry(prefix_nops = 20, entry_nops = 1)] -pub fn fun3() {} - -// The attribute should override the compile flags -#[no_mangle] -#[patchable_function_entry(prefix_nops = 2, entry_nops = 19)] -pub fn fun4() {} - -// The attribute should override patchable-function-entry to 3 -// and patchable-function-prefix to the default of 0, clearing it entirely -#[no_mangle] -#[patchable_function_entry(entry_nops = 3)] -pub fn fun5() {} - -// The attribute should override patchable-function-prefix to 4 -// and patchable-function-entry to the default of 0, clearing it entirely -#[no_mangle] -#[patchable_function_entry(prefix_nops = 4)] -pub fn fun6() {} - -// CHECK: @fun0() unnamed_addr #0 -// CHECK: @fun1() unnamed_addr #1 -// CHECK: @fun2() unnamed_addr #2 -// CHECK: @fun3() unnamed_addr #3 -// CHECK: @fun4() unnamed_addr #4 -// CHECK: @fun5() unnamed_addr #5 -// CHECK: @fun6() unnamed_addr #6 - -// CHECK: attributes #0 = { {{.*}}"patchable-function-entry"="15" {{.*}} } -// CHECK-NOT: attributes #0 = { {{.*}}patchable-function-prefix{{.*}} } - -// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} } - -// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-entry{{.*}} } -// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} } -// CHECK: attributes #2 = { {{.*}} } - -// CHECK: attributes #3 = { {{.*}}"patchable-function-entry"="1"{{.*}}"patchable-function-prefix"="20" {{.*}} } -// CHECK: attributes #4 = { {{.*}}"patchable-function-entry"="19"{{.*}}"patchable-function-prefix"="2" {{.*}} } - -// CHECK: attributes #5 = { {{.*}}"patchable-function-entry"="3"{{.*}} } -// CHECK-NOT: attributes #5 = { {{.*}}patchable-function-prefix{{.*}} } - -// CHECK: attributes #6 = { {{.*}}"patchable-function-prefix"="4"{{.*}} } -// CHECK-NOT: attributes #6 = { {{.*}}patchable-function-entry{{.*}} } diff --git a/tests/codegen/pattern_type_symbols.rs b/tests/codegen/pattern_type_symbols.rs deleted file mode 100644 index e86a9ef27de..00000000000 --- a/tests/codegen/pattern_type_symbols.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! Check that symbol names with pattern types in them are -//! different from the same symbol with the base type - -//@ compile-flags: -Csymbol-mangling-version=v0 -Copt-level=0 --crate-type=lib - -#![feature(pattern_types)] -#![feature(pattern_type_macro)] - -use std::pat::pattern_type; - -type NanoU32 = crate::pattern_type!(u32 is 0..=999_999_999); - -fn foo() {} - -pub fn bar() { - // CHECK: call pattern_type_symbols::foo:: - // CHECK: call void @_RINvC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_20pattern_type_symbols3foomEB2_ - foo::(); - // CHECK: call pattern_type_symbols::foo::<(u32, [(); 0], [(); 999999999])> - // CHECK: call void @_RINvC[[CRATE_IDENT]]_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_EEB2_ - foo::(); -} diff --git a/tests/codegen/personality_lifetimes.rs b/tests/codegen/personality_lifetimes.rs deleted file mode 100644 index cd81db63953..00000000000 --- a/tests/codegen/personality_lifetimes.rs +++ /dev/null @@ -1,32 +0,0 @@ -//@ ignore-msvc -//@ needs-unwind - -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes - -#![crate_type = "lib"] - -struct S; - -impl Drop for S { - #[inline(never)] - fn drop(&mut self) {} -} - -#[inline(never)] -fn might_unwind() {} - -// CHECK-LABEL: @test -#[no_mangle] -pub fn test() { - let _s = S; - // Check that the personality slot alloca gets a lifetime start in each cleanup block, not just - // in the first one. - // CHECK: [[SLOT:%[0-9]+]] = alloca [{{[0-9]+}} x i8] - // CHECK-LABEL: cleanup: - // CHECK: call void @llvm.lifetime.start.{{.*}}({{.*}}) - // CHECK-LABEL: cleanup1: - // CHECK: call void @llvm.lifetime.start.{{.*}}({{.*}}) - might_unwind(); - let _t = S; - might_unwind(); -} diff --git a/tests/codegen/pgo-counter-bias.rs b/tests/codegen/pgo-counter-bias.rs deleted file mode 100644 index 48e815dda04..00000000000 --- a/tests/codegen/pgo-counter-bias.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Test that __llvm_profile_counter_bias does not get internalized by lto. - -//@ ignore-apple -runtime-counter-relocation not honored on Mach-O -//@ compile-flags: -Cprofile-generate -Cllvm-args=-runtime-counter-relocation -Clto=fat -//@ compile-flags: -Zno-profiler-runtime -//@ no-prefer-dynamic - -// CHECK: @__llvm_profile_counter_bias = {{.*}}global - -pub fn main() {} diff --git a/tests/codegen/pgo-instrumentation.rs b/tests/codegen/pgo-instrumentation.rs deleted file mode 100644 index a8f12ccce1c..00000000000 --- a/tests/codegen/pgo-instrumentation.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that `-Cprofile-generate` creates expected instrumentation artifacts in LLVM IR. - -//@ compile-flags: -Zno-profiler-runtime -//@ compile-flags: -Cprofile-generate -Ccodegen-units=1 - -// CHECK: @__llvm_profile_raw_version = -// CHECK-DAG: @__profc_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = {{.*}}global -// CHECK-DAG: @__profd_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = {{.*}}global -// CHECK-DAG: @__profc_{{.*}}pgo_instrumentation{{.*}}some_other_function{{.*}} = {{.*}}global -// CHECK-DAG: @__profd_{{.*}}pgo_instrumentation{{.*}}some_other_function{{.*}} = {{.*}}global -// CHECK: @__llvm_profile_filename = {{.*}}"default_%m.profraw\00"{{.*}} - -#![crate_type = "lib"] - -#[inline(never)] -fn some_function() {} - -pub fn some_other_function() { - some_function(); -} diff --git a/tests/codegen/pic-relocation-model.rs b/tests/codegen/pic-relocation-model.rs deleted file mode 100644 index a1d1678a6bd..00000000000 --- a/tests/codegen/pic-relocation-model.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ compile-flags: -C relocation-model=pic -Copt-level=0 - -#![crate_type = "rlib"] - -// CHECK: define i8 @call_foreign_fn() -#[no_mangle] -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() -extern "C" { - fn foreign_fn() -> u8; -} - -// CHECK: !{i32 {{[78]}}, !"PIC Level", i32 2} diff --git a/tests/codegen/pie-relocation-model.rs b/tests/codegen/pie-relocation-model.rs deleted file mode 100644 index cb8de91ccd7..00000000000 --- a/tests/codegen/pie-relocation-model.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ compile-flags: -C relocation-model=pie -Copt-level=0 -//@ only-x86_64-unknown-linux-gnu - -#![crate_type = "rlib"] - -// With PIE we know local functions cannot be interpositioned, we can mark them -// as dso_local. -// CHECK: define dso_local i8 @call_foreign_fn() -#[no_mangle] -pub fn call_foreign_fn() -> u8 { - unsafe { foreign_fn() } -} - -// 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 i8 @foreign_fn() -extern "C" { - fn foreign_fn() -> u8; -} - -// CHECK: !{i32 {{[78]}}, !"PIC Level", i32 2} -// CHECK: !{i32 7, !"PIE Level", i32 2} diff --git a/tests/codegen/placement-new.rs b/tests/codegen/placement-new.rs deleted file mode 100644 index 7f7f0033bec..00000000000 --- a/tests/codegen/placement-new.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ compile-flags: -Zmerge-functions=disabled -#![crate_type = "lib"] - -// Test to check that types with "complex" destructors, but trivial `Default` impls -// are constructed directly into the allocation in `Box::default` and `Arc::default`. - -use std::rc::Rc; -use std::sync::Arc; - -// CHECK-LABEL: @box_default_inplace -#[no_mangle] -pub fn box_default_inplace() -> Box<(String, String)> { - // CHECK-NOT: alloca - // CHECK: [[BOX:%.*]] = {{.*}}call {{.*}}__rust_alloc( - // CHECK-NOT: call void @llvm.memcpy - // CHECK: ret ptr [[BOX]] - Box::default() -} - -// CHECK-LABEL: @rc_default_inplace -#[no_mangle] -pub fn rc_default_inplace() -> Rc<(String, String)> { - // CHECK-NOT: alloca - // CHECK: [[RC:%.*]] = {{.*}}call {{.*}}__rust_alloc( - // CHECK-NOT: call void @llvm.memcpy - // CHECK: ret ptr [[RC]] - Rc::default() -} - -// CHECK-LABEL: @arc_default_inplace -#[no_mangle] -pub fn arc_default_inplace() -> Arc<(String, String)> { - // CHECK-NOT: alloca - // CHECK: [[ARC:%.*]] = {{.*}}call {{.*}}__rust_alloc( - // CHECK-NOT: call void @llvm.memcpy - // CHECK: ret ptr [[ARC]] - Arc::default() -} diff --git a/tests/codegen/powerpc64le-struct-align-128.rs b/tests/codegen/powerpc64le-struct-align-128.rs deleted file mode 100644 index c1c1ac26485..00000000000 --- a/tests/codegen/powerpc64le-struct-align-128.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Test that structs aligned to 128 bits are passed with the correct ABI on powerpc64le. -// This is similar to aarch64-struct-align-128.rs, but for ppc. - -//@ add-core-stubs -//@ compile-flags: --target powerpc64le-unknown-linux-gnu -//@ needs-llvm-components: powerpc - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[repr(C)] -pub struct Align8 { - pub a: u64, - pub b: u64, -} - -#[repr(transparent)] -pub struct Transparent8 { - a: Align8, -} - -#[repr(C)] -pub struct Wrapped8 { - a: Align8, -} - -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); -} - -#[repr(C)] -#[repr(align(16))] -pub struct Align16 { - pub a: u64, - pub b: u64, -} - -#[repr(transparent)] -pub struct Transparent16 { - a: Align16, -} - -#[repr(C)] -pub struct Wrapped16 { - pub a: Align16, -} - -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); -} - -#[repr(C)] -#[repr(align(32))] -pub struct Align32 { - pub a: u64, - pub b: u64, - pub c: u64, -} - -#[repr(transparent)] -pub struct Transparent32 { - a: Align32, -} - -#[repr(C)] -pub struct Wrapped32 { - pub a: Align32, -} - -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); -} - -pub unsafe fn main( - a1: Align8, - a2: Transparent8, - a3: Wrapped8, - b1: Align16, - b2: Transparent16, - b3: Wrapped16, - c1: Align32, - c2: Transparent32, - c3: Wrapped32, -) { - test_8(a1, a2, a3); - test_16(b1, b2, b3); - test_32(c1, c2, c3); -} diff --git a/tests/codegen/precondition-checks.rs b/tests/codegen/precondition-checks.rs deleted file mode 100644 index 16812ca1720..00000000000 --- a/tests/codegen/precondition-checks.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 -Cdebug-assertions=no - -// This test ensures that in a debug build which turns off debug assertions, we do not monomorphize -// any of the standard library's unsafe precondition checks. -// The naive codegen of those checks contains the actual check underneath an `if false`, which -// could be optimized out if optimizations are enabled. But if we rely on optimizations to remove -// panic branches, then we can't link compiler_builtins without optimizing it, which means that -// -Zbuild-std doesn't work with -Copt-level=0. -// -// In other words, this tests for a mandatory optimization. - -#![crate_type = "lib"] - -use std::ptr::NonNull; - -// CHECK-LABEL: ; core::ptr::non_null::NonNull::new_unchecked -// CHECK-NOT: call -// CHECK: } - -// CHECK-LABEL: @nonnull_new -#[no_mangle] -pub unsafe fn nonnull_new(ptr: *mut u8) -> NonNull { - // CHECK: ; call core::ptr::non_null::NonNull::new_unchecked - unsafe { NonNull::new_unchecked(ptr) } -} diff --git a/tests/codegen/ptr-arithmetic.rs b/tests/codegen/ptr-arithmetic.rs deleted file mode 100644 index fc4441ef448..00000000000 --- a/tests/codegen/ptr-arithmetic.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled - -#![crate_type = "lib"] - -// CHECK-LABEL: ptr @i32_add( -// CHECK-SAME: [[WORD:i[0-9]+]] noundef %n) -#[no_mangle] -pub unsafe fn i32_add(p: *const i32, n: usize) -> *const i32 { - // CHECK: %[[TEMP:.+]] = getelementptr inbounds{{( nuw)?}} i32, ptr %p, [[WORD]] %n - // CHECK: ret ptr %[[TEMP]] - p.add(n) -} - -// Ensure we tell LLVM that the negation in `sub` can't overflow. - -// CHECK-LABEL: ptr @i32_sub( -// CHECK-SAME: [[WORD:i[0-9]+]] noundef %n) -#[no_mangle] -pub unsafe fn i32_sub(p: *const i32, n: usize) -> *const i32 { - // CHECK: %[[DELTA:.+]] = sub nsw [[WORD]] 0, %n - // CHECK: %[[TEMP:.+]] = getelementptr inbounds i32, ptr %p, [[WORD]] %[[DELTA]] - // CHECK: ret ptr %[[TEMP]] - p.sub(n) -} - -// CHECK-LABEL: ptr @i32_offset( -// CHECK-SAME: [[WORD:i[0-9]+]] noundef %d) -#[no_mangle] -pub unsafe fn i32_offset(p: *const i32, d: isize) -> *const i32 { - // CHECK: %[[TEMP:.+]] = getelementptr inbounds i32, ptr %p, [[WORD]] %d - // CHECK: ret ptr %[[TEMP]] - p.offset(d) -} diff --git a/tests/codegen/ptr-read-metadata.rs b/tests/codegen/ptr-read-metadata.rs deleted file mode 100644 index b38cfdbff88..00000000000 --- a/tests/codegen/ptr-read-metadata.rs +++ /dev/null @@ -1,94 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled - -#![crate_type = "lib"] - -// Ensure that various forms of reading pointers correctly annotate the `load`s -// with `!noundef` and `!range` metadata to enable extra optimization. - -use std::mem::MaybeUninit; - -// CHECK-LABEL: define {{(dso_local )?}}noundef i8 @copy_byte( -#[no_mangle] -pub unsafe fn copy_byte(p: *const u8) -> u8 { - // CHECK-NOT: load - // CHECK: load i8, ptr %p, align 1 - // CHECK-SAME: !noundef ! - // CHECK-NOT: load - *p -} - -// CHECK-LABEL: define {{(dso_local )?}}noundef i8 @read_byte( -#[no_mangle] -pub unsafe fn read_byte(p: *const u8) -> u8 { - // CHECK-NOT: load - // CHECK: load i8, ptr %p, align 1 - // CHECK-SAME: !noundef ! - // CHECK-NOT: load - p.read() -} - -// CHECK-LABEL: define {{(dso_local )?}}i8 @read_byte_maybe_uninit( -#[no_mangle] -pub unsafe fn read_byte_maybe_uninit(p: *const MaybeUninit) -> MaybeUninit { - // CHECK-NOT: load - // CHECK: load i8, ptr %p, align 1 - // CHECK-NOT: noundef - // CHECK-NOT: load - p.read() -} - -// CHECK-LABEL: define {{(dso_local )?}}noundef i8 @read_byte_assume_init( -#[no_mangle] -pub unsafe fn read_byte_assume_init(p: &MaybeUninit) -> u8 { - // CHECK-NOT: load - // CHECK: load i8, ptr %p, align 1 - // CHECK-SAME: !noundef ! - // CHECK-NOT: load - p.assume_init_read() -} - -// CHECK-LABEL: define {{(dso_local )?}}noundef {{(range\(.*\) )?}}i32 @copy_char( -#[no_mangle] -pub unsafe fn copy_char(p: *const char) -> char { - // CHECK-NOT: load - // CHECK: load i32, ptr %p - // CHECK-SAME: !range ![[RANGE:[0-9]+]] - // CHECK-SAME: !noundef ! - // CHECK-NOT: load - *p -} - -// CHECK-LABEL: define {{(dso_local )?}}noundef {{(range\(.*\) )?}}i32 @read_char( -#[no_mangle] -pub unsafe fn read_char(p: *const char) -> char { - // CHECK-NOT: load - // CHECK: load i32, ptr %p - // CHECK-SAME: !range ![[RANGE]] - // CHECK-SAME: !noundef ! - // CHECK-NOT: load - p.read() -} - -// CHECK-LABEL: define {{(dso_local )?}}i32 @read_char_maybe_uninit( -#[no_mangle] -pub unsafe fn read_char_maybe_uninit(p: *const MaybeUninit) -> MaybeUninit { - // CHECK-NOT: load - // CHECK: load i32, ptr %p - // CHECK-NOT: range - // CHECK-NOT: noundef - // CHECK-NOT: load - p.read() -} - -// CHECK-LABEL: define {{(dso_local )?}}noundef {{(range\(.*\) )?}}i32 @read_char_assume_init( -#[no_mangle] -pub unsafe fn read_char_assume_init(p: &MaybeUninit) -> char { - // CHECK-NOT: load - // CHECK: load i32, ptr %p - // CHECK-SAME: !range ![[RANGE]] - // CHECK-SAME: !noundef ! - // CHECK-NOT: load - p.assume_init_read() -} - -// CHECK: ![[RANGE]] = !{i32 0, i32 1114112} diff --git a/tests/codegen/range-attribute.rs b/tests/codegen/range-attribute.rs deleted file mode 100644 index b81ff9ab3e2..00000000000 --- a/tests/codegen/range-attribute.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Checks that range metadata gets emitted on functions result and arguments -// with scalar value. - -// 32-bit systems will return 128bit values using a return area pointer. -//@ revisions: bit32 bit64 -//@[bit32] only-32bit -//@[bit64] only-64bit -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes - -#![crate_type = "lib"] - -use std::num::NonZero; - -// Hack to get the correct size for usize -// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1) -#[no_mangle] -pub fn helper(_: usize) {} - -// bit32: void @nonzero_int({{.*}} sret([16 x i8]) {{.*}}, i128 noundef range(i128 1, 0) %x) -// bit64: noundef range(i128 1, 0) i128 @nonzero_int(i128 noundef range(i128 1, 0) %x) -#[no_mangle] -pub fn nonzero_int(x: NonZero) -> NonZero { - x -} - -// CHECK: noundef range(i8 0, 3) i8 @optional_bool(i8{{.*}} range(i8 0, 3) %x) -#[no_mangle] -pub fn optional_bool(x: Option) -> Option { - x -} - -pub enum Enum0 { - A(bool), - B, - C, -} - -// CHECK: noundef range(i8 0, 4) i8 @enum0_value(i8{{.*}} range(i8 0, 4) %x) -#[no_mangle] -pub fn enum0_value(x: Enum0) -> Enum0 { - x -} - -pub enum Enum1 { - A(u64), - B(u64), - C(u64), -} - -// bit32: void @enum1_value({{.*}} sret({{[^,]*}}) {{[^,]*}}, [[ENUM1_TYP:i[0-9]+]] -// bit64: { [[ENUM1_TYP:i[0-9]+]], i64 } @enum1_value([[ENUM1_TYP]] -// CHECK-SAME: noundef range([[ENUM1_TYP]] 0, 3) %x.0, i64 noundef %x.1) -#[no_mangle] -pub fn enum1_value(x: Enum1) -> Enum1 { - x -} - -pub enum Enum2 { - A(Enum0), - B(Enum0), - C(Enum0), -} - -// CHECK: { i8, i8 } @enum2_value(i8 noundef range(i8 0, 3) %x.0, i8 noundef %x.1) -#[no_mangle] -pub fn enum2_value(x: Enum2) -> Enum2 { - x -} - -// CHECK: noundef [[USIZE]] @takes_slice(ptr noalias noundef nonnull readonly align 4 %x.0, [[USIZE]] noundef %x.1) -#[no_mangle] -pub fn takes_slice(x: &[i32]) -> usize { - x.len() -} diff --git a/tests/codegen/range-loop.rs b/tests/codegen/range-loop.rs deleted file mode 100644 index b131beb40dd..00000000000 --- a/tests/codegen/range-loop.rs +++ /dev/null @@ -1,44 +0,0 @@ -//@ ignore-std-debug-assertions -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes - -#![crate_type = "lib"] - -// Ensure that MIR optimizations have cleaned things up enough that the IR we -// emit is good even without running the LLVM optimizations. - -// CHECK-NOT: define - -// CHECK-LABEL: define{{.+}}void @call_for_zero_to_n -#[no_mangle] -pub fn call_for_zero_to_n(n: u32, f: fn(u32)) { - // CHECK: start: - // CHECK-NOT: alloca - // CHECK: %[[IND:.+]] = alloca [4 x i8] - // CHECK-NEXT: %[[ALWAYS_SOME_OPTION:.+]] = alloca - // CHECK-NOT: alloca - // CHECK: store i32 0, ptr %[[IND]], - // CHECK: br label %[[HEAD:.+]] - - // CHECK: [[HEAD]]: - // CHECK: %[[T1:.+]] = load i32, ptr %[[IND]], - // CHECK: %[[NOT_DONE:.+]] = icmp ult i32 %[[T1]], %n - // CHECK: br i1 %[[NOT_DONE]], label %[[BODY:.+]], label %[[BREAK:.+]] - - // CHECK: [[BREAK]]: - // CHECK: ret void - - // CHECK: [[BODY]]: - // CHECK: %[[T2:.+]] = load i32, ptr %[[IND]], - // CHECK: %[[T3:.+]] = add nuw i32 %[[T2]], 1 - // CHECK: store i32 %[[T3]], ptr %[[IND]], - - // CHECK: store i32 %[[T2]] - // CHECK: %[[T4:.+]] = load i32 - // CHECK: call void %f(i32{{.+}}%[[T4]]) - - for i in 0..n { - f(i); - } -} - -// CHECK-NOT: define diff --git a/tests/codegen/range_to_inclusive.rs b/tests/codegen/range_to_inclusive.rs deleted file mode 100644 index 6d939f40f55..00000000000 --- a/tests/codegen/range_to_inclusive.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! Test that `RangeTo` and `RangeToInclusive` generate identical -//! (and optimal) code; #63646 -//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled -#![crate_type = "lib"] - -#[no_mangle] -// CHECK-LABEL: range_to( -pub fn range_to(a: i32, mut b: i32) -> i32 { - // CHECK: %1 = and i32 %0, %a - // CHECK-NEXT: ret i32 %1 - for _ in 0..65 { - b &= a; - } - - b -} - -#[no_mangle] -// CHECK-LABEL: range_to_inclusive( -pub fn range_to_inclusive(a: i32, mut b: i32) -> i32 { - // CHECK: %1 = and i32 %0, %a - // CHECK-NEXT: ret i32 %1 - for _ in 0..=64 { - b &= a; - } - - b -} diff --git a/tests/codegen/refs.rs b/tests/codegen/refs.rs deleted file mode 100644 index 97c36295085..00000000000 --- a/tests/codegen/refs.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 -Copt-level=0 - -#![crate_type = "lib"] - -// Hack to get the correct size for the length part in slices -// CHECK: @helper([[USIZE:i[0-9]+]] %_1) -#[no_mangle] -pub fn helper(_: usize) {} - -// CHECK-LABEL: @ref_dst -#[no_mangle] -pub fn ref_dst(s: &[u8]) { - // We used to generate an extra alloca and memcpy to ref the dst, so check that we copy - // directly to the alloca for "x" - // CHECK: store ptr %s.0, {{.*}} %x - // CHECK: [[X1:%[0-9]+]] = getelementptr inbounds i8, {{.*}} %x, {{i32 4|i64 8}} - // CHECK: store [[USIZE]] %s.1, {{.*}} [[X1]] - - let x = &*s; - &x; // keep variable in an alloca -} diff --git a/tests/codegen/reg-struct-return.rs b/tests/codegen/reg-struct-return.rs deleted file mode 100644 index dfc9f8c519c..00000000000 --- a/tests/codegen/reg-struct-return.rs +++ /dev/null @@ -1,206 +0,0 @@ -// Checks how `reg-struct-return` flag works with different calling conventions: -// Return struct with 8/16/32/64 bit size will be converted into i8/i16/i32/i64 -// (like abi_return_struct_as_int target spec). -// x86 only. - -//@ revisions: ENABLED DISABLED -//@ add-core-stubs -//@ compile-flags: --target i686-unknown-linux-gnu -Cno-prepopulate-passes -Copt-level=3 -//@ [ENABLED] compile-flags: -Zreg-struct-return -//@ needs-llvm-components: x86 - -#![crate_type = "lib"] -#![no_std] -#![no_core] -#![feature(no_core, lang_items)] - -extern crate minicore; -use minicore::*; - -#[repr(C)] -pub struct Foo { - x: u32, - y: u32, -} - -#[repr(C)] -pub struct Foo1 { - x: u32, -} - -#[repr(C)] -pub struct Foo2 { - x: bool, - y: bool, - z: i16, -} - -#[repr(C)] -pub struct Foo3 { - x: i16, - y: bool, - z: bool, -} - -#[repr(C)] -pub struct Foo4 { - x: char, - y: bool, - z: u8, -} - -#[repr(C)] -pub struct Foo5 { - x: u32, - y: u16, - z: u8, - a: bool, -} - -#[repr(C)] -pub struct FooOversize1 { - x: u32, - y: u32, - z: u32, -} - -#[repr(C)] -pub struct FooOversize2 { - f0: u16, - f1: u16, - f2: u16, - f3: u16, - f4: u16, -} - -#[repr(C)] -pub struct FooFloat1 { - x: f32, - y: f32, -} - -#[repr(C)] -pub struct FooFloat2 { - x: f64, -} - -#[repr(C)] -pub struct FooFloat3 { - x: f32, -} - -pub mod tests { - use { - Foo, Foo1, Foo2, Foo3, Foo4, Foo5, FooFloat1, FooFloat2, FooFloat3, FooOversize1, - FooOversize2, - }; - - // ENABLED: i64 @f1() - // DISABLED: void @f1(ptr {{.*}}sret - #[no_mangle] - pub extern "fastcall" fn f1() -> Foo { - Foo { x: 1, y: 2 } - } - - // CHECK: { i32, i32 } @f2() - #[no_mangle] - pub extern "Rust" fn f2() -> Foo { - Foo { x: 1, y: 2 } - } - - // ENABLED: i64 @f3() - // DISABLED: void @f3(ptr {{.*}}sret - #[no_mangle] - pub extern "C" fn f3() -> Foo { - Foo { x: 1, y: 2 } - } - - // ENABLED: i64 @f4() - // DISABLED: void @f4(ptr {{.*}}sret - #[no_mangle] - pub extern "cdecl" fn f4() -> Foo { - Foo { x: 1, y: 2 } - } - - // ENABLED: i64 @f5() - // DISABLED: void @f5(ptr {{.*}}sret - #[no_mangle] - pub extern "stdcall" fn f5() -> Foo { - Foo { x: 1, y: 2 } - } - - // ENABLED: i64 @f6() - // DISABLED: void @f6(ptr {{.*}}sret - #[no_mangle] - pub extern "thiscall" fn f6() -> Foo { - Foo { x: 1, y: 2 } - } - - // ENABLED: i32 @f7() - // DISABLED: void @f7(ptr {{.*}}sret - #[no_mangle] - pub extern "C" fn f7() -> Foo1 { - Foo1 { x: 1 } - } - - // ENABLED: i32 @f8() - // DISABLED: void @f8(ptr {{.*}}sret - #[no_mangle] - pub extern "C" fn f8() -> Foo2 { - Foo2 { x: true, y: false, z: 5 } - } - - // ENABLED: i32 @f9() - // DISABLED: void @f9(ptr {{.*}}sret - #[no_mangle] - pub extern "C" fn f9() -> Foo3 { - Foo3 { x: 5, y: false, z: true } - } - - // ENABLED: i64 @f10() - // DISABLED: void @f10(ptr {{.*}}sret - #[no_mangle] - pub extern "C" fn f10() -> Foo4 { - Foo4 { x: 'x', y: true, z: 170 } - } - - // ENABLED: i64 @f11() - // DISABLED: void @f11(ptr {{.*}}sret - #[no_mangle] - pub extern "C" fn f11() -> Foo5 { - Foo5 { x: 1, y: 2, z: 3, a: true } - } - - // CHECK: void @f12(ptr {{.*}}sret - #[no_mangle] - pub extern "C" fn f12() -> FooOversize1 { - FooOversize1 { x: 1, y: 2, z: 3 } - } - - // CHECK: void @f13(ptr {{.*}}sret - #[no_mangle] - pub extern "C" fn f13() -> FooOversize2 { - FooOversize2 { f0: 1, f1: 2, f2: 3, f3: 4, f4: 5 } - } - - // ENABLED: i64 @f14() - // DISABLED: void @f14(ptr {{.*}}sret - #[no_mangle] - pub extern "C" fn f14() -> FooFloat1 { - FooFloat1 { x: 1.0, y: 1.0 } - } - - // ENABLED: double @f15() - // DISABLED: void @f15(ptr {{.*}}sret - #[no_mangle] - pub extern "C" fn f15() -> FooFloat2 { - FooFloat2 { x: 1.0 } - } - - // ENABLED: float @f16() - // DISABLED: void @f16(ptr {{.*}}sret - #[no_mangle] - pub extern "C" fn f16() -> FooFloat3 { - FooFloat3 { x: 1.0 } - } -} diff --git a/tests/codegen/regparm-inreg.rs b/tests/codegen/regparm-inreg.rs deleted file mode 100644 index 15702804dfd..00000000000 --- a/tests/codegen/regparm-inreg.rs +++ /dev/null @@ -1,125 +0,0 @@ -// Checks how `regparm` flag works with different calling conventions: -// marks function arguments as "inreg" like the C/C++ compilers for the platforms. -// x86 only. - -//@ add-core-stubs -//@ compile-flags: --target i686-unknown-linux-gnu -Cno-prepopulate-passes -Copt-level=3 -Ctarget-feature=+avx -//@ needs-llvm-components: x86 - -//@ revisions:regparm0 regparm1 regparm2 regparm3 -//@[regparm0] compile-flags: -Zregparm=0 -//@[regparm1] compile-flags: -Zregparm=1 -//@[regparm2] compile-flags: -Zregparm=2 -//@[regparm3] compile-flags: -Zregparm=3 - -#![crate_type = "lib"] -#![no_core] -#![feature(no_core, lang_items, repr_simd)] - -extern crate minicore; -use minicore::*; - -pub mod tests { - // regparm doesn't work for "fastcall" calling conv (only 2 inregs) - // CHECK: @f1(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) - #[no_mangle] - pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {} - - // regparm0: @f3(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) - // regparm1: @f3(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3) - // regparm2: @f3(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) - // regparm3: @f3(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) - #[no_mangle] - pub extern "C" fn f3(_: i32, _: i32, _: i32) {} - - // regparm0: @f4(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) - // regparm1: @f4(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3) - // regparm2: @f4(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) - // regparm3: @f4(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) - #[no_mangle] - pub extern "cdecl" fn f4(_: i32, _: i32, _: i32) {} - - // regparm0: @f5(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) - // regparm1: @f5(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3) - // regparm2: @f5(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) - // regparm3: @f5(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) - #[no_mangle] - pub extern "stdcall" fn f5(_: i32, _: i32, _: i32) {} - - // regparm doesn't work for thiscall - // CHECK: @f6(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) - #[no_mangle] - pub extern "thiscall" fn f6(_: i32, _: i32, _: i32) {} - - struct S1 { - x1: i32, - } - // regparm0: @f7(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3, i32 noundef %_4) - // regparm1: @f7(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3, i32 noundef %_4) - // regparm2: @f7(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3, i32 noundef %_4) - // regparm3: @f7(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3, - // regparm3-SAME: i32 noundef %_4) - #[no_mangle] - pub extern "C" fn f7(_: i32, _: i32, _: S1, _: i32) {} - - #[repr(C)] - struct S2 { - x1: i32, - x2: i32, - } - // regparm0: @f8(i32 noundef %_1, i32 noundef %_2, ptr {{.*}} %_3, i32 noundef %_4) - // regparm1: @f8(i32 inreg noundef %_1, i32 noundef %_2, ptr {{.*}} %_3, i32 noundef %_4) - // regparm2: @f8(i32 inreg noundef %_1, i32 inreg noundef %_2, ptr {{.*}} %_3, i32 noundef %_4) - // regparm3: @f8(i32 inreg noundef %_1, i32 inreg noundef %_2, ptr {{.*}} %_3, - // regparm3-SAME: i32 inreg noundef %_4) - #[no_mangle] - pub extern "C" fn f8(_: i32, _: i32, _: S2, _: i32) {} - - // regparm0: @f9(i1 noundef zeroext %_1, i16 noundef signext %_2, i64 noundef %_3, - // regparm0-SAME: i128 noundef %_4) - // regparm1: @f9(i1 inreg noundef zeroext %_1, i16 noundef signext %_2, i64 noundef %_3, - // regparm1-SAME: i128 noundef %_4) - // regparm2: @f9(i1 inreg noundef zeroext %_1, i16 inreg noundef signext %_2, i64 noundef %_3, - // regparm2-SAME: i128 noundef %_4) - // regparm3: @f9(i1 inreg noundef zeroext %_1, i16 inreg noundef signext %_2, i64 noundef %_3, - // regparm3-SAME: i128 noundef %_4) - #[no_mangle] - pub extern "C" fn f9(_: bool, _: i16, _: i64, _: u128) {} - - // regparm0: @f10(float noundef %_1, double noundef %_2, i1 noundef zeroext %_3, - // regparm0-SAME: i16 noundef signext %_4) - // regparm1: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3, - // regparm1-SAME: i16 noundef signext %_4) - // regparm2: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3, - // regparm2-SAME: i16 inreg noundef signext %_4) - // regparm3: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3, - // regparm3-SAME: i16 inreg noundef signext %_4) - #[no_mangle] - pub extern "C" fn f10(_: f32, _: f64, _: bool, _: i16) {} - - #[allow(non_camel_case_types)] - #[repr(simd)] - pub struct __m128([f32; 4]); - - // regparm0: @f11(i32 noundef %_1, <4 x float> %_2, i32 noundef %_3, i32 noundef %_4) - // regparm1: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 noundef %_3, i32 noundef %_4) - // regparm2: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 inreg noundef %_3, - // regparm2-SAME: i32 noundef %_4) - // regparm3: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 inreg noundef %_3, - // regparm3-SAME: i32 inreg noundef %_4) - #[no_mangle] - pub extern "C" fn f11(_: i32, _: __m128, _: i32, _: i32) {} - - #[allow(non_camel_case_types)] - #[repr(simd)] - pub struct __m256([f32; 8]); - - // regparm0: @f12(i32 noundef %_1, <8 x float> %_2, i32 noundef %_3, i32 noundef %_4) - // regparm1: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 noundef %_3, i32 noundef %_4) - // regparm2: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 inreg noundef %_3, - // regparm2-SAME: i32 noundef %_4) - // regparm3: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 inreg noundef %_3, - // regparm3-SAME: i32 inreg noundef %_4) - #[no_mangle] - pub extern "C" fn f12(_: i32, _: __m256, _: i32, _: i32) {} -} diff --git a/tests/codegen/remap_path_prefix/aux_mod.rs b/tests/codegen/remap_path_prefix/aux_mod.rs deleted file mode 100644 index 3217e9e51e7..00000000000 --- a/tests/codegen/remap_path_prefix/aux_mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ ignore-auxiliary (used by `./main.rs`) - -#[inline] -pub fn some_aux_mod_function() -> i32 { - 1234 -} diff --git a/tests/codegen/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs b/tests/codegen/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs deleted file mode 100644 index 7afc16ec72f..00000000000 --- a/tests/codegen/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs +++ /dev/null @@ -1,8 +0,0 @@ -// - -//@ compile-flags: -g --remap-path-prefix={{cwd}}=/the/aux-cwd --remap-path-prefix={{src-base}}/remap_path_prefix/auxiliary=/the/aux-src - -#[inline] -pub fn some_aux_function() -> i32 { - 1234 -} diff --git a/tests/codegen/remap_path_prefix/auxiliary/xcrate-generic.rs b/tests/codegen/remap_path_prefix/auxiliary/xcrate-generic.rs deleted file mode 100644 index 9d5cdfe063b..00000000000 --- a/tests/codegen/remap_path_prefix/auxiliary/xcrate-generic.rs +++ /dev/null @@ -1,8 +0,0 @@ -// -//@ compile-flags: -g --remap-path-prefix={{cwd}}=/the/aux-cwd --remap-path-prefix={{src-base}}/remap_path_prefix/auxiliary=/the/aux-src - -#![crate_type = "lib"] - -pub fn foo() -> T { - T::default() -} diff --git a/tests/codegen/remap_path_prefix/issue-73167-remap-std.rs b/tests/codegen/remap_path_prefix/issue-73167-remap-std.rs deleted file mode 100644 index eb610168dd3..00000000000 --- a/tests/codegen/remap_path_prefix/issue-73167-remap-std.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ ignore-windows - -//@ compile-flags: -g -C no-prepopulate-passes -Z simulate-remapped-rust-src-base=/rustc/xyz - -// Here we check that importing std will not cause real path to std source files -// to leak. If rustc was compiled with remap-debuginfo = true, this should be -// true automatically. If paths to std library hasn't been remapped, we use the -// above simulate-remapped-rust-src-base option to do it temporarily - -// CHECK: !DIFile(filename: "{{/rustc/.*/library/std/src/panic.rs}}" -fn main() { - std::thread::spawn(|| { - println!("hello"); - }); -} diff --git a/tests/codegen/remap_path_prefix/main.rs b/tests/codegen/remap_path_prefix/main.rs deleted file mode 100644 index 7d17b3b67cf..00000000000 --- a/tests/codegen/remap_path_prefix/main.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ ignore-windows -// - -//@ compile-flags: -g -C no-prepopulate-passes --remap-path-prefix={{cwd}}=/the/cwd --remap-path-prefix={{src-base}}=/the/src -Zinline-mir=no -//@ aux-build:remap_path_prefix_aux.rs - -extern crate remap_path_prefix_aux; - -// Here we check that submodules and include files are found using the path without -// remapping. This test requires that rustc is called with an absolute path. -mod aux_mod; -include!("aux_mod.rs"); - -// Here we check that the expansion of the file!() macro is mapped. -// CHECK: @alloc_5761061597a97f66e13ef2ff92712c4b = private unnamed_addr constant [34 x i8] c"/the/src/remap_path_prefix/main.rs" -pub static FILE_PATH: &'static str = file!(); - -fn main() { - remap_path_prefix_aux::some_aux_function(); - aux_mod::some_aux_mod_function(); - some_aux_mod_function(); -} - -// Here we check that local debuginfo is mapped correctly. -// CHECK: !DIFile(filename: "/the/src/remap_path_prefix/main.rs", directory: "" - -// And here that debuginfo from other crates are expanded to absolute paths. -// CHECK: !DIFile(filename: "/the/aux-src/remap_path_prefix_aux.rs", directory: "" diff --git a/tests/codegen/remap_path_prefix/xcrate-generic.rs b/tests/codegen/remap_path_prefix/xcrate-generic.rs deleted file mode 100644 index db69b72d904..00000000000 --- a/tests/codegen/remap_path_prefix/xcrate-generic.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ ignore-windows -//@ compile-flags: -g -C metadata=foo -C no-prepopulate-passes -//@ aux-build:xcrate-generic.rs - -#![crate_type = "lib"] - -extern crate xcrate_generic; - -pub fn foo() { - println!("{}", xcrate_generic::foo::()); -} - -// Here we check that local debuginfo is mapped correctly. -// CHECK: !DIFile(filename: "/the/aux-src/xcrate-generic.rs", directory: "" diff --git a/tests/codegen/repeat-operand-zero-len.rs b/tests/codegen/repeat-operand-zero-len.rs deleted file mode 100644 index b4cec42a07c..00000000000 --- a/tests/codegen/repeat-operand-zero-len.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes - -// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`. -// It only applies when the resulting array is a ZST, so the test is written in -// such a way as to keep MIR optimizations from seeing that fact and removing -// the local and statement altogether. (At the time of writing, no other codegen -// test hit that code path, nor did a stage 2 build of the compiler.) - -#![crate_type = "lib"] - -#[repr(transparent)] -pub struct Wrapper([T; N]); - -// CHECK-LABEL: define {{.+}}do_repeat{{.+}}(i32 noundef %x) -// CHECK-NEXT: start: -// CHECK-NOT: alloca -// CHECK-NEXT: ret void -#[inline(never)] -pub fn do_repeat(x: T) -> Wrapper { - Wrapper([x; N]) -} - -// CHECK-LABEL: @trigger_repeat_zero_len -#[no_mangle] -pub fn trigger_repeat_zero_len() -> Wrapper { - // CHECK: call void {{.+}}do_repeat{{.+}}(i32 noundef 4) - do_repeat(4) -} diff --git a/tests/codegen/repeat-operand-zst-elem.rs b/tests/codegen/repeat-operand-zst-elem.rs deleted file mode 100644 index c3637759afa..00000000000 --- a/tests/codegen/repeat-operand-zst-elem.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes - -// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`. -// It only applies when the resulting array is a ZST, so the test is written in -// such a way as to keep MIR optimizations from seeing that fact and removing -// the local and statement altogether. (At the time of writing, no other codegen -// test hit that code path, nor did a stage 2 build of the compiler.) - -#![crate_type = "lib"] - -#[repr(transparent)] -pub struct Wrapper([T; N]); - -// CHECK-LABEL: define {{.+}}do_repeat{{.+}}() -// CHECK-NEXT: start: -// CHECK-NOT: alloca -// CHECK-NEXT: ret void -#[inline(never)] -pub fn do_repeat(x: T) -> Wrapper { - Wrapper([x; N]) -} - -// CHECK-LABEL: @trigger_repeat_zst_elem -#[no_mangle] -pub fn trigger_repeat_zst_elem() -> Wrapper<(), 8> { - // CHECK: call void {{.+}}do_repeat{{.+}}() - do_repeat(()) -} diff --git a/tests/codegen/repeat-trusted-len.rs b/tests/codegen/repeat-trusted-len.rs deleted file mode 100644 index 95379535971..00000000000 --- a/tests/codegen/repeat-trusted-len.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ compile-flags: -Copt-level=3 -// - -#![crate_type = "lib"] - -use std::iter; - -// CHECK-LABEL: @repeat_take_collect -#[no_mangle] -pub fn repeat_take_collect() -> Vec { - // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}align 1{{.*}} %{{.*}}, i8 42, i{{[0-9]+}} 100000, i1 false) - iter::repeat(42).take(100000).collect() -} - -// CHECK-LABEL: @repeat_with_take_collect -#[no_mangle] -pub fn repeat_with_take_collect() -> Vec { - // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}align 1{{.*}} %{{.*}}, i8 13, i{{[0-9]+}} 12345, i1 false) - iter::repeat_with(|| 13).take(12345).collect() -} diff --git a/tests/codegen/repr/transparent-byval-struct-ptr.rs b/tests/codegen/repr/transparent-byval-struct-ptr.rs deleted file mode 100644 index 0918884144f..00000000000 --- a/tests/codegen/repr/transparent-byval-struct-ptr.rs +++ /dev/null @@ -1,111 +0,0 @@ -//@ add-core-stubs -//@ revisions: i686-linux i686-freebsd x64-linux x64-apple -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes - -//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu -//@[i686-linux] needs-llvm-components: x86 -//@[i686-freebsd] compile-flags: --target i686-unknown-freebsd -//@[i686-freebsd] needs-llvm-components: x86 -//@[x64-linux] compile-flags: --target x86_64-unknown-linux-gnu -//@[x64-linux] needs-llvm-components: x86 -//@[x64-apple] compile-flags: --target x86_64-apple-darwin -//@[x64-apple] needs-llvm-components: x86 - -// See ./transparent.rs -// Some platforms pass large aggregates using immediate arrays in LLVMIR -// Other platforms pass large aggregates using by-value struct pointer in LLVMIR -// Yet more platforms pass large aggregates using opaque pointer in LLVMIR -// This covers the "by-value struct pointer" case. - -#![feature(no_core, lang_items, transparent_unions)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; - -impl Copy for BigS {} -impl Copy for BigU {} - -#[repr(C)] -pub struct BigS([u32; 16]); - -#[repr(transparent)] -pub struct TsBigS(BigS); - -#[repr(transparent)] -pub union TuBigS { - field: BigS, -} - -#[repr(transparent)] -pub enum TeBigS { - Variant(BigS), -} - -// CHECK: define{{.*}}void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], ptr [[BIGS_ARG_ATTRS1:.*]] byval([64 x i8]) [[BIGS_ARG_ATTRS2:.*]]) -#[no_mangle] -pub extern "C" fn test_BigS(_: BigS) -> BigS { - loop {} -} - -// CHECK: define{{.*}}void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval([64 x i8]) [[BIGS_ARG_ATTRS2:.*]]) -#[no_mangle] -pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS { - loop {} -} - -// CHECK: define{{.*}}void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval([64 x i8]) [[BIGS_ARG_ATTRS2:.*]]) -#[no_mangle] -pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { - loop {} -} - -// CHECK: define{{.*}}void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval([64 x i8]) [[BIGS_ARG_ATTRS2]]) -#[no_mangle] -pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { - loop {} -} - -#[repr(C)] -pub union BigU { - foo: [u32; 16], -} - -#[repr(transparent)] -pub struct TsBigU(BigU); - -#[repr(transparent)] -pub union TuBigU { - field: BigU, -} - -#[repr(transparent)] -pub enum TeBigU { - Variant(BigU), -} - -// CHECK: define{{.*}}void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1:.*]] byval([64 x i8]) [[BIGU_ARG_ATTRS2:.*]]) -#[no_mangle] -pub extern "C" fn test_BigU(_: BigU) -> BigU { - loop {} -} - -// CHECK: define{{.*}}void @test_TsBigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval([64 x i8]) [[BIGU_ARG_ATTRS2]]) -#[no_mangle] -pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU { - loop {} -} - -// CHECK: define{{.*}}void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval([64 x i8]) [[BIGU_ARG_ATTRS2]]) -#[no_mangle] -pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU { - loop {} -} - -// CHECK: define{{.*}}void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval([64 x i8]) [[BIGU_ARG_ATTRS2]]) -#[no_mangle] -pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU { - loop {} -} diff --git a/tests/codegen/repr/transparent-imm-array.rs b/tests/codegen/repr/transparent-imm-array.rs deleted file mode 100644 index 6dad0447784..00000000000 --- a/tests/codegen/repr/transparent-imm-array.rs +++ /dev/null @@ -1,116 +0,0 @@ -//@ add-core-stubs -//@ revisions: arm-linux arm-android armv7-linux armv7-android mips thumb sparc -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes - -//@[arm-linux] compile-flags: --target arm-unknown-linux-gnueabi -//@[arm-linux] needs-llvm-components: arm -//@[arm-android] compile-flags: --target arm-linux-androideabi -//@[arm-android] needs-llvm-components: arm -//@[armv7-linux] compile-flags: --target armv7-unknown-linux-gnueabi -//@[armv7-linux] needs-llvm-components: arm -//@[armv7-android] compile-flags: --target armv7-linux-androideabi -//@[armv7-android] needs-llvm-components: arm -//@[mips] compile-flags: --target mips-unknown-linux-gnu -//@[mips] needs-llvm-components: mips -//@[thumb] compile-flags: --target thumbv7neon-linux-androideabi -//@[thumb] needs-llvm-components: arm -//@[sparc] compile-flags: --target sparc-unknown-linux-gnu -//@[sparc] needs-llvm-components: sparc - -// See ./transparent.rs -// Some platforms pass large aggregates using immediate arrays in LLVMIR -// Other platforms pass large aggregates using by-value struct pointer in LLVMIR -// Yet more platforms pass large aggregates using opaque pointer in LLVMIR -// This covers the "immediate array" case. - -#![feature(no_core, lang_items, transparent_unions)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; -impl Copy for BigS {} -impl Copy for BigU {} - -#[repr(C)] -pub struct BigS([u32; 16]); - -#[repr(transparent)] -pub struct TsBigS(BigS); - -#[repr(transparent)] -pub union TuBigS { - field: BigS, -} - -#[repr(transparent)] -pub enum TeBigS { - Variant(BigS), -} - -// CHECK: define void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], [16 x i32] -#[no_mangle] -pub extern "C" fn test_BigS(_: BigS) -> BigS { - loop {} -} - -// CHECK: define void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [16 x i32] -#[no_mangle] -pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS { - loop {} -} - -// CHECK: define void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [16 x i32] -#[no_mangle] -pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { - loop {} -} - -// CHECK: define void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [16 x i32] -#[no_mangle] -pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { - loop {} -} - -#[repr(C)] -pub union BigU { - foo: [u32; 16], -} - -#[repr(transparent)] -pub struct TsBigU(BigU); - -#[repr(transparent)] -pub union TuBigU { - field: BigU, -} - -#[repr(transparent)] -pub enum TeBigU { - Variant(BigU), -} - -// CHECK: define void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], [16 x i32] -#[no_mangle] -pub extern "C" fn test_BigU(_: BigU) -> BigU { - loop {} -} - -// CHECK: define void @test_TsBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [16 x i32] -#[no_mangle] -pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU { - loop {} -} - -// CHECK: define void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [16 x i32] -#[no_mangle] -pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU { - loop {} -} - -// CHECK: define void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [16 x i32] -#[no_mangle] -pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU { - loop {} -} diff --git a/tests/codegen/repr/transparent-mips64.rs b/tests/codegen/repr/transparent-mips64.rs deleted file mode 100644 index 98901350154..00000000000 --- a/tests/codegen/repr/transparent-mips64.rs +++ /dev/null @@ -1,103 +0,0 @@ -//@ add-core-stubs -//@ revisions: mips64 mips64el -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes - -//@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 -//@[mips64] needs-llvm-components: mips -//@[mips64el] compile-flags: --target mips64el-unknown-linux-gnuabi64 -//@[mips64el] needs-llvm-components: mips - -// See ./transparent.rs - -#![feature(no_core, lang_items, transparent_unions)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; - -impl Copy for BigS {} -impl Copy for BigU {} - -#[repr(C)] -pub struct BigS([u32; 16]); - -#[repr(transparent)] -pub struct TsBigS(BigS); - -#[repr(transparent)] -pub union TuBigS { - field: BigS, -} - -#[repr(transparent)] -pub enum TeBigS { - Variant(BigS), -} - -// CHECK: define void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], [8 x i64] -#[no_mangle] -pub extern "C" fn test_BigS(_: BigS) -> BigS { - loop {} -} - -// CHECK: define void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [8 x i64] -#[no_mangle] -pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS { - loop {} -} - -// CHECK: define void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [8 x i64] -#[no_mangle] -pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { - loop {} -} - -// CHECK: define void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [8 x i64] -#[no_mangle] -pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { - loop {} -} - -#[repr(C)] -pub union BigU { - foo: [u32; 16], -} - -#[repr(transparent)] -pub struct TsBigU(BigU); - -#[repr(transparent)] -pub union TuBigU { - field: BigU, -} - -#[repr(transparent)] -pub enum TeBigU { - Variant(BigU), -} - -// CHECK: define void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], [8 x i64] -#[no_mangle] -pub extern "C" fn test_BigU(_: BigU) -> BigU { - loop {} -} - -// CHECK: define void @test_TsBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [8 x i64] -#[no_mangle] -pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU { - loop {} -} - -// CHECK: define void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [8 x i64] -#[no_mangle] -pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU { - loop {} -} - -// CHECK: define void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [8 x i64] -#[no_mangle] -pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU { - loop {} -} diff --git a/tests/codegen/repr/transparent-opaque-ptr.rs b/tests/codegen/repr/transparent-opaque-ptr.rs deleted file mode 100644 index 7911370c478..00000000000 --- a/tests/codegen/repr/transparent-opaque-ptr.rs +++ /dev/null @@ -1,109 +0,0 @@ -//@ add-core-stubs -//@ revisions: aarch64-linux aarch64-darwin wasm32-wasip1 -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes - -//@[aarch64-linux] compile-flags: --target aarch64-unknown-linux-gnu -//@[aarch64-linux] needs-llvm-components: aarch64 -//@[aarch64-darwin] compile-flags: --target aarch64-apple-darwin -//@[aarch64-darwin] needs-llvm-components: aarch64 -//@[wasm32-wasip1] compile-flags: --target wasm32-wasip1 -//@[wasm32-wasip1] needs-llvm-components: webassembly - -// See ./transparent.rs -// Some platforms pass large aggregates using immediate arrays in LLVMIR -// Other platforms pass large aggregates using by-value struct pointer in LLVMIR -// Yet more platforms pass large aggregates using opaque pointer in LLVMIR -// This covers the "opaque pointer" case. - -#![feature(no_core, lang_items, transparent_unions)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; - -impl Copy for BigS {} -impl Copy for BigU {} - -#[repr(C)] -pub struct BigS([u32; 16]); - -#[repr(transparent)] -pub struct TsBigS(BigS); - -#[repr(transparent)] -pub union TuBigS { - field: BigS, -} - -#[repr(transparent)] -pub enum TeBigS { - Variant(BigS), -} - -// CHECK: define{{.*}}void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], ptr [[BIGS_ARG_ATTRS1:.*]]) -#[no_mangle] -pub extern "C" fn test_BigS(_: BigS) -> BigS { - loop {} -} - -// CHECK: define{{.*}}void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]]) -#[no_mangle] -pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS { - loop {} -} - -// CHECK: define{{.*}}void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]]) -#[no_mangle] -pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { - loop {} -} - -// CHECK: define{{.*}}void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]]) -#[no_mangle] -pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { - loop {} -} - -#[repr(C)] -pub union BigU { - foo: [u32; 16], -} - -#[repr(transparent)] -pub struct TsBigU(BigU); - -#[repr(transparent)] -pub union TuBigU { - field: BigU, -} - -#[repr(transparent)] -pub enum TeBigU { - Variant(BigU), -} - -// CHECK: define{{.*}}void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1:.*]]) -#[no_mangle] -pub extern "C" fn test_BigU(_: BigU) -> BigU { - loop {} -} - -// CHECK: define{{.*}}void @test_TsBigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]]) -#[no_mangle] -pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU { - loop {} -} - -// CHECK: define{{.*}}void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]]) -#[no_mangle] -pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU { - loop {} -} - -// CHECK: define{{.*}}void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]]) -#[no_mangle] -pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU { - loop {} -} diff --git a/tests/codegen/repr/transparent-sparc64.rs b/tests/codegen/repr/transparent-sparc64.rs deleted file mode 100644 index 62bfc8a5fce..00000000000 --- a/tests/codegen/repr/transparent-sparc64.rs +++ /dev/null @@ -1,113 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes --target sparc64-unknown-linux-gnu -//@ needs-llvm-components: sparc - -// See ./transparent.rs - -#![feature(no_core, lang_items, transparent_unions)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; -impl Copy for BigS {} -impl Copy for BigU {} - -#[repr(C)] -pub struct BigS([u32; 16]); - -#[repr(transparent)] -pub struct TsBigS(BigS); - -#[repr(transparent)] -pub union TuBigS { - field: BigS, -} - -#[repr(transparent)] -pub enum TeBigS { - Variant(BigS), -} - -// CHECK: define{{.*}}void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], ptr -// CHECK-NOT: byval -// CHECK-SAME: %{{[0-9a-z_]+}}) -#[no_mangle] -pub extern "C" fn test_BigS(_: BigS) -> BigS { - loop {} -} - -// CHECK: define{{.*}}void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr -// CHECK-NOT: byval -// CHECK-SAME: %{{[0-9a-z_]+}}) -#[no_mangle] -pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS { - loop {} -} - -// CHECK: define{{.*}}void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr -// CHECK-NOT: byval -// CHECK-SAME: %{{[0-9a-z_]+}}) -#[no_mangle] -pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { - loop {} -} - -// CHECK: define{{.*}}void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr -// CHECK-NOT: byval -// CHECK-SAME: %{{[0-9a-z_]+}}) -#[no_mangle] -pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { - loop {} -} - -#[repr(C)] -pub union BigU { - foo: [u32; 16], -} - -#[repr(transparent)] -pub struct TsBigU(BigU); - -#[repr(transparent)] -pub union TuBigU { - field: BigU, -} - -#[repr(transparent)] -pub enum TeBigU { - Variant(BigU), -} - -// CHECK: define{{.*}}void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr -// CHECK-NOT: byval -// CHECK-SAME: %{{[0-9a-z_]+}}) -#[no_mangle] -pub extern "C" fn test_BigU(_: BigU) -> BigU { - loop {} -} - -// CHECK: define{{.*}}void @test_TsBigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr -// CHECK-NOT: byval -// CHECK-SAME: %{{[0-9a-z_]+}}) -#[no_mangle] -pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU { - loop {} -} - -// CHECK: define{{.*}}void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr -// CHECK-NOT: byval -// CHECK-SAME: %{{[0-9a-z_]+}}) -#[no_mangle] -pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU { - loop {} -} - -// CHECK: define{{.*}}void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr -// CHECK-NOT: byval -// CHECK-SAME: %{{[0-9a-z_]+}}) -#[no_mangle] -pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU { - loop {} -} diff --git a/tests/codegen/repr/transparent-sysv64.rs b/tests/codegen/repr/transparent-sysv64.rs deleted file mode 100644 index 3efc3f7c391..00000000000 --- a/tests/codegen/repr/transparent-sysv64.rs +++ /dev/null @@ -1,49 +0,0 @@ -//@ add-core-stubs -//@ revisions: linux apple win -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes - -//@[linux] compile-flags: --target x86_64-unknown-linux-gnu -//@[linux] needs-llvm-components: x86 -//@[apple] compile-flags: --target x86_64-apple-darwin -//@[apple] needs-llvm-components: x86 -//@[win] compile-flags: --target x86_64-pc-windows-msvc -//@[win] needs-llvm-components: x86 - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[repr(C)] -pub struct Rgb8 { - r: u8, - g: u8, - b: u8, -} - -#[repr(transparent)] -pub struct Rgb8Wrap(Rgb8); - -// CHECK: i24 @test_Rgb8Wrap(i24{{( %0)?}}) -#[no_mangle] -pub extern "sysv64" fn test_Rgb8Wrap(_: Rgb8Wrap) -> Rgb8Wrap { - loop {} -} - -#[repr(C)] -pub union FloatBits { - float: f32, - bits: u32, -} - -#[repr(transparent)] -pub struct SmallUnion(FloatBits); - -// CHECK: i32 @test_SmallUnion(i32{{( %0)?}}) -#[no_mangle] -pub extern "sysv64" fn test_SmallUnion(_: SmallUnion) -> SmallUnion { - loop {} -} diff --git a/tests/codegen/repr/transparent.rs b/tests/codegen/repr/transparent.rs deleted file mode 100644 index 29b627462a4..00000000000 --- a/tests/codegen/repr/transparent.rs +++ /dev/null @@ -1,221 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -//@ ignore-riscv64 riscv64 has an i128 type used with test_Vector -//@ ignore-s390x s390x with default march passes vector types per reference -//@ ignore-loongarch64 see codegen/loongarch-abi for loongarch function call tests - -// This codegen test embeds assumptions about how certain "C" psABIs are handled -// so it doesn't apply to all architectures or even all OS -// For RISCV: see codegen/riscv-abi -// For LoongArch: see codegen/loongarch-abi - -#![crate_type = "lib"] -#![feature(repr_simd, transparent_unions, arm_target_feature, mips_target_feature)] - -use std::marker::PhantomData; - -#[derive(Copy, Clone)] -pub struct Zst1; -#[derive(Copy, Clone)] -pub struct Zst2(()); - -#[derive(Copy, Clone)] -#[repr(transparent)] -pub struct F32(f32); - -// CHECK: define{{.*}}float @test_F32(float noundef %_1) -#[no_mangle] -pub extern "C" fn test_F32(_: F32) -> F32 { - loop {} -} - -#[repr(transparent)] -pub struct Ptr(*mut u8); - -// CHECK: define{{.*}}ptr @test_Ptr(ptr noundef %_1) -#[no_mangle] -pub extern "C" fn test_Ptr(_: Ptr) -> Ptr { - loop {} -} - -#[repr(transparent)] -pub struct WithZst(u64, Zst1); - -// CHECK: define{{.*}}i64 @test_WithZst(i64 noundef %_1) -#[no_mangle] -pub extern "C" fn test_WithZst(_: WithZst) -> WithZst { - loop {} -} - -#[repr(transparent)] -pub struct WithZeroSizedArray(*const f32, [i8; 0]); - -// CHECK: define{{.*}}ptr @test_WithZeroSizedArray(ptr noundef %_1) -#[no_mangle] -pub extern "C" fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { - loop {} -} - -#[repr(transparent)] -pub struct Generic(T); - -// CHECK: define{{.*}}double @test_Generic(double noundef %_1) -#[no_mangle] -pub extern "C" fn test_Generic(_: Generic) -> Generic { - loop {} -} - -#[repr(transparent)] -pub struct GenericPlusZst(T, Zst2); - -#[repr(u8)] -pub enum Bool { - True, - False, - FileNotFound, -} - -// CHECK: define{{( dso_local)?}} noundef{{( zeroext)?( range\(i8 0, 3\))?}} i8 @test_Gpz(i8 noundef{{( zeroext)?( range\(i8 0, 3\))?}} %_1) -#[no_mangle] -pub extern "C" fn test_Gpz(_: GenericPlusZst) -> GenericPlusZst { - loop {} -} - -#[repr(transparent)] -pub struct LifetimePhantom<'a, T: 'a>(*const T, PhantomData<&'a T>); - -// CHECK: define{{.*}}ptr @test_LifetimePhantom(ptr noundef %_1) -#[no_mangle] -pub extern "C" fn test_LifetimePhantom(_: LifetimePhantom) -> LifetimePhantom { - loop {} -} - -// This works despite current alignment resrictions because PhantomData is always align(1) -#[repr(transparent)] -pub struct UnitPhantom { - val: T, - unit: PhantomData, -} - -pub struct Px; - -// CHECK: define{{.*}}float @test_UnitPhantom(float noundef %_1) -#[no_mangle] -pub extern "C" fn test_UnitPhantom(_: UnitPhantom) -> UnitPhantom { - loop {} -} - -#[repr(transparent)] -pub struct TwoZsts(Zst1, i8, Zst2); - -// CHECK: define{{( dso_local)?}} noundef{{( signext)?}} i8 @test_TwoZsts(i8 noundef{{( signext)?}} %_1) -#[no_mangle] -pub extern "C" fn test_TwoZsts(_: TwoZsts) -> TwoZsts { - loop {} -} - -#[repr(transparent)] -pub struct Nested1(Zst2, Generic); - -// CHECK: define{{.*}}double @test_Nested1(double noundef %_1) -#[no_mangle] -pub extern "C" fn test_Nested1(_: Nested1) -> Nested1 { - loop {} -} - -#[repr(transparent)] -pub struct Nested2(Nested1, Zst1); - -// CHECK: define{{.*}}double @test_Nested2(double noundef %_1) -#[no_mangle] -pub extern "C" fn test_Nested2(_: Nested2) -> Nested2 { - loop {} -} - -#[repr(simd)] -struct f32x4([f32; 4]); - -#[repr(transparent)] -pub struct Vector(f32x4); - -// CHECK: define{{.*}}<4 x float> @test_Vector(<4 x float> %_1) -#[no_mangle] -#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] -#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] -#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] -#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] -pub extern "C" fn test_Vector(_: Vector) -> Vector { - loop {} -} - -trait Mirror { - type It: ?Sized; -} -impl Mirror for T { - type It = Self; -} - -#[repr(transparent)] -pub struct StructWithProjection(::It); - -// CHECK: define{{.*}}float @test_Projection(float noundef %_1) -#[no_mangle] -pub extern "C" fn test_Projection(_: StructWithProjection) -> StructWithProjection { - loop {} -} - -#[repr(transparent)] -pub enum EnumF32 { - Variant(F32), -} - -// CHECK: define{{.*}}float @test_EnumF32(float noundef %_1) -#[no_mangle] -pub extern "C" fn test_EnumF32(_: EnumF32) -> EnumF32 { - loop {} -} - -#[repr(transparent)] -pub enum EnumF32WithZsts { - Variant(Zst1, F32, Zst2), -} - -// CHECK: define{{.*}}float @test_EnumF32WithZsts(float noundef %_1) -#[no_mangle] -pub extern "C" fn test_EnumF32WithZsts(_: EnumF32WithZsts) -> EnumF32WithZsts { - loop {} -} - -#[repr(transparent)] -pub union UnionF32 { - field: F32, -} - -// CHECK: define{{.*}} float @test_UnionF32(float %_1) -#[no_mangle] -pub extern "C" fn test_UnionF32(_: UnionF32) -> UnionF32 { - loop {} -} - -#[repr(transparent)] -pub union UnionF32WithZsts { - zst1: Zst1, - field: F32, - zst2: Zst2, -} - -// CHECK: define{{.*}}float @test_UnionF32WithZsts(float %_1) -#[no_mangle] -pub extern "C" fn test_UnionF32WithZsts(_: UnionF32WithZsts) -> UnionF32WithZsts { - loop {} -} - -// All that remains to be tested are aggregates. They are tested in separate files called -// transparent-*.rs with `only-*` or `ignore-*` directives, because the expected LLVM IR -// function signatures vary so much that it's not reasonably possible to cover all of them with a -// single CHECK line. -// -// You may be wondering why we don't just compare the return types and argument types for equality -// with FileCheck regex captures. Well, rustc doesn't perform newtype unwrapping on newtypes -// containing aggregates. This is OK on all ABIs we support, but because LLVM has not gotten rid of -// pointee types yet, the IR function signature will be syntactically different (%Foo* vs -// %FooWrapper*). diff --git a/tests/codegen/retpoline.rs b/tests/codegen/retpoline.rs deleted file mode 100644 index 915c2c3d797..00000000000 --- a/tests/codegen/retpoline.rs +++ /dev/null @@ -1,27 +0,0 @@ -// ignore-tidy-linelength -// Test that the -// `retpoline-external-thunk`, `retpoline-indirect-branches`, `retpoline-indirect-calls` -// target features are (not) emitted when the `retpoline/retpoline-external-thunk` flag is (not) set. - -//@ add-core-stubs -//@ revisions: disabled enabled_retpoline enabled_retpoline_external_thunk -//@ needs-llvm-components: x86 -//@ compile-flags: --target x86_64-unknown-linux-gnu -//@ [enabled_retpoline] compile-flags: -Zretpoline -//@ [enabled_retpoline_external_thunk] compile-flags: -Zretpoline-external-thunk -#![crate_type = "lib"] -#![feature(no_core)] -#![no_core] -extern crate minicore; - -#[no_mangle] -pub fn foo() { - // CHECK: @foo() unnamed_addr #0 - - // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk{{.*}} } - // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches{{.*}} } - // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-calls{{.*}} } - - // enabled_retpoline: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} } - // enabled_retpoline_external_thunk: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk,+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} } -} diff --git a/tests/codegen/riscv-abi/call-llvm-intrinsics.rs b/tests/codegen/riscv-abi/call-llvm-intrinsics.rs deleted file mode 100644 index e72a649a530..00000000000 --- a/tests/codegen/riscv-abi/call-llvm-intrinsics.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -//@ only-riscv64 - -#![feature(link_llvm_intrinsics)] -#![crate_type = "lib"] - -struct A; - -impl Drop for A { - fn drop(&mut self) { - println!("A"); - } -} - -extern "C" { - #[link_name = "llvm.sqrt.f32"] - fn sqrt(x: f32) -> f32; -} - -pub fn do_call() { - let _a = A; - - unsafe { - // Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them - // CHECK: store float 4.000000e+00, ptr %{{.}}, align 4 - // CHECK: call float @llvm.sqrt.f32(float %{{.}} - sqrt(4.0); - } -} diff --git a/tests/codegen/riscv-abi/cast-local-large-enough.rs b/tests/codegen/riscv-abi/cast-local-large-enough.rs deleted file mode 100644 index 9d21d73b459..00000000000 --- a/tests/codegen/riscv-abi/cast-local-large-enough.rs +++ /dev/null @@ -1,44 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: -Copt-level=0 -Cdebuginfo=0 --target riscv64gc-unknown-linux-gnu -//@ needs-llvm-components: riscv - -#![feature(no_core, lang_items)] -#![no_std] -#![no_core] -#![crate_type = "lib"] - -extern crate minicore; -use minicore::*; - -#[repr(C, align(64))] -struct Aligned(f64); - -#[repr(C, align(64))] -struct AlignedPair(f32, f64); - -impl Copy for Aligned {} -impl Copy for AlignedPair {} - -// CHECK-LABEL: define double @read_aligned -#[unsafe(no_mangle)] -pub extern "C" fn read_aligned(x: &Aligned) -> Aligned { - // CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64 - // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false) - // CHECK-NEXT: %[[RES:.*]] = load double, ptr %[[TEMP]], align 64 - // CHECK-NEXT: ret double %[[RES]] - *x -} - -// CHECK-LABEL: define { float, double } @read_aligned_pair -#[unsafe(no_mangle)] -pub extern "C" fn read_aligned_pair(x: &AlignedPair) -> AlignedPair { - // CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64 - // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false) - // CHECK-NEXT: %[[FIRST:.*]] = load float, ptr %[[TEMP]], align 64 - // CHECK-NEXT: %[[SECOND_PTR:.*]] = getelementptr inbounds i8, ptr %[[TEMP]], i64 8 - // CHECK-NEXT: %[[SECOND:.*]] = load double, ptr %[[SECOND_PTR]], align 8 - // CHECK-NEXT: %[[RES1:.*]] = insertvalue { float, double } poison, float %[[FIRST]], 0 - // CHECK-NEXT: %[[RES2:.*]] = insertvalue { float, double } %[[RES1]], double %[[SECOND]], 1 - // CHECK-NEXT: ret { float, double } %[[RES2]] - *x -} diff --git a/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs b/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs deleted file mode 100644 index df99f6969fc..00000000000 --- a/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs +++ /dev/null @@ -1,176 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: --target riscv64gc-unknown-linux-gnu -Copt-level=3 -C no-prepopulate-passes -C panic=abort -//@ needs-llvm-components: riscv - -#![crate_type = "lib"] -#![no_core] -#![feature(no_core, lang_items)] -#![allow(improper_ctypes)] - -extern crate minicore; -use minicore::*; - -// CHECK: define void @f_void() -#[no_mangle] -pub extern "C" fn f_void() {} - -// CHECK: define noundef zeroext i1 @f_scalar_0(i1 noundef zeroext %a) -#[no_mangle] -pub extern "C" fn f_scalar_0(a: bool) -> bool { - a -} - -// CHECK: define noundef signext i8 @f_scalar_1(i8 noundef signext %x) -#[no_mangle] -pub extern "C" fn f_scalar_1(x: i8) -> i8 { - x -} - -// CHECK: define noundef zeroext i8 @f_scalar_2(i8 noundef zeroext %x) -#[no_mangle] -pub extern "C" fn f_scalar_2(x: u8) -> u8 { - x -} - -// CHECK: define noundef signext i32 @f_scalar_3(i32 noundef signext %x) -#[no_mangle] -pub extern "C" fn f_scalar_3(x: i32) -> u32 { - x as u32 -} - -// CHECK: define noundef i64 @f_scalar_4(i64 noundef %x) -#[no_mangle] -pub extern "C" fn f_scalar_4(x: i64) -> i64 { - x -} - -// CHECK: define float @f_fp_scalar_1(float %0) -#[no_mangle] -pub extern "C" fn f_fp_scalar_1(x: f32) -> f32 { - x -} -// CHECK: define double @f_fp_scalar_2(double %0) -#[no_mangle] -pub extern "C" fn f_fp_scalar_2(x: f64) -> f64 { - x -} - -#[repr(C)] -pub struct Empty {} - -// CHECK: define void @f_agg_empty_struct() -#[no_mangle] -pub extern "C" fn f_agg_empty_struct(e: Empty) -> Empty { - e -} - -#[repr(C)] -pub struct Tiny { - a: u16, - b: u16, - c: u16, - d: u16, -} - -// CHECK: define void @f_agg_tiny(i64 %0) -#[no_mangle] -pub extern "C" fn f_agg_tiny(mut e: Tiny) {} - -// CHECK: define i64 @f_agg_tiny_ret() -#[no_mangle] -pub extern "C" fn f_agg_tiny_ret() -> Tiny { - Tiny { a: 1, b: 2, c: 3, d: 4 } -} - -#[repr(C)] -pub struct Small { - a: i64, - b: *mut i64, -} - -// CHECK: define void @f_agg_small([2 x i64] %0) -#[no_mangle] -pub extern "C" fn f_agg_small(mut x: Small) {} - -// CHECK: define [2 x i64] @f_agg_small_ret() -#[no_mangle] -pub extern "C" fn f_agg_small_ret() -> Small { - Small { a: 1, b: 0 as *mut _ } -} - -#[repr(C)] -pub struct SmallAligned { - a: i128, -} - -// CHECK: define void @f_agg_small_aligned(i128 %0) -#[no_mangle] -pub extern "C" fn f_agg_small_aligned(mut x: SmallAligned) {} - -#[repr(C)] -pub struct Large { - a: i64, - b: i64, - c: i64, - d: i64, -} - -// CHECK: define void @f_agg_large(ptr {{.*}}%x) -#[no_mangle] -pub extern "C" fn f_agg_large(mut x: Large) {} - -// CHECK: define void @f_agg_large_ret(ptr {{.*}}sret{{.*}}, i32 noundef signext %i, i8 noundef signext %j) -#[no_mangle] -pub extern "C" fn f_agg_large_ret(i: i32, j: i8) -> Large { - Large { a: 1, b: 2, c: 3, d: 4 } -} - -// CHECK: define void @f_scalar_stack_1(i64 %0, [2 x i64] %1, i128 %2, ptr {{.*}}%d, i8 noundef zeroext %e, i8 noundef signext %f, i8 noundef %g, i8 noundef %h) -#[no_mangle] -pub extern "C" fn f_scalar_stack_1( - a: Tiny, - b: Small, - c: SmallAligned, - d: Large, - e: u8, - f: i8, - g: u8, - h: i8, -) { -} - -// CHECK: define void @f_scalar_stack_2(ptr {{.*}}sret{{.*}} %_0, i64 noundef %a, i128 %0, i128 %1, i64 noundef %d, i8 noundef zeroext %e, i8 noundef %f, i8 noundef %g) -#[no_mangle] -pub extern "C" fn f_scalar_stack_2( - a: u64, - b: SmallAligned, - c: SmallAligned, - d: u64, - e: u8, - f: i8, - g: u8, -) -> Large { - Large { a: a as i64, b: e as i64, c: f as i64, d: g as i64 } -} - -extern "C" { - fn f_va_callee(_: i32, ...) -> i32; -} - -#[no_mangle] -pub unsafe extern "C" fn f_va_caller() { - // CHECK: call noundef signext i32 (i32, ...) @f_va_callee(i32 noundef signext 1, i32 noundef signext 2, i64 noundef 3, double {{.*}}, double {{.*}}, i64 {{.*}}, [2 x i64] {{.*}}, i128 {{.*}}, ptr {{.*}}) - f_va_callee( - 1, - 2i32, - 3i64, - 4.0f64, - 5.0f64, - Tiny { a: 1, b: 2, c: 3, d: 4 }, - Small { a: 10, b: 0 as *mut _ }, - SmallAligned { a: 11 }, - Large { a: 12, b: 13, c: 14, d: 15 }, - ); - // CHECK: call noundef signext i32 (i32, ...) @f_va_callee(i32 noundef signext 1, i32 noundef signext 2, i32 noundef signext 3, i32 noundef signext 4, i128 {{.*}}, i32 noundef signext 6, i32 noundef signext 7, i32 noundef 8, i32 noundef 9) - f_va_callee(1, 2i32, 3i32, 4i32, SmallAligned { a: 5 }, 6i32, 7i32, 8i32, 9i32); -} diff --git a/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs b/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs deleted file mode 100644 index d768ab9381a..00000000000 --- a/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs +++ /dev/null @@ -1,299 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes --target riscv64gc-unknown-linux-gnu -//@ needs-llvm-components: riscv - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK: define void @f_fpr_tracking(double %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, i8 noundef zeroext %i) -#[no_mangle] -pub extern "C" fn f_fpr_tracking( - a: f64, - b: f64, - c: f64, - d: f64, - e: f64, - f: f64, - g: f64, - h: f64, - i: u8, -) { -} - -#[repr(C)] -pub struct Double { - f: f64, -} - -#[repr(C)] -pub struct DoubleDouble { - f: f64, - g: f64, -} - -#[repr(C)] -pub struct DoubleFloat { - f: f64, - g: f32, -} - -// CHECK: define void @f_double_s_arg(double %0) -#[no_mangle] -pub extern "C" fn f_double_s_arg(a: Double) {} - -// CHECK: define double @f_ret_double_s() -#[no_mangle] -pub extern "C" fn f_ret_double_s() -> Double { - Double { f: 1. } -} - -// CHECK: define void @f_double_double_s_arg({ double, double } %0) -#[no_mangle] -pub extern "C" fn f_double_double_s_arg(a: DoubleDouble) {} - -// CHECK: define { double, double } @f_ret_double_double_s() -#[no_mangle] -pub extern "C" fn f_ret_double_double_s() -> DoubleDouble { - DoubleDouble { f: 1., g: 2. } -} - -// CHECK: define void @f_double_float_s_arg({ double, float } %0) -#[no_mangle] -pub extern "C" fn f_double_float_s_arg(a: DoubleFloat) {} - -// CHECK: define { double, float } @f_ret_double_float_s() -#[no_mangle] -pub extern "C" fn f_ret_double_float_s() -> DoubleFloat { - DoubleFloat { f: 1., g: 2. } -} - -// CHECK: define void @f_double_double_s_arg_insufficient_fprs(double %0, double %1, double %2, double %3, double %4, double %5, double %6, [2 x i64] %7) -#[no_mangle] -pub extern "C" fn f_double_double_s_arg_insufficient_fprs( - a: f64, - b: f64, - c: f64, - d: f64, - e: f64, - f: f64, - g: f64, - h: DoubleDouble, -) { -} - -#[repr(C)] -pub struct DoubleInt8 { - f: f64, - i: i8, -} - -#[repr(C)] -pub struct DoubleUInt8 { - f: f64, - i: u8, -} - -#[repr(C)] -pub struct DoubleInt32 { - f: f64, - i: i32, -} - -#[repr(C)] -pub struct DoubleInt64 { - f: f64, - i: i64, -} - -// CHECK: define void @f_double_int8_s_arg({ double, i8 } %0) -#[no_mangle] -pub extern "C" fn f_double_int8_s_arg(a: DoubleInt8) {} - -// CHECK: define { double, i8 } @f_ret_double_int8_s() -#[no_mangle] -pub extern "C" fn f_ret_double_int8_s() -> DoubleInt8 { - DoubleInt8 { f: 1., i: 2 } -} - -// CHECK: define void @f_double_int32_s_arg({ double, i32 } %0) -#[no_mangle] -pub extern "C" fn f_double_int32_s_arg(a: DoubleInt32) {} - -// CHECK: define { double, i32 } @f_ret_double_int32_s() -#[no_mangle] -pub extern "C" fn f_ret_double_int32_s() -> DoubleInt32 { - DoubleInt32 { f: 1., i: 2 } -} - -// CHECK: define void @f_double_uint8_s_arg({ double, i8 } %0) -#[no_mangle] -pub extern "C" fn f_double_uint8_s_arg(a: DoubleUInt8) {} - -// CHECK: define { double, i8 } @f_ret_double_uint8_s() -#[no_mangle] -pub extern "C" fn f_ret_double_uint8_s() -> DoubleUInt8 { - DoubleUInt8 { f: 1., i: 2 } -} - -// CHECK: define void @f_double_int64_s_arg({ double, i64 } %0) -#[no_mangle] -pub extern "C" fn f_double_int64_s_arg(a: DoubleInt64) {} - -// CHECK: define { double, i64 } @f_ret_double_int64_s() -#[no_mangle] -pub extern "C" fn f_ret_double_int64_s() -> DoubleInt64 { - DoubleInt64 { f: 1., i: 2 } -} - -// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 noundef signext %a, i32 noundef signext %b, i32 noundef signext %c, i32 noundef signext %d, i32 noundef signext %e, i32 noundef signext %f, i32 noundef signext %g, i32 noundef signext %h, [2 x i64] %0) -#[no_mangle] -pub extern "C" fn f_double_int8_s_arg_insufficient_gprs( - a: i32, - b: i32, - c: i32, - d: i32, - e: i32, - f: i32, - g: i32, - h: i32, - i: DoubleInt8, -) { -} - -// CHECK: define void @f_struct_double_int8_insufficient_fprs(float %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, [2 x i64] %8) -#[no_mangle] -pub extern "C" fn f_struct_double_int8_insufficient_fprs( - a: f32, - b: f64, - c: f64, - d: f64, - e: f64, - f: f64, - g: f64, - h: f64, - i: DoubleInt8, -) { -} - -#[repr(C)] -pub struct DoubleArr1 { - a: [f64; 1], -} - -// CHECK: define void @f_doublearr1_s_arg(double %0) -#[no_mangle] -pub extern "C" fn f_doublearr1_s_arg(a: DoubleArr1) {} - -// CHECK: define double @f_ret_doublearr1_s() -#[no_mangle] -pub extern "C" fn f_ret_doublearr1_s() -> DoubleArr1 { - DoubleArr1 { a: [1.] } -} - -#[repr(C)] -pub struct DoubleArr2 { - a: [f64; 2], -} - -// CHECK: define void @f_doublearr2_s_arg({ double, double } %0) -#[no_mangle] -pub extern "C" fn f_doublearr2_s_arg(a: DoubleArr2) {} - -// CHECK: define { double, double } @f_ret_doublearr2_s() -#[no_mangle] -pub extern "C" fn f_ret_doublearr2_s() -> DoubleArr2 { - DoubleArr2 { a: [1., 2.] } -} - -#[repr(C)] -pub struct Tricky1 { - f: [f64; 1], -} - -#[repr(C)] -pub struct DoubleArr2Tricky1 { - g: [Tricky1; 2], -} - -// CHECK: define void @f_doublearr2_tricky1_s_arg({ double, double } %0) -#[no_mangle] -pub extern "C" fn f_doublearr2_tricky1_s_arg(a: DoubleArr2Tricky1) {} - -// CHECK: define { double, double } @f_ret_doublearr2_tricky1_s() -#[no_mangle] -pub extern "C" fn f_ret_doublearr2_tricky1_s() -> DoubleArr2Tricky1 { - DoubleArr2Tricky1 { g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } -} - -#[repr(C)] -pub struct EmptyStruct {} - -#[repr(C)] -pub struct DoubleArr2Tricky2 { - s: EmptyStruct, - g: [Tricky1; 2], -} - -// CHECK: define void @f_doublearr2_tricky2_s_arg({ double, double } %0) -#[no_mangle] -pub extern "C" fn f_doublearr2_tricky2_s_arg(a: DoubleArr2Tricky2) {} - -// CHECK: define { double, double } @f_ret_doublearr2_tricky2_s() -#[no_mangle] -pub extern "C" fn f_ret_doublearr2_tricky2_s() -> DoubleArr2Tricky2 { - DoubleArr2Tricky2 { s: EmptyStruct {}, g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } -} - -#[repr(C)] -pub struct IntDoubleInt { - a: i32, - b: f64, - c: i32, -} - -// CHECK: define void @f_int_double_int_s_arg(ptr {{.*}} %a) -#[no_mangle] -pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {} - -// CHECK: define void @f_ret_int_double_int_s(ptr {{.*}} sret([24 x i8]) align 8 {{.*}}dereferenceable(24) %_0) -#[no_mangle] -pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt { - IntDoubleInt { a: 1, b: 2., c: 3 } -} - -#[repr(C)] -pub struct CharCharDouble { - a: u8, - b: u8, - c: f64, -} - -// CHECK: define void @f_char_char_double_s_arg([2 x i64] %0) -#[no_mangle] -pub extern "C" fn f_char_char_double_s_arg(a: CharCharDouble) {} - -// CHECK: define [2 x i64] @f_ret_char_char_double_s() -#[no_mangle] -pub extern "C" fn f_ret_char_char_double_s() -> CharCharDouble { - CharCharDouble { a: 1, b: 2, c: 3. } -} - -#[repr(C)] -pub union DoubleU { - a: f64, -} - -// CHECK: define void @f_double_u_arg(i64 %0) -#[no_mangle] -pub extern "C" fn f_double_u_arg(a: DoubleU) {} - -// CHECK: define i64 @f_ret_double_u() -#[no_mangle] -pub extern "C" fn f_ret_double_u() -> DoubleU { - unsafe { DoubleU { a: 1. } } -} diff --git a/tests/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs b/tests/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs deleted file mode 100644 index 361f0322690..00000000000 --- a/tests/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs +++ /dev/null @@ -1,283 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes --target riscv64gc-unknown-linux-gnu -//@ needs-llvm-components: riscv - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK: define void @f_fpr_tracking(float %0, float %1, float %2, float %3, float %4, float %5, float %6, float %7, i8 noundef zeroext %i) -#[no_mangle] -pub extern "C" fn f_fpr_tracking( - a: f32, - b: f32, - c: f32, - d: f32, - e: f32, - f: f32, - g: f32, - h: f32, - i: u8, -) { -} - -#[repr(C)] -pub struct Float { - f: f32, -} - -#[repr(C)] -pub struct FloatFloat { - f: f32, - g: f32, -} - -// CHECK: define void @f_float_s_arg(float %0) -#[no_mangle] -pub extern "C" fn f_float_s_arg(a: Float) {} - -// CHECK: define float @f_ret_float_s() -#[no_mangle] -pub extern "C" fn f_ret_float_s() -> Float { - Float { f: 1. } -} - -// CHECK: define void @f_float_float_s_arg({ float, float } %0) -#[no_mangle] -pub extern "C" fn f_float_float_s_arg(a: FloatFloat) {} - -// CHECK: define { float, float } @f_ret_float_float_s() -#[no_mangle] -pub extern "C" fn f_ret_float_float_s() -> FloatFloat { - FloatFloat { f: 1., g: 2. } -} - -// CHECK: define void @f_float_float_s_arg_insufficient_fprs(float %0, float %1, float %2, float %3, float %4, float %5, float %6, i64 %7) -#[no_mangle] -pub extern "C" fn f_float_float_s_arg_insufficient_fprs( - a: f32, - b: f32, - c: f32, - d: f32, - e: f32, - f: f32, - g: f32, - h: FloatFloat, -) { -} - -#[repr(C)] -pub struct FloatInt8 { - f: f32, - i: i8, -} - -#[repr(C)] -pub struct FloatUInt8 { - f: f32, - i: u8, -} - -#[repr(C)] -pub struct FloatInt32 { - f: f32, - i: i32, -} - -#[repr(C)] -pub struct FloatInt64 { - f: f32, - i: i64, -} - -// CHECK: define void @f_float_int8_s_arg({ float, i8 } %0) -#[no_mangle] -pub extern "C" fn f_float_int8_s_arg(a: FloatInt8) {} - -// CHECK: define { float, i8 } @f_ret_float_int8_s() -#[no_mangle] -pub extern "C" fn f_ret_float_int8_s() -> FloatInt8 { - FloatInt8 { f: 1., i: 2 } -} - -// CHECK: define void @f_float_int32_s_arg({ float, i32 } %0) -#[no_mangle] -pub extern "C" fn f_float_int32_s_arg(a: FloatInt32) {} - -// CHECK: define { float, i32 } @f_ret_float_int32_s() -#[no_mangle] -pub extern "C" fn f_ret_float_int32_s() -> FloatInt32 { - FloatInt32 { f: 1., i: 2 } -} - -// CHECK: define void @f_float_uint8_s_arg({ float, i8 } %0) -#[no_mangle] -pub extern "C" fn f_float_uint8_s_arg(a: FloatUInt8) {} - -// CHECK: define { float, i8 } @f_ret_float_uint8_s() -#[no_mangle] -pub extern "C" fn f_ret_float_uint8_s() -> FloatUInt8 { - FloatUInt8 { f: 1., i: 2 } -} - -// CHECK: define void @f_float_int64_s_arg({ float, i64 } %0) -#[no_mangle] -pub extern "C" fn f_float_int64_s_arg(a: FloatInt64) {} - -// CHECK: define { float, i64 } @f_ret_float_int64_s() -#[no_mangle] -pub extern "C" fn f_ret_float_int64_s() -> FloatInt64 { - FloatInt64 { f: 1., i: 2 } -} - -// CHECK: define void @f_float_int8_s_arg_insufficient_gprs(i32 noundef signext %a, i32 noundef signext %b, i32 noundef signext %c, i32 noundef signext %d, i32 noundef signext %e, i32 noundef signext %f, i32 noundef signext %g, i32 noundef signext %h, i64 %0) -#[no_mangle] -pub extern "C" fn f_float_int8_s_arg_insufficient_gprs( - a: i32, - b: i32, - c: i32, - d: i32, - e: i32, - f: i32, - g: i32, - h: i32, - i: FloatInt8, -) { -} - -// CHECK: define void @f_struct_float_int8_insufficient_fprs(float %0, float %1, float %2, float %3, float %4, float %5, float %6, float %7, i64 %8) -#[no_mangle] -pub extern "C" fn f_struct_float_int8_insufficient_fprs( - a: f32, - b: f32, - c: f32, - d: f32, - e: f32, - f: f32, - g: f32, - h: f32, - i: FloatInt8, -) { -} - -#[repr(C)] -pub struct FloatArr1 { - a: [f32; 1], -} - -// CHECK: define void @f_floatarr1_s_arg(float %0) -#[no_mangle] -pub extern "C" fn f_floatarr1_s_arg(a: FloatArr1) {} - -// CHECK: define float @f_ret_floatarr1_s() -#[no_mangle] -pub extern "C" fn f_ret_floatarr1_s() -> FloatArr1 { - FloatArr1 { a: [1.] } -} - -#[repr(C)] -pub struct FloatArr2 { - a: [f32; 2], -} - -// CHECK: define void @f_floatarr2_s_arg({ float, float } %0) -#[no_mangle] -pub extern "C" fn f_floatarr2_s_arg(a: FloatArr2) {} - -// CHECK: define { float, float } @f_ret_floatarr2_s() -#[no_mangle] -pub extern "C" fn f_ret_floatarr2_s() -> FloatArr2 { - FloatArr2 { a: [1., 2.] } -} - -#[repr(C)] -pub struct Tricky1 { - f: [f32; 1], -} - -#[repr(C)] -pub struct FloatArr2Tricky1 { - g: [Tricky1; 2], -} - -// CHECK: define void @f_floatarr2_tricky1_s_arg({ float, float } %0) -#[no_mangle] -pub extern "C" fn f_floatarr2_tricky1_s_arg(a: FloatArr2Tricky1) {} - -// CHECK: define { float, float } @f_ret_floatarr2_tricky1_s() -#[no_mangle] -pub extern "C" fn f_ret_floatarr2_tricky1_s() -> FloatArr2Tricky1 { - FloatArr2Tricky1 { g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } -} - -#[repr(C)] -pub struct EmptyStruct {} - -#[repr(C)] -pub struct FloatArr2Tricky2 { - s: EmptyStruct, - g: [Tricky1; 2], -} - -// CHECK: define void @f_floatarr2_tricky2_s_arg({ float, float } %0) -#[no_mangle] -pub extern "C" fn f_floatarr2_tricky2_s_arg(a: FloatArr2Tricky2) {} - -// CHECK: define { float, float } @f_ret_floatarr2_tricky2_s() -#[no_mangle] -pub extern "C" fn f_ret_floatarr2_tricky2_s() -> FloatArr2Tricky2 { - FloatArr2Tricky2 { s: EmptyStruct {}, g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } -} - -#[repr(C)] -pub struct IntFloatInt { - a: i32, - b: f32, - c: i32, -} - -// CHECK: define void @f_int_float_int_s_arg([2 x i64] %0) -#[no_mangle] -pub extern "C" fn f_int_float_int_s_arg(a: IntFloatInt) {} - -// CHECK: define [2 x i64] @f_ret_int_float_int_s() -#[no_mangle] -pub extern "C" fn f_ret_int_float_int_s() -> IntFloatInt { - IntFloatInt { a: 1, b: 2., c: 3 } -} - -#[repr(C)] -pub struct CharCharFloat { - a: u8, - b: u8, - c: f32, -} - -// CHECK: define void @f_char_char_float_s_arg(i64 %0) -#[no_mangle] -pub extern "C" fn f_char_char_float_s_arg(a: CharCharFloat) {} - -// CHECK: define i64 @f_ret_char_char_float_s() -#[no_mangle] -pub extern "C" fn f_ret_char_char_float_s() -> CharCharFloat { - CharCharFloat { a: 1, b: 2, c: 3. } -} - -#[repr(C)] -pub union FloatU { - a: f32, -} - -// CHECK: define void @f_float_u_arg(i64 %0) -#[no_mangle] -pub extern "C" fn f_float_u_arg(a: FloatU) {} - -// CHECK: define i64 @f_ret_float_u() -#[no_mangle] -pub extern "C" fn f_ret_float_u() -> FloatU { - unsafe { FloatU { a: 1. } } -} diff --git a/tests/codegen/riscv-target-abi.rs b/tests/codegen/riscv-target-abi.rs deleted file mode 100644 index d41fcb4dd84..00000000000 --- a/tests/codegen/riscv-target-abi.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ add-core-stubs -//@ revisions:riscv64gc riscv32gc riscv32imac - -//@[riscv64gc] compile-flags: --target=riscv64gc-unknown-linux-gnu -//@[riscv64gc] needs-llvm-components: riscv -// riscv64gc: !{i32 1, !"target-abi", !"lp64d"} - -//@[riscv32gc] compile-flags: --target=riscv32gc-unknown-linux-musl -//@[riscv32gc] needs-llvm-components: riscv -// riscv32gc: !{i32 1, !"target-abi", !"ilp32d"} - -//@[riscv32imac] compile-flags: --target=riscv32imac-unknown-none-elf -//@[riscv32imac] needs-llvm-components: riscv -// riscv32imac: !{i32 1, !"target-abi", !"ilp32"} - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; diff --git a/tests/codegen/rust-abi-arch-specific-adjustment.rs b/tests/codegen/rust-abi-arch-specific-adjustment.rs deleted file mode 100644 index 561f081c700..00000000000 --- a/tests/codegen/rust-abi-arch-specific-adjustment.rs +++ /dev/null @@ -1,111 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -//@ revisions: riscv64 loongarch64 - -//@[riscv64] only-riscv64 -//@[riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu -//@[riscv64] needs-llvm-components: riscv - -//@[loongarch64] only-loongarch64 -//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu -//@[loongarch64] needs-llvm-components: loongarch - -#![crate_type = "lib"] - -#[no_mangle] -// riscv64: define noundef i8 @arg_attr_u8(i8 noundef zeroext %x) -// loongarch64: define noundef i8 @arg_attr_u8(i8 noundef zeroext %x) -pub fn arg_attr_u8(x: u8) -> u8 { - x -} - -#[no_mangle] -// riscv64: define noundef i16 @arg_attr_u16(i16 noundef zeroext %x) -// loongarch64: define noundef i16 @arg_attr_u16(i16 noundef zeroext %x) -pub fn arg_attr_u16(x: u16) -> u16 { - x -} - -#[no_mangle] -// riscv64: define noundef i32 @arg_attr_u32(i32 noundef signext %x) -// loongarch64: define noundef i32 @arg_attr_u32(i32 noundef signext %x) -pub fn arg_attr_u32(x: u32) -> u32 { - x -} - -#[no_mangle] -// riscv64: define noundef i64 @arg_attr_u64(i64 noundef %x) -// loongarch64: define noundef i64 @arg_attr_u64(i64 noundef %x) -pub fn arg_attr_u64(x: u64) -> u64 { - x -} - -#[no_mangle] -// riscv64: define noundef i128 @arg_attr_u128(i128 noundef %x) -// loongarch64: define noundef i128 @arg_attr_u128(i128 noundef %x) -pub fn arg_attr_u128(x: u128) -> u128 { - x -} - -#[no_mangle] -// riscv64: define noundef i8 @arg_attr_i8(i8 noundef signext %x) -// loongarch64: define noundef i8 @arg_attr_i8(i8 noundef signext %x) -pub fn arg_attr_i8(x: i8) -> i8 { - x -} - -#[no_mangle] -// riscv64: define noundef i16 @arg_attr_i16(i16 noundef signext %x) -// loongarch64: define noundef i16 @arg_attr_i16(i16 noundef signext %x) -pub fn arg_attr_i16(x: i16) -> i16 { - x -} - -#[no_mangle] -// riscv64: define noundef i32 @arg_attr_i32(i32 noundef signext %x) -// loongarch64: define noundef i32 @arg_attr_i32(i32 noundef signext %x) -pub fn arg_attr_i32(x: i32) -> i32 { - x -} - -#[no_mangle] -// riscv64: define noundef i64 @arg_attr_i64(i64 noundef %x) -// loongarch64: define noundef i64 @arg_attr_i64(i64 noundef %x) -pub fn arg_attr_i64(x: i64) -> i64 { - x -} - -#[no_mangle] -// riscv64: define noundef i128 @arg_attr_i128(i128 noundef %x) -// loongarch64: define noundef i128 @arg_attr_i128(i128 noundef %x) -pub fn arg_attr_i128(x: i128) -> i128 { - x -} - -#[no_mangle] -// riscv64: define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x) -// loongarch64: define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x) -pub fn arg_attr_bool(x: bool) -> bool { - x -} - -#[no_mangle] -// ignore-tidy-linelength -// riscv64: define noundef{{( range\(i32 0, 1114112\))?}} i32 @arg_attr_char(i32 noundef signext{{( range\(i32 0, 1114112\))?}} %x) -// loongarch64: define noundef{{( range\(i32 0, 1114112\))?}} i32 @arg_attr_char(i32 noundef signext{{( range\(i32 0, 1114112\))?}} %x) -pub fn arg_attr_char(x: char) -> char { - x -} - -#[no_mangle] -// riscv64: define noundef float @arg_attr_f32(float noundef %x) -// loongarch64: define noundef float @arg_attr_f32(float noundef %x) -pub fn arg_attr_f32(x: f32) -> f32 { - x -} - -#[no_mangle] -// riscv64: define noundef double @arg_attr_f64(double noundef %x) -// loongarch64: define noundef double @arg_attr_f64(double noundef %x) -pub fn arg_attr_f64(x: f64) -> f64 { - x -} diff --git a/tests/codegen/s390x-simd.rs b/tests/codegen/s390x-simd.rs deleted file mode 100644 index ac39357519e..00000000000 --- a/tests/codegen/s390x-simd.rs +++ /dev/null @@ -1,143 +0,0 @@ -//! test that s390x vector types are passed using `PassMode::Direct` -//! see also https://github.com/rust-lang/rust/issues/135744 -//@ add-core-stubs -//@ compile-flags: --target s390x-unknown-linux-gnu -Copt-level=3 -//@ needs-llvm-components: systemz - -#![crate_type = "rlib"] -#![feature(no_core, asm_experimental_arch)] -#![feature(s390x_target_feature, simd_ffi, link_llvm_intrinsics, repr_simd)] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[repr(simd)] -struct i8x16([i8; 16]); - -#[repr(simd)] -struct i16x8([i16; 8]); - -#[repr(simd)] -struct i32x4([i32; 4]); - -#[repr(simd)] -struct i64x2([i64; 2]); - -#[repr(simd)] -struct f32x4([f32; 4]); - -#[repr(simd)] -struct f64x2([f64; 2]); - -#[allow(improper_ctypes)] -extern "C" { - #[link_name = "llvm.smax.v16i8"] - fn vmxb(a: i8x16, b: i8x16) -> i8x16; - #[link_name = "llvm.smax.v8i16"] - fn vmxh(a: i16x8, b: i16x8) -> i16x8; - #[link_name = "llvm.smax.v4i32"] - fn vmxf(a: i32x4, b: i32x4) -> i32x4; - #[link_name = "llvm.smax.v2i64"] - fn vmxg(a: i64x2, b: i64x2) -> i64x2; -} - -// CHECK-LABEL: define <16 x i8> @max_i8x16 -// CHECK-SAME: <16 x i8> %a, <16 x i8> %b -// CHECK: call <16 x i8> @llvm.smax.v16i8(<16 x i8> %a, <16 x i8> %b) -#[no_mangle] -#[target_feature(enable = "vector")] -pub unsafe extern "C" fn max_i8x16(a: i8x16, b: i8x16) -> i8x16 { - vmxb(a, b) -} - -// CHECK-LABEL: define <8 x i16> @max_i16x8 -// CHECK-SAME: <8 x i16> %a, <8 x i16> %b -// CHECK: call <8 x i16> @llvm.smax.v8i16(<8 x i16> %a, <8 x i16> %b) -#[no_mangle] -#[target_feature(enable = "vector")] -pub unsafe extern "C" fn max_i16x8(a: i16x8, b: i16x8) -> i16x8 { - vmxh(a, b) -} - -// CHECK-LABEL: define <4 x i32> @max_i32x4 -// CHECK-SAME: <4 x i32> %a, <4 x i32> %b -// CHECK: call <4 x i32> @llvm.smax.v4i32(<4 x i32> %a, <4 x i32> %b) -#[no_mangle] -#[target_feature(enable = "vector")] -pub unsafe extern "C" fn max_i32x4(a: i32x4, b: i32x4) -> i32x4 { - vmxf(a, b) -} - -// CHECK-LABEL: define <2 x i64> @max_i64x2 -// CHECK-SAME: <2 x i64> %a, <2 x i64> %b -// CHECK: call <2 x i64> @llvm.smax.v2i64(<2 x i64> %a, <2 x i64> %b) -#[no_mangle] -#[target_feature(enable = "vector")] -pub unsafe extern "C" fn max_i64x2(a: i64x2, b: i64x2) -> i64x2 { - vmxg(a, b) -} - -// CHECK-LABEL: define <4 x float> @choose_f32x4 -// CHECK-SAME: <4 x float> %a, <4 x float> %b -#[no_mangle] -#[target_feature(enable = "vector")] -pub unsafe extern "C" fn choose_f32x4(a: f32x4, b: f32x4, c: bool) -> f32x4 { - if c { a } else { b } -} - -// CHECK-LABEL: define <2 x double> @choose_f64x2 -// CHECK-SAME: <2 x double> %a, <2 x double> %b -#[no_mangle] -#[target_feature(enable = "vector")] -pub unsafe extern "C" fn choose_f64x2(a: f64x2, b: f64x2, c: bool) -> f64x2 { - if c { a } else { b } -} - -#[repr(C)] -struct Wrapper(T); - -#[no_mangle] -#[inline(never)] -#[target_feature(enable = "vector")] -pub unsafe extern "C" fn max_wrapper_i8x16(a: Wrapper, b: Wrapper) -> Wrapper { - // CHECK-LABEL: max_wrapper_i8x16 - // CHECK-SAME: sret([16 x i8]) - // CHECK-SAME: <16 x i8> - // CHECK-SAME: <16 x i8> - // CHECK: call <16 x i8> @llvm.smax.v16i8 - // CHECK-SAME: <16 x i8> - // CHECK-SAME: <16 x i8> - Wrapper(vmxb(a.0, b.0)) -} - -#[no_mangle] -#[inline(never)] -#[target_feature(enable = "vector")] -pub unsafe extern "C" fn max_wrapper_i64x2(a: Wrapper, b: Wrapper) -> Wrapper { - // CHECK-LABEL: max_wrapper_i64x2 - // CHECK-SAME: sret([16 x i8]) - // CHECK-SAME: <16 x i8> - // CHECK-SAME: <16 x i8> - // CHECK: call <2 x i64> @llvm.smax.v2i64 - // CHECK-SAME: <2 x i64> - // CHECK-SAME: <2 x i64> - Wrapper(vmxg(a.0, b.0)) -} - -#[no_mangle] -#[inline(never)] -#[target_feature(enable = "vector")] -pub unsafe extern "C" fn choose_wrapper_f64x2( - a: Wrapper, - b: Wrapper, - c: bool, -) -> Wrapper { - // CHECK-LABEL: choose_wrapper_f64x2 - // CHECK-SAME: sret([16 x i8]) - // CHECK-SAME: <16 x i8> - // CHECK-SAME: <16 x i8> - Wrapper(choose_f64x2(a.0, b.0, c)) -} - -// CHECK: declare <2 x i64> @llvm.smax.v2i64(<2 x i64>, <2 x i64>) diff --git a/tests/codegen/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs b/tests/codegen/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs deleted file mode 100644 index e1d7dc2d631..00000000000 --- a/tests/codegen/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ add-core-stubs -//@ revisions: aarch64 android -//@[aarch64] compile-flags: --target aarch64-unknown-none -Zfixed-x18 -Zsanitizer=shadow-call-stack -//@[aarch64] needs-llvm-components: aarch64 -//@[android] compile-flags: --target aarch64-linux-android -Zsanitizer=shadow-call-stack -//@[android] needs-llvm-components: aarch64 - -#![allow(internal_features)] -#![crate_type = "rlib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK: ; Function Attrs:{{.*}}shadowcallstack -#[no_mangle] -pub fn foo() {} - -// CHECK: attributes #0 = {{.*}}shadowcallstack{{.*}} diff --git a/tests/codegen/sanitizer/address-sanitizer-globals-tracking.rs b/tests/codegen/sanitizer/address-sanitizer-globals-tracking.rs deleted file mode 100644 index f319306f93f..00000000000 --- a/tests/codegen/sanitizer/address-sanitizer-globals-tracking.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Verifies that AddressSanitizer symbols show up as expected in LLVM IR with `-Zsanitizer`. -// This is a regression test for https://github.com/rust-lang/rust/issues/113404 -// -// Notes about the `compile-flags` below: -// -// * The original issue only reproed with LTO - this is why this angle has -// extra test coverage via different `revisions` -// * To observe the failure/repro at LLVM-IR level we need to use `staticlib` -// which necessitates `-C prefer-dynamic=false` - without the latter flag, -// we would have run into "cannot prefer dynamic linking when performing LTO". -// -// The test is restricted to `only-linux`, because the sanitizer-related instrumentation is target -// specific. In particular, `___asan_globals_registered` is only used in the -// `InstrumentGlobalsELF` and `InstrumentGlobalsMachO` code paths. The `only-linux` filter is -// narrower than really needed (i.e. narrower than ELF-or-MachO), but this seems ok - having a -// linux-only regression test should be sufficient here. -// -//@ needs-sanitizer-address -//@ only-linux -// -//@ revisions:ASAN ASAN-FAT-LTO -//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static -//@[ASAN] compile-flags: -//@[ASAN-FAT-LTO] compile-flags: -Cprefer-dynamic=false -Clto=fat - -#![crate_type = "staticlib"] - -// The test below mimics `CACHED_POW10` from `library/core/src/num/flt2dec/strategy/grisu.rs` which -// (because of incorrect handling of `___asan_globals_registered` during LTO) was incorrectly -// reported as an ODR violation in https://crbug.com/1459233#c1. Before this bug was fixed, -// `___asan_globals_registered` would show up as `internal global i64` rather than `common hidden -// global i64`. (The test expectations ignore the exact type because on `arm-android` the type -// is `i32` rather than `i64`.) -// -// CHECK: @___asan_globals_registered = common hidden global -// CHECK: @__start_asan_globals = extern_weak hidden global -// CHECK: @__stop_asan_globals = extern_weak hidden global -#[no_mangle] -pub static CACHED_POW10: [(u64, i16, i16); 4] = [ - (0xe61acf033d1a45df, -1087, -308), - (0xab70fe17c79ac6ca, -1060, -300), - (0xff77b1fcbebcdc4f, -1034, -292), - (0xbe5691ef416bd60c, -1007, -284), -]; diff --git a/tests/codegen/sanitizer/cfi/add-canonical-jump-tables-flag.rs b/tests/codegen/sanitizer/cfi/add-canonical-jump-tables-flag.rs deleted file mode 100644 index 22577e2a3c4..00000000000 --- a/tests/codegen/sanitizer/cfi/add-canonical-jump-tables-flag.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Verifies that "CFI Canonical Jump Tables" module flag is added. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi - -#![crate_type = "lib"] - -pub fn foo() {} - -// CHECK: !{{[0-9]+}} = !{i32 4, !"CFI Canonical Jump Tables", i32 1} diff --git a/tests/codegen/sanitizer/cfi/add-cfi-normalize-integers-flag.rs b/tests/codegen/sanitizer/cfi/add-cfi-normalize-integers-flag.rs deleted file mode 100644 index a54a6d84a80..00000000000 --- a/tests/codegen/sanitizer/cfi/add-cfi-normalize-integers-flag.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Verifies that "cfi-normalize-integers" module flag is added. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers - -#![crate_type = "lib"] - -pub fn foo() {} - -// CHECK: !{{[0-9]+}} = !{i32 4, !"cfi-normalize-integers", i32 1} diff --git a/tests/codegen/sanitizer/cfi/add-enable-split-lto-unit-flag.rs b/tests/codegen/sanitizer/cfi/add-enable-split-lto-unit-flag.rs deleted file mode 100644 index 283b8f26102..00000000000 --- a/tests/codegen/sanitizer/cfi/add-enable-split-lto-unit-flag.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Verifies that "EnableSplitLTOUnit" module flag is added. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi - -#![crate_type = "lib"] - -pub fn foo() {} - -// CHECK: !{{[0-9]+}} = !{i32 4, !"EnableSplitLTOUnit", i32 1} diff --git a/tests/codegen/sanitizer/cfi/dbg-location-on-cfi-blocks.rs b/tests/codegen/sanitizer/cfi/dbg-location-on-cfi-blocks.rs deleted file mode 100644 index df65960dfe0..00000000000 --- a/tests/codegen/sanitizer/cfi/dbg-location-on-cfi-blocks.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Verifies that the parent block's debug information are assigned to the inserted cfi block. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -Cdebuginfo=1 - -#![crate_type = "lib"] - -pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: define{{.*}}foo{{.*}}!dbg !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - // CHECK: start: - // CHECK: [[TT:%.+]] = call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"{{[[:print:]]+}}"), !dbg !{{[0-9]+}} - // CHECK-NEXT: br i1 [[TT]], label %type_test.pass, label %type_test.fail, !dbg !{{[0-9]+}} - // CHECK: type_test.pass: ; preds = %start - // CHECK-NEXT: {{%.+}} = call i32 %f(i32{{.*}} %arg), !dbg !{{[0-9]+}} - // CHECK: type_test.fail: ; preds = %start - // CHECK-NEXT: call void @llvm.trap(), !dbg !{{[0-9]+}} - // CHECK-NEXT: unreachable, !dbg !{{[0-9]+}} - f(arg) -} diff --git a/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs b/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs deleted file mode 100644 index 71ccdc8ca62..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Verifies that pointer type membership tests for indirect calls are omitted. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 - -#![crate_type = "lib"] -#![feature(no_sanitize)] - -#[no_sanitize(cfi)] -pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: emit_type_checks_attr_no_sanitize::foo - // CHECK: Function Attrs: {{.*}} - // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - // CHECK: start: - // CHECK-NEXT: {{%.+}} = call i32 %f(i32{{.*}} %arg) - // CHECK-NEXT: ret i32 {{%.+}} - f(arg) -} diff --git a/tests/codegen/sanitizer/cfi/emit-type-checks.rs b/tests/codegen/sanitizer/cfi/emit-type-checks.rs deleted file mode 100644 index ebc66a015df..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-checks.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Verifies that pointer type membership tests for indirect calls are emitted. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 - -#![crate_type = "lib"] - -pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - // CHECK: start: - // CHECK: [[TT:%.+]] = call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"{{[[:print:]]+}}") - // CHECK-NEXT: br i1 [[TT]], label %type_test.pass, label %type_test.fail - // CHECK: type_test.pass: - // CHECK-NEXT: {{%.+}} = call i32 %f(i32{{.*}} %arg) - // CHECK: type_test.fail: - // CHECK-NEXT: call void @llvm.trap() - // CHECK-NEXT: unreachable - f(arg) -} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs deleted file mode 100644 index 9bc2e42db0f..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs +++ /dev/null @@ -1,73 +0,0 @@ -// Verifies that user-defined CFI encoding for types are emitted. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 - -#![crate_type = "lib"] -#![feature(cfi_encoding, extern_types)] - -#[cfi_encoding = "3Foo"] -pub struct Type1(i32); - -extern "C" { - #[cfi_encoding = "3Bar"] - type Type2; -} - -#[cfi_encoding = "3Baz"] -#[repr(transparent)] -pub struct Type3(i32); - -#[cfi_encoding = "i"] -pub struct Type4(i32); - -#[cfi_encoding = "j"] -#[repr(transparent)] -pub struct Type5(u32); - -pub fn foo0(_: Type1) {} -// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo1(_: Type1, _: Type1) {} -// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo2(_: Type1, _: Type1, _: Type1) {} -// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo3(_: *mut Type2) {} -// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo4(_: *mut Type2, _: *mut Type2) {} -// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo5(_: *mut Type2, _: *mut Type2, _: *mut Type2) {} -// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo6(_: *mut Type3) {} -// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo7(_: *mut Type3, _: *mut Type3) {} -// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo8(_: *mut Type3, _: *mut Type3, _: *mut Type3) {} -// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo9(_: Type4) {} -// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo10(_: Type4, _: Type4) {} -// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo11(_: Type4, _: Type4, _: Type4) {} -// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo12(_: Type5) {} -// CHECK: define{{.*}}foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo13(_: Type5, _: Type5) {} -// CHECK: define{{.*}}foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo14(_: Type5, _: Type5, _: Type5) {} -// CHECK: define{{.*}}foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - -// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFv3FooE"} -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFv3FooS_E"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFv3FooS_S_E"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvP3BarE"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvP3BarS0_E"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvP3BarS0_S0_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvP3BazE"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvP3BazS0_E"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvP3BazS0_S0_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFviE"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFviiE"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFviiiE"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvjE"} -// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvjjE"} -// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvjjjE"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs deleted file mode 100644 index 9048c6a1f18..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Verifies that type metadata identifiers for functions are emitted correctly -// for const generics. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 - -#![crate_type = "lib"] -#![feature(type_alias_impl_trait)] - -extern crate core; - -pub type Type1 = impl Send; - -#[define_opaque(Type1)] -pub fn foo() -where - Type1: 'static, -{ - pub struct Foo([T; N]); - let _: Type1 = Foo([0; 32]); -} - -pub fn foo1(_: Type1) {} -// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo2(_: Type1, _: Type1) {} -// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo3(_: Type1, _: Type1, _: Type1) {} -// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooIu3i32Lu5usize32EEE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooIu3i32Lu5usize32EES2_E"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooIu3i32Lu5usize32EES2_S2_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs deleted file mode 100644 index 8fec275fd06..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Verifies that type metadata identifiers for drop functions are emitted correctly. -// -// Non needs_drop drop glue isn't codegen'd at all, so we don't try to check the IDs there. But we -// do check it's not emitted which should help catch bugs if we do start generating it again in the -// future. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static - -#![crate_type = "lib"] - -// CHECK-LABEL: define{{.*}}4core3ptr47drop_in_place$LT$dyn$u20$core..marker..Send$GT$ -// CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -// CHECK: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE") - -struct EmptyDrop; -// CHECK-NOT: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}EmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - -struct PresentDrop; - -impl Drop for PresentDrop { - fn drop(&mut self) {} - // CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}PresentDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -} - -pub fn foo() { - let _ = Box::new(EmptyDrop) as Box; - let _ = Box::new(PresentDrop) as Box; -} - -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs deleted file mode 100644 index 7e60aafff68..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Verifies that type metadata identifiers for functions are emitted correctly -// for function types. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static - -#![crate_type = "lib"] - -pub fn foo1(_: fn(i32) -> i32) {} -// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo2(_: fn(i32) -> i32, _: fn(i32) -> i32) {} -// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo3(_: fn(i32) -> i32, _: fn(i32) -> i32, _: fn(i32) -> i32) {} -// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo4(_: &dyn Fn(i32) -> i32) {} -// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo5(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) {} -// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo6(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) {} -// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo7(_: &dyn FnMut(i32) -> i32) {} -// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo8(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) {} -// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo9(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) {} -// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo10(_: &dyn FnOnce(i32) -> i32) {} -// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo11(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) {} -// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo12(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) {} -// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs deleted file mode 100644 index 36d2e8c9f25..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Verifies that type metadata identifiers for functions are emitted correctly -// for lifetimes/regions. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 - -#![crate_type = "lib"] -#![feature(type_alias_impl_trait)] - -extern crate core; - -pub type Type1 = impl Send; - -#[define_opaque(Type1)] -pub fn foo<'a>() -where - Type1: 'static, -{ - pub struct Foo<'a>(&'a i32); - pub struct Bar<'a, 'b>(&'a i32, &'b Foo<'b>); - let _: Type1 = Bar; -} - -pub fn foo1(_: Type1) {} -// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo2(_: Type1, _: Type1) {} -// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo3(_: Type1, _: Type1, _: Type1) {} -// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs deleted file mode 100644 index 9d611777ff0..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Verifies that a secondary type metadata identifier is assigned to methods with their concrete -// self so they can be used as function pointers. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static - -#![crate_type = "lib"] - -trait Trait1 { - fn foo(&self); -} - -struct Type1; - -impl Trait1 for Type1 { - fn foo(&self) {} - // CHECK: define{{.*}}3foo{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} -} - -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type1EE"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs deleted file mode 100644 index a8ba8db1be3..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Verifies that type metadata identifiers for functions are emitted correctly -// for paths. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static - -#![crate_type = "lib"] -#![feature(type_alias_impl_trait)] - -extern crate core; - -pub type Type1 = impl Send; -pub type Type2 = impl Send; -pub type Type3 = impl Send; -pub type Type4 = impl Send; - -#[define_opaque(Type1, Type2, Type4)] -pub fn foo() { - // Type in extern path - extern "C" { - fn bar(); - } - let _: Type1 = bar; - - // Type in closure path - || { - pub struct Foo; - let _: Type2 = Foo; - }; - - // Type in const path - const { - pub struct Foo; - #[define_opaque(Type3)] - fn bar() -> Type3 { - Foo - } - }; - - // Type in impl path - struct Foo; - impl Foo { - fn bar(&self) {} - } - let _: Type4 = ::bar; -} - -// Force arguments to be passed by using a reference. Otherwise, they may end up PassMode::Ignore - -pub fn foo1(_: &Type1) {} -// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo2(_: &Type1, _: &Type1) {} -// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo3(_: &Type1, _: &Type1, _: &Type1) {} -// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo4(_: &Type2) {} -// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo5(_: &Type2, _: &Type2) {} -// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo6(_: &Type2, _: &Type2, _: &Type2) {} -// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo7(_: &Type3) {} -// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo8(_: &Type3, _: &Type3) {} -// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo9(_: &Type3, _: &Type3, _: &Type3) {} -// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo10(_: &Type4) {} -// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo11(_: &Type4, _: &Type4) {} -// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo12(_: &Type4, _: &Type4, _: &Type4) {} -// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barEE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_E"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_S0_E"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooEE"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_S0_E"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooEE"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_S0_E"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barEE"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_E"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_S0_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs deleted file mode 100644 index d37bb740f55..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs +++ /dev/null @@ -1,54 +0,0 @@ -// Verifies that type metadata identifiers for functions are emitted correctly -// for pointer types. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static - -#![crate_type = "lib"] - -pub fn foo1(_: &mut i32) {} -// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo2(_: &mut i32, _: &i32) {} -// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo3(_: &mut i32, _: &i32, _: &i32) {} -// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo4(_: &i32) {} -// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo5(_: &i32, _: &mut i32) {} -// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo6(_: &i32, _: &mut i32, _: &mut i32) {} -// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo7(_: *mut i32) {} -// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo8(_: *mut i32, _: *const i32) {} -// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo9(_: *mut i32, _: *const i32, _: *const i32) {} -// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo10(_: *const i32) {} -// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo11(_: *const i32, _: *mut i32) {} -// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo12(_: *const i32, _: *mut i32, _: *mut i32) {} -// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo13(_: fn(i32) -> i32) {} -// CHECK: define{{.*}}5foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo14(_: fn(i32) -> i32, _: fn(i32) -> i32) {} -// CHECK: define{{.*}}5foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo15(_: fn(i32) -> i32, _: fn(i32) -> i32, _: fn(i32) -> i32) {} -// CHECK: define{{.*}}5foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32EE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_E"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_S0_E"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3i32EE"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_S1_E"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPu3i32E"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPu3i32PKS_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvPu3i32PKS_S2_E"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPKu3i32E"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPKu3i32PS_E"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvPKu3i32PS_S2_E"} -// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"} -// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"} -// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs deleted file mode 100644 index 7d9e4d05872..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs +++ /dev/null @@ -1,190 +0,0 @@ -// Verifies that type metadata identifiers for functions are emitted correctly -// for primitive types. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static - -#![crate_type = "lib"] - -extern crate core; -use core::ffi::*; - -pub fn foo1(_: ()) {} -// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo2(_: (), _: c_void) {} -// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo3(_: (), _: c_void, _: c_void) {} -// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo4(_: *mut ()) {} -// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo5(_: *mut (), _: *mut c_void) {} -// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo6(_: *mut (), _: *mut c_void, _: *mut c_void) {} -// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo7(_: *const ()) {} -// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo8(_: *const (), _: *const c_void) {} -// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo9(_: *const (), _: *const c_void, _: *const c_void) {} -// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo10(_: bool) {} -// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo11(_: bool, _: bool) {} -// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo12(_: bool, _: bool, _: bool) {} -// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo13(_: i8) {} -// CHECK: define{{.*}}5foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo14(_: i8, _: i8) {} -// CHECK: define{{.*}}5foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo15(_: i8, _: i8, _: i8) {} -// CHECK: define{{.*}}5foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo16(_: i16) {} -// CHECK: define{{.*}}5foo16{{.*}}!type ![[TYPE16:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo17(_: i16, _: i16) {} -// CHECK: define{{.*}}5foo17{{.*}}!type ![[TYPE17:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo18(_: i16, _: i16, _: i16) {} -// CHECK: define{{.*}}5foo18{{.*}}!type ![[TYPE18:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo19(_: i32) {} -// CHECK: define{{.*}}5foo19{{.*}}!type ![[TYPE19:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo20(_: i32, _: i32) {} -// CHECK: define{{.*}}5foo20{{.*}}!type ![[TYPE20:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo21(_: i32, _: i32, _: i32) {} -// CHECK: define{{.*}}5foo21{{.*}}!type ![[TYPE21:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo22(_: i64) {} -// CHECK: define{{.*}}5foo22{{.*}}!type ![[TYPE22:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo23(_: i64, _: i64) {} -// CHECK: define{{.*}}5foo23{{.*}}!type ![[TYPE23:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo24(_: i64, _: i64, _: i64) {} -// CHECK: define{{.*}}5foo24{{.*}}!type ![[TYPE24:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo25(_: i128) {} -// CHECK: define{{.*}}5foo25{{.*}}!type ![[TYPE25:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo26(_: i128, _: i128) {} -// CHECK: define{{.*}}5foo26{{.*}}!type ![[TYPE26:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo27(_: i128, _: i128, _: i128) {} -// CHECK: define{{.*}}5foo27{{.*}}!type ![[TYPE27:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo28(_: isize) {} -// CHECK: define{{.*}}5foo28{{.*}}!type ![[TYPE28:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo29(_: isize, _: isize) {} -// CHECK: define{{.*}}5foo29{{.*}}!type ![[TYPE29:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo30(_: isize, _: isize, _: isize) {} -// CHECK: define{{.*}}5foo30{{.*}}!type ![[TYPE30:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo31(_: u8) {} -// CHECK: define{{.*}}5foo31{{.*}}!type ![[TYPE31:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo32(_: u8, _: u8) {} -// CHECK: define{{.*}}5foo32{{.*}}!type ![[TYPE32:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo33(_: u8, _: u8, _: u8) {} -// CHECK: define{{.*}}5foo33{{.*}}!type ![[TYPE33:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo34(_: u16) {} -// CHECK: define{{.*}}5foo34{{.*}}!type ![[TYPE34:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo35(_: u16, _: u16) {} -// CHECK: define{{.*}}5foo35{{.*}}!type ![[TYPE35:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo36(_: u16, _: u16, _: u16) {} -// CHECK: define{{.*}}5foo36{{.*}}!type ![[TYPE36:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo37(_: u32) {} -// CHECK: define{{.*}}5foo37{{.*}}!type ![[TYPE37:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo38(_: u32, _: u32) {} -// CHECK: define{{.*}}5foo38{{.*}}!type ![[TYPE38:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo39(_: u32, _: u32, _: u32) {} -// CHECK: define{{.*}}5foo39{{.*}}!type ![[TYPE39:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo40(_: u64) {} -// CHECK: define{{.*}}5foo40{{.*}}!type ![[TYPE40:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo41(_: u64, _: u64) {} -// CHECK: define{{.*}}5foo41{{.*}}!type ![[TYPE41:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo42(_: u64, _: u64, _: u64) {} -// CHECK: define{{.*}}5foo42{{.*}}!type ![[TYPE42:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo43(_: u128) {} -// CHECK: define{{.*}}5foo43{{.*}}!type ![[TYPE43:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo44(_: u128, _: u128) {} -// CHECK: define{{.*}}5foo44{{.*}}!type ![[TYPE44:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo45(_: u128, _: u128, _: u128) {} -// CHECK: define{{.*}}5foo45{{.*}}!type ![[TYPE45:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo46(_: usize) {} -// CHECK: define{{.*}}5foo46{{.*}}!type ![[TYPE46:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo47(_: usize, _: usize) {} -// CHECK: define{{.*}}5foo47{{.*}}!type ![[TYPE47:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo48(_: usize, _: usize, _: usize) {} -// CHECK: define{{.*}}5foo48{{.*}}!type ![[TYPE48:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo49(_: f32) {} -// CHECK: define{{.*}}5foo49{{.*}}!type ![[TYPE49:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo50(_: f32, _: f32) {} -// CHECK: define{{.*}}5foo50{{.*}}!type ![[TYPE50:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo51(_: f32, _: f32, _: f32) {} -// CHECK: define{{.*}}5foo51{{.*}}!type ![[TYPE51:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo52(_: f64) {} -// CHECK: define{{.*}}5foo52{{.*}}!type ![[TYPE52:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo53(_: f64, _: f64) {} -// CHECK: define{{.*}}5foo53{{.*}}!type ![[TYPE53:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo54(_: f64, _: f64, _: f64) {} -// CHECK: define{{.*}}5foo54{{.*}}!type ![[TYPE54:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo55(_: char) {} -// CHECK: define{{.*}}5foo55{{.*}}!type ![[TYPE55:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo56(_: char, _: char) {} -// CHECK: define{{.*}}5foo56{{.*}}!type ![[TYPE56:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo57(_: char, _: char, _: char) {} -// CHECK: define{{.*}}5foo57{{.*}}!type ![[TYPE57:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo58(_: &str) {} -// CHECK: define{{.*}}5foo58{{.*}}!type ![[TYPE58:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo59(_: &str, _: &str) {} -// CHECK: define{{.*}}5foo59{{.*}}!type ![[TYPE59:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo60(_: &str, _: &str, _: &str) {} -// CHECK: define{{.*}}5foo60{{.*}}!type ![[TYPE60:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvE"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvPvE"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvPvS_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPvS_S_E"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPKvE"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPKvS0_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvPKvS0_S0_E"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvbE"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvbbE"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvbbbE"} -// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu2i8E"} -// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu2i8S_E"} -// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu2i8S_S_E"} -// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3i16E"} -// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3i16S_E"} -// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3i16S_S_E"} -// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3i32E"} -// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3i32S_E"} -// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3i32S_S_E"} -// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3i64E"} -// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3i64S_E"} -// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu3i64S_S_E"} -// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu4i128E"} -// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu4i128S_E"} -// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu4i128S_S_E"} -// CHECK: ![[TYPE28]] = !{i64 0, !"_ZTSFvu5isizeE"} -// CHECK: ![[TYPE29]] = !{i64 0, !"_ZTSFvu5isizeS_E"} -// CHECK: ![[TYPE30]] = !{i64 0, !"_ZTSFvu5isizeS_S_E"} -// CHECK: ![[TYPE31]] = !{i64 0, !"_ZTSFvu2u8E"} -// CHECK: ![[TYPE32]] = !{i64 0, !"_ZTSFvu2u8S_E"} -// CHECK: ![[TYPE33]] = !{i64 0, !"_ZTSFvu2u8S_S_E"} -// CHECK: ![[TYPE34]] = !{i64 0, !"_ZTSFvu3u16E"} -// CHECK: ![[TYPE35]] = !{i64 0, !"_ZTSFvu3u16S_E"} -// CHECK: ![[TYPE36]] = !{i64 0, !"_ZTSFvu3u16S_S_E"} -// CHECK: ![[TYPE37]] = !{i64 0, !"_ZTSFvu3u32E"} -// CHECK: ![[TYPE38]] = !{i64 0, !"_ZTSFvu3u32S_E"} -// CHECK: ![[TYPE39]] = !{i64 0, !"_ZTSFvu3u32S_S_E"} -// CHECK: ![[TYPE40]] = !{i64 0, !"_ZTSFvu3u64E"} -// CHECK: ![[TYPE41]] = !{i64 0, !"_ZTSFvu3u64S_E"} -// CHECK: ![[TYPE42]] = !{i64 0, !"_ZTSFvu3u64S_S_E"} -// CHECK: ![[TYPE43]] = !{i64 0, !"_ZTSFvu4u128E"} -// CHECK: ![[TYPE44]] = !{i64 0, !"_ZTSFvu4u128S_E"} -// CHECK: ![[TYPE45]] = !{i64 0, !"_ZTSFvu4u128S_S_E"} -// CHECK: ![[TYPE46]] = !{i64 0, !"_ZTSFvu5usizeE"} -// CHECK: ![[TYPE47]] = !{i64 0, !"_ZTSFvu5usizeS_E"} -// CHECK: ![[TYPE48]] = !{i64 0, !"_ZTSFvu5usizeS_S_E"} -// CHECK: ![[TYPE49]] = !{i64 0, !"_ZTSFvfE"} -// CHECK: ![[TYPE50]] = !{i64 0, !"_ZTSFvffE"} -// CHECK: ![[TYPE51]] = !{i64 0, !"_ZTSFvfffE"} -// CHECK: ![[TYPE52]] = !{i64 0, !"_ZTSFvdE"} -// CHECK: ![[TYPE53]] = !{i64 0, !"_ZTSFvddE"} -// CHECK: ![[TYPE54]] = !{i64 0, !"_ZTSFvdddE"} -// CHECK: ![[TYPE55]] = !{i64 0, !"_ZTSFvu4charE"} -// CHECK: ![[TYPE56]] = !{i64 0, !"_ZTSFvu4charS_E"} -// CHECK: ![[TYPE57]] = !{i64 0, !"_ZTSFvu4charS_S_E"} -// CHECK: ![[TYPE58]] = !{i64 0, !"_ZTSFvu3refIu3strEE"} -// CHECK: ![[TYPE59]] = !{i64 0, !"_ZTSFvu3refIu3strES0_E"} -// CHECK: ![[TYPE60]] = !{i64 0, !"_ZTSFvu3refIu3strES0_S0_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs deleted file mode 100644 index 0f97c70f3f9..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Verifies that type metadata identifiers for functions are emitted correctly -// for repr transparent types. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static - -#![crate_type = "lib"] - -extern crate core; -use core::ffi::*; -use std::marker::PhantomData; - -struct Foo(i32); - -// repr(transparent) user-defined type -#[repr(transparent)] -pub struct Type1 { - member1: (), - member2: PhantomData, - member3: Foo, -} - -// Self-referencing repr(transparent) user-defined type -#[repr(transparent)] -pub struct Type2<'a> { - member1: (), - member2: PhantomData, - member3: &'a Type2<'a>, -} - -pub struct Bar(i32); - -// repr(transparent) user-defined generic type -#[repr(transparent)] -pub struct Type3(T); - -// repr(transparent) wrapper which engages in self-reference -#[repr(transparent)] -pub struct Type4(Type4Helper); -#[repr(transparent)] -pub struct Type4Helper(*mut T); - -pub fn foo1(_: Type1) {} -// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo2(_: Type1, _: Type1) {} -// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo3(_: Type1, _: Type1, _: Type1) {} -// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo4(_: Type2) {} -// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo5(_: Type2, _: Type2) {} -// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo6(_: Type2, _: Type2, _: Type2) {} -// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo7(_: Type3) {} -// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo8(_: Type3, _: Type3) {} -// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo9(_: Type3, _: Type3, _: Type3) {} -// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo10(_: Type4) {} -// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo11(_: Type4, _: Type4) {} -// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo12(_: Type4, _: Type4, _: Type4) {} -// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooS_E"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooS_S_E"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIvEE"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIvES_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIvES_S_E"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarE"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarS_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarS_S_E"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4E"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4S0_E"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4S0_S0_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs deleted file mode 100644 index bdee3f47a83..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Verifies that type metadata identifiers for functions are emitted correctly -// for sequence types. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static - -#![crate_type = "lib"] - -pub fn foo1(_: (i32, i32)) {} -// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo2(_: (i32, i32), _: (i32, i32)) {} -// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo3(_: (i32, i32), _: (i32, i32), _: (i32, i32)) {} -// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo4(_: [i32; 32]) {} -// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo5(_: [i32; 32], _: [i32; 32]) {} -// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo6(_: [i32; 32], _: [i32; 32], _: [i32; 32]) {} -// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo7(_: &[i32]) {} -// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo8(_: &[i32], _: &[i32]) {} -// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo9(_: &[i32], _: &[i32], _: &[i32]) {} -// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_EE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_E"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_S0_E"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvA32u3i32E"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvA32u3i32S0_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvA32u3i32S0_S0_E"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EEE"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_S1_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs deleted file mode 100644 index 55e816178f8..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs +++ /dev/null @@ -1,175 +0,0 @@ -// Verifies that type metadata identifiers for functions are emitted correctly -// for trait types. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static - -#![crate_type = "lib"] - -extern crate core; - -pub trait Trait1 { - fn foo(&self); -} - -#[derive(Clone, Copy)] -pub struct Type1; - -impl Trait1 for Type1 { - fn foo(&self) {} -} - -pub trait Trait2 { - fn bar(&self); -} - -pub struct Type2; - -impl Trait2 for Type2 { - fn bar(&self) {} -} - -pub trait Trait3 { - fn baz(&self, _: &T); -} - -pub struct Type3; - -impl Trait3 for T { - fn baz(&self, _: &U) {} -} - -pub trait Trait4<'a, T> { - type Output: 'a; - fn qux(&self, _: &T) -> Self::Output; -} - -pub struct Type4; - -impl<'a, T, U> Trait4<'a, U> for T { - type Output = &'a i32; - fn qux(&self, _: &U) -> Self::Output { - &0 - } -} - -pub trait Trait5 { - fn quux(&self, _: &[T; N]); -} - -#[derive(Copy, Clone)] -pub struct Type5; - -impl Trait5 for T { - fn quux(&self, _: &[U; N]) {} -} - -pub fn foo1(_: &dyn Send) {} -// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo2(_: &dyn Send, _: &dyn Send) {} -// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo3(_: &dyn Send, _: &dyn Send, _: &dyn Send) {} -// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo4(_: &(dyn Send + Sync)) {} -// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo5(_: &(dyn Send + Sync), _: &(dyn Sync + Send)) {} -// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo6(_: &(dyn Send + Sync), _: &(dyn Sync + Send), _: &(dyn Sync + Send)) {} -// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo7(_: &(dyn Trait1 + Send)) {} -// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo8(_: &(dyn Trait1 + Send), _: &(dyn Trait1 + Send)) {} -// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo9(_: &(dyn Trait1 + Send), _: &(dyn Trait1 + Send), _: &(dyn Trait1 + Send)) {} -// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo10(_: &(dyn Trait1 + Send + Sync)) {} -// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo11(_: &(dyn Trait1 + Send + Sync), _: &(dyn Trait1 + Sync + Send)) {} -// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo12( - _: &(dyn Trait1 + Send + Sync), - _: &(dyn Trait1 + Sync + Send), - _: &(dyn Trait1 + Sync + Send), -) { -} -// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo13(_: &dyn Trait1) {} -// CHECK: define{{.*}}5foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo14(_: &dyn Trait1, _: &dyn Trait1) {} -// CHECK: define{{.*}}5foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo15(_: &dyn Trait1, _: &dyn Trait1, _: &dyn Trait1) {} -// CHECK: define{{.*}}5foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo16(_: &dyn Trait2) {} -pub fn bar16() { - let a = Type2; - foo16(&a); -} -// CHECK: define{{.*}}5foo16{{.*}}!type ![[TYPE16:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo17(_: &dyn Trait2, _: &dyn Trait2) {} -pub fn bar17() { - let a = Type2; - foo17(&a, &a); -} -// CHECK: define{{.*}}5foo17{{.*}}!type ![[TYPE17:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo18(_: &dyn Trait2, _: &dyn Trait2, _: &dyn Trait2) {} -pub fn bar18() { - let a = Type2; - foo18(&a, &a, &a); -} -// CHECK: define{{.*}}5foo18{{.*}}!type ![[TYPE18:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo19(_: &dyn Trait3) {} -// CHECK: define{{.*}}5foo19{{.*}}!type ![[TYPE19:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo20(_: &dyn Trait3, _: &dyn Trait3) {} -// CHECK: define{{.*}}5foo20{{.*}}!type ![[TYPE20:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo21(_: &dyn Trait3, _: &dyn Trait3, _: &dyn Trait3) {} -// CHECK: define{{.*}}5foo21{{.*}}!type ![[TYPE21:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo22<'a>(_: &dyn Trait4<'a, Type4, Output = &'a i32>) {} -// CHECK: define{{.*}}5foo22{{.*}}!type ![[TYPE22:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo23<'a>( - _: &dyn Trait4<'a, Type4, Output = &'a i32>, - _: &dyn Trait4<'a, Type4, Output = &'a i32>, -) { -} -// CHECK: define{{.*}}5foo23{{.*}}!type ![[TYPE23:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo24<'a>( - _: &dyn Trait4<'a, Type4, Output = &'a i32>, - _: &dyn Trait4<'a, Type4, Output = &'a i32>, - _: &dyn Trait4<'a, Type4, Output = &'a i32>, -) { -} -// CHECK: define{{.*}}5foo24{{.*}}!type ![[TYPE24:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo25(_: &dyn Trait5) {} -// CHECK: define{{.*}}5foo25{{.*}}!type ![[TYPE25:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo26(_: &dyn Trait5, _: &dyn Trait5) {} -// CHECK: define{{.*}}5foo26{{.*}}!type ![[TYPE26:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo27(_: &dyn Trait5, _: &dyn Trait5, _: &dyn Trait5) {} -// CHECK: define{{.*}}5foo27{{.*}}!type ![[TYPE27:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - -// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"} -// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEEE"} -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"} -// FIXME(rcvalle): Enforce autotraits ordering when encoding (e.g., alphabetical order) -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEEE"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES3_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES3_S3_E"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES3_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES3_S3_E"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEEE"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES4_E"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES4_S4_E"} -// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEES2_E"} -// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEES2_S2_E"} -// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEES3_E"} -// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEES3_S3_E"} -// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEEE"} -// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEES3_E"} -// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEES3_S3_E"} -// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EEE"} -// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EES6_E"} -// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EES6_S6_E"} -// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEEE"} -// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEES5_E"} -// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEES5_S5_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs deleted file mode 100644 index c1f3ca61afe..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Verifies that type metadata identifiers for functions are emitted correctly -// for user-defined types. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static - -#![crate_type = "lib"] -#![feature(extern_types)] - -pub struct Struct1 { - member1: T, -} - -pub enum Enum1 { - Variant1(T), -} - -pub union Union1 { - member1: std::mem::ManuallyDrop, -} - -extern "C" { - pub type type1; -} - -pub fn foo1(_: &Struct1) {} -// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo2(_: &Struct1, _: &Struct1) {} -// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo3(_: &Struct1, _: &Struct1, _: &Struct1) {} -// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo4(_: &Enum1) {} -// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo5(_: &Enum1, _: &Enum1) {} -// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo6(_: &Enum1, _: &Enum1, _: &Enum1) {} -// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo7(_: &Union1) {} -// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo8(_: &Union1, _: &Union1) {} -// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo9(_: &Union1, _: &Union1, _: &Union1) {} -// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo10(_: *mut type1) {} -// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo11(_: *mut type1, _: *mut type1) {} -// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo12(_: *mut type1, _: *mut type1, _: *mut type1) {} -// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}7Struct1Iu3i32EEE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}7Struct1Iu3i32EES1_E"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}7Struct1Iu3i32EES1_S1_E"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Enum1Iu3i32EEE"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Enum1Iu3i32EES1_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Enum1Iu3i32EES1_S1_E"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Union1Iu3i32EEE"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Union1Iu3i32EES1_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Union1Iu3i32EES1_S1_E"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvP5type1E"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvP5type1S0_E"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvP5type1S0_S0_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs deleted file mode 100644 index 32637b64b3e..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Verifies that generalized type metadata for functions are emitted. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers - -#![crate_type = "lib"] - -pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: define{{.*}}foo - // CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.generalized") - f(arg) -} - -pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { - // CHECK-LABEL: define{{.*}}bar - // CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.generalized") - f(arg1, arg2) -} - -pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { - // CHECK-LABEL: define{{.*}}baz - // CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.generalized") - f(arg1, arg2, arg3) -} - -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PKvS_E.generalized"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PKvS_S_E.generalized"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PKvS_S_S_E.generalized"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs deleted file mode 100644 index 51121b0aef1..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Verifies that normalized and generalized type metadata for functions are emitted. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Zsanitizer-cfi-generalize-pointers - -#![crate_type = "lib"] - -pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: define{{.*}}foo - // CHECK-SAME: {{.*}}![[TYPE1:[0-9]+]] - // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.normalized.generalized") - f(arg) -} - -pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { - // CHECK-LABEL: define{{.*}}bar - // CHECK-SAME: {{.*}}![[TYPE2:[0-9]+]] - // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.normalized.generalized") - f(arg1, arg2) -} - -pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { - // CHECK-LABEL: define{{.*}}baz - // CHECK-SAME: {{.*}}![[TYPE3:[0-9]+]] - // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.normalized.generalized") - f(arg1, arg2, arg3) -} - -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PKvS_E.normalized.generalized"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PKvS_S_E.normalized.generalized"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PKvS_S_S_E.normalized.generalized"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs deleted file mode 100644 index 1cfdd23006e..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Verifies that normalized type metadata for functions are emitted. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers - -#![crate_type = "lib"] - -pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: define{{.*}}foo - // CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.normalized") - f(arg) -} - -pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { - // CHECK-LABEL: define{{.*}}bar - // CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.normalized") - f(arg1, arg2) -} - -pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { - // CHECK-LABEL: define{{.*}}baz - // CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.normalized") - f(arg1, arg2, arg3) -} - -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PFS_S_ES_E.normalized"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_ES_S_E.normalized"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_S_ES_S_S_E.normalized"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs deleted file mode 100644 index 56ab1ce4b35..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Verifies that type metadata for functions are emitted. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi - -#![crate_type = "lib"] - -pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: define{{.*}}foo - // CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E") - f(arg) -} - -pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { - // CHECK-LABEL: define{{.*}}bar - // CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E") - f(arg1, arg2) -} - -pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { - // CHECK-LABEL: define{{.*}}baz - // CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E") - f(arg1, arg2, arg3) -} - -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PFS_S_ES_E"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_ES_S_E"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_S_ES_S_S_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-trait-objects.rs deleted file mode 100644 index 0e57ce322d1..00000000000 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-trait-objects.rs +++ /dev/null @@ -1,145 +0,0 @@ -// Verifies that type metadata identifiers for trait objects are emitted correctly. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Ctarget-feature=-crt-static -Zsanitizer=cfi - -#![crate_type = "lib"] - -pub trait Trait1 { - fn foo(&self); -} - -#[derive(Clone, Copy)] -pub struct Type1; - -impl Trait1 for Type1 { - fn foo(&self) {} -} - -pub trait Trait2 { - fn bar(&self); -} - -pub struct Type2; - -impl Trait2 for Type2 { - fn bar(&self) {} -} - -pub trait Trait3 { - fn baz(&self, _: &T); -} - -pub struct Type3; - -impl Trait3 for T { - fn baz(&self, _: &U) {} -} - -pub trait Trait4<'a, T> { - type Output: 'a; - fn qux(&self, _: &T) -> Self::Output; -} - -pub struct Type4; - -impl<'a, T, U> Trait4<'a, U> for T { - type Output = &'a i32; - fn qux(&self, _: &U) -> Self::Output { - &0 - } -} - -pub trait Trait5 { - fn quux(&self, _: &[T; N]); -} - -#[derive(Copy, Clone)] -pub struct Type5; - -impl Trait5 for T { - fn quux(&self, _: &[U; N]) {} -} - -pub fn foo1(a: &dyn Trait1) { - a.foo(); - // CHECK-LABEL: define{{.*}}4foo1{{.*}}!type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE1:[[:print:]]+]]") -} - -pub fn bar1() { - let a = Type1; - let b = &a as &dyn Trait1; - b.foo(); - // CHECK-LABEL: define{{.*}}4bar1{{.*}}!type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]") -} - -pub fn foo2(a: &dyn Trait2) { - a.bar(); - // CHECK-LABEL: define{{.*}}4foo2{{.*}}!type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]") -} - -pub fn bar2() { - let a = Type2; - foo2(&a); - let b = &a as &dyn Trait2; - b.bar(); - // CHECK-LABEL: define{{.*}}4bar2{{.*}}!type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]") -} - -pub fn foo3(a: &dyn Trait3) { - let b = Type3; - a.baz(&b); - // CHECK-LABEL: define{{.*}}4foo3{{.*}}!type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]") -} - -pub fn bar3() { - let a = Type3; - foo3(&a); - let b = &a as &dyn Trait3; - b.baz(&a); - // CHECK-LABEL: define{{.*}}4bar3{{.*}}!type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]") -} - -pub fn foo4<'a>(a: &dyn Trait4<'a, Type4, Output = &'a i32>) { - let b = Type4; - a.qux(&b); - // CHECK-LABEL: define{{.*}}4foo4{{.*}}!type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE4:[[:print:]]+]]") -} - -pub fn bar4<'a>() { - let a = Type4; - foo4(&a); - let b = &a as &dyn Trait4<'a, Type4, Output = &'a i32>; - b.qux(&a); - // CHECK-LABEL: define{{.*}}4bar4{{.*}}!type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE4:[[:print:]]+]]") -} - -pub fn foo5(a: &dyn Trait5) { - let b = &[Type5; 32]; - a.quux(&b); - // CHECK-LABEL: define{{.*}}4foo5{{.*}}!type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE5:[[:print:]]+]]") -} - -pub fn bar5() { - let a = &[Type5; 32]; - foo5(&a); - let b = &a as &dyn Trait5; - b.quux(&a); - // CHECK-LABEL: define{{.*}}4bar5{{.*}}!type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE5:[[:print:]]+]]") -} - -// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE1]]"} -// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE2]]"} -// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE3]]"} -// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE4]]"} -// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE5]]"} diff --git a/tests/codegen/sanitizer/cfi/external_weak_symbols.rs b/tests/codegen/sanitizer/cfi/external_weak_symbols.rs deleted file mode 100644 index 00e9b5029af..00000000000 --- a/tests/codegen/sanitizer/cfi/external_weak_symbols.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Verifies that type metadata identifiers for for weakly-linked symbols are -// emitted correctly. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clinker-plugin-lto -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -#![crate_type = "bin"] -#![feature(linkage)] - -unsafe extern "C" { - #[linkage = "extern_weak"] - static FOO: Option ()>; -} -// CHECK: @_rust_extern_with_linkage_FOO = internal global ptr @FOO - -fn main() { - unsafe { - if let Some(method) = FOO { - method(4.2); - // CHECK: call i1 @llvm.type.test(ptr {{%method|%0}}, metadata !"_ZTSFvdE") - } - } -} - -// CHECK: declare !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} extern_weak void @FOO(double) unnamed_addr #{{[0-9]+}} diff --git a/tests/codegen/sanitizer/cfi/generalize-pointers.rs b/tests/codegen/sanitizer/cfi/generalize-pointers.rs deleted file mode 100644 index 57004da6f8e..00000000000 --- a/tests/codegen/sanitizer/cfi/generalize-pointers.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Verifies that pointer types are generalized. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers -Copt-level=0 - -#![crate_type = "lib"] - -extern crate core; - -pub fn foo0(_: &mut i32) {} -// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo1(_: &mut i32, _: &mut i32) {} -// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo2(_: &mut i32, _: &mut i32, _: &mut i32) {} -// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo3(_: &i32) {} -// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo4(_: &i32, _: &i32) {} -// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo5(_: &i32, _: &i32, _: &i32) {} -// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo6(_: *mut i32) {} -// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo7(_: *mut i32, _: *mut i32) {} -// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo8(_: *mut i32, _: *mut i32, _: *mut i32) {} -// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo9(_: *const i32) {} -// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo10(_: *const i32, _: *const i32) {} -// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo11(_: *const i32, _: *const i32, _: *const i32) {} -// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} - -// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvU3mutu3refIvEE.generalized"} -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvU3mutu3refIvES0_E.generalized"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvU3mutu3refIvES0_S0_E.generalized"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIvEE.generalized"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIvES_E.generalized"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIvES_S_E.generalized"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPvE.generalized"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPvS_E.generalized"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPvS_S_E.generalized"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvPKvE.generalized"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPKvS0_E.generalized"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPKvS0_S0_E.generalized"} diff --git a/tests/codegen/sanitizer/cfi/normalize-integers.rs b/tests/codegen/sanitizer/cfi/normalize-integers.rs deleted file mode 100644 index 770ee4e64e0..00000000000 --- a/tests/codegen/sanitizer/cfi/normalize-integers.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Verifies that integer types are normalized. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Copt-level=0 - -#![crate_type = "lib"] - -extern crate core; - -pub fn foo0(_: bool) {} -// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}} -pub fn foo1(_: bool, _: bool) {} -// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} -pub fn foo2(_: bool, _: bool, _: bool) {} -// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} -pub fn foo3(_: char) {} -// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} -pub fn foo4(_: char, _: char) {} -// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} -pub fn foo5(_: char, _: char, _: char) {} -// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} -pub fn foo6(_: isize) {} -// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} -pub fn foo7(_: isize, _: isize) {} -// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} -pub fn foo8(_: isize, _: isize, _: isize) {} -// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} -pub fn foo9(_: (), _: usize) {} -// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} -pub fn foo10(_: (), _: usize, _: usize) {} -// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} -pub fn foo11(_: (), _: usize, _: usize, _: usize) {} -// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} - -// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvu2u8E.normalized"} -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu2u8S_E.normalized"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu2u8S_S_E.normalized"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3u32E.normalized"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3u32S_E.normalized"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3u32S_S_E.normalized"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}E.normalized"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_E.normalized"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_S_E.normalized"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}E.normalized"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}S_E.normalized"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}S_S_E.normalized"} diff --git a/tests/codegen/sanitizer/dataflow-instrument-functions.rs b/tests/codegen/sanitizer/dataflow-instrument-functions.rs deleted file mode 100644 index a2d0d63cc17..00000000000 --- a/tests/codegen/sanitizer/dataflow-instrument-functions.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Verifies that functions are instrumented. -// -//@ needs-sanitizer-dataflow -//@ compile-flags: -Copt-level=0 -Zsanitizer=dataflow - -#![crate_type = "lib"] - -pub fn foo() {} -// CHECK: define{{.*}}foo{{.*}}.dfsan diff --git a/tests/codegen/sanitizer/kasan-emits-instrumentation.rs b/tests/codegen/sanitizer/kasan-emits-instrumentation.rs deleted file mode 100644 index 774c9ab53f1..00000000000 --- a/tests/codegen/sanitizer/kasan-emits-instrumentation.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Verifies that `-Zsanitizer=kernel-address` emits sanitizer instrumentation. - -//@ add-core-stubs -//@ compile-flags: -Zsanitizer=kernel-address -Copt-level=0 -//@ revisions: aarch64 riscv64imac riscv64gc x86_64 -//@[aarch64] compile-flags: --target aarch64-unknown-none -//@[aarch64] needs-llvm-components: aarch64 -//@[riscv64imac] compile-flags: --target riscv64imac-unknown-none-elf -//@[riscv64imac] needs-llvm-components: riscv -//@[riscv64gc] compile-flags: --target riscv64gc-unknown-none-elf -//@[riscv64gc] needs-llvm-components: riscv -//@[x86_64] compile-flags: --target x86_64-unknown-none -//@[x86_64] needs-llvm-components: x86 - -#![crate_type = "rlib"] -#![feature(no_core, no_sanitize, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK-LABEL: ; kasan_emits_instrumentation::unsanitized -// CHECK-NEXT: ; Function Attrs: -// CHECK-NOT: sanitize_address -// CHECK: start: -// CHECK-NOT: call void @__asan_report_load -// CHECK: } -#[no_sanitize(address)] -pub fn unsanitized(b: &mut u8) -> u8 { - *b -} - -// CHECK-LABEL: ; kasan_emits_instrumentation::sanitized -// CHECK-NEXT: ; Function Attrs: -// CHECK: sanitize_address -// CHECK: start: -// CHECK: call void @__asan_report_load -// CHECK: } -pub fn sanitized(b: &mut u8) -> u8 { - *b -} diff --git a/tests/codegen/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs b/tests/codegen/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs deleted file mode 100644 index 0be1ff19774..00000000000 --- a/tests/codegen/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Verifies that "cfi-normalize-integers" module flag is added. -// -//@ add-core-stubs -//@ revisions: aarch64 x86_64 -//@ [aarch64] compile-flags: --target aarch64-unknown-none -//@ [aarch64] needs-llvm-components: aarch64 -//@ [x86_64] compile-flags: --target x86_64-unknown-none -//@ [x86_64] needs-llvm-components: x86 -//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -pub fn foo() {} - -// CHECK: !{{[0-9]+}} = !{i32 4, !"cfi-normalize-integers", i32 1} diff --git a/tests/codegen/sanitizer/kcfi/add-kcfi-arity-flag.rs b/tests/codegen/sanitizer/kcfi/add-kcfi-arity-flag.rs deleted file mode 100644 index 9a2290901d6..00000000000 --- a/tests/codegen/sanitizer/kcfi/add-kcfi-arity-flag.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Verifies that "kcfi-arity" module flag is added. -// -//@ add-core-stubs -//@ revisions: x86_64 -//@ [x86_64] compile-flags: --target x86_64-unknown-none -//@ [x86_64] needs-llvm-components: x86 -//@ compile-flags: -Ctarget-feature=-crt-static -Cpanic=abort -Zsanitizer=kcfi -Zsanitizer-kcfi-arity -//@ min-llvm-version: 21.0.0 - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -pub fn foo() {} - -// CHECK: !{{[0-9]+}} = !{i32 4, !"kcfi-arity", i32 1} diff --git a/tests/codegen/sanitizer/kcfi/add-kcfi-flag.rs b/tests/codegen/sanitizer/kcfi/add-kcfi-flag.rs deleted file mode 100644 index eabe0409c9a..00000000000 --- a/tests/codegen/sanitizer/kcfi/add-kcfi-flag.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Verifies that "kcfi" module flag is added. -// -//@ add-core-stubs -//@ revisions: aarch64 x86_64 -//@ [aarch64] compile-flags: --target aarch64-unknown-none -//@ [aarch64] needs-llvm-components: aarch64 -//@ [x86_64] compile-flags: --target x86_64-unknown-none -//@ [x86_64] needs-llvm-components: x86 -//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -pub fn foo() {} - -// CHECK: !{{[0-9]+}} = !{i32 4, !"kcfi", i32 1} diff --git a/tests/codegen/sanitizer/kcfi/add-kcfi-offset-flag.rs b/tests/codegen/sanitizer/kcfi/add-kcfi-offset-flag.rs deleted file mode 100644 index 2f18c9d84b9..00000000000 --- a/tests/codegen/sanitizer/kcfi/add-kcfi-offset-flag.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Verifies that "kcfi-offset" module flag is added. -// -//@ add-core-stubs -//@ revisions: aarch64 x86_64 -//@ [aarch64] compile-flags: --target aarch64-unknown-none -//@ [aarch64] needs-llvm-components: aarch64 -//@ [x86_64] compile-flags: --target x86_64-unknown-none -//@ [x86_64] needs-llvm-components: x86 -//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Z patchable-function-entry=4,3 - -#![feature(no_core, lang_items, patchable_function_entry)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -pub fn foo() {} - -// CHECK: !{{[0-9]+}} = !{i32 4, !"kcfi-offset", i32 3} diff --git a/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs b/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs deleted file mode 100644 index 6b40918dd3a..00000000000 --- a/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Verifies that KCFI operand bundles are omitted. -// -//@ add-core-stubs -//@ revisions: aarch64 x86_64 -//@ [aarch64] compile-flags: --target aarch64-unknown-none -//@ [aarch64] needs-llvm-components: aarch64 -//@ [x86_64] compile-flags: --target x86_64-unknown-none -//@ [x86_64] needs-llvm-components: -//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0 - -#![crate_type = "lib"] -#![feature(no_core, no_sanitize, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[no_sanitize(kcfi)] -pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: emit_kcfi_operand_bundle_attr_no_sanitize::foo - // CHECK: Function Attrs: {{.*}} - // CHECK-LABEL: define{{.*}}foo{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: start: - // CHECK-NOT: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 {{[-0-9]+}}) ] - // CHECK: ret i32 {{%.+}} - f(arg) -} diff --git a/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs b/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs deleted file mode 100644 index 942b50deb02..00000000000 --- a/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Verifies that generalized KCFI type metadata for functions are emitted. -// -//@ add-core-stubs -//@ revisions: aarch64 x86_64 -//@ [aarch64] compile-flags: --target aarch64-unknown-none -//@ [aarch64] needs-llvm-components: aarch64 -//@ [x86_64] compile-flags: --target x86_64-unknown-none -//@ [x86_64] needs-llvm-components: -//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Zsanitizer-cfi-generalize-pointers - -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: define{{.*}}foo - // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE1:[0-9]+]] - // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 233085384) ] - f(arg) -} - -pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { - // CHECK-LABEL: define{{.*}}bar - // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE2:[0-9]+]] - // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2){{.*}}[ "kcfi"(i32 435418021) ] - f(arg1, arg2) -} - -pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { - // CHECK-LABEL: define{{.*}}baz - // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE3:[0-9]+]] - // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 -1003721339) ] - f(arg1, arg2, arg3) -} - -// CHECK: ![[TYPE1]] = !{i32 -1741689296} -// CHECK: ![[TYPE2]] = !{i32 489439372} -// CHECK: ![[TYPE3]] = !{i32 2026563871} diff --git a/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs deleted file mode 100644 index c89d9bdd121..00000000000 --- a/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Verifies that normalized and generalized KCFI type metadata for functions are emitted. -// -//@ add-core-stubs -//@ revisions: aarch64 x86_64 -//@ [aarch64] compile-flags: --target aarch64-unknown-none -//@ [aarch64] needs-llvm-components: aarch64 -//@ [x86_64] compile-flags: --target x86_64-unknown-none -//@ [x86_64] needs-llvm-components: -//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers -Zsanitizer-cfi-generalize-pointers - -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: define{{.*}}foo - // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE1:[0-9]+]] - // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 -686570305) ] - f(arg) -} - -pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { - // CHECK-LABEL: define{{.*}}bar - // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE2:[0-9]+]] - // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2){{.*}}[ "kcfi"(i32 1281038450) ] - f(arg1, arg2) -} - -pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { - // CHECK-LABEL: define{{.*}}baz - // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE3:[0-9]+]] - // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 -1751512973) ] - f(arg1, arg2, arg3) -} - -// CHECK: ![[TYPE1]] = !{i32 975484707} -// CHECK: ![[TYPE2]] = !{i32 1658833102} -// CHECK: ![[TYPE3]] = !{i32 230429758} diff --git a/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs b/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs deleted file mode 100644 index 220cae1a4fa..00000000000 --- a/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Verifies that normalized KCFI type metadata for functions are emitted. -// -//@ add-core-stubs -//@ revisions: aarch64 x86_64 -//@ [aarch64] compile-flags: --target aarch64-unknown-none -//@ [aarch64] needs-llvm-components: aarch64 -//@ [x86_64] compile-flags: --target x86_64-unknown-none -//@ [x86_64] needs-llvm-components: -//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers - -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: define{{.*}}foo - // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE1:[0-9]+]] - // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 -841055669) ] - f(arg) -} - -pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { - // CHECK-LABEL: define{{.*}}bar - // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE2:[0-9]+]] - // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2){{.*}}[ "kcfi"(i32 1390819368) ] - f(arg1, arg2) -} - -pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { - // CHECK-LABEL: define{{.*}}baz - // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE3:[0-9]+]] - // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 586925835) ] - f(arg1, arg2, arg3) -} - -// CHECK: ![[TYPE1]] = !{i32 -458317079} -// CHECK: ![[TYPE2]] = !{i32 1737138182} -// CHECK: ![[TYPE3]] = !{i32 197182412} diff --git a/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs b/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs deleted file mode 100644 index bb9a0005903..00000000000 --- a/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Verifies that KCFI type metadata for functions are emitted. -// -//@ add-core-stubs -//@ revisions: aarch64 x86_64 -//@ [aarch64] compile-flags: --target aarch64-unknown-none -//@ [aarch64] needs-llvm-components: aarch64 -//@ [x86_64] compile-flags: --target x86_64-unknown-none -//@ [x86_64] needs-llvm-components: -//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0 - -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: define{{.*}}foo - // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE1:[0-9]+]] - // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 -1666898348) ] - f(arg) -} - -pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 { - // CHECK-LABEL: define{{.*}}bar - // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE2:[0-9]+]] - // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2){{.*}}[ "kcfi"(i32 -1789026986) ] - f(arg1, arg2) -} - -pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 { - // CHECK-LABEL: define{{.*}}baz - // CHECK-SAME: {{.*}}!{{|kcfi_type}} ![[TYPE3:[0-9]+]] - // CHECK: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg1, i32 {{(noundef )*}}%arg2, i32 {{(noundef )*}}%arg3){{.*}}[ "kcfi"(i32 1248878270) ] - f(arg1, arg2, arg3) -} - -// CHECK: ![[TYPE1]] = !{i32 653723426} -// CHECK: ![[TYPE2]] = !{i32 412174924} -// CHECK: ![[TYPE3]] = !{i32 -636668840} diff --git a/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle.rs b/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle.rs deleted file mode 100644 index 8b844b99142..00000000000 --- a/tests/codegen/sanitizer/kcfi/emit-kcfi-operand-bundle.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Verifies that KCFI operand bundles are emitted. -// -//@ add-core-stubs -//@ revisions: aarch64 x86_64 -//@ [aarch64] compile-flags: --target aarch64-unknown-none -//@ [aarch64] needs-llvm-components: aarch64 -//@ [x86_64] compile-flags: --target x86_64-unknown-none -//@ [x86_64] needs-llvm-components: -//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0 - -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: define{{.*}}foo{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: start: - // CHECK-NEXT: {{%.+}} = call {{(noundef )*}}i32 %f(i32 {{(noundef )*}}%arg){{.*}}[ "kcfi"(i32 {{[-0-9]+}}) ] - // CHECK-NEXT: ret i32 {{%.+}} - f(arg) -} diff --git a/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs deleted file mode 100644 index 15c107bea15..00000000000 --- a/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs +++ /dev/null @@ -1,155 +0,0 @@ -// Verifies that type metadata identifiers for trait objects are emitted correctly. -// -//@ add-core-stubs -//@ revisions: aarch64 x86_64 -//@ [aarch64] compile-flags: --target aarch64-unknown-none -//@ [aarch64] needs-llvm-components: aarch64 -//@ [x86_64] compile-flags: --target x86_64-unknown-none -//@ [x86_64] needs-llvm-components: -//@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0 - -#![crate_type = "lib"] -#![feature(arbitrary_self_types, no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -pub trait Trait1 { - fn foo(&self); -} - -pub struct Type1; - -impl Trait1 for Type1 { - fn foo(&self) {} -} - -pub trait Trait2 { - fn bar(&self); -} - -pub struct Type2; - -impl Trait2 for Type2 { - fn bar(&self) {} -} - -pub trait Trait3 { - fn baz(&self, _: &T); -} - -pub struct Type3; - -impl Trait3 for T { - fn baz(&self, _: &U) {} -} - -pub trait Trait4<'a, T> { - type Output: 'a; - fn qux(&self, _: &T) -> Self::Output; -} - -pub struct Type4; - -impl<'a, T, U> Trait4<'a, U> for T { - type Output = &'a i32; - fn qux(&self, _: &U) -> Self::Output { - &0 - } -} - -pub trait Trait5 { - fn quux(&self, _: &[T; N]); -} - -pub struct Type5; - -impl Copy for Type5 {} - -impl Trait5 for T { - fn quux(&self, _: &[U; N]) {} -} - -pub fn foo1(a: &dyn Trait1) { - a.foo(); - // CHECK-LABEL: define{{.*}}4foo1{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] -} - -pub fn bar1() { - let a = Type1; - let b = &a as &dyn Trait1; - b.foo(); - // CHECK-LABEL: define{{.*}}4bar1{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] -} - -pub fn foo2(a: &dyn Trait2) { - a.bar(); - // CHECK-LABEL: define{{.*}}4foo2{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ] -} - -pub fn bar2() { - let a = Type2; - foo2(&a); - let b = &a as &dyn Trait2; - b.bar(); - // CHECK-LABEL: define{{.*}}4bar2{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ] -} - -pub fn foo3(a: &dyn Trait3) { - let b = Type3; - a.baz(&b); - // CHECK-LABEL: define{{.*}}4foo3{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ] -} - -pub fn bar3() { - let a = Type3; - foo3(&a); - let b = &a as &dyn Trait3; - b.baz(&a); - // CHECK-LABEL: define{{.*}}4bar3{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ] -} - -pub fn foo4<'a>(a: &dyn Trait4<'a, Type4, Output = &'a i32>) { - let b = Type4; - a.qux(&b); - // CHECK-LABEL: define{{.*}}4foo4{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call align 4 ptr %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ] -} - -pub fn bar4<'a>() { - let a = Type4; - foo4(&a); - let b = &a as &dyn Trait4<'a, Type4, Output = &'a i32>; - b.qux(&a); - // CHECK-LABEL: define{{.*}}4bar4{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call align 4 ptr %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ] -} - -pub fn foo5(a: &dyn Trait5) { - let b = &[Type5; 32]; - a.quux(&b); - // CHECK-LABEL: define{{.*}}4foo5{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z](\.0)*|%_[0-9]+]}}, ptr align 1 {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ] -} - -pub fn bar5() { - let a = &[Type5; 32]; - foo5(&a); - let b = &a as &dyn Trait5; - b.quux(&a); - // CHECK-LABEL: define{{.*}}4bar5{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z](\.0)*|%_[0-9]+]}}, ptr align 1 {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ] -} - -// CHECK: !{{[0-9]+}} = !{i32 [[TYPE1]]} -// CHECK: !{{[0-9]+}} = !{i32 [[TYPE2]]} -// CHECK: !{{[0-9]+}} = !{i32 [[TYPE3]]} -// CHECK: !{{[0-9]+}} = !{i32 [[TYPE4]]} -// CHECK: !{{[0-9]+}} = !{i32 [[TYPE5]]} diff --git a/tests/codegen/sanitizer/kcfi/naked-function.rs b/tests/codegen/sanitizer/kcfi/naked-function.rs deleted file mode 100644 index 2c8cdc919b8..00000000000 --- a/tests/codegen/sanitizer/kcfi/naked-function.rs +++ /dev/null @@ -1,47 +0,0 @@ -//@ add-core-stubs -//@ revisions: aarch64 x86_64 -//@ [aarch64] compile-flags: --target aarch64-unknown-none -//@ [aarch64] needs-llvm-components: aarch64 -//@ [x86_64] compile-flags: --target x86_64-unknown-none -//@ [x86_64] needs-llvm-components: x86 -//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Cno-prepopulate-passes -Copt-level=0 - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -struct Thing; -trait MyTrait { - #[unsafe(naked)] - extern "C" fn my_naked_function() { - // the real function is defined - // CHECK: .globl - // CHECK-SAME: my_naked_function - naked_asm!("ret") - } -} -impl MyTrait for Thing {} - -// the shim calls the real function -// CHECK-LABEL: define -// CHECK-SAME: my_naked_function -// CHECK-SAME: reify.shim.fnptr - -// CHECK-LABEL: main -#[unsafe(no_mangle)] -pub fn main() { - // Trick the compiler into generating an indirect call. - const F: extern "C" fn() = Thing::my_naked_function; - - // main calls the shim function - // CHECK: call void - // CHECK-SAME: my_naked_function - // CHECK-SAME: reify.shim.fnptr - (F)(); -} - -// CHECK: declare !kcfi_type -// CHECK-SAME: my_naked_function diff --git a/tests/codegen/sanitizer/memory-track-origins.rs b/tests/codegen/sanitizer/memory-track-origins.rs deleted file mode 100644 index 318c277e10c..00000000000 --- a/tests/codegen/sanitizer/memory-track-origins.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Verifies that MemorySanitizer track-origins level can be controlled -// with -Zsanitizer-memory-track-origins option. -// -//@ needs-sanitizer-memory -//@ revisions:MSAN-0 MSAN-1 MSAN-2 MSAN-1-LTO MSAN-2-LTO -// -//@ compile-flags: -Zsanitizer=memory -Ctarget-feature=-crt-static -//@[MSAN-0] compile-flags: -//@[MSAN-1] compile-flags: -Zsanitizer-memory-track-origins=1 -//@[MSAN-2] compile-flags: -Zsanitizer-memory-track-origins -//@[MSAN-1-LTO] compile-flags: -Zsanitizer-memory-track-origins=1 -C lto=fat -//@[MSAN-2-LTO] compile-flags: -Zsanitizer-memory-track-origins -C lto=fat - -#![crate_type = "lib"] - -// MSAN-0-NOT: @__msan_track_origins -// MSAN-1: @__msan_track_origins = weak_odr {{.*}}constant i32 1 -// MSAN-2: @__msan_track_origins = weak_odr {{.*}}constant i32 2 -// MSAN-1-LTO: @__msan_track_origins = weak_odr {{.*}}constant i32 1 -// MSAN-2-LTO: @__msan_track_origins = weak_odr {{.*}}constant i32 2 -// -// MSAN-0-LABEL: define void @copy( -// MSAN-1-LABEL: define void @copy( -// MSAN-2-LABEL: define void @copy( -#[no_mangle] -pub fn copy(dst: &mut i32, src: &i32) { - // MSAN-0-NOT: call i32 @__msan_chain_origin( - // MSAN-1-NOT: call i32 @__msan_chain_origin( - // MSAN-2: call i32 @__msan_chain_origin( - *dst = *src; -} diff --git a/tests/codegen/sanitizer/memtag-attr-check.rs b/tests/codegen/sanitizer/memtag-attr-check.rs deleted file mode 100644 index ffe3a2322a2..00000000000 --- a/tests/codegen/sanitizer/memtag-attr-check.rs +++ /dev/null @@ -1,12 +0,0 @@ -// This tests that the sanitize_memtag attribute is -// applied when enabling the memtag sanitizer. -// -//@ needs-sanitizer-memtag -//@ compile-flags: -Zsanitizer=memtag -Ctarget-feature=+mte -Copt-level=0 - -#![crate_type = "lib"] - -// CHECK: ; Function Attrs:{{.*}}sanitize_memtag -pub fn tagged() {} - -// CHECK: attributes #0 = {{.*}}sanitize_memtag diff --git a/tests/codegen/sanitizer/no-sanitize-inlining.rs b/tests/codegen/sanitizer/no-sanitize-inlining.rs deleted file mode 100644 index 4bd832d2ab1..00000000000 --- a/tests/codegen/sanitizer/no-sanitize-inlining.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Verifies that no_sanitize attribute prevents inlining when -// given sanitizer is enabled, but has no effect on inlining otherwise. -// -//@ needs-sanitizer-address -//@ needs-sanitizer-leak -//@ revisions: ASAN LSAN -//@ compile-flags: -Copt-level=3 -Zmir-opt-level=4 -Ctarget-feature=-crt-static -//@[ASAN] compile-flags: -Zsanitizer=address -//@[LSAN] compile-flags: -Zsanitizer=leak - -#![crate_type = "lib"] -#![feature(no_sanitize)] - -// ASAN-LABEL: define void @test -// ASAN: call {{.*}} @random_inline -// ASAN: } -// -// LSAN-LABEL: define void @test -// LSAN-NOT: call -// LSAN: } -#[no_mangle] -pub fn test(n: &mut u32) { - random_inline(n); -} - -#[no_sanitize(address)] -#[inline] -#[no_mangle] -pub fn random_inline(n: &mut u32) { - *n = 42; -} diff --git a/tests/codegen/sanitizer/no-sanitize.rs b/tests/codegen/sanitizer/no-sanitize.rs deleted file mode 100644 index 2a309f6b9c6..00000000000 --- a/tests/codegen/sanitizer/no-sanitize.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Verifies that no_sanitize attribute can be used to -// selectively disable sanitizer instrumentation. -// -//@ needs-sanitizer-address -//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static -Copt-level=0 - -#![crate_type = "lib"] -#![feature(no_sanitize)] - -// CHECK: @UNSANITIZED = constant{{.*}} no_sanitize_address -// CHECK-NOT: @__asan_global_UNSANITIZED -#[no_mangle] -#[no_sanitize(address)] -pub static UNSANITIZED: u32 = 0; - -// CHECK: @__asan_global_SANITIZED -#[no_mangle] -pub static SANITIZED: u32 = 0; - -// CHECK-LABEL: ; no_sanitize::unsanitized -// CHECK-NEXT: ; Function Attrs: -// CHECK-NOT: sanitize_address -// CHECK: start: -// CHECK-NOT: call void @__asan_report_load -// CHECK: } -#[no_sanitize(address)] -pub fn unsanitized(b: &mut u8) -> u8 { - *b -} - -// CHECK-LABEL: ; no_sanitize::sanitized -// CHECK-NEXT: ; Function Attrs: -// CHECK: sanitize_address -// CHECK: start: -// CHECK: call void @__asan_report_load -// CHECK: } -pub fn sanitized(b: &mut u8) -> u8 { - *b -} diff --git a/tests/codegen/sanitizer/riscv64-shadow-call-stack.rs b/tests/codegen/sanitizer/riscv64-shadow-call-stack.rs deleted file mode 100644 index 945e46218d0..00000000000 --- a/tests/codegen/sanitizer/riscv64-shadow-call-stack.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: --target riscv64imac-unknown-none-elf -Zsanitizer=shadow-call-stack -//@ needs-llvm-components: riscv - -#![allow(internal_features)] -#![crate_type = "rlib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -// CHECK: ; Function Attrs:{{.*}}shadowcallstack -// CHECK: define dso_local void @foo() unnamed_addr #0 -#[no_mangle] -pub fn foo() {} - -// CHECK: attributes #0 = {{.*}}shadowcallstack{{.*}} diff --git a/tests/codegen/sanitizer/safestack-attr-check.rs b/tests/codegen/sanitizer/safestack-attr-check.rs deleted file mode 100644 index 050a60333af..00000000000 --- a/tests/codegen/sanitizer/safestack-attr-check.rs +++ /dev/null @@ -1,11 +0,0 @@ -// This tests that the safestack attribute is applied when enabling the safe-stack sanitizer. -// -//@ needs-sanitizer-safestack -//@ compile-flags: -Zsanitizer=safestack -Copt-level=0 - -#![crate_type = "lib"] - -// CHECK: ; Function Attrs:{{.*}}safestack -pub fn tagged() {} - -// CHECK: attributes #0 = {{.*}}safestack diff --git a/tests/codegen/sanitizer/sanitizer-recover.rs b/tests/codegen/sanitizer/sanitizer-recover.rs deleted file mode 100644 index 6b659320481..00000000000 --- a/tests/codegen/sanitizer/sanitizer-recover.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Verifies that AddressSanitizer and MemorySanitizer -// recovery mode can be enabled with -Zsanitizer-recover. -// -//@ needs-sanitizer-address -//@ needs-sanitizer-memory -//@ revisions:ASAN ASAN-RECOVER MSAN MSAN-RECOVER MSAN-RECOVER-LTO -//@ no-prefer-dynamic -// -//@ compile-flags: -Ctarget-feature=-crt-static -//@[ASAN] compile-flags: -Zsanitizer=address -Copt-level=0 -//@[ASAN-RECOVER] compile-flags: -Zsanitizer=address -Zsanitizer-recover=address -Copt-level=0 -//@[MSAN] compile-flags: -Zsanitizer=memory -//@[MSAN-RECOVER] compile-flags: -Zsanitizer=memory -Zsanitizer-recover=memory -//@[MSAN-RECOVER-LTO] compile-flags: -Zsanitizer=memory -Zsanitizer-recover=memory -C lto=fat -// -// MSAN-NOT: @__msan_keep_going -// MSAN-RECOVER: @__msan_keep_going = weak_odr {{.*}}constant i32 1 -// MSAN-RECOVER-LTO: @__msan_keep_going = weak_odr {{.*}}constant i32 1 - -// ASAN-LABEL: define dso_local i32 @penguin( -// ASAN: call void @__asan_report_load4(i64 %0) -// ASAN: unreachable -// ASAN: } -// -// ASAN-RECOVER-LABEL: define dso_local i32 @penguin( -// ASAN-RECOVER: call void @__asan_report_load4_noabort( -// ASAN-RECOVER-NOT: unreachable -// ASAN: } -// -// MSAN-LABEL: define dso_local noundef i32 @penguin( -// MSAN: call void @__msan_warning{{(_with_origin_noreturn\(i32 0\)|_noreturn\(\))}} -// MSAN: unreachable -// MSAN: } -// -// MSAN-RECOVER-LABEL: define dso_local noundef i32 @penguin( -// MSAN-RECOVER: call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}} -// MSAN-RECOVER-NOT: unreachable -// MSAN-RECOVER: } -// -// MSAN-RECOVER-LTO-LABEL: define dso_local noundef i32 @penguin( -// MSAN-RECOVER-LTO: call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}} -// MSAN-RECOVER-LTO-NOT: unreachable -// MSAN-RECOVER-LTO: } -// -#[no_mangle] -pub fn penguin(p: &mut i32) -> i32 { - *p -} - -fn main() {} diff --git a/tests/codegen/sanitizer/scs-attr-check.rs b/tests/codegen/sanitizer/scs-attr-check.rs deleted file mode 100644 index 6f4cbc2c0a6..00000000000 --- a/tests/codegen/sanitizer/scs-attr-check.rs +++ /dev/null @@ -1,17 +0,0 @@ -// This tests that the shadowcallstack attribute is -// applied when enabling the shadow-call-stack sanitizer. -// -//@ needs-sanitizer-shadow-call-stack -//@ compile-flags: -Zsanitizer=shadow-call-stack - -#![crate_type = "lib"] -#![feature(no_sanitize)] - -// CHECK: ; sanitizer_scs_attr_check::scs -// CHECK-NEXT: ; Function Attrs:{{.*}}shadowcallstack -pub fn scs() {} - -// CHECK: ; sanitizer_scs_attr_check::no_scs -// CHECK-NOT: ; Function Attrs:{{.*}}shadowcallstack -#[no_sanitize(shadow_call_stack)] -pub fn no_scs() {} diff --git a/tests/codegen/scalar-pair-bool.rs b/tests/codegen/scalar-pair-bool.rs deleted file mode 100644 index def3b32f71a..00000000000 --- a/tests/codegen/scalar-pair-bool.rs +++ /dev/null @@ -1,45 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK: define{{.*}}{ i1, i1 } @pair_bool_bool(i1 noundef zeroext %pair.0, i1 noundef zeroext %pair.1) -#[no_mangle] -pub fn pair_bool_bool(pair: (bool, bool)) -> (bool, bool) { - pair -} - -// CHECK: define{{.*}}{ i1, i32 } @pair_bool_i32(i1 noundef zeroext %pair.0, i32 noundef %pair.1) -#[no_mangle] -pub fn pair_bool_i32(pair: (bool, i32)) -> (bool, i32) { - pair -} - -// CHECK: define{{.*}}{ i32, i1 } @pair_i32_bool(i32 noundef %pair.0, i1 noundef zeroext %pair.1) -#[no_mangle] -pub fn pair_i32_bool(pair: (i32, bool)) -> (i32, bool) { - pair -} - -// CHECK: define{{.*}}{ i1, i1 } @pair_and_or(i1 noundef zeroext %_1.0, i1 noundef zeroext %_1.1) -#[no_mangle] -pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) { - // Make sure it can operate directly on the unpacked args - // (but it might not be using simple and/or instructions) - // CHECK-DAG: %_1.0 - // CHECK-DAG: %_1.1 - (a && b, a || b) -} - -// CHECK: define{{.*}}void @pair_branches(i1 noundef zeroext %_1.0, i1 noundef zeroext %_1.1) -#[no_mangle] -pub fn pair_branches((a, b): (bool, bool)) { - // Make sure it can branch directly on the unpacked bool args - // CHECK: br i1 %_1.0 - if a { - println!("Hello!"); - } - // CHECK: br i1 %_1.1 - if b { - println!("Goodbye!"); - } -} diff --git a/tests/codegen/set-discriminant-invalid.rs b/tests/codegen/set-discriminant-invalid.rs deleted file mode 100644 index dd584ef1c14..00000000000 --- a/tests/codegen/set-discriminant-invalid.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@ compile-flags: -C opt-level=0 -#![crate_type = "lib"] - -pub enum ApiError {} -#[allow(dead_code)] -pub struct TokioError { - b: bool, -} -pub enum Error { - Api { source: ApiError }, - Ethereum, - Tokio { source: TokioError }, -} -struct Api; -impl IntoError for Api { - type Source = ApiError; - // CHECK-LABEL: @into_error - // CHECK: llvm.trap() - // Also check the next instruction to make sure we do not match against `trap` - // elsewhere in the code. - // CHECK-NEXT: ret i8 poison - #[no_mangle] - fn into_error(self, error: Self::Source) -> Error { - Error::Api { source: error } - } -} - -pub trait IntoError { - /// The underlying error - type Source; - - /// Combine the information to produce the error - fn into_error(self, source: Self::Source) -> E; -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs deleted file mode 100644 index baf445d0a1b..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_fabs; - -// CHECK-LABEL: @fabs_32x2 -#[no_mangle] -pub unsafe fn fabs_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.fabs.v2f32 - simd_fabs(a) -} - -// CHECK-LABEL: @fabs_32x4 -#[no_mangle] -pub unsafe fn fabs_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.fabs.v4f32 - simd_fabs(a) -} - -// CHECK-LABEL: @fabs_32x8 -#[no_mangle] -pub unsafe fn fabs_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.fabs.v8f32 - simd_fabs(a) -} - -// CHECK-LABEL: @fabs_32x16 -#[no_mangle] -pub unsafe fn fabs_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.fabs.v16f32 - simd_fabs(a) -} - -// CHECK-LABEL: @fabs_64x4 -#[no_mangle] -pub unsafe fn fabs_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.fabs.v4f64 - simd_fabs(a) -} - -// CHECK-LABEL: @fabs_64x2 -#[no_mangle] -pub unsafe fn fabs_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.fabs.v2f64 - simd_fabs(a) -} - -// CHECK-LABEL: @fabs_64x8 -#[no_mangle] -pub unsafe fn fabs_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.fabs.v8f64 - simd_fabs(a) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs deleted file mode 100644 index 096de569274..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_ceil; - -// CHECK-LABEL: @ceil_32x2 -#[no_mangle] -pub unsafe fn ceil_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.ceil.v2f32 - simd_ceil(a) -} - -// CHECK-LABEL: @ceil_32x4 -#[no_mangle] -pub unsafe fn ceil_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.ceil.v4f32 - simd_ceil(a) -} - -// CHECK-LABEL: @ceil_32x8 -#[no_mangle] -pub unsafe fn ceil_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.ceil.v8f32 - simd_ceil(a) -} - -// CHECK-LABEL: @ceil_32x16 -#[no_mangle] -pub unsafe fn ceil_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.ceil.v16f32 - simd_ceil(a) -} - -// CHECK-LABEL: @ceil_64x4 -#[no_mangle] -pub unsafe fn ceil_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.ceil.v4f64 - simd_ceil(a) -} - -// CHECK-LABEL: @ceil_64x2 -#[no_mangle] -pub unsafe fn ceil_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.ceil.v2f64 - simd_ceil(a) -} - -// CHECK-LABEL: @ceil_64x8 -#[no_mangle] -pub unsafe fn ceil_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.ceil.v8f64 - simd_ceil(a) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs deleted file mode 100644 index 5b2197924bc..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_fcos; - -// CHECK-LABEL: @fcos_32x2 -#[no_mangle] -pub unsafe fn fcos_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.cos.v2f32 - simd_fcos(a) -} - -// CHECK-LABEL: @fcos_32x4 -#[no_mangle] -pub unsafe fn fcos_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.cos.v4f32 - simd_fcos(a) -} - -// CHECK-LABEL: @fcos_32x8 -#[no_mangle] -pub unsafe fn fcos_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.cos.v8f32 - simd_fcos(a) -} - -// CHECK-LABEL: @fcos_32x16 -#[no_mangle] -pub unsafe fn fcos_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.cos.v16f32 - simd_fcos(a) -} - -// CHECK-LABEL: @fcos_64x4 -#[no_mangle] -pub unsafe fn fcos_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.cos.v4f64 - simd_fcos(a) -} - -// CHECK-LABEL: @fcos_64x2 -#[no_mangle] -pub unsafe fn fcos_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.cos.v2f64 - simd_fcos(a) -} - -// CHECK-LABEL: @fcos_64x8 -#[no_mangle] -pub unsafe fn fcos_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.cos.v8f64 - simd_fcos(a) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs deleted file mode 100644 index d4eadb36c65..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_fexp; - -// CHECK-LABEL: @exp_32x2 -#[no_mangle] -pub unsafe fn exp_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.exp.v2f32 - simd_fexp(a) -} - -// CHECK-LABEL: @exp_32x4 -#[no_mangle] -pub unsafe fn exp_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.exp.v4f32 - simd_fexp(a) -} - -// CHECK-LABEL: @exp_32x8 -#[no_mangle] -pub unsafe fn exp_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.exp.v8f32 - simd_fexp(a) -} - -// CHECK-LABEL: @exp_32x16 -#[no_mangle] -pub unsafe fn exp_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.exp.v16f32 - simd_fexp(a) -} - -// CHECK-LABEL: @exp_64x4 -#[no_mangle] -pub unsafe fn exp_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.exp.v4f64 - simd_fexp(a) -} - -// CHECK-LABEL: @exp_64x2 -#[no_mangle] -pub unsafe fn exp_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.exp.v2f64 - simd_fexp(a) -} - -// CHECK-LABEL: @exp_64x8 -#[no_mangle] -pub unsafe fn exp_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.exp.v8f64 - simd_fexp(a) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs deleted file mode 100644 index d32015b7990..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_fexp2; - -// CHECK-LABEL: @exp2_32x2 -#[no_mangle] -pub unsafe fn exp2_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.exp2.v2f32 - simd_fexp2(a) -} - -// CHECK-LABEL: @exp2_32x4 -#[no_mangle] -pub unsafe fn exp2_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.exp2.v4f32 - simd_fexp2(a) -} - -// CHECK-LABEL: @exp2_32x8 -#[no_mangle] -pub unsafe fn exp2_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.exp2.v8f32 - simd_fexp2(a) -} - -// CHECK-LABEL: @exp2_32x16 -#[no_mangle] -pub unsafe fn exp2_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.exp2.v16f32 - simd_fexp2(a) -} - -// CHECK-LABEL: @exp2_64x4 -#[no_mangle] -pub unsafe fn exp2_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.exp2.v4f64 - simd_fexp2(a) -} - -// CHECK-LABEL: @exp2_64x2 -#[no_mangle] -pub unsafe fn exp2_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.exp2.v2f64 - simd_fexp2(a) -} - -// CHECK-LABEL: @exp2_64x8 -#[no_mangle] -pub unsafe fn exp2_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.exp2.v8f64 - simd_fexp2(a) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs deleted file mode 100644 index 1e1c8ce0c35..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_floor; - -// CHECK-LABEL: @floor_32x2 -#[no_mangle] -pub unsafe fn floor_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.floor.v2f32 - simd_floor(a) -} - -// CHECK-LABEL: @floor_32x4 -#[no_mangle] -pub unsafe fn floor_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.floor.v4f32 - simd_floor(a) -} - -// CHECK-LABEL: @floor_32x8 -#[no_mangle] -pub unsafe fn floor_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.floor.v8f32 - simd_floor(a) -} - -// CHECK-LABEL: @floor_32x16 -#[no_mangle] -pub unsafe fn floor_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.floor.v16f32 - simd_floor(a) -} - -// CHECK-LABEL: @floor_64x4 -#[no_mangle] -pub unsafe fn floor_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.floor.v4f64 - simd_floor(a) -} - -// CHECK-LABEL: @floor_64x2 -#[no_mangle] -pub unsafe fn floor_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.floor.v2f64 - simd_floor(a) -} - -// CHECK-LABEL: @floor_64x8 -#[no_mangle] -pub unsafe fn floor_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.floor.v8f64 - simd_floor(a) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs deleted file mode 100644 index 982077d81f9..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_fma; - -// CHECK-LABEL: @fma_32x2 -#[no_mangle] -pub unsafe fn fma_32x2(a: f32x2, b: f32x2, c: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.fma.v2f32 - simd_fma(a, b, c) -} - -// CHECK-LABEL: @fma_32x4 -#[no_mangle] -pub unsafe fn fma_32x4(a: f32x4, b: f32x4, c: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.fma.v4f32 - simd_fma(a, b, c) -} - -// CHECK-LABEL: @fma_32x8 -#[no_mangle] -pub unsafe fn fma_32x8(a: f32x8, b: f32x8, c: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.fma.v8f32 - simd_fma(a, b, c) -} - -// CHECK-LABEL: @fma_32x16 -#[no_mangle] -pub unsafe fn fma_32x16(a: f32x16, b: f32x16, c: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.fma.v16f32 - simd_fma(a, b, c) -} - -// CHECK-LABEL: @fma_64x4 -#[no_mangle] -pub unsafe fn fma_64x4(a: f64x4, b: f64x4, c: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.fma.v4f64 - simd_fma(a, b, c) -} - -// CHECK-LABEL: @fma_64x2 -#[no_mangle] -pub unsafe fn fma_64x2(a: f64x2, b: f64x2, c: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.fma.v2f64 - simd_fma(a, b, c) -} - -// CHECK-LABEL: @fma_64x8 -#[no_mangle] -pub unsafe fn fma_64x8(a: f64x8, b: f64x8, c: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.fma.v8f64 - simd_fma(a, b, c) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs deleted file mode 100644 index e20a591f573..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_fsqrt; - -// CHECK-LABEL: @fsqrt_32x2 -#[no_mangle] -pub unsafe fn fsqrt_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.sqrt.v2f32 - simd_fsqrt(a) -} - -// CHECK-LABEL: @fsqrt_32x4 -#[no_mangle] -pub unsafe fn fsqrt_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.sqrt.v4f32 - simd_fsqrt(a) -} - -// CHECK-LABEL: @fsqrt_32x8 -#[no_mangle] -pub unsafe fn fsqrt_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.sqrt.v8f32 - simd_fsqrt(a) -} - -// CHECK-LABEL: @fsqrt_32x16 -#[no_mangle] -pub unsafe fn fsqrt_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.sqrt.v16f32 - simd_fsqrt(a) -} - -// CHECK-LABEL: @fsqrt_64x4 -#[no_mangle] -pub unsafe fn fsqrt_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.sqrt.v4f64 - simd_fsqrt(a) -} - -// CHECK-LABEL: @fsqrt_64x2 -#[no_mangle] -pub unsafe fn fsqrt_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.sqrt.v2f64 - simd_fsqrt(a) -} - -// CHECK-LABEL: @fsqrt_64x8 -#[no_mangle] -pub unsafe fn fsqrt_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.sqrt.v8f64 - simd_fsqrt(a) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs deleted file mode 100644 index bf1ffc76330..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_flog; - -// CHECK-LABEL: @log_32x2 -#[no_mangle] -pub unsafe fn log_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.log.v2f32 - simd_flog(a) -} - -// CHECK-LABEL: @log_32x4 -#[no_mangle] -pub unsafe fn log_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.log.v4f32 - simd_flog(a) -} - -// CHECK-LABEL: @log_32x8 -#[no_mangle] -pub unsafe fn log_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.log.v8f32 - simd_flog(a) -} - -// CHECK-LABEL: @log_32x16 -#[no_mangle] -pub unsafe fn log_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.log.v16f32 - simd_flog(a) -} - -// CHECK-LABEL: @log_64x4 -#[no_mangle] -pub unsafe fn log_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.log.v4f64 - simd_flog(a) -} - -// CHECK-LABEL: @log_64x2 -#[no_mangle] -pub unsafe fn log_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.log.v2f64 - simd_flog(a) -} - -// CHECK-LABEL: @log_64x8 -#[no_mangle] -pub unsafe fn log_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.log.v8f64 - simd_flog(a) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs deleted file mode 100644 index ccf484e0e41..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_flog10; - -// CHECK-LABEL: @log10_32x2 -#[no_mangle] -pub unsafe fn log10_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.log10.v2f32 - simd_flog10(a) -} - -// CHECK-LABEL: @log10_32x4 -#[no_mangle] -pub unsafe fn log10_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.log10.v4f32 - simd_flog10(a) -} - -// CHECK-LABEL: @log10_32x8 -#[no_mangle] -pub unsafe fn log10_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.log10.v8f32 - simd_flog10(a) -} - -// CHECK-LABEL: @log10_32x16 -#[no_mangle] -pub unsafe fn log10_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.log10.v16f32 - simd_flog10(a) -} - -// CHECK-LABEL: @log10_64x4 -#[no_mangle] -pub unsafe fn log10_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.log10.v4f64 - simd_flog10(a) -} - -// CHECK-LABEL: @log10_64x2 -#[no_mangle] -pub unsafe fn log10_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.log10.v2f64 - simd_flog10(a) -} - -// CHECK-LABEL: @log10_64x8 -#[no_mangle] -pub unsafe fn log10_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.log10.v8f64 - simd_flog10(a) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs deleted file mode 100644 index 677d8b01e84..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_flog2; - -// CHECK-LABEL: @log2_32x2 -#[no_mangle] -pub unsafe fn log2_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.log2.v2f32 - simd_flog2(a) -} - -// CHECK-LABEL: @log2_32x4 -#[no_mangle] -pub unsafe fn log2_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.log2.v4f32 - simd_flog2(a) -} - -// CHECK-LABEL: @log2_32x8 -#[no_mangle] -pub unsafe fn log2_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.log2.v8f32 - simd_flog2(a) -} - -// CHECK-LABEL: @log2_32x16 -#[no_mangle] -pub unsafe fn log2_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.log2.v16f32 - simd_flog2(a) -} - -// CHECK-LABEL: @log2_64x4 -#[no_mangle] -pub unsafe fn log2_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.log2.v4f64 - simd_flog2(a) -} - -// CHECK-LABEL: @log2_64x2 -#[no_mangle] -pub unsafe fn log2_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.log2.v2f64 - simd_flog2(a) -} - -// CHECK-LABEL: @log2_64x8 -#[no_mangle] -pub unsafe fn log2_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.log2.v8f64 - simd_flog2(a) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs deleted file mode 100644 index 8dd464a1bff..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::{simd_fmax, simd_fmin}; - -// CHECK-LABEL: @fmin -#[no_mangle] -pub unsafe fn fmin(a: f32x4, b: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.minnum.v4f32 - simd_fmin(a, b) -} - -// CHECK-LABEL: @fmax -#[no_mangle] -pub unsafe fn fmax(a: f32x4, b: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.maxnum.v4f32 - simd_fmax(a, b) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs deleted file mode 100644 index 48becc72c0b..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_fsin; - -// CHECK-LABEL: @fsin_32x2 -#[no_mangle] -pub unsafe fn fsin_32x2(a: f32x2) -> f32x2 { - // CHECK: call <2 x float> @llvm.sin.v2f32 - simd_fsin(a) -} - -// CHECK-LABEL: @fsin_32x4 -#[no_mangle] -pub unsafe fn fsin_32x4(a: f32x4) -> f32x4 { - // CHECK: call <4 x float> @llvm.sin.v4f32 - simd_fsin(a) -} - -// CHECK-LABEL: @fsin_32x8 -#[no_mangle] -pub unsafe fn fsin_32x8(a: f32x8) -> f32x8 { - // CHECK: call <8 x float> @llvm.sin.v8f32 - simd_fsin(a) -} - -// CHECK-LABEL: @fsin_32x16 -#[no_mangle] -pub unsafe fn fsin_32x16(a: f32x16) -> f32x16 { - // CHECK: call <16 x float> @llvm.sin.v16f32 - simd_fsin(a) -} - -// CHECK-LABEL: @fsin_64x4 -#[no_mangle] -pub unsafe fn fsin_64x4(a: f64x4) -> f64x4 { - // CHECK: call <4 x double> @llvm.sin.v4f64 - simd_fsin(a) -} - -// CHECK-LABEL: @fsin_64x2 -#[no_mangle] -pub unsafe fn fsin_64x2(a: f64x2) -> f64x2 { - // CHECK: call <2 x double> @llvm.sin.v2f64 - simd_fsin(a) -} - -// CHECK-LABEL: @fsin_64x8 -#[no_mangle] -pub unsafe fn fsin_64x8(a: f64x8) -> f64x8 { - // CHECK: call <8 x double> @llvm.sin.v8f64 - simd_fsin(a) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs deleted file mode 100644 index 06d46889715..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs +++ /dev/null @@ -1,579 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] -#![deny(unused)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub}; - -// NOTE(eddyb) `%{{x|0}}` is used because on some targets (e.g. WASM) -// SIMD vectors are passed directly, resulting in `%x` being a vector, -// while on others they're passed indirectly, resulting in `%x` being -// a pointer to a vector, and `%0` a vector loaded from that pointer. -// This is controlled by the target spec option `simd_types_indirect`. -// The same applies to `%{{y|1}}` as well. - -// CHECK-LABEL: @sadd_i8x2 -#[no_mangle] -pub unsafe fn sadd_i8x2(x: i8x2, y: i8x2) -> i8x2 { - // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i8x4 -#[no_mangle] -pub unsafe fn sadd_i8x4(x: i8x4, y: i8x4) -> i8x4 { - // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i8x8 -#[no_mangle] -pub unsafe fn sadd_i8x8(x: i8x8, y: i8x8) -> i8x8 { - // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.sadd.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i8x16 -#[no_mangle] -pub unsafe fn sadd_i8x16(x: i8x16, y: i8x16) -> i8x16 { - // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.sadd.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i8x32 -#[no_mangle] -pub unsafe fn sadd_i8x32(x: i8x32, y: i8x32) -> i8x32 { - // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.sadd.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i8x64 -#[no_mangle] -pub unsafe fn sadd_i8x64(x: i8x64, y: i8x64) -> i8x64 { - // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.sadd.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i16x2 -#[no_mangle] -pub unsafe fn sadd_i16x2(x: i16x2, y: i16x2) -> i16x2 { - // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i16x4 -#[no_mangle] -pub unsafe fn sadd_i16x4(x: i16x4, y: i16x4) -> i16x4 { - // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i16x8 -#[no_mangle] -pub unsafe fn sadd_i16x8(x: i16x8, y: i16x8) -> i16x8 { - // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.sadd.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i16x16 -#[no_mangle] -pub unsafe fn sadd_i16x16(x: i16x16, y: i16x16) -> i16x16 { - // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.sadd.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i16x32 -#[no_mangle] -pub unsafe fn sadd_i16x32(x: i16x32, y: i16x32) -> i16x32 { - // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.sadd.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i32x2 -#[no_mangle] -pub unsafe fn sadd_i32x2(x: i32x2, y: i32x2) -> i32x2 { - // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i32x4 -#[no_mangle] -pub unsafe fn sadd_i32x4(x: i32x4, y: i32x4) -> i32x4 { - // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i32x8 -#[no_mangle] -pub unsafe fn sadd_i32x8(x: i32x8, y: i32x8) -> i32x8 { - // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i32x16 -#[no_mangle] -pub unsafe fn sadd_i32x16(x: i32x16, y: i32x16) -> i32x16 { - // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.sadd.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i64x2 -#[no_mangle] -pub unsafe fn sadd_i64x2(x: i64x2, y: i64x2) -> i64x2 { - // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.sadd.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i64x4 -#[no_mangle] -pub unsafe fn sadd_i64x4(x: i64x4, y: i64x4) -> i64x4 { - // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.sadd.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i64x8 -#[no_mangle] -pub unsafe fn sadd_i64x8(x: i64x8, y: i64x8) -> i64x8 { - // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.sadd.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i128x2 -#[no_mangle] -pub unsafe fn sadd_i128x2(x: i128x2, y: i128x2) -> i128x2 { - // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.sadd.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @sadd_i128x4 -#[no_mangle] -pub unsafe fn sadd_i128x4(x: i128x4, y: i128x4) -> i128x4 { - // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.sadd.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u8x2 -#[no_mangle] -pub unsafe fn uadd_u8x2(x: u8x2, y: u8x2) -> u8x2 { - // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u8x4 -#[no_mangle] -pub unsafe fn uadd_u8x4(x: u8x4, y: u8x4) -> u8x4 { - // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u8x8 -#[no_mangle] -pub unsafe fn uadd_u8x8(x: u8x8, y: u8x8) -> u8x8 { - // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.uadd.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u8x16 -#[no_mangle] -pub unsafe fn uadd_u8x16(x: u8x16, y: u8x16) -> u8x16 { - // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u8x32 -#[no_mangle] -pub unsafe fn uadd_u8x32(x: u8x32, y: u8x32) -> u8x32 { - // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u8x64 -#[no_mangle] -pub unsafe fn uadd_u8x64(x: u8x64, y: u8x64) -> u8x64 { - // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u16x2 -#[no_mangle] -pub unsafe fn uadd_u16x2(x: u16x2, y: u16x2) -> u16x2 { - // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u16x4 -#[no_mangle] -pub unsafe fn uadd_u16x4(x: u16x4, y: u16x4) -> u16x4 { - // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.uadd.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u16x8 -#[no_mangle] -pub unsafe fn uadd_u16x8(x: u16x8, y: u16x8) -> u16x8 { - // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u16x16 -#[no_mangle] -pub unsafe fn uadd_u16x16(x: u16x16, y: u16x16) -> u16x16 { - // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u16x32 -#[no_mangle] -pub unsafe fn uadd_u16x32(x: u16x32, y: u16x32) -> u16x32 { - // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u32x2 -#[no_mangle] -pub unsafe fn uadd_u32x2(x: u32x2, y: u32x2) -> u32x2 { - // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.uadd.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u32x4 -#[no_mangle] -pub unsafe fn uadd_u32x4(x: u32x4, y: u32x4) -> u32x4 { - // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u32x8 -#[no_mangle] -pub unsafe fn uadd_u32x8(x: u32x8, y: u32x8) -> u32x8 { - // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u32x16 -#[no_mangle] -pub unsafe fn uadd_u32x16(x: u32x16, y: u32x16) -> u32x16 { - // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.uadd.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u64x2 -#[no_mangle] -pub unsafe fn uadd_u64x2(x: u64x2, y: u64x2) -> u64x2 { - // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.uadd.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u64x4 -#[no_mangle] -pub unsafe fn uadd_u64x4(x: u64x4, y: u64x4) -> u64x4 { - // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.uadd.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u64x8 -#[no_mangle] -pub unsafe fn uadd_u64x8(x: u64x8, y: u64x8) -> u64x8 { - // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.uadd.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u128x2 -#[no_mangle] -pub unsafe fn uadd_u128x2(x: u128x2, y: u128x2) -> u128x2 { - // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.uadd.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @uadd_u128x4 -#[no_mangle] -pub unsafe fn uadd_u128x4(x: u128x4, y: u128x4) -> u128x4 { - // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.uadd.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}}) - simd_saturating_add(x, y) -} - -// CHECK-LABEL: @ssub_i8x2 -#[no_mangle] -pub unsafe fn ssub_i8x2(x: i8x2, y: i8x2) -> i8x2 { - // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i8x4 -#[no_mangle] -pub unsafe fn ssub_i8x4(x: i8x4, y: i8x4) -> i8x4 { - // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i8x8 -#[no_mangle] -pub unsafe fn ssub_i8x8(x: i8x8, y: i8x8) -> i8x8 { - // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.ssub.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i8x16 -#[no_mangle] -pub unsafe fn ssub_i8x16(x: i8x16, y: i8x16) -> i8x16 { - // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i8x32 -#[no_mangle] -pub unsafe fn ssub_i8x32(x: i8x32, y: i8x32) -> i8x32 { - // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.ssub.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i8x64 -#[no_mangle] -pub unsafe fn ssub_i8x64(x: i8x64, y: i8x64) -> i8x64 { - // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.ssub.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i16x2 -#[no_mangle] -pub unsafe fn ssub_i16x2(x: i16x2, y: i16x2) -> i16x2 { - // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i16x4 -#[no_mangle] -pub unsafe fn ssub_i16x4(x: i16x4, y: i16x4) -> i16x4 { - // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.ssub.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i16x8 -#[no_mangle] -pub unsafe fn ssub_i16x8(x: i16x8, y: i16x8) -> i16x8 { - // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i16x16 -#[no_mangle] -pub unsafe fn ssub_i16x16(x: i16x16, y: i16x16) -> i16x16 { - // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.ssub.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i16x32 -#[no_mangle] -pub unsafe fn ssub_i16x32(x: i16x32, y: i16x32) -> i16x32 { - // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.ssub.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i32x2 -#[no_mangle] -pub unsafe fn ssub_i32x2(x: i32x2, y: i32x2) -> i32x2 { - // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.ssub.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i32x4 -#[no_mangle] -pub unsafe fn ssub_i32x4(x: i32x4, y: i32x4) -> i32x4 { - // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i32x8 -#[no_mangle] -pub unsafe fn ssub_i32x8(x: i32x8, y: i32x8) -> i32x8 { - // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i32x16 -#[no_mangle] -pub unsafe fn ssub_i32x16(x: i32x16, y: i32x16) -> i32x16 { - // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.ssub.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i64x2 -#[no_mangle] -pub unsafe fn ssub_i64x2(x: i64x2, y: i64x2) -> i64x2 { - // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.ssub.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i64x4 -#[no_mangle] -pub unsafe fn ssub_i64x4(x: i64x4, y: i64x4) -> i64x4 { - // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.ssub.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i64x8 -#[no_mangle] -pub unsafe fn ssub_i64x8(x: i64x8, y: i64x8) -> i64x8 { - // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.ssub.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i128x2 -#[no_mangle] -pub unsafe fn ssub_i128x2(x: i128x2, y: i128x2) -> i128x2 { - // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.ssub.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @ssub_i128x4 -#[no_mangle] -pub unsafe fn ssub_i128x4(x: i128x4, y: i128x4) -> i128x4 { - // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.ssub.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u8x2 -#[no_mangle] -pub unsafe fn usub_u8x2(x: u8x2, y: u8x2) -> u8x2 { - // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u8x4 -#[no_mangle] -pub unsafe fn usub_u8x4(x: u8x4, y: u8x4) -> u8x4 { - // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u8x8 -#[no_mangle] -pub unsafe fn usub_u8x8(x: u8x8, y: u8x8) -> u8x8 { - // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.usub.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u8x16 -#[no_mangle] -pub unsafe fn usub_u8x16(x: u8x16, y: u8x16) -> u8x16 { - // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u8x32 -#[no_mangle] -pub unsafe fn usub_u8x32(x: u8x32, y: u8x32) -> u8x32 { - // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u8x64 -#[no_mangle] -pub unsafe fn usub_u8x64(x: u8x64, y: u8x64) -> u8x64 { - // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u16x2 -#[no_mangle] -pub unsafe fn usub_u16x2(x: u16x2, y: u16x2) -> u16x2 { - // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u16x4 -#[no_mangle] -pub unsafe fn usub_u16x4(x: u16x4, y: u16x4) -> u16x4 { - // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.usub.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u16x8 -#[no_mangle] -pub unsafe fn usub_u16x8(x: u16x8, y: u16x8) -> u16x8 { - // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.usub.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u16x16 -#[no_mangle] -pub unsafe fn usub_u16x16(x: u16x16, y: u16x16) -> u16x16 { - // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u16x32 -#[no_mangle] -pub unsafe fn usub_u16x32(x: u16x32, y: u16x32) -> u16x32 { - // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u32x2 -#[no_mangle] -pub unsafe fn usub_u32x2(x: u32x2, y: u32x2) -> u32x2 { - // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.usub.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u32x4 -#[no_mangle] -pub unsafe fn usub_u32x4(x: u32x4, y: u32x4) -> u32x4 { - // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u32x8 -#[no_mangle] -pub unsafe fn usub_u32x8(x: u32x8, y: u32x8) -> u32x8 { - // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u32x16 -#[no_mangle] -pub unsafe fn usub_u32x16(x: u32x16, y: u32x16) -> u32x16 { - // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.usub.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u64x2 -#[no_mangle] -pub unsafe fn usub_u64x2(x: u64x2, y: u64x2) -> u64x2 { - // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u64x4 -#[no_mangle] -pub unsafe fn usub_u64x4(x: u64x4, y: u64x4) -> u64x4 { - // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.usub.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u64x8 -#[no_mangle] -pub unsafe fn usub_u64x8(x: u64x8, y: u64x8) -> u64x8 { - // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.usub.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u128x2 -#[no_mangle] -pub unsafe fn usub_u128x2(x: u128x2, y: u128x2) -> u128x2 { - // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.usub.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}}) - simd_saturating_sub(x, y) -} - -// CHECK-LABEL: @usub_u128x4 -#[no_mangle] -pub unsafe fn usub_u128x4(x: u128x4, y: u128x4) -> u128x4 { - // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.usub.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}}) - simd_saturating_sub(x, y) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs deleted file mode 100644 index 294262d8152..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs +++ /dev/null @@ -1,48 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -// - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_bitmask; - -// NOTE(eddyb) `%{{x|1}}` is used because on some targets (e.g. WASM) -// SIMD vectors are passed directly, resulting in `%x` being a vector, -// while on others they're passed indirectly, resulting in `%x` being -// a pointer to a vector, and `%1` a vector loaded from that pointer. -// This is controlled by the target spec option `simd_types_indirect`. - -// CHECK-LABEL: @bitmask_int -#[no_mangle] -pub unsafe fn bitmask_int(x: i32x2) -> u8 { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> - // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2 - // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8 - simd_bitmask(x) -} - -// CHECK-LABEL: @bitmask_uint -#[no_mangle] -pub unsafe fn bitmask_uint(x: u32x2) -> u8 { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> - // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2 - // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8 - simd_bitmask(x) -} - -// CHECK-LABEL: @bitmask_int16 -#[no_mangle] -pub unsafe fn bitmask_int16(x: i8x16) -> u16 { - // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1|2}}, {{|splat \(i8 7\)}} - // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1> - // CHECK: %{{[0-9]+}} = bitcast <16 x i1> [[B]] to i16 - // CHECK-NOT: zext - simd_bitmask(x) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs deleted file mode 100644 index 690bfb432f9..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs +++ /dev/null @@ -1,55 +0,0 @@ -// - -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_gather; - -pub type Vec2 = Simd; -pub type Vec4 = Simd; - -// CHECK-LABEL: @gather_f32x2 -#[no_mangle] -pub unsafe fn gather_f32x2( - pointers: Vec2<*const f32>, - mask: Vec2, - values: Vec2, -) -> Vec2 { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> - // CHECK: call <2 x float> @llvm.masked.gather.v2f32.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]], <2 x float> {{.*}}) - simd_gather(values, pointers, mask) -} - -// CHECK-LABEL: @gather_f32x2_unsigned -#[no_mangle] -pub unsafe fn gather_f32x2_unsigned( - pointers: Vec2<*const f32>, - mask: Vec2, - values: Vec2, -) -> Vec2 { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> - // CHECK: call <2 x float> @llvm.masked.gather.v2f32.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]], <2 x float> {{.*}}) - simd_gather(values, pointers, mask) -} - -// CHECK-LABEL: @gather_pf32x2 -#[no_mangle] -pub unsafe fn gather_pf32x2( - pointers: Vec2<*const *const f32>, - mask: Vec2, - values: Vec2<*const f32>, -) -> Vec2<*const f32> { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> - // CHECK: call <2 x ptr> @llvm.masked.gather.v2p0.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]], <2 x ptr> {{.*}}) - simd_gather(values, pointers, mask) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs deleted file mode 100644 index fda315dc66c..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs +++ /dev/null @@ -1,49 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_masked_load; - -pub type Vec2 = Simd; -pub type Vec4 = Simd; - -// CHECK-LABEL: @load_f32x2 -#[no_mangle] -pub unsafe fn load_f32x2(mask: Vec2, pointer: *const f32, values: Vec2) -> Vec2 { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> - // CHECK: call <2 x float> @llvm.masked.load.v2f32.p0(ptr {{.*}}, i32 4, <2 x i1> [[B]], <2 x float> {{.*}}) - simd_masked_load(mask, pointer, values) -} - -// CHECK-LABEL: @load_f32x2_unsigned -#[no_mangle] -pub unsafe fn load_f32x2_unsigned( - mask: Vec2, - pointer: *const f32, - values: Vec2, -) -> Vec2 { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> - // CHECK: call <2 x float> @llvm.masked.load.v2f32.p0(ptr {{.*}}, i32 4, <2 x i1> [[B]], <2 x float> {{.*}}) - simd_masked_load(mask, pointer, values) -} - -// CHECK-LABEL: @load_pf32x4 -#[no_mangle] -pub unsafe fn load_pf32x4( - mask: Vec4, - pointer: *const *const f32, - values: Vec4<*const f32>, -) -> Vec4<*const f32> { - // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> {{.*}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1> - // CHECK: call <4 x ptr> @llvm.masked.load.v4p0.p0(ptr {{.*}}, i32 {{.*}}, <4 x i1> [[B]], <4 x ptr> {{.*}}) - simd_masked_load(mask, pointer, values) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs deleted file mode 100644 index 6ca7388d464..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs +++ /dev/null @@ -1,41 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_masked_store; - -pub type Vec2 = Simd; -pub type Vec4 = Simd; - -// CHECK-LABEL: @store_f32x2 -#[no_mangle] -pub unsafe fn store_f32x2(mask: Vec2, pointer: *mut f32, values: Vec2) { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> - // CHECK: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr {{.*}}, i32 4, <2 x i1> [[B]]) - simd_masked_store(mask, pointer, values) -} - -// CHECK-LABEL: @store_f32x2_unsigned -#[no_mangle] -pub unsafe fn store_f32x2_unsigned(mask: Vec2, pointer: *mut f32, values: Vec2) { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> - // CHECK: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr {{.*}}, i32 4, <2 x i1> [[B]]) - simd_masked_store(mask, pointer, values) -} - -// CHECK-LABEL: @store_pf32x4 -#[no_mangle] -pub unsafe fn store_pf32x4(mask: Vec4, pointer: *mut *const f32, values: Vec4<*const f32>) { - // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> {{.*}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1> - // CHECK: call void @llvm.masked.store.v4p0.p0(<4 x ptr> {{.*}}, ptr {{.*}}, i32 {{.*}}, <4 x i1> [[B]]) - simd_masked_store(mask, pointer, values) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs deleted file mode 100644 index 743652966e1..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs +++ /dev/null @@ -1,47 +0,0 @@ -// - -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::simd_scatter; - -pub type Vec2 = Simd; -pub type Vec4 = Simd; - -// CHECK-LABEL: @scatter_f32x2 -#[no_mangle] -pub unsafe fn scatter_f32x2(pointers: Vec2<*mut f32>, mask: Vec2, values: Vec2) { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> - // CHECK: call void @llvm.masked.scatter.v2f32.v2p0(<2 x float> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]] - simd_scatter(values, pointers, mask) -} - -// CHECK-LABEL: @scatter_f32x2_unsigned -#[no_mangle] -pub unsafe fn scatter_f32x2_unsigned(pointers: Vec2<*mut f32>, mask: Vec2, values: Vec2) { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> - // CHECK: call void @llvm.masked.scatter.v2f32.v2p0(<2 x float> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]] - simd_scatter(values, pointers, mask) -} - -// CHECK-LABEL: @scatter_pf32x2 -#[no_mangle] -pub unsafe fn scatter_pf32x2( - pointers: Vec2<*mut *const f32>, - mask: Vec2, - values: Vec2<*const f32>, -) { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> - // CHECK: call void @llvm.masked.scatter.v2p0.v2p0(<2 x ptr> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]] - simd_scatter(values, pointers, mask) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs deleted file mode 100644 index 2c0bad21f44..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs +++ /dev/null @@ -1,48 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::{simd_select, simd_select_bitmask}; - -pub type b8x4 = i8x4; - -// CHECK-LABEL: @select_m8 -#[no_mangle] -pub unsafe fn select_m8(m: b8x4, a: f32x4, b: f32x4) -> f32x4 { - // CHECK: [[A:%[0-9]+]] = lshr <4 x i8> %{{.*}}, {{|splat \(i8 7\)}} - // CHECK: [[B:%[0-9]+]] = trunc <4 x i8> [[A]] to <4 x i1> - // CHECK: select <4 x i1> [[B]] - simd_select(m, a, b) -} - -// CHECK-LABEL: @select_m32 -#[no_mangle] -pub unsafe fn select_m32(m: i32x4, a: f32x4, b: f32x4) -> f32x4 { - // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> %{{.*}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1> - // CHECK: select <4 x i1> [[B]] - simd_select(m, a, b) -} - -// CHECK-LABEL: @select_m32_unsigned -#[no_mangle] -pub unsafe fn select_m32_unsigned(m: u32x4, a: f32x4, b: f32x4) -> f32x4 { - // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> %{{.*}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1> - // CHECK: select <4 x i1> [[B]] - simd_select(m, a, b) -} - -// CHECK-LABEL: @select_bitmask -#[no_mangle] -pub unsafe fn select_bitmask(m: i8, a: f32x8, b: f32x8) -> f32x8 { - // CHECK: [[A:%[0-9]+]] = bitcast i8 {{.*}} to <8 x i1> - // CHECK: select <8 x i1> [[A]] - simd_select_bitmask(m, a, b) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs deleted file mode 100644 index 79f00a6ed60..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -use std::intrinsics::simd::{simd_reduce_all, simd_reduce_any}; - -pub type mask32x2 = Simd; -pub type mask8x16 = Simd; - -// NOTE(eddyb) `%{{x|1}}` is used because on some targets (e.g. WASM) -// SIMD vectors are passed directly, resulting in `%x` being a vector, -// while on others they're passed indirectly, resulting in `%x` being -// a pointer to a vector, and `%1` a vector loaded from that pointer. -// This is controlled by the target spec option `simd_types_indirect`. - -// CHECK-LABEL: @reduce_any_32x2 -#[no_mangle] -pub unsafe fn reduce_any_32x2(x: mask32x2) -> bool { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> - // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.or.v2i1(<2 x i1> [[B]]) - // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8 - simd_reduce_any(x) -} - -// CHECK-LABEL: @reduce_all_32x2 -#[no_mangle] -pub unsafe fn reduce_all_32x2(x: mask32x2) -> bool { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{|splat \(i32 31\)}} - // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> - // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.and.v2i1(<2 x i1> [[B]]) - // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8 - simd_reduce_all(x) -} - -// CHECK-LABEL: @reduce_any_8x16 -#[no_mangle] -pub unsafe fn reduce_any_8x16(x: mask8x16) -> bool { - // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1}}, {{|splat \(i8 7\)}} - // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1> - // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.or.v16i1(<16 x i1> [[B]]) - // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8 - simd_reduce_any(x) -} - -// CHECK-LABEL: @reduce_all_8x16 -#[no_mangle] -pub unsafe fn reduce_all_8x16(x: mask8x16) -> bool { - // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1}}, {{|splat \(i8 7\)}} - // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1> - // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.and.v16i1(<16 x i1> [[B]]) - // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8 - simd_reduce_all(x) -} diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs deleted file mode 100644 index 05c2f7e1bdf..00000000000 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs +++ /dev/null @@ -1,58 +0,0 @@ -// -//@ compile-flags: -C no-prepopulate-passes -// 32bit MSVC does not align things properly so we suppress high alignment annotations (#112480) -//@ ignore-i686-pc-windows-msvc -//@ ignore-i686-pc-windows-gnu - -#![crate_type = "lib"] -#![allow(non_camel_case_types)] -#![feature(repr_simd, core_intrinsics)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::*; - -pub type S = Simd; -pub type T = Simd; - -// CHECK-LABEL: @array_align( -#[no_mangle] -pub fn array_align() -> usize { - // CHECK: ret [[USIZE:i[0-9]+]] [[ARRAY_ALIGN:[0-9]+]] - const { std::mem::align_of::() } -} - -// CHECK-LABEL: @vector_align( -#[no_mangle] -pub fn vector_align() -> usize { - // CHECK: ret [[USIZE]] [[VECTOR_ALIGN:[0-9]+]] - const { std::mem::align_of::() } -} - -// CHECK-LABEL: @build_array_s -#[no_mangle] -pub fn build_array_s(x: [f32; 4]) -> S<4> { - // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) - Simd(x) -} - -// CHECK-LABEL: @build_array_transmute_s -#[no_mangle] -pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> { - // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) - unsafe { std::mem::transmute(x) } -} - -// CHECK-LABEL: @build_array_t -#[no_mangle] -pub fn build_array_t(x: [f32; 4]) -> T { - // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) - Simd(x) -} - -// CHECK-LABEL: @build_array_transmute_t -#[no_mangle] -pub fn build_array_transmute_t(x: [f32; 4]) -> T { - // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) - unsafe { std::mem::transmute(x) } -} diff --git a/tests/codegen/simd/aggregate-simd.rs b/tests/codegen/simd/aggregate-simd.rs deleted file mode 100644 index 57a301d634c..00000000000 --- a/tests/codegen/simd/aggregate-simd.rs +++ /dev/null @@ -1,102 +0,0 @@ -//@ compile-flags: -C opt-level=3 -C no-prepopulate-passes -//@ only-64bit - -#![feature(core_intrinsics, repr_simd)] -#![no_std] -#![crate_type = "lib"] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use core::intrinsics::simd::{simd_add, simd_extract}; - -use minisimd::*; - -#[repr(transparent)] -pub struct Transparent(T); - -// These tests don't actually care about the add/extract, but it ensures the -// aggregated temporaries are only used in potentially-SSA ways. - -#[no_mangle] -pub fn simd_aggregate_pot(x: [u32; 4], y: [u32; 4]) -> u32 { - // CHECK-LABEL: simd_aggregate_pot - // CHECK: %a = load <4 x i32>, ptr %x, align 4 - // CHECK: %b = load <4 x i32>, ptr %y, align 4 - // CHECK: add <4 x i32> %a, %b - - unsafe { - let a = Simd(x); - let b = Simd(y); - let c = simd_add(a, b); - simd_extract(c, 1) - } -} - -#[no_mangle] -pub fn simd_aggregate_npot(x: [u32; 7], y: [u32; 7]) -> u32 { - // CHECK-LABEL: simd_aggregate_npot - // CHECK: %a = load <7 x i32>, ptr %x, align 4 - // CHECK: %b = load <7 x i32>, ptr %y, align 4 - // CHECK: add <7 x i32> %a, %b - - unsafe { - let a = Simd(x); - let b = Simd(y); - let c = simd_add(a, b); - simd_extract(c, 1) - } -} - -#[no_mangle] -pub fn packed_simd_aggregate_pot(x: [u32; 4], y: [u32; 4]) -> u32 { - // CHECK-LABEL: packed_simd_aggregate_pot - // CHECK: %a = load <4 x i32>, ptr %x, align 4 - // CHECK: %b = load <4 x i32>, ptr %y, align 4 - // CHECK: add <4 x i32> %a, %b - - unsafe { - let a = PackedSimd(x); - let b = PackedSimd(y); - let c = simd_add(a, b); - simd_extract(c, 1) - } -} - -#[no_mangle] -pub fn packed_simd_aggregate_npot(x: [u32; 7], y: [u32; 7]) -> u32 { - // CHECK-LABEL: packed_simd_aggregate_npot - // CHECK: %b = alloca [28 x i8], align 4 - // CHECK: %a = alloca [28 x i8], align 4 - // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a, ptr align 4 %x, i64 28, i1 false) - // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %b, ptr align 4 %y, i64 28, i1 false) - // CHECK: %[[TEMPA:.+]] = load <7 x i32>, ptr %a, align 4 - // CHECK: %[[TEMPB:.+]] = load <7 x i32>, ptr %b, align 4 - // CHECK: add <7 x i32> %[[TEMPA]], %[[TEMPB]] - - unsafe { - let a = PackedSimd(x); - let b = PackedSimd(y); - let c = simd_add(a, b); - simd_extract(c, 1) - } -} - -#[no_mangle] -pub fn transparent_simd_aggregate(x: [u32; 4]) -> u32 { - // The transparent wrapper can just use the same SSA value as its field. - // No extra processing or spilling needed. - - // CHECK-LABEL: transparent_simd_aggregate - // CHECK-NOT: alloca - // CHECK: %[[RET:.+]] = alloca [4 x i8] - // CHECK-NOT: alloca - // CHECK: %a = load <4 x i32>, ptr %x, align 4 - // CHECK: %[[TEMP:.+]] = extractelement <4 x i32> %a, i32 1 - // CHECK: store i32 %[[TEMP]], ptr %[[RET]] - - unsafe { - let a = Simd(x); - let b = Transparent(a); - simd_extract(b.0, 1) - } -} diff --git a/tests/codegen/simd/extract-insert-dyn.rs b/tests/codegen/simd/extract-insert-dyn.rs deleted file mode 100644 index 729f0145314..00000000000 --- a/tests/codegen/simd/extract-insert-dyn.rs +++ /dev/null @@ -1,121 +0,0 @@ -//@compile-flags: -C opt-level=3 -C no-prepopulate-passes - -#![feature( - core_intrinsics, - repr_simd, - arm_target_feature, - mips_target_feature, - s390x_target_feature -)] -#![no_std] -#![crate_type = "lib"] -#![allow(non_camel_case_types)] - -// Test that `core::intrinsics::simd::{simd_extract_dyn, simd_insert_dyn}` -// lower to an LLVM extractelement or insertelement operation. - -use core::intrinsics::simd::{simd_extract, simd_extract_dyn, simd_insert, simd_insert_dyn}; - -#[repr(simd)] -#[derive(Clone, Copy)] -pub struct u32x16([u32; 16]); - -#[repr(simd)] -#[derive(Clone, Copy)] -pub struct i8x16([i8; 16]); - -// CHECK-LABEL: dyn_simd_extract -// CHECK: extractelement <16 x i8> %x, i32 %idx -#[no_mangle] -#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] -#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] -#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] -#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] -#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] -unsafe extern "C" fn dyn_simd_extract(x: i8x16, idx: u32) -> i8 { - simd_extract_dyn(x, idx) -} - -// CHECK-LABEL: literal_dyn_simd_extract -// CHECK: extractelement <16 x i8> %x, i32 7 -#[no_mangle] -#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] -#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] -#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] -#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] -#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] -unsafe extern "C" fn literal_dyn_simd_extract(x: i8x16) -> i8 { - simd_extract_dyn(x, 7) -} - -// CHECK-LABEL: const_dyn_simd_extract -// CHECK: extractelement <16 x i8> %x, i32 7 -#[no_mangle] -#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] -#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] -#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] -#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] -#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] -unsafe extern "C" fn const_dyn_simd_extract(x: i8x16) -> i8 { - simd_extract_dyn(x, const { 3 + 4 }) -} - -// CHECK-LABEL: const_simd_extract -// CHECK: extractelement <16 x i8> %x, i32 7 -#[no_mangle] -#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] -#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] -#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] -#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] -#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] -unsafe extern "C" fn const_simd_extract(x: i8x16) -> i8 { - simd_extract(x, const { 3 + 4 }) -} - -// CHECK-LABEL: dyn_simd_insert -// CHECK: insertelement <16 x i8> %x, i8 %e, i32 %idx -#[no_mangle] -#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] -#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] -#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] -#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] -#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] -unsafe extern "C" fn dyn_simd_insert(x: i8x16, e: i8, idx: u32) -> i8x16 { - simd_insert_dyn(x, idx, e) -} - -// CHECK-LABEL: literal_dyn_simd_insert -// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7 -#[no_mangle] -#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] -#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] -#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] -#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] -#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] -unsafe extern "C" fn literal_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { - simd_insert_dyn(x, 7, e) -} - -// CHECK-LABEL: const_dyn_simd_insert -// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7 -#[no_mangle] -#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] -#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] -#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] -#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] -#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] -unsafe extern "C" fn const_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { - simd_insert_dyn(x, const { 3 + 4 }, e) -} - -// CHECK-LABEL: const_simd_insert -// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7 -#[no_mangle] -#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] -#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] -#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] -#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] -#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] -unsafe extern "C" fn const_simd_insert(x: i8x16, e: i8) -> i8x16 { - simd_insert(x, const { 3 + 4 }, e) -} diff --git a/tests/codegen/simd/packed-simd-alignment.rs b/tests/codegen/simd/packed-simd-alignment.rs deleted file mode 100644 index 53e88d8e5cf..00000000000 --- a/tests/codegen/simd/packed-simd-alignment.rs +++ /dev/null @@ -1,44 +0,0 @@ -//@ compile-flags: -Cno-prepopulate-passes - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] -// make sure that codegen emits correctly-aligned loads and stores for repr(packed, simd) types -// the alignment of a load should be no less than T, and no more than the size of the vector type -use std::intrinsics::simd as intrinsics; - -#[derive(Copy, Clone)] -#[repr(packed, simd)] -struct f32x3([f32; 3]); - -#[derive(Copy, Clone)] -#[repr(packed, simd)] -struct f32x4([f32; 4]); - -// CHECK-LABEL: load_f32x3 -#[no_mangle] -pub fn load_f32x3(floats: &f32x3) -> f32x3 { - // FIXME: Is a memcpy really the best we can do? - // CHECK: @llvm.memcpy.{{.*}}ptr align 4 {{.*}}ptr align 4 - *floats -} - -// CHECK-LABEL: load_f32x4 -#[no_mangle] -pub fn load_f32x4(floats: &f32x4) -> f32x4 { - // CHECK: load <4 x float>, ptr %{{[a-z0-9_]*}}, align {{4|8|16}} - *floats -} - -// CHECK-LABEL: add_f32x3 -#[no_mangle] -pub fn add_f32x3(x: f32x3, y: f32x3) -> f32x3 { - // CHECK: load <3 x float>, ptr %{{[a-z0-9_]*}}, align 4 - unsafe { intrinsics::simd_add(x, y) } -} - -// CHECK-LABEL: add_f32x4 -#[no_mangle] -pub fn add_f32x4(x: f32x4, y: f32x4) -> f32x4 { - // CHECK: load <4 x float>, ptr %{{[a-z0-9_]*}}, align {{4|8|16}} - unsafe { intrinsics::simd_add(x, y) } -} diff --git a/tests/codegen/simd/packed-simd.rs b/tests/codegen/simd/packed-simd.rs deleted file mode 100644 index 70c03fcc955..00000000000 --- a/tests/codegen/simd/packed-simd.rs +++ /dev/null @@ -1,56 +0,0 @@ -//@ revisions:opt3 noopt -//@ only-x86_64 -//@[opt3] compile-flags: -Copt-level=3 -//@[noopt] compile-flags: -Cno-prepopulate-passes - -#![crate_type = "lib"] -#![no_std] -#![feature(repr_simd, core_intrinsics)] -use core::intrinsics::simd as intrinsics; -use core::{mem, ptr}; - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use minisimd::{PackedSimd, Simd as FullSimd}; - -// Test codegen for not only "packed" but also "fully aligned" SIMD types, and conversion between -// them. A repr(packed,simd) type with 3 elements can't exceed its element alignment, whereas the -// same type as repr(simd) will instead have padding. - -// non-powers-of-two have padding and need to be expanded to full vectors -fn load(v: PackedSimd) -> FullSimd { - unsafe { - let mut tmp = mem::MaybeUninit::>::uninit(); - ptr::copy_nonoverlapping(&v as *const _, tmp.as_mut_ptr().cast(), 1); - tmp.assume_init() - } -} - -// CHECK-LABEL: square_packed_full -// CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align (8|16)]]{{[^%]*}} [[RET_VREG:%[_0-9]*]] -// CHECK-SAME: ptr{{[a-z_ ]*}} align 4 -#[no_mangle] -pub fn square_packed_full(x: PackedSimd) -> FullSimd { - // CHECK-NEXT: start - // noopt: alloca [[RET_TYPE]], [[RET_ALIGN]] - // CHECK: load <3 x float> - let x = load(x); - // CHECK: [[VREG:%[a-z0-9_]+]] = fmul <3 x float> - // CHECK-NEXT: store <3 x float> [[VREG]], ptr [[RET_VREG]], [[RET_ALIGN]] - // CHECK-NEXT: ret void - unsafe { intrinsics::simd_mul(x, x) } -} - -// CHECK-LABEL: square_packed -// CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align 4]]{{[^%]*}} [[RET_VREG:%[_0-9]*]] -// CHECK-SAME: ptr{{[a-z_ ]*}} align 4 -#[no_mangle] -pub fn square_packed(x: PackedSimd) -> PackedSimd { - // CHECK-NEXT: start - // CHECK-NEXT: load <3 x float> - // noopt-NEXT: load <3 x float> - // CHECK-NEXT: [[VREG:%[a-z0-9_]+]] = fmul <3 x float> - // CHECK-NEXT: store <3 x float> [[VREG]], ptr [[RET_VREG]], [[RET_ALIGN]] - // CHECK-NEXT: ret void - unsafe { intrinsics::simd_mul(x, x) } -} diff --git a/tests/codegen/simd/simd-wide-sum.rs b/tests/codegen/simd/simd-wide-sum.rs deleted file mode 100644 index 95117b2c748..00000000000 --- a/tests/codegen/simd/simd-wide-sum.rs +++ /dev/null @@ -1,59 +0,0 @@ -//@ revisions: llvm mir-opt3 -//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled -//@ edition: 2021 -//@ only-x86_64 -//@ [mir-opt3]compile-flags: -Zmir-opt-level=3 -//@ [mir-opt3]build-pass - -// mir-opt3 is a regression test for https://github.com/rust-lang/rust/issues/98016 - -#![crate_type = "lib"] -#![feature(portable_simd)] - -use std::simd::prelude::*; -const N: usize = 16; - -#[no_mangle] -// CHECK-LABEL: @wider_reduce_simd -pub fn wider_reduce_simd(x: Simd) -> u16 { - // CHECK: zext <16 x i8> - // CHECK-SAME: to <16 x i16> - // CHECK: call i16 @llvm.vector.reduce.add.v16i16(<16 x i16> - let x: Simd = x.cast(); - x.reduce_sum() -} - -#[no_mangle] -// CHECK-LABEL: @wider_reduce_loop -pub fn wider_reduce_loop(x: Simd) -> u16 { - // CHECK: zext <16 x i8> - // CHECK-SAME: to <16 x i16> - // CHECK: call i16 @llvm.vector.reduce.add.v16i16(<16 x i16> - let mut sum = 0_u16; - for i in 0..N { - sum += u16::from(x[i]); - } - sum -} - -#[no_mangle] -// CHECK-LABEL: @wider_reduce_iter -pub fn wider_reduce_iter(x: Simd) -> u16 { - // CHECK: zext <16 x i8> - // CHECK-SAME: to <16 x i16> - // CHECK: call i16 @llvm.vector.reduce.add.v16i16(<16 x i16> - x.as_array().iter().copied().map(u16::from).sum() -} - -// This iterator one is the most interesting, as it's the one -// which used to not auto-vectorize due to a suboptimality in the -// `::fold` implementation. - -#[no_mangle] -// CHECK-LABEL: @wider_reduce_into_iter -pub fn wider_reduce_into_iter(x: Simd) -> u16 { - // CHECK: zext <16 x i8> - // CHECK-SAME: to <16 x i16> - // CHECK: call i16 @llvm.vector.reduce.add.v16i16(<16 x i16> - x.to_array().into_iter().map(u16::from).sum() -} diff --git a/tests/codegen/simd/simd_arith_offset.rs b/tests/codegen/simd/simd_arith_offset.rs deleted file mode 100644 index 210b4e9bb50..00000000000 --- a/tests/codegen/simd/simd_arith_offset.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -//@ only-64bit (because the LLVM type of i64 for usize shows up) -// - -#![crate_type = "lib"] -#![feature(repr_simd, core_intrinsics)] - -#[path = "../../auxiliary/minisimd.rs"] -mod minisimd; -use std::intrinsics::simd::simd_arith_offset; - -use minisimd::*; - -/// A vector of *const T. -pub type SimdConstPtr = Simd<*const T, LANES>; - -// CHECK-LABEL: smoke -#[no_mangle] -pub fn smoke(ptrs: SimdConstPtr, offsets: Simd) -> SimdConstPtr { - // CHECK: getelementptr i8, <8 x ptr> %0, <8 x i64> %1 - unsafe { simd_arith_offset(ptrs, offsets) } -} diff --git a/tests/codegen/simd/swap-simd-types.rs b/tests/codegen/simd/swap-simd-types.rs deleted file mode 100644 index c063cc683a6..00000000000 --- a/tests/codegen/simd/swap-simd-types.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C target-feature=+avx -//@ only-x86_64 - -#![crate_type = "lib"] - -use std::mem::swap; - -// SIMD types are highly-aligned already, so make sure the swap code leaves their -// types alone and doesn't pessimize them (such as by swapping them as `usize`s). -extern crate core; -use core::arch::x86_64::__m256; - -// CHECK-LABEL: @swap_single_m256 -#[no_mangle] -pub fn swap_single_m256(x: &mut __m256, y: &mut __m256) { - // CHECK-NOT: alloca - // CHECK: load <8 x float>{{.+}}align 32 - // CHECK: store <8 x float>{{.+}}align 32 - swap(x, y) -} - -// CHECK-LABEL: @swap_m256_slice -#[no_mangle] -pub fn swap_m256_slice(x: &mut [__m256], y: &mut [__m256]) { - // CHECK-NOT: alloca - // CHECK-COUNT-2: load <4 x i64>{{.+}}align 32 - // CHECK-COUNT-2: store <4 x i64>{{.+}}align 32 - if x.len() == y.len() { - x.swap_with_slice(y); - } -} - -// CHECK-LABEL: @swap_bytes32 -#[no_mangle] -pub fn swap_bytes32(x: &mut [u8; 32], y: &mut [u8; 32]) { - // CHECK-NOT: alloca - // CHECK-COUNT-2: load <4 x i64>{{.+}}align 1 - // CHECK-COUNT-2: store <4 x i64>{{.+}}align 1 - swap(x, y) -} diff --git a/tests/codegen/simd/unpadded-simd.rs b/tests/codegen/simd/unpadded-simd.rs deleted file mode 100644 index ef067a15702..00000000000 --- a/tests/codegen/simd/unpadded-simd.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Make sure that no 0-sized padding is inserted in structs and that -// structs are represented as expected by Neon intrinsics in LLVM. -// See #87254. - -#![crate_type = "lib"] -#![feature(repr_simd, abi_unadjusted)] - -#[derive(Copy, Clone)] -#[repr(simd)] -pub struct int16x4_t(pub [i16; 4]); - -#[derive(Copy, Clone)] -pub struct int16x4x2_t(pub int16x4_t, pub int16x4_t); - -// CHECK: %int16x4x2_t = type { <4 x i16>, <4 x i16> } -#[no_mangle] -extern "unadjusted" fn takes_int16x4x2_t(t: int16x4x2_t) -> int16x4x2_t { - t -} diff --git a/tests/codegen/skip-mono-inside-if-false.rs b/tests/codegen/skip-mono-inside-if-false.rs deleted file mode 100644 index 8b95de99dd3..00000000000 --- a/tests/codegen/skip-mono-inside-if-false.rs +++ /dev/null @@ -1,41 +0,0 @@ -//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 - -#![crate_type = "lib"] - -#[no_mangle] -pub fn demo_for_i32() { - generic_impl::(); -} - -// Two important things here: -// - We replace the "then" block with `unreachable` to avoid linking problems -// - We neither declare nor define the `big_impl` that said block "calls". - -// CHECK-LABEL: ; skip_mono_inside_if_false::generic_impl -// CHECK: start: -// CHECK-NEXT: br label %[[ELSE_BRANCH:bb[0-9]+]] -// CHECK: [[ELSE_BRANCH]]: -// CHECK-NEXT: call skip_mono_inside_if_false::small_impl -// CHECK: bb{{[0-9]+}}: -// CHECK-NEXT: ret void -// CHECK: bb{{[0-9+]}}: -// CHECK-NEXT: unreachable - -fn generic_impl() { - trait MagicTrait { - const IS_BIG: bool; - } - impl MagicTrait for T { - const IS_BIG: bool = std::mem::size_of::() > 10; - } - if T::IS_BIG { - big_impl::(); - } else { - small_impl::(); - } -} - -#[inline(never)] -fn small_impl() {} -#[inline(never)] -fn big_impl() {} diff --git a/tests/codegen/slice-as_chunks.rs b/tests/codegen/slice-as_chunks.rs deleted file mode 100644 index 337eb8981f6..00000000000 --- a/tests/codegen/slice-as_chunks.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-64bit (because the LLVM type of i64 for usize shows up) - -#![crate_type = "lib"] - -// CHECK-LABEL: @chunks4 -#[no_mangle] -pub fn chunks4(x: &[u8]) -> &[[u8; 4]] { - // CHECK-NEXT: start: - // CHECK-NEXT: lshr i64 %x.1, 2 - // CHECK-NOT: shl - // CHECK-NOT: mul - // CHECK-NOT: udiv - // CHECK-NOT: urem - // CHECK: ret - x.as_chunks().0 -} - -// CHECK-LABEL: @chunks4_with_remainder -#[no_mangle] -pub fn chunks4_with_remainder(x: &[u8]) -> (&[[u8; 4]], &[u8]) { - // CHECK-DAG: and i64 %x.1, -4 - // CHECK-DAG: and i64 %x.1, 3 - // CHECK-DAG: lshr - // CHECK-NOT: mul - // CHECK-NOT: udiv - // CHECK-NOT: urem - // CHECK: ret - x.as_chunks() -} diff --git a/tests/codegen/slice-indexing.rs b/tests/codegen/slice-indexing.rs deleted file mode 100644 index d957ccfb5ef..00000000000 --- a/tests/codegen/slice-indexing.rs +++ /dev/null @@ -1,99 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-64bit (because the LLVM type of i64 for usize shows up) - -#![crate_type = "lib"] - -use std::ops::Range; - -// CHECK-LABEL: @index_by_range( -#[no_mangle] -pub fn index_by_range(x: &[u16], r: Range) -> &[u16] { - // CHECK: sub nuw i64 - &x[r] -} - -// CHECK-LABEL: @get_unchecked_by_range( -#[no_mangle] -pub unsafe fn get_unchecked_by_range(x: &[u16], r: Range) -> &[u16] { - // CHECK: sub nuw i64 - x.get_unchecked(r) -} - -// CHECK-LABEL: @index_mut_by_range( -#[no_mangle] -pub fn index_mut_by_range(x: &mut [i32], r: Range) -> &mut [i32] { - // CHECK: sub nuw i64 - &mut x[r] -} - -// CHECK-LABEL: @get_unchecked_mut_by_range( -#[no_mangle] -pub unsafe fn get_unchecked_mut_by_range(x: &mut [i32], r: Range) -> &mut [i32] { - // CHECK: sub nuw i64 - x.get_unchecked_mut(r) -} - -// CHECK-LABEL: @str_index_by_range( -#[no_mangle] -pub fn str_index_by_range(x: &str, r: Range) -> &str { - // CHECK: sub nuw i64 - &x[r] -} - -// CHECK-LABEL: @str_get_unchecked_by_range( -#[no_mangle] -pub unsafe fn str_get_unchecked_by_range(x: &str, r: Range) -> &str { - // CHECK: sub nuw i64 - x.get_unchecked(r) -} - -// CHECK-LABEL: @str_index_mut_by_range( -#[no_mangle] -pub fn str_index_mut_by_range(x: &mut str, r: Range) -> &mut str { - // CHECK: sub nuw i64 - &mut x[r] -} - -// CHECK-LABEL: @str_get_unchecked_mut_by_range( -#[no_mangle] -pub unsafe fn str_get_unchecked_mut_by_range(x: &mut str, r: Range) -> &mut str { - // CHECK: sub nuw i64 - x.get_unchecked_mut(r) -} - -// CHECK-LABEL: @slice_repeated_indexing( -#[no_mangle] -pub fn slice_repeated_indexing(dst: &mut [u8], offset: usize) { - let mut i = offset; - // CHECK: panic_bounds_check - dst[i] = 1; - i += 1; - // CHECK: panic_bounds_check - dst[i] = 2; - i += 1; - // CHECK: panic_bounds_check - dst[i] = 3; - i += 1; - // CHECK: panic_bounds_check - dst[i] = 4; -} - -// CHECK-LABEL: @slice_repeated_indexing_coalesced( -#[no_mangle] -pub fn slice_repeated_indexing_coalesced(dst: &mut [u8], offset: usize) { - let mut i = offset; - if i.checked_add(4).unwrap() <= dst.len() { - // CHECK-NOT: panic_bounds_check - dst[i] = 1; - i += 1; - // CHECK-NOT: panic_bounds_check - dst[i] = 2; - i += 1; - // CHECK-NOT: panic_bounds_check - dst[i] = 3; - i += 1; - // CHECK-NOT: panic_bounds_check - dst[i] = 4; - } - // CHECK: ret -} diff --git a/tests/codegen/slice-init.rs b/tests/codegen/slice-init.rs deleted file mode 100644 index 950e0b0c10d..00000000000 --- a/tests/codegen/slice-init.rs +++ /dev/null @@ -1,108 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "lib"] - -// CHECK-LABEL: @zero_sized_elem -#[no_mangle] -pub fn zero_sized_elem() { - // CHECK-NOT: br label %repeat_loop_header{{.*}} - // CHECK-NOT: call void @llvm.memset.p0 - let x = [(); 4]; - opaque(&x); -} - -// CHECK-LABEL: @zero_len_array -#[no_mangle] -pub fn zero_len_array() { - // CHECK-NOT: br label %repeat_loop_header{{.*}} - // CHECK-NOT: call void @llvm.memset.p0 - let x = [4; 0]; - opaque(&x); -} - -// CHECK-LABEL: @byte_array -#[no_mangle] -pub fn byte_array() { - // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}, i8 7, i{{[0-9]+}} 4 - // CHECK-NOT: br label %repeat_loop_header{{.*}} - let x = [7u8; 4]; - opaque(&x); -} - -#[allow(dead_code)] -#[derive(Copy, Clone)] -enum Init { - Loop, - Memset, -} - -// CHECK-LABEL: @byte_enum_array -#[no_mangle] -pub fn byte_enum_array() { - // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}, i8 {{.*}}, i{{[0-9]+}} 4 - // CHECK-NOT: br label %repeat_loop_header{{.*}} - let x = [Init::Memset; 4]; - opaque(&x); -} - -// CHECK-LABEL: @zeroed_integer_array -#[no_mangle] -pub fn zeroed_integer_array() { - // CHECK: call void @llvm.memset.{{.+}}(ptr {{.*}}, i8 0, i{{[0-9]+}} 16 - // CHECK-NOT: br label %repeat_loop_header{{.*}} - let x = [0u32; 4]; - opaque(&x); -} - -// CHECK-LABEL: @nonzero_integer_array -#[no_mangle] -pub fn nonzero_integer_array() { - // CHECK: br label %repeat_loop_header{{.*}} - // CHECK-NOT: call void @llvm.memset.p0 - let x = [0x1a_2b_3c_4d_u32; 4]; - opaque(&x); -} - -const N: usize = 100; - -// CHECK-LABEL: @u16_init_one_bytes -#[no_mangle] -pub fn u16_init_one_bytes() -> [u16; N] { - // CHECK-NOT: select - // CHECK-NOT: br - // CHECK-NOT: switch - // CHECK-NOT: icmp - // CHECK: call void @llvm.memset.p0 - [const { u16::from_be_bytes([1, 1]) }; N] -} - -// FIXME: undef bytes can just be initialized with the same value as the -// defined bytes, if the defines bytes are all the same. -// CHECK-LABEL: @option_none_init -#[no_mangle] -pub fn option_none_init() -> [Option; N] { - // CHECK-NOT: select - // CHECK: br label %repeat_loop_header{{.*}} - // CHECK-NOT: switch - // CHECK: icmp - // CHECK-NOT: call void @llvm.memset.p0 - [None; N] -} - -use std::mem::MaybeUninit; - -// FIXME: This could be optimized into a memset. -// Regression test for . -#[no_mangle] -pub fn half_uninit() -> [(u128, MaybeUninit); N] { - // CHECK-NOT: select - // CHECK: br label %repeat_loop_header{{.*}} - // CHECK-NOT: switch - // CHECK: icmp - // CHECK-NOT: call void @llvm.memset.p0 - [const { (0, MaybeUninit::uninit()) }; N] -} - -// Use an opaque function to prevent rustc from removing useless drops. -#[inline(never)] -pub fn opaque(_: impl Sized) {} diff --git a/tests/codegen/slice-is-ascii.rs b/tests/codegen/slice-is-ascii.rs deleted file mode 100644 index 67537c871a0..00000000000 --- a/tests/codegen/slice-is-ascii.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ only-x86_64 -//@ compile-flags: -C opt-level=3 -C target-cpu=x86-64 -#![crate_type = "lib"] - -/// Check that the fast-path of `is_ascii` uses a `pmovmskb` instruction. -/// Platforms lacking an equivalent instruction use other techniques for -/// optimizing `is_ascii`. -// CHECK-LABEL: @is_ascii_autovectorized -#[no_mangle] -pub fn is_ascii_autovectorized(s: &[u8]) -> bool { - // CHECK: load <32 x i8> - // CHECK-NEXT: icmp slt <32 x i8> - // CHECK-NEXT: bitcast <32 x i1> - // CHECK-NEXT: icmp eq i32 - s.is_ascii() -} diff --git a/tests/codegen/slice-iter-fold.rs b/tests/codegen/slice-iter-fold.rs deleted file mode 100644 index 55ab34661c3..00000000000 --- a/tests/codegen/slice-iter-fold.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -// CHECK-LABEL: @slice_fold_to_last -#[no_mangle] -pub fn slice_fold_to_last(slice: &[i32]) -> Option<&i32> { - // CHECK-NOT: loop - // CHECK-NOT: br - // CHECK-NOT: call - // CHECK: ret - slice.iter().fold(None, |_, i| Some(i)) -} diff --git a/tests/codegen/slice-iter-len-eq-zero.rs b/tests/codegen/slice-iter-len-eq-zero.rs deleted file mode 100644 index 6998d98e498..00000000000 --- a/tests/codegen/slice-iter-len-eq-zero.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ needs-deterministic-layouts (opposite scalar pair orders breaks it) -#![crate_type = "lib"] - -type Demo = [u8; 3]; - -// CHECK-LABEL: @slice_iter_len_eq_zero -#[no_mangle] -pub fn slice_iter_len_eq_zero(y: std::slice::Iter<'_, Demo>) -> bool { - // CHECK-NOT: sub - // CHECK: %[[RET:.+]] = icmp eq ptr {{%y.0, %y.1|%y.1, %y.0}} - // CHECK: ret i1 %[[RET]] - y.len() == 0 -} - -// CHECK-LABEL: @slice_iter_len_eq_zero_ref -#[no_mangle] -pub fn slice_iter_len_eq_zero_ref(y: &mut std::slice::Iter<'_, Demo>) -> bool { - // CHECK-NOT: sub - // CHECK: %[[A:.+]] = load ptr - // CHECK-SAME: !nonnull - // CHECK: %[[B:.+]] = load ptr - // CHECK-SAME: !nonnull - // CHECK: %[[RET:.+]] = icmp eq ptr %[[A]], %[[B]] - // CHECK: ret i1 %[[RET]] - y.len() == 0 -} - -struct MyZST; - -// CHECK-LABEL: @slice_zst_iter_len_eq_zero -#[no_mangle] -pub fn slice_zst_iter_len_eq_zero(y: std::slice::Iter<'_, MyZST>) -> bool { - // CHECK: %[[RET:.+]] = icmp eq ptr %y.1, null - // CHECK: ret i1 %[[RET]] - y.len() == 0 -} - -// CHECK-LABEL: @slice_zst_iter_len_eq_zero_ref -#[no_mangle] -pub fn slice_zst_iter_len_eq_zero_ref(y: &mut std::slice::Iter<'_, MyZST>) -> bool { - // CHECK: %[[LEN:.+]] = load ptr - // CHECK-NOT: !nonnull - // CHECK: %[[RET:.+]] = icmp eq ptr %[[LEN]], null - // CHECK: ret i1 %[[RET]] - y.len() == 0 -} - -// CHECK-LABEL: @array_into_iter_len_eq_zero -#[no_mangle] -pub fn array_into_iter_len_eq_zero(y: std::array::IntoIter) -> bool { - // This should be able to just check that the indexes are equal, and not - // need any subtractions or comparisons to handle `start > end`. - - // CHECK-NOT: icmp - // CHECK-NOT: sub - // CHECK: %_0 = icmp eq {{i16|i32|i64}} - // CHECK: ret i1 %_0 - y.len() == 0 -} diff --git a/tests/codegen/slice-iter-nonnull.rs b/tests/codegen/slice-iter-nonnull.rs deleted file mode 100644 index 87907e7ad0a..00000000000 --- a/tests/codegen/slice-iter-nonnull.rs +++ /dev/null @@ -1,115 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ needs-deterministic-layouts -#![crate_type = "lib"] -#![feature(exact_size_is_empty)] - -// The slice iterator used to `assume` that the `start` pointer was non-null. -// That ought to be unneeded, though, since the type is `NonNull`, so this test -// confirms that the appropriate metadata is included to denote that. - -// It also used to `assume` the `end` pointer was non-null, but that's no longer -// needed as the code changed to read it as a `NonNull`, and thus gets the -// appropriate `!nonnull` annotations naturally. - -// CHECK-LABEL: @slice_iter_next( -#[no_mangle] -pub fn slice_iter_next<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'a u32> { - // CHECK: %[[START:.+]] = load ptr, ptr %it, - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - // CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}} - // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]] - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - // CHECK: icmp eq ptr %[[START]], %[[END]] - - // CHECK: store ptr{{.+}}, ptr %it, - - it.next() -} - -// CHECK-LABEL: @slice_iter_next_back( -#[no_mangle] -pub fn slice_iter_next_back<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'a u32> { - // CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}} - // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]] - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - // CHECK: %[[START:.+]] = load ptr, ptr %it, - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - // CHECK: icmp eq ptr %[[START]], %[[END]] - - // CHECK: store ptr{{.+}}, ptr %[[ENDP]], - - it.next_back() -} - -// The slice iterator `new` methods used to `assume` that the pointer is non-null, -// but passing slices already requires that, to the extent that LLVM actually -// removed the `call @llvm.assume` anyway. These tests just demonstrate that the -// attribute is there, and confirms adding the assume back doesn't do anything. - -// CHECK-LABEL: @slice_iter_new -// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef %slice.1) -#[no_mangle] -pub fn slice_iter_new(slice: &[u32]) -> std::slice::Iter<'_, u32> { - // CHECK-NOT: slice - // CHECK: %[[END:.+]] = getelementptr inbounds{{( nuw)?}} i32{{.+}} %slice.0{{.+}} %slice.1 - // CHECK-NOT: slice - // CHECK: insertvalue {{.+}} ptr %slice.0, 0 - // CHECK-NOT: slice - // CHECK: insertvalue {{.+}} ptr %[[END]], 1 - // CHECK-NOT: slice - // CHECK: } - slice.iter() -} - -// CHECK-LABEL: @slice_iter_mut_new -// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef %slice.1) -#[no_mangle] -pub fn slice_iter_mut_new(slice: &mut [u32]) -> std::slice::IterMut<'_, u32> { - // CHECK-NOT: slice - // CHECK: %[[END:.+]] = getelementptr inbounds{{( nuw)?}} i32{{.+}} %slice.0{{.+}} %slice.1 - // CHECK-NOT: slice - // CHECK: insertvalue {{.+}} ptr %slice.0, 0 - // CHECK-NOT: slice - // CHECK: insertvalue {{.+}} ptr %[[END]], 1 - // CHECK-NOT: slice - // CHECK: } - slice.iter_mut() -} - -// CHECK-LABEL: @slice_iter_is_empty -#[no_mangle] -pub fn slice_iter_is_empty(it: &std::slice::Iter<'_, u32>) -> bool { - // CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}} - // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]] - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - // CHECK: %[[START:.+]] = load ptr, ptr %it, - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - - // CHECK: %[[RET:.+]] = icmp eq ptr %[[START]], %[[END]] - // CHECK: ret i1 %[[RET]] - it.is_empty() -} - -// CHECK-LABEL: @slice_iter_len -#[no_mangle] -pub fn slice_iter_len(it: &std::slice::Iter<'_, u32>) -> usize { - // CHECK: %[[ENDP:.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %it, {{i32 4|i64 8}} - // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]] - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - // CHECK: %[[START:.+]] = load ptr, ptr %it, - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - - // CHECK: ptrtoint - // CHECK: ptrtoint - // CHECK: sub nuw - // CHECK: lshr exact - it.len() -} diff --git a/tests/codegen/slice-last-elements-optimization.rs b/tests/codegen/slice-last-elements-optimization.rs deleted file mode 100644 index b90f91d7b17..00000000000 --- a/tests/codegen/slice-last-elements-optimization.rs +++ /dev/null @@ -1,37 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-x86_64 -//@ min-llvm-version: 20 -#![crate_type = "lib"] - -// This test verifies that LLVM 20 properly optimizes the bounds check -// when accessing the last few elements of a slice with proper conditions. -// Previously, this would generate an unreachable branch to -// slice_start_index_len_fail even when the bounds check was provably safe. - -// CHECK-LABEL: @last_four_initial( -#[no_mangle] -pub fn last_four_initial(s: &[u8]) -> &[u8] { - // Previously this would generate a branch to slice_start_index_len_fail - // that is unreachable. The LLVM 20 fix should eliminate this branch. - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: unreachable - let start = if s.len() <= 4 { 0 } else { s.len() - 4 }; - &s[start..] -} - -// CHECK-LABEL: @last_four_optimized( -#[no_mangle] -pub fn last_four_optimized(s: &[u8]) -> &[u8] { - // This version was already correctly optimized before the fix in LLVM 20. - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: unreachable - if s.len() <= 4 { &s[0..] } else { &s[s.len() - 4..] } -} - -// Just to verify we're correctly checking for the right thing -// CHECK-LABEL: @test_bounds_check_happens( -#[no_mangle] -pub fn test_bounds_check_happens(s: &[u8], i: usize) -> &[u8] { - // CHECK: slice_start_index_len_fail - &s[i..] -} diff --git a/tests/codegen/slice-pointer-nonnull-unwrap.rs b/tests/codegen/slice-pointer-nonnull-unwrap.rs deleted file mode 100644 index 35e4bf2c661..00000000000 --- a/tests/codegen/slice-pointer-nonnull-unwrap.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -use std::ptr::NonNull; - -// CHECK-LABEL: @slice_ptr_len_1 -// CHECK-NEXT: {{.*}}: -// CHECK-NEXT: ret {{i(32|64)}} %ptr.1 -#[no_mangle] -pub fn slice_ptr_len_1(ptr: *const [u8]) -> usize { - let ptr = ptr.cast_mut(); - if let Some(ptr) = NonNull::new(ptr) { - ptr.len() - } else { - // We know ptr is null, so we know ptr.wrapping_byte_add(1) is not null. - NonNull::new(ptr.wrapping_byte_add(1)).unwrap().len() - } -} diff --git a/tests/codegen/slice-position-bounds-check.rs b/tests/codegen/slice-position-bounds-check.rs deleted file mode 100644 index 0d1d1d869ae..00000000000 --- a/tests/codegen/slice-position-bounds-check.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C panic=abort -#![crate_type = "lib"] - -fn search(arr: &mut [T], a: &T) -> Result { - match arr.iter().position(|x| x == a) { - Some(p) => Ok(p), - None => Err(()), - } -} - -// CHECK-LABEL: @position_no_bounds_check -#[no_mangle] -pub fn position_no_bounds_check(y: &mut [u32], x: &u32, z: &u32) -> bool { - // This contains "call assume" so we cannot just rule out all calls - // CHECK-NOT: panic_bounds_check - if let Ok(p) = search(y, x) { y[p] == *z } else { false } -} - -// just to make sure that panicking really emits "panic_bounds_check" somewhere in the IR -// CHECK-LABEL: @test_check -#[no_mangle] -pub fn test_check(y: &[i32]) -> i32 { - // CHECK: panic_bounds_check - y[12] -} diff --git a/tests/codegen/slice-ref-equality.rs b/tests/codegen/slice-ref-equality.rs deleted file mode 100644 index 2940378da3c..00000000000 --- a/tests/codegen/slice-ref-equality.rs +++ /dev/null @@ -1,90 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled -#![crate_type = "lib"] - -use std::num::NonZero; - -// #71602 reported a simple array comparison just generating a loop. -// This was originally fixed by ensuring it generates a single bcmp, -// but we now generate it as a load+icmp instead. `is_zero_slice` was -// tweaked to still test the case of comparison against a slice, -// and `is_zero_array` tests the new array-specific behaviour. -// The optimization was then extended to short slice-to-array comparisons, -// so the first test here now has a long slice to still get the bcmp. - -// CHECK-LABEL: @is_zero_slice_long -#[no_mangle] -pub fn is_zero_slice_long(data: &[u8; 456]) -> bool { - // CHECK: %[[BCMP:.+]] = tail call i32 @{{bcmp|memcmp}}({{.+}}) - // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[BCMP]], 0 - // CHECK-NEXT: ret i1 %[[EQ]] - &data[..] == [0; 456] -} - -// CHECK-LABEL: @is_zero_slice_short -#[no_mangle] -pub fn is_zero_slice_short(data: &[u8; 4]) -> bool { - // CHECK: %[[LOAD:.+]] = load i32, ptr %{{.+}}, align 1 - // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[LOAD]], 0 - // CHECK-NEXT: ret i1 %[[EQ]] - &data[..] == [0; 4] -} - -// CHECK-LABEL: @is_zero_array -#[no_mangle] -pub fn is_zero_array(data: &[u8; 4]) -> bool { - // CHECK: %[[LOAD:.+]] = load i32, ptr %{{.+}}, align 1 - // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[LOAD]], 0 - // CHECK-NEXT: ret i1 %[[EQ]] - *data == [0; 4] -} - -// The following test the extra specializations to make sure that slice -// equality for non-byte types also just emit a `bcmp`, not a loop. - -// CHECK-LABEL: @eq_slice_of_nested_u8( -// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1 -// CHECK-SAME: [[USIZE]] noundef %y.1 -#[no_mangle] -fn eq_slice_of_nested_u8(x: &[[u8; 3]], y: &[[u8; 3]]) -> bool { - // CHECK: icmp eq [[USIZE]] %x.1, %y.1 - // CHECK: %[[BYTES:.+]] = mul nuw nsw [[USIZE]] {{%x.1|%y.1}}, 3 - // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr - // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) - x == y -} - -// CHECK-LABEL: @eq_slice_of_i32( -// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1 -// CHECK-SAME: [[USIZE]] noundef %y.1 -#[no_mangle] -fn eq_slice_of_i32(x: &[i32], y: &[i32]) -> bool { - // CHECK: icmp eq [[USIZE]] %x.1, %y.1 - // CHECK: %[[BYTES:.+]] = shl nuw nsw [[USIZE]] {{%x.1|%y.1}}, 2 - // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr - // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) - x == y -} - -// CHECK-LABEL: @eq_slice_of_nonzero( -// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1 -// CHECK-SAME: [[USIZE]] noundef %y.1 -#[no_mangle] -fn eq_slice_of_nonzero(x: &[NonZero], y: &[NonZero]) -> bool { - // CHECK: icmp eq [[USIZE]] %x.1, %y.1 - // CHECK: %[[BYTES:.+]] = shl nuw nsw [[USIZE]] {{%x.1|%y.1}}, 2 - // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr - // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) - x == y -} - -// CHECK-LABEL: @eq_slice_of_option_of_nonzero( -// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1 -// CHECK-SAME: [[USIZE]] noundef %y.1 -#[no_mangle] -fn eq_slice_of_option_of_nonzero(x: &[Option>], y: &[Option>]) -> bool { - // CHECK: icmp eq [[USIZE]] %x.1, %y.1 - // CHECK: %[[BYTES:.+]] = shl nuw nsw [[USIZE]] {{%x.1|%y.1}}, 1 - // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr - // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) - x == y -} diff --git a/tests/codegen/slice-reverse.rs b/tests/codegen/slice-reverse.rs deleted file mode 100644 index e58d1c1d9d8..00000000000 --- a/tests/codegen/slice-reverse.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-x86_64 -//@ ignore-std-debug-assertions (debug assertions prevent generating shufflevector) - -#![crate_type = "lib"] - -// CHECK-LABEL: @slice_reverse_u8 -#[no_mangle] -pub fn slice_reverse_u8(slice: &mut [u8]) { - // CHECK-NOT: panic_bounds_check - // CHECK-NOT: slice_end_index_len_fail - // CHECK: shufflevector <{{[0-9]+}} x i8> - // CHECK-NOT: panic_bounds_check - // CHECK-NOT: slice_end_index_len_fail - slice.reverse(); -} - -// CHECK-LABEL: @slice_reverse_i32 -#[no_mangle] -pub fn slice_reverse_i32(slice: &mut [i32]) { - // CHECK-NOT: panic_bounds_check - // CHECK-NOT: slice_end_index_len_fail - // CHECK: shufflevector <{{[0-9]+}} x i32> - // CHECK-NOT: panic_bounds_check - // CHECK-NOT: slice_end_index_len_fail - slice.reverse(); -} diff --git a/tests/codegen/slice-split-at.rs b/tests/codegen/slice-split-at.rs deleted file mode 100644 index 07018cf9c91..00000000000 --- a/tests/codegen/slice-split-at.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -// Check that no panic is generated in `split_at` when calculating the index for -// the tail chunk using `checked_sub`. -// -// Tests written for refactored implementations of: -// `<[T]>::{split_last_chunk, split_last_chunk_mut, last_chunk, last_chunk_mut}` - -// CHECK-LABEL: @split_at_last_chunk -#[no_mangle] -pub fn split_at_last_chunk(s: &[u8], chunk_size: usize) -> Option<(&[u8], &[u8])> { - // CHECK-NOT: panic - let Some(index) = s.len().checked_sub(chunk_size) else { return None }; - Some(s.split_at(index)) -} - -// CHECK-LABEL: @split_at_mut_last_chunk -#[no_mangle] -pub fn split_at_mut_last_chunk(s: &mut [u8], chunk_size: usize) -> Option<(&mut [u8], &mut [u8])> { - // CHECK-NOT: panic - let Some(index) = s.len().checked_sub(chunk_size) else { return None }; - Some(s.split_at_mut(index)) -} diff --git a/tests/codegen/slice-windows-no-bounds-check.rs b/tests/codegen/slice-windows-no-bounds-check.rs deleted file mode 100644 index 87e89b14f06..00000000000 --- a/tests/codegen/slice-windows-no-bounds-check.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![crate_type = "lib"] - -//@ compile-flags: -Copt-level=3 - -use std::slice::Windows; - -// CHECK-LABEL: @naive_string_search -#[no_mangle] -pub fn naive_string_search(haystack: &str, needle: &str) -> Option { - if needle.is_empty() { - return Some(0); - } - // CHECK-NOT: panic - // CHECK-NOT: fail - haystack.as_bytes().windows(needle.len()).position(|sub| sub == needle.as_bytes()) -} - -// CHECK-LABEL: @next -#[no_mangle] -pub fn next<'a>(w: &mut Windows<'a, u32>) -> Option<&'a [u32]> { - // CHECK-NOT: panic - // CHECK-NOT: fail - w.next() -} - -// CHECK-LABEL: @next_back -#[no_mangle] -pub fn next_back<'a>(w: &mut Windows<'a, u32>) -> Option<&'a [u32]> { - // CHECK-NOT: panic - // CHECK-NOT: fail - w.next_back() -} diff --git a/tests/codegen/slice_as_from_ptr_range.rs b/tests/codegen/slice_as_from_ptr_range.rs deleted file mode 100644 index 2073f05c07f..00000000000 --- a/tests/codegen/slice_as_from_ptr_range.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-64bit (because we're using [ui]size) - -#![crate_type = "lib"] -#![feature(slice_from_ptr_range)] - -// This is intentionally using a non-power-of-two array length, -// as that's where the optimization differences show up - -// CHECK-LABEL: @flatten_via_ptr_range -#[no_mangle] -pub fn flatten_via_ptr_range(slice_of_arrays: &[[i32; 13]]) -> &[i32] { - // CHECK-NOT: lshr - // CHECK-NOT: udiv - // CHECK: mul nuw nsw i64 %{{.+}}, 13 - // CHECK-NOT: lshr - // CHECK-NOT: udiv - let r = slice_of_arrays.as_ptr_range(); - let r = r.start.cast()..r.end.cast(); - unsafe { core::slice::from_ptr_range(r) } -} diff --git a/tests/codegen/some-abis-do-extend-params-to-32-bits.rs b/tests/codegen/some-abis-do-extend-params-to-32-bits.rs deleted file mode 100644 index 6ca6697588f..00000000000 --- a/tests/codegen/some-abis-do-extend-params-to-32-bits.rs +++ /dev/null @@ -1,236 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 - -//@ revisions:x86_64 i686 aarch64-apple aarch64-windows aarch64-linux arm riscv - -//@[x86_64] compile-flags: --target x86_64-unknown-uefi -//@[x86_64] needs-llvm-components: x86 -//@[i686] compile-flags: --target i686-unknown-linux-musl -//@[i686] needs-llvm-components: x86 -//@[aarch64-windows] compile-flags: --target aarch64-pc-windows-msvc -//@[aarch64-windows] needs-llvm-components: aarch64 -//@[aarch64-linux] compile-flags: --target aarch64-unknown-linux-gnu -//@[aarch64-linux] needs-llvm-components: aarch64 -//@[aarch64-apple] compile-flags: --target aarch64-apple-darwin -//@[aarch64-apple] needs-llvm-components: aarch64 -//@[arm] compile-flags: --target armv7r-none-eabi -//@[arm] needs-llvm-components: arm -//@[riscv] compile-flags: --target riscv64gc-unknown-none-elf -//@[riscv] needs-llvm-components: riscv - -// See bottom of file for a corresponding C source file that is meant to yield -// equivalent declarations. -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -extern crate minicore; -use minicore::*; - -// The patterns in this file are written in the style of a table to make the -// uniformities and distinctions more apparent. -// -// ZERO/SIGN-EXTENDING TO 32 BITS NON-EXTENDING -// ============================== ======================= -// x86_64: void @c_arg_u8(i8 zeroext %_a) -// i686: void @c_arg_u8(i8 zeroext %_a) -// aarch64-apple: void @c_arg_u8(i8 zeroext %_a) -// aarch64-windows: void @c_arg_u8(i8 %_a) -// aarch64-linux: void @c_arg_u8(i8 %_a) -// arm: void @c_arg_u8(i8 zeroext %_a) -// riscv: void @c_arg_u8(i8 zeroext %_a) -#[no_mangle] -pub extern "C" fn c_arg_u8(_a: u8) {} - -// x86_64: void @c_arg_u16(i16 zeroext %_a) -// i686: void @c_arg_u16(i16 zeroext %_a) -// aarch64-apple: void @c_arg_u16(i16 zeroext %_a) -// aarch64-windows: void @c_arg_u16(i16 %_a) -// aarch64-linux: void @c_arg_u16(i16 %_a) -// arm: void @c_arg_u16(i16 zeroext %_a) -// riscv: void @c_arg_u16(i16 zeroext %_a) -#[no_mangle] -pub extern "C" fn c_arg_u16(_a: u16) {} - -// x86_64: void @c_arg_u32(i32 %_a) -// i686: void @c_arg_u32(i32 %_a) -// aarch64-apple: void @c_arg_u32(i32 %_a) -// aarch64-windows: void @c_arg_u32(i32 %_a) -// aarch64-linux: void @c_arg_u32(i32 %_a) -// arm: void @c_arg_u32(i32 %_a) -// riscv: void @c_arg_u32(i32 signext %_a) -#[no_mangle] -pub extern "C" fn c_arg_u32(_a: u32) {} - -// x86_64: void @c_arg_u64(i64 %_a) -// i686: void @c_arg_u64(i64 %_a) -// aarch64-apple: void @c_arg_u64(i64 %_a) -// aarch64-windows: void @c_arg_u64(i64 %_a) -// aarch64-linux: void @c_arg_u64(i64 %_a) -// arm: void @c_arg_u64(i64 %_a) -// riscv: void @c_arg_u64(i64 %_a) -#[no_mangle] -pub extern "C" fn c_arg_u64(_a: u64) {} - -// x86_64: void @c_arg_i8(i8 signext %_a) -// i686: void @c_arg_i8(i8 signext %_a) -// aarch64-apple: void @c_arg_i8(i8 signext %_a) -// aarch64-windows: void @c_arg_i8(i8 %_a) -// aarch64-linux: void @c_arg_i8(i8 %_a) -// arm: void @c_arg_i8(i8 signext %_a) -// riscv: void @c_arg_i8(i8 signext %_a) -#[no_mangle] -pub extern "C" fn c_arg_i8(_a: i8) {} - -// x86_64: void @c_arg_i16(i16 signext %_a) -// i686: void @c_arg_i16(i16 signext %_a) -// aarch64-apple: void @c_arg_i16(i16 signext %_a) -// aarch64-windows: void @c_arg_i16(i16 %_a) -// aarch64-linux: void @c_arg_i16(i16 %_a) -// arm: void @c_arg_i16(i16 signext %_a) -// riscv: void @c_arg_i16(i16 signext %_a) -#[no_mangle] -pub extern "C" fn c_arg_i16(_a: i16) {} - -// x86_64: void @c_arg_i32(i32 %_a) -// i686: void @c_arg_i32(i32 %_a) -// aarch64-apple: void @c_arg_i32(i32 %_a) -// aarch64-windows: void @c_arg_i32(i32 %_a) -// aarch64-linux: void @c_arg_i32(i32 %_a) -// arm: void @c_arg_i32(i32 %_a) -// riscv: void @c_arg_i32(i32 signext %_a) -#[no_mangle] -pub extern "C" fn c_arg_i32(_a: i32) {} - -// x86_64: void @c_arg_i64(i64 %_a) -// i686: void @c_arg_i64(i64 %_a) -// aarch64-apple: void @c_arg_i64(i64 %_a) -// aarch64-windows: void @c_arg_i64(i64 %_a) -// aarch64-linux: void @c_arg_i64(i64 %_a) -// arm: void @c_arg_i64(i64 %_a) -// riscv: void @c_arg_i64(i64 %_a) -#[no_mangle] -pub extern "C" fn c_arg_i64(_a: i64) {} - -// x86_64: zeroext i8 @c_ret_u8() -// i686: zeroext i8 @c_ret_u8() -// aarch64-apple: zeroext i8 @c_ret_u8() -// aarch64-windows: i8 @c_ret_u8() -// aarch64-linux: i8 @c_ret_u8() -// arm: zeroext i8 @c_ret_u8() -// riscv: zeroext i8 @c_ret_u8() -#[no_mangle] -pub extern "C" fn c_ret_u8() -> u8 { - 0 -} - -// x86_64: zeroext i16 @c_ret_u16() -// i686: zeroext i16 @c_ret_u16() -// aarch64-apple: zeroext i16 @c_ret_u16() -// aarch64-windows: i16 @c_ret_u16() -// aarch64-linux: i16 @c_ret_u16() -// arm: zeroext i16 @c_ret_u16() -// riscv: zeroext i16 @c_ret_u16() -#[no_mangle] -pub extern "C" fn c_ret_u16() -> u16 { - 0 -} - -// x86_64: i32 @c_ret_u32() -// i686: i32 @c_ret_u32() -// aarch64-apple: i32 @c_ret_u32() -// aarch64-windows: i32 @c_ret_u32() -// aarch64-linux: i32 @c_ret_u32() -// arm: i32 @c_ret_u32() -// riscv: signext i32 @c_ret_u32() -#[no_mangle] -pub extern "C" fn c_ret_u32() -> u32 { - 0 -} - -// x86_64: i64 @c_ret_u64() -// i686: i64 @c_ret_u64() -// aarch64-apple: i64 @c_ret_u64() -// aarch64-windows: i64 @c_ret_u64() -// aarch64-linux: i64 @c_ret_u64() -// arm: i64 @c_ret_u64() -// riscv: i64 @c_ret_u64() -#[no_mangle] -pub extern "C" fn c_ret_u64() -> u64 { - 0 -} - -// x86_64: signext i8 @c_ret_i8() -// i686: signext i8 @c_ret_i8() -// aarch64-apple: signext i8 @c_ret_i8() -// aarch64-windows: i8 @c_ret_i8() -// aarch64-linux: i8 @c_ret_i8() -// arm: signext i8 @c_ret_i8() -// riscv: signext i8 @c_ret_i8() -#[no_mangle] -pub extern "C" fn c_ret_i8() -> i8 { - 0 -} - -// x86_64: signext i16 @c_ret_i16() -// i686: signext i16 @c_ret_i16() -// aarch64-apple: signext i16 @c_ret_i16() -// aarch64-windows: i16 @c_ret_i16() -// aarch64-linux: i16 @c_ret_i16() -// arm: signext i16 @c_ret_i16() -// riscv: signext i16 @c_ret_i16() -#[no_mangle] -pub extern "C" fn c_ret_i16() -> i16 { - 0 -} - -// x86_64: i32 @c_ret_i32() -// i686: i32 @c_ret_i32() -// aarch64-apple: i32 @c_ret_i32() -// aarch64-windows: i32 @c_ret_i32() -// aarch64-linux: i32 @c_ret_i32() -// arm: i32 @c_ret_i32() -// riscv: signext i32 @c_ret_i32() -#[no_mangle] -pub extern "C" fn c_ret_i32() -> i32 { - 0 -} - -// x86_64: i64 @c_ret_i64() -// i686: i64 @c_ret_i64() -// aarch64-apple: i64 @c_ret_i64() -// aarch64-windows: i64 @c_ret_i64() -// aarch64-linux: i64 @c_ret_i64() -// arm: i64 @c_ret_i64() -// riscv: i64 @c_ret_i64() -#[no_mangle] -pub extern "C" fn c_ret_i64() -> i64 { - 0 -} - -const C_SOURCE_FILE: &'static str = r##" -#include -#include -#include - -void c_arg_u8(uint8_t _a) { } -void c_arg_u16(uint16_t _a) { } -void c_arg_u32(uint32_t _a) { } -void c_arg_u64(uint64_t _a) { } - -void c_arg_i8(int8_t _a) { } -void c_arg_i16(int16_t _a) { } -void c_arg_i32(int32_t _a) { } -void c_arg_i64(int64_t _a) { } - -uint8_t c_ret_u8() { return 0; } -uint16_t c_ret_u16() { return 0; } -uint32_t c_ret_u32() { return 0; } -uint64_t c_ret_u64() { return 0; } - -int8_t c_ret_i8() { return 0; } -int16_t c_ret_i16() { return 0; } -int32_t c_ret_i32() { return 0; } -int64_t c_ret_i64() { return 0; } -"##; diff --git a/tests/codegen/some-global-nonnull.rs b/tests/codegen/some-global-nonnull.rs deleted file mode 100644 index bb4d12e1c76..00000000000 --- a/tests/codegen/some-global-nonnull.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @test -// CHECK-NEXT: start: -// CHECK-NEXT: tail call void @ext_fn0() -#[no_mangle] -pub fn test() { - test_inner(Some(inner0)); -} - -fn test_inner(f_maybe: Option) { - if let Some(f) = f_maybe { - f(); - } -} - -fn inner0() { - unsafe { ext_fn0() }; -} - -extern "C" { - fn ext_fn0(); -} diff --git a/tests/codegen/sparc-struct-abi.rs b/tests/codegen/sparc-struct-abi.rs deleted file mode 100644 index 32d2c5bb0ef..00000000000 --- a/tests/codegen/sparc-struct-abi.rs +++ /dev/null @@ -1,97 +0,0 @@ -// Checks that we correctly codegen extern "C" functions returning structs. -// See issues #52638 and #86163. - -//@ add-core-stubs -//@ compile-flags: -Copt-level=3 --target=sparc64-unknown-linux-gnu --crate-type=rlib -//@ needs-llvm-components: sparc -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[repr(C)] -pub struct Bool { - b: bool, -} - -// CHECK: define{{.*}} i64 @structbool() -// CHECK-NEXT: start: -// CHECK-NEXT: ret i64 72057594037927936 -#[no_mangle] -pub extern "C" fn structbool() -> Bool { - Bool { b: true } -} - -#[repr(C)] -pub struct BoolFloat { - b: bool, - f: f32, -} - -// CHECK: define inreg { i32, float } @structboolfloat() -// CHECK-NEXT: start: -// CHECK-NEXT: ret { i32, float } { i32 16777216, float 0x40091EB860000000 } -#[no_mangle] -pub extern "C" fn structboolfloat() -> BoolFloat { - BoolFloat { b: true, f: 3.14 } -} - -// CHECK: define void @structboolfloat_input({ i32, float } inreg %0) -// CHECK-NEXT: start: -#[no_mangle] -pub extern "C" fn structboolfloat_input(a: BoolFloat) {} - -#[repr(C)] -pub struct ShortDouble { - s: i16, - d: f64, -} - -// CHECK: define { i64, double } @structshortdouble() -// CHECK-NEXT: start: -// CHECK-NEXT: ret { i64, double } { i64 34621422135410688, double 3.140000e+00 } -#[no_mangle] -pub extern "C" fn structshortdouble() -> ShortDouble { - ShortDouble { s: 123, d: 3.14 } -} - -// CHECK: define void @structshortdouble_input({ i64, double } %0) -// CHECK-NEXT: start: -#[no_mangle] -pub extern "C" fn structshortdouble_input(a: ShortDouble) {} - -#[repr(C)] -pub struct FloatLongFloat { - f: f32, - i: i64, - g: f32, -} - -// CHECK: define inreg { float, i32, i64, float, i32 } @structfloatlongfloat() -// CHECK-NEXT: start: -// CHECK-NEXT: ret { float, i32, i64, float, i32 } { float 0x3FB99999A0000000, i32 undef, i64 123, float 0x40091EB860000000, i32 undef } -#[no_mangle] -pub extern "C" fn structfloatlongfloat() -> FloatLongFloat { - FloatLongFloat { f: 0.1, i: 123, g: 3.14 } -} - -#[repr(C)] -pub struct FloatFloat { - f: f32, - g: f32, -} - -#[repr(C)] -pub struct NestedStructs { - a: FloatFloat, - b: FloatFloat, -} - -// CHECK: define inreg { float, float, float, float } @structnestestructs() -// CHECK-NEXT: start: -// CHECK-NEXT: ret { float, float, float, float } { float 0x3FB99999A0000000, float 0x3FF19999A0000000, float 0x40019999A0000000, float 0x400A666660000000 } -#[no_mangle] -pub extern "C" fn structnestestructs() -> NestedStructs { - NestedStructs { a: FloatFloat { f: 0.1, g: 1.1 }, b: FloatFloat { f: 2.2, g: 3.3 } } -} diff --git a/tests/codegen/split-lto-unit.rs b/tests/codegen/split-lto-unit.rs deleted file mode 100644 index 7858a0e7b79..00000000000 --- a/tests/codegen/split-lto-unit.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Verifies that "EnableSplitLTOUnit" module flag is added. -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsplit-lto-unit - -#![crate_type = "lib"] - -pub fn foo() {} - -// CHECK: !{{[0-9]+}} = !{i32 4, !"EnableSplitLTOUnit", i32 1} diff --git a/tests/codegen/src-hash-algorithm/src-hash-algorithm-md5.rs b/tests/codegen/src-hash-algorithm/src-hash-algorithm-md5.rs deleted file mode 100644 index 7aec8d545dc..00000000000 --- a/tests/codegen/src-hash-algorithm/src-hash-algorithm-md5.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ compile-flags: -g -Z src-hash-algorithm=md5 -Copt-level=0 - -#![crate_type = "lib"] - -pub fn test() {} -// CHECK: checksumkind: CSK_MD5 diff --git a/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha1.rs b/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha1.rs deleted file mode 100644 index 5389c32f938..00000000000 --- a/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha1.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ compile-flags: -g -Z src-hash-algorithm=sha1 -Copt-level=0 - -#![crate_type = "lib"] - -pub fn test() {} -// CHECK: checksumkind: CSK_SHA1 diff --git a/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs b/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs deleted file mode 100644 index 520890c47f1..00000000000 --- a/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ compile-flags: -g -Z src-hash-algorithm=sha256 -Copt-level=0 - -#![crate_type = "lib"] - -pub fn test() {} -// CHECK: checksumkind: CSK_SHA256 diff --git a/tests/codegen/sroa-fragment-debuginfo.rs b/tests/codegen/sroa-fragment-debuginfo.rs deleted file mode 100644 index 0413cf96894..00000000000 --- a/tests/codegen/sroa-fragment-debuginfo.rs +++ /dev/null @@ -1,46 +0,0 @@ -//@ compile-flags: -g -Zmir-opt-level=0 -Zmir-enable-passes=+ScalarReplacementOfAggregates -//@ compile-flags: -Cno-prepopulate-passes -// -// Tested offsets are only correct for x86_64. -//@ only-x86_64 - -#![crate_type = "lib"] - -pub struct ExtraSlice<'input> { - slice: &'input [u8], - extra: u32, -} - -#[no_mangle] -pub fn extra(s: &[u8]) { - // CHECK: void @extra( - // CHECK: %slice.dbg.spill1 = alloca [4 x i8], - // CHECK: %slice.dbg.spill = alloca [16 x i8], - // CHECK: %s.dbg.spill = alloca [16 x i8], - // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %s.dbg.spill, {{(metadata )?}}![[S_EXTRA:.*]], {{(metadata )?}}!DIExpression() - // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %slice.dbg.spill, {{(metadata )?}}![[SLICE_EXTRA:.*]], {{(metadata )?}}!DIExpression(DW_OP_LLVM_fragment, 0, 128) - // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %slice.dbg.spill1, {{(metadata )?}}![[SLICE_EXTRA]], {{(metadata )?}}!DIExpression(DW_OP_LLVM_fragment, 128, 32) - let slice = ExtraSlice { slice: s, extra: s.len() as u32 }; -} - -struct Zst; - -pub struct ZstSlice<'input> { - slice: &'input [u8], - extra: Zst, -} - -#[no_mangle] -pub fn zst(s: &[u8]) { - // The field `extra` is a ZST. The fragment for the field `slice` encompasses the whole - // variable, so is not a fragment. In that case, the variable must have no fragment. - - // CHECK: void @zst( - // CHECK-NOT: dbg{{.}}declare({{(metadata )?}}ptr %slice.dbg.spill, {{(metadata )?}}!{}, {{(metadata )?}}!DIExpression(DW_OP_LLVM_fragment, - // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %{{.*}}, {{(metadata )?}}![[SLICE_ZST:.*]], {{(metadata )?}}!DIExpression() - // CHECK-NOT: dbg{{.}}declare({{(metadata )?}}ptr %{{.*}}, {{(metadata )?}}![[SLICE_ZST]], - let slice = ZstSlice { slice: s, extra: Zst }; -} - -// CHECK: ![[S_EXTRA]] = !DILocalVariable(name: "s", -// CHECK: ![[SLICE_EXTRA]] = !DILocalVariable(name: "slice", diff --git a/tests/codegen/sse42-implies-crc32.rs b/tests/codegen/sse42-implies-crc32.rs deleted file mode 100644 index 8a9c496a3a5..00000000000 --- a/tests/codegen/sse42-implies-crc32.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ only-x86_64 -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "sse4.2")] -#[no_mangle] -pub unsafe fn crc32sse(v: u8) -> u32 { - use std::arch::x86_64::*; - let out = !0u32; - _mm_crc32_u8(out, v) -} - -// CHECK: attributes #0 {{.*"target-features"=".*\+sse4.2,\+crc32.*"}} diff --git a/tests/codegen/stack-probes-inline.rs b/tests/codegen/stack-probes-inline.rs deleted file mode 100644 index 746272b0994..00000000000 --- a/tests/codegen/stack-probes-inline.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Check the "probe-stack" attribute for targets with `StackProbeType::Inline`, -// or `StackProbeType::InlineOrCall` when running on newer LLVM. - -//@ add-core-stubs -//@ compile-flags: -C no-prepopulate-passes -//@ revisions: aarch64 powerpc powerpc64 powerpc64le s390x i686 x86_64 -//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu -//@[aarch64] needs-llvm-components: aarch64 -//@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu -//@[powerpc] needs-llvm-components: powerpc -//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu -//@[powerpc64] needs-llvm-components: powerpc -//@[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu -//@[powerpc64le] needs-llvm-components: powerpc -//@[s390x] compile-flags: --target s390x-unknown-linux-gnu -//@[s390x] needs-llvm-components: systemz -//@[i686] compile-flags: --target i686-unknown-linux-gnu -//@[i686] needs-llvm-components: x86 -//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu -//@[x86_64] needs-llvm-components: x86 - -#![crate_type = "rlib"] -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[no_mangle] -pub fn foo() { - // CHECK: @foo() unnamed_addr #0 - // CHECK: attributes #0 = { {{.*}}"probe-stack"="inline-asm"{{.*}} } -} diff --git a/tests/codegen/stack-protector.rs b/tests/codegen/stack-protector.rs deleted file mode 100644 index 8ab25b470cd..00000000000 --- a/tests/codegen/stack-protector.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@ revisions: all strong basic none -//@ ignore-nvptx64 stack protector not supported -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic - -#![crate_type = "lib"] - -#[no_mangle] -pub fn foo() { - // CHECK: @foo() unnamed_addr #0 - - // all-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } - // all-NOT: attributes #0 = { {{.*}}ssp {{.*}} } - // all: attributes #0 = { {{.*}}sspreq {{.*}} } - // all-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } - // all-NOT: attributes #0 = { {{.*}}ssp {{.*}} } - - // strong-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } - // strong-NOT: attributes #0 = { {{.*}}ssp {{.*}} } - // strong: attributes #0 = { {{.*}}sspstrong {{.*}} } - // strong-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } - // strong-NOT: attributes #0 = { {{.*}}ssp {{.*}} } - - // basic-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } - // basic-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } - // basic: attributes #0 = { {{.*}}ssp {{.*}} } - // basic-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } - // basic-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } - - // none-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } - // none-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } - // none-NOT: attributes #0 = { {{.*}}ssp {{.*}} } -} diff --git a/tests/codegen/static-relocation-model-msvc.rs b/tests/codegen/static-relocation-model-msvc.rs deleted file mode 100644 index 4d30e6ec505..00000000000 --- a/tests/codegen/static-relocation-model-msvc.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Verify linkage of external symbols in the static relocation model on MSVC. -// -//@ compile-flags: -Copt-level=3 -C relocation-model=static -//@ aux-build: extern_decl.rs -//@ only-x86_64-pc-windows-msvc - -#![crate_type = "rlib"] - -extern crate extern_decl; - -// The `extern_decl` definitions are imported from a statically linked rust -// crate, thus they are expected to be marked `dso_local` without `dllimport`. -// -// The `access_extern()` symbol is from this compilation unit, thus we expect -// it to be marked `dso_local` as well, given the static relocation model. -// -// CHECK: @extern_static = external dso_local local_unnamed_addr global i8 -// CHECK: define dso_local noundef i8 @access_extern() {{.*}} -// CHECK: declare dso_local noundef i8 @extern_fn() {{.*}} - -#[no_mangle] -pub fn access_extern() -> u8 { - unsafe { extern_decl::extern_fn() + extern_decl::extern_static } -} diff --git a/tests/codegen/staticlib-external-inline-fns.rs b/tests/codegen/staticlib-external-inline-fns.rs deleted file mode 100644 index 23316a2d9a5..00000000000 --- a/tests/codegen/staticlib-external-inline-fns.rs +++ /dev/null @@ -1,43 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -#![crate_type = "staticlib"] - -// CHECK: define{{.*}}void @a() -#[no_mangle] -#[inline] -pub extern "C" fn a() {} - -// CHECK: define{{.*}}void @b() -#[export_name = "b"] -#[inline] -pub extern "C" fn b() {} - -// CHECK: define{{.*}}void @c() -#[no_mangle] -#[inline] -extern "C" fn c() {} - -// CHECK: define{{.*}}void @d() -#[export_name = "d"] -#[inline] -extern "C" fn d() {} - -// CHECK: define{{.*}}void @e() -#[no_mangle] -#[inline(always)] -pub extern "C" fn e() {} - -// CHECK: define{{.*}}void @f() -#[export_name = "f"] -#[inline(always)] -pub extern "C" fn f() {} - -// CHECK: define{{.*}}void @g() -#[no_mangle] -#[inline(always)] -extern "C" fn g() {} - -// CHECK: define{{.*}}void @h() -#[export_name = "h"] -#[inline(always)] -extern "C" fn h() {} diff --git a/tests/codegen/step_by-overflow-checks.rs b/tests/codegen/step_by-overflow-checks.rs deleted file mode 100644 index 53800e9f879..00000000000 --- a/tests/codegen/step_by-overflow-checks.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -use std::iter::StepBy; -use std::slice::Iter; - -// The constructor for `StepBy` ensures we can never end up needing to do zero -// checks on denominators, so check that the code isn't emitting panic paths. - -// CHECK-LABEL: @step_by_len_std -#[no_mangle] -pub fn step_by_len_std(x: &StepBy>) -> usize { - // CHECK-NOT: div_by_zero - // CHECK: udiv - // CHECK-NOT: div_by_zero - x.len() -} - -// CHECK-LABEL: @step_by_len_naive -#[no_mangle] -pub fn step_by_len_naive(x: Iter, step_minus_one: usize) -> usize { - // CHECK: udiv - // CHECK: call{{.+}}div_by_zero - x.len() / (step_minus_one + 1) -} diff --git a/tests/codegen/stores.rs b/tests/codegen/stores.rs deleted file mode 100644 index aa3090db6d3..00000000000 --- a/tests/codegen/stores.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -// - -#![crate_type = "lib"] - -pub struct Bytes { - a: u8, - b: u8, - c: u8, - d: u8, -} - -// CHECK-LABEL: small_array_alignment -// The array is stored as i32, but its alignment is lower, go with 1 byte to avoid target -// dependent alignment -#[no_mangle] -pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) { - // CHECK: [[TMP:%.+]] = alloca [4 x i8], align 4 - // CHECK: %y = alloca [4 x i8], align 1 - // CHECK: store i32 %0, ptr [[TMP]] - // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 {{.+}}, ptr align 4 {{.+}}, i{{[0-9]+}} 4, i1 false) - *x = y; -} - -// CHECK-LABEL: small_struct_alignment -// The struct is stored as i32, but its alignment is lower, go with 1 byte to avoid target -// dependent alignment -#[no_mangle] -pub fn small_struct_alignment(x: &mut Bytes, y: Bytes) { - // CHECK: [[TMP:%.+]] = alloca [4 x i8], align 4 - // CHECK: %y = alloca [4 x i8], align 1 - // CHECK: store i32 %0, ptr [[TMP]] - // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 {{.+}}, ptr align 4 {{.+}}, i{{[0-9]+}} 4, i1 false) - *x = y; -} diff --git a/tests/codegen/string-push.rs b/tests/codegen/string-push.rs deleted file mode 100644 index cf5f6bb1aa3..00000000000 --- a/tests/codegen/string-push.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Check that `String::push` is optimized enough not to call `memcpy`. - -//@ compile-flags: -O -#![crate_type = "lib"] - -// CHECK-LABEL: @string_push_does_not_call_memcpy -#[no_mangle] -pub fn string_push_does_not_call_memcpy(s: &mut String, ch: char) { - // CHECK-NOT: call void @llvm.memcpy - s.push(ch); -} diff --git a/tests/codegen/swap-large-types.rs b/tests/codegen/swap-large-types.rs deleted file mode 100644 index 08c486affd9..00000000000 --- a/tests/codegen/swap-large-types.rs +++ /dev/null @@ -1,116 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-x86_64 - -#![crate_type = "lib"] - -use std::mem::swap; -use std::ptr::{copy_nonoverlapping, read, write}; - -type KeccakBuffer = [[u64; 5]; 5]; - -// A basic read+copy+write swap implementation ends up copying one of the values -// to stack for large types, which is completely unnecessary as the lack of -// overlap means we can just do whatever fits in registers at a time. - -// The tests here (after the first one showing that the problem still exists) -// are less about testing *exactly* what the codegen is, and more about testing -// 1) That things are swapped directly from one argument to the other, -// never going through stack along the way, and -// 2) That we're doing the swapping for big things using large vector types, -// rather then `i64` or `<8 x i8>` (or, even worse, `i8`) at a time. -// -// (There are separate tests for intrinsics::typed_swap_nonoverlapping that -// check that it, as an intrinsic, are emitting exactly what it should.) - -// CHECK-LABEL: @swap_basic -#[no_mangle] -pub fn swap_basic(x: &mut KeccakBuffer, y: &mut KeccakBuffer) { - // CHECK: alloca [200 x i8] - - // SAFETY: exclusive references are always valid to read/write, - // are non-overlapping, and nothing here panics so it's drop-safe. - unsafe { - let z = read(x); - copy_nonoverlapping(y, x, 1); - write(y, z); - } -} - -// CHECK-LABEL: @swap_std -#[no_mangle] -pub fn swap_std(x: &mut KeccakBuffer, y: &mut KeccakBuffer) { - // CHECK-NOT: alloca - // CHECK: load <{{2|4}} x i64> - // CHECK: store <{{2|4}} x i64> - swap(x, y) -} - -// CHECK-LABEL: @swap_slice -#[no_mangle] -pub fn swap_slice(x: &mut [KeccakBuffer], y: &mut [KeccakBuffer]) { - // CHECK-NOT: alloca - // CHECK: load <{{2|4}} x i64> - // CHECK: store <{{2|4}} x i64> - if x.len() == y.len() { - x.swap_with_slice(y); - } -} - -type OneKilobyteBuffer = [u8; 1024]; - -// CHECK-LABEL: @swap_1kb_slices -#[no_mangle] -pub fn swap_1kb_slices(x: &mut [OneKilobyteBuffer], y: &mut [OneKilobyteBuffer]) { - // CHECK-NOT: alloca - - // CHECK-NOT: load i32 - // CHECK-NOT: store i32 - // CHECK-NOT: load i16 - // CHECK-NOT: store i16 - // CHECK-NOT: load i8 - // CHECK-NOT: store i8 - - // CHECK: load <{{2|4}} x i64>{{.+}}align 1, - // CHECK: store <{{2|4}} x i64>{{.+}}align 1, - - // CHECK-NOT: load i32 - // CHECK-NOT: store i32 - // CHECK-NOT: load i16 - // CHECK-NOT: store i16 - // CHECK-NOT: load i8 - // CHECK-NOT: store i8 - - if x.len() == y.len() { - x.swap_with_slice(y); - } -} - -#[repr(align(64))] -pub struct BigButHighlyAligned([u8; 64 * 3]); - -// CHECK-LABEL: @swap_big_aligned -#[no_mangle] -pub fn swap_big_aligned(x: &mut BigButHighlyAligned, y: &mut BigButHighlyAligned) { - // CHECK-NOT: call void @llvm.memcpy - // CHECK-NOT: load i32 - // CHECK-NOT: store i32 - // CHECK-NOT: load i16 - // CHECK-NOT: store i16 - // CHECK-NOT: load i8 - // CHECK-NOT: store i8 - - // CHECK-COUNT-2: load <{{2|4}} x i64>{{.+}}align 64, - // CHECK-COUNT-2: store <{{2|4}} x i64>{{.+}}align 64, - - // CHECK-COUNT-2: load <{{2|4}} x i64>{{.+}}align 32, - // CHECK-COUNT-2: store <{{2|4}} x i64>{{.+}}align 32, - - // CHECK-NOT: load i32 - // CHECK-NOT: store i32 - // CHECK-NOT: load i16 - // CHECK-NOT: store i16 - // CHECK-NOT: load i8 - // CHECK-NOT: store i8 - // CHECK-NOT: call void @llvm.memcpy - swap(x, y) -} diff --git a/tests/codegen/swap-small-types.rs b/tests/codegen/swap-small-types.rs deleted file mode 100644 index 7aa613ae9c2..00000000000 --- a/tests/codegen/swap-small-types.rs +++ /dev/null @@ -1,182 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled -//@ only-x86_64 -//@ min-llvm-version: 20 -//@ ignore-std-debug-assertions (`ptr::swap_nonoverlapping` has one which blocks some optimizations) - -#![crate_type = "lib"] - -use std::mem::swap; - -type RGB48 = [u16; 3]; - -// CHECK-LABEL: @swap_rgb48_manually( -#[no_mangle] -pub fn swap_rgb48_manually(x: &mut RGB48, y: &mut RGB48) { - // FIXME: See #115212 for why this has an alloca again - - // CHECK: alloca [6 x i8], align 2 - // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 6, i1 false) - // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 6, i1 false) - // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 6, i1 false) - - let temp = *x; - *x = *y; - *y = temp; -} - -// CHECK-LABEL: @swap_rgb48 -#[no_mangle] -pub fn swap_rgb48(x: &mut RGB48, y: &mut RGB48) { - // CHECK-NOT: alloca - - // Swapping `i48` might be cleaner in LLVM-IR here, but `i32`+`i16` isn't bad, - // and is closer to the assembly it generates anyway. - - // CHECK-NOT: load{{ }} - // CHECK: load i32{{.+}}align 2 - // CHECK-NEXT: load i32{{.+}}align 2 - // CHECK-NEXT: store i32{{.+}}align 2 - // CHECK-NEXT: store i32{{.+}}align 2 - // CHECK: load i16{{.+}}align 2 - // CHECK-NEXT: load i16{{.+}}align 2 - // CHECK-NEXT: store i16{{.+}}align 2 - // CHECK-NEXT: store i16{{.+}}align 2 - // CHECK-NOT: store{{ }} - swap(x, y) -} - -type RGBA64 = [u16; 4]; - -// CHECK-LABEL: @swap_rgba64 -#[no_mangle] -pub fn swap_rgba64(x: &mut RGBA64, y: &mut RGBA64) { - // CHECK-NOT: alloca - // CHECK-DAG: %[[XVAL:.+]] = load i64, ptr %x, align 2 - // CHECK-DAG: %[[YVAL:.+]] = load i64, ptr %y, align 2 - // CHECK-DAG: store i64 %[[YVAL]], ptr %x, align 2 - // CHECK-DAG: store i64 %[[XVAL]], ptr %y, align 2 - swap(x, y) -} - -// CHECK-LABEL: @swap_vecs -#[no_mangle] -pub fn swap_vecs(x: &mut Vec, y: &mut Vec) { - // CHECK-NOT: alloca - // There are plenty more loads and stores than just these, - // but at least one sure better be 64-bit (for size or capacity). - // CHECK: load i64 - // CHECK: load i64 - // CHECK: store i64 - // CHECK: store i64 - // CHECK: ret void - swap(x, y) -} - -// CHECK-LABEL: @swap_slices -#[no_mangle] -pub fn swap_slices<'a>(x: &mut &'a [u32], y: &mut &'a [u32]) { - // CHECK-NOT: alloca - // CHECK: load ptr - // CHECK: load i64 - // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 16, i1 false) - // CHECK: store ptr - // CHECK: store i64 - swap(x, y) -} - -type RGB24 = [u8; 3]; - -// CHECK-LABEL: @swap_rgb24_slices -#[no_mangle] -pub fn swap_rgb24_slices(x: &mut [RGB24], y: &mut [RGB24]) { - // CHECK-NOT: alloca - - // CHECK: mul nuw nsw i64 %{{x|y}}.1, 3 - - // CHECK: load <{{[0-9]+}} x i64> - // CHECK: store <{{[0-9]+}} x i64> - - // CHECK-COUNT-2: load i32 - // CHECK-COUNT-2: store i32 - // CHECK-COUNT-2: load i16 - // CHECK-COUNT-2: store i16 - // CHECK-COUNT-2: load i8 - // CHECK-COUNT-2: store i8 - if x.len() == y.len() { - x.swap_with_slice(y); - } -} - -type RGBA32 = [u8; 4]; - -// CHECK-LABEL: @swap_rgba32_slices -#[no_mangle] -pub fn swap_rgba32_slices(x: &mut [RGBA32], y: &mut [RGBA32]) { - // CHECK-NOT: alloca - - // Because the size in bytes in a multiple of 4, we can skip the smallest sizes. - - // CHECK: load <{{[0-9]+}} x i64> - // CHECK: store <{{[0-9]+}} x i64> - - // CHECK-COUNT-2: load i32 - // CHECK-COUNT-2: store i32 - - // CHECK-NOT: load i16 - // CHECK-NOT: store i16 - // CHECK-NOT: load i8 - // CHECK-NOT: store i8 - - if x.len() == y.len() { - x.swap_with_slice(y); - } -} - -// Strings have a non-power-of-two size, but have pointer alignment, -// so we swap usizes instead of dropping all the way down to bytes. -const _: () = assert!(!std::mem::size_of::().is_power_of_two()); - -// CHECK-LABEL: @swap_string_slices -#[no_mangle] -pub fn swap_string_slices(x: &mut [String], y: &mut [String]) { - // CHECK-NOT: alloca - // CHECK: load <{{[0-9]+}} x i64>{{.+}}, align 8, - // CHECK: store <{{[0-9]+}} x i64>{{.+}}, align 8, - if x.len() == y.len() { - x.swap_with_slice(y); - } -} - -#[repr(C, packed)] -pub struct Packed { - pub first: bool, - pub second: usize, -} - -// CHECK-LABEL: @swap_packed_structs -#[no_mangle] -pub fn swap_packed_structs(x: &mut Packed, y: &mut Packed) { - // CHECK-NOT: alloca - - // CHECK-NOT: load - // CHECK-NOT: store - - // CHECK: %[[A:.+]] = load i64, ptr %x, align 1, - // CHECK-NEXT: %[[B:.+]] = load i64, ptr %y, align 1, - // CHECK-NEXT: store i64 %[[B]], ptr %x, align 1, - // CHECK-NEXT: store i64 %[[A]], ptr %y, align 1, - - // CHECK-NOT: load - // CHECK-NOT: store - - // CHECK: %[[C:.+]] = load i8, ptr %[[X8:.+]], align 1, - // CHECK-NEXT: %[[D:.+]] = load i8, ptr %[[Y8:.+]], align 1, - // CHECK-NEXT: store i8 %[[D]], ptr %[[X8]], align 1, - // CHECK-NEXT: store i8 %[[C]], ptr %[[Y8]], align 1, - - // CHECK-NOT: load - // CHECK-NOT: store - - // CHECK: ret void - swap(x, y) -} diff --git a/tests/codegen/target-cpu-on-functions.rs b/tests/codegen/target-cpu-on-functions.rs deleted file mode 100644 index 25c10e7ce44..00000000000 --- a/tests/codegen/target-cpu-on-functions.rs +++ /dev/null @@ -1,22 +0,0 @@ -// This test makes sure that functions get annotated with the proper -// "target-cpu" attribute in LLVM. - -//@ no-prefer-dynamic -// -//@ compile-flags: -C no-prepopulate-passes -C panic=abort -C linker-plugin-lto -Cpasses=name-anon-globals - -#![crate_type = "staticlib"] - -// CHECK-LABEL: define {{.*}} @exported() {{.*}} #0 -#[no_mangle] -pub extern "C" fn exported() { - not_exported(); -} - -// CHECK-LABEL: ; target_cpu_on_functions::not_exported -// CHECK-NEXT: ; Function Attrs: -// CHECK-NEXT: define {{.*}}() {{.*}} #1 -#[inline(never)] -fn not_exported() {} - -// CHECK: attributes #0 = {{.*}} "target-cpu"="{{.*}}" diff --git a/tests/codegen/target-feature-inline-closure.rs b/tests/codegen/target-feature-inline-closure.rs deleted file mode 100644 index 5d54444f994..00000000000 --- a/tests/codegen/target-feature-inline-closure.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@ only-x86_64 -// Set the base cpu explicitly, in case the default has been changed. -//@ compile-flags: -Copt-level=3 -Ctarget-cpu=x86-64 - -#![crate_type = "lib"] - -#[cfg(target_arch = "x86_64")] -use std::arch::x86_64::*; - -// CHECK-LABEL: @with_avx -#[no_mangle] -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "avx")] -fn with_avx(x: __m256) -> __m256 { - // CHECK: fadd <8 x float> - let add = { - #[inline(always)] - |x, y| unsafe { _mm256_add_ps(x, y) } - }; - add(x, x) -} - -// CHECK-LABEL: @without_avx -#[no_mangle] -#[cfg(target_arch = "x86_64")] -unsafe fn without_avx(x: __m256) -> __m256 { - // CHECK-NOT: fadd <8 x float> - let add = { - #[inline(always)] - |x, y| unsafe { _mm256_add_ps(x, y) } - }; - add(x, x) -} diff --git a/tests/codegen/target-feature-negative-implication.rs b/tests/codegen/target-feature-negative-implication.rs deleted file mode 100644 index 36cd82dd8cf..00000000000 --- a/tests/codegen/target-feature-negative-implication.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ add-core-stubs -//@ needs-llvm-components: x86 -//@ compile-flags: --target=x86_64-unknown-linux-gnu -//@ compile-flags: -Ctarget-feature=-avx2 - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[no_mangle] -pub unsafe fn banana() { - // CHECK-LABEL: @banana() - // CHECK-SAME: [[BANANAATTRS:#[0-9]+]] { -} - -// CHECK: attributes [[BANANAATTRS]] -// CHECK-SAME: -avx512 diff --git a/tests/codegen/target-feature-overrides.rs b/tests/codegen/target-feature-overrides.rs deleted file mode 100644 index 63a586d388b..00000000000 --- a/tests/codegen/target-feature-overrides.rs +++ /dev/null @@ -1,46 +0,0 @@ -// ignore-tidy-linelength -//@ add-core-stubs -//@ revisions: COMPAT INCOMPAT -//@ needs-llvm-components: x86 -//@ compile-flags: --target=x86_64-unknown-linux-gnu -Copt-level=3 -//@ [COMPAT] compile-flags: -Ctarget-feature=+avx2 -//@ [INCOMPAT] compile-flags: -Ctarget-feature=-avx2,-avx - -// See also tests/assembly-llvm/target-feature-multiple.rs -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -extern "C" { - fn peach() -> u32; -} - -#[inline] -#[target_feature(enable = "avx")] -#[no_mangle] -pub unsafe fn apple() -> u32 { - // CHECK-LABEL: @apple() - // CHECK-SAME: [[APPLEATTRS:#[0-9]+]] { - // CHECK: {{.*}}call{{.*}}@peach - peach() -} - -// target features same as global -#[no_mangle] -pub unsafe fn banana() -> u32 { - // CHECK-LABEL: @banana() - // CHECK-SAME: [[BANANAATTRS:#[0-9]+]] { - // COMPAT: {{.*}}call{{.*}}@peach - // INCOMPAT: {{.*}}call{{.*}}@apple - apple() // Compatible for inline in COMPAT revision and can't be inlined in INCOMPAT -} - -// CHECK: attributes [[APPLEATTRS]] -// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}" -// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}},+avx{{(,\+[^,]+)*}}" -// CHECK: attributes [[BANANAATTRS]] -// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}" -// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}}" diff --git a/tests/codegen/terminating-catchpad.rs b/tests/codegen/terminating-catchpad.rs deleted file mode 100644 index a2ec19871d1..00000000000 --- a/tests/codegen/terminating-catchpad.rs +++ /dev/null @@ -1,43 +0,0 @@ -//@ revisions: emscripten wasi seh -//@[emscripten] compile-flags: --target wasm32-unknown-emscripten -Z emscripten-wasm-eh -//@[wasi] compile-flags: --target wasm32-wasip1 -C panic=unwind -//@[seh] compile-flags: --target x86_64-pc-windows-msvc -//@[emscripten] needs-llvm-components: webassembly -//@[wasi] needs-llvm-components: webassembly -//@[seh] needs-llvm-components: x86 - -// Ensure a catch-all generates: -// - `catchpad ... [ptr null]` on Wasm (otherwise LLVM gets confused) -// - `catchpad ... [ptr null, i32 64, ptr null]` on Windows (otherwise we catch SEH exceptions) - -#![feature(no_core, lang_items, rustc_attrs)] -#![crate_type = "lib"] -#![no_std] -#![no_core] - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} - -unsafe extern "C-unwind" { - safe fn unwinds(); -} - -#[lang = "panic_cannot_unwind"] -fn panic_cannot_unwind() -> ! { - loop {} -} - -#[no_mangle] -#[rustc_nounwind] -pub fn doesnt_unwind() { - // emscripten: %catchpad = catchpad within %catchswitch [ptr null] - // wasi: %catchpad = catchpad within %catchswitch [ptr null] - // seh: %catchpad = catchpad within %catchswitch [ptr null, i32 64, ptr null] - unwinds(); -} diff --git a/tests/codegen/thread-local.rs b/tests/codegen/thread-local.rs deleted file mode 100644 index 41df8c9be1b..00000000000 --- a/tests/codegen/thread-local.rs +++ /dev/null @@ -1,54 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ aux-build:thread_local_aux.rs -//@ ignore-windows FIXME(#134939) -//@ ignore-wasm globals are used instead of thread locals -//@ ignore-emscripten globals are used instead of thread locals -//@ ignore-android does not use #[thread_local] -//@ ignore-nto does not use #[thread_local] - -#![crate_type = "lib"] - -extern crate thread_local_aux as aux; - -use std::cell::Cell; - -thread_local!(static A: Cell = const { Cell::new(1) }); - -// CHECK: [[TLS_AUX:@.+]] = external thread_local{{.*}} global i64 -// CHECK: [[TLS:@.+]] = internal thread_local{{.*}} global - -// CHECK-LABEL: @get -#[no_mangle] -fn get() -> u32 { - // CHECK: [[PTR:%.+]] = tail call {{.*}} ptr @llvm.threadlocal.address.p0(ptr [[TLS]]) - // CHECK-NEXT: [[RET_0:%.+]] = load i32, ptr [[PTR]] - // CHECK-NEXT: ret i32 [[RET_0]] - A.with(|a| a.get()) -} - -// CHECK-LABEL: @set -#[no_mangle] -fn set(v: u32) { - // CHECK: [[PTR:%.+]] = tail call {{.*}} ptr @llvm.threadlocal.address.p0(ptr [[TLS]]) - // CHECK-NEXT: store i32 %0, ptr [[PTR]] - // CHECK-NEXT: ret void - A.with(|a| a.set(v)) -} - -// CHECK-LABEL: @get_aux -#[no_mangle] -fn get_aux() -> u64 { - // CHECK: [[PTR:%.+]] = tail call {{.*}} ptr @llvm.threadlocal.address.p0(ptr [[TLS_AUX]]) - // CHECK-NEXT: [[RET_1:%.+]] = load i64, ptr [[PTR]] - // CHECK-NEXT: ret i64 [[RET_1]] - aux::A.with(|a| a.get()) -} - -// CHECK-LABEL: @set_aux -#[no_mangle] -fn set_aux(v: u64) { - // CHECK: [[PTR:%.+]] = tail call {{.*}} ptr @llvm.threadlocal.address.p0(ptr [[TLS_AUX]]) - // CHECK-NEXT: store i64 %0, ptr [[PTR]] - // CHECK-NEXT: ret void - aux::A.with(|a| a.set(v)) -} diff --git a/tests/codegen/tied-features-strength.rs b/tests/codegen/tied-features-strength.rs deleted file mode 100644 index 81499c070d1..00000000000 --- a/tests/codegen/tied-features-strength.rs +++ /dev/null @@ -1,34 +0,0 @@ -// ignore-tidy-linelength -//@ add-core-stubs -//@ revisions: ENABLE_SVE DISABLE_SVE DISABLE_NEON ENABLE_NEON -//@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu -//@ needs-llvm-components: aarch64 - -// Rust made SVE require neon. -//@ [ENABLE_SVE] compile-flags: -C target-feature=+sve -Copt-level=0 -// ENABLE_SVE: attributes #0 -// ENABLE_SVE-SAME: +neon -// ENABLE_SVE-SAME: +sve - -// However, disabling SVE does not disable neon. -//@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0 -// DISABLE_SVE: attributes #0 -// DISABLE_SVE-NOT: -neon -// DISABLE_SVE-SAME: -sve - -// OTOH, neon fn `fp-armv8` are fully tied; toggling neon must toggle `fp-armv8` the same way. -//@ [DISABLE_NEON] compile-flags: -C target-feature=-neon -Copt-level=0 -// DISABLE_NEON: attributes #0 -// DISABLE_NEON-SAME: -neon -// DISABLE_NEON-SAME: -fp-armv8 - -//@ [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0 -// ENABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fp-armv8,?)|(\+neon,?))*}}" } - -#![feature(no_core, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -pub fn test() {} diff --git a/tests/codegen/to_vec.rs b/tests/codegen/to_vec.rs deleted file mode 100644 index 4f6e77188d8..00000000000 --- a/tests/codegen/to_vec.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @copy_to_vec -#[no_mangle] -fn copy_to_vec(s: &[u64]) -> Vec { - s.to_vec() - // CHECK: call void @llvm.memcpy -} diff --git a/tests/codegen/trailing_zeros.rs b/tests/codegen/trailing_zeros.rs deleted file mode 100644 index 0816a980992..00000000000 --- a/tests/codegen/trailing_zeros.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @trailing_zeros_ge -#[no_mangle] -pub fn trailing_zeros_ge(val: u32) -> bool { - // CHECK: %[[AND:.*]] = and i32 %val, 7 - // CHECK: %[[ICMP:.*]] = icmp eq i32 %[[AND]], 0 - // CHECK: ret i1 %[[ICMP]] - val.trailing_zeros() >= 3 -} - -// CHECK-LABEL: @trailing_zeros_gt -#[no_mangle] -pub fn trailing_zeros_gt(val: u64) -> bool { - // CHECK: %[[AND:.*]] = and i64 %val, 15 - // CHECK: %[[ICMP:.*]] = icmp eq i64 %[[AND]], 0 - // CHECK: ret i1 %[[ICMP]] - val.trailing_zeros() > 3 -} diff --git a/tests/codegen/transmute-optimized.rs b/tests/codegen/transmute-optimized.rs deleted file mode 100644 index 477fdc6de90..00000000000 --- a/tests/codegen/transmute-optimized.rs +++ /dev/null @@ -1,120 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled -#![crate_type = "lib"] - -// This tests that LLVM can optimize based on the niches in the source or -// destination types for transmutes. - -#[repr(u32)] -pub enum AlwaysZero32 { - X = 0, -} - -// CHECK-LABEL: i32 @issue_109958(i32 -#[no_mangle] -pub fn issue_109958(x: AlwaysZero32) -> i32 { - // CHECK: ret i32 0 - unsafe { std::mem::transmute(x) } -} - -// CHECK-LABEL: i1 @reference_is_null(ptr -#[no_mangle] -pub fn reference_is_null(x: &i32) -> bool { - // CHECK: ret i1 false - let p: *const i32 = unsafe { std::mem::transmute(x) }; - p.is_null() -} - -// CHECK-LABEL: i1 @non_null_is_null(ptr -#[no_mangle] -pub fn non_null_is_null(x: std::ptr::NonNull) -> bool { - // CHECK: ret i1 false - let p: *const i32 = unsafe { std::mem::transmute(x) }; - p.is_null() -} - -// CHECK-LABEL: i1 @non_zero_is_null( -#[no_mangle] -pub fn non_zero_is_null(x: std::num::NonZero) -> bool { - // CHECK: ret i1 false - let p: *const i32 = unsafe { std::mem::transmute(x) }; - p.is_null() -} - -// CHECK-LABEL: i1 @non_null_is_zero(ptr -#[no_mangle] -pub fn non_null_is_zero(x: std::ptr::NonNull) -> bool { - // CHECK: ret i1 false - let a: isize = unsafe { std::mem::transmute(x) }; - a == 0 -} - -// CHECK-LABEL: i1 @bool_ordering_is_ge(i1 -#[no_mangle] -pub fn bool_ordering_is_ge(x: bool) -> bool { - // CHECK: ret i1 true - let y: std::cmp::Ordering = unsafe { std::mem::transmute(x) }; - y.is_ge() -} - -// CHECK-LABEL: i1 @ordering_is_ge_then_transmute_to_bool(i8 -#[no_mangle] -pub fn ordering_is_ge_then_transmute_to_bool(x: std::cmp::Ordering) -> bool { - let r = x.is_ge(); - let _: bool = unsafe { std::mem::transmute(x) }; - r -} - -// CHECK-LABEL: i32 @normal_div(i32 -#[no_mangle] -pub fn normal_div(a: u32, b: u32) -> u32 { - // CHECK: call core::panicking::panic - a / b -} - -// CHECK-LABEL: i32 @div_transmute_nonzero(i32 -#[no_mangle] -pub fn div_transmute_nonzero(a: u32, b: std::num::NonZero) -> u32 { - // CHECK-NOT: call core::panicking::panic - // CHECK: %[[R:.+]] = udiv i32 %a, %b - // CHECK-NEXT: ret i32 %[[R]] - // CHECK-NOT: call core::panicking::panic - let d: u32 = unsafe { std::mem::transmute(b) }; - a / d -} - -#[repr(i8)] -pub enum OneTwoThree { - One = 1, - Two = 2, - Three = 3, -} - -// CHECK-LABEL: i8 @ordering_transmute_onetwothree(i8 -#[no_mangle] -pub unsafe fn ordering_transmute_onetwothree(x: std::cmp::Ordering) -> OneTwoThree { - // CHECK: ret i8 1 - std::mem::transmute(x) -} - -// CHECK-LABEL: i8 @onetwothree_transmute_ordering(i8 -#[no_mangle] -pub unsafe fn onetwothree_transmute_ordering(x: OneTwoThree) -> std::cmp::Ordering { - // CHECK: ret i8 1 - std::mem::transmute(x) -} - -// CHECK-LABEL: i1 @char_is_negative(i32 -#[no_mangle] -pub fn char_is_negative(c: char) -> bool { - // CHECK: ret i1 false - let x: i32 = unsafe { std::mem::transmute(c) }; - x < 0 -} - -// CHECK-LABEL: i1 @transmute_to_char_is_negative(i32 -#[no_mangle] -pub fn transmute_to_char_is_negative(x: i32) -> bool { - // CHECK: ret i1 false - let _c: char = unsafe { std::mem::transmute(x) }; - x < 0 -} diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs deleted file mode 100644 index ce1b0558b2e..00000000000 --- a/tests/codegen/transmute-scalar.rs +++ /dev/null @@ -1,143 +0,0 @@ -//@ add-core-stubs -//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(no_core, repr_simd, arm_target_feature, mips_target_feature, s390x_target_feature)] -#![no_core] -extern crate minicore; - -use minicore::*; - -// With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type, -// without needing to pointercast, and SRoA will turn that into a `bitcast`. -// Thus memory-to-memory transmutes don't need to generate them ourselves. - -// However, `bitcast`s and `ptrtoint`s and `inttoptr`s are still worth doing when -// that allows us to avoid the `alloca`s entirely; see `rvalue_creates_operand`. - -// CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float %x) -// CHECK: %_0 = bitcast float %x to i32 -// CHECK-NEXT: ret i32 %_0 -#[no_mangle] -pub fn f32_to_bits(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -// CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 zeroext %b) -// CHECK: %_0 = zext i1 %b to i8 -// CHECK-NEXT: ret i8 %_0 -#[no_mangle] -pub fn bool_to_byte(b: bool) -> u8 { - unsafe { mem::transmute(b) } -} - -// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte) -// CHECK: %_0 = trunc{{( nuw)?}} i8 %byte to i1 -// CHECK-NEXT: ret i1 %_0 -#[no_mangle] -pub unsafe fn byte_to_bool(byte: u8) -> bool { - mem::transmute(byte) -} - -// CHECK-LABEL: define{{.*}}ptr @ptr_to_ptr(ptr %p) -// CHECK: ret ptr %p -#[no_mangle] -pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 { - unsafe { mem::transmute(p) } -} - -// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int(ptr %p) -// CHECK: %_0 = ptrtoint ptr %p to [[USIZE]] -// CHECK-NEXT: ret [[USIZE]] %_0 -#[no_mangle] -pub fn ptr_to_int(p: *mut u16) -> usize { - unsafe { mem::transmute(p) } -} - -// CHECK: define{{.*}}ptr @int_to_ptr([[USIZE]] %i) -// CHECK: %_0 = getelementptr i8, ptr null, [[USIZE]] %i -// CHECK-NEXT: ret ptr %_0 -#[no_mangle] -pub fn int_to_ptr(i: usize) -> *mut u16 { - unsafe { mem::transmute(i) } -} - -// This is the one case where signedness matters to transmuting: -// the LLVM type is `i8` here because of `repr(i8)`, -// whereas below with the `repr(u8)` it's `i1` in LLVM instead. -#[repr(i8)] -pub enum FakeBoolSigned { - False = 0, - True = 1, -} - -// CHECK-LABEL: define{{.*}}i8 @bool_to_fake_bool_signed(i1 zeroext %b) -// CHECK: %_0 = zext i1 %b to i8 -// CHECK-NEXT: ret i8 %_0 -#[no_mangle] -pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned { - unsafe { mem::transmute(b) } -} - -// CHECK-LABEL: define{{.*}}i1 @fake_bool_signed_to_bool(i8 %b) -// CHECK: %_0 = trunc nuw i8 %b to i1 -// CHECK-NEXT: ret i1 %_0 -#[no_mangle] -pub fn fake_bool_signed_to_bool(b: FakeBoolSigned) -> bool { - unsafe { mem::transmute(b) } -} - -#[repr(u8)] -pub enum FakeBoolUnsigned { - False = 0, - True = 1, -} - -// CHECK-LABEL: define{{.*}}i1 @bool_to_fake_bool_unsigned(i1 zeroext %b) -// CHECK: ret i1 %b -#[no_mangle] -pub fn bool_to_fake_bool_unsigned(b: bool) -> FakeBoolUnsigned { - unsafe { mem::transmute(b) } -} - -// CHECK-LABEL: define{{.*}}i1 @fake_bool_unsigned_to_bool(i1 zeroext %b) -// CHECK: ret i1 %b -#[no_mangle] -pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool { - unsafe { mem::transmute(b) } -} - -#[repr(simd)] -struct S([i64; 1]); - -// CHECK-LABEL: define{{.*}}i64 @single_element_simd_to_scalar(<1 x i64> %b) -// CHECK-NEXT: start: -// CHECK-NEXT: %[[RET:.+]] = alloca [8 x i8] -// CHECK-NEXT: store <1 x i64> %b, ptr %[[RET]] -// CHECK-NEXT: %[[TEMP:.+]] = load i64, ptr %[[RET]] -// CHECK-NEXT: ret i64 %[[TEMP]] -#[no_mangle] -#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] -#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] -#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] -#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] -#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] -pub extern "C" fn single_element_simd_to_scalar(b: S) -> i64 { - unsafe { mem::transmute(b) } -} - -// CHECK-LABEL: define{{.*}}<1 x i64> @scalar_to_single_element_simd(i64 %b) -// CHECK-NEXT: start: -// CHECK-NEXT: %[[RET:.+]] = alloca [8 x i8] -// CHECK-NEXT: store i64 %b, ptr %[[RET]] -// CHECK-NEXT: %[[TEMP:.+]] = load <1 x i64>, ptr %[[RET]] -// CHECK-NEXT: ret <1 x i64> %[[TEMP]] -#[no_mangle] -#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] -#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] -#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] -#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] -#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] -pub extern "C" fn scalar_to_single_element_simd(b: i64) -> S { - unsafe { mem::transmute(b) } -} diff --git a/tests/codegen/try_question_mark_nop.rs b/tests/codegen/try_question_mark_nop.rs deleted file mode 100644 index 398c9a580bc..00000000000 --- a/tests/codegen/try_question_mark_nop.rs +++ /dev/null @@ -1,243 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled -//@ edition: 2021 -//@ only-x86_64 -//@ revisions: NINETEEN TWENTY -//@[NINETEEN] exact-llvm-major-version: 19 -//@[TWENTY] min-llvm-version: 20 - -#![crate_type = "lib"] -#![feature(try_blocks)] - -use std::ops::ControlFlow::{self, Break, Continue}; -use std::ptr::NonNull; - -// CHECK-LABEL: @option_nop_match_32 -#[no_mangle] -pub fn option_nop_match_32(x: Option) -> Option { - // CHECK: start: - // CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i32 %0 to i1 - - // NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %0, i32 0 - // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 [[SELECT]], 0 - // NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 %1, 1 - - // TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %1, i32 undef - // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0 - // TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 [[SELECT]], 1 - - // CHECK-NEXT: ret { i32, i32 } [[REG3]] - match x { - Some(x) => Some(x), - None => None, - } -} - -// CHECK-LABEL: @option_nop_traits_32 -#[no_mangle] -pub fn option_nop_traits_32(x: Option) -> Option { - // CHECK: start: - // TWENTY-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %0 to i1 - // TWENTY-NEXT: select i1 %[[IS_SOME]], i32 %1, i32 undef - // CHECK-NEXT: insertvalue { i32, i32 } - // CHECK-NEXT: insertvalue { i32, i32 } - // CHECK-NEXT: ret { i32, i32 } - try { x? } -} - -// CHECK-LABEL: @result_nop_match_32 -#[no_mangle] -pub fn result_nop_match_32(x: Result) -> Result { - // CHECK: start: - // CHECK-NEXT: insertvalue { i32, i32 } - // CHECK-NEXT: insertvalue { i32, i32 } - // CHECK-NEXT: ret { i32, i32 } - match x { - Ok(x) => Ok(x), - Err(x) => Err(x), - } -} - -// CHECK-LABEL: @result_nop_traits_32 -#[no_mangle] -pub fn result_nop_traits_32(x: Result) -> Result { - // CHECK: start: - // CHECK-NEXT: insertvalue { i32, i32 } - // CHECK-NEXT: insertvalue { i32, i32 } - // CHECK-NEXT: ret { i32, i32 } - try { x? } -} - -// CHECK-LABEL: @control_flow_nop_match_32 -#[no_mangle] -pub fn control_flow_nop_match_32(x: ControlFlow) -> ControlFlow { - // CHECK: start: - // CHECK-NEXT: insertvalue { i32, i32 } - // CHECK-NEXT: insertvalue { i32, i32 } - // CHECK-NEXT: ret { i32, i32 } - match x { - Continue(x) => Continue(x), - Break(x) => Break(x), - } -} - -// CHECK-LABEL: @control_flow_nop_traits_32 -#[no_mangle] -pub fn control_flow_nop_traits_32(x: ControlFlow) -> ControlFlow { - // CHECK: start: - // CHECK-NEXT: insertvalue { i32, i32 } - // CHECK-NEXT: insertvalue { i32, i32 } - // CHECK-NEXT: ret { i32, i32 } - try { x? } -} - -// CHECK-LABEL: @option_nop_match_64 -#[no_mangle] -pub fn option_nop_match_64(x: Option) -> Option { - // CHECK: start: - // CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i64 %0 to i1 - - // NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %0, i64 0 - // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 [[SELECT]], 0 - // NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 %1, 1 - - // TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %1, i64 undef - // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 %0, 0 - // TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 [[SELECT]], 1 - - // CHECK-NEXT: ret { i64, i64 } [[REG3]] - match x { - Some(x) => Some(x), - None => None, - } -} - -// CHECK-LABEL: @option_nop_traits_64 -#[no_mangle] -pub fn option_nop_traits_64(x: Option) -> Option { - // CHECK: start: - // TWENTY-NEXT: %[[TRUNC:[0-9]+]] = trunc nuw i64 %0 to i1 - // TWENTY-NEXT: %[[SEL:\.[0-9]+]] = select i1 %[[TRUNC]], i64 %1, i64 undef - // CHECK-NEXT: insertvalue { i64, i64 } - // CHECK-NEXT: insertvalue { i64, i64 } - // CHECK-NEXT: ret { i64, i64 } - try { x? } -} - -// CHECK-LABEL: @result_nop_match_64 -#[no_mangle] -pub fn result_nop_match_64(x: Result) -> Result { - // CHECK: start: - // CHECK-NEXT: insertvalue { i64, i64 } - // CHECK-NEXT: insertvalue { i64, i64 } - // CHECK-NEXT: ret { i64, i64 } - match x { - Ok(x) => Ok(x), - Err(x) => Err(x), - } -} - -// CHECK-LABEL: @result_nop_traits_64 -#[no_mangle] -pub fn result_nop_traits_64(x: Result) -> Result { - // CHECK: start: - // CHECK-NEXT: insertvalue { i64, i64 } - // CHECK-NEXT: insertvalue { i64, i64 } - // CHECK-NEXT: ret { i64, i64 } - try { x? } -} - -// CHECK-LABEL: @control_flow_nop_match_64 -#[no_mangle] -pub fn control_flow_nop_match_64(x: ControlFlow) -> ControlFlow { - // CHECK: start: - // CHECK-NEXT: insertvalue { i64, i64 } - // CHECK-NEXT: insertvalue { i64, i64 } - // CHECK-NEXT: ret { i64, i64 } - match x { - Continue(x) => Continue(x), - Break(x) => Break(x), - } -} - -// CHECK-LABEL: @control_flow_nop_traits_64 -#[no_mangle] -pub fn control_flow_nop_traits_64(x: ControlFlow) -> ControlFlow { - // CHECK: start: - // CHECK-NEXT: insertvalue { i64, i64 } - // CHECK-NEXT: insertvalue { i64, i64 } - // CHECK-NEXT: ret { i64, i64 } - try { x? } -} - -// CHECK-LABEL: @result_nop_match_128 -#[no_mangle] -pub fn result_nop_match_128(x: Result) -> Result { - // CHECK: start: - // CHECK-NEXT: store i128 - // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8 - // CHECK-NEXT: store i128 - // CHECK-NEXT: ret void - match x { - Ok(x) => Ok(x), - Err(x) => Err(x), - } -} - -// CHECK-LABEL: @result_nop_traits_128 -#[no_mangle] -pub fn result_nop_traits_128(x: Result) -> Result { - // CHECK: start: - // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8 - // CHECK-NEXT: store i128 - // CHECK-NEXT: store i128 - // CHECK-NEXT: ret void - try { x? } -} - -// CHECK-LABEL: @control_flow_nop_match_128 -#[no_mangle] -pub fn control_flow_nop_match_128(x: ControlFlow) -> ControlFlow { - // CHECK: start: - // CHECK-NEXT: store i128 - // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8 - // CHECK-NEXT: store i128 - // CHECK-NEXT: ret void - match x { - Continue(x) => Continue(x), - Break(x) => Break(x), - } -} - -// CHECK-LABEL: @control_flow_nop_traits_128 -#[no_mangle] -pub fn control_flow_nop_traits_128(x: ControlFlow) -> ControlFlow { - // CHECK: start: - // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8 - // CHECK-NEXT: store i128 - // CHECK-NEXT: store i128 - // CHECK-NEXT: ret void - try { x? } -} - -// CHECK-LABEL: @result_nop_match_ptr -#[no_mangle] -pub fn result_nop_match_ptr(x: Result>) -> Result> { - // CHECK: start: - // CHECK-NEXT: insertvalue { i{{[0-9]+}}, ptr } - // CHECK-NEXT: insertvalue { i{{[0-9]+}}, ptr } - // CHECK-NEXT: ret - match x { - Ok(x) => Ok(x), - Err(x) => Err(x), - } -} - -// CHECK-LABEL: @result_nop_traits_ptr -#[no_mangle] -pub fn result_nop_traits_ptr(x: Result>) -> Result> { - // CHECK: start: - // CHECK-NEXT: insertvalue { i{{[0-9]+}}, ptr } - // CHECK-NEXT: insertvalue { i{{[0-9]+}}, ptr } - // CHECK-NEXT: ret - try { x? } -} diff --git a/tests/codegen/tune-cpu-on-functions.rs b/tests/codegen/tune-cpu-on-functions.rs deleted file mode 100644 index f50245b797f..00000000000 --- a/tests/codegen/tune-cpu-on-functions.rs +++ /dev/null @@ -1,21 +0,0 @@ -// This test makes sure that functions get annotated with the proper -// "tune-cpu" attribute in LLVM. - -//@ no-prefer-dynamic -// -//@ compile-flags: -C no-prepopulate-passes -C panic=abort -C linker-plugin-lto -Cpasses=name-anon-globals -Z tune-cpu=generic -Copt-level=0 - -#![crate_type = "staticlib"] - -// CHECK-LABEL: define {{.*}} @exported() {{.*}} #0 -#[no_mangle] -pub extern "C" fn exported() { - not_exported(); -} - -// CHECK-LABEL: ; tune_cpu_on_functions::not_exported -// CHECK-NEXT: ; Function Attrs: -// CHECK-NEXT: define {{.*}}() {{.*}} #0 -fn not_exported() {} - -// CHECK: attributes #0 = {{.*}} "tune-cpu"="{{.*}}" diff --git a/tests/codegen/tuple-layout-opt.rs b/tests/codegen/tuple-layout-opt.rs deleted file mode 100644 index 5b2f65e7aa7..00000000000 --- a/tests/codegen/tuple-layout-opt.rs +++ /dev/null @@ -1,57 +0,0 @@ -// 32-bit systems will return 128bit values using a return area pointer. -//@ revisions: bit32 bit64 -//@[bit32] only-32bit -//@[bit64] only-64bit -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 - -// Test that tuples get optimized layout, in particular with a ZST in the last field (#63244) - -#![crate_type = "lib"] - -type ScalarZstLast = (u128, ()); -// bit32: define {{(dso_local )?}}void @test_ScalarZstLast({{.*}} sret([16 x i8]) {{.*}}, i128 %_1) -// bit64: define {{(dso_local )?}}i128 @test_ScalarZstLast(i128 %_1) -#[no_mangle] -pub fn test_ScalarZstLast(_: ScalarZstLast) -> ScalarZstLast { - loop {} -} - -type ScalarZstFirst = ((), u128); -// bit32: define {{(dso_local )?}}void @test_ScalarZstFirst({{.*}} sret([16 x i8]) {{.*}}, i128 %_1) -// bit64: define {{(dso_local )?}}i128 @test_ScalarZstFirst(i128 %_1) -#[no_mangle] -pub fn test_ScalarZstFirst(_: ScalarZstFirst) -> ScalarZstFirst { - loop {} -} - -type ScalarPairZstLast = (u8, u128, ()); -// CHECK: define {{(dso_local )?}}void @test_ScalarPairZstLast(ptr sret({{[^,]*}}) -// CHECK-SAME: %_0, i128 %_1.0, i8 %_1.1) -#[no_mangle] -pub fn test_ScalarPairZstLast(_: ScalarPairZstLast) -> ScalarPairZstLast { - loop {} -} - -type ScalarPairZstFirst = ((), u8, u128); -// CHECK: define {{(dso_local )?}}void @test_ScalarPairZstFirst(ptr sret({{[^,]*}}) -// CHECK-SAME: %_0, i8 %_1.0, i128 %_1.1) -#[no_mangle] -pub fn test_ScalarPairZstFirst(_: ScalarPairZstFirst) -> ScalarPairZstFirst { - loop {} -} - -type ScalarPairLotsOfZsts = ((), u8, (), u128, ()); -// CHECK: define {{(dso_local )?}}void @test_ScalarPairLotsOfZsts(ptr sret({{[^,]*}}) -// CHECK-SAME: %_0, i128 %_1.0, i8 %_1.1) -#[no_mangle] -pub fn test_ScalarPairLotsOfZsts(_: ScalarPairLotsOfZsts) -> ScalarPairLotsOfZsts { - loop {} -} - -type ScalarPairLottaNesting = (((), ((), u8, (), u128, ())), ()); -// CHECK: define {{(dso_local )?}}void @test_ScalarPairLottaNesting(ptr sret({{[^,]*}}) -// CHECK-SAME: %_0, i128 %_1.0, i8 %_1.1) -#[no_mangle] -pub fn test_ScalarPairLottaNesting(_: ScalarPairLottaNesting) -> ScalarPairLottaNesting { - loop {} -} diff --git a/tests/codegen/ub-checks.rs b/tests/codegen/ub-checks.rs deleted file mode 100644 index 67f5bff08d5..00000000000 --- a/tests/codegen/ub-checks.rs +++ /dev/null @@ -1,28 +0,0 @@ -// With -Zub-checks=yes (enabled by default by -Cdebug-assertions=yes) we will produce a runtime -// check that the index to slice::get_unchecked is in-bounds of the slice. That is tested for by -// tests/ui/precondition-checks/out-of-bounds-get-unchecked.rs -// -// This test ensures that such a runtime check is *not* emitted when debug-assertions are enabled, -// but ub-checks are explicitly disabled. - -//@ revisions: DEBUG NOCHECKS -//@ [DEBUG] compile-flags: -//@ [NOCHECKS] compile-flags: -Zub-checks=no -//@ compile-flags: -Copt-level=3 -Cdebug-assertions=yes - -#![crate_type = "lib"] - -use std::ops::Range; - -// CHECK-LABEL: @slice_get_unchecked( -#[no_mangle] -pub unsafe fn slice_get_unchecked(x: &[i32], i: usize) -> &i32 { - // CHECK: icmp ult - // NOCHECKS: tail call void @llvm.assume - // DEBUG: br i1 - // DEBUG: call core::panicking::panic_nounwind - // DEBUG: unreachable - // CHECK: getelementptr inbounds - // CHECK: ret ptr - x.get_unchecked(i) -} diff --git a/tests/codegen/unchecked-float-casts.rs b/tests/codegen/unchecked-float-casts.rs deleted file mode 100644 index d1869abc87b..00000000000 --- a/tests/codegen/unchecked-float-casts.rs +++ /dev/null @@ -1,36 +0,0 @@ -// This file tests that we don't generate any code for saturation when using the -// unchecked intrinsics. - -//@ compile-flags: -C opt-level=3 -//@ ignore-wasm32 the wasm target is tested in `wasm_casts_*` - -#![crate_type = "lib"] - -// CHECK-LABEL: @f32_to_u32 -#[no_mangle] -pub fn f32_to_u32(x: f32) -> u32 { - // CHECK: fptoui - // CHECK-NOT: fcmp - // CHECK-NOT: icmp - // CHECK-NOT: select - unsafe { x.to_int_unchecked() } -} - -// CHECK-LABEL: @f32_to_i32 -#[no_mangle] -pub fn f32_to_i32(x: f32) -> i32 { - // CHECK: fptosi - // CHECK-NOT: fcmp - // CHECK-NOT: icmp - // CHECK-NOT: select - unsafe { x.to_int_unchecked() } -} - -#[no_mangle] -pub fn f64_to_u16(x: f64) -> u16 { - // CHECK: fptoui - // CHECK-NOT: fcmp - // CHECK-NOT: icmp - // CHECK-NOT: select - unsafe { x.to_int_unchecked() } -} diff --git a/tests/codegen/unchecked_shifts.rs b/tests/codegen/unchecked_shifts.rs deleted file mode 100644 index 3f533718a2d..00000000000 --- a/tests/codegen/unchecked_shifts.rs +++ /dev/null @@ -1,100 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes - -// This runs mir-opts to inline the standard library call, but doesn't run LLVM -// optimizations so it doesn't need to worry about them adding more flags. - -#![crate_type = "lib"] -#![feature(unchecked_shifts)] -#![feature(core_intrinsics)] - -// CHECK-LABEL: @unchecked_shl_unsigned_same -#[no_mangle] -pub unsafe fn unchecked_shl_unsigned_same(a: u32, b: u32) -> u32 { - // CHECK-NOT: assume - // CHECK-NOT: and i32 - // CHECK: shl i32 %a, %b - // CHECK-NOT: and i32 - a.unchecked_shl(b) -} - -// CHECK-LABEL: @unchecked_shl_unsigned_smaller -#[no_mangle] -pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 { - // CHECK-NOT: assume - // CHECK: %[[TRUNC:.+]] = trunc nuw i32 %b to i16 - // CHECK: shl i16 %a, %[[TRUNC]] - a.unchecked_shl(b) -} - -// CHECK-LABEL: @unchecked_shl_unsigned_bigger -#[no_mangle] -pub unsafe fn unchecked_shl_unsigned_bigger(a: u64, b: u32) -> u64 { - // CHECK-NOT: assume - // CHECK: %[[EXT:.+]] = zext i32 %b to i64 - // CHECK: shl i64 %a, %[[EXT]] - a.unchecked_shl(b) -} - -// CHECK-LABEL: @unchecked_shr_signed_same -#[no_mangle] -pub unsafe fn unchecked_shr_signed_same(a: i32, b: u32) -> i32 { - // CHECK-NOT: assume - // CHECK-NOT: and i32 - // CHECK: ashr i32 %a, %b - // CHECK-NOT: and i32 - a.unchecked_shr(b) -} - -// CHECK-LABEL: @unchecked_shr_signed_smaller -#[no_mangle] -pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 { - // CHECK-NOT: assume - // CHECK: %[[TRUNC:.+]] = trunc nuw i32 %b to i16 - // CHECK: ashr i16 %a, %[[TRUNC]] - a.unchecked_shr(b) -} - -// CHECK-LABEL: @unchecked_shr_signed_bigger -#[no_mangle] -pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 { - // CHECK-NOT: assume - // CHECK: %[[EXT:.+]] = zext i32 %b to i64 - // CHECK: ashr i64 %a, %[[EXT]] - a.unchecked_shr(b) -} - -// CHECK-LABEL: @unchecked_shr_u128_i8 -#[no_mangle] -pub unsafe fn unchecked_shr_u128_i8(a: u128, b: i8) -> u128 { - // CHECK-NOT: assume - // CHECK: %[[EXT:.+]] = zext i8 %b to i128 - // CHECK: lshr i128 %a, %[[EXT]] - std::intrinsics::unchecked_shr(a, b) -} - -// CHECK-LABEL: @unchecked_shl_i128_u8 -#[no_mangle] -pub unsafe fn unchecked_shl_i128_u8(a: i128, b: u8) -> i128 { - // CHECK-NOT: assume - // CHECK: %[[EXT:.+]] = zext i8 %b to i128 - // CHECK: shl i128 %a, %[[EXT]] - std::intrinsics::unchecked_shl(a, b) -} - -// CHECK-LABEL: @unchecked_shl_u8_i128 -#[no_mangle] -pub unsafe fn unchecked_shl_u8_i128(a: u8, b: i128) -> u8 { - // CHECK-NOT: assume - // CHECK: %[[TRUNC:.+]] = trunc nuw i128 %b to i8 - // CHECK: shl i8 %a, %[[TRUNC]] - std::intrinsics::unchecked_shl(a, b) -} - -// CHECK-LABEL: @unchecked_shr_i8_u128 -#[no_mangle] -pub unsafe fn unchecked_shr_i8_u128(a: i8, b: u128) -> i8 { - // CHECK-NOT: assume - // CHECK: %[[TRUNC:.+]] = trunc nuw i128 %b to i8 - // CHECK: ashr i8 %a, %[[TRUNC]] - std::intrinsics::unchecked_shr(a, b) -} diff --git a/tests/codegen/uninhabited-transparent-return-abi.rs b/tests/codegen/uninhabited-transparent-return-abi.rs deleted file mode 100644 index face1577c3f..00000000000 --- a/tests/codegen/uninhabited-transparent-return-abi.rs +++ /dev/null @@ -1,44 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -// See https://github.com/rust-lang/rust/issues/135802 - -#![crate_type = "lib"] - -enum Void {} - -// Should be ABI-compatible with T, but wasn't prior to the PR adding this test. -#[repr(transparent)] -struct NoReturn(T, Void); - -// Returned by invisible reference (in most ABIs) -#[allow(dead_code)] -struct Large(u64, u64, u64); - -extern "Rust" { - fn opaque() -> NoReturn; - fn opaque_with_arg(rsi: u32) -> NoReturn; -} - -// CHECK-LABEL: @test_uninhabited_ret_by_ref -#[no_mangle] -pub fn test_uninhabited_ret_by_ref() { - // CHECK: %_1 = alloca [24 x i8], align {{8|4}} - // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %_1) - // CHECK-NEXT: call void @opaque({{.*}} sret([24 x i8]) {{.*}} %_1) #2 - // CHECK-NEXT: unreachable - unsafe { - opaque(); - } -} - -// CHECK-LABEL: @test_uninhabited_ret_by_ref_with_arg -#[no_mangle] -pub fn test_uninhabited_ret_by_ref_with_arg(rsi: u32) { - // CHECK: %_2 = alloca [24 x i8], align {{8|4}} - // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %_2) - // CHECK-NEXT: call void @opaque_with_arg({{.*}} sret([24 x i8]) {{.*}} %_2, i32 noundef %rsi) #2 - // CHECK-NEXT: unreachable - unsafe { - opaque_with_arg(rsi); - } -} diff --git a/tests/codegen/uninit-consts.rs b/tests/codegen/uninit-consts.rs deleted file mode 100644 index bde71a35c47..00000000000 --- a/tests/codegen/uninit-consts.rs +++ /dev/null @@ -1,54 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes - -// Check that we use undef (and not zero) for uninitialized bytes in constants. - -#![crate_type = "lib"] - -use std::mem::MaybeUninit; - -pub struct PartiallyUninit { - x: u32, - y: MaybeUninit<[u8; 10]>, -} - -// CHECK: [[FULLY_UNINIT:@.*]] = private unnamed_addr constant [10 x i8] undef - -// CHECK: [[PARTIALLY_UNINIT:@.*]] = private unnamed_addr constant <{ [4 x i8], [12 x i8] }> <{ [4 x i8] c"{{\\EF\\BE\\AD\\DE|\\DE\\AD\\BE\\EF}}", [12 x i8] undef }>, align 4 - -// This shouldn't contain undef, since it contains more chunks -// than the default value of uninit_const_chunk_threshold. -// CHECK: [[UNINIT_PADDING_HUGE:@.*]] = private unnamed_addr constant [32768 x i8] c"{{.+}}", align 4 - -// CHECK: [[FULLY_UNINIT_HUGE:@.*]] = private unnamed_addr constant [16384 x i8] undef - -// CHECK-LABEL: @fully_uninit -#[no_mangle] -pub const fn fully_uninit() -> MaybeUninit<[u8; 10]> { - const M: MaybeUninit<[u8; 10]> = MaybeUninit::uninit(); - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %_0, ptr align 1 {{.*}}[[FULLY_UNINIT]]{{.*}}, i{{(32|64)}} 10, i1 false) - M -} - -// CHECK-LABEL: @partially_uninit -#[no_mangle] -pub const fn partially_uninit() -> PartiallyUninit { - const X: PartiallyUninit = PartiallyUninit { x: 0xdeadbeef, y: MaybeUninit::uninit() }; - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[PARTIALLY_UNINIT]]{{.*}}, i{{(32|64)}} 16, i1 false) - X -} - -// CHECK-LABEL: @uninit_padding_huge -#[no_mangle] -pub const fn uninit_padding_huge() -> [(u32, u8); 4096] { - const X: [(u32, u8); 4096] = [(123, 45); 4096]; - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[UNINIT_PADDING_HUGE]]{{.*}}, i{{(32|64)}} 32768, i1 false) - X -} - -// CHECK-LABEL: @fully_uninit_huge -#[no_mangle] -pub const fn fully_uninit_huge() -> MaybeUninit<[u32; 4096]> { - const F: MaybeUninit<[u32; 4096]> = MaybeUninit::uninit(); - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[FULLY_UNINIT_HUGE]]{{.*}}, i{{(32|64)}} 16384, i1 false) - F -} diff --git a/tests/codegen/uninit-repeat-in-aggregate.rs b/tests/codegen/uninit-repeat-in-aggregate.rs deleted file mode 100644 index 0fa2eb7d56c..00000000000 --- a/tests/codegen/uninit-repeat-in-aggregate.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -use std::mem::MaybeUninit; - -// We need to make sure len is at offset 0, otherwise codegen needs an extra instruction -#[repr(C)] -pub struct SmallVec { - pub len: u64, - pub arr: [MaybeUninit; 24], -} - -// CHECK-LABEL: @uninit_arr_via_const -#[no_mangle] -pub fn uninit_arr_via_const() -> SmallVec { - // CHECK-NEXT: start: - // CHECK-NEXT: store i64 0, - // CHECK-NEXT: ret - SmallVec { len: 0, arr: [const { MaybeUninit::uninit() }; 24] } -} diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs deleted file mode 100644 index 28acc4de2f3..00000000000 --- a/tests/codegen/union-abi.rs +++ /dev/null @@ -1,145 +0,0 @@ -//@ ignore-emscripten vectors passed directly -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -// 32-bit x86 returns `f32` differently to avoid the x87 stack. -// 32-bit systems will return 128bit values using a return area pointer. -//@ revisions: x86-sse x86-nosse bit32 bit64 -//@[x86-sse] only-x86 -//@[x86-sse] only-rustc_abi-x86-sse2 -//@[x86-nosse] only-x86 -//@[x86-nosse] ignore-rustc_abi-x86-sse2 -//@[bit32] ignore-x86 -//@[bit32] only-32bit -//@[bit64] ignore-x86 -//@[bit64] only-64bit - -// This test that using union forward the abi of the inner type, as -// discussed in #54668 - -#![crate_type = "lib"] -#![feature(repr_simd)] - -#[derive(Copy, Clone)] -pub enum Unhab {} - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct i64x4([i64; 4]); - -#[derive(Copy, Clone)] -pub union UnionI64x4 { - a: (), - b: i64x4, -} - -// CHECK: define {{(dso_local )?}}void @test_UnionI64x4(ptr {{.*}} %_1) -#[no_mangle] -pub fn test_UnionI64x4(_: UnionI64x4) { - loop {} -} - -pub union UnionI64x4_ { - a: i64x4, - b: (), - c: i64x4, - d: Unhab, - e: ((), ()), - f: UnionI64x4, -} - -// CHECK: define {{(dso_local )?}}void @test_UnionI64x4_(ptr {{.*}} %_1) -#[no_mangle] -pub fn test_UnionI64x4_(_: UnionI64x4_) { - loop {} -} - -pub union UnionI64x4I64 { - a: i64x4, - b: i64, -} - -// CHECK: define {{(dso_local )?}}void @test_UnionI64x4I64(ptr {{.*}} %_1) -#[no_mangle] -pub fn test_UnionI64x4I64(_: UnionI64x4I64) { - loop {} -} - -pub union UnionI64x4Tuple { - a: i64x4, - b: (i64, i64, i64, i64), -} - -// CHECK: define {{(dso_local )?}}void @test_UnionI64x4Tuple(ptr {{.*}} %_1) -#[no_mangle] -pub fn test_UnionI64x4Tuple(_: UnionI64x4Tuple) { - loop {} -} - -pub union UnionF32 { - a: f32, -} - -// x86-sse: define {{(dso_local )?}}<4 x i8> @test_UnionF32(float %_1) -// x86-nosse: define {{(dso_local )?}}i32 @test_UnionF32(float %_1) -// bit32: define {{(dso_local )?}}float @test_UnionF32(float %_1) -// bit64: define {{(dso_local )?}}float @test_UnionF32(float %_1) -#[no_mangle] -pub fn test_UnionF32(_: UnionF32) -> UnionF32 { - loop {} -} - -pub union UnionF32F32 { - a: f32, - b: f32, -} - -// x86-sse: define {{(dso_local )?}}<4 x i8> @test_UnionF32F32(float %_1) -// x86-nosse: define {{(dso_local )?}}i32 @test_UnionF32F32(float %_1) -// bit32: define {{(dso_local )?}}float @test_UnionF32F32(float %_1) -// bit64: define {{(dso_local )?}}float @test_UnionF32F32(float %_1) -#[no_mangle] -pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { - loop {} -} - -pub union UnionF32U32 { - a: f32, - b: u32, -} - -// CHECK: define {{(dso_local )?}}i32 @test_UnionF32U32(i32{{( %0)?}}) -#[no_mangle] -pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { - loop {} -} - -pub union UnionU128 { - a: u128, -} -// x86-sse: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1) -// x86-nosse: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1) -// bit32: define {{(dso_local )?}}void @test_UnionU128({{.*}}sret([16 x i8]){{.*}}, i128 %_1) -// bit64: define {{(dso_local )?}}i128 @test_UnionU128(i128 %_1) -#[no_mangle] -pub fn test_UnionU128(_: UnionU128) -> UnionU128 { - loop {} -} - -#[repr(C)] -pub union CUnionU128 { - a: u128, -} -// CHECK: define {{(dso_local )?}}void @test_CUnionU128(ptr {{.*}} %_1) -#[no_mangle] -pub fn test_CUnionU128(_: CUnionU128) { - loop {} -} - -pub union UnionBool { - b: bool, -} -// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8{{.*}} %b) -#[no_mangle] -pub fn test_UnionBool(b: UnionBool) -> bool { - unsafe { b.b } -} -// CHECK: %_0 = trunc{{( nuw)?}} i8 %b to i1 diff --git a/tests/codegen/union-aggregate.rs b/tests/codegen/union-aggregate.rs deleted file mode 100644 index aac66c5dcdd..00000000000 --- a/tests/codegen/union-aggregate.rs +++ /dev/null @@ -1,108 +0,0 @@ -//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes -//@ min-llvm-version: 19 -//@ only-64bit - -#![crate_type = "lib"] -#![feature(transparent_unions)] -#![feature(repr_simd)] - -#[repr(transparent)] -union MU { - uninit: (), - value: T, -} - -use std::cmp::Ordering; -use std::num::NonZero; -use std::ptr::NonNull; - -#[no_mangle] -fn make_mu_bool(x: bool) -> MU { - // CHECK-LABEL: i8 @make_mu_bool(i1 zeroext %x) - // CHECK-NEXT: start: - // CHECK-NEXT: %[[WIDER:.+]] = zext i1 %x to i8 - // CHECK-NEXT: ret i8 %[[WIDER]] - MU { value: x } -} - -#[no_mangle] -fn make_mu_bool_uninit() -> MU { - // CHECK-LABEL: i8 @make_mu_bool_uninit() - // CHECK-NEXT: start: - // CHECK-NEXT: ret i8 undef - MU { uninit: () } -} - -#[no_mangle] -fn make_mu_ref(x: &u16) -> MU<&u16> { - // CHECK-LABEL: ptr @make_mu_ref(ptr align 2 %x) - // CHECK-NEXT: start: - // CHECK-NEXT: ret ptr %x - MU { value: x } -} - -#[no_mangle] -fn make_mu_ref_uninit<'a>() -> MU<&'a u16> { - // CHECK-LABEL: ptr @make_mu_ref_uninit() - // CHECK-NEXT: start: - // CHECK-NEXT: ret ptr undef - MU { uninit: () } -} - -#[no_mangle] -fn make_mu_str(x: &str) -> MU<&str> { - // CHECK-LABEL: { ptr, i64 } @make_mu_str(ptr align 1 %x.0, i64 %x.1) - // CHECK-NEXT: start: - // CHECK-NEXT: %0 = insertvalue { ptr, i64 } poison, ptr %x.0, 0 - // CHECK-NEXT: %1 = insertvalue { ptr, i64 } %0, i64 %x.1, 1 - // CHECK-NEXT: ret { ptr, i64 } %1 - MU { value: x } -} - -#[no_mangle] -fn make_mu_str_uninit<'a>() -> MU<&'a str> { - // CHECK-LABEL: { ptr, i64 } @make_mu_str_uninit() - // CHECK-NEXT: start: - // CHECK-NEXT: ret { ptr, i64 } undef - MU { uninit: () } -} - -#[no_mangle] -fn make_mu_pair(x: (u8, u32)) -> MU<(u8, u32)> { - // CHECK-LABEL: { i8, i32 } @make_mu_pair(i8 %x.0, i32 %x.1) - // CHECK-NEXT: start: - // CHECK-NEXT: %0 = insertvalue { i8, i32 } poison, i8 %x.0, 0 - // CHECK-NEXT: %1 = insertvalue { i8, i32 } %0, i32 %x.1, 1 - // CHECK-NEXT: ret { i8, i32 } %1 - MU { value: x } -} - -#[no_mangle] -fn make_mu_pair_uninit() -> MU<(u8, u32)> { - // CHECK-LABEL: { i8, i32 } @make_mu_pair_uninit() - // CHECK-NEXT: start: - // CHECK-NEXT: ret { i8, i32 } undef - MU { uninit: () } -} - -#[repr(simd)] -#[derive(Copy, Clone)] -struct I32X32([i32; 32]); - -#[no_mangle] -fn make_mu_simd(x: I32X32) -> MU { - // CHECK-LABEL: void @make_mu_simd(ptr{{.+}}%_0, ptr{{.+}}%x) - // CHECK-NEXT: start: - // CHECK-NEXT: %[[TEMP:.+]] = load <32 x i32>, ptr %x, - // CHECK-NEXT: store <32 x i32> %[[TEMP]], ptr %_0, - // CHECK-NEXT: ret void - MU { value: x } -} - -#[no_mangle] -fn make_mu_simd_uninit() -> MU { - // CHECK-LABEL: void @make_mu_simd_uninit(ptr{{.+}}%_0) - // CHECK-NEXT: start: - // CHECK-NEXT: ret void - MU { uninit: () } -} diff --git a/tests/codegen/unwind-abis/aapcs-unwind-abi.rs b/tests/codegen/unwind-abis/aapcs-unwind-abi.rs deleted file mode 100644 index ecace722e0d..00000000000 --- a/tests/codegen/unwind-abis/aapcs-unwind-abi.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ needs-llvm-components: arm -//@ compile-flags: --target=armv7-unknown-linux-gnueabihf --crate-type=rlib -Cno-prepopulate-passes -#![no_core] -#![feature(no_core, lang_items)] - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} - -// Test that `nounwind` attributes are correctly applied to exported `aapcs` and -// `aapcs-unwind` extern functions. `aapcs-unwind` functions MUST NOT have this attribute. We -// disable optimizations above to prevent LLVM from inferring the attribute. - -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { -#[no_mangle] -pub extern "aapcs" fn rust_item_that_cannot_unwind() {} - -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { -#[no_mangle] -pub extern "aapcs-unwind" fn rust_item_that_can_unwind() {} - -// Now, make some assertions that the LLVM attributes for these functions are correct. First, make -// sure that the first item is correctly marked with the `nounwind` attribute: -// -// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } -// -// Next, let's assert that the second item, which CAN unwind, does not have this attribute. -// -// CHECK: attributes #1 = { -// CHECK-NOT: nounwind -// CHECK: } diff --git a/tests/codegen/unwind-abis/c-unwind-abi-panic-abort.rs b/tests/codegen/unwind-abis/c-unwind-abi-panic-abort.rs deleted file mode 100644 index 8d2745ba2f7..00000000000 --- a/tests/codegen/unwind-abis/c-unwind-abi-panic-abort.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ compile-flags: -C panic=abort - -// Test that `nounwind` attributes are also applied to extern `C-unwind` Rust functions -// when the code is compiled with `panic=abort`. - -#![crate_type = "lib"] - -// CHECK: @rust_item_that_can_unwind() unnamed_addr [[ATTR0:#[0-9]+]] -#[no_mangle] -pub unsafe extern "C-unwind" fn rust_item_that_can_unwind() { - // Handle both legacy and v0 symbol mangling. - // CHECK: call void @{{.*core9panicking19panic_cannot_unwind}} - may_unwind(); -} - -extern "C-unwind" { - // CHECK: @may_unwind() unnamed_addr [[ATTR1:#[0-9]+]] - fn may_unwind(); -} - -// Now, make sure that the LLVM attributes for this functions are correct. First, make -// sure that the first item is correctly marked with the `nounwind` attribute: -// -// CHECK: attributes [[ATTR0]] = { {{.*}}nounwind{{.*}} } -// -// Now, check that foreign item is correctly marked without the `nounwind` attribute. -// CHECK-NOT: attributes [[ATTR1]] = { {{.*}}nounwind{{.*}} } diff --git a/tests/codegen/unwind-abis/c-unwind-abi.rs b/tests/codegen/unwind-abis/c-unwind-abi.rs deleted file mode 100644 index 46c08b5fc4f..00000000000 --- a/tests/codegen/unwind-abis/c-unwind-abi.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ compile-flags: -C opt-level=0 -//@ needs-unwind - -// Test that `nounwind` attributes are correctly applied to exported `C` and `C-unwind` extern -// functions. `C-unwind` functions MUST NOT have this attribute. We disable optimizations above -// to prevent LLVM from inferring the attribute. - -#![crate_type = "lib"] - -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { -#[no_mangle] -pub extern "C" fn rust_item_that_cannot_unwind() {} - -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { -#[no_mangle] -pub extern "C-unwind" fn rust_item_that_can_unwind() {} - -// Now, make some assertions that the LLVM attributes for these functions are correct. First, make -// sure that the first item is correctly marked with the `nounwind` attribute: -// -// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } -// -// Next, let's assert that the second item, which CAN unwind, does not have this attribute. -// -// CHECK: attributes #1 = { -// CHECK-NOT: nounwind -// CHECK: } diff --git a/tests/codegen/unwind-abis/cdecl-unwind-abi.rs b/tests/codegen/unwind-abis/cdecl-unwind-abi.rs deleted file mode 100644 index 8e643d6ce49..00000000000 --- a/tests/codegen/unwind-abis/cdecl-unwind-abi.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ compile-flags: -C opt-level=0 -//@ needs-unwind - -// Test that `nounwind` attributes are correctly applied to exported `cdecl` and -// `cdecl-unwind` extern functions. `cdecl-unwind` functions MUST NOT have this attribute. We -// disable optimizations above to prevent LLVM from inferring the attribute. - -#![crate_type = "lib"] - -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { -#[no_mangle] -pub extern "cdecl" fn rust_item_that_cannot_unwind() {} - -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { -#[no_mangle] -pub extern "cdecl-unwind" fn rust_item_that_can_unwind() {} - -// Now, make some assertions that the LLVM attributes for these functions are correct. First, make -// sure that the first item is correctly marked with the `nounwind` attribute: -// -// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } -// -// Next, let's assert that the second item, which CAN unwind, does not have this attribute. -// -// CHECK: attributes #1 = { -// CHECK-NOT: nounwind -// CHECK: } diff --git a/tests/codegen/unwind-abis/fastcall-unwind-abi.rs b/tests/codegen/unwind-abis/fastcall-unwind-abi.rs deleted file mode 100644 index 7df46813ed1..00000000000 --- a/tests/codegen/unwind-abis/fastcall-unwind-abi.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ needs-llvm-components: x86 -//@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes -#![no_core] -#![feature(no_core, lang_items)] - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} - -// Test that `nounwind` attributes are correctly applied to exported `fastcall` and -// `fastcall-unwind` extern functions. `fastcall-unwind` functions MUST NOT have this attribute. We -// disable optimizations above to prevent LLVM from inferring the attribute. - -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { -#[no_mangle] -pub extern "fastcall" fn rust_item_that_cannot_unwind() {} - -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { -#[no_mangle] -pub extern "fastcall-unwind" fn rust_item_that_can_unwind() {} - -// Now, make some assertions that the LLVM attributes for these functions are correct. First, make -// sure that the first item is correctly marked with the `nounwind` attribute: -// -// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } -// -// Next, let's assert that the second item, which CAN unwind, does not have this attribute. -// -// CHECK: attributes #1 = { -// CHECK-NOT: nounwind -// CHECK: } diff --git a/tests/codegen/unwind-abis/nounwind-on-stable-panic-abort.rs b/tests/codegen/unwind-abis/nounwind-on-stable-panic-abort.rs deleted file mode 100644 index d27cbd60437..00000000000 --- a/tests/codegen/unwind-abis/nounwind-on-stable-panic-abort.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: -C opt-level=0 -Cpanic=abort - -#![crate_type = "lib"] - -// We disable optimizations to prevent LLVM from inferring the attribute. - -// CHECK: Function Attrs:{{.*}}nounwind -// CHECK-NEXT: @foo -#[no_mangle] -pub extern "C" fn foo() {} - -// CHECK: Function Attrs:{{.*}}nounwind -// CHECK-NEXT: @bar -#[no_mangle] -pub fn bar() {} diff --git a/tests/codegen/unwind-abis/nounwind.rs b/tests/codegen/unwind-abis/nounwind.rs deleted file mode 100644 index e40ed48ca73..00000000000 --- a/tests/codegen/unwind-abis/nounwind.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ compile-flags: -C opt-level=0 -Cpanic=abort -//@ needs-unwind - -#![crate_type = "lib"] - -// We disable optimizations to prevent LLVM from inferring the attribute. - -// CHECK: Function Attrs:{{.*}}nounwind -// CHECK-NEXT: @foo -#[no_mangle] -pub extern "C" fn foo() {} - -// CHECK: Function Attrs:{{.*}}nounwind -// CHECK-NEXT: @bar -#[no_mangle] -pub fn bar() {} diff --git a/tests/codegen/unwind-abis/stdcall-unwind-abi.rs b/tests/codegen/unwind-abis/stdcall-unwind-abi.rs deleted file mode 100644 index cc06ee12549..00000000000 --- a/tests/codegen/unwind-abis/stdcall-unwind-abi.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ needs-llvm-components: x86 -//@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes -#![no_core] -#![feature(no_core, lang_items)] - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} - -// Test that `nounwind` attributes are correctly applied to exported `stdcall` and `stdcall-unwind` -// extern functions. `stdcall-unwind` functions MUST NOT have this attribute. We disable -// optimizations above to prevent LLVM from inferring the attribute. - -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { -#[no_mangle] -pub extern "stdcall" fn rust_item_that_cannot_unwind() {} - -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { -#[no_mangle] -pub extern "stdcall-unwind" fn rust_item_that_can_unwind() {} - -// Now, make some assertions that the LLVM attributes for these functions are correct. First, make -// sure that the first item is correctly marked with the `nounwind` attribute: -// -// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } -// -// Next, let's assert that the second item, which CAN unwind, does not have this attribute. -// -// CHECK: attributes #1 = { -// CHECK-NOT: nounwind -// CHECK: } diff --git a/tests/codegen/unwind-abis/system-unwind-abi.rs b/tests/codegen/unwind-abis/system-unwind-abi.rs deleted file mode 100644 index 5f910248346..00000000000 --- a/tests/codegen/unwind-abis/system-unwind-abi.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ compile-flags: -C opt-level=0 -//@ needs-unwind - -// Test that `nounwind` attributes are correctly applied to exported `system` and `system-unwind` -// extern functions. `system-unwind` functions MUST NOT have this attribute. We disable -// optimizations above to prevent LLVM from inferring the attribute. - -#![crate_type = "lib"] - -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { -#[no_mangle] -pub extern "system" fn rust_item_that_cannot_unwind() {} - -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { -#[no_mangle] -pub extern "system-unwind" fn rust_item_that_can_unwind() {} - -// Now, make some assertions that the LLVM attributes for these functions are correct. First, make -// sure that the first item is correctly marked with the `nounwind` attribute: -// -// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } -// -// Next, let's assert that the second item, which CAN unwind, does not have this attribute. -// -// CHECK: attributes #1 = { -// CHECK-NOT: nounwind -// CHECK: } diff --git a/tests/codegen/unwind-abis/sysv64-unwind-abi.rs b/tests/codegen/unwind-abis/sysv64-unwind-abi.rs deleted file mode 100644 index 69bfaf80b4b..00000000000 --- a/tests/codegen/unwind-abis/sysv64-unwind-abi.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ needs-llvm-components: x86 -//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes -#![no_core] -#![feature(no_core, lang_items)] - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} - -// Test that `nounwind` attributes are correctly applied to exported `sysv64` and -// `sysv64-unwind` extern functions. `sysv64-unwind` functions MUST NOT have this attribute. We -// disable optimizations above to prevent LLVM from inferring the attribute. - -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { -#[no_mangle] -pub extern "sysv64" fn rust_item_that_cannot_unwind() {} - -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { -#[no_mangle] -pub extern "sysv64-unwind" fn rust_item_that_can_unwind() {} - -// Now, make some assertions that the LLVM attributes for these functions are correct. First, make -// sure that the first item is correctly marked with the `nounwind` attribute: -// -// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } -// -// Next, let's assert that the second item, which CAN unwind, does not have this attribute. -// -// CHECK: attributes #1 = { -// CHECK-NOT: nounwind -// CHECK: } diff --git a/tests/codegen/unwind-abis/thiscall-unwind-abi.rs b/tests/codegen/unwind-abis/thiscall-unwind-abi.rs deleted file mode 100644 index 05f6b8b70e1..00000000000 --- a/tests/codegen/unwind-abis/thiscall-unwind-abi.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ needs-llvm-components: x86 -//@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes -#![no_core] -#![feature(no_core, lang_items)] - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} - -// Test that `nounwind` attributes are correctly applied to exported `thiscall` and -// `thiscall-unwind` extern functions. `thiscall-unwind` functions MUST NOT have this attribute. We -// disable optimizations above to prevent LLVM from inferring the attribute. - -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { -#[no_mangle] -pub extern "thiscall" fn rust_item_that_cannot_unwind() {} - -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { -#[no_mangle] -pub extern "thiscall-unwind" fn rust_item_that_can_unwind() {} - -// Now, make some assertions that the LLVM attributes for these functions are correct. First, make -// sure that the first item is correctly marked with the `nounwind` attribute: -// -// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } -// -// Next, let's assert that the second item, which CAN unwind, does not have this attribute. -// -// CHECK: attributes #1 = { -// CHECK-NOT: nounwind -// CHECK: } diff --git a/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs b/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs deleted file mode 100644 index d001a16b32a..00000000000 --- a/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ needs-llvm-components: x86 -//@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes -#![no_core] -#![feature(no_core, lang_items, abi_vectorcall)] - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} - -// Test that `nounwind` attributes are correctly applied to exported `vectorcall` and -// `vectorcall-unwind` extern functions. `vectorcall-unwind` functions MUST NOT have this attribute. -// We disable optimizations above to prevent LLVM from inferring the attribute. - -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { -#[no_mangle] -pub extern "vectorcall" fn rust_item_that_cannot_unwind() {} - -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { -#[no_mangle] -pub extern "vectorcall-unwind" fn rust_item_that_can_unwind() {} - -// Now, make some assertions that the LLVM attributes for these functions are correct. First, make -// sure that the first item is correctly marked with the `nounwind` attribute: -// -// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } -// -// Next, let's assert that the second item, which CAN unwind, does not have this attribute. -// -// CHECK: attributes #1 = { -// CHECK-NOT: nounwind -// CHECK: } diff --git a/tests/codegen/unwind-abis/win64-unwind-abi.rs b/tests/codegen/unwind-abis/win64-unwind-abi.rs deleted file mode 100644 index 257f00b54e4..00000000000 --- a/tests/codegen/unwind-abis/win64-unwind-abi.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ needs-llvm-components: x86 -//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes -#![no_core] -#![feature(no_core, lang_items)] - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} - -// Test that `nounwind` attributes are correctly applied to exported `win64` and -// `win64-unwind` extern functions. `win64-unwind` functions MUST NOT have this attribute. We -// disable optimizations above to prevent LLVM from inferring the attribute. - -// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { -#[no_mangle] -pub extern "win64" fn rust_item_that_cannot_unwind() {} - -// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { -#[no_mangle] -pub extern "win64-unwind" fn rust_item_that_can_unwind() {} - -// Now, make some assertions that the LLVM attributes for these functions are correct. First, make -// sure that the first item is correctly marked with the `nounwind` attribute: -// -// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } -// -// Next, let's assert that the second item, which CAN unwind, does not have this attribute. -// -// CHECK: attributes #1 = { -// CHECK-NOT: nounwind -// CHECK: } diff --git a/tests/codegen/unwind-and-panic-abort.rs b/tests/codegen/unwind-and-panic-abort.rs deleted file mode 100644 index 8efa140058a..00000000000 --- a/tests/codegen/unwind-and-panic-abort.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ compile-flags: -C panic=abort - -#![crate_type = "lib"] - -extern "C-unwind" { - fn bar(); -} - -// CHECK: Function Attrs:{{.*}}nounwind -// CHECK-NEXT: define{{.*}}void @foo -// Handle both legacy and v0 symbol mangling. -// CHECK: call void @{{.*core9panicking19panic_cannot_unwind}} -#[no_mangle] -pub unsafe extern "C" fn foo() { - bar(); -} diff --git a/tests/codegen/unwind-extern-exports.rs b/tests/codegen/unwind-extern-exports.rs deleted file mode 100644 index e692fd1a547..00000000000 --- a/tests/codegen/unwind-extern-exports.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: -C opt-level=0 -//@ needs-unwind - -#![crate_type = "lib"] - -// Make sure these all do *not* get the attribute. -// We disable optimizations to prevent LLVM from inferring the attribute. -// CHECK-NOT: nounwind - -// "C" ABI -pub extern "C-unwind" fn foo_unwind() {} - -// "Rust" -// (`extern "Rust"` could be removed as all `fn` get it implicitly; we leave it in for clarity.) -pub fn bar() {} diff --git a/tests/codegen/unwind-extern-imports.rs b/tests/codegen/unwind-extern-imports.rs deleted file mode 100644 index dfae8aae64a..00000000000 --- a/tests/codegen/unwind-extern-imports.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -//@ needs-unwind - -#![crate_type = "lib"] - -extern "C" { - // CHECK: Function Attrs:{{.*}}nounwind - // CHECK-NEXT: declare{{.*}}void @extern_fn - fn extern_fn(); -} - -extern "C-unwind" { - // CHECK-NOT: nounwind - // CHECK: declare{{.*}}void @c_unwind_extern_fn - fn c_unwind_extern_fn(); -} - -pub unsafe fn force_declare() { - extern_fn(); - c_unwind_extern_fn(); -} diff --git a/tests/codegen/unwind-landingpad-cold.rs b/tests/codegen/unwind-landingpad-cold.rs deleted file mode 100644 index fb095e04650..00000000000 --- a/tests/codegen/unwind-landingpad-cold.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: -Cno-prepopulate-passes -//@ needs-unwind -#![crate_type = "lib"] - -// This test checks that drop calls in unwind landing pads -// get the `cold` attribute. - -// CHECK-LABEL: @check_cold -// CHECK: {{(call|invoke) void .+}}drop_in_place{{.+}} [[ATTRIBUTES:#[0-9]+]] -// CHECK: attributes [[ATTRIBUTES]] = { cold } -#[no_mangle] -pub fn check_cold(f: fn(), x: Box) { - // this may unwind - f(); -} diff --git a/tests/codegen/unwind-landingpad-inline.rs b/tests/codegen/unwind-landingpad-inline.rs deleted file mode 100644 index 1cf606279e6..00000000000 --- a/tests/codegen/unwind-landingpad-inline.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -// This test checks that we can inline drop_in_place in -// unwind landing pads. - -// Without inlining, the box pointers escape via the call to drop_in_place, -// and LLVM will not optimize out the pointer comparison. -// With inlining, everything should be optimized out. -// See https://github.com/rust-lang/rust/issues/46515 -// CHECK-LABEL: @check_no_escape_in_landingpad -// CHECK: start: -// CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 -// CHECK-NEXT: tail call void @[[NO_ALLOC_SHIM:_R.+__rust_no_alloc_shim_is_unstable_v2]]() -// CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 -// CHECK-NEXT: tail call void @[[NO_ALLOC_SHIM]]() -// CHECK-NEXT: ret void -#[no_mangle] -pub fn check_no_escape_in_landingpad(f: fn()) { - let x = &*Box::new(0); - let y = &*Box::new(0); - - if x as *const _ == y as *const _ { - f(); - } -} - -// Without inlining, the compiler can't tell that -// dropping an empty string (in a landing pad) does nothing. -// With inlining, the landing pad should be optimized out. -// See https://github.com/rust-lang/rust/issues/87055 -// CHECK-LABEL: @check_eliminate_noop_drop -// CHECK: call void %g() -// CHECK-NEXT: ret void -#[no_mangle] -pub fn check_eliminate_noop_drop(g: fn()) { - let _var = String::new(); - g(); -} diff --git a/tests/codegen/used_with_arg.rs b/tests/codegen/used_with_arg.rs deleted file mode 100644 index 4515cb2aed0..00000000000 --- a/tests/codegen/used_with_arg.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![crate_type = "lib"] -#![feature(used_with_arg)] - -// CHECK: @llvm.used = appending global {{.*}}USED_LINKER -#[used(linker)] -static mut USED_LINKER: [usize; 1] = [0]; - -// CHECK-NEXT: @llvm.compiler.used = appending global {{.*}}USED_COMPILER -#[used(compiler)] -static mut USED_COMPILER: [usize; 1] = [0]; diff --git a/tests/codegen/var-names.rs b/tests/codegen/var-names.rs deleted file mode 100644 index 40720e19761..00000000000 --- a/tests/codegen/var-names.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes - -#![crate_type = "lib"] - -// CHECK-LABEL: define{{.*}}i32 @test(i32{{.*}} %a, i32{{.*}} %b) -#[no_mangle] -pub fn test(a: u32, b: u32) -> u32 { - let c = a + b; - // CHECK: %c = add i32 %a, %b - let d = c; - let e = d * a; - // CHECK-NEXT: %e = mul i32 %c, %a - e - // CHECK-NEXT: ret i32 %e -} diff --git a/tests/codegen/vec-as-ptr.rs b/tests/codegen/vec-as-ptr.rs deleted file mode 100644 index 5c997802640..00000000000 --- a/tests/codegen/vec-as-ptr.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled - -#![crate_type = "lib"] - -// Test that even though we return a *const u8 not a &[u8] or a NonNull, LLVM knows that this -// pointer is nonnull. -// CHECK: nonnull ptr @vec_as_ptr -#[no_mangle] -pub fn vec_as_ptr(v: &Vec) -> *const u8 { - v.as_ptr() -} - -// Test that even though we return a *const u8 not a &[u8] or a NonNull, LLVM knows that this -// pointer is nonnull. -// CHECK: nonnull ptr @vec_as_mut_ptr -#[no_mangle] -pub fn vec_as_mut_ptr(v: &mut Vec) -> *mut u8 { - v.as_mut_ptr() -} diff --git a/tests/codegen/vec-calloc.rs b/tests/codegen/vec-calloc.rs deleted file mode 100644 index d1c320ead01..00000000000 --- a/tests/codegen/vec-calloc.rs +++ /dev/null @@ -1,182 +0,0 @@ -//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled -//@ only-x86_64 - -#![crate_type = "lib"] - -// CHECK-LABEL: @vec_zero_bytes -#[no_mangle] -pub fn vec_zero_bytes(n: usize) -> Vec { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - // CHECK-NOT: call {{.*}}llvm.memset - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - // CHECK-NOT: call {{.*}}llvm.memset - - // CHECK: ret void - vec![0; n] -} - -// CHECK-LABEL: @vec_one_bytes -#[no_mangle] -pub fn vec_one_bytes(n: usize) -> Vec { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: call {{.*}}__rust_alloc( - // CHECK: call {{.*}}llvm.memset - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: ret void - vec![1; n] -} - -// CHECK-LABEL: @vec_zero_scalar -#[no_mangle] -pub fn vec_zero_scalar(n: usize) -> Vec { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![0; n] -} - -// CHECK-LABEL: @vec_one_scalar -#[no_mangle] -pub fn vec_one_scalar(n: usize) -> Vec { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: call {{.*}}__rust_alloc( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: ret void - vec![1; n] -} - -// CHECK-LABEL: @vec_zero_rgb48 -#[no_mangle] -pub fn vec_zero_rgb48(n: usize) -> Vec<[u16; 3]> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![[0, 0, 0]; n] -} - -// CHECK-LABEL: @vec_zero_array_16 -#[no_mangle] -pub fn vec_zero_array_16(n: usize) -> Vec<[i64; 16]> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![[0_i64; 16]; n] -} - -// CHECK-LABEL: @vec_zero_tuple -#[no_mangle] -pub fn vec_zero_tuple(n: usize) -> Vec<(i16, u8, char)> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![(0, 0, '\0'); n] -} - -// CHECK-LABEL: @vec_non_zero_tuple -#[no_mangle] -pub fn vec_non_zero_tuple(n: usize) -> Vec<(i16, u8, char)> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: call {{.*}}__rust_alloc( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: ret void - vec![(0, 0, 'A'); n] -} - -// CHECK-LABEL: @vec_option_bool -#[no_mangle] -pub fn vec_option_bool(n: usize) -> Vec> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![Some(false); n] -} - -// CHECK-LABEL: @vec_option_i32 -#[no_mangle] -pub fn vec_option_i32(n: usize) -> Vec> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![None; n] -} - -// Ensure that __rust_alloc_zeroed gets the right attributes for LLVM to optimize it away. -// CHECK: declare noalias noundef ptr @{{.*}}__rust_alloc_zeroed(i64 noundef, i64 allocalign noundef) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]] - -// CHECK-DAG: attributes [[RUST_ALLOC_ZEROED_ATTRS]] = { {{.*}} allockind("alloc,zeroed,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} } diff --git a/tests/codegen/vec-in-place.rs b/tests/codegen/vec-in-place.rs deleted file mode 100644 index a5ef8653b99..00000000000 --- a/tests/codegen/vec-in-place.rs +++ /dev/null @@ -1,161 +0,0 @@ -//@ ignore-std-debug-assertions (FIXME: checks for call detect scoped noalias metadata) -//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled -#![crate_type = "lib"] - -// Ensure that trivial casts of vec elements are O(1) - -pub struct Wrapper(T); - -// previously repr(C) caused the optimization to fail -#[repr(C)] -pub struct Foo { - a: u64, - b: u64, - c: u64, - d: u64, -} - -// implementing Copy exercises the TrustedRandomAccess specialization inside the in-place -// specialization -#[derive(Copy, Clone)] -pub struct Bar { - a: u64, - b: u64, - c: u64, - d: u64, -} - -// this exercises the try-fold codepath -pub struct Baz { - a: u64, - b: u64, - c: u64, - d: u64, -} - -// CHECK-LABEL: @vec_iterator_cast_primitive -#[no_mangle] -pub fn vec_iterator_cast_primitive(vec: Vec) -> Vec { - // CHECK-NOT: loop - // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call - vec.into_iter().map(|e| e as u8).collect() -} - -// CHECK-LABEL: @vec_iterator_cast_wrapper -#[no_mangle] -pub fn vec_iterator_cast_wrapper(vec: Vec) -> Vec> { - // CHECK-NOT: loop - // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call - vec.into_iter().map(|e| Wrapper(e)).collect() -} - -// CHECK-LABEL: @vec_iterator_cast_signed -#[no_mangle] -pub fn vec_iterator_cast_signed(vec: Vec) -> Vec { - // CHECK-NOT: and i{{[0-9]+}} %{{.*}}, {{[0-9]+}} - vec.into_iter().map(|e| u32::from_ne_bytes(e.to_ne_bytes())).collect() -} - -// CHECK-LABEL: @vec_iterator_cast_signed_nested -#[no_mangle] -pub fn vec_iterator_cast_signed_nested(vec: Vec>) -> Vec> { - // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} - // CHECK-NOT: %{{.*}} = udiv - vec.into_iter() - .map(|e| e.into_iter().map(|e| u32::from_ne_bytes(e.to_ne_bytes())).collect()) - .collect() -} - -// CHECK-LABEL: @vec_iterator_cast_unwrap -#[no_mangle] -pub fn vec_iterator_cast_unwrap(vec: Vec>) -> Vec { - // CHECK-NOT: loop - // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call - vec.into_iter().map(|e| e.0).collect() -} - -// CHECK-LABEL: @vec_iterator_cast_aggregate -#[no_mangle] -pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec { - // CHECK-NOT: loop - // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call - vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect() -} - -// CHECK-LABEL: @vec_iterator_cast_deaggregate_tra -#[no_mangle] -pub fn vec_iterator_cast_deaggregate_tra(vec: Vec) -> Vec<[u64; 4]> { - // CHECK-NOT: loop - // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call - - // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4]. - // This currently is not guaranteed for repr(Rust) types, but it happens to work here and - // the UCG may add additional guarantees for homogenous types in the future that would make this - // correct. - vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect() -} - -// CHECK-LABEL: @vec_iterator_cast_deaggregate_fold -#[no_mangle] -pub fn vec_iterator_cast_deaggregate_fold(vec: Vec) -> Vec<[u64; 4]> { - // CHECK-NOT: loop - // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call - - // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4]. - // This currently is not guaranteed for repr(Rust) types, but it happens to work here and - // the UCG may add additional guarantees for homogenous types in the future that would make this - // correct. - vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect() -} - -// CHECK-LABEL: @vec_iterator_cast_unwrap_drop -#[no_mangle] -pub fn vec_iterator_cast_unwrap_drop(vec: Vec>) -> Vec { - // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} - // CHECK-NOT: %{{.*}} = mul - // CHECK-NOT: %{{.*}} = udiv - // CHECK: call - // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} - // CHECK-NOT: call - // CHECK-NOT: %{{.*}} = mul - // CHECK-NOT: %{{.*}} = udiv - // CHECK: ret void - - vec.into_iter().map(|Wrapper(e)| e).collect() -} - -// CHECK-LABEL: @vec_iterator_cast_wrap_drop -#[no_mangle] -pub fn vec_iterator_cast_wrap_drop(vec: Vec) -> Vec> { - // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} - // CHECK-NOT: %{{.*}} = mul - // CHECK-NOT: %{{.*}} = udiv - // CHECK: call - // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} - // CHECK-NOT: call - // CHECK-NOT: %{{.*}} = mul - // CHECK-NOT: %{{.*}} = udiv - // CHECK: ret void - - vec.into_iter().map(Wrapper).collect() -} diff --git a/tests/codegen/vec-iter-collect-len.rs b/tests/codegen/vec-iter-collect-len.rs deleted file mode 100644 index 807548ef883..00000000000 --- a/tests/codegen/vec-iter-collect-len.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -#[no_mangle] -pub fn get_len() -> usize { - // CHECK-LABEL: @get_len - // CHECK-NEXT: start: - // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 - // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() - // CHECK-NEXT: ret i{{[0-9]+}} 3 - [1, 2, 3].iter().collect::>().len() -} diff --git a/tests/codegen/vec-iter.rs b/tests/codegen/vec-iter.rs deleted file mode 100644 index 4ed00d2d34f..00000000000 --- a/tests/codegen/vec-iter.rs +++ /dev/null @@ -1,58 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] -#![feature(exact_size_is_empty)] - -use std::vec; - -// CHECK-LABEL: @vec_iter_len_nonnull -#[no_mangle] -pub fn vec_iter_len_nonnull(it: &vec::IntoIter) -> usize { - // CHECK: load ptr - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - // CHECK: load ptr - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - // CHECK: sub nuw - // CHECK: ret - it.len() -} - -// CHECK-LABEL: @vec_iter_is_empty_nonnull -#[no_mangle] -pub fn vec_iter_is_empty_nonnull(it: &vec::IntoIter) -> bool { - // CHECK: load ptr - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - // CHECK: load ptr - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - // CHECK: ret - it.is_empty() -} - -// CHECK-LABEL: @vec_iter_next_nonnull -#[no_mangle] -pub fn vec_iter_next_nonnull(it: &mut vec::IntoIter) -> Option { - // CHECK: load ptr - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - // CHECK: load ptr - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - // CHECK: ret - it.next() -} - -// CHECK-LABEL: @vec_iter_next_back_nonnull -#[no_mangle] -pub fn vec_iter_next_back_nonnull(it: &mut vec::IntoIter) -> Option { - // CHECK: load ptr - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - // CHECK: load ptr - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef - // CHECK: ret - it.next_back() -} diff --git a/tests/codegen/vec-len-invariant.rs b/tests/codegen/vec-len-invariant.rs deleted file mode 100644 index 033181c2bfb..00000000000 --- a/tests/codegen/vec-len-invariant.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ only-64bit -// -// This test confirms that we do not reload the length of a Vec after growing it in push. - -#![crate_type = "lib"] - -// CHECK-LABEL: @should_load_once -#[no_mangle] -pub fn should_load_once(v: &mut Vec) { - // CHECK: load i64 - // CHECK: call {{.*}}grow_one - // CHECK-NOT: load i64 - // CHECK: add {{.*}}, 1 - v.push(1); -} diff --git a/tests/codegen/vec-optimizes-away.rs b/tests/codegen/vec-optimizes-away.rs deleted file mode 100644 index 93b55454b10..00000000000 --- a/tests/codegen/vec-optimizes-away.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ compile-flags: -Copt-level=3 -#![crate_type = "lib"] - -#[no_mangle] -pub fn sum_me() -> i32 { - // CHECK-LABEL: @sum_me - // CHECK-NEXT: {{^.*:$}} - // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 - // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() - // CHECK-NEXT: ret i32 6 - vec![1, 2, 3].iter().sum::() -} diff --git a/tests/codegen/vec-reserve-extend.rs b/tests/codegen/vec-reserve-extend.rs deleted file mode 100644 index 4d3f23ccecf..00000000000 --- a/tests/codegen/vec-reserve-extend.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @should_reserve_once -#[no_mangle] -pub fn should_reserve_once(v: &mut Vec) { - // CHECK: tail call void @llvm.assume - v.try_reserve(3).unwrap(); - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}do_reserve_and_handle - // CHECK-NOT: call {{.*}}__rust_alloc( - v.extend([1, 2, 3]); -} diff --git a/tests/codegen/vec-shrink-panik.rs b/tests/codegen/vec-shrink-panik.rs deleted file mode 100644 index 23dd300d48c..00000000000 --- a/tests/codegen/vec-shrink-panik.rs +++ /dev/null @@ -1,31 +0,0 @@ -// LLVM 17 realizes double panic is not possible and doesn't generate calls -// to panic_cannot_unwind. -//@ compile-flags: -Copt-level=3 -//@ ignore-std-debug-assertions (plain old debug assertions) -//@ needs-unwind -#![crate_type = "lib"] -#![feature(shrink_to)] - -// Make sure that `Vec::shrink_to_fit` never emits panics via `RawVec::shrink_to_fit`, -// "Tried to shrink to a larger capacity", because the length is *always* <= capacity. - -// CHECK-LABEL: @shrink_to_fit -#[no_mangle] -pub fn shrink_to_fit(vec: &mut Vec) { - // CHECK-NOT: panic - vec.shrink_to_fit(); -} - -// CHECK-LABEL: @issue71861 -#[no_mangle] -pub fn issue71861(vec: Vec) -> Box<[u32]> { - // CHECK-NOT: panic - vec.into_boxed_slice() -} - -// CHECK-LABEL: @issue75636 -#[no_mangle] -pub fn issue75636<'a>(iter: &[&'a str]) -> Box<[&'a str]> { - // CHECK-NOT: panic - iter.iter().copied().collect() -} diff --git a/tests/codegen/vec-with-capacity.rs b/tests/codegen/vec-with-capacity.rs deleted file mode 100644 index 777bbcc4fcb..00000000000 --- a/tests/codegen/vec-with-capacity.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@ compile-flags: -Copt-level=3 -//@ ignore-std-debug-assertions -// (with debug assertions turned on, `assert_unchecked` generates a real assertion) - -#![crate_type = "lib"] -#![feature(try_with_capacity)] - -// CHECK-LABEL: @with_capacity_does_not_grow1 -#[no_mangle] -pub fn with_capacity_does_not_grow1() -> Vec { - let v = Vec::with_capacity(1234); - // CHECK: call {{.*}}__rust_alloc( - // CHECK-NOT: call {{.*}}__rust_realloc - // CHECK-NOT: call {{.*}}capacity_overflow - // CHECK-NOT: call {{.*}}finish_grow - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: memcpy - // CHECK-NOT: memset - v -} - -// CHECK-LABEL: @try_with_capacity_does_not_grow2 -#[no_mangle] -pub fn try_with_capacity_does_not_grow2() -> Option>> { - let v = Vec::try_with_capacity(1234).ok()?; - // CHECK: call {{.*}}__rust_alloc( - // CHECK-NOT: call {{.*}}__rust_realloc - // CHECK-NOT: call {{.*}}capacity_overflow - // CHECK-NOT: call {{.*}}finish_grow - // CHECK-NOT: call {{.*}}handle_alloc_error - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: memcpy - // CHECK-NOT: memset - Some(v) -} diff --git a/tests/codegen/vec_pop_push_noop.rs b/tests/codegen/vec_pop_push_noop.rs deleted file mode 100644 index 3e375219fe0..00000000000 --- a/tests/codegen/vec_pop_push_noop.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -#[no_mangle] -// CHECK-LABEL: @noop( -pub fn noop(v: &mut Vec) { - // CHECK-NOT: grow_one - // CHECK-NOT: call - // CHECK: tail call void @llvm.assume - // CHECK-NOT: grow_one - // CHECK-NOT: call - // CHECK: {{ret|[}]}} - if let Some(x) = v.pop() { - v.push(x) - } -} - -#[no_mangle] -// CHECK-LABEL: @push_byte( -pub fn push_byte(v: &mut Vec) { - // CHECK: call {{.*}}grow_one - v.push(3); -} diff --git a/tests/codegen/vecdeque-drain.rs b/tests/codegen/vecdeque-drain.rs deleted file mode 100644 index a5e5da65013..00000000000 --- a/tests/codegen/vecdeque-drain.rs +++ /dev/null @@ -1,70 +0,0 @@ -// Check that draining at the front or back doesn't copy memory. - -//@ compile-flags: -Copt-level=3 -//@ needs-deterministic-layouts -//@ ignore-std-debug-assertions (FIXME: checks for call detect scoped noalias metadata) - -#![crate_type = "lib"] - -use std::collections::VecDeque; - -// CHECK-LABEL: @clear -// CHECK-NOT: call -// CHECK-NOT: br -// CHECK: getelementptr inbounds -// CHECK-NEXT: {{call void @llvm.memset|store}} -// CHECK-NEXT: ret void -#[no_mangle] -pub fn clear(v: &mut VecDeque) { - v.drain(..); -} - -// CHECK-LABEL: @truncate -// CHECK-NOT: call -// CHECK: br -// CHECK-NOT: call -// CHECK: br -// CHECK-NOT: call -// CHECK: br -// CHECK-NOT: call -// CHECK: br -// CHECK-NOT: call -// CHECK-NOT: br -// CHECK: ret void -#[no_mangle] -pub fn truncate(v: &mut VecDeque, n: usize) { - if n < v.len() { - v.drain(n..); - } -} - -// CHECK-LABEL: @advance -// CHECK-NOT: call -// CHECK: br -// CHECK-NOT: call -// CHECK: br -// CHECK-NOT: call -// CHECK: br -// CHECK-NOT: call -// CHECK: br -// CHECK-NOT: call -// CHECK: br -// CHECK-NOT: call -// CHECK-NOT: br -// CHECK: ret void -#[no_mangle] -pub fn advance(v: &mut VecDeque, n: usize) { - if n < v.len() { - v.drain(..n); - } else { - v.clear(); - } -} - -// CHECK-LABEL: @remove -// CHECK: call -// CHECK: ret void -#[no_mangle] -pub fn remove(v: &mut VecDeque, a: usize, b: usize) { - v.drain(a..b); -} diff --git a/tests/codegen/vecdeque-nonempty-get-no-panic.rs b/tests/codegen/vecdeque-nonempty-get-no-panic.rs deleted file mode 100644 index 1f886b096bb..00000000000 --- a/tests/codegen/vecdeque-nonempty-get-no-panic.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Guards against regression for optimization discussed in issue #80836 - -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -use std::collections::VecDeque; - -// CHECK-LABEL: @front -// CHECK: ret void -#[no_mangle] -pub fn front(v: VecDeque) { - if !v.is_empty() { - v.get(0).unwrap(); - } -} diff --git a/tests/codegen/vecdeque_no_panic.rs b/tests/codegen/vecdeque_no_panic.rs deleted file mode 100644 index 3166842afca..00000000000 --- a/tests/codegen/vecdeque_no_panic.rs +++ /dev/null @@ -1,19 +0,0 @@ -// This test checks that `VecDeque::front[_mut]()` and `VecDeque::back[_mut]()` can't panic. - -//@ compile-flags: -Copt-level=3 -//@ ignore-std-debug-assertions (plain old debug assertions) - -#![crate_type = "lib"] - -use std::collections::VecDeque; - -// CHECK-LABEL: @dont_panic -#[no_mangle] -pub fn dont_panic(v: &mut VecDeque) { - // CHECK-NOT: expect - // CHECK-NOT: panic - v.front(); - v.front_mut(); - v.back(); - v.back_mut(); -} diff --git a/tests/codegen/vecdeque_pop_push.rs b/tests/codegen/vecdeque_pop_push.rs deleted file mode 100644 index 5afa1b2248b..00000000000 --- a/tests/codegen/vecdeque_pop_push.rs +++ /dev/null @@ -1,67 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -use std::collections::VecDeque; - -#[no_mangle] -// CHECK-LABEL: @noop_back( -pub fn noop_back(v: &mut VecDeque) { - // CHECK-NOT: grow - // CHECK: tail call void @llvm.assume - // CHECK-NOT: grow - // CHECK: ret - if let Some(x) = v.pop_back() { - v.push_back(x); - } -} - -#[no_mangle] -// CHECK-LABEL: @noop_front( -pub fn noop_front(v: &mut VecDeque) { - // CHECK-NOT: grow - // CHECK: tail call void @llvm.assume - // CHECK-NOT: grow - // CHECK: ret - if let Some(x) = v.pop_front() { - v.push_front(x); - } -} - -#[no_mangle] -// CHECK-LABEL: @move_byte_front_to_back( -pub fn move_byte_front_to_back(v: &mut VecDeque) { - // CHECK-NOT: grow - // CHECK: tail call void @llvm.assume - // CHECK-NOT: grow - // CHECK: ret - if let Some(x) = v.pop_front() { - v.push_back(x); - } -} - -#[no_mangle] -// CHECK-LABEL: @move_byte_back_to_front( -pub fn move_byte_back_to_front(v: &mut VecDeque) { - // CHECK-NOT: grow - // CHECK: tail call void @llvm.assume - // CHECK-NOT: grow - // CHECK: ret - if let Some(x) = v.pop_back() { - v.push_front(x); - } -} - -#[no_mangle] -// CHECK-LABEL: @push_back_byte( -pub fn push_back_byte(v: &mut VecDeque) { - // CHECK: call {{.*}}grow - v.push_back(3); -} - -#[no_mangle] -// CHECK-LABEL: @push_front_byte( -pub fn push_front_byte(v: &mut VecDeque) { - // CHECK: call {{.*}}grow - v.push_front(3); -} diff --git a/tests/codegen/virtual-call-attrs-issue-137646.rs b/tests/codegen/virtual-call-attrs-issue-137646.rs deleted file mode 100644 index 5e453947f27..00000000000 --- a/tests/codegen/virtual-call-attrs-issue-137646.rs +++ /dev/null @@ -1,37 +0,0 @@ -//! Regression test for https://github.com/rust-lang/rust/issues/137646. -//! Since we don't know the exact implementation of the virtual call, -//! it might write to parameters, we can't infer the readonly attribute. -//@ compile-flags: -C opt-level=3 -C no-prepopulate-passes - -#![crate_type = "lib"] -#![feature(rustc_attrs)] - -pub trait Trait { - #[rustc_nounwind] - fn m(&self, _: (i32, i32, i32)) {} -} - -#[no_mangle] -pub fn foo(trait_: &dyn Trait) { - // CHECK-LABEL: @foo( - // CHECK: call void - // CHECK-NOT: readonly - trait_.m((1, 1, 1)); -} - -#[no_mangle] -#[rustc_nounwind] -pub fn foo_nounwind(trait_: &dyn Trait) { - // CHECK-LABEL: @foo_nounwind( - // FIXME: Here should be invoke. - // COM: CHECK: invoke - trait_.m((1, 1, 1)); -} - -#[no_mangle] -pub extern "C" fn c_nounwind(trait_: &dyn Trait) { - // CHECK-LABEL: @c_nounwind( - // FIXME: Here should be invoke. - // COM: CHECK: invoke - trait_.m((1, 1, 1)); -} diff --git a/tests/codegen/virtual-function-elimination-32bit.rs b/tests/codegen/virtual-function-elimination-32bit.rs deleted file mode 100644 index c9919cecccf..00000000000 --- a/tests/codegen/virtual-function-elimination-32bit.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@ compile-flags: -Zvirtual-function-elimination -Clto -Copt-level=3 -Csymbol-mangling-version=v0 -//@ ignore-64bit - -// CHECK: @vtable.0 = {{.*}}, !type ![[TYPE0:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]] - -#![crate_type = "lib"] - -trait T { - // CHECK-LABEL: ; ::used - fn used(&self) -> i32 { - 1 - } - // CHECK-LABEL-NOT: {{.*}}::unused - fn unused(&self) -> i32 { - 2 - } -} - -#[derive(Copy, Clone)] -struct S; - -impl T for S {} - -fn taking_t(t: &dyn T) -> i32 { - // CHECK: @llvm.type.checked.load({{.*}}, i32 12, metadata !"[[MANGLED_TYPE0:[0-9a-zA-Z_]+]]") - t.used() -} - -pub fn main() { - let s = S; - taking_t(&s); -} - -// CHECK: ![[TYPE0]] = !{i32 0, !"[[MANGLED_TYPE0]]"} -// CHECK: ![[VCALL_VIS0]] = !{i64 2} diff --git a/tests/codegen/virtual-function-elimination.rs b/tests/codegen/virtual-function-elimination.rs deleted file mode 100644 index 26604478c11..00000000000 --- a/tests/codegen/virtual-function-elimination.rs +++ /dev/null @@ -1,98 +0,0 @@ -//@ compile-flags: -Zvirtual-function-elimination -Clto -Copt-level=3 -Csymbol-mangling-version=v0 -//@ ignore-32bit - -// CHECK: @vtable.0 = {{.*}}, !type ![[TYPE0:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]] -// CHECK: @vtable.1 = {{.*}}, !type ![[TYPE1:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]] -// CHECK: @vtable.2 = {{.*}}, !type ![[TYPE2:[0-9]+]], !vcall_visibility ![[VCALL_VIS2:[0-9]+]] - -#![crate_type = "lib"] - -use std::rc::Rc; - -trait T { - // CHECK-LABEL: ; ::used - fn used(&self) -> i32 { - 1 - } - // CHECK-LABEL: ; ::used_through_sub_trait - fn used_through_sub_trait(&self) -> i32 { - 3 - } - // CHECK-LABEL: ; ::by_rc - fn by_rc(self: Rc) -> i32 { - self.used() + self.used() - } - // CHECK-LABEL-NOT: {{.*}}::unused - fn unused(&self) -> i32 { - 2 - } - // CHECK-LABEL-NOT: {{.*}}::by_rc_unused - fn by_rc_unused(self: Rc) -> i32 { - self.by_rc() - } -} - -trait U: T { - // CHECK-LABEL: ; ::subtrait_used - fn subtrait_used(&self) -> i32 { - 4 - } - // CHECK-LABEL-NOT: {{.*}}::subtrait_unused - fn subtrait_unused(&self) -> i32 { - 5 - } -} - -pub trait V { - // CHECK-LABEL: ; ::public_function - fn public_function(&self) -> i32; -} - -#[derive(Copy, Clone)] -struct S; - -impl T for S {} - -impl U for S {} - -impl V for S { - fn public_function(&self) -> i32 { - 6 - } -} - -fn taking_t(t: &dyn T) -> i32 { - // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"[[MANGLED_TYPE0:[0-9a-zA-Z_]+]]") - t.used() -} - -fn taking_rc_t(t: Rc) -> i32 { - // CHECK: @llvm.type.checked.load({{.*}}, i32 40, metadata !"[[MANGLED_TYPE0:[0-9a-zA-Z_]+]]") - t.by_rc() -} - -fn taking_u(u: &dyn U) -> i32 { - // CHECK: @llvm.type.checked.load({{.*}}, i32 64, metadata !"[[MANGLED_TYPE1:[0-9a-zA-Z_]+]]") - // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"[[MANGLED_TYPE1:[0-9a-zA-Z_]+]]") - // CHECK: @llvm.type.checked.load({{.*}}, i32 32, metadata !"[[MANGLED_TYPE1:[0-9a-zA-Z_]+]]") - u.subtrait_used() + u.used() + u.used_through_sub_trait() -} - -pub fn taking_v(v: &dyn V) -> i32 { - // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"NtC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_28virtual_function_elimination1V") - v.public_function() -} - -pub fn main() { - let s = S; - taking_t(&s); - taking_rc_t(Rc::new(s)); - taking_u(&s); - taking_v(&s); -} - -// CHECK: ![[TYPE0]] = !{i64 0, !"[[MANGLED_TYPE0]]"} -// CHECK: ![[VCALL_VIS0]] = !{i64 2} -// CHECK: ![[TYPE1]] = !{i64 0, !"[[MANGLED_TYPE1]]"} -// CHECK: ![[TYPE2]] = !{i64 0, !"NtC[[CRATE_IDENT]]_28virtual_function_elimination1V"} -// CHECK: ![[VCALL_VIS2]] = !{i64 1} diff --git a/tests/codegen/vtable-loads.rs b/tests/codegen/vtable-loads.rs deleted file mode 100644 index aa103ec6f7c..00000000000 --- a/tests/codegen/vtable-loads.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ compile-flags: -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @loop_skips_vtable_load -#[no_mangle] -pub fn loop_skips_vtable_load(x: &dyn Fn()) { - // CHECK: load ptr, ptr %0{{.*}}, !invariant.load - // CHECK-NEXT: tail call void %1 - // CHECK-NOT: load ptr - x(); - for _ in 0..100 { - // CHECK: tail call void %1 - x(); - } -} diff --git a/tests/codegen/vtable-upcast.rs b/tests/codegen/vtable-upcast.rs deleted file mode 100644 index 9e13e8dd68a..00000000000 --- a/tests/codegen/vtable-upcast.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! This file tests that we correctly generate GEP instructions for vtable upcasting. -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 - -#![crate_type = "lib"] - -pub trait Base { - fn base(&self); -} - -pub trait A: Base { - fn a(&self); -} - -pub trait B: Base { - fn b(&self); -} - -pub trait Diamond: A + B { - fn diamond(&self); -} - -// CHECK-LABEL: upcast_a_to_base -#[no_mangle] -pub fn upcast_a_to_base(x: &dyn A) -> &dyn Base { - // Requires no adjustment, since its vtable is extended from `Base`. - - // CHECK: start: - // CHECK-NEXT: insertvalue - // CHECK-NEXT: insertvalue - // CHECK-NEXT: ret - x as &dyn Base -} - -// CHECK-LABEL: upcast_b_to_base -#[no_mangle] -pub fn upcast_b_to_base(x: &dyn B) -> &dyn Base { - // Requires no adjustment, since its vtable is extended from `Base`. - - // CHECK: start: - // CHECK-NEXT: insertvalue - // CHECK-NEXT: insertvalue - // CHECK-NEXT: ret - x as &dyn Base -} - -// CHECK-LABEL: upcast_diamond_to_a -#[no_mangle] -pub fn upcast_diamond_to_a(x: &dyn Diamond) -> &dyn A { - // Requires no adjustment, since its vtable is extended from `A` (as the first supertrait). - - // CHECK: start: - // CHECK-NEXT: insertvalue - // CHECK-NEXT: insertvalue - // CHECK-NEXT: ret - x as &dyn A -} - -// CHECK-LABEL: upcast_diamond_to_b -// CHECK-SAME: (ptr align {{[0-9]+}} [[DATA_PTR:%.+]], ptr align {{[0-9]+}} [[VTABLE_PTR:%.+]]) -#[no_mangle] -pub fn upcast_diamond_to_b(x: &dyn Diamond) -> &dyn B { - // Requires adjustment, since it's a non-first supertrait. - - // CHECK: start: - // CHECK-NEXT: [[UPCAST_SLOT_PTR:%.+]] = getelementptr inbounds i8, ptr [[VTABLE_PTR]] - // CHECK-NEXT: [[UPCAST_VTABLE_PTR:%.+]] = load ptr, ptr [[UPCAST_SLOT_PTR]] - // CHECK-NEXT: [[FAT_PTR_1:%.+]] = insertvalue { ptr, ptr } poison, ptr [[DATA_PTR]], 0 - // CHECK-NEXT: [[FAT_PTR_2:%.+]] = insertvalue { ptr, ptr } [[FAT_PTR_1]], ptr [[UPCAST_VTABLE_PTR]], 1 - // CHECK-NEXT: ret { ptr, ptr } [[FAT_PTR_2]] - x as &dyn B -} - -// CHECK-LABEL: upcast_diamond_to_b -#[no_mangle] -pub fn upcast_diamond_to_base(x: &dyn Diamond) -> &dyn Base { - // Requires no adjustment, since `Base` is the first supertrait of `A`, - // which is the first supertrait of `Diamond`. - - // CHECK: start: - // CHECK-NEXT: insertvalue - // CHECK-NEXT: insertvalue - // CHECK-NEXT: ret - x as &dyn Base -} diff --git a/tests/codegen/wasm_casts_trapping.rs b/tests/codegen/wasm_casts_trapping.rs deleted file mode 100644 index 0908acd85fc..00000000000 --- a/tests/codegen/wasm_casts_trapping.rs +++ /dev/null @@ -1,157 +0,0 @@ -//@ only-wasm32 -//@ compile-flags: -C target-feature=-nontrapping-fptoint -#![crate_type = "lib"] - -// CHECK-LABEL: @cast_f64_i64 -#[no_mangle] -pub fn cast_f64_i64(a: f64) -> i64 { - // CHECK-NOT: fptosi double {{.*}} to i64 - // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i64.f64{{.*}} - a as _ -} - -// CHECK-LABEL: @cast_f64_i32 -#[no_mangle] -pub fn cast_f64_i32(a: f64) -> i32 { - // CHECK-NOT: fptosi double {{.*}} to i32 - // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i32.f64{{.*}} - a as _ -} - -// CHECK-LABEL: @cast_f32_i64 -#[no_mangle] -pub fn cast_f32_i64(a: f32) -> i64 { - // CHECK-NOT: fptosi float {{.*}} to i64 - // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i64.f32{{.*}} - a as _ -} - -// CHECK-LABEL: @cast_f32_i32 -#[no_mangle] -pub fn cast_f32_i32(a: f32) -> i32 { - // CHECK-NOT: fptosi float {{.*}} to i32 - // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i32.f32{{.*}} - a as _ -} - -// CHECK-LABEL: @cast_f64_u64 -#[no_mangle] -pub fn cast_f64_u64(a: f64) -> u64 { - // CHECK-NOT: fptoui double {{.*}} to i64 - // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i64.f64{{.*}} - a as _ -} - -// CHECK-LABEL: @cast_f64_u32 -#[no_mangle] -pub fn cast_f64_u32(a: f64) -> u32 { - // CHECK-NOT: fptoui double {{.*}} to i32 - // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i32.f64{{.*}} - a as _ -} - -// CHECK-LABEL: @cast_f32_u64 -#[no_mangle] -pub fn cast_f32_u64(a: f32) -> u64 { - // CHECK-NOT: fptoui float {{.*}} to i64 - // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i64.f32{{.*}} - a as _ -} - -// CHECK-LABEL: @cast_f32_u32 -#[no_mangle] -pub fn cast_f32_u32(a: f32) -> u32 { - // CHECK-NOT: fptoui float {{.*}} to i32 - // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i32.f32{{.*}} - a as _ -} - -// CHECK-LABEL: @cast_f32_u8 -#[no_mangle] -pub fn cast_f32_u8(a: f32) -> u8 { - // CHECK-NOT: fptoui float {{.*}} to i8 - // CHECK-NOT: select i1 {{.*}}, i8 {{.*}}, i8 {{.*}} - // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i8.f32{{.*}} - a as _ -} - -// CHECK-LABEL: @cast_unchecked_f64_i64 -#[no_mangle] -pub unsafe fn cast_unchecked_f64_i64(a: f64) -> i64 { - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}} - // CHECK-NEXT: ret i64 {{.*}} - a.to_int_unchecked() -} - -// CHECK-LABEL: @cast_unchecked_f64_i32 -#[no_mangle] -pub unsafe fn cast_unchecked_f64_i32(a: f64) -> i32 { - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}} - // CHECK-NEXT: ret i32 {{.*}} - a.to_int_unchecked() -} - -// CHECK-LABEL: @cast_unchecked_f32_i64 -#[no_mangle] -pub unsafe fn cast_unchecked_f32_i64(a: f32) -> i64 { - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}} - // CHECK-NEXT: ret i64 {{.*}} - a.to_int_unchecked() -} - -// CHECK-LABEL: @cast_unchecked_f32_i32 -#[no_mangle] -pub unsafe fn cast_unchecked_f32_i32(a: f32) -> i32 { - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}} - // CHECK-NEXT: ret i32 {{.*}} - a.to_int_unchecked() -} - -// CHECK-LABEL: @cast_unchecked_f64_u64 -#[no_mangle] -pub unsafe fn cast_unchecked_f64_u64(a: f64) -> u64 { - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}} - // CHECK-NEXT: ret i64 {{.*}} - a.to_int_unchecked() -} - -// CHECK-LABEL: @cast_unchecked_f64_u32 -#[no_mangle] -pub unsafe fn cast_unchecked_f64_u32(a: f64) -> u32 { - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}} - // CHECK-NEXT: ret i32 {{.*}} - a.to_int_unchecked() -} - -// CHECK-LABEL: @cast_unchecked_f32_u64 -#[no_mangle] -pub unsafe fn cast_unchecked_f32_u64(a: f32) -> u64 { - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}} - // CHECK-NEXT: ret i64 {{.*}} - a.to_int_unchecked() -} - -// CHECK-LABEL: @cast_unchecked_f32_u32 -#[no_mangle] -pub unsafe fn cast_unchecked_f32_u32(a: f32) -> u32 { - // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}} - // CHECK-NEXT: ret i32 {{.*}} - a.to_int_unchecked() -} - -// CHECK-LABEL: @cast_unchecked_f32_u8 -#[no_mangle] -pub unsafe fn cast_unchecked_f32_u8(a: f32) -> u8 { - // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}} - // CHECK: fptoui float {{.*}} to i8 - // CHECK-NEXT: ret i8 {{.*}} - a.to_int_unchecked() -} diff --git a/tests/codegen/wasm_exceptions.rs b/tests/codegen/wasm_exceptions.rs deleted file mode 100644 index 07b8ae6e9d7..00000000000 --- a/tests/codegen/wasm_exceptions.rs +++ /dev/null @@ -1,59 +0,0 @@ -//@ only-wasm32 -//@ compile-flags: -C panic=unwind -Z emscripten-wasm-eh - -#![crate_type = "lib"] -#![feature(core_intrinsics)] - -extern "C-unwind" { - fn may_panic(); -} - -extern "C" { - fn log_number(number: usize); -} - -struct LogOnDrop; - -impl Drop for LogOnDrop { - fn drop(&mut self) { - unsafe { - log_number(0); - } - } -} - -// CHECK-LABEL: @test_cleanup() {{.*}} @__gxx_wasm_personality_v0 -#[no_mangle] -pub fn test_cleanup() { - let _log_on_drop = LogOnDrop; - unsafe { - may_panic(); - } - - // CHECK-NOT: call - // CHECK: invoke void @may_panic() - // CHECK: %cleanuppad = cleanuppad within none [] -} - -// CHECK-LABEL: @test_rtry() {{.*}} @__gxx_wasm_personality_v0 -#[no_mangle] -pub fn test_rtry() { - unsafe { - core::intrinsics::catch_unwind( - |_| { - may_panic(); - }, - core::ptr::null_mut(), - |data, exception| { - log_number(data as usize); - log_number(exception as usize); - }, - ); - } - - // CHECK-NOT: call - // CHECK: invoke void @may_panic() - // CHECK: {{.*}} = catchswitch within none [label {{.*}}] unwind to caller - // CHECK: {{.*}} = catchpad within {{.*}} [ptr null] - // CHECK: catchret -} diff --git a/tests/codegen/zip.rs b/tests/codegen/zip.rs deleted file mode 100644 index 38ecf7c15c6..00000000000 --- a/tests/codegen/zip.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ compile-flags: -Cno-prepopulate-passes -Copt-level=3 - -#![crate_type = "lib"] - -// CHECK-LABEL: @zip_copy -#[no_mangle] -pub fn zip_copy(xs: &[u8], ys: &mut [u8]) { - // CHECK: memcpy - for (x, y) in xs.iter().zip(ys) { - *y = *x; - } -} - -// CHECK-LABEL: @zip_copy_mapped -#[no_mangle] -pub fn zip_copy_mapped(xs: &[u8], ys: &mut [u8]) { - // CHECK: memcpy - for (x, y) in xs.iter().map(|&x| x).zip(ys) { - *y = x; - } -} diff --git a/tests/codegen/zst-offset.rs b/tests/codegen/zst-offset.rs deleted file mode 100644 index 475394a8815..00000000000 --- a/tests/codegen/zst-offset.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 - -#![crate_type = "lib"] -#![feature(repr_simd)] - -// Hack to get the correct size for the length part in slices -// CHECK: @helper([[USIZE:i[0-9]+]] %_1) -#[no_mangle] -pub fn helper(_: usize) {} - -// Check that we correctly generate a GEP for a ZST that is not included in Scalar layout -// CHECK-LABEL: @scalar_layout -#[no_mangle] -pub fn scalar_layout(s: &(u64, ())) { - // CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 8 - let x = &s.1; - witness(&x); // keep variable in an alloca -} - -// Check that we correctly generate a GEP for a ZST that is not included in ScalarPair layout -// CHECK-LABEL: @scalarpair_layout -#[no_mangle] -pub fn scalarpair_layout(s: &(u64, u32, ())) { - // CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 12 - let x = &s.2; - witness(&x); // keep variable in an alloca -} - -#[repr(simd)] -pub struct U64x4([u64; 4]); - -// Check that we correctly generate a GEP for a ZST that is not included in Vector layout -// CHECK-LABEL: @vector_layout -#[no_mangle] -pub fn vector_layout(s: &(U64x4, ())) { - // CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 32 - let x = &s.1; - witness(&x); // keep variable in an alloca -} - -#[inline(never)] -fn witness(_: &impl Sized) {} diff --git a/tests/run-make/llvm-ident/rmake.rs b/tests/run-make/llvm-ident/rmake.rs index 47e6fc4de15..b4d30ee7bfb 100644 --- a/tests/run-make/llvm-ident/rmake.rs +++ b/tests/run-make/llvm-ident/rmake.rs @@ -27,7 +27,7 @@ fn main() { // Check LLVM IR files (including temporary outputs) have `!llvm.ident` // named metadata, reusing the related codegen test. - let llvm_ident_path = source_root().join("tests/codegen/llvm-ident.rs"); + let llvm_ident_path = source_root().join("tests/codegen-llvm/llvm-ident.rs"); let files = shallow_find_files(".", |path| has_extension(path, "ll")); for file in files { llvm_filecheck().input_file(file).arg(&llvm_ident_path).run(); diff --git a/tests/ui/abi/fixed_x18.rs b/tests/ui/abi/fixed_x18.rs index 09d16303033..baf215ba903 100644 --- a/tests/ui/abi/fixed_x18.rs +++ b/tests/ui/abi/fixed_x18.rs @@ -1,5 +1,5 @@ // This tests that -Zfixed-x18 causes a compilation failure on targets other than aarch64. -// Behavior on aarch64 is tested by tests/codegen/fixed-x18.rs. +// Behavior on aarch64 is tested by tests/codegen-llvm/fixed-x18.rs. // //@ revisions: x64 i686 arm riscv32 riscv64 //@ dont-check-compiler-stderr diff --git a/triagebot.toml b/triagebot.toml index e34e4a88f42..162e244c0ad 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -304,7 +304,7 @@ trigger_files = [ # Tests "tests/assembly-llvm", "tests/auxiliary", - "tests/codegen", + "tests/codegen-llvm", "tests/codegen-units", "tests/COMPILER_TESTS.md", "tests/coverage", @@ -558,10 +558,10 @@ trigger_files = [ "src/doc/unstable-book/src/language-features/cfg-sanitize.md", "src/doc/unstable-book/src/language-features/cfi-encoding.md", "src/doc/unstable-book/src/language-features/no-sanitize.md", - "tests/codegen/sanitizer", - "tests/codegen/split-lto-unit.rs", - "tests/codegen/stack-probes-inline.rs", - "tests/codegen/stack-protector.rs", + "tests/codegen-llvm/sanitizer", + "tests/codegen-llvm/split-lto-unit.rs", + "tests/codegen-llvm/stack-probes-inline.rs", + "tests/codegen-llvm/stack-protector.rs", "tests/ui/sanitizer", "tests/ui/stack-protector" ] @@ -1183,16 +1183,16 @@ cc = ["@Urgau"] [mentions."src/doc/rustc/src/platform-support"] cc = ["@Noratrieb"] -[mentions."tests/codegen/sanitizer"] +[mentions."tests/codegen-llvm/sanitizer"] cc = ["@rcvalle"] -[mentions."tests/codegen/split-lto-unit.rs"] +[mentions."tests/codegen-llvm/split-lto-unit.rs"] cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"] -[mentions."tests/codegen/stack-probes-inline.rs"] +[mentions."tests/codegen-llvm/stack-probes-inline.rs"] cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"] -[mentions."tests/codegen/stack-protector.rs"] +[mentions."tests/codegen-llvm/stack-protector.rs"] cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"] [mentions."tests/ui/sanitizer"] -- cgit 1.4.1-3-g733a5