mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 04:30:23 +00:00
First step in fixing PR8927:
Add a unnamed_addr bit to global variables and functions. This will be used to indicate that the address is not significant and therefore the constant or function can be merged with others. If an optimization pass can show that an address is not used, it can set this. Examples of things that can have this set by the FE are globals created to hold string literals and C++ constructors. Adding unnamed_addr to a non-const global should have no effect unless an optimization can transform that global into a constant. Aliases are not allowed to have unnamed_addr since I couldn't figure out any use for it. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@123063 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
8368ac3688
commit
bea4626f93
@ -922,6 +922,9 @@ encoding of the visibility of this variable:
|
||||
<li><i>threadlocal</i>: If present and non-zero, indicates that the variable
|
||||
is <tt>thread_local</tt></li>
|
||||
|
||||
<li><i>unnamed_addr</i>: If present and non-zero, indicates that the variable
|
||||
has <tt>unnamed_addr<tt></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@ -975,6 +978,10 @@ entries.</li>
|
||||
<li><i>gc</i>: If present and nonzero, the 1-based garbage collector
|
||||
index in the table of
|
||||
<a href="#MODULE_CODE_GCNAME">MODULE_CODE_GCNAME</a> entries.</li>
|
||||
|
||||
<li><i>unnamed_addr</i>: If present and non-zero, indicates that the function
|
||||
has <tt>unnamed_addr<tt></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
@ -846,6 +846,10 @@ define i32 @main() { <i>; i32()* </i>
|
||||
region of memory, and all memory objects in LLVM are accessed through
|
||||
pointers.</p>
|
||||
|
||||
<p>Global variables can be marked with <tt>unnamed_addr</tt> which indicates
|
||||
that the address is not significant, only the content. Constants marked
|
||||
like this can be merged if they have the same content.</p>
|
||||
|
||||
<p>A global variable may be declared to reside in a target-specific numbered
|
||||
address space. For targets that support them, address spaces may affect how
|
||||
optimizations are performed and/or what target instructions are used to
|
||||
@ -885,7 +889,8 @@ define i32 @main() { <i>; i32()* </i>
|
||||
<p>LLVM function definitions consist of the "<tt>define</tt>" keyword, an
|
||||
optional <a href="#linkage">linkage type</a>, an optional
|
||||
<a href="#visibility">visibility style</a>, an optional
|
||||
<a href="#callingconv">calling convention</a>, a return type, an optional
|
||||
<a href="#callingconv">calling convention</a>,
|
||||
an optional <tt>unnamed_addr</tt> attribute, a return type, an optional
|
||||
<a href="#paramattrs">parameter attribute</a> for the return type, a function
|
||||
name, a (possibly empty) argument list (each with optional
|
||||
<a href="#paramattrs">parameter attributes</a>), optional
|
||||
@ -896,7 +901,8 @@ define i32 @main() { <i>; i32()* </i>
|
||||
<p>LLVM function declarations consist of the "<tt>declare</tt>" keyword, an
|
||||
optional <a href="#linkage">linkage type</a>, an optional
|
||||
<a href="#visibility">visibility style</a>, an optional
|
||||
<a href="#callingconv">calling convention</a>, a return type, an optional
|
||||
<a href="#callingconv">calling convention</a>,
|
||||
an optional <tt>unnamed_addr</tt> attribute, a return type, an optional
|
||||
<a href="#paramattrs">parameter attribute</a> for the return type, a function
|
||||
name, a possibly empty list of arguments, an optional alignment, and an
|
||||
optional <a href="#gc">garbage collector name</a>.</p>
|
||||
@ -922,6 +928,9 @@ define i32 @main() { <i>; i32()* </i>
|
||||
specified, the function is forced to have at least that much alignment. All
|
||||
alignments must be a power of 2.</p>
|
||||
|
||||
<p>If the <tt>unnamed_addr</tt> attribute is given, the address is know to not
|
||||
be significant and two identical functions can be merged</p>.
|
||||
|
||||
<h5>Syntax:</h5>
|
||||
<pre class="doc_code">
|
||||
define [<a href="#linkage">linkage</a>] [<a href="#visibility">visibility</a>]
|
||||
|
@ -60,7 +60,8 @@ protected:
|
||||
GlobalValue(const Type *ty, ValueTy vty, Use *Ops, unsigned NumOps,
|
||||
LinkageTypes linkage, const Twine &Name)
|
||||
: Constant(ty, vty, Ops, NumOps), Parent(0),
|
||||
Linkage(linkage), Visibility(DefaultVisibility), Alignment(0) {
|
||||
Linkage(linkage), Visibility(DefaultVisibility), Alignment(0),
|
||||
UnnamedAddr(0) {
|
||||
setName(Name);
|
||||
}
|
||||
|
||||
@ -70,6 +71,7 @@ protected:
|
||||
LinkageTypes Linkage : 5; // The linkage of this global
|
||||
unsigned Visibility : 2; // The visibility style of this global
|
||||
unsigned Alignment : 16; // Alignment of this symbol, must be power of two
|
||||
unsigned UnnamedAddr : 1; // This value's address is not significant
|
||||
std::string Section; // Section to emit this into, empty mean default
|
||||
public:
|
||||
~GlobalValue() {
|
||||
@ -81,6 +83,9 @@ public:
|
||||
}
|
||||
void setAlignment(unsigned Align);
|
||||
|
||||
bool hasUnnamedAddr() const { return UnnamedAddr; }
|
||||
void setUnnamedAddr(bool Val) { UnnamedAddr = Val; }
|
||||
|
||||
VisibilityTypes getVisibility() const { return VisibilityTypes(Visibility); }
|
||||
bool hasDefaultVisibility() const { return Visibility == DefaultVisibility; }
|
||||
bool hasHiddenVisibility() const { return Visibility == HiddenVisibility; }
|
||||
|
@ -509,6 +509,7 @@ lltok::Kind LLLexer::LexIdentifier() {
|
||||
KEYWORD(default);
|
||||
KEYWORD(hidden);
|
||||
KEYWORD(protected);
|
||||
KEYWORD(unnamed_addr);
|
||||
KEYWORD(extern_weak);
|
||||
KEYWORD(external);
|
||||
KEYWORD(thread_local);
|
||||
|
@ -194,7 +194,8 @@ bool LLParser::ParseTopLevelEntities() {
|
||||
// The Global variable production with no name can have many different
|
||||
// optional leading prefixes, the production is:
|
||||
// GlobalVar ::= OptionalLinkage OptionalVisibility OptionalThreadLocal
|
||||
// OptionalAddrSpace ('constant'|'global') ...
|
||||
// OptionalAddrSpace OptionalUnNammedAddr
|
||||
// ('constant'|'global') ...
|
||||
case lltok::kw_private: // OptionalLinkage
|
||||
case lltok::kw_linker_private: // OptionalLinkage
|
||||
case lltok::kw_linker_private_weak: // OptionalLinkage
|
||||
@ -682,9 +683,9 @@ bool LLParser::ParseAlias(const std::string &Name, LocTy NameLoc,
|
||||
|
||||
/// ParseGlobal
|
||||
/// ::= GlobalVar '=' OptionalLinkage OptionalVisibility OptionalThreadLocal
|
||||
/// OptionalAddrSpace GlobalType Type Const
|
||||
/// OptionalAddrSpace OptionalUnNammedAddr GlobalType Type Const
|
||||
/// ::= OptionalLinkage OptionalVisibility OptionalThreadLocal
|
||||
/// OptionalAddrSpace GlobalType Type Const
|
||||
/// OptionalAddrSpace OptionalUnNammedAddr GlobalType Type Const
|
||||
///
|
||||
/// Everything through visibility has been parsed already.
|
||||
///
|
||||
@ -692,12 +693,13 @@ bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc,
|
||||
unsigned Linkage, bool HasLinkage,
|
||||
unsigned Visibility) {
|
||||
unsigned AddrSpace;
|
||||
bool ThreadLocal, IsConstant;
|
||||
bool ThreadLocal, IsConstant, UnnamedAddr;
|
||||
LocTy TyLoc;
|
||||
|
||||
PATypeHolder Ty(Type::getVoidTy(Context));
|
||||
if (ParseOptionalToken(lltok::kw_thread_local, ThreadLocal) ||
|
||||
ParseOptionalAddrSpace(AddrSpace) ||
|
||||
ParseOptionalToken(lltok::kw_unnamed_addr, UnnamedAddr) ||
|
||||
ParseGlobalType(IsConstant) ||
|
||||
ParseType(Ty, TyLoc))
|
||||
return true;
|
||||
@ -755,6 +757,7 @@ bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc,
|
||||
GV->setLinkage((GlobalValue::LinkageTypes)Linkage);
|
||||
GV->setVisibility((GlobalValue::VisibilityTypes)Visibility);
|
||||
GV->setThreadLocal(ThreadLocal);
|
||||
GV->setUnnamedAddr(UnnamedAddr);
|
||||
|
||||
// Parse attributes on the global.
|
||||
while (Lex.getKind() == lltok::comma) {
|
||||
@ -2657,7 +2660,7 @@ bool LLParser::ParseTypeAndBasicBlock(BasicBlock *&BB, LocTy &Loc,
|
||||
|
||||
/// FunctionHeader
|
||||
/// ::= OptionalLinkage OptionalVisibility OptionalCallingConv OptRetAttrs
|
||||
/// Type GlobalName '(' ArgList ')' OptFuncAttrs OptSection
|
||||
/// OptUnnamedAddr Type GlobalName '(' ArgList ')' OptFuncAttrs OptSection
|
||||
/// OptionalAlign OptGC
|
||||
bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
|
||||
// Parse the linkage.
|
||||
@ -2665,6 +2668,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
|
||||
unsigned Linkage;
|
||||
|
||||
unsigned Visibility, RetAttrs;
|
||||
bool UnnamedAddr;
|
||||
CallingConv::ID CC;
|
||||
PATypeHolder RetType(Type::getVoidTy(Context));
|
||||
LocTy RetTypeLoc = Lex.getLoc();
|
||||
@ -2672,6 +2676,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
|
||||
ParseOptionalVisibility(Visibility) ||
|
||||
ParseOptionalCallingConv(CC) ||
|
||||
ParseOptionalAttrs(RetAttrs, 1) ||
|
||||
ParseOptionalToken(lltok::kw_unnamed_addr, UnnamedAddr) ||
|
||||
ParseType(RetType, RetTypeLoc, true /*void allowed*/))
|
||||
return true;
|
||||
|
||||
@ -2841,6 +2846,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
|
||||
Fn->setVisibility((GlobalValue::VisibilityTypes)Visibility);
|
||||
Fn->setCallingConv(CC);
|
||||
Fn->setAttributes(PAL);
|
||||
Fn->setUnnamedAddr(UnnamedAddr);
|
||||
Fn->setAlignment(Alignment);
|
||||
Fn->setSection(Section);
|
||||
if (!GC.empty()) Fn->setGC(GC.c_str());
|
||||
|
@ -42,6 +42,7 @@ namespace lltok {
|
||||
kw_linkonce, kw_linkonce_odr, kw_weak, kw_weak_odr, kw_appending,
|
||||
kw_dllimport, kw_dllexport, kw_common, kw_available_externally,
|
||||
kw_default, kw_hidden, kw_protected,
|
||||
kw_unnamed_addr,
|
||||
kw_extern_weak,
|
||||
kw_external, kw_thread_local,
|
||||
kw_zeroinitializer,
|
||||
|
@ -1422,7 +1422,8 @@ bool BitcodeReader::ParseModule() {
|
||||
break;
|
||||
}
|
||||
// GLOBALVAR: [pointer type, isconst, initid,
|
||||
// linkage, alignment, section, visibility, threadlocal]
|
||||
// linkage, alignment, section, visibility, threadlocal,
|
||||
// unnamed_addr]
|
||||
case bitc::MODULE_CODE_GLOBALVAR: {
|
||||
if (Record.size() < 6)
|
||||
return Error("Invalid MODULE_CODE_GLOBALVAR record");
|
||||
@ -1449,6 +1450,10 @@ bool BitcodeReader::ParseModule() {
|
||||
if (Record.size() > 7)
|
||||
isThreadLocal = Record[7];
|
||||
|
||||
bool UnnamedAddr = false;
|
||||
if (Record.size() > 8)
|
||||
UnnamedAddr = Record[8];
|
||||
|
||||
GlobalVariable *NewGV =
|
||||
new GlobalVariable(*TheModule, Ty, isConstant, Linkage, 0, "", 0,
|
||||
isThreadLocal, AddressSpace);
|
||||
@ -1457,6 +1462,7 @@ bool BitcodeReader::ParseModule() {
|
||||
NewGV->setSection(Section);
|
||||
NewGV->setVisibility(Visibility);
|
||||
NewGV->setThreadLocal(isThreadLocal);
|
||||
NewGV->setUnnamedAddr(UnnamedAddr);
|
||||
|
||||
ValueList.push_back(NewGV);
|
||||
|
||||
@ -1466,7 +1472,7 @@ bool BitcodeReader::ParseModule() {
|
||||
break;
|
||||
}
|
||||
// FUNCTION: [type, callingconv, isproto, linkage, paramattr,
|
||||
// alignment, section, visibility, gc]
|
||||
// alignment, section, visibility, gc, unnamed_addr]
|
||||
case bitc::MODULE_CODE_FUNCTION: {
|
||||
if (Record.size() < 8)
|
||||
return Error("Invalid MODULE_CODE_FUNCTION record");
|
||||
@ -1499,6 +1505,10 @@ bool BitcodeReader::ParseModule() {
|
||||
return Error("Invalid GC ID");
|
||||
Func->setGC(GCTable[Record[8]-1].c_str());
|
||||
}
|
||||
bool UnnamedAddr = false;
|
||||
if (Record.size() > 9)
|
||||
UnnamedAddr = Record[9];
|
||||
Func->setUnnamedAddr(UnnamedAddr);
|
||||
ValueList.push_back(Func);
|
||||
|
||||
// If this is a function with a body, remember the prototype we are
|
||||
|
@ -404,7 +404,8 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
|
||||
unsigned AbbrevToUse = 0;
|
||||
|
||||
// GLOBALVAR: [type, isconst, initid,
|
||||
// linkage, alignment, section, visibility, threadlocal]
|
||||
// linkage, alignment, section, visibility, threadlocal,
|
||||
// unnamed_addr]
|
||||
Vals.push_back(VE.getTypeID(GV->getType()));
|
||||
Vals.push_back(GV->isConstant());
|
||||
Vals.push_back(GV->isDeclaration() ? 0 :
|
||||
@ -413,9 +414,11 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
|
||||
Vals.push_back(Log2_32(GV->getAlignment())+1);
|
||||
Vals.push_back(GV->hasSection() ? SectionMap[GV->getSection()] : 0);
|
||||
if (GV->isThreadLocal() ||
|
||||
GV->getVisibility() != GlobalValue::DefaultVisibility) {
|
||||
GV->getVisibility() != GlobalValue::DefaultVisibility ||
|
||||
GV->hasUnnamedAddr()) {
|
||||
Vals.push_back(getEncodedVisibility(GV));
|
||||
Vals.push_back(GV->isThreadLocal());
|
||||
Vals.push_back(GV->hasUnnamedAddr());
|
||||
} else {
|
||||
AbbrevToUse = SimpleGVarAbbrev;
|
||||
}
|
||||
@ -427,7 +430,7 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
|
||||
// Emit the function proto information.
|
||||
for (Module::const_iterator F = M->begin(), E = M->end(); F != E; ++F) {
|
||||
// FUNCTION: [type, callingconv, isproto, paramattr,
|
||||
// linkage, alignment, section, visibility, gc]
|
||||
// linkage, alignment, section, visibility, gc, unnamed_addr]
|
||||
Vals.push_back(VE.getTypeID(F->getType()));
|
||||
Vals.push_back(F->getCallingConv());
|
||||
Vals.push_back(F->isDeclaration());
|
||||
@ -437,6 +440,7 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
|
||||
Vals.push_back(F->hasSection() ? SectionMap[F->getSection()] : 0);
|
||||
Vals.push_back(getEncodedVisibility(F));
|
||||
Vals.push_back(F->hasGC() ? GCMap[F->getGC()] : 0);
|
||||
Vals.push_back(F->hasUnnamedAddr());
|
||||
|
||||
unsigned AbbrevToUse = 0;
|
||||
Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse);
|
||||
|
@ -1459,6 +1459,7 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) {
|
||||
if (GV->isThreadLocal()) Out << "thread_local ";
|
||||
if (unsigned AddressSpace = GV->getType()->getAddressSpace())
|
||||
Out << "addrspace(" << AddressSpace << ") ";
|
||||
if (GV->hasUnnamedAddr()) Out << "unnamed_addr ";
|
||||
Out << (GV->isConstant() ? "constant " : "global ");
|
||||
TypePrinter.print(GV->getType()->getElementType(), Out);
|
||||
|
||||
@ -1589,6 +1590,8 @@ void AssemblyWriter::printFunction(const Function *F) {
|
||||
Attributes RetAttrs = Attrs.getRetAttributes();
|
||||
if (RetAttrs != Attribute::None)
|
||||
Out << Attribute::getAsString(Attrs.getRetAttributes()) << ' ';
|
||||
if (F->hasUnnamedAddr())
|
||||
Out << "unnamed_addr ";
|
||||
TypePrinter.print(F->getReturnType(), Out);
|
||||
Out << ' ';
|
||||
WriteAsOperandInternal(Out, F, &TypePrinter, &Machine, F->getParent());
|
||||
|
@ -484,6 +484,7 @@ void Verifier::visitGlobalAlias(GlobalAlias &GA) {
|
||||
"Aliasee cannot be NULL!", &GA);
|
||||
Assert1(GA.getType() == GA.getAliasee()->getType(),
|
||||
"Alias and aliasee types should match!", &GA);
|
||||
Assert1(!GA.hasUnnamedAddr(), "Alias cannot have unnamed_addr!", &GA);
|
||||
|
||||
if (!isa<GlobalValue>(GA.getAliasee())) {
|
||||
const ConstantExpr *CE = dyn_cast<ConstantExpr>(GA.getAliasee());
|
||||
|
18
test/Assembler/unnamed-addr.ll
Normal file
18
test/Assembler/unnamed-addr.ll
Normal file
@ -0,0 +1,18 @@
|
||||
; RUN: llvm-as < %s | llvm-dis | FileCheck %s
|
||||
|
||||
%struct.foobar = type { i32 }
|
||||
|
||||
@bar.d = internal unnamed_addr constant %struct.foobar zeroinitializer, align 4
|
||||
@foo.d = internal constant %struct.foobar zeroinitializer, align 4
|
||||
|
||||
define unnamed_addr i32 @main() nounwind ssp {
|
||||
entry:
|
||||
%call2 = tail call i32 @zed(%struct.foobar* @foo.d, %struct.foobar* @bar.d) nounwind
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
declare i32 @zed(%struct.foobar*, %struct.foobar*)
|
||||
|
||||
; CHECK: @bar.d = internal unnamed_addr constant %struct.foobar zeroinitializer, align 4
|
||||
; CHECK: @foo.d = internal constant %struct.foobar zeroinitializer, align 4
|
||||
; CHECK: define unnamed_addr i32 @main() nounwind ssp {
|
@ -10,8 +10,11 @@
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/GlobalAlias.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "gtest/gtest.h"
|
||||
@ -41,5 +44,22 @@ TEST(VerifierTest, Branch_i1) {
|
||||
EXPECT_TRUE(verifyFunction(*F, ReturnStatusAction));
|
||||
}
|
||||
|
||||
TEST(VerifierTest, AliasUnnamedAddr) {
|
||||
LLVMContext &C = getGlobalContext();
|
||||
Module M("M", C);
|
||||
const Type *Ty = Type::getInt8Ty(C);
|
||||
Constant *Init = Constant::getNullValue(Ty);
|
||||
GlobalVariable *Aliasee = new GlobalVariable(M, Ty, true,
|
||||
GlobalValue::ExternalLinkage,
|
||||
Init, "foo");
|
||||
GlobalAlias *GA = new GlobalAlias(Type::getInt8PtrTy(C),
|
||||
GlobalValue::ExternalLinkage,
|
||||
"bar", Aliasee, &M);
|
||||
GA->setUnnamedAddr(true);
|
||||
std::string Error;
|
||||
EXPECT_TRUE(verifyModule(M, ReturnStatusAction, &Error));
|
||||
EXPECT_TRUE(StringRef(Error).startswith("Alias cannot have unnamed_addr"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user