Skip to content

Commit ff07a31

Browse files
authored
Unrolled build for #155106
Rollup merge of #155106 - davidtwco:scalable-vector-more-simd-intrinsics, r=Amanieu cg_llvm: scalable vectors with `simd_cast` and `simd_select` Previously `sve_cast`'s implementation was abstracted to power both `sve_cast` and `simd_cast` which supported scalable and non-scalable vectors respectively. In anticipation of having to do this for another `simd_*` intrinsic, `sve_cast` is removed and `simd_cast` is changed to accept both scalable and non-scalable intrinsics, an approach that will scale better to the other intrinsics. Building on the previous change, support scalable vectors with `simd_select`. Previous patches already landed the necessary changes in the implementation of this intrinsic, but didn't allow scalable vector arguments to be passed in.
2 parents 14196db + 62ffc89 commit ff07a31

File tree

6 files changed

+181
-134
lines changed

6 files changed

+181
-134
lines changed

compiler/rustc_abi/src/lib.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ use bitflags::bitflags;
4747
#[cfg(feature = "nightly")]
4848
use rustc_data_structures::stable_hasher::StableOrd;
4949
#[cfg(feature = "nightly")]
50+
use rustc_error_messages::{DiagArgValue, IntoDiagArg};
51+
#[cfg(feature = "nightly")]
5052
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, msg};
5153
use rustc_hashes::Hash64;
5254
use rustc_index::{Idx, IndexSlice, IndexVec};
@@ -1775,6 +1777,24 @@ impl NumScalableVectors {
17751777
}
17761778
}
17771779

1780+
#[cfg(feature = "nightly")]
1781+
impl IntoDiagArg for NumScalableVectors {
1782+
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
1783+
DiagArgValue::Str(std::borrow::Cow::Borrowed(match self.0 {
1784+
0 => panic!("`NumScalableVectors(0)` is illformed"),
1785+
1 => "one",
1786+
2 => "two",
1787+
3 => "three",
1788+
4 => "four",
1789+
5 => "five",
1790+
6 => "six",
1791+
7 => "seven",
1792+
8 => "eight",
1793+
_ => panic!("`NumScalableVectors(N)` for N>8 is illformed"),
1794+
}))
1795+
}
1796+
}
1797+
17781798
/// The way we represent values to the backend
17791799
///
17801800
/// Previously this was conflated with the "ABI" a type is given, as in the platform-specific ABI.

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 125 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -606,27 +606,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
606606
self.pointercast(val, self.type_ptr())
607607
}
608608

609-
sym::sve_cast => {
610-
let Some((in_cnt, in_elem, in_num_vecs)) =
611-
args[0].layout.ty.scalable_vector_parts(self.cx.tcx)
612-
else {
613-
bug!("input parameter to `sve_cast` was not scalable vector");
614-
};
615-
let out_layout = self.layout_of(fn_args.type_at(1));
616-
let Some((out_cnt, out_elem, out_num_vecs)) =
617-
out_layout.ty.scalable_vector_parts(self.cx.tcx)
618-
else {
619-
bug!("output parameter to `sve_cast` was not scalable vector");
620-
};
621-
assert_eq!(in_cnt, out_cnt);
622-
assert_eq!(in_num_vecs, out_num_vecs);
623-
let out_llty = self.backend_type(out_layout);
624-
match simd_cast(self, sym::simd_cast, args, out_llty, in_elem, out_elem) {
625-
Some(val) => val,
626-
_ => bug!("could not cast scalable vectors"),
627-
}
628-
}
629-
630609
sym::sve_tuple_create2 => {
631610
assert_matches!(
632611
self.layout_of(fn_args.type_at(0)).backend_repr,
@@ -1668,6 +1647,23 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
16681647
}};
16691648
}
16701649

