<feed xmlns='http://www.w3.org/2005/Atom'>
<title>otp.git/lib/compiler/test/core_SUITE_data, branch OTP-21.0.3</title>
<subtitle>Mirror of Erlang/OTP repository.
</subtitle>
<link rel='alternate' type='text/html' href='http://git.ninenines.eu/otp.git/'/>
<entry>
<title>sys_core_fold: Fix name capture problem</title>
<updated>2018-06-04T08:41:21+00:00</updated>
<author>
<name>Björn Gustavsson</name>
<email>bjorn@erlang.org</email>
</author>
<published>2018-06-04T04:14:19+00:00</published>
<link rel='alternate' type='text/html' href='http://git.ninenines.eu/otp.git/commit/?id=7eb06ed5ac1687d38245db2e0aef2756cb43b1ae'/>
<id>7eb06ed5ac1687d38245db2e0aef2756cb43b1ae</id>
<content type='text'>
sys_core_fold could do unsafe transformations on the
code from the old inliner (invoked using the compiler
option `{inline,[{F/A}]}` to request inlining of specific
functions).

To explain the bug, let's first look at an example that
sys_core_fold handles correctly. Consider this code:

    'foo'/2 =
        fun (Arg1,Arg2) -&gt;
          let &lt;B&gt; = Arg2
          in let &lt;A,B&gt; = &lt;B,Arg1&gt;
             in {A,B}

In this example, the lets can be completely eliminated,
since the arguments for the lets are variables (as opposed
to expressions). Since the variable B is rebound in the
inner let, `sys_core_fold` must take special care when
doing the substitutions.

Here is the correct result:

    'foo'/2 =
        fun (Arg1, Arg2) -&gt;
          {Arg2,Arg1}

Consider a slight modifictation of the example:

    'bar'/2 =
        fun (Arg1,Arg2) -&gt;
            let &lt;B&gt; = [Arg2]
            in let &lt;A,B&gt; = &lt;B,[Arg1]&gt;
               in {A,B}

Here some of the arguments for the lets are expressions, so
the lets must be kept. sys_core_fold does not handle this
example correctly:

    'bar'/2 =
        fun (Arg1,Arg2) -&gt;
          let &lt;B&gt; = [Arg2]
    	  in let &lt;B&gt; = [Arg1]
    	     in {B,B}

In the inner let, the variable A has been eliminated and
replaced with the variable B in the body (the first B in
the tuple). Since the B in the outer let is never used,
the outer let will be eliminated, giving:

    'bar'/2 =
        fun (Arg1,Arg2) -&gt;
    	  let &lt;B&gt; = [Arg1]
    	  in {B,B}

To handle this example correctly, sys_core_fold must
rename the variable B in the inner let like this to
avoid capturing B:

    'bar'/2 =
       fun (Arg1,Arg2) -&gt;
         let &lt;B&gt; = [Arg2]
         in let &lt;NewName&gt; = [Arg1]
            in {B,NewName}

(Note: The `v3_kernel` pass alreday handles those examples correctly
in case `sys_core_fold` has been disabled.)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
sys_core_fold could do unsafe transformations on the
code from the old inliner (invoked using the compiler
option `{inline,[{F/A}]}` to request inlining of specific
functions).

To explain the bug, let's first look at an example that
sys_core_fold handles correctly. Consider this code:

    'foo'/2 =
        fun (Arg1,Arg2) -&gt;
          let &lt;B&gt; = Arg2
          in let &lt;A,B&gt; = &lt;B,Arg1&gt;
             in {A,B}

In this example, the lets can be completely eliminated,
since the arguments for the lets are variables (as opposed
to expressions). Since the variable B is rebound in the
inner let, `sys_core_fold` must take special care when
doing the substitutions.

Here is the correct result:

    'foo'/2 =
        fun (Arg1, Arg2) -&gt;
          {Arg2,Arg1}

Consider a slight modifictation of the example:

    'bar'/2 =
        fun (Arg1,Arg2) -&gt;
            let &lt;B&gt; = [Arg2]
            in let &lt;A,B&gt; = &lt;B,[Arg1]&gt;
               in {A,B}

