aboutsummaryrefslogtreecommitdiff
path: root/src/regalloc.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-06-27 19:17:50 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2024-06-27 19:17:50 +0300
commit67443867c2743eda27be650b58f5021004789a45 (patch)
tree8034dd383552f37fb8c41ed02cd57f76d4126d1e /src/regalloc.c
parent123860bc029465ff88c3bf82165a89170fa41153 (diff)
downloadqbt-67443867c2743eda27be650b58f5021004789a45.tar.gz
qbt-67443867c2743eda27be650b58f5021004789a45.zip
allow compiling some massive functions
Diffstat (limited to 'src/regalloc.c')
-rw-r--r--src/regalloc.c48
1 files changed, 40 insertions, 8 deletions
diff --git a/src/regalloc.c b/src/regalloc.c
index cd21f5e..6265c6d 100644
--- a/src/regalloc.c
+++ b/src/regalloc.c
@@ -175,10 +175,26 @@ static void collect_lifetimes(struct blk *b, struct vec *hints,
}
}
-static void build_active_between(struct vec *active, struct vec *lifetimes,
- size_t start, size_t end)
+static void build_active_between(struct vec *active, struct vec *prev_active, struct vec *lifetimes,
+ size_t i, size_t start, size_t end)
{
- foreach_lifetime(li, *lifetimes) {
+ /* we really only need to look at previously active lifetimes and check
+ * which ones are still active, no need to iterate all the way from the
+ * start. Only works if prev_active is really the previous lifetime in
+ * the lifetimes vector */
+ if (prev_active)
+ foreach_lifetime(li, *prev_active) {
+ struct lifetime l = lifetime_at(*lifetimes, li);
+ if (l.end <= start)
+ continue;
+
+ if (l.start >= end)
+ break;
+
+ vec_append(active, &l);
+ }
+
+ for (size_t li = i; li < vec_len(lifetimes); ++li) {
struct lifetime l = lifetime_at(*lifetimes, li);
if (l.used == 0)
continue;
@@ -188,17 +204,20 @@ static void build_active_between(struct vec *active, struct vec *lifetimes,
if (l.end <= start)
continue;
+ /* since lifetimes must be strictly ascending by start value, we
+ * know that no other lifetimes can possibly be active after
+ * this point */
if (l.start >= end)
- continue;
+ break;
vec_append(active, &l);
}
}
-static void build_active(struct vec *active, struct vec *lifetimes, size_t i)
+static void build_active(struct vec *active, struct vec *prev_active, struct vec *lifetimes, size_t i)
{
struct lifetime ref = lifetime_at(*lifetimes, i);
- build_active_between(active, lifetimes, ref.start, ref.end);
+ build_active_between(active, prev_active, lifetimes, i, ref.start, ref.end);
}
static void build_reserved(struct vec *reserved, struct vec *active,
@@ -279,10 +298,18 @@ static size_t highest_sreg(struct val f)
return 0;
}
+static void swap_lifetimes(struct vec *a, struct vec *b)
+{
+ struct vec tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
+
static size_t build_rmap(struct vec *hints, struct vec *lifetimes,
struct vec *rmap)
{
size_t max_callee_save = 0;
+ struct vec prev_active = vec_create(sizeof(struct lifetime));
struct vec active = vec_create(sizeof(struct lifetime));
struct vec reserved = vec_create(sizeof(struct val));
@@ -296,7 +323,7 @@ static size_t build_rmap(struct vec *hints, struct vec *lifetimes,
vec_reset(&active);
vec_reset(&reserved);
- build_active(&active, lifetimes, li);
+ build_active(&active, &prev_active, lifetimes, li);
build_reserved(&reserved, &active, rmap);
struct val h = get_hint(hints, l.v);
@@ -315,10 +342,15 @@ static size_t build_rmap(struct vec *hints, struct vec *lifetimes,
max_callee_save = highest_sreg(f);
add_rewrite_rule(rmap, l.v, f);
+
+ /* store currently active in prev_active */
+ swap_lifetimes(&active, &prev_active);
+ vec_reset(&active);
}
vec_destroy(&active);
vec_destroy(&reserved);
+ vec_destroy(&prev_active);
return max_callee_save;
}
@@ -457,7 +489,7 @@ static size_t do_call_saves(struct blk *b, struct vec *lifetimes,
vec_reset(&active);
vec_reset(&reserved);
- build_active_between(&active, lifetimes, call_pos, call_pos);
+ build_active_between(&active, NULL, lifetimes, 0, call_pos, call_pos);
build_reserved(&reserved, &active, rmap);
/* what follows is a slight bit of index counting, a bit