Skip to content

Commit 7b94396

Browse files
committed
Cleaner implementation of LLVM patch and changelog
1 parent fb14952 commit 7b94396

File tree

7 files changed

+85
-34
lines changed

7 files changed

+85
-34
lines changed

.github/workflows/riscv-rt.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ jobs:
1414
toolchain: [ stable, nightly, 1.61.0 ]
1515
target:
1616
- riscv32i-unknown-none-elf
17+
- riscv32im-unknown-none-elf
1718
- riscv32imc-unknown-none-elf
1819
- riscv32imac-unknown-none-elf
20+
- riscv32imafc-unknown-none-elf
1921
- riscv64imac-unknown-none-elf
2022
- riscv64gc-unknown-none-elf
2123
example:

riscv-rt/CHANGELOG.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Changed
1111

12+
- Limit rustc cfg flags to `riscvi`, `riscve`, `riscvm`, `riscvf`, and `riscvd`.
13+
- Temporary use of `RISCV_RT_LLVM_ARCH_PATCH` environment variable to include the
14+
temporary patch required for avoid LLVM spurious errors.
15+
- `riscv-rt` now use the `RISCV_RT_BASE_ISA` environment variable to configure the behavior
16+
of `riscv-rt-macros` depending on aspects of the base ISA (e.g., RV32I or RV32E).
17+
- Use `riscv-target-parser` in build script to identify target-specific configurations.
1218
- Add documentation to trap frame fields.
13-
- Avoid using `t3`+ in startup assembly to ensure compatibility with RVE32.
19+
- Avoid using `t3`+ in startup assembly to ensure compatibility with RVE.
1420
- `link.x.in`: remove references to `eh_frame`.
1521
- Rename start/end section symbols to align with `cortex-m-rt`:
1622
- `_stext`: it remains, as linker files can modify it.

riscv-rt/build.rs

+24-17
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
// NOTE: Adapted from cortex-m/build.rs
22

3-
use riscv_target_parser::{Extension, RiscvTarget, Width};
3+
use riscv_target_parser::RiscvTarget;
44
use std::{env, fs, io, path::PathBuf};
55

