#include "timevar.h"
#include "tree-pass.h"
#include "df.h"
+#include "cgraph.h"
/* Number of attempts to combine instructions in this function. */
setup_incoming_promotions (rtx first)
{
tree arg;
+ bool strictly_local = false;
if (!targetm.calls.promote_function_args (TREE_TYPE (cfun->decl)))
return;
arg = TREE_CHAIN (arg))
{
rtx reg = DECL_INCOMING_RTL (arg);
+ int uns1, uns3;
+ enum machine_mode mode1, mode2, mode3, mode4;
+ /* Only continue if the incoming argument is in a register. */
if (!REG_P (reg))
continue;
- if (TYPE_MODE (DECL_ARG_TYPE (arg)) == TYPE_MODE (TREE_TYPE (arg)))
- {
- enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg));
- int uns = TYPE_UNSIGNED (TREE_TYPE (arg));
-
- mode = promote_mode (TREE_TYPE (arg), mode, &uns, 1);
- if (mode == GET_MODE (reg) && mode != DECL_MODE (arg))
- {
- rtx x;
- x = gen_rtx_CLOBBER (DECL_MODE (arg), const0_rtx);
- x = gen_rtx_fmt_e ((uns ? ZERO_EXTEND : SIGN_EXTEND), mode, x);
- record_value_for_reg (reg, first, x);
- }
+ /* Determine, if possible, whether all call sites of the current
+ function lie within the current compilation unit. (This does
+ take into account the exporting of a function via taking its
+ address, and so forth.) */
+ if (flag_unit_at_a_time)
+ strictly_local = cgraph_local_info (current_function_decl)->local;
+
+ /* The mode and signedness of the argument before any promotions happen
+ (equal to the mode of the pseudo holding it at that stage). */
+ mode1 = TYPE_MODE (TREE_TYPE (arg));
+ uns1 = TYPE_UNSIGNED (TREE_TYPE (arg));
+
+ /* The mode and signedness of the argument after any source language and
+ TARGET_PROMOTE_PROTOTYPES-driven promotions. */
+ mode2 = TYPE_MODE (DECL_ARG_TYPE (arg));
+ uns3 = TYPE_UNSIGNED (DECL_ARG_TYPE (arg));
+
+ /* The mode and signedness of the argument as it is actually passed,
+ after any TARGET_PROMOTE_FUNCTION_ARGS-driven ABI promotions. */
+ mode3 = promote_mode (DECL_ARG_TYPE (arg), mode2, &uns3, 1);
+
+ /* The mode of the register in which the argument is being passed. */
+ mode4 = GET_MODE (reg);
+
+ /* Eliminate sign extensions in the callee when possible. Only
+ do this when:
+ (a) a mode promotion has occurred;
+ (b) the mode of the register is the same as the mode of
+ the argument as it is passed; and
+ (c) the signedness does not change across any of the promotions; and
+ (d) when no language-level promotions (which we cannot guarantee
+ will have been done by an external caller) are necessary,
+ unless we know that this function is only ever called from
+ the current compilation unit -- all of whose call sites will
+ do the mode1 --> mode2 promotion. */
+ if (mode1 != mode3
+ && mode3 == mode4
+ && uns1 == uns3
+ && (mode1 == mode2 || strictly_local))
+ {
+ /* Record that the value was promoted from mode1 to mode3,
+ so that any sign extension at the head of the current
+ function may be eliminated. */
+ rtx x;
+ x = gen_rtx_CLOBBER (mode1, const0_rtx);
+ x = gen_rtx_fmt_e ((uns3 ? ZERO_EXTEND : SIGN_EXTEND), mode3, x);
+ record_value_for_reg (reg, first, x);
}
}
}
-\f
+
/* Called via note_stores. If X is a pseudo that is narrower than
HOST_BITS_PER_WIDE_INT and is being set, record what bits are known zero.
}
}
+ /* Check if we are loading something from the constant pool via float
+ extension; in this case we would undo compress_float_constant
+ optimization and degenerate constant load to an immediate value. */
+ if (GET_CODE (x) == FLOAT_EXTEND
+ && MEM_P (XEXP (x, 0))
+ && MEM_READONLY_P (XEXP (x, 0)))
+ {
+ rtx tmp = avoid_constant_pool_reference (x);
+ if (x != tmp)
+ return x;
+ }
+
/* Try to simplify X. If the simplification changed the code, it is likely
that further simplification will help, so loop, but limit the number
of repetitions that will be performed. */
|| code == AND || code == IOR || code == XOR
|| code == SMAX || code == SMIN || code == UMAX || code == UMIN)
&& ((INTEGRAL_MODE_P (mode) && code != DIV)
- || (flag_unsafe_math_optimizations && FLOAT_MODE_P (mode))))
+ || (flag_associative_math && FLOAT_MODE_P (mode))))
{
if (GET_CODE (XEXP (x, 0)) == code)
{
}
/* Try simplify a*(b/c) as (a*b)/c. */
- if (FLOAT_MODE_P (mode) && flag_unsafe_math_optimizations
+ if (FLOAT_MODE_P (mode) && flag_associative_math
&& GET_CODE (XEXP (x, 0)) == DIV)
{
rtx tem = simplify_binary_operation (MULT, mode,
&& ((unsigned HOST_WIDE_INT) const_op
< (((unsigned HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (mode) - 1))))
- && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+ && optab_handler (cmp_optab, mode)->insn_code != CODE_FOR_nothing)
{
op0 = XEXP (op0, 0);
continue;
&& (unsigned_comparison_p || equality_comparison_p)
&& (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
&& ((unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode))
- && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+ && optab_handler (cmp_optab, mode)->insn_code != CODE_FOR_nothing)
{
op0 = XEXP (op0, 0);
continue;
}
break;
- case REG_LABEL:
+ case REG_LABEL_TARGET:
+ case REG_LABEL_OPERAND:
/* This can show up in several ways -- either directly in the
pattern, or hidden off in the constant pool with (or without?)
a REG_EQUAL note. */
place = i2;
}
- /* Don't attach REG_LABEL note to a JUMP_INSN. Add
- a JUMP_LABEL instead or decrement LABEL_NUSES. */
- if (place && JUMP_P (place))
+ /* For REG_LABEL_TARGET on a JUMP_P, we prefer to put the note
+ as a JUMP_LABEL or decrement LABEL_NUSES if it's already
+ there. */
+ if (place && JUMP_P (place)
+ && REG_NOTE_KIND (note) == REG_LABEL_TARGET
+ && (JUMP_LABEL (place) == NULL
+ || JUMP_LABEL (place) == XEXP (note, 0)))
{
rtx label = JUMP_LABEL (place);
if (!label)
JUMP_LABEL (place) = XEXP (note, 0);
- else
- {
- gcc_assert (label == XEXP (note, 0));
- if (LABEL_P (label))
- LABEL_NUSES (label)--;
- }
- place = 0;
+ else if (LABEL_P (label))
+ LABEL_NUSES (label)--;
}
- if (place2 && JUMP_P (place2))
+
+ if (place2 && JUMP_P (place2)
+ && REG_NOTE_KIND (note) == REG_LABEL_TARGET
+ && (JUMP_LABEL (place2) == NULL
+ || JUMP_LABEL (place2) == XEXP (note, 0)))
{
rtx label = JUMP_LABEL (place2);
if (!label)
JUMP_LABEL (place2) = XEXP (note, 0);
- else
- {
- gcc_assert (label == XEXP (note, 0));
- if (LABEL_P (label))
- LABEL_NUSES (label)--;
- }
+ else if (LABEL_P (label))
+ LABEL_NUSES (label)--;
place2 = 0;
}
break;
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func |
- TODO_df_finish |
+ TODO_df_finish | TODO_verify_rtl_sharing |
TODO_ggc_collect, /* todo_flags_finish */
'c' /* letter */
};