blob: e8eb9339633639aaa39e4882e85ca0ba83760f42 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s
; Test that SETCC_CARRY is not poison/undef
; SETCC_CARRY reads the carry flag from SUB/CMP operations
; Pattern: (a < b) ? -1 : 0 -> SETCC_CARRY with X86::COND_B
define i32 @setcc_carry_i32_lt(i32 %a, i32 %b) {
; CHECK-LABEL: setcc_carry_i32_lt:
; CHECK: # %bb.0:
; CHECK-NEXT: xorl %eax, %eax
; CHECK-NEXT: cmpl %esi, %edi
; CHECK-NEXT: sbbl %eax, %eax
; CHECK-NEXT: retq
%cmp = icmp ult i32 %a, %b
%sel = select i1 %cmp, i32 -1, i32 0
ret i32 %sel
}
; Pattern: (a >= b) ? 0 : -1 -> ~SETCC_CARRY with X86::COND_B
define i32 @setcc_carry_i32_ge(i32 %a, i32 %b) {
; CHECK-LABEL: setcc_carry_i32_ge:
; CHECK: # %bb.0:
; CHECK-NEXT: xorl %eax, %eax
; CHECK-NEXT: cmpl %esi, %edi
; CHECK-NEXT: sbbl %eax, %eax
; CHECK-NEXT: retq
%cmp = icmp uge i32 %a, %b
%sel = select i1 %cmp, i32 0, i32 -1
ret i32 %sel
}
; Pattern: (a < b) ? 1 : 0 -> SETCC_CARRY (zero-extended)
define i32 @setcc_carry_i32_lt_zext(i32 %a, i32 %b) {
; CHECK-LABEL: setcc_carry_i32_lt_zext:
; CHECK: # %bb.0:
; CHECK-NEXT: xorl %eax, %eax
; CHECK-NEXT: cmpl %esi, %edi
; CHECK-NEXT: setb %al
; CHECK-NEXT: retq
%cmp = icmp ult i32 %a, %b
%ext = zext i1 %cmp to i32
ret i32 %ext
}
; Test with i64
define i64 @setcc_carry_i64_lt(i64 %a, i64 %b) {
; CHECK-LABEL: setcc_carry_i64_lt:
; CHECK: # %bb.0:
; CHECK-NEXT: xorl %eax, %eax
; CHECK-NEXT: cmpq %rsi, %rdi
; CHECK-NEXT: sbbq %rax, %rax
; CHECK-NEXT: retq
%cmp = icmp ult i64 %a, %b
%sel = select i1 %cmp, i64 -1, i64 0
ret i64 %sel
}
; Test with i8
define i8 @setcc_carry_i8_lt(i8 %a, i8 %b) {
; CHECK-LABEL: setcc_carry_i8_lt:
; CHECK: # %bb.0:
; CHECK-NEXT: xorl %eax, %eax
; CHECK-NEXT: cmpb %sil, %dil
; CHECK-NEXT: sbbl %eax, %eax
; CHECK-NEXT: # kill: def $al killed $al killed $eax
; CHECK-NEXT: retq
%cmp = icmp ult i8 %a, %b
%sel = select i1 %cmp, i8 -1, i8 0
ret i8 %sel
}
; Test OR with SETCC_CARRY result
define i32 @setcc_carry_or(i32 %a, i32 %b, i32 %y) {
; CHECK-LABEL: setcc_carry_or:
; CHECK: # %bb.0:
; CHECK-NEXT: cmpl %esi, %edi
; CHECK-NEXT: movl $-1, %eax
; CHECK-NEXT: cmovael %edx, %eax
; CHECK-NEXT: retq
%cmp = icmp ult i32 %a, %b
%sel = select i1 %cmp, i32 -1, i32 %y
ret i32 %sel
}
; Test with constant comparison (pattern: x <= MAX ? x : -1)
define i32 @setcc_carry_clamp_max(i32 %x) {
; CHECK-LABEL: setcc_carry_clamp_max:
; CHECK: # %bb.0:
; CHECK-NEXT: cmpl $101, %edi
; CHECK-NEXT: movl $-1, %eax
; CHECK-NEXT: cmovbl %edi, %eax
; CHECK-NEXT: retq
%cmp = icmp ugt i32 %x, 100
%sel = select i1 %cmp, i32 -1, i32 %x
ret i32 %sel
}
; Test SETCC_CARRY is not poison even with freeze
; This verifies isGuaranteedNotToBeUndefOrPoisonForTargetNode works
define i32 @setcc_carry_with_freeze(i32 %a, i32 %b) {
; CHECK-LABEL: setcc_carry_with_freeze:
; CHECK: # %bb.0:
; CHECK-NEXT: xorl %eax, %eax
; CHECK-NEXT: cmpl %esi, %edi
; CHECK-NEXT: sbbl %eax, %eax
; CHECK-NEXT: retq
%cmp = icmp ult i32 %a, %b
%frozen = freeze i1 %cmp
%sel = select i1 %frozen, i32 -1, i32 0
ret i32 %sel
}