forked from OSchip/llvm-project
Revert "[InstCombine] keep assumption before sinking calls"
Summary:
This reverts commit c3b06d0c39
.
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
This commit is contained in:
parent
52812f2ade
commit
055779a9ac
|
@ -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
|
||||
|
|
|
@ -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 }
|
|
@ -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 }
|
Loading…
Reference in New Issue