Skip to content

Commit c1444a0

Browse files
committed
preseve SIMD element type information
and provide it to LLVM for better optimization
1 parent c753cef commit c1444a0

15 files changed

Lines changed: 261 additions & 25 deletions

File tree

compiler/rustc_abi/src/callconv.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{BackendRepr, FieldsShape, Primitive, Size, TyAbiInterface, TyAndLayo
33

44
mod reg;
55

6-
pub use reg::{Reg, RegKind};
6+
pub use reg::{Reg, RegKind, VectorElemKind};
77

88
/// Return value from the `homogeneous_aggregate` test function.
99
#[derive(Copy, Clone, Debug)]
@@ -75,10 +75,30 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
7575
Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
7676
}
7777

78-
BackendRepr::SimdVector { .. } => {
78+
BackendRepr::SimdVector { element, count: _ } => {
7979
assert!(!self.is_zst());
80+
81+
let hint_vector_elem = match element.primitive() {
82+
Primitive::Int(integer, _) => match integer.size().bits() {
83+
8 => VectorElemKind::I8,
84+
16 => VectorElemKind::I16,
85+
32 => VectorElemKind::I32,
86+
64 => VectorElemKind::I64,
87+
128 => VectorElemKind::I128,
88+
bits => panic!("unsupported vector integer element size: {bits}"),
89+
},
90+
Primitive::Float(float) => match float.size().bits() {
91+
16 => VectorElemKind::F16,
92+
32 => VectorElemKind::F32,
93+
64 => VectorElemKind::F64,
94+
128 => VectorElemKind::F128,
95+
bits => panic!("unsupported vector float element size: {bits}"),
96+
},
97+
Primitive::Pointer(_) => VectorElemKind::Ptr,
98+
};
99+
80100
Ok(HomogeneousAggregate::Homogeneous(Reg {
81-
kind: RegKind::Vector,
101+
kind: RegKind::Vector { hint_vector_elem },
82102
size: self.size,
83103
}))
84104
}

compiler/rustc_abi/src/callconv/reg.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,38 @@ use rustc_macros::HashStable_Generic;
33

44
use crate::{Align, HasDataLayout, Size};
55

6+
/// The element kind of a vector type. This is used to generate a more accurate vector type in
7+
/// the backend, and not relevant for the ABI.
8+
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
9+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
10+
pub enum VectorElemKind {
11+
I8,
12+
I16,
13+
I32,
14+
I64,
15+
I128,
16+
17+
F16,
18+
F32,
19+
F64,
20+
F128,
21+
22+
Ptr,
23+
}
24+
625
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
726
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
827
pub enum RegKind {
928
Integer,
1029
Float,
11-
Vector,
30+
Vector {
31+
/// The `hint_vector_elem` is strictly for optimization purposes and can be safely ignored (e.g.
32+
/// by always picking i8) by codegen backends.
33+
///
34+
/// The element kind is used to provide more accurate type information to the backend, which
35+
/// helps with optimization (e.g. because it prevents extra bitcasts that obscure a pattern).
36+
hint_vector_elem: VectorElemKind,
37+
},
1238
}
1339

1440
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
@@ -36,6 +62,11 @@ impl Reg {
3662
reg_ctor!(f32, Float, 32);
3763
reg_ctor!(f64, Float, 64);
3864
reg_ctor!(f128, Float, 128);
65+
66+
/// A vector of the given size with an unknown (and irrelevant) element type.
67+
pub fn opaque_vector(size: Size) -> Reg {
68+
Reg { kind: RegKind::Vector { hint_vector_elem: VectorElemKind::I8 }, size }
69+
}
3970
}
4071

4172
impl Reg {
@@ -58,7 +89,7 @@ impl Reg {
5889
128 => dl.f128_align,
5990
_ => panic!("unsupported float: {self:?}"),
6091
},
61-
RegKind::Vector => dl.llvmlike_vector_align(self.size),
92+
RegKind::Vector { .. } => dl.llvmlike_vector_align(self.size),
6293
}
6394
}
6495
}

compiler/rustc_abi/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ mod layout;
5858
#[cfg(test)]
5959
mod tests;
6060

61-
pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind};
61+
pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind, VectorElemKind};
6262
pub use canon_abi::{ArmCall, CanonAbi, InterruptKind, X86Call};
6363
#[cfg(feature = "nightly")]
6464
pub use extern_abi::CVariadicStatus;

compiler/rustc_codegen_llvm/src/abi.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::cmp;
33
use libc::c_uint;
44
use rustc_abi::{
55
ArmCall, BackendRepr, CanonAbi, HasDataLayout, InterruptKind, Primitive, Reg, RegKind, Size,
6-
X86Call,
6+
VectorElemKind, X86Call,
77
};
88
use rustc_codegen_ssa::MemFlags;
99
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
@@ -137,7 +137,27 @@ impl LlvmType for Reg {
137137
128 => cx.type_f128(),
138138
_ => bug!("unsupported float: {:?}", self),
139139
},
140-
RegKind::Vector => cx.type_vector(cx.type_i8(), self.size.bytes()),
140+
RegKind::Vector { hint_vector_elem } => {
141+
// NOTE: it is valid to ignore the element type hint (and always pick i8).
142+
// But providing a more accurate type means fewer casts in LLVM IR,
143+
// which helps with optimization.
144+
let (ty, bytes) = match hint_vector_elem {
145+
VectorElemKind::I8 => (cx.type_ix(8), 1),
146+
VectorElemKind::I16 => (cx.type_ix(16), 2),
147+
VectorElemKind::I32 => (cx.type_ix(32), 4),
148+
VectorElemKind::I64 => (cx.type_ix(64), 8),
149+
VectorElemKind::I128 => (cx.type_ix(128), 16),
150+
VectorElemKind::F16 => (cx.type_f16(), 2),
151+
VectorElemKind::F32 => (cx.type_f32(), 4),
152+
VectorElemKind::F64 => (cx.type_f64(), 8),
153+
VectorElemKind::F128 => (cx.type_f128(), 16),
154+
VectorElemKind::Ptr => {
155+
(cx.type_ptr(), cx.tcx.data_layout.pointer_size().bytes())
156+
}
157+
};
158+
159+
cx.type_vector(ty, self.size.bytes() / bytes)
160+
}
141161
}
142162
}
143163
}

compiler/rustc_codegen_ssa/src/mir/naked_asm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ fn wasm_type<'tcx>(signature: &mut String, arg_abi: &ArgAbi<'_, Ty<'tcx>>, ptr_t
416416
..=8 => "f64",
417417
_ => ptr_type,
418418
},
419-
RegKind::Vector => "v128",
419+
RegKind::Vector { .. } => "v128",
420420
};
421421

422422
signature.push_str(wrapped_wasm_type);

compiler/rustc_monomorphize/src/mono_checks/abi_check.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@ fn passes_vectors_by_value(mode: &PassMode, repr: &BackendRepr) -> UsesVectorReg
2525
match mode {
2626
PassMode::Ignore | PassMode::Indirect { .. } => UsesVectorRegisters::No,
2727
PassMode::Cast { pad_i32: _, cast }
28-
if cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector))
29-
|| cast.rest.unit.kind == RegKind::Vector =>
28+
if cast
29+
.prefix
30+
.iter()
31+
.any(|r| r.is_some_and(|x| matches!(x.kind, RegKind::Vector { .. })))
32+
|| matches!(cast.rest.unit.kind, RegKind::Vector { .. }) =>
3033
{
3134
UsesVectorRegisters::FixedVector
3235
}

compiler/rustc_target/src/callconv/aarch64.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ where
3535
// The softfloat ABI treats floats like integers, so they
3636
// do not get homogeneous aggregate treatment.
3737
RegKind::Float => cx.target_spec().rustc_abi != Some(RustcAbi::Softfloat),
38-
RegKind::Vector => size.bits() == 64 || size.bits() == 128,
38+
RegKind::Vector { .. } => size.bits() == 64 || size.bits() == 128,
3939
};
4040

4141
valid_unit.then_some(Uniform::consecutive(unit, size))

compiler/rustc_target/src/callconv/arm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ where
1919
let valid_unit = match unit.kind {
2020
RegKind::Integer => false,
2121
RegKind::Float => true,
22-
RegKind::Vector => size.bits() == 64 || size.bits() == 128,
22+
RegKind::Vector { .. } => size.bits() == 64 || size.bits() == 128,
2323
};
2424

2525
valid_unit.then_some(Uniform::consecutive(unit, size))

compiler/rustc_target/src/callconv/powerpc64.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ where
3636
let valid_unit = match unit.kind {
3737
RegKind::Integer => false,
3838
RegKind::Float => true,
39-
RegKind::Vector => arg.layout.size.bits() == 128,
39+
RegKind::Vector { .. } => arg.layout.size.bits() == 128,
4040
};
4141

4242
valid_unit.then_some(Uniform::consecutive(unit, arg.layout.size))

compiler/rustc_target/src/callconv/s390x.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use rustc_abi::{BackendRepr, HasDataLayout, TyAbiInterface};
55

6-
use crate::callconv::{ArgAbi, FnAbi, Reg, RegKind};
6+
use crate::callconv::{ArgAbi, FnAbi, Reg};
77
use crate::spec::{Env, HasTargetSpec, Os};
88

99
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
@@ -51,7 +51,7 @@ where
5151

5252
if arg.layout.is_single_vector_element(cx, size) {
5353
// pass non-transparent wrappers around a vector as `PassMode::Cast`
54-
arg.cast_to(Reg { kind: RegKind::Vector, size });
54+
arg.cast_to(Reg::opaque_vector(size));
5555
return;
5656
}
5757
}

0 commit comments

Comments
 (0)