# [erlang-questions] scope of variables

Richard Carlsson <>
Mon Sep 25 23:59:11 CEST 2006

```Vlad Dumitrescu wrote:
> If it will work as advertised, there are a lot of cool things that
> will become posible to do. Like for example optimizations. If I have
> to do a lot of math:pow(X, 72) with different X, I could write a
> powN/2 macro that produces an optimized powN/1 for any particular N
> (72 in this case). That would be
>  Pow72 = fun(X) ->
>    X2 = X*X,
>    X4 = X2*X2,
>    X8 = X4*X4,
>    X16 = X8*X8,
>    X32 = X16*X16,
>    X64 = X32*X32,
>   X64+X8.
> Maybe not so spectacular, but a similar example wouuld be to produce
> custom regexp-matching funs, that might be much more efficient than
> the current ones. I didn't take that example because it's not as
> simple to produce one by hand :-)

Ok, it took a while before I had time to look at it, but the fact is
that the normal inliner is technically able to do some of this stuff
already - it's just not been enabled! (It was a long time since I wrote
that thing, and I had an idea that there was some kind of error that
prevented unrolling from working properly, but it seems that either I
was wrong all the time, or the problem went away at some point and I
just never tried it again.)

So, I just made a patch to lib/compiler/src/cerl_inline.erl (attached)
which adds a new option {inline_unroll, N} (default is 1 - it can't be
lower than 1). This can unroll short recursive loops and help specialize
function calls in general. Example:
----
-module(test).
-compile(inline).
-compile({inline_size, 100}).
-compile({inline_effort, 1000}).
-compile({inline_unroll, 2}).

-export([e/1,f/1,g/1,h/1,i/1,j/1,k/1,l/1]).

e(X) -> powN(X, 0).
f(X) -> powN(X, 1).
g(X) -> powN(X, 2).
h(X) -> powN(X, 3).
i(X) -> powN(X, 4).
j(X) -> powN(X, 5).
k(X) -> powN(X, 6).
l(X) -> powN(X, 7).

powN(X,1) -> X;
powN(_,0) -> 1;
powN(X,N) when (N band 1) =:= 1 -> X * powN(X*X, N bsr 1);
powN(X,N) -> powN(X*X, N bsr 1).
----

generates the following core erlang code (cleaned up for readability):

----
module 'test' ['e'/1, 'f'/1, 'g'/1, 'h'/1, 'i'/1, 'j'/1, 'k'/1, 'l'/1,
...]
attributes []
'e'/1 = fun (_cor0) -> 1
'f'/1 = fun (_cor0) -> _cor0
'g'/1 = fun (_cor0) -> call 'erlang':'*'(_cor0, _cor0)
'h'/1 = fun (_cor0) ->
let <_cor4> = call 'erlang':'*'(_cor0, _cor0)
in call 'erlang':'*'(_cor0, _cor4)
'i'/1 = fun (_cor0) ->
let <_cor7> = call 'erlang':'*'(_cor0, _cor0)
in call 'erlang':'*'(_cor7, _cor7)
'j'/1 = fun (_cor0) ->
let <_cor4> = call 'erlang':'*'(_cor0, _cor0)
in let <_cor5> = call 'erlang':'*'(_cor4, _cor4)
in call 'erlang':'*'(_cor0, _cor5)
'k'/1 = fun (_cor0) ->
let <_cor7> = call 'erlang':'*'(_cor0, _cor0)
in let <_cor4> = call 'erlang':'*'(_cor7, _cor7)
in call 'erlang':'*'(_cor7, _cor4)
'l'/1 = fun (_cor0) ->
let <_cor4> = call 'erlang':'*'(_cor0, _cor0)
in let <_68> = call 'erlang':'*'(_cor4, _cor4)
in let <_cor5> = call 'erlang':'*'(_cor4, _68)
in call 'erlang':'*'(_cor0, _cor5)
...
end
----

This should be in an upcoming release, if you don't feel like patching
your own system. Note that just setting unroll=2 enables the elimination
of all recursive calls to powN/1 in the examples e/1..l/1. On the other
hand, it can be good to provide the inliner with higher size/effort
settings than the default, if unrolling is turned on - this gives it
more room for temporary expressions that may be optimized away later.

/Richard

--
"Having users is like optimization: the wise course is to delay it."
-- Paul Graham
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: diff.inliner
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20060925/f49f0097/attachment.ksh>
```