forked from OSchip/llvm-project
Teach CorrelatedValuePropagation to mark adds as no wrap
Use LVI to prove that adds do not wrap. The change is motivated by https://llvm.org/bugs/show_bug.cgi?id=28620 bug and it's the first step to fix that problem. Reviewed By: sanjoy Differential Revision: http://reviews.llvm.org/D23059 llvm-svn: 277592
This commit is contained in:
parent
629109b633
commit
68cb947cc9
|
@ -18,6 +18,7 @@
|
|||
#include "llvm/Analysis/InstructionSimplify.h"
|
||||
#include "llvm/Analysis/LazyValueInfo.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/ConstantRange.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
|
@ -381,6 +382,59 @@ static bool processSDiv(BinaryOperator *SDI, LazyValueInfo *LVI) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool processAdd(BinaryOperator *AddOp, LazyValueInfo *LVI) {
|
||||
typedef OverflowingBinaryOperator OBO;
|
||||
|
||||
if (AddOp->getType()->isVectorTy() || hasLocalDefs(AddOp))
|
||||
return false;
|
||||
|
||||
bool NSW = AddOp->hasNoSignedWrap();
|
||||
bool NUW = AddOp->hasNoUnsignedWrap();
|
||||
if (NSW && NUW)
|
||||
return false;
|
||||
|
||||
BasicBlock *BB = AddOp->getParent();
|
||||
|
||||
Value *LHS = AddOp->getOperand(0);
|
||||
Value *RHS = AddOp->getOperand(1);
|
||||
|
||||
ConstantRange LRange = LVI->getConstantRange(LHS, BB, AddOp);
|
||||
|
||||
// Initialize RRange only if we need it. If we know that guaranteed no wrap
|
||||
// range for the given LHS range is empty don't spend time calculating the
|
||||
// range for the RHS.
|
||||
Optional<ConstantRange> RRange;
|
||||
auto LazyRRange = [&] () {
|
||||
if (!RRange)
|
||||
RRange = LVI->getConstantRange(RHS, BB, AddOp);
|
||||
return RRange.getValue();
|
||||
};
|
||||
|
||||
bool Changed = false;
|
||||
if (!NUW) {
|
||||
ConstantRange NUWRange =
|
||||
LRange.makeGuaranteedNoWrapRegion(BinaryOperator::Add, LRange,
|
||||
OBO::NoUnsignedWrap);
|
||||
if (!NUWRange.isEmptySet()) {
|
||||
bool NewNUW = NUWRange.contains(LazyRRange());
|
||||
AddOp->setHasNoUnsignedWrap(NewNUW);
|
||||
Changed |= NewNUW;
|
||||
}
|
||||
}
|
||||
if (!NSW) {
|
||||
ConstantRange NSWRange =
|
||||
LRange.makeGuaranteedNoWrapRegion(BinaryOperator::Add, LRange,
|
||||
OBO::NoSignedWrap);
|
||||
if (!NSWRange.isEmptySet()) {
|
||||
bool NewNSW = NSWRange.contains(LazyRRange());
|
||||
AddOp->setHasNoSignedWrap(NewNSW);
|
||||
Changed |= NewNSW;
|
||||
}
|
||||
}
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
static Constant *getConstantAt(Value *V, Instruction *At, LazyValueInfo *LVI) {
|
||||
if (Constant *C = LVI->getConstant(V, At->getParent(), At))
|
||||
return C;
|
||||
|
@ -436,6 +490,9 @@ static bool runImpl(Function &F, LazyValueInfo *LVI) {
|
|||
case Instruction::SDiv:
|
||||
BBChanged |= processSDiv(cast<BinaryOperator>(II), LVI);
|
||||
break;
|
||||
case Instruction::Add:
|
||||
BBChanged |= processAdd(cast<BinaryOperator>(II), LVI);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
; RUN: opt < %s -correlated-propagation -S | FileCheck %s
|
||||
|
||||
; CHECK-LABEL: @test0(
|
||||
define void @test0(i32 %a) {
|
||||
entry:
|
||||
%cmp = icmp slt i32 %a, 100
|
||||
br i1 %cmp, label %bb, label %exit
|
||||
|
||||
bb:
|
||||
; CHECK: %add = add nsw i32 %a, 1
|
||||
%add = add i32 %a, 1
|
||||
br label %exit
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test1(
|
||||
define void @test1(i32 %a) {
|
||||
entry:
|
||||
%cmp = icmp ult i32 %a, 100
|
||||
br i1 %cmp, label %bb, label %exit
|
||||
|
||||
bb:
|
||||
; CHECK: %add = add nuw nsw i32 %a, 1
|
||||
%add = add i32 %a, 1
|
||||
br label %exit
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test2(
|
||||
define void @test2(i32 %a) {
|
||||
entry:
|
||||
%cmp = icmp ult i32 %a, -1
|
||||
br i1 %cmp, label %bb, label %exit
|
||||
|
||||
bb:
|
||||
; CHECK: %add = add nuw i32 %a, 1
|
||||
%add = add i32 %a, 1
|
||||
br label %exit
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test3(
|
||||
define void @test3(i32 %a) {
|
||||
entry:
|
||||
%cmp = icmp ule i32 %a, -1
|
||||
br i1 %cmp, label %bb, label %exit
|
||||
|
||||
bb:
|
||||
; CHECK: %add = add i32 %a, 1
|
||||
%add = add i32 %a, 1
|
||||
br label %exit
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test4(
|
||||
define void @test4(i32 %a) {
|
||||
entry:
|
||||
%cmp = icmp slt i32 %a, 2147483647
|
||||
br i1 %cmp, label %bb, label %exit
|
||||
|
||||
bb:
|
||||
; CHECK: %add = add nsw i32 %a, 1
|
||||
%add = add i32 %a, 1
|
||||
br label %exit
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test5(
|
||||
define void @test5(i32 %a) {
|
||||
entry:
|
||||
%cmp = icmp sle i32 %a, 2147483647
|
||||
br i1 %cmp, label %bb, label %exit
|
||||
|
||||
bb:
|
||||
; CHECK: %add = add i32 %a, 1
|
||||
%add = add i32 %a, 1
|
||||
br label %exit
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
Loading…
Reference in New Issue