13ca95b02SDimitry Andric //===- WholeProgramDevirt.cpp - Whole program virtual call optimization ---===//
23ca95b02SDimitry Andric //
33ca95b02SDimitry Andric //                     The LLVM Compiler Infrastructure
43ca95b02SDimitry Andric //
53ca95b02SDimitry Andric // This file is distributed under the University of Illinois Open Source
63ca95b02SDimitry Andric // License. See LICENSE.TXT for details.
73ca95b02SDimitry Andric //
83ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
93ca95b02SDimitry Andric //
103ca95b02SDimitry Andric // This pass implements whole program optimization of virtual calls in cases
113ca95b02SDimitry Andric // where we know (via !type metadata) that the list of callees is fixed. This
123ca95b02SDimitry Andric // includes the following:
133ca95b02SDimitry Andric // - Single implementation devirtualization: if a virtual call has a single
143ca95b02SDimitry Andric //   possible callee, replace all calls with a direct call to that callee.
153ca95b02SDimitry Andric // - Virtual constant propagation: if the virtual function's return type is an
163ca95b02SDimitry Andric //   integer <=64 bits and all possible callees are readnone, for each class and
173ca95b02SDimitry Andric //   each list of constant arguments: evaluate the function, store the return
183ca95b02SDimitry Andric //   value alongside the virtual table, and rewrite each virtual call as a load
193ca95b02SDimitry Andric //   from the virtual table.
203ca95b02SDimitry Andric // - Uniform return value optimization: if the conditions for virtual constant
213ca95b02SDimitry Andric //   propagation hold and each function returns the same constant value, replace
223ca95b02SDimitry Andric //   each virtual call with that constant.
233ca95b02SDimitry Andric // - Unique return value optimization for i1 return values: if the conditions
243ca95b02SDimitry Andric //   for virtual constant propagation hold and a single vtable's function
253ca95b02SDimitry Andric //   returns 0, or a single vtable's function returns 1, replace each virtual
263ca95b02SDimitry Andric //   call with a comparison of the vptr against that vtable's address.
273ca95b02SDimitry Andric //
287a7e6055SDimitry Andric // This pass is intended to be used during the regular and thin LTO pipelines.
297a7e6055SDimitry Andric // During regular LTO, the pass determines the best optimization for each
307a7e6055SDimitry Andric // virtual call and applies the resolutions directly to virtual calls that are
317a7e6055SDimitry Andric // eligible for virtual call optimization (i.e. calls that use either of the
327a7e6055SDimitry Andric // llvm.assume(llvm.type.test) or llvm.type.checked.load intrinsics). During
337a7e6055SDimitry Andric // ThinLTO, the pass operates in two phases:
347a7e6055SDimitry Andric // - Export phase: this is run during the thin link over a single merged module
357a7e6055SDimitry Andric //   that contains all vtables with !type metadata that participate in the link.
367a7e6055SDimitry Andric //   The pass computes a resolution for each virtual call and stores it in the
377a7e6055SDimitry Andric //   type identifier summary.
387a7e6055SDimitry Andric // - Import phase: this is run during the thin backends over the individual
397a7e6055SDimitry Andric //   modules. The pass applies the resolutions previously computed during the
407a7e6055SDimitry Andric //   import phase to each eligible virtual call.
417a7e6055SDimitry Andric //
423ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
433ca95b02SDimitry Andric 
443ca95b02SDimitry Andric #include "llvm/Transforms/IPO/WholeProgramDevirt.h"
453ca95b02SDimitry Andric #include "llvm/ADT/ArrayRef.h"
46d88c1a5aSDimitry Andric #include "llvm/ADT/DenseMap.h"
47d88c1a5aSDimitry Andric #include "llvm/ADT/DenseMapInfo.h"
483ca95b02SDimitry Andric #include "llvm/ADT/DenseSet.h"
493ca95b02SDimitry Andric #include "llvm/ADT/MapVector.h"
50d88c1a5aSDimitry Andric #include "llvm/ADT/SmallVector.h"
51db17bf38SDimitry Andric #include "llvm/ADT/iterator_range.h"
527a7e6055SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h"
537a7e6055SDimitry Andric #include "llvm/Analysis/BasicAliasAnalysis.h"
542cab237bSDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h"
553ca95b02SDimitry Andric #include "llvm/Analysis/TypeMetadataUtils.h"
563ca95b02SDimitry Andric #include "llvm/IR/CallSite.h"
573ca95b02SDimitry Andric #include "llvm/IR/Constants.h"
583ca95b02SDimitry Andric #include "llvm/IR/DataLayout.h"
59d88c1a5aSDimitry Andric #include "llvm/IR/DebugLoc.h"
60d88c1a5aSDimitry Andric #include "llvm/IR/DerivedTypes.h"
61*b5893f02SDimitry Andric #include "llvm/IR/Dominators.h"
62d88c1a5aSDimitry Andric #include "llvm/IR/Function.h"
63d88c1a5aSDimitry Andric #include "llvm/IR/GlobalAlias.h"
64d88c1a5aSDimitry Andric #include "llvm/IR/GlobalVariable.h"
653ca95b02SDimitry Andric #include "llvm/IR/IRBuilder.h"
66d88c1a5aSDimitry Andric #include "llvm/IR/InstrTypes.h"
67d88c1a5aSDimitry Andric #include "llvm/IR/Instruction.h"
683ca95b02SDimitry Andric #include "llvm/IR/Instructions.h"
693ca95b02SDimitry Andric #include "llvm/IR/Intrinsics.h"
70d88c1a5aSDimitry Andric #include "llvm/IR/LLVMContext.h"
71d88c1a5aSDimitry Andric #include "llvm/IR/Metadata.h"
723ca95b02SDimitry Andric #include "llvm/IR/Module.h"
737a7e6055SDimitry Andric #include "llvm/IR/ModuleSummaryIndexYAML.h"
743ca95b02SDimitry Andric #include "llvm/Pass.h"
75d88c1a5aSDimitry Andric #include "llvm/PassRegistry.h"
76d88c1a5aSDimitry Andric #include "llvm/PassSupport.h"
77d88c1a5aSDimitry Andric #include "llvm/Support/Casting.h"
787a7e6055SDimitry Andric #include "llvm/Support/Error.h"
797a7e6055SDimitry Andric #include "llvm/Support/FileSystem.h"
80d88c1a5aSDimitry Andric #include "llvm/Support/MathExtras.h"
813ca95b02SDimitry Andric #include "llvm/Transforms/IPO.h"
827a7e6055SDimitry Andric #include "llvm/Transforms/IPO/FunctionAttrs.h"
833ca95b02SDimitry Andric #include "llvm/Transforms/Utils/Evaluator.h"
84d88c1a5aSDimitry Andric #include <algorithm>
85d88c1a5aSDimitry Andric #include <cstddef>
86d88c1a5aSDimitry Andric #include <map>
873ca95b02SDimitry Andric #include <set>
88d88c1a5aSDimitry Andric #include <string>
893ca95b02SDimitry Andric 
903ca95b02SDimitry Andric using namespace llvm;
913ca95b02SDimitry Andric using namespace wholeprogramdevirt;
923ca95b02SDimitry Andric 
933ca95b02SDimitry Andric #define DEBUG_TYPE "wholeprogramdevirt"
943ca95b02SDimitry Andric 
957a7e6055SDimitry Andric static cl::opt<PassSummaryAction> ClSummaryAction(
967a7e6055SDimitry Andric     "wholeprogramdevirt-summary-action",
977a7e6055SDimitry Andric     cl::desc("What to do with the summary when running this pass"),
987a7e6055SDimitry Andric     cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"),
997a7e6055SDimitry Andric                clEnumValN(PassSummaryAction::Import, "import",
1007a7e6055SDimitry Andric                           "Import typeid resolutions from summary and globals"),
1017a7e6055SDimitry Andric                clEnumValN(PassSummaryAction::Export, "export",
1027a7e6055SDimitry Andric                           "Export typeid resolutions to summary and globals")),
1037a7e6055SDimitry Andric     cl::Hidden);
1047a7e6055SDimitry Andric 
1057a7e6055SDimitry Andric static cl::opt<std::string> ClReadSummary(
1067a7e6055SDimitry Andric     "wholeprogramdevirt-read-summary",
1077a7e6055SDimitry Andric     cl::desc("Read summary from given YAML file before running pass"),
1087a7e6055SDimitry Andric     cl::Hidden);
1097a7e6055SDimitry Andric 
1107a7e6055SDimitry Andric static cl::opt<std::string> ClWriteSummary(
1117a7e6055SDimitry Andric     "wholeprogramdevirt-write-summary",
1127a7e6055SDimitry Andric     cl::desc("Write summary to given YAML file after running pass"),
1137a7e6055SDimitry Andric     cl::Hidden);
1147a7e6055SDimitry Andric 
1154ba319b5SDimitry Andric static cl::opt<unsigned>
1164ba319b5SDimitry Andric     ClThreshold("wholeprogramdevirt-branch-funnel-threshold", cl::Hidden,
1174ba319b5SDimitry Andric                 cl::init(10), cl::ZeroOrMore,
1184ba319b5SDimitry Andric                 cl::desc("Maximum number of call targets per "
1194ba319b5SDimitry Andric                          "call site to enable branch funnels"));
1204ba319b5SDimitry Andric 
1213ca95b02SDimitry Andric // Find the minimum offset that we may store a value of size Size bits at. If
1223ca95b02SDimitry Andric // IsAfter is set, look for an offset before the object, otherwise look for an
1233ca95b02SDimitry Andric // offset after the object.
1243ca95b02SDimitry Andric uint64_t
findLowestOffset(ArrayRef<VirtualCallTarget> Targets,bool IsAfter,uint64_t Size)1253ca95b02SDimitry Andric wholeprogramdevirt::findLowestOffset(ArrayRef<VirtualCallTarget> Targets,
1263ca95b02SDimitry Andric                                      bool IsAfter, uint64_t Size) {
1273ca95b02SDimitry Andric   // Find a minimum offset taking into account only vtable sizes.
1283ca95b02SDimitry Andric   uint64_t MinByte = 0;
1293ca95b02SDimitry Andric   for (const VirtualCallTarget &Target : Targets) {
1303ca95b02SDimitry Andric     if (IsAfter)
1313ca95b02SDimitry Andric       MinByte = std::max(MinByte, Target.minAfterBytes());
1323ca95b02SDimitry Andric     else
1333ca95b02SDimitry Andric       MinByte = std::max(MinByte, Target.minBeforeBytes());
1343ca95b02SDimitry Andric   }
1353ca95b02SDimitry Andric 
1363ca95b02SDimitry Andric   // Build a vector of arrays of bytes covering, for each target, a slice of the
1373ca95b02SDimitry Andric   // used region (see AccumBitVector::BytesUsed in
1383ca95b02SDimitry Andric   // llvm/Transforms/IPO/WholeProgramDevirt.h) starting at MinByte. Effectively,
1393ca95b02SDimitry Andric   // this aligns the used regions to start at MinByte.
1403ca95b02SDimitry Andric   //
1413ca95b02SDimitry Andric   // In this example, A, B and C are vtables, # is a byte already allocated for
1423ca95b02SDimitry Andric   // a virtual function pointer, AAAA... (etc.) are the used regions for the
1433ca95b02SDimitry Andric   // vtables and Offset(X) is the value computed for the Offset variable below
1443ca95b02SDimitry Andric   // for X.
1453ca95b02SDimitry Andric   //
1463ca95b02SDimitry Andric   //                    Offset(A)
1473ca95b02SDimitry Andric   //                    |       |
1483ca95b02SDimitry Andric   //                            |MinByte
1493ca95b02SDimitry Andric   // A: ################AAAAAAAA|AAAAAAAA
1503ca95b02SDimitry Andric   // B: ########BBBBBBBBBBBBBBBB|BBBB
1513ca95b02SDimitry Andric   // C: ########################|CCCCCCCCCCCCCCCC
1523ca95b02SDimitry Andric   //            |   Offset(B)   |
1533ca95b02SDimitry Andric   //
1543ca95b02SDimitry Andric   // This code produces the slices of A, B and C that appear after the divider
1553ca95b02SDimitry Andric   // at MinByte.
1563ca95b02SDimitry Andric   std::vector<ArrayRef<uint8_t>> Used;
1573ca95b02SDimitry Andric   for (const VirtualCallTarget &Target : Targets) {
1583ca95b02SDimitry Andric     ArrayRef<uint8_t> VTUsed = IsAfter ? Target.TM->Bits->After.BytesUsed
1593ca95b02SDimitry Andric                                        : Target.TM->Bits->Before.BytesUsed;
1603ca95b02SDimitry Andric     uint64_t Offset = IsAfter ? MinByte - Target.minAfterBytes()
1613ca95b02SDimitry Andric                               : MinByte - Target.minBeforeBytes();
1623ca95b02SDimitry Andric 
1633ca95b02SDimitry Andric     // Disregard used regions that are smaller than Offset. These are
1643ca95b02SDimitry Andric     // effectively all-free regions that do not need to be checked.
1653ca95b02SDimitry Andric     if (VTUsed.size() > Offset)
1663ca95b02SDimitry Andric       Used.push_back(VTUsed.slice(Offset));
1673ca95b02SDimitry Andric   }
1683ca95b02SDimitry Andric 
1693ca95b02SDimitry Andric   if (Size == 1) {
1703ca95b02SDimitry Andric     // Find a free bit in each member of Used.
1713ca95b02SDimitry Andric     for (unsigned I = 0;; ++I) {
1723ca95b02SDimitry Andric       uint8_t BitsUsed = 0;
1733ca95b02SDimitry Andric       for (auto &&B : Used)
1743ca95b02SDimitry Andric         if (I < B.size())
1753ca95b02SDimitry Andric           BitsUsed |= B[I];
1763ca95b02SDimitry Andric       if (BitsUsed != 0xff)
1773ca95b02SDimitry Andric         return (MinByte + I) * 8 +
1783ca95b02SDimitry Andric                countTrailingZeros(uint8_t(~BitsUsed), ZB_Undefined);
1793ca95b02SDimitry Andric     }
1803ca95b02SDimitry Andric   } else {
1813ca95b02SDimitry Andric     // Find a free (Size/8) byte region in each member of Used.
1823ca95b02SDimitry Andric     // FIXME: see if alignment helps.
1833ca95b02SDimitry Andric     for (unsigned I = 0;; ++I) {
1843ca95b02SDimitry Andric       for (auto &&B : Used) {
1853ca95b02SDimitry Andric         unsigned Byte = 0;
1863ca95b02SDimitry Andric         while ((I + Byte) < B.size() && Byte < (Size / 8)) {
1873ca95b02SDimitry Andric           if (B[I + Byte])
1883ca95b02SDimitry Andric             goto NextI;
1893ca95b02SDimitry Andric           ++Byte;
1903ca95b02SDimitry Andric         }
1913ca95b02SDimitry Andric       }
1923ca95b02SDimitry Andric       return (MinByte + I) * 8;
1933ca95b02SDimitry Andric     NextI:;
1943ca95b02SDimitry Andric     }
1953ca95b02SDimitry Andric   }
1963ca95b02SDimitry Andric }
1973ca95b02SDimitry Andric 
setBeforeReturnValues(MutableArrayRef<VirtualCallTarget> Targets,uint64_t AllocBefore,unsigned BitWidth,int64_t & OffsetByte,uint64_t & OffsetBit)1983ca95b02SDimitry Andric void wholeprogramdevirt::setBeforeReturnValues(
1993ca95b02SDimitry Andric     MutableArrayRef<VirtualCallTarget> Targets, uint64_t AllocBefore,
2003ca95b02SDimitry Andric     unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {
2013ca95b02SDimitry Andric   if (BitWidth == 1)
2023ca95b02SDimitry Andric     OffsetByte = -(AllocBefore / 8 + 1);
2033ca95b02SDimitry Andric   else
2043ca95b02SDimitry Andric     OffsetByte = -((AllocBefore + 7) / 8 + (BitWidth + 7) / 8);
2053ca95b02SDimitry Andric   OffsetBit = AllocBefore % 8;
2063ca95b02SDimitry Andric 
2073ca95b02SDimitry Andric   for (VirtualCallTarget &Target : Targets) {
2083ca95b02SDimitry Andric     if (BitWidth == 1)
2093ca95b02SDimitry Andric       Target.setBeforeBit(AllocBefore);
2103ca95b02SDimitry Andric     else
2113ca95b02SDimitry Andric       Target.setBeforeBytes(AllocBefore, (BitWidth + 7) / 8);
2123ca95b02SDimitry Andric   }
2133ca95b02SDimitry Andric }
2143ca95b02SDimitry Andric 
setAfterReturnValues(MutableArrayRef<VirtualCallTarget> Targets,uint64_t AllocAfter,unsigned BitWidth,int64_t & OffsetByte,uint64_t & OffsetBit)2153ca95b02SDimitry Andric void wholeprogramdevirt::setAfterReturnValues(
2163ca95b02SDimitry Andric     MutableArrayRef<VirtualCallTarget> Targets, uint64_t AllocAfter,
2173ca95b02SDimitry Andric     unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {
2183ca95b02SDimitry Andric   if (BitWidth == 1)
2193ca95b02SDimitry Andric     OffsetByte = AllocAfter / 8;
2203ca95b02SDimitry Andric   else
2213ca95b02SDimitry Andric     OffsetByte = (AllocAfter + 7) / 8;
2223ca95b02SDimitry Andric   OffsetBit = AllocAfter % 8;
2233ca95b02SDimitry Andric 
2243ca95b02SDimitry Andric   for (VirtualCallTarget &Target : Targets) {
2253ca95b02SDimitry Andric     if (BitWidth == 1)
2263ca95b02SDimitry Andric       Target.setAfterBit(AllocAfter);
2273ca95b02SDimitry Andric     else
2283ca95b02SDimitry Andric       Target.setAfterBytes(AllocAfter, (BitWidth + 7) / 8);
2293ca95b02SDimitry Andric   }
2303ca95b02SDimitry Andric }
2313ca95b02SDimitry Andric 
VirtualCallTarget(Function * Fn,const TypeMemberInfo * TM)2323ca95b02SDimitry Andric VirtualCallTarget::VirtualCallTarget(Function *Fn, const TypeMemberInfo *TM)
2333ca95b02SDimitry Andric     : Fn(Fn), TM(TM),
234d88c1a5aSDimitry Andric       IsBigEndian(Fn->getParent()->getDataLayout().isBigEndian()), WasDevirt(false) {}
2353ca95b02SDimitry Andric 
2363ca95b02SDimitry Andric namespace {
2373ca95b02SDimitry Andric 
2383ca95b02SDimitry Andric // A slot in a set of virtual tables. The TypeID identifies the set of virtual
2393ca95b02SDimitry Andric // tables, and the ByteOffset is the offset in bytes from the address point to
2403ca95b02SDimitry Andric // the virtual function pointer.
2413ca95b02SDimitry Andric struct VTableSlot {
2423ca95b02SDimitry Andric   Metadata *TypeID;
2433ca95b02SDimitry Andric   uint64_t ByteOffset;
2443ca95b02SDimitry Andric };
2453ca95b02SDimitry Andric 
246d88c1a5aSDimitry Andric } // end anonymous namespace
2473ca95b02SDimitry Andric 
2483ca95b02SDimitry Andric namespace llvm {
2493ca95b02SDimitry Andric 
2503ca95b02SDimitry Andric template <> struct DenseMapInfo<VTableSlot> {
getEmptyKeyllvm::DenseMapInfo2513ca95b02SDimitry Andric   static VTableSlot getEmptyKey() {
2523ca95b02SDimitry Andric     return {DenseMapInfo<Metadata *>::getEmptyKey(),
2533ca95b02SDimitry Andric             DenseMapInfo<uint64_t>::getEmptyKey()};
2543ca95b02SDimitry Andric   }
getTombstoneKeyllvm::DenseMapInfo2553ca95b02SDimitry Andric   static VTableSlot getTombstoneKey() {
2563ca95b02SDimitry Andric     return {DenseMapInfo<Metadata *>::getTombstoneKey(),
2573ca95b02SDimitry Andric             DenseMapInfo<uint64_t>::getTombstoneKey()};
2583ca95b02SDimitry Andric   }
getHashValuellvm::DenseMapInfo2593ca95b02SDimitry Andric   static unsigned getHashValue(const VTableSlot &I) {
2603ca95b02SDimitry Andric     return DenseMapInfo<Metadata *>::getHashValue(I.TypeID) ^
2613ca95b02SDimitry Andric            DenseMapInfo<uint64_t>::getHashValue(I.ByteOffset);
2623ca95b02SDimitry Andric   }
isEqualllvm::DenseMapInfo2633ca95b02SDimitry Andric   static bool isEqual(const VTableSlot &LHS,
2643ca95b02SDimitry Andric                       const VTableSlot &RHS) {
2653ca95b02SDimitry Andric     return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
2663ca95b02SDimitry Andric   }
2673ca95b02SDimitry Andric };
2683ca95b02SDimitry Andric 
269d88c1a5aSDimitry Andric } // end namespace llvm
2703ca95b02SDimitry Andric 
2713ca95b02SDimitry Andric namespace {
2723ca95b02SDimitry Andric 
2733ca95b02SDimitry Andric // A virtual call site. VTable is the loaded virtual table pointer, and CS is
2743ca95b02SDimitry Andric // the indirect virtual call.
2753ca95b02SDimitry Andric struct VirtualCallSite {
2763ca95b02SDimitry Andric   Value *VTable;
2773ca95b02SDimitry Andric   CallSite CS;
2783ca95b02SDimitry Andric 
2793ca95b02SDimitry Andric   // If non-null, this field points to the associated unsafe use count stored in
2803ca95b02SDimitry Andric   // the DevirtModule::NumUnsafeUsesForTypeTest map below. See the description
2813ca95b02SDimitry Andric   // of that field for details.
2823ca95b02SDimitry Andric   unsigned *NumUnsafeUses;
2833ca95b02SDimitry Andric 
2842cab237bSDimitry Andric   void
emitRemark__anon3453c20f0211::VirtualCallSite2852cab237bSDimitry Andric   emitRemark(const StringRef OptName, const StringRef TargetName,
2862cab237bSDimitry Andric              function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter) {
2873ca95b02SDimitry Andric     Function *F = CS.getCaller();
2882cab237bSDimitry Andric     DebugLoc DLoc = CS->getDebugLoc();
2892cab237bSDimitry Andric     BasicBlock *Block = CS.getParent();
2902cab237bSDimitry Andric 
2912cab237bSDimitry Andric     using namespace ore;
2924ba319b5SDimitry Andric     OREGetter(F).emit(OptimizationRemark(DEBUG_TYPE, OptName, DLoc, Block)
2934ba319b5SDimitry Andric                       << NV("Optimization", OptName)
2944ba319b5SDimitry Andric                       << ": devirtualized a call to "
2952cab237bSDimitry Andric                       << NV("FunctionName", TargetName));
2962cab237bSDimitry Andric   }
2972cab237bSDimitry Andric 
replaceAndErase__anon3453c20f0211::VirtualCallSite2982cab237bSDimitry Andric   void replaceAndErase(
2992cab237bSDimitry Andric       const StringRef OptName, const StringRef TargetName, bool RemarksEnabled,
3002cab237bSDimitry Andric       function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter,
3012cab237bSDimitry Andric       Value *New) {
302d88c1a5aSDimitry Andric     if (RemarksEnabled)
3032cab237bSDimitry Andric       emitRemark(OptName, TargetName, OREGetter);
3043ca95b02SDimitry Andric     CS->replaceAllUsesWith(New);
3053ca95b02SDimitry Andric     if (auto II = dyn_cast<InvokeInst>(CS.getInstruction())) {
3063ca95b02SDimitry Andric       BranchInst::Create(II->getNormalDest(), CS.getInstruction());
3073ca95b02SDimitry Andric       II->getUnwindDest()->removePredecessor(II->getParent());
3083ca95b02SDimitry Andric     }
3093ca95b02SDimitry Andric     CS->eraseFromParent();
3103ca95b02SDimitry Andric     // This use is no longer unsafe.
3113ca95b02SDimitry Andric     if (NumUnsafeUses)
3123ca95b02SDimitry Andric       --*NumUnsafeUses;
3133ca95b02SDimitry Andric   }
3143ca95b02SDimitry Andric };
3153ca95b02SDimitry Andric 
3167a7e6055SDimitry Andric // Call site information collected for a specific VTableSlot and possibly a list
3177a7e6055SDimitry Andric // of constant integer arguments. The grouping by arguments is handled by the
3187a7e6055SDimitry Andric // VTableSlotInfo class.
3197a7e6055SDimitry Andric struct CallSiteInfo {
3207a7e6055SDimitry Andric   /// The set of call sites for this slot. Used during regular LTO and the
3217a7e6055SDimitry Andric   /// import phase of ThinLTO (as well as the export phase of ThinLTO for any
3227a7e6055SDimitry Andric   /// call sites that appear in the merged module itself); in each of these
3237a7e6055SDimitry Andric   /// cases we are directly operating on the call sites at the IR level.
3247a7e6055SDimitry Andric   std::vector<VirtualCallSite> CallSites;
3257a7e6055SDimitry Andric 
3264ba319b5SDimitry Andric   /// Whether all call sites represented by this CallSiteInfo, including those
3274ba319b5SDimitry Andric   /// in summaries, have been devirtualized. This starts off as true because a
3284ba319b5SDimitry Andric   /// default constructed CallSiteInfo represents no call sites.
3294ba319b5SDimitry Andric   bool AllCallSitesDevirted = true;
3304ba319b5SDimitry Andric 
3317a7e6055SDimitry Andric   // These fields are used during the export phase of ThinLTO and reflect
3327a7e6055SDimitry Andric   // information collected from function summaries.
3337a7e6055SDimitry Andric 
3347a7e6055SDimitry Andric   /// Whether any function summary contains an llvm.assume(llvm.type.test) for
3357a7e6055SDimitry Andric   /// this slot.
3364ba319b5SDimitry Andric   bool SummaryHasTypeTestAssumeUsers = false;
3377a7e6055SDimitry Andric 
3387a7e6055SDimitry Andric   /// CFI-specific: a vector containing the list of function summaries that use
3397a7e6055SDimitry Andric   /// the llvm.type.checked.load intrinsic and therefore will require
3407a7e6055SDimitry Andric   /// resolutions for llvm.type.test in order to implement CFI checks if
3417a7e6055SDimitry Andric   /// devirtualization was unsuccessful. If devirtualization was successful, the
3427a7e6055SDimitry Andric   /// pass will clear this vector by calling markDevirt(). If at the end of the
3437a7e6055SDimitry Andric   /// pass the vector is non-empty, we will need to add a use of llvm.type.test
3447a7e6055SDimitry Andric   /// to each of the function summaries in the vector.
3457a7e6055SDimitry Andric   std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;
3467a7e6055SDimitry Andric 
isExported__anon3453c20f0211::CallSiteInfo3477a7e6055SDimitry Andric   bool isExported() const {
3487a7e6055SDimitry Andric     return SummaryHasTypeTestAssumeUsers ||
3497a7e6055SDimitry Andric            !SummaryTypeCheckedLoadUsers.empty();
3507a7e6055SDimitry Andric   }
3517a7e6055SDimitry Andric 
markSummaryHasTypeTestAssumeUsers__anon3453c20f0211::CallSiteInfo3524ba319b5SDimitry Andric   void markSummaryHasTypeTestAssumeUsers() {
3534ba319b5SDimitry Andric     SummaryHasTypeTestAssumeUsers = true;
3544ba319b5SDimitry Andric     AllCallSitesDevirted = false;
3554ba319b5SDimitry Andric   }
3564ba319b5SDimitry Andric 
addSummaryTypeCheckedLoadUser__anon3453c20f0211::CallSiteInfo3574ba319b5SDimitry Andric   void addSummaryTypeCheckedLoadUser(FunctionSummary *FS) {
3584ba319b5SDimitry Andric     SummaryTypeCheckedLoadUsers.push_back(FS);
3594ba319b5SDimitry Andric     AllCallSitesDevirted = false;
3604ba319b5SDimitry Andric   }
3614ba319b5SDimitry Andric 
markDevirt__anon3453c20f0211::CallSiteInfo3624ba319b5SDimitry Andric   void markDevirt() {
3634ba319b5SDimitry Andric     AllCallSitesDevirted = true;
3644ba319b5SDimitry Andric 
3654ba319b5SDimitry Andric     // As explained in the comment for SummaryTypeCheckedLoadUsers.
3664ba319b5SDimitry Andric     SummaryTypeCheckedLoadUsers.clear();
3674ba319b5SDimitry Andric   }
3687a7e6055SDimitry Andric };
3697a7e6055SDimitry Andric 
3707a7e6055SDimitry Andric // Call site information collected for a specific VTableSlot.
3717a7e6055SDimitry Andric struct VTableSlotInfo {
3727a7e6055SDimitry Andric   // The set of call sites which do not have all constant integer arguments
3737a7e6055SDimitry Andric   // (excluding "this").
3747a7e6055SDimitry Andric   CallSiteInfo CSInfo;
3757a7e6055SDimitry Andric 
3767a7e6055SDimitry Andric   // The set of call sites with all constant integer arguments (excluding
3777a7e6055SDimitry Andric   // "this"), grouped by argument list.
3787a7e6055SDimitry Andric   std::map<std::vector<uint64_t>, CallSiteInfo> ConstCSInfo;
3797a7e6055SDimitry Andric 
3807a7e6055SDimitry Andric   void addCallSite(Value *VTable, CallSite CS, unsigned *NumUnsafeUses);
3817a7e6055SDimitry Andric 
3827a7e6055SDimitry Andric private:
3837a7e6055SDimitry Andric   CallSiteInfo &findCallSiteInfo(CallSite CS);
3847a7e6055SDimitry Andric };
3857a7e6055SDimitry Andric 
findCallSiteInfo(CallSite CS)3867a7e6055SDimitry Andric CallSiteInfo &VTableSlotInfo::findCallSiteInfo(CallSite CS) {
3877a7e6055SDimitry Andric   std::vector<uint64_t> Args;
3887a7e6055SDimitry Andric   auto *CI = dyn_cast<IntegerType>(CS.getType());
3897a7e6055SDimitry Andric   if (!CI || CI->getBitWidth() > 64 || CS.arg_empty())
3907a7e6055SDimitry Andric     return CSInfo;
3917a7e6055SDimitry Andric   for (auto &&Arg : make_range(CS.arg_begin() + 1, CS.arg_end())) {
3927a7e6055SDimitry Andric     auto *CI = dyn_cast<ConstantInt>(Arg);
3937a7e6055SDimitry Andric     if (!CI || CI->getBitWidth() > 64)
3947a7e6055SDimitry Andric       return CSInfo;
3957a7e6055SDimitry Andric     Args.push_back(CI->getZExtValue());
3967a7e6055SDimitry Andric   }
3977a7e6055SDimitry Andric   return ConstCSInfo[Args];
3987a7e6055SDimitry Andric }
3997a7e6055SDimitry Andric 
addCallSite(Value * VTable,CallSite CS,unsigned * NumUnsafeUses)4007a7e6055SDimitry Andric void VTableSlotInfo::addCallSite(Value *VTable, CallSite CS,
4017a7e6055SDimitry Andric                                  unsigned *NumUnsafeUses) {
4024ba319b5SDimitry Andric   auto &CSI = findCallSiteInfo(CS);
4034ba319b5SDimitry Andric   CSI.AllCallSitesDevirted = false;
4044ba319b5SDimitry Andric   CSI.CallSites.push_back({VTable, CS, NumUnsafeUses});
4057a7e6055SDimitry Andric }
4067a7e6055SDimitry Andric 
4073ca95b02SDimitry Andric struct DevirtModule {
4083ca95b02SDimitry Andric   Module &M;
4097a7e6055SDimitry Andric   function_ref<AAResults &(Function &)> AARGetter;
410*b5893f02SDimitry Andric   function_ref<DominatorTree &(Function &)> LookupDomTree;
4117a7e6055SDimitry Andric 
4127a7e6055SDimitry Andric   ModuleSummaryIndex *ExportSummary;
4137a7e6055SDimitry Andric   const ModuleSummaryIndex *ImportSummary;
4147a7e6055SDimitry Andric 
4153ca95b02SDimitry Andric   IntegerType *Int8Ty;
4163ca95b02SDimitry Andric   PointerType *Int8PtrTy;
4173ca95b02SDimitry Andric   IntegerType *Int32Ty;
4187a7e6055SDimitry Andric   IntegerType *Int64Ty;
4197a7e6055SDimitry Andric   IntegerType *IntPtrTy;
4203ca95b02SDimitry Andric 
421d88c1a5aSDimitry Andric   bool RemarksEnabled;
4222cab237bSDimitry Andric   function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter;
423d88c1a5aSDimitry Andric 
4247a7e6055SDimitry Andric   MapVector<VTableSlot, VTableSlotInfo> CallSlots;
4253ca95b02SDimitry Andric 
4263ca95b02SDimitry Andric   // This map keeps track of the number of "unsafe" uses of a loaded function
4273ca95b02SDimitry Andric   // pointer. The key is the associated llvm.type.test intrinsic call generated
4283ca95b02SDimitry Andric   // by this pass. An unsafe use is one that calls the loaded function pointer
4293ca95b02SDimitry Andric   // directly. Every time we eliminate an unsafe use (for example, by
4303ca95b02SDimitry Andric   // devirtualizing it or by applying virtual constant propagation), we
4313ca95b02SDimitry Andric   // decrement the value stored in this map. If a value reaches zero, we can
4323ca95b02SDimitry Andric   // eliminate the type check by RAUWing the associated llvm.type.test call with
4333ca95b02SDimitry Andric   // true.
4343ca95b02SDimitry Andric   std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
4353ca95b02SDimitry Andric 
DevirtModule__anon3453c20f0211::DevirtModule4367a7e6055SDimitry Andric   DevirtModule(Module &M, function_ref<AAResults &(Function &)> AARGetter,
4372cab237bSDimitry Andric                function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter,
438*b5893f02SDimitry Andric                function_ref<DominatorTree &(Function &)> LookupDomTree,
4397a7e6055SDimitry Andric                ModuleSummaryIndex *ExportSummary,
4407a7e6055SDimitry Andric                const ModuleSummaryIndex *ImportSummary)
441*b5893f02SDimitry Andric       : M(M), AARGetter(AARGetter), LookupDomTree(LookupDomTree),
442*b5893f02SDimitry Andric         ExportSummary(ExportSummary), ImportSummary(ImportSummary),
443*b5893f02SDimitry Andric         Int8Ty(Type::getInt8Ty(M.getContext())),
4443ca95b02SDimitry Andric         Int8PtrTy(Type::getInt8PtrTy(M.getContext())),
445d88c1a5aSDimitry Andric         Int32Ty(Type::getInt32Ty(M.getContext())),
4467a7e6055SDimitry Andric         Int64Ty(Type::getInt64Ty(M.getContext())),
4477a7e6055SDimitry Andric         IntPtrTy(M.getDataLayout().getIntPtrType(M.getContext(), 0)),
4482cab237bSDimitry Andric         RemarksEnabled(areRemarksEnabled()), OREGetter(OREGetter) {
4497a7e6055SDimitry Andric     assert(!(ExportSummary && ImportSummary));
4507a7e6055SDimitry Andric   }
451d88c1a5aSDimitry Andric 
452d88c1a5aSDimitry Andric   bool areRemarksEnabled();
4533ca95b02SDimitry Andric 
4543ca95b02SDimitry Andric   void scanTypeTestUsers(Function *TypeTestFunc, Function *AssumeFunc);
4553ca95b02SDimitry Andric   void scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc);
4563ca95b02SDimitry Andric 
4573ca95b02SDimitry Andric   void buildTypeIdentifierMap(
4583ca95b02SDimitry Andric       std::vector<VTableBits> &Bits,
4593ca95b02SDimitry Andric       DenseMap<Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
460d88c1a5aSDimitry Andric   Constant *getPointerAtOffset(Constant *I, uint64_t Offset);
4613ca95b02SDimitry Andric   bool
4623ca95b02SDimitry Andric   tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
4633ca95b02SDimitry Andric                             const std::set<TypeMemberInfo> &TypeMemberInfos,
4643ca95b02SDimitry Andric                             uint64_t ByteOffset);
4657a7e6055SDimitry Andric 
4667a7e6055SDimitry Andric   void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn,
4677a7e6055SDimitry Andric                              bool &IsExported);
468d88c1a5aSDimitry Andric   bool trySingleImplDevirt(MutableArrayRef<VirtualCallTarget> TargetsForSlot,
4697a7e6055SDimitry Andric                            VTableSlotInfo &SlotInfo,
4707a7e6055SDimitry Andric                            WholeProgramDevirtResolution *Res);
4717a7e6055SDimitry Andric 
4724ba319b5SDimitry Andric   void applyICallBranchFunnel(VTableSlotInfo &SlotInfo, Constant *JT,
4734ba319b5SDimitry Andric                               bool &IsExported);
4744ba319b5SDimitry Andric   void tryICallBranchFunnel(MutableArrayRef<VirtualCallTarget> TargetsForSlot,
4754ba319b5SDimitry Andric                             VTableSlotInfo &SlotInfo,
4764ba319b5SDimitry Andric                             WholeProgramDevirtResolution *Res, VTableSlot Slot);
4774ba319b5SDimitry Andric 
4783ca95b02SDimitry Andric   bool tryEvaluateFunctionsWithArgs(
4793ca95b02SDimitry Andric       MutableArrayRef<VirtualCallTarget> TargetsForSlot,
4807a7e6055SDimitry Andric       ArrayRef<uint64_t> Args);
4817a7e6055SDimitry Andric 
4827a7e6055SDimitry Andric   void applyUniformRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,
4837a7e6055SDimitry Andric                              uint64_t TheRetVal);
4847a7e6055SDimitry Andric   bool tryUniformRetValOpt(MutableArrayRef<VirtualCallTarget> TargetsForSlot,
4857a7e6055SDimitry Andric                            CallSiteInfo &CSInfo,
4867a7e6055SDimitry Andric                            WholeProgramDevirtResolution::ByArg *Res);
4877a7e6055SDimitry Andric 
4887a7e6055SDimitry Andric   // Returns the global symbol name that is used to export information about the
4897a7e6055SDimitry Andric   // given vtable slot and list of arguments.
4907a7e6055SDimitry Andric   std::string getGlobalName(VTableSlot Slot, ArrayRef<uint64_t> Args,
4917a7e6055SDimitry Andric                             StringRef Name);
4927a7e6055SDimitry Andric 
4932cab237bSDimitry Andric   bool shouldExportConstantsAsAbsoluteSymbols();
4942cab237bSDimitry Andric 
4957a7e6055SDimitry Andric   // This function is called during the export phase to create a symbol
4967a7e6055SDimitry Andric   // definition containing information about the given vtable slot and list of
4977a7e6055SDimitry Andric   // arguments.
4987a7e6055SDimitry Andric   void exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
4997a7e6055SDimitry Andric                     Constant *C);
5002cab237bSDimitry Andric   void exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
5012cab237bSDimitry Andric                       uint32_t Const, uint32_t &Storage);
5027a7e6055SDimitry Andric 
5037a7e6055SDimitry Andric   // This function is called during the import phase to create a reference to
5047a7e6055SDimitry Andric   // the symbol definition created during the export phase.
5057a7e6055SDimitry Andric   Constant *importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
5062cab237bSDimitry Andric                          StringRef Name);
5072cab237bSDimitry Andric   Constant *importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
5082cab237bSDimitry Andric                            StringRef Name, IntegerType *IntTy,
5092cab237bSDimitry Andric                            uint32_t Storage);
5107a7e6055SDimitry Andric 
5114ba319b5SDimitry Andric   Constant *getMemberAddr(const TypeMemberInfo *M);
5124ba319b5SDimitry Andric 
5137a7e6055SDimitry Andric   void applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName, bool IsOne,
5147a7e6055SDimitry Andric                             Constant *UniqueMemberAddr);
5153ca95b02SDimitry Andric   bool tryUniqueRetValOpt(unsigned BitWidth,
516d88c1a5aSDimitry Andric                           MutableArrayRef<VirtualCallTarget> TargetsForSlot,
5177a7e6055SDimitry Andric                           CallSiteInfo &CSInfo,
5187a7e6055SDimitry Andric                           WholeProgramDevirtResolution::ByArg *Res,
5197a7e6055SDimitry Andric                           VTableSlot Slot, ArrayRef<uint64_t> Args);
5207a7e6055SDimitry Andric 
5217a7e6055SDimitry Andric   void applyVirtualConstProp(CallSiteInfo &CSInfo, StringRef FnName,
5227a7e6055SDimitry Andric                              Constant *Byte, Constant *Bit);
5233ca95b02SDimitry Andric   bool tryVirtualConstProp(MutableArrayRef<VirtualCallTarget> TargetsForSlot,
5247a7e6055SDimitry Andric                            VTableSlotInfo &SlotInfo,
5257a7e6055SDimitry Andric                            WholeProgramDevirtResolution *Res, VTableSlot Slot);
5263ca95b02SDimitry Andric 
5273ca95b02SDimitry Andric   void rebuildGlobal(VTableBits &B);
5283ca95b02SDimitry Andric 
5297a7e6055SDimitry Andric   // Apply the summary resolution for Slot to all virtual calls in SlotInfo.
5307a7e6055SDimitry Andric   void importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo);
5317a7e6055SDimitry Andric 
5327a7e6055SDimitry Andric   // If we were able to eliminate all unsafe uses for a type checked load,
5337a7e6055SDimitry Andric   // eliminate the associated type tests by replacing them with true.
5347a7e6055SDimitry Andric   void removeRedundantTypeTests();
5357a7e6055SDimitry Andric 
5363ca95b02SDimitry Andric   bool run();
5377a7e6055SDimitry Andric 
5387a7e6055SDimitry Andric   // Lower the module using the action and summary passed as command line
5397a7e6055SDimitry Andric   // arguments. For testing purposes only.
540*b5893f02SDimitry Andric   static bool
541*b5893f02SDimitry Andric   runForTesting(Module &M, function_ref<AAResults &(Function &)> AARGetter,
542*b5893f02SDimitry Andric                 function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter,
543*b5893f02SDimitry Andric                 function_ref<DominatorTree &(Function &)> LookupDomTree);
5443ca95b02SDimitry Andric };
5453ca95b02SDimitry Andric 
5463ca95b02SDimitry Andric struct WholeProgramDevirt : public ModulePass {
5473ca95b02SDimitry Andric   static char ID;
548d88c1a5aSDimitry Andric 
5497a7e6055SDimitry Andric   bool UseCommandLine = false;
5507a7e6055SDimitry Andric 
5517a7e6055SDimitry Andric   ModuleSummaryIndex *ExportSummary;
5527a7e6055SDimitry Andric   const ModuleSummaryIndex *ImportSummary;
5537a7e6055SDimitry Andric 
WholeProgramDevirt__anon3453c20f0211::WholeProgramDevirt5547a7e6055SDimitry Andric   WholeProgramDevirt() : ModulePass(ID), UseCommandLine(true) {
5557a7e6055SDimitry Andric     initializeWholeProgramDevirtPass(*PassRegistry::getPassRegistry());
5567a7e6055SDimitry Andric   }
5577a7e6055SDimitry Andric 
WholeProgramDevirt__anon3453c20f0211::WholeProgramDevirt5587a7e6055SDimitry Andric   WholeProgramDevirt(ModuleSummaryIndex *ExportSummary,
5597a7e6055SDimitry Andric                      const ModuleSummaryIndex *ImportSummary)
5607a7e6055SDimitry Andric       : ModulePass(ID), ExportSummary(ExportSummary),
5617a7e6055SDimitry Andric         ImportSummary(ImportSummary) {
5623ca95b02SDimitry Andric     initializeWholeProgramDevirtPass(*PassRegistry::getPassRegistry());
5633ca95b02SDimitry Andric   }
564d88c1a5aSDimitry Andric 
runOnModule__anon3453c20f0211::WholeProgramDevirt565d88c1a5aSDimitry Andric   bool runOnModule(Module &M) override {
5663ca95b02SDimitry Andric     if (skipModule(M))
5673ca95b02SDimitry Andric       return false;
5682cab237bSDimitry Andric 
5694ba319b5SDimitry Andric     // In the new pass manager, we can request the optimization
5704ba319b5SDimitry Andric     // remark emitter pass on a per-function-basis, which the
5714ba319b5SDimitry Andric     // OREGetter will do for us.
5724ba319b5SDimitry Andric     // In the old pass manager, this is harder, so we just build
5734ba319b5SDimitry Andric     // an optimization remark emitter on the fly, when we need it.
5744ba319b5SDimitry Andric     std::unique_ptr<OptimizationRemarkEmitter> ORE;
5754ba319b5SDimitry Andric     auto OREGetter = [&](Function *F) -> OptimizationRemarkEmitter & {
5764ba319b5SDimitry Andric       ORE = make_unique<OptimizationRemarkEmitter>(F);
5774ba319b5SDimitry Andric       return *ORE;
5784ba319b5SDimitry Andric     };
5792cab237bSDimitry Andric 
580*b5893f02SDimitry Andric     auto LookupDomTree = [this](Function &F) -> DominatorTree & {
581*b5893f02SDimitry Andric       return this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
582*b5893f02SDimitry Andric     };
5832cab237bSDimitry Andric 
584*b5893f02SDimitry Andric     if (UseCommandLine)
585*b5893f02SDimitry Andric       return DevirtModule::runForTesting(M, LegacyAARGetter(*this), OREGetter,
586*b5893f02SDimitry Andric                                          LookupDomTree);
587*b5893f02SDimitry Andric 
588*b5893f02SDimitry Andric     return DevirtModule(M, LegacyAARGetter(*this), OREGetter, LookupDomTree,
589*b5893f02SDimitry Andric                         ExportSummary, ImportSummary)
5907a7e6055SDimitry Andric         .run();
5917a7e6055SDimitry Andric   }
5923ca95b02SDimitry Andric 
getAnalysisUsage__anon3453c20f0211::WholeProgramDevirt5937a7e6055SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
5947a7e6055SDimitry Andric     AU.addRequired<AssumptionCacheTracker>();
5957a7e6055SDimitry Andric     AU.addRequired<TargetLibraryInfoWrapperPass>();
596*b5893f02SDimitry Andric     AU.addRequired<DominatorTreeWrapperPass>();
5973ca95b02SDimitry Andric   }
5983ca95b02SDimitry Andric };
5993ca95b02SDimitry Andric 
600d88c1a5aSDimitry Andric } // end anonymous namespace
6013ca95b02SDimitry Andric 
6027a7e6055SDimitry Andric INITIALIZE_PASS_BEGIN(WholeProgramDevirt, "wholeprogramdevirt",
6037a7e6055SDimitry Andric                       "Whole program devirtualization", false, false)
6047a7e6055SDimitry Andric INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
6057a7e6055SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
606*b5893f02SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
6077a7e6055SDimitry Andric INITIALIZE_PASS_END(WholeProgramDevirt, "wholeprogramdevirt",
6083ca95b02SDimitry Andric                     "Whole program devirtualization", false, false)
6093ca95b02SDimitry Andric char WholeProgramDevirt::ID = 0;
6103ca95b02SDimitry Andric 
6117a7e6055SDimitry Andric ModulePass *
createWholeProgramDevirtPass(ModuleSummaryIndex * ExportSummary,const ModuleSummaryIndex * ImportSummary)6127a7e6055SDimitry Andric llvm::createWholeProgramDevirtPass(ModuleSummaryIndex *ExportSummary,
6137a7e6055SDimitry Andric                                    const ModuleSummaryIndex *ImportSummary) {
6147a7e6055SDimitry Andric   return new WholeProgramDevirt(ExportSummary, ImportSummary);
6153ca95b02SDimitry Andric }
6163ca95b02SDimitry Andric 
run(Module & M,ModuleAnalysisManager & AM)6173ca95b02SDimitry Andric PreservedAnalyses WholeProgramDevirtPass::run(Module &M,
6187a7e6055SDimitry Andric                                               ModuleAnalysisManager &AM) {
6197a7e6055SDimitry Andric   auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
6207a7e6055SDimitry Andric   auto AARGetter = [&](Function &F) -> AAResults & {
6217a7e6055SDimitry Andric     return FAM.getResult<AAManager>(F);
6227a7e6055SDimitry Andric   };
6232cab237bSDimitry Andric   auto OREGetter = [&](Function *F) -> OptimizationRemarkEmitter & {
6242cab237bSDimitry Andric     return FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F);
6252cab237bSDimitry Andric   };
626*b5893f02SDimitry Andric   auto LookupDomTree = [&FAM](Function &F) -> DominatorTree & {
627*b5893f02SDimitry Andric     return FAM.getResult<DominatorTreeAnalysis>(F);
628*b5893f02SDimitry Andric   };
629*b5893f02SDimitry Andric   if (!DevirtModule(M, AARGetter, OREGetter, LookupDomTree, ExportSummary,
630*b5893f02SDimitry Andric                     ImportSummary)
6314ba319b5SDimitry Andric            .run())
6323ca95b02SDimitry Andric     return PreservedAnalyses::all();
6333ca95b02SDimitry Andric   return PreservedAnalyses::none();
6343ca95b02SDimitry Andric }
6353ca95b02SDimitry Andric 
runForTesting(Module & M,function_ref<AAResults & (Function &)> AARGetter,function_ref<OptimizationRemarkEmitter & (Function *)> OREGetter,function_ref<DominatorTree & (Function &)> LookupDomTree)6367a7e6055SDimitry Andric bool DevirtModule::runForTesting(
6372cab237bSDimitry Andric     Module &M, function_ref<AAResults &(Function &)> AARGetter,
638*b5893f02SDimitry Andric     function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter,
639*b5893f02SDimitry Andric     function_ref<DominatorTree &(Function &)> LookupDomTree) {
6404ba319b5SDimitry Andric   ModuleSummaryIndex Summary(/*HaveGVs=*/false);
6417a7e6055SDimitry Andric 
6427a7e6055SDimitry Andric   // Handle the command-line summary arguments. This code is for testing
6437a7e6055SDimitry Andric   // purposes only, so we handle errors directly.
6447a7e6055SDimitry Andric   if (!ClReadSummary.empty()) {
6457a7e6055SDimitry Andric     ExitOnError ExitOnErr("-wholeprogramdevirt-read-summary: " + ClReadSummary +
6467a7e6055SDimitry Andric                           ": ");
6477a7e6055SDimitry Andric     auto ReadSummaryFile =
6487a7e6055SDimitry Andric         ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(ClReadSummary)));
6497a7e6055SDimitry Andric 
6507a7e6055SDimitry Andric     yaml::Input In(ReadSummaryFile->getBuffer());
6517a7e6055SDimitry Andric     In >> Summary;
6527a7e6055SDimitry Andric     ExitOnErr(errorCodeToError(In.error()));
6537a7e6055SDimitry Andric   }
6547a7e6055SDimitry Andric 
6557a7e6055SDimitry Andric   bool Changed =
6567a7e6055SDimitry Andric       DevirtModule(
657*b5893f02SDimitry Andric           M, AARGetter, OREGetter, LookupDomTree,
6587a7e6055SDimitry Andric           ClSummaryAction == PassSummaryAction::Export ? &Summary : nullptr,
6597a7e6055SDimitry Andric           ClSummaryAction == PassSummaryAction::Import ? &Summary : nullptr)
6607a7e6055SDimitry Andric           .run();
6617a7e6055SDimitry Andric 
6627a7e6055SDimitry Andric   if (!ClWriteSummary.empty()) {
6637a7e6055SDimitry Andric     ExitOnError ExitOnErr(
6647a7e6055SDimitry Andric         "-wholeprogramdevirt-write-summary: " + ClWriteSummary + ": ");
6657a7e6055SDimitry Andric     std::error_code EC;
6667a7e6055SDimitry Andric     raw_fd_ostream OS(ClWriteSummary, EC, sys::fs::F_Text);
6677a7e6055SDimitry Andric     ExitOnErr(errorCodeToError(EC));
6687a7e6055SDimitry Andric 
6697a7e6055SDimitry Andric     yaml::Output Out(OS);
6707a7e6055SDimitry Andric     Out << Summary;
6717a7e6055SDimitry Andric   }
6727a7e6055SDimitry Andric 
6737a7e6055SDimitry Andric   return Changed;
6747a7e6055SDimitry Andric }
6757a7e6055SDimitry Andric 
buildTypeIdentifierMap(std::vector<VTableBits> & Bits,DenseMap<Metadata *,std::set<TypeMemberInfo>> & TypeIdMap)6763ca95b02SDimitry Andric void DevirtModule::buildTypeIdentifierMap(
6773ca95b02SDimitry Andric     std::vector<VTableBits> &Bits,
6783ca95b02SDimitry Andric     DenseMap<Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
6793ca95b02SDimitry Andric   DenseMap<GlobalVariable *, VTableBits *> GVToBits;
6803ca95b02SDimitry Andric   Bits.reserve(M.getGlobalList().size());
6813ca95b02SDimitry Andric   SmallVector<MDNode *, 2> Types;
6823ca95b02SDimitry Andric   for (GlobalVariable &GV : M.globals()) {
6833ca95b02SDimitry Andric     Types.clear();
6843ca95b02SDimitry Andric     GV.getMetadata(LLVMContext::MD_type, Types);
685*b5893f02SDimitry Andric     if (GV.isDeclaration() || Types.empty())
6863ca95b02SDimitry Andric       continue;
6873ca95b02SDimitry Andric 
6883ca95b02SDimitry Andric     VTableBits *&BitsPtr = GVToBits[&GV];
6893ca95b02SDimitry Andric     if (!BitsPtr) {
6903ca95b02SDimitry Andric       Bits.emplace_back();
6913ca95b02SDimitry Andric       Bits.back().GV = &GV;
6923ca95b02SDimitry Andric       Bits.back().ObjectSize =
6933ca95b02SDimitry Andric           M.getDataLayout().getTypeAllocSize(GV.getInitializer()->getType());
6943ca95b02SDimitry Andric       BitsPtr = &Bits.back();
6953ca95b02SDimitry Andric     }
6963ca95b02SDimitry Andric 
6973ca95b02SDimitry Andric     for (MDNode *Type : Types) {
6983ca95b02SDimitry Andric       auto TypeID = Type->getOperand(1).get();
6993ca95b02SDimitry Andric 
7003ca95b02SDimitry Andric       uint64_t Offset =
7013ca95b02SDimitry Andric           cast<ConstantInt>(
7023ca95b02SDimitry Andric               cast<ConstantAsMetadata>(Type->getOperand(0))->getValue())
7033ca95b02SDimitry Andric               ->getZExtValue();
7043ca95b02SDimitry Andric 
7053ca95b02SDimitry Andric       TypeIdMap[TypeID].insert({BitsPtr, Offset});
7063ca95b02SDimitry Andric     }
7073ca95b02SDimitry Andric   }
7083ca95b02SDimitry Andric }
7093ca95b02SDimitry Andric 
getPointerAtOffset(Constant * I,uint64_t Offset)710d88c1a5aSDimitry Andric Constant *DevirtModule::getPointerAtOffset(Constant *I, uint64_t Offset) {
711d88c1a5aSDimitry Andric   if (I->getType()->isPointerTy()) {
712d88c1a5aSDimitry Andric     if (Offset == 0)
713d88c1a5aSDimitry Andric       return I;
714d88c1a5aSDimitry Andric     return nullptr;
715d88c1a5aSDimitry Andric   }
716d88c1a5aSDimitry Andric 
717d88c1a5aSDimitry Andric   const DataLayout &DL = M.getDataLayout();
718d88c1a5aSDimitry Andric 
719d88c1a5aSDimitry Andric   if (auto *C = dyn_cast<ConstantStruct>(I)) {
720d88c1a5aSDimitry Andric     const StructLayout *SL = DL.getStructLayout(C->getType());
721d88c1a5aSDimitry Andric     if (Offset >= SL->getSizeInBytes())
722d88c1a5aSDimitry Andric       return nullptr;
723d88c1a5aSDimitry Andric 
724d88c1a5aSDimitry Andric     unsigned Op = SL->getElementContainingOffset(Offset);
725d88c1a5aSDimitry Andric     return getPointerAtOffset(cast<Constant>(I->getOperand(Op)),
726d88c1a5aSDimitry Andric                               Offset - SL->getElementOffset(Op));
727d88c1a5aSDimitry Andric   }
728d88c1a5aSDimitry Andric   if (auto *C = dyn_cast<ConstantArray>(I)) {
729d88c1a5aSDimitry Andric     ArrayType *VTableTy = C->getType();
730d88c1a5aSDimitry Andric     uint64_t ElemSize = DL.getTypeAllocSize(VTableTy->getElementType());
731d88c1a5aSDimitry Andric 
732d88c1a5aSDimitry Andric     unsigned Op = Offset / ElemSize;
733d88c1a5aSDimitry Andric     if (Op >= C->getNumOperands())
734d88c1a5aSDimitry Andric       return nullptr;
735d88c1a5aSDimitry Andric 
736d88c1a5aSDimitry Andric     return getPointerAtOffset(cast<Constant>(I->getOperand(Op)),
737d88c1a5aSDimitry Andric                               Offset % ElemSize);
738d88c1a5aSDimitry Andric   }
739d88c1a5aSDimitry Andric   return nullptr;
740d88c1a5aSDimitry Andric }
741d88c1a5aSDimitry Andric 
tryFindVirtualCallTargets(std::vector<VirtualCallTarget> & TargetsForSlot,const std::set<TypeMemberInfo> & TypeMemberInfos,uint64_t ByteOffset)7423ca95b02SDimitry Andric bool DevirtModule::tryFindVirtualCallTargets(
7433ca95b02SDimitry Andric     std::vector<VirtualCallTarget> &TargetsForSlot,
7443ca95b02SDimitry Andric     const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset) {
7453ca95b02SDimitry Andric   for (const TypeMemberInfo &TM : TypeMemberInfos) {
7463ca95b02SDimitry Andric     if (!TM.Bits->GV->isConstant())
7473ca95b02SDimitry Andric       return false;
7483ca95b02SDimitry Andric 
749d88c1a5aSDimitry Andric     Constant *Ptr = getPointerAtOffset(TM.Bits->GV->getInitializer(),
750d88c1a5aSDimitry Andric                                        TM.Offset + ByteOffset);
751d88c1a5aSDimitry Andric     if (!Ptr)
7523ca95b02SDimitry Andric       return false;
7533ca95b02SDimitry Andric 
754d88c1a5aSDimitry Andric     auto Fn = dyn_cast<Function>(Ptr->stripPointerCasts());
7553ca95b02SDimitry Andric     if (!Fn)
7563ca95b02SDimitry Andric       return false;
7573ca95b02SDimitry Andric 
7583ca95b02SDimitry Andric     // We can disregard __cxa_pure_virtual as a possible call target, as
7593ca95b02SDimitry Andric     // calls to pure virtuals are UB.
7603ca95b02SDimitry Andric     if (Fn->getName() == "__cxa_pure_virtual")
7613ca95b02SDimitry Andric       continue;
7623ca95b02SDimitry Andric 
7633ca95b02SDimitry Andric     TargetsForSlot.push_back({Fn, &TM});
7643ca95b02SDimitry Andric   }
7653ca95b02SDimitry Andric 
7663ca95b02SDimitry Andric   // Give up if we couldn't find any targets.
7673ca95b02SDimitry Andric   return !TargetsForSlot.empty();
7683ca95b02SDimitry Andric }
7693ca95b02SDimitry Andric 
applySingleImplDevirt(VTableSlotInfo & SlotInfo,Constant * TheFn,bool & IsExported)7707a7e6055SDimitry Andric void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
7717a7e6055SDimitry Andric                                          Constant *TheFn, bool &IsExported) {
7727a7e6055SDimitry Andric   auto Apply = [&](CallSiteInfo &CSInfo) {
7737a7e6055SDimitry Andric     for (auto &&VCallSite : CSInfo.CallSites) {
774d88c1a5aSDimitry Andric       if (RemarksEnabled)
775*b5893f02SDimitry Andric         VCallSite.emitRemark("single-impl",
776*b5893f02SDimitry Andric                              TheFn->stripPointerCasts()->getName(), OREGetter);
7773ca95b02SDimitry Andric       VCallSite.CS.setCalledFunction(ConstantExpr::getBitCast(
7783ca95b02SDimitry Andric           TheFn, VCallSite.CS.getCalledValue()->getType()));
7793ca95b02SDimitry Andric       // This use is no longer unsafe.
7803ca95b02SDimitry Andric       if (VCallSite.NumUnsafeUses)
7813ca95b02SDimitry Andric         --*VCallSite.NumUnsafeUses;
7823ca95b02SDimitry Andric     }
7834ba319b5SDimitry Andric     if (CSInfo.isExported())
7847a7e6055SDimitry Andric       IsExported = true;
7857a7e6055SDimitry Andric     CSInfo.markDevirt();
7867a7e6055SDimitry Andric   };
7877a7e6055SDimitry Andric   Apply(SlotInfo.CSInfo);
7887a7e6055SDimitry Andric   for (auto &P : SlotInfo.ConstCSInfo)
7897a7e6055SDimitry Andric     Apply(P.second);
7907a7e6055SDimitry Andric }
7917a7e6055SDimitry Andric 
trySingleImplDevirt(MutableArrayRef<VirtualCallTarget> TargetsForSlot,VTableSlotInfo & SlotInfo,WholeProgramDevirtResolution * Res)7927a7e6055SDimitry Andric bool DevirtModule::trySingleImplDevirt(
7937a7e6055SDimitry Andric     MutableArrayRef<VirtualCallTarget> TargetsForSlot,
7947a7e6055SDimitry Andric     VTableSlotInfo &SlotInfo, WholeProgramDevirtResolution *Res) {
7957a7e6055SDimitry Andric   // See if the program contains a single implementation of this virtual
7967a7e6055SDimitry Andric   // function.
7977a7e6055SDimitry Andric   Function *TheFn = TargetsForSlot[0].Fn;
7987a7e6055SDimitry Andric   for (auto &&Target : TargetsForSlot)
7997a7e6055SDimitry Andric     if (TheFn != Target.Fn)
8007a7e6055SDimitry Andric       return false;
8017a7e6055SDimitry Andric 
8027a7e6055SDimitry Andric   // If so, update each call site to call that implementation directly.
8037a7e6055SDimitry Andric   if (RemarksEnabled)
8047a7e6055SDimitry Andric     TargetsForSlot[0].WasDevirt = true;
8057a7e6055SDimitry Andric 
8067a7e6055SDimitry Andric   bool IsExported = false;
8077a7e6055SDimitry Andric   applySingleImplDevirt(SlotInfo, TheFn, IsExported);
8087a7e6055SDimitry Andric   if (!IsExported)
8097a7e6055SDimitry Andric     return false;
8107a7e6055SDimitry Andric 
8117a7e6055SDimitry Andric   // If the only implementation has local linkage, we must promote to external
8127a7e6055SDimitry Andric   // to make it visible to thin LTO objects. We can only get here during the
8137a7e6055SDimitry Andric   // ThinLTO export phase.
8147a7e6055SDimitry Andric   if (TheFn->hasLocalLinkage()) {
8152cab237bSDimitry Andric     std::string NewName = (TheFn->getName() + "$merged").str();
8162cab237bSDimitry Andric 
8172cab237bSDimitry Andric     // Since we are renaming the function, any comdats with the same name must
8182cab237bSDimitry Andric     // also be renamed. This is required when targeting COFF, as the comdat name
8192cab237bSDimitry Andric     // must match one of the names of the symbols in the comdat.
8202cab237bSDimitry Andric     if (Comdat *C = TheFn->getComdat()) {
8212cab237bSDimitry Andric       if (C->getName() == TheFn->getName()) {
8222cab237bSDimitry Andric         Comdat *NewC = M.getOrInsertComdat(NewName);
8232cab237bSDimitry Andric         NewC->setSelectionKind(C->getSelectionKind());
8242cab237bSDimitry Andric         for (GlobalObject &GO : M.global_objects())
8252cab237bSDimitry Andric           if (GO.getComdat() == C)
8262cab237bSDimitry Andric             GO.setComdat(NewC);
8272cab237bSDimitry Andric       }
8282cab237bSDimitry Andric     }
8292cab237bSDimitry Andric 
8307a7e6055SDimitry Andric     TheFn->setLinkage(GlobalValue::ExternalLinkage);
8317a7e6055SDimitry Andric     TheFn->setVisibility(GlobalValue::HiddenVisibility);
8322cab237bSDimitry Andric     TheFn->setName(NewName);
8337a7e6055SDimitry Andric   }
8347a7e6055SDimitry Andric 
8357a7e6055SDimitry Andric   Res->TheKind = WholeProgramDevirtResolution::SingleImpl;
8367a7e6055SDimitry Andric   Res->SingleImplName = TheFn->getName();
8377a7e6055SDimitry Andric 
8383ca95b02SDimitry Andric   return true;
8393ca95b02SDimitry Andric }
8403ca95b02SDimitry Andric 
tryICallBranchFunnel(MutableArrayRef<VirtualCallTarget> TargetsForSlot,VTableSlotInfo & SlotInfo,WholeProgramDevirtResolution * Res,VTableSlot Slot)8414ba319b5SDimitry Andric void DevirtModule::tryICallBranchFunnel(
8424ba319b5SDimitry Andric     MutableArrayRef<VirtualCallTarget> TargetsForSlot, VTableSlotInfo &SlotInfo,
8434ba319b5SDimitry Andric     WholeProgramDevirtResolution *Res, VTableSlot Slot) {
8444ba319b5SDimitry Andric   Triple T(M.getTargetTriple());
8454ba319b5SDimitry Andric   if (T.getArch() != Triple::x86_64)
8464ba319b5SDimitry Andric     return;
8474ba319b5SDimitry Andric 
8484ba319b5SDimitry Andric   if (TargetsForSlot.size() > ClThreshold)
8494ba319b5SDimitry Andric     return;
8504ba319b5SDimitry Andric 
8514ba319b5SDimitry Andric   bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;
8524ba319b5SDimitry Andric   if (!HasNonDevirt)
8534ba319b5SDimitry Andric     for (auto &P : SlotInfo.ConstCSInfo)
8544ba319b5SDimitry Andric       if (!P.second.AllCallSitesDevirted) {
8554ba319b5SDimitry Andric         HasNonDevirt = true;
8564ba319b5SDimitry Andric         break;
8574ba319b5SDimitry Andric       }
8584ba319b5SDimitry Andric 
8594ba319b5SDimitry Andric   if (!HasNonDevirt)
8604ba319b5SDimitry Andric     return;
8614ba319b5SDimitry Andric 
8624ba319b5SDimitry Andric   FunctionType *FT =
8634ba319b5SDimitry Andric       FunctionType::get(Type::getVoidTy(M.getContext()), {Int8PtrTy}, true);
8644ba319b5SDimitry Andric   Function *JT;
8654ba319b5SDimitry Andric   if (isa<MDString>(Slot.TypeID)) {
8664ba319b5SDimitry Andric     JT = Function::Create(FT, Function::ExternalLinkage,
867*b5893f02SDimitry Andric                           M.getDataLayout().getProgramAddressSpace(),
8684ba319b5SDimitry Andric                           getGlobalName(Slot, {}, "branch_funnel"), &M);
8694ba319b5SDimitry Andric     JT->setVisibility(GlobalValue::HiddenVisibility);
8704ba319b5SDimitry Andric   } else {
871*b5893f02SDimitry Andric     JT = Function::Create(FT, Function::InternalLinkage,
872*b5893f02SDimitry Andric                           M.getDataLayout().getProgramAddressSpace(),
873*b5893f02SDimitry Andric                           "branch_funnel", &M);
8744ba319b5SDimitry Andric   }
8754ba319b5SDimitry Andric   JT->addAttribute(1, Attribute::Nest);
8764ba319b5SDimitry Andric 
8774ba319b5SDimitry Andric   std::vector<Value *> JTArgs;
8784ba319b5SDimitry Andric   JTArgs.push_back(JT->arg_begin());
8794ba319b5SDimitry Andric   for (auto &T : TargetsForSlot) {
8804ba319b5SDimitry Andric     JTArgs.push_back(getMemberAddr(T.TM));
8814ba319b5SDimitry Andric     JTArgs.push_back(T.Fn);
8824ba319b5SDimitry Andric   }
8834ba319b5SDimitry Andric 
8844ba319b5SDimitry Andric   BasicBlock *BB = BasicBlock::Create(M.getContext(), "", JT, nullptr);
8854ba319b5SDimitry Andric   Constant *Intr =
8864ba319b5SDimitry Andric       Intrinsic::getDeclaration(&M, llvm::Intrinsic::icall_branch_funnel, {});
8874ba319b5SDimitry Andric 
8884ba319b5SDimitry Andric   auto *CI = CallInst::Create(Intr, JTArgs, "", BB);
8894ba319b5SDimitry Andric   CI->setTailCallKind(CallInst::TCK_MustTail);
8904ba319b5SDimitry Andric   ReturnInst::Create(M.getContext(), nullptr, BB);
8914ba319b5SDimitry Andric 
8924ba319b5SDimitry Andric   bool IsExported = false;
8934ba319b5SDimitry Andric   applyICallBranchFunnel(SlotInfo, JT, IsExported);
8944ba319b5SDimitry Andric   if (IsExported)
8954ba319b5SDimitry Andric     Res->TheKind = WholeProgramDevirtResolution::BranchFunnel;
8964ba319b5SDimitry Andric }
8974ba319b5SDimitry Andric 
applyICallBranchFunnel(VTableSlotInfo & SlotInfo,Constant * JT,bool & IsExported)8984ba319b5SDimitry Andric void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
8994ba319b5SDimitry Andric                                           Constant *JT, bool &IsExported) {
9004ba319b5SDimitry Andric   auto Apply = [&](CallSiteInfo &CSInfo) {
9014ba319b5SDimitry Andric     if (CSInfo.isExported())
9024ba319b5SDimitry Andric       IsExported = true;
9034ba319b5SDimitry Andric     if (CSInfo.AllCallSitesDevirted)
9044ba319b5SDimitry Andric       return;
9054ba319b5SDimitry Andric     for (auto &&VCallSite : CSInfo.CallSites) {
9064ba319b5SDimitry Andric       CallSite CS = VCallSite.CS;
9074ba319b5SDimitry Andric 
9084ba319b5SDimitry Andric       // Jump tables are only profitable if the retpoline mitigation is enabled.
9094ba319b5SDimitry Andric       Attribute FSAttr = CS.getCaller()->getFnAttribute("target-features");
9104ba319b5SDimitry Andric       if (FSAttr.hasAttribute(Attribute::None) ||
9114ba319b5SDimitry Andric           !FSAttr.getValueAsString().contains("+retpoline"))
9124ba319b5SDimitry Andric         continue;
9134ba319b5SDimitry Andric 
9144ba319b5SDimitry Andric       if (RemarksEnabled)
915*b5893f02SDimitry Andric         VCallSite.emitRemark("branch-funnel",
916*b5893f02SDimitry Andric                              JT->stripPointerCasts()->getName(), OREGetter);
9174ba319b5SDimitry Andric 
9184ba319b5SDimitry Andric       // Pass the address of the vtable in the nest register, which is r10 on
9194ba319b5SDimitry Andric       // x86_64.
9204ba319b5SDimitry Andric       std::vector<Type *> NewArgs;
9214ba319b5SDimitry Andric       NewArgs.push_back(Int8PtrTy);
9224ba319b5SDimitry Andric       for (Type *T : CS.getFunctionType()->params())
9234ba319b5SDimitry Andric         NewArgs.push_back(T);
9244ba319b5SDimitry Andric       PointerType *NewFT = PointerType::getUnqual(
9254ba319b5SDimitry Andric           FunctionType::get(CS.getFunctionType()->getReturnType(), NewArgs,
9264ba319b5SDimitry Andric                             CS.getFunctionType()->isVarArg()));
9274ba319b5SDimitry Andric 
9284ba319b5SDimitry Andric       IRBuilder<> IRB(CS.getInstruction());
9294ba319b5SDimitry Andric       std::vector<Value *> Args;
9304ba319b5SDimitry Andric       Args.push_back(IRB.CreateBitCast(VCallSite.VTable, Int8PtrTy));
9314ba319b5SDimitry Andric       for (unsigned I = 0; I != CS.getNumArgOperands(); ++I)
9324ba319b5SDimitry Andric         Args.push_back(CS.getArgOperand(I));
9334ba319b5SDimitry Andric 
9344ba319b5SDimitry Andric       CallSite NewCS;
9354ba319b5SDimitry Andric       if (CS.isCall())
9364ba319b5SDimitry Andric         NewCS = IRB.CreateCall(IRB.CreateBitCast(JT, NewFT), Args);
9374ba319b5SDimitry Andric       else
9384ba319b5SDimitry Andric         NewCS = IRB.CreateInvoke(
9394ba319b5SDimitry Andric             IRB.CreateBitCast(JT, NewFT),
9404ba319b5SDimitry Andric             cast<InvokeInst>(CS.getInstruction())->getNormalDest(),
9414ba319b5SDimitry Andric             cast<InvokeInst>(CS.getInstruction())->getUnwindDest(), Args);
9424ba319b5SDimitry Andric       NewCS.setCallingConv(CS.getCallingConv());
9434ba319b5SDimitry Andric 
9444ba319b5SDimitry Andric       AttributeList Attrs = CS.getAttributes();
9454ba319b5SDimitry Andric       std::vector<AttributeSet> NewArgAttrs;
9464ba319b5SDimitry Andric       NewArgAttrs.push_back(AttributeSet::get(
9474ba319b5SDimitry Andric           M.getContext(), ArrayRef<Attribute>{Attribute::get(
9484ba319b5SDimitry Andric                               M.getContext(), Attribute::Nest)}));
9494ba319b5SDimitry Andric       for (unsigned I = 0; I + 2 <  Attrs.getNumAttrSets(); ++I)
9504ba319b5SDimitry Andric         NewArgAttrs.push_back(Attrs.getParamAttributes(I));
9514ba319b5SDimitry Andric       NewCS.setAttributes(
9524ba319b5SDimitry Andric           AttributeList::get(M.getContext(), Attrs.getFnAttributes(),
9534ba319b5SDimitry Andric                              Attrs.getRetAttributes(), NewArgAttrs));
9544ba319b5SDimitry Andric 
9554ba319b5SDimitry Andric       CS->replaceAllUsesWith(NewCS.getInstruction());
9564ba319b5SDimitry Andric       CS->eraseFromParent();
9574ba319b5SDimitry Andric 
9584ba319b5SDimitry Andric       // This use is no longer unsafe.
9594ba319b5SDimitry Andric       if (VCallSite.NumUnsafeUses)
9604ba319b5SDimitry Andric         --*VCallSite.NumUnsafeUses;
9614ba319b5SDimitry Andric     }
9624ba319b5SDimitry Andric     // Don't mark as devirtualized because there may be callers compiled without
9634ba319b5SDimitry Andric     // retpoline mitigation, which would mean that they are lowered to
9644ba319b5SDimitry Andric     // llvm.type.test and therefore require an llvm.type.test resolution for the
9654ba319b5SDimitry Andric     // type identifier.
9664ba319b5SDimitry Andric   };
9674ba319b5SDimitry Andric   Apply(SlotInfo.CSInfo);
9684ba319b5SDimitry Andric   for (auto &P : SlotInfo.ConstCSInfo)
9694ba319b5SDimitry Andric     Apply(P.second);
9704ba319b5SDimitry Andric }
9714ba319b5SDimitry Andric 
tryEvaluateFunctionsWithArgs(MutableArrayRef<VirtualCallTarget> TargetsForSlot,ArrayRef<uint64_t> Args)9723ca95b02SDimitry Andric bool DevirtModule::tryEvaluateFunctionsWithArgs(
9733ca95b02SDimitry Andric     MutableArrayRef<VirtualCallTarget> TargetsForSlot,
9747a7e6055SDimitry Andric     ArrayRef<uint64_t> Args) {
9753ca95b02SDimitry Andric   // Evaluate each function and store the result in each target's RetVal
9763ca95b02SDimitry Andric   // field.
9773ca95b02SDimitry Andric   for (VirtualCallTarget &Target : TargetsForSlot) {
9783ca95b02SDimitry Andric     if (Target.Fn->arg_size() != Args.size() + 1)
9793ca95b02SDimitry Andric       return false;
9803ca95b02SDimitry Andric 
9813ca95b02SDimitry Andric     Evaluator Eval(M.getDataLayout(), nullptr);
9823ca95b02SDimitry Andric     SmallVector<Constant *, 2> EvalArgs;
9833ca95b02SDimitry Andric     EvalArgs.push_back(
9843ca95b02SDimitry Andric         Constant::getNullValue(Target.Fn->getFunctionType()->getParamType(0)));
9857a7e6055SDimitry Andric     for (unsigned I = 0; I != Args.size(); ++I) {
9867a7e6055SDimitry Andric       auto *ArgTy = dyn_cast<IntegerType>(
9877a7e6055SDimitry Andric           Target.Fn->getFunctionType()->getParamType(I + 1));
9887a7e6055SDimitry Andric       if (!ArgTy)
9897a7e6055SDimitry Andric         return false;
9907a7e6055SDimitry Andric       EvalArgs.push_back(ConstantInt::get(ArgTy, Args[I]));
9917a7e6055SDimitry Andric     }
9927a7e6055SDimitry Andric 
9933ca95b02SDimitry Andric     Constant *RetVal;
9943ca95b02SDimitry Andric     if (!Eval.EvaluateFunction(Target.Fn, RetVal, EvalArgs) ||
9953ca95b02SDimitry Andric         !isa<ConstantInt>(RetVal))
9963ca95b02SDimitry Andric       return false;
9973ca95b02SDimitry Andric     Target.RetVal = cast<ConstantInt>(RetVal)->getZExtValue();
9983ca95b02SDimitry Andric   }
9993ca95b02SDimitry Andric   return true;
10003ca95b02SDimitry Andric }
10013ca95b02SDimitry Andric 
applyUniformRetValOpt(CallSiteInfo & CSInfo,StringRef FnName,uint64_t TheRetVal)10027a7e6055SDimitry Andric void DevirtModule::applyUniformRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,
10037a7e6055SDimitry Andric                                          uint64_t TheRetVal) {
10047a7e6055SDimitry Andric   for (auto Call : CSInfo.CallSites)
10057a7e6055SDimitry Andric     Call.replaceAndErase(
10062cab237bSDimitry Andric         "uniform-ret-val", FnName, RemarksEnabled, OREGetter,
10077a7e6055SDimitry Andric         ConstantInt::get(cast<IntegerType>(Call.CS.getType()), TheRetVal));
10087a7e6055SDimitry Andric   CSInfo.markDevirt();
10097a7e6055SDimitry Andric }
10107a7e6055SDimitry Andric 
tryUniformRetValOpt(MutableArrayRef<VirtualCallTarget> TargetsForSlot,CallSiteInfo & CSInfo,WholeProgramDevirtResolution::ByArg * Res)10113ca95b02SDimitry Andric bool DevirtModule::tryUniformRetValOpt(
10127a7e6055SDimitry Andric     MutableArrayRef<VirtualCallTarget> TargetsForSlot, CallSiteInfo &CSInfo,
10137a7e6055SDimitry Andric     WholeProgramDevirtResolution::ByArg *Res) {
10143ca95b02SDimitry Andric   // Uniform return value optimization. If all functions return the same
10153ca95b02SDimitry Andric   // constant, replace all calls with that constant.
10163ca95b02SDimitry Andric   uint64_t TheRetVal = TargetsForSlot[0].RetVal;
10173ca95b02SDimitry Andric   for (const VirtualCallTarget &Target : TargetsForSlot)
10183ca95b02SDimitry Andric     if (Target.RetVal != TheRetVal)
10193ca95b02SDimitry Andric       return false;
10203ca95b02SDimitry Andric 
10217a7e6055SDimitry Andric   if (CSInfo.isExported()) {
10227a7e6055SDimitry Andric     Res->TheKind = WholeProgramDevirtResolution::ByArg::UniformRetVal;
10237a7e6055SDimitry Andric     Res->Info = TheRetVal;
10247a7e6055SDimitry Andric   }
10257a7e6055SDimitry Andric 
10267a7e6055SDimitry Andric   applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->getName(), TheRetVal);
1027d88c1a5aSDimitry Andric   if (RemarksEnabled)
1028d88c1a5aSDimitry Andric     for (auto &&Target : TargetsForSlot)
1029d88c1a5aSDimitry Andric       Target.WasDevirt = true;
10303ca95b02SDimitry Andric   return true;
10313ca95b02SDimitry Andric }
10323ca95b02SDimitry Andric 
getGlobalName(VTableSlot Slot,ArrayRef<uint64_t> Args,StringRef Name)10337a7e6055SDimitry Andric std::string DevirtModule::getGlobalName(VTableSlot Slot,
10347a7e6055SDimitry Andric                                         ArrayRef<uint64_t> Args,
10357a7e6055SDimitry Andric                                         StringRef Name) {
10367a7e6055SDimitry Andric   std::string FullName = "__typeid_";
10377a7e6055SDimitry Andric   raw_string_ostream OS(FullName);
10387a7e6055SDimitry Andric   OS << cast<MDString>(Slot.TypeID)->getString() << '_' << Slot.ByteOffset;
10397a7e6055SDimitry Andric   for (uint64_t Arg : Args)
10407a7e6055SDimitry Andric     OS << '_' << Arg;
10417a7e6055SDimitry Andric   OS << '_' << Name;
10427a7e6055SDimitry Andric   return OS.str();
10437a7e6055SDimitry Andric }
10447a7e6055SDimitry Andric 
shouldExportConstantsAsAbsoluteSymbols()10452cab237bSDimitry Andric bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
10462cab237bSDimitry Andric   Triple T(M.getTargetTriple());
10472cab237bSDimitry Andric   return (T.getArch() == Triple::x86 || T.getArch() == Triple::x86_64) &&
10482cab237bSDimitry Andric          T.getObjectFormat() == Triple::ELF;
10492cab237bSDimitry Andric }
10502cab237bSDimitry Andric 
exportGlobal(VTableSlot Slot,ArrayRef<uint64_t> Args,StringRef Name,Constant * C)10517a7e6055SDimitry Andric void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
10527a7e6055SDimitry Andric                                 StringRef Name, Constant *C) {
10537a7e6055SDimitry Andric   GlobalAlias *GA = GlobalAlias::create(Int8Ty, 0, GlobalValue::ExternalLinkage,
10547a7e6055SDimitry Andric                                         getGlobalName(Slot, Args, Name), C, &M);
10557a7e6055SDimitry Andric   GA->setVisibility(GlobalValue::HiddenVisibility);
10567a7e6055SDimitry Andric }
10577a7e6055SDimitry Andric 
exportConstant(VTableSlot Slot,ArrayRef<uint64_t> Args,StringRef Name,uint32_t Const,uint32_t & Storage)10582cab237bSDimitry Andric void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
10592cab237bSDimitry Andric                                   StringRef Name, uint32_t Const,
10602cab237bSDimitry Andric                                   uint32_t &Storage) {
10612cab237bSDimitry Andric   if (shouldExportConstantsAsAbsoluteSymbols()) {
10622cab237bSDimitry Andric     exportGlobal(
10632cab237bSDimitry Andric         Slot, Args, Name,
10642cab237bSDimitry Andric         ConstantExpr::getIntToPtr(ConstantInt::get(Int32Ty, Const), Int8PtrTy));
10652cab237bSDimitry Andric     return;
10662cab237bSDimitry Andric   }
10672cab237bSDimitry Andric 
10682cab237bSDimitry Andric   Storage = Const;
10692cab237bSDimitry Andric }
10702cab237bSDimitry Andric 
importGlobal(VTableSlot Slot,ArrayRef<uint64_t> Args,StringRef Name)10717a7e6055SDimitry Andric Constant *DevirtModule::importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
10722cab237bSDimitry Andric                                      StringRef Name) {
10737a7e6055SDimitry Andric   Constant *C = M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Ty);
10747a7e6055SDimitry Andric   auto *GV = dyn_cast<GlobalVariable>(C);
10752cab237bSDimitry Andric   if (GV)
10762cab237bSDimitry Andric     GV->setVisibility(GlobalValue::HiddenVisibility);
10772cab237bSDimitry Andric   return C;
10782cab237bSDimitry Andric }
10792cab237bSDimitry Andric 
importConstant(VTableSlot Slot,ArrayRef<uint64_t> Args,StringRef Name,IntegerType * IntTy,uint32_t Storage)10802cab237bSDimitry Andric Constant *DevirtModule::importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
10812cab237bSDimitry Andric                                        StringRef Name, IntegerType *IntTy,
10822cab237bSDimitry Andric                                        uint32_t Storage) {
10832cab237bSDimitry Andric   if (!shouldExportConstantsAsAbsoluteSymbols())
10842cab237bSDimitry Andric     return ConstantInt::get(IntTy, Storage);
10852cab237bSDimitry Andric 
10862cab237bSDimitry Andric   Constant *C = importGlobal(Slot, Args, Name);
10872cab237bSDimitry Andric   auto *GV = cast<GlobalVariable>(C->stripPointerCasts());
10882cab237bSDimitry Andric   C = ConstantExpr::getPtrToInt(C, IntTy);
10892cab237bSDimitry Andric 
10907a7e6055SDimitry Andric   // We only need to set metadata if the global is newly created, in which
10917a7e6055SDimitry Andric   // case it would not have hidden visibility.
10924ba319b5SDimitry Andric   if (GV->hasMetadata(LLVMContext::MD_absolute_symbol))
10937a7e6055SDimitry Andric     return C;
10947a7e6055SDimitry Andric 
10957a7e6055SDimitry Andric   auto SetAbsRange = [&](uint64_t Min, uint64_t Max) {
10967a7e6055SDimitry Andric     auto *MinC = ConstantAsMetadata::get(ConstantInt::get(IntPtrTy, Min));
10977a7e6055SDimitry Andric     auto *MaxC = ConstantAsMetadata::get(ConstantInt::get(IntPtrTy, Max));
10987a7e6055SDimitry Andric     GV->setMetadata(LLVMContext::MD_absolute_symbol,
10997a7e6055SDimitry Andric                     MDNode::get(M.getContext(), {MinC, MaxC}));
11007a7e6055SDimitry Andric   };
11012cab237bSDimitry Andric   unsigned AbsWidth = IntTy->getBitWidth();
11027a7e6055SDimitry Andric   if (AbsWidth == IntPtrTy->getBitWidth())
11037a7e6055SDimitry Andric     SetAbsRange(~0ull, ~0ull); // Full set.
11042cab237bSDimitry Andric   else
11057a7e6055SDimitry Andric     SetAbsRange(0, 1ull << AbsWidth);
11062cab237bSDimitry Andric   return C;
11077a7e6055SDimitry Andric }
11087a7e6055SDimitry Andric 
applyUniqueRetValOpt(CallSiteInfo & CSInfo,StringRef FnName,bool IsOne,Constant * UniqueMemberAddr)11097a7e6055SDimitry Andric void DevirtModule::applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,
11107a7e6055SDimitry Andric                                         bool IsOne,
11117a7e6055SDimitry Andric                                         Constant *UniqueMemberAddr) {
11127a7e6055SDimitry Andric   for (auto &&Call : CSInfo.CallSites) {
11137a7e6055SDimitry Andric     IRBuilder<> B(Call.CS.getInstruction());
11142cab237bSDimitry Andric     Value *Cmp =
11152cab237bSDimitry Andric         B.CreateICmp(IsOne ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE,
11162cab237bSDimitry Andric                      B.CreateBitCast(Call.VTable, Int8PtrTy), UniqueMemberAddr);
11177a7e6055SDimitry Andric     Cmp = B.CreateZExt(Cmp, Call.CS->getType());
11182cab237bSDimitry Andric     Call.replaceAndErase("unique-ret-val", FnName, RemarksEnabled, OREGetter,
11192cab237bSDimitry Andric                          Cmp);
11207a7e6055SDimitry Andric   }
11217a7e6055SDimitry Andric   CSInfo.markDevirt();
11227a7e6055SDimitry Andric }
11237a7e6055SDimitry Andric 
getMemberAddr(const TypeMemberInfo * M)11244ba319b5SDimitry Andric Constant *DevirtModule::getMemberAddr(const TypeMemberInfo *M) {
11254ba319b5SDimitry Andric   Constant *C = ConstantExpr::getBitCast(M->Bits->GV, Int8PtrTy);
11264ba319b5SDimitry Andric   return ConstantExpr::getGetElementPtr(Int8Ty, C,
11274ba319b5SDimitry Andric                                         ConstantInt::get(Int64Ty, M->Offset));
11284ba319b5SDimitry Andric }
11294ba319b5SDimitry Andric 
tryUniqueRetValOpt(unsigned BitWidth,MutableArrayRef<VirtualCallTarget> TargetsForSlot,CallSiteInfo & CSInfo,WholeProgramDevirtResolution::ByArg * Res,VTableSlot Slot,ArrayRef<uint64_t> Args)11303ca95b02SDimitry Andric bool DevirtModule::tryUniqueRetValOpt(
1131d88c1a5aSDimitry Andric     unsigned BitWidth, MutableArrayRef<VirtualCallTarget> TargetsForSlot,
11327a7e6055SDimitry Andric     CallSiteInfo &CSInfo, WholeProgramDevirtResolution::ByArg *Res,
11337a7e6055SDimitry Andric     VTableSlot Slot, ArrayRef<uint64_t> Args) {
11343ca95b02SDimitry Andric   // IsOne controls whether we look for a 0 or a 1.
11353ca95b02SDimitry Andric   auto tryUniqueRetValOptFor = [&](bool IsOne) {
1136d88c1a5aSDimitry Andric     const TypeMemberInfo *UniqueMember = nullptr;
11373ca95b02SDimitry Andric     for (const VirtualCallTarget &Target : TargetsForSlot) {
11383ca95b02SDimitry Andric       if (Target.RetVal == (IsOne ? 1 : 0)) {
11393ca95b02SDimitry Andric         if (UniqueMember)
11403ca95b02SDimitry Andric           return false;
11413ca95b02SDimitry Andric         UniqueMember = Target.TM;
11423ca95b02SDimitry Andric       }
11433ca95b02SDimitry Andric     }
11443ca95b02SDimitry Andric 
11453ca95b02SDimitry Andric     // We should have found a unique member or bailed out by now. We already
11463ca95b02SDimitry Andric     // checked for a uniform return value in tryUniformRetValOpt.
11473ca95b02SDimitry Andric     assert(UniqueMember);
11483ca95b02SDimitry Andric 
11494ba319b5SDimitry Andric     Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);
11507a7e6055SDimitry Andric     if (CSInfo.isExported()) {
11517a7e6055SDimitry Andric       Res->TheKind = WholeProgramDevirtResolution::ByArg::UniqueRetVal;
11527a7e6055SDimitry Andric       Res->Info = IsOne;
11537a7e6055SDimitry Andric 
11547a7e6055SDimitry Andric       exportGlobal(Slot, Args, "unique_member", UniqueMemberAddr);
11553ca95b02SDimitry Andric     }
11567a7e6055SDimitry Andric 
11577a7e6055SDimitry Andric     // Replace each call with the comparison.
11587a7e6055SDimitry Andric     applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->getName(), IsOne,
11597a7e6055SDimitry Andric                          UniqueMemberAddr);
11607a7e6055SDimitry Andric 
1161d88c1a5aSDimitry Andric     // Update devirtualization statistics for targets.
1162d88c1a5aSDimitry Andric     if (RemarksEnabled)
1163d88c1a5aSDimitry Andric       for (auto &&Target : TargetsForSlot)
1164d88c1a5aSDimitry Andric         Target.WasDevirt = true;
1165d88c1a5aSDimitry Andric 
11663ca95b02SDimitry Andric     return true;
11673ca95b02SDimitry Andric   };
11683ca95b02SDimitry Andric 
11693ca95b02SDimitry Andric   if (BitWidth == 1) {
11703ca95b02SDimitry Andric     if (tryUniqueRetValOptFor(true))
11713ca95b02SDimitry Andric       return true;
11723ca95b02SDimitry Andric     if (tryUniqueRetValOptFor(false))
11733ca95b02SDimitry Andric       return true;
11743ca95b02SDimitry Andric   }
11753ca95b02SDimitry Andric   return false;
11763ca95b02SDimitry Andric }
11773ca95b02SDimitry Andric 
applyVirtualConstProp(CallSiteInfo & CSInfo,StringRef FnName,Constant * Byte,Constant * Bit)11787a7e6055SDimitry Andric void DevirtModule::applyVirtualConstProp(CallSiteInfo &CSInfo, StringRef FnName,
11797a7e6055SDimitry Andric                                          Constant *Byte, Constant *Bit) {
11807a7e6055SDimitry Andric   for (auto Call : CSInfo.CallSites) {
11817a7e6055SDimitry Andric     auto *RetType = cast<IntegerType>(Call.CS.getType());
11827a7e6055SDimitry Andric     IRBuilder<> B(Call.CS.getInstruction());
11832cab237bSDimitry Andric     Value *Addr =
11842cab237bSDimitry Andric         B.CreateGEP(Int8Ty, B.CreateBitCast(Call.VTable, Int8PtrTy), Byte);
11857a7e6055SDimitry Andric     if (RetType->getBitWidth() == 1) {
11867a7e6055SDimitry Andric       Value *Bits = B.CreateLoad(Addr);
11877a7e6055SDimitry Andric       Value *BitsAndBit = B.CreateAnd(Bits, Bit);
11887a7e6055SDimitry Andric       auto IsBitSet = B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0));
11897a7e6055SDimitry Andric       Call.replaceAndErase("virtual-const-prop-1-bit", FnName, RemarksEnabled,
11902cab237bSDimitry Andric                            OREGetter, IsBitSet);
11917a7e6055SDimitry Andric     } else {
11927a7e6055SDimitry Andric       Value *ValAddr = B.CreateBitCast(Addr, RetType->getPointerTo());
11937a7e6055SDimitry Andric       Value *Val = B.CreateLoad(RetType, ValAddr);
11942cab237bSDimitry Andric       Call.replaceAndErase("virtual-const-prop", FnName, RemarksEnabled,
11952cab237bSDimitry Andric                            OREGetter, Val);
11967a7e6055SDimitry Andric     }
11977a7e6055SDimitry Andric   }
11987a7e6055SDimitry Andric   CSInfo.markDevirt();
11997a7e6055SDimitry Andric }
12007a7e6055SDimitry Andric 
tryVirtualConstProp(MutableArrayRef<VirtualCallTarget> TargetsForSlot,VTableSlotInfo & SlotInfo,WholeProgramDevirtResolution * Res,VTableSlot Slot)12013ca95b02SDimitry Andric bool DevirtModule::tryVirtualConstProp(
12027a7e6055SDimitry Andric     MutableArrayRef<VirtualCallTarget> TargetsForSlot, VTableSlotInfo &SlotInfo,
12037a7e6055SDimitry Andric     WholeProgramDevirtResolution *Res, VTableSlot Slot) {
12043ca95b02SDimitry Andric   // This only works if the function returns an integer.
12053ca95b02SDimitry Andric   auto RetType = dyn_cast<IntegerType>(TargetsForSlot[0].Fn->getReturnType());
12063ca95b02SDimitry Andric   if (!RetType)
12073ca95b02SDimitry Andric     return false;
12083ca95b02SDimitry Andric   unsigned BitWidth = RetType->getBitWidth();
12093ca95b02SDimitry Andric   if (BitWidth > 64)
12103ca95b02SDimitry Andric     return false;
12113ca95b02SDimitry Andric 
12127a7e6055SDimitry Andric   // Make sure that each function is defined, does not access memory, takes at
12137a7e6055SDimitry Andric   // least one argument, does not use its first argument (which we assume is
12147a7e6055SDimitry Andric   // 'this'), and has the same return type.
12157a7e6055SDimitry Andric   //
12167a7e6055SDimitry Andric   // Note that we test whether this copy of the function is readnone, rather
12177a7e6055SDimitry Andric   // than testing function attributes, which must hold for any copy of the
12187a7e6055SDimitry Andric   // function, even a less optimized version substituted at link time. This is
12197a7e6055SDimitry Andric   // sound because the virtual constant propagation optimizations effectively
12207a7e6055SDimitry Andric   // inline all implementations of the virtual function into each call site,
12217a7e6055SDimitry Andric   // rather than using function attributes to perform local optimization.
12223ca95b02SDimitry Andric   for (VirtualCallTarget &Target : TargetsForSlot) {
12237a7e6055SDimitry Andric     if (Target.Fn->isDeclaration() ||
12247a7e6055SDimitry Andric         computeFunctionBodyMemoryAccess(*Target.Fn, AARGetter(*Target.Fn)) !=
12257a7e6055SDimitry Andric             MAK_ReadNone ||
12267a7e6055SDimitry Andric         Target.Fn->arg_empty() || !Target.Fn->arg_begin()->use_empty() ||
12273ca95b02SDimitry Andric         Target.Fn->getReturnType() != RetType)
12283ca95b02SDimitry Andric       return false;
12293ca95b02SDimitry Andric   }
12303ca95b02SDimitry Andric 
12317a7e6055SDimitry Andric   for (auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {
12323ca95b02SDimitry Andric     if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))
12333ca95b02SDimitry Andric       continue;
12343ca95b02SDimitry Andric 
12357a7e6055SDimitry Andric     WholeProgramDevirtResolution::ByArg *ResByArg = nullptr;
12367a7e6055SDimitry Andric     if (Res)
12377a7e6055SDimitry Andric       ResByArg = &Res->ResByArg[CSByConstantArg.first];
12387a7e6055SDimitry Andric 
12397a7e6055SDimitry Andric     if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))
12403ca95b02SDimitry Andric       continue;
12413ca95b02SDimitry Andric 
12427a7e6055SDimitry Andric     if (tryUniqueRetValOpt(BitWidth, TargetsForSlot, CSByConstantArg.second,
12437a7e6055SDimitry Andric                            ResByArg, Slot, CSByConstantArg.first))
12443ca95b02SDimitry Andric       continue;
12453ca95b02SDimitry Andric 
12463ca95b02SDimitry Andric     // Find an allocation offset in bits in all vtables associated with the
12473ca95b02SDimitry Andric     // type.
12483ca95b02SDimitry Andric     uint64_t AllocBefore =
12493ca95b02SDimitry Andric         findLowestOffset(TargetsForSlot, /*IsAfter=*/false, BitWidth);
12503ca95b02SDimitry Andric     uint64_t AllocAfter =
12513ca95b02SDimitry Andric         findLowestOffset(TargetsForSlot, /*IsAfter=*/true, BitWidth);
12523ca95b02SDimitry Andric 
12533ca95b02SDimitry Andric     // Calculate the total amount of padding needed to store a value at both
12543ca95b02SDimitry Andric     // ends of the object.
12553ca95b02SDimitry Andric     uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;
12563ca95b02SDimitry Andric     for (auto &&Target : TargetsForSlot) {
12573ca95b02SDimitry Andric       TotalPaddingBefore += std::max<int64_t>(
12583ca95b02SDimitry Andric           (AllocBefore + 7) / 8 - Target.allocatedBeforeBytes() - 1, 0);
12593ca95b02SDimitry Andric       TotalPaddingAfter += std::max<int64_t>(
12603ca95b02SDimitry Andric           (AllocAfter + 7) / 8 - Target.allocatedAfterBytes() - 1, 0);
12613ca95b02SDimitry Andric     }
12623ca95b02SDimitry Andric 
12633ca95b02SDimitry Andric     // If the amount of padding is too large, give up.
12643ca95b02SDimitry Andric     // FIXME: do something smarter here.
12653ca95b02SDimitry Andric     if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)
12663ca95b02SDimitry Andric       continue;
12673ca95b02SDimitry Andric 
12683ca95b02SDimitry Andric     // Calculate the offset to the value as a (possibly negative) byte offset
12693ca95b02SDimitry Andric     // and (if applicable) a bit offset, and store the values in the targets.
12703ca95b02SDimitry Andric     int64_t OffsetByte;
12713ca95b02SDimitry Andric     uint64_t OffsetBit;
12723ca95b02SDimitry Andric     if (TotalPaddingBefore <= TotalPaddingAfter)
12733ca95b02SDimitry Andric       setBeforeReturnValues(TargetsForSlot, AllocBefore, BitWidth, OffsetByte,
12743ca95b02SDimitry Andric                             OffsetBit);
12753ca95b02SDimitry Andric     else
12763ca95b02SDimitry Andric       setAfterReturnValues(TargetsForSlot, AllocAfter, BitWidth, OffsetByte,
12773ca95b02SDimitry Andric                            OffsetBit);
12783ca95b02SDimitry Andric 
1279d88c1a5aSDimitry Andric     if (RemarksEnabled)
1280d88c1a5aSDimitry Andric       for (auto &&Target : TargetsForSlot)
1281d88c1a5aSDimitry Andric         Target.WasDevirt = true;
1282d88c1a5aSDimitry Andric 
12837a7e6055SDimitry Andric 
12847a7e6055SDimitry Andric     if (CSByConstantArg.second.isExported()) {
12857a7e6055SDimitry Andric       ResByArg->TheKind = WholeProgramDevirtResolution::ByArg::VirtualConstProp;
12862cab237bSDimitry Andric       exportConstant(Slot, CSByConstantArg.first, "byte", OffsetByte,
12872cab237bSDimitry Andric                      ResByArg->Byte);
12882cab237bSDimitry Andric       exportConstant(Slot, CSByConstantArg.first, "bit", 1ULL << OffsetBit,
12892cab237bSDimitry Andric                      ResByArg->Bit);
12907a7e6055SDimitry Andric     }
12917a7e6055SDimitry Andric 
12923ca95b02SDimitry Andric     // Rewrite each call to a load from OffsetByte/OffsetBit.
12932cab237bSDimitry Andric     Constant *ByteConst = ConstantInt::get(Int32Ty, OffsetByte);
12942cab237bSDimitry Andric     Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
12957a7e6055SDimitry Andric     applyVirtualConstProp(CSByConstantArg.second,
12967a7e6055SDimitry Andric                           TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);
12973ca95b02SDimitry Andric   }
12983ca95b02SDimitry Andric   return true;
12993ca95b02SDimitry Andric }
13003ca95b02SDimitry Andric 
rebuildGlobal(VTableBits & B)13013ca95b02SDimitry Andric void DevirtModule::rebuildGlobal(VTableBits &B) {
13023ca95b02SDimitry Andric   if (B.Before.Bytes.empty() && B.After.Bytes.empty())
13033ca95b02SDimitry Andric     return;
13043ca95b02SDimitry Andric 
13053ca95b02SDimitry Andric   // Align each byte array to pointer width.
13063ca95b02SDimitry Andric   unsigned PointerSize = M.getDataLayout().getPointerSize();
13073ca95b02SDimitry Andric   B.Before.Bytes.resize(alignTo(B.Before.Bytes.size(), PointerSize));
13083ca95b02SDimitry Andric   B.After.Bytes.resize(alignTo(B.After.Bytes.size(), PointerSize));
13093ca95b02SDimitry Andric 
13103ca95b02SDimitry Andric   // Before was stored in reverse order; flip it now.
13113ca95b02SDimitry Andric   for (size_t I = 0, Size = B.Before.Bytes.size(); I != Size / 2; ++I)
13123ca95b02SDimitry Andric     std::swap(B.Before.Bytes[I], B.Before.Bytes[Size - 1 - I]);
13133ca95b02SDimitry Andric 
13143ca95b02SDimitry Andric   // Build an anonymous global containing the before bytes, followed by the
13153ca95b02SDimitry Andric   // original initializer, followed by the after bytes.
13163ca95b02SDimitry Andric   auto NewInit = ConstantStruct::getAnon(
13173ca95b02SDimitry Andric       {ConstantDataArray::get(M.getContext(), B.Before.Bytes),
13183ca95b02SDimitry Andric        B.GV->getInitializer(),
13193ca95b02SDimitry Andric        ConstantDataArray::get(M.getContext(), B.After.Bytes)});
13203ca95b02SDimitry Andric   auto NewGV =
13213ca95b02SDimitry Andric       new GlobalVariable(M, NewInit->getType(), B.GV->isConstant(),
13223ca95b02SDimitry Andric                          GlobalVariable::PrivateLinkage, NewInit, "", B.GV);
13233ca95b02SDimitry Andric   NewGV->setSection(B.GV->getSection());
13243ca95b02SDimitry Andric   NewGV->setComdat(B.GV->getComdat());
13253ca95b02SDimitry Andric 
13263ca95b02SDimitry Andric   // Copy the original vtable's metadata to the anonymous global, adjusting
13273ca95b02SDimitry Andric   // offsets as required.
13283ca95b02SDimitry Andric   NewGV->copyMetadata(B.GV, B.Before.Bytes.size());
13293ca95b02SDimitry Andric 
13303ca95b02SDimitry Andric   // Build an alias named after the original global, pointing at the second
13313ca95b02SDimitry Andric   // element (the original initializer).
13323ca95b02SDimitry Andric   auto Alias = GlobalAlias::create(
13333ca95b02SDimitry Andric       B.GV->getInitializer()->getType(), 0, B.GV->getLinkage(), "",
13343ca95b02SDimitry Andric       ConstantExpr::getGetElementPtr(
13353ca95b02SDimitry Andric           NewInit->getType(), NewGV,
13363ca95b02SDimitry Andric           ArrayRef<Constant *>{ConstantInt::get(Int32Ty, 0),
13373ca95b02SDimitry Andric                                ConstantInt::get(Int32Ty, 1)}),
13383ca95b02SDimitry Andric       &M);
13393ca95b02SDimitry Andric   Alias->setVisibility(B.GV->getVisibility());
13403ca95b02SDimitry Andric   Alias->takeName(B.GV);
13413ca95b02SDimitry Andric 
13423ca95b02SDimitry Andric   B.GV->replaceAllUsesWith(Alias);
13433ca95b02SDimitry Andric   B.GV->eraseFromParent();
13443ca95b02SDimitry Andric }
13453ca95b02SDimitry Andric 
areRemarksEnabled()1346d88c1a5aSDimitry Andric bool DevirtModule::areRemarksEnabled() {
1347d88c1a5aSDimitry Andric   const auto &FL = M.getFunctionList();
1348*b5893f02SDimitry Andric   for (const Function &Fn : FL) {
13497a7e6055SDimitry Andric     const auto &BBL = Fn.getBasicBlockList();
13507a7e6055SDimitry Andric     if (BBL.empty())
1351*b5893f02SDimitry Andric       continue;
13527a7e6055SDimitry Andric     auto DI = OptimizationRemark(DEBUG_TYPE, "", DebugLoc(), &BBL.front());
1353d88c1a5aSDimitry Andric     return DI.isEnabled();
1354d88c1a5aSDimitry Andric   }
1355*b5893f02SDimitry Andric   return false;
1356*b5893f02SDimitry Andric }
1357d88c1a5aSDimitry Andric 
scanTypeTestUsers(Function * TypeTestFunc,Function * AssumeFunc)13583ca95b02SDimitry Andric void DevirtModule::scanTypeTestUsers(Function *TypeTestFunc,
13593ca95b02SDimitry Andric                                      Function *AssumeFunc) {
13603ca95b02SDimitry Andric   // Find all virtual calls via a virtual table pointer %p under an assumption
13613ca95b02SDimitry Andric   // of the form llvm.assume(llvm.type.test(%p, %md)). This indicates that %p
13623ca95b02SDimitry Andric   // points to a member of the type identifier %md. Group calls by (type ID,
13633ca95b02SDimitry Andric   // offset) pair (effectively the identity of the virtual function) and store
13643ca95b02SDimitry Andric   // to CallSlots.
1365*b5893f02SDimitry Andric   DenseSet<CallSite> SeenCallSites;
13663ca95b02SDimitry Andric   for (auto I = TypeTestFunc->use_begin(), E = TypeTestFunc->use_end();
13673ca95b02SDimitry Andric        I != E;) {
13683ca95b02SDimitry Andric     auto CI = dyn_cast<CallInst>(I->getUser());
13693ca95b02SDimitry Andric     ++I;
13703ca95b02SDimitry Andric     if (!CI)
13713ca95b02SDimitry Andric       continue;
13723ca95b02SDimitry Andric 
13733ca95b02SDimitry Andric     // Search for virtual calls based on %p and add them to DevirtCalls.
13743ca95b02SDimitry Andric     SmallVector<DevirtCallSite, 1> DevirtCalls;
13753ca95b02SDimitry Andric     SmallVector<CallInst *, 1> Assumes;
1376*b5893f02SDimitry Andric     auto &DT = LookupDomTree(*CI->getFunction());
1377*b5893f02SDimitry Andric     findDevirtualizableCallsForTypeTest(DevirtCalls, Assumes, CI, DT);
13783ca95b02SDimitry Andric 
1379*b5893f02SDimitry Andric     // If we found any, add them to CallSlots.
13803ca95b02SDimitry Andric     if (!Assumes.empty()) {
13813ca95b02SDimitry Andric       Metadata *TypeId =
13823ca95b02SDimitry Andric           cast<MetadataAsValue>(CI->getArgOperand(1))->getMetadata();
13833ca95b02SDimitry Andric       Value *Ptr = CI->getArgOperand(0)->stripPointerCasts();
13843ca95b02SDimitry Andric       for (DevirtCallSite Call : DevirtCalls) {
1385*b5893f02SDimitry Andric         // Only add this CallSite if we haven't seen it before. The vtable
1386*b5893f02SDimitry Andric         // pointer may have been CSE'd with pointers from other call sites,
1387*b5893f02SDimitry Andric         // and we don't want to process call sites multiple times. We can't
1388*b5893f02SDimitry Andric         // just skip the vtable Ptr if it has been seen before, however, since
1389*b5893f02SDimitry Andric         // it may be shared by type tests that dominate different calls.
1390*b5893f02SDimitry Andric         if (SeenCallSites.insert(Call.CS).second)
13912cab237bSDimitry Andric           CallSlots[{TypeId, Call.Offset}].addCallSite(Ptr, Call.CS, nullptr);
13923ca95b02SDimitry Andric       }
13933ca95b02SDimitry Andric     }
13943ca95b02SDimitry Andric 
13953ca95b02SDimitry Andric     // We no longer need the assumes or the type test.
13963ca95b02SDimitry Andric     for (auto Assume : Assumes)
13973ca95b02SDimitry Andric       Assume->eraseFromParent();
13983ca95b02SDimitry Andric     // We can't use RecursivelyDeleteTriviallyDeadInstructions here because we
13993ca95b02SDimitry Andric     // may use the vtable argument later.
14003ca95b02SDimitry Andric     if (CI->use_empty())
14013ca95b02SDimitry Andric       CI->eraseFromParent();
14023ca95b02SDimitry Andric   }
14033ca95b02SDimitry Andric }
14043ca95b02SDimitry Andric 
scanTypeCheckedLoadUsers(Function * TypeCheckedLoadFunc)14053ca95b02SDimitry Andric void DevirtModule::scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc) {
14063ca95b02SDimitry Andric   Function *TypeTestFunc = Intrinsic::getDeclaration(&M, Intrinsic::type_test);
14073ca95b02SDimitry Andric 
14083ca95b02SDimitry Andric   for (auto I = TypeCheckedLoadFunc->use_begin(),
14093ca95b02SDimitry Andric             E = TypeCheckedLoadFunc->use_end();
14103ca95b02SDimitry Andric        I != E;) {
14113ca95b02SDimitry Andric     auto CI = dyn_cast<CallInst>(I->getUser());
14123ca95b02SDimitry Andric     ++I;
14133ca95b02SDimitry Andric     if (!CI)
14143ca95b02SDimitry Andric       continue;
14153ca95b02SDimitry Andric 
14163ca95b02SDimitry Andric     Value *Ptr = CI->getArgOperand(0);
14173ca95b02SDimitry Andric     Value *Offset = CI->getArgOperand(1);
14183ca95b02SDimitry Andric     Value *TypeIdValue = CI->getArgOperand(2);
14193ca95b02SDimitry Andric     Metadata *TypeId = cast<MetadataAsValue>(TypeIdValue)->getMetadata();
14203ca95b02SDimitry Andric 
14213ca95b02SDimitry Andric     SmallVector<DevirtCallSite, 1> DevirtCalls;
14223ca95b02SDimitry Andric     SmallVector<Instruction *, 1> LoadedPtrs;
14233ca95b02SDimitry Andric     SmallVector<Instruction *, 1> Preds;
14243ca95b02SDimitry Andric     bool HasNonCallUses = false;
1425*b5893f02SDimitry Andric     auto &DT = LookupDomTree(*CI->getFunction());
14263ca95b02SDimitry Andric     findDevirtualizableCallsForTypeCheckedLoad(DevirtCalls, LoadedPtrs, Preds,
1427*b5893f02SDimitry Andric                                                HasNonCallUses, CI, DT);
14283ca95b02SDimitry Andric 
14293ca95b02SDimitry Andric     // Start by generating "pessimistic" code that explicitly loads the function
14303ca95b02SDimitry Andric     // pointer from the vtable and performs the type check. If possible, we will
14313ca95b02SDimitry Andric     // eliminate the load and the type check later.
14323ca95b02SDimitry Andric 
14333ca95b02SDimitry Andric     // If possible, only generate the load at the point where it is used.
14343ca95b02SDimitry Andric     // This helps avoid unnecessary spills.
14353ca95b02SDimitry Andric     IRBuilder<> LoadB(
14363ca95b02SDimitry Andric         (LoadedPtrs.size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);
14373ca95b02SDimitry Andric     Value *GEP = LoadB.CreateGEP(Int8Ty, Ptr, Offset);
14383ca95b02SDimitry Andric     Value *GEPPtr = LoadB.CreateBitCast(GEP, PointerType::getUnqual(Int8PtrTy));
14393ca95b02SDimitry Andric     Value *LoadedValue = LoadB.CreateLoad(Int8PtrTy, GEPPtr);
14403ca95b02SDimitry Andric 
14413ca95b02SDimitry Andric     for (Instruction *LoadedPtr : LoadedPtrs) {
14423ca95b02SDimitry Andric       LoadedPtr->replaceAllUsesWith(LoadedValue);
14433ca95b02SDimitry Andric       LoadedPtr->eraseFromParent();
14443ca95b02SDimitry Andric     }
14453ca95b02SDimitry Andric 
14463ca95b02SDimitry Andric     // Likewise for the type test.
14473ca95b02SDimitry Andric     IRBuilder<> CallB((Preds.size() == 1 && !HasNonCallUses) ? Preds[0] : CI);
14483ca95b02SDimitry Andric     CallInst *TypeTestCall = CallB.CreateCall(TypeTestFunc, {Ptr, TypeIdValue});
14493ca95b02SDimitry Andric 
14503ca95b02SDimitry Andric     for (Instruction *Pred : Preds) {
14513ca95b02SDimitry Andric       Pred->replaceAllUsesWith(TypeTestCall);
14523ca95b02SDimitry Andric       Pred->eraseFromParent();
14533ca95b02SDimitry Andric     }
14543ca95b02SDimitry Andric 
14553ca95b02SDimitry Andric     // We have already erased any extractvalue instructions that refer to the
14563ca95b02SDimitry Andric     // intrinsic call, but the intrinsic may have other non-extractvalue uses
14573ca95b02SDimitry Andric     // (although this is unlikely). In that case, explicitly build a pair and
14583ca95b02SDimitry Andric     // RAUW it.
14593ca95b02SDimitry Andric     if (!CI->use_empty()) {
14603ca95b02SDimitry Andric       Value *Pair = UndefValue::get(CI->getType());
14613ca95b02SDimitry Andric       IRBuilder<> B(CI);
14623ca95b02SDimitry Andric       Pair = B.CreateInsertValue(Pair, LoadedValue, {0});
14633ca95b02SDimitry Andric       Pair = B.CreateInsertValue(Pair, TypeTestCall, {1});
14643ca95b02SDimitry Andric       CI->replaceAllUsesWith(Pair);
14653ca95b02SDimitry Andric     }
14663ca95b02SDimitry Andric 
14673ca95b02SDimitry Andric     // The number of unsafe uses is initially the number of uses.
14683ca95b02SDimitry Andric     auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];
14693ca95b02SDimitry Andric     NumUnsafeUses = DevirtCalls.size();
14703ca95b02SDimitry Andric 
14713ca95b02SDimitry Andric     // If the function pointer has a non-call user, we cannot eliminate the type
14723ca95b02SDimitry Andric     // check, as one of those users may eventually call the pointer. Increment
14733ca95b02SDimitry Andric     // the unsafe use count to make sure it cannot reach zero.
14743ca95b02SDimitry Andric     if (HasNonCallUses)
14753ca95b02SDimitry Andric       ++NumUnsafeUses;
14763ca95b02SDimitry Andric     for (DevirtCallSite Call : DevirtCalls) {
14777a7e6055SDimitry Andric       CallSlots[{TypeId, Call.Offset}].addCallSite(Ptr, Call.CS,
14787a7e6055SDimitry Andric                                                    &NumUnsafeUses);
14793ca95b02SDimitry Andric     }
14803ca95b02SDimitry Andric 
14813ca95b02SDimitry Andric     CI->eraseFromParent();
14823ca95b02SDimitry Andric   }
14833ca95b02SDimitry Andric }
14843ca95b02SDimitry Andric 
importResolution(VTableSlot Slot,VTableSlotInfo & SlotInfo)14857a7e6055SDimitry Andric void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
14867a7e6055SDimitry Andric   const TypeIdSummary *TidSummary =
14877a7e6055SDimitry Andric       ImportSummary->getTypeIdSummary(cast<MDString>(Slot.TypeID)->getString());
14887a7e6055SDimitry Andric   if (!TidSummary)
14897a7e6055SDimitry Andric     return;
14907a7e6055SDimitry Andric   auto ResI = TidSummary->WPDRes.find(Slot.ByteOffset);
14917a7e6055SDimitry Andric   if (ResI == TidSummary->WPDRes.end())
14927a7e6055SDimitry Andric     return;
14937a7e6055SDimitry Andric   const WholeProgramDevirtResolution &Res = ResI->second;
14947a7e6055SDimitry Andric 
14957a7e6055SDimitry Andric   if (Res.TheKind == WholeProgramDevirtResolution::SingleImpl) {
14967a7e6055SDimitry Andric     // The type of the function in the declaration is irrelevant because every
14977a7e6055SDimitry Andric     // call site will cast it to the correct type.
14987a7e6055SDimitry Andric     auto *SingleImpl = M.getOrInsertFunction(
14997a7e6055SDimitry Andric         Res.SingleImplName, Type::getVoidTy(M.getContext()));
15007a7e6055SDimitry Andric 
15017a7e6055SDimitry Andric     // This is the import phase so we should not be exporting anything.
15027a7e6055SDimitry Andric     bool IsExported = false;
15037a7e6055SDimitry Andric     applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);
15047a7e6055SDimitry Andric     assert(!IsExported);
15057a7e6055SDimitry Andric   }
15067a7e6055SDimitry Andric 
15077a7e6055SDimitry Andric   for (auto &CSByConstantArg : SlotInfo.ConstCSInfo) {
15087a7e6055SDimitry Andric     auto I = Res.ResByArg.find(CSByConstantArg.first);
15097a7e6055SDimitry Andric     if (I == Res.ResByArg.end())
15107a7e6055SDimitry Andric       continue;
15117a7e6055SDimitry Andric     auto &ResByArg = I->second;
15127a7e6055SDimitry Andric     // FIXME: We should figure out what to do about the "function name" argument
15137a7e6055SDimitry Andric     // to the apply* functions, as the function names are unavailable during the
15147a7e6055SDimitry Andric     // importing phase. For now we just pass the empty string. This does not
15157a7e6055SDimitry Andric     // impact correctness because the function names are just used for remarks.
15167a7e6055SDimitry Andric     switch (ResByArg.TheKind) {
15177a7e6055SDimitry Andric     case WholeProgramDevirtResolution::ByArg::UniformRetVal:
15187a7e6055SDimitry Andric       applyUniformRetValOpt(CSByConstantArg.second, "", ResByArg.Info);
15197a7e6055SDimitry Andric       break;
15207a7e6055SDimitry Andric     case WholeProgramDevirtResolution::ByArg::UniqueRetVal: {
15217a7e6055SDimitry Andric       Constant *UniqueMemberAddr =
15227a7e6055SDimitry Andric           importGlobal(Slot, CSByConstantArg.first, "unique_member");
15237a7e6055SDimitry Andric       applyUniqueRetValOpt(CSByConstantArg.second, "", ResByArg.Info,
15247a7e6055SDimitry Andric                            UniqueMemberAddr);
15257a7e6055SDimitry Andric       break;
15267a7e6055SDimitry Andric     }
15277a7e6055SDimitry Andric     case WholeProgramDevirtResolution::ByArg::VirtualConstProp: {
15282cab237bSDimitry Andric       Constant *Byte = importConstant(Slot, CSByConstantArg.first, "byte",
15292cab237bSDimitry Andric                                       Int32Ty, ResByArg.Byte);
15302cab237bSDimitry Andric       Constant *Bit = importConstant(Slot, CSByConstantArg.first, "bit", Int8Ty,
15312cab237bSDimitry Andric                                      ResByArg.Bit);
15327a7e6055SDimitry Andric       applyVirtualConstProp(CSByConstantArg.second, "", Byte, Bit);
1533da09e106SDimitry Andric       break;
15347a7e6055SDimitry Andric     }
15357a7e6055SDimitry Andric     default:
15367a7e6055SDimitry Andric       break;
15377a7e6055SDimitry Andric     }
15387a7e6055SDimitry Andric   }
15394ba319b5SDimitry Andric 
15404ba319b5SDimitry Andric   if (Res.TheKind == WholeProgramDevirtResolution::BranchFunnel) {
15414ba319b5SDimitry Andric     auto *JT = M.getOrInsertFunction(getGlobalName(Slot, {}, "branch_funnel"),
15424ba319b5SDimitry Andric                                      Type::getVoidTy(M.getContext()));
15434ba319b5SDimitry Andric     bool IsExported = false;
15444ba319b5SDimitry Andric     applyICallBranchFunnel(SlotInfo, JT, IsExported);
15454ba319b5SDimitry Andric     assert(!IsExported);
15464ba319b5SDimitry Andric   }
15477a7e6055SDimitry Andric }
15487a7e6055SDimitry Andric 
removeRedundantTypeTests()15497a7e6055SDimitry Andric void DevirtModule::removeRedundantTypeTests() {
15507a7e6055SDimitry Andric   auto True = ConstantInt::getTrue(M.getContext());
15517a7e6055SDimitry Andric   for (auto &&U : NumUnsafeUsesForTypeTest) {
15527a7e6055SDimitry Andric     if (U.second == 0) {
15537a7e6055SDimitry Andric       U.first->replaceAllUsesWith(True);
15547a7e6055SDimitry Andric       U.first->eraseFromParent();
15557a7e6055SDimitry Andric     }
15567a7e6055SDimitry Andric   }
15577a7e6055SDimitry Andric }
15587a7e6055SDimitry Andric 
run()15593ca95b02SDimitry Andric bool DevirtModule::run() {
15603ca95b02SDimitry Andric   Function *TypeTestFunc =
15613ca95b02SDimitry Andric       M.getFunction(Intrinsic::getName(Intrinsic::type_test));
15623ca95b02SDimitry Andric   Function *TypeCheckedLoadFunc =
15633ca95b02SDimitry Andric       M.getFunction(Intrinsic::getName(Intrinsic::type_checked_load));
15643ca95b02SDimitry Andric   Function *AssumeFunc = M.getFunction(Intrinsic::getName(Intrinsic::assume));
15653ca95b02SDimitry Andric 
1566*b5893f02SDimitry Andric   // If only some of the modules were split, we cannot correctly handle
1567*b5893f02SDimitry Andric   // code that contains type tests or type checked loads.
1568*b5893f02SDimitry Andric   if ((ExportSummary && ExportSummary->partiallySplitLTOUnits()) ||
1569*b5893f02SDimitry Andric       (ImportSummary && ImportSummary->partiallySplitLTOUnits())) {
1570*b5893f02SDimitry Andric     if ((TypeTestFunc && !TypeTestFunc->use_empty()) ||
1571*b5893f02SDimitry Andric         (TypeCheckedLoadFunc && !TypeCheckedLoadFunc->use_empty()))
1572*b5893f02SDimitry Andric       report_fatal_error("inconsistent LTO Unit splitting with llvm.type.test "
1573*b5893f02SDimitry Andric                          "or llvm.type.checked.load");
1574*b5893f02SDimitry Andric     return false;
1575*b5893f02SDimitry Andric   }
1576*b5893f02SDimitry Andric 
15777a7e6055SDimitry Andric   // Normally if there are no users of the devirtualization intrinsics in the
15787a7e6055SDimitry Andric   // module, this pass has nothing to do. But if we are exporting, we also need
15797a7e6055SDimitry Andric   // to handle any users that appear only in the function summaries.
15807a7e6055SDimitry Andric   if (!ExportSummary &&
15817a7e6055SDimitry Andric       (!TypeTestFunc || TypeTestFunc->use_empty() || !AssumeFunc ||
15823ca95b02SDimitry Andric        AssumeFunc->use_empty()) &&
15833ca95b02SDimitry Andric       (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->use_empty()))
15843ca95b02SDimitry Andric     return false;
15853ca95b02SDimitry Andric 
15863ca95b02SDimitry Andric   if (TypeTestFunc && AssumeFunc)
15873ca95b02SDimitry Andric     scanTypeTestUsers(TypeTestFunc, AssumeFunc);
15883ca95b02SDimitry Andric 
15893ca95b02SDimitry Andric   if (TypeCheckedLoadFunc)
15903ca95b02SDimitry Andric     scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);
15913ca95b02SDimitry Andric 
15927a7e6055SDimitry Andric   if (ImportSummary) {
15937a7e6055SDimitry Andric     for (auto &S : CallSlots)
15947a7e6055SDimitry Andric       importResolution(S.first, S.second);
15957a7e6055SDimitry Andric 
15967a7e6055SDimitry Andric     removeRedundantTypeTests();
15977a7e6055SDimitry Andric 
15987a7e6055SDimitry Andric     // The rest of the code is only necessary when exporting or during regular
15997a7e6055SDimitry Andric     // LTO, so we are done.
16007a7e6055SDimitry Andric     return true;
16017a7e6055SDimitry Andric   }
16027a7e6055SDimitry Andric 
16033ca95b02SDimitry Andric   // Rebuild type metadata into a map for easy lookup.
16043ca95b02SDimitry Andric   std::vector<VTableBits> Bits;
16053ca95b02SDimitry Andric   DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap;
16063ca95b02SDimitry Andric   buildTypeIdentifierMap(Bits, TypeIdMap);
16073ca95b02SDimitry Andric   if (TypeIdMap.empty())
16083ca95b02SDimitry Andric     return true;
16093ca95b02SDimitry Andric 
16107a7e6055SDimitry Andric   // Collect information from summary about which calls to try to devirtualize.
16117a7e6055SDimitry Andric   if (ExportSummary) {
16127a7e6055SDimitry Andric     DenseMap<GlobalValue::GUID, TinyPtrVector<Metadata *>> MetadataByGUID;
16137a7e6055SDimitry Andric     for (auto &P : TypeIdMap) {
16147a7e6055SDimitry Andric       if (auto *TypeId = dyn_cast<MDString>(P.first))
16157a7e6055SDimitry Andric         MetadataByGUID[GlobalValue::getGUID(TypeId->getString())].push_back(
16167a7e6055SDimitry Andric             TypeId);
16177a7e6055SDimitry Andric     }
16187a7e6055SDimitry Andric 
16197a7e6055SDimitry Andric     for (auto &P : *ExportSummary) {
16200f5676f4SDimitry Andric       for (auto &S : P.second.SummaryList) {
16217a7e6055SDimitry Andric         auto *FS = dyn_cast<FunctionSummary>(S.get());
16227a7e6055SDimitry Andric         if (!FS)
16237a7e6055SDimitry Andric           continue;
16247a7e6055SDimitry Andric         // FIXME: Only add live functions.
16257a7e6055SDimitry Andric         for (FunctionSummary::VFuncId VF : FS->type_test_assume_vcalls()) {
16267a7e6055SDimitry Andric           for (Metadata *MD : MetadataByGUID[VF.GUID]) {
16274ba319b5SDimitry Andric             CallSlots[{MD, VF.Offset}]
16284ba319b5SDimitry Andric                 .CSInfo.markSummaryHasTypeTestAssumeUsers();
16297a7e6055SDimitry Andric           }
16307a7e6055SDimitry Andric         }
16317a7e6055SDimitry Andric         for (FunctionSummary::VFuncId VF : FS->type_checked_load_vcalls()) {
16327a7e6055SDimitry Andric           for (Metadata *MD : MetadataByGUID[VF.GUID]) {
16334ba319b5SDimitry Andric             CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
16347a7e6055SDimitry Andric           }
16357a7e6055SDimitry Andric         }
16367a7e6055SDimitry Andric         for (const FunctionSummary::ConstVCall &VC :
16377a7e6055SDimitry Andric              FS->type_test_assume_const_vcalls()) {
16387a7e6055SDimitry Andric           for (Metadata *MD : MetadataByGUID[VC.VFunc.GUID]) {
16397a7e6055SDimitry Andric             CallSlots[{MD, VC.VFunc.Offset}]
16407a7e6055SDimitry Andric                 .ConstCSInfo[VC.Args]
16414ba319b5SDimitry Andric                 .markSummaryHasTypeTestAssumeUsers();
16427a7e6055SDimitry Andric           }
16437a7e6055SDimitry Andric         }
16447a7e6055SDimitry Andric         for (const FunctionSummary::ConstVCall &VC :
16457a7e6055SDimitry Andric              FS->type_checked_load_const_vcalls()) {
16467a7e6055SDimitry Andric           for (Metadata *MD : MetadataByGUID[VC.VFunc.GUID]) {
16477a7e6055SDimitry Andric             CallSlots[{MD, VC.VFunc.Offset}]
16487a7e6055SDimitry Andric                 .ConstCSInfo[VC.Args]
16494ba319b5SDimitry Andric                 .addSummaryTypeCheckedLoadUser(FS);
16507a7e6055SDimitry Andric           }
16517a7e6055SDimitry Andric         }
16527a7e6055SDimitry Andric       }
16537a7e6055SDimitry Andric     }
16547a7e6055SDimitry Andric   }
16557a7e6055SDimitry Andric 
16563ca95b02SDimitry Andric   // For each (type, offset) pair:
16573ca95b02SDimitry Andric   bool DidVirtualConstProp = false;
1658d88c1a5aSDimitry Andric   std::map<std::string, Function*> DevirtTargets;
16593ca95b02SDimitry Andric   for (auto &S : CallSlots) {
16603ca95b02SDimitry Andric     // Search each of the members of the type identifier for the virtual
16613ca95b02SDimitry Andric     // function implementation at offset S.first.ByteOffset, and add to
16623ca95b02SDimitry Andric     // TargetsForSlot.
16633ca95b02SDimitry Andric     std::vector<VirtualCallTarget> TargetsForSlot;
16647a7e6055SDimitry Andric     if (tryFindVirtualCallTargets(TargetsForSlot, TypeIdMap[S.first.TypeID],
16657a7e6055SDimitry Andric                                   S.first.ByteOffset)) {
16667a7e6055SDimitry Andric       WholeProgramDevirtResolution *Res = nullptr;
16677a7e6055SDimitry Andric       if (ExportSummary && isa<MDString>(S.first.TypeID))
16687a7e6055SDimitry Andric         Res = &ExportSummary
16697a7e6055SDimitry Andric                    ->getOrInsertTypeIdSummary(
16707a7e6055SDimitry Andric                        cast<MDString>(S.first.TypeID)->getString())
16717a7e6055SDimitry Andric                    .WPDRes[S.first.ByteOffset];
16723ca95b02SDimitry Andric 
16734ba319b5SDimitry Andric       if (!trySingleImplDevirt(TargetsForSlot, S.second, Res)) {
16744ba319b5SDimitry Andric         DidVirtualConstProp |=
16754ba319b5SDimitry Andric             tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
16764ba319b5SDimitry Andric 
16774ba319b5SDimitry Andric         tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
16784ba319b5SDimitry Andric       }
16793ca95b02SDimitry Andric 
1680d88c1a5aSDimitry Andric       // Collect functions devirtualized at least for one call site for stats.
1681d88c1a5aSDimitry Andric       if (RemarksEnabled)
1682d88c1a5aSDimitry Andric         for (const auto &T : TargetsForSlot)
1683d88c1a5aSDimitry Andric           if (T.WasDevirt)
1684d88c1a5aSDimitry Andric             DevirtTargets[T.Fn->getName()] = T.Fn;
1685d88c1a5aSDimitry Andric     }
1686d88c1a5aSDimitry Andric 
16877a7e6055SDimitry Andric     // CFI-specific: if we are exporting and any llvm.type.checked.load
16887a7e6055SDimitry Andric     // intrinsics were *not* devirtualized, we need to add the resulting
16897a7e6055SDimitry Andric     // llvm.type.test intrinsics to the function summaries so that the
16907a7e6055SDimitry Andric     // LowerTypeTests pass will export them.
16917a7e6055SDimitry Andric     if (ExportSummary && isa<MDString>(S.first.TypeID)) {
16927a7e6055SDimitry Andric       auto GUID =
16937a7e6055SDimitry Andric           GlobalValue::getGUID(cast<MDString>(S.first.TypeID)->getString());
16947a7e6055SDimitry Andric       for (auto FS : S.second.CSInfo.SummaryTypeCheckedLoadUsers)
16957a7e6055SDimitry Andric         FS->addTypeTest(GUID);
16967a7e6055SDimitry Andric       for (auto &CCS : S.second.ConstCSInfo)
16977a7e6055SDimitry Andric         for (auto FS : CCS.second.SummaryTypeCheckedLoadUsers)
16987a7e6055SDimitry Andric           FS->addTypeTest(GUID);
16997a7e6055SDimitry Andric     }
17007a7e6055SDimitry Andric   }
17017a7e6055SDimitry Andric 
1702d88c1a5aSDimitry Andric   if (RemarksEnabled) {
1703d88c1a5aSDimitry Andric     // Generate remarks for each devirtualized function.
1704d88c1a5aSDimitry Andric     for (const auto &DT : DevirtTargets) {
1705d88c1a5aSDimitry Andric       Function *F = DT.second;
17062cab237bSDimitry Andric 
17072cab237bSDimitry Andric       using namespace ore;
17084ba319b5SDimitry Andric       OREGetter(F).emit(OptimizationRemark(DEBUG_TYPE, "Devirtualized", F)
17094ba319b5SDimitry Andric                         << "devirtualized "
17104ba319b5SDimitry Andric                         << NV("FunctionName", F->getName()));
1711d88c1a5aSDimitry Andric     }
17123ca95b02SDimitry Andric   }
17133ca95b02SDimitry Andric 
17147a7e6055SDimitry Andric   removeRedundantTypeTests();
17153ca95b02SDimitry Andric 
17163ca95b02SDimitry Andric   // Rebuild each global we touched as part of virtual constant propagation to
17173ca95b02SDimitry Andric   // include the before and after bytes.
17183ca95b02SDimitry Andric   if (DidVirtualConstProp)
17193ca95b02SDimitry Andric     for (VTableBits &B : Bits)
17203ca95b02SDimitry Andric       rebuildGlobal(B);
17213ca95b02SDimitry Andric 
17223ca95b02SDimitry Andric   return true;
17233ca95b02SDimitry Andric }
1724