Skip to content

[RISCV] Support resumable non-maskable interrupt handlers #148134

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,9 @@ RISC-V Support

- Add support for the `__builtin_riscv_pause()` intrinsic from the `Zihintpause` extension.

- Add support for `__attribute__((interrupt("rnmi")))` to be used with the `Smrnmi` extension.
With this the `Smrnmi` extension is fully supported.

CUDA/HIP Language Changes
^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -2361,6 +2361,7 @@ def RISCVInterrupt : InheritableAttr, TargetSpecificAttr<TargetRISCV> {
[
"supervisor",
"machine",
"rnmi",
"qci-nest",
"qci-nonest",
"SiFive-CLIC-preemptible",
Expand All @@ -2369,6 +2370,7 @@ def RISCVInterrupt : InheritableAttr, TargetSpecificAttr<TargetRISCV> {
[
"supervisor",
"machine",
"rnmi",
"qcinest",
"qcinonest",
"SiFiveCLICPreemptible",
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -2905,10 +2905,13 @@ the backend to generate appropriate function entry/exit code so that it can be
used directly as an interrupt service routine.

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

The ``rnmi`` value is used for resumable non-maskable interrupts. It requires the
standard Smrnmi extension.

The ``qci-nest`` and ``qci-nonest`` values require Qualcomm's Xqciint extension
and are used for Machine-mode Interrupts and Machine-mode Non-maskable
interrupts. These use the following instructions from Xqciint to save and
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,9 @@ class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
case RISCVInterruptAttr::supervisor:
Kind = "supervisor";
break;
case RISCVInterruptAttr::rnmi:
Kind = "rnmi";
break;
case RISCVInterruptAttr::qcinest:
Kind = "qci-nest";
break;
Expand Down
12 changes: 11 additions & 1 deletion clang/lib/Sema/SemaRISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1552,9 +1552,11 @@ void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
HasSiFiveCLICType = true;
break;
case RISCVInterruptAttr::supervisor:
case RISCVInterruptAttr::rnmi:
case RISCVInterruptAttr::qcinest:
case RISCVInterruptAttr::qcinonest:
// "supervisor" and "qci-(no)nest" cannot be combined with any other types
// "supervisor", "rnmi" and "qci-(no)nest" cannot be combined with any
// other types
HasUnaryType = true;
break;
}
Expand Down Expand Up @@ -1608,6 +1610,14 @@ void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
return;
}
} break;
case RISCVInterruptAttr::rnmi: {
if (!HasFeature("smrnmi")) {
Diag(AL.getLoc(),
diag::err_riscv_attribute_interrupt_requires_extension)
<< RISCVInterruptAttr::ConvertInterruptTypeToStr(Type) << "Smrnmi";
return;
}
} break;
default:
break;
}
Expand Down
28 changes: 28 additions & 0 deletions clang/test/Sema/riscv-interrupt-attr-rnmi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// RUN: %clang_cc1 -triple riscv32-unknown-elf -target-feature +smrnmi -emit-llvm -DCHECK_IR < %s | FileCheck %s
// RUN: %clang_cc1 %s -triple riscv32-unknown-elf -target-feature +smrnmi -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 -target-feature -srnmi -verify=disabled,both -fsyntax-only

#if defined(CHECK_IR)
// CHECK-LABEL: foo_rnmi_interrupt() #0
// CHECK: ret void
__attribute__((interrupt("rnmi")))
void foo_rnmi_interrupt(void) {}

// CHECK-LABEL: @foo_rnmi_rnmi_interrupt() #0
// CHECK: ret void
__attribute__((interrupt("rnmi", "rnmi")))
void foo_rnmi_rnmi_interrupt(void) {}

// CHECK: attributes #0
// CHECK: "interrupt"="rnmi"
#else

__attribute__((interrupt("rnmi"))) void test_rnmi(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'rnmi' requires extension 'Smrnmi'}}
__attribute__((interrupt("rnmi", "rnmi"))) void test_rnmi_rnmi(void) {} // disabled-error {{RISC-V 'interrupt' attribute 'rnmi' requires extension 'Smrnmi'}}

__attribute__((interrupt("rnmi", "supervisor"))) void foo_rnmi_supervisor(void) {} // both-error {{RISC-V 'interrupt' attribute contains invalid combination of interrupt types}}
__attribute__((interrupt("rnmi", "machine"))) void foo_rnmi_machine(void) {} // both-error {{RISC-V 'interrupt' attribute contains invalid combination of interrupt types}}

