-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[ConstantTime][MIPS] Add comprehensive tests for ct.select #166705
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][MIPS] Add comprehensive tests for ct.select #166705
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. |
22e9292 to
9dac6ca
Compare
|
@llvm/pr-subscribers-backend-mips Author: Julius Alexandre (wizardengineer) ChangesPatch is 70.17 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/166705.diff 5 Files Affected:
diff --git a/llvm/test/CodeGen/Mips/ctselect-fallback-edge-cases.ll b/llvm/test/CodeGen/Mips/ctselect-fallback-edge-cases.ll
new file mode 100644
index 0000000000000..f1831a625d4a4
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/ctselect-fallback-edge-cases.ll
@@ -0,0 +1,244 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=mipsel-unknown-linux-gnu -O3 | FileCheck %s --check-prefix=M32
+; RUN: llc < %s -mtriple=mips64el-unknown-linux-gnu -O3 | FileCheck %s --check-prefix=M64
+
+; Portable edge case tests
+
+; Test with small integer types
+define i1 @test_ctselect_i1(i1 %cond, i1 %a, i1 %b) {
+; M32-LABEL: test_ctselect_i1:
+; M32: # %bb.0:
+; M32-NEXT: xori $2, $4, 1
+; M32-NEXT: and $1, $4, $5
+; M32-NEXT: and $2, $2, $6
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $1, $2
+;
+; M64-LABEL: test_ctselect_i1:
+; M64: # %bb.0:
+; M64-NEXT: sll $2, $4, 0
+; M64-NEXT: sll $1, $6, 0
+; M64-NEXT: xori $2, $2, 1
+; M64-NEXT: and $1, $2, $1
+; M64-NEXT: and $2, $4, $5
+; M64-NEXT: sll $2, $2, 0
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $2, $1
+ %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) {
+; M32-LABEL: test_ctselect_extremal_values:
+; M32: # %bb.0:
+; M32-NEXT: lui $3, 32767
+; M32-NEXT: andi $1, $4, 1
+; M32-NEXT: negu $2, $1
+; M32-NEXT: ori $3, $3, 65535
+; M32-NEXT: addiu $1, $1, -1
+; M32-NEXT: and $2, $2, $3
+; M32-NEXT: lui $3, 32768
+; M32-NEXT: and $1, $1, $3
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_extremal_values:
+; M64: # %bb.0:
+; M64-NEXT: sll $1, $4, 0
+; M64-NEXT: lui $3, 32767
+; M64-NEXT: andi $1, $1, 1
+; M64-NEXT: ori $3, $3, 65535
+; M64-NEXT: negu $2, $1
+; M64-NEXT: addiu $1, $1, -1
+; M64-NEXT: and $2, $2, $3
+; M64-NEXT: lui $3, 32768
+; M64-NEXT: and $1, $1, $3
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $2, $1
+ %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) {
+; M32-LABEL: test_ctselect_null_ptr:
+; M32: # %bb.0:
+; M32-NEXT: andi $1, $4, 1
+; M32-NEXT: negu $1, $1
+; M32-NEXT: jr $ra
+; M32-NEXT: and $2, $1, $5
+;
+; M64-LABEL: test_ctselect_null_ptr:
+; M64: # %bb.0:
+; M64-NEXT: andi $1, $4, 1
+; M64-NEXT: dnegu $1, $1
+; M64-NEXT: jr $ra
+; M64-NEXT: and $2, $1, $5
+ %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) {
+; M32-LABEL: test_ctselect_function_ptr:
+; M32: # %bb.0:
+; M32-NEXT: andi $1, $4, 1
+; M32-NEXT: negu $2, $1
+; M32-NEXT: addiu $1, $1, -1
+; M32-NEXT: and $2, $2, $5
+; M32-NEXT: and $1, $1, $6
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_function_ptr:
+; M64: # %bb.0:
+; M64-NEXT: andi $1, $4, 1
+; M64-NEXT: dnegu $2, $1
+; M64-NEXT: daddiu $1, $1, -1
+; M64-NEXT: and $2, $2, $5
+; M64-NEXT: and $1, $1, $6
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $2, $1
+ %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) {
+; M32-LABEL: test_ctselect_ptr_cmp:
+; M32: # %bb.0:
+; M32-NEXT: xor $1, $4, $5
+; M32-NEXT: sltu $1, $zero, $1
+; M32-NEXT: addiu $1, $1, -1
+; M32-NEXT: and $2, $1, $6
+; M32-NEXT: not $1, $1
+; M32-NEXT: and $1, $1, $7
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_ptr_cmp:
+; M64: # %bb.0:
+; M64-NEXT: xor $1, $4, $5
+; M64-NEXT: daddiu $3, $zero, -1
+; M64-NEXT: daddiu $2, $zero, -1
+; M64-NEXT: movn $3, $zero, $1
+; M64-NEXT: xor $2, $3, $2
+; M64-NEXT: and $1, $3, $6
+; M64-NEXT: and $2, $2, $7
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $1, $2
+ %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) {
+; M32-LABEL: test_ctselect_struct_ptr:
+; M32: # %bb.0:
+; M32-NEXT: andi $1, $4, 1
+; M32-NEXT: negu $2, $1
+; M32-NEXT: addiu $1, $1, -1
+; M32-NEXT: and $2, $2, $5
+; M32-NEXT: and $1, $1, $6
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_struct_ptr:
+; M64: # %bb.0:
+; M64-NEXT: andi $1, $4, 1
+; M64-NEXT: dnegu $2, $1
+; M64-NEXT: daddiu $1, $1, -1
+; M64-NEXT: and $2, $2, $5
+; M64-NEXT: and $1, $1, $6
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $2, $1
+ %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) {
+; M32-LABEL: test_ctselect_deeply_nested:
+; M32: # %bb.0:
+; M32-NEXT: andi $1, $4, 1
+; M32-NEXT: lw $3, 16($sp)
+; M32-NEXT: lw $9, 32($sp)
+; M32-NEXT: lw $8, 28($sp)
+; M32-NEXT: negu $2, $1
+; M32-NEXT: addiu $1, $1, -1
+; M32-NEXT: and $2, $2, $3
+; M32-NEXT: lw $3, 20($sp)
+; M32-NEXT: and $1, $1, $3
+; M32-NEXT: andi $3, $5, 1
+; M32-NEXT: or $1, $2, $1
+; M32-NEXT: andi $2, $6, 1
+; M32-NEXT: andi $6, $7, 1
+; M32-NEXT: negu $4, $3
+; M32-NEXT: addiu $3, $3, -1
+; M32-NEXT: addiu $7, $6, -1
+; M32-NEXT: and $1, $4, $1
+; M32-NEXT: addiu $5, $2, -1
+; M32-NEXT: negu $2, $2
+; M32-NEXT: negu $6, $6
+; M32-NEXT: and $4, $7, $9
+; M32-NEXT: lw $7, 24($sp)
+; M32-NEXT: and $5, $5, $8
+; M32-NEXT: and $3, $3, $7
+; M32-NEXT: or $1, $1, $3
+; M32-NEXT: and $1, $2, $1
+; M32-NEXT: or $1, $1, $5
+; M32-NEXT: and $1, $6, $1
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $1, $4
+;
+; M64-LABEL: test_ctselect_deeply_nested:
+; M64: # %bb.0:
+; M64-NEXT: sll $1, $4, 0
+; M64-NEXT: sll $3, $8, 0
+; M64-NEXT: sll $4, $5, 0
+; M64-NEXT: lw $8, 0($sp)
+; M64-NEXT: andi $1, $1, 1
+; M64-NEXT: andi $4, $4, 1
+; M64-NEXT: negu $2, $1
+; M64-NEXT: addiu $1, $1, -1
+; M64-NEXT: negu $5, $4
+; M64-NEXT: addiu $4, $4, -1
+; M64-NEXT: and $2, $2, $3
+; M64-NEXT: sll $3, $9, 0
+; M64-NEXT: and $1, $1, $3
+; M64-NEXT: sll $3, $11, 0
+; M64-NEXT: or $1, $2, $1
+; M64-NEXT: sll $2, $6, 0
+; M64-NEXT: sll $6, $7, 0
+; M64-NEXT: andi $2, $2, 1
+; M64-NEXT: and $1, $5, $1
+; M64-NEXT: andi $6, $6, 1
+; M64-NEXT: addiu $5, $2, -1
+; M64-NEXT: negu $2, $2
+; M64-NEXT: addiu $7, $6, -1
+; M64-NEXT: negu $6, $6
+; M64-NEXT: and $3, $5, $3
+; M64-NEXT: sll $5, $10, 0
+; M64-NEXT: and $7, $7, $8
+; M64-NEXT: and $4, $4, $5
+; M64-NEXT: or $1, $1, $4
+; M64-NEXT: and $1, $2, $1
+; M64-NEXT: or $1, $1, $3
+; M64-NEXT: and $1, $6, $1
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $1, $7
+ %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/Mips/ctselect-fallback-patterns.ll b/llvm/test/CodeGen/Mips/ctselect-fallback-patterns.ll
new file mode 100644
index 0000000000000..2e65e586ce5fa
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/ctselect-fallback-patterns.ll
@@ -0,0 +1,426 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=mipsel-unknown-linux-gnu -O3 | FileCheck %s --check-prefix=M32
+; RUN: llc < %s -mtriple=mips64el-unknown-linux-gnu -O3 | FileCheck %s --check-prefix=M64
+
+; Test smin(x, 0) pattern
+define i32 @test_ctselect_smin_zero(i32 %x) {
+; M32-LABEL: test_ctselect_smin_zero:
+; M32: # %bb.0:
+; M32-NEXT: sra $1, $4, 31
+; M32-NEXT: jr $ra
+; M32-NEXT: and $2, $1, $4
+;
+; M64-LABEL: test_ctselect_smin_zero:
+; M64: # %bb.0:
+; M64-NEXT: sll $1, $4, 0
+; M64-NEXT: sra $2, $1, 31
+; M64-NEXT: jr $ra
+; M64-NEXT: and $2, $2, $1
+ %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) {
+; M32-LABEL: test_ctselect_smax_zero:
+; M32: # %bb.0:
+; M32-NEXT: slti $1, $4, 1
+; M32-NEXT: movn $4, $zero, $1
+; M32-NEXT: jr $ra
+; M32-NEXT: move $2, $4
+;
+; M64-LABEL: test_ctselect_smax_zero:
+; M64: # %bb.0:
+; M64-NEXT: sll $2, $4, 0
+; M64-NEXT: slti $1, $2, 1
+; M64-NEXT: jr $ra
+; M64-NEXT: movn $2, $zero, $1
+ %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) {
+; M32-LABEL: test_ctselect_smin_generic:
+; M32: # %bb.0:
+; M32-NEXT: slt $1, $4, $5
+; M32-NEXT: xori $1, $1, 1
+; M32-NEXT: addiu $1, $1, -1
+; M32-NEXT: and $2, $1, $4
+; M32-NEXT: not $1, $1
+; M32-NEXT: and $1, $1, $5
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_smin_generic:
+; M64: # %bb.0:
+; M64-NEXT: sll $1, $5, 0
+; M64-NEXT: sll $2, $4, 0
+; M64-NEXT: slt $3, $2, $1
+; M64-NEXT: xori $3, $3, 1
+; M64-NEXT: addiu $3, $3, -1
+; M64-NEXT: and $2, $3, $2
+; M64-NEXT: not $3, $3
+; M64-NEXT: and $1, $3, $1
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $2, $1
+ %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) {
+; M32-LABEL: test_ctselect_smax_generic:
+; M32: # %bb.0:
+; M32-NEXT: slt $1, $5, $4
+; M32-NEXT: xori $1, $1, 1
+; M32-NEXT: addiu $1, $1, -1
+; M32-NEXT: and $2, $1, $4
+; M32-NEXT: not $1, $1
+; M32-NEXT: and $1, $1, $5
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_smax_generic:
+; M64: # %bb.0:
+; M64-NEXT: sll $1, $4, 0
+; M64-NEXT: sll $2, $5, 0
+; M64-NEXT: slt $3, $2, $1
+; M64-NEXT: xori $3, $3, 1
+; M64-NEXT: addiu $3, $3, -1
+; M64-NEXT: and $1, $3, $1
+; M64-NEXT: not $3, $3
+; M64-NEXT: and $2, $3, $2
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $1, $2
+ %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) {
+; M32-LABEL: test_ctselect_umin_generic:
+; M32: # %bb.0:
+; M32-NEXT: sltu $1, $4, $5
+; M32-NEXT: xori $1, $1, 1
+; M32-NEXT: addiu $1, $1, -1
+; M32-NEXT: and $2, $1, $4
+; M32-NEXT: not $1, $1
+; M32-NEXT: and $1, $1, $5
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_umin_generic:
+; M64: # %bb.0:
+; M64-NEXT: sll $1, $5, 0
+; M64-NEXT: sll $2, $4, 0
+; M64-NEXT: sltu $3, $2, $1
+; M64-NEXT: xori $3, $3, 1
+; M64-NEXT: addiu $3, $3, -1
+; M64-NEXT: and $2, $3, $2
+; M64-NEXT: not $3, $3
+; M64-NEXT: and $1, $3, $1
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $2, $1
+ %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) {
+; M32-LABEL: test_ctselect_umax_generic:
+; M32: # %bb.0:
+; M32-NEXT: sltu $1, $5, $4
+; M32-NEXT: xori $1, $1, 1
+; M32-NEXT: addiu $1, $1, -1
+; M32-NEXT: and $2, $1, $4
+; M32-NEXT: not $1, $1
+; M32-NEXT: and $1, $1, $5
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_umax_generic:
+; M64: # %bb.0:
+; M64-NEXT: sll $1, $4, 0
+; M64-NEXT: sll $2, $5, 0
+; M64-NEXT: sltu $3, $2, $1
+; M64-NEXT: xori $3, $3, 1
+; M64-NEXT: addiu $3, $3, -1
+; M64-NEXT: and $1, $3, $1
+; M64-NEXT: not $3, $3
+; M64-NEXT: and $2, $3, $2
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $1, $2
+ %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) {
+; M32-LABEL: test_ctselect_abs:
+; M32: # %bb.0:
+; M32-NEXT: negu $1, $4
+; M32-NEXT: sra $2, $4, 31
+; M32-NEXT: and $1, $2, $1
+; M32-NEXT: not $2, $2
+; M32-NEXT: and $2, $2, $4
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $1, $2
+;
+; M64-LABEL: test_ctselect_abs:
+; M64: # %bb.0:
+; M64-NEXT: sll $1, $4, 0
+; M64-NEXT: negu $2, $1
+; M64-NEXT: sra $3, $1, 31
+; M64-NEXT: and $2, $3, $2
+; M64-NEXT: not $3, $3
+; M64-NEXT: and $1, $3, $1
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $2, $1
+ %neg = sub i32 0, %x
+ %cmp = icmp slt i32 %x, 0
+ %result = call i32 @llvm.ct.select.i32(i1 %cmp, i32 %neg, i32 %x)
+ ret i32 %result
+}
+
+; Test nabs pattern (negative abs)
+define i32 @test_ctselect_nabs(i32 %x) {
+; M32-LABEL: test_ctselect_nabs:
+; M32: # %bb.0:
+; M32-NEXT: sra $1, $4, 31
+; M32-NEXT: negu $3, $4
+; M32-NEXT: and $2, $1, $4
+; M32-NEXT: not $1, $1
+; M32-NEXT: and $1, $1, $3
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_nabs:
+; M64: # %bb.0:
+; M64-NEXT: sll $1, $4, 0
+; M64-NEXT: sra $2, $1, 31
+; M64-NEXT: and $3, $2, $1
+; M64-NEXT: negu $1, $1
+; M64-NEXT: not $2, $2
+; M64-NEXT: and $1, $2, $1
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $3, $1
+ %neg = sub i32 0, %x
+ %cmp = icmp slt i32 %x, 0
+ %result = call i32 @llvm.ct.select.i32(i1 %cmp, i32 %x, i32 %neg)
+ ret i32 %result
+}
+
+; Test sign extension pattern
+define i32 @test_ctselect_sign_extend(i32 %x) {
+; M32-LABEL: test_ctselect_sign_extend:
+; M32: # %bb.0:
+; M32-NEXT: jr $ra
+; M32-NEXT: sra $2, $4, 31
+;
+; M64-LABEL: test_ctselect_sign_extend:
+; M64: # %bb.0:
+; M64-NEXT: sll $1, $4, 0
+; M64-NEXT: jr $ra
+; M64-NEXT: sra $2, $1, 31
+ %cmp = icmp slt i32 %x, 0
+ %result = call i32 @llvm.ct.select.i32(i1 %cmp, i32 -1, i32 0)
+ ret i32 %result
+}
+
+; Test zero extension pattern
+define i32 @test_ctselect_zero_extend(i32 %x) {
+; M32-LABEL: test_ctselect_zero_extend:
+; M32: # %bb.0:
+; M32-NEXT: jr $ra
+; M32-NEXT: sltu $2, $zero, $4
+;
+; M64-LABEL: test_ctselect_zero_extend:
+; M64: # %bb.0:
+; M64-NEXT: sll $1, $4, 0
+; M64-NEXT: jr $ra
+; M64-NEXT: sltu $2, $zero, $1
+ %cmp = icmp ne i32 %x, 0
+ %result = call i32 @llvm.ct.select.i32(i1 %cmp, i32 1, i32 0)
+ ret i32 %result
+}
+
+; Test constant folding with known condition
+define i32 @test_ctselect_constant_folding_true(i32 %a, i32 %b) {
+; M32-LABEL: test_ctselect_constant_folding_true:
+; M32: # %bb.0:
+; M32-NEXT: jr $ra
+; M32-NEXT: move $2, $4
+;
+; M64-LABEL: test_ctselect_constant_folding_true:
+; M64: # %bb.0:
+; M64-NEXT: jr $ra
+; M64-NEXT: sll $2, $4, 0
+ %result = call i32 @llvm.ct.select.i32(i1 true, i32 %a, i32 %b)
+ ret i32 %result
+}
+
+define i32 @test_ctselect_constant_folding_false(i32 %a, i32 %b) {
+; M32-LABEL: test_ctselect_constant_folding_false:
+; M32: # %bb.0:
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $zero, $5
+;
+; M64-LABEL: test_ctselect_constant_folding_false:
+; M64: # %bb.0:
+; M64-NEXT: sll $1, $5, 0
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $zero, $1
+ %result = call i32 @llvm.ct.select.i32(i1 false, i32 %a, i32 %b)
+ ret i32 %result
+}
+
+; Test with identical operands
+define i32 @test_ctselect_identical_operands(i1 %cond, i32 %x) {
+; M32-LABEL: test_ctselect_identical_operands:
+; M32: # %bb.0:
+; M32-NEXT: andi $1, $4, 1
+; M32-NEXT: negu $2, $1
+; M32-NEXT: addiu $1, $1, -1
+; M32-NEXT: and $2, $2, $5
+; M32-NEXT: and $1, $1, $5
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_identical_operands:
+; M64: # %bb.0:
+; M64-NEXT: sll $1, $4, 0
+; M64-NEXT: sll $3, $5, 0
+; M64-NEXT: andi $1, $1, 1
+; M64-NEXT: negu $2, $1
+; M64-NEXT: addiu $1, $1, -1
+; M64-NEXT: and $2, $2, $3
+; M64-NEXT: and $1, $1, $3
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $2, $1
+ %result = call i32 @llvm.ct.select.i32(i1 %cond, i32 %x, i32 %x)
+ ret i32 %result
+}
+
+; Test with inverted condition
+define i32 @test_ctselect_inverted_condition(i32 %x, i32 %y, i32 %a, i32 %b) {
+; M32-LABEL: test_ctselect_inverted_condition:
+; M32: # %bb.0:
+; M32-NEXT: xor $1, $4, $5
+; M32-NEXT: sltiu $1, $1, 1
+; M32-NEXT: addiu $1, $1, -1
+; M32-NEXT: and $2, $1, $6
+; M32-NEXT: not $1, $1
+; M32-NEXT: and $1, $1, $7
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $2, $1
+;
+; M64-LABEL: test_ctselect_inverted_condition:
+; M64: # %bb.0:
+; M64-NEXT: sll $1, $5, 0
+; M64-NEXT: sll $2, $4, 0
+; M64-NEXT: sll $3, $7, 0
+; M64-NEXT: xor $1, $2, $1
+; M64-NEXT: sll $2, $6, 0
+; M64-NEXT: sltiu $1, $1, 1
+; M64-NEXT: addiu $1, $1, -1
+; M64-NEXT: and $2, $1, $2
+; M64-NEXT: not $1, $1
+; M64-NEXT: and $1, $1, $3
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $2, $1
+ %cmp = icmp eq i32 %x, %y
+ %not_cmp = xor i1 %cmp, true
+ %result = call i32 @llvm.ct.select.i32(i1 %not_cmp, i32 %a, i32 %b)
+ ret i32 %result
+}
+
+; Test chain of ct.select operations
+define i32 @test_ctselect_chain(i1 %c1, i1 %c2, i1 %c3, i32 %a, i32 %b, i32 %c, i32 %d) {
+; M32-LABEL: test_ctselect_chain:
+; M32: # %bb.0:
+; M32-NEXT: andi $1, $4, 1
+; M32-NEXT: andi $3, $5, 1
+; M32-NEXT: lw $5, 16($sp)
+; M32-NEXT: negu $2, $1
+; M32-NEXT: addiu $1, $1, -1
+; M32-NEXT: negu $4, $3
+; M32-NEXT: addiu $3, $3, -1
+; M32-NEXT: and $1, $1, $5
+; M32-NEXT: and $2, $2, $7
+; M32-NEXT: lw $5, 24($sp)
+; M32-NEXT: or $1, $2, $1
+; M32-NEXT: andi $2, $6, 1
+; M32-NEXT: and $1, $4, $1
+; M32-NEXT: addiu $4, $2, -1
+; M32-NEXT: negu $2, $2
+; M32-NEXT: and $4, $4, $5
+; M32-NEXT: lw $5, 20($sp)
+; M32-NEXT: and $3, $3, $5
+; M32-NEXT: or $1, $1, $3
+; M32-NEXT: and $1, $2, $1
+; M32-NEXT: jr $ra
+; M32-NEXT: or $2, $1, $4
+;
+; M64-LABEL: test_ctselect_chain:
+; M64: # %bb.0:
+; M64-NEXT: sll $1, $4, 0
+; M64-NEXT: sll $3, $7, 0
+; M64-NEXT: sll $4, $5, 0
+; M64-NEXT: andi $1, $1, 1
+; M64-NEXT: andi $4, $4, 1
+; M64-NEXT: negu $2, $1
+; M64-NEXT: addiu $1, $1, -1
+; M64-NEXT: negu $5, $4
+; M64-NEXT: addiu $4, $4, -1
+; M64-NEXT: and $2, $2, $3
+; M64-NEXT: sll $3, $8, 0
+; M64-NEXT: and $1, $1, $3
+; M64-NEXT: sll $3, $6, 0
+; M64-NEXT: sll $6, $10, 0
+; M64-NEXT: or $1, $2, $1
+; M64-NEXT: andi $3, $3, 1
+; M64-NEXT: and $1, $5, $1
+; M64-NEXT: sll $5, $9, 0
+; M64-NEXT: addiu $2, $3, -1
+; M64-NEXT: negu $3, $3
+; M64-NEXT: and $4, $4, $5
+; M64-NEXT: and $2, $2, $6
+; M64-NEXT: or $1, $1, $4
+; M64-NEXT: and $1, $3, $1
+; M64-NEXT: jr $ra
+; M64-NEXT: or $2, $1, $2
+ %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)
+ ret i32 %sel3
+}
+
+; Test for 64-bit operations (supported on all 64-bit architectures)
+define i64 @test_ctselect_i64_smin_zero(i64 %x) {
+; M32-LABEL: test_ctselect_i64_smin_zero:
+; M32: # %bb.0:
+; M32-NEXT: sra $1, $5, 31
+; M32-NEXT: and $2, $1, $4
+; M32-NEXT: jr $ra
+; M32-NEXT: and $3, $1, $5
+;
+; M64-LABEL: test_ctselect_i64_smin_zero:
+; M64: # %bb.0:
+; M64-NEXT: dsra ...
[truncated]
|

No description provided.