edward-jones created this revision.
Herald added subscribers: vkmr, frasercrmck, dexonsmith, dang, jdoerfert, 
evandro, luismarques, apazos, sameer.abuasal, simoncook, s.egerton, Jim, benna, 
psnobl, jocewei, PkmX, the_o, brucehoult, MartinMosbeck, rogfer01, zzheng, 
jrtc27, shiva0217, kito-cheng, niosHD, sabuasal, johnrusso, rbar, asb.
Herald added a reviewer: aaron.ballman.
edward-jones requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay.
Herald added a project: clang.

This is the Clang component of a change to add support for a proposed 'overlay' 
system for RISC-V to LLVM.

This adds two new attributes, __attribute__((overlaydata)), and 
__attribute__((overlaycall)), which are used to mark functions or global data 
as only accessible through the overlay engine. Internally they are converted to 
'overlay-data' and 'overlay-call' attributes in LLVM IR.

This change also adds the option `-fcomrv` to enable use of the overlay system. 
This has the effect of reserving registers x28, x29, x30 and x31 for exclusive 
used by the overlay engine.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D109372

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticDriverKinds.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Basic/LangOptions.def
  clang/include/clang/Driver/Options.td
  clang/lib/AST/TypePrinter.cpp
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/Driver/ToolChains/Arch/RISCV.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Driver/ToolChains/CommonArgs.cpp
  clang/lib/Driver/ToolChains/RISCVToolchain.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/CodeGen/riscv-overlaycall.c
  clang/test/Driver/riscv-comrv.c
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/Sema/attr-overlaycall.c
  clang/test/Sema/riscv-overlaycall-namespace.cpp

Index: clang/test/Sema/riscv-overlaycall-namespace.cpp
===================================================================
--- /dev/null
+++ clang/test/Sema/riscv-overlaycall-namespace.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -verify -fsyntax-only -fcomrv
+// RUN: %clang_cc1 %s -triple riscv64-unknown-elf -verify -fsyntax-only -fcomrv
+
+namespace {
+class foo {
+public:
+  static int X() __attribute__((overlaycall)) { return 0; } // expected-error {{RISC-V 'overlaycall' attribute not supported on static functions}}
+};
+} // end of anonymous namespace
+
+namespace X {
+  class bar {
+  public:
+    static int X() __attribute__((overlaycall)) { return 1; }
+  };
+} // end of namespace X
+
+extern "C" {
+int main(void) { return foo::X() + X::bar::X(); }
+}
Index: clang/test/Sema/attr-overlaycall.c
===================================================================
--- /dev/null
+++ clang/test/Sema/attr-overlaycall.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple riscv32 -fcomrv -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple riscv64 -fcomrv -fsyntax-only -verify %s
+
+int notAFunction __attribute__((overlaycall));
+// expected-warning@-1 {{'overlaycall' attribute only applies to functions}}
+
+void incompatForwardDecl(int x);
+void __attribute__((overlaycall)) incompatForwardDecl(int x) {}
+// expected-error@-1 {{redeclaration of 'incompatForwardDecl' must not have the RISC-V 'overlaycall' attribute}}
+// expected-note@-3 {{previous definition is here}}
+
+static void staticcall() __attribute__((overlaycall)) {}
+// expected-error@-1 {{attribute not supported on static functions}}
+// expected-warning@-2 {{GCC does not allow 'overlaycall' attribute in this position on a function definition}}
+
+static void __attribute__((overlaycall)) staticcall2(){}
+// expected-error@-1 {{attribute not supported on static functions}}
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -147,6 +147,7 @@
 // CHECK-NEXT: PassObjectSize (SubjectMatchRule_variable_is_parameter)
 // CHECK-NEXT: PatchableFunctionEntry (SubjectMatchRule_function, SubjectMatchRule_objc_method)
 // CHECK-NEXT: Pointer (SubjectMatchRule_record_not_is_union)
+// CHECK-NEXT: RISCVOverlayCall (SubjectMatchRule_function)
 // CHECK-NEXT: ReleaseHandle (SubjectMatchRule_variable_is_parameter)
 // CHECK-NEXT: RenderScriptKernel (SubjectMatchRule_function)
 // CHECK-NEXT: ReqdWorkGroupSize (SubjectMatchRule_function)
Index: clang/test/Driver/riscv-comrv.c
===================================================================
--- /dev/null
+++ clang/test/Driver/riscv-comrv.c
@@ -0,0 +1,8 @@
+// Check ComRV Driver Arguments
+//
+// REQUIRES: riscv-registered-target
+//
+// RUN: %clang -target riscv32-unknown-elf -fcomrv \
+// RUN:   -march=rv32if -mabi=ilp32f -### -c %s 2>&1 \
+// RUN:   | FileCheck -check-prefix=INVALID-ABI %s
+// INVALID-ABI: invalid ABI 'ilp32f' when using -fcomrv
Index: clang/test/CodeGen/riscv-overlaycall.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/riscv-overlaycall.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -triple=riscv64 -fcomrv -emit-llvm -o - \
+// RUN:    | FileCheck %s
+
+int __attribute__((overlaycall)) test_overlay_func(void) {
+// CHECK-LABEL: define{{.*}}@test_overlay_func() #0 align 4 {
+// CHECK: attributes #0 = {
+// CHECK-SAME: "overlay-call"
+  return 5;
+}
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -2039,6 +2039,28 @@
   D->addAttr(::new (S.Context) CmseNSEntryAttr(S.Context, AL));
 }
 
+static void handleRISCVOverlayCallAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+  if (!isFunctionOrMethod(D)) {
+    S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
+        << AL << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  const auto *FD = cast<FunctionDecl>(D);
+  if (!FD->isExternallyVisible()) {
+    S.Diag(AL.getLoc(), diag::err_overlaycall_static);
+    AL.setInvalid();
+    return;
+  }
+
+  // overlaycall implies noinline
+  Attr *A = ::new(S.Context) NoInlineAttr(S.Context, AL);
+  A->setImplicit(true);
+  D->addAttr(A);
+
+  handleSimpleAttribute<RISCVOverlayCallAttr>(S, D, AL);
+}
+
 static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   if (AL.isDeclspecAttribute()) {
     const auto &Triple = S.getASTContext().getTargetInfo().getTriple();
@@ -8264,6 +8286,9 @@
   case ParsedAttr::AT_CmseNSEntry:
     handleCmseNSEntryAttr(S, D, AL);
     break;
+  case ParsedAttr::AT_RISCVOverlayCall:
+    handleRISCVOverlayCallAttr(S, D, AL);
+    break;
   case ParsedAttr::AT_StdCall:
   case ParsedAttr::AT_CDecl:
   case ParsedAttr::AT_FastCall:
@@ -8483,6 +8508,15 @@
     handleArmBuiltinAliasAttr(S, D, AL);
     break;
 
+  case ParsedAttr::AT_RISCVOverlayData:
+    if (!S.getLangOpts().RISCVOverlayFunctions) {
+      AL.setInvalid();
+      S.Diag(AL.getLoc(), diag::err_overlaydata_unsupported);
+      break;
+    }
+    D->addAttr(::new (S.Context) RISCVOverlayDataAttr(S.Context, AL));
+    break;
+
   case ParsedAttr::AT_AcquireHandle:
     handleAcquireHandleAttr(S, D, AL);
     break;
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -3358,6 +3358,15 @@
     }
   }
 
+  bool NewIsOverlayCall = New->hasAttr<RISCVOverlayCallAttr>();
+  bool OldIsOverlayCall = Old->hasAttr<RISCVOverlayCallAttr>();
+  if (NewIsOverlayCall != OldIsOverlayCall) {
+    Diag(New->getLocation(), diag::err_overlaycall_mismatch)
+      << New << OldIsOverlayCall;
+    notePreviousDefinition(Old, New->getLocation());
+    return true;
+  }
+
   if (const auto *ILA = New->getAttr<InternalLinkageAttr>())
     if (!Old->hasAttr<InternalLinkageAttr>()) {
       Diag(New->getLocation(), diag::err_attribute_missing_on_first_decl)
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -4063,6 +4063,9 @@
         {std::string(Split.first), std::string(Split.second)});
   }
 
+  // RISC-V overlay functions support
+  Opts.RISCVOverlayFunctions = Args.hasArg(OPT_fcomrv);
+
   return Diags.getNumErrors() == NumErrorsBefore;
 }
 
@@ -4455,6 +4458,9 @@
   Res.getCodeGenOpts().Argv0 = Argv0;
   Res.getCodeGenOpts().CommandLineArgs = CommandLineArgs;
 
+  // RISC-V overlay functions support
+  LangOpts.RISCVOverlayFunctions = Args.hasArg(OPT_fcomrv);
+
   FixupInvocation(Res, Diags, Args, DashX);
 
   return Diags.getNumErrors() == NumErrorsBefore;
Index: clang/lib/Driver/ToolChains/RISCVToolchain.cpp
===================================================================
--- clang/lib/Driver/ToolChains/RISCVToolchain.cpp
+++ clang/lib/Driver/ToolChains/RISCVToolchain.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "RISCVToolchain.h"
+#include "Arch/RISCV.h"
 #include "CommonArgs.h"
 #include "clang/Driver/Compilation.h"
 #include "clang/Driver/InputInfo.h"
Index: clang/lib/Driver/ToolChains/CommonArgs.cpp
===================================================================
--- clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -12,6 +12,7 @@
 #include "Arch/M68k.h"
 #include "Arch/Mips.h"
 #include "Arch/PPC.h"
+#include "Arch/RISCV.h"
 #include "Arch/SystemZ.h"
 #include "Arch/VE.h"
 #include "Arch/X86.h"
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -2095,6 +2095,16 @@
     CmdArgs.push_back("-tune-cpu");
     CmdArgs.push_back(Args.MakeArgString(TuneCPU));
   }
+
+  // If comrv mode is requested, pass on this flag, and produce an error if an
+  // invalid ABI has been requested
+  if (Args.getLastArg(options::OPT_fcomrv)) {
+    CmdArgs.push_back("-fcomrv");
+
+    if (ABIName != "ilp32")
+      getToolChain().getDriver().Diag(diag::err_drv_invalid_riscv_abi_fcomrv)
+          << ABIName;
+  }
 }
 
 void Clang::AddSparcTargetArgs(const ArgList &Args,
Index: clang/lib/Driver/ToolChains/Arch/RISCV.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Arch/RISCV.cpp
+++ clang/lib/Driver/ToolChains/Arch/RISCV.cpp
@@ -492,6 +492,15 @@
   if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
     getRISCFeaturesFromMcpu(D, Triple, Args, A, A->getValue(), Features);
 
+  // Handle features corresponding to custom language feature
+  // "RISCVOverlayFunctions"
+  if (Args.hasArg(options::OPT_fcomrv)) {
+    Features.push_back("+reserve-x28"); // Overlay Stack Register
+    Features.push_back("+reserve-x29"); // Overlay Stack Frames Pool Register
+    Features.push_back("+reserve-x30"); // Overlay Address Token Reg
+    Features.push_back("+reserve-x31"); // Overlay Entry Point Address Register
+  }
+
   // Handle features corresponding to "-ffixed-X" options
   if (Args.hasArg(options::OPT_ffixed_x1))
     Features.push_back("+reserve-x1");
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -1880,6 +1880,10 @@
     if (LangOpts.FunctionAlignment)
       F->setAlignment(llvm::Align(1ull << LangOpts.FunctionAlignment));
 
+  // Overlay functions must have a minimum 4-byte alignment.
+  if (F->getAlignment() < 4 && D->hasAttr<RISCVOverlayCallAttr>())
+    F->setAlignment(llvm::Align(4));
+
   // Some C++ ABIs require 2-byte alignment for member functions, in order to
   // reserve a bit for differentiating between virtual and non-virtual member
   // functions. If the current target's C++ ABI requires this and this is a
@@ -4525,6 +4529,9 @@
   if (CGDebugInfo *DI = getModuleDebugInfo())
     if (getCodeGenOpts().hasReducedDebugInfo())
       DI->EmitGlobalVariable(GV, D);
+
+  if (D->hasAttr<RISCVOverlayDataAttr>())
+    GV->addAttribute("overlay-data");
 }
 
 void CodeGenModule::EmitExternalVarDeclaration(const VarDecl *D) {
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ clang/lib/CodeGen/CGCall.cpp
@@ -2042,6 +2042,8 @@
       FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
     if (TargetDecl->hasAttr<ConvergentAttr>())
       FuncAttrs.addAttribute(llvm::Attribute::Convergent);
+    if (TargetDecl->hasAttr<RISCVOverlayCallAttr>())
+      FuncAttrs.addAttribute("overlay-call");
 
     if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
       AddAttributesFromFunctionProtoType(
Index: clang/lib/AST/TypePrinter.cpp
===================================================================
--- clang/lib/AST/TypePrinter.cpp
+++ clang/lib/AST/TypePrinter.cpp
@@ -1743,6 +1743,9 @@
   case attr::ArmMveStrictPolymorphism:
     OS << "__clang_arm_mve_strict_polymorphism";
     break;
+  case attr::RISCVOverlayData:
+    OS << "overlaydata";
+    break;
   }
   OS << "))";
 }
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -3229,6 +3229,9 @@
   HelpText<"Equivalent to -mcmodel=medium, compatible with RISC-V gcc.">;
 def menable_experimental_extensions : Flag<["-"], "menable-experimental-extensions">, Group<m_Group>,
   HelpText<"Enable use of experimental RISC-V extensions.">;
+def fcomrv : Flag<["-"], "fcomrv">, Group<f_Group>,
+  Flags<[CC1Option]>,
+  HelpText<"Enable RISC-V overlay functions support">;
 
 def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_arm_Features_Group>,
   HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64 only)">;
Index: clang/include/clang/Basic/LangOptions.def
===================================================================
--- clang/include/clang/Basic/LangOptions.def
+++ clang/include/clang/Basic/LangOptions.def
@@ -428,6 +428,8 @@
              "Controls how scalar integer arguments are extended in calls "
              "to unprototyped and varargs functions")
 
+LANGOPT(RISCVOverlayFunctions, 1, 0, "RISC-V overlay functions support")
+
 #undef LANGOPT
 #undef COMPATIBLE_LANGOPT
 #undef BENIGN_LANGOPT
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -309,6 +309,16 @@
   "repeated RISC-V 'interrupt' attribute">, InGroup<IgnoredAttributes>;
 def note_riscv_repeated_interrupt_attribute : Note<
   "repeated RISC-V 'interrupt' attribute is here">;
+def err_overlaycall_unsupported : Error<
+  "RISC-V 'overlaycall' attribute requires support to be enabled with "
+  "the -fcomrv option">;
+def err_overlaycall_static : Error<
+  "RISC-V 'overlaycall' attribute not supported on static functions">;
+def err_overlaycall_mismatch : Error<
+  "redeclaration of %0 must %select{not |}1have the RISC-V 'overlaycall' attribute">;
+def err_overlaydata_unsupported : Error<
+  "RISC-V 'overlaydata' attribute requires support to be enabled with "
+  "the -fcomrv option">;
 def warn_unused_parameter : Warning<"unused parameter %0">,
   InGroup<UnusedParameter>, DefaultIgnore;
 def warn_unused_but_set_parameter : Warning<"parameter %0 set but not used">,
Index: clang/include/clang/Basic/DiagnosticDriverKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -32,6 +32,8 @@
 def warn_drv_invalid_arch_name_with_suggestion : Warning<
   "ignoring invalid /arch: argument '%0'; for %select{64|32}1-bit expected one of %2">,
   InGroup<UnusedCommandLineArgument>;
+def err_drv_invalid_riscv_abi_fcomrv : Error<
+  "invalid ABI '%0' when using -fcomrv">;
 def warn_drv_avr_mcu_not_specified : Warning<
   "no target microcontroller specified on command line, cannot "
   "link standard libraries, please pass -mmcu=<mcu name>">,
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -2142,6 +2142,20 @@
   }];
 }
 
+def RISCVOverlayDocs : Documentation {
+  let Category = DocCatFunction;
+  let Heading = "overlaycall, overlaydata (RISCV)";
+  let Content = [{
+``__attribute__((overlaycall))`` indicates that a function resides in an
+overlay and therefore any calls to or from that function must be handled
+through the overlay engine.
+
+``__attribute__((overlaydata))`` is used to mark global constants and signifies
+that the global is in an overlay and can only be accessed using the overlay
+engine.
+  }];
+}
+
 def AVRInterruptDocs : Documentation {
   let Category = DocCatFunction;
   let Heading = "interrupt (AVR)";
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -118,6 +118,11 @@
 def GlobalVar : SubsetSubject<Var,
                              [{S->hasGlobalStorage()}], "global variables">;
 
+def GlobalConst : SubsetSubject<Var,
+                               [{S->hasGlobalStorage() &&
+                                 S->getType().isConstQualified()}],
+                               "global constants">;
+
 def InlineFunction : SubsetSubject<Function,
                              [{S->isInlineSpecified()}], "inline functions">;
 
@@ -339,6 +344,9 @@
 // Language option for CMSE extensions
 def Cmse : LangOpt<"Cmse">;
 
+// Language option for Overlay functions
+def RISCVOverlayFunctions : LangOpt<"RISCVOverlayFunctions">;
+
 // Defines targets for target-specific attributes. Empty lists are unchecked.
 class TargetSpec {
   // Specifies Architectures for which the target applies, based off the
@@ -1782,6 +1790,22 @@
   let Documentation = [RISCVInterruptDocs];
 }
 
+// This is not marked as a TargetSpecificAttr because that would trigger
+// an 'attribute ignored' warning, but we want to check it explicitly and
+// trigger an error.
+def RISCVOverlayCall : InheritableAttr {
+  let Spellings = [GCC<"overlaycall">];
+  let Subjects = SubjectList<[Function]>;
+  let LangOpts = [RISCVOverlayFunctions];
+  let Documentation = [RISCVOverlayDocs];
+}
+
+def RISCVOverlayData : TypeAttr, TargetSpecificAttr<TargetRISCV> {
+  let Spellings = [GCC<"overlaydata">];
+  let Subjects = SubjectList<[GlobalConst]>;
+  let Documentation = [RISCVOverlayDocs];
+}
+
 // This is not a TargetSpecificAttr so that is silently accepted and
 // ignored on other targets as encouraged by the OpenCL spec.
 //
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to