MimIR
0.4-dev
MimIR is my Intermediate Representation
Toggle main menu visibility
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
#include <fe/bitset.h>
5
6
#include <
mim/def.h
>
7
#include <
mim/phase.h
>
8
9
#include <
mim/util/gid.h
>
10
11
namespace
mim::plug::mem::phase
{
12
13
/// Symbolic Expression Optimization.
14
/// Based on [SSA Translation Is an Abstract Interpretation](https://dl.acm.org/doi/10.1145/3571258).
15
/// In addition:
16
/// * propagates whole expressions - not just constants
17
/// * optimistically combines φs/Vars that are already present with those being constructed through SSA translation
18
/// * since abstract domain is a MimIR expression, stack slots themselves can be propagated etc.
19
///
20
/// Additional papers worth reading:
21
/// * [Constant propagation with conditional branches](https://dl.acm.org/doi/pdf/10.1145/103135.103136)
22
/// * [Detecting equality of variables in programs](https://dl.acm.org/doi/10.1145/73560.73561)
23
/// * [Combining analyses, combining optimizations](https://dl.acm.org/doi/pdf/10.1145/201059.201061)
24
/// * [Simple and efficient construction of static single assignment
25
/// form](https://dl.acm.org/doi/10.1007/978-3-642-37051-9_6)
26
///
27
/// Due to MimIR's sea of node structure a number of other optimizations kick in such as arithmetic simplifications and
28
/// code motion.
29
///
30
/// Lattice per Lam::var:
31
/// ```
32
/// ⊤ ← Keep as is
33
/// |
34
/// Bundle ← Vars that (horizontally) behave the same build a single congruence class
35
/// |
36
/// Expr ← Whole expression is propagated (vertically) through var
37
/// |
38
/// ⊥
39
/// ```
40
/// A var that has reached ⊤ for propagation but still awaits GVN bundling is marked with a dedicated Proxy sentinel.
41
class
SEO
:
public
RWPhase
{
42
private
:
43
using
Super =
mim::RWPhase
;
44
45
class
Analysis :
public
mim::Analysis
{
46
public
:
47
using
Super =
mim::Analysis
;
48
49
Analysis
(
World
&
world
)
50
:
mim::Analysis
(
world
,
"SEO::Analyzer"
) {}
51
52
void
reset
()
final
;
53
54
const
LamSet
& unknowns()
const
{
return
unknowns_; }
55
56
// SSA
57
const
auto
& slots()
const
{
return
slots_; }
58
const
Def
* lam2sloxy2val(
Lam
* lam,
const
Def
* sloxy);
59
/// Can *every* recorded call site of @p lam supply a value for @p sloxy?
60
/// Only then may build_args() find an argument for a phi threaded through @p lam.
61
bool
can_supply(
Lam
* lam,
const
Def
* sloxy);
62
63
private
:
64
// SCCP
65
const
Proxy
* mk_sccp_top(
const
Def
* var);
66
const
Def
* sccp_join(
Lam
*,
const
Def
*,
const
Def
*);
67
68
/// Applies @p known to @p abstr_targs (one per tvar): propagates phis, runs SCCP + GVN, and sets the vars.
69
const
Def
* apply_known(
Lam
* known,
Defs
abstr_targs);
70
/// An App that merely records "@p callee applied to these abstract args"; never emitted code.
71
const
Def
* abstract_app(
const
Def
* callee,
const
Def
* arg);
72
73
// GVN
74
const
Proxy
* mk_bundle(
Lam
* lam,
const
Def
* var,
Defs
bundle_vars);
75
void
gvn_bundle(
Lam
*,
Defs
,
Defs
, fe::Span<const Def*>);
76
void
gvn_split(
Lam
*,
Defs
, fe::Span<const Def*>, fe::Span<const Def*>);
77
78
// SSA
79
void
propagate_phis(
Lam
*,
DefVec
& vars,
DefVec
& abstr_args);
80
const
Def
* sloxy2val(
const
Def
* sloxy) {
return
lam2sloxy2val(
curr_mut<Lam>
(), sloxy); }
81
const
Def
* sloxy2val(
const
Def
* sloxy,
const
Def
* val) {
return
lam2sloxy2val_[
curr_mut<Lam>
()][sloxy] = val; }
82
const
Def
*
rewrite_imm_App
(
const
App
*)
final
;
83
void
leave
()
final
;
84
85
// post-processing analysis to find sloxies that must be set to top
86
void
finalize
()
final
;
87
void
analyze
(
const
Def
*);
88
89
// local (reset between iterations)
90
absl::node_hash_map<Lam*, Def2Def, GIDHash<const Def*>> lam2sloxy2val_;
91
DefSet
visited_;
92
DefSet
first_;
93
Def2Def
sloxy2slot_;
// global (kept between iterations)
94
absl::btree_set<const Def*, GIDLt<const Def*>> slots_;
// actually slot ptrs
95
LamSet
unknowns_;
// Lam%s reached as a *value*; their signature must stay untouched
96
LamMap<MutSet>
lam2callers_;
// all muts that apply a Lam; tainted when the Lam's abstract vars change
97
};
98
99
public
:
100
SEO
(
World
&
world
,
flags_t
annex
)
101
:
RWPhase
(
world
,
annex
, &analysis_)
102
, analysis_(
world
) {}
103
104
private
:
105
const
Def
*
rewrite_imm_App
(
const
App
*)
final
;
106
const
Def
*
rewrite_imm_Var
(
const
Var
*)
final
;
107
const
Def
*
rewrite_mut_Lam
(
Lam
*)
final
;
108
109
/// A live phi for a Lam: the @p sloxy it stands for, the @p phi proxy, its abstract @p val,
110
/// and whether the new signature keeps it as a var.
111
struct
Phi {
112
const
Def
* sloxy;
113
const
Def
* phi;
114
const
Def
* val;
115
bool
keep;
116
};
117
118
/// The new signature of an old Lam.
119
struct
Sig {
120
fe::Vector<Phi> phis;
///< Its live phis.
121
fe::Bitset keeps;
///< Which tvars of the old Lam are kept as is?
122
size_t
num_vars = 0;
///< Vars of the new Lam: the kept old ones plus the kept phis.
123
bool
todo
=
false
;
///< Does the old Lam need a new signature at all?
124
};
125
126
bool
analyze
() final;
127
128
/// Was the SSA construction able to eliminate this sloxy?
129
const
Def
* isa_optimized_sloxy(const
Def
*) const;
130
/// The (memoized) new signature of @p old_lam.
131
const Sig& sig_of(
Lam
* old_lam);
132
/// The new spelling of @p old_lam's var: kept projections become new vars, dropped ones their
133
/// propagated value (⊥ for a promoted slot). The single source of truth for both build_lam() and
134
/// rewrite_imm_Var(), and hence well-defined independent of build order.
135
const
Def
* var_of(
Lam
* old_lam);
136
/// Builds (and caches) the new Lam for @p old_lam with propagated vars removed and kept phis appended.
137
Lam
* build_lam(
Lam
* old_lam);
138
/// Builds the argument list for a jump to @p old_lam (with the given @p old_targs, one per tvar)
139
/// matching the signature built by build_lam().
140
DefVec
build_args(
Lam
* old_lam,
Defs
old_targs);
141
142
Analysis
analysis_;
143
Lam2Lam
lam_old2new_;
144
Lam2Lam
lam_new2old_;
145
absl::node_hash_map<
Lam
*, Sig,
GIDHash
<
Lam
*>> lam2sig_;
// node_hash_map: a Sig& outlives nested rewrites
146
DefVec
sloxies_;
// the eliminated sloxies; every Lam's phi candidates
147
};
148
149
}
// namespace mim::plug::mem::phase
mim::Analysis
Traverses the current World using Rewriter infrastructure while staying in the same world.
Definition
phase.h:151
mim::Analysis::leave
virtual void leave()
Called after curr_mut() has been completely dealt with.
Definition
phase.h:292
mim::App
Definition
lam.h:224
mim::Def
Base class for all Defs.
Definition
def.h:273
mim::Lam
A function.
Definition
lam.h:113
mim::Phase::Analysis
friend class Analysis
Definition
phase.h:125
mim::Phase::annex
flags_t annex() const
Definition
phase.h:81
mim::Phase::todo
bool todo() const
Definition
phase.h:90
mim::Proxy
Used as intermediate value during optimizatinos such as Analysis.
Definition
def.h:1032
mim::RWBase::finalize
virtual void finalize()
Run after all roots have been walked - but for an RWPhase still before the two worlds are swapped.
Definition
phase.h:415
mim::RWPhase
Rebuilds old_world() into new_world() and then swaps them.
Definition
phase.h:427
mim::RWPhase::RWPhase
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition
phase.h:431
mim::RWPhase::world
World & world()=delete
Hides both and forbids direct access.
mim::Rewriter::curr_mut
D * curr_mut() const
Definition
rewrite.h:96
mim::Rewriter::reset
void reset(std::unique_ptr< World > &&ptr)
Definition
rewrite.cpp:29
mim::Var
A variable introduced by a binder (mutable).
Definition
def.h:825
mim::World
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition
world.h:40
mim::plug::mem::phase::SEO::analyze
bool analyze() final
Runs the optional pre-analysis on Phase::world, typically to a fixed point, before rewriting begins.
Definition
seo.cpp:429
mim::plug::mem::phase::SEO::rewrite_imm_Var
const Def * rewrite_imm_Var(const Var *) final
Definition
seo.cpp:534
mim::plug::mem::phase::SEO::rewrite_imm_App
const Def * rewrite_imm_App(const App *) final
Definition
seo.cpp:470
mim::plug::mem::phase::SEO::rewrite_mut_Lam
const Def * rewrite_mut_Lam(Lam *) final
Definition
seo.cpp:526
mim::plug::mem::phase::SEO::SEO
SEO(World &world, flags_t annex)
Definition
seo.h:100
def.h
gid.h
mim::plug::mem::phase
Definition
add_mem.h:5
mim::Def2Def
DefMap< const Def * > Def2Def
Definition
def.h:90
mim::LamSet
GIDSet< Lam * > LamSet
Definition
lam.h:220
mim::flags_t
u64 flags_t
Definition
types.h:39
mim::Defs
fe::View< const Def * > Defs
Definition
def.h:91
mim::Lam2Lam
LamMap< Lam * > Lam2Lam
Definition
lam.h:221
mim::LamMap
GIDMap< Lam *, To > LamMap
Definition
lam.h:219
mim::DefVec
fe::Vector< const Def * > DefVec
Definition
def.h:93
mim::DefSet
GIDSet< const Def * > DefSet
Definition
def.h:89
phase.h
mim::GIDHash
Definition
gid.h:12
include
mim
plug
mem
phase
seo.h
Generated by
1.18.0