qbe

Internal scc patchset buffer for QBE
Log | Files | Refs | README | LICENSE

commit ce0ab53ed73fb24f9537cab762467efad56f2664
parent 834b5cb08bbf0f4fbc1992a72327dfc2c0a31796
Author: Quentin Carbonneaux <quentin@c9x.me>
Date:   Wed,  6 Feb 2019 08:34:51 +0100

2 bug fixes in rega

The worst one was that "part 3" of rega()
could break the critical invariant that
two interferring temporaries get assigned
different registers.  This is fixed by
being careful when changing the register
of a temporary based on predecessor
blocks.

Thanks to Michael Forney for reporting
these bugs and helping with the analysis.

Diffstat:
Mrega.c | 8+++++---
Atest/rega1.ssa | 24++++++++++++++++++++++++
2 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/rega.c b/rega.c @@ -571,7 +571,8 @@ rega(Fn *fn) if (rtype(src) != RTmp) continue; x = rfind(&end[b->id], src.val); - assert(x != -1); + if (x == -1) /* spilled */ + continue; rl[r] = (!rl[r] || rl[r] == x) ? x : -1; } if (rl[r] == 0) @@ -586,7 +587,8 @@ rega(Fn *fn) continue; for (bp=s->pred; bp<&s->pred[s->npred]; bp++) { x = rfind(&end[(*bp)->id], t); - assert(x != -1); + if (x == -1) /* spilled */ + continue; rl[r] = (!rl[r] || rl[r] == x) ? x : -1; } } @@ -597,7 +599,7 @@ rega(Fn *fn) r = m->r[j]; x = rl[r]; assert(x != 0 || t < Tmp0 /* todo, ditto */); - if (x > 0) { + if (x > 0 && !bshas(m->b, x)) { pmadd(TMP(x), TMP(r), tmp[t].cls); m->r[j] = x; } diff --git a/test/rega1.ssa b/test/rega1.ssa @@ -0,0 +1,24 @@ +# tests that %b and %a0 do not end up in +# the same register at the start of @loop + +export function l $f(l %a) { +@start +@loop + %b =l phi @start 42, @loop0 %a1, @loop1 %a1 + %a0 =l phi @start %a, @loop0 %a1, @loop1 %a1 + %a1 =l sub %a0, 1 + jnz %b, @loop0, @loop1 +@loop0 + jnz %a1, @loop, @end +@loop1 + jnz %a1, @loop, @end +@end + ret %b +} + +# >>> driver +# extern long long f(long long); +# int main() { +# return !(f(1) == 42 && f(2) == 1 && f(42) == 1); +# } +# <<<