Here some of the arguments for the lets are expressions, so
the lets must be kept. sys_core_fold does not handle this
example correctly:

    'bar'/2 =
        fun (Arg1,Arg2) -&gt;
          let &lt;B&gt; = [Arg2]
    	  in let &lt;B&gt; = [Arg1]
    	     in {B,B}

In the inner let, the variable A has been eliminated and
replaced with the variable B in the body (the first B in
the tuple). Since the B in the outer let is never used,
the outer let will be eliminated, giving:

    'bar'/2 =
        fun (Arg1,Arg2) -&gt;
    	  let &lt;B&gt; = [Arg1]
    	  in {B,B}

To handle this example correctly, sys_core_fold must
rename the variable B in the inner let like this to
avoid capturing B:

    'bar'/2 =
       fun (Arg1,Arg2) -&gt;
         let &lt;B&gt; = [Arg2]
         in let &lt;NewName&gt; = [Arg1]
            in {B,NewName}

(Note: The `v3_kernel` pass alreday handles those examples correctly
in case `sys_core_fold` has been disabled.)
</pre>
</div>
</content>
</entry>
<entry>
<title>sys_core_fold: Fix unsafe optimization of non-variable apply</title>
<updated>2017-08-07T05:20:29+00:00</updated>
<author>
<name>Björn Gustavsson</name>
<email>bjorn@erlang.org</email>
</author>
<published>2017-08-07T05:00:14+00:00</published>
<link rel='alternate' type='text/html' href='http://git.ninenines.eu/otp.git/commit/?id=f59e70ce61913356a67d58e03d6b68c29e983363'/>
<id>f59e70ce61913356a67d58e03d6b68c29e983363</id>
<content type='text'>
The sys_core_fold pass would do an unsafe "optimization" when an
apply operation did not have a variable in the function position
as in the following example:

&gt; cat test1.core
module 'test1' ['test1'/2]
    attributes []
'i'/1 =
  fun (_f) -&gt; _f
'test1'/2 =
  fun (_f, _x) -&gt;
    apply apply 'i'/1 (_f) (_x)
end
&gt; erlc test1.core
no_file: Warning: invalid function call

Reported-by: Mikael Pettersson
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The sys_core_fold pass would do an unsafe "optimization" when an
apply operation did not have a variable in the function position
as in the following example:

&gt; cat test1.core
module 'test1' ['test1'/2]
    attributes []
'i'/1 =
  fun (_f) -&gt; _f
'test1'/2 =
  fun (_f, _x) -&gt;
    apply apply 'i'/1 (_f) (_x)
end
&gt; erlc test1.core
no_file: Warning: invalid function call

Reported-by: Mikael Pettersson
</pre>
</div>
</content>
</entry>
<entry>
<title>v3_kernel: Generate optimized code for guards</title>
<updated>2016-11-18T10:58:34+00:00</updated>
<author>
<name>Björn Gustavsson</name>
<email>bjorn@erlang.org</email>
</author>
<published>2016-09-15T14:33:57+00:00</published>
<link rel='alternate' type='text/html' href='http://git.ninenines.eu/otp.git/commit/?id=348b5e6bee2f83d10642558d511cc904f5015ab3'/>
<id>348b5e6bee2f83d10642558d511cc904f5015ab3</id>
<content type='text'>
The compiler produces poor code for complex guard expressions with andalso/orelse.
Here is an example from the filename module:

-define(IS_DRIVELETTER(Letter),(((Letter &gt;= $A) andalso (Letter =&lt; $Z)) orelse
				((Letter &gt;= $a) andalso (Letter =&lt; $z)))).
skip_prefix(Name, false) -&gt;
    Name;
skip_prefix([L, DrvSep|Name], DrvSep) when ?IS_DRIVELETTER(L) -&gt;
    Name;
skip_prefix(Name, _) -&gt;
    Name.

beam_bool fails to simplify the code for the guard, leaving several 'bif'
instructions:

