Skip to content

Commit c42be79

Browse files
committed
Support repr(simd) on ADTs containing a single array field
This is the cg_clif half of rust PR 78863
1 parent 3563608 commit c42be79

File tree

3 files changed

+82
-23
lines changed

3 files changed

+82
-23
lines changed

src/intrinsics/mod.rs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,11 @@ fn simd_for_each_lane<'tcx>(
175175
assert_eq!(lane_count, ret_lane_count);
176176

177177
for lane_idx in 0..lane_count {
178-
let lane_idx = mir::Field::new(lane_idx.try_into().unwrap());
179-
let lane = val.value_field(fx, lane_idx).load_scalar(fx);
178+
let lane = val.value_lane(fx, lane_idx).load_scalar(fx);
180179

181180
let res_lane = f(fx, lane_layout, ret_lane_layout, lane);
182181

183-
ret.place_field(fx, lane_idx).write_cvalue(fx, res_lane);
182+
ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane);
184183
}
185184
}
186185

@@ -206,14 +205,13 @@ fn simd_pair_for_each_lane<'tcx>(
206205
let ret_lane_layout = fx.layout_of(ret_lane_ty);
207206
assert_eq!(lane_count, ret_lane_count);
208207

209-
for lane in 0..lane_count {
210-
let lane = mir::Field::new(lane.try_into().unwrap());
211-
let x_lane = x.value_field(fx, lane).load_scalar(fx);
212-
let y_lane = y.value_field(fx, lane).load_scalar(fx);
208+
for lane_idx in 0..lane_count {
209+
let x_lane = x.value_lane(fx, lane_idx).load_scalar(fx);
210+
let y_lane = y.value_lane(fx, lane_idx).load_scalar(fx);
213211

214212
let res_lane = f(fx, lane_layout, ret_lane_layout, x_lane, y_lane);
215213

216-
ret.place_field(fx, lane).write_cvalue(fx, res_lane);
214+
ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane);
217215
}
218216
}
219217

@@ -227,10 +225,9 @@ fn simd_reduce<'tcx>(
227225
let lane_layout = fx.layout_of(lane_ty);
228226
assert_eq!(lane_layout, ret.layout());
229227

230-
let mut res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx);
228+
let mut res_val = val.value_lane(fx, 0).load_scalar(fx);
231229
for lane_idx in 1..lane_count {
232-
let lane =
233-
val.value_field(fx, mir::Field::new(lane_idx.try_into().unwrap())).load_scalar(fx);
230+
let lane = val.value_lane(fx, lane_idx).load_scalar(fx);
234231
res_val = f(fx, lane_layout, res_val, lane);
235232
}
236233
let res = CValue::by_val(res_val, lane_layout);
@@ -246,11 +243,10 @@ fn simd_reduce_bool<'tcx>(
246243
let (lane_count, _lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
247244
assert!(ret.layout().ty.is_bool());
248245

249-
let res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx);
246+
let res_val = val.value_lane(fx, 0).load_scalar(fx);
250247
let mut res_val = fx.bcx.ins().band_imm(res_val, 1); // mask to boolean
251248
for lane_idx in 1..lane_count {
252-
let lane =
253-
val.value_field(fx, mir::Field::new(lane_idx.try_into().unwrap())).load_scalar(fx);
249+
let lane = val.value_lane(fx, lane_idx).load_scalar(fx);
254250
let lane = fx.bcx.ins().band_imm(lane, 1); // mask to boolean
255251
res_val = f(fx, res_val, lane);
256252
}

src/intrinsics/simd.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,11 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
108108

109109
for (out_idx, in_idx) in indexes.into_iter().enumerate() {
110110
let in_lane = if u64::from(in_idx) < lane_count {
111-
x.value_field(fx, mir::Field::new(in_idx.into()))
111+
x.value_lane(fx, in_idx.into())
112112
} else {
113-
y.value_field(fx, mir::Field::new(usize::from(in_idx) - usize::try_from(lane_count).unwrap()))
113+
y.value_lane(fx, u64::from(in_idx) - lane_count)
114114
};
115-
let out_lane = ret.place_field(fx, mir::Field::new(out_idx));
115+
let out_lane = ret.place_lane(fx, u64::try_from(out_idx).unwrap());
116116
out_lane.write_cvalue(fx, in_lane);
117117
}
118118
};
@@ -163,7 +163,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
163163
fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count));
164164
}
165165

166-
let ret_lane = v.value_field(fx, mir::Field::new(idx.try_into().unwrap()));
166+
let ret_lane = v.value_lane(fx, idx.try_into().unwrap());
167167
ret.write_cvalue(fx, ret_lane);
168168
};
169169

@@ -216,15 +216,14 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
216216
let ret_lane_layout = fx.layout_of(ret_lane_ty);
217217

