[clang] [llvm] [LoongArch] Support per-global code model attribute for LoongArch (PR #72079)

via cfe-commits cfe-commits at lists.llvm.org
Mon Dec 4 20:18:38 PST 2023


https://github.com/heiher updated https://github.com/llvm/llvm-project/pull/72079

>From 478cbb52d3ed3c6311389dd48c8d187cb28de18d Mon Sep 17 00:00:00 2001
From: WANG Rui <wangrui at loongson.cn>
Date: Fri, 10 Nov 2023 21:07:48 -0600
Subject: [PATCH 1/2] [clang] Add per-global code model attribute

This adds a per-global code model attribute, which can override
the target's code model to access global variables.

Suggested-by: Arthur Eubanks <aeubanks at google.com>
Signed-off-by: WANG Rui <wangrui at loongson.cn>
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
---
 clang/include/clang/Basic/Attr.td             |  8 ++++++++
 clang/include/clang/Basic/AttrDocs.td         |  9 +++++++++
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 ++
 clang/lib/CodeGen/CodeGenModule.cpp           | 13 ++++++++++++
 clang/lib/Sema/SemaDeclAttr.cpp               | 20 +++++++++++++++++++
 clang/test/CodeGen/attributes.c               | 15 ++++++++++++++
 ...a-attribute-supported-attributes-list.test |  1 +
 clang/test/Sema/attr-model.c                  | 12 +++++++++++
 8 files changed, 80 insertions(+)
 create mode 100644 clang/test/Sema/attr-model.c

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 1800f584c7e10..d5b5717f3d77c 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -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>,
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index b45ec6bbb8d37..1d37c2da6bec0 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 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 = [{
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6dfb2d7195203..d438fdde9ac7e 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 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<
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index dea58a7ff4146..1f49721e79ddc 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -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.
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 87c78d742d0ff..a4dace539d096 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3369,6 +3369,23 @@ static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   }
 }
 
+static void handleCodeModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+  StringRef CM;
+  SourceLocation LiteralLoc;
+  // Check that it is a string.
+  if (!S.checkStringLiteralArgumentAttr(AL, 0, CM, &LiteralLoc))
+    return;
+
+  // Check that the value.
+  if (CM != "tiny" && CM != "small" && CM != "kernel" && CM != "medium" &&
+      CM != "large") {
+    S.Diag(LiteralLoc, diag::err_attr_codemodel_arg) << CM;
+    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 +9326,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/attributes.c b/clang/test/CodeGen/attributes.c
index 5afef72b747af..7783d87b84c29 100644
--- a/clang/test/CodeGen/attributes.c
+++ b/clang/test/CodeGen/attributes.c
@@ -25,6 +25,21 @@ int t6 __attribute__((visibility("protected")));
 // CHECK: @t12 ={{.*}} global i32 0, section "SECT"
 int t12 __attribute__((section("SECT")));
 
+// CHECK: @tiny ={{.*}} global i32 0, code_model "tiny"
+int tiny __attribute__((model("tiny")));
+
+// CHECK: @small ={{.*}} global i32 0, code_model "small"
+int small __attribute__((model("small")));
+
+// CHECK: @kernel ={{.*}} global i32 0, code_model "kernel"
+int kernel __attribute__((model("kernel")));
+
+// CHECK: @medium ={{.*}} global i32 0, code_model "medium"
+int medium __attribute__((model("medium")));
+
+// CHECK: @large ={{.*}} global i32 0, code_model "large"
+int large __attribute__((model("large")));
+
 // CHECK: @t9 = weak{{.*}} alias void (...), ptr @__t8
 void __t8() {}
 void t9() __attribute__((weak, alias("__t8")));
diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
index dd91f4f88ad68..2b191abdac8b5 100644
--- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -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)
diff --git a/clang/test/Sema/attr-model.c b/clang/test/Sema/attr-model.c
new file mode 100644
index 0000000000000..cc46a60e48935
--- /dev/null
+++ b/clang/test/Sema/attr-model.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple x86_64 -verify -fsyntax-only %s
+
+#if !__has_attribute(model)
+#error "Should support model attribute"
+#endif
+
+int a __attribute((model("tiny"))); // no-warning
+int b __attribute((model("small"))); // no-warning
+int c __attribute((model("kernel"))); // no-warning
+int d __attribute((model("medium"))); // no-warning
+int e __attribute((model("large"))); // no-warning
+int f __attribute((model("huge"))); // expected-error {{code_model 'huge' is not yet supported on this target}}

>From f34aaa516df47ead79db6e272de1ed3abd25ecdd Mon Sep 17 00:00:00 2001
From: WANG Rui <wangrui at loongson.cn>
Date: Fri, 10 Nov 2023 21:07:50 -0600
Subject: [PATCH 2/2] [LoongArch] Support per-global code model attribute for
 LoongArch

This patch gets the code model from global variable attribute if it has,
otherwise the target's will be used.

This patch also maps GCC's code model names to LLVM's, which allows for
better compatibility between the two compilers.

Signed-off-by: WANG Rui <wangrui at loongson.cn>
---
 clang/lib/Sema/SemaDeclAttr.cpp               | 21 +++++++--
 clang/test/Sema/loongarch-attr-model.c        | 13 ++++++
 .../LoongArch/LoongArchISelLowering.cpp       | 24 +++++++---
 .../Target/LoongArch/LoongArchISelLowering.h  |  3 +-
 .../LoongArch/global-variable-code-model.ll   | 44 +++++++++++++++++++
 5 files changed, 95 insertions(+), 10 deletions(-)
 create mode 100644 clang/test/Sema/loongarch-attr-model.c
 create mode 100644 llvm/test/CodeGen/LoongArch/global-variable-code-model.ll

diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index a4dace539d096..bdfea963dfd97 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3371,15 +3371,28 @@ 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, CM, &LiteralLoc))
+  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);
+  } else {
+    Ok = CM == "tiny" || CM == "small" || CM == "kernel" || CM == "medium" ||
+         CM == "large";
+  }
+
   // Check that the value.
