17bc9cdef7
Most warnings are for functions implicitly returning int. Change most
of these functions to return void. (Traditional K&R C had no void
type, but C89 has it.)
Add prototypes to most function declarations in headers. This is
easy, because ego declares most of its extern functions, and the
comments listed most parameters. There were a few outdated or missing
declarations, and a few .c files that failed to include an .h with the
declarations.
Add prototypes to a few function definitions in .c files. Most
functions still have traditional K&R definitions. Most STATIC
functions still don't have prototypes, because they have no earlier
declaration where I would have added the prototype.
Change some prototypes in util/ego/share/alloc.h. Functions newmap()
and oldmap() handle an array of pointers to something; change the
array's type from `short **` to `void **`. Callers use casts to go
between `void **` and the correct type, like `line_p *`. Function
oldtable() takes a `short *`, not a `short **`; I added the wrong type
in 5bbbaf4
.
Make a few other changes to silence warnings. There are a few places
where clang wants extra parentheses in the code.
Edit util/ego/ra/build.lua to add the missing dependency on ra*.h; I
needed this to prevent crashes from ra.
328 lines
6.8 KiB
C
328 lines
6.8 KiB
C
/* $Id$ */
|
|
/*
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
*/
|
|
/* B R A N C H O P T I M I Z A T I O N
|
|
*
|
|
* B O . C
|
|
*/
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <em_mnem.h>
|
|
#include <em_pseu.h>
|
|
#include <em_spec.h>
|
|
#include <em_flag.h>
|
|
#include "../share/types.h"
|
|
#include "../share/debug.h"
|
|
#include "../share/global.h"
|
|
#include "../share/files.h"
|
|
#include "../share/get.h"
|
|
#include "../share/put.h"
|
|
#include "../share/lset.h"
|
|
#include "../share/map.h"
|
|
#include "../share/alloc.h"
|
|
#include "../share/utils.h"
|
|
#include "../share/def.h"
|
|
#include "../share/go.h"
|
|
|
|
extern char em_flag[];
|
|
|
|
#define LP_BLOCKS lp_extend->lpx_ra.lpx_blocks
|
|
|
|
#define newbolpx() (lpext_p) newstruct(lpext_ra)
|
|
#define oldbolpx(x) oldstruct(lpext_ra,x)
|
|
|
|
STATIC int Sbo; /* #optimizations found */
|
|
|
|
#define DLINK(l1,l2) l1->l_next=l2; l2->l_prev=l1
|
|
|
|
/* This module performs some very simple branch optimizations.
|
|
*
|
|
* I) Look for pairs of basic blocks (B1,B2), such that
|
|
* SUCC(b1) = {B2} and
|
|
* PRED(B2) = {B1}.
|
|
* In this case B1 and B2 can be combined into one block.
|
|
* This optimization is mainly succesful:
|
|
* 1) for switch statements in C, as the C compiler generates a branch
|
|
* over the entire switch.
|
|
* 2) for return statements, if the only way to return from a procedure
|
|
* is via a return statement somewhere in the middle of the procedure.
|
|
* II) Optimize while statements. Transformations like:
|
|
* 1: jmp 2
|
|
* tst cond 1:
|
|
* beq 2f S
|
|
* S 2:
|
|
* jmp 1 tst cond
|
|
* 2: bneq 1
|
|
* are done by this optimization.
|
|
*/
|
|
|
|
|
|
|
|
STATIC line_p last_code(line_p lines, bool skip_pseu)
|
|
{
|
|
/* Determine the last line of a list */
|
|
|
|
register line_p l;
|
|
|
|
for (l = lines; l->l_next != (line_p) 0; l = l->l_next);
|
|
if (skip_pseu) {
|
|
while (l && (INSTR(l) < sp_fmnem || INSTR(l) > sp_lmnem)) l = PREV(l);
|
|
}
|
|
return l;
|
|
}
|
|
|
|
STATIC short cc_tab[12] =
|
|
{op_blt,op_zlt,op_ble,op_zle,op_beq,op_zeq,
|
|
op_zne,op_bne,op_zgt,op_bgt,op_zge,op_bge};
|
|
|
|
|
|
STATIC short rev_cond(short cond)
|
|
{
|
|
register int i;
|
|
|
|
for (i = 0; i < 12; i++) {
|
|
if (cond == cc_tab[i]) return cc_tab[11-i];
|
|
}
|
|
return op_nop;
|
|
}
|
|
|
|
STATIC bool is_bcc(l)
|
|
line_p l;
|
|
{
|
|
return rev_cond(INSTR(l)) != op_nop;
|
|
}
|
|
|
|
|
|
STATIC void bo_optloop(p,b,x,bra,bcc)
|
|
proc_p p;
|
|
bblock_p b,x;
|
|
line_p bra,bcc;
|
|
{
|
|
bblock_p prevb,n;
|
|
line_p l;
|
|
|
|
if (b->b_start == bra) {
|
|
b->b_start = (line_p) 0;
|
|
} else {
|
|
PREV(bra)->l_next = (line_p) 0;
|
|
}
|
|
PREV(bra) = (line_p) 0;
|
|
bcc->l_instr = rev_cond(INSTR(bcc));
|
|
n = x->b_next;
|
|
l = n->b_start;
|
|
if (l == (line_p) 0 || INSTR(l) != op_lab) {
|
|
l = newline(OPINSTRLAB);
|
|
l->l_instr = op_lab;
|
|
INSTRLAB(l) = freshlabel();
|
|
if (n->b_start != (line_p) 0) {
|
|
DLINK(l,n->b_start);
|
|
}
|
|
n->b_start = l;
|
|
}
|
|
INSTRLAB(bcc) = INSTRLAB(l);
|
|
for (prevb = p->p_start; prevb != (bblock_p) 0 && prevb->b_next != x;
|
|
prevb = prevb->b_next);
|
|
if (prevb == (bblock_p) 0) {
|
|
p->p_start = x->b_next;
|
|
} else {
|
|
prevb->b_next = x->b_next;
|
|
l = last_instr(prevb);
|
|
if (l == (line_p) 0) {
|
|
prevb->b_start = bra;
|
|
} else {
|
|
if ((em_flag[INSTR(l)-sp_fmnem]&EM_FLO) == FLO_T) {
|
|
oldline(bra);
|
|
} else {
|
|
appnd_line(bra,l);
|
|
}
|
|
}
|
|
}
|
|
x->b_next = b->b_next;
|
|
b->b_next = x;
|
|
}
|
|
|
|
|
|
|
|
STATIC void bo_tryloop(p,loop)
|
|
proc_p p;
|
|
lset loop;
|
|
{
|
|
Lindex i,j;
|
|
bblock_p b,x;
|
|
line_p bra,bcc;
|
|
|
|
for (i = Lfirst(loop); i != (Lindex) 0; i = Lnext(i,loop)) {
|
|
b = (bblock_p) Lelem(i);
|
|
if (b->b_next != (bblock_p) 0 && !Lis_elem(b->b_next,loop)) {
|
|
j = Lfirst(b->b_succ);
|
|
if (j != (Lindex) 0 &&
|
|
(bra = last_instr(b)) != (line_p) 0 &&
|
|
INSTR(bra) == op_bra) {
|
|
x = (bblock_p) Lelem(j); /* single successor */
|
|
if (Lis_elem(b->b_next,x->b_succ) &&
|
|
is_bcc((bcc = last_instr(x)))) {
|
|
OUTVERBOSE("branch optimization proc %d block %d\n", curproc->p_id,x->b_id);
|
|
Sbo++;
|
|
bo_optloop(p,b,x,bra,bcc);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
STATIC void bo_loops(p)
|
|
proc_p p;
|
|
{
|
|
Lindex i;
|
|
loop_p lp;
|
|
|
|
for (i = Lfirst(p->p_loops); i != (Lindex) 0; i = Lnext(i,p->p_loops)) {
|
|
lp = (loop_p) (Lelem(i));
|
|
bo_tryloop(p,lp->LP_BLOCKS);
|
|
}
|
|
}
|
|
|
|
STATIC void mv_code(b1,b2)
|
|
bblock_p b1,b2;
|
|
{
|
|
line_p l,x;
|
|
|
|
l = last_code(b2->b_start,TRUE);
|
|
assert(INSTR(l) == op_bra);
|
|
DLINK(l,b1->b_start);
|
|
x = l->l_next;
|
|
rm_line(l,b2);
|
|
if (INSTR(x) == op_lab) {
|
|
rm_line(x,b2);
|
|
}
|
|
}
|
|
|
|
STATIC void bo_switch(b)
|
|
bblock_p b;
|
|
{
|
|
bblock_p s,x;
|
|
Lindex i;
|
|
line_p l,bra;
|
|
|
|
if (Lnrelems(b->b_succ) == 1) {
|
|
s = (bblock_p) Lelem(Lfirst(b->b_succ));
|
|
if (b->b_start != (line_p) 0 &&
|
|
s->b_start != (line_p) 0 &&
|
|
Lnrelems(s->b_pred) == 1 &&
|
|
(bra = last_code(b->b_start,TRUE)) != (line_p) 0 &&
|
|
INSTR(bra) == op_bra &&
|
|
(s->b_next == (bblock_p) 0 ||
|
|
!Lis_elem(s->b_next,s->b_succ) ||
|
|
((bra = last_code(s->b_start, TRUE)) != (line_p) 0 &&
|
|
(em_flag[INSTR(bra)-sp_fmnem]&EM_FLO) == FLO_T))) {
|
|
l = last_code(s->b_start,FALSE);
|
|
if (INSTR(l) == ps_end) {
|
|
if (PREV(l) == (line_p) 0) return;
|
|
PREV(l)->l_next = (line_p) 0;
|
|
PREV(l) = (line_p) 0;
|
|
} else {
|
|
l = (line_p) 0;
|
|
}
|
|
OUTVERBOSE("branch optimization in proc %d, block %d",curproc->p_id,b->b_id);
|
|
Sbo++;
|
|
Ldeleteset(b->b_succ);
|
|
b->b_succ = s->b_succ;
|
|
Ldeleteset(s->b_pred);
|
|
s->b_succ = Lempty_set();
|
|
s->b_pred = Lempty_set();
|
|
for (i = Lfirst(b->b_succ); i != (Lindex) 0;
|
|
i = Lnext(i,b->b_succ)) {
|
|
x = (bblock_p) Lelem(i);
|
|
Lremove(s,&x->b_pred);
|
|
Ladd(b,&x->b_pred);
|
|
if (x->b_idom == s) {
|
|
x->b_idom = b;
|
|
}
|
|
}
|
|
mv_code(s,b);
|
|
s->b_start = l;
|
|
}
|
|
}
|
|
}
|
|
|
|
STATIC void bo_extproc(p)
|
|
proc_p p;
|
|
{
|
|
/* Allocate the extended data structures for procedure p */
|
|
|
|
register loop_p lp;
|
|
register Lindex pi;
|
|
|
|
for (pi = Lfirst(p->p_loops); pi != (Lindex) 0;
|
|
pi = Lnext(pi,p->p_loops)) {
|
|
lp = (loop_p) Lelem(pi);
|
|
lp->lp_extend = newbolpx();
|
|
}
|
|
}
|
|
|
|
|
|
STATIC void loop_blocks(p)
|
|
proc_p p;
|
|
{
|
|
/* Compute the LP_BLOCKS sets for all loops of p */
|
|
|
|
register bblock_p b;
|
|
register Lindex i;
|
|
|
|
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
|
for (i = Lfirst(b->b_loops); i != (Lindex) 0;
|
|
i = Lnext(i,b->b_loops)) {
|
|
Ladd(b,&(((loop_p) Lelem(i))->LP_BLOCKS));
|
|
}
|
|
}
|
|
}
|
|
|
|
STATIC void bo_cleanproc(p)
|
|
proc_p p;
|
|
{
|
|
/* Allocate the extended data structures for procedure p */
|
|
|
|
register loop_p lp;
|
|
register Lindex pi;
|
|
register bblock_p b;
|
|
|
|
for (pi = Lfirst(p->p_loops); pi != (Lindex) 0;
|
|
pi = Lnext(pi,p->p_loops)) {
|
|
lp = (loop_p) Lelem(pi);
|
|
oldbolpx(lp->lp_extend);
|
|
}
|
|
}
|
|
|
|
void bo_optimize(void *vp)
|
|
{
|
|
proc_p p = vp;
|
|
bblock_p b;
|
|
|
|
if (IS_ENTERED_WITH_GTO(p)) return;
|
|
bo_extproc(p);
|
|
loop_blocks(p);
|
|
bo_loops(p);
|
|
for (b = p->p_start; b != 0; b = b->b_next) {
|
|
bo_switch(b);
|
|
}
|
|
bo_cleanproc(p);
|
|
}
|
|
|
|
|
|
|
|
int main(argc,argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
go(argc,argv,no_action,bo_optimize,no_action,no_action);
|
|
report("branch optimizations", Sbo);
|
|
exit(0);
|
|
}
|