llvm.org GIT mirror llvm / 9a694d9
Revert "Dead Virtual Function Elimination" This reverts commit 9f6a873268e1ad9855873d9d8007086c0d01cf4f. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@374844 91177308-0d34-0410-b5e6-96231b3b80d8 Jorge Gorbe Moya 1 year, 1 month ago
23 changed file(s) with 39 addition(s) and 1092 deletion(s). Raw diff Collapse all Expand all
62636263 !0 = !{i32 1, !"short_wchar", i32 1}
62646264 !1 = !{i32 1, !"short_enum", i32 0}
62656265
6266 LTO Post-Link Module Flags Metadata
6267 -----------------------------------
6268
6269 Some optimisations are only when the entire LTO unit is present in the current
6270 module. This is represented by the ``LTOPostLink`` module flags metadata, which
6271 will be created with a value of ``1`` when LTO linking occurs.
6272
62736266 Automatic Linker Flags Named Metadata
62746267 =====================================
62756268
1681516808 The ``llvm.type.test`` intrinsic tests whether the given pointer is associated
1681616809 with the given type identifier.
1681716810
16818 .. _type.checked.load:
16819
1682016811 '``llvm.type.checked.load``' Intrinsic
1682116812 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1682216813
223223 }
224224
225225 .. _GlobalLayoutBuilder: https://github.com/llvm/llvm-project/blob/master/llvm/include/llvm/Transforms/IPO/LowerTypeTests.h
226
227 ``!vcall_visibility`` Metadata
228 ==============================
229
230 In order to allow removing unused function pointers from vtables, we need to
231 know whether every virtual call which could use it is known to the compiler, or
232 whether another translation unit could introduce more calls through the vtable.
233 This is not the same as the linkage of the vtable, because call sites could be
234 using a pointer of a more widely-visible base class. For example, consider this
235 code:
236
237 .. code-block:: c++
238
239 __attribute__((visibility("default")))
240 struct A {
241 virtual void f();
242 };
243
244 __attribute__((visibility("hidden")))
245 struct B : A {
246 virtual void f();
247 };
248
249 With LTO, we know that all code which can see the declaration of ``B`` is
250 visible to us. However, a pointer to a ``B`` could be cast to ``A*`` and passed
251 to another linkage unit, which could then call ``f`` on it. This call would
252 load from the vtable for ``B`` (using the object pointer), and then call
253 ``B::f``. This means we can't remove the function pointer from ``B``'s vtable,
254 or the implementation of ``B::f``. However, if we can see all code which knows
255 about any dynamic base class (which would be the case if ``B`` only inherited
256 from classes with hidden visibility), then this optimisation would be valid.
257
258 This concept is represented in IR by the ``!vcall_visibility`` metadata
259 attached to vtable objects, with the following values:
260
261 .. list-table::
262 :header-rows: 1
263 :widths: 10 90
264
265 * - Value
266 - Behavior
267
268 * - 0 (or omitted)
269 - **Public**
270 Virtual function calls using this vtable could be made from external
271 code.
272
273 * - 1
274 - **Linkage Unit**
275 All virtual function calls which might use this vtable are in the
276 current LTO unit, meaning they will be in the current module once
277 LTO linking has been performed.
278
279 * - 2
280 - **Translation Unit**
281 All virtual function calls which might use this vtable are in the
282 current module.
283
284 In addition, all function pointer loads from a vtable marked with the
285 ``!vcall_visibility`` metadata (with a non-zero value) must be done using the
286 :ref:`llvm.type.checked.load ` intrinsic, so that virtual
287 calls sites can be correlated with the vtables which they might load from.
288 Other parts of the vtable (RTTI, offset-to-top, ...) can still be accessed with
289 normal loads.
4949 SmallVectorImpl &LoadedPtrs,
5050 SmallVectorImpl &Preds, bool &HasNonCallUses,
5151 const CallInst *CI, DominatorTree &DT);
52
53 Constant *getPointerAtOffset(Constant *I, uint64_t Offset, Module &M);
5452 }
5553
5654 #endif
3939 LLVM_FIXED_MD_KIND(MD_callback, "callback", 26)
4040 LLVM_FIXED_MD_KIND(MD_preserve_access_index, "llvm.preserve.access.index", 27)
4141 LLVM_FIXED_MD_KIND(MD_misexpect, "misexpect", 28)
42 LLVM_FIXED_MD_KIND(MD_vcall_visibility, "vcall_visibility", 29)
2727 class Metadata;
2828
2929 class GlobalObject : public GlobalValue {
30 public:
31 // VCallVisibility - values for visibility metadata attached to vtables. This
32 // describes the scope in which a virtual call could end up being dispatched
33 // through this vtable.
34 enum VCallVisibility {
35 // Type is potentially visible to external code.
36 VCallVisibilityPublic = 0,
37 // Type is only visible to code which will be in the current Module after
38 // LTO internalization.
39 VCallVisibilityLinkageUnit = 1,
40 // Type is only visible to code in the current Module.
41 VCallVisibilityTranslationUnit = 2,
42 };
43
4430 protected:
4531 GlobalObject(Type *Ty, ValueTy VTy, Use *Ops, unsigned NumOps,
4632 LinkageTypes Linkage, const Twine &Name,
176162 void copyMetadata(const GlobalObject *Src, unsigned Offset);
177163
178164 void addTypeMetadata(unsigned Offset, Metadata *TypeID);
179 void addVCallVisibilityMetadata(VCallVisibility Visibility);
180 VCallVisibility getVCallVisibility() const;
181165
182166 protected:
183167 void copyAttributesFrom(const GlobalObject *Src);
4242 /// Comdat -> Globals in that Comdat section.
4343 std::unordered_multimap ComdatMembers;
4444
45 /// !type metadata -> set of (vtable, offset) pairs
46 DenseMap, 4>>
47 TypeIdMap;
48
49 // Global variables which are vtables, and which we have enough information
50 // about to safely do dead virtual function elimination.
51 SmallPtrSet VFESafeVTables;
52
5345 void UpdateGVDependencies(GlobalValue &GV);
5446 void MarkLive(GlobalValue &GV,
5547 SmallVectorImpl *Updates = nullptr);
5648 bool RemoveUnusedGlobalValue(GlobalValue &GV);
57
58 // Dead virtual function elimination.
59 void AddVirtualFunctionDependencies(Module &M);
60 void ScanVTables(Module &M);
61 void ScanTypeCheckedLoadIntrinsics(Module &M);
62 void ScanVTableLoad(Function *Caller, Metadata *TypeId, uint64_t CallOffset);
6349
6450 void ComputeDependencies(Value *V, SmallPtrSetImpl &U);
6551 };
126126 findCallsAtConstantOffset(DevirtCalls, &HasNonCallUses, LoadedPtr,
127127 Offset->getZExtValue(), CI, DT);
128128 }
129
130 Constant *llvm::getPointerAtOffset(Constant *I, uint64_t Offset, Module &M) {
131 if (I->getType()->isPointerTy()) {
132 if (Offset == 0)
133 return I;
134 return nullptr;
135 }
136
137 const DataLayout &DL = M.getDataLayout();
138
139 if (auto *C = dyn_cast(I)) {
140 const StructLayout *SL = DL.getStructLayout(C->getType());
141 if (Offset >= SL->getSizeInBytes())
142 return nullptr;
143
144 unsigned Op = SL->getElementContainingOffset(Offset);
145 return getPointerAtOffset(cast(I->getOperand(Op)),
146 Offset - SL->getElementOffset(Op), M);
147 }
148 if (auto *C = dyn_cast(I)) {
149 ArrayType *VTableTy = C->getType();
150 uint64_t ElemSize = DL.getTypeAllocSize(VTableTy->getElementType());
151
152 unsigned Op = Offset / ElemSize;
153 if (Op >= C->getNumOperands())
154 return nullptr;
155
156 return getPointerAtOffset(cast(I->getOperand(Op)),
157 Offset % ElemSize, M);
158 }
159 return nullptr;
160 }
14961496 TypeID}));
14971497 }
14981498
1499 void GlobalObject::addVCallVisibilityMetadata(VCallVisibility Visibility) {
1500 addMetadata(LLVMContext::MD_vcall_visibility,
1501 *MDNode::get(getContext(),
1502 {ConstantAsMetadata::get(ConstantInt::get(
1503 Type::getInt64Ty(getContext()), Visibility))}));
1504 }
1505
1506 GlobalObject::VCallVisibility GlobalObject::getVCallVisibility() const {
1507 if (MDNode *MD = getMetadata(LLVMContext::MD_vcall_visibility)) {
1508 uint64_t Val = cast(
1509 cast(MD->getOperand(0))->getValue())
1510 ->getZExtValue();
1511 assert(Val <= 2 && "unknown vcall visibility!");
1512 return (VCallVisibility)Val;
1513 }
1514 return VCallVisibility::VCallVisibilityPublic;
1515 }
1516
15171499 void Function::setSubprogram(DISubprogram *SP) {
15181500 setMetadata(LLVMContext::MD_dbg, SP);
15191501 }
10021002 GV->setLinkage(GlobalValue::InternalLinkage);
10031003 }
10041004
1005 RegularLTO.CombinedModule->addModuleFlag(Module::Error, "LTOPostLink", 1);
1006
10071005 if (Conf.PostInternalizeModuleHook &&
10081006 !Conf.PostInternalizeModuleHook(0, *RegularLTO.CombinedModule))
10091007 return Error::success();
462462
463463 internalizeModule(*MergedModule, mustPreserveGV);
464464
465 MergedModule->addModuleFlag(Module::Error, "LTOPostLink", 1);
466
467465 ScopeRestrictionsDone = true;
468466 }
469467
1616 #include "llvm/Transforms/IPO/GlobalDCE.h"
1717 #include "llvm/ADT/SmallPtrSet.h"
1818 #include "llvm/ADT/Statistic.h"
19 #include "llvm/Analysis/TypeMetadataUtils.h"
2019 #include "llvm/IR/Instructions.h"
2120 #include "llvm/IR/IntrinsicInst.h"
2221 #include "llvm/IR/Module.h"
23 #include "llvm/IR/Operator.h"
2422 #include "llvm/Pass.h"
2523 #include "llvm/Transforms/IPO.h"
2624 #include "llvm/Transforms/Utils/CtorUtils.h"
3028
3129 #define DEBUG_TYPE "globaldce"
3230
33 static cl::opt
34 ClEnableVFE("enable-vfe", cl::Hidden, cl::init(true), cl::ZeroOrMore,
35 cl::desc("Enable virtual function elimination"));
36
3731 STATISTIC(NumAliases , "Number of global aliases removed");
3832 STATISTIC(NumFunctions, "Number of functions removed");
3933 STATISTIC(NumIFuncs, "Number of indirect functions removed");
4034 STATISTIC(NumVariables, "Number of global variables removed");
41 STATISTIC(NumVFuncs, "Number of virtual functions removed");
4235
4336 namespace {
4437 class GlobalDCELegacyPass : public ModulePass {
124117 ComputeDependencies(User, Deps);
125118 Deps.erase(&GV); // Remove self-reference.
126119 for (GlobalValue *GVU : Deps) {
127 // If this is a dep from a vtable to a virtual function, and we have
128 // complete information about all virtual call sites which could call
129 // though this vtable, then skip it, because the call site information will
130 // be more precise.
131 if (VFESafeVTables.count(GVU) && isa(&GV)) {
132 LLVM_DEBUG(dbgs() << "Ignoring dep " << GVU->getName() << " -> "
133 << GV.getName() << "\n");
134 continue;
135 }
136120 GVDependencies[GVU].insert(&GV);
137121 }
138122 }
147131 if (Updates)
148132 Updates->push_back(&GV);
149133 if (Comdat *C = GV.getComdat()) {
150 for (auto &&CM : make_range(ComdatMembers.equal_range(C))) {
134 for (auto &&CM : make_range(ComdatMembers.equal_range(C)))
151135 MarkLive(*CM.second, Updates); // Recursion depth is only two because only
152136 // globals in the same comdat are visited.
153 }
154 }
155 }
156
157 void GlobalDCEPass::ScanVTables(Module &M) {
158 SmallVector Types;
159 LLVM_DEBUG(dbgs() << "Building type info -> vtable map\n");
160
161 auto *LTOPostLinkMD =
162 cast_or_null(M.getModuleFlag("LTOPostLink"));
163 bool LTOPostLink =
164 LTOPostLinkMD &&
165 (cast(LTOPostLinkMD->getValue())->getZExtValue() != 0);
166
167 for (GlobalVariable &GV : M.globals()) {
168 Types.clear();
169 GV.getMetadata(LLVMContext::MD_type, Types);
170 if (GV.isDeclaration() || Types.empty())
171 continue;
172
173 // Use the typeid metadata on the vtable to build a mapping from typeids to
174 // the list of (GV, offset) pairs which are the possible vtables for that
175 // typeid.
176 for (MDNode *Type : Types) {
177 Metadata *TypeID = Type->getOperand(1).get();
178
179 uint64_t Offset =
180 cast(
181 cast(Type->getOperand(0))->getValue())
182 ->getZExtValue();
183
184 TypeIdMap[TypeID].insert(std::make_pair(&GV, Offset));
185 }
186
187 // If the type corresponding to the vtable is private to this translation
188 // unit, we know that we can see all virtual functions which might use it,
189 // so VFE is safe.
190 if (auto GO = dyn_cast(&GV)) {
191 GlobalObject::VCallVisibility TypeVis = GO->getVCallVisibility();
192 if (TypeVis == GlobalObject::VCallVisibilityTranslationUnit ||
193 (LTOPostLink &&
194 TypeVis == GlobalObject::VCallVisibilityLinkageUnit)) {
195 LLVM_DEBUG(dbgs() << GV.getName() << " is safe for VFE\n");
196 VFESafeVTables.insert(&GV);
197 }
198 }
199 }
200 }
201
202 void GlobalDCEPass::ScanVTableLoad(Function *Caller, Metadata *TypeId,
203 uint64_t CallOffset) {
204 for (auto &VTableInfo : TypeIdMap[TypeId]) {
205 GlobalVariable *VTable = VTableInfo.first;
206 uint64_t VTableOffset = VTableInfo.second;
207
208 Constant *Ptr =
209 getPointerAtOffset(VTable->getInitializer(), VTableOffset + CallOffset,
210 *Caller->getParent());
211 if (!Ptr) {
212 LLVM_DEBUG(dbgs() << "can't find pointer in vtable!\n");
213 VFESafeVTables.erase(VTable);
214 return;
215 }
216
217 auto Callee = dyn_cast(Ptr->stripPointerCasts());
218 if (!Callee) {
219 LLVM_DEBUG(dbgs() << "vtable entry is not function pointer!\n");
220 VFESafeVTables.erase(VTable);
221 return;
222 }
223
224 LLVM_DEBUG(dbgs() << "vfunc dep " << Caller->getName() << " -> "
225 << Callee->getName() << "\n");
226 GVDependencies[Caller].insert(Callee);
227 }
228 }
229
230 void GlobalDCEPass::ScanTypeCheckedLoadIntrinsics(Module &M) {
231 LLVM_DEBUG(dbgs() << "Scanning type.checked.load intrinsics\n");
232 Function *TypeCheckedLoadFunc =
233 M.getFunction(Intrinsic::getName(Intrinsic::type_checked_load));
234
235 if (!TypeCheckedLoadFunc)
236 return;
237
238 for (auto U : TypeCheckedLoadFunc->users()) {
239 auto CI = dyn_cast(U);
240 if (!CI)
241 continue;
242
243 auto *Offset = dyn_cast(CI->getArgOperand(1));
244 Value *TypeIdValue = CI->getArgOperand(2);
245 auto *TypeId = cast(TypeIdValue)->getMetadata();
246
247 if (Offset) {
248 ScanVTableLoad(CI->getFunction(), TypeId, Offset->getZExtValue());
249 } else {
250 // type.checked.load with a non-constant offset, so assume every entry in
251 // every matching vtable is used.
252 for (auto &VTableInfo : TypeIdMap[TypeId]) {
253 VFESafeVTables.erase(VTableInfo.first);
254 }
255 }
256 }
257 }
258
259 void GlobalDCEPass::AddVirtualFunctionDependencies(Module &M) {
260 if (!ClEnableVFE)
261 return;
262
263 ScanVTables(M);
264
265 if (VFESafeVTables.empty())
266 return;
267
268 ScanTypeCheckedLoadIntrinsics(M);
269
270 LLVM_DEBUG(
271 dbgs() << "VFE safe vtables:\n";
272 for (auto *VTable : VFESafeVTables)
273 dbgs() << " " << VTable->getName() << "\n";
274 );
137 }
275138 }
276139
277140 PreservedAnalyses GlobalDCEPass::run(Module &M, ModuleAnalysisManager &MAM) {
298161 for (GlobalAlias &GA : M.aliases())
299162 if (Comdat *C = GA.getComdat())
300163 ComdatMembers.insert(std::make_pair(C, &GA));
301
302 // Add dependencies between virtual call sites and the virtual functions they
303 // might call, if we have that information.
304 AddVirtualFunctionDependencies(M);
305164
306165 // Loop over the module, adding globals which are obviously necessary.
307166 for (GlobalObject &GO : M.global_objects()) {
397256 };
398257
399258 NumFunctions += DeadFunctions.size();
400 for (Function *F : DeadFunctions) {
401 if (!F->use_empty()) {
402 // Virtual functions might still be referenced by one or more vtables,
403 // but if we've proven them to be unused then it's safe to replace the
404 // virtual function pointers with null, allowing us to remove the
405 // function itself.
406 ++NumVFuncs;
407 F->replaceAllUsesWith(ConstantPointerNull::get(F->getType()));
408 }
259 for (Function *F : DeadFunctions)
409260 EraseUnusedGlobalValue(F);
410 }
411261
412262 NumVariables += DeadGlobalVars.size();
413263 for (GlobalVariable *GV : DeadGlobalVars)
426276 ConstantDependenciesCache.clear();
427277 GVDependencies.clear();
428278 ComdatMembers.clear();
429 TypeIdMap.clear();
430 VFESafeVTables.clear();
431279
432280 if (Changed)
433281 return PreservedAnalyses::none();
495495 void buildTypeIdentifierMap(
496496 std::vector &Bits,
497497 DenseMap> &TypeIdMap);
498 Constant *getPointerAtOffset(Constant *I, uint64_t Offset);
498499 bool
499500 tryFindVirtualCallTargets(std::vector &TargetsForSlot,
500501 const std::set &TypeMemberInfos,
811812 }
812813 }
813814
815 Constant *DevirtModule::getPointerAtOffset(Constant *I, uint64_t Offset) {
816 if (I->getType()->isPointerTy()) {
817 if (Offset == 0)
818 return I;
819 return nullptr;
820 }
821
822 const DataLayout &DL = M.getDataLayout();
823
824 if (auto *C = dyn_cast(I)) {
825 const StructLayout *SL = DL.getStructLayout(C->getType());
826 if (Offset >= SL->getSizeInBytes())
827 return nullptr;
828
829 unsigned Op = SL->getElementContainingOffset(Offset);
830 return getPointerAtOffset(cast(I->getOperand(Op)),
831 Offset - SL->getElementOffset(Op));
832 }
833 if (auto *C = dyn_cast(I)) {
834 ArrayType *VTableTy = C->getType();
835 uint64_t ElemSize = DL.getTypeAllocSize(VTableTy->getElementType());
836
837 unsigned Op = Offset / ElemSize;
838 if (Op >= C->getNumOperands())
839 return nullptr;
840
841 return getPointerAtOffset(cast(I->getOperand(Op)),
842 Offset % ElemSize);
843 }
844 return nullptr;
845 }
846
814847 bool DevirtModule::tryFindVirtualCallTargets(
815848 std::vector &TargetsForSlot,
816849 const std::set &TypeMemberInfos, uint64_t ByteOffset) {
819852 return false;
820853
821854 Constant *Ptr = getPointerAtOffset(TM.Bits->GV->getInitializer(),
822 TM.Offset + ByteOffset, M);
855 TM.Offset + ByteOffset);
823856 if (!Ptr)
824857 return false;
825858
19071940 for (VTableBits &B : Bits)
19081941 rebuildGlobal(B);
19091942
1910 // We have lowered or deleted the type checked load intrinsics, so we no
1911 // longer have enough information to reason about the liveness of virtual
1912 // function pointers in GlobalDCE.
1913 for (GlobalVariable &GV : M.globals())
1914 GV.eraseMetadata(LLVMContext::MD_vcall_visibility);
1915
19161943 return true;
19171944 }
19181945
+0
-19
test/LTO/ARM/lto-linking-metadata.ll less more
None ; RUN: opt %s -o %t1.bc
1
2 ; RUN: llvm-lto %t1.bc -o %t1.save.opt -save-merged-module -O1 --exported-symbol=foo
3 ; RUN: llvm-dis < %t1.save.opt.merged.bc | FileCheck %s
4
5 ; RUN: llvm-lto2 run %t1.bc -o %t.out.o -save-temps \
6 ; RUN: -r=%t1.bc,foo,pxl
7 ; RUN: llvm-dis < %t.out.o.0.2.internalize.bc | FileCheck %s
8
9 target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
10 target triple = "armv7a-unknown-linux"
11
12 define void @foo() {
13 entry:
14 ret void
15 }
16
17 ; CHECK: !llvm.module.flags = !{[[MD_NUM:![0-9]+]]}
18 ; CHECK: [[MD_NUM]] = !{i32 1, !"LTOPostLink", i32 1}
99 ; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t3.bc \
1010 ; RUN: -o /dev/null -stats \
1111 ; RUN: 2>&1 | FileCheck %s -check-prefix=LAZY
12 ; LAZY: 65 bitcode-reader - Number of Metadata records loaded
12 ; LAZY: 63 bitcode-reader - Number of Metadata records loaded
1313 ; LAZY: 2 bitcode-reader - Number of MDStrings loaded
1414
1515 ; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t3.bc \
1616 ; RUN: -o /dev/null -disable-ondemand-mds-loading -stats \
1717 ; RUN: 2>&1 | FileCheck %s -check-prefix=NOTLAZY
18 ; NOTLAZY: 74 bitcode-reader - Number of Metadata records loaded
18 ; NOTLAZY: 72 bitcode-reader - Number of Metadata records loaded
1919 ; NOTLAZY: 7 bitcode-reader - Number of MDStrings loaded
2020
2121
+0
-78
test/Transforms/GlobalDCE/virtual-functions-base-call.ll less more
None ; RUN: opt < %s -globaldce -S | FileCheck %s
1
2 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
3
4 ; struct A {
5 ; A();
6 ; virtual int foo();
7 ; };
8 ;
9 ; struct B : A {
10 ; B();
11 ; virtual int foo();
12 ; };
13 ;
14 ; A::A() {}
15 ; B::B() {}
16 ; int A::foo() { return 42; }
17 ; int B::foo() { return 1337; }
18 ;
19 ; extern "C" int test(A *p) { return p->foo(); }
20
21 ; The virtual call in test could be dispatched to either A::foo or B::foo, so
22 ; both must be retained.
23
24 %struct.A = type { i32 (...)** }
25 %struct.B = type { %struct.A }
26
27 ; CHECK: @_ZTV1A = internal unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.A*)* @_ZN1A3fooEv to i8*)] }
28 @_ZTV1A = internal unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.A*)* @_ZN1A3fooEv to i8*)] }, align 8, !type !0, !type !1, !vcall_visibility !2
29
30 ; CHECK: @_ZTV1B = internal unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.B*)* @_ZN1B3fooEv to i8*)] }
31 @_ZTV1B = internal unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.B*)* @_ZN1B3fooEv to i8*)] }, align 8, !type !0, !type !1, !type !3, !type !4, !vcall_visibility !2
32
33 ; CHECK: define internal i32 @_ZN1A3fooEv(
34 define internal i32 @_ZN1A3fooEv(%struct.A* nocapture readnone %this) {
35 entry:
36 ret i32 42
37 }
38
39 ; CHECK: define internal i32 @_ZN1B3fooEv(
40 define internal i32 @_ZN1B3fooEv(%struct.B* nocapture readnone %this) {
41 entry:
42 ret i32 1337
43 }
44
45 define hidden void @_ZN1AC2Ev(%struct.A* nocapture %this) {
46 entry:
47 %0 = getelementptr inbounds %struct.A, %struct.A* %this, i64 0, i32 0
48 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV1A, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
49 ret void
50 }
51
52 define hidden void @_ZN1BC2Ev(%struct.B* nocapture %this) {
53 entry:
54 %0 = getelementptr inbounds %struct.B, %struct.B* %this, i64 0, i32 0, i32 0
55 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV1B, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
56 ret void
57 }
58
59 define hidden i32 @test(%struct.A* %p) {
60 entry:
61 %0 = bitcast %struct.A* %p to i8**
62 %vtable1 = load i8*, i8** %0, align 8
63 %1 = tail call { i8*, i1 } @llvm.type.checked.load(i8* %vtable1, i32 0, metadata !"_ZTS1A"), !nosanitize !10
64 %2 = extractvalue { i8*, i1 } %1, 0, !nosanitize !10
65 %3 = bitcast i8* %2 to i32 (%struct.A*)*, !nosanitize !10
66 %call = tail call i32 %3(%struct.A* %p)
67 ret i32 %call
68 }
69
70 declare { i8*, i1 } @llvm.type.checked.load(i8*, i32, metadata) #2
71
72 !0 = !{i64 16, !"_ZTS1A"}
73 !1 = !{i64 16, !"_ZTSM1AFivE.virtual"}
74 !2 = !{i64 2}
75 !3 = !{i64 16, !"_ZTS1B"}
76 !4 = !{i64 16, !"_ZTSM1BFivE.virtual"}
77 !10 = !{}
+0
-118
test/Transforms/GlobalDCE/virtual-functions-base-pointer-call.ll less more
None ; RUN: opt < %s -globaldce -S | FileCheck %s
1
2 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
3
4 ; struct A {
5 ; A();
6 ; virtual int foo(int);
7 ; virtual int bar(float);
8 ; };
9 ;
10 ; struct B : A {
11 ; B();
12 ; virtual int foo(int);
13 ; virtual int bar(float);
14 ; };
15 ;
16 ; A::A() {}
17 ; B::B() {}
18 ; int A::foo(int) { return 1; }
19 ; int A::bar(float) { return 2; }
20 ; int B::foo(int) { return 3; }
21 ; int B::bar(float) { return 4; }
22 ;
23 ; extern "C" int test(A *p, int (A::*q)(int)) { return (p->*q)(42); }
24
25 ; Member function pointers are tracked by the combination of their object type
26 ; and function type, which must both be compatible. Here, the call is through a
27 ; pointer of type "int (A::*q)(int)", so the call could be dispatched to A::foo
28 ; or B::foo. It can't be dispatched to A::bar or B::bar as the function pointer
29 ; does not match, so those can be removed.
30
31 %struct.A = type { i32 (...)** }
32 %struct.B = type { %struct.A }
33
34 ; CHECK: @_ZTV1A = internal unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A3fooEi to i8*), i8* null] }
35 @_ZTV1A = internal unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A3fooEi to i8*), i8* bitcast (i32 (%struct.A*, float)* @_ZN1A3barEf to i8*)] }, align 8, !type !0, !type !1, !type !2, !vcall_visibility !3
36 ; CHECK: @_ZTV1B = internal unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.B*, i32)* @_ZN1B3fooEi to i8*), i8* null] }
37 @_ZTV1B = internal unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.B*, i32)* @_ZN1B3fooEi to i8*), i8* bitcast (i32 (%struct.B*, float)* @_ZN1B3barEf to i8*)] }, align 8, !type !0, !type !1, !type !2, !type !4, !type !5, !type !6, !vcall_visibility !3
38
39
40 ; CHECK: define internal i32 @_ZN1A3fooEi(
41 define internal i32 @_ZN1A3fooEi(%struct.A* nocapture readnone %this, i32) unnamed_addr #1 align 2 {
42 entry:
43 ret i32 1
44 }
45
46 ; CHECK-NOT: define internal i32 @_ZN1A3barEf(
47 define internal i32 @_ZN1A3barEf(%struct.A* nocapture readnone %this, float) unnamed_addr #1 align 2 {
48 entry:
49 ret i32 2
50 }
51
52 ; CHECK: define internal i32 @_ZN1B3fooEi(
53 define internal i32 @_ZN1B3fooEi(%struct.B* nocapture readnone %this, i32) unnamed_addr #1 align 2 {
54 entry:
55 ret i32 3
56 }
57
58 ; CHECK-NOT: define internal i32 @_ZN1B3barEf(
59 define internal i32 @_ZN1B3barEf(%struct.B* nocapture readnone %this, float) unnamed_addr #1 align 2 {
60 entry:
61 ret i32 4
62 }
63
64
65 define hidden void @_ZN1AC2Ev(%struct.A* nocapture %this) {
66 entry:
67 %0 = getelementptr inbounds %struct.A, %struct.A* %this, i64 0, i32 0
68 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [4 x i8*] }, { [4 x i8*] }* @_ZTV1A, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
69 ret void
70 }
71
72 define hidden void @_ZN1BC2Ev(%struct.B* nocapture %this) {
73 entry:
74 %0 = getelementptr inbounds %struct.B, %struct.B* %this, i64 0, i32 0, i32 0
75 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [4 x i8*] }, { [4 x i8*] }* @_ZTV1B, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
76 ret void
77 }
78
79 define hidden i32 @test(%struct.A* %p, i64 %q.coerce0, i64 %q.coerce1) {
80 entry:
81 %0 = bitcast %struct.A* %p to i8*
82 %1 = getelementptr inbounds i8, i8* %0, i64 %q.coerce1
83 %this.adjusted = bitcast i8* %1 to %struct.A*
84 %2 = and i64 %q.coerce0, 1
85 %memptr.isvirtual = icmp eq i64 %2, 0
86 br i1 %memptr.isvirtual, label %memptr.nonvirtual, label %memptr.virtual
87
88 memptr.virtual: ; preds = %entry
89 %3 = bitcast i8* %1 to i8**
90 %vtable = load i8*, i8** %3, align 8
91 %4 = add i64 %q.coerce0, -1
92 %5 = getelementptr i8, i8* %vtable, i64 %4, !nosanitize !12
93 %6 = tail call { i8*, i1 } @llvm.type.checked.load(i8* %5, i32 0, metadata !"_ZTSM1AFiiE.virtual"), !nosanitize !12
94 %7 = extractvalue { i8*, i1 } %6, 0, !nosanitize !12
95 %memptr.virtualfn = bitcast i8* %7 to i32 (%struct.A*, i32)*, !nosanitize !12
96 br label %memptr.end
97
98 memptr.nonvirtual: ; preds = %entry
99 %memptr.nonvirtualfn = inttoptr i64 %q.coerce0 to i32 (%struct.A*, i32)*
100 br label %memptr.end
101
102 memptr.end: ; preds = %memptr.nonvirtual, %memptr.virtual
103 %8 = phi i32 (%struct.A*, i32)* [ %memptr.virtualfn, %memptr.virtual ], [ %memptr.nonvirtualfn, %memptr.nonvirtual ]
104 %call = tail call i32 %8(%struct.A* %this.adjusted, i32 42)
105 ret i32 %call
106 }
107
108 declare { i8*, i1 } @llvm.type.checked.load(i8*, i32, metadata)
109
110 !0 = !{i64 16, !"_ZTS1A"}
111 !1 = !{i64 16, !"_ZTSM1AFiiE.virtual"}
112 !2 = !{i64 24, !"_ZTSM1AFifE.virtual"}
113 !3 = !{i64 2}
114 !4 = !{i64 16, !"_ZTS1B"}
115 !5 = !{i64 16, !"_ZTSM1BFiiE.virtual"}
116 !6 = !{i64 24, !"_ZTSM1BFifE.virtual"}
117 !12 = !{}
+0
-78
test/Transforms/GlobalDCE/virtual-functions-derived-call.ll less more
None ; RUN: opt < %s -globaldce -S | FileCheck %s
1
2 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
3
4 ; struct A {
5 ; A();
6 ; virtual int foo();
7 ; };
8 ;
9 ; struct B : A {
10 ; B();
11 ; virtual int foo();
12 ; };
13 ;
14 ; A::A() {}
15 ; B::B() {}
16 ; int A::foo() { return 42; }
17 ; int B::foo() { return 1337; }
18 ;
19 ; extern "C" int test(B *p) { return p->foo(); }
20
21 ; The virtual call in test can only be dispatched to B::foo (or a more-derived
22 ; class, if there was one), so A::foo can be removed.
23
24 %struct.A = type { i32 (...)** }
25 %struct.B = type { %struct.A }
26
27 ; CHECK: @_ZTV1A = internal unnamed_addr constant { [3 x i8*] } zeroinitializer
28 @_ZTV1A = internal unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.A*)* @_ZN1A3fooEv to i8*)] }, align 8, !type !0, !type !1, !vcall_visibility !2
29
30 ; CHECK: @_ZTV1B = internal unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.B*)* @_ZN1B3fooEv to i8*)] }
31 @_ZTV1B = internal unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.B*)* @_ZN1B3fooEv to i8*)] }, align 8, !type !0, !type !1, !type !3, !type !4, !vcall_visibility !2
32
33 ; CHECK-NOT: define internal i32 @_ZN1A3fooEv(
34 define internal i32 @_ZN1A3fooEv(%struct.A* nocapture readnone %this) {
35 entry:
36 ret i32 42
37 }
38
39 ; CHECK: define internal i32 @_ZN1B3fooEv(
40 define internal i32 @_ZN1B3fooEv(%struct.B* nocapture readnone %this) {
41 entry:
42 ret i32 1337
43 }
44
45 define hidden void @_ZN1AC2Ev(%struct.A* nocapture %this) {
46 entry:
47 %0 = getelementptr inbounds %struct.A, %struct.A* %this, i64 0, i32 0
48 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV1A, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
49 ret void
50 }
51
52 define hidden void @_ZN1BC2Ev(%struct.B* nocapture %this) {
53 entry:
54 %0 = getelementptr inbounds %struct.B, %struct.B* %this, i64 0, i32 0, i32 0
55 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV1B, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
56 ret void
57 }
58
59 define hidden i32 @test(%struct.B* %p) {
60 entry:
61 %0 = bitcast %struct.B* %p to i8**
62 %vtable1 = load i8*, i8** %0, align 8
63 %1 = tail call { i8*, i1 } @llvm.type.checked.load(i8* %vtable1, i32 0, metadata !"_ZTS1B"), !nosanitize !10
64 %2 = extractvalue { i8*, i1 } %1, 0, !nosanitize !10
65 %3 = bitcast i8* %2 to i32 (%struct.B*)*, !nosanitize !10
66 %call = tail call i32 %3(%struct.B* %p)
67 ret i32 %call
68 }
69
70 declare { i8*, i1 } @llvm.type.checked.load(i8*, i32, metadata) #2
71
72 !0 = !{i64 16, !"_ZTS1A"}
73 !1 = !{i64 16, !"_ZTSM1AFivE.virtual"}
74 !2 = !{i64 2}
75 !3 = !{i64 16, !"_ZTS1B"}
76 !4 = !{i64 16, !"_ZTSM1BFivE.virtual"}
77 !10 = !{}
+0
-120
test/Transforms/GlobalDCE/virtual-functions-derived-pointer-call.ll less more
None
1 ; RUN: opt < %s -globaldce -S | FileCheck %s
2
3 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
4
5 ; struct A {
6 ; A();
7 ; virtual int foo(int);
8 ; virtual int bar(float);
9 ; };
10 ;
11 ; struct B : A {
12 ; B();
13 ; virtual int foo(int);
14 ; virtual int bar(float);
15 ; };
16 ;
17 ; A::A() {}
18 ; B::B() {}
19 ; int A::foo(int) { return 1; }
20 ; int A::bar(float) { return 2; }
21 ; int B::foo(int) { return 3; }
22 ; int B::bar(float) { return 4; }
23 ;
24 ; extern "C" int test(B *p, int (B::*q)(int)) { return (p->*q)(42); }
25
26 ; Member function pointers are tracked by the combination of their object type
27 ; and function type, which must both be compatible. Here, the call is through a
28 ; pointer of type "int (B::*q)(int)", so the call could only be dispatched to
29 ; B::foo. It can't be dispatched to A::bar or B::bar as the function pointer
30 ; does not match, and it can't be dispatched to A::foo as the object type
31 ; doesn't match, so those can be removed.
32
33 %struct.A = type { i32 (...)** }
34 %struct.B = type { %struct.A }
35
36 ; CHECK: @_ZTV1A = internal unnamed_addr constant { [4 x i8*] } zeroinitializer
37 @_ZTV1A = internal unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A3fooEi to i8*), i8* bitcast (i32 (%struct.A*, float)* @_ZN1A3barEf to i8*)] }, align 8, !type !0, !type !1, !type !2, !vcall_visibility !3
38 ; CHECK: @_ZTV1B = internal unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.B*, i32)* @_ZN1B3fooEi to i8*), i8* null] }
39 @_ZTV1B = internal unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.B*, i32)* @_ZN1B3fooEi to i8*), i8* bitcast (i32 (%struct.B*, float)* @_ZN1B3barEf to i8*)] }, align 8, !type !0, !type !1, !type !2, !type !4, !type !5, !type !6, !vcall_visibility !3
40
41
42 ; CHECK-NOT: define internal i32 @_ZN1A3fooEi(
43 define internal i32 @_ZN1A3fooEi(%struct.A* nocapture readnone %this, i32) unnamed_addr #1 align 2 {
44 entry:
45 ret i32 1
46 }
47
48 ; CHECK-NOT: define internal i32 @_ZN1A3barEf(
49 define internal i32 @_ZN1A3barEf(%struct.A* nocapture readnone %this, float) unnamed_addr #1 align 2 {
50 entry:
51 ret i32 2
52 }
53
54 ; CHECK: define internal i32 @_ZN1B3fooEi(
55 define internal i32 @_ZN1B3fooEi(%struct.B* nocapture readnone %this, i32) unnamed_addr #1 align 2 {
56 entry:
57 ret i32 3
58 }
59
60 ; CHECK-NOT: define internal i32 @_ZN1B3barEf(
61 define internal i32 @_ZN1B3barEf(%struct.B* nocapture readnone %this, float) unnamed_addr #1 align 2 {
62 entry:
63 ret i32 4
64 }
65
66
67 define hidden void @_ZN1AC2Ev(%struct.A* nocapture %this) {
68 entry:
69 %0 = getelementptr inbounds %struct.A, %struct.A* %this, i64 0, i32 0
70 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [4 x i8*] }, { [4 x i8*] }* @_ZTV1A, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
71 ret void
72 }
73
74 define hidden void @_ZN1BC2Ev(%struct.B* nocapture %this) {
75 entry:
76 %0 = getelementptr inbounds %struct.B, %struct.B* %this, i64 0, i32 0, i32 0
77 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [4 x i8*] }, { [4 x i8*] }* @_ZTV1B, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
78 ret void
79 }
80
81 define hidden i32 @test(%struct.B* %p, i64 %q.coerce0, i64 %q.coerce1) {
82 entry:
83 %0 = bitcast %struct.B* %p to i8*
84 %1 = getelementptr inbounds i8, i8* %0, i64 %q.coerce1
85 %this.adjusted = bitcast i8* %1 to %struct.B*
86 %2 = and i64 %q.coerce0, 1
87 %memptr.isvirtual = icmp eq i64 %2, 0
88 br i1 %memptr.isvirtual, label %memptr.nonvirtual, label %memptr.virtual
89
90 memptr.virtual: ; preds = %entry
91 %3 = bitcast i8* %1 to i8**
92 %vtable = load i8*, i8** %3, align 8
93 %4 = add i64 %q.coerce0, -1
94 %5 = getelementptr i8, i8* %vtable, i64 %4, !nosanitize !12
95 %6 = tail call { i8*, i1 } @llvm.type.checked.load(i8* %5, i32 0, metadata !"_ZTSM1BFiiE.virtual"), !nosanitize !12
96 %7 = extractvalue { i8*, i1 } %6, 0, !nosanitize !12
97 %memptr.virtualfn = bitcast i8* %7 to i32 (%struct.B*, i32)*, !nosanitize !12
98 br label %memptr.end
99
100 memptr.nonvirtual: ; preds = %entry
101 %memptr.nonvirtualfn = inttoptr i64 %q.coerce0 to i32 (%struct.B*, i32)*
102 br label %memptr.end
103
104 memptr.end: ; preds = %memptr.nonvirtual, %memptr.virtual
105 %8 = phi i32 (%struct.B*, i32)* [ %memptr.virtualfn, %memptr.virtual ], [ %memptr.nonvirtualfn, %memptr.nonvirtual ]
106 %call = tail call i32 %8(%struct.B* %this.adjusted, i32 42)
107 ret i32 %call
108 }
109
110 declare { i8*, i1 } @llvm.type.checked.load(i8*, i32, metadata)
111
112 !0 = !{i64 16, !"_ZTS1A"}
113 !1 = !{i64 16, !"_ZTSM1AFiiE.virtual"}
114 !2 = !{i64 24, !"_ZTSM1AFifE.virtual"}
115 !3 = !{i64 2}
116 !4 = !{i64 16, !"_ZTS1B"}
117 !5 = !{i64 16, !"_ZTSM1BFiiE.virtual"}
118 !6 = !{i64 24, !"_ZTSM1BFifE.virtual"}
119 !12 = !{}
+0
-95
test/Transforms/GlobalDCE/virtual-functions-visibility-post-lto.ll less more
None ; RUN: opt < %s -globaldce -S | FileCheck %s
1
2 ; structs A, B and C have vcall_visibility of public, linkage-unit and
3 ; translation-unit respectively. This test is run after LTO linking (the
4 ; LTOPostLink metadata is present), so B and C can be VFE'd.
5
6 target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
7
8 %struct.A = type { i32 (...)** }
9
10 @_ZTV1A = hidden unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (void (%struct.A*)* @_ZN1A3fooEv to i8*)] }, align 8, !type !0, !type !1, !vcall_visibility !2
11
12 define internal void @_ZN1AC2Ev(%struct.A* %this) {
13 entry:
14 %0 = getelementptr inbounds %struct.A, %struct.A* %this, i64 0, i32 0
15 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV1A, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
16 ret void
17 }
18
19 ; CHECK: define {{.*}} @_ZN1A3fooEv(
20 define internal void @_ZN1A3fooEv(%struct.A* nocapture %this) {
21 entry:
22 ret void
23 }
24
25 define dso_local i8* @_Z6make_Av() {
26 entry:
27 %call = tail call i8* @_Znwm(i64 8)
28 %0 = bitcast i8* %call to %struct.A*
29 tail call void @_ZN1AC2Ev(%struct.A* %0)
30 ret i8* %call
31 }
32
33
34 %struct.B = type { i32 (...)** }
35
36 @_ZTV1B = hidden unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (void (%struct.B*)* @_ZN1B3fooEv to i8*)] }, align 8, !type !0, !type !1, !vcall_visibility !3
37
38 define internal void @_ZN1BC2Ev(%struct.B* %this) {
39 entry:
40 %0 = getelementptr inbounds %struct.B, %struct.B* %this, i64 0, i32 0
41 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV1B, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
42 ret void
43 }
44
45 ; CHECK-NOT: define {{.*}} @_ZN1B3fooEv(
46 define internal void @_ZN1B3fooEv(%struct.B* nocapture %this) {
47 entry:
48 ret void
49 }
50
51 define dso_local i8* @_Z6make_Bv() {
52 entry:
53 %call = tail call i8* @_Znwm(i64 8)
54 %0 = bitcast i8* %call to %struct.B*
55 tail call void @_ZN1BC2Ev(%struct.B* %0)
56 ret i8* %call
57 }
58
59
60 %struct.C = type { i32 (...)** }
61
62 @_ZTV1C = hidden unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (void (%struct.C*)* @_ZN1C3fooEv to i8*)] }, align 8, !type !0, !type !1, !vcall_visibility !4
63
64 define internal void @_ZN1CC2Ev(%struct.C* %this) {
65 entry:
66 %0 = getelementptr inbounds %struct.C, %struct.C* %this, i64 0, i32 0
67 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV1C, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
68 ret void
69 }
70
71 ; CHECK-NOT: define {{.*}} @_ZN1C3fooEv(
72 define internal void @_ZN1C3fooEv(%struct.C* nocapture %this) {
73 entry:
74 ret void
75 }
76
77 define dso_local i8* @_Z6make_Cv() {
78 entry:
79 %call = tail call i8* @_Znwm(i64 8)
80 %0 = bitcast i8* %call to %struct.C*
81 tail call void @_ZN1CC2Ev(%struct.C* %0)
82 ret i8* %call
83 }
84
85 declare dso_local noalias nonnull i8* @_Znwm(i64)
86
87 !llvm.module.flags = !{!5}
88
89 !0 = !{i64 16, !"_ZTS1A"}
90 !1 = !{i64 16, !"_ZTSM1AFvvE.virtual"}
91 !2 = !{i64 0} ; public vcall visibility
92 !3 = !{i64 1} ; linkage-unit vcall visibility
93 !4 = !{i64 2} ; translation-unit vcall visibility
94 !5 = !{i32 1, !"LTOPostLink", i32 1}
+0
-94
test/Transforms/GlobalDCE/virtual-functions-visibility-pre-lto.ll less more
None ; RUN: opt < %s -globaldce -S | FileCheck %s
1
2 ; structs A, B and C have vcall_visibility of public, linkage-unit and
3 ; translation-unit respectively. This test is run before LTO linking occurs
4 ; (the LTOPostLink metadata is not present), so only C can be VFE'd.
5
6 target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
7
8 %struct.A = type { i32 (...)** }
9
10 @_ZTV1A = hidden unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (void (%struct.A*)* @_ZN1A3fooEv to i8*)] }, align 8, !type !0, !type !1, !vcall_visibility !2
11
12 define internal void @_ZN1AC2Ev(%struct.A* %this) {
13 entry:
14 %0 = getelementptr inbounds %struct.A, %struct.A* %this, i64 0, i32 0
15 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV1A, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
16 ret void
17 }
18
19 ; CHECK: define {{.*}} @_ZN1A3fooEv(
20 define internal void @_ZN1A3fooEv(%struct.A* nocapture %this) {
21 entry:
22 ret void
23 }
24
25 define dso_local i8* @_Z6make_Av() {
26 entry:
27 %call = tail call i8* @_Znwm(i64 8)
28 %0 = bitcast i8* %call to %struct.A*
29 tail call void @_ZN1AC2Ev(%struct.A* %0)
30 ret i8* %call
31 }
32
33
34 %struct.B = type { i32 (...)** }
35
36 @_ZTV1B = hidden unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (void (%struct.B*)* @_ZN1B3fooEv to i8*)] }, align 8, !type !0, !type !1, !vcall_visibility !3
37
38 define internal void @_ZN1BC2Ev(%struct.B* %this) {
39 entry:
40 %0 = getelementptr inbounds %struct.B, %struct.B* %this, i64 0, i32 0
41 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV1B, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
42 ret void
43 }
44
45 ; CHECK: define {{.*}} @_ZN1B3fooEv(
46 define internal void @_ZN1B3fooEv(%struct.B* nocapture %this) {
47 entry:
48 ret void
49 }
50
51 define dso_local i8* @_Z6make_Bv() {
52 entry:
53 %call = tail call i8* @_Znwm(i64 8)
54 %0 = bitcast i8* %call to %struct.B*
55 tail call void @_ZN1BC2Ev(%struct.B* %0)
56 ret i8* %call
57 }
58
59
60 %struct.C = type { i32 (...)** }
61
62 @_ZTV1C = hidden unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (void (%struct.C*)* @_ZN1C3fooEv to i8*)] }, align 8, !type !0, !type !1, !vcall_visibility !4
63
64 define internal void @_ZN1CC2Ev(%struct.C* %this) {
65 entry:
66 %0 = getelementptr inbounds %struct.C, %struct.C* %this, i64 0, i32 0
67 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV1C, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
68 ret void
69 }
70
71 ; CHECK-NOT: define {{.*}} @_ZN1C3fooEv(
72 define internal void @_ZN1C3fooEv(%struct.C* nocapture %this) {
73 entry:
74 ret void
75 }
76
77 define dso_local i8* @_Z6make_Cv() {
78 entry:
79 %call = tail call i8* @_Znwm(i64 8)
80 %0 = bitcast i8* %call to %struct.C*
81 tail call void @_ZN1CC2Ev(%struct.C* %0)
82 ret i8* %call
83 }
84
85 declare dso_local noalias nonnull i8* @_Znwm(i64)
86
87 !llvm.module.flags = !{}
88
89 !0 = !{i64 16, !"_ZTS1A"}
90 !1 = !{i64 16, !"_ZTSM1AFvvE.virtual"}
91 !2 = !{i64 0} ; public vcall visibility
92 !3 = !{i64 1} ; linkage-unit vcall visibility
93 !4 = !{i64 2} ; translation-unit vcall visibility
+0
-55
test/Transforms/GlobalDCE/virtual-functions.ll less more
None ; RUN: opt < %s -globaldce -S | FileCheck %s
1
2 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
3
4 declare dso_local noalias nonnull i8* @_Znwm(i64)
5 declare { i8*, i1 } @llvm.type.checked.load(i8*, i32, metadata)
6
7 ; %struct.A is a C++ struct with two virtual functions, A::foo and A::bar. The
8 ; !vcall_visibility metadata is set on the vtable, so we know that all virtual
9 ; calls through this vtable are visible and use the @llvm.type.checked.load
10 ; intrinsic. Function test_A makes a call to A::foo, but there is no call to
11 ; A::bar anywhere, so A::bar can be deleted, and its vtable slot replaced with
12 ; null.
13
14 %struct.A = type { i32 (...)** }
15
16 ; The pointer to A::bar in the vtable can be removed, because it will never be
17 ; loaded. We replace it with null to keep the layout the same. Because it is at
18 ; the end of the vtable we could potentially shrink the vtable, but don't
19 ; currently do that.
20 ; CHECK: @_ZTV1A = internal unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.A*)* @_ZN1A3fooEv to i8*), i8* null] }
21 @_ZTV1A = internal unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* null, i8* bitcast (i32 (%struct.A*)* @_ZN1A3fooEv to i8*), i8* bitcast (i32 (%struct.A*)* @_ZN1A3barEv to i8*)] }, align 8, !type !0, !type !1, !type !2, !vcall_visibility !3
22
23 ; A::foo is called, so must be retained.
24 ; CHECK: define internal i32 @_ZN1A3fooEv(
25 define internal i32 @_ZN1A3fooEv(%struct.A* nocapture readnone %this) {
26 entry:
27 ret i32 42
28 }
29
30 ; A::bar is not used, so can be deleted.
31 ; CHECK-NOT: define internal i32 @_ZN1A3barEv(
32 define internal i32 @_ZN1A3barEv(%struct.A* nocapture readnone %this) {
33 entry:
34 ret i32 1337
35 }
36
37 define dso_local i32 @test_A() {
38 entry:
39 %call = tail call i8* @_Znwm(i64 8)
40 %0 = bitcast i8* %call to %struct.A*
41 %1 = bitcast i8* %call to i32 (...)***
42 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [4 x i8*] }, { [4 x i8*] }* @_ZTV1A, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %1, align 8
43 %2 = tail call { i8*, i1 } @llvm.type.checked.load(i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*] }, { [4 x i8*] }* @_ZTV1A, i64 0, inrange i32 0, i64 2) to i8*), i32 0, metadata !"_ZTS1A"), !nosanitize !9
44 %3 = extractvalue { i8*, i1 } %2, 0, !nosanitize !9
45 %4 = bitcast i8* %3 to i32 (%struct.A*)*, !nosanitize !9
46 %call1 = tail call i32 %4(%struct.A* nonnull %0)
47 ret i32 %call1
48 }
49
50 !0 = !{i64 16, !"_ZTS1A"}
51 !1 = !{i64 16, !"_ZTSM1AFivE.virtual"}
52 !2 = !{i64 24, !"_ZTSM1AFivE.virtual"}
53 !3 = !{i64 2}
54 !9 = !{}
+0
-47
test/Transforms/GlobalDCE/vtable-rtti.ll less more
None ; RUN: opt < %s -globaldce -S | FileCheck %s
1
2 ; We currently only use llvm.type.checked.load for virtual function pointers,
3 ; not any other part of the vtable, so we can't remove the RTTI pointer even if
4 ; it's never going to be loaded from.
5
6 target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
7
8 %struct.A = type { i32 (...)** }
9
10 ; CHECK: @_ZTV1A = hidden unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* null] }, align 8, !type !0, !type !1, !vcall_visibility !2
11
12 @_ZTV1A = hidden unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast (void (%struct.A*)* @_ZN1A3fooEv to i8*)] }, align 8, !type !0, !type !1, !vcall_visibility !2
13 @_ZTS1A = hidden constant [3 x i8] c"1A\00", align 1
14 @_ZTI1A = hidden constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1A, i32 0, i32 0) }, align 8
15
16 define internal void @_ZN1AC2Ev(%struct.A* %this) {
17 entry:
18 %0 = getelementptr inbounds %struct.A, %struct.A* %this, i64 0, i32 0
19 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV1A, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
20 ret void
21 }
22
23 ; CHECK-NOT: define {{.*}} @_ZN1A3fooEv(
24 define internal void @_ZN1A3fooEv(%struct.A* nocapture %this) {
25 entry:
26 ret void
27 }
28
29 define dso_local i8* @_Z6make_Av() {
30 entry:
31 %call = tail call i8* @_Znwm(i64 8)
32 %0 = bitcast i8* %call to %struct.A*
33 tail call void @_ZN1AC2Ev(%struct.A* %0)
34 ret i8* %call
35 }
36
37
38 declare dso_local noalias nonnull i8* @_Znwm(i64)
39 @_ZTVN10__cxxabiv117__class_type_infoE = external dso_local global i8*
40
41 !llvm.module.flags = !{!3}
42
43 !0 = !{i64 16, !"_ZTS1A"}
44 !1 = !{i64 16, !"_ZTSM1AFvvE.virtual"}
45 !2 = !{i64 2} ; translation-unit vcall visibility
46 !3 = !{i32 1, !"LTOPostLink", i32 1}
+0
-64
test/Transforms/Internalize/vcall-visibility.ll less more
None ; RUN: opt < %s -internalize -S | FileCheck %s
1
2 %struct.A = type { i32 (...)** }
3 %struct.B = type { i32 (...)** }
4 %struct.C = type { i32 (...)** }
5
6 ; Class A has default visibility, so has no !vcall_visibility metadata before
7 ; or after LTO.
8 ; CHECK-NOT: @_ZTV1A = {{.*}}!vcall_visibility
9 @_ZTV1A = dso_local unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (void (%struct.A*)* @_ZN1A3fooEv to i8*)] }, align 8, !type !0, !type !1
10
11 ; Class B has hidden visibility but public LTO visibility, so has no
12 ; !vcall_visibility metadata before or after LTO.
13 ; CHECK-NOT: @_ZTV1B = {{.*}}!vcall_visibility
14 @_ZTV1B = hidden unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (void (%struct.B*)* @_ZN1B3fooEv to i8*)] }, align 8, !type !2, !type !3
15
16 ; Class C has hidden visibility, so the !vcall_visibility metadata is set to 1
17 ; (linkage unit) before LTO, and 2 (translation unit) after LTO.
18 ; CHECK: @_ZTV1C ={{.*}}!vcall_visibility [[MD_TU_VIS:![0-9]+]]
19 @_ZTV1C = hidden unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (void (%struct.C*)* @_ZN1C3fooEv to i8*)] }, align 8, !type !4, !type !5, !vcall_visibility !6
20
21 ; Class D has translation unit visibility before LTO, and this is not changed
22 ; by LTO.
23 ; CHECK: @_ZTVN12_GLOBAL__N_11DE = {{.*}}!vcall_visibility [[MD_TU_VIS:![0-9]+]]
24 @_ZTVN12_GLOBAL__N_11DE = internal unnamed_addr constant { [3 x i8*] } zeroinitializer, align 8, !type !7, !type !9, !vcall_visibility !11
25
26 define dso_local void @_ZN1A3fooEv(%struct.A* nocapture %this) {
27 entry:
28 ret void
29 }
30
31 define hidden void @_ZN1B3fooEv(%struct.B* nocapture %this) {
32 entry:
33 ret void
34 }
35
36 define hidden void @_ZN1C3fooEv(%struct.C* nocapture %this) {
37 entry:
38 ret void
39 }
40
41 define hidden noalias nonnull i8* @_Z6make_dv() {
42 entry:
43 %call = tail call i8* @_Znwm(i64 8) #3
44 %0 = bitcast i8* %call to i32 (...)***
45 store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTVN12_GLOBAL__N_11DE, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %0, align 8
46 ret i8* %call
47 }
48
49 declare dso_local noalias nonnull i8* @_Znwm(i64)
50
51 ; CHECK: [[MD_TU_VIS]] = !{i64 2}
52 !0 = !{i64 16, !"_ZTS1A"}
53 !1 = !{i64 16, !"_ZTSM1AFvvE.virtual"}
54 !2 = !{i64 16, !"_ZTS1B"}
55 !3 = !{i64 16, !"_ZTSM1BFvvE.virtual"}
56 !4 = !{i64 16, !"_ZTS1C"}
57 !5 = !{i64 16, !"_ZTSM1CFvvE.virtual"}
58 !6 = !{i64 1}
59 !7 = !{i64 16, !8}
60 !8 = distinct !{}
61 !9 = !{i64 16, !10}
62 !10 = distinct !{}
63 !11 = !{i64 2}