{function, skip_prefix, 2, 49}.
  {label,48}.
    {line,[{location,"filename.erl",187}]}.
    {func_info,{atom,filename},{atom,skip_prefix},2}.
  {label,49}.
    {test,is_ne_exact,{f,52},[{x,1},{atom,false}]}.
    {test,is_nonempty_list,{f,52},[{x,0}]}.
    {get_list,{x,0},{x,2},{x,3}}.
    {test,is_nonempty_list,{f,52},[{x,3}]}.
    {get_list,{x,3},{x,4},{x,5}}.
    {bif,'=:=',{f,52},[{x,1},{x,4}],{x,6}}.
    {test,is_ge,{f,50},[{x,2},{integer,65}]}.
    {bif,'=&lt;',{f,52},[{x,2},{integer,90}],{x,7}}.
    {test,is_eq_exact,{f,51},[{x,7},{atom,false}]}.
    {test,is_ge,{f,50},[{x,2},{integer,97}]}.
    {bif,'=&lt;',{f,52},[{x,2},{integer,122}],{x,7}}.
    {jump,{f,51}}.
  {label,50}.
    {move,{atom,false},{x,7}}.
  {label,51}.
    {bif,'=:=',{f,52},[{x,7},{atom,true}],{x,7}}.
    {test,is_eq_exact,{f,52},[{x,6},{atom,true}]}.
    {test,is_eq_exact,{f,52},[{x,7},{atom,true}]}.
    {move,{x,5},{x,0}}.
    return.
  {label,52}.
    return.

We can add optimizations of guard tests to v3_kernel to achive a better result:

{function, skip_prefix, 2, 49}.
  {label,48}.
    {line,[{location,"filename.erl",187}]}.
    {func_info,{atom,filename},{atom,skip_prefix},2}.
  {label,49}.
    {test,is_ne_exact,{f,51},[{x,1},{atom,false}]}.
    {test,is_nonempty_list,{f,51},[{x,0}]}.
    {get_list,{x,0},{x,2},{x,3}}.
    {test,is_nonempty_list,{f,51},[{x,3}]}.
    {get_list,{x,3},{x,4},{x,5}}.
    {test,is_eq_exact,{f,51},[{x,1},{x,4}]}.
    {test,is_ge,{f,51},[{x,2},{integer,65}]}.
    {test,is_lt,{f,50},[{integer,90},{x,2}]}.
    {test,is_ge,{f,51},[{x,2},{integer,97}]}.
    {test,is_ge,{f,51},[{integer,122},{x,2}]}.
  {label,50}.
    {move,{x,5},{x,0}}.
    return.
  {label,51}.
    return.

Looking at the STDLIB application, there were 112 lines of BIF calls in guards
that beam_bool failed to convert to test instructions. This commit eliminates
all those BIF calls.

Here is how I counted the instructions:

$ PATH=$ERL_TOP/bin:$PATH erlc -I ../include -I ../../kernel/include -S *.erl
$ grep "bif,'[=&lt;&gt;]" *.S | grep -v f,0
dets.S:    {bif,'=:=',{f,547},[{x,4},{atom,read_write}],{x,4}}.
dets.S:    {bif,'=:=',{f,547},[{x,5},{atom,saved}],{x,5}}.
dets.S:    {bif,'=:=',{f,589},[{x,5},{atom,read}],{x,5}}.
.
.
.
$ grep "bif,'[=&lt;&gt;]" *.S | grep -v f,0 | wc
     112     224    6765
$
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The compiler produces poor code for complex guard expressions with andalso/orelse.
Here is an example from the filename module:

-define(IS_DRIVELETTER(Letter),(((Letter &gt;= $A) andalso (Letter =&lt; $Z)) orelse
				((Letter &gt;= $a) andalso (Letter =&lt; $z)))).
skip_prefix(Name, false) -&gt;
    Name;
skip_prefix([L, DrvSep|Name], DrvSep) when ?IS_DRIVELETTER(L) -&gt;
    Name;
skip_prefix(Name, _) -&gt;
    Name.

beam_bool fails to simplify the code for the guard, leaving several 'bif'
instructions:

