| commit 055779a9ac11e56442cbcdc73da59f8bce7ce57d |
| Author: Bob Haarman <llvm@inglorion.net> |
| Date: Mon Dec 2 17:23:54 2019 -0800 |
| |
| Revert "[InstCombine] keep assumption before sinking calls" |
| |
| Summary: |
| This reverts commit c3b06d0c393e533eab712922911d14e5a079fa5d. |
| |
| Reason for revert: Caused miscompiles when inserting assume for undef. |
| |
| Also adds a test to prevent similar breakage in future. |
| |
| Fixes PR44154. |
| |
| Reviewers: rnk, jdoerfert, efriedma, xbolva00 |
| |
| Reviewed By: rnk |
| |
| Subscribers: thakis, hiraditya, llvm-commits |
| |
| Tags: #llvm |
| |
| Differential Revision: https://reviews.llvm.org/D70933 |
| |
| diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp |
| index faaf5dcb2a4..5383da8fd86 100644 |
| --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp |
| +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp |
| @@ -3147,8 +3147,7 @@ Instruction *InstCombiner::visitFreeze(FreezeInst &I) { |
| /// beginning of DestBlock, which can only happen if it's safe to move the |
| /// instruction past all of the instructions between it and the end of its |
| /// block. |
| -static bool TryToSinkInstruction(Instruction *I, BasicBlock *DestBlock, |
| - InstCombiner::BuilderTy &Builder) { |
| +static bool TryToSinkInstruction(Instruction *I, BasicBlock *DestBlock) { |
| assert(I->hasOneUse() && "Invariants didn't hold!"); |
| BasicBlock *SrcBlock = I->getParent(); |
| |
| @@ -3182,24 +3181,6 @@ static bool TryToSinkInstruction(Instruction *I, BasicBlock *DestBlock, |
| if (Scan->mayWriteToMemory()) |
| return false; |
| } |
| - |
| - // If this instruction was providing nonnull guarantees insert assumptions for |
| - // nonnull call site arguments. |
| - if (auto CS = dyn_cast<CallBase>(I)) { |
| - for (unsigned Idx = 0; Idx != CS->getNumArgOperands(); Idx++) |
| - if (CS->paramHasAttr(Idx, Attribute::NonNull) || |
| - (CS->paramHasAttr(Idx, Attribute::Dereferenceable) && |
| - !llvm::NullPointerIsDefined(CS->getFunction(), |
| - CS->getArgOperand(Idx) |
| - ->getType() |
| - ->getPointerAddressSpace()))) { |
| - Value *V = CS->getArgOperand(Idx); |
| - |
| - Builder.SetInsertPoint(I->getParent(), I->getIterator()); |
| - Builder.CreateAssumption(Builder.CreateIsNotNull(V)); |
| - } |
| - } |
| - |
| BasicBlock::iterator InsertPos = DestBlock->getFirstInsertionPt(); |
| I->moveBefore(&*InsertPos); |
| ++NumSunkInst; |
| @@ -3334,7 +3315,7 @@ bool InstCombiner::run() { |
| // otherwise), we can keep going. |
| if (UserIsSuccessor && UserParent->getUniquePredecessor()) { |
| // Okay, the CFG is simple enough, try to sink this instruction. |
| - if (TryToSinkInstruction(I, UserParent, Builder)) { |
| + if (TryToSinkInstruction(I, UserParent)) { |
| LLVM_DEBUG(dbgs() << "IC: Sink: " << *I << '\n'); |
| MadeIRChange = true; |
| // We'll add uses of the sunk instruction below, but since sinking |
| diff --git a/llvm/test/Transforms/InstCombine/assume-replacing-call.ll b/llvm/test/Transforms/InstCombine/assume-replacing-call.ll |
| deleted file mode 100644 |
| index e039f61f67e..00000000000 |
| --- a/llvm/test/Transforms/InstCombine/assume-replacing-call.ll |
| +++ /dev/null |
| @@ -1,192 +0,0 @@ |
| -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| -; RUN: opt < %s -instcombine -S | FileCheck %s |
| -target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" |
| -target triple = "x86_64-unknown-linux-gnu" |
| - |
| -define i32 @test_sink_replacement1(i8* %p) { |
| -; CHECK-LABEL: @test_sink_replacement1( |
| -; CHECK-NEXT: entry: |
| -; CHECK-NEXT: [[TMP0:%.*]] = icmp ne i8* [[P:%.*]], null |
| -; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) |
| -; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i8* [[P]], null |
| -; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| -; CHECK: if.then: |
| -; CHECK-NEXT: br label [[CLEANUP:%.*]] |
| -; CHECK: if.end: |
| -; CHECK-NEXT: [[CALL:%.*]] = call i64 @func_test(i8* nonnull [[P]]) #2 |
| -; CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[CALL]] to i32 |
| -; CHECK-NEXT: br label [[CLEANUP]] |
| -; CHECK: cleanup: |
| -; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CONV]], [[IF_END]] ], [ -1, [[IF_THEN]] ] |
| -; CHECK-NEXT: ret i32 [[RETVAL_0]] |
| -; |
| -entry: |
| - %call = call i64 @func_test(i8* nonnull %p) #2 |
| - %conv = trunc i64 %call to i32 |
| - %tobool = icmp ne i8* %p, null |
| - br i1 %tobool, label %if.end, label %if.then |
| - |
| -if.then: |
| - br label %cleanup |
| - |
| -if.end: |
| - br label %cleanup |
| - |
| -cleanup: |
| - %retval.0 = phi i32 [ %conv, %if.end ], [ -1, %if.then ] |
| - ret i32 %retval.0 |
| -} |
| - |
| -define i32 @test_sink_replacement2(i8* %p) { |
| -; CHECK-LABEL: @test_sink_replacement2( |
| -; CHECK-NEXT: entry: |
| -; CHECK-NEXT: [[TMP0:%.*]] = icmp ne i8* [[P:%.*]], null |
| -; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) |
| -; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i8* [[P]], null |
| -; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| -; CHECK: if.then: |
| -; CHECK-NEXT: br label [[CLEANUP:%.*]] |
| -; CHECK: if.end: |
| -; CHECK-NEXT: [[CALL:%.*]] = call i64 @func_test(i8* nonnull dereferenceable(1) [[P]]) #2 |
| -; CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[CALL]] to i32 |
| -; CHECK-NEXT: br label [[CLEANUP]] |
| -; CHECK: cleanup: |
| -; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CONV]], [[IF_END]] ], [ -1, [[IF_THEN]] ] |
| -; CHECK-NEXT: ret i32 [[RETVAL_0]] |
| -; |
| -entry: |
| - %call = call i64 @func_test(i8* dereferenceable(1) %p) #2 |
| - %conv = trunc i64 %call to i32 |
| - %tobool = icmp ne i8* %p, null |
| - br i1 %tobool, label %if.end, label %if.then |
| - |
| -if.then: |
| - br label %cleanup |
| - |
| -if.end: |
| - br label %cleanup |
| - |
| -cleanup: |
| - %retval.0 = phi i32 [ %conv, %if.end ], [ -1, %if.then ] |
| - ret i32 %retval.0 |
| -} |
| - |
| -define i32 @test_sink_replacement3(i8* %p) { |
| -; CHECK-LABEL: @test_sink_replacement3( |
| -; CHECK-NEXT: entry: |
| -; CHECK-NEXT: [[TMP0:%.*]] = icmp ne i8* [[P:%.*]], null |
| -; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) |
| -; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i8* [[P]], null |
| -; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| -; CHECK: if.then: |
| -; CHECK-NEXT: br label [[CLEANUP:%.*]] |
| -; CHECK: if.end: |
| -; CHECK-NEXT: [[CALL:%.*]] = call i64 @func_test_nonnull(i8* [[P]]) #2 |
| -; CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[CALL]] to i32 |
| -; CHECK-NEXT: br label [[CLEANUP]] |
| -; CHECK: cleanup: |
| -; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CONV]], [[IF_END]] ], [ -1, [[IF_THEN]] ] |
| -; CHECK-NEXT: ret i32 [[RETVAL_0]] |
| -; |
| -entry: |
| - %call = call i64 @func_test_nonnull(i8* %p) #2 |
| - %conv = trunc i64 %call to i32 |
| - %tobool = icmp ne i8* %p, null |
| - br i1 %tobool, label %if.end, label %if.then |
| - |
| -if.then: |
| - br label %cleanup |
| - |
| -if.end: |
| - br label %cleanup |
| - |
| -cleanup: |
| - %retval.0 = phi i32 [ %conv, %if.end ], [ -1, %if.then ] |
| - ret i32 %retval.0 |
| -} |
| - |
| -define i32 @test_sink_replacement4(i8* %p) { |
| -; CHECK-LABEL: @test_sink_replacement4( |
| -; CHECK-NEXT: entry: |
| -; CHECK-NEXT: br label [[A:%.*]] |
| -; CHECK: a: |
| -; CHECK-NEXT: [[TMP0:%.*]] = icmp ne i8* [[P:%.*]], null |
| -; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) |
| -; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i8* [[P]], null |
| -; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| -; CHECK: if.then: |
| -; CHECK-NEXT: br label [[CLEANUP:%.*]] |
| -; CHECK: if.end: |
| -; CHECK-NEXT: [[CALL:%.*]] = call i64 @func_test(i8* nonnull dereferenceable(1) [[P]]) #2 |
| -; CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[CALL]] to i32 |
| -; CHECK-NEXT: br label [[CLEANUP]] |
| -; CHECK: cleanup: |
| -; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CONV]], [[IF_END]] ], [ -1, [[IF_THEN]] ] |
| -; CHECK-NEXT: ret i32 [[RETVAL_0]] |
| -; |
| -entry: |
| - br label %a |
| -a: |
| - %call = call i64 @func_test(i8* dereferenceable(1) %p) #2 |
| - %conv = trunc i64 %call to i32 |
| - %tobool = icmp ne i8* %p, null |
| - br i1 %tobool, label %if.end, label %if.then |
| - |
| -if.then: |
| - br label %cleanup |
| - |
| -if.end: |
| - br label %cleanup |
| - |
| -cleanup: |
| - %retval.0 = phi i32 [ %conv, %if.end ], [ -1, %if.then ] |
| - ret i32 %retval.0 |
| -} |
| - |
| -define i32 @test_sink_replacement5(i64 %i) { |
| -; CHECK-LABEL: @test_sink_replacement5( |
| -; CHECK-NEXT: entry: |
| -; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[I:%.*]] to i8* |
| -; CHECK-NEXT: br label [[A:%.*]] |
| -; CHECK: a: |
| -; CHECK-NEXT: [[TMP0:%.*]] = icmp ne i64 [[I]], 0 |
| -; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) |
| -; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[I]], 0 |
| -; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| -; CHECK: if.then: |
| -; CHECK-NEXT: br label [[CLEANUP:%.*]] |
| -; CHECK: if.end: |
| -; CHECK-NEXT: [[CALL:%.*]] = call i64 @func_test(i8* nonnull dereferenceable(1) [[P]]) #2 |
| -; CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[CALL]] to i32 |
| -; CHECK-NEXT: br label [[CLEANUP]] |
| -; CHECK: cleanup: |
| -; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CONV]], [[IF_END]] ], [ -1, [[IF_THEN]] ] |
| -; CHECK-NEXT: ret i32 [[RETVAL_0]] |
| -; |
| -entry: |
| - %p = inttoptr i64 %i to i8* |
| - br label %a |
| -a: |
| - %call = call i64 @func_test(i8* dereferenceable(1) %p) #2 |
| - %conv = trunc i64 %call to i32 |
| - %tobool = icmp ne i8* %p, null |
| - br i1 %tobool, label %if.end, label %if.then |
| - |
| -if.then: |
| - br label %cleanup |
| - |
| -if.end: |
| - br label %cleanup |
| - |
| -cleanup: |
| - %retval.0 = phi i32 [ %conv, %if.end ], [ -1, %if.then ] |
| - ret i32 %retval.0 |
| -} |
| - |
| -declare i64 @func_test(i8* %0) #1 |
| - |
| -declare i64 @func_test_nonnull(i8* nonnull %0) #3 |
| - |
| -attributes #1 = { readonly } |
| -attributes #2 = { nounwind } |
| -attributes #3 = { readonly } |
| diff --git a/llvm/test/Transforms/InstCombine/unused-nonnull.ll b/llvm/test/Transforms/InstCombine/unused-nonnull.ll |
| new file mode 100644 |
| index 00000000000..518cd268ea1 |
| --- /dev/null |
| +++ b/llvm/test/Transforms/InstCombine/unused-nonnull.ll |
| @@ -0,0 +1,45 @@ |
| +; PR44154: LLVM c3b06d0c393e caused the body of @main to be replaced with |
| +; unreachable. Check that we perform the expected calls and optimizations. |
| +; |
| +; RUN: opt -S -O3 -o - %s | FileCheck %s |
| +; CHECK-LABEL: @main |
| +; CHECK: %0 = icmp slt i32 %argc, 2 |
| +; CHECK-NEXT: br i1 %0, label %done, label %do_work |
| +; CHECK-LABEL: do_work: |
| +; CHECK: %1 = tail call i32 @compute( |
| +; CHECK-LABEL: done: |
| +; CHECK: %retval = phi i32 [ 0, %entry ], [ %1, %do_work ] |
| +; CHECK-NEXT: ret i32 %retval |
| + |
| +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" |
| +target triple = "x86_64-unknown-linux-gnu" |
| + |
| +define i32 @main(i32 %argc, i8** %argv) #0 { |
| +entry: |
| + %0 = getelementptr inbounds i8*, i8** %argv, i32 0 |
| + %ptr = load i8*, i8** %0 |
| + %1 = call i32 @compute(i8* %ptr, i32 %argc) |
| + %2 = icmp slt i32 %argc, 2 |
| + br i1 %2, label %done, label %do_work |
| + |
| +do_work: |
| + %3 = icmp eq i8* %ptr, null |
| + br i1 %3, label %null, label %done |
| + |
| +null: |
| + call void @call_if_null(i8* %ptr) |
| + br label %done |
| + |
| +done: |
| + %retval = phi i32 [0, %entry], [%1, %do_work], [%1, %null] |
| + ret i32 %retval |
| +} |
| + |
| +define i32 @compute(i8* nonnull %ptr, i32 %x) #1 { |
| + ret i32 %x |
| +} |
| + |
| +declare void @call_if_null(i8* %ptr) #0 |
| + |
| +attributes #0 = { nounwind } |
| +attributes #1 = { noinline nounwind readonly } |