[llvm] r279105 - Fix SystemZ compilation abort caused by negative AND mask

Elliot Colp via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 18 11:04:27 PDT 2016


Author: colpell
Date: Thu Aug 18 13:04:26 2016
New Revision: 279105

URL: http://llvm.org/viewvc/llvm-project?rev=279105&view=rev
Log:
Fix SystemZ compilation abort caused by negative AND mask

Normally, when an AND with a constant is lowered to NILL, the constant value is truncated to 16 bits. However, since r274066, ANDs whose results are used in a shift are caught by a different pattern that does not truncate. The instruction printer expects a 16-bit unsigned immediate operand for NILL, so this results in an abort.

This patch adds code to manually truncate the constant in this situation. The rest of the bits are then set, so we will detect a case for NILL "naturally" rather than using peephole optimizations.

Differential Revision: http://reviews.llvm.org/D21854

Modified:
    llvm/trunk/lib/Target/SystemZ/SystemZISelLowering.cpp
    llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.td
    llvm/trunk/test/CodeGen/SystemZ/shift-11.ll

Modified: llvm/trunk/lib/Target/SystemZ/SystemZISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/SystemZ/SystemZISelLowering.cpp?rev=279105&r1=279104&r2=279105&view=diff
==============================================================================
--- llvm/trunk/lib/Target/SystemZ/SystemZISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/SystemZ/SystemZISelLowering.cpp Thu Aug 18 13:04:26 2016
@@ -5093,17 +5093,23 @@ SDValue SystemZTargetLowering::combineSH
   // Shift/rotate instructions only use the last 6 bits of the second operand
   // register. If the second operand is the result of an AND with an immediate
   // value that has its last 6 bits set, we can safely remove the AND operation.
