Scalar values in vectorizelanes & extractlanes (#3922)

- `extractlanes` will now function on a scalar value, returning the
value as a single-element array.
- `vectorizelanes` will accept a single-element array, returning the
contained value.

Existing `if !x.is_vector()` code-patterns have been simplified as a
result.

Copyright (c) 2022 Arm Limited
This commit is contained in:
Damian Heaton
2022-03-28 17:32:59 +01:00
committed by GitHub
parent 105163cc15
commit 6c8c94723a

View File

@@ -546,7 +546,6 @@ where
Opcode::Iabs => { Opcode::Iabs => {
let (min_val, _) = ctrl_ty.lane_type().bounds(true); let (min_val, _) = ctrl_ty.lane_type().bounds(true);
let min_val: V = Value::int(min_val as i128, ctrl_ty.lane_type())?; let min_val: V = Value::int(min_val as i128, ctrl_ty.lane_type())?;
if ctrl_ty.is_vector() {
let arg0 = extractlanes(&arg(0)?, ctrl_ty.lane_type())?; let arg0 = extractlanes(&arg(0)?, ctrl_ty.lane_type())?;
let new_vec = arg0 let new_vec = arg0
.into_iter() .into_iter()
@@ -559,13 +558,6 @@ where
}) })
.collect::<ValueResult<SimdVec<V>>>()?; .collect::<ValueResult<SimdVec<V>>>()?;
assign(vectorizelanes(&new_vec, ctrl_ty)?) assign(vectorizelanes(&new_vec, ctrl_ty)?)
} else {
assign(if Value::eq(&arg(0)?, &min_val)? {
min_val.clone()
} else {
Value::int(arg(0)?.into_int()?.abs(), ctrl_ty.lane_type())?
})
}
} }
Opcode::Imul => binary(Value::mul, arg(0)?, arg(1)?)?, Opcode::Imul => binary(Value::mul, arg(0)?, arg(1)?)?,
Opcode::Umulhi | Opcode::Smulhi => { Opcode::Umulhi | Opcode::Smulhi => {
@@ -581,7 +573,6 @@ where
} else { } else {
ValueConversionKind::SignExtend(double_length) ValueConversionKind::SignExtend(double_length)
}; };
if ctrl_ty.is_vector() {
let arg0 = extractlanes(&arg(0)?, ctrl_ty.lane_type())?; let arg0 = extractlanes(&arg(0)?, ctrl_ty.lane_type())?;
let arg1 = extractlanes(&arg(1)?, ctrl_ty.lane_type())?; let arg1 = extractlanes(&arg(1)?, ctrl_ty.lane_type())?;
@@ -598,12 +589,6 @@ where
.collect::<ValueResult<SimdVec<V>>>()?; .collect::<ValueResult<SimdVec<V>>>()?;
assign(vectorizelanes(&res, ctrl_ty)?) assign(vectorizelanes(&res, ctrl_ty)?)
} else {
let x: V = arg(0)?.convert(conv_type.clone())?;
let y: V = arg(1)?.convert(conv_type.clone())?;
let z = Value::mul(x, y)?.convert(ValueConversionKind::ExtractUpper(ctrl_ty))?;
assign(z)
}
} }
Opcode::Udiv => binary_unsigned_can_trap(Value::div, arg(0)?, arg(1)?)?, Opcode::Udiv => binary_unsigned_can_trap(Value::div, arg(0)?, arg(1)?)?,
Opcode::Sdiv => binary_can_trap(Value::div, arg(0)?, arg(1)?)?, Opcode::Sdiv => binary_can_trap(Value::div, arg(0)?, arg(1)?)?,
@@ -813,15 +798,11 @@ where
Opcode::Bmask => assign({ Opcode::Bmask => assign({
let bool = arg(0)?; let bool = arg(0)?;
let bool_ty = ctrl_ty.as_bool_pedantic(); let bool_ty = ctrl_ty.as_bool_pedantic();
if ctrl_ty.is_vector() {
let lanes = extractlanes(&bool, bool_ty.lane_type())? let lanes = extractlanes(&bool, bool_ty.lane_type())?
.into_iter() .into_iter()
.map(|lane| lane.convert(ValueConversionKind::Exact(ctrl_ty.lane_type()))) .map(|lane| lane.convert(ValueConversionKind::Exact(ctrl_ty.lane_type())))
.collect::<ValueResult<SimdVec<V>>>()?; .collect::<ValueResult<SimdVec<V>>>()?;
vectorizelanes(&lanes, ctrl_ty)? vectorizelanes(&lanes, ctrl_ty)?
} else {
bool.convert(ValueConversionKind::Exact(ctrl_ty))?
}
}), }),
Opcode::Sextend => assign(Value::convert( Opcode::Sextend => assign(Value::convert(
arg(0)?, arg(0)?,
@@ -1126,7 +1107,6 @@ where
}; };
let dst_ty = ctrl_ty.as_bool(); let dst_ty = ctrl_ty.as_bool();
Ok(if ctrl_ty.is_vector() {
let lane_type = ctrl_ty.lane_type(); let lane_type = ctrl_ty.lane_type();
let left = extractlanes(left, lane_type)?; let left = extractlanes(left, lane_type)?;
let right = extractlanes(right, lane_type)?; let right = extractlanes(right, lane_type)?;
@@ -1137,10 +1117,7 @@ where
.map(|(l, r)| cmp(dst_ty.lane_type(), code, &l, &r)) .map(|(l, r)| cmp(dst_ty.lane_type(), code, &l, &r))
.collect::<ValueResult<SimdVec<V>>>()?; .collect::<ValueResult<SimdVec<V>>>()?;
vectorizelanes(&res, dst_ty)? Ok(vectorizelanes(&res, dst_ty)?)
} else {
cmp(dst_ty, code, left, right)?
})
} }
/// Compare two values using the given floating point condition `code`. /// Compare two values using the given floating point condition `code`.
@@ -1177,10 +1154,18 @@ where
type SimdVec<V> = SmallVec<[V; 4]>; type SimdVec<V> = SmallVec<[V; 4]>;
/// Converts a SIMD vector value into a Rust array of [Value] for processing. /// Converts a SIMD vector value into a Rust array of [Value] for processing.
/// If `x` is a scalar, it will be returned as a single-element array.
fn extractlanes<V>(x: &V, lane_type: types::Type) -> ValueResult<SimdVec<V>> fn extractlanes<V>(x: &V, lane_type: types::Type) -> ValueResult<SimdVec<V>>
where where
V: Value, V: Value,
{ {
let mut lanes = SimdVec::new();
// Wrap scalar values as a single-element vector and return.
if !x.ty().is_vector() {
lanes.push(x.clone());
return Ok(lanes);
}
let iterations = match lane_type { let iterations = match lane_type {
types::I8 | types::B1 | types::B8 => 1, types::I8 | types::B1 | types::B8 => 1,
types::I16 | types::B16 => 2, types::I16 | types::B16 => 2,
@@ -1190,7 +1175,6 @@ where
}; };
let x = x.into_array()?; let x = x.into_array()?;
let mut lanes = SimdVec::new();
for (i, _) in x.iter().enumerate() { for (i, _) in x.iter().enumerate() {
let mut lane: i128 = 0; let mut lane: i128 = 0;
if i % iterations != 0 { if i % iterations != 0 {
@@ -1210,11 +1194,17 @@ where
return Ok(lanes); return Ok(lanes);
} }
/// Convert a Rust array of i128s back into a `Value::vector`. /// Convert a Rust array of [Value] back into a `Value::vector`.
/// Supplying a single-element array will simply return its contained value.
fn vectorizelanes<V>(x: &[V], vector_type: types::Type) -> ValueResult<V> fn vectorizelanes<V>(x: &[V], vector_type: types::Type) -> ValueResult<V>
where where
V: Value, V: Value,
{ {
// If the array is only one element, return it as a scalar.
if x.len() == 1 {
return Ok(x[0].clone());
}
let lane_type = vector_type.lane_type(); let lane_type = vector_type.lane_type();
let iterations = match lane_type { let iterations = match lane_type {
types::I8 | types::B1 | types::B8 => 1, types::I8 | types::B1 | types::B8 => 1,