Skip to content

Commit 28c52ed

Browse files
authored
[clang][X86] Support __attribute__((model("small"/"large"))) (#124834)
Following up #72078, on x86-64 this allows a global to be considered small or large regardless of the code model. For example, x86-64's medium code model by default classifies globals as small or large depending on their size relative to -mlarge-data-threshold. GPU compilations compile the same TU for both the host and device, but only codegen the host or device portions of it depending on attributes. However, we still Sema the TU, and will warn on an unknown attribute for the device compilation since this attribute is target-specific. Since they're intended for the host, accept but ignore this attribute for device compilations where the host is either unknown or known to support the attribute. Co-authored-by: @pranavk
1 parent 77041da commit 28c52ed

File tree

6 files changed

+152
-58
lines changed

6 files changed

+152
-58
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ Attribute Changes in Clang
125125

126126
- The ``no_sanitize`` attribute now accepts both ``gnu`` and ``clang`` names.
127127
- Clang now diagnoses use of declaration attributes on void parameters. (#GH108819)
128+
- Clang now allows ``__attribute__((model("small")))`` and
129+
``__attribute__((model("large")))`` on non-TLS globals in x86-64 compilations.
130+
This forces the global to be considered small or large in regards to the
131+
x86-64 code model, regardless of the code model specified for the compilation.
128132

129133
Improvements to Clang's diagnostics
130134
-----------------------------------

clang/include/clang/Basic/Attr.td

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@ class TargetArch<list<string> arches> : TargetSpec {
459459
}
460460
def TargetARM : TargetArch<["arm", "thumb", "armeb", "thumbeb"]>;
461461
def TargetAArch64 : TargetArch<["aarch64", "aarch64_be", "aarch64_32"]>;
462+
def TargetAMDGPU : TargetArch<["amdgcn", "r600"]>;
462463
def TargetAnyArm : TargetArch<!listconcat(TargetARM.Arches, TargetAArch64.Arches)>;
463464
def TargetAVR : TargetArch<["avr"]>;
464465
def TargetBPF : TargetArch<["bpfel", "bpfeb"]>;
@@ -469,7 +470,9 @@ def TargetMSP430 : TargetArch<["msp430"]>;
469470
def TargetM68k : TargetArch<["m68k"]>;
470471
def TargetRISCV : TargetArch<["riscv32", "riscv64"]>;
471472
def TargetX86 : TargetArch<["x86"]>;
473+
def TargetX86_64 : TargetArch<["x86_64"]>;
472474
def TargetAnyX86 : TargetArch<["x86", "x86_64"]>;
475+
def TargetSPIRV : TargetArch<["spirv", "spirv32", "spirv64"]>;
473476
def TargetWebAssembly : TargetArch<["wasm32", "wasm64"]>;
474477
def TargetNVPTX : TargetArch<["nvptx", "nvptx64"]>;
475478
def TargetWindows : TargetSpec {
@@ -3124,11 +3127,20 @@ def PragmaClangTextSection : InheritableAttr {
31243127
let Documentation = [InternalOnly];
31253128
}
31263129

3127-
def CodeModel : InheritableAttr, TargetSpecificAttr<TargetLoongArch> {
3130+
// The code model attribute only applies to LoongArch and x86-64, but for NVPTX
3131+
// compilations that share code with the host, we want to ignore the attribute
3132+
// rather than warn on it.
3133+
def CodeModel
3134+
: InheritableAttr,
3135+
TargetSpecificAttr<TargetArch<!listconcat(
3136+
TargetLoongArch.Arches, TargetX86_64.Arches, TargetNVPTX.Arches,
3137+
TargetAMDGPU.Arches, TargetSPIRV.Arches)>> {
31283138
let Spellings = [GCC<"model">];
3129-
let Args = [EnumArgument<"Model", "llvm::CodeModel::Model", /*is_string=*/1,
3130-
["normal", "medium", "extreme"], ["Small", "Medium", "Large"],
3131-
/*opt=*/0, /*fake=*/0, /*isExternalType=*/1, /*isCovered=*/0>];
3139+
let Args = [EnumArgument<
3140+
"Model", "llvm::CodeModel::Model",
3141+
/*is_string=*/1, ["small", "normal", "medium", "large", "extreme"],
3142+
["Small", "Small", "Medium", "Large", "Large"],
3143+
/*opt=*/0, /*fake=*/0, /*isExternalType=*/1, /*isCovered=*/0>];
31323144
let Subjects = SubjectList<[NonTLSGlobalVar], ErrorDiag>;
31333145
let Documentation = [CodeModelDocs];
31343146
}

clang/include/clang/Basic/AttrDocs.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ def CodeModelDocs : Documentation {
6262
let Content = [{
6363
The ``model`` attribute allows overriding the translation unit's
6464
code model (specified by ``-mcmodel``) for a specific global variable.
65+
66+
On LoongArch, allowed values are "normal", "medium", "extreme".
67+
68+
On x86-64, allowed values are ``"small"`` and ``"large"``. ``"small"`` is
69+
roughly equivalent to ``-mcmodel=small``, meaning the global is considered
70+
"small" placed closer to the ``.text`` section relative to "large" globals, and
71+
to prefer using 32-bit relocations to access the global. ``"large"`` is roughly
72+
equivalent to ``-mcmodel=large``, meaning the global is considered "large" and
73+
placed further from the ``.text`` section relative to "small" globals, and
74+
64-bit relocations must be used to access the global.
6575
}];
6676
let Heading = "model";
6777
}

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
#include "llvm/IR/DerivedTypes.h"
6565
#include "llvm/MC/MCSectionMachO.h"
6666
#include "llvm/Support/Error.h"
67+
#include "llvm/Support/ErrorHandling.h"
6768
#include "llvm/Support/MathExtras.h"
6869
#include "llvm/Support/raw_ostream.h"
6970
#include "llvm/TargetParser/Triple.h"
@@ -2949,15 +2950,49 @@ static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
29492950
}
29502951
}
29512952

2953+
static bool isValidCodeModelAttr(llvm::Triple &Triple, StringRef Str) {
2954+
if (Triple.isLoongArch()) {
2955+
return Str == "normal" || Str == "medium" || Str == "extreme";
2956+
} else {
2957+
assert(Triple.getArch() == llvm::Triple::x86_64 &&
2958+
"only loongarch/x86-64 supported");
2959+
return Str == "small" || Str == "large";
2960+
}
2961+
}
2962+
29522963
static void handleCodeModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
29532964
StringRef Str;
29542965
SourceLocation LiteralLoc;
2966+
auto IsTripleSupported = [](llvm::Triple &Triple) {
2967+
return Triple.getArch() == llvm::Triple::ArchType::x86_64 ||
2968+
Triple.isLoongArch();
2969+
};
2970+
29552971
// Check that it is a string.
29562972
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc))
29572973
return;
29582974

