Chapter 3: EGraph Program Rewrites¶

In this chapter, we walk through implementing our first program rewrite using EGraphs. We show how to define rewrite rules, propagate constants, and fold if-else branches at compile time. This chapter demonstrates the power of EGraph-based optimizations in the compiler pipeline.

The chapter covers:

  • How to define and use EGraph rewrite rules
  • How to propagate constants and fold branches
  • How to extend the compiler pipeline for EGraph-based optimizations

Imports and Setup¶

Import all necessary modules for EGraph program rewrites.

In [1]:
from __future__ import annotations
In [2]:
from egglog import EGraph, Ruleset, Unit, function, i64, rewrite, rule, ruleset
from sealir import rvsdg
from sealir.eqsat import rvsdg_eqsat
from sealir.eqsat.rvsdg_eqsat import GraphRoot, Term, TermList
In [3]:
# We'll be extending from chapter 2.
from ch02_egraph_basic import (
    EGraphOutput,
)
from ch02_egraph_basic import compiler_pipeline as _ch02_compiler_pipeline
from ch02_egraph_basic import (
    run_test,
)
from utils import IN_NOTEBOOK, Report, display

Next, we'll explore a new compiler pipeline designed with customizable rulesets. To enable this flexibility, we've introduced a ruleset argument, allowing you to tailor the pipeline's behavior to your specific needs.

In [4]:
def egraph_saturation(
    egraph: EGraph,
    egraph_root: GraphRoot,
    ruleset: Ruleset,
    pipeline_report=Report.Sink(),
) -> EGraphOutput:
    # Apply the ruleset to the egraph
    egraph.run(ruleset.saturate())
    pipeline_report.append("EGraph Saturated", egraph)
    return {"egraph": egraph, "egraph_root": egraph_root}
In [5]:
compiler_pipeline = _ch02_compiler_pipeline.replace(
    "egraph_action", egraph_saturation
)
In [6]:
if __name__ == "__main__":
    display(compiler_pipeline.visualize())
Pipeline-pipeline_backend cluster_legend Legend input_fn fn Any stage_1 Stage 1 pipeline_frontend → FrontendOutput input_fn->stage_1 fn input_ruleset ruleset Ruleset stage_3 Stage 3 egraph_saturation → EGraphOutput input_ruleset->stage_3 ruleset input_pipeline_report pipeline_report Any = DummyReport() input_pipeline_report->stage_1 pipeline_report stage_2 Stage 2 pipeline_egraph_conversion → EGraphOutput input_pipeline_report->stage_2 pipeline_report input_pipeline_report->stage_3 pipeline_report stage_4 Stage 4 pipeline_egraph_extraction → EGraphExtractionOutput input_pipeline_report->stage_4 pipeline_report stage_5 Stage 5 pipeline_backend → BackendOutput input_pipeline_report->stage_5 pipeline_report stage_1->stage_2 rvsdg_expr stage_1->stage_4 rvsdg_expr out_dbginfo dbginfo object stage_1->out_dbginfo dbginfo out_rvsdg_expr rvsdg_expr object stage_1->out_rvsdg_expr rvsdg_expr stage_2->stage_3 egraph stage_2->stage_3 egraph_root stage_3->stage_4 egraph out_egraph egraph EGraph stage_3->out_egraph egraph out_egraph_root egraph_root GraphRoot stage_3->out_egraph_root egraph_root stage_4->stage_5 extracted out_cost cost float stage_4->out_cost cost out_extracted extracted Any stage_4->out_extracted extracted out_jit_func jit_func Any stage_5->out_jit_func jit_func out_llmod llmod Any stage_5->out_llmod llmod legend_input Required Input legend_optional Optional Input legend_input->legend_optional legend_stage Processing Stage legend_optional->legend_stage legend_output Output legend_stage->legend_output

Rules for defining constants¶

Now, let's define a simple rule by specifying what makes a constant boolean. We'll use egglog.function to annotate properties on terms (Term instances). Each term directly corresponds to an RVSDG-IR node, which in turn maps to a Python AST node. As a result, a term can represent various constructs—such as an expression, a literal constant, an operation, or a control-flow element.

An egglog.function acts as a symbolic entity, meaning it doesn't require a function body. In our case, we'll use it to mark specific terms: a term is labeled as IsConstantTrue(Term) if it represents an expression of a non-zero literal int64, indicating a constant True. Conversely, we mark a term as IsConstantFalse(Term) if it's an expression of a literal zero, signifying a constant False.

In [7]:
@function
def IsConstantTrue(t: Term) -> Unit: ...


@function
def IsConstantFalse(t: Term) -> Unit: ...

Rules can be organized into groups known as ruleset. Below, we'll define a set of rules for recognizing constants, laying the groundwork for our optimization process.

In [8]:
@ruleset
def ruleset_const_propagate(a: Term, ival: i64):
    # a Literal Int64 is constant True if it's non-zero
    yield rule(
        # Given a LiteralI64 where the integer-value is non zero
        a == Term.LiteralI64(ival),
        ival != 0,
    ).then(
        # Setup the following fact
        IsConstantTrue(a)
    )
    # a Literal Int64 is constant False if it's zero
    yield rule(
        # Given a LiteralI64 where the integer-value is zero
        a == Term.LiteralI64(ival),
        ival == 0,
    ).then(
        # Setup the following fact
        IsConstantFalse(a)
    )

Now, we'll test our newly defined ruleset. This complete ruleset combines a few built-in RVSDG rules with our recently crafted simple constant-propagation rules.

In [9]:
if __name__ == "__main__":

    def ifelse_fold(a, b):
        c = 0
        if c:
            return a
        else:
            return b

    # Add our const-propagation rule to the basic rvsdg ruleset
    my_ruleset = rvsdg_eqsat.ruleset_rvsdg_basic | ruleset_const_propagate

    report = Report("Test", default_expanded=True)
    jt = compiler_pipeline(
        fn=ifelse_fold, pipeline_report=report, ruleset=my_ruleset
    ).jit_func
    report.display()
    run_test(ifelse_fold, jt, (12, 34))

Test

1. Frontend ▶
Frontend
Debug Info on RVSDG ▶
--------------------------------original source---------------------------------
   3|    def ifelse_fold(a, b):
   4|        c = 0
   5|        if c:
   6|            return a
   7|        else:
   8|            return b
----------------------------------inter source----------------------------------
   1|def transformed_ifelse_fold(a, b):
   2|    """#file: /tmp/ipykernel_3478/2418884614.py"""
   3|    '#loc: 4:8-4:13'
   4|    c = 0
   5|    '#loc: 5:8-8:20'
   6|    if c:
   7|        '#loc: 6:12-6:20'
   8|        __scfg_return_value__ = a
   9|    else:
  10|        __scfg_return_value__ = b
  11|    return __scfg_return_value__
