diff --git a/cranelift/filetests/filetests/runtests/br_icmp_overflow.clif b/cranelift/filetests/filetests/runtests/br_icmp_overflow.clif new file mode 100644 index 0000000000..71c3a43169 --- /dev/null +++ b/cranelift/filetests/filetests/runtests/br_icmp_overflow.clif @@ -0,0 +1,217 @@ +test interpret +test run +target aarch64 +target x86_64 machinst + +; TODO: Merge this with the main br_icmp file when s390x supports overflows. +; See: https://github.com/bytecodealliance/wasmtime/issues/3060 + +function %bricmp_of_i64(i64, i64) -> b1 { +block0(v0: i64, v1: i64): + br_icmp.i64 of v0, v1, block2 + jump block1 + +block1: + v2 = bconst.b1 false + return v2 + +block2: + v3 = bconst.b1 true + return v3 +} +; run: %bricmp_of_i64(0, 0) == false +; run: %bricmp_of_i64(0, 1) == false +; run: %bricmp_of_i64(1, 0) == false +; run: %bricmp_of_i64(0, -1) == false +; run: %bricmp_of_i64(0x80000000_00000000, 0x80000000_00000000) == false +; run: %bricmp_of_i64(0x7FFFFFFF_FFFFFFFF, 1) == false +; run: %bricmp_of_i64(0x7FFFFFFF_FFFFFFFF, 0x7FFFFFFF_FFFFFFFF) == false +; run: %bricmp_of_i64(0xFFFFFFFF_FFFFFFFF, 1) == false +; run: %bricmp_of_i64(0x80000000_00000000, 1) == true +; run: %bricmp_of_i64(0x7FFFFFFF_FFFFFFFF, 0x80000000_00000000) == true +; run: %bricmp_of_i64(0x80000000_00000000, 0x7FFFFFFF_FFFFFFFF) == true +; run: %bricmp_of_i64(0x7FFFFFFF_FFFFFFFF, 0xFFFFFFFF_FFFFFFFF) == true + +function %bricmp_of_i32(i32, i32) -> b1 { +block0(v0: i32, v1: i32): + br_icmp.i32 of v0, v1, block2 + jump block1 + +block1: + v2 = bconst.b1 false + return v2 + +block2: + v3 = bconst.b1 true + return v3 +} +; run: %bricmp_of_i32(0, 0) == false +; run: %bricmp_of_i32(0, 1) == false +; run: %bricmp_of_i32(1, 0) == false +; run: %bricmp_of_i32(0, -1) == false +; run: %bricmp_of_i32(0x80000000, 0x80000000) == false +; run: %bricmp_of_i32(0x7FFFFFFF, 1) == false +; run: %bricmp_of_i32(0x7FFFFFFF, 0x7FFFFFFF) == false +; run: %bricmp_of_i32(0xFFFFFFFF, 1) == false +; run: %bricmp_of_i32(0x80000000, 1) == true +; run: %bricmp_of_i32(0x7FFFFFFF, 0x80000000) == true +; run: %bricmp_of_i32(0x80000000, 0x7FFFFFFF) == true +; run: %bricmp_of_i32(0x7FFFFFFF, 0xFFFFFFFF) == true + +function %bricmp_of_i16(i16, i16) -> b1 { +block0(v0: i16, v1: i16): + br_icmp.i16 of v0, v1, block2 + jump block1 + +block1: + v2 = bconst.b1 false + return v2 + +block2: + v3 = bconst.b1 true + return v3 +} +; run: %bricmp_of_i16(0, 0) == false +; run: %bricmp_of_i16(0, 1) == false +; run: %bricmp_of_i16(1, 0) == false +; run: %bricmp_of_i16(0, -1) == false +; run: %bricmp_of_i16(0x8000, 0x8000) == false +; run: %bricmp_of_i16(0x7FFF, 1) == false +; run: %bricmp_of_i16(0x7FFF, 0x7FFF) == false +; run: %bricmp_of_i16(0xFFFF, 1) == false +; run: %bricmp_of_i16(0x8000, 1) == true +; run: %bricmp_of_i16(0x7FFF, 0x8000) == true +; run: %bricmp_of_i16(0x8000, 0x7FFF) == true +; run: %bricmp_of_i16(0x7FFF, 0xFFFF) == true + +function %bricmp_of_i8(i8, i8) -> b1 { +block0(v0: i8, v1: i8): + br_icmp.i8 of v0, v1, block2 + jump block1 + +block1: + v2 = bconst.b1 false + return v2 + +block2: + v3 = bconst.b1 true + return v3 +} +; run: %bricmp_of_i8(0, 0) == false +; run: %bricmp_of_i8(0, 1) == false +; run: %bricmp_of_i8(1, 0) == false +; run: %bricmp_of_i8(0, -1) == false +; run: %bricmp_of_i8(0x80, 0x80) == false +; run: %bricmp_of_i8(0x7F, 1) == false +; run: %bricmp_of_i8(0x7F, 0x7F) == false +; run: %bricmp_of_i8(0xFF, 1) == false +; run: %bricmp_of_i8(0x80, 1) == true +; run: %bricmp_of_i8(0x7F, 0x80) == true +; run: %bricmp_of_i8(0x80, 0x7F) == true +; run: %bricmp_of_i8(0x7F, 0xFF) == true + + + +function %bricmp_nof_i64(i64, i64) -> b1 { +block0(v0: i64, v1: i64): + br_icmp.i64 nof v0, v1, block2 + jump block1 + +block1: + v2 = bconst.b1 false + return v2 + +block2: + v3 = bconst.b1 true + return v3 +} +; run: %bricmp_nof_i64(0, 0) == true +; run: %bricmp_nof_i64(0, 1) == true +; run: %bricmp_nof_i64(1, 0) == true +; run: %bricmp_nof_i64(0, -1) == true +; run: %bricmp_nof_i64(0x80000000_00000000, 0x80000000_00000000) == true +; run: %bricmp_nof_i64(0x7FFFFFFF_FFFFFFFF, 1) == true +; run: %bricmp_nof_i64(0x7FFFFFFF_FFFFFFFF, 0x7FFFFFFF_FFFFFFFF) == true +; run: %bricmp_nof_i64(0xFFFFFFFF_FFFFFFFF, 1) == true +; run: %bricmp_nof_i64(0x80000000_00000000, 1) == false +; run: %bricmp_nof_i64(0x7FFFFFFF_FFFFFFFF, 0x80000000_00000000) == false +; run: %bricmp_nof_i64(0x80000000_00000000, 0x7FFFFFFF_FFFFFFFF) == false +; run: %bricmp_nof_i64(0x7FFFFFFF_FFFFFFFF, 0xFFFFFFFF_FFFFFFFF) == false + +function %bricmp_nof_i32(i32, i32) -> b1 { +block0(v0: i32, v1: i32): + br_icmp.i32 nof v0, v1, block2 + jump block1 + +block1: + v2 = bconst.b1 false + return v2 + +block2: + v3 = bconst.b1 true + return v3 +} +; run: %bricmp_nof_i32(0, 0) == true +; run: %bricmp_nof_i32(0, 1) == true +; run: %bricmp_nof_i32(1, 0) == true +; run: %bricmp_nof_i32(0, -1) == true +; run: %bricmp_nof_i32(0x80000000, 0x80000000) == true +; run: %bricmp_nof_i32(0x7FFFFFFF, 1) == true +; run: %bricmp_nof_i32(0x7FFFFFFF, 0x7FFFFFFF) == true +; run: %bricmp_nof_i32(0xFFFFFFFF, 1) == true +; run: %bricmp_nof_i32(0x80000000, 1) == false +; run: %bricmp_nof_i32(0x7FFFFFFF, 0x80000000) == false +; run: %bricmp_nof_i32(0x80000000, 0x7FFFFFFF) == false +; run: %bricmp_nof_i32(0x7FFFFFFF, 0xFFFFFFFF) == false + +function %bricmp_nof_i16(i16, i16) -> b1 { +block0(v0: i16, v1: i16): + br_icmp.i16 nof v0, v1, block2 + jump block1 + +block1: + v2 = bconst.b1 false + return v2 + +block2: + v3 = bconst.b1 true + return v3 +} +; run: %bricmp_nof_i16(0, 0) == true +; run: %bricmp_nof_i16(0, 1) == true +; run: %bricmp_nof_i16(1, 0) == true +; run: %bricmp_nof_i16(0, -1) == true +; run: %bricmp_nof_i16(0x8000, 0x8000) == true +; run: %bricmp_nof_i16(0x7FFF, 1) == true +; run: %bricmp_nof_i16(0x7FFF, 0x7FFF) == true +; run: %bricmp_nof_i16(0xFFFF, 1) == true +; run: %bricmp_nof_i16(0x8000, 1) == false +; run: %bricmp_nof_i16(0x7FFF, 0x8000) == false +; run: %bricmp_nof_i16(0x8000, 0x7FFF) == false +; run: %bricmp_nof_i16(0x7FFF, 0xFFFF) == false + +function %bricmp_nof_i8(i8, i8) -> b1 { +block0(v0: i8, v1: i8): + br_icmp.i8 nof v0, v1, block2 + jump block1 + +block1: + v2 = bconst.b1 false + return v2 + +block2: + v3 = bconst.b1 true + return v3 +} +; run: %bricmp_nof_i8(0, 0) == true +; run: %bricmp_nof_i8(0, 1) == true +; run: %bricmp_nof_i8(1, 0) == true +; run: %bricmp_nof_i8(0, -1) == true +; run: %bricmp_nof_i8(0x80, 0x80) == true +; run: %bricmp_nof_i8(0x7F, 1) == true +; run: %bricmp_nof_i8(0x7F, 0x7F) == true +; run: %bricmp_nof_i8(0xFF, 1) == true +; run: %bricmp_nof_i8(0x80, 1) == false +; run: %bricmp_nof_i8(0x7F, 0x80) == false +; run: %bricmp_nof_i8(0x80, 0x7F) == false +; run: %bricmp_nof_i8(0x7F, 0xFF) == false diff --git a/cranelift/interpreter/src/step.rs b/cranelift/interpreter/src/step.rs index 28699b8273..2843be21f6 100644 --- a/cranelift/interpreter/src/step.rs +++ b/cranelift/interpreter/src/step.rs @@ -720,8 +720,8 @@ where &left.clone().convert(ValueConversionKind::ToUnsigned)?, &right.clone().convert(ValueConversionKind::ToUnsigned)?, )?, - IntCC::Overflow => unimplemented!("IntCC::Overflow"), - IntCC::NotOverflow => unimplemented!("IntCC::NotOverflow"), + IntCC::Overflow => Value::of(left, right)?, + IntCC::NotOverflow => !Value::of(left, right)?, }) } diff --git a/cranelift/interpreter/src/value.rs b/cranelift/interpreter/src/value.rs index bf3e5e2691..492a7e5fef 100644 --- a/cranelift/interpreter/src/value.rs +++ b/cranelift/interpreter/src/value.rs @@ -37,6 +37,7 @@ pub trait Value: Clone + From { Ok(other.eq(self)? || other.gt(self)?) } fn uno(&self, other: &Self) -> ValueResult; + fn of(&self, other: &Self) -> ValueResult; // Arithmetic. fn add(self, other: Self) -> ValueResult; @@ -277,6 +278,16 @@ impl Value for DataValue { Ok(self.is_nan()? || other.is_nan()?) } + fn of(&self, other: &Self) -> ValueResult { + Ok(match (self, other) { + (DataValue::I8(a), DataValue::I8(b)) => a.checked_sub(*b).is_none(), + (DataValue::I16(a), DataValue::I16(b)) => a.checked_sub(*b).is_none(), + (DataValue::I32(a), DataValue::I32(b)) => a.checked_sub(*b).is_none(), + (DataValue::I64(a), DataValue::I64(b)) => a.checked_sub(*b).is_none(), + _ => unimplemented!(), + }) + } + fn add(self, other: Self) -> ValueResult { binary_match!(wrapping_add(&self, &other); [I8, I16, I32, I64]) // TODO: floats must handle NaNs, +/-0 }