<div class="gmail_quote">Guards seem to be given a rather stepmotherly treatment in the compiler... whether any decent code is generated appear to be entirely up to the mercy of the peephole optimizer. That's worse than I'd imagined.<br>
<br>For instance,<br>  g3(X) when X=:=foo orelse<br>         X=:=bar orelse<br>         X=:=baz -> ok.<br>generates the rather asymmetric<br>      {select_val,{x,0},{f,11},{list,[{atom,foo},{f,12},{atom,bar},{f,12}]}}.<br>
    {label,11}.<br>      {test,is_eq_exact,{f,9},[{x,0},{atom,baz}]}.<br>    {label,12}.<br>      {move,{atom,ok},{x,0}}.<br>      return.<br><br>And worse, in some cases like<br>  h(X,Y) when (X=:=a andalso Y>0) -> aa;<br>
  h(X,Y) when (X=:=b andalso Y>0) -> bb;<br>  h(X,Y) when (X=:=c andalso Y>0) -> cc.<br>the size of the generated code is quadratic in the size of the source code:<br>    {select_val,{x,0},<br>                {f,29},<br>
                {list,[{atom,a},{f,31},{atom,b},{f,33},{atom,c},{f,35}]}}.<br>  {label,31}.<br>    {test,is_lt,{f,32},[{integer,0},{x,1}]}.<br>    {move,{atom,aa},{x,0}}.<br>    return.<br>  {label,32}.<br>    {select_val,{x,0},{f,29},{list,[{atom,b},{f,33},{atom,c},{f,35}]}}.<br>
  {label,33}.<br>    {test,is_lt,{f,34},[{integer,0},{x,1}]}.<br>    {move,{atom,bb},{x,0}}.<br>    return.<br>  {label,34}.<br>    {test,is_eq_exact,{f,29},[{x,0},{atom,c}]}.<br>  {label,35}.<br>    {test,is_lt,{f,29},[{integer,0},{x,1}]}.<br>
    {move,{atom,cc},{x,0}}.<br>    return.<br>(Notice the tables in the select_val instructions.)<br><br>This bad behaviour happens after the transition to beam code (in beam_dead:combine_eqs(), afaict).<br>Looks like guards really would like to be taken into account during pattern match compilation... (no offence, Dijkstra).<br>
<br>Anyway, the first roadblock appears to be that at the time when match compilation occurs (at the core->kernel representation transition), guards have already been flattened, meaning that what was at guard top-level in the source code is more difficult to find.<br>
For this reason, I'm considering a representation change of Core's clauses - from<br>  -record(c_clause, {anno=[], pats,       % pats :: [Tree],<br>                     guard,               % guard :: Tree,<br>                     body}).              % body :: Tree<br>
to<br>  -record(c_clause, {anno=[], pats,<br>
                     guard_pats :: [{Tree, Tree}], % {ExprToTest, Pattern}<br>                     guard_exp :: Tree, <br>
                     body}).<br>such that the guard is split into a part that can integrated into the pattern matching step, and a remainder that can't.<br>
For instance, the guard "when Y > 0, element(1,X) =:= foo" would be represented as<br>  guard_pats = [{E1, P1}], guard_exp=E2<br>where E1 = repr. of "element(1,X)", P1 = repr. of "'foo'", and E2 = repr. of "Y > 0".<br>
<br>Handling "P ?= E" at guard top level would then follow quite naturally: by including {E,P} in guard_pats.<br>(As for scoping, it is handled in an earlier phase.)<br>Integrating type tests need a bit more, but that can be left for later if necessary.<br>
<br>/Erik<br><br>Den 18. apr. 2012 14.54 skrev Erik Søe Sørensen <span dir="ltr"><<a href="mailto:eriksoe@gmail.com">eriksoe@gmail.com</a>></span>:<br>[snip]<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Handling 'orelse' might be tricky, though; the current approach for ';' appears to be to simply duplicate the clause and let a downstream optimizer recognize the duplication, so I suppose that will work for 'orelse' as well.<br>

(Looking at generated code, I notice that 'orelse' and 'andalso' in guards gives rise (in R14B03)  to some surprising - and suboptimal - code.)<br></blockquote></div><br><br>