1650+
macro_rules! require_simd_or_scalable {
1651+
($ty: expr, $variant:ident) => {{
1652+
require!(
1653+
$ty.is_simd() || $ty.is_scalable_vector(),
1654+
InvalidMonomorphization::$variant { span, name, ty: $ty }
1655+
);
1656+
if $ty.is_simd() {
1657+
let (len, ty) = $ty.simd_size_and_type(bx.tcx());
1658+
(len, ty, None)
1659+
} else {
1660+
let (count, ty, num_vecs) =
1661+
$ty.scalable_vector_parts(bx.tcx()).expect("`is_scalable_vector` was wrong");
1662+
(count as u64, ty, Some(num_vecs))
1663+
}
1664+
}};
1665+
}
1666+
16711667
/// Returns the bitwidth of the `$ty` argument if it is an `Int` or `Uint` type.
16721668
macro_rules! require_int_or_uint_ty {
16731669
($ty: expr, $diag: expr) => {
@@ -1787,8 +1783,19 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
17871783
return Ok(splat);
17881784
}
17891785

1790-
// every intrinsic below takes a SIMD vector as its first argument
1791-
let (in_len, in_elem) = require_simd!(args[0].layout.ty, SimdInput);
1786+
let supports_scalable = match name {
1787+
sym::simd_cast | sym::simd_select => true,
1788+
_ => false,
1789+
};
1790+
1791+
// Every intrinsic below takes a SIMD vector as its first argument. Some intrinsics also accept
1792+
// scalable vectors. `require_simd_or_scalable` is used regardless as it'll do the right thing
1793+
// for non-scalable vectors, and an additional check to prohibit scalable vectors for those
1794+
// intrinsics that do not support them is added.
1795+
if !supports_scalable {
1796+
let _ = require_simd!(args[0].layout.ty, SimdInput);
1797+
}
1798+
let (in_len, in_elem, in_num_vecs) = require_simd_or_scalable!(args[0].layout.ty, SimdInput);
17921799
let in_ty = args[0].layout.ty;
17931800

17941801
let comparison = match name {
@@ -1977,7 +1984,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
19771984
if name == sym::simd_select {
19781985
let m_elem_ty = in_elem;
19791986
let m_len = in_len;
1980-
let (v_len, _) = require_simd!(args[1].layout.ty, SimdArgument);
1987+
let (v_len, _, _) = require_simd_or_scalable!(args[1].layout.ty, SimdArgument);
19811988
require!(
19821989
m_len == v_len,
19831990
InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
@@ -2781,7 +2788,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
27812788
}
27822789

27832790
if name == sym::simd_cast || name == sym::simd_as {
2784-
let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn);
2791+
let (out_len, out_elem, out_num_vecs) = require_simd_or_scalable!(ret_ty, SimdReturn);
27852792
require!(
27862793
in_len == out_len,
27872794
InvalidMonomorphization::ReturnLengthInputType {
@@ -2793,9 +2800,99 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
27932800
out_len
27942801
}
27952802
);
2796-
match simd_cast(bx, name, args, llret_ty, in_elem, out_elem) {
2797-
Some(val) => return Ok(val),
2798-
None => return_error!(InvalidMonomorphization::UnsupportedCast {
2803+
require!(
2804+
in_num_vecs == out_num_vecs,
2805+
InvalidMonomorphization::ReturnNumVecsInputType {
2806+
span,
2807+
name,
2808+
in_num_vecs: in_num_vecs.unwrap_or(NumScalableVectors(1)),
2809+
in_ty,
2810+
ret_ty,
2811+
out_num_vecs: out_num_vecs.unwrap_or(NumScalableVectors(1))
2812+
}
2813+
);
2814+
2815+
// Casting cares about nominal type, not just structural type
2816+
if in_elem == out_elem {
2817+
return Ok(args[0].immediate());
2818+
}
2819+
2820+
#[derive(Copy, Clone)]
2821+
enum Sign {
2822+
Unsigned,
2823+
Signed,
2824+
}
2825+
use Sign::*;
2826+
2827+
enum Style {
2828+
Float,
2829+
Int(Sign),
2830+
Unsupported,
2831+
}
2832+
2833+
let (in_style, in_width) = match in_elem.kind() {
2834+
// vectors of pointer-sized integers should've been
2835+
// disallowed before here, so this unwrap is safe.
2836+
ty::Int(i) => (
2837+
Style::Int(Signed),
2838+
i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
2839+
),
2840+
ty::Uint(u) => (
2841+
Style::Int(Unsigned),
2842+
u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
2843+
),
2844+
ty::Float(f) => (Style::Float, f.bit_width()),
2845+
_ => (Style::Unsupported, 0),
2846+
};
2847+
let (out_style, out_width) = match out_elem.kind() {
2848+
ty::Int(i) => (
2849+
Style::Int(Signed),
2850+
i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
2851+
),
2852+
ty::Uint(u) => (
2853+
Style::Int(Unsigned),
2854+
u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
2855+
),
2856+
ty::Float(f) => (Style::Float, f.bit_width()),
2857+
_ => (Style::Unsupported, 0),
2858+
};
2859+
2860+
match (in_style, out_style) {
2861+
(Style::Int(sign), Style::Int(_)) => {
2862+
return Ok(match in_width.cmp(&out_width) {
2863+
Ordering::Greater => bx.trunc(args[0].immediate(), llret_ty),
2864+
Ordering::Equal => args[0].immediate(),
2865+
Ordering::Less => match sign {
2866+
Sign::Signed => bx.sext(args[0].immediate(), llret_ty),
2867+
Sign::Unsigned => bx.zext(args[0].immediate(), llret_ty),
2868+
},
2869+
});
2870+
}
2871+
(Style::Int(Sign::Signed), Style::Float) => {
2872+
return Ok(bx.sitofp(args[0].immediate(), llret_ty));
2873+
}
2874+
(Style::Int(Sign::Unsigned), Style::Float) => {
2875+
return Ok(bx.uitofp(args[0].immediate(), llret_ty));
2876+
}
2877+
(Style::Float, Style::Int(sign)) => {
2878+
return Ok(match (sign, name == sym::simd_as) {
2879+
(Sign::Unsigned, false) => bx.fptoui(args[0].immediate(), llret_ty),
2880+
(Sign::Signed, false) => bx.fptosi(args[0].immediate(), llret_ty),
2881+
(_, true) => bx.cast_float_to_int(
2882+
matches!(sign, Sign::Signed),
2883+
args[0].immediate(),
2884+
llret_ty,
2885+
),
2886+
});
2887+
}
2888+
(Style::Float, Style::Float) => {
2889+
return Ok(match in_width.cmp(&out_width) {
2890+
Ordering::Greater => bx.fptrunc(args[0].immediate(), llret_ty),
2891+
Ordering::Equal => args[0].immediate(),
2892+
Ordering::Less => bx.fpext(args[0].immediate(), llret_ty),
2893+
});
2894+
}
2895+
_ => return_error!(InvalidMonomorphization::UnsupportedCast {
27992896
span,
28002897
name,
28012898
in_ty,
@@ -2977,86 +3074,3 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
29773074

29783075
span_bug!(span, "unknown SIMD intrinsic");
29793076
}
2980-
2981-
/// Implementation of `core::intrinsics::simd_cast`, re-used by `core::scalable::sve_cast`.
2982-
fn simd_cast<'ll, 'tcx>(
2983-
bx: &mut Builder<'_, 'll, 'tcx>,
2984-
name: Symbol,
2985-
args: &[OperandRef<'tcx, &'ll Value>],
2986-
llret_ty: &'ll Type,
2987-
in_elem: Ty<'tcx>,
2988-
out_elem: Ty<'tcx>,
2989-
) -> Option<&'ll Value> {
2990-
// Casting cares about nominal type, not just structural type
2991-
if in_elem == out_elem {
2992-
return Some(args[0].immediate());
2993-
}
2994-
2995-
#[derive(Copy, Clone)]
2996-
enum Sign {
2997-
Unsigned,
2998-
Signed,
2999-
}
3000-
use Sign::*;
3001-
3002-
enum Style {
3003-
Float,
3004-
Int(Sign),
3005-
Unsupported,
3006-
}
3007-
3008-
let (in_style, in_width) = match in_elem.kind() {
3009-
// vectors of pointer-sized integers should've been
3010-
// disallowed before here, so this unwrap is safe.
3011-
ty::Int(i) => (
3012-
Style::Int(Signed),
3013-
i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
3014-
),
3015-
ty::Uint(u) => (
3016-
Style::Int(Unsigned),
3017-
u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
3018-
),
3019-
ty::Float(f) => (Style::Float, f.bit_width()),
3020-
_ => (Style::Unsupported, 0),
3021-
};
3022-
let (out_style, out_width) = match out_elem.kind() {
3023-
ty::Int(i) => (
3024-
Style::Int(Signed),
3025-
i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
3026-
),
3027-
ty::Uint(u) => (
3028-
Style::Int(Unsigned),
3029-
u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
3030-
),
3031-
ty::Float(f) => (Style::Float, f.bit_width()),
3032-
_ => (Style::Unsupported, 0),
3033-
};
3034-
3035-
match (in_style, out_style) {
3036-
(Style::Int(sign), Style::Int(_)) => Some(match in_width.cmp(&out_width) {
3037-
Ordering::Greater => bx.trunc(args[0].immediate(), llret_ty),
3038-
Ordering::Equal => args[0].immediate(),
3039-
Ordering::Less => match sign {
3040-
Sign::Signed => bx.sext(args[0].immediate(), llret_ty),
3041-
Sign::Unsigned => bx.zext(args[0].immediate(), llret_ty),
3042-
},
3043-
}),
3044-
(Style::Int(Sign::Signed), Style::Float) => Some(bx.sitofp(args[0].immediate(), llret_ty)),
3045-
(Style::Int(Sign::Unsigned), Style::Float) => {
3046-
Some(bx.uitofp(args[0].immediate(), llret_ty))
3047-
}
3048-
(Style::Float, Style::Int(sign)) => Some(match (sign, name == sym::simd_as) {
3049-
(Sign::Unsigned, false) => bx.fptoui(args[0].immediate(), llret_ty),
3050-
(Sign::Signed, false) => bx.fptosi(args[0].immediate(), llret_ty),
3051-
(_, true) => {
3052-
bx.cast_float_to_int(matches!(sign, Sign::Signed), args[0].immediate(), llret_ty)
3053-
}
3054-
}),
3055-
(Style::Float, Style::Float) => Some(match in_width.cmp(&out_width) {
3056-
Ordering::Greater => bx.fptrunc(args[0].immediate(), llret_ty),
3057-
Ordering::Equal => args[0].immediate(),
3058-
Ordering::Less => bx.fpext(args[0].immediate(), llret_ty),
3059-
}),
3060-
_ => None,
3061-
}
3062-
}

compiler/rustc_codegen_ssa/src/errors.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::io::Error;
66
use std::path::{Path, PathBuf};
77
use std::process::ExitStatus;
88

9+
use rustc_abi::NumScalableVectors;
910
use rustc_errors::codes::*;
1011
use rustc_errors::{
1112
Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, IntoDiagArg,
@@ -809,6 +810,17 @@ pub enum InvalidMonomorphization<'tcx> {
809810
out_len: u64,
810811
},
811812

813+
#[diag("invalid monomorphization of `{$name}` intrinsic: expected return type with {$in_num_vecs} vectors (same as input type `{$in_ty}`), found `{$ret_ty}` with length {$out_num_vecs}", code = E0511)]
814+
ReturnNumVecsInputType {
815+
#[primary_span]
816+
span: Span,
817+
name: Symbol,
818+
in_num_vecs: NumScalableVectors,
819+
in_ty: Ty<'tcx>,
820+
ret_ty: Ty<'tcx>,
821+
out_num_vecs: NumScalableVectors,
822+
},
823+
812824
#[diag("invalid monomorphization of `{$name}` intrinsic: expected second argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}", code = E0511)]
813825
SecondArgumentLength {
814826
#[primary_span]

library/core/src/intrinsics/simd/scalable.rs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,6 @@
22
//!
33
//! In this module, a "vector" is any `#[rustc_scalable_vector]`-annotated type.
44
5-
/// Numerically casts a vector, elementwise.
6-
///
7-
/// `T` and `U` must be vectors of integers or floats, and must have the same length.
8-
///
9-
/// When casting floats to integers, the result is truncated. Out-of-bounds result lead to UB.
10-
/// When casting integers to floats, the result is rounded.
11-
/// Otherwise, truncates or extends the value, maintaining the sign for signed integers.
12-
///
13-
/// # Safety
14-
/// Casting from integer types is always safe.
15-
/// Casting between two float types is also always safe.
16-
///
17-
/// Casting floats to integers truncates, following the same rules as `to_int_unchecked`.
18-
/// Specifically, each element must:
19-
/// * Not be `NaN`
20-
/// * Not be infinite
21-
/// * Be representable in the return type, after truncating off its fractional part
22-
#[rustc_intrinsic]
23-
#[rustc_nounwind]
24-
pub unsafe fn sve_cast<T, U>(x: T) -> U;
25-
265
/// Create a tuple of two vectors.
276
///
287
/// `SVecTup` must be a scalable vector tuple (`#[rustc_scalable_vector]`) and `SVec` must be a

tests/ui/scalable-vectors/cast-intrinsic.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#![allow(incomplete_features, internal_features, improper_ctypes)]
55
#![feature(abi_unadjusted, core_intrinsics, link_llvm_intrinsics, rustc_attrs)]
66

7-
use std::intrinsics::simd::scalable::sve_cast;
7+
use std::intrinsics::simd::simd_cast;
88

99
#[derive(Copy, Clone)]
1010
#[rustc_scalable_vector(16)]
@@ -61,5 +61,5 @@ pub unsafe fn svld1sh_gather_s64offset_s64(
6161
offsets: svint64_t,
6262
) -> nxv2i16;
6363
}
64-
sve_cast(_svld1sh_gather_s64offset_s64(pg.sve_into(), base, offsets))
64+
simd_cast(_svld1sh_gather_s64offset_s64(pg.sve_into(), base, offsets))
6565
}

0 commit comments

Comments
 (0)