RVSDG ▶
transformed_ifelse_fold = Func (Args (ArgSpec 'a' (PyNone)) (ArgSpec 'b' (PyNone)))
$0 = Region[443] <- !io a b
{
  $1 = PyInt 0
  $2 = DbgValue 'c' $1
  $3 = If $2 <- $0[0] $0[1] $0[2] $2
    $4 = Region[507] <- !io a b c
    {
      $5 = DbgValue '__scfg_return_value__' $4[1]
    } [709] -> !io=$4[0] __scfg_return_value__=$5 a=$4[1] b=$4[2] c=$4[3]
    Else
    $6 = Region[599] <- !io a b c
    {
      $7 = DbgValue '__scfg_return_value__' $6[2]
    } [743] -> !io=$6[0] __scfg_return_value__=$7 a=$6[1] b=$6[2] c=$6[3]
  Endif
} [827] -> !io=$3[0] !ret=$3[1]
2. EGraph Conversion ▶
EGraph Conversion
EGraph ▶
outer_cluster_InPorts-3 cluster_InPorts-3 outer_cluster_InPorts-0 cluster_InPorts-0 outer_cluster_Port-39 cluster_Port-39 outer_cluster_Port-15 cluster_Port-15 outer_cluster_Port-13 cluster_Port-13 outer_cluster_Port-23 cluster_Port-23 outer_cluster_Port-37 cluster_Port-37 outer_cluster_Port-26 cluster_Port-26 outer_cluster_Port-25 cluster_Port-25 outer_cluster_Port-21 cluster_Port-21 outer_cluster_Port-17 cluster_Port-17 outer_cluster_Port-28 cluster_Port-28 outer_cluster_Port-12 cluster_Port-12 outer_cluster_Port-10 cluster_Port-10 outer_cluster_PortList-40 cluster_PortList-40 outer_cluster_PortList-29 cluster_PortList-29 outer_cluster_PortList-18 cluster_PortList-18 outer_cluster_Region-5 cluster_Region-5 outer_cluster_Region-1 cluster_Region-1 outer_cluster_Region-4 cluster_Region-4 outer_cluster_Term-2 cluster_Term-2 outer_cluster_Term-36 cluster_Term-36 outer_cluster_Term-20 cluster_Term-20 outer_cluster_Term-33 cluster_Term-33 outer_cluster_Term-16 cluster_Term-16 outer_cluster_Term-14 cluster_Term-14 outer_cluster_Term-27 cluster_Term-27 outer_cluster_Term-43 cluster_Term-43 outer_cluster_Term-31 cluster_Term-31 outer_cluster_Term-6 cluster_Term-6 outer_cluster_Term-38 cluster_Term-38 outer_cluster_Term-8 cluster_Term-8 outer_cluster_Term-35 cluster_Term-35 outer_cluster_Term-22 cluster_Term-22 outer_cluster_Term-11 cluster_Term-11 outer_cluster_Term-42 cluster_Term-42 outer_cluster_Term-30 cluster_Term-30 outer_cluster_Term-41 cluster_Term-41 outer_cluster_Term-24 cluster_Term-24 outer_cluster_Term-32 cluster_Term-32 outer_cluster_Term-7 cluster_Term-7 outer_cluster_Term-19 cluster_Term-19 outer_cluster_Term-9 cluster_Term-9 outer_cluster_TermList-34 cluster_TermList-34 outer_cluster_Vec_Port-2 cluster_Vec_Port-2 outer_cluster_Vec_Port-1 cluster_Vec_Port-1 outer_cluster_Vec_Port-0 cluster_Vec_Port-0 outer_cluster_Vec_String-1 cluster_Vec_String-1 outer_cluster_Vec_String-0 cluster_Vec_String-0 outer_cluster_Vec_Term-0 cluster_Vec_Term-0 function-1-InPorts___init__:s->primitive-Vec_String-1 function-0-InPorts___init__:s->primitive-Vec_String-0 function-11-Port___init__:s->function-1-Term_getPort function-1-Term_getPort:s->function-0-Term_IfElse function-3-Port___init__:s->function-3-Region_get function-3-Region_get:s->function-0-Region___init__ function-2-Port___init__:s->function-0-Region_get function-0-Region_get:s->function-0-Region___init__ function-6-Port___init__:s->function-2-Term_DbgValue function-2-Term_DbgValue:s->function-1-Region_get function-10-Port___init__:s->function-0-Term_getPort function-0-Term_getPort:s->function-0-Term_IfElse function-8-Port___init__:s->function-1-Region_get function-1-Region_get:s->function-2-Region___init__ function-7-Port___init__:s->function-6-Region_get function-6-Region_get:s->function-2-Region___init__ function-5-Port___init__:s->function-5-Region_get function-5-Region_get:s->function-2-Region___init__ function-4-Port___init__:s->function-4-Region_get function-4-Region_get:s->function-0-Region___init__ function-9-Port___init__:s->function-7-Region_get function-7-Region_get:s->function-2-Region___init__ function-1-Port___init__:s->function-1-Term_DbgValue function-1-Term_DbgValue:s->function-0-Region_get function-0-Port___init__:s->function-2-Region_get function-2-Region_get:s->function-0-Region___init__ function-2-PortList___init__:s->primitive-Vec_Port-2 primitive-Vec_Port-2:s->function-11-Port___init__ primitive-Vec_Port-2:s->function-10-Port___init__ function-1-PortList___init__:s->primitive-Vec_Port-1 primitive-Vec_Port-1:s->function-6-Port___init__ primitive-Vec_Port-1:s->function-8-Port___init__ primitive-Vec_Port-1:s->function-7-Port___init__ primitive-Vec_Port-1:s->function-5-Port___init__ primitive-Vec_Port-1:s->function-9-Port___init__ function-0-PortList___init__:s->primitive-Vec_Port-0 primitive-Vec_Port-0:s->function-3-Port___init__ primitive-Vec_Port-0:s->function-2-Port___init__ primitive-Vec_Port-0:s->function-4-Port___init__ primitive-Vec_Port-0:s->function-1-Port___init__ primitive-Vec_Port-0:s->function-0-Port___init__ function-2-Region___init__:s->function-0-InPorts___init__ function-0-Region___init__:s->function-0-InPorts___init__ function-1-Region___init__:s->function-1-InPorts___init__ function-0-Term_IfElse:s->function-0-Term_DbgValue function-0-Term_IfElse:s->function-0-Term_RegionEnd function-0-Term_IfElse:s->function-1-Term_RegionEnd function-0-Term_IfElse:s->function-0-TermList___init__ function-10-Region_get:s->function-1-Region___init__ function-0-GraphRoot:s->function-0-Term_Func function-0-Term_Func:s->function-2-Term_RegionEnd function-8-Region_get:s->function-1-Region___init__ function-0-Term_DbgValue:s->function-0-Term_LiteralI64 function-0-Term_RegionEnd:s->function-0-PortList___init__ function-0-Term_RegionEnd:s->function-0-Region___init__ function-1-Term_RegionEnd:s->function-1-PortList___init__ function-1-Term_RegionEnd:s->function-2-Region___init__ function-0-TermList___init__:s->primitive-Vec_Term-0 function-2-Term_RegionEnd:s->function-2-PortList___init__ function-2-Term_RegionEnd:s->function-1-Region___init__ function-9-Region_get:s->function-1-Region___init__ primitive-Vec_Term-0:s->function-10-Region_get primitive-Vec_Term-0:s->function-8-Region_get primitive-Vec_Term-0:s->function-0-Term_DbgValue primitive-Vec_Term-0:s->function-9-Region_get function-1-InPorts___init__ InPorts primitive-Vec_String-1 Vec("!io", "a", "b") function-0-InPorts___init__ InPorts primitive-Vec_String-0 Vec("!io", "a", "b", "c") function-11-Port___init__ Port("!ret", ·) function-1-Term_getPort ·.getPort(·, 1) function-3-Port___init__ Port("b", ·) function-3-Region_get ·.get(·, 2) function-2-Port___init__ Port("a", ·) function-0-Region_get ·.get(·, 1) function-6-Port___init__ Port("__scfg_return_value__", ·) function-2-Term_DbgValue Term.DbgValue("__scfg_return_value__", ·) function-10-Port___init__ Port("!io", ·) function-0-Term_getPort ·.getPort(·, 0) function-8-Port___init__ Port("b", ·) function-1-Region_get ·.get(·, 2) function-7-Port___init__ Port("a", ·) function-6-Region_get ·.get(·, 1) function-5-Port___init__ Port("!io", ·) function-5-Region_get ·.get(·, 0) function-4-Port___init__ Port("c", ·) function-4-Region_get ·.get(·, 3) function-9-Port___init__ Port("c", ·) function-7-Region_get ·.get(·, 3) function-1-Port___init__ Port("__scfg_return_value__", ·) function-1-Term_DbgValue Term.DbgValue("__scfg_return_value__", ·) function-0-Port___init__ Port("!io", ·) function-2-Region_get ·.get(·, 0) function-2-PortList___init__ PortList primitive-Vec_Port-2 Vec function-1-PortList___init__ PortList primitive-Vec_Port-1 Vec function-0-PortList___init__ PortList primitive-Vec_Port-0 Vec function-2-Region___init__ Region("599", ·) function-0-Region___init__ Region("507", ·) function-1-Region___init__ Region("443", ·) function-0-Term_IfElse Term.IfElse function-10-Region_get ·.get(·, 2) function-0-GraphRoot GraphRoot function-0-Term_Func Term.Func("833", "transformed_ifelse_fold", ·) function-8-Region_get ·.get(·, 0) function-0-Term_DbgValue Term.DbgValue("c", ·) function-0-Term_LiteralI64 Term.LiteralI64(0) function-0-Term_RegionEnd Term.RegionEnd function-1-Term_RegionEnd Term.RegionEnd function-0-TermList___init__ TermList function-2-Term_RegionEnd Term.RegionEnd function-9-Region_get ·.get(·, 1) primitive-Vec_Term-0 Vec
3. EGraph Saturated ▶
outer_cluster_InPorts-3 cluster_InPorts-3 outer_cluster_InPorts-0 cluster_InPorts-0 outer_cluster_Port-67 cluster_Port-67 outer_cluster_Port-90 cluster_Port-90 outer_cluster_Port-97 cluster_Port-97 outer_cluster_Port-83 cluster_Port-83 outer_cluster_Port-95 cluster_Port-95 outer_cluster_Port-63 cluster_Port-63 outer_cluster_Port-72 cluster_Port-72 outer_cluster_Port-81 cluster_Port-81 outer_cluster_Port-65 cluster_Port-65 outer_cluster_Port-88 cluster_Port-88 outer_cluster_Port-77 cluster_Port-77 outer_cluster_Port-61 cluster_Port-61 outer_cluster_PortList-18 cluster_PortList-18 outer_cluster_PortList-40 cluster_PortList-40 outer_cluster_PortList-29 cluster_PortList-29 outer_cluster_Region-4 cluster_Region-4 outer_cluster_Region-1 cluster_Region-1 outer_cluster_Region-5 cluster_Region-5 outer_cluster_String-536870921 cluster_String-536870921 outer_cluster_String-2952790028 cluster_String-2952790028 outer_cluster_split-0-primitive-String-2952790028 cluster_split-0-primitive-String-2952790028 outer_cluster_split-0-primitive-String-536870921 cluster_split-0-primitive-String-536870921 outer_cluster_String-10 cluster_String-10 outer_cluster_split-1-primitive-String-10 cluster_split-1-primitive-String-10 outer_cluster_split-0-primitive-String-1879048202 cluster_split-0-primitive-String-1879048202 outer_cluster_String-2147483657 cluster_String-2147483657 outer_cluster_split-0-primitive-String-2147483657 cluster_split-0-primitive-String-2147483657 outer_cluster_String-2684354576 cluster_String-2684354576 outer_cluster_split-0-primitive-String-10 cluster_split-0-primitive-String-10 outer_cluster_String-1879048202 cluster_String-1879048202 outer_cluster_Term-35 cluster_Term-35 outer_cluster_Term-31 cluster_Term-31 outer_cluster_Term-79 cluster_Term-79 outer_cluster_Term-87 cluster_Term-87 outer_cluster_Term-80 cluster_Term-80 outer_cluster_Term-32 cluster_Term-32 outer_cluster_Term-74 cluster_Term-74 outer_cluster_Term-92 cluster_Term-92 outer_cluster_Term-30 cluster_Term-30 outer_cluster_Term-94 cluster_Term-94 outer_cluster_Term-41 cluster_Term-41 outer_cluster_Term-43 cluster_Term-43 outer_cluster_Term-57 cluster_Term-57 outer_cluster_Term-93 cluster_Term-93 outer_cluster_Term-85 cluster_Term-85 outer_cluster_Term-86 cluster_Term-86 outer_cluster_Term-56 cluster_Term-56 outer_cluster_Term-33 cluster_Term-33 outer_cluster_Term-19 cluster_Term-19 outer_cluster_Term-42 cluster_Term-42 outer_cluster_Term-8 cluster_Term-8 outer_cluster_Term-69 cluster_Term-69 outer_cluster_TermList-34 cluster_TermList-34 outer_cluster_Unit-0 cluster_Unit-0 outer_cluster_Vec_Port-6 cluster_Vec_Port-6 outer_cluster_Vec_Port-11 cluster_Vec_Port-11 outer_cluster_Vec_Port-12 cluster_Vec_Port-12 outer_cluster_Vec_String-0 cluster_Vec_String-0 outer_cluster_Vec_String-1 cluster_Vec_String-1 outer_cluster_Vec_Term-0 cluster_Vec_Term-0 function-1-InPorts___init__:s->primitive-Vec_String-1 function-0-InPorts___init__:s->primitive-Vec_String-0 function-15-Port___init__:s->function-9-PortList_getValue function-9-PortList_getValue:s->function-4-PortList___init__ function-3-PortList___getitem__:s->function-4-PortList___init__ function-4-PortList___init__:s->primitive-Vec_Port-12 function-16-Port___init__:s->function-13-PortList_getValue function-13-PortList_getValue:s->function-4-PortList___init__ function-9-PortList___getitem__:s->function-4-PortList___init__ function-20-Port___init__:s->function-11-PortList_getValue function-11-PortList_getValue:s->function-4-PortList___init__ function-11-PortList___getitem__:s->function-4-PortList___init__ function-11-Port___init__:s->function-7-PortList_getValue function-7-PortList_getValue:s->function-4-PortList___init__ function-7-PortList___getitem__:s->function-4-PortList___init__ function-19-Port___init__:s->function-10-PortList_getValue function-10-PortList_getValue:s->function-3-PortList___init__ function-10-PortList___getitem__:s->function-3-PortList___init__ function-3-PortList___init__:s->primitive-Vec_Port-11 function-4-Port___init__:s->function-1-PortList_getValue function-1-PortList_getValue:s->function-4-PortList___init__ function-1-PortList___getitem__:s->function-4-PortList___init__ function-7-Port___init__:s->function-2-Port_value function-2-Port_value:s->function-7-Port___init__ function-4-PortList___getitem__:s->function-0-PortList___init__ function-0-PortList___init__:s->primitive-Vec_Port-6 function-10-Port___init__:s->function-12-PortList_getValue function-12-PortList_getValue:s->function-3-PortList___init__ function-6-PortList___getitem__:s->function-3-PortList___init__ function-9-Port___init__:s->function-6-PortList_getValue function-6-PortList_getValue:s->function-3-PortList___init__ function-2-PortList___getitem__:s->function-3-PortList___init__ function-14-Port___init__:s->function-8-PortList_getValue function-8-PortList_getValue:s->function-3-PortList___init__ function-8-PortList___getitem__:s->function-3-PortList___init__ function-8-Port___init__:s->function-3-Port_value function-3-Port_value:s->function-8-Port___init__ function-5-PortList___getitem__:s->function-0-PortList___init__ function-3-Port___init__:s->function-0-PortList_getValue function-0-PortList_getValue:s->function-3-PortList___init__ function-0-PortList___getitem__:s->function-3-PortList___init__ primitive-Vec_Port-11:s->function-10-PortList___getitem__ primitive-Vec_Port-11:s->function-6-PortList___getitem__ primitive-Vec_Port-11:s->function-2-PortList___getitem__ primitive-Vec_Port-11:s->function-8-PortList___getitem__ primitive-Vec_Port-11:s->function-0-PortList___getitem__ primitive-Vec_Port-6:s->function-4-PortList___getitem__ primitive-Vec_Port-6:s->function-5-PortList___getitem__ primitive-Vec_Port-12:s->function-3-PortList___getitem__ primitive-Vec_Port-12:s->function-9-PortList___getitem__ primitive-Vec_Port-12:s->function-11-PortList___getitem__ primitive-Vec_Port-12:s->function-7-PortList___getitem__ primitive-Vec_Port-12:s->function-1-PortList___getitem__ function-1-Region___init__:s->function-1-InPorts___init__ function-0-Region___init__:s->function-0-InPorts___init__ function-2-Region___init__:s->function-0-InPorts___init__ function-13-Port_name:s->function-2-PortList___getitem__ function-18-Port_name:s->function-6-PortList___getitem__ function-19-Port_name:s->function-7-PortList___getitem__ function-15-Port_name:s->function-3-PortList___getitem__ function-12-Port_name:s->function-0-PortList___getitem__ function-16-Port_name:s->function-4-PortList___getitem__ function-21-Port_name:s->function-9-PortList___getitem__ function-22-Port_name:s->function-10-PortList___getitem__ function-23-Port_name:s->function-11-PortList___getitem__ function-17-Port_name:s->function-5-PortList___getitem__ function-14-Port_name:s->function-1-PortList___getitem__ function-20-Port_name:s->function-8-PortList___getitem__ function-0-Term_IfElse:s->function-0-Term_DbgValue function-0-Term_IfElse:s->function-0-Term_RegionEnd function-0-Term_IfElse:s->function-1-Term_RegionEnd function-0-Term_IfElse:s->function-0-TermList___init__ function-0-Term_DbgValue:s->function-0-Term_DbgValue function-0-Term_RegionEnd:s->function-3-PortList___init__ function-0-Term_RegionEnd:s->function-0-Region___init__ function-1-Term_RegionEnd:s->function-4-PortList___init__ function-1-Term_RegionEnd:s->function-2-Region___init__ function-0-TermList___init__:s->primitive-Vec_Term-0 function-0-Region_get:s->function-1-Region___init__ function-11-Region_get:s->function-0-Region___init__ function-3-Term_DbgValue:s->function-8-Port_value function-8-Port_value:s->function-9-Port___init__ function-4-Port_value:s->function-10-Port___init__ function-5-Term_getPort:s->function-2-Term_RegionEnd function-2-Term_RegionEnd:s->function-0-PortList___init__ function-2-Term_RegionEnd:s->function-1-Region___init__ function-12-Region_get:s->function-2-Region___init__ function-5-Port_value:s->function-11-Port___init__ function-1-Region_get:s->function-1-Region___init__ function-4-Term_getPort:s->function-0-Term_IfElse function-5-PortList_getValue:s->function-0-PortList___init__ function-15-Region_get:s->function-0-Region___init__ function-9-Port_value:s->function-19-Port___init__ function-6-Term_getPort:s->function-2-Term_RegionEnd function-0-GraphRoot:s->function-0-Term_Func function-0-Term_Func:s->function-2-Term_RegionEnd function-9-Region_get:s->function-2-Region___init__ function-1-Port_value:s->function-4-Port___init__ function-16-Region_get:s->function-2-Region___init__ function-10-Port_value:s->function-20-Port___init__ function-13-Region_get:s->function-0-Region___init__ function-6-Port_value:s->function-14-Port___init__ function-14-Region_get:s->function-2-Region___init__ function-4-Term_DbgValue:s->function-11-Port_value function-11-Port_value:s->function-15-Port___init__ function-7-Port_value:s->function-16-Port___init__ function-7-Region_get:s->function-0-Region___init__ function-0-Port_value:s->function-3-Port___init__ function-2-Region_get:s->function-1-Region___init__ function-3-Term_getPort:s->function-0-Term_IfElse function-4-PortList_getValue:s->function-0-PortList___init__ primitive-Vec_Term-0:s->function-0-Region_get primitive-Vec_Term-0:s->function-1-Region_get primitive-Vec_Term-0:s->function-2-Region_get primitive-Vec_Term-0:s->function-1-Term_LiteralI64 function-1-IsConstantFalse:s->function-0-Term_DbgValue function-1-InPorts___init__ InPorts primitive-Vec_String-1 Vec("!io", "a", "b") function-0-InPorts___init__ InPorts primitive-Vec_String-0 Vec("!io", "a", "b", "c") function-15-Port___init__ Port("__scfg_return_value__", ·) function-9-PortList_getValue ·.getValue(·, 3) function-3-PortList___getitem__ ·[1] function-4-PortList___init__ PortList function-16-Port___init__ Port("b", ·) function-13-PortList_getValue ·.getValue(·, 1) function-9-PortList___getitem__ ·[3] function-20-Port___init__ Port("c", ·) function-11-PortList_getValue ·.getValue(·, 4) function-11-PortList___getitem__ ·[4] function-11-Port___init__ Port("a", ·) function-7-PortList_getValue ·.getValue(·, 2) function-7-PortList___getitem__ ·[2] function-19-Port___init__ Port("c", ·) function-10-PortList_getValue ·.getValue(·, 4) function-10-PortList___getitem__ ·[4] function-3-PortList___init__ PortList function-4-Port___init__ Port("!io", ·) function-1-PortList_getValue ·.getValue(·, 0) function-1-PortList___getitem__ ·[0] function-7-Port___init__ Port("!io", ·) function-2-Port_value ·.value function-4-PortList___getitem__ ·[0] function-0-PortList___init__ PortList function-10-Port___init__ Port("a", ·) function-12-PortList_getValue ·.getValue(·, 1) function-6-PortList___getitem__ ·[2] function-9-Port___init__ Port("__scfg_return_value__", ·) function-6-PortList_getValue ·.getValue(·, 2) function-2-PortList___getitem__ ·[1] function-14-Port___init__ Port("b", ·) function-8-PortList_getValue ·.getValue(·, 3) function-8-PortList___getitem__ ·[3] function-8-Port___init__ Port("!ret", ·) function-3-Port_value ·.value function-5-PortList___getitem__ ·[1] function-3-Port___init__ Port("!io", ·) function-0-PortList_getValue ·.getValue(·, 0) function-0-PortList___getitem__ ·[0] primitive-Vec_Port-11 Vec primitive-Vec_Port-6 Vec primitive-Vec_Port-12 Vec function-1-Region___init__ Region("443", ·) function-0-Region___init__ Region("507", ·) function-2-Region___init__ Region("599", ·) function-13-Port_name ·.name primitive-String-536870921 "__scfg_return_value__" function-18-Port_name ·.name primitive-String-2952790028 "a" function-19-Port_name ·.name split-0-primitive-String-2952790028 "a" function-15-Port_name ·.name split-0-primitive-String-536870921 "__scfg_return_value__" function-12-Port_name ·.name primitive-String-10 "!io" function-16-Port_name ·.name split-1-primitive-String-10 "!io" function-21-Port_name ·.name split-0-primitive-String-1879048202 "b" function-22-Port_name ·.name primitive-String-2147483657 "c" function-23-Port_name ·.name split-0-primitive-String-2147483657 "c" function-17-Port_name ·.name primitive-String-2684354576 "!ret" function-14-Port_name ·.name split-0-primitive-String-10 "!io" function-20-Port_name ·.name primitive-String-1879048202 "b" function-0-Term_IfElse Term.IfElse function-0-Term_DbgValue Term.DbgValue("c", ·) function-0-Term_RegionEnd Term.RegionEnd function-1-Term_RegionEnd Term.RegionEnd function-0-TermList___init__ TermList function-0-Region_get ·.get(·, 0) function-11-Region_get ·.get(·, 1) function-3-Term_DbgValue Term.DbgValue("__scfg_return_value__", ·) function-8-Port_value ·.value function-4-Port_value ·.value function-5-Term_getPort ·.getPort(·, 0) function-2-Term_RegionEnd Term.RegionEnd function-12-Region_get ·.get(·, 1) function-5-Port_value ·.value function-1-Region_get ·.get(·, 1) function-4-Term_getPort ·.getPort(·, 1) function-5-PortList_getValue ·.getValue(·, 1) function-15-Region_get ·.get(·, 3) function-9-Port_value ·.value function-6-Term_getPort ·.getPort(·, 1) function-0-GraphRoot GraphRoot function-0-Term_Func Term.Func("833", "transformed_ifelse_fold", ·) function-9-Region_get ·.get(·, 0) function-1-Port_value ·.value function-16-Region_get ·.get(·, 3) function-10-Port_value ·.value function-13-Region_get ·.get(·, 2) function-6-Port_value ·.value function-14-Region_get ·.get(·, 2) function-4-Term_DbgValue Term.DbgValue("__scfg_return_value__", ·) function-11-Port_value ·.value function-7-Port_value ·.value function-7-Region_get ·.get(·, 0) function-0-Port_value ·.value function-2-Region_get ·.get(·, 2) function-1-Term_LiteralI64 Term.LiteralI64(0) function-3-Term_getPort ·.getPort(·, 0) function-4-PortList_getValue ·.getValue(·, 0) primitive-Vec_Term-0 Vec function-1-IsConstantFalse IsConstantFalse primitive-Unit-0 ()
4. EGraph Extraction ▶
EGraph Extraction
Cost ▶
6194507.0
Extracted ▶
transformed_ifelse_fold = Func (Args (ArgSpec 'a' (PyNone)) (ArgSpec 'b' (PyNone)))
$0 = Region[950] <- !io a b
{
  $1 = PyInt 0
  $2 = If $1 <- $0[0] $0[1] $0[2] $1
    $3 = Region[964] <- !io a b c
    {
    } [1017] -> !io=$3[0] __scfg_return_value__=$3[1] a=$3[1] b=$3[2] c=$3[3]
    Else
    $4 = Region[1029] <- !io a b c
    {
    } [1082] -> !io=$4[0] __scfg_return_value__=$4[2] a=$4[1] b=$4[2] c=$4[3]
  Endif
} [1136] -> !io=$2[0] !ret=$2[1]
5. Backend ▶
Backend
LLVM ▶
; ModuleID = ""
target triple = "unknown-unknown-unknown"
target datalayout = ""

define ptr @"foo"(ptr %".1", ptr %".2")
{
.4:
  %".5" = alloca ptr
  store ptr null, ptr %".5"
  br label %".7"
.7:
  br label %".9"
.9:
  %".11" = call ptr @"PyLong_FromSsize_t"(i64 0)
  %".12" = call i32 @"PyObject_IsTrue"(ptr %".11")
  %".13" = icmp ne i32 0, %".12"
  br i1 %".13", label %"then", label %"else"
then:
  br label %"endif"
else:
  br label %"endif"
endif:
  %".17" = phi  ptr [%".1", %"then"], [%".2", %"else"]
  %".18" = phi  ptr [%".1", %"then"], [%".1", %"else"]
  %".19" = phi  ptr [%".2", %"then"], [%".2", %"else"]
  %".20" = phi  ptr [%".11", %"then"], [%".11", %"else"]
  ret ptr %".17"
}

declare ptr @"PyLong_FromSsize_t"(i64 %".1")

declare i32 @"PyObject_IsTrue"(ptr %".1")

In the example above, observe that a new IsConstantFalse node appears on the LiteralI64(0). This indicates that our ruleset is successfully identifying constants as intended.

Rules for folding if-else¶

Now, let's create a more complex rule. This time, we'll fold an if-else expression when its condition is a constant, simplifying the code by resolving the branch at compile time.

