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 3d1235bac0a00ab86c3fb489a8074c8194b92d8b..a4b4d26a0a2d9c7620cd923cb9529163c2bd650d 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)
       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);
       std::swap(LHS, RHS);
-      CanPushNegateL = true;
-    }
   }
 
   // Emit RHS. If we want to negate the tree we only need to push a negate
   }
 
   // Emit RHS. If we want to negate the tree we only need to push a negate
index d8ad067a1bfa4e1d1bc3faab4c71e6f11f7cea2c..2f343abd2a55d4a4c8c8b83f6aff7411790e9393 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-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 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
 ; 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
 }
 
   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
 ; CHECK-LABEL: select_noccmp1
 define i64 @select_noccmp1(i64 %v1, i64 %v2, i64 %v3, i64 %r) {
 ; CHECK-NOT: CCMP