Repository: bytecodealliance/wasmtime
Pull request #6199 (2023-04-11 23:58:50)

Remove `unsigned_add_overflow_condition` from TargetIsa and FuncEnvironment
As mentioned in #6198 `unsigned_add_overflow_condition` is no longer used or makes a lot of sense otherwise.
This PR removes it.

However, there is [this note](https://github.com/bytecodealliance/wasmtime/blob/c0166f78f9f9954320b52ef3be258b97410ef15c/cranelift/codegen/src/isa/s390x/lower.isle#L3839-L3842) in the lowering rules for s390x which I can't make sense of.
This rewriting does not seem to take place anywhere and all uses of `IntCC::UnsignedGreaterThan` seem normal enough.
Maybe someone with more experience in that backend can check whether this can be safely deleted, along with the comment in the lowering rules.


Patch:
diff --git a/cranelift/codegen/meta/src/shared/instructions.rs b/cranelift/codegen/meta/src/shared/instructions.rs
index d3b10f8b8..0995f116d 100755
--- a/cranelift/codegen/meta/src/shared/instructions.rs
+++ b/cranelift/codegen/meta/src/shared/instructions.rs
@@ -1615,6 +1615,14 @@ pub(crate) fn define(
 
         When this instruction compares integer vectors, it returns a vector of
         lane-wise comparisons.
+
+        When comparing scalars, the result is:
+            - `1` if the condition holds.
+            - `0` if the condition does not hold.
+
+        When comparing vectors, the result is:
+            - `-1` (i.e. all ones) in each lane where the condition holds.
+            - `0` in each lane where the condition does not hold.
         "#,
             &formats.int_compare,
         )
@@ -2003,31 +2011,6 @@ pub(crate) fn define(
         .operands_out(vec![Operand::new("a", iB)]),
     );
 
-    ig.push(
-        Inst::new(
-            "iadd_cout",
-            r#"
-        Add integers with carry out.
-
-        Same as `iadd` with an additional carry output.
-
-        ```text
-            a &= x + y \pmod 2^B \\
-            c_{out} &= x+y >= 2^B
-        ```
-
-        Polymorphic over all scalar integer types, but does not support vector
-        types.
-        "#,
-            &formats.binary,
-        )
-        .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)])
-        .operands_out(vec![
-            Operand::new("a", iB),
-            Operand::new("c_out", i8).with_doc("Output carry flag"),
-        ]),
-    );
-
     ig.push(
         Inst::new(
             "iadd_carry",
@@ -2227,31 +2210,6 @@ pub(crate) fn define(
         .operands_out(vec![Operand::new("a", iB)]),
     );
 
-    ig.push(
-        Inst::new(
-            "isub_bout",
-            r#"
-        Subtract integers with borrow out.
-
-        Same as `isub` with an additional borrow flag output.
-
-        ```text
-            a &= x - y \pmod 2^B \\
-            b_{out} &= x < y
-        ```
-
-        Polymorphic over all scalar integer types, but does not support vector
-        types.
-        "#,
-            &formats.binary,
-        )
-        .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)])
-        .operands_out(vec![
-            Operand::new("a", iB),
-            Operand::new("b_out", i8).with_doc("Output borrow flag"),
-        ]),
-    );
-
     ig.push(
         Inst::new(
             "isub_borrow",
@@ -2791,6 +2749,14 @@ pub(crate) fn define(
 
         When this instruction compares floating point vectors, it returns a
         vector with the results of lane-wise comparisons.
+
+        When comparing scalars, the result is:
+            - `1` if the condition holds.
+            - `0` if the condition does not hold.
+
+        When comparing vectors, the result is:
+            - `-1` (i.e. all ones) in each lane where the condition holds.
+            - `0` in each lane where the condition does not hold.
         "#,
             &formats.float_compare,
         )
diff --git a/cranelift/codegen/src/inst_predicates.rs b/cranelift/codegen/src/inst_predicates.rs
index f82f41daa..707a01c1a 100644
--- a/cranelift/codegen/src/inst_predicates.rs
+++ b/cranelift/codegen/src/inst_predicates.rs
@@ -60,7 +60,7 @@ pub fn is_pure_for_egraph(func: &Function, inst: Inst) -> bool {
     };
     // Multi-value results do not play nicely with much of the egraph
     // infrastructure. They are in practice used only for multi-return
-    // calls and some other odd instructions (e.g. iadd_cout) which,
+    // calls and some other odd instructions (e.g. uadd_overflow) which,
     // for now, we can afford to leave in place as opaque
     // side-effecting ops. So if more than one result, then the inst
     // is "not pure". Similarly, ops with zero results can be used
diff --git a/cranelift/codegen/src/ir/dfg.rs b/cranelift/codegen/src/ir/dfg.rs
index 507881c77..064179369 100644
--- a/cranelift/codegen/src/ir/dfg.rs
+++ b/cranelift/codegen/src/ir/dfg.rs
@@ -1644,7 +1644,7 @@ mod tests {
         assert_eq!(pos.func.dfg.resolve_aliases(v1), v1);
 
         let arg0 = pos.func.dfg.append_block_param(block0, types::I32);
-        let (s, c) = pos.ins().iadd_cout(v1, arg0);
+        let (s, c) = pos.ins().uadd_overflow(v1, arg0);
         let iadd = match pos.func.dfg.value_def(s) {
             ValueDef::Result(i, 0) => i,
             _ => panic!(),
@@ -1654,7 +1654,7 @@ mod tests {
         pos.func.dfg.clear_results(iadd);
         pos.func.dfg.attach_result(iadd, s);
 
-        // Replace `iadd_cout` with a normal `iadd` and an `icmp`.
+        // Replace `uadd_overflow` with a normal `iadd` and an `icmp`.
         pos.func.dfg.replace(iadd).iadd(v1, arg0);
         let c2 = pos.ins().icmp(IntCC::Equal, s, v1);
         pos.func.dfg.change_to_alias(c, c2);
diff --git a/cranelift/codegen/src/isa/aarch64/lower.isle b/cranelift/codegen/src/isa/aarch64/lower.isle
index 12c9a2a83..1d7cbe4a5 100644
--- a/cranelift/codegen/src/isa/aarch64/lower.isle
+++ b/cranelift/codegen/src/isa/aarch64/lower.isle
@@ -2575,43 +2575,6 @@
             (lower_msb Reg (lsr_imm $I64 lower_msb (imm_shift_from_u8 63))))
         (add_shift $I64 lower_msb upper_msb (lshl_from_u64 $I64 1))))
 
-;;; Rules for `iadd_cout` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-;; For values smaller than a register, we do a normal `add` with both arguments
-;; sign extended. We then check if the output sign bit has flipped.
-(rule 0 (lower (has_type (fits_in_16 ty) (iadd_cout a b)))
-      (let ((extend ExtendOp (lower_extend_op ty (ArgumentExtension.Sext)))
-
-            ;; Instead of emitting two `sxt{b,h}` we do one as an instruction and
-            ;; the other as an extend operation in the `add` instruction.
-            ;;
-            ;; sxtb    a_sext, a
-            ;; add     out, a_sext, b, sxtb
-            ;; cmp     out, out, sxtb
-            ;; cset    out_carry, ne
-            (a_sext Reg (put_in_reg_sext32 a))
-            (out Reg (add_extend_op ty a_sext b extend))
-            (out_carry Reg (with_flags_reg
-                  (cmp_extend (OperandSize.Size32) out out extend)
-                  (cset (Cond.Ne)))))
-      (output_pair
-            (value_reg out)
-            (value_reg out_carry))))
-
-
-;; For register sized add's we just emit a adds+cset, without further masking.
-;;
-;; adds out, a, b
-;; cset carry, vs
-(rule 1 (lower (has_type (ty_32_or_64 ty) (iadd_cout a b)))
-      (let ((out ValueRegs
-              (with_flags
-                  (add_with_flags_paired ty a b)
-                  (cset_paired (Cond.Vs)))))
-      (output_pair
-            (value_regs_get out 0)
-            (value_regs_get out 1))))
-
 ;;; Rules for `uadd_overflow_trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (rule (lower (has_type (fits_in_64 ty) (uadd_overflow_trap a b tc)))
diff --git a/cranelift/codegen/src/isa/aarch64/mod.rs b/cranelift/codegen/src/isa/aarch64/mod.rs
index a5403ca5c..1c3f2809c 100644
--- a/cranelift/codegen/src/isa/aarch64/mod.rs
+++ b/cranelift/codegen/src/isa/aarch64/mod.rs
@@ -1,7 +1,6 @@
 //! ARM 64-bit Instruction Set Architecture.
 
 use crate::dominator_tree::DominatorTree;
-use crate::ir::condcodes::IntCC;
 use crate::ir::{Function, Type};
 use crate::isa::aarch64::settings as aarch64_settings;
 #[cfg(feature = "unwind")]
@@ -134,12 +133,6 @@ impl TargetIsa for AArch64Backend {
         16
     }
 
-    fn unsigned_add_overflow_condition(&self) -> IntCC {
-        // Unsigned `>=`; this corresponds to the carry flag set on aarch64, which happens on
-        // overflow of an add.
-        IntCC::UnsignedGreaterThanOrEqual
-    }
-
     #[cfg(feature = "unwind")]
     fn emit_unwind_info(
         &self,
diff --git a/cranelift/codegen/src/isa/mod.rs b/cranelift/codegen/src/isa/mod.rs
index da778c9b6..6ea98af98 100644
--- a/cranelift/codegen/src/isa/mod.rs
+++ b/cranelift/codegen/src/isa/mod.rs
@@ -286,9 +286,6 @@ pub trait TargetIsa: fmt::Display + Send + Sync {
         Err(RegisterMappingError::UnsupportedArchitecture)
     }
 
-    /// IntCC condition for Unsigned Addition Overflow (Carry).
-    fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC;
-
     /// Creates unwind information for the function.
     ///
     /// Returns `None` if there is no unwind information for the function.
diff --git a/cranelift/codegen/src/isa/riscv64/mod.rs b/cranelift/codegen/src/isa/riscv64/mod.rs
index f567481e9..8babe53e9 100644
--- a/cranelift/codegen/src/isa/riscv64/mod.rs
+++ b/cranelift/codegen/src/isa/riscv64/mod.rs
@@ -2,7 +2,6 @@
 
 use crate::dominator_tree::DominatorTree;
 use crate::ir;
-use crate::ir::condcodes::IntCC;
 use crate::ir::Function;
 
 use crate::isa::riscv64::settings as riscv_settings;
@@ -130,10 +129,6 @@ impl TargetIsa for Riscv64Backend {
         self.isa_flags.iter().collect()
     }
 
-    fn unsigned_add_overflow_condition(&self) -> IntCC {
-        IntCC::UnsignedGreaterThanOrEqual
-    }
-
     #[cfg(feature = "unwind")]
     fn emit_unwind_info(
         &self,
diff --git a/cranelift/codegen/src/isa/s390x/mod.rs b/cranelift/codegen/src/isa/s390x/mod.rs
index d2705e78c..bcd3c733b 100644
--- a/cranelift/codegen/src/isa/s390x/mod.rs
+++ b/cranelift/codegen/src/isa/s390x/mod.rs
@@ -1,7 +1,6 @@
 //! IBM Z 64-bit Instruction Set Architecture.
 
 use crate::dominator_tree::DominatorTree;
-use crate::ir::condcodes::IntCC;
 use crate::ir::{Function, Type};
 use crate::isa::s390x::settings as s390x_settings;
 #[cfg(feature = "unwind")]
@@ -131,15 +130,6 @@ impl TargetIsa for S390xBackend {
         16
     }
 
-    fn unsigned_add_overflow_condition(&self) -> IntCC {
-        // The ADD LOGICAL family of instructions set the condition code
-        // differently from normal comparisons, in a way that cannot be
-        // represented by any of the standard IntCC values.  So we use a
-        // dummy value here, which gets remapped to the correct condition
-        // code mask during lowering.
-        IntCC::UnsignedGreaterThan
-    }
-
     #[cfg(feature = "unwind")]
     fn emit_unwind_info(
         &self,
diff --git a/cranelift/codegen/src/isa/x64/lower.isle b/cranelift/codegen/src/isa/x64/lower.isle
index fab850035..05649b820 100644
--- a/cranelift/codegen/src/isa/x64/lower.isle
+++ b/cranelift/codegen/src/isa/x64/lower.isle
@@ -98,19 +98,6 @@
           (with_flags (x64_add_with_flags_paired $I64 x_lo y_lo)
                       (x64_adc_paired $I64 x_hi y_hi)))))
 
-;;;; Rules for `iadd_cout` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-;; TODO: i8 and i16 support. Requires either learning how to encode ALU
-;; operations on values narrower than 32-bits (better code; big change) or doing
-;; the same extend-to-32-bits trick that aarch64 does (worse code; small
-;; change).
-
-(rule (lower (iadd_cout x y @ (value_type (ty_32_or_64 ty))))
-      (let ((results ValueRegs (with_flags (x64_add_with_flags_paired ty x y)
-                                           (x64_setcc_paired (CC.O)))))
-        (output_pair (value_regs_get results 0)
-                     (value_regs_get results 1))))
-
 ;;;; Helpers for `*_overflow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (decl construct_overflow_op (CC ProducesFlags) InstOutput)
diff --git a/cranelift/codegen/src/isa/x64/mod.rs b/cranelift/codegen/src/isa/x64/mod.rs
index 029c7f9f5..51556a892 100644
--- a/cranelift/codegen/src/isa/x64/mod.rs
+++ b/cranelift/codegen/src/isa/x64/mod.rs
@@ -4,7 +4,7 @@ pub use self::inst::{args, CallInfo, EmitInfo, EmitState, Inst};
 
 use super::{OwnedTargetIsa, TargetIsa};
 use crate::dominator_tree::DominatorTree;
-use crate::ir::{condcodes::IntCC, Function, Type};
+use crate::ir::{Function, Type};
 #[cfg(feature = "unwind")]
 use crate::isa::unwind::systemv;
 use crate::isa::x64::{inst::regs::create_reg_env_systemv, settings as x64_settings};
@@ -124,12 +124,6 @@ impl TargetIsa for X64Backend {
         &self.triple
     }
 
-    fn unsigned_add_overflow_condition(&self) -> IntCC {
-        // Unsigned `<`; this corresponds to the carry flag set on x86, which
-        // indicates an add has overflowed.
-        IntCC::UnsignedLessThan
-    }
-
     #[cfg(feature = "unwind")]
     fn emit_unwind_info(
         &self,
diff --git a/cranelift/codegen/src/opts/selects.isle b/cranelift/codegen/src/opts/selects.isle
index 1fcc6c8d6..ba682fcc3 100644
--- a/cranelift/codegen/src/opts/selects.isle
+++ b/cranelift/codegen/src/opts/selects.isle
@@ -25,24 +25,24 @@
 (rule (simplify (select ty (uge _ x y) y x)) (umin ty x y))
 
 ;; Transform bitselect-of-icmp into {u,s}{min,max} instructions where possible.
-(rule (simplify (bitselect ty (sgt _ x y) x y)) (smax ty x y))
-(rule (simplify (bitselect ty (sge _ x y) x y)) (smax ty x y))
-(rule (simplify (bitselect ty (ugt _ x y) x y)) (umax ty x y))
-(rule (simplify (bitselect ty (uge _ x y) x y)) (umax ty x y))
-(rule (simplify (bitselect ty (slt _ x y) x y)) (smin ty x y))
-(rule (simplify (bitselect ty (sle _ x y) x y)) (smin ty x y))
-(rule (simplify (bitselect ty (ult _ x y) x y)) (umin ty x y))
-(rule (simplify (bitselect ty (ule _ x y) x y)) (umin ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (sgt _ x y) x y)) (smax ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (sge _ x y) x y)) (smax ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (ugt _ x y) x y)) (umax ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (uge _ x y) x y)) (umax ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (slt _ x y) x y)) (smin ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (sle _ x y) x y)) (smin ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (ult _ x y) x y)) (umin ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (ule _ x y) x y)) (umin ty x y))
 
 ;; These are the same rules as above, but when the operands for select are swapped
