blob: b85ec309e6029af2b51bfb42aa66da12ee95cb81 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc --mtriple=loongarch32 -mattr=+32s,+d < %s | FileCheck %s --check-prefixes=CHECK,LA32
; RUN: llc --mtriple=loongarch64 -mattr=+d < %s | FileCheck %s --check-prefixes=CHECK,LA64
;; Part 1: add — commutative, 2 (shared-operand side) x 2 (arm) = 4
;; Expect: single maskeqz/masknez + add (2 insns for select+add).
define i64 @add_lhs_true(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: add_lhs_true:
; LA32: # %bb.0: # %entry
; LA32-NEXT: add.w $a3, $a1, $a3
; LA32-NEXT: add.w $a6, $a0, $a2
; LA32-NEXT: sltu $a6, $a6, $a0
; LA32-NEXT: add.w $a3, $a3, $a6
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: maskeqz $a3, $a3, $a4
; LA32-NEXT: masknez $a1, $a1, $a4
; LA32-NEXT: or $a1, $a3, $a1
; LA32-NEXT: maskeqz $a2, $a2, $a4
; LA32-NEXT: add.w $a0, $a0, $a2
; LA32-NEXT: ret
;
; LA64-LABEL: add_lhs_true:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: maskeqz $a1, $a1, $a2
; LA64-NEXT: add.d $a0, $a0, $a1
; LA64-NEXT: ret
entry:
%0 = add i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %0, i64 %a
ret i64 %2
}
define i64 @add_rhs_true(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: add_rhs_true:
; LA32: # %bb.0: # %entry
; LA32-NEXT: add.w $a1, $a1, $a3
; LA32-NEXT: add.w $a6, $a0, $a2
; LA32-NEXT: sltu $a6, $a6, $a0
; LA32-NEXT: add.w $a1, $a1, $a6
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: maskeqz $a1, $a1, $a4
; LA32-NEXT: masknez $a3, $a3, $a4
; LA32-NEXT: or $a1, $a1, $a3
; LA32-NEXT: maskeqz $a0, $a0, $a4
; LA32-NEXT: add.w $a0, $a2, $a0
; LA32-NEXT: ret
;
; LA64-LABEL: add_rhs_true:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: maskeqz $a0, $a0, $a2
; LA64-NEXT: add.d $a0, $a1, $a0
; LA64-NEXT: ret
entry:
%0 = add i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %0, i64 %b
ret i64 %2
}
define i64 @add_lhs_false(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: add_lhs_false:
; LA32: # %bb.0: # %entry
; LA32-NEXT: add.w $a3, $a1, $a3
; LA32-NEXT: add.w $a6, $a0, $a2
; LA32-NEXT: sltu $a6, $a6, $a0
; LA32-NEXT: add.w $a3, $a3, $a6
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: masknez $a3, $a3, $a4
; LA32-NEXT: maskeqz $a1, $a1, $a4
; LA32-NEXT: or $a1, $a1, $a3
; LA32-NEXT: masknez $a2, $a2, $a4
; LA32-NEXT: add.w $a0, $a0, $a2
; LA32-NEXT: ret
;
; LA64-LABEL: add_lhs_false:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: masknez $a1, $a1, $a2
; LA64-NEXT: add.d $a0, $a0, $a1
; LA64-NEXT: ret
entry:
%0 = add i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %a, i64 %0
ret i64 %2
}
define i64 @add_rhs_false(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: add_rhs_false:
; LA32: # %bb.0: # %entry
; LA32-NEXT: add.w $a1, $a1, $a3
; LA32-NEXT: add.w $a6, $a0, $a2
; LA32-NEXT: sltu $a6, $a6, $a0
; LA32-NEXT: add.w $a1, $a1, $a6
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: masknez $a1, $a1, $a4
; LA32-NEXT: maskeqz $a3, $a3, $a4
; LA32-NEXT: or $a1, $a3, $a1
; LA32-NEXT: masknez $a0, $a0, $a4
; LA32-NEXT: add.w $a0, $a2, $a0
; LA32-NEXT: ret
;
; LA64-LABEL: add_rhs_false:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: masknez $a0, $a0, $a2
; LA64-NEXT: add.d $a0, $a1, $a0
; LA64-NEXT: ret
entry:
%0 = add i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %b, i64 %0
ret i64 %2
}
;; Part 2: or / xor — same 4 combos each, commutative like add.
define i64 @or_lhs_true(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: or_lhs_true:
; LA32: # %bb.0: # %entry
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: maskeqz $a2, $a2, $a4
; LA32-NEXT: or $a0, $a0, $a2
; LA32-NEXT: maskeqz $a2, $a3, $a4
; LA32-NEXT: or $a1, $a1, $a2
; LA32-NEXT: ret
;
; LA64-LABEL: or_lhs_true:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: maskeqz $a1, $a1, $a2
; LA64-NEXT: or $a0, $a0, $a1
; LA64-NEXT: ret
entry:
%0 = or i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %0, i64 %a
ret i64 %2
}
define i64 @or_rhs_true(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: or_rhs_true:
; LA32: # %bb.0: # %entry
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: maskeqz $a0, $a0, $a4
; LA32-NEXT: or $a0, $a2, $a0
; LA32-NEXT: maskeqz $a1, $a1, $a4
; LA32-NEXT: or $a1, $a3, $a1
; LA32-NEXT: ret
;
; LA64-LABEL: or_rhs_true:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: maskeqz $a0, $a0, $a2
; LA64-NEXT: or $a0, $a1, $a0
; LA64-NEXT: ret
entry:
%0 = or i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %0, i64 %b
ret i64 %2
}
define i64 @or_lhs_false(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: or_lhs_false:
; LA32: # %bb.0: # %entry
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: masknez $a2, $a2, $a4
; LA32-NEXT: or $a0, $a0, $a2
; LA32-NEXT: masknez $a2, $a3, $a4
; LA32-NEXT: or $a1, $a1, $a2
; LA32-NEXT: ret
;
; LA64-LABEL: or_lhs_false:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: masknez $a1, $a1, $a2
; LA64-NEXT: or $a0, $a0, $a1
; LA64-NEXT: ret
entry:
%0 = or i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %a, i64 %0
ret i64 %2
}
define i64 @or_rhs_false(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: or_rhs_false:
; LA32: # %bb.0: # %entry
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: masknez $a0, $a0, $a4
; LA32-NEXT: or $a0, $a2, $a0
; LA32-NEXT: masknez $a1, $a1, $a4
; LA32-NEXT: or $a1, $a3, $a1
; LA32-NEXT: ret
;
; LA64-LABEL: or_rhs_false:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: masknez $a0, $a0, $a2
; LA64-NEXT: or $a0, $a1, $a0
; LA64-NEXT: ret
entry:
%0 = or i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %b, i64 %0
ret i64 %2
}
define i64 @xor_lhs_true(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: xor_lhs_true:
; LA32: # %bb.0: # %entry
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: maskeqz $a2, $a2, $a4
; LA32-NEXT: xor $a0, $a0, $a2
; LA32-NEXT: maskeqz $a2, $a3, $a4
; LA32-NEXT: xor $a1, $a1, $a2
; LA32-NEXT: ret
;
; LA64-LABEL: xor_lhs_true:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: maskeqz $a1, $a1, $a2
; LA64-NEXT: xor $a0, $a0, $a1
; LA64-NEXT: ret
entry:
%0 = xor i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %0, i64 %a
ret i64 %2
}
define i64 @xor_rhs_true(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: xor_rhs_true:
; LA32: # %bb.0: # %entry
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: maskeqz $a0, $a0, $a4
; LA32-NEXT: xor $a0, $a2, $a0
; LA32-NEXT: maskeqz $a1, $a1, $a4
; LA32-NEXT: xor $a1, $a3, $a1
; LA32-NEXT: ret
;
; LA64-LABEL: xor_rhs_true:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: maskeqz $a0, $a0, $a2
; LA64-NEXT: xor $a0, $a1, $a0
; LA64-NEXT: ret
entry:
%0 = xor i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %0, i64 %b
ret i64 %2
}
define i64 @xor_lhs_false(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: xor_lhs_false:
; LA32: # %bb.0: # %entry
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: masknez $a2, $a2, $a4
; LA32-NEXT: xor $a0, $a0, $a2
; LA32-NEXT: masknez $a2, $a3, $a4
; LA32-NEXT: xor $a1, $a1, $a2
; LA32-NEXT: ret
;
; LA64-LABEL: xor_lhs_false:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: masknez $a1, $a1, $a2
; LA64-NEXT: xor $a0, $a0, $a1
; LA64-NEXT: ret
entry:
%0 = xor i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %a, i64 %0
ret i64 %2
}
define i64 @xor_rhs_false(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: xor_rhs_false:
; LA32: # %bb.0: # %entry
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: masknez $a0, $a0, $a4
; LA32-NEXT: xor $a0, $a2, $a0
; LA32-NEXT: masknez $a1, $a1, $a4
; LA32-NEXT: xor $a1, $a3, $a1
; LA32-NEXT: ret
;
; LA64-LABEL: xor_rhs_false:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: masknez $a0, $a0, $a2
; LA64-NEXT: xor $a0, $a1, $a0
; LA64-NEXT: ret
entry:
%0 = xor i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %b, i64 %0
ret i64 %2
}
;; Part 3: sub — NOT commutative.
;; Positive: shared operand is the minuend (1st operand of sub).
;; Negative: shared operand is the subtrahend (2nd operand of sub).
;; MUST NOT be optimized (must keep maskeqz/masknez+or, 3 insns).
;; Positive: a - b, a shared -> should fold to: sub a, (select cond, b, 0)
define i64 @sub_minuend_true(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: sub_minuend_true:
; LA32: # %bb.0: # %entry
; LA32-NEXT: sltu $a6, $a0, $a2
; LA32-NEXT: sub.w $a3, $a1, $a3
; LA32-NEXT: sub.w $a3, $a3, $a6
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: maskeqz $a3, $a3, $a4
; LA32-NEXT: masknez $a1, $a1, $a4
; LA32-NEXT: or $a1, $a3, $a1
; LA32-NEXT: maskeqz $a2, $a2, $a4
; LA32-NEXT: sub.w $a0, $a0, $a2
; LA32-NEXT: ret
;
; LA64-LABEL: sub_minuend_true:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: maskeqz $a1, $a1, $a2
; LA64-NEXT: sub.d $a0, $a0, $a1
; LA64-NEXT: ret
entry:
%0 = sub i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %0, i64 %a
ret i64 %2
}
define i64 @sub_minuend_false(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: sub_minuend_false:
; LA32: # %bb.0: # %entry
; LA32-NEXT: sltu $a6, $a0, $a2
; LA32-NEXT: sub.w $a3, $a1, $a3
; LA32-NEXT: sub.w $a3, $a3, $a6
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: masknez $a3, $a3, $a4
; LA32-NEXT: maskeqz $a1, $a1, $a4
; LA32-NEXT: or $a1, $a1, $a3
; LA32-NEXT: masknez $a2, $a2, $a4
; LA32-NEXT: sub.w $a0, $a0, $a2
; LA32-NEXT: ret
;
; LA64-LABEL: sub_minuend_false:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: masknez $a1, $a1, $a2
; LA64-NEXT: sub.d $a0, $a0, $a1
; LA64-NEXT: ret
entry:
%0 = sub i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %a, i64 %0
ret i64 %2
}
;; Negative: b - a, a is the subtrahend (2nd operand). Cannot be rewritten as
;; `a op (select ...)`. Must NOT be folded; must still emit
;; maskeqz/masknez + or (3 instructions).
define i64 @sub_subtrahend_true_noopt(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: sub_subtrahend_true_noopt:
; LA32: # %bb.0: # %entry
; LA32-NEXT: sltu $a6, $a2, $a0
; LA32-NEXT: sub.w $a3, $a3, $a1
; LA32-NEXT: sub.w $a3, $a3, $a6
; LA32-NEXT: sub.w $a2, $a2, $a0
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: maskeqz $a2, $a2, $a4
; LA32-NEXT: masknez $a0, $a0, $a4
; LA32-NEXT: or $a0, $a2, $a0
; LA32-NEXT: maskeqz $a2, $a3, $a4
; LA32-NEXT: masknez $a1, $a1, $a4
; LA32-NEXT: or $a1, $a2, $a1
; LA32-NEXT: ret
;
; LA64-LABEL: sub_subtrahend_true_noopt:
; LA64: # %bb.0: # %entry
; LA64-NEXT: sub.d $a1, $a1, $a0
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: maskeqz $a1, $a1, $a2
; LA64-NEXT: masknez $a0, $a0, $a2
; LA64-NEXT: or $a0, $a1, $a0
; LA64-NEXT: ret
entry:
%0 = sub i64 %b, %a
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %0, i64 %a
ret i64 %2
}
define i64 @sub_subtrahend_false_noopt(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: sub_subtrahend_false_noopt:
; LA32: # %bb.0: # %entry
; LA32-NEXT: sltu $a6, $a2, $a0
; LA32-NEXT: sub.w $a3, $a3, $a1
; LA32-NEXT: sub.w $a3, $a3, $a6
; LA32-NEXT: sub.w $a2, $a2, $a0
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: masknez $a2, $a2, $a4
; LA32-NEXT: maskeqz $a0, $a0, $a4
; LA32-NEXT: or $a0, $a0, $a2
; LA32-NEXT: masknez $a2, $a3, $a4
; LA32-NEXT: maskeqz $a1, $a1, $a4
; LA32-NEXT: or $a1, $a1, $a2
; LA32-NEXT: ret
;
; LA64-LABEL: sub_subtrahend_false_noopt:
; LA64: # %bb.0: # %entry
; LA64-NEXT: sub.d $a1, $a1, $a0
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: masknez $a1, $a1, $a2
; LA64-NEXT: maskeqz $a0, $a0, $a2
; LA64-NEXT: or $a0, $a0, $a1
; LA64-NEXT: ret
entry:
%0 = sub i64 %b, %a
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %a, i64 %0
ret i64 %2
}
;; Part 4: negative cases unrelated to the sub-direction issue.
;; Unsupported opcode (mul is not add/sub/or/xor) -> must NOT be folded.
define i64 @mul_noopt(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: mul_noopt:
; LA32: # %bb.0: # %entry
; LA32-NEXT: mul.w $a3, $a0, $a3
; LA32-NEXT: mulh.wu $a6, $a0, $a2
; LA32-NEXT: add.w $a3, $a6, $a3
; LA32-NEXT: mul.w $a6, $a1, $a2
; LA32-NEXT: add.w $a3, $a3, $a6
; LA32-NEXT: mul.w $a2, $a0, $a2
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: maskeqz $a2, $a2, $a4
; LA32-NEXT: masknez $a0, $a0, $a4
; LA32-NEXT: or $a0, $a2, $a0
; LA32-NEXT: maskeqz $a2, $a3, $a4
; LA32-NEXT: masknez $a1, $a1, $a4
; LA32-NEXT: or $a1, $a2, $a1
; LA32-NEXT: ret
;
; LA64-LABEL: mul_noopt:
; LA64: # %bb.0: # %entry
; LA64-NEXT: mul.d $a1, $a0, $a1
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: maskeqz $a1, $a1, $a2
; LA64-NEXT: masknez $a0, $a0, $a2
; LA64-NEXT: or $a0, $a1, $a0
; LA64-NEXT: ret
entry:
%0 = mul i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %0, i64 %a
ret i64 %2
}
;; binop operands are unrelated to the other select arm (%e is unrelated to
;; add(a,b)) -> must NOT be folded.
define i64 @add_unrelated_noopt(i64 %a, i64 %b, i64 %e, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: add_unrelated_noopt:
; LA32: # %bb.0: # %entry
; LA32-NEXT: add.w $a1, $a1, $a3
; LA32-NEXT: add.w $a2, $a0, $a2
; LA32-NEXT: sltu $a0, $a2, $a0
; LA32-NEXT: add.w $a1, $a1, $a0
; LA32-NEXT: slt $a3, $a6, $a7
; LA32-NEXT: maskeqz $a0, $a2, $a3
; LA32-NEXT: masknez $a2, $a4, $a3
; LA32-NEXT: or $a0, $a0, $a2
; LA32-NEXT: maskeqz $a1, $a1, $a3
; LA32-NEXT: masknez $a2, $a5, $a3
; LA32-NEXT: or $a1, $a1, $a2
; LA32-NEXT: ret
;
; LA64-LABEL: add_unrelated_noopt:
; LA64: # %bb.0: # %entry
; LA64-NEXT: add.d $a0, $a0, $a1
; LA64-NEXT: slt $a1, $a3, $a4
; LA64-NEXT: maskeqz $a0, $a0, $a1
; LA64-NEXT: masknez $a1, $a2, $a1
; LA64-NEXT: or $a0, $a0, $a1
; LA64-NEXT: ret
entry:
%0 = add i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %0, i64 %e
ret i64 %2
}
;; Part 5: multi-use — only representative for add/sub, mechanism identical
;; for or/xor. Original binop result must still be computed once and
;; reused; select part should still shrink to a single mask instruction.
define i64 @add_lhs_true_multi_use(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: add_lhs_true_multi_use:
; LA32: # %bb.0: # %entry
; LA32-NEXT: add.w $a3, $a1, $a3
; LA32-NEXT: add.w $a6, $a0, $a2
; LA32-NEXT: sltu $a7, $a6, $a0
; LA32-NEXT: add.w $a3, $a3, $a7
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: maskeqz $a5, $a3, $a4
; LA32-NEXT: masknez $a1, $a1, $a4
; LA32-NEXT: or $a1, $a5, $a1
; LA32-NEXT: maskeqz $a2, $a2, $a4
; LA32-NEXT: add.w $a0, $a0, $a2
; LA32-NEXT: add.w $a1, $a3, $a1
; LA32-NEXT: add.w $a0, $a6, $a0
; LA32-NEXT: sltu $a2, $a0, $a6
; LA32-NEXT: add.w $a1, $a1, $a2
; LA32-NEXT: ret
;
; LA64-LABEL: add_lhs_true_multi_use:
; LA64: # %bb.0: # %entry
; LA64-NEXT: add.d $a4, $a0, $a1
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: maskeqz $a1, $a1, $a2
; LA64-NEXT: add.d $a0, $a0, $a1
; LA64-NEXT: add.d $a0, $a4, $a0
; LA64-NEXT: ret
entry:
%0 = add i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %0, i64 %a
%3 = add i64 %0, %2
ret i64 %3
}
define i64 @sub_minuend_true_multi_use(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: sub_minuend_true_multi_use:
; LA32: # %bb.0: # %entry
; LA32-NEXT: sltu $a6, $a0, $a2
; LA32-NEXT: sub.w $a3, $a1, $a3
; LA32-NEXT: sub.w $a3, $a3, $a6
; LA32-NEXT: sub.w $a6, $a0, $a2
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: maskeqz $a5, $a3, $a4
; LA32-NEXT: masknez $a1, $a1, $a4
; LA32-NEXT: or $a1, $a5, $a1
; LA32-NEXT: maskeqz $a2, $a2, $a4
; LA32-NEXT: sub.w $a0, $a0, $a2
; LA32-NEXT: add.w $a1, $a3, $a1
; LA32-NEXT: add.w $a0, $a6, $a0
; LA32-NEXT: sltu $a2, $a0, $a6
; LA32-NEXT: add.w $a1, $a1, $a2
; LA32-NEXT: ret
;
; LA64-LABEL: sub_minuend_true_multi_use:
; LA64: # %bb.0: # %entry
; LA64-NEXT: sub.d $a4, $a0, $a1
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: maskeqz $a1, $a1, $a2
; LA64-NEXT: sub.d $a0, $a0, $a1
; LA64-NEXT: add.d $a0, $a4, $a0
; LA64-NEXT: ret
entry:
%0 = sub i64 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %0, i64 %a
%3 = add i64 %0, %2
ret i64 %3
}
;; multi-use negative sub case: must still not be folded even with reuse.
define i64 @sub_subtrahend_true_noopt_multi_use(i64 %a, i64 %b, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: sub_subtrahend_true_noopt_multi_use:
; LA32: # %bb.0: # %entry
; LA32-NEXT: sltu $a6, $a2, $a0
; LA32-NEXT: sub.w $a3, $a3, $a1
; LA32-NEXT: sub.w $a3, $a3, $a6
; LA32-NEXT: sub.w $a2, $a2, $a0
; LA32-NEXT: slt $a4, $a4, $a5
; LA32-NEXT: maskeqz $a5, $a2, $a4
; LA32-NEXT: masknez $a0, $a0, $a4
; LA32-NEXT: or $a0, $a5, $a0
; LA32-NEXT: maskeqz $a5, $a3, $a4
; LA32-NEXT: masknez $a1, $a1, $a4
; LA32-NEXT: or $a1, $a5, $a1
; LA32-NEXT: add.w $a1, $a3, $a1
; LA32-NEXT: add.w $a0, $a2, $a0
; LA32-NEXT: sltu $a2, $a0, $a2
; LA32-NEXT: add.w $a1, $a1, $a2
; LA32-NEXT: ret
;
; LA64-LABEL: sub_subtrahend_true_noopt_multi_use:
; LA64: # %bb.0: # %entry
; LA64-NEXT: sub.d $a1, $a1, $a0
; LA64-NEXT: slt $a2, $a2, $a3
; LA64-NEXT: maskeqz $a3, $a1, $a2
; LA64-NEXT: masknez $a0, $a0, $a2
; LA64-NEXT: or $a0, $a3, $a0
; LA64-NEXT: add.d $a0, $a1, $a0
; LA64-NEXT: ret
entry:
%0 = sub i64 %b, %a
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %0, i64 %a
%3 = add i64 %0, %2
ret i64 %3
}
;; Part 6: immediate operand variants (also exercise add/sub with a
;; constant "Y" operand). Kept with `icmp slt i32 %c, %d` to isolate
;; from the unrelated SETCC-immediate combine.
define i64 @add_imm_true(i64 %a, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: add_imm_true:
; LA32: # %bb.0: # %entry
; LA32-NEXT: addi.w $a4, $a0, 5
; LA32-NEXT: sltu $a4, $a4, $a0
; LA32-NEXT: slt $a2, $a2, $a3
; LA32-NEXT: masknez $a3, $a4, $a2
; LA32-NEXT: add.w $a1, $a1, $a3
; LA32-NEXT: ori $a3, $zero, 5
; LA32-NEXT: masknez $a2, $a3, $a2
; LA32-NEXT: add.w $a0, $a0, $a2
; LA32-NEXT: ret
;
; LA64-LABEL: add_imm_true:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a1, $a1, $a2
; LA64-NEXT: ori $a2, $zero, 5
; LA64-NEXT: masknez $a1, $a2, $a1
; LA64-NEXT: add.d $a0, $a0, $a1
; LA64-NEXT: ret
entry:
%0 = add i64 %a, 5
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %a, i64 %0
ret i64 %2
}
;; Positive: a - 5, a is minuend -> fold.
define i64 @sub_imm_minuend_true(i64 %a, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: sub_imm_minuend_true:
; LA32: # %bb.0: # %entry
; LA32-NEXT: addi.w $a4, $a0, -5
; LA32-NEXT: sltu $a4, $a4, $a0
; LA32-NEXT: add.w $a4, $a1, $a4
; LA32-NEXT: addi.w $a4, $a4, -1
; LA32-NEXT: slt $a2, $a2, $a3
; LA32-NEXT: masknez $a3, $a4, $a2
; LA32-NEXT: maskeqz $a1, $a1, $a2
; LA32-NEXT: or $a1, $a1, $a3
; LA32-NEXT: addi.w $a3, $zero, -5
; LA32-NEXT: masknez $a2, $a3, $a2
; LA32-NEXT: add.w $a0, $a0, $a2
; LA32-NEXT: ret
;
; LA64-LABEL: sub_imm_minuend_true:
; LA64: # %bb.0: # %entry
; LA64-NEXT: slt $a1, $a1, $a2
; LA64-NEXT: addi.w $a2, $zero, -5
; LA64-NEXT: masknez $a1, $a2, $a1
; LA64-NEXT: add.d $a0, $a0, $a1
; LA64-NEXT: ret
entry:
%0 = sub i64 %a, 5
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %a, i64 %0
ret i64 %2
}
;; Negative: 5 - a, a is subtrahend -> must NOT fold.
define i64 @sub_imm_subtrahend_noopt(i64 %a, i32 signext %c, i32 signext %d) nounwind {
; LA32-LABEL: sub_imm_subtrahend_noopt:
; LA32: # %bb.0: # %entry
; LA32-NEXT: ori $a4, $zero, 5
; LA32-NEXT: sltu $a5, $a4, $a0
; LA32-NEXT: add.w $a5, $a1, $a5
; LA32-NEXT: sub.w $a5, $zero, $a5
; LA32-NEXT: sub.w $a4, $a4, $a0
; LA32-NEXT: slt $a2, $a2, $a3
; LA32-NEXT: masknez $a3, $a4, $a2
; LA32-NEXT: maskeqz $a0, $a0, $a2
; LA32-NEXT: or $a0, $a0, $a3
; LA32-NEXT: masknez $a3, $a5, $a2
; LA32-NEXT: maskeqz $a1, $a1, $a2
; LA32-NEXT: or $a1, $a1, $a3
; LA32-NEXT: ret
;
; LA64-LABEL: sub_imm_subtrahend_noopt:
; LA64: # %bb.0: # %entry
; LA64-NEXT: ori $a3, $zero, 5
; LA64-NEXT: sub.d $a3, $a3, $a0
; LA64-NEXT: slt $a1, $a1, $a2
; LA64-NEXT: masknez $a2, $a3, $a1
; LA64-NEXT: maskeqz $a0, $a0, $a1
; LA64-NEXT: or $a0, $a0, $a2
; LA64-NEXT: ret
entry:
%0 = sub i64 5, %a
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i64 %a, i64 %0
ret i64 %2
}
;; Part 7: LA32 (i32 GRLen) sanity — same logic must hold for 32-bit.
define signext i32 @add_lhs_true_i32(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d) nounwind {
; CHECK-LABEL: add_lhs_true_i32:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: slt $a2, $a2, $a3
; CHECK-NEXT: maskeqz $a1, $a1, $a2
; CHECK-NEXT: add.w $a0, $a0, $a1
; CHECK-NEXT: ret
entry:
%0 = add i32 %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i32 %0, i32 %a
ret i32 %2
}
;; Negative sub case must also hold on i32.
define signext i32 @sub_subtrahend_true_noopt_i32(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d) nounwind {
; CHECK-LABEL: sub_subtrahend_true_noopt_i32:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: sub.w $a1, $a1, $a0
; CHECK-NEXT: slt $a2, $a2, $a3
; CHECK-NEXT: maskeqz $a1, $a1, $a2
; CHECK-NEXT: masknez $a0, $a0, $a2
; CHECK-NEXT: or $a0, $a1, $a0
; CHECK-NEXT: ret
entry:
%0 = sub i32 %b, %a
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, i32 %0, i32 %a
ret i32 %2
}
;; Part 8: types outside the combine's scope must be unaffected.
;; Float select: VT is f64, not GRLenVT -> must be unaffected by this combine.
define double @fadd_select_unaffected(double %a, double %b, i32 signext %c, i32 signext %d) nounwind {
; CHECK-LABEL: fadd_select_unaffected:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: slt $a0, $a0, $a1
; CHECK-NEXT: fadd.d $fa1, $fa0, $fa1
; CHECK-NEXT: movgr2cf $fcc0, $a0
; CHECK-NEXT: fsel $fa0, $fa0, $fa1, $fcc0
; CHECK-NEXT: ret
entry:
%0 = fadd double %a, %b
%1 = icmp slt i32 %c, %d
%2 = select i1 %1, double %0, double %a
ret double %2
}