version.c: Bump for new snapshot.
* version.c: Bump for new snapshot. * local-alloc.c (update_equiv_regs): All the target to reject promotion of some REG_EQUAL to REG_EQUIV notes. * pa.h (DONT_RECORD_EQUIVALENCE): Define. Fixes some c-torture failures, also improves generated code. * pa.c (secondary_reload_class): (mem (mem ... )) does not need secondary reloads. Fixes 094.fpppp/twldrv.f abort. * pa.c (hppa_builtin_saveregs): Emit a blockage insn after the store of the argument registers. Fixes c-torture failure. * fold-const.c (multiple_of_p): New function. (fold): Turn some cases of *_DIV_EXPR into EXACT_DIV_EXPR. One of the performance patches from the g77 folks. From-SVN: r14915
This commit is contained in:
parent
d78778ebf9
commit
39dfb55a01
7 changed files with 194 additions and 1 deletions
|
@ -1,3 +1,22 @@
|
|||
Mon Aug 25 08:55:00 1997 Jeffrey A Law (law@cygnus.com)
|
||||
|
||||
* version.c: Bump for new snapshot.
|
||||
|
||||
* local-alloc.c (update_equiv_regs): All the target to reject
|
||||
promotion of some REG_EQUAL to REG_EQUIV notes.
|
||||
* pa.h (DONT_RECORD_EQUIVALENCE): Define.
|
||||
|
||||
* pa.c (secondary_reload_class): (mem (mem ... )) does not need
|
||||
secondary reloads.
|
||||
|
||||
* pa.c (hppa_builtin_saveregs): Emit a blockage insn after the
|
||||
store of the argument registers.
|
||||
|
||||
Mon Aug 25 08:39:02 1997 Craig Burley (burley@gnu.ai.mit.edu)
|
||||
|
||||
* fold-const.c (multiple_of_p): New function.
|
||||
(fold): Turn some cases of *_DIV_EXPR into EXACT_DIV_EXPR.
|
||||
|
||||
Mon Aug 25 01:47:41 1997 Jeffrey A Law (law@cygnus.com)
|
||||
|
||||
* expr.h (insn_gen_function): Temporarily remove prototype.
|
||||
|
|
|
@ -4195,6 +4195,15 @@ secondary_reload_class (class, mode, in)
|
|||
else
|
||||
regno = -1;
|
||||
|
||||
/* If we have something like (mem (mem (...)), we can safely assume the
|
||||
inner MEM will end up in a general register after reloading, so there's
|
||||
no need for a secondary reload. */
|
||||
if (GET_CODE (in) == MEM
|
||||
&& GET_CODE (XEXP (in, 0)) == MEM)
|
||||
return NO_REGS;
|
||||
|
||||
/* Handle out of range displacement for integer mode loads/stores of
|
||||
FP registers. */
|
||||
if (((regno >= FIRST_PSEUDO_REGISTER || regno == -1)
|
||||
&& GET_MODE_CLASS (mode) == MODE_INT
|
||||
&& FP_REG_CLASS_P (class))
|
||||
|
@ -4223,6 +4232,7 @@ secondary_reload_class (class, mode, in)
|
|||
|| GET_CODE (XEXP (tmp, 0)) == LABEL_REF)
|
||||
&& GET_CODE (XEXP (tmp, 1)) == CONST_INT);
|
||||
break;
|
||||
|
||||
default:
|
||||
is_symbolic = 0;
|
||||
break;
|
||||
|
@ -4291,6 +4301,17 @@ hppa_builtin_saveregs (arglist)
|
|||
plus_constant (current_function_internal_arg_pointer, -16));
|
||||
move_block_from_reg (23, dest, 4, 4 * UNITS_PER_WORD);
|
||||
|
||||
/* move_block_from_reg will emit code to store the argument registers
|
||||
individually as scalar stores.
|
||||
|
||||
However, other insns may later load from the same addresses for
|
||||
a struture load (passing a struct to a varargs routine).
|
||||
|
||||
The alias code assumes that such aliasing can never happen, so we
|
||||
have to keep memory referencing insns from moving up beyond the
|
||||
last argument register store. So we emit a blockage insn here. */
|
||||
emit_insn (gen_blockage ());
|
||||
|
||||
if (flag_check_memory_usage)
|
||||
emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
|
||||
dest, ptr_mode,
|
||||
|
|
|
@ -793,6 +793,20 @@ enum reg_class { NO_REGS, R1_REGS, GENERAL_REGS, FP_REGS, GENERAL_OR_FP_REGS,
|
|||
#define CLASS_MAX_NREGS(CLASS, MODE) \
|
||||
(!TARGET_SNAKE && (CLASS) == FP_REGS ? 1 : \
|
||||
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
|
||||
|
||||
/* We do not want to record equivalences for expressions which are
|
||||
likely to cause a spill of %r1 if they are used by reload.
|
||||
|
||||
Nor do we want to record an equivalence of a constant expression
|
||||
that the target can not handle appearing in an insn, but which
|
||||
also must be accepted by LEGITIMATE_CONSTANT_P.
|
||||
|
||||
On the PA, these two goals are the same -- don't record any equivalences
|
||||
for symbolic operands that are not read_only_operands. */
|
||||
#define DONT_RECORD_EQUIVALENCE(NOTE) \
|
||||
(symbolic_operand (XEXP (NOTE, 0), VOIDmode) \
|
||||
&& !read_only_operand (XEXP (NOTE, 0), VOIDmode))
|
||||
|
||||
|
||||
/* Stack layout; function entry, exit and calling. */
|
||||
|
||||
|
|
113
gcc/fold-const.c
113
gcc/fold-const.c
|
@ -91,6 +91,7 @@ static tree fold_range_test PROTO((tree));
|
|||
static tree unextend PROTO((tree, int, int, tree));
|
||||
static tree fold_truthop PROTO((enum tree_code, tree, tree, tree));
|
||||
static tree strip_compound_expr PROTO((tree, tree));
|
||||
static int multiple_of_p PROTO((tree, tree, tree));
|
||||
|
||||
#ifndef BRANCH_COST
|
||||
#define BRANCH_COST 1
|
||||
|
@ -4548,6 +4549,17 @@ fold (expr)
|
|||
if (integer_zerop (arg1))
|
||||
return t;
|
||||
|
||||
/* If arg0 is a multiple of arg1, then rewrite to the fastest div
|
||||
operation, EXACT_DIV_EXPR.
|
||||
|
||||
Note that only CEIL_DIV_EXPR is rewritten now, only because the
|
||||
others seem to be faster in some cases. This is probably just
|
||||
due to more work being done to optimize others in expmed.c than on
|
||||
EXACT_DIV_EXPR. */
|
||||
if (code == CEIL_DIV_EXPR
|
||||
&& multiple_of_p (type, arg0, arg1))
|
||||
return fold (build (EXACT_DIV_EXPR, type, arg0, arg1));
|
||||
|
||||
/* If we have ((a / C1) / C2) where both division are the same type, try
|
||||
to simplify. First see if C1 * C2 overflows or not. */
|
||||
if (TREE_CODE (arg0) == code && TREE_CODE (arg1) == INTEGER_CST
|
||||
|
@ -5723,3 +5735,104 @@ fold (expr)
|
|||
return t;
|
||||
} /* switch (code) */
|
||||
}
|
||||
|
||||
/* Determine if first argument is a multiple of second argument.
|
||||
Return 0 if it is not, or is not easily determined to so be.
|
||||
|
||||
An example of the sort of thing we care about (at this point --
|
||||
this routine could surely be made more general, and expanded
|
||||
to do what the *_DIV_EXPR's fold() cases do now) is discovering
|
||||
that
|
||||
|
||||
SAVE_EXPR (I) * SAVE_EXPR (J * 8)
|
||||
|
||||
is a multiple of
|
||||
|
||||
SAVE_EXPR (J * 8)
|
||||
|
||||
when we know that the two `SAVE_EXPR (J * 8)' nodes are the
|
||||
same node (which means they will have the same value at run
|
||||
time, even though we don't know when they'll be assigned).
|
||||
|
||||
This code also handles discovering that
|
||||
|
||||
SAVE_EXPR (I) * SAVE_EXPR (J * 8)
|
||||
|
||||
is a multiple of
|
||||
|
||||
8
|
||||
|
||||
(of course) so we don't have to worry about dealing with a
|
||||
possible remainder.
|
||||
|
||||
Note that we _look_ inside a SAVE_EXPR only to determine
|
||||
how it was calculated; it is not safe for fold() to do much
|
||||
of anything else with the internals of a SAVE_EXPR, since
|
||||
fold() cannot know when it will be evaluated at run time.
|
||||
For example, the latter example above _cannot_ be implemented
|
||||
as
|
||||
|
||||
SAVE_EXPR (I) * J
|
||||
|
||||
or any variant thereof, since the value of J at evaluation time
|
||||
of the original SAVE_EXPR is not necessarily the same at the time
|
||||
the new expression is evaluated. The only optimization of this
|
||||
sort that would be valid is changing
|
||||
|
||||
SAVE_EXPR (I) * SAVE_EXPR (SAVE_EXPR (J) * 8)
|
||||
divided by
|
||||
8
|
||||
|
||||
to
|
||||
|
||||
SAVE_EXPR (I) * SAVE_EXPR (J)
|
||||
|
||||
(where the same SAVE_EXPR (J) is used in the original and the
|
||||
transformed version). */
|
||||
|
||||
static int
|
||||
multiple_of_p (type, top, bottom)
|
||||
tree type;
|
||||
tree top;
|
||||
tree bottom;
|
||||
{
|
||||
if (operand_equal_p (top, bottom, 0))
|
||||
return 1;
|
||||
|
||||
if (TREE_CODE (type) != INTEGER_TYPE)
|
||||
return 0;
|
||||
|
||||
switch (TREE_CODE (top))
|
||||
{
|
||||
case MULT_EXPR:
|
||||
return (multiple_of_p (type, TREE_OPERAND (top, 0), bottom)
|
||||
|| multiple_of_p (type, TREE_OPERAND (top, 1), bottom));
|
||||
|
||||
case PLUS_EXPR:
|
||||
case MINUS_EXPR:
|
||||
return (multiple_of_p (type, TREE_OPERAND (top, 0), bottom)
|
||||
&& multiple_of_p (type, TREE_OPERAND (top, 1), bottom));
|
||||
|
||||
case NOP_EXPR:
|
||||
/* Punt if conversion from non-integral or wider integral type. */
|
||||
if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (top, 0))) != INTEGER_TYPE)
|
||||
|| (TYPE_PRECISION (type)
|
||||
< TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (top, 0)))))
|
||||
return 0;
|
||||
/* Fall through. */
|
||||
case SAVE_EXPR:
|
||||
return multiple_of_p (type, TREE_OPERAND (top, 0), bottom);
|
||||
|
||||
case INTEGER_CST:
|
||||
if ((TREE_CODE (bottom) != INTEGER_CST)
|
||||
|| (tree_int_cst_sgn (top) < 0)
|
||||
|| (tree_int_cst_sgn (bottom) < 0))
|
||||
return 0;
|
||||
return integer_zerop (const_binop (TRUNC_MOD_EXPR,
|
||||
top, bottom, 0));
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1048,6 +1048,22 @@ update_equiv_regs ()
|
|||
|
||||
note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
|
||||
|
||||
#ifdef DONT_RECORD_EQUIVALENCE
|
||||
/* Allow the target to reject promotions of some REG_EQUAL notes to
|
||||
REG_EQUIV notes.
|
||||
|
||||
In some cases this can improve register allocation if the existence
|
||||
of the REG_EQUIV note is likely to increase the lifetime of a register
|
||||
that is likely to be spilled.
|
||||
|
||||
It may also be necessary if the target can't handle certain constant
|
||||
expressions appearing randomly in insns, but for whatever reason
|
||||
those expressions must be considered legitimate constant expressions
|
||||
to prevent them from being forced into memory. */
|
||||
if (note && DONT_RECORD_EQUIVALENCE (note))
|
||||
note = NULL;
|
||||
#endif
|
||||
|
||||
/* Record this insn as initializing this register. */
|
||||
reg_equiv_init_insn[regno] = insn;
|
||||
|
||||
|
|
10
gcc/tm.texi
10
gcc/tm.texi
|
@ -4177,6 +4177,16 @@ an immediate operand on the target machine. You can assume that
|
|||
@var{x} satisfies @code{CONSTANT_P}, so you need not check this. In fact,
|
||||
@samp{1} is a suitable definition for this macro on machines where
|
||||
anything @code{CONSTANT_P} is valid.@refill
|
||||
|
||||
@findex DONT_RECORD_EQUIVALENCE
|
||||
@item DONT_RECORD_EQUIVALENCE (@var{note})
|
||||
A C expression that is nonzero if the @code{REG_EQUAL} note @var{x} should not
|
||||
be promoted to a @code{REG_EQUIV} note.
|
||||
|
||||
Define this macro if @var{note} refers to a constant that must be accepted
|
||||
by @code{LEGITIMATE_CONSTANT_P}, but must not appear as an immediate operand.
|
||||
|
||||
Most machine descriptions do not need to define this macro.
|
||||
@end table
|
||||
|
||||
@node Condition Code
|
||||
|
|
|
@ -1 +1 @@
|
|||
char *version_string = "egcs-2.90.01 970821 (gcc2-970802 experimental)";
|
||||
char *version_string = "egcs-2.90.02 970825 (gcc2-970802 experimental)";
|
||||
|
|
Loading…
Add table
Reference in a new issue