mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 02:33:06 +01:00
Revert "[ThinLTO] Add summary entries for index-based WPD"
Mistaken commit of something still under review! This reverts commit r351453. llvm-svn: 351455
This commit is contained in:
parent
e47bb6d8cf
commit
e8cb930dbb
@ -264,25 +264,10 @@ enum GlobalValueSummarySymtabCodes {
|
||||
// Index-wide flags
|
||||
FS_FLAGS = 20,
|
||||
// Maps type identifier to summary information for that type identifier.
|
||||
// Produced by the thin link (only lives in combined index).
|
||||
// TYPE_ID: [typeid, kind, bitwidth, align, size, bitmask, inlinebits,
|
||||
// n x (typeid, kind, name, numrba,
|
||||
// numrba x (numarg, numarg x arg, kind, info, byte, bit))]
|
||||
FS_TYPE_ID = 21,
|
||||
// Maps type identifier to summary information for that type identifier
|
||||
// computed from type metadata: the valueid of each vtable definition
|
||||
// decorated with a type metadata for that identifier, and the offset from
|
||||
// the corresponding type metadata.
|
||||
// Exists in the per-module summary to provide information to thin link
|
||||
// for index-based whole program devirtualization.
|
||||
// TYPE_ID_METADATA: [typeid, n x (valueid, offset)]
|
||||
FS_TYPE_ID_METADATA = 22,
|
||||
// Summarizes vtable definition for use in index-based whole program
|
||||
// devirtualization during the thin link.
|
||||
// PERMODULE_VTABLE_GLOBALVAR_INIT_REFS: [valueid, flags, varflags,
|
||||
// numrefs, numrefs x valueid,
|
||||
// n x (valueid, offset)]
|
||||
FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS = 23,
|
||||
};
|
||||
|
||||
enum MetadataCodes {
|
||||
|
@ -666,12 +666,6 @@ template <> struct DenseMapInfo<FunctionSummary::ConstVCall> {
|
||||
}
|
||||
};
|
||||
|
||||
/// Pair of function ValueInfo and offset within a vtable definition
|
||||
/// initializer array.
|
||||
using VirtFuncOffsetPair = std::pair<ValueInfo, uint64_t>;
|
||||
/// List of functions referenced by a particular vtable definition.
|
||||
using VTableFuncList = std::vector<VirtFuncOffsetPair>;
|
||||
|
||||
/// Global variable summary information to aid decisions and
|
||||
/// implementation of importing.
|
||||
///
|
||||
@ -679,11 +673,6 @@ using VTableFuncList = std::vector<VirtFuncOffsetPair>;
|
||||
/// modified during the program run or not. This affects ThinLTO
|
||||
/// internalization
|
||||
class GlobalVarSummary : public GlobalValueSummary {
|
||||
private:
|
||||
/// For vtable definitions this holds the list of functions and
|
||||
/// their corresponding offsets within the initializer array.
|
||||
std::unique_ptr<VTableFuncList> VTableFuncs;
|
||||
|
||||
public:
|
||||
struct GVarFlags {
|
||||
GVarFlags(bool ReadOnly = false) : ReadOnly(ReadOnly) {}
|
||||
@ -704,17 +693,6 @@ public:
|
||||
GVarFlags varflags() const { return VarFlags; }
|
||||
void setReadOnly(bool RO) { VarFlags.ReadOnly = RO; }
|
||||
bool isReadOnly() const { return VarFlags.ReadOnly; }
|
||||
|
||||
void setVTableFuncs(VTableFuncList Funcs) {
|
||||
assert(!VTableFuncs);
|
||||
VTableFuncs = llvm::make_unique<VTableFuncList>(std::move(Funcs));
|
||||
}
|
||||
|
||||
ArrayRef<VirtFuncOffsetPair> vTableFuncs() const {
|
||||
if (VTableFuncs)
|
||||
return *VTableFuncs;
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
struct TypeTestResolution {
|
||||
@ -813,14 +791,6 @@ using GVSummaryMapTy = DenseMap<GlobalValue::GUID, GlobalValueSummary *>;
|
||||
using TypeIdSummaryMapTy =
|
||||
std::multimap<GlobalValue::GUID, std::pair<std::string, TypeIdSummary>>;
|
||||
|
||||
/// Holds information about vtable definitions decorated with type metadata:
|
||||
/// the vtable definition value and its offset in the corresponding type
|
||||
/// metadata.
|
||||
using TypeIdOffsetGVPair = std::pair<uint64_t, ValueInfo>;
|
||||
/// List of vtable definitions decorated by the same type id metadata,
|
||||
/// and their corresponding offsets in the type id metadata.
|
||||
using TypeIdGVInfo = std::vector<TypeIdOffsetGVPair>;
|
||||
|
||||
/// Class to hold module path string table and global value map,
|
||||
/// and encapsulate methods for operating on them.
|
||||
class ModuleSummaryIndex {
|
||||
@ -833,14 +803,9 @@ private:
|
||||
ModulePathStringTableTy ModulePathStringTable;
|
||||
|
||||
/// Mapping from type identifier GUIDs to type identifier and its summary
|
||||
/// information. Produced by thin link.
|
||||
/// information.
|
||||
TypeIdSummaryMapTy TypeIdMap;
|
||||
|
||||
/// Mapping from type identifier to information about vtables decorated
|
||||
/// with that type identifier's metadata. Produced by per module summary
|
||||
/// analysis and consumed by thin link.
|
||||
std::map<std::string, TypeIdGVInfo> TypeIdMetadataMap;
|
||||
|
||||
/// Mapping from original ID to GUID. If original ID can map to multiple
|
||||
/// GUIDs, it will be mapped to 0.
|
||||
std::map<GlobalValue::GUID, GlobalValue::GUID> OidGuidMap;
|
||||
@ -1198,27 +1163,6 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::map<std::string, TypeIdGVInfo> &typeIdMetadataMap() const {
|
||||
return TypeIdMetadataMap;
|
||||
}
|
||||
|
||||
/// Return an existing or new TypeIdMetadataMap entry for \p TypeId.
|
||||
/// This accessor can mutate the map and therefore should not be used in
|
||||
/// the ThinLTO backends.
|
||||
TypeIdGVInfo &getOrInsertTypeIdMetadataSummary(StringRef TypeId) {
|
||||
return TypeIdMetadataMap[TypeId];
|
||||
}
|
||||
|
||||
/// For the given \p TypeId, this returns either a pointer to the
|
||||
/// TypeIdMetadataMap entry (if present in the summary map) or null
|
||||
/// (if not present). This may be used when importing.
|
||||
const TypeIdGVInfo *getTypeIdMetadataSummary(StringRef TypeId) const {
|
||||
auto I = TypeIdMetadataMap.find(TypeId);
|
||||
if (I == TypeIdMetadataMap.end())
|
||||
return nullptr;
|
||||
return &I->second;
|
||||
}
|
||||
|
||||
/// Collect for the given module the list of functions it defines
|
||||
/// (GUID -> Summary).
|
||||
void collectDefinedFunctionsForModule(StringRef ModulePath,
|
||||
|
@ -406,98 +406,9 @@ static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M,
|
||||
Index.addGlobalValueSummary(F, std::move(FuncSummary));
|
||||
}
|
||||
|
||||
/// Find function pointers referenced within the given vtable initializer
|
||||
/// (or subset of an initializer) \p I. The starting offset of \p I within
|
||||
/// the vtable initializer is \p StartingOffset. Any discovered function
|
||||
/// pointers are added to \p VTableFuncs along with their cumulative offset
|
||||
/// within the initializer.
|
||||
static void findFuncPointers(const Constant *I, uint64_t StartingOffset,
|
||||
const Module &M, ModuleSummaryIndex &Index,
|
||||
VTableFuncList &VTableFuncs) {
|
||||
// First check if this is a function pointer.
|
||||
if (I->getType()->isPointerTy()) {
|
||||
auto Fn = dyn_cast<Function>(I->stripPointerCasts());
|
||||
// We can disregard __cxa_pure_virtual as a possible call target, as
|
||||
// calls to pure virtuals are UB.
|
||||
if (Fn && Fn->getName() != "__cxa_pure_virtual")
|
||||
VTableFuncs.push_back(
|
||||
std::make_pair(Index.getOrInsertValueInfo(Fn), StartingOffset));
|
||||
return;
|
||||
}
|
||||
|
||||
// Walk through the elements in the constant struct or array and recursively
|
||||
// look for virtual function pointers.
|
||||
const DataLayout &DL = M.getDataLayout();
|
||||
if (auto *C = dyn_cast<ConstantStruct>(I)) {
|
||||
StructType *STy = dyn_cast<StructType>(C->getType());
|
||||
assert(STy);
|
||||
const StructLayout *SL = DL.getStructLayout(C->getType());
|
||||
|
||||
for (StructType::element_iterator EB = STy->element_begin(), EI = EB,
|
||||
EE = STy->element_end();
|
||||
EI != EE; ++EI) {
|
||||
auto Offset = SL->getElementOffset(EI - EB);
|
||||
unsigned Op = SL->getElementContainingOffset(Offset);
|
||||
findFuncPointers(cast<Constant>(I->getOperand(Op)),
|
||||
StartingOffset + Offset, M, Index, VTableFuncs);
|
||||
}
|
||||
} else if (auto *C = dyn_cast<ConstantArray>(I)) {
|
||||
ArrayType *ATy = C->getType();
|
||||
Type *EltTy = ATy->getElementType();
|
||||
uint64_t EltSize = DL.getTypeAllocSize(EltTy);
|
||||
for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {
|
||||
findFuncPointers(cast<Constant>(I->getOperand(i)),
|
||||
StartingOffset + i * EltSize, M, Index, VTableFuncs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Identify the function pointers referenced by vtable definition \p V.
|
||||
static void computeVTableFuncs(ModuleSummaryIndex &Index,
|
||||
const GlobalVariable &V, const Module &M,
|
||||
VTableFuncList &VTableFuncs) {
|
||||
if (!V.isConstant())
|
||||
return;
|
||||
|
||||
findFuncPointers(V.getInitializer(), /*StartingOffset=*/0, M, Index,
|
||||
VTableFuncs);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Validate that the VTableFuncs list is ordered by offset.
|
||||
uint64_t PrevOffset = 0;
|
||||
for (auto &P : VTableFuncs) {
|
||||
// The findVFuncPointers traversal should have encountered the
|
||||
// functions in offset order. We need to use ">=" since PrevOffset
|
||||
// starts at 0.
|
||||
assert(P.second >= PrevOffset);
|
||||
PrevOffset = P.second;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Record vtable definition \p V for each type metadata it references.
|
||||
static void recordTypeIdMetadataReferences(ModuleSummaryIndex &Index,
|
||||
const GlobalVariable &V,
|
||||
SmallVectorImpl<MDNode *> &Types) {
|
||||
for (MDNode *Type : Types) {
|
||||
auto TypeID = Type->getOperand(1).get();
|
||||
|
||||
uint64_t Offset =
|
||||
cast<ConstantInt>(
|
||||
cast<ConstantAsMetadata>(Type->getOperand(0))->getValue())
|
||||
->getZExtValue();
|
||||
|
||||
if (auto *TypeId = dyn_cast<MDString>(TypeID))
|
||||
Index.getOrInsertTypeIdMetadataSummary(TypeId->getString())
|
||||
.push_back({Offset, Index.getOrInsertValueInfo(&V)});
|
||||
}
|
||||
}
|
||||
|
||||
static void computeVariableSummary(ModuleSummaryIndex &Index,
|
||||
const GlobalVariable &V,
|
||||
DenseSet<GlobalValue::GUID> &CantBePromoted,
|
||||
const Module &M,
|
||||
SmallVectorImpl<MDNode *> &Types) {
|
||||
static void
|
||||
computeVariableSummary(ModuleSummaryIndex &Index, const GlobalVariable &V,
|
||||
DenseSet<GlobalValue::GUID> &CantBePromoted) {
|
||||
SetVector<ValueInfo> RefEdges;
|
||||
SmallPtrSet<const User *, 8> Visited;
|
||||
bool HasBlockAddress = findRefEdges(Index, &V, RefEdges, Visited);
|
||||
@ -505,21 +416,6 @@ static void computeVariableSummary(ModuleSummaryIndex &Index,
|
||||
GlobalValueSummary::GVFlags Flags(V.getLinkage(), NonRenamableLocal,
|
||||
/* Live = */ false, V.isDSOLocal());
|
||||
|
||||
VTableFuncList VTableFuncs;
|
||||
// If splitting is not enabled, then we compute the summary information
|
||||
// necessary for index-based whole program devirtualization.
|
||||
if (!Index.enableSplitLTOUnit()) {
|
||||
Types.clear();
|
||||
V.getMetadata(LLVMContext::MD_type, Types);
|
||||
if (!Types.empty()) {
|
||||
// Identify the function pointers referenced by this vtable definition.
|
||||
computeVTableFuncs(Index, V, M, VTableFuncs);
|
||||
|
||||
// Record this vtable definition for each type metadata it references.
|
||||
recordTypeIdMetadataReferences(Index, V, Types);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't mark variables we won't be able to internalize as read-only.
|
||||
GlobalVarSummary::GVarFlags VarFlags(
|
||||
!V.hasComdat() && !V.hasAppendingLinkage() && !V.isInterposable() &&
|
||||
@ -530,8 +426,6 @@ static void computeVariableSummary(ModuleSummaryIndex &Index,
|
||||
CantBePromoted.insert(V.getGUID());
|
||||
if (HasBlockAddress)
|
||||
GVarSummary->setNotEligibleToImport();
|
||||
if (!VTableFuncs.empty())
|
||||
GVarSummary->setVTableFuncs(VTableFuncs);
|
||||
Index.addGlobalValueSummary(V, std::move(GVarSummary));
|
||||
}
|
||||
|
||||
@ -674,11 +568,10 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(
|
||||
|
||||
// Compute summaries for all variables defined in module, and save in the
|
||||
// index.
|
||||
SmallVector<MDNode *, 2> Types;
|
||||
for (const GlobalVariable &G : M.globals()) {
|
||||
if (G.isDeclaration())
|
||||
continue;
|
||||
computeVariableSummary(Index, G, CantBePromoted, M, Types);
|
||||
computeVariableSummary(Index, G, CantBePromoted);
|
||||
}
|
||||
|
||||
// Compute summaries for all aliases defined in module, and save in the
|
||||
|
@ -749,8 +749,6 @@ lltok::Kind LLLexer::LexIdentifier() {
|
||||
KEYWORD(critical);
|
||||
KEYWORD(relbf);
|
||||
KEYWORD(variable);
|
||||
KEYWORD(vTableFuncs);
|
||||
KEYWORD(virtFunc);
|
||||
KEYWORD(aliasee);
|
||||
KEYWORD(refs);
|
||||
KEYWORD(typeIdInfo);
|
||||
@ -763,7 +761,6 @@ lltok::Kind LLLexer::LexIdentifier() {
|
||||
KEYWORD(offset);
|
||||
KEYWORD(args);
|
||||
KEYWORD(typeid);
|
||||
KEYWORD(typeidMetadata);
|
||||
KEYWORD(summary);
|
||||
KEYWORD(typeTestRes);
|
||||
KEYWORD(kind);
|
||||
|
@ -822,9 +822,6 @@ bool LLParser::ParseSummaryEntry() {
|
||||
case lltok::kw_typeid:
|
||||
return ParseTypeIdEntry(SummaryID);
|
||||
break;
|
||||
case lltok::kw_typeidMetadata:
|
||||
return ParseTypeIdMetadataEntry(SummaryID);
|
||||
break;
|
||||
default:
|
||||
return Error(Lex.getLoc(), "unexpected summary kind");
|
||||
}
|
||||
@ -7260,90 +7257,6 @@ bool LLParser::ParseTypeIdSummary(TypeIdSummary &TIS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static ValueInfo EmptyVI =
|
||||
ValueInfo(false, (GlobalValueSummaryMapTy::value_type *)-8);
|
||||
|
||||
/// TypeIdMetadataEntry
|
||||
/// ::= 'typeidMetadata' ':' '(' 'name' ':' STRINGCONSTANT ',' TypeIdGVInfo
|
||||
/// ')'
|
||||
bool LLParser::ParseTypeIdMetadataEntry(unsigned ID) {
|
||||
assert(Lex.getKind() == lltok::kw_typeidMetadata);
|
||||
Lex.Lex();
|
||||
|
||||
std::string Name;
|
||||
if (ParseToken(lltok::colon, "expected ':' here") ||
|
||||
ParseToken(lltok::lparen, "expected '(' here") ||
|
||||
ParseToken(lltok::kw_name, "expected 'name' here") ||
|
||||
ParseToken(lltok::colon, "expected ':' here") ||
|
||||
ParseStringConstant(Name))
|
||||
return true;
|
||||
|
||||
TypeIdGVInfo &TI = Index->getOrInsertTypeIdMetadataSummary(Name);
|
||||
if (ParseToken(lltok::comma, "expected ',' here") ||
|
||||
ParseToken(lltok::kw_summary, "expected 'summary' here") ||
|
||||
ParseToken(lltok::colon, "expected ':' here") ||
|
||||
ParseToken(lltok::lparen, "expected '(' here"))
|
||||
return true;
|
||||
|
||||
IdToIndexMapType IdToIndexMap;
|
||||
// Parse each call edge
|
||||
do {
|
||||
uint64_t Offset;
|
||||
if (ParseToken(lltok::lparen, "expected '(' here") ||
|
||||
ParseToken(lltok::kw_offset, "expected 'offset' here") ||
|
||||
ParseToken(lltok::colon, "expected ':' here") || ParseUInt64(Offset) ||
|
||||
ParseToken(lltok::comma, "expected ',' here"))
|
||||
return true;
|
||||
|
||||
LocTy Loc = Lex.getLoc();
|
||||
unsigned GVId;
|
||||
ValueInfo VI;
|
||||
if (ParseGVReference(VI, GVId))
|
||||
return true;
|
||||
|
||||
// Keep track of the TypeIdGVInfo array index needing a forward reference.
|
||||
// We will save the location of the ValueInfo needing an update, but
|
||||
// can only do so once the std::vector is finalized.
|
||||
if (VI == EmptyVI)
|
||||
IdToIndexMap[GVId].push_back(std::make_pair(TI.size(), Loc));
|
||||
TI.push_back({Offset, VI});
|
||||
|
||||
if (ParseToken(lltok::rparen, "expected ')' in call"))
|
||||
return true;
|
||||
} while (EatIfPresent(lltok::comma));
|
||||
|
||||
// Now that the TI vector is finalized, it is safe to save the locations
|
||||
// of any forward GV references that need updating later.
|
||||
for (auto I : IdToIndexMap) {
|
||||
for (auto P : I.second) {
|
||||
assert(TI[P.first].second == EmptyVI &&
|
||||
"Forward referenced ValueInfo expected to be empty");
|
||||
auto FwdRef = ForwardRefValueInfos.insert(std::make_pair(
|
||||
I.first, std::vector<std::pair<ValueInfo *, LocTy>>()));
|
||||
FwdRef.first->second.push_back(
|
||||
std::make_pair(&TI[P.first].second, P.second));
|
||||
}
|
||||
}
|
||||
|
||||
if (ParseToken(lltok::rparen, "expected ')' here") ||
|
||||
ParseToken(lltok::rparen, "expected ')' here"))
|
||||
return true;
|
||||
|
||||
// Check if this ID was forward referenced, and if so, update the
|
||||
// corresponding GUIDs.
|
||||
auto FwdRefTIDs = ForwardRefTypeIds.find(ID);
|
||||
if (FwdRefTIDs != ForwardRefTypeIds.end()) {
|
||||
for (auto TIDRef : FwdRefTIDs->second) {
|
||||
assert(!*TIDRef.first &&
|
||||
"Forward referenced type id GUID expected to be 0");
|
||||
*TIDRef.first = GlobalValue::getGUID(Name);
|
||||
}
|
||||
ForwardRefTypeIds.erase(FwdRefTIDs);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// TypeTestResolution
|
||||
/// ::= 'typeTestRes' ':' '(' 'kind' ':'
|
||||
/// ( 'unsat' | 'byteArray' | 'inline' | 'single' | 'allOnes' ) ','
|
||||
@ -7851,7 +7764,6 @@ bool LLParser::ParseVariableSummary(std::string Name, GlobalValue::GUID GUID,
|
||||
/*Live=*/false, /*IsLocal=*/false);
|
||||
GlobalVarSummary::GVarFlags GVarFlags(/*ReadOnly*/ false);
|
||||
std::vector<ValueInfo> Refs;
|
||||
VTableFuncList VTableFuncs;
|
||||
if (ParseToken(lltok::colon, "expected ':' here") ||
|
||||
ParseToken(lltok::lparen, "expected '(' here") ||
|
||||
ParseModuleReference(ModulePath) ||
|
||||
@ -7860,20 +7772,10 @@ bool LLParser::ParseVariableSummary(std::string Name, GlobalValue::GUID GUID,
|
||||
ParseGVarFlags(GVarFlags))
|
||||
return true;
|
||||
|
||||
// Parse optional fields
|
||||
while (EatIfPresent(lltok::comma)) {
|
||||
switch (Lex.getKind()) {
|
||||
case lltok::kw_vTableFuncs:
|
||||
if (ParseOptionalVTableFuncs(VTableFuncs))
|
||||
return true;
|
||||
break;
|
||||
case lltok::kw_refs:
|
||||
if (ParseOptionalRefs(Refs))
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
return Error(Lex.getLoc(), "expected optional variable summary field");
|
||||
}
|
||||
// Parse optional refs field
|
||||
if (EatIfPresent(lltok::comma)) {
|
||||
if (ParseOptionalRefs(Refs))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ParseToken(lltok::rparen, "expected ')' here"))
|
||||
@ -7883,7 +7785,6 @@ bool LLParser::ParseVariableSummary(std::string Name, GlobalValue::GUID GUID,
|
||||
llvm::make_unique<GlobalVarSummary>(GVFlags, GVarFlags, std::move(Refs));
|
||||
|
||||
GS->setModulePath(ModulePath);
|
||||
GS->setVTableFuncs(std::move(VTableFuncs));
|
||||
|
||||
AddGlobalValueToIndex(Name, GUID, (GlobalValue::LinkageTypes)GVFlags.Linkage,
|
||||
ID, std::move(GS));
|
||||
@ -8101,67 +8002,6 @@ bool LLParser::ParseHotness(CalleeInfo::HotnessType &Hotness) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// OptionalVTableFuncs
|
||||
/// := 'vTableFuncs' ':' '(' VTableFunc [',' VTableFunc]* ')'
|
||||
/// VTableFunc ::= '(' 'virtFunc' ':' GVReference ',' 'offset' ':' UInt64 ')'
|
||||
bool LLParser::ParseOptionalVTableFuncs(VTableFuncList &VTableFuncs) {
|
||||
assert(Lex.getKind() == lltok::kw_vTableFuncs);
|
||||
Lex.Lex();
|
||||
|
||||
if (ParseToken(lltok::colon, "expected ':' in vTableFuncs") |
|
||||
ParseToken(lltok::lparen, "expected '(' in vTableFuncs"))
|
||||
return true;
|
||||
|
||||
IdToIndexMapType IdToIndexMap;
|
||||
// Parse each virtual function pair
|
||||
do {
|
||||
ValueInfo VI;
|
||||
if (ParseToken(lltok::lparen, "expected '(' in vTableFunc") ||
|
||||
ParseToken(lltok::kw_virtFunc, "expected 'callee' in vTableFunc") ||
|
||||
ParseToken(lltok::colon, "expected ':'"))
|
||||
return true;
|
||||
|
||||
LocTy Loc = Lex.getLoc();
|
||||
unsigned GVId;
|
||||
if (ParseGVReference(VI, GVId))
|
||||
return true;
|
||||
|
||||
uint64_t Offset;
|
||||
if (ParseToken(lltok::comma, "expected comma") ||
|
||||
ParseToken(lltok::kw_offset, "expected offset") ||
|
||||
ParseToken(lltok::colon, "expected ':'") || ParseUInt64(Offset))
|
||||
return true;
|
||||
|
||||
// Keep track of the VTableFuncs array index needing a forward reference.
|
||||
// We will save the location of the ValueInfo needing an update, but
|
||||
// can only do so once the std::vector is finalized.
|
||||
if (VI == EmptyVI)
|
||||
IdToIndexMap[GVId].push_back(std::make_pair(VTableFuncs.size(), Loc));
|
||||
VTableFuncs.push_back(std::make_pair(VI, Offset));
|
||||
|
||||
if (ParseToken(lltok::rparen, "expected ')' in vTableFunc"))
|
||||
return true;
|
||||
} while (EatIfPresent(lltok::comma));
|
||||
|
||||
// Now that the VTableFuncs vector is finalized, it is safe to save the
|
||||
// locations of any forward GV references that need updating later.
|
||||
for (auto I : IdToIndexMap) {
|
||||
for (auto P : I.second) {
|
||||
assert(VTableFuncs[P.first].first == EmptyVI &&
|
||||
"Forward referenced ValueInfo expected to be empty");
|
||||
auto FwdRef = ForwardRefValueInfos.insert(std::make_pair(
|
||||
I.first, std::vector<std::pair<ValueInfo *, LocTy>>()));
|
||||
FwdRef.first->second.push_back(
|
||||
std::make_pair(&VTableFuncs[P.first].first, P.second));
|
||||
}
|
||||
}
|
||||
|
||||
if (ParseToken(lltok::rparen, "expected ')' in vTableFuncs"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// OptionalRefs
|
||||
/// := 'refs' ':' '(' GVReference [',' GVReference]* ')'
|
||||
bool LLParser::ParseOptionalRefs(std::vector<ValueInfo> &Refs) {
|
||||
|
@ -369,11 +369,9 @@ namespace llvm {
|
||||
IdToIndexMapType &IdToIndexMap, unsigned Index);
|
||||
bool ParseVFuncId(FunctionSummary::VFuncId &VFuncId,
|
||||
IdToIndexMapType &IdToIndexMap, unsigned Index);
|
||||
bool ParseOptionalVTableFuncs(VTableFuncList &VTableFuncs);
|
||||
bool ParseOptionalRefs(std::vector<ValueInfo> &Refs);
|
||||
bool ParseTypeIdEntry(unsigned ID);
|
||||
bool ParseTypeIdSummary(TypeIdSummary &TIS);
|
||||
bool ParseTypeIdMetadataEntry(unsigned ID);
|
||||
bool ParseTypeTestResolution(TypeTestResolution &TTRes);
|
||||
bool ParseOptionalWpdResolutions(
|
||||
std::map<uint64_t, WholeProgramDevirtResolution> &WPDResMap);
|
||||
|
@ -379,8 +379,6 @@ enum Kind {
|
||||
kw_critical,
|
||||
kw_relbf,
|
||||
kw_variable,
|
||||
kw_vTableFuncs,
|
||||
kw_virtFunc,
|
||||
kw_aliasee,
|
||||
kw_refs,
|
||||
kw_typeIdInfo,
|
||||
@ -393,7 +391,6 @@ enum Kind {
|
||||
kw_offset,
|
||||
kw_args,
|
||||
kw_typeid,
|
||||
kw_typeidMetadata,
|
||||
kw_summary,
|
||||
kw_typeTestRes,
|
||||
kw_kind,
|
||||
|
@ -748,9 +748,6 @@ private:
|
||||
bool HasRelBF);
|
||||
Error parseEntireSummary(unsigned ID);
|
||||
Error parseModuleStringTable();
|
||||
void parseTypeIdMetadataSummaryRecord(ArrayRef<uint64_t> Record);
|
||||
void parseTypeIdGVInfo(ArrayRef<uint64_t> Record, size_t &Slot,
|
||||
TypeIdGVInfo &TypeId);
|
||||
|
||||
std::pair<ValueInfo, GlobalValue::GUID>
|
||||
getValueInfoFromValueId(unsigned ValueId);
|
||||
@ -5227,24 +5224,6 @@ static void parseTypeIdSummaryRecord(ArrayRef<uint64_t> Record,
|
||||
parseWholeProgramDevirtResolution(Record, Strtab, Slot, TypeId);
|
||||
}
|
||||
|
||||
void ModuleSummaryIndexBitcodeReader::parseTypeIdGVInfo(
|
||||
ArrayRef<uint64_t> Record, size_t &Slot, TypeIdGVInfo &TypeId) {
|
||||
uint64_t Offset = Record[Slot++];
|
||||
ValueInfo Callee = getValueInfoFromValueId(Record[Slot++]).first;
|
||||
TypeId.push_back({Offset, Callee});
|
||||
}
|
||||
|
||||
void ModuleSummaryIndexBitcodeReader::parseTypeIdMetadataSummaryRecord(
|
||||
ArrayRef<uint64_t> Record) {
|
||||
size_t Slot = 0;
|
||||
TypeIdGVInfo &TypeId = TheIndex.getOrInsertTypeIdMetadataSummary(
|
||||
{Strtab.data() + Record[Slot], static_cast<size_t>(Record[Slot + 1])});
|
||||
Slot += 2;
|
||||
|
||||
while (Slot < Record.size())
|
||||
parseTypeIdGVInfo(Record, Slot, TypeId);
|
||||
}
|
||||
|
||||
static void setImmutableRefs(std::vector<ValueInfo> &Refs, unsigned Count) {
|
||||
// Read-only refs are in the end of the refs list.
|
||||
for (unsigned RefNo = Refs.size() - Count; RefNo < Refs.size(); ++RefNo)
|
||||
@ -5462,34 +5441,6 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
|
||||
TheIndex.addGlobalValueSummary(GUID.first, std::move(FS));
|
||||
break;
|
||||
}
|
||||
// FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS: [valueid, flags, varflags,
|
||||
// numrefs, numrefs x valueid,
|
||||
// n x (valueid, offset)]
|
||||
case bitc::FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS: {
|
||||
unsigned ValueID = Record[0];
|
||||
uint64_t RawFlags = Record[1];
|
||||
GlobalVarSummary::GVarFlags GVF = getDecodedGVarFlags(Record[2]);
|
||||
unsigned NumRefs = Record[3];
|
||||
unsigned RefListStartIndex = 4;
|
||||
unsigned VTableListStartIndex = RefListStartIndex + NumRefs;
|
||||
auto Flags = getDecodedGVSummaryFlags(RawFlags, Version);
|
||||
std::vector<ValueInfo> Refs = makeRefList(
|
||||
ArrayRef<uint64_t>(Record).slice(RefListStartIndex, NumRefs));
|
||||
VTableFuncList VTableFuncs;
|
||||
for (unsigned I = VTableListStartIndex, E = Record.size(); I != E; ++I) {
|
||||
ValueInfo Callee = getValueInfoFromValueId(Record[I]).first;
|
||||
uint64_t Offset = Record[++I];
|
||||
VTableFuncs.push_back({Callee, Offset});
|
||||
}
|
||||
auto VS =
|
||||
llvm::make_unique<GlobalVarSummary>(Flags, GVF, std::move(Refs));
|
||||
VS->setModulePath(getThisModule()->first());
|
||||
VS->setVTableFuncs(VTableFuncs);
|
||||
auto GUID = getValueInfoFromValueId(ValueID);
|
||||
VS->setOriginalName(GUID.second);
|
||||
TheIndex.addGlobalValueSummary(GUID.first, std::move(VS));
|
||||
break;
|
||||
}
|
||||
// FS_COMBINED: [valueid, modid, flags, instcount, fflags, numrefs,
|
||||
// numrefs x valueid, n x (valueid)]
|
||||
// FS_COMBINED_PROFILE: [valueid, modid, flags, instcount, fflags, numrefs,
|
||||
@ -5659,10 +5610,6 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
|
||||
case bitc::FS_TYPE_ID:
|
||||
parseTypeIdSummaryRecord(Record, Strtab, TheIndex);
|
||||
break;
|
||||
|
||||
case bitc::FS_TYPE_ID_METADATA:
|
||||
parseTypeIdMetadataSummaryRecord(Record);
|
||||
break;
|
||||
}
|
||||
}
|
||||
llvm_unreachable("Exit infinite loop");
|
||||
|
@ -215,8 +215,7 @@ private:
|
||||
const Function &F);
|
||||
void writeModuleLevelReferences(const GlobalVariable &V,
|
||||
SmallVector<uint64_t, 64> &NameVals,
|
||||
unsigned FSModRefsAbbrev,
|
||||
unsigned FSModVTableRefsAbbrev);
|
||||
unsigned FSModRefsAbbrev);
|
||||
|
||||
void assignValueId(GlobalValue::GUID ValGUID) {
|
||||
GUIDToValueIdMap[ValGUID] = ++GlobalValueId;
|
||||
@ -3529,18 +3528,6 @@ static void writeTypeIdSummaryRecord(SmallVector<uint64_t, 64> &NameVals,
|
||||
W.second);
|
||||
}
|
||||
|
||||
static void writeTypeIdMetadataSummaryRecord(
|
||||
SmallVector<uint64_t, 64> &NameVals, StringTableBuilder &StrtabBuilder,
|
||||
const std::string &Id, const TypeIdGVInfo &Summary, ValueEnumerator &VE) {
|
||||
NameVals.push_back(StrtabBuilder.add(Id));
|
||||
NameVals.push_back(Id.size());
|
||||
|
||||
for (auto &P : Summary) {
|
||||
NameVals.push_back(P.first);
|
||||
NameVals.push_back(VE.getValueID(P.second.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to emit a single function summary record.
|
||||
void ModuleBitcodeWriterBase::writePerModuleFunctionSummaryRecord(
|
||||
SmallVector<uint64_t, 64> &NameVals, GlobalValueSummary *Summary,
|
||||
@ -3585,7 +3572,7 @@ void ModuleBitcodeWriterBase::writePerModuleFunctionSummaryRecord(
|
||||
// and emit them in a summary record.
|
||||
void ModuleBitcodeWriterBase::writeModuleLevelReferences(
|
||||
const GlobalVariable &V, SmallVector<uint64_t, 64> &NameVals,
|
||||
unsigned FSModRefsAbbrev, unsigned FSModVTableRefsAbbrev) {
|
||||
unsigned FSModRefsAbbrev) {
|
||||
auto VI = Index->getValueInfo(V.getGUID());
|
||||
if (!VI || VI.getSummaryList().empty()) {
|
||||
// Only declarations should not have a summary (a declaration might however
|
||||
@ -3599,10 +3586,6 @@ void ModuleBitcodeWriterBase::writeModuleLevelReferences(
|
||||
NameVals.push_back(getEncodedGVSummaryFlags(VS->flags()));
|
||||
NameVals.push_back(getEncodedGVarFlags(VS->varflags()));
|
||||
|
||||
auto VTableFuncs = VS->vTableFuncs();
|
||||
if (!VTableFuncs.empty())
|
||||
NameVals.push_back(VS->refs().size());
|
||||
|
||||
unsigned SizeBeforeRefs = NameVals.size();
|
||||
for (auto &RI : VS->refs())
|
||||
NameVals.push_back(VE.getValueID(RI.getValue()));
|
||||
@ -3610,20 +3593,8 @@ void ModuleBitcodeWriterBase::writeModuleLevelReferences(
|
||||
// been initialized from a DenseSet.
|
||||
llvm::sort(NameVals.begin() + SizeBeforeRefs, NameVals.end());
|
||||
|
||||
if (!VTableFuncs.empty()) {
|
||||
// VTableFuncs pairs should already be sorted by offset.
|
||||
for (auto &P : VTableFuncs) {
|
||||
NameVals.push_back(VE.getValueID(P.first.getValue()));
|
||||
NameVals.push_back(P.second);
|
||||
}
|
||||
}
|
||||
|
||||
if (VTableFuncs.empty())
|
||||
Stream.EmitRecord(bitc::FS_PERMODULE_GLOBALVAR_INIT_REFS, NameVals,
|
||||
FSModRefsAbbrev);
|
||||
else
|
||||
Stream.EmitRecord(bitc::FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS, NameVals,
|
||||
FSModVTableRefsAbbrev);
|
||||
Stream.EmitRecord(bitc::FS_PERMODULE_GLOBALVAR_INIT_REFS, NameVals,
|
||||
FSModRefsAbbrev);
|
||||
NameVals.clear();
|
||||
}
|
||||
|
||||
@ -3704,17 +3675,6 @@ void ModuleBitcodeWriterBase::writePerModuleGlobalValueSummary() {
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
|
||||
unsigned FSModRefsAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
|
||||
// Abbrev for FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS.
|
||||
Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // valueid
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // flags
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs
|
||||
// numrefs x valueid, n x (valueid , offset)
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
|
||||
unsigned FSModVTableRefsAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
|
||||
// Abbrev for FS_ALIAS.
|
||||
Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::FS_ALIAS));
|
||||
@ -3747,8 +3707,7 @@ void ModuleBitcodeWriterBase::writePerModuleGlobalValueSummary() {
|
||||
// Capture references from GlobalVariable initializers, which are outside
|
||||
// of a function scope.
|
||||
for (const GlobalVariable &G : M.globals())
|
||||
writeModuleLevelReferences(G, NameVals, FSModRefsAbbrev,
|
||||
FSModVTableRefsAbbrev);
|
||||
writeModuleLevelReferences(G, NameVals, FSModRefsAbbrev);
|
||||
|
||||
for (const GlobalAlias &A : M.aliases()) {
|
||||
auto *Aliasee = A.getBaseObject();
|
||||
@ -3766,16 +3725,6 @@ void ModuleBitcodeWriterBase::writePerModuleGlobalValueSummary() {
|
||||
NameVals.clear();
|
||||
}
|
||||
|
||||
if (!Index->typeIdMetadataMap().empty()) {
|
||||
SmallVector<uint64_t, 64> NameVals;
|
||||
for (auto &S : Index->typeIdMetadataMap()) {
|
||||
writeTypeIdMetadataSummaryRecord(NameVals, StrtabBuilder, S.first,
|
||||
S.second, VE);
|
||||
Stream.EmitRecord(bitc::FS_TYPE_ID_METADATA, NameVals);
|
||||
NameVals.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Stream.ExitBlock();
|
||||
}
|
||||
|
||||
|
@ -1038,9 +1038,6 @@ void SlotTracker::processIndex() {
|
||||
TidIter != TheIndex->typeIds().end(); TidIter++)
|
||||
CreateTypeIdSlot(TidIter->second.first);
|
||||
|
||||
for (auto &TId : TheIndex->typeIdMetadataMap())
|
||||
CreateGUIDSlot(GlobalValue::getGUID(TId.first));
|
||||
|
||||
ST_DEBUG("end processIndex!\n");
|
||||
}
|
||||
|
||||
@ -2396,7 +2393,6 @@ public:
|
||||
void printGlobalVarSummary(const GlobalVarSummary *GS);
|
||||
void printFunctionSummary(const FunctionSummary *FS);
|
||||
void printTypeIdSummary(const TypeIdSummary &TIS);
|
||||
void printTypeIdMetadataSummary(const TypeIdGVInfo &TI);
|
||||
void printTypeTestResolution(const TypeTestResolution &TTRes);
|
||||
void printArgs(const std::vector<uint64_t> &Args);
|
||||
void printWPDRes(const WholeProgramDevirtResolution &WPDRes);
|
||||
@ -2699,15 +2695,6 @@ void AssemblyWriter::printModuleSummaryIndex() {
|
||||
printTypeIdSummary(TidIter->second.second);
|
||||
Out << ") ; guid = " << TidIter->first << "\n";
|
||||
}
|
||||
|
||||
// Print the TypeIdMetadataMap entries.
|
||||
for (auto &TId : TheIndex->typeIdMetadataMap()) {
|
||||
auto GUID = GlobalValue::getGUID(TId.first);
|
||||
Out << "^" << Machine.getGUIDSlot(GUID) << " = typeidMetadata: (name: \""
|
||||
<< TId.first << "\"";
|
||||
printTypeIdMetadataSummary(TId.second);
|
||||
Out << ") ; guid = " << GUID << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
@ -2790,18 +2777,6 @@ void AssemblyWriter::printTypeIdSummary(const TypeIdSummary &TIS) {
|
||||
Out << ")";
|
||||
}
|
||||
|
||||
void AssemblyWriter::printTypeIdMetadataSummary(const TypeIdGVInfo &TI) {
|
||||
Out << ", summary: (";
|
||||
FieldSeparator FS;
|
||||
for (auto &P : TI) {
|
||||
Out << FS;
|
||||
Out << "(offset: " << P.first << ", ";
|
||||
Out << "^" << Machine.getGUIDSlot(P.second.getGUID());
|
||||
Out << ")";
|
||||
}
|
||||
Out << ")";
|
||||
}
|
||||
|
||||
void AssemblyWriter::printArgs(const std::vector<uint64_t> &Args) {
|
||||
Out << "args: (";
|
||||
FieldSeparator FS;
|
||||
@ -2871,19 +2846,6 @@ void AssemblyWriter::printAliasSummary(const AliasSummary *AS) {
|
||||
|
||||
void AssemblyWriter::printGlobalVarSummary(const GlobalVarSummary *GS) {
|
||||
Out << ", varFlags: (readonly: " << GS->VarFlags.ReadOnly << ")";
|
||||
|
||||
auto VTableFuncs = GS->vTableFuncs();
|
||||
if (!VTableFuncs.empty()) {
|
||||
Out << ", vTableFuncs: (";
|
||||
FieldSeparator FS;
|
||||
for (auto &P : VTableFuncs) {
|
||||
Out << FS;
|
||||
Out << "(virtFunc: ^" << Machine.getGUIDSlot(P.first.getGUID())
|
||||
<< ", offset: " << P.second;
|
||||
Out << ")";
|
||||
}
|
||||
Out << ")";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getLinkageName(GlobalValue::LinkageTypes LT) {
|
||||
|
@ -418,55 +418,34 @@ void splitAndWriteThinLTOBitcode(
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the LTO Unit splitting has been enabled.
|
||||
bool enableSplitLTOUnit(Module &M) {
|
||||
// Returns whether this module needs to be split because splitting is
|
||||
// enabled and it uses type metadata.
|
||||
bool requiresSplit(Module &M) {
|
||||
// First check if the LTO Unit splitting has been enabled.
|
||||
bool EnableSplitLTOUnit = false;
|
||||
if (auto *MD = mdconst::extract_or_null<ConstantInt>(
|
||||
M.getModuleFlag("EnableSplitLTOUnit")))
|
||||
EnableSplitLTOUnit = MD->getZExtValue();
|
||||
return EnableSplitLTOUnit;
|
||||
}
|
||||
if (!EnableSplitLTOUnit)
|
||||
return false;
|
||||
|
||||
// Returns whether this module needs to be split because it uses type metadata.
|
||||
bool hasTypeMetadata(Module &M) {
|
||||
// Module only needs to be split if it contains type metadata.
|
||||
for (auto &GO : M.global_objects()) {
|
||||
if (GO.hasMetadata(LLVMContext::MD_type))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void writeThinLTOBitcode(raw_ostream &OS, raw_ostream *ThinLinkOS,
|
||||
function_ref<AAResults &(Function &)> AARGetter,
|
||||
Module &M, const ModuleSummaryIndex *Index) {
|
||||
std::unique_ptr<ModuleSummaryIndex> NewIndex = nullptr;
|
||||
// See if this module has any type metadata. If so, we try to split it
|
||||
// or at least promote type ids to enable WPD.
|
||||
if (hasTypeMetadata(M)) {
|
||||
if (enableSplitLTOUnit(M))
|
||||
return splitAndWriteThinLTOBitcode(OS, ThinLinkOS, AARGetter, M);
|
||||
else {
|
||||
// Promote type ids as needed for index-based WPD.
|
||||
std::string ModuleId = getUniqueModuleId(&M);
|
||||
if (!ModuleId.empty()) {
|
||||
promoteTypeIds(M, ModuleId);
|
||||
// Need to rebuild the index so that it contains type metadata
|
||||
// for the newly promoted type ids.
|
||||
// FIXME: Probably should not bother building the index at all
|
||||
// in the caller of writeThinLTOBitcode (which does so via the
|
||||
// ModuleSummaryIndexAnalysis pass), since we have to rebuild it
|
||||
// anyway whenever there is type metadata (here or in
|
||||
// splitAndWriteThinLTOBitcode). Just always build it once via the
|
||||
// buildModuleSummaryIndex when Module(s) are ready.
|
||||
ProfileSummaryInfo PSI(M);
|
||||
NewIndex = llvm::make_unique<ModuleSummaryIndex>(
|
||||
buildModuleSummaryIndex(M, nullptr, &PSI));
|
||||
Index = NewIndex.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Split module if splitting is enabled and it contains any type metadata.
|
||||
if (requiresSplit(M))
|
||||
return splitAndWriteThinLTOBitcode(OS, ThinLinkOS, AARGetter, M);
|
||||
|
||||
// Write it out as an unsplit ThinLTO module.
|
||||
// Otherwise we can just write it out as a regular module.
|
||||
|
||||
// Save the module hash produced for the full bitcode, which will
|
||||
// be used in the backends, and use that in the minimized bitcode
|
||||
|
@ -1,38 +0,0 @@
|
||||
; Test summary parsing of index-based WPD related summary fields
|
||||
; RUN: llvm-as %s -o - | llvm-dis -o %t.ll
|
||||
; RUN: grep "^\^" %s >%t2
|
||||
; RUN: grep "^\^" %t.ll >%t3
|
||||
; Expect that the summary information is the same after round-trip through
|
||||
; llvm-as and llvm-dis.
|
||||
; RUN: diff %t2 %t3
|
||||
|
||||
source_filename = "thinlto-vtable-summary.ll"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-grtev4-linux-gnu"
|
||||
|
||||
%struct.A = type { i32 (...)** }
|
||||
%struct.B = type { %struct.A }
|
||||
%struct.C = type { %struct.A }
|
||||
|
||||
@_ZTV1B = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.B*, i32)* @_ZN1B1fEi to i8*), i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0, !type !1
|
||||
@_ZTV1C = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.C*, i32)* @_ZN1C1fEi to i8*), i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0, !type !2
|
||||
|
||||
declare i32 @_ZN1B1fEi(%struct.B*, i32)
|
||||
|
||||
declare i32 @_ZN1A1nEi(%struct.A*, i32)
|
||||
|
||||
declare i32 @_ZN1C1fEi(%struct.C*, i32)
|
||||
|
||||
!0 = !{i64 16, !"_ZTS1A"}
|
||||
!1 = !{i64 16, !"_ZTS1B"}
|
||||
!2 = !{i64 16, !"_ZTS1C"}
|
||||
|
||||
^0 = module: (path: "<stdin>", hash: (0, 0, 0, 0, 0))
|
||||
^1 = gv: (name: "_ZN1A1nEi") ; guid = 1621563287929432257
|
||||
^2 = gv: (name: "_ZTV1B", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), varFlags: (readonly: 0), vTableFuncs: ((virtFunc: ^3, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^3, ^1)))) ; guid = 5283576821522790367
|
||||
^3 = gv: (name: "_ZN1B1fEi") ; guid = 7162046368816414394
|
||||
^4 = gv: (name: "_ZTV1C", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), varFlags: (readonly: 0), vTableFuncs: ((virtFunc: ^5, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^1, ^5)))) ; guid = 13624023785555846296
|
||||
^5 = gv: (name: "_ZN1C1fEi") ; guid = 14876272565662207556
|
||||
^6 = typeidMetadata: (name: "_ZTS1A", summary: ((offset: 16, ^2), (offset: 16, ^4))) ; guid = 7004155349499253778
|
||||
^7 = typeidMetadata: (name: "_ZTS1B", summary: ((offset: 16, ^2))) ; guid = 6203814149063363976
|
||||
^8 = typeidMetadata: (name: "_ZTS1C", summary: ((offset: 16, ^4))) ; guid = 1884921850105019584
|
@ -1,146 +0,0 @@
|
||||
; REQUIRES: x86-registered-target
|
||||
|
||||
; Test devirtualization through the thin link and backend.
|
||||
|
||||
; Generate split module with summary for hybrid Thin/Regular LTO WPD.
|
||||
; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t.o %s
|
||||
|
||||
; Check that we have module flag showing splitting enabled, and that we don't
|
||||
; generate summary information needed for index-based WPD.
|
||||
; RUN: llvm-modextract -b -n=0 %t.o -o %t.o.0
|
||||
; RUN: llvm-dis -o - %t.o.0 | FileCheck %s --check-prefix=ENABLESPLITFLAG --implicit-check-not=vTableFuncs --implicit-check-not=typeidMetadata
|
||||
; RUN: llvm-modextract -b -n=1 %t.o -o %t.o.1
|
||||
; RUN: llvm-dis -o - %t.o.1 | FileCheck %s --check-prefix=ENABLESPLITFLAG --implicit-check-not=vTableFuncs --implicit-check-not=typeidMetadata
|
||||
; ENABLESPLITFLAG: !{i32 1, !"EnableSplitLTOUnit", i32 1}
|
||||
|
||||
; Generate unsplit module with summary for ThinLTO index-based WPD.
|
||||
; RUN: opt -thinlto-bc -o %t2.o %s
|
||||
|
||||
; Check that we don't have module flag when splitting not enabled for ThinLTO,
|
||||
; and that we generate summary information needed for index-based WPD.
|
||||
; RUN: llvm-dis -o - %t2.o | FileCheck %s --check-prefix=NOENABLESPLITFLAG
|
||||
; NOENABLESPLITFLAG-DAG: !{i32 1, !"EnableSplitLTOUnit", i32 0}
|
||||
; NOENABLESPLITFLAG-DAG: [[An:\^[0-9]+]] = gv: (name: "_ZN1A1nEi")
|
||||
; NOENABLESPLITFLAG-DAG: [[Bf:\^[0-9]+]] = gv: (name: "_ZN1B1fEi")
|
||||
; NOENABLESPLITFLAG-DAG: [[Cf:\^[0-9]+]] = gv: (name: "_ZN1C1fEi")
|
||||
; NOENABLESPLITFLAG-DAG: [[Dm:\^[0-9]+]] = gv: (name: "_ZN1D1mEi")
|
||||
; NOENABLESPLITFLAG-DAG: [[B:\^[0-9]+]] = gv: (name: "_ZTV1B", {{.*}} vTableFuncs: ((virtFunc: [[Bf]], offset: 16), (virtFunc: [[An]], offset: 24)), refs: ([[Bf]], [[An]])
|
||||
; NOENABLESPLITFLAG-DAG: [[C:\^[0-9]+]] = gv: (name: "_ZTV1C", {{.*}} vTableFuncs: ((virtFunc: [[Cf]], offset: 16), (virtFunc: [[An]], offset: 24)), refs: ([[An]], [[Cf]])
|
||||
; NOENABLESPLITFLAG-DAG: [[D:\^[0-9]+]] = gv: (name: "_ZTV1D", {{.*}} vTableFuncs: ((virtFunc: [[Dm]], offset: 16)), refs: ([[Dm]])
|
||||
; NOENABLESPLITFLAG-DAG: typeidMetadata: (name: "_ZTS1A", summary: ((offset: 16, [[B]]), (offset: 16, [[C]])))
|
||||
; NOENABLESPLITFLAG-DAG: typeidMetadata: (name: "_ZTS1B", summary: ((offset: 16, [[B]])))
|
||||
; NOENABLESPLITFLAG-DAG: typeidMetadata: (name: "_ZTS1C", summary: ((offset: 16, [[C]])))
|
||||
; Type Id on _ZTV1D should have been promoted
|
||||
; NOENABLESPLITFLAG-DAG: typeidMetadata: (name: "1${{.*}}", summary: ((offset: 16, [[D]])))
|
||||
|
||||
; TODO: Test index-based WPD one %t2.o once implemented.
|
||||
|
||||
; Legacy PM
|
||||
; RUN: llvm-lto2 run %t.o -save-temps -pass-remarks=. \
|
||||
; RUN: -o %t3 \
|
||||
; RUN: -r=%t.o,test,px \
|
||||
; RUN: -r=%t.o,_ZN1A1nEi,p \
|
||||
; RUN: -r=%t.o,_ZN1B1fEi,p \
|
||||
; RUN: -r=%t.o,_ZN1C1fEi,p \
|
||||
; RUN: -r=%t.o,_ZN1D1mEi,p \
|
||||
; RUN: -r=%t.o,_ZTV1B, \
|
||||
; RUN: -r=%t.o,_ZTV1C, \
|
||||
; RUN: -r=%t.o,_ZTV1D, \
|
||||
; RUN: -r=%t.o,_ZN1A1nEi, \
|
||||
; RUN: -r=%t.o,_ZN1B1fEi, \
|
||||
; RUN: -r=%t.o,_ZN1C1fEi, \
|
||||
; RUN: -r=%t.o,_ZN1D1mEi, \
|
||||
; RUN: -r=%t.o,_ZTV1B,px \
|
||||
; RUN: -r=%t.o,_ZTV1C,px \
|
||||
; RUN: -r=%t.o,_ZTV1D,px 2>&1 | FileCheck %s --check-prefix=REMARK
|
||||
; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
|
||||
|
||||
; New PM
|
||||
; RUN: llvm-lto2 run %t.o -save-temps -use-new-pm -pass-remarks=. \
|
||||
; RUN: -o %t3 \
|
||||
; RUN: -r=%t.o,test,px \
|
||||
; RUN: -r=%t.o,_ZN1A1nEi,p \
|
||||
; RUN: -r=%t.o,_ZN1B1fEi,p \
|
||||
; RUN: -r=%t.o,_ZN1C1fEi,p \
|
||||
; RUN: -r=%t.o,_ZN1D1mEi,p \
|
||||
; RUN: -r=%t.o,_ZTV1B, \
|
||||
; RUN: -r=%t.o,_ZTV1C, \
|
||||
; RUN: -r=%t.o,_ZTV1D, \
|
||||
; RUN: -r=%t.o,_ZN1A1nEi, \
|
||||
; RUN: -r=%t.o,_ZN1B1fEi, \
|
||||
; RUN: -r=%t.o,_ZN1C1fEi, \
|
||||
; RUN: -r=%t.o,_ZN1D1mEi, \
|
||||
; RUN: -r=%t.o,_ZTV1B,px \
|
||||
; RUN: -r=%t.o,_ZTV1C,px \
|
||||
; RUN: -r=%t.o,_ZTV1D,px 2>&1 | FileCheck %s --check-prefix=REMARK
|
||||
; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
|
||||
|
||||
; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi
|
||||
; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEi
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-grtev4-linux-gnu"
|
||||
|
||||
%struct.A = type { i32 (...)** }
|
||||
%struct.B = type { %struct.A }
|
||||
%struct.C = type { %struct.A }
|
||||
%struct.D = type { i32 (...)** }
|
||||
|
||||
@_ZTV1B = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.B*, i32)* @_ZN1B1fEi to i8*), i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0, !type !1
|
||||
@_ZTV1C = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.C*, i32)* @_ZN1C1fEi to i8*), i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0, !type !2
|
||||
@_ZTV1D = constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.D*, i32)* @_ZN1D1mEi to i8*)] }, !type !3
|
||||
|
||||
|
||||
; CHECK-IR-LABEL: define i32 @test
|
||||
define i32 @test(%struct.A* %obj, %struct.D* %obj2, i32 %a) {
|
||||
entry:
|
||||
%0 = bitcast %struct.A* %obj to i8***
|
||||
%vtable = load i8**, i8*** %0
|
||||
%1 = bitcast i8** %vtable to i8*
|
||||
%p = call i1 @llvm.type.test(i8* %1, metadata !"_ZTS1A")
|
||||
call void @llvm.assume(i1 %p)
|
||||
%fptrptr = getelementptr i8*, i8** %vtable, i32 1
|
||||
%2 = bitcast i8** %fptrptr to i32 (%struct.A*, i32)**
|
||||
%fptr1 = load i32 (%struct.A*, i32)*, i32 (%struct.A*, i32)** %2, align 8
|
||||
|
||||
; Check that the call was devirtualized.
|
||||
; CHECK-IR: %call = tail call i32 @_ZN1A1nEi
|
||||
%call = tail call i32 %fptr1(%struct.A* nonnull %obj, i32 %a)
|
||||
|
||||
%3 = bitcast i8** %vtable to i32 (%struct.A*, i32)**
|
||||
%fptr22 = load i32 (%struct.A*, i32)*, i32 (%struct.A*, i32)** %3, align 8
|
||||
|
||||
; We still have to call it as virtual.
|
||||
; CHECK-IR: %call3 = tail call i32 %fptr22
|
||||
%call3 = tail call i32 %fptr22(%struct.A* nonnull %obj, i32 %call)
|
||||
|
||||
%4 = bitcast %struct.D* %obj2 to i8***
|
||||
%vtable2 = load i8**, i8*** %4
|
||||
%5 = bitcast i8** %vtable2 to i8*
|
||||
%p2 = call i1 @llvm.type.test(i8* %5, metadata !4)
|
||||
call void @llvm.assume(i1 %p2)
|
||||
|
||||
%6 = bitcast i8** %vtable2 to i32 (%struct.D*, i32)**
|
||||
%fptr33 = load i32 (%struct.D*, i32)*, i32 (%struct.D*, i32)** %6, align 8
|
||||
|
||||
; Check that the call was devirtualized.
|
||||
; CHECK-IR: %call4 = tail call i32 @_ZN1D1mEi
|
||||
%call4 = tail call i32 %fptr33(%struct.D* nonnull %obj2, i32 %call3)
|
||||
ret i32 %call4
|
||||
}
|
||||
; CHECK-IR-LABEL: ret i32
|
||||
; CHECK-IR-LABEL: }
|
||||
|
||||
declare i1 @llvm.type.test(i8*, metadata)
|
||||
declare void @llvm.assume(i1)
|
||||
|
||||
declare i32 @_ZN1B1fEi(%struct.B* %this, i32 %a)
|
||||
declare i32 @_ZN1A1nEi(%struct.A* %this, i32 %a)
|
||||
declare i32 @_ZN1C1fEi(%struct.C* %this, i32 %a)
|
||||
declare i32 @_ZN1D1mEi(%struct.D* %this, i32 %a)
|
||||
|
||||
!0 = !{i64 16, !"_ZTS1A"}
|
||||
!1 = !{i64 16, !"_ZTS1B"}
|
||||
!2 = !{i64 16, !"_ZTS1C"}
|
||||
!3 = !{i64 16, !4}
|
||||
!4 = distinct !{}
|
@ -317,7 +317,6 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
|
||||
STRINGIFY_CODE(FS, PERMODULE_PROFILE)
|
||||
STRINGIFY_CODE(FS, PERMODULE_RELBF)
|
||||
STRINGIFY_CODE(FS, PERMODULE_GLOBALVAR_INIT_REFS)
|
||||
STRINGIFY_CODE(FS, PERMODULE_VTABLE_GLOBALVAR_INIT_REFS)
|
||||
STRINGIFY_CODE(FS, COMBINED)
|
||||
STRINGIFY_CODE(FS, COMBINED_PROFILE)
|
||||
STRINGIFY_CODE(FS, COMBINED_GLOBALVAR_INIT_REFS)
|
||||
@ -335,7 +334,6 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
|
||||
STRINGIFY_CODE(FS, CFI_FUNCTION_DEFS)
|
||||
STRINGIFY_CODE(FS, CFI_FUNCTION_DECLS)
|
||||
STRINGIFY_CODE(FS, TYPE_ID)
|
||||
STRINGIFY_CODE(FS, TYPE_ID_METADATA)
|
||||
}
|
||||
case bitc::METADATA_ATTACHMENT_ID:
|
||||
switch(CodeID) {
|
||||
|
Loading…
Reference in New Issue
Block a user