@@ -1981,6 +1981,97 @@ static bool isShiftedMask(uint64_t Mask, EVT VT) {
1981
1981
return isShiftedMask_64 (Mask);
1982
1982
}
1983
1983
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
+
1984
2075
static bool tryBitfieldInsertOpFromOr (SDNode *N, const APInt &UsefulBits,
1985
2076
SelectionDAG *CurDAG) {
1986
2077
assert (N->getOpcode () == ISD::OR && " Expect a OR operation" );
@@ -2159,7 +2250,10 @@ bool AArch64DAGToDAGISel::tryBitfieldInsertOp(SDNode *N) {
2159
2250
return true ;
2160
2251
}
2161
2252
2162
- return tryBitfieldInsertOpFromOr (N, NUsefulBits, CurDAG);
2253
+ if (tryBitfieldInsertOpFromOr (N, NUsefulBits, CurDAG))
2254
+ return true ;
2255
+
2256
+ return tryBitfieldInsertOpFromOrAndImm (N, CurDAG);
2163
2257
}
2164
2258
2165
2259
// / SelectBitfieldInsertInZeroOp - Match a UBFIZ instruction that is the
0 commit comments