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