In [10]:
@ruleset
def ruleset_const_fold_if_else(a: Term, b: Term, c: Term, operands: TermList):
    yield rewrite(
        # Define the if-else pattern to match
        Term.IfElse(cond=a, then=b, orelse=c, operands=operands),
        subsume=True,  # subsume to disable extracting the original term
    ).to(
        # Define the target expression
        # This apply region `b` (then) using the `operands`.
        Term.Apply(b, operands),
        # Given that the condition is constant True
        IsConstantTrue(a),
    )
    yield rewrite(
        # Define the if-else pattern to match
        Term.IfElse(cond=a, then=b, orelse=c, operands=operands),
        subsume=True,  # subsume to disable extracting the original term
    ).to(
        # Define the target expression.
        # This apply region `c` (orelse) using the `operands`.
        Term.Apply(c, operands),
        # Given that the condition is constant False
        IsConstantFalse(a),
    )
In [11]:
if __name__ == "__main__":
    my_ruleset = (
        rvsdg_eqsat.ruleset_rvsdg_basic
        | ruleset_const_propagate
        | ruleset_const_fold_if_else  # <-- the new rule for if-else
    )

    report = Report("Test", default_expanded=True)
    jt = compiler_pipeline(
        fn=ifelse_fold, pipeline_report=report, ruleset=my_ruleset
    ).jit_func
    report.display()
    run_test(ifelse_fold, jt, (12, 34))

