#include "llvm/Transforms/IPO/WholeProgramDevirt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/TypeMetadataUtils.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ModuleSummaryIndexYAML.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/GlobPattern.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/FunctionAttrs.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/CallPromotionUtils.h"
#include "llvm/Transforms/Utils/Evaluator.h"
#include <algorithm>
#include <cstddef>
#include <map>
#include <set>
#include <string>
usingnamespacellvm;
usingnamespacewholeprogramdevirt;
#define DEBUG_TYPE …
STATISTIC(NumDevirtTargets, "Number of whole program devirtualization targets");
STATISTIC(NumSingleImpl, "Number of single implementation devirtualizations");
STATISTIC(NumBranchFunnel, "Number of branch funnels");
STATISTIC(NumUniformRetVal, "Number of uniform return value optimizations");
STATISTIC(NumUniqueRetVal, "Number of unique return value optimizations");
STATISTIC(NumVirtConstProp1Bit,
"Number of 1 bit virtual constant propagations");
STATISTIC(NumVirtConstProp, "Number of virtual constant propagations");
static cl::opt<PassSummaryAction> ClSummaryAction(
"wholeprogramdevirt-summary-action",
cl::desc("What to do with the summary when running this pass"),
cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"),
clEnumValN(PassSummaryAction::Import, "import",
"Import typeid resolutions from summary and globals"),
clEnumValN(PassSummaryAction::Export, "export",
"Export typeid resolutions to summary and globals")),
cl::Hidden);
static cl::opt<std::string> ClReadSummary(
"wholeprogramdevirt-read-summary",
cl::desc(
"Read summary from given bitcode or YAML file before running pass"),
cl::Hidden);
static cl::opt<std::string> ClWriteSummary(
"wholeprogramdevirt-write-summary",
cl::desc("Write summary to given bitcode or YAML file after running pass. "
"Output file format is deduced from extension: *.bc means writing "
"bitcode, otherwise YAML"),
cl::Hidden);
static cl::opt<unsigned>
ClThreshold("wholeprogramdevirt-branch-funnel-threshold", cl::Hidden,
cl::init(10),
cl::desc("Maximum number of call targets per "
"call site to enable branch funnels"));
static cl::opt<bool>
PrintSummaryDevirt("wholeprogramdevirt-print-index-based", cl::Hidden,
cl::desc("Print index-based devirtualization messages"));
static cl::opt<bool>
WholeProgramVisibility("whole-program-visibility", cl::Hidden,
cl::desc("Enable whole program visibility"));
static cl::opt<bool> DisableWholeProgramVisibility(
"disable-whole-program-visibility", cl::Hidden,
cl::desc("Disable whole program visibility (overrides enabling options)"));
static cl::list<std::string>
SkipFunctionNames("wholeprogramdevirt-skip",
cl::desc("Prevent function(s) from being devirtualized"),
cl::Hidden, cl::CommaSeparated);
enum WPDCheckMode { … };
static cl::opt<WPDCheckMode> DevirtCheckMode(
"wholeprogramdevirt-check", cl::Hidden,
cl::desc("Type of checking for incorrect devirtualizations"),
cl::values(clEnumValN(WPDCheckMode::None, "none", "No checking"),
clEnumValN(WPDCheckMode::Trap, "trap", "Trap when incorrect"),
clEnumValN(WPDCheckMode::Fallback, "fallback",
"Fallback to indirect when incorrect")));
namespace {
struct PatternList { … };
}
uint64_t
wholeprogramdevirt::findLowestOffset(ArrayRef<VirtualCallTarget> Targets,
bool IsAfter, uint64_t Size) { … }
void wholeprogramdevirt::setBeforeReturnValues(
MutableArrayRef<VirtualCallTarget> Targets, uint64_t AllocBefore,
unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) { … }
void wholeprogramdevirt::setAfterReturnValues(
MutableArrayRef<VirtualCallTarget> Targets, uint64_t AllocAfter,
unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) { … }
VirtualCallTarget::VirtualCallTarget(GlobalValue *Fn, const TypeMemberInfo *TM)
: … { … }
namespace {
struct VTableSlot { … };
}
namespace llvm {
template <> struct DenseMapInfo<VTableSlot> { … };
template <> struct DenseMapInfo<VTableSlotSummary> { … };
}
static bool mustBeUnreachableFunction(ValueInfo TheFnVI) { … }
namespace {
struct VirtualCallSite { … };
struct CallSiteInfo { … };
struct VTableSlotInfo { … };
CallSiteInfo &VTableSlotInfo::findCallSiteInfo(CallBase &CB) { … }
void VTableSlotInfo::addCallSite(Value *VTable, CallBase &CB,
unsigned *NumUnsafeUses) { … }
struct DevirtModule { … };
struct DevirtIndex { … };
}
PreservedAnalyses WholeProgramDevirtPass::run(Module &M,
ModuleAnalysisManager &AM) { … }
bool llvm::hasWholeProgramVisibility(bool WholeProgramVisibilityEnabledInLTO) { … }
static bool
typeIDVisibleToRegularObj(StringRef TypeID,
function_ref<bool(StringRef)> IsVisibleToRegularObj) { … }
static bool
skipUpdateDueToValidation(GlobalVariable &GV,
function_ref<bool(StringRef)> IsVisibleToRegularObj) { … }
void llvm::updateVCallVisibilityInModule(
Module &M, bool WholeProgramVisibilityEnabledInLTO,
const DenseSet<GlobalValue::GUID> &DynamicExportSymbols,
bool ValidateAllVtablesHaveTypeInfos,
function_ref<bool(StringRef)> IsVisibleToRegularObj) { … }
void llvm::updatePublicTypeTestCalls(Module &M,
bool WholeProgramVisibilityEnabledInLTO) { … }
void llvm::getVisibleToRegularObjVtableGUIDs(
ModuleSummaryIndex &Index,
DenseSet<GlobalValue::GUID> &VisibleToRegularObjSymbols,
function_ref<bool(StringRef)> IsVisibleToRegularObj) { … }
void llvm::updateVCallVisibilityInIndex(
ModuleSummaryIndex &Index, bool WholeProgramVisibilityEnabledInLTO,
const DenseSet<GlobalValue::GUID> &DynamicExportSymbols,
const DenseSet<GlobalValue::GUID> &VisibleToRegularObjSymbols) { … }
void llvm::runWholeProgramDevirtOnIndex(
ModuleSummaryIndex &Summary, std::set<GlobalValue::GUID> &ExportedGUIDs,
std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) { … }
void llvm::updateIndexWPDForExports(
ModuleSummaryIndex &Summary,
function_ref<bool(StringRef, ValueInfo)> isExported,
std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) { … }
static Error checkCombinedSummaryForTesting(ModuleSummaryIndex *Summary) { … }
bool DevirtModule::runForTesting(
Module &M, function_ref<AAResults &(Function &)> AARGetter,
function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter,
function_ref<DominatorTree &(Function &)> LookupDomTree) { … }
void DevirtModule::buildTypeIdentifierMap(
std::vector<VTableBits> &Bits,
DenseMap<Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) { … }
bool DevirtModule::tryFindVirtualCallTargets(
std::vector<VirtualCallTarget> &TargetsForSlot,
const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset,
ModuleSummaryIndex *ExportSummary) { … }
bool DevirtIndex::tryFindVirtualCallTargets(
std::vector<ValueInfo> &TargetsForSlot,
const TypeIdCompatibleVtableInfo TIdInfo, uint64_t ByteOffset) { … }
void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
Constant *TheFn, bool &IsExported) { … }
static bool AddCalls(VTableSlotInfo &SlotInfo, const ValueInfo &Callee) { … }
bool DevirtModule::trySingleImplDevirt(
ModuleSummaryIndex *ExportSummary,
MutableArrayRef<VirtualCallTarget> TargetsForSlot, VTableSlotInfo &SlotInfo,
WholeProgramDevirtResolution *Res) { … }
bool DevirtIndex::trySingleImplDevirt(MutableArrayRef<ValueInfo> TargetsForSlot,
VTableSlotSummary &SlotSummary,
VTableSlotInfo &SlotInfo,
WholeProgramDevirtResolution *Res,
std::set<ValueInfo> &DevirtTargets) { … }
void DevirtModule::tryICallBranchFunnel(
MutableArrayRef<VirtualCallTarget> TargetsForSlot, VTableSlotInfo &SlotInfo,
WholeProgramDevirtResolution *Res, VTableSlot Slot) { … }
void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
Constant *JT, bool &IsExported) { … }
bool DevirtModule::tryEvaluateFunctionsWithArgs(
MutableArrayRef<VirtualCallTarget> TargetsForSlot,
ArrayRef<uint64_t> Args) { … }
void DevirtModule::applyUniformRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,
uint64_t TheRetVal) { … }
bool DevirtModule::tryUniformRetValOpt(
MutableArrayRef<VirtualCallTarget> TargetsForSlot, CallSiteInfo &CSInfo,
WholeProgramDevirtResolution::ByArg *Res) { … }
std::string DevirtModule::getGlobalName(VTableSlot Slot,
ArrayRef<uint64_t> Args,
StringRef Name) { … }
bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() { … }
void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
StringRef Name, Constant *C) { … }
void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
StringRef Name, uint32_t Const,
uint32_t &Storage) { … }
Constant *DevirtModule::importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
StringRef Name) { … }
Constant *DevirtModule::importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
StringRef Name, IntegerType *IntTy,
uint32_t Storage) { … }
void DevirtModule::applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,
bool IsOne,
Constant *UniqueMemberAddr) { … }
Constant *DevirtModule::getMemberAddr(const TypeMemberInfo *M) { … }
bool DevirtModule::tryUniqueRetValOpt(
unsigned BitWidth, MutableArrayRef<VirtualCallTarget> TargetsForSlot,
CallSiteInfo &CSInfo, WholeProgramDevirtResolution::ByArg *Res,
VTableSlot Slot, ArrayRef<uint64_t> Args) { … }
void DevirtModule::applyVirtualConstProp(CallSiteInfo &CSInfo, StringRef FnName,
Constant *Byte, Constant *Bit) { … }
bool DevirtModule::tryVirtualConstProp(
MutableArrayRef<VirtualCallTarget> TargetsForSlot, VTableSlotInfo &SlotInfo,
WholeProgramDevirtResolution *Res, VTableSlot Slot) { … }
void DevirtModule::rebuildGlobal(VTableBits &B) { … }
bool DevirtModule::areRemarksEnabled() { … }
void DevirtModule::scanTypeTestUsers(
Function *TypeTestFunc,
DenseMap<Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) { … }
void DevirtModule::scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc) { … }
void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) { … }
void DevirtModule::removeRedundantTypeTests() { … }
ValueInfo
DevirtModule::lookUpFunctionValueInfo(Function *TheFn,
ModuleSummaryIndex *ExportSummary) { … }
bool DevirtModule::mustBeUnreachableFunction(
Function *const F, ModuleSummaryIndex *ExportSummary) { … }
bool DevirtModule::run() { … }
void DevirtIndex::run() { … }