1 //! Run commands. 2 //! 3 //! Functions in a `.clif` file can have *run commands* appended that control how a function is 4 //! invoked and tested within the `test run` context. The general syntax is: 5 //! 6 //! - `; run`: this assumes the function has a signature like `() -> b*`. 7 //! - `; run: %fn(42, 4.2) == false`: this syntax specifies the parameters and return values. 8 9 use cranelift_codegen::ir::immediates::{Ieee32, Ieee64}; 10 use cranelift_codegen::ir::ConstantData; 11 use std::fmt::{Display, Formatter, Result}; 12 13 /// A run command appearing in a test file. 14 /// 15 /// For parsing, see 16 /// [Parser::parse_run_command](crate::parser::Parser::parse_run_command). 17 #[derive(PartialEq, Debug)] 18 pub enum RunCommand { 19 /// Invoke a function and print its result. 20 Print(Invocation), 21 /// Invoke a function and compare its result to a value sequence. 22 Run(Invocation, Comparison, Vec<DataValue>), 23 } 24 25 impl Display for RunCommand { 26 fn fmt(&self, f: &mut Formatter) -> Result { 27 match self { 28 RunCommand::Print(invocation) => write!(f, "print: {}", invocation), 29 RunCommand::Run(invocation, comparison, expected) => { 30 write!(f, "run: {} {} ", invocation, comparison)?; 31 if expected.len() == 1 { 32 write!(f, "{}", expected[0]) 33 } else { 34 write!(f, "[")?; 35 write_data_value_list(f, expected)?; 36 write!(f, "]") 37 } 38 } 39 } 40 } 41 } 42 43 /// Represent a function call; [RunCommand]s invoke a CLIF function using an [Invocation]. 44 #[derive(Debug, PartialEq)] 45 pub struct Invocation { 46 /// The name of the function to call. Note: this field is for mostly included for informational 47 /// purposes and may not always be necessary for identifying which function to call. 48 pub func: String, 49 /// The arguments to be passed to the function when invoked. 50 pub args: Vec<DataValue>, 51 } 52 53 impl Invocation { 54 pub(crate) fn new(func: &str, args: Vec<DataValue>) -> Self { 55 let func = func.to_string(); 56 Self { func, args } 57 } 58 } 59 60 impl Display for Invocation { 61 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 62 write!(f, "%{}(", self.func)?; 63 write_data_value_list(f, &self.args)?; 64 write!(f, ")") 65 } 66 } 67 68 /// Represent a data value. Where [Value] is an SSA reference, [DataValue] is the type + value 69 /// that would be referred to by a [Value]. 70 /// 71 /// [Value]: cranelift_codegen::ir::Value 72 #[allow(missing_docs)] 73 #[derive(Clone, Debug, PartialEq)] 74 pub enum DataValue { 75 B(bool), 76 I8(i8), 77 I16(i16), 78 I32(i32), 79 I64(i64), 80 F32(f32), 81 F64(f64), 82 V128([u8; 16]), 83 } 84 85 /// Helper for creating [From] implementations for [DataValue] 86 macro_rules! from_data { 87 ( $ty:ty, $variant:ident ) => { 88 impl From<$ty> for DataValue { 89 fn from(data: $ty) -> Self { 90 DataValue::$variant(data) 91 } 92 } 93 }; 94 } 95 from_data!(bool, B); 96 from_data!(i8, I8); 97 from_data!(i16, I16); 98 from_data!(i32, I32); 99 from_data!(i64, I64); 100 from_data!(f32, F32); 101 from_data!(f64, F64); 102 from_data!([u8; 16], V128); 103 104 impl Display for DataValue { 105 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 106 match self { 107 DataValue::B(dv) => write!(f, "{}", dv), 108 DataValue::I8(dv) => write!(f, "{}", dv), 109 DataValue::I16(dv) => write!(f, "{}", dv), 110 DataValue::I32(dv) => write!(f, "{}", dv), 111 DataValue::I64(dv) => write!(f, "{}", dv), 112 // Use the Ieee* wrappers here to maintain a consistent syntax. 113 DataValue::F32(dv) => write!(f, "{}", Ieee32::from(*dv)), 114 DataValue::F64(dv) => write!(f, "{}", Ieee64::from(*dv)), 115 // Again, for syntax consistency, use ConstantData, which in this case displays as hex. 116 DataValue::V128(dv) => write!(f, "{}", ConstantData::from(&dv[..])), 117 } 118 } 119 } 120 121 /// Helper function for displaying `Vec<DataValue>`. 122 fn write_data_value_list(f: &mut Formatter<'_>, list: &[DataValue]) -> Result { 123 match list.len() { 124 0 => Ok(()), 125 1 => write!(f, "{}", list[0]), 126 _ => { 127 write!(f, "{}", list[0])?; 128 for dv in list.iter().skip(1) { 129 write!(f, ", {}", dv)?; 130 } 131 Ok(()) 132 } 133 } 134 } 135 136 /// A CLIF comparison operation; e.g. `==`. 137 #[allow(missing_docs)] 138 #[derive(Debug, PartialEq)] 139 pub enum Comparison { 140 Equals, 141 NotEquals, 142 } 143 144 impl Display for Comparison { 145 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 146 match self { 147 Comparison::Equals => write!(f, "=="), 148 Comparison::NotEquals => write!(f, "!="), 149 } 150 } 151 } 152