6+
// List of all possible RISC-V configurations to check for in risv-rt
7+
const RISCV_CFG: [&str; 5] = ["riscvi", "riscve", "riscvm", "riscvf", "riscvd"];
8+
69
fn add_linker_script(arch_width: u32) -> io::Result<()> {
710
// Read the file to a string and replace all occurrences of ${ARCH_WIDTH} with the arch width
811
let mut content = fs::read_to_string("link.x.in")?;
@@ -20,32 +23,36 @@ fn add_linker_script(arch_width: u32) -> io::Result<()> {
2023

2124
fn main() {
2225
// Required until target_feature risc-v is stable and in-use (rust 1.75)
23-
for ext in ['i', 'e', 'm', 'a', 'f', 'd', 'g', 'c'] {
24-
println!("cargo:rustc-check-cfg=cfg(riscv{})", ext);
26+
for ext in RISCV_CFG.iter() {
27+
println!("cargo:rustc-check-cfg=cfg({ext})");
2528
}
2629

2730
let target = env::var("TARGET").unwrap();
2831
let cargo_flags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap();
2932

3033
if let Ok(target) = RiscvTarget::build(&target, &cargo_flags) {
3134
let width = target.width();
32-
let base = target.base_extension().expect("No base extension found");
33-
34-
// set environmet variable RISCV_RT_BASE_ISA to the width of the target
35-
// this is used in riscv_rt_macros to determine the base ISA
36-
let env_var = match (width, base) {
37-
(Width::W32, Extension::I) => "rv32i",
38-
(Width::W32, Extension::E) => "rv32e",
39-
(Width::W64, Extension::I) => "rv64i",
40-
(Width::W64, Extension::E) => "rv64e",
41-
_ => panic!("Unsupported target"),
42-
};
43-
println!("cargo:rustc-env=RISCV_RT_BASE_ISA={env_var}");
35+
36+
// set environmet variable RISCV_RT_BASE_ISA to the base ISA of the target.
37+
println!(
38+
"cargo:rustc-env=RISCV_RT_BASE_ISA={}",
39+
target.llvm_base_isa()
40+
);
41+
// set environment variable RISCV_RT_LLVM_ARCH_PATCH to patch LLVM bug.
42+
// (this env variable is temporary and will be removed after LLVM being fixed)
43+
println!(
44+
"cargo:rustc-env=RISCV_RT_LLVM_ARCH_PATCH={}",
45+
target.llvm_arch_patch()
46+
);
47+
// make sure that these env variables are not changed without notice.
48+
println!("cargo:rerun-if-env-changed=RISCV_RT_BASE_ISA");
49+
println!("cargo:rerun-if-env-changed=RISCV_RT_LLVM_ARCH_PATCH");
4450

4551
for flag in target.rustc_flags() {
4652
// Required until target_feature risc-v is stable and in-use
47-
println!("cargo:rustc-check-cfg=cfg({flag})");
48-
println!("cargo:rustc-cfg={flag}");
53+
if RISCV_CFG.contains(&flag.as_str()) {
54+
println!("cargo:rustc-cfg={flag}");
55+
}
4956
}
5057
add_linker_script(width.into()).unwrap();
5158
}

riscv-rt/macros/src/lib.rs

+12
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,18 @@ fn load_trap(arch: RiscvArch) -> String {
452452
.join("\n ")
453453
}
454454

455+
/// Temporary patch macro to deal with LLVM bug
456+
#[proc_macro]
457+
pub fn llvm_arch_patch(_input: TokenStream) -> TokenStream {
458+
let q = if let Ok(arch) = std::env::var("RISCV_RT_LLVM_ARCH_PATCH") {
459+
let patch = format!(".attribute arch,\"{arch}\"");
460+
quote! { core::arch::global_asm!{#patch} }
461+
} else {
462+
quote!(compile_error!("RISCV_RT_LLVM_ARCH_PATCH is not set"))
463+
};
464+
q.into()
465+
}
466+
455467
/// Generates weak `_start_trap` function in assembly.
456468
///
457469
/// This implementation stores all registers in the trap frame and calls `_start_trap_rust`.

riscv-rt/src/asm.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,7 @@ macro_rules! cfg_global_asm {
2929
// - https://github.com/rust-embedded/riscv/issues/175
3030
// - https://github.com/rust-lang/rust/issues/80608
3131
// - https://github.com/llvm/llvm-project/issues/61991
32-
cfg_global_asm!(
33-
"// Provisional patch to avoid LLVM spurious errors when compiling in release mode.",
34-
#[cfg(all(target_arch = "riscv32", riscvm))]
35-
".attribute arch, \"rv32im\"",
36-
#[cfg(all(target_arch = "riscv64", riscvm, not(riscvg)))]
37-
".attribute arch, \"rv64im\"",
38-
#[cfg(all(target_arch = "riscv64", riscvg))]
39-
".attribute arch, \"rv64g\"",
40-
);
32+
riscv_rt_macros::llvm_arch_patch!();
4133

4234
// Entry point of all programs (_start). It initializes DWARF call frame information,
4335
// the stack pointer, the frame pointer (needed for closures to work in start_rust)

riscv-target-parser/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ authors = ["The RISC-V Team <risc-v@teams.rust-embedded.org>"]
77
categories = ["embedded", "no-std"]
88
description = "Parser for RISC-V target specifications"
99
documentation = "https://docs.rs/riscv-target-parser"
10-
keywords = ["riscv", "runtime", "startup"]
10+
keywords = ["riscv", "build"]
1111
license = "ISC"
1212
edition = "2021"

riscv-target-parser/src/lib.rs

+38-6
Original file line numberDiff line numberDiff line change
@@ -162,16 +162,48 @@ impl RiscvTarget {
162162
/// }
163163
///
164164
pub fn rustc_flags(&self) -> Vec<String> {
165-
let mut res = self
166-
.extensions
165+
self.extensions
167166
.extensions()
168167
.iter()
169168
.map(|e| format!("riscv{e}"))
170-
.collect::<Vec<_>>();
171-
if self.extensions.is_g() {
172-
res.push("riscvg".to_string());
169+
.collect::<Vec<_>>()
170+
}
171+
172+
/// Returns the LLVM base ISA for the given RISC-V target.
173+
pub fn llvm_base_isa(&self) -> String {
174+
match (self.width, self.extensions.base_extension()) {
175+
(Width::W32, Some(Extension::I)) => String::from("rv32i"),
176+
(Width::W32, Some(Extension::E)) => String::from("rv32e"),
177+
(Width::W64, Some(Extension::I)) => String::from("rv64i"),
178+
(Width::W64, Some(Extension::E)) => String::from("rv64e"),
179+
(_, None) => panic!("RISC-V target must have a base extension"),
180+
_ => panic!("LLVM does not support this base ISA"),
181+
}
182+
}
183+
184+
/// Returns the arch code to patch LLVM spurious errors.
185+
///
186+
/// # Note
187+
///
188+
/// This is a provisional patch and is limited to work for the riscv-rt crate only.
189+
///
190+
/// # Related issues
191+
///
192+
/// - https://github.com/rust-embedded/riscv/issues/175
193+
/// - https://github.com/rust-lang/rust/issues/80608
194+
/// - https://github.com/llvm/llvm-project/issues/61991
195+
pub fn llvm_arch_patch(&self) -> String {
196+
let mut patch = self.llvm_base_isa();
197+
if self.extensions.contains(&Extension::M) {
198+
patch.push('m');
199+
}
200+
if self.extensions.contains(&Extension::F) {
201+
patch.push('f');
202+
}
203+
if self.extensions.contains(&Extension::D) {
204+
patch.push('d');
173205
}
174-
res
206+
patch
175207
}
176208

177209
/// Returns the width of the RISC-V architecture.

0 commit comments

Comments
 (0)