Skip to content

Commit 474f5ef

Browse files
committed
Revert "[llvm] Teach whole program devirtualization about relative vtables"
This reverts commit db28818. Reverting since it broke our lto builders reported by fxbug.dev/123807.
1 parent bb4f6c4 commit 474f5ef

12 files changed

+11
-459
lines changed

llvm/include/llvm/Analysis/TypeMetadataUtils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ void findDevirtualizableCallsForTypeCheckedLoad(
6464
/// Used for example from GlobalDCE to find an entry in a C++ vtable that
6565
/// matches a vcall offset.
6666
///
67-
/// To support relative vtables, getPointerAtOffset can see through "relative
67+
/// To support Swift vtables, getPointerAtOffset can see through "relative
6868
/// pointers", i.e. (sub-)expressions of the form of:
6969
///
7070
/// @symbol = ... {

llvm/lib/Analysis/ModuleSummaryAnalysis.cpp

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
#include "llvm/ADT/StringRef.h"
2323
#include "llvm/Analysis/BlockFrequencyInfo.h"
2424
#include "llvm/Analysis/BranchProbabilityInfo.h"
25-
#include "llvm/Analysis/ConstantFolding.h"
2625
#include "llvm/Analysis/IndirectCallPromotionAnalysis.h"
2726
#include "llvm/Analysis/LoopInfo.h"
2827
#include "llvm/Analysis/MemoryProfileInfo.h"
@@ -581,8 +580,7 @@ static void computeFunctionSummary(
581580
/// within the initializer.
582581
static void findFuncPointers(const Constant *I, uint64_t StartingOffset,
583582
const Module &M, ModuleSummaryIndex &Index,
584-
VTableFuncList &VTableFuncs,
585-
const GlobalVariable &OrigGV) {
583+
VTableFuncList &VTableFuncs) {
586584
// First check if this is a function pointer.
587585
if (I->getType()->isPointerTy()) {
588586
auto C = I->stripPointerCasts();
@@ -610,42 +608,15 @@ static void findFuncPointers(const Constant *I, uint64_t StartingOffset,
610608
auto Offset = SL->getElementOffset(EI.index());
611609
unsigned Op = SL->getElementContainingOffset(Offset);
612610
findFuncPointers(cast<Constant>(I->getOperand(Op)),
613-
StartingOffset + Offset, M, Index, VTableFuncs, OrigGV);
611+
StartingOffset + Offset, M, Index, VTableFuncs);
614612
}
615613
} else if (auto *C = dyn_cast<ConstantArray>(I)) {
616614
ArrayType *ATy = C->getType();
617615
Type *EltTy = ATy->getElementType();
618616
uint64_t EltSize = DL.getTypeAllocSize(EltTy);
619617
for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {
620618
findFuncPointers(cast<Constant>(I->getOperand(i)),
621-
StartingOffset + i * EltSize, M, Index, VTableFuncs,
622-
OrigGV);
623-
}
624-
} else if (const auto *CE = dyn_cast<ConstantExpr>(I)) {
625-
// For relative vtables, the next sub-component should be a trunc.
626-
if (CE->getOpcode() != Instruction::Trunc ||
627-
!(CE = dyn_cast<ConstantExpr>(CE->getOperand(0))))
628-
return;
629-
630-
// If this constant can be reduced to the offset between a function and a
631-
// global, then we know this is a valid virtual function if the RHS is the
632-
// original vtable we're scanning through.
633-
if (CE->getOpcode() == Instruction::Sub) {
634-
GlobalValue *LHS, *RHS;
635-
APSInt LHSOffset, RHSOffset;
636-
if (IsConstantOffsetFromGlobal(CE->getOperand(0), LHS, LHSOffset, DL) &&
637-
IsConstantOffsetFromGlobal(CE->getOperand(1), RHS, RHSOffset, DL) &&
638-
RHS == &OrigGV &&
639-
640-
// For relative vtables, this component should point to the callable
641-
// function without any offsets.
642-
LHSOffset == 0 &&
643-
644-
// Also, the RHS should always point to somewhere within the vtable.
645-
RHSOffset <=
646-
static_cast<uint64_t>(DL.getTypeAllocSize(OrigGV.getInitializer()->getType()))) {
647-
findFuncPointers(LHS, StartingOffset, M, Index, VTableFuncs, OrigGV);
648-
}
619+
StartingOffset + i * EltSize, M, Index, VTableFuncs);
649620
}
650621
}
651622
}
@@ -658,7 +629,7 @@ static void computeVTableFuncs(ModuleSummaryIndex &Index,
658629
return;
659630

660631
findFuncPointers(V.getInitializer(), /*StartingOffset=*/0, M, Index,
661-
VTableFuncs, V);
632+
VTableFuncs);
662633

