diff --git a/CITATION.cff b/CITATION.cff index 1538a84..4969f77 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,30 +1,24 @@ cff-version: 1.2.0 title: Rustlantis -message: A Rust Mid-level Intermediate Representation fuzzer +message: A fuzzer for the Rust compiler type: software authors: - - given-names: Andy + - given-names: Qian (Andy) family-names: Wang - affiliation: ETH Zürich orcid: 'https://orcid.org/0009-0006-0779-8651' + affiliation: ETH Zürich - given-names: Ralf family-names: Jung - affiliation: ETH Zürich orcid: 'https://orcid.org/0000-0001-7669-6348' + affiliation: ETH Zürich identifiers: - - type: url - value: >- - https://ethz.ch/content/dam/ethz/special-interest/infk/inst-pls/plf-dam/documents/StudentProjects/MasterTheses/2023-Andy-Thesis.pdf + - type: doi + value: 10.1145/3689780 repository-code: 'https://github.com/cbeuw/rustlantis' -abstract: >- - Rustlantis is a novel fuzzer capable of generating - programs in Rust’s Mid-level Intermediate Representation - that are deterministic and free from Undefined Behaviour. keywords: + - Compiler testing - Rust - - fuzzing - - software validation - - compilers + - Fuzzing license: - - Apache-2.0 - - MIT + - Apache-2.0 + - MIT diff --git a/difftest/src/lib.rs b/difftest/src/lib.rs index c3d48d7..e1933d9 100644 --- a/difftest/src/lib.rs +++ b/difftest/src/lib.rs @@ -36,11 +36,12 @@ impl ExecResults { 'outer: for (&name, result) in map { for (class_result, names) in &mut eq_classes { // Put into an existing equivalence class - let eq = if let Ok(class_out) = class_result && let Ok(out) = result { + let eq = if let Ok(class_out) = class_result + && let Ok(out) = result + { class_out.stdout == out.stdout } else { result == class_result - }; if eq { names.insert(name); diff --git a/generate/src/generation/intrinsics.rs b/generate/src/generation/intrinsics.rs index f2b05e2..85dba65 100644 --- a/generate/src/generation/intrinsics.rs +++ b/generate/src/generation/intrinsics.rs @@ -127,7 +127,9 @@ impl CoreIntrinsic for Transmute { fn dest_type(&self, ty: TyId, tcx: &TyCtxt) -> bool { if ty.contains(tcx, |tcx, ty| match ty.kind(tcx) { // Tys with value validity contstraints - TyKind::Unit | TyKind::Bool | TyKind::Char | TyKind::RawPtr(..) | TyKind::Ref(..) => true, // TODO: pointer transmute + TyKind::Unit | TyKind::Bool | TyKind::Char | TyKind::RawPtr(..) | TyKind::Ref(..) => { + true + } // TODO: pointer transmute _ => false, }) { return false; diff --git a/generate/src/generation/mod.rs b/generate/src/generation/mod.rs index 4a35591..900ed10 100644 --- a/generate/src/generation/mod.rs +++ b/generate/src/generation/mod.rs @@ -13,6 +13,7 @@ use mir::syntax::{ SwitchTargets, Terminator, TyId, TyKind, UnOp, VariantIdx, }; use mir::tyctxt::TyCtxt; +use mir::VarDumper; use rand::seq::SliceRandom; use rand::{seq::IteratorRandom, Rng, RngCore, SeedableRng}; use rand_distr::{Distribution, WeightedError, WeightedIndex}; @@ -300,40 +301,80 @@ impl GenerationCtx { let target_ty = lhs.ty(self.current_decls(), &self.tcx); let source_tys = match target_ty.kind(&self.tcx) { // TODO: no int to ptr cast for now - TyKind::Int(..) | TyKind::Uint(..) => &[ - TyCtxt::ISIZE, - TyCtxt::I8, - TyCtxt::I16, - TyCtxt::I32, - TyCtxt::I64, - TyCtxt::I128, - TyCtxt::USIZE, - TyCtxt::U8, - TyCtxt::U16, - TyCtxt::U32, - TyCtxt::U64, - TyCtxt::U128, - TyCtxt::F32, - TyCtxt::F64, - TyCtxt::CHAR, - TyCtxt::BOOL, - ][..], - TyKind::Float(..) => &[ - TyCtxt::ISIZE, - TyCtxt::I8, - TyCtxt::I16, - TyCtxt::I32, - TyCtxt::I64, - TyCtxt::I128, - TyCtxt::USIZE, - TyCtxt::U8, - TyCtxt::U16, - TyCtxt::U32, - TyCtxt::U64, - TyCtxt::U128, - TyCtxt::F32, - TyCtxt::F64, - ][..], + TyKind::Int(..) | TyKind::Uint(..) => { + if self.tcx.no_128_bit_ints() { + &[ + TyCtxt::ISIZE, + TyCtxt::I8, + TyCtxt::I16, + TyCtxt::I32, + TyCtxt::I64, + TyCtxt::USIZE, + TyCtxt::U8, + TyCtxt::U16, + TyCtxt::U32, + TyCtxt::U64, + TyCtxt::F32, + TyCtxt::F64, + TyCtxt::CHAR, + TyCtxt::BOOL, + ][..] + } else { + &[ + TyCtxt::ISIZE, + TyCtxt::I8, + TyCtxt::I16, + TyCtxt::I32, + TyCtxt::I64, + TyCtxt::I128, + TyCtxt::USIZE, + TyCtxt::U8, + TyCtxt::U16, + TyCtxt::U32, + TyCtxt::U64, + TyCtxt::U128, + TyCtxt::F32, + TyCtxt::F64, + TyCtxt::CHAR, + TyCtxt::BOOL, + ][..] + } + } + TyKind::Float(..) => { + if self.tcx.no_128_bit_ints() { + &[ + TyCtxt::ISIZE, + TyCtxt::I8, + TyCtxt::I16, + TyCtxt::I32, + TyCtxt::I64, + TyCtxt::USIZE, + TyCtxt::U8, + TyCtxt::U16, + TyCtxt::U32, + TyCtxt::U64, + TyCtxt::F32, + TyCtxt::F64, + ][..] + } else { + &[ + TyCtxt::ISIZE, + TyCtxt::I8, + TyCtxt::I16, + TyCtxt::I32, + TyCtxt::I64, + TyCtxt::I128, + TyCtxt::USIZE, + TyCtxt::U8, + TyCtxt::U16, + TyCtxt::U32, + TyCtxt::U64, + TyCtxt::U128, + TyCtxt::F32, + TyCtxt::F64, + ][..] + } + } _ => &[][..], }; let rvalue = self.make_choice( @@ -990,7 +1031,10 @@ impl GenerationCtx { for vars in dumpped.chunks(Program::DUMPER_ARITY) { let new_bb = self.add_new_bb(); - let args = if self.program.use_debug_dumper { + let args = if matches!( + self.program.var_dumper, + VarDumper::StdVarDumper | VarDumper::PrintfVarDumper { .. } + ) { let mut args = Vec::with_capacity(1 + Program::DUMPER_ARITY * 2); args.push(Operand::Constant( self.cursor.function.index().try_into().unwrap(), @@ -1182,9 +1226,36 @@ impl GenerationCtx { } } - pub fn new(seed: u64, debug_dump: bool) -> Self { + fn make_choice_mut( + &mut self, + choices: impl Iterator + Clone, + mut use_choice: F, + ) -> Result + where + F: FnMut(&mut Self, T) -> Result, + T: Clone, + { + let mut failed: Vec = vec![]; + loop { + let (i, choice) = choices + .clone() + .enumerate() + .filter(|(i, _)| !failed.contains(i)) + .choose(&mut *self.rng.borrow_mut()) + .ok_or(SelectionError::Exhausted)?; + let res = use_choice(self, choice.clone()); + match res { + Ok(val) => return Ok(val), + Err(_) => { + failed.push(i); + } + } + } + } + + pub fn new(seed: u64, debug_dump: VarDumper, no_enums: bool,no_128_bit_ints:bool) -> Self { let rng = RefCell::new(Box::new(rand::rngs::SmallRng::seed_from_u64(seed))); - let tcx = Rc::new(seed_tys(&mut *rng.borrow_mut())); + let tcx = Rc::new(seed_tys(&mut *rng.borrow_mut(), no_enums,no_128_bit_ints)); let ty_weights = TySelect::new(&tcx); // TODO: don't zero-initialize current_function and current_bb Self { @@ -1238,7 +1309,7 @@ impl GenerationCtx { let arg_tys: Vec = self .tcx .indices() - .filter(|ty| ::is_literalble(*ty, &self.tcx)) + .filter(|ty| ::is_literalble(*ty, &self.tcx) ) .choose_multiple(&mut *self.rng.borrow_mut(), args_count); let arg_literals: Vec = arg_tys .iter() diff --git a/generate/src/literal.rs b/generate/src/literal.rs index 640c5a0..bd28cca 100644 --- a/generate/src/literal.rs +++ b/generate/src/literal.rs @@ -32,10 +32,17 @@ impl Distribution for Sombrero { pub trait GenLiteral: Rng { fn is_literalble(ty: TyId, tcx: &TyCtxt) -> bool { - match ty.kind(tcx) { + let res = match ty.kind(tcx) { TyKind::Unit => false, - _ => ty.is_scalar(tcx), - } + _ => { + if tcx.no_128_bit_ints() && (ty == TyCtxt::U128 || ty == TyCtxt::I128) { + false + } else { + ty.is_scalar(tcx) + } + } + }; + res } fn gen_literal(&mut self, ty: TyId, tcx: &TyCtxt) -> Option { let lit: Literal = match ty.kind(tcx) { diff --git a/generate/src/main.rs b/generate/src/main.rs index 4f5e583..f27c7db 100644 --- a/generate/src/main.rs +++ b/generate/src/main.rs @@ -10,10 +10,10 @@ mod generation; mod literal; mod mem; -mod place_select; mod pgraph; +mod place_select; mod ty; - +use mir::VarDumper; use std::time::Instant; use clap::{arg, command, value_parser, Arg}; @@ -26,11 +26,18 @@ fn main() { let matches = command!() .args(&[ arg!(-d --debug "generate a program where values are printed instead of hashed (slow)"), + + arg!(-p --printf_debug "generate a program where values are printed using the C 'printf' function instead of hashed (slow)"), + arg!(--rust_gpu "generate a program where values are printed using the C 'printf' function instead of hashed (slow)"), + arg!(--no_enums "generate a program without enums"), + arg!(--no_128_bit_ints "generate a program without 128 bit ints"), + Arg::new("call-syntax") .long("call-syntax") .value_parser(["v1", "v2", "v3", "v4"]) .default_value("v4") .help("switch between different versions of Call syntaxes"), + arg!( "generation seed").value_parser(value_parser!(u64)), ]) .get_matches(); @@ -39,13 +46,38 @@ fn main() { .get_one::("seed") .expect("need an integer as seed"); let debug_dump = matches.get_one::("debug").copied().unwrap_or(false); + let rust_gpu = matches + .get_one::("rust_gpu") + .copied() + .unwrap_or(false); + let no_enums = matches + .get_one::("no_enums") + .copied() + .unwrap_or(false); + let no_128_bit_ints = matches + .get_one::("no_128_bit_ints") + .copied() + .unwrap_or(false); + let printf_dump = matches + .get_one::("printf_debug") + .copied() + .unwrap_or(false) + | rust_gpu; + let dumper = match (debug_dump,printf_dump){ + (false,false)=>VarDumper::HashDumper, + (true,false)=>VarDumper::StdVarDumper, + (false,true)=>VarDumper::PrintfVarDumper{rust_gpu}, + (true,true)=>panic!("You can only choose either the `debug` dumper or `printf_debug` dumper, but both of them have been selected."), + }; info!("Generating a program with seed {seed}"); + let call_syntax = matches.get_one::("call-syntax").unwrap(); - let genctxt = GenerationCtx::new(seed, debug_dump); + let genctxt = GenerationCtx::new(seed, dumper, no_enums,no_128_bit_ints); let time = Instant::now(); let (program, tcx) = genctxt.generate(); println!("{}", program.serialize(&tcx, call_syntax.as_str().into())); - println!("{}", tcx.serialize()); + println!("{}", tcx.serialize(dumper)); + let dur = time.elapsed(); debug!("took {}s to generate", dur.as_secs_f32()); } diff --git a/generate/src/place_select.rs b/generate/src/place_select.rs index 0d16822..1fa5ac3 100644 --- a/generate/src/place_select.rs +++ b/generate/src/place_select.rs @@ -159,6 +159,7 @@ impl PlaceSelector { } fn into_iter_path(self, pt: &PlaceGraph) -> impl Iterator + Clone + '_ { + let exclusion_indicies: Vec = self .exclusions .iter() @@ -289,10 +290,12 @@ impl PlaceSelector { pub fn into_weighted(self, pt: &PlaceGraph) -> Option<(Vec, WeightedIndex)> { let usage = self.usage; let tcx = self.tcx.clone(); + let (places, weights): (Vec, Vec) = self.into_iter_path(pt) .map(|ppath| { let place = ppath.target_index(); + let mut weight = match usage { PlaceUsage::Argument => { let mut weight = 1; diff --git a/generate/src/ty.rs b/generate/src/ty.rs index f82f679..958771c 100644 --- a/generate/src/ty.rs +++ b/generate/src/ty.rs @@ -65,9 +65,7 @@ impl TySelect { TyKind::Int(..) => Some(p_ints / TyKind::INTS.len() as f32), TyKind::Uint(..) => Some(p_ints / TyKind::INTS.len() as f32), TyKind::Float(..) => Some(p_floats / TyKind::FLOATS.len() as f32), - TyKind::RawPtr(..) | TyKind::Ref(..) => { - Some(p_pointers / num_ptrs as f32) - } + TyKind::RawPtr(..) | TyKind::Ref(..) => Some(p_pointers / num_ptrs as f32), _ => None, }; if let Some(rate) = p { @@ -96,7 +94,9 @@ impl TySelect { .unwrap(); } trace!("Typing context with weights:\n{s}"); - trace!("{}", tcx.serialize()); + // FractalFir: serialization requires info about which dumper(printf-based one or not) is used. I pass `StdVarDumper` here to preserve + // previous behaviour. + trace!("{}", tcx.serialize(mir::VarDumper::StdVarDumper)); } WeightedIndex::new(tcx.iter_enumerated().map(|(tyid, _)| weights[&tyid])) @@ -104,9 +104,15 @@ impl TySelect { } pub fn choose_ty(&self, rng: &mut impl Rng, tcx: &TyCtxt) -> TyId { - tcx.indices() + let res = tcx.indices() .nth(self.weights.sample(rng)) - .expect("tyctxt isn't empty") + .expect("tyctxt isn't empty"); + if tcx.no_128_bit_ints() && (res == TyCtxt::I128 || res == TyCtxt::U128){ + TyCtxt::U64 + }else{ + res + } + } } @@ -118,7 +124,11 @@ fn new_composite(tcx: &mut TyCtxt, rng: &mut impl Rng) { (0..length) .map(|_| { tcx.indices() - .filter(|ty| *ty != TyCtxt::UNIT) + .filter(|ty| { + *ty != TyCtxt::UNIT + && (!tcx.no_128_bit_ints() + || !(*ty == TyCtxt::U128 || *ty == TyCtxt::I128)) + }) .choose(rng) .unwrap() }) @@ -126,7 +136,10 @@ fn new_composite(tcx: &mut TyCtxt, rng: &mut impl Rng) { }), 1 => TyKind::RawPtr( tcx.indices() - .filter(|ty| *ty != TyCtxt::UNIT) + .filter(|ty| { + *ty != TyCtxt::UNIT + && (!tcx.no_128_bit_ints() || !(*ty == TyCtxt::U128 || *ty == TyCtxt::I128)) + }) .choose(rng) .unwrap(), if rng.gen_bool(0.5) { @@ -137,7 +150,10 @@ fn new_composite(tcx: &mut TyCtxt, rng: &mut impl Rng) { ), 2 => TyKind::Ref( tcx.indices() - .filter(|ty| *ty != TyCtxt::UNIT) + .filter(|ty| { + *ty != TyCtxt::UNIT + && (!tcx.no_128_bit_ints() || !(*ty == TyCtxt::U128 || *ty == TyCtxt::I128)) + }) .choose(rng) .unwrap(), if rng.gen_bool(0.5) { @@ -148,7 +164,12 @@ fn new_composite(tcx: &mut TyCtxt, rng: &mut impl Rng) { ), 3 => TyKind::Array( tcx.iter_enumerated() - .filter_map(|(ty, kind)| (ty != TyCtxt::UNIT && kind.is_scalar()).then_some(ty)) + .filter_map(|(ty, kind)| { + (ty != TyCtxt::UNIT + && kind.is_scalar() + && (!tcx.no_128_bit_ints() || !(ty == TyCtxt::U128 || ty == TyCtxt::I128))) + .then_some(ty) + }) .choose(rng) .unwrap(), rng.gen_range(1..=ARRAY_MAX_LEN), @@ -162,13 +183,17 @@ fn new_composite(tcx: &mut TyCtxt, rng: &mut impl Rng) { fn new_adt(tcx: &mut TyCtxt, rng: &mut impl Rng) { // TODO: recursive types - let variant_count = rng.gen_range(1..=ADT_MAX_VARIANTS); + let variant_count = if tcx.no_enums() { + 1 + } else { + rng.gen_range(1..=ADT_MAX_VARIANTS) + }; let variants = (0..variant_count).map(|_| { let field_count = rng.gen_range(1..=STRUCT_MAX_FIELDS); let field_tys = tcx .indices() - .filter(|ty| *ty != TyCtxt::UNIT && /* https://github.com/rust-lang/rust/issues/119940 */ !ty.contains(&tcx, |tcx, ty| ty.is_ref(tcx))) + .filter(|ty| *ty != TyCtxt::UNIT && /* https://github.com/rust-lang/rust/issues/119940 */ !ty.contains(tcx, |tcx, ty| ty.is_ref(tcx)) && (!tcx.no_128_bit_ints() || !(*ty == TyCtxt::U128 || *ty == TyCtxt::I128))) .choose_multiple(rng, field_count); VariantDef { fields: IndexVec::from_iter(field_tys.into_iter()), @@ -189,9 +214,9 @@ fn new_adt(tcx: &mut TyCtxt, rng: &mut impl Rng) { tcx.push_adt(adt, meta); } -pub fn seed_tys(rng: &mut R) -> TyCtxt { +pub fn seed_tys(rng: &mut R, no_enums: bool,no_128_bit_ints:bool) -> TyCtxt { // Seed with primitives - let mut tcx: TyCtxt = TyCtxt::from_primitives(); + let mut tcx: TyCtxt = TyCtxt::from_primitives(no_enums,no_128_bit_ints); #[derive(Clone, Copy)] enum Kind { @@ -225,7 +250,12 @@ mod tests { #[test] fn tys_unique() { let mut rng = rand::rngs::SmallRng::seed_from_u64(0); - let tcx = seed_tys(&mut rng); + let tcx = seed_tys(&mut rng, false); + let set: HashSet = tcx.indices().collect(); + assert!(set.len() == tcx.len()); + // Test without enums + let mut rng = rand::rngs::SmallRng::seed_from_u64(0); + let tcx = seed_tys(&mut rng, true); let set: HashSet = tcx.indices().collect(); assert!(set.len() == tcx.len()) } diff --git a/mir/src/lib.rs b/mir/src/lib.rs index f4025f0..006c790 100644 --- a/mir/src/lib.rs +++ b/mir/src/lib.rs @@ -4,3 +4,13 @@ pub mod serialize; pub mod syntax; pub mod tyctxt; +pub const ENABLE_PRINTF_DEBUG: bool = true; +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum VarDumper { + /// Print variable hashes + HashDumper, + /// Print variables using standard rust formatting + StdVarDumper, + /// Print variables using the c `printf` function. If `rust_gpu` is true, then use the `debug_printf!()` rust-gpu macro instead of `printf` + PrintfVarDumper { rust_gpu: bool }, +} diff --git a/mir/src/serialize.rs b/mir/src/serialize.rs index 52b4370..b865518 100644 --- a/mir/src/serialize.rs +++ b/mir/src/serialize.rs @@ -1,4 +1,4 @@ -use crate::{syntax::*, tyctxt::TyCtxt}; +use crate::{syntax::*, tyctxt::TyCtxt, VarDumper}; #[derive(Debug, Clone, Copy)] pub enum CallSynatx { @@ -368,11 +368,18 @@ impl Body { impl Program { pub fn serialize(&self, tcx: &TyCtxt, call_syntax: CallSynatx) -> String { - let mut program = Program::HEADER.to_string(); - if self.use_debug_dumper { - program += Program::DEBUG_DUMPER; - } else { - program += Program::DUMPER; + let mut program = match self.var_dumper { + VarDumper::PrintfVarDumper { rust_gpu: true } => Program::NOSTD_HEADER.to_string(), + _ => Program::HEADER.to_string(), + }; + program += match self.var_dumper { + VarDumper::HashDumper => Program::DUMPER, + VarDumper::StdVarDumper => Program::DEBUG_DUMPER, + VarDumper::PrintfVarDumper { rust_gpu: false } => Program::PRINTF_DUMPER, + VarDumper::PrintfVarDumper { rust_gpu: true } => Program::RUSTGPU_PRINTF_DUMPER, + }; + if let VarDumper::PrintfVarDumper { rust_gpu: true } = self.var_dumper { + program += "use spirv_std::{spirv,macros::debug_printf};\n"; } program.extend(self.functions.iter_enumerated().map(|(idx, body)| { let args_list: String = body @@ -401,7 +408,7 @@ impl Program { let arg_list: String = self .entry_args .iter() - .map(|arg| format!("std::hint::black_box({})", arg.serialize(tcx))) + .map(|arg| format!("core::hint::black_box({})", arg.serialize(tcx))) .intersperse(", ".to_string()) .collect(); @@ -412,7 +419,7 @@ impl Program { .expect("program has functions") .identifier(); - let hash_printer = if self.use_debug_dumper { + let hash_printer = if self.var_dumper != VarDumper::HashDumper { "" } else { r#" @@ -421,13 +428,23 @@ impl Program { } "# }; + if let VarDumper::PrintfVarDumper { rust_gpu: true } = self.var_dumper { + program.push_str(&format!( + "#[spirv(compute(threads(1)))] + pub fn main() {{ + {first_fn}({arg_list}); + {hash_printer} + }}" + )); + } else { + program.push_str(&format!( + "pub fn main() {{ + {first_fn}({arg_list}); + {hash_printer} + }}" + )); + } - program.push_str(&format!( - "pub fn main() {{ - {first_fn}({arg_list}); - {hash_printer} - }}" - )); program } } diff --git a/mir/src/syntax.rs b/mir/src/syntax.rs index 1c7efac..0cd265a 100644 --- a/mir/src/syntax.rs +++ b/mir/src/syntax.rs @@ -3,13 +3,13 @@ use std::num::TryFromIntError; use index_vec::{define_index_type, IndexVec}; use smallvec::SmallVec; -use crate::tyctxt::TyCtxt; +use crate::{tyctxt::TyCtxt, VarDumper}; #[derive(Clone)] pub struct Program { pub functions: IndexVec, pub entry_args: Vec, - pub use_debug_dumper: bool, + pub var_dumper: VarDumper, } pub type LocalDecls = IndexVec; @@ -718,11 +718,15 @@ impl Program { pub const FUNCTION_ATTRIBUTE: &'static str = "#[custom_mir(dialect = \"runtime\", phase = \"initial\")]"; pub const HEADER: &'static str = "#![recursion_limit = \"1024\"] - #![feature(custom_mir, core_intrinsics, const_hash)] - #![allow(unused_parens, unused_assignments, overflowing_literals)] + #![feature(custom_mir, core_intrinsics)] + #![allow(unused_parens, unused_assignments, overflowing_literals,internal_features)] extern crate core; use core::intrinsics::mir::*;\n"; - + pub const NOSTD_HEADER: &'static str = "#![recursion_limit = \"1024\"] + #![feature(custom_mir, core_intrinsics,asm_experimental_arch)] + #![allow(unused_parens, unused_assignments, overflowing_literals,internal_features)] + #![no_std] + use core::intrinsics::mir::*;\n"; pub const DUMPER: &'static str = r#" use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; @@ -759,17 +763,790 @@ impl Program { println!("fn{f}:_{var0} = {val0:?}\n_{var1} = {val1:?}\n_{var2} = {val2:?}\n_{var3} = {val3:?}"); } "#; + /// Implements printf based debuggig for primitive types. + pub const PRINTF_DUMPER: &'static str = r#" + use core::ffi::{c_char, c_int}; + extern "C" { + fn printf(fmt: *const c_char, ...) -> c_int; + } + trait PrintFDebug{ + unsafe fn printf_debug(&self); + } + impl PrintFDebug for *const T{ + unsafe fn printf_debug(&self){ + unsafe{(**self).printf_debug()}; + } + } + impl PrintFDebug for *mut T{ + unsafe fn printf_debug(&self){ + unsafe{(**self).printf_debug()}; + } + } + impl PrintFDebug for &T{ + unsafe fn printf_debug(&self){ + (**self).printf_debug(); + } + } + impl PrintFDebug for &mut T{ + unsafe fn printf_debug(&self){ + (**self).printf_debug(); + } + } + impl PrintFDebug for i8{ + unsafe fn printf_debug(&self){ + printf("%i\0".as_ptr() as *const c_char,*self as i8 as c_int); + } + } + impl PrintFDebug for u8{ + unsafe fn printf_debug(&self){ + printf("%u\0".as_ptr() as *const c_char,*self as u8 as c_int); + } + } + impl PrintFDebug for i16{ + unsafe fn printf_debug(&self){ + printf("%i\0".as_ptr() as *const c_char,*self as i16 as c_int); + } + } + impl PrintFDebug for u16{ + unsafe fn printf_debug(&self){ + printf("%u\0".as_ptr() as *const c_char,*self as u16 as c_int); + } + } + impl PrintFDebug for i32{ + unsafe fn printf_debug(&self){ + printf("%i\0".as_ptr() as *const c_char,*self); + } + } + impl PrintFDebug for f32 { + unsafe fn printf_debug(&self) { + if self.is_nan(){ + printf( + "NaN\0".as_ptr() as *const c_char, + ); + }else{ + printf( + "%f\0".as_ptr() as *const c_char, + *self as core::ffi::c_double, + ); + } + + } + } + impl PrintFDebug for f64 { + unsafe fn printf_debug(&self) { + if self.is_nan(){ + printf( + "NaN\0".as_ptr() as *const c_char, + ); + }else{ + printf( + "%f\0".as_ptr() as *const c_char, + *self as core::ffi::c_double, + ); + } + } + } + impl PrintFDebug for [T;N]{ + unsafe fn printf_debug(&self){ + printf("[\0".as_ptr() as *const c_char); + for b in self{ + b.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + } + printf("]\0".as_ptr() as *const c_char); + } + } + impl PrintFDebug for u32{ + unsafe fn printf_debug(&self){ + printf("%u\0".as_ptr() as *const c_char,*self); + } + } + impl PrintFDebug for char{ + unsafe fn printf_debug(&self){ + printf("%u\0".as_ptr() as *const c_char,*self as u64); + } + } + impl PrintFDebug for i64{ + unsafe fn printf_debug(&self){ + printf("%li\0".as_ptr() as *const c_char,*self); + } + } + impl PrintFDebug for u64{ + unsafe fn printf_debug(&self){ + printf("%lu\0".as_ptr() as *const c_char,*self); + } + } + impl PrintFDebug for i128{ + unsafe fn printf_debug(&self){ + u128::printf_debug(&(*self as u128)); + } + } + impl PrintFDebug for u128{ + unsafe fn printf_debug(&self){ + printf("%lx%lx\0".as_ptr() as *const c_char, (*self >> 64) as u64,*self as u64); + } + } + impl PrintFDebug for isize{ + unsafe fn printf_debug(&self){ + printf("%li\0".as_ptr() as *const c_char,*self as isize); + } + } + impl PrintFDebug for usize{ + unsafe fn printf_debug(&self){ + printf("%lu\0".as_ptr() as *const c_char,*self as usize); + } + } + impl PrintFDebug for bool{ + unsafe fn printf_debug(&self){ + if *self{ + printf("true\0".as_ptr() as *const c_char); + } + else{ + printf("false\0".as_ptr() as *const c_char); + } + } + } + impl PrintFDebug for (){ + unsafe fn printf_debug(&self){ + printf("()\0".as_ptr() as *const c_char); + } + } + impl PrintFDebug for (A,){ + unsafe fn printf_debug(&self){ + printf("(\0".as_ptr() as *const c_char); + self.0.printf_debug(); + printf(",)\0".as_ptr() as *const c_char); + } + } + impl PrintFDebug for (A,B){ + unsafe fn printf_debug(&self){ + printf("(\0".as_ptr() as *const c_char); + self.0.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.1.printf_debug(); + printf(")\0".as_ptr() as *const c_char); + } + } + impl PrintFDebug for (A,B,C){ + unsafe fn printf_debug(&self){ + printf("(\0".as_ptr() as *const c_char); + self.0.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.1.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.2.printf_debug(); + printf(")\0".as_ptr() as *const c_char); + } + } + impl PrintFDebug for (A,B,C,D){ + unsafe fn printf_debug(&self){ + printf("(\0".as_ptr() as *const c_char); + self.0.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.1.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.2.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.3.printf_debug(); + printf(")\0".as_ptr() as *const c_char); + } + } + impl PrintFDebug for (A,B,C,D,E){ + unsafe fn printf_debug(&self){ + printf("(\0".as_ptr() as *const c_char); + self.0.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.1.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.2.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.3.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.4.printf_debug(); + printf(")\0".as_ptr() as *const c_char); + } + } + impl PrintFDebug for (A,B,C,D,E,F){ + unsafe fn printf_debug(&self){ + printf("(\0".as_ptr() as *const c_char); + self.0.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.1.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.2.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.3.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.4.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.5.printf_debug(); + printf(")\0".as_ptr() as *const c_char); + } + } + impl PrintFDebug for (A,B,C,D,E,F,G){ + unsafe fn printf_debug(&self){ + printf("(\0".as_ptr() as *const c_char); + self.0.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.1.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.2.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.3.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.4.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.5.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.6.printf_debug(); + printf(")\0".as_ptr() as *const c_char); + } + } + impl PrintFDebug for (A,B,C,D,E,F,G,H){ + unsafe fn printf_debug(&self){ + printf("(\0".as_ptr() as *const c_char); + self.0.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.1.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.2.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.3.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.4.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.5.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.6.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.7.printf_debug(); + printf(")\0".as_ptr() as *const c_char); + } + } + impl PrintFDebug for (A,B,C,D,E,F,G,H,I){ + unsafe fn printf_debug(&self){ + printf("(\0".as_ptr() as *const c_char); + self.0.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.1.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.2.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.3.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.4.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.5.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.6.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.7.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.8.printf_debug(); + printf(")\0".as_ptr() as *const c_char); + } + } + impl PrintFDebug for (A,B,C,D,E,F,G,H,I,J){ + unsafe fn printf_debug(&self){ + printf("(\0".as_ptr() as *const c_char); + self.0.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.1.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.2.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.3.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.4.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.5.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.6.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.7.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.8.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.9.printf_debug(); + printf(")\0".as_ptr() as *const c_char); + } + } + impl PrintFDebug for (A,B,C,D,E,F,G,H,I,J,K){ + unsafe fn printf_debug(&self){ + printf("(\0".as_ptr() as *const c_char); + self.0.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.1.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.2.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.3.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.4.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.5.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.6.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.7.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.8.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.9.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.10.printf_debug(); + printf(")\0".as_ptr() as *const c_char); + } + } + impl PrintFDebug for (A,B,C,D,E,F,G,H,I,J,K,L){ + unsafe fn printf_debug(&self){ + printf("(\0".as_ptr() as *const c_char); + self.0.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.1.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.2.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.3.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.4.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.5.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.6.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.7.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.8.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.9.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.10.printf_debug(); + printf(",\0".as_ptr() as *const c_char); + self.11.printf_debug(); + printf(")\0".as_ptr() as *const c_char); + } + } + #[inline(never)] + fn dump_var( + f: usize, + var0: usize, val0: impl PrintFDebug, + var1: usize, val1: impl PrintFDebug, + var2: usize, val2: impl PrintFDebug, + var3: usize, val3: impl PrintFDebug, + ) { + unsafe{ + printf("fn%u:_%u = \0".as_ptr() as *const c_char,f,var0); + val0.printf_debug(); + printf("\n_%u = \0".as_ptr() as *const c_char,var1); + val1.printf_debug(); + printf("\n_%u = \0".as_ptr() as *const c_char,var2); + val2.printf_debug(); + printf("\n_%u = \0".as_ptr() as *const c_char,var3); + val3.printf_debug(); + printf("\n\0".as_ptr() as *const c_char); + } + } + "#; + /// Implements printf based debuggig for primitive types. + pub const RUSTGPU_PRINTF_DUMPER: &'static str = r#" + use core::ffi::{c_char, c_int,c_uint,c_long}; + trait PrintFDebug{ + unsafe fn printf_debug(&self); + } + impl PrintFDebug for *const T{ + unsafe fn printf_debug(&self){ + unsafe{(**self).printf_debug()}; + } + } + impl PrintFDebug for *mut T{ + unsafe fn printf_debug(&self){ + unsafe{(**self).printf_debug()}; + } + } + impl PrintFDebug for &T{ + unsafe fn printf_debug(&self){ + (**self).printf_debug(); + } + } + impl PrintFDebug for &mut T{ + unsafe fn printf_debug(&self){ + (**self).printf_debug(); + } + } + impl PrintFDebug for i8{ + unsafe fn printf_debug(&self){ + debug_printf!("%i",*self as c_int); + } + } + impl PrintFDebug for u8{ + unsafe fn printf_debug(&self){ + debug_printf!("%u",*self as c_uint); + } + } + impl PrintFDebug for i16{ + unsafe fn printf_debug(&self){ + debug_printf!("%i",*self as c_int); + } + } + impl PrintFDebug for u16{ + unsafe fn printf_debug(&self){ + debug_printf!("%u",*self as c_uint); + } + } + impl PrintFDebug for i32{ + unsafe fn printf_debug(&self){ + debug_printf!("%i",*self as c_int); + } + } + impl PrintFDebug for f32 { + unsafe fn printf_debug(&self) { + if self.is_nan(){ + debug_printf!("NaN"); + }else{ + debug_printf!( + "%f", + *self as f32, + ); + } + + } + } + impl PrintFDebug for f64 { + unsafe fn printf_debug(&self) { + if self.is_nan(){ + debug_printf!("NaN"); + }else{ + debug_printf!( + "%f", + *self as f32, + ); + } + } + } + impl PrintFDebug for [T;N]{ + unsafe fn printf_debug(&self){ + debug_printf!("["); + for b in self{ + b.printf_debug(); + debug_printf!(","); + } + debug_printf!("]"); + } + } + impl PrintFDebug for u32{ + unsafe fn printf_debug(&self){ + debug_printf!("%u",*self as c_uint); + } + } + impl PrintFDebug for char{ + unsafe fn printf_debug(&self){ + debug_printf!("%u",*self as u32 as c_uint); + } + } + impl PrintFDebug for i64{ + unsafe fn printf_debug(&self){ + if *self < 0{ + debug_printf!("-%lu",-self as u64); + } + else{ + debug_printf!("%lu",*self as u64);} + } + } + impl PrintFDebug for u64{ + unsafe fn printf_debug(&self){ + debug_printf!("%lu",*self); + } + } + impl PrintFDebug for i128{ + unsafe fn printf_debug(&self){ + u128::printf_debug(&(*self as u128)); + } + } + impl PrintFDebug for u128{ + unsafe fn printf_debug(&self){ + debug_printf!("%lx%lx", (*self >> 64) as u64,*self as u64); + } + } + impl PrintFDebug for isize{ + unsafe fn printf_debug(&self){ + + if *self < 0{ + debug_printf!("-%lu",-self as u64); + } + else{ + debug_printf!("%lu",*self as u64);} + } + + } + impl PrintFDebug for usize{ + unsafe fn printf_debug(&self){ + debug_printf!("%lu",*self as u64); + } + } + impl PrintFDebug for bool{ + unsafe fn printf_debug(&self){ + if *self{ + debug_printf!("true"); + } + else{ + debug_printf!("false"); + } + } + } + impl PrintFDebug for (){ + unsafe fn printf_debug(&self){ + debug_printf!("()"); + } + } + impl PrintFDebug for (A,){ + unsafe fn printf_debug(&self){ + debug_printf!("("); + self.0.printf_debug(); + debug_printf!(",)"); + } + } + impl PrintFDebug for (A,B){ + unsafe fn printf_debug(&self){ + debug_printf!("("); + self.0.printf_debug(); + debug_printf!(","); + self.1.printf_debug(); + debug_printf!(")"); + } + } + impl PrintFDebug for (A,B,C){ + unsafe fn printf_debug(&self){ + debug_printf!("("); + self.0.printf_debug(); + debug_printf!(","); + self.1.printf_debug(); + debug_printf!(","); + self.2.printf_debug(); + debug_printf!(")"); + } + } + impl PrintFDebug for (A,B,C,D){ + unsafe fn printf_debug(&self){ + debug_printf!("("); + self.0.printf_debug(); + debug_printf!(","); + self.1.printf_debug(); + debug_printf!(","); + self.2.printf_debug(); + debug_printf!(","); + self.3.printf_debug(); + debug_printf!(")"); + } + } + impl PrintFDebug for (A,B,C,D,E){ + unsafe fn printf_debug(&self){ + debug_printf!("("); + self.0.printf_debug(); + debug_printf!(","); + self.1.printf_debug(); + debug_printf!(","); + self.2.printf_debug(); + debug_printf!(","); + self.3.printf_debug(); + debug_printf!(","); + self.4.printf_debug(); + debug_printf!(")"); + } + } + impl PrintFDebug for (A,B,C,D,E,F){ + unsafe fn printf_debug(&self){ + debug_printf!("("); + self.0.printf_debug(); + debug_printf!(","); + self.1.printf_debug(); + debug_printf!(","); + self.2.printf_debug(); + debug_printf!(","); + self.3.printf_debug(); + debug_printf!(","); + self.4.printf_debug(); + debug_printf!(","); + self.5.printf_debug(); + debug_printf!(")"); + } + } + impl PrintFDebug for (A,B,C,D,E,F,G){ + unsafe fn printf_debug(&self){ + debug_printf!("("); + self.0.printf_debug(); + debug_printf!(","); + self.1.printf_debug(); + debug_printf!(","); + self.2.printf_debug(); + debug_printf!(","); + self.3.printf_debug(); + debug_printf!(","); + self.4.printf_debug(); + debug_printf!(","); + self.5.printf_debug(); + debug_printf!(","); + self.6.printf_debug(); + debug_printf!(")"); + } + } + impl PrintFDebug for (A,B,C,D,E,F,G,H){ + unsafe fn printf_debug(&self){ + debug_printf!("("); + self.0.printf_debug(); + debug_printf!(","); + self.1.printf_debug(); + debug_printf!(","); + self.2.printf_debug(); + debug_printf!(","); + self.3.printf_debug(); + debug_printf!(","); + self.4.printf_debug(); + debug_printf!(","); + self.5.printf_debug(); + debug_printf!(","); + self.6.printf_debug(); + debug_printf!(","); + self.7.printf_debug(); + debug_printf!(")"); + } + } + impl PrintFDebug for (A,B,C,D,E,F,G,H,I){ + unsafe fn printf_debug(&self){ + debug_printf!("("); + self.0.printf_debug(); + debug_printf!(","); + self.1.printf_debug(); + debug_printf!(","); + self.2.printf_debug(); + debug_printf!(","); + self.3.printf_debug(); + debug_printf!(","); + self.4.printf_debug(); + debug_printf!(","); + self.5.printf_debug(); + debug_printf!(","); + self.6.printf_debug(); + debug_printf!(","); + self.7.printf_debug(); + debug_printf!(","); + self.8.printf_debug(); + debug_printf!(")"); + } + } + impl PrintFDebug for (A,B,C,D,E,F,G,H,I,J){ + unsafe fn printf_debug(&self){ + debug_printf!("("); + self.0.printf_debug(); + debug_printf!(","); + self.1.printf_debug(); + debug_printf!(","); + self.2.printf_debug(); + debug_printf!(","); + self.3.printf_debug(); + debug_printf!(","); + self.4.printf_debug(); + debug_printf!(","); + self.5.printf_debug(); + debug_printf!(","); + self.6.printf_debug(); + debug_printf!(","); + self.7.printf_debug(); + debug_printf!(","); + self.8.printf_debug(); + debug_printf!(","); + self.9.printf_debug(); + debug_printf!(")"); + } + } + impl PrintFDebug for (A,B,C,D,E,F,G,H,I,J,K){ + unsafe fn printf_debug(&self){ + debug_printf!("("); + self.0.printf_debug(); + debug_printf!(","); + self.1.printf_debug(); + debug_printf!(","); + self.2.printf_debug(); + debug_printf!(","); + self.3.printf_debug(); + debug_printf!(","); + self.4.printf_debug(); + debug_printf!(","); + self.5.printf_debug(); + debug_printf!(","); + self.6.printf_debug(); + debug_printf!(","); + self.7.printf_debug(); + debug_printf!(","); + self.8.printf_debug(); + debug_printf!(","); + self.9.printf_debug(); + debug_printf!(","); + self.10.printf_debug(); + debug_printf!(")"); + } + } + impl PrintFDebug for (A,B,C,D,E,F,G,H,I,J,K,L){ + unsafe fn printf_debug(&self){ + debug_printf!("("); + self.0.printf_debug(); + debug_printf!(","); + self.1.printf_debug(); + debug_printf!(","); + self.2.printf_debug(); + debug_printf!(","); + self.3.printf_debug(); + debug_printf!(","); + self.4.printf_debug(); + debug_printf!(","); + self.5.printf_debug(); + debug_printf!(","); + self.6.printf_debug(); + debug_printf!(","); + self.7.printf_debug(); + debug_printf!(","); + self.8.printf_debug(); + debug_printf!(","); + self.9.printf_debug(); + debug_printf!(","); + self.10.printf_debug(); + debug_printf!(","); + self.11.printf_debug(); + debug_printf!(")"); + } + } + #[inline(never)] + fn dump_var( + f: usize, + var0: usize, val0: impl PrintFDebug, + var1: usize, val1: impl PrintFDebug, + var2: usize, val2: impl PrintFDebug, + var3: usize, val3: impl PrintFDebug, + ) { + unsafe{ + debug_printf!("fn%lu:_%lu = ",f as u64,var0 as u64); + val0.printf_debug(); + debug_printf!("\n_%lu = ",var1 as u64); + val1.printf_debug(); + debug_printf!("\n_%lu = ",var2 as u64); + val2.printf_debug(); + debug_printf!("\n_%lu = ",var3 as u64); + val3.printf_debug(); + debug_printf!("\n"); + } + } + "#; // Fake "intrinsic" pub const DUMPER_CALL: Callee = Callee::Named("dump_var"); pub const DUMPER_ARITY: usize = 4; // A new, empty function - pub fn new(debug: bool) -> Self { + pub fn new(debug: VarDumper) -> Self { Self { functions: IndexVec::default(), entry_args: vec![], - use_debug_dumper: debug, + var_dumper: debug, } } diff --git a/mir/src/tyctxt.rs b/mir/src/tyctxt.rs index 479ce9a..63ed71f 100644 --- a/mir/src/tyctxt.rs +++ b/mir/src/tyctxt.rs @@ -5,6 +5,7 @@ use index_vec::IndexVec; use crate::{ serialize::Serialize, syntax::{Adt, TyId, TyKind}, + VarDumper, }; #[derive(Debug, Clone, Copy)] @@ -32,6 +33,8 @@ impl AdtMeta { pub struct TyCtxt { tys: IndexVec, adt_meta: HashMap, + no_enums: bool, + no_128_bit_ints: bool, } impl TyCtxt { @@ -53,7 +56,7 @@ impl TyCtxt { pub const F32: TyId = TyId::from_usize_unchecked(15); pub const F64: TyId = TyId::from_usize_unchecked(16); - pub fn from_primitives() -> Self { + pub fn from_primitives(no_enums: bool,no_128_bit_ints:bool) -> Self { let primitives: [TyKind; 17] = [ TyKind::Unit, TyKind::Bool, @@ -77,6 +80,8 @@ impl TyCtxt { Self { tys, adt_meta: HashMap::new(), + no_enums, + no_128_bit_ints, } } @@ -115,13 +120,19 @@ impl TyCtxt { self.tys.len() } - pub fn serialize(&self) -> String { + pub fn serialize(&self, dumper: VarDumper) -> String { let mut str = String::new(); for (id, adt) in self.tys.iter_enumerated().filter(|(_, kind)| kind.is_adt()) { let TyKind::Adt(adt) = adt else { panic!("not an adt"); }; - str += &self.adt_meta[&id].derive_attrs(); + // `Debug` derive is ommited for printf-based dumping. An implemntation of the PrintFDebug trait is emmited instead. + str += &match dumper { + VarDumper::HashDumper | VarDumper::StdVarDumper => { + self.adt_meta[&id].derive_attrs() + } + VarDumper::PrintfVarDumper { rust_gpu } => adt_impl_printf_debug(adt, id, rust_gpu), + }; if adt.is_enum() { let variants: String = adt .variants @@ -143,4 +154,99 @@ impl TyCtxt { } str } + + pub fn no_enums(&self) -> bool { + self.no_enums + } + + pub fn no_128_bit_ints(&self) -> bool { + self.no_128_bit_ints + } +} +/// Implements the PrintFDebug trait for an ADT. +/// This trait is used to dump variables using `printf` +pub fn adt_impl_printf_debug(adt: &Adt, id: TyId, rust_gpu: bool) -> String { + let res = if adt.is_enum() { + // Formats an enum + let name = id.type_name(); + let mut res = format!("impl PrintFDebug for {name}{{\n\tunsafe fn printf_debug(&self){{"); + if rust_gpu { + res.push_str(&format!("unsafe{{debug_printf!(\"{name}::\")}};")); + } else { + res.push_str(&format!( + "unsafe{{printf(\"{name}::\\0\".as_ptr() as *const c_char)}};" + )); + } + + res.push_str("match self{\n"); + // Iterate through variants cratete a match statement + for (variant_idx, variant) in adt.variants.iter().enumerate() { + res.push_str(&format!("\tSelf::Variant{variant_idx}{{",)); + // Iterate trough fields to generate match patterns + for (field_id, _) in variant.fields.iter().enumerate() { + res.push_str(&format!("fld{field_id},")); + } + res.push_str("}=>{\n"); + if rust_gpu { + res.push_str(&format!( + "unsafe{{debug_printf!(\"Variant{variant_idx}{{\")}};\n" + )); + } else { + res.push_str(&format!( + "unsafe{{printf(\"Variant{variant_idx}{{\\0\".as_ptr() as *const c_char)}};\n" + )); + } + + // Iterate trough fields to print values of fields of variant + for (field_id, _) in variant.fields.iter().enumerate() { + if rust_gpu { + res.push_str(&format!( + "\t\tunsafe{{debug_printf!(\"fld{field_id}:\")}};\n" + )); + res.push_str(&format!("\t\tfld{field_id}.printf_debug();\n")); + res.push_str("unsafe{debug_printf!(\",\")};\n"); + } else { + res.push_str(&format!( + "\t\tunsafe{{printf(\"fld{field_id}:\\0\".as_ptr() as *const c_char)}};\n" + )); + res.push_str(&format!("\t\tfld{field_id}.printf_debug();\n")); + res.push_str("unsafe{printf(\",\\0\".as_ptr() as *const c_char)};\n"); + } + } + res.push_str("},\n") + } + res.push_str("\t\t}\n"); + if rust_gpu { + res.push_str("unsafe{debug_printf!(\"}\")};\n"); + } else { + res.push_str("unsafe{printf(\"\\0}\".as_ptr() as *const c_char)};\n"); + } + + res.push_str("\t}\n}"); + res + } else { + // Formats a struct + let mut res = if rust_gpu { + format!("impl PrintFDebug for {name}{{\n\tunsafe fn printf_debug(&self){{\n\tunsafe{{debug_printf!(\"{name}{{\")}};",name = id.type_name()) + } else { + format!("impl PrintFDebug for {name}{{\n\tunsafe fn printf_debug(&self){{\n\tunsafe{{printf(\"{name}{{\\0\".as_ptr() as *const c_char)}};",name = id.type_name()) + }; + // Iterate trough fields to print values of fields of stuct + for (field_id, _) in adt.variants[0].fields.iter().enumerate() { + if rust_gpu { + res.push_str(&format!( + "\n\tdebug_printf!(\"fld{field_id}:\");\n\tself.fld{field_id}.printf_debug();" + )); + } else { + res.push_str(&format!("\n\tprintf(\"fld{field_id}:\\0\".as_ptr() as *const c_char);\n\tself.fld{field_id}.printf_debug();")); + } + } + if rust_gpu { + res.push_str("\n\tunsafe{debug_printf!(\"}\")};}\n}"); + } else { + res.push_str("\n\tunsafe{printf(\"}\\0\".as_ptr() as *const c_char)};}\n}"); + } + res + }; + format!("{res}\n#[derive(Copy,Clone)]") }