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:
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.
The optimization just isn't performed.
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.
Erlang programs must be compiled to object code. The compiler can generate a new file that contains the object code. The current abstract machine, which runs the object code, is called BEAM, therefore the object files get the suffix . beam.
compile:file(File, Options). File is a file name, and Options is a list of compiler options. Refer to the Reference Manual for a complete list of Options . You can also enter the command c(File) from the Erlang shell.
Erlang (/ˈɜːrlæŋ/ UR-lang) is a general-purpose, concurrent, functional programming language, and a garbage-collected runtime system.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With