Skip to content

Commit 7d78885

Browse files
authored
Rollup merge of rust-lang#111891 - rustbox:feat/riscv-isr-cconv, r=jackh726
feat: `riscv-interrupt-{m,s}` calling conventions Similar to prior support added for the mips430, avr, and x86 targets this change implements the rough equivalent of clang's [`__attribute__((interrupt))`][clang-attr] for riscv targets, enabling e.g. ```rust static mut CNT: usize = 0; pub extern "riscv-interrupt-m" fn isr_m() { unsafe { CNT += 1; } } ``` to produce highly effective assembly like: ```asm pub extern "riscv-interrupt-m" fn isr_m() { 420003a0: 1141 addi sp,sp,-16 unsafe { CNT += 1; 420003a2: c62a sw a0,12(sp) 420003a4: c42e sw a1,8(sp) 420003a6: 3fc80537 lui a0,0x3fc80 420003aa: 63c52583 lw a1,1596(a0) # 3fc8063c <_ZN12esp_riscv_rt3CNT17hcec3e3a214887d53E.0> 420003ae: 0585 addi a1,a1,1 420003b0: 62b52e23 sw a1,1596(a0) } } 420003b4: 4532 lw a0,12(sp) 420003b6: 45a2 lw a1,8(sp) 420003b8: 0141 addi sp,sp,16 420003ba: 30200073 mret ``` (disassembly via `riscv64-unknown-elf-objdump -C -S --disassemble ./esp32c3-hal/target/riscv32imc-unknown-none-elf/release/examples/gpio_interrupt`) This outcome is superior to hand-coded interrupt routines which, lacking visibility into any non-assembly body of the interrupt handler, have to be very conservative and save the [entire CPU state to the stack frame][full-frame-save]. By instead asking LLVM to only save the registers that it uses, we defer the decision to the tool with the best context: it can more accurately account for the cost of spills if it knows that every additional register used is already at the cost of an implicit spill. At the LLVM level, this is apparently [implemented by] marking every register as "[callee-save]," matching the semantics of an interrupt handler nicely (it has to leave the CPU state just as it found it after its `{m|s}ret`). This approach is not suitable for every interrupt handler, as it makes no attempt to e.g. save the state in a user-accessible stack frame. For a full discussion of those challenges and tradeoffs, please refer to [the interrupt calling conventions RFC][rfc]. Inside rustc, this implementation differs from prior art because LLVM does not expose the "all-saved" function flavor as a calling convention directly, instead preferring to use an attribute that allows for differentiating between "machine-mode" and "superivsor-mode" interrupts. Finally, some effort has been made to guide those who may not yet be aware of the differences between machine-mode and supervisor-mode interrupts as to why no `riscv-interrupt` calling convention is exposed through rustc, and similarly for why `riscv-interrupt-u` makes no appearance (as it would complicate future LLVM upgrades). [clang-attr]: https://clang.llvm.org/docs/AttributeReference.html#interrupt-risc-v [full-frame-save]: https://github.com/esp-rs/esp-riscv-rt/blob/9281af2ecffe13e40992917316f36920c26acaf3/src/lib.rs#L440-L469 [implemented by]: https://github.com/llvm/llvm-project/blob/b7fb2a3fec7c187d58a6d338ab512d9173bca987/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp#L61-L67 [callee-save]: https://github.com/llvm/llvm-project/blob/973f1fe7a8591c7af148e573491ab68cc15b6ecf/llvm/lib/Target/RISCV/RISCVCallingConv.td#L30-L37 [rfc]: rust-lang/rfcs#3246
2 parents 4e7e2a5 + 26bd86d commit 7d78885

33 files changed

+513
-69
lines changed

compiler/rustc_ast_lowering/src/errors.rs

+17
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,26 @@ pub struct InvalidAbi {
3131
pub abi: Symbol,
3232
pub command: String,
3333
#[subdiagnostic]
34+
pub explain: Option<InvalidAbiReason>,
35+
#[subdiagnostic]
3436
pub suggestion: Option<InvalidAbiSuggestion>,
3537
}
3638

39+
pub struct InvalidAbiReason(pub &'static str);
40+
41+
impl rustc_errors::AddToDiagnostic for InvalidAbiReason {
42+
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
43+
where
44+
F: Fn(
45+
&mut rustc_errors::Diagnostic,
46+
rustc_errors::SubdiagnosticMessage,
47+
) -> rustc_errors::SubdiagnosticMessage,
48+
{
49+
#[allow(rustc::untranslatable_diagnostic)]
50+
diag.note(self.0);
51+
}
52+
}
53+
3754
#[derive(Subdiagnostic)]
3855
#[suggestion(
3956
ast_lowering_invalid_abi_suggestion,

compiler/rustc_ast_lowering/src/item.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::errors::{InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
1+
use super::errors::{InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
22
use super::ResolverAstLoweringExt;
33
use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
44
use super::{FnDeclKind, LoweringContext, ParamMode};
@@ -1271,8 +1271,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
12711271
}
12721272

12731273
pub(super) fn lower_abi(&mut self, abi: StrLit) -> abi::Abi {
1274-
abi::lookup(abi.symbol_unescaped.as_str()).unwrap_or_else(|| {
1275-
self.error_on_invalid_abi(abi);
1274+
abi::lookup(abi.symbol_unescaped.as_str()).unwrap_or_else(|err| {
1275+
self.error_on_invalid_abi(abi, err);
12761276
abi::Abi::Rust
12771277
})
12781278
}
@@ -1285,7 +1285,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
12851285
}
12861286
}
12871287

1288-
fn error_on_invalid_abi(&self, abi: StrLit) {
1288+
fn error_on_invalid_abi(&self, abi: StrLit, err: abi::AbiUnsupported) {
12891289
let abi_names = abi::enabled_names(self.tcx.features(), abi.span)
12901290
.iter()
12911291
.map(|s| Symbol::intern(s))
@@ -1294,6 +1294,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
12941294
self.tcx.sess.emit_err(InvalidAbi {
12951295
abi: abi.symbol_unescaped,
12961296
span: abi.span,
1297+
explain: match err {
1298+
abi::AbiUnsupported::Reason { explain } => Some(InvalidAbiReason(explain)),
1299+
_ => None,
1300+
},
12971301
suggestion: suggested_name.map(|suggested_name| InvalidAbiSuggestion {
12981302
span: abi.span,
12991303
suggestion: format!("\"{suggested_name}\""),

compiler/rustc_codegen_cranelift/src/abi/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: Call
4848
default_call_conv
4949
}
5050

51-
Conv::X86Intr => sess.fatal("x86-interrupt call conv not yet implemented"),
51+
Conv::X86Intr | Conv::RiscvInterrupt { .. } => {
52+
sess.fatal(format!("interrupt call conv {c:?} not yet implemented"))
53+
}
5254

5355
Conv::ArmAapcs => sess.fatal("aapcs call conv not yet implemented"),
5456
Conv::CCmseNonSecureCall => {

compiler/rustc_codegen_llvm/src/abi.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -383,13 +383,16 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
383383
}
384384

385385
fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
386-
let mut func_attrs = SmallVec::<[_; 2]>::new();
386+
let mut func_attrs = SmallVec::<[_; 3]>::new();
387387
if self.ret.layout.abi.is_uninhabited() {
388388
func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(cx.llcx));
389389
}
390390
if !self.can_unwind {
391391
func_attrs.push(llvm::AttributeKind::NoUnwind.create_attr(cx.llcx));
392392
}
393+
if let Conv::RiscvInterrupt { kind } = self.conv {
394+
func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", kind.as_str()));
395+
}
393396
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &{ func_attrs });
394397

395398
let mut i = 0;
@@ -565,7 +568,9 @@ impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
565568
impl From<Conv> for llvm::CallConv {
566569
fn from(conv: Conv) -> Self {
567570
match conv {
568-
Conv::C | Conv::Rust | Conv::CCmseNonSecureCall => llvm::CCallConv,
571+
Conv::C | Conv::Rust | Conv::CCmseNonSecureCall | Conv::RiscvInterrupt { .. } => {
572+
llvm::CCallConv
573+
}
569574
Conv::RustCold => llvm::ColdCallConv,
570575
Conv::AmdGpuKernel => llvm::AmdGpuKernel,
571576
Conv::AvrInterrupt => llvm::AvrInterrupt,

compiler/rustc_feature/src/active.rs

+2
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ declare_features! (
313313
(active, abi_msp430_interrupt, "1.16.0", Some(38487), None),
314314
/// Allows `extern "ptx-*" fn()`.
315315
(active, abi_ptx, "1.15.0", Some(38788), None),
316+
/// Allows `extern "riscv-interrupt-m" fn()` and `extern "riscv-interrupt-s" fn()`.
317+
(active, abi_riscv_interrupt, "CURRENT_RUSTC_VERSION", Some(111889), None),
316318
/// Allows `extern "x86-interrupt" fn()`.
317319
(active, abi_x86_interrupt, "1.17.0", Some(40180), None),
318320
/// Allows additional const parameter types, such as `&'static str` or user defined types

compiler/rustc_middle/src/ty/layout.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,8 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) ->
12391239
| EfiApi
12401240
| AvrInterrupt
12411241
| AvrNonBlockingInterrupt
1242+
| RiscvInterruptM
1243+
| RiscvInterruptS
12421244
| CCmseNonSecureCall
12431245
| Wasm
12441246
| PlatformIntrinsic

compiler/rustc_mir_transform/src/ffi_unwind_calls.rs

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ fn abi_can_unwind(abi: Abi) -> bool {
3030
| EfiApi
3131
| AvrInterrupt
3232
| AvrNonBlockingInterrupt
33+
| RiscvInterruptM
34+
| RiscvInterruptS
3335
| CCmseNonSecureCall
3436
| Wasm
3537
| RustIntrinsic

compiler/rustc_smir/src/rustc_smir/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,8 @@ impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> {
877877
abi::Abi::PlatformIntrinsic => Abi::PlatformIntrinsic,
878878
abi::Abi::Unadjusted => Abi::Unadjusted,
879879
abi::Abi::RustCold => Abi::RustCold,
880+
abi::Abi::RiscvInterruptM => Abi::RiscvInterruptM,
881+
abi::Abi::RiscvInterruptS => Abi::RiscvInterruptS,
880882
},
881883
}
882884
}

compiler/rustc_smir/src/stable_mir/ty.rs

+2
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ pub enum Abi {
178178
PlatformIntrinsic,
179179
Unadjusted,
180180
RustCold,
181+
RiscvInterruptM,
182+
RiscvInterruptS,
181183
}
182184

183185
#[derive(Clone, Debug)]

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ symbols! {
326326
abi_efiapi,
327327
abi_msp430_interrupt,
328328
abi_ptx,
329+
abi_riscv_interrupt,
329330
abi_sysv64,
330331
abi_thiscall,
331332
abi_unadjusted,

compiler/rustc_target/src/abi/call/mod.rs

+25
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,25 @@ pub enum Conv {
603603
AmdGpuKernel,
604604
AvrInterrupt,
605605
AvrNonBlockingInterrupt,
606+
607+
RiscvInterrupt {
608+
kind: RiscvInterruptKind,
609+
},
610+
}
611+
612+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
613+
pub enum RiscvInterruptKind {
614+
Machine,
615+
Supervisor,
616+
}
617+
618+
impl RiscvInterruptKind {
619+
pub fn as_str(&self) -> &'static str {
620+
match self {
621+
Self::Machine => "machine",
622+
Self::Supervisor => "supervisor",
623+
}
624+
}
606625
}
607626

608627
/// Metadata describing how the arguments to a native function
@@ -753,6 +772,12 @@ impl FromStr for Conv {
753772
"AmdGpuKernel" => Ok(Conv::AmdGpuKernel),
754773
"AvrInterrupt" => Ok(Conv::AvrInterrupt),
755774
"AvrNonBlockingInterrupt" => Ok(Conv::AvrNonBlockingInterrupt),
775+
"RiscvInterrupt(machine)" => {
776+
Ok(Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine })
777+
}
778+
"RiscvInterrupt(supervisor)" => {
779+
Ok(Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor })
780+
}
756781
_ => Err(format!("'{s}' is not a valid value for entry function call convention.")),
757782
}
758783
}

compiler/rustc_target/src/json.rs

+5
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ impl<A: ToJson> ToJson for Option<A> {
9292

9393
impl ToJson for crate::abi::call::Conv {
9494
fn to_json(&self) -> Json {
95+
let buf: String;
9596
let s = match self {
9697
Self::C => "C",
9798
Self::Rust => "Rust",
@@ -110,6 +111,10 @@ impl ToJson for crate::abi::call::Conv {
110111
Self::AmdGpuKernel => "AmdGpuKernel",
111112
Self::AvrInterrupt => "AvrInterrupt",
112113
Self::AvrNonBlockingInterrupt => "AvrNonBlockingInterrupt",
114+
Self::RiscvInterrupt { kind } => {
115+
buf = format!("RiscvInterrupt({})", kind.as_str());
116+
&buf
117+
}
113118
};
114119
Json::String(s.to_owned())
115120
}

compiler/rustc_target/src/spec/abi.rs

+28-2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ pub enum Abi {
3838
PlatformIntrinsic,
3939
Unadjusted,
4040
RustCold,
41+
RiscvInterruptM,
42+
RiscvInterruptS,
4143
}
4244

4345
impl Abi {
@@ -107,11 +109,29 @@ const AbiDatas: &[AbiData] = &[
107109
AbiData { abi: Abi::PlatformIntrinsic, name: "platform-intrinsic" },
108110
AbiData { abi: Abi::Unadjusted, name: "unadjusted" },
109111
AbiData { abi: Abi::RustCold, name: "rust-cold" },
112+
AbiData { abi: Abi::RiscvInterruptM, name: "riscv-interrupt-m" },
113+
AbiData { abi: Abi::RiscvInterruptS, name: "riscv-interrupt-s" },
110114
];
111115

116+
#[derive(Copy, Clone, Debug)]
117+
pub enum AbiUnsupported {
118+
Unrecognized,
119+
Reason { explain: &'static str },
120+
}
121+
112122
/// Returns the ABI with the given name (if any).
113-
pub fn lookup(name: &str) -> Option<Abi> {
114-
AbiDatas.iter().find(|abi_data| name == abi_data.name).map(|&x| x.abi)
123+
pub fn lookup(name: &str) -> Result<Abi, AbiUnsupported> {
124+
AbiDatas.iter().find(|abi_data| name == abi_data.name).map(|&x| x.abi).ok_or_else(|| match name {
125+
"riscv-interrupt" => AbiUnsupported::Reason {
126+
explain: "please use one of riscv-interrupt-m or riscv-interrupt-s for machine- or supervisor-level interrupts, respectively",
127+
},
128+
"riscv-interrupt-u" => AbiUnsupported::Reason {
129+
explain: "user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314",
130+
},
131+
132+
_ => AbiUnsupported::Unrecognized,
133+
134+
})
115135
}
116136

117137
pub fn all_names() -> Vec<&'static str> {
@@ -200,6 +220,10 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
200220
feature: sym::abi_avr_interrupt,
201221
explain: "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change",
202222
}),
223+
"riscv-interrupt-m" | "riscv-interrupt-s" => Err(AbiDisabled::Unstable {
224+
feature: sym::abi_riscv_interrupt,
225+
explain: "riscv-interrupt ABIs are experimental and subject to change",
226+
}),
203227
"C-cmse-nonsecure-call" => Err(AbiDisabled::Unstable {
204228
feature: sym::abi_c_cmse_nonsecure_call,
205229
explain: "C-cmse-nonsecure-call ABI is experimental and subject to change",
@@ -260,6 +284,8 @@ impl Abi {
260284
PlatformIntrinsic => 32,
261285
Unadjusted => 33,
262286
RustCold => 34,
287+
RiscvInterruptM => 35,
288+
RiscvInterruptS => 36,
263289
};
264290
debug_assert!(
265291
AbiDatas

compiler/rustc_target/src/spec/abi/tests.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@ use super::*;
44
#[test]
55
fn lookup_Rust() {
66
let abi = lookup("Rust");
7-
assert!(abi.is_some() && abi.unwrap().data().name == "Rust");
7+
assert!(abi.is_ok() && abi.unwrap().data().name == "Rust");
88
}
99

1010
#[test]
1111
fn lookup_cdecl() {
1212
let abi = lookup("cdecl");
13-
assert!(abi.is_some() && abi.unwrap().data().name == "cdecl");
13+
assert!(abi.is_ok() && abi.unwrap().data().name == "cdecl");
1414
}
1515

1616
#[test]
1717
fn lookup_baz() {
1818
let abi = lookup("baz");
19-
assert!(abi.is_none());
19+
assert!(matches!(abi, Err(AbiUnsupported::Unrecognized)))
2020
}
2121

2222
#[test]

compiler/rustc_target/src/spec/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2270,6 +2270,7 @@ impl Target {
22702270
PtxKernel => self.arch == "nvptx64",
22712271
Msp430Interrupt => self.arch == "msp430",
22722272
AmdGpuKernel => self.arch == "amdgcn",
2273+
RiscvInterruptM | RiscvInterruptS => ["riscv32", "riscv64"].contains(&&self.arch[..]),
22732274
AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr",
22742275
Wasm => ["wasm32", "wasm64"].contains(&&self.arch[..]),
22752276
Thiscall { .. } => self.arch == "x86",
@@ -2701,7 +2702,7 @@ impl Target {
27012702
let name = (stringify!($key_name)).replace("_", "-");
27022703
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
27032704
match lookup_abi(s) {
2704-
Some(abi) => base.$key_name = Some(abi),
2705+
Ok(abi) => base.$key_name = Some(abi),
27052706
_ => return Some(Err(format!("'{}' is not a valid value for abi", s))),
27062707
}
27072708
Some(Ok(()))

compiler/rustc_ty_utils/src/abi.rs

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_session::config::OptLevel;
99
use rustc_span::def_id::DefId;
1010
use rustc_target::abi::call::{
1111
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
12+
RiscvInterruptKind,
1213
};
1314
use rustc_target::abi::*;
1415
use rustc_target::spec::abi::Abi as SpecAbi;
@@ -193,6 +194,8 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
193194
AmdGpuKernel => Conv::AmdGpuKernel,
194195
AvrInterrupt => Conv::AvrInterrupt,
195196
AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
197+
RiscvInterruptM => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine },
198+
RiscvInterruptS => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor },
196199
Wasm => Conv::C,
197200

198201
// These API constants ought to be more specific...

src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[
3030
"efiapi",
3131
"avr-interrupt",
3232
"avr-non-blocking-interrupt",
33+
"riscv-interrupt-m",
34+
"riscv-interrupt-s",
3335
"C-cmse-nonsecure-call",
3436
"wasm",
3537
"system",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0703]: invalid ABI: found `riscv-interrupt`
2+
--> $DIR/riscv-discoverability-guidance.rs:17:8
3+
|
4+
LL | extern "riscv-interrupt" fn isr() {}
5+
| ^^^^^^^^^^^^^^^^^
6+
| |
7+
| invalid ABI
8+
| help: did you mean: `"riscv-interrupt-m"`
9+
|
10+
= note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions.
11+
= note: please use one of riscv-interrupt-m or riscv-interrupt-s for machine- or supervisor-level interrupts, respectively
12+
13+
error[E0703]: invalid ABI: found `riscv-interrupt-u`
14+
--> $DIR/riscv-discoverability-guidance.rs:23:8
15+
|
16+
LL | extern "riscv-interrupt-u" fn isr_U() {}
17+
| ^^^^^^^^^^^^^^^^^^^
18+
| |
19+
| invalid ABI
20+
| help: did you mean: `"riscv-interrupt-m"`
21+
|
22+
= note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions.
23+
= note: user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314
24+
25+
error: aborting due to 2 previous errors
26+
27+
For more information about this error, try `rustc --explain E0703`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0703]: invalid ABI: found `riscv-interrupt`
2+
--> $DIR/riscv-discoverability-guidance.rs:17:8
3+
|
4+
LL | extern "riscv-interrupt" fn isr() {}
5+
| ^^^^^^^^^^^^^^^^^
6+
| |
7+
| invalid ABI
8+
| help: did you mean: `"riscv-interrupt-m"`
9+
|
10+
= note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions.
11+
= note: please use one of riscv-interrupt-m or riscv-interrupt-s for machine- or supervisor-level interrupts, respectively
12+
13+
error[E0703]: invalid ABI: found `riscv-interrupt-u`
14+
--> $DIR/riscv-discoverability-guidance.rs:23:8
15+
|
16+
LL | extern "riscv-interrupt-u" fn isr_U() {}
17+
| ^^^^^^^^^^^^^^^^^^^
18+
| |
19+
| invalid ABI
20+
| help: did you mean: `"riscv-interrupt-m"`
21+
|
22+
= note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions.
23+
= note: user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314
24+
25+
error: aborting due to 2 previous errors
26+
27+
For more information about this error, try `rustc --explain E0703`.

0 commit comments

Comments
 (0)