| ; 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: slti $1, $4, 0 |
| ; M32-NEXT: negu $1, $1 |
| ; M32-NEXT: jr $ra |
| ; M32-NEXT: and $2, $4, $1 |
| ; |
| ; M64-LABEL: test_ctselect_smin_zero: |
| ; M64: # %bb.0: |
| ; M64-NEXT: sll $1, $4, 0 |
| ; M64-NEXT: slti $2, $1, 0 |
| ; M64-NEXT: negu $2, $2 |
| ; M64-NEXT: jr $ra |
| ; M64-NEXT: and $2, $1, $2 |
| %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: slt $1, $zero, $4 |
| ; M32-NEXT: negu $1, $1 |
| ; M32-NEXT: jr $ra |
| ; M32-NEXT: and $2, $4, $1 |
| ; |
| ; M64-LABEL: test_ctselect_smax_zero: |
| ; M64: # %bb.0: |
| ; M64-NEXT: sll $1, $4, 0 |
| ; M64-NEXT: slt $2, $zero, $1 |
| ; M64-NEXT: negu $2, $2 |
| ; M64-NEXT: jr $ra |
| ; M64-NEXT: and $2, $1, $2 |
| %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 $2, $4, $5 |
| ; M32-NEXT: xor $1, $4, $5 |
| ; M32-NEXT: negu $2, $2 |
| ; M32-NEXT: and $1, $1, $2 |
| ; M32-NEXT: jr $ra |
| ; M32-NEXT: xor $2, $5, $1 |
| ; |
| ; M64-LABEL: test_ctselect_smin_generic: |
| ; M64: # %bb.0: |
| ; M64-NEXT: sll $1, $5, 0 |
| ; M64-NEXT: sll $2, $4, 0 |
| ; M64-NEXT: xor $3, $2, $1 |
| ; M64-NEXT: slt $2, $2, $1 |
| ; M64-NEXT: negu $2, $2 |
| ; M64-NEXT: and $2, $3, $2 |
| ; M64-NEXT: jr $ra |
| ; M64-NEXT: xor $2, $1, $2 |
| %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 $2, $5, $4 |
| ; M32-NEXT: xor $1, $4, $5 |
| ; M32-NEXT: negu $2, $2 |
| ; M32-NEXT: and $1, $1, $2 |
| ; M32-NEXT: jr $ra |
| ; M32-NEXT: xor $2, $5, $1 |
| ; |
| ; M64-LABEL: test_ctselect_smax_generic: |
| ; M64: # %bb.0: |
| ; M64-NEXT: sll $1, $5, 0 |
| ; M64-NEXT: sll $2, $4, 0 |
| ; M64-NEXT: xor $3, $2, $1 |
| ; M64-NEXT: slt $2, $1, $2 |
| ; M64-NEXT: negu $2, $2 |
| ; M64-NEXT: and $2, $3, $2 |
| ; M64-NEXT: jr $ra |
| ; M64-NEXT: xor $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 $2, $4, $5 |
| ; M32-NEXT: xor $1, $4, $5 |
| ; M32-NEXT: negu $2, $2 |
| ; M32-NEXT: and $1, $1, $2 |
| ; M32-NEXT: jr $ra |
| ; M32-NEXT: xor $2, $5, $1 |
| ; |
| ; M64-LABEL: test_ctselect_umin_generic: |
| ; M64: # %bb.0: |
| ; M64-NEXT: sll $1, $5, 0 |
| ; M64-NEXT: sll $2, $4, 0 |
| ; M64-NEXT: xor $3, $2, $1 |
| ; M64-NEXT: sltu $2, $2, $1 |
| ; M64-NEXT: negu $2, $2 |
| ; M64-NEXT: and $2, $3, $2 |
| ; M64-NEXT: jr $ra |
| ; M64-NEXT: xor $2, $1, $2 |
| %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 $2, $5, $4 |
| ; M32-NEXT: xor $1, $4, $5 |
| ; M32-NEXT: negu $2, $2 |
| ; M32-NEXT: and $1, $1, $2 |
| ; M32-NEXT: jr $ra |
| ; M32-NEXT: xor $2, $5, $1 |
| ; |
| ; M64-LABEL: test_ctselect_umax_generic: |
| ; M64: # %bb.0: |
| ; M64-NEXT: sll $1, $5, 0 |
| ; M64-NEXT: sll $2, $4, 0 |
| ; M64-NEXT: xor $3, $2, $1 |
| ; M64-NEXT: sltu $2, $1, $2 |
| ; M64-NEXT: negu $2, $2 |
| ; M64-NEXT: and $2, $3, $2 |
| ; M64-NEXT: jr $ra |
| ; M64-NEXT: xor $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: slti $1, $4, 0 |
| ; M32-NEXT: negu $2, $4 |
| ; M32-NEXT: negu $1, $1 |
| ; M32-NEXT: xor $2, $2, $4 |
| ; M32-NEXT: and $1, $2, $1 |
| ; M32-NEXT: jr $ra |
| ; M32-NEXT: xor $2, $4, $1 |
| ; |
| ; M64-LABEL: test_ctselect_abs: |
| ; M64: # %bb.0: |
| ; M64-NEXT: sll $1, $4, 0 |
| ; M64-NEXT: slti $2, $1, 0 |
| ; M64-NEXT: negu $3, $1 |
| ; M64-NEXT: negu $2, $2 |
| ; M64-NEXT: xor $3, $3, $1 |
| ; M64-NEXT: and $2, $3, $2 |
| ; M64-NEXT: jr $ra |
| ; M64-NEXT: xor $2, $1, $2 |
| %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: slti $1, $4, 0 |
| ; M32-NEXT: negu $2, $4 |
| ; M32-NEXT: negu $1, $1 |
| ; M32-NEXT: xor $3, $4, $2 |
| ; M32-NEXT: and $1, $3, $1 |
| ; M32-NEXT: jr $ra |
| ; M32-NEXT: xor $2, $2, $1 |
| ; |
| ; M64-LABEL: test_ctselect_nabs: |
| ; M64: # %bb.0: |
| ; M64-NEXT: sll $1, $4, 0 |
| ; M64-NEXT: slti $2, $1, 0 |
| ; M64-NEXT: negu $3, $1 |
| ; M64-NEXT: negu $2, $2 |
| ; M64-NEXT: xor $1, $1, $3 |
| ; M64-NEXT: and $1, $1, $2 |
| ; M64-NEXT: jr $ra |
| ; M64-NEXT: xor $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: slti $1, $4, 0 |
| ; M32-NEXT: jr $ra |
| ; M32-NEXT: negu $2, $1 |
| ; |
| ; M64-LABEL: test_ctselect_sign_extend: |
| ; M64: # %bb.0: |
| ; M64-NEXT: sll $1, $4, 0 |
| ; M64-NEXT: slti $1, $1, 0 |
| ; M64-NEXT: jr $ra |
| ; M64-NEXT: negu $2, $1 |
| %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: move $2, $5 |
| ; |
| ; M64-LABEL: test_ctselect_constant_folding_false: |
| ; M64: # %bb.0: |
| ; M64-NEXT: jr $ra |
| ; M64-NEXT: sll $2, $5, 0 |
| %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: jr $ra |
| ; M32-NEXT: move $2, $5 |
| ; |
| ; M64-LABEL: test_ctselect_identical_operands: |
| ; M64: # %bb.0: |
| ; M64-NEXT: jr $ra |
| ; M64-NEXT: sll $2, $5, 0 |
| %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 $2, $4, $5 |
| ; M32-NEXT: xor $1, $7, $6 |
| ; M32-NEXT: sltiu $2, $2, 1 |
| ; M32-NEXT: negu $2, $2 |
| ; M32-NEXT: and $1, $1, $2 |
| ; M32-NEXT: jr $ra |
| ; M32-NEXT: xor $2, $6, $1 |
| ; |
| ; M64-LABEL: test_ctselect_inverted_condition: |
| ; M64: # %bb.0: |
| ; M64-NEXT: sll $1, $5, 0 |
| ; M64-NEXT: sll $2, $4, 0 |
| ; M64-NEXT: xor $1, $2, $1 |
| ; M64-NEXT: xor $2, $7, $6 |
| ; M64-NEXT: sltiu $1, $1, 1 |
| ; M64-NEXT: sll $2, $2, 0 |
| ; M64-NEXT: negu $1, $1 |
| ; M64-NEXT: and $1, $2, $1 |
| ; M64-NEXT: sll $2, $6, 0 |
| ; M64-NEXT: jr $ra |
| ; M64-NEXT: xor $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: lw $1, 16($sp) |
| ; M32-NEXT: andi $3, $4, 1 |
| ; M32-NEXT: negu $3, $3 |
| ; M32-NEXT: xor $2, $7, $1 |
| ; M32-NEXT: and $2, $2, $3 |
| ; M32-NEXT: andi $3, $5, 1 |
| ; M32-NEXT: xor $1, $1, $2 |
| ; M32-NEXT: lw $2, 20($sp) |
| ; M32-NEXT: negu $3, $3 |
| ; M32-NEXT: xor $1, $1, $2 |
| ; M32-NEXT: and $1, $1, $3 |
| ; M32-NEXT: lw $3, 24($sp) |
| ; M32-NEXT: xor $1, $2, $1 |
| ; M32-NEXT: andi $2, $6, 1 |
| ; M32-NEXT: xor $1, $1, $3 |
| ; M32-NEXT: negu $2, $2 |
| ; M32-NEXT: and $1, $1, $2 |
| ; M32-NEXT: jr $ra |
| ; M32-NEXT: xor $2, $3, $1 |
| ; |
| ; M64-LABEL: test_ctselect_chain: |
| ; M64: # %bb.0: |
| ; M64-NEXT: sll $1, $4, 0 |
| ; M64-NEXT: xor $2, $7, $8 |
| ; M64-NEXT: sll $3, $5, 0 |
| ; M64-NEXT: andi $1, $1, 1 |
| ; M64-NEXT: sll $2, $2, 0 |
| ; M64-NEXT: andi $3, $3, 1 |
| ; M64-NEXT: negu $1, $1 |
| ; M64-NEXT: negu $3, $3 |
| ; M64-NEXT: and $1, $2, $1 |
| ; M64-NEXT: sll $2, $8, 0 |
| ; M64-NEXT: xor $1, $2, $1 |
| ; M64-NEXT: sll $2, $9, 0 |
| ; M64-NEXT: xor $1, $1, $2 |
| ; M64-NEXT: and $1, $1, $3 |
| ; M64-NEXT: sll $3, $6, 0 |
| ; M64-NEXT: xor $1, $2, $1 |
| ; M64-NEXT: andi $2, $3, 1 |
| ; M64-NEXT: sll $3, $10, 0 |
| ; M64-NEXT: xor $1, $1, $3 |
| ; M64-NEXT: negu $2, $2 |
| ; M64-NEXT: and $1, $1, $2 |
| ; M64-NEXT: jr $ra |
| ; M64-NEXT: xor $2, $3, $1 |
| %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: slti $1, $5, 0 |
| ; M32-NEXT: negu $1, $1 |
| ; M32-NEXT: and $2, $4, $1 |
| ; M32-NEXT: jr $ra |
| ; M32-NEXT: and $3, $5, $1 |
| ; |
| ; M64-LABEL: test_ctselect_i64_smin_zero: |
| ; M64: # %bb.0: |
| ; M64-NEXT: dsra $1, $4, 63 |
| ; M64-NEXT: jr $ra |
| ; M64-NEXT: and $2, $4, $1 |
| %cmp = icmp slt i64 %x, 0 |
| %result = call i64 @llvm.ct.select.i64(i1 %cmp, i64 %x, i64 0) |
| ret i64 %result |
| } |
| |
| ; Declare the intrinsics |
| declare i32 @llvm.ct.select.i32(i1, i32, i32) |
| declare i64 @llvm.ct.select.i64(i1, i64, i64) |