-  if (CM != "tiny" && CM != "small" && CM != "kernel" && CM != "medium" &&
-      CM != "large") {
-    S.Diag(LiteralLoc, diag::err_attr_codemodel_arg) << CM;
+  if (!Ok) {
+    S.Diag(LiteralLoc, diag::err_attr_codemodel_arg) << Str;
     return;
   }
 
diff --git a/clang/test/Sema/loongarch-attr-model.c b/clang/test/Sema/loongarch-attr-model.c
new file mode 100644
index 0000000000000..3f32f9fba8768
--- /dev/null
+++ b/clang/test/Sema/loongarch-attr-model.c
@@ -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
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index d297d115d59cb..e9504bb05ccb1 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -720,12 +720,13 @@ static SDValue getTargetNode(JumpTableSDNode *N, SDLoc DL, EVT Ty,
 
 template <class NodeTy>
 SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
+                                         CodeModel::Model M,
                                          bool IsLocal) const {
   SDLoc DL(N);
   EVT Ty = getPointerTy(DAG.getDataLayout());
   SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
 
-  switch (DAG.getTarget().getCodeModel()) {
+  switch (M) {
   default:
     report_fatal_error("Unsupported code model");
 
@@ -766,24 +767,37 @@ SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
 
 SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op,
                                                    SelectionDAG &DAG) const {
-  return getAddr(cast<BlockAddressSDNode>(Op), DAG);
+  return getAddr(cast<BlockAddressSDNode>(Op), DAG,
+                 DAG.getTarget().getCodeModel());
 }
 
 SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op,
                                                 SelectionDAG &DAG) const {
-  return getAddr(cast<JumpTableSDNode>(Op), DAG);
+  return getAddr(cast<JumpTableSDNode>(Op), DAG,
+                 DAG.getTarget().getCodeModel());
 }
 
 SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
                                                    SelectionDAG &DAG) const {
-  return getAddr(cast<ConstantPoolSDNode>(Op), DAG);
+  return getAddr(cast<ConstantPoolSDNode>(Op), DAG,
+                 DAG.getTarget().getCodeModel());
 }
 
 SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
                                                     SelectionDAG &DAG) const {
   GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
   assert(N->getOffset() == 0 && "unexpected offset in global node");
-  return getAddr(N, DAG, N->getGlobal()->isDSOLocal());
+  auto CM = DAG.getTarget().getCodeModel();
+  const GlobalValue *GV = N->getGlobal();
+
+  if (GV->isDSOLocal()) {
+    if (auto *G = dyn_cast<GlobalVariable>(GV)) {
+      if (auto GCM = G->getCodeModel())
+        CM = *GCM;
+    }
+  }
+
+  return getAddr(N, DAG, CM, GV->isDSOLocal());
 }
 
 SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N,
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index ec1e3351ac87b..439521d9218b2 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -251,7 +251,8 @@ class LoongArchTargetLowering : public TargetLowering {
                          LoongArchCCAssignFn Fn) const;
 
   template <class NodeTy>