+  //
+  // If the AND operation doesn't have the last 6 bits set, we can't remove it
+  // entirely, but we can still truncate it to a 16-bit value with all other
+  // bits set. This will allow us to generate a NILL instead of a NILF for
+  // smaller code size.
   SDValue N1 = N->getOperand(1);
   if (N1.getOpcode() == ISD::AND) {
-    auto *AndMask = dyn_cast<ConstantSDNode>(N1.getOperand(1));
+    SDValue AndOp = N1->getOperand(0);
+    SDValue AndMaskOp = N1->getOperand(1);
+    auto *AndMask = dyn_cast<ConstantSDNode>(AndMaskOp);
 
     // The AND mask is constant
     if (AndMask) {
-      auto AmtVal = AndMask->getZExtValue();
+      uint64_t AmtVal = AndMask->getZExtValue();
 
       // Bottom 6 bits are set
       if ((AmtVal & 0x3f) == 0x3f) {
-        SDValue AndOp = N1->getOperand(0);
 
         // This is the only use, so remove the node
         if (N1.hasOneUse()) {
@@ -5121,6 +5127,31 @@ SDValue SystemZTargetLowering::combineSH
           DCI.AddToWorklist(Replace.getNode());
 
           return Replace;
+        }
+
+      // We can't remove the AND, but we can use NILL here instead of NILF if we
+      // truncate the mask to 16 bits and set the remaining bits
+      } else {
+        unsigned BitWidth = AndMask->getAPIntValue().getBitWidth();
+
+        // All bits for the operand's size except the lower 16
+        uint64_t UpperBits = ((1ull << (uint64_t)BitWidth) - 1ull) &
+                             0xffffffffffff0000ull;
+
+        if ((AmtVal & UpperBits) != UpperBits) {
+          auto NewMaskValue = (AmtVal & 0xffff) | UpperBits;
+
+          auto NewMask = DAG.getConstant(NewMaskValue,
+                                         SDLoc(AndMaskOp),
+                                         AndMaskOp.getValueType());
+          auto NewAnd = DAG.getNode(N1.getOpcode(), SDLoc(N1), N1.getValueType(),
+                                    AndOp, NewMask);
+          auto Replace = DAG.getNode(N->getOpcode(), SDLoc(N),
+                                     N->getValueType(0), N->getOperand(0),
+                                     NewAnd);
+          DCI.AddToWorklist(Replace.getNode());
+
+          return Replace;
         }
       }
     }

Modified: llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.td?rev=279105&r1=279104&r2=279105&view=diff
==============================================================================
--- llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.td (original)
+++ llvm/trunk/lib/Target/SystemZ/SystemZInstrInfo.td Thu Aug 18 13:04:26 2016
@@ -1834,37 +1834,6 @@ def : Pat<(sra (shl (i64 (anyext (i32 (z
 def : Pat<(and (xor GR64:$x, (i64 -1)), GR64:$y),
                           (XGR GR64:$y, (NGR GR64:$y, GR64:$x))>;
 
-// Shift/rotate instructions only use the last 6 bits of the second operand
-// register, so we can safely use NILL (16 fewer bits than NILF) to only AND the
-// last 16 bits.
-// Complexity is added so that we match this before we match NILF on the AND
-// operation alone.
-let AddedComplexity = 4 in {
-  def : Pat<(shl GR32:$val, (and GR32:$shift, uimm32:$imm)),
-            (SLL GR32:$val, (NILL GR32:$shift, uimm32:$imm), 0)>;
-
-  def : Pat<(sra GR32:$val, (and GR32:$shift, uimm32:$imm)),
-            (SRA GR32:$val, (NILL GR32:$shift, uimm32:$imm), 0)>;
-
-  def : Pat<(srl GR32:$val, (and GR32:$shift, uimm32:$imm)),
-            (SRL GR32:$val, (NILL GR32:$shift, uimm32:$imm), 0)>;
-
-  def : Pat<(shl GR64:$val, (and GR32:$shift, uimm32:$imm)),
-            (SLLG GR64:$val, (NILL GR32:$shift, uimm32:$imm), 0)>;
-
-  def : Pat<(sra GR64:$val, (and GR32:$shift, uimm32:$imm)),
-            (SRAG GR64:$val, (NILL GR32:$shift, uimm32:$imm), 0)>;
-
-  def : Pat<(srl GR64:$val, (and GR32:$shift, uimm32:$imm)),
-            (SRLG GR64:$val, (NILL GR32:$shift, uimm32:$imm), 0)>;
-
-  def : Pat<(rotl GR32:$val, (and GR32:$shift, uimm32:$imm)),
-            (RLL GR32:$val, (NILL GR32:$shift, uimm32:$imm), 0)>;
-
-  def : Pat<(rotl GR64:$val, (and GR32:$shift, uimm32:$imm)),
-            (RLLG GR64:$val, (NILL GR32:$shift, uimm32:$imm), 0)>;
-}
-
 // Peepholes for turning scalar operations into block operations.
 defm : BlockLoadStore<anyextloadi8, i32, MVCSequence, NCSequence, OCSequence,
                       XCSequence, 1>;

Modified: llvm/trunk/test/CodeGen/SystemZ/shift-11.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/SystemZ/shift-11.ll?rev=279105&r1=279104&r2=279105&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/SystemZ/shift-11.ll (original)
+++ llvm/trunk/test/CodeGen/SystemZ/shift-11.ll Thu Aug 18 13:04:26 2016
@@ -61,3 +61,25 @@ define i64 @f6(i64 %a, i64 %sh) {
   %shift = shl i64 %a, %and
   ret i64 %shift
 }
+
+; Test shift with negative 32-bit value.
+define i32 @f8(i32 %a, i32 %sh, i32 %test) {
+; CHECK-LABEL: f8:
+; CHECK: nill %r3, 65529
+; CHECK: sll %r2, 0(%r3)
+  %and = and i32 %sh, -7
+  %shift = shl i32 %a, %and
+
+  ret i32 %shift
+}
+
+; Test shift with negative 64-bit value.
+define i64 @f9(i64 %a, i64 %sh, i64 %test) {
+; CHECK-LABEL: f9:
+; CHECK: nill %r3, 65529
+; CHECK: sllg %r2, %r2, 0(%r3)
+  %and = and i64 %sh, -7
+  %shift = shl i64 %a, %and
+
+  ret i64 %shift
+}




More information about the llvm-commits mailing list