[llvm-branch-commits] [llvm] [ConstantTime][WebAssembly] Add comprehensive tests for ct.select (PR #166709)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Nov 6 12:37:20 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-webassembly
Author: Julius Alexandre (wizardengineer)
<details>
<summary>Changes</summary>
---
Patch is 79.36 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/166709.diff
5 Files Affected:
- (added) llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll (+376)
- (added) llvm/test/CodeGen/WebAssembly/ctselect-fallback-patterns.ll (+641)
- (added) llvm/test/CodeGen/WebAssembly/ctselect-fallback-vector.ll (+714)
- (added) llvm/test/CodeGen/WebAssembly/ctselect-fallback.ll (+552)
- (added) llvm/test/CodeGen/WebAssembly/ctselect-side-effects.ll (+226)
``````````diff
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]
``````````
</details>
https://github.com/llvm/llvm-project/pull/166709
More information about the llvm-branch-commits
mailing list