Skip to content

Commit 7110510

Browse files
committed
[WPD] Don't optimize calls more than once
WPD currently assumes that there is a one to one correspondence between type test assume sequences and virtual calls. However, with -fstrict-vtable-pointers this may not be true. This ends up causing crashes when we try to optimize a virtual call more than once ( applyUniformRetValOpt()/applyUniqueRetValOpt()/applyVirtualConstProp()/applySingleImplDevirt()). applySingleImplDevirt() actually didn't previous crash because it would replace the devirtualized call with the same direct call. Adding an assert that the call is indirect causes the corresponding test to crash with the rest of the patch. This makes Chrome successfully build with -fstrict-vtable-pointers + WPD. Reviewed By: tejohnson Differential Revision: https://reviews.llvm.org/D104798
1 parent a08fa8a commit 7110510

File tree

5 files changed

+172
-1
lines changed

5 files changed

+172
-1
lines changed

llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,11 @@ struct DevirtModule {
518518

519519
MapVector<VTableSlot, VTableSlotInfo> CallSlots;
520520

521+
// Calls that have already been optimized. We may add a call to multiple
522+
// VTableSlotInfos if vtable loads are coalesced and need to make sure not to
523+
// optimize a call more than once.
524+
SmallPtrSet<CallBase *, 8> OptimizedCalls;
525+
521526
// This map keeps track of the number of "unsafe" uses of a loaded function
522527
// pointer. The key is the associated llvm.type.test intrinsic call generated
523528
// by this pass. An unsafe use is one that calls the loaded function pointer
@@ -1064,10 +1069,14 @@ void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
10641069
return;
10651070
auto Apply = [&](CallSiteInfo &CSInfo) {
10661071
for (auto &&VCallSite : CSInfo.CallSites) {
1072+
if (!OptimizedCalls.insert(&VCallSite.CB).second)
1073+
continue;
1074+
10671075
if (RemarksEnabled)
10681076
VCallSite.emitRemark("single-impl",
10691077
TheFn->stripPointerCasts()->getName(), OREGetter);
10701078
auto &CB = VCallSite.CB;
1079+
assert(!CB.getCalledFunction() && "devirtualizing direct call?");
10711080
IRBuilder<> Builder(&CB);
10721081
Value *Callee =
10731082
Builder.CreateBitCast(TheFn, CB.getCalledOperand()->getType());
@@ -1406,10 +1415,13 @@ bool DevirtModule::tryEvaluateFunctionsWithArgs(
14061415

14071416
void DevirtModule::applyUniformRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,
14081417
uint64_t TheRetVal) {
1409-
for (auto Call : CSInfo.CallSites)
1418+
for (auto Call : CSInfo.CallSites) {
1419+
if (!OptimizedCalls.insert(&Call.CB).second)
1420+
continue;
14101421
Call.replaceAndErase(
14111422
"uniform-ret-val", FnName, RemarksEnabled, OREGetter,
14121423
ConstantInt::get(cast<IntegerType>(Call.CB.getType()), TheRetVal));
1424+
}
14131425
CSInfo.markDevirt();
14141426
}
14151427

@@ -1515,6 +1527,8 @@ void DevirtModule::applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,
15151527
bool IsOne,
15161528
Constant *UniqueMemberAddr) {
15171529
for (auto &&Call : CSInfo.CallSites) {
1530+
if (!OptimizedCalls.insert(&Call.CB).second)
1531+
continue;
15181532
IRBuilder<> B(&Call.CB);
15191533
Value *Cmp =
15201534
B.CreateICmp(IsOne ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE, Call.VTable,
@@ -1583,6 +1597,8 @@ bool DevirtModule::tryUniqueRetValOpt(
15831597
void DevirtModule::applyVirtualConstProp(CallSiteInfo &CSInfo, StringRef FnName,
15841598
Constant *Byte, Constant *Bit) {
15851599
for (auto Call : CSInfo.CallSites) {
1600+
if (!OptimizedCalls.insert(&Call.CB).second)
1601+
continue;
15861602
auto *RetType = cast<IntegerType>(Call.CB.getType());
15871603
IRBuilder<> B(&Call.CB);
15881604
Value *Addr =
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
; RUN: opt -S -wholeprogramdevirt -whole-program-visibility %s | FileCheck %s
2+
3+
target datalayout = "e-p:64:64"
4+
target triple = "x86_64-unknown-linux-gnu"
5+
6+
@vt1 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)], !type !0
7+
@vt2 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)], !type !0
8+
9+
define void @vf(i8* %this) {
10+
ret void
11+
}
12+
13+
; CHECK: define void @call
14+
define void @call(i8* %obj) {
15+
%vtableptr = bitcast i8* %obj to [1 x i8*]**
16+
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
17+
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
18+
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
19+
call void @llvm.assume(i1 %p)
20+
%p2 = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
21+
call void @llvm.assume(i1 %p2)
22+
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
23+
%fptr = load i8*, i8** %fptrptr
24+
%fptr_casted = bitcast i8* %fptr to void (i8*)*
25+
; CHECK: call void @vf(
26+
call void %fptr_casted(i8* %obj)
27+
ret void
28+
}
29+
30+
declare i1 @llvm.type.test(i8*, metadata)
31+
declare void @llvm.assume(i1)
32+
33+
!0 = !{i32 0, !"typeid"}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
; RUN: opt -S -wholeprogramdevirt -whole-program-visibility %s | FileCheck %s
2+
3+
target datalayout = "e-p:64:64"
4+
target triple = "x86_64-unknown-linux-gnu"
5+
6+
@vt1 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)], !type !0
7+
@vt2 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)], !type !0
8+
9+
define i32 @vf1(i8* %this) readnone {
10+
ret i32 123
11+
}
12+
13+
define i32 @vf2(i8* %this) readnone {
14+
ret i32 123
15+
}
16+
17+
; CHECK: define i32 @call
18+
define i32 @call(i8* %obj) {
19+
%vtableptr = bitcast i8* %obj to [1 x i8*]**
20+
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
21+
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
22+
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
23+
call void @llvm.assume(i1 %p)
24+
%p2 = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
25+
call void @llvm.assume(i1 %p2)
26+
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
27+
%fptr = load i8*, i8** %fptrptr
28+
%fptr_casted = bitcast i8* %fptr to i32 (i8*)*
29+
%result = call i32 %fptr_casted(i8* %obj)
30+
; CHECK-NOT: call i32 %
31+
; CHECK: ret i32 123
32+
ret i32 %result
33+
}
34+
35+
declare i1 @llvm.type.test(i8*, metadata)
36+
declare void @llvm.assume(i1)
37+
38+
!0 = !{i32 0, !"typeid"}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
; RUN: opt -S -wholeprogramdevirt -whole-program-visibility %s | FileCheck %s
2+
3+
target datalayout = "e-p:64:64"
4+
target triple = "x86_64-unknown-linux-gnu"
5+
6+
@vt1 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf0 to i8*)], !type !0
7+
@vt2 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf0 to i8*)], !type !0, !type !1
8+
@vt3 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf1 to i8*)], !type !0, !type !1
9+
@vt4 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf1 to i8*)], !type !1
10+
11+
define i1 @vf0(i8* %this) readnone {
12+
ret i1 0
13+
}
14+
15+
define i1 @vf1(i8* %this) readnone {
16+
ret i1 1
17+
}
18+
19+
; CHECK: define i1 @call
20+
define i1 @call(i8* %obj) {
21+
%vtableptr = bitcast i8* %obj to [1 x i8*]**
22+
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
23+
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
24+
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid1")
25+
call void @llvm.assume(i1 %p)
26+
%p2 = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid1")
27+
call void @llvm.assume(i1 %p2)
28+
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
29+
%fptr = load i8*, i8** %fptrptr
30+
%fptr_casted = bitcast i8* %fptr to i1 (i8*)*
31+
; CHECK: [[RES1:%[^ ]*]] = icmp eq [1 x i8*]* %vtable, @vt3
32+
%result = call i1 %fptr_casted(i8* %obj)
33+
; CHECK: ret i1 [[RES1]]
34+
ret i1 %result
35+
}
36+
37+
declare i1 @llvm.type.test(i8*, metadata)
38+
declare void @llvm.assume(i1)
39+
40+
!0 = !{i32 0, !"typeid1"}
41+
!1 = !{i32 0, !"typeid2"}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
; RUN: opt -S -wholeprogramdevirt -whole-program-visibility %s | FileCheck %s
2+
3+
target datalayout = "e-p:64:64"
4+
target triple = "x86_64-unknown-linux-gnu"
5+
6+
@vt2 = constant [3 x i8*] [
7+
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
8+
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
9+
i8* bitcast (i32 (i8*)* @vf2i32 to i8*)
10+
], !type !0
11+
12+
define i1 @vf0i1(i8* %this) readnone {
13+
ret i1 0
14+
}
15+
16+
define i1 @vf1i1(i8* %this) readnone {
17+
ret i1 1
18+
}
19+
20+
define i32 @vf2i32(i8* %this) readnone {
21+
ret i32 2
22+
}
23+
24+
; CHECK: define i1 @call1(
25+
define i1 @call1(i8* %obj) {
26+
%vtableptr = bitcast i8* %obj to [3 x i8*]**
27+
%vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr
28+
%vtablei8 = bitcast [3 x i8*]* %vtable to i8*
29+
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
30+
call void @llvm.assume(i1 %p)
31+
%p2 = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
32+
call void @llvm.assume(i1 %p2)
33+
%fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 0
34+
%fptr = load i8*, i8** %fptrptr
35+
%fptr_casted = bitcast i8* %fptr to i1 (i8*)*
36+
%result = call i1 %fptr_casted(i8* %obj)
37+
ret i1 %result
38+
}
39+
40+
declare i1 @llvm.type.test(i8*, metadata)
41+
declare void @llvm.assume(i1)
42+
43+
!0 = !{i32 0, !"typeid"}

0 commit comments

Comments
 (0)