Test

1. Frontend ▶
Frontend
Debug Info on RVSDG ▶
--------------------------------original source---------------------------------
   3|    def ifelse_fold(a, b):
   4|        c = 0
   5|        if c:
   6|            return a
   7|        else:
   8|            return b
----------------------------------inter source----------------------------------
   1|def transformed_ifelse_fold(a, b):
   2|    """#file: /tmp/ipykernel_3478/2418884614.py"""
   3|    '#loc: 4:8-4:13'
   4|    c = 0
   5|    '#loc: 5:8-8:20'
   6|    if c:
   7|        '#loc: 6:12-6:20'
   8|        __scfg_return_value__ = a
   9|    else:
  10|        __scfg_return_value__ = b
  11|    return __scfg_return_value__
RVSDG ▶
transformed_ifelse_fold = Func (Args (ArgSpec 'a' (PyNone)) (ArgSpec 'b' (PyNone)))
$0 = Region[443] <- !io a b
{
  $1 = PyInt 0
  $2 = DbgValue 'c' $1
  $3 = If $2 <- $0[0] $0[1] $0[2] $2
    $4 = Region[507] <- !io a b c
    {
      $5 = DbgValue '__scfg_return_value__' $4[1]
    } [709] -> !io=$4[0] __scfg_return_value__=$5 a=$4[1] b=$4[2] c=$4[3]
    Else
    $6 = Region[599] <- !io a b c
    {
      $7 = DbgValue '__scfg_return_value__' $6[2]
    } [743] -> !io=$6[0] __scfg_return_value__=$7 a=$6[1] b=$6[2] c=$6[3]
  Endif
} [827] -> !io=$3[0] !ret=$3[1]
2. EGraph Conversion ▶
EGraph Conversion
EGraph ▶
outer_cluster_InPorts-0 cluster_InPorts-0 outer_cluster_InPorts-3 cluster_InPorts-3 outer_cluster_Port-21 cluster_Port-21 outer_cluster_Port-13 cluster_Port-13 outer_cluster_Port-37 cluster_Port-37 outer_cluster_Port-26 cluster_Port-26 outer_cluster_Port-15 cluster_Port-15 outer_cluster_Port-17 cluster_Port-17 outer_cluster_Port-25 cluster_Port-25 outer_cluster_Port-39 cluster_Port-39 outer_cluster_Port-28 cluster_Port-28 outer_cluster_Port-12 cluster_Port-12 outer_cluster_Port-10 cluster_Port-10 outer_cluster_Port-23 cluster_Port-23 outer_cluster_PortList-18 cluster_PortList-18 outer_cluster_PortList-29 cluster_PortList-29 outer_cluster_PortList-40 cluster_PortList-40 outer_cluster_Region-4 cluster_Region-4 outer_cluster_Region-5 cluster_Region-5 outer_cluster_Region-1 cluster_Region-1 outer_cluster_Term-24 cluster_Term-24 outer_cluster_Term-33 cluster_Term-33 outer_cluster_Term-27 cluster_Term-27 outer_cluster_Term-6 cluster_Term-6 outer_cluster_Term-14 cluster_Term-14 outer_cluster_Term-30 cluster_Term-30 outer_cluster_Term-7 cluster_Term-7 outer_cluster_Term-16 cluster_Term-16 outer_cluster_Term-38 cluster_Term-38 outer_cluster_Term-19 cluster_Term-19 outer_cluster_Term-42 cluster_Term-42 outer_cluster_Term-31 cluster_Term-31 outer_cluster_Term-22 cluster_Term-22 outer_cluster_Term-36 cluster_Term-36 outer_cluster_Term-32 cluster_Term-32 outer_cluster_Term-43 cluster_Term-43 outer_cluster_Term-20 cluster_Term-20 outer_cluster_Term-8 cluster_Term-8 outer_cluster_Term-41 cluster_Term-41 outer_cluster_Term-2 cluster_Term-2 outer_cluster_Term-11 cluster_Term-11 outer_cluster_Term-35 cluster_Term-35 outer_cluster_Term-9 cluster_Term-9 outer_cluster_TermList-34 cluster_TermList-34 outer_cluster_Vec_Port-2 cluster_Vec_Port-2 outer_cluster_Vec_Port-1 cluster_Vec_Port-1 outer_cluster_Vec_Port-0 cluster_Vec_Port-0 outer_cluster_Vec_String-1 cluster_Vec_String-1 outer_cluster_Vec_String-0 cluster_Vec_String-0 outer_cluster_Vec_Term-0 cluster_Vec_Term-0 function-0-InPorts___init__:s->primitive-Vec_String-0 function-1-InPorts___init__:s->primitive-Vec_String-1 function-5-Port___init__:s->function-5-Region_get function-5-Region_get:s->function-2-Region___init__ function-2-Port___init__:s->function-0-Region_get function-0-Region_get:s->function-0-Region___init__ function-10-Port___init__:s->function-0-Term_getPort function-0-Term_getPort:s->function-0-Term_IfElse function-8-Port___init__:s->function-1-Region_get function-1-Region_get:s->function-2-Region___init__ function-3-Port___init__:s->function-3-Region_get function-3-Region_get:s->function-0-Region___init__ function-4-Port___init__:s->function-4-Region_get function-4-Region_get:s->function-0-Region___init__ function-7-Port___init__:s->function-6-Region_get function-6-Region_get:s->function-2-Region___init__ function-11-Port___init__:s->function-1-Term_getPort function-1-Term_getPort:s->function-0-Term_IfElse function-9-Port___init__:s->function-7-Region_get function-7-Region_get:s->function-2-Region___init__ function-1-Port___init__:s->function-1-Term_DbgValue function-1-Term_DbgValue:s->function-0-Region_get function-0-Port___init__:s->function-2-Region_get function-2-Region_get:s->function-0-Region___init__ function-6-Port___init__:s->function-2-Term_DbgValue function-2-Term_DbgValue:s->function-1-Region_get function-0-PortList___init__:s->primitive-Vec_Port-0 primitive-Vec_Port-0:s->function-2-Port___init__ primitive-Vec_Port-0:s->function-3-Port___init__ primitive-Vec_Port-0:s->function-4-Port___init__ primitive-Vec_Port-0:s->function-1-Port___init__ primitive-Vec_Port-0:s->function-0-Port___init__ function-1-PortList___init__:s->primitive-Vec_Port-1 primitive-Vec_Port-1:s->function-5-Port___init__ primitive-Vec_Port-1:s->function-8-Port___init__ primitive-Vec_Port-1:s->function-7-Port___init__ primitive-Vec_Port-1:s->function-9-Port___init__ primitive-Vec_Port-1:s->function-6-Port___init__ function-2-PortList___init__:s->primitive-Vec_Port-2 primitive-Vec_Port-2:s->function-10-Port___init__ primitive-Vec_Port-2:s->function-11-Port___init__ function-1-Region___init__:s->function-1-InPorts___init__ function-2-Region___init__:s->function-0-InPorts___init__ function-0-Region___init__:s->function-0-InPorts___init__ function-10-Region_get:s->function-1-Region___init__ function-1-Term_RegionEnd:s->function-1-PortList___init__ function-1-Term_RegionEnd:s->function-2-Region___init__ function-0-Term_IfElse:s->function-1-Term_RegionEnd function-0-Term_IfElse:s->function-0-Term_RegionEnd function-0-Term_IfElse:s->function-0-Term_DbgValue function-0-Term_IfElse:s->function-0-TermList___init__ function-0-Term_RegionEnd:s->function-0-PortList___init__ function-0-Term_RegionEnd:s->function-0-Region___init__ function-0-Term_Func:s->function-2-Term_RegionEnd function-2-Term_RegionEnd:s->function-2-PortList___init__ function-2-Term_RegionEnd:s->function-1-Region___init__ function-8-Region_get:s->function-1-Region___init__ function-9-Region_get:s->function-1-Region___init__ function-0-GraphRoot:s->function-0-Term_Func function-0-Term_DbgValue:s->function-0-Term_LiteralI64 function-0-TermList___init__:s->primitive-Vec_Term-0 primitive-Vec_Term-0:s->function-10-Region_get primitive-Vec_Term-0:s->function-8-Region_get primitive-Vec_Term-0:s->function-9-Region_get primitive-Vec_Term-0:s->function-0-Term_DbgValue function-0-InPorts___init__ InPorts primitive-Vec_String-0 Vec("!io", "a", "b", "c") function-1-InPorts___init__ InPorts primitive-Vec_String-1 Vec("!io", "a", "b") function-5-Port___init__ Port("!io", ·) function-5-Region_get ·.get(·, 0) function-2-Port___init__ Port("a", ·) function-0-Region_get ·.get(·, 1) function-10-Port___init__ Port("!io", ·) function-0-Term_getPort ·.getPort(·, 0) function-8-Port___init__ Port("b", ·) function-1-Region_get ·.get(·, 2) function-3-Port___init__ Port("b", ·) function-3-Region_get ·.get(·, 2) function-4-Port___init__ Port("c", ·) function-4-Region_get ·.get(·, 3) function-7-Port___init__ Port("a", ·) function-6-Region_get ·.get(·, 1) function-11-Port___init__ Port("!ret", ·) function-1-Term_getPort ·.getPort(·, 1) function-9-Port___init__ Port("c", ·) function-7-Region_get ·.get(·, 3) function-1-Port___init__ Port("__scfg_return_value__", ·) function-1-Term_DbgValue Term.DbgValue("__scfg_return_value__", ·) function-0-Port___init__ Port("!io", ·) function-2-Region_get ·.get(·, 0) function-6-Port___init__ Port("__scfg_return_value__", ·) function-2-Term_DbgValue Term.DbgValue("__scfg_return_value__", ·) function-0-PortList___init__ PortList primitive-Vec_Port-0 Vec function-1-PortList___init__ PortList primitive-Vec_Port-1 Vec function-2-PortList___init__ PortList primitive-Vec_Port-2 Vec function-1-Region___init__ Region("443", ·) function-2-Region___init__ Region("599", ·) function-0-Region___init__ Region("507", ·) function-10-Region_get ·.get(·, 2) function-1-Term_RegionEnd Term.RegionEnd function-0-Term_LiteralI64 Term.LiteralI64(0) function-0-Term_IfElse Term.IfElse function-0-Term_RegionEnd Term.RegionEnd function-0-Term_Func Term.Func("833", "transformed_ifelse_fold", ·) function-2-Term_RegionEnd Term.RegionEnd function-8-Region_get ·.get(·, 0) function-9-Region_get ·.get(·, 1) function-0-GraphRoot GraphRoot function-0-Term_DbgValue Term.DbgValue("c", ·) function-0-TermList___init__ TermList primitive-Vec_Term-0 Vec
3. EGraph Saturated ▶
outer_cluster_InPorts-3 cluster_InPorts-3 outer_cluster_InPorts-0 cluster_InPorts-0 outer_cluster_Port-86 cluster_Port-86 outer_cluster_Port-102 cluster_Port-102 outer_cluster_Port-67 cluster_Port-67 outer_cluster_Port-61 cluster_Port-61 outer_cluster_Port-93 cluster_Port-93 outer_cluster_Port-82 cluster_Port-82 outer_cluster_Port-73 cluster_Port-73 outer_cluster_Port-65 cluster_Port-65 outer_cluster_Port-88 cluster_Port-88 outer_cluster_Port-95 cluster_Port-95 outer_cluster_Port-100 cluster_Port-100 outer_cluster_PortList-40 cluster_PortList-40 outer_cluster_PortList-18 cluster_PortList-18 outer_cluster_PortList-29 cluster_PortList-29 outer_cluster_Region-5 cluster_Region-5 outer_cluster_Region-4 cluster_Region-4 outer_cluster_Region-1 cluster_Region-1 outer_cluster_split-0-primitive-String-2147483657 cluster_split-0-primitive-String-2147483657 outer_cluster_String-2147483657 cluster_String-2147483657 outer_cluster_String-2684354576 cluster_String-2684354576 outer_cluster_String-536870921 cluster_String-536870921 outer_cluster_split-0-primitive-String-1879048202 cluster_split-0-primitive-String-1879048202 outer_cluster_String-10 cluster_String-10 outer_cluster_split-0-primitive-String-536870921 cluster_split-0-primitive-String-536870921 outer_cluster_split-0-primitive-String-10 cluster_split-0-primitive-String-10 outer_cluster_split-0-primitive-String-2952790028 cluster_split-0-primitive-String-2952790028 outer_cluster_String-2952790028 cluster_String-2952790028 outer_cluster_String-1879048202 cluster_String-1879048202 outer_cluster_Term-42 cluster_Term-42 outer_cluster_Term-56 cluster_Term-56 outer_cluster_Term-90 cluster_Term-90 outer_cluster_Term-69 cluster_Term-69 outer_cluster_Term-98 cluster_Term-98 outer_cluster_Term-43 cluster_Term-43 outer_cluster_Term-85 cluster_Term-85 outer_cluster_Term-91 cluster_Term-91 outer_cluster_Term-99 cluster_Term-99 outer_cluster_Term-84 cluster_Term-84 outer_cluster_Term-35 cluster_Term-35 outer_cluster_Term-92 cluster_Term-92 outer_cluster_Term-19 cluster_Term-19 outer_cluster_Term-30 cluster_Term-30 outer_cluster_Term-41 cluster_Term-41 outer_cluster_Term-97 cluster_Term-97 outer_cluster_TermList-34 cluster_TermList-34 outer_cluster_Unit-0 cluster_Unit-0 outer_cluster_Vec_Port-13 cluster_Vec_Port-13 outer_cluster_Vec_Port-14 cluster_Vec_Port-14 outer_cluster_Vec_Port-8 cluster_Vec_Port-8 outer_cluster_Vec_String-0 cluster_Vec_String-0 outer_cluster_Vec_String-1 cluster_Vec_String-1 outer_cluster_Vec_Term-6 cluster_Vec_Term-6 function-1-InPorts___init__:s->primitive-Vec_String-1 function-0-InPorts___init__:s->primitive-Vec_String-0 function-3-Port___init__:s->function-16-PortList_getValue function-16-PortList_getValue:s->function-3-PortList___init__ function-8-PortList___getitem__:s->function-3-PortList___init__ function-3-PortList___init__:s->primitive-Vec_Port-13 function-12-Port___init__:s->function-7-TermList___getitem__ function-7-TermList___getitem__:s->function-0-TermList___init__ function-13-PortList___getitem__:s->function-4-PortList___init__ function-4-PortList___init__:s->primitive-Vec_Port-14 function-6-Port___init__:s->function-13-Port_value function-13-Port_value:s->function-7-Port___init__ function-3-PortList___getitem__:s->function-4-PortList___init__ function-0-Port___init__:s->function-0-PortList_getValue function-0-PortList_getValue:s->function-3-PortList___init__ function-0-PortList___getitem__:s->function-3-PortList___init__ function-5-Port___init__:s->function-11-PortList_getValue function-11-PortList_getValue:s->function-3-PortList___init__ function-10-PortList___getitem__:s->function-3-PortList___init__ function-7-Port___init__:s->function-14-Port_value function-14-Port_value:s->function-6-Port___init__ function-6-PortList___getitem__:s->function-0-PortList___init__ function-0-PortList___init__:s->primitive-Vec_Port-8 function-1-Port___init__:s->function-3-Port_value function-3-Port_value:s->function-1-Port___init__ function-4-PortList___getitem__:s->function-0-PortList___init__ function-7-PortList___getitem__:s->function-4-PortList___init__ function-2-Port___init__:s->function-8-PortList_getValue function-8-PortList_getValue:s->function-3-PortList___init__ function-2-PortList___getitem__:s->function-3-PortList___init__ function-4-Port___init__:s->function-9-PortList_getValue function-9-PortList_getValue:s->function-4-PortList___init__ function-9-PortList___getitem__:s->function-4-PortList___init__ function-8-Port___init__:s->function-12-PortList_getValue function-12-PortList_getValue:s->function-4-PortList___init__ function-11-PortList___getitem__:s->function-4-PortList___init__ function-11-Port___init__:s->function-14-PortList_getValue function-14-PortList_getValue:s->function-3-PortList___init__ function-12-PortList___getitem__:s->function-3-PortList___init__ primitive-Vec_Port-8:s->function-6-PortList___getitem__ primitive-Vec_Port-8:s->function-4-PortList___getitem__ primitive-Vec_Port-13:s->function-8-PortList___getitem__ primitive-Vec_Port-13:s->function-0-PortList___getitem__ primitive-Vec_Port-13:s->function-10-PortList___getitem__ primitive-Vec_Port-13:s->function-2-PortList___getitem__ primitive-Vec_Port-13:s->function-12-PortList___getitem__ primitive-Vec_Port-14:s->function-13-PortList___getitem__ primitive-Vec_Port-14:s->function-3-PortList___getitem__ primitive-Vec_Port-14:s->function-7-PortList___getitem__ primitive-Vec_Port-14:s->function-9-PortList___getitem__ primitive-Vec_Port-14:s->function-11-PortList___getitem__ function-2-Region___init__:s->function-0-InPorts___init__ function-1-Region___init__:s->function-1-InPorts___init__ function-0-Region___init__:s->function-0-InPorts___init__ function-10-Port_name:s->function-13-PortList___getitem__ function-9-Port_name:s->function-12-PortList___getitem__ function-4-Port_name:s->function-6-PortList___getitem__ function-1-Port_name:s->function-2-PortList___getitem__ function-8-Port_name:s->function-11-PortList___getitem__ function-0-Port_name:s->function-0-PortList___getitem__ function-2-Port_name:s->function-3-PortList___getitem__ function-3-Port_name:s->function-4-PortList___getitem__ function-6-Port_name:s->function-9-PortList___getitem__ function-5-Port_name:s->function-8-PortList___getitem__ function-7-Port_name:s->function-10-PortList___getitem__ function-0-Term_Func:s->function-2-Term_RegionEnd function-2-Term_RegionEnd:s->function-0-PortList___init__ function-2-Term_RegionEnd:s->function-1-Region___init__ function-2-Region_get:s->function-0-Region___init__ function-2-Port_value:s->function-0-Port___init__ function-8-Region_get:s->function-0-Region___init__ function-8-Port_value:s->function-5-Port___init__ function-3-Region_get:s->function-2-Region___init__ function-4-Region_get:s->function-1-Region___init__ function-3-Term_getPort:s->function-1-Term_Apply function-1-Term_Apply:s->function-0-TermList___init__ function-1-Term_Apply:s->function-1-Term_RegionEnd function-4-PortList_getValue:s->function-0-PortList___init__ function-10-PortList_getValue:s->function-4-PortList___init__ function-3-TermList___getitem__:s->function-0-TermList___init__ function-0-TermList___init__:s->primitive-Vec_Term-6 function-12-Region_get:s->function-2-Region___init__ function-3-Term_DbgValue:s->function-12-Port_value function-12-Port_value:s->function-12-Port___init__ function-15-PortList_getValue:s->function-4-PortList___init__ function-0-GraphRoot:s->function-0-Term_Func function-6-Region_get:s->function-2-Region___init__ function-7-Region_get:s->function-1-Region___init__ function-6-Port_value:s->function-4-Port___init__ function-5-TermList___getitem__:s->function-0-TermList___init__ function-9-Region_get:s->function-2-Region___init__ function-10-Region_get:s->function-1-Region___init__ function-6-TermList___getitem__:s->function-0-TermList___init__ function-2-Term_DbgValue:s->function-9-Port_value function-9-Port_value:s->function-8-Port___init__ function-7-Term_getPort:s->function-1-Term_IfElse function-1-Term_IfElse:s->function-0-TermList___init__ function-1-Term_IfElse:s->function-12-Region_get function-1-Term_IfElse:s->function-0-Term_RegionEnd function-1-Term_IfElse:s->function-1-Term_RegionEnd function-17-PortList_getValue:s->function-0-PortList___init__ function-18-PortList_getValue:s->function-4-PortList___init__ function-6-Term_getPort:s->function-2-Term_RegionEnd function-5-Region_get:s->function-0-Region___init__ function-1-Term_DbgValue:s->function-10-Port_value function-10-Port_value:s->function-2-Port___init__ function-5-Port_value:s->function-3-Port___init__ function-0-Term_RegionEnd:s->function-3-PortList___init__ function-0-Term_RegionEnd:s->function-0-Region___init__ function-1-Term_RegionEnd:s->function-4-PortList___init__ function-1-Term_RegionEnd:s->function-2-Region___init__ function-5-Term_getPort:s->function-2-Term_RegionEnd function-11-Region_get:s->function-0-Region___init__ function-11-Port_value:s->function-11-Port___init__ primitive-Vec_Term-6:s->function-10-PortList_getValue primitive-Vec_Term-6:s->function-3-Term_DbgValue primitive-Vec_Term-6:s->function-5-TermList___getitem__ primitive-Vec_Term-6:s->function-18-PortList_getValue function-1-IsConstantFalse:s->function-7-TermList___getitem__ function-1-InPorts___init__ InPorts primitive-Vec_String-1 Vec("!io", "a", "b") function-0-InPorts___init__ InPorts primitive-Vec_String-0 Vec("!io", "a", "b", "c") function-3-Port___init__ Port("a", ·) function-16-PortList_getValue ·.getValue(·, 1) function-8-PortList___getitem__ ·[2] function-3-PortList___init__ PortList function-12-Port___init__ Port("c", ·) function-7-TermList___getitem__ ·[3] function-13-PortList___getitem__ ·[4] function-4-PortList___init__ PortList function-6-Port___init__ Port("__scfg_return_value__", ·) function-13-Port_value ·.value function-3-PortList___getitem__ ·[1] function-0-Port___init__ Port("!io", ·) function-0-PortList_getValue ·.getValue(·, 0) function-0-PortList___getitem__ ·[0] function-5-Port___init__ Port("b", ·) function-11-PortList_getValue ·.getValue(·, 3) function-10-PortList___getitem__ ·[3] function-7-Port___init__ Port("!ret", ·) function-14-Port_value ·.value function-6-PortList___getitem__ ·[1] function-0-PortList___init__ PortList function-1-Port___init__ Port("!io", ·) function-3-Port_value ·.value function-4-PortList___getitem__ ·[0] function-7-PortList___getitem__ ·[0] function-2-Port___init__ Port("__scfg_return_value__", ·) function-8-PortList_getValue ·.getValue(·, 2) function-2-PortList___getitem__ ·[1] function-4-Port___init__ Port("a", ·) function-9-PortList_getValue ·.getValue(·, 2) function-9-PortList___getitem__ ·[2] function-8-Port___init__ Port("b", ·) function-12-PortList_getValue ·.getValue(·, 3) function-11-PortList___getitem__ ·[3] function-11-Port___init__ Port("c", ·) function-14-PortList_getValue ·.getValue(·, 4) function-12-PortList___getitem__ ·[4] primitive-Vec_Port-8 Vec primitive-Vec_Port-13 Vec primitive-Vec_Port-14 Vec function-2-Region___init__ Region("599", ·) function-1-Region___init__ Region("443", ·) function-0-Region___init__ Region("507", ·) function-10-Port_name ·.name split-0-primitive-String-2147483657 "c" function-9-Port_name ·.name primitive-String-2147483657 "c" function-4-Port_name ·.name primitive-String-2684354576 "!ret" function-1-Port_name ·.name primitive-String-536870921 "__scfg_return_value__" function-8-Port_name ·.name split-0-primitive-String-1879048202 "b" function-0-Port_name ·.name primitive-String-10 "!io" function-2-Port_name ·.name split-0-primitive-String-536870921 "__scfg_return_value__" function-3-Port_name ·.name split-0-primitive-String-10 "!io" function-6-Port_name ·.name split-0-primitive-String-2952790028 "a" function-5-Port_name ·.name primitive-String-2952790028 "a" function-7-Port_name ·.name primitive-String-1879048202 "b" function-0-Term_Func Term.Func("833", "transformed_ifelse_fold", ·) function-2-Term_RegionEnd Term.RegionEnd function-2-Region_get ·.get(·, 0) function-2-Port_value ·.value function-8-Region_get ·.get(·, 2) function-8-Port_value ·.value function-3-Region_get ·.get(·, 0) function-4-Region_get ·.get(·, 0) function-3-Term_getPort ·.getPort(·, 0) function-1-Term_Apply Term.Apply function-4-PortList_getValue ·.getValue(·, 0) function-10-PortList_getValue ·.getValue(·, 0) function-3-TermList___getitem__ ·[0] function-0-TermList___init__ TermList function-12-Region_get ·.get(·, 3) function-3-Term_DbgValue Term.DbgValue("c", ·) function-12-Port_value ·.value function-15-PortList_getValue ·.getValue(·, 4) function-1-Term_LiteralI64 Term.LiteralI64(0) function-0-GraphRoot GraphRoot function-6-Region_get ·.get(·, 1) function-7-Region_get ·.get(·, 1) function-6-Port_value ·.value function-5-TermList___getitem__ ·[1] function-9-Region_get ·.get(·, 2) function-10-Region_get ·.get(·, 2) function-6-TermList___getitem__ ·[2] function-2-Term_DbgValue Term.DbgValue("__scfg_return_value__", ·) function-9-Port_value ·.value function-7-Term_getPort ·.getPort(·, 1) function-1-Term_IfElse Term.IfElse function-17-PortList_getValue ·.getValue(·, 1) function-18-PortList_getValue ·.getValue(·, 1) function-6-Term_getPort ·.getPort(·, 1) function-5-Region_get ·.get(·, 1) function-1-Term_DbgValue Term.DbgValue("__scfg_return_value__", ·) function-10-Port_value ·.value function-5-Port_value ·.value function-0-Term_RegionEnd Term.RegionEnd function-1-Term_RegionEnd Term.RegionEnd function-5-Term_getPort ·.getPort(·, 0) function-11-Region_get ·.get(·, 3) function-11-Port_value ·.value primitive-Vec_Term-6 Vec function-1-IsConstantFalse IsConstantFalse primitive-Unit-0 ()
4. EGraph Extraction ▶
EGraph Extraction
Cost ▶
8635.0
Extracted ▶
transformed_ifelse_fold = Func (Args (ArgSpec 'a' (PyNone)) (ArgSpec 'b' (PyNone)))
$0 = Region[950] <- !io a b
{
} [977] -> !io=$0[0] !ret=$0[2]
5. Backend ▶
Backend
LLVM ▶
; ModuleID = ""
target triple = "unknown-unknown-unknown"
target datalayout = ""

define ptr @"foo"(ptr %".1", ptr %".2")
{
.4:
  %".5" = alloca ptr
  store ptr null, ptr %".5"
  br label %".7"
.7:
  br label %".9"
.9:
  ret ptr %".2"
}

After applying the rewrite, the RVSDG simplifies dramatically, leaving a nearly empty function body. The !ret instruction is now hardcoded to $0[2], which represents the variable b, aligning with the return b from the else branch.

Meanwhile, the EGraph becomes more intriguing, with numerous nodes merged to reflect their equivalence. For example, the Term.Apply and Term.IfElse nodes are now combined, showcasing how the rewrite consolidates equivalent expressions.