In this PR I implement an optimization pass for static argument transformation.
Definitions with recursive calls that involve static arguments will now be wrapped in another function, abstracting arguments along the way.
For example, in pseudocode:
def foo(a, b, c) =
if (a == b) println(c)
else foo(a - 2, b - 1, c)
foo(4, 2, 0)
becomes:
def foo(a_fresh, b_fresh, c) =
def foo_worker(a, b) =
if (a == b) println(c)
else foo_worker(a - 2, b - 1)
foo_worker(a_fresh, b_fresh)
foo(4, 2, 0)
For now this works great for transforming static vargs, but has some bugs left for static capture/block arguments. Mutual recursion is also not supported for now.
We can see the optimization in the following example:
def fold[A, B](list: List[A], end: B) { f: (B, A) => B }: B = {
list match {
case Nil() => end
case Cons(elem, rest) => f(fold(rest, end) { f }, elem)
}
}
def sum(list: List[Int]): Int =
fold(list, 0) { (a, b) => a + b }
def main() = println(sum([1, 2, 3]))
Previously the resulting core was:
def fold2239[A2234, B2235](list2236: List910[A2234], end2237: B2235){f2238} =
def b_k_23733524() =
end2237;
def b_k_23803525(elem2243: A2234, rest2244: List910[A2234]) =
val v_r_23773526: B2235 = fold2239[A2234, B2235](rest2244, end2237, f2238);
f2238(v_r_23773526, elem2243)
list2236 match {
case Nil1114 { () =>
b_k_23733524()
}
case Cons1115 { (v_y_23812384: A2234, v_y_23822383: List910[A2234]) =>
b_k_23803525(v_y_23812384, v_y_23822383)
}
};
def sum2241(list2240: List910[BoxedInt296]) =
val v_coe_39623971: BoxedInt296 = fold2239[BoxedInt296, BoxedInt296](list2240, boxInt298(0), { (v_coe_39633968: BoxedInt296, v_coe_39643969: BoxedInt296) =>
def b_tmp_39663967(a2245: Int398, b2246: Int398) =
infixAdd93(a2245, b2246)
val v_coe_39653970: Int398 = b_tmp_39663967(unboxInt300(v_coe_39633968), unboxInt300(v_coe_39643969));
boxInt298(v_coe_39653970)
});
unboxInt300(v_coe_39623971);
def main2242() =
let v_r_23893523 = run {sum2241(make List910[BoxedInt296] Cons1115(boxInt298(1), make List910[BoxedInt296] Cons1115(boxInt298(2), make List910[BoxedInt296] Cons1115(boxInt298(3), make List910[BoxedInt296] Nil1114()))))}
Now:
def fold2239[A2234, B2235](list3972: List910[A2234], end2237: B2235){f2238} =
def fold_worker3973[A2234, B2235](list2236: List910[A2234]) =
def b_k_23733524() =
end2237;
def b_k_23803525(elem2243: A2234, rest2244: List910[A2234]) =
val v_r_23773526: B2235 = fold_worker3973[A2234, B2235](rest2244);
f2238(v_r_23773526, elem2243)
list2236 match {
case Nil1114 { () =>
b_k_23733524()
}
case Cons1115 { (v_y_23812384: A2234, v_y_23822383: List910[A2234]) =>
b_k_23803525(v_y_23812384, v_y_23822383)
}
}
fold_worker3973[A2234, B2235](list3972);
def sum2241(list2240: List910[BoxedInt296]) =
val v_coe_39623971: BoxedInt296 = fold2239[BoxedInt296, BoxedInt296](list2240, boxInt298(0), { (v_coe_39633968: BoxedInt296, v_coe_39643969: BoxedInt296) =>
def b_tmp_39663967(a2245: Int398, b2246: Int398) =
infixAdd93(a2245, b2246)
val v_coe_39653970: Int398 = b_tmp_39663967(unboxInt300(v_coe_39633968), unboxInt300(v_coe_39643969));
boxInt298(v_coe_39653970)
});
unboxInt300(v_coe_39623971);
def main2242() =
let v_r_23893523 = run {sum2241(make List910[BoxedInt296] Cons1115(boxInt298(1), make List910[BoxedInt296] Cons1115(boxInt298(2), make List910[BoxedInt296] Cons1115(boxInt298(3), make List910[BoxedInt296] Nil1114()))))}
In this PR I implement an optimization pass for static argument transformation.
Definitions with recursive calls that involve static arguments will now be wrapped in another function, abstracting arguments along the way.
For example, in pseudocode:
becomes:
For now this works great for transforming static vargs, but has some bugs left for static capture/block arguments. Mutual recursion is also not supported for now.
We can see the optimization in the following example:
Previously the resulting core was:
Now: