Index: lib/Target/SystemZ/SystemZISelLowering.cpp =================================================================== --- lib/Target/SystemZ/SystemZISelLowering.cpp +++ lib/Target/SystemZ/SystemZISelLowering.cpp @@ -5070,17 +5070,23 @@ // 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(N1.getOperand(1)); + SDValue AndOp = N1->getOperand(0); + SDValue AndMaskOp = N1->getOperand(1); + auto *AndMask = dyn_cast(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()) { @@ -5099,6 +5105,31 @@ 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; + } } } } Index: lib/Target/SystemZ/SystemZInstrInfo.td =================================================================== --- lib/Target/SystemZ/SystemZInstrInfo.td +++ lib/Target/SystemZ/SystemZInstrInfo.td @@ -1738,37 +1738,6 @@ 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; Index: test/CodeGen/SystemZ/shift-11.ll =================================================================== --- test/CodeGen/SystemZ/shift-11.ll +++ test/CodeGen/SystemZ/shift-11.ll @@ -61,3 +61,25 @@ %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 +}