__attribute__((interrupt("RNMI"))) void test_RNMI(void) {} // both-warning {{'interrupt' attribute argument not supported: "RNMI"}}
#endif
2 changes: 1 addition & 1 deletion llvm/docs/RISCVUsage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ on support follow.
``Smepmp`` Supported
``Smmpm`` Supported
``Smnpm`` Supported
``Smrnmi`` Assembly Support
``Smrnmi`` Supported
``Smstateen`` Assembly Support
``Ssaia`` Supported
``Ssccfg`` Supported
Expand Down
11 changes: 10 additions & 1 deletion llvm/lib/Target/RISCV/RISCVISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22242,6 +22242,7 @@ SDValue RISCVTargetLowering::LowerFormalArguments(
constexpr StringLiteral SupportedInterruptKinds[] = {
"machine",
"supervisor",
"rnmi",
"qci-nest",
"qci-nonest",
"SiFive-CLIC-preemptible",
Expand All @@ -22259,6 +22260,10 @@ SDValue RISCVTargetLowering::LowerFormalArguments(
reportFatalUsageError(
"'SiFive-CLIC-*' interrupt kinds require XSfmclic extension");

if (Kind == "rnmi" && !Subtarget.hasStdExtSmrnmi())
reportFatalUsageError("Handling of resumable non-maskable interrupts "
"handling requires Smrnmi extension");

const TargetFrameLowering *TFI = Subtarget.getFrameLowering();
if (Kind.starts_with("SiFive-CLIC-preemptible") && TFI->hasFP(MF))
reportFatalUsageError("'SiFive-CLIC-preemptible' interrupt kinds cannot "
Expand Down Expand Up @@ -22891,7 +22896,11 @@ RISCVTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,

if (Kind == "supervisor")
RetOpc = RISCVISD::SRET_GLUE;
else if (Kind == "qci-nest" || Kind == "qci-nonest") {
else if (Kind == "rnmi") {
assert(STI.hasFeature(RISCV::FeatureStdExtSmrnmi) &&
"Need Smrnmi extension for rnmi");
RetOpc = RISCVISD::MNRET_GLUE;
} else if (Kind == "qci-nest" || Kind == "qci-nonest") {
assert(STI.hasFeature(RISCV::FeatureVendorXqciint) &&
"Need Xqciint for qci-(no)nest");
RetOpc = RISCVISD::QC_C_MILEAVERET_GLUE;
Expand Down
7 changes: 6 additions & 1 deletion llvm/lib/Target/RISCV/RISCVInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ def riscv_sret_glue : RVSDNode<"SRET_GLUE", SDTNone,
[SDNPHasChain, SDNPOptInGlue]>;
def riscv_mret_glue : RVSDNode<"MRET_GLUE", SDTNone,
[SDNPHasChain, SDNPOptInGlue]>;
def riscv_mnret_glue : RVSDNode<"MNRET_GLUE", SDTNone,
[SDNPHasChain, SDNPOptInGlue]>;
def riscv_mileaveret_glue : RVSDNode<"QC_C_MILEAVERET_GLUE", SDTNone,
[SDNPHasChain, SDNPOptInGlue]>;

Expand Down Expand Up @@ -921,7 +923,6 @@ def MRET : Priv<"mret", 0b0011000>, Sched<[]> {
let rs1 = 0;
let rs2 = 0b00010;
}
} // isBarrier = 1, isReturn = 1, isTerminator = 1

let Predicates = [HasStdExtSmrnmi] in {
def MNRET : Priv<"mnret", 0b0111000>, Sched<[]> {
Expand All @@ -930,6 +931,8 @@ def MNRET : Priv<"mnret", 0b0111000>, Sched<[]> {
let rs2 = 0b00010;
}
}// Predicates = [HasStdExtSmrnmi]
} // isBarrier = 1, isReturn = 1, isTerminator = 1


def WFI : Priv<"wfi", 0b0001000>, Sched<[]> {
let rd = 0;
Expand Down Expand Up @@ -1787,6 +1790,8 @@ def : Pat<(riscv_call texternalsym:$func), (PseudoCALL texternalsym:$func)>;

def : Pat<(riscv_sret_glue), (SRET)>;
def : Pat<(riscv_mret_glue), (MRET)>;
let Predicates = [HasStdExtSmrnmi] in
def : Pat<(riscv_mnret_glue), (MNRET)>;

let isCall = 1, Defs = [X1] in {
let Predicates = [NoStdExtZicfilp] in
Expand Down
9 changes: 9 additions & 0 deletions llvm/test/CodeGen/RISCV/rnmi-interrupt-attr-error.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
; RUN: not llc -mtriple riscv32-unknown-elf -mattr=-smrnmi -o - %s 2>&1 \
; RUN: | FileCheck %s
; RUN: not llc -mtriple riscv64-unknown-elf -mattr=-smrnmi -o - %s 2>&1 \
; RUN: | FileCheck %s

; CHECK: LLVM ERROR: Handling of resumable non-maskable interrupts handling requires Smrnmi extension
define void @test_rnmi() "interrupt"="rnmi" {
ret void
}
Loading
Loading