From 68cb947cc92d9c3ba7e97cbb635d6927ee13363c Mon Sep 17 00:00:00 2001 From: Artur Pilipenko Date: Wed, 3 Aug 2016 13:11:39 +0000 Subject: [PATCH] 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 --- .../Scalar/CorrelatedValuePropagation.cpp | 57 ++++++++++++ .../CorrelatedValuePropagation/add.ll | 91 +++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 llvm/test/Transforms/CorrelatedValuePropagation/add.ll diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp index c0fed0533392..8b0d7e4d19aa 100644 --- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -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 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(II), LVI); break; + case Instruction::Add: + BBChanged |= processAdd(cast(II), LVI); + break; } } diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/add.ll b/llvm/test/Transforms/CorrelatedValuePropagation/add.ll new file mode 100644 index 000000000000..9f3f99bcadd5 --- /dev/null +++ b/llvm/test/Transforms/CorrelatedValuePropagation/add.ll @@ -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 +}