[PATCH][AArch64] Enable sign check optimization by CSE

Sergey Dmitrouk sdmitrouk at accesssoftek.com
Wed Jul 23 08:54:06 PDT 2014


Hi,

Basing on the following information from [this post][0] by James Molloy:

  2. "if (a < 0 && b == c || a > 0 && b == d)" - the first comparison of
  'a' against zero is done twice, when the flag results of the first
  comparison could be used for the second comparison.

I've made a patch (attached) that removes this extra comparison.  More
complex cases like comparisons with non-zero immediate values or with
registers doesn't seem to be task for a code generator.  Comparing with
zero is quite common, so I seems to be worth adding.

Please review the patch.  Couldn't find a better place to make the
change, but I'll be happy to adjust the patch if anyone has better ideas.

Best regards,
Sergey

0: http://article.gmane.org/gmane.comp.compilers.llvm.devel/74269
-------------- next part --------------
[AArch64] Enable sign check optimization by CSE

Turn "x > 1" condition into "x >= 0" to make both "x < 0" and "x > 0"
checks generate the same code.  This allows CSE pass to remove
duplicated compare instructions in this quite common branching case.

diff --git a/lib/Target/AArch64/AArch64ISelLowering.cpp b/lib/Target/AArch64/AArch64ISelLowering.cpp
index 4921826..5367817 100644
--- a/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -2949,6 +2949,18 @@ SDValue AArch64TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
       }
     }
 
+    // Turn "x > 1" condition into "x >= 0" to make both "x < 0" and "x > 0"
+    // checks generate the same code.  This allows CSE pass to remove duplicated
+    // compare instructions in this quite common branching case.
+    if (RHSC && RHSC->isOne() && CC == ISD::SETLT) {
+      CC = ISD::SETLE;
+
+      uint64_t C = RHSC->getZExtValue();
+      C = (RHS.getValueType() == MVT::i32) ? (uint32_t)(C - 1) : (C - 1);
+
+      RHS = DAG.getConstant(C, RHS.getValueType());
+    }
+
     SDValue CCVal;
     SDValue Cmp = getAArch64Cmp(LHS, RHS, CC, CCVal, DAG, dl);
     return DAG.getNode(AArch64ISD::BRCOND, dl, MVT::Other, Chain, Dest, CCVal,
diff --git a/test/CodeGen/AArch64/combine-sign-comparisons-by-cse.ll b/test/CodeGen/AArch64/combine-sign-comparisons-by-cse.ll
new file mode 100644
index 0000000..aa74be9
--- /dev/null
+++ b/test/CodeGen/AArch64/combine-sign-comparisons-by-cse.ll
@@ -0,0 +1,39 @@
+; RUN: llc < %s -march=aarch64 -mtriple=aarch64-linux-gnu | FileCheck %s
+
+; marked as external to prevent possible optimizations
+ at a = external global i32
+ at b = external global i32
+ at c = external global i32
+ at d = external global i32
+
+define void @combine-sign-comparisons-by-cse() {
+; CHECK-LABEL: %lor.lhs.false
+; CHECK-NEXT: b.l
+entry:
+  %0 = load i32* @a, align 4
+  %cmp = icmp slt i32 %0, 0
+  br i1 %cmp, label %land.lhs.true, label %lor.lhs.false
+
+land.lhs.true:
+  %1 = load i32* @b, align 4
+  %2 = load i32* @c, align 4
+  %cmp1 = icmp eq i32 %1, %2
+  br i1 %cmp1, label %return, label %if.end
+
+lor.lhs.false:
+  %cmp2 = icmp sgt i32 %0, 0
+  br i1 %cmp2, label %land.lhs.true3, label %if.end
+
+land.lhs.true3:
+  %3 = load i32* @b, align 4
+  %4 = load i32* @d, align 4
+  %cmp4 = icmp eq i32 %3, %4
+  br i1 %cmp4, label %return, label %if.end
+
+if.end:
+  br label %return
+
+return:
+  %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ]
+  ret void
+}


More information about the llvm-commits mailing list