Initial revision
This commit is contained in:
108
util/ego/sr/Makefile
Normal file
108
util/ego/sr/Makefile
Normal file
@@ -0,0 +1,108 @@
|
||||
|
||||
EMH=../../../h
|
||||
EML=../../../lib
|
||||
CFLAGS=-DVERBOSE
|
||||
SHARE=../share
|
||||
SR=.
|
||||
OBJECTS=sr.o sr_expr.o sr_reduce.o sr_iv.o sr_cand.o sr_xform.o sr_aux.o
|
||||
SHOBJECTS=$(SHARE)/get.o $(SHARE)/put.o $(SHARE)/alloc.o $(SHARE)/global.o $(SHARE)/debug.o $(SHARE)/files.o $(SHARE)/map.o $(SHARE)/lset.o $(SHARE)/cset.o $(SHARE)/aux.o $(SHARE)/go.o
|
||||
SRC=sr.h sr_iv.h sr_reduce.h sr_cand.h sr_xform.h sr_expr.h sr_aux.h sr.c sr_iv.c sr_reduce.c sr_cand.c sr_xform.c sr_expr.c sr_aux.c
|
||||
.c.o:
|
||||
cc $(CFLAGS) -c $<
|
||||
all: $(OBJECTS)
|
||||
sr: \
|
||||
$(OBJECTS) $(SHOBJECTS)
|
||||
cc -o sr -i $(OBJECTS) $(SHOBJECTS) $(EML)/em_data.a
|
||||
lpr:
|
||||
pr $(SRC) | lpr
|
||||
opr:
|
||||
pr $(SRC) | opr
|
||||
dumpflop:
|
||||
tar -uf /mnt/ego/sr/sr.tarf $(SRC) Makefile
|
||||
# the next lines are generated automatically
|
||||
# AUTOAUTOAUTOAUTOAUTOAUTO
|
||||
sr.o: ../share/alloc.h
|
||||
sr.o: ../share/debug.h
|
||||
sr.o: ../share/files.h
|
||||
sr.o: ../share/get.h
|
||||
sr.o: ../share/global.h
|
||||
sr.o: ../share/lset.h
|
||||
sr.o: ../share/map.h
|
||||
sr.o: ../share/put.h
|
||||
sr.o: ../share/types.h
|
||||
sr.o: sr.h
|
||||
sr.o: sr_aux.h
|
||||
sr.o: sr_iv.h
|
||||
sr_aux.o: ../../../h/em_mnem.h
|
||||
sr_aux.o: ../../../h/em_pseu.h
|
||||
sr_aux.o: ../share/aux.h
|
||||
sr_aux.o: ../share/debug.h
|
||||
sr_aux.o: ../share/global.h
|
||||
sr_aux.o: ../share/lset.h
|
||||
sr_aux.o: ../share/types.h
|
||||
sr_aux.o: sr.h
|
||||
sr_aux.o: sr_aux.h
|
||||
sr_aux.o: sr_xform.h
|
||||
sr_cand.o: ../../../h/em_mnem.h
|
||||
sr_cand.o: ../../../h/em_pseu.h
|
||||
sr_cand.o: ../share/aux.h
|
||||
sr_cand.o: ../share/cset.h
|
||||
sr_cand.o: ../share/debug.h
|
||||
sr_cand.o: ../share/global.h
|
||||
sr_cand.o: ../share/lset.h
|
||||
sr_cand.o: ../share/map.h
|
||||
sr_cand.o: ../share/types.h
|
||||
sr_cand.o: sr.h
|
||||
sr_cand.o: sr_aux.h
|
||||
sr_cand.o: sr_cand.h
|
||||
sr_expr.o: ../../../h/em_mnem.h
|
||||
sr_expr.o: ../share/aux.h
|
||||
sr_expr.o: ../share/debug.h
|
||||
sr_expr.o: ../share/global.h
|
||||
sr_expr.o: ../share/lset.h
|
||||
sr_expr.o: ../share/types.h
|
||||
sr_expr.o: sr.h
|
||||
sr_expr.o: sr_aux.h
|
||||
sr_expr.o: sr_iv.h
|
||||
sr_iv.o: ../../../h/em_mnem.h
|
||||
sr_iv.o: ../../../h/em_pseu.h
|
||||
sr_iv.o: ../share/alloc.h
|
||||
sr_iv.o: ../share/aux.h
|
||||
sr_iv.o: ../share/cset.h
|
||||
sr_iv.o: ../share/debug.h
|
||||
sr_iv.o: ../share/global.h
|
||||
sr_iv.o: ../share/lset.h
|
||||
sr_iv.o: ../share/types.h
|
||||
sr_iv.o: sr.h
|
||||
sr_iv.o: sr_aux.h
|
||||
sr_iv.o: sr_cand.h
|
||||
sr_iv.o: sr_iv.h
|
||||
sr_reduce.o: ../../../h/em_mes.h
|
||||
sr_reduce.o: ../../../h/em_mnem.h
|
||||
sr_reduce.o: ../../../h/em_pseu.h
|
||||
sr_reduce.o: ../../../h/em_reg.h
|
||||
sr_reduce.o: ../share/alloc.h
|
||||
sr_reduce.o: ../share/aux.h
|
||||
sr_reduce.o: ../share/debug.h
|
||||
sr_reduce.o: ../share/global.h
|
||||
sr_reduce.o: ../share/lset.h
|
||||
sr_reduce.o: ../share/types.h
|
||||
sr_reduce.o: sr.h
|
||||
sr_reduce.o: sr_aux.h
|
||||
sr_reduce.o: sr_expr.h
|
||||
sr_reduce.o: sr_reduce.h
|
||||
sr_reduce.o: sr_xform.h
|
||||
sr_xform.o: ../../../h/em_mnem.h
|
||||
sr_xform.o: ../../../h/em_pseu.h
|
||||
sr_xform.o: ../../../h/em_spec.h
|
||||
sr_xform.o: ../share/alloc.h
|
||||
sr_xform.o: ../share/aux.h
|
||||
sr_xform.o: ../share/debug.h
|
||||
sr_xform.o: ../share/def.h
|
||||
sr_xform.o: ../share/get.h
|
||||
sr_xform.o: ../share/global.h
|
||||
sr_xform.o: ../share/lset.h
|
||||
sr_xform.o: ../share/types.h
|
||||
sr_xform.o: sr.h
|
||||
sr_xform.o: sr_aux.h
|
||||
sr_xform.o: sr_xform.h
|
||||
205
util/ego/sr/sr.c
Normal file
205
util/ego/sr/sr.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/* S T R E N G T H R E D U C T I O N */
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "sr.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/go.h"
|
||||
#include "sr_aux.h"
|
||||
#include "sr_iv.h"
|
||||
|
||||
/* Strength reduction tries to change expensive operators occurring
|
||||
* in a loop into cheaper operators. The expensive operators considered
|
||||
* are multiplication and array referencing.
|
||||
* The transformations can be expressed in C as:
|
||||
*
|
||||
* [1]: for (i = e1; i <= e2; i++)
|
||||
* print(118*i);
|
||||
* becomes:
|
||||
* for (i = e1, t = 118*e1; i <= e2; i++, t += 118)
|
||||
* print(t);
|
||||
*
|
||||
* [2]: for (i = e1; i <= e2; i++)
|
||||
* print(a[i]);
|
||||
* becomes:
|
||||
* for (i = e1, p = &a[i]; i <= e2; i++, p++)
|
||||
* print(*p);
|
||||
* The latter optimization is suppressed if array bound checking
|
||||
* is required.
|
||||
*/
|
||||
|
||||
/* Machine and/or language dependent parameters: */
|
||||
|
||||
bool ovfl_harmful;
|
||||
bool arrbound_harmful;
|
||||
|
||||
int Ssr; /* #optimizations found */
|
||||
|
||||
sr_machinit(f)
|
||||
FILE *f;
|
||||
{
|
||||
/* Read target machine dependent information */
|
||||
char s[100];
|
||||
|
||||
|
||||
for (;;) {
|
||||
while(getc(f) != '\n');
|
||||
fscanf(f,"%s",s);
|
||||
if (strcmp(s,"%%SR") == 0)break;
|
||||
}
|
||||
fscanf(f,"%d",&ovfl_harmful);
|
||||
fscanf(f,"%d",&arrbound_harmful);
|
||||
}
|
||||
|
||||
STATIC del_ivs(ivs)
|
||||
lset ivs;
|
||||
{
|
||||
/* Delete the set of iv structs */
|
||||
|
||||
Lindex i;
|
||||
|
||||
for (i = Lfirst(ivs); i != (Lindex) 0; i = Lnext(i,ivs)) {
|
||||
oldiv(Lelem(i));
|
||||
}
|
||||
Ldeleteset(ivs);
|
||||
}
|
||||
|
||||
|
||||
STATIC do_loop(loop)
|
||||
loop_p loop;
|
||||
{
|
||||
lset ivs, vars;
|
||||
|
||||
OUTTRACE("going to process loop %d",loop->lp_id);
|
||||
induc_vars(loop,&ivs, &vars);
|
||||
/* Build a set of iv_structs, one for every induction
|
||||
* variable of the loop, i.e. a variable i that
|
||||
* is changed only by i := i + c, where c is a loop constant.
|
||||
* Also detects variables that are changed (including induction
|
||||
* variables!).
|
||||
*/
|
||||
OUTTRACE("loop has %d induction variables",Lnrelems(ivs));
|
||||
if (Lnrelems(ivs) > 0) {
|
||||
strength_reduction(loop,ivs,vars);
|
||||
/* Perform strength reduction. Reduce:
|
||||
* iv * c to addition
|
||||
* a[iv] to indirection (*p)
|
||||
* (unless array bound checking is required)
|
||||
*/
|
||||
}
|
||||
del_ivs(ivs);
|
||||
Ldeleteset(vars);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC loopblocks(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 opt_proc(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Optimize all loops of one procedure. We first do all
|
||||
* outer loops at the lowest nesting level and proceed
|
||||
* in the inwards direction.
|
||||
*/
|
||||
|
||||
Lindex i;
|
||||
loop_p lp,outermost;
|
||||
int min_level;
|
||||
|
||||
for (;;) {
|
||||
min_level = 1000;
|
||||
for (i = Lfirst(p->p_loops); i != (Lindex) 0;
|
||||
i = Lnext(i,p->p_loops)) {
|
||||
lp = (loop_p) Lelem(i);
|
||||
if (!lp->LP_DONE && lp->lp_level < min_level) {
|
||||
min_level = lp->lp_level;
|
||||
outermost = lp;
|
||||
}
|
||||
}
|
||||
if (min_level == 1000) break;
|
||||
do_loop(outermost);
|
||||
outermost->LP_DONE = TRUE;
|
||||
OUTTRACE("loop %d processed",outermost->lp_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC sr_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 = newsrlpx();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC sr_cleanproc(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Remove 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);
|
||||
oldsrlpx(lp->lp_extend);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sr_optimize(p)
|
||||
proc_p p;
|
||||
{
|
||||
sr_extproc(p);
|
||||
loopblocks(p);
|
||||
opt_proc(p);
|
||||
sr_cleanproc(p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
go(argc,argv,no_action,sr_optimize,sr_machinit,no_action);
|
||||
report("strength reductions",Ssr);
|
||||
exit(0);
|
||||
}
|
||||
28
util/ego/sr/sr.h
Normal file
28
util/ego/sr/sr.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/* I N T E R N A L D A T A S T R U C T U R E S O F
|
||||
*
|
||||
* S T R E N G T H R E D U C T I O N
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#define LOAD 0
|
||||
#define STORE 1
|
||||
|
||||
#define DLINK(l1,l2) l1->l_next=l2; l2->l_prev=l1
|
||||
|
||||
#define same_local(l1,l2) (off_set(l1) == off_set(l2))
|
||||
|
||||
#define LP_BLOCKS lp_extend->lpx_sr.lpx_blocks
|
||||
#define LP_DONE lp_extend->lpx_sr.lpx_done
|
||||
#define LP_HEADER lp_extend->lpx_sr.lpx_header
|
||||
#define LP_INSTR lp_extend->lpx_sr.lpx_instr
|
||||
|
||||
/* Parameters to be provided by environment: */
|
||||
|
||||
extern bool ovfl_harmful; /* Does overflow during multiplication
|
||||
* cause a trap ?
|
||||
*/
|
||||
extern bool arrbound_harmful; /* Is it harmful to take the address of
|
||||
* a non-existing array element ?
|
||||
*/
|
||||
extern int Ssr; /* #optimizations found */
|
||||
115
util/ego/sr/sr_aux.c
Normal file
115
util/ego/sr/sr_aux.c
Normal file
@@ -0,0 +1,115 @@
|
||||
/* S T R E N G T H R E D U C T I O N
|
||||
*
|
||||
* S R _ A U X . C
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "../share/types.h"
|
||||
#include "sr.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/aux.h"
|
||||
#include "sr_aux.h"
|
||||
#include "sr_xform.h"
|
||||
|
||||
#define INSIDE_LOOP(b,lp) Lis_elem(b,lp->LP_BLOCKS)
|
||||
|
||||
|
||||
bool is_loopconst(lnp,vars)
|
||||
line_p lnp;
|
||||
lset vars;
|
||||
{
|
||||
Lindex i;
|
||||
|
||||
assert(TYPE(lnp) == OPSHORT || TYPE(lnp) == OPOFFSET);
|
||||
if (!is_regvar(off_set(lnp))) return FALSE;
|
||||
for (i = Lfirst(vars); i != (Lindex) 0; i = Lnext(i,vars)) {
|
||||
if (same_local(Lelem(i),lnp)) {
|
||||
return FALSE; /* variable was changed */
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
bool is_caddress(lnp,vars)
|
||||
line_p lnp;
|
||||
lset vars; /* variables changed in loop */
|
||||
{
|
||||
/* See if lnp is a single instruction (i.e. without arguments)
|
||||
* that pushes a loop-invariant entity of size pointer-size (ps)
|
||||
* on the stack.
|
||||
*/
|
||||
|
||||
if (lnp == (line_p) 0) return FALSE;
|
||||
switch(INSTR(lnp)) {
|
||||
case op_lae:
|
||||
case op_lal:
|
||||
return TRUE;
|
||||
case op_lol:
|
||||
return ps == ws && is_loopconst(lnp,vars);
|
||||
case op_ldl:
|
||||
return ps == 2*ws && is_loopconst(lnp,vars);
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC arg_p find_arg(n,list)
|
||||
int n;
|
||||
arg_p list;
|
||||
{
|
||||
/* Find the n-th element of the list */
|
||||
|
||||
while (--n) {
|
||||
if (list == (arg_p) 0) break;
|
||||
list = list->a_next;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
int elemsize(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* lnp is an instruction that loads the address of an array
|
||||
* descriptor. Find the size of the elements of the array.
|
||||
* If this size cannot be determined (e.g. the descriptor may
|
||||
* not be in a rom) then return UNKNOWN_SIZE.
|
||||
*/
|
||||
|
||||
dblock_p d;
|
||||
arg_p v;
|
||||
|
||||
assert (lnp != (line_p) 0);
|
||||
if (INSTR(lnp) == op_lae) {
|
||||
d = OBJ(lnp)->o_dblock; /* datablock */
|
||||
if (d->d_pseudo == DROM &&
|
||||
(v = find_arg(3,d->d_values)) != (arg_p) 0 &&
|
||||
v->a_type == ARGOFF) {
|
||||
return (int) v->a_a.a_offset;
|
||||
}
|
||||
}
|
||||
return UNKNOWN_SIZE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
concatenate(list1,list2)
|
||||
line_p list1,list2;
|
||||
{
|
||||
/* Append list2 to the end of list1. list1 may not be empty. */
|
||||
|
||||
register line_p l;
|
||||
|
||||
assert(list1 != (line_p) 0);
|
||||
for (l =list1; l->l_next != (line_p) 0; l = l->l_next);
|
||||
l->l_next = list2;
|
||||
}
|
||||
20
util/ego/sr/sr_aux.h
Normal file
20
util/ego/sr/sr_aux.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/* S R _ A U X . H */
|
||||
|
||||
|
||||
extern bool is_loopconst(); /* (line_p l; lset vars)
|
||||
* See if l is a loop-constant. vars is the
|
||||
* set of variables changed in the loop.
|
||||
*/
|
||||
extern bool is_caddress(); /* (line_p l)
|
||||
* See if l loads a loop-invariant entity of
|
||||
* size pointer-size.
|
||||
*/
|
||||
extern int elemsize(); /* (line_p l)
|
||||
* l is an instruction that loads an array
|
||||
* descriptor. Try to determine the size
|
||||
* of the array elements.
|
||||
*/
|
||||
extern concatenate(); /* (line_p list1,list2)
|
||||
* Append list2 to the end of list1
|
||||
*/
|
||||
#define is_const(l) (INSTR(l) == op_loc)
|
||||
187
util/ego/sr/sr_cand.c
Normal file
187
util/ego/sr/sr_cand.c
Normal file
@@ -0,0 +1,187 @@
|
||||
/* S T R E N G T H R E D U C T I O N
|
||||
*
|
||||
* S R _ C A N D . C
|
||||
*/
|
||||
|
||||
|
||||
#include "../share/types.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/cset.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/map.h"
|
||||
#include "../share/aux.h"
|
||||
#include "sr.h"
|
||||
#include "sr_aux.h"
|
||||
#include "sr_cand.h"
|
||||
|
||||
|
||||
/* A candidate induction variable of a loop (hereafter called candidate) is a
|
||||
* local variable (of the current procedure) that is assigned a value
|
||||
* precisely once within the loop. Furthermore, this assignment must
|
||||
* take place in a firm block of the loop.
|
||||
* We determine those locals that are assigned precisely once, within
|
||||
* a firm block;
|
||||
*
|
||||
* We represent a local variable via an instruction that references it,
|
||||
* e.g. LOL -6 represents the local variable at offset -6 with size=wordsize.
|
||||
* We keep track of two sets:
|
||||
* cand - the set of all candidate variables
|
||||
* dismiss - a set of variables that may not be made a candidate
|
||||
* (because they are assigned more than once, or because
|
||||
* they are assigned outside a firm block).
|
||||
* Only local variables for which a register message is given are considered.
|
||||
*/
|
||||
|
||||
|
||||
STATIC lset cand, /* set of candidates */
|
||||
dism; /* set of dismissed variables */
|
||||
|
||||
|
||||
#define ALL_LINES(lnp,list) lnp = list; lnp != (line_p) 0; lnp = lnp->l_next
|
||||
|
||||
|
||||
|
||||
STATIC un_cand(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* remove the variable stored into by lnp from the list of
|
||||
* candidates (if it was there anyway).
|
||||
*/
|
||||
|
||||
Lindex i, next;
|
||||
|
||||
for (i = Lfirst(cand); i != (Lindex) 0; i = next) {
|
||||
next = Lnext(i,cand);
|
||||
if (same_local(lnp,Lelem(i))) {
|
||||
OUTTRACE("remove candidate",0);
|
||||
Lremove(Lelem(i), &cand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC bool is_cand(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* see if the variable stored into by lnp is a candate */
|
||||
|
||||
Lindex i;
|
||||
|
||||
for (i = Lfirst(cand); i != (Lindex) 0; i = Lnext(i,cand)) {
|
||||
if (same_local(lnp,Lelem(i))) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
STATIC make_cand(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* make the variable stored into by lnp a candidate */
|
||||
|
||||
|
||||
OUTTRACE("add a new candidate",0);
|
||||
Ladd(lnp,&cand);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC do_dismiss(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
Ladd(lnp,&dism);
|
||||
}
|
||||
|
||||
|
||||
STATIC dismiss(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* The variable referenced by lnp is turned definitely into
|
||||
* a non-candidate.
|
||||
*/
|
||||
|
||||
un_cand(lnp); /* remove it from the candidate set,
|
||||
* if it was there in the first place.
|
||||
*/
|
||||
do_dismiss(lnp); /* add it to the set of dismissed variables */
|
||||
}
|
||||
|
||||
|
||||
STATIC bool not_dismissed(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
Lindex i;
|
||||
|
||||
for (i = Lfirst(dism); i != (Lindex) 0; i = Lnext(i,dism)) {
|
||||
if (same_local(Lelem(i),lnp)) {
|
||||
return FALSE; /* variable was dismissed */
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
STATIC try_cand(lnp,b)
|
||||
line_p lnp;
|
||||
bblock_p b;
|
||||
{
|
||||
/* If the variable stored into by lnp was not already a candidate
|
||||
* and was not dismissed, then it is made a candidate
|
||||
* (unless the assignment takes places in a block that is not firm).
|
||||
*/
|
||||
|
||||
if (!is_regvar(off_set(lnp))) return;
|
||||
if (is_cand(lnp) || !IS_FIRM(b)) {
|
||||
dismiss(lnp);
|
||||
} else {
|
||||
if (not_dismissed(lnp)) {
|
||||
make_cand(lnp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
candidates(lp,cand_out,vars_out)
|
||||
loop_p lp;
|
||||
lset *cand_out, *vars_out;
|
||||
{
|
||||
/* Find the candidate induction variables.
|
||||
*/
|
||||
|
||||
bblock_p b;
|
||||
line_p lnp;
|
||||
Lindex i;
|
||||
|
||||
OUTTRACE("find candidates of loop %d",lp->lp_id);
|
||||
cand = Lempty_set();
|
||||
dism = Lempty_set();
|
||||
|
||||
for (i = Lfirst(lp->LP_BLOCKS); i != (Lindex) 0;
|
||||
i = Lnext(i,lp->LP_BLOCKS)) {
|
||||
b = (bblock_p) Lelem(i);
|
||||
for ( ALL_LINES(lnp, b->b_start)) {
|
||||
OUTTRACE("inspect instruction %d",INSTR(lnp));
|
||||
switch(INSTR(lnp)) {
|
||||
case op_stl:
|
||||
case op_inl:
|
||||
case op_del:
|
||||
OUTTRACE("it's a store local",0);
|
||||
try_cand(lnp,b);
|
||||
break;
|
||||
case op_zrl:
|
||||
OUTTRACE("it's a destroy local",0);
|
||||
if (is_regvar(off_set(lnp))) {
|
||||
dismiss(lnp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*cand_out = cand;
|
||||
*vars_out = dism;
|
||||
}
|
||||
14
util/ego/sr/sr_cand.h
Normal file
14
util/ego/sr/sr_cand.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/* S T R E N G T H R E D U C T I O N
|
||||
*
|
||||
* S R _ C A N D . H
|
||||
*/
|
||||
|
||||
|
||||
extern candidates(); /* (loop_p lp; lset *iv_cand, *vars)
|
||||
* Find candidate induction variables,
|
||||
* i.e. local variables that are assigned
|
||||
* a value precisely once within the loop,
|
||||
* within a strong block. Also find the
|
||||
* local variables that are changed within
|
||||
* the loop, but that are not a candidate.
|
||||
*/
|
||||
199
util/ego/sr/sr_expr.c
Normal file
199
util/ego/sr/sr_expr.c
Normal file
@@ -0,0 +1,199 @@
|
||||
/* S T R E N G T H R E D U C T I O N
|
||||
*
|
||||
* S R _ E X P R . C
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "sr.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/aux.h"
|
||||
#include "sr_aux.h"
|
||||
#include "../share/lset.h"
|
||||
#include "sr_iv.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
|
||||
|
||||
|
||||
#define ME_NONE 0
|
||||
#define ME_UNAIR 1
|
||||
#define ME_BINAIR 2
|
||||
#define ME_LOOPCONST 3
|
||||
#define ME_IV 4
|
||||
|
||||
|
||||
|
||||
STATIC iv_p last_iv;
|
||||
STATIC int iv_sign;
|
||||
STATIC lset ivars, loopvars;
|
||||
|
||||
STATIC bool is_loadiv(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* See if lnp is a LOL iv instruction, where iv is an
|
||||
* induction variable of the set ivars. If so, set the
|
||||
* the global variable last_iv to its descriptor.
|
||||
*/
|
||||
|
||||
Lindex i;
|
||||
iv_p iv;
|
||||
offset off;
|
||||
|
||||
if (INSTR(lnp) == op_lol) {
|
||||
off = off_set(lnp);
|
||||
for (i = Lfirst(ivars); i != (Lindex) 0; i = Lnext(i,ivars)) {
|
||||
iv = (iv_p) Lelem(i);
|
||||
if (iv->iv_off == off) {
|
||||
last_iv = iv;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#define size_ok(l) (TYPE(l) == OPSHORT && SHORT(l) == ws)
|
||||
|
||||
|
||||
STATIC int me_kind(l,sign_in,sign_out)
|
||||
line_p l;
|
||||
int sign_in, *sign_out;
|
||||
{
|
||||
if (l != (line_p) 0) {
|
||||
switch(INSTR(l)) {
|
||||
case op_adi:
|
||||
case op_adu:
|
||||
if (size_ok(l)) {
|
||||
*sign_out = sign_in;
|
||||
return ME_BINAIR;
|
||||
}
|
||||
break;
|
||||
case op_sbi:
|
||||
case op_sbu:
|
||||
if (size_ok(l)) {
|
||||
*sign_out = - sign_in;
|
||||
return ME_BINAIR;
|
||||
}
|
||||
break;
|
||||
case op_ngi:
|
||||
if (size_ok(l)) {
|
||||
*sign_out = - sign_in;
|
||||
return ME_UNAIR;
|
||||
}
|
||||
break;
|
||||
case op_inc:
|
||||
case op_dec:
|
||||
*sign_out = sign_in;
|
||||
return ME_UNAIR;
|
||||
case op_loc:
|
||||
return ME_LOOPCONST;
|
||||
case op_lol:
|
||||
if (is_loadiv(l)) {
|
||||
iv_sign = sign_in;
|
||||
return ME_IV;
|
||||
}
|
||||
if (is_loopconst(l,loopvars)) return ME_LOOPCONST;
|
||||
}
|
||||
}
|
||||
return ME_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool match_expr(l,iv_allowed,lbegin,iv_seen,sign)
|
||||
line_p l,*lbegin;
|
||||
bool iv_allowed, *iv_seen;
|
||||
int sign;
|
||||
{
|
||||
/* This routine is a top down parser for simple
|
||||
* EM expressions. It recognizes expressions that
|
||||
* have as operators + and - (unary - is also allowed)
|
||||
* and that have as operands a number of loop constants
|
||||
* (either a constant or a variable that is not
|
||||
* changed within the loop) and at most one induction
|
||||
* variable.
|
||||
* The parameter iv_allowed is propagated downwards
|
||||
* in the expression tree, indicating whether the
|
||||
* subexpression may use an induction variable as
|
||||
* operand. The parameter iv_seen is propagated
|
||||
* upwards, indicating if the subexpression has used
|
||||
* an induction variable. The parameter sign is
|
||||
* propagated downwards; it indicates the sign of
|
||||
* the subexpression. lbegin will point to the
|
||||
* beginning of the recognized subexpression
|
||||
* (it is an out parameter). Note that we scan the
|
||||
* EM text from right to left (i.e. top down).
|
||||
*/
|
||||
|
||||
line_p l1;
|
||||
bool iv_insubexpr;
|
||||
int sign2;
|
||||
|
||||
switch(me_kind(l,sign,&sign2)) {
|
||||
case ME_UNAIR:
|
||||
/* unairy operator, match one subexpression */
|
||||
if (match_expr(PREV(l),iv_allowed,&l1,&iv_insubexpr,sign2)) {
|
||||
*lbegin = l1;
|
||||
*iv_seen = iv_insubexpr;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
case ME_BINAIR:
|
||||
/* binairy operator, match two subexpressions */
|
||||
if (match_expr(PREV(l), iv_allowed, &l1, &iv_insubexpr,sign2)) {
|
||||
l = PREV(l1);
|
||||
iv_allowed = iv_allowed && !iv_insubexpr;
|
||||
if (match_expr(l,iv_allowed,&l1,
|
||||
&iv_insubexpr,sign)) {
|
||||
*lbegin = l1;
|
||||
*iv_seen = !iv_allowed || iv_insubexpr;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE; /* subexpression not recognized */
|
||||
case ME_LOOPCONST:
|
||||
*lbegin = l; /* expression is a loop constant */
|
||||
*iv_seen = FALSE;
|
||||
return TRUE;
|
||||
case ME_IV:
|
||||
if (iv_allowed) {
|
||||
*iv_seen = TRUE;
|
||||
*lbegin = l;
|
||||
return TRUE;
|
||||
}
|
||||
/* fall through ... */
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool is_ivexpr(l,ivs,vars,lbegin_out,iv_out,sign_out)
|
||||
line_p l, *lbegin_out;
|
||||
lset ivs,vars;
|
||||
iv_p *iv_out;
|
||||
int *sign_out;
|
||||
{
|
||||
line_p l2;
|
||||
bool iv_seen;
|
||||
|
||||
|
||||
loopvars = vars;
|
||||
ivars = ivs;
|
||||
if (match_expr(l,TRUE,&l2,&iv_seen,1)) {
|
||||
if (iv_seen) {
|
||||
/* recognized a correct expression */
|
||||
*lbegin_out = l2;
|
||||
*iv_out = last_iv;
|
||||
*sign_out = iv_sign;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
13
util/ego/sr/sr_expr.h
Normal file
13
util/ego/sr/sr_expr.h
Normal file
@@ -0,0 +1,13 @@
|
||||
/* S T R E N G T H R E D U C T I O N
|
||||
*
|
||||
* S R _ E X P R . H
|
||||
*
|
||||
*/
|
||||
|
||||
extern bool is_ivexpr();/* (line_p l; lset ivs,vars; line_p *lbegin; iv_p *iv;
|
||||
* int *out_sign)
|
||||
* Try to recognize an expression that is a linear
|
||||
* function of presicely one induction variable.
|
||||
* It may only use loop constants (besides the
|
||||
* induc. var.).
|
||||
*/
|
||||
183
util/ego/sr/sr_iv.c
Normal file
183
util/ego/sr/sr_iv.c
Normal file
@@ -0,0 +1,183 @@
|
||||
/* S T R E N G T H R E D U C T I O N
|
||||
*
|
||||
* S R _ I V . C
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "../share/types.h"
|
||||
#include "sr.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/cset.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/aux.h"
|
||||
#include "sr_aux.h"
|
||||
#include "sr_cand.h"
|
||||
#include "sr_iv.h"
|
||||
|
||||
|
||||
|
||||
STATIC lset ivars; /* set of induction variables */
|
||||
|
||||
STATIC short nature(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* Auxiliary routine used by inc_or_dec, is_add and plus_or_min.
|
||||
* Determine if lnp had INCREMENT/DECREMENT-nature (1),
|
||||
* ADD-nature (2), SUBTRACT-nature (3)
|
||||
* or Buddha-nature (0).
|
||||
*/
|
||||
|
||||
bool size_ok;
|
||||
|
||||
assert(lnp != (line_p) 0);
|
||||
size_ok = (TYPE(lnp) == OPSHORT && SHORT(lnp) == ws);
|
||||
switch(INSTR(lnp)) {
|
||||
case op_inc:
|
||||
case op_dec:
|
||||
return 1;
|
||||
case op_adi:
|
||||
case op_adu:
|
||||
return (size_ok? 2:0);
|
||||
case op_sbi:
|
||||
case op_sbu:
|
||||
return (size_ok? 3:0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define is_add(l) (nature(l) == 2)
|
||||
#define plus_or_min(l) (nature(l) > 1)
|
||||
#define inc_or_dec(l) (nature(l) == 1)
|
||||
|
||||
|
||||
STATIC bool is_same(l,lnp)
|
||||
line_p l, lnp;
|
||||
{
|
||||
/* lnp is a STL x , where x is a candidate
|
||||
* induction variable. See if l is a LOL x
|
||||
* (with the same x as the store-instruction)
|
||||
*/
|
||||
|
||||
assert(INSTR(lnp) == op_stl);
|
||||
return l != (line_p) 0 && INSTR(l) == op_lol &&
|
||||
off_set(l) == off_set(lnp);
|
||||
}
|
||||
|
||||
|
||||
STATIC ivar(lnp,step)
|
||||
line_p lnp;
|
||||
int step;
|
||||
{
|
||||
/* Record the fact that we've found a new induction variable.
|
||||
* lnp points to the last instruction of the code that
|
||||
* increments the induction variable, i.e. a STL, DEL or INL.
|
||||
*/
|
||||
|
||||
iv_p i;
|
||||
|
||||
i = newiv();
|
||||
i->iv_off = (TYPE(lnp) == OPSHORT ? (offset) SHORT(lnp) : OFFSET(lnp));
|
||||
i->iv_incr = lnp; /* last instruction of increment code */
|
||||
i->iv_step = step; /* step value */
|
||||
Ladd(i,&ivars);
|
||||
}
|
||||
|
||||
|
||||
STATIC int sign(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
switch(INSTR(lnp)) {
|
||||
case op_inc:
|
||||
case op_inl:
|
||||
case op_adi:
|
||||
case op_adu:
|
||||
return 1;
|
||||
case op_dec:
|
||||
case op_del:
|
||||
case op_sbi:
|
||||
case op_sbu:
|
||||
return (-1);
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
STATIC try_patterns(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* lnp is a STL x; try to recognize
|
||||
* one of the patterns:
|
||||
* 'LOAD const; LOAD x; ADD; STORE x'
|
||||
* or 'LOAD x; LOAD const; ADD or SUBTRACT;
|
||||
* STORE x'
|
||||
* or 'LOAD x; INCREMENT/DECREMENT; STORE x'
|
||||
*/
|
||||
|
||||
line_p l, l2;
|
||||
|
||||
l = PREV(lnp); /* instruction before lnp*/
|
||||
if (l == (line_p) 0) return; /* no match possible */
|
||||
l2 = PREV(l);
|
||||
if (inc_or_dec(l)) {
|
||||
if (is_same(l2,lnp)) {
|
||||
/* e.g. LOL iv ; INC ; STL iv */
|
||||
ivar(lnp,sign(l));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (is_add(lnp)) {
|
||||
if(is_same(l2,lnp) && is_const(PREV(l2))) {
|
||||
ivar(lnp,SHORT(PREV(l2)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (plus_or_min(l)) {
|
||||
if (is_const(l2) && is_same(PREV(l2),lnp)) {
|
||||
ivar(lnp,sign(l) * SHORT(l2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
induc_vars(loop,ivar_out, vars_out)
|
||||
loop_p loop;
|
||||
lset *ivar_out, *vars_out;
|
||||
{
|
||||
/* Construct the set of induction variables. We use several
|
||||
* global variables computed by 'candidates'.
|
||||
*/
|
||||
|
||||
Lindex i;
|
||||
line_p lnp;
|
||||
lset cand_iv, vars;
|
||||
|
||||
ivars = Lempty_set();
|
||||
candidates(loop, &cand_iv, &vars);
|
||||
/* Find the set of all variables that are assigned precisely
|
||||
* once within the loop, within a firm block.
|
||||
* Also find all remaining local variables that are changed
|
||||
* within the loop.
|
||||
*/
|
||||
if (Lnrelems(cand_iv) > 0) {
|
||||
for (i = Lfirst(cand_iv); i != (Lindex) 0; i = Lnext(i,cand_iv)) {
|
||||
lnp = (line_p) Lelem(i);
|
||||
if (INSTR(lnp) == op_inl || INSTR(lnp) == op_del) {
|
||||
ivar(lnp,sign(lnp));
|
||||
} else {
|
||||
try_patterns(lnp);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ljoin(cand_iv, &vars);
|
||||
*ivar_out = ivars;
|
||||
*vars_out = vars;
|
||||
}
|
||||
7
util/ego/sr/sr_iv.h
Normal file
7
util/ego/sr/sr_iv.h
Normal file
@@ -0,0 +1,7 @@
|
||||
/* S R _ I V . H */
|
||||
|
||||
extern induc_vars(); /* (loop_p loop; lset *ivars, *vars)
|
||||
* Find the set of induction variables
|
||||
* of the loop. Also find the set of (local)
|
||||
* variables that are changed.
|
||||
*/
|
||||
625
util/ego/sr/sr_reduce.c
Normal file
625
util/ego/sr/sr_reduce.c
Normal file
@@ -0,0 +1,625 @@
|
||||
/* S T R E N G T H R E D U C T I O N
|
||||
*
|
||||
* S R _ R E D U C E . C
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "../share/types.h"
|
||||
#include "sr.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/aux.h"
|
||||
#include "sr_aux.h"
|
||||
#include "../share/lset.h"
|
||||
#include "sr_xform.h"
|
||||
#include "sr_reduce.h"
|
||||
#include "sr_expr.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_reg.h"
|
||||
#include "../../../h/em_mes.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
|
||||
|
||||
|
||||
STATIC lset avail;
|
||||
/* If an expression such as "iv * const" or "A[iv]" is
|
||||
* used more than once in a loop, we only use one temporary
|
||||
* local for it and reuse this local each time.
|
||||
* After the first occurrence, the expression is said to
|
||||
* be available.
|
||||
*/
|
||||
|
||||
STATIC int regtyp(code)
|
||||
code_p code;
|
||||
{
|
||||
switch(code->co_instr) {
|
||||
case op_mli:
|
||||
case op_mlu:
|
||||
return reg_any;
|
||||
default:
|
||||
return reg_pointer;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
STATIC gen_regmes(tmp,score,code,p)
|
||||
offset tmp;
|
||||
int score;
|
||||
code_p code;
|
||||
proc_p p;
|
||||
{
|
||||
/* generate a register message for the temporary variable and
|
||||
* insert it at the start of the procedure.
|
||||
*/
|
||||
|
||||
line_p l,pro;
|
||||
|
||||
l = reg_mes(tmp,code->co_tmpsize,regtyp(code),score);
|
||||
pro = p->p_start->b_start; /* every proc. begins with a PRO pseudo */
|
||||
l->l_next = pro->l_next;
|
||||
PREV(l->l_next) = l;
|
||||
pro->l_next = l;
|
||||
PREV(l) = pro;
|
||||
}
|
||||
|
||||
|
||||
STATIC line_p newcode(code,tmp)
|
||||
code_p code;
|
||||
offset tmp;
|
||||
{
|
||||
/* Construct the EM code that will replace the reducible code,
|
||||
* e.g. iv * c -> tmp
|
||||
* a[iv] -> *tmp
|
||||
*/
|
||||
|
||||
line_p l;
|
||||
|
||||
switch(code->co_instr) {
|
||||
case op_mli:
|
||||
case op_mlu:
|
||||
/* new code is just a LOL tmp */
|
||||
l = int_line(tmp);
|
||||
l->l_instr = op_lol;
|
||||
break;
|
||||
case op_aar:
|
||||
/* New code is a LOAD tmp, where tmp is a
|
||||
* pointer variable, so the actual EM code
|
||||
* depends on the pointer size.
|
||||
*/
|
||||
l = move_pointer(tmp,LOAD);
|
||||
break;
|
||||
case op_lar:
|
||||
/* New code is a load-indirect */
|
||||
l = int_line(tmp);
|
||||
l->l_instr = op_lil;
|
||||
break;
|
||||
case op_sar:
|
||||
/* New code is a store-indirect */
|
||||
l = int_line(tmp);
|
||||
l->l_instr = op_sil;
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC replcode(code,text)
|
||||
code_p code;
|
||||
line_p text;
|
||||
{
|
||||
/* Replace old code (extending from code->co_lfirst to
|
||||
* code->co_llast) by new code (headed by 'text').
|
||||
*/
|
||||
|
||||
line_p l, l1, l2;
|
||||
|
||||
for (l = text; l->l_next != (line_p) 0; l = l->l_next);
|
||||
/* 'l' now points to last instruction of text */
|
||||
l1 = PREV(code->co_lfirst); /* instruction just before old code */
|
||||
l2 = code->co_llast->l_next; /* instruction just behind old code */
|
||||
if (l1 == (line_p) 0) {
|
||||
code->co_block->b_start = text;
|
||||
PREV(text) = (line_p) 0;
|
||||
} else {
|
||||
l1->l_next = text;
|
||||
PREV(text) = l1;
|
||||
}
|
||||
if (l2 != (line_p) 0) {
|
||||
PREV(l2) = l;
|
||||
}
|
||||
l->l_next = l2;
|
||||
code->co_llast->l_next = (line_p) 0;
|
||||
/* Note that the old code is still accessible via code->co_lfirst */
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC init_code(code,tmp)
|
||||
code_p code;
|
||||
offset tmp;
|
||||
{
|
||||
/* Generate code to set up the temporary local.
|
||||
* For multiplication, its initial value is const*iv_expr,
|
||||
* for array operations it is &a[iv_expr] (where iv_expr is
|
||||
* an expression that is a linear function of the induc. var.
|
||||
* This code is inserted immediately before the loop entry.
|
||||
* As the initializing code looks very much like the
|
||||
* reduced code, we reuse that (old) code.
|
||||
*/
|
||||
|
||||
line_p l, *p;
|
||||
|
||||
l = code->co_llast; /* the mli, lar etc. instruction */
|
||||
switch(INSTR(l)) {
|
||||
case op_mli:
|
||||
case op_mlu:
|
||||
/* reduced code is: iv_expr * lc (or lc * iv_expr)
|
||||
* init_code is: tmp = iv_expr * lc (or lc*iv_expr)
|
||||
* So we just insert a 'STL tmp'.
|
||||
*/
|
||||
l->l_next = int_line(tmp);
|
||||
l->l_next->l_instr = op_stl;
|
||||
break;
|
||||
case op_lar:
|
||||
case op_sar:
|
||||
/* reduced code is: ...= A[iv_expr] resp.
|
||||
* A[iv]_expr = ..
|
||||
* init_code is: tmp = &A[iv_expr].
|
||||
* So just change the lar or sar into a aar ...
|
||||
*/
|
||||
l->l_instr = (byte) op_aar;
|
||||
/* ... and fall through !! */
|
||||
case op_aar:
|
||||
/* append code to store a pointer in temp. local */
|
||||
l->l_next = move_pointer(tmp,STORE);
|
||||
break;
|
||||
default:
|
||||
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) {
|
||||
/* 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 =
|
||||
code->co_lfirst;
|
||||
} else {
|
||||
(*p)->l_next = code->co_lfirst;
|
||||
PREV(code->co_lfirst) = *p;
|
||||
}
|
||||
*p = l->l_next; /* new last instruction */
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC incr_code(code,tmp)
|
||||
code_p code;
|
||||
offset tmp;
|
||||
{
|
||||
/* Generate code to increment the temporary local variable.
|
||||
* The variable is incremented by
|
||||
* 1) multiply --> step value of iv * loop constant
|
||||
* 2) array --> step value of iv * element size
|
||||
* This value can be determined statically.
|
||||
* If the induction variable is used in a linear
|
||||
* expression in which its sign is negative
|
||||
* (such as in: "5-(6-(-iv))" ), this value is negated.
|
||||
* The generated code looks like:
|
||||
* LOL tmp ; LOC incr ; ADI ws ; STL tmp
|
||||
* For pointer-increments we generate a "ADP c", rather than
|
||||
* a "LOC c; ADS ws".
|
||||
* This code is put just after the code that increments
|
||||
* the induction variable.
|
||||
*/
|
||||
|
||||
line_p load_tmp, loc, add, store_tmp, l;
|
||||
|
||||
add = newline(OPSHORT);
|
||||
SHORT(add) = ws; /* the add instruction, can be ADI,ADU or ADS */
|
||||
switch(code->co_instr) {
|
||||
case op_mli:
|
||||
case op_mlu:
|
||||
loc = int_line(
|
||||
code->co_sign *
|
||||
off_set(code->c_o.co_loadlc) *
|
||||
code->co_iv->iv_step);
|
||||
loc->l_instr = op_loc;
|
||||
add->l_instr = op_adi;
|
||||
load_tmp = int_line(tmp);
|
||||
load_tmp->l_instr = op_lol;
|
||||
store_tmp = int_line(tmp);
|
||||
store_tmp->l_instr = op_stl;
|
||||
break;
|
||||
case op_lar:
|
||||
case op_sar:
|
||||
case op_aar:
|
||||
loc = (line_p) 0;
|
||||
add = int_line(
|
||||
code->co_sign *
|
||||
code->co_iv->iv_step *
|
||||
elemsize(code->c_o.co_desc));
|
||||
add->l_instr = op_adp;
|
||||
load_tmp = move_pointer(tmp,LOAD);
|
||||
store_tmp = move_pointer(tmp,STORE);
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
/* Now we've got pieces of code to load the temp. local,
|
||||
* load the constant, add the two and store the result in
|
||||
* the local. This code will be put just after the code that
|
||||
* increments the induction variable.
|
||||
*/
|
||||
if (loc != (line_p) 0) concatenate(load_tmp,loc);
|
||||
concatenate(load_tmp,add);
|
||||
concatenate(load_tmp,store_tmp);
|
||||
/* Now load_tmp points to a list of EM instructions */
|
||||
l = code->co_iv->iv_incr;
|
||||
if (l->l_next != (line_p) 0) {
|
||||
DLINK(store_tmp,l->l_next);
|
||||
}
|
||||
DLINK(l,load_tmp); /* doubly link them */
|
||||
}
|
||||
|
||||
|
||||
STATIC remcode(c)
|
||||
code_p c;
|
||||
{
|
||||
line_p l, next;
|
||||
|
||||
for (l = c->co_lfirst; l != (line_p) 0; l = next) {
|
||||
next = l->l_next;
|
||||
oldline(l);
|
||||
}
|
||||
oldcinfo(c);
|
||||
}
|
||||
|
||||
|
||||
STATIC bool same_address(l1,l2,vars)
|
||||
line_p l1,l2;
|
||||
lset vars;
|
||||
{
|
||||
/* See if l1 and l2 load the same address */
|
||||
|
||||
if (INSTR(l1) != INSTR(l2)) return FALSE;
|
||||
switch(INSTR(l1)) {
|
||||
case op_lae:
|
||||
return OBJ(l1) == OBJ(l2);
|
||||
case op_lal:
|
||||
return off_set(l1) == off_set(l2);
|
||||
case op_lol:
|
||||
return ps == ws &&
|
||||
off_set(l1) == off_set(l2) &&
|
||||
is_loopconst(l1,vars);
|
||||
case op_ldl:
|
||||
return ps == 2*ws &&
|
||||
off_set(l1) == off_set(l2) &&
|
||||
is_loopconst(l1,vars);
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC bool same_expr(lb1,le1,lb2,le2)
|
||||
line_p lb1,le1,lb2,le2;
|
||||
{
|
||||
/* See if the code from lb1 to le1 is the same
|
||||
* expression as the code from lb2 to le2.
|
||||
*/
|
||||
|
||||
|
||||
register line_p l1,l2;
|
||||
|
||||
l1 = lb1;
|
||||
l2 = lb2;
|
||||
for (;;) {
|
||||
if (INSTR(l1) != INSTR(l2)) return FALSE;
|
||||
switch(TYPE(l1)) {
|
||||
case OPSHORT:
|
||||
if (TYPE(l2) != OPSHORT ||
|
||||
SHORT(l1) != SHORT(l2)) return FALSE;
|
||||
break;
|
||||
case OPOFFSET:
|
||||
if (TYPE(l2) != OPOFFSET ||
|
||||
OFFSET(l1) != OFFSET(l2)) return FALSE;
|
||||
break;
|
||||
case OPNO:
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
if (l1 == le1 ) return l2 == le2;
|
||||
if (l2 == le2) return FALSE;
|
||||
l1 = l1->l_next;
|
||||
l2 = l2->l_next;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC bool same_code(c1,c2,vars)
|
||||
code_p c1,c2;
|
||||
lset vars;
|
||||
{
|
||||
/* See if c1 and c2 compute the same expression. Two array
|
||||
* references can be the same even if one is e.g a fetch
|
||||
* and the other a store.
|
||||
*/
|
||||
|
||||
switch(c1->co_instr) {
|
||||
case op_mli:
|
||||
return c1->co_instr == c2->co_instr &&
|
||||
off_set(c1->c_o.co_loadlc) ==
|
||||
off_set(c2->c_o.co_loadlc) &&
|
||||
same_expr(c1->co_ivexpr,c1->co_endexpr,
|
||||
c2->co_ivexpr,c2->co_endexpr);
|
||||
case op_aar:
|
||||
case op_lar:
|
||||
case op_sar:
|
||||
return c2->co_instr != op_mli &&
|
||||
c2->co_instr != op_mlu &&
|
||||
same_expr(c1->co_ivexpr,c1->co_endexpr,
|
||||
c2->co_ivexpr,c2->co_endexpr) &&
|
||||
same_address(c1->c_o.co_desc,c2->c_o.co_desc,vars) &&
|
||||
same_address(c1->co_lfirst,c2->co_lfirst,vars);
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
STATIC code_p available(c,vars)
|
||||
code_p c;
|
||||
lset vars;
|
||||
{
|
||||
/* See if the code is already available.
|
||||
* If so, return a pointer to the first occurrence
|
||||
* of the code.
|
||||
*/
|
||||
|
||||
Lindex i;
|
||||
code_p cp;
|
||||
|
||||
for (i = Lfirst(avail); i != (Lindex) 0; i = Lnext(i,avail)) {
|
||||
cp = (code_p) Lelem(i);
|
||||
if (same_code(c,cp,vars)) {
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
return (code_p) 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC reduce(code,vars)
|
||||
code_p code;
|
||||
lset vars;
|
||||
{
|
||||
/* Perform the actual transformations. The code on the left
|
||||
* gets transformed into the code on the right. Note that
|
||||
* each piece of code is assigned a name, that will be
|
||||
* used to describe the whole process.
|
||||
*
|
||||
* t = iv * 118; (init_code)
|
||||
* do ---> do
|
||||
* .. iv * 118 .. .. t .. (new_code)
|
||||
* iv++; iv++;
|
||||
* t += 118; (incr_code)
|
||||
* od od
|
||||
*/
|
||||
|
||||
offset tmp;
|
||||
code_p ac;
|
||||
|
||||
OUTTRACE("succeeded!!",0);
|
||||
if ((ac = available(code,vars)) != (code_p) 0) {
|
||||
/* The expression is already available, so we
|
||||
* don't have to generate a new temporary local for it.
|
||||
*/
|
||||
OUTTRACE("expression was already available",0);
|
||||
replcode(code,newcode(code,ac->co_temp));
|
||||
remcode(code);
|
||||
} else {
|
||||
make_header(code->co_loop);
|
||||
/* make sure there's a header block */
|
||||
tmp = tmplocal(curproc,code->co_tmpsize);
|
||||
code->co_temp = tmp;
|
||||
/* create a new local variable in the stack frame
|
||||
* of current proc.
|
||||
*/
|
||||
gen_regmes(tmp,3,code,curproc); /* generate register message */
|
||||
/* score is set to 3, as TMP is used at least 3 times */
|
||||
replcode(code,newcode(code,tmp));
|
||||
OUTTRACE("replaced old code by new code",0);
|
||||
/* Construct the EM-code that will replace the reducible code
|
||||
* and replace the old code by the new code.
|
||||
*/
|
||||
init_code(code,tmp);
|
||||
OUTTRACE("emitted initializing code",0);
|
||||
/* Emit code to initialize the temporary local. This code is
|
||||
* put in the loop header block.
|
||||
*/
|
||||
incr_code(code,tmp); /* emit code to increment temp. local */
|
||||
OUTTRACE("emitted increment code",0);
|
||||
Ladd(code,&avail);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC try_multiply(lp,ivs,vars,b,mul)
|
||||
loop_p lp;
|
||||
lset ivs,vars;
|
||||
bblock_p b;
|
||||
line_p mul;
|
||||
{
|
||||
/* See if we can reduce the strength of the multiply
|
||||
* instruction. If so, then set up the global common
|
||||
* data structure 'c' (containing information about the
|
||||
* code to be reduced) and call 'reduce'.
|
||||
*/
|
||||
|
||||
line_p l2,lbegin;
|
||||
iv_p iv;
|
||||
code_p c;
|
||||
int sign;
|
||||
|
||||
VL(mul);
|
||||
OUTTRACE("trying multiply instruction on line %d",linecount);
|
||||
if (ovfl_harmful && !IS_STRONG(b)) return;
|
||||
/* If b is not a strong block, optimization may
|
||||
* introduce an overflow error in the initializing code.
|
||||
*/
|
||||
|
||||
l2 = PREV(mul); /* Instruction before the multiply */
|
||||
if ( (is_ivexpr(l2,ivs,vars,&lbegin,&iv,&sign)) &&
|
||||
is_const(PREV(lbegin)) ) {
|
||||
/* recognized expression "const * iv_expr" */
|
||||
c = newcinfo();
|
||||
c->c_o.co_loadlc = PREV(l2);
|
||||
c->co_endexpr = l2;
|
||||
} else {
|
||||
if (is_const(l2) &&
|
||||
(is_ivexpr(PREV(l2),ivs,vars,&lbegin,&iv,&sign))) {
|
||||
/* recognized "iv * const " */
|
||||
c = newcinfo();
|
||||
c->c_o.co_loadlc = l2;
|
||||
c->co_endexpr = PREV(l2);
|
||||
} else {
|
||||
OUTTRACE("failed",0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* common part for both patterns */
|
||||
c->co_iv = iv;
|
||||
c->co_loop = lp;
|
||||
c->co_block = b;
|
||||
c->co_lfirst = PREV(l2);
|
||||
c->co_llast = mul;
|
||||
c->co_ivexpr = lbegin;
|
||||
c->co_sign = sign;
|
||||
c->co_tmpsize = ws; /* temp. local is a word */
|
||||
c->co_instr = INSTR(mul);
|
||||
OUTVERBOSE("sr: multiply in proc %d loop %d",
|
||||
curproc->p_id, lp->lp_id);
|
||||
Ssr++;
|
||||
reduce(c,vars);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC try_array(lp,ivs,vars,b,arr)
|
||||
loop_p lp;
|
||||
lset ivs,vars;
|
||||
bblock_p b;
|
||||
line_p arr;
|
||||
{
|
||||
/* See if we can reduce the strength of the array reference
|
||||
* instruction 'arr'.
|
||||
*/
|
||||
|
||||
line_p l2,l3,lbegin;
|
||||
iv_p iv;
|
||||
code_p c;
|
||||
int sign;
|
||||
|
||||
/* Try to recognize the pattern:
|
||||
* LOAD ADDRES OF A
|
||||
* LOAD IV
|
||||
* LOAD ADDRESS OF DESCRIPTOR
|
||||
*/
|
||||
VL(arr);
|
||||
OUTTRACE("trying array instruction on line %d",linecount);
|
||||
if (arrbound_harmful && !IS_STRONG(b)) return;
|
||||
/* If b is not a strong block, optimization may
|
||||
* introduce an array bound error in the initializing code.
|
||||
*/
|
||||
l2 = PREV(arr);
|
||||
if (is_caddress(l2,vars) &&
|
||||
(INSTR(arr) == op_aar || elemsize(l2) == ws) &&
|
||||
(is_ivexpr(PREV(l2),ivs,vars,&lbegin,&iv,&sign)) ) {
|
||||
l3 = PREV(lbegin);
|
||||
if (is_caddress(l3,vars)) {
|
||||
c = newcinfo();
|
||||
c->co_iv = iv;
|
||||
c->co_loop = lp;
|
||||
c->co_block = b;
|
||||
c->co_lfirst = l3;
|
||||
c->co_llast = arr;
|
||||
c->co_ivexpr = lbegin;
|
||||
c->co_endexpr = PREV(l2);
|
||||
c->co_sign = sign;
|
||||
c->co_tmpsize = ps; /* temp. local is pointer */
|
||||
c->co_instr = INSTR(arr);
|
||||
c->c_o.co_desc = l2;
|
||||
OUTVERBOSE("sr: array in proc %d loop %d",
|
||||
curproc->p_id,lp->lp_id);
|
||||
Ssr++;
|
||||
reduce(c,vars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC clean_avail()
|
||||
{
|
||||
Lindex i;
|
||||
|
||||
for (i = Lfirst(avail); i != (Lindex) 0; i = Lnext(i,avail)) {
|
||||
oldcinfo(Lelem(i));
|
||||
}
|
||||
Ldeleteset(avail);
|
||||
}
|
||||
|
||||
|
||||
|
||||
strength_reduction(lp,ivs,vars)
|
||||
loop_p lp; /* description of the loop */
|
||||
lset ivs; /* set of induction variables of the loop */
|
||||
lset vars; /* set of local variables changed in loop */
|
||||
{
|
||||
/* Find all expensive instructions (multiply, array) and see if
|
||||
* they can be reduced. We branch to several instruction-specific
|
||||
* routines (try_...) that check if reduction is possible,
|
||||
* and that set up a common data structure (code_info).
|
||||
* The actual transformations are done by 'reduce', that is
|
||||
* essentially instruction-independend.
|
||||
*/
|
||||
|
||||
bblock_p b;
|
||||
line_p l, next;
|
||||
Lindex i;
|
||||
|
||||
avail = Lempty_set();
|
||||
for (i = Lfirst(lp->LP_BLOCKS); i != (Lindex) 0;
|
||||
i = Lnext(i,lp->LP_BLOCKS)) {
|
||||
b = (bblock_p) Lelem(i);
|
||||
for (l = b->b_start; l != (line_p) 0; l = next) {
|
||||
next = l->l_next;
|
||||
if (TYPE(l) == OPSHORT && SHORT(l) == ws) {
|
||||
switch(INSTR(l)) {
|
||||
case op_mlu:
|
||||
case op_mli:
|
||||
try_multiply(lp,ivs,vars,b,l);
|
||||
break;
|
||||
case op_lar:
|
||||
case op_sar:
|
||||
case op_aar:
|
||||
try_array(lp,ivs,vars,b,l);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
clean_avail();
|
||||
}
|
||||
5
util/ego/sr/sr_reduce.h
Normal file
5
util/ego/sr/sr_reduce.h
Normal file
@@ -0,0 +1,5 @@
|
||||
/* S R _ R E D U C E . H */
|
||||
|
||||
extern strength_reduction(); /* (loop_p loop; lset ivs, vars)
|
||||
* Perform streength reduction.
|
||||
*/
|
||||
178
util/ego/sr/sr_xform.c
Normal file
178
util/ego/sr/sr_xform.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/* S T R E N G T H R E D U C T I O N
|
||||
*
|
||||
* S R _ X F O R M . C
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "sr.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/def.h"
|
||||
#include "../share/get.h"
|
||||
#include "sr_aux.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "sr_xform.h"
|
||||
|
||||
/* Transformations on EM texts */
|
||||
|
||||
line_p move_pointer(tmp,dir)
|
||||
offset tmp;
|
||||
int dir;
|
||||
{
|
||||
/* Generate EM code to load/store a pointer variable
|
||||
* onto/from the stack, depending on dir(ection).
|
||||
* We accept all kinds of pointer sizes.
|
||||
*/
|
||||
|
||||
line_p l;
|
||||
|
||||
l = int_line(tmp);
|
||||
if (ps == ws) {
|
||||
/* pointer fits in a word */
|
||||
l->l_instr = (dir == LOAD ? op_lol : op_stl);
|
||||
} else {
|
||||
if (ps == 2 * ws) {
|
||||
/* pointer fits in a double word */
|
||||
l->l_instr = (dir == LOAD ? op_ldl : op_sdl);
|
||||
} else {
|
||||
/* very large pointer size, generate code:
|
||||
* LAL tmp ; LOI/STI ps */
|
||||
l->l_instr = op_lal;
|
||||
l->l_next = newline(OPSHORT);
|
||||
SHORT(l->l_next) = ps;
|
||||
l->l_next->l_instr =
|
||||
(dir == LOAD ? op_loi : op_sti);
|
||||
PREV(l->l_next) = l;
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* make_header */
|
||||
|
||||
STATIC copy_loops(b1,b2,except)
|
||||
bblock_p b1,b2;
|
||||
loop_p except;
|
||||
{
|
||||
/* Copy the loopset of b2 to b1, except for 'except' */
|
||||
|
||||
Lindex i;
|
||||
loop_p lp;
|
||||
for (i = Lfirst(b2->b_loops); i != (Lindex) 0;
|
||||
i = Lnext(i,b2->b_loops)) {
|
||||
lp = (loop_p) Lelem(i);
|
||||
if (lp != except) {
|
||||
Ladd(lp,&b1->b_loops);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC lab_id label(b)
|
||||
bblock_p b;
|
||||
{
|
||||
/* Find the label at the head of block b. If there is
|
||||
* no such label yet, create one.
|
||||
*/
|
||||
|
||||
line_p l;
|
||||
|
||||
assert (b->b_start != (line_p) 0);
|
||||
if (INSTR(b->b_start) == op_lab) return INSTRLAB(b->b_start);
|
||||
/* The block has no label yet. */
|
||||
l = newline(OPINSTRLAB);
|
||||
INSTRLAB(l) = freshlabel();
|
||||
DLINK(l,b->b_start); /* doubly link them */
|
||||
return INSTRLAB(l);
|
||||
}
|
||||
|
||||
|
||||
STATIC adjust_jump(newtarg,oldtarg,c)
|
||||
bblock_p newtarg,oldtarg,c;
|
||||
{
|
||||
/* If the last instruction of c is a jump to the
|
||||
* old target, then change it into a jump to the
|
||||
* start of the new target.
|
||||
*/
|
||||
|
||||
line_p l;
|
||||
|
||||
if (INSTR(oldtarg->b_start) == op_lab) {
|
||||
/* If old target has no label, it cannot be jumped to */
|
||||
l = last_instr(c);
|
||||
assert(l != (line_p) 0);
|
||||
if (TYPE(l) == OPINSTRLAB &&
|
||||
INSTRLAB(l) == INSTRLAB(oldtarg->b_start)) {
|
||||
INSTRLAB(l) = label(newtarg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
make_header(lp)
|
||||
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
|
||||
* that dominates the loop entry block.
|
||||
* If there is no header yet, create one.
|
||||
*/
|
||||
|
||||
bblock_p b,c,entry;
|
||||
Lindex i,next;
|
||||
|
||||
if (lp->LP_HEADER != (bblock_p) 0) return;
|
||||
OUTTRACE("creating a new header block",0);
|
||||
/* The loop has no header yet. The main problem is to
|
||||
* keep all relations (SUCC, PRED, NEXT, IDOM, LOOPS)
|
||||
* up to date.
|
||||
*/
|
||||
b = freshblock(); /* new block with new b_id */
|
||||
entry = lp->lp_entry;
|
||||
|
||||
/* update succ/pred. Also take care that any jump from outside
|
||||
* the loop to the entry block now goes to b.
|
||||
*/
|
||||
|
||||
for (i = Lfirst(entry->b_pred); i != (Lindex) 0; i = next ) {
|
||||
next = Lnext(i,entry->b_pred);
|
||||
c = (bblock_p) Lelem(i);
|
||||
/* c is a predecessor of the entry block */
|
||||
if (!Lis_elem(c,lp->LP_BLOCKS)) {
|
||||
/* c is outside the loop */
|
||||
Lremove(c,&entry->b_pred);
|
||||
Lremove(entry,&c->b_succ);
|
||||
Ladd(b,&c->b_succ);
|
||||
adjust_jump(b,entry,c);
|
||||
}
|
||||
}
|
||||
Ladd(b,&entry->b_pred);
|
||||
b->b_succ = Lempty_set();
|
||||
b->b_pred = Lempty_set();
|
||||
Ladd(entry,&b->b_succ);
|
||||
if (curproc->p_start == entry) {
|
||||
/* entry was the first block of curproc */
|
||||
curproc->p_start = b;
|
||||
} else {
|
||||
/* find block before entry block */
|
||||
for (c = curproc->p_start; c->b_next != entry; c = c->b_next);
|
||||
c->b_next = b;
|
||||
Ladd(c,&b->b_pred);
|
||||
}
|
||||
b->b_next = entry;
|
||||
copy_loops(b,entry,lp);
|
||||
b->b_idom = entry->b_idom;
|
||||
entry->b_idom = b;
|
||||
lp->LP_HEADER = b;
|
||||
}
|
||||
19
util/ego/sr/sr_xform.h
Normal file
19
util/ego/sr/sr_xform.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/* S T R E N G T H R E D U C T I O N
|
||||
*
|
||||
* S R _ X F O R M . H
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
line_p move_pointer(); /* (offset tmp; int dir ) */
|
||||
/* Generate EM code to load/store a pointer variable
|
||||
* onto/from the stack, depending on dir(ection).
|
||||
* We accept all kinds of pointer sizes.
|
||||
*/
|
||||
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
|
||||
* that dominates the loop entry block.
|
||||
* If there is no header yet, create one.
|
||||
*/
|
||||
Reference in New Issue
Block a user