663634
#ifndef NDEBUG
664635
// Validate that the VTableFuncs list is ordered by offset.

llvm/lib/Analysis/TypeMetadataUtils.cpp

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,6 @@ static void findLoadCallsAtConstantOffset(
6767
findLoadCallsAtConstantOffset(M, DevirtCalls, User, Offset + GEPOffset,
6868
CI, DT);
6969
}
70-
} else if (auto *Call = dyn_cast<CallInst>(User)) {
71-
if (Call->getIntrinsicID() == llvm::Intrinsic::load_relative) {
72-
if (auto *LoadOffset = dyn_cast<ConstantInt>(Call->getOperand(1))) {
73-
findCallsAtConstantOffset(DevirtCalls, nullptr, User,
74-
Offset + LoadOffset->getSExtValue(), CI,
75-
DT);
76-
}
77-
}
7870
}
7971
}
8072
}
@@ -137,12 +129,6 @@ void llvm::findDevirtualizableCallsForTypeCheckedLoad(
137129

138130
Constant *llvm::getPointerAtOffset(Constant *I, uint64_t Offset, Module &M,
139131
Constant *TopLevelGlobal) {
140-
// TODO: Ideally it would be the caller who knows if it's appropriate to strip
141-
// the DSOLocalEquicalent. More generally, it would feel more appropriate to
142-
// have two functions that handle absolute and relative pointers separately.
143-
if (auto *Equiv = dyn_cast<DSOLocalEquivalent>(I))
144-
I = Equiv->getGlobalValue();
145-
146132
if (I->getType()->isPointerTy()) {
147133
if (Offset == 0)
148134
return I;
@@ -173,7 +159,7 @@ Constant *llvm::getPointerAtOffset(Constant *I, uint64_t Offset, Module &M,
173159
Offset % ElemSize, M, TopLevelGlobal);
174160
}
175161

176-
// Relative-pointer support starts here.
162+
// (Swift-specific) relative-pointer support starts here.
177163
if (auto *CI = dyn_cast<ConstantInt>(I)) {
178164
if (Offset == 0 && CI->isZero()) {
179165
return I;

llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1005,7 +1005,7 @@ bool DevirtModule::tryFindVirtualCallTargets(
10051005
return false;
10061006

10071007
Constant *Ptr = getPointerAtOffset(TM.Bits->GV->getInitializer(),
1008-
TM.Offset + ByteOffset, M, TM.Bits->GV);
1008+
TM.Offset + ByteOffset, M);
10091009
if (!Ptr)
10101010
return false;
10111011

llvm/test/ThinLTO/X86/devirt.ll

Lines changed: 3 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -27,36 +27,24 @@
2727
; NOENABLESPLITFLAG-DAG: [[B:\^[0-9]+]] = gv: (name: "_ZTV1B", {{.*}} vTableFuncs: ((virtFunc: [[Bf]], offset: 16), (virtFunc: [[An]], offset: 24)), refs: ([[Bf]], [[An]])
2828
; NOENABLESPLITFLAG-DAG: [[C:\^[0-9]+]] = gv: (name: "_ZTV1C", {{.*}} vTableFuncs: ((virtFunc: [[Cf]], offset: 16), (virtFunc: [[An]], offset: 24)), refs: ([[An]], [[Cf]])
2929
; NOENABLESPLITFLAG-DAG: [[D:\^[0-9]+]] = gv: (name: "_ZTV1D", {{.*}} vTableFuncs: ((virtFunc: [[Dm]], offset: 16)), refs: ([[Dm]])
30-
; NOENABLESPLITFLAG-DAG: [[B_RV:\^[0-9]+]] = gv: (name: "_ZTV1B_RV", {{.*}} vTableFuncs: ((virtFunc: [[Bf]], offset: 8), (virtFunc: [[An]], offset: 12)), refs: ([[B_RV]], [[Bf]], [[An]])
31-
; NOENABLESPLITFLAG-DAG: [[C_RV:\^[0-9]+]] = gv: (name: "_ZTV1C_RV", {{.*}} vTableFuncs: ((virtFunc: [[Cf]], offset: 8), (virtFunc: [[An]], offset: 12)), refs: ([[C_RV]], [[An]], [[Cf]])
32-
; NOENABLESPLITFLAG-DAG: [[D_RV:\^[0-9]+]] = gv: (name: "_ZTV1D_RV", {{.*}} vTableFuncs: ((virtFunc: [[Dm]], offset: 8)), refs: ([[D_RV]], [[Dm]])
3330
; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "_ZTS1A", summary: ((offset: 16, [[B]]), (offset: 16, [[C]])))
3431
; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "_ZTS1B", summary: ((offset: 16, [[B]])))
3532
; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "_ZTS1C", summary: ((offset: 16, [[C]])))
36-
; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "_ZTS1A_RV", summary: ((offset: 8, [[B_RV]]), (offset: 8, [[C_RV]])))
37-
; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "_ZTS1B_RV", summary: ((offset: 8, [[B_RV]])))
38-
; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "_ZTS1C_RV", summary: ((offset: 8, [[C_RV]])))
3933
; Type Id on _ZTV1D should have been promoted
4034
; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "1.{{.*}}", summary: ((offset: 16, [[D]])))
41-
; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "2.{{.*}}", summary: ((offset: 8, [[D_RV]])))
4235

4336
; Index based WPD
4437
; RUN: llvm-lto2 run %t2.o -save-temps -pass-remarks=. \
4538
; RUN: -whole-program-visibility \
4639
; RUN: -o %t3 \
4740
; RUN: -r=%t2.o,test,px \
48-
; RUN: -r=%t2.o,test_rv,px \
4941
; RUN: -r=%t2.o,_ZN1A1nEi,p \
5042
; RUN: -r=%t2.o,_ZN1B1fEi,p \
5143
; RUN: -r=%t2.o,_ZN1C1fEi,p \
5244
; RUN: -r=%t2.o,_ZN1D1mEi,p \
5345
; RUN: -r=%t2.o,_ZTV1B,px \
5446
; RUN: -r=%t2.o,_ZTV1C,px \
55-
; RUN: -r=%t2.o,_ZTV1D,px \
56-
; RUN: -r=%t2.o,_ZTV1B_RV,px \
57-
; RUN: -r=%t2.o,_ZTV1C_RV,px \
58-
; RUN: -r=%t2.o,_ZTV1D_RV,px \
59-
; RUN: 2>&1 | FileCheck %s --check-prefix=REMARK
47+
; RUN: -r=%t2.o,_ZTV1D,px 2>&1 | FileCheck %s --check-prefix=REMARK
6048
; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
6149

6250
; Check that we're able to prevent specific function from being
@@ -66,49 +54,34 @@
6654
; RUN: -wholeprogramdevirt-skip=_ZN1A1nEi \
6755
; RUN: -o %t3 \
6856
; RUN: -r=%t2.o,test,px \
69-
; RUN: -r=%t2.o,test_rv,px \
7057
; RUN: -r=%t2.o,_ZN1A1nEi,p \
7158
; RUN: -r=%t2.o,_ZN1B1fEi,p \
7259
; RUN: -r=%t2.o,_ZN1C1fEi,p \
7360
; RUN: -r=%t2.o,_ZN1D1mEi,p \
7461
; RUN: -r=%t2.o,_ZTV1B,px \
7562
; RUN: -r=%t2.o,_ZTV1C,px \
76-
; RUN: -r=%t2.o,_ZTV1D,px \
77-
; RUN: -r=%t2.o,_ZTV1B_RV,px \
78-
; RUN: -r=%t2.o,_ZTV1C_RV,px \
79-
; RUN: -r=%t2.o,_ZTV1D_RV,px \
80-
; RUN: 2>&1 | FileCheck %s --check-prefix=SKIP
63+
; RUN: -r=%t2.o,_ZTV1D,px 2>&1 | FileCheck %s --check-prefix=SKIP
8164

8265
; RUN: llvm-lto2 run %t.o -save-temps -pass-remarks=. \
8366
; RUN: -whole-program-visibility \
8467
; RUN: -o %t3 \
8568
; RUN: -r=%t.o,test,px \
86-
; RUN: -r=%t.o,test_rv,px \
8769
; RUN: -r=%t.o,_ZN1A1nEi,p \
8870
; RUN: -r=%t.o,_ZN1B1fEi,p \
8971
; RUN: -r=%t.o,_ZN1C1fEi,p \
9072
; RUN: -r=%t.o,_ZN1D1mEi,p \
9173
; RUN: -r=%t.o,_ZTV1B, \
9274
; RUN: -r=%t.o,_ZTV1C, \
9375
; RUN: -r=%t.o,_ZTV1D, \
94-
; RUN: -r=%t.o,_ZTV1B_RV, \
95-
; RUN: -r=%t.o,_ZTV1C_RV, \
96-
; RUN: -r=%t.o,_ZTV1D_RV, \
9776
; RUN: -r=%t.o,_ZN1A1nEi, \
9877
; RUN: -r=%t.o,_ZN1B1fEi, \
9978
; RUN: -r=%t.o,_ZN1C1fEi, \
10079
; RUN: -r=%t.o,_ZN1D1mEi, \
10180
; RUN: -r=%t.o,_ZTV1B,px \
10281
; RUN: -r=%t.o,_ZTV1C,px \
103-
; RUN: -r=%t.o,_ZTV1D,px \
104-
; RUN: -r=%t.o,_ZTV1B_RV,px \
105-
; RUN: -r=%t.o,_ZTV1C_RV,px \
106-
; RUN: -r=%t.o,_ZTV1D_RV,px \
107-
; RUN: 2>&1 | FileCheck %s --check-prefix=REMARK --dump-input=fail
82+
; RUN: -r=%t.o,_ZTV1D,px 2>&1 | FileCheck %s --check-prefix=REMARK --dump-input=fail
10883
; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
10984

110-
; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi
111-
; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEi
11285
; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi
11386
; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEi
11487

@@ -126,25 +99,6 @@ target triple = "x86_64-grtev4-linux-gnu"
12699
@_ZTV1C = constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr undef, ptr @_ZN1C1fEi, ptr @_ZN1A1nEi] }, !type !0, !type !2
127100
@_ZTV1D = constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr undef, ptr @_ZN1D1mEi] }, !type !3
128101

