cranelift: Fuzz icmp and fcmp (#4713)

* cranelift: Add `fcmp` to fuzzer

* cranelift: Add IntCC::all()

* cranelift: Add `icmp` to fuzzer
This commit is contained in:
Afonso Bordado
2022-08-16 00:16:50 +01:00
committed by GitHub
parent 498e7156b4
commit 0f944937c0
2 changed files with 86 additions and 59 deletions

View File

@@ -100,6 +100,24 @@ impl CondCode for IntCC {
} }
impl IntCC { impl IntCC {
/// Returns a slice with all possible [IntCC] values.
pub fn all() -> &'static [IntCC] {
&[
IntCC::Equal,
IntCC::NotEqual,
IntCC::SignedLessThan,
IntCC::SignedGreaterThanOrEqual,
IntCC::SignedGreaterThan,
IntCC::SignedLessThanOrEqual,
IntCC::UnsignedLessThan,
IntCC::UnsignedGreaterThanOrEqual,
IntCC::UnsignedGreaterThan,
IntCC::UnsignedLessThanOrEqual,
IntCC::Overflow,
IntCC::NotOverflow,
]
}
/// Get the corresponding IntCC with the equal component removed. /// Get the corresponding IntCC with the equal component removed.
/// For conditions without a zero component, this is a no-op. /// For conditions without a zero component, this is a no-op.
pub fn without_equal(self) -> Self { pub fn without_equal(self) -> Self {
@@ -227,6 +245,28 @@ pub enum FloatCC {
UnorderedOrGreaterThanOrEqual, UnorderedOrGreaterThanOrEqual,
} }
impl FloatCC {
/// Returns a slice with all possible [FloatCC] values.
pub fn all() -> &'static [FloatCC] {
&[
FloatCC::Ordered,
FloatCC::Unordered,
FloatCC::Equal,
FloatCC::NotEqual,
FloatCC::OrderedNotEqual,
FloatCC::UnorderedOrEqual,
FloatCC::LessThan,
FloatCC::LessThanOrEqual,
FloatCC::GreaterThan,
FloatCC::GreaterThanOrEqual,
FloatCC::UnorderedOrLessThan,
FloatCC::UnorderedOrLessThanOrEqual,
FloatCC::UnorderedOrGreaterThan,
FloatCC::UnorderedOrGreaterThanOrEqual,
]
}
}
impl CondCode for FloatCC { impl CondCode for FloatCC {
fn inverse(self) -> Self { fn inverse(self) -> Self {
use self::FloatCC::*; use self::FloatCC::*;
@@ -320,24 +360,9 @@ mod tests {
use super::*; use super::*;
use std::string::ToString; use std::string::ToString;
static INT_ALL: [IntCC; 12] = [
IntCC::Equal,
IntCC::NotEqual,
IntCC::SignedLessThan,
IntCC::SignedGreaterThanOrEqual,
IntCC::SignedGreaterThan,
IntCC::SignedLessThanOrEqual,
IntCC::UnsignedLessThan,
IntCC::UnsignedGreaterThanOrEqual,
IntCC::UnsignedGreaterThan,
IntCC::UnsignedLessThanOrEqual,
IntCC::Overflow,
IntCC::NotOverflow,
];
#[test] #[test]
fn int_inverse() { fn int_inverse() {
for r in &INT_ALL { for r in IntCC::all() {
let cc = *r; let cc = *r;
let inv = cc.inverse(); let inv = cc.inverse();
assert!(cc != inv); assert!(cc != inv);
@@ -347,7 +372,7 @@ mod tests {
#[test] #[test]
fn int_reverse() { fn int_reverse() {
for r in &INT_ALL { for r in IntCC::all() {
let cc = *r; let cc = *r;
let rev = cc.reverse(); let rev = cc.reverse();
assert_eq!(rev.reverse(), cc); assert_eq!(rev.reverse(), cc);
@@ -356,33 +381,16 @@ mod tests {
#[test] #[test]
fn int_display() { fn int_display() {
for r in &INT_ALL { for r in IntCC::all() {
let cc = *r; let cc = *r;
assert_eq!(cc.to_string().parse(), Ok(cc)); assert_eq!(cc.to_string().parse(), Ok(cc));
} }
assert_eq!("bogus".parse::<IntCC>(), Err(())); assert_eq!("bogus".parse::<IntCC>(), Err(()));
} }
static FLOAT_ALL: [FloatCC; 14] = [
FloatCC::Ordered,
FloatCC::Unordered,
FloatCC::Equal,
FloatCC::NotEqual,
FloatCC::OrderedNotEqual,
FloatCC::UnorderedOrEqual,
FloatCC::LessThan,
FloatCC::LessThanOrEqual,
FloatCC::GreaterThan,
FloatCC::GreaterThanOrEqual,
FloatCC::UnorderedOrLessThan,
FloatCC::UnorderedOrLessThanOrEqual,
FloatCC::UnorderedOrGreaterThan,
FloatCC::UnorderedOrGreaterThanOrEqual,
];
#[test] #[test]
fn float_inverse() { fn float_inverse() {
for r in &FLOAT_ALL { for r in FloatCC::all() {
let cc = *r; let cc = *r;
let inv = cc.inverse(); let inv = cc.inverse();
assert!(cc != inv); assert!(cc != inv);
@@ -392,7 +400,7 @@ mod tests {
#[test] #[test]
fn float_reverse() { fn float_reverse() {
for r in &FLOAT_ALL { for r in FloatCC::all() {
let cc = *r; let cc = *r;
let rev = cc.reverse(); let rev = cc.reverse();
assert_eq!(rev.reverse(), cc); assert_eq!(rev.reverse(), cc);
@@ -401,7 +409,7 @@ mod tests {
#[test] #[test]
fn float_display() { fn float_display() {
for r in &FLOAT_ALL { for r in FloatCC::all() {
let cc = *r; let cc = *r;
assert_eq!(cc.to_string().parse(), Ok(cc)); assert_eq!(cc.to_string().parse(), Ok(cc));
} }

View File

@@ -9,7 +9,8 @@ use cranelift::codegen::ir::{
use cranelift::codegen::isa::CallConv; use cranelift::codegen::isa::CallConv;
use cranelift::frontend::{FunctionBuilder, FunctionBuilderContext, Switch, Variable}; use cranelift::frontend::{FunctionBuilder, FunctionBuilderContext, Switch, Variable};
use cranelift::prelude::{ use cranelift::prelude::{
EntityRef, ExtFuncData, InstBuilder, IntCC, JumpTableData, StackSlotData, StackSlotKind, EntityRef, ExtFuncData, FloatCC, InstBuilder, IntCC, JumpTableData, StackSlotData,
StackSlotKind,
}; };
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::RangeInclusive; use std::ops::RangeInclusive;
@@ -110,6 +111,32 @@ fn insert_stack_store(
Ok(()) Ok(())
} }
fn insert_cmp(
fgen: &mut FunctionGenerator,
builder: &mut FunctionBuilder,
opcode: Opcode,
args: &'static [Type],
rets: &'static [Type],
) -> Result<()> {
let lhs = fgen.get_variable_of_type(args[0])?;
let lhs = builder.use_var(lhs);
let rhs = fgen.get_variable_of_type(args[1])?;
let rhs = builder.use_var(rhs);
let res = if opcode == Opcode::Fcmp {
let cc = *fgen.u.choose(FloatCC::all())?;
builder.ins().fcmp(cc, lhs, rhs)
} else {
let cc = *fgen.u.choose(IntCC::all())?;
builder.ins().icmp(cc, lhs, rhs)
};
let var = fgen.get_variable_of_type(rets[0])?;
builder.def_var(var, res);
Ok(())
}
fn insert_const( fn insert_const(
fgen: &mut FunctionGenerator, fgen: &mut FunctionGenerator,
builder: &mut FunctionBuilder, builder: &mut FunctionBuilder,
@@ -391,6 +418,17 @@ const OPCODE_SIGNATURES: &'static [(
// Nearest // Nearest
(Opcode::Nearest, &[F32], &[F32], insert_opcode), (Opcode::Nearest, &[F32], &[F32], insert_opcode),
(Opcode::Nearest, &[F64], &[F64], insert_opcode), (Opcode::Nearest, &[F64], &[F64], insert_opcode),
// Fcmp
(Opcode::Fcmp, &[F32, F32], &[B1], insert_cmp),
(Opcode::Fcmp, &[F64, F64], &[B1], insert_cmp),
// Icmp
(Opcode::Icmp, &[I8, I8], &[B1], insert_cmp),
(Opcode::Icmp, &[I16, I16], &[B1], insert_cmp),
(Opcode::Icmp, &[I32, I32], &[B1], insert_cmp),
(Opcode::Icmp, &[I64, I64], &[B1], insert_cmp),
// TODO: icmp of/nof broken for i128 on x86_64
// See: https://github.com/bytecodealliance/wasmtime/issues/4406
// (Opcode::Icmp, &[I128, I128], &[B1], insert_cmp),
// Stack Access // Stack Access
(Opcode::StackStore, &[I8], &[], insert_stack_store), (Opcode::StackStore, &[I8], &[], insert_stack_store),
(Opcode::StackStore, &[I16], &[], insert_stack_store), (Opcode::StackStore, &[I16], &[], insert_stack_store),
@@ -458,25 +496,6 @@ where
Ok(CallConv::SystemV) Ok(CallConv::SystemV)
} }
fn generate_intcc(&mut self) -> Result<IntCC> {
Ok(*self.u.choose(
&[
IntCC::Equal,
IntCC::NotEqual,
IntCC::SignedLessThan,
IntCC::SignedGreaterThanOrEqual,
IntCC::SignedGreaterThan,
IntCC::SignedLessThanOrEqual,
IntCC::UnsignedLessThan,
IntCC::UnsignedGreaterThanOrEqual,
IntCC::UnsignedGreaterThan,
IntCC::UnsignedLessThanOrEqual,
IntCC::Overflow,
IntCC::NotOverflow,
][..],
)?)
}
fn generate_type(&mut self) -> Result<Type> { fn generate_type(&mut self) -> Result<Type> {
// TODO: It would be nice if we could get these directly from cranelift // TODO: It would be nice if we could get these directly from cranelift
let scalars = [ let scalars = [
@@ -681,7 +700,7 @@ where
fn generate_bricmp(&mut self, builder: &mut FunctionBuilder) -> Result<()> { fn generate_bricmp(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
let (block, args) = self.generate_target_block(builder)?; let (block, args) = self.generate_target_block(builder)?;
let cond = self.generate_intcc()?; let cond = *self.u.choose(IntCC::all())?;
let bricmp_types = [ let bricmp_types = [
I8, I16, I32, I8, I16, I32,