-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[ConstantTime][WebAssembly] Add comprehensive tests for ct.select #166709
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: users/wizardengineer/ct-select-clang
Are you sure you want to change the base?
[ConstantTime][WebAssembly] Add comprehensive tests for ct.select #166709
Conversation
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
cbb5490 to
6ac8221
Compare
d55c2d6 to
046e875
Compare
|
@llvm/pr-subscribers-backend-webassembly Author: Julius Alexandre (wizardengineer) ChangesPatch is 79.36 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/166709.diff 5 Files Affected:
diff --git a/llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll b/llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll
new file mode 100644
index 0000000000000..b0f7f2807debd
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll
@@ -0,0 +1,376 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=wasm32-unknown-unknown -O3 -filetype=asm | FileCheck %s --check-prefix=W32
+; RUN: llc < %s -mtriple=wasm64-unknown-unknown -O3 -filetype=asm | FileCheck %s --check-prefix=W64
+
+; Test with small integer types
+define i1 @test_ctselect_i1(i1 %cond, i1 %a, i1 %b) {
+; W32-LABEL: test_ctselect_i1:
+; W32: .functype test_ctselect_i1 (i32, i32, i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT: local.get 0
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.and
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.const 1
+; W32-NEXT: i32.xor
+; W32-NEXT: local.get 2
+; W32-NEXT: i32.and
+; W32-NEXT: i32.or
+; W32-NEXT: # fallthrough-return
+;
+; W64-LABEL: test_ctselect_i1:
+; W64: .functype test_ctselect_i1 (i32, i32, i32) -> (i32)
+; W64-NEXT: # %bb.0:
+; W64-NEXT: local.get 0
+; W64-NEXT: local.get 1
+; W64-NEXT: i32.and
+; W64-NEXT: local.get 0
+; W64-NEXT: i32.const 1
+; W64-NEXT: i32.xor
+; W64-NEXT: local.get 2
+; W64-NEXT: i32.and
+; W64-NEXT: i32.or
+; W64-NEXT: # fallthrough-return
+ %result = call i1 @llvm.ct.select.i1(i1 %cond, i1 %a, i1 %b)
+ ret i1 %result
+}
+
+; Test with extremal values
+define i32 @test_ctselect_extremal_values(i1 %cond) {
+; W32-LABEL: test_ctselect_extremal_values:
+; W32: .functype test_ctselect_extremal_values (i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT: i32.const 0
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.const 1
+; W32-NEXT: i32.and
+; W32-NEXT: local.tee 0
+; W32-NEXT: i32.sub
+; W32-NEXT: i32.const 2147483647
+; W32-NEXT: i32.and
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.add
+; W32-NEXT: i32.const -2147483648
+; W32-NEXT: i32.and
+; W32-NEXT: i32.or
+; W32-NEXT: # fallthrough-return
+;
+; W64-LABEL: test_ctselect_extremal_values:
+; W64: .functype test_ctselect_extremal_values (i32) -> (i32)
+; W64-NEXT: # %bb.0:
+; W64-NEXT: i32.const 0
+; W64-NEXT: local.get 0
+; W64-NEXT: i32.const 1
+; W64-NEXT: i32.and
+; W64-NEXT: local.tee 0
+; W64-NEXT: i32.sub
+; W64-NEXT: i32.const 2147483647
+; W64-NEXT: i32.and
+; W64-NEXT: local.get 0
+; W64-NEXT: i32.const -1
+; W64-NEXT: i32.add
+; W64-NEXT: i32.const -2147483648
+; W64-NEXT: i32.and
+; W64-NEXT: i32.or
+; W64-NEXT: # fallthrough-return
+ %result = call i32 @llvm.ct.select.i32(i1 %cond, i32 2147483647, i32 -2147483648)
+ ret i32 %result
+}
+
+; Test with null pointers
+define ptr @test_ctselect_null_ptr(i1 %cond, ptr %ptr) {
+; W32-LABEL: test_ctselect_null_ptr:
+; W32: .functype test_ctselect_null_ptr (i32, i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT: i32.const 0
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.const 1
+; W32-NEXT: i32.and
+; W32-NEXT: i32.sub
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.and
+; W32-NEXT: # fallthrough-return
+;
+; W64-LABEL: test_ctselect_null_ptr:
+; W64: .functype test_ctselect_null_ptr (i32, i64) -> (i64)
+; W64-NEXT: # %bb.0:
+; W64-NEXT: i64.const 0
+; W64-NEXT: local.get 0
+; W64-NEXT: i64.extend_i32_u
+; W64-NEXT: i64.const 1
+; W64-NEXT: i64.and
+; W64-NEXT: i64.sub
+; W64-NEXT: local.get 1
+; W64-NEXT: i64.and
+; W64-NEXT: # fallthrough-return
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %ptr, ptr null)
+ ret ptr %result
+}
+
+; Test with function pointers
+define ptr @test_ctselect_function_ptr(i1 %cond, ptr %func1, ptr %func2) {
+; W32-LABEL: test_ctselect_function_ptr:
+; W32: .functype test_ctselect_function_ptr (i32, i32, i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT: i32.const 0
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.const 1
+; W32-NEXT: i32.and
+; W32-NEXT: local.tee 0
+; W32-NEXT: i32.sub
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.and
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.add
+; W32-NEXT: local.get 2
+; W32-NEXT: i32.and
+; W32-NEXT: i32.or
+; W32-NEXT: # fallthrough-return
+;
+; W64-LABEL: test_ctselect_function_ptr:
+; W64: .functype test_ctselect_function_ptr (i32, i64, i64) -> (i64)
+; W64-NEXT: .local i64
+; W64-NEXT: # %bb.0:
+; W64-NEXT: i64.const 0
+; W64-NEXT: local.get 0
+; W64-NEXT: i64.extend_i32_u
+; W64-NEXT: i64.const 1
+; W64-NEXT: i64.and
+; W64-NEXT: local.tee 3
+; W64-NEXT: i64.sub
+; W64-NEXT: local.get 1
+; W64-NEXT: i64.and
+; W64-NEXT: local.get 3
+; W64-NEXT: i64.const -1
+; W64-NEXT: i64.add
+; W64-NEXT: local.get 2
+; W64-NEXT: i64.and
+; W64-NEXT: i64.or
+; W64-NEXT: # fallthrough-return
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %func1, ptr %func2)
+ ret ptr %result
+}
+
+; Test with condition from icmp on pointers
+define ptr @test_ctselect_ptr_cmp(ptr %p1, ptr %p2, ptr %a, ptr %b) {
+; W32-LABEL: test_ctselect_ptr_cmp:
+; W32: .functype test_ctselect_ptr_cmp (i32, i32, i32, i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.const 0
+; W32-NEXT: local.get 0
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.eq
+; W32-NEXT: i32.select
+; W32-NEXT: local.tee 1
+; W32-NEXT: local.get 2
+; W32-NEXT: i32.and
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.xor
+; W32-NEXT: local.get 3
+; W32-NEXT: i32.and
+; W32-NEXT: i32.or
+; W32-NEXT: # fallthrough-return
+;
+; W64-LABEL: test_ctselect_ptr_cmp:
+; W64: .functype test_ctselect_ptr_cmp (i64, i64, i64, i64) -> (i64)
+; W64-NEXT: # %bb.0:
+; W64-NEXT: i64.const -1
+; W64-NEXT: i64.const 0
+; W64-NEXT: local.get 0
+; W64-NEXT: local.get 1
+; W64-NEXT: i64.eq
+; W64-NEXT: i64.select
+; W64-NEXT: local.tee 1
+; W64-NEXT: local.get 2
+; W64-NEXT: i64.and
+; W64-NEXT: local.get 1
+; W64-NEXT: i64.const -1
+; W64-NEXT: i64.xor
+; W64-NEXT: local.get 3
+; W64-NEXT: i64.and
+; W64-NEXT: i64.or
+; W64-NEXT: # fallthrough-return
+ %cmp = icmp eq ptr %p1, %p2
+ %result = call ptr @llvm.ct.select.p0(i1 %cmp, ptr %a, ptr %b)
+ ret ptr %result
+}
+
+; Test with struct pointer types
+%struct.pair = type { i32, i32 }
+
+define ptr @test_ctselect_struct_ptr(i1 %cond, ptr %a, ptr %b) {
+; W32-LABEL: test_ctselect_struct_ptr:
+; W32: .functype test_ctselect_struct_ptr (i32, i32, i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT: i32.const 0
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.const 1
+; W32-NEXT: i32.and
+; W32-NEXT: local.tee 0
+; W32-NEXT: i32.sub
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.and
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.add
+; W32-NEXT: local.get 2
+; W32-NEXT: i32.and
+; W32-NEXT: i32.or
+; W32-NEXT: # fallthrough-return
+;
+; W64-LABEL: test_ctselect_struct_ptr:
+; W64: .functype test_ctselect_struct_ptr (i32, i64, i64) -> (i64)
+; W64-NEXT: .local i64
+; W64-NEXT: # %bb.0:
+; W64-NEXT: i64.const 0
+; W64-NEXT: local.get 0
+; W64-NEXT: i64.extend_i32_u
+; W64-NEXT: i64.const 1
+; W64-NEXT: i64.and
+; W64-NEXT: local.tee 3
+; W64-NEXT: i64.sub
+; W64-NEXT: local.get 1
+; W64-NEXT: i64.and
+; W64-NEXT: local.get 3
+; W64-NEXT: i64.const -1
+; W64-NEXT: i64.add
+; W64-NEXT: local.get 2
+; W64-NEXT: i64.and
+; W64-NEXT: i64.or
+; W64-NEXT: # fallthrough-return
+ %result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %a, ptr %b)
+ ret ptr %result
+}
+
+; Test with deeply nested conditions
+define i32 @test_ctselect_deeply_nested(i1 %c1, i1 %c2, i1 %c3, i1 %c4, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) {
+; W32-LABEL: test_ctselect_deeply_nested:
+; W32: .functype test_ctselect_deeply_nested (i32, i32, i32, i32, i32, i32, i32, i32, i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT: i32.const 0
+; W32-NEXT: local.get 3
+; W32-NEXT: i32.const 1
+; W32-NEXT: i32.and
+; W32-NEXT: local.tee 3
+; W32-NEXT: i32.sub
+; W32-NEXT: i32.const 0
+; W32-NEXT: local.get 2
+; W32-NEXT: i32.const 1
+; W32-NEXT: i32.and
+; W32-NEXT: local.tee 2
+; W32-NEXT: i32.sub
+; W32-NEXT: i32.const 0
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.const 1
+; W32-NEXT: i32.and
+; W32-NEXT: local.tee 1
+; W32-NEXT: i32.sub
+; W32-NEXT: i32.const 0
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.const 1
+; W32-NEXT: i32.and
+; W32-NEXT: local.tee 0
+; W32-NEXT: i32.sub
+; W32-NEXT: local.get 4
+; W32-NEXT: i32.and
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.add
+; W32-NEXT: local.get 5
+; W32-NEXT: i32.and
+; W32-NEXT: i32.or
+; W32-NEXT: i32.and
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.add
+; W32-NEXT: local.get 6
+; W32-NEXT: i32.and
+; W32-NEXT: i32.or
+; W32-NEXT: i32.and
+; W32-NEXT: local.get 2
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.add
+; W32-NEXT: local.get 7
+; W32-NEXT: i32.and
+; W32-NEXT: i32.or
+; W32-NEXT: i32.and
+; W32-NEXT: local.get 3
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.add
+; W32-NEXT: local.get 8
+; W32-NEXT: i32.and
+; W32-NEXT: i32.or
+; W32-NEXT: # fallthrough-return
+;
+; W64-LABEL: test_ctselect_deeply_nested:
+; W64: .functype test_ctselect_deeply_nested (i32, i32, i32, i32, i32, i32, i32, i32, i32) -> (i32)
+; W64-NEXT: # %bb.0:
+; W64-NEXT: i32.const 0
+; W64-NEXT: local.get 3
+; W64-NEXT: i32.const 1
+; W64-NEXT: i32.and
+; W64-NEXT: local.tee 3
+; W64-NEXT: i32.sub
+; W64-NEXT: i32.const 0
+; W64-NEXT: local.get 2
+; W64-NEXT: i32.const 1
+; W64-NEXT: i32.and
+; W64-NEXT: local.tee 2
+; W64-NEXT: i32.sub
+; W64-NEXT: i32.const 0
+; W64-NEXT: local.get 1
+; W64-NEXT: i32.const 1
+; W64-NEXT: i32.and
+; W64-NEXT: local.tee 1
+; W64-NEXT: i32.sub
+; W64-NEXT: i32.const 0
+; W64-NEXT: local.get 0
+; W64-NEXT: i32.const 1
+; W64-NEXT: i32.and
+; W64-NEXT: local.tee 0
+; W64-NEXT: i32.sub
+; W64-NEXT: local.get 4
+; W64-NEXT: i32.and
+; W64-NEXT: local.get 0
+; W64-NEXT: i32.const -1
+; W64-NEXT: i32.add
+; W64-NEXT: local.get 5
+; W64-NEXT: i32.and
+; W64-NEXT: i32.or
+; W64-NEXT: i32.and
+; W64-NEXT: local.get 1
+; W64-NEXT: i32.const -1
+; W64-NEXT: i32.add
+; W64-NEXT: local.get 6
+; W64-NEXT: i32.and
+; W64-NEXT: i32.or
+; W64-NEXT: i32.and
+; W64-NEXT: local.get 2
+; W64-NEXT: i32.const -1
+; W64-NEXT: i32.add
+; W64-NEXT: local.get 7
+; W64-NEXT: i32.and
+; W64-NEXT: i32.or
+; W64-NEXT: i32.and
+; W64-NEXT: local.get 3
+; W64-NEXT: i32.const -1
+; W64-NEXT: i32.add
+; W64-NEXT: local.get 8
+; W64-NEXT: i32.and
+; W64-NEXT: i32.or
+; W64-NEXT: # fallthrough-return
+ %sel1 = call i32 @llvm.ct.select.i32(i1 %c1, i32 %a, i32 %b)
+ %sel2 = call i32 @llvm.ct.select.i32(i1 %c2, i32 %sel1, i32 %c)
+ %sel3 = call i32 @llvm.ct.select.i32(i1 %c3, i32 %sel2, i32 %d)
+ %sel4 = call i32 @llvm.ct.select.i32(i1 %c4, i32 %sel3, i32 %e)
+ ret i32 %sel4
+}
+
+; Declare the intrinsics
+declare i1 @llvm.ct.select.i1(i1, i1, i1)
+declare i32 @llvm.ct.select.i32(i1, i32, i32)
+declare ptr @llvm.ct.select.p0(i1, ptr, ptr)
diff --git a/llvm/test/CodeGen/WebAssembly/ctselect-fallback-patterns.ll b/llvm/test/CodeGen/WebAssembly/ctselect-fallback-patterns.ll
new file mode 100644
index 0000000000000..040ee44addb69
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/ctselect-fallback-patterns.ll
@@ -0,0 +1,641 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=wasm32-unknown-unknown -O3 -filetype=asm | FileCheck %s --check-prefix=W32
+; RUN: llc < %s -mtriple=wasm64-unknown-unknown -O3 -filetype=asm | FileCheck %s --check-prefix=W64
+
+; Test smin(x, 0) pattern
+define i32 @test_ctselect_smin_zero(i32 %x) {
+; W32-LABEL: test_ctselect_smin_zero:
+; W32: .functype test_ctselect_smin_zero (i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.const 31
+; W32-NEXT: i32.shr_s
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.and
+; W32-NEXT: # fallthrough-return
+;
+; W64-LABEL: test_ctselect_smin_zero:
+; W64: .functype test_ctselect_smin_zero (i32) -> (i32)
+; W64-NEXT: # %bb.0:
+; W64-NEXT: local.get 0
+; W64-NEXT: i32.const 31
+; W64-NEXT: i32.shr_s
+; W64-NEXT: local.get 0
+; W64-NEXT: i32.and
+; W64-NEXT: # fallthrough-return
+ %cmp = icmp slt i32 %x, 0
+ %result = call i32 @llvm.ct.select.i32(i1 %cmp, i32 %x, i32 0)
+ ret i32 %result
+}
+
+; Test smax(x, 0) pattern
+define i32 @test_ctselect_smax_zero(i32 %x) {
+; W32-LABEL: test_ctselect_smax_zero:
+; W32: .functype test_ctselect_smax_zero (i32) -> (i32)
+; W32-NEXT: # %bb.0:
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.const 0
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.const 0
+; W32-NEXT: i32.gt_s
+; W32-NEXT: i32.select
+; W32-NEXT: # fallthrough-return
+;
+; W64-LABEL: test_ctselect_smax_zero:
+; W64: .functype test_ctselect_smax_zero (i32) -> (i32)
+; W64-NEXT: # %bb.0:
+; W64-NEXT: local.get 0
+; W64-NEXT: i32.const 0
+; W64-NEXT: local.get 0
+; W64-NEXT: i32.const 0
+; W64-NEXT: i32.gt_s
+; W64-NEXT: i32.select
+; W64-NEXT: # fallthrough-return
+ %cmp = icmp sgt i32 %x, 0
+ %result = call i32 @llvm.ct.select.i32(i1 %cmp, i32 %x, i32 0)
+ ret i32 %result
+}
+
+; Test generic smin pattern
+define i32 @test_ctselect_smin_generic(i32 %x, i32 %y) {
+; W32-LABEL: test_ctselect_smin_generic:
+; W32: .functype test_ctselect_smin_generic (i32, i32) -> (i32)
+; W32-NEXT: .local i32
+; W32-NEXT: # %bb.0:
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.const 0
+; W32-NEXT: local.get 0
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.lt_s
+; W32-NEXT: i32.select
+; W32-NEXT: local.tee 2
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.and
+; W32-NEXT: local.get 2
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.xor
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.and
+; W32-NEXT: i32.or
+; W32-NEXT: # fallthrough-return
+;
+; W64-LABEL: test_ctselect_smin_generic:
+; W64: .functype test_ctselect_smin_generic (i32, i32) -> (i32)
+; W64-NEXT: .local i32
+; W64-NEXT: # %bb.0:
+; W64-NEXT: i32.const -1
+; W64-NEXT: i32.const 0
+; W64-NEXT: local.get 0
+; W64-NEXT: local.get 1
+; W64-NEXT: i32.lt_s
+; W64-NEXT: i32.select
+; W64-NEXT: local.tee 2
+; W64-NEXT: local.get 0
+; W64-NEXT: i32.and
+; W64-NEXT: local.get 2
+; W64-NEXT: i32.const -1
+; W64-NEXT: i32.xor
+; W64-NEXT: local.get 1
+; W64-NEXT: i32.and
+; W64-NEXT: i32.or
+; W64-NEXT: # fallthrough-return
+ %cmp = icmp slt i32 %x, %y
+ %result = call i32 @llvm.ct.select.i32(i1 %cmp, i32 %x, i32 %y)
+ ret i32 %result
+}
+
+; Test generic smax pattern
+define i32 @test_ctselect_smax_generic(i32 %x, i32 %y) {
+; W32-LABEL: test_ctselect_smax_generic:
+; W32: .functype test_ctselect_smax_generic (i32, i32) -> (i32)
+; W32-NEXT: .local i32
+; W32-NEXT: # %bb.0:
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.const 0
+; W32-NEXT: local.get 0
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.gt_s
+; W32-NEXT: i32.select
+; W32-NEXT: local.tee 2
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.and
+; W32-NEXT: local.get 2
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.xor
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.and
+; W32-NEXT: i32.or
+; W32-NEXT: # fallthrough-return
+;
+; W64-LABEL: test_ctselect_smax_generic:
+; W64: .functype test_ctselect_smax_generic (i32, i32) -> (i32)
+; W64-NEXT: .local i32
+; W64-NEXT: # %bb.0:
+; W64-NEXT: i32.const -1
+; W64-NEXT: i32.const 0
+; W64-NEXT: local.get 0
+; W64-NEXT: local.get 1
+; W64-NEXT: i32.gt_s
+; W64-NEXT: i32.select
+; W64-NEXT: local.tee 2
+; W64-NEXT: local.get 0
+; W64-NEXT: i32.and
+; W64-NEXT: local.get 2
+; W64-NEXT: i32.const -1
+; W64-NEXT: i32.xor
+; W64-NEXT: local.get 1
+; W64-NEXT: i32.and
+; W64-NEXT: i32.or
+; W64-NEXT: # fallthrough-return
+ %cmp = icmp sgt i32 %x, %y
+ %result = call i32 @llvm.ct.select.i32(i1 %cmp, i32 %x, i32 %y)
+ ret i32 %result
+}
+
+; Test umin pattern
+define i32 @test_ctselect_umin_generic(i32 %x, i32 %y) {
+; W32-LABEL: test_ctselect_umin_generic:
+; W32: .functype test_ctselect_umin_generic (i32, i32) -> (i32)
+; W32-NEXT: .local i32
+; W32-NEXT: # %bb.0:
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.const 0
+; W32-NEXT: local.get 0
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.lt_u
+; W32-NEXT: i32.select
+; W32-NEXT: local.tee 2
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.and
+; W32-NEXT: local.get 2
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.xor
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.and
+; W32-NEXT: i32.or
+; W32-NEXT: # fallthrough-return
+;
+; W64-LABEL: test_ctselect_umin_generic:
+; W64: .functype test_ctselect_umin_generic (i32, i32) -> (i32)
+; W64-NEXT: .local i32
+; W64-NEXT: # %bb.0:
+; W64-NEXT: i32.const -1
+; W64-NEXT: i32.const 0
+; W64-NEXT: local.get 0
+; W64-NEXT: local.get 1
+; W64-NEXT: i32.lt_u
+; W64-NEXT: i32.select
+; W64-NEXT: local.tee 2
+; W64-NEXT: local.get 0
+; W64-NEXT: i32.and
+; W64-NEXT: local.get 2
+; W64-NEXT: i32.const -1
+; W64-NEXT: i32.xor
+; W64-NEXT: local.get 1
+; W64-NEXT: i32.and
+; W64-NEXT: i32.or
+; W64-NEXT: # fallthrough-return
+ %cmp = icmp ult i32 %x, %y
+ %result = call i32 @llvm.ct.select.i32(i1 %cmp, i32 %x, i32 %y)
+ ret i32 %result
+}
+
+; Test umax pattern
+define i32 @test_ctselect_umax_generic(i32 %x, i32 %y) {
+; W32-LABEL: test_ctselect_umax_generic:
+; W32: .functype test_ctselect_umax_generic (i32, i32) -> (i32)
+; W32-NEXT: .local i32
+; W32-NEXT: # %bb.0:
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.const 0
+; W32-NEXT: local.get 0
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.gt_u
+; W32-NEXT: i32.select
+; W32-NEXT: local.tee 2
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.and
+; W32-NEXT: local.get 2
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.xor
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.and
+; W32-NEXT: i32.or
+; W32-NEXT: # fallthrough-return
+;
+; W64-LABEL: test_ctselect_umax_generic:
+; W64: .functype test_ctselect_umax_generic (i32, i32) -> (i32)
+; W64-NEXT: .local i32
+; W64-NEXT: # %bb.0:
+; W64-NEXT: i32.const -1
+; W64-NEXT: i32.const 0
+; W64-NEXT: local.get 0
+; W64-NEXT: local.get 1
+; W64-NEXT: i32.gt_u
+; W64-NEXT: i32.select
+; W64-NEXT: local.tee 2
+; W64-NEXT: local.get 0
+; W64-NEXT: i32.and
+; W64-NEXT: local.get 2
+; W64-NEXT: i32.const -1
+; W64-NEXT: i32.xor
+; W64-NEXT: local.get 1
+; W64-NEXT: i32.and
+; W64-NEXT: i32.or
+; W64-NEXT: # fallthrough-return
+ %cmp = icmp ugt i32 %x, %y
+ %result = call i32 @llvm.ct.select.i32(i1 %cmp, i32 %x, i32 %y)
+ ret i32 %result
+}
+
+; Test abs pattern
+define i32 @test_ctselect_abs(i32 %x) {
+; W32-LABEL: test_ctselect_abs:
+; W32: .functype test_ctselect_abs (i32) -> (i32)
+; W32-NEXT: .local i32
+; W32-NEXT: # %bb.0:
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.const 31
+; W32-NEXT: i32.shr_s
+; W32-NEXT: local.tee 1
+; W32-NEXT: i32.const 0
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.sub
+; W32-NEXT: i32.and
+; W32-NEXT: local.get 1
+; W32-NEXT: i32.const -1
+; W32-NEXT: i32.xor
+; W32-NEXT: local.get 0
+; W32-NEXT: i32.and
+; W32-NEXT: i32.or
+; W32-NEXT: # fallthrough-return
+;
+; W64-LABEL: test_ctselect_abs:
+; W64: .functype test_ctselect_abs (i32) -> (i32)
+; W64-NEXT: .local i32
+; W64-NEXT: # %bb.0:
+; W64-NEXT: local.get 0
+; W64-NEXT: i32.const 31
+; W64-NEXT: i32.shr_s
+; W6...
[truncated]
|

No description provided.