Skip to content

Conversation

@wizardengineer
Copy link
Contributor

No description provided.

Copy link
Contributor Author

wizardengineer commented Nov 6, 2025

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.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@llvmbot
Copy link
Member

llvmbot commented Nov 6, 2025

@llvm/pr-subscribers-backend-webassembly

Author: Julius Alexandre (wizardengineer)

Changes

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 --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]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants