Skip to content

Commit 6e6fe43

Browse files
committed
modified mod.rs to handle avr doubles, introduced regex, dynamic modified mod.rs creation
1 parent 8321f00 commit 6e6fe43

File tree

4 files changed

+445
-1
lines changed

4 files changed

+445
-1
lines changed

library/core/src/ffi/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ type_alias! { "c_longlong.md", c_longlong = i64; }
6666
type_alias! { "c_ulonglong.md", c_ulonglong = u64; }
6767

6868
type_alias! { "c_float.md", c_float = f32; }
69-
type_alias! { "c_double.md", c_double = f64; }
69+
type_alias! { "c_double.md", c_double = c_double_definition::c_double; #[doc(cfg(all()))]}
7070

7171
/// Equivalent to C's `size_t` type, from `stddef.h` (or `cstddef` for C++).
7272
///
@@ -205,6 +205,16 @@ mod c_long_definition {
205205
}
206206
}
207207

208+
mod c_double_definition {
209+
cfg_if! {
210+
if #[cfg(all(target_arch = "avr"))] {
211+
pub type c_double = f32;
212+
} else {
213+
pub type c_double = f64;
214+
}
215+
}
216+
}
217+
208218
// N.B., for LLVM to recognize the void pointer type and by extension
209219
// functions like malloc(), we need to have it represented as i8* in
210220
// LLVM bitcode. The enum used here ensures this and prevents misuse

