summaryrefslogtreecommitdiff
path: root/gcc/config/i386/i386.c
diff options
context:
space:
mode:
authoruros <uros@138bc75d-0d04-0410-961f-82ee72b054a4>2016-06-06 22:35:18 +0000
committeruros <uros@138bc75d-0d04-0410-961f-82ee72b054a4>2016-06-06 22:35:18 +0000
commite83ab54fa22a9f9d99daa4adc7e926d835b8f481 (patch)
tree9f439388509de6078944a34a327284a7a0125c55 /gcc/config/i386/i386.c
parent61f1f80c56eacfdd8ba00ffc34718d9831bf0b0f (diff)
downloadgcc-e83ab54fa22a9f9d99daa4adc7e926d835b8f481.tar.gz
* config/i386/i386.h (enum ix86_enitity): Add X86_DIRFLAG.
(enum x86_dirflag_state): New enum. (NUM_MODES_FOR_MODE_SWITCHING): Add X86_DIRFLAG_ANY. (machine_function): Remove needs_cld. (ix86_current_function_needs_cld): Remove. * config/i386/i386.c (ix86_set_func_type): Set ix86_optimize_mode_switching[X86_DIRFLAG] to 1. (ix86_expand_prologue): Do not emit CLD here. (ix86_dirflag_mode_needed): New function. (ix86_dirflag_mode_entry): Ditto. (ix86_mode_needed): Handle X86_DIRFLAG entity. (ix86_mode_after): Ditto. (ix86_mode_entry): Ditto. (ix86_mode_exit): Ditto. (ix86_emit_mode_set): Ditto. * config/i386/i386.md (strmov_singleop): Set ix86_optimize_mode_switching[X86_DIRFLAG] to 1 for TARGET_CLD. Do not set ix86_current_function_needs_cld. (rep_mov): Ditto. (strset_singleop): Ditto. (rep_stos): Ditto. (cmpstrnqi_nz_1): Ditto. (cmpstrnqi_1): Ditto. (strlenqi_1): Ditto. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@237156 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/i386/i386.c')
-rw-r--r--gcc/config/i386/i386.c65
1 files changed, 55 insertions, 10 deletions
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index c191eebc09d..b807a9a0004 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -6823,6 +6823,8 @@ ix86_set_func_type (tree fndecl)
cfun->machine->func_type
= nargs == 2 ? TYPE_EXCEPTION : TYPE_INTERRUPT;
+ ix86_optimize_mode_switching[X86_DIRFLAG] = 1;
+
/* Only dwarf2out.c can handle -WORD(AP) as a pointer argument. */
if (write_symbols != NO_DEBUG && write_symbols != DWARF2_DEBUG)
sorry ("Only DWARF debug format is supported for interrupt "
@@ -13817,16 +13819,6 @@ ix86_expand_prologue (void)
if (frame_pointer_needed && frame.red_zone_size)
emit_insn (gen_memory_blockage ());
- /* Emit cld instruction if stringops are used in the function. Since
- we can't assume the direction flag in interrupt handler, we must
- emit cld instruction if stringops are used in interrupt handler or
- interrupt handler isn't a leaf function. */
- if ((TARGET_CLD && ix86_current_function_needs_cld)
- || (!TARGET_CLD
- && cfun->machine->func_type != TYPE_NORMAL
- && (ix86_current_function_needs_cld || !crtl->is_leaf)))
- emit_insn (gen_cld ());
-
/* SEH requires that the prologue end within 256 bytes of the start of
the function. Prevent instruction schedules that would extend that.
Further, prevent alloca modifications to the stack pointer from being
@@ -18600,6 +18592,35 @@ output_387_binary_op (rtx insn, rtx *operands)
return buf;
}
+/* Return needed mode for entity in optimize_mode_switching pass. */
+
+static int
+ix86_dirflag_mode_needed (rtx_insn *insn)
+{
+ if (CALL_P (insn))
+ {
+ if (cfun->machine->func_type == TYPE_NORMAL)
+ return X86_DIRFLAG_ANY;
+ else
+ /* No need to emit CLD in interrupt handler for TARGET_CLD. */
+ return TARGET_CLD ? X86_DIRFLAG_ANY : X86_DIRFLAG_RESET;
+ }
+
+ if (recog_memoized (insn) < 0)
+ return X86_DIRFLAG_ANY;
+
+ if (get_attr_type (insn) == TYPE_STR)
+ {
+ /* Emit cld instruction if stringops are used in the function. */
+ if (cfun->machine->func_type == TYPE_NORMAL)
+ return TARGET_CLD ? X86_DIRFLAG_RESET : X86_DIRFLAG_ANY;
+ else
+ return X86_DIRFLAG_RESET;
+ }
+
+ return X86_DIRFLAG_ANY;
+}
+
/* Check if a 256bit AVX register is referenced inside of EXP. */
static bool
@@ -18712,6 +18733,8 @@ ix86_mode_needed (int entity, rtx_insn *insn)
{
switch (entity)
{
+ case X86_DIRFLAG:
+ return ix86_dirflag_mode_needed (insn);
case AVX_U128:
return ix86_avx_u128_mode_needed (insn);
case I387_TRUNC:
@@ -18771,6 +18794,8 @@ ix86_mode_after (int entity, int mode, rtx_insn *insn)
{
switch (entity)
{
+ case X86_DIRFLAG:
+ return mode;
case AVX_U128:
return ix86_avx_u128_mode_after (mode, insn);
case I387_TRUNC:
@@ -18784,6 +18809,18 @@ ix86_mode_after (int entity, int mode, rtx_insn *insn)
}
static int
+ix86_dirflag_mode_entry (void)
+{
+ /* For TARGET_CLD or in the interrupt handler we can't assume
+ direction flag state at function entry. */
+ if (TARGET_CLD
+ || cfun->machine->func_type != TYPE_NORMAL)
+ return X86_DIRFLAG_ANY;
+
+ return X86_DIRFLAG_RESET;
+}
+
+static int
ix86_avx_u128_mode_entry (void)
{
tree arg;
@@ -18810,6 +18847,8 @@ ix86_mode_entry (int entity)
{
switch (entity)
{
+ case X86_DIRFLAG:
+ return ix86_dirflag_mode_entry ();
case AVX_U128:
return ix86_avx_u128_mode_entry ();
case I387_TRUNC:
@@ -18843,6 +18882,8 @@ ix86_mode_exit (int entity)
{
switch (entity)
{
+ case X86_DIRFLAG:
+ return X86_DIRFLAG_ANY;
case AVX_U128:
return ix86_avx_u128_mode_exit ();
case I387_TRUNC:
@@ -18986,6 +19027,10 @@ ix86_emit_mode_set (int entity, int mode, int prev_mode ATTRIBUTE_UNUSED,
{
switch (entity)
{
+ case X86_DIRFLAG:
+ if (mode == X86_DIRFLAG_RESET)
+ emit_insn (gen_cld ());
+ break;
case AVX_U128:
if (mode == AVX_U128_CLEAN)
ix86_avx_emit_vzeroupper (regs_live);