129-
@_ZTV1B_RV = constant { [4 x i32] } { [4 x i32] [
130-
i32 0,
131-
i32 undef,
132-
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1B1fEi to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1B_RV, i32 0, i32 0, i32 2) to i64)) to i32),
133-
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1A1nEi to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1B_RV, i32 0, i32 0, i32 3) to i64)) to i32)
134-
] }, !type !7, !type !8
135-
136-
@_ZTV1C_RV = constant { [4 x i32] } { [4 x i32] [
137-
i32 0,
138-
i32 undef,
139-
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1C1fEi to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1C_RV, i32 0, i32 0, i32 2) to i64)) to i32),
140-
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1A1nEi to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1C_RV, i32 0, i32 0, i32 3) to i64)) to i32)
141-
] }, !type !7, !type !9
142-
143-
@_ZTV1D_RV = constant { [3 x i32] } { [3 x i32] [
144-
i32 0,
145-
i32 undef,
146-
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1D1mEi to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [3 x i32] }, ptr @_ZTV1D_RV, i32 0, i32 0, i32 2) to i64)) to i32)
147-
] }, !type !10
148102

149103
; CHECK-IR-LABEL: define i32 @test
150104
define i32 @test(ptr %obj, ptr %obj2, i32 %a) {
@@ -182,43 +136,6 @@ entry:
182136
; CHECK-IR-LABEL: ret i32
183137
; CHECK-IR-LABEL: }
184138

185-
declare ptr @llvm.load.relative.i32(ptr, i32)
186-
187-
; CHECK-IR-LABEL: define i32 @test_rv
188-
define i32 @test_rv(ptr %obj, ptr %obj2, i32 %a) {
189-
entry:
190-
%vtable = load ptr, ptr %obj
191-
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"_ZTS1A_RV")
192-
call void @llvm.assume(i1 %p)
193-
%fptr1_rv = call ptr @llvm.load.relative.i32(ptr %vtable, i32 4)
194-
195-
; Check that the call was devirtualized.
196-
; CHECK-IR: %call = tail call i32 @_ZN1A1nEi
197-
; Ensure !prof and !callees metadata for indirect call promotion removed.
198-
; CHECK-IR-NOT: prof
199-
; CHECK-IR-NOT: callees
200-
%call = tail call i32 %fptr1_rv(ptr nonnull %obj, i32 %a), !prof !5, !callees !6
201-
202-
%fptr22_rv = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
203-
204-
; We still have to call it as virtual.
205-
; CHECK-IR: %call3 = tail call i32 %fptr22
206-
%call3 = tail call i32 %fptr22_rv(ptr nonnull %obj, i32 %call)
207-
208-
%vtable2 = load ptr, ptr %obj2
209-
%p2 = call i1 @llvm.type.test(ptr %vtable2, metadata !11)
210-
call void @llvm.assume(i1 %p2)
211-
212-
%fptr33_rv = call ptr @llvm.load.relative.i32(ptr %vtable2, i32 0)
213-
214-
; Check that the call was devirtualized.
215-
; CHECK-IR: %call4 = tail call i32 @_ZN1D1mEi
216-
%call4 = tail call i32 %fptr33_rv(ptr nonnull %obj2, i32 %call3)
217-
ret i32 %call4
218-
}
219-
; CHECK-IR-LABEL: ret i32
220-
; CHECK-IR-LABEL: }
221-
222139
declare i1 @llvm.type.test(ptr, metadata)
223140
declare void @llvm.assume(i1)
224141

