llvm.org GIT mirror llvm / 3400920
Reland: Dead Virtual Function Elimination Remove dead virtual functions from vtables with replaceNonMetadataUsesWith, so that CGProfile metadata gets cleaned up correctly. Original commit message: Currently, it is hard for the compiler to remove unused C++ virtual functions, because they are all referenced from vtables, which are referenced by constructors. This means that if the constructor is called from any live code, then we keep every virtual function in the final link, even if there are no call sites which can use it. This patch allows unused virtual functions to be removed during LTO (and regular compilation in limited circumstances) by using type metadata to match virtual function call sites to the vtable slots they might load from. This information can then be used in the global dead code elimination pass instead of the references from vtables to virtual functions, to more accurately determine which functions are reachable. To make this transformation safe, I have changed clang's code-generation to always load virtual function pointers using the llvm.type.checked.load intrinsic, instead of regular load instructions. I originally tried writing this using clang's existing code-generation, which uses the llvm.type.test and llvm.assume intrinsics after doing a normal load. However, it is possible for optimisations to obscure the relationship between the GEP, load and llvm.type.test, causing GlobalDCE to fail to find virtual function call sites. The existing linkage and visibility types don't accurately describe the scope in which a virtual call could be made which uses a given vtable. This is wider than the visibility of the type itself, because a virtual function call could be made using a more-visible base class. I've added a new !vcall_visibility metadata type to represent this, described in TypeMetadata.rst. The internalization pass and libLTO have been updated to change this metadata when linking is performed. This doesn't currently work with ThinLTO, because it needs to see every call to llvm.type.checked.load in the linkage unit. It might be possible to extend this optimisation to be able to use the ThinLTO summary, as was done for devirtualization, but until then that combination is rejected in the clang driver. To test this, I've written a fuzzer which generates random C++ programs with complex class inheritance graphs, and virtual functions called through object and function pointers of different types. The programs are spread across multiple translation units and DSOs to test the different visibility restrictions. I've also tried doing bootstrap builds of LLVM to test this. This isn't ideal, because only classes in anonymous namespaces can be optimised with -fvisibility=default, and some parts of LLVM (plugins and bugpoint) do not work correctly with -fvisibility=hidden. However, there are only 12 test failures when building with -fvisibility=hidden (and an unmodified compiler), and this change does not cause any new failures for either value of -fvisibility. On the 7 C++ sub-benchmarks of SPEC2006, this gives a geomean code-size reduction of ~6%, over a baseline compiled with "-O2 -flto -fvisibility=hidden -fwhole-program-vtables". The best cases are reductions of ~14% in 450.soplex and 483.xalancbmk, and there are no code size increases. I've also run this on a set of 8 mbed-os examples compiled for Armv7M, which show a geomean size reduction of ~3%, again with no size increases. I had hoped that this would have no effect on performance, which would allow it to awlays be enabled (when using -fwhole-program-vtables). However, the changes in clang to use the llvm.type.checked.load intrinsic are causing ~1% performance regression in the C++ parts of SPEC2006. It should be possible to recover some of this perf loss by teaching optimisations about the llvm.type.checked.load intrinsic, which would make it worth turning this on by default (though it's still dependent on -fwhole-program-vtables). Differential revision: https://reviews.llvm.org/D63932 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@375094 91177308-0d34-0410-b5e6-96231b3b80d8 Oliver Stannard 1 year, 1 month ago
23 changed file(s) with 1092 addition(s) and 39 deletion(s). Raw diff Collapse all Expand all
62706270 !0 = !{i32 1, !"short_wchar", i32 1}
62716271 !1 = !{i32 1, !"short_enum", i32 0}
62726272
6273 LTO Post-Link Module Flags Metadata
6274 -----------------------------------
6275
6276 Some optimisations are only when the entire LTO unit is present in the current
6277 module. This is represented by the ``LTOPostLink`` module flags metadata, which
6278 will be created with a value of ``1`` when LTO linking occurs.
6279
62736280 Automatic Linker Flags Named Metadata
62746281 =====================================
62756282
1681516822 The ``llvm.type.test`` intrinsic tests whether the given pointer is associated
1681616823 with the given type identifier.
1681716824
16825 .. _type.checked.load:
16826
1681816827 '``llvm.type.checked.load``' Intrinsic
1681916828 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1682016829
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);
5254 }
5355
5456 #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
3044 protected:
3145 GlobalObject(Type *Ty, ValueTy VTy, Use *Ops, unsigned NumOps,
3246 LinkageTypes Linkage, const Twine &Name,
163177 void copyMetadata(const GlobalObject *Src, unsigned Offset);
164178
165179 void addTypeMetadata(unsigned Offset, Metadata *TypeID);
180 void addVCallVisibilityMetadata(VCallVisibility Visibility);
181 VCallVisibility getVCallVisibility() const;
166182
167183 protected:
168184 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
4553 void UpdateGVDependencies(GlobalValue &GV);
4654 void MarkLive(GlobalValue &GV,
4755 SmallVectorImpl *Updates = nullptr);
4856 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);
4963
5064 void ComputeDependencies(Value *V, SmallPtrSetImpl &U);
5165 };
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
14991517 void Function::setSubprogram(DISubprogram *SP) {
15001518 setMetadata(LLVMContext::MD_dbg, SP);
15011519 }
10031003 GV->setLinkage(GlobalValue::InternalLinkage);
10041004 }
10051005
1006 RegularLTO.CombinedModule->addModuleFlag(Module::Error, "LTOPostLink", 1);
1007
10061008 if (Conf.PostInternalizeModuleHook &&
10071009 !Conf.PostInternalizeModuleHook(0, *RegularLTO.CombinedModule))
10081010 return Error::success();
462462
463463 internalizeModule(*MergedModule, mustPreserveGV);
464464
465 MergedModule->addModuleFlag(Module::Error, "LTOPostLink", 1);
466
465467 ScopeRestrictionsDone = true;
466468 }
467469
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"
1920 #include "llvm/IR/Instructions.h"
2021 #include "llvm/IR/IntrinsicInst.h"
2122 #include "llvm/IR/Module.h"
23 #include "llvm/IR/Operator.h"
2224 #include "llvm/Pass.h"
2325 #include "llvm/Transforms/IPO.h"
2426 #include "llvm/Transforms/Utils/CtorUtils.h"
2830
2931 #define DEBUG_TYPE "globaldce"
3032
33 static cl::opt
34 ClEnableVFE("enable-vfe", cl::Hidden, cl::init(true), cl::ZeroOrMore,
35 cl::desc("Enable virtual function elimination"));
36
3137 STATISTIC(NumAliases , "Number of global aliases removed");
3238 STATISTIC(NumFunctions, "Number of functions removed");
3339 STATISTIC(NumIFuncs, "Number of indirect functions removed");
3440 STATISTIC(NumVariables, "Number of global variables removed");
41 STATISTIC(NumVFuncs, "Number of virtual functions removed");
3542
3643 namespace {
3744 class GlobalDCELegacyPass : public ModulePass {
117124 ComputeDependencies(User, Deps);
118125 Deps.erase(&GV); // Remove self-reference.
119126 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 }
120136 GVDependencies[GVU].insert(&GV);
121137 }
122138 }
131147 if (Updates)
132148 Updates->push_back(&GV);
133149 if (Comdat *C = GV.getComdat()) {
134 for (auto &&CM : make_range(ComdatMembers.equal_range(C)))
150 for (auto &&CM : make_range(ComdatMembers.equal_range(C))) {
135151 MarkLive(*CM.second, Updates); // Recursion depth is only two because only
136152 // globals in the same comdat are visited.
137 }
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 );
138275 }
139276
140277 PreservedAnalyses GlobalDCEPass::run(Module &M, ModuleAnalysisManager &MAM) {
161298 for (GlobalAlias &GA : M.aliases())
162299 if (Comdat *C = GA.getComdat())
163300 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);
164305
165306 // Loop over the module, adding globals which are obviously necessary.
166307 for (GlobalObject &GO : M.global_objects()) {
256397 };
257398
258399 NumFunctions += DeadFunctions.size();
259 for (Function *F : DeadFunctions)
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->replaceNonMetadataUsesWith(ConstantPointerNull::get(F->getType()));
408 }
260409 EraseUnusedGlobalValue(F);
410 }
261411
262412 NumVariables += DeadGlobalVars.size();
263413 for (GlobalVariable *GV : DeadGlobalVars)
276426 ConstantDependenciesCache.clear();
277427 GVDependencies.clear();
278428 ComdatMembers.clear();
429 TypeIdMap.clear();
430 VFESafeVTables.clear();
279431
280432 if (Changed)
281433 return PreservedAnalyses::none();
491491 void buildTypeIdentifierMap(
492492 std::vector &Bits,
493493 DenseMap> &TypeIdMap);
494 Constant *getPointerAtOffset(Constant *I, uint64_t Offset);
495494 bool
496495 tryFindVirtualCallTargets(std::vector &TargetsForSlot,
497496 const std::set &TypeMemberInfos,
809808 }
810809 }
811810
812 Constant *DevirtModule::getPointerAtOffset(Constant *I, uint64_t Offset) {
813 if (I->getType()->isPointerTy()) {
814 if (Offset == 0)
815 return I;
816 return nullptr;
817 }
818
819 const DataLayout &DL = M.getDataLayout();
820
821 if (auto *C = dyn_cast(I)) {
822 const StructLayout *SL = DL.getStructLayout(C->getType());
823 if (Offset >= SL->getSizeInBytes())
824 return nullptr;
825
826 unsigned Op = SL->getElementContainingOffset(Offset);
827 return getPointerAtOffset(cast(I->getOperand(Op)),
828 Offset - SL->getElementOffset(Op));
829 }
830 if (auto *C = dyn_cast(I)) {
831 ArrayType *VTableTy = C->getType();
832 uint64_t ElemSize = DL.getTypeAllocSize(VTableTy->getElementType());
833
834 unsigned Op = Offset / ElemSize;
835 if (Op >= C->getNumOperands())
836 return nullptr;
837
838 return getPointerAtOffset(cast(I->getOperand(Op)),
839 Offset % ElemSize);
840 }
841 return nullptr;
842 }
843
844811 bool DevirtModule::tryFindVirtualCallTargets(
845812 std::vector &TargetsForSlot,
846813 const std::set &TypeMemberInfos, uint64_t ByteOffset) {
849816 return false;
850817
851818 Constant *Ptr = getPointerAtOffset(TM.Bits->GV->getInitializer(),
852 TM.Offset + ByteOffset);
819 TM.Offset + ByteOffset, M);
853820 if (!Ptr)
854821 return false;
855822
19501917 for (VTableBits &B : Bits)
19511918 rebuildGlobal(B);
19521919
1920 // We have lowered or deleted the type checked load intrinsics, so we no
1921 // longer have enough information to reason about the liveness of virtual
1922 // function pointers in GlobalDCE.
1923 for (GlobalVariable &GV : M.globals())
1924 GV.eraseMetadata(LLVMContext::MD_vcall_visibility);
1925
19531926 return true;
19541927 }
19551928
0 ; 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: 63 bitcode-reader - Number of Metadata records loaded
12 ; LAZY: 65 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: 72 bitcode-reader - Number of Metadata records loaded
18 ; NOTLAZY: 74 bitcode-reader - Number of Metadata records loaded
1919 ; NOTLAZY: 7 bitcode-reader - Number of MDStrings loaded
2020
2121
0 ; 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 ; 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 ; 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
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 ; 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 ; 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 ; 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 ; 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 ; 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}