From cd55dc956827746b07c803dc986f16637cfacd45 Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Sat, 4 Sep 2021 17:20:55 -0700 Subject: [PATCH] WIP. --- cranelift/isle/src/codegen.rs | 55 ++++++++++++++++++++++++++--------- cranelift/isle/src/ir.rs | 7 +++-- cranelift/isle/src/lexer.rs | 2 +- cranelift/isle/src/sema.rs | 3 ++ 4 files changed, 50 insertions(+), 17 deletions(-) diff --git a/cranelift/isle/src/codegen.rs b/cranelift/isle/src/codegen.rs index 55f530f9c3..001c1f36b9 100644 --- a/cranelift/isle/src/codegen.rs +++ b/cranelift/isle/src/codegen.rs @@ -852,6 +852,8 @@ impl<'a> Codegen<'a> { Ok(()) } + /// Returns a `bool` indicating whether this pattern inst is + /// infallible. fn generate_pattern_inst( &self, code: &mut dyn Write, @@ -859,27 +861,30 @@ impl<'a> Codegen<'a> { inst: &PatternInst, indent: &str, ctx: &mut BodyContext, - ) -> Result<(), Error> { + ) -> Result { match inst { &PatternInst::Arg { index, .. } => { - let output = Value::Expr { + let output = Value::Pattern { inst: id, output: 0, }; let outputname = self.value_name(&output); writeln!(code, "{}let {} = arg{};", indent, outputname, index)?; writeln!(code, "{}{{", indent)?; + Ok(true) } &PatternInst::MatchEqual { ref a, ref b, .. } => { let a = self.value_by_ref(a, ctx); let b = self.value_by_ref(b, ctx); writeln!(code, "{}if {} == {} {{", indent, a, b)?; + Ok(false) } &PatternInst::MatchInt { ref input, int_val, .. } => { let input = self.value_by_val(input, ctx); writeln!(code, "{}if {} == {} {{", indent, input, int_val)?; + Ok(false) } &PatternInst::MatchVariant { ref input, @@ -897,21 +902,23 @@ impl<'a> Codegen<'a> { let variantname = &self.typeenv.syms[variant.name.index()]; let args = arg_tys .iter() + .zip(variant.fields.iter()) .enumerate() - .map(|(i, ty)| { + .map(|(i, (ty, field))| { let value = Value::Pattern { inst: id, output: i, }; let valuename = self.value_name(&value); + let fieldname = &self.typeenv.syms[field.name.index()]; match &self.typeenv.types[ty.index()] { &Type::Primitive(..) => { self.define_val(&value, ctx, /* is_ref = */ false); - valuename + format!("{}: {}", fieldname, valuename) } &Type::Enum { .. } => { self.define_val(&value, ctx, /* is_ref = */ true); - format!("ref {}", valuename) + format!("{}: ref {}", fieldname, valuename) } } }) @@ -925,6 +932,7 @@ impl<'a> Codegen<'a> { args.join(", "), input )?; + Ok(false) } &PatternInst::Extract { ref input, @@ -968,10 +976,9 @@ impl<'a> Codegen<'a> { input )?; } + Ok(infallible) } } - - Ok(()) } fn generate_body( @@ -981,15 +988,27 @@ impl<'a> Codegen<'a> { trie: &TrieNode, indent: &str, ctx: &mut BodyContext, - ) -> Result<(), Error> { + ) -> Result { + log::trace!("generate_body: trie {:?}", trie); + let mut returned = false; match trie { &TrieNode::Empty => {} &TrieNode::Leaf { ref output, .. } => { + writeln!( + code, + "{}// Rule at {}.", + indent, + output.pos.pretty_print_line(&self.typeenv.filenames[..]) + )?; // If this is a leaf node, generate the ExprSequence and return. for (id, inst) in output.insts.iter().enumerate() { let id = InstId(id); self.generate_expr_inst(code, id, inst, indent, ctx)?; + if let &ExprInst::Return { .. } = inst { + returned = true; + break; + } } } @@ -1005,20 +1024,28 @@ impl<'a> Codegen<'a> { { match symbol { &TrieSymbol::EndOfMatch => { - self.generate_body(code, depth + 1, node, &subindent, ctx)?; + returned = self.generate_body(code, depth + 1, node, indent, ctx)?; } &TrieSymbol::Match { ref op } => { let id = InstId(depth); - self.generate_pattern_inst(code, id, op, &subindent, ctx)?; - self.generate_body(code, depth + 1, node, &subindent, ctx)?; - writeln!(code, "{}}}", subindent)?; + let infallible = + self.generate_pattern_inst(code, id, op, indent, ctx)?; + let sub_returned = + self.generate_body(code, depth + 1, node, &subindent, ctx)?; + writeln!(code, "{}}}", indent)?; + if infallible && sub_returned { + returned = true; + break; + } } } } } } - writeln!(code, "{}return None;", indent)?; - Ok(()) + if !returned { + writeln!(code, "{}return None;", indent)?; + } + Ok(returned) } } diff --git a/cranelift/isle/src/ir.rs b/cranelift/isle/src/ir.rs index b1f3057619..33641c4de2 100644 --- a/cranelift/isle/src/ir.rs +++ b/cranelift/isle/src/ir.rs @@ -1,6 +1,7 @@ //! Lowered matching IR. use crate::declare_id; +use crate::lexer::Pos; use crate::sema::*; use std::collections::HashMap; @@ -110,6 +111,8 @@ pub struct ExprSequence { /// Instruction sequence for expression. InstId indexes into this /// sequence for `Value::Expr` values. pub insts: Vec, + /// Position at which the rule producing this sequence was located. + pub pos: Pos, } impl PatternSequence { @@ -197,8 +200,7 @@ impl PatternSequence { // Bind the appropriate variable and recurse. assert!(!vars.contains_key(&var)); vars.insert(var, (None, input.unwrap())); // bind first, so subpat can use it - let root_term = - self.gen_pattern(input, typeenv, termenv, &*subpat, vars); + let root_term = self.gen_pattern(input, typeenv, termenv, &*subpat, vars); vars.get_mut(&var).unwrap().0 = root_term; root_term } @@ -352,6 +354,7 @@ pub fn lower_rule( ) { let mut pattern_seq: PatternSequence = Default::default(); let mut expr_seq: ExprSequence = Default::default(); + expr_seq.pos = termenv.rules[rule.index()].pos; // Lower the pattern, starting from the root input value. let ruledata = &termenv.rules[rule.index()]; diff --git a/cranelift/isle/src/lexer.rs b/cranelift/isle/src/lexer.rs index af53d7313e..5c85f5a730 100644 --- a/cranelift/isle/src/lexer.rs +++ b/cranelift/isle/src/lexer.rs @@ -18,7 +18,7 @@ enum LexerInput<'a> { File { content: String, filename: String }, } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, Hash)] pub struct Pos { pub file: usize, pub offset: usize, diff --git a/cranelift/isle/src/sema.rs b/cranelift/isle/src/sema.rs index b9c3d2eeac..40789ded0d 100644 --- a/cranelift/isle/src/sema.rs +++ b/cranelift/isle/src/sema.rs @@ -113,6 +113,7 @@ pub struct Rule { pub lhs: Pattern, pub rhs: Expr, pub prio: Option, + pub pos: Pos, } #[derive(Clone, Debug, PartialEq, Eq)] @@ -414,6 +415,7 @@ impl TermEnv { for def in &defs.defs { match def { &ast::Def::Rule(ref rule) => { + let pos = rule.pos; let mut bindings = Bindings { next_var: 0, vars: vec![], @@ -434,6 +436,7 @@ impl TermEnv { lhs, rhs, prio: rule.prio, + pos, }); } &ast::Def::Extern(ast::Extern::Constructor {