[RISCV] SiFive CLIC Support (#132481)
This Change adds support for two SiFive vendor attributes in clang: - "SiFive-CLIC-preemptible" - "SiFive-CLIC-stack-swap" These can be given together, and can be combined with "machine", but cannot be combined with any other interrupt attribute values. These are handled primarily in RISCVFrameLowering: - "SiFive-CLIC-stack-swap" entails swapping `sp` with `sf.mscratchcsw` at function entry and exit, which holds the trap stack pointer. - "SiFive-CLIC-preemptible" entails saving `mcause` and `mepc` before re-enabling interrupts using `mstatus`. To save these, `s0` and `s1` are first spilled to the stack, and then the values are read into these registers. If these registers are used in the function, their values will be spilled a second time onto the stack with the generic callee-saved-register handling. At the end of the function interrupts are disabled again before `mepc` and `mcause` are restored. This Change also adds support for the following two experimental extensions, which only contain CSRs: - XSfsclic - for SiFive's CLIC Supervisor-Mode CSRs - XSfmclic - for SiFive's CLIC Machine-Mode CSRs The latter is needed for interrupt support. The CFI information for this implementation is not correct, but I'd prefer to correct this in a follow-up. While it's unlikely anyone wants to unwind through a handler, the CFI information is also used by debuggers so it would be good to get it right. Co-authored-by: Ana Pazos <apazos@quicinc.com>
This commit is contained in:
parent
5137587fb1
commit
cfc5baf6e6
@ -634,6 +634,12 @@ RISC-V Support
|
|||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
- Add support for `-mtune=generic-ooo` (a generic out-of-order model).
|
- Add support for `-mtune=generic-ooo` (a generic out-of-order model).
|
||||||
|
- Adds support for `__attribute__((interrupt("SiFive-CLIC-preemptible")))` and
|
||||||
|
`__attribute__((interrupt("SiFive-CLIC-stack-swap")))`. The former
|
||||||
|
automatically saves some interrupt CSRs before re-enabling interrupts in the
|
||||||
|
function prolog, the latter swaps `sp` with the value in a CSR before it is
|
||||||
|
used or modified. These two can also be combined, and can be combined with
|
||||||
|
`interrupt("machine")`.
|
||||||
|
|
||||||
- Adds support for `__attribute__((interrupt("qci-nest")))` and
|
- Adds support for `__attribute__((interrupt("qci-nest")))` and
|
||||||
`__attribute__((interrupt("qci-nonest")))`. These use instructions from
|
`__attribute__((interrupt("qci-nonest")))`. These use instructions from
|
||||||
|
@ -2252,10 +2252,23 @@ def NoMicroMips : InheritableAttr, TargetSpecificAttr<TargetMips32> {
|
|||||||
def RISCVInterrupt : InheritableAttr, TargetSpecificAttr<TargetRISCV> {
|
def RISCVInterrupt : InheritableAttr, TargetSpecificAttr<TargetRISCV> {
|
||||||
let Spellings = [GCC<"interrupt">];
|
let Spellings = [GCC<"interrupt">];
|
||||||
let Subjects = SubjectList<[Function]>;
|
let Subjects = SubjectList<[Function]>;
|
||||||
let Args = [EnumArgument<"Interrupt", "InterruptType", /*is_string=*/true,
|
let Args = [VariadicEnumArgument<"Interrupt", "InterruptType", /*is_string=*/true,
|
||||||
["supervisor", "machine", "qci-nest", "qci-nonest"],
|
[
|
||||||
["supervisor", "machine", "qcinest", "qcinonest"],
|
"supervisor",
|
||||||
1>];
|
"machine",
|
||||||
|
"qci-nest",
|
||||||
|
"qci-nonest",
|
||||||
|
"SiFive-CLIC-preemptible",
|
||||||
|
"SiFive-CLIC-stack-swap",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"supervisor",
|
||||||
|
"machine",
|
||||||
|
"qcinest",
|
||||||
|
"qcinonest",
|
||||||
|
"SiFiveCLICPreemptible",
|
||||||
|
"SiFiveCLICStackSwap",
|
||||||
|
]>];
|
||||||
let ParseKind = "Interrupt";
|
let ParseKind = "Interrupt";
|
||||||
let Documentation = [RISCVInterruptDocs];
|
let Documentation = [RISCVInterruptDocs];
|
||||||
}
|
}
|
||||||
|
@ -2900,8 +2900,9 @@ targets. This attribute may be attached to a function definition and instructs
|
|||||||
the backend to generate appropriate function entry/exit code so that it can be
|
the backend to generate appropriate function entry/exit code so that it can be
|
||||||
used directly as an interrupt service routine.
|
used directly as an interrupt service routine.
|
||||||
|
|
||||||
Permissible values for this parameter are ``supervisor``, ``machine``,
|
Permissible values for this parameter are ``machine``, ``supervisor``,
|
||||||
``qci-nest`` and ``qci-nonest``. If there is no parameter, then it defaults to
|
``qci-nest``, ``qci-nonest``, ``SiFive-CLIC-preemptible``, and
|
||||||
|
``SiFive-CLIC-stack-swap``. If there is no parameter, then it defaults to
|
||||||
``machine``.
|
``machine``.
|
||||||
|
|
||||||
The ``qci-nest`` and ``qci-nonest`` values require Qualcomm's Xqciint extension
|
The ``qci-nest`` and ``qci-nonest`` values require Qualcomm's Xqciint extension
|
||||||
@ -2912,6 +2913,15 @@ restore interrupt state to the stack -- the ``qci-nest`` value will use
|
|||||||
begin the interrupt handler. Both of these will use ``qc.c.mileaveret`` to
|
begin the interrupt handler. Both of these will use ``qc.c.mileaveret`` to
|
||||||
restore the state and return to the previous context.
|
restore the state and return to the previous context.
|
||||||
|
|
||||||
|
The ``SiFive-CLIC-preemptible`` and ``SiFive-CLIC-stack-swap`` values are used
|
||||||
|
for machine-mode interrupts. For ``SiFive-CLIC-preemptible`` interrupts, the
|
||||||
|
values of ``mcause`` and ``mepc`` are saved onto the stack, and interrupts are
|
||||||
|
re-enabled. For ``SiFive-CLIC-stack-swap`` interrupts, the stack pointer is
|
||||||
|
swapped with ``mscratch`` before its first use and after its last use.
|
||||||
|
|
||||||
|
The SiFive CLIC values may be combined with each other and with the ``machine``
|
||||||
|
attribute value. Any other combination of different values is not allowed.
|
||||||
|
|
||||||
Repeated interrupt attribute on the same declaration will cause a warning
|
Repeated interrupt attribute on the same declaration will cause a warning
|
||||||
to be emitted. In case of repeated declarations, the last one prevails.
|
to be emitted. In case of repeated declarations, the last one prevails.
|
||||||
|
|
||||||
@ -2921,6 +2931,7 @@ https://riscv.org/specifications/privileged-isa/
|
|||||||
The RISC-V Instruction Set Manual Volume II: Privileged Architecture
|
The RISC-V Instruction Set Manual Volume II: Privileged Architecture
|
||||||
Version 1.10.
|
Version 1.10.
|
||||||
https://github.com/quic/riscv-unified-db/releases/tag/Xqci-0.7
|
https://github.com/quic/riscv-unified-db/releases/tag/Xqci-0.7
|
||||||
|
https://sifive.cdn.prismic.io/sifive/d1984d2b-c9b9-4c91-8de0-d68a5e64fa0f_sifive-interrupt-cookbook-v1p2.pdf
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12763,7 +12763,9 @@ def err_riscv_builtin_invalid_lmul : Error<
|
|||||||
def err_riscv_type_requires_extension : Error<
|
def err_riscv_type_requires_extension : Error<
|
||||||
"RISC-V type %0 requires the '%1' extension">;
|
"RISC-V type %0 requires the '%1' extension">;
|
||||||
def err_riscv_attribute_interrupt_requires_extension : Error<
|
def err_riscv_attribute_interrupt_requires_extension : Error<
|
||||||
"RISC-V interrupt attribute '%0' requires extension '%1'">;
|
"RISC-V 'interrupt' attribute '%0' requires extension '%1'">;
|
||||||
|
def err_riscv_attribute_interrupt_invalid_combination : Error<
|
||||||
|
"RISC-V 'interrupt' attribute contains invalid combination of interrupt types">;
|
||||||
|
|
||||||
def err_std_source_location_impl_not_found : Error<
|
def err_std_source_location_impl_not_found : Error<
|
||||||
"'std::source_location::__impl' was not found; it must be defined before '__builtin_source_location' is called">;
|
"'std::source_location::__impl' was not found; it must be defined before '__builtin_source_location' is called">;
|
||||||
|
@ -829,16 +829,39 @@ public:
|
|||||||
if (!Attr)
|
if (!Attr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const char *Kind;
|
StringRef Kind = "machine";
|
||||||
switch (Attr->getInterrupt()) {
|
bool HasSiFiveCLICPreemptible = false;
|
||||||
case RISCVInterruptAttr::supervisor: Kind = "supervisor"; break;
|
bool HasSiFiveCLICStackSwap = false;
|
||||||
case RISCVInterruptAttr::machine: Kind = "machine"; break;
|
for (RISCVInterruptAttr::InterruptType type : Attr->interrupt()) {
|
||||||
case RISCVInterruptAttr::qcinest:
|
switch (type) {
|
||||||
Kind = "qci-nest";
|
case RISCVInterruptAttr::machine:
|
||||||
break;
|
// Do not update `Kind` because `Kind` is already "machine", or the
|
||||||
case RISCVInterruptAttr::qcinonest:
|
// kinds also contains SiFive types which need to be applied.
|
||||||
Kind = "qci-nonest";
|
break;
|
||||||
break;
|
case RISCVInterruptAttr::supervisor:
|
||||||
|
Kind = "supervisor";
|
||||||
|
break;
|
||||||
|
case RISCVInterruptAttr::qcinest:
|
||||||
|
Kind = "qci-nest";
|
||||||
|
break;
|
||||||
|
case RISCVInterruptAttr::qcinonest:
|
||||||
|
Kind = "qci-nonest";
|
||||||
|
break;
|
||||||
|
// There are three different LLVM IR attribute values for SiFive CLIC
|
||||||
|
// interrupt kinds, one for each kind and one extra for their combination.
|
||||||
|
case RISCVInterruptAttr::SiFiveCLICPreemptible: {
|
||||||
|
HasSiFiveCLICPreemptible = true;
|
||||||
|
Kind = HasSiFiveCLICStackSwap ? "SiFive-CLIC-preemptible-stack-swap"
|
||||||
|
: "SiFive-CLIC-preemptible";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RISCVInterruptAttr::SiFiveCLICStackSwap: {
|
||||||
|
HasSiFiveCLICStackSwap = true;
|
||||||
|
Kind = HasSiFiveCLICPreemptible ? "SiFive-CLIC-preemptible-stack-swap"
|
||||||
|
: "SiFive-CLIC-stack-swap";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Fn->addFnAttr("interrupt", Kind);
|
Fn->addFnAttr("interrupt", Kind);
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "clang/Sema/SemaRISCV.h"
|
#include "clang/Sema/SemaRISCV.h"
|
||||||
#include "clang/AST/ASTContext.h"
|
#include "clang/AST/ASTContext.h"
|
||||||
#include "clang/AST/Attr.h"
|
#include "clang/AST/Attr.h"
|
||||||
|
#include "clang/AST/Attrs.inc"
|
||||||
#include "clang/AST/Decl.h"
|
#include "clang/AST/Decl.h"
|
||||||
#include "clang/Basic/Builtins.h"
|
#include "clang/Basic/Builtins.h"
|
||||||
#include "clang/Basic/TargetBuiltins.h"
|
#include "clang/Basic/TargetBuiltins.h"
|
||||||
@ -1453,25 +1454,14 @@ void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the attribute argument. Argument is optional.
|
|
||||||
if (!AL.checkAtMostNumArgs(SemaRef, 1))
|
|
||||||
return;
|
|
||||||
|
|
||||||
StringRef Str;
|
|
||||||
SourceLocation ArgLoc;
|
|
||||||
|
|
||||||
// 'machine'is the default interrupt mode.
|
|
||||||
if (AL.getNumArgs() == 0)
|
|
||||||
Str = "machine";
|
|
||||||
else if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Semantic checks for a function with the 'interrupt' attribute:
|
// Semantic checks for a function with the 'interrupt' attribute:
|
||||||
// - Must be a function.
|
// - Must be a function.
|
||||||
// - Must have no parameters.
|
// - Must have no parameters.
|
||||||
// - Must have the 'void' return type.
|
// - Must have the 'void' return type.
|
||||||
// - The attribute itself must either have no argument or one of the
|
// - The attribute itself must have at most 2 arguments
|
||||||
// valid interrupt types, see [RISCVInterruptDocs].
|
// - The attribute arguments must be string literals, and valid choices.
|
||||||
|
// - The attribute arguments must be a valid combination
|
||||||
|
// - The current target must support the right extensions for the combination.
|
||||||
|
|
||||||
if (D->getFunctionType() == nullptr) {
|
if (D->getFunctionType() == nullptr) {
|
||||||
Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
|
Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
|
||||||
@ -1491,35 +1481,105 @@ void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RISCVInterruptAttr::InterruptType Kind;
|
if (!AL.checkAtMostNumArgs(SemaRef, 2))
|
||||||
if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
|
return;
|
||||||
Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
|
|
||||||
<< AL << Str << ArgLoc;
|
bool HasSiFiveCLICType = false;
|
||||||
|
bool HasUnaryType = false;
|
||||||
|
|
||||||
|
SmallSet<RISCVInterruptAttr::InterruptType, 2> Types;
|
||||||
|
for (unsigned ArgIndex = 0; ArgIndex < AL.getNumArgs(); ++ArgIndex) {
|
||||||
|
RISCVInterruptAttr::InterruptType Type;
|
||||||
|
StringRef TypeString;
|
||||||
|
SourceLocation Loc;
|
||||||
|
|
||||||
|
if (!SemaRef.checkStringLiteralArgumentAttr(AL, ArgIndex, TypeString, &Loc))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!RISCVInterruptAttr::ConvertStrToInterruptType(TypeString, Type)) {
|
||||||
|
std::string TypeLiteral = ("\"" + TypeString + "\"").str();
|
||||||
|
Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
|
||||||
|
<< AL << TypeLiteral << Loc;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (Type) {
|
||||||
|
case RISCVInterruptAttr::machine:
|
||||||
|
// "machine" could be combined with the SiFive CLIC types, or could be
|
||||||
|
// just "machine".
|
||||||
|
break;
|
||||||
|
case RISCVInterruptAttr::SiFiveCLICPreemptible:
|
||||||
|
case RISCVInterruptAttr::SiFiveCLICStackSwap:
|
||||||
|
// SiFive-CLIC types can be combined with each other and "machine"
|
||||||
|
HasSiFiveCLICType = true;
|
||||||
|
break;
|
||||||
|
case RISCVInterruptAttr::supervisor:
|
||||||
|
case RISCVInterruptAttr::qcinest:
|
||||||
|
case RISCVInterruptAttr::qcinonest:
|
||||||
|
// "supervisor" and "qci-(no)nest" cannot be combined with any other types
|
||||||
|
HasUnaryType = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Types.insert(Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasUnaryType && Types.size() > 1) {
|
||||||
|
Diag(AL.getLoc(), diag::err_riscv_attribute_interrupt_invalid_combination);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (Kind) {
|
if (HasUnaryType && HasSiFiveCLICType) {
|
||||||
default:
|
Diag(AL.getLoc(), diag::err_riscv_attribute_interrupt_invalid_combination);
|
||||||
break;
|
return;
|
||||||
case RISCVInterruptAttr::InterruptType::qcinest:
|
|
||||||
case RISCVInterruptAttr::InterruptType::qcinonest: {
|
|
||||||
const TargetInfo &TI = getASTContext().getTargetInfo();
|
|
||||||
llvm::StringMap<bool> FunctionFeatureMap;
|
|
||||||
getASTContext().getFunctionFeatureMap(FunctionFeatureMap,
|
|
||||||
dyn_cast<FunctionDecl>(D));
|
|
||||||
|
|
||||||
if (!TI.hasFeature("experimental-xqciint") &&
|
|
||||||
!FunctionFeatureMap.lookup("experimental-xqciint")) {
|
|
||||||
Diag(AL.getLoc(), diag::err_riscv_attribute_interrupt_requires_extension)
|
|
||||||
<< Str << "Xqciint";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "machine" is the default, if nothing is specified.
|
||||||
|
if (AL.getNumArgs() == 0)
|
||||||
|
Types.insert(RISCVInterruptAttr::machine);
|
||||||
|
|
||||||
|
const TargetInfo &TI = getASTContext().getTargetInfo();
|
||||||
|
llvm::StringMap<bool> FunctionFeatureMap;
|
||||||
|
getASTContext().getFunctionFeatureMap(FunctionFeatureMap,
|
||||||
|
dyn_cast<FunctionDecl>(D));
|
||||||
|
|
||||||
|
auto HasFeature = [&](StringRef FeatureName) -> bool {
|
||||||
|
return TI.hasFeature(FeatureName) || FunctionFeatureMap.lookup(FeatureName);
|
||||||
};
|
};
|
||||||
|
|
||||||
D->addAttr(::new (getASTContext())
|
for (RISCVInterruptAttr::InterruptType Type : Types) {
|
||||||
RISCVInterruptAttr(getASTContext(), AL, Kind));
|
switch (Type) {
|
||||||
|
// The QCI interrupt types require Xqciint
|
||||||
|
case RISCVInterruptAttr::qcinest:
|
||||||
|
case RISCVInterruptAttr::qcinonest: {
|
||||||
|
if (!HasFeature("experimental-xqciint")) {
|
||||||
|
Diag(AL.getLoc(),
|
||||||
|
diag::err_riscv_attribute_interrupt_requires_extension)
|
||||||
|
<< RISCVInterruptAttr::ConvertInterruptTypeToStr(Type) << "Xqciint";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
// The SiFive CLIC interrupt types require Xsfmclic
|
||||||
|
case RISCVInterruptAttr::SiFiveCLICPreemptible:
|
||||||
|
case RISCVInterruptAttr::SiFiveCLICStackSwap: {
|
||||||
|
if (!HasFeature("experimental-xsfmclic")) {
|
||||||
|
Diag(AL.getLoc(),
|
||||||
|
diag::err_riscv_attribute_interrupt_requires_extension)
|
||||||
|
<< RISCVInterruptAttr::ConvertInterruptTypeToStr(Type)
|
||||||
|
<< "XSfmclic";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallVector<RISCVInterruptAttr::InterruptType, 2> TypesVec(Types.begin(),
|
||||||
|
Types.end());
|
||||||
|
|
||||||
|
D->addAttr(::new (getASTContext()) RISCVInterruptAttr(
|
||||||
|
getASTContext(), AL, TypesVec.data(), TypesVec.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SemaRISCV::isAliasValid(unsigned BuiltinID, StringRef AliasName) {
|
bool SemaRISCV::isAliasValid(unsigned BuiltinID, StringRef AliasName) {
|
||||||
|
@ -219,6 +219,8 @@
|
|||||||
// CHECK-NEXT: xqcisync 0.2 'Xqcisync' (Qualcomm uC Sync Delay Extension)
|
// CHECK-NEXT: xqcisync 0.2 'Xqcisync' (Qualcomm uC Sync Delay Extension)
|
||||||
// CHECK-NEXT: xrivosvisni 0.1 'XRivosVisni' (Rivos Vector Integer Small New)
|
// CHECK-NEXT: xrivosvisni 0.1 'XRivosVisni' (Rivos Vector Integer Small New)
|
||||||
// CHECK-NEXT: xrivosvizip 0.1 'XRivosVizip' (Rivos Vector Register Zips)
|
// CHECK-NEXT: xrivosvizip 0.1 'XRivosVizip' (Rivos Vector Register Zips)
|
||||||
|
// CHECK-NEXT: xsfmclic 0.1 'XSfmclic' (SiFive CLIC Machine-mode CSRs)
|
||||||
|
// CHECK-NEXT: xsfsclic 0.1 'XSfsclic' (SiFive CLIC Supervisor-mode CSRs)
|
||||||
// CHECK-EMPTY:
|
// CHECK-EMPTY:
|
||||||
// CHECK-NEXT: Supported Profiles
|
// CHECK-NEXT: Supported Profiles
|
||||||
// CHECK-NEXT: rva20s64
|
// CHECK-NEXT: rva20s64
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// RUN: %clang_cc1 -triple riscv32-unknown-elf -target-feature +experimental-xqciint -emit-llvm -DCHECK_IR < %s| FileCheck %s
|
// RUN: %clang_cc1 -triple riscv32-unknown-elf -target-feature +experimental-xqciint -emit-llvm -DCHECK_IR < %s | FileCheck %s
|
||||||
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -target-feature +experimental-xqciint -verify=enabled,both -fsyntax-only
|
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -target-feature +experimental-xqciint -verify=enabled,both -fsyntax-only
|
||||||
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -verify=disabled,both -fsyntax-only
|
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -verify=disabled,both -fsyntax-only
|
||||||
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -target-feature -experimental-xqciint -verify=disabled,both -fsyntax-only
|
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -target-feature -experimental-xqciint -verify=disabled,both -fsyntax-only
|
||||||
@ -11,10 +11,20 @@
|
|||||||
__attribute__((interrupt("qci-nest")))
|
__attribute__((interrupt("qci-nest")))
|
||||||
void foo_nest_interrupt(void) {}
|
void foo_nest_interrupt(void) {}
|
||||||
|
|
||||||
// CHECK-LABEL: @foo_nonnest_interrupt() #1
|
// CHECK-LABEL: @foo_nest_nest_interrupt() #0
|
||||||
|
// CHECK: ret void
|
||||||
|
__attribute__((interrupt("qci-nest", "qci-nest")))
|
||||||
|
void foo_nest_nest_interrupt(void) {}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @foo_nonest_interrupt() #1
|
||||||
// CHECK: ret void
|
// CHECK: ret void
|
||||||
__attribute__((interrupt("qci-nonest")))
|
__attribute__((interrupt("qci-nonest")))
|
||||||
void foo_nonnest_interrupt(void) {}
|
void foo_nonest_interrupt(void) {}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @foo_nonest_nonest_interrupt() #1
|
||||||
|
// CHECK: ret void
|
||||||
|
__attribute__((interrupt("qci-nonest", "qci-nonest")))
|
||||||
|
void foo_nonest_nonest_interrupt(void) {}
|
||||||
|
|
||||||
// CHECK: attributes #0
|
// CHECK: attributes #0
|
||||||
// CHECK: "interrupt"="qci-nest"
|
// CHECK: "interrupt"="qci-nest"
|
||||||
@ -22,18 +32,23 @@ void foo_nonnest_interrupt(void) {}
|
|||||||
// CHECK: "interrupt"="qci-nonest"
|
// CHECK: "interrupt"="qci-nonest"
|
||||||
#else
|
#else
|
||||||
// Test for QCI extension's interrupt attribute support
|
// Test for QCI extension's interrupt attribute support
|
||||||
__attribute__((interrupt("qci-est"))) void foo_nest1(void) {} // both-warning {{'interrupt' attribute argument not supported: qci-est}}
|
__attribute__((interrupt(1))) void foo1(void) {} // both-error {{expected string literal as argument of 'interrupt' attribute}}
|
||||||
__attribute__((interrupt("qci-noest"))) void foo_nonest1(void) {} // both-warning {{'interrupt' attribute argument not supported: qci-noest}}
|
__attribute__((interrupt("qci-nonest", 1))) void foo_nonest2(void) {} // both-error {{expected string literal as argument of 'interrupt' attribute}}
|
||||||
__attribute__((interrupt(1))) void foo_nest2(void) {} // both-error {{expected string literal as argument of 'interrupt' attribute}}
|
__attribute__((interrupt("qci-nest", 1))) void foo_nest2(void) {} // both-error {{expected string literal as argument of 'interrupt' attribute}}
|
||||||
__attribute__((interrupt("qci-nest", "qci-nonest"))) void foo1(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
|
__attribute__((interrupt("qci-est"))) void foo_nest3(void) {} // both-warning {{'interrupt' attribute argument not supported: "qci-est"}}
|
||||||
__attribute__((interrupt("qci-nonest", "qci-nest"))) void foo2(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
|
__attribute__((interrupt("qci-noest"))) void foo_nonest3(void) {} // both-warning {{'interrupt' attribute argument not supported: "qci-noest"}}
|
||||||
__attribute__((interrupt("", "qci-nonest"))) void foo3(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
|
__attribute__((interrupt("", "qci-nonest"))) void foo_nonest4(void) {} // both-warning {{'interrupt' attribute argument not supported: ""}}
|
||||||
__attribute__((interrupt("", "qci-nest"))) void foo4(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
|
__attribute__((interrupt("", "qci-nest"))) void foo_nest4(void) {} // both-warning {{'interrupt' attribute argument not supported: ""}}
|
||||||
__attribute__((interrupt("qci-nonest", 1))) void foo5(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
|
|
||||||
__attribute__((interrupt("qci-nest", 1))) void foo6(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
|
__attribute__((interrupt("qci-nonest", "qci-nest"))) void foo_nonest5(void) {} // both-error {{RISC-V 'interrupt' attribute contains invalid combination of interrupt types}}
|
||||||
|
__attribute__((interrupt("qci-nest", "qci-nonest"))) void foo_nest5(void) {} // both-error {{RISC-V 'interrupt' attribute contains invalid combination of interrupt types}}
|
||||||
|
|
||||||
|
__attribute__((interrupt("qci-nest"))) void foo_nest(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nest' requires extension 'Xqciint'}}
|
||||||
|
__attribute__((interrupt("qci-nonest"))) void foo_nonest(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nonest' requires extension 'Xqciint'}}
|
||||||
|
|
||||||
|
__attribute__((interrupt("qci-nest", "qci-nest"))) void foo_nest_nest(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nest' requires extension 'Xqciint'}}
|
||||||
|
__attribute__((interrupt("qci-nonest", "qci-nonest"))) void foo_nonest_nonest(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nonest' requires extension 'Xqciint'}}
|
||||||
|
|
||||||
__attribute__((interrupt("qci-nest"))) void foo_nest(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nest' requires extension 'Xqciint'}}
|
|
||||||
__attribute__((interrupt("qci-nonest"))) void foo_nonest(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nonest' requires extension 'Xqciint'}}
|
|
||||||
|
|
||||||
// This tests the errors for the qci interrupts when using
|
// This tests the errors for the qci interrupts when using
|
||||||
// `__attribute__((target(...)))` - but they fail on RV64, because you cannot
|
// `__attribute__((target(...)))` - but they fail on RV64, because you cannot
|
||||||
@ -44,8 +59,8 @@ __attribute__((target("arch=+xqciint"))) __attribute__((interrupt("qci-nonest"))
|
|||||||
|
|
||||||
// The attribute order is important, the interrupt attribute must come after the
|
// The attribute order is important, the interrupt attribute must come after the
|
||||||
// target attribute
|
// target attribute
|
||||||
__attribute__((interrupt("qci-nest"))) __attribute__((target("arch=+xqciint"))) void foo_nest_xqciint2(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nest' requires extension 'Xqciint'}}
|
__attribute__((interrupt("qci-nest"))) __attribute__((target("arch=+xqciint"))) void foo_nest_xqciint2(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nest' requires extension 'Xqciint'}}
|
||||||
__attribute__((interrupt("qci-nonest"))) __attribute__((target("arch=+xqciint"))) void foo_nonest_xqciint2(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nonest' requires extension 'Xqciint'}}
|
__attribute__((interrupt("qci-nonest"))) __attribute__((target("arch=+xqciint"))) void foo_nonest_xqciint2(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nonest' requires extension 'Xqciint'}}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
106
clang/test/Sema/riscv-interrupt-attr-sifive.c
Normal file
106
clang/test/Sema/riscv-interrupt-attr-sifive.c
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// RUN: %clang_cc1 -triple riscv32-unknown-elf -target-feature +experimental-xsfmclic -emit-llvm -DCHECK_IR < %s| FileCheck %s
|
||||||
|
// RUN: %clang_cc1 -triple riscv64-unknown-elf -target-feature +experimental-xsfmclic -emit-llvm -DCHECK_IR < %s| FileCheck %s
|
||||||
|
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -target-feature +experimental-xsfmclic -verify=enabled,both -fsyntax-only
|
||||||
|
// RUN: %clang_cc1 %s -triple riscv64-unknown-elf -target-feature +experimental-xsfmclic -verify=enabled,both -fsyntax-only
|
||||||
|
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -verify=disabled,both -fsyntax-only
|
||||||
|
// RUN: %clang_cc1 %s -triple riscv64-unknown-elf -verify=disabled,both -fsyntax-only
|
||||||
|
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -target-feature -experimental-xsfmclic -verify=disabled,both -fsyntax-only
|
||||||
|
// RUN: %clang_cc1 %s -triple riscv64-unknown-elf -target-feature -experimental-xsfmclic -verify=disabled,both -fsyntax-only
|
||||||
|
|
||||||
|
#if defined(CHECK_IR)
|
||||||
|
// CHECK-LABEL: @foo_stack_swap() #0
|
||||||
|
// CHECK: ret void
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-stack-swap"))) void foo_stack_swap(void) {}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @foo_preemptible() #1
|
||||||
|
// CHECK: ret void
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-preemptible"))) void foo_preemptible(void) {}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @foo_stack_swap_preemptible() #2
|
||||||
|
// CHECK: ret void
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-stack-swap", "SiFive-CLIC-preemptible")))
|
||||||
|
void foo_stack_swap_preemptible(void) {}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @foo_preemptible_stack_swap() #2
|
||||||
|
// CHECK: ret void
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-preemptible", "SiFive-CLIC-stack-swap")))
|
||||||
|
void foo_preemptible_stack_swap(void) {}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @foo_stack_swap_repeat() #0
|
||||||
|
// CHECK: ret void
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-stack-swap", "SiFive-CLIC-stack-swap")))
|
||||||
|
void foo_stack_swap_repeat(void) {}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @foo_preemptible_repeat() #1
|
||||||
|
// CHECK: ret void
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-preemptible", "SiFive-CLIC-preemptible")))
|
||||||
|
void foo_preemptible_repeat(void) {}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @foo_machine_stack_swap() #0
|
||||||
|
// CHECK: ret void
|
||||||
|
__attribute__((interrupt("machine", "SiFive-CLIC-stack-swap")))
|
||||||
|
void foo_machine_stack_swap(void) {}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @foo_stack_swap_machine() #0
|
||||||
|
// CHECK: ret void
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-stack-swap", "machine")))
|
||||||
|
void foo_stack_swap_machine(void) {}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @foo_preemptible_machine() #1
|
||||||
|
// CHECK: ret void
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-preemptible", "machine")))
|
||||||
|
void foo_preemptible_machine(void) {}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @foo_machine_preemptible() #1
|
||||||
|
// CHECK: ret void
|
||||||
|
__attribute__((interrupt("machine", "SiFive-CLIC-preemptible")))
|
||||||
|
void foo_machine_preemptible(void) {}
|
||||||
|
|
||||||
|
|
||||||
|
// CHECK: attributes #0
|
||||||
|
// CHECK: "interrupt"="SiFive-CLIC-stack-swap"
|
||||||
|
// CHECK: attributes #1
|
||||||
|
// CHECK: "interrupt"="SiFive-CLIC-preemptible"
|
||||||
|
// CHECK: attributes #2
|
||||||
|
// CHECK: "interrupt"="SiFive-CLIC-preemptible-stack-swap"
|
||||||
|
#else
|
||||||
|
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-stack-swap"))) void foo15(void); // disabled-error {{RISC-V 'interrupt' attribute 'SiFive-CLIC-stack-swap' requires extension 'XSfmclic'}}
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-stack-swap", "SiFive-CLIC-stack-swap"))) void foo15(void); // disabled-error {{RISC-V 'interrupt' attribute 'SiFive-CLIC-stack-swap' requires extension 'XSfmclic'}}
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-stack-swap", "machine"))) void foo15(void); // disabled-error {{RISC-V 'interrupt' attribute 'SiFive-CLIC-stack-swap' requires extension 'XSfmclic'}}
|
||||||
|
__attribute__((interrupt("machine", "SiFive-CLIC-stack-swap"))) void foo15(void); // disabled-error {{RISC-V 'interrupt' attribute 'SiFive-CLIC-stack-swap' requires extension 'XSfmclic'}}
|
||||||
|
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-preemptible"))) void foo15(void); // disabled-error {{RISC-V 'interrupt' attribute 'SiFive-CLIC-preemptible' requires extension 'XSfmclic'}}
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-preemptible", "SiFive-CLIC-preemptible"))) void foo15(void); // disabled-error {{RISC-V 'interrupt' attribute 'SiFive-CLIC-preemptible' requires extension 'XSfmclic'}}
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-preemptible", "machine"))) void foo15(void); // disabled-error {{RISC-V 'interrupt' attribute 'SiFive-CLIC-preemptible' requires extension 'XSfmclic'}}
|
||||||
|
__attribute__((interrupt("machine", "SiFive-CLIC-preemptible"))) void foo15(void); // disabled-error {{RISC-V 'interrupt' attribute 'SiFive-CLIC-preemptible' requires extension 'XSfmclic'}}
|
||||||
|
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-preemptible", "SiFive-CLIC-stack-swap"))) void foo16(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'SiFive-CLIC-preemptible' requires extension 'XSfmclic'}}
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-stack-swap", "SiFive-CLIC-preemptible"))) void foo17(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'SiFive-CLIC-stack-swap' requires extension 'XSfmclic'}}
|
||||||
|
|
||||||
|
__attribute__((interrupt("machine", "machine", "SiFive-CLIC-preemptible"))) void foo24(void) {} // both-error {{'interrupt' attribute takes no more than 2 arguments}}
|
||||||
|
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-preemptible", "supervisor"))) void foo27(void) {} // both-error {{RISC-V 'interrupt' attribute contains invalid combination of interrupt types}}
|
||||||
|
|
||||||
|
__attribute__((interrupt("supervisor", "SiFive-CLIC-stack-swap"))) void foo28(void) {} // both-error {{RISC-V 'interrupt' attribute contains invalid combination of interrupt types}}
|
||||||
|
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-stack-swap", 1))) void foo29(void) {} // both-error {{expected string literal as argument of 'interrupt' attribute}}
|
||||||
|
|
||||||
|
__attribute__((interrupt(1, "SiFive-CLIC-stack-swap"))) void foo30(void) {} // both-error {{expected string literal as argument of 'interrupt' attribute}}
|
||||||
|
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-stack-swap", "foo"))) void foo31(void) {} // both-warning {{'interrupt' attribute argument not supported: "foo"}}
|
||||||
|
|
||||||
|
__attribute__((interrupt("foo", "SiFive-CLIC-stack-swap"))) void foo32(void) {} // both-warning {{'interrupt' attribute argument not supported: "foo"}}
|
||||||
|
|
||||||
|
|
||||||
|
__attribute__((target("arch=+xsfmclic"))) __attribute__((interrupt("SiFive-CLIC-preemptible"))) void foo_sfmclic_preemptible(void) {}
|
||||||
|
__attribute__((target("arch=+xsfmclic"))) __attribute__((interrupt("SiFive-CLIC-stack-swap"))) void foo_sfmclic_stack_swap(void) {}
|
||||||
|
__attribute__((target("arch=+xsfmclic"))) __attribute__((interrupt("SiFive-CLIC-preemptible", "SiFive-CLIC-stack-swap"))) void foo_sfmclic_both(void) {}
|
||||||
|
|
||||||
|
// The attribute order is important, the interrupt attribute must come after the
|
||||||
|
// target attribute
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-preemptible"))) __attribute__((target("arch=+xsfmclic"))) void foo_preemptible_sfmclic(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'SiFive-CLIC-preemptible' requires extension 'XSfmclic'}}
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-stack-swap"))) __attribute__((target("arch=+xsfmclic"))) void fooc_stack_swap_sfmclic(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'SiFive-CLIC-stack-swap' requires extension 'XSfmclic'}}
|
||||||
|
__attribute__((interrupt("SiFive-CLIC-preemptible", "SiFive-CLIC-stack-swap"))) __attribute__((target("arch=+xsfmclic"))) void foo_both_sfmclic(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'SiFive-CLIC-preemptible' requires extension 'XSfmclic'}}
|
||||||
|
|
||||||
|
#endif
|
@ -16,37 +16,48 @@ __attribute__((interrupt())) void foo_default(void) {}
|
|||||||
// CHECK-LABEL: @foo_default2() #1
|
// CHECK-LABEL: @foo_default2() #1
|
||||||
// CHECK: ret void
|
// CHECK: ret void
|
||||||
__attribute__((interrupt())) void foo_default2(void) {}
|
__attribute__((interrupt())) void foo_default2(void) {}
|
||||||
|
// CHECK-LABEL: @foo_machine_twice() #1
|
||||||
|
// CHECK: ret void
|
||||||
|
__attribute__((interrupt("machine", "machine")))
|
||||||
|
void foo_machine_twice(void) {}
|
||||||
|
// CHECK-LABEL: @foo_supervisor_twice() #0
|
||||||
|
// CHECK: ret void
|
||||||
|
__attribute__((interrupt("supervisor", "supervisor")))
|
||||||
|
void foo_supervisor_twice(void) {}
|
||||||
|
|
||||||
// CHECK: attributes #0
|
// CHECK: attributes #0
|
||||||
// CHECK: "interrupt"="supervisor"
|
// CHECK: "interrupt"="supervisor"
|
||||||
// CHECK: attributes #1
|
// CHECK: attributes #1
|
||||||
// CHECK: "interrupt"="machine"
|
// CHECK: "interrupt"="machine"
|
||||||
#else
|
#else
|
||||||
struct a { int b; };
|
|
||||||
|
|
||||||
struct a test __attribute__((interrupt)); // expected-warning {{'interrupt' attribute only applies to functions}}
|
|
||||||
|
|
||||||
__attribute__((interrupt(42))) void foo0(void) {} // expected-error {{expected string literal as argument of 'interrupt' attribute}}
|
|
||||||
__attribute__((interrupt("USER"))) void foo1(void) {} // expected-warning {{'interrupt' attribute argument not supported: USER}}
|
|
||||||
__attribute__((interrupt("user"))) void foo1b(void) {} // expected-warning {{'interrupt' attribute argument not supported: user}}
|
|
||||||
__attribute__((interrupt("MACHINE"))) void foo1c(void) {} // expected-warning {{'interrupt' attribute argument not supported: MACHINE}}
|
|
||||||
|
|
||||||
__attribute__((interrupt("machine", 1))) void foo2(void) {} // expected-error {{'interrupt' attribute takes no more than 1 argument}}
|
|
||||||
|
|
||||||
__attribute__((interrupt)) int foo3(void) {return 0;} // expected-warning {{RISC-V 'interrupt' attribute only applies to functions that have a 'void' return type}}
|
|
||||||
|
|
||||||
__attribute__((interrupt())) void foo4(void);
|
|
||||||
__attribute__((interrupt())) void foo4(void) {}
|
|
||||||
|
|
||||||
__attribute__((interrupt())) void foo5(int a) {} // expected-warning {{RISC-V 'interrupt' attribute only applies to functions that have no parameters}}
|
|
||||||
|
|
||||||
__attribute__((interrupt("machine"), interrupt("supervisor"))) void foo6(void) {} // expected-warning {{repeated RISC-V 'interrupt' attribute}} \
|
__attribute__((interrupt("machine"), interrupt("supervisor"))) void foo6(void) {} // expected-warning {{repeated RISC-V 'interrupt' attribute}} \
|
||||||
// expected-note {{repeated RISC-V 'interrupt' attribute is here}}
|
// expected-note {{repeated RISC-V 'interrupt' attribute is here}}
|
||||||
|
|
||||||
__attribute__((interrupt, interrupt)) void foo7(void) {} // expected-warning {{repeated RISC-V 'interrupt' attribute}} \
|
__attribute__((interrupt, interrupt)) void foo7(void) {} // expected-warning {{repeated RISC-V 'interrupt' attribute}} \
|
||||||
// expected-note {{repeated RISC-V 'interrupt' attribute is here}}
|
// expected-note {{repeated RISC-V 'interrupt' attribute is here}}
|
||||||
|
struct a { int b; };
|
||||||
|
|
||||||
|
struct a test __attribute__((interrupt)); // expected-warning {{'interrupt' attribute only applies to functions}}
|
||||||
|
|
||||||
|
__attribute__((interrupt)) int foo3(void) {return 0;} // expected-warning {{RISC-V 'interrupt' attribute only applies to functions that have a 'void' return type}}
|
||||||
|
__attribute__((interrupt())) void foo5(int a) {} // expected-warning {{RISC-V 'interrupt' attribute only applies to functions that have no parameters}}
|
||||||
|
|
||||||
|
__attribute__((interrupt("machine", "supervisor", "machine"))) void foo15(void) {} // expected-error {{'interrupt' attribute takes no more than 2 arguments}}
|
||||||
|
|
||||||
|
__attribute__((interrupt(42))) void foo0(void) {} // expected-error {{expected string literal as argument of 'interrupt' attribute}}
|
||||||
|
__attribute__((interrupt("machine", 1))) void foo2(void) {} // expected-error {{expected string literal as argument of 'interrupt' attribute}}
|
||||||
|
__attribute__((interrupt("USER"))) void foo1(void) {} // expected-warning {{'interrupt' attribute argument not supported: "USER"}}
|
||||||
|
__attribute__((interrupt("user"))) void foo1b(void) {} // expected-warning {{'interrupt' attribute argument not supported: "user"}}
|
||||||
|
__attribute__((interrupt("MACHINE"))) void foo1c(void) {} // expected-warning {{'interrupt' attribute argument not supported: "MACHINE"}}
|
||||||
|
|
||||||
__attribute__((interrupt(""))) void foo8(void) {} // expected-warning {{'interrupt' attribute argument not supported}}
|
__attribute__((interrupt(""))) void foo8(void) {} // expected-warning {{'interrupt' attribute argument not supported}}
|
||||||
|
|
||||||
|
__attribute__((interrupt("machine", "supervisor"))) void foo_machine_supervisor(void) {} // expected-error {{RISC-V 'interrupt' attribute contains invalid combination of interrupt types}}
|
||||||
|
__attribute__((interrupt("supervisor", "machine"))) void foo_supervisor_machine(void) {} // expected-error {{RISC-V 'interrupt' attribute contains invalid combination of interrupt types}}
|
||||||
|
|
||||||
|
__attribute__((interrupt())) void foo4(void);
|
||||||
|
__attribute__((interrupt())) void foo4(void) {}
|
||||||
|
|
||||||
__attribute__((interrupt("supervisor"))) void foo9(void);
|
__attribute__((interrupt("supervisor"))) void foo9(void);
|
||||||
__attribute__((interrupt("machine"))) void foo9(void);
|
__attribute__((interrupt("machine"))) void foo9(void);
|
||||||
|
|
||||||
@ -54,5 +65,10 @@ __attribute__((interrupt("supervisor"))) void foo11(void) {}
|
|||||||
__attribute__((interrupt("machine"))) void foo12(void) {}
|
__attribute__((interrupt("machine"))) void foo12(void) {}
|
||||||
__attribute__((interrupt())) void foo13(void) {}
|
__attribute__((interrupt())) void foo13(void) {}
|
||||||
__attribute__((interrupt)) void foo14(void) {}
|
__attribute__((interrupt)) void foo14(void) {}
|
||||||
|
|
||||||
|
__attribute__((interrupt("machine", "machine"))) void foo_machine_twice(void) {}
|
||||||
|
__attribute__((interrupt("supervisor", "supervisor"))) void foo_supervisor_supervisor(void) {}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -167,11 +167,14 @@ Changes to the RISC-V Backend
|
|||||||
* Adds assembler support for ``.option exact``, which disables automatic compression,
|
* Adds assembler support for ``.option exact``, which disables automatic compression,
|
||||||
and branch and linker relaxation. This can be disabled with ``.option noexact``,
|
and branch and linker relaxation. This can be disabled with ``.option noexact``,
|
||||||
which is also the default.
|
which is also the default.
|
||||||
<<<<<<< HEAD
|
|
||||||
* `-mcpu=xiangshan-kunminghu` was added.
|
* `-mcpu=xiangshan-kunminghu` was added.
|
||||||
* `-mcpu=andes-n45` and `-mcpu=andes-nx45` were added.
|
* `-mcpu=andes-n45` and `-mcpu=andes-nx45` were added.
|
||||||
* `-mcpu=andes-a45` and `-mcpu=andes-ax45` were added.
|
* `-mcpu=andes-a45` and `-mcpu=andes-ax45` were added.
|
||||||
* Adds support for the 'Ziccamoc` (Main Memory Supports Atomics in Zacas) extension, which was introduced as an optional extension of the RISC-V Profiles specification.
|
* Adds support for the 'Ziccamoc` (Main Memory Supports Atomics in Zacas) extension, which was introduced as an optional extension of the RISC-V Profiles specification.
|
||||||
|
* Adds experimental assembler support for SiFive CLIC CSRs, under the names
|
||||||
|
`Zsfmclic` for the M-mode registers and `Zsfsclic` for the S-mode registers.
|
||||||
|
* Adds Support for SiFive CLIC interrupt attributes, which automate writing CLIC
|
||||||
|
interrupt handlers without using inline assembly.
|
||||||
|
|
||||||
Changes to the WebAssembly Backend
|
Changes to the WebAssembly Backend
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
@ -1257,6 +1257,14 @@ def HasVendorXSfcease
|
|||||||
AssemblerPredicate<(all_of FeatureVendorXSfcease),
|
AssemblerPredicate<(all_of FeatureVendorXSfcease),
|
||||||
"'XSfcease' (SiFive sf.cease Instruction)">;
|
"'XSfcease' (SiFive sf.cease Instruction)">;
|
||||||
|
|
||||||
|
def FeatureVendorXSfmclic
|
||||||
|
: RISCVExperimentalExtension<0, 1,
|
||||||
|
"SiFive CLIC Machine-mode CSRs">;
|
||||||
|
|
||||||
|
def FeatureVendorXSfsclic
|
||||||
|
: RISCVExperimentalExtension<0, 1,
|
||||||
|
"SiFive CLIC Supervisor-mode CSRs">;
|
||||||
|
|
||||||
// Core-V Extensions
|
// Core-V Extensions
|
||||||
|
|
||||||
def FeatureVendorXCVelw
|
def FeatureVendorXCVelw
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "RISCVFrameLowering.h"
|
#include "RISCVFrameLowering.h"
|
||||||
|
#include "MCTargetDesc/RISCVBaseInfo.h"
|
||||||
#include "RISCVMachineFunctionInfo.h"
|
#include "RISCVMachineFunctionInfo.h"
|
||||||
#include "RISCVSubtarget.h"
|
#include "RISCVSubtarget.h"
|
||||||
#include "llvm/BinaryFormat/Dwarf.h"
|
#include "llvm/BinaryFormat/Dwarf.h"
|
||||||
@ -27,6 +28,8 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#define DEBUG_TYPE "riscv-frame"
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
static Align getABIStackAlignment(RISCVABI::ABI ABI) {
|
static Align getABIStackAlignment(RISCVABI::ABI ABI) {
|
||||||
@ -200,6 +203,149 @@ static void emitSCSEpilogue(MachineFunction &MF, MachineBasicBlock &MBB,
|
|||||||
CFIInstBuilder(MBB, MI, MachineInstr::FrameDestroy).buildRestore(SCSPReg);
|
CFIInstBuilder(MBB, MI, MachineInstr::FrameDestroy).buildRestore(SCSPReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Insert instruction to swap mscratchsw with sp
|
||||||
|
static void emitSiFiveCLICStackSwap(MachineFunction &MF, MachineBasicBlock &MBB,
|
||||||
|
MachineBasicBlock::iterator MBBI,
|
||||||
|
const DebugLoc &DL) {
|
||||||
|
auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
|
||||||
|
|
||||||
|
if (!RVFI->isSiFiveStackSwapInterrupt(MF))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto &STI = MF.getSubtarget<RISCVSubtarget>();
|
||||||
|
const RISCVInstrInfo *TII = STI.getInstrInfo();
|
||||||
|
|
||||||
|
assert(STI.hasVendorXSfmclic() && "Stack Swapping Requires XSfmclic");
|
||||||
|
|
||||||
|
BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRW))
|
||||||
|
.addReg(SPReg, RegState::Define)
|
||||||
|
.addImm(RISCVSysReg::sf_mscratchcsw)
|
||||||
|
.addReg(SPReg, RegState::Kill)
|
||||||
|
.setMIFlag(MachineInstr::FrameSetup);
|
||||||
|
|
||||||
|
// FIXME: CFI Information for this swap.
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
createSiFivePreemptibleInterruptFrameEntries(MachineFunction &MF,
|
||||||
|
RISCVMachineFunctionInfo &RVFI) {
|
||||||
|
if (!RVFI.isSiFivePreemptibleInterrupt(MF))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const TargetRegisterClass &RC = RISCV::GPRRegClass;
|
||||||
|
const TargetRegisterInfo &TRI =
|
||||||
|
*MF.getSubtarget<RISCVSubtarget>().getRegisterInfo();
|
||||||
|
MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||||
|
|
||||||
|
// Create two frame objects for spilling X8 and X9, which will be done in
|
||||||
|
// `emitSiFiveCLICPreemptibleSaves`. This is in addition to any other stack
|
||||||
|
// objects we might have for X8 and X9, as they might be saved twice.
|
||||||
|
for (int I = 0; I < 2; ++I) {
|
||||||
|
int FI = MFI.CreateStackObject(TRI.getSpillSize(RC), TRI.getSpillAlign(RC),
|
||||||
|
true);
|
||||||
|
RVFI.pushInterruptCSRFrameIndex(FI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emitSiFiveCLICPreemptibleSaves(MachineFunction &MF,
|
||||||
|
MachineBasicBlock &MBB,
|
||||||
|
MachineBasicBlock::iterator MBBI,
|
||||||
|
const DebugLoc &DL) {
|
||||||
|
auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
|
||||||
|
|
||||||
|
if (!RVFI->isSiFivePreemptibleInterrupt(MF))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto &STI = MF.getSubtarget<RISCVSubtarget>();
|
||||||
|
const RISCVInstrInfo *TII = STI.getInstrInfo();
|
||||||
|
|
||||||
|
// FIXME: CFI Information here is nonexistent/wrong.
|
||||||
|
|
||||||
|
// X8 and X9 might be stored into the stack twice, initially into the
|
||||||
|
// `interruptCSRFrameIndex` here, and then maybe again into their CSI frame
|
||||||
|
// index.
|
||||||
|
//
|
||||||
|
// This is done instead of telling the register allocator that we need two
|
||||||
|
// VRegs to store the value of `mcause` and `mepc` through the instruction,
|
||||||
|
// which affects other passes.
|
||||||
|
TII->storeRegToStackSlot(MBB, MBBI, RISCV::X8, /* IsKill=*/true,
|
||||||
|
RVFI->getInterruptCSRFrameIndex(0),
|
||||||
|
&RISCV::GPRRegClass, STI.getRegisterInfo(),
|
||||||
|
Register(), MachineInstr::FrameSetup);
|
||||||
|
TII->storeRegToStackSlot(MBB, MBBI, RISCV::X9, /* IsKill=*/true,
|
||||||
|
RVFI->getInterruptCSRFrameIndex(1),
|
||||||
|
&RISCV::GPRRegClass, STI.getRegisterInfo(),
|
||||||
|
Register(), MachineInstr::FrameSetup);
|
||||||
|
|
||||||
|
// Put `mcause` into X8 (s0), and `mepc` into X9 (s1). If either of these are
|
||||||
|
// used in the function, then they will appear in `getUnmanagedCSI` and will
|
||||||
|
// be saved again.
|
||||||
|
BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRS))
|
||||||
|
.addReg(RISCV::X8, RegState::Define)
|
||||||
|
.addImm(RISCVSysReg::mcause)
|
||||||
|
.addReg(RISCV::X0)
|
||||||
|
.setMIFlag(MachineInstr::FrameSetup);
|
||||||
|
BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRS))
|
||||||
|
.addReg(RISCV::X9, RegState::Define)
|
||||||
|
.addImm(RISCVSysReg::mepc)
|
||||||
|
.addReg(RISCV::X0)
|
||||||
|
.setMIFlag(MachineInstr::FrameSetup);
|
||||||
|
|
||||||
|
// Enable interrupts.
|
||||||
|
BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRSI))
|
||||||
|
.addReg(RISCV::X0)
|
||||||
|
.addImm(RISCVSysReg::mstatus)
|
||||||
|
.addImm(8)
|
||||||
|
.setMIFlag(MachineInstr::FrameSetup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emitSiFiveCLICPreemptibleRestores(MachineFunction &MF,
|
||||||
|
MachineBasicBlock &MBB,
|
||||||
|
MachineBasicBlock::iterator MBBI,
|
||||||
|
const DebugLoc &DL) {
|
||||||
|
auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
|
||||||
|
|
||||||
|
if (!RVFI->isSiFivePreemptibleInterrupt(MF))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto &STI = MF.getSubtarget<RISCVSubtarget>();
|
||||||
|
const RISCVInstrInfo *TII = STI.getInstrInfo();
|
||||||
|
|
||||||
|
// FIXME: CFI Information here is nonexistent/wrong.
|
||||||
|
|
||||||
|
// Disable interrupts.
|
||||||
|
BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRCI))
|
||||||
|
.addReg(RISCV::X0)
|
||||||
|
.addImm(RISCVSysReg::mstatus)
|
||||||
|
.addImm(8)
|
||||||
|
.setMIFlag(MachineInstr::FrameSetup);
|
||||||
|
|
||||||
|
// Restore `mepc` from x9 (s1), and `mcause` from x8 (s0). If either were used
|
||||||
|
// in the function, they have already been restored once, so now have the
|
||||||
|
// value stored in `emitSiFiveCLICPreemptibleSaves`.
|
||||||
|
BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRW))
|
||||||
|
.addReg(RISCV::X0)
|
||||||
|
.addImm(RISCVSysReg::mepc)
|
||||||
|
.addReg(RISCV::X9, RegState::Kill)
|
||||||
|
.setMIFlag(MachineInstr::FrameSetup);
|
||||||
|
BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRW))
|
||||||
|
.addReg(RISCV::X0)
|
||||||
|
.addImm(RISCVSysReg::mcause)
|
||||||
|
.addReg(RISCV::X8, RegState::Kill)
|
||||||
|
.setMIFlag(MachineInstr::FrameSetup);
|
||||||
|
|
||||||
|
// X8 and X9 need to be restored to their values on function entry, which we
|
||||||
|
// saved onto the stack in `emitSiFiveCLICPreemptibleSaves`.
|
||||||
|
TII->loadRegFromStackSlot(MBB, MBBI, RISCV::X9,
|
||||||
|
RVFI->getInterruptCSRFrameIndex(1),
|
||||||
|
&RISCV::GPRRegClass, STI.getRegisterInfo(),
|
||||||
|
Register(), MachineInstr::FrameSetup);
|
||||||
|
TII->loadRegFromStackSlot(MBB, MBBI, RISCV::X8,
|
||||||
|
RVFI->getInterruptCSRFrameIndex(0),
|
||||||
|
&RISCV::GPRRegClass, STI.getRegisterInfo(),
|
||||||
|
Register(), MachineInstr::FrameSetup);
|
||||||
|
}
|
||||||
|
|
||||||
// Get the ID of the libcall used for spilling and restoring callee saved
|
// Get the ID of the libcall used for spilling and restoring callee saved
|
||||||
// registers. The ID is representative of the number of registers saved or
|
// registers. The ID is representative of the number of registers saved or
|
||||||
// restored by the libcall, except it is zero-indexed - ID 0 corresponds to a
|
// restored by the libcall, except it is zero-indexed - ID 0 corresponds to a
|
||||||
@ -762,6 +908,9 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
|
|||||||
if (MF.getFunction().getCallingConv() == CallingConv::GHC)
|
if (MF.getFunction().getCallingConv() == CallingConv::GHC)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// SiFive CLIC needs to swap `sp` into `sf.mscratchcsw`
|
||||||
|
emitSiFiveCLICStackSwap(MF, MBB, MBBI, DL);
|
||||||
|
|
||||||
// Emit prologue for shadow call stack.
|
// Emit prologue for shadow call stack.
|
||||||
emitSCSPrologue(MF, MBB, MBBI, DL);
|
emitSCSPrologue(MF, MBB, MBBI, DL);
|
||||||
|
|
||||||
@ -871,6 +1020,9 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
|
|||||||
allocateStack(MBB, MBBI, MF, StackSize, RealStackSize, /*EmitCFI=*/true,
|
allocateStack(MBB, MBBI, MF, StackSize, RealStackSize, /*EmitCFI=*/true,
|
||||||
NeedProbe, ProbeSize, DynAllocation);
|
NeedProbe, ProbeSize, DynAllocation);
|
||||||
|
|
||||||
|
// Save SiFive CLIC CSRs into Stack
|
||||||
|
emitSiFiveCLICPreemptibleSaves(MF, MBB, MBBI, DL);
|
||||||
|
|
||||||
// The frame pointer is callee-saved, and code has been generated for us to
|
// The frame pointer is callee-saved, and code has been generated for us to
|
||||||
// save it to the stack. We need to skip over the storing of callee-saved
|
// save it to the stack. We need to skip over the storing of callee-saved
|
||||||
// registers as the frame pointer must be modified after it has been saved
|
// registers as the frame pointer must be modified after it has been saved
|
||||||
@ -1159,12 +1311,17 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emitSiFiveCLICPreemptibleRestores(MF, MBB, MBBI, DL);
|
||||||
|
|
||||||
// Deallocate stack if StackSize isn't a zero yet
|
// Deallocate stack if StackSize isn't a zero yet
|
||||||
if (StackSize != 0)
|
if (StackSize != 0)
|
||||||
deallocateStack(MF, MBB, MBBI, DL, StackSize, RealStackSize - StackSize);
|
deallocateStack(MF, MBB, MBBI, DL, StackSize, RealStackSize - StackSize);
|
||||||
|
|
||||||
// Emit epilogue for shadow call stack.
|
// Emit epilogue for shadow call stack.
|
||||||
emitSCSEpilogue(MF, MBB, MBBI, DL);
|
emitSCSEpilogue(MF, MBB, MBBI, DL);
|
||||||
|
|
||||||
|
// SiFive CLIC needs to swap `sf.mscratchcsw` into `sp`
|
||||||
|
emitSiFiveCLICStackSwap(MF, MBB, MBBI, DL);
|
||||||
}
|
}
|
||||||
|
|
||||||
StackOffset
|
StackOffset
|
||||||
@ -1357,6 +1514,9 @@ void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF,
|
|||||||
auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
|
auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
|
||||||
if (RVFI->isPushable(MF) && SavedRegs.test(RISCV::X26))
|
if (RVFI->isPushable(MF) && SavedRegs.test(RISCV::X26))
|
||||||
SavedRegs.set(RISCV::X27);
|
SavedRegs.set(RISCV::X27);
|
||||||
|
|
||||||
|
// SiFive Preemptible Interrupt Handlers need additional frame entries
|
||||||
|
createSiFivePreemptibleInterruptFrameEntries(MF, *RVFI);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<int64_t, Align>
|
std::pair<int64_t, Align>
|
||||||
@ -1716,11 +1876,22 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
|
|||||||
MachineFunction &MF, const TargetRegisterInfo *TRI,
|
MachineFunction &MF, const TargetRegisterInfo *TRI,
|
||||||
std::vector<CalleeSavedInfo> &CSI, unsigned &MinCSFrameIndex,
|
std::vector<CalleeSavedInfo> &CSI, unsigned &MinCSFrameIndex,
|
||||||
unsigned &MaxCSFrameIndex) const {
|
unsigned &MaxCSFrameIndex) const {
|
||||||
|
auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
|
||||||
|
|
||||||
|
// Preemptible Interrupts have two additional Callee-save Frame Indexes,
|
||||||
|
// not tracked by `CSI`.
|
||||||
|
if (RVFI->isSiFivePreemptibleInterrupt(MF)) {
|
||||||
|
for (int I = 0; I < 2; ++I) {
|
||||||
|
int FI = RVFI->getInterruptCSRFrameIndex(I);
|
||||||
|
MinCSFrameIndex = std::min<unsigned>(MinCSFrameIndex, FI);
|
||||||
|
MaxCSFrameIndex = std::max<unsigned>(MaxCSFrameIndex, FI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Early exit if no callee saved registers are modified!
|
// Early exit if no callee saved registers are modified!
|
||||||
if (CSI.empty())
|
if (CSI.empty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
|
|
||||||
if (RVFI->useQCIInterrupt(MF)) {
|
if (RVFI->useQCIInterrupt(MF)) {
|
||||||
RVFI->setQCIInterruptStackSize(QCIInterruptPushAmount);
|
RVFI->setQCIInterruptStackSize(QCIInterruptPushAmount);
|
||||||
} else if (RVFI->isPushable(MF)) {
|
} else if (RVFI->isPushable(MF)) {
|
||||||
|
@ -21423,15 +21423,28 @@ SDValue RISCVTargetLowering::LowerFormalArguments(
|
|||||||
"supervisor",
|
"supervisor",
|
||||||
"qci-nest",
|
"qci-nest",
|
||||||
"qci-nonest",
|
"qci-nonest",
|
||||||
|
"SiFive-CLIC-preemptible",
|
||||||
|
"SiFive-CLIC-stack-swap",
|
||||||
|
"SiFive-CLIC-preemptible-stack-swap",
|
||||||
};
|
};
|
||||||
if (llvm::find(SupportedInterruptKinds, Kind) ==
|
if (llvm::find(SupportedInterruptKinds, Kind) ==
|
||||||
std::end(SupportedInterruptKinds))
|
std::end(SupportedInterruptKinds))
|
||||||
report_fatal_error(
|
report_fatal_error(
|
||||||
"Function interrupt attribute argument not supported!");
|
"Function interrupt attribute argument not supported!");
|
||||||
|
|
||||||
if ((Kind == "qci-nest" || Kind == "qci-nonest") &&
|
if (Kind.starts_with("qci-") && !Subtarget.hasVendorXqciint())
|
||||||
!Subtarget.hasVendorXqciint())
|
|
||||||
report_fatal_error("'qci-*' interrupt kinds require Xqciint extension");
|
report_fatal_error("'qci-*' interrupt kinds require Xqciint extension");
|
||||||
|
|
||||||
|
if (Kind.starts_with("SiFive-CLIC-") && !Subtarget.hasVendorXSfmclic())
|
||||||
|
report_fatal_error(
|
||||||
|
"'SiFive-CLIC-*' interrupt kinds require XSfmclic extension",
|
||||||
|
/*gen_crash_diag=*/false);
|
||||||
|
|
||||||
|
const TargetFrameLowering *TFI = Subtarget.getFrameLowering();
|
||||||
|
if (Kind.starts_with("SiFive-CLIC-preemptible") && TFI->hasFP(MF))
|
||||||
|
report_fatal_error("'SiFive-CLIC-preemptible' interrupt kinds cannot "
|
||||||
|
"have a frame pointer",
|
||||||
|
/*gen_crash_diag=*/false);
|
||||||
}
|
}
|
||||||
|
|
||||||
EVT PtrVT = getPointerTy(DAG.getDataLayout());
|
EVT PtrVT = getPointerTy(DAG.getDataLayout());
|
||||||
|
@ -67,12 +67,17 @@ RISCVMachineFunctionInfo::getInterruptStackKind(
|
|||||||
|
|
||||||
StringRef InterruptVal =
|
StringRef InterruptVal =
|
||||||
MF.getFunction().getFnAttribute("interrupt").getValueAsString();
|
MF.getFunction().getFnAttribute("interrupt").getValueAsString();
|
||||||
if (InterruptVal == "qci-nest")
|
|
||||||
return InterruptStackKind::QCINest;
|
|
||||||
if (InterruptVal == "qci-nonest")
|
|
||||||
return InterruptStackKind::QCINoNest;
|
|
||||||
|
|
||||||
return InterruptStackKind::None;
|
return StringSwitch<RISCVMachineFunctionInfo::InterruptStackKind>(
|
||||||
|
InterruptVal)
|
||||||
|
.Case("qci-nest", InterruptStackKind::QCINest)
|
||||||
|
.Case("qci-nonest", InterruptStackKind::QCINoNest)
|
||||||
|
.Case("SiFive-CLIC-preemptible",
|
||||||
|
InterruptStackKind::SiFiveCLICPreemptible)
|
||||||
|
.Case("SiFive-CLIC-stack-swap", InterruptStackKind::SiFiveCLICStackSwap)
|
||||||
|
.Case("SiFive-CLIC-preemptible-stack-swap",
|
||||||
|
InterruptStackKind::SiFiveCLICPreemptibleStackSwap)
|
||||||
|
.Default(InterruptStackKind::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
void yaml::RISCVMachineFunctionInfo::mappingImpl(yaml::IO &YamlIO) {
|
void yaml::RISCVMachineFunctionInfo::mappingImpl(yaml::IO &YamlIO) {
|
||||||
@ -87,6 +92,10 @@ RISCVMachineFunctionInfo::getPushPopKind(const MachineFunction &MF) const {
|
|||||||
if (VarArgsSaveSize != 0)
|
if (VarArgsSaveSize != 0)
|
||||||
return PushPopKind::None;
|
return PushPopKind::None;
|
||||||
|
|
||||||
|
// SiFive interrupts are not compatible with push/pop.
|
||||||
|
if (useSiFiveInterrupt(MF))
|
||||||
|
return PushPopKind::None;
|
||||||
|
|
||||||
// Zcmp is not compatible with the frame pointer convention.
|
// Zcmp is not compatible with the frame pointer convention.
|
||||||
if (MF.getSubtarget<RISCVSubtarget>().hasStdExtZcmp() &&
|
if (MF.getSubtarget<RISCVSubtarget>().hasStdExtZcmp() &&
|
||||||
!MF.getTarget().Options.DisableFramePointerElim(MF))
|
!MF.getTarget().Options.DisableFramePointerElim(MF))
|
||||||
|
@ -78,6 +78,9 @@ private:
|
|||||||
/// Size of any opaque stack adjustment due to QCI Interrupt instructions.
|
/// Size of any opaque stack adjustment due to QCI Interrupt instructions.
|
||||||
unsigned QCIInterruptStackSize = 0;
|
unsigned QCIInterruptStackSize = 0;
|
||||||
|
|
||||||
|
/// Store Frame Indexes for Interrupt-Related CSR Spills.
|
||||||
|
SmallVector<int, 2> InterruptCSRFrameIndexes;
|
||||||
|
|
||||||
int64_t StackProbeSize = 0;
|
int64_t StackProbeSize = 0;
|
||||||
|
|
||||||
/// Does it probe the stack for a dynamic allocation?
|
/// Does it probe the stack for a dynamic allocation?
|
||||||
@ -153,7 +156,14 @@ public:
|
|||||||
unsigned getRVPushStackSize() const { return RVPushStackSize; }
|
unsigned getRVPushStackSize() const { return RVPushStackSize; }
|
||||||
void setRVPushStackSize(unsigned Size) { RVPushStackSize = Size; }
|
void setRVPushStackSize(unsigned Size) { RVPushStackSize = Size; }
|
||||||
|
|
||||||
enum class InterruptStackKind { None = 0, QCINest, QCINoNest };
|
enum class InterruptStackKind {
|
||||||
|
None = 0,
|
||||||
|
QCINest,
|
||||||
|
QCINoNest,
|
||||||
|
SiFiveCLICPreemptible,
|
||||||
|
SiFiveCLICStackSwap,
|
||||||
|
SiFiveCLICPreemptibleStackSwap
|
||||||
|
};
|
||||||
|
|
||||||
InterruptStackKind getInterruptStackKind(const MachineFunction &MF) const;
|
InterruptStackKind getInterruptStackKind(const MachineFunction &MF) const;
|
||||||
|
|
||||||
@ -166,6 +176,32 @@ public:
|
|||||||
unsigned getQCIInterruptStackSize() const { return QCIInterruptStackSize; }
|
unsigned getQCIInterruptStackSize() const { return QCIInterruptStackSize; }
|
||||||
void setQCIInterruptStackSize(unsigned Size) { QCIInterruptStackSize = Size; }
|
void setQCIInterruptStackSize(unsigned Size) { QCIInterruptStackSize = Size; }
|
||||||
|
|
||||||
|
bool useSiFiveInterrupt(const MachineFunction &MF) const {
|
||||||
|
InterruptStackKind Kind = getInterruptStackKind(MF);
|
||||||
|
return Kind == InterruptStackKind::SiFiveCLICPreemptible ||
|
||||||
|
Kind == InterruptStackKind::SiFiveCLICStackSwap ||
|
||||||
|
Kind == InterruptStackKind::SiFiveCLICPreemptibleStackSwap;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSiFivePreemptibleInterrupt(const MachineFunction &MF) const {
|
||||||
|
InterruptStackKind Kind = getInterruptStackKind(MF);
|
||||||
|
return Kind == InterruptStackKind::SiFiveCLICPreemptible ||
|
||||||
|
Kind == InterruptStackKind::SiFiveCLICPreemptibleStackSwap;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSiFiveStackSwapInterrupt(const MachineFunction &MF) const {
|
||||||
|
InterruptStackKind Kind = getInterruptStackKind(MF);
|
||||||
|
return Kind == InterruptStackKind::SiFiveCLICStackSwap ||
|
||||||
|
Kind == InterruptStackKind::SiFiveCLICPreemptibleStackSwap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pushInterruptCSRFrameIndex(int FI) {
|
||||||
|
InterruptCSRFrameIndexes.push_back(FI);
|
||||||
|
}
|
||||||
|
int getInterruptCSRFrameIndex(size_t Idx) const {
|
||||||
|
return InterruptCSRFrameIndexes[Idx];
|
||||||
|
}
|
||||||
|
|
||||||
// Some Stack Management Variants automatically update FP in a frame-pointer
|
// Some Stack Management Variants automatically update FP in a frame-pointer
|
||||||
// convention compatible way - which means we don't need to manually update
|
// convention compatible way - which means we don't need to manually update
|
||||||
// the FP, but we still need to emit the correct CFI information for
|
// the FP, but we still need to emit the correct CFI information for
|
||||||
|
@ -496,6 +496,24 @@ def : SysReg<"minstretcfgh", 0x722>;
|
|||||||
// Vendor CSRs
|
// Vendor CSRs
|
||||||
//===-----------------------------------------------
|
//===-----------------------------------------------
|
||||||
|
|
||||||
|
// XSfmclic
|
||||||
|
let FeaturesRequired = [{ {RISCV::FeatureVendorXSfmclic} }] in {
|
||||||
|
def : SysReg<"sf.mtvt", 0x307>;
|
||||||
|
def : SysReg<"sf.mnxti", 0x345>;
|
||||||
|
def : SysReg<"sf.mintstatus", 0x346>;
|
||||||
|
def : SysReg<"sf.mscratchcsw", 0x348>;
|
||||||
|
def : SysReg<"sf.mscratchcswl", 0x349>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XSfsclic
|
||||||
|
let FeaturesRequired = [{ {RISCV::FeatureVendorXSfsclic} }] in {
|
||||||
|
def : SysReg<"sf.stvt", 0x107>;
|
||||||
|
def : SysReg<"sf.snxti", 0x145>;
|
||||||
|
def : SysReg<"sf.sintstatus", 0x146>;
|
||||||
|
def : SysReg<"sf.sscratchcsw", 0x148>;
|
||||||
|
def : SysReg<"sf.sscratchcswl", 0x149>;
|
||||||
|
}
|
||||||
|
|
||||||
// Xqciint
|
// Xqciint
|
||||||
let FeaturesRequired = [{ {RISCV::FeatureVendorXqciint} }], isRV32Only = 1 in {
|
let FeaturesRequired = [{ {RISCV::FeatureVendorXqciint} }], isRV32Only = 1 in {
|
||||||
def : SysReg<"qc.mmcr", 0x7C0>;
|
def : SysReg<"qc.mmcr", 0x7C0>;
|
||||||
|
@ -42,6 +42,8 @@
|
|||||||
; CHECK-NEXT: experimental-xqcisync - 'Xqcisync' (Qualcomm uC Sync Delay Extension).
|
; CHECK-NEXT: experimental-xqcisync - 'Xqcisync' (Qualcomm uC Sync Delay Extension).
|
||||||
; CHECK-NEXT: experimental-xrivosvisni - 'XRivosVisni' (Rivos Vector Integer Small New).
|
; CHECK-NEXT: experimental-xrivosvisni - 'XRivosVisni' (Rivos Vector Integer Small New).
|
||||||
; CHECK-NEXT: experimental-xrivosvizip - 'XRivosVizip' (Rivos Vector Register Zips).
|
; CHECK-NEXT: experimental-xrivosvizip - 'XRivosVizip' (Rivos Vector Register Zips).
|
||||||
|
; CHECK-NEXT: experimental-xsfmclic - 'XSfmclic' (SiFive CLIC Machine-mode CSRs).
|
||||||
|
; CHECK-NEXT: experimental-xsfsclic - 'XSfsclic' (SiFive CLIC Supervisor-mode CSRs).
|
||||||
; CHECK-NEXT: experimental-zalasr - 'Zalasr' (Load-Acquire and Store-Release Instructions).
|
; CHECK-NEXT: experimental-zalasr - 'Zalasr' (Load-Acquire and Store-Release Instructions).
|
||||||
; CHECK-NEXT: experimental-zicfilp - 'Zicfilp' (Landing pad).
|
; CHECK-NEXT: experimental-zicfilp - 'Zicfilp' (Landing pad).
|
||||||
; CHECK-NEXT: experimental-zicfiss - 'Zicfiss' (Shadow stack).
|
; CHECK-NEXT: experimental-zicfiss - 'Zicfiss' (Shadow stack).
|
||||||
|
12
llvm/test/CodeGen/RISCV/sifive-interrupt-attr-err.ll
Normal file
12
llvm/test/CodeGen/RISCV/sifive-interrupt-attr-err.ll
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
; RUN: not llc -mtriple riscv32-unknown-elf -mattr=+experimental-xsfmclic -o - %s 2>&1 \
|
||||||
|
; RUN: | FileCheck %s
|
||||||
|
; RUN: not llc -mtriple riscv64-unknown-elf -mattr=+experimental-xsfmclic -o - %s 2>&1 \
|
||||||
|
; RUN: | FileCheck %s
|
||||||
|
|
||||||
|
;; Test that these report fatal errors.
|
||||||
|
|
||||||
|
; CHECK: LLVM ERROR: 'SiFive-CLIC-preemptible' interrupt kinds cannot have a frame pointer
|
||||||
|
|
||||||
|
define void @preemptible() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="all" {
|
||||||
|
ret void
|
||||||
|
}
|
1050
llvm/test/CodeGen/RISCV/sifive-interrupt-attr.ll
Normal file
1050
llvm/test/CodeGen/RISCV/sifive-interrupt-attr.ll
Normal file
File diff suppressed because it is too large
Load Diff
20
llvm/test/MC/RISCV/xsfmclic-invalid.s
Normal file
20
llvm/test/MC/RISCV/xsfmclic-invalid.s
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# RUN: not llvm-mc -triple riscv32 -mattr=-experimental-xsfmclic < %s 2>&1 \
|
||||||
|
# RUN: | FileCheck -check-prefixes=CHECK-FEATURE %s
|
||||||
|
|
||||||
|
# RUN: not llvm-mc -triple riscv64 -mattr=-experimental-xsfmclic < %s 2>&1 \
|
||||||
|
# RUN: | FileCheck -check-prefixes=CHECK-FEATURE %s
|
||||||
|
|
||||||
|
csrrs t1, sf.mtvt, zero
|
||||||
|
// CHECK-FEATURE: :[[@LINE-1]]:11: error: system register 'sf.mtvt' requires 'experimental-xsfmclic' to be enabled
|
||||||
|
|
||||||
|
csrrs t1, sf.mnxti, zero
|
||||||
|
// CHECK-FEATURE: :[[@LINE-1]]:11: error: system register 'sf.mnxti' requires 'experimental-xsfmclic' to be enabled
|
||||||
|
|
||||||
|
csrrs t1, sf.mintstatus, zero
|
||||||
|
// CHECK-FEATURE: :[[@LINE-1]]:11: error: system register 'sf.mintstatus' requires 'experimental-xsfmclic' to be enabled
|
||||||
|
|
||||||
|
csrrs t1, sf.mscratchcsw, zero
|
||||||
|
// CHECK-FEATURE: :[[@LINE-1]]:11: error: system register 'sf.mscratchcsw' requires 'experimental-xsfmclic' to be enabled
|
||||||
|
|
||||||
|
csrrs t1, sf.mscratchcswl, zero
|
||||||
|
// CHECK-FEATURE: :[[@LINE-1]]:11: error: system register 'sf.mscratchcswl' requires 'experimental-xsfmclic' to be enabled
|
46
llvm/test/MC/RISCV/xsfmclic-valid.s
Normal file
46
llvm/test/MC/RISCV/xsfmclic-valid.s
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xsfmclic -riscv-no-aliases -show-encoding \
|
||||||
|
# RUN: | FileCheck -check-prefixes=CHECK-INST,CHECK-ENC %s
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xsfmclic < %s \
|
||||||
|
# RUN: | llvm-objdump -d --mattr=+experimental-xsfmclic -M no-aliases - \
|
||||||
|
# RUN: | FileCheck -check-prefix=CHECK-INST %s
|
||||||
|
#
|
||||||
|
# RUN: llvm-mc %s -triple=riscv64 -mattr=+experimental-xsfmclic -riscv-no-aliases -show-encoding \
|
||||||
|
# RUN: | FileCheck -check-prefixes=CHECK-INST,CHECK-ENC %s
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+experimental-xsfmclic < %s \
|
||||||
|
# RUN: | llvm-objdump -d --mattr=+experimental-xsfmclic -M no-aliases - \
|
||||||
|
# RUN: | FileCheck -check-prefix=CHECK-INST %s
|
||||||
|
|
||||||
|
# CHECK-INST: csrrs t1, sf.mtvt, zero
|
||||||
|
# CHECK-ENC: encoding: [0x73,0x23,0x70,0x30]
|
||||||
|
csrrs t1, sf.mtvt, zero
|
||||||
|
# CHECK-INST: csrrs t2, sf.mtvt, zero
|
||||||
|
# CHECK-ENC: encoding: [0xf3,0x23,0x70,0x30]
|
||||||
|
csrrs t2, 0x307, zero
|
||||||
|
|
||||||
|
# CHECK-INST: csrrs t1, sf.mnxti, zero
|
||||||
|
# CHECK-ENC: encoding: [0x73,0x23,0x50,0x34]
|
||||||
|
csrrs t1, sf.mnxti, zero
|
||||||
|
# CHECK-INST: csrrs t2, sf.mnxti, zero
|
||||||
|
# CHECK-ENC: encoding: [0xf3,0x23,0x50,0x34]
|
||||||
|
csrrs t2, 0x345, zero
|
||||||
|
|
||||||
|
# CHECK-INST: csrrs t1, sf.mintstatus, zero
|
||||||
|
# CHECK-ENC: encoding: [0x73,0x23,0x60,0x34]
|
||||||
|
csrrs t1, sf.mintstatus, zero
|
||||||
|
# CHECK-INST: csrrs t2, sf.mintstatus, zero
|
||||||
|
# CHECK-ENC: encoding: [0xf3,0x23,0x60,0x34]
|
||||||
|
csrrs t2, 0x346, zero
|
||||||
|
|
||||||
|
# CHECK-INST: csrrs t1, sf.mscratchcsw, zero
|
||||||
|
# CHECK-ENC: encoding: [0x73,0x23,0x80,0x34]
|
||||||
|
csrrs t1, sf.mscratchcsw, zero
|
||||||
|
# CHECK-INST: csrrs t2, sf.mscratchcsw, zero
|
||||||
|
# CHECK-ENC: encoding: [0xf3,0x23,0x80,0x34]
|
||||||
|
csrrs t2, 0x348, zero
|
||||||
|
|
||||||
|
# CHECK-INST: csrrs t1, sf.mscratchcswl, zero
|
||||||
|
# CHECK-ENC: encoding: [0x73,0x23,0x90,0x34]
|
||||||
|
csrrs t1, sf.mscratchcswl, zero
|
||||||
|
# CHECK-INST: csrrs t2, sf.mscratchcswl, zero
|
||||||
|
# CHECK-ENC: encoding: [0xf3,0x23,0x90,0x34]
|
||||||
|
csrrs t2, 0x349, zero
|
20
llvm/test/MC/RISCV/xsfsclic-invalid.s
Normal file
20
llvm/test/MC/RISCV/xsfsclic-invalid.s
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# RUN: not llvm-mc -triple riscv32 -mattr=-experimental-xsfsclic < %s 2>&1 \
|
||||||
|
# RUN: | FileCheck -check-prefixes=CHECK-FEATURE %s
|
||||||
|
|
||||||
|
# RUN: not llvm-mc -triple riscv64 -mattr=-experimental-xsfsclic < %s 2>&1 \
|
||||||
|
# RUN: | FileCheck -check-prefixes=CHECK-FEATURE %s
|
||||||
|
|
||||||
|
csrrs t1, sf.stvt, zero
|
||||||
|
// CHECK-FEATURE: :[[@LINE-1]]:11: error: system register 'sf.stvt' requires 'experimental-xsfsclic' to be enabled
|
||||||
|
|
||||||
|
csrrs t1, sf.snxti, zero
|
||||||
|
// CHECK-FEATURE: :[[@LINE-1]]:11: error: system register 'sf.snxti' requires 'experimental-xsfsclic' to be enabled
|
||||||
|
|
||||||
|
csrrs t1, sf.sintstatus, zero
|
||||||
|
// CHECK-FEATURE: :[[@LINE-1]]:11: error: system register 'sf.sintstatus' requires 'experimental-xsfsclic' to be enabled
|
||||||
|
|
||||||
|
csrrs t1, sf.sscratchcsw, zero
|
||||||
|
// CHECK-FEATURE: :[[@LINE-1]]:11: error: system register 'sf.sscratchcsw' requires 'experimental-xsfsclic' to be enabled
|
||||||
|
|
||||||
|
csrrs t1, sf.sscratchcswl, zero
|
||||||
|
// CHECK-FEATURE: :[[@LINE-1]]:11: error: system register 'sf.sscratchcswl' requires 'experimental-xsfsclic' to be enabled
|
46
llvm/test/MC/RISCV/xsfsclic-valid.s
Normal file
46
llvm/test/MC/RISCV/xsfsclic-valid.s
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xsfsclic -riscv-no-aliases -show-encoding \
|
||||||
|
# RUN: | FileCheck -check-prefixes=CHECK-INST,CHECK-ENC %s
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xsfsclic < %s \
|
||||||
|
# RUN: | llvm-objdump -d --mattr=+experimental-xsfsclic -M no-aliases - \
|
||||||
|
# RUN: | FileCheck -check-prefix=CHECK-INST %s
|
||||||
|
#
|
||||||
|
# RUN: llvm-mc %s -triple=riscv64 -mattr=+experimental-xsfsclic -riscv-no-aliases -show-encoding \
|
||||||
|
# RUN: | FileCheck -check-prefixes=CHECK-INST,CHECK-ENC %s
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+experimental-xsfsclic < %s \
|
||||||
|
# RUN: | llvm-objdump -d --mattr=+experimental-xsfsclic -M no-aliases - \
|
||||||
|
# RUN: | FileCheck -check-prefix=CHECK-INST %s
|
||||||
|
|
||||||
|
# CHECK-INST: csrrs t1, sf.stvt, zero
|
||||||
|
# CHECK-ENC: encoding: [0x73,0x23,0x70,0x10]
|
||||||
|
csrrs t1, sf.stvt, zero
|
||||||
|
# CHECK-INST: csrrs t2, sf.stvt, zero
|
||||||
|
# CHECK-ENC: encoding: [0xf3,0x23,0x70,0x10]
|
||||||
|
csrrs t2, 0x107, zero
|
||||||
|
|
||||||
|
# CHECK-INST: csrrs t1, sf.snxti, zero
|
||||||
|
# CHECK-ENC: encoding: [0x73,0x23,0x50,0x14]
|
||||||
|
csrrs t1, sf.snxti, zero
|
||||||
|
# CHECK-INST: csrrs t2, sf.snxti, zero
|
||||||
|
# CHECK-ENC: encoding: [0xf3,0x23,0x50,0x14]
|
||||||
|
csrrs t2, 0x145, zero
|
||||||
|
|
||||||
|
# CHECK-INST: csrrs t1, sf.sintstatus, zero
|
||||||
|
# CHECK-ENC: encoding: [0x73,0x23,0x60,0x14]
|
||||||
|
csrrs t1, sf.sintstatus, zero
|
||||||
|
# CHECK-INST: csrrs t2, sf.sintstatus, zero
|
||||||
|
# CHECK-ENC: encoding: [0xf3,0x23,0x60,0x14]
|
||||||
|
csrrs t2, 0x146, zero
|
||||||
|
|
||||||
|
# CHECK-INST: csrrs t1, sf.sscratchcsw, zero
|
||||||
|
# CHECK-ENC: encoding: [0x73,0x23,0x80,0x14]
|
||||||
|
csrrs t1, sf.sscratchcsw, zero
|
||||||
|
# CHECK-INST: csrrs t2, sf.sscratchcsw, zero
|
||||||
|
# CHECK-ENC: encoding: [0xf3,0x23,0x80,0x14]
|
||||||
|
csrrs t2, 0x148, zero
|
||||||
|
|
||||||
|
# CHECK-INST: csrrs t1, sf.sscratchcswl, zero
|
||||||
|
# CHECK-ENC: encoding: [0x73,0x23,0x90,0x14]
|
||||||
|
csrrs t1, sf.sscratchcswl, zero
|
||||||
|
# CHECK-INST: csrrs t2, sf.sscratchcswl, zero
|
||||||
|
# CHECK-ENC: encoding: [0xf3,0x23,0x90,0x14]
|
||||||
|
csrrs t2, 0x149, zero
|
@ -1182,6 +1182,8 @@ Experimental extensions
|
|||||||
xqcisync 0.2
|
xqcisync 0.2
|
||||||
xrivosvisni 0.1
|
xrivosvisni 0.1
|
||||||
xrivosvizip 0.1
|
xrivosvizip 0.1
|
||||||
|
xsfmclic 0.1
|
||||||
|
xsfsclic 0.1
|
||||||
|
|
||||||
Supported Profiles
|
Supported Profiles
|
||||||
rva20s64
|
rva20s64
|
||||||
|
Loading…
x
Reference in New Issue
Block a user