mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-19 11:35:51 -04:00

Summary: Third part in series to support Safe Whole Program Devirtualization Enablement, see RFC here: http://lists.llvm.org/pipermail/llvm-dev/2019-December/137543.html This patch adds type test metadata under -fwhole-program-vtables, even for classes without hidden visibility. It then changes WPD to skip devirtualization for a virtual function call when any of the compatible vtables has public vcall visibility. Additionally, internal LLVM options as well as lld and gold-plugin options are added which enable upgrading all public vcall visibility to linkage unit (hidden) visibility during LTO. This enables the more aggressive WPD to kick in based on LTO time knowledge of the visibility guarantees. Support was added to all flavors of LTO WPD (regular, hybrid and index-only), and to both the new and old LTO APIs. Unfortunately it was not simple to split the first and second parts of this part of the change (the unconditional emission of type tests and the upgrading of the vcall visiblity) as I needed a way to upgrade the public visibility on legacy WPD llvm assembly tests that don't include linkage unit vcall visibility specifiers, to avoid a lot of test churn. I also added a mechanism to LowerTypeTests that allows dropping type test assume sequences we now aggressively insert when we invoke distributed ThinLTO backends with null indexes, which is used in testing mode, and which doesn't invoke the normal ThinLTO backend pipeline. Depends on D71907 and D71911. Reviewers: pcc, evgeny777, steven_wu, espindola Subscribers: emaste, Prazek, inglorion, arichardson, hiraditya, MaskRay, dexonsmith, dang, davidxl, cfe-commits, llvm-commits Tags: #clang, #llvm Differential Revision: https://reviews.llvm.org/D71913
70 lines
2.2 KiB
LLVM
70 lines
2.2 KiB
LLVM
; RUN: opt -S -wholeprogramdevirt -whole-program-visibility %s | FileCheck %s
|
|
; RUN: opt -S -passes=wholeprogramdevirt -whole-program-visibility %s | FileCheck %s
|
|
|
|
target datalayout = "e-p:64:64"
|
|
target triple = "x86_64-unknown-linux-gnu"
|
|
|
|
@vt1 = constant [2 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1a to i8*), i8* bitcast (i32 (i8*, i32)* @vf1b to i8*)], !type !0
|
|
@vt2 = constant [2 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2a to i8*), i8* bitcast (i32 (i8*, i32)* @vf2b to i8*)], !type !0
|
|
|
|
@sink = external global i32
|
|
|
|
define i32 @vf1a(i8* %this, i32 %arg) {
|
|
store i32 %arg, i32* @sink
|
|
ret i32 %arg
|
|
}
|
|
|
|
define i32 @vf2a(i8* %this, i32 %arg) {
|
|
store i32 %arg, i32* @sink
|
|
ret i32 %arg
|
|
}
|
|
|
|
define i32 @vf1b(i8* %this, i32 %arg) {
|
|
ret i32 %arg
|
|
}
|
|
|
|
define i32 @vf2b(i8* %this, i32 %arg) {
|
|
ret i32 %arg
|
|
}
|
|
|
|
; Test that we don't apply VCP if the virtual function body accesses memory,
|
|
; even if the function returns a constant.
|
|
|
|
; CHECK: define i32 @call1
|
|
define i32 @call1(i8* %obj) {
|
|
%vtableptr = bitcast i8* %obj to [1 x i8*]**
|
|
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
|
|
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
|
|
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
|
|
call void @llvm.assume(i1 %p)
|
|
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
|
|
%fptr = load i8*, i8** %fptrptr
|
|
%fptr_casted = bitcast i8* %fptr to i32 (i8*, i32)*
|
|
; CHECK: call i32 %
|
|
%result = call i32 %fptr_casted(i8* %obj, i32 1)
|
|
ret i32 %result
|
|
}
|
|
|
|
; Test that we can apply VCP regardless of the function attributes by analyzing
|
|
; the function body itself.
|
|
|
|
; CHECK: define i32 @call2
|
|
define i32 @call2(i8* %obj) {
|
|
%vtableptr = bitcast i8* %obj to [1 x i8*]**
|
|
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
|
|
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
|
|
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
|
|
call void @llvm.assume(i1 %p)
|
|
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 1
|
|
%fptr = load i8*, i8** %fptrptr
|
|
%fptr_casted = bitcast i8* %fptr to i32 (i8*, i32)*
|
|
%result = call i32 %fptr_casted(i8* %obj, i32 1)
|
|
; CHECK: ret i32 1
|
|
ret i32 %result
|
|
}
|
|
|
|
declare i1 @llvm.type.test(i8*, metadata)
|
|
declare void @llvm.assume(i1)
|
|
|
|
!0 = !{i32 0, !"typeid"}
|