[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:
   -compile({inline_size, 100}).
   -compile({inline_effort, 1000}).
   -compile({inline_unroll, 2}).


   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)

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.


  "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>

More information about the erlang-questions mailing list