[llvm] r187883 - [SystemZ] Optimize floating-point comparisons with zero

Richard Sandiford rsandifo at linux.vnet.ibm.com
Wed Aug 7 04:10:06 PDT 2013


Author: rsandifo
Date: Wed Aug  7 06:10:06 2013
New Revision: 187883

URL: http://llvm.org/viewvc/llvm-project?rev=187883&view=rev
Log:
[SystemZ] Optimize floating-point comparisons with zero

This follows the same lines as the integer code.  In the end it seemed
easier to have a second 4-bit mask in TSFlags to specify the compare-like
CC values.  That eats one more TSFlags bit than adding a CCHasUnordered
would have done, but it feels more concise.

Added:
    llvm/trunk/test/CodeGen/SystemZ/fp-cmp-04.ll
Modified:
    llvm/trunk/lib/Target/SystemZ/SystemZElimCompare.cpp
    llvm/trunk/lib/Target/SystemZ/SystemZInstrFP.td
    llvm/trunk/lib/Target/SystemZ/SystemZInstrFormats.td
    llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.cpp
    llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.h
    llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.td

Modified: llvm/trunk/lib/Target/SystemZ/SystemZElimCompare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/SystemZ/SystemZElimCompare.cpp?rev=187883&r1=187882&r2=187883&view=diff
==============================================================================
--- llvm/trunk/lib/Target/SystemZ/SystemZElimCompare.cpp (original)
+++ llvm/trunk/lib/Target/SystemZ/SystemZElimCompare.cpp Wed Aug  7 06:10:06 2013
@@ -122,6 +122,12 @@ static bool resultTests(MachineInstr *MI
   case SystemZ::LTR:
   case SystemZ::LTGR:
   case SystemZ::LTGFR:
+  case SystemZ::LER:
+  case SystemZ::LDR:
+  case SystemZ::LXR:
+  case SystemZ::LTEBR:
+  case SystemZ::LTDBR:
+  case SystemZ::LTXBR:
     if (MI->getOperand(1).getReg() == Reg &&
         MI->getOperand(1).getSubReg() == SubReg)
       return true;
@@ -230,15 +236,12 @@ adjustCCMasksForInstr(MachineInstr *MI,
   unsigned MIFlags = Desc.TSFlags;
 
   // See which compare-style condition codes are available.
-  unsigned ReusableCCMask = 0;
-  if (MIFlags & SystemZII::CCHasZero)
-    ReusableCCMask |= SystemZ::CCMASK_CMP_EQ;
+  unsigned ReusableCCMask = SystemZII::getCompareZeroCCMask(MIFlags);
 
   // For unsigned comparisons with zero, only equality makes sense.
   unsigned CompareFlags = Compare->getDesc().TSFlags;
-  if (!(CompareFlags & SystemZII::IsLogical) &&
-      (MIFlags & SystemZII::CCHasOrder))
-    ReusableCCMask |= SystemZ::CCMASK_CMP_LT | SystemZ::CCMASK_CMP_GT;
+  if (CompareFlags & SystemZII::IsLogical)
+    ReusableCCMask &= SystemZ::CCMASK_CMP_EQ;
 
   if (ReusableCCMask == 0)
     return false;
@@ -297,6 +300,21 @@ adjustCCMasksForInstr(MachineInstr *MI,
   return true;
 }
 
+// Return true if Compare is a comparison against zero.
+static bool isCompareZero(MachineInstr *Compare) {
+  switch (Compare->getOpcode()) {
+  case SystemZ::LTEBRCompare:
+  case SystemZ::LTDBRCompare:
+  case SystemZ::LTXBRCompare:
+    return true;
+
+  default:
+    return (Compare->getNumExplicitOperands() == 2 &&
+            Compare->getOperand(1).isImm() &&
+            Compare->getOperand(1).getImm() == 0);
+  }
+}
+
 // Try to optimize cases where comparison instruction Compare is testing
 // a value against zero.  Return true on success and if Compare should be
 // deleted as dead.  CCUsers is the list of instructions that use the CC
@@ -304,10 +322,7 @@ adjustCCMasksForInstr(MachineInstr *MI,
 bool SystemZElimCompare::
 optimizeCompareZero(MachineInstr *Compare,
                     SmallVectorImpl<MachineInstr *> &CCUsers) {
-  // Check whether this is a comparison against zero.
-  if (Compare->getNumExplicitOperands() != 2 ||
-      !Compare->getOperand(1).isImm() ||
-      Compare->getOperand(1).getImm() != 0)
+  if (!isCompareZero(Compare))
     return false;
 
   // Search back for CC results that are based on the first operand.

Modified: llvm/trunk/lib/Target/SystemZ/SystemZInstrFP.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/SystemZ/SystemZInstrFP.td?rev=187883&r1=187882&r2=187883&view=diff
==============================================================================
--- llvm/trunk/lib/Target/SystemZ/SystemZInstrFP.td (original)
+++ llvm/trunk/lib/Target/SystemZ/SystemZInstrFP.td Wed Aug  7 06:10:06 2013
@@ -41,7 +41,7 @@ let neverHasSideEffects = 1 in {
 
 // Moves between two floating-point registers that also set the condition
 // codes.
-let Defs = [CC] in {
+let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in {
   defm LTEBR : LoadAndTestRRE<"lteb", 0xB302, FP32>;
   defm LTDBR : LoadAndTestRRE<"ltdb", 0xB312, FP64>;
   defm LTXBR : LoadAndTestRRE<"ltxb", 0xB342, FP128>;
@@ -149,15 +149,13 @@ def LXEB : UnaryRXE<"lxeb", 0xED06, extl
 def LXDB : UnaryRXE<"lxdb", 0xED05, extloadf64, FP128, 8>;
 
 // Convert a signed integer register value to a floating-point one.
-let Defs = [CC] in {
-  def CEFBR : UnaryRRE<"cefb", 0xB394, sint_to_fp, FP32,  GR32>;
-  def CDFBR : UnaryRRE<"cdfb", 0xB395, sint_to_fp, FP64,  GR32>;
-  def CXFBR : UnaryRRE<"cxfb", 0xB396, sint_to_fp, FP128, GR32>;
-
-  def CEGBR : UnaryRRE<"cegb", 0xB3A4, sint_to_fp, FP32,  GR64>;
-  def CDGBR : UnaryRRE<"cdgb", 0xB3A5, sint_to_fp, FP64,  GR64>;
-  def CXGBR : UnaryRRE<"cxgb", 0xB3A6, sint_to_fp, FP128, GR64>;
-}
+def CEFBR : UnaryRRE<"cefb", 0xB394, sint_to_fp, FP32,  GR32>;
+def CDFBR : UnaryRRE<"cdfb", 0xB395, sint_to_fp, FP64,  GR32>;
+def CXFBR : UnaryRRE<"cxfb", 0xB396, sint_to_fp, FP128, GR32>;
+
+def CEGBR : UnaryRRE<"cegb", 0xB3A4, sint_to_fp, FP32,  GR64>;
+def CDGBR : UnaryRRE<"cdgb", 0xB3A5, sint_to_fp, FP64,  GR64>;
+def CXGBR : UnaryRRE<"cxgb", 0xB3A6, sint_to_fp, FP128, GR64>;
 
 // Convert a floating-point register value to a signed integer value,
 // with the second operand (modifier M3) specifying the rounding mode.
@@ -185,21 +183,21 @@ def : Pat<(i64 (fp_to_sint FP128:$src)),
 //===----------------------------------------------------------------------===//
 
 // Negation (Load Complement).
-let Defs = [CC] in {
+let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in {
   def LCEBR : UnaryRRE<"lceb", 0xB303, fneg, FP32,  FP32>;
   def LCDBR : UnaryRRE<"lcdb", 0xB313, fneg, FP64,  FP64>;
   def LCXBR : UnaryRRE<"lcxb", 0xB343, fneg, FP128, FP128>;
 }
 
 // Absolute value (Load Positive).
-let Defs = [CC] in {
+let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in {
   def LPEBR : UnaryRRE<"lpeb", 0xB300, fabs, FP32,  FP32>;
   def LPDBR : UnaryRRE<"lpdb", 0xB310, fabs, FP64,  FP64>;
   def LPXBR : UnaryRRE<"lpxb", 0xB340, fabs, FP128, FP128>;
 }
 
 // Negative absolute value (Load Negative).
-let Defs = [CC] in {
+let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in {
   def LNEBR : UnaryRRE<"lneb", 0xB301, fnabs, FP32,  FP32>;
   def LNDBR : UnaryRRE<"lndb", 0xB311, fnabs, FP64,  FP64>;
   def LNXBR : UnaryRRE<"lnxb", 0xB341, fnabs, FP128, FP128>;
@@ -219,11 +217,9 @@ def SQDB : UnaryRXE<"sqdb", 0xED15, load
 // These forms always check for inexact conditions.  z196 added versions
 // that allow this to suppressed (as for fnearbyint), but we don't yet
 // support -march=z196.
-let Defs = [CC] in {
-  def FIEBR : UnaryRRF<"fieb", 0xB357, FP32,  FP32>;
-  def FIDBR : UnaryRRF<"fidb", 0xB35F, FP64,  FP64>;
-  def FIXBR : UnaryRRF<"fixb", 0xB347, FP128, FP128>;
-}
+def FIEBR : UnaryRRF<"fieb", 0xB357, FP32,  FP32>;
+def FIDBR : UnaryRRF<"fidb", 0xB35F, FP64,  FP64>;
+def FIXBR : UnaryRRF<"fixb", 0xB347, FP128, FP128>;
 
 // frint rounds according to the current mode (modifier 0) and detects
 // inexact conditions.
@@ -236,7 +232,7 @@ def : Pat<(frint FP128:$src), (FIXBR 0,
 //===----------------------------------------------------------------------===//
 
 // Addition.
-let Defs = [CC] in {
+let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in {
   let isCommutable = 1 in {
     def AEBR : BinaryRRE<"aeb", 0xB30A, fadd, FP32,  FP32>;
     def ADBR : BinaryRRE<"adb", 0xB31A, fadd, FP64,  FP64>;
@@ -247,7 +243,7 @@ let Defs = [CC] in {
 }
 
 // Subtraction.
-let Defs = [CC] in {
+let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in {
   def SEBR : BinaryRRE<"seb", 0xB30B, fsub, FP32,  FP32>;
   def SDBR : BinaryRRE<"sdb", 0xB31B, fsub, FP64,  FP64>;
   def SXBR : BinaryRRE<"sxb", 0xB34B, fsub, FP128, FP128>;
@@ -317,7 +313,7 @@ def DDB : BinaryRXE<"ddb", 0xED1D, fdiv,
 // Comparisons
 //===----------------------------------------------------------------------===//
 
-let Defs = [CC] in {
+let Defs = [CC], CCValues = 0xF in {
   def CEBR : CompareRRE<"ceb", 0xB309, z_cmp, FP32,  FP32>;
   def CDBR : CompareRRE<"cdb", 0xB319, z_cmp, FP64,  FP64>;
   def CXBR : CompareRRE<"cxb", 0xB349, z_cmp, FP128, FP128>;

Modified: llvm/trunk/lib/Target/SystemZ/SystemZInstrFormats.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/SystemZ/SystemZInstrFormats.td?rev=187883&r1=187882&r2=187883&view=diff
==============================================================================
--- llvm/trunk/lib/Target/SystemZ/SystemZInstrFormats.td (original)
+++ llvm/trunk/lib/Target/SystemZ/SystemZInstrFormats.td Wed Aug  7 06:10:06 2013
@@ -66,12 +66,9 @@ class InstSystemZ<int size, dag outs, da
   // SystemZ::CCMASK_*.
   bits<4> CCValues = 0;
 
-  // True if the instruction sets CC to 0 when the result is 0.
-  bit CCHasZero = 0;
-
-  // True if the instruction sets CC to 1 when the result is less than 0
-  // and to 2 when the result is greater than 0.
-  bit CCHasOrder = 0;
+  // The subset of CCValues that have the same meaning as they would after
+  // a comparison of the first operand against zero.
+  bits<4> CompareZeroCCMask = 0;
 
   // True if the instruction is conditional and if the CC mask operand
   // comes first (as for BRC, etc.).
@@ -91,11 +88,10 @@ class InstSystemZ<int size, dag outs, da
   let TSFlags{4}     = Is128Bit;
   let TSFlags{9-5}   = AccessBytes;
   let TSFlags{13-10} = CCValues;
-  let TSFlags{14}    = CCHasZero;
-  let TSFlags{15}    = CCHasOrder;
-  let TSFlags{16}    = CCMaskFirst;
-  let TSFlags{17}    = CCMaskLast;
-  let TSFlags{18}    = IsLogical;
+  let TSFlags{17-14} = CompareZeroCCMask;
+  let TSFlags{18}    = CCMaskFirst;
+  let TSFlags{19}    = CCMaskLast;
+  let TSFlags{20}    = IsLogical;
 }
 
 //===----------------------------------------------------------------------===//

Modified: llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.cpp?rev=187883&r1=187882&r2=187883&view=diff
==============================================================================
--- llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.cpp (original)
+++ llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.cpp Wed Aug  7 06:10:06 2013
@@ -770,6 +770,9 @@ unsigned SystemZInstrInfo::getLoadAndTes
   case SystemZ::LR:   return SystemZ::LTR;
   case SystemZ::LGFR: return SystemZ::LTGFR;
   case SystemZ::LGR:  return SystemZ::LTGR;
+  case SystemZ::LER:  return SystemZ::LTEBR;
+  case SystemZ::LDR:  return SystemZ::LTDBR;
+  case SystemZ::LXR:  return SystemZ::LTXBR;
   default:            return 0;
   }
 }

Modified: llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.h?rev=187883&r1=187882&r2=187883&view=diff
==============================================================================
--- llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.h (original)
+++ llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.h Wed Aug  7 06:10:06 2013
@@ -28,20 +28,20 @@ class SystemZTargetMachine;
 namespace SystemZII {
   enum {
     // See comments in SystemZInstrFormats.td.
-    SimpleBDXLoad   = (1 << 0),
-    SimpleBDXStore  = (1 << 1),
-    Has20BitOffset  = (1 << 2),
-    HasIndex        = (1 << 3),
-    Is128Bit        = (1 << 4),
-    AccessSizeMask  = (31 << 5),
-    AccessSizeShift = 5,
-    CCValuesMask    = (15 << 10),
-    CCValuesShift   = 10,
-    CCHasZero       = (1 << 14),
-    CCHasOrder      = (1 << 15),
-    CCMaskFirst     = (1 << 16),
-    CCMaskLast      = (1 << 17),
-    IsLogical       = (1 << 18)
+    SimpleBDXLoad          = (1 << 0),
+    SimpleBDXStore         = (1 << 1),
+    Has20BitOffset         = (1 << 2),
+    HasIndex               = (1 << 3),
+    Is128Bit               = (1 << 4),
+    AccessSizeMask         = (31 << 5),
+    AccessSizeShift        = 5,
+    CCValuesMask           = (15 << 10),
+    CCValuesShift          = 10,
+    CompareZeroCCMaskMask  = (15 << 14),
+    CompareZeroCCMaskShift = 14,
+    CCMaskFirst            = (1 << 18),
+    CCMaskLast             = (1 << 19),
+    IsLogical              = (1 << 20)
   };
   static inline unsigned getAccessSize(unsigned int Flags) {
     return (Flags & AccessSizeMask) >> AccessSizeShift;
@@ -49,6 +49,9 @@ namespace SystemZII {
   static inline unsigned getCCValues(unsigned int Flags) {
     return (Flags & CCValuesMask) >> CCValuesShift;
   }
+  static inline unsigned getCompareZeroCCMask(unsigned int Flags) {
+    return (Flags & CompareZeroCCMaskMask) >> CompareZeroCCMaskShift;
+  }
 
   // SystemZ MachineOperand target flags.
   enum {

Modified: llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.td?rev=187883&r1=187882&r2=187883&view=diff
==============================================================================
--- llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.td (original)
+++ llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.td Wed Aug  7 06:10:06 2013
@@ -230,7 +230,7 @@ let neverHasSideEffects = 1 in {
   def LR  : UnaryRR <"l",  0x18,   null_frag, GR32, GR32>;
   def LGR : UnaryRRE<"lg", 0xB904, null_frag, GR64, GR64>;
 }
-let Defs = [CC], CCValues = 0xE, CCHasZero = 1, CCHasOrder = 1 in {
+let Defs = [CC], CCValues = 0xE, CompareZeroCCMask = 0xE in {
   def LTR  : UnaryRR <"lt",  0x12,   null_frag, GR32, GR32>;
   def LTGR : UnaryRRE<"ltg", 0xB902, null_frag, GR64, GR64>;
 }
@@ -276,7 +276,7 @@ let canFoldAsLoad = 1, SimpleBDXLoad = 1
                       [(set GR128:$dst, (load bdxaddr20only128:$src))]>;
   }
 }
-let Defs = [CC], CCValues = 0xE, CCHasZero = 1, CCHasOrder = 1 in {
+let Defs = [CC], CCValues = 0xE, CompareZeroCCMask = 0xE in {
   def LT  : UnaryRXY<"lt",  0xE312, load, GR32, 4>;
   def LTG : UnaryRXY<"ltg", 0xE302, load, GR64, 8>;
 }
@@ -374,7 +374,7 @@ let neverHasSideEffects = 1 in {
   def LGHR : UnaryRRE<"lgh", 0xB907, sext16, GR64, GR64>;
   def LGFR : UnaryRRE<"lgf", 0xB914, sext32, GR64, GR32>;
 }
-let Defs = [CC], CCValues = 0xE, CCHasZero = 1, CCHasOrder = 1 in
+let Defs = [CC], CCValues = 0xE, CompareZeroCCMask = 0xE in
   def LTGFR : UnaryRRE<"ltgf", 0xB912, null_frag, GR64, GR64>;
 
 // Match 32-to-64-bit sign extensions in which the source is already
@@ -393,7 +393,7 @@ def LGH   : UnaryRXY<"lgh", 0xE315, sext
 def LGF   : UnaryRXY<"lgf", 0xE314, sextloadi32, GR64, 4>;
 def LGHRL : UnaryRILPC<"lghrl", 0xC44, aligned_sextloadi16, GR64>;
 def LGFRL : UnaryRILPC<"lgfrl", 0xC4C, aligned_sextloadi32, GR64>;
-let Defs = [CC], CCValues = 0xE, CCHasZero = 1, CCHasOrder = 1 in
+let Defs = [CC], CCValues = 0xE, CompareZeroCCMask = 0xE in
   def LTGF : UnaryRXY<"ltgf", 0xE332, sextloadi32, GR64, 4>;
 
 // If the sign of a load-extend operation doesn't matter, use the signed ones.
@@ -532,11 +532,11 @@ let neverHasSideEffects = 1, isAsCheapAs
 //===----------------------------------------------------------------------===//
 
 let Defs = [CC] in {
-  let CCValues = 0xF, CCHasZero = 1 in {
+  let CCValues = 0xF, CompareZeroCCMask = 0x8 in {
     def LCR  : UnaryRR <"lc",  0x13,   ineg, GR32, GR32>;
     def LCGR : UnaryRRE<"lcg", 0xB903, ineg, GR64, GR64>;
   }
-  let CCValues = 0xE, CCHasZero = 1, CCHasOrder = 1 in
+  let CCValues = 0xE, CompareZeroCCMask = 0xE in
     def LCGFR : UnaryRRE<"lcgf", 0xB913, null_frag, GR64, GR32>;
 }
 defm : SXU<ineg, LCGFR>;
@@ -589,7 +589,7 @@ def : Pat<(or (zext32 GR32:$src), imm64h
 //===----------------------------------------------------------------------===//
 
 // Plain addition.
-let Defs = [CC], CCValues = 0xF, CCHasZero = 1 in {
+let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0x8 in {
   // Addition of a register.
   let isCommutable = 1 in {
     defm AR : BinaryRRAndK<"a", 0x1A, 0xB9F8, add, GR32, GR32>;
@@ -660,7 +660,7 @@ let Defs = [CC], Uses = [CC] in {
 
 // Plain substraction.  Although immediate forms exist, we use the
 // add-immediate instruction instead.
-let Defs = [CC], CCValues = 0xF, CCHasZero = 1 in {
+let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0x8 in {
   // Subtraction of a register.
   defm SR : BinaryRRAndK<"s", 0x1B, 0xB9F9, sub, GR32, GR32>;
   def SGFR : BinaryRRE<"sgf", 0xB919, null_frag, GR64, GR32>;
@@ -710,7 +710,7 @@ let Defs = [CC], Uses = [CC] in {
 
 let Defs = [CC] in {
   // ANDs of a register.
-  let isCommutable = 1, CCValues = 0xC, CCHasZero = 1 in {
+  let isCommutable = 1, CCValues = 0xC, CompareZeroCCMask = 0x8 in {
     defm NR : BinaryRRAndK<"n", 0x14, 0xB9F4, and, GR32, GR32>;
     defm NGR : BinaryRREAndK<"ng", 0xB980, 0xB9E4, and, GR64, GR64>;
   }
@@ -730,14 +730,14 @@ let Defs = [CC] in {
     // ANDs of a 32-bit immediate, leaving other bits unaffected.
     // The CC result only reflects the 32-bit field, which means we can
     // use it as a zero indicator for i32 operations but not otherwise.
-    let isCodeGenOnly = 1, CCValues = 0xC, CCHasZero = 1 in
+    let isCodeGenOnly = 1, CCValues = 0xC, CompareZeroCCMask = 0x8 in
       def NILF32 : BinaryRIL<"nilf", 0xC0B, and, GR32, uimm32>;
     def NILF : BinaryRIL<"nilf", 0xC0B, and, GR64, imm64lf32c>;
     def NIHF : BinaryRIL<"nihf", 0xC0A, and, GR64, imm64hf32c>;
   }
 
   // ANDs of memory.
-  let CCValues = 0xC, CCHasZero = 1 in {
+  let CCValues = 0xC, CompareZeroCCMask = 0x8 in {
     defm N  : BinaryRXPair<"n", 0x54, 0xE354, and, GR32, load, 4>;
     def  NG : BinaryRXY<"ng", 0xE380, and, GR64, load, 8>; 
   }
@@ -754,7 +754,7 @@ defm : RMWIByte<and, bdaddr20pair, NIY>;
 
 let Defs = [CC] in {
   // ORs of a register.
-  let isCommutable = 1, CCValues = 0xC, CCHasZero = 1 in {
+  let isCommutable = 1, CCValues = 0xC, CompareZeroCCMask = 0x8 in {
     defm OR : BinaryRRAndK<"o", 0x16, 0xB9F6, or, GR32, GR32>;
     defm OGR : BinaryRREAndK<"og", 0xB981, 0xB9E6, or, GR64, GR64>;
   }
@@ -773,13 +773,13 @@ let Defs = [CC] in {
   // ORs of a 32-bit immediate, leaving other bits unaffected.
   // The CC result only reflects the 32-bit field, which means we can
   // use it as a zero indicator for i32 operations but not otherwise.
-  let isCodeGenOnly = 1, CCValues = 0xC, CCHasZero = 1 in
+  let isCodeGenOnly = 1, CCValues = 0xC, CompareZeroCCMask = 0x8 in
     def OILF32 : BinaryRIL<"oilf", 0xC0D, or, GR32, uimm32>;
   def OILF : BinaryRIL<"oilf", 0xC0D, or, GR64, imm64lf32>;
   def OIHF : BinaryRIL<"oihf", 0xC0C, or, GR64, imm64hf32>;
 
   // ORs of memory.
-  let CCValues = 0xC, CCHasZero = 1 in {
+  let CCValues = 0xC, CompareZeroCCMask = 0x8 in {
     defm O  : BinaryRXPair<"o", 0x56, 0xE356, or, GR32, load, 4>;
     def  OG : BinaryRXY<"og", 0xE381, or, GR64, load, 8>;
   }
@@ -796,7 +796,7 @@ defm : RMWIByte<or, bdaddr20pair, OIY>;
 
 let Defs = [CC] in {
   // XORs of a register.
-  let isCommutable = 1, CCValues = 0xC, CCHasZero = 1 in {
+  let isCommutable = 1, CCValues = 0xC, CompareZeroCCMask = 0x8 in {
     defm XR : BinaryRRAndK<"x", 0x17, 0xB9F7, xor, GR32, GR32>;
     defm XGR : BinaryRREAndK<"xg", 0xB982, 0xB9E7, xor, GR64, GR64>;
   }
@@ -804,13 +804,13 @@ let Defs = [CC] in {
   // XORs of a 32-bit immediate, leaving other bits unaffected.
   // The CC result only reflects the 32-bit field, which means we can
   // use it as a zero indicator for i32 operations but not otherwise.
-  let isCodeGenOnly = 1, CCValues = 0xC, CCHasZero = 1 in
+  let isCodeGenOnly = 1, CCValues = 0xC, CompareZeroCCMask = 0x8 in
     def XILF32 : BinaryRIL<"xilf", 0xC07, xor, GR32, uimm32>;
   def XILF : BinaryRIL<"xilf", 0xC07, xor, GR64, imm64lf32>;
   def XIHF : BinaryRIL<"xihf", 0xC06, xor, GR64, imm64hf32>;
 
   // XORs of memory.
-  let CCValues = 0xC, CCHasZero = 1 in {
+  let CCValues = 0xC, CompareZeroCCMask = 0x8 in {
     defm X  : BinaryRXPair<"x",0x57, 0xE357, xor, GR32, load, 4>;
     def  XG : BinaryRXY<"xg", 0xE382, xor, GR64, load, 8>;
   }
@@ -886,7 +886,7 @@ let neverHasSideEffects = 1 in {
 }
 
 // Arithmetic shift right.
-let Defs = [CC], CCValues = 0xE, CCHasZero = 1, CCHasOrder = 1 in {
+let Defs = [CC], CCValues = 0xE, CompareZeroCCMask = 0xE in {
   defm SRA : ShiftRSAndK<"sra", 0x8A, 0xEBDC, sra, GR32>;
   def SRAG : ShiftRSY<"srag", 0xEB0A, sra, GR64>;
 }
@@ -903,7 +903,7 @@ let neverHasSideEffects = 1 in {
 let Defs = [CC] in {
   let isCodeGenOnly = 1 in
     def RISBG32 : RotateSelectRIEf<"risbg", 0xEC55, GR32, GR32>;
-  let CCValues = 0xE, CCHasZero = 1, CCHasOrder = 1 in
+  let CCValues = 0xE, CompareZeroCCMask = 0xE in
     def RISBG : RotateSelectRIEf<"risbg", 0xEC55, GR64, GR64>;
 }
 

Added: llvm/trunk/test/CodeGen/SystemZ/fp-cmp-04.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/SystemZ/fp-cmp-04.ll?rev=187883&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/SystemZ/fp-cmp-04.ll (added)
+++ llvm/trunk/test/CodeGen/SystemZ/fp-cmp-04.ll Wed Aug  7 06:10:06 2013
@@ -0,0 +1,348 @@
+; Test that floating-point compares are ommitted if CC already has the
+; right value.
+;
+; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 | FileCheck %s
+
+declare float @llvm.fabs.f32(float %f)
+
+; Test addition followed by EQ, which can use the CC result of the addition.
+define float @f1(float %a, float %b, float *%dest) {
+; CHECK-LABEL: f1:
+; CHECK: aebr %f0, %f2
+; CHECK-NEXT: je .L{{.*}}
+; CHECK: br %r14
+entry:
+  %res = fadd float %a, %b
+  %cmp = fcmp oeq float %res, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store float %b, float *%dest
+  br label %exit
+
+exit:
+  ret float %res
+}
+
+; ...and again with LT.
+define float @f2(float %a, float %b, float *%dest) {
+; CHECK-LABEL: f2:
+; CHECK: aebr %f0, %f2
+; CHECK-NEXT: jl .L{{.*}}
+; CHECK: br %r14
+entry:
+  %res = fadd float %a, %b
+  %cmp = fcmp olt float %res, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store float %b, float *%dest
+  br label %exit
+
+exit:
+  ret float %res
+}
+
+; ...and again with GT.
+define float @f3(float %a, float %b, float *%dest) {
+; CHECK-LABEL: f3:
+; CHECK: aebr %f0, %f2
+; CHECK-NEXT: jh .L{{.*}}
+; CHECK: br %r14
+entry:
+  %res = fadd float %a, %b
+  %cmp = fcmp ogt float %res, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store float %b, float *%dest
+  br label %exit
+
+exit:
+  ret float %res
+}
+
+; ...and again with UEQ.
+define float @f4(float %a, float %b, float *%dest) {
+; CHECK-LABEL: f4:
+; CHECK: aebr %f0, %f2
+; CHECK-NEXT: jnlh .L{{.*}}
+; CHECK: br %r14
+entry:
+  %res = fadd float %a, %b
+  %cmp = fcmp ueq float %res, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store float %b, float *%dest
+  br label %exit
+
+exit:
+  ret float %res
+}
+
+; Subtraction also provides a zero-based CC value.
+define float @f5(float %a, float %b, float *%dest) {
+; CHECK-LABEL: f5:
+; CHECK: seb %f0, 0(%r2)
+; CHECK-NEXT: jnhe .L{{.*}}
+; CHECK: br %r14
+entry:
+  %cur = load float *%dest
+  %res = fsub float %a, %cur
+  %cmp = fcmp ult float %res, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store float %b, float *%dest
+  br label %exit
+
+exit:
+  ret float %res
+}
+
+; Test the result of LOAD POSITIVE.
+define float @f6(float %dummy, float %a, float *%dest) {
+; CHECK-LABEL: f6:
+; CHECK: lpebr %f0, %f2
+; CHECK-NEXT: jh .L{{.*}}
+; CHECK: br %r14
+entry:
+  %res = call float @llvm.fabs.f32(float %a)
+  %cmp = fcmp ogt float %res, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store float %res, float *%dest
+  br label %exit
+
+exit:
+  ret float %res
+}
+
+; Test the result of LOAD NEGATIVE.
+define float @f7(float %dummy, float %a, float *%dest) {
+; CHECK-LABEL: f7:
+; 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 olt float %res, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store float %res, float *%dest
+  br label %exit
+
+exit:
+  ret float %res
+}
+
+; Test the result of LOAD COMPLEMENT.
+define float @f8(float %dummy, float %a, float *%dest) {
+; CHECK-LABEL: f8:
+; CHECK: lcebr %f0, %f2
+; CHECK-NEXT: jle .L{{.*}}
+; CHECK: br %r14
+entry:
+  %res = fsub float -0.0, %a
+  %cmp = fcmp ole float %res, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store float %res, float *%dest
+  br label %exit
+
+exit:
+  ret float %res
+}
+
+; Multiplication (for example) does not modify CC.
+define float @f9(float %a, float %b, float *%dest) {
+; CHECK-LABEL: f9:
+; CHECK: meebr %f0, %f2
+; CHECK-NEXT: ltebr %f0, %f0
+; CHECK-NEXT: jlh .L{{.*}}
+; CHECK: br %r14
+entry:
+  %res = fmul float %a, %b
+  %cmp = fcmp one float %res, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store float %b, float *%dest
+  br label %exit
+
+exit:
+  ret float %res
+}
+
+; Test a combination involving a CC-setting instruction followed by
+; a non-CC-setting instruction.
+define float @f10(float %a, float %b, float %c, float *%dest) {
+; CHECK-LABEL: f10:
+; CHECK: aebr %f0, %f2
+; CHECK-NEXT: debr %f0, %f4
+; CHECK-NEXT: ltebr %f0, %f0
+; CHECK-NEXT: jne .L{{.*}}
+; CHECK: br %r14
+entry:
+  %add = fadd float %a, %b
+  %res = fdiv float %add, %c
+  %cmp = fcmp une float %res, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store float %b, float *%dest
+  br label %exit
+
+exit:
+  ret float %res
+}
+
+; Test a case where CC is set based on a different register from the
+; compare input.
+define float @f11(float %a, float %b, float %c, float *%dest1, float *%dest2) {
+; CHECK-LABEL: f11:
+; CHECK: aebr %f0, %f2
+; CHECK-NEXT: sebr %f4, %f0
+; CHECK-NEXT: ste %f4, 0(%r2)
+; CHECK-NEXT: ltebr %f0, %f0
+; CHECK-NEXT: je .L{{.*}}
+; CHECK: br %r14
+entry:
+  %add = fadd float %a, %b
+  %sub = fsub float %c, %add
+  store float %sub, float *%dest1
+  %cmp = fcmp oeq float %add, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store float %sub, float *%dest2
+  br label %exit
+
+exit:
+  ret float %add
+}
+
+; Test that LER gets converted to LTEBR where useful.
+define float @f12(float %dummy, float %val, float *%dest) {
+; CHECK-LABEL: f12:
+; CHECK: ltebr %f0, %f2
+; CHECK-NEXT: #APP
+; CHECK-NEXT: blah %f0
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: jl .L{{.*}}
+; CHECK: br %r14
+entry:
+  call void asm sideeffect "blah $0", "{f0}"(float %val)
+  %cmp = fcmp olt float %val, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store float %val, float *%dest
+  br label %exit
+
+exit:
+  ret float %val
+}
+
+; Test that LDR gets converted to LTDBR where useful.
+define double @f13(double %dummy, double %val, double *%dest) {
+; CHECK-LABEL: f13:
+; CHECK: ltdbr %f0, %f2
+; CHECK-NEXT: #APP
+; CHECK-NEXT: blah %f0
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: jl .L{{.*}}
+; CHECK: br %r14
+entry:
+  call void asm sideeffect "blah $0", "{f0}"(double %val)
+  %cmp = fcmp olt double %val, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store double %val, double *%dest
+  br label %exit
+
+exit:
+  ret double %val
+}
+
+; Test that LXR gets converted to LTXBR where useful.
+define void @f14(fp128 *%ptr1, fp128 *%ptr2) {
+; CHECK-LABEL: f14:
+; CHECK: ltxbr
+; CHECK-NEXT: dxbr
+; CHECK-NEXT: std
+; CHECK-NEXT: std
+; CHECK-NEXT: mxbr
+; CHECK-NEXT: std
+; CHECK-NEXT: std
+; CHECK-NEXT: jl .L{{.*}}
+; CHECK: br %r14
+entry:
+  %val1 = load fp128 *%ptr1
+  %val2 = load fp128 *%ptr2
+  %div = fdiv fp128 %val1, %val2
+  store fp128 %div, fp128 *%ptr1
+  %mul = fmul fp128 %val1, %val2
+  store fp128 %mul, fp128 *%ptr2
+  %cmp = fcmp olt fp128 %val1, 0xL00000000000000000000000000000000
+  br i1 %cmp, label %exit, label %store
+
+store:
+  call void asm sideeffect "blah", ""()
+  br label %exit
+
+exit:
+  ret void
+}
+
+; Test a case where it is the source rather than destination of LER that
+; we need.
+define float @f15(float %val, float %dummy, float *%dest) {
+; CHECK-LABEL: f15:
+; CHECK: ltebr %f2, %f0
+; CHECK-NEXT: #APP
+; CHECK-NEXT: blah %f2
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: jl .L{{.*}}
+; CHECK: br %r14
+entry:
+  call void asm sideeffect "blah $0", "{f2}"(float %val)
+  %cmp = fcmp olt float %val, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store float %val, float *%dest
+  br label %exit
+
+exit:
+  ret float %val
+}
+
+; Test a case where it is the source rather than destination of LDR that
+; we need.
+define double @f16(double %val, double %dummy, double *%dest) {
+; CHECK-LABEL: f16:
+; CHECK: ltdbr %f2, %f0
+; CHECK-NEXT: #APP
+; CHECK-NEXT: blah %f2
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: jl .L{{.*}}
+; CHECK: br %r14
+entry:
+  call void asm sideeffect "blah $0", "{f2}"(double %val)
+  %cmp = fcmp olt double %val, 0.0
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store double %val, double *%dest
+  br label %exit
+
+exit:
+  ret double %val
+}





More information about the llvm-commits mailing list