diff --git a/cranelift/isle/src/codegen.rs b/cranelift/isle/src/codegen.rs index d503c81515..e97ef8b6ce 100644 --- a/cranelift/isle/src/codegen.rs +++ b/cranelift/isle/src/codegen.rs @@ -2,7 +2,7 @@ use crate::error::Error; use crate::ir::{lower_rule, ExprSequence, PatternInst, PatternSequence}; -use crate::sema::{RuleId, TermEnv, TermId, Type, TypeEnv}; +use crate::sema::{RuleId, TermEnv, TermId, TermKind, Type, TypeEnv, TypeId}; use std::collections::HashMap; use std::fmt::Write; @@ -511,21 +511,31 @@ impl<'a> Codegen<'a> { pub fn generate_rust(&self) -> Result { let mut code = String::new(); - writeln!(&mut code, "// GENERATED BY ISLE. DO NOT EDIT!")?; - writeln!(&mut code, "//")?; + + self.generate_header(&mut code)?; + self.generate_internal_types(&mut code)?; + self.generate_internal_term_constructors(&mut code)?; + self.generate_internal_term_extractors(&mut code)?; + + Ok(code) + } + + fn generate_header(&self, code: &mut dyn Write) -> Result<(), Error> { + writeln!(code, "// GENERATED BY ISLE. DO NOT EDIT!")?; + writeln!(code, "//")?; writeln!( - &mut code, + code, "// Generated automatically from the instruction-selection DSL code in:", )?; for file in &self.typeenv.filenames { - writeln!(&mut code, "// - {}", file)?; + writeln!(code, "// - {}", file)?; } writeln!( - &mut code, + code, "\nuse super::*; // Pulls in all external types and ctors/etors" )?; - self.generate_internal_types(&mut code)?; - Ok(code) + + Ok(()) } fn generate_internal_types(&self, code: &mut dyn Write) -> Result<(), Error> { @@ -564,4 +574,84 @@ impl<'a> Codegen<'a> { } Ok(()) } + + fn constructor_name(&self, term: TermId) -> String { + let termdata = &self.termenv.terms[term.index()]; + match &termdata.kind { + &TermKind::EnumVariant { .. } => panic!("using enum variant as constructor"), + &TermKind::Regular { + constructor: Some(sym), + .. + } => self.typeenv.syms[sym.index()].clone(), + &TermKind::Regular { + constructor: None, .. + } => { + format!("constructor_{}", self.typeenv.syms[termdata.name.index()]) + } + } + } + + fn type_name(&self, typeid: TypeId, by_ref: bool) -> String { + match &self.typeenv.types[typeid.index()] { + &Type::Primitive(_, sym) => self.typeenv.syms[sym.index()].clone(), + &Type::Enum { name, .. } => { + let r = if by_ref { "&" } else { "" }; + format!("{}{}", r, self.typeenv.syms[name.index()]) + } + } + } + + fn generate_internal_term_constructors(&self, code: &mut dyn Write) -> Result<(), Error> { + for (&termid, trie) in &self.functions_by_input { + let termdata = &self.termenv.terms[termid.index()]; + // Skip terms that are enum variants or that have external constructors. + match &termdata.kind { + &TermKind::EnumVariant { .. } => continue, + &TermKind::Regular { constructor, .. } if constructor.is_some() => continue, + _ => {} + } + + // Get the name of the term and build up the signature. + let func_name = self.constructor_name(termid); + let args = termdata + .arg_tys + .iter() + .enumerate() + .map(|(i, &arg_ty)| { + format!("arg{}: {}", i, self.type_name(arg_ty, /* by_ref = */ true)) + }) + .collect::>(); + writeln!( + code, + "\n// Generated as internal constructor for term {}.", + self.typeenv.syms[termdata.name.index()], + )?; + writeln!( + code, + "fn {}(ctx: &mut C, {}) -> Option<{}> {{", + func_name, + args.join(", "), + self.type_name(termdata.ret_ty, /* by_ref = */ false) + )?; + + self.generate_body(code, termid, trie)?; + + writeln!(code, "}}")?; + } + + Ok(()) + } + + fn generate_internal_term_extractors(&self, _code: &mut dyn Write) -> Result<(), Error> { + Ok(()) + } + + fn generate_body( + &self, + _code: &mut dyn Write, + _termid: TermId, + _trie: &TrieNode, + ) -> Result<(), Error> { + Ok(()) + } }