[llvm] [LoongArch][NFC] Add tests for select-binop DAG combine (PR #215519)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 11 04:03:28 PDT 2026


https://github.com/heiher created https://github.com/llvm/llvm-project/pull/215519

None

>From d6f93fea96170a0ca6b635262f668fab55c4104d Mon Sep 17 00:00:00 2001
From: WANG Rui <wangrui at loongson.cn>
Date: Tue, 11 Aug 2026 15:19:05 +0800
Subject: [PATCH] [LoongArch][NFC] Add tests for select-binop DAG combine

---
 .../CodeGen/LoongArch/select-binop-combine.ll | 835 ++++++++++++++++++
 1 file changed, 835 insertions(+)
 create mode 100644 llvm/test/CodeGen/LoongArch/select-binop-combine.ll

diff --git a/llvm/test/CodeGen/LoongArch/select-binop-combine.ll b/llvm/test/CodeGen/LoongArch/select-binop-combine.ll
new file mode 100644
index 0000000000000..14631056f8948
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/select-binop-combine.ll
@@ -0,0 +1,835 @@
+; 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 $a2, $a0, $a2
+; LA32-NEXT:    sltu $a6, $a2, $a0
+; LA32-NEXT:    add.w $a3, $a3, $a6
+; 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: add_lhs_true:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    add.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 = 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 $a0, $a6, $a0
+; LA32-NEXT:    add.w $a1, $a1, $a0
+; LA32-NEXT:    slt $a4, $a4, $a5
+; LA32-NEXT:    maskeqz $a0, $a6, $a4
+; LA32-NEXT:    masknez $a2, $a2, $a4
+; LA32-NEXT:    or $a0, $a0, $a2
+; LA32-NEXT:    maskeqz $a1, $a1, $a4
+; LA32-NEXT:    masknez $a2, $a3, $a4
+; LA32-NEXT:    or $a1, $a1, $a2
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: add_rhs_true:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    slt $a2, $a2, $a3
+; LA64-NEXT:    maskeqz $a0, $a0, $a2
+; LA64-NEXT:    masknez $a1, $a1, $a2
+; 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 %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 $a2, $a0, $a2
+; LA32-NEXT:    sltu $a6, $a2, $a0
+; LA32-NEXT:    add.w $a3, $a3, $a6
+; 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: add_lhs_false:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    add.d $a1, $a0, $a1
+; 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 = 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 $a0, $a6, $a0
+; LA32-NEXT:    add.w $a1, $a1, $a0
+; LA32-NEXT:    slt $a4, $a4, $a5
+; LA32-NEXT:    masknez $a0, $a6, $a4
+; LA32-NEXT:    maskeqz $a2, $a2, $a4
+; LA32-NEXT:    or $a0, $a2, $a0
+; LA32-NEXT:    masknez $a1, $a1, $a4
+; LA32-NEXT:    maskeqz $a2, $a3, $a4
+; LA32-NEXT:    or $a1, $a2, $a1
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: add_rhs_false:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    slt $a2, $a2, $a3
+; LA64-NEXT:    masknez $a0, $a0, $a2
+; LA64-NEXT:    maskeqz $a1, $a1, $a2
+; LA64-NEXT:    or $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:    or $a3, $a1, $a3
+; LA32-NEXT:    or $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: or_lhs_true:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    or $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 = 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:    or $a1, $a1, $a3
+; LA32-NEXT:    or $a0, $a0, $a2
+; LA32-NEXT:    slt $a4, $a4, $a5
+; LA32-NEXT:    maskeqz $a0, $a0, $a4
+; LA32-NEXT:    masknez $a2, $a2, $a4
+; LA32-NEXT:    or $a0, $a0, $a2
+; LA32-NEXT:    maskeqz $a1, $a1, $a4
+; LA32-NEXT:    masknez $a2, $a3, $a4
+; LA32-NEXT:    or $a1, $a1, $a2
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: or_rhs_true:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    or $a0, $a0, $a1
+; LA64-NEXT:    slt $a2, $a2, $a3
+; LA64-NEXT:    maskeqz $a0, $a0, $a2
+; 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 %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:    or $a3, $a1, $a3
+; LA32-NEXT:    or $a2, $a0, $a2
+; 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: or_lhs_false:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    or $a1, $a0, $a1
+; 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 = 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:    or $a1, $a1, $a3
+; LA32-NEXT:    or $a0, $a0, $a2
+; LA32-NEXT:    slt $a4, $a4, $a5
+; LA32-NEXT:    masknez $a0, $a0, $a4
+; LA32-NEXT:    maskeqz $a2, $a2, $a4
+; LA32-NEXT:    or $a0, $a2, $a0
+; LA32-NEXT:    masknez $a1, $a1, $a4
+; LA32-NEXT:    maskeqz $a2, $a3, $a4
+; LA32-NEXT:    or $a1, $a2, $a1
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: or_rhs_false:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    or $a0, $a0, $a1
+; LA64-NEXT:    slt $a2, $a2, $a3
+; LA64-NEXT:    masknez $a0, $a0, $a2
+; LA64-NEXT:    maskeqz $a1, $a1, $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:    xor $a3, $a1, $a3
+; LA32-NEXT:    xor $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: xor_lhs_true:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    xor $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 = 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:    xor $a1, $a1, $a3
+; LA32-NEXT:    xor $a0, $a0, $a2
+; LA32-NEXT:    slt $a4, $a4, $a5
+; LA32-NEXT:    maskeqz $a0, $a0, $a4
+; LA32-NEXT:    masknez $a2, $a2, $a4
+; LA32-NEXT:    or $a0, $a0, $a2
+; LA32-NEXT:    maskeqz $a1, $a1, $a4
+; LA32-NEXT:    masknez $a2, $a3, $a4
+; LA32-NEXT:    or $a1, $a1, $a2
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: xor_rhs_true:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    xor $a0, $a0, $a1
+; LA64-NEXT:    slt $a2, $a2, $a3
+; LA64-NEXT:    maskeqz $a0, $a0, $a2
+; LA64-NEXT:    masknez $a1, $a1, $a2
+; LA64-NEXT:    or $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 %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:    xor $a3, $a1, $a3
+; LA32-NEXT:    xor $a2, $a0, $a2
+; 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: xor_lhs_false:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    xor $a1, $a0, $a1
+; 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 = 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:    xor $a1, $a1, $a3
+; LA32-NEXT:    xor $a0, $a0, $a2
+; LA32-NEXT:    slt $a4, $a4, $a5
+; LA32-NEXT:    masknez $a0, $a0, $a4
+; LA32-NEXT:    maskeqz $a2, $a2, $a4
+; LA32-NEXT:    or $a0, $a2, $a0
+; LA32-NEXT:    masknez $a1, $a1, $a4
+; LA32-NEXT:    maskeqz $a2, $a3, $a4
+; LA32-NEXT:    or $a1, $a2, $a1
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: xor_rhs_false:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    xor $a0, $a0, $a1
+; LA64-NEXT:    slt $a2, $a2, $a3
+; LA64-NEXT:    masknez $a0, $a0, $a2
+; LA64-NEXT:    maskeqz $a1, $a1, $a2
+; LA64-NEXT:    or $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:    sub.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: sub_minuend_true:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    sub.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 = 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:    sub.w $a2, $a0, $a2
+; 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_minuend_false:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    sub.d $a1, $a0, $a1
+; 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 %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 $a2, $a0, $a2
+; LA32-NEXT:    sltu $a6, $a2, $a0
+; LA32-NEXT:    add.w $a3, $a3, $a6
+; 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: add_lhs_true_multi_use:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    add.d $a1, $a0, $a1
+; 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 = 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 $a2, $a0, $a2
+; 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_minuend_true_multi_use:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    sub.d $a1, $a0, $a1
+; 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 %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 $a5, $a4, $a0
+; LA32-NEXT:    add.w $a5, $a1, $a5
+; 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: add_imm_true:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    addi.d $a3, $a0, 5
+; 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 = 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 $a5, $a4, $a0
+; LA32-NEXT:    add.w $a5, $a1, $a5
+; LA32-NEXT:    addi.w $a5, $a5, -1
+; 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_minuend_true:
+; LA64:       # %bb.0: # %entry
+; LA64-NEXT:    addi.d $a3, $a0, -5
+; 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 %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:    add.w $a1, $a0, $a1
+; 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 = 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
+}



More information about the llvm-commits mailing list