## Check that BOLT handles correctly folding functions with --icf=safe
## that can be referenced through a non control flow instruction when ICP optimization is enabled.
## This tests also checks that destructors are folded.

# REQUIRES: system-linux, asserts
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o
# RUN: %clang %cflags %t1.o -o %t.exe -Wl,-q
# RUN: llvm-bolt --no-threads %t.exe --icf      -debug-only=bolt-icf -o %t.bolt 2>&1 | FileCheck --check-prefix=ICFCHECK %s
# RUN: llvm-bolt --no-threads %t.exe --icf=safe -debug-only=bolt-icf -o %t.bolt 2>&1 | FileCheck --check-prefix=SAFEICFCHECK %s

# ICFCHECK:      ICF iteration 1
# ICFCHECK-NEXT: folding Derived3Destructor into Derived2Destructor
# ICFCHECK-NEXT: folding Derived3Func into Derived2Func

# SAFEICFCHECK: skipping function with reference taken Derived3Func
# SAFEICFCHECK-NEXT: ICF iteration 1
# SAFEICFCHECK-NEXT: folding Derived3Destructor into Derived2Destructor


## generate profile
## clang++ -O2 -fprofile-generate=. main.cpp   -c -o mainProf.o
## PROF=test.profdata
## clang++ -m64  -fprofile-use=$PROF \
##   -mllvm -disable-icp=true -mllvm -print-after-all \
##   -g0 -flto=thin -fwhole-program-vtables -fno-split-lto-unit -O2 \
##   -fdebug-types-section \
##   main.cpp -c -o mainProfLTO.bc
## PASS='pgo-icall-prom'
## clang++ -m64  -fprofile-use=$PROF \
##   -O3 -Rpass=$PASS \
##   -mllvm -print-before=$PASS \
##   -mllvm -print-after=$PASS \
##   -mllvm -filter-print-funcs=main \
##   -mllvm -debug-only=$PASS \
##   -x ir \
##   mainProfLTO.bc -c -o mainProfFinal.o

## class Base {
## public:
##   virtual int func(int a, int b) const = 0;
##
##   virtual ~Base() {};
## };
##
## class Derived2 : public Base {
##   int c = 5;
## public:
##   __attribute__((noinline)) int func(int a, int b)const override { return a * (a - b) + this->c; }
##
##   ~Derived2() {}
## };
##
## class Derived3 : public Base {
##   int c = 500;
## public:
##   __attribute__((noinline)) int func(int a, int b) const override { return a * (a - b) + this->c; }
##   ~Derived3() {}
## };
##
## __attribute__((noinline)) Base *createType(int a) {
##     Base *base = nullptr;
##     if (a == 4)
##       base = new Derived2();
##     else
##       base = new Derived3();
##     return base;
## }
##
## extern int returnFive();
## extern int returnFourOrFive(int val);
## int main(int argc, char **argv) {
##   int sum = 0;
##   int a = returnFourOrFive(argc);
##   int b = returnFive();
##   Base *ptr = createType(a);
##   Base *ptr2 = createType(b);
##   sum += ptr->func(b, a) + ptr2->func(b, a);
##   return 0;
## }
## clang++ -c helper.cpp -o helper.o
## int FooVar = 1;
## int BarVar = 2;
##
## int fooGlobalFuncHelper(int a, int b) {
##   return 5;
## }
## Manually modified to remove "extra" assembly.
	.globl	main
	.type	main,@function
main:
	leaq	Derived3Func(%rip), %rcx
	callq	Derived3Func
	.size	main, .-main

	.weak	Derived2Func
	.type	Derived2Func,@function
Derived2Func:
	imull	%esi, %eax
	retq
	.size	Derived2Func, .-Derived2Func

	.weak	Derived2Destructor
	.type	Derived2Destructor,@function
Derived2Destructor:
	jmp	_ZdlPvm@PLT
	.size	Derived2Destructor, .-Derived2Destructor

	.weak	Derived3Func
	.type	Derived3Func,@function
Derived3Func:
	imull	%esi, %eax
	retq
	.size	Derived3Func, .-Derived3Func

	.weak	_ZN4BaseD2Ev
	.type	_ZN4BaseD2Ev,@function
_ZN4BaseD2Ev:
	retq
	.size	_ZN4BaseD2Ev, .-_ZN4BaseD2Ev

	.weak	Derived3Destructor
	.type	Derived3Destructor,@function
Derived3Destructor:
	jmp	_ZdlPvm@PLT
	.size	Derived3Destructor, .-Derived3Destructor

	.type	_ZTV8Derived2,@object
	.section	.data.rel.ro._ZTV8Derived2,"awG",@progbits,_ZTV8Derived2,comdat
	.weak	_ZTV8Derived2
_ZTV8Derived2:
	.quad	0
	.quad	_ZTI8Derived2
	.quad	Derived2Func
	.quad	_ZN4BaseD2Ev
	.quad	Derived2Destructor
	.size	_ZTV8Derived2, 40

	.type	_ZTV8Derived3,@object
	.section	.data.rel.ro._ZTV8Derived3,"awG",@progbits,_ZTV8Derived3,comdat
	.weak	_ZTV8Derived3
_ZTV8Derived3:
	.quad	0
	.quad	_ZTI8Derived3
	.quad	Derived3Func
	.quad	_ZN4BaseD2Ev
	.quad	Derived3Destructor
	.size	_ZTV8Derived3, 40