{function, skip_prefix, 2, 49}.
  {label,48}.
    {line,[{location,"filename.erl",187}]}.
    {func_info,{atom,filename},{atom,skip_prefix},2}.
  {label,49}.
    {test,is_ne_exact,{f,52},[{x,1},{atom,false}]}.
    {test,is_nonempty_list,{f,52},[{x,0}]}.
    {get_list,{x,0},{x,2},{x,3}}.
    {test,is_nonempty_list,{f,52},[{x,3}]}.
    {get_list,{x,3},{x,4},{x,5}}.
    {bif,'=:=',{f,52},[{x,1},{x,4}],{x,6}}.
    {test,is_ge,{f,50},[{x,2},{integer,65}]}.
    {bif,'=&lt;',{f,52},[{x,2},{integer,90}],{x,7}}.
    {test,is_eq_exact,{f,51},[{x,7},{atom,false}]}.
    {test,is_ge,{f,50},[{x,2},{integer,97}]}.
    {bif,'=&lt;',{f,52},[{x,2},{integer,122}],{x,7}}.
    {jump,{f,51}}.
  {label,50}.
    {move,{atom,false},{x,7}}.
  {label,51}.
    {bif,'=:=',{f,52},[{x,7},{atom,true}],{x,7}}.
    {test,is_eq_exact,{f,52},[{x,6},{atom,true}]}.
    {test,is_eq_exact,{f,52},[{x,7},{atom,true}]}.
    {move,{x,5},{x,0}}.
    return.
  {label,52}.
    return.

We can add optimizations of guard tests to v3_kernel to achive a better result:

{function, skip_prefix, 2, 49}.
  {label,48}.
    {line,[{location,"filename.erl",187}]}.
    {func_info,{atom,filename},{atom,skip_prefix},2}.
  {label,49}.
    {test,is_ne_exact,{f,51},[{x,1},{atom,false}]}.
    {test,is_nonempty_list,{f,51},[{x,0}]}.
    {get_list,{x,0},{x,2},{x,3}}.
    {test,is_nonempty_list,{f,51},[{x,3}]}.
    {get_list,{x,3},{x,4},{x,5}}.
    {test,is_eq_exact,{f,51},[{x,1},{x,4}]}.
    {test,is_ge,{f,51},[{x,2},{integer,65}]}.
    {test,is_lt,{f,50},[{integer,90},{x,2}]}.
    {test,is_ge,{f,51},[{x,2},{integer,97}]}.
    {test,is_ge,{f,51},[{integer,122},{x,2}]}.
  {label,50}.
    {move,{x,5},{x,0}}.
    return.
  {label,51}.
    return.

Looking at the STDLIB application, there were 112 lines of BIF calls in guards
that beam_bool failed to convert to test instructions. This commit eliminates
all those BIF calls.

Here is how I counted the instructions:

$ PATH=$ERL_TOP/bin:$PATH erlc -I ../include -I ../../kernel/include -S *.erl
$ grep "bif,'[=&lt;&gt;]" *.S | grep -v f,0
dets.S:    {bif,'=:=',{f,547},[{x,4},{atom,read_write}],{x,4}}.
dets.S:    {bif,'=:=',{f,547},[{x,5},{atom,saved}],{x,5}}.
dets.S:    {bif,'=:=',{f,589},[{x,5},{atom,read}],{x,5}}.
.
.
.
$ grep "bif,'[=&lt;&gt;]" *.S | grep -v f,0 | wc
     112     224    6765
$
</pre>
</div>
</content>
</entry>
<entry>
<title>test suite: Always place .core files in data directories</title>
<updated>2015-04-22T08:12:32+00:00</updated>
<author>
<name>Björn Gustavsson</name>
<email>bjorn@erlang.org</email>
</author>
<published>2015-04-20T08:19:55+00:00</published>
<link rel='alternate' type='text/html' href='http://git.ninenines.eu/otp.git/commit/?id=37996d71a60f8aa4dd1078a7903098aa656b9e35'/>
<id>37996d71a60f8aa4dd1078a7903098aa656b9e35</id>
<content type='text'>
For tidiness, always place .core files in data directories.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
For tidiness, always place .core files in data directories.
</pre>
</div>
</content>
</entry>
<entry>
<title>Make the syntax for map pairs readable</title>
<updated>2015-01-30T14:51:52+00:00</updated>
<author>
<name>Björn Gustavsson</name>
<email>bjorn@erlang.org</email>
</author>
<published>2015-01-30T14:43:41+00:00</published>
<link rel='alternate' type='text/html' href='http://git.ninenines.eu/otp.git/commit/?id=f667931e2905797ffab63e224e56eaf07f77178a'/>
<id>f667931e2905797ffab63e224e56eaf07f77178a</id>
<content type='text'>
Use the same syntax for map pairs in Core Erlang code as in the
Erlang Code. This Erlang code:

  M#{x:=42,y=&gt;1}

will look like this in Core Erlang:

  ~{'x':=42,'y'=&gt;1|M}~
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Use the same syntax for map pairs in Core Erlang code as in the
Erlang Code. This Erlang code:

  M#{x:=42,y=&gt;1}

will look like this in Core Erlang:

  ~{'x':=42,'y'=&gt;1|M}~
</pre>
</div>
</content>
</entry>
<entry>
<title>compiler: Change Maps Core Format</title>
<updated>2014-03-17T16:47:34+00:00</updated>
<author>
<name>Björn-Egil Dahlberg</name>
<email>egil@erlang.org</email>
</author>
<published>2014-03-06T16:59:09+00:00</published>
<link rel='alternate' type='text/html' href='http://git.ninenines.eu/otp.git/commit/?id=70c968442a8e2afbae7fa485527920006bfe2031'/>
<id>70c968442a8e2afbae7fa485527920006bfe2031</id>
<content type='text'>
Ex.

Instead of:

    M~{~&lt;K,V&gt;}~

The format is now:

    ~{~&lt;K,V&gt;|M}~

This also removes a shift/reduce warning.

The changes in core_pp now requires compiler-5.0 to compile
because of is_map/1 guard, i.e. a need for a compiler with Maps know-how.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Ex.

Instead of:

    M~{~&lt;K,V&gt;}~

The format is now:

    ~{~&lt;K,V&gt;|M}~

This also removes a shift/reduce warning.

The changes in core_pp now requires compiler-5.0 to compile
because of is_map/1 guard, i.e. a need for a compiler with Maps know-how.
</pre>
</div>
</content>
</entry>
<entry>
<title>Do not try to optimize non-boolean guards</title>
<updated>2014-03-05T09:18:15+00:00</updated>
<author>
<name>Anthony Ramine</name>
<email>n.oxyde@gmail.com</email>
</author>
<published>2014-03-01T16:26:56+00:00</published>
<link rel='alternate' type='text/html' href='http://git.ninenines.eu/otp.git/commit/?id=926be4d0a3a75f48bc280a7aa2f97fc4adbef189'/>
<id>926be4d0a3a75f48bc280a7aa2f97fc4adbef189</id>
<content type='text'>
Expressions such as erlang:'or'(bar, true) can make beam_bool crash if it tries
to optimize them, as this code is not quite really written by users, no attempt
to rewrite them more efficiently should be done, for simplicity's sake.

Reported-by: Ulf Norell
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Expressions such as erlang:'or'(bar, true) can make beam_bool crash if it tries
to optimize them, as this code is not quite really written by users, no attempt
to rewrite them more efficiently should be done, for simplicity's sake.

Reported-by: Ulf Norell
</pre>
</div>
</content>
</entry>
<entry>
<title>Teach sys_core_fold:eval_case/2 to cope with handwritten Core Erlang</title>
<updated>2014-02-11T09:09:46+00:00</updated>
<author>
<name>Björn Gustavsson</name>
<email>bjorn@erlang.org</email>
</author>
<published>2014-02-11T07:31:37+00:00</published>
<link rel='alternate' type='text/html' href='http://git.ninenines.eu/otp.git/commit/?id=c89ada7517420ce9065840ea857a0009418ce2af'/>
<id>c89ada7517420ce9065840ea857a0009418ce2af</id>
<content type='text'>
Starting in e12b7d5331c58b41db06cadfa4af75b78b62a2b1,
sys_core_fold:eval_case/2 will crash on handwritten but legal
Core Erlang programs such as:

   case let &lt;Var&gt; = Arg in {'x',Var} of
      {x,X} -&gt; X
   end

