Skip to content

Commit cfc5baf

Browse files
lenaryapazos
andauthored
[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>
1 parent 5137587 commit cfc5baf

25 files changed

+1805
-95
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,12 @@ RISC-V Support
634634
^^^^^^^^^^^^^^
635635

636636
- Add support for `-mtune=generic-ooo` (a generic out-of-order model).
637+
- Adds support for `__attribute__((interrupt("SiFive-CLIC-preemptible")))` and
638+
`__attribute__((interrupt("SiFive-CLIC-stack-swap")))`. The former
639+
automatically saves some interrupt CSRs before re-enabling interrupts in the
640+
function prolog, the latter swaps `sp` with the value in a CSR before it is
641+
used or modified. These two can also be combined, and can be combined with
642+
`interrupt("machine")`.
637643

638644
- Adds support for `__attribute__((interrupt("qci-nest")))` and
639645
`__attribute__((interrupt("qci-nonest")))`. These use instructions from

clang/include/clang/Basic/Attr.td

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2252,10 +2252,23 @@ def NoMicroMips : InheritableAttr, TargetSpecificAttr<TargetMips32> {
22522252
def RISCVInterrupt : InheritableAttr, TargetSpecificAttr<TargetRISCV> {
22532253
let Spellings = [GCC<"interrupt">];
22542254
let Subjects = SubjectList<[Function]>;
2255-
let Args = [EnumArgument<"Interrupt", "InterruptType", /*is_string=*/true,
2256-
["supervisor", "machine", "qci-nest", "qci-nonest"],
2257-
["supervisor", "machine", "qcinest", "qcinonest"],
2258-
1>];
2255+
let Args = [VariadicEnumArgument<"Interrupt", "InterruptType", /*is_string=*/true,
2256+
[
2257+
"supervisor",
2258+
"machine",
2259+
"qci-nest",
2260+
"qci-nonest",
2261+
"SiFive-CLIC-preemptible",
2262+
"SiFive-CLIC-stack-swap",
2263+
],
2264+
[
2265+
"supervisor",
2266+
"machine",
2267+
"qcinest",
2268+
"qcinonest",
2269+
"SiFiveCLICPreemptible",
2270+
"SiFiveCLICStackSwap",
2271+
]>];
22592272
let ParseKind = "Interrupt";
22602273
let Documentation = [RISCVInterruptDocs];
22612274
}

clang/include/clang/Basic/AttrDocs.td

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2900,8 +2900,9 @@ targets. This attribute may be attached to a function definition and instructs
29002900
the backend to generate appropriate function entry/exit code so that it can be
29012901
used directly as an interrupt service routine.
29022902

2903-
Permissible values for this parameter are ``supervisor``, ``machine``,
2904-
``qci-nest`` and ``qci-nonest``. If there is no parameter, then it defaults to
2903+
Permissible values for this parameter are ``machine``, ``supervisor``,
2904+
``qci-nest``, ``qci-nonest``, ``SiFive-CLIC-preemptible``, and
2905+
``SiFive-CLIC-stack-swap``. If there is no parameter, then it defaults to
29052906
``machine``.
29062907

29072908
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
29122913
begin the interrupt handler. Both of these will use ``qc.c.mileaveret`` to
29132914
restore the state and return to the previous context.
29142915

2916+
The ``SiFive-CLIC-preemptible`` and ``SiFive-CLIC-stack-swap`` values are used
2917+
for machine-mode interrupts. For ``SiFive-CLIC-preemptible`` interrupts, the
2918+
values of ``mcause`` and ``mepc`` are saved onto the stack, and interrupts are
2919+
re-enabled. For ``SiFive-CLIC-stack-swap`` interrupts, the stack pointer is
2920+
swapped with ``mscratch`` before its first use and after its last use.
2921+
2922+
The SiFive CLIC values may be combined with each other and with the ``machine``
2923+
attribute value. Any other combination of different values is not allowed.
2924+
29152925
Repeated interrupt attribute on the same declaration will cause a warning
29162926
to be emitted. In case of repeated declarations, the last one prevails.
29172927

@@ -2921,6 +2931,7 @@ https://riscv.org/specifications/privileged-isa/
29212931
The RISC-V Instruction Set Manual Volume II: Privileged Architecture
29222932
Version 1.10.
29232933
https://github.com/quic/riscv-unified-db/releases/tag/Xqci-0.7
2934+
https://sifive.cdn.prismic.io/sifive/d1984d2b-c9b9-4c91-8de0-d68a5e64fa0f_sifive-interrupt-cookbook-v1p2.pdf
29242935
}];
29252936
}
29262937

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12763,7 +12763,9 @@ def err_riscv_builtin_invalid_lmul : Error<
1276312763
def err_riscv_type_requires_extension : Error<
1276412764
"RISC-V type %0 requires the '%1' extension">;
1276512765
def err_riscv_attribute_interrupt_requires_extension : Error<
12766-
"RISC-V interrupt attribute '%0' requires extension '%1'">;
12766+
"RISC-V 'interrupt' attribute '%0' requires extension '%1'">;
12767+
def err_riscv_attribute_interrupt_invalid_combination : Error<
12768+
"RISC-V 'interrupt' attribute contains invalid combination of interrupt types">;
1276712769

1276812770
def err_std_source_location_impl_not_found : Error<
1276912771
"'std::source_location::__impl' was not found; it must be defined before '__builtin_source_location' is called">;

clang/lib/CodeGen/Targets/RISCV.cpp

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -829,16 +829,39 @@ class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
829829
if (!Attr)
830830
return;
831831

832-
const char *Kind;
833-
switch (Attr->getInterrupt()) {
834-
case RISCVInterruptAttr::supervisor: Kind = "supervisor"; break;
835-
case RISCVInterruptAttr::machine: Kind = "machine"; break;
836-
case RISCVInterruptAttr::qcinest:
837-
Kind = "qci-nest";
838-
break;
839-
case RISCVInterruptAttr::qcinonest:
840-
Kind = "qci-nonest";
841-
break;
832+
StringRef Kind = "machine";
833+
bool HasSiFiveCLICPreemptible = false;
834+
bool HasSiFiveCLICStackSwap = false;
835+
for (RISCVInterruptAttr::InterruptType type : Attr->interrupt()) {
836+
switch (type) {
837+
case RISCVInterruptAttr::machine:
838+
// Do not update `Kind` because `Kind` is already "machine", or the
839+
// kinds also contains SiFive types which need to be applied.
840+
break;
841+
case RISCVInterruptAttr::supervisor:
842+
Kind = "supervisor";
843+
break;
844+
case RISCVInterruptAttr::qcinest:
845+
Kind = "qci-nest";
846+
break;
847+
case RISCVInterruptAttr::qcinonest:
848+
Kind = "qci-nonest";
849+
break;
850+
// There are three different LLVM IR attribute values for SiFive CLIC
851+
// interrupt kinds, one for each kind and one extra for their combination.
852+
case RISCVInterruptAttr::SiFiveCLICPreemptible: {
853+
HasSiFiveCLICPreemptible = true;
854+
Kind = HasSiFiveCLICStackSwap ? "SiFive-CLIC-preemptible-stack-swap"
855+
: "SiFive-CLIC-preemptible";
856+
break;
857+
}
858+
case RISCVInterruptAttr::SiFiveCLICStackSwap: {
859+
HasSiFiveCLICStackSwap = true;
860+
Kind = HasSiFiveCLICPreemptible ? "SiFive-CLIC-preemptible-stack-swap"
861+
: "SiFive-CLIC-stack-swap";
862+
break;
863+
}
864+
}
842865
}
843866

844867
Fn->addFnAttr("interrupt", Kind);

clang/lib/Sema/SemaRISCV.cpp

Lines changed: 96 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "clang/Sema/SemaRISCV.h"
1414
#include "clang/AST/ASTContext.h"
1515
#include "clang/AST/Attr.h"
16+
#include "clang/AST/Attrs.inc"
1617
#include "clang/AST/Decl.h"
1718
#include "clang/Basic/Builtins.h"
1819
#include "clang/Basic/TargetBuiltins.h"
@@ -1453,25 +1454,14 @@ void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
14531454
return;
14541455
}
14551456

1456-
// Check the attribute argument. Argument is optional.
1457-
if (!AL.checkAtMostNumArgs(SemaRef, 1))
1458-
return;
1459-
1460-
StringRef Str;
1461-
SourceLocation ArgLoc;
1462-
1463-
// 'machine'is the default interrupt mode.
1464-
if (AL.getNumArgs() == 0)
1465-
Str = "machine";
1466-
else if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
1467-
return;
1468-
14691457
// Semantic checks for a function with the 'interrupt' attribute:
14701458
// - Must be a function.
14711459
// - Must have no parameters.
14721460
// - Must have the 'void' return type.
1473-
// - The attribute itself must either have no argument or one of the
1474-
// valid interrupt types, see [RISCVInterruptDocs].
1461+
// - The attribute itself must have at most 2 arguments
1462+
// - The attribute arguments must be string literals, and valid choices.
1463+
// - The attribute arguments must be a valid combination
1464+
// - The current target must support the right extensions for the combination.
14751465

14761466
if (D->getFunctionType() == nullptr) {
14771467
Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
@@ -1491,35 +1481,105 @@ void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
14911481
return;
14921482
}
14931483

1494-
RISCVInterruptAttr::InterruptType Kind;
1495-
if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
1496-
Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
1497-
<< AL << Str << ArgLoc;
1484+
if (!AL.checkAtMostNumArgs(SemaRef, 2))
14981485
return;
1499-
}
15001486

1501-
switch (Kind) {
1502-
default:
1503-
break;
1504-
case RISCVInterruptAttr::InterruptType::qcinest:
1505-
case RISCVInterruptAttr::InterruptType::qcinonest: {
1506-
const TargetInfo &TI = getASTContext().getTargetInfo();
1507-
llvm::StringMap<bool> FunctionFeatureMap;
1508-
getASTContext().getFunctionFeatureMap(FunctionFeatureMap,
1509-
dyn_cast<FunctionDecl>(D));
1487+
bool HasSiFiveCLICType = false;
1488+
bool HasUnaryType = false;
1489+
1490+
SmallSet<RISCVInterruptAttr::InterruptType, 2> Types;
1491+
for (unsigned ArgIndex = 0; ArgIndex < AL.getNumArgs(); ++ArgIndex) {
1492+
RISCVInterruptAttr::InterruptType Type;
1493+
StringRef TypeString;
1494+
SourceLocation Loc;
15101495

1511-
if (!TI.hasFeature("experimental-xqciint") &&
1512-
!FunctionFeatureMap.lookup("experimental-xqciint")) {
1513-
Diag(AL.getLoc(), diag::err_riscv_attribute_interrupt_requires_extension)
1514-
<< Str << "Xqciint";
1496+
if (!SemaRef.checkStringLiteralArgumentAttr(AL, ArgIndex, TypeString, &Loc))
1497+
return;
1498+
1499+
if (!RISCVInterruptAttr::ConvertStrToInterruptType(TypeString, Type)) {
1500+
std::string TypeLiteral = ("\"" + TypeString + "\"").str();
1501+
Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
1502+
<< AL << TypeLiteral << Loc;
15151503
return;
15161504
}
1517-
break;
1505+
1506+
switch (Type) {
1507+
case RISCVInterruptAttr::machine:
1508+
// "machine" could be combined with the SiFive CLIC types, or could be
1509+
// just "machine".
1510+
break;
1511+
case RISCVInterruptAttr::SiFiveCLICPreemptible:
1512+
case RISCVInterruptAttr::SiFiveCLICStackSwap:
1513+
// SiFive-CLIC types can be combined with each other and "machine"
1514+
HasSiFiveCLICType = true;
1515+
break;
1516+
case RISCVInterruptAttr::supervisor:
1517+
case RISCVInterruptAttr::qcinest:
1518+
case RISCVInterruptAttr::qcinonest:
1519+
// "supervisor" and "qci-(no)nest" cannot be combined with any other types
1520+
HasUnaryType = true;
1521+
break;
1522+
}
1523+
1524+
Types.insert(Type);
1525+
}
1526+
1527+
if (HasUnaryType && Types.size() > 1) {
1528+
Diag(AL.getLoc(), diag::err_riscv_attribute_interrupt_invalid_combination);
1529+
return;
15181530
}
1531+
1532+
if (HasUnaryType && HasSiFiveCLICType) {
1533+
Diag(AL.getLoc(), diag::err_riscv_attribute_interrupt_invalid_combination);
1534+
return;
1535+
}
1536+
1537+
// "machine" is the default, if nothing is specified.
1538+
if (AL.getNumArgs() == 0)
1539+
Types.insert(RISCVInterruptAttr::machine);
1540+
1541+
const TargetInfo &TI = getASTContext().getTargetInfo();
1542+
llvm::StringMap<bool> FunctionFeatureMap;
1543+
getASTContext().getFunctionFeatureMap(FunctionFeatureMap,
1544+
dyn_cast<FunctionDecl>(D));
1545+
1546+
auto HasFeature = [&](StringRef FeatureName) -> bool {
1547+
return TI.hasFeature(FeatureName) || FunctionFeatureMap.lookup(FeatureName);
15191548
};
15201549

1521-
D->addAttr(::new (getASTContext())
1522-
RISCVInterruptAttr(getASTContext(), AL, Kind));
1550+
for (RISCVInterruptAttr::InterruptType Type : Types) {
1551+
switch (Type) {
1552+
// The QCI interrupt types require Xqciint
1553+
case RISCVInterruptAttr::qcinest:
1554+
case RISCVInterruptAttr::qcinonest: {
1555+
if (!HasFeature("experimental-xqciint")) {
1556+
Diag(AL.getLoc(),
1557+
diag::err_riscv_attribute_interrupt_requires_extension)
1558+
<< RISCVInterruptAttr::ConvertInterruptTypeToStr(Type) << "Xqciint";
1559+
return;
1560+
}
1561+
} break;
1562+
// The SiFive CLIC interrupt types require Xsfmclic
1563+
case RISCVInterruptAttr::SiFiveCLICPreemptible:
1564+
case RISCVInterruptAttr::SiFiveCLICStackSwap: {
1565+
if (!HasFeature("experimental-xsfmclic")) {
1566+
Diag(AL.getLoc(),
1567+
diag::err_riscv_attribute_interrupt_requires_extension)
1568+
<< RISCVInterruptAttr::ConvertInterruptTypeToStr(Type)
1569+
<< "XSfmclic";
1570+
return;
1571+
}
1572+
} break;
1573+
default:
1574+
break;
1575+
}
1576+
}
1577+
1578+
SmallVector<RISCVInterruptAttr::InterruptType, 2> TypesVec(Types.begin(),
1579+
Types.end());
1580+
1581+
D->addAttr(::new (getASTContext()) RISCVInterruptAttr(
1582+
getASTContext(), AL, TypesVec.data(), TypesVec.size()));
15231583
}
15241584

15251585
bool SemaRISCV::isAliasValid(unsigned BuiltinID, StringRef AliasName) {

clang/test/Driver/print-supported-extensions-riscv.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@
219219
// CHECK-NEXT: xqcisync 0.2 'Xqcisync' (Qualcomm uC Sync Delay Extension)
220220
// CHECK-NEXT: xrivosvisni 0.1 'XRivosVisni' (Rivos Vector Integer Small New)
221221
// CHECK-NEXT: xrivosvizip 0.1 'XRivosVizip' (Rivos Vector Register Zips)
222+
// CHECK-NEXT: xsfmclic 0.1 'XSfmclic' (SiFive CLIC Machine-mode CSRs)
223+
// CHECK-NEXT: xsfsclic 0.1 'XSfsclic' (SiFive CLIC Supervisor-mode CSRs)
222224
// CHECK-EMPTY:
223225
// CHECK-NEXT: Supported Profiles
224226
// CHECK-NEXT: rva20s64
Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -triple riscv32-unknown-elf -target-feature +experimental-xqciint -emit-llvm -DCHECK_IR < %s| FileCheck %s
1+
// RUN: %clang_cc1 -triple riscv32-unknown-elf -target-feature +experimental-xqciint -emit-llvm -DCHECK_IR < %s | FileCheck %s
22
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -target-feature +experimental-xqciint -verify=enabled,both -fsyntax-only
33
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -verify=disabled,both -fsyntax-only
44
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -target-feature -experimental-xqciint -verify=disabled,both -fsyntax-only
@@ -11,29 +11,44 @@
1111
__attribute__((interrupt("qci-nest")))
1212
void foo_nest_interrupt(void) {}
1313

14-
// CHECK-LABEL: @foo_nonnest_interrupt() #1
14+
// CHECK-LABEL: @foo_nest_nest_interrupt() #0
15+
// CHECK: ret void
16+
__attribute__((interrupt("qci-nest", "qci-nest")))
17+
void foo_nest_nest_interrupt(void) {}
18+
19+
// CHECK-LABEL: @foo_nonest_interrupt() #1
1520
// CHECK: ret void
1621
__attribute__((interrupt("qci-nonest")))
17-
void foo_nonnest_interrupt(void) {}
22+
void foo_nonest_interrupt(void) {}
23+
24+
// CHECK-LABEL: @foo_nonest_nonest_interrupt() #1
25+
// CHECK: ret void
26+
__attribute__((interrupt("qci-nonest", "qci-nonest")))
27+
void foo_nonest_nonest_interrupt(void) {}
1828

1929
// CHECK: attributes #0
2030
// CHECK: "interrupt"="qci-nest"
2131
// CHECK: attributes #1
2232
// CHECK: "interrupt"="qci-nonest"
2333
#else
2434
// Test for QCI extension's interrupt attribute support
25-
__attribute__((interrupt("qci-est"))) void foo_nest1(void) {} // both-warning {{'interrupt' attribute argument not supported: qci-est}}
26-
__attribute__((interrupt("qci-noest"))) void foo_nonest1(void) {} // both-warning {{'interrupt' attribute argument not supported: qci-noest}}
27-
__attribute__((interrupt(1))) void foo_nest2(void) {} // both-error {{expected string literal as argument of 'interrupt' attribute}}
28-
__attribute__((interrupt("qci-nest", "qci-nonest"))) void foo1(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
29-
__attribute__((interrupt("qci-nonest", "qci-nest"))) void foo2(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
30-
__attribute__((interrupt("", "qci-nonest"))) void foo3(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
31-
__attribute__((interrupt("", "qci-nest"))) void foo4(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
32-
__attribute__((interrupt("qci-nonest", 1))) void foo5(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
33-
__attribute__((interrupt("qci-nest", 1))) void foo6(void) {} // both-error {{'interrupt' attribute takes no more than 1 argument}}
34-
35-
__attribute__((interrupt("qci-nest"))) void foo_nest(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nest' requires extension 'Xqciint'}}
36-
__attribute__((interrupt("qci-nonest"))) void foo_nonest(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nonest' requires extension 'Xqciint'}}
35+
__attribute__((interrupt(1))) void foo1(void) {} // both-error {{expected string literal as argument of 'interrupt' attribute}}
36+
__attribute__((interrupt("qci-nonest", 1))) void foo_nonest2(void) {} // both-error {{expected string literal as argument of 'interrupt' attribute}}
37+
__attribute__((interrupt("qci-nest", 1))) void foo_nest2(void) {} // both-error {{expected string literal as argument of 'interrupt' attribute}}
38+
__attribute__((interrupt("qci-est"))) void foo_nest3(void) {} // both-warning {{'interrupt' attribute argument not supported: "qci-est"}}
39+
__attribute__((interrupt("qci-noest"))) void foo_nonest3(void) {} // both-warning {{'interrupt' attribute argument not supported: "qci-noest"}}
40+
__attribute__((interrupt("", "qci-nonest"))) void foo_nonest4(void) {} // both-warning {{'interrupt' attribute argument not supported: ""}}
41+
__attribute__((interrupt("", "qci-nest"))) void foo_nest4(void) {} // both-warning {{'interrupt' attribute argument not supported: ""}}
42+
43+
__attribute__((interrupt("qci-nonest", "qci-nest"))) void foo_nonest5(void) {} // both-error {{RISC-V 'interrupt' attribute contains invalid combination of interrupt types}}
44+
__attribute__((interrupt("qci-nest", "qci-nonest"))) void foo_nest5(void) {} // both-error {{RISC-V 'interrupt' attribute contains invalid combination of interrupt types}}
45+
46+
__attribute__((interrupt("qci-nest"))) void foo_nest(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nest' requires extension 'Xqciint'}}
47+
__attribute__((interrupt("qci-nonest"))) void foo_nonest(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nonest' requires extension 'Xqciint'}}
48+
49+
__attribute__((interrupt("qci-nest", "qci-nest"))) void foo_nest_nest(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nest' requires extension 'Xqciint'}}
50+
__attribute__((interrupt("qci-nonest", "qci-nonest"))) void foo_nonest_nonest(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nonest' requires extension 'Xqciint'}}
51+
3752

3853
// This tests the errors for the qci interrupts when using
3954
// `__attribute__((target(...)))` - but they fail on RV64, because you cannot
@@ -44,8 +59,8 @@ __attribute__((target("arch=+xqciint"))) __attribute__((interrupt("qci-nonest"))
4459

4560
// The attribute order is important, the interrupt attribute must come after the
4661
// target attribute
47-
__attribute__((interrupt("qci-nest"))) __attribute__((target("arch=+xqciint"))) void foo_nest_xqciint2(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nest' requires extension 'Xqciint'}}
48-
__attribute__((interrupt("qci-nonest"))) __attribute__((target("arch=+xqciint"))) void foo_nonest_xqciint2(void) {} // disabled-error {{RISC-V interrupt attribute 'qci-nonest' requires extension 'Xqciint'}}
62+
__attribute__((interrupt("qci-nest"))) __attribute__((target("arch=+xqciint"))) void foo_nest_xqciint2(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nest' requires extension 'Xqciint'}}
63+
__attribute__((interrupt("qci-nonest"))) __attribute__((target("arch=+xqciint"))) void foo_nonest_xqciint2(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'qci-nonest' requires extension 'Xqciint'}}
4964
#endif
5065

5166
#endif

0 commit comments

Comments
 (0)