AArch64: Fix cmp;ccmp ordering
authorMatthias Braun <matze@braunis.de>
Thu, 20 Aug 2015 23:33:34 +0000 (23:33 +0000)
committerMatthias Braun <matze@braunis.de>
Thu, 20 Aug 2015 23:33:34 +0000 (23:33 +0000)
When producing conditional compare sequences for or operations we need
to negate the operands and the finally tested flags. The thing is if we negate
the finally tested flags this equals a logical negation of all previously
emitted expressions. There was a case missing where we have to order OR
expressions so they get emitted first.

This fixes http://llvm.org/PR24459

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@245641 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/AArch64/AArch64ISelLowering.cpp
test/CodeGen/AArch64/arm64-ccmp.ll

index 3d1235b..a4b4d26 100644 (file)
@@ -1374,10 +1374,17 @@ static SDValue emitConjunctionDisjunctionTree(SelectionDAG &DAG, SDValue Val,
     if (!CanPushNegateL && !CanPushNegateR)
       return SDValue();
     // Order the side where we can push the negate through to LHS.
-    if (!CanPushNegateL && CanPushNegateR) {
+    if (!CanPushNegateL && CanPushNegateR)
+      std::swap(LHS, RHS);
+  } else {
+    bool NeedsNegOutL = LHS->getOpcode() == ISD::OR;
+    bool NeedsNegOutR = RHS->getOpcode() == ISD::OR;
+    if (NeedsNegOutL && NeedsNegOutR)
+      return SDValue();
+    // Order the side where we need to negate the output flags to RHS so it
+    // gets emitted first.
+    if (NeedsNegOutL)
       std::swap(LHS, RHS);
-      CanPushNegateL = true;
-    }
   }
 
   // Emit RHS. If we want to negate the tree we only need to push a negate
index d8ad067..2f343ab 100644 (file)
@@ -337,9 +337,9 @@ define i16 @select_complicated(double %v1, double %v2, i16 %a, i16 %b) {
 
 ; CHECK-LABEL: gccbug
 define i64 @gccbug(i64 %x0, i64 %x1) {
-; CHECK: cmp x1, #0
-; CHECK-NEXT: ccmp x0, #2, #0, eq
+; CHECK: cmp x0, #2
 ; CHECK-NEXT: ccmp x0, #4, #4, ne
+; CHECK-NEXT: ccmp x1, #0, #0, eq
 ; CHECK-NEXT: orr w[[REGNUM:[0-9]+]], wzr, #0x1
 ; CHECK-NEXT: cinc x0, x[[REGNUM]], eq
 ; CHECK-NEXT: ret
@@ -373,6 +373,22 @@ define i32 @select_ororand(i32 %w0, i32 %w1, i32 %w2, i32 %w3) {
   ret i32 %sel
 }
 
+; CHECK-LABEL: select_andor
+define i32 @select_andor(i32 %v1, i32 %v2, i32 %v3) {
+; CHECK: cmp w1, w2
+; CHECK-NEXT: ccmp w0, #0, #4, lt
+; CHECK-NEXT: ccmp w0, w1, #0, eq
+; CHECK-NEXT: csel w0, w0, w1, eq
+; CHECK-NEXT: ret
+  %c0 = icmp eq i32 %v1, %v2
+  %c1 = icmp sge i32 %v2, %v3
+  %c2 = icmp eq i32 %v1, 0
+  %or = or i1 %c2, %c1
+  %and = and i1 %or, %c0
+  %sel = select i1 %and, i32 %v1, i32 %v2
+  ret i32 %sel
+}
+
 ; CHECK-LABEL: select_noccmp1
 define i64 @select_noccmp1(i64 %v1, i64 %v2, i64 %v3, i64 %r) {
 ; CHECK-NOT: CCMP