diff --git a/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp index 67e9d217ee3..0f9a37ed0cf 100644 --- a/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp +++ b/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp @@ -647,9 +647,29 @@ static bool refineRxSBGMask(RxSBGOperands &RxSBG, uint64_t Mask) { return false; } +// RxSBG.Input is a shift of Count bits in the direction given by IsLeft. +// Return true if the result depends on the signs or zeros that are +// shifted in. +static bool shiftedInBitsMatter(RxSBGOperands &RxSBG, uint64_t Count, + bool IsLeft) { + // Work out which bits of the shift result are zeros or sign copies. + uint64_t ShiftedIn = allOnes(Count); + if (!IsLeft) + ShiftedIn <<= RxSBG.BitSize - Count; + + // Rotate that mask in the same way as RxSBG.Input is rotated. + if (RxSBG.Rotate != 0) + ShiftedIn = ((ShiftedIn << RxSBG.Rotate) | + (ShiftedIn >> (64 - RxSBG.Rotate))); + + // Fail if any of the zero or sign bits are used. + return (ShiftedIn & RxSBG.Mask) != 0; +} + bool SystemZDAGToDAGISel::expandRxSBG(RxSBGOperands &RxSBG) { SDValue N = RxSBG.Input; - switch (N.getOpcode()) { + unsigned Opcode = N.getOpcode(); + switch (Opcode) { case ISD::AND: { ConstantSDNode *MaskNode = dyn_cast(N.getOperand(1).getNode()); @@ -704,44 +724,33 @@ bool SystemZDAGToDAGISel::expandRxSBG(RxSBGOperands &RxSBG) { return true; } - case ISD::SRL: { - // Treat (srl X, count), mask) as (and (rotl X, size-count), ~0>>count), - // which is similar to SLL above. + case ISD::SRL: + case ISD::SRA: { ConstantSDNode *CountNode = dyn_cast(N.getOperand(1).getNode()); if (!CountNode) return false; uint64_t Count = CountNode->getZExtValue(); - if (Count < 1 || - Count >= RxSBG.BitSize || - !refineRxSBGMask(RxSBG, allOnes(RxSBG.BitSize - Count))) + if (Count < 1 || Count >= RxSBG.BitSize) return false; + if (Opcode == ISD::SRA) { + // Treat (sra X, count) as (rotl X, size-count) as long as the top + // Count bits from RxSBG.Input are ignored. + if (shiftedInBitsMatter(RxSBG, Count, false)) + return false; + } else { + // Treat (srl X, count), mask) as (and (rotl X, size-count), ~0>>count), + // which is similar to SLL above. + if (!refineRxSBGMask(RxSBG, allOnes(RxSBG.BitSize - Count))) + return false; + } + RxSBG.Rotate = (RxSBG.Rotate - Count) & 63; RxSBG.Input = N.getOperand(0); return true; } - - case ISD::SRA: { - // Treat (sra X, count) as (rotl X, size-count) as long as the top - // count bits from Ops.Input are ignored. - ConstantSDNode *CountNode = - dyn_cast(N.getOperand(1).getNode()); - if (!CountNode) - return false; - - uint64_t Count = CountNode->getZExtValue(); - if (RxSBG.Rotate != 0 || - Count < 1 || - Count >= RxSBG.BitSize || - RxSBG.Start < 64 - (RxSBG.BitSize - Count)) - return false; - - RxSBG.Rotate = -Count & 63; - RxSBG.Input = N.getOperand(0); - return true; - } default: return false; } diff --git a/test/CodeGen/SystemZ/risbg-01.ll b/test/CodeGen/SystemZ/risbg-01.ll index 0c6826ad1f3..6f89fefd9fe 100644 --- a/test/CodeGen/SystemZ/risbg-01.ll +++ b/test/CodeGen/SystemZ/risbg-01.ll @@ -416,3 +416,41 @@ define i64 @f37(i64 %foo) { %shl = lshr i64 %and, 1 ret i64 %shl } + +; Test a combination involving a large ASHR and a shift left. We can't +; use RISBG there. +define i64 @f38(i64 %foo) { +; CHECK-LABEL: f38: +; CHECK: srag {{%r[0-5]}} +; CHECK: sllg {{%r[0-5]}} +; CHECK: br %r14 + %ashr = ashr i64 %foo, 32 + %shl = shl i64 %ashr, 5 + ret i64 %shl +} + +; Try a similar thing in which no shifted sign bits are kept. +define i64 @f39(i64 %foo, i64 *%dest) { +; CHECK-LABEL: f39: +; CHECK: srag [[REG:%r[01345]]], %r2, 35 +; CHECK: risbg %r2, %r2, 33, 189, 31 +; CHECK: br %r14 + %ashr = ashr i64 %foo, 35 + store i64 %ashr, i64 *%dest + %shl = shl i64 %ashr, 2 + %and = and i64 %shl, 2147483647 + ret i64 %and +} + +; ...and again with the next highest shift value, where one sign bit is kept. +define i64 @f40(i64 %foo, i64 *%dest) { +; CHECK-LABEL: f40: +; CHECK: srag [[REG:%r[01345]]], %r2, 36 +; CHECK: risbg %r2, [[REG]], 33, 189, 2 +; CHECK: br %r14 + %ashr = ashr i64 %foo, 36 + store i64 %ashr, i64 *%dest + %shl = shl i64 %ashr, 2 + %and = and i64 %shl, 2147483647 + ret i64 %and +}