Skip to content

Commit a8874cf

Browse files
authored
[llvm][IR] Add per-global code model attribute (#72077)
This adds a per-global code model attribute, which can override the target's code model to access global variables. Suggested-by: Arthur Eubanks <[email protected]> Link: https://discourse.llvm.org/t/how-to-best-implement-code-model-overriding-for-certain-values/71816 Link: https://discourse.llvm.org/t/rfc-add-per-global-code-model-attribute/74944
1 parent 192439d commit a8874cf

File tree

13 files changed

+156
-2
lines changed

13 files changed

+156
-2
lines changed

llvm/docs/LangRef.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,13 @@ information. Attaching section information to an external declaration is an
705705
assertion that its definition is located in the specified section. If the
706706
definition is located in a different section, the behavior is undefined.
707707

708+
LLVM allows an explicit code model to be specified for globals. If the
709+
target supports it, it will emit globals in the code model specified,
710+
overriding the code model used to compile the translation unit.
711+
The allowed values are "tiny", "small", "kernel", "medium", "large".
712+
This may be extended in the future to specify global data layout that
713+
doesn't cleanly fit into a specific code model.
714+
708715
By default, global initializers are optimized by assuming that global
709716
variables defined within the module are not modified from their
710717
initial values before the start of the global initializer. This is
@@ -761,6 +768,7 @@ Syntax::
761768
<global | constant> <Type> [<InitializerConstant>]
762769
[, section "name"] [, partition "name"]
763770
[, comdat [($name)]] [, align <Alignment>]
771+
[, code_model "model"]
764772
[, no_sanitize_address] [, no_sanitize_hwaddress]
765773
[, sanitize_address_dyninit] [, sanitize_memtag]
766774
(, !name !N)*
@@ -778,6 +786,13 @@ The following example just declares a global variable
778786

779787
@G = external global i32
780788

789+
The following example defines a global variable with the
790+
``large`` code model:
791+
792+
.. code-block:: llvm
793+
794+
@G = internal global i32 0, code_model "large"
795+
781796
The following example defines a thread-local global with the
782797
``initialexec`` TLS model:
783798

llvm/include/llvm/AsmParser/LLParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ namespace llvm {
290290
bool parseOptionalCallingConv(unsigned &CC);
291291
bool parseOptionalAlignment(MaybeAlign &Alignment,
292292
bool AllowParens = false);
293+
bool parseOptionalCodeModel(CodeModel::Model &model);
293294
bool parseOptionalDerefAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes);
294295
bool parseOptionalUWTableKind(UWTableKind &Kind);
295296
bool parseAllocKind(AllocFnKind &Kind);

llvm/include/llvm/AsmParser/LLToken.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ enum Kind {
116116
kw_addrspace,
117117
kw_section,
118118
kw_partition,
119+
kw_code_model,
119120
kw_alias,
120121
kw_ifunc,
121122
kw_module,

llvm/include/llvm/IR/GlobalObject.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class GlobalObject : public GlobalValue {
5151
Comdat *ObjComdat = nullptr;
5252
enum {
5353
LastAlignmentBit = 5,
54+
LastCodeModelBit = 8,
5455
HasSectionHashEntryBit,
5556

5657
GlobalObjectBits,

llvm/include/llvm/IR/GlobalVariable.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ class GlobalVariable : public GlobalObject, public ilist_node<GlobalVariable> {
4747
// global initializers are run?
4848
bool isExternallyInitializedConstant : 1;
4949

50+
private:
51+
static const unsigned CodeModelBits = LastCodeModelBit - LastAlignmentBit;
52+
static const unsigned CodeModelMask = (1 << CodeModelBits) - 1;
53+
static const unsigned CodeModelShift = LastAlignmentBit + 1;
54+
5055
public:
5156
/// GlobalVariable ctor - If a parent module is specified, the global is
5257
/// automatically inserted into the end of the specified modules global list.
@@ -247,6 +252,28 @@ class GlobalVariable : public GlobalObject, public ilist_node<GlobalVariable> {
247252
getAttributes().hasAttribute("rodata-section");
248253
}
249254

255+
/// Get the custom code model raw value of this global.
256+
///
257+
unsigned getCodeModelRaw() const {
258+
unsigned Data = getGlobalValueSubClassData();
259+
return (Data >> CodeModelShift) & CodeModelMask;
260+
}
261+
262+
/// Get the custom code model of this global if it has one.
263+
///
264+
/// If this global does not have a custom code model, the empty instance
265+
/// will be returned.
266+
std::optional<CodeModel::Model> getCodeModel() const {
267+
unsigned CodeModelData = getCodeModelRaw();
268+
if (CodeModelData > 0)
269+
return static_cast<CodeModel::Model>(CodeModelData - 1);
270+
return {};
271+
}
272+
273+
/// Change the code model for this global.
274+
///
275+
void setCodeModel(CodeModel::Model CM);
276+
250277
// Methods for support type inquiry through isa, cast, and dyn_cast:
251278
static bool classof(const Value *V) {
252279
return V->getValueID() == Value::GlobalVariableVal;

llvm/lib/AsmParser/LLLexer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,7 @@ lltok::Kind LLLexer::LexIdentifier() {
571571
KEYWORD(addrspace);
572572
KEYWORD(section);
573573
KEYWORD(partition);
574+
KEYWORD(code_model);
574575
KEYWORD(alias);
575576
KEYWORD(ifunc);
576577
KEYWORD(module);

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,6 +1286,11 @@ bool LLParser::parseGlobal(const std::string &Name, LocTy NameLoc,
12861286
return true;
12871287
if (Alignment)
12881288
GV->setAlignment(*Alignment);
1289+
} else if (Lex.getKind() == lltok::kw_code_model) {
1290+
CodeModel::Model CodeModel;
1291+
if (parseOptionalCodeModel(CodeModel))
1292+
return true;
1293+
GV->setCodeModel(CodeModel);
12891294
} else if (Lex.getKind() == lltok::MetadataVar) {
12901295
if (parseGlobalObjectMetadataAttachment(*GV))
12911296
return true;
@@ -2168,6 +2173,30 @@ bool LLParser::parseOptionalAlignment(MaybeAlign &Alignment, bool AllowParens) {
21682173
return false;
21692174
}
21702175

2176+
/// parseOptionalCodeModel
2177+
/// ::= /* empty */
2178+
/// ::= 'code_model' "large"
2179+
bool LLParser::parseOptionalCodeModel(CodeModel::Model &model) {
2180+
Lex.Lex();
2181+
auto StrVal = Lex.getStrVal();
2182+
auto ErrMsg = "expected global code model string";
2183+
if (StrVal == "tiny")
2184+
model = CodeModel::Tiny;
2185+
else if (StrVal == "small")
2186+
model = CodeModel::Small;
2187+
else if (StrVal == "kernel")
2188+
model = CodeModel::Kernel;
2189+
else if (StrVal == "medium")
2190+
model = CodeModel::Medium;
2191+
else if (StrVal == "large")
2192+
model = CodeModel::Large;
2193+
else
2194+
return tokError(ErrMsg);
2195+
if (parseToken(lltok::StringConstant, ErrMsg))
2196+
return true;
2197+
return false;
2198+
}
2199+
21712200
/// parseOptionalDerefAttrBytes
21722201
/// ::= /* empty */
21732202
/// ::= AttrKind '(' 4 ')'

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,23 @@ static bool getDecodedDSOLocal(unsigned Val) {
11441144
}
11451145
}
11461146

1147+
static std::optional<CodeModel::Model> getDecodedCodeModel(unsigned Val) {
1148+
switch (Val) {
1149+
case 1:
1150+
return CodeModel::Tiny;
1151+
case 2:
1152+
return CodeModel::Small;
1153+
case 3:
1154+
return CodeModel::Kernel;
1155+
case 4:
1156+
return CodeModel::Medium;
1157+
case 5:
1158+
return CodeModel::Large;
1159+
}
1160+
1161+
return {};
1162+
}
1163+
11471164
static GlobalVariable::ThreadLocalMode getDecodedThreadLocalMode(unsigned Val) {
11481165
switch (Val) {
11491166
case 0: return GlobalVariable::NotThreadLocal;
@@ -3805,6 +3822,7 @@ Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
38053822
// dllstorageclass, comdat, attributes, preemption specifier,
38063823
// partition strtab offset, partition strtab size] (name in VST)
38073824
// v2: [strtab_offset, strtab_size, v1]
3825+
// v3: [v2, code_model]
38083826
StringRef Name;
38093827
std::tie(Name, Record) = readNameFromStrtab(Record);
38103828

@@ -3913,6 +3931,13 @@ Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
39133931
NewGV->setSanitizerMetadata(Meta);
39143932
}
39153933

3934+
if (Record.size() > 17 && Record[17]) {
3935+
if (auto CM = getDecodedCodeModel(Record[17]))
3936+
NewGV->setCodeModel(*CM);
3937+
else
3938+
return error("Invalid global variable code model");
3939+
}
3940+
39163941
return Error::success();
39173942
}
39183943

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,7 +1403,7 @@ void ModuleBitcodeWriter::writeModuleInfo() {
14031403
// GLOBALVAR: [strtab offset, strtab size, type, isconst, initid,
14041404
// linkage, alignment, section, visibility, threadlocal,
14051405
// unnamed_addr, externally_initialized, dllstorageclass,
1406-
// comdat, attributes, DSO_Local, GlobalSanitizer]
1406+
// comdat, attributes, DSO_Local, GlobalSanitizer, code_model]
14071407
Vals.push_back(addToStrtab(GV.getName()));
14081408
Vals.push_back(GV.getName().size());
14091409
Vals.push_back(VE.getTypeID(GV.getValueType()));
@@ -1420,7 +1420,7 @@ void ModuleBitcodeWriter::writeModuleInfo() {
14201420
GV.isExternallyInitialized() ||
14211421
GV.getDLLStorageClass() != GlobalValue::DefaultStorageClass ||
14221422
GV.hasComdat() || GV.hasAttributes() || GV.isDSOLocal() ||
1423-
GV.hasPartition() || GV.hasSanitizerMetadata()) {
1423+
GV.hasPartition() || GV.hasSanitizerMetadata() || GV.getCodeModel()) {
14241424
Vals.push_back(getEncodedVisibility(GV));
14251425
Vals.push_back(getEncodedThreadLocalMode(GV));
14261426
Vals.push_back(getEncodedUnnamedAddr(GV));
@@ -1438,6 +1438,7 @@ void ModuleBitcodeWriter::writeModuleInfo() {
14381438
Vals.push_back((GV.hasSanitizerMetadata() ? serializeSanitizerMetadata(
14391439
GV.getSanitizerMetadata())
14401440
: 0));
1441+
Vals.push_back(GV.getCodeModelRaw());
14411442
} else {
14421443
AbbrevToUse = SimpleGVarAbbrev;
14431444
}

llvm/lib/IR/AsmWriter.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3672,6 +3672,27 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) {
36723672
printEscapedString(GV->getPartition(), Out);
36733673
Out << '"';
36743674
}
3675+
if (auto CM = GV->getCodeModel()) {
3676+
Out << ", code_model \"";
3677+
switch (*CM) {
3678+
case CodeModel::Tiny:
3679+
Out << "tiny";
3680+
break;
3681+
case CodeModel::Small:
3682+
Out << "small";
3683+
break;
3684+
case CodeModel::Kernel:
3685+
Out << "kernel";
3686+
break;
3687+
case CodeModel::Medium:
3688+
Out << "medium";
3689+
break;
3690+
case CodeModel::Large:
3691+
Out << "large";
3692+
break;
3693+
}
3694+
Out << '"';
3695+
}
36753696

36763697
using SanitizerMetadata = llvm::GlobalValue::SanitizerMetadata;
36773698
if (GV->hasSanitizerMetadata()) {

llvm/lib/IR/Globals.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,13 +482,24 @@ void GlobalVariable::copyAttributesFrom(const GlobalVariable *Src) {
482482
GlobalObject::copyAttributesFrom(Src);
483483
setExternallyInitialized(Src->isExternallyInitialized());
484484
setAttributes(Src->getAttributes());
485+
if (auto CM = Src->getCodeModel())
486+
setCodeModel(*CM);
485487
}
486488

487489
void GlobalVariable::dropAllReferences() {
488490
User::dropAllReferences();
489491
clearMetadata();
490492
}
491493

494+
void GlobalVariable::setCodeModel(CodeModel::Model CM) {
495+
unsigned CodeModelData = static_cast<unsigned>(CM) + 1;
496+
unsigned OldData = getGlobalValueSubClassData();
497+
unsigned NewData = (OldData & ~(CodeModelMask << CodeModelShift)) |
498+
(CodeModelData << CodeModelShift);
499+
setGlobalValueSubClassData(NewData);
500+
assert(getCodeModel() == CM && "Code model representation error!");
501+
}
502+
492503
//===----------------------------------------------------------------------===//
493504
// GlobalAlias Implementation
494505
//===----------------------------------------------------------------------===//

llvm/test/Assembler/globalvariable-attributes.ll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
@g7 = global i32 2, sanitize_address_dyninit, align 4
1010
@g8 = global i32 2, sanitize_memtag, align 4
1111
@g9 = global i32 2, no_sanitize_address, no_sanitize_hwaddress, sanitize_memtag, align 4
12+
@g10 = global i32 2, code_model "tiny"
13+
@g11 = global i32 2, code_model "small"
14+
@g12 = global i32 2, code_model "kernel"
15+
@g13 = global i32 2, code_model "medium"
16+
@g14 = global i32 2, code_model "large"
1217

1318
attributes #0 = { "string" = "value" nobuiltin norecurse }
1419

@@ -21,6 +26,11 @@ attributes #0 = { "string" = "value" nobuiltin norecurse }
2126
; CHECK: @g7 = global i32 2, sanitize_address_dyninit, align 4
2227
; CHECK: @g8 = global i32 2, sanitize_memtag, align 4
2328
; CHECK: @g9 = global i32 2, no_sanitize_address, no_sanitize_hwaddress, sanitize_memtag, align 4
29+
; CHECK: @g10 = global i32 2, code_model "tiny"
30+
; CHECK: @g11 = global i32 2, code_model "small"
31+
; CHECK: @g12 = global i32 2, code_model "kernel"
32+
; CHECK: @g13 = global i32 2, code_model "medium"
33+
; CHECK: @g14 = global i32 2, code_model "large"
2434

2535
; CHECK: attributes #0 = { "key"="value" "key2"="value2" }
2636
; CHECK: attributes #1 = { "key3"="value3" }
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
; RUN: opt -passes=globalopt -S < %s | FileCheck %s
2+
3+
@G = internal global i32 5, code_model "large"
4+
5+
define i32 @test() norecurse {
6+
%a = load i32, ptr @G
7+
store i32 4, ptr @G
8+
ret i32 %a
9+
}
10+
11+
; CHECK: @G = internal unnamed_addr global i1 false, code_model "large"

0 commit comments

Comments
 (0)