mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
75870000ad
Identify dynamically exported symbols (--export-dynamic[-symbol=], --dynamic-list=, or definitions needed to preempt shared objects) and prevent their LTO visibility from being upgraded. This helps avoid use of whole program devirtualization when there may be overrides in dynamic libraries. Differential Revision: https://reviews.llvm.org/D91583
148 lines
5.9 KiB
LLVM
148 lines
5.9 KiB
LLVM
;; Test that plugin option whole-program-visibility enables devirtualization.
|
|
|
|
;; Index based WPD
|
|
;; Generate unsplit module with summary for ThinLTO index-based WPD.
|
|
; RUN: opt -thinlto-bc -o %t2.o %s
|
|
; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext \
|
|
; RUN: --plugin-opt=whole-program-visibility \
|
|
; RUN: --plugin-opt=save-temps \
|
|
; RUN: --plugin-opt=-pass-remarks=. \
|
|
; RUN: %t2.o -o %t3 2>&1 | FileCheck %s --check-prefix=REMARK
|
|
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
|
|
|
|
;; Hybrid WPD
|
|
;; Generate split module with summary for hybrid Thin/Regular LTO WPD.
|
|
; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t.o %s
|
|
; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext \
|
|
; RUN: --plugin-opt=whole-program-visibility \
|
|
; RUN: --plugin-opt=save-temps \
|
|
; RUN: --plugin-opt=-pass-remarks=. \
|
|
; RUN: %t.o -o %t3 2>&1 | FileCheck %s --check-prefix=REMARK
|
|
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
|
|
|
|
;; Regular LTO WPD
|
|
; RUN: opt -o %t4.o %s
|
|
; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext \
|
|
; RUN: --plugin-opt=whole-program-visibility \
|
|
; RUN: --plugin-opt=save-temps \
|
|
; RUN: --plugin-opt=-pass-remarks=. \
|
|
; RUN: %t4.o -o %t3 2>&1 | FileCheck %s --check-prefix=REMARK
|
|
; RUN: llvm-dis %t3.0.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
|
|
|
|
; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi
|
|
; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEi
|
|
|
|
;; Try everything again but without -whole-program-visibility to confirm
|
|
;; WPD fails
|
|
|
|
;; Index based WPD
|
|
; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext \
|
|
; RUN: --plugin-opt=save-temps \
|
|
; RUN: --plugin-opt=-pass-remarks=. \
|
|
; RUN: %t2.o -o %t3 \
|
|
; RUN: 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
|
|
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
|
|
|
|
;; Hybrid WPD
|
|
; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext \
|
|
; RUN: --plugin-opt=save-temps \
|
|
; RUN: --plugin-opt=-pass-remarks=. \
|
|
; RUN: %t.o -o %t3 \
|
|
; RUN: 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
|
|
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
|
|
|
|
;; Regular LTO WPD
|
|
; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext \
|
|
; RUN: --plugin-opt=save-temps \
|
|
; RUN: --plugin-opt=-pass-remarks=. \
|
|
; RUN: %t4.o -o %t3 \
|
|
; RUN: 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
|
|
; RUN: llvm-dis %t3.0.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
|
|
|
|
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-grtev4-linux-gnu"
|
|
|
|
%struct.A = type { i32 (...)** }
|
|
%struct.B = type { %struct.A }
|
|
%struct.C = type { %struct.A }
|
|
%struct.D = type { i32 (...)** }
|
|
|
|
@_ZTV1B = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.B*, i32)* @_ZN1B1fEi to i8*), i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0, !type !1, !vcall_visibility !5
|
|
@_ZTV1C = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.C*, i32)* @_ZN1C1fEi to i8*), i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0, !type !2, !vcall_visibility !5
|
|
@_ZTV1D = constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.D*, i32)* @_ZN1D1mEi to i8*)] }, !type !3, !vcall_visibility !5
|
|
|
|
; Prevent the vtables from being dead code eliminated.
|
|
@llvm.used = appending global [3 x i8*] [ i8* bitcast ( { [4 x i8*] }* @_ZTV1B to i8*), i8* bitcast ( { [4 x i8*] }* @_ZTV1C to i8*), i8* bitcast ( { [3 x i8*] }* @_ZTV1D to i8*)]
|
|
|
|
; CHECK-IR-LABEL: define dso_local i32 @_start
|
|
define i32 @_start(%struct.A* %obj, %struct.D* %obj2, i32 %a) {
|
|
entry:
|
|
%0 = bitcast %struct.A* %obj to i8***
|
|
%vtable = load i8**, i8*** %0
|
|
%1 = bitcast i8** %vtable to i8*
|
|
%p = call i1 @llvm.type.test(i8* %1, metadata !"_ZTS1A")
|
|
call void @llvm.assume(i1 %p)
|
|
%fptrptr = getelementptr i8*, i8** %vtable, i32 1
|
|
%2 = bitcast i8** %fptrptr to i32 (%struct.A*, i32)**
|
|
%fptr1 = load i32 (%struct.A*, i32)*, i32 (%struct.A*, i32)** %2, align 8
|
|
|
|
;; Check that the call was devirtualized.
|
|
; CHECK-IR: %call = tail call i32 @_ZN1A1nEi
|
|
; CHECK-NODEVIRT-IR: %call = tail call i32 %fptr1
|
|
%call = tail call i32 %fptr1(%struct.A* nonnull %obj, i32 %a)
|
|
|
|
%3 = bitcast i8** %vtable to i32 (%struct.A*, i32)**
|
|
%fptr22 = load i32 (%struct.A*, i32)*, i32 (%struct.A*, i32)** %3, align 8
|
|
|
|
;; We still have to call it as virtual.
|
|
; CHECK-IR: %call3 = tail call i32 %fptr22
|
|
; CHECK-NODEVIRT-IR: %call3 = tail call i32 %fptr22
|
|
%call3 = tail call i32 %fptr22(%struct.A* nonnull %obj, i32 %call)
|
|
|
|
%4 = bitcast %struct.D* %obj2 to i8***
|
|
%vtable2 = load i8**, i8*** %4
|
|
%5 = bitcast i8** %vtable2 to i8*
|
|
%p2 = call i1 @llvm.type.test(i8* %5, metadata !4)
|
|
call void @llvm.assume(i1 %p2)
|
|
|
|
%6 = bitcast i8** %vtable2 to i32 (%struct.D*, i32)**
|
|
%fptr33 = load i32 (%struct.D*, i32)*, i32 (%struct.D*, i32)** %6, align 8
|
|
|
|
;; Check that the call was devirtualized.
|
|
; CHECK-IR: %call4 = tail call i32 @_ZN1D1mEi
|
|
; CHECK-NODEVIRT-IR: %call4 = tail call i32 %fptr33
|
|
%call4 = tail call i32 %fptr33(%struct.D* nonnull %obj2, i32 %call3)
|
|
ret i32 %call4
|
|
}
|
|
; CHECK-IR-LABEL: ret i32
|
|
; CHECK-IR-LABEL: }
|
|
|
|
declare i1 @llvm.type.test(i8*, metadata)
|
|
declare void @llvm.assume(i1)
|
|
|
|
define i32 @_ZN1B1fEi(%struct.B* %this, i32 %a) #0 {
|
|
ret i32 0;
|
|
}
|
|
|
|
define i32 @_ZN1A1nEi(%struct.A* %this, i32 %a) #0 {
|
|
ret i32 0;
|
|
}
|
|
|
|
define i32 @_ZN1C1fEi(%struct.C* %this, i32 %a) #0 {
|
|
ret i32 0;
|
|
}
|
|
|
|
define i32 @_ZN1D1mEi(%struct.D* %this, i32 %a) #0 {
|
|
ret i32 0;
|
|
}
|
|
|
|
;; Make sure we don't inline or otherwise optimize out the direct calls.
|
|
attributes #0 = { noinline optnone }
|
|
|
|
!0 = !{i64 16, !"_ZTS1A"}
|
|
!1 = !{i64 16, !"_ZTS1B"}
|
|
!2 = !{i64 16, !"_ZTS1C"}
|
|
!3 = !{i64 16, !4}
|
|
!4 = distinct !{}
|
|
!5 = !{i64 0}
|