@@ -1981,6 +1981,97 @@ static bool isShiftedMask(uint64_t Mask, EVT VT) {
19811981 return isShiftedMask_64 (Mask);
19821982}
19831983
1984+ // Generate a BFI/BFXIL from 'or (and X, MaskImm), OrImm' iff the value being
1985+ // inserted only sets known zero bits.
1986+ static bool tryBitfieldInsertOpFromOrAndImm (SDNode *N, SelectionDAG *CurDAG) {
1987+ assert (N->getOpcode () == ISD::OR && " Expect a OR operation" );
1988+
1989+ EVT VT = N->getValueType (0 );
1990+ if (VT != MVT::i32 && VT != MVT::i64 )
1991+ return false ;
1992+
1993+ unsigned BitWidth = VT.getSizeInBits ();
1994+
1995+ uint64_t OrImm;
1996+ if (!isOpcWithIntImmediate (N, ISD::OR, OrImm))
1997+ return false ;
1998+
1999+ // Skip this transformation if the ORR immediate can be encoded in the ORR.
2000+ // Otherwise, we'll trade an AND+ORR for ORR+BFI/BFXIL, which is most likely
2001+ // performance neutral.
2002+ if (AArch64_AM::isLogicalImmediate (OrImm, BitWidth))
2003+ return false ;
2004+
2005+ uint64_t MaskImm;
2006+ SDValue And = N->getOperand (0 );
2007+ // Must be a single use AND with an immediate operand.
2008+ if (!And.hasOneUse () ||
2009+ !isOpcWithIntImmediate (And.getNode (), ISD::AND, MaskImm))
2010+ return false ;
2011+
2012+ // Compute the Known Zero for the AND as this allows us to catch more general
2013+ // cases than just looking for AND with imm.
2014+ APInt KnownZero, KnownOne;
2015+ CurDAG->computeKnownBits (And, KnownZero, KnownOne);
2016+
2017+ // Non-zero in the sense that they're not provably zero, which is the key
2018+ // point if we want to use this value.
2019+ uint64_t NotKnownZero = (~KnownZero).getZExtValue ();
2020+
2021+ // The KnownZero mask must be a shifted mask (e.g., 1110..011, 11100..00).
2022+ if (!isShiftedMask (KnownZero.getZExtValue (), VT))
2023+ return false ;
2024+
2025+ // The bits being inserted must only set those bits that are known to be zero.
2026+ if ((OrImm & NotKnownZero) != 0 ) {
2027+ // FIXME: It's okay if the OrImm sets NotKnownZero bits to 1, but we don't
2028+ // currently handle this case.
2029+ return false ;
2030+ }
2031+
2032+ // BFI/BFXIL dst, src, #lsb, #width.
2033+ int LSB = countTrailingOnes (NotKnownZero);
2034+ int Width = BitWidth - APInt (BitWidth, NotKnownZero).countPopulation ();
2035+
2036+ // BFI/BFXIL is an alias of BFM, so translate to BFM operands.
2037+ unsigned ImmR = (BitWidth - LSB) % BitWidth;
2038+ unsigned ImmS = Width - 1 ;
2039+
2040+ // If we're creating a BFI instruction avoid cases where we need more
2041+ // instructions to materialize the BFI constant as compared to the original
2042+ // ORR. A BFXIL will use the same constant as the original ORR, so the code
2043+ // should be no worse in this case.
2044+ bool IsBFI = LSB != 0 ;
2045+ uint64_t BFIImm = OrImm >> LSB;
2046+ if (IsBFI && !AArch64_AM::isLogicalImmediate (BFIImm, BitWidth)) {
2047+ // We have a BFI instruction and we know the constant can't be materialized
2048+ // with a ORR-immediate with the zero register.
2049+ unsigned OrChunks = 0 , BFIChunks = 0 ;
2050+ for (unsigned Shift = 0 ; Shift < BitWidth; Shift += 16 ) {
2051+ if (((OrImm >> Shift) & 0xFFFF ) != 0 )
2052+ ++OrChunks;
2053+ if (((BFIImm >> Shift) & 0xFFFF ) != 0 )
2054+ ++BFIChunks;
2055+ }
2056+ if (BFIChunks > OrChunks)
2057+ return false ;
2058+ }
2059+
2060+ // Materialize the constant to be inserted.
2061+ SDLoc DL (N);
2062+ unsigned MOVIOpc = VT == MVT::i32 ? AArch64::MOVi32imm : AArch64::MOVi64imm;
2063+ SDNode *MOVI = CurDAG->getMachineNode (
2064+ MOVIOpc, DL, VT, CurDAG->getTargetConstant (BFIImm, DL, VT));
2065+
2066+ // Create the BFI/BFXIL instruction.
2067+ SDValue Ops[] = {And.getOperand (0 ), SDValue (MOVI, 0 ),
2068+ CurDAG->getTargetConstant (ImmR, DL, VT),
2069+ CurDAG->getTargetConstant (ImmS, DL, VT)};
2070+ unsigned Opc = (VT == MVT::i32 ) ? AArch64::BFMWri : AArch64::BFMXri;
2071+ CurDAG->SelectNodeTo (N, Opc, VT, Ops);
2072+ return true ;
2073+ }
2074+
19842075static bool tryBitfieldInsertOpFromOr (SDNode *N, const APInt &UsefulBits,
19852076 SelectionDAG *CurDAG) {
19862077 assert (N->getOpcode () == ISD::OR && " Expect a OR operation" );
@@ -2159,7 +2250,10 @@ bool AArch64DAGToDAGISel::tryBitfieldInsertOp(SDNode *N) {
21592250 return true ;
21602251 }
21612252
2162- return tryBitfieldInsertOpFromOr (N, NUsefulBits, CurDAG);
2253+ if (tryBitfieldInsertOpFromOr (N, NUsefulBits, CurDAG))
2254+ return true ;
2255+
2256+ return tryBitfieldInsertOpFromOrAndImm (N, CurDAG);
21632257}
21642258
21652259// / SelectBitfieldInsertInZeroOp - Match a UBFIZ instruction that is the
0 commit comments