From e841adf97020e57cda9f4c88432b251a0ba6c69b Mon Sep 17 00:00:00 2001 From: George Koehler Date: Fri, 15 Nov 2019 11:50:05 -0500 Subject: [PATCH] Fix END pseudo in util/ego/sr; closes #203 The strength reduction (SR) phase mishandled the END pseudo when SR found at least 2 different expressions in the same loop, and SR made a new header for the loop. Since 1987 (commit 159b84e), SR appended the new header to the end of the procedure. Later, SR fixed the header by adding a BRA branch to the loop's entry, and moving the END pseudo from the previous basic block to the header. If SR found multiple expressions, it called fix_header() multiple times, and tried to move the END again. The extra move failed assert(INSTR(e) == ps_end), or moved another line after the END, so opt2 (the peephole optimizer) would crash. Fix by removing fix_header() and moving the code to make_header(), so SR adds the BRA and moves the END when it makes the header, and does so only once for each header. Adjust init_code(), which inserts code into a header. Stop checking for an empty header, because make_header() now adds BRA. After inserting code before BRA, don't move LP_INSTR, because later insertions should go before BRA, not after END. --- util/ego/sr/sr_reduce.c | 62 ++++++++--------------------------------- util/ego/sr/sr_xform.c | 32 +++++++++++++++++---- 2 files changed, 37 insertions(+), 57 deletions(-) diff --git a/util/ego/sr/sr_reduce.c b/util/ego/sr/sr_reduce.c index c78e456a1..7480f900c 100644 --- a/util/ego/sr/sr_reduce.c +++ b/util/ego/sr/sr_reduce.c @@ -171,9 +171,7 @@ STATIC line_p add_code(pl, l) -STATIC void init_code(code,tmp) - code_p code; - offset tmp; +STATIC void init_code(code_p code, offset tmp) { /* Generate code to set up the temporary local. * For multiplication, its initial value is const*iv_expr, @@ -223,20 +221,19 @@ STATIC void init_code(code,tmp) assert(FALSE); /* non-reducible instruction */ } PREV(l->l_next) = l; + /* Now insert the code at the end of the header block */ p = &code->co_loop->LP_INSTR; - if (*p == (line_p) 0 || (PREV((*p)) == 0 && INSTR((*p)) == op_bra)) { - /* LP_INSTR points to last instruction of header block, - * so if it is 0, the header block is empty yet. - */ - code->co_loop->LP_HEADER->b_start = - add_code(code->co_loop->LP_HEADER->b_start, code->co_lfirst); - } else if (INSTR((*p)) == op_bra) { + if (INSTR((*p)) == op_bra) { + /* Add code before branching to the loop. */ add_code(PREV((*p)), code->co_lfirst); + } else { + /* Add code before falling into the loop. */ + add_code(*p, code->co_lfirst); + while (l->l_next) + l = l->l_next; + *p = l; /* new last instruction */ } - else add_code(*p, code->co_lfirst); - while (l->l_next) l = l->l_next; - *p = l; /* new last instruction */ } STATIC void incr_code(code,tmp) @@ -453,43 +450,7 @@ STATIC code_p available(c,vars) return (code_p) 0; } -STATIC void fix_header(lp) - loop_p lp; -{ - /* Check if a header block was added, and if so, add a branch to - * the entry block. - * If it was added, it was added to the end of the procedure, so - * move the END pseudo. - */ - bblock_p b = curproc->p_start; - - if (lp->LP_HEADER->b_next == 0) { - line_p l = last_instr(lp->LP_HEADER); - line_p e; - - assert(l != 0); - if (INSTR(l) != op_bra) { - line_p j = newline(OPINSTRLAB); - - assert(INSTR(lp->lp_entry->b_start) == op_lab); - INSTRLAB(j) = INSTRLAB(lp->lp_entry->b_start); - j->l_instr = op_bra; - DLINK(l, j); - l = j; - } - - while (b->b_next != lp->LP_HEADER) b = b->b_next; - e = last_instr(b); - assert(INSTR(e) == ps_end); - assert(PREV(e) != 0); - PREV(e)->l_next = 0; - DLINK(l, e); - } -} - -STATIC void reduce(code,vars) - code_p code; - lset vars; +STATIC void reduce(code_p code, lset vars) { /* Perform the actual transformations. The code on the left * gets transformed into the code on the right. Note that @@ -538,7 +499,6 @@ STATIC void reduce(code,vars) incr_code(code,tmp); /* emit code to increment temp. local */ OUTTRACE("emitted increment code",0); Ladd(code,&avail); - fix_header(code->co_loop); } } diff --git a/util/ego/sr/sr_xform.c b/util/ego/sr/sr_xform.c index d48a70844..5323ceacb 100644 --- a/util/ego/sr/sr_xform.c +++ b/util/ego/sr/sr_xform.c @@ -138,9 +138,7 @@ STATIC void adjust_jump(newtarg,oldtarg,c) } -void -make_header(lp) - loop_p lp; +void make_header(loop_p lp) { /* Make sure that the loop has a header block, i.e. a block * has the loop entry block as its only successor and @@ -149,6 +147,7 @@ make_header(lp) */ bblock_p b,c,entry; + line_p branch,last; Lindex i,next; if (lp->LP_HEADER != (bblock_p) 0) return; @@ -160,6 +159,17 @@ make_header(lp) b = freshblock(); /* new block with new b_id */ entry = lp->lp_entry; + /* In the header, add a branch from to the entry block. */ + branch = newline(OPINSTRLAB); + assert(INSTR(entry->b_start) == op_lab); + INSTRLAB(branch) = INSTRLAB(entry->b_start); + branch->l_instr = op_bra; + b->b_start = branch; + + /* Plan to insert code before the branch. */ + assert(lp->LP_INSTR == 0); + lp->LP_INSTR = branch; + /* update succ/pred. Also take care that any jump from outside * the loop to the entry block now goes to b. */ @@ -180,14 +190,24 @@ make_header(lp) adjust_jump(b,entry,c); } } - assert(lp->LP_INSTR == 0); - lp->LP_INSTR = b->b_start; + Ladd(b,&entry->b_pred); Ladd(entry,&b->b_succ); + /* put header block at end of procedure */ - for (c = curproc->p_start; c->b_next != 0; c = c->b_next); + for (c = curproc->p_start; c->b_next != 0; c = c->b_next) + continue; c->b_next = b; /* b->b_next = 0; */ + + /* move the END pseudo to header block */ + last = last_instr(c); + assert(INSTR(last) == ps_end); + assert(PREV(last) != (line_p) 0); + PREV(last)->l_next = 0; + DLINK(branch, last); + + /* fix loops and dominance */ copy_loops(b,entry,lp); b->b_idom = entry->b_idom; entry->b_idom = b;