summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/docs/LangRef.rst13
-rw-r--r--llvm/include/llvm/IR/Attributes.h41
-rw-r--r--llvm/include/llvm/IR/GlobalVariable.h57
-rw-r--r--llvm/lib/AsmParser/LLParser.cpp18
-rw-r--r--llvm/lib/Bitcode/Reader/BitcodeReader.cpp7
-rw-r--r--llvm/lib/Bitcode/Writer/BitcodeWriter.cpp8
-rw-r--r--llvm/lib/Bitcode/Writer/ValueEnumerator.cpp7
-rw-r--r--llvm/lib/IR/AsmWriter.cpp7
-rw-r--r--llvm/lib/IR/Attributes.cpp66
-rw-r--r--llvm/lib/IR/Globals.cpp1
-rw-r--r--llvm/test/Assembler/globalvariable-attributes.ll19
-rw-r--r--llvm/test/Bitcode/globalvariable-attributes.ll19
12 files changed, 254 insertions, 9 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index dc6350c5520..e7c2888cd0d 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -641,8 +641,9 @@ assume that the globals are densely packed in their section and try to
iterate over them as an array, alignment padding would break this
iteration. The maximum alignment is ``1 << 29``.
-Globals can also have a :ref:`DLL storage class <dllstorageclass>` and
-an optional list of attached :ref:`metadata <metadata>`,
+Globals can also have a :ref:`DLL storage class <dllstorageclass>`,
+an optional :ref:`global attributes <glattrs>` and
+an optional list of attached :ref:`metadata <metadata>`.
Variables and aliases can have a
:ref:`Thread Local Storage Model <tls_model>`.
@@ -1624,6 +1625,14 @@ example:
the ELF x86-64 abi, but it can be disabled for some compilation
units.
+.. _glattrs:
+
+Global Attributes
+-----------------
+
+Attributes may be set to communicate additional information about a global variable.
+Unlike :ref:`function attributes <fnattrs>`, attributes on a global variable
+are grouped into a single :ref:`attribute group <attrgrp>`.
.. _opbundles:
diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
index cbe681684a5..d4a896c0186 100644
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -35,6 +35,7 @@ namespace llvm {
class AttrBuilder;
class AttributeImpl;
class AttributeListImpl;
+class AttributeList;
class AttributeSetNode;
template<typename T> struct DenseMapInfo;
class Function;
@@ -227,14 +228,51 @@ public:
bool operator==(const AttributeSet &O) { return SetNode == O.SetNode; }
bool operator!=(const AttributeSet &O) { return !(*this == O); }
+ /// Add an argument attribute. Because
+ /// attribute sets are immutable, this returns a new set.
+ AttributeSet addAttribute(LLVMContext &C,
+ Attribute::AttrKind Kind) const;
+
+ /// Add a target-dependent attribute. Because
+ /// attribute sets are immutable, this returns a new set.
+ AttributeSet addAttribute(LLVMContext &C, StringRef Kind,
+ StringRef Value = StringRef()) const;
+
+ /// Add attributes to the attribute set. Because
+ /// attribute sets are immutable, this returns a new set.
+ AttributeSet addAttributes(LLVMContext &C, AttributeSet AS) const;
+
+ /// Remove the specified attribute from this set. Because
+ /// attribute sets are immutable, this returns a new set.
+ AttributeSet removeAttribute(LLVMContext &C,
+ Attribute::AttrKind Kind) const;
+
+ /// Remove the specified attribute from this set. Because
+ /// attribute sets are immutable, this returns a new set.
+ AttributeSet removeAttribute(LLVMContext &C,
+ StringRef Kind) const;
+
+ /// Remove the specified attributes from this set. Because
+ /// attribute sets are immutable, this returns a new set.
+ AttributeSet removeAttributes(LLVMContext &C,
+ const AttrBuilder &AttrsToRemove) const;
+
+ /// Return the number of attributes in this set.
unsigned getNumAttributes() const;
+ /// Return true if attributes exists in this set.
bool hasAttributes() const { return SetNode != nullptr; }
+ /// Return true if the attribute exists in this set.
bool hasAttribute(Attribute::AttrKind Kind) const;
+
+ /// Return true if the attribute exists in this set.
bool hasAttribute(StringRef Kind) const;
+ /// Return the attribute object.
Attribute getAttribute(Attribute::AttrKind Kind) const;
+
+ /// Return the target-dependent attribute object.
Attribute getAttribute(StringRef Kind) const;
unsigned getAlignment() const;
@@ -248,6 +286,9 @@ public:
iterator begin() const;
iterator end() const;
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ void dump() const;
+#endif
};
//===----------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/IR/GlobalVariable.h b/llvm/include/llvm/IR/GlobalVariable.h
index 3b545d811d4..c25e08059ce 100644
--- a/llvm/include/llvm/IR/GlobalVariable.h
+++ b/llvm/include/llvm/IR/GlobalVariable.h
@@ -24,6 +24,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/ilist_node.h"
#include "llvm/IR/GlobalObject.h"
+#include "llvm/IR/Attributes.h"
#include "llvm/IR/OperandTraits.h"
#include "llvm/IR/Value.h"
#include <cassert>
@@ -41,6 +42,7 @@ class DIGlobalVariableExpression;
class GlobalVariable : public GlobalObject, public ilist_node<GlobalVariable> {
friend class SymbolTableListTraits<GlobalVariable>;
+ AttributeSet Attrs;
bool isConstantGlobal : 1; // Is this a global constant?
bool isExternallyInitializedConstant : 1; // Is this a global whose value
// can change from its initial
@@ -178,6 +180,61 @@ public:
/// Fill the vector with all debug info attachements.
void getDebugInfo(SmallVectorImpl<DIGlobalVariableExpression *> &GVs) const;
+ /// Add attribute to this global.
+ void addAttribute(Attribute::AttrKind Kind) {
+ Attrs = Attrs.addAttribute(getContext(), Kind);
+ }
+
+ /// Add attribute to this global.
+ void addAttribute(StringRef Kind, StringRef Val = StringRef()) {
+ Attrs = Attrs.addAttribute(getContext(), Kind, Val);
+ }
+
+ /// Return true if the attribute exists.
+ bool hasAttribute(Attribute::AttrKind Kind) const {
+ return Attrs.hasAttribute(Kind);
+ }
+
+ /// Return true if the attribute exists.
+ bool hasAttribute(StringRef Kind) const {
+ return Attrs.hasAttribute(Kind);
+ }
+
+ /// Return true if any attributes exist.
+ bool hasAttributes() const {
+ return Attrs.hasAttributes();
+ }
+
+ /// Return the attribute object.
+ Attribute getAttribute(Attribute::AttrKind Kind) const {
+ return Attrs.getAttribute(Kind);
+ }
+
+ /// Return the attribute object.
+ Attribute getAttribute(StringRef Kind) const {
+ return Attrs.getAttribute(Kind);
+ }
+
+ /// Return the attribute set for this global
+ AttributeSet getAttributes() const {
+ return Attrs;
+ }
+
+ /// Return attribute set as list with index.
+ /// FIXME: This may not be required once ValueEnumerators
+ /// in bitcode-writer can enumerate attribute-set.
+ AttributeList getAttributesAsList(unsigned index) const {
+ if (!hasAttributes())
+ return AttributeList();
+ std::pair<unsigned, AttributeSet> AS[1] = {{index, Attrs}};
+ return AttributeList::get(getContext(), AS);
+ }
+
+ /// Set attribute list for this global
+ void setAttributes(AttributeSet A) {
+ Attrs = A;
+ }
+
// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const Value *V) {
return V->getValueID() == Value::GlobalVariableVal;
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 97a567565b4..d7602c83435 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -162,6 +162,10 @@ bool LLParser::ValidateEndOfModule() {
AS = AS.addAttributes(Context, AttributeList::FunctionIndex,
AttributeSet::get(Context, FnAttrs));
II->setAttributes(AS);
+ } else if (auto *GV = dyn_cast<GlobalVariable>(V)) {
+ AttrBuilder Attrs(GV->getAttributes());
+ Attrs.merge(B);
+ GV->setAttributes(AttributeSet::get(Context,Attrs));
} else {
llvm_unreachable("invalid object with forward attribute group reference");
}
@@ -832,10 +836,10 @@ bool LLParser::parseIndirectSymbol(
/// ParseGlobal
/// ::= GlobalVar '=' OptionalLinkage OptionalVisibility OptionalDLLStorageClass
/// OptionalThreadLocal OptionalUnnamedAddr OptionalAddrSpace
-/// OptionalExternallyInitialized GlobalType Type Const
+/// OptionalExternallyInitialized GlobalType Type Const OptionalAttrs
/// ::= OptionalLinkage OptionalVisibility OptionalDLLStorageClass
/// OptionalThreadLocal OptionalUnnamedAddr OptionalAddrSpace
-/// OptionalExternallyInitialized GlobalType Type Const
+/// OptionalExternallyInitialized GlobalType Type Const OptionalAttrs
///
/// Everything up to and including OptionalUnnamedAddr has been parsed
/// already.
@@ -950,6 +954,16 @@ bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc,
}
}
+ AttrBuilder Attrs;
+ LocTy BuiltinLoc;
+ std::vector<unsigned> FwdRefAttrGrps;
+ if (ParseFnAttributeValuePairs(Attrs, FwdRefAttrGrps, false, BuiltinLoc))
+ return true;
+ if (Attrs.hasAttributes() || !FwdRefAttrGrps.empty()) {
+ GV->setAttributes(AttributeSet::get(Context, Attrs));
+ ForwardRefAttrGroups[GV] = FwdRefAttrGrps;
+ }
+
return false;
}
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 580261a3b5e..900d718b00b 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2750,7 +2750,7 @@ Error BitcodeReader::parseComdatRecord(ArrayRef<uint64_t> Record) {
Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
// v1: [pointer type, isconst, initid, linkage, alignment, section,
// visibility, threadlocal, unnamed_addr, externally_initialized,
- // dllstorageclass, comdat] (name in VST)
+ // dllstorageclass, comdat, attributes] (name in VST)
// v2: [strtab_offset, strtab_size, v1]
StringRef Name;
std::tie(Name, Record) = readNameFromStrtab(Record);
@@ -2830,6 +2830,11 @@ Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
} else if (hasImplicitComdat(RawLinkage)) {
NewGV->setComdat(reinterpret_cast<Comdat *>(1));
}
+
+ if (Record.size() > 12) {
+ auto AS = getAttributes(Record[12]).getFnAttributes();
+ NewGV->setAttributes(AS);
+ }
return Error::success();
}
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 1b8d81a6020..1f8b50342c2 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -1109,7 +1109,7 @@ void ModuleBitcodeWriter::writeModuleInfo() {
// GLOBALVAR: [strtab offset, strtab size, type, isconst, initid,
// linkage, alignment, section, visibility, threadlocal,
// unnamed_addr, externally_initialized, dllstorageclass,
- // comdat]
+ // comdat, attributes]
Vals.push_back(StrtabBuilder.add(GV.getName()));
Vals.push_back(GV.getName().size());
Vals.push_back(VE.getTypeID(GV.getValueType()));
@@ -1124,13 +1124,17 @@ void ModuleBitcodeWriter::writeModuleInfo() {
GV.getUnnamedAddr() != GlobalValue::UnnamedAddr::None ||
GV.isExternallyInitialized() ||
GV.getDLLStorageClass() != GlobalValue::DefaultStorageClass ||
- GV.hasComdat()) {
+ GV.hasComdat() ||
+ GV.hasAttributes()) {
Vals.push_back(getEncodedVisibility(GV));
Vals.push_back(getEncodedThreadLocalMode(GV));
Vals.push_back(getEncodedUnnamedAddr(GV));
Vals.push_back(GV.isExternallyInitialized());
Vals.push_back(getEncodedDLLStorageClass(GV));
Vals.push_back(GV.hasComdat() ? VE.getComdatID(GV.getComdat()) : 0);
+
+ auto AL = GV.getAttributesAsList(AttributeList::FunctionIndex);
+ Vals.push_back(VE.getAttributeListID(AL));
} else {
AbbrevToUse = SimpleGVarAbbrev;
}
diff --git a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
index 86115076698..fd76400331d 100644
--- a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
+++ b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
@@ -314,10 +314,13 @@ ValueEnumerator::ValueEnumerator(const Module &M,
// Remember what is the cutoff between globalvalue's and other constants.
unsigned FirstConstant = Values.size();
- // Enumerate the global variable initializers.
- for (const GlobalVariable &GV : M.globals())
+ // Enumerate the global variable initializers and attributes.
+ for (const GlobalVariable &GV : M.globals()) {
if (GV.hasInitializer())
EnumerateValue(GV.getInitializer());
+ if (GV.hasAttributes())
+ EnumerateAttributes(GV.getAttributesAsList(AttributeList::FunctionIndex));
+ }
// Enumerate the aliasees.
for (const GlobalAlias &GA : M.aliases())
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index 4c6e3e3788b..ec4663018bd 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -805,6 +805,9 @@ void SlotTracker::processModule() {
if (!Var.hasName())
CreateModuleSlot(&Var);
processGlobalObjectMetadata(Var);
+ auto Attrs = Var.getAttributes();
+ if (Attrs.hasAttributes())
+ CreateAttributeSetSlot(Attrs);
}
for (const GlobalAlias &A : TheModule->aliases()) {
@@ -2502,6 +2505,10 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) {
GV->getAllMetadata(MDs);
printMetadataAttachments(MDs, ", ");
+ auto Attrs = GV->getAttributes();
+ if (Attrs.hasAttributes())
+ Out << " #" << Machine.getAttributeGroupSlot(Attrs);
+
printInfoComment(*GV);
}
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 3b1140ab542..b97afb6f4a6 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -504,6 +504,64 @@ AttributeSet AttributeSet::get(LLVMContext &C, ArrayRef<Attribute> Attrs) {
return AttributeSet(AttributeSetNode::get(C, Attrs));
}
+AttributeSet AttributeSet::addAttribute(LLVMContext &C,
+ Attribute::AttrKind Kind) const {
+ if (hasAttribute(Kind)) return *this;
+ AttrBuilder B;
+ B.addAttribute(Kind);
+ return addAttributes(C, AttributeSet::get(C, B));
+}
+
+AttributeSet AttributeSet::addAttribute(LLVMContext &C, StringRef Kind,
+ StringRef Value) const {
+ AttrBuilder B;
+ B.addAttribute(Kind, Value);
+ return addAttributes(C, AttributeSet::get(C, B));
+}
+
+AttributeSet AttributeSet::addAttributes(LLVMContext &C,
+ const AttributeSet AS) const {
+ if (!hasAttributes())
+ return AS;
+
+ if (!AS.hasAttributes())
+ return *this;
+
+ AttrBuilder B(AS);
+ for (Attribute I : *this)
+ B.addAttribute(I);
+
+ return get(C, B);
+}
+
+AttributeSet AttributeSet::removeAttribute(LLVMContext &C,
+ Attribute::AttrKind Kind) const {
+ if (!hasAttribute(Kind)) return *this;
+ AttrBuilder B;
+ B.addAttribute(Kind);
+ return removeAttributes(C, B);
+}
+
+AttributeSet AttributeSet::removeAttribute(LLVMContext &C,
+ StringRef Kind) const {
+ if (!hasAttribute(Kind)) return *this;
+ AttrBuilder B;
+ B.addAttribute(Kind);
+ return removeAttributes(C, B);
+}
+
+AttributeSet AttributeSet::removeAttributes(LLVMContext &C,
+ const AttrBuilder &Attrs) const {
+
+ // FIXME it is not obvious how this should work for alignment.
+ // For now, say we can't pass in alignment, which no current use does.
+ assert(!Attrs.hasAlignmentAttr() && "Attempt to change alignment!");
+
+ AttrBuilder B(*this);
+ B.remove(Attrs);
+ return get(C, B);
+}
+
unsigned AttributeSet::getNumAttributes() const {
return SetNode ? SetNode->getNumAttributes() : 0;
}
@@ -557,6 +615,14 @@ AttributeSet::iterator AttributeSet::end() const {
return SetNode ? SetNode->end() : nullptr;
}
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void AttributeSet::dump() const {
+ dbgs() << "AS =\n";
+ dbgs() << " { ";
+ dbgs() << getAsString(true) << " }\n";
+}
+#endif
+
//===----------------------------------------------------------------------===//
// AttributeSetNode Definition
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/IR/Globals.cpp b/llvm/lib/IR/Globals.cpp
index 5f338f58d94..5fbf51e0089 100644
--- a/llvm/lib/IR/Globals.cpp
+++ b/llvm/lib/IR/Globals.cpp
@@ -338,6 +338,7 @@ void GlobalVariable::copyAttributesFrom(const GlobalValue *Src) {
if (const GlobalVariable *SrcVar = dyn_cast<GlobalVariable>(Src)) {
setThreadLocalMode(SrcVar->getThreadLocalMode());
setExternallyInitialized(SrcVar->isExternallyInitialized());
+ setAttributes(SrcVar->getAttributes());
}
}
diff --git a/llvm/test/Assembler/globalvariable-attributes.ll b/llvm/test/Assembler/globalvariable-attributes.ll
new file mode 100644
index 00000000000..64227a451c2
--- /dev/null
+++ b/llvm/test/Assembler/globalvariable-attributes.ll
@@ -0,0 +1,19 @@
+; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
+
+@g1 = global i32 7 "key" = "value" "key2" = "value2"
+@g2 = global i32 2, align 4 "key3" = "value3"
+@g3 = global i32 2 #0
+@g4 = global i32 2, align 4 "key5" = "value5" #0
+
+attributes #0 = { "string" = "value" nobuiltin norecurse }
+
+; CHECK: @g1 = global i32 7 #0
+; CHECK: @g2 = global i32 2, align 4 #1
+; CHECK: @g3 = global i32 2 #2
+; CHECK: @g4 = global i32 2, align 4 #3
+
+; CHECK: attributes #0 = { "key"="value" "key2"="value2" }
+; CHECK: attributes #1 = { "key3"="value3" }
+; CHECK: attributes #2 = { nobuiltin norecurse "string"="value" }
+; CHECK: attributes #3 = { nobuiltin norecurse "key5"="value5" "string"="value" }
+
diff --git a/llvm/test/Bitcode/globalvariable-attributes.ll b/llvm/test/Bitcode/globalvariable-attributes.ll
new file mode 100644
index 00000000000..cbab3b71e58
--- /dev/null
+++ b/llvm/test/Bitcode/globalvariable-attributes.ll
@@ -0,0 +1,19 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+
+@g1 = global i32 7 "key" = "value" "key2" = "value2"
+@g2 = global i32 2, align 4 "key3" = "value3"
+@g3 = global i32 2 #0
+@g4 = global i32 2, align 4 "key5" = "value5" #0
+
+attributes #0 = { "string" = "value" nobuiltin norecurse }
+
+; CHECK: @g1 = global i32 7 #0
+; CHECK: @g2 = global i32 2, align 4 #1
+; CHECK: @g3 = global i32 2 #2
+; CHECK: @g4 = global i32 2, align 4 #3
+
+; CHECK: attributes #0 = { "key"="value" "key2"="value2" }
+; CHECK: attributes #1 = { "key3"="value3" }
+; CHECK: attributes #2 = { nobuiltin norecurse "string"="value" }
+; CHECK: attributes #3 = { nobuiltin norecurse "key5"="value5" "string"="value" }
+
OpenPOWER on IntegriCloud