This is an archive of the discontinued LLVM Phabricator instance.

[RISCV] select(C0, x, select(C1, x, y)) -> select(C0|C1, x, y)
AbandonedPublic

Authored by liaolucy on May 22 2023, 11:31 PM.

Details

Summary

RV32, ExpandIntRes_MINMAX expanding i64 will generate select + select.

This patch reduces the number of branch instructions for a specific condition:
select(C0, x, select(C1, x, y)) -> select(C0|C1, x, y)
select(C0, select(C1, x, y), y) -> select(C0&C1, x, y)

Possible related patch, https://reviews.llvm.org/D98932

Diff Detail

Event Timeline

liaolucy created this revision.May 22 2023, 11:31 PM
Herald added a project: Restricted Project. · View Herald TranscriptMay 22 2023, 11:31 PM
liaolucy requested review of this revision.May 22 2023, 11:31 PM
liaolucy edited the summary of this revision. (Show Details)May 22 2023, 11:31 PM

Do we need to care about poison here? https://alive2.llvm.org/ce/z/RKimev

jrtc27 added a comment.EditedMay 22 2023, 11:41 PM

(If so you need to freeze C1 for that case https://alive2.llvm.org/ce/z/RKimev. Haven't looked at the other case, though at a glance I imagine it's the same)

I'm not sure this is even the simplest form for these cases. I'm going to post an alternative patch in a minute.

I'm not sure this is even the simplest form for these cases. I'm going to post an alternative patch in a minute.

Scratch that. We do get to the simpler answer. In all the tests here C0|C1 and C0&C1 can be simplified because they are 2 setccs with the same operands like (seteq X, -1)|(setlt X, -1).

Here's my patch to special case directly in ExpandIntRes_MINMAX.

diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
index 7e85a2ea0f97..b756f2b0fbfc 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
@@ -2936,6 +2936,22 @@ void DAGTypeLegalizer::ExpandIntRes_MINMAX(SDNode *N,
   // Hi part is always the same op
   Hi = DAG.getNode(N->getOpcode(), DL, NVT, {LHSH, RHSH});
 
+  // The Lo of smin(X, -1) is LHSL if X is negative. Otherwise it's -1.
+  if (N->getOpcode() == ISD::SMIN && isAllOnesConstant(RHS)) {
+    SDValue HiNeg = DAG.getSetCC(DL, CCT, LHSH, DAG.getConstant(0, DL, NVT),
+                                 ISD::SETLT);
+    Lo = DAG.getSelect(DL, NVT, HiNeg, LHSL, DAG.getConstant(-1, DL, NVT));
+    return;
+  }
+
+  // The Lo of smax(X, 0) is 0 if X is negative. Otherwise it's LHSL.
+  if (N->getOpcode() == ISD::SMAX && isNullConstant(RHS)) {
+    SDValue HiNeg = DAG.getSetCC(DL, CCT, LHSH, DAG.getConstant(0, DL, NVT),
+                                 ISD::SETLT);
+    Lo = DAG.getSelect(DL, NVT, HiNeg, DAG.getConstant(0, DL, NVT), LHSL);
+    return;
+  }
+
   // We need to know whether to select Lo part that corresponds to 'winning'
   // Hi part or if Hi parts are equal.
   SDValue IsHiLeft = DAG.getSetCC(DL, CCT, LHSH, RHSH, CondC);

Posted my patch D151182. I think it's useful because it optimizes more targets. There may still be value in this patch for RISC-V but we need new tests.

Thanks Jessica and Craig.

I haven't found any more examples of this patch still being valuable.

Abandon it later.

liaolucy abandoned this revision.May 24 2023, 5:53 AM