Commit ad17c504 authored by mei-ye's avatar mei-ye
Browse files

create live intervals

parent 7db934b0
#ifndef MIGRAPH_GUARD_RTGLIB_COMMON_HEADER_HPP #ifndef MIGRAPH_GUARD_RTGLIB_COMMON_HEADER_HPP
#define MIGRAPH_GUARD_RTGLIB_COMMON_HEADER_HPP #define MIGRAPH_GUARD_RTGLIB_COMMON_HEADER_HPP
#include <migraph/program.hpp> #include <migraph/program.hpp>
#include <migraph/stringutils.hpp>
#include <migraph/instruction.hpp> #include <migraph/instruction.hpp>
#include <migraph/operators.hpp> #include <migraph/operators.hpp>
#include <migraph/iterator_for.hpp> #include <migraph/iterator_for.hpp>
#include <set>
#include <list>
#include <vector>
#define DEBUG_OPT #define DEBUG_OPT
#ifdef DEBUG_OPT #ifdef DEBUG_OPT
......
#include "memory_coloring_impl.hpp" #include "memory_coloring_impl.hpp"
#include <set>
namespace migraph { namespace migraph {
void memory_coloring_impl::run() void memory_coloring_impl::run()
...@@ -8,60 +7,82 @@ void memory_coloring_impl::run() ...@@ -8,60 +7,82 @@ void memory_coloring_impl::run()
if (num_of_instrs == 0) if (num_of_instrs == 0)
return; return;
DEBUG(dump("before memory coloring")); DEBUG(dump("---Before memory coloring---"));
int cur_points = num_of_instrs * 2; int cur_points = num_of_instrs * 2;
instruction_ref iter = std::prev(p_program->end()); instruction_ref iter = std::prev(p_program->end());
instruction_ref begin = p_program->begin(); instruction_ref begin = p_program->begin();
std::vector<T_live_interval> live_intervals; std::vector<T_live_interval*> live_intervals;
std::vector<instruction_ref> dead_instrs; std::vector<instruction_ref> dead_instrs;
std::vector<int> orderings; std::list<T_live_interval*> active_queue;
int num_of_lives = 0; int num_of_lives = 0;
std::unordered_map<const instruction*, int> instr2Live; std::unordered_map<const instruction*, T_live_interval*> instr2Live;
std::set<int> live_set; std::set<int> live_set;
live_set.clear(); T_live_interval* next_def = nullptr;
instr2Live.clear(); live_intervals.reserve(num_of_instrs);
live_intervals.resize(num_of_instrs);
do { do {
const instruction* p_iter = &(*iter); const instruction* p_iter = &(*iter);
int def_id = -1; T_live_interval* def_interval = nullptr;
bool isDead = false;
if (instr2Live.find(p_iter) != instr2Live.end()) { if (instr2Live.find(p_iter) != instr2Live.end()) {
def_id = instr2Live[p_iter]; def_interval = instr2Live[p_iter];
bool isLit = isLiteral(iter); bool isLit = isLiteral(iter);
if (isAllocate(iter) || isLit) { if (isAllocate(iter) || isLit) {
live_intervals[def_id].begin = cur_points; T_live_range& range = def_interval->segments.front();
live_intervals[def_id].result = iter->result; range.begin = cur_points;
live_intervals[def_id].isLiteral = isLit; def_interval->result = iter->result;
orderings.push_back(def_id); def_interval->isLiteral = isLit;
live_set.erase(def_id); def_interval->next_enqueue_def = cur_points;
active_queue.push_front(def_interval);
next_def = def_interval;
live_set.erase(def_interval->id);
} }
} else if (!isParam(iter) && !isOutline(iter) && !isCheckContext(iter)) { } else if (!isParam(iter) && !isOutline(iter) && !isCheckContext(iter)) {
// dead instruction. isDead = true;
dead_instrs.push_back(iter);
} }
if (!iter->arguments.empty()) { if (!iter->arguments.empty()) {
for (auto&& arg : iter->arguments) { for (auto&& arg : iter->arguments) {
if (isParam(arg) || isOutline(arg)) { if (isParam(arg) || isOutline(arg)) {
if (isOutputParam(arg))
isDead = false;
continue; continue;
} }
const instruction* p_arg = &(*arg); const instruction* p_arg = &(*arg);
if (isAllocate(arg)) { if (isAllocate(arg)) {
assert(def_id != -1); // input is from hip::allocate, def is considered as use
live_intervals[def_id].addUse(cur_points); // and coalesce the live intervals.
instr2Live[p_arg] = def_id; def_interval->addUse(cur_points);
instr2Live[p_arg] = def_interval;
} else if (instr2Live.find(p_arg) == instr2Live.end()) { } else if (instr2Live.find(p_arg) == instr2Live.end()) {
// First time see a use, create a live interval.
int id = num_of_lives++; int id = num_of_lives++;
live_intervals[id].id = id; T_live_interval* interval = new live_interval();
live_intervals[id].end = cur_points; interval->id = id;
live_intervals[id].addUse(cur_points); interval->segments.push_back(T_live_range{-1, cur_points, -1});
instr2Live[p_arg] = id; interval->addUse(cur_points);
instr2Live[p_arg] = interval;
live_set.insert(id); live_set.insert(id);
} // Keep track of live intervals that are inactive when
// next_def is enqueued.
if (next_def != nullptr)
next_def->inactive_afters.push_back(interval);
live_intervals[id] = interval;
} else {
T_live_interval* interval = instr2Live[p_arg];
interval->addUse(cur_points);
DEBUG(assert(live_set.find(interval->id) != live_set.end()));
}
} }
} }
if (isDead)
dead_instrs.push_back(iter);
cur_points -= 2; cur_points -= 2;
iter = std::prev(iter); iter = std::prev(iter);
} while (iter != begin); } while (iter != begin);
DEBUG(dump(live_intervals, num_of_lives));
for (int i = 0; i < num_of_lives; ++i)
free(live_intervals[i]);
} }
#ifdef DEBUG_OPT #ifdef DEBUG_OPT
...@@ -70,6 +91,44 @@ void memory_coloring_impl::dump(std::string str) ...@@ -70,6 +91,44 @@ void memory_coloring_impl::dump(std::string str)
std::cout << str << std::endl; std::cout << str << std::endl;
std::cout << *p_program << std::endl; std::cout << *p_program << std::endl;
} }
void memory_coloring_impl::dump(std::vector<T_live_interval*>& live_intervals, int num_of_lives)
{
if (num_of_lives > 0) {
std::cout << "---live intervals ---" << std::endl;
for (int i = 0; i < num_of_lives; ++i) {
T_live_interval* interval = live_intervals[i];
interval->dump();
}
}
}
#define GET_INS_ENUM(x) (((x) >> 1) - 1)
void live_interval::dump()
{
std::cout << "id:" << id;
for (auto iter = segments.begin(), end = segments.end(); iter != end; ++iter) {
T_live_range& range = *iter;
std::cout << " [" << GET_INS_ENUM(range.begin) << ", " << GET_INS_ENUM(range.end) << "]";
}
std::cout << " uses:";
for (auto iter = use_points.begin(), end = use_points.end(); iter != end; ++iter) {
int& use = *iter;
std::cout << " " << GET_INS_ENUM(use) << ",";
}
if (!inactive_afters.empty()) {
std::cout << " inactivate:";
for (auto iter = inactive_afters.begin(), end = inactive_afters.end(); iter != end; ++iter) {
T_live_interval*& interval = *iter;
std::cout << " " << interval->id << ",";
}
}
if (isLiteral)
std::cout << " literal";
std::cout << std::endl;
}
#endif #endif
} // namespace migraph } // namespace migraph
...@@ -3,35 +3,65 @@ ...@@ -3,35 +3,65 @@
#include "common_header.hpp" #include "common_header.hpp"
namespace migraph { namespace migraph {
typedef struct live_range {
explicit live_range(int b, int e, int o ) : begin(b), end(e), offset(o) {};
int begin;
int end;
int offset;
} T_live_range;
typedef struct live_interval {
explicit live_interval() { init(); }
void addUse(int use) { use_points.push_front(use); }
void init() {
id = -1; isLiteral = false;
}
std::list <T_live_range> segments;
int id;
std::list<int> use_points;
// Live intervals that are inactive when this live interval is enqueued.
std::list<struct live_interval*> inactive_afters;
// Next enqueue point for this live interval. It is not always
// equal to the begin if this live interval is rematerialized.
int next_enqueue_def;
shape result;
bool isLiteral;
#ifdef DEBUG_OPT
void dump();
#endif
} T_live_interval;
typedef struct occupant_range {
explicit occupant_range(int b, int e, T_live_interval* in)
: begin(b), end(e), interval(in) {};
int begin;
int end;
T_live_interval* interval;
} T_occupant_range;
struct memory_coloring_impl { struct memory_coloring_impl {
explicit memory_coloring_impl(program *p) : p_program(p) {} explicit memory_coloring_impl(program *p) : p_program(p) {}
void run(); void run();
private: private:
bool isParam(const instruction_ref ins) { return ins->op.name() == "@param"; } bool isParam(const instruction_ref ins) { return ins->op.name() == "@param"; }
bool isOutputParam(const instruction_ref ins)
{
return isParam(ins) && any_cast<builtin::param>(ins->op).parameter == "output";
}
bool isAllocate(const instruction_ref ins) { return ins->op.name() == "hip::allocate"; } bool isAllocate(const instruction_ref ins) { return ins->op.name() == "hip::allocate"; }
bool isOutline(const instruction_ref ins) { return ins->op.name() == "@outline"; } bool isOutline(const instruction_ref ins) { return ins->op.name() == "@outline"; }
bool isLiteral(const instruction_ref ins) { return ins->op.name() == "@literal"; } bool isLiteral(const instruction_ref ins) { return ins->op.name() == "@literal"; }
bool isCheckContext(const instruction_ref ins) { return ins->op.name() == "check_context"; } bool isCheckContext(const instruction_ref ins) { return ins->op.name() == "check_context"; }
#ifdef DEBUG_OPT #ifdef DEBUG_OPT
void dump(std::string); void dump(std::string);
void dump(std::vector<T_live_interval*>&, int);
#endif #endif
program* p_program; program* p_program;
}; };
typedef struct live_interval {
explicit live_interval() { init(); }
bool isValid() const { return (begin != -1) && (end != -1); }
void addUse(int use) { use_points.push_back(use); }
void init() { begin = -1; end = -1; id = -1; isLiteral = false; }
int begin;
int end;
int id;
std::vector<int> use_points;
shape result;
bool isLiteral;
} T_live_interval;
} // namespace migraph } // namespace migraph
#endif #endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment