cranelift: Remove booleans (#5031)

Remove the boolean types from cranelift, and the associated instructions breduce, bextend, bconst, and bint. Standardize on using 1/0 for the return value from instructions that produce scalar boolean results, and -1/0 for boolean vector elements.

Fixes #3205

Co-authored-by: Afonso Bordado <afonso360@users.noreply.github.com>
Co-authored-by: Ulrich Weigand <ulrich.weigand@de.ibm.com>
Co-authored-by: Chris Fallin <chris@cfallin.org>
This commit is contained in:
Trevor Elliott
2022-10-17 16:00:27 -07:00
committed by GitHub
parent 766ecb561e
commit 32a7593c94
242 changed files with 7695 additions and 10010 deletions

View File

@@ -238,7 +238,7 @@ mod tests {
// Formula.
let cmp = pos.ins().icmp(IntCC::Equal, arg0, v0);
assert_eq!(pos.func.dfg.value_type(cmp), B1);
assert_eq!(pos.func.dfg.value_type(cmp), I8);
}
#[test]

View File

@@ -58,7 +58,6 @@ impl Block {
/// - [`iconst`](super::InstBuilder::iconst) for integer constants
/// - [`f32const`](super::InstBuilder::f32const) for 32-bit float constants
/// - [`f64const`](super::InstBuilder::f64const) for 64-bit float constants
/// - [`bconst`](super::InstBuilder::bconst) for boolean constants
/// - [`vconst`](super::InstBuilder::vconst) for vector constants
/// - [`null`](super::InstBuilder::null) for null reference constants
///

View File

@@ -372,7 +372,7 @@ impl<'a> fmt::Display for DisplayableExtFuncData<'a> {
#[cfg(test)]
mod tests {
use super::*;
use crate::ir::types::{B8, F32, I32};
use crate::ir::types::{F32, I32, I8};
use alloc::string::ToString;
#[test]
@@ -424,7 +424,7 @@ mod tests {
assert_eq!(sig.to_string(), "(i32) -> f32 windows_fastcall");
sig.params.push(AbiParam::new(I32.by(4).unwrap()));
assert_eq!(sig.to_string(), "(i32, i32x4) -> f32 windows_fastcall");
sig.returns.push(AbiParam::new(B8));
assert_eq!(sig.to_string(), "(i32, i32x4) -> f32, b8 windows_fastcall");
sig.returns.push(AbiParam::new(I8));
assert_eq!(sig.to_string(), "(i32, i32x4) -> f32, i8 windows_fastcall");
}
}

View File

@@ -575,8 +575,6 @@ pub struct ValueTypeSet {
pub ints: BitSet8,
/// Allowed float widths
pub floats: BitSet8,
/// Allowed bool widths
pub bools: BitSet8,
/// Allowed ref widths
pub refs: BitSet8,
/// Allowed dynamic vectors minimum lane sizes
@@ -593,8 +591,6 @@ impl ValueTypeSet {
self.ints.contains(l2b)
} else if scalar.is_float() {
self.floats.contains(l2b)
} else if scalar.is_bool() {
self.bools.contains(l2b)
} else if scalar.is_ref() {
self.refs.contains(l2b)
} else {
@@ -621,10 +617,8 @@ impl ValueTypeSet {
types::I32
} else if self.floats.max().unwrap_or(0) > 5 {
types::F32
} else if self.bools.max().unwrap_or(0) > 5 {
types::B32
} else {
types::B1
types::I8
};
t.by(1 << self.lanes.min().unwrap()).unwrap()
}
@@ -860,7 +854,6 @@ mod tests {
lanes: BitSet16::from_range(0, 8),
ints: BitSet8::from_range(4, 7),
floats: BitSet8::from_range(0, 0),
bools: BitSet8::from_range(3, 7),
refs: BitSet8::from_range(5, 7),
dynamic_lanes: BitSet16::from_range(0, 4),
};
@@ -870,9 +863,6 @@ mod tests {
assert!(vts.contains(I32X4));
assert!(vts.contains(I32X4XN));
assert!(!vts.contains(F32));
assert!(!vts.contains(B1));
assert!(vts.contains(B8));
assert!(vts.contains(B64));
assert!(vts.contains(R32));
assert!(vts.contains(R64));
assert_eq!(vts.example().to_string(), "i32");
@@ -881,7 +871,6 @@ mod tests {
lanes: BitSet16::from_range(0, 8),
ints: BitSet8::from_range(0, 0),
floats: BitSet8::from_range(5, 7),
bools: BitSet8::from_range(3, 7),
refs: BitSet8::from_range(0, 0),
dynamic_lanes: BitSet16::from_range(0, 8),
};
@@ -891,7 +880,6 @@ mod tests {
lanes: BitSet16::from_range(1, 8),
ints: BitSet8::from_range(0, 0),
floats: BitSet8::from_range(5, 7),
bools: BitSet8::from_range(3, 7),
refs: BitSet8::from_range(0, 0),
dynamic_lanes: BitSet16::from_range(0, 8),
};
@@ -899,23 +887,18 @@ mod tests {
let vts = ValueTypeSet {
lanes: BitSet16::from_range(2, 8),
ints: BitSet8::from_range(0, 0),
ints: BitSet8::from_range(3, 7),
floats: BitSet8::from_range(0, 0),
bools: BitSet8::from_range(3, 7),
refs: BitSet8::from_range(0, 0),
dynamic_lanes: BitSet16::from_range(0, 8),
};
assert!(!vts.contains(B32X2));
assert!(vts.contains(B32X4));
assert!(vts.contains(B16X4XN));
assert_eq!(vts.example().to_string(), "b32x4");
assert_eq!(vts.example().to_string(), "i32x4");
let vts = ValueTypeSet {
// TypeSet(lanes=(1, 256), ints=(8, 64))
lanes: BitSet16::from_range(0, 9),
ints: BitSet8::from_range(3, 7),
floats: BitSet8::from_range(0, 0),
bools: BitSet8::from_range(0, 0),
refs: BitSet8::from_range(0, 0),
dynamic_lanes: BitSet16::from_range(0, 8),
};

View File

@@ -17,10 +17,7 @@ use target_lexicon::{PointerWidth, Triple};
///
/// Basic floating point types: `F32` and `F64`. IEEE single and double precision.
///
/// Boolean types: `B1`, `B8`, `B16`, `B32`, `B64`, and `B128`. These all encode 'true' or 'false'. The
/// larger types use redundant bits.
///
/// SIMD vector types have power-of-two lanes, up to 256. Lanes can be any int/float/bool type.
/// SIMD vector types have power-of-two lanes, up to 256. Lanes can be any int/float type.
///
/// Note that this is encoded in a `u16` currently for extensibility,
/// but allows only 14 bits to be used due to some bitpacking tricks
@@ -59,12 +56,11 @@ impl Type {
/// Get log_2 of the number of bits in a lane.
pub fn log2_lane_bits(self) -> u32 {
match self.lane_type() {
B1 => 0,
B8 | I8 => 3,
B16 | I16 => 4,
B32 | I32 | F32 | R32 => 5,
B64 | I64 | F64 | R64 => 6,
B128 | I128 => 7,
I8 => 3,
I16 => 4,
I32 | F32 | R32 => 5,
I64 | F64 | R64 => 6,
I128 => 7,
_ => 0,
}
}
@@ -72,12 +68,11 @@ impl Type {
/// Get the number of bits in a lane.
pub fn lane_bits(self) -> u32 {
match self.lane_type() {
B1 => 1,
B8 | I8 => 8,
B16 | I16 => 16,
B32 | I32 | F32 | R32 => 32,
B64 | I64 | F64 | R64 => 64,
B128 | I128 => 128,
I8 => 8,
I16 => 16,
I32 | F32 | R32 => 32,
I64 | F64 | R64 => 64,
I128 => 128,
_ => 0,
}
}
@@ -141,13 +136,13 @@ impl Type {
pub fn as_bool_pedantic(self) -> Self {
// Replace the low 4 bits with the boolean version, preserve the high 4 bits.
self.replace_lanes(match self.lane_type() {
B8 | I8 => B8,
B16 | I16 => B16,
B32 | I32 | F32 => B32,
B64 | I64 | F64 => B64,
I8 => I8,
I16 => I16,
I32 | F32 => I32,
I64 | F64 => I64,
R32 | R64 => panic!("Reference types should not convert to bool"),
B128 | I128 => B128,
_ => B1,
I128 => I128,
_ => I8,
})
}
@@ -157,7 +152,7 @@ impl Type {
/// Scalar types are all converted to `b1` which is usually what you want.
pub fn as_bool(self) -> Self {
if !self.is_vector() {
B1
I8
} else {
self.as_bool_pedantic()
}
@@ -169,11 +164,11 @@ impl Type {
/// Scalar types follow this same rule, but `b1` is converted into `i8`
pub fn as_int(self) -> Self {
self.replace_lanes(match self.lane_type() {
I8 | B1 | B8 => I8,
I16 | B16 => I16,
I32 | B32 | F32 => I32,
I64 | B64 | F64 => I64,
I128 | B128 => I128,
I8 => I8,
I16 => I16,
I32 | F32 => I32,
I64 | F64 => I64,
I128 => I128,
_ => unimplemented!(),
})
}
@@ -187,10 +182,6 @@ impl Type {
I64 => I32,
I128 => I64,
F64 => F32,
B16 => B8,
B32 => B16,
B64 => B32,
B128 => B64,
_ => return None,
}))
}
@@ -204,10 +195,6 @@ impl Type {
I32 => I64,
I64 => I128,
F32 => F64,
B8 => B16,
B16 => B32,
B32 => B64,
B64 => B128,
_ => return None,
}))
}
@@ -241,19 +228,6 @@ impl Type {
self.0 >= constants::DYNAMIC_VECTOR_BASE
}
/// Is this a scalar boolean type?
pub fn is_bool(self) -> bool {
match self {
B1 | B8 | B16 | B32 | B64 | B128 => true,
_ => false,
}
}
/// Is this a vector boolean type?
pub fn is_bool_vector(self) -> bool {
self.is_vector() && self.lane_type().is_bool()
}
/// Is this a scalar integer type?
pub fn is_int(self) -> bool {
match self {
@@ -453,19 +427,6 @@ impl Type {
}
}
/// Coerces boolean types (scalar and vectors) into their integer counterparts.
/// B1 is converted into I8.
pub fn coerce_bools_to_ints(self) -> Self {
let is_scalar_bool = self.is_bool();
let is_vector_bool = self.is_vector() && self.lane_type().is_bool();
if is_scalar_bool || is_vector_bool {
self.as_int()
} else {
self
}
}
/// Gets a bit-level representation of the type. Used only
/// internally for efficiently storing types.
pub(crate) fn repr(self) -> u16 {
@@ -481,9 +442,7 @@ impl Type {
impl Display for Type {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.is_bool() {
write!(f, "b{}", self.lane_bits())
} else if self.is_int() {
if self.is_int() {
write!(f, "i{}", self.lane_bits())
} else if self.is_float() {
write!(f, "f{}", self.lane_bits())
@@ -506,9 +465,7 @@ impl Display for Type {
impl Debug for Type {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.is_bool() {
write!(f, "types::B{}", self.lane_bits())
} else if self.is_int() {
if self.is_int() {
write!(f, "types::I{}", self.lane_bits())
} else if self.is_float() {
write!(f, "types::F{}", self.lane_bits())
@@ -548,12 +505,6 @@ mod tests {
assert_eq!(0, IFLAGS.bits());
assert_eq!(FFLAGS, FFLAGS.lane_type());
assert_eq!(0, FFLAGS.bits());
assert_eq!(B1, B1.lane_type());
assert_eq!(B8, B8.lane_type());
assert_eq!(B16, B16.lane_type());
assert_eq!(B32, B32.lane_type());
assert_eq!(B64, B64.lane_type());
assert_eq!(B128, B128.lane_type());
assert_eq!(I8, I8.lane_type());
assert_eq!(I16, I16.lane_type());
assert_eq!(I32, I32.lane_type());
@@ -561,7 +512,6 @@ mod tests {
assert_eq!(I128, I128.lane_type());
assert_eq!(F32, F32.lane_type());
assert_eq!(F64, F64.lane_type());
assert_eq!(B1, B1.by(8).unwrap().lane_type());
assert_eq!(I32, I32X4.lane_type());
assert_eq!(F64, F64X2.lane_type());
assert_eq!(R32, R32.lane_type());
@@ -570,12 +520,6 @@ mod tests {
assert_eq!(INVALID.lane_bits(), 0);
assert_eq!(IFLAGS.lane_bits(), 0);
assert_eq!(FFLAGS.lane_bits(), 0);
assert_eq!(B1.lane_bits(), 1);
assert_eq!(B8.lane_bits(), 8);
assert_eq!(B16.lane_bits(), 16);
assert_eq!(B32.lane_bits(), 32);
assert_eq!(B64.lane_bits(), 64);
assert_eq!(B128.lane_bits(), 128);
assert_eq!(I8.lane_bits(), 8);
assert_eq!(I16.lane_bits(), 16);
assert_eq!(I32.lane_bits(), 32);
@@ -592,12 +536,6 @@ mod tests {
assert_eq!(INVALID.half_width(), None);
assert_eq!(INVALID.half_width(), None);
assert_eq!(FFLAGS.half_width(), None);
assert_eq!(B1.half_width(), None);
assert_eq!(B8.half_width(), None);
assert_eq!(B16.half_width(), Some(B8));
assert_eq!(B32.half_width(), Some(B16));
assert_eq!(B64.half_width(), Some(B32));
assert_eq!(B128.half_width(), Some(B64));
assert_eq!(I8.half_width(), None);
assert_eq!(I16.half_width(), Some(I8));
assert_eq!(I32.half_width(), Some(I16));
@@ -610,12 +548,6 @@ mod tests {
assert_eq!(INVALID.double_width(), None);
assert_eq!(IFLAGS.double_width(), None);
assert_eq!(FFLAGS.double_width(), None);
assert_eq!(B1.double_width(), None);
assert_eq!(B8.double_width(), Some(B16));
assert_eq!(B16.double_width(), Some(B32));
assert_eq!(B32.double_width(), Some(B64));
assert_eq!(B64.double_width(), Some(B128));
assert_eq!(B128.double_width(), None);
assert_eq!(I8.double_width(), Some(I16));
assert_eq!(I16.double_width(), Some(I32));
assert_eq!(I32.double_width(), Some(I64));
@@ -634,7 +566,6 @@ mod tests {
assert_eq!(big.bits(), 64 * 256);
assert_eq!(big.half_vector().unwrap().to_string(), "f64x128");
assert_eq!(B1.by(2).unwrap().half_vector().unwrap().to_string(), "b1");
assert_eq!(I32.half_vector(), None);
assert_eq!(INVALID.half_vector(), None);
@@ -647,7 +578,6 @@ mod tests {
fn dynamic_vectors() {
// Identification.
assert_eq!(I8X16XN.is_dynamic_vector(), true);
assert_eq!(B16X4XN.is_dynamic_vector(), true);
assert_eq!(F32X8XN.is_dynamic_vector(), true);
assert_eq!(F64X4XN.is_dynamic_vector(), true);
assert_eq!(I128X2XN.is_dynamic_vector(), true);
@@ -656,28 +586,19 @@ mod tests {
assert_eq!(I16X8XN.lane_count(), 0);
assert_eq!(I16X8XN.min_lane_count(), 8);
// Size
assert_eq!(B32X2XN.bits(), 0);
assert_eq!(B32X2XN.min_bits(), 64);
// Change lane counts
assert_eq!(F64X4XN.half_vector(), None);
assert_eq!(I8X8XN.by(2), None);
// Conversions to and from vectors.
assert_eq!(B8.by(8).unwrap().vector_to_dynamic(), Some(B8X8XN));
assert_eq!(I8.by(16).unwrap().vector_to_dynamic(), Some(I8X16XN));
assert_eq!(I16.by(8).unwrap().vector_to_dynamic(), Some(I16X8XN));
assert_eq!(B16.by(16).unwrap().vector_to_dynamic(), Some(B16X16XN));
assert_eq!(B32.by(2).unwrap().vector_to_dynamic(), Some(B32X2XN));
assert_eq!(B32.by(8).unwrap().vector_to_dynamic(), Some(B32X8XN));
assert_eq!(I32.by(4).unwrap().vector_to_dynamic(), Some(I32X4XN));
assert_eq!(F32.by(4).unwrap().vector_to_dynamic(), Some(F32X4XN));
assert_eq!(F64.by(2).unwrap().vector_to_dynamic(), Some(F64X2XN));
assert_eq!(I128.by(2).unwrap().vector_to_dynamic(), Some(I128X2XN));
assert_eq!(I128X2XN.dynamic_to_vector(), Some(I128X2));
assert_eq!(B64X2XN.dynamic_to_vector(), Some(B64X2));
assert_eq!(F32X4XN.dynamic_to_vector(), Some(F32X4));
assert_eq!(F64X4XN.dynamic_to_vector(), Some(F64X4));
assert_eq!(I32X2XN.dynamic_to_vector(), Some(I32X2));
@@ -686,7 +607,6 @@ mod tests {
assert_eq!(I8X32XN.dynamic_to_vector(), Some(I8X32));
assert_eq!(I8X64.vector_to_dynamic(), None);
assert_eq!(B16X32.vector_to_dynamic(), None);
assert_eq!(F32X16.vector_to_dynamic(), None);
assert_eq!(I64X8.vector_to_dynamic(), None);
assert_eq!(I128X4.vector_to_dynamic(), None);
@@ -696,12 +616,6 @@ mod tests {
fn format_scalars() {
assert_eq!(IFLAGS.to_string(), "iflags");
assert_eq!(FFLAGS.to_string(), "fflags");
assert_eq!(B1.to_string(), "b1");
assert_eq!(B8.to_string(), "b8");
assert_eq!(B16.to_string(), "b16");
assert_eq!(B32.to_string(), "b32");
assert_eq!(B64.to_string(), "b64");
assert_eq!(B128.to_string(), "b128");
assert_eq!(I8.to_string(), "i8");
assert_eq!(I16.to_string(), "i16");
assert_eq!(I32.to_string(), "i32");
@@ -715,11 +629,6 @@ mod tests {
#[test]
fn format_vectors() {
assert_eq!(B1.by(8).unwrap().to_string(), "b1x8");
assert_eq!(B8.by(1).unwrap().to_string(), "b8");
assert_eq!(B16.by(256).unwrap().to_string(), "b16x256");
assert_eq!(B32.by(4).unwrap().by(2).unwrap().to_string(), "b32x8");
assert_eq!(B64.by(8).unwrap().to_string(), "b64x8");
assert_eq!(I8.by(64).unwrap().to_string(), "i8x64");
assert_eq!(F64.by(2).unwrap().to_string(), "f64x2");
assert_eq!(I8.by(3), None);
@@ -729,19 +638,10 @@ mod tests {
#[test]
fn as_bool() {
assert_eq!(I32X4.as_bool(), B32X4);
assert_eq!(I32.as_bool(), B1);
assert_eq!(I32X4.as_bool_pedantic(), B32X4);
assert_eq!(I32.as_bool_pedantic(), B32);
}
#[test]
fn as_int() {
assert_eq!(B32X4.as_int(), I32X4);
assert_eq!(B8X8.as_int(), I8X8);
assert_eq!(B1.as_int(), I8);
assert_eq!(B8.as_int(), I8);
assert_eq!(B128.as_int(), I128);
assert_eq!(I32X4.as_bool(), I32X4);
assert_eq!(I32.as_bool(), I8);
assert_eq!(I32X4.as_bool_pedantic(), I32X4);
assert_eq!(I32.as_bool_pedantic(), I32);
}
#[test]