diff --git a/llvm/docs/BitCodeFormat.rst b/llvm/docs/BitCodeFormat.rst --- a/llvm/docs/BitCodeFormat.rst +++ b/llvm/docs/BitCodeFormat.rst @@ -749,6 +749,7 @@ * not ``unnamed_addr``: code 0 * ``unnamed_addr``: code 1 * ``local_unnamed_addr``: code 2 + * ``significant_addr``: code 3 .. _bcdllstorageclass: diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -652,6 +652,14 @@ If the ``local_unnamed_addr`` attribute is given, the address is known to not be significant within the module. +If the ``significant_addr`` attribute is given, the address is known to be +significant throughout the whole optimization process. + +By default, a global vairable is unspecified by +``unnamed_addr/local_unnamed_addr/significant_addr`` is significant but subject +to change to ``unnamed_addr/local_unnamed_addr`` depend on if it has local +linkage. + 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 @@ -712,8 +720,8 @@ @ = [Linkage] [PreemptionSpecifier] [Visibility] [DLLStorageClass] [ThreadLocal] - [(unnamed_addr|local_unnamed_addr)] [AddrSpace] - [ExternallyInitialized] + [(unnamed_addr|local_unnamed_addr|significant_addr)] + [AddrSpace] [ExternallyInitialized] [] [, section "name"] [, comdat [($name)]] [, align ] (, !name !N)* @@ -763,12 +771,13 @@ LLVM function declarations consist of the "``declare``" keyword, an optional :ref:`linkage type `, an optional :ref:`visibility style `, an optional :ref:`DLL storage class `, an -optional :ref:`calling convention `, an optional ``unnamed_addr`` -or ``local_unnamed_addr`` attribute, an optional address space, a return type, -an optional :ref:`parameter attribute ` for the return type, a function name, a possibly -empty list of arguments, an optional alignment, an optional :ref:`garbage -collector name `, an optional :ref:`prefix `, and an optional -:ref:`prologue `. +optional :ref:`calling convention `, an optional +``unnamed_addr/local_unnamed_addr/significant_addr`` attribute, +an optional address space, a return type, an optional +:ref:`parameter attribute ` for the return type, a function name, a +possibly empty list of arguments, an optional alignment, an optional +:ref:`garbage collector name `, an optional :ref:`prefix `, and +an optional :ref:`prologue `. A function definition contains a list of basic blocks, forming the CFG (Control Flow Graph) for the function. Each basic block may optionally start with a label @@ -804,6 +813,9 @@ If the ``local_unnamed_addr`` attribute is given, the address is known to not be significant within the module. +If the ``significant_addr`` attribute is given, the address is known to be +significant and cannot be changed during optimization. + If an explicit address space is not given, it will default to the program address space from the :ref:`datalayout string`. @@ -812,7 +824,7 @@ define [linkage] [PreemptionSpecifier] [visibility] [DLLStorageClass] [cconv] [ret attrs] @ ([argument list]) - [(unnamed_addr|local_unnamed_addr)] [AddrSpace] [fn Attrs] + [(unnamed_addr|local_unnamed_addr|significant_addr)] [AddrSpace] [fn Attrs] [section "name"] [comdat [($name)]] [align N] [gc] [prefix Constant] [prologue Constant] [personality Constant] (!name !N)* { ... } @@ -853,7 +865,7 @@ to the same content. If the ``local_unnamed_addr`` attribute is given, the address is known to -not be significant within the module. +not be significant within the module. Alias cannot have ``significant_addr``. Since aliases are only a second name, some restrictions apply, of which some can only be checked when producing an object file: diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h --- a/llvm/include/llvm-c/Core.h +++ b/llvm/include/llvm-c/Core.h @@ -196,7 +196,8 @@ } LLVMVisibility; typedef enum { - LLVMNoUnnamedAddr, /**< Address of the GV is significant. */ + LLVMSignificantAddr, /**< Address of the GV is significant (specified). */ + LLVMNoUnnamedAddr, /**< Address of the GV is significant (default). */ LLVMLocalUnnamedAddr, /**< Address of the GV is locally insignificant. */ LLVMGlobalUnnamedAddr /**< Address of the GV is globally insignificant. */ } LLVMUnnamedAddr; diff --git a/llvm/include/llvm/IR/GlobalValue.h b/llvm/include/llvm/IR/GlobalValue.h --- a/llvm/include/llvm/IR/GlobalValue.h +++ b/llvm/include/llvm/IR/GlobalValue.h @@ -188,6 +188,7 @@ unsigned getAddressSpace() const; enum class UnnamedAddr { + Significant, None, Local, Global, @@ -197,13 +198,18 @@ return getUnnamedAddr() == UnnamedAddr::Global; } + bool hasSignificantAddr() const { + return getUnnamedAddr() == UnnamedAddr::Significant; + } + /// Returns true if this value's address is not significant in this module. /// This attribute is intended to be used only by the code generator and LTO /// to allow the linker to decide whether the global needs to be in the symbol /// table. It should probably not be used in optimizations, as the value may /// have uses outside the module; use hasGlobalUnnamedAddr() instead. bool hasAtLeastLocalUnnamedAddr() const { - return getUnnamedAddr() != UnnamedAddr::None; + return getUnnamedAddr() != UnnamedAddr::None && + getUnnamedAddr() != UnnamedAddr::Significant; } UnnamedAddr getUnnamedAddr() const { @@ -212,6 +218,8 @@ void setUnnamedAddr(UnnamedAddr Val) { UnnamedAddrVal = unsigned(Val); } static UnnamedAddr getMinUnnamedAddr(UnnamedAddr A, UnnamedAddr B) { + if (A == UnnamedAddr::Significant || B == UnnamedAddr::Significant) + return UnnamedAddr::Significant; if (A == UnnamedAddr::None || B == UnnamedAddr::None) return UnnamedAddr::None; if (A == UnnamedAddr::Local || B == UnnamedAddr::Local) diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -520,6 +520,7 @@ KEYWORD(protected); KEYWORD(unnamed_addr); KEYWORD(local_unnamed_addr); + KEYWORD(significant_addr); KEYWORD(externally_initialized); KEYWORD(extern_weak); KEYWORD(external); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -590,6 +590,8 @@ UnnamedAddr = GlobalValue::UnnamedAddr::Global; else if (EatIfPresent(lltok::kw_local_unnamed_addr)) UnnamedAddr = GlobalValue::UnnamedAddr::Local; + else if (EatIfPresent(lltok::kw_significant_addr)) + UnnamedAddr = GlobalValue::UnnamedAddr::Significant; else UnnamedAddr = GlobalValue::UnnamedAddr::None; return false; diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -65,6 +65,7 @@ kw_protected, kw_unnamed_addr, kw_local_unnamed_addr, + kw_significant_addr, kw_externally_initialized, kw_extern_weak, kw_external, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1044,6 +1044,8 @@ case 0: return GlobalVariable::UnnamedAddr::None; case 1: return GlobalVariable::UnnamedAddr::Global; case 2: return GlobalVariable::UnnamedAddr::Local; + case 3: + return GlobalVariable::UnnamedAddr::Significant; } } diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1120,6 +1120,8 @@ case GlobalValue::UnnamedAddr::None: return 0; case GlobalValue::UnnamedAddr::Local: return 2; case GlobalValue::UnnamedAddr::Global: return 1; + case GlobalValue::UnnamedAddr::Significant: + return 3; } llvm_unreachable("Invalid unnamed_addr"); } diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -3493,6 +3493,8 @@ return "local_unnamed_addr"; case GlobalVariable::UnnamedAddr::Global: return "unnamed_addr"; + case GlobalVariable::UnnamedAddr::Significant: + return "significant_addr"; } llvm_unreachable("Unknown UnnamedAddr"); } diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -1991,6 +1991,8 @@ LLVMUnnamedAddr LLVMGetUnnamedAddress(LLVMValueRef Global) { switch (unwrap(Global)->getUnnamedAddr()) { + case GlobalVariable::UnnamedAddr::Significant: + return LLVMSignificantAddr; case GlobalVariable::UnnamedAddr::None: return LLVMNoUnnamedAddr; case GlobalVariable::UnnamedAddr::Local: @@ -2005,6 +2007,8 @@ GlobalValue *GV = unwrap(Global); switch (UnnamedAddr) { + case LLVMSignificantAddr: + return GV->setUnnamedAddr(GlobalVariable::UnnamedAddr::Significant); case LLVMNoUnnamedAddr: return GV->setUnnamedAddr(GlobalVariable::UnnamedAddr::None); case LLVMLocalUnnamedAddr: diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -584,6 +584,10 @@ Assert(!GV.isDeclaration() || GV.hasValidDeclarationLinkage(), "Global is external, but doesn't have external or weak linkage!", &GV); + if (const GlobalAlias *GA = dyn_cast(&GV)) + Assert(!GA->hasSignificantAddr(), "Aliases cannot have significant address", + GA); + if (const GlobalObject *GO = dyn_cast(&GV)) Assert(GO->getAlignment() <= Value::MaximumAlignment, "huge alignment values are unsupported", GO); diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp --- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -2107,9 +2107,11 @@ return false; bool Changed = false; - if (!GS.IsCompared && !GV.hasGlobalUnnamedAddr()) { - auto NewUnnamedAddr = GV.hasLocalLinkage() ? GlobalValue::UnnamedAddr::Global - : GlobalValue::UnnamedAddr::Local; + if (!GS.IsCompared && !GV.hasGlobalUnnamedAddr() && + !GV.hasSignificantAddr()) { + auto NewUnnamedAddr = GV.hasLocalLinkage() + ? GlobalValue::UnnamedAddr::Global + : GlobalValue::UnnamedAddr::Local; if (NewUnnamedAddr != GV.getUnnamedAddr()) { GV.setUnnamedAddr(NewUnnamedAddr); NumUnnamed++; diff --git a/llvm/test/Assembler/significant-addr.ll b/llvm/test/Assembler/significant-addr.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Assembler/significant-addr.ll @@ -0,0 +1,13 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s +; RUN: verify-uselistorder %s + +; CHECK: @c = significant_addr constant i32 0 +@c = significant_addr constant i32 0 + +; CHECK: declare void @g() significant_addr +declare void @g() significant_addr + +; CHECK: define void @f() significant_addr { +define void @f() significant_addr { + ret void +} diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll --- a/llvm/test/Bitcode/compatibility.ll +++ b/llvm/test/Bitcode/compatibility.ll @@ -80,7 +80,7 @@ ;; Global Variables ; Format: [@ =] [Linkage] [Visibility] [DLLStorageClass] -; [ThreadLocal] [(unnamed_addr|local_unnamed_addr)] [AddrSpace] [ExternallyInitialized] +; [ThreadLocal] [(unnamed_addr|local_unnamed_addr|significant_addr)] [AddrSpace] [ExternallyInitialized] ; [] ; [, section "name"] [, comdat [($name)]] [, align ] @@ -142,11 +142,13 @@ @g.localexec = thread_local(localexec) global i32 0 ; CHECK: @g.localexec = thread_local(localexec) global i32 0 -; Global Variables -- unnamed_addr and local_unnamed_addr +; Global Variables -- unnamed_addr, local_unnamed_addr and significant_addr @g.unnamed_addr = unnamed_addr global i32 0 ; CHECK: @g.unnamed_addr = unnamed_addr global i32 0 @g.local_unnamed_addr = local_unnamed_addr global i32 0 ; CHECK: @g.local_unnamed_addr = local_unnamed_addr global i32 0 +@g.significant_addr = significant_addr global i32 0 +; CHECK: @g.significant_addr = significant_addr global i32 0 ; Global Variables -- AddrSpace @g.addrspace = addrspace(1) global i32 0 @@ -292,7 +294,7 @@ ; Format: define [linkage] [visibility] [DLLStorageClass] ; [cconv] [ret attrs] ; @ ([argument list]) -; [(unnamed_addr|local_unnamed_addr)] [fn Attrs] [section "name"] [comdat [($name)]] +; [(unnamed_addr|local_unnamed_addr|significant_addr)] [fn Attrs] [section "name"] [comdat [($name)]] ; [align N] [gc] [prefix Constant] [prologue Constant] ; [personality Constant] { ... } @@ -551,11 +553,13 @@ declare void @f.param.dereferenceable_or_null(i8* dereferenceable_or_null(4)) ; CHECK: declare void @f.param.dereferenceable_or_null(i8* dereferenceable_or_null(4)) -; Functions -- unnamed_addr and local_unnamed_addr +; Functions -- unnamed_addr, local_unnamed_addr and significant_addr declare void @f.unnamed_addr() unnamed_addr ; CHECK: declare void @f.unnamed_addr() unnamed_addr declare void @f.local_unnamed_addr() local_unnamed_addr ; CHECK: declare void @f.local_unnamed_addr() local_unnamed_addr +declare void @f.significant_addr() significant_addr +; CHECK: declare void @f.significant_addr() significant_addr ; Functions -- fn Attrs (Function attributes) declare void @f.alignstack4() alignstack(4) diff --git a/llvm/test/Verifier/alias.ll b/llvm/test/Verifier/alias.ll --- a/llvm/test/Verifier/alias.ll +++ b/llvm/test/Verifier/alias.ll @@ -31,3 +31,7 @@ @test3_c = alias i32, i32* @test3_b ; CHECK: Alias cannot point to an interposable alias ; CHECK-NEXT: i32* @test3_c + +@test4_a = global i32 42 +@test4_b = significant_addr alias i32, i32* @test4_a +; CHECK: Aliases cannot have significant address