-(rule (simplify (bitselect ty (slt _ x y) y x)) (smax ty x y))
-(rule (simplify (bitselect ty (sle _ x y) y x)) (smax ty x y))
-(rule (simplify (bitselect ty (ult _ x y) y x)) (umax ty x y))
-(rule (simplify (bitselect ty (ule _ x y) y x)) (umax ty x y))
-(rule (simplify (bitselect ty (sgt _ x y) y x)) (smin ty x y))
-(rule (simplify (bitselect ty (sge _ x y) y x)) (smin ty x y))
-(rule (simplify (bitselect ty (ugt _ x y) y x)) (umin ty x y))
-(rule (simplify (bitselect ty (uge _ x y) y x)) (umin ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (slt _ x y) y x)) (smax ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (sle _ x y) y x)) (smax ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (ult _ x y) y x)) (umax ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (ule _ x y) y x)) (umax ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (sgt _ x y) y x)) (smin ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (sge _ x y) y x)) (smin ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (ugt _ x y) y x)) (umin ty x y))
+(rule (simplify (bitselect ty @ (multi_lane _ _) (uge _ x y) y x)) (umin ty x y))
 
 ;; For floats convert fcmp lt into pseudo_min and gt into pseudo_max
 ;;
diff --git a/cranelift/codegen/src/souper_harvest.rs b/cranelift/codegen/src/souper_harvest.rs
index d818eee9f..02958ed56 100644
--- a/cranelift/codegen/src/souper_harvest.rs
+++ b/cranelift/codegen/src/souper_harvest.rs
@@ -129,7 +129,6 @@ fn harvest_candidate_lhs(
                 | ir::Opcode::Clz
                 | ir::Opcode::Ctz
                 // TODO: ir::Opcode::IaddCarry
-                // TODO: ir::Opcode::IaddCout
                 | ir::Opcode::SaddSat
                 | ir::Opcode::SsubSat
                 | ir::Opcode::UsubSat => true,
@@ -470,7 +469,6 @@ fn harvest_candidate_lhs(
                         ast::Instruction::Cttz { a }.into()
                     }
                     // TODO: ir::Opcode::IaddCarry
-                    // TODO: ir::Opcode::IaddCout
                     (ir::Opcode::SaddSat, _) => {
                         let a = arg(allocs, 0);
                         let b = arg(allocs, 1);
diff --git a/cranelift/fuzzgen/src/function_generator.rs b/cranelift/fuzzgen/src/function_generator.rs
index 940db95b9..b6f118624 100644
--- a/cranelift/fuzzgen/src/function_generator.rs
+++ b/cranelift/fuzzgen/src/function_generator.rs
@@ -465,7 +465,6 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
                 op,
                 args,
                 rets,
-                (Opcode::IaddCout, &([I8, I8] | [I16, I16] | [I128, I128])),
                 (Opcode::UmulOverflow | Opcode::SmulOverflow, &[I128, I128]),
                 (Opcode::Imul, &[I8X16, I8X16]),
                 // https://github.com/bytecodealliance/wasmtime/issues/5468
@@ -583,7 +582,6 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
                 op,
                 args,
                 rets,
-                (Opcode::IaddCout, &[I128, I128]),
                 (Opcode::UmulOverflow | Opcode::SmulOverflow, &[I128, I128]),
                 // https://github.com/bytecodealliance/wasmtime/issues/4864
                 (Opcode::Udiv | Opcode::Sdiv, &[I128, I128]),
@@ -639,7 +637,6 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
                 op,
                 args,
                 rets,
-                (Opcode::IaddCout),
                 (Opcode::UaddOverflow | Opcode::SaddOverflow),
                 (Opcode::UsubOverflow | Opcode::SsubOverflow),
                 (Opcode::UmulOverflow | Opcode::SmulOverflow),
@@ -686,7 +683,6 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
                 args,
                 rets,
                 // TODO
-                (Opcode::IaddCout),
                 (Opcode::UaddOverflow | Opcode::SaddOverflow),
                 (Opcode::UsubOverflow | Opcode::SsubOverflow),
                 (Opcode::UmulOverflow | Opcode::SmulOverflow),
@@ -863,7 +859,6 @@ static OPCODE_SIGNATURES: Lazy<Vec<OpcodeSignature>> = Lazy::new(|| {
                 (Opcode::IaddCarry),
                 (Opcode::UaddOverflowTrap),
                 (Opcode::IsubBin),
-                (Opcode::IsubBout),
                 (Opcode::IsubBorrow),
                 (Opcode::BandImm),
                 (Opcode::BorImm),
diff --git a/cranelift/interpreter/src/step.rs b/cranelift/interpreter/src/step.rs
index 129a5cd22..a4e46e1c8 100644
--- a/cranelift/interpreter/src/step.rs
+++ b/cranelift/interpreter/src/step.rs
@@ -802,11 +802,6 @@ where
             )?,
             DataValueExt::add(arg(0), arg(1))?,
         ),
-        Opcode::IaddCout => {
-            let carry = arg(0).checked_add(arg(1))?.is_none();
-            let sum = arg(0).add(arg(1))?;
-            assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?])
-        }
         Opcode::IaddCarry => {
             let mut sum = DataValueExt::add(arg(0), arg(1))?;
             let mut carry = arg(0).checked_add(arg(1))?.is_none();
@@ -838,11 +833,6 @@ where
             )?,
             DataValueExt::sub(arg(0), arg(1))?,
         ),
