7
votes

I'm no compiler optimization expert. I'm not even sure what's "reasonable" to expect as far as compilers or optimizations. I'm just curious and asking questions is all.

At any rate, I was coding up some Erlang in a basic form such as this:

% TOY EXAMPLE 1
test(X) ->
    if
        X-1 > 0 ->
            yes;
        X-1 == 0 ->
            maybe;
        true -> no
    end.

Then I then optimized it in order not to do the subtract twice:

% TOY EXAMPLE 2
test(X) ->
    Z = X-1,
    if
        Z > 0 ->
            yes;
        Z == 0 ->
            maybe;
        true -> no
    end.

Then I thought "a waste of time - surely the compiler optimizes the first example into the second anyway." So I decided to check by running compile:file with 'S' option for both. Here is output:

% TOY EXAMPLE 1
{function, test, 1, 15}.
  {label,14}.
    {func_info,{atom,exchange},{atom,test},1}.
  {label,15}.
    {gc_bif,'-',{f,16},1,[{x,0},{integer,1}],{x,1}}.
    {test,is_lt,{f,16},[{integer,0},{x,1}]}.
    {move,{atom,yes},{x,0}}.
    return.
  {label,16}.
    {gc_bif,'-',{f,17},1,[{x,0},{integer,1}],{x,1}}.
    {test,is_eq,{f,17},[{x,1},{integer,0}]}.
    {move,{atom,maybe},{x,0}}.
    return.
  {label,17}.
    {move,{atom,no},{x,0}}.
    return.

% TOY EXAMPLE 2
{function, test, 1, 15}.
  {label,14}.
    {func_info,{atom,exchange},{atom,test},1}.
  {label,15}.
    {gc_bif,'-',{f,0},1,[{x,0},{integer,1}],{x,0}}.
    {test,is_lt,{f,16},[{integer,0},{x,0}]}.
    {move,{atom,yes},{x,0}}.
    return.
  {label,16}.
    {test,is_eq,{f,17},[{x,0},{integer,0}]}.
    {move,{atom,maybe},{x,0}}.
    return.
  {label,17}.
    {move,{atom,no},{x,0}}.
    return.

They aren't the same. If I'm reading this right (maybe I'm not), the optimization isn't performed.

I can see a few possibilities:

  1. The optimization can be performed, I'm just not enabling the optimizations because I'm using the wrong function to compile, or not using the correct flags, etc.

  2. The optimization just isn't performed.

  3. Other.

Which is it?

Note: Please don't get bogged down with talk of "if you use a case statement you can do such-and-such" or "you can avoid this by doing blah-blah." The point is simply to test which optimizations the erlang compiler does or doesn't do, and why or why not.

Thanks.

1

1 Answers

5
votes

You're quite right - the Beam compiler doesn't do any common subexpression elimination. The reason is probably that in the kind of programs that Erlang is typically used for, this would not have any noticeable effect, so nobody has bothered to implement it. (For the rare cases of computationally intensive Erlang code, it's usually easy for the programmer to take care of this, as you did in the second example.)

If you compile to native code, you might get this kind of optimization - the HiPE compiler puts in a greater effort to generate good low level code.