| ; 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 |
| } |