[SystemZ] Generalize RxSBG SRA case

The original code only folded SRA into ROTATE ... SELECTED BITS
if there was no outer shift.  This patch splits out that check
and generalises it slightly.  The extra cases aren't really that
interesting, but this is paving the way for RNSBG support.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@186571 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Sandiford 2013-07-18 10:14:55 +00:00
parent 30a132f767
commit 9dffd71d0a
2 changed files with 74 additions and 27 deletions

View File

@ -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<ConstantSDNode>(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<ConstantSDNode>(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<ConstantSDNode>(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;
}

View File

@ -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
}