OSDN Git Service

[DCE] Don't remove non-willreturn calls
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 18 Feb 2021 21:29:19 +0000 (22:29 +0100)
committerTom Stellard <tstellar@redhat.com>
Sat, 20 Feb 2021 00:32:07 +0000 (16:32 -0800)
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)

llvm/lib/Analysis/DemandedBits.cpp
llvm/lib/Transforms/Scalar/ADCE.cpp
llvm/test/Feature/OperandBundles/adce.ll
llvm/test/LTO/X86/parallel.ll
llvm/test/Transforms/ADCE/dce_pure_call.ll
llvm/test/Transforms/ADCE/willreturn.ll
llvm/test/Transforms/BDCE/dce-pure.ll
llvm/test/Transforms/BDCE/dead-void-ro.ll
llvm/test/Transforms/BDCE/willreturn.ll
llvm/test/tools/gold/X86/parallel.ll

index 461fd72..dd11b0b 100644 (file)
@@ -80,7 +80,7 @@ void DemandedBitsWrapperPass::print(raw_ostream &OS, const Module *M) const {
 
 static bool isAlwaysLive(Instruction *I) {
   return I->isTerminator() || isa<DbgInfoIntrinsic>(I) || I->isEHPad() ||
-         I->mayHaveSideEffects();
+         I->mayHaveSideEffects() || !I->willReturn();
 }
 
 void DemandedBits::determineLiveOperandBits(
index 2b64973..ce4e5e5 100644 (file)
@@ -325,7 +325,7 @@ void AggressiveDeadCodeElimination::initialize() {
 
 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))
index a729ba7..fa4e045 100644 (file)
@@ -5,8 +5,8 @@
 ; 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(
index b3c1281..34235ec 100644 (file)
@@ -11,7 +11,7 @@ target triple = "x86_64-unknown-linux-gnu"
 ; CHECK0-NOT: bar
 ; CHECK0: T foo
 ; CHECK0-NOT: bar
-define void @foo() {
+define void @foo() mustprogress {
   call void @bar()
   ret void
 }
@@ -19,7 +19,7 @@ define void @foo() {
 ; CHECK1-NOT: foo
 ; CHECK1: T bar
 ; CHECK1-NOT: foo
-define void @bar() {
+define void @bar() mustprogress {
   call void @foo()
   ret void
 }
index 66483ab..88e92bf 100644 (file)
@@ -1,6 +1,6 @@
 ; 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]
index c3482a4..61bbbe0 100644 (file)
@@ -4,9 +4,10 @@
 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
index a487a04..e00121d 100644 (file)
@@ -1,7 +1,7 @@
 ; 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 )
index 36f0951..77f4e09 100644 (file)
@@ -14,5 +14,5 @@ define void @PR34211(i16* %p) {
 
 declare void @no_side_effects_so_dead(i16) #0
 
-attributes #0 = { nounwind readnone }
+attributes #0 = { nounwind readnone willreturn }
 
index b87ab00..5efd6ad 100644 (file)
@@ -4,9 +4,10 @@
 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
index 6972efc..b8072f0 100644 (file)
@@ -14,7 +14,7 @@ target triple = "x86_64-unknown-linux-gnu"
 ; CHECK0-NOT: bar
 ; CHECK0: T foo
 ; CHECK0-NOT: bar
-define void @foo() {
+define void @foo() mustprogress {
   call void @bar()
   ret void
 }
@@ -24,7 +24,7 @@ define void @foo() {
 ; CHECK1-NOT: foo
 ; CHECK1: T bar
 ; CHECK1-NOT: foo
-define void @bar() {
+define void @bar() mustprogress {
   call void @foo()
   ret void
 }