In both ADCE and BDCE (via DemandedBits) we should not remove
instructions that are not guaranteed to return. This issue was
pointed out by fhahn in the recent llvm-dev thread.
Differential Revision: https://reviews.llvm.org/D96993
(cherry picked from commit
2f17ed294fcd8cde505b93c9c5bbab06ba59051c)
static bool isAlwaysLive(Instruction *I) {
return I->isTerminator() || isa<DbgInfoIntrinsic>(I) || I->isEHPad() ||
- I->mayHaveSideEffects();
+ I->mayHaveSideEffects() || !I->willReturn();
}
void DemandedBits::determineLiveOperandBits(
bool AggressiveDeadCodeElimination::isAlwaysLive(Instruction &I) {
// TODO -- use llvm::isInstructionTriviallyDead
- if (I.isEHPad() || I.mayHaveSideEffects()) {
+ if (I.isEHPad() || I.mayHaveSideEffects() || !I.willReturn()) {
// Skip any value profile instrumentation calls if they are
// instrumenting constants.
if (isInstrumentsConstant(I))
; bundles since the presence of unknown operand bundles implies
; arbitrary memory effects.
-declare void @readonly_function() readonly nounwind
-declare void @readnone_function() readnone nounwind
+declare void @readonly_function() readonly nounwind willreturn
+declare void @readnone_function() readnone nounwind willreturn
define void @test0() {
; CHECK-LABEL: @test0(
; CHECK0-NOT: bar
; CHECK0: T foo
; CHECK0-NOT: bar
-define void @foo() {
+define void @foo() mustprogress {
call void @bar()
ret void
}
; CHECK1-NOT: foo
; CHECK1: T bar
; CHECK1-NOT: foo
-define void @bar() {
+define void @bar() mustprogress {
call void @foo()
ret void
}
; RUN: opt -adce -S < %s | not grep call
-declare i32 @strlen(i8*) readonly nounwind
+declare i32 @strlen(i8*) readonly nounwind willreturn
define void @test() {
call i32 @strlen( i8* null ) ; <i32>:1 [#uses=0]
declare void @may_not_return(i32) nounwind readnone
declare void @will_return(i32) nounwind readnone willreturn
-; FIXME: This is a miscompile.
define void @test(i32 %a) {
; CHECK-LABEL: @test(
+; CHECK-NEXT: [[B:%.*]] = add i32 [[A:%.*]], 1
+; CHECK-NEXT: call void @may_not_return(i32 [[B]])
; CHECK-NEXT: ret void
;
%b = add i32 %a, 1
; RUN: opt -bdce -S < %s | FileCheck %s
; RUN: opt -passes=bdce -S < %s | FileCheck %s
-declare i32 @strlen(i8*) readonly nounwind
+declare i32 @strlen(i8*) readonly nounwind willreturn
define void @test1() {
call i32 @strlen( i8* null )
declare void @no_side_effects_so_dead(i16) #0
-attributes #0 = { nounwind readnone }
+attributes #0 = { nounwind readnone willreturn }
declare void @may_not_return(i32) nounwind readnone
declare void @will_return(i32) nounwind readnone willreturn
-; FIXME: This is a miscompile.
define void @test(i32 %a) {
; CHECK-LABEL: @test(
+; CHECK-NEXT: [[B:%.*]] = add i32 [[A:%.*]], 1
+; CHECK-NEXT: call void @may_not_return(i32 [[B]])
; CHECK-NEXT: ret void
;
%b = add i32 %a, 1
; CHECK0-NOT: bar
; CHECK0: T foo
; CHECK0-NOT: bar
-define void @foo() {
+define void @foo() mustprogress {
call void @bar()
ret void
}
; CHECK1-NOT: foo
; CHECK1: T bar
; CHECK1-NOT: foo
-define void @bar() {
+define void @bar() mustprogress {
call void @foo()
ret void
}