-        Opcode::IsubBout => {
-            let sum = DataValueExt::sub(arg(0), arg(1))?;
-            let borrow = arg(0) < arg(1);
-            assign_multiple(&[sum, DataValueExt::bool(borrow, false, types::I8)?])
-        }
         Opcode::IsubBorrow => {
             let rhs = if DataValueExt::into_bool(arg(2))? {
                 DataValueExt::add(arg(1), DataValueExt::int(1, ctrl_ty)?)?
diff --git a/cranelift/wasm/src/environ/dummy.rs b/cranelift/wasm/src/environ/dummy.rs
index 030e0c9ed..d17eda818 100644
--- a/cranelift/wasm/src/environ/dummy.rs
+++ b/cranelift/wasm/src/environ/dummy.rs
@@ -655,10 +655,6 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
     ) -> WasmResult<ir::Value> {
         Ok(pos.ins().iconst(I32, 0))
     }
-
-    fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC {
-        unimplemented!()
-    }
 }
 
 impl TargetEnvironment for DummyEnvironment {
diff --git a/cranelift/wasm/src/environ/spec.rs b/cranelift/wasm/src/environ/spec.rs
index 03121c8c9..63712c3b9 100644
--- a/cranelift/wasm/src/environ/spec.rs
+++ b/cranelift/wasm/src/environ/spec.rs
@@ -522,10 +522,6 @@ pub trait FuncEnvironment: TargetEnvironment {
         Ok(())
     }
 
-    /// Returns the target ISA's condition to check for unsigned addition
-    /// overflowing.
-    fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC;
-
     /// Whether or not to force relaxed simd instructions to have deterministic
     /// lowerings meaning they will produce the same results across all hosts,
     /// regardless of the cost to performance.
diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs
index 55272b1b9..305d12355 100644
--- a/crates/cranelift/src/func_environ.rs
+++ b/crates/cranelift/src/func_environ.rs
@@ -2150,10 +2150,6 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
         Ok(())
     }
 
