llvm.org GIT mirror llvm / a8ddcaa
[IR] Allow attributes with global variables This patch extends llvm-ir to allow attributes to be set on global variables. An RFC was sent out earlier by my colleague James Molloy: http://lists.llvm.org/pipermail/cfe-dev/2017-March/053100.html A key part of that proposal was to extend LLVM-IR to carry attributes on global variables. This generic feature could be useful for multiple purposes. In our present context, it would be useful to carry user specified sections for bss/rodata/data. Reviewed by: Jonathan Roelofs, Reid Kleckner Differential Revision: https://reviews.llvm.org/D32009 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@302794 91177308-0d34-0410-b5e6-96231b3b80d8 Javed Absar 3 years ago
12 changed file(s) with 254 addition(s) and 9 deletion(s). Raw diff Collapse all Expand all
640640 iterate over them as an array, alignment padding would break this
641641 iteration. The maximum alignment is ``1 << 29``.
642642
643 Globals can also have a :ref:`DLL storage class ` and
644 an optional list of attached :ref:`metadata >`,
643 Globals can also have a :ref:`DLL storage class >`,
644 an optional :ref:`global attributes ` and
645 an optional list of attached :ref:`metadata `.
645646
646647 Variables and aliases can have a
647648 :ref:`Thread Local Storage Model `.
16231624 the ELF x86-64 abi, but it can be disabled for some compilation
16241625 units.
16251626
1627 .. _glattrs:
1628
1629 Global Attributes
1630 -----------------
1631
1632 Attributes may be set to communicate additional information about a global variable.
1633 Unlike :ref:`function attributes `, attributes on a global variable
1634 are grouped into a single :ref:`attribute group `.
16261635
16271636 .. _opbundles:
16281637
3434 class AttrBuilder;
3535 class AttributeImpl;
3636 class AttributeListImpl;
37 class AttributeList;
3738 class AttributeSetNode;
3839 template struct DenseMapInfo;
3940 class Function;
226227 bool operator==(const AttributeSet &O) { return SetNode == O.SetNode; }
227228 bool operator!=(const AttributeSet &O) { return !(*this == O); }
228229
230 /// Add an argument attribute. Because
231 /// attribute sets are immutable, this returns a new set.
232 AttributeSet addAttribute(LLVMContext &C,
233 Attribute::AttrKind Kind) const;
234
235 /// Add a target-dependent attribute. Because
236 /// attribute sets are immutable, this returns a new set.
237 AttributeSet addAttribute(LLVMContext &C, StringRef Kind,
238 StringRef Value = StringRef()) const;
239
240 /// Add attributes to the attribute set. Because
241 /// attribute sets are immutable, this returns a new set.
242 AttributeSet addAttributes(LLVMContext &C, AttributeSet AS) const;
243
244 /// Remove the specified attribute from this set. Because
245 /// attribute sets are immutable, this returns a new set.
246 AttributeSet removeAttribute(LLVMContext &C,
247 Attribute::AttrKind Kind) const;
248
249 /// Remove the specified attribute from this set. Because
250 /// attribute sets are immutable, this returns a new set.
251 AttributeSet removeAttribute(LLVMContext &C,
252 StringRef Kind) const;
253
254 /// Remove the specified attributes from this set. Because
255 /// attribute sets are immutable, this returns a new set.
256 AttributeSet removeAttributes(LLVMContext &C,
257 const AttrBuilder &AttrsToRemove) const;
258
259 /// Return the number of attributes in this set.
229260 unsigned getNumAttributes() const;
230261
262 /// Return true if attributes exists in this set.
231263 bool hasAttributes() const { return SetNode != nullptr; }
232264
265 /// Return true if the attribute exists in this set.
233266 bool hasAttribute(Attribute::AttrKind Kind) const;
267
268 /// Return true if the attribute exists in this set.
234269 bool hasAttribute(StringRef Kind) const;
235270
271 /// Return the attribute object.
236272 Attribute getAttribute(Attribute::AttrKind Kind) const;
273
274 /// Return the target-dependent attribute object.
237275 Attribute getAttribute(StringRef Kind) const;
238276
239277 unsigned getAlignment() const;
247285
248286 iterator begin() const;
249287 iterator end() const;
288 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
289 void dump() const;
290 #endif
250291 };
251292
252293 //===----------------------------------------------------------------------===//
2323 #include "llvm/ADT/Twine.h"
2424 #include "llvm/ADT/ilist_node.h"
2525 #include "llvm/IR/GlobalObject.h"
26 #include "llvm/IR/Attributes.h"
2627 #include "llvm/IR/OperandTraits.h"
2728 #include "llvm/IR/Value.h"
2829 #include
4041 class GlobalVariable : public GlobalObject, public ilist_node {
4142 friend class SymbolTableListTraits;
4243
44 AttributeSet Attrs;
4345 bool isConstantGlobal : 1; // Is this a global constant?
4446 bool isExternallyInitializedConstant : 1; // Is this a global whose value
4547 // can change from its initial
177179 /// Fill the vector with all debug info attachements.
178180 void getDebugInfo(SmallVectorImpl &GVs) const;
179181
182 /// Add attribute to this global.
183 void addAttribute(Attribute::AttrKind Kind) {
184 Attrs = Attrs.addAttribute(getContext(), Kind);
185 }
186
187 /// Add attribute to this global.
188 void addAttribute(StringRef Kind, StringRef Val = StringRef()) {
189 Attrs = Attrs.addAttribute(getContext(), Kind, Val);
190 }
191
192 /// Return true if the attribute exists.
193 bool hasAttribute(Attribute::AttrKind Kind) const {
194 return Attrs.hasAttribute(Kind);
195 }
196
197 /// Return true if the attribute exists.
198 bool hasAttribute(StringRef Kind) const {
199 return Attrs.hasAttribute(Kind);
200 }
201
202 /// Return true if any attributes exist.
203 bool hasAttributes() const {
204 return Attrs.hasAttributes();
205 }
206
207 /// Return the attribute object.
208 Attribute getAttribute(Attribute::AttrKind Kind) const {
209 return Attrs.getAttribute(Kind);
210 }
211
212 /// Return the attribute object.
213 Attribute getAttribute(StringRef Kind) const {
214 return Attrs.getAttribute(Kind);
215 }
216
217 /// Return the attribute set for this global
218 AttributeSet getAttributes() const {
219 return Attrs;
220 }
221
222 /// Return attribute set as list with index.
223 /// FIXME: This may not be required once ValueEnumerators
224 /// in bitcode-writer can enumerate attribute-set.
225 AttributeList getAttributesAsList(unsigned index) const {
226 if (!hasAttributes())
227 return AttributeList();
228 std::pair AS[1] = {{index, Attrs}};
229 return AttributeList::get(getContext(), AS);
230 }
231
232 /// Set attribute list for this global
233 void setAttributes(AttributeSet A) {
234 Attrs = A;
235 }
236
180237 // Methods for support type inquiry through isa, cast, and dyn_cast:
181238 static inline bool classof(const Value *V) {
182239 return V->getValueID() == Value::GlobalVariableVal;
161161 AS = AS.addAttributes(Context, AttributeList::FunctionIndex,
162162 AttributeSet::get(Context, FnAttrs));
163163 II->setAttributes(AS);
164 } else if (auto *GV = dyn_cast(V)) {
165 AttrBuilder Attrs(GV->getAttributes());
166 Attrs.merge(B);
167 GV->setAttributes(AttributeSet::get(Context,Attrs));
164168 } else {
165169 llvm_unreachable("invalid object with forward attribute group reference");
166170 }
831835 /// ParseGlobal
832836 /// ::= GlobalVar '=' OptionalLinkage OptionalVisibility OptionalDLLStorageClass
833837 /// OptionalThreadLocal OptionalUnnamedAddr OptionalAddrSpace
834 /// OptionalExternallyInitialized GlobalType Type Const
838 /// OptionalExternallyInitialized GlobalType Type Const OptionalAttrs
835839 /// ::= OptionalLinkage OptionalVisibility OptionalDLLStorageClass
836840 /// OptionalThreadLocal OptionalUnnamedAddr OptionalAddrSpace
837 /// OptionalExternallyInitialized GlobalType Type Const
841 /// OptionalExternallyInitialized GlobalType Type Const OptionalAttrs
838842 ///
839843 /// Everything up to and including OptionalUnnamedAddr has been parsed
840844 /// already.
947951 else
948952 return TokError("unknown global variable property!");
949953 }
954 }
955
956 AttrBuilder Attrs;
957 LocTy BuiltinLoc;
958 std::vector FwdRefAttrGrps;
959 if (ParseFnAttributeValuePairs(Attrs, FwdRefAttrGrps, false, BuiltinLoc))
960 return true;
961 if (Attrs.hasAttributes() || !FwdRefAttrGrps.empty()) {
962 GV->setAttributes(AttributeSet::get(Context, Attrs));
963 ForwardRefAttrGroups[GV] = FwdRefAttrGrps;
950964 }
951965
952966 return false;
27492749 Error BitcodeReader::parseGlobalVarRecord(ArrayRef Record) {
27502750 // v1: [pointer type, isconst, initid, linkage, alignment, section,
27512751 // visibility, threadlocal, unnamed_addr, externally_initialized,
2752 // dllstorageclass, comdat] (name in VST)
2752 // dllstorageclass, comdat, attributes] (name in VST)
27532753 // v2: [strtab_offset, strtab_size, v1]
27542754 StringRef Name;
27552755 std::tie(Name, Record) = readNameFromStrtab(Record);
28282828 }
28292829 } else if (hasImplicitComdat(RawLinkage)) {
28302830 NewGV->setComdat(reinterpret_cast(1));
2831 }
2832
2833 if (Record.size() > 12) {
2834 auto AS = getAttributes(Record[12]).getFnAttributes();
2835 NewGV->setAttributes(AS);
28312836 }
28322837 return Error::success();
28332838 }
11081108 // GLOBALVAR: [strtab offset, strtab size, type, isconst, initid,
11091109 // linkage, alignment, section, visibility, threadlocal,
11101110 // unnamed_addr, externally_initialized, dllstorageclass,
1111 // comdat]
1111 // comdat, attributes]
11121112 Vals.push_back(StrtabBuilder.add(GV.getName()));
11131113 Vals.push_back(GV.getName().size());
11141114 Vals.push_back(VE.getTypeID(GV.getValueType()));
11231123 GV.getUnnamedAddr() != GlobalValue::UnnamedAddr::None ||
11241124 GV.isExternallyInitialized() ||
11251125 GV.getDLLStorageClass() != GlobalValue::DefaultStorageClass ||
1126 GV.hasComdat()) {
1126 GV.hasComdat() ||
1127 GV.hasAttributes()) {
11271128 Vals.push_back(getEncodedVisibility(GV));
11281129 Vals.push_back(getEncodedThreadLocalMode(GV));
11291130 Vals.push_back(getEncodedUnnamedAddr(GV));
11301131 Vals.push_back(GV.isExternallyInitialized());
11311132 Vals.push_back(getEncodedDLLStorageClass(GV));
11321133 Vals.push_back(GV.hasComdat() ? VE.getComdatID(GV.getComdat()) : 0);
1134
1135 auto AL = GV.getAttributesAsList(AttributeList::FunctionIndex);
1136 Vals.push_back(VE.getAttributeListID(AL));
11331137 } else {
11341138 AbbrevToUse = SimpleGVarAbbrev;
11351139 }
313313 // Remember what is the cutoff between globalvalue's and other constants.
314314 unsigned FirstConstant = Values.size();
315315
316 // Enumerate the global variable initializers.
317 for (const GlobalVariable &GV : M.globals())
316 // Enumerate the global variable initializers and attributes.
317 for (const GlobalVariable &GV : M.globals()) {
318318 if (GV.hasInitializer())
319319 EnumerateValue(GV.getInitializer());
320 if (GV.hasAttributes())
321 EnumerateAttributes(GV.getAttributesAsList(AttributeList::FunctionIndex));
322 }
320323
321324 // Enumerate the aliasees.
322325 for (const GlobalAlias &GA : M.aliases())
804804 if (!Var.hasName())
805805 CreateModuleSlot(&Var);
806806 processGlobalObjectMetadata(Var);
807 auto Attrs = Var.getAttributes();
808 if (Attrs.hasAttributes())
809 CreateAttributeSetSlot(Attrs);
807810 }
808811
809812 for (const GlobalAlias &A : TheModule->aliases()) {
25012504 GV->getAllMetadata(MDs);
25022505 printMetadataAttachments(MDs, ", ");
25032506
2507 auto Attrs = GV->getAttributes();
2508 if (Attrs.hasAttributes())
2509 Out << " #" << Machine.getAttributeGroupSlot(Attrs);
2510
25042511 printInfoComment(*GV);
25052512 }
25062513
503503 return AttributeSet(AttributeSetNode::get(C, Attrs));
504504 }
505505
506 AttributeSet AttributeSet::addAttribute(LLVMContext &C,
507 Attribute::AttrKind Kind) const {
508 if (hasAttribute(Kind)) return *this;
509 AttrBuilder B;
510 B.addAttribute(Kind);
511 return addAttributes(C, AttributeSet::get(C, B));
512 }
513
514 AttributeSet AttributeSet::addAttribute(LLVMContext &C, StringRef Kind,
515 StringRef Value) const {
516 AttrBuilder B;
517 B.addAttribute(Kind, Value);
518 return addAttributes(C, AttributeSet::get(C, B));
519 }
520
521 AttributeSet AttributeSet::addAttributes(LLVMContext &C,
522 const AttributeSet AS) const {
523 if (!hasAttributes())
524 return AS;
525
526 if (!AS.hasAttributes())
527 return *this;
528
529 AttrBuilder B(AS);
530 for (Attribute I : *this)
531 B.addAttribute(I);
532
533 return get(C, B);
534 }
535
536 AttributeSet AttributeSet::removeAttribute(LLVMContext &C,
537 Attribute::AttrKind Kind) const {
538 if (!hasAttribute(Kind)) return *this;
539 AttrBuilder B;
540 B.addAttribute(Kind);
541 return removeAttributes(C, B);
542 }
543
544 AttributeSet AttributeSet::removeAttribute(LLVMContext &C,
545 StringRef Kind) const {
546 if (!hasAttribute(Kind)) return *this;
547 AttrBuilder B;
548 B.addAttribute(Kind);
549 return removeAttributes(C, B);
550 }
551
552 AttributeSet AttributeSet::removeAttributes(LLVMContext &C,
553 const AttrBuilder &Attrs) const {
554
555 // FIXME it is not obvious how this should work for alignment.
556 // For now, say we can't pass in alignment, which no current use does.
557 assert(!Attrs.hasAlignmentAttr() && "Attempt to change alignment!");
558
559 AttrBuilder B(*this);
560 B.remove(Attrs);
561 return get(C, B);
562 }
563
506564 unsigned AttributeSet::getNumAttributes() const {
507565 return SetNode ? SetNode->getNumAttributes() : 0;
508566 }
555613 AttributeSet::iterator AttributeSet::end() const {
556614 return SetNode ? SetNode->end() : nullptr;
557615 }
616
617 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
618 LLVM_DUMP_METHOD void AttributeSet::dump() const {
619 dbgs() << "AS =\n";
620 dbgs() << " { ";
621 dbgs() << getAsString(true) << " }\n";
622 }
623 #endif
558624
559625 //===----------------------------------------------------------------------===//
560626 // AttributeSetNode Definition
337337 if (const GlobalVariable *SrcVar = dyn_cast(Src)) {
338338 setThreadLocalMode(SrcVar->getThreadLocalMode());
339339 setExternallyInitialized(SrcVar->isExternallyInitialized());
340 setAttributes(SrcVar->getAttributes());
340341 }
341342 }
342343
0 ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
1
2 @g1 = global i32 7 "key" = "value" "key2" = "value2"
3 @g2 = global i32 2, align 4 "key3" = "value3"
4 @g3 = global i32 2 #0
5 @g4 = global i32 2, align 4 "key5" = "value5" #0
6
7 attributes #0 = { "string" = "value" nobuiltin norecurse }
8
9 ; CHECK: @g1 = global i32 7 #0
10 ; CHECK: @g2 = global i32 2, align 4 #1
11 ; CHECK: @g3 = global i32 2 #2
12 ; CHECK: @g4 = global i32 2, align 4 #3
13
14 ; CHECK: attributes #0 = { "key"="value" "key2"="value2" }
15 ; CHECK: attributes #1 = { "key3"="value3" }
16 ; CHECK: attributes #2 = { nobuiltin norecurse "string"="value" }
17 ; CHECK: attributes #3 = { nobuiltin norecurse "key5"="value5" "string"="value" }
18
0 ; RUN: llvm-as < %s | llvm-dis | FileCheck %s
1
2 @g1 = global i32 7 "key" = "value" "key2" = "value2"
3 @g2 = global i32 2, align 4 "key3" = "value3"
4 @g3 = global i32 2 #0
5 @g4 = global i32 2, align 4 "key5" = "value5" #0
6
7 attributes #0 = { "string" = "value" nobuiltin norecurse }
8
9 ; CHECK: @g1 = global i32 7 #0
10 ; CHECK: @g2 = global i32 2, align 4 #1
11 ; CHECK: @g3 = global i32 2 #2
12 ; CHECK: @g4 = global i32 2, align 4 #3
13
14 ; CHECK: attributes #0 = { "key"="value" "key2"="value2" }
15 ; CHECK: attributes #1 = { "key3"="value3" }
16 ; CHECK: attributes #2 = { nobuiltin norecurse "string"="value" }
17 ; CHECK: attributes #3 = { nobuiltin norecurse "key5"="value5" "string"="value" }
18