tests/auxiliary/minicore.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,127 @@ macro_rules! stringify {
108108
/* compiler built-in */
109109
};
110110
}
111+
112+
macro_rules! cfg_if {
113+
// match if/else chains with a final `else`
114+
(
115+
$(
116+
if #[cfg( $i_meta:meta )] { $( $i_tokens:tt )* }
117+
) else+
118+
else { $( $e_tokens:tt )* }
119+
) => {
120+
cfg_if! {
121+
@__items () ;
122+
$(
123+
(( $i_meta ) ( $( $i_tokens )* )) ,
124+
)+
125+
(() ( $( $e_tokens )* )) ,
126+
}
127+
};
128+
129+
// Internal and recursive macro to emit all the items
130+
//
131+
// Collects all the previous cfgs in a list at the beginning, so they can be
132+
// negated. After the semicolon is all the remaining items.
133+
(@__items ( $( $_:meta , )* ) ; ) => {};
134+
(
135+
@__items ( $( $no:meta , )* ) ;
136+
(( $( $yes:meta )? ) ( $( $tokens:tt )* )) ,
137+
$( $rest:tt , )*
138+
) => {
139+
// Emit all items within one block, applying an appropriate #[cfg]. The
140+
// #[cfg] will require all `$yes` matchers specified and must also negate
141+
// all previous matchers.
142+
#[cfg(all(
143+
$( $yes , )?
144+
not(any( $( $no ),* ))
145+
))]
146+
cfg_if! { @__identity $( $tokens )* }
147+
148+
// Recurse to emit all other items in `$rest`, and when we do so add all
149+
// our `$yes` matchers to the list of `$no` matchers as future emissions
150+
// will have to negate everything we just matched as well.
151+
cfg_if! {
152+
@__items ( $( $no , )* $( $yes , )? ) ;
153+
$( $rest , )*
154+
}
155+
};
156+
157+
// Internal macro to make __apply work out right for different match types,
158+
// because of how macros match/expand stuff.
159+
(@__identity $( $tokens:tt )* ) => {
160+
$( $tokens )*
161+
};
162+
}
163+
164+
#[macro_export]
165+
macro_rules! panic {
166+
($msg:literal) => {
167+
$crate::panic(&$msg)
168+
};
169+
}
170+
171+
#[rustc_intrinsic]
172+
#[rustc_intrinsic_const_stable_indirect]
173+
#[rustc_intrinsic_must_be_overridden]
174+
pub const fn size_of<T>() -> usize {
175+
loop {}
176+
}
177+
178+
#[rustc_intrinsic]
179+
#[rustc_intrinsic_must_be_overridden]
180+
pub const fn abort() -> ! {
181+
loop {}
182+
}
183+
184+
#[lang = "panic"]
185+
#[rustc_const_panic_str]
186+
const fn panic(_expr: &&'static str) -> ! {
187+
abort();
188+
}
189+
190+
#[lang = "eq"]
191+
pub trait PartialEq<Rhs: ?Sized = Self> {
192+
fn eq(&self, other: &Rhs) -> bool;
193+
fn ne(&self, other: &Rhs) -> bool {
194+
!self.eq(other)
195+
}
196+
}
197+
198+
impl PartialEq for usize {
199+
fn eq(&self, other: &usize) -> bool {
200+
(*self) == (*other)
201+
}
202+
}
203+
204+
impl PartialEq for bool {
205+
fn eq(&self, other: &bool) -> bool {
206+
(*self) == (*other)
207+
}
208+
}
209+
210+
#[lang = "bitxor"]
211+
pub trait BitXor<Rhs = Self> {
212+
type Output;
213+
fn bitxor(self, rhs: Rhs) -> Self::Output;
214+
}
215+
216+
impl BitXor for bool {
217+
type Output = bool;
218+
fn bitxor(self, rhs: bool) -> bool {
219+
(self || rhs) && !(self && rhs)
220+
}
221+
}
222+
223+
#[lang = "not"]
224+
pub trait Not {
225+
type Output;
226+
fn not(self) -> Self::Output;
227+
}
228+
229+
impl Not for bool {
230+
type Output = bool;
231+
fn not(self) -> Self {
232+
!self
233+
}
234+
}
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
use run_make_support::{clang, regex, rfs, rustc};
2+
3+
const SKIPPED_TARGETS: &[&str] = &[
4+
"riscv", //error: unknown target triple 'riscv32e-unknown-none-elf'
5+
"wasm", //error: unknown target triple 'wasm32v1-none'
6+
"xtensa", //error: unknown target triple 'xtensa-esp32-espidf'
7+
];
8+
9+
fn main() {
10+
let targets = get_target_list();
11+
12+
let minicore_path = run_make_support::source_root().join("tests/auxiliary/minicore.rs");
13+
14+
regex_mod();
15+
16+
for target in targets.lines() {
17+
if SKIPPED_TARGETS.iter().any(|prefix| target.starts_with(prefix)) {
18+
continue;
19+
}
20+
21+
let clang_output =
22+
clang().args(&["-E", "-dM", "-x", "c", "/dev/null", "-target", target]).run();
23+
24+
let defines = String::from_utf8(clang_output.stdout()).expect("Invalid UTF-8");
25+
26+
let minicore_content = rfs::read_to_string(&minicore_path);
27+
let mut rmake_content = format!(
28+
r#"
29+
#![no_std]
30+
#![no_core]
31+
#![feature(intrinsics)]
32+
#![feature(link_cfg)]
33+
#![allow(unused)]
34+
#![crate_type = "rlib"]
35+
{}
36+
#[path = "processed_mod.rs"]
37+
mod ffi;
38+
#[path = "tests.rs"]
39+
mod tests;
40+
"#,
41+
minicore_content
42+
);
43+
44+
rmake_content.push_str(&format!(
45+
"
46+
const CLANG_C_CHAR_SIZE: usize = {};
47+
const CLANG_C_CHAR_SIGNED: bool = {};
48+
const CLANG_C_SHORT_SIZE: usize = {};
49+
const CLANG_C_INT_SIZE: usize = {};
50+
const CLANG_C_LONG_SIZE: usize = {};
51+
const CLANG_C_LONGLONG_SIZE: usize = {};
52+
const CLANG_C_FLOAT_SIZE: usize = {};
53+
const CLANG_C_DOUBLE_SIZE: usize = {};
54+
",
55+
parse_size(&defines, "CHAR"),
56+
parse_signed(&defines, "CHAR"),
57+
parse_size(&defines, "SHORT"),
58+
parse_size(&defines, "INT"),
59+
parse_size(&defines, "LONG"),
60+
parse_size(&defines, "LONG_LONG"),
61+
parse_size(&defines, "FLOAT"),
62+
parse_size(&defines, "DOUBLE"),
63+
));
64+
65+
// Write to target-specific rmake file
66+
let mut file_name = format!("{}_rmake.rs", target.replace("-", "_"));
67+
68+
if target.starts_with("thumbv8m") {
69+
file_name = String::from("thumbv8m_rmake.rs");
70+
}
71+
72+
rfs::create_file(&file_name);
73+
rfs::write(&file_name, rmake_content);
74+
let rustc_output = rustc()
75+
.arg("-Zunstable-options")
76+
.arg("--emit=metadata")
77+
.arg("--target")
78+
.arg(target)
79+
.arg(&file_name)
80+
.run();
81+
rfs::remove_file(&file_name);
82+
if !rustc_output.status().success() {
83+
panic!("Failed for target {}", target);
84+
}
85+
}
86+
87+
// Cleanup
88+
rfs::remove_file("processed_mod.rs");
89+
}
90+
91+
fn get_target_list() -> String {
92+
let completed_process = rustc().arg("--print").arg("target-list").run();
93+
String::from_utf8(completed_process.stdout()).expect("error not a string")
94+
}
95+
96+
// Helper to parse size from clang defines
97+
fn parse_size(defines: &str, type_name: &str) -> usize {
98+
let search_pattern = format!("__SIZEOF_{}__ ", type_name.to_uppercase());
99+
for line in defines.lines() {
100+
if line.contains(&search_pattern) {
101+
if let Some(size_str) = line.split_whitespace().last() {
102+
return size_str.parse().unwrap_or(0);
103+
}
104+
}
105+
}
106+
107+
// Only allow CHAR to default to 1
108+
if type_name.to_uppercase() == "CHAR" {
109+
return 1;
110+
}
111+
112+
panic!("Could not find size definition for type: {}", type_name);
113+
}
114+
115+
// Helper to parse signedness from clang defines
116+
fn parse_signed(defines: &str, type_name: &str) -> bool {
117+
match type_name.to_uppercase().as_str() {
118+
"CHAR" => {
119+
// Check if char is explicitly unsigned
120+
!defines.lines().any(|line| line.contains("__CHAR_UNSIGNED__"))
121+
}
122+
_ => true,
123+
}
124+
}
125+
126+
// Parse core/ffi/mod.rs to retrieve only necessary macros and type defines
127+
fn regex_mod() {
128+
let mod_path = run_make_support::source_root().join("library/core/src/ffi/mod.rs");
129+
let mut content = rfs::read_to_string(&mod_path);
130+
131+
//remove stability features #![unstable]
132+
let mut re = regex::Regex::new(r"#!?\[(un)?stable[^]]*?\]").unwrap();
133+
content = re.replace_all(&content, "").to_string();
134+
135+
//remove doc features #[doc...]
136+
re = regex::Regex::new(r"#\[doc[^]]*?\]").unwrap();
137+
content = re.replace_all(&content, "").to_string();
138+
139+
//remove lang feature #[lang...]
140+
re = regex::Regex::new(r"#\[lang[^]]*?\]").unwrap();
141+
content = re.replace_all(&content, "").to_string();
142+
143+
//remove non inline modules
144+
re = regex::Regex::new(r".*mod.*;").unwrap();
145+
content = re.replace_all(&content, "").to_string();
146+
147+
//remove use
148+
re = regex::Regex::new(r".*use.*;").unwrap();
149+
content = re.replace_all(&content, "").to_string();
150+
151+
//remove fn fmt {...}
152+
re = regex::Regex::new(r"(?s)fn fmt.*?\{.*?\}").unwrap();
153+
content = re.replace_all(&content, "").to_string();
154+
155+
//rmv impl fmt {...}
156+
re = regex::Regex::new(r"(?s)impl fmt::Debug for.*?\{.*?\}").unwrap();
157+
content = re.replace_all(&content, "").to_string();
158+
159+
let file_name = format!("processed_mod.rs");
160+
161+
rfs::create_file(&file_name);
162+
rfs::write(&file_name, content);
163+
}

0 commit comments

Comments
 (0)