1 //! Predicate functions for testing instruction fields.
2 //!
3 //! This module defines functions that are used by the instruction predicates defined by
4 //! `cranelift-codegen/meta/src/cdsl/instructions.rs` classes.
5 //!
6 //! The predicates the operate on integer fields use `Into<i64>` as a shared trait bound. This
7 //! bound is implemented by all the native integer types as well as `Imm64`.
8 //!
9 //! Some of these predicates may be unused in certain ISA configurations, so we suppress the
10 //! dead code warning.
11
12 use crate::ir;
13 use crate::ir::ConstantData;
14
15 /// Check that an integer value is zero.
16 #[allow(dead_code)]
is_zero_int<T: Into<i64>>(x: T) -> bool17 pub fn is_zero_int<T: Into<i64>>(x: T) -> bool {
18 x.into() == 0
19 }
20
21 /// Check that a 64-bit floating point value is zero.
22 #[allow(dead_code)]
is_zero_64_bit_float<T: Into<ir::immediates::Ieee64>>(x: T) -> bool23 pub fn is_zero_64_bit_float<T: Into<ir::immediates::Ieee64>>(x: T) -> bool {
24 let x64 = x.into();
25 x64.bits() == 0
26 }
27
28 /// Check that a 32-bit floating point value is zero.
29 #[allow(dead_code)]
is_zero_32_bit_float<T: Into<ir::immediates::Ieee32>>(x: T) -> bool30 pub fn is_zero_32_bit_float<T: Into<ir::immediates::Ieee32>>(x: T) -> bool {
31 let x32 = x.into();
32 x32.bits() == 0
33 }
34
35 /// Check that a constant contains all zeroes.
36 #[allow(dead_code)]
is_all_zeroes(x: &ConstantData) -> bool37 pub fn is_all_zeroes(x: &ConstantData) -> bool {
38 x.iter().all(|&f| f == 0)
39 }
40
41 /// Check that a constant contains all ones.
42 #[allow(dead_code)]
is_all_ones(x: &ConstantData) -> bool43 pub fn is_all_ones(x: &ConstantData) -> bool {
44 x.iter().all(|&f| f == 0xff)
45 }
46
47 /// Check that `x` is the same as `y`.
48 #[allow(dead_code)]
is_equal<T: Eq + Copy, O: Into<T> + Copy>(x: T, y: O) -> bool49 pub fn is_equal<T: Eq + Copy, O: Into<T> + Copy>(x: T, y: O) -> bool {
50 x == y.into()
51 }
52
53 /// Check that `x` can be represented as a `wd`-bit signed integer with `sc` low zero bits.
54 #[allow(dead_code)]
is_signed_int<T: Into<i64>>(x: T, wd: u8, sc: u8) -> bool55 pub fn is_signed_int<T: Into<i64>>(x: T, wd: u8, sc: u8) -> bool {
56 let s = x.into();
57 s == (s >> sc << (64 - wd + sc) >> (64 - wd))
58 }
59
60 /// Check that `x` can be represented as a `wd`-bit unsigned integer with `sc` low zero bits.
61 #[allow(dead_code)]
is_unsigned_int<T: Into<i64>>(x: T, wd: u8, sc: u8) -> bool62 pub fn is_unsigned_int<T: Into<i64>>(x: T, wd: u8, sc: u8) -> bool {
63 let u = x.into() as u64;
64 // Bit-mask of the permitted bits.
65 let m = (1 << wd) - (1 << sc);
66 u == (u & m)
67 }
68
69 #[allow(dead_code)]
is_colocated_func(func_ref: ir::FuncRef, func: &ir::Function) -> bool70 pub fn is_colocated_func(func_ref: ir::FuncRef, func: &ir::Function) -> bool {
71 func.dfg.ext_funcs[func_ref].colocated
72 }
73
74 #[allow(dead_code)]
is_colocated_data(global_value: ir::GlobalValue, func: &ir::Function) -> bool75 pub fn is_colocated_data(global_value: ir::GlobalValue, func: &ir::Function) -> bool {
76 match func.global_values[global_value] {
77 ir::GlobalValueData::Symbol { colocated, .. } => colocated,
78 _ => panic!("is_colocated_data only makes sense for data with symbolic addresses"),
79 }
80 }
81
82 #[allow(dead_code)]
has_length_of(value_list: &ir::ValueList, num: usize, func: &ir::Function) -> bool83 pub fn has_length_of(value_list: &ir::ValueList, num: usize, func: &ir::Function) -> bool {
84 value_list.len(&func.dfg.value_lists) == num
85 }
86
87 #[cfg(test)]
88 mod tests {
89 use super::*;
90
91 #[test]
cvt_u32()92 fn cvt_u32() {
93 let x1 = 0u32;
94 let x2 = 1u32;
95 let x3 = 0xffff_fff0u32;
96
97 assert!(is_signed_int(x1, 1, 0));
98 assert!(is_signed_int(x1, 2, 1));
99 assert!(is_signed_int(x2, 2, 0));
100 assert!(!is_signed_int(x2, 2, 1));
101
102 // `u32` doesn't sign-extend when converted to `i64`.
103 assert!(!is_signed_int(x3, 8, 0));
104
105 assert!(is_unsigned_int(x1, 1, 0));
106 assert!(is_unsigned_int(x1, 8, 4));
107 assert!(is_unsigned_int(x2, 1, 0));
108 assert!(!is_unsigned_int(x2, 8, 4));
109 assert!(!is_unsigned_int(x3, 1, 0));
110 assert!(is_unsigned_int(x3, 32, 4));
111 }
112
113 #[test]
cvt_imm64()114 fn cvt_imm64() {
115 use crate::ir::immediates::Imm64;
116
117 let x1 = Imm64::new(-8);
118 let x2 = Imm64::new(8);
119
120 assert!(is_signed_int(x1, 16, 2));
121 assert!(is_signed_int(x2, 16, 2));
122 assert!(!is_signed_int(x1, 16, 4));
123 assert!(!is_signed_int(x2, 16, 4));
124 }
125
126 #[test]
check_is_all_zeroes()127 fn check_is_all_zeroes() {
128 assert!(is_all_zeroes(&[0; 16].as_ref().into()));
129 assert!(is_all_zeroes(
130 &vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].into()
131 ));
132 assert!(!is_all_zeroes(&[1; 16].as_ref().into()));
133 }
134
135 #[test]
check_is_all_ones()136 fn check_is_all_ones() {
137 assert!(!is_all_ones(&[0; 16].as_ref().into()));
138 assert!(is_all_ones(&[0xff; 16].as_ref().into()));
139 }
140 }
141