12bool in_loop(
const Nest::Node* node) {
14 while (fun->level() > 1)
16 return node->loop_depth() > fun->loop_depth();
24 , max_(
driver().arg_nat(
"mem",
"heap2stack").value_or(1024)) {}
27 if (max_ == 0)
return false;
30 auto nest = std::optional<const Nest>();
31 for (
const auto& [lam, chain] : escape_.chains()) {
32 auto allocs = fe::Vector<const App*>();
33 for (
auto op : chain.ops) {
35 if (!
alloc || escape_.is_top(op))
continue;
36 auto [
pointee, addr_space] =
alloc->decurry()->args<2>();
37 if (
Lit::isa(addr_space) == 0 && num_elems(
pointee)) allocs.emplace_back(op);
39 if (allocs.empty())
continue;
40 if (!lam->is_closed()) {
42 if (in_loop((*nest)[lam]))
continue;
44 converted_.insert(allocs.begin(), allocs.end());
45 slots_[chain.tail] = std::move(allocs);
48 log().d(
"heap2stack: slots on {} chains", slots_.size());
52std::optional<nat_t> Heap2Stack::num_elems(
const Def* type)
const {
53 if (type->isa_mut())
return {};
55 if (
auto sigma = type->isa<
Sigma>()) {
57 for (
auto op : sigma->ops()) {
58 auto n = num_elems(op);
59 if (!n || (res += *n) > max_)
return {};
64 if (
auto arr = type->isa<Arr>()) {
65 auto res = num_elems(arr->body());
66 auto shape = arr->shape();
67 auto rank = shape.rank();
68 if (!res || !rank)
return {};
69 for (
nat_t i = 0; i != *rank; ++i) {
71 if (!e || (*e != 0 && *res > max_ / *e))
return {};
84 auto allocs = fe::lookup(slots_, app);
87 auto ks = fe::Vector<Lam*>();
88 for (
auto alloc : *allocs) {
95 for (
size_t i = ks.size(); i-- != 0;) {
96 auto alloc = (*allocs)[i];
97 auto [
pointee, addr_space] =
alloc->decurry()->args<2>();
98 ks[i]->set(
false, res);
static auto isa(const Def *def)
Lam * set(Filter filter, const Def *body)
static std::optional< T > isa(const Def *def)
const fe::Log & log() const
virtual bool analyze()
Runs the optional pre-analysis on old_world(), typically to a fixed point, before rewriting begins.
World & new_world()
Create new Defs into this.
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
World & world()=delete
Hides both and forbids direct access.
World & old_world()
Get old Defs from here.
const Def * rewrite_imm_App(const App *) override
const Def * map(const Def *old_def, const Def *new_def)
virtual const Def * rewrite(const Def *)
static std::optional< nat_t > extent(const Def *axis)
The extent of axis: the axis itself for a shape, its Idx size for an index.
The World represents the whole program and manages creation of MimIR nodes (Defs).
Lam * mut_con(const Def *dom)
static const App * freed_alloc(const Def *def)
The allocation def releases if it is a mem.free of one; nullptr otherwise.
bool analyze() final
Runs the optional pre-analysis on old_world(), typically to a fixed point, before rewriting begins.
Heap2Stack(World &, flags_t annex)
const Def * rewrite_imm_App(const App *) final
const Def * pointee(const Def *ptr)
const Def * op_slot(const Def *type, const Def *as, const Def *mem, const Def *ret)