feat: Remove tuple_index and record_access in favor of faster more direct functions for

accessing an item in a tuple or a field in a record
This commit is contained in:
microproofs
2023-09-27 16:24:16 -04:00
committed by Lucas
parent 1bcc9e8524
commit 47596f0324
30 changed files with 191 additions and 421 deletions

View File

@@ -10,7 +10,7 @@ use indexmap::{IndexMap, IndexSet};
use itertools::Itertools;
use uplc::{
ast::{Constant as UplcConstant, Name, NamedDeBruijn, Program, Term, Type as UplcType},
builder::{CONSTR_FIELDS_EXPOSER, CONSTR_GET_FIELD, CONSTR_INDEX_EXPOSER, EXPECT_ON_LIST},
builder::{CONSTR_FIELDS_EXPOSER, CONSTR_INDEX_EXPOSER, EXPECT_ON_LIST},
builtins::DefaultFunction,
machine::cost_model::ExBudget,
optimize::aiken_optimize_and_intern,
@@ -22,7 +22,7 @@ use crate::{
AssignmentKind, BinOp, Pattern, Span, TypedArg, TypedClause, TypedDataType, TypedFunction,
TypedPattern, TypedValidator, UnOp,
},
builtins::{bool, data, int, void},
builtins::{bool, data, int, list, void},
expr::TypedExpr,
gen_uplc::builder::{
check_replaceable_opaque_type, convert_opaque_type, erase_opaque_type_operations,
@@ -187,10 +187,7 @@ impl<'a> CodeGenerator<'a> {
fn finalize(&mut self, mut term: Term<Name>) -> Program<Name> {
if self.needs_field_access {
term = term
.constr_get_field()
.constr_fields_exposer()
.constr_index_exposer();
term = term.constr_fields_exposer().constr_index_exposer();
}
// TODO: Once SOP is implemented, new version is 1.1.0
@@ -550,7 +547,38 @@ impl<'a> CodeGenerator<'a> {
if check_replaceable_opaque_type(&record.tipo(), &self.data_types) {
self.build(record)
} else {
AirTree::record_access(*index, tipo.clone(), self.build(record))
self.needs_field_access = true;
let function_name = format!("__access_index_{}", *index);
if self.code_gen_functions.get(&function_name).is_none() {
let mut body = AirTree::local_var("__fields", list(data()));
for _ in 0..*index {
body = AirTree::builtin(
DefaultFunction::TailList,
list(data()),
vec![body],
)
}
body = AirTree::builtin(DefaultFunction::HeadList, data(), vec![body]);
self.code_gen_functions.insert(
function_name.clone(),
CodeGenFunction::Function {
body,
params: vec!["__fields".to_string()],
},
);
}
let list_of_fields = AirTree::call(
AirTree::local_var(CONSTR_FIELDS_EXPOSER, void()),
list(data()),
vec![self.build(record)],
);
AirTree::index_access(function_name, tipo.clone(), list_of_fields)
}
}
@@ -622,8 +650,38 @@ impl<'a> CodeGenerator<'a> {
tipo.clone(),
),
TypedExpr::TupleIndex { index, tuple, .. } => {
AirTree::tuple_index(*index, tuple.tipo(), self.build(tuple))
TypedExpr::TupleIndex {
index, tuple, tipo, ..
} => {
if tuple.tipo().is_2_tuple() {
AirTree::pair_index(*index, tipo.clone(), self.build(tuple))
} else {
let function_name = format!("__access_index_{}", *index);
if self.code_gen_functions.get(&function_name).is_none() {
let mut body = AirTree::local_var("__fields", list(data()));
for _ in 0..*index {
body = AirTree::builtin(
DefaultFunction::TailList,
list(data()),
vec![body],
)
}
body = AirTree::builtin(DefaultFunction::HeadList, data(), vec![body]);
self.code_gen_functions.insert(
function_name.clone(),
CodeGenFunction::Function {
body,
params: vec!["__fields".to_string()],
},
);
}
AirTree::index_access(function_name, tipo.clone(), self.build(tuple))
}
}
TypedExpr::ErrorTerm { tipo, .. } => AirTree::error(tipo.clone()),
@@ -3876,10 +3934,7 @@ impl<'a> CodeGenerator<'a> {
) {
let mut term = self.uplc_code_gen(air_vec.clone());
term = term
.constr_get_field()
.constr_fields_exposer()
.constr_index_exposer();
term = term.constr_fields_exposer().constr_index_exposer();
let mut program: Program<Name> = Program {
version: (1, 0, 0),
@@ -4660,18 +4715,6 @@ impl<'a> CodeGenerator<'a> {
arg_stack.push(term);
}
Air::RecordAccess { record_index, tipo } => {
self.needs_field_access = true;
let constr = arg_stack.pop().unwrap();
let mut term = Term::var(CONSTR_GET_FIELD)
.apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(constr))
.apply(Term::integer(record_index.into()));
term = builder::convert_data_to_type(term, &tipo);
arg_stack.push(term);
}
Air::FieldsExpose {
indices,
check_last_item,
@@ -4931,33 +4974,6 @@ impl<'a> CodeGenerator<'a> {
arg_stack.push(term);
}
Air::TupleIndex { tipo, tuple_index } => {
let mut term = arg_stack.pop().unwrap();
if matches!(tipo.get_uplc_type(), UplcType::Pair(_, _)) {
if tuple_index == 0 {
term = builder::convert_data_to_type(
Term::fst_pair().apply(term),
&tipo.get_inner_types()[0],
);
} else {
term = builder::convert_data_to_type(
Term::snd_pair().apply(term),
&tipo.get_inner_types()[1],
);
}
} else {
self.needs_field_access = true;
term = builder::convert_data_to_type(
Term::var(CONSTR_GET_FIELD)
.apply(term)
.apply(Term::integer(tuple_index.into())),
&tipo.get_inner_types()[tuple_index],
);
}
arg_stack.push(term);
}
Air::TupleAccessor {
tipo,
names,

View File

@@ -147,10 +147,6 @@ pub enum Air {
tipo: Rc<Type>,
},
// Field Access
RecordAccess {
record_index: u64,
tipo: Rc<Type>,
},
FieldsExpose {
indices: Vec<(usize, String, Rc<Type>)>,
check_last_item: bool,
@@ -173,10 +169,6 @@ pub enum Air {
tipo: Rc<Type>,
check_last_item: bool,
},
TupleIndex {
tipo: Rc<Type>,
tuple_index: usize,
},
// Misc.
ErrorTerm {
tipo: Rc<Type>,

View File

@@ -315,18 +315,6 @@ pub enum AirExpression {
record: Box<AirTree>,
args: Vec<AirTree>,
},
// Field Access
RecordAccess {
field_index: u64,
tipo: Rc<Type>,
record: Box<AirTree>,
},
// Tuple Access
TupleIndex {
tipo: Rc<Type>,
tuple_index: usize,
tuple: Box<AirTree>,
},
// Misc.
ErrorTerm {
tipo: Rc<Type>,
@@ -684,12 +672,33 @@ impl AirTree {
args,
})
}
pub fn record_access(field_index: u64, tipo: Rc<Type>, record: AirTree) -> AirTree {
AirTree::Expression(AirExpression::RecordAccess {
field_index,
tipo,
record: record.into(),
})
pub fn index_access(function_name: String, tipo: Rc<Type>, list_of_fields: AirTree) -> AirTree {
AirTree::cast_from_data(
AirTree::call(
AirTree::var(
ValueConstructor::public(
Type::Fn {
args: vec![list(data())],
ret: data(),
}
.into(),
ValueConstructorVariant::ModuleFn {
name: function_name.clone(),
field_map: None,
module: "".to_string(),
arity: 1,
location: Span::empty(),
builtin: None,
},
),
function_name,
"",
),
data(),
vec![list_of_fields],
),
tipo.clone(),
)
}
pub fn fields_expose(
@@ -754,12 +763,19 @@ impl AirTree {
hoisted_over: None,
}
}
pub fn tuple_index(tuple_index: usize, tipo: Rc<Type>, tuple: AirTree) -> AirTree {
AirTree::Expression(AirExpression::TupleIndex {
tipo,
tuple_index,
tuple: tuple.into(),
})
pub fn pair_index(index: usize, tipo: Rc<Type>, tuple: AirTree) -> AirTree {
AirTree::cast_from_data(
AirTree::builtin(
if index == 0 {
DefaultFunction::FstPair
} else {
DefaultFunction::SndPair
},
data(),
vec![tuple],
),
tipo.clone(),
)
}
pub fn error(tipo: Rc<Type>) -> AirTree {
AirTree::Expression(AirExpression::ErrorTerm { tipo })
@@ -1241,28 +1257,6 @@ impl AirTree {
arg.create_air_vec(air_vec);
}
}
AirExpression::RecordAccess {
field_index,
tipo,
record,
} => {
air_vec.push(Air::RecordAccess {
record_index: *field_index,
tipo: tipo.clone(),
});
record.create_air_vec(air_vec);
}
AirExpression::TupleIndex {
tipo,
tuple_index,
tuple,
} => {
air_vec.push(Air::TupleIndex {
tipo: tipo.clone(),
tuple_index: *tuple_index,
});
tuple.create_air_vec(air_vec);
}
AirExpression::ErrorTerm { tipo } => {
air_vec.push(Air::ErrorTerm { tipo: tipo.clone() })
}
@@ -1300,8 +1294,6 @@ impl AirTree {
| AirExpression::If { tipo, .. }
| AirExpression::Constr { tipo, .. }
| AirExpression::RecordUpdate { tipo, .. }
| AirExpression::RecordAccess { tipo, .. }
| AirExpression::TupleIndex { tipo, .. }
| AirExpression::ErrorTerm { tipo }
| AirExpression::Trace { tipo, .. } => tipo.clone(),
AirExpression::Void => void(),
@@ -1351,9 +1343,7 @@ impl AirTree {
| AirExpression::CastFromData { tipo, .. }
| AirExpression::CastToData { tipo, .. }
| AirExpression::If { tipo, .. }
| AirExpression::RecordAccess { tipo, .. }
| AirExpression::Constr { tipo, .. }
| AirExpression::TupleIndex { tipo, .. }
| AirExpression::ErrorTerm { tipo }
| AirExpression::Trace { tipo, .. } => vec![tipo],
AirExpression::Var { constructor, .. } => {
@@ -1836,24 +1826,6 @@ impl AirTree {
);
}
}
AirExpression::RecordAccess { record, .. } => {
record.do_traverse_tree_with(
tree_path,
current_depth + 1,
index_count.next_number(),
with,
apply_with_func_last,
);
}
AirExpression::TupleIndex { tuple, .. } => {
tuple.do_traverse_tree_with(
tree_path,
current_depth + 1,
index_count.next_number(),
with,
apply_with_func_last,
);
}
AirExpression::Trace { msg, then, .. } => {
msg.do_traverse_tree_with(
tree_path,
@@ -2170,21 +2142,6 @@ impl AirTree {
item.do_find_air_tree_node(tree_path_iter)
}
AirExpression::RecordAccess { record, .. } => {
if *index == 0 {
record.as_mut().do_find_air_tree_node(tree_path_iter)
} else {
panic!("Tree Path index outside tree children nodes")
}
}
AirExpression::TupleIndex { tuple, .. } => {
if *index == 0 {
tuple.as_mut().do_find_air_tree_node(tree_path_iter)
} else {
panic!("Tree Path index outside tree children nodes")
}
}
AirExpression::Trace { msg, then, .. } => {
if *index == 0 {
msg.as_mut().do_find_air_tree_node(tree_path_iter)