Making progress on using interning in gen_uplc
Done interning for uniqueness. Now to fix the static optimization Remove unused function Fixing issues. Have a few remaining tests
This commit is contained in:
parent
0905146140
commit
7c52094b15
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,7 @@
|
||||||
use super::{
|
use super::{
|
||||||
air::ExpectLevel,
|
air::ExpectLevel,
|
||||||
tree::{AirMsg, AirTree, TreePath},
|
interner::AirInterner,
|
||||||
|
tree::{AirMsg, AirTree},
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
|
@ -17,7 +18,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
use itertools::{Itertools, Position};
|
use itertools::{Itertools, Position};
|
||||||
use std::{collections::HashMap, ops::Deref, rc::Rc};
|
use std::{ops::Deref, rc::Rc};
|
||||||
use uplc::{
|
use uplc::{
|
||||||
ast::{Constant as UplcConstant, Name, Term, Type as UplcType},
|
ast::{Constant as UplcConstant, Name, Term, Type as UplcType},
|
||||||
builder::{CONSTR_FIELDS_EXPOSER, CONSTR_INDEX_EXPOSER},
|
builder::{CONSTR_FIELDS_EXPOSER, CONSTR_INDEX_EXPOSER},
|
||||||
|
@ -41,6 +42,7 @@ pub const CONSTR_NOT_EMPTY: &str = "__CONSTR_NOT_EMPTY";
|
||||||
pub const INCORRECT_BOOLEAN: &str = "__INCORRECT_BOOLEAN";
|
pub const INCORRECT_BOOLEAN: &str = "__INCORRECT_BOOLEAN";
|
||||||
pub const INCORRECT_CONSTR: &str = "__INCORRECT_CONSTR";
|
pub const INCORRECT_CONSTR: &str = "__INCORRECT_CONSTR";
|
||||||
pub const CONSTR_INDEX_MISMATCH: &str = "__CONSTR_INDEX_MISMATCH";
|
pub const CONSTR_INDEX_MISMATCH: &str = "__CONSTR_INDEX_MISMATCH";
|
||||||
|
pub const DISCARDED: &str = "_";
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum CodeGenFunction {
|
pub enum CodeGenFunction {
|
||||||
|
@ -421,21 +423,17 @@ pub fn is_recursive_function_call<'a>(
|
||||||
|
|
||||||
pub fn identify_recursive_static_params(
|
pub fn identify_recursive_static_params(
|
||||||
air_tree: &mut AirTree,
|
air_tree: &mut AirTree,
|
||||||
tree_path: &TreePath,
|
|
||||||
func_params: &[String],
|
func_params: &[String],
|
||||||
func_key: &(FunctionAccessKey, String),
|
func_key: &(FunctionAccessKey, String),
|
||||||
function_calls_and_usage: &mut (usize, usize),
|
function_calls_and_usage: &mut (usize, usize),
|
||||||
shadowed_parameters: &mut HashMap<String, TreePath>,
|
|
||||||
potential_recursive_statics: &mut Vec<String>,
|
potential_recursive_statics: &mut Vec<String>,
|
||||||
) {
|
) {
|
||||||
let variant = &func_key.1;
|
let variant = &func_key.1;
|
||||||
let func_key = &func_key.0;
|
let func_key = &func_key.0;
|
||||||
// Find whether any of the potential recursive statics get shadowed (because even if we pass in the same referenced name, it might not be static)
|
|
||||||
for introduced_variable in find_introduced_variables(air_tree) {
|
// Now all variables can't be shadowed at this stage due to interning
|
||||||
if potential_recursive_statics.contains(&introduced_variable) {
|
|
||||||
shadowed_parameters.insert(introduced_variable, tree_path.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Otherwise, if this is a recursive call site, disqualify anything that is different (or the same, but shadowed)
|
// Otherwise, if this is a recursive call site, disqualify anything that is different (or the same, but shadowed)
|
||||||
if let (true, Some(args)) = is_recursive_function_call(air_tree, func_key, variant) {
|
if let (true, Some(args)) = is_recursive_function_call(air_tree, func_key, variant) {
|
||||||
for (param, arg) in func_params.iter().zip(args) {
|
for (param, arg) in func_params.iter().zip(args) {
|
||||||
|
@ -446,18 +444,9 @@ pub fn identify_recursive_static_params(
|
||||||
// Check if we pass something different in this recursive call site
|
// Check if we pass something different in this recursive call site
|
||||||
// by different, we mean
|
// by different, we mean
|
||||||
// - a variable that is bound to a different name
|
// - a variable that is bound to a different name
|
||||||
// - a variable with the same name, but that was shadowed in an ancestor scope
|
|
||||||
// - any other type of expression
|
// - any other type of expression
|
||||||
let param_is_different = match arg {
|
let param_is_different = match arg {
|
||||||
AirTree::Var { name, .. } => {
|
AirTree::Var { name, .. } => name != param || false,
|
||||||
// "shadowed in an ancestor scope" means "the definition scope is a prefix of our scope"
|
|
||||||
name != param
|
|
||||||
|| if let Some(p) = shadowed_parameters.get(param) {
|
|
||||||
p.common_ancestor(tree_path) == *p
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => true,
|
_ => true,
|
||||||
};
|
};
|
||||||
// If so, then we disqualify this parameter from being a recursive static parameter
|
// If so, then we disqualify this parameter from being a recursive static parameter
|
||||||
|
@ -499,17 +488,14 @@ pub fn modify_self_calls(
|
||||||
// identify which parameters are recursively nonstatic (i.e. get modified before the self-call)
|
// identify which parameters are recursively nonstatic (i.e. get modified before the self-call)
|
||||||
// TODO: this would be a lot simpler if each `Var`, `Let`, function argument, etc. had a unique identifier
|
// TODO: this would be a lot simpler if each `Var`, `Let`, function argument, etc. had a unique identifier
|
||||||
// rather than just a name; this would let us track if the Var passed to itself was the same value as the method argument
|
// rather than just a name; this would let us track if the Var passed to itself was the same value as the method argument
|
||||||
let mut shadowed_parameters: HashMap<String, TreePath> = HashMap::new();
|
|
||||||
let mut calls_and_var_usage = (0, 0);
|
let mut calls_and_var_usage = (0, 0);
|
||||||
body.traverse_tree_with(
|
body.traverse_tree_with(
|
||||||
&mut |air_tree: &mut AirTree, tree_path| {
|
&mut |air_tree: &mut AirTree, _tree_path| {
|
||||||
identify_recursive_static_params(
|
identify_recursive_static_params(
|
||||||
air_tree,
|
air_tree,
|
||||||
tree_path,
|
|
||||||
func_params,
|
func_params,
|
||||||
&(func_key.clone(), variant.clone()),
|
&(func_key.clone(), variant.clone()),
|
||||||
&mut calls_and_var_usage,
|
&mut calls_and_var_usage,
|
||||||
&mut shadowed_parameters,
|
|
||||||
&mut potential_recursive_statics,
|
&mut potential_recursive_statics,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -1661,19 +1647,26 @@ pub fn get_list_elements_len_and_tail(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cast_validator_args(term: Term<Name>, arguments: &[TypedArg]) -> Term<Name> {
|
pub fn cast_validator_args(
|
||||||
|
term: Term<Name>,
|
||||||
|
arguments: &[TypedArg],
|
||||||
|
interner: &AirInterner,
|
||||||
|
) -> Term<Name> {
|
||||||
let mut term = term;
|
let mut term = term;
|
||||||
for arg in arguments.iter().rev() {
|
for arg in arguments.iter().rev() {
|
||||||
|
let name = arg
|
||||||
|
.arg_name
|
||||||
|
.get_variable_name()
|
||||||
|
.map(|arg| interner.lookup_interned(&arg.to_string()))
|
||||||
|
.unwrap_or_else(|| "_".to_string());
|
||||||
|
|
||||||
if !matches!(arg.tipo.get_uplc_type(), Some(UplcType::Data) | None) {
|
if !matches!(arg.tipo.get_uplc_type(), Some(UplcType::Data) | None) {
|
||||||
term = term
|
term = term
|
||||||
.lambda(arg.arg_name.get_variable_name().unwrap_or("_"))
|
.lambda(&name)
|
||||||
.apply(known_data_to_type(
|
.apply(known_data_to_type(Term::var(&name), &arg.tipo));
|
||||||
Term::var(arg.arg_name.get_variable_name().unwrap_or("_")),
|
|
||||||
&arg.tipo,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
term = term.lambda(arg.arg_name.get_variable_name().unwrap_or("_"))
|
term = term.lambda(name)
|
||||||
}
|
}
|
||||||
term
|
term
|
||||||
}
|
}
|
||||||
|
@ -1751,3 +1744,89 @@ pub fn get_line_columns_by_span(
|
||||||
.line_and_column_number(span.start)
|
.line_and_column_number(span.start)
|
||||||
.expect("Out of bounds span")
|
.expect("Out of bounds span")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn introduce_pattern(interner: &mut AirInterner, pattern: &TypedPattern) {
|
||||||
|
match pattern {
|
||||||
|
Pattern::Int { .. } | Pattern::ByteArray { .. } | Pattern::Discard { .. } => (),
|
||||||
|
|
||||||
|
Pattern::Var { name, .. } => {
|
||||||
|
interner.intern(name.clone());
|
||||||
|
}
|
||||||
|
Pattern::Assign { name, pattern, .. } => {
|
||||||
|
interner.intern(name.clone());
|
||||||
|
introduce_pattern(interner, pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pattern::List { elements, tail, .. } => {
|
||||||
|
elements.iter().for_each(|element| {
|
||||||
|
introduce_pattern(interner, element);
|
||||||
|
});
|
||||||
|
|
||||||
|
tail.iter().for_each(|tail| {
|
||||||
|
introduce_pattern(interner, tail);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Pattern::Constructor {
|
||||||
|
arguments: elems, ..
|
||||||
|
} => {
|
||||||
|
elems.iter().for_each(|element| {
|
||||||
|
introduce_pattern(interner, &element.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Pattern::Tuple { elems, .. } => {
|
||||||
|
elems.iter().for_each(|element| {
|
||||||
|
introduce_pattern(interner, element);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Pattern::Pair { fst, snd, .. } => {
|
||||||
|
introduce_pattern(interner, fst);
|
||||||
|
introduce_pattern(interner, snd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_pattern(interner: &mut AirInterner, pattern: &TypedPattern) {
|
||||||
|
match pattern {
|
||||||
|
Pattern::Int { .. } | Pattern::ByteArray { .. } | Pattern::Discard { .. } => (),
|
||||||
|
|
||||||
|
Pattern::Var { name, .. } => {
|
||||||
|
interner.pop_text(name.clone());
|
||||||
|
}
|
||||||
|
Pattern::Assign { name, pattern, .. } => {
|
||||||
|
interner.pop_text(name.clone());
|
||||||
|
pop_pattern(interner, pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pattern::List { elements, tail, .. } => {
|
||||||
|
elements.iter().for_each(|element| {
|
||||||
|
pop_pattern(interner, element);
|
||||||
|
});
|
||||||
|
|
||||||
|
tail.iter().for_each(|tail| {
|
||||||
|
pop_pattern(interner, tail);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Pattern::Constructor {
|
||||||
|
arguments: elems, ..
|
||||||
|
} => {
|
||||||
|
elems.iter().for_each(|element| {
|
||||||
|
pop_pattern(interner, &element.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Pattern::Tuple { elems, .. } => {
|
||||||
|
elems.iter().for_each(|element| {
|
||||||
|
pop_pattern(interner, element);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Pattern::Pair { fst, snd, .. } => {
|
||||||
|
pop_pattern(interner, fst);
|
||||||
|
pop_pattern(interner, snd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn introduce_name(interner: &mut AirInterner, name: &String) -> String {
|
||||||
|
interner.intern(name.clone());
|
||||||
|
|
||||||
|
interner.lookup_interned(&name)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use vec1::{vec1, Vec1};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AirInterner {
|
||||||
|
identifiers: HashMap<String, Vec1<usize>>,
|
||||||
|
current: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AirInterner {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interner that uses previous uniques to prevent future unique collisions
|
||||||
|
/// when performing optimizations
|
||||||
|
impl AirInterner {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
identifiers: HashMap::new(),
|
||||||
|
current: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn intern(&mut self, text: String) {
|
||||||
|
if let Some(u) = self.identifiers.get_mut(&text) {
|
||||||
|
u.push(self.current);
|
||||||
|
|
||||||
|
self.current += 1;
|
||||||
|
} else {
|
||||||
|
self.identifiers.insert(text, vec1!(self.current));
|
||||||
|
|
||||||
|
self.current += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_text(&mut self, text: String) {
|
||||||
|
if let Some(mut u) = self.identifiers.remove(&text) {
|
||||||
|
if u.len() != 1 {
|
||||||
|
u.pop().unwrap();
|
||||||
|
self.identifiers.insert(text, u);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable!("Looking up a missing text: {}", text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lookup_interned(&self, text: &String) -> String {
|
||||||
|
if let Some(u) = self.identifiers.get(text) {
|
||||||
|
format!("{}_id_{}", text, *u.last())
|
||||||
|
} else {
|
||||||
|
unreachable!("Looking up a missing text: {}", text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue