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 : SubsetSubjecthasGlobalStorage()}], "global variables">; +def GlobalConst : SubsetSubjecthasGlobalStorage() && + S->getType().isConstQualified()}], + "global constants">; + def InlineFunction : SubsetSubjectisInlineSpecified()}], "inline functions">; @@ -1782,6 +1787,18 @@ let Documentation = [RISCVInterruptDocs]; } +def RISCVOverlayCall : InheritableAttr, TargetSpecificAttr { + let Spellings = [Clang<"overlay_call">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [RISCVOverlayCallDocs]; +} + +def RISCVOverlayData : InheritableAttr, TargetSpecificAttr { + let Spellings = [Clang<"overlay_data">]; + let Subjects = SubjectList<[GlobalConst]>; + let Documentation = [RISCVOverlayDataDocs]; +} + // This is not a TargetSpecificAttr so that is silently accepted and // ignored on other targets as encouraged by the OpenCL spec. // Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -2142,6 +2142,52 @@ }]; } +def RISCVOverlayCallDocs : Documentation { + let Category = DocCatFunction; + let Heading = "overlay_call (RISCV)"; + let Content = [{ +Clang supports the ``__attribute__((overlay_call))`` attribute on RISC-V +targets. This attribute may be attached to a function definition and signifies +that the function is placed in a software overlay. In order to use this +attribute the ``-moverlay`` flag must also be specified during compilation. + +A function cannot be marked as ``overlay_call`` if it does not have external +linkage. This includes functions marked ``static`` or defined in an +anonymous namespace. + +When a function is marked with this attribute it is forced to have an +alignment of at least 4 bytes. + +When a function exists in an overlay it can only be called indirectly +through the RISC-V Overlay Runtime engine. The runtime engine is responsible +for shuffling overlay functions into resident memory as required. The +attribute facilities this as follows: + +* When referencing functions marked as ``overlay_call`` a 'token' is used + instead of an address. This 'token' encodes information for use by the + runtime engine. +* When calling to/from an overlay function the call target (either a + token or the address of a resident function) is first stored to an argument + register, then a call is performed into the runtime engine. +* When the address of a ``overlay_call`` function is taken the address + of a 'thunk' corresponding to that function is used instead. The + 'thunk' is a stub in resident memory which can be used in a normal + indirect call, but redirects the call through the runtime engine. + }]; +} + +def RISCVOverlayDataDocs : Documentation { + let Category = DocCatVariable; + let Heading = "overlay_data (RISCV)"; + let Content = [{ +Clang supports the ``__attribute__((overlay_data))`` attribute on RISC-V +targets. This attribute may be attached to a global constant declaration +and signifies that the value is placed in a software overlay. In order to +use this attribute the ``-moverlay`` flag must also be specified during +compilation. + }]; +} + def AVRInterruptDocs : Documentation { let Category = DocCatFunction; let Heading = "interrupt (AVR)"; 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; +def err_drv_invalid_riscv_abi_moverlay : Error< + "invalid ABI '%0' when using '-moverlay'">; def warn_drv_avr_mcu_not_specified : Warning< "no target microcontroller specified on command line, cannot " "link standard libraries, please pass -mmcu=">, Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -309,6 +309,13 @@ "repeated RISC-V 'interrupt' attribute">, InGroup; def note_riscv_repeated_interrupt_attribute : Note< "repeated RISC-V 'interrupt' attribute is here">; +def err_overlay_func_external_linkage : Error< + "functions marked with 'overlay_call' attribute must have external linkage">; +def err_overlay_mismatch : Error< + "redeclaration of %0 must %select{not |}1have the 'overlay_call' attribute">; +def warn_attribute_ignored_overlay : Warning< + "%0 attribute ignored, use '-moverlay' to enable support">, + InGroup; def warn_unused_parameter : Warning<"unused parameter %0">, InGroup, DefaultIgnore; def warn_unused_but_set_parameter : Warning<"parameter %0 set but not used">, Index: clang/include/clang/Basic/LangOptions.def =================================================================== --- clang/include/clang/Basic/LangOptions.def +++ clang/include/clang/Basic/LangOptions.def @@ -428,6 +428,10 @@ "Controls how scalar integer arguments are extended in calls " "to unprototyped and varargs functions") +LANGOPT(Overlay, 1, 0, + "Enable support for use of an overlay system for calls and data " + "accesses") + #undef LANGOPT #undef COMPATIBLE_LANGOPT #undef BENIGN_LANGOPT Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -3229,6 +3229,10 @@ HelpText<"Equivalent to -mcmodel=medium, compatible with RISC-V gcc.">; def menable_experimental_extensions : Flag<["-"], "menable-experimental-extensions">, Group, HelpText<"Enable use of experimental RISC-V extensions.">; +def moverlay : Flag<["-"], "moverlay">, + Group, Flags<[CC1Option]>, + HelpText<"Enable RISC-V overlay manager support">, + MarshallingInfoFlag>; def munaligned_access : Flag<["-"], "munaligned-access">, Group, HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64 only)">; Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -2199,8 +2199,12 @@ // Collect non-call-site function IR attributes from declaration-specific // information. if (!AttrOnCallSite) { - if (TargetDecl && TargetDecl->hasAttr()) - FuncAttrs.addAttribute("cmse_nonsecure_entry"); + if (TargetDecl) { + if (TargetDecl->hasAttr()) + FuncAttrs.addAttribute("overlay"); + if (TargetDecl->hasAttr()) + FuncAttrs.addAttribute("cmse_nonsecure_entry"); + } // Whether tail calls are enabled. auto shouldDisableTailCalls = [&] { 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()) + 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()) + GV->addAttribute("overlay"); } void CodeGenModule::EmitExternalVarDeclaration(const VarDecl *D) { 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,14 @@ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) getRISCFeaturesFromMcpu(D, Triple, Args, A, A->getValue(), Features); + // Extra register reservations required to handle -moverlay + if (Args.hasArg(options::OPT_moverlay)) { + 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/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -2095,6 +2095,15 @@ 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_moverlay)) { + CmdArgs.push_back("-moverlay"); + if (ABIName != "ilp32") + getToolChain().getDriver().Diag(diag::err_drv_invalid_riscv_abi_moverlay) + << ABIName; + } } void Clang::AddSparcTargetArgs(const ArgList &Args, Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -3358,6 +3358,15 @@ } } + bool NewIsOverlayCall = New->hasAttr(); + bool OldIsOverlayCall = Old->hasAttr(); + if (NewIsOverlayCall != OldIsOverlayCall) { + Diag(New->getLocation(), diag::err_overlay_mismatch) + << New << OldIsOverlayCall; + notePreviousDefinition(Old, New->getLocation()); + return true; + } + if (const auto *ILA = New->getAttr()) if (!Old->hasAttr()) { Diag(New->getLocation(), diag::err_attribute_missing_on_first_decl) Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -2039,6 +2039,33 @@ D->addAttr(::new (S.Context) CmseNSEntryAttr(S.Context, AL)); } +static void handleRISCVOverlayAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!S.getLangOpts().Overlay) { + S.Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored_overlay) + << AL; + return; + } + + if (isFunctionOrMethod(D)) { + const auto *ND = cast(D); + if (!ND->isExternallyVisible()) { + S.Diag(AL.getLoc(), diag::err_overlay_func_external_linkage); + AL.setInvalid(); + return; + } + + // 'overlay' on a function implies 'noinline' + Attr *A = ::new (S.Context) NoInlineAttr(S.Context, AL); + A->setImplicit(true); + D->addAttr(A); + } + + if (AL.getKind() == ParsedAttr::AT_RISCVOverlayCall) + handleSimpleAttribute(S, D, AL); + else + handleSimpleAttribute(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 +8291,10 @@ case ParsedAttr::AT_CmseNSEntry: handleCmseNSEntryAttr(S, D, AL); break; + case ParsedAttr::AT_RISCVOverlayCall: + case ParsedAttr::AT_RISCVOverlayData: + handleRISCVOverlayAttr(S, D, AL); + break; case ParsedAttr::AT_StdCall: case ParsedAttr::AT_CDecl: case ParsedAttr::AT_FastCall: Index: clang/test/CodeGen/riscv-overlay.c =================================================================== --- /dev/null +++ clang/test/CodeGen/riscv-overlay.c @@ -0,0 +1,11 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes +// RUN: %clang_cc1 -triple riscv32 -moverlay -emit-llvm %s -o - \ +// RUN: | FileCheck %s + +// CHECK-LABEL: @test_overlay_func( +// CHECK-SAME: #0 +// CHECK: attributes #0 = { +// CHECK-SAME: "overlay" +int __attribute__((overlay_call)) test_overlay_func(void) { + return 5; +} Index: clang/test/Driver/riscv-overlay.c =================================================================== --- /dev/null +++ clang/test/Driver/riscv-overlay.c @@ -0,0 +1,5 @@ +// Check that ComRV Driver Arguments + +// RUN: not %clang -target riscv32 -moverlay %s -o %t.o -mabi=ilp32f 2>&1 \ +// RUN: | FileCheck -check-prefix=INVALID-ABI %s +// INVALID-ABI: invalid ABI 'ilp32f' when using '-moverlay' 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/Sema/riscv-overlay-attr.c =================================================================== --- /dev/null +++ clang/test/Sema/riscv-overlay-attr.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple riscv32 -moverlay -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple riscv64 -moverlay -fsyntax-only -verify %s + +int notAFunction __attribute__((overlay_call)); +// expected-warning@-1 {{'overlay_call' attribute only applies to functions}} + +void incompatForwardDecl(int x); +void __attribute__((overlay_call)) incompatForwardDecl(int x) {} +// expected-error@-1 {{redeclaration of 'incompatForwardDecl' must not have the 'overlay_call' attribute}} +// expected-note@-3 {{previous definition is here}} + +static void staticcall() __attribute__((overlay_call)) {} +// expected-error@-1 {{functions marked with 'overlay_call' attribute must have external linkage}} + +static void __attribute__((overlay_call)) staticcall2() {} +// expected-error@-1 {{functions marked with 'overlay_call' attribute must have external linkage}} Index: clang/test/Sema/riscv-overlay-namespace.cpp =================================================================== --- /dev/null +++ clang/test/Sema/riscv-overlay-namespace.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -verify -fsyntax-only -moverlay +// RUN: %clang_cc1 %s -triple riscv64-unknown-elf -verify -fsyntax-only -moverlay + +namespace { +class foo { +public: + static int X() __attribute__((overlay_call)) { return 0; } // expected-error {{functions marked with 'overlay_call' attribute must have external linkage}} +}; +} // end of anonymous namespace + +namespace X { +class bar { +public: + static int X() __attribute__((overlay_call)) { return 1; } +}; +} // end of namespace X + +extern "C" { +int main(void) { return foo::X() + X::bar::X(); } +}