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());
return true;
}
- case ISD::SRL: {
- // Treat (srl X, count), mask) as (and (rotl X, size-count), ~0>>count),
- // which is similar to SLL above.
- 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)))
- return false;
-
- RxSBG.Rotate = (RxSBG.Rotate - Count) & 63;
- RxSBG.Input = N.getOperand(0);
- return true;
- }
-
+ case ISD::SRL:
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))
+ if (Count < 1 || Count >= RxSBG.BitSize)
return false;
- RxSBG.Rotate = -Count & 63;
+ 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;
}
%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
+}