egraphs-good / eggcc

MIT License
42 stars 8 forks source link

Redundant load elimination #529

Closed rtjoa closed 4 months ago

rtjoa commented 4 months ago

Summary

Eliminate loads for which we already have the value from a prior load.

We perform this mainly by beefing up PointsToExpr:

(function PointsToExpr (Expr Expr) Expr :unextractable)

(= e (PointsToExpr state p)) indicates that at program point state, p points to e.

I also re-organized the memory bril tests. Previously, mem_simple_redundant_load actually was an example of store forwarding, so I moved it to mem_simple_store_forwarding, and added an actual test for redundant load elimination in its place.

Example optimization

Optimizes the following bril, containing two loads:

@main(cond: bool) {
    one: int = const 1;
    p: ptr<int> = alloc one;
    br cond .t .f;
.t:
    two: int = const 2;
    store p two;
    jmp .done;
.f:
    three: int = const 3;
    store p three;
.done:
    load1: int = load p;
    load2: int = load p;
    print load2;
    free p;
    ret;
}

To (just one load!):

@main(v0: bool) {
  v1_: int = const 1;
  v2_: ptr<int> = alloc v1_;
  br v0 .v3_ .v4_;
.v3_:
  v5_: int = const 2;
  store v2_ v5_;
  v6_: ptr<int> = id v2_;
  jmp .v7_;
.v4_:
  v8_: int = const 3;
  store v2_ v8_;
  v6_: ptr<int> = id v2_;
.v7_:
  v9_: int = load v2_;
  print v9_;
  free v2_;
}

Note that this test makes it unknown what value is written via the cond arg; otherwise, store forwarding usually subsumes redundant load elimination.