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:
@@ -94,7 +94,6 @@ pub type S390xCallee = Callee<S390xMachineDeps>;
|
||||
fn in_int_reg(ty: Type) -> bool {
|
||||
match ty {
|
||||
types::I8 | types::I16 | types::I32 | types::I64 | types::R64 => true,
|
||||
types::B1 | types::B8 | types::B16 | types::B32 | types::B64 => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3129,7 +3129,6 @@
|
||||
dst))
|
||||
|
||||
;; Sign-extend a register from a smaller `Type` into a 32-bit register.
|
||||
;; This handles both integer and boolean input types (except $B1).
|
||||
(decl sext32_reg (Type Reg) Reg)
|
||||
(rule (sext32_reg ty src)
|
||||
(let ((dst WritableReg (temp_writable_reg $I32))
|
||||
@@ -3137,7 +3136,6 @@
|
||||
dst))
|
||||
|
||||
;; Zero-extend a register from a smaller `Type` into a 64-bit register.
|
||||
;; This handles both integer and boolean input types (except $B1).
|
||||
(decl zext64_reg (Type Reg) Reg)
|
||||
(rule (zext64_reg ty src)
|
||||
(let ((dst WritableReg (temp_writable_reg $I64))
|
||||
@@ -3145,7 +3143,6 @@
|
||||
dst))
|
||||
|
||||
;; Sign-extend a register from a smaller `Type` into a 64-bit register.
|
||||
;; This handles both integer and boolean input types (except $B1).
|
||||
(decl sext64_reg (Type Reg) Reg)
|
||||
(rule (sext64_reg ty src)
|
||||
(let ((dst WritableReg (temp_writable_reg $I64))
|
||||
@@ -3477,14 +3474,19 @@
|
||||
(_ Unit (emit_consumer (emit_cmov_imm ty dst cond imm_true))))
|
||||
dst))
|
||||
|
||||
;; Lower a boolean condition to a boolean type. The value used to represent
|
||||
;; "true" is -1 for all result types except for $B1, which uses 1.
|
||||
;; Lower a boolean condition to the values 1/0. This rule is only used in the
|
||||
;; context of instructions that return $I8 results.
|
||||
(decl lower_bool (Type ProducesBool) Reg)
|
||||
(rule (lower_bool $B1 cond) (select_bool_imm $B1 cond 1 0))
|
||||
(rule (lower_bool $B8 cond) (select_bool_imm $B8 cond -1 0))
|
||||
(rule (lower_bool $B16 cond) (select_bool_imm $B16 cond -1 0))
|
||||
(rule (lower_bool $B32 cond) (select_bool_imm $B32 cond -1 0))
|
||||
(rule (lower_bool $B64 cond) (select_bool_imm $B64 cond -1 0))
|
||||
(rule (lower_bool $I8 cond) (select_bool_imm $I8 cond 1 0))
|
||||
|
||||
;; Lower a boolean condition to the values -1/0.
|
||||
(decl lower_bool_to_mask (Type ProducesBool) Reg)
|
||||
(rule 0 (lower_bool_to_mask (fits_in_64 ty) producer)
|
||||
(select_bool_imm ty producer -1 0))
|
||||
|
||||
(rule 1 (lower_bool_to_mask $I128 producer)
|
||||
(let ((res Reg (lower_bool_to_mask $I64 producer)))
|
||||
(mov_to_vec128 $I128 res res)))
|
||||
|
||||
;; Emit a conditional branch based on a boolean condition.
|
||||
(decl cond_br_bool (ProducesBool MachLabel MachLabel) SideEffectNoResult)
|
||||
|
||||
@@ -397,10 +397,10 @@ impl Inst {
|
||||
/// Generic constructor for a load (zero-extending where appropriate).
|
||||
pub fn gen_load(into_reg: Writable<Reg>, mem: MemArg, ty: Type) -> Inst {
|
||||
match ty {
|
||||
types::B1 | types::B8 | types::I8 => Inst::Load64ZExt8 { rd: into_reg, mem },
|
||||
types::B16 | types::I16 => Inst::Load64ZExt16 { rd: into_reg, mem },
|
||||
types::B32 | types::I32 => Inst::Load64ZExt32 { rd: into_reg, mem },
|
||||
types::B64 | types::I64 | types::R64 => Inst::Load64 { rd: into_reg, mem },
|
||||
types::I8 => Inst::Load64ZExt8 { rd: into_reg, mem },
|
||||
types::I16 => Inst::Load64ZExt16 { rd: into_reg, mem },
|
||||
types::I32 => Inst::Load64ZExt32 { rd: into_reg, mem },
|
||||
types::I64 | types::R64 => Inst::Load64 { rd: into_reg, mem },
|
||||
types::F32 => Inst::VecLoadLaneUndef {
|
||||
size: 32,
|
||||
rd: into_reg,
|
||||
@@ -414,7 +414,7 @@ impl Inst {
|
||||
lane_imm: 0,
|
||||
},
|
||||
_ if ty.is_vector() && ty.bits() == 128 => Inst::VecLoad { rd: into_reg, mem },
|
||||
types::B128 | types::I128 => Inst::VecLoad { rd: into_reg, mem },
|
||||
types::I128 => Inst::VecLoad { rd: into_reg, mem },
|
||||
_ => unimplemented!("gen_load({})", ty),
|
||||
}
|
||||
}
|
||||
@@ -422,10 +422,10 @@ impl Inst {
|
||||
/// Generic constructor for a store.
|
||||
pub fn gen_store(mem: MemArg, from_reg: Reg, ty: Type) -> Inst {
|
||||
match ty {
|
||||
types::B1 | types::B8 | types::I8 => Inst::Store8 { rd: from_reg, mem },
|
||||
types::B16 | types::I16 => Inst::Store16 { rd: from_reg, mem },
|
||||
types::B32 | types::I32 => Inst::Store32 { rd: from_reg, mem },
|
||||
types::B64 | types::I64 | types::R64 => Inst::Store64 { rd: from_reg, mem },
|
||||
types::I8 => Inst::Store8 { rd: from_reg, mem },
|
||||
types::I16 => Inst::Store16 { rd: from_reg, mem },
|
||||
types::I32 => Inst::Store32 { rd: from_reg, mem },
|
||||
types::I64 | types::R64 => Inst::Store64 { rd: from_reg, mem },
|
||||
types::F32 => Inst::VecStoreLane {
|
||||
size: 32,
|
||||
rd: from_reg,
|
||||
@@ -439,7 +439,7 @@ impl Inst {
|
||||
lane_imm: 0,
|
||||
},
|
||||
_ if ty.is_vector() && ty.bits() == 128 => Inst::VecStore { rd: from_reg, mem },
|
||||
types::B128 | types::I128 => Inst::VecStore { rd: from_reg, mem },
|
||||
types::I128 => Inst::VecStore { rd: from_reg, mem },
|
||||
_ => unimplemented!("gen_store({})", ty),
|
||||
}
|
||||
}
|
||||
@@ -1086,7 +1086,7 @@ impl MachInst for Inst {
|
||||
.only_reg()
|
||||
.expect("multi-reg values not supported yet");
|
||||
match ty {
|
||||
types::I128 | types::B128 => {
|
||||
types::I128 => {
|
||||
let mut ret = SmallVec::new();
|
||||
ret.push(Inst::load_vec_constant(to_reg, value));
|
||||
ret
|
||||
@@ -1112,14 +1112,8 @@ impl MachInst for Inst {
|
||||
));
|
||||
ret
|
||||
}
|
||||
types::I64 | types::B64 | types::R64 => Inst::load_constant64(to_reg, value as u64),
|
||||
types::B1
|
||||
| types::I8
|
||||
| types::B8
|
||||
| types::I16
|
||||
| types::B16
|
||||
| types::I32
|
||||
| types::B32 => Inst::load_constant32(to_reg, value as u32),
|
||||
types::I64 | types::R64 => Inst::load_constant64(to_reg, value as u64),
|
||||
types::I8 | types::I16 | types::I32 => Inst::load_constant32(to_reg, value as u32),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -1140,17 +1134,11 @@ impl MachInst for Inst {
|
||||
types::I16 => Ok((&[RegClass::Int], &[types::I16])),
|
||||
types::I32 => Ok((&[RegClass::Int], &[types::I32])),
|
||||
types::I64 => Ok((&[RegClass::Int], &[types::I64])),
|
||||
types::B1 => Ok((&[RegClass::Int], &[types::B1])),
|
||||
types::B8 => Ok((&[RegClass::Int], &[types::B8])),
|
||||
types::B16 => Ok((&[RegClass::Int], &[types::B16])),
|
||||
types::B32 => Ok((&[RegClass::Int], &[types::B32])),
|
||||
types::B64 => Ok((&[RegClass::Int], &[types::B64])),
|
||||
types::R32 => panic!("32-bit reftype pointer should never be seen on s390x"),
|
||||
types::R64 => Ok((&[RegClass::Int], &[types::R64])),
|
||||
types::F32 => Ok((&[RegClass::Float], &[types::F32])),
|
||||
types::F64 => Ok((&[RegClass::Float], &[types::F64])),
|
||||
types::I128 => Ok((&[RegClass::Float], &[types::I128])),
|
||||
types::B128 => Ok((&[RegClass::Float], &[types::B128])),
|
||||
_ if ty.is_vector() && ty.bits() == 128 => Ok((&[RegClass::Float], &[types::I8X16])),
|
||||
// FIXME: We don't really have IFLAGS, but need to allow it here
|
||||
// for now to support the SelectifSpectreGuard instruction.
|
||||
|
||||
@@ -16,14 +16,6 @@
|
||||
(imm ty n))
|
||||
|
||||
|
||||
;;;; Rules for `bconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(rule (lower (has_type ty (bconst $false)))
|
||||
(imm ty 0))
|
||||
(rule (lower (has_type ty (bconst $true)))
|
||||
(imm ty 1))
|
||||
|
||||
|
||||
;;;; Rules for `f32const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(rule (lower (f32const (u64_from_ieee32 x)))
|
||||
@@ -1163,92 +1155,10 @@
|
||||
(vec_select ty y z x))
|
||||
|
||||
|
||||
;;;; Rules for `breduce` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;; Rules for `bmask` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Up to 64-bit source type: Always a no-op.
|
||||
(rule 1 (lower (breduce x @ (value_type (fits_in_64 _ty))))
|
||||
x)
|
||||
|
||||
;; 128-bit source type: Extract the low half.
|
||||
(rule (lower (breduce x @ (value_type (vr128_ty _ty))))
|
||||
(vec_extract_lane $I64X2 x 1 (zero_reg)))
|
||||
|
||||
|
||||
;;;; Rules for `bextend` and `bmask` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Use a common helper to type cast bools to either bool or integer types.
|
||||
(decl cast_bool (Type Value) Reg)
|
||||
(rule (lower (has_type ty (bextend x)))
|
||||
(cast_bool ty x))
|
||||
(rule (lower (has_type ty (bmask x)))
|
||||
(cast_bool ty x))
|
||||
|
||||
;; If the target has the same or a smaller size than the source, it's a no-op.
|
||||
(rule 8 (cast_bool $B1 x @ (value_type $B1)) x)
|
||||
(rule 8 (cast_bool $B1 x @ (value_type $B8)) x)
|
||||
(rule 8 (cast_bool $B8 x @ (value_type $B8)) x)
|
||||
(rule 8 (cast_bool $I8 x @ (value_type $B8)) x)
|
||||
(rule 7 (cast_bool (fits_in_16 _ty) x @ (value_type $B16)) x)
|
||||
(rule 6 (cast_bool (fits_in_32 _ty) x @ (value_type $B32)) x)
|
||||
(rule 5 (cast_bool (fits_in_64 _ty) x @ (value_type $B64)) x)
|
||||
(rule 4 (cast_bool (vr128_ty _ty) x @ (value_type $B128)) x)
|
||||
(rule 5 (cast_bool (fits_in_64 _ty) x @ (value_type $B128))
|
||||
(vec_extract_lane $I64X2 x 1 (zero_reg)))
|
||||
|
||||
;; Single-bit values are sign-extended via a pair of shifts.
|
||||
(rule 0 (cast_bool (gpr32_ty ty) x @ (value_type $B1))
|
||||
(ashr_imm $I32 (lshl_imm $I32 x 31) 31))
|
||||
(rule 1 (cast_bool (gpr64_ty ty) x @ (value_type $B1))
|
||||
(ashr_imm $I64 (lshl_imm $I64 x 63) 63))
|
||||
(rule 4 (cast_bool (vr128_ty ty) x @ (value_type $B1))
|
||||
(let ((gpr Reg (ashr_imm $I64 (lshl_imm $I64 x 63) 63)))
|
||||
(mov_to_vec128 ty gpr gpr)))
|
||||
|
||||
;; Other values are just sign-extended normally.
|
||||
(rule 0 (cast_bool (gpr32_ty _ty) x @ (value_type $B8))
|
||||
(sext32_reg $I8 x))
|
||||
(rule 0 (cast_bool (gpr32_ty _ty) x @ (value_type $B16))
|
||||
(sext32_reg $I16 x))
|
||||
(rule 1(cast_bool (gpr64_ty _ty) x @ (value_type $B8))
|
||||
(sext64_reg $I8 x))
|
||||
(rule 1(cast_bool (gpr64_ty _ty) x @ (value_type $B16))
|
||||
(sext64_reg $I16 x))
|
||||
(rule 1(cast_bool (gpr64_ty _ty) x @ (value_type $B32))
|
||||
(sext64_reg $I32 x))
|
||||
(rule 3 (cast_bool (vr128_ty ty) x @ (value_type (gpr32_ty src_ty)))
|
||||
(let ((x_ext Reg (sext64_reg src_ty x)))
|
||||
(mov_to_vec128 ty x_ext x_ext)))
|
||||
(rule 2 (cast_bool (vr128_ty ty) x @ (value_type (gpr64_ty src_ty)))
|
||||
(mov_to_vec128 ty x x))
|
||||
|
||||
|
||||
;;;; Rules for `bint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Mask with 1 to get a 0/1 result (8- or 16-bit result types).
|
||||
(rule 5 (lower (has_type (fits_in_16 ty) (bint x @ (value_type (fits_in_64 _)))))
|
||||
(and_uimm16shifted ty x (uimm16shifted 1 0)))
|
||||
|
||||
;; Mask with 1 to get a 0/1 result (32-bit result types).
|
||||
(rule 4 (lower (has_type (fits_in_32 ty) (bint x @ (value_type (fits_in_64 _)))))
|
||||
(and_uimm32shifted ty x (uimm32shifted 1 0)))
|
||||
|
||||
;; Mask with 1 to get a 0/1 result (64-bit result types).
|
||||
(rule 3 (lower (has_type (fits_in_64 ty) (bint x @ (value_type (fits_in_64 _)))))
|
||||
(and_reg ty x (imm ty 1)))
|
||||
|
||||
;; Mask with 1 to get a 0/1 result (128-bit result types).
|
||||
(rule 1 (lower (has_type (vr128_ty ty) (bint x @ (value_type (fits_in_64 _)))))
|
||||
(let ((x_ext Reg (and_uimm16shifted $I8 x (uimm16shifted 1 0))))
|
||||
(vec_insert_lane $I8X16 (vec_imm ty 0) x_ext 15 (zero_reg))))
|
||||
|
||||
;; Mask with 1 to get a 0/1 result (128-bit source types).
|
||||
(rule 2 (lower (has_type (fits_in_64 ty) (bint x @ (value_type (vr128_ty _)))))
|
||||
(let ((x_gpr Reg (vec_extract_lane $I8X16 x 15 (zero_reg))))
|
||||
(and_uimm16shifted ty x_gpr (uimm16shifted 1 0))))
|
||||
|
||||
;; Mask with 1 to get a 0/1 result (128-bit source and result types).
|
||||
(rule 0 (lower (has_type (vr128_ty ty) (bint x @ (value_type (vr128_ty _)))))
|
||||
(vec_and ty x (vec_imm ty 1)))
|
||||
(lower_bool_to_mask ty (value_nonzero x)))
|
||||
|
||||
|
||||
;;;; Rules for `bitrev` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -1864,7 +1774,7 @@
|
||||
(rule 1 (lower (insertlane x @ (value_type ty)
|
||||
y @ (value_type in_ty)
|
||||
(u8_from_uimm8 idx)))
|
||||
(if (ty_int_bool_ref_scalar_64 in_ty))
|
||||
(if (ty_int_ref_scalar_64 in_ty))
|
||||
(vec_insert_lane ty x y (be_lane_idx ty idx) (zero_reg)))
|
||||
|
||||
;; Insert vector lane from floating-point register.
|
||||
@@ -1980,7 +1890,7 @@
|
||||
;; Extract vector lane to general-purpose register.
|
||||
(rule 1 (lower (has_type out_ty
|
||||
(extractlane x @ (value_type ty) (u8_from_uimm8 idx))))
|
||||
(if (ty_int_bool_ref_scalar_64 out_ty))
|
||||
(if (ty_int_ref_scalar_64 out_ty))
|
||||
(vec_extract_lane ty x (be_lane_idx ty idx) (zero_reg)))
|
||||
|
||||
;; Extract vector lane to floating-point register.
|
||||
@@ -2037,7 +1947,7 @@
|
||||
|
||||
;; Load replicated value from general-purpose register.
|
||||
(rule 1 (lower (has_type ty (splat x @ (value_type in_ty))))
|
||||
(if (ty_int_bool_ref_scalar_64 in_ty))
|
||||
(if (ty_int_ref_scalar_64 in_ty))
|
||||
(vec_replicate_lane ty (vec_insert_lane_undef ty x 0 (zero_reg)) 0))
|
||||
|
||||
;; Load replicated value from floating-point register.
|
||||
@@ -2097,7 +2007,7 @@
|
||||
;; Load scalar value from general-purpose register.
|
||||
(rule 1 (lower (has_type ty (scalar_to_vector
|
||||
x @ (value_type in_ty))))
|
||||
(if (ty_int_bool_ref_scalar_64 in_ty))
|
||||
(if (ty_int_ref_scalar_64 in_ty))
|
||||
(vec_insert_lane ty (vec_imm ty 0) x (be_lane_idx ty 0) (zero_reg)))
|
||||
|
||||
;; Load scalar value from floating-point register.
|
||||
@@ -3783,14 +3693,14 @@
|
||||
;;;; Rules for `is_null` and `is_invalid` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Null references are represented by the constant value 0.
|
||||
(rule (lower (has_type $B1 (is_null x @ (value_type $R64))))
|
||||
(lower_bool $B1 (bool (icmps_simm16 $I64 x 0)
|
||||
(rule (lower (has_type $I8 (is_null x @ (value_type $R64))))
|
||||
(lower_bool $I8 (bool (icmps_simm16 $I64 x 0)
|
||||
(intcc_as_cond (IntCC.Equal)))))
|
||||
|
||||
|
||||
;; Invalid references are represented by the constant value -1.
|
||||
(rule (lower (has_type $B1 (is_invalid x @ (value_type $R64))))
|
||||
(lower_bool $B1 (bool (icmps_simm16 $I64 x -1)
|
||||
(rule (lower (has_type $I8 (is_invalid x @ (value_type $R64))))
|
||||
(lower_bool $I8 (bool (icmps_simm16 $I64 x -1)
|
||||
(intcc_as_cond (IntCC.Equal)))))
|
||||
|
||||
|
||||
@@ -3798,10 +3708,9 @@
|
||||
|
||||
;; Return a `ProducesBool` to capture the fact that the input value is nonzero.
|
||||
;; In the common case where that input is the result of an `icmp` or `fcmp`
|
||||
;; instruction (possibly via an intermediate `bint`), directly use that compare.
|
||||
;; Note that it is not safe to sink memory loads here, see the `icmp` comment.
|
||||
;; instruction, directly use that compare. Note that it is not safe to sink
|
||||
;; memory loads here, see the `icmp` comment.
|
||||
(decl value_nonzero (Value) ProducesBool)
|
||||
(rule (value_nonzero (bint val)) (value_nonzero val))
|
||||
(rule (value_nonzero (icmp int_cc x y)) (icmp_val $false int_cc x y))
|
||||
(rule (value_nonzero (fcmp float_cc x y)) (fcmp_val float_cc x y))
|
||||
(rule -1 (value_nonzero val @ (value_type (gpr32_ty ty)))
|
||||
|
||||
@@ -45,7 +45,6 @@ impl LowerBackend for S390xBackend {
|
||||
Opcode::Nop
|
||||
| Opcode::Copy
|
||||
| Opcode::Iconst
|
||||
| Opcode::Bconst
|
||||
| Opcode::F32const
|
||||
| Opcode::F64const
|
||||
| Opcode::Vconst
|
||||
@@ -100,10 +99,7 @@ impl LowerBackend for S390xBackend {
|
||||
| Opcode::BxorNot
|
||||
| Opcode::Bitselect
|
||||
| Opcode::Vselect
|
||||
| Opcode::Breduce
|
||||
| Opcode::Bextend
|
||||
| Opcode::Bmask
|
||||
| Opcode::Bint
|
||||
| Opcode::Bitrev
|
||||
| Opcode::Clz
|
||||
| Opcode::Cls
|
||||
|
||||
@@ -252,7 +252,7 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6>
|
||||
#[inline]
|
||||
fn gpr32_ty(&mut self, ty: Type) -> Option<Type> {
|
||||
match ty {
|
||||
I8 | I16 | I32 | B1 | B8 | B16 | B32 => Some(ty),
|
||||
I8 | I16 | I32 => Some(ty),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -260,7 +260,7 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6>
|
||||
#[inline]
|
||||
fn gpr64_ty(&mut self, ty: Type) -> Option<Type> {
|
||||
match ty {
|
||||
I64 | B64 | R64 => Some(ty),
|
||||
I64 | R64 => Some(ty),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -268,7 +268,7 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6>
|
||||
#[inline]
|
||||
fn vr128_ty(&mut self, ty: Type) -> Option<Type> {
|
||||
match ty {
|
||||
I128 | B128 => Some(ty),
|
||||
I128 => Some(ty),
|
||||
_ if ty.is_vector() && ty.bits() == 128 => Some(ty),
|
||||
_ => None,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user