MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
seo.h
Go to the documentation of this file.
1#pragma once
2
3#include <absl/container/btree_set.h>
4
5#include <mim/def.h>
6#include <mim/phase.h>
7
8#include <mim/util/util.h>
9
10namespace mim::plug::mem::phase {
11
12/// Symbolic Expression Optimization.
13/// Based on [SSA Translation Is an Abstract Interpretation](https://dl.acm.org/doi/10.1145/3571258).
14/// In addition:
15/// * propagates whole expressions - not just constants
16/// * optimistically combines φs/Vars that are already present with those being constructed through SSA translation
17/// * since abstract domain is a MimIR expression, stack slots themselves can be propagated etc.
18///
19/// Additional papers worth reading:
20/// * [Constant propagation with conditional branches](https://dl.acm.org/doi/pdf/10.1145/103135.103136)
21/// * [Detecting equality of variables in programs](https://dl.acm.org/doi/10.1145/73560.73561)
22/// * [Combining analyses, combining optimizations](https://dl.acm.org/doi/pdf/10.1145/201059.201061)
23/// * [Simple and efficient construction of static single assignment
24/// form](https://dl.acm.org/doi/10.1007/978-3-642-37051-9_6)
25///
26/// Due to MimIR's sea of node structure a number of other optimizations kick in such as arithmetic simplifications and
27/// code motion.
28///
29/// Lattice per Lam::var:
30/// ```
31/// ⊤ ← Keep as is
32/// |
33/// Bundle ← Vars that (horizontally) behave the same build a single congruence class
34/// |
35/// Expr ← Whole expression is propagated (vertically) through var
36/// |
37/// ⊥
38/// ```
39/// A var that has reached ⊤ for propagation but still awaits GVN bundling is marked with a dedicated Proxy sentinel.
40class SEO : public RWPhase {
41private:
42 using Super = mim::RWPhase;
43
44 class Analysis : public mim::Analysis {
45 public:
46 using Super = mim::Analysis;
47
49 : mim::Analysis(world, "SEO::Analyzer") {}
50
51 void reset() final;
52
53 const LamSet& unknowns() const { return unknowns_; }
54
55 // SSA
56 const auto& slots() const { return slots_; }
57 const auto& lam2sloxy2val() const { return lam2sloxy2val_; }
58 const Def* lam2sloxy2val(Lam* lam, const Def* sloxy);
59
60 private:
61 // SCCP
62 const Proxy* mk_sccp_top(const Def* var);
63 const Def* sccp_join(Lam*, const Def*, const Def*);
64 DefVec sccp(Lam*, Defs vars, Defs abstr_args);
65
66 /// Applies @p known to @p abstr_targs (one per tvar): propagates phis, runs SCCP + GVN, and sets the vars.
67 const Def* apply_known(Lam* known, Defs abstr_targs);
68
69 // GVN
70 const Proxy* mk_bundle(Lam* lam, const Def* var, Defs bundle_vars);
71 void gvn_bundle(Lam*, Defs, Defs, Span<const Def*>);
72 void gvn_split(Lam*, Defs, Span<const Def*>, Span<const Def*>);
73
74 // SSA
75 void propagate_phis(Lam*, DefVec& vars, DefVec& abstr_args);
76 const Def* sloxy2val(const Def* sloxy) { return lam2sloxy2val(curr_mut<Lam>(), sloxy); }
77 const Def* sloxy2val(const Def* sloxy, const Def* val) { return lam2sloxy2val_[curr_mut<Lam>()][sloxy] = val; }
78
79 const Def* rewrite_imm_App(const App*) final;
80
81 // post-processing analysis to find sloxies that must be set to top
82 void finalize() final;
83 void analyze(const Def*);
84
85 // local (reset between iterations)
86 absl::node_hash_map<Lam*, Def2Def, GIDHash<const Def*>> lam2sloxy2val_;
87 DefSet visited_;
88 DefSet first_;
89
90 // global (kept between iterations)
91 Def2Def sloxy2slot_;
92 absl::btree_set<const Def*, GIDLt<const Def*>> slots_; // actually slot ptrs
93 LamSet unknowns_; // Lam%s reached as a *value*; their signature must stay untouched
94 LamMap<MutSet> lam2callers_; // all muts that apply a Lam; tainted when the Lam's abstract vars change
95 };
96
97public:
99 : RWPhase(world, annex, &analysis_)
100 , analysis_(world) {}
101
102private:
103 const Def* rewrite_imm_App(const App*) final;
104 const Def* rewrite_mut_Lam(Lam*) final;
105
106 /// A live phi for @p old_lam: the @p sloxy it stands for, the @p phi proxy, and its abstract @p val.
107 struct Phi {
108 const Def* sloxy;
109 const Def* phi;
110 const Def* val;
111 };
112
113 /// Was the SSA construction able to eliminate this sloxy?
114 const Def* isa_optimized_sloxy(const Def*) const;
115 /// The (memoized) live phis of @p old_lam.
116 const Vector<Phi>& phis_of(Lam* old_lam);
117 /// Does @p old_lam have propagated vars or live phis and hence needs a new signature?
118 bool needs_seo(View<Phi>, Lam* old_lam);
119 /// Builds (and caches) the new Lam for @p old_lam with propagated vars removed and kept phis appended.
120 Lam* build_lam(View<Phi>, Lam* old_lam);
121 /// Builds the argument list for a jump to @p old_lam (with the given @p old_targs, one per tvar)
122 /// matching the signature built by build_lam().
123 DefVec build_args(View<Phi>, Lam* old_lam, Defs old_targs);
124
125 Analysis analysis_;
126 Lam2Lam lam_old2new_;
127 Lam2Lam lam_new2old_;
128 absl::node_hash_map<Lam*, Vector<Phi>, GIDHash<Lam*>> lam2phis_;
129};
130
131} // namespace mim::plug::mem::phase
Traverses the current World using Rewriter infrastructure while staying in the same world.
Definition phase.h:149
virtual void reset()
Clears the rewriter map and resets Phase::todo() for the next fixed-point iteration.
Definition phase.cpp:51
virtual void finalize()
Run after the main analysis - only in full rounds, so it always sees the complete abstract World.
Definition phase.h:256
Base class for all Defs.
Definition def.h:261
A function.
Definition lam.h:110
friend class Analysis
Definition phase.h:125
flags_t annex() const
Definition phase.h:81
Rebuilds old_world() into new_world() and then swaps them.
Definition phase.h:312
virtual bool analyze()
Runs the optional pre-analysis on RWPhase::old_world(), typically to a fixed point,...
Definition phase.cpp:148
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition phase.h:316
World & world()=delete
Hides both and forbids direct access.
D * curr_mut() const
Definition rewrite.h:89
This is a thin wrapper for std::span<T, N> with the following additional features:
Definition span.h:29
This is a thin wrapper for absl::InlinedVector<T, N, A> which is a drop-in replacement for std::vecto...
Definition vector.h:18
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:36
const Def * rewrite_imm_App(const App *) final
Definition seo.cpp:418
const Def * rewrite_mut_Lam(Lam *) final
Definition seo.cpp:476
SEO(World &world, flags_t annex)
Definition seo.h:98
View< const Def * > Defs
Definition def.h:78
DefMap< const Def * > Def2Def
Definition def.h:77
Vector< const Def * > DefVec
Definition def.h:79
GIDSet< Lam * > LamSet
Definition lam.h:220
u64 flags_t
Definition types.h:39
Span< const T, N > View
Definition span.h:102
LamMap< Lam * > Lam2Lam
Definition lam.h:221
GIDMap< Lam *, To > LamMap
Definition lam.h:219
GIDSet< const Def * > DefSet
Definition def.h:76