aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2009-05-16 09:12:02 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2009-05-16 09:12:02 +0200
commit40a8f07a47f1192d06e895ce1a4d0fc91a723743 (patch)
tree6e8f264af352b2d4f86c2430ec273c272f874f45 /gcc
parenta99c6711f83e23596c5fdbf575484e3fa34d6e45 (diff)
downloadgcc-40a8f07a47f1192d06e895ce1a4d0fc91a723743.zip
gcc-40a8f07a47f1192d06e895ce1a4d0fc91a723743.tar.gz
gcc-40a8f07a47f1192d06e895ce1a4d0fc91a723743.tar.bz2
re PR target/39942 (Nonoptimal code - leaveq; xchg %ax,%ax; retq)
PR target/39942 * final.c (label_to_max_skip): New function. (label_to_alignment): Only use LABEL_TO_ALIGNMENT if CODE_LABEL_NUMBER <= max_labelno. * output.h (label_to_max_skip): New prototype. * config/i386/i386.c (ix86_avoid_jump_misspredicts): Renamed to... (ix86_avoid_jump_mispredicts): ... this. Don't define if ASM_OUTPUT_MAX_SKIP_ALIGN isn't defined. Update comment. Handle CODE_LABELs with >= 16 byte alignment or with max_skip == (1 << align) - 1. (ix86_reorg): Don't call ix86_avoid_jump_mispredicts if ASM_OUTPUT_MAX_SKIP_ALIGN isn't defined. From-SVN: r147607
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/config/i386/i386.c57
-rw-r--r--gcc/final.c12
-rw-r--r--gcc/output.h6
4 files changed, 78 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 950c8f5..61c62b6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,6 +1,19 @@
2009-05-16 Jakub Jelinek <jakub@redhat.com>
PR target/39942
+ * final.c (label_to_max_skip): New function.
+ (label_to_alignment): Only use LABEL_TO_ALIGNMENT if
+ CODE_LABEL_NUMBER <= max_labelno.
+ * output.h (label_to_max_skip): New prototype.
+ * config/i386/i386.c (ix86_avoid_jump_misspredicts): Renamed to...
+ (ix86_avoid_jump_mispredicts): ... this. Don't define if
+ ASM_OUTPUT_MAX_SKIP_ALIGN isn't defined. Update comment.
+ Handle CODE_LABELs with >= 16 byte alignment or with
+ max_skip == (1 << align) - 1.
+ (ix86_reorg): Don't call ix86_avoid_jump_mispredicts if
+ ASM_OUTPUT_MAX_SKIP_ALIGN isn't defined.
+
+ PR target/39942
* config/i386/x86-64.h (ASM_OUTPUT_MAX_SKIP_ALIGN): Don't emit second
.p2align 3 if MAX_SKIP is smaller than 7.
* config/i386/linux.h (ASM_OUTPUT_MAX_SKIP_ALIGN): Likewise.
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index cc0bb02..acd3069 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -27191,6 +27191,7 @@ x86_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
}
}
+#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
/* We don't have exact information about the insn sizes, but we may assume
quite safely that we are informed about all 1 byte insns and memory
address sizes. This is enough to eliminate unnecessary padding in
@@ -27241,7 +27242,7 @@ min_insn_size (rtx insn)
window. */
static void
-ix86_avoid_jump_misspredicts (void)
+ix86_avoid_jump_mispredicts (void)
{
rtx insn, start = get_insns ();
int nbytes = 0, njumps = 0;
@@ -27255,15 +27256,52 @@ ix86_avoid_jump_misspredicts (void)
The smallest offset in the page INSN can start is the case where START
ends on the offset 0. Offset of INSN is then NBYTES - sizeof (INSN).
- We add p2align to 16byte window with maxskip 17 - NBYTES + sizeof (INSN).
+ We add p2align to 16byte window with maxskip 15 - NBYTES + sizeof (INSN).
*/
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ for (insn = start; insn; insn = NEXT_INSN (insn))
{
+ int min_size;
- nbytes += min_insn_size (insn);
+ if (GET_CODE (insn) == CODE_LABEL)
+ {
+ int align = label_to_alignment (insn);
+ int max_skip = label_to_max_skip (insn);
+
+ if (max_skip > 15)
+ max_skip = 15;
+ /* If align > 3, only up to 16 - max_skip - 1 bytes can be
+ already in the current 16 byte page, because otherwise
+ ASM_OUTPUT_MAX_SKIP_ALIGN could skip max_skip or fewer
+ bytes to reach 16 byte boundary. */
+ if (align <= 0
+ || (align <= 3 && max_skip != (1 << align) - 1))
+ max_skip = 0;
+ if (dump_file)
+ fprintf (dump_file, "Label %i with max_skip %i\n",
+ INSN_UID (insn), max_skip);
+ if (max_skip)
+ {
+ while (nbytes + max_skip >= 16)
+ {
+ start = NEXT_INSN (start);
+ if ((JUMP_P (start)
+ && GET_CODE (PATTERN (start)) != ADDR_VEC
+ && GET_CODE (PATTERN (start)) != ADDR_DIFF_VEC)
+ || CALL_P (start))
+ njumps--, isjump = 1;
+ else
+ isjump = 0;
+ nbytes -= min_insn_size (start);
+ }
+ }
+ continue;
+ }
+
+ min_size = min_insn_size (insn);
+ nbytes += min_size;
if (dump_file)
- fprintf(dump_file, "Insn %i estimated to %i bytes\n",
- INSN_UID (insn), min_insn_size (insn));
+ fprintf (dump_file, "Insn %i estimated to %i bytes\n",
+ INSN_UID (insn), min_size);
if ((JUMP_P (insn)
&& GET_CODE (PATTERN (insn)) != ADDR_VEC
&& GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
@@ -27287,7 +27325,7 @@ ix86_avoid_jump_misspredicts (void)
gcc_assert (njumps >= 0);
if (dump_file)
fprintf (dump_file, "Interval %i to %i has %i bytes\n",
- INSN_UID (start), INSN_UID (insn), nbytes);
+ INSN_UID (start), INSN_UID (insn), nbytes);
if (njumps == 3 && isjump && nbytes < 16)
{
@@ -27300,6 +27338,7 @@ ix86_avoid_jump_misspredicts (void)
}
}
}
+#endif
/* AMD Athlon works faster
when RET is not destination of conditional jump or directly preceded
@@ -27363,8 +27402,10 @@ ix86_reorg (void)
{
if (TARGET_PAD_RETURNS)
ix86_pad_returns ();
+#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
if (TARGET_FOUR_JUMP_LIMIT)
- ix86_avoid_jump_misspredicts ();
+ ix86_avoid_jump_mispredicts ();
+#endif
}
}
diff --git a/gcc/final.c b/gcc/final.c
index 30ccc85..3c2e364 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -553,7 +553,17 @@ static int min_labelno, max_labelno;
int
label_to_alignment (rtx label)
{
- return LABEL_TO_ALIGNMENT (label);
+ if (CODE_LABEL_NUMBER (label) <= max_labelno)
+ return LABEL_TO_ALIGNMENT (label);
+ return 0;
+}
+
+int
+label_to_max_skip (rtx label)
+{
+ if (CODE_LABEL_NUMBER (label) <= max_labelno)
+ return LABEL_TO_MAX_SKIP (label);
+ return 0;
}
#ifdef HAVE_ATTR_length
diff --git a/gcc/output.h b/gcc/output.h
index e7871f9..543164a 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -1,7 +1,7 @@
/* Declarations for insn-output.c. These functions are defined in recog.c,
final.c, and varasm.c.
Copyright (C) 1987, 1991, 1994, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GCC.
@@ -94,6 +94,10 @@ extern int insn_current_reference_address (rtx);
Defined in final.c. */
extern int label_to_alignment (rtx);
+/* Find the alignment maximum skip associated with a CODE_LABEL.
+ Defined in final.c. */
+extern int label_to_max_skip (rtx);
+
/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */
extern void output_asm_label (rtx);