Compiler projects using llvm
; Test that unreachable functions are ignored by WPD in hybrid LTO, and thin LTO.
; In this test case, the unreachable function is the virtual deleting destructor of an abstract class.

; Generate split module with summary for hybrid Regular LTO WPD
; RUN: opt -thinlto-bc -thinlto-split-lto-unit %s -o %t-main.bc
; RUN: opt -thinlto-bc -thinlto-split-lto-unit %p/Inputs/devirt_after_filtering_unreachable_lib.ll -o %t-foo.bc

; Check that deleting destructor of pure virtual class is unreachable.

; Check that deleting destructor of pure virtual class is unreachable.
; RUN: llvm-modextract -b -n=0 %t-foo.bc -o %t-foo.bc.0
; RUN: llvm-dis -o - %t-foo.bc.0 | FileCheck %s --check-prefix=UNREACHABLEFLAG

; Tests that devirtualization happens.
; RUN: llvm-lto2 run -save-temps %t-main.bc %t-foo.bc -pass-remarks=. -o %t \
; RUN:   -whole-program-visibility \
; RUN:   -r=%t-foo.bc,_Z3fooP4Base,pl \
; RUN:   -r=%t-foo.bc,_ZN7DerivedD0Ev,pl \
; RUN:   -r=%t-foo.bc,_ZN4BaseD0Ev,pl \
; RUN:   -r=%t-foo.bc,_ZTV7Derived,l \
; RUN:   -r=%t-foo.bc,_ZTV4Base,l \
; RUN:   -r=%t-foo.bc,_ZN7DerivedD0Ev, \
; RUN:   -r=%t-foo.bc,_ZN4BaseD0Ev, \
; RUN:   -r=%t-foo.bc,_ZTV7Derived,pl \
; RUN:   -r=%t-foo.bc,_ZTV4Base,pl \
; RUN:   -r=%t-main.bc,main,plx \
; RUN:   -r=%t-main.bc,_Znwm,pl \
; RUN:   -r=%t-main.bc,_Z3fooP4Base, \
; RUN:   -r=%t-main.bc,_ZTV7Derived, 2>&1 | FileCheck %s --check-prefix=REMARK
 
; REMARK-COUNT-1: single-impl: devirtualized a call to _ZN7DerivedD0Ev

; Generate unsplit module with summary for ThinLTO index-based WPD.
; RUN: opt -thinlto-bc -o %t3.o %s

; Check that deleting destructor of pure virtual class is unreachable.
; RUN: opt -thinlto-bc -o %t4.o %p/Inputs/devirt_after_filtering_unreachable_lib.ll
; RUN: llvm-dis -o - %t4.o | FileCheck %s --check-prefix=UNREACHABLEFLAG

; UNREACHABLEFLAG: gv: (name: "_ZN4BaseD0Ev", {{.*}}, funcFlags: ({{.*}} mustBeUnreachable: 1

; Test that devirtualized happen in index based WPD
; RUN: llvm-lto2 run %t4.o %t3.o -save-temps -pass-remarks=. \
; RUN:   -whole-program-visibility \
; RUN:   -wholeprogramdevirt-print-index-based \
; RUN:   -o %t5 \
; RUN:   -r=%t4.o,_Z3fooP4Base,pl \
; RUN:   -r=%t4.o,_ZN7DerivedD0Ev,pl \
; RUN:   -r=%t4.o,_ZN4BaseD0Ev,pl \
; RUN:   -r=%t4.o,_ZTV7Derived,pl \
; RUN:   -r=%t4.o,_ZTV4Base,pl \
; RUN:   -r=%t3.o,main,plx \
; RUN:   -r=%t3.o,_Znwm, \
; RUN:   -r=%t3.o,_Z3fooP4Base, \
; RUN:   -r=%t3.o,_ZTV7Derived,  2>&1 | FileCheck %s --check-prefix=THINREMARK

; THINREMARK: Devirtualized call to {{.*}} (_ZN7DerivedD0Ev)
; THINREMARK: single-impl: devirtualized a call to _ZN7DerivedD0Ev
; THINREMARK: single-impl: devirtualized a call to _ZN7DerivedD0Ev

; ModuleID = 'tmp.cc'
source_filename = "tmp.cc"
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"

%Derived = type { %Base }
%Base = type { i32 (...)** }

@_ZTV7Derived = external constant { [5 x i8*] }

define hidden i32 @main() {
entry:
  %call = tail call i8* @_Znwm(i64 8)
  %0 = bitcast i8* %call to %Derived*
  %1 = getelementptr inbounds %Derived, %Derived* %0, i64 0, i32 0, i32 0
  store i32 (...)** bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTV7Derived, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %1
  %2 = getelementptr %Derived, %Derived* %0, i64 0, i32 0
  tail call void @_Z3fooP4Base(%Base* nonnull %2)
  ret i32 0
}

declare i8* @_Znwm(i64)

declare void @_Z3fooP4Base(%Base*)