diff --git a/cranelift/codegen/src/ir/types.rs b/cranelift/codegen/src/ir/types.rs index b9499435b8..4284021190 100644 --- a/cranelift/codegen/src/ir/types.rs +++ b/cranelift/codegen/src/ir/types.rs @@ -127,6 +127,21 @@ impl Type { } } + /// Get a type with the same number of lanes as this type, but with the lanes replaced by + /// integers of the same size. + /// + /// 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() { + B1 | B8 => I8, + B16 => I16, + B32 => I32, + B64 => I64, + B128 => I128, + _ => unimplemented!(), + }) + } + /// Get a type with the same number of lanes as this type, but with lanes that are half the /// number of bits. pub fn half_width(self) -> Option { @@ -193,6 +208,11 @@ impl Type { } } + /// 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 { @@ -325,6 +345,19 @@ impl Type { Err(()) => panic!("unable to determine architecture pointer width"), } } + + /// 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 + } + } } impl Display for Type { @@ -530,4 +563,13 @@ mod tests { 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); + } } diff --git a/cranelift/filetests/filetests/runtests/simd-valltrue.clif b/cranelift/filetests/filetests/runtests/simd-valltrue.clif index 247b3d4bfd..ced9a6bb0d 100644 --- a/cranelift/filetests/filetests/runtests/simd-valltrue.clif +++ b/cranelift/filetests/filetests/runtests/simd-valltrue.clif @@ -3,67 +3,41 @@ test run target aarch64 target x86_64 machinst -; TODO: Refactor this once we support simd bools in the trampoline - -function %vall_true_b8x16() -> b1, b1, b1 { -block0: - v0 = vconst.b8x16 [false false false false false false false false false false false false false false false false] +function %vall_true_b8x16(b8x16) -> b1 { +block0(v0: b8x16): v1 = vall_true v0 - - v2 = vconst.b8x16 [true false false false false false false false false false false false false false false false] - v3 = vall_true v2 - - v4 = vconst.b8x16 [true true true true true true true true true true true true true true true true] - v5 = vall_true v4 - - return v1, v3, v5 + return v1 } -; run: %vall_true_b8x16() == [false, false, true] +; run: %vall_true_b8x16([false false false false false false false false false false false false false false false false]) == false +; run: %vall_true_b8x16([true false false false false false false false false false false false false false false false]) == false +; run: %vall_true_b8x16([true true true true true true true true true true true true true true true true]) == true -function %vall_true_b16x8() -> b1, b1, b1 { -block0: - v0 = vconst.b16x8 [false false false false false false false false] +function %vall_true_b16x8(b16x8) -> b1 { +block0(v0: b16x8): v1 = vall_true v0 - - v2 = vconst.b16x8 [true false false false false false false false] - v3 = vall_true v2 - - v4 = vconst.b16x8 [true true true true true true true true] - v5 = vall_true v4 - - return v1, v3, v5 + return v1 } -; run: %vall_true_b16x8() == [false, false, true] +; run: %vall_true_b16x8([false false false false false false false false]) == false +; run: %vall_true_b16x8([true false false false false false false false]) == false +; run: %vall_true_b16x8([true true true true true true true true]) == true -function %vall_true_b32x4() -> b1, b1, b1 { -block0: - v0 = vconst.b32x4 [false false false false] +function %vall_true_b32x4(b32x4) -> b1 { +block0(v0: b32x4): v1 = vall_true v0 - - v2 = vconst.b32x4 [true false false false] - v3 = vall_true v2 - - v4 = vconst.b32x4 [true true true true] - v5 = vall_true v4 - - return v1, v3, v5 + return v1 } -; run: %vall_true_b32x4() == [false, false, true] +; run: %vall_true_b32x4([false false false false]) == false +; run: %vall_true_b32x4([true false false false]) == false +; run: %vall_true_b32x4([true true true true]) == true -function %vall_true_b64x2() -> b1, b1, b1 { -block0: - v0 = vconst.b64x2 [false false] +function %vall_true_b64x2(b64x2) -> b1 { +block0(v0: b64x2): v1 = vall_true v0 - - v2 = vconst.b64x2 [true false] - v3 = vall_true v2 - - v4 = vconst.b64x2 [true true] - v5 = vall_true v4 - - return v1, v3, v5 + return v1 } -; run: %vall_true_b64x2() == [false, false, true] +; run: %vall_true_b64x2([false false]) == false +; run: %vall_true_b64x2([true false]) == false +; run: %vall_true_b64x2([true true]) == true diff --git a/cranelift/filetests/filetests/runtests/simd-vanytrue.clif b/cranelift/filetests/filetests/runtests/simd-vanytrue.clif index 15d7f9a040..fd206d54ef 100644 --- a/cranelift/filetests/filetests/runtests/simd-vanytrue.clif +++ b/cranelift/filetests/filetests/runtests/simd-vanytrue.clif @@ -3,67 +3,41 @@ test run target x86_64 machinst ; TODO: The AArch64 backend is producing an illegal instruction for b64x2. See: #3304 -; TODO: Refactor this once we support simd bools in the trampoline - -function %vany_true_b8x16() -> b1, b1, b1 { -block0: - v0 = vconst.b8x16 [false false false false false false false false false false false false false false false false] +function %vany_true_b8x16(b8x16) -> b1 { +block0(v0: b8x16): v1 = vany_true v0 - - v2 = vconst.b8x16 [true false false false false false false false false false false false false false false false] - v3 = vany_true v2 - - v4 = vconst.b8x16 [true true true true true true true true true true true true true true true true] - v5 = vany_true v4 - - return v1, v3, v5 + return v1 } -; run: %vany_true_b8x16() == [false, true, true] +; run: %vany_true_b8x16([false false false false false false false false false false false false false false false false]) == false +; run: %vany_true_b8x16([true false false false false false false false false false false false false false false false]) == true +; run: %vany_true_b8x16([true true true true true true true true true true true true true true true true]) == true -function %vany_true_b16x8() -> b1, b1, b1 { -block0: - v0 = vconst.b16x8 [false false false false false false false false] +function %vany_true_b16x8(b16x8) -> b1 { +block0(v0: b16x8): v1 = vany_true v0 - - v2 = vconst.b16x8 [true false false false false false false false] - v3 = vany_true v2 - - v4 = vconst.b16x8 [true true true true true true true true] - v5 = vany_true v4 - - return v1, v3, v5 + return v1 } -; run: %vany_true_b16x8() == [false, true, true] +; run: %vany_true_b16x8([false false false false false false false false]) == false +; run: %vany_true_b16x8([true false false false false false false false]) == true +; run: %vany_true_b16x8([true true true true true true true true]) == true -function %vany_true_b32x4() -> b1, b1, b1 { -block0: - v0 = vconst.b32x4 [false false false false] +function %vany_true_b32x4(b32x4) -> b1 { +block0(v0: b32x4): v1 = vany_true v0 - - v2 = vconst.b32x4 [true false false false] - v3 = vany_true v2 - - v4 = vconst.b32x4 [true true true true] - v5 = vany_true v4 - - return v1, v3, v5 + return v1 } -; run: %vany_true_b32x4() == [false, true, true] +; run: %vany_true_b32x4([false false false false]) == false +; run: %vany_true_b32x4([true false false false]) == true +; run: %vany_true_b32x4([true true true true]) == true -function %vany_true_b64x2() -> b1, b1, b1 { -block0: - v0 = vconst.b64x2 [false false] +function %vany_true_b64x2(b64x2) -> b1 { +block0(v0: b64x2): v1 = vany_true v0 - - v2 = vconst.b64x2 [true false] - v3 = vany_true v2 - - v4 = vconst.b64x2 [true true] - v5 = vany_true v4 - - return v1, v3, v5 + return v1 } -; run: %vany_true_b64x2() == [false, true, true] +; run: %vany_true_b64x2([false false]) == false +; run: %vany_true_b64x2([true false]) == true +; run: %vany_true_b64x2([true true]) == true diff --git a/cranelift/filetests/src/function_runner.rs b/cranelift/filetests/src/function_runner.rs index 1db16c2232..d764b916e5 100644 --- a/cranelift/filetests/src/function_runner.rs +++ b/cranelift/filetests/src/function_runner.rs @@ -2,7 +2,7 @@ use core::mem; use cranelift_codegen::binemit::{NullRelocSink, NullStackMapSink, NullTrapSink}; use cranelift_codegen::data_value::DataValue; -use cranelift_codegen::ir::{condcodes::IntCC, Function, InstBuilder, Signature, Type}; +use cranelift_codegen::ir::{condcodes::IntCC, Function, InstBuilder, Signature}; use cranelift_codegen::isa::{BackendVariant, TargetIsa}; use cranelift_codegen::{ir, settings, CodegenError, Context}; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; @@ -297,13 +297,8 @@ fn make_trampoline(signature: &ir::Signature, isa: &dyn TargetIsa) -> Function { .enumerate() .map(|(i, param)| { // Calculate the type to load from memory, using integers for booleans (no encodings). - let ty = if param.value_type.is_bool() { - Type::int(max(param.value_type.bits(), 8)).expect( - "to be able to convert any boolean type to its equal-width integer type", - ) - } else { - param.value_type - }; + let ty = param.value_type.coerce_bools_to_ints(); + // Load the value. let loaded = builder.ins().load( ty, @@ -311,11 +306,16 @@ fn make_trampoline(signature: &ir::Signature, isa: &dyn TargetIsa) -> Function { values_vec_ptr_val, (i * UnboxedValues::SLOT_SIZE) as i32, ); + // For booleans, we want to type-convert the loaded integer into a boolean and ensure // that we are using the architecture's canonical boolean representation (presumably // comparison will emit this). if param.value_type.is_bool() { builder.ins().icmp_imm(IntCC::NotEqual, loaded, 0) + } else if param.value_type.is_bool_vector() { + let zero_constant = builder.func.dfg.constants.insert(vec![0; 16].into()); + let zero_vec = builder.ins().vconst(ty, zero_constant); + builder.ins().icmp(IntCC::NotEqual, loaded, zero_vec) } else { loaded } @@ -332,9 +332,8 @@ fn make_trampoline(signature: &ir::Signature, isa: &dyn TargetIsa) -> Function { let results = builder.func.dfg.inst_results(call).to_vec(); for ((i, value), param) in results.iter().enumerate().zip(&signature.returns) { // Before storing return values, we convert booleans to their integer representation. - let value = if param.value_type.is_bool() { - let ty = Type::int(max(param.value_type.bits(), 8)) - .expect("to be able to convert any boolean type to its equal-width integer type"); + let value = if param.value_type.lane_type().is_bool() { + let ty = param.value_type.lane_type().as_int(); builder.ins().bint(ty, *value) } else { *value