183 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			183 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* 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 ivvars;	/* 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,&ivvars);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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;
 | 
						|
 | 
						|
	ivvars = 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 = ivvars;
 | 
						|
	*vars_out = vars;
 | 
						|
}
 |