FunctionSpecializer: skip specializing recursive functions

This avoids potential pathological behaviour, like in Ackermann function.
This commit is contained in:
hrkrshnn 2021-03-25 13:19:23 +01:00
parent bd5e47dc55
commit 0100f48e05
11 changed files with 61 additions and 3230 deletions

View File

@ -19,6 +19,7 @@
#include <libyul/optimiser/FunctionSpecializer.h>
#include <libyul/optimiser/ASTCopier.h>
#include <libyul/optimiser/CallGraphGenerator.h>
#include <libyul/optimiser/NameCollector.h>
#include <libyul/optimiser/NameDispenser.h>
@ -53,7 +54,11 @@ void FunctionSpecializer::operator()(FunctionCall& _f)
{
ASTModifier::operator()(_f);
if (m_dialect.builtin(_f.functionName.name))
// TODO When backtracking is implemented, the restriction of recursive functions can be lifted.
if (
m_dialect.builtin(_f.functionName.name) ||
m_recursiveFunctions.count(_f.functionName.name)
)
return;
LiteralArguments arguments = specializableArguments(_f);
@ -108,7 +113,7 @@ FunctionDefinition FunctionSpecializer::specialize(
newFunction.body.statements =
move(missingVariableDeclarations) + move(newFunction.body.statements);
// Only take those indices where optional in arguments in nullopt
// Only take those indices that cannot be specialized, i.e., whose value is `nullopt`.
newFunction.parameters =
util::filter(
newFunction.parameters,
@ -122,8 +127,11 @@ FunctionDefinition FunctionSpecializer::specialize(
void FunctionSpecializer::run(OptimiserStepContext& _context, Block& _ast)
{
// Finds all function calls that can be replaced.
FunctionSpecializer f{_context.dispenser, _context.dialect};
FunctionSpecializer f{
CallGraphGenerator::callGraph(_ast).recursiveFunctions(),
_context.dispenser,
_context.dialect
};
f(_ast);
iterateReplacing(_ast.statements, [&](Statement& _s) -> optional<vector<Statement>>

View File

@ -66,7 +66,12 @@ public:
void operator()(FunctionCall& _f) override;
private:
explicit FunctionSpecializer(NameDispenser& _nameDispenser, Dialect const& _dialect):
explicit FunctionSpecializer(
std::set<YulString> _recursiveFunctions,
NameDispenser& _nameDispenser,
Dialect const& _dialect
):
m_recursiveFunctions(std::move(_recursiveFunctions)),
m_nameDispenser(_nameDispenser),
m_dialect(_dialect)
{}
@ -98,6 +103,8 @@ private:
/// A mapping between the old function name and a pair of new function name and its arguments.
/// Note that at least one of the argument will have a literal value.
std::map<YulString, std::vector<std::pair<YulString, LiteralArguments>>> m_oldToNewMap;
/// We skip specializing recursive functions. Need backtracking to properly deal with them.
std::set<YulString> const m_recursiveFunctions;
NameDispenser& m_nameDispenser;
Dialect const& m_dialect;

View File

@ -25,4 +25,4 @@ contract CopyTest {
// compileViaYul: also
// ----
// run() -> 2, 23, 42
// gas irOptimized: 112957
// gas irOptimized: 110109

View File

@ -33,4 +33,4 @@ contract C {
// compileViaYul: true
// ----
// f() -> 0, 0, 0
// gas irOptimized: 124761
// gas irOptimized: 124791

View File

@ -24,511 +24,9 @@
//
// {
// {
// sstore(0, 5)
// sstore(1, add(2, 5))
// let _1 := not(0)
// let _2 := A_985(A_4878(A_4886(add(5, _1))))
// let ret := 0
// switch _2
// case 0 { ret := 5 }
// default {
// let _3 := A_985(add(_2, _1))
// let ret_1 := 0
// switch _3
// case 0 { ret_1 := 3 }
// default {
// ret_1 := A_2511(A_2505(add(_3, _1)))
// }
// ret := ret_1
// }
// sstore(2, ret)
// }
// function A_20862() -> ret
// {
// switch 1
// case 0 { ret := add(ret, 1) }
// default {
// let _1 := add(1, not(0))
// let ret_1 := 0
// switch _1
// case 0 { ret_1 := 2 }
// default {
// ret_1 := A(add(1, not(1)), A_294(_1))
// }
// ret := ret_1
// }
// }
// function A_20864() -> ret
// {
// switch 2
// case 0 { ret := add(ret, 1) }
// default {
// let _1 := add(2, not(0))
// let ret_1 := 0
// switch _1
// case 0 { ret_1 := 2 }
// default {
// ret_1 := A(add(2, not(1)), A_294(_1))
// }
// ret := ret_1
// }
// }
// function A_20874() -> ret
// {
// switch 1
// case 0 { ret := add(ret, 1) }
// default {
// let _1 := add(1, not(0))
// let ret_1 := 0
// switch _1
// case 0 { ret_1 := 2 }
// default {
// ret_1 := A(add(1, not(1)), A_294(_1))
// }
// ret := ret_1
// }
// }
// function A_294(m) -> ret
// {
// switch m
// case 0 { ret := add(ret, 1) }
// default {
// let _1 := add(m, not(0))
// let ret_1 := 0
// switch _1
// case 0 { ret_1 := 2 }
// default {
// ret_1 := A(add(m, not(1)), A_294(_1))
// }
// ret := ret_1
// }
// }
// function A_985(n) -> ret
// {
// switch n
// case 0 { ret := 5 }
// default {
// let ret_1 := 0
// switch add(n, not(0))
// case 0 { ret_1 := 5 }
// default {
// let ret_2 := 0
// switch add(n, not(1))
// case 0 { ret_2 := add(2, 3) }
// default {
// let ret_3 := 0
// switch add(n, not(2))
// case 0 {
// ret_3 := add(A_13949(A_13949(A_20856())), 1)
// }
// default {
// let ret_4 := 0
// switch add(n, not(3))
// case 0 { ret_4 := add(A_20857(), 1) }
// default {
// let ret_5 := 0
// switch add(n, not(4))
// case 0 { ret_5 := A_20858() }
// default {
// ret_5 := A_13953(A_13952(add(n, not(5))))
// }
// ret_4 := A_11648(ret_5)
// }
// ret_3 := A_9730(ret_4)
// }
// ret_2 := A_7274(ret_3)
// }
// ret_1 := A_4886(ret_2)
// }
// ret := A_2505(ret_1)
// }
// }
// function A_2505(n) -> ret
// {
// switch n
// case 0 { ret := 3 }
// default {
// ret := A_4878(A_4886(add(n, not(0))))
// }
// }
// function A_2511(n) -> ret
// {
// switch n
// case 0 { ret := 2 }
// default {
// ret := add(A_4878(add(n, not(0))), 1)
// }
// }
// function A_4878(n) -> ret
// {
// switch n
// case 0 { ret := 2 }
// default {
// ret := add(A_7272(add(n, not(0))), 1)
// }
// }
// function A_4886(n) -> ret
// {
// switch n
// case 0 { ret := 3 }
// default {
// ret := A_7272(A_7274(add(n, not(0))))
// }
// }
// function A_7272(n) -> ret
// {
// switch n
// case 0 { ret := 2 }
// default {
// ret := add(A_9725(add(n, not(0))), 1)
// }
// }
// function A_7274(n) -> ret
// {
// switch n
// case 0 { ret := 3 }
// default {
// ret := A_9725(A_9730(add(n, not(0))))
// }
// }
// function A_9725(n) -> ret
// {
// switch n
// case 0 { ret := 2 }
// default {
// ret := add(A_11646(add(n, not(0))), 1)
// }
// }
// function A_9730(n) -> ret
// {
// switch n
// case 0 { ret := 3 }
// default {
// ret := A_11646(A_11648(add(n, not(0))))
// }
// }
// function A_11646(n) -> ret
// {
// switch n
// case 0 { ret := 2 }
// default {
// ret := add(A_13951(add(n, not(0))), 1)
// }
// }
// function A_11648(n) -> ret
// {
// switch n
// case 0 { ret := 3 }
// default {
// ret := A_13951(A_13953(add(n, not(0))))
// }
// }
// function A_13949(n) -> ret
// { ret := add(n, 1) }
// function A_20857() -> ret
// {
// switch 2
// case 0 { ret := 2 }
// default {
// ret := add(A_16299(add(2, not(0))), 1)
// }
// }
// function A_20858() -> ret
// {
// switch 3
// case 0 { ret := 2 }
// default {
// ret := add(A_16299(add(3, not(0))), 1)
// }
// }
// function A_13951(n) -> ret
// {
// switch n
// case 0 { ret := 2 }
// default {
// ret := add(A_16299(add(n, not(0))), 1)
// }
// }
// function A_13952(n) -> ret
// {
// switch n
// case 0 { ret := A_20861() }
// default {
// let ret_1 := 0
// switch add(n, not(0))
// case 0 {
// ret_1 := A_18381(A_20863(A_20862()))
// }
// default {
// let ret_2 := 0
// switch add(n, not(1))
// case 0 { ret_2 := A_20865(A_20864()) }
// default {
// ret_2 := A_20867(A_20866(add(n, not(2))))
// }
// ret_1 := A_18383(ret_2)
// }
// ret := A_16304(ret_1)
// }
// }
// function A_13953(n) -> ret
// {
// switch n
// case 0 { ret := 3 }
// default {
// ret := A_16299(A_16304(add(n, not(0))))
// }
// }
// function A_20856() -> ret
// {
// switch ret
// case 0 { ret := 2 }
// default {
// ret := add(A_18381(add(0, not(0))), 1)
// }
// }
// function A_20861() -> ret
// {
// switch 3
// case 0 { ret := 2 }
// default {
// ret := add(A_18381(add(3, not(0))), 1)
// }
// }
// function A_16299(n) -> ret
// {
// switch n
// case 0 { ret := 2 }
// default {
// ret := add(A_18381(add(n, not(0))), 1)
// }
// }
// function A_16304(n) -> ret
// {
// switch n
// case 0 { ret := 3 }
// default {
// ret := A_18381(A_18383(add(n, not(0))))
// }
// }
// function A_18381(n) -> ret
// {
// switch n
// case 0 { ret := 2 }
// default {
// ret := A_20869(A_20868(add(n, not(0))))
// }
// }
// function A_18383(n) -> ret
// {
// switch n
// case 0 { ret := A_20875(A_20874()) }
// default {
// ret := A_20877(A_20876(add(n, not(0))))
// }
// }
// function A_20863(n) -> ret
// {
// switch ret
// case 0 { ret := add(n, 1) }
// default {
// switch n
// case 0 {
// let _1 := add(0, not(0))
// let ret_1 := 0
// switch _1
// case 0 { ret_1 := 2 }
// default {
// ret_1 := A(add(0, not(1)), A_294(_1))
// }
// ret := ret_1
// }
// default {
// let _2 := not(0)
// ret := A(add(0, _2), A(0, add(n, _2)))
// }
// }
// }
// function A_20865(n) -> ret
// {
// let m := 1
// switch m
// case 0 { ret := add(n, m) }
// default {
// switch n
// case 0 {
// let _1 := add(m, not(0))
// let ret_1 := 0
// switch _1
// case 0 { ret_1 := 2 }
// default {
// ret_1 := A(add(m, not(1)), A_294(_1))
// }
// ret := ret_1
// }
// default {
// let _2 := not(0)
// ret := A(add(m, _2), A(m, add(n, _2)))
// }
// }
// }
// function A_20866(n) -> ret
// {
// switch 3
// case 0 { ret := add(n, 1) }
// default {
// switch n
// case 0 {
// let _1 := add(3, not(0))
// let ret_1 := 0
// switch _1
// case 0 { ret_1 := 2 }
// default {
// ret_1 := A(add(3, not(1)), A_294(_1))
// }
// ret := ret_1
// }
// default {
// let _2 := not(0)
// ret := A(add(3, _2), A(3, add(n, _2)))
// }
// }
// }
// function A_20867(n) -> ret
// {
// let m := 2
// switch m
// case 0 { ret := add(n, 1) }
// default {
// switch n
// case 0 {
// let _1 := add(m, not(0))
// let ret_1 := 0
// switch _1
// case 0 { ret_1 := m }
// default {
// ret_1 := A(add(m, not(1)), A_294(_1))
// }
// ret := ret_1
// }
// default {
// let _2 := not(0)
// ret := A(add(m, _2), A(m, add(n, _2)))
// }
// }
// }
// function A_20868(n) -> ret
// {
// let m := 1
// switch m
// case 0 { ret := add(n, m) }
// default {
// switch n
// case 0 {
// let _1 := add(m, not(0))
// let ret_1 := 0
// switch _1
// case 0 { ret_1 := 2 }
// default {
// ret_1 := A(add(m, not(1)), A_294(_1))
// }
// ret := ret_1
// }
// default {
// let _2 := not(0)
// ret := A(add(m, _2), A(m, add(n, _2)))
// }
// }
// }
// function A_20869(n) -> ret
// {
// switch ret
// case 0 { ret := add(n, 1) }
// default {
// switch n
// case 0 {
// let _1 := add(0, not(0))
// let ret_1 := 0
// switch _1
// case 0 { ret_1 := 2 }
// default {
// ret_1 := A(add(0, not(1)), A_294(_1))
// }
// ret := ret_1
// }
// default {
// let _2 := not(0)
// ret := A(add(0, _2), A(0, add(n, _2)))
// }
// }
// }
// function A_20875(n) -> ret
// {
// switch ret
// case 0 { ret := add(n, 1) }
// default {
// switch n
// case 0 {
// let _1 := add(0, not(0))
// let ret_1 := 0
// switch _1
// case 0 { ret_1 := 2 }
// default {
// ret_1 := A(add(0, not(1)), A_294(_1))
// }
// ret := ret_1
// }
// default {
// let _2 := not(0)
// ret := A(add(0, _2), A(0, add(n, _2)))
// }
// }
// }
// function A_20876(n) -> ret
// {
// let m := 2
// switch m
// case 0 { ret := add(n, 1) }
// default {
// switch n
// case 0 {
// let _1 := add(m, not(0))
// let ret_1 := 0
// switch _1
// case 0 { ret_1 := m }
// default {
// ret_1 := A(add(m, not(1)), A_294(_1))
// }
// ret := ret_1
// }
// default {
// let _2 := not(0)
// ret := A(add(m, _2), A(m, add(n, _2)))
// }
// }
// }
// function A_20877(n) -> ret
// {
// let m := 1
// switch m
// case 0 { ret := add(n, m) }
// default {
// switch n
// case 0 {
// let _1 := add(m, not(0))
// let ret_1 := 0
// switch _1
// case 0 { ret_1 := 2 }
// default {
// ret_1 := A(add(m, not(1)), A_294(_1))
// }
// ret := ret_1
// }
// default {
// let _2 := not(0)
// ret := A(add(m, _2), A(m, add(n, _2)))
// }
// }
// sstore(0, A(2, 1))
// sstore(1, A(2, 2))
// sstore(2, A(4, 2))
// }
// function A(m, n) -> ret
// {
@ -536,19 +34,10 @@
// case 0 { ret := add(n, 1) }
// default {
// switch n
// case 0 {
// let _1 := add(m, not(0))
// let ret_1 := 0
// switch _1
// case 0 { ret_1 := 2 }
// default {
// ret_1 := A(add(m, not(1)), A_294(_1))
// }
// ret := ret_1
// }
// case 0 { ret := A(add(m, not(0)), 1) }
// default {
// let _2 := not(0)
// ret := A(add(m, _2), A(m, add(n, _2)))
// let _1 := not(0)
// ret := A(add(m, _1), A(m, add(n, _1)))
// }
// }
// }

View File

@ -25,15 +25,23 @@
//
// {
// {
// sstore(0, 1)
// sstore(1, 1)
// sstore(2, 2)
// sstore(3, 3)
// sstore(4, 5)
// sstore(5, 8)
// sstore(7, 13)
// sstore(8, 21)
// sstore(9, 34)
// sstore(10, 55)
// sstore(0, fib(0))
// sstore(1, fib(2))
// sstore(2, fib(3))
// sstore(3, fib(4))
// sstore(4, fib(5))
// sstore(5, fib(6))
// sstore(7, fib(7))
// sstore(8, fib(8))
// sstore(9, fib(9))
// sstore(10, fib(10))
// }
// function fib(i) -> y
// {
// y := 1
// if gt(i, 2)
// {
// y := add(fib(add(i, not(0))), fib(add(i, not(1))))
// }
// }
// }

View File

@ -17,51 +17,14 @@
//
// {
// {
// pop(mstore_1011())
// let y := 8
// let _1 := calldataload(y)
// sstore(y, _1)
// sstore(y, _1)
// sstore(y, _1)
// sstore(y, _1)
// sstore(y, _1)
// sstore(y, _1)
// sstore(y, _1)
// sstore(y, _1)
// sstore(y, _1)
// sstore(y, _1)
// sstore(y, _1)
// nonmstore_1012()
// let _2 := calldataload(2)
// let _3 := 10
// sstore(_3, _2)
// sstore(_3, _2)
// sstore(_3, _2)
// sstore(_3, _2)
// sstore(_3, _2)
// sstore(_3, _2)
// sstore(_3, _2)
// sstore(_3, _2)
// sstore(_3, _2)
// sstore(_3, _2)
// sstore(_3, _2)
// }
// function nonmstore_1012()
// {
// pop(mstore_(7))
// nonmstore(70)
// sstore(10, calldataload(2))
// }
// function nonmstore(x)
// {
// nonmstore(x)
// sstore(10, calldataload(2))
// }
// function mstore_1011() -> y
// {
// pop(mstore_(7))
// y := 8
// sstore(y, calldataload(y))
// }
// function mstore_(x) -> y
// {
// pop(mstore_(x))

View File

@ -16,160 +16,14 @@
//
// {
// {
// let linkersymbol_1 := 0
// let _1 := calldataload(linkersymbol_1)
// if _1
// {
// let linkersymbol_2 := linkersymbol_1
// if _1
// {
// let linkersymbol_3 := linkersymbol_1
// if _1
// {
// let linkersymbol_4 := linkersymbol_1
// if _1
// {
// let linkersymbol_5 := linkersymbol_1
// if _1
// {
// linkersymbol_5 := datasize_1042()
// }
// sstore(linkersymbol_5, calldataload(linkersymbol_5))
// linkersymbol_4 := linkersymbol_5
// }
// sstore(linkersymbol_4, calldataload(linkersymbol_4))
// linkersymbol_3 := linkersymbol_4
// }
// sstore(linkersymbol_3, calldataload(linkersymbol_3))
// linkersymbol_2 := linkersymbol_3
// }
// sstore(linkersymbol_2, calldataload(linkersymbol_2))
// linkersymbol_1 := linkersymbol_2
// }
// sstore(linkersymbol_1, calldataload(linkersymbol_1))
// let z := 0
// let _2 := calldataload(1)
// if _2
// {
// let z_1 := z
// if _2
// {
// let z_2 := z
// if _2
// {
// let z_3 := z
// if _2 { z_3 := g_780() }
// sstore(z_3, calldataload(10))
// z_2 := z_3
// }
// sstore(z_2, calldataload(10))
// z_1 := z_2
// }
// sstore(z_1, calldataload(10))
// z := z_1
// }
// sstore(z, calldataload(10))
// sstore(linkersymbol_1, z)
// }
// function g_780() -> z
// {
// let _1 := calldataload(1)
// if _1
// {
// let z_1 := z
// if _1
// {
// let z_2 := z
// if _1
// {
// let z_3 := z
// if _1
// {
// let z_4 := z
// if _1
// {
// let z_5 := z
// if _1
// {
// let z_6 := z
// if _1 { z_6 := g_3303() }
// sstore(z_6, calldataload(10))
// z_5 := z_6
// }
// sstore(z_5, calldataload(10))
// z_4 := z_5
// }
// sstore(z_4, calldataload(10))
// z_3 := z_4
// }
// sstore(z_3, calldataload(10))
// z_2 := z_3
// }
// sstore(z_2, calldataload(10))
// z_1 := z_2
// }
// sstore(z_1, calldataload(10))
// z := z_1
// }
// sstore(z, calldataload(10))
// }
// function g_3303() -> z
// {
// if calldataload(1) { z := g(9) }
// sstore(z, calldataload(add(9, 1)))
// let dataoffset_ := datasize_(7)
// sstore(dataoffset_, g(9))
// }
// function g(x) -> z
// {
// if calldataload(1) { z := g(x) }
// sstore(z, calldataload(add(x, 1)))
// }
// function datasize_1042() -> linkersymbol_1
// {
// let _1 := calldataload(linkersymbol_1)
// if _1
// {
// let linkersymbol_2 := linkersymbol_1
// if _1
// {
// let linkersymbol_3 := linkersymbol_1
// if _1
// {
// let linkersymbol_4 := linkersymbol_1
// if _1
// {
// let linkersymbol_5 := linkersymbol_1
// if _1
// {
// let linkersymbol_6 := linkersymbol_1
// if _1
// {
// linkersymbol_6 := datasize_3305()
// }
// sstore(linkersymbol_6, calldataload(linkersymbol_6))
// linkersymbol_5 := linkersymbol_6
// }
// sstore(linkersymbol_5, calldataload(linkersymbol_5))
// linkersymbol_4 := linkersymbol_5
// }
// sstore(linkersymbol_4, calldataload(linkersymbol_4))
// linkersymbol_3 := linkersymbol_4
// }
// sstore(linkersymbol_3, calldataload(linkersymbol_3))
// linkersymbol_2 := linkersymbol_3
// }
// sstore(linkersymbol_2, calldataload(linkersymbol_2))
// linkersymbol_1 := linkersymbol_2
// }
// sstore(linkersymbol_1, calldataload(linkersymbol_1))
// }
// function datasize_3305() -> linkersymbol_1
// {
// if calldataload(linkersymbol_1)
// {
// linkersymbol_1 := datasize_(7)
// }
// sstore(linkersymbol_1, calldataload(linkersymbol_1))
// }
// function datasize_(x) -> linkersymbol_
// {
// if calldataload(linkersymbol_) { linkersymbol_ := datasize_(x) }

View File

@ -38,69 +38,21 @@
//
// {
// {
// let _1 := gt(not(gcd_1042()), 1)
// let _2 := gcd_1043()
// let _1 := gt(not(gcd(10, 15)), 1)
// let _2 := gcd(10, 15)
// let _3 := not(0)
// let _4 := lt(or(1, add(gcd_1044(), _3)), 1)
// let _5 := gcd_1045()
// let _6 := gcd_1046()
// pop(keccak256(gcd_1048(), or(gt(not(gcd_1047()), 1), 1)))
// let _4 := lt(or(1, add(gcd(10, 15), _3)), 1)
// let _5 := gcd(10, 15)
// let _6 := gcd(10, 15)
// pop(keccak256(gcd(10, 15), or(gt(not(gcd(10, 15)), 1), 1)))
// mstore(lt(or(gt(1, or(or(gt(or(or(or(gt(or(gt(_3, _6), 1), _5), _4), _2), 1), 1), _1), 1)), 1), 1), 1)
// sstore(not(gcd_1049()), 1)
// sstore(not(gcd(10, 15)), 1)
// sstore(0, 0)
// sstore(2, 1)
// extcodecopy(1, msize(), 1, 1)
// sstore(0, 0)
// sstore(3, 1)
// }
// function gcd_1042() -> out
// {
// switch 5
// case 0 { out := 10 }
// default { out := gcd(5, mod(10, 5)) }
// }
// function gcd_1043() -> out
// {
// switch 5
// case 0 { out := 10 }
// default { out := gcd(5, mod(10, 5)) }
// }
// function gcd_1044() -> out
// {
// switch 5
// case 0 { out := 10 }
// default { out := gcd(5, mod(10, 5)) }
// }
// function gcd_1045() -> out
// {
// switch 5
// case 0 { out := 10 }
// default { out := gcd(5, mod(10, 5)) }
// }
// function gcd_1046() -> out
// {
// switch 5
// case 0 { out := 10 }
// default { out := gcd(5, mod(10, 5)) }
// }
// function gcd_1047() -> out
// {
// switch 5
// case 0 { out := 10 }
// default { out := gcd(5, mod(10, 5)) }
// }
// function gcd_1048() -> out
// {
// switch 5
// case 0 { out := 10 }
// default { out := gcd(5, mod(10, 5)) }
// }
// function gcd_1049() -> out
// {
// switch 5
// case 0 { out := 10 }
// default { out := gcd(5, mod(10, 5)) }
// }
// function gcd(_a, _b) -> out
// {
// switch _b

View File

@ -13,16 +13,7 @@
// step: functionSpecializer
//
// {
// sstore(0, fib_1())
// function fib_1() -> y_2
// {
// let i_3 := 8
// y_2 := 1
// if gt(i_3, 2)
// {
// y_2 := add(fib(sub(i_3, 1)), fib(sub(i_3, 2)))
// }
// }
// sstore(0, fib(8))
// function fib(i) -> y
// {
// y := 1