First pass update erasure IR

This commit is contained in:
Ayaz Hafiz 2023-07-02 12:38:09 -05:00
parent 7ea85e44d2
commit dc56a0ffef
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
4 changed files with 128 additions and 151 deletions

View file

@ -2119,9 +2119,9 @@ impl<'a> Expr<'a> {
}; };
let callee = symbol_to_doc(alloc, *callee, pretty); let callee = symbol_to_doc(alloc, *callee, pretty);
alloc alloc
.text("ErasedMake { value:") .text("ErasedMake { value: ")
.append(value) .append(value)
.append(", callee:") .append(", callee: ")
.append(callee) .append(callee)
.append(" }") .append(" }")
} }
@ -4091,7 +4091,7 @@ impl<'a> ProcLayout<'a> {
arguments arguments
} else { } else {
let mut extended_args = Vec::with_capacity_in(arguments.len(), arena); let mut extended_args = Vec::with_capacity_in(arguments.len(), arena);
extended_args.extend(arguments.iter().chain(&[Layout::OPAQUE_PTR]).copied()); extended_args.extend(arguments.iter().chain(&[Layout::ERASED]).copied());
extended_args.into_bump_slice() extended_args.into_bump_slice()
}; };

View file

@ -4,30 +4,26 @@ use roc_types::subs::Variable;
use crate::{ use crate::{
borrow::Ownership, borrow::Ownership,
layout::{ErasedIndex, FunctionPointer, InLayout, LambdaName, Layout, LayoutCache, LayoutRepr}, layout::{FunctionPointer, InLayout, LambdaName, Layout, LayoutCache, LayoutRepr},
}; };
use super::{ use super::{
with_hole, BranchInfo, Call, CallType, CapturedSymbols, Env, Expr, JoinPointId, Param, Procs, with_hole, BranchInfo, Call, CallType, CapturedSymbols, Env, ErasedField, Expr, JoinPointId,
Stmt, UpdateModeId, Param, Procs, Stmt, UpdateModeId,
}; };
const ERASED_FUNCTION_FIELD_LAYOUTS: &[InLayout] =
&[Layout::OPAQUE_PTR, Layout::OPAQUE_PTR, Layout::OPAQUE_PTR];
fn index_erased_function<'a>( fn index_erased_function<'a>(
arena: &'a Bump, arena: &'a Bump,
assign_to: Symbol, assign_to: Symbol,
erased_function: Symbol, erased_function: Symbol,
index: ErasedIndex, field: ErasedField,
) -> impl FnOnce(Stmt<'a>) -> Stmt<'a> { ) -> impl FnOnce(Stmt<'a>) -> Stmt<'a> {
move |rest| { move |rest| {
Stmt::Let( Stmt::Let(
assign_to, assign_to,
Expr::StructAtIndex { Expr::ErasedLoad {
index: index as _, symbol: erased_function,
structure: erased_function, field,
field_layouts: ERASED_FUNCTION_FIELD_LAYOUTS,
}, },
Layout::OPAQUE_PTR, Layout::OPAQUE_PTR,
arena.alloc(rest), arena.alloc(rest),
@ -153,30 +149,30 @@ pub fn call_erased_function<'a>(
let join_point_id = JoinPointId(env.unique_symbol()); let join_point_id = JoinPointId(env.unique_symbol());
// f_value = f.value // f_value = ErasedLoad(f, .value)
let f_value = env.unique_symbol(); let f_value = env.unique_symbol();
let let_f_value = index_erased_function(arena, f_value, f, ErasedIndex::Value); let let_f_value = index_erased_function(arena, f_value, f, ErasedField::Value);
// f_callee = f.callee // f_callee = ErasedLoad(f, .callee)
let f_callee = env.unique_symbol(); let f_callee = env.unique_symbol();
let let_f_callee = index_erased_function(arena, f_callee, f, ErasedIndex::Callee); let let_f_callee = index_erased_function(arena, f_callee, f, ErasedField::Callee);
let mut build_closure_data_branch = |env: &mut Env, pass_closure| { let mut build_closure_data_branch = |env: &mut Env, pass_closure| {
// f_callee = cast(f_callee, (..params) -> ret); // f_callee = Cast(f_callee, (..params) -> ret);
// result = f_callee ..args // result = f_callee ..args
// jump join result // jump join result
let (f_args, function_argument_symbols) = if pass_closure { let (f_args, function_argument_symbols) = if pass_closure {
// f_args = ...args, f.value // f_args = ...args, f
// function_argument_symbols = ...args, f.value // function_argument_symbols = ...args, f.value
let f_args = { let f_args = {
let mut args = AVec::with_capacity_in(f_args.len() + 1, arena); let mut args = AVec::with_capacity_in(f_args.len() + 1, arena);
args.extend(f_args.iter().chain(&[Layout::OPAQUE_PTR]).copied()); args.extend(f_args.iter().chain(&[Layout::ERASED]).copied());
args.into_bump_slice() args.into_bump_slice()
}; };
let function_argument_symbols = { let function_argument_symbols = {
let mut args = AVec::with_capacity_in(function_argument_symbols.len() + 1, arena); let mut args = AVec::with_capacity_in(function_argument_symbols.len() + 1, arena);
args.extend(function_argument_symbols.iter().chain(&[f_value])); args.extend(function_argument_symbols.iter().chain(&[f]));
args.into_bump_slice() args.into_bump_slice()
}; };
(f_args, function_argument_symbols) (f_args, function_argument_symbols)
@ -239,9 +235,9 @@ pub fn call_erased_function<'a>(
}; };
let remainder = let remainder =
// f_value = f.value // f_value = ErasedLoad(f, .value)
let_f_value( let_f_value(
// f_callee = f.callee // f_callee = ErasedLoad(f, .callee)
let_f_callee( let_f_callee(
// //
call_and_jump_on_value, call_and_jump_on_value,
@ -302,33 +298,27 @@ pub fn build_erased_function<'a>(
assigned: Symbol, assigned: Symbol,
hole: &'a Stmt<'a>, hole: &'a Stmt<'a>,
) -> Stmt<'a> { ) -> Stmt<'a> {
let value = env.unique_symbol();
let callee = env.unique_symbol();
let refcounter = env.unique_symbol();
// assigned = Expr::Struct({ value, callee, refcounter })
// hole <assigned>
let result = Stmt::Let(
assigned,
Expr::Struct(env.arena.alloc([value, callee, refcounter])),
Layout::ERASED,
hole,
);
// refcounter = TODO
// <hole>
let result = Stmt::Let(
refcounter,
Expr::NullPointer,
Layout::OPAQUE_PTR,
env.arena.alloc(result),
);
let ResolvedErasedLambda { let ResolvedErasedLambda {
captures, captures,
lambda_name, lambda_name,
} = resolved_lambda; } = resolved_lambda;
let value = match captures {
None => None,
Some(_) => Some(env.unique_symbol()),
};
let callee = env.unique_symbol();
// assigned = Expr::ErasedMake({ value, callee })
// hole <assigned>
let result = Stmt::Let(
assigned,
Expr::ErasedMake { value, callee },
Layout::ERASED,
hole,
);
// callee = Expr::FunctionPointer(f) // callee = Expr::FunctionPointer(f)
let result = Stmt::Let( let result = Stmt::Let(
callee, callee,
@ -339,16 +329,7 @@ pub fn build_erased_function<'a>(
// value = Expr::Box({s}) // value = Expr::Box({s})
match captures { match captures {
None => { None => result,
// value = nullptr
// <hole>
Stmt::Let(
value,
Expr::NullPointer,
Layout::OPAQUE_PTR,
env.arena.alloc(result),
)
}
Some(ResolvedErasedCaptures { layouts, symbols }) => { Some(ResolvedErasedCaptures { layouts, symbols }) => {
// captures = {...captures} // captures = {...captures}
// captures = Box(captures) // captures = Box(captures)
@ -364,7 +345,7 @@ pub fn build_erased_function<'a>(
layout_cache.put_in_direct_no_semantic(LayoutRepr::Boxed(stack_captures_layout)); layout_cache.put_in_direct_no_semantic(LayoutRepr::Boxed(stack_captures_layout));
let result = Stmt::Let( let result = Stmt::Let(
value, value.unwrap(),
Expr::Call(Call { Expr::Call(Call {
call_type: CallType::LowLevel { call_type: CallType::LowLevel {
op: LowLevel::PtrCast, op: LowLevel::PtrCast,
@ -473,6 +454,7 @@ pub fn unpack_closure_data<'a>(
captures: &[(Symbol, Variable)], captures: &[(Symbol, Variable)],
mut hole: Stmt<'a>, mut hole: Stmt<'a>,
) -> Stmt<'a> { ) -> Stmt<'a> {
let loaded_captures = env.unique_symbol();
let heap_captures = env.unique_symbol(); let heap_captures = env.unique_symbol();
let stack_captures = env.unique_symbol(); let stack_captures = env.unique_symbol();
@ -525,5 +507,12 @@ pub fn unpack_closure_data<'a>(
env.arena.alloc(hole), env.arena.alloc(hole),
); );
hole let let_loaded_captures = index_erased_function(
env.arena,
loaded_captures,
captures_symbol,
ErasedField::Value,
);
let_loaded_captures(hole)
} }

View file

@ -1413,7 +1413,7 @@ impl<'a> ClosureDataKind<'a> {
pub fn data_layout(&self) -> InLayout<'a> { pub fn data_layout(&self) -> InLayout<'a> {
match self { match self {
Self::LambdaSet(lambda_set) => lambda_set.full_layout, Self::LambdaSet(lambda_set) => lambda_set.full_layout,
Self::Erased => Layout::OPAQUE_PTR, Self::Erased => Layout::ERASED,
} }
} }
} }
@ -2603,14 +2603,6 @@ impl<'a> Layout<'a> {
} }
} }
/// Index into an [Erased layout][Layout::ERASED].
#[repr(u8)]
pub(crate) enum ErasedIndex {
Value = 0,
Callee = 1,
RefCounter = 2,
}
impl<'a> LayoutRepr<'a> { impl<'a> LayoutRepr<'a> {
pub const UNIT: Self = LayoutRepr::struct_(&[]); pub const UNIT: Self = LayoutRepr::struct_(&[]);
pub const BOOL: Self = LayoutRepr::Builtin(Builtin::Bool); pub const BOOL: Self = LayoutRepr::Builtin(Builtin::Bool);

View file

@ -13,101 +13,97 @@ main = (f "") {}
# ^^^^ {} -?-> Str # ^^^^ {} -?-> Str
# -emit:mono # -emit:mono
procedure : `#UserApp.3` Str procedure Bool.2 ():
procedure = `#UserApp.3` (`#UserApp.40`: {}): let Bool.23 : Int1 = true;
let `#UserApp.41` : Str = ""; ret Bool.23;
ret `#UserApp.41`;
procedure : `#UserApp.4` Str procedure Test.1 (Test.2):
procedure = `#UserApp.4` (`#UserApp.29`: {}, `#Attr.#arg_closure`: Boxed([])): let Test.38 : Int1 = CallByName Bool.2;
let `#UserApp.31` : Boxed({Str}) = lowlevel PtrCast `#Attr.#arg_closure`; if Test.38 then
let `#UserApp.32` : {Str} = Unbox `#UserApp.31`; dec Test.2;
joinpoint `#Derived_gen.IdentId(0)`: let Test.44 : {} = Struct {};
let `#UserApp.s` : Str = StructAtIndex 0 `#UserApp.32`; let Test.45 : Boxed({}) = Box Test.44;
ret `#UserApp.s`; let Test.42 : Boxed([]) = lowlevel PtrCast Test.45;
let Test.43 : Boxed([]) = FunctionPointer Test.3;
dec Test.43;
let Test.39 : ?Erased = ErasedMake { value: Test.42, callee: Test.43 };
ret Test.39;
else
let Test.36 : {Str} = Struct {Test.2};
let Test.37 : Boxed({Str}) = Box Test.36;
let Test.34 : Boxed([]) = lowlevel PtrCast Test.37;
let Test.35 : Boxed([]) = FunctionPointer Test.4;
dec Test.35;
let Test.28 : ?Erased = ErasedMake { value: Test.34, callee: Test.35 };
ret Test.28;
procedure Test.3 (Test.40):
let Test.41 : Str = "";
ret Test.41;
procedure Test.4 (Test.29, #Attr.12):
inc #Attr.12;
let Test.31 : Boxed([]) = ErasedLoad #Attr.12 .Value;
dec Test.31;
let Test.32 : Boxed({Str}) = lowlevel PtrCast #Attr.12;
let Test.33 : {Str} = Unbox Test.32;
joinpoint #Derived_gen.0:
let Test.2 : Str = StructAtIndex 0 Test.33;
ret Test.2;
in in
let `#Derived_gen.IdentId(1)` : Int1 = lowlevel RefCountIsUnique `#UserApp.31`; let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.32;
if `#Derived_gen.IdentId(1)` then if #Derived_gen.1 then
decref `#UserApp.31`; free Test.32;
jump `#Derived_gen.IdentId(0)`; jump #Derived_gen.0;
else else
inc `#UserApp.32`; inc Test.33;
decref `#UserApp.31`; decref Test.32;
jump `#Derived_gen.IdentId(0)`; jump #Derived_gen.0;
procedure : `#UserApp.f` {Boxed([]), Boxed([]), Boxed([])} procedure Test.0 ():
procedure = `#UserApp.f` (`#UserApp.s`: Str): let Test.6 : {} = Struct {};
let `#UserApp.38` : Int1 = CallByName `Bool.true`; let Test.17 : Str = "";
if `#UserApp.38` then let Test.46 : Boxed([]) = FunctionPointer Test.1;
dec `#UserApp.s`; dec Test.46;
let `#UserApp.45` : {} = Struct {}; let Test.18 : ?Erased = ErasedMake { value: <null>, callee: Test.46 };
let `#UserApp.46` : Boxed({}) = Box `#UserApp.45`; joinpoint Test.19 Test.7:
let `#UserApp.42` : Boxed([]) = lowlevel PtrCast `#UserApp.46`; joinpoint Test.8 Test.5:
let `#UserApp.43` : Boxed([]) = FunctionPointer `#UserApp.3`; ret Test.5;
let `#UserApp.44` : Boxed([]) = NullPointer;
let `#UserApp.39` : {Boxed([]), Boxed([]), Boxed([])} = Struct {`#UserApp.42`, `#UserApp.43`, `#UserApp.44`};
ret `#UserApp.39`;
else
let `#UserApp.36` : {Str} = Struct {`#UserApp.s`};
let `#UserApp.37` : Boxed({Str}) = Box `#UserApp.36`;
let `#UserApp.33` : Boxed([]) = lowlevel PtrCast `#UserApp.37`;
let `#UserApp.34` : Boxed([]) = FunctionPointer `#UserApp.4`;
let `#UserApp.35` : Boxed([]) = NullPointer;
let `#UserApp.28` : {Boxed([]), Boxed([]), Boxed([])} = Struct {`#UserApp.33`, `#UserApp.34`, `#UserApp.35`};
ret `#UserApp.28`;
procedure : `Bool.true` Int1
procedure = `Bool.true` ():
let `Bool.23` : Int1 = true;
ret `Bool.23`;
procedure : `#UserApp.main` Str
procedure = `#UserApp.main` ():
let `#UserApp.6` : {} = Struct {};
let `#UserApp.17` : Str = "";
let `#UserApp.47` : Boxed([]) = NullPointer;
let `#UserApp.48` : Boxed([]) = FunctionPointer `#UserApp.f`;
let `#UserApp.49` : Boxed([]) = NullPointer;
let `#UserApp.18` : {Boxed([]), Boxed([]), Boxed([])} = Struct {`#UserApp.47`, `#UserApp.48`, `#UserApp.49`};
joinpoint `#UserApp.19` `#UserApp.7`:
joinpoint `#UserApp.8` `#UserApp.5`:
ret `#UserApp.5`;
in in
let `#UserApp.9` : Boxed([]) = StructAtIndex 0 `#UserApp.7`; let Test.9 : Boxed([]) = ErasedLoad Test.7 .Value;
let `#UserApp.10` : Boxed([]) = StructAtIndex 1 `#UserApp.7`; let Test.10 : Boxed([]) = ErasedLoad Test.7 .Callee;
let `#Derived_gen.IdentId(4)` : Boxed([]) = StructAtIndex 2 `#UserApp.7`; let Test.12 : Boxed([]) = NullPointer;
dec `#Derived_gen.IdentId(4)`; let Test.11 : Int1 = lowlevel Eq Test.9 Test.12;
let `#UserApp.12` : Boxed([]) = NullPointer; dec Test.12;
let `#UserApp.11` : Int1 = lowlevel Eq `#UserApp.9` `#UserApp.12`; dec Test.9;
dec `#UserApp.12`; switch Test.11:
switch `#UserApp.11`:
case 0: case 0:
dec `#UserApp.9`; let Test.13 : FunPtr({} -> Str) = lowlevel PtrCast Test.10;
let `#UserApp.13` : FunPtr({} -> Str) = lowlevel PtrCast `#UserApp.10`; let Test.14 : Str = CallByPtr Test.13 Test.6;
let `#UserApp.14` : Str = CallByPtr `#UserApp.13` `#UserApp.6`; jump Test.8 Test.14;
jump `#UserApp.8` `#UserApp.14`;
default: default:
let `#UserApp.15` : FunPtr({}, Boxed([]) -> Str) = lowlevel PtrCast `#UserApp.10`; inc Test.7;
let `#UserApp.16` : Str = CallByPtr `#UserApp.15` `#UserApp.6` `#UserApp.9`; let Test.15 : FunPtr({}, ?Erased -> Str) = lowlevel PtrCast Test.10;
jump `#UserApp.8` `#UserApp.16`; let Test.16 : Str = CallByPtr Test.15 Test.6 Test.7;
jump Test.8 Test.16;
in in
let `#UserApp.20` : Boxed([]) = StructAtIndex 0 `#UserApp.18`; let Test.20 : Boxed([]) = ErasedLoad Test.18 .Value;
let `#UserApp.21` : Boxed([]) = StructAtIndex 1 `#UserApp.18`; let Test.21 : Boxed([]) = ErasedLoad Test.18 .Callee;
dec `#UserApp.49`; let Test.23 : Boxed([]) = NullPointer;
let `#UserApp.23` : Boxed([]) = NullPointer; let Test.22 : Int1 = lowlevel Eq Test.20 Test.23;
let `#UserApp.22` : Int1 = lowlevel Eq `#UserApp.20` `#UserApp.23`; dec Test.20;
dec `#UserApp.23`; dec Test.23;
switch `#UserApp.22`: switch Test.22:
case 0: case 0:
dec `#UserApp.20`; let Test.24 : FunPtr(Str -> ?Erased) = lowlevel PtrCast Test.21;
let `#UserApp.24` : FunPtr(Str -> {Boxed([]), Boxed([]), Boxed([])}) = lowlevel PtrCast `#UserApp.21`; let Test.25 : ?Erased = CallByPtr Test.24 Test.17;
let `#UserApp.25` : {Boxed([]), Boxed([]), Boxed([])} = CallByPtr `#UserApp.24` `#UserApp.17`; jump Test.19 Test.25;
jump `#UserApp.19` `#UserApp.25`;
default: default:
let `#UserApp.26` : FunPtr(Str, Boxed([]) -> {Boxed([]), Boxed([]), Boxed([])}) = lowlevel PtrCast `#UserApp.21`; inc Test.18;
let `#UserApp.27` : {Boxed([]), Boxed([]), Boxed([])} = CallByPtr `#UserApp.26` `#UserApp.17` `#UserApp.20`; let Test.26 : FunPtr(Str, ?Erased -> ?Erased) = lowlevel PtrCast Test.21;
jump `#UserApp.19` `#UserApp.27`; let Test.27 : ?Erased = CallByPtr Test.26 Test.17 Test.18;
jump Test.19 Test.27;