#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"
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;
case Instruction::SDiv:
BBChanged |= processSDiv(cast<BinaryOperator>(II), LVI);
break;
+ case Instruction::Add:
+ BBChanged |= processAdd(cast<BinaryOperator>(II), LVI);
+ break;
}
}
--- /dev/null
+; 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
+}