218218
for lane in 0..lane_count {
219-
let lane = mir::Field::new(lane.try_into().unwrap());
220-
let a_lane = a.value_field(fx, lane).load_scalar(fx);
221-
let b_lane = b.value_field(fx, lane).load_scalar(fx);
222-
let c_lane = c.value_field(fx, lane).load_scalar(fx);
219+
let a_lane = a.value_lane(fx, lane).load_scalar(fx);
220+
let b_lane = b.value_lane(fx, lane).load_scalar(fx);
221+
let c_lane = c.value_lane(fx, lane).load_scalar(fx);
223222

224223
let mul_lane = fx.bcx.ins().fmul(a_lane, b_lane);
225224
let res_lane = CValue::by_val(fx.bcx.ins().fadd(mul_lane, c_lane), ret_lane_layout);
226225

227-
ret.place_field(fx, lane).write_cvalue(fx, res_lane);
226+
ret.place_lane(fx, lane).write_cvalue(fx, res_lane);
228227
}
229228
};
230229

src/value_and_place.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,38 @@ impl<'tcx> CValue<'tcx> {
206206
}
207207
}
208208

209+
/// Like [`CValue::value_field`] except handling ADTs containing a single array field in a way
210+
/// such that you can access individual lanes.
211+
pub(crate) fn value_lane(
212+
self,
213+
fx: &mut FunctionCx<'_, '_, 'tcx>,
214+
lane_idx: u64,
215+
) -> CValue<'tcx> {
216+
let layout = self.1;
217+
assert!(layout.ty.is_simd());
218+
let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
219+
let lane_layout = fx.layout_of(lane_ty);
220+
assert!(lane_idx < lane_count);
221+
match self.0 {
222+
CValueInner::ByVal(val) => match layout.abi {
223+
Abi::Vector { element: _, count: _ } => {
224+
assert!(lane_count <= u8::MAX.into(), "SIMD type with more than 255 lanes???");
225+
let lane_idx = u8::try_from(lane_idx).unwrap();
226+
let lane = fx.bcx.ins().extractlane(val, lane_idx);
227+
CValue::by_val(lane, lane_layout)
228+
}
229+
_ => unreachable!("value_lane for ByVal with abi {:?}", layout.abi),
230+
},
231+
CValueInner::ByValPair(_, _) => unreachable!(),
232+
CValueInner::ByRef(ptr, None) => {
233+
let field_offset = lane_layout.size * lane_idx;
234+
let field_ptr = ptr.offset_i64(fx, i64::try_from(field_offset.bytes()).unwrap());
235+
CValue::by_ref(field_ptr, lane_layout)
236+
}
237+
CValueInner::ByRef(_, Some(_)) => unreachable!(),
238+
}
239+
}
240+
209241
pub(crate) fn unsize_value(self, fx: &mut FunctionCx<'_, '_, 'tcx>, dest: CPlace<'tcx>) {
210242
crate::unsize::coerce_unsized_into(fx, self, dest);
211243
}
@@ -610,6 +642,38 @@ impl<'tcx> CPlace<'tcx> {
610642
}
611643
}
612644

645+
/// Like [`CPlace::place_field`] except handling ADTs containing a single array field in a way
646+
/// such that you can access individual lanes.
647+
pub(crate) fn place_lane(
648+
self,
649+
fx: &mut FunctionCx<'_, '_, 'tcx>,
650+
lane_idx: u64,
651+
) -> CPlace<'tcx> {
652+
let layout = self.layout();
653+
assert!(layout.ty.is_simd());
654+
let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
655+
let lane_layout = fx.layout_of(lane_ty);
656+
assert!(lane_idx < lane_count);
657+
658+
match self.inner {
659+
CPlaceInner::Var(local, var) => {
660+
assert!(matches!(layout.abi, Abi::Vector { .. }));
661+
CPlace {
662+
inner: CPlaceInner::VarLane(local, var, lane_idx.try_into().unwrap()),
663+
layout: lane_layout,
664+
}
665+
}
666+
CPlaceInner::VarPair(_, _, _) => unreachable!(),
667+
CPlaceInner::VarLane(_, _, _) => unreachable!(),
668+
CPlaceInner::Addr(ptr, None) => {
669+
let field_offset = lane_layout.size * lane_idx;
670+
let field_ptr = ptr.offset_i64(fx, i64::try_from(field_offset.bytes()).unwrap());
671+
CPlace::for_ptr(field_ptr, lane_layout)
672+
}
673+
CPlaceInner::Addr(_, Some(_)) => unreachable!(),
674+
}
675+
}
676+
613677
pub(crate) fn place_index(
614678
self,
615679
fx: &mut FunctionCx<'_, '_, 'tcx>,

0 commit comments

Comments
 (0)