[IFUNC] Use GlobalIndirectSymbol when aliases and ifuncs have something similar

Second part extracted from http://reviews.llvm.org/D15525

Use GlobalIndirectSymbol in all cases when aliases and ifuncs have
something in common.

Differential Revision: http://reviews.llvm.org/D18754

llvm-svn: 265382
This commit is contained in:
Dmitry Polukhin 2016-04-05 08:47:51 +00:00
parent 50b6ceff1f
commit a3d5b0b218
8 changed files with 141 additions and 102 deletions

View File

@ -34,6 +34,7 @@ class ConstantArray;
class DIE;
class DIEAbbrev;
class GCMetadataPrinter;
class GlobalIndirectSymbol;
class GlobalValue;
class GlobalVariable;
class MachineBasicBlock;
@ -546,6 +547,9 @@ private:
void EmitXXStructorList(const DataLayout &DL, const Constant *List,
bool isCtor);
GCMetadataPrinter *GetOrCreateGCPrinter(GCStrategy &C);
/// Emit GlobalAlias or GlobalIFunc.
void emitGlobalIndirectSymbol(Module &M,
const GlobalIndirectSymbol& GIS);
};
}

View File

@ -503,8 +503,9 @@ bool LLParser::ParseUnnamedGlobal() {
if (Lex.getKind() != lltok::kw_alias)
return ParseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility,
DLLStorageClass, TLM, UnnamedAddr);
return ParseAlias(Name, NameLoc, Linkage, Visibility, DLLStorageClass, TLM,
UnnamedAddr);
return parseIndirectSymbol(Name, NameLoc, Linkage, Visibility,
DLLStorageClass, TLM, UnnamedAddr);
}
/// ParseNamedGlobal:
@ -533,8 +534,8 @@ bool LLParser::ParseNamedGlobal() {
return ParseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility,
DLLStorageClass, TLM, UnnamedAddr);
return ParseAlias(Name, NameLoc, Linkage, Visibility, DLLStorageClass, TLM,
UnnamedAddr);
return parseIndirectSymbol(Name, NameLoc, Linkage, Visibility,
DLLStorageClass, TLM, UnnamedAddr);
}
bool LLParser::parseComdat() {
@ -690,26 +691,31 @@ static bool isValidVisibilityForLinkage(unsigned V, unsigned L) {
(GlobalValue::VisibilityTypes)V == GlobalValue::DefaultVisibility;
}
/// ParseAlias:
/// parseIndirectSymbol:
/// ::= GlobalVar '=' OptionalLinkage OptionalVisibility
/// OptionalDLLStorageClass OptionalThreadLocal
/// OptionalUnnamedAddr 'alias' Aliasee
/// OptionalUnnamedAddr 'alias' IndirectSymbol
///
/// Aliasee
/// IndirectSymbol
/// ::= TypeAndValue
///
/// Everything through OptionalUnnamedAddr has already been parsed.
///
bool LLParser::ParseAlias(const std::string &Name, LocTy NameLoc, unsigned L,
unsigned Visibility, unsigned DLLStorageClass,
GlobalVariable::ThreadLocalMode TLM,
bool UnnamedAddr) {
assert(Lex.getKind() == lltok::kw_alias);
bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc,
unsigned L, unsigned Visibility,
unsigned DLLStorageClass,
GlobalVariable::ThreadLocalMode TLM,
bool UnnamedAddr) {
bool IsAlias;
if (Lex.getKind() == lltok::kw_alias)
IsAlias = true;
else
llvm_unreachable("Not an alias!");
Lex.Lex();
GlobalValue::LinkageTypes Linkage = (GlobalValue::LinkageTypes) L;
if(!GlobalAlias::isValidLinkage(Linkage))
if(IsAlias && !GlobalAlias::isValidLinkage(Linkage))
return Error(NameLoc, "invalid linkage type for alias");
if (!isValidVisibilityForLinkage(Visibility, L))
@ -746,11 +752,16 @@ bool LLParser::ParseAlias(const std::string &Name, LocTy NameLoc, unsigned L,
return Error(AliaseeLoc, "An alias must have pointer type");
unsigned AddrSpace = PTy->getAddressSpace();
if (Ty != PTy->getElementType())
if (IsAlias && Ty != PTy->getElementType())
return Error(
ExplicitTypeLoc,
"explicit pointee type doesn't match operand's pointee type");
if (!IsAlias && !PTy->getElementType()->isFunctionTy())
return Error(
ExplicitTypeLoc,
"explicit pointee type should be a function type");
GlobalValue *GVal = nullptr;
// See if the alias was forward referenced, if so, prepare to replace the
@ -770,9 +781,13 @@ bool LLParser::ParseAlias(const std::string &Name, LocTy NameLoc, unsigned L,
}
// Okay, create the alias but do not insert it into the module yet.
std::unique_ptr<GlobalAlias> GA(
GlobalAlias::create(Ty, AddrSpace, (GlobalValue::LinkageTypes)Linkage,
Name, Aliasee, /*Parent*/ nullptr));
std::unique_ptr<GlobalIndirectSymbol> GA;
if (IsAlias)
GA.reset(GlobalAlias::create(Ty, AddrSpace,
(GlobalValue::LinkageTypes)Linkage, Name,
Aliasee, /*Parent*/ nullptr));
else
llvm_unreachable("Not an alias!");
GA->setThreadLocalMode(TLM);
GA->setVisibility((GlobalValue::VisibilityTypes)Visibility);
GA->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass);
@ -795,7 +810,10 @@ bool LLParser::ParseAlias(const std::string &Name, LocTy NameLoc, unsigned L,
}
// Insert into the module, we know its name won't collide now.
M->getAliasList().push_back(GA.get());
if (IsAlias)
M->getAliasList().push_back(cast<GlobalAlias>(GA.get()));
else
llvm_unreachable("Not an alias!");
assert(GA->getName() == Name && "Should not be a name conflict!");
// The module owns this now

View File

@ -275,9 +275,11 @@ namespace llvm {
bool HasLinkage, unsigned Visibility,
unsigned DLLStorageClass,
GlobalVariable::ThreadLocalMode TLM, bool UnnamedAddr);
bool ParseAlias(const std::string &Name, LocTy Loc, unsigned Linkage,
unsigned Visibility, unsigned DLLStorageClass,
GlobalVariable::ThreadLocalMode TLM, bool UnnamedAddr);
bool parseIndirectSymbol(const std::string &Name, LocTy Loc,
unsigned Linkage, unsigned Visibility,
unsigned DLLStorageClass,
GlobalVariable::ThreadLocalMode TLM,
bool UnnamedAddr);
bool parseComdat();
bool ParseStandaloneMetadata();
bool ParseNamedMetadata();

View File

@ -163,7 +163,7 @@ class BitcodeReader : public GVMaterializer {
SmallVector<Instruction *, 64> InstructionList;
std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInits;
std::vector<std::pair<GlobalAlias*, unsigned> > AliasInits;
std::vector<std::pair<GlobalIndirectSymbol*, unsigned> > IndirectSymbolInits;
std::vector<std::pair<Function*, unsigned> > FunctionPrefixes;
std::vector<std::pair<Function*, unsigned> > FunctionPrologues;
std::vector<std::pair<Function*, unsigned> > FunctionPersonalityFns;
@ -395,7 +395,7 @@ private:
std::error_code rememberAndSkipMetadata();
std::error_code parseFunctionBody(Function *F);
std::error_code globalCleanup();
std::error_code resolveGlobalAndAliasInits();
std::error_code resolveGlobalAndIndirectSymbolInits();
std::error_code parseMetadata(bool ModuleLevel = false);
std::error_code parseMetadataStrings(ArrayRef<uint64_t> Record,
StringRef Blob,
@ -2492,15 +2492,16 @@ uint64_t BitcodeReader::decodeSignRotatedValue(uint64_t V) {
}
/// Resolve all of the initializers for global values and aliases that we can.
std::error_code BitcodeReader::resolveGlobalAndAliasInits() {
std::error_code BitcodeReader::resolveGlobalAndIndirectSymbolInits() {
std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInitWorklist;
std::vector<std::pair<GlobalAlias*, unsigned> > AliasInitWorklist;
std::vector<std::pair<GlobalIndirectSymbol*, unsigned> >
IndirectSymbolInitWorklist;
std::vector<std::pair<Function*, unsigned> > FunctionPrefixWorklist;
std::vector<std::pair<Function*, unsigned> > FunctionPrologueWorklist;
std::vector<std::pair<Function*, unsigned> > FunctionPersonalityFnWorklist;
GlobalInitWorklist.swap(GlobalInits);
AliasInitWorklist.swap(AliasInits);
IndirectSymbolInitWorklist.swap(IndirectSymbolInits);
FunctionPrefixWorklist.swap(FunctionPrefixes);
FunctionPrologueWorklist.swap(FunctionPrologues);
FunctionPersonalityFnWorklist.swap(FunctionPersonalityFns);
@ -2519,20 +2520,20 @@ std::error_code BitcodeReader::resolveGlobalAndAliasInits() {
GlobalInitWorklist.pop_back();
}
while (!AliasInitWorklist.empty()) {
unsigned ValID = AliasInitWorklist.back().second;
while (!IndirectSymbolInitWorklist.empty()) {
unsigned ValID = IndirectSymbolInitWorklist.back().second;
if (ValID >= ValueList.size()) {
AliasInits.push_back(AliasInitWorklist.back());
IndirectSymbolInits.push_back(IndirectSymbolInitWorklist.back());
} else {
Constant *C = dyn_cast_or_null<Constant>(ValueList[ValID]);
if (!C)
return error("Expected a constant");
GlobalAlias *Alias = AliasInitWorklist.back().first;
if (C->getType() != Alias->getType())
GlobalIndirectSymbol *GIS = IndirectSymbolInitWorklist.back().first;
if (isa<GlobalAlias>(GIS) && C->getType() != GIS->getType())
return error("Alias and aliasee types don't match");
Alias->setAliasee(C);
GIS->setIndirectSymbol(C);
}
AliasInitWorklist.pop_back();
IndirectSymbolInitWorklist.pop_back();
}
while (!FunctionPrefixWorklist.empty()) {
@ -3157,8 +3158,8 @@ std::error_code BitcodeReader::rememberAndSkipFunctionBody() {
std::error_code BitcodeReader::globalCleanup() {
// Patch the initializers for globals and aliases up.
resolveGlobalAndAliasInits();
if (!GlobalInits.empty() || !AliasInits.empty())
resolveGlobalAndIndirectSymbolInits();
if (!GlobalInits.empty() || !IndirectSymbolInits.empty())
return error("Malformed global initializer set");
// Look for intrinsic functions which need to be upgraded at some point
@ -3175,7 +3176,8 @@ std::error_code BitcodeReader::globalCleanup() {
// Force deallocation of memory for these vectors to favor the client that
// want lazy deserialization.
std::vector<std::pair<GlobalVariable*, unsigned> >().swap(GlobalInits);
std::vector<std::pair<GlobalAlias*, unsigned> >().swap(AliasInits);
std::vector<std::pair<GlobalIndirectSymbol*, unsigned> >().swap(
IndirectSymbolInits);
return std::error_code();
}
@ -3325,7 +3327,7 @@ std::error_code BitcodeReader::parseModule(uint64_t ResumeBit,
case bitc::CONSTANTS_BLOCK_ID:
if (std::error_code EC = parseConstants())
return EC;
if (std::error_code EC = resolveGlobalAndAliasInits())
if (std::error_code EC = resolveGlobalAndIndirectSymbolInits())
return EC;
break;
case bitc::METADATA_BLOCK_ID:
@ -3658,7 +3660,7 @@ std::error_code BitcodeReader::parseModule(uint64_t ResumeBit,
// ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility, dllstorageclass]
case bitc::MODULE_CODE_ALIAS:
case bitc::MODULE_CODE_ALIAS_OLD: {
bool NewRecord = BitCode == bitc::MODULE_CODE_ALIAS;
bool NewRecord = BitCode != bitc::MODULE_CODE_ALIAS_OLD;
if (Record.size() < (3 + (unsigned)NewRecord))
return error("Invalid record");
unsigned OpNum = 0;
@ -3679,8 +3681,13 @@ std::error_code BitcodeReader::parseModule(uint64_t ResumeBit,
auto Val = Record[OpNum++];
auto Linkage = Record[OpNum++];
auto *NewGA = GlobalAlias::create(
GlobalIndirectSymbol *NewGA;
if (BitCode == bitc::MODULE_CODE_ALIAS ||
BitCode == bitc::MODULE_CODE_ALIAS_OLD)
NewGA = GlobalAlias::create(
Ty, AddrSpace, getDecodedLinkage(Linkage), "", TheModule);
else
llvm_unreachable("Not an alias!");
// Old bitcode files didn't have visibility field.
// Local linkage must have default visibility.
if (OpNum != Record.size()) {
@ -3698,7 +3705,7 @@ std::error_code BitcodeReader::parseModule(uint64_t ResumeBit,
if (OpNum != Record.size())
NewGA->setUnnamedAddr(Record[OpNum++]);
ValueList.push_back(NewGA);
AliasInits.push_back(std::make_pair(NewGA, Val));
IndirectSymbolInits.push_back(std::make_pair(NewGA, Val));
break;
}
/// MODULE_CODE_PURGEVALS: [numvals]

View File

@ -1060,6 +1060,49 @@ void AsmPrinter::emitGlobalGOTEquivs() {
EmitGlobalVariable(GV);
}
void AsmPrinter::emitGlobalIndirectSymbol(Module &M,
const GlobalIndirectSymbol& GIS) {
MCSymbol *Name = getSymbol(&GIS);
if (GIS.hasExternalLinkage() || !MAI->getWeakRefDirective())
OutStreamer->EmitSymbolAttribute(Name, MCSA_Global);
else if (GIS.hasWeakLinkage() || GIS.hasLinkOnceLinkage())
OutStreamer->EmitSymbolAttribute(Name, MCSA_WeakReference);
else
assert(GIS.hasLocalLinkage() && "Invalid alias linkage");
// Set the symbol type to function if the alias has a function type.
// This affects codegen when the aliasee is not a function.
if (GIS.getType()->getPointerElementType()->isFunctionTy())
OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeFunction);
EmitVisibility(Name, GIS.getVisibility());
const MCExpr *Expr = lowerConstant(GIS.getIndirectSymbol());
if (isa<GlobalAlias>(&GIS) && MAI->hasAltEntry() && isa<MCBinaryExpr>(Expr))
OutStreamer->EmitSymbolAttribute(Name, MCSA_AltEntry);
// Emit the directives as assignments aka .set:
OutStreamer->EmitAssignment(Name, Expr);
if (auto *GA = dyn_cast<GlobalAlias>(&GIS)) {
// If the aliasee does not correspond to a symbol in the output, i.e. the
// alias is not of an object or the aliased object is private, then set the
// size of the alias symbol from the type of the alias. We don't do this in
// other situations as the alias and aliasee having differing types but same
// size may be intentional.
const GlobalObject *BaseObject = GA->getBaseObject();
if (MAI->hasDotTypeDotSizeDirective() && GA->getValueType()->isSized() &&
(!BaseObject || BaseObject->hasPrivateLinkage())) {
const DataLayout &DL = M.getDataLayout();
uint64_t Size = DL.getTypeAllocSize(GA->getValueType());
OutStreamer->emitELFSize(cast<MCSymbolELF>(Name),
MCConstantExpr::create(Size, OutContext));
}
}
}
bool AsmPrinter::doFinalization(Module &M) {
// Set the MachineFunction to nullptr so that we can catch attempted
// accesses to MF specific features at the module level and so that
@ -1148,45 +1191,7 @@ bool AsmPrinter::doFinalization(Module &M) {
}
OutStreamer->AddBlankLine();
const auto printAlias = [this, &M](const GlobalAlias &Alias) {
MCSymbol *Name = getSymbol(&Alias);
if (Alias.hasExternalLinkage() || !MAI->getWeakRefDirective())
OutStreamer->EmitSymbolAttribute(Name, MCSA_Global);
else if (Alias.hasWeakLinkage() || Alias.hasLinkOnceLinkage())
OutStreamer->EmitSymbolAttribute(Name, MCSA_WeakReference);
else
assert(Alias.hasLocalLinkage() && "Invalid alias linkage");
// Set the symbol type to function if the alias has a function type.
// This affects codegen when the aliasee is not a function.
if (Alias.getType()->getPointerElementType()->isFunctionTy())
OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeFunction);
EmitVisibility(Name, Alias.getVisibility());
const MCExpr *Expr = lowerConstant(Alias.getAliasee());
if (MAI->hasAltEntry() && isa<MCBinaryExpr>(Expr))
OutStreamer->EmitSymbolAttribute(Name, MCSA_AltEntry);
// Emit the directives as assignments aka .set:
OutStreamer->EmitAssignment(Name, Expr);
// If the aliasee does not correspond to a symbol in the output, i.e. the
// alias is not of an object or the aliased object is private, then set the
// size of the alias symbol from the type of the alias. We don't do this in
// other situations as the alias and aliasee having differing types but same
// size may be intentional.
const GlobalObject *BaseObject = Alias.getBaseObject();
if (MAI->hasDotTypeDotSizeDirective() && Alias.getValueType()->isSized() &&
(!BaseObject || BaseObject->hasPrivateLinkage())) {
const DataLayout &DL = M.getDataLayout();
uint64_t Size = DL.getTypeAllocSize(Alias.getValueType());
OutStreamer->emitELFSize(cast<MCSymbolELF>(Name),
MCConstantExpr::create(Size, OutContext));
}
};
// Print aliases in topological order, that is, for each alias a = b,
// b must be printed before a.
// This is because on some targets (e.g. PowerPC) linker expects aliases in
@ -1201,7 +1206,7 @@ bool AsmPrinter::doFinalization(Module &M) {
AliasStack.push_back(Cur);
}
for (const GlobalAlias *AncestorAlias : reverse(AliasStack))
printAlias(*AncestorAlias);
emitGlobalIndirectSymbol(M, *AncestorAlias);
AliasStack.clear();
}

View File

@ -2047,7 +2047,7 @@ public:
void printTypeIdentities();
void printGlobal(const GlobalVariable *GV);
void printAlias(const GlobalAlias *GV);
void printIndirectSymbol(const GlobalIndirectSymbol *GIS);
void printComdat(const Comdat *C);
void printFunction(const Function *F);
void printArgument(const Argument *FA, AttributeSet Attrs, unsigned Idx);
@ -2270,7 +2270,7 @@ void AssemblyWriter::printModule(const Module *M) {
// Output all aliases.
if (!M->alias_empty()) Out << "\n";
for (const GlobalAlias &GA : M->aliases())
printAlias(&GA);
printIndirectSymbol(&GA);
// Output global use-lists.
printUseLists(nullptr);
@ -2451,36 +2451,39 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) {
printInfoComment(*GV);
}
void AssemblyWriter::printAlias(const GlobalAlias *GA) {
if (GA->isMaterializable())
void AssemblyWriter::printIndirectSymbol(const GlobalIndirectSymbol *GIS) {
if (GIS->isMaterializable())
Out << "; Materializable\n";
WriteAsOperandInternal(Out, GA, &TypePrinter, &Machine, GA->getParent());
WriteAsOperandInternal(Out, GIS, &TypePrinter, &Machine, GIS->getParent());
Out << " = ";
PrintLinkage(GA->getLinkage(), Out);
PrintVisibility(GA->getVisibility(), Out);
PrintDLLStorageClass(GA->getDLLStorageClass(), Out);
PrintThreadLocalModel(GA->getThreadLocalMode(), Out);
if (GA->hasUnnamedAddr())
PrintLinkage(GIS->getLinkage(), Out);
PrintVisibility(GIS->getVisibility(), Out);
PrintDLLStorageClass(GIS->getDLLStorageClass(), Out);
PrintThreadLocalModel(GIS->getThreadLocalMode(), Out);
if (GIS->hasUnnamedAddr())
Out << "unnamed_addr ";
Out << "alias ";
if (isa<GlobalAlias>(GIS))
Out << "alias ";
else
llvm_unreachable("Not an alias!");
TypePrinter.print(GA->getValueType(), Out);
TypePrinter.print(GIS->getValueType(), Out);
Out << ", ";
const Constant *Aliasee = GA->getAliasee();
const Constant *IS = GIS->getIndirectSymbol();
if (!Aliasee) {
TypePrinter.print(GA->getType(), Out);
if (!IS) {
TypePrinter.print(GIS->getType(), Out);
Out << " <<NULL ALIASEE>>";
} else {
writeOperand(Aliasee, !isa<ConstantExpr>(Aliasee));
writeOperand(IS, !isa<ConstantExpr>(IS));
}
printInfoComment(*GA);
printInfoComment(*GIS);
Out << '\n';
}
@ -3348,7 +3351,7 @@ void Value::print(raw_ostream &ROS, ModuleSlotTracker &MST,
else if (const Function *F = dyn_cast<Function>(GV))
W.printFunction(F);
else
W.printAlias(cast<GlobalAlias>(GV));
W.printIndirectSymbol(cast<GlobalIndirectSymbol>(GV));
} else if (const MetadataAsValue *V = dyn_cast<MetadataAsValue>(this)) {
V->getMetadata()->print(ROS, MST, getModuleFromVal(V));
} else if (const Constant *C = dyn_cast<Constant>(this)) {

View File

@ -159,8 +159,8 @@ bool GlobalValue::isDeclaration() const {
if (const Function *F = dyn_cast<Function>(this))
return F->empty() && !F->isMaterializable();
// Aliases are always definitions.
assert(isa<GlobalAlias>(this));
// Aliases and ifuncs are always definitions.
assert(isa<GlobalIndirectSymbol>(this));
return false;
}

View File

@ -205,9 +205,9 @@ void GlobalDCE::GlobalIsNeeded(GlobalValue *G) {
// referenced by the initializer to the alive set.
if (GV->hasInitializer())
MarkUsedGlobalsAsNeeded(GV->getInitializer());
} else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(G)) {
// The target of a global alias is needed.
MarkUsedGlobalsAsNeeded(GA->getAliasee());
} else if (GlobalIndirectSymbol *GIS = dyn_cast<GlobalIndirectSymbol>(G)) {
// The target of a global alias or ifunc is needed.
MarkUsedGlobalsAsNeeded(GIS->getIndirectSymbol());
} else {
// Otherwise this must be a function object. We have to scan the body of
// the function looking for constants and global values which are used as