-  SDValue getAddr(NodeTy *N, SelectionDAG &DAG, bool IsLocal = true) const;
+  SDValue getAddr(NodeTy *N, SelectionDAG &DAG, CodeModel::Model M,
+                  bool IsLocal = true) const;
   SDValue getStaticTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG,
                            unsigned Opc, bool Large = false) const;
   SDValue getDynamicTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG,
diff --git a/llvm/test/CodeGen/LoongArch/global-variable-code-model.ll b/llvm/test/CodeGen/LoongArch/global-variable-code-model.ll
new file mode 100644
index 0000000000000..db2feb5c0acdb
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/global-variable-code-model.ll
@@ -0,0 +1,44 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=loongarch64 < %s | FileCheck %s
+
+ at a= external dso_local global i32, code_model "small", align 4
+
+define dso_local signext i32 @local_small() #0 {
+; CHECK-LABEL: local_small:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pcalau12i $a0, %pc_hi20(a)
+; CHECK-NEXT:    addi.d $a0, $a0, %pc_lo12(a)
+; CHECK-NEXT:    ld.w $a0, $a0, 0
+; CHECK-NEXT:    ret
+  %1 = load i32, ptr @a, align 4
+  ret i32 %1
+}
+
+ at b= external dso_local global i32, code_model "large", align 4
+
+define dso_local signext i32 @local_large() #0 {
+; CHECK-LABEL: local_large:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pcalau12i $a0, %pc_hi20(b)
+; CHECK-NEXT:    addi.d $a1, $zero, %pc_lo12(b)
+; CHECK-NEXT:    lu32i.d $a1, %pc64_lo20(b)
+; CHECK-NEXT:    lu52i.d $a1, $a1, %pc64_hi12(b)
+; CHECK-NEXT:    add.d $a0, $a1, $a0
+; CHECK-NEXT:    ld.w $a0, $a0, 0
+; CHECK-NEXT:    ret
+  %1 = load i32, ptr @b, align 4
+  ret i32 %1
+}
+
+ at c= external global i32, code_model "large", align 4
+
+define dso_local signext i32 @non_local_large() #0 {
+; CHECK-LABEL: non_local_large:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pcalau12i $a0, %got_pc_hi20(c)
+; CHECK-NEXT:    ld.d $a0, $a0, %got_pc_lo12(c)
+; CHECK-NEXT:    ld.w $a0, $a0, 0
+; CHECK-NEXT:    ret
+  %1 = load i32, ptr @c, align 4
+  ret i32 %1
+}



More information about the cfe-commits mailing list