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:
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user