Skip to content
Snippets Groups Projects
Commit bf0d479a authored by Aaron Councilman's avatar Aaron Councilman
Browse files

Front-end changes for multi-return

parent 902f4dfc
No related branches found
No related tags found
1 merge request!196Multi return
......@@ -118,15 +118,18 @@ impl CodeGenerator<'_> {
param_types.push(solver_inst.lower_type(&mut self.builder.builder, *ty));
}
let return_type =
solver_inst.lower_type(&mut self.builder.builder, func.return_type);
let return_types =
func.return_types
.iter()
.map(|t| solver_inst.lower_type(&mut self.builder.builder, *t))
.collect::<Vec<_>>();
let (func_id, entry) = self
.builder
.create_function(
&name,
param_types,
return_type,
return_types,
func.num_dyn_consts as u32,
func.entry,
)
......@@ -264,10 +267,16 @@ impl CodeGenerator<'_> {
// loop
Some(block_exit)
}
Stmt::ReturnStmt { expr } => {
let (val_ret, block_ret) = self.codegen_expr(expr, types, ssa, cur_block);
Stmt::ReturnStmt { exprs } => {
let mut vals = vec![];
let mut block = cur_block;
for expr in exprs {
let (val_ret, block_ret) = self.codegen_expr(expr, types, ssa, block);
vals.push(val_ret);
block = block_ret;
}
let mut return_node = self.builder.allocate_node();
return_node.build_return(block_ret, val_ret);
return_node.build_return(block, vals);
self.builder.add_node(return_node);
None
}
......@@ -482,6 +491,7 @@ impl CodeGenerator<'_> {
ty_args,
dyn_consts,
args,
num_returns, // number of non-inout returns (which are first)
..
} => {
// We start by lowering the type arguments to TypeIDs
......@@ -541,30 +551,27 @@ impl CodeGenerator<'_> {
// Read each of the "inout values" and perform the SSA update
let has_inouts = !inouts.is_empty();
// TODO: We should omit unit returns, if we do so the + 1 below is not needed
for (idx, var) in inouts.into_iter().enumerate() {
let index = self.builder.builder.create_field_index(idx + 1);
let mut read = self.builder.allocate_node();
let read_id = read.id();
read.build_read(call_id, vec![index].into());
self.builder.add_node(read);
let index = self.builder.builder.create_field_index(num_returns + idx);
let mut proj = self.builder.allocate_node();
let proj_id = proj.id();
proj.build_data_projection(call_id, index);
self.builder.add_node(proj);
ssa.write_variable(var, block, read_id);
ssa.write_variable(var, block, proj_id);
}
// Read the "actual return" value and return it
let result = if !has_inouts {
call_id
} else {
let value_index = self.builder.builder.create_field_index(0);
let mut read = self.builder.allocate_node();
let read_id = read.id();
read.build_read(call_id, vec![value_index].into());
self.builder.add_node(read);
read_id
};
(call_id, block)
}
Expr::CallExtract { call, index, .. } => {
let (call, block) = self.codegen_expr(call, types, ssa, cur_block);
let mut proj = self.builder.allocate_node();
let proj_id = proj.id();
proj.build_data_projection(call, index);
self.builder.add_node(proj);
(result, block)
(proj_id, block)
}
Expr::Intrinsic {
id,
......
......@@ -33,14 +33,14 @@ impl<'a> LabeledBuilder<'a> {
&mut self,
name: &str,
param_types: Vec<TypeID>,
return_type: TypeID,
return_types: Vec<TypeID>,
num_dynamic_constants: u32,
entry: bool,
) -> Result<(FunctionID, NodeID), String> {
let (func, entry) = self.builder.create_function(
name,
param_types,
return_type,
return_types,
num_dynamic_constants,
entry,
)?;
......
......@@ -167,17 +167,17 @@ ConstDecl -> Result<Top, ()>
FuncDecl -> Result<Top, ()>
: PubOption 'fn' 'ID' TypeVars '(' Arguments ')' Stmts
{ Ok(Top::FuncDecl{ span : $span, public : $1?, attr : None, name : span_of_tok($3)?,
ty_vars : $4?, args : $6?, ty : None, body : $8? }) }
ty_vars : $4?, args : $6?, rets: vec![], body : $8? }) }
| 'FUNC_ATTR' PubOption 'fn' 'ID' TypeVars '(' Arguments ')' Stmts
{ Ok(Top::FuncDecl{ span : $span, public : $2?, attr : Some(span_of_tok($1)?),
name : span_of_tok($4)?, ty_vars : $5?, args : $7?, ty : None,
name : span_of_tok($4)?, ty_vars : $5?, args : $7?, rets: vec![],
body : $9? }) }
| PubOption 'fn' 'ID' TypeVars '(' Arguments ')' '->' Type Stmts
| PubOption 'fn' 'ID' TypeVars '(' Arguments ')' '->' Types Stmts
{ Ok(Top::FuncDecl{ span : $span, public : $1?, attr : None, name : span_of_tok($3)?,
ty_vars : $4?, args : $6?, ty : Some($9?), body : $10? }) }
| 'FUNC_ATTR' PubOption 'fn' 'ID' TypeVars '(' Arguments ')' '->' Type Stmts
ty_vars : $4?, args : $6?, rets: $9?, body : $10? }) }
| 'FUNC_ATTR' PubOption 'fn' 'ID' TypeVars '(' Arguments ')' '->' Types Stmts
{ Ok(Top::FuncDecl{ span : $span, public : $2?, attr : Some(span_of_tok($1)?),
name : span_of_tok($4)?, ty_vars : $5?, args : $7?, ty : Some($10?),
name : span_of_tok($4)?, ty_vars : $5?, args : $7?, rets: $10?,
body : $11? }) }
;
Arguments -> Result<Vec<(Option<Span>, VarBind)>, ()>
......@@ -198,6 +198,18 @@ VarBind -> Result<VarBind, ()>
| Pattern ':' Type { Ok(VarBind{ span : $span, pattern : $1?, typ : Some($3?) }) }
;
LetBind -> Result<LetBind, ()>
: VarBind {
let VarBind { span, pattern, typ } = $1?;
Ok(LetBind::Single { span, pattern, typ })
}
| PatternsCommaS ',' Pattern {
let mut pats = $1?;
pats.push($3?);
Ok(LetBind::Multi { span: $span, patterns: pats })
}
;
Pattern -> Result<Pattern, ()>
: '_' { Ok(Pattern::Wildcard { span : $span }) }
| IntLit { let (span, base) = $1?;
......@@ -240,9 +252,9 @@ StructPatterns -> Result<(VecDeque<(Id, Pattern)>, bool), ()>
;
Stmt -> Result<Stmt, ()>
: 'let' VarBind ';'
: 'let' LetBind ';'
{ Ok(Stmt::LetStmt{ span : $span, var : $2?, init : None }) }
| 'let' VarBind '=' Expr ';'
| 'let' LetBind '=' Expr ';'
{ Ok(Stmt::LetStmt{ span : $span, var : $2?, init : Some($4?) }) }
| 'const' VarBind ';'
{ Ok(Stmt::ConstStmt{ span : $span, var : $2?, init : None }) }
......@@ -305,10 +317,8 @@ Stmt -> Result<Stmt, ()>
inclusive: true, step: None, body: Box::new($8?) }) }
| 'while' NonStructExpr Stmts
{ Ok(Stmt::WhileStmt{ span : $span, cond : $2?, body : Box::new($3?) }) }
| 'return' ';'
{ Ok(Stmt::ReturnStmt{ span : $span, expr : None }) }
| 'return' Expr ';'
{ Ok(Stmt::ReturnStmt{ span : $span, expr : Some($2?)}) }
| 'return' Exprs ';'
{ Ok(Stmt::ReturnStmt{ span : $span, vals: $2?}) }
| 'break' ';'
{ Ok(Stmt::BreakStmt{ span : $span }) }
| 'continue' ';'
......@@ -659,6 +669,15 @@ pub struct VarBind { pub span : Span, pub pattern : Pattern, pub typ : Option<Ty
#[derive(Debug)]
pub struct Case { pub span : Span, pub pat : Vec<Pattern>, pub body : Stmt }
// Let bindings are different from other bindings because they can be used to
// destruct multi-return function values, and so can actually contain multiple
// patterns
#[derive(Debug)]
pub enum LetBind {
Single { span: Span, pattern: Pattern, typ: Option<Type> },
Multi { span: Span, patterns: Vec<Pattern> },
}
#[derive(Debug)]
pub enum Top {
Import { span : Span, name : ImportName },
......@@ -666,7 +685,7 @@ pub enum Top {
ConstDecl { span : Span, public : bool, name : Id, ty : Option<Type>, body : Expr },
FuncDecl { span : Span, public : bool, attr : Option<Span>, name : Id, ty_vars : Vec<TypeVar>,
args : Vec<(Option<Span>, VarBind)>, // option is for inout
ty : Option<Type>, body : Stmt },
rets : Vec<Type>, body : Stmt },
ModDecl { span : Span, public : bool, name : Id, body : Vec<Top> },
}
......@@ -688,7 +707,7 @@ pub enum Type {
#[derive(Debug)]
pub enum Stmt {
LetStmt { span : Span, var : VarBind, init : Option<Expr> },
LetStmt { span : Span, var : LetBind, init : Option<Expr> },
ConstStmt { span : Span, var : VarBind, init : Option<Expr> },
AssignStmt { span : Span, lhs : LExpr, assign : AssignOp, assign_span : Span, rhs : Expr },
IfStmt { span : Span, cond : Expr, thn : Box<Stmt>, els : Option<Box<Stmt>> },
......@@ -697,7 +716,7 @@ pub enum Stmt {
ForStmt { span : Span, var : VarBind, init : Expr, bound : Expr,
inclusive: bool, step : Option<(bool, Span, IntBase)>, body : Box<Stmt> },
WhileStmt { span : Span, cond : Expr, body : Box<Stmt> },
ReturnStmt { span : Span, expr : Option<Expr> },
ReturnStmt { span : Span, vals : Vec<Expr> },
BreakStmt { span : Span },
ContinueStmt { span : Span },
BlockStmt { span : Span, body : Vec<Stmt> },
......
This diff is collapsed.
......@@ -45,10 +45,10 @@ impl SSA {
let right_proj = right_builder.id();
// True branch
left_builder.build_projection(if_builder.id(), 1);
left_builder.build_control_projection(if_builder.id(), 1);
// False branch
right_builder.build_projection(if_builder.id(), 0);
right_builder.build_control_projection(if_builder.id(), 0);
builder.add_node(left_builder);
builder.add_node(right_builder);
......
......@@ -204,6 +204,11 @@ enum TypeForm {
kind: parser::Kind,
loc: Location,
},
// The types of call nodes are MultiReturns
MultiReturn {
types: Vec<Type>,
},
}
#[derive(Debug)]
......@@ -279,6 +284,10 @@ impl TypeSolver {
})
}
pub fn new_multi_return(&mut self, types: Vec<Type>) -> Type {
self.create_type(TypeForm::MultiReturn { types })
}
fn create_type(&mut self, typ: TypeForm) -> Type {
let idx = self.types.len();
self.types.push(typ);
......@@ -543,26 +552,13 @@ impl TypeSolver {
}
}
// Note that MultReturn types never unify with anything (even itself), this is
// intentional and makes it so that the only way MultiReturns can be used is to
// destruct them
_ => false,
}
}
/*
pub fn is_tuple(&self, Type { val } : Type) -> bool {
match &self.types[val] {
TypeForm::Tuple(_) => true,
TypeForm::OtherType(t) => self.is_tuple(*t),
_ => false,
}
}
pub fn get_num_fields(&self, Type { val } : Type) -> Option<usize> {
match &self.types[val] {
TypeForm::Tuple(fields) => { Some(fields.len()) },
TypeForm::OtherType(t) => self.get_num_fields(*t),
_ => None,
}
}
*/
// Returns the types of the fields of a tuple
pub fn get_fields(&self, Type { val }: Type) -> Option<&Vec<Type>> {
......@@ -676,26 +672,13 @@ impl TypeSolver {
}
}
/*
pub fn get_constructor_list(&self, Type { val } : Type) -> Option<Vec<usize>> {
match &self.types[val] {
TypeForm::Union { name : _, id : _, constr : _, names } => {
Some(names.keys().map(|i| *i).collect::<Vec<_>>())
},
TypeForm::OtherType(t) => self.get_constructor_list(*t),
_ => None,
}
}
fn is_type_var_num(&self, num : usize, Type { val } : Type) -> bool {
match &self.types[val] {
TypeForm::TypeVar { name : _, index, .. } => *index == num,
TypeForm::OtherType(t) => self.is_type_var_num(num, *t),
_ => false,
}
pub fn get_return_types(&self, Type { val }: Type) -> Option<&Vec<Type>> {
match &self.types[val] {
TypeForm::MultiReturn { types } => Some(types),
TypeForm::OtherType { other, .. } => self.get_return_types(*other),
_ => None,
}
*/
}
pub fn to_string(&self, Type { val }: Type, stringtab: &dyn Fn(usize) -> String) -> String {
match &self.types[val] {
......@@ -724,6 +707,8 @@ impl TypeSolver {
| TypeForm::Struct { name, .. }
| TypeForm::Union { name, .. } => stringtab(*name),
TypeForm::AnyOfKind { kind, .. } => kind.to_string(),
TypeForm::MultiReturn { types } =>
types.iter().map(|t| self.to_string(*t, stringtab)).collect::<Vec<_>>().join(", "),
}
}
......@@ -825,6 +810,9 @@ impl TypeSolver {
Some(Type { val })
}
}
TypeForm::MultiReturn { .. } => {
panic!("Multi-Return types should never be instantiated")
}
}
}
......@@ -969,6 +957,9 @@ impl TypeSolverInst<'_> {
TypeForm::AnyOfKind { .. } => {
panic!("TypeSolverInst only works on solved types which do not have AnyOfKinds")
}
TypeForm::MultiReturn { .. } => {
panic!("MultiReturn types should never be lowered")
}
};
match solution {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment