diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index 1b831c9511e272..8e9b7ad8b46826 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -25,6 +25,7 @@ #include "clang/Basic/Sanitizers.h" #include "clang/Basic/SourceLocation.h" #include "llvm/Frontend/HLSL/HLSLResource.h" +#include "llvm/Support/CodeGen.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/VersionTuple.h" #include "llvm/Support/raw_ostream.h" diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 1800f584c7e108..8c77e41f7ed0a3 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -143,6 +143,11 @@ def ExternalGlobalVar : SubsetSubjectisLocalExternDecl()}], "external global variables">; +def NonTLSGlobalVar : SubsetSubjecthasGlobalStorage() && + S->getTLSKind() == 0}], + "non-TLS global variables">; + def InlineFunction : SubsetSubjectisInlineSpecified()}], "inline functions">; @@ -431,6 +436,7 @@ def TargetAArch64 : TargetArch<["aarch64", "aarch64_be", "aarch64_32"]>; def TargetAnyArm : TargetArch; def TargetAVR : TargetArch<["avr"]>; def TargetBPF : TargetArch<["bpfel", "bpfeb"]>; +def TargetLoongArch : TargetArch<["loongarch32", "loongarch64"]>; def TargetMips32 : TargetArch<["mips", "mipsel"]>; def TargetAnyMips : TargetArch<["mips", "mipsel", "mips64", "mips64el"]>; def TargetMSP430 : TargetArch<["msp430"]>; @@ -2718,6 +2724,15 @@ def PragmaClangTextSection : InheritableAttr { let Documentation = [InternalOnly]; } +def CodeModel : InheritableAttr, TargetSpecificAttr { + let Spellings = [GCC<"model">]; + let Args = [EnumArgument<"Model", "llvm::CodeModel::Model", + ["normal", "medium", "extreme"], ["Small", "Medium", "Large"], + /*opt=*/0, /*fake=*/0, /*isExternalType=*/1>]; + let Subjects = SubjectList<[NonTLSGlobalVar], ErrorDiag>; + let Documentation = [CodeModelDocs]; +} + def Sentinel : InheritableAttr { let Spellings = [GCC<"sentinel">]; let Args = [DefaultIntArgument<"Sentinel", 0>, diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index b45ec6bbb8d37e..428de4cfdbafea 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -57,6 +57,15 @@ global variable or function should be in after translation. let Heading = "section, __declspec(allocate)"; } +def CodeModelDocs : Documentation { + let Category = DocCatVariable; + let Content = [{ +The ``model`` attribute allows overriding the translation unit's +code model (specified by ``-mcmodel``) for a specific global variable. + }]; + let Heading = "model"; +} + def UsedDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6dfb2d7195203a..9691f268978fdd 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3408,6 +3408,8 @@ def warn_objc_redundant_literal_use : Warning< def err_attr_tlsmodel_arg : Error<"tls_model must be \"global-dynamic\", " "\"local-dynamic\", \"initial-exec\" or \"local-exec\"">; +def err_attr_codemodel_arg : Error<"code model '%0' is not supported on this target">; + def err_aix_attr_unsupported_tls_model : Error<"TLS model '%0' is not yet supported on AIX">; def err_tls_var_aligned_over_maximum : Error< diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index dea58a7ff4146a..f6925e7f4f3ee8 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -4841,6 +4841,10 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty, isExternallyVisible(D->getLinkageAndVisibility().getLinkage())) GV->setSection(".cp.rodata"); + // Handle code model attribute + if (const auto *CMA = D->getAttr()) + GV->setCodeModel(CMA->getModel()); + // Check if we a have a const declaration with an initializer, we may be // able to emit it as available_externally to expose it's value to the // optimizer. diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 87c78d742d0ff4..6e2cef6595f0bd 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3369,6 +3369,22 @@ static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } +static void handleCodeModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Str; + SourceLocation LiteralLoc; + // Check that it is a string. + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc)) + return; + + llvm::CodeModel::Model CM; + if (!CodeModelAttr::ConvertStrToModel(Str, CM)) { + S.Diag(LiteralLoc, diag::err_attr_codemodel_arg) << Str; + return; + } + + D->addAttr(::new (S.Context) CodeModelAttr(S.Context, AL, CM)); +} + // This is used for `__declspec(code_seg("segname"))` on a decl. // `#pragma code_seg("segname")` uses checkSectionName() instead. static bool checkCodeSegName(Sema &S, SourceLocation LiteralLoc, @@ -9309,6 +9325,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_Section: handleSectionAttr(S, D, AL); break; + case ParsedAttr::AT_CodeModel: + handleCodeModelAttr(S, D, AL); + break; case ParsedAttr::AT_RandomizeLayout: handleRandomizeLayoutAttr(S, D, AL); break; diff --git a/clang/test/CodeGen/LoongArch/attributes.cpp b/clang/test/CodeGen/LoongArch/attributes.cpp new file mode 100644 index 00000000000000..fb700ad305012b --- /dev/null +++ b/clang/test/CodeGen/LoongArch/attributes.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -emit-llvm -triple loongarch64 %s -o - | FileCheck %s + +// CHECK: @_ZL2v1 ={{.*}} global i32 0, code_model "small" +static int v1 __attribute__((model("normal"))); + +void use1() { + v1 = 1; +} + +// CHECK: @v2 ={{.*}} global i32 0, code_model "medium" +int v2 __attribute__((model("medium"))); + +// CHECK: @v3 ={{.*}} global float 0.000000e+00, code_model "large" +float v3 __attribute__((model("extreme"))); + +// CHECK: @_ZL2v4IiE ={{.*}} global i32 0, code_model "medium" +template +static T v4 __attribute__((model("medium"))); + +void use2() { + v4 = 1; +} + +struct S { + double d; +}; + +// CHECK: @v5 ={{.*}} global {{.*}}, code_model "medium" +S v5 __attribute__((model("medium"))); + +typedef void (*F)(); + +// CHECK: @v6 ={{.*}} global ptr null, code_model "large" +F v6 __attribute__((model("extreme"))); diff --git a/clang/test/Sema/attr-model.cpp b/clang/test/Sema/attr-model.cpp new file mode 100644 index 00000000000000..898cc039398436 --- /dev/null +++ b/clang/test/Sema/attr-model.cpp @@ -0,0 +1,64 @@ +// 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 + +#if defined(__loongarch__) && !__has_attribute(model) +#error "Should support model attribute" +#endif + +int a __attribute((model("tiny"))); // aarch64-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}} \ + // 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}} \ + // 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}} \ + // 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}} + +void __attribute((model("extreme"))) h() {} // 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}} + +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}}