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