Skip to content

Commit

Permalink
[clang] Add per-global code model attribute
Browse files Browse the repository at this point in the history
This patch adds a per-global code model attribute, which can override
the target's code model to access global variables.

Currently, the code model attribute is only supported on LoongArch.
This patch also maps GCC's code model names to LLVM's, which allows
for better compatibility between the two compilers.

Suggested-by: Arthur Eubanks <[email protected]>
Signed-off-by: WANG Rui <[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
  • Loading branch information
heiher committed Dec 5, 2023
1 parent a8874cf commit e386387
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 0 deletions.
8 changes: 8 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -2718,6 +2718,14 @@ def PragmaClangTextSection : InheritableAttr {
let Documentation = [InternalOnly];
}

def CodeModel : InheritableAttr {
let Spellings = [GCC<"model">];
let Args = [StringArgument<"Model">];
let Subjects =
SubjectList<[ GlobalVar ], ErrorDiag>;
let Documentation = [CodeModelDocs];
}

def Sentinel : InheritableAttr {
let Spellings = [GCC<"sentinel">];
let Args = [DefaultIntArgument<"Sentinel", 0>,
Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -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 you to specify a specific code model a
global variable should be in after translation.
}];
let Heading = "model";
}

def UsedDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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 yet 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<
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4841,6 +4841,19 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty,
isExternallyVisible(D->getLinkageAndVisibility().getLinkage()))
GV->setSection(".cp.rodata");

// Handle code model attribute
if (D->hasAttr<CodeModelAttr>()) {
if (const CodeModelAttr *CMA = D->getAttr<CodeModelAttr>()) {
auto CM = llvm::StringSwitch<llvm::CodeModel::Model>(CMA->getModel())
.Case("tiny", llvm::CodeModel::Tiny)
.Case("kernel", llvm::CodeModel::Kernel)
.Case("medium", llvm::CodeModel::Medium)
.Case("large", llvm::CodeModel::Large)
.Default(llvm::CodeModel::Small);
GV->setCodeModel(CM);
}
}

// 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.
Expand Down
30 changes: 30 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3369,6 +3369,33 @@ static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}

static void handleCodeModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef CM;
StringRef Str;
SourceLocation LiteralLoc;
bool Ok = false;
// Check that it is a string.
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc))
return;

CM = Str;
if (S.getASTContext().getTargetInfo().getTriple().isLoongArch()) {
Ok = CM == "normal" || CM == "medium" || CM == "extreme";
CM = llvm::StringSwitch<StringRef>(CM)
.Case("normal", "small")
.Case("extreme", "large")
.Default(CM);
}

// Check that the value.
if (!Ok) {
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,
Expand Down Expand Up @@ -9309,6 +9336,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;
Expand Down
10 changes: 10 additions & 0 deletions clang/test/CodeGen/LoongArch/attributes.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// RUN: %clang_cc1 -emit-llvm -triple loongarch64 %s -o - | FileCheck %s

// CHECK: @normal ={{.*}} global i32 0, code_model "small"
int normal __attribute__((model("normal")));

// CHECK: @medium ={{.*}} global i32 0, code_model "medium"
int medium __attribute__((model("medium")));

// CHECK: @extreme ={{.*}} global i32 0, code_model "large"
int extreme __attribute__((model("extreme")));
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
// CHECK-NEXT: CarriesDependency (SubjectMatchRule_variable_is_parameter, SubjectMatchRule_objc_method, SubjectMatchRule_function)
// CHECK-NEXT: Cleanup (SubjectMatchRule_variable_is_local)
// CHECK-NEXT: CmseNSEntry (SubjectMatchRule_function)
// CHECK-NEXT: CodeModel (SubjectMatchRule_variable_is_global)
// CHECK-NEXT: Cold (SubjectMatchRule_function)
// CHECK-NEXT: Common (SubjectMatchRule_variable)
// CHECK-NEXT: ConstInit (SubjectMatchRule_variable_is_global)
Expand Down
13 changes: 13 additions & 0 deletions clang/test/Sema/loongarch-attr-model.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: %clang_cc1 -triple loongarch64 -verify -fsyntax-only %s

#if !__has_attribute(model)
#error "Should support model attribute"
#endif

int a __attribute((model("tiny"))); // expected-error {{code_model 'tiny' is not yet supported on this target}}
int b __attribute((model("small"))); // expected-error {{code_model 'small' is not yet supported on this target}}
int c __attribute((model("normal"))); // no-warning
int d __attribute((model("kernel"))); // expected-error {{code_model 'kernel' is not yet supported on this target}}
int e __attribute((model("medium"))); // no-warning
int f __attribute((model("large"))); // expected-error {{code_model 'large' is not yet supported on this target}}
int g __attribute((model("extreme"))); // no-warning

0 comments on commit e386387

Please sign in to comment.