-    fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC {
-        self.isa.unsigned_add_overflow_condition()
-    }
-
     fn relaxed_simd_deterministic(&self) -> bool {
         self.tunables.relaxed_simd_deterministic
     }


Test patch:
diff --git a/cranelift/filetests/filetests/parser/ternary.clif b/cranelift/filetests/filetests/parser/ternary.clif
index 5f86eb668..b521aecc8 100644
--- a/cranelift/filetests/filetests/parser/ternary.clif
+++ b/cranelift/filetests/filetests/parser/ternary.clif
@@ -10,8 +10,8 @@ block1(v1: i32, v2: i32, v3: i32):
 
 function %add_i96(i32, i32, i32, i32, i32, i32) -> i32, i32, i32 {
 block1(v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32):
-    v10, v11 = iadd_cout v1, v4
-    ;check: v10, v11 = iadd_cout v1, v4
+    v10, v11 = uadd_overflow v1, v4
+    ;check: v10, v11 = uadd_overflow v1, v4
     v20, v21 = iadd_carry v2, v5, v11
     ; check: v20, v21 = iadd_carry v2, v5, v11
     v30 = iadd_cin v3, v6, v21
@@ -21,8 +21,8 @@ block1(v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32):
 
 function %sub_i96(i32, i32, i32, i32, i32, i32) -> i32, i32, i32 {
 block1(v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32):
-    v10, v11 = isub_bout v1, v4
-    ;check: v10, v11 = isub_bout v1, v4
+    v10, v11 = usub_overflow v1, v4
+    ;check: v10, v11 = usub_overflow v1, v4
     v20, v21 = isub_borrow v2, v5, v11
     ; check: v20, v21 = isub_borrow v2, v5, v11
     v30 = isub_bin v3, v6, v21
diff --git a/cranelift/filetests/filetests/runtests/i128-iaddcout.clif b/cranelift/filetests/filetests/runtests/i128-iaddcout.clif
deleted file mode 100644
index ad0c88570..000000000
--- a/cranelift/filetests/filetests/runtests/i128-iaddcout.clif
+++ /dev/null
@@ -1,29 +0,0 @@
-test interpret
-; test run
-; set enable_llvm_abi_extensions=true
-; target aarch64
-; target s390x
-; target x86_64
-; target riscv64
-
-function %iaddcout_i128_v(i128, i128) -> i128 {
-block0(v0: i128, v1: i128):
-    v2, v3 = iadd_cout v0, v1
-    return v2
-}
-; run: %iaddcout_i128_v(0, 1) == 1
-; run: %iaddcout_i128_v(100, 27) == 127
-; run: %iaddcout_i128_v(100, 28) == 128
-; run: %iaddcout_i128_v(0x7FFFFFFF_FFFFFFFF_FFFFFFFF_FFFF0000, 0xFFFF) == 0x7FFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF
-; run: %iaddcout_i128_v(0x7FFFFFFF_FFFFFFFF_FFFFFFFF_FFFF0000, 0x10000) == 0x80000000_00000000_00000000_00000000
-
-function %iaddcout_i128_c(i128, i128) -> i8 {
-block0(v0: i128, v1: i128):
-    v2, v3 = iadd_cout v0, v1
-    return v3
-}
-; run: %iaddcout_i128_c(0, 1) == 0
-; run: %iaddcout_i128_c(100, 27) == 0
-; run: %iaddcout_i128_c(100, 28) == 0
-; run: %iaddcout_i128_c(0x7FFFFFFF_FFFFFFFF_FFFFFFFF_FFFF0000, 0xFFFF) == 0
-; run: %iaddcout_i128_c(0x7FFFFFFF_FFFFFFFF_FFFFFFFF_FFFF0000, 0x10000) == 1
diff --git a/cranelift/filetests/filetests/runtests/i128-isubbout.clif b/cranelift/filetests/filetests/runtests/i128-isubbout.clif
deleted file mode 100644
index 11f99f643..000000000
--- a/cranelift/filetests/filetests/runtests/i128-isubbout.clif
+++ /dev/null
@@ -1,30 +0,0 @@
-test interpret
-; test run
-; set enable_llvm_abi_extensions=true
-; target aarch64
-; target s390x
-; target x86_64
-; target riscv64
-
-
-function %isubbout_i128_v(i128, i128) -> i128 {
-block0(v0: i128, v1: i128):
-    v2, v3 = isub_bout v0, v1
-    return v2
-}
-; run: %isubbout_i128_v(0, 1) == -1
-; run: %isubbout_i128_v(100, 20) == 80
-; run: %isubbout_i128_v(100, -28) == 128
-; run: %isubbout_i128_v(-2147483640, 8) == -2147483648
-; run: %isubbout_i128_v(-2147483640, 9) == -2147483649
-
-function %isubbout_i128_c(i128, i128) -> i8 {
-block0(v0: i128, v1: i128):
-    v2, v3 = isub_bout v0, v1
-    return v3
-}
-; run: %isubbout_i128_c(0, 1) == 1
-; run: %isubbout_i128_c(100, 20) == 0
-; run: %isubbout_i128_c(100, -28) == 0
-; run: %isubbout_i128_c(-2147483640, 8) == 1
-; run: %isubbout_i128_c(-2147483640, 9) == 1
diff --git a/cranelift/filetests/filetests/runtests/iaddcout-i16.clif b/cranelift/filetests/filetests/runtests/iaddcout-i16.clif
deleted file mode 100644
index d5fe26721..000000000
--- a/cranelift/filetests/filetests/runtests/iaddcout-i16.clif
+++ /dev/null
@@ -1,29 +0,0 @@
-test interpret
-test run
-target aarch64
-; target s390x
-; target x86_64
-; target riscv64
-
-function %iaddcout_i16_v(i16, i16) -> i16 {
-block0(v0: i16, v1: i16):
-    v2, v3 = iadd_cout v0, v1
-    return v2
-}
-; run: %iaddcout_i16_v(0, 1) == 1
-; run: %iaddcout_i16_v(100, 27) == 127
-; run: %iaddcout_i16_v(100, 28) == 128
-; run: %iaddcout_i16_v(32000, 767) == 32767
-; run: %iaddcout_i16_v(32000, 768) == -32768
-
-function %iaddcout_i16_c(i16, i16) -> i8 {
-block0(v0: i16, v1: i16):
-    v2, v3 = iadd_cout v0, v1
-    return v3
-}
-; run: %iaddcout_i16_c(0, 1) == 0
-; run: %iaddcout_i16_c(100, 27) == 0
-; run: %iaddcout_i16_c(100, 28) == 0
-; run: %iaddcout_i16_c(32000, 767) == 0
-; run: %iaddcout_i16_c(32000, 768) == 1
-
diff --git a/cranelift/filetests/filetests/runtests/iaddcout-i32.clif b/cranelift/filetests/filetests/runtests/iaddcout-i32.clif
deleted file mode 100644
index 8fd7deba6..000000000
--- a/cranelift/filetests/filetests/runtests/iaddcout-i32.clif
+++ /dev/null
@@ -1,29 +0,0 @@
-test interpret
-test run
-target aarch64
-; target s390x
-target x86_64
-; target riscv64
-
-function %iaddcout_i32_v(i32, i32) -> i32 {
-block0(v0: i32, v1: i32):
-    v2, v3 = iadd_cout v0, v1
-    return v2
-}
-; run: %iaddcout_i32_v(0, 1) == 1
-; run: %iaddcout_i32_v(100, 27) == 127
-; run: %iaddcout_i32_v(100, 28) == 128
-; run: %iaddcout_i32_v(2000000000, 147483647) == 2147483647
-; run: %iaddcout_i32_v(2000000000, 147483648) == -2147483648
-
-function %iaddcout_i32_c(i32, i32) -> i8 {
-block0(v0: i32, v1: i32):
-    v2, v3 = iadd_cout v0, v1
-    return v3
-}
-; run: %iaddcout_i32_c(0, 1) == 0
-; run: %iaddcout_i32_c(100, 27) == 0
-; run: %iaddcout_i32_c(100, 28) == 0
-; run: %iaddcout_i32_c(2000000000, 147483647) == 0
-; run: %iaddcout_i32_c(2000000000, 147483648) == 1
-
diff --git a/cranelift/filetests/filetests/runtests/iaddcout-i64.clif b/cranelift/filetests/filetests/runtests/iaddcout-i64.clif
deleted file mode 100644
index 51a09599a..000000000
--- a/cranelift/filetests/filetests/runtests/iaddcout-i64.clif
+++ /dev/null
@@ -1,28 +0,0 @@
-test interpret
-test run
-target aarch64
-; target s390x
-target x86_64
-; target riscv64
-
-function %iaddcout_i64_v(i64, i64) -> i64 {
-block0(v0: i64, v1: i64):
-    v2, v3 = iadd_cout v0, v1
-    return v2
-}
-; run: %iaddcout_i64_v(0, 1) == 1
-; run: %iaddcout_i64_v(100, 27) == 127
-; run: %iaddcout_i64_v(100, 28) == 128
-; run: %iaddcout_i64_v(0x7FFFFFFF_FFFF0000, 0xFFFF) == 0x7FFFFFFF_FFFFFFFF
-; run: %iaddcout_i64_v(0x7FFFFFFF_FFFF0000, 0x10000) == 0x80000000_00000000
-
-function %iaddcout_i64_c(i64, i64) -> i8 {
-block0(v0: i64, v1: i64):
-    v2, v3 = iadd_cout v0, v1
-    return v3
-}
-; run: %iaddcout_i64_c(0, 1) == 0
-; run: %iaddcout_i64_c(100, 27) == 0
-; run: %iaddcout_i64_c(100, 28) == 0
-; run: %iaddcout_i64_c(0x7FFFFFFF_FFFF0000, 0xFFFF) == 0
-; run: %iaddcout_i64_c(0x7FFFFFFF_FFFF0000, 0x10000) == 1
diff --git a/cranelift/filetests/filetests/runtests/iaddcout-i8.clif b/cranelift/filetests/filetests/runtests/iaddcout-i8.clif
deleted file mode 100644
index 3deb3dee9..000000000
--- a/cranelift/filetests/filetests/runtests/iaddcout-i8.clif
+++ /dev/null
@@ -1,29 +0,0 @@
-test interpret
-test run
-target aarch64
-; target s390x
-; target x86_64
-; target riscv64
-
-function %iaddcout_i8_v(i8, i8) -> i8 {
-block0(v0: i8, v1: i8):
-    v2, v3 = iadd_cout v0, v1
-    return v2
-}
-; run: %iaddcout_i8_v(0, 1) == 1
-; run: %iaddcout_i8_v(100, 27) == 127
-; run: %iaddcout_i8_v(100, -20) == 80
-; run: %iaddcout_i8_v(100, 28) == -128
-; run: %iaddcout_i8_v(-128, -128) == 0
-
-function %iaddcout_i8_c(i8, i8) -> i8 {
-block0(v0: i8, v1: i8):
-    v2, v3 = iadd_cout v0, v1
-    return v3
-}
-; run: %iaddcout_i8_c(0, 1) == 0
-; run: %iaddcout_i8_c(100, 27) == 0
-; run: %iaddcout_i8_c(100, -20) == 0
-; run: %iaddcout_i8_c(100, 28) == 1
-; run: %iaddcout_i8_c(-128, -128) == 1
-
diff --git a/cranelift/filetests/filetests/runtests/isubbout.clif b/cranelift/filetests/filetests/runtests/isubbout.clif
deleted file mode 100644
index bbbf72556..000000000
--- a/cranelift/filetests/filetests/runtests/isubbout.clif
+++ /dev/null
@@ -1,92 +0,0 @@
-test interpret
-; test run
-; target aarch64
-; target s390x
-; target x86_64
-; target riscv64
-
-function %isubbout_i8_v(i8, i8) -> i8 {
-block0(v0: i8, v1: i8):
-    v2, v3 = isub_bout v0, v1
-    return v2
-}
-; run: %isubbout_i8_v(0, 1) == -1
-; run: %isubbout_i8_v(100, 20) == 80
-; run: %isubbout_i8_v(100, -20) == 120
-; run: %isubbout_i8_v(-128, 1) == 127
-
-function %isubbout_i8_c(i8, i8) -> i8 {
-block0(v0: i8, v1: i8):
-    v2, v3 = isub_bout v0, v1
-    return v3
-}
-; run: %isubbout_i8_c(0, 1) == 1
-; run: %isubbout_i8_c(100, 20) == 0
-; run: %isubbout_i8_c(100, -20) == 0
-; run: %isubbout_i8_c(-128, 1) == 1
-
-function %isubbout_i16_v(i16, i16) -> i16 {
-block0(v0: i16, v1: i16):
-    v2, v3 = isub_bout v0, v1
-    return v2
-}
-; run: %isubbout_i16_v(0, 1) == -1
-; run: %isubbout_i16_v(100, 20) == 80
-; run: %isubbout_i16_v(100, -28) == 128
-; run: %isubbout_i16_v(-32000, 768) == -32768
-; run: %isubbout_i16_v(-32000, 769) == 32767
-
-function %isubbout_i16_c(i16, i16) -> i8 {
-block0(v0: i16, v1: i16):
-    v2, v3 = isub_bout v0, v1
-    return v3
-}
-; run: %isubbout_i16_c(0, 1) == 1
-; run: %isubbout_i16_c(100, 20) == 0
-; run: %isubbout_i16_c(100, -28) == 0
-; run: %isubbout_i16_c(-32000, 768) == 1
-; run: %isubbout_i16_c(-32000, 769) == 1
-
-function %isubbout_i32_v(i32, i32) -> i32 {
-block0(v0: i32, v1: i32):
-    v2, v3 = isub_bout v0, v1
-    return v2
-}
-; run: %isubbout_i32_v(0, 1) == -1
-; run: %isubbout_i32_v(100, 20) == 80
-; run: %isubbout_i32_v(100, -28) == 128
-; run: %isubbout_i32_v(-2147483640, 8) == -2147483648
-; run: %isubbout_i32_v(-2147483640, 9) == 2147483647
-
-function %isubbout_i32_c(i32, i32) -> i8 {
-block0(v0: i32, v1: i32):
-    v2, v3 = isub_bout v0, v1
-    return v3
-}
-; run: %isubbout_i32_c(0, 1) == 1
-; run: %isubbout_i32_c(100, 20) == 0
-; run: %isubbout_i32_c(100, -28) == 0
-; run: %isubbout_i32_c(-2147483640, 8) == 1
-; run: %isubbout_i32_c(-2147483640, 9) == 1
-
-function %isubbout_i64_v(i64, i64) -> i64 {
-block0(v0: i64, v1: i64):
-    v2, v3 = isub_bout v0, v1
-    return v2
-}
-; run: %isubbout_i64_v(0, 1) == -1
-; run: %isubbout_i64_v(100, 20) == 80
-; run: %isubbout_i64_v(100, -28) == 128
-; run: %isubbout_i64_v(-2147483640, 8) == -2147483648
-; run: %isubbout_i64_v(-2147483640, 9) == -2147483649
-
-function %isubbout_i64_c(i64, i64) -> i8 {
-block0(v0: i64, v1: i64):
-    v2, v3 = isub_bout v0, v1
-    return v3
-}
-; run: %isubbout_i64_c(0, 1) == 1
-; run: %isubbout_i64_c(100, 20) == 0
-; run: %isubbout_i64_c(100, -28) == 0
-; run: %isubbout_i64_c(-2147483640, 8) == 1
-; run: %isubbout_i64_c(-2147483640, 9) == 1
diff --git a/cranelift/filetests/src/test_wasm/env.rs b/cranelift/filetests/src/test_wasm/env.rs
index 8a0ea656b..23ca9bac8 100644
--- a/cranelift/filetests/src/test_wasm/env.rs
+++ b/cranelift/filetests/src/test_wasm/env.rs
@@ -604,10 +604,6 @@ impl<'a> FuncEnvironment for FuncEnv<'a> {
             .translate_atomic_notify(pos, index, heap, addr, count)
     }
 
-    fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC {
-        self.inner.unsigned_add_overflow_condition()
-    }
-
     fn heaps(
         &self,
     ) -> &cranelift_codegen::entity::PrimaryMap<cranelift_wasm::Heap, cranelift_wasm::HeapData>
diff --git a/crates/test-programs/wasi-tests/src/bin/dir_fd_op_failures.rs b/crates/test-programs/wasi-tests/src/bin/dir_fd_op_failures.rs
new file mode 100644
index 000000000..35c0f2827
--- /dev/null
+++ b/crates/test-programs/wasi-tests/src/bin/dir_fd_op_failures.rs
@@ -0,0 +1,99 @@
+use std::{env, process};
+use wasi_tests::open_scratch_directory;
+
+unsafe fn test_fd_dir_ops(dir_fd: wasi::Fd) {
+    let stat = wasi::fd_filestat_get(dir_fd).expect("failed to fdstat");
+    assert_eq!(stat.filetype, wasi::FILETYPE_DIRECTORY);
+
+    let mut read_buf = vec![0; 128].into_boxed_slice();
+    let iovec = wasi::Iovec {
+        buf: read_buf.as_mut_ptr(),
+        buf_len: read_buf.len(),
+    };
+    let r = wasi::fd_read(dir_fd, &[iovec]);
+    // On posix, this fails with ERRNO_ISDIR:
+    assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_read error");
+
+    let r = wasi::fd_pread(dir_fd, &[iovec], 0);
+    // On posix, this fails with ERRNO_ISDIR
+    assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_pread error");
+
+    let write_buf = vec![0; 128].into_boxed_slice();
+    let ciovec = wasi::Ciovec {
+        buf: write_buf.as_ptr(),
+        buf_len: write_buf.len(),
+    };
+    let r = wasi::fd_write(dir_fd, &[ciovec]);
+    // Same behavior as specified by POSIX:
+    assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_write error");
+
+    let r = wasi::fd_pwrite(dir_fd, &[ciovec], 0);
+    // Same behavior as specified by POSIX:
+    assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_pwrite error");
+
+    // Divergence from posix: lseek(dirfd) will return 0
+    let r = wasi::fd_seek(dir_fd, 0, wasi::WHENCE_CUR);
+    assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_seek WHENCE_CUR error");
+    let r = wasi::fd_seek(dir_fd, 0, wasi::WHENCE_SET);
+    assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_seek WHENCE_SET error");
+    let r = wasi::fd_seek(dir_fd, 0, wasi::WHENCE_END);
+    assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_seek WHENCE_END error");
+
+    // Tell isnt in posix, its basically lseek with WHENCE_CUR above
+    let r = wasi::fd_tell(dir_fd);
+    assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_tell error");
+
+    // posix_fadvise(dirfd, 0, 0, POSIX_FADV_DONTNEED) will return 0 on linux.
+    // not available on mac os.
+    let r = wasi::fd_advise(dir_fd, 0, 0, wasi::ADVICE_DONTNEED);
+    assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_advise error");
+
+    // fallocate(dirfd, FALLOC_FL_ZERO_RANGE, 0, 1) will fail with errno EBADF on linux.
+    // not available on mac os.
+    let r = wasi::fd_allocate(dir_fd, 0, 0);
+    assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_allocate error");
+
+    // fdatasync(dirfd) will return 0 on linux.
+    // not available on mac os.
+    let r = wasi::fd_datasync(dir_fd);
+    assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_datasync error");
+
+    // fsync(dirfd) will return 0 on linux.
+    // not available on mac os.
+    let r = wasi::fd_sync(dir_fd);
+    assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_sync error");
+
+    // fcntl(dirfd,  F_SETFL, O_NONBLOCK) will return 0 on linux.
+    // not available on mac os.
+    let r = wasi::fd_fdstat_set_flags(dir_fd, wasi::FDFLAGS_NONBLOCK);
+    assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_fdstat_set_flags error");
+
+    // ftruncate(dirfd, 1) will fail with errno EINVAL on posix.
+    // here, we fail with EBADF instead:
+    let r = wasi::fd_filestat_set_size(dir_fd, 0);
+    assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_filestat_set_size error");
+}
+
+fn main() {
+    let mut args = env::args();
+    let prog = args.next().unwrap();
+    let arg = if let Some(arg) = args.next() {
+        arg
+    } else {
+        eprintln!("usage: {} <scratch directory>", prog);
+        process::exit(1);
+    };
+
+    // Open scratch directory
+    let dir_fd = match open_scratch_directory(&arg) {
+        Ok(dir_fd) => dir_fd,
+        Err(err) => {
+            eprintln!("{}", err);
+            process::exit(1)
+        }
+    };
+
+    unsafe {
+        test_fd_dir_ops(dir_fd);
+    }
+}