2975+
SmallVector<llvm::Triple, 2> Triples = {
2976+
S.Context.getTargetInfo().getTriple()};
2977+
if (auto *aux = S.Context.getAuxTargetInfo()) {
2978+
Triples.push_back(aux->getTriple());
2979+
} else if (S.Context.getTargetInfo().getTriple().isNVPTX() ||
2980+
S.Context.getTargetInfo().getTriple().isAMDGPU() ||
2981+
S.Context.getTargetInfo().getTriple().isSPIRV()) {
2982+
// Ignore the attribute for pure GPU device compiles since it only applies
2983+
// to host globals.
2984+
return;
2985+
}
2986+
2987+
auto SupportedTripleIt = llvm::find_if(Triples, IsTripleSupported);
2988+
if (SupportedTripleIt == Triples.end()) {
2989+
S.Diag(LiteralLoc, diag::warn_unknown_attribute_ignored) << AL;
2990+
return;
2991+
}
2992+
29592993
llvm::CodeModel::Model CM;
2960-
if (!CodeModelAttr::ConvertStrToModel(Str, CM)) {
2994+
if (!CodeModelAttr::ConvertStrToModel(Str, CM) ||
2995+
!isValidCodeModelAttr(*SupportedTripleIt, Str)) {
29612996
S.Diag(LiteralLoc, diag::err_attr_codemodel_arg) << Str;
29622997
return;
29632998
}

clang/test/CodeGen/X86/codemodel.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 -emit-llvm -triple x86_64-unknown-unknown %s -o - | FileCheck %s
2+
3+
// CHECK: @_ZL2v1 ={{.*}} global i32 0, code_model "small"
4+
static int v1 __attribute__((model("small")));
5+
6+
void use1() {
7+
v1 = 1;
8+
}
9+
10+
// CHECK: @v2 ={{.*}} global float 0.000000e+00, code_model "large"
11+
float v2 __attribute__((model("large")));
12+
13+
// CHECK: @_ZL2v3IiE ={{.*}} global i32 0, code_model "small"
14+
template <typename T>
15+
static T v3 __attribute__((model("small")));
16+
17+
void use2() {
18+
v3<int> = 1;
19+
}
20+
struct S {
21+
double d;
22+
};
23+
24+
typedef void (*F)();
25+
26+
// CHECK: @v4 ={{.*}} global ptr null, code_model "large"
27+
F v4 __attribute__((model("large")));

clang/test/Sema/attr-model.cpp

Lines changed: 59 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,70 @@
1-
// RUN: %clang_cc1 -triple aarch64 -verify=expected,aarch64 -fsyntax-only %s
2-
// RUN: %clang_cc1 -triple loongarch64 -verify=expected,loongarch64 -fsyntax-only %s
3-
// RUN: %clang_cc1 -triple mips64 -verify=expected,mips64 -fsyntax-only %s
4-
// RUN: %clang_cc1 -triple powerpc64 -verify=expected,powerpc64 -fsyntax-only %s
5-
// RUN: %clang_cc1 -triple riscv64 -verify=expected,riscv64 -fsyntax-only %s
6-
// RUN: %clang_cc1 -triple x86_64 -verify=expected,x86_64 -fsyntax-only %s
1+
// RUN: %clang_cc1 -triple aarch64 -verify=unsupported -fsyntax-only %s
2+
// RUN: %clang_cc1 -triple loongarch64 -verify=loongarch64 -fsyntax-only %s
3+
// RUN: %clang_cc1 -triple mips64 -verify=unsupported -fsyntax-only %s
4+
// RUN: %clang_cc1 -triple powerpc64 -verify=unsupported -fsyntax-only %s
5+
// RUN: %clang_cc1 -triple riscv64 -verify=unsupported -fsyntax-only %s
6+
// RUN: %clang_cc1 -triple x86_64 -verify=x86_64 -fsyntax-only %s
7+
// RUN: %clang_cc1 -triple nvptx64-unknown-cuda -fcuda-is-device -x cuda -verify=ignored -fsyntax-only %s
8+
// RUN: %clang_cc1 -triple amdgcn -verify=ignored -fsyntax-only %s
9+
// RUN: %clang_cc1 -triple r600 -verify=ignored -fsyntax-only %s
10+
// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -verify=ignored -fsyntax-only %s
11+
// RUN: %clang_cc1 -triple spirv32-unknown-unknown -verify=ignored -fsyntax-only %s
12+
// RUN: %clang_cc1 -triple spirv64-unknown-unknown -verify=ignored -fsyntax-only %s
713

8-
#if defined(__loongarch__) && !__has_attribute(model)
14+
// RUN: %clang_cc1 -triple x86_64 -aux-triple nvptx64 -x cuda -verify=x86_64 -fsyntax-only %s
15+
// RUN: %clang_cc1 -triple nvptx64 -aux-triple x86_64 -x cuda -fcuda-is-device -verify=nvptx64-x86_64 -fsyntax-only %s
16+
// RUN: %clang_cc1 -triple aarch64 -aux-triple nvptx64 -x cuda -verify=unsupported -fsyntax-only %s
17+
// RUN: %clang_cc1 -triple nvptx64 -aux-triple aarch64 -x cuda -fcuda-is-device -verify=nvptx64-unsupported -fsyntax-only %s
18+
19+
#if (defined(__loongarch__) || defined(__x86_64__)) && !__has_attribute(model)
920
#error "Should support model attribute"
1021
#endif
1122

12-
int a __attribute((model("tiny"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
23+
int a __attribute((model("tiny"))); // unsupported-warning {{unknown attribute 'model' ignored}} \
1324
// loongarch64-error {{code model 'tiny' is not supported on this target}} \
14-
// mips64-warning {{unknown attribute 'model' ignored}} \
15-
// powerpc64-warning {{unknown attribute 'model' ignored}} \
16-
// riscv64-warning {{unknown attribute 'model' ignored}} \
17-
// x86_64-warning {{unknown attribute 'model' ignored}}
18-
int b __attribute((model("small"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
25+
// x86_64-error {{code model 'tiny' is not supported on this target}} \
26+
// nvptx64-unsupported-warning {{unknown attribute 'model' ignored}} \
27+
// nvptx64-x86_64-error {{code model 'tiny' is not supported on this target}}
28+
int b __attribute((model("small"))); // unsupported-warning {{unknown attribute 'model' ignored}} \
1929
// loongarch64-error {{code model 'small' is not supported on this target}} \
20-
// mips64-warning {{unknown attribute 'model' ignored}} \
21-
// powerpc64-warning {{unknown attribute 'model' ignored}} \
22-
// riscv64-warning {{unknown attribute 'model' ignored}} \
23-
// x86_64-warning {{unknown attribute 'model' ignored}}
24-
int c __attribute((model("normal"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
25-
// mips64-warning {{unknown attribute 'model' ignored}} \
26-
// powerpc64-warning {{unknown attribute 'model' ignored}} \
27-
// riscv64-warning {{unknown attribute 'model' ignored}} \
28-
// x86_64-warning {{unknown attribute 'model' ignored}}
29-
int d __attribute((model("kernel"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
30+
// nvptx64-unsupported-warning {{unknown attribute 'model' ignored}}
31+
int c __attribute((model("normal"))); // unsupported-warning {{unknown attribute 'model' ignored}} \
32+
// x86_64-error {{code model 'normal' is not supported on this target}} \
33+
// nvptx64-unsupported-warning {{unknown attribute 'model' ignored}} \
34+
// nvptx64-x86_64-error {{code model 'normal' is not supported on this target}}
35+
int d __attribute((model("kernel"))); // unsupported-warning {{unknown attribute 'model' ignored}} \
3036
// loongarch64-error {{code model 'kernel' is not supported on this target}} \
31-
// mips64-warning {{unknown attribute 'model' ignored}} \
32-
// powerpc64-warning {{unknown attribute 'model' ignored}} \
33-
// riscv64-warning {{unknown attribute 'model' ignored}} \
34-
// x86_64-warning {{unknown attribute 'model' ignored}}
35-
int e __attribute((model("medium"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
36-
// mips64-warning {{unknown attribute 'model' ignored}} \
37-
// powerpc64-warning {{unknown attribute 'model' ignored}} \
38-
// riscv64-warning {{unknown attribute 'model' ignored}} \
39-
// x86_64-warning {{unknown attribute 'model' ignored}}
40-
int f __attribute((model("large"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
37+
// x86_64-error {{code model 'kernel' is not supported on this target}} \
38+
// nvptx64-unsupported-warning {{unknown attribute 'model' ignored}} \
39+
// nvptx64-x86_64-error {{code model 'kernel' is not supported on this target}}
40+
int e __attribute((model("medium"))); // unsupported-warning {{unknown attribute 'model' ignored}} \
41+
// x86_64-error {{code model 'medium' is not supported on this target}} \
42+
// nvptx64-unsupported-warning {{unknown attribute 'model' ignored}} \
43+
// nvptx64-x86_64-error {{code model 'medium' is not supported on this target}}
44+
int f __attribute((model("large"))); // unsupported-warning {{unknown attribute 'model' ignored}} \
4145
// loongarch64-error {{code model 'large' is not supported on this target}} \
42-
// mips64-warning {{unknown attribute 'model' ignored}} \
43-
// powerpc64-warning {{unknown attribute 'model' ignored}} \
44-
// riscv64-warning {{unknown attribute 'model' ignored}} \
45-
// x86_64-warning {{unknown attribute 'model' ignored}}
46-
int g __attribute((model("extreme"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
47-
// mips64-warning {{unknown attribute 'model' ignored}} \
48-
// powerpc64-warning {{unknown attribute 'model' ignored}} \
49-
// riscv64-warning {{unknown attribute 'model' ignored}} \
50-
// x86_64-warning {{unknown attribute 'model' ignored}}
46+
// nvptx64-unsupported-warning {{unknown attribute 'model' ignored}}
47+
int g __attribute((model("extreme"))); // unsupported-warning {{unknown attribute 'model' ignored}} \
48+
// x86_64-error {{code model 'extreme' is not supported on this target}} \
49+
// nvptx64-unsupported-warning {{unknown attribute 'model' ignored}} \
50+
// nvptx64-x86_64-error {{code model 'extreme' is not supported on this target}}
5151

52-
void __attribute((model("extreme"))) h() {} // aarch64-warning {{unknown attribute 'model' ignored}} \
52+
void __attribute((model("extreme"))) h() {} // unsupported-warning {{unknown attribute 'model' ignored}} \
53+
// ignored-error {{'model' attribute only applies to non-TLS global variables}} \
5354
// loongarch64-error {{'model' attribute only applies to non-TLS global variables}} \
54-
// mips64-warning {{unknown attribute 'model' ignored}} \
55-
// powerpc64-warning {{unknown attribute 'model' ignored}} \
56-
// riscv64-warning {{unknown attribute 'model' ignored}} \
57-
// x86_64-warning {{unknown attribute 'model' ignored}}
55+
// x86_64-error {{'model' attribute only applies to non-TLS global variables}} \
56+
// nvptx64-unsupported-error {{'model' attribute only applies to non-TLS global variables}} \
57+
// nvptx64-x86_64-error {{'model' attribute only applies to non-TLS global variables}}
5858

59-
thread_local int i __attribute((model("extreme"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
60-
// loongarch64-error {{'model' attribute only applies to non-TLS global variables}} \
61-
// mips64-warning {{unknown attribute 'model' ignored}} \
62-
// powerpc64-warning {{unknown attribute 'model' ignored}} \
63-
// riscv64-warning {{unknown attribute 'model' ignored}} \
64-
// x86_64-warning {{unknown attribute 'model' ignored}}
59+
#if !defined(__CUDA__) || !defined(__CUDA_ARCH__)
60+
// if we are compiling for non-cuda host, or host mode in a CUDA compile
61+
#if !defined(__AMDGCN__) && !defined(__R600__) && !defined(__SPIRV__)
62+
// for all non-cuda hosts, above targets don't support thread_local
63+
thread_local
64+
#endif
65+
#endif
66+
int i __attribute((model("extreme"))); // unsupported-warning {{unknown attribute 'model' ignored}} \
67+
// loongarch64-error {{'model' attribute only applies to non-TLS global variables}} \
68+
// x86_64-error {{'model' attribute only applies to non-TLS global variables}} \
69+
// nvptx64-unsupported-warning {{unknown attribute 'model' ignored}} \
70+
// nvptx64-x86_64-error {{code model 'extreme' is not supported on this target}}

0 commit comments

Comments
 (0)