Repository: bytecodealliance/wasmtime
Pull request #7615 (2023-11-30 07:59:40)

Cranelift: additional `icmp` & `select` ISLE opts
I was writing a pattern for Rust's `Ord::cmp` ([context zulip thread](https://bytecodealliance.zulipchat.com/#narrow/stream/217117-cranelift/topic/3-way.20compare.20.28Rust.20.60cmp.60.2C.20C.2B.2B20.20.60.3C.3D.3E.60.29/near/404501312))

https://github.com/rust-lang/rust/blob/e55544c8043ec2074c1ef2499afc78ee6b5108b7/library/core/src/cmp.rs#L1518-L1520

And noticed that the `if *self == *other { Equal } else { Greater }` part is `if c { false } else { true }`.

So here's a smaller PR with some simpler sub-patterns first.


github-actions[bot]: #### Subscribe to Label Action

cc @cfallin, @fitzgen

<details>
This issue or pull request has been labeled: "cranelift", "isle"

Thus the following users have been cc'd because of the following labels:

* cfallin: isle
* fitzgen: isle

To subscribe or unsubscribe from this label, edit the <code>.github/subscribe-to-label.json</code> configuration file.

[Learn more.](https://github.com/bytecodealliance/subscribe-to-label-action)
</details>

Patch:
diff --git a/RELEASES.md b/RELEASES.md
index 6986babf6..5c97e7bd4 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -10,6 +10,21 @@ Unreleased.
 
 --------------------------------------------------------------------------------
 
+## 15.0.1
+
+Released 2023-12-01.
+
+### Fixed
+
+* The `wasi:random/insecure{,_seed}` interfaces are now available through the
+  CLI.
+  [#7614](https://github.com/bytecodealliance/wasmtime/pull/7614)
+
+* A stray debugging `println!` was removed.
+  [#7618](https://github.com/bytecodealliance/wasmtime/pull/7618)
+
+--------------------------------------------------------------------------------
+
 ## 15.0.0
 
 Released 2023-11-20
diff --git a/cranelift/codegen/src/opts/icmp.isle b/cranelift/codegen/src/opts/icmp.isle
index b0f57fdf1..b95d978c6 100644
--- a/cranelift/codegen/src/opts/icmp.isle
+++ b/cranelift/codegen/src/opts/icmp.isle
@@ -133,6 +133,28 @@
   (if-let signed (intcc_comparable cc1 cc2))
   (compose_icmp ty (u64_or (decompose_intcc cc1) (decompose_intcc cc2)) signed x y))
 
+;; Prefer comparing against zero
+;; uge(x, 1) == ne(x, 0)
+(rule (simplify (uge ty x (iconst cty (u64_from_imm64 1))))
+      (ne ty x (iconst cty (imm64 0))))
+;; ult(x, 1) == eq(x, 0)
+(rule (simplify (ult ty x (iconst cty (u64_from_imm64 1))))
+      (eq ty x (iconst cty (imm64 0))))
+;; sge(x, 1) == sgt(x, 0)
+(rule (simplify (sge ty x (iconst cty (u64_from_imm64 1))))
+      (sgt ty x (iconst cty (imm64 0))))
+;; slt(x, 1) == sle(x, 0)
+(rule (simplify (slt ty x (iconst cty (u64_from_imm64 1))))
+      (sle ty x (iconst cty (imm64 0))))
+;; sgt(x, -1) == sge(x, 0)
+(rule (simplify (sgt ty x (iconst cty c)))
+      (if-let -1 (i64_sextend_imm64 cty c))
+      (sge ty x (iconst cty (imm64 0))))
+;; sle(x, -1) == slt(x, 0)
+(rule (simplify (sle ty x (iconst cty c)))
+      (if-let -1 (i64_sextend_imm64 cty c))
+      (slt ty x (iconst cty (imm64 0))))
+
 (decl pure partial intcc_comparable (IntCC IntCC) bool)
 (rule (intcc_comparable x y)
   (if-let (u64_nonzero class) (u64_and (intcc_class x) (intcc_class y)))
diff --git a/cranelift/codegen/src/opts/selects.isle b/cranelift/codegen/src/opts/selects.isle
index e66250327..052a7b59c 100644
--- a/cranelift/codegen/src/opts/selects.isle
+++ b/cranelift/codegen/src/opts/selects.isle
@@ -4,6 +4,17 @@
 (rule (simplify (select    ty _ x x)) x)
 (rule (simplify (bitselect ty _ x x)) x)
 
+;; if icmp(x, y) { 1 } else { 0 } => uextend(icmp(x, y))
+(rule (simplify (select ty cmp@(icmp _ cc x y)
+                        (iconst _ (u64_from_imm64 1))
+                        (iconst _ (u64_from_imm64 0))))
+    (uextend_from_i8 ty cmp))
+;; if icmp(x, y) { 0 } else { 1 } => uextend(!icmp(x, y))
+(rule (simplify (select sty (icmp cty cc x y)
+                        (iconst _ (u64_from_imm64 0))
+                        (iconst _ (u64_from_imm64 1))))
+    (uextend_from_i8 sty (icmp cty (intcc_complement cc) x y)))
+
 ;; Transform select-of-icmp into {u,s}{min,max} instructions where possible.
 (rule (simplify (select ty (sgt _ x y) x y)) (smax ty x y))
 (rule (simplify (select ty (sge _ x y) x y)) (smax ty x y))
@@ -57,3 +68,9 @@
 (rule (simplify (bor (ty_vec128 ty) (band ty (bnot ty c) y) (band ty x c))) (bitselect ty c x y))
 (rule (simplify (bor (ty_vec128 ty) (band ty y (bnot ty c)) (band ty c x))) (bitselect ty c x y))
 (rule (simplify (bor (ty_vec128 ty) (band ty y (bnot ty c)) (band ty x c))) (bitselect ty c x y))
+
+;; extend from i8 to i8 is invalid CLIF, so this allows fixing that in the output
+;; rather than needing to duplicate rules for the different width categories
+(decl uextend_from_i8 (Type Value) Value)
+(rule 0 (uextend_from_i8 ty val) (uextend ty val))
+(rule 1 (uextend_from_i8 $I8 val) val)
diff --git a/winch/codegen/src/visitor.rs b/winch/codegen/src/visitor.rs
index 64726aadf..8a26cda94 100644
--- a/winch/codegen/src/visitor.rs
+++ b/winch/codegen/src/visitor.rs
@@ -1225,8 +1225,7 @@ where
         let labels: SmallVec<[_; 5]> = (0..len).map(|_| self.masm.get_label()).collect();
 
         let default_index = control_index(targets.default(), self.control_frames.len());
-        let default_frame = &self.control_frames[default_index];
-        let default_result = default_frame.as_target_results();
+        let default_result = self.control_frames[default_index].as_target_results();
 
         let (index, tmp) = if let Some(data) = default_result {
             let index_and_tmp = self.context.without::<(TypedReg, _), M, _>(
@@ -1246,10 +1245,6 @@ where
             )
         };
 
-        let (_, offset) = default_frame.base_stack_len_and_sp();
-        // Ensure that the stack pointer is correctly positioned before
-        // jumping to the jump table code.
-        self.masm.ensure_sp_for_jump(offset);
         self.masm.jmp_table(&labels, index.into(), tmp);
 
         for (t, l) in targets


Test patch:
diff --git a/cranelift/filetests/filetests/egraph/icmp-parameterized.clif b/cranelift/filetests/filetests/egraph/icmp-parameterized.clif
index 095361408..0ce76115c 100644
--- a/cranelift/filetests/filetests/egraph/icmp-parameterized.clif
+++ b/cranelift/filetests/filetests/egraph/icmp-parameterized.clif
@@ -567,9 +567,9 @@ block0(v0: i32):
 
 ; function %icmp_sle_umax(i32) -> i8 fast {
 ; block0(v0: i32):
-;     v1 = iconst.i32 0xffff_ffff
-;     v2 = icmp sle v0, v1  ; v1 = 0xffff_ffff
-;     return v2
+;     v3 = iconst.i32 0
+;     v4 = icmp slt v0, v3  ; v3 = 0
+;     return v4
 ; }
 
 function %icmp_sle_smin(i32) -> i8 {
@@ -622,9 +622,9 @@ block0(v0: i32):
 
 ; function %icmp_sgt_umax(i32) -> i8 fast {
 ; block0(v0: i32):
-;     v1 = iconst.i32 0xffff_ffff
-;     v2 = icmp sgt v0, v1  ; v1 = 0xffff_ffff
-;     return v2
+;     v3 = iconst.i32 0
+;     v4 = icmp sge v0, v3  ; v3 = 0
+;     return v4
 ; }
 
 function %icmp_sgt_smin(i32) -> i8 {
diff --git a/cranelift/filetests/filetests/egraph/icmp.clif b/cranelift/filetests/filetests/egraph/icmp.clif
index ef60cbf95..f82d4aaa3 100644
--- a/cranelift/filetests/filetests/egraph/icmp.clif
+++ b/cranelift/filetests/filetests/egraph/icmp.clif
@@ -53,3 +53,59 @@ block0:
 ;     v5 = icmp ne v2, v3  ; v3 = 0
 ;     return v5
 ; }
+
+function %sge_one(i64) -> i8 {
+block0(v0: i64):
+    v1 = iconst.i64 1
+    v2 = icmp sge v0, v1
+    return v2
+}
+
+; function %sge_one(i64) -> i8 fast {
+; block0(v0: i64):
+;     v3 = iconst.i64 0
+;     v4 = icmp sgt v0, v3  ; v3 = 0
+;     return v4
+; }
+
+function %slt_one(i16) -> i8 {
+block0(v0: i16):
+    v1 = iconst.i16 1
+    v2 = icmp slt v0, v1
+    return v2
+}
+
+; function %slt_one(i16) -> i8 fast {
+; block0(v0: i16):
+;     v3 = iconst.i16 0
+;     v4 = icmp sle v0, v3  ; v3 = 0
+;     return v4
+; }
+
+function %uge_one(i32) -> i8 {
+block0(v0: i32):
+    v1 = iconst.i32 1
+    v2 = icmp uge v0, v1
+    return v2
+}
+
+; function %uge_one(i32) -> i8 fast {
+; block0(v0: i32):
+;     v3 = iconst.i32 0
+;     v4 = icmp ne v0, v3  ; v3 = 0
+;     return v4
+; }
+
+function %ult_one(i8) -> i8 {
+block0(v0: i8):
+    v1 = iconst.i8 1
+    v2 = icmp ult v0, v1
+    return v2
+}
+
+; function %ult_one(i8) -> i8 fast {
+; block0(v0: i8):
+;     v3 = iconst.i8 0
+;     v4 = icmp eq v0, v3  ; v3 = 0
+;     return v4
+; }
diff --git a/cranelift/filetests/filetests/egraph/select.clif b/cranelift/filetests/filetests/egraph/select.clif
index 8f5339417..062909a81 100644
--- a/cranelift/filetests/filetests/egraph/select.clif
+++ b/cranelift/filetests/filetests/egraph/select.clif
@@ -141,3 +141,47 @@ block0(v0: i32, v1: i32, v2: i32, v3: i32):
 ; check:    v4 = icmp ule v0, v1
 ; check:    v5 = select v4, v2, v3
 ; check:    return v5
+
+function %then_true_else_false(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = iconst.i8 1
+    v4 = iconst.i8 0
+    v5 = select v2, v3, v4
+    return v5
+}
+; check: return v2
+
+function %then_false_else_true(i32, i32) -> i8 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = iconst.i8 0
+    v4 = iconst.i8 1
+    v5 = select v2, v3, v4
+    return v5
+}
+; check: v6 = icmp sge v0, v1
+; check: return v6
+
+function %then_one_else_zero(i32, i32) -> i64 {
+block0(v0: i32, v1: i32):
+    v2 = icmp ule v0, v1
+    v3 = iconst.i64 1
+    v4 = iconst.i64 0
+    v5 = select v2, v3, v4
+    return v5
+}
+; check: v6 = uextend.i64 v2
+; check: return v6
+
+function %then_zero_else_false(i32, i32) -> i64 {
+block0(v0: i32, v1: i32):
+    v2 = icmp slt v0, v1
+    v3 = iconst.i64 0
+    v4 = iconst.i64 1
+    v5 = select v2, v3, v4
+    return v5
+}
+; check: v6 = icmp sge v0, v1
+; check: v7 = uextend.i64 v6
+; check: return v7
diff --git a/crates/test-programs/src/bin/preview2_random.rs b/crates/test-programs/src/bin/preview2_random.rs
index 663a01590..491037d65 100644
--- a/crates/test-programs/src/bin/preview2_random.rs
+++ b/crates/test-programs/src/bin/preview2_random.rs
@@ -1,6 +1,40 @@
+use test_programs::wasi::random;
+
 fn main() {
     let mut bytes = [0_u8; 256];
     getrandom::getrandom(&mut bytes).unwrap();
 
     assert!(bytes.iter().any(|x| *x != 0));
+
+    // Acquired random bytes should be of the expected length.
+    let array = random::random::get_random_bytes(100);
+    assert_eq!(array.len(), 100);
+
+    // It shouldn't take 100+ tries to get a nonzero random integer.
+    for i in 0.. {
+        if random::random::get_random_u64() == 0 {
+            continue;
+        }
+        assert!(i < 100);
+        break;
+    }
+
+    // The `insecure_seed` API should return the same result each time.
+    let (a1, b1) = random::insecure_seed::insecure_seed();
+    let (a2, b2) = random::insecure_seed::insecure_seed();
+    assert_eq!(a1, a2);
+    assert_eq!(b1, b2);
+
+    // Acquired random bytes should be of the expected length.
+    let array = random::insecure::get_insecure_random_bytes(100);
+    assert_eq!(array.len(), 100);
+
+    // It shouldn't take 100+ tries to get a nonzero random integer.
+    for i in 0.. {
+        if random::insecure::get_insecure_random_u64() == 0 {
+            continue;
+        }
+        assert!(i < 100);
+        break;
+    }
 }
diff --git a/tests/misc_testsuite/winch/br_table.wast b/tests/misc_testsuite/winch/br_table.wast
index 6a7a8c288..54784e13d 100644
--- a/tests/misc_testsuite/winch/br_table.wast
+++ b/tests/misc_testsuite/winch/br_table.wast
@@ -11,25 +11,6 @@
     (block (drop (i64.ctz (br_table 0 0 (i32.const 0)))))
   )
 
-  (func (export "type-f32")
-    (block (drop (f32.neg (br_table 0 0 (i32.const 0)))))
-  )
-  (func (export "type-f64")
-    (block (drop (f64.neg (br_table 0 0 (i32.const 0)))))
-  )
-
-  (func (export "type-i32-value") (result i32)
-    (block (result i32) (i32.ctz (br_table 0 0 (i32.const 1) (i32.const 0))))
-  )
-  (func (export "type-i64-value") (result i64)
-    (block (result i64) (i64.ctz (br_table 0 0 (i64.const 2) (i32.const 0))))
-  )
-  (func (export "type-f32-value") (result f32)
-    (block (result f32) (f32.neg (br_table 0 0 (f32.const 3) (i32.const 0))))
-  )
-  (func (export "type-f64-value") (result f64)
-    (block (result f64) (f64.neg (br_table 0 0 (f64.const 4) (i32.const 0))))
-  )
   (func (export "empty") (param i32) (result i32)
     (block (br_table 0 (local.get 0)) (return (i32.const 21)))
     (i32.const 22)
@@ -1142,12 +1123,6 @@
 
 (assert_return (invoke "type-i32"))
 (assert_return (invoke "type-i64"))
-(assert_return (invoke "type-f32"))
-(assert_return (invoke "type-f64"))
-(assert_return (invoke "type-i32-value") (i32.const 1))
-(assert_return (invoke "type-i64-value") (i64.const 2))
-(assert_return (invoke "type-f32-value") (f32.const 3))
-(assert_return (invoke "type-f64-value") (f64.const 4))
 
 (assert_return (invoke "empty" (i32.const 0)) (i32.const 22))
 (assert_return (invoke "empty" (i32.const 1)) (i32.const 22))
diff --git a/tests/misc_testsuite/winch/misc.wast b/tests/misc_testsuite/winch/misc.wast
deleted file mode 100644
index 481fba8dd..000000000
--- a/tests/misc_testsuite/winch/misc.wast
+++ /dev/null
@@ -1,15 +0,0 @@
-;; Additional run tests for Winch not covered in the official spec test suite.
-
-(module
-  (func (export "br-table-ensure-sp") (result i32)
-    (block (result i32)
-       (i32.const 0)
-    )
-    (i32.const 0)
-    (i32.const 0)
-    (br_table 0)
-  )
-)
-
-(assert_return (invoke "br-table-ensure-sp") (i32.const 0))
-
diff --git a/winch/filetests/filetests/x64/br_table/ensure_sp_state.wat b/winch/filetests/filetests/x64/br_table/ensure_sp_state.wat
deleted file mode 100644
index 413469403..000000000
--- a/winch/filetests/filetests/x64/br_table/ensure_sp_state.wat
+++ /dev/null
@@ -1,34 +0,0 @@
-;;! target = "x86_64"
-
-(module
-  (func (export "") (result i32)
-    block (result i32)
-       i32.const 0
-    end
-    i32.const 0
-    i32.const 0
-    br_table 0
-  )
-)
-;;    0:	 55                   	push	rbp
-;;    1:	 4889e5               	mov	rbp, rsp
-;;    4:	 4883ec08             	sub	rsp, 8
-;;    8:	 4c893424             	mov	qword ptr [rsp], r14
-;;    c:	 b800000000           	mov	eax, 0
-;;   11:	 4883ec04             	sub	rsp, 4
-;;   15:	 890424               	mov	dword ptr [rsp], eax
-;;   18:	 b900000000           	mov	ecx, 0
-;;   1d:	 b800000000           	mov	eax, 0
-;;   22:	 4883c404             	add	rsp, 4
-;;   26:	 ba00000000           	mov	edx, 0
-;;   2b:	 39ca                 	cmp	edx, ecx
-;;   2d:	 0f42ca               	cmovb	ecx, edx
-;;   30:	 4c8d1d0a000000       	lea	r11, [rip + 0xa]
-;;   37:	 4963148b             	movsxd	rdx, dword ptr [r11 + rcx*4]
-;;   3b:	 4901d3               	add	r11, rdx
-;;   3e:	 41ffe3               	jmp	r11
-;;   41:	 0400                 	add	al, 0
-;;   43:	 0000                 	add	byte ptr [rax], al
-;;   45:	 4883c408             	add	rsp, 8
-;;   49:	 5d                   	pop	rbp
-;;   4a:	 c3                   	ret