Merge pull request #3306 from afonso360/trampoline-simd-bools
Implement SIMD bools in trampoline
This commit is contained in:
@@ -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
|
/// Get a type with the same number of lanes as this type, but with lanes that are half the
|
||||||
/// number of bits.
|
/// number of bits.
|
||||||
pub fn half_width(self) -> Option<Self> {
|
pub fn half_width(self) -> Option<Self> {
|
||||||
@@ -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?
|
/// Is this a scalar integer type?
|
||||||
pub fn is_int(self) -> bool {
|
pub fn is_int(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
@@ -325,6 +345,19 @@ impl Type {
|
|||||||
Err(()) => panic!("unable to determine architecture pointer width"),
|
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 {
|
impl Display for Type {
|
||||||
@@ -530,4 +563,13 @@ mod tests {
|
|||||||
assert_eq!(I32X4.as_bool_pedantic(), B32X4);
|
assert_eq!(I32X4.as_bool_pedantic(), B32X4);
|
||||||
assert_eq!(I32.as_bool_pedantic(), B32);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,67 +3,41 @@ test run
|
|||||||
target aarch64
|
target aarch64
|
||||||
target x86_64 machinst
|
target x86_64 machinst
|
||||||
|
|
||||||
; TODO: Refactor this once we support simd bools in the trampoline
|
function %vall_true_b8x16(b8x16) -> b1 {
|
||||||
|
block0(v0: b8x16):
|
||||||
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]
|
|
||||||
v1 = vall_true v0
|
v1 = vall_true v0
|
||||||
|
return v1
|
||||||
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
|
|
||||||
}
|
}
|
||||||
; 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 {
|
function %vall_true_b16x8(b16x8) -> b1 {
|
||||||
block0:
|
block0(v0: b16x8):
|
||||||
v0 = vconst.b16x8 [false false false false false false false false]
|
|
||||||
v1 = vall_true v0
|
v1 = vall_true v0
|
||||||
|
return v1
|
||||||
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
|
|
||||||
}
|
}
|
||||||
; 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 {
|
function %vall_true_b32x4(b32x4) -> b1 {
|
||||||
block0:
|
block0(v0: b32x4):
|
||||||
v0 = vconst.b32x4 [false false false false]
|
|
||||||
v1 = vall_true v0
|
v1 = vall_true v0
|
||||||
|
return v1
|
||||||
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
|
|
||||||
}
|
}
|
||||||
; 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 {
|
function %vall_true_b64x2(b64x2) -> b1 {
|
||||||
block0:
|
block0(v0: b64x2):
|
||||||
v0 = vconst.b64x2 [false false]
|
|
||||||
v1 = vall_true v0
|
v1 = vall_true v0
|
||||||
|
return v1
|
||||||
v2 = vconst.b64x2 [true false]
|
|
||||||
v3 = vall_true v2
|
|
||||||
|
|
||||||
v4 = vconst.b64x2 [true true]
|
|
||||||
v5 = vall_true v4
|
|
||||||
|
|
||||||
return v1, v3, v5
|
|
||||||
}
|
}
|
||||||
; 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
|
||||||
|
|||||||
@@ -3,67 +3,41 @@ test run
|
|||||||
target x86_64 machinst
|
target x86_64 machinst
|
||||||
; TODO: The AArch64 backend is producing an illegal instruction for b64x2. See: #3304
|
; 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(b8x16) -> b1 {
|
||||||
|
block0(v0: b8x16):
|
||||||
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]
|
|
||||||
v1 = vany_true v0
|
v1 = vany_true v0
|
||||||
|
return v1
|
||||||
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
|
|
||||||
}
|
}
|
||||||
; 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 {
|
function %vany_true_b16x8(b16x8) -> b1 {
|
||||||
block0:
|
block0(v0: b16x8):
|
||||||
v0 = vconst.b16x8 [false false false false false false false false]
|
|
||||||
v1 = vany_true v0
|
v1 = vany_true v0
|
||||||
|
return v1
|
||||||
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
|
|
||||||
}
|
}
|
||||||
; 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 {
|
function %vany_true_b32x4(b32x4) -> b1 {
|
||||||
block0:
|
block0(v0: b32x4):
|
||||||
v0 = vconst.b32x4 [false false false false]
|
|
||||||
v1 = vany_true v0
|
v1 = vany_true v0
|
||||||
|
return v1
|
||||||
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
|
|
||||||
}
|
}
|
||||||
; 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 {
|
function %vany_true_b64x2(b64x2) -> b1 {
|
||||||
block0:
|
block0(v0: b64x2):
|
||||||
v0 = vconst.b64x2 [false false]
|
|
||||||
v1 = vany_true v0
|
v1 = vany_true v0
|
||||||
|
return v1
|
||||||
v2 = vconst.b64x2 [true false]
|
|
||||||
v3 = vany_true v2
|
|
||||||
|
|
||||||
v4 = vconst.b64x2 [true true]
|
|
||||||
v5 = vany_true v4
|
|
||||||
|
|
||||||
return v1, v3, v5
|
|
||||||
}
|
}
|
||||||
; 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
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
use core::mem;
|
use core::mem;
|
||||||
use cranelift_codegen::binemit::{NullRelocSink, NullStackMapSink, NullTrapSink};
|
use cranelift_codegen::binemit::{NullRelocSink, NullStackMapSink, NullTrapSink};
|
||||||
use cranelift_codegen::data_value::DataValue;
|
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::isa::{BackendVariant, TargetIsa};
|
||||||
use cranelift_codegen::{ir, settings, CodegenError, Context};
|
use cranelift_codegen::{ir, settings, CodegenError, Context};
|
||||||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||||
@@ -297,13 +297,8 @@ fn make_trampoline(signature: &ir::Signature, isa: &dyn TargetIsa) -> Function {
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, param)| {
|
.map(|(i, param)| {
|
||||||
// Calculate the type to load from memory, using integers for booleans (no encodings).
|
// Calculate the type to load from memory, using integers for booleans (no encodings).
|
||||||
let ty = if param.value_type.is_bool() {
|
let ty = param.value_type.coerce_bools_to_ints();
|
||||||
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
|
|
||||||
};
|
|
||||||
// Load the value.
|
// Load the value.
|
||||||
let loaded = builder.ins().load(
|
let loaded = builder.ins().load(
|
||||||
ty,
|
ty,
|
||||||
@@ -311,11 +306,16 @@ fn make_trampoline(signature: &ir::Signature, isa: &dyn TargetIsa) -> Function {
|
|||||||
values_vec_ptr_val,
|
values_vec_ptr_val,
|
||||||
(i * UnboxedValues::SLOT_SIZE) as i32,
|
(i * UnboxedValues::SLOT_SIZE) as i32,
|
||||||
);
|
);
|
||||||
|
|
||||||
// For booleans, we want to type-convert the loaded integer into a boolean and ensure
|
// 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
|
// that we are using the architecture's canonical boolean representation (presumably
|
||||||
// comparison will emit this).
|
// comparison will emit this).
|
||||||
if param.value_type.is_bool() {
|
if param.value_type.is_bool() {
|
||||||
builder.ins().icmp_imm(IntCC::NotEqual, loaded, 0)
|
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 {
|
} else {
|
||||||
loaded
|
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();
|
let results = builder.func.dfg.inst_results(call).to_vec();
|
||||||
for ((i, value), param) in results.iter().enumerate().zip(&signature.returns) {
|
for ((i, value), param) in results.iter().enumerate().zip(&signature.returns) {
|
||||||
// Before storing return values, we convert booleans to their integer representation.
|
// Before storing return values, we convert booleans to their integer representation.
|
||||||
let value = if param.value_type.is_bool() {
|
let value = if param.value_type.lane_type().is_bool() {
|
||||||
let ty = Type::int(max(param.value_type.bits(), 8))
|
let ty = param.value_type.lane_type().as_int();
|
||||||
.expect("to be able to convert any boolean type to its equal-width integer type");
|
|
||||||
builder.ins().bint(ty, *value)
|
builder.ins().bint(ty, *value)
|
||||||
} else {
|
} else {
|
||||||
*value
|
*value
|
||||||
|
|||||||
Reference in New Issue
Block a user