diff options
author | Paolo Bonzini <bonzini@gnu.org> | 2008-04-02 09:53:34 +0000 |
---|---|---|
committer | Paolo Bonzini <bonzini@gcc.gnu.org> | 2008-04-02 09:53:34 +0000 |
commit | 460d667de96a60d8dc0caad68a41422d165a5619 (patch) | |
tree | c27ceffbcdf941a1893f3e4693d2b26cb171f702 /gcc/fwprop.c | |
parent | a26a02d7a7dd7aab2ba509d41f24ec3ebc649280 (diff) | |
download | gcc-460d667de96a60d8dc0caad68a41422d165a5619.zip gcc-460d667de96a60d8dc0caad68a41422d165a5619.tar.gz gcc-460d667de96a60d8dc0caad68a41422d165a5619.tar.bz2 |
fwprop.c (PR_CAN_APPEAR, [...]): New.
2008-04-02 Paolo Bonzini <bonzini@gnu.org>
* fwprop.c (PR_CAN_APPEAR, PR_HANDLE_MEM): New.
(propagate_rtx_1): Handle PR_HANDLE_MEM.
(propagate_rtx): Pass PR_HANDLE_MEM if appropriate.
(varying_mem_p): Move above propagate_rtx.
(all_uses_available_at): Do not check MEMs.
From-SVN: r133828
Diffstat (limited to 'gcc/fwprop.c')
-rw-r--r-- | gcc/fwprop.c | 113 |
1 files changed, 74 insertions, 39 deletions
diff --git a/gcc/fwprop.c b/gcc/fwprop.c index b0ae1ba..2566cbb 100644 --- a/gcc/fwprop.c +++ b/gcc/fwprop.c @@ -208,47 +208,76 @@ should_replace_address (rtx old, rtx new, enum machine_mode mode) return (gain > 0); } + +/* Flags for the last parameter of propagate_rtx_1. */ + +enum { + /* If PR_CAN_APPEAR is true, propagate_rtx_1 always returns true; + if it is false, propagate_rtx_1 returns false if, for at least + one occurrence OLD, it failed to collapse the result to a constant. + For example, (mult:M (reg:M A) (minus:M (reg:M B) (reg:M A))) may + collapse to zero if replacing (reg:M B) with (reg:M A). + + PR_CAN_APPEAR is disregarded inside MEMs: in that case, + propagate_rtx_1 just tries to make cheaper and valid memory + addresses. */ + PR_CAN_APPEAR = 1, + + /* If PR_HANDLE_MEM is not set, propagate_rtx_1 won't attempt any replacement + outside memory addresses. This is needed because propagate_rtx_1 does + not do any analysis on memory; thus it is very conservative and in general + it will fail if non-read-only MEMs are found in the source expression. + + PR_HANDLE_MEM is set when the source of the propagation was not + another MEM. Then, it is safe not to treat non-read-only MEMs as + ``opaque'' objects. */ + PR_HANDLE_MEM = 2, +}; + + /* Replace all occurrences of OLD in *PX with NEW and try to simplify the resulting expression. Replace *PX with a new RTL expression if an occurrence of OLD was found. - If CAN_APPEAR is true, we always return true; if it is false, we - can return false if, for at least one occurrence OLD, we failed to - collapse the result to a constant. For example, (mult:M (reg:M A) - (minus:M (reg:M B) (reg:M A))) may collapse to zero if replacing - (reg:M B) with (reg:M A). - - CAN_APPEAR is disregarded inside MEMs: in that case, we always return - true if the simplification is a cheaper and valid memory address. - This is only a wrapper around simplify-rtx.c: do not add any pattern matching code here. (The sole exception is the handling of LO_SUM, but that is because there is no simplify_gen_* function for LO_SUM). */ static bool -propagate_rtx_1 (rtx *px, rtx old, rtx new, bool can_appear) +propagate_rtx_1 (rtx *px, rtx old, rtx new, int flags) { rtx x = *px, tem = NULL_RTX, op0, op1, op2; enum rtx_code code = GET_CODE (x); enum machine_mode mode = GET_MODE (x); enum machine_mode op_mode; + bool can_appear = (flags & PR_CAN_APPEAR) != 0; bool valid_ops = true; - /* If X is OLD_RTX, return NEW_RTX. Otherwise, if this is an expression, - try to build a new expression from recursive substitution. */ + if (!(flags & PR_HANDLE_MEM) && MEM_P (x) && !MEM_READONLY_P (x)) + { + /* If unsafe, change MEMs to CLOBBERs or SCRATCHes (to preserve whether + they have side effects or not). */ + *px = (side_effects_p (x) + ? gen_rtx_CLOBBER (GET_MODE (x), const0_rtx) + : gen_rtx_SCRATCH (GET_MODE (x))); + return false; + } + /* If X is OLD_RTX, return NEW_RTX. But not if replacing only within an + address, and we are *not* inside one. */ if (x == old) { *px = new; return can_appear; } + /* If this is an expression, try recursive substitution. */ switch (GET_RTX_CLASS (code)) { case RTX_UNARY: op0 = XEXP (x, 0); op_mode = GET_MODE (op0); - valid_ops &= propagate_rtx_1 (&op0, old, new, can_appear); + valid_ops &= propagate_rtx_1 (&op0, old, new, flags); if (op0 == XEXP (x, 0)) return true; tem = simplify_gen_unary (code, mode, op0, op_mode); @@ -258,8 +287,8 @@ propagate_rtx_1 (rtx *px, rtx old, rtx new, bool can_appear) case RTX_COMM_ARITH: op0 = XEXP (x, 0); op1 = XEXP (x, 1); - valid_ops &= propagate_rtx_1 (&op0, old, new, can_appear); - valid_ops &= propagate_rtx_1 (&op1, old, new, can_appear); + valid_ops &= propagate_rtx_1 (&op0, old, new, flags); + valid_ops &= propagate_rtx_1 (&op1, old, new, flags); if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1)) return true; tem = simplify_gen_binary (code, mode, op0, op1); @@ -270,8 +299,8 @@ propagate_rtx_1 (rtx *px, rtx old, rtx new, bool can_appear) op0 = XEXP (x, 0); op1 = XEXP (x, 1); op_mode = GET_MODE (op0) != VOIDmode ? GET_MODE (op0) : GET_MODE (op1); - valid_ops &= propagate_rtx_1 (&op0, old, new, can_appear); - valid_ops &= propagate_rtx_1 (&op1, old, new, can_appear); + valid_ops &= propagate_rtx_1 (&op0, old, new, flags); + valid_ops &= propagate_rtx_1 (&op1, old, new, flags); if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1)) return true; tem = simplify_gen_relational (code, mode, op_mode, op0, op1); @@ -283,9 +312,9 @@ propagate_rtx_1 (rtx *px, rtx old, rtx new, bool can_appear) op1 = XEXP (x, 1); op2 = XEXP (x, 2); op_mode = GET_MODE (op0); - valid_ops &= propagate_rtx_1 (&op0, old, new, can_appear); - valid_ops &= propagate_rtx_1 (&op1, old, new, can_appear); - valid_ops &= propagate_rtx_1 (&op2, old, new, can_appear); + valid_ops &= propagate_rtx_1 (&op0, old, new, flags); + valid_ops &= propagate_rtx_1 (&op1, old, new, flags); + valid_ops &= propagate_rtx_1 (&op2, old, new, flags); if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1) && op2 == XEXP (x, 2)) return true; if (op_mode == VOIDmode) @@ -298,7 +327,7 @@ propagate_rtx_1 (rtx *px, rtx old, rtx new, bool can_appear) if (code == SUBREG) { op0 = XEXP (x, 0); - valid_ops &= propagate_rtx_1 (&op0, old, new, can_appear); + valid_ops &= propagate_rtx_1 (&op0, old, new, flags); if (op0 == XEXP (x, 0)) return true; tem = simplify_gen_subreg (mode, op0, GET_MODE (SUBREG_REG (x)), @@ -317,7 +346,8 @@ propagate_rtx_1 (rtx *px, rtx old, rtx new, bool can_appear) return true; op0 = new_op0 = targetm.delegitimize_address (op0); - valid_ops &= propagate_rtx_1 (&new_op0, old, new, true); + valid_ops &= propagate_rtx_1 (&new_op0, old, new, + flags | PR_CAN_APPEAR); /* Dismiss transformation that we do not want to carry on. */ if (!valid_ops @@ -344,8 +374,8 @@ propagate_rtx_1 (rtx *px, rtx old, rtx new, bool can_appear) /* The only simplification we do attempts to remove references to op0 or make it constant -- in both cases, op0's invalidity will not make the result invalid. */ - propagate_rtx_1 (&op0, old, new, true); - valid_ops &= propagate_rtx_1 (&op1, old, new, can_appear); + propagate_rtx_1 (&op0, old, new, flags | PR_CAN_APPEAR); + valid_ops &= propagate_rtx_1 (&op1, old, new, flags); if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1)) return true; @@ -387,6 +417,18 @@ propagate_rtx_1 (rtx *px, rtx old, rtx new, bool can_appear) return valid_ops || can_appear || CONSTANT_P (tem); } + +/* for_each_rtx traversal function that returns 1 if BODY points to + a non-constant mem. */ + +static int +varying_mem_p (rtx *body, void *data ATTRIBUTE_UNUSED) +{ + rtx x = *body; + return MEM_P (x) && !MEM_READONLY_P (x); +} + + /* Replace all occurrences of OLD in X with NEW and try to simplify the resulting expression (in mode MODE). Return a new expression if it is a constant, otherwise X. @@ -400,14 +442,19 @@ propagate_rtx (rtx x, enum machine_mode mode, rtx old, rtx new) { rtx tem; bool collapsed; + int flags; if (REG_P (new) && REGNO (new) < FIRST_PSEUDO_REGISTER) return NULL_RTX; - new = copy_rtx (new); + flags = 0; + if (REG_P (new) || CONSTANT_P (new)) + flags |= PR_CAN_APPEAR; + if (!for_each_rtx (&new, varying_mem_p, NULL)) + flags |= PR_HANDLE_MEM; tem = x; - collapsed = propagate_rtx_1 (&tem, old, new, REG_P (new) || CONSTANT_P (new)); + collapsed = propagate_rtx_1 (&tem, old, copy_rtx (new), flags); if (tem == x || !collapsed) return NULL_RTX; @@ -516,16 +563,6 @@ use_killed_between (struct df_ref *use, rtx def_insn, rtx target_insn) } -/* for_each_rtx traversal function that returns 1 if BODY points to - a non-constant mem. */ - -static int -varying_mem_p (rtx *body, void *data ATTRIBUTE_UNUSED) -{ - rtx x = *body; - return MEM_P (x) && !MEM_READONLY_P (x); -} - /* Check if all uses in DEF_INSN can be used in TARGET_INSN. This would require full computation of available expressions; we check only restricted conditions, see use_killed_between. */ @@ -577,9 +614,7 @@ all_uses_available_at (rtx def_insn, rtx target_insn) } } - /* We don't do any analysis of memories or aliasing. Reject any - instruction that involves references to non-constant memory. */ - return !for_each_rtx (&SET_SRC (def_set), varying_mem_p, NULL); + return true; } |