[clang] 28c52ed - [clang][X86] Support __attribute__((model("small"/"large"))) (#124834)

via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 14 16:35:19 PST 2025


Author: Arthur Eubanks
Date: 2025-02-14T16:35:16-08:00
New Revision: 28c52edbe33e671ace58309e60598f3342e9ca73

URL: https://github.com/llvm/llvm-project/commit/28c52edbe33e671ace58309e60598f3342e9ca73
DIFF: https://github.com/llvm/llvm-project/commit/28c52edbe33e671ace58309e60598f3342e9ca73.diff

LOG: [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

Added: 
    clang/test/CodeGen/X86/codemodel.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/Attr.td
    clang/include/clang/Basic/AttrDocs.td
    clang/lib/Sema/SemaDeclAttr.cpp
    clang/test/Sema/attr-model.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 6056a6964fbcc..efaacdf18d50a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -125,6 +125,10 @@ Attribute Changes in Clang
 
 - The ``no_sanitize`` attribute now accepts both ``gnu`` and ``clang`` names.
 - Clang now diagnoses use of declaration attributes on void parameters. (#GH108819)
+- Clang now allows ``__attribute__((model("small")))`` and
+  ``__attribute__((model("large")))`` on non-TLS globals in x86-64 compilations.
+  This forces the global to be considered small or large in regards to the
+  x86-64 code model, regardless of the code model specified for the compilation.
 
 Improvements to Clang's diagnostics
 -----------------------------------

diff  --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 4384a98d63eb3..65c91ccd75ecc 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -459,6 +459,7 @@ class TargetArch<list<string> arches> : TargetSpec {
 }
 def TargetARM : TargetArch<["arm", "thumb", "armeb", "thumbeb"]>;
 def TargetAArch64 : TargetArch<["aarch64", "aarch64_be", "aarch64_32"]>;
+def TargetAMDGPU : TargetArch<["amdgcn", "r600"]>;
 def TargetAnyArm : TargetArch<!listconcat(TargetARM.Arches, TargetAArch64.Arches)>;
 def TargetAVR : TargetArch<["avr"]>;
 def TargetBPF : TargetArch<["bpfel", "bpfeb"]>;
@@ -469,7 +470,9 @@ def TargetMSP430 : TargetArch<["msp430"]>;
 def TargetM68k : TargetArch<["m68k"]>;
 def TargetRISCV : TargetArch<["riscv32", "riscv64"]>;
 def TargetX86 : TargetArch<["x86"]>;
+def TargetX86_64 : TargetArch<["x86_64"]>;
 def TargetAnyX86 : TargetArch<["x86", "x86_64"]>;
+def TargetSPIRV : TargetArch<["spirv", "spirv32", "spirv64"]>;
 def TargetWebAssembly : TargetArch<["wasm32", "wasm64"]>;
 def TargetNVPTX : TargetArch<["nvptx", "nvptx64"]>;
 def TargetWindows : TargetSpec {
@@ -3124,11 +3127,20 @@ def PragmaClangTextSection : InheritableAttr {
   let Documentation = [InternalOnly];
 }
 
-def CodeModel : InheritableAttr, TargetSpecificAttr<TargetLoongArch> {
+// The code model attribute only applies to LoongArch and x86-64, but for NVPTX
+// compilations that share code with the host, we want to ignore the attribute
+// rather than warn on it.
+def CodeModel
+    : InheritableAttr,
+      TargetSpecificAttr<TargetArch<!listconcat(
+          TargetLoongArch.Arches, TargetX86_64.Arches, TargetNVPTX.Arches,
+          TargetAMDGPU.Arches, TargetSPIRV.Arches)>> {
   let Spellings = [GCC<"model">];
-  let Args = [EnumArgument<"Model", "llvm::CodeModel::Model", /*is_string=*/1,
-              ["normal", "medium", "extreme"], ["Small", "Medium", "Large"],
-              /*opt=*/0, /*fake=*/0, /*isExternalType=*/1, /*isCovered=*/0>];
+  let Args = [EnumArgument<
+      "Model", "llvm::CodeModel::Model",
+      /*is_string=*/1, ["small", "normal", "medium", "large", "extreme"],
+      ["Small", "Small", "Medium", "Large", "Large"],
+      /*opt=*/0, /*fake=*/0, /*isExternalType=*/1, /*isCovered=*/0>];
   let Subjects = SubjectList<[NonTLSGlobalVar], ErrorDiag>;
   let Documentation = [CodeModelDocs];
 }

diff  --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 8ab20774de034..f5362b4d59142 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -62,6 +62,16 @@ def CodeModelDocs : Documentation {
   let Content = [{
 The ``model`` attribute allows overriding the translation unit's
 code model (specified by ``-mcmodel``) for a specific global variable.
+
+On LoongArch, allowed values are "normal", "medium", "extreme".
+
+On x86-64, allowed values are ``"small"`` and ``"large"``. ``"small"`` is
+roughly equivalent to ``-mcmodel=small``, meaning the global is considered
+"small" placed closer to the ``.text`` section relative to "large" globals, and
+to prefer using 32-bit relocations to access the global. ``"large"`` is roughly
+equivalent to ``-mcmodel=large``, meaning the global is considered "large" and
+placed further from the ``.text`` section relative to "small" globals, and
+64-bit relocations must be used to access the global.
   }];
   let Heading = "model";
 }

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 527db176cf8dd..620290af9509f 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -64,6 +64,7 @@
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/MC/MCSectionMachO.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TargetParser/Triple.h"
@@ -2949,15 +2950,49 @@ static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   }
 }
 
+static bool isValidCodeModelAttr(llvm::Triple &Triple, StringRef Str) {
+  if (Triple.isLoongArch()) {
+    return Str == "normal" || Str == "medium" || Str == "extreme";
+  } else {
+    assert(Triple.getArch() == llvm::Triple::x86_64 &&
+           "only loongarch/x86-64 supported");
+    return Str == "small" || Str == "large";
+  }
+}
+
 static void handleCodeModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   StringRef Str;
   SourceLocation LiteralLoc;
+  auto IsTripleSupported = [](llvm::Triple &Triple) {
+    return Triple.getArch() == llvm::Triple::ArchType::x86_64 ||
+           Triple.isLoongArch();
+  };
+
   // Check that it is a string.
   if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc))
     return;
 
+  SmallVector<llvm::Triple, 2> Triples = {
+      S.Context.getTargetInfo().getTriple()};
+  if (auto *aux = S.Context.getAuxTargetInfo()) {
+    Triples.push_back(aux->getTriple());
+  } else if (S.Context.getTargetInfo().getTriple().isNVPTX() ||
+             S.Context.getTargetInfo().getTriple().isAMDGPU() ||
+             S.Context.getTargetInfo().getTriple().isSPIRV()) {
+    // Ignore the attribute for pure GPU device compiles since it only applies
+    // to host globals.
+    return;
+  }
+
+  auto SupportedTripleIt = llvm::find_if(Triples, IsTripleSupported);
+  if (SupportedTripleIt == Triples.end()) {
+    S.Diag(LiteralLoc, diag::warn_unknown_attribute_ignored) << AL;
+    return;
+  }
+
   llvm::CodeModel::Model CM;
-  if (!CodeModelAttr::ConvertStrToModel(Str, CM)) {
+  if (!CodeModelAttr::ConvertStrToModel(Str, CM) ||
+      !isValidCodeModelAttr(*SupportedTripleIt, Str)) {
     S.Diag(LiteralLoc, diag::err_attr_codemodel_arg) << Str;
     return;
   }

diff  --git a/clang/test/CodeGen/X86/codemodel.cpp b/clang/test/CodeGen/X86/codemodel.cpp
new file mode 100644
index 0000000000000..60a840665b49c
--- /dev/null
+++ b/clang/test/CodeGen/X86/codemodel.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-unknown-unknown %s -o - | FileCheck %s
+
+// CHECK: @_ZL2v1 ={{.*}} global i32 0, code_model "small"
+static int v1 __attribute__((model("small")));
+
+void use1() {
+  v1 = 1;
+}
+
+// CHECK: @v2 ={{.*}} global float 0.000000e+00, code_model "large"
+float v2 __attribute__((model("large")));
+
+// CHECK: @_ZL2v3IiE ={{.*}} global i32 0, code_model "small"
+template <typename T>
+static T v3 __attribute__((model("small")));
+
+void use2() {
+  v3<int> = 1;
+}
+struct S {
+  double d;
+};
+
+typedef void (*F)();
+
+// CHECK: @v4 ={{.*}} global ptr null, code_model "large"
+F v4 __attribute__((model("large")));

diff  --git a/clang/test/Sema/attr-model.cpp b/clang/test/Sema/attr-model.cpp
index 898cc03939843..558439cf8db0f 100644
--- a/clang/test/Sema/attr-model.cpp
+++ b/clang/test/Sema/attr-model.cpp
@@ -1,64 +1,70 @@
-// RUN: %clang_cc1 -triple aarch64 -verify=expected,aarch64 -fsyntax-only %s
-// RUN: %clang_cc1 -triple loongarch64 -verify=expected,loongarch64 -fsyntax-only %s
-// RUN: %clang_cc1 -triple mips64 -verify=expected,mips64 -fsyntax-only %s
-// RUN: %clang_cc1 -triple powerpc64 -verify=expected,powerpc64 -fsyntax-only %s
-// RUN: %clang_cc1 -triple riscv64 -verify=expected,riscv64 -fsyntax-only %s
-// RUN: %clang_cc1 -triple x86_64 -verify=expected,x86_64 -fsyntax-only %s
+// RUN: %clang_cc1 -triple aarch64 -verify=unsupported -fsyntax-only %s
+// RUN: %clang_cc1 -triple loongarch64 -verify=loongarch64 -fsyntax-only %s
+// RUN: %clang_cc1 -triple mips64 -verify=unsupported -fsyntax-only %s
+// RUN: %clang_cc1 -triple powerpc64 -verify=unsupported -fsyntax-only %s
+// RUN: %clang_cc1 -triple riscv64 -verify=unsupported -fsyntax-only %s
+// RUN: %clang_cc1 -triple x86_64 -verify=x86_64 -fsyntax-only %s
+// RUN: %clang_cc1 -triple nvptx64-unknown-cuda -fcuda-is-device -x cuda -verify=ignored -fsyntax-only %s
+// RUN: %clang_cc1 -triple amdgcn -verify=ignored -fsyntax-only %s
+// RUN: %clang_cc1 -triple r600 -verify=ignored -fsyntax-only %s
+// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -verify=ignored -fsyntax-only %s
+// RUN: %clang_cc1 -triple spirv32-unknown-unknown -verify=ignored -fsyntax-only %s
+// RUN: %clang_cc1 -triple spirv64-unknown-unknown -verify=ignored -fsyntax-only %s
 
-#if defined(__loongarch__) && !__has_attribute(model)
+// RUN: %clang_cc1 -triple x86_64 -aux-triple nvptx64 -x cuda -verify=x86_64 -fsyntax-only %s
+// RUN: %clang_cc1 -triple nvptx64 -aux-triple x86_64 -x cuda -fcuda-is-device -verify=nvptx64-x86_64 -fsyntax-only %s
+// RUN: %clang_cc1 -triple aarch64 -aux-triple nvptx64 -x cuda -verify=unsupported -fsyntax-only %s
+// RUN: %clang_cc1 -triple nvptx64 -aux-triple aarch64 -x cuda -fcuda-is-device -verify=nvptx64-unsupported -fsyntax-only %s
+
+#if (defined(__loongarch__) || defined(__x86_64__)) && !__has_attribute(model)
 #error "Should support model attribute"
 #endif
 
-int a __attribute((model("tiny")));    // aarch64-warning {{unknown attribute 'model' ignored}} \
+int a __attribute((model("tiny")));    // unsupported-warning {{unknown attribute 'model' ignored}} \
                                        // loongarch64-error {{code model 'tiny' is not supported on this target}} \
-                                       // mips64-warning {{unknown attribute 'model' ignored}} \
-                                       // powerpc64-warning {{unknown attribute 'model' ignored}} \
-                                       // riscv64-warning {{unknown attribute 'model' ignored}} \
-                                       // x86_64-warning {{unknown attribute 'model' ignored}}
-int b __attribute((model("small")));   // aarch64-warning {{unknown attribute 'model' ignored}} \
+                                       // x86_64-error {{code model 'tiny' is not supported on this target}} \
+                                       // nvptx64-unsupported-warning {{unknown attribute 'model' ignored}} \
+                                       // nvptx64-x86_64-error {{code model 'tiny' is not supported on this target}}
+int b __attribute((model("small")));   // unsupported-warning {{unknown attribute 'model' ignored}} \
                                        // loongarch64-error {{code model 'small' is not supported on this target}} \
-                                       // mips64-warning {{unknown attribute 'model' ignored}} \
-                                       // powerpc64-warning {{unknown attribute 'model' ignored}} \
-                                       // riscv64-warning {{unknown attribute 'model' ignored}} \
-                                       // x86_64-warning {{unknown attribute 'model' ignored}}
-int c __attribute((model("normal")));  // aarch64-warning {{unknown attribute 'model' ignored}} \
-                                       // mips64-warning {{unknown attribute 'model' ignored}} \
-                                       // powerpc64-warning {{unknown attribute 'model' ignored}} \
-                                       // riscv64-warning {{unknown attribute 'model' ignored}} \
-                                       // x86_64-warning {{unknown attribute 'model' ignored}}
-int d __attribute((model("kernel")));  // aarch64-warning {{unknown attribute 'model' ignored}} \
+                                       // nvptx64-unsupported-warning {{unknown attribute 'model' ignored}}
+int c __attribute((model("normal")));  // unsupported-warning {{unknown attribute 'model' ignored}} \
+                                       // x86_64-error {{code model 'normal' is not supported on this target}} \
+                                       // nvptx64-unsupported-warning {{unknown attribute 'model' ignored}} \
+                                       // nvptx64-x86_64-error {{code model 'normal' is not supported on this target}}
+int d __attribute((model("kernel")));  // unsupported-warning {{unknown attribute 'model' ignored}} \
                                        // loongarch64-error {{code model 'kernel' is not supported on this target}} \
-                                       // mips64-warning {{unknown attribute 'model' ignored}} \
-                                       // powerpc64-warning {{unknown attribute 'model' ignored}} \
-                                       // riscv64-warning {{unknown attribute 'model' ignored}} \
-                                       // x86_64-warning {{unknown attribute 'model' ignored}}
-int e __attribute((model("medium")));  // aarch64-warning {{unknown attribute 'model' ignored}} \
-                                       // mips64-warning {{unknown attribute 'model' ignored}} \
-                                       // powerpc64-warning {{unknown attribute 'model' ignored}} \
-                                       // riscv64-warning {{unknown attribute 'model' ignored}} \
-                                       // x86_64-warning {{unknown attribute 'model' ignored}}
-int f __attribute((model("large")));   // aarch64-warning {{unknown attribute 'model' ignored}} \
+                                       // x86_64-error {{code model 'kernel' is not supported on this target}} \
+                                       // nvptx64-unsupported-warning {{unknown attribute 'model' ignored}} \
+                                       // nvptx64-x86_64-error {{code model 'kernel' is not supported on this target}}
+int e __attribute((model("medium")));  // unsupported-warning {{unknown attribute 'model' ignored}} \
+                                       // x86_64-error {{code model 'medium' is not supported on this target}} \
+                                       // nvptx64-unsupported-warning {{unknown attribute 'model' ignored}} \
+                                       // nvptx64-x86_64-error {{code model 'medium' is not supported on this target}}
+int f __attribute((model("large")));   // unsupported-warning {{unknown attribute 'model' ignored}} \
                                        // loongarch64-error {{code model 'large' is not supported on this target}} \
-                                       // mips64-warning {{unknown attribute 'model' ignored}} \
-                                       // powerpc64-warning {{unknown attribute 'model' ignored}} \
-                                       // riscv64-warning {{unknown attribute 'model' ignored}} \
-                                       // x86_64-warning {{unknown attribute 'model' ignored}}
-int g __attribute((model("extreme"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
-                                       // mips64-warning {{unknown attribute 'model' ignored}} \
-                                       // powerpc64-warning {{unknown attribute 'model' ignored}} \
-                                       // riscv64-warning {{unknown attribute 'model' ignored}} \
-                                       // x86_64-warning {{unknown attribute 'model' ignored}}
+                                       // nvptx64-unsupported-warning {{unknown attribute 'model' ignored}}
+int g __attribute((model("extreme"))); // unsupported-warning {{unknown attribute 'model' ignored}} \
+                                       // x86_64-error {{code model 'extreme' is not supported on this target}} \
+                                       // nvptx64-unsupported-warning {{unknown attribute 'model' ignored}} \
+                                       // nvptx64-x86_64-error {{code model 'extreme' is not supported on this target}}
 
-void __attribute((model("extreme"))) h() {} // aarch64-warning {{unknown attribute 'model' ignored}} \
+void __attribute((model("extreme"))) h() {} // unsupported-warning {{unknown attribute 'model' ignored}} \
+                                            // ignored-error {{'model' attribute only applies to non-TLS global variables}} \
                                             // loongarch64-error {{'model' attribute only applies to non-TLS global variables}} \
-                                            // mips64-warning {{unknown attribute 'model' ignored}} \
-                                            // powerpc64-warning {{unknown attribute 'model' ignored}} \
-                                            // riscv64-warning {{unknown attribute 'model' ignored}} \
-                                            // x86_64-warning {{unknown attribute 'model' ignored}}
+                                            // x86_64-error {{'model' attribute only applies to non-TLS global variables}} \
+                                            // nvptx64-unsupported-error {{'model' attribute only applies to non-TLS global variables}} \
+                                            // nvptx64-x86_64-error {{'model' attribute only applies to non-TLS global variables}}
 
-thread_local int i __attribute((model("extreme"))); // aarch64-warning {{unknown attribute 'model' ignored}} \
-                                                    // loongarch64-error {{'model' attribute only applies to non-TLS global variables}} \
-                                                    // mips64-warning {{unknown attribute 'model' ignored}} \
-                                                    // powerpc64-warning {{unknown attribute 'model' ignored}} \
-                                                    // riscv64-warning {{unknown attribute 'model' ignored}} \
-                                                    // x86_64-warning {{unknown attribute 'model' ignored}}
+#if !defined(__CUDA__) || !defined(__CUDA_ARCH__)
+// if we are compiling for non-cuda host, or host mode in a CUDA compile
+#if !defined(__AMDGCN__) && !defined(__R600__) && !defined(__SPIRV__)
+// for all non-cuda hosts, above targets don't support thread_local
+thread_local
+#endif
+#endif
+int i __attribute((model("extreme"))); // unsupported-warning {{unknown attribute 'model' ignored}} \
+                                       // loongarch64-error {{'model' attribute only applies to non-TLS global variables}} \
+                                       // x86_64-error {{'model' attribute only applies to non-TLS global variables}} \
+                                       // nvptx64-unsupported-warning {{unknown attribute 'model' ignored}} \
+                                       // nvptx64-x86_64-error {{code model 'extreme' is not supported on this target}}


        


More information about the cfe-commits mailing list