Skip to content

Use information about previous pattern matches to optimize #1083

@b-studios

Description

@b-studios

For the following effekt code

import args

def join(left: Bool, right: Bool): Bool = (left, right) match {
  case (true, true) => true
  case (false,     _) => false
  case (_    , false) => false
}

def main() = commandLineArgs() match {
  case Cons(input, _) => println(join(input == "a", input == "b"))
  case Nil() => ()
}

our pattern matching compiler currently generates

switch (v_r_0.__tag) {
      case 1: 
        const input_0 = v_r_0.head_0;
        const tmp_3 = input_0 === "a";
        const tmp_4 = input_0 === "b";
        if (tmp_3) if (tmp_4) {
          const tmp_5 = $effekt.println("true");
          return () => k_1(tmp_5, ks_2);
        } else if (tmp_4) {
          return $effekt.hole();  // UNREACHABLE
        } else {
          const tmp_6 = $effekt.println("false");
          return () => k_1(tmp_6, ks_2);
        } else if (tmp_3) {
          return $effekt.hole(); // UNREACHABLE
        } else {
          const tmp_7 = $effekt.println("false");
          return () => k_1(tmp_7, ks_2);
        }
        break;
      case 0:  return () => k_1($effekt.unit, ks_2);
    }

where I marked the two holes as unreachable. We seem to lose the positive information about scrutinees (maybe look at Sestoft's paper again?)

Ideally, in this case we would generate

    if (tmp_3) {
      if (tmp_4) {
        const tmp_5 = $effekt.println("true");
        return () => k_1(tmp_5, ks_2);
      } else {
        const tmp_6 = $effekt.println("false");
        return () => k_1(tmp_6, ks_2);
      }
    } else {
      const tmp_7 = $effekt.println("false");
      return () => k_1(tmp_7, ks_2);
    }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions