Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
376 changes: 376 additions & 0 deletions llvm/test/CodeGen/WebAssembly/ctselect-fallback-edge-cases.ll
Original file line number Diff line number Diff line change
@@ -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)
Loading
Loading