Skip to content

Commit 81d219a

Browse files
committed
Auto merge of #115933 - oli-obk:simd_shuffle_const, r=workingjubilee
Prototype using const generic for simd_shuffle IDX array cc #85229 r? `@workingjubilee` on the design TLDR: there is now a `fn simd_shuffle_generic<T, U, const IDX: &'static [u32]>(x: T, y: T) -> U;` intrinsic that allows replacing ```rust simd_shuffle(a, b, const { stuff }) ``` with ```rust simd_shuffle_generic::<_, _, {&stuff}>(a, b) ``` which makes the compiler implementations much simpler, if we manage to at some point eliminate `simd_shuffle`. There are some issues with this today though (can't do math without bubbling it up in the generic arguments). With this change, we can start porting the simple cases and get better data on the others.
2 parents 809cd20 + 6fd5dc8 commit 81d219a

File tree

1 file changed

+49
-1
lines changed

1 file changed

+49
-1
lines changed

Diff for: src/intrinsics/simd.rs

+49-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ fn report_simd_type_validation_error(
2121
pub(super) fn codegen_simd_intrinsic_call<'tcx>(
2222
fx: &mut FunctionCx<'_, '_, 'tcx>,
2323
intrinsic: Symbol,
24-
_args: GenericArgsRef<'tcx>,
24+
generic_args: GenericArgsRef<'tcx>,
2525
args: &[mir::Operand<'tcx>],
2626
ret: CPlace<'tcx>,
2727
target: BasicBlock,
@@ -117,6 +117,54 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
117117
});
118118
}
119119

120+
// simd_shuffle_generic<T, U, const I: &[u32]>(x: T, y: T) -> U
121+
sym::simd_shuffle_generic => {
122+
let [x, y] = args else {
123+
bug!("wrong number of args for intrinsic {intrinsic}");
124+
};
125+
let x = codegen_operand(fx, x);
126+
let y = codegen_operand(fx, y);
127+
128+
if !x.layout().ty.is_simd() {
129+
report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty);
130+
return;
131+
}
132+
133+
let idx = generic_args[2]
134+
.expect_const()
135+
.eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(span))
136+
.unwrap()
137+
.unwrap_branch();
138+
139+
assert_eq!(x.layout(), y.layout());
140+
let layout = x.layout();
141+
142+
let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
143+
let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
144+
145+
assert_eq!(lane_ty, ret_lane_ty);
146+
assert_eq!(idx.len() as u64, ret_lane_count);
147+
148+
let total_len = lane_count * 2;
149+
150+
let indexes =
151+
idx.iter().map(|idx| idx.unwrap_leaf().try_to_u16().unwrap()).collect::<Vec<u16>>();
152+
153+
for &idx in &indexes {
154+
assert!(u64::from(idx) < total_len, "idx {} out of range 0..{}", idx, total_len);
155+
}
156+
157+
for (out_idx, in_idx) in indexes.into_iter().enumerate() {
158+
let in_lane = if u64::from(in_idx) < lane_count {
159+
x.value_lane(fx, in_idx.into())
160+
} else {
161+
y.value_lane(fx, u64::from(in_idx) - lane_count)
162+
};
163+
let out_lane = ret.place_lane(fx, u64::try_from(out_idx).unwrap());
164+
out_lane.write_cvalue(fx, in_lane);
165+
}
166+
}
167+
120168
// simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U
121169
sym::simd_shuffle => {
122170
let (x, y, idx) = match args {

0 commit comments

Comments
 (0)