summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <rsandifo@linux.vnet.ibm.com>2013-07-11 09:10:09 +0000
committerRichard Sandiford <rsandifo@linux.vnet.ibm.com>2013-07-11 09:10:09 +0000
commit261e2877ebcb3c6139ddcc67992662494232b096 (patch)
tree76654e9edb8c1c3b668633c9ee83a39137f36347
parentb3cabb44c32b5a3aba9b4d23aae9723d498ea7a9 (diff)
downloadllvm-261e2877ebcb3c6139ddcc67992662494232b096.tar.gz
llvm-261e2877ebcb3c6139ddcc67992662494232b096.tar.bz2
llvm-261e2877ebcb3c6139ddcc67992662494232b096.tar.xz
[SystemZ] Use zeroing form of RISBG for shift-and-AND sequences
Extend r186072 to handle shifts and ANDs. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@186073 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Target/SystemZ/SystemZISelDAGToDAG.cpp71
-rw-r--r--test/CodeGen/SystemZ/fp-move-02.ll4
2 files changed, 68 insertions, 7 deletions
diff --git a/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index 5b1b77b2d5..39589f6d20 100644
--- a/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -613,20 +613,81 @@ SDNode *SystemZDAGToDAGISel::tryRISBGForAND(SDNode *N) {
unsigned Start, End;
ConstantSDNode *MaskNode =
dyn_cast<ConstantSDNode>(N->getOperand(1).getNode());
- if (!MaskNode
- || !isRISBGMask(MaskNode->getZExtValue(), BitSize, Start, End))
+ if (!MaskNode)
return 0;
+ SDValue Input = N->getOperand(0);
+ uint64_t Mask = MaskNode->getZExtValue();
+ if (!isRISBGMask(Mask, BitSize, Start, End)) {
+ APInt KnownZero, KnownOne;
+ CurDAG->ComputeMaskedBits(Input, KnownZero, KnownOne);
+ Mask |= KnownZero.getZExtValue();
+ if (!isRISBGMask(Mask, BitSize, Start, End))
+ return 0;
+ }
+
+ unsigned Rotate = 0;
+ if (Input->getOpcode() == ISD::ROTL && BitSize == 64) {
+ // Any 64-bit rotate left can be merged into the RISBG.
+ if (ConstantSDNode *CountNode =
+ dyn_cast<ConstantSDNode>(Input.getOperand(1).getNode())) {
+ Rotate = CountNode->getZExtValue() & (BitSize - 1);
+ Input = Input->getOperand(0);
+ }
+ } else if (Input->getOpcode() == ISD::SHL) {
+ // Try to convert (and (shl X, count), mask) into
+ // (and (rotl X, count), mask&(~0<<count)), where the new mask
+ // removes bits from the original mask that are zeroed by the shl
+ // but that are not necessarily zero in X.
+ if (ConstantSDNode *CountNode =
+ dyn_cast<ConstantSDNode>(Input.getOperand(1).getNode())) {
+ uint64_t Count = CountNode->getZExtValue();
+ if (Count > 0 &&
+ Count < BitSize &&
+ isRISBGMask(Mask & (allOnes(BitSize - Count) << Count),
+ BitSize, Start, End)) {
+ Rotate = Count;
+ Input = Input->getOperand(0);
+ }
+ }
+ } else if (Input->getOpcode() == ISD::SRL) {
+ // Try to convert (and (srl X, count), mask) into
+ // (and (rotl X, size-count), mask&(~0>>count)), which is similar
+ // to SLL above.
+ if (ConstantSDNode *CountNode =
+ dyn_cast<ConstantSDNode>(Input.getOperand(1).getNode())) {
+ uint64_t Count = CountNode->getZExtValue();
+ if (Count > 0 &&
+ Count < BitSize &&
+ isRISBGMask(Mask & allOnes(BitSize - Count), BitSize, Start, End)) {
+ Rotate = 64 - Count;
+ Input = Input->getOperand(0);
+ }
+ }
+ } else if (Start <= End && Input->getOpcode() == ISD::SRA) {
+ // Try to convert (and (sra X, count), mask) into
+ // (and (rotl X, size-count), mask). The mask must not include
+ // any sign bits.
+ if (ConstantSDNode *CountNode =
+ dyn_cast<ConstantSDNode>(Input.getOperand(1).getNode())) {
+ uint64_t Count = CountNode->getZExtValue();
+ if (Count > 0 && Count < BitSize && Start >= 64 - (BitSize - Count)) {
+ Rotate = 64 - Count;
+ Input = Input->getOperand(0);
+ }
+ }
+ }
+
// Prefer register extensions like LLC over RSIBG.
- if ((Start == 32 || Start == 48 || Start == 56) && End == 63)
+ if (Rotate == 0 && (Start == 32 || Start == 48 || Start == 56) && End == 63)
return 0;
SDValue Ops[5] = {
getUNDEF64(SDLoc(N)),
- convertTo(SDLoc(N), MVT::i64, N->getOperand(0)),
+ convertTo(SDLoc(N), MVT::i64, Input),
CurDAG->getTargetConstant(Start, MVT::i32),
CurDAG->getTargetConstant(End | 128, MVT::i32),
- CurDAG->getTargetConstant(0, MVT::i32)
+ CurDAG->getTargetConstant(Rotate, MVT::i32)
};
N = CurDAG->getMachineNode(SystemZ::RISBG, SDLoc(N), MVT::i64, Ops);
return convertTo(SDLoc(N), VT, SDValue(N, 0)).getNode();
diff --git a/test/CodeGen/SystemZ/fp-move-02.ll b/test/CodeGen/SystemZ/fp-move-02.ll
index a02c856412..f828b2d1ad 100644
--- a/test/CodeGen/SystemZ/fp-move-02.ll
+++ b/test/CodeGen/SystemZ/fp-move-02.ll
@@ -16,7 +16,7 @@ define float @f1(i32 %a) {
; surrounding code.
define float @f2(i64 %big) {
; CHECK: f2:
-; CHECK: sllg [[REGISTER:%r[0-5]]], %r2, 31
+; CHECK: risbg [[REGISTER:%r[0-5]]], %r2, 0, 159, 31
; CHECK: ldgr %f0, [[REGISTER]]
%shift = lshr i64 %big, 1
%a = trunc i64 %shift to i32
@@ -27,7 +27,7 @@ define float @f2(i64 %big) {
; Another example of the same thing.
define float @f3(i64 %big) {
; CHECK: f3:
-; CHECK: sllg [[REGISTER:%r[0-5]]], %r2, 2
+; CHECK: risbg [[REGISTER:%r[0-5]]], %r2, 0, 159, 2
; CHECK: ldgr %f0, [[REGISTER]]
%shift = ashr i64 %big, 30
%a = trunc i64 %shift to i32