Handle guards that appear multiple times in a compiled decision tree

Suppose we have a when expression

```
15 if foo -> <b1>
b  if bar -> <b2>
_         -> <b3>
```

that may have a decision tree like

```
15?
  \true => foo?
              \true  => <b1>
              \false => bar?
                           \true  => <b2>
                           \false => <b3>
  \false => bar?
               \true  => <b2>
               \false => <b3>
```

In this case, the guard "bar?" appears twice in the compiled decision
tree. We need to materialize the guard expression in both locations in
the compiled tree, which means we cannot as-is stamp a compiled `bar?`
twice in each location. The reason is that

- the compiled joinpoint for each `bar?` guard needs to have a unique ID
- the guard expression might have call which needs unique call spec IDs,
  or other joins that need unique joinpoint IDs.

So, save the expression as we build up the decision tree and materialize
the guard each time we need it. In practice the guards should be quite
small, so duplicating should be fine. We could avoid duplication, but
it's not clear to me how to do that exactly since the branches after the
guard might end up being different.
This commit is contained in:
Ayaz Hafiz 2023-03-25 13:48:40 -05:00
parent f3ddc254c1
commit dd55be6142
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
3 changed files with 160 additions and 43 deletions

View file

@ -0,0 +1,51 @@
procedure Bool.2 ():
let Bool.25 : Int1 = true;
ret Bool.25;
procedure Num.19 (#Attr.2, #Attr.3):
let Num.275 : U8 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.275;
procedure Test.1 (Test.2):
joinpoint Test.12:
let Test.9 : U8 = 3i64;
ret Test.9;
in
joinpoint Test.11 Test.10:
let Test.8 : U8 = 2i64;
let Test.7 : U8 = CallByName Num.19 Test.10 Test.8;
ret Test.7;
in
let Test.22 : U8 = 15i64;
let Test.23 : Int1 = lowlevel Eq Test.22 Test.2;
if Test.23 then
joinpoint Test.17 Test.13:
if Test.13 then
let Test.6 : U8 = 1i64;
ret Test.6;
else
joinpoint Test.15 Test.14:
if Test.14 then
jump Test.11 Test.2;
else
jump Test.12;
in
let Test.16 : Int1 = CallByName Bool.2;
jump Test.15 Test.16;
in
let Test.18 : Int1 = CallByName Bool.2;
jump Test.17 Test.18;
else
joinpoint Test.20 Test.19:
if Test.19 then
jump Test.11 Test.2;
else
jump Test.12;
in
let Test.21 : Int1 = CallByName Bool.2;
jump Test.20 Test.21;
procedure Test.0 ():
let Test.5 : U8 = 46i64;
let Test.4 : U8 = CallByName Test.1 Test.5;
ret Test.4;