The problem is that the only clause *is* guaranteed to match, but
cerl_clauses:match_list/2 does not understand that; all it can say is
that the clause *may* match. In those circumstances, we will need to
keep the case.

Also make sure that we keep the case if the guard is something else
than 'true'. That is not strictly necessary, because in a legal Core
Erlang program the guard in the last clause in a case must always
evaluate to 'true', so removing the guard test would still leave the
program correct. Keeping the guard, however, will make it somewhat
easier to debug an incorrect Core Erlang program. (The unsafe_case
test case has guard test in the only clause in a case, so we don't
need to write a new test case to test that.)

Reported-by: Anthony Ramine
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Starting in e12b7d5331c58b41db06cadfa4af75b78b62a2b1,
sys_core_fold:eval_case/2 will crash on handwritten but legal
Core Erlang programs such as:

   case let &lt;Var&gt; = Arg in {'x',Var} of
      {x,X} -&gt; X
   end

The problem is that the only clause *is* guaranteed to match, but
cerl_clauses:match_list/2 does not understand that; all it can say is
that the clause *may* match. In those circumstances, we will need to
keep the case.

Also make sure that we keep the case if the guard is something else
than 'true'. That is not strictly necessary, because in a legal Core
Erlang program the guard in the last clause in a case must always
evaluate to 'true', so removing the guard test would still leave the
program correct. Keeping the guard, however, will make it somewhat
easier to debug an incorrect Core Erlang program. (The unsafe_case
test case has guard test in the only clause in a case, so we don't
need to write a new test case to test that.)

Reported-by: Anthony Ramine
</pre>
</div>
</content>
</entry>
<entry>
<title>compiler: Add core compile test for maps</title>
<updated>2014-01-29T10:08:51+00:00</updated>
<author>
<name>Björn-Egil Dahlberg</name>
<email>egil@erlang.org</email>
</author>
<published>2014-01-28T13:46:16+00:00</published>
<link rel='alternate' type='text/html' href='http://git.ninenines.eu/otp.git/commit/?id=cf5bc2e917dbcb2c2841bf07b995efe105bea4be'/>
<id>cf5bc2e917dbcb2c2841bf07b995efe105bea4be</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>v3_kernel: Handle sequences in guards</title>
<updated>2012-01-11T07:39:57+00:00</updated>
<author>
<name>Björn Gustavsson</name>
<email>bjorn@erlang.org</email>
</author>
<published>2012-01-04T15:40:31+00:00</published>
<link rel='alternate' type='text/html' href='http://git.ninenines.eu/otp.git/commit/?id=823f47c8cf3c7a4f32401cae5a2e47916d3593e4'/>
<id>823f47c8cf3c7a4f32401cae5a2e47916d3593e4</id>
<content type='text'>
A guard with a sequence will cause a crash in v3_codegen. Currently,
it seems that a sequence in a guard will never happen when compiling
from Erlang code, but there are several reasons to fix this problem
anyway:

* There are other compilers that generate Core Erlang code.

* Changes to sys_core_fold (perhaps additional optimizations) may
  cause sequences to be generated in guards.

* A previously uncovered line in sys_core_fold:opt_guard_try/1 will
  now be covered.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
A guard with a sequence will cause a crash in v3_codegen. Currently,
it seems that a sequence in a guard will never happen when compiling
from Erlang code, but there are several reasons to fix this problem
anyway:

* There are other compilers that generate Core Erlang code.

* Changes to sys_core_fold (perhaps additional optimizations) may
  cause sequences to be generated in guards.

* A previously uncovered line in sys_core_fold:opt_guard_try/1 will
  now be covered.
</pre>
</div>
</content>
</entry>
</feed>
