[SystemZ] Use zeroing form of RISBG for some AND sequences

RISBG can handle some ANDs for which no AND IMMEDIATE exists.
It also acts as a three-operand AND for some cases where an
AND IMMEDIATE could be used instead.

It might be worth adding a pass to replace RISBG with AND IMMEDIATE
in cases where the register operands end up being the same and where
AND IMMEDIATE is smaller.

llvm-svn: 186072
diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index 0891adc..5b1b77b 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -200,6 +200,16 @@
                          Addr, Base, Disp, Index);
   }
 
+  // Return an undefined i64 value.
+  SDValue getUNDEF64(SDLoc DL);
+
+  // Convert N to VT, if it isn't already.
+  SDValue convertTo(SDLoc DL, EVT VT, SDValue N);
+
+  // Try to use RISBG to implement ISD::AND node N.  Return the selected
+  // node on success, otherwise return null.
+  SDNode *tryRISBGForAND(SDNode *N);
+
   // If Op0 is null, then Node is a constant that can be loaded using:
   //
   //   (Opcode UpperVal LowerVal)
@@ -521,6 +531,107 @@
   return true;
 }
 
+// Return true if Mask matches the regexp 0*1+0*, given that zero masks
+// have already been filtered out.  Store the first set bit in LSB and
+// the number of set bits in Length if so.
+static bool isStringOfOnes(uint64_t Mask, unsigned &LSB, unsigned &Length) {
+  unsigned First = findFirstSet(Mask);
+  uint64_t Top = (Mask >> First) + 1;
+  if ((Top & -Top) == Top)
+    {
+      LSB = First;
+      Length = findFirstSet(Top);
+      return true;
+    }
+  return false;
+}
+
+// Return a mask with Count low bits set.
+static uint64_t allOnes(unsigned int Count) {
+  return Count == 0 ? 0 : (uint64_t(1) << (Count - 1) << 1) - 1;
+}
+
+// Return true if RISBG can be used to extract the bits in Mask from
+// a value that has BitSize bits.  Store the start and end operands
+// (I3 and I4) in Start and End if so.
+static bool isRISBGMask(uint64_t Mask, unsigned BitSize, unsigned &Start,
+                        unsigned &End) {
+  // Reject trivial all-zero and all-one masks.
+  uint64_t Used = allOnes(BitSize);
+  if (Mask == 0 || Mask == Used)
+    return false;
+
+  // Handle the 1+0+ or 0+1+0* cases.  Start then specifies the index of
+  // the msb and End specifies the index of the lsb.
+  unsigned LSB, Length;
+  if (isStringOfOnes(Mask, LSB, Length))
+    {
+      Start = 63 - (LSB + Length - 1);
+      End = 63 - LSB;
+      return true;
+    }
+
+  // Handle the wrap-around 1+0+1+ cases.  Start then specifies the msb
+  // of the low 1s and End specifies the lsb of the high 1s.
+  if (isStringOfOnes(Mask ^ Used, LSB, Length))
+    {
+      assert(LSB > 0 && "Bottom bit must be set");
+      assert(LSB + Length < BitSize && "Top bit must be set");
+      Start = 63 - (LSB - 1);
+      End = 63 - (LSB + Length);
+      return true;
+    }
+
+  return false;
+}
+
+SDValue SystemZDAGToDAGISel::getUNDEF64(SDLoc DL) {
+  SDNode *N = CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, MVT::i64);
+  return SDValue(N, 0);
+}
+
+SDValue SystemZDAGToDAGISel::convertTo(SDLoc DL, EVT VT, SDValue N) {
+  if (N.getValueType() == MVT::i32 && VT == MVT::i64) {
+    SDValue Index = CurDAG->getTargetConstant(SystemZ::subreg_32bit, MVT::i64);
+    SDNode *Insert = CurDAG->getMachineNode(TargetOpcode::INSERT_SUBREG,
+                                            DL, VT, getUNDEF64(DL), N, Index);
+    return SDValue(Insert, 0);
+  }
+  if (N.getValueType() == MVT::i64 && VT == MVT::i32) {
+    SDValue Index = CurDAG->getTargetConstant(SystemZ::subreg_32bit, MVT::i64);
+    SDNode *Extract = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
+                                             DL, VT, N, Index);
+    return SDValue(Extract, 0);
+  }
+  assert(N.getValueType() == VT && "Unexpected value types");
+  return N;
+}
+
+SDNode *SystemZDAGToDAGISel::tryRISBGForAND(SDNode *N) {
+  EVT VT = N->getValueType(0);
+  unsigned BitSize = VT.getSizeInBits();
+  unsigned Start, End;
+  ConstantSDNode *MaskNode =
+    dyn_cast<ConstantSDNode>(N->getOperand(1).getNode());
+  if (!MaskNode
+      || !isRISBGMask(MaskNode->getZExtValue(), BitSize, Start, End))
+    return 0;
+
+  // Prefer register extensions like LLC over RSIBG.
+  if ((Start == 32 || Start == 48 || Start == 56) && End == 63)
+    return 0;
+
+  SDValue Ops[5] = {
+    getUNDEF64(SDLoc(N)),
+    convertTo(SDLoc(N), MVT::i64, N->getOperand(0)),
+    CurDAG->getTargetConstant(Start, MVT::i32),
+    CurDAG->getTargetConstant(End | 128, MVT::i32),
+    CurDAG->getTargetConstant(0, MVT::i32)
+  };
+  N = CurDAG->getMachineNode(SystemZ::RISBG, SDLoc(N), MVT::i64, Ops);
+  return convertTo(SDLoc(N), VT, SDValue(N, 0)).getNode();
+}
+
 SDNode *SystemZDAGToDAGISel::splitLargeImmediate(unsigned Opcode, SDNode *Node,
                                                  SDValue Op0, uint64_t UpperVal,
                                                  uint64_t LowerVal) {
@@ -590,6 +701,7 @@
   }
 
   unsigned Opcode = Node->getOpcode();
+  SDNode *ResNode = 0;
   switch (Opcode) {
   case ISD::OR:
   case ISD::XOR:
@@ -604,6 +716,10 @@
       }
     break;
 
+  case ISD::AND:
+    ResNode = tryRISBGForAND(Node);
+    break;
+
   case ISD::Constant:
     // If this is a 64-bit constant that is out of the range of LLILF,
     // LLIHF and LGFI, split it into two 32-bit pieces.
@@ -631,7 +747,8 @@
   }
 
   // Select the default instruction
-  SDNode *ResNode = SelectCode(Node);
+  if (!ResNode)
+    ResNode = SelectCode(Node);
 
   DEBUG(errs() << "=> ";
         if (ResNode == NULL || ResNode == Node)