[SystemZ] Optimize fcmp X, 0 in cases where X is also negated
authorRichard Sandiford <rsandifo@linux.vnet.ibm.com>
Wed, 11 Dec 2013 11:45:08 +0000 (11:45 +0000)
committerRichard Sandiford <rsandifo@linux.vnet.ibm.com>
Wed, 11 Dec 2013 11:45:08 +0000 (11:45 +0000)
In such cases it's often better to test the result of the negation instead,
since the negation also sets CC.

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

lib/Target/SystemZ/SystemZISelLowering.cpp
test/CodeGen/SystemZ/fp-cmp-04.ll

index b0a8fca7de7841d6a4b2bfd25d57eb8a5b8af7ea..84b5009fd79c4ce48f5359b93c8cb9c81589cb3f 100644 (file)
@@ -1252,6 +1252,34 @@ static bool shouldSwapCmpOperands(SDValue Op0, SDValue Op1,
   return false;
 }
 
+// Return a version of comparison CC mask CCMask in which the LT and GT
+// actions are swapped.
+static unsigned reverseCCMask(unsigned CCMask) {
+  return ((CCMask & SystemZ::CCMASK_CMP_EQ) |
+          (CCMask & SystemZ::CCMASK_CMP_GT ? SystemZ::CCMASK_CMP_LT : 0) |
+          (CCMask & SystemZ::CCMASK_CMP_LT ? SystemZ::CCMASK_CMP_GT : 0) |
+          (CCMask & SystemZ::CCMASK_CMP_UO));
+}
+
+// CmpOp0 and CmpOp1 are being compared using CC mask CCMask.  Check whether
+// CmpOp0 is a floating-point result that is also negated and if CmpOp1
+// is zero.  In this case we can use the negation to set CC, so avoiding
+// separate LOAD AND TEST and LOAD (NEGATIVE/COMPLEMENT) instructions.
+static void adjustForFNeg(SDValue &CmpOp0, SDValue &CmpOp1, unsigned &CCMask) {
+  ConstantFPSDNode *C1 = dyn_cast<ConstantFPSDNode>(CmpOp1);
+  if (C1 && C1->isZero()) {
+    for (SDNode::use_iterator I = CmpOp0->use_begin(), E = CmpOp0->use_end();
+         I != E; ++I) {
+      SDNode *N = *I;
+      if (N->getOpcode() == ISD::FNEG) {
+        CmpOp0 = SDValue(N, 0);
+        CCMask = reverseCCMask(CCMask);
+        return;
+      }
+    }
+  }
+}
+
 // Return true if shift operation N has an in-range constant shift value.
 // Store it in ShiftVal if so.
 static bool isSimpleShift(SDValue N, unsigned &ShiftVal) {
@@ -1463,14 +1491,12 @@ static SDValue emitCmp(const SystemZTargetMachine &TM, SelectionDAG &DAG,
 
   if (shouldSwapCmpOperands(CmpOp0, CmpOp1, ICmpType)) {
     std::swap(CmpOp0, CmpOp1);
-    CCMask = ((CCMask & SystemZ::CCMASK_CMP_EQ) |
-              (CCMask & SystemZ::CCMASK_CMP_GT ? SystemZ::CCMASK_CMP_LT : 0) |
-              (CCMask & SystemZ::CCMASK_CMP_LT ? SystemZ::CCMASK_CMP_GT : 0) |
-              (CCMask & SystemZ::CCMASK_CMP_UO));
+    CCMask = reverseCCMask(CCMask);
   }
 
   adjustForTestUnderMask(DAG, Opcode, CmpOp0, CmpOp1, CCValid, CCMask,
                          ICmpType);
+  adjustForFNeg(CmpOp0, CmpOp1, CCMask);
   if (Opcode == SystemZISD::ICMP || Opcode == SystemZISD::TM)
     return DAG.getNode(Opcode, DL, MVT::Glue, CmpOp0, CmpOp1,
                        DAG.getConstant(ICmpType, MVT::i32));
index 705a276563c35fdf02dd8e106271269e84ff596a..94f4b7cb3709ff8e967a46ba206c78df6c7bbd5f 100644 (file)
@@ -365,3 +365,43 @@ store:
 exit:
   ret float %res
 }
+
+; Test another form of f7 in which the condition is based on the unnegated
+; result.  This is what InstCombine would produce.
+define float @f18(float %dummy, float %a, float *%dest) {
+; CHECK-LABEL: f18:
+; CHECK: lnebr %f0, %f2
+; CHECK-NEXT: jl .L{{.*}}
+; CHECK: br %r14
+entry:
+  %abs = call float @llvm.fabs.f32(float %a)
+  %res = fsub float -0.0, %abs
+  %cmp = fcmp ogt float %abs, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store float %res, float *%dest
+  br label %exit
+
+exit:
+  ret float %res
+}
+
+; Similarly for f8.
+define float @f19(float %dummy, float %a, float *%dest) {
+; CHECK-LABEL: f19:
+; CHECK: lcebr %f0, %f2
+; CHECK-NEXT: jle .L{{.*}}
+; CHECK: br %r14
+entry:
+  %res = fsub float -0.0, %a
+  %cmp = fcmp oge float %a, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store float %res, float *%dest
+  br label %exit
+
+exit:
+  ret float %res
+}