[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