forked from OSchip/llvm-project
Analysis: Reformulate WillNotOverflowUnsignedAdd for reusability
WillNotOverflowUnsignedAdd's smarts will live in ValueTracking as computeOverflowForUnsignedAdd. It now returns a tri-state result: never overflows, always overflows and sometimes overflows. llvm-svn: 225329
This commit is contained in:
parent
3b83b3fa0b
commit
5310c1e954
|
@ -221,6 +221,11 @@ namespace llvm {
|
||||||
AssumptionCache *AC,
|
AssumptionCache *AC,
|
||||||
const Instruction *CxtI,
|
const Instruction *CxtI,
|
||||||
const DominatorTree *DT);
|
const DominatorTree *DT);
|
||||||
|
OverflowResult computeOverflowForUnsignedAdd(Value *LHS, Value *RHS,
|
||||||
|
const DataLayout *DL,
|
||||||
|
AssumptionCache *AC,
|
||||||
|
const Instruction *CxtI,
|
||||||
|
const DominatorTree *DT);
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2729,3 +2729,32 @@ OverflowResult llvm::computeOverflowForUnsignedMul(Value *LHS, Value *RHS,
|
||||||
|
|
||||||
return OverflowResult::MayOverflow;
|
return OverflowResult::MayOverflow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OverflowResult llvm::computeOverflowForUnsignedAdd(Value *LHS, Value *RHS,
|
||||||
|
const DataLayout *DL,
|
||||||
|
AssumptionCache *AC,
|
||||||
|
const Instruction *CxtI,
|
||||||
|
const DominatorTree *DT) {
|
||||||
|
bool LHSKnownNonNegative, LHSKnownNegative;
|
||||||
|
ComputeSignBit(LHS, LHSKnownNonNegative, LHSKnownNegative, DL, /*Depth=*/0,
|
||||||
|
AC, CxtI, DT);
|
||||||
|
if (LHSKnownNonNegative || LHSKnownNegative) {
|
||||||
|
bool RHSKnownNonNegative, RHSKnownNegative;
|
||||||
|
ComputeSignBit(RHS, RHSKnownNonNegative, RHSKnownNegative, DL, /*Depth=*/0,
|
||||||
|
AC, CxtI, DT);
|
||||||
|
|
||||||
|
if (LHSKnownNegative && RHSKnownNegative) {
|
||||||
|
// The sign bit is set in both cases: this MUST overflow.
|
||||||
|
// Create a simple add instruction, and insert it into the struct.
|
||||||
|
return OverflowResult::AlwaysOverflows;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LHSKnownNonNegative && RHSKnownNonNegative) {
|
||||||
|
// The sign bit is clear in both cases: this CANNOT overflow.
|
||||||
|
// Create a simple add instruction, and insert it into the struct.
|
||||||
|
return OverflowResult::NeverOverflows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OverflowResult::MayOverflow;
|
||||||
|
}
|
||||||
|
|
|
@ -282,7 +282,6 @@ private:
|
||||||
bool DoXform = true);
|
bool DoXform = true);
|
||||||
Instruction *transformSExtICmp(ICmpInst *ICI, Instruction &CI);
|
Instruction *transformSExtICmp(ICmpInst *ICI, Instruction &CI);
|
||||||
bool WillNotOverflowSignedAdd(Value *LHS, Value *RHS, Instruction *CxtI);
|
bool WillNotOverflowSignedAdd(Value *LHS, Value *RHS, Instruction *CxtI);
|
||||||
bool WillNotOverflowUnsignedAdd(Value *LHS, Value *RHS, Instruction *CxtI);
|
|
||||||
bool WillNotOverflowSignedSub(Value *LHS, Value *RHS, Instruction *CxtI);
|
bool WillNotOverflowSignedSub(Value *LHS, Value *RHS, Instruction *CxtI);
|
||||||
bool WillNotOverflowUnsignedSub(Value *LHS, Value *RHS, Instruction *CxtI);
|
bool WillNotOverflowUnsignedSub(Value *LHS, Value *RHS, Instruction *CxtI);
|
||||||
bool WillNotOverflowSignedMul(Value *LHS, Value *RHS, Instruction *CxtI);
|
bool WillNotOverflowSignedMul(Value *LHS, Value *RHS, Instruction *CxtI);
|
||||||
|
@ -391,6 +390,10 @@ public:
|
||||||
const Instruction *CxtI) {
|
const Instruction *CxtI) {
|
||||||
return llvm::computeOverflowForUnsignedMul(LHS, RHS, DL, AC, CxtI, DT);
|
return llvm::computeOverflowForUnsignedMul(LHS, RHS, DL, AC, CxtI, DT);
|
||||||
}
|
}
|
||||||
|
OverflowResult computeOverflowForUnsignedAdd(Value *LHS, Value *RHS,
|
||||||
|
const Instruction *CxtI) {
|
||||||
|
return llvm::computeOverflowForUnsignedAdd(LHS, RHS, DL, AC, CxtI, DT);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// SimplifyAssociativeOrCommutative - This performs a few simplifications for
|
/// SimplifyAssociativeOrCommutative - This performs a few simplifications for
|
||||||
|
|
|
@ -937,22 +937,6 @@ bool InstCombiner::WillNotOverflowSignedAdd(Value *LHS, Value *RHS,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// WillNotOverflowUnsignedAdd - Return true if we can prove that:
|
|
||||||
/// (zext (add LHS, RHS)) === (add (zext LHS), (zext RHS))
|
|
||||||
bool InstCombiner::WillNotOverflowUnsignedAdd(Value *LHS, Value *RHS,
|
|
||||||
Instruction *CxtI) {
|
|
||||||
// There are different heuristics we can use for this. Here is a simple one.
|
|
||||||
// If the sign bit of LHS and that of RHS are both zero, no unsigned wrap.
|
|
||||||
bool LHSKnownNonNegative, LHSKnownNegative;
|
|
||||||
bool RHSKnownNonNegative, RHSKnownNegative;
|
|
||||||
ComputeSignBit(LHS, LHSKnownNonNegative, LHSKnownNegative, /*Depth=*/0, CxtI);
|
|
||||||
ComputeSignBit(RHS, RHSKnownNonNegative, RHSKnownNegative, /*Depth=*/0, CxtI);
|
|
||||||
if (LHSKnownNonNegative && RHSKnownNonNegative)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Return true if we can prove that:
|
/// \brief Return true if we can prove that:
|
||||||
/// (sub LHS, RHS) === (sub nsw LHS, RHS)
|
/// (sub LHS, RHS) === (sub nsw LHS, RHS)
|
||||||
/// This basically requires proving that the add in the original type would not
|
/// This basically requires proving that the add in the original type would not
|
||||||
|
@ -1327,7 +1311,9 @@ Instruction *InstCombiner::visitAdd(BinaryOperator &I) {
|
||||||
Changed = true;
|
Changed = true;
|
||||||
I.setHasNoSignedWrap(true);
|
I.setHasNoSignedWrap(true);
|
||||||
}
|
}
|
||||||
if (!I.hasNoUnsignedWrap() && WillNotOverflowUnsignedAdd(LHS, RHS, &I)) {
|
if (!I.hasNoUnsignedWrap() &&
|
||||||
|
computeOverflowForUnsignedAdd(LHS, RHS, &I) ==
|
||||||
|
OverflowResult::NeverOverflows) {
|
||||||
Changed = true;
|
Changed = true;
|
||||||
I.setHasNoUnsignedWrap(true);
|
I.setHasNoUnsignedWrap(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,33 +352,11 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
|
||||||
break;
|
break;
|
||||||
case Intrinsic::uadd_with_overflow: {
|
case Intrinsic::uadd_with_overflow: {
|
||||||
Value *LHS = II->getArgOperand(0), *RHS = II->getArgOperand(1);
|
Value *LHS = II->getArgOperand(0), *RHS = II->getArgOperand(1);
|
||||||
IntegerType *IT = cast<IntegerType>(II->getArgOperand(0)->getType());
|
OverflowResult OR = computeOverflowForUnsignedAdd(LHS, RHS, II);
|
||||||
uint32_t BitWidth = IT->getBitWidth();
|
if (OR == OverflowResult::NeverOverflows)
|
||||||
APInt LHSKnownZero(BitWidth, 0);
|
return CreateOverflowTuple(II, Builder->CreateNUWAdd(LHS, RHS), false);
|
||||||
APInt LHSKnownOne(BitWidth, 0);
|
if (OR == OverflowResult::AlwaysOverflows)
|
||||||
computeKnownBits(LHS, LHSKnownZero, LHSKnownOne, 0, II);
|
return CreateOverflowTuple(II, Builder->CreateAdd(LHS, RHS), true);
|
||||||
bool LHSKnownNegative = LHSKnownOne[BitWidth - 1];
|
|
||||||
bool LHSKnownPositive = LHSKnownZero[BitWidth - 1];
|
|
||||||
|
|
||||||
if (LHSKnownNegative || LHSKnownPositive) {
|
|
||||||
APInt RHSKnownZero(BitWidth, 0);
|
|
||||||
APInt RHSKnownOne(BitWidth, 0);
|
|
||||||
computeKnownBits(RHS, RHSKnownZero, RHSKnownOne, 0, II);
|
|
||||||
bool RHSKnownNegative = RHSKnownOne[BitWidth - 1];
|
|
||||||
bool RHSKnownPositive = RHSKnownZero[BitWidth - 1];
|
|
||||||
if (LHSKnownNegative && RHSKnownNegative) {
|
|
||||||
// The sign bit is set in both cases: this MUST overflow.
|
|
||||||
// Create a simple add instruction, and insert it into the struct.
|
|
||||||
return CreateOverflowTuple(II, Builder->CreateAdd(LHS, RHS), true,
|
|
||||||
/*ReUseName*/true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LHSKnownPositive && RHSKnownPositive) {
|
|
||||||
// The sign bit is clear in both cases: this CANNOT overflow.
|
|
||||||
// Create a simple add instruction, and insert it into the struct.
|
|
||||||
return CreateOverflowTuple(II, Builder->CreateNUWAdd(LHS, RHS), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// FALL THROUGH uadd into sadd
|
// FALL THROUGH uadd into sadd
|
||||||
case Intrinsic::sadd_with_overflow:
|
case Intrinsic::sadd_with_overflow:
|
||||||
|
|
Loading…
Reference in New Issue