MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
lower_index.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4
5#include <optional>
6
7#include <mim/phase.h>
8
10
11/// Lowers the affine index algebra to core arithmetic.
12///
13/// The opaque affine.Index type is rewritten to the wide `Idx 0` (i64) carrier, and the index operations are computed
14/// with wrap-around (`core.Mode::none`) arithmetic, so negation/subtraction are correct via two's complement:
15/// * `affine.lit n` ↦ `n` reinterpreted as an `Idx 0`,
16/// * `affine.op.add (a, b)` ↦ `core.wrap.add none (a, b)`,
17/// * `affine.op.sub (a, b)` ↦ `core.wrap.sub none (a, b)`,
18/// * `affine.op.neg a` ↦ `core.wrap.sub none (0, a)`,
19/// * `affine.semiop.mul (a, c)` ↦ `core.wrap.mul none (a, c)`.
20///
21/// The `affine.map f idxs mem` bridge lowers to: widen each runtime `idxs#i : Idx (sin#i)` to `Idx 0` via
22/// `core.conv.u`, apply the (now core-arithmetic) function `f`, and
23/// narrow each result back to its target `Idx (sout#j)` via `core.conv.u`.
24///
25/// The division-based semiops (`ceildiv`, `floordiv`, `rem`) lower to `core.div`, which threads a `mem.M`. The mem is
26/// taken from the enclosing `affine.map`'s mem operand (tracked in #mem_), advanced through the div chain, and
27/// returned alongside the result.
28class LowerIndex : public RWPhase {
29public:
30 using RWPhase::RWPhase;
31
32 const Def* rewrite(const Def*) final;
33 const Def* rewrite_imm_App(const App*) final;
34
35private:
36 /// Inclusive range of the values a lowered `Idx 0` expression can take, proven not to wrap.
37 struct Range {
38 int64_t lo, hi;
39 };
40
41 /// The body sees every index as a bare `Idx 0`, so this is the only place the domain is still known.
42 struct Domain {
43 const Def* idxs = nullptr;
44 fe::Vector<std::optional<int64_t>> extents;
45 };
46
47 /// The addends of an expression that are multiples of `c`, and whether the rest can carry into a division by it.
48 struct Split {
49 DefVec even, rest;
50 bool carries;
51 };
52
53 /// `x = q·k + r` with `0 ≤ r < k` for a proper divisor `k` of the divisor at hand.
54 struct Peel {
55 const Def *q, *r;
56 int64_t k;
57 };
58
59 std::optional<Range> range_of(const Def*) const;
60 Split split(const Def*, int64_t);
61 std::optional<Peel> peel(const Def*, int64_t);
62 const Def* fold_udiv(const Def*, int64_t);
63 const Def* fold_urem(const Def*, int64_t);
64 const Def* udiv(const Def*, const Def*);
65 const Def* urem(const Def*, const Def*);
66
67 const Def* mem_ = nullptr;
68 Domain dom_;
69
70 /// Rewritten access-map lams, keyed by `f` and then `sin`: shared annex lams like `tensor.proj_map` are reached
71 /// from `affine.map`s over different domains, and a fold only holds for the extents that justified it.
72 DefMap<DefMap<Lam*>> specialized_;
73 DefMap<Lam*> etas_;
74};
75
76} // namespace mim::plug::affine::phase
Base class for all Defs.
Definition def.h:289
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition phase.h:334
Lowers the affine index algebra to core arithmetic.
Definition lower_index.h:28
const Def * rewrite_imm_App(const App *) final
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
Definition phase.h:334
const Def * rewrite(const Def *) final
GIDMap< const Def *, To > DefMap
Definition def.h:93
fe::Vector< const Def * > DefVec
Definition def.h:98