blob: 04741e4f807570f4940d3022d285670d0e1ca579 [file] [log] [blame]
use crate::common::intrinsic::Intrinsic;
use super::argument::Argument;
use super::indentation::Indentation;
use super::intrinsic_helpers::IntrinsicTypeDefinition;
// The number of times each intrinsic will be called.
const PASSES: u32 = 20;
const COMMON_HEADERS: [&str; 7] = [
"iostream",
"string",
"cstring",
"iomanip",
"sstream",
"type_traits",
"cassert",
];
pub fn generate_c_test_loop<T: IntrinsicTypeDefinition + Sized>(
w: &mut impl std::io::Write,
intrinsic: &Intrinsic<T>,
indentation: Indentation,
additional: &str,
passes: u32,
) -> std::io::Result<()> {
let body_indentation = indentation.nested();
writeln!(
w,
"{indentation}for (int i=0; i<{passes}; i++) {{\n\
{loaded_args}\
{body_indentation}auto __return_value = {intrinsic_call}({args});\n\
{print_result}\n\
{indentation}}}",
loaded_args = intrinsic.arguments.load_values_c(body_indentation),
intrinsic_call = intrinsic.name,
args = intrinsic.arguments.as_call_param_c(),
print_result = intrinsic
.results
.print_result_c(body_indentation, additional)
)
}
pub fn generate_c_constraint_blocks<'a, T: IntrinsicTypeDefinition + 'a>(
w: &mut impl std::io::Write,
intrinsic: &Intrinsic<T>,
indentation: Indentation,
constraints: &mut (impl Iterator<Item = &'a Argument<T>> + Clone),
name: String,
) -> std::io::Result<()> {
let Some(current) = constraints.next() else {
return generate_c_test_loop(w, intrinsic, indentation, &name, PASSES);
};
let body_indentation = indentation.nested();
for i in current.constraint.iter().flat_map(|c| c.iter()) {
let ty = current.ty.c_type();
writeln!(w, "{indentation}{{")?;
// TODO: Move to actually specifying the enum value
// instead of typecasting integers, for better clarity
// of generated code.
writeln!(
w,
"{body_indentation}const {ty} {} = ({ty}){i};",
current.generate_name()
)?;
generate_c_constraint_blocks(
w,
intrinsic,
body_indentation,
&mut constraints.clone(),
format!("{name}-{i}"),
)?;
writeln!(w, "{indentation}}}")?;
}
Ok(())
}
// Compiles C test programs using specified compiler
pub fn create_c_test_function<T: IntrinsicTypeDefinition>(
w: &mut impl std::io::Write,
intrinsic: &Intrinsic<T>,
) -> std::io::Result<()> {
let indentation = Indentation::default();
writeln!(w, "int run_{}() {{", intrinsic.name)?;
// Define the arrays of arguments.
let arguments = &intrinsic.arguments;
arguments.gen_arglists_c(w, indentation.nested(), PASSES)?;
generate_c_constraint_blocks(
w,
intrinsic,
indentation.nested(),
&mut arguments.iter().rev().filter(|&i| i.has_constraint()),
Default::default(),
)?;
writeln!(w, " return 0;")?;
writeln!(w, "}}")?;
Ok(())
}
pub fn write_mod_cpp<T: IntrinsicTypeDefinition>(
w: &mut impl std::io::Write,
notice: &str,
platform_headers: &[&str],
forward_declarations: &str,
intrinsics: &[Intrinsic<T>],
) -> std::io::Result<()> {
write!(w, "{notice}")?;
for header in COMMON_HEADERS.iter().chain(platform_headers.iter()) {
writeln!(w, "#include <{header}>")?;
}
writeln!(w, "{}", forward_declarations)?;
for intrinsic in intrinsics {
create_c_test_function(w, intrinsic)?;
}
Ok(())
}
pub fn write_main_cpp<'a>(
w: &mut impl std::io::Write,
arch_specific_definitions: &str,
arch_specific_headers: &[&str],
intrinsics: impl Iterator<Item = &'a str> + Clone,
) -> std::io::Result<()> {
for header in COMMON_HEADERS.iter().chain(arch_specific_headers.iter()) {
writeln!(w, "#include <{header}>")?;
}
// NOTE: It's assumed that this value contains the required `ifdef`s.
writeln!(w, "{arch_specific_definitions }")?;
for intrinsic in intrinsics.clone() {
writeln!(w, "extern int run_{intrinsic}(void);")?;
}
writeln!(w, "int main(int argc, char **argv) {{")?;
writeln!(w, " std::string intrinsic_name = argv[1];")?;
writeln!(w, " if (false) {{")?;
for intrinsic in intrinsics {
writeln!(w, " }} else if (intrinsic_name == \"{intrinsic}\") {{")?;
writeln!(w, " return run_{intrinsic}();")?;
}
writeln!(w, " }} else {{")?;
writeln!(
w,
" std::cerr << \"Unknown command: \" << intrinsic_name << \"\\n\";"
)?;
writeln!(w, " return -1;")?;
writeln!(w, " }}")?;
writeln!(w, "}}")?;
Ok(())
}