; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
; RUN: | FileCheck %s -check-prefixes=RV32
; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
; RUN: | FileCheck %s -check-prefixes=RV64
;Copy tests from llvm/tests/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll
;to test shouldFormOverflowOp on RISCV
define i64 @uaddo1_overflow_used(i64 %a, i64 %b) nounwind ssp {
; RV32-LABEL: uaddo1_overflow_used:
; RV32: # %bb.0:
; RV32-NEXT: add a5, a3, a1
; RV32-NEXT: add a4, a2, a0
; RV32-NEXT: sltu a6, a4, a2
; RV32-NEXT: add a5, a5, a6
; RV32-NEXT: beq a5, a1, .LBB0_2
; RV32-NEXT: # %bb.1:
; RV32-NEXT: sltu a0, a5, a1
; RV32-NEXT: beqz a0, .LBB0_3
; RV32-NEXT: j .LBB0_4
; RV32-NEXT: .LBB0_2:
; RV32-NEXT: sltu a0, a4, a0
; RV32-NEXT: bnez a0, .LBB0_4
; RV32-NEXT: .LBB0_3:
; RV32-NEXT: li a2, 42
; RV32-NEXT: .LBB0_4:
; RV32-NEXT: neg a1, a0
; RV32-NEXT: and a1, a1, a3
; RV32-NEXT: mv a0, a2
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo1_overflow_used:
; RV64: # %bb.0:
; RV64-NEXT: add a2, a1, a0
; RV64-NEXT: bltu a2, a0, .LBB0_2
; RV64-NEXT: # %bb.1:
; RV64-NEXT: li a1, 42
; RV64-NEXT: .LBB0_2:
; RV64-NEXT: mv a0, a1
; RV64-NEXT: ret
%add = add i64 %b, %a
%cmp = icmp ult i64 %add, %a
%Q = select i1 %cmp, i64 %b, i64 42
ret i64 %Q
}
define i64 @uaddo1_math_overflow_used(i64 %a, i64 %b, ptr %res) nounwind ssp {
; RV32-LABEL: uaddo1_math_overflow_used:
; RV32: # %bb.0:
; RV32-NEXT: add a5, a3, a1
; RV32-NEXT: add a0, a2, a0
; RV32-NEXT: sltu a1, a0, a2
; RV32-NEXT: add a5, a5, a1
; RV32-NEXT: beq a5, a3, .LBB1_2
; RV32-NEXT: # %bb.1:
; RV32-NEXT: sltu a1, a5, a3
; RV32-NEXT: .LBB1_2:
; RV32-NEXT: bnez a1, .LBB1_4
; RV32-NEXT: # %bb.3:
; RV32-NEXT: li a2, 42
; RV32-NEXT: .LBB1_4:
; RV32-NEXT: neg a1, a1
; RV32-NEXT: and a1, a1, a3
; RV32-NEXT: sw a0, 0(a4)
; RV32-NEXT: sw a5, 4(a4)
; RV32-NEXT: mv a0, a2
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo1_math_overflow_used:
; RV64: # %bb.0:
; RV64-NEXT: add a0, a1, a0
; RV64-NEXT: bltu a0, a1, .LBB1_2
; RV64-NEXT: # %bb.1:
; RV64-NEXT: li a1, 42
; RV64-NEXT: .LBB1_2:
; RV64-NEXT: sd a0, 0(a2)
; RV64-NEXT: mv a0, a1
; RV64-NEXT: ret
%add = add i64 %b, %a
%cmp = icmp ult i64 %add, %a
%Q = select i1 %cmp, i64 %b, i64 42
store i64 %add, ptr %res
ret i64 %Q
}
define i64 @uaddo2_overflow_used(i64 %a, i64 %b) nounwind ssp {
; RV32-LABEL: uaddo2_overflow_used:
; RV32: # %bb.0:
; RV32-NEXT: add a1, a3, a1
; RV32-NEXT: add a0, a2, a0
; RV32-NEXT: sltu a0, a0, a2
; RV32-NEXT: add a1, a1, a0
; RV32-NEXT: beq a1, a3, .LBB2_2
; RV32-NEXT: # %bb.1:
; RV32-NEXT: sltu a0, a1, a3
; RV32-NEXT: .LBB2_2:
; RV32-NEXT: bnez a0, .LBB2_4
; RV32-NEXT: # %bb.3:
; RV32-NEXT: li a2, 42
; RV32-NEXT: .LBB2_4:
; RV32-NEXT: neg a1, a0
; RV32-NEXT: and a1, a1, a3
; RV32-NEXT: mv a0, a2
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo2_overflow_used:
; RV64: # %bb.0:
; RV64-NEXT: add a0, a1, a0
; RV64-NEXT: bltu a0, a1, .LBB2_2
; RV64-NEXT: # %bb.1:
; RV64-NEXT: li a1, 42
; RV64-NEXT: .LBB2_2:
; RV64-NEXT: mv a0, a1
; RV64-NEXT: ret
%add = add i64 %b, %a
%cmp = icmp ult i64 %add, %b
%Q = select i1 %cmp, i64 %b, i64 42
ret i64 %Q
}
define i64 @uaddo2_math_overflow_used(i64 %a, i64 %b, ptr %res) nounwind ssp {
; RV32-LABEL: uaddo2_math_overflow_used:
; RV32: # %bb.0:
; RV32-NEXT: add a5, a3, a1
; RV32-NEXT: add a0, a2, a0
; RV32-NEXT: sltu a1, a0, a2
; RV32-NEXT: add a5, a5, a1
; RV32-NEXT: beq a5, a3, .LBB3_2
; RV32-NEXT: # %bb.1:
; RV32-NEXT: sltu a1, a5, a3
; RV32-NEXT: .LBB3_2:
; RV32-NEXT: bnez a1, .LBB3_4
; RV32-NEXT: # %bb.3:
; RV32-NEXT: li a2, 42
; RV32-NEXT: .LBB3_4:
; RV32-NEXT: neg a1, a1
; RV32-NEXT: and a1, a1, a3
; RV32-NEXT: sw a0, 0(a4)
; RV32-NEXT: sw a5, 4(a4)
; RV32-NEXT: mv a0, a2
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo2_math_overflow_used:
; RV64: # %bb.0:
; RV64-NEXT: add a0, a1, a0
; RV64-NEXT: bltu a0, a1, .LBB3_2
; RV64-NEXT: # %bb.1:
; RV64-NEXT: li a1, 42
; RV64-NEXT: .LBB3_2:
; RV64-NEXT: sd a0, 0(a2)
; RV64-NEXT: mv a0, a1
; RV64-NEXT: ret
%add = add i64 %b, %a
%cmp = icmp ult i64 %add, %b
%Q = select i1 %cmp, i64 %b, i64 42
store i64 %add, ptr %res
ret i64 %Q
}
define i64 @uaddo3_overflow_used(i64 %a, i64 %b) nounwind ssp {
; RV32-LABEL: uaddo3_overflow_used:
; RV32: # %bb.0:
; RV32-NEXT: add a1, a3, a1
; RV32-NEXT: add a0, a2, a0
; RV32-NEXT: sltu a0, a0, a2
; RV32-NEXT: add a1, a1, a0
; RV32-NEXT: beq a3, a1, .LBB4_2
; RV32-NEXT: # %bb.1:
; RV32-NEXT: sltu a0, a1, a3
; RV32-NEXT: .LBB4_2:
; RV32-NEXT: bnez a0, .LBB4_4
; RV32-NEXT: # %bb.3:
; RV32-NEXT: li a2, 42
; RV32-NEXT: .LBB4_4:
; RV32-NEXT: neg a1, a0
; RV32-NEXT: and a1, a1, a3
; RV32-NEXT: mv a0, a2
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo3_overflow_used:
; RV64: # %bb.0:
; RV64-NEXT: add a0, a1, a0
; RV64-NEXT: bltu a0, a1, .LBB4_2
; RV64-NEXT: # %bb.1:
; RV64-NEXT: li a1, 42
; RV64-NEXT: .LBB4_2:
; RV64-NEXT: mv a0, a1
; RV64-NEXT: ret
%add = add i64 %b, %a
%cmp = icmp ugt i64 %b, %add
%Q = select i1 %cmp, i64 %b, i64 42
ret i64 %Q
}
define i64 @uaddo3_math_overflow_used(i64 %a, i64 %b, ptr %res) nounwind ssp {
; RV32-LABEL: uaddo3_math_overflow_used:
; RV32: # %bb.0:
; RV32-NEXT: add a5, a3, a1
; RV32-NEXT: add a0, a2, a0
; RV32-NEXT: sltu a1, a0, a2
; RV32-NEXT: add a5, a5, a1
; RV32-NEXT: beq a5, a3, .LBB5_2
; RV32-NEXT: # %bb.1:
; RV32-NEXT: sltu a1, a5, a3
; RV32-NEXT: .LBB5_2:
; RV32-NEXT: bnez a1, .LBB5_4
; RV32-NEXT: # %bb.3:
; RV32-NEXT: li a2, 42
; RV32-NEXT: .LBB5_4:
; RV32-NEXT: neg a1, a1
; RV32-NEXT: and a1, a1, a3
; RV32-NEXT: sw a0, 0(a4)
; RV32-NEXT: sw a5, 4(a4)
; RV32-NEXT: mv a0, a2
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo3_math_overflow_used:
; RV64: # %bb.0:
; RV64-NEXT: add a0, a1, a0
; RV64-NEXT: bltu a0, a1, .LBB5_2
; RV64-NEXT: # %bb.1:
; RV64-NEXT: li a1, 42
; RV64-NEXT: .LBB5_2:
; RV64-NEXT: sd a0, 0(a2)
; RV64-NEXT: mv a0, a1
; RV64-NEXT: ret
%add = add i64 %b, %a
%cmp = icmp ugt i64 %b, %add
%Q = select i1 %cmp, i64 %b, i64 42
store i64 %add, ptr %res
ret i64 %Q
}
; TODO? CGP sinks the compare before we have a chance to form the overflow intrinsic.
define i64 @uaddo4(i64 %a, i64 %b, i1 %c) nounwind ssp {
; RV32-LABEL: uaddo4:
; RV32: # %bb.0: # %entry
; RV32-NEXT: andi a4, a4, 1
; RV32-NEXT: beqz a4, .LBB6_6
; RV32-NEXT: # %bb.1: # %next
; RV32-NEXT: add a1, a3, a1
; RV32-NEXT: add a0, a2, a0
; RV32-NEXT: sltu a0, a0, a2
; RV32-NEXT: add a1, a1, a0
; RV32-NEXT: beq a3, a1, .LBB6_3
; RV32-NEXT: # %bb.2: # %next
; RV32-NEXT: sltu a0, a1, a3
; RV32-NEXT: .LBB6_3: # %next
; RV32-NEXT: bnez a0, .LBB6_5
; RV32-NEXT: # %bb.4: # %next
; RV32-NEXT: li a2, 42
; RV32-NEXT: .LBB6_5: # %next
; RV32-NEXT: neg a1, a0
; RV32-NEXT: and a1, a1, a3
; RV32-NEXT: mv a0, a2
; RV32-NEXT: ret
; RV32-NEXT: .LBB6_6: # %exit
; RV32-NEXT: li a0, 0
; RV32-NEXT: li a1, 0
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo4:
; RV64: # %bb.0: # %entry
; RV64-NEXT: andi a2, a2, 1
; RV64-NEXT: beqz a2, .LBB6_4
; RV64-NEXT: # %bb.1: # %next
; RV64-NEXT: add a0, a1, a0
; RV64-NEXT: bltu a0, a1, .LBB6_3
; RV64-NEXT: # %bb.2: # %next
; RV64-NEXT: li a1, 42
; RV64-NEXT: .LBB6_3: # %next
; RV64-NEXT: mv a0, a1
; RV64-NEXT: ret
; RV64-NEXT: .LBB6_4: # %exit
; RV64-NEXT: li a0, 0
; RV64-NEXT: ret
entry:
%add = add i64 %b, %a
%cmp = icmp ugt i64 %b, %add
br i1 %c, label %next, label %exit
next:
%Q = select i1 %cmp, i64 %b, i64 42
ret i64 %Q
exit:
ret i64 0
}
define i64 @uaddo5(i64 %a, i64 %b, ptr %ptr, i1 %c) nounwind ssp {
; RV32-LABEL: uaddo5:
; RV32: # %bb.0: # %entry
; RV32-NEXT: andi a5, a5, 1
; RV32-NEXT: add a1, a3, a1
; RV32-NEXT: add a6, a2, a0
; RV32-NEXT: sltu a0, a6, a2
; RV32-NEXT: add a1, a1, a0
; RV32-NEXT: sw a6, 0(a4)
; RV32-NEXT: sw a1, 4(a4)
; RV32-NEXT: beqz a5, .LBB7_6
; RV32-NEXT: # %bb.1: # %next
; RV32-NEXT: beq a3, a1, .LBB7_3
; RV32-NEXT: # %bb.2: # %next
; RV32-NEXT: sltu a0, a1, a3
; RV32-NEXT: .LBB7_3: # %next
; RV32-NEXT: bnez a0, .LBB7_5
; RV32-NEXT: # %bb.4: # %next
; RV32-NEXT: li a2, 42
; RV32-NEXT: .LBB7_5: # %next
; RV32-NEXT: neg a1, a0
; RV32-NEXT: and a1, a1, a3
; RV32-NEXT: mv a0, a2
; RV32-NEXT: ret
; RV32-NEXT: .LBB7_6: # %exit
; RV32-NEXT: li a0, 0
; RV32-NEXT: li a1, 0
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo5:
; RV64: # %bb.0: # %entry
; RV64-NEXT: andi a3, a3, 1
; RV64-NEXT: add a0, a1, a0
; RV64-NEXT: sd a0, 0(a2)
; RV64-NEXT: beqz a3, .LBB7_4
; RV64-NEXT: # %bb.1: # %next
; RV64-NEXT: bltu a0, a1, .LBB7_3
; RV64-NEXT: # %bb.2: # %next
; RV64-NEXT: li a1, 42
; RV64-NEXT: .LBB7_3: # %next
; RV64-NEXT: mv a0, a1
; RV64-NEXT: ret
; RV64-NEXT: .LBB7_4: # %exit
; RV64-NEXT: li a0, 0
; RV64-NEXT: ret
entry:
%add = add i64 %b, %a
store i64 %add, ptr %ptr
%cmp = icmp ugt i64 %b, %add
br i1 %c, label %next, label %exit
next:
%Q = select i1 %cmp, i64 %b, i64 42
ret i64 %Q
exit:
ret i64 0
}
; Instcombine folds (a + b <u a) to (a ^ -1 <u b). Make sure we match this
; pattern as well.
define i64 @uaddo6_xor(i64 %a, i64 %b) {
; RV32-LABEL: uaddo6_xor:
; RV32: # %bb.0:
; RV32-NEXT: not a1, a1
; RV32-NEXT: beq a1, a3, .LBB8_2
; RV32-NEXT: # %bb.1:
; RV32-NEXT: sltu a0, a1, a3
; RV32-NEXT: beqz a0, .LBB8_3
; RV32-NEXT: j .LBB8_4
; RV32-NEXT: .LBB8_2:
; RV32-NEXT: not a0, a0
; RV32-NEXT: sltu a0, a0, a2
; RV32-NEXT: bnez a0, .LBB8_4
; RV32-NEXT: .LBB8_3:
; RV32-NEXT: li a2, 42
; RV32-NEXT: .LBB8_4:
; RV32-NEXT: neg a1, a0
; RV32-NEXT: and a1, a1, a3
; RV32-NEXT: mv a0, a2
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo6_xor:
; RV64: # %bb.0:
; RV64-NEXT: not a2, a0
; RV64-NEXT: mv a0, a1
; RV64-NEXT: bltu a2, a1, .LBB8_2
; RV64-NEXT: # %bb.1:
; RV64-NEXT: li a0, 42
; RV64-NEXT: .LBB8_2:
; RV64-NEXT: ret
%x = xor i64 %a, -1
%cmp = icmp ult i64 %x, %b
%Q = select i1 %cmp, i64 %b, i64 42
ret i64 %Q
}
define i64 @uaddo6_xor_commuted(i64 %a, i64 %b) {
; RV32-LABEL: uaddo6_xor_commuted:
; RV32: # %bb.0:
; RV32-NEXT: not a1, a1
; RV32-NEXT: beq a1, a3, .LBB9_2
; RV32-NEXT: # %bb.1:
; RV32-NEXT: sltu a0, a1, a3
; RV32-NEXT: beqz a0, .LBB9_3
; RV32-NEXT: j .LBB9_4
; RV32-NEXT: .LBB9_2:
; RV32-NEXT: not a0, a0
; RV32-NEXT: sltu a0, a0, a2
; RV32-NEXT: bnez a0, .LBB9_4
; RV32-NEXT: .LBB9_3:
; RV32-NEXT: li a2, 42
; RV32-NEXT: .LBB9_4:
; RV32-NEXT: neg a1, a0
; RV32-NEXT: and a1, a1, a3
; RV32-NEXT: mv a0, a2
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo6_xor_commuted:
; RV64: # %bb.0:
; RV64-NEXT: not a2, a0
; RV64-NEXT: mv a0, a1
; RV64-NEXT: bltu a2, a1, .LBB9_2
; RV64-NEXT: # %bb.1:
; RV64-NEXT: li a0, 42
; RV64-NEXT: .LBB9_2:
; RV64-NEXT: ret
%x = xor i64 %a, -1
%cmp = icmp ult i64 %x, %b
%Q = select i1 %cmp, i64 %b, i64 42
ret i64 %Q
}
declare void @use(i64)
define i64 @uaddo6_xor_multi_use(i64 %a, i64 %b) {
; RV32-LABEL: uaddo6_xor_multi_use:
; RV32: # %bb.0:
; RV32-NEXT: addi sp, sp, -16
; RV32-NEXT: .cfi_def_cfa_offset 16
; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
; RV32-NEXT: sw s0, 8(sp) # 4-byte Folded Spill
; RV32-NEXT: sw s1, 4(sp) # 4-byte Folded Spill
; RV32-NEXT: .cfi_offset ra, -4
; RV32-NEXT: .cfi_offset s0, -8
; RV32-NEXT: .cfi_offset s1, -12
; RV32-NEXT: mv s0, a2
; RV32-NEXT: not a1, a1
; RV32-NEXT: not a0, a0
; RV32-NEXT: beq a1, a3, .LBB10_2
; RV32-NEXT: # %bb.1:
; RV32-NEXT: sltu a2, a1, a3
; RV32-NEXT: beqz a2, .LBB10_3
; RV32-NEXT: j .LBB10_4
; RV32-NEXT: .LBB10_2:
; RV32-NEXT: sltu a2, a0, s0
; RV32-NEXT: bnez a2, .LBB10_4
; RV32-NEXT: .LBB10_3:
; RV32-NEXT: li s0, 42
; RV32-NEXT: .LBB10_4:
; RV32-NEXT: neg s1, a2
; RV32-NEXT: and s1, s1, a3
; RV32-NEXT: call use
; RV32-NEXT: mv a0, s0
; RV32-NEXT: mv a1, s1
; RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
; RV32-NEXT: lw s0, 8(sp) # 4-byte Folded Reload
; RV32-NEXT: lw s1, 4(sp) # 4-byte Folded Reload
; RV32-NEXT: addi sp, sp, 16
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo6_xor_multi_use:
; RV64: # %bb.0:
; RV64-NEXT: addi sp, sp, -16
; RV64-NEXT: .cfi_def_cfa_offset 16
; RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
; RV64-NEXT: sd s0, 0(sp) # 8-byte Folded Spill
; RV64-NEXT: .cfi_offset ra, -8
; RV64-NEXT: .cfi_offset s0, -16
; RV64-NEXT: not a0, a0
; RV64-NEXT: mv s0, a1
; RV64-NEXT: bltu a0, a1, .LBB10_2
; RV64-NEXT: # %bb.1:
; RV64-NEXT: li s0, 42
; RV64-NEXT: .LBB10_2:
; RV64-NEXT: call use
; RV64-NEXT: mv a0, s0
; RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
; RV64-NEXT: ld s0, 0(sp) # 8-byte Folded Reload
; RV64-NEXT: addi sp, sp, 16
; RV64-NEXT: ret
%x = xor i64 -1, %a
%cmp = icmp ult i64 %x, %b
%Q = select i1 %cmp, i64 %b, i64 42
call void @use(i64 %x)
ret i64 %Q
}
; Make sure we do not use the XOR binary operator as insert point, as it may
; come before the second operand of the overflow intrinsic.
define i1 @uaddo6_xor_op_after_XOR(i32 %a, ptr %b.ptr) {
; RV32-LABEL: uaddo6_xor_op_after_XOR:
; RV32: # %bb.0:
; RV32-NEXT: lw a1, 0(a1)
; RV32-NEXT: not a0, a0
; RV32-NEXT: sltu a0, a0, a1
; RV32-NEXT: xori a0, a0, 1
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo6_xor_op_after_XOR:
; RV64: # %bb.0:
; RV64-NEXT: lw a1, 0(a1)
; RV64-NEXT: not a0, a0
; RV64-NEXT: sext.w a0, a0
; RV64-NEXT: sltu a0, a0, a1
; RV64-NEXT: xori a0, a0, 1
; RV64-NEXT: ret
%x = xor i32 %a, -1
%b = load i32, ptr %b.ptr, align 8
%cmp14 = icmp ugt i32 %b, %x
%ov = xor i1 %cmp14, true
ret i1 %ov
}
; When adding 1, the general pattern for add-overflow may be different due to icmp canonicalization.
; PR31754: https://bugs.llvm.org/show_bug.cgi?id=31754
define i1 @uaddo_i64_increment(i64 %x, ptr %p) {
; RV32-LABEL: uaddo_i64_increment:
; RV32: # %bb.0:
; RV32-NEXT: addi a3, a0, 1
; RV32-NEXT: seqz a0, a3
; RV32-NEXT: add a1, a1, a0
; RV32-NEXT: or a0, a3, a1
; RV32-NEXT: seqz a0, a0
; RV32-NEXT: sw a3, 0(a2)
; RV32-NEXT: sw a1, 4(a2)
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo_i64_increment:
; RV64: # %bb.0:
; RV64-NEXT: addi a2, a0, 1
; RV64-NEXT: seqz a0, a2
; RV64-NEXT: sd a2, 0(a1)
; RV64-NEXT: ret
%a = add i64 %x, 1
%ov = icmp eq i64 %a, 0
store i64 %a, ptr %p
ret i1 %ov
}
define i1 @uaddo_i8_increment_noncanonical_1(i8 %x, ptr %p) {
; RV32-LABEL: uaddo_i8_increment_noncanonical_1:
; RV32: # %bb.0:
; RV32-NEXT: addi a2, a0, 1
; RV32-NEXT: andi a0, a2, 255
; RV32-NEXT: seqz a0, a0
; RV32-NEXT: sb a2, 0(a1)
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo_i8_increment_noncanonical_1:
; RV64: # %bb.0:
; RV64-NEXT: addi a2, a0, 1
; RV64-NEXT: andi a0, a2, 255
; RV64-NEXT: seqz a0, a0
; RV64-NEXT: sb a2, 0(a1)
; RV64-NEXT: ret
%a = add i8 1, %x ; commute
%ov = icmp eq i8 %a, 0
store i8 %a, ptr %p
ret i1 %ov
}
define i1 @uaddo_i32_increment_noncanonical_2(i32 %x, ptr %p) {
; RV32-LABEL: uaddo_i32_increment_noncanonical_2:
; RV32: # %bb.0:
; RV32-NEXT: addi a2, a0, 1
; RV32-NEXT: seqz a0, a2
; RV32-NEXT: sw a2, 0(a1)
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo_i32_increment_noncanonical_2:
; RV64: # %bb.0:
; RV64-NEXT: addiw a2, a0, 1
; RV64-NEXT: seqz a0, a2
; RV64-NEXT: sw a2, 0(a1)
; RV64-NEXT: ret
%a = add i32 %x, 1
%ov = icmp eq i32 0, %a ; commute
store i32 %a, ptr %p
ret i1 %ov
}
define i1 @uaddo_i16_increment_noncanonical_3(i16 %x, ptr %p) {
; RV32-LABEL: uaddo_i16_increment_noncanonical_3:
; RV32: # %bb.0:
; RV32-NEXT: addi a2, a0, 1
; RV32-NEXT: slli a0, a2, 16
; RV32-NEXT: srli a0, a0, 16
; RV32-NEXT: seqz a0, a0
; RV32-NEXT: sh a2, 0(a1)
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo_i16_increment_noncanonical_3:
; RV64: # %bb.0:
; RV64-NEXT: addi a2, a0, 1
; RV64-NEXT: slli a0, a2, 48
; RV64-NEXT: srli a0, a0, 48
; RV64-NEXT: seqz a0, a0
; RV64-NEXT: sh a2, 0(a1)
; RV64-NEXT: ret
%a = add i16 1, %x ; commute
%ov = icmp eq i16 0, %a ; commute
store i16 %a, ptr %p
ret i1 %ov
}
; The overflow check may be against the input rather than the sum.
define i1 @uaddo_i64_increment_alt(i64 %x, ptr %p) {
; RV32-LABEL: uaddo_i64_increment_alt:
; RV32: # %bb.0:
; RV32-NEXT: addi a3, a0, 1
; RV32-NEXT: seqz a0, a3
; RV32-NEXT: add a1, a1, a0
; RV32-NEXT: or a0, a3, a1
; RV32-NEXT: seqz a0, a0
; RV32-NEXT: sw a3, 0(a2)
; RV32-NEXT: sw a1, 4(a2)
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo_i64_increment_alt:
; RV64: # %bb.0:
; RV64-NEXT: addi a2, a0, 1
; RV64-NEXT: seqz a0, a2
; RV64-NEXT: sd a2, 0(a1)
; RV64-NEXT: ret
%a = add i64 %x, 1
store i64 %a, ptr %p
%ov = icmp eq i64 %x, -1
ret i1 %ov
}
; Make sure insertion is done correctly based on dominance.
define i1 @uaddo_i64_increment_alt_dom(i64 %x, ptr %p) {
; RV32-LABEL: uaddo_i64_increment_alt_dom:
; RV32: # %bb.0:
; RV32-NEXT: addi a3, a0, 1
; RV32-NEXT: seqz a0, a3
; RV32-NEXT: add a1, a1, a0
; RV32-NEXT: or a0, a3, a1
; RV32-NEXT: seqz a0, a0
; RV32-NEXT: sw a3, 0(a2)
; RV32-NEXT: sw a1, 4(a2)
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo_i64_increment_alt_dom:
; RV64: # %bb.0:
; RV64-NEXT: addi a2, a0, 1
; RV64-NEXT: seqz a0, a2
; RV64-NEXT: sd a2, 0(a1)
; RV64-NEXT: ret
%ov = icmp eq i64 %x, -1
%a = add i64 %x, 1
store i64 %a, ptr %p
ret i1 %ov
}
; The overflow check may be against the input rather than the sum.
define i1 @uaddo_i32_decrement_alt(i32 signext %x, ptr %p) {
; RV32-LABEL: uaddo_i32_decrement_alt:
; RV32: # %bb.0:
; RV32-NEXT: snez a2, a0
; RV32-NEXT: addi a0, a0, -1
; RV32-NEXT: sw a0, 0(a1)
; RV32-NEXT: mv a0, a2
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo_i32_decrement_alt:
; RV64: # %bb.0:
; RV64-NEXT: snez a2, a0
; RV64-NEXT: addi a0, a0, -1
; RV64-NEXT: sw a0, 0(a1)
; RV64-NEXT: mv a0, a2
; RV64-NEXT: ret
%a = add i32 %x, -1
store i32 %a, ptr %p
%ov = icmp ne i32 %x, 0
ret i1 %ov
}
define i1 @uaddo_i64_decrement_alt(i64 %x, ptr %p) {
; RV32-LABEL: uaddo_i64_decrement_alt:
; RV32: # %bb.0:
; RV32-NEXT: or a3, a0, a1
; RV32-NEXT: snez a3, a3
; RV32-NEXT: seqz a4, a0
; RV32-NEXT: sub a1, a1, a4
; RV32-NEXT: addi a0, a0, -1
; RV32-NEXT: sw a0, 0(a2)
; RV32-NEXT: sw a1, 4(a2)
; RV32-NEXT: mv a0, a3
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo_i64_decrement_alt:
; RV64: # %bb.0:
; RV64-NEXT: snez a2, a0
; RV64-NEXT: addi a0, a0, -1
; RV64-NEXT: sd a0, 0(a1)
; RV64-NEXT: mv a0, a2
; RV64-NEXT: ret
%a = add i64 %x, -1
store i64 %a, ptr %p
%ov = icmp ne i64 %x, 0
ret i1 %ov
}
; Make sure insertion is done correctly based on dominance.
define i1 @uaddo_i64_decrement_alt_dom(i64 %x, ptr %p) {
; RV32-LABEL: uaddo_i64_decrement_alt_dom:
; RV32: # %bb.0:
; RV32-NEXT: or a3, a0, a1
; RV32-NEXT: snez a3, a3
; RV32-NEXT: seqz a4, a0
; RV32-NEXT: sub a1, a1, a4
; RV32-NEXT: addi a0, a0, -1
; RV32-NEXT: sw a0, 0(a2)
; RV32-NEXT: sw a1, 4(a2)
; RV32-NEXT: mv a0, a3
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo_i64_decrement_alt_dom:
; RV64: # %bb.0:
; RV64-NEXT: snez a2, a0
; RV64-NEXT: addi a0, a0, -1
; RV64-NEXT: sd a0, 0(a1)
; RV64-NEXT: mv a0, a2
; RV64-NEXT: ret
%ov = icmp ne i64 %x, 0
%a = add i64 %x, -1
store i64 %a, ptr %p
ret i1 %ov
}
; No transform for illegal types.
define i1 @uaddo_i42_increment_illegal_type(i42 %x, ptr %p) {
; RV32-LABEL: uaddo_i42_increment_illegal_type:
; RV32: # %bb.0:
; RV32-NEXT: addi a3, a0, 1
; RV32-NEXT: seqz a0, a3
; RV32-NEXT: add a0, a1, a0
; RV32-NEXT: andi a1, a0, 1023
; RV32-NEXT: or a0, a3, a1
; RV32-NEXT: seqz a0, a0
; RV32-NEXT: sw a3, 0(a2)
; RV32-NEXT: sh a1, 4(a2)
; RV32-NEXT: ret
;
; RV64-LABEL: uaddo_i42_increment_illegal_type:
; RV64: # %bb.0:
; RV64-NEXT: addi a2, a0, 1
; RV64-NEXT: slli a0, a2, 22
; RV64-NEXT: srli a3, a0, 22
; RV64-NEXT: seqz a0, a3
; RV64-NEXT: sw a2, 0(a1)
; RV64-NEXT: srli a3, a3, 32
; RV64-NEXT: sh a3, 4(a1)
; RV64-NEXT: ret
%a = add i42 %x, 1
%ov = icmp eq i42 %a, 0
store i42 %a, ptr %p
ret i1 %ov
}
define i1 @usubo_ult_i64_overflow_used(i64 %x, i64 %y, ptr %p) {
; RV32-LABEL: usubo_ult_i64_overflow_used:
; RV32: # %bb.0:
; RV32-NEXT: beq a1, a3, .LBB22_2
; RV32-NEXT: # %bb.1:
; RV32-NEXT: sltu a0, a1, a3
; RV32-NEXT: ret
; RV32-NEXT: .LBB22_2:
; RV32-NEXT: sltu a0, a0, a2
; RV32-NEXT: ret
;
; RV64-LABEL: usubo_ult_i64_overflow_used:
; RV64: # %bb.0:
; RV64-NEXT: sltu a0, a0, a1
; RV64-NEXT: ret
%s = sub i64 %x, %y
%ov = icmp ult i64 %x, %y
ret i1 %ov
}
define i1 @usubo_ult_i64_math_overflow_used(i64 %x, i64 %y, ptr %p) {
; RV32-LABEL: usubo_ult_i64_math_overflow_used:
; RV32: # %bb.0:
; RV32-NEXT: mv a5, a0
; RV32-NEXT: sltu a0, a0, a2
; RV32-NEXT: sub a6, a1, a3
; RV32-NEXT: sub a6, a6, a0
; RV32-NEXT: sub a5, a5, a2
; RV32-NEXT: sw a5, 0(a4)
; RV32-NEXT: sw a6, 4(a4)
; RV32-NEXT: beq a1, a3, .LBB23_2
; RV32-NEXT: # %bb.1:
; RV32-NEXT: sltu a0, a1, a3
; RV32-NEXT: .LBB23_2:
; RV32-NEXT: ret
;
; RV64-LABEL: usubo_ult_i64_math_overflow_used:
; RV64: # %bb.0:
; RV64-NEXT: sub a3, a0, a1
; RV64-NEXT: sltu a0, a0, a1
; RV64-NEXT: sd a3, 0(a2)
; RV64-NEXT: ret
%s = sub i64 %x, %y
store i64 %s, ptr %p
%ov = icmp ult i64 %x, %y
ret i1 %ov
}
; Verify insertion point for single-BB. Toggle predicate.
define i1 @usubo_ugt_i32(i32 %x, i32 %y, ptr %p) {
; RV32-LABEL: usubo_ugt_i32:
; RV32: # %bb.0:
; RV32-NEXT: sltu a3, a0, a1
; RV32-NEXT: sub a0, a0, a1
; RV32-NEXT: sw a0, 0(a2)
; RV32-NEXT: mv a0, a3
; RV32-NEXT: ret
;
; RV64-LABEL: usubo_ugt_i32:
; RV64: # %bb.0:
; RV64-NEXT: sext.w a3, a1
; RV64-NEXT: sext.w a4, a0
; RV64-NEXT: sltu a3, a4, a3
; RV64-NEXT: subw a0, a0, a1
; RV64-NEXT: sw a0, 0(a2)
; RV64-NEXT: mv a0, a3
; RV64-NEXT: ret
%ov = icmp ugt i32 %y, %x
%s = sub i32 %x, %y
store i32 %s, ptr %p
ret i1 %ov
}
; Constant operand should match.
define i1 @usubo_ugt_constant_op0_i8(i8 %x, ptr %p) {
; RV32-LABEL: usubo_ugt_constant_op0_i8:
; RV32: # %bb.0:
; RV32-NEXT: andi a2, a0, 255
; RV32-NEXT: li a3, 42
; RV32-NEXT: sub a3, a3, a0
; RV32-NEXT: sltiu a0, a2, 43
; RV32-NEXT: xori a0, a0, 1
; RV32-NEXT: sb a3, 0(a1)
; RV32-NEXT: ret
;
; RV64-LABEL: usubo_ugt_constant_op0_i8:
; RV64: # %bb.0:
; RV64-NEXT: andi a2, a0, 255
; RV64-NEXT: li a3, 42
; RV64-NEXT: subw a3, a3, a0
; RV64-NEXT: sltiu a0, a2, 43
; RV64-NEXT: xori a0, a0, 1
; RV64-NEXT: sb a3, 0(a1)
; RV64-NEXT: ret
%s = sub i8 42, %x
%ov = icmp ugt i8 %x, 42
store i8 %s, ptr %p
ret i1 %ov
}
; Compare with constant operand 0 is canonicalized by commuting, but verify match for non-canonical form.
define i1 @usubo_ult_constant_op0_i16(i16 %x, ptr %p) {
; RV32-LABEL: usubo_ult_constant_op0_i16:
; RV32: # %bb.0:
; RV32-NEXT: slli a2, a0, 16
; RV32-NEXT: srli a2, a2, 16
; RV32-NEXT: li a3, 43
; RV32-NEXT: sub a3, a3, a0
; RV32-NEXT: sltiu a0, a2, 44
; RV32-NEXT: xori a0, a0, 1
; RV32-NEXT: sh a3, 0(a1)
; RV32-NEXT: ret
;
; RV64-LABEL: usubo_ult_constant_op0_i16:
; RV64: # %bb.0:
; RV64-NEXT: slli a2, a0, 48
; RV64-NEXT: srli a2, a2, 48
; RV64-NEXT: li a3, 43
; RV64-NEXT: subw a3, a3, a0
; RV64-NEXT: sltiu a0, a2, 44
; RV64-NEXT: xori a0, a0, 1
; RV64-NEXT: sh a3, 0(a1)
; RV64-NEXT: ret
%s = sub i16 43, %x
%ov = icmp ult i16 43, %x
store i16 %s, ptr %p
ret i1 %ov
}
; Subtract with constant operand 1 is canonicalized to add.
define i1 @usubo_ult_constant_op1_i16(i16 %x, ptr %p) {
; RV32-LABEL: usubo_ult_constant_op1_i16:
; RV32: # %bb.0:
; RV32-NEXT: slli a2, a0, 16
; RV32-NEXT: srli a2, a2, 16
; RV32-NEXT: addi a3, a0, -44
; RV32-NEXT: sltiu a0, a2, 44
; RV32-NEXT: sh a3, 0(a1)
; RV32-NEXT: ret
;
; RV64-LABEL: usubo_ult_constant_op1_i16:
; RV64: # %bb.0:
; RV64-NEXT: slli a2, a0, 48
; RV64-NEXT: srli a2, a2, 48
; RV64-NEXT: addi a3, a0, -44
; RV64-NEXT: sltiu a0, a2, 44
; RV64-NEXT: sh a3, 0(a1)
; RV64-NEXT: ret
%s = add i16 %x, -44
%ov = icmp ult i16 %x, 44
store i16 %s, ptr %p
ret i1 %ov
}
define i1 @usubo_ugt_constant_op1_i8(i8 %x, ptr %p) {
; RV32-LABEL: usubo_ugt_constant_op1_i8:
; RV32: # %bb.0:
; RV32-NEXT: andi a2, a0, 255
; RV32-NEXT: sltiu a2, a2, 45
; RV32-NEXT: addi a0, a0, -45
; RV32-NEXT: sb a0, 0(a1)
; RV32-NEXT: mv a0, a2
; RV32-NEXT: ret
;
; RV64-LABEL: usubo_ugt_constant_op1_i8:
; RV64: # %bb.0:
; RV64-NEXT: andi a2, a0, 255
; RV64-NEXT: sltiu a2, a2, 45
; RV64-NEXT: addi a0, a0, -45
; RV64-NEXT: sb a0, 0(a1)
; RV64-NEXT: mv a0, a2
; RV64-NEXT: ret
%ov = icmp ugt i8 45, %x
%s = add i8 %x, -45
store i8 %s, ptr %p
ret i1 %ov
}
; Special-case: subtract 1 changes the compare predicate and constant.
define i1 @usubo_eq_constant1_op1_i32(i32 %x, ptr %p) {
; RV32-LABEL: usubo_eq_constant1_op1_i32:
; RV32: # %bb.0:
; RV32-NEXT: addi a2, a0, -1
; RV32-NEXT: seqz a0, a0
; RV32-NEXT: sw a2, 0(a1)
; RV32-NEXT: ret
;
; RV64-LABEL: usubo_eq_constant1_op1_i32:
; RV64: # %bb.0:
; RV64-NEXT: sext.w a2, a0
; RV64-NEXT: addi a3, a0, -1
; RV64-NEXT: seqz a0, a2
; RV64-NEXT: sw a3, 0(a1)
; RV64-NEXT: ret
%s = add i32 %x, -1
%ov = icmp eq i32 %x, 0
store i32 %s, ptr %p
ret i1 %ov
}
; Special-case: subtract from 0 (negate) changes the compare predicate.
define i1 @usubo_ne_constant0_op1_i32(i32 %x, ptr %p) {
; RV32-LABEL: usubo_ne_constant0_op1_i32:
; RV32: # %bb.0:
; RV32-NEXT: neg a2, a0
; RV32-NEXT: snez a0, a0
; RV32-NEXT: sw a2, 0(a1)
; RV32-NEXT: ret
;
; RV64-LABEL: usubo_ne_constant0_op1_i32:
; RV64: # %bb.0:
; RV64-NEXT: sext.w a2, a0
; RV64-NEXT: negw a3, a0
; RV64-NEXT: snez a0, a2
; RV64-NEXT: sw a3, 0(a1)
; RV64-NEXT: ret
%s = sub i32 0, %x
%ov = icmp ne i32 %x, 0
store i32 %s, ptr %p
ret i1 %ov
}
; This used to verify insertion point for multi-BB, but now we just bail out.
declare void @call(i1)
define i1 @usubo_ult_sub_dominates_i64(i64 %x, i64 %y, ptr %p, i1 %cond) {
; RV32-LABEL: usubo_ult_sub_dominates_i64:
; RV32: # %bb.0: # %entry
; RV32-NEXT: andi a6, a5, 1
; RV32-NEXT: beqz a6, .LBB31_5
; RV32-NEXT: # %bb.1: # %t
; RV32-NEXT: mv a7, a0
; RV32-NEXT: sltu a0, a0, a2
; RV32-NEXT: sub t0, a1, a3
; RV32-NEXT: sub t0, t0, a0
; RV32-NEXT: sub a2, a7, a2
; RV32-NEXT: sw a2, 0(a4)
; RV32-NEXT: sw t0, 4(a4)
; RV32-NEXT: beqz a6, .LBB31_5
; RV32-NEXT: # %bb.2: # %end
; RV32-NEXT: beq a1, a3, .LBB31_4
; RV32-NEXT: # %bb.3: # %end
; RV32-NEXT: sltu a0, a1, a3
; RV32-NEXT: .LBB31_4: # %end
; RV32-NEXT: ret
; RV32-NEXT: .LBB31_5: # %f
; RV32-NEXT: mv a0, a5
; RV32-NEXT: ret
;
; RV64-LABEL: usubo_ult_sub_dominates_i64:
; RV64: # %bb.0: # %entry
; RV64-NEXT: andi a4, a3, 1
; RV64-NEXT: beqz a4, .LBB31_3
; RV64-NEXT: # %bb.1: # %t
; RV64-NEXT: sub a5, a0, a1
; RV64-NEXT: sd a5, 0(a2)
; RV64-NEXT: beqz a4, .LBB31_3
; RV64-NEXT: # %bb.2: # %end
; RV64-NEXT: sltu a0, a0, a1
; RV64-NEXT: ret
; RV64-NEXT: .LBB31_3: # %f
; RV64-NEXT: mv a0, a3
; RV64-NEXT: ret
entry:
br i1 %cond, label %t, label %f
t:
%s = sub i64 %x, %y
store i64 %s, ptr %p
br i1 %cond, label %end, label %f
f:
ret i1 %cond
end:
%ov = icmp ult i64 %x, %y
ret i1 %ov
}
define i1 @usubo_ult_cmp_dominates_i64(i64 %x, i64 %y, ptr %p, i1 %cond) {
; RV32-LABEL: usubo_ult_cmp_dominates_i64:
; RV32: # %bb.0: # %entry
; RV32-NEXT: addi sp, sp, -32
; RV32-NEXT: .cfi_def_cfa_offset 32
; RV32-NEXT: sw ra, 28(sp) # 4-byte Folded Spill
; RV32-NEXT: sw s0, 24(sp) # 4-byte Folded Spill
; RV32-NEXT: sw s1, 20(sp) # 4-byte Folded Spill
; RV32-NEXT: sw s2, 16(sp) # 4-byte Folded Spill
; RV32-NEXT: sw s3, 12(sp) # 4-byte Folded Spill
; RV32-NEXT: sw s4, 8(sp) # 4-byte Folded Spill
; RV32-NEXT: sw s5, 4(sp) # 4-byte Folded Spill
; RV32-NEXT: sw s6, 0(sp) # 4-byte Folded Spill
; RV32-NEXT: .cfi_offset ra, -4
; RV32-NEXT: .cfi_offset s0, -8
; RV32-NEXT: .cfi_offset s1, -12
; RV32-NEXT: .cfi_offset s2, -16
; RV32-NEXT: .cfi_offset s3, -20
; RV32-NEXT: .cfi_offset s4, -24
; RV32-NEXT: .cfi_offset s5, -28
; RV32-NEXT: .cfi_offset s6, -32
; RV32-NEXT: mv s2, a5
; RV32-NEXT: andi a5, a5, 1
; RV32-NEXT: beqz a5, .LBB32_8
; RV32-NEXT: # %bb.1: # %t
; RV32-NEXT: mv s0, a4
; RV32-NEXT: mv s3, a3
; RV32-NEXT: mv s1, a2
; RV32-NEXT: mv s5, a1
; RV32-NEXT: mv s4, a0
; RV32-NEXT: beq a1, a3, .LBB32_3
; RV32-NEXT: # %bb.2: # %t
; RV32-NEXT: sltu s6, s5, s3
; RV32-NEXT: j .LBB32_4
; RV32-NEXT: .LBB32_3:
; RV32-NEXT: sltu s6, s4, s1
; RV32-NEXT: .LBB32_4: # %t
; RV32-NEXT: mv a0, s6
; RV32-NEXT: call call
; RV32-NEXT: beqz s6, .LBB32_8
; RV32-NEXT: # %bb.5: # %end
; RV32-NEXT: sltu a1, s4, s1
; RV32-NEXT: mv a0, a1
; RV32-NEXT: beq s5, s3, .LBB32_7
; RV32-NEXT: # %bb.6: # %end
; RV32-NEXT: sltu a0, s5, s3
; RV32-NEXT: .LBB32_7: # %end
; RV32-NEXT: sub a2, s5, s3
; RV32-NEXT: sub a2, a2, a1
; RV32-NEXT: sub a1, s4, s1
; RV32-NEXT: sw a1, 0(s0)
; RV32-NEXT: sw a2, 4(s0)
; RV32-NEXT: j .LBB32_9
; RV32-NEXT: .LBB32_8: # %f
; RV32-NEXT: mv a0, s2
; RV32-NEXT: .LBB32_9: # %f
; RV32-NEXT: lw ra, 28(sp) # 4-byte Folded Reload
; RV32-NEXT: lw s0, 24(sp) # 4-byte Folded Reload
; RV32-NEXT: lw s1, 20(sp) # 4-byte Folded Reload
; RV32-NEXT: lw s2, 16(sp) # 4-byte Folded Reload
; RV32-NEXT: lw s3, 12(sp) # 4-byte Folded Reload
; RV32-NEXT: lw s4, 8(sp) # 4-byte Folded Reload
; RV32-NEXT: lw s5, 4(sp) # 4-byte Folded Reload
; RV32-NEXT: lw s6, 0(sp) # 4-byte Folded Reload
; RV32-NEXT: addi sp, sp, 32
; RV32-NEXT: ret
;
; RV64-LABEL: usubo_ult_cmp_dominates_i64:
; RV64: # %bb.0: # %entry
; RV64-NEXT: addi sp, sp, -48
; RV64-NEXT: .cfi_def_cfa_offset 48
; RV64-NEXT: sd ra, 40(sp) # 8-byte Folded Spill
; RV64-NEXT: sd s0, 32(sp) # 8-byte Folded Spill
; RV64-NEXT: sd s1, 24(sp) # 8-byte Folded Spill
; RV64-NEXT: sd s2, 16(sp) # 8-byte Folded Spill
; RV64-NEXT: sd s3, 8(sp) # 8-byte Folded Spill
; RV64-NEXT: sd s4, 0(sp) # 8-byte Folded Spill
; RV64-NEXT: .cfi_offset ra, -8
; RV64-NEXT: .cfi_offset s0, -16
; RV64-NEXT: .cfi_offset s1, -24
; RV64-NEXT: .cfi_offset s2, -32
; RV64-NEXT: .cfi_offset s3, -40
; RV64-NEXT: .cfi_offset s4, -48
; RV64-NEXT: mv s0, a3
; RV64-NEXT: andi a3, a3, 1
; RV64-NEXT: beqz a3, .LBB32_3
; RV64-NEXT: # %bb.1: # %t
; RV64-NEXT: mv s1, a2
; RV64-NEXT: mv s2, a1
; RV64-NEXT: mv s3, a0
; RV64-NEXT: sltu s4, a0, a1
; RV64-NEXT: mv a0, s4
; RV64-NEXT: call call
; RV64-NEXT: bgeu s3, s2, .LBB32_3
; RV64-NEXT: # %bb.2: # %end
; RV64-NEXT: sub a0, s3, s2
; RV64-NEXT: sd a0, 0(s1)
; RV64-NEXT: mv a0, s4
; RV64-NEXT: j .LBB32_4
; RV64-NEXT: .LBB32_3: # %f
; RV64-NEXT: mv a0, s0
; RV64-NEXT: .LBB32_4: # %f
; RV64-NEXT: ld ra, 40(sp) # 8-byte Folded Reload
; RV64-NEXT: ld s0, 32(sp) # 8-byte Folded Reload
; RV64-NEXT: ld s1, 24(sp) # 8-byte Folded Reload
; RV64-NEXT: ld s2, 16(sp) # 8-byte Folded Reload
; RV64-NEXT: ld s3, 8(sp) # 8-byte Folded Reload
; RV64-NEXT: ld s4, 0(sp) # 8-byte Folded Reload
; RV64-NEXT: addi sp, sp, 48
; RV64-NEXT: ret
entry:
br i1 %cond, label %t, label %f
t:
%ov = icmp ult i64 %x, %y
call void @call(i1 %ov)
br i1 %ov, label %end, label %f
f:
ret i1 %cond
end:
%s = sub i64 %x, %y
store i64 %s, ptr %p
ret i1 %ov
}
; Verify that crazy/non-canonical code does not crash.
define void @bar() {
; RV32-LABEL: bar:
; RV32: # %bb.0:
;
; RV64-LABEL: bar:
; RV64: # %bb.0:
%cmp = icmp eq i64 1, -1
%frombool = zext i1 %cmp to i8
unreachable
}
define void @foo() {
; RV32-LABEL: foo:
; RV32: # %bb.0:
;
; RV64-LABEL: foo:
; RV64: # %bb.0:
%sub = add nsw i64 1, 1
%conv = trunc i64 %sub to i32
unreachable
}
; Similarly for usubo.
define i1 @bar2() {
; RV32-LABEL: bar2:
; RV32: # %bb.0:
; RV32-NEXT: li a0, 0
; RV32-NEXT: ret
;
; RV64-LABEL: bar2:
; RV64: # %bb.0:
; RV64-NEXT: li a0, 0
; RV64-NEXT: ret
%cmp = icmp eq i64 1, 0
ret i1 %cmp
}
define i64 @foo2(ptr %p) {
; RV32-LABEL: foo2:
; RV32: # %bb.0:
; RV32-NEXT: li a0, 0
; RV32-NEXT: li a1, 0
; RV32-NEXT: ret
;
; RV64-LABEL: foo2:
; RV64: # %bb.0:
; RV64-NEXT: li a0, 0
; RV64-NEXT: ret
%sub = add nsw i64 1, -1
ret i64 %sub
}
; Avoid hoisting a math op into a dominating block which would
; increase the critical path.
define void @PR41129(ptr %p64) {
; RV32-LABEL: PR41129:
; RV32: # %bb.0: # %entry
; RV32-NEXT: lw a2, 4(a0)
; RV32-NEXT: lw a1, 0(a0)
; RV32-NEXT: or a3, a1, a2
; RV32-NEXT: beqz a3, .LBB37_2
; RV32-NEXT: # %bb.1: # %false
; RV32-NEXT: andi a1, a1, 7
; RV32-NEXT: sw zero, 4(a0)
; RV32-NEXT: sw a1, 0(a0)
; RV32-NEXT: ret
; RV32-NEXT: .LBB37_2: # %true
; RV32-NEXT: seqz a3, a1
; RV32-NEXT: sub a2, a2, a3
; RV32-NEXT: addi a1, a1, -1
; RV32-NEXT: sw a1, 0(a0)
; RV32-NEXT: sw a2, 4(a0)
; RV32-NEXT: ret
;
; RV64-LABEL: PR41129:
; RV64: # %bb.0: # %entry
; RV64-NEXT: ld a1, 0(a0)
; RV64-NEXT: beqz a1, .LBB37_2
; RV64-NEXT: # %bb.1: # %false
; RV64-NEXT: andi a1, a1, 7
; RV64-NEXT: sd a1, 0(a0)
; RV64-NEXT: ret
; RV64-NEXT: .LBB37_2: # %true
; RV64-NEXT: addi a1, a1, -1
; RV64-NEXT: sd a1, 0(a0)
; RV64-NEXT: ret
entry:
%key = load i64, ptr %p64, align 8
%cond17 = icmp eq i64 %key, 0
br i1 %cond17, label %true, label %false
false:
%andval = and i64 %key, 7
store i64 %andval, ptr %p64
br label %exit
true:
%svalue = add i64 %key, -1
store i64 %svalue, ptr %p64
br label %exit
exit:
ret void
}
define i16 @overflow_not_used(i16 %a, i16 %b, ptr %res) {
; RV32-LABEL: overflow_not_used:
; RV32: # %bb.0:
; RV32-NEXT: lui a3, 16
; RV32-NEXT: addi a3, a3, -1
; RV32-NEXT: and a4, a1, a3
; RV32-NEXT: add a0, a1, a0
; RV32-NEXT: and a3, a0, a3
; RV32-NEXT: bltu a3, a4, .LBB38_2
; RV32-NEXT: # %bb.1:
; RV32-NEXT: li a1, 42
; RV32-NEXT: .LBB38_2:
; RV32-NEXT: sh a0, 0(a2)
; RV32-NEXT: mv a0, a1
; RV32-NEXT: ret
;
; RV64-LABEL: overflow_not_used:
; RV64: # %bb.0:
; RV64-NEXT: lui a3, 16
; RV64-NEXT: addiw a3, a3, -1
; RV64-NEXT: and a4, a1, a3
; RV64-NEXT: add a0, a1, a0
; RV64-NEXT: and a3, a0, a3
; RV64-NEXT: bltu a3, a4, .LBB38_2
; RV64-NEXT: # %bb.1:
; RV64-NEXT: li a1, 42
; RV64-NEXT: .LBB38_2:
; RV64-NEXT: sh a0, 0(a2)
; RV64-NEXT: mv a0, a1
; RV64-NEXT: ret
%add = add i16 %b, %a
%cmp = icmp ult i16 %add, %b
%Q = select i1 %cmp, i16 %b, i16 42
store i16 %add, ptr %res
ret i16 %Q
}