diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h --- a/llvm/include/llvm/ADT/APInt.h +++ b/llvm/include/llvm/ADT/APInt.h @@ -430,6 +430,17 @@ return countPopulationSlowCase() == 1; } + /// Check if this APInt's negated value is a power of two greater than zero. + bool isNegatedPowerOf2() const { + assert(BitWidth && "zero width values not allowed"); + if (isNonNegative()) + return false; + // NegatedPowerOf2 - shifted mask in the top bits. + unsigned LO = countLeadingOnes(); + unsigned TZ = countTrailingZeros(); + return (LO + TZ) == BitWidth; + } + /// Check if the APInt's value is returned by getSignMask. /// /// \returns true if this is the value returned by getSignMask. diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h --- a/llvm/include/llvm/IR/PatternMatch.h +++ b/llvm/include/llvm/IR/PatternMatch.h @@ -549,7 +549,7 @@ } struct is_negated_power2 { - bool isValue(const APInt &C) { return (-C).isPowerOf2(); } + bool isValue(const APInt &C) { return C.isNegatedPowerOf2(); } }; /// Match a integer or vector negated power-of-2. /// For vectors, this includes constants with undefined elements. diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -3841,7 +3841,7 @@ } // fold (mul x, -(1 << c)) -> -(x << c) or (-x) << c - if (N1IsConst && !N1IsOpaqueConst && (-ConstValue1).isPowerOf2()) { + if (N1IsConst && !N1IsOpaqueConst && ConstValue1.isNegatedPowerOf2()) { unsigned Log2Val = (-ConstValue1).logBase2(); SDLoc DL(N); // FIXME: If the input is something that is easily negated (e.g. a @@ -4212,7 +4212,7 @@ return false; if (C->getAPIntValue().isPowerOf2()) return true; - if ((-C->getAPIntValue()).isPowerOf2()) + if (C->getAPIntValue().isNegatedPowerOf2()) return true; return false; }; diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -4150,7 +4150,7 @@ N0.getOpcode() == ISD::AND && N0.hasOneUse()) { if (auto *AndRHS = dyn_cast(N0.getOperand(1))) { const APInt &AndRHSC = AndRHS->getAPIntValue(); - if ((-AndRHSC).isPowerOf2() && (AndRHSC & C1) == C1) { + if (AndRHSC.isNegatedPowerOf2() && (AndRHSC & C1) == C1) { unsigned ShiftBits = AndRHSC.countTrailingZeros(); if (!TLI.shouldAvoidTransformToShift(ShValTy, ShiftBits)) { SDValue Shift = diff --git a/llvm/lib/Target/AArch64/AArch64FastISel.cpp b/llvm/lib/Target/AArch64/AArch64FastISel.cpp --- a/llvm/lib/Target/AArch64/AArch64FastISel.cpp +++ b/llvm/lib/Target/AArch64/AArch64FastISel.cpp @@ -4806,7 +4806,7 @@ const APInt &C = cast(I->getOperand(1))->getValue(); if ((VT != MVT::i32 && VT != MVT::i64) || !C || - !(C.isPowerOf2() || (-C).isPowerOf2())) + !(C.isPowerOf2() || C.isNegatedPowerOf2())) return selectBinaryOp(I, ISD::SDIV); unsigned Lg2 = C.countTrailingZeros(); diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -12802,7 +12802,7 @@ // fold (sdiv X, pow2) EVT VT = N->getValueType(0); if ((VT != MVT::i32 && VT != MVT::i64) || - !(Divisor.isPowerOf2() || (-Divisor).isPowerOf2())) + !(Divisor.isPowerOf2() || Divisor.isNegatedPowerOf2())) return SDValue(); SDLoc DL(N); diff --git a/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp b/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp --- a/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp +++ b/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp @@ -342,7 +342,7 @@ if (InstSPF == SPF_SMAX && PatternMatch::match(RHS, PatternMatch::m_ConstantInt(C)) && - C->getValue() == Imm && Imm.isNegative() && (-Imm).isPowerOf2()) { + C->getValue() == Imm && Imm.isNegative() && Imm.isNegatedPowerOf2()) { auto isSSatMin = [&](Value *MinInst) { if (isa(MinInst)) { diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -15606,13 +15606,13 @@ if (VT == MVT::i64 && !Subtarget.isPPC64()) return SDValue(); if ((VT != MVT::i32 && VT != MVT::i64) || - !(Divisor.isPowerOf2() || (-Divisor).isPowerOf2())) + !(Divisor.isPowerOf2() || Divisor.isNegatedPowerOf2())) return SDValue(); SDLoc DL(N); SDValue N0 = N->getOperand(0); - bool IsNegPow2 = (-Divisor).isPowerOf2(); + bool IsNegPow2 = Divisor.isNegatedPowerOf2(); unsigned Lg2 = (IsNegPow2 ? -Divisor : Divisor).countTrailingZeros(); SDValue ShiftAmt = DAG.getConstant(Lg2, DL, VT); diff --git a/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp b/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp --- a/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp +++ b/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp @@ -424,8 +424,8 @@ (C->getType()->isVectorTy() ? dyn_cast_or_null(C->getSplatValue()) : dyn_cast(C)); - if (CVal != nullptr && - (CVal->getValue().isPowerOf2() || (-CVal->getValue()).isPowerOf2())) + if (CVal && (CVal->getValue().isPowerOf2() || + CVal->getValue().isNegatedPowerOf2())) DivRemConstPow2 = true; else DivRemConst = true; diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -23263,7 +23263,7 @@ if (isIntDivCheap(N->getValueType(0), Attr)) return SDValue(N,0); // Lower SDIV as SDIV - assert((Divisor.isPowerOf2() || (-Divisor).isPowerOf2()) && + assert((Divisor.isPowerOf2() || Divisor.isNegatedPowerOf2()) && "Unexpected divisor!"); // Only perform this transform if CMOV is supported otherwise the select diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1889,7 +1889,7 @@ // X & -C == -C -> X > u ~C // X & -C != -C -> X <= u ~C // iff C is a power of 2 - if (Cmp.getOperand(1) == Y && (-C).isPowerOf2()) { + if (Cmp.getOperand(1) == Y && C.isNegatedPowerOf2()) { auto NewPred = Pred == CmpInst::ICMP_EQ ? CmpInst::ICMP_UGT : CmpInst::ICMP_ULE; return new ICmpInst(NewPred, X, SubOne(cast(Cmp.getOperand(1)))); diff --git a/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp b/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp --- a/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp +++ b/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp @@ -620,7 +620,7 @@ ConstantInt *Exponent = ConstantInt::get(DeltaType, IndexOffset.logBase2()); return Builder.CreateShl(ExtendedStride, Exponent); } - if ((-IndexOffset).isPowerOf2()) { + if (IndexOffset.isNegatedPowerOf2()) { // If (i - i') is a power of 2, Bump = -sext/trunc(S) << log(i' - i). ConstantInt *Exponent = ConstantInt::get(DeltaType, (-IndexOffset).logBase2()); diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp --- a/llvm/unittests/ADT/APIntTest.cpp +++ b/llvm/unittests/ADT/APIntTest.cpp @@ -1785,6 +1785,32 @@ } } +TEST(APIntTest, isNegatedPowerOf2) { + EXPECT_FALSE(APInt(5, 0x00).isNegatedPowerOf2()); + EXPECT_TRUE(APInt(15, 0x7ffe).isNegatedPowerOf2()); + EXPECT_TRUE(APInt(16, 0xfffc).isNegatedPowerOf2()); + EXPECT_TRUE(APInt(32, 0xffffffff).isNegatedPowerOf2()); + + for (int N : {1, 2, 3, 4, 7, 8, 16, 32, 64, 127, 128, 129, 256}) { + EXPECT_FALSE(APInt(N, 0).isNegatedPowerOf2()); + EXPECT_TRUE(APInt::getAllOnes(N).isNegatedPowerOf2()); + EXPECT_TRUE(APInt::getSignedMinValue(N).isNegatedPowerOf2()); + EXPECT_TRUE((-APInt::getSignedMinValue(N)).isNegatedPowerOf2()); + + APInt One(N, 1); + for (int I = 1; I < N - 1; ++I) { + EXPECT_FALSE(APInt::getOneBitSet(N, I).isNegatedPowerOf2()); + EXPECT_TRUE((-APInt::getOneBitSet(N, I)).isNegatedPowerOf2()); + + APInt MaskVal = One.shl(I); + EXPECT_TRUE((-MaskVal).isNegatedPowerOf2()); + + APInt ShiftMaskVal = One.getHighBitsSet(N, I); + EXPECT_TRUE(ShiftMaskVal.isNegatedPowerOf2()); + } + } +} + // Test that self-move works with EXPENSIVE_CHECKS. It calls std::shuffle which // does self-move on some platforms. #ifdef EXPENSIVE_CHECKS