diff options
author | Chad Rosier <mcrosier@codeaurora.org> | 2016-05-19 14:19:47 +0000 |
---|---|---|
committer | Chad Rosier <mcrosier@codeaurora.org> | 2016-05-19 14:19:47 +0000 |
commit | 02f25a95655e9e320c524978e54df8e4a22ef921 (patch) | |
tree | babcfe9f5df8aef9b092fb08af720479639ec783 /llvm/lib | |
parent | 01319e93abe3a4d3e722de4e849762ea54d12d70 (diff) | |
download | bcm5719-llvm-02f25a95655e9e320c524978e54df8e4a22ef921.tar.gz bcm5719-llvm-02f25a95655e9e320c524978e54df8e4a22ef921.zip |
[AArch64 ] Generate a BFXIL from 'or (and X, Mask0Imm),(and Y, Mask1Imm)'.
Mask0Imm and ~Mask1Imm must be equivalent and one of the MaskImms is a shifted
mask (e.g., 0x000ffff0). Both 'and's must have a single use.
This changes code like:
and w8, w0, #0xffff000f
and w9, w1, #0x0000fff0
orr w0, w9, w8
into
lsr w8, w1, #4
bfi w0, w8, #4, #12
llvm-svn: 270063
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp index b8ee03a3558..fe5d6045bde 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -1974,6 +1974,13 @@ static bool isBitfieldPositioningOp(SelectionDAG *CurDAG, SDValue Op, return true; } +static bool isShiftedMask(uint64_t Mask, EVT VT) { + assert(VT == MVT::i32 || VT == MVT::i64); + if (VT == MVT::i32) + return isShiftedMask_32(Mask); + return isShiftedMask_64(Mask); +} + static bool tryBitfieldInsertOpFromOr(SDNode *N, const APInt &UsefulBits, SelectionDAG *CurDAG) { assert(N->getOpcode() == ISD::OR && "Expect a OR operation"); @@ -2084,6 +2091,58 @@ static bool tryBitfieldInsertOpFromOr(SDNode *N, const APInt &UsefulBits, CurDAG->SelectNodeTo(N, Opc, VT, Ops); return true; } + + // Generate a BFXIL from 'or (and X, Mask0Imm), (and Y, Mask1Imm)' iff + // Mask0Imm and ~Mask1Imm are equivalent and one of the MaskImms is a shifted + // mask (e.g., 0x000ffff0). + uint64_t Mask0Imm, Mask1Imm; + SDValue And0 = N->getOperand(0); + SDValue And1 = N->getOperand(1); + if (And0.hasOneUse() && And1.hasOneUse() && + isOpcWithIntImmediate(And0.getNode(), ISD::AND, Mask0Imm) && + isOpcWithIntImmediate(And1.getNode(), ISD::AND, Mask1Imm) && + APInt(BitWidth, Mask0Imm) == ~APInt(BitWidth, Mask1Imm) && + (isShiftedMask(Mask0Imm, VT) || isShiftedMask(Mask1Imm, VT))) { + + // We should have already caught the case where we extract hi and low parts. + // E.g. BFXIL from 'or (and X, 0xffff0000), (and Y, 0x0000ffff)'. + assert(!(isShiftedMask(Mask0Imm, VT) && isShiftedMask(Mask1Imm, VT)) && + "BFXIL should have already been optimized."); + + // ORR is commutative, so canonicalize to the form 'or (and X, Mask0Imm), + // (and Y, Mask1Imm)' where Mask1Imm is the shifted mask masking off the + // bits to be inserted. + if (isShiftedMask(Mask0Imm, VT)) { + std::swap(And0, And1); + std::swap(Mask0Imm, Mask1Imm); + } + + SDValue Src = And1->getOperand(0); + SDValue Dst = And0->getOperand(0); + unsigned LSB = countTrailingZeros(Mask1Imm); + int Width = BitWidth - APInt(BitWidth, Mask0Imm).countPopulation(); + + // The BFXIL inserts the low-order bits from a source register, so right + // shift the needed bits into place. + SDLoc DL(N); + unsigned ShiftOpc = (VT == MVT::i32) ? AArch64::UBFMWri : AArch64::UBFMXri; + SDNode *LSR = CurDAG->getMachineNode( + ShiftOpc, DL, VT, Src, CurDAG->getTargetConstant(LSB, DL, VT), + CurDAG->getTargetConstant(BitWidth - 1, DL, VT)); + + // BFXIL is an alias of BFM, so translate to BFM operands. + unsigned ImmR = (BitWidth - LSB) % BitWidth; + unsigned ImmS = Width - 1; + + // Create the BFXIL instruction. + SDValue Ops[] = {Dst, SDValue(LSR, 0), + CurDAG->getTargetConstant(ImmR, DL, VT), + CurDAG->getTargetConstant(ImmS, DL, VT)}; + unsigned Opc = (VT == MVT::i32) ? AArch64::BFMWri : AArch64::BFMXri; + CurDAG->SelectNodeTo(N, Opc, VT, Ops); + return true; + } + return false; } |