Remove the Cranelift vselect instruction (#5918)

* Remove the Cranelift `vselect` instruction

This instruction is documented as selecting lanes based on the "truthy"
value of the condition lane, but the current status of the
implementation of this instruction is:

* x64 - uses the high bit for `f32x4` and `f64x2` and otherwise uses the
  high bit of each byte doing a byte-wise lane select rather than
  whatever the controlling type is.

* AArch64 - this is the same as `bitselect` which is a bit-wise
  selection rather than a lane-wise selection.

* s390x - this is the same as AArch64, a bit-wise selection rather than
  lane-wise.

* interpreter - the interpreter implements the documented semantics of
  selecting based on "truthy" values.

Coupled with the status of the implementation is the fact that this
instruction is not used by WebAssembly SIMD today either. The only use
of this instruction in Cranelift is the nan-canonicalization pass. By
moving nan-canonicalization to `bitselect`, since that has the desired
semantics, there's no longer any need for `vselect`.

Given this situation this commit subsqeuently removes `vselect` and all
usage of it throughout Cranelift.

Closes #5917

* Review comments

* Bring back vselect opts as bitselect opts

* Clean up vselect usage in the interpreter

* Move bitcast in nan canonicalization

* Add a comment about float optimization
This commit is contained in:
Alex Crichton
2023-03-07 18:42:05 -06:00
committed by GitHub
parent fc45ccc125
commit 07518dfd36
14 changed files with 163 additions and 333 deletions

View File

@@ -218,6 +218,28 @@ macro_rules! binary_match {
};
}
macro_rules! bitop {
( $op:tt($arg1:expr, $arg2:expr) ) => {
Ok(match ($arg1, $arg2) {
(DataValue::I8(a), DataValue::I8(b)) => DataValue::I8(a $op b),
(DataValue::I16(a), DataValue::I16(b)) => DataValue::I16(a $op b),
(DataValue::I32(a), DataValue::I32(b)) => DataValue::I32(a $op b),
(DataValue::I64(a), DataValue::I64(b)) => DataValue::I64(a $op b),
(DataValue::I128(a), DataValue::I128(b)) => DataValue::I128(a $op b),
(DataValue::F32(a), DataValue::F32(b)) => DataValue::F32(a $op b),
(DataValue::F64(a), DataValue::F64(b)) => DataValue::F64(a $op b),
(DataValue::V128(a), DataValue::V128(b)) => {
let mut a2 = a.clone();
for (a, b) in a2.iter_mut().zip(b.iter()) {
*a = *a $op *b;
}
DataValue::V128(a2)
}
_ => unimplemented!(),
})
};
}
impl Value for DataValue {
fn ty(&self) -> Type {
self.ty()
@@ -686,19 +708,35 @@ impl Value for DataValue {
}
fn and(self, other: Self) -> ValueResult<Self> {
binary_match!(&(self, other); [I8, I16, I32, I64, I128, F32, F64])
bitop!(&(self, other))
}
fn or(self, other: Self) -> ValueResult<Self> {
binary_match!(|(self, other); [I8, I16, I32, I64, I128, F32, F64])
bitop!(|(self, other))
}
fn xor(self, other: Self) -> ValueResult<Self> {
binary_match!(^(self, other); [I8, I16, I32, I64, I128, F32, F64])
bitop!(^(self, other))
}
fn not(self) -> ValueResult<Self> {
unary_match!(!(self); [I8, I16, I32, I64, I128, F32, F64])
Ok(match self {
DataValue::I8(a) => DataValue::I8(!a),
DataValue::I16(a) => DataValue::I16(!a),
DataValue::I32(a) => DataValue::I32(!a),
DataValue::I64(a) => DataValue::I64(!a),
DataValue::I128(a) => DataValue::I128(!a),
DataValue::F32(a) => DataValue::F32(!a),
DataValue::F64(a) => DataValue::F64(!a),
DataValue::V128(a) => {
let mut a2 = a.clone();
for a in a2.iter_mut() {
*a = !*a;
}
DataValue::V128(a2)
}
_ => unimplemented!(),
})
}
fn count_ones(self) -> ValueResult<Self> {