@@ -248,9 +165,3 @@ attributes #0 = { noinline optnone }
248165
!4 = distinct !{}
249166
!5 = !{!"VP", i32 0, i64 1, i64 1621563287929432257, i64 1}
250167
!6 = !{ptr @_ZN1A1nEi}
251-
252-
!7 = !{i64 8, !"_ZTS1A_RV"}
253-
!8 = !{i64 8, !"_ZTS1B_RV"}
254-
!9 = !{i64 8, !"_ZTS1C_RV"}
255-
!10 = !{i64 8, !11}
256-
!11 = distinct !{}

llvm/test/Transforms/WholeProgramDevirt/Inputs/export.yaml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,14 @@ GlobalValueMap:
55
TypeTestAssumeVCalls:
66
- GUID: 14276520915468743435 # typeid1
77
Offset: 0
8-
- GUID: 271751036925422857 # typeid1_rv
9-
Offset: 0
108
TypeCheckedLoadVCalls:
119
- GUID: 15427464259790519041 # typeid2
1210
Offset: 0
13-
- GUID: 1146149264729288256 # typeid2_rv
14-
Offset: 0
1511
TypeTestAssumeConstVCalls:
1612
- VFunc:
1713
GUID: 3515965990081467659 # typeid3
1814
Offset: 0
1915
Args: [12, 24]
20-
- VFunc:
21-
GUID: 2777626534618191571 # typeid3_rv
22-
Offset: 0
23-
Args: [12, 24]
2416
TypeCheckedLoadConstVCalls:
2517
- VFunc:
2618
GUID: 17525413373118030901 # typeid4

0 commit comments

Comments
 (0)