aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Henderson <rth@cygnus.com>1999-09-01 21:20:21 -0700
committerRichard Henderson <rth@gcc.gnu.org>1999-09-01 21:20:21 -0700
commite075ae69f9d1263e78376038ab138c03e279f391 (patch)
tree2741b1e654e069ae0926889ad907a3122fc70944 /gcc
parenta41cb705f69a848a70b1765cc0e9fdb70a079db9 (diff)
downloadgcc-e075ae69f9d1263e78376038ab138c03e279f391.zip
gcc-e075ae69f9d1263e78376038ab138c03e279f391.tar.gz
gcc-e075ae69f9d1263e78376038ab138c03e279f391.tar.bz2
Merge new ia32 backend from the branch!
From-SVN: r29044
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/config/i386/cygwin.h11
-rw-r--r--gcc/config/i386/gas.h11
-rw-r--r--gcc/config/i386/i386.c6812
-rw-r--r--gcc/config/i386/i386.h1356
-rw-r--r--gcc/config/i386/i386.md12450
-rw-r--r--gcc/config/i386/unix.h151
-rw-r--r--gcc/config/i386/win32.h5
-rw-r--r--gcc/config/i386/winnt.c4
-rw-r--r--gcc/reg-stack.c802
-rw-r--r--gcc/rtl.h1
11 files changed, 10616 insertions, 11002 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0828f99..c6188fb 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,18 @@
+Wed Sep 1 21:13:48 1999 Richard Henderson <rth@cygnus.com>
+
+ Merge new ia32 backend from the branch!
+
+ * i386.h, i386.c, i386.md, reg-stack.c, i386/unix.h: Many changes.
+ See ChangeLog.P2 on new_ia32_branch for details.
+
+ * rtl.h (stack_regs_mentioned_p): Delete prototype.
+ * i386/cygwin.h (SUBTARGET_PROLOGUE): No more do_rtl.
+ * i386/win32.h (SUBTARGET_PROLOGUE): Likewise.
+ * i386/gas.h (ASM_FILE_START): Define.
+ * i386/winnt.c (i386_pe_valid_decl_attribute_p): Update
+ for name change of ix86_valid_decl_attribute_p.
+ (i386_pe_valid_type_attribute_p): Similarly.
+
Wed Sep 1 18:21:23 1999 Richard Henderson <rth@cygnus.com>
* emit-rtl.c (init_emit_once): Don't use GET_MODE_WIDER_MODE
diff --git a/gcc/config/i386/cygwin.h b/gcc/config/i386/cygwin.h
index f19ea50..a6e967f 100644
--- a/gcc/config/i386/cygwin.h
+++ b/gcc/config/i386/cygwin.h
@@ -482,13 +482,10 @@ do { \
&& strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),\
"main") == 0) \
{ \
- rtx xops[1]; \
- xops[0] = gen_rtx_MEM (FUNCTION_MODE, \
- gen_rtx (SYMBOL_REF, Pmode, "_monstartup")); \
- if (do_rtl) \
- emit_call_insn (gen_rtx (CALL, VOIDmode, xops[0], const0_rtx)); \
- else \
- output_asm_insn (AS1 (call,%P1), xops); \
+ emit_call_insn (gen_rtx (CALL, VOIDmode, \
+ gen_rtx_MEM (FUNCTION_MODE, \
+ gen_rtx_SYMBOL_REF (Pmode, "_monstartup")), \
+ const0_rtx)); \
}
/* External function declarations. */
diff --git a/gcc/config/i386/gas.h b/gcc/config/i386/gas.h
index 4ce1891..cef4385 100644
--- a/gcc/config/i386/gas.h
+++ b/gcc/config/i386/gas.h
@@ -160,3 +160,14 @@ Boston, MA 02111-1307, USA. */
fprintf (FILE, ".%s%d:\n", PREFIX, NUM)
#endif /* NO_UNDERSCORES */
+
+/* Output at beginning of assembler file. */
+/* The .file command should always begin the output. */
+#undef ASM_FILE_START
+#define ASM_FILE_START(FILE) \
+ do { \
+ if (target_flags & MASK_INTEL_SYNTAX) \
+ fputs ("\t.intel_syntax\n", FILE); \
+ output_file_directive (FILE, main_input_filename); \
+ fputs ("\t.version\t\"01.01\"\n", FILE); \
+ } while (0)
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 4abb594..faa4eac 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -1,4 +1,4 @@
-/* Subroutines for insn-output.c for Intel X86.
+/* Subroutines used for code generation on IA-32.
Copyright (C) 1988, 92, 94-98, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -37,6 +37,7 @@ Boston, MA 02111-1307, USA. */
#include "recog.h"
#include "expr.h"
#include "toplev.h"
+#include "basic-block.h"
#ifdef EXTRA_CONSTRAINT
/* If EXTRA_CONSTRAINT is defined, then the 'S'
@@ -51,14 +52,6 @@ Boston, MA 02111-1307, USA. */
#define CHECK_STACK_LIMIT -1
#endif
-/* Type of an operand for ix86_{binary,unary}_operator_ok */
-enum reg_mem
-{
- reg_p,
- mem_p,
- imm_p
-};
-
/* Processor costs (relative to an add) */
struct processor_costs i386_cost = { /* 386 specific costs */
1, /* cost of an add instruction */
@@ -67,7 +60,8 @@ struct processor_costs i386_cost = { /* 386 specific costs */
2, /* constant shift costs */
6, /* cost of starting a multiply */
1, /* cost of multiply per each bit set */
- 23 /* cost of a divide/mod */
+ 23, /* cost of a divide/mod */
+ 15 /* "large" insn */
};
struct processor_costs i486_cost = { /* 486 specific costs */
@@ -77,7 +71,8 @@ struct processor_costs i486_cost = { /* 486 specific costs */
2, /* constant shift costs */
12, /* cost of starting a multiply */
1, /* cost of multiply per each bit set */
- 40 /* cost of a divide/mod */
+ 40, /* cost of a divide/mod */
+ 15 /* "large" insn */
};
struct processor_costs pentium_cost = {
@@ -87,32 +82,30 @@ struct processor_costs pentium_cost = {
1, /* constant shift costs */
11, /* cost of starting a multiply */
0, /* cost of multiply per each bit set */
- 25 /* cost of a divide/mod */
+ 25, /* cost of a divide/mod */
+ 8 /* "large" insn */
};
struct processor_costs pentiumpro_cost = {
1, /* cost of an add instruction */
1, /* cost of a lea instruction */
- 3, /* variable shift costs */
+ 1, /* variable shift costs */
1, /* constant shift costs */
- 4, /* cost of starting a multiply */
+ 1, /* cost of starting a multiply */
0, /* cost of multiply per each bit set */
- 17 /* cost of a divide/mod */
+ 17, /* cost of a divide/mod */
+ 8 /* "large" insn */
};
-/* We use decoding time together with execution time.
- To get correct vale add 1 for short decodable, 2 for long decodable
- and 4 for vector decodable instruction to execution time and divide
- by two (because CPU is able to do two insns at a time). */
-
struct processor_costs k6_cost = {
1, /* cost of an add instruction */
- 1, /* cost of a lea instruction */
+ 2, /* cost of a lea instruction */
1, /* variable shift costs */
1, /* constant shift costs */
3, /* cost of starting a multiply */
0, /* cost of multiply per each bit set */
- 20 /* cost of a divide/mod */
+ 18, /* cost of a divide/mod */
+ 8 /* "large" insn */
};
struct processor_costs *ix86_cost = &pentium_cost;
@@ -127,53 +120,53 @@ struct processor_costs *ix86_cost = &pentium_cost;
const int x86_use_leave = m_386 | m_K6;
const int x86_push_memory = m_386 | m_K6;
const int x86_zero_extend_with_and = m_486 | m_PENT;
-const int x86_movx = m_386 | m_PPRO | m_K6;
-const int x86_double_with_add = ~(m_386 | m_PENT | m_PPRO);
+const int x86_movx = 0 /* m_386 | m_PPRO | m_K6 */;
+const int x86_double_with_add = ~m_386;
const int x86_use_bit_test = m_386;
-const int x86_unroll_strlen = m_486 | m_PENT | m_PPRO;
+const int x86_unroll_strlen = m_486 | m_PENT;
const int x86_use_q_reg = m_PENT | m_PPRO | m_K6;
const int x86_use_any_reg = m_486;
const int x86_cmove = m_PPRO;
-const int x86_deep_branch = m_PPRO| m_K6;
+const int x86_deep_branch = m_PPRO | m_K6;
+const int x86_use_sahf = m_PPRO | m_K6;
+const int x86_partial_reg_stall = m_PPRO;
+const int x86_use_loop = m_K6;
+const int x86_use_fiop = ~m_PPRO;
+const int x86_use_mov0 = m_K6;
+const int x86_use_cltd = ~(m_PENT | m_K6);
+const int x86_read_modify_write = ~m_PENT;
+const int x86_read_modify = ~(m_PENT | m_PPRO);
+const int x86_split_long_moves = m_PPRO;
#define AT_BP(mode) (gen_rtx_MEM ((mode), frame_pointer_rtx))
-extern FILE *asm_out_file;
-extern char *strcat ();
-
-static void ix86_epilogue PROTO((int));
-static void ix86_prologue PROTO((int));
-
-char *singlemove_string ();
-char *output_move_const_single ();
-char *output_fp_cc0_set ();
-
-char *hi_reg_name[] = HI_REGISTER_NAMES;
-char *qi_reg_name[] = QI_REGISTER_NAMES;
-char *qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES;
+const char * const hi_reg_name[] = HI_REGISTER_NAMES;
+const char * const qi_reg_name[] = QI_REGISTER_NAMES;
+const char * const qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES;
/* Array of the smallest class containing reg number REGNO, indexed by
REGNO. Used by REGNO_REG_CLASS in i386.h. */
-enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
+enum reg_class const regclass_map[FIRST_PSEUDO_REGISTER] =
{
/* ax, dx, cx, bx */
AREG, DREG, CREG, BREG,
/* si, di, bp, sp */
- SIREG, DIREG, INDEX_REGS, GENERAL_REGS,
+ SIREG, DIREG, NON_Q_REGS, NON_Q_REGS,
/* FP registers */
FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS,
FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
/* arg pointer */
- INDEX_REGS
+ INDEX_REGS,
+ /* flags, fpsr */
+ NO_REGS, NO_REGS
};
/* Test and compare insns in i386.md store the information needed to
generate branch and scc insns here. */
-struct rtx_def *i386_compare_op0 = NULL_RTX;
-struct rtx_def *i386_compare_op1 = NULL_RTX;
-struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
+struct rtx_def *ix86_compare_op0 = NULL_RTX;
+struct rtx_def *ix86_compare_op1 = NULL_RTX;
/* which cpu are we scheduling for */
enum processor_type ix86_cpu;
@@ -186,43 +179,71 @@ const char *ix86_cpu_string; /* for -mcpu=<xxx> */
const char *ix86_arch_string; /* for -march=<xxx> */
/* Register allocation order */
-const char *i386_reg_alloc_order;
+const char *ix86_reg_alloc_order;
static char regs_allocated[FIRST_PSEUDO_REGISTER];
/* # of registers to use to pass arguments. */
-const char *i386_regparm_string;
+const char *ix86_regparm_string;
-/* i386_regparm_string as a number */
-int i386_regparm;
+/* ix86_regparm_string as a number */
+int ix86_regparm;
/* Alignment to use for loops and jumps: */
/* Power of two alignment for loops. */
-const char *i386_align_loops_string;
+const char *ix86_align_loops_string;
/* Power of two alignment for non-loop jumps. */
-const char *i386_align_jumps_string;
+const char *ix86_align_jumps_string;
/* Power of two alignment for stack boundary in bytes. */
-const char *i386_preferred_stack_boundary_string;
+const char *ix86_preferred_stack_boundary_string;
/* Preferred alignment for stack boundary in bits. */
-int i386_preferred_stack_boundary;
+int ix86_preferred_stack_boundary;
/* Values 1-5: see jump.c */
-int i386_branch_cost;
-const char *i386_branch_cost_string;
+int ix86_branch_cost;
+const char *ix86_branch_cost_string;
/* Power of two alignment for functions. */
-int i386_align_funcs;
-const char *i386_align_funcs_string;
+int ix86_align_funcs;
+const char *ix86_align_funcs_string;
/* Power of two alignment for loops. */
-int i386_align_loops;
+int ix86_align_loops;
/* Power of two alignment for non-loop jumps. */
-int i386_align_jumps;
+int ix86_align_jumps;
+
+static void output_pic_addr_const PROTO ((FILE *, rtx, int));
+static void put_condition_code PROTO ((enum rtx_code, enum machine_mode,
+ int, int, FILE *));
+static enum rtx_code unsigned_comparison PROTO ((enum rtx_code code));
+static rtx ix86_expand_int_compare PROTO ((enum rtx_code, rtx, rtx));
+static rtx ix86_expand_fp_compare PROTO ((enum rtx_code, rtx, rtx, int));
+static rtx ix86_expand_compare PROTO ((enum rtx_code, int));
+static rtx gen_push PROTO ((rtx));
+static int memory_address_length PROTO ((rtx addr));
+static int ix86_flags_dependant PROTO ((rtx, rtx, enum attr_type));
+static int ix86_agi_dependant PROTO ((rtx, rtx, enum attr_type));
+static int ix86_safe_length PROTO ((rtx));
+static enum attr_memory ix86_safe_memory PROTO ((rtx));
+static enum attr_pent_pair ix86_safe_pent_pair PROTO ((rtx));
+static enum attr_ppro_uops ix86_safe_ppro_uops PROTO ((rtx));
+static void ix86_dump_ppro_packet PROTO ((FILE *));
+static void ix86_reorder_insn PROTO ((rtx *, rtx *));
+static rtx * ix86_pent_find_pair PROTO ((rtx *, rtx *, enum attr_pent_pair,
+ rtx));
+
+struct ix86_address
+{
+ rtx base, index, disp;
+ HOST_WIDE_INT scale;
+};
+static int ix86_decompose_address PARAMS ((rtx, struct ix86_address *));
+
/* Sometimes certain combinations of command options do not make
sense on a particular target machine. You can define a macro
`OVERRIDE_OPTIONS' to take account of this. This macro, if
@@ -235,37 +256,93 @@ int i386_align_jumps;
void
override_options ()
{
- int ch, i, j;
- int def_align;
+ /* Comes from final.c -- no real reason to change it. */
+#define MAX_CODE_ALIGN 16
static struct ptt
{
- char *name; /* Canonical processor name. */
- enum processor_type processor; /* Processor type enum value. */
- struct processor_costs *cost; /* Processor costs */
- int target_enable; /* Target flags to enable. */
- int target_disable; /* Target flags to disable. */
- } processor_target_table[] = {
- {PROCESSOR_I386_STRING, PROCESSOR_I386, &i386_cost, 0, 0},
- {PROCESSOR_I486_STRING, PROCESSOR_I486, &i486_cost, 0, 0},
- {PROCESSOR_I586_STRING, PROCESSOR_PENTIUM, &pentium_cost, 0, 0},
- {PROCESSOR_PENTIUM_STRING, PROCESSOR_PENTIUM, &pentium_cost, 0, 0},
- {PROCESSOR_I686_STRING, PROCESSOR_PENTIUMPRO, &pentiumpro_cost, 0, 0},
- {PROCESSOR_PENTIUMPRO_STRING, PROCESSOR_PENTIUMPRO,
- &pentiumpro_cost, 0, 0},
- {PROCESSOR_K6_STRING, PROCESSOR_K6, &k6_cost, 0, 0}
+ struct processor_costs *cost; /* Processor costs */
+ int target_enable; /* Target flags to enable. */
+ int target_disable; /* Target flags to disable. */
+ int align_loop; /* Default alignments. */
+ int align_jump;
+ int align_func;
+ int branch_cost;
+ }
+ const processor_target_table[PROCESSOR_max] =
+ {
+ {&i386_cost, 0, 0, 2, 2, 2, 1},
+ {&i486_cost, 0, 0, 4, 4, 4, 1},
+ {&pentium_cost, 0, 0, -4, -4, -4, 1},
+ {&pentiumpro_cost, 0, 0, 4, -4, 4, 1},
+ {&k6_cost, 0, 0, -5, -5, 4, 1}
+ };
+
+ static struct pta
+ {
+ char *name; /* processor name or nickname. */
+ enum processor_type processor;
+ }
+ const processor_alias_table[] =
+ {
+ {"i386", PROCESSOR_I386},
+ {"i486", PROCESSOR_I486},
+ {"i586", PROCESSOR_PENTIUM},
+ {"pentium", PROCESSOR_PENTIUM},
+ {"i686", PROCESSOR_PENTIUMPRO},
+ {"pentiumpro", PROCESSOR_PENTIUMPRO},
+ {"ppro", PROCESSOR_PENTIUMPRO},
+ {"pentium2", PROCESSOR_PENTIUMPRO},
+ {"p2", PROCESSOR_PENTIUMPRO},
+ {"k6", PROCESSOR_K6},
};
- int ptt_size = sizeof (processor_target_table) / sizeof (struct ptt);
+ int const pta_size = sizeof(processor_alias_table)/sizeof(struct pta);
#ifdef SUBTARGET_OVERRIDE_OPTIONS
SUBTARGET_OVERRIDE_OPTIONS;
#endif
+ ix86_arch = PROCESSOR_PENTIUM;
+ ix86_cpu = (enum processor_type) TARGET_CPU_DEFAULT;
+
+ if (ix86_arch_string != 0)
+ {
+ int i;
+ for (i = 0; i < pta_size; i++)
+ if (! strcmp (ix86_arch_string, processor_alias_table[i].name))
+ {
+ ix86_arch = processor_alias_table[i].processor;
+ /* Default cpu tuning to the architecture. */
+ ix86_cpu = ix86_arch;
+ break;
+ }
+ if (i == pta_size)
+ error ("bad value (%s) for -march= switch", ix86_arch_string);
+ }
+
+ if (ix86_cpu_string != 0)
+ {
+ int i;
+ for (i = 0; i < pta_size; i++)
+ if (! strcmp (ix86_cpu_string, processor_alias_table[i].name))
+ {
+ ix86_cpu = processor_alias_table[i].processor;
+ break;
+ }
+ if (i == pta_size)
+ error ("bad value (%s) for -mcpu= switch", ix86_cpu_string);
+ }
+
+ ix86_cost = processor_target_table[ix86_cpu].cost;
+ target_flags |= processor_target_table[ix86_cpu].target_enable;
+ target_flags &= ~processor_target_table[ix86_cpu].target_disable;
+
/* Validate registers in register allocation order. */
- if (i386_reg_alloc_order)
+ if (ix86_reg_alloc_order)
{
- for (i = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
+ int i, ch;
+ for (i = 0; (ch = ix86_reg_alloc_order[i]) != '\0'; i++)
{
int regno = 0;
@@ -289,129 +366,78 @@ override_options ()
}
}
- if (ix86_arch_string == 0)
- {
- ix86_arch_string = PROCESSOR_PENTIUM_STRING;
- if (ix86_cpu_string == 0)
- ix86_cpu_string = PROCESSOR_DEFAULT_STRING;
- }
-
- for (i = 0; i < ptt_size; i++)
- if (! strcmp (ix86_arch_string, processor_target_table[i].name))
- {
- ix86_arch = processor_target_table[i].processor;
- if (ix86_cpu_string == 0)
- ix86_cpu_string = processor_target_table[i].name;
- break;
- }
-
- if (i == ptt_size)
- {
- error ("bad value (%s) for -march= switch", ix86_arch_string);
- ix86_arch_string = PROCESSOR_PENTIUM_STRING;
- ix86_arch = PROCESSOR_DEFAULT;
- }
-
- if (ix86_cpu_string == 0)
- ix86_cpu_string = PROCESSOR_DEFAULT_STRING;
-
- for (j = 0; j < ptt_size; j++)
- if (! strcmp (ix86_cpu_string, processor_target_table[j].name))
- {
- ix86_cpu = processor_target_table[j].processor;
- ix86_cost = processor_target_table[j].cost;
- if (i > j && (int) ix86_arch >= (int) PROCESSOR_K6)
- error ("-mcpu=%s does not support -march=%s",
- ix86_cpu_string, ix86_arch_string);
-
- target_flags |= processor_target_table[j].target_enable;
- target_flags &= ~processor_target_table[j].target_disable;
- break;
- }
-
- if (j == ptt_size)
- {
- error ("bad value (%s) for -mcpu= switch", ix86_cpu_string);
- ix86_cpu_string = PROCESSOR_DEFAULT_STRING;
- ix86_cpu = PROCESSOR_DEFAULT;
- }
-
/* Validate -mregparm= value. */
- if (i386_regparm_string)
+ if (ix86_regparm_string)
{
- i386_regparm = atoi (i386_regparm_string);
- if (i386_regparm < 0 || i386_regparm > REGPARM_MAX)
+ ix86_regparm = atoi (ix86_regparm_string);
+ if (ix86_regparm < 0 || ix86_regparm > REGPARM_MAX)
fatal ("-mregparm=%d is not between 0 and %d",
- i386_regparm, REGPARM_MAX);
+ ix86_regparm, REGPARM_MAX);
}
- /* The 486 suffers more from non-aligned cache line fills, and the
- larger code size results in a larger cache foot-print and more misses.
- The 486 has a 16 byte cache line, pentium and pentiumpro have a 32 byte
- cache line. */
- def_align = (TARGET_486) ? 4 : 2;
-
/* Validate -malign-loops= value, or provide default. */
-#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
- i386_align_loops = 4;
-#else
- i386_align_loops = 2;
-#endif
- if (i386_align_loops_string)
+ ix86_align_loops = processor_target_table[ix86_cpu].align_loop;
+ if (ix86_align_loops_string)
{
- i386_align_loops = atoi (i386_align_loops_string);
- if (i386_align_loops < 0 || i386_align_loops > MAX_CODE_ALIGN)
+ ix86_align_loops = atoi (ix86_align_loops_string);
+ if (ix86_align_loops < 0 || ix86_align_loops > MAX_CODE_ALIGN)
fatal ("-malign-loops=%d is not between 0 and %d",
- i386_align_loops, MAX_CODE_ALIGN);
+ ix86_align_loops, MAX_CODE_ALIGN);
}
/* Validate -malign-jumps= value, or provide default. */
-#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
- i386_align_jumps = 4;
-#else
- i386_align_jumps = def_align;
-#endif
- if (i386_align_jumps_string)
+ ix86_align_jumps = processor_target_table[ix86_cpu].align_jump;
+ if (ix86_align_jumps_string)
{
- i386_align_jumps = atoi (i386_align_jumps_string);
- if (i386_align_jumps < 0 || i386_align_jumps > MAX_CODE_ALIGN)
+ ix86_align_jumps = atoi (ix86_align_jumps_string);
+ if (ix86_align_jumps < 0 || ix86_align_jumps > MAX_CODE_ALIGN)
fatal ("-malign-jumps=%d is not between 0 and %d",
- i386_align_jumps, MAX_CODE_ALIGN);
+ ix86_align_jumps, MAX_CODE_ALIGN);
}
/* Validate -malign-functions= value, or provide default. */
- i386_align_funcs = def_align;
- if (i386_align_funcs_string)
+ ix86_align_funcs = processor_target_table[ix86_cpu].align_func;
+ if (ix86_align_funcs_string)
{
- i386_align_funcs = atoi (i386_align_funcs_string);
- if (i386_align_funcs < 0 || i386_align_funcs > MAX_CODE_ALIGN)
+ ix86_align_funcs = atoi (ix86_align_funcs_string);
+ if (ix86_align_funcs < 0 || ix86_align_funcs > MAX_CODE_ALIGN)
fatal ("-malign-functions=%d is not between 0 and %d",
- i386_align_funcs, MAX_CODE_ALIGN);
+ ix86_align_funcs, MAX_CODE_ALIGN);
}
/* Validate -mpreferred_stack_boundary= value, or provide default.
The default of 128 bits is for Pentium III's SSE __m128. */
- i386_preferred_stack_boundary = 128;
- if (i386_preferred_stack_boundary_string)
+ ix86_preferred_stack_boundary = 128;
+ if (ix86_preferred_stack_boundary_string)
{
- i = atoi (i386_preferred_stack_boundary_string);
+ int i = atoi (ix86_preferred_stack_boundary_string);
if (i < 2 || i > 31)
fatal ("-mpreferred_stack_boundary=%d is not between 2 and 31", i);
- i386_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT;
+ ix86_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT;
}
/* Validate -mbranch-cost= value, or provide default. */
- i386_branch_cost = 1;
- if (i386_branch_cost_string)
+ ix86_branch_cost = processor_target_table[ix86_cpu].branch_cost;
+ if (ix86_branch_cost_string)
{
- i386_branch_cost = atoi (i386_branch_cost_string);
- if (i386_branch_cost < 0 || i386_branch_cost > 5)
- fatal ("-mbranch-cost=%d is not between 0 and 5", i386_branch_cost);
+ ix86_branch_cost = atoi (ix86_branch_cost_string);
+ if (ix86_branch_cost < 0 || ix86_branch_cost > 5)
+ fatal ("-mbranch-cost=%d is not between 0 and 5",
+ ix86_branch_cost);
}
/* Keep nonleaf frame pointers. */
if (TARGET_OMIT_LEAF_FRAME_POINTER)
flag_omit_frame_pointer = 1;
+
+ /* If we're doing fast math, we don't care about comparison order
+ wrt NaNs. This lets us use a shorter comparison sequence. */
+ if (flag_fast_math)
+ target_flags &= ~MASK_IEEE_FP;
+
+ /* If we're planning on using `loop', use it. */
+ if (TARGET_USE_LOOP && optimize)
+ flag_branch_on_count_reg = 1;
}
/* A C statement (sans semicolon) to choose the order in which to
@@ -434,9 +460,9 @@ order_regs_for_local_alloc ()
/* User specified the register allocation order. */
- if (i386_reg_alloc_order)
+ if (ix86_reg_alloc_order)
{
- for (i = order = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
+ for (i = order = 0; (ch = ix86_reg_alloc_order[i]) != '\0'; i++)
{
int regno = 0;
@@ -482,40 +508,15 @@ optimization_options (level, size)
#endif
}
-/* Sign-extend a 16-bit constant */
-
-struct rtx_def *
-i386_sext16_if_const (op)
- struct rtx_def *op;
-{
- if (GET_CODE (op) == CONST_INT)
- {
- HOST_WIDE_INT val = INTVAL (op);
- HOST_WIDE_INT sext_val;
- if (val & 0x8000)
- sext_val = val | ~0xffff;
- else
- sext_val = val & 0xffff;
- if (sext_val != val)
- op = GEN_INT (sext_val);
- }
- return op;
-}
-
-/* Return nonzero if the rtx is aligned */
-
-static int
-i386_aligned_reg_p (regno)
- int regno;
-{
- return (regno == STACK_POINTER_REGNUM
- || (! flag_omit_frame_pointer && regno == FRAME_POINTER_REGNUM));
-}
+/* Return nonzero if the rtx is known aligned. */
+/* ??? Unused. */
int
-i386_aligned_p (op)
+ix86_aligned_p (op)
rtx op;
{
+ struct ix86_address parts;
+
/* Registers and immediate operands are always "aligned". */
if (GET_CODE (op) != MEM)
return 1;
@@ -524,47 +525,38 @@ i386_aligned_p (op)
if (MEM_VOLATILE_P (op))
return 0;
- /* Get address of memory operand. */
op = XEXP (op, 0);
- switch (GET_CODE (op))
- {
- case CONST_INT:
- if (INTVAL (op) & 3)
- break;
- return 1;
-
- /* Match "reg + offset" */
- case PLUS:
- if (GET_CODE (XEXP (op, 1)) != CONST_INT)
- break;
- if (INTVAL (XEXP (op, 1)) & 3)
- break;
-
- op = XEXP (op, 0);
- if (GET_CODE (op) != REG)
- break;
-
- /* ... fall through ... */
+ /* Pushes and pops are only valid on the stack pointer. */
+ if (GET_CODE (op) == PRE_DEC
+ || GET_CODE (op) == POST_INC)
+ return 1;
- case REG:
- return i386_aligned_reg_p (REGNO (op));
+ /* Decode the address. */
+ if (! ix86_decompose_address (op, &parts))
+ abort ();
- default:
- break;
+ /* Look for some component that isn't known to be aligned. */
+ if (parts.index)
+ {
+ if (parts.scale < 4
+ && REGNO_POINTER_ALIGN (REGNO (parts.index)) < 4)
+ return 0;
+ }
+ if (parts.base)
+ {
+ if (REGNO_POINTER_ALIGN (REGNO (parts.index)) < 4)
+ return 0;
+ }
+ if (parts.disp)
+ {
+ if (GET_CODE (parts.disp) != CONST_INT
+ || (INTVAL (parts.disp) & 3) != 0)
+ return 0;
}
- return 0;
-}
-
-/* Return nonzero if INSN looks like it won't compute useful cc bits
- as a side effect. This information is only a hint. */
-
-int
-i386_cc_probably_useless_p (insn)
- rtx insn;
-{
- return ! next_cc0_user (insn);
+ /* Didn't find one -- this must be an aligned address. */
+ return 1;
}
/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
@@ -572,7 +564,7 @@ i386_cc_probably_useless_p (insn)
assigned to DECL. */
int
-i386_valid_decl_attribute_p (decl, attributes, identifier, args)
+ix86_valid_decl_attribute_p (decl, attributes, identifier, args)
tree decl ATTRIBUTE_UNUSED;
tree attributes ATTRIBUTE_UNUSED;
tree identifier ATTRIBUTE_UNUSED;
@@ -586,7 +578,7 @@ i386_valid_decl_attribute_p (decl, attributes, identifier, args)
assigned to TYPE. */
int
-i386_valid_type_attribute_p (type, attributes, identifier, args)
+ix86_valid_type_attribute_p (type, attributes, identifier, args)
tree type;
tree attributes ATTRIBUTE_UNUSED;
tree identifier;
@@ -638,7 +630,7 @@ i386_valid_type_attribute_p (type, attributes, identifier, args)
warning to be generated). */
int
-i386_comp_type_attributes (type1, type2)
+ix86_comp_type_attributes (type1, type2)
tree type1;
tree type2;
{
@@ -654,7 +646,6 @@ i386_comp_type_attributes (type1, type2)
return 0;
return 1;
}
-
/* Value is the number of bytes of arguments automatically
popped when returning from a subroutine call.
@@ -674,7 +665,7 @@ i386_comp_type_attributes (type1, type2)
The attribute stdcall is equivalent to RTD on a per module basis. */
int
-i386_return_pops_args (fundecl, funtype, size)
+ix86_return_pops_args (fundecl, funtype, size)
tree fundecl;
tree funtype;
int size;
@@ -701,7 +692,6 @@ i386_return_pops_args (fundecl, funtype, size)
return 0;
}
-
/* Argument support functions. */
@@ -735,7 +725,7 @@ init_cumulative_args (cum, fntype, libname)
*cum = zero_cum;
/* Set up the number of registers to use for passing arguments. */
- cum->nregs = i386_regparm;
+ cum->nregs = ix86_regparm;
if (fntype)
{
tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype));
@@ -856,598 +846,441 @@ function_arg (cum, mode, type, named)
return ret;
}
-
-/* For an arg passed partly in registers and partly in memory,
- this is the number of registers used.
- For args passed entirely in registers or entirely in memory, zero. */
-
-int
-function_arg_partial_nregs (cum, mode, type, named)
- CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED; /* current arg information */
- enum machine_mode mode ATTRIBUTE_UNUSED; /* current arg mode */
- tree type ATTRIBUTE_UNUSED; /* type of the argument or 0 if lib support */
- int named ATTRIBUTE_UNUSED; /* != 0 for normal args, == 0 for ... args */
-{
- return 0;
-}
-
-char *
-singlemove_string (operands)
- rtx *operands;
-{
- rtx x;
- if (GET_CODE (operands[0]) == MEM
- && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC)
- {
- if (XEXP (x, 0) != stack_pointer_rtx)
- abort ();
- return "push%L1 %1";
- }
- else if (GET_CODE (operands[1]) == CONST_DOUBLE)
- return output_move_const_single (operands);
- else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG)
- return AS2 (mov%L0,%1,%0);
- else if (CONSTANT_P (operands[1]))
- return AS2 (mov%L0,%1,%0);
- else
- {
- output_asm_insn ("push%L1 %1", operands);
- return "pop%L0 %0";
- }
-}
-/* Output an insn to add the constant N to the register X. */
+/* Returns 1 if OP is either a symbol reference or a sum of a symbol
+ reference and a constant. */
-static void
-asm_add (n, x)
- int n;
- rtx x;
+int
+symbolic_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
- rtx xops[2];
- xops[0] = x;
-
- if (n == -1)
- output_asm_insn (AS1 (dec%L0,%0), xops);
- else if (n == 1)
- output_asm_insn (AS1 (inc%L0,%0), xops);
- else if (n < 0 || n == 128)
- {
- xops[1] = GEN_INT (-n);
- output_asm_insn (AS2 (sub%L0,%1,%0), xops);
- }
- else if (n > 0)
+ switch (GET_CODE (op))
{
- xops[1] = GEN_INT (n);
- output_asm_insn (AS2 (add%L0,%1,%0), xops);
- }
-}
-
-/* Output assembler code to perform a doubleword move insn
- with operands OPERANDS. */
-
-char *
-output_move_double (operands)
- rtx *operands;
-{
- enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
- rtx latehalf[2];
- rtx middlehalf[2];
- rtx xops[2];
- int dest_overlapped_low = 0;
- int size = GET_MODE_SIZE (GET_MODE (operands[0]));
-
- middlehalf[0] = 0;
- middlehalf[1] = 0;
-
- /* First classify both operands. */
-
- if (REG_P (operands[0]))
- optype0 = REGOP;
- else if (offsettable_memref_p (operands[0]))
- optype0 = OFFSOP;
- else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
- optype0 = POPOP;
- else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
- optype0 = PUSHOP;
- else if (GET_CODE (operands[0]) == MEM)
- optype0 = MEMOP;
- else
- optype0 = RNDOP;
-
- if (REG_P (operands[1]))
- optype1 = REGOP;
- else if (CONSTANT_P (operands[1]))
- optype1 = CNSTOP;
- else if (offsettable_memref_p (operands[1]))
- optype1 = OFFSOP;
- else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
- optype1 = POPOP;
- else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
- optype1 = PUSHOP;
- else if (GET_CODE (operands[1]) == MEM)
- optype1 = MEMOP;
- else
- optype1 = RNDOP;
-
- /* Check for the cases that are not supposed to happen
- either due to the operand constraints or the fact
- that all memory operands on the x86 are offsettable.
- Abort if we get one, because generating code for these
- cases is painful. */
+ case SYMBOL_REF:
+ case LABEL_REF:
+ return 1;
- if (optype0 == RNDOP || optype1 == RNDOP
- || optype0 == MEMOP || optype1 == MEMOP)
- abort ();
+ case CONST:
+ op = XEXP (op, 0);
+ if (GET_CODE (op) == SYMBOL_REF
+ || GET_CODE (op) == LABEL_REF
+ || (GET_CODE (op) == UNSPEC
+ && XINT (op, 1) >= 6
+ && XINT (op, 1) <= 7))
+ return 1;
+ if (GET_CODE (op) != PLUS
+ || GET_CODE (XEXP (op, 1)) != CONST_INT)
+ return 0;
- /* If one operand is decrementing and one is incrementing
- decrement the former register explicitly
- and change that operand into ordinary indexing. */
+ op = XEXP (op, 0);
+ if (GET_CODE (op) == SYMBOL_REF
+ || GET_CODE (op) == LABEL_REF)
+ return 1;
+ /* Only @GOTOFF gets offsets. */
+ if (GET_CODE (op) != UNSPEC
+ || XINT (op, 1) != 7)
+ return 0;
- if (optype0 == PUSHOP && optype1 == POPOP)
- {
- /* ??? Can this ever happen on i386? */
- operands[0] = XEXP (XEXP (operands[0], 0), 0);
- asm_add (-size, operands[0]);
- if (GET_MODE (operands[1]) == XFmode)
- operands[0] = gen_rtx_MEM (XFmode, operands[0]);
- else if (GET_MODE (operands[0]) == DFmode)
- operands[0] = gen_rtx_MEM (DFmode, operands[0]);
- else
- operands[0] = gen_rtx_MEM (DImode, operands[0]);
- optype0 = OFFSOP;
- }
+ op = XVECEXP (op, 0, 0);
+ if (GET_CODE (op) == SYMBOL_REF
+ || GET_CODE (op) == LABEL_REF)
+ return 1;
+ return 0;
- if (optype0 == POPOP && optype1 == PUSHOP)
- {
- /* ??? Can this ever happen on i386? */
- operands[1] = XEXP (XEXP (operands[1], 0), 0);
- asm_add (-size, operands[1]);
- if (GET_MODE (operands[1]) == XFmode)
- operands[1] = gen_rtx_MEM (XFmode, operands[1]);
- else if (GET_MODE (operands[1]) == DFmode)
- operands[1] = gen_rtx_MEM (DFmode, operands[1]);
- else
- operands[1] = gen_rtx_MEM (DImode, operands[1]);
- optype1 = OFFSOP;
+ default:
+ return 0;
}
+}
- /* Ok, we can do one word at a time.
- Normally we do the low-numbered word first,
- but if either operand is autodecrementing then we
- do the high-numbered word first.
-
- In either case, set up in LATEHALF the operands to use
- for the high-numbered word and in some cases alter the
- operands in OPERANDS to be suitable for the low-numbered word. */
-
- if (size == 12)
- {
- if (optype0 == REGOP)
- {
- middlehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
- latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
- }
- else if (optype0 == OFFSOP)
- {
- middlehalf[0] = adj_offsettable_operand (operands[0], 4);
- latehalf[0] = adj_offsettable_operand (operands[0], 8);
- }
- else
- {
- middlehalf[0] = operands[0];
- latehalf[0] = operands[0];
- }
-
- if (optype1 == REGOP)
- {
- middlehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
- latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
- }
- else if (optype1 == OFFSOP)
- {
- middlehalf[1] = adj_offsettable_operand (operands[1], 4);
- latehalf[1] = adj_offsettable_operand (operands[1], 8);
- }
- else if (optype1 == CNSTOP)
- {
- if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- REAL_VALUE_TYPE r; long l[3];
-
- REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
- REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
- operands[1] = GEN_INT (l[0]);
- middlehalf[1] = GEN_INT (l[1]);
- latehalf[1] = GEN_INT (l[2]);
- }
- else if (CONSTANT_P (operands[1]))
- /* No non-CONST_DOUBLE constant should ever appear here. */
- abort ();
- }
- else
- {
- middlehalf[1] = operands[1];
- latehalf[1] = operands[1];
- }
- }
+/* Return true if the operand contains a @GOT or @GOTOFF reference. */
- else
+int
+pic_symbolic_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (op) == CONST)
{
- /* Size is not 12. */
-
- if (optype0 == REGOP)
- latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
- else if (optype0 == OFFSOP)
- latehalf[0] = adj_offsettable_operand (operands[0], 4);
- else
- latehalf[0] = operands[0];
-
- if (optype1 == REGOP)
- latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
- else if (optype1 == OFFSOP)
- latehalf[1] = adj_offsettable_operand (operands[1], 4);
- else if (optype1 == CNSTOP)
- split_double (operands[1], &operands[1], &latehalf[1]);
- else
- latehalf[1] = operands[1];
- }
-
- /* If insn is effectively movd N (sp),-(sp) then we will do the
- high word first. We should use the adjusted operand 1
- (which is N+4 (sp) or N+8 (sp))
- for the low word and middle word as well,
- to compensate for the first decrement of sp. */
- if (optype0 == PUSHOP
- && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
- && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
- middlehalf[1] = operands[1] = latehalf[1];
-
- /* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)),
- if the upper part of reg N does not appear in the MEM, arrange to
- emit the move late-half first. Otherwise, compute the MEM address
- into the upper part of N and use that as a pointer to the memory
- operand. */
- if (optype0 == REGOP && optype1 == OFFSOP)
- {
- if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
- && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
- {
- /* If both halves of dest are used in the src memory address,
- compute the address into latehalf of dest. */
- compadr:
- xops[0] = latehalf[0];
- xops[1] = XEXP (operands[1], 0);
- output_asm_insn (AS2 (lea%L0,%a1,%0), xops);
- if (GET_MODE (operands[1]) == XFmode)
- {
- operands[1] = gen_rtx_MEM (XFmode, latehalf[0]);
- middlehalf[1] = adj_offsettable_operand (operands[1], size-8);
- latehalf[1] = adj_offsettable_operand (operands[1], size-4);
- }
- else
- {
- operands[1] = gen_rtx_MEM (DImode, latehalf[0]);
- latehalf[1] = adj_offsettable_operand (operands[1], size-4);
- }
- }
-
- else if (size == 12
- && reg_mentioned_p (middlehalf[0], XEXP (operands[1], 0)))
- {
- /* Check for two regs used by both source and dest. */
- if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
- || reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
- goto compadr;
-
- /* Only the middle reg conflicts; simply put it last. */
- output_asm_insn (singlemove_string (operands), operands);
- output_asm_insn (singlemove_string (latehalf), latehalf);
- output_asm_insn (singlemove_string (middlehalf), middlehalf);
- return "";
- }
-
- else if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
- /* If the low half of dest is mentioned in the source memory
- address, the arrange to emit the move late half first. */
- dest_overlapped_low = 1;
+ op = XEXP (op, 0);
+ if (GET_CODE (op) == UNSPEC)
+ return 1;
+ if (GET_CODE (op) != PLUS
+ || GET_CODE (XEXP (op, 1)) != CONST_INT)
+ return 0;
+ op = XEXP (op, 0);
+ if (GET_CODE (op) == UNSPEC)
+ return 1;
}
+ return 0;
+}
- /* If one or both operands autodecrementing,
- do the two words, high-numbered first. */
-
- /* Likewise, the first move would clobber the source of the second one,
- do them in the other order. This happens only for registers;
- such overlap can't happen in memory unless the user explicitly
- sets it up, and that is an undefined circumstance. */
-
-#if 0
- if (optype0 == PUSHOP || optype1 == PUSHOP
- || (optype0 == REGOP && optype1 == REGOP
- && REGNO (operands[0]) == REGNO (latehalf[1]))
- || dest_overlapped_low)
-#endif
+/* Test for a valid operand for a call instruction.
+ Don't allow the arg pointer register or virtual regs
+ since they may change into reg + const, which the patterns
+ can't handle yet. */
- if (optype0 == PUSHOP || optype1 == PUSHOP
- || (optype0 == REGOP && optype1 == REGOP
- && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1]))
- || REGNO (operands[0]) == REGNO (latehalf[1])))
- || dest_overlapped_low)
- {
- /* Do the high-numbered word. */
- output_asm_insn (singlemove_string (latehalf), latehalf);
+int
+call_insn_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (op) != MEM)
+ return 0;
+ op = XEXP (op, 0);
- if (size == 12)
- output_asm_insn (singlemove_string (middlehalf), middlehalf);
+ /* Disallow indirect through a virtual register. This leads to
+ compiler aborts when trying to eliminate them. */
+ if (GET_CODE (op) == REG
+ && (op == arg_pointer_rtx
+ || (REGNO (op) >= FIRST_PSEUDO_REGISTER
+ && REGNO (op) <= LAST_VIRTUAL_REGISTER)))
+ return 0;
- /* Do low-numbered word. */
- return singlemove_string (operands);
- }
+ /* Otherwise we can allow any general_operand in the address. */
+ return general_operand (op, Pmode);
+}
- /* Normal case: do the two words, low-numbered first. */
+/* Like call_insn_operand but allow (mem (symbol_ref ...))
+ even if pic. */
- output_asm_insn (singlemove_string (operands), operands);
+int
+expander_call_insn_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (op) != MEM)
+ return 0;
+ op = XEXP (op, 0);
- /* Do the middle one of the three words for long double */
- if (size == 12)
- output_asm_insn (singlemove_string (middlehalf), middlehalf);
+ /* Direct symbol references. */
+ if (CONSTANT_ADDRESS_P (op))
+ return 1;
- /* Do the high-numbered word. */
- output_asm_insn (singlemove_string (latehalf), latehalf);
+ /* Disallow indirect through a virtual register. This leads to
+ compiler aborts when trying to eliminate them. */
+ if (GET_CODE (op) == REG
+ && (op == arg_pointer_rtx
+ || (REGNO (op) >= FIRST_PSEUDO_REGISTER
+ && REGNO (op) <= LAST_VIRTUAL_REGISTER)))
+ return 0;
- return "";
+ /* Otherwise we can allow any general_operand in the address. */
+ return general_operand (op, mode);
}
-
-#define MAX_TMPS 2 /* max temporary registers used */
-/* Output the appropriate code to move push memory on the stack */
-
-char *
-output_move_pushmem (operands, insn, length, tmp_start, n_operands)
- rtx operands[];
- rtx insn;
- int length;
- int tmp_start;
- int n_operands;
+int
+constant_call_address_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
- struct
- {
- char *load;
- char *push;
- rtx xops[2];
- } tmp_info[MAX_TMPS];
-
- rtx src = operands[1];
- int max_tmps = 0;
- int offset = 0;
- int stack_p = reg_overlap_mentioned_p (stack_pointer_rtx, src);
- int stack_offset = 0;
- int i, num_tmps;
- rtx xops[1];
+ return GET_CODE (op) == MEM && CONSTANT_ADDRESS_P (XEXP (op, 0));
+}
- if (! offsettable_memref_p (src))
- fatal_insn ("Source is not offsettable", insn);
+/* Match exactly zero and one. */
- if ((length & 3) != 0)
- fatal_insn ("Pushing non-word aligned size", insn);
+int
+const0_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return op == CONST0_RTX (mode);
+}
- /* Figure out which temporary registers we have available */
- for (i = tmp_start; i < n_operands; i++)
- {
- if (GET_CODE (operands[i]) == REG)
- {
- if (reg_overlap_mentioned_p (operands[i], src))
- continue;
+int
+const1_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return op == const1_rtx;
+}
- tmp_info[ max_tmps++ ].xops[1] = operands[i];
- if (max_tmps == MAX_TMPS)
- break;
- }
- }
+/* Match 2, 4, or 8. Used for leal multiplicands. */
- if (max_tmps == 0)
- for (offset = length - 4; offset >= 0; offset -= 4)
- {
- xops[0] = adj_offsettable_operand (src, offset + stack_offset);
- output_asm_insn (AS1(push%L0,%0), xops);
- if (stack_p)
- stack_offset += 4;
- }
+int
+const248_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return (GET_CODE (op) == CONST_INT
+ && (INTVAL (op) == 2 || INTVAL (op) == 4 || INTVAL (op) == 8));
+}
- else
- for (offset = length - 4; offset >= 0; )
- {
- for (num_tmps = 0; num_tmps < max_tmps && offset >= 0; num_tmps++)
- {
- tmp_info[num_tmps].load = AS2(mov%L0,%0,%1);
- tmp_info[num_tmps].push = AS1(push%L0,%1);
- tmp_info[num_tmps].xops[0]
- = adj_offsettable_operand (src, offset + stack_offset);
- offset -= 4;
- }
+/* True if this is a constant appropriate for an increment or decremenmt. */
- for (i = 0; i < num_tmps; i++)
- output_asm_insn (tmp_info[i].load, tmp_info[i].xops);
+int
+incdec_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (op == const1_rtx || op == constm1_rtx)
+ return 1;
+ if (GET_CODE (op) != CONST_INT)
+ return 0;
+ if (mode == SImode && INTVAL (op) == (HOST_WIDE_INT) 0xffffffff)
+ return 1;
+ if (mode == HImode && INTVAL (op) == (HOST_WIDE_INT) 0xffff)
+ return 1;
+ if (mode == QImode && INTVAL (op) == (HOST_WIDE_INT) 0xff)
+ return 1;
+ return 0;
+}
- for (i = 0; i < num_tmps; i++)
- output_asm_insn (tmp_info[i].push, tmp_info[i].xops);
+/* Return false if this is the stack pointer, or any other fake
+ register eliminable to the stack pointer. Otherwise, this is
+ a register operand.
- if (stack_p)
- stack_offset += 4*num_tmps;
- }
+ This is used to prevent esp from being used as an index reg.
+ Which would only happen in pathological cases. */
- return "";
-}
-
int
-standard_80387_constant_p (x)
- rtx x;
+reg_no_sp_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
{
-#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
- REAL_VALUE_TYPE d;
- jmp_buf handler;
- int is0, is1;
-
- if (setjmp (handler))
+ rtx t = op;
+ if (GET_CODE (t) == SUBREG)
+ t = SUBREG_REG (t);
+ if (t == stack_pointer_rtx || t == arg_pointer_rtx)
return 0;
- set_float_handler (handler);
- REAL_VALUE_FROM_CONST_DOUBLE (d, x);
- is0 = REAL_VALUES_EQUAL (d, dconst0) && !REAL_VALUE_MINUS_ZERO (d);
- is1 = REAL_VALUES_EQUAL (d, dconst1);
- set_float_handler (NULL_PTR);
+ return register_operand (op, mode);
+}
- if (is0)
- return 1;
+/* Return true if op is a Q_REGS class register. */
- if (is1)
- return 2;
+int
+q_regs_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (mode != VOIDmode && GET_MODE (op) != mode)
+ return 0;
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+ return QI_REG_P (op);
+}
- /* Note that on the 80387, other constants, such as pi,
- are much slower to load as standard constants
- than to load from doubles in memory! */
- /* ??? Not true on K6: all constants are equal cost. */
-#endif
+/* Return true if op is a NON_Q_REGS class register. */
- return 0;
-}
-
-char *
-output_move_const_single (operands)
- rtx *operands;
+int
+non_q_regs_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
{
- if (FP_REG_P (operands[0]))
- {
- int conval = standard_80387_constant_p (operands[1]);
+ if (mode != VOIDmode && GET_MODE (op) != mode)
+ return 0;
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+ return NON_QI_REG_P (op);
+}
- if (conval == 1)
- return "fldz";
+/* Return 1 if OP is a comparison operator that can use the condition code
+ generated by a logical operation, which characteristicly does not set
+ overflow or carry. To be used with CCNOmode. */
- if (conval == 2)
- return "fld1";
- }
+int
+no_comparison_operator (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return ((mode == VOIDmode || GET_MODE (op) == mode)
+ && GET_RTX_CLASS (GET_CODE (op)) == '<'
+ && GET_CODE (op) != LE
+ && GET_CODE (op) != GT);
+}
- if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- REAL_VALUE_TYPE r; long l;
+/* Return 1 if OP is a comparison operator that can be issued by fcmov. */
- if (GET_MODE (operands[1]) == XFmode)
- abort ();
+int
+fcmov_comparison_operator (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return ((mode == VOIDmode || GET_MODE (op) == mode)
+ && GET_RTX_CLASS (GET_CODE (op)) == '<'
+ && GET_CODE (op) == unsigned_condition (GET_CODE (op)));
+}
- REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
- REAL_VALUE_TO_TARGET_SINGLE (r, l);
- operands[1] = GEN_INT (l);
- }
+/* Nearly general operand, but accept any const_double, since we wish
+ to be able to drop them into memory rather than have them get pulled
+ into registers. */
- return singlemove_string (operands);
+int
+cmp_fp_expander_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (mode != VOIDmode && mode != GET_MODE (op))
+ return 0;
+ if (GET_CODE (op) == CONST_DOUBLE)
+ return 1;
+ return general_operand (op, mode);
}
-
-/* Returns 1 if OP is either a symbol reference or a sum of a symbol
- reference and a constant. */
+
+/* Match an SI or HImode register for a zero_extract. */
int
-symbolic_operand (op, mode)
+ext_register_operand (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
+ if (GET_MODE (op) != SImode && GET_MODE (op) != HImode)
+ return 0;
+ return register_operand (op, VOIDmode);
+}
+
+/* Return 1 if this is a valid binary floating-point operation.
+ OP is the expression matched, and MODE is its mode. */
+
+int
+binary_fp_operator (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (mode != VOIDmode && mode != GET_MODE (op))
+ return 0;
+
switch (GET_CODE (op))
{
- case SYMBOL_REF:
- case LABEL_REF:
- return 1;
-
- case CONST:
- op = XEXP (op, 0);
- return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
- || GET_CODE (XEXP (op, 0)) == LABEL_REF)
- && GET_CODE (XEXP (op, 1)) == CONST_INT);
+ case PLUS:
+ case MINUS:
+ case MULT:
+ case DIV:
+ return GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT;
default:
return 0;
}
}
-/* Return nonzero if OP is a constant shift count small enough to
- encode into an lea instruction. */
+int
+mult_operator(op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return GET_CODE (op) == MULT;
+}
int
-small_shift_operand (op, mode)
- rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
+div_operator(op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
- return (GET_CODE (op) == CONST_INT && INTVAL (op) > 0 && INTVAL (op) < 4);
+ return GET_CODE (op) == DIV;
}
-/* Test for a valid operand for a call instruction.
- Don't allow the arg pointer register or virtual regs
- since they may change into reg + const, which the patterns
- can't handle yet. */
+int
+arith_or_logical_operator (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return ((mode == VOIDmode || GET_MODE (op) == mode)
+ && (GET_RTX_CLASS (GET_CODE (op)) == 'c'
+ || GET_RTX_CLASS (GET_CODE (op)) == '2'));
+}
+
+/* Returns 1 if OP is memory operand with a displacement. */
int
-call_insn_operand (op, mode)
- rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
+memory_displacement_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
{
- if (GET_CODE (op) == MEM
- && ((CONSTANT_ADDRESS_P (XEXP (op, 0))
- /* This makes a difference for PIC. */
- && general_operand (XEXP (op, 0), Pmode))
- || (GET_CODE (XEXP (op, 0)) == REG
- && XEXP (op, 0) != arg_pointer_rtx
- && ! (REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
- && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
- return 1;
+ struct ix86_address parts;
- return 0;
+ if (! memory_operand (op, mode))
+ return 0;
+
+ if (! ix86_decompose_address (XEXP (op, 0), &parts))
+ abort ();
+
+ return parts.disp != NULL_RTX;
}
-/* Like call_insn_operand but allow (mem (symbol_ref ...))
- even if pic. */
+/* To avoid problems when jump re-emits comparisons like testqi_ext_0,
+ re-recognize the operand to avoid a copy_to_mode_reg that will fail.
+
+ ??? It seems likely that this will only work because cmpsi is an
+ expander, and no actual insns use this. */
int
-expander_call_insn_operand (op, mode)
- rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
+cmpsi_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
{
- if (GET_CODE (op) == MEM
- && (CONSTANT_ADDRESS_P (XEXP (op, 0))
- || (GET_CODE (XEXP (op, 0)) == REG
- && XEXP (op, 0) != arg_pointer_rtx
- && ! (REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
- && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
+ if (general_operand (op, mode))
+ return 1;
+
+ if (GET_CODE (op) == AND
+ && GET_MODE (op) == SImode
+ && GET_CODE (XEXP (op, 0)) == ZERO_EXTRACT
+ && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT
+ && GET_CODE (XEXP (XEXP (op, 0), 2)) == CONST_INT
+ && INTVAL (XEXP (XEXP (op, 0), 1)) == 8
+ && INTVAL (XEXP (XEXP (op, 0), 2)) == 8
+ && GET_CODE (XEXP (op, 1)) == CONST_INT)
return 1;
return 0;
}
-/* Return 1 if OP is a comparison operator that can use the condition code
- generated by an arithmetic operation. */
+/* Returns 1 if OP is memory operand that can not be represented by the
+ modRM array. */
int
-arithmetic_comparison_operator (op, mode)
+long_memory_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
- enum rtx_code code;
-
- if (mode != VOIDmode && mode != GET_MODE (op))
- return 0;
-
- code = GET_CODE (op);
- if (GET_RTX_CLASS (code) != '<')
+ if (! memory_operand (op, mode))
return 0;
- return (code != GT && code != LE);
+ return memory_address_length (op) != 0;
}
+
+/* Return true if the constant is something that can be loaded with
+ a special instruction. Only handle 0.0 and 1.0; others are less
+ worthwhile. */
int
-ix86_logical_operator (op, mode)
- register rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
+standard_80387_constant_p (x)
+ rtx x;
{
- return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
+ if (GET_CODE (x) != CONST_DOUBLE)
+ return -1;
+
+#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
+ {
+ REAL_VALUE_TYPE d;
+ jmp_buf handler;
+ int is0, is1;
+
+ if (setjmp (handler))
+ return 0;
+
+ set_float_handler (handler);
+ REAL_VALUE_FROM_CONST_DOUBLE (d, x);
+ is0 = REAL_VALUES_EQUAL (d, dconst0) && !REAL_VALUE_MINUS_ZERO (d);
+ is1 = REAL_VALUES_EQUAL (d, dconst1);
+ set_float_handler (NULL_PTR);
+
+ if (is0)
+ return 1;
+
+ if (is1)
+ return 2;
+
+ /* Note that on the 80387, other constants, such as pi,
+ are much slower to load as standard constants
+ than to load from doubles in memory! */
+ /* ??? Not true on K6: all constants are equal cost. */
+ }
+#endif
+
+ return 0;
}
-
/* Returns 1 if OP contains a symbol reference */
int
@@ -1478,156 +1311,47 @@ symbolic_reference_mentioned_p (op)
return 0;
}
-
-/* Attempt to expand a binary operator. Make the expansion closer to the
- actual machine, then just general_operand, which will allow 3 separate
- memory references (one output, two input) in a single insn. Return
- whether the insn fails, or succeeds. */
-
-int
-ix86_expand_binary_operator (code, mode, operands)
- enum rtx_code code;
- enum machine_mode mode;
- rtx operands[];
-{
- int modified;
-
- /* Recognize <var1> = <value> <op> <var1> for commutative operators */
- if (GET_RTX_CLASS (code) == 'c'
- && (rtx_equal_p (operands[0], operands[2])
- || immediate_operand (operands[1], mode)))
- {
- rtx temp = operands[1];
- operands[1] = operands[2];
- operands[2] = temp;
- }
-
- /* If optimizing, copy to regs to improve CSE */
- if (TARGET_PSEUDO && optimize
- && ((reload_in_progress | reload_completed) == 0))
- {
- if (GET_CODE (operands[1]) == MEM
- && ! rtx_equal_p (operands[0], operands[1]))
- operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
- if (GET_CODE (operands[2]) == MEM)
- operands[2] = force_reg (GET_MODE (operands[2]), operands[2]);
-
- if (GET_CODE (operands[1]) == CONST_INT && code == MINUS)
- {
- rtx temp = gen_reg_rtx (GET_MODE (operands[0]));
-
- emit_move_insn (temp, operands[1]);
- operands[1] = temp;
- return TRUE;
- }
- }
-
- if (!ix86_binary_operator_ok (code, mode, operands))
- {
- /* If not optimizing, try to make a valid insn (optimize code
- previously did this above to improve chances of CSE) */
-
- if ((! TARGET_PSEUDO || !optimize)
- && ((reload_in_progress | reload_completed) == 0)
- && (GET_CODE (operands[1]) == MEM || GET_CODE (operands[2]) == MEM))
- {
- modified = FALSE;
- if (GET_CODE (operands[1]) == MEM
- && ! rtx_equal_p (operands[0], operands[1]))
- {
- operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
- modified = TRUE;
- }
-
- if (GET_CODE (operands[2]) == MEM)
- {
- operands[2] = force_reg (GET_MODE (operands[2]), operands[2]);
- modified = TRUE;
- }
-
- if (GET_CODE (operands[1]) == CONST_INT && code == MINUS)
- {
- rtx temp = gen_reg_rtx (GET_MODE (operands[0]));
-
- emit_move_insn (temp, operands[1]);
- operands[1] = temp;
- return TRUE;
- }
-
- if (modified && ! ix86_binary_operator_ok (code, mode, operands))
- return FALSE;
- }
- else
- return FALSE;
- }
+/* Return 1 if it is appropriate to emit `ret' instructions in the
+ body of a function. Do this only if the epilogue is simple, needing a
+ couple of insns. Prior to reloading, we can't tell how many registers
+ must be saved, so return 0 then. Return 0 if there is no frame
+ marker to de-allocate.
- return TRUE;
-}
-
-/* Return TRUE or FALSE depending on whether the binary operator meets the
- appropriate constraints. */
+ If NON_SAVING_SETJMP is defined and true, then it is not possible
+ for the epilogue to be simple, so return 0. This is a special case
+ since NON_SAVING_SETJMP will not cause regs_ever_live to change
+ until final, but jump_optimize may need to know sooner if a
+ `return' is OK. */
int
-ix86_binary_operator_ok (code, mode, operands)
- enum rtx_code code;
- enum machine_mode mode ATTRIBUTE_UNUSED;
- rtx operands[3];
+ix86_can_use_return_insn_p ()
{
- return (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)
- && (GET_CODE (operands[1]) != CONST_INT || GET_RTX_CLASS (code) == 'c');
-}
-
-/* Attempt to expand a unary operator. Make the expansion closer to the
- actual machine, then just general_operand, which will allow 2 separate
- memory references (one output, one input) in a single insn. Return
- whether the insn fails, or succeeds. */
+ int regno;
+ int nregs = 0;
+ int reglimit = (frame_pointer_needed
+ ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
+ int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
+ || current_function_uses_const_pool);
-int
-ix86_expand_unary_operator (code, mode, operands)
- enum rtx_code code;
- enum machine_mode mode;
- rtx operands[];
-{
- /* If optimizing, copy to regs to improve CSE */
- if (TARGET_PSEUDO
- && optimize
- && ((reload_in_progress | reload_completed) == 0)
- && GET_CODE (operands[1]) == MEM)
- operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
+#ifdef NON_SAVING_SETJMP
+ if (NON_SAVING_SETJMP && current_function_calls_setjmp)
+ return 0;
+#endif
- if (! ix86_unary_operator_ok (code, mode, operands))
- {
- if ((! TARGET_PSEUDO || optimize == 0)
- && ((reload_in_progress | reload_completed) == 0)
- && GET_CODE (operands[1]) == MEM)
- {
- operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
- if (! ix86_unary_operator_ok (code, mode, operands))
- return FALSE;
- }
- else
- return FALSE;
- }
+ if (! reload_completed)
+ return 0;
- return TRUE;
-}
-
-/* Return TRUE or FALSE depending on whether the unary operator meets the
- appropriate constraints. */
+ for (regno = reglimit - 1; regno >= 0; regno--)
+ if ((regs_ever_live[regno] && ! call_used_regs[regno])
+ || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
+ nregs++;
-int
-ix86_unary_operator_ok (code, mode, operands)
- enum rtx_code code ATTRIBUTE_UNUSED;
- enum machine_mode mode ATTRIBUTE_UNUSED;
- rtx operands[2] ATTRIBUTE_UNUSED;
-{
- return TRUE;
+ return nregs == 0 || ! frame_pointer_needed;
}
-static rtx pic_label_rtx;
-static char pic_label_name [256];
-static int pic_label_no = 0;
+static char pic_label_name[32];
+static int pic_label_output;
/* This function generates code for -fpic that loads %ebx with
the return address of the caller and then returns. */
@@ -1646,130 +1370,63 @@ asm_output_function_prefix (file, name)
/* Deep branch prediction favors having a return for every call. */
if (pic_reg_used && TARGET_DEEP_BRANCH_PREDICTION)
{
- tree prologue_node;
-
- if (pic_label_rtx == 0)
+ if (!pic_label_output)
{
- pic_label_rtx = gen_label_rtx ();
- ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", pic_label_no++);
- LABEL_NAME (pic_label_rtx) = pic_label_name;
- }
-
- prologue_node = make_node (FUNCTION_DECL);
- DECL_RESULT (prologue_node) = 0;
-
- /* This used to call ASM_DECLARE_FUNCTION_NAME() but since it's an
- internal (non-global) label that's being emitted, it didn't make
- sense to have .type information for local labels. This caused
- the SCO OpenServer 5.0.4 ELF assembler grief (why are you giving
- me debug info for a label that you're declaring non-global?) this
- was changed to call ASM_OUTPUT_LABEL() instead. */
+ /* This used to call ASM_DECLARE_FUNCTION_NAME() but since it's an
+ internal (non-global) label that's being emitted, it didn't make
+ sense to have .type information for local labels. This caused
+ the SCO OpenServer 5.0.4 ELF assembler grief (why are you giving
+ me debug info for a label that you're declaring non-global?) this
+ was changed to call ASM_OUTPUT_LABEL() instead. */
+ ASM_OUTPUT_LABEL (file, pic_label_name);
- ASM_OUTPUT_LABEL (file, pic_label_name);
- output_asm_insn ("movl (%1),%0", xops);
- output_asm_insn ("ret", xops);
- }
-}
+ xops[1] = gen_rtx_MEM (SImode, xops[1]);
+ output_asm_insn ("mov{l}\t{%1, %0|%0, %1}", xops);
+ output_asm_insn ("ret", xops);
-/* Generate the assembly code for function entry.
- FILE is an stdio stream to output the code to.
- SIZE is an int: how many units of temporary storage to allocate. */
-
-void
-function_prologue (file, size)
- FILE *file ATTRIBUTE_UNUSED;
- int size ATTRIBUTE_UNUSED;
-{
- if (TARGET_SCHEDULE_PROLOGUE)
- {
- pic_label_rtx = 0;
- return;
+ pic_label_output = 1;
+ }
}
-
- ix86_prologue (0);
}
-/* Expand the prologue into a bunch of separate insns. */
-
void
-ix86_expand_prologue ()
+load_pic_register ()
{
- if (! TARGET_SCHEDULE_PROLOGUE)
- return;
+ rtx gotsym, pclab;
- ix86_prologue (1);
-}
-
-void
-load_pic_register (do_rtl)
- int do_rtl;
-{
- rtx xops[4];
+ gotsym = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
if (TARGET_DEEP_BRANCH_PREDICTION)
{
- xops[0] = pic_offset_table_rtx;
- if (pic_label_rtx == 0)
- {
- pic_label_rtx = gen_label_rtx ();
- ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", pic_label_no++);
- LABEL_NAME (pic_label_rtx) = pic_label_name;
- }
-
- xops[1] = gen_rtx_MEM (QImode,
- gen_rtx (SYMBOL_REF, Pmode,
- LABEL_NAME (pic_label_rtx)));
-
- if (do_rtl)
- {
- emit_insn (gen_prologue_get_pc (xops[0], xops[1]));
- emit_insn (gen_prologue_set_got (xops[0],
-#ifdef YES_UNDERSCORES
- gen_rtx_SYMBOL_REF (Pmode,
- "$__GLOBAL_OFFSET_TABLE_"),
-#else
- gen_rtx_SYMBOL_REF (Pmode,
- "$_GLOBAL_OFFSET_TABLE_"),
-#endif
- xops[1]));
- }
- else
- {
- output_asm_insn (AS1 (call,%X1), xops);
- output_asm_insn ("addl $%__GLOBAL_OFFSET_TABLE_,%0", xops);
- pic_label_rtx = 0;
- }
+ if (pic_label_name[0] == '\0')
+ ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", 0);
+ pclab = gen_rtx_MEM (QImode, gen_rtx_SYMBOL_REF (Pmode, pic_label_name));
}
-
else
{
- xops[0] = pic_offset_table_rtx;
- xops[1] = gen_label_rtx ();
-
- if (do_rtl)
- {
- /* We can't put a raw CODE_LABEL into the RTL, and we can't emit
- a new CODE_LABEL after reload, so we need a single pattern to
- emit the 3 necessary instructions. */
- emit_insn (gen_prologue_get_pc_and_set_got (xops[0]));
- }
- else
- {
- output_asm_insn (AS1 (call,%P1), xops);
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
- CODE_LABEL_NUMBER (xops[1]));
- output_asm_insn (AS1 (pop%L0,%0), xops);
- output_asm_insn ("addl $%__GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops);
- }
+ pclab = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
}
- /* When -fpic, we must emit a scheduling barrier, so that the instruction
- that restores %ebx (which is PIC_OFFSET_TABLE_REGNUM), does not get
- moved before any instruction which implicitly uses the got. */
+ emit_insn (gen_prologue_get_pc (pic_offset_table_rtx, pclab));
- if (do_rtl)
- emit_insn (gen_blockage ());
+ if (! TARGET_DEEP_BRANCH_PREDICTION)
+ emit_insn (gen_popsi1 (pic_offset_table_rtx));
+
+ emit_insn (gen_prologue_set_got (pic_offset_table_rtx, gotsym, pclab));
+}
+
+/* Generate an SImode "push" pattern for input ARG. */
+
+static rtx
+gen_push (arg)
+ rtx arg;
+{
+ return gen_rtx (SET, VOIDmode,
+ gen_rtx_MEM (SImode,
+ gen_rtx (PRE_DEC, SImode,
+ stack_pointer_rtx)),
+ arg);
}
/* Compute the size of local storage taking into consideration the
@@ -1833,148 +1490,68 @@ ix86_compute_frame_size (size, nregs_on_stack)
return size + padding;
}
-static void
-ix86_prologue (do_rtl)
- int do_rtl;
+/* Expand the prologue into a bunch of separate insns. */
+
+void
+ix86_expand_prologue ()
{
register int regno;
int limit;
- rtx xops[4];
int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
|| current_function_uses_const_pool);
HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), (int *)0);
rtx insn;
- int cfa_offset = INCOMING_FRAME_SP_OFFSET, cfa_store_offset = cfa_offset;
- xops[0] = stack_pointer_rtx;
- xops[1] = frame_pointer_rtx;
- xops[2] = GEN_INT (tsize);
+ /* Note: AT&T enter does NOT have reversed args. Enter is probably
+ slower on all targets. Also sdb doesn't like it. */
if (frame_pointer_needed)
{
- if (do_rtl)
- {
- insn = emit_insn (gen_rtx (SET, VOIDmode,
- gen_rtx_MEM (SImode,
- gen_rtx (PRE_DEC, SImode,
- stack_pointer_rtx)),
- frame_pointer_rtx));
-
- RTX_FRAME_RELATED_P (insn) = 1;
- insn = emit_move_insn (xops[1], xops[0]);
- RTX_FRAME_RELATED_P (insn) = 1;
- }
-
- else
- {
- output_asm_insn ("push%L1 %1", xops);
-#ifdef INCOMING_RETURN_ADDR_RTX
- if (dwarf2out_do_frame ())
- {
- char *l = dwarf2out_cfi_label ();
-
- cfa_store_offset += 4;
- cfa_offset = cfa_store_offset;
- dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
- dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, - cfa_store_offset);
- }
-#endif
+ insn = emit_insn (gen_push (frame_pointer_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
- output_asm_insn (AS2 (mov%L0,%0,%1), xops);
-#ifdef INCOMING_RETURN_ADDR_RTX
- if (dwarf2out_do_frame ())
- dwarf2out_def_cfa ("", FRAME_POINTER_REGNUM, cfa_offset);
-#endif
- }
+ insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+ RTX_FRAME_RELATED_P (insn) = 1;
}
if (tsize == 0)
;
else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT)
{
- if (do_rtl)
- {
- insn = emit_insn (gen_prologue_set_stack_ptr (xops[2]));
- RTX_FRAME_RELATED_P (insn) = 1;
- }
+ if (frame_pointer_needed)
+ insn = emit_insn (gen_prologue_allocate_stack (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (-tsize),
+ frame_pointer_rtx));
else
- {
- output_asm_insn (AS2 (sub%L0,%2,%0), xops);
-#ifdef INCOMING_RETURN_ADDR_RTX
- if (dwarf2out_do_frame ())
- {
- cfa_store_offset += tsize;
- if (! frame_pointer_needed)
- {
- cfa_offset = cfa_store_offset;
- dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, cfa_offset);
- }
- }
-#endif
- }
+ insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (-tsize)));
+ RTX_FRAME_RELATED_P (insn) = 1;
}
else
{
- xops[3] = gen_rtx_REG (SImode, 0);
- if (do_rtl)
- emit_move_insn (xops[3], xops[2]);
- else
- output_asm_insn (AS2 (mov%L0,%2,%3), xops);
+ /* ??? Is this only valid for Win32? */
- xops[3] = gen_rtx_MEM (FUNCTION_MODE,
- gen_rtx (SYMBOL_REF, Pmode, "_alloca"));
+ rtx arg0, sym;
- if (do_rtl)
- emit_call_insn (gen_rtx (CALL, VOIDmode, xops[3], const0_rtx));
- else
- output_asm_insn (AS1 (call,%P3), xops);
- }
+ arg0 = gen_rtx_REG (SImode, 0);
+ emit_move_insn (arg0, GEN_INT (tsize));
- /* Note If use enter it is NOT reversed args.
- This one is not reversed from intel!!
- I think enter is slower. Also sdb doesn't like it.
- But if you want it the code is:
- {
- xops[3] = const0_rtx;
- output_asm_insn ("enter %2,%3", xops);
- }
- */
+ sym = gen_rtx_MEM (FUNCTION_MODE,
+ gen_rtx_SYMBOL_REF (Pmode, "_alloca"));
+ insn = emit_call_insn (gen_call (sym, const0_rtx));
+
+ CALL_INSN_FUNCTION_USAGE (insn)
+ = gen_rtx_EXPR_LIST (VOIDmode, arg0, CALL_INSN_FUNCTION_USAGE (insn));
+ }
limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
for (regno = limit - 1; regno >= 0; regno--)
if ((regs_ever_live[regno] && ! call_used_regs[regno])
|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
{
- xops[0] = gen_rtx_REG (SImode, regno);
- if (do_rtl)
- {
- insn = emit_insn (gen_rtx (SET, VOIDmode,
- gen_rtx_MEM (SImode,
- gen_rtx (PRE_DEC, SImode,
- stack_pointer_rtx)),
- xops[0]));
-
- RTX_FRAME_RELATED_P (insn) = 1;
- }
- else
- {
- output_asm_insn ("push%L0 %0", xops);
-#ifdef INCOMING_RETURN_ADDR_RTX
- if (dwarf2out_do_frame ())
- {
- char *l = dwarf2out_cfi_label ();
-
- cfa_store_offset += 4;
- if (! frame_pointer_needed)
- {
- cfa_offset = cfa_store_offset;
- dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
- }
-
- dwarf2out_reg_save (l, regno, - cfa_store_offset);
- }
-#endif
- }
+ insn = emit_insn (gen_push (gen_rtx_REG (SImode, regno)));
+ RTX_FRAME_RELATED_P (insn) = 1;
}
#ifdef SUBTARGET_PROLOGUE
@@ -1982,247 +1559,135 @@ ix86_prologue (do_rtl)
#endif
if (pic_reg_used)
- load_pic_register (do_rtl);
+ load_pic_register ();
/* If we are profiling, make sure no instructions are scheduled before
the call to mcount. However, if -fpic, the above call will have
done that. */
- if ((profile_flag || profile_block_flag)
- && ! pic_reg_used && do_rtl)
+ if ((profile_flag || profile_block_flag) && ! pic_reg_used)
emit_insn (gen_blockage ());
}
-/* Return 1 if it is appropriate to emit `ret' instructions in the
- body of a function. Do this only if the epilogue is simple, needing a
- couple of insns. Prior to reloading, we can't tell how many registers
- must be saved, so return 0 then. Return 0 if there is no frame
- marker to de-allocate.
-
- If NON_SAVING_SETJMP is defined and true, then it is not possible
- for the epilogue to be simple, so return 0. This is a special case
- since NON_SAVING_SETJMP will not cause regs_ever_live to change
- until final, but jump_optimize may need to know sooner if a
- `return' is OK. */
-
-int
-ix86_can_use_return_insn_p ()
-{
- int regno;
- int nregs = 0;
- int reglimit = (frame_pointer_needed
- ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
- int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
- || current_function_uses_const_pool);
-
-#ifdef NON_SAVING_SETJMP
- if (NON_SAVING_SETJMP && current_function_calls_setjmp)
- return 0;
-#endif
-
- if (! reload_completed)
- return 0;
-
- for (regno = reglimit - 1; regno >= 0; regno--)
- if ((regs_ever_live[regno] && ! call_used_regs[regno])
- || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
- nregs++;
-
- return nregs == 0 || ! frame_pointer_needed;
-}
-
-/* This function generates the assembly code for function exit.
- FILE is an stdio stream to output the code to.
- SIZE is an int: how many units of temporary storage to deallocate. */
-
-void
-function_epilogue (file, size)
- FILE *file ATTRIBUTE_UNUSED;
- int size ATTRIBUTE_UNUSED;
-{
- return;
-}
-
/* Restore function stack, frame, and registers. */
void
ix86_expand_epilogue ()
{
- ix86_epilogue (1);
-}
-
-static void
-ix86_epilogue (do_rtl)
- int do_rtl;
-{
register int regno;
register int limit;
int nregs;
- rtx xops[3];
int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
|| current_function_uses_const_pool);
int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging;
HOST_WIDE_INT offset;
HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), &nregs);
- /* sp is often unreliable so we may have to go off the frame pointer. */
+ /* SP is often unreliable so we may have to go off the frame pointer. */
offset = -(tsize + nregs * UNITS_PER_WORD);
- xops[2] = stack_pointer_rtx;
-
- /* When -fpic, we must emit a scheduling barrier, so that the instruction
- that restores %ebx (which is PIC_OFFSET_TABLE_REGNUM), does not get
- moved before any instruction which implicitly uses the got. This
- includes any instruction which uses a SYMBOL_REF or a LABEL_REF.
-
- Alternatively, this could be fixed by making the dependence on the
- PIC_OFFSET_TABLE_REGNUM explicit in the RTL. */
-
- if (flag_pic || profile_flag || profile_block_flag)
- emit_insn (gen_blockage ());
-
/* If we're only restoring one register and sp is not valid then
using a move instruction to restore the register since it's
less work than reloading sp and popping the register. Otherwise,
restore sp (if necessary) and pop the registers. */
- limit = frame_pointer_needed
- ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM;
+ limit = (frame_pointer_needed
+ ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
if (nregs > 1 || sp_valid)
{
if ( !sp_valid )
{
- xops[0] = adj_offsettable_operand (AT_BP (QImode), offset);
- if (do_rtl)
- emit_insn (gen_movsi_lea (xops[2], XEXP (xops[0], 0)));
- else
- output_asm_insn (AS2 (lea%L2,%0,%2), xops);
+ rtx addr_offset;
+ addr_offset = adj_offsettable_operand (AT_BP (QImode), offset);
+ addr_offset = XEXP (addr_offset, 0);
+
+ emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx, addr_offset));
}
for (regno = 0; regno < limit; regno++)
if ((regs_ever_live[regno] && ! call_used_regs[regno])
|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
{
- xops[0] = gen_rtx_REG (SImode, regno);
-
- if (do_rtl)
- emit_insn (gen_pop (xops[0]));
- else
- output_asm_insn ("pop%L0 %0", xops);
+ emit_insn (gen_popsi1 (gen_rtx_REG (SImode, regno)));
}
}
-
else
- for (regno = 0; regno < limit; regno++)
- if ((regs_ever_live[regno] && ! call_used_regs[regno])
- || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
- {
- xops[0] = gen_rtx_REG (SImode, regno);
- xops[1] = adj_offsettable_operand (AT_BP (Pmode), offset);
-
- if (do_rtl)
- emit_move_insn (xops[0], xops[1]);
- else
- output_asm_insn (AS2 (mov%L0,%1,%0), xops);
-
- offset += 4;
- }
+ {
+ for (regno = 0; regno < limit; regno++)
+ if ((regs_ever_live[regno] && ! call_used_regs[regno])
+ || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
+ {
+ emit_move_insn (gen_rtx_REG (SImode, regno),
+ adj_offsettable_operand (AT_BP (Pmode), offset));
+ offset += 4;
+ }
+ }
if (frame_pointer_needed)
{
/* If not an i386, mov & pop is faster than "leave". */
-
if (TARGET_USE_LEAVE)
- {
- if (do_rtl)
- emit_insn (gen_leave());
- else
- output_asm_insn ("leave", xops);
- }
+ emit_insn (gen_leave());
else
{
- xops[0] = frame_pointer_rtx;
- xops[1] = stack_pointer_rtx;
-
- if (do_rtl)
- {
- emit_insn (gen_epilogue_set_stack_ptr());
- emit_insn (gen_pop (xops[0]));
- }
- else
- {
- output_asm_insn (AS2 (mov%L2,%0,%2), xops);
- output_asm_insn ("pop%L0 %0", xops);
- }
+ emit_insn (gen_epilogue_deallocate_stack (stack_pointer_rtx,
+ frame_pointer_rtx));
+ emit_insn (gen_popsi1 (frame_pointer_rtx));
}
}
-
else if (tsize)
{
/* Intel's docs say that for 4 or 8 bytes of stack frame one should
use `pop' and not `add'. */
int use_pop = tsize == 4;
+ rtx edx = 0, ecx;
/* Use two pops only for the Pentium processors. */
if (tsize == 8 && !TARGET_386 && !TARGET_486)
{
rtx retval = current_function_return_rtx;
- xops[1] = gen_rtx_REG (SImode, 1); /* %edx */
+ edx = gen_rtx_REG (SImode, 1);
/* This case is a bit more complex. Since we cannot pop into
%ecx twice we need a second register. But this is only
available if the return value is not of DImode in which
case the %edx register is not available. */
use_pop = (retval == NULL
- || ! reg_overlap_mentioned_p (xops[1], retval));
+ || ! reg_overlap_mentioned_p (edx, retval));
}
if (use_pop)
{
- xops[0] = gen_rtx_REG (SImode, 2); /* %ecx */
-
- if (do_rtl)
- {
- /* We have to prevent the two pops here from being scheduled.
- GCC otherwise would try in some situation to put other
- instructions in between them which has a bad effect. */
- emit_insn (gen_blockage ());
- emit_insn (gen_pop (xops[0]));
- if (tsize == 8)
- emit_insn (gen_pop (xops[1]));
- }
- else
- {
- output_asm_insn ("pop%L0 %0", xops);
- if (tsize == 8)
- output_asm_insn ("pop%L1 %1", xops);
- }
+ ecx = gen_rtx_REG (SImode, 2);
+
+ /* We have to prevent the two pops here from being scheduled.
+ GCC otherwise would try in some situation to put other
+ instructions in between them which has a bad effect. */
+ emit_insn (gen_blockage ());
+ emit_insn (gen_popsi1 (ecx));
+ if (tsize == 8)
+ emit_insn (gen_popsi1 (edx));
}
else
{
/* If there is no frame pointer, we must still release the frame. */
- xops[0] = GEN_INT (tsize);
-
- if (do_rtl)
- emit_insn (gen_rtx (SET, VOIDmode, xops[2],
- gen_rtx (PLUS, SImode, xops[2], xops[0])));
- else
- output_asm_insn (AS2 (add%L2,%0,%2), xops);
+ emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (tsize)));
}
}
#ifdef FUNCTION_BLOCK_PROFILER_EXIT
if (profile_block_flag == 2)
{
- FUNCTION_BLOCK_PROFILER_EXIT(file);
+ FUNCTION_BLOCK_PROFILER_EXIT;
}
#endif
if (current_function_pops_args && current_function_args_size)
{
- xops[1] = GEN_INT (current_function_pops_args);
+ rtx popc = GEN_INT (current_function_pops_args);
/* i386 can only pop 32K bytes (maybe 64K? Is it signed?). If
asked to pop more, pop return address, do explicit add, and jump
@@ -2230,74 +1695,144 @@ ix86_epilogue (do_rtl)
if (current_function_pops_args >= 32768)
{
- /* ??? Which register to use here? */
- xops[0] = gen_rtx_REG (SImode, 2);
+ rtx ecx = gen_rtx_REG (SImode, 2);
- if (do_rtl)
- {
- emit_insn (gen_pop (xops[0]));
- emit_insn (gen_rtx (SET, VOIDmode, xops[2],
- gen_rtx (PLUS, SImode, xops[1], xops[2])));
- emit_jump_insn (xops[0]);
- }
- else
- {
- output_asm_insn ("pop%L0 %0", xops);
- output_asm_insn (AS2 (add%L2,%1,%2), xops);
- output_asm_insn ("jmp %*%0", xops);
- }
+ emit_insn (gen_popsi1 (ecx));
+ emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, popc));
+ emit_indirect_jump (ecx);
}
else
+ emit_jump_insn (gen_return_pop_internal (popc));
+ }
+ else
+ emit_jump_insn (gen_return_internal ());
+}
+
+/* Extract the parts of an RTL expression that is a valid memory address
+ for an instruction. Return false if the structure of the address is
+ grossly off. */
+
+static int
+ix86_decompose_address (addr, out)
+ register rtx addr;
+ struct ix86_address *out;
+{
+ rtx base = NULL_RTX;
+ rtx index = NULL_RTX;
+ rtx disp = NULL_RTX;
+ HOST_WIDE_INT scale = 1;
+ rtx scale_rtx = NULL_RTX;
+
+ if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG)
+ base = addr;
+ else if (GET_CODE (addr) == PLUS)
+ {
+ rtx op0 = XEXP (addr, 0);
+ rtx op1 = XEXP (addr, 1);
+ enum rtx_code code0 = GET_CODE (op0);
+ enum rtx_code code1 = GET_CODE (op1);
+
+ if (code0 == REG || code0 == SUBREG)
{
- if (do_rtl)
- emit_jump_insn (gen_return_pop_internal (xops[1]));
+ if (code1 == REG || code1 == SUBREG)
+ index = op0, base = op1; /* index + base */
else
- output_asm_insn ("ret %1", xops);
+ base = op0, disp = op1; /* base + displacement */
}
+ else if (code0 == MULT)
+ {
+ index = XEXP (op0, 0);
+ scale_rtx = XEXP (op0, 1);
+ if (code1 == REG || code1 == SUBREG)
+ base = op1; /* index*scale + base */
+ else
+ disp = op1; /* index*scale + disp */
+ }
+ else if (code0 == PLUS && GET_CODE (XEXP (op0, 0)) == MULT)
+ {
+ index = XEXP (XEXP (op0, 0), 0); /* index*scale + base + disp */
+ scale_rtx = XEXP (XEXP (op0, 0), 1);
+ base = XEXP (op0, 1);
+ disp = op1;
+ }
+ else if (code0 == PLUS)
+ {
+ index = XEXP (op0, 0); /* index + base + disp */
+ base = XEXP (op0, 1);
+ disp = op1;
+ }
+ else
+ return FALSE;
+ }
+ else if (GET_CODE (addr) == MULT)
+ {
+ index = XEXP (addr, 0); /* index*scale */
+ scale_rtx = XEXP (addr, 1);
+ }
+ else if (GET_CODE (addr) == ASHIFT)
+ {
+ rtx tmp;
+
+ /* We're called for lea too, which implements ashift on occasion. */
+ index = XEXP (addr, 0);
+ tmp = XEXP (addr, 1);
+ if (GET_CODE (tmp) != CONST_INT)
+ return FALSE;
+ scale = INTVAL (tmp);
+ if ((unsigned HOST_WIDE_INT) scale > 3)
+ return FALSE;
+ scale = 1 << scale;
}
else
+ disp = addr; /* displacement */
+
+ /* Extract the integral value of scale. */
+ if (scale_rtx)
{
- if (do_rtl)
- emit_jump_insn (gen_return_internal ());
- else
- output_asm_insn ("ret", xops);
+ if (GET_CODE (scale_rtx) != CONST_INT)
+ return FALSE;
+ scale = INTVAL (scale_rtx);
}
-}
-
-/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
- that is a valid memory address for an instruction.
- The MODE argument is the machine mode for the MEM expression
- that wants to use this address.
-
- On x86, legitimate addresses are:
- base movl (base),reg
- displacement movl disp,reg
- base + displacement movl disp(base),reg
- index + base movl (base,index),reg
- (index + base) + displacement movl disp(base,index),reg
- index*scale movl (,index,scale),reg
- index*scale + disp movl disp(,index,scale),reg
- index*scale + base movl (base,index,scale),reg
- (index*scale + base) + disp movl disp(base,index,scale),reg
-
- In each case, scale can be 1, 2, 4, 8. */
-
-/* This is exactly the same as print_operand_addr, except that
- it recognizes addresses instead of printing them.
- It only recognizes address in canonical form. LEGITIMIZE_ADDRESS should
- convert common non-canonical forms to canonical form so that they will
- be recognized. */
+ /* Allow arg pointer and stack pointer as index if there is not scaling */
+ if (base && index && scale == 1
+ && (index == arg_pointer_rtx || index == stack_pointer_rtx))
+ {
+ rtx tmp = base;
+ base = index;
+ index = tmp;
+ }
-#define ADDR_INVALID(msg,insn) \
-do { \
- if (TARGET_DEBUG_ADDR) \
- { \
- fprintf (stderr, msg); \
- debug_rtx (insn); \
- } \
-} while (0)
+ /* Special case: %ebp cannot be encoded as a base without a displacement. */
+ if (base == frame_pointer_rtx && !disp)
+ disp = const0_rtx;
+
+ /* Special case: on K6, [%esi] makes the instruction vector decoded.
+ Avoid this by transforming to [%esi+0]. */
+ if (ix86_cpu == PROCESSOR_K6 && !optimize_size
+ && base && !index && !disp
+ && REGNO_REG_CLASS (REGNO (base)) == SIREG)
+ disp = const0_rtx;
+ /* Special case: encode reg+reg instead of reg*2. */
+ if (!base && index && scale && scale == 2)
+ base = index, scale = 1;
+
+ /* Special case: scaling cannot be encoded without base or displacement. */
+ if (!base && !disp && index && scale != 1)
+ disp = const0_rtx;
+
+ out->base = base;
+ out->index = index;
+ out->disp = disp;
+ out->scale = scale;
+
+ return TRUE;
+}
+
+/* Determine if a given CONST RTX is a valid memory displacement
+ in PIC mode. */
+
int
legitimate_pic_address_disp_p (disp)
register rtx disp;
@@ -2329,104 +1864,46 @@ legitimate_pic_address_disp_p (disp)
return 1;
}
+/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression that is a valid
+ memory address for an instruction. The MODE argument is the machine mode
+ for the MEM expression that wants to use this address.
+
+ It only recognizes address in canonical form. LEGITIMIZE_ADDRESS should
+ convert common non-canonical forms to canonical form so that they will
+ be recognized. */
+
int
legitimate_address_p (mode, addr, strict)
enum machine_mode mode;
register rtx addr;
int strict;
{
- rtx base = NULL_RTX;
- rtx indx = NULL_RTX;
- rtx scale = NULL_RTX;
- rtx disp = NULL_RTX;
+ struct ix86_address parts;
+ rtx base, index, disp;
+ HOST_WIDE_INT scale;
+ const char *reason = NULL;
+ rtx reason_rtx = NULL_RTX;
if (TARGET_DEBUG_ADDR)
{
fprintf (stderr,
"\n======\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n",
GET_MODE_NAME (mode), strict);
-
debug_rtx (addr);
}
- if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG)
- base = addr;
-
- else if (GET_CODE (addr) == PLUS)
- {
- rtx op0 = XEXP (addr, 0);
- rtx op1 = XEXP (addr, 1);
- enum rtx_code code0 = GET_CODE (op0);
- enum rtx_code code1 = GET_CODE (op1);
-
- if (code0 == REG || code0 == SUBREG)
- {
- if (code1 == REG || code1 == SUBREG)
- {
- indx = op0; /* index + base */
- base = op1;
- }
-
- else
- {
- base = op0; /* base + displacement */
- disp = op1;
- }
- }
-
- else if (code0 == MULT)
- {
- indx = XEXP (op0, 0);
- scale = XEXP (op0, 1);
-
- if (code1 == REG || code1 == SUBREG)
- base = op1; /* index*scale + base */
-
- else
- disp = op1; /* index*scale + disp */
- }
-
- else if (code0 == PLUS && GET_CODE (XEXP (op0, 0)) == MULT)
- {
- indx = XEXP (XEXP (op0, 0), 0); /* index*scale + base + disp */
- scale = XEXP (XEXP (op0, 0), 1);
- base = XEXP (op0, 1);
- disp = op1;
- }
-
- else if (code0 == PLUS)
- {
- indx = XEXP (op0, 0); /* index + base + disp */
- base = XEXP (op0, 1);
- disp = op1;
- }
-
- else
- {
- ADDR_INVALID ("PLUS subcode is not valid.\n", op0);
- return FALSE;
- }
- }
-
- else if (GET_CODE (addr) == MULT)
+ if (! ix86_decompose_address (addr, &parts))
{
- indx = XEXP (addr, 0); /* index*scale */
- scale = XEXP (addr, 1);
+ reason = "decomposition failed";
+ goto error;
}
- else
- disp = addr; /* displacement */
-
- /* Allow arg pointer and stack pointer as index if there is not scaling */
- if (base && indx && !scale
- && (indx == arg_pointer_rtx || indx == stack_pointer_rtx))
- {
- rtx tmp = base;
- base = indx;
- indx = tmp;
- }
+ base = parts.base;
+ index = parts.index;
+ disp = parts.disp;
+ scale = parts.scale;
- /* Validate base register:
+ /* Validate base register.
Don't allow SUBREG's here, it can lead to spill failures when the base
is one word out of a two word structure, which is represented internally
@@ -2434,123 +1911,132 @@ legitimate_address_p (mode, addr, strict)
if (base)
{
+ reason_rtx = base;
+
if (GET_CODE (base) != REG)
{
- ADDR_INVALID ("Base is not a register.\n", base);
- return FALSE;
+ reason = "base is not a register";
+ goto error;
}
if (GET_MODE (base) != Pmode)
{
- ADDR_INVALID ("Base is not in Pmode.\n", base);
- return FALSE;
+ reason = "base is not in Pmode";
+ goto error;
}
if ((strict && ! REG_OK_FOR_BASE_STRICT_P (base))
|| (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (base)))
{
- ADDR_INVALID ("Base is not valid.\n", base);
- return FALSE;
+ reason = "base is not valid";
+ goto error;
}
}
- /* Validate index register:
+ /* Validate index register.
Don't allow SUBREG's here, it can lead to spill failures when the index
is one word out of a two word structure, which is represented internally
as a DImode int. */
- if (indx)
+
+ if (index)
{
- if (GET_CODE (indx) != REG)
+ reason_rtx = index;
+
+ if (GET_CODE (index) != REG)
{
- ADDR_INVALID ("Index is not a register.\n", indx);
- return FALSE;
+ reason = "index is not a register";
+ goto error;
}
- if (GET_MODE (indx) != Pmode)
+ if (GET_MODE (index) != Pmode)
{
- ADDR_INVALID ("Index is not in Pmode.\n", indx);
- return FALSE;
+ reason = "index is not in Pmode";
+ goto error;
}
- if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (indx))
- || (! strict && ! REG_OK_FOR_INDEX_NONSTRICT_P (indx)))
+ if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (index))
+ || (! strict && ! REG_OK_FOR_INDEX_NONSTRICT_P (index)))
{
- ADDR_INVALID ("Index is not valid.\n", indx);
- return FALSE;
+ reason = "index is not valid";
+ goto error;
}
}
- else if (scale)
- abort (); /* scale w/o index invalid */
- /* Validate scale factor: */
- if (scale)
+ /* Validate scale factor. */
+ if (scale != 1)
{
- HOST_WIDE_INT value;
-
- if (GET_CODE (scale) != CONST_INT)
+ reason_rtx = GEN_INT (scale);
+ if (!index)
{
- ADDR_INVALID ("Scale is not valid.\n", scale);
- return FALSE;
+ reason = "scale without index";
+ goto error;
}
- value = INTVAL (scale);
- if (value != 1 && value != 2 && value != 4 && value != 8)
+ if (scale != 2 && scale != 4 && scale != 8)
{
- ADDR_INVALID ("Scale is not a good multiplier.\n", scale);
- return FALSE;
+ reason = "scale is not a valid multiplier";
+ goto error;
}
}
/* Validate displacement. */
if (disp)
{
+ reason_rtx = disp;
+
if (!CONSTANT_ADDRESS_P (disp))
{
- ADDR_INVALID ("Displacement is not valid.\n", disp);
- return FALSE;
+ reason = "displacement is not constant";
+ goto error;
}
- else if (GET_CODE (disp) == CONST_DOUBLE)
+ if (GET_CODE (disp) == CONST_DOUBLE)
{
- ADDR_INVALID ("Displacement is a const_double.\n", disp);
- return FALSE;
+ reason = "displacement is a const_double";
+ goto error;
}
if (flag_pic && SYMBOLIC_CONST (disp))
{
if (! legitimate_pic_address_disp_p (disp))
{
- ADDR_INVALID ("Displacement is an invalid PIC construct.\n",
- disp);
- return FALSE;
+ reason = "displacement is an invalid pic construct";
+ goto error;
}
+ /* Verify that a symbolic pic displacement includes
+ the pic_offset_table_rtx register. */
if (base != pic_offset_table_rtx
- && (indx != pic_offset_table_rtx || scale != NULL_RTX))
+ && (index != pic_offset_table_rtx || scale != 1))
{
- ADDR_INVALID ("PIC displacement against invalid base.\n", disp);
- return FALSE;
+ reason = "pic displacement against invalid base";
+ goto error;
}
}
-
else if (HALF_PIC_P ())
{
if (! HALF_PIC_ADDRESS_P (disp)
- || (base != NULL_RTX || indx != NULL_RTX))
+ || (base != NULL_RTX || index != NULL_RTX))
{
- ADDR_INVALID ("Displacement is an invalid half-pic reference.\n",
- disp);
- return FALSE;
+ reason = "displacement is an invalid half-pic reference";
+ goto error;
}
}
}
+ /* Everything looks valid. */
if (TARGET_DEBUG_ADDR)
- fprintf (stderr, "Address is valid.\n");
-
- /* Everything looks valid, return true */
+ fprintf (stderr, "Success.\n");
return TRUE;
+
+error:
+ if (TARGET_DEBUG_ADDR)
+ {
+ fprintf (stderr, "Error: %s\n", reason);
+ debug_rtx (reason_rtx);
+ }
+ return FALSE;
}
/* Return a legitimate reference for ORIG (an address) using the
@@ -2675,21 +2161,6 @@ legitimize_pic_address (orig, reg)
return new;
}
-/* Emit insns to move operands[1] into operands[0]. */
-
-void
-emit_pic_move (operands, mode)
- rtx *operands;
- enum machine_mode mode ATTRIBUTE_UNUSED;
-{
- rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
-
- if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
- operands[1] = force_reg (Pmode, operands[1]);
- else
- operands[1] = legitimize_pic_address (operands[1], temp);
-}
-
/* Try machine-dependent ways of modifying an illegitimate address
to be legitimate. If we find one, return the new, valid address.
This macro is used in only one place: `memory_address' in explow.c.
@@ -2943,13 +2414,13 @@ output_pic_addr_const (file, x, code)
if (GET_CODE (XEXP (x, 0)) == CONST_INT)
{
output_pic_addr_const (file, XEXP (x, 0), code);
- fprintf (file, "+");
+ putc ('+', file);
output_pic_addr_const (file, XEXP (x, 1), code);
}
else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
{
output_pic_addr_const (file, XEXP (x, 1), code);
- fprintf (file, "+");
+ putc ('+', file);
output_pic_addr_const (file, XEXP (x, 0), code);
}
else
@@ -2957,9 +2428,11 @@ output_pic_addr_const (file, x, code)
break;
case MINUS:
+ putc (ASSEMBLER_DIALECT ? '(' : '[', file);
output_pic_addr_const (file, XEXP (x, 0), code);
- fprintf (file, "-");
+ putc ('-', file);
output_pic_addr_const (file, XEXP (x, 1), code);
+ putc (ASSEMBLER_DIALECT ? ')' : ']', file);
break;
case UNSPEC:
@@ -2989,222 +2462,121 @@ output_pic_addr_const (file, x, code)
}
static void
-put_jump_code (code, reverse, file)
+put_condition_code (code, mode, reverse, fp, file)
enum rtx_code code;
- int reverse;
+ enum machine_mode mode;
+ int reverse, fp;
FILE *file;
{
- int flags = cc_prev_status.flags;
- int ieee = (TARGET_IEEE_FP && (flags & CC_IN_80387)
- && !(cc_prev_status.flags & CC_FCOMI));
const char *suffix;
- if (flags & CC_Z_IN_NOT_C)
- switch (code)
- {
- case EQ:
- fputs (reverse ? "c" : "nc", file);
- return;
-
- case NE:
- fputs (reverse ? "nc" : "c", file);
- return;
-
- default:
- abort ();
- }
- if (ieee)
- {
- switch (code)
- {
- case LE:
- suffix = reverse ? "ae" : "b";
- break;
- case GT:
- case LT:
- case GE:
- suffix = reverse ? "ne" : "e";
- break;
- case EQ:
- suffix = reverse ? "ne" : "e";
- break;
- case NE:
- suffix = reverse ? "e" : "ne";
- break;
- default:
- abort ();
- }
- fputs (suffix, file);
- return;
- }
- if (flags & CC_TEST_AX)
- abort();
- if ((flags & CC_NO_OVERFLOW) && (code == LE || code == GT))
- abort ();
if (reverse)
code = reverse_condition (code);
+
switch (code)
{
case EQ:
suffix = "e";
break;
-
case NE:
suffix = "ne";
break;
-
case GT:
- suffix = flags & CC_IN_80387 ? "a" : "g";
+ if (mode == CCNOmode)
+ abort ();
+ suffix = "g";
break;
-
case GTU:
- suffix = "a";
+ /* ??? Use "nbe" instead of "a" for fcmov losage on some assemblers.
+ Those same assemblers have the same but opposite losage on cmov. */
+ suffix = fp ? "nbe" : "a";
break;
-
case LT:
- if (flags & CC_NO_OVERFLOW)
+ if (mode == CCNOmode)
suffix = "s";
else
- suffix = flags & CC_IN_80387 ? "b" : "l";
+ suffix = "l";
break;
-
case LTU:
suffix = "b";
break;
-
case GE:
- if (flags & CC_NO_OVERFLOW)
+ if (mode == CCNOmode)
suffix = "ns";
else
- suffix = flags & CC_IN_80387 ? "ae" : "ge";
+ suffix = "ge";
break;
-
case GEU:
- suffix = "ae";
+ /* ??? As above. */
+ suffix = fp ? "nb" : "ae";
break;
-
case LE:
- suffix = flags & CC_IN_80387 ? "be" : "le";
+ if (mode == CCNOmode)
+ abort ();
+ suffix = "le";
break;
-
case LEU:
suffix = "be";
break;
-
default:
abort ();
}
fputs (suffix, file);
}
-/* Append the correct conditional move suffix which corresponds to CODE. */
-
-static void
-put_condition_code (code, reverse_cc, mode, file)
- enum rtx_code code;
- int reverse_cc;
- enum mode_class mode;
- FILE * file;
+void
+print_reg (x, code, file)
+ rtx x;
+ int code;
+ FILE *file;
{
- int ieee = (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
- && ! (cc_prev_status.flags & CC_FCOMI));
- if (reverse_cc && ! ieee)
- code = reverse_condition (code);
-
- if (mode == MODE_INT)
- switch (code)
- {
- case NE:
- if (cc_prev_status.flags & CC_Z_IN_NOT_C)
- fputs ("b", file);
- else
- fputs ("ne", file);
- return;
-
- case EQ:
- if (cc_prev_status.flags & CC_Z_IN_NOT_C)
- fputs ("ae", file);
- else
- fputs ("e", file);
- return;
-
- case GE:
- if (cc_prev_status.flags & CC_NO_OVERFLOW)
- fputs ("ns", file);
- else
- fputs ("ge", file);
- return;
-
- case GT:
- fputs ("g", file);
- return;
-
- case LE:
- fputs ("le", file);
- return;
-
- case LT:
- if (cc_prev_status.flags & CC_NO_OVERFLOW)
- fputs ("s", file);
- else
- fputs ("l", file);
- return;
-
- case GEU:
- fputs ("ae", file);
- return;
-
- case GTU:
- fputs ("a", file);
- return;
-
- case LEU:
- fputs ("be", file);
- return;
-
- case LTU:
- fputs ("b", file);
- return;
+ if (REGNO (x) == ARG_POINTER_REGNUM
+ || REGNO (x) == FLAGS_REG
+ || REGNO (x) == FPSR_REG)
+ abort ();
- default:
- output_operand_lossage ("Invalid %%C operand");
- }
+ if (ASSEMBLER_DIALECT == 0 || USER_LABEL_PREFIX[0] == 0)
+ putc ('%', file);
+
+ if (code == 'w')
+ code = 2;
+ else if (code == 'b')
+ code = 1;
+ else if (code == 'k')
+ code = 4;
+ else if (code == 'y')
+ code = 3;
+ else if (code == 'h')
+ code = 0;
+ else
+ code = GET_MODE_SIZE (GET_MODE (x));
- else if (mode == MODE_FLOAT)
- switch (code)
- {
- case NE:
- fputs (ieee ? (reverse_cc ? "ne" : "e") : "ne", file);
- return;
- case EQ:
- fputs (ieee ? (reverse_cc ? "ne" : "e") : "e", file);
- return;
- case GE:
- fputs (ieee ? (reverse_cc ? "ne" : "e") : "nb", file);
- return;
- case GT:
- fputs (ieee ? (reverse_cc ? "ne" : "e") : "nbe", file);
- return;
- case LE:
- fputs (ieee ? (reverse_cc ? "nb" : "b") : "be", file);
- return;
- case LT:
- fputs (ieee ? (reverse_cc ? "ne" : "e") : "b", file);
- return;
- case GEU:
- fputs (ieee ? (reverse_cc ? "ne" : "e") : "nb", file);
- return;
- case GTU:
- fputs (ieee ? (reverse_cc ? "ne" : "e") : "nbe", file);
- return;
- case LEU:
- fputs (ieee ? (reverse_cc ? "nb" : "b") : "be", file);
- return;
- case LTU:
- fputs (ieee ? (reverse_cc ? "ne" : "e") : "b", file);
- return;
- default:
- output_operand_lossage ("Invalid %%C operand");
+ switch (code)
+ {
+ case 3:
+ if (STACK_TOP_P (x))
+ {
+ fputs ("st(0)", file);
+ break;
+ }
+ /* FALLTHRU */
+ case 4:
+ case 8:
+ case 12:
+ if (! FP_REG_P (x))
+ putc ('e', file);
+ /* FALLTHRU */
+ case 2:
+ fputs (hi_reg_name[REGNO (x)], file);
+ break;
+ case 1:
+ fputs (qi_reg_name[REGNO (x)], file);
+ break;
+ case 0:
+ fputs (qi_high_reg_name[REGNO (x)], file);
+ break;
+ default:
+ abort ();
}
}
@@ -3212,15 +2584,10 @@ put_condition_code (code, reverse_cc, mode, file)
L,W,B,Q,S,T -- print the opcode suffix for specified size of operand.
C -- print opcode suffix for set/cmov insn.
c -- like C, but print reversed condition
- F -- print opcode suffix for fcmov insn.
- f -- like F, but print reversed condition
- D -- print the opcode suffix for a jump
- d -- like D, but print reversed condition
R -- print the prefix for register names.
z -- print the opcode suffix for the size of the current operand.
* -- print a star (in certain assembler syntax)
w -- print the operand as if it's a "word" (HImode) even if it isn't.
- J -- print the appropriate jump operand.
s -- print a shift double count, followed by the assemblers argument
delimiter.
b -- print the QImode name of the register for the indicated operand.
@@ -3228,9 +2595,7 @@ put_condition_code (code, reverse_cc, mode, file)
w -- likewise, print the HImode name of the register.
k -- likewise, print the SImode name of the register.
h -- print the QImode name for a "high" register, either ah, bh, ch or dh.
- y -- print "st(0)" instead of "st" as a register.
- P -- print as a PIC constant
- _ -- output "_" if YES_UNDERSCORES */
+ y -- print "st(0)" instead of "st" as a register. */
void
print_operand (file, x, code)
@@ -3243,38 +2608,38 @@ print_operand (file, x, code)
switch (code)
{
case '*':
- if (USE_STAR)
+ if (ASSEMBLER_DIALECT == 0)
putc ('*', file);
return;
- case '_':
-#ifdef YES_UNDERSCORES
- putc ('_', file);
-#endif
- return;
-
case 'L':
- PUT_OP_SIZE (code, 'l', file);
+ if (ASSEMBLER_DIALECT == 0)
+ putc ('l', file);
return;
case 'W':
- PUT_OP_SIZE (code, 'w', file);
+ if (ASSEMBLER_DIALECT == 0)
+ putc ('w', file);
return;
case 'B':
- PUT_OP_SIZE (code, 'b', file);
+ if (ASSEMBLER_DIALECT == 0)
+ putc ('b', file);
return;
case 'Q':
- PUT_OP_SIZE (code, 'l', file);
+ if (ASSEMBLER_DIALECT == 0)
+ putc ('l', file);
return;
case 'S':
- PUT_OP_SIZE (code, 's', file);
+ if (ASSEMBLER_DIALECT == 0)
+ putc ('s', file);
return;
case 'T':
- PUT_OP_SIZE (code, 't', file);
+ if (ASSEMBLER_DIALECT == 0)
+ putc ('t', file);
return;
case 'z':
@@ -3284,45 +2649,48 @@ print_operand (file, x, code)
if (STACK_REG_P (x))
return;
+ /* Intel syntax has no truck with instruction suffixes. */
+ if (ASSEMBLER_DIALECT != 0)
+ return;
+
/* this is the size of op from size of operand */
switch (GET_MODE_SIZE (GET_MODE (x)))
{
+ case 1:
+ putc ('b', file);
+ return;
+
case 2:
-#ifdef HAVE_GAS_FILDS_FISTS
- PUT_OP_SIZE ('W', 's', file);
-#endif
+ putc ('w', file);
return;
case 4:
if (GET_MODE (x) == SFmode)
{
- PUT_OP_SIZE ('S', 's', file);
+ putc ('s', file);
return;
}
else
- PUT_OP_SIZE ('L', 'l', file);
+ putc ('l', file);
return;
case 12:
- PUT_OP_SIZE ('T', 't', file);
- return;
+ putc ('t', file);
+ return;
case 8:
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
{
#ifdef GAS_MNEMONICS
- PUT_OP_SIZE ('Q', 'q', file);
- return;
+ putc ('q', file);
#else
- PUT_OP_SIZE ('Q', 'l', file); /* Fall through */
+ putc ('l', file);
+ putc ('l', file);
#endif
}
-
- PUT_OP_SIZE ('Q', 'l', file);
+ else
+ putc ('l', file);
return;
-
- default:
- abort ();
}
case 'b':
@@ -3330,71 +2698,36 @@ print_operand (file, x, code)
case 'k':
case 'h':
case 'y':
- case 'P':
case 'X':
+ case 'P':
break;
- case 'J':
- switch (GET_CODE (x))
- {
- /* These conditions are appropriate for testing the result
- of an arithmetic operation, not for a compare operation.
- Cases GE, LT assume CC_NO_OVERFLOW true. All cases assume
- CC_Z_IN_NOT_C false and not floating point. */
- case NE: fputs ("jne", file); return;
- case EQ: fputs ("je", file); return;
- case GE: fputs ("jns", file); return;
- case LT: fputs ("js", file); return;
- case GEU: fputs ("jmp", file); return;
- case GTU: fputs ("jne", file); return;
- case LEU: fputs ("je", file); return;
- case LTU: fputs ("#branch never", file); return;
-
- /* no matching branches for GT nor LE */
-
- default:
- abort ();
- }
-
case 's':
if (GET_CODE (x) == CONST_INT || ! SHIFT_DOUBLE_OMITS_COUNT)
{
PRINT_OPERAND (file, x, 0);
- fputs (AS2C (,) + 1, file);
+ putc (',', file);
}
-
- return;
-
- case 'D':
- put_jump_code (GET_CODE (x), 0, file);
return;
- case 'd':
- put_jump_code (GET_CODE (x), 1, file);
- return;
-
- /* This is used by the conditional move instructions. */
case 'C':
- put_condition_code (GET_CODE (x), 0, MODE_INT, file);
+ put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 0, 0, file);
return;
-
- /* Like above, but reverse condition */
- case 'c':
- put_condition_code (GET_CODE (x), 1, MODE_INT, file); return;
-
case 'F':
- put_condition_code (GET_CODE (x), 0, MODE_FLOAT, file);
+ put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 0, 1, file);
return;
/* Like above, but reverse condition */
+ case 'c':
+ put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 1, 0, file);
+ return;
case 'f':
- put_condition_code (GET_CODE (x), 1, MODE_FLOAT, file);
+ put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 1, 1, file);
return;
default:
{
char str[50];
-
sprintf (str, "invalid operand code `%c'", code);
output_operand_lossage (str);
}
@@ -3408,16 +2741,29 @@ print_operand (file, x, code)
else if (GET_CODE (x) == MEM)
{
- PRINT_PTR (x, file);
- if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
+ /* No `byte ptr' prefix for call instructions. */
+ if (ASSEMBLER_DIALECT != 0 && code != 'X' && code != 'P')
{
- if (flag_pic)
- output_pic_addr_const (file, XEXP (x, 0), code);
- else
- output_addr_const (file, XEXP (x, 0));
+ char * size;
+ switch (GET_MODE_SIZE (GET_MODE (x)))
+ {
+ case 1: size = "BYTE"; break;
+ case 2: size = "WORD"; break;
+ case 4: size = "DWORD"; break;
+ case 8: size = "QWORD"; break;
+ case 12: size = "XWORD"; break;
+ default:
+ abort();
+ }
+ fputs (size, file);
+ fputs (" PTR ", file);
}
+
+ x = XEXP (x, 0);
+ if (flag_pic && CONSTANT_ADDRESS_P (x))
+ output_pic_addr_const (file, x, code);
else
- output_address (XEXP (x, 0));
+ output_address (x);
}
else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
@@ -3427,7 +2773,9 @@ print_operand (file, x, code)
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
REAL_VALUE_TO_TARGET_SINGLE (r, l);
- PRINT_IMMED_PREFIX (file);
+
+ if (ASSEMBLER_DIALECT == 0)
+ putc ('$', file);
fprintf (file, "0x%lx", l);
}
@@ -3456,12 +2804,22 @@ print_operand (file, x, code)
if (code != 'P')
{
if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
- PRINT_IMMED_PREFIX (file);
+ {
+ if (ASSEMBLER_DIALECT == 0)
+ putc ('$', file);
+ }
else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF
|| GET_CODE (x) == LABEL_REF)
- PRINT_OFFSET_PREFIX (file);
+ {
+ if (ASSEMBLER_DIALECT == 0)
+ putc ('$', file);
+ else
+ fputs ("OFFSET FLAT:", file);
+ }
}
- if (flag_pic)
+ if (GET_CODE (x) == CONST_INT)
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
+ else if (flag_pic)
output_pic_addr_const (file, x, code);
else
output_addr_const (file, x);
@@ -3475,306 +2833,110 @@ print_operand_address (file, addr)
FILE *file;
register rtx addr;
{
- register rtx reg1, reg2, breg, ireg;
- rtx offset;
-
- switch (GET_CODE (addr))
- {
- case REG:
- /* ESI addressing makes instruction vector decoded on the K6. We can
- avoid this by ESI+0 addressing. */
- if (REGNO_REG_CLASS (REGNO (addr)) == SIREG
- && ix86_cpu == PROCESSOR_K6 && !optimize_size)
- output_addr_const (file, const0_rtx);
- ADDR_BEG (file);
- fprintf (file, "%se", RP);
- fputs (hi_reg_name[REGNO (addr)], file);
- ADDR_END (file);
- break;
-
- case PLUS:
- reg1 = 0;
- reg2 = 0;
- ireg = 0;
- breg = 0;
- offset = 0;
- if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
- {
- offset = XEXP (addr, 0);
- addr = XEXP (addr, 1);
- }
- else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
- {
- offset = XEXP (addr, 1);
- addr = XEXP (addr, 0);
- }
+ struct ix86_address parts;
+ rtx base, index, disp;
+ int scale;
- if (GET_CODE (addr) != PLUS)
- ;
- else if (GET_CODE (XEXP (addr, 0)) == MULT)
- reg1 = XEXP (addr, 0), addr = XEXP (addr, 1);
- else if (GET_CODE (XEXP (addr, 1)) == MULT)
- reg1 = XEXP (addr, 1), addr = XEXP (addr, 0);
- else if (GET_CODE (XEXP (addr, 0)) == REG)
- reg1 = XEXP (addr, 0), addr = XEXP (addr, 1);
- else if (GET_CODE (XEXP (addr, 1)) == REG)
- reg1 = XEXP (addr, 1), addr = XEXP (addr, 0);
-
- if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
- {
- if (reg1 == 0)
- reg1 = addr;
- else
- reg2 = addr;
+ if (! ix86_decompose_address (addr, &parts))
+ abort ();
- addr = 0;
- }
+ base = parts.base;
+ index = parts.index;
+ disp = parts.disp;
+ scale = parts.scale;
- if (offset != 0)
- {
- if (addr != 0)
- abort ();
- addr = offset;
- }
+ if (!base && !index)
+ {
+ /* Displacement only requires special attention. */
- if ((reg1 && GET_CODE (reg1) == MULT)
- || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))
- {
- breg = reg2;
- ireg = reg1;
- }
- else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1)))
+ if (GET_CODE (disp) == CONST_INT)
{
- breg = reg1;
- ireg = reg2;
+ if (ASSEMBLER_DIALECT != 0)
+ fputs ("ds:", file);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
}
-
- if (ireg != 0 || breg != 0)
+ else if (flag_pic)
+ output_pic_addr_const (file, addr, 0);
+ else
+ output_addr_const (file, addr);
+ }
+ else
+ {
+ if (ASSEMBLER_DIALECT == 0)
{
- int scale = 1;
-
- if (addr != 0)
+ if (disp)
{
if (flag_pic)
- output_pic_addr_const (file, addr, 0);
- else if (GET_CODE (addr) == LABEL_REF)
- output_asm_label (addr);
+ output_pic_addr_const (file, disp, 0);
+ else if (GET_CODE (disp) == LABEL_REF)
+ output_asm_label (disp);
else
- output_addr_const (file, addr);
+ output_addr_const (file, disp);
}
- if (ireg != 0 && GET_CODE (ireg) == MULT)
+ putc ('(', file);
+ if (base)
+ PRINT_REG (base, 0, file);
+ if (index)
{
- scale = INTVAL (XEXP (ireg, 1));
- ireg = XEXP (ireg, 0);
- }
-
- /* The stack pointer can only appear as a base register,
- never an index register, so exchange the regs if it is wrong. */
-
- if (scale == 1 && ireg && REGNO (ireg) == STACK_POINTER_REGNUM)
- {
- rtx tmp;
-
- tmp = breg;
- breg = ireg;
- ireg = tmp;
+ putc (',', file);
+ PRINT_REG (index, 0, file);
+ if (scale != 1)
+ fprintf (file, ",%d", scale);
}
-
- /* output breg+ireg*scale */
- PRINT_B_I_S (breg, ireg, scale, file);
- break;
+ putc (')', file);
}
-
- case MULT:
- {
- int scale;
-
- if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
- {
- scale = INTVAL (XEXP (addr, 0));
- ireg = XEXP (addr, 1);
- }
- else
- {
- scale = INTVAL (XEXP (addr, 1));
- ireg = XEXP (addr, 0);
- }
-
- /* (reg,reg,) is shorter than (,reg,2). */
- if (scale == 2)
- {
- PRINT_B_I_S (ireg, ireg, 1, file);
- }
- else
- {
- output_addr_const (file, const0_rtx);
- PRINT_B_I_S (NULL_RTX, ireg, scale, file);
- }
- }
- break;
-
- default:
- if (GET_CODE (addr) == CONST_INT
- && INTVAL (addr) < 0x8000
- && INTVAL (addr) >= -0x8000)
- fprintf (file, "%d", (int) INTVAL (addr));
else
{
- if (flag_pic)
- output_pic_addr_const (file, addr, 0);
- else
- output_addr_const (file, addr);
- }
- }
-}
-
-/* Set the cc_status for the results of an insn whose pattern is EXP.
- On the 80386, we assume that only test and compare insns, as well
- as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, BSF, ASHIFT,
- ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully.
- Also, we assume that jumps, moves and sCOND don't affect the condition
- codes. All else clobbers the condition codes, by assumption.
-
- We assume that ALL integer add, minus, etc. instructions effect the
- condition codes. This MUST be consistent with i386.md.
-
- We don't record any float test or compare - the redundant test &
- compare check in final.c does not handle stack-like regs correctly. */
-
-void
-notice_update_cc (exp)
- rtx exp;
-{
- if (GET_CODE (exp) == SET)
- {
- /* Jumps do not alter the cc's. */
- if (SET_DEST (exp) == pc_rtx)
- return;
-
- /* Moving register or memory into a register:
- it doesn't alter the cc's, but it might invalidate
- the RTX's which we remember the cc's came from.
- (Note that moving a constant 0 or 1 MAY set the cc's). */
- if (REG_P (SET_DEST (exp))
- && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM
- || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'
- || GET_CODE (SET_SRC (exp)) == IF_THEN_ELSE))
- {
- if (cc_status.value1
- && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
- cc_status.value1 = 0;
-
- if (cc_status.value2
- && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
- cc_status.value2 = 0;
-
- return;
- }
-
- /* Moving register into memory doesn't alter the cc's.
- It may invalidate the RTX's which we remember the cc's came from. */
- if (GET_CODE (SET_DEST (exp)) == MEM
- && (REG_P (SET_SRC (exp))
- || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'))
- {
- if (cc_status.value1
- && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
- cc_status.value1 = 0;
- if (cc_status.value2
- && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
- cc_status.value2 = 0;
-
- return;
- }
-
- /* Function calls clobber the cc's. */
- else if (GET_CODE (SET_SRC (exp)) == CALL)
- {
- CC_STATUS_INIT;
- return;
- }
-
- /* Tests and compares set the cc's in predictable ways. */
- else if (SET_DEST (exp) == cc0_rtx)
- {
- CC_STATUS_INIT;
- cc_status.value1 = SET_SRC (exp);
- return;
- }
-
- /* Certain instructions effect the condition codes. */
- else if (GET_MODE (SET_SRC (exp)) == SImode
- || GET_MODE (SET_SRC (exp)) == HImode
- || GET_MODE (SET_SRC (exp)) == QImode)
- switch (GET_CODE (SET_SRC (exp)))
- {
- case ASHIFTRT: case LSHIFTRT: case ASHIFT:
- /* Shifts on the 386 don't set the condition codes if the
- shift count is zero. */
- if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT)
- {
- CC_STATUS_INIT;
- break;
- }
-
- /* We assume that the CONST_INT is non-zero (this rtx would
- have been deleted if it were zero. */
-
- case PLUS: case MINUS: case NEG:
- case AND: case IOR: case XOR:
- cc_status.flags = CC_NO_OVERFLOW;
- cc_status.value1 = SET_SRC (exp);
- cc_status.value2 = SET_DEST (exp);
- break;
+ rtx offset = NULL_RTX;
- /* This is the bsf pattern used by ffs. */
- case UNSPEC:
- if (XINT (SET_SRC (exp), 1) == 5)
- {
- /* Only the Z flag is defined after bsf. */
- cc_status.flags
- = CC_NOT_POSITIVE | CC_NOT_NEGATIVE | CC_NO_OVERFLOW;
- cc_status.value1 = XVECEXP (SET_SRC (exp), 0, 0);
- cc_status.value2 = 0;
- break;
- }
- /* FALLTHRU */
+ if (disp)
+ {
+ /* Pull out the offset of a symbol; print any symbol itself. */
+ if (GET_CODE (disp) == CONST
+ && GET_CODE (XEXP (disp, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT)
+ {
+ offset = XEXP (XEXP (disp, 0), 1);
+ disp = gen_rtx_CONST (VOIDmode,
+ XEXP (XEXP (disp, 0), 0));
+ }
- default:
- CC_STATUS_INIT;
- }
- else
- {
- CC_STATUS_INIT;
- }
- }
- else if (GET_CODE (exp) == PARALLEL
- && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
- {
- if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx)
- return;
- if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx)
+ if (flag_pic)
+ output_pic_addr_const (file, disp, 0);
+ else if (GET_CODE (disp) == LABEL_REF)
+ output_asm_label (disp);
+ else if (GET_CODE (disp) == CONST_INT)
+ offset = disp;
+ else
+ output_addr_const (file, disp);
+ }
- {
- CC_STATUS_INIT;
- if (stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0))))
+ putc ('[', file);
+ if (base)
{
- cc_status.flags |= CC_IN_80387;
- if (TARGET_CMOVE && stack_regs_mentioned_p
- (XEXP (SET_SRC (XVECEXP (exp, 0, 0)), 1)))
- cc_status.flags |= CC_FCOMI;
+ PRINT_REG (base, 0, file);
+ if (offset)
+ {
+ if (INTVAL (offset) >= 0)
+ putc ('+', file);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (offset));
+ }
}
+ else if (offset)
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (offset));
else
- cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
- return;
- }
+ putc ('0', file);
- CC_STATUS_INIT;
- }
- else
- {
- CC_STATUS_INIT;
+ if (index)
+ {
+ putc ('+', file);
+ PRINT_REG (index, 0, file);
+ if (scale != 1)
+ fprintf (file, "*%d", scale);
+ }
+ putc (']', file);
+ }
}
}
@@ -3793,7 +2955,9 @@ split_di (operands, num, lo_half, hi_half)
while (num--)
{
rtx op = operands[num];
- if (! reload_completed)
+ if (CONSTANT_P (op))
+ split_double (op, &lo_half[num], &hi_half[num]);
+ else if (! reload_completed)
{
lo_half[num] = gen_lowpart (SImode, op);
hi_half[num] = gen_highpart (SImode, op);
@@ -3803,8 +2967,6 @@ split_di (operands, num, lo_half, hi_half)
lo_half[num] = gen_rtx_REG (SImode, REGNO (op));
hi_half[num] = gen_rtx_REG (SImode, REGNO (op) + 1);
}
- else if (CONSTANT_P (op))
- split_double (op, &lo_half[num], &hi_half[num]);
else if (offsettable_memref_p (op))
{
rtx lo_addr = XEXP (op, 0);
@@ -3817,65 +2979,6 @@ split_di (operands, num, lo_half, hi_half)
}
}
-/* Return 1 if this is a valid binary operation on a 387.
- OP is the expression matched, and MODE is its mode. */
-
-int
-binary_387_op (op, mode)
- register rtx op;
- enum machine_mode mode;
-{
- if (mode != VOIDmode && mode != GET_MODE (op))
- return 0;
-
- switch (GET_CODE (op))
- {
- case PLUS:
- case MINUS:
- case MULT:
- case DIV:
- return GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT;
-
- default:
- return 0;
- }
-}
-
-/* Return 1 if this is a valid shift or rotate operation on a 386.
- OP is the expression matched, and MODE is its mode. */
-
-int
-shift_op (op, mode)
- register rtx op;
- enum machine_mode mode;
-{
- rtx operand = XEXP (op, 0);
-
- if (mode != VOIDmode && mode != GET_MODE (op))
- return 0;
-
- if (GET_MODE (operand) != GET_MODE (op)
- || GET_MODE_CLASS (GET_MODE (op)) != MODE_INT)
- return 0;
-
- return (GET_CODE (op) == ASHIFT
- || GET_CODE (op) == ASHIFTRT
- || GET_CODE (op) == LSHIFTRT
- || GET_CODE (op) == ROTATE
- || GET_CODE (op) == ROTATERT);
-}
-
-/* Return 1 if OP is COMPARE rtx with mode VOIDmode.
- MODE is not used. */
-
-int
-VOIDmode_compare_op (op, mode)
- register rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
-{
- return GET_CODE (op) == COMPARE && GET_MODE (op) == VOIDmode;
-}
-
/* Output code to perform a 387 binary operation in INSN, one of PLUS,
MINUS, MULT or DIV. OPERANDS are the insn operands, where operands[3]
is the expression of the binary operation. The output may either be
@@ -3889,33 +2992,49 @@ output_387_binary_op (insn, operands)
rtx insn;
rtx *operands;
{
- rtx temp;
- char *base_op;
static char buf[100];
+ rtx temp;
+ char *p;
switch (GET_CODE (operands[3]))
{
case PLUS:
- base_op = "fadd";
+ if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
+ || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
+ p = "fiadd";
+ else
+ p = "fadd";
break;
case MINUS:
- base_op = "fsub";
+ if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
+ || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
+ p = "fisub";
+ else
+ p = "fsub";
break;
case MULT:
- base_op = "fmul";
+ if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
+ || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
+ p = "fimul";
+ else
+ p = "fmul";
break;
case DIV:
- base_op = "fdiv";
+ if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
+ || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
+ p = "fidiv";
+ else
+ p = "fdiv";
break;
default:
abort ();
}
- strcpy (buf, base_op);
+ strcpy (buf, p);
switch (GET_CODE (operands[3]))
{
@@ -3929,73 +3048,89 @@ output_387_binary_op (insn, operands)
}
if (GET_CODE (operands[2]) == MEM)
- return strcat (buf, AS1 (%z2,%2));
-
- if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2]))
- abort ();
+ {
+ p = "%z2\t%2";
+ break;
+ }
if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
{
if (STACK_TOP_P (operands[0]))
- return strcat (buf, AS2 (p,%0,%2));
+ p = "p\t{%0,%2|%2, %0}";
else
- return strcat (buf, AS2 (p,%2,%0));
+ p = "p\t{%2,%0|%0, %2}";
+ break;
}
if (STACK_TOP_P (operands[0]))
- return strcat (buf, AS2C (%y2,%0));
+ p = "\t{%y2,%0|%0, %y2}";
else
- return strcat (buf, AS2C (%2,%0));
+ p = "\t{%2,%0|%0, %2}";
+ break;
case MINUS:
case DIV:
if (GET_CODE (operands[1]) == MEM)
- return strcat (buf, AS1 (r%z1,%1));
+ {
+ p = "r%z1\t%1";
+ break;
+ }
if (GET_CODE (operands[2]) == MEM)
- return strcat (buf, AS1 (%z2,%2));
+ {
+ p = "%z2\t%2";
+ break;
+ }
if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2]))
abort ();
+ /* Note that the Unixware assembler, and the AT&T assembler before
+ that, are confusingly not reversed from Intel syntax in this
+ area. */
if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
{
if (STACK_TOP_P (operands[0]))
- return strcat (buf, AS2 (p,%0,%2));
+ p = "p\t%0,%2";
else
- return strcat (buf, AS2 (rp,%2,%0));
+ p = "rp\t%2,%0";
+ break;
}
if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
{
if (STACK_TOP_P (operands[0]))
- return strcat (buf, AS2 (rp,%0,%1));
+ p = "rp\t%0,%1";
else
- return strcat (buf, AS2 (p,%1,%0));
+ p = "p\t%1,%0";
+ break;
}
if (STACK_TOP_P (operands[0]))
{
if (STACK_TOP_P (operands[1]))
- return strcat (buf, AS2C (%y2,%0));
+ p = "\t%y2,%0";
else
- return strcat (buf, AS2 (r,%y1,%0));
+ p = "r\t%y1,%0";
+ break;
}
else if (STACK_TOP_P (operands[1]))
- return strcat (buf, AS2C (%1,%0));
+ p = "\t%1,%0";
else
- return strcat (buf, AS2 (r,%2,%0));
+ p = "r\t%2,%0";
+ break;
default:
abort ();
}
+
+ strcat (buf, p);
+ return buf;
}
-
+
/* Output code for INSN to convert a float to a signed int. OPERANDS
- are the insn operands. The input may be SFmode, DFmode, or XFmode
- and the output operand may be SImode or DImode. As a special case,
- make sure that the 387 stack top dies if the output mode is DImode,
- because the hardware requires this. */
+ are the insn operands. The output may be [SD]Imode and the input
+ operand may be [SDX]Fmode. */
char *
output_fix_trunc (insn, operands)
@@ -4003,1739 +3138,2584 @@ output_fix_trunc (insn, operands)
rtx *operands;
{
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
- rtx xops[2];
-
- if (! STACK_TOP_P (operands[1]))
- abort ();
-
- if (GET_MODE (operands[0]) == DImode && ! stack_top_dies)
- abort ();
-
- xops[0] = GEN_INT (0x0c00);
- xops[1] = operands[5];
+ int dimode_p = GET_MODE (operands[0]) == DImode;
+ rtx xops[4];
- output_asm_insn (AS1 (fnstc%W2,%2), operands);
- output_asm_insn (AS2 (mov%W5,%2,%w5), operands);
- output_asm_insn (AS2 (or%W1,%0,%w1), xops);
- output_asm_insn (AS2 (mov%W3,%w5,%3), operands);
- output_asm_insn (AS1 (fldc%W3,%3), operands);
+ /* Jump through a hoop or two for DImode, since the hardware has no
+ non-popping instruction. We used to do this a different way, but
+ that was somewhat fragile and broke with post-reload splitters. */
+ if (dimode_p)
+ {
+ if (! STACK_TOP_P (operands[1]))
+ {
+ rtx tmp;
- xops[0] = NON_STACK_REG_P (operands[0]) ? operands[4] : operands[0];
+ output_asm_insn ("fst\t%y1", operands);
- if (stack_top_dies)
- output_asm_insn (AS1 (fistp%z0,%y0), xops);
- else
- output_asm_insn (AS1 (fist%z0,%y0), xops);
+ /* The scratch we allocated sure better have died. */
+ if (! stack_top_dies)
+ abort ();
- if (NON_STACK_REG_P (operands[0]))
- {
- if (GET_MODE (operands[0]) == SImode)
- output_asm_insn (AS2 (mov%L0,%4,%0), operands);
- else
- {
- xops[0] = operands[0];
- xops[1] = operands[4];
- output_asm_insn (output_move_double (xops), xops);
+ tmp = operands[1];
+ operands[1] = operands[5];
+ operands[5] = tmp;
}
+ else if (! stack_top_dies)
+ output_asm_insn ("fld\t%y1", operands);
}
- return AS1 (fldc%W2,%2);
-}
-
-/* Output code for INSN to extend a float. OPERANDS are the insn
- operands. The output may be DFmode or XFmode and the input operand
- may be SFmode or DFmode. Operands 2 and 3 are scratch memory and
- are only necessary if operands 0 or 1 are non-stack registers. */
-
-void
-output_float_extend (insn, operands)
- rtx insn;
- rtx *operands;
-{
- int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
- rtx xops[2];
-
- if (! STACK_TOP_P (operands[0]) && ! STACK_TOP_P (operands[1]))
+ if (! STACK_TOP_P (operands[1]))
abort ();
- if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1]) && stack_top_dies)
- return;
+ xops[0] = GEN_INT (12);
+ xops[1] = adj_offsettable_operand (operands[2], 1);
+ xops[1] = change_address (xops[1], QImode, NULL_RTX);
- if (STACK_TOP_P (operands[0]) )
- {
- if (NON_STACK_REG_P (operands[1]))
- {
- if (GET_MODE (operands[1]) == SFmode)
- output_asm_insn (AS2 (mov%L0,%1,%2), operands);
- else
- {
- xops[0] = operands[2];
- xops[1] = operands[1];
- output_asm_insn (output_move_double (xops), xops);
- }
- }
+ xops[2] = operands[0];
+ if (GET_CODE (operands[0]) != MEM)
+ xops[2] = operands[3];
- xops[0] = NON_STACK_REG_P (operands[1]) ? operands[2] : operands[1];
+ output_asm_insn ("fnstcw\t%2", operands);
+ output_asm_insn ("mov{l}\t{%2, %4|%4, %2}", operands);
+ output_asm_insn ("mov{b}\t{%0, %1|%1, %0}", xops);
+ output_asm_insn ("fldcw\t%2", operands);
+ output_asm_insn ("mov{l}\t{%4, %2|%2, %4}", operands);
- output_asm_insn (AS1 (fld%z0,%y0), xops);
- }
+ if (stack_top_dies || dimode_p)
+ output_asm_insn ("fistp%z2\t%2", xops);
else
- {
- xops[0] = NON_STACK_REG_P (operands[0]) ? operands[3] : operands[0];
+ output_asm_insn ("fist%z2\t%2", xops);
- if (stack_top_dies
- || (GET_CODE (xops[0]) == MEM && GET_MODE (xops[0]) == XFmode))
- {
- output_asm_insn (AS1 (fstp%z0,%y0), xops);
- if (! stack_top_dies)
- output_asm_insn (AS1 (fld%z0,%y0), xops);
- }
- else
- output_asm_insn (AS1 (fst%z0,%y0), xops);
+ output_asm_insn ("fldcw\t%2", operands);
- if (NON_STACK_REG_P (operands[0]))
+ if (GET_CODE (operands[0]) != MEM)
+ {
+ if (dimode_p)
{
- xops[0] = operands[0];
- xops[1] = operands[3];
- output_asm_insn (output_move_double (xops), xops);
+ split_di (operands+0, 1, xops+0, xops+1);
+ split_di (operands+3, 1, xops+2, xops+3);
+ output_asm_insn ("mov{l}\t{%2, %0|%0, %2}", xops);
+ output_asm_insn ("mov{l}\t{%3, %1|%1, %3}", xops);
}
+ else
+ output_asm_insn ("mov{l}\t{%3,%0|%0, %3}", operands);
}
+
+ return "";
}
-
-/* Output code for INSN to compare OPERANDS. The two operands might
- not have the same mode: one might be within a FLOAT or FLOAT_EXTEND
- expression. If the compare is in mode CCFPEQmode, use an opcode that
- will not fault if a qNaN is present. */
+
+/* Output code for INSN to compare OPERANDS. EFLAGS_P is 1 when fcomi
+ should be used and 2 when fnstsw should be used. UNORDERED_P is true
+ when fucom should be used. */
char *
-output_float_compare (insn, operands)
+output_fp_compare (insn, operands, eflags_p, unordered_p)
rtx insn;
rtx *operands;
+ int eflags_p, unordered_p;
{
int stack_top_dies;
- rtx body = XVECEXP (PATTERN (insn), 0, 0);
- int unordered_compare = GET_MODE (SET_SRC (body)) == CCFPEQmode;
- rtx tmp;
- int cc0_set = 1;
- int i;
+ rtx cmp_op0 = operands[0];
+ rtx cmp_op1 = operands[1];
- if (TARGET_CMOVE && STACK_REG_P (operands[1])
- && STACK_REG_P (operands[0]))
+ if (eflags_p == 2)
{
- cc_status.flags |= CC_FCOMI;
- cc_prev_status.flags &= ~CC_TEST_AX;
+ cmp_op0 = cmp_op1;
+ cmp_op1 = operands[2];
}
- if (! STACK_TOP_P (operands[0]))
- {
- tmp = operands[0];
- operands[0] = operands[1];
- operands[1] = tmp;
- cc_status.flags |= CC_REVERSED;
- }
-
- if (! STACK_TOP_P (operands[0]))
+ if (! STACK_TOP_P (cmp_op0))
abort ();
stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
- if (STACK_REG_P (operands[1])
+ if (STACK_REG_P (cmp_op1)
&& stack_top_dies
- && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))
- && REGNO (operands[1]) == FIRST_STACK_REG + 1)
+ && find_regno_note (insn, REG_DEAD, REGNO (cmp_op1))
+ && REGNO (cmp_op1) != FIRST_STACK_REG)
{
/* If both the top of the 387 stack dies, and the other operand
is also a stack register that dies, then this must be a
`fcompp' float compare */
- if (unordered_compare)
+ if (eflags_p == 1)
{
- if (cc_status.flags & CC_FCOMI)
- {
- output_asm_insn (AS2 (fucomip,%y1,%0), operands);
- output_asm_insn (AS1 (fstp, %y0), operands);
- if (!TARGET_IEEE_FP)
- cc0_set = 0;
- }
+ /* There is no double popping fcomi variant. Fortunately,
+ eflags is immune from the fstp's cc clobbering. */
+ if (unordered_p)
+ output_asm_insn ("fucomip\t{%y1, %0|%0, %y1}", operands);
else
- output_asm_insn ("fucompp", operands);
+ output_asm_insn ("fcomip\t{%y1, %0|%0, %y1}", operands);
+ return "fstp\t%y0";
}
else
{
- if (cc_status.flags & CC_FCOMI)
+ if (eflags_p == 2)
{
- output_asm_insn (AS2 (fcomip, %y1,%0), operands);
- output_asm_insn (AS1 (fstp, %y0), operands);
- if (!TARGET_IEEE_FP)
- cc0_set = 0;
+ if (unordered_p)
+ return "fucompp\n\tfnstsw\t%0";
+ else
+ return "fcompp\n\tfnstsw\t%0";
}
else
- output_asm_insn ("fcompp", operands);
+ {
+ if (unordered_p)
+ return "fucompp";
+ else
+ return "fcompp";
+ }
}
}
else
{
- static char buf[100];
+ /* Encoded here as eflags_p | intmode | unordered_p | stack_top_dies. */
- /* Decide if this is a float compare or an unordered float compare. */
+ static char * const alt[24] =
+ {
+ "fcom%z1\t%y1",
+ "fcomp%z1\t%y1",
+ "fucom%z1\t%y1",
+ "fucomp%z1\t%y1",
+
+ "ficom%z1\t%y1",
+ "ficomp%z1\t%y1",
+ NULL,
+ NULL,
+
+ "fcomi\t{%y1, %0|%0, %y1}",
+ "fcomip\t{%y1, %0|%0, %y1}",
+ "fucomi\t{%y1, %0|%0, %y1}",
+ "fucomip\t{%y1, %0|%0, %y1}",
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ "fcom%z2\t%y2\n\tfnstsw\t%0",
+ "fcomp%z2\t%y2\n\tfnstsw\t%0",
+ "fucom%z2\t%y2\n\tfnstsw\t%0",
+ "fucomp%z2\t%y2\n\tfnstsw\t%0",
+
+ "ficom%z2\t%y2\n\tfnstsw\t%0",
+ "ficomp%z2\t%y2\n\tfnstsw\t%0",
+ NULL,
+ NULL
+ };
+
+ int mask;
+ char *ret;
+
+ mask = eflags_p << 3;
+ mask |= (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT) << 2;
+ mask |= unordered_p << 1;
+ mask |= stack_top_dies;
+
+ if (mask >= 24)
+ abort ();
+ ret = alt[mask];
+ if (ret == NULL)
+ abort ();
- if (unordered_compare)
- strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fucomi" : "fucom");
- else
- strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fcomi" : "fcom");
+ return ret;
+ }
+}
- /* Modify the opcode if the 387 stack is to be popped. */
+/* Output assembler code to FILE to initialize basic-block profiling.
- if (stack_top_dies)
- strcat (buf, "p");
+ If profile_block_flag == 2
- if (cc_status.flags & CC_FCOMI)
- {
- output_asm_insn (strcat (buf, AS2 (%z1,%y1,%0)), operands);
- if (!TARGET_IEEE_FP)
- cc0_set = 0;
- }
- else
- output_asm_insn (strcat (buf, AS1 (%z1,%y1)), operands);
- }
+ Output code to call the subroutine `__bb_init_trace_func'
+ and pass two parameters to it. The first parameter is
+ the address of a block allocated in the object module.
+ The second parameter is the number of the first basic block
+ of the function.
- /* Now retrieve the condition code. */
- if (cc0_set)
- {
- char *r = output_fp_cc0_set (insn);
- if (r[0]) output_asm_insn (r, operands);
- }
+ The name of the block is a local symbol made with this statement:
+
+ ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
+ Of course, since you are writing the definition of
+ `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
+ can take a short cut in the definition of this macro and use the
+ name that you know will result.
- /* We emit fstp instruction after integer comparsions to improve
- scheduling. */
- for (i = 0; i < 2 ; i++)
- {
- if (STACK_REG_P (operands[i])
- && find_regno_note (insn, REG_DEAD, REGNO (operands[i]))
- && REGNO (operands[i]) != FIRST_STACK_REG
- && (!stack_top_dies || REGNO (operands[i]) != FIRST_STACK_REG + 1))
- {
- rtx xexp[2];
- xexp[0] = gen_rtx_REG (DFmode,
- REGNO (operands[i]) - (stack_top_dies != 0));
- output_asm_insn (AS1 (fstp, %y0), xexp);
- }
- }
+ The number of the first basic block of the function is
+ passed to the macro in BLOCK_OR_LABEL.
- return "";
+ If described in a virtual assembler language the code to be
+ output looks like:
+ parameter1 <- LPBX0
+ parameter2 <- BLOCK_OR_LABEL
+ call __bb_init_trace_func
-}
-
-/* Output opcodes to transfer the results of FP compare or test INSN
- from the FPU to the CPU flags. If TARGET_IEEE_FP, ensure that if the
- result of the compare or test is unordered, no comparison operator
- succeeds except NE. Return an output template, if any. */
+ else if profile_block_flag != 0
-char *
-output_fp_cc0_set (insn)
- rtx insn;
-{
- rtx xops[3];
- rtx next;
- enum rtx_code code;
+ Output code to call the subroutine `__bb_init_func'
+ and pass one single parameter to it, which is the same
+ as the first parameter to `__bb_init_trace_func'.
- if (!(cc_status.flags & CC_FCOMI))
- {
- xops[0] = gen_rtx_REG (HImode, 0);
- output_asm_insn (AS1 (fnsts%W0,%0), xops);
- }
+ The first word of this parameter is a flag which will be nonzero if
+ the object module has already been initialized. So test this word
+ first, and do not call `__bb_init_func' if the flag is nonzero.
+ Note: When profile_block_flag == 2 the test need not be done
+ but `__bb_init_trace_func' *must* be called.
- if (! TARGET_IEEE_FP)
- {
- if (!(cc_status.flags & CC_REVERSED))
- {
- next = next_cc0_user (insn);
-
- if (GET_CODE (PATTERN (next)) == SET
- && SET_DEST (PATTERN (next)) == pc_rtx
- && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
- code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
- else if (GET_CODE (PATTERN (next)) == SET)
- code = GET_CODE (SET_SRC (PATTERN (next)));
- else
- return "sahf";
-
- if (code == GT || code == LT || code == EQ || code == NE
- || code == LE || code == GE)
- {
- /* We will test eax directly. */
- cc_status.flags |= CC_TEST_AX;
- return "";
- }
- }
+ BLOCK_OR_LABEL may be used to generate a label number as a
+ branch destination in case `__bb_init_func' will not be called.
- return "sahf";
- }
+ If described in a virtual assembler language the code to be
+ output looks like:
- next = next_cc0_user (insn);
- if (next == NULL_RTX)
- abort ();
+ cmp (LPBX0),0
+ jne local_label
+ parameter1 <- LPBX0
+ call __bb_init_func
+ local_label:
+*/
+
+void
+ix86_output_function_block_profiler (file, block_or_label)
+ FILE *file;
+ int block_or_label;
+{
+ static int num_func = 0;
+ rtx xops[8];
+ char block_table[80], false_label[80];
+
+ ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0);
+
+ xops[1] = gen_rtx_SYMBOL_REF (VOIDmode, block_table);
+ xops[5] = stack_pointer_rtx;
+ xops[7] = gen_rtx_REG (Pmode, 0); /* eax */
+
+ CONSTANT_POOL_ADDRESS_P (xops[1]) = TRUE;
- if (GET_CODE (PATTERN (next)) == SET
- && SET_DEST (PATTERN (next)) == pc_rtx
- && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
- code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
- else if (GET_CODE (PATTERN (next)) == SET)
+ switch (profile_block_flag)
{
- if (GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
- code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
+ case 2:
+ xops[2] = GEN_INT (block_or_label);
+ xops[3] = gen_rtx_MEM (Pmode,
+ gen_rtx_SYMBOL_REF (VOIDmode, "__bb_init_trace_func"));
+ xops[6] = GEN_INT (8);
+
+ output_asm_insn ("push{l}\t%2", xops);
+ if (!flag_pic)
+ output_asm_insn ("push{l}\t%1", xops);
else
- code = GET_CODE (SET_SRC (PATTERN (next)));
- }
+ {
+ output_asm_insn ("lea{l}\t{%a1, %7|%7, %a1}", xops);
+ output_asm_insn ("push{l}\t%7", xops);
+ }
+ output_asm_insn ("call\t%P3", xops);
+ output_asm_insn ("add{l}\t{%6, %5|%5, %6}", xops);
+ break;
- else if (GET_CODE (PATTERN (next)) == PARALLEL
- && GET_CODE (XVECEXP (PATTERN (next), 0, 0)) == SET)
- {
- if (GET_CODE (SET_SRC (XVECEXP (PATTERN (next), 0, 0))) == IF_THEN_ELSE)
- code = GET_CODE (XEXP (SET_SRC (XVECEXP (PATTERN (next), 0, 0)), 0));
+ default:
+ ASM_GENERATE_INTERNAL_LABEL (false_label, "LPBZ", num_func);
+
+ xops[0] = const0_rtx;
+ xops[2] = gen_rtx_MEM (Pmode,
+ gen_rtx_SYMBOL_REF (VOIDmode, false_label));
+ xops[3] = gen_rtx_MEM (Pmode,
+ gen_rtx_SYMBOL_REF (VOIDmode, "__bb_init_func"));
+ xops[4] = gen_rtx_MEM (Pmode, xops[1]);
+ xops[6] = GEN_INT (4);
+
+ CONSTANT_POOL_ADDRESS_P (xops[2]) = TRUE;
+
+ output_asm_insn ("cmp{l}\t{%0, %4|%4, %0}", xops);
+ output_asm_insn ("jne\t%2", xops);
+
+ if (!flag_pic)
+ output_asm_insn ("push{l}\t%1", xops);
else
- code = GET_CODE (SET_SRC (XVECEXP (PATTERN (next), 0, 0)));
+ {
+ output_asm_insn ("lea{l}\t{%a1, %7|%7, %a2}", xops);
+ output_asm_insn ("push{l}\t%7", xops);
+ }
+ output_asm_insn ("call\t%P3", xops);
+ output_asm_insn ("add{l}\t{%6, %5|%5, %6}", xops);
+ ASM_OUTPUT_INTERNAL_LABEL (file, "LPBZ", num_func);
+ num_func++;
+ break;
}
- else
- abort ();
+}
- if (cc_status.flags & CC_FCOMI)
- {
- /* It is very tricky. We have to do it right. */
+/* Output assembler code to FILE to increment a counter associated
+ with basic block number BLOCKNO.
- xops [0] = gen_rtx_REG (QImode, 0);
+ If profile_block_flag == 2
- switch (code)
- {
- case GT:
- case GE:
- break;
+ Output code to initialize the global structure `__bb' and
+ call the function `__bb_trace_func' which will increment the
+ counter.
- case LT:
- output_asm_insn (AS1 (setb,%b0), xops);
- output_asm_insn (AS1 (setp,%h0), xops);
- output_asm_insn (AS2 (cmp%B0,%b0,%h0), xops);
- break;
+ `__bb' consists of two words. In the first word the number
+ of the basic block has to be stored. In the second word
+ the address of a block allocated in the object module
+ has to be stored.
- case LE:
- output_asm_insn (AS1 (setbe,%b0), xops);
- output_asm_insn (AS1 (setnp,%h0), xops);
- output_asm_insn (AS2 (xor%B0,%b0,%h0), xops);
- break;
+ The basic block number is given by BLOCKNO.
- case EQ:
- case NE:
- output_asm_insn (AS1 (setne,%b0), xops);
- output_asm_insn (AS1 (setp,%h0), xops);
- output_asm_insn (AS2 (or%B0,%b0,%h0), xops);
- break;
+ The address of the block is given by the label created with
- case GTU:
- case LTU:
- case GEU:
- case LEU:
- default:
- abort ();
- }
- }
- else
- {
- xops[0] = gen_rtx_REG (QImode, 0);
+ ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
- switch (code)
- {
- case GT:
- xops[1] = GEN_INT (0x45);
- output_asm_insn (AS2 (and%B0,%1,%h0), xops);
- /* je label */
- break;
+ by FUNCTION_BLOCK_PROFILER.
- case LT:
- xops[1] = GEN_INT (0x45);
- xops[2] = GEN_INT (0x01);
- output_asm_insn (AS2 (and%B0,%1,%h0), xops);
- output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
- /* je label */
- break;
+ Of course, since you are writing the definition of
+ `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
+ can take a short cut in the definition of this macro and use the
+ name that you know will result.
- case GE:
- xops[1] = GEN_INT (0x05);
- output_asm_insn (AS2 (and%B0,%1,%h0), xops);
- /* je label */
- break;
+ If described in a virtual assembler language the code to be
+ output looks like:
- case LE:
- xops[1] = GEN_INT (0x45);
- xops[2] = GEN_INT (0x40);
- output_asm_insn (AS2 (and%B0,%1,%h0), xops);
- output_asm_insn (AS1 (dec%B0,%h0), xops);
- output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
- /* jb label */
- break;
+ move BLOCKNO -> (__bb)
+ move LPBX0 -> (__bb+4)
+ call __bb_trace_func
- case EQ:
- xops[1] = GEN_INT (0x45);
- xops[2] = GEN_INT (0x40);
- output_asm_insn (AS2 (and%B0,%1,%h0), xops);
- output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
- /* je label */
- break;
+ Note that function `__bb_trace_func' must not change the
+ machine state, especially the flag register. To grant
+ this, you must output code to save and restore registers
+ either in this macro or in the macros MACHINE_STATE_SAVE
+ and MACHINE_STATE_RESTORE. The last two macros will be
+ used in the function `__bb_trace_func', so you must make
+ sure that the function prologue does not change any
+ register prior to saving it with MACHINE_STATE_SAVE.
- case NE:
- xops[1] = GEN_INT (0x44);
- xops[2] = GEN_INT (0x40);
- output_asm_insn (AS2 (and%B0,%1,%h0), xops);
- output_asm_insn (AS2 (xor%B0,%2,%h0), xops);
- /* jne label */
- break;
+ else if profile_block_flag != 0
- case GTU:
- case LTU:
- case GEU:
- case LEU:
- default:
- abort ();
- }
- }
+ Output code to increment the counter directly.
+ Basic blocks are numbered separately from zero within each
+ compiled object module. The count associated with block number
+ BLOCKNO is at index BLOCKNO in an array of words; the name of
+ this array is a local symbol made with this statement:
- return "";
-}
-
-#define MAX_386_STACK_LOCALS 2
+ ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 2);
-static rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
+ Of course, since you are writing the definition of
+ `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
+ can take a short cut in the definition of this macro and use the
+ name that you know will result.
-/* Define the structure for the machine field in struct function. */
-struct machine_function
-{
- rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
- rtx pic_label_rtx;
- char pic_label_name[256];
-};
+ If described in a virtual assembler language the code to be
+ output looks like:
-/* Functions to save and restore i386_stack_locals.
- These will be called, via pointer variables,
- from push_function_context and pop_function_context. */
+ inc (LPBX2+4*BLOCKNO)
+*/
void
-save_386_machine_status (p)
- struct function *p;
+ix86_output_block_profiler (file, blockno)
+ FILE *file ATTRIBUTE_UNUSED;
+ int blockno;
{
- p->machine
- = (struct machine_function *) xmalloc (sizeof (struct machine_function));
- bcopy ((char *) i386_stack_locals, (char *) p->machine->i386_stack_locals,
- sizeof i386_stack_locals);
- p->machine->pic_label_rtx = pic_label_rtx;
- bcopy (pic_label_name, p->machine->pic_label_name, 256);
-}
+ rtx xops[8], cnt_rtx;
+ char counts[80];
+ char *block_table = counts;
-void
-restore_386_machine_status (p)
- struct function *p;
-{
- bcopy ((char *) p->machine->i386_stack_locals, (char *) i386_stack_locals,
- sizeof i386_stack_locals);
- pic_label_rtx = p->machine->pic_label_rtx;
- bcopy (p->machine->pic_label_name, pic_label_name, 256);
- free (p->machine);
- p->machine = NULL;
-}
+ switch (profile_block_flag)
+ {
+ case 2:
+ ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0);
-/* Clear stack slot assignments remembered from previous functions.
- This is called from INIT_EXPANDERS once before RTL is emitted for each
- function. */
+ xops[1] = gen_rtx_SYMBOL_REF (VOIDmode, block_table);
+ xops[2] = GEN_INT (blockno);
+ xops[3] = gen_rtx_MEM (Pmode,
+ gen_rtx_SYMBOL_REF (VOIDmode, "__bb_trace_func"));
+ xops[4] = gen_rtx_SYMBOL_REF (VOIDmode, "__bb");
+ xops[5] = plus_constant (xops[4], 4);
+ xops[0] = gen_rtx_MEM (SImode, xops[4]);
+ xops[6] = gen_rtx_MEM (SImode, xops[5]);
-void
-clear_386_stack_locals ()
-{
- enum machine_mode mode;
- int n;
+ CONSTANT_POOL_ADDRESS_P (xops[1]) = TRUE;
- for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE;
- mode = (enum machine_mode) ((int) mode + 1))
- for (n = 0; n < MAX_386_STACK_LOCALS; n++)
- i386_stack_locals[(int) mode][n] = NULL_RTX;
+ output_asm_insn ("pushf", xops);
+ output_asm_insn ("mov{l}\t{%2, %0|%0, %2}", xops);
+ if (flag_pic)
+ {
+ xops[7] = gen_rtx_REG (Pmode, 0); /* eax */
+ output_asm_insn ("push{l}\t%7", xops);
+ output_asm_insn ("lea{l}\t{%a1, %7|%7, %a1}", xops);
+ output_asm_insn ("mov{l}\t{%7, %6|%6, %7}", xops);
+ output_asm_insn ("pop{l}\t%7", xops);
+ }
+ else
+ output_asm_insn ("mov{l}\t{%1, %6|%6, %1}", xops);
+ output_asm_insn ("call\t%P3", xops);
+ output_asm_insn ("popf", xops);
- pic_label_rtx = NULL_RTX;
- bzero (pic_label_name, 256);
- /* Arrange to save and restore i386_stack_locals around nested functions. */
- save_machine_status = save_386_machine_status;
- restore_machine_status = restore_386_machine_status;
-}
+ break;
-/* Return a MEM corresponding to a stack slot with mode MODE.
- Allocate a new slot if necessary.
+ default:
+ ASM_GENERATE_INTERNAL_LABEL (counts, "LPBX", 2);
+ cnt_rtx = gen_rtx_SYMBOL_REF (VOIDmode, counts);
+ SYMBOL_REF_FLAG (cnt_rtx) = TRUE;
- The RTL for a function can have several slots available: N is
- which slot to use. */
+ if (blockno)
+ cnt_rtx = plus_constant (cnt_rtx, blockno*4);
-rtx
-assign_386_stack_local (mode, n)
- enum machine_mode mode;
- int n;
-{
- if (n < 0 || n >= MAX_386_STACK_LOCALS)
- abort ();
+ if (flag_pic)
+ cnt_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, cnt_rtx);
- if (i386_stack_locals[(int) mode][n] == NULL_RTX)
- i386_stack_locals[(int) mode][n]
- = assign_stack_local (mode, GET_MODE_SIZE (mode), 0);
+ xops[0] = gen_rtx_MEM (SImode, cnt_rtx);
+ output_asm_insn ("inc{l}\t%0", xops);
- return i386_stack_locals[(int) mode][n];
+ break;
+ }
}
-int is_mul(op,mode)
- register rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
+void
+ix86_expand_move (mode, operands)
+ enum machine_mode mode;
+ rtx operands[];
{
- return (GET_CODE (op) == MULT);
-}
+ int strict = (reload_in_progress || reload_completed);
+ int want_clobber = 0;
+ rtx insn;
-int is_div(op,mode)
- register rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
-{
- return (GET_CODE (op) == DIV);
+ if (flag_pic && mode == Pmode && symbolic_operand (operands[1], Pmode))
+ {
+ /* Emit insns to move operands[1] into operands[0]. */
+
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (Pmode, operands[1]);
+ else
+ {
+ rtx temp = operands[0];
+ if (GET_CODE (temp) != REG)
+ temp = gen_reg_rtx (Pmode);
+ temp = legitimize_pic_address (operands[1], temp);
+ if (temp == operands[0])
+ return;
+ operands[1] = temp;
+ }
+ }
+ else
+ {
+ if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
+ operands[1] = force_reg (mode, operands[1]);
+
+ if (FLOAT_MODE_P (mode))
+ {
+ /* If we are loading a floating point constant that isn't 0 or 1
+ into a register, force the value to memory now, since we'll
+ get better code out the back end. */
+
+ if (strict)
+ ;
+ else if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (mode, operands[1]);
+ else if (GET_CODE (operands[1]) == CONST_DOUBLE
+ && ! standard_80387_constant_p (operands[1]))
+ operands[1] = validize_mem (force_const_mem (mode, operands[1]));
+ }
+ else
+ {
+ /* Try to guess when a cc clobber on the move might be fruitful. */
+ if (!strict
+ && GET_CODE (operands[0]) == REG
+ && operands[1] == const0_rtx
+ && !flag_peephole2)
+ want_clobber = 1;
+ }
+ }
+
+ insn = gen_rtx_SET (VOIDmode, operands[0], operands[1]);
+ if (want_clobber)
+ {
+ rtx clob;
+ clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
+ insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, insn, clob));
+ }
+
+ emit_insn (insn);
}
-
-#ifdef NOTYET
-/* Create a new copy of an rtx.
- Recursively copies the operands of the rtx,
- except for those few rtx codes that are sharable.
- Doesn't share CONST */
-rtx
-copy_all_rtx (orig)
- register rtx orig;
+/* Attempt to expand a binary operator. Make the expansion closer to the
+ actual machine, then just general_operand, which will allow 3 separate
+ memory references (one output, two input) in a single insn. Return
+ whether the insn fails, or succeeds. */
+
+void
+ix86_expand_binary_operator (code, mode, operands)
+ enum rtx_code code;
+ enum machine_mode mode;
+ rtx operands[];
{
- register rtx copy;
- register int i, j;
- register RTX_CODE code;
- register const char *format_ptr;
+ int matching_memory;
+ rtx src1, src2, dst, op, clob;
- code = GET_CODE (orig);
+ dst = operands[0];
+ src1 = operands[1];
+ src2 = operands[2];
- switch (code)
+ /* Recognize <var1> = <value> <op> <var1> for commutative operators */
+ if (GET_RTX_CLASS (code) == 'c'
+ && (rtx_equal_p (dst, src2)
+ || immediate_operand (src1, mode)))
{
- case REG:
- case QUEUED:
- case CONST_INT:
- case CONST_DOUBLE:
- case SYMBOL_REF:
- case CODE_LABEL:
- case PC:
- case CC0:
- case SCRATCH:
- /* SCRATCH must be shared because they represent distinct values. */
- return orig;
+ rtx temp = src1;
+ src1 = src2;
+ src2 = temp;
+ }
-#if 0
- case CONST:
- /* CONST can be shared if it contains a SYMBOL_REF. If it contains
- a LABEL_REF, it isn't sharable. */
- if (GET_CODE (XEXP (orig, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF
- && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT)
- return orig;
- break;
-#endif
- /* A MEM with a constant address is not sharable. The problem is that
- the constant address may need to be reloaded. If the mem is shared,
- then reloading one copy of this mem will cause all copies to appear
- to have been reloaded. */
+ /* If the destination is memory, and we do not have matching source
+ operands, do things in registers. */
+ matching_memory = 0;
+ if (GET_CODE (dst) == MEM)
+ {
+ if (rtx_equal_p (dst, src1))
+ matching_memory = 1;
+ else if (GET_RTX_CLASS (code) == 'c'
+ && rtx_equal_p (dst, src2))
+ matching_memory = 2;
+ else
+ dst = gen_reg_rtx (mode);
+ }
+
+ /* Both source operands cannot be in memory. */
+ if (GET_CODE (src1) == MEM && GET_CODE (src2) == MEM)
+ {
+ if (matching_memory != 2)
+ src2 = force_reg (mode, src2);
+ else
+ src1 = force_reg (mode, src1);
}
- copy = rtx_alloc (code);
- PUT_MODE (copy, GET_MODE (orig));
- copy->in_struct = orig->in_struct;
- copy->volatil = orig->volatil;
- copy->unchanging = orig->unchanging;
- copy->integrated = orig->integrated;
- /* intel1 */
- copy->is_spill_rtx = orig->is_spill_rtx;
+ /* If the operation is not commutable, source 1 cannot be a constant. */
+ if (CONSTANT_P (src1) && GET_RTX_CLASS (code) != 'c')
+ src1 = force_reg (mode, src1);
+
+ /* If optimizing, copy to regs to improve CSE */
+ if (optimize && !reload_in_progress && !reload_completed)
+ {
+ if (GET_CODE (dst) == MEM)
+ dst = gen_reg_rtx (mode);
+ if (GET_CODE (src1) == MEM)
+ src1 = force_reg (mode, src1);
+ if (GET_CODE (src2) == MEM)
+ src2 = force_reg (mode, src2);
+ }
- format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
+ /* Emit the instruction. */
- for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
+ op = gen_rtx_SET (VOIDmode, dst, gen_rtx_fmt_ee (code, mode, src1, src2));
+ if (reload_in_progress)
{
- switch (*format_ptr++)
- {
- case 'e':
- XEXP (copy, i) = XEXP (orig, i);
- if (XEXP (orig, i) != NULL)
- XEXP (copy, i) = copy_rtx (XEXP (orig, i));
- break;
+ /* Reload doesn't know about the flags register, and doesn't know that
+ it doesn't want to clobber it. We can only do this with PLUS. */
+ if (code != PLUS)
+ abort ();
+ emit_insn (op);
+ }
+ else
+ {
+ clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
+ emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clob)));
+ }
- case '0':
- case 'u':
- XEXP (copy, i) = XEXP (orig, i);
- break;
+ /* Fix up the destination if needed. */
+ if (dst != operands[0])
+ emit_move_insn (operands[0], dst);
+}
- case 'E':
- case 'V':
- XVEC (copy, i) = XVEC (orig, i);
- if (XVEC (orig, i) != NULL)
- {
- XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
- for (j = 0; j < XVECLEN (copy, i); j++)
- XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j));
- }
- break;
+/* Return TRUE or FALSE depending on whether the binary operator meets the
+ appropriate constraints. */
- case 'w':
- XWINT (copy, i) = XWINT (orig, i);
- break;
+int
+ix86_binary_operator_ok (code, mode, operands)
+ enum rtx_code code;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+ rtx operands[3];
+{
+ /* Both source operands cannot be in memory. */
+ if (GET_CODE (operands[1]) == MEM && GET_CODE (operands[2]) == MEM)
+ return 0;
+ /* If the operation is not commutable, source 1 cannot be a constant. */
+ if (CONSTANT_P (operands[1]) && GET_RTX_CLASS (code) != 'c')
+ return 0;
+ /* If the destination is memory, we must have a matching source operand. */
+ if (GET_CODE (operands[0]) == MEM
+ && ! (rtx_equal_p (operands[0], operands[1])
+ || (GET_RTX_CLASS (code) == 'c'
+ && rtx_equal_p (operands[0], operands[2]))))
+ return 0;
+ return 1;
+}
- case 'i':
- XINT (copy, i) = XINT (orig, i);
- break;
+/* Attempt to expand a unary operator. Make the expansion closer to the
+ actual machine, then just general_operand, which will allow 2 separate
+ memory references (one output, one input) in a single insn. Return
+ whether the insn fails, or succeeds. */
- case 's':
- case 'S':
- XSTR (copy, i) = XSTR (orig, i);
- break;
+int
+ix86_expand_unary_operator (code, mode, operands)
+ enum rtx_code code;
+ enum machine_mode mode;
+ rtx operands[];
+{
+ /* If optimizing, copy to regs to improve CSE */
+ if (optimize
+ && ((reload_in_progress | reload_completed) == 0)
+ && GET_CODE (operands[1]) == MEM)
+ operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
- default:
- abort ();
+ if (! ix86_unary_operator_ok (code, mode, operands))
+ {
+ if (optimize == 0
+ && ((reload_in_progress | reload_completed) == 0)
+ && GET_CODE (operands[1]) == MEM)
+ {
+ operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
+ if (! ix86_unary_operator_ok (code, mode, operands))
+ return FALSE;
}
+ else
+ return FALSE;
}
- return copy;
+
+ return TRUE;
}
-
-/* Try to rewrite a memory address to make it valid */
+/* Return TRUE or FALSE depending on whether the unary operator meets the
+ appropriate constraints. */
-void
-rewrite_address (mem_rtx)
- rtx mem_rtx;
+int
+ix86_unary_operator_ok (code, mode, operands)
+ enum rtx_code code ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+ rtx operands[2] ATTRIBUTE_UNUSED;
{
- rtx index_rtx, base_rtx, offset_rtx, scale_rtx, ret_rtx;
- int scale = 1;
- int offset_adjust = 0;
- int was_only_offset = 0;
- rtx mem_addr = XEXP (mem_rtx, 0);
- char *storage = oballoc (0);
- int in_struct = 0;
- int is_spill_rtx = 0;
-
- in_struct = MEM_IN_STRUCT_P (mem_rtx);
- is_spill_rtx = RTX_IS_SPILL_P (mem_rtx);
-
- if (GET_CODE (mem_addr) == PLUS
- && GET_CODE (XEXP (mem_addr, 1)) == PLUS
- && GET_CODE (XEXP (XEXP (mem_addr, 1), 0)) == REG)
- {
- /* This part is utilized by the combiner. */
- ret_rtx
- = gen_rtx (PLUS, GET_MODE (mem_addr),
- gen_rtx (PLUS, GET_MODE (XEXP (mem_addr, 1)),
- XEXP (mem_addr, 0), XEXP (XEXP (mem_addr, 1), 0)),
- XEXP (XEXP (mem_addr, 1), 1));
-
- if (memory_address_p (GET_MODE (mem_rtx), ret_rtx))
- {
- XEXP (mem_rtx, 0) = ret_rtx;
- RTX_IS_SPILL_P (ret_rtx) = is_spill_rtx;
- return;
- }
+ return TRUE;
+}
+
+/* Produce an unsigned comparison for a given signed comparison. */
- obfree (storage);
+static enum rtx_code
+unsigned_comparison (code)
+ enum rtx_code code;
+{
+ switch (code)
+ {
+ case GT:
+ code = GTU;
+ break;
+ case LT:
+ code = LTU;
+ break;
+ case GE:
+ code = GEU;
+ break;
+ case LE:
+ code = LEU;
+ break;
+ case EQ:
+ case NE:
+ case LEU:
+ case LTU:
+ case GEU:
+ case GTU:
+ break;
+ default:
+ abort ();
}
+ return code;
+}
+
+/* Generate insn patterns to do an integer compare of OPERANDS. */
+
+static rtx
+ix86_expand_int_compare (code, op0, op1)
+ enum rtx_code code;
+ rtx op0, op1;
+{
+ enum machine_mode cmpmode;
+ rtx tmp, flags;
- /* This part is utilized by loop.c.
- If the address contains PLUS (reg,const) and this pattern is invalid
- in this case - try to rewrite the address to make it valid. */
- storage = oballoc (0);
- index_rtx = base_rtx = offset_rtx = NULL;
+ cmpmode = SELECT_CC_MODE (code, op0, op1);
+ flags = gen_rtx_REG (cmpmode, FLAGS_REG);
- /* Find the base index and offset elements of the memory address. */
- if (GET_CODE (mem_addr) == PLUS)
+ /* This is very simple, but making the interface the same as in the
+ FP case makes the rest of the code easier. */
+ tmp = gen_rtx_COMPARE (cmpmode, op0, op1);
+ emit_insn (gen_rtx_SET (VOIDmode, flags, tmp));
+
+ /* Return the test that should be put into the flags user, i.e.
+ the bcc, scc, or cmov instruction. */
+ return gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
+}
+
+/* Generate insn patterns to do a floating point compare of OPERANDS.
+ If UNORDERED, allow for unordered compares. */
+
+static rtx
+ix86_expand_fp_compare (code, op0, op1, unordered)
+ enum rtx_code code;
+ rtx op0, op1;
+ int unordered;
+{
+ enum machine_mode fpcmp_mode;
+ enum machine_mode intcmp_mode;
+ rtx tmp;
+
+ /* When not doing IEEE compliant compares, disable unordered. */
+ if (! TARGET_IEEE_FP)
+ unordered = 0;
+ fpcmp_mode = unordered ? CCFPUmode : CCFPmode;
+
+ /* ??? If we knew whether invalid-operand exceptions were masked,
+ we could rely on fcom to raise an exception and take care of
+ NaNs. But we don't. We could know this from c9x math bits. */
+ if (TARGET_IEEE_FP)
+ unordered = 1;
+
+ /* All of the unordered compare instructions only work on registers.
+ The same is true of the XFmode compare instructions. */
+ if (unordered || GET_MODE (op0) == XFmode)
{
- if (GET_CODE (XEXP (mem_addr, 0)) == REG)
+ op0 = force_reg (GET_MODE (op0), op0);
+ op1 = force_reg (GET_MODE (op1), op1);
+ }
+ else
+ {
+ /* %%% We only allow op1 in memory; op0 must be st(0). So swap
+ things around if they appear profitable, otherwise force op0
+ into a register. */
+
+ if (standard_80387_constant_p (op0) == 0
+ || (GET_CODE (op0) == MEM
+ && ! (standard_80387_constant_p (op1) == 0
+ || GET_CODE (op1) == MEM)))
{
- if (GET_CODE (XEXP (mem_addr, 1)) == REG)
- base_rtx = XEXP (mem_addr, 1), index_rtx = XEXP (mem_addr, 0);
- else
- base_rtx = XEXP (mem_addr, 0), offset_rtx = XEXP (mem_addr, 1);
+ rtx tmp;
+ tmp = op0, op0 = op1, op1 = tmp;
+ code = swap_condition (code);
}
- else if (GET_CODE (XEXP (mem_addr, 0)) == MULT)
+ if (GET_CODE (op0) != REG)
+ op0 = force_reg (GET_MODE (op0), op0);
+
+ if (CONSTANT_P (op1))
{
- index_rtx = XEXP (mem_addr, 0);
- if (GET_CODE (XEXP (mem_addr, 1)) == REG)
- base_rtx = XEXP (mem_addr, 1);
+ if (standard_80387_constant_p (op1))
+ op1 = force_reg (GET_MODE (op1), op1);
else
- offset_rtx = XEXP (mem_addr, 1);
+ op1 = validize_mem (force_const_mem (GET_MODE (op1), op1));
}
+ }
+
+ /* %%% fcomi is probably always faster, even when dealing with memory,
+ since compare-and-branch would be three insns instead of four. */
+ if (TARGET_CMOVE && !unordered)
+ {
+ if (GET_CODE (op0) != REG)
+ op0 = force_reg (GET_MODE (op0), op0);
+ if (GET_CODE (op1) != REG)
+ op1 = force_reg (GET_MODE (op1), op1);
- else if (GET_CODE (XEXP (mem_addr, 0)) == PLUS)
+ tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
+ tmp = gen_rtx_SET (VOIDmode, gen_rtx_REG (fpcmp_mode, FLAGS_REG), tmp);
+ emit_insn (tmp);
+
+ /* The FP codes work out to act like unsigned. */
+ code = unsigned_comparison (code);
+ intcmp_mode = fpcmp_mode;
+ }
+ else
+ {
+ /* Sadness wrt reg-stack pops killing fpsr -- gotta get fnstsw first. */
+
+ rtx tmp2;
+ tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
+ tmp2 = gen_rtx_UNSPEC (HImode, gen_rtvec (1, tmp), 9);
+ tmp = gen_reg_rtx (HImode);
+ emit_insn (gen_rtx_SET (VOIDmode, tmp, tmp2));
+
+ if (! unordered)
{
- if (GET_CODE (XEXP (XEXP (mem_addr, 0), 0)) == PLUS
- && GET_CODE (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0)) == MULT
- && (GET_CODE (XEXP (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0), 0))
- == REG)
- && (GET_CODE (XEXP (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0), 1))
- == CONST_INT)
- && (GET_CODE (XEXP (XEXP (XEXP (mem_addr, 0), 0), 1))
- == CONST_INT)
- && GET_CODE (XEXP (XEXP (mem_addr, 0), 1)) == REG
- && GET_CODE (XEXP (mem_addr, 1)) == SYMBOL_REF)
+ /* We have two options here -- use sahf, or testing bits of ah
+ directly. On PPRO, they are equivalent, sahf being one byte
+ smaller. On Pentium, sahf is non-pairable while test is UV
+ pairable. */
+
+ if (TARGET_USE_SAHF || optimize_size)
{
- index_rtx = XEXP (XEXP (XEXP (mem_addr, 0), 0), 0);
- offset_rtx = XEXP (mem_addr, 1);
- base_rtx = XEXP (XEXP (mem_addr, 0), 1);
- offset_adjust = INTVAL (XEXP (XEXP (XEXP (mem_addr, 0), 0), 1));
+ do_sahf:
+
+ /* The FP codes work out to act like unsigned. */
+ code = unsigned_comparison (code);
+ emit_insn (gen_x86_sahf_1 (tmp));
+ intcmp_mode = CCmode;
}
else
{
- offset_rtx = XEXP (mem_addr, 1);
- index_rtx = XEXP (XEXP (mem_addr, 0), 0);
- base_rtx = XEXP (XEXP (mem_addr, 0), 1);
- }
- }
+ /*
+ * The numbers below correspond to the bits of the FPSW in AH.
+ * C3, C2, and C0 are in bits 0x40, 0x40, and 0x01 respectively.
+ *
+ * cmp C3 C2 C0
+ * > 0 0 0
+ * < 0 0 1
+ * = 1 0 0
+ * un 1 1 1
+ */
+
+ int mask;
+
+ switch (code)
+ {
+ case GT:
+ mask = 0x01;
+ code = EQ;
+ break;
+ case LT:
+ mask = 0x01;
+ code = NE;
+ break;
+ case GE:
+ /* We'd have to use `xorb 1,ah; andb 0x41,ah', so it's
+ faster in all cases to just fall back on sahf. */
+ goto do_sahf;
+ case LE:
+ mask = 0x41;
+ code = NE;
+ break;
+ case EQ:
+ mask = 0x40;
+ code = NE;
+ break;
+ case NE:
+ mask = 0x40;
+ code = EQ;
+ break;
+ default:
+ abort ();
+ }
- else if (GET_CODE (XEXP (mem_addr, 0)) == CONST_INT)
- {
- was_only_offset = 1;
- index_rtx = NULL;
- base_rtx = NULL;
- offset_rtx = XEXP (mem_addr, 1);
- offset_adjust = INTVAL (XEXP (mem_addr, 0));
- if (offset_adjust == 0)
- {
- XEXP (mem_rtx, 0) = offset_rtx;
- RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx;
- return;
+ emit_insn (gen_testqi_ext_0 (tmp, GEN_INT (mask)));
+ intcmp_mode = CCNOmode;
}
}
else
{
- obfree (storage);
- return;
+ /* In the unordered case, we have to check C2 for NaN's, which
+ doesn't happen to work out to anything nice combination-wise.
+ So do some bit twiddling on the value we've got in AH to come
+ up with an appropriate set of condition codes. */
+
+ intcmp_mode = CCNOmode;
+ switch (code)
+ {
+ case GT:
+ emit_insn (gen_testqi_ext_0 (tmp, GEN_INT (0x45)));
+ code = EQ;
+ break;
+ case LT:
+ emit_insn (gen_andqi_ext_0 (tmp, tmp, GEN_INT (0x45)));
+ emit_insn (gen_cmpqi_ext_3 (tmp, GEN_INT (0x01)));
+ intcmp_mode = CCmode;
+ code = EQ;
+ break;
+ case GE:
+ emit_insn (gen_testqi_ext_0 (tmp, GEN_INT (0x05)));
+ code = EQ;
+ break;
+ case LE:
+ emit_insn (gen_andqi_ext_0 (tmp, tmp, GEN_INT (0x45)));
+ emit_insn (gen_addqi_ext_1 (tmp, tmp, constm1_rtx));
+ emit_insn (gen_cmpqi_ext_3 (tmp, GEN_INT (0x40)));
+ intcmp_mode = CCmode;
+ code = LTU;
+ break;
+ case EQ:
+ emit_insn (gen_andqi_ext_0 (tmp, tmp, GEN_INT (0x45)));
+ emit_insn (gen_cmpqi_ext_3 (tmp, GEN_INT (0x40)));
+ intcmp_mode = CCmode;
+ code = EQ;
+ break;
+ case NE:
+ emit_insn (gen_andqi_ext_0 (tmp, tmp, GEN_INT (0x45)));
+ emit_insn (gen_xorcqi_ext_1 (tmp, tmp, GEN_INT (0x40)));
+ code = NE;
+ break;
+ default:
+ abort ();
+ }
}
}
- else if (GET_CODE (mem_addr) == MULT)
- index_rtx = mem_addr;
+
+ /* Return the test that should be put into the flags user, i.e.
+ the bcc, scc, or cmov instruction. */
+ return gen_rtx_fmt_ee (code, VOIDmode,
+ gen_rtx_REG (intcmp_mode, FLAGS_REG),
+ const0_rtx);
+}
+
+static rtx
+ix86_expand_compare (code, unordered)
+ enum rtx_code code;
+ int unordered;
+{
+ rtx op0, op1, ret;
+ op0 = ix86_compare_op0;
+ op1 = ix86_compare_op1;
+
+ if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
+ ret = ix86_expand_fp_compare (code, op0, op1, unordered);
else
+ ret = ix86_expand_int_compare (code, op0, op1);
+
+ return ret;
+}
+
+void
+ix86_expand_branch (code, unordered, label)
+ enum rtx_code code;
+ int unordered;
+ rtx label;
+{
+ rtx tmp, lo[2], hi[2], label2;
+ enum rtx_code code1, code2, code3;
+
+ if (GET_MODE (ix86_compare_op0) != DImode)
{
- obfree (storage);
+ tmp = ix86_expand_compare (code, unordered);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode, label),
+ pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
return;
}
- if (index_rtx != 0 && GET_CODE (index_rtx) == MULT)
- {
- if (GET_CODE (XEXP (index_rtx, 1)) != CONST_INT)
- {
- obfree (storage);
- return;
- }
+ /* Expand DImode branch into multiple compare+branch. */
- scale_rtx = XEXP (index_rtx, 1);
- scale = INTVAL (scale_rtx);
- index_rtx = copy_all_rtx (XEXP (index_rtx, 0));
+ if (CONSTANT_P (ix86_compare_op0) && ! CONSTANT_P (ix86_compare_op1))
+ {
+ tmp = ix86_compare_op0;
+ ix86_compare_op0 = ix86_compare_op1;
+ ix86_compare_op1 = tmp;
+ code = swap_condition (code);
}
+ split_di (&ix86_compare_op0, 1, lo+0, hi+0);
+ split_di (&ix86_compare_op1, 1, lo+1, hi+1);
- /* Now find which of the elements are invalid and try to fix them. */
- if (index_rtx && GET_CODE (index_rtx) == CONST_INT && base_rtx == NULL)
+ /* When comparing for equality, we can use (hi0^hi1)|(lo0^lo1) to avoid
+ two branches. This costs one extra insn, so disable when optimizing
+ for size. */
+
+ if ((code == EQ || code == NE)
+ && (!optimize_size
+ || hi[1] == const0_rtx || lo[1] == const0_rtx))
{
- offset_adjust = INTVAL (index_rtx) * scale;
+ rtx xor0, xor1;
- if (offset_rtx != 0 && CONSTANT_P (offset_rtx))
- offset_rtx = plus_constant (offset_rtx, offset_adjust);
- else if (offset_rtx == 0)
- offset_rtx = const0_rtx;
+ xor1 = hi[0];
+ if (hi[1] != const0_rtx)
+ {
+ xor1 = expand_binop (SImode, xor_optab, xor1, hi[1],
+ NULL_RTX, 0, OPTAB_WIDEN);
+ }
- RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx;
- XEXP (mem_rtx, 0) = offset_rtx;
+ xor0 = lo[0];
+ if (lo[1] != const0_rtx)
+ {
+ xor0 = expand_binop (SImode, xor_optab, xor0, lo[1],
+ NULL_RTX, 0, OPTAB_WIDEN);
+ }
+
+ tmp = expand_binop (SImode, ior_optab, xor1, xor0,
+ NULL_RTX, 0, OPTAB_WIDEN);
+
+ ix86_compare_op0 = tmp;
+ ix86_compare_op1 = const0_rtx;
+ ix86_expand_branch (code, unordered, label);
return;
}
- if (base_rtx && GET_CODE (base_rtx) == PLUS
- && GET_CODE (XEXP (base_rtx, 0)) == REG
- && GET_CODE (XEXP (base_rtx, 1)) == CONST_INT)
+ /* Otherwise, if we are doing less-than, op1 is a constant and the
+ low word is zero, then we can just examine the high word. */
+
+ if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
+ && (code == LT || code == LTU))
{
- offset_adjust += INTVAL (XEXP (base_rtx, 1));
- base_rtx = copy_all_rtx (XEXP (base_rtx, 0));
+ ix86_compare_op0 = hi[0];
+ ix86_compare_op1 = hi[1];
+ ix86_expand_branch (code, unordered, label);
+ return;
}
- else if (base_rtx && GET_CODE (base_rtx) == CONST_INT)
+ /* Otherwise, we need two or three jumps. */
+
+ label2 = gen_label_rtx ();
+
+ code1 = code;
+ code2 = swap_condition (code);
+ code3 = unsigned_condition (code);
+
+ switch (code)
{
- offset_adjust += INTVAL (base_rtx);
- base_rtx = NULL;
+ case LT: case GT: case LTU: case GTU:
+ break;
+
+ case LE: code1 = LT; code2 = GT; break;
+ case GE: code1 = GT; code2 = LT; break;
+ case LEU: code1 = LTU; code2 = GTU; break;
+ case GEU: code1 = GTU; code2 = LTU; break;
+
+ case EQ: code1 = NIL; code2 = NE; break;
+ case NE: code2 = NIL; break;
+
+ default:
+ abort ();
}
- if (index_rtx && GET_CODE (index_rtx) == PLUS
- && GET_CODE (XEXP (index_rtx, 0)) == REG
- && GET_CODE (XEXP (index_rtx, 1)) == CONST_INT)
+ /*
+ * a < b =>
+ * if (hi(a) < hi(b)) goto true;
+ * if (hi(a) > hi(b)) goto false;
+ * if (lo(a) < lo(b)) goto true;
+ * false:
+ */
+
+ ix86_compare_op0 = hi[0];
+ ix86_compare_op1 = hi[1];
+
+ if (code1 != NIL)
+ ix86_expand_branch (code1, unordered, label);
+ if (code2 != NIL)
+ ix86_expand_branch (code2, unordered, label2);
+
+ ix86_compare_op0 = lo[0];
+ ix86_compare_op1 = lo[1];
+ ix86_expand_branch (code3, unordered, label);
+
+ if (code2 != NIL)
+ emit_label (label2);
+}
+
+int
+ix86_expand_setcc (code, unordered, dest)
+ enum rtx_code code;
+ int unordered;
+ rtx dest;
+{
+ rtx ret, tmp;
+ int type;
+
+ if (GET_MODE (ix86_compare_op0) == DImode)
+ return 0; /* FAIL */
+
+ /* Three modes of generation:
+ 0 -- destination does not overlap compare sources:
+ clear dest first, emit strict_low_part setcc.
+ 1 -- destination does overlap compare sources:
+ emit subreg setcc, zero extend.
+ 2 -- destination is in QImode:
+ emit setcc only.
+ */
+
+ type = 0;
+ /* %%% reload problems with in-out. Revisit. */
+ type = 1;
+
+ if (GET_MODE (dest) == QImode)
+ type = 2;
+ else if (reg_overlap_mentioned_p (dest, ix86_compare_op0)
+ || reg_overlap_mentioned_p (dest, ix86_compare_op0))
+ type = 1;
+
+ if (type == 0)
+ emit_move_insn (dest, const0_rtx);
+
+ ret = ix86_expand_compare (code, unordered);
+ PUT_MODE (ret, QImode);
+
+ tmp = dest;
+ if (type == 0)
{
- offset_adjust += INTVAL (XEXP (index_rtx, 1)) * scale;
- index_rtx = copy_all_rtx (XEXP (index_rtx, 0));
+ tmp = gen_lowpart (QImode, dest);
+ tmp = gen_rtx_STRICT_LOW_PART (VOIDmode, tmp);
}
+ else if (type == 1)
+ {
+ if (!cse_not_expected)
+ tmp = gen_reg_rtx (QImode);
+ else
+ tmp = gen_lowpart (QImode, dest);
+ }
+
+ emit_insn (gen_rtx_SET (VOIDmode, tmp, ret));
- if (index_rtx)
+ if (type == 1)
{
- if (! LEGITIMATE_INDEX_P (index_rtx)
- && ! (index_rtx == stack_pointer_rtx && scale == 1
- && base_rtx == NULL))
- {
- obfree (storage);
- return;
- }
+ rtx clob;
+
+ tmp = gen_rtx_ZERO_EXTEND (GET_MODE (dest), tmp);
+ tmp = gen_rtx_SET (VOIDmode, dest, tmp);
+ clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
+ tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob));
+ emit_insn (tmp);
}
- if (base_rtx)
+ return 1; /* DONE */
+}
+
+int
+ix86_expand_int_movcc (operands)
+ rtx operands[];
+{
+ enum rtx_code code = GET_CODE (operands[1]), compare_code;
+ rtx compare_seq, compare_op;
+
+ start_sequence ();
+ compare_op = ix86_expand_compare (code, code == EQ || code == NE);
+ compare_seq = gen_sequence ();
+ end_sequence ();
+
+ compare_code = GET_CODE (compare_op);
+
+ /* Don't attempt mode expansion here -- if we had to expand 5 or 6
+ HImode insns, we'd be swallowed in word prefix ops. */
+
+ if (GET_MODE (operands[0]) != HImode
+ && GET_CODE (operands[2]) == CONST_INT
+ && GET_CODE (operands[3]) == CONST_INT)
{
- if (! LEGITIMATE_INDEX_P (base_rtx) && GET_CODE (base_rtx) != REG)
+ rtx out = operands[0];
+ HOST_WIDE_INT ct = INTVAL (operands[2]);
+ HOST_WIDE_INT cf = INTVAL (operands[3]);
+ HOST_WIDE_INT diff;
+
+ /* Special cases: */
+ if (ct == 0)
{
- obfree (storage);
- return;
+ ct = cf;
+ cf = 0;
+ compare_code = reverse_condition (compare_code);
+ code = reverse_condition (code);
}
- }
+ if (cf == 0 && ct == -1 && (compare_code == LTU || compare_code == GEU))
+ {
+ /*
+ * xorl dest,dest
+ * cmpl op0,op1
+ * sbbl dest,dest
+ *
+ * Size 6.
+ */
- if (offset_adjust != 0)
- {
- if (offset_rtx != 0 && CONSTANT_P (offset_rtx))
- offset_rtx = plus_constant (offset_rtx, offset_adjust);
- else
- offset_rtx = const0_rtx;
+ /* Detect overlap between destination and compare sources. */
+ rtx tmp = out;
+
+ if (reg_overlap_mentioned_p (out, ix86_compare_op0)
+ || reg_overlap_mentioned_p (out, ix86_compare_op0))
+ tmp = gen_reg_rtx (SImode);
+
+ emit_insn (compare_seq);
+ emit_insn (gen_x86_movsicc_0_m1 (tmp));
+
+ if (compare_code == GEU)
+ emit_insn (gen_one_cmplsi2 (tmp, tmp));
- if (index_rtx)
+ if (tmp != out)
+ emit_move_insn (out, tmp);
+
+ return 1; /* DONE */
+ }
+
+ diff = ct - cf;
+ if (diff < 0)
{
- if (base_rtx)
+ HOST_WIDE_INT tmp;
+ tmp = ct, ct = cf, cf = tmp;
+ diff = -diff;
+ compare_code = reverse_condition (compare_code);
+ code = reverse_condition (code);
+ }
+ if (diff == 1 || diff == 2 || diff == 4 || diff == 8
+ || diff == 3 || diff == 5 || diff == 9)
+ {
+ /*
+ * xorl dest,dest
+ * cmpl op1,op2
+ * setcc dest
+ * lea cf(dest*(ct-cf)),dest
+ *
+ * Size 14.
+ *
+ * This also catches the degenerate setcc-only case.
+ */
+
+ rtx tmp;
+ int nops;
+
+ out = emit_store_flag (out, code, ix86_compare_op0,
+ ix86_compare_op1, VOIDmode, 0, 1);
+
+ nops = 0;
+ if (diff == 1)
+ tmp = out;
+ else
{
- if (scale != 1)
+ tmp = gen_rtx_MULT (SImode, out, GEN_INT (diff & ~1));
+ nops++;
+ if (diff & 1)
{
- ret_rtx = gen_rtx (PLUS, GET_MODE (base_rtx),
- gen_rtx (MULT, GET_MODE (index_rtx),
- index_rtx, scale_rtx),
- base_rtx);
-
- if (GET_CODE (offset_rtx) != CONST_INT
- || INTVAL (offset_rtx) != 0)
- ret_rtx = gen_rtx (PLUS, GET_MODE (ret_rtx),
- ret_rtx, offset_rtx);
- }
- else
- {
- ret_rtx = gen_rtx (PLUS, GET_MODE (index_rtx),
- index_rtx, base_rtx);
-
- if (GET_CODE (offset_rtx) != CONST_INT
- || INTVAL (offset_rtx) != 0)
- ret_rtx = gen_rtx (PLUS, GET_MODE (ret_rtx),
- ret_rtx, offset_rtx);
+ tmp = gen_rtx_PLUS (SImode, tmp, out);
+ nops++;
}
}
- else
+ if (cf != 0)
{
- if (scale != 1)
+ tmp = gen_rtx_PLUS (SImode, tmp, GEN_INT (cf));
+ nops++;
+ }
+ if (tmp != out)
+ {
+ if (nops == 0)
+ emit_move_insn (out, tmp);
+ else if (nops == 1)
{
- ret_rtx = gen_rtx (MULT, GET_MODE (index_rtx),
- index_rtx, scale_rtx);
+ rtx clob;
- if (GET_CODE (offset_rtx) != CONST_INT
- || INTVAL (offset_rtx) != 0)
- ret_rtx = gen_rtx (PLUS, GET_MODE (ret_rtx),
- ret_rtx, offset_rtx);
+ clob = gen_rtx_REG (CCmode, FLAGS_REG);
+ clob = gen_rtx_CLOBBER (VOIDmode, clob);
+
+ tmp = gen_rtx_SET (VOIDmode, out, tmp);
+ tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob));
+ emit_insn (tmp);
}
else
- {
- if (GET_CODE (offset_rtx) == CONST_INT
- && INTVAL (offset_rtx) == 0)
- ret_rtx = index_rtx;
- else
- ret_rtx = gen_rtx (PLUS, GET_MODE (index_rtx),
- index_rtx, offset_rtx);
- }
+ emit_insn (gen_rtx_SET (VOIDmode, out, tmp));
}
+ if (out != operands[0])
+ emit_move_insn (operands[0], out);
+
+ return 1; /* DONE */
}
- else
+
+ /*
+ * General case: Jumpful:
+ * xorl dest,dest cmpl op1, op2
+ * cmpl op1, op2 movl ct, dest
+ * setcc dest jcc 1f
+ * decl dest movl cf, dest
+ * andl (cf-ct),dest 1:
+ * addl ct,dest
+ *
+ * Size 20. Size 14.
+ *
+ * This is reasonably steep, but branch mispredict costs are
+ * high on modern cpus, so consider failing only if optimizing
+ * for space.
+ *
+ * %%% Parameterize branch_cost on the tuning architecture, then
+ * use that. The 80386 couldn't care less about mispredicts.
+ */
+
+ if (!optimize_size && !TARGET_CMOVE)
{
- if (base_rtx)
+ if (ct == 0)
{
- if (GET_CODE (offset_rtx) == CONST_INT
- && INTVAL (offset_rtx) == 0)
- ret_rtx = base_rtx;
- else
- ret_rtx = gen_rtx (PLUS, GET_MODE (base_rtx), base_rtx,
- offset_rtx);
- }
- else if (was_only_offset)
- ret_rtx = offset_rtx;
- else
- {
- obfree (storage);
- return;
+ ct = cf;
+ cf = 0;
+ compare_code = reverse_condition (compare_code);
+ code = reverse_condition (code);
}
- }
- XEXP (mem_rtx, 0) = ret_rtx;
- RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx;
- return;
- }
- else
- {
- obfree (storage);
- return;
+ out = emit_store_flag (out, code, ix86_compare_op0,
+ ix86_compare_op1, VOIDmode, 0, 1);
+
+ emit_insn (gen_addsi3 (out, out, constm1_rtx));
+ emit_insn (gen_andsi3 (out, out, GEN_INT (cf-ct)));
+ if (ct != 0)
+ emit_insn (gen_addsi3 (out, out, GEN_INT (ct)));
+ if (out != operands[0])
+ emit_move_insn (operands[0], out);
+
+ return 1; /* DONE */
+ }
}
-}
-#endif /* NOTYET */
-
-/* Return 1 if the first insn to set cc before INSN also sets the register
- REG_RTX; otherwise return 0. */
-int
-last_to_set_cc (reg_rtx, insn)
- rtx reg_rtx, insn;
-{
- rtx prev_insn = PREV_INSN (insn);
- while (prev_insn)
+ if (!TARGET_CMOVE)
{
- if (GET_CODE (prev_insn) == NOTE)
- ;
+ /* Try a few things more with specific constants and a variable. */
- else if (GET_CODE (prev_insn) == INSN)
- {
- if (GET_CODE (PATTERN (prev_insn)) != SET)
- return (0);
+ optab op = NULL;
+ rtx var, orig_out, out, tmp;
- if (rtx_equal_p (SET_DEST (PATTERN (prev_insn)), reg_rtx))
- {
- if (sets_condition_code (SET_SRC (PATTERN (prev_insn))))
- return (1);
+ if (optimize_size)
+ return 0; /* FAIL */
- return (0);
- }
-
- else if (! doesnt_set_condition_code (SET_SRC (PATTERN (prev_insn))))
- return (0);
+ /* If one of the two operands is an interesting constant, load a
+ constant with the above and mask it in with a logical operation. */
+
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ var = operands[3];
+ if (INTVAL (operands[2]) == 0)
+ operands[3] = constm1_rtx, op = and_optab;
+ else if (INTVAL (operands[2]) == -1)
+ operands[3] = const0_rtx, op = ior_optab;
+ }
+ else if (GET_CODE (operands[3]) == CONST_INT)
+ {
+ var = operands[2];
+ if (INTVAL (operands[3]) == 0)
+ operands[2] = constm1_rtx, op = and_optab;
+ else if (INTVAL (operands[3]) == -1)
+ operands[2] = const0_rtx, op = ior_optab;
}
- else
- return (0);
-
- prev_insn = PREV_INSN (prev_insn);
- }
-
- return (0);
+ if (op == NULL)
+ return 0; /* FAIL */
+
+ orig_out = operands[0];
+ tmp = gen_reg_rtx (GET_MODE (orig_out));
+ operands[0] = tmp;
+
+ /* Recurse to get the constant loaded. */
+ if (ix86_expand_int_movcc (operands) == 0)
+ return 0; /* FAIL */
+
+ /* Mask in the interesting variable. */
+ out = expand_binop (GET_MODE (orig_out), op, var, tmp, orig_out, 0,
+ OPTAB_WIDEN);
+ if (out != orig_out)
+ emit_move_insn (orig_out, out);
+
+ return 1; /* DONE */
+ }
+
+ /*
+ * For comparison with above,
+ *
+ * movl cf,dest
+ * movl ct,tmp
+ * cmpl op1,op2
+ * cmovcc tmp,dest
+ *
+ * Size 15.
+ */
+
+ if (! nonimmediate_operand (operands[2], GET_MODE (operands[0])))
+ operands[2] = force_reg (GET_MODE (operands[0]), operands[2]);
+ if (! nonimmediate_operand (operands[3], GET_MODE (operands[0])))
+ operands[3] = force_reg (GET_MODE (operands[0]), operands[3]);
+
+ emit_insn (compare_seq);
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
+ compare_op, operands[2],
+ operands[3])));
+
+ return 1; /* DONE */
}
-
+
int
-doesnt_set_condition_code (pat)
- rtx pat;
+ix86_expand_fp_movcc (operands)
+ rtx operands[];
{
- switch (GET_CODE (pat))
+ enum rtx_code code;
+ enum machine_mode mode;
+ rtx tmp;
+
+ /* The floating point conditional move instructions don't directly
+ support conditions resulting from a signed integer comparison. */
+
+ code = GET_CODE (operands[1]);
+ switch (code)
{
- case MEM:
- case REG:
- return 1;
+ case LT:
+ case LE:
+ case GE:
+ case GT:
+ tmp = gen_reg_rtx (QImode);
+ ix86_expand_setcc (code, 0, tmp);
+ code = NE;
+ ix86_compare_op0 = tmp;
+ ix86_compare_op1 = const0_rtx;
+ break;
default:
- return 0;
-
+ break;
}
+
+ mode = SELECT_CC_MODE (code, ix86_compare_op0, ix86_compare_op1);
+ emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, FLAGS_REG),
+ gen_rtx_COMPARE (mode,
+ ix86_compare_op0,
+ ix86_compare_op1)));
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
+ gen_rtx_fmt_ee (code, VOIDmode,
+ gen_rtx_REG (mode, FLAGS_REG),
+ const0_rtx),
+ operands[2],
+ operands[3])));
+
+ return 1;
}
-
+
int
-sets_condition_code (pat)
- rtx pat;
+ix86_split_movdi (operands)
+ rtx operands[];
{
- switch (GET_CODE (pat))
+ split_di (operands+0, 1, operands+2, operands+3);
+ split_di (operands+1, 1, operands+4, operands+5);
+ if (reg_overlap_mentioned_p (operands[2], operands[1]))
{
- case PLUS:
- case MINUS:
- case AND:
- case IOR:
- case XOR:
- case NOT:
- case NEG:
- case MULT:
- case DIV:
- case MOD:
- case UDIV:
- case UMOD:
- return 1;
+ rtx tmp;
+ if (!reg_overlap_mentioned_p (operands[3], operands[4]))
+ {
+ tmp = operands[2], operands[2] = operands[3], operands[3] = tmp;
+ tmp = operands[4], operands[4] = operands[5], operands[5] = tmp;
+ }
+ else
+ {
+ emit_insn (gen_push (operands[4]));
+ emit_insn (gen_rtx_SET (VOIDmode, operands[3], operands[5]));
+ emit_insn (gen_popsi1 (operands[2]));
- default:
- return (0);
+ return 1; /* DONE */
+ }
}
-}
-
-int
-str_immediate_operand (op, mode)
- register rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
-{
- if (GET_CODE (op) == CONST_INT && INTVAL (op) <= 32 && INTVAL (op) >= 0)
- return 1;
return 0;
}
-
-int
-is_fp_insn (insn)
- rtx insn;
+
+void
+ix86_split_ashldi (operands, scratch)
+ rtx *operands, scratch;
{
- if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
- && (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode
- || GET_MODE (SET_DEST (PATTERN (insn))) == SFmode
- || GET_MODE (SET_DEST (PATTERN (insn))) == XFmode))
- return 1;
+ rtx low[2], high[2];
+ int count;
- return 0;
-}
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ split_di (operands, 2, low, high);
+ count = INTVAL (operands[2]) & 63;
-/* Return 1 if the mode of the SET_DEST of insn is floating point
- and it is not an fld or a move from memory to memory.
- Otherwise return 0 */
+ if (count >= 32)
+ {
+ emit_move_insn (high[0], low[1]);
+ emit_move_insn (low[0], const0_rtx);
-int
-is_fp_dest (insn)
- rtx insn;
-{
- if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
- && (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode
- || GET_MODE (SET_DEST (PATTERN (insn))) == SFmode
- || GET_MODE (SET_DEST (PATTERN (insn))) == XFmode)
- && GET_CODE (SET_DEST (PATTERN (insn))) == REG
- && REGNO (SET_DEST (PATTERN (insn))) >= FIRST_FLOAT_REG
- && GET_CODE (SET_SRC (PATTERN (insn))) != MEM)
- return 1;
+ if (count > 32)
+ emit_insn (gen_ashlsi3 (high[0], high[0], GEN_INT (count - 32)));
+ }
+ else
+ {
+ if (!rtx_equal_p (operands[0], operands[1]))
+ emit_move_insn (operands[0], operands[1]);
+ emit_insn (gen_x86_shld_1 (high[0], low[0], GEN_INT (count)));
+ emit_insn (gen_ashlsi3 (low[0], low[0], GEN_INT (count)));
+ }
+ }
+ else
+ {
+ if (!rtx_equal_p (operands[0], operands[1]))
+ emit_move_insn (operands[0], operands[1]);
- return 0;
-}
+ split_di (operands, 1, low, high);
-/* Return 1 if the mode of the SET_DEST of INSN is floating point and is
- memory and the source is a register. */
+ emit_insn (gen_x86_shld_1 (high[0], low[0], operands[2]));
+ emit_insn (gen_ashlsi3 (low[0], low[0], operands[2]));
-int
-is_fp_store (insn)
- rtx insn;
-{
- if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
- && (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode
- || GET_MODE (SET_DEST (PATTERN (insn))) == SFmode
- || GET_MODE (SET_DEST (PATTERN (insn))) == XFmode)
- && GET_CODE (SET_DEST (PATTERN (insn))) == MEM
- && GET_CODE (SET_SRC (PATTERN (insn))) == REG)
- return 1;
+ if (TARGET_CMOVE && (! reload_completed || scratch))
+ {
+ if (! reload_completed)
+ scratch = force_reg (SImode, const0_rtx);
+ else
+ emit_move_insn (scratch, const0_rtx);
- return 0;
+ emit_insn (gen_x86_shift_adj_1 (high[0], low[0], operands[2],
+ scratch));
+ }
+ else
+ emit_insn (gen_x86_shift_adj_2 (high[0], low[0], operands[2]));
+ }
}
-
-/* Return 1 if DEP_INSN sets a register which INSN uses as a base
- or index to reference memory.
- otherwise return 0 */
-int
-agi_dependent (insn, dep_insn)
- rtx insn, dep_insn;
+void
+ix86_split_ashrdi (operands, scratch)
+ rtx *operands, scratch;
{
- int push = 0, push_dep = 0;
- if (GET_CODE (dep_insn) == INSN
- && GET_CODE (PATTERN (dep_insn)) == SET
- && GET_CODE (SET_DEST (PATTERN (dep_insn))) == REG
- && reg_mentioned_in_mem (SET_DEST (PATTERN (dep_insn)), insn))
- return 1;
+ rtx low[2], high[2];
+ int count;
- if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
- && GET_CODE (SET_DEST (PATTERN (insn))) == MEM
- && push_operand (SET_DEST (PATTERN (insn)),
- GET_MODE (SET_DEST (PATTERN (insn)))))
- push = 1;
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ split_di (operands, 2, low, high);
+ count = INTVAL (operands[2]) & 63;
- if (GET_CODE (dep_insn) == INSN && GET_CODE (PATTERN (dep_insn)) == SET
- && GET_CODE (SET_DEST (PATTERN (dep_insn))) == MEM
- && push_operand (SET_DEST (PATTERN (dep_insn)),
- GET_MODE (SET_DEST (PATTERN (dep_insn)))))
- push_dep = 1;
+ if (count >= 32)
+ {
+ emit_move_insn (low[0], high[1]);
- /* CPUs contain special hardware to allow two pushes. */
- if (push && push_dep)
- return 0;
+ if (! reload_completed)
+ emit_insn (gen_ashrsi3 (high[0], low[0], GEN_INT (31)));
+ else
+ {
+ emit_move_insn (high[0], low[0]);
+ emit_insn (gen_ashrsi3 (high[0], high[0], GEN_INT (31)));
+ }
- /* Push operation implicitly change stack pointer causing AGI stalls. */
- if (push_dep && reg_mentioned_in_mem (stack_pointer_rtx, insn))
- return 1;
+ if (count > 32)
+ emit_insn (gen_ashrsi3 (low[0], low[0], GEN_INT (count - 32)));
+ }
+ else
+ {
+ if (!rtx_equal_p (operands[0], operands[1]))
+ emit_move_insn (operands[0], operands[1]);
+ emit_insn (gen_x86_shrd_1 (low[0], high[0], GEN_INT (count)));
+ emit_insn (gen_ashrsi3 (high[0], high[0], GEN_INT (count)));
+ }
+ }
+ else
+ {
+ if (!rtx_equal_p (operands[0], operands[1]))
+ emit_move_insn (operands[0], operands[1]);
- /* Push also implicitly read stack pointer. */
- if (push && modified_in_p (stack_pointer_rtx, dep_insn))
- return 1;
+ split_di (operands, 1, low, high);
- return 0;
+ emit_insn (gen_x86_shrd_1 (low[0], high[0], operands[2]));
+ emit_insn (gen_ashrsi3 (high[0], high[0], operands[2]));
+
+ if (TARGET_CMOVE && (!reload_completed || scratch))
+ {
+ if (! reload_completed)
+ scratch = gen_reg_rtx (SImode);
+ emit_move_insn (scratch, high[0]);
+ emit_insn (gen_ashrsi3 (scratch, scratch, GEN_INT (31)));
+ emit_insn (gen_x86_shift_adj_1 (low[0], high[0], operands[2],
+ scratch));
+ }
+ else
+ emit_insn (gen_x86_shift_adj_3 (low[0], high[0], operands[2]));
+ }
}
-
-/* Return 1 if reg is used in rtl as a base or index for a memory ref
- otherwise return 0. */
-int
-reg_mentioned_in_mem (reg, rtl)
- rtx reg, rtl;
+void
+ix86_split_lshrdi (operands, scratch)
+ rtx *operands, scratch;
{
- register const char *fmt;
- register int i, j;
- register enum rtx_code code;
+ rtx low[2], high[2];
+ int count;
- if (rtl == NULL)
- return 0;
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ split_di (operands, 2, low, high);
+ count = INTVAL (operands[2]) & 63;
- code = GET_CODE (rtl);
+ if (count >= 32)
+ {
+ emit_move_insn (low[0], high[1]);
+ emit_move_insn (high[0], const0_rtx);
- switch (code)
- {
- case HIGH:
- case CONST_INT:
- case CONST:
- case CONST_DOUBLE:
- case SYMBOL_REF:
- case LABEL_REF:
- case PC:
- case CC0:
- case SUBREG:
- return 0;
- default:
- break;
+ if (count > 32)
+ emit_insn (gen_lshrsi3 (low[0], low[0], GEN_INT (count - 32)));
+ }
+ else
+ {
+ if (!rtx_equal_p (operands[0], operands[1]))
+ emit_move_insn (operands[0], operands[1]);
+ emit_insn (gen_x86_shrd_1 (low[0], high[0], GEN_INT (count)));
+ emit_insn (gen_lshrsi3 (high[0], high[0], GEN_INT (count)));
+ }
}
+ else
+ {
+ if (!rtx_equal_p (operands[0], operands[1]))
+ emit_move_insn (operands[0], operands[1]);
- if (code == MEM && reg_mentioned_p (reg, rtl))
- return 1;
+ split_di (operands, 1, low, high);
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'E')
+ emit_insn (gen_x86_shrd_1 (low[0], high[0], operands[2]));
+ emit_insn (gen_lshrsi3 (high[0], high[0], operands[2]));
+
+ /* Heh. By reversing the arguments, we can reuse this pattern. */
+ if (TARGET_CMOVE && (! reload_completed || scratch))
{
- for (j = XVECLEN (rtl, i) - 1; j >= 0; j--)
- if (reg_mentioned_in_mem (reg, XVECEXP (rtl, i, j)))
- return 1;
- }
+ if (! reload_completed)
+ scratch = force_reg (SImode, const0_rtx);
+ else
+ emit_move_insn (scratch, const0_rtx);
- else if (fmt[i] == 'e' && reg_mentioned_in_mem (reg, XEXP (rtl, i)))
- return 1;
+ emit_insn (gen_x86_shift_adj_1 (low[0], high[0], operands[2],
+ scratch));
+ }
+ else
+ emit_insn (gen_x86_shift_adj_2 (low[0], high[0], operands[2]));
}
-
- return 0;
}
-
-/* Output the appropriate insns for doing strlen if not just doing repnz; scasb
- operands[0] = result, initialized with the startaddress
- operands[1] = alignment of the address.
- operands[2] = scratch register, initialized with the startaddress when
- not aligned, otherwise undefined
+/* Expand the appropriate insns for doing strlen if not just doing
+ repnz; scasb
+
+ out = result, initialized with the start address
+ align_rtx = alignment of the address.
+ scratch = scratch register, initialized with the startaddress when
+ not aligned, otherwise undefined
This is just the body. It needs the initialisations mentioned above and
some address computing at the end. These things are done in i386.md. */
-char *
-output_strlen_unroll (operands)
- rtx operands[];
+void
+ix86_expand_strlensi_unroll_1 (out, align_rtx, scratch)
+ rtx out, align_rtx, scratch;
{
- rtx xops[18];
-
- xops[0] = operands[0]; /* Result */
- /* operands[1]; * Alignment */
- xops[1] = operands[2]; /* Scratch */
- xops[2] = GEN_INT (0);
- xops[3] = GEN_INT (2);
- xops[4] = GEN_INT (3);
- xops[5] = GEN_INT (4);
- /* xops[6] = gen_label_rtx (); * label when aligned to 3-byte */
- /* xops[7] = gen_label_rtx (); * label when aligned to 2-byte */
- xops[8] = gen_label_rtx (); /* label of main loop */
-
- if (TARGET_USE_Q_REG && QI_REG_P (xops[1]))
- xops[9] = gen_label_rtx (); /* pentium optimisation */
-
- xops[10] = gen_label_rtx (); /* end label 2 */
- xops[11] = gen_label_rtx (); /* end label 1 */
- xops[12] = gen_label_rtx (); /* end label */
- /* xops[13] * Temporary used */
- xops[14] = GEN_INT (0xff);
- xops[15] = GEN_INT (0xff00);
- xops[16] = GEN_INT (0xff0000);
- xops[17] = GEN_INT (0xff000000);
+ int align;
+ rtx tmp;
+ rtx align_2_label = NULL_RTX;
+ rtx align_3_label = NULL_RTX;
+ rtx align_4_label = gen_label_rtx ();
+ rtx end_0_label = gen_label_rtx ();
+ rtx end_2_label = gen_label_rtx ();
+ rtx end_3_label = gen_label_rtx ();
+ rtx mem;
+ rtx flags = gen_rtx_REG (CCNOmode, FLAGS_REG);
+
+ align = 0;
+ if (GET_CODE (align_rtx) == CONST_INT)
+ align = INTVAL (align_rtx);
/* Loop to check 1..3 bytes for null to get an aligned pointer. */
/* Is there a known alignment and is it less than 4? */
- if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) < 4)
+ if (align < 4)
{
/* Is there a known alignment and is it not 2? */
- if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2)
+ if (align != 2)
{
- xops[6] = gen_label_rtx (); /* Label when aligned to 3-byte */
- xops[7] = gen_label_rtx (); /* Label when aligned to 2-byte */
-
- /* Leave just the 3 lower bits.
- If this is a q-register, then the high part is used later
- therefore use andl rather than andb. */
- output_asm_insn (AS2 (and%L1,%4,%1), xops);
-
- /* Is aligned to 4-byte address when zero */
- output_asm_insn (AS1 (je,%l8), xops);
-
- /* Side-effect even Parity when %eax == 3 */
- output_asm_insn (AS1 (jp,%6), xops);
-
- /* Is it aligned to 2 bytes ? */
- if (QI_REG_P (xops[1]))
- output_asm_insn (AS2 (cmp%L1,%3,%1), xops);
- else
- output_asm_insn (AS2 (cmp%L1,%3,%1), xops);
-
- output_asm_insn (AS1 (je,%7), xops);
+ align_3_label = gen_label_rtx (); /* Label when aligned to 3-byte */
+ align_2_label = gen_label_rtx (); /* Label when aligned to 2-byte */
+
+ /* Leave just the 3 lower bits. */
+ align_rtx = expand_binop (SImode, and_optab, scratch, GEN_INT (3),
+ NULL_RTX, 0, OPTAB_WIDEN);
+
+ emit_insn (gen_cmpsi_0 (align_rtx, const0_rtx));
+
+ tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode,
+ align_4_label),
+ pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
+
+ emit_insn (gen_cmpsi_1 (align_rtx, GEN_INT (2)));
+
+ tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode,
+ align_2_label),
+ pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
+
+ tmp = gen_rtx_GTU (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode,
+ align_3_label),
+ pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
}
else
{
/* Since the alignment is 2, we have to check 2 or 0 bytes;
check if is aligned to 4 - byte. */
- output_asm_insn (AS2 (and%L1,%3,%1), xops);
- /* Is aligned to 4-byte address when zero */
- output_asm_insn (AS1 (je,%l8), xops);
- }
+ align_rtx = expand_binop (SImode, and_optab, scratch, GEN_INT (2),
+ NULL_RTX, 0, OPTAB_WIDEN);
- xops[13] = gen_rtx_MEM (QImode, xops[0]);
+ emit_insn (gen_cmpsi_0 (align_rtx, const0_rtx));
- /* Now compare the bytes; compare with the high part of a q-reg
- gives shorter code. */
- if (QI_REG_P (xops[1]))
- {
- /* Compare the first n unaligned byte on a byte per byte basis. */
- output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
+ tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode,
+ align_4_label),
+ pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
+ }
- /* When zero we reached the end. */
- output_asm_insn (AS1 (je,%l12), xops);
+ mem = gen_rtx_MEM (QImode, out);
- /* Increment the address. */
- output_asm_insn (AS1 (inc%L0,%0), xops);
+ /* Now compare the bytes. */
- /* Not needed with an alignment of 2 */
- if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2)
- {
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
- CODE_LABEL_NUMBER (xops[7]));
- output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
- output_asm_insn (AS1 (je,%l12), xops);
- output_asm_insn (AS1 (inc%L0,%0), xops);
-
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
- CODE_LABEL_NUMBER (xops[6]));
- }
+ /* Compare the first n unaligned byte on a byte per byte basis. */
+ emit_insn (gen_cmpqi_0 (mem, const0_rtx));
- output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
- }
- else
- {
- output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
- output_asm_insn (AS1 (je,%l12), xops);
- output_asm_insn (AS1 (inc%L0,%0), xops);
+ tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode, end_0_label),
+ pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
- /* Not needed with an alignment of 2 */
- if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2)
- {
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
- CODE_LABEL_NUMBER (xops[7]));
- output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
- output_asm_insn (AS1 (je,%l12), xops);
- output_asm_insn (AS1 (inc%L0,%0), xops);
-
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
- CODE_LABEL_NUMBER (xops[6]));
- }
+ /* Increment the address. */
+ emit_insn (gen_addsi3 (out, out, const1_rtx));
- output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
- }
+ /* Not needed with an alignment of 2 */
+ if (align != 2)
+ {
+ emit_label (align_2_label);
- output_asm_insn (AS1 (je,%l12), xops);
- output_asm_insn (AS1 (inc%L0,%0), xops);
- }
+ emit_insn (gen_cmpqi_0 (mem, const0_rtx));
- /* Generate loop to check 4 bytes at a time. It is not a good idea to
- align this loop. It gives only huge programs, but does not help to
- speed up. */
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[8]));
+ tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode,
+ end_0_label),
+ pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
- xops[13] = gen_rtx_MEM (SImode, xops[0]);
- output_asm_insn (AS2 (mov%L1,%13,%1), xops);
+ emit_insn (gen_addsi3 (out, out, const1_rtx));
- if (QI_REG_P (xops[1]))
- {
- /* On i586 it is faster to combine the hi- and lo- part as
- a kind of lookahead. If anding both yields zero, then one
- of both *could* be zero, otherwise none of both is zero;
- this saves one instruction, on i486 this is slower
- tested with P-90, i486DX2-66, AMD486DX2-66 */
- if (TARGET_PENTIUM)
- {
- output_asm_insn (AS2 (test%B1,%h1,%b1), xops);
- output_asm_insn (AS1 (jne,%l9), xops);
- }
+ emit_label (align_3_label);
+ }
- /* Check first byte. */
- output_asm_insn (AS2 (test%B1,%b1,%b1), xops);
- output_asm_insn (AS1 (je,%l12), xops);
+ emit_insn (gen_cmpqi_0 (mem, const0_rtx));
- /* Check second byte. */
- output_asm_insn (AS2 (test%B1,%h1,%h1), xops);
- output_asm_insn (AS1 (je,%l11), xops);
+ tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode, end_0_label),
+ pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
- if (TARGET_PENTIUM)
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
- CODE_LABEL_NUMBER (xops[9]));
+ emit_insn (gen_addsi3 (out, out, const1_rtx));
}
- else
- {
- /* Check first byte. */
- output_asm_insn (AS2 (test%L1,%14,%1), xops);
- output_asm_insn (AS1 (je,%l12), xops);
+ /* Generate loop to check 4 bytes at a time. It is not a good idea to
+ align this loop. It gives only huge programs, but does not help to
+ speed up. */
+ emit_label (align_4_label);
- /* Check second byte. */
- output_asm_insn (AS2 (test%L1,%15,%1), xops);
- output_asm_insn (AS1 (je,%l11), xops);
- }
+ mem = gen_rtx_MEM (SImode, out);
+ emit_move_insn (scratch, mem);
+
+ /* Check first byte. */
+ emit_insn (gen_cmpqi_0 (gen_lowpart (QImode, scratch), const0_rtx));
+ tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode, end_0_label),
+ pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
+
+ /* Check second byte. */
+ emit_insn (gen_cmpqi_ext_3 (scratch, const0_rtx));
+ tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode, end_3_label),
+ pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
/* Check third byte. */
- output_asm_insn (AS2 (test%L1,%16,%1), xops);
- output_asm_insn (AS1 (je,%l10), xops);
+ emit_insn (gen_testsi_1 (scratch, GEN_INT (0x00ff0000)));
+ tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode, end_2_label),
+ pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
/* Check fourth byte and increment address. */
- output_asm_insn (AS2 (add%L0,%5,%0), xops);
- output_asm_insn (AS2 (test%L1,%17,%1), xops);
- output_asm_insn (AS1 (jne,%l8), xops);
+ emit_insn (gen_addsi3 (out, out, GEN_INT (4)));
+ emit_insn (gen_testsi_1 (scratch, GEN_INT (0xff000000)));
+ tmp = gen_rtx_NE (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode, align_4_label),
+ pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
/* Now generate fixups when the compare stops within a 4-byte word. */
- output_asm_insn (AS2 (sub%L0,%4,%0), xops);
+ emit_insn (gen_subsi3 (out, out, GEN_INT (3)));
+
+ emit_label (end_2_label);
+ emit_insn (gen_addsi3 (out, out, const1_rtx));
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[10]));
- output_asm_insn (AS1 (inc%L0,%0), xops);
+ emit_label (end_3_label);
+ emit_insn (gen_addsi3 (out, out, const1_rtx));
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[11]));
- output_asm_insn (AS1 (inc%L0,%0), xops);
+ emit_label (end_0_label);
+}
+
+#define MAX_386_STACK_LOCALS 2
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[12]));
+static rtx ix86_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
- return "";
+/* Define the structure for the machine field in struct function. */
+struct machine_function
+{
+ rtx ix86_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
+};
+
+/* Functions to save and restore ix86_stack_locals.
+ These will be called, via pointer variables,
+ from push_function_context and pop_function_context. */
+
+void
+save_386_machine_status (p)
+ struct function *p;
+{
+ p->machine
+ = (struct machine_function *) xmalloc (sizeof (struct machine_function));
+ bcopy ((char *) ix86_stack_locals, (char *) p->machine->ix86_stack_locals,
+ sizeof ix86_stack_locals);
}
-char *
-output_fp_conditional_move (which_alternative, operands)
- int which_alternative;
- rtx operands[];
+void
+restore_386_machine_status (p)
+ struct function *p;
+{
+ bcopy ((char *) p->machine->ix86_stack_locals, (char *) ix86_stack_locals,
+ sizeof ix86_stack_locals);
+ free (p->machine);
+ p->machine = NULL;
+}
+
+/* Clear stack slot assignments remembered from previous functions.
+ This is called from INIT_EXPANDERS once before RTL is emitted for each
+ function. */
+
+void
+clear_386_stack_locals ()
+{
+ enum machine_mode mode;
+ int n;
+
+ for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE;
+ mode = (enum machine_mode) ((int) mode + 1))
+ for (n = 0; n < MAX_386_STACK_LOCALS; n++)
+ ix86_stack_locals[(int) mode][n] = NULL_RTX;
+
+ /* Arrange to save and restore ix86_stack_locals around nested functions. */
+ save_machine_status = save_386_machine_status;
+ restore_machine_status = restore_386_machine_status;
+}
+
+/* Return a MEM corresponding to a stack slot with mode MODE.
+ Allocate a new slot if necessary.
+
+ The RTL for a function can have several slots available: N is
+ which slot to use. */
+
+rtx
+assign_386_stack_local (mode, n)
+ enum machine_mode mode;
+ int n;
{
- enum rtx_code code = GET_CODE (operands[1]);
+ if (n < 0 || n >= MAX_386_STACK_LOCALS)
+ abort ();
- /* This should never happen. */
- if (!(cc_prev_status.flags & CC_IN_80387)
- && (code == GT || code == LE || code == GE || code == LT))
+ if (ix86_stack_locals[(int) mode][n] == NULL_RTX)
+ ix86_stack_locals[(int) mode][n]
+ = assign_stack_local (mode, GET_MODE_SIZE (mode), 0);
+
+ return ix86_stack_locals[(int) mode][n];
+}
+
+/* Calculate the length of the memory address in the instruction
+ encoding. Does not include the one-byte modrm, opcode, or prefix. */
+
+static int
+memory_address_length (addr)
+ rtx addr;
+{
+ struct ix86_address parts;
+ rtx base, index, disp;
+ int len;
+
+ if (GET_CODE (addr) == PRE_DEC
+ || GET_CODE (addr) == POST_INC)
+ return 0;
+
+ if (! ix86_decompose_address (addr, &parts))
abort ();
- switch (which_alternative)
+ base = parts.base;
+ index = parts.index;
+ disp = parts.disp;
+ len = 0;
+
+ /* Register Indirect. */
+ if (base && !index && !disp)
{
- case 0:
- /* r <- cond ? arg : r */
- output_asm_insn (AS2 (fcmov%F1,%2,%0), operands);
+ /* Special cases: ebp and esp need the two-byte modrm form. */
+ if (addr == stack_pointer_rtx
+ || addr == arg_pointer_rtx
+ || addr == frame_pointer_rtx)
+ len = 1;
+ }
+
+ /* Direct Addressing. */
+ else if (disp && !base && !index)
+ len = 4;
+
+ else
+ {
+ /* Find the length of the displacement constant. */
+ if (disp)
+ {
+ if (GET_CODE (disp) == CONST_INT
+ && CONST_OK_FOR_LETTER_P (INTVAL (disp), 'K'))
+ len = 1;
+ else
+ len = 4;
+ }
+
+ /* An index requires the two-byte modrm form. */
+ if (index)
+ len += 1;
+ }
+
+ return len;
+}
+
+int
+ix86_attr_length_default (insn)
+ rtx insn;
+{
+ enum attr_type type;
+ int len = 0, i;
+
+ type = get_attr_type (insn);
+ extract_insn (insn);
+ switch (type)
+ {
+ case TYPE_INCDEC:
+ case TYPE_SETCC:
+ case TYPE_ICMOV:
+ case TYPE_FMOV:
+ case TYPE_FOP:
+ case TYPE_FCMP:
+ case TYPE_FOP1:
+ case TYPE_FMUL:
+ case TYPE_FDIV:
+ case TYPE_FSGN:
+ case TYPE_FPSPC:
+ case TYPE_FCMOV:
+ case TYPE_IBR:
break;
- case 1:
- /* r <- cond ? r : arg */
- output_asm_insn (AS2 (fcmov%f1,%3,%0), operands);
+ case TYPE_ALU1:
+ case TYPE_NEGNOT:
+ case TYPE_ALU:
+ case TYPE_ICMP:
+ case TYPE_IMOVX:
+ case TYPE_ISHIFT:
+ case TYPE_IMUL:
+ case TYPE_IDIV:
+ case TYPE_PUSH:
+ case TYPE_POP:
+ for (i = recog_n_operands - 1; i >= 0; --i)
+ if (CONSTANT_P (recog_operand[i]))
+ {
+ if (GET_CODE (recog_operand[i]) == CONST_INT
+ && CONST_OK_FOR_LETTER_P (INTVAL (recog_operand[i]), 'K'))
+ len += 1;
+ else
+ len += GET_MODE_SIZE (GET_MODE (recog_operand[0]));
+ }
+ break;
+
+ case TYPE_IMOV:
+ if (CONSTANT_P (recog_operand[1]))
+ len += GET_MODE_SIZE (GET_MODE (recog_operand[0]));
+ break;
+
+ case TYPE_CALL:
+ if (constant_call_address_operand (recog_operand[0]))
+ return 5;
break;
+ case TYPE_CALLV:
+ if (constant_call_address_operand (recog_operand[1]))
+ return 5;
+ break;
+
+ case TYPE_LEA:
+ len += memory_address_length (SET_SRC (single_set (insn)));
+ goto just_opcode;
+
+ case TYPE_OTHER:
+ case TYPE_MULTI:
+ return 15;
+
default:
abort ();
}
- return "";
+ for (i = recog_n_operands - 1; i >= 0; --i)
+ if (GET_CODE (recog_operand[i]) == MEM)
+ {
+ len += memory_address_length (XEXP (recog_operand[i], 0));
+ break;
+ }
+
+just_opcode:
+ len += get_attr_length_opcode (insn);
+ len += get_attr_length_prefix (insn);
+
+ return len;
}
+
+/* Return the maximum number of instructions a cpu can issue. */
-char *
-output_int_conditional_move (which_alternative, operands)
- int which_alternative;
- rtx operands[];
+int
+ix86_issue_rate ()
{
- enum rtx_code code = GET_CODE (operands[1]);
+ switch (ix86_cpu)
+ {
+ case PROCESSOR_PENTIUM:
+ case PROCESSOR_K6:
+ return 2;
+
+ case PROCESSOR_PENTIUMPRO:
+ return 3;
+
+ default:
+ return 1;
+ }
+}
- /* This is very tricky. We have to do it right. For a code segement
- like:
+/* A subroutine of ix86_adjust_cost -- return true iff INSN reads flags set
+ by DEP_INSN and nothing set by DEP_INSN. */
- int foo, bar;
- ....
- foo = foo - x;
- if (foo >= 0)
- bar = y;
+static int
+ix86_flags_dependant (insn, dep_insn, insn_type)
+ rtx insn, dep_insn;
+ enum attr_type insn_type;
+{
+ rtx set, set2;
- final_scan_insn () may delete the insn which sets CC. We have to
- tell final_scan_insn () if it should be reinserted. When CODE is
- GT or LE, we have to check the CC_NO_OVERFLOW bit and return
- NULL_PTR to tell final to reinsert the test insn because the
- conditional move cannot be handled properly without it. */
- if ((code == GT || code == LE)
- && (cc_prev_status.flags & CC_NO_OVERFLOW))
- return NULL_PTR;
+ /* Simplify the test for uninteresting insns. */
+ if (insn_type != TYPE_SETCC
+ && insn_type != TYPE_ICMOV
+ && insn_type != TYPE_FCMOV
+ && insn_type != TYPE_IBR)
+ return 0;
- switch (which_alternative)
+ if ((set = single_set (dep_insn)) != 0)
{
- case 0:
- /* r <- cond ? arg : r */
- output_asm_insn (AS2 (cmov%C1,%2,%0), operands);
- break;
+ set = SET_DEST (set);
+ set2 = NULL_RTX;
+ }
+ else if (GET_CODE (PATTERN (dep_insn)) == PARALLEL
+ && XVECLEN (PATTERN (dep_insn), 0) == 2
+ && GET_CODE (XVECEXP (PATTERN (dep_insn), 0, 0)) == SET
+ && GET_CODE (XVECEXP (PATTERN (dep_insn), 0, 1)) == SET)
+ {
+ set = SET_DEST (XVECEXP (PATTERN (dep_insn), 0, 0));
+ set2 = SET_DEST (XVECEXP (PATTERN (dep_insn), 0, 0));
+ }
- case 1:
- /* r <- cond ? r : arg */
- output_asm_insn (AS2 (cmov%c1,%3,%0), operands);
- break;
+ if (set && GET_CODE (set) == REG && REGNO (set) == FLAGS_REG)
+ {
+ /* This test is true if the dependant insn reads the flags but
+ not any other potentially set register. */
+ if (reg_overlap_mentioned_p (set, PATTERN (insn))
+ && (!set2 || !reg_overlap_mentioned_p (set2, PATTERN (insn))))
+ return 1;
+ }
- default:
- abort ();
+ return 0;
+}
+
+/* A subroutine of ix86_adjust_cost -- return true iff INSN has a memory
+ address with operands set by DEP_INSN. */
+
+static int
+ix86_agi_dependant (insn, dep_insn, insn_type)
+ rtx insn, dep_insn;
+ enum attr_type insn_type;
+{
+ rtx addr;
+
+ if (insn_type == TYPE_LEA)
+ addr = SET_SRC (single_set (insn));
+ else
+ {
+ int i;
+ extract_insn (insn);
+ for (i = recog_n_operands - 1; i >= 0; --i)
+ if (GET_CODE (recog_operand[i]) == MEM)
+ {
+ addr = XEXP (recog_operand[i], 0);
+ goto found;
+ }
+ return 0;
+ found:;
}
- return "";
+ return modified_in_p (addr, dep_insn);
}
int
-x86_adjust_cost (insn, link, dep_insn, cost)
+ix86_adjust_cost (insn, link, dep_insn, cost)
rtx insn, link, dep_insn;
int cost;
{
- rtx next_inst;
+ enum attr_type insn_type, dep_insn_type;
+ rtx set, set2;
- if (GET_CODE (dep_insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
- return 0;
+ /* We describe no anti or output depenancies. */
+ if (REG_NOTE_KIND (link) != 0)
+ return cost;
- if (GET_CODE (dep_insn) == INSN
- && GET_CODE (PATTERN (dep_insn)) == SET
- && GET_CODE (SET_DEST (PATTERN (dep_insn))) == REG
- && GET_CODE (insn) == INSN
- && GET_CODE (PATTERN (insn)) == SET
- && !reg_overlap_mentioned_p (SET_DEST (PATTERN (dep_insn)),
- SET_SRC (PATTERN (insn))))
- return 0; /* ??? */
+ /* If we can't recognize the insns, we can't really do anything. */
+ if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0)
+ return cost;
+ insn_type = get_attr_type (insn);
+ dep_insn_type = get_attr_type (dep_insn);
switch (ix86_cpu)
{
case PROCESSOR_PENTIUM:
- if (cost != 0 && is_fp_insn (insn) && is_fp_insn (dep_insn)
- && !is_fp_dest (dep_insn))
- return 0;
+ /* Address Generation Interlock adds a cycle of latency. */
+ if (ix86_agi_dependant (insn, dep_insn, insn_type))
+ cost += 1;
+
+ /* ??? Compares pair with jump/setcc. */
+ if (ix86_flags_dependant (insn, dep_insn, insn_type))
+ cost = 0;
+
+ /* Floating point stores require value to be ready one cycle ealier. */
+ if (insn_type == TYPE_FMOV
+ && get_attr_memory (insn) == MEMORY_STORE
+ && !ix86_agi_dependant (insn, dep_insn, insn_type))
+ cost += 1;
+ break;
- if (agi_dependent (insn, dep_insn))
- return cost ? cost + 1 : 2;
+ case PROCESSOR_PENTIUMPRO:
+ /* Since we can't represent delayed latencies of load+operation,
+ increase the cost here for non-imov insns. */
+ if (dep_insn_type != TYPE_IMOV
+ && dep_insn_type != TYPE_FMOV
+ && get_attr_memory (dep_insn) == MEMORY_LOAD)
+ cost += 1;
+
+ /* INT->FP conversion is expensive. */
+ if (get_attr_fp_int_src (dep_insn))
+ cost += 5;
+
+ /* There is one cycle extra latency between an FP op and a store. */
+ if (insn_type == TYPE_FMOV
+ && (set = single_set (dep_insn)) != NULL_RTX
+ && (set2 = single_set (insn)) != NULL_RTX
+ && rtx_equal_p (SET_DEST (set), SET_SRC (set2))
+ && GET_CODE (SET_DEST (set2)) == MEM)
+ cost += 1;
+ break;
- if (GET_CODE (insn) == INSN
- && GET_CODE (PATTERN (insn)) == SET
- && SET_DEST (PATTERN (insn)) == cc0_rtx
- && (next_inst = next_nonnote_insn (insn))
- && GET_CODE (next_inst) == JUMP_INSN)
- /* compare probably paired with jump */
- return 0;
+ case PROCESSOR_K6:
+ /* The esp dependency is resolved before the instruction is really
+ finished. */
+ if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
+ && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP))
+ return 1;
- /* Stores stalls one cycle longer than other insns. */
- if (is_fp_insn (insn) && cost && is_fp_store (dep_insn))
- cost++;
+ /* Since we can't represent delayed latencies of load+operation,
+ increase the cost here for non-imov insns. */
+ if (get_attr_memory (dep_insn) == MEMORY_LOAD)
+ cost += (dep_insn_type != TYPE_IMOV) ? 2 : 1;
+
+ /* INT->FP conversion is expensive. */
+ if (get_attr_fp_int_src (dep_insn))
+ cost += 5;
break;
- case PROCESSOR_K6:
+
default:
- if (!is_fp_dest (dep_insn))
- {
- if(!agi_dependent (insn, dep_insn))
- return 0;
- if (TARGET_486)
- return 2;
- }
- else
- if (is_fp_store (insn) && is_fp_insn (dep_insn)
- && NEXT_INSN (insn) && NEXT_INSN (NEXT_INSN (insn))
- && NEXT_INSN (NEXT_INSN (NEXT_INSN (insn)))
- && (GET_CODE (NEXT_INSN (insn)) == INSN)
- && (GET_CODE (NEXT_INSN (NEXT_INSN (insn))) == JUMP_INSN)
- && (GET_CODE (NEXT_INSN (NEXT_INSN (NEXT_INSN (insn)))) == NOTE)
- && (NOTE_LINE_NUMBER (NEXT_INSN (NEXT_INSN (NEXT_INSN (insn))))
- == NOTE_INSN_LOOP_END))
- return 3;
break;
}
return cost;
}
-/* Output assembly code for a left shift.
+static union
+{
+ struct ppro_sched_data
+ {
+ rtx decode[3];
+ int issued_this_cycle;
+ } ppro;
+} ix86_sched_data;
- Always use "sal" when shifting a memory operand or for a non constant
- shift count.
+static int
+ix86_safe_length (insn)
+ rtx insn;
+{
+ if (recog_memoized (insn) >= 0)
+ return get_attr_length(insn);
+ else
+ return 128;
+}
- When optimizing for size, we know that src == dest, and we should always
- use "sal". If src != dest, then copy src to dest and use "sal".
-
- Pentium and PPro (speed):
+static int
+ix86_safe_length_prefix (insn)
+ rtx insn;
+{
+ if (recog_memoized (insn) >= 0)
+ return get_attr_length(insn);
+ else
+ return 0;
+}
- When src == dest, use "add" for a shift counts of one, else use
- "sal". If we modeled Pentium AGI stalls and U/V pipelining better we
- would want to generate lea for some shifts on the Pentium.
+static enum attr_memory
+ix86_safe_memory (insn)
+ rtx insn;
+{
+ if (recog_memoized (insn) >= 0)
+ return get_attr_memory(insn);
+ else
+ return MEMORY_UNKNOWN;
+}
- When src != dest, use "lea" for small shift counts. Otherwise,
- copy src to dest and use the normal shifting code. Exception for
- TARGET_DOUBLE_WITH_ADD. */
+static enum attr_pent_pair
+ix86_safe_pent_pair (insn)
+ rtx insn;
+{
+ if (recog_memoized (insn) >= 0)
+ return get_attr_pent_pair(insn);
+ else
+ return PENT_PAIR_NP;
+}
-char *
-output_ashl (insn, operands)
- rtx insn, *operands;
+static enum attr_ppro_uops
+ix86_safe_ppro_uops (insn)
+ rtx insn;
+{
+ if (recog_memoized (insn) >= 0)
+ return get_attr_ppro_uops (insn);
+ else
+ return PPRO_UOPS_MANY;
+}
+
+static void
+ix86_dump_ppro_packet (dump)
+ FILE *dump;
{
- /* Handle case where srcreg != dstreg. */
- if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1]))
+ if (ix86_sched_data.ppro.decode[0])
{
- if (TARGET_DOUBLE_WITH_ADD && INTVAL (operands[2]) == 1)
- switch (GET_MODE (operands[0]))
- {
- case SImode:
- output_asm_insn (AS2 (mov%L0,%1,%0), operands);
- return AS2 (add%L0,%1,%0);
- case HImode:
- output_asm_insn (AS2 (mov%L0,%k1,%k0), operands);
- if (i386_cc_probably_useless_p (insn))
- {
- CC_STATUS_INIT;
- return AS2 (add%L0,%k1,%k0);
- }
- return AS2 (add%W0,%k1,%k0);
- case QImode:
- output_asm_insn (AS2 (mov%B0,%1,%0), operands);
- return AS2 (add%B0,%1,%0);
- default:
- abort ();
- }
- else
- {
- CC_STATUS_INIT;
+ fprintf (dump, "PPRO packet: %d",
+ INSN_UID (ix86_sched_data.ppro.decode[0]));
+ if (ix86_sched_data.ppro.decode[1])
+ fprintf (dump, " %d", INSN_UID (ix86_sched_data.ppro.decode[1]));
+ if (ix86_sched_data.ppro.decode[2])
+ fprintf (dump, " %d", INSN_UID (ix86_sched_data.ppro.decode[2]));
+ fputc ('\n', dump);
+ }
+}
- /* This should be extremely rare (impossible?). We can not encode a
- shift of the stack pointer using an lea instruction. So copy the
- stack pointer into the destination register and use an lea. */
- if (operands[1] == stack_pointer_rtx)
- {
- output_asm_insn (AS2 (mov%L0,%k1,%k0), operands);
- operands[1] = operands[0];
- }
+/* We're beginning a new block. Initialize data structures as necessary. */
- /* For shifts up to and including 3 bits, use lea. */
- operands[1] = gen_rtx_MULT (SImode,
- gen_rtx_REG (SImode, REGNO (operands[1])),
- GEN_INT (1 << INTVAL (operands[2])));
- return AS2 (lea%L0,%a1,%k0);
- }
+void
+ix86_sched_init (dump, sched_verbose)
+ FILE *dump ATTRIBUTE_UNUSED;
+ int sched_verbose ATTRIBUTE_UNUSED;
+{
+ memset (&ix86_sched_data, 0, sizeof (ix86_sched_data));
+}
+
+/* Shift INSN to SLOT, and shift everything else down. */
+
+static void
+ix86_reorder_insn (insnp, slot)
+ rtx *insnp, *slot;
+{
+ if (insnp != slot)
+ {
+ rtx insn = *insnp;
+ do
+ insnp[0] = insnp[1];
+ while (++insnp != slot);
+ *insnp = insn;
}
+}
- /* Source and destination match. */
+/* Find an instruction with given pairability and minimal amount of cycles
+ lost by the fact that the CPU waits for both pipelines to finish before
+ reading next instructions. Also take care that both instructions together
+ can not exceed 7 bytes. */
+
+static rtx *
+ix86_pent_find_pair (e_ready, ready, type, first)
+ rtx *e_ready;
+ rtx *ready;
+ enum attr_pent_pair type;
+ rtx first;
+{
+ int mincycles, cycles;
+ enum attr_pent_pair tmp;
+ enum attr_memory memory;
+ rtx *insnp, *bestinsnp = NULL;
- /* Handle variable shift. */
- if (REG_P (operands[2]))
- switch (GET_MODE (operands[0]))
+ if (ix86_safe_length (first) > 7 + ix86_safe_length_prefix (first))
+ return NULL;
+
+ memory = ix86_safe_memory (first);
+ cycles = result_ready_cost (first);
+ mincycles = INT_MAX;
+
+ for (insnp = e_ready; insnp >= ready && mincycles; --insnp)
+ if ((tmp = ix86_safe_pent_pair (*insnp)) == type
+ && ix86_safe_length (*insnp) <= 7 + ix86_safe_length_prefix (*insnp))
{
- case SImode:
- return AS2 (sal%L0,%b2,%0);
- case HImode:
- if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn))
+ enum attr_memory second_memory;
+ int secondcycles, currentcycles;
+
+ second_memory = ix86_safe_memory (*insnp);
+ secondcycles = result_ready_cost (*insnp);
+ currentcycles = abs (cycles - secondcycles);
+
+ if (secondcycles >= 1 && cycles >= 1)
{
- CC_STATUS_INIT;
- return AS2 (sal%L0,%b2,%k0);
+ /* Two read/modify/write instructions together takes two
+ cycles longer. */
+ if (memory == MEMORY_BOTH && second_memory == MEMORY_BOTH)
+ currentcycles += 2;
+
+ /* Read modify/write instruction followed by read/modify
+ takes one cycle longer. */
+ if (memory == MEMORY_BOTH && second_memory == MEMORY_LOAD
+ && tmp != PENT_PAIR_UV
+ && ix86_safe_pent_pair (first) != PENT_PAIR_UV)
+ currentcycles += 1;
}
- else
- return AS2 (sal%W0,%b2,%0);
- case QImode:
- return AS2 (sal%B0,%b2,%0);
- default:
- abort ();
+ if (currentcycles < mincycles)
+ bestinsnp = insnp, mincycles = currentcycles;
}
- /* Always perform shift by 1 using an add instruction. */
- if (REG_P (operands[0]) && operands[2] == const1_rtx)
- switch (GET_MODE (operands[0]))
+ return bestinsnp;
+}
+
+/* We are about to being issuing insns for this clock cycle.
+ Override the default sort algorithm to better slot instructions. */
+
+int
+ix86_sched_reorder (dump, sched_verbose, ready, n_ready, clock_var)
+ FILE *dump ATTRIBUTE_UNUSED;
+ int sched_verbose ATTRIBUTE_UNUSED;
+ rtx *ready;
+ int n_ready, clock_var;
+{
+ rtx *e_ready = ready + n_ready - 1;
+ rtx *insnp;
+ int i;
+
+ if (n_ready < 2)
+ goto out;
+
+ switch (ix86_cpu)
+ {
+ default:
+ goto out;
+
+ case PROCESSOR_PENTIUM:
+ /* This wouldn't be necessary if Haifa knew that static insn ordering
+ is important to which pipe an insn is issued to. So we have to make
+ some minor rearrangements. */
{
- case SImode:
- return AS2 (add%L0,%0,%0);
- case HImode:
- if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn))
+ enum attr_pent_pair pair1, pair2;
+
+ pair1 = ix86_safe_pent_pair (*e_ready);
+
+ /* If the first insn is non-pairable, let it be. */
+ if (pair1 == PENT_PAIR_NP)
+ goto out;
+ pair2 = PENT_PAIR_NP;
+
+ /* If the first insn is UV or PV pairable, search for a PU
+ insn to go with. */
+ if (pair1 == PENT_PAIR_UV || pair1 == PENT_PAIR_PV)
+ {
+ insnp = ix86_pent_find_pair (e_ready-1, ready,
+ PENT_PAIR_PU, *e_ready);
+ if (insnp)
+ pair2 = PENT_PAIR_PU;
+ }
+
+ /* If the first insn is PU or UV pairable, search for a PV
+ insn to go with. */
+ if (pair2 == PENT_PAIR_NP
+ && (pair1 == PENT_PAIR_PU || pair1 == PENT_PAIR_UV))
+ {
+ insnp = ix86_pent_find_pair (e_ready-1, ready,
+ PENT_PAIR_PV, *e_ready);
+ if (insnp)
+ pair2 = PENT_PAIR_PV;
+ }
+
+ /* If the first insn is pairable, search for a UV
+ insn to go with. */
+ if (pair2 == PENT_PAIR_NP)
{
- CC_STATUS_INIT;
- return AS2 (add%L0,%k0,%k0);
+ insnp = ix86_pent_find_pair (e_ready-1, ready,
+ PENT_PAIR_UV, *e_ready);
+ if (insnp)
+ pair2 = PENT_PAIR_UV;
}
+
+ if (pair2 == PENT_PAIR_NP)
+ goto out;
+
+ /* Found something! Decide if we need to swap the order. */
+ if (pair1 == PENT_PAIR_PV || pair2 == PENT_PAIR_PU
+ || (pair1 == PENT_PAIR_UV && pair2 == PENT_PAIR_UV
+ && ix86_safe_memory (*e_ready) == MEMORY_BOTH
+ && ix86_safe_memory (*insnp) == MEMORY_LOAD))
+ ix86_reorder_insn (insnp, e_ready);
else
- return AS2 (add%W0,%0,%0);
- case QImode:
- return AS2 (add%B0,%0,%0);
- default:
- abort ();
+ ix86_reorder_insn (insnp, e_ready - 1);
}
+ break;
-#if 0
- /* ??? Currently disabled. Because our model of Pentium is far from being
- exact, this change will need some benchmarking. */
- /* Shift reg by 2 or 3 use an lea instruction for Pentium if this is
- insn is expected to issue into the V pipe (the insn's mode will be
- TImode for a U pipe, and !TImode for a V pipe instruction). */
- if (! optimize_size
- && REG_P (operands[0])
- && GET_CODE (operands[2]) == CONST_INT
- && INTVAL (operands[2]) <= 3
- && (int)ix86_cpu == (int)PROCESSOR_PENTIUM
- && GET_MODE (insn) != TImode)
- {
- CC_STATUS_INIT;
- operands[1] = gen_rtx_MULT (SImode, gen_rtx_REG (SImode, REGNO (operands[1])),
- GEN_INT (1 << INTVAL (operands[2])));
- return AS2 (lea%L0,%a1,%0);
- }
-#endif
+ case PROCESSOR_PENTIUMPRO:
+ {
+ rtx decode[3];
+ enum attr_ppro_uops cur_uops;
+ int issued_this_cycle;
- /* Otherwise use a shift instruction. */
- switch (GET_MODE (operands[0]))
- {
- case SImode:
- return AS2 (sal%L0,%2,%0);
- case HImode:
- if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn))
- {
- CC_STATUS_INIT;
- return AS2 (sal%L0,%2,%k0);
- }
- else
- return AS2 (sal%W0,%2,%0);
- case QImode:
- return AS2 (sal%B0,%2,%0);
- default:
- abort ();
- }
-}
+ /* At this point .ppro.decode contains the state of the three
+ decoders from last "cycle". That is, those insns that were
+ actually independant. But here we're scheduling for the
+ decoder, and we may find things that are decodable in the
+ same cycle. */
-/* Given the memory address ADDR, calculate the length of the address or
- the length of just the displacement (controlled by DISP_LENGTH).
-
- The length returned does not include the one-byte modrm, opcode,
- or prefix. */
+ memcpy (decode, ix86_sched_data.ppro.decode, sizeof(decode));
+ issued_this_cycle = 0;
-int
-memory_address_info (addr, disp_length)
- rtx addr;
- int disp_length;
-{
- rtx base, index, disp, scale;
- rtx op0, op1;
- int len;
+ insnp = e_ready;
+ cur_uops = ix86_safe_ppro_uops (*insnp);
- if (GET_CODE (addr) == PRE_DEC
- || GET_CODE (addr) == POST_INC)
- return 0;
+ /* If the decoders are empty, and we've a complex insn at the
+ head of the priority queue, let it issue without complaint. */
+ if (decode[0] == NULL)
+ {
+ if (cur_uops == PPRO_UOPS_MANY)
+ {
+ decode[0] = *insnp;
+ goto ppro_done;
+ }
- /* Register Indirect. */
- if (register_operand (addr, Pmode))
- {
- /* Special cases: ebp and esp need the two-byte modrm form.
+ /* Otherwise, search for a 2-4 uop unsn to issue. */
+ while (cur_uops != PPRO_UOPS_FEW)
+ {
+ if (insnp == ready)
+ break;
+ cur_uops = ix86_safe_ppro_uops (*--insnp);
+ }
- We change [ESI] to [ESI+0] on the K6 when not optimizing
- for size. */
- if (addr == stack_pointer_rtx
- || addr == arg_pointer_rtx
- || addr == frame_pointer_rtx
- || (REGNO_REG_CLASS (REGNO (addr)) == SIREG
- && ix86_cpu == PROCESSOR_K6 && !optimize_size))
- return 1;
- else
- return 0;
- }
+ /* If so, move it to the head of the line. */
+ if (cur_uops == PPRO_UOPS_FEW)
+ ix86_reorder_insn (insnp, e_ready);
- /* Direct Addressing. */
- if (CONSTANT_P (addr))
- return 4;
+ /* Issue the head of the queue. */
+ issued_this_cycle = 1;
+ decode[0] = *e_ready--;
+ }
- index = base = disp = scale = NULL_RTX;
- op0 = XEXP (addr, 0);
- op1 = XEXP (addr, 1);
+ /* Look for simple insns to fill in the other two slots. */
+ for (i = 1; i < 3; ++i)
+ if (decode[i] == NULL)
+ {
+ if (ready >= e_ready)
+ goto ppro_done;
- if (GET_CODE (addr) == PLUS)
- {
- if (register_operand (op0, Pmode))
- {
- if (register_operand (op1, Pmode))
- index = op0, base = op1;
- else
- base = op0, disp = op1;
- }
- else if (GET_CODE (op0) == MULT)
- {
- index = XEXP (op0, 0);
- scale = XEXP (op0, 1);
- if (register_operand (op1, Pmode))
- base = op1;
- else
- disp = op1;
- }
- else if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 0)) == MULT)
- {
- index = XEXP (XEXP (op0, 0), 0);
- scale = XEXP (XEXP (op0, 0), 1);
- base = XEXP (op0, 1);
- disp = op1;
- }
- else if (GET_CODE (op0) == PLUS)
- {
- index = XEXP (op0, 0);
- base = XEXP (op0, 1);
- disp = op1;
- }
- else
- abort ();
- }
- else if (GET_CODE (addr) == MULT
- /* We're called for lea too, which implements ashift on occasion. */
- || GET_CODE (addr) == ASHIFT)
- {
- index = XEXP (addr, 0);
- scale = XEXP (addr, 1);
- }
- else
- abort ();
-
- /* Allow arg pointer and stack pointer as index if there is not scaling */
- if (base && index && !scale
- && (index == stack_pointer_rtx
- || index == arg_pointer_rtx
- || index == frame_pointer_rtx))
- {
- rtx tmp = base;
- base = index;
- index = tmp;
+ insnp = e_ready;
+ cur_uops = ix86_safe_ppro_uops (*insnp);
+ while (cur_uops != PPRO_UOPS_ONE)
+ {
+ if (insnp == ready)
+ break;
+ cur_uops = ix86_safe_ppro_uops (*--insnp);
+ }
+
+ /* Found one. Move it to the head of the queue and issue it. */
+ if (cur_uops == PPRO_UOPS_ONE)
+ {
+ ix86_reorder_insn (insnp, e_ready);
+ decode[i] = *e_ready--;
+ issued_this_cycle++;
+ continue;
+ }
+
+ /* ??? Didn't find one. Ideally, here we would do a lazy split
+ of 2-uop insns, issue one and queue the other. */
+ }
+
+ ppro_done:
+ if (issued_this_cycle == 0)
+ issued_this_cycle = 1;
+ ix86_sched_data.ppro.issued_this_cycle = issued_this_cycle;
+ }
+ break;
}
- /* Special case: ebp cannot be encoded as a base without a displacement. */
- if (base == frame_pointer_rtx && !disp)
- disp = const0_rtx;
+out:
+ return ix86_issue_rate ();
+}
- /* Scaling can not be encoded without base or displacement.
- Except for scale == 1 where we can encode reg + reg instead of reg * 2. */
- if (!base && index
- && (!scale || GET_CODE (scale) != CONST_INT || (INTVAL (scale) != 1)))
- disp = const0_rtx;
+/* We are about to issue INSN. Return the number of insns left on the
+ ready queue that can be issued this cycle. */
- /* Find the length of the displacement constant. */
- len = 0;
- if (disp)
+int
+ix86_variable_issue (dump, sched_verbose, insn, can_issue_more)
+ FILE *dump;
+ int sched_verbose;
+ rtx insn;
+ int can_issue_more;
+{
+ int i;
+ switch (ix86_cpu)
{
- if (GET_CODE (disp) == CONST_INT
- && CONST_OK_FOR_LETTER_P (INTVAL (disp), 'K'))
- len = 1;
- else
- len = 4;
- }
+ default:
+ return can_issue_more - 1;
- /* An index requires the two-byte modrm form. Not important
- if we are computing just length of the displacement. */
- if (index && ! disp_length)
- len += 1;
+ case PROCESSOR_PENTIUMPRO:
+ {
+ enum attr_ppro_uops uops = ix86_safe_ppro_uops (insn);
- return len;
+ if (uops == PPRO_UOPS_MANY)
+ {
+ if (sched_verbose)
+ ix86_dump_ppro_packet (dump);
+ ix86_sched_data.ppro.decode[0] = insn;
+ ix86_sched_data.ppro.decode[1] = NULL;
+ ix86_sched_data.ppro.decode[2] = NULL;
+ if (sched_verbose)
+ ix86_dump_ppro_packet (dump);
+ ix86_sched_data.ppro.decode[0] = NULL;
+ }
+ else if (uops == PPRO_UOPS_FEW)
+ {
+ if (sched_verbose)
+ ix86_dump_ppro_packet (dump);
+ ix86_sched_data.ppro.decode[0] = insn;
+ ix86_sched_data.ppro.decode[1] = NULL;
+ ix86_sched_data.ppro.decode[2] = NULL;
+ }
+ else
+ {
+ for (i = 0; i < 3; ++i)
+ if (ix86_sched_data.ppro.decode[i] == NULL)
+ {
+ ix86_sched_data.ppro.decode[i] = insn;
+ break;
+ }
+ if (i == 3)
+ abort ();
+ if (i == 2)
+ {
+ if (sched_verbose)
+ ix86_dump_ppro_packet (dump);
+ ix86_sched_data.ppro.decode[0] = NULL;
+ ix86_sched_data.ppro.decode[1] = NULL;
+ ix86_sched_data.ppro.decode[2] = NULL;
+ }
+ }
+ }
+ return --ix86_sched_data.ppro.issued_this_cycle;
+ }
}
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 827d021..ec05ac4 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -1,6 +1,5 @@
-/* Definitions of target machine for GNU compiler for Intel X86
- (386, 486, Pentium).
- Copyright (C) 1988, 92, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+/* Definitions of target machine for GNU compiler for IA-32.
+ Copyright (C) 1988, 92, 94-98, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -30,9 +29,9 @@ Boston, MA 02111-1307, USA. */
Many macros that specify assembler syntax are omitted entirely from
this file because they really belong in the files for particular
- assemblers. These include AS1, AS2, AS3, RP, IP, LPREFIX, L_SIZE,
- PUT_OP_SIZE, USE_STAR, ADDR_BEG, ADDR_END, PRINT_IREG, PRINT_SCALE,
- PRINT_B_I_S, and many that start with ASM_ or end in ASM_OP. */
+ assemblers. These include RP, IP, LPREFIX, PUT_OP_SIZE, USE_STAR,
+ ADDR_BEG, ADDR_END, PRINT_IREG, PRINT_SCALE, PRINT_B_I_S, and many
+ that start with ASM_ or end in ASM_OP. */
/* Names to predefine in the preprocessor for this target machine. */
@@ -62,6 +61,7 @@ struct processor_costs {
int mult_init; /* cost of starting a multiply */
int mult_bit; /* cost of multiply per each bit set */
int divide; /* cost of a divide/mod */
+ int large_insn; /* insns larger than this cost more */
};
extern struct processor_costs *ix86_cost;
@@ -73,29 +73,26 @@ extern int target_flags;
/* Macros used in the machine description to test the flags. */
/* configure can arrange to make this 2, to force a 486. */
+
#ifndef TARGET_CPU_DEFAULT
#define TARGET_CPU_DEFAULT 0
#endif
/* Masks for the -m switches */
-#define MASK_80387 000000000001 /* Hardware floating point */
-#define MASK_NOTUSED1 000000000002 /* bit not currently used */
-#define MASK_NOTUSED2 000000000004 /* bit not currently used */
-#define MASK_RTD 000000000010 /* Use ret that pops args */
-#define MASK_ALIGN_DOUBLE 000000000020 /* align doubles to 2 word boundary */
-#define MASK_SVR3_SHLIB 000000000040 /* Uninit locals into bss */
-#define MASK_IEEE_FP 000000000100 /* IEEE fp comparisons */
-#define MASK_FLOAT_RETURNS 000000000200 /* Return float in st(0) */
-#define MASK_NO_FANCY_MATH_387 000000000400 /* Disable sin, cos, sqrt */
-#define MASK_OMIT_LEAF_FRAME_POINTER 0x00000800 /* omit leaf frame pointers */
- /* Temporary codegen switches */
-#define MASK_DEBUG_ADDR 000001000000 /* Debug GO_IF_LEGITIMATE_ADDRESS */
-#define MASK_NO_WIDE_MULTIPLY 000002000000 /* Disable 32x32->64 multiplies */
-#define MASK_NO_MOVE 000004000000 /* Don't generate mem->mem */
-#define MASK_NO_PSEUDO 000010000000 /* Move op's args -> pseudos */
-#define MASK_DEBUG_ARG 000020000000 /* Debug function_arg */
-#define MASK_SCHEDULE_PROLOGUE 000040000000 /* Emit prologue as rtl */
-#define MASK_STACK_PROBE 000100000000 /* Enable stack probing */
+#define MASK_80387 0x00000001 /* Hardware floating point */
+#define MASK_RTD 0x00000002 /* Use ret that pops args */
+#define MASK_ALIGN_DOUBLE 0x00000004 /* align doubles to 2 word boundary */
+#define MASK_SVR3_SHLIB 0x00000008 /* Uninit locals into bss */
+#define MASK_IEEE_FP 0x00000010 /* IEEE fp comparisons */
+#define MASK_FLOAT_RETURNS 0x00000020 /* Return float in st(0) */
+#define MASK_NO_FANCY_MATH_387 0x00000040 /* Disable sin, cos, sqrt */
+#define MASK_OMIT_LEAF_FRAME_POINTER 0x080 /* omit leaf frame pointers */
+#define MASK_STACK_PROBE 0x00000100 /* Enable stack probing */
+
+/* Temporary codegen switches */
+#define MASK_INTEL_SYNTAX 0x10000000
+#define MASK_DEBUG_ARG 0x20000000 /* function_arg */
+#define MASK_DEBUG_ADDR 0x40000000 /* GO_IF_LEGITIMATE_ADDRESS */
/* Use the floating point instructions */
#define TARGET_80387 (target_flags & MASK_80387)
@@ -129,17 +126,8 @@ extern int target_flags;
#define TARGET_NO_FANCY_MATH_387 (target_flags & MASK_NO_FANCY_MATH_387)
/* Don't create frame pointers for leaf functions */
-#define TARGET_OMIT_LEAF_FRAME_POINTER (target_flags & MASK_OMIT_LEAF_FRAME_POINTER)
-
-/* Temporary switches for tuning code generation */
-
-/* Disable 32x32->64 bit multiplies that are used for long long multiplies
- and division by constants, but sometimes cause reload problems. */
-#define TARGET_NO_WIDE_MULTIPLY (target_flags & MASK_NO_WIDE_MULTIPLY)
-#define TARGET_WIDE_MULTIPLY (!TARGET_NO_WIDE_MULTIPLY)
-
-/* Emit/Don't emit prologue as rtl */
-#define TARGET_SCHEDULE_PROLOGUE (target_flags & MASK_SCHEDULE_PROLOGUE)
+#define TARGET_OMIT_LEAF_FRAME_POINTER \
+ (target_flags & MASK_OMIT_LEAF_FRAME_POINTER)
/* Debug GO_IF_LEGITIMATE_ADDRESS */
#define TARGET_DEBUG_ADDR (target_flags & MASK_DEBUG_ADDR)
@@ -147,10 +135,6 @@ extern int target_flags;
/* Debug FUNCTION_ARG macros */
#define TARGET_DEBUG_ARG (target_flags & MASK_DEBUG_ARG)
-/* Hack macros for tuning code generation */
-#define TARGET_MOVE ((target_flags & MASK_NO_MOVE) == 0) /* Don't generate memory->memory */
-#define TARGET_PSEUDO ((target_flags & MASK_NO_PSEUDO) == 0) /* Move op's args into pseudos */
-
#define TARGET_386 (ix86_cpu == PROCESSOR_I386)
#define TARGET_486 (ix86_cpu == PROCESSOR_I486)
#define TARGET_PENTIUM (ix86_cpu == PROCESSOR_PENTIUM)
@@ -161,7 +145,10 @@ extern int target_flags;
extern const int x86_use_leave, x86_push_memory, x86_zero_extend_with_and;
extern const int x86_use_bit_test, x86_cmove, x86_deep_branch;
extern const int x86_unroll_strlen, x86_use_q_reg, x86_use_any_reg;
-extern const int x86_double_with_add;
+extern const int x86_double_with_add, x86_partial_reg_stall, x86_movx;
+extern const int x86_use_loop, x86_use_fiop, x86_use_mov0;
+extern const int x86_use_cltd, x86_read_modify_write;
+extern const int x86_read_modify, x86_split_long_moves;
#define TARGET_USE_LEAVE (x86_use_leave & CPUMASK)
#define TARGET_PUSH_MEMORY (x86_push_memory & CPUMASK)
@@ -173,81 +160,87 @@ extern const int x86_double_with_add;
#define TARGET_CMOVE (x86_cmove & (1 << ix86_arch))
#define TARGET_DEEP_BRANCH_PREDICTION (x86_deep_branch & CPUMASK)
#define TARGET_DOUBLE_WITH_ADD (x86_double_with_add & CPUMASK)
+#define TARGET_USE_SAHF (x86_use_sahf & CPUMASK)
+#define TARGET_MOVX (x86_movx & CPUMASK)
+#define TARGET_PARTIAL_REG_STALL (x86_partial_reg_stall & CPUMASK)
+#define TARGET_USE_LOOP (x86_use_loop & CPUMASK)
+#define TARGET_USE_FIOP (x86_use_fiop & CPUMASK)
+#define TARGET_USE_MOV0 (x86_use_mov0 & CPUMASK)
+#define TARGET_USE_CLTD (x86_use_cltd & CPUMASK)
+#define TARGET_SPLIT_LONG_MOVES (x86_split_long_moves & CPUMASK)
+#define TARGET_READ_MODIFY_WRITE (x86_read_modify_write & CPUMASK)
+#define TARGET_READ_MODIFY (x86_read_modify & CPUMASK)
#define TARGET_STACK_PROBE (target_flags & MASK_STACK_PROBE)
-#define TARGET_SWITCHES \
-{ { "80387", MASK_80387, "Use hardware fp" }, \
- { "no-80387", -MASK_80387, "Do not use hardware fp" },\
- { "hard-float", MASK_80387, "Use hardware fp" }, \
- { "soft-float", -MASK_80387, "Do not use hardware fp" },\
- { "no-soft-float", MASK_80387, "Use hardware fp" }, \
- { "386", 0, "Same as -mcpu=i386" }, \
- { "486", 0, "Same as -mcpu=i486" }, \
- { "pentium", 0, "Same as -mcpu=pentium" }, \
- { "pentiumpro", 0, "Same as -mcpu=pentiumpro" }, \
- { "rtd", MASK_RTD, "Alternate calling convention" },\
- { "no-rtd", -MASK_RTD, "Use normal calling convention" },\
- { "align-double", MASK_ALIGN_DOUBLE, "Align some doubles on dword boundary" },\
- { "no-align-double", -MASK_ALIGN_DOUBLE, "Align doubles on word boundary" }, \
- { "svr3-shlib", MASK_SVR3_SHLIB, "Uninitialized locals in .bss" }, \
- { "no-svr3-shlib", -MASK_SVR3_SHLIB, "Uninitialized locals in .data" }, \
- { "ieee-fp", MASK_IEEE_FP, "Use IEEE math for fp comparisons" }, \
- { "no-ieee-fp", -MASK_IEEE_FP, "Do not use IEEE math for fp comparisons" }, \
- { "fp-ret-in-387", MASK_FLOAT_RETURNS, "Return values of functions in FPU registers" }, \
- { "no-fp-ret-in-387", -MASK_FLOAT_RETURNS , "Do not return values of functions in FPU registers"}, \
- { "no-fancy-math-387", MASK_NO_FANCY_MATH_387, "Do not generate sin, cos, sqrt for 387" }, \
- { "fancy-math-387", -MASK_NO_FANCY_MATH_387, "Generate sin, cos, sqrt for FPU"}, \
- { "omit-leaf-frame-pointer", MASK_OMIT_LEAF_FRAME_POINTER, "Omit the frame pointer in leaf functions" }, \
- { "no-omit-leaf-frame-pointer",-MASK_OMIT_LEAF_FRAME_POINTER, "" }, \
- { "no-wide-multiply", MASK_NO_WIDE_MULTIPLY, "multiplies of 32 bits constrained to 32 bits" }, \
- { "wide-multiply", -MASK_NO_WIDE_MULTIPLY, "multiplies of 32 bits are 64 bits" }, \
- { "schedule-prologue", MASK_SCHEDULE_PROLOGUE, "Schedule function prologues" }, \
- { "no-schedule-prologue", -MASK_SCHEDULE_PROLOGUE, "" }, \
- { "debug-addr", MASK_DEBUG_ADDR, 0 /* intentionally undoc */ }, \
- { "no-debug-addr", -MASK_DEBUG_ADDR, 0 /* intentionally undoc */ }, \
- { "move", -MASK_NO_MOVE, "Generate mem-mem moves" }, \
- { "no-move", MASK_NO_MOVE, "Don't generate mem-mem moves" }, \
- { "debug-arg", MASK_DEBUG_ARG, 0 /* intentionally undoc */ }, \
- { "no-debug-arg", -MASK_DEBUG_ARG, 0 /* intentionally undoc */ }, \
- { "stack-arg-probe", MASK_STACK_PROBE, "Enable stack probing" }, \
- { "no-stack-arg-probe", -MASK_STACK_PROBE, "" }, \
- { "windows", 0, 0 /* intentionally undoc */ }, \
- { "dll", 0, 0 /* intentionally undoc */ }, \
- SUBTARGET_SWITCHES \
- { "", MASK_SCHEDULE_PROLOGUE | TARGET_DEFAULT, 0 }}
+#define ASSEMBLER_DIALECT ((target_flags & MASK_INTEL_SYNTAX) != 0)
+
+#define TARGET_SWITCHES \
+{ { "80387", MASK_80387, "Use hardware fp" }, \
+ { "no-80387", -MASK_80387, "Do not use hardware fp" }, \
+ { "hard-float", MASK_80387, "Use hardware fp" }, \
+ { "soft-float", -MASK_80387, "Do not use hardware fp" }, \
+ { "no-soft-float", MASK_80387, "Use hardware fp" }, \
+ { "386", 0, "Same as -mcpu=i386" }, \
+ { "486", 0, "Same as -mcpu=i486" }, \
+ { "pentium", 0, "Same as -mcpu=pentium" }, \
+ { "pentiumpro", 0, "Same as -mcpu=pentiumpro" }, \
+ { "rtd", MASK_RTD, "Alternate calling convention" }, \
+ { "no-rtd", -MASK_RTD, "Use normal calling convention" }, \
+ { "align-double", MASK_ALIGN_DOUBLE, \
+ "Align some doubles on dword boundary" }, \
+ { "no-align-double", -MASK_ALIGN_DOUBLE, \
+ "Align doubles on word boundary" }, \
+ { "svr3-shlib", MASK_SVR3_SHLIB, \
+ "Uninitialized locals in .bss" }, \
+ { "no-svr3-shlib", -MASK_SVR3_SHLIB, \
+ "Uninitialized locals in .data" }, \
+ { "ieee-fp", MASK_IEEE_FP, \
+ "Use IEEE math for fp comparisons" }, \
+ { "no-ieee-fp", -MASK_IEEE_FP, \
+ "Do not use IEEE math for fp comparisons" }, \
+ { "fp-ret-in-387", MASK_FLOAT_RETURNS, \
+ "Return values of functions in FPU registers" }, \
+ { "no-fp-ret-in-387", -MASK_FLOAT_RETURNS , \
+ "Do not return values of functions in FPU registers"}, \
+ { "no-fancy-math-387", MASK_NO_FANCY_MATH_387, \
+ "Do not generate sin, cos, sqrt for FPU" }, \
+ { "fancy-math-387", -MASK_NO_FANCY_MATH_387, \
+ "Generate sin, cos, sqrt for FPU"}, \
+ { "omit-leaf-frame-pointer", MASK_OMIT_LEAF_FRAME_POINTER, \
+ "Omit the frame pointer in leaf functions" }, \
+ { "no-omit-leaf-frame-pointer",-MASK_OMIT_LEAF_FRAME_POINTER, "" }, \
+ { "debug-addr", MASK_DEBUG_ADDR, 0 /* undocumented */ }, \
+ { "no-debug-addr", -MASK_DEBUG_ADDR, 0 /* undocumented */ }, \
+ { "debug-arg", MASK_DEBUG_ARG, 0 /* undocumented */ }, \
+ { "no-debug-arg", -MASK_DEBUG_ARG, 0 /* undocumented */ }, \
+ { "stack-arg-probe", MASK_STACK_PROBE, "Enable stack probing" }, \
+ { "no-stack-arg-probe", -MASK_STACK_PROBE, "" }, \
+ { "windows", 0, 0 /* undocumented */ }, \
+ { "dll", 0, 0 /* undocumented */ }, \
+ { "intel-syntax", MASK_INTEL_SYNTAX, \
+ "Emit Intel syntax assembler opcodes" }, \
+ { "no-intel-syntax", -MASK_INTEL_SYNTAX, "" }, \
+ SUBTARGET_SWITCHES \
+ { "", TARGET_DEFAULT, 0 }}
/* Which processor to schedule for. The cpu attribute defines a list that
mirrors this list, so changes to i386.md must be made at the same time. */
enum processor_type
- {PROCESSOR_I386, /* 80386 */
+{
+ PROCESSOR_I386, /* 80386 */
PROCESSOR_I486, /* 80486DX, 80486SX, 80486DX[24] */
PROCESSOR_PENTIUM,
PROCESSOR_PENTIUMPRO,
- PROCESSOR_K6};
-
-#define PROCESSOR_I386_STRING "i386"
-#define PROCESSOR_I486_STRING "i486"
-#define PROCESSOR_I586_STRING "i586"
-#define PROCESSOR_PENTIUM_STRING "pentium"
-#define PROCESSOR_I686_STRING "i686"
-#define PROCESSOR_PENTIUMPRO_STRING "pentiumpro"
-#define PROCESSOR_K6_STRING "k6"
+ PROCESSOR_K6,
+ PROCESSOR_max
+};
extern enum processor_type ix86_cpu;
extern int ix86_arch;
-/* Define the default processor. This is overridden by other tm.h files. */
-#define PROCESSOR_DEFAULT (enum processor_type) TARGET_CPU_DEFAULT
-#define PROCESSOR_DEFAULT_STRING \
- (PROCESSOR_DEFAULT == PROCESSOR_I486 ? PROCESSOR_I486_STRING \
- : PROCESSOR_DEFAULT == PROCESSOR_PENTIUM ? PROCESSOR_PENTIUM_STRING \
- : PROCESSOR_DEFAULT == PROCESSOR_PENTIUMPRO ? PROCESSOR_PENTIUMPRO_STRING \
- : PROCESSOR_DEFAULT == PROCESSOR_K6 ? PROCESSOR_K6_STRING \
- : PROCESSOR_I386_STRING)
-
/* This macro is similar to `TARGET_SWITCHES' but defines names of
command options that have values. Its definition is an
initializer with a subgrouping for each command option.
@@ -257,17 +250,27 @@ extern int ix86_arch;
variable, type `char *', is set to the variable part of the given
option if the fixed part matches. The actual option name is made
by appending `-m' to the specified name. */
-#define TARGET_OPTIONS \
-{ { "cpu=", &ix86_cpu_string, "Schedule code for given CPU"}, \
- { "arch=", &ix86_arch_string, "Generate code for given CPU"}, \
- { "reg-alloc=", &i386_reg_alloc_order, "Control allocation order of integer registers" }, \
- { "regparm=", &i386_regparm_string, "Number of registers used to pass integer arguments" }, \
- { "align-loops=", &i386_align_loops_string, "Loop code aligned to this power of 2" }, \
- { "align-jumps=", &i386_align_jumps_string, "Jump targets are aligned to this power of 2" }, \
- { "align-functions=", &i386_align_funcs_string, "Function starts are aligned to this power of 2" }, \
- { "preferred-stack-boundary=", &i386_preferred_stack_boundary_string, "Attempt to keep stack aligned to this power of 2" }, \
- { "branch-cost=", &i386_branch_cost_string, "Branches are this expensive (1-5, arbitrary units)" }, \
- SUBTARGET_OPTIONS \
+#define TARGET_OPTIONS \
+{ { "cpu=", &ix86_cpu_string, \
+ "Schedule code for given CPU"}, \
+ { "arch=", &ix86_arch_string, \
+ "Generate code for given CPU"}, \
+ { "reg-alloc=", &ix86_reg_alloc_order, \
+ "Control allocation order of integer registers" }, \
+ { "regparm=", &ix86_regparm_string, \
+ "Number of registers used to pass integer arguments" }, \
+ { "align-loops=", &ix86_align_loops_string, \
+ "Loop code aligned to this power of 2" }, \
+ { "align-jumps=", &ix86_align_jumps_string, \
+ "Jump targets are aligned to this power of 2" }, \
+ { "align-functions=", &ix86_align_funcs_string, \
+ "Function starts are aligned to this power of 2" }, \
+ { "preferred-stack-boundary=", \
+ &ix86_preferred_stack_boundary_string, \
+ "Attempt to keep stack aligned to this power of 2" }, \
+ { "branch-cost=", &ix86_branch_cost_string, \
+ "Branches are this expensive (1-5, arbitrary units)" }, \
+ SUBTARGET_OPTIONS \
}
/* Sometimes certain combinations of command options do not make
@@ -294,34 +297,34 @@ extern int ix86_arch;
#define CC1_CPU_SPEC "\
%{!mcpu*: \
%{m386:-mcpu=i386 -march=i386} \
+%{mno-486:-mcpu=i386 -march=i386} \
%{m486:-mcpu=i486 -march=i486} \
+%{mno-386:-mcpu=i486 -march=i486} \
+%{mno-pentium:-mcpu=i486 -march=i486} \
%{mpentium:-mcpu=pentium} \
+%{mno-pentiumpro:-mcpu=pentium} \
%{mpentiumpro:-mcpu=pentiumpro}}"
#endif
#define CPP_486_SPEC "%{!ansi:-Di486} -D__i486 -D__i486__"
#define CPP_586_SPEC "%{!ansi:-Di586 -Dpentium} \
-D__i586 -D__i586__ -D__pentium -D__pentium__"
-#define CPP_K6_SPEC "%{!ansi:-Di586 -Dk6} \
- -D__i586 -D__i586__ -D__k6 -D__k6__"
#define CPP_686_SPEC "%{!ansi:-Di686 -Dpentiumpro} \
-D__i686 -D__i686__ -D__pentiumpro -D__pentiumpro__"
#ifndef CPP_CPU_DEFAULT_SPEC
#if TARGET_CPU_DEFAULT == 1
#define CPP_CPU_DEFAULT_SPEC "%(cpp_486)"
-#endif
+#else
#if TARGET_CPU_DEFAULT == 2
#define CPP_CPU_DEFAULT_SPEC "%(cpp_586)"
-#endif
+#else
#if TARGET_CPU_DEFAULT == 3
#define CPP_CPU_DEFAULT_SPEC "%(cpp_686)"
+#else
+#define CPP_CPU_DEFAULT_SPEC ""
#endif
-#if TARGET_CPU_DEFAULT == 4
-#define CPP_CPU_DEFAULT_SPEC "%(cpp_k6)"
#endif
-#ifndef CPP_CPU_DEFAULT_SPEC
-#define CPP_CPU_DEFAULT_SPEC ""
#endif
#endif /* CPP_CPU_DEFAULT_SPEC */
@@ -332,7 +335,6 @@ extern int ix86_arch;
%{mcpu=i486:%(cpp_486)} %{m486:%(cpp_486)} \
%{mpentium:%(cpp_586)} %{mcpu=pentium:%(cpp_586)} \
%{mpentiumpro:%(cpp_686)} %{mcpu=pentiumpro:%(cpp_686)} \
-%{mcpu=k6:%(cpp_k6)} \
%{!mcpu*:%{!m486:%{!mpentium*:%(cpp_cpu_default)}}}"
#endif
@@ -357,7 +359,6 @@ extern int ix86_arch;
#define EXTRA_SPECS \
{ "cpp_486", CPP_486_SPEC}, \
{ "cpp_586", CPP_586_SPEC}, \
- { "cpp_k6", CPP_K6_SPEC}, \
{ "cpp_686", CPP_686_SPEC}, \
{ "cpp_cpu_default", CPP_CPU_DEFAULT_SPEC }, \
{ "cpp_cpu", CPP_CPU_SPEC }, \
@@ -408,17 +409,16 @@ extern int ix86_arch;
/* Allocation boundary (in *bits*) for storing arguments in argument list. */
#define PARM_BOUNDARY 32
-/* Boundary (in *bits*) on which the stack pointer must be aligned. */
+/* Boundary (in *bits*) on which stack pointer should be aligned. */
#define STACK_BOUNDARY 32
/* Boundary (in *bits*) on which the stack pointer preferrs to be
aligned; the compiler cannot rely on having this alignment. */
-#define PREFERRED_STACK_BOUNDARY i386_preferred_stack_boundary
+#define PREFERRED_STACK_BOUNDARY ix86_preferred_stack_boundary
-/* Allocation boundary (in *bits*) for the code of a function.
- For i486, we get better performance by aligning to a cache
- line (i.e. 16 byte) boundary. */
-#define FUNCTION_BOUNDARY (1 << (i386_align_funcs + 3))
+/* Allocation boundary for the code of a function. */
+#define FUNCTION_BOUNDARY \
+ (1 << ((ix86_align_funcs >= 0 ? ix86_align_funcs : -ix86_align_funcs) + 3))
/* Alignment of field after `int : 0' in a structure. */
@@ -556,19 +556,17 @@ extern int ix86_arch;
/* Required on the 386 since it doesn't have bitfield insns. */
#define PCC_BITFIELD_TYPE_MATTERS 1
-/* Maximum power of 2 that code can be aligned to. */
-#define MAX_CODE_ALIGN 6 /* 64 byte alignment */
-
/* Align loop starts for optimal branching. */
-#define LOOP_ALIGN(LABEL) (i386_align_loops)
-#define LOOP_ALIGN_MAX_SKIP (i386_align_loops_string ? 0 : 7)
-
-/* This is how to align an instruction for optimal branching.
- On i486 we'll get better performance by aligning on a
- cache line (i.e. 16 byte) boundary. */
-#define LABEL_ALIGN_AFTER_BARRIER(LABEL) (i386_align_jumps)
-#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP (i386_align_jumps_string ? 0 : 7)
-
+#define LOOP_ALIGN(LABEL) \
+ (ix86_align_loops < 0 ? -ix86_align_loops : ix86_align_loops)
+#define LOOP_ALIGN_MAX_SKIP \
+ (ix86_align_loops < -3 ? (1<<(-ix86_align_loops-1))-1 : 0)
+
+/* This is how to align an instruction for optimal branching. */
+#define LABEL_ALIGN_AFTER_BARRIER(LABEL) \
+ (ix86_align_jumps < 0 ? -ix86_align_jumps : ix86_align_jumps)
+#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP \
+ (ix86_align_jumps < -3 ? (1<<(-ix86_align_jumps-1))-1 : 0)
/* Standard register usage. */
@@ -594,14 +592,14 @@ extern int ix86_arch;
eliminated during reloading in favor of either the stack or frame
pointer. */
-#define FIRST_PSEUDO_REGISTER 17
+#define FIRST_PSEUDO_REGISTER 19
/* 1 for registers that have pervasive standard uses
and are not available for the register allocator.
On the 80386, the stack pointer is such, as is the arg pointer. */
#define FIXED_REGISTERS \
-/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \
-{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
+/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg,flags,fpsr*/ \
+{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }
/* 1 for registers not available across function calls.
These must include the FIXED_REGISTERS and also any
@@ -611,8 +609,8 @@ extern int ix86_arch;
Aside from that, you can include as many other registers as you like. */
#define CALL_USED_REGISTERS \
-/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \
-{ 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
+/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg,flags,fpsr*/ \
+{ 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
/* Order in which to allocate registers. Each register must be
listed once, even those in FIXED_REGISTERS. List frame pointer
@@ -634,8 +632,8 @@ extern int ix86_arch;
generated by allocating edx first, so restore the 'natural' order of things. */
#define REG_ALLOC_ORDER \
-/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \
-{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }
+/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg,cc,fpsr*/ \
+{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,17, 18 }
/* A C statement (sans semicolon) to choose the order in which to
allocate hard registers for pseudo-registers local to a basic
@@ -685,22 +683,26 @@ extern int ix86_arch;
(FP_REGNO_P (REGNO) ? 1 \
: ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
-/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
- On the 80386, the first 4 cpu registers can hold any mode
- while the floating point registers may hold only floating point.
- Make it clear that the fp regs could not hold a 16-byte float. */
-
-/* The casts to int placate a compiler on a microvax,
- for cross-compiler testing. */
+/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
-#define HARD_REGNO_MODE_OK(REGNO, MODE) \
- ((REGNO) < 4 ? 1 \
+#define HARD_REGNO_MODE_OK(REGNO, MODE) \
+ /* Flags and only flags can only hold CCmode values. */ \
+ (CC_REGNO_P (REGNO) \
+ ? GET_MODE_CLASS (MODE) == MODE_CC \
+ : GET_MODE_CLASS (MODE) == MODE_CC ? 0 \
+ /* FP regs can only hold floating point; make it clear they \
+ cannot hold TFmode floats. */ \
: FP_REGNO_P (REGNO) \
- ? (((int) GET_MODE_CLASS (MODE) == (int) MODE_FLOAT \
- || (int) GET_MODE_CLASS (MODE) == (int) MODE_COMPLEX_FLOAT) \
+ ? ((GET_MODE_CLASS (MODE) == MODE_FLOAT \
+ || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \
&& GET_MODE_UNIT_SIZE (MODE) <= (LONG_DOUBLE_TYPE_SIZE == 96 ? 12 : 8))\
- : (int) (MODE) != (int) QImode ? 1 \
- : (reload_in_progress | reload_completed) == 1)
+ /* Only allow DImode in even registers. */ \
+ : (MODE) == DImode && ((REGNO) & 1) ? 0 \
+ /* The first four integer regs can hold any mode. */ \
+ : (REGNO) < 4 ? 1 \
+ /* Other regs cannot do byte accesses. */ \
+ : (MODE) != QImode ? 1 \
+ : reload_in_progress || reload_completed)
/* Value is 1 if it is a good idea to tie two pseudo registers
when one has mode MODE1 and one has mode MODE2.
@@ -712,6 +714,13 @@ extern int ix86_arch;
|| ((MODE1) == SImode && (MODE2) == HImode) \
|| ((MODE1) == HImode && (MODE2) == SImode))
+/* Specify the modes required to caller save a given hard regno.
+ We do this on i386 to prevent flags from being saved at all. */
+
+#define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS) \
+ (CC_REGNO_P (REGNO) ? VOIDmode \
+ : choose_hard_reg_mode ((REGNO), (NREGS)))
+
/* Specify the registers used for certain standard purposes.
The values of these macros are register numbers. */
@@ -732,6 +741,9 @@ extern int ix86_arch;
#define FIRST_STACK_REG FIRST_FLOAT_REG
#define LAST_STACK_REG (FIRST_FLOAT_REG + 7)
+#define FLAGS_REG 17
+#define FPSR_REG 18
+
/* Value should be nonzero if functions must have frame pointers.
Zero means the frame pointer need not be set up (and parms
may be accessed via the stack pointer) in functions that seem suitable.
@@ -800,15 +812,17 @@ extern int ix86_arch;
It might seem that class BREG is unnecessary, since no useful 386
opcode needs reg %ebx. But some systems pass args to the OS in ebx,
- and the "b" register constraint is useful in asms for syscalls. */
+ and the "b" register constraint is useful in asms for syscalls.
+
+ The flags and fpsr registers are in no class. */
enum reg_class
{
NO_REGS,
- AREG, DREG, CREG, BREG,
+ AREG, DREG, CREG, BREG, SIREG, DIREG,
AD_REGS, /* %eax/%edx for DImode */
Q_REGS, /* %eax %ebx %ecx %edx */
- SIREG, DIREG,
+ NON_Q_REGS, /* %esi %edi %ebp %esi */
INDEX_REGS, /* %eax %ebx %ecx %edx %esi %edi %ebp */
GENERAL_REGS, /* %eax %ebx %ecx %edx %esi %edi %ebp %esp */
FP_TOP_REG, FP_SECOND_REG, /* %st(0) %st(1) */
@@ -825,9 +839,9 @@ enum reg_class
#define REG_CLASS_NAMES \
{ "NO_REGS", \
"AREG", "DREG", "CREG", "BREG", \
- "AD_REGS", \
- "Q_REGS", \
"SIREG", "DIREG", \
+ "AD_REGS", \
+ "Q_REGS", "NON_Q_REGS", \
"INDEX_REGS", \
"GENERAL_REGS", \
"FP_TOP_REG", "FP_SECOND_REG", \
@@ -838,17 +852,19 @@ enum reg_class
This is an initializer for a vector of HARD_REG_SET
of length N_REG_CLASSES. */
-#define REG_CLASS_CONTENTS \
+#define REG_CLASS_CONTENTS \
{ {0}, \
- {0x1}, {0x2}, {0x4}, {0x8}, /* AREG, DREG, CREG, BREG */ \
+ {0x1}, {0x2}, {0x4}, {0x8},/* AREG, DREG, CREG, BREG */ \
+ {0x10}, {0x20}, /* SIREG, DIREG */ \
{0x3}, /* AD_REGS */ \
{0xf}, /* Q_REGS */ \
- {0x10}, {0x20}, /* SIREG, DIREG */ \
- {0x7f}, /* INDEX_REGS */ \
+ {0xf0}, /* NON_Q_REGS */ \
+ {0x7f}, /* INDEX_REGS */ \
{0x100ff}, /* GENERAL_REGS */ \
{0x0100}, {0x0200}, /* FP_TOP_REG, FP_SECOND_REG */ \
{0xff00}, /* FLOAT_REGS */ \
- {0x1ffff}}
+ {0x7ffff} \
+}
/* The same information, inverted:
Return the class number of the smallest class containing
@@ -879,6 +895,9 @@ enum reg_class
#define STACK_TOP_P(xop) (REG_P (xop) && REGNO (xop) == FIRST_STACK_REG)
+#define CC_REG_P(X) (REG_P (X) && CC_REGNO_P (REGNO (X)))
+#define CC_REGNO_P(X) ((X) == FLAGS_REG || (X) == FPSR_REG)
+
/* 1 if register REGNO can magically overlap other regs.
Note that nonzero values work only in very special circumstances. */
@@ -919,19 +938,18 @@ enum reg_class
I is for non-DImode shifts.
J is for DImode shifts.
- K and L are for an `andsi' optimization.
+ K is for signed imm8 operands.
+ L is for andsi as zero-extending move.
M is for shifts that can be executed by the "lea" opcode.
*/
-#define CONST_OK_FOR_LETTER_P(VALUE, C) \
- ((C) == 'I' ? (VALUE) >= 0 && (VALUE) <= 31 : \
- (C) == 'J' ? (VALUE) >= 0 && (VALUE) <= 63 : \
- (C) == 'K' ? (VALUE) == 0xff : \
- (C) == 'L' ? (VALUE) == 0xffff : \
- (C) == 'M' ? (VALUE) >= 0 && (VALUE) <= 3 : \
- (C) == 'N' ? (VALUE) >= 0 && (VALUE) <= 255 :\
- (C) == 'O' ? (VALUE) >= 0 && (VALUE) <= 32 : \
- 0)
+#define CONST_OK_FOR_LETTER_P(VALUE, C) \
+ ((C) == 'I' ? (VALUE) >= 0 && (VALUE) <= 31 \
+ : (C) == 'J' ? (VALUE) >= 0 && (VALUE) <= 63 \
+ : (C) == 'K' ? (VALUE) >= -128 && (VALUE) <= 127 \
+ : (C) == 'L' ? (VALUE) == 0xff || (VALUE) == 0xffff \
+ : (C) == 'M' ? (VALUE) >= 0 && (VALUE) <= 3 \
+ : 0)
/* Similar, but for floating constants, and defining letters G and H.
Here VALUE is the CONST_DOUBLE rtx itself. We allow constants even if
@@ -976,8 +994,14 @@ enum reg_class
location. */
#define SECONDARY_MEMORY_NEEDED(CLASS1,CLASS2,MODE) \
- ((FLOAT_CLASS_P (CLASS1) && ! FLOAT_CLASS_P (CLASS2)) \
- || (! FLOAT_CLASS_P (CLASS1) && FLOAT_CLASS_P (CLASS2)))
+ (FLOAT_CLASS_P (CLASS1) != FLOAT_CLASS_P (CLASS2))
+
+/* QImode spills from non-QI registers need a scratch. This does not
+ happen often -- the only example so far requires an uninitialized
+ pseudo. */
+
+#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,OUT) \
+ ((CLASS) == GENERAL_REGS && (MODE) == QImode ? Q_REGS : NO_REGS)
/* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS. */
@@ -1012,6 +1036,17 @@ enum reg_class
|| ((CLASS) == SIREG) \
|| ((CLASS) == DIREG))
+/* A C statement that adds to CLOBBERS any hard regs the port wishes
+ to automatically clobber for all asms.
+
+ We do this in the new i386 backend to maintain source compatibility
+ with the old cc0-based compiler. */
+
+#define MD_ASM_CLOBBERS(CLOBBERS) \
+ do { \
+ (CLOBBERS) = tree_cons (NULL_TREE, build_string (5, "flags"), (CLOBBERS));\
+ (CLOBBERS) = tree_cons (NULL_TREE, build_string (4, "fpsr"), (CLOBBERS)); \
+ } while (0)
/* Stack layout; function entry, exit and calling. */
@@ -1060,7 +1095,7 @@ enum reg_class
The attribute stdcall is equivalent to RTD on a per module basis. */
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \
- (i386_return_pops_args (FUNDECL, FUNTYPE, SIZE))
+ (ix86_return_pops_args (FUNDECL, FUNTYPE, SIZE))
/* Define how to find the value returned by a function.
VALTYPE is the data type of the value (as a tree).
@@ -1091,7 +1126,7 @@ enum reg_class
and about the args processed so far, enough to enable macros
such as FUNCTION_ARG to determine where the next arg should go. */
-typedef struct i386_args {
+typedef struct ix86_args {
int words; /* # words passed so far */
int nregs; /* # registers available for passing */
int regno; /* next available register number */
@@ -1131,8 +1166,7 @@ typedef struct i386_args {
this is the number of registers used.
For args passed entirely in registers or entirely in memory, zero. */
-#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
- (function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED))
+#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0
/* This macro is invoked just before the start of a function.
It is used here to output code for -fpic that will load the
@@ -1142,17 +1176,6 @@ typedef struct i386_args {
#define ASM_OUTPUT_FUNCTION_PREFIX(FILE, FNNAME) \
asm_output_function_prefix (FILE, FNNAME)
-/* This macro generates the assembly code for function entry.
- FILE is a stdio stream to output the code to.
- SIZE is an int: how many units of temporary storage to allocate.
- Refer to the array `regs_ever_live' to determine which registers
- to save; `regs_ever_live[I]' is nonzero if register number I
- is ever used in the function. This macro is responsible for
- knowing which registers should not be saved even if used. */
-
-#define FUNCTION_PROLOGUE(FILE, SIZE) \
- function_prologue (FILE, SIZE)
-
/* Output assembler code to FILE to increment profiler label # LABELNO
for profiling a function entry. */
@@ -1160,14 +1183,14 @@ typedef struct i386_args {
{ \
if (flag_pic) \
{ \
- fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \
+ fprintf (FILE, "\tleal\t%sP%d@GOTOFF(%%ebx),%%edx\n", \
LPREFIX, (LABELNO)); \
- fprintf (FILE, "\tcall *_mcount@GOT(%%ebx)\n"); \
+ fprintf (FILE, "\tcall\t*_mcount@GOT(%%ebx)\n"); \
} \
else \
{ \
- fprintf (FILE, "\tmovl $%sP%d,%%edx\n", LPREFIX, (LABELNO)); \
- fprintf (FILE, "\tcall _mcount\n"); \
+ fprintf (FILE, "\tmovl\t$%sP%d,%%edx\n", LPREFIX, (LABELNO)); \
+ fprintf (FILE, "\tcall\t_mcount\n"); \
} \
}
@@ -1202,262 +1225,19 @@ typedef struct i386_args {
*/
/* The following macro shall output assembler code to FILE
- to initialize basic-block profiling.
-
- If profile_block_flag == 2
-
- Output code to call the subroutine `__bb_init_trace_func'
- and pass two parameters to it. The first parameter is
- the address of a block allocated in the object module.
- The second parameter is the number of the first basic block
- of the function.
-
- The name of the block is a local symbol made with this statement:
-
- ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
-
- Of course, since you are writing the definition of
- `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
- can take a short cut in the definition of this macro and use the
- name that you know will result.
-
- The number of the first basic block of the function is
- passed to the macro in BLOCK_OR_LABEL.
-
- If described in a virtual assembler language the code to be
- output looks like:
-
- parameter1 <- LPBX0
- parameter2 <- BLOCK_OR_LABEL
- call __bb_init_trace_func
-
- else if profile_block_flag != 0
-
- Output code to call the subroutine `__bb_init_func'
- and pass one single parameter to it, which is the same
- as the first parameter to `__bb_init_trace_func'.
-
- The first word of this parameter is a flag which will be nonzero if
- the object module has already been initialized. So test this word
- first, and do not call `__bb_init_func' if the flag is nonzero.
- Note: When profile_block_flag == 2 the test need not be done
- but `__bb_init_trace_func' *must* be called.
-
- BLOCK_OR_LABEL may be used to generate a label number as a
- branch destination in case `__bb_init_func' will not be called.
-
- If described in a virtual assembler language the code to be
- output looks like:
-
- cmp (LPBX0),0
- jne local_label
- parameter1 <- LPBX0
- call __bb_init_func
-local_label:
-
-*/
+ to initialize basic-block profiling. */
#undef FUNCTION_BLOCK_PROFILER
-#define FUNCTION_BLOCK_PROFILER(FILE, BLOCK_OR_LABEL) \
-do \
- { \
- static int num_func = 0; \
- rtx xops[8]; \
- char block_table[80], false_label[80]; \
- \
- ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0); \
- \
- xops[1] = gen_rtx_SYMBOL_REF (VOIDmode, block_table); \
- xops[5] = stack_pointer_rtx; \
- xops[7] = gen_rtx_REG (Pmode, 0); /* eax */ \
- \
- CONSTANT_POOL_ADDRESS_P (xops[1]) = TRUE; \
- \
- switch (profile_block_flag) \
- { \
- \
- case 2: \
- \
- xops[2] = GEN_INT ((BLOCK_OR_LABEL)); \
- xops[3] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, "__bb_init_trace_func")); \
- xops[6] = GEN_INT (8); \
- \
- output_asm_insn (AS1(push%L2,%2), xops); \
- if (!flag_pic) \
- output_asm_insn (AS1(push%L1,%1), xops); \
- else \
- { \
- output_asm_insn (AS2 (lea%L7,%a1,%7), xops); \
- output_asm_insn (AS1 (push%L7,%7), xops); \
- } \
- \
- output_asm_insn (AS1(call,%P3), xops); \
- output_asm_insn (AS2(add%L0,%6,%5), xops); \
- \
- break; \
- \
- default: \
- \
- ASM_GENERATE_INTERNAL_LABEL (false_label, "LPBZ", num_func); \
- \
- xops[0] = const0_rtx; \
- xops[2] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, false_label)); \
- xops[3] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, "__bb_init_func")); \
- xops[4] = gen_rtx_MEM (Pmode, xops[1]); \
- xops[6] = GEN_INT (4); \
- \
- CONSTANT_POOL_ADDRESS_P (xops[2]) = TRUE; \
- \
- output_asm_insn (AS2(cmp%L4,%0,%4), xops); \
- output_asm_insn (AS1(jne,%2), xops); \
- \
- if (!flag_pic) \
- output_asm_insn (AS1(push%L1,%1), xops); \
- else \
- { \
- output_asm_insn (AS2 (lea%L7,%a1,%7), xops); \
- output_asm_insn (AS1 (push%L7,%7), xops); \
- } \
- \
- output_asm_insn (AS1(call,%P3), xops); \
- output_asm_insn (AS2(add%L0,%6,%5), xops); \
- ASM_OUTPUT_INTERNAL_LABEL (FILE, "LPBZ", num_func); \
- num_func++; \
- \
- break; \
- \
- } \
- } \
-while (0)
+#define FUNCTION_BLOCK_PROFILER(FILE, BLOCK_OR_LABEL) \
+ ix86_output_function_block_profiler (FILE, BLOCK_OR_LABEL)
/* The following macro shall output assembler code to FILE
- to increment a counter associated with basic block number BLOCKNO.
-
- If profile_block_flag == 2
-
- Output code to initialize the global structure `__bb' and
- call the function `__bb_trace_func' which will increment the
- counter.
-
- `__bb' consists of two words. In the first word the number
- of the basic block has to be stored. In the second word
- the address of a block allocated in the object module
- has to be stored.
-
- The basic block number is given by BLOCKNO.
-
- The address of the block is given by the label created with
+ to increment a counter associated with basic block number BLOCKNO. */
- ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
-
- by FUNCTION_BLOCK_PROFILER.
-
- Of course, since you are writing the definition of
- `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
- can take a short cut in the definition of this macro and use the
- name that you know will result.
-
- If described in a virtual assembler language the code to be
- output looks like:
-
- move BLOCKNO -> (__bb)
- move LPBX0 -> (__bb+4)
- call __bb_trace_func
-
- Note that function `__bb_trace_func' must not change the
- machine state, especially the flag register. To grant
- this, you must output code to save and restore registers
- either in this macro or in the macros MACHINE_STATE_SAVE
- and MACHINE_STATE_RESTORE. The last two macros will be
- used in the function `__bb_trace_func', so you must make
- sure that the function prologue does not change any
- register prior to saving it with MACHINE_STATE_SAVE.
-
- else if profile_block_flag != 0
-
- Output code to increment the counter directly.
- Basic blocks are numbered separately from zero within each
- compiled object module. The count associated with block number
- BLOCKNO is at index BLOCKNO in an array of words; the name of
- this array is a local symbol made with this statement:
-
- ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 2);
-
- Of course, since you are writing the definition of
- `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
- can take a short cut in the definition of this macro and use the
- name that you know will result.
-
- If described in a virtual assembler language the code to be
- output looks like:
-
- inc (LPBX2+4*BLOCKNO)
-
-*/
-
-#define BLOCK_PROFILER(FILE, BLOCKNO) \
-do \
- { \
- rtx xops[8], cnt_rtx; \
- char counts[80]; \
- char *block_table = counts; \
- \
- switch (profile_block_flag) \
- { \
- \
- case 2: \
- \
- ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0); \
- \
- xops[1] = gen_rtx_SYMBOL_REF (VOIDmode, block_table); \
- xops[2] = GEN_INT ((BLOCKNO)); \
- xops[3] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, "__bb_trace_func")); \
- xops[4] = gen_rtx_SYMBOL_REF (VOIDmode, "__bb"); \
- xops[5] = plus_constant (xops[4], 4); \
- xops[0] = gen_rtx_MEM (SImode, xops[4]); \
- xops[6] = gen_rtx_MEM (SImode, xops[5]); \
- \
- CONSTANT_POOL_ADDRESS_P (xops[1]) = TRUE; \
- \
- fprintf(FILE, "\tpushf\n"); \
- output_asm_insn (AS2(mov%L0,%2,%0), xops); \
- if (flag_pic) \
- { \
- xops[7] = gen_rtx_REG (Pmode, 0); /* eax */ \
- output_asm_insn (AS1(push%L7,%7), xops); \
- output_asm_insn (AS2(lea%L7,%a1,%7), xops); \
- output_asm_insn (AS2(mov%L6,%7,%6), xops); \
- output_asm_insn (AS1(pop%L7,%7), xops); \
- } \
- else \
- output_asm_insn (AS2(mov%L6,%1,%6), xops); \
- output_asm_insn (AS1(call,%P3), xops); \
- fprintf(FILE, "\tpopf\n"); \
- \
- break; \
- \
- default: \
- \
- ASM_GENERATE_INTERNAL_LABEL (counts, "LPBX", 2); \
- cnt_rtx = gen_rtx_SYMBOL_REF (VOIDmode, counts); \
- SYMBOL_REF_FLAG (cnt_rtx) = TRUE; \
- \
- if (BLOCKNO) \
- cnt_rtx = plus_constant (cnt_rtx, (BLOCKNO)*4); \
- \
- if (flag_pic) \
- cnt_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, cnt_rtx); \
- \
- xops[0] = gen_rtx_MEM (SImode, cnt_rtx); \
- output_asm_insn (AS1(inc%L0,%0), xops); \
- \
- break; \
- \
- } \
- } \
-while (0)
+#define BLOCK_PROFILER(FILE, BLOCKNO) \
+ ix86_output_block_profiler (FILE, BLOCKNO)
-/* The following macro shall output assembler code to FILE
+/* The following macro shall output rtl for the epilogue
to indicate a return from function during basic-block profiling.
If profiling_block_flag == 2:
@@ -1479,17 +1259,10 @@ while (0)
these cases.
*/
-#define FUNCTION_BLOCK_PROFILER_EXIT(FILE) \
-do \
- { \
- rtx xops[1]; \
- \
- xops[0] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, "__bb_trace_ret")); \
- \
- output_asm_insn (AS1(call,%P0), xops); \
- \
- } \
-while (0)
+#define FUNCTION_BLOCK_PROFILER_EXIT \
+emit_call_insn (gen_call (gen_rtx_MEM (Pmode, \
+ gen_rtx_SYMBOL_REF (VOIDmode, "__bb_trace_ret")), \
+ const0_rtx))
/* The function `__bb_trace_func' is called in every basic block
and is not allowed to change the machine state. Saving (restoring)
@@ -1512,17 +1285,33 @@ while (0)
therefore we handle save and restore of the flag register
in the BLOCK_PROFILER macro. */
-#define MACHINE_STATE_SAVE(ID) \
- asm (" pushl %eax"); \
- asm (" pushl %ecx"); \
- asm (" pushl %edx"); \
- asm (" pushl %esi");
-
-#define MACHINE_STATE_RESTORE(ID) \
- asm (" popl %esi"); \
- asm (" popl %edx"); \
- asm (" popl %ecx"); \
- asm (" popl %eax");
+#define MACHINE_STATE_SAVE(ID) \
+do { \
+ register int eax_ __asm__("eax"); \
+ register int ecx_ __asm__("ecx"); \
+ register int edx_ __asm__("edx"); \
+ register int esi_ __asm__("esi"); \
+ __asm__ __volatile__ ( \
+ "push{l} %0\n\t" \
+ "push{l} %1\n\t" \
+ "push{l} %2\n\t" \
+ "push{l} %3" \
+ : : "r"(eax_), "r"(ecx_), "r"(edx_), "r"(esi_)); \
+} while (0);
+
+#define MACHINE_STATE_RESTORE(ID) \
+do { \
+ register int eax_ __asm__("eax"); \
+ register int ecx_ __asm__("ecx"); \
+ register int edx_ __asm__("edx"); \
+ register int esi_ __asm__("esi"); \
+ __asm__ __volatile__ ( \
+ "pop{l} %3\n\t" \
+ "pop{l} %2\n\t" \
+ "pop{l} %1\n\t" \
+ "pop{l} %0" \
+ : "=r"(eax_), "=r"(ecx_), "=r"(edx_), "=r"(esi_)); \
+} while (0);
/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
the stack pointer does not matter. The value is tested only in
@@ -1534,35 +1323,6 @@ while (0)
#define EXIT_IGNORE_STACK 1
-/* This macro generates the assembly code for function exit,
- on machines that need it. If FUNCTION_EPILOGUE is not defined
- then individual return instructions are generated for each
- return statement. Args are same as for FUNCTION_PROLOGUE.
-
- The function epilogue should not depend on the current stack pointer!
- It should use the frame pointer only. This is mandatory because
- of alloca; we also take advantage of it to omit stack adjustments
- before returning.
-
- If the last non-note insn in the function is a BARRIER, then there
- is no need to emit a function prologue, because control does not fall
- off the end. This happens if the function ends in an "exit" call, or
- if a `return' insn is emitted directly into the function. */
-
-#if 0
-#define FUNCTION_BEGIN_EPILOGUE(FILE) \
-do { \
- rtx last = get_last_insn (); \
- if (last && GET_CODE (last) == NOTE) \
- last = prev_nonnote_insn (last); \
-/* if (! last || GET_CODE (last) != BARRIER) \
- function_epilogue (FILE, SIZE);*/ \
-} while (0)
-#endif
-
-#define FUNCTION_EPILOGUE(FILE, SIZE) \
- function_epilogue (FILE, SIZE)
-
/* Output assembler code for a block containing the constant parts
of a trampoline, leaving space for the variable parts. */
@@ -1797,8 +1557,9 @@ do { \
when generating PIC code. It is given that flag_pic is on and
that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
-#define LEGITIMATE_PIC_OPERAND_P(X) \
- (! SYMBOLIC_CONST (X) || legitimate_pic_address_disp_p (X))
+#define LEGITIMATE_PIC_OPERAND_P(X) \
+ (! SYMBOLIC_CONST (X) \
+ || legitimate_pic_address_disp_p (X))
#define SYMBOLIC_CONST(X) \
(GET_CODE (X) == SYMBOL_REF \
@@ -1869,14 +1630,14 @@ while (0)
The attributes in ATTRIBUTES have previously been assigned to DECL. */
#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, NAME, ARGS) \
- (i386_valid_decl_attribute_p (DECL, ATTRIBUTES, NAME, ARGS))
+ (ix86_valid_decl_attribute_p (DECL, ATTRIBUTES, NAME, ARGS))
/* If defined, a C expression whose value is nonzero if IDENTIFIER
with arguments ARGS is a valid machine specific attribute for TYPE.
The attributes in ATTRIBUTES have previously been assigned to TYPE. */
#define VALID_MACHINE_TYPE_ATTRIBUTE(TYPE, ATTRIBUTES, NAME, ARGS) \
- (i386_valid_type_attribute_p (TYPE, ATTRIBUTES, NAME, ARGS))
+ (ix86_valid_type_attribute_p (TYPE, ATTRIBUTES, NAME, ARGS))
/* If defined, a C expression whose value is zero if the attributes on
TYPE1 and TYPE2 are incompatible, one if they are compatible, and
@@ -1884,7 +1645,7 @@ while (0)
generated). */
#define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \
- (i386_comp_type_attributes (TYPE1, TYPE2))
+ (ix86_comp_type_attributes (TYPE1, TYPE2))
/* If defined, a C statement that assigns default attributes to newly
defined TYPE. */
@@ -2002,7 +1763,8 @@ while (0)
}
/* Delete the definition here when TOPLEVEL_COSTS_N_INSNS gets added to cse.c */
-#define TOPLEVEL_COSTS_N_INSNS(N) {total = COSTS_N_INSNS (N); break;}
+#define TOPLEVEL_COSTS_N_INSNS(N) \
+ do { total = COSTS_N_INSNS (N); goto egress_rtx_costs; } while (0)
/* Like `CONST_COSTS' but applies to nonconstant RTL expressions.
This can be used, for example, to indicate how costly a multiply
@@ -2020,14 +1782,10 @@ while (0)
&& GET_MODE (XEXP (X, 0)) == SImode) \
{ \
HOST_WIDE_INT value = INTVAL (XEXP (X, 1)); \
- \
if (value == 1) \
- return COSTS_N_INSNS (ix86_cost->add) \
- + rtx_cost(XEXP (X, 0), OUTER_CODE); \
- \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->add); \
if (value == 2 || value == 3) \
- return COSTS_N_INSNS (ix86_cost->lea) \
- + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->lea); \
} \
/* fall through */ \
\
@@ -2040,18 +1798,26 @@ while (0)
if (GET_CODE (XEXP (X, 1)) == CONST_INT) \
{ \
if (INTVAL (XEXP (X, 1)) > 32) \
- return COSTS_N_INSNS(ix86_cost->shift_const + 2); \
- return COSTS_N_INSNS(ix86_cost->shift_const * 2); \
+ TOPLEVEL_COSTS_N_INSNS(ix86_cost->shift_const + 2); \
+ else \
+ TOPLEVEL_COSTS_N_INSNS(ix86_cost->shift_const * 2); \
+ } \
+ else \
+ { \
+ if (GET_CODE (XEXP (X, 1)) == AND) \
+ TOPLEVEL_COSTS_N_INSNS(ix86_cost->shift_var * 2); \
+ else \
+ TOPLEVEL_COSTS_N_INSNS(ix86_cost->shift_var * 6 + 2); \
} \
- return ((GET_CODE (XEXP (X, 1)) == AND \
- ? COSTS_N_INSNS(ix86_cost->shift_var * 2) \
- : COSTS_N_INSNS(ix86_cost->shift_var * 6 + 2)) \
- + rtx_cost(XEXP (X, 0), OUTER_CODE)); \
} \
- return COSTS_N_INSNS (GET_CODE (XEXP (X, 1)) == CONST_INT \
- ? ix86_cost->shift_const \
- : ix86_cost->shift_var) \
- + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ else \
+ { \
+ if (GET_CODE (XEXP (X, 1)) == CONST_INT) \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->shift_const); \
+ else \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->shift_var); \
+ } \
+ break; \
\
case MULT: \
if (GET_CODE (XEXP (X, 1)) == CONST_INT) \
@@ -2060,11 +1826,9 @@ while (0)
int nbits = 0; \
\
if (value == 2) \
- return COSTS_N_INSNS (ix86_cost->add) \
- + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->add); \
if (value == 4 || value == 8) \
- return COSTS_N_INSNS (ix86_cost->lea) \
- + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->lea); \
\
while (value != 0) \
{ \
@@ -2073,14 +1837,11 @@ while (0)
} \
\
if (nbits == 1) \
- return COSTS_N_INSNS (ix86_cost->shift_const) \
- + rtx_cost(XEXP (X, 0), OUTER_CODE); \
- \
- return COSTS_N_INSNS (ix86_cost->mult_init \
- + nbits * ix86_cost->mult_bit) \
- + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->shift_const); \
+ else \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->mult_init \
+ + nbits * ix86_cost->mult_bit); \
} \
- \
else /* This is arbitrary */ \
TOPLEVEL_COSTS_N_INSNS (ix86_cost->mult_init \
+ 7 * ix86_cost->mult_bit); \
@@ -2092,10 +1853,38 @@ while (0)
TOPLEVEL_COSTS_N_INSNS (ix86_cost->divide); \
\
case PLUS: \
- if (GET_CODE (XEXP (X, 0)) == REG \
- && GET_MODE (XEXP (X, 0)) == SImode \
- && GET_CODE (XEXP (X, 1)) == PLUS) \
- return COSTS_N_INSNS (ix86_cost->lea); \
+ if (GET_CODE (XEXP (X, 0)) == PLUS \
+ && GET_CODE (XEXP (XEXP (X, 0), 0)) == MULT \
+ && GET_CODE (XEXP (XEXP (XEXP (X, 0), 0), 1)) == CONST_INT \
+ && GET_CODE (XEXP (X, 1)) == CONST_INT) \
+ { \
+ HOST_WIDE_INT val = INTVAL (XEXP (XEXP (XEXP (X, 0), 0), 1)); \
+ if (val == 2 || val == 4 || val == 8) \
+ { \
+ return (COSTS_N_INSNS (ix86_cost->lea) \
+ + rtx_cost (XEXP (XEXP (X, 0), 1), OUTER_CODE) \
+ + rtx_cost (XEXP (XEXP (XEXP (X, 0), 0), 0), OUTER_CODE) \
+ + rtx_cost (XEXP (X, 1), OUTER_CODE)); \
+ } \
+ } \
+ else if (GET_CODE (XEXP (X, 0)) == MULT \
+ && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT) \
+ { \
+ HOST_WIDE_INT val = INTVAL (XEXP (XEXP (X, 0), 1)); \
+ if (val == 2 || val == 4 || val == 8) \
+ { \
+ return (COSTS_N_INSNS (ix86_cost->lea) \
+ + rtx_cost (XEXP (XEXP (X, 0), 0), OUTER_CODE) \
+ + rtx_cost (XEXP (X, 1), OUTER_CODE)); \
+ } \
+ } \
+ else if (GET_CODE (XEXP (X, 0)) == PLUS) \
+ { \
+ return (COSTS_N_INSNS (ix86_cost->lea) \
+ + rtx_cost (XEXP (XEXP (X, 0), 0), OUTER_CODE) \
+ + rtx_cost (XEXP (XEXP (X, 0), 1), OUTER_CODE) \
+ + rtx_cost (XEXP (X, 1), OUTER_CODE)); \
+ } \
\
/* fall through */ \
case AND: \
@@ -2103,16 +1892,21 @@ while (0)
case XOR: \
case MINUS: \
if (GET_MODE (X) == DImode) \
- return COSTS_N_INSNS (ix86_cost->add) * 2 \
- + (rtx_cost (XEXP (X, 0), OUTER_CODE) \
- << (GET_MODE (XEXP (X, 0)) != DImode)) \
- + (rtx_cost (XEXP (X, 1), OUTER_CODE) \
- << (GET_MODE (XEXP (X, 1)) != DImode)); \
+ return (COSTS_N_INSNS (ix86_cost->add) * 2 \
+ + (rtx_cost (XEXP (X, 0), OUTER_CODE) \
+ << (GET_MODE (XEXP (X, 0)) != DImode)) \
+ + (rtx_cost (XEXP (X, 1), OUTER_CODE) \
+ << (GET_MODE (XEXP (X, 1)) != DImode))); \
+ \
+ /* fall through */ \
case NEG: \
case NOT: \
if (GET_MODE (X) == DImode) \
- TOPLEVEL_COSTS_N_INSNS (ix86_cost->add * 2) \
- TOPLEVEL_COSTS_N_INSNS (ix86_cost->add)
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->add * 2); \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->add); \
+ \
+ egress_rtx_costs: \
+ break;
/* An expression giving the cost of an addressing mode that contains
@@ -2198,7 +1992,7 @@ while (0)
/* A C expression for the cost of a branch instruction. A value of 1
is the default; other values are interpreted relative to that. */
-#define BRANCH_COST i386_branch_cost
+#define BRANCH_COST ix86_branch_cost
/* Define this macro as a C expression which is nonzero if accessing
less than a word of memory (i.e. a `char' or a `short') is no
@@ -2273,94 +2067,51 @@ while (0)
the scheduler that an output- or anti-dependence does not incur
the same cost as a data-dependence. */
-#define ADJUST_COST(insn,link,dep_insn,cost) \
- (cost) = x86_adjust_cost(insn, link, dep_insn, cost)
+#define ADJUST_COST(insn,link,dep_insn,cost) \
+ (cost) = ix86_adjust_cost(insn, link, dep_insn, cost)
-#define ADJUST_BLOCKAGE(last_insn,insn,blockage) \
-{ \
- if (is_fp_store (last_insn) && is_fp_insn (insn) \
- && NEXT_INSN (last_insn) && NEXT_INSN (NEXT_INSN (last_insn)) \
- && NEXT_INSN (NEXT_INSN (NEXT_INSN (last_insn))) \
- && (GET_CODE (NEXT_INSN (last_insn)) == INSN) \
- && (GET_CODE (NEXT_INSN (NEXT_INSN (last_insn))) == JUMP_INSN) \
- && (GET_CODE (NEXT_INSN (NEXT_INSN (NEXT_INSN (last_insn)))) == NOTE) \
- && (NOTE_LINE_NUMBER (NEXT_INSN (NEXT_INSN (NEXT_INSN (last_insn)))) \
- == NOTE_INSN_LOOP_END)) \
- { \
- (blockage) = 3; \
- } \
-}
+#define ISSUE_RATE \
+ ix86_issue_rate ()
+
+#define MD_SCHED_INIT(DUMP, SCHED_VERBOSE) \
+ ix86_sched_init (DUMP, SCHED_VERBOSE)
-#define ISSUE_RATE ((int)ix86_cpu > (int)PROCESSOR_I486 ? 2 : 1)
+#define MD_SCHED_REORDER(DUMP, SCHED_VERBOSE, READY, N_READY, CLOCK, CIM) \
+ (CIM) = ix86_sched_reorder (DUMP, SCHED_VERBOSE, READY, N_READY, CLOCK)
+#define MD_SCHED_VARIABLE_ISSUE(DUMP, SCHED_VERBOSE, INSN, CAN_ISSUE_MORE) \
+ ((CAN_ISSUE_MORE) = \
+ ix86_variable_issue (DUMP, SCHED_VERBOSE, INSN, CAN_ISSUE_MORE))
/* Add any extra modes needed to represent the condition code.
- For the i386, we need separate modes when floating-point equality
- comparisons are being done. */
+ For the i386, we need separate modes when floating-point
+ equality comparisons are being done.
+
+ Add CCNO to indicate No Overflow, which is often also includes
+ No Carry. This is typically used on the output of logicals,
+ and is only valid in comparisons against zero. */
-#define EXTRA_CC_MODES CC(CCFPEQmode, "CCFPEQ")
+#define EXTRA_CC_MODES \
+ CC(CCNOmode, "CCNO") \
+ CC(CCFPmode, "CCFP") \
+ CC(CCFPUmode, "CCFPU")
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison.
For floating-point equality comparisons, CCFPEQmode should be used.
- VOIDmode should be used in all other cases. */
-
-#define SELECT_CC_MODE(OP,X,Y) \
- (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
- && ((OP) == EQ || (OP) == NE) ? CCFPEQmode : VOIDmode)
-
-/* Define the information needed to generate branch and scc insns. This is
- stored from the compare operation. Note that we can't use "rtx" here
- since it hasn't been defined! */
-
-extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
+ VOIDmode should be used in all other cases.
-/* Tell final.c how to eliminate redundant test instructions. */
+ For integer comparisons against zero, reduce to CCNOmode if
+ possible, to allow for more combinations. */
-/* Here we define machine-dependent flags and fields in cc_status
- (see `conditions.h'). */
-
-/* Set if the cc value was actually from the 80387 and
- we are testing eax directly (i.e. no sahf) */
-#define CC_TEST_AX 020000
-
-/* Set if the cc value is actually in the 80387, so a floating point
- conditional branch must be output. */
-#define CC_IN_80387 04000
-
-/* Set if the CC value was stored in a nonstandard way, so that
- the state of equality is indicated by zero in the carry bit. */
-#define CC_Z_IN_NOT_C 010000
-
-/* Set if the CC value was actually from the 80387 and loaded directly
- into the eflags instead of via eax/sahf. */
-#define CC_FCOMI 040000
-
-/* Store in cc_status the expressions
- that the condition codes will describe
- after execution of an instruction whose pattern is EXP.
- Do not alter them if the instruction would not alter the cc's. */
-
-#define NOTICE_UPDATE_CC(EXP, INSN) \
- notice_update_cc((EXP))
-
-/* Output a signed jump insn. Use template NORMAL ordinarily, or
- FLOAT following a floating point comparison.
- Use NO_OV following an arithmetic insn that set the cc's
- before a test insn that was deleted.
- NO_OV may be zero, meaning final should reinsert the test insn
- because the jump cannot be handled properly without it. */
-
-#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \
-{ \
- if (cc_prev_status.flags & CC_IN_80387) \
- return FLOAT; \
- if (cc_prev_status.flags & CC_NO_OVERFLOW) \
- return NO_OV; \
- return NORMAL; \
-}
+#define SELECT_CC_MODE(OP,X,Y) \
+ (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
+ ? (OP) == EQ || (OP) == NE ? CCFPUmode : CCFPmode \
+ : (OP) == LE || (OP) == GT ? CCmode \
+ : (Y) != const0_rtx ? CCmode \
+ : CCNOmode)
/* Control the assembler format that we output, to the extent
this does not vary between assemblers. */
@@ -2374,9 +2125,10 @@ extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
For float regs, the stack top is sometimes referred to as "%st(0)"
instead of just "%st". PRINT_REG handles this with the "y" code. */
-#define HI_REGISTER_NAMES \
-{"ax","dx","cx","bx","si","di","bp","sp", \
- "st","st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)","" }
+#define HI_REGISTER_NAMES \
+{"ax","dx","cx","bx","si","di","bp","sp", \
+ "st","st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)","", \
+ "flags","fpsr" }
#define REGISTER_NAMES HI_REGISTER_NAMES
@@ -2447,7 +2199,7 @@ number as al, and ax.
#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
do { long l[2]; \
REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \
- fprintf (FILE, "%s 0x%lx,0x%lx\n", ASM_LONG, l[0], l[1]); \
+ fprintf (FILE, "%s\t0x%lx,0x%lx\n", ASM_LONG, l[0], l[1]); \
} while (0)
/* This is how to output a `long double' extended real constant. */
@@ -2456,7 +2208,7 @@ do { long l[2]; \
#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \
do { long l[3]; \
REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \
- fprintf (FILE, "%s 0x%lx,0x%lx,0x%lx\n", ASM_LONG, l[0], l[1], l[2]); \
+ fprintf (FILE, "%s\t0x%lx,0x%lx,0x%lx\n", ASM_LONG, l[0], l[1], l[2]); \
} while (0)
/* This is how to output an assembler line defining a `float' constant. */
@@ -2464,7 +2216,7 @@ do { long l[3]; \
#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
do { long l; \
REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \
- fprintf ((FILE), "%s 0x%lx\n", ASM_LONG, l); \
+ fprintf ((FILE), "%s\t0x%lx\n", ASM_LONG, l); \
} while (0)
/* Store in OUTPUT a string (made with alloca) containing
@@ -2475,12 +2227,10 @@ do { long l; \
( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO)))
-
-
/* This is how to output an assembler line defining an `int' constant. */
#define ASM_OUTPUT_INT(FILE,VALUE) \
-( fprintf (FILE, "%s ", ASM_LONG), \
+( fprintf (FILE, "%s\t", ASM_LONG), \
output_addr_const (FILE,(VALUE)), \
putc('\n',FILE))
@@ -2488,41 +2238,31 @@ do { long l; \
/* is this supposed to do align too?? */
#define ASM_OUTPUT_SHORT(FILE,VALUE) \
-( fprintf (FILE, "%s ", ASM_SHORT), \
+( fprintf (FILE, "%s\t", ASM_SHORT), \
output_addr_const (FILE,(VALUE)), \
putc('\n',FILE))
-/*
-#define ASM_OUTPUT_SHORT(FILE,VALUE) \
-( fprintf (FILE, "%s ", ASM_BYTE_OP), \
- output_addr_const (FILE,(VALUE)), \
- fputs (",", FILE), \
- output_addr_const (FILE,(VALUE)), \
- fputs (" >> 8\n",FILE))
-*/
-
-
#define ASM_OUTPUT_CHAR(FILE,VALUE) \
-( fprintf (FILE, "%s ", ASM_BYTE_OP), \
+( fprintf (FILE, "%s\t", ASM_BYTE_OP), \
output_addr_const (FILE, (VALUE)), \
putc ('\n', FILE))
/* This is how to output an assembler line for a numeric constant byte. */
#define ASM_OUTPUT_BYTE(FILE,VALUE) \
- fprintf ((FILE), "%s 0x%x\n", ASM_BYTE_OP, (VALUE))
+ asm_fprintf ((FILE), "%s\t0x%x\n", ASM_BYTE_OP, (VALUE))
/* This is how to output an insn to push a register on the stack.
It need not be very fast code. */
#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \
- fprintf (FILE, "\tpushl %%e%s\n", reg_names[REGNO])
+ asm_fprintf (FILE, "\tpush{l}\t%%e%s\n", reg_names[REGNO])
/* This is how to output an insn to pop a register from the stack.
It need not be very fast code. */
#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
- fprintf (FILE, "\tpopl %%e%s\n", reg_names[REGNO])
+ asm_fprintf (FILE, "\tpop{l}\t%%e%s\n", reg_names[REGNO])
/* This is how to output an element of a case-vector that is absolute.
*/
@@ -2536,7 +2276,7 @@ do { long l; \
*/
#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
- fprintf (FILE, "\t.word %s%d-%s%d\n",LPREFIX, VALUE,LPREFIX, REL)
+ fprintf (FILE, "\t%s\t%s%d-%s%d\n",ASM_LONG, LPREFIX, VALUE, LPREFIX, REL)
/* Define the parentheses used to group arithmetic operations
in assembler code. */
@@ -2566,14 +2306,13 @@ do { long l; \
* -- print a star (in certain assembler syntax)
P -- if PIC, print an @PLT suffix.
X -- don't print any sort of PIC '@' suffix for a symbol.
- J -- print jump insn for arithmetic_comparison_operator.
s -- ??? something to do with double shifts. not actually used, afaik.
C -- print a conditional move suffix corresponding to the op code.
c -- likewise, but reverse the condition.
F,f -- likewise, but for floating-point. */
#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
- ((CODE) == '*' || (CODE) == '_')
+ ((CODE) == '*')
/* Print the name of a register based on its machine mode and number.
If CODE is 'w', pretend the mode is HImode.
@@ -2582,42 +2321,8 @@ do { long l; \
If CODE is 'h', pretend the reg is the `high' byte register.
If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op. */
-extern char *hi_reg_name[];
-extern char *qi_reg_name[];
-extern char *qi_high_reg_name[];
-
-#define PRINT_REG(X, CODE, FILE) \
- do { if (REGNO (X) == ARG_POINTER_REGNUM) \
- abort (); \
- fprintf (FILE, "%s", RP); \
- switch ((CODE == 'w' ? 2 \
- : CODE == 'b' ? 1 \
- : CODE == 'k' ? 4 \
- : CODE == 'y' ? 3 \
- : CODE == 'h' ? 0 \
- : GET_MODE_SIZE (GET_MODE (X)))) \
- { \
- case 3: \
- if (STACK_TOP_P (X)) \
- { \
- fputs ("st(0)", FILE); \
- break; \
- } \
- case 4: \
- case 8: \
- case 12: \
- if (! FP_REG_P (X)) fputs ("e", FILE); \
- case 2: \
- fputs (hi_reg_name[REGNO (X)], FILE); \
- break; \
- case 1: \
- fputs (qi_reg_name[REGNO (X)], FILE); \
- break; \
- case 0: \
- fputs (qi_high_reg_name[REGNO (X)], FILE); \
- break; \
- } \
- } while (0)
+#define PRINT_REG(X, CODE, FILE) \
+ print_reg (X, CODE, FILE)
#define PRINT_OPERAND(FILE, X, CODE) \
print_operand (FILE, X, CODE)
@@ -2630,10 +2335,14 @@ extern char *qi_high_reg_name[];
This macro is different from PRINT_REG in that it may be used in
programs that are not linked with aux-output.o. */
-#define DEBUG_PRINT_REG(X, CODE, FILE) \
+#define DEBUG_PRINT_REG(X, CODE, FILE) \
do { static char *hi_name[] = HI_REGISTER_NAMES; \
static char *qi_name[] = QI_REGISTER_NAMES; \
- fprintf (FILE, "%d %s", REGNO (X), RP); \
+ fprintf (FILE, "%d ", REGNO (X)); \
+ if (REGNO (X) == FLAGS_REG) \
+ { fputs ("flags", FILE); break; } \
+ if (REGNO (X) == FPSR_REG) \
+ { fputs ("fpsr", FILE); break; } \
if (REGNO (X) == ARG_POINTER_REGNUM) \
{ fputs ("argp", FILE); break; } \
if (STACK_TOP_P (X)) \
@@ -2653,10 +2362,6 @@ extern char *qi_high_reg_name[];
} \
} while (0)
-/* Output the prefix for an immediate operand, or for an offset operand. */
-#define PRINT_IMMED_PREFIX(FILE) fputs (IP, (FILE))
-#define PRINT_OFFSET_PREFIX(FILE) fputs (IP, (FILE))
-
/* Routines in libgcc that return floats must return them in an fp reg,
just as other functions do which return such values.
These macros make that happen. */
@@ -2664,13 +2369,6 @@ extern char *qi_high_reg_name[];
#define FLOAT_VALUE_TYPE float
#define INTIFY(FLOATVAL) FLOATVAL
-/* Nonzero if INSN magically clobbers register REGNO. */
-
-/* #define INSN_CLOBBERS_REGNO_P(INSN, REGNO) \
- (FP_REGNO_P (REGNO) \
- && (GET_CODE (INSN) == JUMP_INSN || GET_CODE (INSN) == BARRIER))
-*/
-
/* a letter which is not needed by the normal asm syntax, which
we can use for operand syntax in the extended asm */
@@ -2678,125 +2376,169 @@ extern char *qi_high_reg_name[];
#define RET return ""
#define AT_SP(mode) (gen_rtx_MEM ((mode), stack_pointer_rtx))
-/* Helper macros to expand a binary/unary operator if needed */
-#define IX86_EXPAND_BINARY_OPERATOR(OP, MODE, OPERANDS) \
-do { \
- if (!ix86_expand_binary_operator (OP, MODE, OPERANDS)) \
- FAIL; \
-} while (0)
-
-#define IX86_EXPAND_UNARY_OPERATOR(OP, MODE, OPERANDS) \
-do { \
- if (!ix86_expand_unary_operator (OP, MODE, OPERANDS,)) \
- FAIL; \
-} while (0)
-
+/* Define the codes that are matched by predicates in i386.c. */
+
+#define PREDICATE_CODES \
+ {"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}}, \
+ {"pic_symbolic_operand", {CONST}}, \
+ {"call_insn_operand", {MEM}}, \
+ {"expander_call_insn_operand", {MEM}}, \
+ {"constant_call_address_operand", {MEM}}, \
+ {"const0_operand", {CONST_INT, CONST_DOUBLE}}, \
+ {"const1_operand", {CONST_INT}}, \
+ {"const248_operand", {CONST_INT}}, \
+ {"incdec_operand", {CONST_INT}}, \
+ {"reg_no_sp_operand", {SUBREG, REG}}, \
+ {"q_regs_operand", {SUBREG, REG}}, \
+ {"non_q_regs_operand", {SUBREG, REG}}, \
+ {"no_comparison_operator", {EQ, NE, LT, GE, LTU, GTU, LEU, GEU}}, \
+ {"fcmov_comparison_operator", {EQ, NE, LTU, GTU, LEU, GEU}}, \
+ {"cmp_fp_expander_operand", {CONST_DOUBLE, SUBREG, REG, MEM}}, \
+ {"ext_register_operand", {SUBREG, REG}}, \
+ {"binary_fp_operator", {PLUS, MINUS, MULT, DIV}}, \
+ {"mult_operator", {MULT}}, \
+ {"div_operator", {DIV}}, \
+ {"arith_or_logical_operator", {PLUS, MULT, AND, IOR, XOR, SMIN, SMAX, \
+ UMIN, UMAX, COMPARE, MINUS, DIV, MOD, \
+ UDIV, UMOD, ASHIFT, ROTATE, ASHIFTRT, \
+ LSHIFTRT, ROTATERT}}, \
+ {"memory_displacement_operand", {MEM}}, \
+ {"cmpsi_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \
+ LABEL_REF, SUBREG, REG, MEM, AND}},
/* Functions in i386.c */
-extern void override_options ();
-extern void order_regs_for_local_alloc ();
-extern char *output_strlen_unroll ();
-extern struct rtx_def *i386_sext16_if_const ();
-extern int i386_aligned_p ();
-extern int i386_cc_probably_useless_p ();
-extern int i386_valid_decl_attribute_p ();
-extern int i386_valid_type_attribute_p ();
-extern int i386_return_pops_args ();
-extern int i386_comp_type_attributes ();
-extern void init_cumulative_args ();
-extern void function_arg_advance ();
-extern struct rtx_def *function_arg ();
-extern int function_arg_partial_nregs ();
-extern char *output_strlen_unroll ();
-extern char *singlemove_string ();
-extern char *output_move_double ();
-extern char *output_move_pushmem ();
-extern int standard_80387_constant_p ();
-extern char *output_move_const_single ();
-extern int symbolic_operand ();
-extern int call_insn_operand ();
-extern int expander_call_insn_operand ();
-extern int symbolic_reference_mentioned_p ();
-extern int ix86_expand_binary_operator ();
-extern int ix86_binary_operator_ok ();
-extern int ix86_expand_unary_operator ();
-extern int ix86_unary_operator_ok ();
-extern void emit_pic_move ();
-extern void function_prologue ();
-extern int simple_386_epilogue ();
-extern void function_epilogue ();
-extern int legitimate_address_p ();
-extern struct rtx_def *legitimize_pic_address ();
-extern struct rtx_def *legitimize_address ();
-extern void print_operand ();
-extern void print_operand_address ();
-extern void notice_update_cc ();
-extern void split_di ();
-extern int binary_387_op ();
-extern int shift_op ();
-extern int VOIDmode_compare_op ();
-extern char *output_387_binary_op ();
-extern char *output_fix_trunc ();
-extern void output_float_extend ();
-extern char *output_float_compare ();
-extern char *output_fp_cc0_set ();
-extern void save_386_machine_status ();
-extern void restore_386_machine_status ();
-extern void clear_386_stack_locals ();
-extern struct rtx_def *assign_386_stack_local ();
-extern int is_mul ();
-extern int is_div ();
-extern int last_to_set_cc ();
-extern int doesnt_set_condition_code ();
-extern int sets_condition_code ();
-extern int str_immediate_operand ();
-extern int is_fp_insn ();
-extern int is_fp_dest ();
-extern int is_fp_store ();
-extern int agi_dependent ();
-extern int reg_mentioned_in_mem ();
-extern char *output_int_conditional_move ();
-extern char *output_fp_conditional_move ();
-extern int ix86_can_use_return_insn_p ();
-extern int small_shift_operand ();
-extern char *output_ashl ();
-extern int memory_address_info ();
-
-#ifdef NOTYET
-extern struct rtx_def *copy_all_rtx ();
-extern void rewrite_address ();
+
+#if 1
+#define XPARAMS(x) ()
+#else
+#define XPARAMS(x) PROTO(x)
#endif
+#define xrtx struct rtx_def *
+#define xtree struct tree_def *
+#define xmode enum machine_mode
+#define xcode enum rtx_code
+
+extern void override_options XPARAMS((void));
+extern void order_regs_for_local_alloc XPARAMS((void));
+extern void optimization_options XPARAMS((int, int));
+extern int ix86_aligned_p XPARAMS((xrtx));
+extern int ix86_valid_decl_attribute_p XPARAMS((xtree, xtree, xtree, xtree));
+extern int ix86_valid_type_attribute_p XPARAMS((xtree, xtree, xtree, xtree));
+extern int ix86_comp_type_attributes XPARAMS((xtree, xtree));
+extern int ix86_return_pops_args XPARAMS((xtree, xtree, int));
+extern void init_cumulative_args XPARAMS((CUMULATIVE_ARGS*, xtree, xrtx));
+extern void function_arg_advance XPARAMS((CUMULATIVE_ARGS*,xmode,xtree,int));
+extern xrtx function_arg XPARAMS((CUMULATIVE_ARGS*, xmode, xtree, int));
+
+extern int symbolic_operand XPARAMS((xrtx, xmode));
+extern int pic_symbolic_operand XPARAMS((xrtx, xmode));
+extern int call_insn_operand XPARAMS((xrtx, xmode));
+extern int expander_call_insn_operand XPARAMS((xrtx, xmode));
+extern int constant_call_address_operand XPARAMS((xrtx, xmode));
+extern int const0_operand XPARAMS((xrtx, xmode));
+extern int const1_operand XPARAMS((xrtx, xmode));
+extern int const248_operand XPARAMS((xrtx, xmode));
+extern int incdec_operand XPARAMS((xrtx, xmode));
+extern int reg_no_sp_operand XPARAMS((xrtx, xmode));
+extern int q_regs_operand XPARAMS((xrtx, xmode));
+extern int non_q_regs_operand XPARAMS((xrtx, xmode));
+extern int no_comparison_operator XPARAMS((xrtx, xmode));
+extern int fcmov_comparison_operator XPARAMS((xrtx, xmode));
+extern int cmp_fp_expander_operand XPARAMS((xrtx, xmode));
+extern int ext_register_operand XPARAMS((xrtx, xmode));
+extern int binary_fp_operator XPARAMS((xrtx, xmode));
+extern int mult_operator XPARAMS((xrtx, xmode));
+extern int div_operator XPARAMS((xrtx, xmode));
+extern int arith_or_logical_operator XPARAMS((xrtx, xmode));
+extern int memory_displacement_operand XPARAMS((xrtx, xmode));
+extern int cmpsi_operand XPARAMS((xrtx, xmode));
+
+extern int standard_80387_constant_p XPARAMS((xrtx));
+extern int symbolic_reference_mentioned_p XPARAMS((xrtx));
+extern int ix86_can_use_return_insn_p XPARAMS((void));
+
+extern void asm_output_function_prefix XPARAMS((FILE, char *));
+extern void load_pic_register XPARAMS((void));
+#if 0
+/* HOST_WIDE_INT isn't defined yet. */
+extern HOST_WIDE_INT ix86_compute_frame_size XPARAMS ((HOST_WIDE_INT, int *));
+#endif
+extern void ix86_expand_prologue XPARAMS((void));
+extern void ix86_expand_epilogue XPARAMS((void));
+
+extern int legitimate_pic_address_disp_p XPARAMS((xrtx));
+extern int legitimate_address_p XPARAMS((xmode, xrtx, int));
+extern xrtx legitimize_pic_address XPARAMS((xrtx, xrtx));
+extern xrtx legitimize_address XPARAMS((xrtx, xrtx, xmode));
+
+extern void print_reg XPARAMS((xrtx, int, FILE*));
+extern void print_operand XPARAMS((FILE*, xrtx, int));
+extern void print_operand_address XPARAMS((FILE*, xrtx));
+
+extern void split_di XPARAMS((xrtx[], int, xrtx[], xrtx[]));
+
+extern char *output_387_binary_op XPARAMS((xrtx, xrtx*));
+extern char *output_fix_trunc XPARAMS((xrtx, xrtx*));
+extern char *output_fp_compare XPARAMS((xrtx, xrtx*, int, int));
+extern void ix86_output_function_block_profiler XPARAMS((FILE*, int));
+extern void ix86_output_block_profiler XPARAMS((FILE*, int));
+
+extern void ix86_expand_move XPARAMS((xmode, xrtx[]));
+extern void ix86_expand_binary_operator XPARAMS((xcode, xmode, xrtx[]));
+extern int ix86_binary_operator_ok XPARAMS((xcode, xmode, xrtx[]));
+extern int ix86_expand_unary_operator XPARAMS((xcode, xmode, xrtx[]));
+extern int ix86_unary_operator_ok XPARAMS((xcode, xmode, xrtx[]));
+extern void ix86_expand_branch XPARAMS((xcode, int, xrtx));
+extern int ix86_expand_setcc XPARAMS((xcode, int, xrtx));
+extern int ix86_expand_int_movcc XPARAMS((xrtx[]));
+extern int ix86_expand_fp_movcc XPARAMS((xrtx[]));
+extern int ix86_split_movdi XPARAMS((xrtx[]));
+extern void ix86_split_ashldi XPARAMS((xrtx *, xrtx));
+extern void ix86_split_ashrdi XPARAMS((xrtx *, xrtx));
+extern void ix86_split_lshrdi XPARAMS((xrtx *, xrtx));
+extern void ix86_expand_strlensi_unroll_1 XPARAMS((xrtx, xrtx, xrtx));
+
+extern void save_386_machine_status XPARAMS((struct function *));
+extern void restore_386_machine_status XPARAMS((struct function *));
+extern void clear_386_stack_locals XPARAMS((void));
+extern xrtx assign_386_stack_local XPARAMS((xmode, int));
+extern int ix86_attr_length_default XPARAMS((xrtx));
+
+extern int ix86_issue_rate XPARAMS((void));
+extern int ix86_adjust_cost XPARAMS((xrtx, xrtx, xrtx, int));
+extern void ix86_sched_init XPARAMS((FILE *, int));
+extern int ix86_sched_reorder XPARAMS((FILE *, int, xrtx *, int));
+extern int ix86_variable_issue XPARAMS((FILE *, int, xrtx, int));
+
+
+#undef XPARAMS
+#undef xrtx
+#undef xtree
+#undef xmode
+#undef xcode
/* Variables in i386.c */
extern const char *ix86_cpu_string; /* for -mcpu=<xxx> */
extern const char *ix86_arch_string; /* for -march=<xxx> */
-extern const char *i386_reg_alloc_order; /* register allocation order */
-extern const char *i386_regparm_string; /* # registers to use to pass args */
-extern const char *i386_align_loops_string; /* power of two alignment for loops */
-extern const char *i386_align_jumps_string; /* power of two alignment for non-loop jumps */
-extern const char *i386_align_funcs_string; /* power of two alignment for functions */
-extern const char *i386_preferred_stack_boundary_string;/* power of two alignment for stack boundary */
-extern const char *i386_branch_cost_string; /* values 1-5: see jump.c */
-extern int i386_regparm; /* i386_regparm_string as a number */
-extern int i386_align_loops; /* power of two alignment for loops */
-extern int i386_align_jumps; /* power of two alignment for non-loop jumps */
-extern int i386_align_funcs; /* power of two alignment for functions */
-extern int i386_preferred_stack_boundary; /* preferred stack boundary alignment in bits */
-extern int i386_branch_cost; /* values 1-5: see jump.c */
-extern char *hi_reg_name[]; /* names for 16 bit regs */
-extern char *qi_reg_name[]; /* names for 8 bit regs (low) */
-extern char *qi_high_reg_name[]; /* names for 8 bit regs (high) */
-extern enum reg_class regclass_map[]; /* smalled class containing REGNO */
-extern struct rtx_def *i386_compare_op0; /* operand 0 for comparisons */
-extern struct rtx_def *i386_compare_op1; /* operand 1 for comparisons */
-
-/* External variables used */
-extern int optimize; /* optimization level */
-extern int obey_regdecls; /* TRUE if stupid register allocation */
-
-/* External functions used */
-extern struct rtx_def *force_operand ();
-
+extern const char *ix86_reg_alloc_order; /* register allocation order */
+extern const char *ix86_regparm_string; /* # registers to use to pass args */
+extern const char *ix86_align_loops_string; /* power of two alignment for loops */
+extern const char *ix86_align_jumps_string; /* power of two alignment for non-loop jumps */
+extern const char *ix86_align_funcs_string; /* power of two alignment for functions */
+extern const char *ix86_preferred_stack_boundary_string;/* power of two alignment for stack boundary */
+extern const char *ix86_branch_cost_string; /* values 1-5: see jump.c */
+extern int ix86_regparm; /* ix86_regparm_string as a number */
+extern int ix86_align_loops; /* power of two alignment for loops */
+extern int ix86_align_jumps; /* power of two alignment for non-loop jumps */
+extern int ix86_align_funcs; /* power of two alignment for functions */
+extern int ix86_preferred_stack_boundary; /* preferred stack boundary alignment in bits */
+extern int ix86_branch_cost; /* values 1-5: see jump.c */
+extern const char * const hi_reg_name[]; /* names for 16 bit regs */
+extern const char * const qi_reg_name[]; /* names for 8 bit regs (low) */
+extern const char * const qi_high_reg_name[]; /* names for 8 bit regs (high) */
+extern enum reg_class const regclass_map[]; /* smalled class containing REGNO */
+extern struct rtx_def *ix86_compare_op0; /* operand 0 for comparisons */
+extern struct rtx_def *ix86_compare_op1; /* operand 1 for comparisons */
/*
Local variables:
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 547facd..7620712 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -1,36 +1,36 @@
-; GCC machine description for Intel X86.
-;; Copyright (C) 1988, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
+;; GCC machine description for IA-32.
+;; Copyright (C) 1988, 94-98, 1999 Free Software Foundation, Inc.
;; Mostly by William Schelter.
-
+;;
;; This file is part of GNU CC.
-
+;;
;; GNU CC is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
-
+;;
;; GNU CC is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
-
+;;
;; You should have received a copy of the GNU General Public License
;; along with GNU CC; see the file COPYING. If not, write to
;; the Free Software Foundation, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA. */
-
+;;
;; The original PO technology requires these to be ordered by speed,
;; so that assigner will pick the fastest.
-
+;;
;; See file "rtl.def" for documentation on define_insn, match_*, et. al.
-
+;;
;; Macro #define NOTICE_UPDATE_CC in file i386.h handles condition code
;; updates for most instructions.
-
+;;
;; Macro REG_CLASS_FROM_LETTER in file i386.h defines the register
;; constraint letters.
-
-;; the special asm out single letter directives following a '%' are:
+;;
+;; The special asm out single letter directives following a '%' are:
;; 'z' mov%z1 would be movl, movw, or movb depending on the mode of
;; operands[1].
;; 'L' Print the opcode suffix for a 32-bit integer opcode.
@@ -40,14 +40,14 @@
;; 'S' Print the opcode suffix for a 32-bit float opcode.
;; 'T' Print the opcode suffix for an 80-bit extended real XFmode float opcode.
;; 'J' Print the appropriate jump operand.
-
+;;
;; 'b' Print the QImode name of the register for the indicated operand.
;; %b0 would print %al if operands[0] is reg 0.
;; 'w' Likewise, print the HImode name of the register.
;; 'k' Likewise, print the SImode name of the register.
;; 'h' Print the QImode name for a "high" register, either ah, bh, ch or dh.
;; 'y' Print "st(0)" instead of "st" as a register.
-
+;;
;; UNSPEC usage:
;; 0 This is a `scas' operation. The mode of the UNSPEC is always SImode.
;; operand 0 is the memory address to scan.
@@ -67,1981 +67,2170 @@
;; 6 This is the @GOT offset of a PIC address.
;; 7 This is the @GOTOFF offset of a PIC address.
;; 8 This is a reference to a symbol's @PLT address.
+;; 9 This is an `fnstsw' operation.
+;; 10 This is a `sahf' operation.
+;; 11 This is a `fstcw' operation
-;; This shadows the processor_type enumeration, so changes must be made
-;; to i386.h at the same time.
+;; Processor type. This attribute must exactly match the processor_type
+;; enumeration in i386.h.
+(define_attr "cpu" "i386,i486,pentium,pentiumpro,k6"
+ (const (symbol_ref "ix86_cpu")))
+;; A basic instruction type. Refinements due to arguments to be
+;; provided in other attributes.
(define_attr "type"
- "integer,binary,memory,test,compare,fcompare,idiv,imul,lea,fld,fpop,fpdiv,fpmul"
- (const_string "integer"))
-
-(define_attr "memory" "none,load,store"
- (cond [(eq_attr "type" "idiv,lea")
- (const_string "none")
-
- (eq_attr "type" "fld")
- (const_string "load")
-
- (eq_attr "type" "test")
- (if_then_else (match_operand 0 "memory_operand" "")
- (const_string "load")
- (const_string "none"))
-
- (eq_attr "type" "compare,fcompare")
- (if_then_else (ior (match_operand 0 "memory_operand" "")
- (match_operand 1 "memory_operand" ""))
- (const_string "load")
- (const_string "none"))
-
- (and (eq_attr "type" "integer,memory,fpop")
- (match_operand 0 "memory_operand" ""))
- (const_string "store")
-
- (and (eq_attr "type" "integer,memory,fpop")
+ "other,multi,alu1,negnot,alu,icmp,imov,imovx,lea,incdec,ishift,imul,idiv,ibr,setcc,push,pop,call,callv,icmov,fmov,fop,fop1,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch"
+ (const_string "other"))
+
+;; The (bounding maximum) length of an instruction in bytes.
+(define_attr "length" ""
+ (symbol_ref "ix86_attr_length_default(insn)"))
+
+;; Supporting: number of prefix bytes
+(define_attr "length_prefix" ""
+ (cond [(and (eq_attr "type" "alu,alu1,negnot,icmp,imovx,incdec,ishift,imul,idiv,imov,pop")
+ (match_operand:HI 0 "general_operand" ""))
+ (const_int 1)
+ (and (eq_attr "type" "push")
+ (match_operand:HI 1 "general_operand" ""))
+ (const_int 1)
+ ]
+ (const_int 0)))
+
+;; Supporting: bytes in the opcode+modrm.
+(define_attr "length_opcode" ""
+ (cond [(eq_attr "type" "imovx,setcc,icmov")
+ (const_int 3)
+ (and (eq_attr "type" "incdec")
+ (ior (match_operand:SI 1 "register_operand" "")
+ (match_operand:HI 1 "register_operand" "")))
+ (const_int 1)
+ (and (eq_attr "type" "push")
+ (not (match_operand 1 "memory_operand" "")))
+ (const_int 1)
+ (and (eq_attr "type" "pop")
+ (not (match_operand 0 "memory_operand" "")))
+ (const_int 1)
+ (and (eq_attr "type" "imov")
+ (and (match_operand 0 "register_operand" "")
+ (match_operand 1 "immediate_operand" "")))
+ (const_int 1)
+ ]
+ (const_int 2)))
+
+;; The `memory' attribute is `none' if no memory is referenced, `load' or
+;; `store' if there is a simple memory reference therein, or `unknown'
+;; if the instruction is complex.
+
+(define_attr "memory" "none,load,store,both,unknown"
+ (cond [(eq_attr "type" "other,multi")
+ (const_string "unknown")
+ (eq_attr "type" "lea,fcmov,fpspc")
+ (const_string "none")
+ (eq_attr "type" "push")
+ (if_then_else (match_operand 1 "memory_operand" "")
+ (const_string "both")
+ (const_string "store"))
+ (eq_attr "type" "pop,setcc")
+ (if_then_else (match_operand 0 "memory_operand" "")
+ (const_string "both")
+ (const_string "load"))
+ (eq_attr "type" "icmp")
+ (if_then_else (ior (match_operand 0 "memory_operand" "")
+ (match_operand 1 "memory_operand" ""))
+ (const_string "load")
+ (const_string "none"))
+ (eq_attr "type" "ibr")
+ (if_then_else (match_operand 0 "memory_operand" "")
+ (const_string "load")
+ (const_string "none"))
+ (eq_attr "type" "call")
+ (if_then_else (match_operand 0 "constant_call_address_operand" "")
+ (const_string "none")
+ (const_string "load"))
+ (eq_attr "type" "callv")
+ (if_then_else (match_operand 1 "constant_call_address_operand" "")
+ (const_string "none")
+ (const_string "load"))
+ (and (eq_attr "type" "alu1,negnot")
(match_operand 1 "memory_operand" ""))
- (const_string "load")
-
- (and (eq_attr "type" "binary,imul,fpmul,fpdiv")
- (ior (match_operand 1 "memory_operand" "")
- (match_operand 2 "memory_operand" "")))
- (const_string "load")]
-
+ (const_string "both")
+ (and (match_operand 0 "memory_operand" "")
+ (match_operand 1 "memory_operand" ""))
+ (const_string "both")
+ (match_operand 0 "memory_operand" "")
+ (const_string "store")
+ (match_operand 1 "memory_operand" "")
+ (const_string "load")
+ (and (eq_attr "type" "!icmp,alu1,negnot,fop1,fsgn,imov,imovx,fmov,fcmp")
+ (match_operand 2 "memory_operand" ""))
+ (const_string "load")
+ (and (eq_attr "type" "icmov")
+ (match_operand 3 "memory_operand" ""))
+ (const_string "load")
+ ]
(const_string "none")))
-;; Functional units
+;; Indicates if an instruction has both an immediate and a displacement.
+
+(define_attr "imm_disp" "false,true,unknown"
+ (cond [(eq_attr "type" "other,multi")
+ (const_string "unknown")
+ (and (eq_attr "type" "icmp,imov")
+ (and (match_operand 0 "memory_displacement_operand" "")
+ (match_operand 1 "immediate_operand" "")))
+ (const_string "true")
+ (and (eq_attr "type" "alu,ishift,imul,idiv")
+ (and (match_operand 0 "memory_displacement_operand" "")
+ (match_operand 2 "immediate_operand" "")))
+ (const_string "true")
+ ]
+ (const_string "false")))
+
+;; Indicates if an FP operation has an integer source.
+
+(define_attr "fp_int_src" "false,true"
+ (const_string "false"))
+
+;; Describe a user's asm statement.
+(define_asm_attributes
+ [(set_attr "length" "128")
+ (set_attr "type" "multi")])
+
+;; Pentium Scheduling
+;;
+;; The Pentium is an in-order core with two integer pipelines.
+
+;; Categorize how an instruction slots.
+
+;; The non-MMX Pentium slots an instruction with prefixes on U pipe only,
+;; while MMX Pentium can slot it on either U or V. Model non-MMX Pentium
+;; rules, because it results in noticeably better code on non-MMX Pentium
+;; and doesn't hurt much on MMX. (Prefixed instructions are not very
+;; common, so the scheduler usualy has a non-prefixed insn to pair).
+
+(define_attr "pent_pair" "uv,pu,pv,np"
+ (cond [(eq_attr "imm_disp" "true")
+ (const_string "np")
+ (eq_attr "type" "alu1,alu,imov,icmp,lea,incdec")
+ (if_then_else (eq_attr "length_prefix" "1")
+ (const_string "pu")
+ (const_string "uv"))
+ (eq_attr "type" "ibr")
+ (const_string "pv")
+ (and (eq_attr "type" "ishift")
+ (match_operand 2 "const_int_operand" ""))
+ (const_string "pu")
+ (and (eq_attr "type" "pop,push")
+ (eq_attr "memory" "!both"))
+ (if_then_else (eq_attr "length_prefix" "1")
+ (const_string "pu")
+ (const_string "uv"))
+ (and (eq_attr "type" "call")
+ (match_operand 0 "constant_call_address_operand" ""))
+ (const_string "pv")
+ (and (eq_attr "type" "callv")
+ (match_operand 1 "constant_call_address_operand" ""))
+ (const_string "pv")
+ ]
+ (const_string "np")))
+
+;; Rough readiness numbers. Fine tuning happens in i386.c.
+;;
+;; u describes pipe U
+;; v describes pipe V
+;; uv describes either pipe U or V for those that can issue to either
+;; np describes not paring
+;; fpu describes fpu
+;; fpm describes fp insns of different types are not pipelined.
+;;
+;; ??? fxch isn't handled; not an issue until sched3 after reg-stack is real.
-; (define_function_unit NAME MULTIPLICITY SIMULTANEITY
-; TEST READY-DELAY ISSUE-DELAY [CONFLICT-LIST])
+(define_function_unit "pent_np" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "type" "imul"))
+ 11 11)
-; pentiumpro has a reservation station with 5 ports
-; port 0 has integer, float add, integer divide, float divide, float
-; multiply, and shifter units.
-; port 1 has integer, and jump units.
-; port 2 has the load address generation unit
-; ports 3 and 4 have the store address generation units
+(define_function_unit "pent_mul" 1 1
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "type" "imul"))
+ 11 11)
-; pentium has two integer pipelines, the main u pipe and the secondary v pipe.
-; and a float pipeline
+; ??? IDIV for SI takes 46 cycles, for HI 30, for QI 22
+(define_function_unit "pent_np" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "type" "idiv"))
+ 46 46)
+
+; Fp reg-reg moves takes 1 cycle. Loads takes 1 cycle for SF/DF mode,
+; 3 cycles for XFmode. Stores takes 2 cycles for SF/DF and 3 for XF.
+; fldz and fld1 takes 2 cycles. Only reg-reg moves are pairable.
+; The integer <-> fp conversion is not modeled correctly. Fild behaves
+; like normal fp operation and fist takes 6 cycles.
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (and (eq_attr "type" "fmov")
+ (ior (and (eq_attr "memory" "store")
+ (match_operand:XF 0 "memory_operand" ""))
+ (and (eq_attr "memory" "load")
+ (match_operand:XF 1 "memory_operand" "")))))
+ 3 3)
+
+(define_function_unit "pent_np" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (and (eq_attr "type" "fmov")
+ (ior (and (eq_attr "memory" "store")
+ (match_operand:XF 0 "memory_operand" ""))
+ (and (eq_attr "memory" "load")
+ (match_operand:XF 1 "memory_operand" "")))))
+ 3 3)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (and (eq_attr "type" "fmov")
+ (ior (match_operand 1 "immediate_operand" "")
+ (eq_attr "memory" "store"))))
+ 2 2)
-;; Floating point
+(define_function_unit "pent_np" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (and (eq_attr "type" "fmov")
+ (ior (match_operand 1 "immediate_operand" "")
+ (eq_attr "memory" "store"))))
+ 2 2)
-(define_function_unit "fp" 1 0
- (and (eq_attr "type" "fpop,fcompare") (eq_attr "cpu" "i386,i486"))
- 5 5)
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (and (eq_attr "type" "fmov")
+ (eq_attr "memory" "none,load")))
+ 1 1)
+
+; Read/Modify/Write instructions usually take 3 cycles.
+(define_function_unit "pent_u" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (and (eq_attr "type" "alu,alu1,ishift")
+ (and (eq_attr "pent_pair" "pu")
+ (eq_attr "memory" "both"))))
+ 3 3)
+
+(define_function_unit "pent_uv" 2 0
+ (and (eq_attr "cpu" "pentium")
+ (and (eq_attr "type" "alu,alu1,ishift")
+ (and (eq_attr "pent_pair" "!np")
+ (eq_attr "memory" "both"))))
+ 3 3)
+
+(define_function_unit "pent_np" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (and (eq_attr "type" "alu,alu1,negnot,ishift")
+ (and (eq_attr "pent_pair" "np")
+ (eq_attr "memory" "both"))))
+ 3 3)
+
+; Read/Modify or Modify/Write instructions usually take 2 cycles.
+(define_function_unit "pent_u" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (and (eq_attr "type" "alu,ishift")
+ (and (eq_attr "pent_pair" "pu")
+ (eq_attr "memory" "load,store"))))
+ 2 2)
-(define_function_unit "fp" 1 0
- (and (eq_attr "type" "fpop,fcompare") (eq_attr "cpu" "pentium,pentiumpro"))
- 3 0)
+(define_function_unit "pent_uv" 2 0
+ (and (eq_attr "cpu" "pentium")
+ (and (eq_attr "type" "alu,ishift")
+ (and (eq_attr "pent_pair" "!np")
+ (eq_attr "memory" "load,store"))))
+ 2 2)
-(define_function_unit "fp" 1 0
- (and (eq_attr "type" "fpmul") (eq_attr "cpu" "pentium"))
- 7 0)
+(define_function_unit "pent_np" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (and (eq_attr "type" "alu,ishift")
+ (and (eq_attr "pent_pair" "np")
+ (eq_attr "memory" "load,store"))))
+ 2 2)
-(define_function_unit "fp" 1 0
- (and (eq_attr "type" "fpmul") (eq_attr "cpu" "pentiumpro"))
- 5 0)
+; Insns w/o memory operands and move instructions usually take one cycle.
+(define_function_unit "pent_u" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "pent_pair" "pu"))
+ 1 1)
+
+(define_function_unit "pent_v" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "pent_pair" "pv"))
+ 1 1)
+
+(define_function_unit "pent_uv" 2 0
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "pent_pair" "!np"))
+ 1 1)
+
+(define_function_unit "pent_np" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "pent_pair" "np"))
+ 1 1)
+
+; Pairable insns only conflict with other non-pairable insns.
+(define_function_unit "pent_np" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (and (eq_attr "type" "alu,alu1,ishift")
+ (and (eq_attr "pent_pair" "!np")
+ (eq_attr "memory" "both"))))
+ 3 3
+ [(eq_attr "pent_pair" "np")])
+
+(define_function_unit "pent_np" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (and (eq_attr "type" "alu,alu1,ishift")
+ (and (eq_attr "pent_pair" "!np")
+ (eq_attr "memory" "load,store"))))
+ 2 2
+ [(eq_attr "pent_pair" "np")])
+
+(define_function_unit "pent_np" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "pent_pair" "!np"))
+ 1 1
+ [(eq_attr "pent_pair" "np")])
+
+; Floating point instructions usually blocks cycle longer when combined with
+; integer instructions, because of the inpaired fxch instruction.
+(define_function_unit "pent_np" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "type" "fmov,fop,fop1,fsgn,fmul,fpspc,fcmov,fcmp"))
+ 2 2
+ [(eq_attr "type" "!fmov,fop,fop1,fsgn,fmul,fpspc,fcmov,fcmp")])
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "type" "fcmp,fxch,fsgn"))
+ 1 1)
+
+; Addition takes 3 cycles; assume other random cruft does as well.
+; ??? Trivial fp operations such as fabs or fchs takes only one cycle.
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "type" "fop,fop1"))
+ 3 1)
+
+; Multiplication takes 3 cycles and is only half pipelined.
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "type" "fmul"))
+ 3 1)
+
+(define_function_unit "pent_mul" 1 1
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "type" "fmul"))
+ 2 2)
-(define_function_unit "fp" 1 0
- (and (eq_attr "type" "idiv") (eq_attr "cpu" "pentiumpro"))
- 10 10)
+; ??? This is correct only for fdiv and sqrt -- sin/cos take 65-100 cycles.
+; They can overlap with integer insns. Only the last two cycles can overlap
+; with other fp insns. Only fsin/fcos can overlap with multiplies.
+; Only last two cycles of fsin/fcos can overlap with other instructions.
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "type" "fdiv"))
+ 39 37)
+
+(define_function_unit "pent_mul" 1 1
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "type" "fdiv"))
+ 39 39)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "type" "fpspc"))
+ 70 68)
+
+(define_function_unit "pent_mul" 1 1
+ (and (eq_attr "cpu" "pentium")
+ (eq_attr "type" "fpspc"))
+ 70 70)
+
+;; Pentium Pro/PII Scheduling
+;;
+;; The PPro has an out-of-order core, but the instruction decoders are
+;; naturally in-order and asymmetric. We get best performance by scheduling
+;; for the decoders, for in doing so we give the oo execution unit the
+;; most choices.
+
+;; Categorize how many uops an ia32 instruction evaluates to:
+;; one -- an instruction with 1 uop can be decoded by any of the
+;; three decoders.
+;; few -- an instruction with 1 to 4 uops can be decoded only by
+;; decoder 0.
+;; many -- a complex instruction may take an unspecified number of
+;; cycles to decode in decoder 0.
+
+(define_attr "ppro_uops" "one,few,many"
+ (cond [(eq_attr "type" "other,multi,call,callv,fpspc")
+ (const_string "many")
+ (eq_attr "type" "icmov,fcmov")
+ (const_string "few")
+ (eq_attr "type" "imov")
+ (if_then_else (eq_attr "memory" "store,both")
+ (const_string "few")
+ (const_string "one"))
+ (eq_attr "memory" "!none")
+ (const_string "few")
+ ]
+ (const_string "one")))
+
+;; Rough readiness numbers. Fine tuning happens in i386.c.
+;;
+;; p0 describes port 0.
+;; p01 describes ports 0 and 1 as a pair; alu insns can issue to either.
+;; p2 describes port 2 for loads.
+;; p34 describes ports 3 and 4 for stores.
+;; fpu describes the fpu accessed via port 0.
+;; ??? It is less than clear if there are separate fadd and fmul units
+;; that could operate in parallel.
+;;
+;; ??? fxch isn't handled; not an issue until sched3 after reg-stack is real.
+
+(define_function_unit "ppro_p0" 1 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (eq_attr "type" "ishift,lea,ibr"))
+ 1 1)
+
+(define_function_unit "ppro_p0" 1 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (eq_attr "type" "imul"))
+ 4 1)
+
+;; ??? Does the divider lock out the pipe while it works,
+;; or is there a disconnected unit?
+(define_function_unit "ppro_p0" 1 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (eq_attr "type" "idiv"))
+ 17 17)
-(define_function_unit "fp" 1 0
- (and (eq_attr "type" "imul") (eq_attr "cpu" "pentiumpro"))
- 6 0)
+(define_function_unit "ppro_p0" 1 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (eq_attr "type" "fop,fop1,fsgn"))
+ 3 1)
+
+(define_function_unit "ppro_p0" 1 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (eq_attr "type" "fcmov"))
+ 2 1)
+
+(define_function_unit "ppro_p0" 1 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (eq_attr "type" "fcmp"))
+ 1 1)
+
+(define_function_unit "ppro_p0" 1 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (eq_attr "type" "fmov"))
+ 1 1)
+
+(define_function_unit "ppro_p0" 1 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (eq_attr "type" "fmul"))
+ 5 1)
+
+(define_function_unit "ppro_p0" 1 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (eq_attr "type" "fdiv,fpspc"))
+ 56 1)
+
+(define_function_unit "ppro_p01" 2 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (eq_attr "type" "!imov,fmov"))
+ 1 1)
+
+(define_function_unit "ppro_p01" 2 0
+ (and (and (eq_attr "cpu" "pentiumpro")
+ (eq_attr "type" "imov,fmov"))
+ (eq_attr "memory" "none"))
+ 1 1)
+
+(define_function_unit "ppro_p2" 1 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (ior (eq_attr "type" "pop")
+ (eq_attr "memory" "load,both")))
+ 3 1)
+
+(define_function_unit "ppro_p34" 1 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (ior (eq_attr "type" "push")
+ (eq_attr "memory" "store,both")))
+ 1 1)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (eq_attr "type" "fop,fop1,fsgn,fmov,fcmp,fcmov"))
+ 1 1)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (eq_attr "type" "fmul"))
+ 5 2)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (eq_attr "type" "fdiv,fpspc"))
+ 56 56)
+
+;; imul uses the fpu. ??? does it have the same throughput as fmul?
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "cpu" "pentiumpro")
+ (eq_attr "type" "imul"))
+ 4 1)
+
+;; AMD K6/K6-2 Scheduling
+;;
+;; The K6 has similar architecture to PPro. Important difference is, that
+;; there are only two decoders and they seems to be much slower than execution
+;; units. So we have to pay much more attention to proper decoding for
+;; schedulers. We share most of scheduler code for PPro in i386.c
+;;
+;; The fp unit is not pipelined and do one operation per two cycles including
+;; the FXCH.
+;;
+;; alu describes both ALU units (ALU-X and ALU-Y).
+;; alux describes X alu unit
+;; fpu describes FPU unit
+;; load describes load unit.
+;; branch describes branch unit.
+;; store decsribes store unit. This unit is not modelled completely and only
+;; used to model lea operation. Otherwise it lie outside of the critical
+;; path.
+;;
+;; ??? fxch isn't handled; not an issue until sched3 after reg-stack is real.
-(define_function_unit "fp" 1 0
- (eq_attr "type" "fpdiv")
- 10 10)
+;; The decoder specification is in the PPro section above!
-(define_function_unit "fp" 1 0
- (and (eq_attr "type" "fld") (eq_attr "cpu" "!pentiumpro,k6"))
- 1 0)
+;; Shift instructions and certain arithmetic are issued only to X pipe.
+(define_function_unit "k6_alux" 1 0
+ (and (eq_attr "cpu" "k6")
+ (eq_attr "type" "ishift,alu1,negnot"))
+ 1 1)
-;; K6 FPU is not pipelined.
-(define_function_unit "fp" 1 0
- (and (eq_attr "type" "fpop,fpmul,fcompare") (eq_attr "cpu" "k6"))
- 2 2)
+;; The QI mode arithmetic is issued to X pipe only.
+(define_function_unit "k6_alux" 1 0
+ (and (eq_attr "cpu" "k6")
+ (and (eq_attr "type" "alu,alu1,negnot,icmp,imovx,incdec")
+ (match_operand:QI 0 "general_operand" "")))
+ 1 1)
-;; i386 and i486 have one integer unit, which need not be modeled
+(define_function_unit "k6_alu" 2 0
+ (and (eq_attr "cpu" "k6")
+ (eq_attr "type" "ishift,alu1,negnot,alu,icmp,imovx,incdec,setcc,lea"))
+ 1 1)
-(define_function_unit "integer" 2 0
- (and (eq_attr "type" "integer,binary,test,compare,lea") (eq_attr "cpu" "pentium,pentiumpro"))
- 1 0)
+(define_function_unit "k6_alu" 2 0
+ (and (eq_attr "cpu" "k6")
+ (and (eq_attr "type" "imov")
+ (eq_attr "memory" "none")))
+ 1 1)
-(define_function_unit "integer" 2 0
+(define_function_unit "k6_branch" 1 0
(and (eq_attr "cpu" "k6")
- (and (eq_attr "type" "integer,binary,test,compare")
- (eq_attr "memory" "!load")))
- 1 0)
+ (eq_attr "type" "call,callv,ibr"))
+ 1 1)
-;; Internally, K6 converts REG OP MEM instructions into a load (2 cycles)
-;; and a register operation (1 cycle).
-(define_function_unit "integer" 2 0
+;; Load unit have two cycle latency, but we take care for it in adjust_cost
+(define_function_unit "k6_load" 1 0
(and (eq_attr "cpu" "k6")
- (and (eq_attr "type" "integer,binary,test,compare")
- (eq_attr "memory" "load")))
- 3 0)
+ (ior (eq_attr "type" "pop")
+ (eq_attr "memory" "load,both")))
+ 1 1)
-;; Multiplies use one of the integer units
-(define_function_unit "integer" 2 0
- (and (eq_attr "cpu" "pentium") (eq_attr "type" "imul"))
- 11 11)
+;; Lea have two instructions, so latency is probably 2
+(define_function_unit "k6_store" 1 0
+ (and (eq_attr "cpu" "k6")
+ (eq_attr "type" "lea"))
+ 2 1)
-(define_function_unit "integer" 2 0
- (and (eq_attr "cpu" "k6") (eq_attr "type" "imul"))
- 2 2)
+(define_function_unit "k6_store" 1 0
+ (and (eq_attr "cpu" "k6")
+ (ior (eq_attr "type" "push")
+ (eq_attr "memory" "store,both")))
+ 1 1)
-(define_function_unit "integer" 2 0
- (and (eq_attr "cpu" "pentium") (eq_attr "type" "idiv"))
- 25 25)
+(define_function_unit "k6_fpu" 1 1
+ (and (eq_attr "cpu" "k6")
+ (eq_attr "type" "fop,fop1,fmov,fcmp"))
+ 2 2)
-(define_function_unit "integer" 2 0
- (and (eq_attr "cpu" "k6") (eq_attr "type" "idiv"))
- 17 17)
+(define_function_unit "k6_fpu" 1 1
+ (and (eq_attr "cpu" "k6")
+ (eq_attr "type" "fmul"))
+ 2 2)
-;; Pentium Pro and K6 have a separate load unit.
-(define_function_unit "load" 1 0
- (and (eq_attr "cpu" "pentiumpro") (eq_attr "memory" "load"))
- 3 0)
+;; ??? Guess
+(define_function_unit "k6_fpu" 1 1
+ (and (eq_attr "cpu" "k6")
+ (eq_attr "type" "fdiv,fpspc"))
+ 56 56)
-(define_function_unit "load" 1 0
- (and (eq_attr "cpu" "k6") (eq_attr "memory" "load"))
- 2 0)
+(define_function_unit "k6_alu" 2 0
+ (and (eq_attr "cpu" "k6")
+ (eq_attr "type" "imul"))
+ 2 2)
-;; Pentium Pro and K6 have a separate store unit.
-(define_function_unit "store" 1 0
- (and (eq_attr "cpu" "pentiumpro,k6") (eq_attr "memory" "store"))
- 1 0)
+(define_function_unit "k6_alux" 1 0
+ (and (eq_attr "cpu" "k6")
+ (eq_attr "type" "imul"))
+ 2 2)
-;; lea executes in the K6 store unit with 1 cycle latency
-(define_function_unit "store" 1 0
- (and (eq_attr "cpu" "k6") (eq_attr "type" "lea"))
- 1 0)
+;; ??? Guess
+(define_function_unit "k6_alu" 2 0
+ (and (eq_attr "cpu" "k6")
+ (eq_attr "type" "idiv"))
+ 17 17)
+(define_function_unit "k6_alux" 1 0
+ (and (eq_attr "cpu" "k6")
+ (eq_attr "type" "idiv"))
+ 17 17)
-;; "movl MEM,REG / testl REG,REG" is faster on a 486 than "cmpl $0,MEM".
-;; But restricting MEM here would mean that gcc could not remove a redundant
-;; test in cases like "incl MEM / je TARGET".
-;;
-;; We don't want to allow a constant operand for test insns because
-;; (set (cc0) (const_int foo)) has no mode information. Such insns will
-;; be folded while optimizing anyway.
+;; Compare instructions.
-;; All test insns have expanders that save the operands away without
+;; All compare insns have expanders that save the operands away without
;; actually generating RTL. The bCOND or sCOND (emitted immediately
-;; after the tstM or cmp) will actually emit the tstM or cmpM.
-
-;; Processor type -- this attribute must exactly match the processor_type
-;; enumeration in i386.h.
-
-(define_attr "cpu" "i386,i486,pentium,pentiumpro,k6"
- (const (symbol_ref "ix86_cpu")))
-
-(define_insn "tstsi_1"
- [(set (cc0)
- (match_operand:SI 0 "nonimmediate_operand" "rm"))]
- ""
- "*
-{
- if (REG_P (operands[0]))
- return AS2 (test%L0,%0,%0);
-
- operands[1] = const0_rtx;
- return AS2 (cmp%L0,%1,%0);
-}"
- [(set_attr "type" "test")])
+;; after the cmp) will actually emit the cmpM.
-(define_expand "tstsi"
- [(set (cc0)
- (match_operand:SI 0 "nonimmediate_operand" ""))]
+(define_expand "cmpdi"
+ [(set (reg:CC 17)
+ (compare:CC (match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "general_operand" "")))]
""
"
{
- i386_compare_gen = gen_tstsi_1;
- i386_compare_op0 = operands[0];
- i386_compare_op1 = const0_rtx;
+ if ((GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
+ || (CONSTANT_P (operands[0]) && CONSTANT_P (operands[1])))
+ operands[0] = force_reg (DImode, operands[0]);
+ ix86_compare_op0 = operands[0];
+ ix86_compare_op1 = operands[1];
DONE;
}")
-(define_insn "tsthi_1"
- [(set (cc0)
- (match_operand:HI 0 "nonimmediate_operand" "rm"))]
- ""
- "*
-{
- if (REG_P (operands[0]))
- return AS2 (test%W0,%0,%0);
-
- operands[1] = const0_rtx;
- return AS2 (cmp%W0,%1,%0);
-}"
- [(set_attr "type" "test")])
-
-(define_expand "tsthi"
- [(set (cc0)
- (match_operand:HI 0 "nonimmediate_operand" ""))]
+(define_expand "cmpsi"
+ [(set (reg:CC 17)
+ (compare:CC (match_operand:SI 0 "cmpsi_operand" "")
+ (match_operand:SI 1 "general_operand" "")))]
""
"
{
- i386_compare_gen = gen_tsthi_1;
- i386_compare_op0 = operands[0];
- i386_compare_op1 = const0_rtx;
+ if ((GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
+ || (CONSTANT_P (operands[0]) && CONSTANT_P (operands[1])))
+ operands[0] = force_reg (SImode, operands[0]);
+ ix86_compare_op0 = operands[0];
+ ix86_compare_op1 = operands[1];
DONE;
}")
-(define_insn "tstqi_1"
- [(set (cc0)
- (match_operand:QI 0 "nonimmediate_operand" "qm"))]
- ""
- "*
-{
- if (REG_P (operands[0]))
- return AS2 (test%B0,%0,%0);
-
- operands[1] = const0_rtx;
- return AS2 (cmp%B0,%1,%0);
-}"
- [(set_attr "type" "test")])
-
-(define_expand "tstqi"
- [(set (cc0)
- (match_operand:QI 0 "nonimmediate_operand" ""))]
+(define_expand "cmphi"
+ [(set (reg:CC 17)
+ (compare:CC (match_operand:HI 0 "general_operand" "")
+ (match_operand:HI 1 "general_operand" "")))]
""
"
{
- i386_compare_gen = gen_tstqi_1;
- i386_compare_op0 = operands[0];
- i386_compare_op1 = const0_rtx;
- DONE;
-}")
-
-(define_insn "tstsf_cc"
- [(set (cc0)
- (match_operand:SF 0 "register_operand" "f"))
- (clobber (match_scratch:HI 1 "=a"))]
- "TARGET_80387 && ! TARGET_IEEE_FP"
- "*
-{
- if (! STACK_TOP_P (operands[0]))
- abort ();
-
- output_asm_insn (\"ftst\", operands);
-
- if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
- output_asm_insn (AS1 (fstp,%y0), operands);
-
- return output_fp_cc0_set (insn);
-}"
- [(set_attr "type" "test")])
-
-;; Don't generate tstsf if generating IEEE code, since the `ftst' opcode
-;; isn't IEEE compliant.
-
-(define_expand "tstsf"
- [(parallel [(set (cc0)
- (match_operand:SF 0 "register_operand" ""))
- (clobber (match_scratch:HI 1 ""))])]
- "TARGET_80387 && ! TARGET_IEEE_FP"
- "
-{
- i386_compare_gen = gen_tstsf_cc;
- i386_compare_op0 = operands[0];
- i386_compare_op1 = const0_rtx;
+ if ((GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
+ || (CONSTANT_P (operands[0]) && CONSTANT_P (operands[1])))
+ operands[0] = force_reg (HImode, operands[0]);
+ ix86_compare_op0 = operands[0];
+ ix86_compare_op1 = operands[1];
DONE;
}")
-(define_insn "tstdf_cc"
- [(set (cc0)
- (match_operand:DF 0 "register_operand" "f"))
- (clobber (match_scratch:HI 1 "=a"))]
- "TARGET_80387 && ! TARGET_IEEE_FP"
- "*
-{
- if (! STACK_TOP_P (operands[0]))
- abort ();
-
- output_asm_insn (\"ftst\", operands);
-
- if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
- output_asm_insn (AS1 (fstp,%y0), operands);
-
- return output_fp_cc0_set (insn);
-}"
- [(set_attr "type" "test")])
-
-;; Don't generate tstdf if generating IEEE code, since the `ftst' opcode
-;; isn't IEEE compliant.
-
-(define_expand "tstdf"
- [(parallel [(set (cc0)
- (match_operand:DF 0 "register_operand" ""))
- (clobber (match_scratch:HI 1 ""))])]
- "TARGET_80387 && ! TARGET_IEEE_FP"
+(define_expand "cmpqi"
+ [(set (reg:CC 17)
+ (compare:CC (match_operand:QI 0 "general_operand" "")
+ (match_operand:QI 1 "general_operand" "")))]
+ ""
"
{
- i386_compare_gen = gen_tstdf_cc;
- i386_compare_op0 = operands[0];
- i386_compare_op1 = const0_rtx;
+ if ((GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
+ || (CONSTANT_P (operands[0]) && CONSTANT_P (operands[1])))
+ operands[0] = force_reg (QImode, operands[0]);
+ ix86_compare_op0 = operands[0];
+ ix86_compare_op1 = operands[1];
DONE;
}")
-(define_insn "tstxf_cc"
- [(set (cc0)
- (match_operand:XF 0 "register_operand" "f"))
- (clobber (match_scratch:HI 1 "=a"))]
- "TARGET_80387 && ! TARGET_IEEE_FP"
- "*
-{
- if (! STACK_TOP_P (operands[0]))
- abort ();
-
- output_asm_insn (\"ftst\", operands);
-
- if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
- output_asm_insn (AS1 (fstp,%y0), operands);
-
- return output_fp_cc0_set (insn);
-}"
- [(set_attr "type" "test")])
-
-;; Don't generate tstxf if generating IEEE code, since the `ftst' opcode
-;; isn't IEEE compliant.
-
-(define_expand "tstxf"
- [(parallel [(set (cc0)
- (match_operand:XF 0 "register_operand" ""))
- (clobber (match_scratch:HI 1 ""))])]
- "TARGET_80387 && ! TARGET_IEEE_FP"
- "
-{
- i386_compare_gen = gen_tstxf_cc;
- i386_compare_op0 = operands[0];
- i386_compare_op1 = const0_rtx;
- DONE;
-}")
-
-;;- compare instructions. See comments above tstM patterns about
-;; expansion of these insns.
+(define_insn "cmpsi_0"
+ [(set (reg:CCNO 17)
+ (compare:CCNO (match_operand:SI 0 "nonimmediate_operand" "r,?mr")
+ (match_operand:SI 1 "const0_operand" "n,n")))]
+ ""
+ "@
+ test{l}\\t{%0, %0|%0, %0}
+ cmp{l}\\t{%1, %0|%0, %1}"
+ [(set_attr "type" "icmp")])
(define_insn "cmpsi_1"
- [(set (cc0)
- (compare (match_operand:SI 0 "nonimmediate_operand" "mr,r")
- (match_operand:SI 1 "general_operand" "ri,mr")))]
+ [(set (reg:CC 17)
+ (compare:CC (match_operand:SI 0 "nonimmediate_operand" "rm,r")
+ (match_operand:SI 1 "general_operand" "ri,mr")))]
"GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
- "* return AS2 (cmp%L0,%1,%0);"
- [(set_attr "type" "compare")])
+ "cmp{l}\\t{%1, %0|%0, %1}"
+ [(set_attr "type" "icmp")])
-(define_expand "cmpsi"
- [(set (cc0)
- (compare (match_operand:SI 0 "nonimmediate_operand" "")
- (match_operand:SI 1 "general_operand" "")))]
+(define_insn "cmphi_0"
+ [(set (reg:CCNO 17)
+ (compare:CCNO (match_operand:HI 0 "nonimmediate_operand" "r,?mr")
+ (match_operand:HI 1 "const0_operand" "n,n")))]
""
- "
-{
- if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
- operands[0] = force_reg (SImode, operands[0]);
-
- i386_compare_gen = gen_cmpsi_1;
- i386_compare_op0 = operands[0];
- i386_compare_op1 = operands[1];
- DONE;
-}")
+ "@
+ test{w}\\t{%0, %0|%0, %0}
+ cmp{w}\\t{%1, %0|%0, %1}"
+ [(set_attr "type" "icmp")])
(define_insn "cmphi_1"
- [(set (cc0)
- (compare (match_operand:HI 0 "nonimmediate_operand" "mr,r")
- (match_operand:HI 1 "general_operand" "ri,mr")))]
+ [(set (reg:CC 17)
+ (compare:CC (match_operand:HI 0 "nonimmediate_operand" "rm,r")
+ (match_operand:HI 1 "general_operand" "ri,mr")))]
"GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
- "* return AS2 (cmp%W0,%1,%0);"
- [(set_attr "type" "compare")])
+ "cmp{w}\\t{%1, %0|%0, %1}"
+ [(set_attr "type" "icmp")])
-(define_expand "cmphi"
- [(set (cc0)
- (compare (match_operand:HI 0 "nonimmediate_operand" "")
- (match_operand:HI 1 "general_operand" "")))]
+(define_insn "cmpqi_0"
+ [(set (reg:CCNO 17)
+ (compare:CCNO (match_operand:QI 0 "nonimmediate_operand" "q,?mq")
+ (match_operand:QI 1 "const0_operand" "n,n")))]
""
- "
-{
- if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
- operands[0] = force_reg (HImode, operands[0]);
-
- i386_compare_gen = gen_cmphi_1;
- i386_compare_op0 = operands[0];
- i386_compare_op1 = operands[1];
- DONE;
-}")
+ "@
+ test{b}\\t{%0, %0|%0, %0}
+ cmp{b}\\t{$0, %0|%0, 0}"
+ [(set_attr "type" "icmp")])
(define_insn "cmpqi_1"
- [(set (cc0)
- (compare (match_operand:QI 0 "nonimmediate_operand" "q,mq")
- (match_operand:QI 1 "general_operand" "qm,nq")))]
+ [(set (reg:CC 17)
+ (compare:CC (match_operand:QI 0 "nonimmediate_operand" "qm,q")
+ (match_operand:QI 1 "general_operand" "qi,mq")))]
"GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
- "* return AS2 (cmp%B0,%1,%0);"
- [(set_attr "type" "compare")])
-
-(define_expand "cmpqi"
- [(set (cc0)
- (compare (match_operand:QI 0 "nonimmediate_operand" "")
- (match_operand:QI 1 "general_operand" "")))]
- ""
- "
-{
- if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
- operands[0] = force_reg (QImode, operands[0]);
-
- i386_compare_gen = gen_cmpqi_1;
- i386_compare_op0 = operands[0];
- i386_compare_op1 = operands[1];
- DONE;
-}")
-
-;; These implement float point compares. For each of DFmode and
-;; SFmode, there is the normal insn, and an insn where the second operand
-;; is converted to the desired mode.
-
-(define_insn ""
- [(set (cc0)
- (match_operator 2 "VOIDmode_compare_op"
- [(match_operand:XF 0 "register_operand" "f")
- (match_operand:XF 1 "register_operand" "f")]))
- (clobber (match_scratch:HI 3 "=a"))]
- "TARGET_80387"
- "* return output_float_compare (insn, operands);"
- [(set_attr "type" "fcompare")])
-
-(define_insn ""
- [(set (cc0)
- (match_operator 2 "VOIDmode_compare_op"
- [(match_operand:XF 0 "register_operand" "f")
- (float_extend:XF
- (match_operand:DF 1 "nonimmediate_operand" "fm"))]))
- (clobber (match_scratch:HI 3 "=a"))]
- "TARGET_80387"
- "* return output_float_compare (insn, operands);"
- [(set_attr "type" "fcompare")])
-
-(define_insn ""
- [(set (cc0)
- (match_operator 2 "VOIDmode_compare_op"
- [(float_extend:XF
- (match_operand:DF 0 "nonimmediate_operand" "fm"))
- (match_operand:XF 1 "register_operand" "f")]))
- (clobber (match_scratch:HI 3 "=a"))]
- "TARGET_80387"
- "* return output_float_compare (insn, operands);"
- [(set_attr "type" "fcompare")])
-
-(define_insn ""
- [(set (cc0)
- (match_operator 2 "VOIDmode_compare_op"
- [(match_operand:XF 0 "register_operand" "f")
- (float_extend:XF
- (match_operand:SF 1 "nonimmediate_operand" "fm"))]))
- (clobber (match_scratch:HI 3 "=a"))]
- "TARGET_80387"
- "* return output_float_compare (insn, operands);"
- [(set_attr "type" "fcompare")])
-
-(define_insn ""
- [(set (cc0)
- (match_operator 2 "VOIDmode_compare_op"
- [(float_extend:XF
- (match_operand:SF 0 "nonimmediate_operand" "fm"))
- (match_operand:XF 1 "register_operand" "f")]))
- (clobber (match_scratch:HI 3 "=a"))]
- "TARGET_80387"
- "* return output_float_compare (insn, operands);"
- [(set_attr "type" "fcompare")])
-
-(define_insn ""
- [(set (cc0)
- (compare:CCFPEQ (match_operand:XF 0 "register_operand" "f")
- (match_operand:XF 1 "register_operand" "f")))
- (clobber (match_scratch:HI 2 "=a"))]
- "TARGET_80387"
- "* return output_float_compare (insn, operands);"
- [(set_attr "type" "fcompare")])
-
-(define_insn ""
- [(set (cc0)
- (match_operator 2 "VOIDmode_compare_op"
- [(match_operand:DF 0 "nonimmediate_operand" "f,fm")
- (match_operand:DF 1 "nonimmediate_operand" "fm,f")]))
- (clobber (match_scratch:HI 3 "=a,a"))]
- "TARGET_80387
- && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
- "* return output_float_compare (insn, operands);"
- [(set_attr "type" "fcompare")])
-
-(define_insn ""
- [(set (cc0)
- (match_operator 2 "VOIDmode_compare_op"
- [(match_operand:DF 0 "register_operand" "f")
- (float_extend:DF
- (match_operand:SF 1 "nonimmediate_operand" "fm"))]))
- (clobber (match_scratch:HI 3 "=a"))]
- "TARGET_80387"
- "* return output_float_compare (insn, operands);"
- [(set_attr "type" "fcompare")])
-
-(define_insn ""
- [(set (cc0)
- (match_operator 2 "VOIDmode_compare_op"
- [(float_extend:DF
- (match_operand:SF 0 "nonimmediate_operand" "fm"))
- (match_operand:DF 1 "register_operand" "f")]))
- (clobber (match_scratch:HI 3 "=a"))]
- "TARGET_80387"
- "* return output_float_compare (insn, operands);"
- [(set_attr "type" "fcompare")])
-
-(define_insn ""
- [(set (cc0)
- (match_operator 2 "VOIDmode_compare_op"
- [(float_extend:DF
- (match_operand:SF 0 "register_operand" "f"))
- (match_operand:DF 1 "nonimmediate_operand" "fm")]))
- (clobber (match_scratch:HI 3 "=a"))]
- "TARGET_80387"
- "* return output_float_compare (insn, operands);"
- [(set_attr "type" "fcompare")])
-
-(define_insn ""
- [(set (cc0)
- (compare:CCFPEQ (match_operand:DF 0 "register_operand" "f")
- (match_operand:DF 1 "register_operand" "f")))
- (clobber (match_scratch:HI 2 "=a"))]
- "TARGET_80387"
- "* return output_float_compare (insn, operands);"
- [(set_attr "type" "fcompare")])
-
-;; These two insns will never be generated by combine due to the mode of
-;; the COMPARE.
-;(define_insn ""
-; [(set (cc0)
-; (compare:CCFPEQ (match_operand:DF 0 "register_operand" "f")
-; (float_extend:DF
-; (match_operand:SF 1 "register_operand" "f"))))
-; (clobber (match_scratch:HI 2 "=a"))]
-; "TARGET_80387"
-; "* return output_float_compare (insn, operands);")
-;
-;(define_insn ""
-; [(set (cc0)
-; (compare:CCFPEQ (float_extend:DF
-; (match_operand:SF 0 "register_operand" "f"))
-; (match_operand:DF 1 "register_operand" "f")))
-; (clobber (match_scratch:HI 2 "=a"))]
-; "TARGET_80387"
-; "* return output_float_compare (insn, operands);")
-
-(define_insn "*cmpsf_cc_1"
- [(set (cc0)
- (match_operator 2 "VOIDmode_compare_op"
- [(match_operand:SF 0 "nonimmediate_operand" "f,fm")
- (match_operand:SF 1 "nonimmediate_operand" "fm,f")]))
- (clobber (match_scratch:HI 3 "=a,a"))]
- "TARGET_80387
- && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
- "* return output_float_compare (insn, operands);"
- [(set_attr "type" "fcompare")])
-
-(define_insn ""
- [(set (cc0)
- (compare:CCFPEQ (match_operand:SF 0 "register_operand" "f")
- (match_operand:SF 1 "register_operand" "f")))
- (clobber (match_scratch:HI 2 "=a"))]
- "TARGET_80387"
- "* return output_float_compare (insn, operands);"
- [(set_attr "type" "fcompare")])
+ "cmp{b}\\t{%1, %0|%0, %1}"
+ [(set_attr "type" "icmp")])
+
+(define_insn "*cmpqi_ext_1"
+ [(set (reg:CC 17)
+ (compare:CC
+ (match_operand:QI 0 "general_operand" "qm")
+ (subreg:QI
+ (zero_extract:SI
+ (match_operand 1 "ext_register_operand" "q")
+ (const_int 8)
+ (const_int 8)) 0)))]
+ ""
+ "cmp{b}\\t{%h1, %0|%0, %h1}"
+ [(set_attr "type" "icmp")])
+
+(define_insn "*cmpqi_ext_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (subreg:QI
+ (zero_extract:SI
+ (match_operand 0 "ext_register_operand" "q")
+ (const_int 8)
+ (const_int 8)) 0)
+ (match_operand:QI 1 "const0_operand" "n")))]
+ ""
+ "test{b}\\t%h0, %h0"
+ [(set_attr "type" "icmp")])
+
+(define_insn "cmpqi_ext_3"
+ [(set (reg:CC 17)
+ (compare:CC
+ (subreg:QI
+ (zero_extract:SI
+ (match_operand 0 "ext_register_operand" "q")
+ (const_int 8)
+ (const_int 8)) 0)
+ (match_operand:QI 1 "general_operand" "qmn")))]
+ ""
+ "cmp{b}\\t{%1, %h0|%h0, %1}"
+ [(set_attr "type" "icmp")])
+
+(define_insn "*cmpqi_ext_4"
+ [(set (reg:CC 17)
+ (compare:CC
+ (subreg:QI
+ (zero_extract:SI
+ (match_operand 0 "ext_register_operand" "q")
+ (const_int 8)
+ (const_int 8)) 0)
+ (subreg:QI
+ (zero_extract:SI
+ (match_operand 1 "ext_register_operand" "q")
+ (const_int 8)
+ (const_int 8)) 0)))]
+ ""
+ "cmp{b}\\t{%h1, %h0|%h0, %h1}"
+ [(set_attr "type" "icmp")])
+
+;; These implement float point compares.
+;; %%% See if we can get away with VOIDmode operands on the actual insns,
+;; which would allow mix and match FP modes on the compares. Which is what
+;; the old patterns did, but with many more of them.
(define_expand "cmpxf"
- [(set (cc0)
- (compare (match_operand:XF 0 "register_operand" "")
- (match_operand:XF 1 "register_operand" "")))]
+ [(set (reg:CC 17)
+ (compare:CC (match_operand:XF 0 "cmp_fp_expander_operand" "")
+ (match_operand:XF 1 "cmp_fp_expander_operand" "")))]
"TARGET_80387"
"
{
- i386_compare_gen = gen_cmpxf_cc;
- i386_compare_gen_eq = gen_cmpxf_ccfpeq;
- i386_compare_op0 = operands[0];
- i386_compare_op1 = operands[1];
+ ix86_compare_op0 = operands[0];
+ ix86_compare_op1 = operands[1];
DONE;
}")
(define_expand "cmpdf"
- [(set (cc0)
- (compare (match_operand:DF 0 "register_operand" "")
- (match_operand:DF 1 "general_operand" "")))]
+ [(set (reg:CC 17)
+ (compare:CC (match_operand:DF 0 "cmp_fp_expander_operand" "")
+ (match_operand:DF 1 "cmp_fp_expander_operand" "")))]
"TARGET_80387"
"
{
- i386_compare_gen = gen_cmpdf_cc;
- i386_compare_gen_eq = gen_cmpdf_ccfpeq;
- i386_compare_op0 = operands[0];
- i386_compare_op1 = (immediate_operand (operands[1], DFmode))
- ? copy_to_mode_reg (DFmode, operands[1]) : operands[1];
+ ix86_compare_op0 = operands[0];
+ ix86_compare_op1 = operands[1];
DONE;
}")
(define_expand "cmpsf"
- [(set (cc0)
- (compare (match_operand:SF 0 "register_operand" "")
- (match_operand:SF 1 "general_operand" "")))]
+ [(set (reg:CC 17)
+ (compare:CC (match_operand:SF 0 "cmp_fp_expander_operand" "")
+ (match_operand:SF 1 "cmp_fp_expander_operand" "")))]
"TARGET_80387"
"
{
- i386_compare_gen = gen_cmpsf_cc;
- i386_compare_gen_eq = gen_cmpsf_ccfpeq;
- i386_compare_op0 = operands[0];
- i386_compare_op1 = (immediate_operand (operands[1], SFmode))
- ? copy_to_mode_reg (SFmode, operands[1]) : operands[1];
+ ix86_compare_op0 = operands[0];
+ ix86_compare_op1 = operands[1];
DONE;
}")
-(define_expand "cmpxf_cc"
- [(parallel [(set (cc0)
- (compare (match_operand:XF 0 "register_operand" "")
- (match_operand:XF 1 "register_operand" "")))
- (clobber (match_scratch:HI 2 ""))])]
- "TARGET_80387"
- "")
+;; FP compares, step 1:
+;; Set the FP condition codes.
+;;
+;; CCFPmode compare with exceptions
+;; CCFPUmode compare with no exceptions
-(define_expand "cmpxf_ccfpeq"
- [(parallel [(set (cc0)
- (compare:CCFPEQ (match_operand:XF 0 "register_operand" "")
- (match_operand:XF 1 "register_operand" "")))
- (clobber (match_scratch:HI 2 ""))])]
- "TARGET_80387"
- "")
+;; %%% It is an unfortunate fact that ftst has no non-popping variant,
+;; and that fp moves clobber the condition codes, and that there is
+;; currently no way to describe this fact to reg-stack. So there are
+;; no splitters yet for this.
-(define_expand "cmpdf_cc"
- [(parallel [(set (cc0)
- (compare (match_operand:DF 0 "register_operand" "")
- (match_operand:DF 1 "register_operand" "")))
- (clobber (match_scratch:HI 2 ""))])]
- "TARGET_80387"
- "")
+;; %%% YIKES! This scheme does not retain a strong connection between
+;; the real compare and the ultimate cc0 user, so CC_REVERSE does not
+;; work! Only allow tos/mem with tos in op 0.
+;;
+;; Hmm, of course, this is what the actual _hardware_ does. Perhaps
+;; things aren't as bad as they sound...
-(define_expand "cmpdf_ccfpeq"
- [(parallel [(set (cc0)
- (compare:CCFPEQ (match_operand:DF 0 "register_operand" "")
- (match_operand:DF 1 "register_operand" "")))
- (clobber (match_scratch:HI 2 ""))])]
- "TARGET_80387"
- "
+(define_insn "*cmpfp_0"
+ [(set (match_operand:HI 0 "register_operand" "=a")
+ (unspec:HI
+ [(compare:CCFP (match_operand 1 "register_operand" "f")
+ (match_operand 2 "const0_operand" "X"))] 9))]
+ "TARGET_80387
+ && FLOAT_MODE_P (GET_MODE (operands[1]))
+ && GET_MODE (operands[1]) == GET_MODE (operands[2])"
+ "*
{
- if (! register_operand (operands[1], DFmode))
- operands[1] = copy_to_mode_reg (DFmode, operands[1]);
-}")
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"ftst\;fnstsw\\t%0\;fstp\\t%y0\";
+ else
+ return \"ftst\;fnstsw\\t%0\";
+}"
+ [(set_attr "type" "multi")])
-(define_expand "cmpsf_cc"
- [(parallel [(set (cc0)
- (compare (match_operand:SF 0 "register_operand" "")
- (match_operand:SF 1 "register_operand" "")))
- (clobber (match_scratch:HI 2 ""))])]
- "TARGET_80387"
- "")
+;; We may not use "#" to split and emit these, since the REG_DEAD notes
+;; used to manage the reg stack popping would not be preserved.
-(define_expand "cmpsf_ccfpeq"
- [(parallel [(set (cc0)
- (compare:CCFPEQ (match_operand:SF 0 "register_operand" "")
- (match_operand:SF 1 "register_operand" "")))
- (clobber (match_scratch:HI 2 ""))])]
+(define_insn "*cmpfp_2_sf"
+ [(set (reg:CCFP 18)
+ (compare:CCFP
+ (match_operand:SF 0 "register_operand" "f")
+ (match_operand:SF 1 "nonimmediate_operand" "fm")))]
"TARGET_80387"
- "
-{
- if (! register_operand (operands[1], SFmode))
- operands[1] = copy_to_mode_reg (SFmode, operands[1]);
-}")
-
-;; logical compare
+ "* return output_fp_compare (insn, operands, 0, 0);"
+ [(set_attr "type" "fcmp")])
(define_insn ""
- [(set (cc0)
- (and:SI (match_operand:SI 0 "general_operand" "%ro")
- (match_operand:SI 1 "nonmemory_operand" "ri")))]
- ""
- "*
-{
- /* For small integers, we may actually use testb. */
- if (GET_CODE (operands[1]) == CONST_INT
- && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
- && (! REG_P (operands[0]) || QI_REG_P (operands[0]))
- /* A Pentium test is pairable only with eax. Not with ah or al. */
- && (! REG_P (operands[0]) || REGNO (operands[0]) || !TARGET_PENTIUM
- || optimize_size))
- {
- /* We may set the sign bit spuriously. */
-
- if ((INTVAL (operands[1]) & ~0xff) == 0)
- {
- cc_status.flags |= CC_NOT_NEGATIVE;
- return AS2 (test%B0,%1,%b0);
- }
-
- if ((INTVAL (operands[1]) & ~0xff00) == 0)
- {
- cc_status.flags |= CC_NOT_NEGATIVE;
- operands[1] = GEN_INT (INTVAL (operands[1]) >> 8);
-
- if (QI_REG_P (operands[0]))
- return AS2 (test%B0,%1,%h0);
- else
- {
- operands[0] = adj_offsettable_operand (operands[0], 1);
- return AS2 (test%B0,%1,%b0);
- }
- }
-
- if (GET_CODE (operands[0]) == MEM
- && (INTVAL (operands[1]) & ~0xff0000) == 0)
- {
- cc_status.flags |= CC_NOT_NEGATIVE;
- operands[1] = GEN_INT (INTVAL (operands[1]) >> 16);
- operands[0] = adj_offsettable_operand (operands[0], 2);
- return AS2 (test%B0,%1,%b0);
- }
-
- if (GET_CODE (operands[0]) == MEM
- && (INTVAL (operands[1]) & ~0xff000000) == 0)
- {
- operands[1] = GEN_INT ((INTVAL (operands[1]) >> 24) & 0xff);
- operands[0] = adj_offsettable_operand (operands[0], 3);
- return AS2 (test%B0,%1,%b0);
- }
- }
-
- if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
- return AS2 (test%L0,%1,%0);
-
- return AS2 (test%L1,%0,%1);
-}"
- [(set_attr "type" "compare")])
+ [(set (match_operand:HI 0 "register_operand" "=a")
+ (unspec:HI
+ [(compare:CCFP
+ (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "nonimmediate_operand" "fm"))] 9))]
+ "TARGET_80387"
+ "* return output_fp_compare (insn, operands, 2, 0);"
+ [(set_attr "type" "fcmp")])
+
+(define_insn "*cmpfp_2_df"
+ [(set (reg:CCFP 18)
+ (compare:CCFP
+ (match_operand:DF 0 "register_operand" "f")
+ (match_operand:DF 1 "nonimmediate_operand" "fm")))]
+ "TARGET_80387"
+ "* return output_fp_compare (insn, operands, 0, 0);"
+ [(set_attr "type" "fcmp")])
(define_insn ""
- [(set (cc0)
- (and:HI (match_operand:HI 0 "general_operand" "%ro")
- (match_operand:HI 1 "nonmemory_operand" "ri")))]
- ""
- "*
-{
- if (GET_CODE (operands[1]) == CONST_INT
- && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
- && (! REG_P (operands[0]) || QI_REG_P (operands[0])))
- {
- if ((INTVAL (operands[1]) & 0xff00) == 0)
- {
- /* ??? This might not be necessary. */
- if (INTVAL (operands[1]) & 0xffff0000)
- operands[1] = GEN_INT (INTVAL (operands[1]) & 0xff);
-
- /* We may set the sign bit spuriously. */
- cc_status.flags |= CC_NOT_NEGATIVE;
- return AS2 (test%B0,%1,%b0);
- }
-
- if ((INTVAL (operands[1]) & 0xff) == 0)
- {
- operands[1] = GEN_INT ((INTVAL (operands[1]) >> 8) & 0xff);
-
- if (QI_REG_P (operands[0]))
- return AS2 (test%B0,%1,%h0);
- else
- {
- operands[0] = adj_offsettable_operand (operands[0], 1);
- return AS2 (test%B0,%1,%b0);
- }
- }
- }
-
- /* use 32-bit test instruction if there are no sign issues */
- if (GET_CODE (operands[1]) == CONST_INT
- && !(INTVAL (operands[1]) & ~0x7fff)
- && i386_aligned_p (operands[0]))
- return AS2 (test%L0,%1,%k0);
-
- if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
- return AS2 (test%W0,%1,%0);
-
- return AS2 (test%W1,%0,%1);
-}"
- [(set_attr "type" "compare")])
+ [(set (match_operand:HI 0 "register_operand" "=a")
+ (unspec:HI
+ [(compare:CCFP
+ (match_operand:DF 1 "register_operand" "f")
+ (match_operand:DF 2 "nonimmediate_operand" "fm"))] 9))]
+ "TARGET_80387"
+ "* return output_fp_compare (insn, operands, 2, 0);"
+ [(set_attr "type" "multi")])
+
+(define_insn "*cmpfp_2_xf"
+ [(set (reg:CCFP 18)
+ (compare:CCFP
+ (match_operand:XF 0 "register_operand" "f")
+ (match_operand:XF 1 "register_operand" "f")))]
+ "TARGET_80387"
+ "* return output_fp_compare (insn, operands, 0, 0);"
+ [(set_attr "type" "fcmp")])
(define_insn ""
- [(set (cc0)
- (and:QI (match_operand:QI 0 "nonimmediate_operand" "%qm")
- (match_operand:QI 1 "nonmemory_operand" "qi")))]
- ""
- "*
-{
- if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
- return AS2 (test%B0,%1,%0);
-
- return AS2 (test%B1,%0,%1);
-}"
- [(set_attr "type" "compare")])
-
-;; move instructions.
-;; There is one for each machine mode,
-;; and each is preceded by a corresponding push-insn pattern
-;; (since pushes are not general_operands on the 386).
+ [(set (match_operand:HI 0 "register_operand" "=a")
+ (unspec:HI
+ [(compare:CCFP
+ (match_operand:XF 1 "register_operand" "f")
+ (match_operand:XF 2 "register_operand" "f"))] 9))]
+ "TARGET_80387"
+ "* return output_fp_compare (insn, operands, 2, 0);"
+ [(set_attr "type" "multi")])
+
+(define_insn "*cmpfp_2u"
+ [(set (reg:CCFPU 18)
+ (compare:CCFPU
+ (match_operand 0 "register_operand" "f")
+ (match_operand 1 "register_operand" "f")))]
+ "TARGET_80387
+ && FLOAT_MODE_P (GET_MODE (operands[0]))
+ && GET_MODE (operands[0]) == GET_MODE (operands[1])"
+ "* return output_fp_compare (insn, operands, 0, 1);"
+ [(set_attr "type" "fcmp")])
(define_insn ""
- [(set (match_operand:SI 0 "push_operand" "=<")
- (match_operand:SI 1 "nonmemory_operand" "rn"))]
- "flag_pic"
- "* return AS1 (push%L0,%1);"
- [(set_attr "memory" "store")])
+ [(set (match_operand:HI 0 "register_operand" "=a")
+ (unspec:HI
+ [(compare:CCFPU
+ (match_operand 1 "register_operand" "f")
+ (match_operand 2 "register_operand" "f"))] 9))]
+ "TARGET_80387
+ && FLOAT_MODE_P (GET_MODE (operands[1]))
+ && GET_MODE (operands[1]) == GET_MODE (operands[2])"
+ "* return output_fp_compare (insn, operands, 2, 1);"
+ [(set_attr "type" "multi")])
-(define_insn ""
- [(set (match_operand:SI 0 "push_operand" "=<")
- (match_operand:SI 1 "nonmemory_operand" "ri"))]
- "!flag_pic"
- "* return AS1 (push%L0,%1);"
- [(set_attr "memory" "store")])
+;; Patterns to match the SImode-in-memory ficom instructions.
+;;
+;; %%% Play games with accepting gp registers, as otherwise we have to
+;; force them to memory during rtl generation, which is no good. We
+;; can get rid of this once we teach reload to do memory input reloads
+;; via pushes.
+
+(define_insn ""
+ [(set (reg:CCFP 18)
+ (compare:CCFP
+ (match_operand 0 "register_operand" "f,f")
+ (float (match_operand:SI 1 "nonimmediate_operand" "m,?r"))))]
+ "0 && TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[0]))
+ && GET_MODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == GET_MODE (operands[0])"
+ "#")
-;; On a 386, it is faster to push MEM directly.
+;; Split the not-really-implemented gp register case into a
+;; push-op-pop sequence.
+;;
+;; %%% This is most efficient, but am I gonna get in trouble
+;; for separating cc0_setter and cc0_user?
-(define_insn ""
- [(set (match_operand:SI 0 "push_operand" "=<")
- (match_operand:SI 1 "memory_operand" "m"))]
- "TARGET_PUSH_MEMORY"
- "* return AS1 (push%L0,%1);"
- [(set_attr "type" "memory")
- (set_attr "memory" "load")])
+(define_split
+ [(set (reg:CCFP 18)
+ (compare:CCFP
+ (match_operand:SF 0 "register_operand" "")
+ (float (match_operand:SI 1 "register_operand" ""))))]
+ "0 && TARGET_80387 && reload_completed"
+ [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 1))
+ (set (reg:CCFP 18) (compare:CCFP (match_dup 0) (match_dup 2)))
+ (parallel [(set (match_dup 1) (mem:SI (reg:SI 7)))
+ (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])]
+ "operands[2] = gen_rtx_MEM (Pmode, stack_pointer_rtx);
+ operands[2] = gen_rtx_FLOAT (GET_MODE (operands[0]), operands[2]);")
+
+;; FP compares, step 2
+;; Move the fpsw to ax.
+
+(define_insn "x86_fnstsw_1"
+ [(set (match_operand:HI 0 "register_operand" "=a")
+ (unspec:HI [(reg 18)] 9))]
+ "TARGET_80387"
+ "fnstsw\\t%0"
+ [(set_attr "length" "2")
+ (set_attr "ppro_uops" "few")])
+
+;; FP compares, step 3
+;; Get ax into flags, general case.
+
+(define_insn "x86_sahf_1"
+ [(set (reg:CC 17)
+ (unspec:CC [(match_operand:HI 0 "register_operand" "a")] 10))]
+ ""
+ "sahf"
+ [(set_attr "length" "1")
+ (set_attr "ppro_uops" "one")])
+
+;; Pentium Pro can do steps 1 through 3 in one go.
+
+(define_insn "*cmpfp_i"
+ [(set (reg:CCFP 17)
+ (compare:CCFP (match_operand 0 "register_operand" "f")
+ (match_operand 1 "register_operand" "f")))]
+ "TARGET_80387 && TARGET_CMOVE
+ && FLOAT_MODE_P (GET_MODE (operands[0]))
+ && GET_MODE (operands[0]) == GET_MODE (operands[0])"
+ "* return output_fp_compare (insn, operands, 1, 0);"
+ [(set_attr "type" "fcmp")])
+
+(define_insn "*cmpfp_iu"
+ [(set (reg:CCFPU 17)
+ (compare:CCFPU (match_operand 0 "register_operand" "f")
+ (match_operand 1 "register_operand" "f")))]
+ "TARGET_80387 && TARGET_CMOVE
+ && FLOAT_MODE_P (GET_MODE (operands[0]))
+ && GET_MODE (operands[0]) == GET_MODE (operands[1])"
+ "* return output_fp_compare (insn, operands, 1, 1);"
+ [(set_attr "type" "fcmp")])
+
+;; Move instructions.
;; General case of fullword move.
-;; If generating PIC code and operands[1] is a symbolic CONST, emit a
-;; move to get the address of the symbolic object from the GOT.
-
(define_expand "movsi"
- [(set (match_operand:SI 0 "general_operand" "")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
(match_operand:SI 1 "general_operand" ""))]
""
- "
-{
- extern int flag_pic;
+ "ix86_expand_move (SImode, operands); DONE;")
- if (flag_pic && SYMBOLIC_CONST (operands[1]))
- emit_pic_move (operands, SImode);
+;; Push/pop instructions. They are separate since autoinc/dec is not a
+;; general_operand.
+;;
+;; %%% We don't use a post-inc memory reference because x86 is not a
+;; general AUTO_INC_DEC host, which impacts how it is treated in flow.
+;; Changing this impacts compiler performance on other non-AUTO_INC_DEC
+;; targets without our curiosities, and it is just as easy to represent
+;; this differently.
- /* Don't generate memory->memory moves, go through a register */
- else if (TARGET_MOVE
- && no_new_pseudos == 0
- && GET_CODE (operands[0]) == MEM
- && GET_CODE (operands[1]) == MEM)
- {
- operands[1] = force_reg (SImode, operands[1]);
- }
-}")
+(define_insn "pushsi2"
+ [(set (match_operand:SI 0 "push_operand" "=<")
+ (match_operand:SI 1 "general_operand" "ri*m"))]
+ ""
+ "push{l}\\t%1"
+ [(set_attr "type" "push")])
-;; On i486, incl reg is faster than movl $1,reg.
+(define_insn "popsi1"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r*m")
+ (mem:SI (reg:SI 7)))
+ (set (reg:SI 7)
+ (plus:SI (reg:SI 7) (const_int 4)))]
+ ""
+ "pop{l}\\t%0"
+ [(set_attr "type" "pop")])
-(define_insn ""
- [(set (match_operand:SI 0 "general_operand" "=g,r,r")
- (match_operand:SI 1 "general_operand" "rn,i,m"))]
- "((!TARGET_MOVE || GET_CODE (operands[0]) != MEM)
- || (GET_CODE (operands[1]) != MEM))
- && flag_pic"
+(define_insn "*movsi_1"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
+ (match_operand:SI 1 "general_operand" "rim,ri"))
+ (clobber (reg:CC 17))]
+ "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
"*
{
- rtx link;
-
- /* K6: mov reg,0 is slightly faster than xor reg,reg but is 3 bytes
- longer. */
- if ((ix86_cpu != PROCESSOR_K6 || optimize_size)
- && operands[1] == const0_rtx && REG_P (operands[0]))
- return AS2 (xor%L0,%0,%0);
-
- if (operands[1] == const1_rtx
- /* PPRO and K6 prefer mov to inc to reduce dependencies. */
- && (optimize_size || (int)ix86_cpu < (int)PROCESSOR_PENTIUMPRO)
- && (link = find_reg_note (insn, REG_WAS_0, 0))
- /* Make sure the insn that stored the 0 is still present. */
- && ! INSN_DELETED_P (XEXP (link, 0))
- && GET_CODE (XEXP (link, 0)) != NOTE
- /* Make sure cross jumping didn't happen here. */
- && no_labels_between_p (XEXP (link, 0), insn)
- /* Make sure the reg hasn't been clobbered. */
- && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
- /* Fastest way to change a 0 to a 1. */
- return AS1 (inc%L0,%0);
-
- if (SYMBOLIC_CONST (operands[1]))
- return AS2 (lea%L0,%a1,%0);
-
- return AS2 (mov%L0,%1,%0);
+ switch (get_attr_type (insn))
+ {
+ case TYPE_ALU1:
+ if (operands[1] != const0_rtx)
+ abort();
+ return \"xor{l}\\t{%0, %0|%0, %0}\";
+ case TYPE_LEA:
+ return \"lea{l}\\t{%1, %0|%0, %1}\";
+ default:
+ if (flag_pic && SYMBOLIC_CONST (operands[1]))
+ abort();
+ return \"mov{l}\\t{%1, %0|%0, %1}\";
+ }
}"
- [(set_attr "type" "integer,integer,memory")
- (set_attr "memory" "*,*,load")])
-
-(define_insn ""
- [(set (match_operand:SI 0 "general_operand" "=g,r")
- (match_operand:SI 1 "general_operand" "ri,m"))]
- "((!TARGET_MOVE || GET_CODE (operands[0]) != MEM)
- || (GET_CODE (operands[1]) != MEM))
- && !flag_pic"
+ [(set (attr "type")
+ (cond [(and (match_operand:SI 1 "const0_operand" "")
+ (and (match_operand:SI 0 "register_operand" "")
+ (ne (symbol_ref "TARGET_USE_MOV0") (const_int 0))))
+ (const_string "alu1")
+ (and (ne (symbol_ref "flag_pic") (const_int 0))
+ (match_operand:SI 1 "symbolic_operand" ""))
+ (const_string "lea")
+ ]
+ (const_string "imov")))])
+
+(define_insn "*movsi_2"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
+ (match_operand:SI 1 "general_operand" "rinm,rin"))]
+ "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
"*
{
- rtx link;
-
- /* Use of xor was disabled for AMD K6 as recommended by the Optimization
- Manual. My test shows, that this generally hurts the performance, because
- mov is longer and takes longer to decode and decoding is the main
- bottleneck of K6 when executing GCC code. */
-
- if (operands[1] == const0_rtx && REG_P (operands[0]))
- return AS2 (xor%L0,%0,%0);
-
- if (operands[1] == const1_rtx
- /* PPRO and K6 prefer mov to inc to reduce dependencies. */
- && (optimize_size || (int)ix86_cpu < (int)PROCESSOR_PENTIUMPRO)
- && (link = find_reg_note (insn, REG_WAS_0, 0))
- /* Make sure the insn that stored the 0 is still present. */
- && ! INSN_DELETED_P (XEXP (link, 0))
- && GET_CODE (XEXP (link, 0)) != NOTE
- /* Make sure cross jumping didn't happen here. */
- && no_labels_between_p (XEXP (link, 0), insn)
- /* Make sure the reg hasn't been clobbered. */
- && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
- /* Fastest way to change a 0 to a 1. */
- return AS1 (inc%L0,%0);
-
- return AS2 (mov%L0,%1,%0);
+ switch (get_attr_type (insn))
+ {
+ case TYPE_LEA:
+ return \"lea{l}\\t{%1, %0|%0, %1}\";
+ default:
+ if (flag_pic && SYMBOLIC_CONST (operands[1]))
+ abort();
+ return \"mov{l}\\t{%1, %0|%0, %1}\";
+ }
}"
- [(set_attr "type" "integer,memory")
- (set_attr "memory" "*,load")])
-
-(define_insn ""
- [(set (match_operand:HI 0 "push_operand" "=<")
- (match_operand:HI 1 "nonmemory_operand" "ri"))]
+ [(set (attr "type")
+ (cond [(and (ne (symbol_ref "flag_pic") (const_int 0))
+ (match_operand:SI 1 "symbolic_operand" ""))
+ (const_string "lea")
+ ]
+ (const_string "imov")))])
+
+(define_insn "*swapsi"
+ [(set (match_operand:SI 0 "register_operand" "+r")
+ (match_operand:SI 1 "register_operand" "+r"))
+ (set (match_dup 1)
+ (match_dup 0))]
""
- "* return AS1 (push%W0,%1);"
- [(set_attr "type" "memory")
- (set_attr "memory" "store")])
-
-(define_insn ""
- [(set (match_operand:HI 0 "push_operand" "=<")
- (match_operand:HI 1 "memory_operand" "m"))]
- "TARGET_PUSH_MEMORY"
- "* return AS1 (push%W0,%1);"
- [(set_attr "type" "memory")
- (set_attr "memory" "load")])
-
-;; On i486, an incl and movl are both faster than incw and movw.
+ "xchg{l}\\t%1, %0"
+ [(set_attr "type" "imov")
+ (set_attr "pent_pair" "np")
+ (set_attr "ppro_uops" "few")])
(define_expand "movhi"
- [(set (match_operand:HI 0 "general_operand" "")
- (match_operand:HI 1 "general_operand" ""))]
+ [(set (match_operand:HI 0 "nonimmediate_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
""
- "
+ "ix86_expand_move (HImode, operands); DONE;")
+
+(define_insn "pushhi2"
+ [(set (match_operand:HI 0 "push_operand" "=<,<")
+ (match_operand:HI 1 "general_operand" "n,r*m"))]
+ ""
+ "@
+ push{w}\\t{|WORD PTR }%1
+ push{w}\\t%1"
+ [(set_attr "type" "push")])
+
+(define_insn "pophi1"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r*m")
+ (mem:HI (reg:SI 7)))
+ (set (reg:SI 7)
+ (plus:SI (reg:SI 7) (const_int 2)))]
+ ""
+ "pop{w}\\t%0"
+ [(set_attr "type" "pop")])
+
+(define_insn "*movhi_1"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m")
+ (match_operand:HI 1 "general_operand" "rn,rm,rn"))
+ (clobber (reg:CC 17))]
+ "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
+ "*
{
- /* Don't generate memory->memory moves, go through a register */
- if (TARGET_MOVE
- && no_new_pseudos == 0
- && GET_CODE (operands[0]) == MEM
- && GET_CODE (operands[1]) == MEM)
+ switch (get_attr_type (insn))
{
- operands[1] = force_reg (HImode, operands[1]);
+ case TYPE_ALU1:
+ /* Clear the whole register -- smaller, faster, better. */
+ if (operands[1] != const0_rtx)
+ abort();
+ return \"xor{l}\\t%k0, %k0\";
+ case TYPE_IMOVX:
+ return \"movz{wl|x}\\t{%1, %k0|%k0, %1}\";
+ default:
+ if (get_attr_length_prefix (insn) == 0)
+ return \"mov{l}\\t{%k1, %k0|%k0, %k1}\";
+ else
+ return \"mov{w}\\t{%1, %0|%0, %1}\";
}
-}")
-
-(define_insn ""
- [(set (match_operand:HI 0 "general_operand" "=g,r")
- (match_operand:HI 1 "general_operand" "ri,m"))]
- "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
+}"
+ [(set (attr "type")
+ (cond [(and (match_operand:HI 1 "const0_operand" "")
+ (and (match_operand:HI 0 "register_operand" "")
+ (ne (symbol_ref "TARGET_USE_MOV0") (const_int 0))))
+ (const_string "alu1")
+ (and (ne (symbol_ref "TARGET_MOVX")
+ (const_int 0))
+ (eq_attr "alternative" "1"))
+ (const_string "imovx")
+ ]
+ (const_string "imov")))
+ (set (attr "length_prefix")
+ (cond [(eq_attr "type" "imovx")
+ (const_string "0")
+ (and (eq_attr "alternative" "0")
+ (eq (symbol_ref "TARGET_PARTIAL_REG_STALL")
+ (const_int 0)))
+ (const_string "0")
+ ]
+ (const_string "1")))
+ ; There's no place to override just the immediate length
+ (set (attr "length")
+ (cond [(and (eq_attr "type" "imov")
+ (and (eq_attr "length_prefix" "0")
+ (match_operand:HI 1 "immediate_operand" "")))
+ (const_string "5")
+ ]
+ (const_string "*")))])
+
+(define_insn "*movhi_2"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m")
+ (match_operand:HI 1 "general_operand" "rn,rm,rn"))]
+ "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
"*
{
- rtx link;
- if (REG_P (operands[0]) && operands[1] == const0_rtx)
- return AS2 (xor%L0,%k0,%k0);
-
- if (REG_P (operands[0]) && operands[1] == const1_rtx
- /* PPRO and K6 prefer mov to inc to reduce dependencies. */
- && (optimize_size || (int)ix86_cpu < (int)PROCESSOR_PENTIUMPRO)
- && (link = find_reg_note (insn, REG_WAS_0, 0))
- /* Make sure the insn that stored the 0 is still present. */
- && ! INSN_DELETED_P (XEXP (link, 0))
- && GET_CODE (XEXP (link, 0)) != NOTE
- /* Make sure cross jumping didn't happen here. */
- && no_labels_between_p (XEXP (link, 0), insn)
- /* Make sure the reg hasn't been clobbered. */
- && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
- /* Fastest way to change a 0 to a 1. */
- return AS1 (inc%L0,%k0);
-
- if (REG_P (operands[0]))
+ switch (get_attr_type (insn))
{
- if (i386_aligned_p (operands[1]))
- {
- operands[1] = i386_sext16_if_const (operands[1]);
- return AS2 (mov%L0,%k1,%k0);
- }
- if (! TARGET_ZERO_EXTEND_WITH_AND)
- {
- /* movzwl is faster than movw on the Pentium Pro,
- * although not as fast as an aligned movl. */
-#ifdef INTEL_SYNTAX
- return AS2 (movzx,%1,%k0);
-#else
- return AS2 (movz%W0%L0,%1,%k0);
-#endif
- }
+ case TYPE_IMOVX:
+ /* movzwl is faster than movw on p2 due to partial word stalls,
+ though not as fast as an aligned movl. */
+ return \"movz{wl|x}\\t{%1, %k0|%k0, %1}\";
+ default:
+ if (get_attr_length_prefix (insn) == 0)
+ return \"mov{l}\\t{%k1, %k0|%k0, %k1}\";
+ else
+ return \"mov{w}\\t{%1, %0|%0, %1}\";
}
-
- return AS2 (mov%W0,%1,%0);
}"
- [(set_attr "type" "integer,memory")
- (set_attr "memory" "*,load")])
+ [(set (attr "type")
+ (cond [(eq_attr "alternative" "0")
+ (const_string "imov")
+ (and (ne (symbol_ref "TARGET_MOVX")
+ (const_int 0))
+ (eq_attr "alternative" "1"))
+ (const_string "imovx")
+ ]
+ (const_string "imov")))
+ (set (attr "length_prefix")
+ (cond [(eq_attr "type" "imovx")
+ (const_string "0")
+ (and (eq_attr "alternative" "0")
+ (eq (symbol_ref "TARGET_PARTIAL_REG_STALL")
+ (const_int 0)))
+ (const_string "0")
+ ]
+ (const_string "1")))
+ ; There's no place to override just the immediate length
+ (set (attr "length")
+ (cond [(and (eq_attr "type" "imov")
+ (and (eq_attr "length_prefix" "0")
+ (match_operand:HI 1 "immediate_operand" "")))
+ (const_string "5")
+ ]
+ (const_string "*")))])
+
+(define_insn "*swaphi_1"
+ [(set (match_operand:HI 0 "register_operand" "+r")
+ (match_operand:HI 1 "register_operand" "+r"))
+ (set (match_dup 1)
+ (match_dup 0))]
+ "TARGET_PARTIAL_REG_STALL"
+ "xchg{w}\\t%1, %0"
+ [(set_attr "type" "imov")
+ (set_attr "pent_pair" "np")
+ (set_attr "ppro_uops" "few")])
+
+(define_insn "*swaphi_2"
+ [(set (match_operand:HI 0 "register_operand" "+r")
+ (match_operand:HI 1 "register_operand" "+r"))
+ (set (match_dup 1)
+ (match_dup 0))]
+ "! TARGET_PARTIAL_REG_STALL"
+ "xchg{l}\\t%k1, %k0"
+ [(set_attr "type" "imov")
+ (set_attr "length_prefix" "0")
+ (set_attr "pent_pair" "np")
+ (set_attr "ppro_uops" "few")])
(define_expand "movstricthi"
- [(set (strict_low_part (match_operand:HI 0 "general_operand" ""))
+ [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" ""))
(match_operand:HI 1 "general_operand" ""))]
- ""
+ "! TARGET_PARTIAL_REG_STALL"
"
{
/* Don't generate memory->memory moves, go through a register */
- if (TARGET_MOVE
- && no_new_pseudos == 0
- && GET_CODE (operands[0]) == MEM
- && GET_CODE (operands[1]) == MEM)
- {
- operands[1] = force_reg (HImode, operands[1]);
- }
+ if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
+ operands[1] = force_reg (HImode, operands[1]);
}")
-(define_insn ""
+(define_insn "*movstricthi_1"
[(set (strict_low_part (match_operand:HI 0 "general_operand" "+g,r"))
- (match_operand:HI 1 "general_operand" "ri,m"))]
- "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
- "*
-{
- rtx link;
-
- /* Use of xor was disabled for AMD K6 as recommended by the Optimization
- Manual. My test shows, that this generally hurts the performance, because
- mov is longer and takes longer to decode and decoding is the main
- bottleneck of K6 when executing GCC code. */
-
- if (operands[1] == const0_rtx && REG_P (operands[0]))
- return AS2 (xor%W0,%0,%0);
-
- if (operands[1] == const1_rtx
- /* PPRO and K6 prefer mov to inc to reduce dependencies. */
- && (optimize_size || (int)ix86_cpu < (int)PROCESSOR_PENTIUMPRO)
- && (link = find_reg_note (insn, REG_WAS_0, 0))
- /* Make sure the insn that stored the 0 is still present. */
- && ! INSN_DELETED_P (XEXP (link, 0))
- && GET_CODE (XEXP (link, 0)) != NOTE
- /* Make sure cross jumping didn't happen here. */
- && no_labels_between_p (XEXP (link, 0), insn)
- /* Make sure the reg hasn't been clobbered. */
- && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
- /* Fastest way to change a 0 to a 1. */
- return AS1 (inc%W0,%0);
-
- return AS2 (mov%W0,%1,%0);
-}"
- [(set_attr "type" "integer,memory")])
-
-;; emit_push_insn when it calls move_by_pieces
-;; requires an insn to "push a byte".
-;; But actually we use pushw, which has the effect of rounding
-;; the amount pushed up to a halfword.
-(define_insn ""
- [(set (match_operand:QI 0 "push_operand" "=<")
- (match_operand:QI 1 "const_int_operand" "n"))]
- ""
- "* return AS1(push%W0,%1);")
-
-(define_insn ""
- [(set (match_operand:QI 0 "push_operand" "=<")
- (match_operand:QI 1 "register_operand" "q"))]
- ""
- "*
-{
- operands[1] = gen_rtx_REG (HImode, REGNO (operands[1]));
- return AS1 (push%W0,%1);
-}")
-
-;; On i486, incb reg is faster than movb $1,reg.
-
-;; ??? Do a recognizer for zero_extract that looks just like this, but reads
-;; or writes %ah, %bh, %ch, %dh.
+ (match_operand:HI 1 "general_operand" "rn,m"))]
+ "! TARGET_PARTIAL_REG_STALL
+ && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
+ "mov{w}\\t{%1, %0|%0, %1}"
+ [(set_attr "type" "imov")])
(define_expand "movqi"
[(set (match_operand:QI 0 "general_operand" "")
(match_operand:QI 1 "general_operand" ""))]
""
- "
+ "ix86_expand_move (QImode, operands); DONE;")
+
+;; emit_push_insn when it calls move_by_pieces requires an insn to
+;; "push a byte". But actually we use pushw, which has the effect
+;; of rounding the amount pushed up to a halfword.
+
+(define_insn "pushqi2"
+ [(set (match_operand:QI 0 "push_operand" "=<,<")
+ (match_operand:QI 1 "nonmemory_operand" "n,r"))]
+ ""
+ "@
+ push{w}\\t{|word ptr }%1
+ push{w}\\t%w1"
+ [(set_attr "type" "push")
+ (set_attr "length_prefix" "1")
+ ; There's no place to override just the immediate length
+ (set (attr "length")
+ (if_then_else (eq_attr "length_prefix" "0")
+ (const_string "4")
+ (const_string "*")))])
+
+(define_insn "popqi1"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=r*m")
+ (mem:QI (reg:SI 7)))
+ (set (reg:SI 7)
+ (plus:SI (reg:SI 7) (const_int 2)))]
+ ""
+ "pop{w}\\t%0"
+ [(set_attr "type" "pop")
+ (set_attr "length_prefix" "1")])
+
+(define_insn "*movqi_1"
+ [(set (match_operand:QI 0 "general_operand" "=q,q,*r,*r,m")
+ (match_operand:QI 1 "general_operand" "qn,qm,*rn,qm,qn"))
+ (clobber (reg:CC 17))]
+ "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
+ "*
{
- /* Don't generate memory->memory moves, go through a register */
- if (TARGET_MOVE
- && no_new_pseudos == 0
- && GET_CODE (operands[0]) == MEM
- && GET_CODE (operands[1]) == MEM)
+ switch (get_attr_type (insn))
{
- operands[1] = force_reg (QImode, operands[1]);
+ case TYPE_ALU1:
+ /* Clear the whole register -- smaller, faster, better. */
+ if (operands[1] != const0_rtx)
+ abort();
+ return \"xor{l}\\t%k0, %k0\";
+ case TYPE_IMOVX:
+ if (!QI_REG_P (operands[1]) && GET_CODE (operands[1]) != MEM)
+ abort ();
+ return \"movz{bl|x}\\t{%1, %k0|%k0, %1}\";
+ default:
+ if (which_alternative == 2)
+ return \"mov{l}\\t{%k1, %k0|%k0, %k1}\";
+ else
+ return \"mov{b}\\t{%1, %0|%0, %1}\";
}
-}")
-
-(define_insn ""
- [(set (match_operand:QI 0 "nonimmediate_operand" "=q,*r,qm")
- (match_operand:QI 1 "general_operand" "*g,*rn,qn"))]
- "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
+}"
+ [(set (attr "type")
+ (cond [(and (match_operand:QI 1 "const0_operand" "")
+ (and (match_operand:QI 0 "register_operand" "")
+ (ne (symbol_ref "TARGET_USE_MOV0") (const_int 0))))
+ (const_string "alu1")
+ (eq_attr "alternative" "3")
+ (const_string "imovx")
+ (and (ne (symbol_ref "TARGET_MOVX")
+ (const_int 0))
+ (eq_attr "alternative" "1"))
+ (const_string "imovx")
+ ]
+ (const_string "imov")))
+ ; There's no place to override just the immediate length
+ (set (attr "length")
+ (cond [(and (eq_attr "type" "imov")
+ (and (eq_attr "alternative" "2")
+ (match_operand:HI 1 "immediate_operand" "")))
+ (const_string "5")
+ ]
+ (const_string "*")))])
+
+(define_insn "*movqi_2"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q,*r,*r,m")
+ (match_operand:QI 1 "general_operand" "qn,qm,*rn,qm,qn"))]
+ "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
"*
{
- rtx link;
-
- /* movb $0,reg8 is 2 bytes, the same as xorl reg8,reg8.
- It is at least as fast as xor on any processor except a Pentium. */
-
- if (operands[1] == const1_rtx
- && TARGET_PENTIUM
- && (link = find_reg_note (insn, REG_WAS_0, 0))
- /* Make sure the insn that stored the 0 is still present. */
- && ! INSN_DELETED_P (XEXP (link, 0))
- && GET_CODE (XEXP (link, 0)) != NOTE
- /* Make sure cross jumping didn't happen here. */
- && no_labels_between_p (XEXP (link, 0), insn)
- /* Make sure the reg hasn't been clobbered. */
- && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
+ switch (get_attr_type (insn))
{
- /* Fastest way to change a 0 to a 1.
- If inc%B0 isn't allowed, use inc%L0. */
- if (NON_QI_REG_P (operands[0]))
- return AS1 (inc%L0,%k0);
+ case TYPE_IMOVX:
+ if (!QI_REG_P (operands[1]) && GET_CODE (operands[1]) != MEM)
+ abort ();
+ return \"movz{bl|x}\\t{%1, %k0|%k0, %1}\";
+ default:
+ if (which_alternative == 2)
+ return \"mov{l}\\t{%k1, %k0|%k0, %k1}\";
else
- return AS1 (inc%B0,%0);
+ return \"mov{b}\\t{%1, %0|%0, %1}\";
}
+}"
+ [(set (attr "type")
+ (cond [(eq_attr "alternative" "3")
+ (const_string "imovx")
+ (and (ne (symbol_ref "TARGET_MOVX")
+ (const_int 0))
+ (eq_attr "alternative" "1"))
+ (const_string "imovx")
+ ]
+ (const_string "imov")))
+ ; There's no place to override just the immediate length
+ (set (attr "length")
+ (cond [(and (eq_attr "type" "imov")
+ (and (eq_attr "alternative" "2")
+ (match_operand:HI 1 "immediate_operand" "")))
+ (const_string "5")
+ ]
+ (const_string "*")))])
+
+(define_expand "reload_outqi"
+ [(parallel [(match_operand:QI 0 "" "=m")
+ (match_operand:QI 1 "register_operand" "r")
+ (match_operand:QI 2 "register_operand" "=&q")])]
+ ""
+ "
+{
+ rtx op0, op1, op2;
+ op0 = operands[0]; op1 = operands[1]; op2 = operands[2];
- /* If mov%B0 isn't allowed for one of these regs, use mov%L0. */
- if (NON_QI_REG_P (operands[0]) || NON_QI_REG_P (operands[1]))
- return (AS2 (mov%L0,%k1,%k0));
-
- return (AS2 (mov%B0,%1,%0));
+ if (reg_overlap_mentioned_p (op2, op0))
+ abort ();
+ if (! q_regs_operand (op1, QImode))
+ {
+ emit_insn (gen_movqi (op2, op1));
+ op1 = op2;
+ }
+ emit_insn (gen_movqi (op0, op1));
+ DONE;
}")
-;; If it becomes necessary to support movstrictqi into %esi or %edi,
-;; use the insn sequence:
-;;
-;; shrdl $8,srcreg,dstreg
-;; rorl $24,dstreg
-;;
-;; If operands[1] is a constant, then an andl/orl sequence would be
-;; faster.
+(define_insn "*swapqi"
+ [(set (match_operand:QI 0 "register_operand" "+r")
+ (match_operand:QI 1 "register_operand" "+r"))
+ (set (match_dup 1)
+ (match_dup 0))]
+ ""
+ "xchg{b}\\t%1, %0"
+ [(set_attr "type" "imov")
+ (set_attr "pent_pair" "np")
+ (set_attr "ppro_uops" "few")])
(define_expand "movstrictqi"
[(set (strict_low_part (match_operand:QI 0 "general_operand" ""))
(match_operand:QI 1 "general_operand" ""))]
- ""
+ "! TARGET_PARTIAL_REG_STALL"
"
{
/* Don't generate memory->memory moves, go through a register */
- if (TARGET_MOVE
- && no_new_pseudos == 0
- && GET_CODE (operands[0]) == MEM
- && GET_CODE (operands[1]) == MEM)
- {
- operands[1] = force_reg (QImode, operands[1]);
- }
+ if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
+ operands[1] = force_reg (QImode, operands[1]);
}")
-(define_insn ""
+(define_insn "*movstrictqi_1"
[(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q"))
(match_operand:QI 1 "general_operand" "*qn,m"))]
- "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
+ "! TARGET_PARTIAL_REG_STALL
+ && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
+ "mov{b}\\t{%1, %0|%0, %1}"
+ [(set_attr "type" "imov")])
+
+(define_insn "*movsi_extv_1"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extract:SI (match_operand:SI 1 "register_operand" "q")
+ (const_int 8)
+ (const_int 8)))]
+ ""
+ "movs{bl|x}\\t{%h1, %0|%0, %h1}"
+ [(set_attr "type" "imovx")])
+
+(define_insn "*movhi_extv_1"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (sign_extract:HI (match_operand:SI 1 "register_operand" "q")
+ (const_int 8)
+ (const_int 8)))]
+ ""
+ "movs{bl|x}\\t{%h1, %k0|%k0, %h1}"
+ [(set_attr "type" "imovx")])
+
+(define_insn "*movqi_extv_1"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm*r")
+ (sign_extract:QI (match_operand:SI 1 "register_operand" "q")
+ (const_int 8)
+ (const_int 8)))]
+ ""
"*
{
- rtx link;
-
- /* movb $0,reg8 is 2 bytes, the same as xorl reg8,reg8. */
-
- if (operands[1] == const1_rtx
- && TARGET_PENTIUM
- && ! NON_QI_REG_P (operands[0])
- && (link = find_reg_note (insn, REG_WAS_0, 0))
- /* Make sure the insn that stored the 0 is still present. */
- && ! INSN_DELETED_P (XEXP (link, 0))
- && GET_CODE (XEXP (link, 0)) != NOTE
- /* Make sure cross jumping didn't happen here. */
- && no_labels_between_p (XEXP (link, 0), insn)
- /* Make sure the reg hasn't been clobbered. */
- && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
- /* Fastest way to change a 0 to a 1. */
- return AS1 (inc%B0,%0);
-
- /* If mov%B0 isn't allowed for one of these regs, use mov%L0. */
- if (NON_QI_REG_P (operands[0]) || NON_QI_REG_P (operands[1]))
+ switch (get_attr_type (insn))
{
- abort ();
- return (AS2 (mov%L0,%k1,%k0));
+ case TYPE_IMOVX:
+ return \"movs{bl|x}\\t{%h1, %k0|%k0, %h1}\";
+ default:
+ return \"mov{b}\\t{%h1, %0|%0, %h1}\";
}
+}"
+ [(set (attr "type")
+ (if_then_else (and (match_operand:QI 0 "register_operand" "")
+ (ior (not (match_operand:QI 0 "q_regs_operand" ""))
+ (ne (symbol_ref "TARGET_MOVX")
+ (const_int 0))))
+ (const_string "imovx")
+ (const_string "imov")))])
+
+(define_insn "*movsi_extzv_1"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extract:SI (match_operand 1 "ext_register_operand" "q")
+ (const_int 8)
+ (const_int 8)))]
+ ""
+ "movz{bl|x}\\t{%h1, %0|%0, %h1}"
+ [(set_attr "type" "imovx")])
- return AS2 (mov%B0,%1,%0);
-}")
-
-(define_insn "movsf_push"
- [(set (match_operand:SF 0 "push_operand" "=<,<")
- (match_operand:SF 1 "general_operand" "*rfF,m"))]
- "TARGET_PUSH_MEMORY || GET_CODE (operands[1]) != MEM
- || reload_in_progress || reload_completed"
+(define_insn "*movqi_extzv_1"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm*r")
+ (subreg:QI (zero_extract:SI (match_operand 1 "ext_register_operand" "q")
+ (const_int 8)
+ (const_int 8)) 0))]
+ ""
"*
{
- if (STACK_REG_P (operands[1]))
+ switch (get_attr_type (insn))
{
- rtx xops[3];
-
- if (! STACK_TOP_P (operands[1]))
- abort ();
+ case TYPE_IMOVX:
+ return \"movz{bl|x}\\t{%h1, %k0|%k0, %h1}\";
+ default:
+ return \"mov{b}\\t{%h1, %0|%0, %h1}\";
+ }
+}"
+ [(set (attr "type")
+ (if_then_else (and (match_operand:QI 0 "register_operand" "")
+ (ior (not (match_operand:QI 0 "q_regs_operand" ""))
+ (ne (symbol_ref "TARGET_MOVX")
+ (const_int 0))))
+ (const_string "imovx")
+ (const_string "imov")))])
+
+(define_insn "*movsi_insv_1"
+ [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+q")
+ (const_int 8)
+ (const_int 8))
+ (match_operand:SI 1 "nonimmediate_operand" "qm"))]
+ ""
+ "mov{b}\\t{%b1, %h0|%h0, %b1}"
+ [(set_attr "type" "imov")])
+
+(define_insn "*movqi_insv_2"
+ [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+q")
+ (const_int 8)
+ (const_int 8))
+ (and:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "q")
+ (const_int 8))
+ (const_int 255)))]
+ ""
+ "mov{b}\\t{%h1, %h0|%h0, %h1}"
+ [(set_attr "type" "imov")])
- xops[0] = AT_SP (SFmode);
- xops[1] = GEN_INT (4);
- xops[2] = stack_pointer_rtx;
+(define_expand "movdi"
+ [(set (match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
+ ""
+ "ix86_expand_move (DImode, operands); DONE;")
- output_asm_insn (AS2 (sub%L2,%1,%2), xops);
+(define_insn "*pushdi"
+ [(set (match_operand:DI 0 "push_operand" "=<")
+ (match_operand:DI 1 "nonmemory_operand" "riF"))]
+ ""
+ "#")
- if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
- output_asm_insn (AS1 (fstp%S0,%0), xops);
- else
- output_asm_insn (AS1 (fst%S0,%0), xops);
+(define_insn "*movdi_1"
+ [(set (match_operand:DI 0 "general_operand" "=r,o")
+ (match_operand:DI 1 "general_operand" "riFo,riF"))
+ (clobber (reg:CC 17))]
+ "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
+ "#")
- RET;
- }
+(define_insn "*movdi_2"
+ [(set (match_operand:DI 0 "general_operand" "=r,o")
+ (match_operand:DI 1 "general_operand" "riFo,riF"))]
+ "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
+ "#")
- return AS1 (push%L0,%1);
+(define_split
+ [(set (match_operand:DI 0 "push_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
+ ""
+ [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 3))
+ (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 2))]
+ "
+{
+ split_di (operands+1, 1, operands+2, operands+3);
+ /* Compensate for the fact that we're changing stack offsets in
+ the middle of this operation. */
+ if (reg_mentioned_p (stack_pointer_rtx, operands[2]))
+ operands[2] = adj_offsettable_operand (operands[2], 4);
}")
+;; %%% This multiword shite has got to go.
(define_split
- [(set (match_operand:SF 0 "push_operand" "")
- (match_operand:SF 1 "general_operand" ""))]
- "reload_completed && STACK_REG_P (operands[1])"
- [(set (reg:SI 7)
- (minus:SI (reg:SI 7) (const_int 4)))
- (set (mem:SF (reg:SI 7))
- (match_dup 1))]
- "")
-
+ [(set (match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "general_operand" ""))
+ (clobber (reg:CC 17))]
+ "reload_completed"
+ [(parallel [(set (match_dup 2) (match_dup 4))
+ (clobber (reg:CC 17))])
+ (parallel [(set (match_dup 3) (match_dup 5))
+ (clobber (reg:CC 17))])]
+ "if (ix86_split_movdi (operands)) DONE;")
+
+(define_split
+ [(set (match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
+ "reload_completed"
+ [(set (match_dup 2) (match_dup 4))
+ (set (match_dup 3) (match_dup 5))]
+ "if (ix86_split_movdi (operands)) DONE;")
+
(define_expand "movsf"
[(set (match_operand:SF 0 "general_operand" "")
(match_operand:SF 1 "general_operand" ""))]
""
- "
-{
- /* Don't generate memory->memory moves, go through a register */
- if (TARGET_MOVE
- && no_new_pseudos == 0
- && GET_CODE (operands[0]) == MEM
- && GET_CODE (operands[1]) == MEM)
- {
- operands[1] = force_reg (SFmode, operands[1]);
- }
+ "ix86_expand_move (SFmode, operands); DONE;")
- /* If we are loading a floating point constant that isn't 0 or 1
- into a register, force the value to memory now, since we'll
- get better code out the back end. */
- else if ((reload_in_progress | reload_completed) == 0
- && GET_CODE (operands[0]) != MEM
- && GET_CODE (operands[1]) == CONST_DOUBLE
- && !standard_80387_constant_p (operands[1]))
- {
- operands[1] = validize_mem (force_const_mem (SFmode, operands[1]));
- }
-}")
-
-;; For the purposes of regclass, prefer FLOAT_REGS.
-(define_insn ""
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f,m,!*r,!m")
- (match_operand:SF 1 "general_operand" "fmG,f,*rmF,*rF"))]
- "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
+(define_insn "*pushsf"
+ [(set (match_operand:SF 0 "push_operand" "=<,<")
+ (match_operand:SF 1 "general_operand" "f,Ffm*r"))]
+ ""
"*
{
- int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
-
- /* First handle a `pop' insn or a `fld %st(0)' */
-
- if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1]))
+ switch (which_alternative)
{
- if (stack_top_dies)
- return AS1 (fstp,%y0);
+ case 0:
+ /* %%% We loose REG_DEAD notes for controling pops if we split late. */
+ operands[0] = gen_rtx_MEM (SFmode, stack_pointer_rtx);
+ operands[2] = stack_pointer_rtx;
+ operands[3] = GEN_INT (4);
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"sub{l}\\t{%3, %2|%2, %3}\;fstp%z0\\t%0\";
else
- return AS1 (fld,%y0);
+ return \"sub{l}\\t{%3, %2|%2, %3}\;fst%z0\\t%0\";
+
+ case 1:
+ return \"push{l}\\t%1\";
+
+ default:
+ abort ();
}
+}"
+ [(set_attr "type" "multi,push")])
- /* Handle other kinds of writes from the 387 */
+;; %%% Kill this when call knows how to work this out.
+(define_split
+ [(set (match_operand:SF 0 "push_operand" "")
+ (match_operand:SF 1 "register_operand" ""))]
+ "FP_REGNO_P (REGNO (operands[1]))"
+ [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -4)))
+ (set (mem:SF (reg:SI 7)) (match_dup 1))])
- if (STACK_TOP_P (operands[1]))
+(define_insn "*movsf_1"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=f,m,f,*r,m,*r")
+ (match_operand:SF 1 "general_operand" "fm,f,G,*rm,*r,G"))]
+ ""
+ "*
+{
+ switch (which_alternative)
{
- if (stack_top_dies)
- return AS1 (fstp%z0,%y0);
+ case 0:
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp\\t%0\";
+ else if (STACK_TOP_P (operands[0]))
+ return \"fld%z1\\t%1\";
else
- return AS1 (fst%z0,%y0);
- }
+ return \"fst\\t%0\";
- /* Handle other kinds of reads to the 387 */
-
- if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE)
- return output_move_const_single (operands);
+ case 1:
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp%z0\\t%0\";
+ else
+ return \"fst%z0\\t%0\";
- if (STACK_TOP_P (operands[0]))
- return AS1 (fld%z1,%y1);
+ case 2:
+ switch (standard_80387_constant_p (operands[1]))
+ {
+ case 1:
+ return \"fldz\";
+ case 2:
+ return \"fld1\";
+ }
+ abort();
- /* Handle all SFmode moves not involving the 387 */
+ case 3:
+ case 4:
+ case 5:
+ return \"mov{l}\\t{%1, %0|%0, %1}\";
- return singlemove_string (operands);
+ default:
+ abort();
+ }
}"
- [(set_attr "type" "fld")])
-
+ [(set_attr "type" "fmov,fmov,fmov,imov,imov,imov")])
(define_insn "swapsf"
- [(set (match_operand:SF 0 "register_operand" "f")
- (match_operand:SF 1 "register_operand" "f"))
+ [(set (match_operand:SF 0 "register_operand" "+f")
+ (match_operand:SF 1 "register_operand" "+f"))
(set (match_dup 1)
(match_dup 0))]
""
"*
{
if (STACK_TOP_P (operands[0]))
- return AS1 (fxch,%1);
+ return \"fxch\\t%1\";
else
- return AS1 (fxch,%0);
-}")
+ return \"fxch\\t%0\";
+}"
+ [(set_attr "type" "fxch")])
+(define_expand "movdf"
+ [(set (match_operand:DF 0 "general_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
+ ""
+ "ix86_expand_move (DFmode, operands); DONE;")
-(define_insn "movdf_push"
+(define_insn "*pushdf"
[(set (match_operand:DF 0 "push_operand" "=<,<")
- (match_operand:DF 1 "general_operand" "*rfF,o"))]
- "TARGET_PUSH_MEMORY || GET_CODE (operands[1]) != MEM
- || reload_in_progress || reload_completed"
+ (match_operand:DF 1 "general_operand" "f,ofF*r"))]
+ ""
"*
{
- if (STACK_REG_P (operands[1]))
+ switch (which_alternative)
{
- rtx xops[3];
-
- xops[0] = AT_SP (DFmode);
- xops[1] = GEN_INT (8);
- xops[2] = stack_pointer_rtx;
-
- output_asm_insn (AS2 (sub%L2,%1,%2), xops);
-
- if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
- output_asm_insn (AS1 (fstp%Q0,%0), xops);
+ case 0:
+ /* %%% We loose REG_DEAD notes for controling pops if we split late. */
+ operands[0] = gen_rtx_MEM (DFmode, stack_pointer_rtx);
+ operands[2] = stack_pointer_rtx;
+ operands[3] = GEN_INT (8);
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"sub{l}\\t{%3, %2|%2, %3}\;fstp%z0\\t%0\";
else
- output_asm_insn (AS1 (fst%Q0,%0), xops);
-
- RET;
- }
+ return \"sub{l}\\t{%3, %2|%2, %3}\;fst%z0\\t%0\";
- if (which_alternative == 1)
- return output_move_pushmem (operands, insn, GET_MODE_SIZE (DFmode), 0, 0);
+ case 1:
+ return \"#\";
- return output_move_double (operands);
-}")
+ default:
+ abort ();
+ }
+}"
+ [(set_attr "type" "multi")])
+;; %%% Kill this when call knows how to work this out.
(define_split
[(set (match_operand:DF 0 "push_operand" "")
- (match_operand:DF 1 "register_operand" ""))]
- "reload_completed && STACK_REG_P (operands[1])"
- [(set (reg:SI 7)
- (minus:SI (reg:SI 7) (const_int 8)))
- (set (mem:DF (reg:SI 7))
- (match_dup 1))]
+ (match_operand:DF 1 "register_operand" ""))]
+ "reload_completed && FP_REGNO_P (REGNO (operands[1]))"
+ [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8)))
+ (set (mem:DF (reg:SI 7)) (match_dup 1))]
"")
-(define_expand "movdf"
- [(set (match_operand:DF 0 "general_operand" "")
+(define_split
+ [(set (match_operand:DF 0 "push_operand" "")
(match_operand:DF 1 "general_operand" ""))]
- ""
+ "reload_completed"
+ [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 1))
+ (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))]
"
{
- /* Don't generate memory->memory moves, go through a register */
- if (TARGET_MOVE
- && no_new_pseudos == 0
- && GET_CODE (operands[0]) == MEM
- && GET_CODE (operands[1]) == MEM)
- {
- operands[1] = force_reg (DFmode, operands[1]);
- }
-
- /* If we are loading a floating point constant that isn't 0 or 1 into a
- register, indicate we need the pic register loaded. This could be
- optimized into stores of constants if the target eventually moves to
- memory, but better safe than sorry. */
- else if ((reload_in_progress | reload_completed) == 0
- && GET_CODE (operands[0]) != MEM
- && GET_CODE (operands[1]) == CONST_DOUBLE
- && !standard_80387_constant_p (operands[1]))
- {
- operands[1] = validize_mem (force_const_mem (DFmode, operands[1]));
- }
+ split_di (operands+1, 1, operands+0, operands+1);
+ /* Compensate for the fact that we're changing stack offsets in
+ the middle of this operation. */
+ if (reg_mentioned_p (stack_pointer_rtx, operands[0]))
+ operands[0] = adj_offsettable_operand (operands[0], 4);
}")
-;; For the purposes of regclass, prefer FLOAT_REGS.
-(define_insn ""
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,!*r,!o")
- (match_operand:DF 1 "general_operand" "fmG,f,*roF,*rF"))]
- "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM)
- || (GET_CODE (operands[1]) != MEM)"
+(define_insn "*movdf_1"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,f,*r,m,*r")
+ (match_operand:DF 1 "general_operand" "fm,f,G,*rm,*r,G"))]
+ ""
"*
{
- int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
-
- /* First handle a `pop' insn or a `fld %st(0)' */
-
- if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1]))
+ switch (which_alternative)
{
- if (stack_top_dies)
- return AS1 (fstp,%y0);
+ case 0:
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp\\t%0\";
+ else if (STACK_TOP_P (operands[0]))
+ return \"fld%z1\\t%1\";
else
- return AS1 (fld,%y0);
- }
+ return \"fst\\t%0\";
- /* Handle other kinds of writes from the 387 */
-
- if (STACK_TOP_P (operands[1]))
- {
- if (stack_top_dies)
- return AS1 (fstp%z0,%y0);
+ case 1:
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp%z0\\t%0\";
else
- return AS1 (fst%z0,%y0);
- }
-
- /* Handle other kinds of reads to the 387 */
-
- if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE)
- return output_move_const_single (operands);
+ return \"fst%z0\\t%0\";
- if (STACK_TOP_P (operands[0]))
- return AS1 (fld%z1,%y1);
+ case 2:
+ switch (standard_80387_constant_p (operands[1]))
+ {
+ case 1:
+ return \"fldz\";
+ case 2:
+ return \"fld1\";
+ }
+ abort();
- /* Handle all DFmode moves not involving the 387 */
+ case 3:
+ case 4:
+ case 5:
+ return \"#\";
- return output_move_double (operands);
+ default:
+ abort();
+ }
}"
- [(set_attr "type" "fld")])
-
+ [(set_attr "type" "fmov,fmov,fmov,multi,multi,multi")])
+(define_split
+ [(set (match_operand:DF 0 "nonimmediate_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
+ "reload_completed
+ && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+ && ! (FP_REG_P (operands[0]) ||
+ (GET_CODE (operands[0]) == SUBREG
+ && FP_REG_P (SUBREG_REG (operands[0]))))
+ && ! (FP_REG_P (operands[1]) ||
+ (GET_CODE (operands[1]) == SUBREG
+ && FP_REG_P (SUBREG_REG (operands[1]))))"
+ [(set (match_dup 0) (match_dup 2))
+ (set (match_dup 1) (match_dup 3))]
+ "split_di (operands+1, 1, operands+2, operands+3);
+ split_di (operands+0, 1, operands+0, operands+1);")
(define_insn "swapdf"
- [(set (match_operand:DF 0 "register_operand" "f")
- (match_operand:DF 1 "register_operand" "f"))
+ [(set (match_operand:DF 0 "register_operand" "+f")
+ (match_operand:DF 1 "register_operand" "+f"))
(set (match_dup 1)
(match_dup 0))]
""
"*
{
if (STACK_TOP_P (operands[0]))
- return AS1 (fxch,%1);
+ return \"fxch\\t%1\";
else
- return AS1 (fxch,%0);
-}")
+ return \"fxch\\t%0\";
+}"
+ [(set_attr "type" "fxch")])
-(define_insn "movxf_push"
- [(set (match_operand:XF 0 "push_operand" "=<,<")
- (match_operand:XF 1 "general_operand" "*rfF,o"))]
- "TARGET_PUSH_MEMORY || GET_CODE (operands[1]) != MEM
- || reload_in_progress || reload_completed"
+(define_expand "movxf"
+ [(set (match_operand:XF 0 "general_operand" "")
+ (match_operand:XF 1 "general_operand" ""))]
+ ""
+ "ix86_expand_move (XFmode, operands); DONE;")
+
+(define_insn "*pushxf"
+ [(set (match_operand:XF 0 "push_operand" "=<")
+ (match_operand:XF 1 "register_operand" "f"))]
+ ""
"*
{
- if (STACK_REG_P (operands[1]))
- {
- rtx xops[3];
-
- xops[0] = AT_SP (XFmode);
- xops[1] = GEN_INT (12);
- xops[2] = stack_pointer_rtx;
-
- output_asm_insn (AS2 (sub%L2,%1,%2), xops);
-
- output_asm_insn (AS1 (fstp%T0,%0), xops);
- if (! find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
- output_asm_insn (AS1 (fld%T0,%0), xops);
-
- RET;
- }
-
- if (which_alternative == 1)
- return output_move_pushmem (operands, insn, GET_MODE_SIZE (XFmode), 0, 0);
-
- return output_move_double (operands);
- }")
+ /* %%% We loose REG_DEAD notes for controling pops if we split late. */
+ operands[0] = gen_rtx_MEM (XFmode, stack_pointer_rtx);
+ operands[2] = stack_pointer_rtx;
+ operands[3] = GEN_INT (12);
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"sub{l}\\t{%3, %2|%2, %3}\;fstp%z0\\t%0\";
+ else
+ return \"sub{l}\\t{%3, %2|%2, %3}\;fst%z0\\t%0\";
+}"
+ [(set_attr "type" "multi")])
(define_split
[(set (match_operand:XF 0 "push_operand" "")
- (match_operand:XF 1 "register_operand" ""))]
- "reload_completed && STACK_REG_P (operands[1])"
- [(set (reg:SI 7)
- (minus:SI (reg:SI 7) (const_int 12)))
- (set (mem:XF (reg:SI 7))
- (match_dup 1))]
- "")
+ (match_operand:XF 1 "register_operand" ""))]
+ "FP_REGNO_P (REGNO (operands[1]))"
+ [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -12)))
+ (set (mem:XF (reg:SI 7)) (match_dup 1))])
-(define_expand "movxf"
- [(set (match_operand:XF 0 "general_operand" "")
- (match_operand:XF 1 "general_operand" ""))]
- ""
+(define_split
+ [(set (match_operand:DF 0 "push_operand" "")
+ (match_operand:DF 1 "memory_operand" ""))]
+ "reload_completed"
+ [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 2))
+ (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 1))
+ (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))]
"
{
- /* Don't generate memory->memory moves, go through a register */
- if (TARGET_MOVE
- && no_new_pseudos == 0
- && GET_CODE (operands[0]) == MEM
- && GET_CODE (operands[1]) == MEM)
- {
- operands[1] = force_reg (XFmode, operands[1]);
- }
-
- /* If we are loading a floating point constant that isn't 0 or 1
- into a register, indicate we need the pic register loaded. This could
- be optimized into stores of constants if the target eventually moves
- to memory, but better safe than sorry. */
- else if ((reload_in_progress | reload_completed) == 0
- && GET_CODE (operands[0]) != MEM
- && GET_CODE (operands[1]) == CONST_DOUBLE
- && !standard_80387_constant_p (operands[1]))
- {
- operands[1] = validize_mem (force_const_mem (XFmode, operands[1]));
- }
+ operands[0] = change_address (operands[1], SImode, NULL_RTX);
+ operands[1] = adj_offsettable_operand (operands[0], 4);
+ operands[2] = adj_offsettable_operand (operands[0], 8);
+ /* Compensate for the fact that we're changing stack offsets in
+ the middle of this operation. */
+ if (reg_mentioned_p (stack_pointer_rtx, operands[1]))
+ operands[1] = adj_offsettable_operand (operands[1], 4);
+ if (reg_mentioned_p (stack_pointer_rtx, operands[0]))
+ operands[0] = adj_offsettable_operand (operands[0], 8);
}")
-
-(define_insn ""
- [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,!*r,!o")
- (match_operand:XF 1 "general_operand" "fmG,f,*roF,*rF"))]
- "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM)
- || (GET_CODE (operands[1]) != MEM)"
+(define_insn "*movxf_1"
+ [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f")
+ (match_operand:XF 1 "general_operand" "fm,f,G"))]
+ ""
"*
{
- int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
-
- /* First handle a `pop' insn or a `fld %st(0)' */
-
- if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1]))
+ switch (which_alternative)
{
- if (stack_top_dies)
- return AS1 (fstp,%y0);
+ case 0:
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp\\t%0\";
+ else if (STACK_TOP_P (operands[0]))
+ return \"fld%z1\\t%1\";
else
- return AS1 (fld,%y0);
- }
+ return \"fst\\t%0\";
- /* Handle other kinds of writes from the 387 */
-
- if (STACK_TOP_P (operands[1]))
- {
- output_asm_insn (AS1 (fstp%z0,%y0), operands);
- if (! stack_top_dies)
- return AS1 (fld%z0,%y0);
+ case 1:
+ /* There is no non-popping store to memory for XFmode. So if
+ we need one, follow the store with a load. */
+ if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp%z0\\t%0\;fld%z0\\t%0\";
+ else
+ return \"fstp%z0\\t%0\";
- RET;
+ case 2:
+ switch (standard_80387_constant_p (operands[1]))
+ {
+ case 1:
+ return \"fldz\";
+ case 2:
+ return \"fld1\";
+ }
+ break;
}
+ abort();
+}"
+ [(set_attr "type" "fmov")])
- /* Handle other kinds of reads to the 387 */
-
- if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE)
- return output_move_const_single (operands);
-
- if (STACK_TOP_P (operands[0]))
- return AS1 (fld%z1,%y1);
-
- /* Handle all XFmode moves not involving the 387 */
-
- return output_move_double (operands);
-}")
-
-(define_insn "swapxf"
- [(set (match_operand:XF 0 "register_operand" "f")
- (match_operand:XF 1 "register_operand" "f"))
+(define_insn "swapxf"
+ [(set (match_operand:XF 0 "register_operand" "+f")
+ (match_operand:XF 1 "register_operand" "+f"))
(set (match_dup 1)
(match_dup 0))]
""
"*
{
if (STACK_TOP_P (operands[0]))
- return AS1 (fxch,%1);
+ return \"fxch\\t%1\";
else
- return AS1 (fxch,%0);
-}")
-
-(define_insn ""
- [(set (match_operand:DI 0 "push_operand" "=<")
- (match_operand:DI 1 "general_operand" "riF"))]
- ""
- "* return output_move_double (operands);")
-
-(define_insn ""
- [(set (match_operand:DI 0 "push_operand" "=<")
- (match_operand:DI 1 "memory_operand" "o"))]
- "TARGET_PUSH_MEMORY"
- "* return output_move_pushmem (operands, insn, GET_MODE_SIZE (DImode),0,0);")
-
-(define_expand "movdi"
- [(set (match_operand:DI 0 "general_operand" "")
- (match_operand:DI 1 "general_operand" ""))]
- ""
- "
-{
- /* Don't generate memory->memory moves, go through a register */
- if (TARGET_MOVE
- && no_new_pseudos == 0
- && GET_CODE (operands[0]) == MEM
- && GET_CODE (operands[1]) == MEM)
- {
- operands[1] = force_reg (DImode, operands[1]);
- }
-}")
-
-(define_insn ""
- [(set (match_operand:DI 0 "general_operand" "=g,r")
- (match_operand:DI 1 "general_operand" "riF,m"))]
- "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM)
- || (GET_CODE (operands[1]) != MEM)"
- "* return output_move_double (operands);"
- [(set_attr "type" "integer,memory")
- (set_attr "memory" "*,load")])
-
-(define_split
- [(set (match_operand:DI 0 "nonimmediate_operand" "")
- (match_operand:DI 1 "general_operand" ""))]
- "reload_completed
- && (offsettable_memref_p (operands[0])
- || nonmemory_operand (operands[0], DImode))
- && (offsettable_memref_p (operands[1])
- || nonmemory_operand (operands[1], DImode))
- && (! reg_overlap_mentioned_p (gen_lowpart (SImode, operands[0]),
- operands[1])
- || ! reg_overlap_mentioned_p (gen_highpart (SImode, operands[0]),
- operands[1]))"
- [(set (match_dup 2)
- (match_dup 4))
- (set (match_dup 3)
- (match_dup 5))]
- "
-{
- split_di (&operands[0], 1, &operands[2], &operands[3]);
- split_di (&operands[1], 1, &operands[4], &operands[5]);
-
- if (reg_overlap_mentioned_p (operands[2], operands[1]))
- {
- rtx tmp;
-
- tmp = operands[2];
- operands[2] = operands[3];
- operands[3] = tmp;
-
- tmp = operands[4];
- operands[4] = operands[5];
- operands[5] = tmp;
- }
-}")
+ return \"fxch\\t%0\";
+}"
+ [(set_attr "type" "fxch")])
-;;- conversion instructions
-;;- NONE
+;; Zero extension instructions
-;;- zero extension instructions
-;; See comments by `andsi' for when andl is faster than movzx.
-
-(define_expand "zero_extendhisi2"
- [(set (match_operand:SI 0 "register_operand" "")
- (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r,?r")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,rm")))
+ (clobber (reg:CC 17))]
""
- "")
-
-;; When optimizing for the PPro/PII or code size, always use movzwl.
-;; We want to use a different pattern so we can use different constraints
-;; than the generic pattern.
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=r")
- (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))]
- "(optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO)"
- "* return AS2 (movz%W0%L0,%1,%0);")
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=r,&r,?r")
- (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,rm,rm")))]
- "! (optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO)"
"*
- {
- rtx xops[2];
-
- if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0)
- && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
- {
- xops[0] = operands[0];
- xops[1] = GEN_INT (0xffff);
- output_asm_insn (AS2 (and%L0,%1,%k0), xops);
- RET;
- }
- if (TARGET_ZERO_EXTEND_WITH_AND && !reg_overlap_mentioned_p (operands[0], operands[1]))
- {
- output_asm_insn (AS2 (xor%L0,%0,%0),operands);
- output_asm_insn (AS2 (mov%W0,%1,%w0),operands);
- RET;
- }
-
- if (TARGET_ZERO_EXTEND_WITH_AND)
+{
+ switch (get_attr_type (insn))
{
- xops[0] = operands[0];
- xops[1] = GEN_INT (0xffff);
- if (i386_aligned_p (operands[1]))
- output_asm_insn (AS2 (mov%L0,%k1,%k0),operands);
- else
- output_asm_insn (AS2 (mov%W0,%1,%w0),operands);
- output_asm_insn (AS2 (and%L0,%1,%k0), xops);
- RET;
+ case TYPE_ALU1:
+ if (!REG_P (operands[1]) || REGNO (operands[0]) != REGNO (operands[1]))
+ abort ();
+ operands[1] = GEN_INT (0xffff);
+ return \"and{l}\\t{%1, %0|%0, %1}\";
+ default:
+ return \"movz{wl|x}\\t{%1, %0|%0, %1}\";
}
-
-#ifdef INTEL_SYNTAX
- return AS2 (movzx,%1,%0);
-#else
- return AS2 (movz%W0%L0,%1,%0);
-#endif
-}")
+}"
+ [(set (attr "type")
+ (if_then_else (and (eq_attr "alternative" "0")
+ (ne (symbol_ref "TARGET_ZERO_EXTEND_WITH_AND")
+ (const_int 0)))
+ (const_string "alu1")
+ (const_string "imovx")))])
(define_split
[(set (match_operand:SI 0 "register_operand" "")
- (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
- "reload_completed && TARGET_ZERO_EXTEND_WITH_AND && !reg_overlap_mentioned_p (operands[0], operands[1])"
- [(set (match_dup 0)
- (const_int 0))
- (set (strict_low_part (match_dup 2))
- (match_dup 1))]
- "operands[2] = gen_rtx_REG (HImode, true_regnum (operands[0]));")
-
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))
+ (clobber (reg:CC 17))]
+ "reload_completed
+ && TARGET_ZERO_EXTEND_WITH_AND
+ && !reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(parallel [(set (match_dup 0) (const_int 0))
+ (clobber (reg:CC 17))])
+ (set (strict_low_part (subreg:HI (match_dup 0) 0)) (match_dup 1))]
+ "")
(define_split
[(set (match_operand:SI 0 "register_operand" "")
- (zero_extend:SI (match_operand:HI 1 "memory_operand" "")))]
- "reload_completed && TARGET_ZERO_EXTEND_WITH_AND && reg_overlap_mentioned_p (operands[0], operands[1])"
- [(set (strict_low_part (match_dup 2))
- (match_dup 1))
- (set (match_dup 0)
- (and:SI (match_dup 0)
- (const_int 65535)))]
- "operands[2] = gen_rtx_REG (HImode, true_regnum (operands[0]));")
-
-(define_expand "zero_extendqihi2"
- [(set (match_operand:HI 0 "register_operand" "")
- (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]
- ""
+ (zero_extend:SI (match_operand:HI 1 "memory_operand" "")))
+ (clobber (reg:CC 17))]
+ "reload_completed
+ && TARGET_ZERO_EXTEND_WITH_AND
+ && reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (strict_low_part (subreg:HI (match_dup 0) 0)) (match_dup 1))
+ (parallel [(set (match_dup 0) (and:SI (match_dup 0) (const_int 65535)))
+ (clobber (reg:CC 17))])]
"")
-(define_insn ""
- [(set (match_operand:HI 0 "register_operand" "=r")
- (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm")))]
- "optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO"
-
- "* return AS2 (movz%B0%W0,%1,%0);")
-
-(define_insn ""
- [(set (match_operand:HI 0 "register_operand" "=q,&q,?r")
- (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,qm,qm")))]
- "! (optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO)"
+(define_insn "zero_extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "=q,r,r")
+ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,0,qm")))
+ (clobber (reg:CC 17))]
+ ""
"*
- {
- rtx xops[2];
-
- if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0)
- && REG_P (operands[1])
- && REGNO (operands[0]) == REGNO (operands[1]))
- {
- xops[0] = operands[0];
- xops[1] = GEN_INT (0xff);
- output_asm_insn (AS2 (and%L0,%1,%k0), xops);
- RET;
- }
- if (TARGET_ZERO_EXTEND_WITH_AND && QI_REG_P (operands[0]))
+{
+ switch (get_attr_type (insn))
{
- if(!reg_overlap_mentioned_p(operands[0],operands[1]))
- {
- output_asm_insn (AS2 (xor%L0,%k0,%k0), operands);
- output_asm_insn (AS2 (mov%B0,%1,%b0), operands);
- }
- else
- {
- xops[0] = operands[0];
- xops[1] = GEN_INT (0xff);
- output_asm_insn (AS2 (mov%B0,%1,%b0),operands);
- output_asm_insn (AS2 (and%L0,%1,%k0), xops);
- }
- RET;
+ case TYPE_ALU1:
+ if (!REG_P (operands[1]) || REGNO (operands[0]) != REGNO (operands[1]))
+ abort ();
+ operands[1] = GEN_INT (0xff);
+ return \"and{l}\\t{%1, %0|%0, %1}\";
+ default:
+ return \"movz{bw|x}\\t{%1, %0|%0, %1}\";
}
-
-#ifdef INTEL_SYNTAX
- return AS2 (movzx,%1,%0);
-#else
- return AS2 (movz%B0%W0,%1,%0);
-#endif
-}")
+}"
+ [(set (attr "type")
+ (cond [(and (eq_attr "alternative" "0")
+ (ne (symbol_ref "TARGET_ZERO_EXTEND_WITH_AND")
+ (const_int 0)))
+ (const_string "alu1")
+ (eq_attr "alternative" "1")
+ (const_string "alu1")
+ ]
+ (const_string "imovx")))])
(define_split
[(set (match_operand:HI 0 "register_operand" "")
- (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]
- "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
- && !reg_overlap_mentioned_p (operands[0], operands[1])"
- [(set (match_dup 0)
- (const_int 0))
- (set (strict_low_part (match_dup 2))
- (match_dup 1))]
- "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));")
-
+ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))
+ (clobber (reg:CC 17))]
+ "reload_completed
+ && QI_REG_P (operands[0])
+ && TARGET_ZERO_EXTEND_WITH_AND
+ && !reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(parallel [(set (match_dup 0) (const_int 0))
+ (clobber (reg:CC 17))])
+ (set (strict_low_part (subreg:QI (match_dup 0) 0)) (match_dup 1))]
+ "")
(define_split
[(set (match_operand:HI 0 "register_operand" "")
- (zero_extend:HI (match_operand:QI 1 "memory_operand" "")))]
- "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
- && reg_overlap_mentioned_p (operands[0], operands[1])"
- [(set (strict_low_part (match_dup 2))
- (match_dup 1))
- (set (match_dup 0)
- (and:HI (match_dup 0)
- (const_int 255)))]
- "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));")
+ (zero_extend:HI (match_operand:QI 1 "memory_operand" "")))
+ (clobber (reg:CC 17))]
+ "reload_completed
+ && QI_REG_P (operands[0])
+ && TARGET_ZERO_EXTEND_WITH_AND
+ && reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (strict_low_part (subreg:QI (match_dup 0) 0)) (match_dup 1))
+ (parallel [(set (match_dup 0) (and:HI (match_dup 0) (const_int 255)))
+ (clobber (reg:CC 17))])]
+ "")
(define_split
[(set (match_operand:HI 0 "register_operand" "")
- (zero_extend:HI (match_operand:QI 1 "register_operand" "")))]
- "reload_completed && TARGET_ZERO_EXTEND_WITH_AND"
- [(set (match_dup 0)
- (match_dup 2))
- (set (match_dup 0)
- (and:HI (match_dup 0)
- (const_int 255)))]
- "if (GET_CODE (operands[1]) == SUBREG && SUBREG_WORD (operands[1]) == 0)
- operands[1] = SUBREG_REG (operands[1]);
- if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG
- || REGNO (operands[0]) == REGNO (operands[1]))
- FAIL;
- operands[2] = gen_rtx_REG (HImode, REGNO (operands[1]));")
-
-(define_expand "zero_extendqisi2"
- [(set (match_operand:SI 0 "register_operand" "")
- (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
- ""
+ (zero_extend:HI (match_operand:QI 1 "register_operand" "")))
+ (clobber (reg:CC 17))]
+ "reload_completed
+ && TARGET_ZERO_EXTEND_WITH_AND
+ && ! reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (match_dup 0) (subreg:HI (match_dup 1) 0))
+ (parallel [(set (match_dup 0) (and:HI (match_dup 0) (const_int 255)))
+ (clobber (reg:CC 17))])]
"")
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=r")
- (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")))]
- "optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO"
- "* return AS2 (movz%B0%L0,%1,%0);")
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=q,&q,?r")
- (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,qm,qm")))]
- "! (optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO)"
+(define_insn "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=q,r,r")
+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,0,qm")))
+ (clobber (reg:CC 17))]
+ ""
"*
- {
- rtx xops[2];
-
- if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0)
- && REG_P (operands[1])
- && REGNO (operands[0]) == REGNO (operands[1]))
- {
- xops[0] = operands[0];
- xops[1] = GEN_INT (0xff);
- output_asm_insn (AS2 (and%L0,%1,%k0), xops);
- RET;
- }
- if (TARGET_ZERO_EXTEND_WITH_AND && QI_REG_P (operands[0]))
- {
- if(!reg_overlap_mentioned_p (operands[0], operands[1]))
- {
- output_asm_insn (AS2 (xor%L0,%0,%0),operands);
- output_asm_insn (AS2 (mov%B0,%1,%b0),operands);
- }
- else
- {
- xops[0] = operands[0];
- xops[1] = GEN_INT (0xff);
- output_asm_insn (AS2 (mov%B0,%1,%b0), operands);
- output_asm_insn (AS2 (and%L0,%1,%k0), xops);
- }
- RET;
- }
-
- if (TARGET_ZERO_EXTEND_WITH_AND && GET_CODE (operands[1]) == REG)
+{
+ switch (get_attr_type (insn))
{
- xops[0] = operands[0];
- xops[1] = GEN_INT (0xff);
- operands[1] = gen_rtx_REG (SImode, REGNO (operands[1]));
- output_asm_insn (AS2 (mov%L0,%1,%0), operands);
- output_asm_insn (AS2 (and%L0,%1,%k0), xops);
- RET;
+ case TYPE_ALU1:
+ if (!REG_P (operands[1]) || REGNO (operands[0]) != REGNO (operands[1]))
+ abort ();
+ operands[1] = GEN_INT (0xff);
+ return \"and{l}\\t{%1, %0|%0, %1}\";
+ default:
+ return \"movz{bl|x}\\t{%1, %0|%0, %1}\";
}
-
-#ifdef INTEL_SYNTAX
- return AS2 (movzx,%1,%0);
-#else
- return AS2 (movz%B0%L0,%1,%0);
-#endif
-}")
-
-(define_split
- [(set (match_operand:SI 0 "register_operand" "")
- (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
- "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
- && !reg_overlap_mentioned_p (operands[0], operands[1])"
- [(set (match_dup 0)
- (const_int 0))
- (set (strict_low_part (match_dup 2))
- (match_dup 1))]
- "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));")
-
+}"
+ [(set (attr "type")
+ (cond [(and (eq_attr "alternative" "0")
+ (ne (symbol_ref "TARGET_ZERO_EXTEND_WITH_AND")
+ (const_int 0)))
+ (const_string "alu1")
+ (eq_attr "alternative" "1")
+ (const_string "alu1")
+ ]
+ (const_string "imovx")))])
(define_split
[(set (match_operand:SI 0 "register_operand" "")
- (zero_extend:SI (match_operand:QI 1 "memory_operand" "")))]
- "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
- && reg_overlap_mentioned_p (operands[0], operands[1])"
- [(set (strict_low_part (match_dup 2))
- (match_dup 1))
- (set (match_dup 0)
- (and:SI (match_dup 0)
- (const_int 255)))]
- "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));")
+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))
+ (clobber (reg:CC 17))]
+ "reload_completed
+ && TARGET_ZERO_EXTEND_WITH_AND
+ && QI_REG_P (operands[0])
+ && (GET_CODE (operands[1]) == MEM || QI_REG_P (operands[1]))
+ && !reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(parallel [(set (match_dup 0) (const_int 0))
+ (clobber (reg:CC 17))])
+ (set (strict_low_part (subreg:QI (match_dup 0) 0)) (match_dup 1))]
+ "")
(define_split
[(set (match_operand:SI 0 "register_operand" "")
- (zero_extend:SI (match_operand:QI 1 "register_operand" "")))]
- "reload_completed && TARGET_ZERO_EXTEND_WITH_AND
- && ! reg_overlap_mentioned_p (operands[0], operands[1])"
- [(set (match_dup 0)
- (match_dup 2))
- (set (match_dup 0)
- (and:SI (match_dup 0)
- (const_int 255)))]
- "operands[2] = gen_rtx_REG (SImode, true_regnum (operands[1]));")
+ (zero_extend:SI (match_operand:QI 1 "register_operand" "")))
+ (clobber (reg:CC 17))]
+ "reload_completed
+ && TARGET_ZERO_EXTEND_WITH_AND
+ && ! reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (match_dup 0) (subreg:SI (match_dup 1) 0))
+ (parallel [(set (match_dup 0) (and:SI (match_dup 0) (const_int 255)))
+ (clobber (reg:CC 17))])]
+ "")
+;; %%% Kill me once multi-word ops are sane.
(define_insn "zero_extendsidi2"
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,?r,?*o")
- (zero_extend:DI (match_operand:SI 1 "general_operand" "0,rm,r")))]
+ (zero_extend:DI (match_operand:SI 1 "general_operand" "0,rm,r")))
+ (clobber (reg:CC 17))]
""
"#")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
- (zero_extend:DI (match_operand:SI 1 "register_operand" "")))]
+ (zero_extend:DI (match_operand:SI 1 "register_operand" "")))
+ (clobber (reg:CC 17))]
"reload_completed && true_regnum (operands[0]) == true_regnum (operands[1])"
- [(set (match_dup 4) (const_int 0))]
+ [(parallel [(set (match_dup 4) (const_int 0))
+ (clobber (reg:CC 17))])]
"split_di (&operands[0], 1, &operands[3], &operands[4]);")
(define_split
[(set (match_operand:DI 0 "nonimmediate_operand" "")
- (zero_extend:DI (match_operand:SI 1 "general_operand" "")))]
+ (zero_extend:DI (match_operand:SI 1 "general_operand" "")))
+ (clobber (reg:CC 17))]
"reload_completed"
[(set (match_dup 3) (match_dup 1))
- (set (match_dup 4) (const_int 0))]
+ (parallel [(set (match_dup 4) (const_int 0))
+ (clobber (reg:CC 17))])]
"split_di (&operands[0], 1, &operands[3], &operands[4]);")
-;;- sign extension instructions
+;; Sign extension instructions
(define_insn "extendsidi2"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=A,?r,?Ar,*o")
- (sign_extend:DI (match_operand:SI 1 "register_operand" "0,0,r,*r")))
- (clobber (match_scratch:SI 2 "=X,X,X,&r"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=*A,r,?r,?*o")
+ (sign_extend:DI (match_operand:SI 1 "register_operand" "0,0,r,r")))
+ (clobber (match_scratch:SI 2 "=X,X,X,&r"))
+ (clobber (reg:CC 17))]
""
"#")
@@ -2049,12 +2238,14 @@
(define_split
[(set (match_operand:DI 0 "memory_operand" "")
(sign_extend:DI (match_operand:SI 1 "register_operand" "")))
- (clobber (match_operand:SI 2 "register_operand" ""))]
+ (clobber (match_operand:SI 2 "register_operand" ""))
+ (clobber (reg:CC 17))]
"(flow2_completed
&& dead_or_set_p (insn, operands[1])
&& !reg_mentioned_p (operands[1], operands[0]))"
[(set (match_dup 3) (match_dup 1))
- (set (match_dup 1) (ashiftrt:SI (match_dup 1) (const_int 31)))
+ (parallel [(set (match_dup 1) (ashiftrt:SI (match_dup 1) (const_int 31)))
+ (clobber (reg:CC 17))])
(set (match_dup 4) (match_dup 1))]
"split_di (&operands[0], 1, &operands[3], &operands[4]);")
@@ -2062,7 +2253,8 @@
(define_split
[(set (match_operand:DI 0 "memory_operand" "")
(sign_extend:DI (match_operand:SI 1 "register_operand" "")))
- (clobber (match_operand:SI 2 "register_operand" ""))]
+ (clobber (match_operand:SI 2 "register_operand" ""))
+ (clobber (reg:CC 17))]
"flow2_completed"
[(const_int 0)]
"
@@ -2074,14 +2266,14 @@
/* Generate a cltd if possible and doing so it profitable. */
if (true_regnum (operands[1]) == 0
&& true_regnum (operands[2]) == 1
- && (optimize_size || !TARGET_PENTIUM))
+ && (optimize_size || TARGET_USE_CLTD))
{
- emit_insn (gen_ashrsi3_31 (operands[2], operands[1]));
+ emit_insn (gen_ashrsi3_31 (operands[2], operands[1], GEN_INT (31)));
}
else
{
emit_move_insn (operands[2], operands[1]);
- emit_insn (gen_ashrsi3_31 (operands[2], operands[2]));
+ emit_insn (gen_ashrsi3_31 (operands[2], operands[2], GEN_INT (31)));
}
emit_move_insn (operands[4], operands[2]);
DONE;
@@ -2092,7 +2284,8 @@
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(sign_extend:DI (match_operand:SI 1 "register_operand" "")))
- (clobber (match_scratch:SI 2 ""))]
+ (clobber (match_scratch:SI 2 ""))
+ (clobber (reg:CC 17))]
"reload_completed"
[(const_int 0)]
"
@@ -2104,368 +2297,211 @@
/* Generate a cltd if possible and doing so it profitable. */
if (true_regnum (operands[3]) == 0
- && (optimize_size || !TARGET_PENTIUM))
+ && (optimize_size || TARGET_USE_CLTD))
{
- emit_insn (gen_ashrsi3_31 (operands[4], operands[3]));
+ emit_insn (gen_ashrsi3_31 (operands[4], operands[3], GEN_INT (31)));
DONE;
}
if (true_regnum (operands[4]) != true_regnum (operands[1]))
emit_move_insn (operands[4], operands[1]);
- emit_insn (gen_ashrsi3_31 (operands[4], operands[4]));
+ emit_insn (gen_ashrsi3_31 (operands[4], operands[4], GEN_INT (31)));
DONE;
}")
-;; Note that the i386 programmers' manual says that the opcodes
-;; are named movsx..., but the assembler on Unix does not accept that.
-;; We use what the Unix assembler expects.
-
(define_insn "extendhisi2"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))]
+ [(set (match_operand:SI 0 "register_operand" "=*a,r")
+ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "*0,rm")))]
""
"*
{
- if (REGNO (operands[0]) == 0
- && REG_P (operands[1]) && REGNO (operands[1]) == 0
- && (optimize_size || ix86_cpu != PROCESSOR_K6))
-#ifdef INTEL_SYNTAX
- return \"cwde\";
-#else
- return \"cwtl\";
-#endif
-
-#ifdef INTEL_SYNTAX
- return AS2 (movsx,%1,%0);
-#else
- return AS2 (movs%W0%L0,%1,%0);
-#endif
-}")
+ switch (get_attr_length (insn))
+ {
+ case 1:
+ return \"{cwtl|cwde}\";
+ default:
+ return \"movs{wl|x}\\t{%1,%0|%0, %1}\";
+ }
+}"
+ [(set_attr "type" "imovx")
+ (set (attr "length")
+ ;; movsx is short decodable while cwtl is vector decoded.
+ (cond [(and (eq_attr "cpu" "!k6")
+ (eq_attr "alternative" "0"))
+ (const_string "1")
+ ]
+ (const_string "*")))])
(define_insn "extendqihi2"
- [(set (match_operand:HI 0 "register_operand" "=r")
- (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm")))]
+ [(set (match_operand:HI 0 "register_operand" "=*a,r")
+ (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "*0,qm")))]
""
"*
{
- if (REGNO (operands[0]) == 0
- && REG_P (operands[1]) && REGNO (operands[1]) == 0
- && (optimize_size || ix86_cpu != PROCESSOR_K6))
- return \"cbtw\";
-
-#ifdef INTEL_SYNTAX
- return AS2 (movsx,%1,%0);
-#else
- return AS2 (movs%B0%W0,%1,%0);
-#endif
-}")
+ switch (get_attr_length (insn))
+ {
+ case 1:
+ return \"{cbtw|cbw}\";
+ default:
+ return \"movs{bw|x}\\t{%1,%0|%0, %1}\";
+ }
+}"
+ [(set_attr "type" "imovx")
+ (set (attr "length")
+ ;; movsx is short decodable while cwtl is vector decoded.
+ (cond [(and (eq_attr "cpu" "!k6")
+ (eq_attr "alternative" "0"))
+ (const_string "1")
+ ]
+ (const_string "*")))])
(define_insn "extendqisi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")))]
""
- "*
-{
-#ifdef INTEL_SYNTAX
- return AS2 (movsx,%1,%0);
-#else
- return AS2 (movs%B0%L0,%1,%0);
-#endif
-}")
-
+ "movs{bl|x}\\t{%1,%0|%0, %1}"
+ [(set_attr "type" "imovx")])
-;; Truncation of long long -> 32 bit
-
-(define_expand "truncdisi2"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
- (truncate:SI (match_operand:DI 1 "nonimmediate_operand" "ro,r")))]
- ""
- "
-{
- /* Don't generate memory->memory moves, go through a register */
- if (TARGET_MOVE
- && (reload_in_progress | reload_completed) == 0
- && GET_CODE (operands[0]) == MEM
- && GET_CODE (operands[1]) == MEM)
- {
- rtx target = gen_reg_rtx (SImode);
- emit_insn (gen_truncdisi2 (target, operands[1]));
- emit_move_insn (operands[0], target);
- DONE;
- }
-}")
-
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
- (truncate:SI (match_operand:DI 1 "nonimmediate_operand" "ro,r")))]
- "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
- "*
-{
- rtx low[2], high[2], xops[2];
+;; Conversions between float and double.
- split_di (&operands[1], 1, low, high);
- xops[0] = operands[0];
- xops[1] = low[0];
- if (!rtx_equal_p (xops[0], xops[1]))
- output_asm_insn (AS2 (mov%L0,%1,%0), xops);
-
- RET;
-}")
+;; These are all no-ops in the model used for the 80387. So just
+;; emit moves.
+;; %%% Kill these when call knows how to work out a DFmode push earlier.
(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
- (truncate:SI (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r")
- (const_int 32))))]
- "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
- "*
-{
- rtx low[2], high[2], xops[2];
-
- split_di (&operands[1], 1, low, high);
- xops[0] = operands[0];
- xops[1] = high[0];
- if (!rtx_equal_p (xops[0], xops[1]))
- output_asm_insn (AS2 (mov%L0,%1,%0), xops);
-
- RET;
-}")
-
-
-
-;; Conversions between float and double.
-
-(define_expand "extendsfdf2"
- [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "")
- (float_extend:DF
- (match_operand:SF 1 "nonimmediate_operand" "")))
- (clobber (match_dup 2))
- (clobber (match_dup 3))])]
- "TARGET_80387"
- "
-{
- if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
- operands[1] = force_reg (SFmode, operands[1]);
+ [(set (match_operand:DF 0 "push_operand" "=<")
+ (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "f")))]
+ "0"
+ "#")
- operands[2] = assign_386_stack_local (SFmode, 0);
- operands[3] = assign_386_stack_local (DFmode, 0);
-}")
+(define_split
+ [(set (match_operand:DF 0 "push_operand" "")
+ (float_extend:DF (match_operand:SF 1 "register_operand" "")))]
+ "FP_REGNO_P (REGNO (operands[1]))"
+ [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8)))
+ (set (mem:DF (reg:SI 7)) (float_extend:DF (match_dup 1)))])
(define_insn ""
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,!f,!*r")
- (float_extend:DF
- (match_operand:SF 1 "nonimmediate_operand" "fm,f,*r,f")))
- (clobber (match_operand:SF 2 "memory_operand" "m,m,m,m"))
- (clobber (match_operand:DF 3 "memory_operand" "m,m,m,o"))]
- "TARGET_80387 && (GET_CODE (operands[0]) != MEM
- || GET_CODE (operands[1]) != MEM)"
- "*
-{
- output_float_extend (insn, operands);
- return \"\";
-}"
- [(set_attr "type" "fld,fpop,fld,fpop")])
+ [(set (match_operand:XF 0 "push_operand" "=<")
+ (float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "f")))]
+ "0"
+ "#")
(define_split
- [(set (match_operand:DF 0 "register_operand" "")
- (float_extend:DF (match_operand:SF 1 "register_operand" "")))
- (clobber (match_operand:SF 2 "memory_operand" ""))
- (clobber (match_operand:DF 3 "memory_operand" ""))]
- "TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[1])"
- [(set (match_dup 2)
- (match_dup 1))
- (set (match_dup 0)
- (float_extend:DF (match_dup 2)))]
- "")
+ [(set (match_operand:XF 0 "push_operand" "")
+ (float_extend:XF (match_operand:SF 1 "register_operand" "")))]
+ "FP_REGNO_P (REGNO (operands[1]))"
+ [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -12)))
+ (set (mem:DF (reg:SI 7)) (float_extend:XF (match_dup 1)))])
-(define_split
- [(set (match_operand:DF 0 "register_operand" "")
- (float_extend:DF (match_operand:SF 1 "register_operand" "")))
- (clobber (match_operand:SF 2 "memory_operand" ""))
- (clobber (match_operand:DF 3 "memory_operand" ""))]
- "TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[0])"
- [(set (match_dup 3)
- (float_extend:DF (match_dup 1)))
- (set (match_dup 0)
- (match_dup 3))]
- "")
+(define_insn ""
+ [(set (match_operand:XF 0 "push_operand" "=<")
+ (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "f")))]
+ "0"
+ "#")
(define_split
- [(set (match_operand:DF 0 "nonimmediate_operand" "")
- (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "")))
- (clobber (match_operand:SF 2 "memory_operand" ""))
- (clobber (match_operand:DF 3 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 0)
- (float_extend:DF (match_dup 1)))]
- "")
+ [(set (match_operand:XF 0 "push_operand" "")
+ (float_extend:XF (match_operand:DF 1 "register_operand" "")))]
+ "FP_REGNO_P (REGNO (operands[1]))"
+ [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -12)))
+ (set (mem:DF (reg:SI 7)) (float_extend:XF (match_dup 1)))])
-(define_insn ""
+(define_insn "extendsfdf2"
[(set (match_operand:DF 0 "nonimmediate_operand" "=f,m")
- (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,f")))]
- "TARGET_80387 && (GET_CODE (operands[0]) != MEM
- || GET_CODE (operands[1]) != MEM)"
- "*
-{
- output_float_extend (insn, operands);
- return \"\";
-}"
- [(set_attr "type" "fld,fpop")])
-
-(define_expand "extenddfxf2"
- [(parallel [(set (match_operand:XF 0 "nonimmediate_operand" "")
- (float_extend:XF
- (match_operand:DF 1 "nonimmediate_operand" "")))
- (clobber (match_dup 2))
- (clobber (match_dup 3))])]
+ (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,f")))]
"TARGET_80387"
- "
-{
- if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
- operands[1] = force_reg (DFmode, operands[1]);
-
- operands[2] = assign_386_stack_local (DFmode, 0);
- operands[3] = assign_386_stack_local (XFmode, 0);
-}")
-
-(define_insn ""
- [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,!f,!*r")
- (float_extend:XF
- (match_operand:DF 1 "nonimmediate_operand" "fm,f,*r,f")))
- (clobber (match_operand:DF 2 "memory_operand" "m,m,o,m"))
- (clobber (match_operand:XF 3 "memory_operand" "m,m,m,o"))]
- "TARGET_80387 && (GET_CODE (operands[0]) != MEM
- || GET_CODE (operands[1]) != MEM)"
"*
{
- output_float_extend (insn, operands);
- return \"\";
-}"
- [(set_attr "type" "fld,fpop,fld,fpop")])
+ switch (which_alternative)
+ {
+ case 0:
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp\\t%0\";
+ else if (STACK_TOP_P (operands[0]))
+ return \"fld%z1\\t%1\";
+ else
+ return \"fst\\t%0\";
-(define_split
- [(set (match_operand:XF 0 "register_operand" "")
- (float_extend:XF (match_operand:DF 1 "register_operand" "")))
- (clobber (match_operand:DF 2 "memory_operand" ""))
- (clobber (match_operand:XF 3 "memory_operand" ""))]
- "TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[1])"
- [(set (match_dup 2)
- (match_dup 1))
- (set (match_dup 0)
- (float_extend:XF (match_dup 2)))]
- "")
+ case 1:
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp%z0\\t%0\";
-(define_split
- [(set (match_operand:XF 0 "register_operand" "")
- (float_extend:XF (match_operand:DF 1 "register_operand" "")))
- (clobber (match_operand:DF 2 "memory_operand" ""))
- (clobber (match_operand:XF 3 "memory_operand" ""))]
- "TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[0])"
- [(set (match_dup 3)
- (float_extend:XF (match_dup 1)))
- (set (match_dup 0)
- (match_dup 3))]
- "")
+ else
+ return \"fst%z0\\t%0\";
-(define_split
- [(set (match_operand:XF 0 "nonimmediate_operand" "")
- (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "")))
- (clobber (match_operand:DF 2 "memory_operand" ""))
- (clobber (match_operand:XF 3 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 0)
- (float_extend:XF (match_dup 1)))]
- "")
+ default:
+ abort ();
+ }
+}"
+ [(set_attr "type" "fmov")])
-(define_insn ""
+(define_insn "extendsfxf2"
[(set (match_operand:XF 0 "nonimmediate_operand" "=f,m")
- (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "fm,f")))]
- "TARGET_80387 && (GET_CODE (operands[0]) != MEM
- || GET_CODE (operands[1]) != MEM)"
- "*
-{
- output_float_extend (insn, operands);
- return \"\";
-}"
- [(set_attr "type" "fld,fpop")])
-
-(define_expand "extendsfxf2"
- [(parallel [(set (match_operand:XF 0 "nonimmediate_operand" "")
- (float_extend:XF
- (match_operand:SF 1 "nonimmediate_operand" "")))
- (clobber (match_dup 2))
- (clobber (match_dup 3))])]
+ (float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "fm,f")))]
"TARGET_80387"
- "
-{
- if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
- operands[1] = force_reg (SFmode, operands[1]);
-
- operands[2] = assign_386_stack_local (SFmode, 0);
- operands[3] = assign_386_stack_local (XFmode, 0);
-}")
-
-(define_insn ""
- [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,!f,!*r")
- (float_extend:XF
- (match_operand:SF 1 "nonimmediate_operand" "fm,f,*r,f")))
- (clobber (match_operand:SF 2 "memory_operand" "m,m,m,m"))
- (clobber (match_operand:XF 3 "memory_operand" "m,m,m,o"))]
- "TARGET_80387 && (GET_CODE (operands[0]) != MEM
- || GET_CODE (operands[1]) != MEM)"
"*
{
- output_float_extend (insn, operands);
- return \"\";
-}"
- [(set_attr "type" "fld,fpop,fld,fpop")])
-
-(define_split
- [(set (match_operand:XF 0 "register_operand" "")
- (float_extend:XF (match_operand:SF 1 "register_operand" "")))
- (clobber (match_operand:SF 2 "memory_operand" ""))
- (clobber (match_operand:XF 3 "memory_operand" ""))]
- "TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[1])"
- [(set (match_dup 2)
- (match_dup 1))
- (set (match_dup 0)
- (float_extend:XF (match_dup 2)))]
- "")
+ switch (which_alternative)
+ {
+ case 0:
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp\\t%0\";
+ else if (STACK_TOP_P (operands[0]))
+ return \"fld%z1\\t%1\";
+ else
+ return \"fst\\t%0\";
-(define_split
- [(set (match_operand:XF 0 "register_operand" "")
- (float_extend:XF (match_operand:SF 1 "register_operand" "")))
- (clobber (match_operand:SF 2 "memory_operand" ""))
- (clobber (match_operand:XF 3 "memory_operand" ""))]
- "TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[0])"
- [(set (match_dup 3)
- (float_extend:XF (match_dup 1)))
- (set (match_dup 0)
- (match_dup 3))]
- "")
+ case 1:
+ /* There is no non-popping store to memory for XFmode. So if
+ we need one, follow the store with a load. */
+ if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp%z0\\t%0\\n\\tfld%z0\\t%0\";
+ else
+ return \"fstp%z0\\t%0\";
-(define_split
- [(set (match_operand:XF 0 "nonimmediate_operand" "")
- (float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "")))
- (clobber (match_operand:SF 2 "memory_operand" ""))
- (clobber (match_operand:XF 3 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 0)
- (float_extend:XF (match_dup 1)))]
- "")
+ default:
+ abort ();
+ }
+}"
+ [(set_attr "type" "fmov")])
-(define_insn ""
+(define_insn "extenddfxf2"
[(set (match_operand:XF 0 "nonimmediate_operand" "=f,m")
- (float_extend:XF
- (match_operand:SF 1 "nonimmediate_operand" "fm,f")))]
- "TARGET_80387 && (GET_CODE (operands[0]) != MEM
- || GET_CODE (operands[1]) != MEM)"
+ (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "fm,f")))]
+ "TARGET_80387"
"*
{
- output_float_extend (insn, operands);
- return \"\";
+ switch (which_alternative)
+ {
+ case 0:
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp\\t%0\";
+ else if (STACK_TOP_P (operands[0]))
+ return \"fld%z1\\t%1\";
+ else
+ return \"fst\\t%0\";
+
+ case 1:
+ /* There is no non-popping store to memory for XFmode. So if
+ we need one, follow the store with a load. */
+ if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp%z0\\t%0\\n\\tfld%z0\\t%0\";
+ else
+ return \"fstp%z0\\t%0\";
+
+ default:
+ abort ();
+ }
}"
- [(set_attr "type" "fld,fpop")])
+ [(set_attr "type" "fmov")])
+
+;; %%% This seems bad bad news.
+;; This cannot output into an f-reg because there is no way to be sure
+;; of truncating in that case. Otherwise this is just like a simple move
+;; insn. So we pretend we can output to a reg in order to get better
+;; register preferencing, but we really use a stack slot.
(define_expand "truncdfsf2"
[(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "")
@@ -2473,1243 +2509,944 @@
(match_operand:DF 1 "register_operand" "")))
(clobber (match_dup 2))])]
"TARGET_80387"
- "
-{
- operands[2] = (rtx) assign_386_stack_local (SFmode, 0);
-}")
+ "operands[2] = assign_386_stack_local (SFmode, 0);")
-(define_insn ""
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f,m,!*r")
+(define_insn "*truncdfsf2_1"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=m,f")
(float_truncate:SF
- (match_operand:DF 1 "register_operand" "0,f,f")))
- (clobber (match_operand:SF 2 "memory_operand" "m,m,m"))]
+ (match_operand:DF 1 "register_operand" "f,0")))
+ (clobber (match_operand:SF 2 "memory_operand" "m,m"))]
"TARGET_80387"
"*
{
- int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
- rtx xops[1];
-
- xops[0] = GET_CODE (operands[0]) == MEM ? operands[0] : operands[2];
+ switch (which_alternative)
+ {
+ case 0:
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp%z0\\t%0\";
+ else
+ return \"fst%z0\\t%0\";
+ case 1:
+ return \"fstp%z2\\t%2\;fld%z2\\t%2\";
+ }
+ abort ();
+}"
+ [(set_attr "type" "fmov,multi")])
- if (stack_top_dies || STACK_REG_P (operands[0]))
- output_asm_insn (AS1 (fstp%z0,%0), xops);
+(define_insn "*truncdfsf2_2"
+ [(set (match_operand:SF 0 "memory_operand" "=m")
+ (float_truncate:SF
+ (match_operand:DF 1 "register_operand" "f")))]
+ "TARGET_80387"
+ "*
+{
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp%z0\\t%0\";
else
- output_asm_insn (AS1 (fst%z0,%0), xops);
-
- if (STACK_REG_P (operands[0]))
- return AS1 (fld%z2,%2);
- else if (NON_STACK_REG_P (operands[0]))
- return AS2 (mov%L0,%2,%0);
-
- return \"\";
+ return \"fst%z0\\t%0\";
}"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fmov")])
(define_split
- [(set (match_operand:SF 0 "register_operand" "")
- (float_truncate:SF (match_operand:DF 1 "register_operand" "")))
+ [(set (match_operand:SF 0 "memory_operand" "")
+ (float_truncate:SF
+ (match_operand:DF 1 "register_operand" "")))
(clobber (match_operand:SF 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 2)
- (float_truncate:SF (match_dup 1)))
- (set (match_dup 0)
- (match_dup 2))]
+ "TARGET_80387"
+ [(set (match_dup 0) (float_truncate:SF (match_dup 1)))]
"")
(define_split
- [(set (match_operand:SF 0 "memory_operand" "")
- (float_truncate:SF (match_operand:DF 1 "register_operand" "")))
+ [(set (match_operand:SF 0 "register_operand" "")
+ (float_truncate:SF
+ (match_operand:DF 1 "register_operand" "")))
(clobber (match_operand:SF 2 "memory_operand" ""))]
"TARGET_80387 && reload_completed"
- [(set (match_dup 0)
- (float_truncate:SF (match_dup 1)))]
+ [(set (match_dup 2) (float_truncate:SF (match_dup 1)))
+ (set (match_dup 0) (match_dup 2))]
"")
-;; This cannot output into an f-reg because there is no way to be sure
-;; of truncating in that case.
-
-(define_insn ""
- [(set (match_operand:SF 0 "memory_operand" "=m")
- (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))]
- "TARGET_80387"
- "*
-{
- int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
-
- if (stack_top_dies)
- return AS1 (fstp%z0,%0);
- else
- return AS1 (fst%z0,%0);
-}"
- [(set_attr "type" "fpop")])
-
(define_expand "truncxfsf2"
[(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "")
(float_truncate:SF
(match_operand:XF 1 "register_operand" "")))
(clobber (match_dup 2))])]
"TARGET_80387"
- "
-{
- operands[2] = (rtx) assign_386_stack_local (SFmode, 0);
-}")
+ "operands[2] = assign_386_stack_local (SFmode, 0);")
-(define_insn ""
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f,m,!*r")
+(define_insn "*truncxfsf2_1"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=m,f")
(float_truncate:SF
- (match_operand:XF 1 "register_operand" "0,f,f")))
- (clobber (match_operand:SF 2 "memory_operand" "m,m,m"))]
+ (match_operand:XF 1 "register_operand" "f,0")))
+ (clobber (match_operand:SF 2 "memory_operand" "m,m"))]
"TARGET_80387"
"*
{
- int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
- rtx xops[1];
-
- xops[0] = GET_CODE (operands[0]) == MEM ? operands[0] : operands[2];
+ switch (which_alternative)
+ {
+ case 0:
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp%z0\\t%0\";
+ else
+ return \"fst%z0\\t%0\";
+ case 1:
+ return \"fstp%z2\\t%2\;fld%z2\\t%2\";
+ }
+ abort ();
+}"
+ [(set_attr "type" "fmov,multi")])
- if (stack_top_dies || STACK_REG_P (operands[0]))
- output_asm_insn (AS1 (fstp%z0,%0), xops);
+(define_insn "*truncxfsf2_2"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=m")
+ (float_truncate:SF
+ (match_operand:XF 1 "register_operand" "f")))]
+ "TARGET_80387"
+ "*
+{
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp%z0\\t%0\";
else
- output_asm_insn (AS1 (fst%z0,%0), xops);
-
- if (STACK_REG_P (operands[0]))
- return AS1 (fld%z2,%2);
- else if (NON_STACK_REG_P (operands[0]))
- return AS2 (mov%L0,%2,%0);
-
- return \"\";
+ return \"fst%z0\\t%0\";
}"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fmov")])
(define_split
- [(set (match_operand:SF 0 "register_operand" "")
- (float_truncate:SF (match_operand:XF 1 "register_operand" "")))
+ [(set (match_operand:SF 0 "memory_operand" "")
+ (float_truncate:SF
+ (match_operand:XF 1 "register_operand" "")))
(clobber (match_operand:SF 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 2)
- (float_truncate:SF (match_dup 1)))
- (set (match_dup 0)
- (match_dup 2))]
+ "TARGET_80387"
+ [(set (match_dup 0) (float_truncate:SF (match_dup 1)))]
"")
(define_split
- [(set (match_operand:SF 0 "memory_operand" "")
- (float_truncate:SF (match_operand:XF 1 "register_operand" "")))
+ [(set (match_operand:SF 0 "register_operand" "")
+ (float_truncate:SF
+ (match_operand:XF 1 "register_operand" "")))
(clobber (match_operand:SF 2 "memory_operand" ""))]
"TARGET_80387 && reload_completed"
- [(set (match_dup 0)
- (float_truncate:SF (match_dup 1)))]
+ [(set (match_dup 2) (float_truncate:SF (match_dup 1)))
+ (set (match_dup 0) (match_dup 2))]
"")
-(define_insn ""
- [(set (match_operand:SF 0 "memory_operand" "=m")
- (float_truncate:SF (match_operand:XF 1 "register_operand" "f")))]
- "TARGET_80387"
- "*
-{
- int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
-
- if (stack_top_dies)
- return AS1 (fstp%z0,%0);
- else
- return AS1 (fst%z0,%0);
-}"
- [(set_attr "type" "fpop")])
-
(define_expand "truncxfdf2"
[(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "")
(float_truncate:DF
(match_operand:XF 1 "register_operand" "")))
(clobber (match_dup 2))])]
"TARGET_80387"
- "
-{
- operands[2] = (rtx) assign_386_stack_local (DFmode, 0);
-}")
+ "operands[2] = assign_386_stack_local (DFmode, 0);")
-(define_insn ""
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,!*r")
+(define_insn "*truncxfdf2_1"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=m,f")
(float_truncate:DF
- (match_operand:XF 1 "register_operand" "0,f,f")))
- (clobber (match_operand:DF 2 "memory_operand" "m,m,o"))]
+ (match_operand:XF 1 "register_operand" "f,0")))
+ (clobber (match_operand:DF 2 "memory_operand" "m,m"))]
"TARGET_80387"
"*
{
- int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
- rtx xops[2];
-
- xops[0] = GET_CODE (operands[0]) == MEM ? operands[0] : operands[2];
-
- if (stack_top_dies || STACK_REG_P (operands[0]))
- output_asm_insn (AS1 (fstp%z0,%0), xops);
- else
- output_asm_insn (AS1 (fst%z0,%0), xops);
-
- if (STACK_REG_P (operands[0]))
- return AS1 (fld%z2,%2);
- else if (NON_STACK_REG_P (operands[0]))
+ switch (which_alternative)
{
- xops[0] = operands[0];
- xops[1] = operands[2];
- output_asm_insn (output_move_double (xops), xops);
+ case 0:
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp%z0\\t%0\";
+ else
+ return \"fst%z0\\t%0\";
+ case 1:
+ return \"fstp%z2\\t%2\;fld%z2\\t%2\";
}
+ abort ();
+}"
+ [(set_attr "type" "fmov,multi")])
- return \"\";
+(define_insn "*truncxfdf2_2"
+ [(set (match_operand:DF 0 "memory_operand" "=m")
+ (float_truncate:DF
+ (match_operand:XF 1 "register_operand" "f")))]
+ "TARGET_80387"
+ "*
+{
+ if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+ return \"fstp%z0\\t%0\";
+ else
+ return \"fst%z0\\t%0\";
}"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fmov")])
(define_split
- [(set (match_operand:DF 0 "register_operand" "")
- (float_truncate:DF (match_operand:XF 1 "register_operand" "")))
+ [(set (match_operand:DF 0 "memory_operand" "")
+ (float_truncate:DF
+ (match_operand:XF 1 "register_operand" "")))
(clobber (match_operand:DF 2 "memory_operand" ""))]
"TARGET_80387 && reload_completed"
- [(set (match_dup 2)
- (float_truncate:DF (match_dup 1)))
- (set (match_dup 0)
- (match_dup 2))]
+ [(set (match_dup 0) (subreg:DF (match_dup 1) 0))]
"")
(define_split
- [(set (match_operand:DF 0 "memory_operand" "")
- (float_truncate:DF (match_operand:XF 1 "register_operand" "")))
+ [(set (match_operand:DF 0 "register_operand" "")
+ (float_truncate:DF
+ (match_operand:XF 1 "register_operand" "")))
(clobber (match_operand:DF 2 "memory_operand" ""))]
"TARGET_80387 && reload_completed"
- [(set (match_dup 0)
- (float_truncate:DF (match_dup 1)))]
+ [(set (match_dup 2) (subreg:DF (match_dup 1) 0))
+ (set (match_dup 0) (match_dup 2))]
"")
-
-(define_insn ""
- [(set (match_operand:DF 0 "memory_operand" "=m")
- (float_truncate:DF (match_operand:XF 1 "register_operand" "f")))]
- "TARGET_80387"
- "*
-{
- int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
-
- if (stack_top_dies)
- return AS1 (fstp%z0,%0);
- else
- return AS1 (fst%z0,%0);
-}"
- [(set_attr "type" "fpop")])
-;; Conversions between floating point and fix point.
+;; %%% Break up all these bad boys.
-(define_expand "fix_truncsfsi2"
- [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
- (fix:SI (fix:SF (match_operand:SF 1 "register_operand" ""))))
+;; Signed conversion to DImode.
+
+(define_expand "fix_truncxfdi2"
+ [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (fix:DI (match_operand:XF 1 "register_operand" "")))
(clobber (match_dup 2))
(clobber (match_dup 3))
- (clobber (match_dup 4))
- (clobber (match_scratch:HI 5 ""))])]
+ (clobber (match_scratch:SI 4 ""))
+ (clobber (match_scratch:XF 5 ""))])]
"TARGET_80387"
- "
-{
- operands[2] = (rtx) assign_386_stack_local (HImode, 0);
- operands[3] = (rtx) assign_386_stack_local (HImode, 1);
- operands[4] = (rtx) assign_386_stack_local (SImode, 0);
-}")
+ "operands[2] = assign_386_stack_local (SImode, 0);
+ operands[3] = assign_386_stack_local (DImode, 1);")
-;; We have to earlyclobber the register output to prevent it from overlapping
-;; with the address for one of the scratch memory operands.
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=m,!&r")
- (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f,f"))))
- (clobber (match_operand:HI 2 "memory_operand" "m,m"))
- (clobber (match_operand:HI 3 "memory_operand" "m,m"))
- (clobber (match_operand:SI 4 "memory_operand" "m,m"))
- (clobber (match_scratch:HI 5 "=&r,&r"))]
+(define_expand "fix_truncdfdi2"
+ [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (fix:DI (match_operand:DF 1 "register_operand" "")))
+ (clobber (match_dup 2))
+ (clobber (match_dup 3))
+ (clobber (match_scratch:SI 4 ""))
+ (clobber (match_scratch:XF 5 ""))])]
"TARGET_80387"
- "* return output_fix_trunc (insn, operands);"
- [(set_attr "type" "fpop")])
+ "operands[2] = assign_386_stack_local (SImode, 0);
+ operands[3] = assign_386_stack_local (DImode, 1);")
(define_expand "fix_truncsfdi2"
[(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
- (fix:DI (fix:SF (match_operand:SF 1 "register_operand" ""))))
- (clobber (match_dup 1))
+ (fix:DI (match_operand:SF 1 "register_operand" "")))
(clobber (match_dup 2))
(clobber (match_dup 3))
- (clobber (match_dup 4))
- (clobber (match_scratch:HI 5 ""))])]
- "TARGET_80387"
- "
-{
- operands[1] = copy_to_mode_reg (SFmode, operands[1]);
- operands[2] = (rtx) assign_386_stack_local (HImode, 0);
- operands[3] = (rtx) assign_386_stack_local (HImode, 1);
- operands[4] = (rtx) assign_386_stack_local (DImode, 0);
-}")
-
-;; We have to earlyclobber the register output to prevent it from overlapping
-;; with the address for one of the scratch memory operands.
-(define_insn ""
- [(set (match_operand:DI 0 "nonimmediate_operand" "=m,!&r")
- (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f,f"))))
- (clobber (match_dup 1))
- (clobber (match_operand:HI 2 "memory_operand" "m,m"))
- (clobber (match_operand:HI 3 "memory_operand" "m,m"))
- (clobber (match_operand:DI 4 "memory_operand" "m,o"))
- (clobber (match_scratch:HI 5 "=&r,&r"))]
+ (clobber (match_scratch:SI 4 ""))
+ (clobber (match_scratch:XF 5 ""))])]
"TARGET_80387"
+ "operands[2] = assign_386_stack_local (SImode, 0);
+ operands[3] = assign_386_stack_local (DImode, 1);")
+
+(define_insn "*fix_truncdi_1"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "m,?r")
+ (fix:DI (match_operand 1 "register_operand" "f,f")))
+ (clobber (match_operand:SI 2 "memory_operand" "o,o"))
+ (clobber (match_operand:DI 3 "memory_operand" "m,m"))
+ (clobber (match_scratch:SI 4 "=&r,=&r"))
+ (clobber (match_scratch:XF 5 "=f,f"))]
+ "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))"
"* return output_fix_trunc (insn, operands);"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "multi")])
-(define_expand "fix_truncdfsi2"
- [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
- (fix:SI (fix:DF (match_operand:DF 1 "register_operand" ""))))
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (fix:DI (match_operand 1 "register_operand" "")))
+ (clobber (match_operand:SI 2 "memory_operand" ""))
+ (clobber (match_operand:DI 3 "memory_operand" ""))
+ (clobber (match_scratch:SI 4 ""))
+ (clobber (match_scratch:XF 5 ""))]
+ "reload_completed && !reg_overlap_mentioned_p (operands[4], operands[3])"
+ [(parallel [(set (match_dup 3) (fix:DI (match_dup 1)))
(clobber (match_dup 2))
(clobber (match_dup 3))
(clobber (match_dup 4))
- (clobber (match_scratch:HI 5 ""))])]
- "TARGET_80387"
- "
-{
- operands[2] = (rtx) assign_386_stack_local (HImode, 0);
- operands[3] = (rtx) assign_386_stack_local (HImode, 1);
- operands[4] = (rtx) assign_386_stack_local (SImode, 0);
-}")
+ (clobber (match_dup 5))])
+ (set (match_dup 0) (match_dup 3))]
+ "")
-;; We have to earlyclobber the register output to prevent it from overlapping
-;; with the address for one of the scratch memory operands.
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=m,!&r")
- (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f,f"))))
- (clobber (match_operand:HI 2 "memory_operand" "m,m"))
- (clobber (match_operand:HI 3 "memory_operand" "m,m"))
- (clobber (match_operand:SI 4 "memory_operand" "m,m"))
- (clobber (match_scratch:HI 5 "=&r,&r"))]
- "TARGET_80387"
- "* return output_fix_trunc (insn, operands);"
- [(set_attr "type" "fpop")])
+;; Signed conversion to SImode.
-(define_expand "fix_truncdfdi2"
- [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
- (fix:DI (fix:DF (match_operand:DF 1 "register_operand" ""))))
- (clobber (match_dup 1))
+(define_expand "fix_truncxfsi2"
+ [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (fix:SI (match_operand:XF 1 "register_operand" "")))
(clobber (match_dup 2))
(clobber (match_dup 3))
- (clobber (match_dup 4))
- (clobber (match_scratch:HI 5 ""))])]
+ (clobber (match_scratch:SI 4 ""))])]
"TARGET_80387"
- "
-{
- operands[1] = copy_to_mode_reg (DFmode, operands[1]);
- operands[2] = (rtx) assign_386_stack_local (HImode, 0);
- operands[3] = (rtx) assign_386_stack_local (HImode, 1);
- operands[4] = (rtx) assign_386_stack_local (DImode, 0);
-}")
+ "operands[2] = assign_386_stack_local (SImode, 0);
+ operands[3] = assign_386_stack_local (SImode, 1);")
-;; We have to earlyclobber the register output to prevent it from overlapping
-;; with the address for one of the scratch memory operands.
-(define_insn ""
- [(set (match_operand:DI 0 "nonimmediate_operand" "=m,!&r")
- (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f,f"))))
- (clobber (match_dup 1))
- (clobber (match_operand:HI 2 "memory_operand" "m,m"))
- (clobber (match_operand:HI 3 "memory_operand" "m,m"))
- (clobber (match_operand:DI 4 "memory_operand" "m,o"))
- (clobber (match_scratch:HI 5 "=&r,&r"))]
- "TARGET_80387"
- "* return output_fix_trunc (insn, operands);"
- [(set_attr "type" "fpop")])
-
-(define_expand "fix_truncxfsi2"
+(define_expand "fix_truncdfsi2"
[(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
- (fix:SI (fix:XF (match_operand:XF 1 "register_operand" ""))))
+ (fix:SI (match_operand:DF 1 "register_operand" "")))
(clobber (match_dup 2))
(clobber (match_dup 3))
- (clobber (match_dup 4))
- (clobber (match_scratch:HI 5 ""))])]
+ (clobber (match_scratch:SI 4 ""))])]
"TARGET_80387"
- "
-{
- operands[2] = (rtx) assign_386_stack_local (HImode, 0);
- operands[3] = (rtx) assign_386_stack_local (HImode, 1);
- operands[4] = (rtx) assign_386_stack_local (SImode, 0);
-}")
+ "operands[2] = assign_386_stack_local (SImode, 0);
+ operands[3] = assign_386_stack_local (SImode, 1);")
-;; We have to earlyclobber the register output to prevent it from overlapping
-;; with the address for one of the scratch memory operands.
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=m,!&r")
- (fix:SI (fix:XF (match_operand:XF 1 "register_operand" "f,f"))))
- (clobber (match_operand:HI 2 "memory_operand" "m,m"))
- (clobber (match_operand:HI 3 "memory_operand" "m,m"))
- (clobber (match_operand:SI 4 "memory_operand" "m,m"))
- (clobber (match_scratch:HI 5 "=&r,&r"))]
+(define_expand "fix_truncsfsi2"
+ [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (fix:SI (match_operand:SF 1 "register_operand" "")))
+ (clobber (match_dup 2))
+ (clobber (match_dup 3))
+ (clobber (match_scratch:SI 4 ""))])]
"TARGET_80387"
+ "operands[2] = assign_386_stack_local (SImode, 0);
+ operands[3] = assign_386_stack_local (SImode, 1);")
+
+(define_insn "*fix_truncsi_1"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "m,?r")
+ (fix:SI (match_operand 1 "register_operand" "f,f")))
+ (clobber (match_operand:SI 2 "memory_operand" "o,o"))
+ (clobber (match_operand:SI 3 "memory_operand" "m,m"))
+ (clobber (match_scratch:SI 4 "=&r,r"))]
+ "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))"
"* return output_fix_trunc (insn, operands);"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "multi")])
-(define_expand "fix_truncxfdi2"
- [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
- (fix:DI (fix:XF (match_operand:XF 1 "register_operand" ""))))
- (clobber (match_dup 1))
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (fix:SI (match_operand 1 "register_operand" "")))
+ (clobber (match_operand:SI 2 "memory_operand" ""))
+ (clobber (match_operand:SI 3 "memory_operand" ""))
+ (clobber (match_scratch:SI 4 ""))]
+ "reload_completed"
+ [(parallel [(set (match_dup 3) (fix:SI (match_dup 1)))
(clobber (match_dup 2))
(clobber (match_dup 3))
- (clobber (match_dup 4))
- (clobber (match_scratch:HI 5 ""))])]
+ (clobber (match_dup 4))])
+ (set (match_dup 0) (match_dup 3))]
+ "")
+
+;; %% Not used yet.
+(define_insn "x86_fnstcw_1"
+ [(set (match_operand:HI 0 "memory_operand" "m")
+ (unspec [(reg:HI 18)] 11))]
"TARGET_80387"
- "
-{
- operands[1] = copy_to_mode_reg (XFmode, operands[1]);
- operands[2] = (rtx) assign_386_stack_local (HImode, 0);
- operands[3] = (rtx) assign_386_stack_local (HImode, 1);
- operands[4] = (rtx) assign_386_stack_local (DImode, 0);
-}")
+ "fnstcw\\t%0"
+ [(set_attr "length_opcode" "2")
+ (set_attr "ppro_uops" "few")])
-;; We have to earlyclobber the register output to prevent it from overlapping
-;; with the address for one of the scratch memory operands.
-(define_insn ""
- [(set (match_operand:DI 0 "nonimmediate_operand" "=m,!&r")
- (fix:DI (fix:XF (match_operand:XF 1 "register_operand" "f,f"))))
- (clobber (match_dup 1))
- (clobber (match_operand:HI 2 "memory_operand" "m,m"))
- (clobber (match_operand:HI 3 "memory_operand" "m,m"))
- (clobber (match_operand:DI 4 "memory_operand" "m,o"))
- (clobber (match_scratch:HI 5 "=&r,&r"))]
+(define_insn "x86_fldcw_1"
+ [(set (reg:HI 18)
+ (unspec [(match_operand:HI 0 "memory_operand" "m")] 12))]
"TARGET_80387"
- "* return output_fix_trunc (insn, operands);"
- [(set_attr "type" "fpop")])
+ "fldcw\\t%0"
+ [(set_attr "length_opcode" "2")
+ (set_attr "ppro_uops" "few")])
;; Conversion between fixed point and floating point.
-;; ??? Possibly represent floatunssidf2 here in gcc2.
-
-(define_expand "floatsisf2"
- [(parallel [(set (match_operand:SF 0 "register_operand" "")
- (float:SF (match_operand:SI 1 "nonimmediate_operand" "")))
- (clobber (match_dup 2))])]
- "TARGET_80387"
- "operands[2] = assign_386_stack_local (SImode, 0);")
-
-(define_insn ""
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (float:SF (match_operand:SI 1 "nonimmediate_operand" "m,!r")))
- (clobber (match_operand:SI 2 "memory_operand" "m,m"))]
- "TARGET_80387"
- "#")
-
-(define_split
- [(set (match_operand:SF 0 "register_operand" "")
- (float:SF (match_operand:SI 1 "memory_operand" "")))
- (clobber (match_operand:SI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 0)
- (float:SF (match_dup 1)))]
- "")
-
-(define_split
- [(set (match_operand:SF 0 "register_operand" "")
- (float:SF (match_operand:SI 1 "register_operand" "")))
- (clobber (match_operand:SI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 2)
- (match_dup 1))
- (set (match_dup 0)
- (float:SF (match_dup 2)))]
- "")
-
-(define_insn ""
- [(set (match_operand:SF 0 "register_operand" "=f")
- (float:SF (match_operand:SI 1 "memory_operand" "m")))]
- "TARGET_80387"
- "* return AS1 (fild%z1,%1);"
- [(set_attr "type" "fpop")])
-
-(define_expand "floathisf2"
- [(parallel [(set (match_operand:SF 0 "register_operand" "")
- (float:SF (match_operand:HI 1 "nonimmediate_operand" "")))
- (clobber (match_dup 2))])]
- "TARGET_80387"
- "operands[2] = assign_386_stack_local (HImode, 0);")
+;; Even though we only accept memory inputs, the backend _really_
+;; wants to be able to do this between registers.
-(define_insn ""
+(define_insn "floatsisf2"
[(set (match_operand:SF 0 "register_operand" "=f,f")
- (float:SF (match_operand:HI 1 "nonimmediate_operand" "m,!r")))
- (clobber (match_operand:HI 2 "memory_operand" "m,m"))]
+ (float:SF (match_operand:SI 1 "nonimmediate_operand" "m,r")))]
"TARGET_80387"
- "#")
-
-(define_split
- [(set (match_operand:SF 0 "register_operand" "")
- (float:SF (match_operand:HI 1 "memory_operand" "")))
- (clobber (match_operand:HI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 0)
- (float:SF (match_dup 1)))]
- "")
-
-(define_split
- [(set (match_operand:SF 0 "register_operand" "")
- (float:SF (match_operand:HI 1 "register_operand" "")))
- (clobber (match_operand:HI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 2)
- (match_dup 1))
- (set (match_dup 0)
- (float:SF (match_dup 2)))]
- "")
-
-(define_insn ""
- [(set (match_operand:SF 0 "register_operand" "=f")
- (float:SF (match_operand:HI 1 "memory_operand" "m")))]
- "TARGET_80387"
- "* return AS1 (fild%z1,%1);"
- [(set_attr "type" "fpop")])
-
-(define_expand "floatdisf2"
- [(parallel [(set (match_operand:SF 0 "register_operand" "")
- (float:SF (match_operand:DI 1 "nonimmediate_operand" "")))
- (clobber (match_dup 2))])]
- "TARGET_80387"
- "operands[2] = assign_386_stack_local (DImode, 0);")
+ "@
+ fild%z1\\t%1
+ #"
+ [(set_attr "type" "fmov,multi")
+ (set_attr "fp_int_src" "true")])
-(define_insn ""
+(define_insn "floatdisf2"
[(set (match_operand:SF 0 "register_operand" "=f,f")
- (float:SF (match_operand:DI 1 "nonimmediate_operand" "m,!r")))
- (clobber (match_operand:DI 2 "memory_operand" "m,o"))]
+ (float:SF (match_operand:DI 1 "nonimmediate_operand" "m,r")))]
"TARGET_80387"
- "#")
-
-(define_split
- [(set (match_operand:SF 0 "register_operand" "")
- (float:SF (match_operand:DI 1 "memory_operand" "")))
- (clobber (match_operand:DI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 0)
- (float:SF (match_dup 1)))]
- "")
-
-(define_split
- [(set (match_operand:SF 0 "register_operand" "")
- (float:SF (match_operand:DI 1 "register_operand" "")))
- (clobber (match_operand:DI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 2)
- (match_dup 1))
- (set (match_dup 0)
- (float:SF (match_dup 2)))]
- "")
-
-(define_insn ""
- [(set (match_operand:SF 0 "register_operand" "=f")
- (float:SF (match_operand:DI 1 "memory_operand" "m")))]
- "TARGET_80387"
- "* return AS1 (fild%z1,%1);"
- [(set_attr "type" "fpop")])
-
-(define_expand "floatsidf2"
- [(parallel [(set (match_operand:DF 0 "register_operand" "")
- (float:DF (match_operand:SI 1 "nonimmediate_operand" "")))
- (clobber (match_dup 2))])]
- "TARGET_80387"
- "operands[2] = assign_386_stack_local (SImode, 0);")
-
-(define_insn ""
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (float:DF (match_operand:SI 1 "nonimmediate_operand" "m,!r")))
- (clobber (match_operand:SI 2 "memory_operand" "m,m"))]
- "TARGET_80387"
- "#")
-
-(define_split
- [(set (match_operand:DF 0 "register_operand" "")
- (float:DF (match_operand:SI 1 "memory_operand" "")))
- (clobber (match_operand:SI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 0)
- (float:DF (match_dup 1)))]
- "")
-
-(define_split
- [(set (match_operand:DF 0 "register_operand" "")
- (float:DF (match_operand:SI 1 "register_operand" "")))
- (clobber (match_operand:SI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 2)
- (match_dup 1))
- (set (match_dup 0)
- (float:DF (match_dup 2)))]
- "")
-
-(define_insn ""
- [(set (match_operand:DF 0 "register_operand" "=f")
- (float:DF (match_operand:SI 1 "memory_operand" "m")))]
- "TARGET_80387"
- "* return AS1 (fild%z1,%1);"
- [(set_attr "type" "fpop")])
-
-(define_expand "floathidf2"
- [(parallel [(set (match_operand:DF 0 "register_operand" "")
- (float:DF (match_operand:HI 1 "nonimmediate_operand" "")))
- (clobber (match_dup 2))])]
- "TARGET_80387"
- "operands[2] = assign_386_stack_local (HImode, 0);")
+ "@
+ fild%z1\\t%1
+ #"
+ [(set_attr "type" "fmov,multi")
+ (set_attr "fp_int_src" "true")])
-(define_insn ""
+(define_insn "floatsidf2"
[(set (match_operand:DF 0 "register_operand" "=f,f")
- (float:DF (match_operand:HI 1 "nonimmediate_operand" "m,!r")))
- (clobber (match_operand:HI 2 "memory_operand" "m,m"))]
- "TARGET_80387"
- "#")
-
-(define_split
- [(set (match_operand:DF 0 "register_operand" "")
- (float:DF (match_operand:HI 1 "memory_operand" "")))
- (clobber (match_operand:HI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 0)
- (float:DF (match_dup 1)))]
- "")
-
-(define_split
- [(set (match_operand:DF 0 "register_operand" "")
- (float:DF (match_operand:HI 1 "register_operand" "")))
- (clobber (match_operand:HI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 2)
- (match_dup 1))
- (set (match_dup 0)
- (float:DF (match_dup 2)))]
- "")
-
-(define_insn ""
- [(set (match_operand:DF 0 "register_operand" "=f")
- (float:DF (match_operand:HI 1 "memory_operand" "m")))]
+ (float:DF (match_operand:SI 1 "nonimmediate_operand" "m,r")))]
"TARGET_80387"
- "* return AS1 (fild%z1,%1);"
- [(set_attr "type" "fpop")])
-
-(define_expand "floatdidf2"
- [(parallel [(set (match_operand:DF 0 "register_operand" "")
- (float:DF (match_operand:DI 1 "nonimmediate_operand" "")))
- (clobber (match_dup 2))])]
- "TARGET_80387"
- "operands[2] = assign_386_stack_local (DImode, 0);")
+ "@
+ fild%z1\\t%1
+ #"
+ [(set_attr "type" "fmov,multi")
+ (set_attr "fp_int_src" "true")])
-(define_insn ""
+(define_insn "floatdidf2"
[(set (match_operand:DF 0 "register_operand" "=f,f")
- (float:DF (match_operand:DI 1 "nonimmediate_operand" "m,!r")))
- (clobber (match_operand:DI 2 "memory_operand" "m,o"))]
- "TARGET_80387"
- "#")
-
-(define_split
- [(set (match_operand:DF 0 "register_operand" "")
- (float:DF (match_operand:DI 1 "memory_operand" "")))
- (clobber (match_operand:DI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 0)
- (float:DF (match_dup 1)))]
- "")
-
-(define_split
- [(set (match_operand:DF 0 "register_operand" "")
- (float:DF (match_operand:DI 1 "register_operand" "")))
- (clobber (match_operand:DI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 2)
- (match_dup 1))
- (set (match_dup 0)
- (float:DF (match_dup 2)))]
- "")
-
-(define_insn ""
- [(set (match_operand:DF 0 "register_operand" "=f")
- (float:DF (match_operand:DI 1 "memory_operand" "m")))]
- "TARGET_80387"
- "* return AS1 (fild%z1,%1);"
- [(set_attr "type" "fpop")])
-
-(define_expand "floatsixf2"
- [(parallel [(set (match_operand:XF 0 "register_operand" "")
- (float:XF (match_operand:SI 1 "nonimmediate_operand" "")))
- (clobber (match_dup 2))])]
+ (float:DF (match_operand:DI 1 "nonimmediate_operand" "m,r")))]
"TARGET_80387"
- "operands[2] = assign_386_stack_local (SImode, 0);")
+ "@
+ fild%z1\\t%1
+ #"
+ [(set_attr "type" "fmov,multi")
+ (set_attr "fp_int_src" "true")])
-(define_insn ""
+(define_insn "floatsixf2"
[(set (match_operand:XF 0 "register_operand" "=f,f")
- (float:XF (match_operand:SI 1 "nonimmediate_operand" "m,!r")))
- (clobber (match_operand:SI 2 "memory_operand" "m,m"))]
+ (float:XF (match_operand:SI 1 "nonimmediate_operand" "m,r")))]
"TARGET_80387"
- "#")
-
-(define_split
- [(set (match_operand:XF 0 "register_operand" "")
- (float:XF (match_operand:SI 1 "memory_operand" "")))
- (clobber (match_operand:SI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 0)
- (float:XF (match_dup 1)))]
- "")
-
-(define_split
- [(set (match_operand:XF 0 "register_operand" "")
- (float:XF (match_operand:SI 1 "register_operand" "")))
- (clobber (match_operand:SI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 2)
- (match_dup 1))
- (set (match_dup 0)
- (float:XF (match_dup 2)))]
- "")
-
-(define_insn ""
- [(set (match_operand:XF 0 "register_operand" "=f")
- (float:XF (match_operand:SI 1 "memory_operand" "m")))]
- "TARGET_80387"
- "* return AS1 (fild%z1,%1);"
- [(set_attr "type" "fpop")])
-
-(define_expand "floathixf2"
- [(parallel [(set (match_operand:XF 0 "register_operand" "")
- (float:XF (match_operand:HI 1 "nonimmediate_operand" "")))
- (clobber (match_dup 2))])]
- "TARGET_80387"
- "operands[2] = assign_386_stack_local (HImode, 0);")
+ "@
+ fild%z1\\t%1
+ #"
+ [(set_attr "type" "fmov,multi")
+ (set_attr "fp_int_src" "true")])
-(define_insn ""
+(define_insn "floatdixf2"
[(set (match_operand:XF 0 "register_operand" "=f,f")
- (float:XF (match_operand:HI 1 "nonimmediate_operand" "m,!r")))
- (clobber (match_operand:HI 2 "memory_operand" "m,m"))]
+ (float:XF (match_operand:DI 1 "nonimmediate_operand" "m,r")))]
"TARGET_80387"
- "#")
+ "@
+ fild%z1\\t%1
+ #"
+ [(set_attr "type" "fmov,multi")
+ (set_attr "fp_int_src" "true")])
+;; %%% Kill these when reload knows how to do it.
(define_split
- [(set (match_operand:XF 0 "register_operand" "")
- (float:XF (match_operand:HI 1 "memory_operand" "")))
- (clobber (match_operand:HI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 0)
- (float:XF (match_dup 1)))]
- "")
+ [(set (match_operand 0 "register_operand" "")
+ (float (match_operand:SI 1 "register_operand" "")))]
+ "reload_completed && FLOAT_MODE_P (GET_MODE (operands[0]))"
+ [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 1))
+ (set (match_dup 0) (match_dup 2))
+ (parallel [(set (match_dup 1) (mem:SI (reg:SI 7)))
+ (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])]
+ "operands[2] = gen_rtx_FLOAT (GET_MODE (operands[0]),
+ gen_rtx_MEM (SImode, stack_pointer_rtx));")
(define_split
- [(set (match_operand:XF 0 "register_operand" "")
- (float:XF (match_operand:HI 1 "register_operand" "")))
- (clobber (match_operand:HI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 2)
- (match_dup 1))
- (set (match_dup 0)
- (float:XF (match_dup 2)))]
- "")
-
-(define_insn ""
- [(set (match_operand:XF 0 "register_operand" "=f")
- (float:XF (match_operand:HI 1 "memory_operand" "m")))]
- "TARGET_80387"
- "* return AS1 (fild%z1,%1);"
- [(set_attr "type" "fpop")])
+ [(set (match_operand 0 "register_operand" "")
+ (float (match_operand:DI 1 "nonmemory_operand" "")))]
+ "reload_completed && FLOAT_MODE_P (GET_MODE (operands[0]))"
+ [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 2))
+ (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 1))
+ (set (match_dup 0) (match_dup 3))
+ (parallel [(set (match_dup 1) (mem:SI (reg:SI 7)))
+ (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])
+ (parallel [(set (match_dup 2) (mem:SI (reg:SI 7)))
+ (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])]
+ "split_di (operands+1, 1, operands+1, operands+2);
+ operands[3] = gen_rtx_FLOAT (GET_MODE (operands[0]),
+ gen_rtx_MEM (DImode, stack_pointer_rtx));")
+
+;; Add instructions
-(define_expand "floatdixf2"
- [(parallel [(set (match_operand:XF 0 "register_operand" "")
- (float:XF (match_operand:DI 1 "nonimmediate_operand" "")))
- (clobber (match_dup 2))])]
- "TARGET_80387"
- "operands[2] = assign_386_stack_local (DImode, 0);")
+;; %%% define_expand from the very first?
+;; %%% splits for addsidi3
+; [(set (match_operand:DI 0 "nonimmediate_operand" "")
+; (plus:DI (match_operand:DI 1 "general_operand" "")
+; (zero_extend:DI (match_operand:SI 2 "general_operand" ""))))]
-(define_insn ""
- [(set (match_operand:XF 0 "register_operand" "=f,f")
- (float:XF (match_operand:DI 1 "nonimmediate_operand" "m,!r")))
- (clobber (match_operand:DI 2 "memory_operand" "m,o"))]
- "TARGET_80387"
+(define_insn "adddi3"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o")
+ (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:DI 2 "general_operand" "roiF,riF")))
+ (clobber (reg:CC 17))]
+ ""
"#")
(define_split
- [(set (match_operand:XF 0 "register_operand" "")
- (float:XF (match_operand:DI 1 "memory_operand" "")))
- (clobber (match_operand:DI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 0)
- (float:XF (match_dup 1)))]
- "")
-
-(define_split
- [(set (match_operand:XF 0 "register_operand" "")
- (float:XF (match_operand:DI 1 "register_operand" "")))
- (clobber (match_operand:DI 2 "memory_operand" ""))]
- "TARGET_80387 && reload_completed"
- [(set (match_dup 2)
- (match_dup 1))
- (set (match_dup 0)
- (float:XF (match_dup 2)))]
- "")
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (plus:DI (match_operand:DI 1 "general_operand" "")
+ (match_operand:DI 2 "general_operand" "")))
+ (clobber (reg:CC 17))]
+ "cse_not_expected"
+ [(parallel [(set (reg:CC 17) (plus:CC (match_dup 1) (match_dup 2)))
+ (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))])
+ (parallel [(set (match_dup 3)
+ (plus:SI (match_dup 4)
+ (plus:SI (match_dup 5)
+ (ltu:SI (reg:CC 17) (const_int 0)))))
+ (clobber (reg:CC 17))])]
+ "split_di (operands+0, 1, operands+0, operands+3);
+ split_di (operands+1, 1, operands+1, operands+4);
+ split_di (operands+2, 1, operands+2, operands+5);")
+
+(define_insn "addcsi3"
+ [(set (reg:CC 17) (plus:CC (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "ri,rm")))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "add{l}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "addxsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+ (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (plus:SI (match_operand:SI 2 "general_operand" "ri,rm")
+ (ltu:SI (reg:CC 17) (const_int 0)))))
+ (clobber (reg:CC 17))]
+ ""
+ "adc{l}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")
+ (set_attr "pent_pair" "pu")
+ (set_attr "ppro_uops" "few")])
-(define_insn ""
- [(set (match_operand:XF 0 "register_operand" "=f")
- (float:XF (match_operand:DI 1 "memory_operand" "m")))]
- "TARGET_80387"
- "* return AS1 (fild%z1,%1);"
- [(set_attr "type" "fpop")])
-
-;;- add instructions
+(define_expand "addsi3"
+ [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (plus:SI (match_operand:SI 1 "nonimmediate_operand" "")
+ (match_operand:SI 2 "general_operand" "")))
+ (clobber (reg:CC 17))])]
+ ""
+ "ix86_expand_binary_operator (PLUS, SImode, operands); DONE;")
-(define_insn "*addsidi3_1"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,!&r,!r,o,!o")
- (plus:DI (match_operand:DI 1 "general_operand" "0,0,0,o,riF,riF,o")
- (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,roi,roi,ri,ri"))))
- (clobber (match_scratch:SI 3 "=X,X,X,X,X,X,&r"))]
+(define_insn "*addsi_0"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "nonmemory_operand" "rni")))]
""
"*
{
- rtx low[3], high[3], xops[7];
-
- CC_STATUS_INIT;
-
- split_di (operands, 2, low, high);
- high[2] = const0_rtx;
- low[2] = operands[2];
-
- if (!rtx_equal_p (operands[0], operands[1]))
- {
- xops[0] = high[0];
- xops[1] = low[0];
- xops[2] = high[1];
- xops[3] = low[1];
-
- if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
- {
- output_asm_insn (AS2 (mov%L1,%3,%1), xops);
- output_asm_insn (AS2 (mov%L0,%2,%0), xops);
- }
- else
- {
- xops[4] = high[2];
- xops[5] = low[2];
- xops[6] = operands[3];
- output_asm_insn (AS2 (mov%L6,%3,%6), xops);
- output_asm_insn (AS2 (add%L6,%5,%6), xops);
- output_asm_insn (AS2 (mov%L1,%6,%1), xops);
- output_asm_insn (AS2 (mov%L6,%2,%6), xops);
- output_asm_insn (AS2 (adc%L6,%4,%6), xops);
- output_asm_insn (AS2 (mov%L0,%6,%0), xops);
- RET;
- }
- }
-
- output_asm_insn (AS2 (add%L0,%2,%0), low);
- output_asm_insn (AS2 (adc%L0,%2,%0), high);
- cc_status.value1 = high[0];
- cc_status.flags = CC_NO_OVERFLOW;
- RET;
+ operands[1] = SET_SRC (PATTERN (insn));
+ return \"lea{l}\\t{%a1, %0|%0, %a1}\";
}"
- [(set_attr "type" "binary")])
+ [(set_attr "type" "lea")])
-(define_insn "addsidi3_2"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,&r,!&r,&r,o,o,!o")
- (plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,o,o,ri,ri,i,r"))
- (match_operand:DI 1 "general_operand" "0,0,0,iF,ro,roiF,riF,o,o")))
- (clobber (match_scratch:SI 3 "=X,X,X,X,X,X,X,&r,&r"))]
- ""
+(define_insn "*addsi_1"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,rm,r")
+ (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,r")
+ (match_operand:SI 2 "general_operand" "rmni,rni,rni")))
+ (clobber (reg:CC 17))]
+ "ix86_binary_operator_ok (PLUS, SImode, operands)"
"*
{
- rtx low[3], high[3], xops[7];
-
- CC_STATUS_INIT;
-
- split_di (operands, 2, low, high);
- high[2] = const0_rtx;
- low[2] = operands[2];
-
- if (!rtx_equal_p (operands[0], operands[1]))
+ switch (get_attr_type (insn))
{
- xops[0] = high[0];
- xops[1] = low[0];
- xops[2] = high[1];
- xops[3] = low[1];
+ case TYPE_LEA:
+ operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
+ return \"lea{l}\\t{%a2, %0|%0, %a2}\";
- if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
- {
- if (rtx_equal_p (low[0], operands[2]))
- {
- output_asm_insn (AS2 (mov%L0,%2,%0), high);
- output_asm_insn (AS2 (add%L0,%1,%0), low);
- output_asm_insn (AS2 (adc%L0,%1,%0), high);
- RET;
- }
- if (rtx_equal_p (high[0], operands[2]))
- {
- if (GET_CODE (operands[0]) != MEM)
- {
- output_asm_insn (AS2 (mov%L0,%2,%0), low);
- output_asm_insn (AS2 (mov%L0,%2,%0), high);
- output_asm_insn (AS2 (add%L0,%1,%0), low);
- output_asm_insn (AS2 (adc%L0,%1,%0), high);
- }
- else
- {
- /* It's too late to ask for a scratch now - but this
- will probably not happen too often. */
- output_asm_insn (AS2 (add%L1,%2,%1), low);
- output_asm_insn (AS2 (mov%L0,%1,%0), low);
- output_asm_insn (AS2 (mov%L1,%2,%1), low);
- output_asm_insn (AS2 (mov%L0,%2,%0), high);
- output_asm_insn (AS2 (adc%L0,%1,%0), high);
- output_asm_insn (AS2 (sub%L1,%0,%1), low);
- output_asm_insn (AS1 (neg%L1,%1), low);
- }
- RET;
- }
- output_asm_insn (AS2 (mov%L1,%3,%1), xops);
- output_asm_insn (AS2 (mov%L0,%2,%0), xops);
- }
+ case TYPE_INCDEC:
+ if (! rtx_equal_p (operands[0], operands[1]))
+ abort ();
+ if (operands[2] == const1_rtx)
+ return \"inc{l}\\t%0\";
+ else if (operands[2] == constm1_rtx)
+ return \"dec{l}\\t%0\";
else
- {
- xops[4] = high[2];
- xops[5] = low[2];
- xops[6] = operands[3];
- output_asm_insn (AS2 (mov%L6,%3,%6), xops);
- output_asm_insn (AS2 (add%L6,%5,%6), xops);
- output_asm_insn (AS2 (mov%L1,%6,%1), xops);
- output_asm_insn (AS2 (mov%L6,%2,%6), xops);
- output_asm_insn (AS2 (adc%L6,%4,%6), xops);
- output_asm_insn (AS2 (mov%L0,%6,%0), xops);
- RET;
- }
- }
+ abort();
- output_asm_insn (AS2 (add%L0,%2,%0), low);
- output_asm_insn (AS2 (adc%L0,%2,%0), high);
- cc_status.value1 = high[0];
- cc_status.flags = CC_NO_OVERFLOW;
- RET;
-}"
- [(set_attr "type" "binary")])
+ default:
+ if (! rtx_equal_p (operands[0], operands[1]))
+ abort ();
-(define_insn "adddi3"
- [(set (match_operand:DI 0 "general_operand" "=&r,&ro,!r,o,!&r,!o,!o")
- (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0iF,or,riF,o")
- (match_operand:DI 2 "general_operand" "o,riF,0,or,or,oriF,o")))
- (clobber (match_scratch:SI 3 "=X,X,X,&r,X,&r,&r"))]
- ""
+ /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'.
+ Exceptions: -128 encodes smaller than 128, so swap sign and op. */
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (INTVAL (operands[2]) == 128
+ || (INTVAL (operands[2]) < 0
+ && INTVAL (operands[2]) != -128)))
+ {
+ operands[2] = GEN_INT (-INTVAL (operands[2]));
+ return \"sub{l}\\t{%2, %0|%0, %2}\";
+ }
+ return \"add{l}\\t{%2, %0|%0, %2}\";
+ }
+}"
+ [(set (attr "type")
+ (cond [(eq_attr "alternative" "2")
+ (const_string "lea")
+ ; Current assemblers are broken and do not allow @GOTOFF in
+ ; ought but a memory context.
+ (match_operand:SI 2 "pic_symbolic_operand" "")
+ (const_string "lea")
+ (match_operand:SI 2 "incdec_operand" "")
+ (const_string "incdec")
+ ]
+ (const_string "alu")))])
+
+(define_insn "*addsi_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "rmni,rni"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (PLUS, SImode, operands)
+ /* Current assemblers are broken and do not allow @GOTOFF in
+ ought but a memory context. */
+ && ! pic_symbolic_operand (operands[2], VOIDmode)"
"*
{
- rtx low[3], high[3], xops[7], temp;
-
- CC_STATUS_INIT;
-
- if (rtx_equal_p (operands[0], operands[2]))
+ switch (get_attr_type (insn))
{
- temp = operands[1];
- operands[1] = operands[2];
- operands[2] = temp;
- }
-
- split_di (operands, 3, low, high);
- if (!rtx_equal_p (operands[0], operands[1]))
- {
- xops[0] = high[0];
- xops[1] = low[0];
- xops[2] = high[1];
- xops[3] = low[1];
-
- if (GET_CODE (operands[0]) != MEM)
- {
- output_asm_insn (AS2 (mov%L1,%3,%1), xops);
- output_asm_insn (AS2 (mov%L0,%2,%0), xops);
- }
+ case TYPE_INCDEC:
+ if (! rtx_equal_p (operands[0], operands[1]))
+ abort ();
+ if (operands[2] == const1_rtx)
+ return \"inc{l}\\t%0\";
+ else if (operands[2] == constm1_rtx)
+ return \"dec{l}\\t%0\";
else
- {
- xops[4] = high[2];
- xops[5] = low[2];
- xops[6] = operands[3];
- output_asm_insn (AS2 (mov%L6,%3,%6), xops);
- output_asm_insn (AS2 (add%L6,%5,%6), xops);
- output_asm_insn (AS2 (mov%L1,%6,%1), xops);
- output_asm_insn (AS2 (mov%L6,%2,%6), xops);
- output_asm_insn (AS2 (adc%L6,%4,%6), xops);
- output_asm_insn (AS2 (mov%L0,%6,%0), xops);
- RET;
- }
- }
-
- cc_status.value1 = high[0];
- cc_status.flags = CC_NO_OVERFLOW;
+ abort();
- if (GET_CODE (operands[3]) == REG && GET_CODE (operands[2]) != REG)
- {
- xops[0] = high[0];
- xops[1] = low[0];
- xops[2] = high[2];
- xops[3] = low[2];
- xops[4] = operands[3];
-
- output_asm_insn (AS2 (mov%L4,%3,%4), xops);
- output_asm_insn (AS2 (add%L1,%4,%1), xops);
- output_asm_insn (AS2 (mov%L4,%2,%4), xops);
- output_asm_insn (AS2 (adc%L0,%4,%0), xops);
- }
-
- else if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0)
- {
- output_asm_insn (AS2 (add%L0,%2,%0), low);
- output_asm_insn (AS2 (adc%L0,%2,%0), high);
+ default:
+ if (! rtx_equal_p (operands[0], operands[1]))
+ abort ();
+ /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'.
+ Exceptions: -128 encodes smaller than 128, so swap sign and op. */
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (INTVAL (operands[2]) == 128
+ || (INTVAL (operands[2]) < 0
+ && INTVAL (operands[2]) != -128)))
+ {
+ operands[2] = GEN_INT (-INTVAL (operands[2]));
+ return \"sub{l}\\t{%2, %0|%0, %2}\";
+ }
+ return \"add{l}\\t{%2, %0|%0, %2}\";
}
-
- else
- output_asm_insn (AS2 (add%L0,%2,%0), high);
-
- RET;
}"
- [(set_attr "type" "binary")])
-
-;; On a 486, it is faster to do movl/addl than to do a single leal if
-;; operands[1] and operands[2] are both registers.
-
-(define_expand "addsi3"
- [(set (match_operand:SI 0 "nonimmediate_operand" "")
- (plus:SI (match_operand:SI 1 "nonimmediate_operand" "")
- (match_operand:SI 2 "general_operand" "")))]
+ [(set (attr "type")
+ (if_then_else (match_operand:SI 2 "incdec_operand" "")
+ (const_string "incdec")
+ (const_string "alu")))])
+
+(define_insn "*addsi_3"
+ [(set (reg:CC 17)
+ (compare:CC (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "rmni,rni"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (PLUS, SImode, operands)
+ /* Current assemblers are broken and do not allow @GOTOFF in
+ ought but a memory context. */
+ && ! pic_symbolic_operand (operands[2], VOIDmode)"
+ "add{l}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+;; %%% Conditionally split these post-reload for better scheduling.
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "%r"))
+ (match_operand:SI 3 "immediate_operand" "i")))]
""
- "IX86_EXPAND_BINARY_OPERATOR (PLUS, SImode, operands);")
+ "*
+{
+ operands[1] = SET_SRC (PATTERN (insn));
+ return \"lea{l}\\t{%a1, %0|%0, %a1}\";
+}"
+ [(set_attr "type" "lea")])
(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,rm,r")
- (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,r")
- (match_operand:SI 2 "general_operand" "rmi,ri,ri")))]
- "ix86_binary_operator_ok (PLUS, SImode, operands)"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (mult:SI (match_operand:SI 1 "reg_no_sp_operand" "r")
+ (match_operand:SI 2 "const248_operand" "I"))
+ (match_operand:SI 3 "nonmemory_operand" "ir")))]
+ ""
"*
{
- if (REG_P (operands[0]) && REG_P (operands[1])
- && (REG_P (operands[2]) || CONSTANT_P (operands[2]))
- && REGNO (operands[0]) != REGNO (operands[1]))
- {
- if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2]))
- return AS2 (add%L0,%1,%0);
-
- if (operands[2] == stack_pointer_rtx)
- {
- rtx temp;
-
- temp = operands[1];
- operands[1] = operands[2];
- operands[2] = temp;
- }
-
- if (operands[2] != stack_pointer_rtx)
- {
- CC_STATUS_INIT;
- operands[1] = SET_SRC (PATTERN (insn));
- return AS2 (lea%L0,%a1,%0);
- }
- }
-
- if (!rtx_equal_p (operands[0], operands[1]))
- output_asm_insn (AS2 (mov%L0,%1,%0), operands);
-
- if (operands[2] == const1_rtx)
- return AS1 (inc%L0,%0);
-
- if (operands[2] == constm1_rtx)
- return AS1 (dec%L0,%0);
-
- /* subl $-128,%ebx is smaller than addl $128,%ebx. */
- if (GET_CODE (operands[2]) == CONST_INT
- && INTVAL (operands[2]) == 128)
- {
- /* This doesn't compute the carry bit in the same way
- * as add%L0, but we use inc and dec above and they
- * don't set the carry bit at all. If inc/dec don't need
- * a CC_STATUS_INIT, this doesn't either... */
- operands[2] = GEN_INT (-128);
- return AS2 (sub%L0,%2,%0);
- }
-
- return AS2 (add%L0,%2,%0);
+ operands[1] = SET_SRC (PATTERN (insn));
+ return \"lea{l}\\t{%a1, %0|%0, %a1}\";
}"
- [(set_attr "type" "binary")])
-
-;; addsi3 is faster, so put this after.
+ [(set_attr "type" "lea")])
-(define_insn "movsi_lea"
+(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
- (match_operand:QI 1 "address_operand" "p"))]
+ (plus:SI (plus:SI (mult:SI (match_operand:SI 1 "reg_no_sp_operand" "r")
+ (match_operand:SI 2 "const248_operand" "I"))
+ (match_operand 3 "register_operand" "%r"))
+ (match_operand:SI 4 "immediate_operand" "i")))]
""
"*
{
- /* Adding a constant to a register is faster with an add. */
- /* ??? can this ever happen? */
- if (GET_CODE (operands[1]) == PLUS
- && GET_CODE (XEXP (operands[1], 1)) == CONST_INT
- && rtx_equal_p (operands[0], XEXP (operands[1], 0)))
- {
- operands[1] = XEXP (operands[1], 1);
-
- if (operands[1] == const1_rtx)
- return AS1 (inc%L0,%0);
-
- if (operands[1] == constm1_rtx)
- return AS1 (dec%L0,%0);
-
- return AS2 (add%L0,%1,%0);
- }
-
- CC_STATUS_INIT;
- return AS2 (lea%L0,%a1,%0);
+ operands[1] = SET_SRC (PATTERN (insn));
+ return \"lea{l}\\t{%a1, %0|%0, %a1}\";
}"
[(set_attr "type" "lea")])
-;; ??? `lea' here, for three operand add? If leaw is used, only %bx,
-;; %si and %di can appear in SET_SRC, and output_asm_insn might not be
-;; able to handle the operand. But leal always works?
-
(define_expand "addhi3"
- [(set (match_operand:HI 0 "general_operand" "")
- (plus:HI (match_operand:HI 1 "nonimmediate_operand" "")
- (match_operand:HI 2 "general_operand" "")))]
+ [(parallel [(set (match_operand:HI 0 "general_operand" "")
+ (plus:HI (match_operand:HI 1 "nonimmediate_operand" "")
+ (match_operand:HI 2 "general_operand" "")))
+ (clobber (reg:CC 17))])]
""
- "IX86_EXPAND_BINARY_OPERATOR (PLUS, HImode, operands);")
+ "ix86_expand_binary_operator (PLUS, HImode, operands); DONE;")
-(define_insn ""
- [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r,?r")
- (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,r")
- (match_operand:HI 2 "general_operand" "ri,rm,ri")))]
+;; %%% After Dave's SUBREG_BYTE stuff goes in, re-enable incb %ah
+;; type optimizations enabled by define-splits. This is not important
+;; for PII, and in fact harmful because of partial register stalls.
+
+(define_insn "*addhi_1"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+ (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "ri,rm")))
+ (clobber (reg:CC 17))]
"ix86_binary_operator_ok (PLUS, HImode, operands)"
"*
{
- if (REG_P (operands[0]) && REG_P (operands[1])
- && (REG_P (operands[2]) || CONSTANT_P (operands[2]))
- && REGNO (operands[0]) != REGNO (operands[1]))
+ switch (get_attr_type (insn))
{
- if (operands[2] == stack_pointer_rtx)
- abort ();
+ case TYPE_INCDEC:
+ if (operands[2] == const1_rtx)
+ return \"inc{w}\\t%0\";
+ else if (operands[2] == constm1_rtx
+ || (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == 65535))
+ return \"dec{w}\\t%0\";
+ abort();
- CC_STATUS_INIT;
- operands[1]
- = gen_rtx_PLUS (SImode,
- gen_rtx_REG (SImode, REGNO (operands[1])),
- (! REG_P (operands[2])
- ? operands[2]
- : gen_rtx_REG (SImode, REGNO (operands[2]))));
- operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
- return AS2 (lea%L0,%a1,%0);
+ default:
+ /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'.
+ Exceptions: -128 encodes smaller than 128, so swap sign and op. */
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (INTVAL (operands[2]) == 128
+ || (INTVAL (operands[2]) < 0
+ && INTVAL (operands[2]) != -128)))
+ {
+ operands[2] = GEN_INT (-INTVAL (operands[2]));
+ return \"sub{w}\\t{%2, %0|%0, %2}\";
+ }
+ return \"add{w}\\t{%2, %0|%0, %2}\";
}
+}"
+ [(set (attr "type")
+ (if_then_else (match_operand:HI 2 "incdec_operand" "")
+ (const_string "incdec")
+ (const_string "alu")))])
- /* ??? what about offsettable memory references? */
- if (!TARGET_PENTIUMPRO /* partial stalls are just too painful to risk. */
- && QI_REG_P (operands[0])
- && GET_CODE (operands[2]) == CONST_INT
- && (INTVAL (operands[2]) & 0xff) == 0
- && i386_cc_probably_useless_p (insn))
+;; If we know we're not touching memory, promote HImode references to SImode.
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "")
+ (plus:HI (match_operand:HI 1 "register_operand" "")
+ (match_operand:HI 2 "nonmemory_operand" "")))
+ (clobber (reg:CC 17))]
+ "! TARGET_PARTIAL_REG_STALL && reload_completed"
+ [(parallel [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC 17))])]
+ "operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_lowpart (SImode, operands[2]);")
+
+(define_insn "*addhi_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "rmni,rni"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm")
+ (plus:HI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (PLUS, HImode, operands)"
+ "*
+{
+ switch (get_attr_type (insn))
{
- int byteval = (INTVAL (operands[2]) >> 8) & 0xff;
- CC_STATUS_INIT;
-
- if (byteval == 1)
- return AS1 (inc%B0,%h0);
- else if (byteval == 255)
- return AS1 (dec%B0,%h0);
+ case TYPE_INCDEC:
+ if (operands[2] == const1_rtx)
+ return \"inc{w}\\t%0\";
+ else if (operands[2] == constm1_rtx
+ || (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == 65535))
+ return \"dec{w}\\t%0\";
+ abort();
- operands[2] = GEN_INT (byteval);
- return AS2 (add%B0,%2,%h0);
+ default:
+ /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'.
+ Exceptions: -128 encodes smaller than 128, so swap sign and op. */
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (INTVAL (operands[2]) == 128
+ || (INTVAL (operands[2]) < 0
+ && INTVAL (operands[2]) != -128)))
+ {
+ operands[2] = GEN_INT (-INTVAL (operands[2]));
+ return \"sub{w}\\t{%2, %0|%0, %2}\";
+ }
+ return \"add{w}\\t{%2, %0|%0, %2}\";
}
+}"
+ [(set (attr "type")
+ (if_then_else (match_operand:HI 2 "incdec_operand" "")
+ (const_string "incdec")
+ (const_string "alu")))])
+
+(define_insn "*addhi_3"
+ [(set (reg:CC 17)
+ (compare:CC (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "rmni,rni"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm")
+ (plus:HI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (PLUS, HImode, operands)"
+ "add{w}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
- /* Use a 32-bit operation when possible, to avoid the prefix penalty. */
- if (REG_P (operands[0])
- && i386_aligned_p (operands[2])
- && i386_cc_probably_useless_p (insn))
+(define_expand "addqi3"
+ [(parallel [(set (match_operand:QI 0 "general_operand" "")
+ (plus:QI (match_operand:QI 1 "general_operand" "")
+ (match_operand:QI 2 "general_operand" "")))
+ (clobber (reg:CC 17))])]
+ ""
+ "ix86_expand_binary_operator (PLUS, QImode, operands); DONE;")
+
+;; %%% Potential partial reg stall on alternative 2. What to do?
+(define_insn "*addqi_1"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,*r")
+ (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
+ (match_operand:QI 2 "general_operand" "qn,qmn,*rn")))
+ (clobber (reg:CC 17))]
+ "ix86_binary_operator_ok (PLUS, QImode, operands)"
+ "*
+{
+ int widen = (which_alternative == 2);
+ switch (get_attr_type (insn))
{
- CC_STATUS_INIT;
+ case TYPE_INCDEC:
+ if (operands[2] == const1_rtx)
+ return widen ? \"inc{l}\\t%k0\" : \"inc{b}\\t%0\";
+ else if (operands[2] == constm1_rtx
+ || (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == 255))
+ return widen ? \"dec{l}\\t%k0\" : \"dec{b}\\t%0\";
+ abort();
- if (GET_CODE (operands[2]) == CONST_INT)
+ default:
+ /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'.
+ Exceptions: -128 encodes smaller than 128, so swap sign and op. */
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (INTVAL (operands[2]) == 128
+ || (INTVAL (operands[2]) < 0
+ && INTVAL (operands[2]) != -128)))
{
- HOST_WIDE_INT intval = 0xffff & INTVAL (operands[2]);
-
- if (intval == 1)
- return AS1 (inc%L0,%k0);
-
- if (intval == 0xffff)
- return AS1 (dec%L0,%k0);
-
- operands[2] = i386_sext16_if_const (operands[2]);
+ operands[2] = GEN_INT (-INTVAL (operands[2]));
+ if (widen)
+ return \"sub{l}\\t{%2, %k0|%k0, %2}\";
+ else
+ return \"sub{b}\\t{%2, %0|%0, %2}\";
}
- return AS2 (add%L0,%k2,%k0);
+ if (widen)
+ return \"add{l}\\t{%k2, %k0|%k0, %k2}\";
+ else
+ return \"add{b}\\t{%2, %0|%0, %2}\";
}
+}"
+ [(set (attr "type")
+ (if_then_else (match_operand:QI 2 "incdec_operand" "")
+ (const_string "incdec")
+ (const_string "alu")))])
+
+(define_insn "*addqi_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:QI 2 "general_operand" "qmni,qni"))
+ (const_int 0)))
+ (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm")
+ (plus:QI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (PLUS, QImode, operands)"
+ "*
+{
+ switch (get_attr_type (insn))
+ {
+ case TYPE_INCDEC:
+ if (operands[2] == const1_rtx)
+ return \"inc{b}\\t%0\";
+ else if (operands[2] == constm1_rtx
+ || (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == 255))
+ return \"dec{b}\\t%0\";
+ abort();
- if (operands[2] == const1_rtx)
- return AS1 (inc%W0,%0);
-
- if (operands[2] == constm1_rtx
- || (GET_CODE (operands[2]) == CONST_INT
- && INTVAL (operands[2]) == 65535))
- return AS1 (dec%W0,%0);
-
- return AS2 (add%W0,%2,%0);
+ default:
+ /* Make things pretty and `subb $4,%al' rather than `addb $-4, %al'. */
+ if (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) < 0)
+ {
+ operands[2] = GEN_INT (-INTVAL (operands[2]));
+ return \"sub{b}\\t{%2, %0|%0, %2}\";
+ }
+ return \"add{b}\\t{%2, %0|%0, %2}\";
+ }
}"
- [(set_attr "type" "binary")])
+ [(set (attr "type")
+ (if_then_else (match_operand:QI 2 "incdec_operand" "")
+ (const_string "incdec")
+ (const_string "alu")))])
+
+(define_insn "*addqi_3"
+ [(set (reg:CC 17)
+ (compare:CC (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:QI 2 "general_operand" "qmni,qni"))
+ (const_int 0)))
+ (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm")
+ (plus:QI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (PLUS, QImode, operands)"
+ "add{b}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
-(define_expand "addqi3"
- [(set (match_operand:QI 0 "general_operand" "")
- (plus:QI (match_operand:QI 1 "general_operand" "")
- (match_operand:QI 2 "general_operand" "")))]
+(define_insn "*addqi_low_1"
+ [(set (strict_low_part (match_operand:QI 0 "register_operand" "q"))
+ (plus:QI (match_operand:QI 1 "register_operand" "0")
+ (match_operand:QI 2 "general_operand" "qmn")))
+ (clobber (reg:CC 17))]
""
- "IX86_EXPAND_BINARY_OPERATOR (PLUS, QImode, operands);")
-
-(define_insn ""
- [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,?q")
- (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,q")
- (match_operand:QI 2 "general_operand" "qn,qmn,qn")))]
- "ix86_binary_operator_ok (PLUS, QImode, operands)"
"*
{
- if (REG_P (operands[0]) && REG_P (operands[1])
- && (REG_P (operands[2]) || CONSTANT_P (operands[2]))
- && (REGNO (operands[0]) != REGNO (operands[1])
- || NON_QI_REG_P (operands[1])
- || (REG_P (operands[2]) && NON_QI_REG_P (operands[2]))))
+ switch (get_attr_type (insn))
{
- if (operands[2] == stack_pointer_rtx)
- abort ();
+ case TYPE_INCDEC:
+ if (operands[2] == const1_rtx)
+ return \"inc{b}\\t%b0\";
+ else if (operands[2] == constm1_rtx
+ || (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == 255))
+ return \"dec{b}\\t%b0\";
+ abort();
- CC_STATUS_INIT;
- operands[1]
- = gen_rtx_PLUS (SImode,
- gen_rtx_REG (SImode, REGNO (operands[1])),
- (! REG_P (operands[2])
- ? operands[2]
- : gen_rtx_REG (SImode, REGNO (operands[2]))));
- operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
- return AS2 (lea%L0,%a1,%0);
+ default:
+ return \"add{b}\\t{%2, %b0|%b0, %2}\";
}
- if (operands[2] == const1_rtx)
- return AS1 (inc%B0,%0);
-
- if (operands[2] == constm1_rtx
- || (GET_CODE (operands[2]) == CONST_INT
- && INTVAL (operands[2]) == 255))
- return AS1 (dec%B0,%0);
+}"
+ [(set (attr "type")
+ (if_then_else (match_operand:QI 2 "incdec_operand" "")
+ (const_string "incdec")
+ (const_string "alu")))])
+
+(define_insn "addqi_ext_1"
+ [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q")
+ (const_int 8)
+ (const_int 8))
+ (plus:SI
+ (zero_extract:SI
+ (match_operand 1 "ext_register_operand" "0")
+ (const_int 8)
+ (const_int 8))
+ (match_operand:QI 2 "general_operand" "qmn")))
+ (clobber (reg:CC 17))]
+ ""
+ "*
+{
+ switch (get_attr_type (insn))
+ {
+ case TYPE_INCDEC:
+ if (operands[2] == const1_rtx)
+ return \"inc{b}\\t%h0\";
+ else if (operands[2] == constm1_rtx
+ || (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == 255))
+ return \"dec{b}\\t%h0\";
+ abort();
- return AS2 (add%B0,%2,%0);
+ default:
+ return \"add{b}\\t{%2, %h0|%h0, %2}\";
+ }
}"
- [(set_attr "type" "binary")])
-
-;Lennart Augustsson <augustss@cs.chalmers.se>
-;says this pattern just makes slower code:
-; pushl %ebp
-; addl $-80,(%esp)
-;instead of
-; leal -80(%ebp),%eax
-; pushl %eax
-;
-;(define_insn ""
-; [(set (match_operand:SI 0 "push_operand" "=<")
-; (plus:SI (match_operand:SI 1 "register_operand" "%r")
-; (match_operand:SI 2 "nonmemory_operand" "ri")))]
-; ""
-; "*
-;{
-; rtx xops[4];
-; xops[0] = operands[0];
-; xops[1] = operands[1];
-; xops[2] = operands[2];
-; xops[3] = gen_rtx_MEM (SImode, stack_pointer_rtx);
-; output_asm_insn (\"push%z1 %1\", xops);
-; output_asm_insn (AS2 (add%z3,%2,%3), xops);
-; RET;
-;}")
+ [(set (attr "type")
+ (if_then_else (match_operand:QI 2 "incdec_operand" "")
+ (const_string "incdec")
+ (const_string "alu")))])
+
+(define_insn "*addqi_ext_2"
+ [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q")
+ (const_int 8)
+ (const_int 8))
+ (plus:SI
+ (zero_extract:SI
+ (match_operand 1 "ext_register_operand" "%0")
+ (const_int 8)
+ (const_int 8))
+ (zero_extract:SI
+ (match_operand 2 "ext_register_operand" "q")
+ (const_int 8)
+ (const_int 8))))
+ (clobber (reg:CC 17))]
+ ""
+ "add{b}\\t{%h2, %h0|%h0, %h2}"
+ [(set_attr "type" "alu")])
;; The patterns that match these are at the end of this file.
@@ -3734,187 +3471,179 @@
"TARGET_80387"
"")
-;;- subtract instructions
+;; Subtract instructions
-(define_insn "subsidi3"
- [(set (match_operand:DI 0 "general_operand" "=&r,&ro,&r,!&r,o,o,!o")
- (minus:DI (match_operand:DI 1 "general_operand" "0iF,0,roiF,roiF,riF,o,o")
- (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,o,ri,i,r"))))
- (clobber (match_scratch:SI 3 "=X,X,X,X,X,&r,&r"))]
- ""
- "*
-{
- rtx low[3], high[3], xops[7];
-
- CC_STATUS_INIT;
-
- split_di (operands, 2, low, high);
- high[2] = const0_rtx;
- low[2] = operands[2];
-
- if (!rtx_equal_p (operands[0], operands[1]))
- {
- xops[0] = high[0];
- xops[1] = low[0];
- xops[2] = high[1];
- xops[3] = low[1];
-
- if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
- {
- output_asm_insn (AS2 (mov%L1,%3,%1), xops);
- output_asm_insn (AS2 (mov%L0,%2,%0), xops);
- }
- else
- {
- xops[4] = high[2];
- xops[5] = low[2];
- xops[6] = operands[3];
- output_asm_insn (AS2 (mov%L6,%3,%6), xops);
- output_asm_insn (AS2 (sub%L6,%5,%6), xops);
- output_asm_insn (AS2 (mov%L1,%6,%1), xops);
- output_asm_insn (AS2 (mov%L6,%2,%6), xops);
- output_asm_insn (AS2 (sbb%L6,%4,%6), xops);
- output_asm_insn (AS2 (mov%L0,%6,%0), xops);
- RET;
- }
- }
-
- output_asm_insn (AS2 (sub%L0,%2,%0), low);
- output_asm_insn (AS2 (sbb%L0,%2,%0), high);
- cc_status.value1 = high[0];
- cc_status.flags = CC_NO_OVERFLOW;
-
- RET;
-}"
- [(set_attr "type" "binary")])
+;; %%% define_expand from the very first?
+;; %%% splits for subsidi3
(define_insn "subdi3"
- [(set (match_operand:DI 0 "general_operand" "=&r,&ro,o,o,!&r,!o")
- (minus:DI (match_operand:DI 1 "general_operand" "0,0,0iF,or,roiF,roiF")
- (match_operand:DI 2 "general_operand" "or,riF,or,iF,roiF,roiF")))
- (clobber (match_scratch:SI 3 "=X,X,&r,&r,X,&r"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o")
+ (minus:DI (match_operand:DI 1 "general_operand" "0,0")
+ (match_operand:DI 2 "general_operand" "roiF,riF")))
+ (clobber (reg:CC 17))]
""
- "*
-{
- rtx low[3], high[3], xops[7];
-
- CC_STATUS_INIT;
-
- split_di (operands, 3, low, high);
-
- if (!rtx_equal_p (operands[0], operands[1]))
- {
- xops[0] = high[0];
- xops[1] = low[0];
- xops[2] = high[1];
- xops[3] = low[1];
-
- if (GET_CODE (operands[0]) != MEM)
- {
- output_asm_insn (AS2 (mov%L1,%3,%1), xops);
- output_asm_insn (AS2 (mov%L0,%2,%0), xops);
- }
- else
- {
- xops[4] = high[2];
- xops[5] = low[2];
- xops[6] = operands[3];
- output_asm_insn (AS2 (mov%L6,%3,%6), xops);
- output_asm_insn (AS2 (sub%L6,%5,%6), xops);
- output_asm_insn (AS2 (mov%L1,%6,%1), xops);
- output_asm_insn (AS2 (mov%L6,%2,%6), xops);
- output_asm_insn (AS2 (sbb%L6,%4,%6), xops);
- output_asm_insn (AS2 (mov%L0,%6,%0), xops);
- RET;
- }
- }
-
- cc_status.value1 = high[0];
- cc_status.flags = CC_NO_OVERFLOW;
-
- if (GET_CODE (operands[3]) == REG)
- {
- xops[0] = high[0];
- xops[1] = low[0];
- xops[2] = high[2];
- xops[3] = low[2];
- xops[4] = operands[3];
-
- output_asm_insn (AS2 (mov%L4,%3,%4), xops);
- output_asm_insn (AS2 (sub%L1,%4,%1), xops);
- output_asm_insn (AS2 (mov%L4,%2,%4), xops);
- output_asm_insn (AS2 (sbb%L0,%4,%0), xops);
- }
-
- else if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0)
- {
- output_asm_insn (AS2 (sub%L0,%2,%0), low);
- output_asm_insn (AS2 (sbb%L0,%2,%0), high);
- }
-
- else
- output_asm_insn (AS2 (sub%L0,%2,%0), high);
-
+ "#")
- RET;
-}"
- [(set_attr "type" "binary")])
+(define_split
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (minus:DI (match_operand:DI 1 "general_operand" "")
+ (match_operand:DI 2 "general_operand" "")))
+ (clobber (reg:CC 17))]
+ "cse_not_expected"
+ [(parallel [(set (reg:CC 17) (minus:CC (match_dup 1) (match_dup 2)))
+ (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2)))])
+ (parallel [(set (match_dup 3)
+ (minus:SI (match_dup 4)
+ (plus:SI (match_dup 5)
+ (ltu:SI (reg:CC 17) (const_int 0)))))
+ (clobber (reg:CC 17))])]
+ "split_di (operands+0, 1, operands+0, operands+3);
+ split_di (operands+1, 1, operands+1, operands+4);
+ split_di (operands+2, 1, operands+2, operands+5);")
+
+(define_insn "subcsi3"
+ [(set (reg:CC 17) (minus:CC (match_operand:SI 1 "nonimmediate_operand" "0,0")
+ (match_operand:SI 2 "general_operand" "ri,rm")))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "sub{l}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "subxsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+ (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+ (plus:SI (match_operand:SI 2 "general_operand" "ri,rm")
+ (ltu:SI (reg:CC 17) (const_int 0)))))
+ (clobber (reg:CC 17))]
+ ""
+ "sbb{l}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")
+ (set_attr "pent_pair" "pu")
+ (set_attr "ppro_uops" "few")])
(define_expand "subsi3"
- [(set (match_operand:SI 0 "nonimmediate_operand" "")
- (minus:SI (match_operand:SI 1 "nonimmediate_operand" "")
- (match_operand:SI 2 "general_operand" "")))]
+ [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (minus:SI (match_operand:SI 1 "nonimmediate_operand" "")
+ (match_operand:SI 2 "general_operand" "")))
+ (clobber (reg:CC 17))])]
""
- "IX86_EXPAND_BINARY_OPERATOR (MINUS, SImode, operands);")
+ "ix86_expand_binary_operator (MINUS, SImode, operands); DONE;")
-(define_insn ""
+(define_insn "*subsi_1"
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
(minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
- (match_operand:SI 2 "general_operand" "ri,rm")))]
+ (match_operand:SI 2 "general_operand" "ri,rm")))
+ (clobber (reg:CC 17))]
+ "ix86_binary_operator_ok (MINUS, SImode, operands)"
+ "sub{l}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "*subsi_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+ (match_operand:SI 2 "general_operand" "ri,rm"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
"ix86_binary_operator_ok (MINUS, SImode, operands)"
- "* return AS2 (sub%L0,%2,%0);"
- [(set_attr "type" "binary")])
+ "sub{l}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "*subsi_3"
+ [(set (reg:CC 17)
+ (compare:CC
+ (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+ (match_operand:SI 2 "general_operand" "ri,rm"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (MINUS, SImode, operands)"
+ "sub{l}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
(define_expand "subhi3"
- [(set (match_operand:HI 0 "general_operand" "")
- (minus:HI (match_operand:HI 1 "nonimmediate_operand" "")
- (match_operand:HI 2 "general_operand" "")))]
+ [(parallel [(set (match_operand:HI 0 "general_operand" "")
+ (minus:HI (match_operand:HI 1 "nonimmediate_operand" "")
+ (match_operand:HI 2 "general_operand" "")))
+ (clobber (reg:CC 17))])]
""
- "IX86_EXPAND_BINARY_OPERATOR (MINUS, HImode, operands);")
+ "ix86_expand_binary_operator (MINUS, HImode, operands); DONE;")
-(define_insn ""
+(define_insn "*subhi_1"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
(minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
- (match_operand:HI 2 "general_operand" "ri,rm")))]
+ (match_operand:HI 2 "general_operand" "ri,rm")))
+ (clobber (reg:CC 17))]
"ix86_binary_operator_ok (MINUS, HImode, operands)"
- "*
-{
- if (REG_P (operands[0])
- && i386_aligned_p (operands[2])
- && i386_cc_probably_useless_p (insn))
- {
- CC_STATUS_INIT;
- operands[2] = i386_sext16_if_const (operands[2]);
- return AS2 (sub%L0,%k2,%k0);
- }
- return AS2 (sub%W0,%2,%0);
-}"
- [(set_attr "type" "binary")])
+ "sub{w}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "*subhi_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
+ (match_operand:HI 2 "general_operand" "ri,rm"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+ (minus:HI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (MINUS, HImode, operands)"
+ "sub{w}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "*subhi_3"
+ [(set (reg:CC 17)
+ (compare:CC
+ (minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
+ (match_operand:HI 2 "general_operand" "ri,rm"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+ (minus:HI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (MINUS, HImode, operands)"
+ "sub{w}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
(define_expand "subqi3"
- [(set (match_operand:QI 0 "general_operand" "")
- (minus:QI (match_operand:QI 1 "general_operand" "")
- (match_operand:QI 2 "general_operand" "")))]
+ [(parallel [(set (match_operand:QI 0 "general_operand" "")
+ (minus:QI (match_operand:QI 1 "general_operand" "")
+ (match_operand:QI 2 "general_operand" "")))
+ (clobber (reg:CC 17))])]
""
- "IX86_EXPAND_BINARY_OPERATOR (MINUS, QImode, operands);")
+ "ix86_expand_binary_operator (MINUS, QImode, operands); DONE;")
-(define_insn ""
+(define_insn "*subqi_1"
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
(minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
- (match_operand:QI 2 "general_operand" "qn,qmn")))]
+ (match_operand:QI 2 "general_operand" "qn,qmn")))
+ (clobber (reg:CC 17))]
+ "ix86_binary_operator_ok (MINUS, QImode, operands)"
+ "sub{b}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "*subqi_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "general_operand" "qi,qm"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=qm,q")
+ (minus:HI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (MINUS, QImode, operands)"
+ "sub{b}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "*subqi_3"
+ [(set (reg:CC 17)
+ (compare:CC
+ (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "general_operand" "qi,qm"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=qm,q")
+ (minus:HI (match_dup 1) (match_dup 2)))]
"ix86_binary_operator_ok (MINUS, QImode, operands)"
- "* return AS2 (sub%B0,%2,%0);"
- [(set_attr "type" "binary")])
+ "sub{b}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
;; The patterns that match these are at the end of this file.
@@ -3939,98 +3668,104 @@
"TARGET_80387"
"")
-;;- multiply instructions
+;; Multiply instructions
-;(define_insn "mulqi3"
-; [(set (match_operand:QI 0 "register_operand" "=a")
-; (mult:QI (match_operand:QI 1 "register_operand" "%0")
-; (match_operand:QI 2 "nonimmediate_operand" "qm")))]
-; ""
-; "imul%B0 %2,%0")
+(define_insn "mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%rm,0,0")
+ (match_operand:SI 2 "general_operand" "K,i,mr")))
+ (clobber (reg:CC 17))]
+ ""
+ ; %%% There was a note about "Assembler has weird restrictions",
+ ; concerning alternative 1 when op1 == op0. True?
+ "@
+ imul{l}\\t{%2, %1, %0|%0, %1, %2}
+ imul{l}\\t{%2, %0|%0, %2}
+ imul{l}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "imul")
+ (set_attr "length" "2,3,2")])
(define_insn "mulhi3"
[(set (match_operand:HI 0 "register_operand" "=r,r")
- (mult:HI (match_operand:HI 1 "nonimmediate_operand" "%0,rm")
- (match_operand:HI 2 "general_operand" "g,i")))]
- ""
- "*
-{
- if (GET_CODE (operands[1]) == REG
- && REGNO (operands[1]) == REGNO (operands[0])
- && (GET_CODE (operands[2]) == MEM || GET_CODE (operands[2]) == REG))
- /* Assembler has weird restrictions. */
- return AS2 (imul%W0,%2,%0);
- return AS3 (imul%W0,%2,%1,%0);
-}"
- [(set_attr "type" "imul")])
-
-(define_insn "mulsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,r")
- (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%0,rm")
- (match_operand:SI 2 "general_operand" "g,i")))]
+ (mult:HI (match_operand:HI 1 "nonimmediate_operand" "%rm,0")
+ (match_operand:HI 2 "general_operand" "K,g")))
+ (clobber (reg:CC 17))]
""
- "*
-{
- if (GET_CODE (operands[1]) == REG
- && REGNO (operands[1]) == REGNO (operands[0])
- && (GET_CODE (operands[2]) == MEM || GET_CODE (operands[2]) == REG))
- /* Assembler has weird restrictions. */
- return AS2 (imul%L0,%2,%0);
- return AS3 (imul%L0,%2,%1,%0);
-}"
+ ; %%% There was a note about "Assembler has weird restrictions",
+ ; concerning alternative 1 when op1 == op0. True?
+ "@
+ imul{w}\\t{%2, %1, %0|%0, %1, %2}
+ imul{w}\\t{%2, %0|%0, %2}"
[(set_attr "type" "imul")])
(define_insn "umulqihi3"
[(set (match_operand:HI 0 "register_operand" "=a")
(mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "%0"))
- (zero_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))]
+ (zero_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))
+ (clobber (reg:CC 17))]
""
- "mul%B0 %2"
+ "mul{b}\\t%2"
[(set_attr "type" "imul")])
(define_insn "mulqihi3"
[(set (match_operand:HI 0 "register_operand" "=a")
(mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "%0"))
- (sign_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))]
+ (sign_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))
+ (clobber (reg:CC 17))]
""
- "imul%B0 %2"
+ "imul{b}\\t%2"
[(set_attr "type" "imul")])
(define_insn "umulsidi3"
[(set (match_operand:DI 0 "register_operand" "=A")
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0"))
- (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))]
- "TARGET_WIDE_MULTIPLY"
- "mul%L0 %2"
- [(set_attr "type" "imul")])
+ (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))
+ (clobber (reg:CC 17))]
+ ""
+ "mul{l}\\t%2"
+ [(set_attr "type" "imul")
+ (set_attr "ppro_uops" "few")])
(define_insn "mulsidi3"
[(set (match_operand:DI 0 "register_operand" "=A")
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0"))
- (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))]
- "TARGET_WIDE_MULTIPLY"
- "imul%L0 %2"
+ (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))
+ (clobber (reg:CC 17))]
+ ""
+ "imul{l}\\t%2"
[(set_attr "type" "imul")])
(define_insn "umulsi3_highpart"
[(set (match_operand:SI 0 "register_operand" "=d")
- (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%a"))
- (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm")))
- (const_int 32))))
- (clobber (match_scratch:SI 3 "=a"))]
- "TARGET_WIDE_MULTIPLY"
- "mul%L0 %2"
- [(set_attr "type" "imul")])
+ (truncate:SI
+ (lshiftrt:DI
+ (mult:DI (zero_extend:DI
+ (match_operand:SI 1 "register_operand" "%a"))
+ (zero_extend:DI
+ (match_operand:SI 2 "nonimmediate_operand" "rm")))
+ (const_int 32))))
+ (clobber (match_scratch:SI 3 "=a"))
+ (clobber (reg:CC 17))]
+ ""
+ "mul{l}\\t%2"
+ [(set_attr "type" "imul")
+ (set_attr "ppro_uops" "few")])
(define_insn "smulsi3_highpart"
[(set (match_operand:SI 0 "register_operand" "=d")
- (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%a"))
- (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm")))
- (const_int 32))))
- (clobber (match_scratch:SI 3 "=a"))]
- "TARGET_WIDE_MULTIPLY"
- "imul%L0 %2"
- [(set_attr "type" "imul")])
+ (truncate:SI
+ (lshiftrt:DI
+ (mult:DI (sign_extend:DI
+ (match_operand:SI 1 "register_operand" "%a"))
+ (sign_extend:DI
+ (match_operand:SI 2 "nonimmediate_operand" "rm")))
+ (const_int 32))))
+ (clobber (match_scratch:SI 3 "=a"))
+ (clobber (reg:CC 17))]
+ ""
+ "imul{l}\\t%2"
+ [(set_attr "type" "imul")
+ (set_attr "ppro_uops" "few")])
;; The patterns that match these are at the end of this file.
@@ -4055,22 +3790,27 @@
"TARGET_80387"
"")
-;;- divide instructions
+;; Divide instructions
(define_insn "divqi3"
[(set (match_operand:QI 0 "register_operand" "=a")
(div:QI (match_operand:HI 1 "register_operand" "0")
- (match_operand:QI 2 "nonimmediate_operand" "qm")))]
+ (match_operand:QI 2 "nonimmediate_operand" "qm")))
+ (clobber (reg:CC 17))]
""
- "idiv%B0 %2")
+ "idiv{b}\\t%2"
+ [(set_attr "type" "idiv")
+ (set_attr "ppro_uops" "few")])
(define_insn "udivqi3"
[(set (match_operand:QI 0 "register_operand" "=a")
(udiv:QI (match_operand:HI 1 "register_operand" "0")
- (match_operand:QI 2 "nonimmediate_operand" "qm")))]
+ (match_operand:QI 2 "nonimmediate_operand" "qm")))
+ (clobber (reg:CC 17))]
""
- "div%B0 %2"
- [(set_attr "type" "idiv")])
+ "div{b}\\t%2"
+ [(set_attr "type" "idiv")
+ (set_attr "ppro_uops" "few")])
;; The patterns that match these are at the end of this file.
@@ -4099,837 +3839,979 @@
(define_insn "divmodsi4"
[(set (match_operand:SI 0 "register_operand" "=a")
- (div:SI (match_operand:SI 1 "register_operand" "0")
+ (div:SI (match_operand:SI 1 "register_operand" "A")
(match_operand:SI 2 "nonimmediate_operand" "rm")))
(set (match_operand:SI 3 "register_operand" "=&d")
- (mod:SI (match_dup 1) (match_dup 2)))]
+ (mod:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC 17))]
""
- "*
+ "{cltd|cdq}\;idiv{l}\\t%2"
+ [(set_attr "type" "multi")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=a")
+ (div:SI (match_operand:SI 1 "register_operand" "A")
+ (match_operand:SI 2 "nonimmediate_operand" "rm")))
+ (set (match_operand:SI 3 "register_operand" "=d")
+ (mod:SI (match_dup 1) (match_dup 2)))
+ (use (match_dup 3))
+ (clobber (reg:CC 17))]
+ ""
+ "idiv{l}\\t%2"
+ [(set_attr "type" "idiv")
+ (set_attr "ppro_uops" "few")])
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (div:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "nonimmediate_operand" "")))
+ (set (match_operand:SI 3 "register_operand" "")
+ (mod:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC 17))]
+ "reload_completed"
+ [(parallel [(set (match_dup 3)
+ (ashiftrt:SI (match_dup 4) (const_int 31)))
+ (clobber (reg:CC 17))])
+ (parallel [(set (match_dup 0)
+ (div:SI (match_dup 1) (match_dup 2)))
+ (set (match_dup 3)
+ (mod:SI (match_dup 1) (match_dup 2)))
+ (use (match_dup 3))
+ (clobber (reg:CC 17))])]
+ "
{
-#ifdef INTEL_SYNTAX
- output_asm_insn (\"cdq\", operands);
-#else
- output_asm_insn (\"cltd\", operands);
-#endif
- return AS1 (idiv%L0,%2);
-}"
- [(set_attr "type" "idiv")])
+ /* Avoid use of cltd in favour of a mov+shift. */
+ if (TARGET_PENTIUM && !optimize_size)
+ {
+ emit_move_insn (operands[3], operands[1]);
+ operands[4] = operands[3];
+ }
+ else
+ operands[4] = operands[1];
+}")
+;; %%% Split me.
(define_insn "divmodhi4"
[(set (match_operand:HI 0 "register_operand" "=a")
(div:HI (match_operand:HI 1 "register_operand" "0")
(match_operand:HI 2 "nonimmediate_operand" "rm")))
(set (match_operand:HI 3 "register_operand" "=&d")
- (mod:HI (match_dup 1) (match_dup 2)))]
+ (mod:HI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC 17))]
""
- "cwtd\;idiv%W0 %2"
- [(set_attr "type" "idiv")])
+ "cwtd\;idiv{w}\\t%2"
+ [(set_attr "type" "multi")])
-;; ??? Can we make gcc zero extend operand[0]?
(define_insn "udivmodsi4"
[(set (match_operand:SI 0 "register_operand" "=a")
(udiv:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "nonimmediate_operand" "rm")))
(set (match_operand:SI 3 "register_operand" "=&d")
- (umod:SI (match_dup 1) (match_dup 2)))]
+ (umod:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC 17))]
""
- "*
-{
- output_asm_insn (AS2 (xor%L3,%3,%3), operands);
- return AS1 (div%L0,%2);
-}"
- [(set_attr "type" "idiv")])
-
-;; ??? Can we make gcc zero extend operand[0]?
-(define_insn "udivmodhi4"
- [(set (match_operand:HI 0 "register_operand" "=a")
- (udiv:HI (match_operand:HI 1 "register_operand" "0")
- (match_operand:HI 2 "nonimmediate_operand" "rm")))
- (set (match_operand:HI 3 "register_operand" "=&d")
- (umod:HI (match_dup 1) (match_dup 2)))]
- ""
- "*
-{
- output_asm_insn (AS2 (xor%W0,%3,%3), operands);
- return AS1 (div%W0,%2);
-}"
- [(set_attr "type" "idiv")])
-
-/*
-;;this should be a valid double division which we may want to add
+ "xor{l}\\t%3, %3\;div{l}\\t%2"
+ [(set_attr "type" "multi")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=a")
- (udiv:DI (match_operand:DI 1 "register_operand" "a")
+ (udiv:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "nonimmediate_operand" "rm")))
(set (match_operand:SI 3 "register_operand" "=d")
- (umod:SI (match_dup 1) (match_dup 2)))]
+ (umod:SI (match_dup 1) (match_dup 2)))
+ (use (match_dup 3))
+ (clobber (reg:CC 17))]
""
- "div%L0 %2,%0"
- [(set_attr "type" "idiv")])
-*/
-
-;;- and instructions
+ "div{l}\\t%2"
+ [(set_attr "type" "idiv")
+ (set_attr "ppro_uops" "few")])
-;; On i386,
-;; movzbl %bl,%ebx
-;; is faster than
-;; andl $255,%ebx
-;;
-;; but if the reg is %eax, then the "andl" is faster.
-;;
-;; On i486, the "andl" is always faster than the "movzbl".
-;;
-;; On both i386 and i486, a three operand AND is as fast with movzbl or
-;; movzwl as with andl, if operands[0] != operands[1].
-
-;; The `r' in `rm' for operand 3 looks redundant, but it causes
-;; optional reloads to be generated if op 3 is a pseudo in a stack slot.
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (udiv:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "nonimmediate_operand" "")))
+ (set (match_operand:SI 3 "register_operand" "")
+ (umod:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC 17))]
+ "reload_completed"
+ [(parallel [(set (match_dup 3) (const_int 0))
+ (clobber (reg:CC 17))])
+ (parallel [(set (match_dup 0)
+ (udiv:SI (match_dup 1) (match_dup 2)))
+ (set (match_dup 3)
+ (umod:SI (match_dup 1) (match_dup 2)))
+ (use (match_dup 3))
+ (clobber (reg:CC 17))])]
+ "")
-(define_insn "andsi3"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
- (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
- (match_operand:SI 2 "general_operand" "ri,rm")))]
+(define_expand "udivmodhi4"
+ [(parallel [(set (match_dup 4) (const_int 0))
+ (clobber (reg:CC 17))])
+ (parallel [(set (match_operand:HI 0 "register_operand" "=a")
+ (udiv:HI (match_operand:HI 1 "register_operand" "0")
+ (match_operand:HI 2 "nonimmediate_operand" "rm")))
+ (set (match_operand:HI 3 "register_operand" "=&d")
+ (umod:HI (match_dup 1) (match_dup 2)))
+ (use (match_dup 4))
+ (clobber (reg:CC 17))])]
""
- "*
-{
- HOST_WIDE_INT intval;
- if (!rtx_equal_p (operands[0], operands[1])
- && rtx_equal_p (operands[0], operands[2]))
- {
- rtx tmp;
- tmp = operands[1];
- operands[1] = operands[2];
- operands[2] = tmp;
- }
- switch (GET_CODE (operands[2]))
- {
- case CONST_INT:
- if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
- break;
- intval = INTVAL (operands[2]);
- /* zero-extend 16->32? */
- if (intval == 0xffff && REG_P (operands[0])
- && (! REG_P (operands[1])
- || REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0)
- && (!TARGET_ZERO_EXTEND_WITH_AND || ! rtx_equal_p (operands[0], operands[1])))
- {
- /* ??? tege: Should forget CC_STATUS only if we clobber a
- remembered operand. Fix that later. */
- CC_STATUS_INIT;
-#ifdef INTEL_SYNTAX
- return AS2 (movzx,%w1,%0);
-#else
- return AS2 (movz%W0%L0,%w1,%0);
-#endif
- }
-
- /* zero extend 8->32? */
- if (intval == 0xff && REG_P (operands[0])
- && !(REG_P (operands[1]) && NON_QI_REG_P (operands[1]))
- && (! REG_P (operands[1])
- || REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0)
- && (!TARGET_ZERO_EXTEND_WITH_AND || ! rtx_equal_p (operands[0], operands[1])))
- {
- /* ??? tege: Should forget CC_STATUS only if we clobber a
- remembered operand. Fix that later. */
- CC_STATUS_INIT;
-#ifdef INTEL_SYNTAX
- return AS2 (movzx,%b1,%0);
-#else
- return AS2 (movz%B0%L0,%b1,%0);
-#endif
- }
-
- /* Check partial bytes.. non-QI-regs are not available */
- if (REG_P (operands[0]) && ! QI_REG_P (operands[0]))
- break;
-
- /* only low byte has zero bits? */
- if (~(intval | 0xff) == 0)
- {
- intval &= 0xff;
- if (REG_P (operands[0]))
- {
- if (intval == 0)
- {
- CC_STATUS_INIT;
- return AS2 (xor%B0,%b0,%b0);
- }
-
- /* we're better off with the 32-bit version if reg != EAX */
- /* the value is sign-extended in 8 bits */
- if (REGNO (operands[0]) != 0 && (intval & 0x80))
- break;
- }
-
- CC_STATUS_INIT;
-
- operands[2] = GEN_INT (intval);
-
- if (intval == 0)
- return AS2 (mov%B0,%2,%b0);
-
- return AS2 (and%B0,%2,%b0);
- }
-
- /* only second byte has zero? */
- if (~(intval | 0xff00) == 0)
- {
- CC_STATUS_INIT;
-
- intval = (intval >> 8) & 0xff;
- operands[2] = GEN_INT (intval);
- if (intval == 0)
- {
- if (REG_P (operands[0]))
- return AS2 (xor%B0,%h0,%h0);
- operands[0] = adj_offsettable_operand (operands[0], 1);
- return AS2 (mov%B0,%2,%b0);
- }
-
- if (REG_P (operands[0]))
- return AS2 (and%B0,%2,%h0);
-
- operands[0] = adj_offsettable_operand (operands[0], 1);
- return AS2 (and%B0,%2,%b0);
- }
-
- if (REG_P (operands[0]))
- break;
-
- /* third byte has zero bits? */
- if (~(intval | 0xff0000) == 0)
- {
- intval = (intval >> 16) & 0xff;
- operands[0] = adj_offsettable_operand (operands[0], 2);
-byte_and_operation:
- CC_STATUS_INIT;
- operands[2] = GEN_INT (intval);
- if (intval == 0)
- return AS2 (mov%B0,%2,%b0);
- return AS2 (and%B0,%2,%b0);
- }
-
- /* fourth byte has zero bits? */
- if (~(intval | 0xff000000) == 0)
- {
- intval = (intval >> 24) & 0xff;
- operands[0] = adj_offsettable_operand (operands[0], 3);
- goto byte_and_operation;
- }
-
- /* Low word is zero? */
- if (intval == 0xffff0000)
- {
-word_zero_and_operation:
- CC_STATUS_INIT;
- operands[2] = const0_rtx;
- return AS2 (mov%W0,%2,%w0);
- }
-
- /* High word is zero? */
- if (intval == 0x0000ffff)
- {
- operands[0] = adj_offsettable_operand (operands[0], 2);
- goto word_zero_and_operation;
- }
-
- default:
- break;
- }
+ "operands[4] = gen_reg_rtx (HImode);")
- return AS2 (and%L0,%2,%0);
-}"
- [(set_attr "type" "binary")])
+(define_insn "*udivmodhi_1"
+ [(set (match_operand:HI 0 "register_operand" "=a")
+ (udiv:HI (match_operand:HI 1 "register_operand" "0")
+ (match_operand:HI 2 "nonimmediate_operand" "rm")))
+ (set (match_operand:HI 3 "register_operand" "=d")
+ (umod:HI (match_dup 1) (match_dup 2)))
+ (use (match_operand:HI 4 "register_operand" "3"))
+ (clobber (reg:CC 17))]
+ ""
+ "div{w}\\t%2"
+ [(set_attr "type" "idiv")
+ (set_attr "ppro_uops" "few")])
+
+;; We can not use div/idiv for double division, because it causes
+;; "division by zero" on the overflow and that's not what we expect
+;; from truncate. Because true (non truncating) double division is
+;; never generated, we can't create this insn anyway.
+;
+;(define_insn ""
+; [(set (match_operand:SI 0 "register_operand" "=a")
+; (truncate:SI
+; (udiv:DI (match_operand:DI 1 "register_operand" "A")
+; (zero_extend:DI
+; (match_operand:SI 2 "nonimmediate_operand" "rm")))))
+; (set (match_operand:SI 3 "register_operand" "=d")
+; (truncate:SI
+; (umod:DI (match_dup 1) (zero_extend:DI (match_dup 2)))))
+; (clobber (reg:CC 17))]
+; ""
+; "div{l}\\t{%2, %0|%0, %2}"
+; [(set_attr "type" "idiv")
+; (set_attr "ppro_uops" "few")])
+
+;;- Logical AND instructions
+
+;; On Pentium, "test imm, reg" is pairable only with eax, ax, and al.
+;; Note that this excludes ah.
+
+(define_insn "testsi_1"
+ [(set (reg:CCNO 17)
+ (compare:CCNO (and:SI (match_operand:SI 0 "nonimmediate_operand" "%*a,r,rm")
+ (match_operand:SI 1 "general_operand" "in,in,rin"))
+ (const_int 0)))]
+ ""
+ "test{l}\\t{%1, %0|%0, %1}"
+ [(set_attr "type" "icmp")
+ (set_attr "pent_pair" "uv,np,uv")])
+
+(define_insn "*testhi_1"
+ [(set (reg:CCNO 17)
+ (compare:CCNO (and:HI (match_operand:HI 0 "nonimmediate_operand" "%*a,r,rm")
+ (match_operand:HI 1 "general_operand" "n,n,rn"))
+ (const_int 0)))]
+ ""
+ "test{w}\\t{%1, %0|%0, %1}"
+ [(set_attr "type" "icmp")
+ (set_attr "pent_pair" "uv,np,uv")])
+
+(define_insn "testqi_1"
+ [(set (reg:CCNO 17)
+ (compare:CCNO (and:QI (match_operand:QI 0 "nonimmediate_operand" "%*a,q,qm")
+ (match_operand:QI 1 "general_operand" "n,n,qn"))
+ (const_int 0)))]
+ ""
+ "test{b}\\t{%1, %0|%0, %1}"
+ [(set_attr "type" "icmp")
+ (set_attr "pent_pair" "uv,np,uv")])
+
+;; ??? A bug in recog prevents it from recognizing a const_int as an
+;; operand to zero_extend in andqi_ext_1. It was checking explicitly
+;; for a QImode operand, which of course failed.
+
+(define_insn "testqi_ext_0"
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (and:SI
+ (zero_extract:SI
+ (match_operand 0 "ext_register_operand" "q")
+ (const_int 8)
+ (const_int 8))
+ (match_operand 1 "const_int_operand" "n"))
+ (const_int 0)))]
+ "(unsigned HOST_WIDE_INT) INTVAL (operands[1]) <= 0xff"
+ "test{b}\\t{%1, %h0|%h0, %1}"
+ [(set_attr "type" "icmp")
+ (set_attr "pent_pair" "np")])
+
+(define_insn "*testqi_ext_1"
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (and:SI
+ (zero_extract:SI
+ (match_operand 0 "ext_register_operand" "q")
+ (const_int 8)
+ (const_int 8))
+ (zero_extend:SI
+ (match_operand:QI 1 "nonimmediate_operand" "qm")))
+ (const_int 0)))]
+ ""
+ "test{b}\\t{%1, %h0|%h0, %1}"
+ [(set_attr "type" "icmp")])
+
+(define_insn "*testqi_ext_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (and:SI
+ (zero_extract:SI
+ (match_operand 0 "ext_register_operand" "q")
+ (const_int 8)
+ (const_int 8))
+ (zero_extract:SI
+ (match_operand 1 "ext_register_operand" "q")
+ (const_int 8)
+ (const_int 8)))
+ (const_int 0)))]
+ ""
+ "test{b}\\t{%h1, %h0|%h0, %h1}"
+ [(set_attr "type" "icmp")])
+
+;; Combine likes to form bit extractions for some tests. Humor it.
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO (zero_extract:SI
+ (match_operand 0 "nonimmediate_operand" "rm")
+ (match_operand:SI 1 "const_int_operand" "")
+ (match_operand:SI 2 "const_int_operand" ""))
+ (const_int 0)))]
+ "GET_MODE (operands[0]) == SImode
+ || GET_MODE (operands[0]) == HImode
+ || GET_MODE (operands[0]) == QImode"
+ "#")
-(define_insn "andhi3"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
- (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
- (match_operand:HI 2 "general_operand" "ri,rm")))]
- ""
- "*
+(define_split
+ [(set (reg:CCNO 17)
+ (compare:CCNO (zero_extract:SI
+ (match_operand 0 "nonimmediate_operand" "rm")
+ (match_operand:SI 1 "const_int_operand" "")
+ (match_operand:SI 2 "const_int_operand" ""))
+ (const_int 0)))]
+ ""
+ [(set (reg:CCNO 17) (compare:CCNO (match_dup 3) (const_int 0)))]
+ "
{
- if (GET_CODE (operands[2]) == CONST_INT
- && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))
- {
- /* Can we ignore the upper byte? */
- if ((! REG_P (operands[0]) || QI_REG_P (operands[0]))
- && (INTVAL (operands[2]) & 0xff00) == 0xff00)
- {
- CC_STATUS_INIT;
-
- if ((INTVAL (operands[2]) & 0xff) == 0)
- {
- operands[2] = const0_rtx;
- return AS2 (mov%B0,%2,%b0);
- }
-
- operands[2] = GEN_INT (INTVAL (operands[2]) & 0xff);
- return AS2 (and%B0,%2,%b0);
- }
-
- /* Can we ignore the lower byte? */
- /* ??? what about offsettable memory references? */
- if (QI_REG_P (operands[0]) && (INTVAL (operands[2]) & 0xff) == 0xff)
- {
- CC_STATUS_INIT;
-
- if ((INTVAL (operands[2]) & 0xff00) == 0)
- {
- operands[2] = const0_rtx;
- return AS2 (mov%B0,%2,%h0);
- }
+ HOST_WIDE_INT len = INTVAL (operands[1]);
+ HOST_WIDE_INT pos = INTVAL (operands[2]);
+ HOST_WIDE_INT mask;
+ enum machine_mode mode;
- operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff);
- return AS2 (and%B0,%2,%h0);
- }
-
- /* use 32-bit ops on registers when there are no sign issues.. */
- if (REG_P (operands[0]))
+ mode = GET_MODE (operands[0]);
+ if (GET_CODE (operands[0]) == MEM)
+ {
+ /* ??? Combine likes to put non-volatile mem extractions in QImode
+ no matter the size of the test. So find a mode that works. */
+ if (! MEM_VOLATILE_P (operands[0]))
{
- if (!(INTVAL (operands[2]) & ~0x7fff))
- return AS2 (and%L0,%2,%k0);
+ mode = smallest_mode_for_size (pos + len, MODE_INT);
+ operands[0] = change_address (operands[0], mode, NULL_RTX);
}
}
-
- if (REG_P (operands[0])
- && i386_aligned_p (operands[2]))
- {
- CC_STATUS_INIT;
- /* If op[2] is constant, we should zero-extend it and */
- /* make a note that op[0] has been zero-extended, so */
- /* that we could use 32-bit ops on it forthwith, but */
- /* there is no such reg-note available. Instead we do */
- /* a sign extension as that can result in shorter asm */
- operands[2] = i386_sext16_if_const (operands[2]);
- return AS2 (and%L0,%k2,%k0);
- }
-
- /* Use a 32-bit word with the upper bits set, invalidate CC */
- if (GET_CODE (operands[2]) == CONST_INT
- && i386_aligned_p (operands[0]))
+ else if (mode == HImode && pos + len <= 8)
{
- HOST_WIDE_INT val = INTVAL (operands[2]);
- CC_STATUS_INIT;
- val |= ~0xffff;
- if (val != INTVAL (operands[2]))
- operands[2] = GEN_INT (val);
- return AS2 (and%L0,%k2,%k0);
+ /* Small HImode tests can be converted to QImode. */
+ mode = QImode;
+ operands[0] = gen_lowpart (QImode, operands[0]);
}
- return AS2 (and%W0,%2,%0);
-}"
- [(set_attr "type" "binary")])
-
-(define_insn "andqi3"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
- (and:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
- (match_operand:QI 2 "general_operand" "qn,qmn")))]
- ""
- "* return AS2 (and%B0,%2,%0);"
- [(set_attr "type" "binary")])
-
-/* I am nervous about these two.. add them later..
-;I presume this means that we have something in say op0= eax which is small
-;and we want to and it with memory so we can do this by just an
-;andb m,%al and have success.
-(define_insn ""
- [(set (match_operand:SI 0 "general_operand" "=r")
- (and:SI (zero_extend:SI
- (match_operand:HI 1 "nonimmediate_operand" "rm"))
- (match_operand:SI 2 "general_operand" "0")))]
- "GET_CODE (operands[2]) == CONST_INT
- && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (HImode))"
- "and%W0 %1,%0")
+ mask = ((HOST_WIDE_INT)1 << (pos + len)) - 1;
+ mask &= ~(((HOST_WIDE_INT)1 << pos) - 1);
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=q")
- (and:SI
- (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm"))
- (match_operand:SI 2 "register_operand" "0")))]
- "GET_CODE (operands[2]) == CONST_INT
- && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (QImode))"
- "and%L0 %1,%0")
+ operands[3] = gen_rtx_AND (mode, operands[0], GEN_INT (mask));
+}")
-*/
-
-;;- Bit set (inclusive or) instructions
+;; %%% This used to optimize known byte-wide and operations to memory,
+;; and sometimes to QImode registers. If this is considered useful,
+;; it should be done with splitters.
-;; This optimizes known byte-wide operations to memory, and in some cases
-;; to QI registers.. Note that we don't want to use the QI registers too
-;; aggressively, because often the 32-bit register instruction is the same
-;; size, and likely to be faster on PentiumPro.
-(define_insn "iorsi3"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
- (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
- (match_operand:SI 2 "general_operand" "ri,rm")))]
- ""
+(define_expand "andsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (and:SI (match_operand:SI 1 "nonimmediate_operand" "")
+ (match_operand:SI 2 "general_operand" "")))
+ (clobber (reg:CC 17))]
+ ""
+ "ix86_expand_binary_operator (AND, SImode, operands); DONE;")
+
+(define_insn "*andsi_1"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r,r")
+ (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,qm")
+ (match_operand:SI 2 "general_operand" "ri,rm,L")))
+ (clobber (reg:CC 17))]
+ "ix86_binary_operator_ok (AND, SImode, operands)"
"*
{
- HOST_WIDE_INT intval;
- switch (GET_CODE (operands[2]))
+ switch (get_attr_type (insn))
{
- case CONST_INT:
-
- if (REG_P (operands[0]) && ! QI_REG_P (operands[0]))
- break;
-
- /* don't try to optimize volatile accesses */
- if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
- break;
-
- intval = INTVAL (operands[2]);
- if ((intval & ~0xff) == 0)
- {
- if (REG_P (operands[0]))
- {
- /* Do low byte access only for %eax or when high bit is set */
- if (REGNO (operands[0]) != 0 && !(intval & 0x80))
- break;
- }
-
-byte_or_operation:
- CC_STATUS_INIT;
-
- if (intval != INTVAL (operands[2]))
- operands[2] = GEN_INT (intval);
+ case TYPE_IMOVX:
+ {
+ enum machine_mode mode;
- if (intval == 0xff)
- return AS2 (mov%B0,%2,%b0);
+ if (GET_CODE (operands[2]) != CONST_INT)
+ abort ();
+ if (INTVAL (operands[2]) == 0xff)
+ mode = QImode;
+ else if (INTVAL (operands[2]) == 0xffff)
+ mode = HImode;
+ else
+ abort ();
+
+ operands[1] = gen_lowpart (mode, operands[1]);
+ if (mode == QImode)
+ return \"movz{bl|x}\\t{%1,%0|%0, %1}\";
+ else
+ return \"movz{wl|x}\\t{%1,%0|%0, %1}\";
+ }
- return AS2 (or%B0,%2,%b0);
- }
+ default:
+ if (! rtx_equal_p (operands[0], operands[1]))
+ abort ();
- /* second byte? */
- if ((intval & ~0xff00) == 0)
+ /* If operands[2] is an immediate, we may be able to use xor.
+ Walk through the cases to figure out which subword we are
+ supposed to clear. */
+ if (REG_P (operands[0])
+ && GET_CODE (operands[2]) == CONST_INT
+ && (optimize_size
+ || ! TARGET_PARTIAL_REG_STALL))
{
- intval >>= 8;
-
- if (REG_P (operands[0]))
+ if (INTVAL (operands[2]) == (HOST_WIDE_INT) 0xffff0000
+ && optimize_size)
+ return \"xor{w}\\t{%w0, %w0|%w0, %w0}\";
+ if (QI_REG_P (operands[0]))
{
- CC_STATUS_INIT;
- operands[2] = GEN_INT (intval);
- if (intval == 0xff)
- return AS2 (mov%B0,%2,%h0);
-
- return AS2 (or%B0,%2,%h0);
+ if (INTVAL (operands[2]) == (HOST_WIDE_INT) 0xffffff00)
+ return \"xor{b}\\t{%b0, %b0|%b0, %b0}\";
+ if (INTVAL (operands[2]) == (HOST_WIDE_INT) 0xffff00ff)
+ return \"xor{b}\\t{%h0, %h0|%h0, %h0}\";
}
-
- operands[0] = adj_offsettable_operand (operands[0], 1);
- goto byte_or_operation;
}
-
- if (REG_P (operands[0]))
- break;
-
- /* third byte? */
- if ((intval & ~0xff0000) == 0)
- {
- intval >>= 16;
- operands[0] = adj_offsettable_operand (operands[0], 2);
- goto byte_or_operation;
- }
-
- /* fourth byte? */
- if ((intval & ~0xff000000) == 0)
- {
- intval = (intval >> 24) & 0xff;
- operands[0] = adj_offsettable_operand (operands[0], 3);
- goto byte_or_operation;
- }
-
- default:
- break;
+ return \"and{l}\\t{%2, %0|%0, %2}\";
}
-
- return AS2 (or%L0,%2,%0);
}"
- [(set_attr "type" "binary")])
-
-(define_insn "iorhi3"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
- (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
- (match_operand:HI 2 "general_operand" "ri,rm")))]
- ""
+ [(set_attr "type" "alu,alu,imovx")])
+
+(define_insn "*andsi_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "rim,ri"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm")
+ (and:SI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (AND, SImode, operands)"
+ "and{l}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_expand "andhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "")
+ (and:HI (match_operand:HI 1 "nonimmediate_operand" "")
+ (match_operand:HI 2 "general_operand" "")))
+ (clobber (reg:CC 17))]
+ ""
+ "ix86_expand_binary_operator (AND, HImode, operands); DONE;")
+
+(define_insn "*andhi_1"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r,r")
+ (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,qm")
+ (match_operand:HI 2 "general_operand" "ri,rm,L")))
+ (clobber (reg:CC 17))]
+ "ix86_binary_operator_ok (AND, HImode, operands)"
"*
{
- HOST_WIDE_INT intval;
- switch (GET_CODE (operands[2]))
+ switch (get_attr_type (insn))
{
- case CONST_INT:
-
- if (REG_P (operands[0]) && ! QI_REG_P (operands[0]))
- break;
-
- /* don't try to optimize volatile accesses */
- if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
- break;
-
- intval = 0xffff & INTVAL (operands[2]);
-
- if ((intval & 0xff00) == 0)
- {
- if (REG_P (operands[0]))
- {
- /* Do low byte access only for %eax or when high bit is set */
- if (REGNO (operands[0]) != 0 && !(intval & 0x80))
- break;
- }
-
-byte_or_operation:
- CC_STATUS_INIT;
-
- if (intval == 0xff)
- return AS2 (mov%B0,%2,%b0);
+ case TYPE_IMOVX:
+ if (GET_CODE (operands[2]) != CONST_INT)
+ abort ();
+ if (INTVAL (operands[2]) == 0xff)
+ return \"movz{bl|x}\\t{%b1, %k0|%k0, %b1}\";
+ abort ();
- return AS2 (or%B0,%2,%b0);
- }
+ default:
+ if (! rtx_equal_p (operands[0], operands[1]))
+ abort ();
- /* high byte? */
- if ((intval & 0xff) == 0)
+ /* If operands[2] is an immediate, we may be able to use xor.
+ Walk through the cases to figure out which subword we are
+ supposed to clear. */
+ /* %%% Do these as splits. They get length_prefix wrong. */
+ if (GET_CODE (operands[2]) == CONST_INT
+ && QI_REG_P (operands[0])
+ && (optimize_size
+ || ! TARGET_PARTIAL_REG_STALL))
{
- intval >>= 8;
- operands[2] = GEN_INT (intval);
-
- if (REG_P (operands[0]))
- {
- CC_STATUS_INIT;
- if (intval == 0xff)
- return AS2 (mov%B0,%2,%h0);
-
- return AS2 (or%B0,%2,%h0);
- }
-
- operands[0] = adj_offsettable_operand (operands[0], 1);
-
- goto byte_or_operation;
+ if ((INTVAL (operands[2]) & 0xffff) == 0xff00)
+ return \"xor{b}\\t{%b0, %b0|%b0, %b0}\";
+ if ((INTVAL (operands[2]) & 0xffff) == 0x00ff)
+ return \"xor{b}\\t{%h0, %h0|%h0, %h0}\";
}
- default:
- break;
+ return \"and{w}\\t{%2, %0|%0, %2}\";
}
+}"
+ [(set_attr "type" "alu,alu,imovx")])
- if (REG_P (operands[0])
- && i386_aligned_p (operands[2]))
- {
- CC_STATUS_INIT;
- operands[2] = i386_sext16_if_const (operands[2]);
- return AS2 (or%L0,%k2,%k0);
- }
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "")
+ (and:HI (match_operand:HI 1 "register_operand" "")
+ (match_operand:HI 2 "nonmemory_operand" "")))
+ (clobber (reg:CC 17))]
+ "! TARGET_PARTIAL_REG_STALL && reload_completed"
+ [(parallel [(set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC 17))])]
+ "operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_lowpart (SImode, operands[2]);")
+
+(define_insn "*andhi_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "rim,ri"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm")
+ (and:HI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (AND, HImode, operands)"
+ "and{w}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
- if (GET_CODE (operands[2]) == CONST_INT
- && i386_aligned_p (operands[0]))
- {
- CC_STATUS_INIT;
- intval = 0xffff & INTVAL (operands[2]);
- if (intval != INTVAL (operands[2]))
- operands[2] = GEN_INT (intval);
- return AS2 (or%L0,%2,%k0);
- }
+(define_split
+ [(set (reg:CCNO 17)
+ (compare:CCNO (and:HI (match_operand:HI 1 "register_operand" "")
+ (match_operand:HI 2 "immediate_operand" ""))
+ (const_int 0)))
+ (set (match_operand:HI 0 "register_operand" "")
+ (and:HI (match_dup 1) (match_dup 2)))]
+ "! TARGET_PARTIAL_REG_STALL && reload_completed"
+ [(parallel [(set (reg:CCNO 17)
+ (compare:CCNO (and:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))
+ (set (match_dup 0)
+ (and:SI (match_dup 1) (match_dup 2)))])]
+ "operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_lowpart (SImode, operands[2]);")
- return AS2 (or%W0,%2,%0);
-}"
- [(set_attr "type" "binary")])
+(define_expand "andqi3"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "")
+ (and:QI (match_operand:QI 1 "nonimmediate_operand" "")
+ (match_operand:QI 2 "general_operand" "")))
+ (clobber (reg:CC 17))]
+ ""
+ "ix86_expand_binary_operator (AND, QImode, operands); DONE;")
+
+;; %%% Potential partial reg stall on alternative 2. What to do?
+(define_insn "*andqi_1"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,*r")
+ (and:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
+ (match_operand:QI 2 "general_operand" "qi,qmi,*ri")))
+ (clobber (reg:CC 17))]
+ "ix86_binary_operator_ok (AND, QImode, operands)"
+ "@
+ and{b}\\t{%2, %0|%0, %2}
+ and{b}\\t{%2, %0|%0, %2}
+ and{l}\\t{%k2, %k0|%k0, %k2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "*andqi_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO (and:QI
+ (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
+ (match_operand:QI 2 "general_operand" "qim,qi,i"))
+ (const_int 0)))
+ (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm,*r")
+ (and:QI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (AND, QImode, operands)"
+ "@
+ and{b}\\t{%2, %0|%0, %2}
+ and{b}\\t{%2, %0|%0, %2}
+ and{l}\\t{%2, %k0|%k0, %2}"
+ [(set_attr "type" "alu")])
+
+;; ??? A bug in recog prevents it from recognizing a const_int as an
+;; operand to zero_extend in andqi_ext_1. It was checking explicitly
+;; for a QImode operand, which of course failed.
+
+(define_insn "andqi_ext_0"
+ [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q")
+ (const_int 8)
+ (const_int 8))
+ (and:SI
+ (zero_extract:SI
+ (match_operand 1 "ext_register_operand" "0")
+ (const_int 8)
+ (const_int 8))
+ (match_operand 2 "const_int_operand" "n")))
+ (clobber (reg:CC 17))]
+ "(unsigned HOST_WIDE_INT)INTVAL (operands[2]) <= 0xff"
+ "and{b}\\t{%2, %h0|%h0, %2}"
+ [(set_attr "type" "alu")])
+
+;; Generated by peephole translating test to and. This shows up
+;; often in fp comparisons.
+
+(define_insn "*andqi_ext_0_cc"
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (and:SI
+ (zero_extract:SI
+ (match_operand 1 "ext_register_operand" "q")
+ (const_int 8)
+ (const_int 8))
+ (match_operand 2 "const_int_operand" "n"))
+ (const_int 0)))
+ (set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q")
+ (const_int 8)
+ (const_int 8))
+ (and:SI
+ (zero_extract:SI
+ (match_dup 1)
+ (const_int 8)
+ (const_int 8))
+ (match_dup 2)))]
+ "(unsigned HOST_WIDE_INT)INTVAL (operands[2]) <= 0xff"
+ "and{b}\\t{%2, %h0|%h0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "*andqi_ext_1"
+ [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q")
+ (const_int 8)
+ (const_int 8))
+ (and:SI
+ (zero_extract:SI
+ (match_operand 1 "ext_register_operand" "0")
+ (const_int 8)
+ (const_int 8))
+ (zero_extend:SI
+ (match_operand:QI 2 "general_operand" "qm"))))
+ (clobber (reg:CC 17))]
+ ""
+ "and{b}\\t{%2, %h0|%h0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "*andqi_ext_2"
+ [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q")
+ (const_int 8)
+ (const_int 8))
+ (and:SI
+ (zero_extract:SI
+ (match_operand 1 "ext_register_operand" "%0")
+ (const_int 8)
+ (const_int 8))
+ (zero_extract:SI
+ (match_operand 2 "ext_register_operand" "q")
+ (const_int 8)
+ (const_int 8))))
+ (clobber (reg:CC 17))]
+ ""
+ "and{b}\\t{%h2, %h0|%h0, %h2}"
+ [(set_attr "type" "alu")])
+
+;; Logical inclusive OR instructions
-(define_insn "iorqi3"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
- (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
- (match_operand:QI 2 "general_operand" "qn,qmn")))]
+;; %%% This used to optimize known byte-wide and operations to memory.
+;; If this is considered useful, it should be done with splitters.
+
+(define_expand "iorsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (ior:SI (match_operand:SI 1 "nonimmediate_operand" "")
+ (match_operand:SI 2 "general_operand" "")))
+ (clobber (reg:CC 17))]
""
- "* return AS2 (or%B0,%2,%0);"
- [(set_attr "type" "binary")])
-
-;;- xor instructions
+ "ix86_expand_binary_operator (IOR, SImode, operands); DONE;")
-(define_insn "xorsi3"
+(define_insn "*iorsi_1"
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
- (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
- (match_operand:SI 2 "general_operand" "ri,rm")))]
+ (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "ri,rmi")))
+ (clobber (reg:CC 17))]
+ "ix86_binary_operator_ok (IOR, SImode, operands)"
+ "or{l}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "*iorsi_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "rim,ri"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm")
+ (ior:SI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (IOR, SImode, operands)"
+ "or{l}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_expand "iorhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "")
+ (ior:HI (match_operand:HI 1 "nonimmediate_operand" "")
+ (match_operand:HI 2 "general_operand" "")))
+ (clobber (reg:CC 17))]
""
- "*
-{
- HOST_WIDE_INT intval;
- switch (GET_CODE (operands[2]))
- {
- case CONST_INT:
-
- if (REG_P (operands[0]) && ! QI_REG_P (operands[0]))
- break;
-
- /* don't try to optimize volatile accesses */
- if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
- break;
+ "ix86_expand_binary_operator (IOR, HImode, operands); DONE;")
- intval = INTVAL (operands[2]);
- if ((intval & ~0xff) == 0)
- {
- if (REG_P (operands[0]))
- {
- /* Do low byte access only for %eax or when high bit is set */
- if (REGNO (operands[0]) != 0 && !(intval & 0x80))
- break;
- }
-
-byte_xor_operation:
- CC_STATUS_INIT;
-
- if (intval == 0xff
- && (!TARGET_PENTIUM || optimize_size
- || (GET_CODE (operands[0]) == MEM
- && memory_address_info (XEXP (operands[0], 0), 1))))
- return AS1 (not%B0,%b0);
-
- if (intval != INTVAL (operands[2]))
- operands[2] = GEN_INT (intval);
- return AS2 (xor%B0,%2,%b0);
- }
-
- /* second byte? */
- if ((intval & ~0xff00) == 0)
- {
- intval >>= 8;
-
- if (REG_P (operands[0]))
- {
- CC_STATUS_INIT;
- if (intval == 0xff
- && (!TARGET_PENTIUM || optimize_size
- || (GET_CODE (operands[0]) == MEM
- && memory_address_info (XEXP (operands[0], 0), 1))))
- return AS1 (not%B0,%h0);
-
- operands[2] = GEN_INT (intval);
- return AS2 (xor%B0,%2,%h0);
- }
-
- operands[0] = adj_offsettable_operand (operands[0], 1);
-
- goto byte_xor_operation;
- }
-
- if (REG_P (operands[0]))
- break;
-
- /* third byte? */
- if ((intval & ~0xff0000) == 0)
- {
- intval >>= 16;
- operands[0] = adj_offsettable_operand (operands[0], 2);
- goto byte_xor_operation;
- }
-
- /* fourth byte? */
- if ((intval & ~0xff000000) == 0)
- {
- intval = (intval >> 24) & 0xff;
- operands[0] = adj_offsettable_operand (operands[0], 3);
- goto byte_xor_operation;
- }
+(define_insn "*iorhi_1"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,m")
+ (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "rmi,ri")))
+ (clobber (reg:CC 17))]
+ "ix86_binary_operator_ok (IOR, HImode, operands)"
+ "or{w}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
- default:
- break;
- }
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "")
+ (ior:HI (match_operand:HI 1 "register_operand" "")
+ (match_operand:HI 2 "nonmemory_operand" "")))
+ (clobber (reg:CC 17))]
+ "! TARGET_PARTIAL_REG_STALL && reload_completed"
+ [(parallel [(set (match_dup 0) (ior:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC 17))])]
+ "operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_lowpart (SImode, operands[2]);")
+
+(define_insn "*iorhi_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "rim,ri"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm")
+ (ior:HI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (IOR, HImode, operands)"
+ "or{w}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_expand "iorqi3"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "")
+ (ior:QI (match_operand:QI 1 "nonimmediate_operand" "")
+ (match_operand:QI 2 "general_operand" "")))
+ (clobber (reg:CC 17))]
+ ""
+ "ix86_expand_binary_operator (IOR, QImode, operands); DONE;")
+
+;; %%% Potential partial reg stall on alternative 2. What to do?
+(define_insn "*iorqi_1"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m,*r")
+ (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
+ (match_operand:QI 2 "general_operand" "qmi,qi,*ri")))
+ (clobber (reg:CC 17))]
+ "ix86_binary_operator_ok (IOR, QImode, operands)"
+ "@
+ or{b}\\t{%2, %0|%0, %2}
+ or{b}\\t{%2, %0|%0, %2}
+ or{l}\\t{%k2, %k0|%k0, %k2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "*iorqi_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:QI 2 "general_operand" "qim,qi"))
+ (const_int 0)))
+ (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm")
+ (ior:QI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (IOR, QImode, operands)"
+ "or{b}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+;; Logical XOR instructions
- return AS2 (xor%L0,%2,%0);
-}"
- [(set_attr "type" "binary")])
+;; %%% This used to optimize known byte-wide and operations to memory.
+;; If this is considered useful, it should be done with splitters.
-(define_insn "xorhi3"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
- (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
- (match_operand:HI 2 "general_operand" "ri,rm")))]
+(define_expand "xorsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (xor:SI (match_operand:SI 1 "nonimmediate_operand" "")
+ (match_operand:SI 2 "general_operand" "")))
+ (clobber (reg:CC 17))]
""
- "*
-{
- if (GET_CODE (operands[2]) == CONST_INT
- && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))
- {
- /* Can we ignore the upper byte? */
- if ((! REG_P (operands[0]) || QI_REG_P (operands[0]))
- && (INTVAL (operands[2]) & 0xff00) == 0)
- {
- CC_STATUS_INIT;
- if (INTVAL (operands[2]) & 0xffff0000)
- operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff);
-
- if (INTVAL (operands[2]) == 0xff
- && (!TARGET_PENTIUM || optimize_size
- || (GET_CODE (operands[0]) == MEM
- && memory_address_info (XEXP (operands[0], 0), 1))))
- return AS1 (not%B0,%b0);
-
- return AS2 (xor%B0,%2,%b0);
- }
+ "ix86_expand_binary_operator (XOR, SImode, operands); DONE;")
- /* Can we ignore the lower byte? */
- /* ??? what about offsettable memory references? */
- if (QI_REG_P (operands[0])
- && (INTVAL (operands[2]) & 0xff) == 0)
- {
- CC_STATUS_INIT;
- operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff);
+(define_insn "*xorsi_1"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+ (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "ri,rm")))
+ (clobber (reg:CC 17))]
+ "ix86_binary_operator_ok (XOR, SImode, operands)"
+ "xor{l}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "*xorsi_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "rim,ri"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm")
+ (xor:SI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (XOR, SImode, operands)"
+ "xor{l}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_expand "xorhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "")
+ (xor:HI (match_operand:HI 1 "nonimmediate_operand" "")
+ (match_operand:HI 2 "general_operand" "")))
+ (clobber (reg:CC 17))]
+ ""
+ "ix86_expand_binary_operator (XOR, HImode, operands); DONE;")
- if (INTVAL (operands[2]) == 0xff
- && (!TARGET_PENTIUM || optimize_size
- || (GET_CODE (operands[0]) == MEM
- && memory_address_info (XEXP (operands[0], 0), 1))))
- return AS1 (not%B0,%h0);
+(define_insn "*xorhi_1"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,m")
+ (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "rmi,ri")))
+ (clobber (reg:CC 17))]
+ "ix86_binary_operator_ok (XOR, HImode, operands)"
+ "xor{w}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
- return AS2 (xor%B0,%2,%h0);
- }
- }
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "")
+ (xor:HI (match_operand:HI 1 "register_operand" "")
+ (match_operand:HI 2 "nonmemory_operand" "")))
+ (clobber (reg:CC 17))]
+ "! TARGET_PARTIAL_REG_STALL && reload_completed"
+ [(parallel [(set (match_dup 0) (xor:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC 17))])]
+ "operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_lowpart (SImode, operands[2]);")
+
+(define_insn "*xorhi_2"
+ [(set (reg:CCNO 17)
+ (compare:CCNO (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "rim,ri"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm")
+ (xor:HI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (XOR, HImode, operands)"
+ "xor{w}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_expand "xorqi3"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "")
+ (xor:QI (match_operand:QI 1 "nonimmediate_operand" "")
+ (match_operand:QI 2 "general_operand" "")))
+ (clobber (reg:CC 17))]
+ ""
+ "ix86_expand_binary_operator (XOR, QImode, operands); DONE;")
+
+;; %%% Potential partial reg stall on alternative 2. What to do?
+(define_insn "*xorqi_1"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m,*r")
+ (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
+ (match_operand:QI 2 "general_operand" "qmi,qi,*ri")))
+ (clobber (reg:CC 17))]
+ "ix86_binary_operator_ok (XOR, QImode, operands)"
+ "@
+ xor{b}\\t{%2, %0|%0, %2}
+ xor{b}\\t{%2, %0|%0, %2}
+ xor{l}\\t{%k2, %k0|%k0, %k2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "xorcqi_1"
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:QI 2 "general_operand" "qim,qi"))
+ (const_int 0)))
+ (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm")
+ (xor:QI (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (XOR, QImode, operands)"
+ "xor{b}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")])
+
+(define_insn "xorcqi_ext_1"
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (xor:SI
+ (zero_extract:SI
+ (match_operand 1 "ext_register_operand" "0")
+ (const_int 8)
+ (const_int 8))
+ (match_operand:QI 2 "general_operand" "qmn"))
+ (const_int 0)))
+ (set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q")
+ (const_int 8)
+ (const_int 8))
+ (xor:SI
+ (zero_extract:SI (match_dup 1) (const_int 8) (const_int 8))
+ (match_dup 2)))]
+ ""
+ "xor{b}\\t{%2, %h0|%h0, %2}"
+ [(set_attr "type" "alu")])
+
+;; Negation instructions
- if (REG_P (operands[0])
- && i386_aligned_p (operands[2]))
- {
- CC_STATUS_INIT;
- operands[2] = i386_sext16_if_const (operands[2]);
- return AS2 (xor%L0,%k2,%k0);
- }
+;; %%% define_expand from the very first?
- if (GET_CODE (operands[2]) == CONST_INT
- && i386_aligned_p (operands[0]))
- {
- HOST_WIDE_INT intval;
- CC_STATUS_INIT;
- intval = 0xffff & INTVAL (operands[2]);
- if (intval != INTVAL (operands[2]))
- operands[2] = GEN_INT (intval);
- return AS2 (xor%L0,%2,%k0);
- }
+(define_insn "negdi2"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=ro")
+ (neg:DI (match_operand:DI 1 "general_operand" "0")))
+ (clobber (reg:CC 17))]
+ ""
+ "#")
- return AS2 (xor%W0,%2,%0);
-}"
- [(set_attr "type" "binary")])
+(define_split
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (neg:DI (match_operand:DI 1 "general_operand" "")))
+ (clobber (reg:CC 17))]
+ "cse_not_expected"
+ [(parallel
+ [(set (reg:CCNO 17)
+ (compare:CCNO (neg:SI (match_dup 2)) (const_int 0)))
+ (set (match_dup 0) (neg:SI (match_dup 2)))])
+ (parallel
+ [(set (match_dup 1)
+ (plus:SI (match_dup 3)
+ (plus:SI (const_int 0)
+ (ltu:SI (reg:CC 17) (const_int 0)))))
+ (clobber (reg:CC 17))])
+ (parallel
+ [(set (match_dup 1)
+ (neg:SI (match_dup 1)))
+ (clobber (reg:CC 17))])]
+ "split_di (operands+1, 1, operands+2, operands+3);
+ split_di (operands+0, 1, operands+0, operands+1);")
-(define_insn "xorqi3"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
- (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
- (match_operand:QI 2 "general_operand" "qn,qm")))]
+(define_insn "negsi2"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0")))
+ (clobber (reg:CC 17))]
""
- "* return AS2 (xor%B0,%2,%0);"
- [(set_attr "type" "binary")])
-
-;; logical operations for DImode
+ "neg{l}\\t%0"
+ [(set_attr "type" "negnot")])
-(define_insn "anddi3"
- [(set (match_operand:DI 0 "general_operand" "=&r,&ro")
- (and:DI (match_operand:DI 1 "general_operand" "%0,0")
- (match_operand:DI 2 "general_operand" "oriF,riF")))]
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (neg:SI (match_dup 1)))]
""
- "#"
- [(set_attr "type" "binary")])
-
+ "neg{l}\\t%0"
+ [(set_attr "type" "negnot")])
-(define_insn "iordi3"
- [(set (match_operand:DI 0 "general_operand" "=&r,&ro")
- (ior:DI (match_operand:DI 1 "general_operand" "%0,0")
- (match_operand:DI 2 "general_operand" "oriF,riF")))]
+(define_insn ""
+ [(set (reg:CC 17)
+ (compare:CC (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (neg:SI (match_dup 1)))]
""
- "#"
- [(set_attr "type" "binary")])
+ "neg{l}\\t%0"
+ [(set_attr "type" "negnot")])
-(define_insn "xordi3"
- [(set (match_operand:DI 0 "general_operand" "=&r,&ro")
- (xor:DI (match_operand:DI 1 "general_operand" "%0,0")
- (match_operand:DI 2 "general_operand" "oriF,riF")))]
+(define_insn "neghi2"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (neg:HI (match_operand:HI 1 "nonimmediate_operand" "0")))
+ (clobber (reg:CC 17))]
""
- "#"
- [(set_attr "type" "binary")])
+ "neg{w}\\t%0"
+ [(set_attr "type" "negnot")])
-(define_split
- [(set (match_operand:DI 0 "general_operand" "")
- (match_operator:DI 3 "ix86_logical_operator"
- [(match_operand:DI 1 "general_operand" "")
- (match_operand:DI 2 "general_operand" "")]))]
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO (neg:HI (match_operand:HI 1 "nonimmediate_operand" "0"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (neg:HI (match_dup 1)))]
""
- [(set (match_dup 4) (match_op_dup:SI 3 [(match_dup 6) (match_dup 8)]))
- (set (match_dup 5) (match_op_dup:SI 3 [(match_dup 7) (match_dup 9)]))]
- "split_di (&operands[0], 1, &operands[4], &operands[5]);
- split_di (&operands[1], 1, &operands[6], &operands[7]);
- split_di (&operands[2], 1, &operands[8], &operands[9]);")
-
-;;- negation instructions
+ "neg{w}\\t%0"
+ [(set_attr "type" "negnot")])
-(define_insn "negdi2"
- [(set (match_operand:DI 0 "general_operand" "=&ro")
- (neg:DI (match_operand:DI 1 "general_operand" "0")))]
+(define_insn ""
+ [(set (reg:CC 17)
+ (compare:CC (neg:HI (match_operand:HI 1 "nonimmediate_operand" "0"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (neg:HI (match_dup 1)))]
""
- "*
-{
- rtx xops[2], low[1], high[1];
-
- CC_STATUS_INIT;
+ "neg{w}\\t%0"
+ [(set_attr "type" "negnot")])
- split_di (operands, 1, low, high);
- xops[0] = const0_rtx;
- xops[1] = high[0];
-
- output_asm_insn (AS1 (neg%L0,%0), low);
- output_asm_insn (AS2 (adc%L1,%0,%1), xops);
- output_asm_insn (AS1 (neg%L0,%0), high);
- RET;
-}")
-
-(define_insn "negsi2"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
- (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
+(define_insn "negqi2"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+ (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0")))
+ (clobber (reg:CC 17))]
""
- "neg%L0 %0")
+ "neg{b}\\t%0"
+ [(set_attr "type" "negnot")])
-(define_insn "neghi2"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
- (neg:HI (match_operand:HI 1 "nonimmediate_operand" "0")))]
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0"))
+ (const_int 0)))
+ (set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+ (neg:QI (match_dup 1)))]
""
- "*
- if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn))
- {
- CC_STATUS_INIT;
- return AS1(neg%L0,%k0);
- }
- return AS1(neg%W0,%0);")
+ "neg{b}\\t%0"
+ [(set_attr "type" "negnot")])
-(define_insn "negqi2"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
- (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0")))]
+(define_insn ""
+ [(set (reg:CC 17)
+ (compare:CC (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0"))
+ (const_int 0)))
+ (set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+ (neg:QI (match_dup 1)))]
""
- "neg%B0 %0")
+ "neg{b}\\t%0"
+ [(set_attr "type" "negnot")])
(define_insn "negsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(neg:SF (match_operand:SF 1 "register_operand" "0")))]
"TARGET_80387"
"fchs"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fsgn")
+ (set_attr "ppro_uops" "few")])
(define_insn "negdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(neg:DF (match_operand:DF 1 "register_operand" "0")))]
"TARGET_80387"
"fchs"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fsgn")
+ (set_attr "ppro_uops" "few")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
- (neg:DF (float_extend:DF (match_operand:SF 1 "register_operand" "0"))))]
+ (neg:DF (float_extend:DF
+ (match_operand:SF 1 "register_operand" "0"))))]
"TARGET_80387"
"fchs"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fsgn")
+ (set_attr "ppro_uops" "few")])
(define_insn "negxf2"
[(set (match_operand:XF 0 "register_operand" "=f")
(neg:XF (match_operand:XF 1 "register_operand" "0")))]
"TARGET_80387"
"fchs"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fsgn")
+ (set_attr "ppro_uops" "few")])
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f")
- (neg:XF (float_extend:XF (match_operand:DF 1 "register_operand" "0"))))]
+ (neg:XF (float_extend:XF
+ (match_operand:DF 1 "register_operand" "0"))))]
"TARGET_80387"
"fchs"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fsgn")
+ (set_attr "ppro_uops" "few")])
+
+(define_insn ""
+ [(set (match_operand:XF 0 "register_operand" "=f")
+ (neg:XF (float_extend:XF
+ (match_operand:SF 1 "register_operand" "0"))))]
+ "TARGET_80387"
+ "fchs"
+ [(set_attr "type" "fsgn")
+ (set_attr "ppro_uops" "few")])
;; Absolute value instructions
@@ -4938,1428 +4820,1307 @@ byte_xor_operation:
(abs:SF (match_operand:SF 1 "register_operand" "0")))]
"TARGET_80387"
"fabs"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fsgn")])
(define_insn "absdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(abs:DF (match_operand:DF 1 "register_operand" "0")))]
"TARGET_80387"
"fabs"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fsgn")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
- (abs:DF (float_extend:DF (match_operand:SF 1 "register_operand" "0"))))]
+ (abs:DF (float_extend:DF
+ (match_operand:SF 1 "register_operand" "0"))))]
"TARGET_80387"
"fabs"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fsgn")])
(define_insn "absxf2"
[(set (match_operand:XF 0 "register_operand" "=f")
(abs:XF (match_operand:XF 1 "register_operand" "0")))]
"TARGET_80387"
"fabs"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fsgn")])
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f")
- (abs:XF (float_extend:XF (match_operand:DF 1 "register_operand" "0"))))]
+ (abs:XF (float_extend:XF
+ (match_operand:DF 1 "register_operand" "0"))))]
"TARGET_80387"
"fabs"
- [(set_attr "type" "fpop")])
-
-(define_insn "sqrtsf2"
- [(set (match_operand:SF 0 "register_operand" "=f")
- (sqrt:SF (match_operand:SF 1 "register_operand" "0")))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
- "fsqrt")
-
-(define_insn "sqrtdf2"
- [(set (match_operand:DF 0 "register_operand" "=f")
- (sqrt:DF (match_operand:DF 1 "register_operand" "0")))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && (TARGET_IEEE_FP || flag_fast_math) "
- "fsqrt")
+ [(set_attr "type" "fsgn")])
(define_insn ""
- [(set (match_operand:DF 0 "register_operand" "=f")
- (sqrt:DF (float_extend:DF
- (match_operand:SF 1 "register_operand" "0"))))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
- "fsqrt")
-
-(define_insn "sqrtxf2"
[(set (match_operand:XF 0 "register_operand" "=f")
- (sqrt:XF (match_operand:XF 1 "register_operand" "0")))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && (TARGET_IEEE_FP || flag_fast_math) "
- "fsqrt")
-
-(define_insn ""
- [(set (match_operand:XF 0 "register_operand" "=f")
- (sqrt:XF (float_extend:XF
- (match_operand:DF 1 "register_operand" "0"))))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
- "fsqrt")
-
-(define_insn ""
- [(set (match_operand:XF 0 "register_operand" "=f")
- (sqrt:XF (float_extend:XF
- (match_operand:SF 1 "register_operand" "0"))))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
- "fsqrt")
-
-(define_insn "sindf2"
- [(set (match_operand:DF 0 "register_operand" "=f")
- (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 1))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
- "fsin")
-
-(define_insn "sinsf2"
- [(set (match_operand:SF 0 "register_operand" "=f")
- (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 1))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
- "fsin")
-
-(define_insn ""
- [(set (match_operand:DF 0 "register_operand" "=f")
- (unspec:DF [(float_extend:DF
- (match_operand:SF 1 "register_operand" "0"))] 1))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
- "fsin")
-
-(define_insn "sinxf2"
- [(set (match_operand:XF 0 "register_operand" "=f")
- (unspec:XF [(match_operand:XF 1 "register_operand" "0")] 1))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
- "fsin")
-
-(define_insn "cosdf2"
- [(set (match_operand:DF 0 "register_operand" "=f")
- (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 2))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
- "fcos")
-
-(define_insn "cossf2"
- [(set (match_operand:SF 0 "register_operand" "=f")
- (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 2))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
- "fcos")
-
-(define_insn ""
- [(set (match_operand:DF 0 "register_operand" "=f")
- (unspec:DF [(float_extend:DF
- (match_operand:SF 1 "register_operand" "0"))] 2))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
- "fcos")
-
-(define_insn "cosxf2"
- [(set (match_operand:XF 0 "register_operand" "=f")
- (unspec:XF [(match_operand:XF 1 "register_operand" "0")] 2))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
- "fcos")
+ (abs:XF (float_extend:XF
+ (match_operand:SF 1 "register_operand" "0"))))]
+ "TARGET_80387"
+ "fabs"
+ [(set_attr "type" "fsgn")])
-;;- one complement instructions
+;; One complement instructions
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
(not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
""
- "*
-{
- /* A Pentium NOT is not pariable. Output it only in case of complex
- memory address, because XOR will be inpariable anyway because
- of immediate/displacement rule. */
+ "not{l}\\t%0"
+ [(set_attr "type" "negnot")])
- if (TARGET_PENTIUM && !optimize_size
- && (GET_CODE (operands[0]) != MEM
- || memory_address_info (XEXP (operands[0], 0), 1) == 0))
- {
- rtx xops[2];
- xops[0] = operands[0];
- xops[1] = GEN_INT (0xffffffff);
- output_asm_insn (AS2 (xor%L0,%1,%0), xops);
- RET;
- }
- else
- return AS1 (not%L0,%0);
-}")
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO (not:SI (match_operand:SI 1 "nonimmediate_operand" "0"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (not:SI (match_dup 1)))]
+ ""
+ "#"
+ [(set_attr "type" "alu1")])
+
+(define_split
+ [(set (reg:CCNO 17)
+ (compare:CCNO (not:SI (match_operand:SI 1 "nonimmediate_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "")
+ (not:SI (match_dup 1)))]
+ ""
+ [(parallel [(set (reg:CCNO 17)
+ (compare:CCNO (xor:SI (match_dup 1) (const_int -1))
+ (const_int 0)))
+ (set (match_dup 0)
+ (xor:SI (match_dup 1) (const_int -1)))])]
+ "")
(define_insn "one_cmplhi2"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
(not:HI (match_operand:HI 1 "nonimmediate_operand" "0")))]
""
- "*
-{
- /* A Pentium NOT is not pariable. Output it only in case of complex
- memory address, because XOR will be inpariable anyway because
- of immediate/displacement rule. */
+ "not{w}\\t%0"
+ [(set_attr "type" "negnot")])
- if (TARGET_PENTIUM && !optimize_size
- && (GET_CODE (operands[0]) != MEM
- || memory_address_info (XEXP (operands[0], 0), 1) == 0))
- {
- rtx xops[2];
- xops[0] = operands[0];
- xops[1] = GEN_INT (0xffff);
- if (REG_P (operands[0])
- && i386_cc_probably_useless_p (insn))
- {
- CC_STATUS_INIT;
- output_asm_insn (AS2 (xor%L0,%1,%k0), xops);
- }
- else
- output_asm_insn (AS2 (xor%W0,%1,%0), xops);
- RET;
- }
- else
- {
- if (REG_P (operands[0])
- && i386_cc_probably_useless_p (insn))
- {
- CC_STATUS_INIT;
- return AS1 (not%L0,%k0);
- }
- return AS1 (not%W0,%0);
- }
-}")
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "")
+ (not:HI (match_operand:HI 1 "register_operand" "")))
+ (clobber (reg:CC 17))]
+ "! TARGET_PARTIAL_REG_STALL && reload_completed"
+ [(parallel [(set (match_dup 0) (not:SI (match_dup 1)))
+ (clobber (reg:CC 17))])]
+ "operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);")
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO (not:HI (match_operand:HI 1 "nonimmediate_operand" "0"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (not:HI (match_dup 1)))]
+ ""
+ "#"
+ [(set_attr "type" "alu1")])
+
+(define_split
+ [(set (reg:CCNO 17)
+ (compare:CCNO (not:HI (match_operand:HI 1 "nonimmediate_operand" ""))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "")
+ (not:HI (match_dup 1)))]
+ ""
+ [(parallel [(set (reg:CCNO 17)
+ (compare:CCNO (xor:HI (match_dup 1) (const_int -1))
+ (const_int 0)))
+ (set (match_dup 0)
+ (xor:HI (match_dup 1) (const_int -1)))])]
+ "")
+
+;; %%% Potential partial reg stall on alternative 1. What to do?
(define_insn "one_cmplqi2"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
- (not:QI (match_operand:QI 1 "nonimmediate_operand" "0")))]
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,*r")
+ (not:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")))]
""
- "*
-{
- /* A Pentium NOT is not pariable. Output it only in case of complex
- memory address, because XOR will be inpariable anyway because
- of immediate/displacement rule. */
+ "@
+ not{b}\\t%0
+ not{l}\\t%k0"
+ [(set_attr "type" "negnot")])
- if (TARGET_PENTIUM && !optimize_size
- && (GET_CODE (operands[0]) != MEM
- || memory_address_info (XEXP (operands[0], 0), 1) == 0))
- {
- rtx xops[2];
- xops[0] = operands[0];
- xops[1] = GEN_INT (0xff);
- output_asm_insn (AS2 (xor%B0,%1,%0), xops);
- RET;
- }
- else
- return AS1 (not%B0,%0);
-}")
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO (not:QI (match_operand:QI 1 "nonimmediate_operand" "0"))
+ (const_int 0)))
+ (set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+ (not:QI (match_dup 1)))]
+ ""
+ "#"
+ [(set_attr "type" "alu1")])
+
+(define_split
+ [(set (reg:CCNO 17)
+ (compare:CCNO (not:QI (match_operand:QI 1 "nonimmediate_operand" ""))
+ (const_int 0)))
+ (set (match_operand:QI 0 "nonimmediate_operand" "")
+ (not:QI (match_dup 1)))]
+ ""
+ [(parallel [(set (reg:CCNO 17)
+ (compare:CCNO (xor:QI (match_dup 1) (const_int -1))
+ (const_int 0)))
+ (set (match_dup 0)
+ (xor:QI (match_dup 1) (const_int -1)))])]
+ "")
-;;- arithmetic shift instructions
+;; Arithmetic shift instructions
;; DImode shifts are implemented using the i386 "shift double" opcode,
;; which is written as "sh[lr]d[lw] imm,reg,reg/mem". If the shift count
;; is variable, then the count is in %cl and the "imm" operand is dropped
;; from the assembler input.
-
+;;
;; This instruction shifts the target reg/mem as usual, but instead of
;; shifting in zeros, bits are shifted in from reg operand. If the insn
;; is a left shift double, bits are taken from the high order bits of
;; reg, else if the insn is a shift right double, bits are taken from the
;; low order bits of reg. So if %eax is "1234" and %edx is "5678",
;; "shldl $8,%edx,%eax" leaves %edx unchanged and sets %eax to "2345".
-
+;;
;; Since sh[lr]d does not change the `reg' operand, that is done
;; separately, making all shifts emit pairs of shift double and normal
;; shift. Since sh[lr]d does not shift more than 31 bits, and we wish to
;; support a 63 bit shift, each shift where the count is in a reg expands
;; to a pair of shifts, a branch, a shift by 32 and a label.
-
+;;
;; If the shift count is a constant, we need never emit more than one
;; shift pair, instead using moves and sign extension for counts greater
;; than 31.
(define_expand "ashldi3"
- [(set (match_operand:DI 0 "register_operand" "")
- (ashift:DI (match_operand:DI 1 "register_operand" "")
- (match_operand:QI 2 "nonmemory_operand" "")))]
+ [(parallel [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashift:DI (match_operand:DI 1 "register_operand" "0")
+ (match_operand:QI 2 "nonmemory_operand" "Jc")))
+ (clobber (reg:CC 17))])]
""
"
{
- if (GET_CODE (operands[2]) != CONST_INT
- || ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J'))
+ if (TARGET_CMOVE && ! immediate_operand (operands[2], QImode))
{
- operands[2] = copy_to_mode_reg (QImode, operands[2]);
- emit_insn (gen_ashldi3_non_const_int (operands[0], operands[1],
- operands[2]));
+ emit_insn (gen_ashldi3_1 (operands[0], operands[1], operands[2]));
+ DONE;
}
- else
- emit_insn (gen_ashldi3_const_int (operands[0], operands[1], operands[2]));
-
- DONE;
}")
-(define_insn "ashldi3_const_int"
- [(set (match_operand:DI 0 "register_operand" "=&r")
+(define_insn "ashldi3_1"
+ [(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (match_operand:DI 1 "register_operand" "0")
- (match_operand:QI 2 "const_int_operand" "J")))]
- "CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')"
- "*
-{
- rtx xops[4], low[1], high[1];
-
- CC_STATUS_INIT;
-
- split_di (operands, 1, low, high);
- xops[0] = operands[2];
- xops[1] = const1_rtx;
- xops[2] = low[0];
- xops[3] = high[0];
-
- if (INTVAL (xops[0]) > 31)
- {
- output_asm_insn (AS2 (mov%L3,%2,%3), xops); /* Fast shift by 32 */
- output_asm_insn (AS2 (xor%L2,%2,%2), xops);
-
- if (INTVAL (xops[0]) > 32)
- {
- xops[0] = GEN_INT (INTVAL (xops[0]) - 32);
- output_asm_insn (AS2 (sal%L3,%0,%3), xops); /* Remaining shift */
- }
- }
- else
- {
- output_asm_insn (AS3 (shld%L3,%0,%2,%3), xops);
- output_asm_insn (AS2 (sal%L2,%0,%2), xops);
- }
- RET;
-}")
+ (match_operand:QI 2 "nonmemory_operand" "Jc")))
+ (clobber (match_scratch:SI 3 "=&r"))
+ (clobber (reg:CC 17))]
+ "TARGET_CMOVE"
+ "#"
+ [(set_attr "type" "multi")])
-(define_insn "ashldi3_non_const_int"
- [(set (match_operand:DI 0 "register_operand" "=&r")
+(define_insn "*ashldi3_2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (match_operand:DI 1 "register_operand" "0")
- (match_operand:QI 2 "register_operand" "c")))]
+ (match_operand:QI 2 "nonmemory_operand" "Jc")))
+ (clobber (reg:CC 17))]
""
- "*
-{
- rtx xops[5], low[1], high[1];
-
- CC_STATUS_INIT;
-
- split_di (operands, 1, low, high);
- xops[0] = operands[2];
- xops[1] = GEN_INT (32);
- xops[2] = low[0];
- xops[3] = high[0];
- xops[4] = gen_label_rtx ();
-
- output_asm_insn (AS3_SHIFT_DOUBLE (shld%L3,%0,%2,%3), xops);
- output_asm_insn (AS2 (sal%L2,%0,%2), xops);
- output_asm_insn (AS2 (test%B0,%1,%b0), xops);
- output_asm_insn (AS1 (je,%X4), xops);
- output_asm_insn (AS2 (mov%L3,%2,%3), xops); /* Fast shift by 32 */
- output_asm_insn (AS2 (xor%L2,%2,%2), xops);
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
- CODE_LABEL_NUMBER (xops[4]));
- RET;
-}")
+ "#"
+ [(set_attr "type" "multi")])
-(define_expand "ashlsi3"
- [(set (match_operand:SI 0 "nonimmediate_operand" "")
- (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "")
- (match_operand:SI 2 "nonmemory_operand" "")))]
- ""
- "")
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (ashift:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:QI 2 "nonmemory_operand" "")))
+ (clobber (match_scratch:SI 3 ""))
+ (clobber (reg:CC 17))]
+ "TARGET_CMOVE && cse_not_expected"
+ [(const_int 0)]
+ "ix86_split_ashldi (operands, operands[3]); DONE;")
-(define_expand "ashlhi3"
- [(set (match_operand:HI 0 "nonimmediate_operand" "")
- (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "")
- (match_operand:HI 2 "nonmemory_operand" "")))]
- ""
- "")
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (ashift:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:QI 2 "nonmemory_operand" "")))
+ (clobber (reg:CC 17))]
+ "cse_not_expected"
+ [(const_int 0)]
+ "ix86_split_ashldi (operands, NULL_RTX); DONE;")
-(define_expand "ashlqi3"
- [(set (match_operand:QI 0 "nonimmediate_operand" "")
- (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "")
- (match_operand:QI 2 "nonmemory_operand" "")))]
+(define_insn "x86_shld_1"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "+r*m,r*m")
+ (ior:SI (ashift:SI (match_dup 0)
+ (match_operand:QI 2 "nonmemory_operand" "I,c"))
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r")
+ (minus:QI (const_int 32) (match_dup 2)))))
+ (clobber (reg:CC 17))]
""
+ "@
+ shld{l}\\t{%2, %1, %0|%0, %1, %2}
+ shld{l}\\t{%s2%1, %0|%0, %1, %2}"
+ [(set_attr "type" "ishift")
+ (set_attr "length_opcode" "3")
+ (set_attr "pent_pair" "np")
+ (set_attr "ppro_uops" "few")])
+
+(define_expand "x86_shift_adj_1"
+ [(set (reg:CCNO 17)
+ (compare:CCNO (and:QI (match_operand:QI 2 "register_operand" "")
+ (const_int 32))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "")
+ (if_then_else:SI (ne (reg:CCNO 17) (const_int 0))
+ (match_operand:SI 1 "register_operand" "")
+ (match_dup 0)))
+ (set (match_dup 1)
+ (if_then_else:SI (ne (reg:CCNO 17) (const_int 0))
+ (match_operand:SI 3 "register_operand" "r")
+ (match_dup 1)))]
+ "TARGET_CMOVE"
"")
-;; Pattern for shifts which can be encoded into an lea instruction.
-;; This is kept as a separate pattern so that regmove can optimize cases
-;; where we know the source and destination must match.
-;;
-;; Do not expose this pattern when optimizing for size since we never want
-;; to use lea when optimizing for size since mov+sal is smaller than lea.
-
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r")
- (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0,r")
- (match_operand:SI 2 "small_shift_operand" "M,M")))]
- "! optimize_size"
- "* return output_ashl (insn, operands);")
-
-;; Generic left shift pattern to catch all cases not handled by the
-;; shift pattern above.
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
- (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0")
- (match_operand:SI 2 "nonmemory_operand" "cI")))]
- ""
- "* return output_ashl (insn, operands);")
-
-(define_insn ""
- [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r")
- (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0,r")
- (match_operand:HI 2 "small_shift_operand" "M,M")))]
- "! optimize_size"
- "* return output_ashl (insn, operands);")
-
-(define_insn ""
- [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
- (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0")
- (match_operand:HI 2 "nonmemory_operand" "cI")))]
+(define_expand "x86_shift_adj_2"
+ [(use (match_operand:SI 0 "register_operand" ""))
+ (use (match_operand:SI 1 "register_operand" ""))
+ (use (match_operand:QI 2 "register_operand" ""))]
""
- "* return output_ashl (insn, operands);")
+ "
+{
+ rtx label = gen_label_rtx ();
+ rtx tmp;
-(define_insn ""
- [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q")
- (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,q")
- (match_operand:QI 2 "small_shift_operand" "M,M")))]
- "! optimize_size"
- "* return output_ashl (insn, operands);")
+ emit_insn (gen_testqi_1 (operands[2], GEN_INT (32)));
-;; Generic left shift pattern to catch all cases not handled by the
-;; shift pattern above.
-(define_insn ""
- [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
- (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0")
- (match_operand:QI 2 "nonmemory_operand" "cI")))]
- ""
- "* return output_ashl (insn, operands);")
+ tmp = gen_rtx_REG (CCNOmode, FLAGS_REG);
+ tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode, label),
+ pc_rtx);
+ tmp = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
+ JUMP_LABEL (tmp) = label;
-;; See comment above `ashldi3' about how this works.
+ emit_move_insn (operands[0], operands[1]);
+ emit_move_insn (operands[1], const0_rtx);
-(define_expand "ashrdi3"
- [(set (match_operand:DI 0 "register_operand" "")
- (ashiftrt:DI (match_operand:DI 1 "register_operand" "")
- (match_operand:QI 2 "nonmemory_operand" "")))]
- ""
- "
-{
- if (GET_CODE (operands[2]) != CONST_INT
- || ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J'))
- {
- operands[2] = copy_to_mode_reg (QImode, operands[2]);
- emit_insn (gen_ashrdi3_non_const_int (operands[0], operands[1],
- operands[2]));
- }
- else
- emit_insn (gen_ashrdi3_const_int (operands[0], operands[1], operands[2]));
+ emit_label (label);
+ LABEL_NUSES (label) = 1;
DONE;
}")
-(define_insn "ashldi3_32"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=r,m")
- (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r")
- (const_int 32)))]
+(define_insn "ashlsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+ (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0,r")
+ (match_operand:QI 2 "nonmemory_operand" "cI,M")))
+ (clobber (reg:CC 17))]
""
"*
{
- rtx low[2], high[2], xops[4];
-
- split_di (operands, 2, low, high);
- xops[0] = high[0];
- xops[1] = low[1];
- xops[2] = low[0];
- xops[3] = const0_rtx;
- if (!rtx_equal_p (xops[0], xops[1]))
- output_asm_insn (AS2 (mov%L0,%1,%0), xops);
-
- if (GET_CODE (low[0]) == MEM)
- output_asm_insn (AS2 (mov%L2,%3,%2), xops);
- else
- output_asm_insn (AS2 (xor%L2,%2,%2), xops);
+ switch (get_attr_type (insn))
+ {
+ case TYPE_ALU:
+ if (operands[2] != const1_rtx)
+ abort ();
+ if (!rtx_equal_p (operands[0], operands[1]))
+ abort ();
+ return \"add{l}\\t{%0, %0|%0, %0}\";
- RET;
-}")
+ case TYPE_LEA:
+ if (GET_CODE (operands[2]) != CONST_INT
+ || (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 3)
+ abort ();
+ operands[1] = gen_rtx_MULT (SImode, operands[1],
+ GEN_INT (1 << INTVAL (operands[2])));
+ return \"lea{l}\\t{%a1, %0|%0, %a1}\";
-(define_insn "ashrdi3_const_int"
- [(set (match_operand:DI 0 "register_operand" "=&r")
- (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
- (match_operand:QI 2 "const_int_operand" "J")))]
- "CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')"
+ default:
+ if (REG_P (operands[2]))
+ return \"sal{l}\\t{%b2, %0|%0, %b2}\";
+ else
+ return \"sal{l}\\t{%2, %0|%0, %2}\";
+ }
+}"
+ [(set (attr "type")
+ (cond [(eq_attr "alternative" "1")
+ (const_string "lea")
+ (and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD")
+ (const_int 0))
+ (match_operand 0 "register_operand" ""))
+ (match_operand 2 "const1_operand" ""))
+ (const_string "alu")
+ ]
+ (const_string "ishift")))])
+
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0")
+ (match_operand:QI 2 "nonmemory_operand" "cI"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (ashift:SI (match_dup 1) (match_dup 2)))]
+ ""
"*
{
- rtx xops[4], low[1], high[1];
-
- CC_STATUS_INIT;
-
- split_di (operands, 1, low, high);
- xops[0] = operands[2];
- xops[1] = const1_rtx;
- xops[2] = low[0];
- xops[3] = high[0];
-
- if (INTVAL (xops[0]) > 31)
+ switch (get_attr_type (insn))
{
- xops[1] = GEN_INT (31);
- output_asm_insn (AS2 (mov%L2,%3,%2), xops);
- output_asm_insn (AS2 (sar%L3,%1,%3), xops); /* shift by 32 */
+ case TYPE_ALU:
+ if (operands[2] != const1_rtx)
+ abort ();
+ return \"add{l}\\t{%0, %0|%0, %0}\";
- if (INTVAL (xops[0]) > 32)
- {
- xops[0] = GEN_INT (INTVAL (xops[0]) - 32);
- output_asm_insn (AS2 (sar%L2,%0,%2), xops); /* Remaining shift */
- }
- }
- else
- {
- output_asm_insn (AS3 (shrd%L2,%0,%3,%2), xops);
- output_asm_insn (AS2 (sar%L3,%0,%3), xops);
+ default:
+ if (REG_P (operands[2]))
+ return \"sal{l}\\t{%b2, %0|%0, %b2}\";
+ else
+ return \"sal{l}\\t{%2, %0|%0, %2}\";
}
-
- RET;
-}")
-
-(define_insn "ashrdi3_non_const_int"
- [(set (match_operand:DI 0 "register_operand" "=&r")
- (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
- (match_operand:QI 2 "register_operand" "c")))]
+}"
+ [(set (attr "type")
+ (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD")
+ (const_int 0))
+ (match_operand 0 "register_operand" ""))
+ (match_operand 2 "const1_operand" ""))
+ (const_string "alu")
+ ]
+ (const_string "ishift")))])
+
+(define_insn "ashlhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0")
+ (match_operand:QI 2 "nonmemory_operand" "cI")))
+ (clobber (reg:CC 17))]
""
"*
{
- rtx xops[5], low[1], high[1];
-
- CC_STATUS_INIT;
-
- split_di (operands, 1, low, high);
- xops[0] = operands[2];
- xops[1] = GEN_INT (32);
- xops[2] = low[0];
- xops[3] = high[0];
- xops[4] = gen_label_rtx ();
-
- output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
- output_asm_insn (AS2 (sar%L3,%0,%3), xops);
- output_asm_insn (AS2 (test%B0,%1,%b0), xops);
- output_asm_insn (AS1 (je,%X4), xops);
- xops[1] = GEN_INT (31);
- output_asm_insn (AS2 (mov%L2,%3,%2), xops);
- output_asm_insn (AS2 (sar%L3,%1,%3), xops); /* shift by 32 */
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
- CODE_LABEL_NUMBER (xops[4]));
- RET;
-}")
+ switch (get_attr_type (insn))
+ {
+ case TYPE_ALU:
+ if (operands[2] != const1_rtx)
+ abort ();
+ return \"add{w}\\t{%0, %0|%0, %0}\";
-(define_insn "ashrsi3_31"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,d")
- (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,a")
- (const_int 31)))]
- "!TARGET_PENTIUM || optimize_size"
- "@
- sar%L0 $31,%0
- cltd")
+ default:
+ if (REG_P (operands[2]))
+ return \"sal{w}\\t{%b2, %0|%0, %b2}\";
+ else
+ return \"sal{w}\\t{%2, %0|%0, %2}\";
+ }
+}"
+ [(set (attr "type")
+ (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD")
+ (const_int 0))
+ (match_operand 0 "register_operand" ""))
+ (match_operand 2 "const1_operand" ""))
+ (const_string "alu")
+ ]
+ (const_string "ishift")))])
-(define_insn "ashrsi3"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
- (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
- (match_operand:SI 2 "nonmemory_operand" "cI")))]
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "")
+ (ashift:HI (match_operand:HI 1 "register_operand" "")
+ (match_operand:QI 2 "nonmemory_operand" "")))
+ (clobber (reg:CC 17))]
+ "! TARGET_PARTIAL_REG_STALL && reload_completed"
+ [(parallel [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC 17))])]
+ "operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);")
+
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0")
+ (match_operand:QI 2 "nonmemory_operand" "cI"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (ashift:HI (match_dup 1) (match_dup 2)))]
""
"*
{
- if (REG_P (operands[2]))
- return AS2 (sar%L0,%b2,%0);
- else
- return AS2 (sar%L0,%2,%0);
-}")
+ switch (get_attr_type (insn))
+ {
+ case TYPE_ALU:
+ if (operands[2] != const1_rtx)
+ abort ();
+ return \"add{w}\\t{%0, %0|%0, %0}\";
-(define_insn "ashrhi3"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
- (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
- (match_operand:HI 2 "nonmemory_operand" "cI")))]
+ default:
+ if (REG_P (operands[2]))
+ return \"sal{w}\\t{%b2, %0|%0, %b2}\";
+ else
+ return \"sal{w}\\t{%2, %0|%0, %2}\";
+ }
+}"
+ [(set (attr "type")
+ (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD")
+ (const_int 0))
+ (match_operand 0 "register_operand" ""))
+ (match_operand 2 "const1_operand" ""))
+ (const_string "alu")
+ ]
+ (const_string "ishift")))])
+
+;; %%% Potential partial reg stall on alternative 2. What to do?
+(define_insn "ashlqi3"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,*r")
+ (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "cI,cI")))
+ (clobber (reg:CC 17))]
""
"*
{
- if (REG_P (operands[2]))
- return AS2 (sar%W0,%b2,%0);
- else
- return AS2 (sar%W0,%2,%0);
-}")
+ switch (get_attr_type (insn))
+ {
+ case TYPE_ALU:
+ if (operands[2] != const1_rtx)
+ abort ();
+ if (NON_QI_REG_P (operands[1]))
+ return \"add{l}\\t{%k0, %k0|%k0, %k0}\";
+ else
+ return \"add{b}\\t{%0, %0|%0, %0}\";
-(define_insn "ashrqi3"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
- (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
- (match_operand:QI 2 "nonmemory_operand" "cI")))]
+ default:
+ if (REG_P (operands[2]))
+ {
+ if (NON_QI_REG_P (operands[1]))
+ return \"sal{l}\\t{%k2, %0|%0, %k2}\";
+ else
+ return \"sal{b}\\t{%b2, %0|%0, %b2}\";
+ }
+ else
+ {
+ if (NON_QI_REG_P (operands[1]))
+ return \"sal{b}\\t{%2, %k0|%k0, %2}\";
+ else
+ return \"sal{b}\\t{%2, %0|%0, %2}\";
+ }
+ }
+}"
+ [(set (attr "type")
+ (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD")
+ (const_int 0))
+ (match_operand 0 "register_operand" ""))
+ (match_operand 2 "const1_operand" ""))
+ (const_string "alu")
+ ]
+ (const_string "ishift")))])
+
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0")
+ (match_operand:QI 2 "nonmemory_operand" "cI"))
+ (const_int 0)))
+ (set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+ (ashift:QI (match_dup 1) (match_dup 2)))]
""
"*
{
- if (REG_P (operands[2]))
- return AS2 (sar%B0,%b2,%0);
- else
- return AS2 (sar%B0,%2,%0);
-}")
-
-;;- logical shift instructions
+ switch (get_attr_type (insn))
+ {
+ case TYPE_ALU:
+ if (operands[2] != const1_rtx)
+ abort ();
+ return \"add{b}\\t{%0, %0|%0, %0}\";
+
+ default:
+ if (REG_P (operands[2]))
+ return \"sal{b}\\t{%b2, %0|%0, %b2}\";
+ else
+ return \"sal{b}\\t{%2, %0|%0, %2}\";
+ }
+}"
+ [(set (attr "type")
+ (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD")
+ (const_int 0))
+ (match_operand 0 "register_operand" ""))
+ (match_operand 2 "const1_operand" ""))
+ (const_string "alu")
+ ]
+ (const_string "ishift")))])
;; See comment above `ashldi3' about how this works.
-(define_expand "lshrdi3"
- [(set (match_operand:DI 0 "register_operand" "")
- (lshiftrt:DI (match_operand:DI 1 "register_operand" "")
- (match_operand:QI 2 "nonmemory_operand" "")))]
+(define_expand "ashrdi3"
+ [(parallel [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
+ (match_operand:QI 2 "nonmemory_operand" "Jc")))
+ (clobber (reg:CC 17))])]
""
"
{
- if (GET_CODE (operands[2]) != CONST_INT
- || ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J'))
+ if (TARGET_CMOVE && ! immediate_operand (operands[2], QImode))
{
- operands[2] = copy_to_mode_reg (QImode, operands[2]);
- emit_insn (gen_lshrdi3_non_const_int (operands[0], operands[1],
- operands[2]));
+ emit_insn (gen_ashrdi3_1 (operands[0], operands[1], operands[2]));
+ DONE;
}
- else
- emit_insn (gen_lshrdi3_const_int (operands[0], operands[1], operands[2]));
-
- DONE;
}")
-(define_insn "lshrdi3_32"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=r,m")
- (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r")
- (const_int 32)))]
+(define_insn "ashrdi3_1"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
+ (match_operand:QI 2 "nonmemory_operand" "Jc")))
+ (clobber (match_scratch:SI 3 "=&r"))
+ (clobber (reg:CC 17))]
+ "TARGET_CMOVE"
+ "#"
+ [(set_attr "type" "multi")])
+
+(define_insn "*ashrdi3_2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
+ (match_operand:QI 2 "nonmemory_operand" "Jc")))
+ (clobber (reg:CC 17))]
""
- "*
-{
- rtx low[2], high[2], xops[4];
-
- split_di (operands, 2, low, high);
- xops[0] = low[0];
- xops[1] = high[1];
- xops[2] = high[0];
- xops[3] = const0_rtx;
- if (!rtx_equal_p (xops[0], xops[1]))
- output_asm_insn (AS2 (mov%L0,%1,%0), xops);
-
- if (GET_CODE (low[0]) == MEM)
- output_asm_insn (AS2 (mov%L2,%3,%2), xops);
- else
- output_asm_insn (AS2 (xor%L2,%2,%2), xops);
+ "#"
+ [(set_attr "type" "multi")])
- RET;
-}")
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (ashiftrt:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:QI 2 "nonmemory_operand" "")))
+ (clobber (match_scratch:SI 3 ""))
+ (clobber (reg:CC 17))]
+ "TARGET_CMOVE && cse_not_expected"
+ [(const_int 0)]
+ "ix86_split_ashrdi (operands, operands[3]); DONE;")
-(define_insn "lshrdi3_const_int"
- [(set (match_operand:DI 0 "register_operand" "=&r")
- (lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
- (match_operand:QI 2 "const_int_operand" "J")))]
- "CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')"
- "*
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (ashiftrt:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:QI 2 "nonmemory_operand" "")))
+ (clobber (reg:CC 17))]
+ "cse_not_expected"
+ [(const_int 0)]
+ "ix86_split_ashrdi (operands, NULL_RTX); DONE;")
+
+(define_insn "x86_shrd_1"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "+r*m,r*m")
+ (ior:SI (ashiftrt:SI (match_dup 0)
+ (match_operand:QI 2 "nonmemory_operand" "I,c"))
+ (ashift:SI (match_operand:SI 1 "register_operand" "r,r")
+ (minus:QI (const_int 32) (match_dup 2)))))
+ (clobber (reg:CC 17))]
+ ""
+ "@
+ shrd{l}\\t{%2, %1, %0|%0, %1, %2}
+ shrd{l}\\t{%s2%1, %0|%0, %1, %2}"
+ [(set_attr "type" "ishift")
+ (set_attr "length_opcode" "3")
+ (set_attr "pent_pair" "np")
+ (set_attr "ppro_uops" "few")])
+
+(define_expand "x86_shift_adj_3"
+ [(use (match_operand:SI 0 "register_operand" ""))
+ (use (match_operand:SI 1 "register_operand" ""))
+ (use (match_operand:QI 2 "register_operand" ""))]
+ ""
+ "
{
- rtx xops[4], low[1], high[1];
+ rtx label = gen_label_rtx ();
+ rtx tmp;
- CC_STATUS_INIT;
+ emit_insn (gen_testqi_1 (operands[2], GEN_INT (32)));
- split_di (operands, 1, low, high);
- xops[0] = operands[2];
- xops[1] = const1_rtx;
- xops[2] = low[0];
- xops[3] = high[0];
+ tmp = gen_rtx_REG (CCNOmode, FLAGS_REG);
+ tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode, label),
+ pc_rtx);
+ tmp = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
+ JUMP_LABEL (tmp) = label;
- if (INTVAL (xops[0]) > 31)
- {
- output_asm_insn (AS2 (mov%L2,%3,%2), xops); /* Fast shift by 32 */
- output_asm_insn (AS2 (xor%L3,%3,%3), xops);
+ emit_move_insn (operands[0], operands[1]);
+ emit_insn (gen_ashrsi3_31 (operands[1], operands[1], GEN_INT (31)));
- if (INTVAL (xops[0]) > 32)
- {
- xops[0] = GEN_INT (INTVAL (xops[0]) - 32);
- output_asm_insn (AS2 (shr%L2,%0,%2), xops); /* Remaining shift */
- }
- }
- else
- {
- output_asm_insn (AS3 (shrd%L2,%0,%3,%2), xops);
- output_asm_insn (AS2 (shr%L3,%0,%3), xops);
- }
-
- RET;
-}")
+ emit_label (label);
+ LABEL_NUSES (label) = 1;
-(define_insn "lshrdi3_non_const_int"
- [(set (match_operand:DI 0 "register_operand" "=&r")
- (lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
- (match_operand:QI 2 "register_operand" "c")))]
- ""
- "*
-{
- rtx xops[5], low[1], high[1];
-
- CC_STATUS_INIT;
-
- split_di (operands, 1, low, high);
- xops[0] = operands[2];
- xops[1] = GEN_INT (32);
- xops[2] = low[0];
- xops[3] = high[0];
- xops[4] = gen_label_rtx ();
-
- output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
- output_asm_insn (AS2 (shr%L3,%0,%3), xops);
- output_asm_insn (AS2 (test%B0,%1,%b0), xops);
- output_asm_insn (AS1 (je,%X4), xops);
- output_asm_insn (AS2 (mov%L2,%3,%2), xops); /* Fast shift by 32 */
- output_asm_insn (AS2 (xor%L3,%3,%3), xops);
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
- CODE_LABEL_NUMBER (xops[4]));
- RET;
+ DONE;
}")
-(define_insn "lshrsi3"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
- (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
- (match_operand:SI 2 "nonmemory_operand" "cI")))]
- ""
- "*
-{
- if (REG_P (operands[2]))
- return AS2 (shr%L0,%b2,%0);
- else
- return AS2 (shr%L0,%2,%1);
-}")
+(define_insn "ashrsi3_31"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=*d,rm")
+ (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "*a,0")
+ (match_operand:SI 2 "const_int_operand" "i,i")))
+ (clobber (reg:CC 17))]
+ "INTVAL (operands[2]) == 31"
+ "@
+ {cltd|cdq}
+ sar{l}\\t{%2, %0|%0, %2}"
+ [(set_attr "type" "imovx,ishift")
+ (set_attr "length" "1,*")])
-(define_insn "lshrhi3"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
- (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
- (match_operand:HI 2 "nonmemory_operand" "cI")))]
+(define_insn "ashrsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
+ (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c")))
+ (clobber (reg:CC 17))]
""
- "*
-{
- if (REG_P (operands[2]))
- return AS2 (shr%W0,%b2,%0);
- else
- return AS2 (shr%W0,%2,%0);
-}")
+ "@
+ sar{l}\\t{%2, %0|%0, %2}
+ sar{l}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
-(define_insn "lshrqi3"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
- (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
- (match_operand:QI 2 "nonmemory_operand" "cI")))]
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
+ (ashiftrt:SI (match_dup 1) (match_dup 2)))]
""
- "*
-{
- if (REG_P (operands[2]))
- return AS2 (shr%B0,%b2,%0);
- else
- return AS2 (shr%B0,%2,%0);
-}")
-
-;;- rotate instructions
+ "@
+ sar{l}\\t{%2, %0|%0, %2}
+ sar{l}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
-(define_insn "rotlsi3"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
- (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0")
- (match_operand:SI 2 "nonmemory_operand" "cI")))]
+(define_insn "ashrhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
+ (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c")))
+ (clobber (reg:CC 17))]
""
- "*
-{
- if (REG_P (operands[2]))
- return AS2 (rol%L0,%b2,%0);
- else
- return AS2 (rol%L0,%2,%0);
-}")
+ "@
+ sar{w}\\t{%2, %0|%0, %2}
+ sar{w}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
-(define_insn "rotlhi3"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
- (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0")
- (match_operand:HI 2 "nonmemory_operand" "cI")))]
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
+ (ashiftrt:HI (match_dup 1) (match_dup 2)))]
""
- "*
-{
- if (REG_P (operands[2]))
- return AS2 (rol%W0,%b2,%0);
- else
- return AS2 (rol%W0,%2,%0);
-}")
+ "@
+ sar{w}\\t{%2, %0|%0, %2}
+ sar{w}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
-(define_insn "rotlqi3"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
- (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0")
- (match_operand:QI 2 "nonmemory_operand" "cI")))]
+(define_insn "ashrqi3"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm")
+ (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c")))
+ (clobber (reg:CC 17))]
""
- "*
-{
- if (REG_P (operands[2]))
- return AS2 (rol%B0,%b2,%0);
- else
- return AS2 (rol%B0,%2,%0);
-}")
+ "@
+ sar{b}\\t{%2, %0|%0, %2}
+ sar{b}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
-(define_insn "rotrsi3"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
- (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0")
- (match_operand:SI 2 "nonmemory_operand" "cI")))]
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c"))
+ (const_int 0)))
+ (set (match_operand:QI 0 "nonimmediate_operand" "=rm,rm")
+ (ashiftrt:QI (match_dup 1) (match_dup 2)))]
""
- "*
-{
- if (REG_P (operands[2]))
- return AS2 (ror%L0,%b2,%0);
- else
- return AS2 (ror%L0,%2,%0);
-}")
+ "@
+ sar{b}\\t{%2, %0|%0, %2}
+ sar{b}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
+
+;; Logical shift instructions
-(define_insn "rotrhi3"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
- (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0")
- (match_operand:HI 2 "nonmemory_operand" "cI")))]
- ""
- "*
-{
- if (REG_P (operands[2]))
- return AS2 (ror%W0,%b2,%0);
- else
- return AS2 (ror%W0,%2,%0);
-}")
+;; See comment above `ashldi3' about how this works.
-(define_insn "rotrqi3"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
- (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0")
- (match_operand:QI 2 "nonmemory_operand" "cI")))]
- ""
- "*
-{
- if (REG_P (operands[2]))
- return AS2 (ror%B0,%b2,%0);
- else
- return AS2 (ror%B0,%2,%0);
-}")
-
-/*
-;; This usually looses. But try a define_expand to recognize a few case
-;; we can do efficiently, such as accessing the "high" QImode registers,
-;; %ah, %bh, %ch, %dh.
-;; ??? Note this has a botch on the mode of operand 0, which needs to be
-;; fixed if this is ever enabled.
-(define_insn "insv"
- [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+&r")
- (match_operand:SI 1 "immediate_operand" "i")
- (match_operand:SI 2 "immediate_operand" "i"))
- (match_operand:SI 3 "nonmemory_operand" "ri"))]
+(define_expand "lshrdi3"
+ [(parallel [(set (match_operand:DI 0 "register_operand" "=r")
+ (lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
+ (match_operand:QI 2 "nonmemory_operand" "Jc")))
+ (clobber (reg:CC 17))])]
""
- "*
+ "
{
- if (INTVAL (operands[1]) + INTVAL (operands[2]) > GET_MODE_BITSIZE (SImode))
- abort ();
- if (GET_CODE (operands[3]) == CONST_INT)
+ if (TARGET_CMOVE && ! immediate_operand (operands[2], QImode))
{
- unsigned int mask = (1 << INTVAL (operands[1])) - 1;
- operands[1] = GEN_INT (~(mask << INTVAL (operands[2])));
- output_asm_insn (AS2 (and%L0,%1,%0), operands);
- operands[3] = GEN_INT (INTVAL (operands[3]) << INTVAL (operands[2]));
- output_asm_insn (AS2 (or%L0,%3,%0), operands);
- }
- else
- {
- operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
- if (INTVAL (operands[2]))
- output_asm_insn (AS2 (ror%L0,%2,%0), operands);
- output_asm_insn (AS3 (shrd%L0,%1,%3,%0), operands);
- operands[2] = GEN_INT (BITS_PER_WORD
- - INTVAL (operands[1]) - INTVAL (operands[2]));
- if (INTVAL (operands[2]))
- output_asm_insn (AS2 (ror%L0,%2,%0), operands);
+ emit_insn (gen_lshrdi3_1 (operands[0], operands[1], operands[2]));
+ DONE;
}
- RET;
}")
-*/
-/*
-;; ??? There are problems with the mode of operand[3]. The point of this
-;; is to represent an HImode move to a "high byte" register.
-(define_expand "insv"
- [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "")
- (match_operand:SI 1 "immediate_operand" "")
- (match_operand:SI 2 "immediate_operand" ""))
- (match_operand:QI 3 "nonmemory_operand" "ri"))]
- ""
- "
-{
- if (GET_CODE (operands[1]) != CONST_INT
- || GET_CODE (operands[2]) != CONST_INT)
- FAIL;
+(define_insn "lshrdi3_1"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
+ (match_operand:QI 2 "nonmemory_operand" "Jc")))
+ (clobber (match_scratch:SI 3 "=&r"))
+ (clobber (reg:CC 17))]
+ "TARGET_CMOVE"
+ "#"
+ [(set_attr "type" "multi")])
- if (! (INTVAL (operands[1]) == 8
- && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 0))
- && ! INTVAL (operands[1]) == 1)
- FAIL;
-}")
-*/
+(define_insn "*lshrdi3_2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
+ (match_operand:QI 2 "nonmemory_operand" "Jc")))
+ (clobber (reg:CC 17))]
+ ""
+ "#"
+ [(set_attr "type" "multi")])
-;; On i386, the register count for a bit operation is *not* truncated,
-;; so SHIFT_COUNT_TRUNCATED must not be defined.
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (lshiftrt:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:QI 2 "nonmemory_operand" "")))
+ (clobber (match_scratch:SI 3 ""))
+ (clobber (reg:CC 17))]
+ "TARGET_CMOVE && cse_not_expected"
+ [(const_int 0)]
+ "ix86_split_lshrdi (operands, operands[3]); DONE;")
-;; On i486, the shift & or/and code is faster than bts or btr. If
-;; operands[0] is a MEM, the bt[sr] is half as fast as the normal code.
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (lshiftrt:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:QI 2 "nonmemory_operand" "")))
+ (clobber (reg:CC 17))]
+ "cse_not_expected"
+ [(const_int 0)]
+ "ix86_split_lshrdi (operands, NULL_RTX); DONE;")
-;; On i386, bts is a little faster if operands[0] is a reg, and a
-;; little slower if operands[0] is a MEM, than the shift & or/and code.
-;; Use bts & btr, since they reload better.
+(define_insn "lshrsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
+ (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c")))
+ (clobber (reg:CC 17))]
+ ""
+ "@
+ shr{l}\\t{%2, %0|%0, %2}
+ shr{l}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
-;; General bit set and clear.
(define_insn ""
- [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+rm")
- (const_int 1)
- (match_operand:SI 2 "register_operand" "r"))
- (match_operand:SI 3 "const_int_operand" "n"))]
- "TARGET_USE_BIT_TEST && GET_CODE (operands[2]) != CONST_INT"
- "*
-{
- CC_STATUS_INIT;
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
+ (lshiftrt:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ shr{l}\\t{%2, %0|%0, %2}
+ shr{l}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
- if (INTVAL (operands[3]) == 1)
- return AS2 (bts%L0,%2,%0);
- else
- return AS2 (btr%L0,%2,%0);
-}")
+(define_insn "lshrhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
+ (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c")))
+ (clobber (reg:CC 17))]
+ ""
+ "@
+ shr{w}\\t{%2, %0|%0, %2}
+ shr{w}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
-;; Bit complement. See comments on previous pattern.
-;; ??? Is this really worthwhile?
(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
- (xor:SI (ashift:SI (const_int 1)
- (match_operand:SI 1 "register_operand" "r"))
- (match_operand:SI 2 "nonimmediate_operand" "0")))]
- "TARGET_USE_BIT_TEST && GET_CODE (operands[1]) != CONST_INT"
- "*
-{
- CC_STATUS_INIT;
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
+ (lshiftrt:HI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ shr{w}\\t{%2, %0|%0, %2}
+ shr{w}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
- return AS2 (btc%L0,%1,%0);
-}")
+(define_insn "lshrqi3"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm")
+ (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c")))
+ (clobber (reg:CC 17))]
+ ""
+ "@
+ shr{b}\\t{%2, %0|%0, %2}
+ shr{b}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
- (xor:SI (match_operand:SI 1 "nonimmediate_operand" "0")
- (ashift:SI (const_int 1)
- (match_operand:SI 2 "register_operand" "r"))))]
- "TARGET_USE_BIT_TEST && GET_CODE (operands[2]) != CONST_INT"
- "*
-{
- CC_STATUS_INIT;
-
- return AS2 (btc%L0,%2,%0);
-}")
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c"))
+ (const_int 0)))
+ (set (match_operand:QI 0 "nonimmediate_operand" "=rm,rm")
+ (lshiftrt:QI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ shr{b}\\t{%2, %0|%0, %2}
+ shr{b}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
-;; Recognizers for bit-test instructions.
-
-;; The bt opcode allows a MEM in operands[0]. But on both i386 and
-;; i486, it is faster to copy a MEM to REG and then use bt, than to use
-;; bt on the MEM directly.
+;; Rotate instructions
-;; ??? The first argument of a zero_extract must not be reloaded, so
-;; don't allow a MEM in the operand predicate without allowing it in the
-;; constraint.
+(define_insn "rotlsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
+ (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c")))
+ (clobber (reg:CC 17))]
+ ""
+ "@
+ rol{l}\\t{%2, %0|%0, %2}
+ rol{l}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
(define_insn ""
- [(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "r")
- (const_int 1)
- (match_operand:SI 1 "register_operand" "r")))]
- "GET_CODE (operands[1]) != CONST_INT"
- "*
-{
- cc_status.flags |= CC_Z_IN_NOT_C;
- return AS2 (bt%L0,%1,%0);
-}")
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
+ (rotate:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ rol{l}\\t{%2, %0|%0, %2}
+ rol{l}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
+
+(define_insn "rotlhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
+ (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c")))
+ (clobber (reg:CC 17))]
+ ""
+ "@
+ rol{w}\\t{%2, %0|%0, %2}
+ rol{w}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
(define_insn ""
- [(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "r")
- (match_operand:SI 1 "const_int_operand" "n")
- (match_operand:SI 2 "const_int_operand" "n")))]
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
+ (rotate:HI (match_dup 1) (match_dup 2)))]
""
- "*
-{
- unsigned int mask;
+ "@
+ rol{w}\\t{%2, %0|%0, %2}
+ rol{w}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
- mask = ((1 << INTVAL (operands[1])) - 1) << INTVAL (operands[2]);
- operands[1] = GEN_INT (mask);
+(define_insn "rotlqi3"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm")
+ (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c")))
+ (clobber (reg:CC 17))]
+ ""
+ "@
+ rol{b}\\t{%2, %0|%0, %2}
+ rol{b}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
- if (QI_REG_P (operands[0])
- /* A Pentium test is pairable only with eax. Not with ah or al. */
- && (! REG_P (operands[0]) || REGNO (operands[0]) || !TARGET_PENTIUM
- || optimize_size))
- {
- if ((mask & ~0xff) == 0)
- {
- cc_status.flags |= CC_NOT_NEGATIVE;
- return AS2 (test%B0,%1,%b0);
- }
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c"))
+ (const_int 0)))
+ (set (match_operand:QI 0 "nonimmediate_operand" "=rm,rm")
+ (rotate:QI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ rol{b}\\t{%2, %0|%0, %2}
+ rol{b}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
- if ((mask & ~0xff00) == 0)
- {
- cc_status.flags |= CC_NOT_NEGATIVE;
- operands[1] = GEN_INT (mask >> 8);
- return AS2 (test%B0,%1,%h0);
- }
- }
+(define_insn "rotrsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
+ (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c")))
+ (clobber (reg:CC 17))]
+ ""
+ "@
+ ror{l}\\t{%2, %0|%0, %2}
+ ror{l}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
- return AS2 (test%L0,%1,%0);
-}")
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
+ (rotatert:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ ror{l}\\t{%2, %0|%0, %2}
+ ror{l}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
-;; ??? All bets are off if operand 0 is a volatile MEM reference.
-;; The CPU may access unspecified bytes around the actual target byte.
+(define_insn "rotrhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
+ (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c")))
+ (clobber (reg:CC 17))]
+ ""
+ "@
+ ror{w}\\t{%2, %0|%0, %2}
+ ror{w}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
(define_insn ""
- [(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "m")
- (match_operand:SI 1 "const_int_operand" "n")
- (match_operand:SI 2 "const_int_operand" "n")))]
- "GET_CODE (operands[0]) != MEM || ! MEM_VOLATILE_P (operands[0])"
- "*
-{
- unsigned int mask;
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
+ (rotatert:HI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ ror{w}\\t{%2, %0|%0, %2}
+ ror{w}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
- mask = ((1 << INTVAL (operands[1])) - 1) << INTVAL (operands[2]);
- operands[1] = GEN_INT (mask);
+(define_insn "rotrqi3"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm")
+ (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c")))
+ (clobber (reg:CC 17))]
+ ""
+ "@
+ ror{b}\\t{%2, %0|%0, %2}
+ ror{b}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
- if ((! REG_P (operands[0]) || QI_REG_P (operands[0]))
- /* A Pentium test is pairable only with eax. Not with ah or al. */
- && (! REG_P (operands[0]) || REGNO (operands[0]) || !TARGET_PENTIUM
- || optimize_size))
- {
- if ((mask & ~0xff) == 0)
- {
- cc_status.flags |= CC_NOT_NEGATIVE;
- return AS2 (test%B0,%1,%b0);
- }
+(define_insn ""
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "I,c"))
+ (const_int 0)))
+ (set (match_operand:QI 0 "nonimmediate_operand" "=rm,rm")
+ (rotatert:QI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ ror{b}\\t{%2, %0|%0, %2}
+ ror{b}\\t{%b2, %0|%0, %b2}"
+ [(set_attr "type" "ishift")])
+
+;; Bit set / bit test instructions
- if ((mask & ~0xff00) == 0)
- {
- cc_status.flags |= CC_NOT_NEGATIVE;
- operands[1] = GEN_INT (mask >> 8);
+(define_expand "extv"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (sign_extract:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "immediate_operand" "")
+ (match_operand:SI 3 "immediate_operand" "")))]
+ ""
+ "
+{
+ /* Handle extractions from %ah et al. */
+ if (INTVAL (operands[2]) != 8 || INTVAL (operands[3]) != 8)
+ FAIL;
- if (QI_REG_P (operands[0]))
- return AS2 (test%B0,%1,%h0);
- else
- {
- operands[0] = adj_offsettable_operand (operands[0], 1);
- return AS2 (test%B0,%1,%b0);
- }
- }
+ /* From mips.md: extract_bit_field doesn't verify that our source
+ matches the predicate, so check it again here. */
+ if (! register_operand (operands[1], VOIDmode))
+ FAIL;
+}")
- if (GET_CODE (operands[0]) == MEM && (mask & ~0xff0000) == 0)
- {
- cc_status.flags |= CC_NOT_NEGATIVE;
- operands[1] = GEN_INT (mask >> 16);
- operands[0] = adj_offsettable_operand (operands[0], 2);
- return AS2 (test%B0,%1,%b0);
- }
+(define_expand "extzv"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extract:SI (match_operand 1 "ext_register_operand" "")
+ (match_operand:SI 2 "immediate_operand" "")
+ (match_operand:SI 3 "immediate_operand" "")))]
+ ""
+ "
+{
+ /* Handle extractions from %ah et al. */
+ if (INTVAL (operands[2]) != 8 || INTVAL (operands[3]) != 8)
+ FAIL;
- if (GET_CODE (operands[0]) == MEM && (mask & ~0xff000000) == 0)
- {
- cc_status.flags |= CC_NOT_NEGATIVE;
- operands[1] = GEN_INT (mask >> 24);
- operands[0] = adj_offsettable_operand (operands[0], 3);
- return AS2 (test%B0,%1,%b0);
- }
- }
+ /* From mips.md: extract_bit_field doesn't verify that our source
+ matches the predicate, so check it again here. */
+ if (! register_operand (operands[1], VOIDmode))
+ FAIL;
+}")
- if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
- return AS2 (test%L0,%1,%0);
+(define_expand "insv"
+ [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "")
+ (match_operand:SI 1 "immediate_operand" "")
+ (match_operand:SI 2 "immediate_operand" ""))
+ (match_operand:SI 3 "register_operand" ""))]
+ ""
+ "
+{
+ /* Handle extractions from %ah et al. */
+ if (INTVAL (operands[1]) != 8 || INTVAL (operands[2]) != 8)
+ FAIL;
- return AS2 (test%L1,%0,%1);
+ /* From mips.md: insert_bit_field doesn't verify that our source
+ matches the predicate, so check it again here. */
+ if (! register_operand (operands[0], VOIDmode))
+ FAIL;
}")
+
+;; %%% bts, btr, btc, bt.
;; Store-flag instructions.
;; For all sCOND expanders, also expand the compare or test insn that
;; generates cc0. Generate an equality comparison if `seq' or `sne'.
+;; %%% Do the expansion to SImode. If PII, do things the xor+setcc way
+;; to avoid partial register stalls. Otherwise do things the setcc+movzx
+;; way, which can later delete the movzx if only QImode is needed.
+
(define_expand "seq"
- [(match_dup 1)
- (set (match_operand:QI 0 "register_operand" "")
- (eq:QI (cc0) (const_int 0)))]
+ [(set (match_operand:SI 0 "register_operand" "")
+ (eq:SI (reg:CC 17) (const_int 0)))]
""
- "
-{
- if (TARGET_IEEE_FP
- && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
- operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
- else
- operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
-}")
+ "if (ix86_expand_setcc (EQ, 1, operands[0])) DONE; else FAIL;")
(define_expand "sne"
- [(match_dup 1)
- (set (match_operand:QI 0 "register_operand" "")
- (ne:QI (cc0) (const_int 0)))]
+ [(set (match_operand:SI 0 "register_operand" "")
+ (ne:SI (reg:CC 17) (const_int 0)))]
""
- "
-{
- if (TARGET_IEEE_FP
- && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
- operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
- else
- operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
-}")
+ "if (ix86_expand_setcc (NE, 1, operands[0])) DONE; else FAIL;")
(define_expand "sgt"
- [(match_dup 1)
- (set (match_operand:QI 0 "register_operand" "")
- (gt:QI (cc0) (const_int 0)))]
+ [(set (match_operand:SI 0 "register_operand" "")
+ (gt:SI (reg:CC 17) (const_int 0)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+ "if (ix86_expand_setcc (GT, 0, operands[0])) DONE; else FAIL;")
(define_expand "sgtu"
- [(match_dup 1)
- (set (match_operand:QI 0 "register_operand" "")
- (gtu:QI (cc0) (const_int 0)))]
+ [(set (match_operand:SI 0 "register_operand" "")
+ (gtu:SI (reg:CC 17) (const_int 0)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+ "if (ix86_expand_setcc (GTU, 0, operands[0])) DONE; else FAIL;")
(define_expand "slt"
- [(match_dup 1)
- (set (match_operand:QI 0 "register_operand" "")
- (lt:QI (cc0) (const_int 0)))]
+ [(set (match_operand:SI 0 "register_operand" "")
+ (lt:SI (reg:CC 17) (const_int 0)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+ "if (ix86_expand_setcc (LT, 0, operands[0])) DONE; else FAIL;")
(define_expand "sltu"
- [(match_dup 1)
- (set (match_operand:QI 0 "register_operand" "")
- (ltu:QI (cc0) (const_int 0)))]
+ [(set (match_operand:SI 0 "register_operand" "")
+ (ltu:SI (reg:CC 17) (const_int 0)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+ "if (ix86_expand_setcc (LTU, 0, operands[0])) DONE; else FAIL;")
(define_expand "sge"
- [(match_dup 1)
- (set (match_operand:QI 0 "register_operand" "")
- (ge:QI (cc0) (const_int 0)))]
+ [(set (match_operand:SI 0 "register_operand" "")
+ (ge:SI (reg:CC 17) (const_int 0)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+ "if (ix86_expand_setcc (GE, 0, operands[0])) DONE; else FAIL;")
(define_expand "sgeu"
- [(match_dup 1)
- (set (match_operand:QI 0 "register_operand" "")
- (geu:QI (cc0) (const_int 0)))]
+ [(set (match_operand:SI 0 "register_operand" "")
+ (geu:SI (reg:CC 17) (const_int 0)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+ "if (ix86_expand_setcc (GEU, 0, operands[0])) DONE; else FAIL;")
(define_expand "sle"
- [(match_dup 1)
- (set (match_operand:QI 0 "register_operand" "")
- (le:QI (cc0) (const_int 0)))]
+ [(set (match_operand:SI 0 "register_operand" "")
+ (le:SI (reg:CC 17) (const_int 0)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+ "if (ix86_expand_setcc (LE, 0, operands[0])) DONE; else FAIL;")
(define_expand "sleu"
- [(match_dup 1)
- (set (match_operand:QI 0 "register_operand" "")
- (leu:QI (cc0) (const_int 0)))]
+ [(set (match_operand:SI 0 "register_operand" "")
+ (leu:SI (reg:CC 17) (const_int 0)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+ "if (ix86_expand_setcc (LEU, 0, operands[0])) DONE; else FAIL;")
-;; The 386 sCOND opcodes can write to memory. But a gcc sCOND insn may
-;; not have any input reloads. A MEM write might need an input reload
-;; for the address of the MEM. So don't allow MEM as the SET_DEST.
-
-(define_insn "*setcc"
+(define_insn "*setcc_1"
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
- (match_operator:QI 1 "comparison_operator" [(cc0) (const_int 0)]))]
- "reload_completed || register_operand (operands[0], QImode)"
- "*
-{
- enum rtx_code code = GET_CODE (operands[1]);
- if (cc_prev_status.flags & CC_TEST_AX)
- {
- int eq;
- HOST_WIDE_INT c;
- operands[2] = gen_rtx_REG (SImode, 0);
- switch (code)
- {
- case EQ:
- c = 0x4000;
- eq = 0;
- break;
- case NE:
- c = 0x4000;
- eq = 1;
- break;
- case GT:
- c = 0x4100;
- eq = 1;
- break;
- case LT:
- c = 0x100;
- eq = 0;
- break;
- case GE:
- c = 0x100;
- eq = 1;
- break;
- case LE:
- c = 0x4100;
- eq = 0;
- break;
- default:
- abort ();
- }
- if (!TARGET_PENTIUM || optimize_size)
- {
- operands[3] = GEN_INT (c >> 8);
- output_asm_insn (AS2 (test%B0,%3,%h2), operands);
- }
- else
- {
- operands[3] = GEN_INT (c);
- output_asm_insn (AS2 (test%L0,%3,%2), operands);
- }
- return eq ? AS1 (sete,%0) : AS1 (setne, %0);
- }
+ (match_operator:QI 1 "no_comparison_operator"
+ [(reg 17) (const_int 0)]))]
+ ""
+ "set%C1\\t%0"
+ [(set_attr "type" "setcc")])
- if ((cc_status.flags & CC_NO_OVERFLOW) && (code == LE || code == GT))
- return (char *)0;
- return AS1(set%D1,%0);
-}")
+(define_insn "*setcc_2"
+ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm"))
+ (match_operator:QI 1 "no_comparison_operator"
+ [(reg 17) (const_int 0)]))]
+ ""
+ "set%C1\\t%0"
+ [(set_attr "type" "setcc")])
+(define_insn "*setcc_3"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+ (match_operator:QI 1 "comparison_operator"
+ [(reg:CC 17) (const_int 0)]))]
+ ""
+ "set%C1\\t%0"
+ [(set_attr "type" "setcc")])
+
+(define_insn "*setcc_4"
+ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm"))
+ (match_operator:QI 1 "comparison_operator"
+ [(reg:CC 17) (const_int 0)]))]
+ ""
+ "set%C1\\t%0"
+ [(set_attr "type" "setcc")])
;; Basic conditional jump instructions.
;; We ignore the overflow flag for signed branch instructions.
;; For all bCOND expanders, also expand the compare or test insn that
-;; generates cc0. Generate an equality comparison if `beq' or `bne'.
+;; generates reg 17. Generate an equality comparison if `beq' or `bne'.
(define_expand "beq"
- [(match_dup 1)
- (set (pc)
- (if_then_else (eq (cc0)
- (const_int 0))
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "
-{
- if (TARGET_IEEE_FP
- && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
- operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
- else
- operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
-}")
+ "ix86_expand_branch (EQ, 1, operands[0]); DONE;")
(define_expand "bne"
- [(match_dup 1)
- (set (pc)
- (if_then_else (ne (cc0)
- (const_int 0))
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "
-{
- if (TARGET_IEEE_FP
- && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
- operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
- else
- operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
-}")
-
+ "ix86_expand_branch (NE, 1, operands[0]); DONE;")
(define_expand "bgt"
- [(match_dup 1)
- (set (pc)
- (if_then_else (gt (cc0)
- (const_int 0))
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+ "ix86_expand_branch (GT, 0, operands[0]); DONE;")
(define_expand "bgtu"
- [(match_dup 1)
- (set (pc)
- (if_then_else (gtu (cc0)
- (const_int 0))
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+ "ix86_expand_branch (GTU, 0, operands[0]); DONE;")
(define_expand "blt"
- [(match_dup 1)
- (set (pc)
- (if_then_else (lt (cc0)
- (const_int 0))
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
-
+ "ix86_expand_branch (LT, 0, operands[0]); DONE;")
(define_expand "bltu"
- [(match_dup 1)
- (set (pc)
- (if_then_else (ltu (cc0)
- (const_int 0))
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+ "ix86_expand_branch (LTU, 0, operands[0]); DONE;")
(define_expand "bge"
- [(match_dup 1)
- (set (pc)
- (if_then_else (ge (cc0)
- (const_int 0))
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+ "ix86_expand_branch (GE, 0, operands[0]); DONE;")
(define_expand "bgeu"
- [(match_dup 1)
- (set (pc)
- (if_then_else (geu (cc0)
- (const_int 0))
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+ "ix86_expand_branch (GEU, 0, operands[0]); DONE;")
(define_expand "ble"
- [(match_dup 1)
- (set (pc)
- (if_then_else (le (cc0)
- (const_int 0))
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+ "ix86_expand_branch (LE, 0, operands[0]); DONE;")
(define_expand "bleu"
- [(match_dup 1)
- (set (pc)
- (if_then_else (leu (cc0)
- (const_int 0))
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
+ "ix86_expand_branch (LEU, 0, operands[0]); DONE;")
-(define_insn ""
+(define_insn "*jcc_1"
+ [(set (pc)
+ (if_then_else (match_operator 0 "no_comparison_operator"
+ [(reg 17) (const_int 0)])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ ""
+ "j%C0\\t%l1"
+ [(set_attr "type" "ibr")
+ (set (attr "length")
+ (if_then_else (and (ge (minus (match_dup 1) (pc))
+ (const_int -128))
+ (lt (minus (match_dup 1) (pc))
+ (const_int 124)))
+ (const_int 2)
+ (const_int 6)))])
+
+(define_insn "*jcc_2"
+ [(set (pc)
+ (if_then_else (match_operator 0 "no_comparison_operator"
+ [(reg 17) (const_int 0)])
+ (pc)
+ (label_ref (match_operand 1 "" ""))))]
+ ""
+ "j%c0\\t%l1"
+ [(set_attr "type" "ibr")
+ (set (attr "length")
+ (if_then_else (and (ge (minus (match_dup 1) (pc))
+ (const_int -128))
+ (lt (minus (match_dup 1) (pc))
+ (const_int 124)))
+ (const_int 2)
+ (const_int 6)))])
+
+(define_insn "*jcc_3"
[(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
- [(cc0) (const_int 0)])
+ [(reg:CC 17) (const_int 0)])
(label_ref (match_operand 1 "" ""))
(pc)))]
""
- "*
-{
- enum rtx_code code = GET_CODE (operands[0]);
- if (cc_prev_status.flags & CC_TEST_AX)
- {
- int eq;
- HOST_WIDE_INT c;
- operands[2] = gen_rtx_REG (SImode, 0);
- switch (code)
- {
- case EQ:
- c = 0x4000;
- eq = 0;
- break;
- case NE:
- c = 0x4000;
- eq = 1;
- break;
- case GT:
- c = 0x4100;
- eq = 1;
- break;
- case LT:
- c = 0x100;
- eq = 0;
- break;
- case GE:
- c = 0x100;
- eq = 1;
- break;
- case LE:
- c = 0x4100;
- eq = 0;
- break;
- default:
- abort ();
- }
- if (!TARGET_PENTIUM || optimize_size)
- {
- operands[3] = GEN_INT (c >> 8);
- output_asm_insn (AS2 (test%B0,%3,%h2), operands);
- }
- else
- {
- operands[3] = GEN_INT (c);
- output_asm_insn (AS2 (test%L0,%3,%2), operands);
- }
- return eq ? AS1 (je,%l1) : AS1 (jne, %l1);
- }
- if ((cc_status.flags & CC_NO_OVERFLOW) && (code == LE || code == GT))
- return (char *)0;
-
- return AS1(j%D0,%l1);
-}")
-
-(define_insn ""
+ "j%C0\\t%l1"
+ [(set_attr "type" "ibr")
+ (set (attr "length")
+ (if_then_else (and (ge (minus (match_dup 1) (pc))
+ (const_int -128))
+ (lt (minus (match_dup 1) (pc))
+ (const_int 124)))
+ (const_int 2)
+ (const_int 6)))])
+
+(define_insn "*jcc_4"
[(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
- [(cc0) (const_int 0)])
+ [(reg:CC 17) (const_int 0)])
(pc)
(label_ref (match_operand 1 "" ""))))]
""
- "*
-{
- enum rtx_code code = GET_CODE (operands[0]);
- if (cc_prev_status.flags & CC_TEST_AX)
- {
- int eq;
- HOST_WIDE_INT c;
- operands[2] = gen_rtx_REG (SImode, 0);
- switch (code)
- {
- case EQ:
- c = 0x4000;
- eq = 1;
- break;
- case NE:
- c = 0x4000;
- eq = 0;
- break;
- case GT:
- c = 0x4100;
- eq = 0;
- break;
- case LT:
- c = 0x100;
- eq = 1;
- break;
- case GE:
- c = 0x100;
- eq = 0;
- break;
- case LE:
- c = 0x4100;
- eq = 1;
- break;
- default:
- abort ();
- }
- if (!TARGET_PENTIUM || optimize_size)
- {
- operands[3] = GEN_INT (c >> 8);
- output_asm_insn (AS2 (test%B0,%3,%h2), operands);
- }
- else
- {
- operands[3] = GEN_INT (c);
- output_asm_insn (AS2 (test%L0,%3,%2), operands);
- }
- return eq ? AS1 (je,%l1) : AS1 (jne, %l1);
- }
- if ((cc_status.flags & CC_NO_OVERFLOW) && (code == LE || code == GT))
- return (char *)0;
-
- return AS1(j%d0,%l1);
-}")
+ "j%c0\\t%l1"
+ [(set_attr "type" "ibr")
+ (set (attr "length")
+ (if_then_else (and (ge (minus (match_dup 1) (pc))
+ (const_int -128))
+ (lt (minus (match_dup 1) (pc))
+ (const_int 124)))
+ (const_int 2)
+ (const_int 6)))])
;; Unconditional and other jump instructions
@@ -6367,235 +6128,34 @@ byte_xor_operation:
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
- "jmp %l0"
- [(set_attr "memory" "none")])
+ "jmp\\t%l0"
+ [(set_attr "type" "ibr")
+ (set (attr "length")
+ (if_then_else (and (ge (minus (match_dup 0) (pc))
+ (const_int -128))
+ (lt (minus (match_dup 0) (pc))
+ (const_int 124)))
+ (const_int 2)
+ (const_int 5)))])
(define_insn "indirect_jump"
[(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))]
""
- "*
-{
- CC_STATUS_INIT;
-
- return AS1 (jmp,%*%0);
-}"
- [(set_attr "memory" "none")])
-
-;; ??? could transform while(--i > 0) S; to if (--i > 0) do S; while(--i);
-;; if S does not change i
-
-(define_expand "decrement_and_branch_until_zero"
- [(parallel [(set (pc)
- (if_then_else (ge (plus:SI (match_operand:SI 0 "general_operand" "")
- (const_int -1))
- (const_int 0))
- (label_ref (match_operand 1 "" ""))
- (pc)))
- (set (match_dup 0)
- (plus:SI (match_dup 0)
- (const_int -1)))])]
- ""
- "")
-
-(define_insn ""
- [(set (pc)
- (if_then_else (match_operator 0 "arithmetic_comparison_operator"
- [(plus:SI (match_operand:SI 1 "nonimmediate_operand" "+c*r,m")
- (match_operand:SI 2 "general_operand" "rmi,ri"))
- (const_int 0)])
- (label_ref (match_operand 3 "" ""))
- (pc)))
- (set (match_dup 1)
- (plus:SI (match_dup 1)
- (match_dup 2)))]
- ""
- "*
-{
- CC_STATUS_INIT;
-
- if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 2 &&
- operands[2] == constm1_rtx && ix86_cpu == PROCESSOR_K6)
- return \"loop %l3\";
-
- if (operands[2] == constm1_rtx)
- output_asm_insn (AS1 (dec%L1,%1), operands);
-
- else if (operands[2] == const1_rtx)
- output_asm_insn (AS1 (inc%L1,%1), operands);
+ "jmp\\t%*%0"
+ [(set_attr "type" "ibr")])
- else
- output_asm_insn (AS2 (add%L1,%2,%1), operands);
-
- return AS1 (%J0,%l3);
-}")
-
-(define_insn ""
- [(set (pc)
- (if_then_else (match_operator 0 "arithmetic_comparison_operator"
- [(minus:SI (match_operand:SI 1 "nonimmediate_operand" "+r,m")
- (match_operand:SI 2 "general_operand" "rmi,ri"))
- (const_int 0)])
- (label_ref (match_operand 3 "" ""))
- (pc)))
- (set (match_dup 1)
- (minus:SI (match_dup 1)
- (match_dup 2)))]
- ""
- "*
-{
- CC_STATUS_INIT;
- if (operands[2] == const1_rtx)
- output_asm_insn (AS1 (dec%L1,%1), operands);
-
- else if (operands[1] == constm1_rtx)
- output_asm_insn (AS1 (inc%L1,%1), operands);
-
- else
- output_asm_insn (AS2 (sub%L1,%2,%1), operands);
-
- return AS1 (%J0,%l3);
-}")
-
-(define_insn ""
- [(set (pc)
- (if_then_else (ne (match_operand:SI 0 "general_operand" "+g")
- (const_int 0))
- (label_ref (match_operand 1 "" ""))
- (pc)))
- (set (match_dup 0)
- (plus:SI (match_dup 0)
- (const_int -1)))]
- ""
- "*
-{
- CC_STATUS_INIT;
- operands[2] = const1_rtx;
- output_asm_insn (AS2 (sub%L0,%2,%0), operands);
- return \"jnc %l1\";
-}")
-
-(define_insn ""
- [(set (pc)
- (if_then_else (eq (match_operand:SI 0 "general_operand" "+g")
- (const_int 0))
- (label_ref (match_operand 1 "" ""))
- (pc)))
- (set (match_dup 0)
- (plus:SI (match_dup 0)
- (const_int -1)))]
- ""
- "*
-{
- CC_STATUS_INIT;
- operands[2] = const1_rtx;
- output_asm_insn (AS2 (sub%L0,%2,%0), operands);
- return \"jc %l1\";
-}")
-
-(define_insn ""
- [(set (pc)
- (if_then_else (ne (match_operand:SI 0 "general_operand" "+g")
- (const_int 1))
- (label_ref (match_operand 1 "" ""))
- (pc)))
- (set (match_dup 0)
- (plus:SI (match_dup 0)
- (const_int -1)))]
- ""
- "*
-{
- CC_STATUS_INIT;
- output_asm_insn (AS1 (dec%L0,%0), operands);
- return \"jnz %l1\";
-}")
-
-(define_insn ""
- [(set (pc)
- (if_then_else (eq (match_operand:SI 0 "general_operand" "+g")
- (const_int 1))
- (label_ref (match_operand 1 "" ""))
- (pc)))
- (set (match_dup 0)
- (plus:SI (match_dup 0)
- (const_int -1)))]
- ""
- "*
-{
- CC_STATUS_INIT;
- output_asm_insn (AS1 (dec%L0,%0), operands);
- return \"jz %l1\";
-}")
-
-(define_insn ""
- [(set (pc)
- (if_then_else (ne (match_operand:SI 0 "general_operand" "+g")
- (const_int -1))
- (label_ref (match_operand 1 "" ""))
- (pc)))
- (set (match_dup 0)
- (plus:SI (match_dup 0)
- (const_int 1)))]
- ""
- "*
-{
- CC_STATUS_INIT;
- output_asm_insn (AS1 (inc%L0,%0), operands);
- return \"jnz %l1\";
-}")
-
-(define_insn ""
- [(set (pc)
- (if_then_else (eq (match_operand:SI 0 "general_operand" "+g")
- (const_int -1))
- (label_ref (match_operand 1 "" ""))
- (pc)))
- (set (match_dup 0)
- (plus:SI (match_dup 0)
- (const_int 1)))]
- ""
- "*
-{
- CC_STATUS_INIT;
- output_asm_insn (AS1 (inc%L0,%0), operands);
- return \"jz %l1\";
-}")
+(define_insn "tablejump"
+ [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))
+ (use (label_ref (match_operand 1 "" "")))]
+ "! flag_pic"
+ "jmp\\t%*%0"
+ [(set_attr "type" "ibr")])
;; Implement switch statements when generating PIC code. Switches are
;; implemented by `tablejump' when not using -fpic.
-
+;;
;; Emit code here to do the range checking and make the index zero based.
-
-(define_expand "casesi"
- [(set (match_dup 5)
- (match_operand:SI 0 "general_operand" ""))
- (set (match_dup 6)
- (minus:SI (match_dup 5)
- (match_operand:SI 1 "general_operand" "")))
- (set (cc0)
- (compare:CC (match_dup 6)
- (match_operand:SI 2 "general_operand" "")))
- (set (pc)
- (if_then_else (gtu (cc0)
- (const_int 0))
- (label_ref (match_operand 4 "" ""))
- (pc)))
- (parallel
- [(set (pc)
- (minus:SI (reg:SI 3)
- (mem:SI (plus:SI (mult:SI (match_dup 6)
- (const_int 4))
- (label_ref (match_operand 3 "" ""))))))
- (clobber (match_scratch:SI 7 ""))])]
- "flag_pic"
- "
-{
- operands[5] = gen_reg_rtx (SImode);
- operands[6] = gen_reg_rtx (SImode);
- current_function_uses_pic_offset_table = 1;
-}")
-
-;; Implement a casesi insn.
-
+;;
;; Each entry in the "addr_diff_vec" looks like this as the result of the
;; two rules below:
;;
@@ -6623,43 +6183,223 @@ byte_xor_operation:
;; The subl above calculates "GOT - (( GOT - . ) + [ . - .L2 ])", which
;; evaluates to just ".L2".
-(define_insn ""
- [(set (pc)
- (minus:SI (reg:SI 3)
- (mem:SI (plus:SI
- (mult:SI (match_operand:SI 0 "register_operand" "r")
- (const_int 4))
- (label_ref (match_operand 1 "" ""))))))
- (clobber (match_scratch:SI 2 "=&r"))]
- ""
- "*
+(define_expand "casesi"
+ [(set (match_dup 5)
+ (match_operand:SI 0 "general_operand" ""))
+ (parallel [(set (match_dup 6)
+ (minus:SI (match_dup 5)
+ (match_operand:SI 1 "general_operand" "")))
+ (clobber (reg:CC 17))])
+ (set (reg:CC 17)
+ (compare:CC (match_dup 6)
+ (match_operand:SI 2 "general_operand" "")))
+ (set (pc)
+ (if_then_else (gtu (reg:CC 17)
+ (const_int 0))
+ (label_ref (match_operand 4 "" ""))
+ (pc)))
+ (parallel
+ [(set (match_dup 7)
+ (minus:SI (match_dup 8)
+ (mem:SI (plus:SI (plus:SI (mult:SI (match_dup 6) (const_int 4))
+ (match_dup 8))
+ (const (unspec [(label_ref (match_operand 3 "" ""))] 7))))))
+ (clobber (reg:CC 17))])
+ (parallel [(set (pc) (match_dup 7))
+ (use (label_ref (match_dup 3)))])]
+ "flag_pic"
+ "
{
- rtx xops[4];
-
- xops[0] = operands[0];
- xops[1] = operands[1];
- xops[2] = operands[2];
- xops[3] = pic_offset_table_rtx;
-
- output_asm_insn (AS2 (mov%L2,%3,%2), xops);
- output_asm_insn (\"sub%L2 %l1@GOTOFF(%3,%0,4),%2\", xops);
- output_asm_insn (AS1 (jmp,%*%2), xops);
- ASM_OUTPUT_ALIGN (asm_out_file, i386_align_jumps);
- RET;
+ operands[5] = gen_reg_rtx (SImode);
+ operands[6] = gen_reg_rtx (SImode);
+ operands[7] = gen_reg_rtx (SImode);
+ operands[8] = pic_offset_table_rtx;
+ current_function_uses_pic_offset_table = 1;
}")
-(define_insn "tablejump"
+(define_insn ""
[(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))
(use (label_ref (match_operand 1 "" "")))]
""
+ "jmp\\t%*%0"
+ [(set_attr "type" "ibr")])
+
+;; Loop instruction
+;;
+;; This is all complicated by the fact that since this is a jump insn
+;; we must handle our own reloads.
+
+(define_expand "decrement_and_branch_on_count"
+ [(parallel [(set (pc) (if_then_else
+ (ne (match_operand:SI 0 "register_operand" "")
+ (const_int 1))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (const_int -1)))
+ (clobber (match_scratch:SI 2 ""))
+ (clobber (reg:CC 17))])]
+ "TARGET_USE_LOOP"
+ "")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (ne (match_operand:SI 1 "register_operand" "c,*r,*r")
+ (const_int 1))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (set (match_operand:SI 2 "register_operand" "=1,*r,*m*r")
+ (plus:SI (match_dup 1)
+ (const_int -1)))
+ (clobber (match_scratch:SI 3 "=X,X,r"))
+ (clobber (reg:CC 17))]
+ "TARGET_USE_LOOP"
"*
{
- CC_STATUS_INIT;
+ if (which_alternative != 0)
+ return \"#\";
+ if (get_attr_length (insn) == 2)
+ return \"loop\\t%l0\";
+ else
+ return \"dec{l}\\t%1\;jne\\t%l0\";
+}"
+ [(set_attr "type" "ibr")
+ (set_attr "ppro_uops" "many")
+ (set (attr "length")
+ (if_then_else (and (eq_attr "alternative" "0")
+ (and (ge (minus (match_dup 0) (pc))
+ (const_int -128))
+ (lt (minus (match_dup 0) (pc))
+ (const_int 124))))
+ (const_int 2)
+ (const_int 16)))])
- return AS1 (jmp,%*%0);
-}")
+(define_insn ""
+ [(set (pc)
+ (if_then_else (ge (match_operand:SI 1 "register_operand" "c,*r,*r")
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (set (match_operand:SI 2 "register_operand" "=1,*r,*m*r")
+ (plus:SI (match_dup 1)
+ (const_int -1)))
+ (clobber (match_scratch:SI 3 "=X,X,r"))
+ (clobber (reg:CC 17))]
+ "TARGET_USE_LOOP && find_reg_note (insn, REG_NONNEG, 0)"
+ "*
+{
+ if (which_alternative != 0)
+ return \"#\";
+ if (get_attr_length (insn) == 2)
+ return \"loop\\t%l0\";
+ else
+ return \"dec{l}\\t%1\;jne\\t%l0\";
+}"
+ [(set_attr "type" "ibr")
+ (set_attr "ppro_uops" "many")
+ (set (attr "length")
+ (if_then_else (and (eq_attr "alternative" "0")
+ (and (ge (minus (match_dup 0) (pc))
+ (const_int -128))
+ (lt (minus (match_dup 0) (pc))
+ (const_int 124))))
+ (const_int 2)
+ (const_int 16)))])
-;; Call insns.
+(define_split
+ [(set (pc)
+ (if_then_else (ne (match_operand:SI 1 "register_operand" "")
+ (const_int 1))
+ (match_operand 0 "" "")
+ (pc)))
+ (set (match_operand:SI 2 "register_operand" "")
+ (plus:SI (match_dup 1)
+ (const_int -1)))
+ (clobber (match_scratch:SI 3 ""))
+ (clobber (reg:CC 17))]
+ "TARGET_USE_LOOP && reload_completed
+ && ! (REGNO (operands[1]) == 2 && rtx_equal_p (operands[1], operands[2]))"
+ [(set (match_dup 2) (match_dup 1))
+ (parallel [(set (reg:CCNO 17)
+ (compare:CCNO (plus:SI (match_dup 2) (const_int -1))
+ (const_int 0)))
+ (set (match_dup 2) (plus:SI (match_dup 2) (const_int -1)))])
+ (set (pc) (if_then_else (ne (reg:CCNO 17) (const_int 0))
+ (match_dup 0)
+ (pc)))]
+ "")
+
+(define_split
+ [(set (pc)
+ (if_then_else (ne (match_operand:SI 1 "register_operand" "")
+ (const_int 1))
+ (match_operand 0 "" "")
+ (pc)))
+ (set (match_operand:SI 2 "memory_operand" "")
+ (plus:SI (match_dup 1)
+ (const_int -1)))
+ (clobber (match_scratch:SI 3 ""))
+ (clobber (reg:CC 17))]
+ "TARGET_USE_LOOP && reload_completed"
+ [(set (match_dup 3) (match_dup 1))
+ (parallel [(set (reg:CCNO 17)
+ (compare:CCNO (plus:SI (match_dup 3) (const_int -1))
+ (const_int 0)))
+ (set (match_dup 3) (plus:SI (match_dup 3) (const_int -1)))])
+ (set (match_dup 2) (match_dup 3))
+ (set (pc) (if_then_else (ne (reg:CCNO 17) (const_int 0))
+ (match_dup 0)
+ (pc)))]
+ "")
+
+(define_split
+ [(set (pc)
+ (if_then_else (ge (match_operand:SI 1 "register_operand" "")
+ (const_int 0))
+ (match_operand 0 "" "")
+ (pc)))
+ (set (match_operand:SI 2 "register_operand" "")
+ (plus:SI (match_dup 1)
+ (const_int -1)))
+ (clobber (match_scratch:SI 3 ""))
+ (clobber (reg:CC 17))]
+ "TARGET_USE_LOOP && reload_completed
+ && ! (REGNO (operands[1]) == 2 && rtx_equal_p (operands[1], operands[2]))"
+ [(set (match_dup 2) (match_dup 1))
+ (parallel [(set (reg:CCNO 17)
+ (compare:CCNO (plus:SI (match_dup 2) (const_int -1))
+ (const_int 0)))
+ (set (match_dup 2) (plus:SI (match_dup 2) (const_int -1)))])
+ (set (pc) (if_then_else (lt (reg:CCNO 17) (const_int 0))
+ (match_dup 0)
+ (pc)))]
+ "")
+
+(define_split
+ [(set (pc)
+ (if_then_else (ge (match_operand:SI 1 "register_operand" "")
+ (const_int 0))
+ (match_operand 0 "" "")
+ (pc)))
+ (set (match_operand:SI 2 "memory_operand" "")
+ (plus:SI (match_dup 1)
+ (const_int -1)))
+ (clobber (match_scratch:SI 3 ""))
+ (clobber (reg:CC 17))]
+ "TARGET_USE_LOOP && reload_completed"
+ [(set (match_dup 3) (match_dup 1))
+ (parallel [(set (reg:CCNO 17)
+ (compare:CCNO (plus:SI (match_dup 3) (const_int -1))
+ (const_int 0)))
+ (set (match_dup 3) (plus:SI (match_dup 3) (const_int -1)))])
+ (set (match_dup 2) (match_dup 3))
+ (set (pc) (if_then_else (lt (reg:CCNO 17) (const_int 0))
+ (match_dup 0)
+ (pc)))]
+ "")
+
+;; Call instructions.
;; If generating PIC code, the predicate indirect_operand will fail
;; for operands[0] containing symbolic references on all of the named
@@ -6709,23 +6449,22 @@ byte_xor_operation:
""
"*
{
- if (GET_CODE (operands[0]) == MEM
- && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
- {
- operands[0] = XEXP (operands[0], 0);
- return AS1 (call,%*%0);
- }
- else
- return AS1 (call,%P0);
-}")
+ if (constant_call_address_operand (operands[0]))
+ return \"call\\t%P0\";
+
+ operands[0] = XEXP (operands[0], 0);
+ return \"call\\t%*%0\";
+}"
+ [(set_attr "type" "call")])
(define_insn ""
- [(call (mem:QI (match_operand:SI 0 "symbolic_operand" ""))
- (match_operand:SI 1 "general_operand" "g"))
+ [(call (match_operand:QI 0 "constant_call_address_operand" "")
+ (match_operand:SI 1 "general_operand" "g"))
(set (reg:SI 7) (plus:SI (reg:SI 7)
- (match_operand:SI 3 "immediate_operand" "i")))]
+ (match_operand:SI 3 "immediate_operand" "i")))]
"!HALF_PIC_P ()"
- "call %P0")
+ "call\\t%P0"
+ [(set_attr "type" "call")])
(define_expand "call"
[(call (match_operand:QI 0 "indirect_operand" "")
@@ -6757,22 +6496,20 @@ byte_xor_operation:
""
"*
{
- if (GET_CODE (operands[0]) == MEM
- && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
- {
- operands[0] = XEXP (operands[0], 0);
- return AS1 (call,%*%0);
- }
- else
- return AS1 (call,%P0);
-}")
+ if (constant_call_address_operand (operands[0]))
+ return \"call\\t%P0\";
+
+ operands[0] = XEXP (operands[0], 0);
+ return \"call\\t%*%0\";
+}"
+ [(set_attr "type" "call")])
(define_insn ""
- [(call (mem:QI (match_operand:SI 0 "symbolic_operand" ""))
- (match_operand:SI 1 "general_operand" "g"))]
- ;; Operand 1 not used on the i386.
+ [(call (match_operand:QI 0 "constant_call_address_operand" "")
+ (match_operand:SI 1 "general_operand" "g"))]
"!HALF_PIC_P ()"
- "call %P0")
+ "call\\t%P0"
+ [(set_attr "type" "call")])
;; Call subroutine, returning value in operand 0
;; (which must be a hard register).
@@ -6818,26 +6555,23 @@ byte_xor_operation:
""
"*
{
- if (GET_CODE (operands[1]) == MEM
- && ! CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
- {
- operands[1] = XEXP (operands[1], 0);
- output_asm_insn (AS1 (call,%*%1), operands);
- }
- else
- output_asm_insn (AS1 (call,%P1), operands);
-
- RET;
-}")
+ if (constant_call_address_operand (operands[1]))
+ return \"call\\t%P1\";
+
+ operands[1] = XEXP (operands[1], 0);
+ return \"call\\t%*%1\";
+}"
+ [(set_attr "type" "callv")])
(define_insn ""
[(set (match_operand 0 "" "=rf")
- (call (mem:QI (match_operand:SI 1 "symbolic_operand" ""))
+ (call (match_operand:QI 1 "constant_call_address_operand" "")
(match_operand:SI 2 "general_operand" "g")))
(set (reg:SI 7) (plus:SI (reg:SI 7)
(match_operand:SI 4 "immediate_operand" "i")))]
"!HALF_PIC_P ()"
- "call %P1")
+ "call\\t%P1"
+ [(set_attr "type" "callv")])
(define_expand "call_value"
[(set (match_operand 0 "" "")
@@ -6871,25 +6605,21 @@ byte_xor_operation:
""
"*
{
- if (GET_CODE (operands[1]) == MEM
- && ! CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
- {
- operands[1] = XEXP (operands[1], 0);
- output_asm_insn (AS1 (call,%*%1), operands);
- }
- else
- output_asm_insn (AS1 (call,%P1), operands);
-
- RET;
-}")
+ if (constant_call_address_operand (operands[1]))
+ return \"call\\t%P1\";
+
+ operands[1] = XEXP (operands[1], 0);
+ return \"call\\t%*%1\";
+}"
+ [(set_attr "type" "callv")])
(define_insn ""
[(set (match_operand 0 "" "=rf")
- (call (mem:QI (match_operand:SI 1 "symbolic_operand" ""))
+ (call (match_operand:QI 1 "constant_call_address_operand" "")
(match_operand:SI 2 "general_operand" "g")))]
- ;; Operand 2 not used on the i386.
"!HALF_PIC_P ()"
- "call %P1")
+ "call\\t%P1"
+ [(set_attr "type" "callv")])
;; Call subroutine returning any type.
@@ -6927,6 +6657,8 @@ byte_xor_operation:
DONE;
}")
+
+;; Prologue and epilogue instructions
;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
;; all of memory. This blocks insns from being moved across this point.
@@ -6935,7 +6667,7 @@ byte_xor_operation:
[(unspec_volatile [(const_int 0)] 0)]
""
""
- [(set_attr "memory" "none")])
+ [(set_attr "length" "0")])
;; Insn emitted into the body of a function to return from a function.
;; This is only done if the function's epilogue is known to be simple.
@@ -6950,72 +6682,45 @@ byte_xor_operation:
[(return)]
"reload_completed"
"ret"
- [(set_attr "memory" "none")])
+ [(set_attr "length" "1")])
(define_insn "return_pop_internal"
[(return)
(use (match_operand:SI 0 "const_int_operand" ""))]
"reload_completed"
- "ret %0"
- [(set_attr "memory" "none")])
+ "ret\\t%0"
+ [(set_attr "length" "3")])
(define_insn "nop"
[(const_int 0)]
""
"nop"
- [(set_attr "memory" "none")])
+ [(set_attr "length" "1")
+ (set_attr "ppro_uops" "one")])
(define_expand "prologue"
[(const_int 1)]
""
- "
-{
- ix86_expand_prologue ();
- DONE;
-}")
-
-;; The use of UNSPEC here is currently not necessary - a simple SET of ebp
-;; to itself would be enough. But this way we are safe even if some optimizer
-;; becomes too clever in the future.
-(define_insn "prologue_set_stack_ptr"
- [(set (reg:SI 7)
- (minus:SI (reg:SI 7) (match_operand:SI 0 "immediate_operand" "i")))
- (set (reg:SI 6) (unspec:SI [(reg:SI 6)] 4))]
- ""
- "*
-{
- rtx xops [2];
-
- xops[0] = operands[0];
- xops[1] = stack_pointer_rtx;
- output_asm_insn (AS2 (sub%L1,%0,%1), xops);
- RET;
-}"
- [(set_attr "memory" "none")])
+ "ix86_expand_prologue (); DONE;")
(define_insn "prologue_set_got"
[(set (match_operand:SI 0 "" "")
(unspec_volatile
[(plus:SI (match_dup 0)
(plus:SI (match_operand:SI 1 "symbolic_operand" "")
- (minus:SI (pc) (match_operand 2 "" ""))))] 1))]
+ (minus:SI (pc) (match_operand 2 "" ""))))] 1))
+ (clobber (reg:CC 17))]
""
"*
{
- char buffer[64];
-
+ if (GET_CODE (operands[2]) == LABEL_REF)
+ operands[2] = XEXP (operands[2], 0);
if (TARGET_DEEP_BRANCH_PREDICTION)
- {
- sprintf (buffer, \"addl %s,%%0\", XSTR (operands[1], 0));
- output_asm_insn (buffer, operands);
- }
+ return \"add{l}\\t{%1, %0|%0, %1}\";
else
- {
- sprintf (buffer, \"addl %s+[.-%%X2],%%0\", XSTR (operands[1], 0));
- output_asm_insn (buffer, operands);
- }
- RET;
-}")
+ return \"add{l}\\t{%1+[.-%X2], %0|%0, %a1+(.-%X2)}\";
+}"
+ [(set_attr "type" "alu")])
(define_insn "prologue_get_pc"
[(set (match_operand:SI 0 "" "")
@@ -7023,73 +6728,470 @@ byte_xor_operation:
""
"*
{
- output_asm_insn (AS1 (call,%X1), operands);
- if (! TARGET_DEEP_BRANCH_PREDICTION)
+ if (GET_CODE (operands[1]) == LABEL_REF)
+ operands[1] = XEXP (operands[1], 0);
+ output_asm_insn (\"call\\t%X1\", operands);
+ if (! TARGET_DEEP_BRANCH_PREDICTION)
{
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (operands[1]));
- }
- RET;
-}"
- [(set_attr "memory" "none")])
-
-(define_insn "prologue_get_pc_and_set_got"
- [(unspec_volatile [(match_operand:SI 0 "" "")] 3)]
- ""
- "*
-{
- operands[1] = gen_label_rtx ();
- output_asm_insn (AS1 (call,%X1), operands);
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
- CODE_LABEL_NUMBER (operands[1]));
- output_asm_insn (AS1 (pop%L0,%0), operands);
- output_asm_insn (\"addl $%__GLOBAL_OFFSET_TABLE_+[.-%X1],%0\", operands);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
+ CODE_LABEL_NUMBER (operands[1]));
+ }
RET;
}"
- [(set_attr "memory" "none")])
+ [(set_attr "type" "multi")])
(define_expand "epilogue"
[(const_int 1)]
""
- "
-{
- ix86_expand_epilogue ();
- DONE;
-}")
+ "ix86_expand_epilogue (); DONE;")
-(define_insn "epilogue_set_stack_ptr"
+(define_insn "leave"
[(set (reg:SI 7) (reg:SI 6))
- (clobber (reg:SI 6))]
+ (set (reg:SI 6) (mem:SI (pre_dec:SI (reg:SI 7))))]
""
- "*
+ "leave"
+ [(set_attr "length" "1")
+ (set_attr "ppro_uops" "few")])
+
+(define_expand "ffssi2"
+ [(set (match_operand:SI 0 "general_operand" "")
+ (ffs:SI (match_operand:SI 1 "general_operand" "")))]
+ ""
+ "
{
- rtx xops [2];
+ rtx out = gen_reg_rtx (SImode), tmp = gen_reg_rtx (SImode);
+ rtx in = operands[1];
- xops[0] = frame_pointer_rtx;
- xops[1] = stack_pointer_rtx;
- output_asm_insn (AS2 (mov%L0,%0,%1), xops);
- RET;
-}"
- [(set_attr "memory" "none")])
+ if (TARGET_CMOVE)
+ {
+ emit_move_insn (tmp, constm1_rtx);
+ emit_insn (gen_ffssi_1 (out, in));
+ emit_insn (gen_rtx_SET (VOIDmode, out,
+ gen_rtx_IF_THEN_ELSE (SImode,
+ gen_rtx_EQ (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG),
+ const0_rtx),
+ tmp,
+ out)));
+ }
+ else
+ {
+ emit_move_insn (tmp, const0_rtx);
+ emit_insn (gen_ffssi_1 (out, in));
+ emit_insn (gen_rtx_SET (VOIDmode,
+ gen_rtx_STRICT_LOW_PART (VOIDmode, gen_lowpart (QImode, tmp)),
+ gen_rtx_EQ (QImode, gen_rtx_REG (CCmode, FLAGS_REG),
+ const0_rtx)));
+ emit_insn (gen_negsi2 (tmp, tmp));
+ emit_insn (gen_iorsi3 (out, out, tmp));
+ }
+ emit_insn (gen_addsi3 (out, out, const1_rtx));
-(define_insn "leave"
- [(const_int 2)
- (clobber (reg:SI 6))
- (clobber (reg:SI 7))]
- ""
- "leave"
- [(set_attr "memory" "none")])
+ emit_move_insn (operands[0], out);
+ DONE;
+}")
-(define_insn "pop"
- [(set (match_operand:SI 0 "register_operand" "r")
- (mem:SI (reg:SI 7)))
- (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))]
- ""
- "*
-{
- output_asm_insn (AS1 (pop%L0,%P0), operands);
- RET;
-}"
- [(set_attr "memory" "load")])
+;; %%% The CCmode here is not strictly correct -- only Z is defined.
+;; But I don't think this can be used except for from above.
+(define_insn "ffssi_1"
+ [(set (reg:CC 17)
+ (compare:CC (match_operand:SI 1 "nonimmediate_operand" "rm")
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_dup 1)] 5))]
+ ""
+ "bsf{l}\\t{%1, %0|%0, %1}"
+ [(set_attr "length_opcode" "3")
+ (set_attr "ppro_uops" "few")])
+
+;; ffshi2 is not useful -- 4 word prefix ops are needed, which is larger
+;; and slower than the two-byte movzx insn needed to do the work in SImode.
+
+;; These patterns match the binary 387 instructions for addM3, subM3,
+;; mulM3 and divM3. There are three patterns for each of DFmode and
+;; SFmode. The first is the normal insn, the second the same insn but
+;; with one operand a conversion, and the third the same insn but with
+;; the other operand a conversion. The conversion may be SFmode or
+;; SImode if the target mode DFmode, but only SImode if the target mode
+;; is SFmode.
+
+(define_insn "*fop_sf_1"
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (match_operator:SF 3 "binary_fp_operator"
+ [(match_operand:SF 1 "nonimmediate_operand" "0,fm")
+ (match_operand:SF 2 "nonimmediate_operand" "fm,0")]))]
+ "TARGET_80387"
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:SF 3 "mult_operator" "")
+ (const_string "fmul")
+ (match_operand:SF 3 "div_operator" "")
+ (const_string "fdiv")
+ ]
+ (const_string "fop")))])
+
+(define_insn "*fop_sf_2"
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (match_operator:SF 3 "binary_fp_operator"
+ [(float:SF (match_operand:SI 1 "nonimmediate_operand" "m,?r"))
+ (match_operand:SF 2 "register_operand" "0,0")]))]
+ "TARGET_80387 && TARGET_USE_FIOP"
+ "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:SF 3 "mult_operator" "")
+ (const_string "fmul")
+ (match_operand:SF 3 "div_operator" "")
+ (const_string "fdiv")
+ ]
+ (const_string "fop")))
+ (set_attr "fp_int_src" "true")
+ (set_attr "ppro_uops" "many")])
+
+(define_insn "*fop_sf_3"
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (match_operator:SF 3 "binary_fp_operator"
+ [(match_operand:SF 1 "register_operand" "0,0")
+ (float:SF (match_operand:SI 2 "nonimmediate_operand" "m,?r"))]))]
+ "TARGET_80387 && TARGET_USE_FIOP"
+ "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:SF 3 "mult_operator" "")
+ (const_string "fmul")
+ (match_operand:SF 3 "div_operator" "")
+ (const_string "fdiv")
+ ]
+ (const_string "fop")))
+ (set_attr "fp_int_src" "true")
+ (set_attr "ppro_uops" "many")])
+
+(define_insn "*fop_df_1"
+ [(set (match_operand:DF 0 "register_operand" "=f,f")
+ (match_operator:DF 3 "binary_fp_operator"
+ [(match_operand:DF 1 "nonimmediate_operand" "0,fm")
+ (match_operand:DF 2 "nonimmediate_operand" "fm,0")]))]
+ "TARGET_80387"
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "mult_operator" "")
+ (const_string "fmul")
+ (match_operand:DF 3 "div_operator" "")
+ (const_string "fdiv")
+ ]
+ (const_string "fop")))])
+
+(define_insn "*fop_df_2"
+ [(set (match_operand:DF 0 "register_operand" "=f,f")
+ (match_operator:DF 3 "binary_fp_operator"
+ [(float:DF (match_operand:SI 1 "nonimmediate_operand" "m,?r"))
+ (match_operand:DF 2 "register_operand" "0,0")]))]
+ "TARGET_80387 && TARGET_USE_FIOP"
+ "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "mult_operator" "")
+ (const_string "fmul")
+ (match_operand:DF 3 "div_operator" "")
+ (const_string "fdiv")
+ ]
+ (const_string "fop")))
+ (set_attr "fp_int_src" "true")
+ (set_attr "ppro_uops" "many")])
+
+(define_insn "*fop_df_3"
+ [(set (match_operand:DF 0 "register_operand" "=f,f")
+ (match_operator:DF 3 "binary_fp_operator"
+ [(match_operand:DF 1 "register_operand" "0,0")
+ (float:DF (match_operand:SI 2 "nonimmediate_operand" "m,?r"))]))]
+ "TARGET_80387 && TARGET_USE_FIOP"
+ "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "mult_operator" "")
+ (const_string "fmul")
+ (match_operand:DF 3 "div_operator" "")
+ (const_string "fdiv")
+ ]
+ (const_string "fop")))
+ (set_attr "fp_int_src" "true")
+ (set_attr "ppro_uops" "many")])
+
+(define_insn "*fop_df_4"
+ [(set (match_operand:DF 0 "register_operand" "=f,f")
+ (match_operator:DF 3 "binary_fp_operator"
+ [(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,0"))
+ (match_operand:DF 2 "register_operand" "0,f")]))]
+ "TARGET_80387"
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "mult_operator" "")
+ (const_string "fmul")
+ (match_operand:DF 3 "div_operator" "")
+ (const_string "fdiv")
+ ]
+ (const_string "fop")))])
+
+(define_insn "*fop_df_5"
+ [(set (match_operand:DF 0 "register_operand" "=f,f")
+ (match_operator:DF 3 "binary_fp_operator"
+ [(match_operand:DF 1 "register_operand" "0,f")
+ (float_extend:DF
+ (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))]
+ "TARGET_80387"
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "mult_operator" "")
+ (const_string "fmul")
+ (match_operand:DF 3 "div_operator" "")
+ (const_string "fdiv")
+ ]
+ (const_string "fop")))])
+
+(define_insn "*fop_xf_1"
+ [(set (match_operand:XF 0 "register_operand" "=f,f")
+ (match_operator:XF 3 "binary_fp_operator"
+ [(match_operand:XF 1 "register_operand" "0,f")
+ (match_operand:XF 2 "register_operand" "f,0")]))]
+ "TARGET_80387"
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "mult_operator" "")
+ (const_string "fmul")
+ (match_operand:DF 3 "div_operator" "")
+ (const_string "fdiv")
+ ]
+ (const_string "fop")))])
+
+(define_insn "*fop_xf_2"
+ [(set (match_operand:XF 0 "register_operand" "=f,f")
+ (match_operator:XF 3 "binary_fp_operator"
+ [(float:XF (match_operand:SI 1 "nonimmediate_operand" "m,?r"))
+ (match_operand:XF 2 "register_operand" "0,0")]))]
+ "TARGET_80387 && TARGET_USE_FIOP"
+ "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "mult_operator" "")
+ (const_string "fmul")
+ (match_operand:DF 3 "div_operator" "")
+ (const_string "fdiv")
+ ]
+ (const_string "fop")))
+ (set_attr "fp_int_src" "true")
+ (set_attr "ppro_uops" "many")])
+
+(define_insn "*fop_xf_3"
+ [(set (match_operand:XF 0 "register_operand" "=f,f")
+ (match_operator:XF 3 "binary_fp_operator"
+ [(match_operand:XF 1 "register_operand" "0,0")
+ (float:XF (match_operand:SI 2 "nonimmediate_operand" "m,?r"))]))]
+ "TARGET_80387 && TARGET_USE_FIOP"
+ "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "mult_operator" "")
+ (const_string "fmul")
+ (match_operand:DF 3 "div_operator" "")
+ (const_string "fdiv")
+ ]
+ (const_string "fop")))
+ (set_attr "fp_int_src" "true")
+ (set_attr "ppro_uops" "many")])
+
+(define_insn "*fop_xf_4"
+ [(set (match_operand:XF 0 "register_operand" "=f,f")
+ (match_operator:XF 3 "binary_fp_operator"
+ [(float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "fm,0"))
+ (match_operand:XF 2 "register_operand" "0,f")]))]
+ "TARGET_80387"
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "mult_operator" "")
+ (const_string "fmul")
+ (match_operand:DF 3 "div_operator" "")
+ (const_string "fdiv")
+ ]
+ (const_string "fop")))])
+
+(define_insn "*fop_xf_5"
+ [(set (match_operand:XF 0 "register_operand" "=f,f")
+ (match_operator:XF 3 "binary_fp_operator"
+ [(match_operand:XF 1 "register_operand" "0,f")
+ (float_extend:XF
+ (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))]
+ "TARGET_80387"
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "mult_operator" "")
+ (const_string "fmul")
+ (match_operand:DF 3 "div_operator" "")
+ (const_string "fdiv")
+ ]
+ (const_string "fop")))])
+
+(define_insn "*fop_xf_6"
+ [(set (match_operand:XF 0 "register_operand" "=f,f")
+ (match_operator:XF 3 "binary_fp_operator"
+ [(float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "fm,0"))
+ (match_operand:XF 2 "register_operand" "0,f")]))]
+ "TARGET_80387"
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "mult_operator" "")
+ (const_string "fmul")
+ (match_operand:DF 3 "div_operator" "")
+ (const_string "fdiv")
+ ]
+ (const_string "fop")))])
+
+(define_insn "*fop_xf_7"
+ [(set (match_operand:XF 0 "register_operand" "=f,f")
+ (match_operator:XF 3 "binary_fp_operator"
+ [(match_operand:XF 1 "register_operand" "0,f")
+ (float_extend:XF
+ (match_operand:DF 2 "nonimmediate_operand" "fm,0"))]))]
+ "TARGET_80387"
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "mult_operator" "")
+ (const_string "fmul")
+ (match_operand:DF 3 "div_operator" "")
+ (const_string "fdiv")
+ ]
+ (const_string "fop")))])
+
+(define_split
+ [(set (match_operand 0 "register_operand" "")
+ (match_operator 3 "binary_fp_operator"
+ [(float (match_operand:SI 1 "register_operand" ""))
+ (match_operand 2 "register_operand" "")]))]
+ "TARGET_80387 && reload_completed
+ && FLOAT_MODE_P (GET_MODE (operands[0]))"
+ [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 1))
+ (set (match_dup 0)
+ (match_op_dup 3 [(match_dup 4) (match_dup 2)]))
+ (parallel [(set (match_dup 1) (mem:SI (reg:SI 7)))
+ (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])]
+ "operands[4] = gen_rtx_FLOAT (GET_MODE (operands[0]),
+ gen_rtx_MEM (SImode, stack_pointer_rtx));")
+
+(define_split
+ [(set (match_operand 0 "register_operand" "")
+ (match_operator 3 "binary_fp_operator"
+ [(match_operand 1 "register_operand" "")
+ (float (match_operand:SI 2 "register_operand" ""))]))]
+ "TARGET_80387 && reload_completed
+ && FLOAT_MODE_P (GET_MODE (operands[0]))"
+ [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 2))
+ (set (match_dup 0)
+ (match_op_dup 3 [(match_dup 1) (match_dup 4)]))
+ (parallel [(set (match_dup 2) (mem:SI (reg:SI 7)))
+ (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])]
+ "operands[4] = gen_rtx_FLOAT (GET_MODE (operands[0]),
+ gen_rtx_MEM (SImode, stack_pointer_rtx));")
+
+;; FPU special functions.
+
+(define_insn "sqrtsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (sqrt:SF (match_operand:SF 1 "register_operand" "0")))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
+ "fsqrt"
+ [(set_attr "type" "fpspc")])
+
+(define_insn "sqrtdf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (sqrt:DF (match_operand:DF 1 "register_operand" "0")))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ && (TARGET_IEEE_FP || flag_fast_math) "
+ "fsqrt"
+ [(set_attr "type" "fpspc")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (sqrt:DF (float_extend:DF
+ (match_operand:SF 1 "register_operand" "0"))))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
+ "fsqrt"
+ [(set_attr "type" "fpspc")])
+
+(define_insn "sqrtxf2"
+ [(set (match_operand:XF 0 "register_operand" "=f")
+ (sqrt:XF (match_operand:XF 1 "register_operand" "0")))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ && (TARGET_IEEE_FP || flag_fast_math) "
+ "fsqrt"
+ [(set_attr "type" "fpspc")])
+
+(define_insn ""
+ [(set (match_operand:XF 0 "register_operand" "=f")
+ (sqrt:XF (float_extend:XF
+ (match_operand:DF 1 "register_operand" "0"))))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
+ "fsqrt"
+ [(set_attr "type" "fpspc")])
+
+(define_insn ""
+ [(set (match_operand:XF 0 "register_operand" "=f")
+ (sqrt:XF (float_extend:XF
+ (match_operand:SF 1 "register_operand" "0"))))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
+ "fsqrt"
+ [(set_attr "type" "fpspc")])
+
+(define_insn "sindf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 1))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
+ "fsin"
+ [(set_attr "type" "fpspc")])
+
+(define_insn "sinsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 1))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
+ "fsin"
+ [(set_attr "type" "fpspc")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (unspec:DF [(float_extend:DF
+ (match_operand:SF 1 "register_operand" "0"))] 1))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
+ "fsin"
+ [(set_attr "type" "fpspc")])
+
+(define_insn "sinxf2"
+ [(set (match_operand:XF 0 "register_operand" "=f")
+ (unspec:XF [(match_operand:XF 1 "register_operand" "0")] 1))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
+ "fsin"
+ [(set_attr "type" "fpspc")])
+
+(define_insn "cosdf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 2))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
+ "fcos"
+ [(set_attr "type" "fpspc")])
+
+(define_insn "cossf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 2))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
+ "fcos"
+ [(set_attr "type" "fpspc")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (unspec:DF [(float_extend:DF
+ (match_operand:SF 1 "register_operand" "0"))] 2))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
+ "fcos"
+ [(set_attr "type" "fpspc")])
+
+(define_insn "cosxf2"
+ [(set (match_operand:XF 0 "register_operand" "=f")
+ (unspec:XF [(match_operand:XF 1 "register_operand" "0")] 2))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
+ "fcos"
+ [(set_attr "type" "fpspc")])
+
+;; Block operation instructions
(define_expand "movstrsi"
[(parallel [(set (match_operand:BLK 0 "memory_operand" "")
@@ -7121,7 +7223,7 @@ byte_xor_operation:
;; But strength reduction might offset the MEM expression. So we let
;; reload put the address into %edi & %esi.
-(define_insn ""
+(define_insn "*movstrsi_1"
[(set (mem:BLK (match_operand:SI 0 "address_operand" "D"))
(mem:BLK (match_operand:SI 1 "address_operand" "S")))
(use (match_operand:SI 2 "const_int_operand" "n"))
@@ -7142,12 +7244,8 @@ byte_xor_operation:
xops[0] = GEN_INT ((INTVAL (operands[2]) >> 2) & 0x3fffffff);
xops[1] = operands[4];
- output_asm_insn (AS2 (mov%L1,%0,%1), xops);
-#ifdef INTEL_SYNTAX
- output_asm_insn (\"rep movsd\", xops);
-#else
- output_asm_insn (\"rep\;movsl\", xops);
-#endif
+ output_asm_insn (\"mov{l}\\t{%0, %1|%1,%0}\", xops);
+ output_asm_insn (\"{rep\;movsl|rep movsd}\", xops);
}
if (INTVAL (operands[2]) & 0x02)
output_asm_insn (\"movsw\", operands);
@@ -7157,7 +7255,8 @@ byte_xor_operation:
else
abort ();
RET;
-}")
+}"
+ [(set_attr "type" "multi")])
(define_expand "clrstrsi"
[(set (match_dup 3) (const_int 0))
@@ -7188,7 +7287,7 @@ byte_xor_operation:
;; But strength reduction might offset the MEM expression. So we let
;; reload put the address into %edi.
-(define_insn "*bzero"
+(define_insn "*clrstrsi_1"
[(set (mem:BLK (match_operand:SI 0 "address_operand" "D"))
(const_int 0))
(use (match_operand:SI 1 "const_int_operand" "n"))
@@ -7217,21 +7316,13 @@ byte_xor_operation:
if (count / 4 < ((int) ix86_cpu < (int)PROCESSOR_PENTIUM ? 4 : 6))
{
do
-#ifdef INTEL_SYNTAX
- output_asm_insn (\"stosd\", xops);
-#else
- output_asm_insn (\"stosl\", xops);
-#endif
+ output_asm_insn (\"{stosl|stosd}\", xops);
while ((count -= 4) > 3);
}
else
{
- output_asm_insn (AS2 (mov%L1,%0,%1), xops);
-#ifdef INTEL_SYNTAX
- output_asm_insn (\"rep stosd\", xops);
-#else
- output_asm_insn (\"rep\;stosl\", xops);
-#endif
+ output_asm_insn (\"mov{l}\\t{%0, %1|%1, %0}\", xops);
+ output_asm_insn (\"{rep\;stosl|rep stosd}\", xops);
}
}
if (INTVAL (operands[1]) & 0x02)
@@ -7242,81 +7333,82 @@ byte_xor_operation:
else
abort ();
RET;
-}")
+}"
+ [(set_attr "type" "multi")])
(define_expand "cmpstrsi"
- [(parallel [(set (match_operand:SI 0 "general_operand" "")
- (compare:SI (match_operand:BLK 1 "general_operand" "")
- (match_operand:BLK 2 "general_operand" "")))
- (use (match_operand:SI 3 "general_operand" ""))
- (use (match_operand:SI 4 "immediate_operand" ""))
- (clobber (match_dup 5))
- (clobber (match_dup 6))
- (clobber (match_dup 3))])]
+ [(set (match_operand:SI 0 "register_operand" "")
+ (compare:SI (match_operand:BLK 1 "general_operand" "")
+ (match_operand:BLK 2 "general_operand" "")))
+ (use (match_operand:SI 3 "general_operand" ""))
+ (use (match_operand:SI 4 "immediate_operand" ""))]
""
"
{
- rtx addr1, addr2;
+ rtx addr1, addr2, out, outlow, count, countreg, align;
+
+ out = operands[0];
+ if (GET_CODE (out) != REG)
+ out = gen_reg_rtx (SImode);
addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
addr2 = copy_to_mode_reg (Pmode, XEXP (operands[2], 0));
- operands[3] = copy_to_mode_reg (SImode, operands[3]);
+
+ count = operands[3];
+ countreg = copy_to_mode_reg (SImode, count);
+
+ /* %%% Iff we are testing strict equality, we can use known alignment
+ to good advantage. This may be possible with combine, particularly
+ once cc0 is dead. */
+ align = operands[4];
+
+ if (GET_CODE (count) == CONST_INT)
+ {
+ if (INTVAL (count) == 0)
+ {
+ emit_move_insn (operands[0], const0_rtx);
+ DONE;
+ }
+ emit_insn (gen_cmpstrsi_nz_1 (addr1, addr2, countreg, align));
+ }
+ else
+ emit_insn (gen_cmpstrsi_1 (addr1, addr2, countreg, align));
- operands[5] = addr1;
- operands[6] = addr2;
+ outlow = gen_lowpart (QImode, out);
+ emit_insn (gen_cmpintqi (outlow));
+ emit_move_insn (out, gen_rtx_SIGN_EXTEND (SImode, outlow));
- operands[1] = gen_rtx_MEM (BLKmode, addr1);
- operands[2] = gen_rtx_MEM (BLKmode, addr2);
+ if (operands[0] != out)
+ emit_move_insn (operands[0], out);
+ DONE;
}")
+;; Produce a tri-state integer (-1, 0, 1) from condition codes.
+
+(define_expand "cmpintqi"
+ [(set (match_dup 1)
+ (gtu:QI (reg:CC 17) (const_int 0)))
+ (set (match_dup 2)
+ (ltu:QI (reg:CC 17) (const_int 0)))
+ (parallel [(set (match_operand:QI 0 "register_operand" "")
+ (minus:QI (match_dup 1)
+ (match_dup 2)))
+ (clobber (reg:CC 17))])]
+ ""
+ "operands[1] = gen_reg_rtx (QImode);
+ operands[2] = gen_reg_rtx (QImode);")
+
;; memcmp recognizers. The `cmpsb' opcode does nothing if the count is
;; zero. Emit extra code to make sure that a zero-length compare is EQ.
-
+;;
;; It might seem that operands 0 & 1 could use predicate register_operand.
;; But strength reduction might offset the MEM expression. So we let
;; reload put the address into %edi & %esi.
-;; ??? Most comparisons have a constant length, and it's therefore
-;; possible to know that the length is non-zero, and to avoid the extra
-;; code to handle zero-length compares.
-
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=&r")
- (compare:SI (mem:BLK (match_operand:SI 1 "address_operand" "S"))
- (mem:BLK (match_operand:SI 2 "address_operand" "D"))))
- (use (match_operand:SI 3 "register_operand" "c"))
- (use (match_operand:SI 4 "immediate_operand" "i"))
- (clobber (match_dup 1))
- (clobber (match_dup 2))
- (clobber (match_dup 3))]
- ""
- "*
-{
- rtx xops[2], label;
-
- label = gen_label_rtx ();
-
- output_asm_insn (\"cld\", operands);
- output_asm_insn (AS2 (xor%L0,%0,%0), operands);
- output_asm_insn (\"repz\;cmps%B2\", operands);
- output_asm_insn (\"je %l0\", &label);
-
- xops[0] = operands[0];
- xops[1] = const1_rtx;
- output_asm_insn (AS2 (sbb%L0,%0,%0), xops);
- if (QI_REG_P (xops[0]))
- output_asm_insn (AS2 (or%B0,%1,%b0), xops);
- else
- output_asm_insn (AS2 (or%L0,%1,%0), xops);
-
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (label));
- RET;
-}")
-
-(define_insn ""
- [(set (cc0)
- (compare:SI (mem:BLK (match_operand:SI 0 "address_operand" "S"))
+(define_insn "cmpstrsi_nz_1"
+ [(set (reg:CC 17)
+ (compare:CC (mem:BLK (match_operand:SI 0 "address_operand" "S"))
(mem:BLK (match_operand:SI 1 "address_operand" "D"))))
(use (match_operand:SI 2 "register_operand" "c"))
(use (match_operand:SI 3 "immediate_operand" "i"))
@@ -7324,363 +7416,150 @@ byte_xor_operation:
(clobber (match_dup 1))
(clobber (match_dup 2))]
""
- "*
-{
- rtx xops[2];
+ "cld\;repz{\;| }cmpsb"
+ [(set_attr "type" "multi")
+ (set_attr "length" "3")])
- cc_status.flags |= CC_NOT_SIGNED;
-
- xops[0] = gen_rtx_REG (QImode, 0);
- xops[1] = CONST0_RTX (QImode);
-
- output_asm_insn (\"cld\", operands);
- output_asm_insn (AS2 (test%B0,%1,%0), xops);
- return \"repz\;cmps%B2\";
-}")
-
-
-;; Note, you cannot optimize away the branch following the bsfl by assuming
-;; that the destination is not modified if the input is 0, since not all
-;; x86 implementations do this.
+;; The same, but the count is not known to not be zero.
-(define_expand "ffssi2"
- [(set (match_operand:SI 0 "general_operand" "")
- (ffs:SI (match_operand:SI 1 "general_operand" "")))]
- ""
- "
-{
- rtx label = gen_label_rtx (), temp = gen_reg_rtx (SImode);
-
- emit_insn (gen_ffssi_1 (temp, operands[1]));
- emit_cmp_insn (operands[1], const0_rtx, NE, NULL_RTX, SImode, 0, 0);
- emit_jump_insn (gen_bne (label));
- emit_move_insn (temp, constm1_rtx);
- emit_label (label);
- temp = expand_binop (SImode, add_optab, temp, const1_rtx,
- operands[0], 0, OPTAB_WIDEN);
-
- if (temp != operands[0])
- emit_move_insn (operands[0], temp);
- DONE;
-}")
-
-(define_insn "ffssi_1"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (unspec:SI [(match_operand:SI 1 "nonimmediate_operand" "rm")] 5))]
+(define_insn "cmpstrsi_1"
+ [(set (reg:CC 17)
+ (if_then_else:CC (ne (match_operand:SI 2 "register_operand" "c")
+ (const_int 0))
+ (compare:SI (mem:BLK (match_operand:SI 0 "address_operand" "S"))
+ (mem:BLK (match_operand:SI 1 "address_operand" "D")))
+ (const_int 0)))
+ (use (match_operand:SI 3 "immediate_operand" "i"))
+ (clobber (match_dup 0))
+ (clobber (match_dup 1))
+ (clobber (match_dup 2))]
""
- "* return AS2 (bsf%L0,%1,%0);")
+ ;; The initial compare sets the zero flag.
+ "cmp{l}\\t%2, %2\;cld\;repz{\;| }cmpsb"
+ [(set_attr "type" "multi")
+ (set_attr "length" "5")])
-(define_expand "ffshi2"
- [(set (match_operand:SI 0 "general_operand" "")
- (ffs:HI (match_operand:HI 1 "general_operand" "")))]
+(define_expand "strlensi"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (unspec:SI [(match_operand:BLK 1 "general_operand" "")
+ (match_operand:QI 2 "immediate_operand" "")
+ (match_operand:SI 3 "immediate_operand" "")] 0))]
""
"
{
- rtx label = gen_label_rtx (), temp = gen_reg_rtx (HImode);
-
- emit_insn (gen_ffshi_1 (temp, operands[1]));
- emit_cmp_insn (operands[1], const0_rtx, NE, NULL_RTX, HImode, 0, 0);
- emit_jump_insn (gen_bne (label));
- emit_move_insn (temp, constm1_rtx);
- emit_label (label);
- temp = expand_binop (HImode, add_optab, temp, const1_rtx,
- operands[0], 0, OPTAB_WIDEN);
-
- if (temp != operands[0])
- emit_move_insn (operands[0], temp);
- DONE;
-}")
-
-(define_insn "ffshi_1"
- [(set (match_operand:HI 0 "register_operand" "=r")
- (unspec:HI [(match_operand:SI 1 "nonimmediate_operand" "rm")] 5))]
- ""
- "* return AS2 (bsf%W0,%1,%0);")
-
-;; These patterns match the binary 387 instructions for addM3, subM3,
-;; mulM3 and divM3. There are three patterns for each of DFmode and
-;; SFmode. The first is the normal insn, the second the same insn but
-;; with one operand a conversion, and the third the same insn but with
-;; the other operand a conversion.
-
-(define_insn ""
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (match_operator:DF 3 "binary_387_op"
- [(match_operand:DF 1 "nonimmediate_operand" "0,fm")
- (match_operand:DF 2 "nonimmediate_operand" "fm,0")]))]
- "TARGET_80387"
- "* return output_387_binary_op (insn, operands);"
- [(set (attr "type")
- (cond [(match_operand:DF 3 "is_mul" "")
- (const_string "fpmul")
- (match_operand:DF 3 "is_div" "")
- (const_string "fpdiv")
- ]
- (const_string "fpop")
- )
- )])
-
-(define_insn ""
- [(set (match_operand:XF 0 "register_operand" "=f,f")
- (match_operator:XF 3 "binary_387_op"
- [(match_operand:XF 1 "register_operand" "0,f")
- (match_operand:XF 2 "register_operand" "f,0")]))]
- "TARGET_80387"
- "* return output_387_binary_op (insn, operands);"
- [(set (attr "type")
- (cond [(match_operand:DF 3 "is_mul" "")
- (const_string "fpmul")
- (match_operand:DF 3 "is_div" "")
- (const_string "fpdiv")
- ]
- (const_string "fpop")
- )
- )])
-
-(define_insn ""
- [(set (match_operand:XF 0 "register_operand" "=f,f")
- (match_operator:XF 3 "binary_387_op"
- [(float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "fm,0"))
- (match_operand:XF 2 "register_operand" "0,f")]))]
- "TARGET_80387"
- "* return output_387_binary_op (insn, operands);"
- [(set (attr "type")
- (cond [(match_operand:DF 3 "is_mul" "")
- (const_string "fpmul")
- (match_operand:DF 3 "is_div" "")
- (const_string "fpdiv")
- ]
- (const_string "fpop")
- )
- )])
-
-(define_insn ""
- [(set (match_operand:XF 0 "register_operand" "=f,f")
- (match_operator:XF 3 "binary_387_op"
- [(match_operand:XF 1 "register_operand" "0,f")
- (float_extend:XF
- (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))]
- "TARGET_80387"
- "* return output_387_binary_op (insn, operands);"
- [(set (attr "type")
- (cond [(match_operand:DF 3 "is_mul" "")
- (const_string "fpmul")
- (match_operand:DF 3 "is_div" "")
- (const_string "fpdiv")
- ]
- (const_string "fpop")
- )
- )])
+ rtx out, addr, eoschar, align, scratch1, scratch2, scratch3;
-(define_insn ""
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (match_operator:DF 3 "binary_387_op"
- [(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,0"))
- (match_operand:DF 2 "register_operand" "0,f")]))]
- "TARGET_80387"
- "* return output_387_binary_op (insn, operands);"
- [(set (attr "type")
- (cond [(match_operand:DF 3 "is_mul" "")
- (const_string "fpmul")
- (match_operand:DF 3 "is_div" "")
- (const_string "fpdiv")
- ]
- (const_string "fpop")
- )
- )])
+ out = operands[0];
+ addr = force_reg (Pmode, XEXP (operands[1], 0));
+ eoschar = operands[2];
+ align = operands[3];
+ scratch1 = gen_reg_rtx (SImode);
-(define_insn ""
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (match_operator:DF 3 "binary_387_op"
- [(match_operand:DF 1 "register_operand" "0,f")
- (float_extend:DF
- (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))]
- "TARGET_80387"
- "* return output_387_binary_op (insn, operands);"
- [(set (attr "type")
- (cond [(match_operand:DF 3 "is_mul" "")
- (const_string "fpmul")
- (match_operand:DF 3 "is_div" "")
- (const_string "fpdiv")
- ]
- (const_string "fpop")
- )
- )])
-
-(define_insn ""
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (match_operator:SF 3 "binary_387_op"
- [(match_operand:SF 1 "nonimmediate_operand" "0,fm")
- (match_operand:SF 2 "nonimmediate_operand" "fm,0")]))]
- "TARGET_80387"
- "* return output_387_binary_op (insn, operands);"
- [(set (attr "type")
- (cond [(match_operand:DF 3 "is_mul" "")
- (const_string "fpmul")
- (match_operand:DF 3 "is_div" "")
- (const_string "fpdiv")
- ]
- (const_string "fpop")
- )
- )])
-
-(define_expand "strlensi"
- [(parallel [(set (match_dup 4)
- (unspec:SI [(mem:BLK (match_operand:BLK 1 "general_operand" ""))
- (match_operand:QI 2 "immediate_operand" "")
- (match_operand:SI 3 "immediate_operand" "")] 0))
- (clobber (match_dup 1))])
- (set (match_dup 5)
- (not:SI (match_dup 4)))
- (set (match_operand:SI 0 "register_operand" "")
- (plus:SI (match_dup 5)
- (const_int -1)))]
- ""
- "
-{
- if (TARGET_UNROLL_STRLEN && operands[2] == const0_rtx && optimize > 1)
+ if (TARGET_UNROLL_STRLEN && eoschar == const0_rtx && optimize > 1)
{
- rtx address;
- rtx scratch;
-
- /* well it seems that some optimizer does not combine a call like
+ /* Well it seems that some optimizer does not combine a call like
foo(strlen(bar), strlen(bar));
- when the move and the subtraction is done here. It does calculate
- the length just once when these instructions are done inside of
- output_strlen_unroll(). But I think since &bar[strlen(bar)] is
- often used and I use one fewer register for the lifetime of
- output_strlen_unroll() this is better. */
- scratch = gen_reg_rtx (SImode);
- address = force_reg (SImode, XEXP (operands[1], 0));
-
- /* move address to scratch-register
- this is done here because the i586 can do the following and
- in the same cycle with the following move. */
- if (GET_CODE (operands[3]) != CONST_INT || INTVAL (operands[3]) < 4)
- emit_insn (gen_movsi (scratch, address));
-
- emit_insn (gen_movsi (operands[0], address));
-
- if(TARGET_USE_Q_REG)
- emit_insn (gen_strlensi_unroll5 (operands[0],
- operands[3],
- scratch,
- operands[0]));
- else
- emit_insn (gen_strlensi_unroll4 (operands[0],
- operands[3],
- scratch,
- operands[0]));
-
- /* gen_strlensi_unroll[45] returns the address of the zero
- at the end of the string, like memchr(), so compute the
- length by subtracting the startaddress. */
- emit_insn (gen_subsi3 (operands[0], operands[0], address));
- DONE;
+ when the move and the subtraction is done here. It does calculate
+ the length just once when these instructions are done inside of
+ output_strlen_unroll(). But I think since &bar[strlen(bar)] is
+ often used and I use one fewer register for the lifetime of
+ output_strlen_unroll() this is better. */
+
+ if (GET_CODE (align) != CONST_INT || INTVAL (align) < 4)
+ emit_move_insn (scratch1, addr);
+ emit_move_insn (out, addr);
+
+ ix86_expand_strlensi_unroll_1 (out, align, scratch1);
+
+ /* strlensi_unroll_1 returns the address of the zero at the end of
+ the string, like memchr(), so compute the length by subtracting
+ the start address. */
+ emit_insn (gen_subsi3 (out, out, addr));
}
+ else
+ {
+ scratch2 = gen_reg_rtx (SImode);
+ scratch3 = gen_reg_rtx (SImode);
- operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
- operands[4] = gen_reg_rtx (SImode);
- operands[5] = gen_reg_rtx (SImode);
+ emit_move_insn (scratch3, addr);
+
+ emit_insn (gen_strlensi_1 (scratch1, scratch3, eoschar,
+ align, constm1_rtx));
+ emit_insn (gen_one_cmplsi2 (scratch2, scratch1));
+ emit_insn (gen_addsi3 (out, scratch2, constm1_rtx));
+ }
+ DONE;
}")
;; It might seem that operands 0 & 1 could use predicate register_operand.
;; But strength reduction might offset the MEM expression. So we let
;; reload put the address into %edi.
-(define_insn ""
+(define_insn "strlensi_1"
[(set (match_operand:SI 0 "register_operand" "=&c")
(unspec:SI [(mem:BLK (match_operand:SI 1 "address_operand" "D"))
- (match_operand:QI 2 "immediate_operand" "a")
- (match_operand:SI 3 "immediate_operand" "i")] 0))
- (clobber (match_dup 1))]
+ (match_operand:QI 2 "general_operand" "a")
+ (match_operand:SI 3 "immediate_operand" "i")
+ (match_operand:SI 4 "immediate_operand" "0")] 0))
+ (clobber (match_dup 1))
+ (clobber (reg:CC 17))]
""
- "*
-{
- rtx xops[2];
-
- xops[0] = operands[0];
- xops[1] = constm1_rtx;
- output_asm_insn (\"cld\", operands);
- output_asm_insn (AS2 (mov%L0,%1,%0), xops);
- return \"repnz\;scas%B2\";
-}")
-
-/* Conditional move define_insns. */
+ "cld\;repnz{\;| }scasb"
+ [(set_attr "type" "multi")
+ (set_attr "length" "3")])
+
+;; Conditional move instructions.
(define_expand "movsicc"
[(set (match_operand:SI 0 "register_operand" "")
(if_then_else:SI (match_operand 1 "comparison_operator" "")
- (match_operand:SI 2 "nonimmediate_operand" "")
- (match_operand:SI 3 "nonimmediate_operand" "")))]
- "TARGET_CMOVE"
- "
-{
- if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
- FAIL;
+ (match_operand:SI 2 "general_operand" "")
+ (match_operand:SI 3 "general_operand" "")))]
+ ""
+ "if (!ix86_expand_int_movcc (operands)) FAIL; DONE;")
- operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
- GET_MODE (i386_compare_op0),
- i386_compare_op0, i386_compare_op1);
-}")
+;; Data flow gets confused by our desire for `sbbl reg,reg', and clearing
+;; the register first winds up with `sbbl $0,reg', which is also weird.
+;; So just document what we're doing explicitly.
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
- (if_then_else:SI (match_operator 1 "comparison_operator"
- [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
- (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
- (match_operand:SI 4 "nonimmediate_operand" "rm,rm,0,0")
- (match_operand:SI 5 "nonimmediate_operand" "0,0,rm,rm")))]
- "TARGET_CMOVE"
- "#")
+(define_insn "x86_movsicc_0_m1"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (if_then_else:SI (ltu (reg:CC 17) (const_int 0))
+ (const_int -1)
+ (const_int 0)))
+ (clobber (reg:CC 17))]
+ ""
+ "sbb{l}\\t%0, %0"
+ ; Since we don't have the proper number of operands for an alu insn,
+ ; fill in all the blanks.
+ [(set_attr "type" "alu")
+ (set_attr "memory" "none")
+ (set_attr "imm_disp" "false")
+ (set_attr "length" "2")])
(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
- (if_then_else:SI (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "r,m,r,m")
- (match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
- (match_operand:SI 4 "nonimmediate_operand" "rm,rm,0,0")
- (match_operand:SI 5 "nonimmediate_operand" "0,0,rm,rm")))]
- "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT"
- "#")
-
-(define_split
- [(set (match_operand:SI 0 "register_operand" "")
- (if_then_else:SI (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "")
- (const_int 0)])
- (match_operand:SI 3 "nonimmediate_operand" "")
- (match_operand:SI 4 "nonimmediate_operand" "")))]
- "TARGET_CMOVE && reload_completed"
- [(set (cc0)
- (match_dup 2))
- (set (match_dup 0)
- (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)])
- (match_dup 3) (match_dup 4)))]
- "")
-
-(define_split
- [(set (match_operand:SI 0 "register_operand" "")
- (if_then_else:SI (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "")
- (match_operand 3 "general_operand" "")])
- (match_operand:SI 4 "nonimmediate_operand" "")
- (match_operand:SI 5 "nonimmediate_operand" "")))]
- "TARGET_CMOVE && reload_completed"
- [(set (cc0) (compare (match_dup 2) (match_dup 3)))
- (set (match_dup 0)
- (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)])
- (match_dup 4) (match_dup 5)))]
- "")
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (if_then_else:SI (match_operator 1 "no_comparison_operator"
+ [(reg 17) (const_int 0)])
+ (match_operand:SI 2 "nonimmediate_operand" "rm,0")
+ (match_operand:SI 3 "nonimmediate_operand" "0,rm")))]
+ "TARGET_CMOVE"
+ "@
+ cmov%C1\\t{%2, %0|%0, %2}
+ cmov%c1\\t{%3, %0|%0, %3}"
+ [(set_attr "type" "icmov")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r,r")
(if_then_else:SI (match_operator 1 "comparison_operator"
- [(cc0) (const_int 0)])
+ [(reg:CC 17) (const_int 0)])
(match_operand:SI 2 "nonimmediate_operand" "rm,0")
(match_operand:SI 3 "nonimmediate_operand" "0,rm")))]
- "TARGET_CMOVE && reload_completed"
- "* return output_int_conditional_move (which_alternative, operands);")
+ "TARGET_CMOVE"
+ "@
+ cmov%C1\\t{%2, %0|%0, %2}
+ cmov%c1\\t{%3, %0|%0, %3}"
+ [(set_attr "type" "icmov")])
(define_expand "movhicc"
[(set (match_operand:HI 0 "register_operand" "")
@@ -7688,176 +7567,64 @@ byte_xor_operation:
(match_operand:HI 2 "nonimmediate_operand" "")
(match_operand:HI 3 "nonimmediate_operand" "")))]
"TARGET_CMOVE"
- "
-{
- if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
- FAIL;
-
- operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
- GET_MODE (i386_compare_op0),
- i386_compare_op0, i386_compare_op1);
-}")
+ "if (!ix86_expand_int_movcc (operands)) FAIL; DONE;")
(define_insn ""
- [(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
- (if_then_else:HI (match_operator 1 "comparison_operator"
- [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
- (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
- (match_operand:HI 4 "nonimmediate_operand" "rm,rm,0,0")
- (match_operand:HI 5 "nonimmediate_operand" "0,0,rm,rm")))]
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (if_then_else:HI (match_operator 1 "no_comparison_operator"
+ [(reg 17) (const_int 0)])
+ (match_operand:HI 2 "nonimmediate_operand" "rm,0")
+ (match_operand:HI 3 "nonimmediate_operand" "0,rm")))]
"TARGET_CMOVE"
- "#")
-
-(define_insn ""
- [(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
- (if_then_else:HI (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "r,m,r,m")
- (match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
- (match_operand:HI 4 "nonimmediate_operand" "rm,rm,0,0")
- (match_operand:HI 5 "nonimmediate_operand" "0,0,rm,rm")))]
- "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT"
- "#")
-
-(define_split
- [(set (match_operand:HI 0 "register_operand" "")
- (if_then_else:HI (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "")
- (const_int 0)])
- (match_operand:HI 3 "nonimmediate_operand" "")
- (match_operand:HI 4 "nonimmediate_operand" "")))]
- "TARGET_CMOVE && reload_completed"
- [(set (cc0)
- (match_dup 2))
- (set (match_dup 0)
- (if_then_else:HI (match_op_dup 1 [(cc0) (const_int 0)])
- (match_dup 3) (match_dup 4)))]
- "")
-
-(define_split
- [(set (match_operand:HI 0 "register_operand" "")
- (if_then_else:HI (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "")
- (match_operand 3 "general_operand" "")])
- (match_operand:HI 4 "nonimmediate_operand" "")
- (match_operand:HI 5 "nonimmediate_operand" "")))]
- "TARGET_CMOVE && reload_completed"
- [(set (cc0)
- (compare (match_dup 2) (match_dup 3)))
- (set (match_dup 0)
- (if_then_else:HI (match_op_dup 1 [(cc0) (const_int 0)])
- (match_dup 4) (match_dup 5)))]
- "")
+ "@
+ cmov%C1\\t{%2, %0|%0, %2}
+ cmov%c1\\t{%3, %0|%0, %3}"
+ [(set_attr "type" "icmov")])
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r,r")
(if_then_else:HI (match_operator 1 "comparison_operator"
- [(cc0) (const_int 0)])
+ [(reg:CC 17) (const_int 0)])
(match_operand:HI 2 "nonimmediate_operand" "rm,0")
(match_operand:HI 3 "nonimmediate_operand" "0,rm")))]
- "TARGET_CMOVE && reload_completed"
- "* return output_int_conditional_move (which_alternative, operands);")
+ "TARGET_CMOVE"
+ "@
+ cmov%C1\\t{%2, %0|%0, %2}
+ cmov%c1\\t{%3, %0|%0, %3}"
+ [(set_attr "type" "icmov")])
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "")
+ (if_then_else:HI (match_operator 1 "comparison_operator"
+ [(reg 17) (const_int 0)])
+ (match_operand:HI 2 "register_operand" "")
+ (match_operand:HI 3 "register_operand" "")))]
+ "! TARGET_PARTIAL_REG_STALL && TARGET_CMOVE"
+ [(set (match_dup 0)
+ (if_then_else:SI (match_dup 1) (match_dup 2) (match_dup 3)))]
+ "operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[2] = gen_lowpart (SImode, operands[2]);
+ operands[3] = gen_lowpart (SImode, operands[3]);")
+
(define_expand "movsfcc"
[(set (match_operand:SF 0 "register_operand" "")
(if_then_else:SF (match_operand 1 "comparison_operator" "")
(match_operand:SF 2 "register_operand" "")
(match_operand:SF 3 "register_operand" "")))]
"TARGET_CMOVE"
- "
-{
- rtx temp;
-
- if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
- FAIL;
-
- /* The floating point conditional move instructions don't directly
- support conditions resulting from a signed integer comparison. */
-
- switch (GET_CODE (operands[1]))
- {
- case LT:
- case LE:
- case GE:
- case GT:
- temp = emit_store_flag (gen_reg_rtx (QImode),
- GET_CODE (operands[1]), i386_compare_op0, i386_compare_op1,
- VOIDmode, 0, 0);
-
- if (!temp)
- FAIL;
-
- operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx);
- break;
-
- default:
- operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
- GET_MODE (i386_compare_op0),
- i386_compare_op0, i386_compare_op1);
- break;
- }
-}")
-
-(define_insn ""
- [(set (match_operand:SF 0 "register_operand" "=f,f,f,f")
- (if_then_else:SF (match_operator 1 "comparison_operator"
- [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
- (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
- (match_operand:SF 4 "register_operand" "f,f,0,0")
- (match_operand:SF 5 "register_operand" "0,0,f,f")))]
- "TARGET_CMOVE
- && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
- && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
- "#")
-
-(define_insn ""
- [(set (match_operand:SF 0 "register_operand" "=f,f,f,f")
- (if_then_else:SF (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "r,m,r,m")
- (match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
- (match_operand:SF 4 "register_operand" "f,f,0,0")
- (match_operand:SF 5 "register_operand" "0,0,f,f")))]
- "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT
- && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
- && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
- "#")
-
-(define_split
- [(set (match_operand:SF 0 "register_operand" "")
- (if_then_else:SF (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "")
- (const_int 0)])
- (match_operand:SF 3 "register_operand" "")
- (match_operand:SF 4 "register_operand" "")))]
- "TARGET_CMOVE && reload_completed"
- [(set (cc0)
- (match_dup 2))
- (set (match_dup 0)
- (if_then_else:SF (match_op_dup 1 [(cc0) (const_int 0)])
- (match_dup 3) (match_dup 4)))]
- "")
-
-(define_split
- [(set (match_operand:SF 0 "register_operand" "")
- (if_then_else:SF (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "")
- (match_operand 3 "general_operand" "")])
- (match_operand:SF 4 "register_operand" "")
- (match_operand:SF 5 "register_operand" "")))]
- "TARGET_CMOVE && reload_completed"
- [(set (cc0) (compare (match_dup 2) (match_dup 3)))
- (set (match_dup 0)
- (if_then_else:SF (match_op_dup 1 [(cc0) (const_int 0)])
- (match_dup 4) (match_dup 5)))]
- "")
+ "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;")
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=f,f")
- (if_then_else:SF (match_operator 1 "comparison_operator"
- [(cc0) (const_int 0)])
+ (if_then_else:SF (match_operator 1 "fcmov_comparison_operator"
+ [(reg 17) (const_int 0)])
(match_operand:SF 2 "register_operand" "f,0")
(match_operand:SF 3 "register_operand" "0,f")))]
- "TARGET_CMOVE && reload_completed"
- "* return output_fp_conditional_move (which_alternative, operands);")
+ "TARGET_CMOVE"
+ "@
+ fcmov%F1\\t{%2, %0|%0, %2}
+ fcmov%f1\\t{%3, %0|%0, %3}"
+ [(set_attr "type" "fcmov")])
(define_expand "movdfcc"
[(set (match_operand:DF 0 "register_operand" "")
@@ -7865,101 +7632,19 @@ byte_xor_operation:
(match_operand:DF 2 "register_operand" "")
(match_operand:DF 3 "register_operand" "")))]
"TARGET_CMOVE"
- "
-{
- rtx temp;
-
- if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
- FAIL;
-
- /* The floating point conditional move instructions don't directly
- support conditions resulting from a signed integer comparison. */
-
- switch (GET_CODE (operands[1]))
- {
- case LT:
- case LE:
- case GE:
- case GT:
- temp = emit_store_flag (gen_reg_rtx (QImode),
- GET_CODE (operands[1]), i386_compare_op0, i386_compare_op1,
- VOIDmode, 0, 0);
-
- if (!temp)
- FAIL;
-
- operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx);
- break;
-
- default:
- operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
- GET_MODE (i386_compare_op0),
- i386_compare_op0, i386_compare_op1);
- break;
- }
-}")
-
-(define_insn ""
- [(set (match_operand:DF 0 "register_operand" "=f,f,f,f")
- (if_then_else:DF (match_operator 1 "comparison_operator"
- [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
- (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
- (match_operand:DF 4 "register_operand" "f,f,0,0")
- (match_operand:DF 5 "register_operand" "0,0,f,f")))]
- "TARGET_CMOVE
- && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
- && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
- "#")
-
-(define_insn ""
- [(set (match_operand:DF 0 "register_operand" "=f,f,f,f")
- (if_then_else:DF (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "r,m,r,m")
- (match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
- (match_operand:DF 4 "register_operand" "f,f,0,0")
- (match_operand:DF 5 "register_operand" "0,0,f,f")))]
- "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT
- && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
- && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
- "#")
-
-(define_split
- [(set (match_operand:DF 0 "register_operand" "")
- (if_then_else:DF (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "")
- (const_int 0)])
- (match_operand:DF 3 "register_operand" "")
- (match_operand:DF 4 "register_operand" "")))]
- "TARGET_CMOVE && reload_completed"
- [(set (cc0)
- (match_dup 2))
- (set (match_dup 0)
- (if_then_else:DF (match_op_dup 1 [(cc0) (const_int 0)])
- (match_dup 3) (match_dup 4)))]
- "")
-
-(define_split
- [(set (match_operand:DF 0 "register_operand" "")
- (if_then_else:DF (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "")
- (match_operand 3 "general_operand" "")])
- (match_operand:DF 4 "register_operand" "")
- (match_operand:DF 5 "register_operand" "")))]
- "TARGET_CMOVE && reload_completed"
- [(set (cc0) (compare (match_dup 2) (match_dup 3)))
- (set (match_dup 0)
- (if_then_else:DF (match_op_dup 1 [(cc0) (const_int 0)])
- (match_dup 4) (match_dup 5)))]
- "")
+ "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;")
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f,f")
- (if_then_else:DF (match_operator 1 "comparison_operator"
- [(cc0) (const_int 0)])
+ (if_then_else:DF (match_operator 1 "fcmov_comparison_operator"
+ [(reg 17) (const_int 0)])
(match_operand:DF 2 "register_operand" "f,0")
(match_operand:DF 3 "register_operand" "0,f")))]
- "TARGET_CMOVE && reload_completed"
- "* return output_fp_conditional_move (which_alternative, operands);")
+ "TARGET_CMOVE"
+ "@
+ fcmov%F1\\t{%2, %0|%0, %2}
+ fcmov%f1\\t{%3, %0|%0, %3}"
+ [(set_attr "type" "fcmov")])
(define_expand "movxfcc"
[(set (match_operand:XF 0 "register_operand" "")
@@ -7967,220 +7652,81 @@ byte_xor_operation:
(match_operand:XF 2 "register_operand" "")
(match_operand:XF 3 "register_operand" "")))]
"TARGET_CMOVE"
- "
-{
- rtx temp;
-
- if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
- FAIL;
-
- /* The floating point conditional move instructions don't directly
- support conditions resulting from a signed integer comparison. */
-
- switch (GET_CODE (operands[1]))
- {
- case LT:
- case LE:
- case GE:
- case GT:
- temp = emit_store_flag (gen_reg_rtx (QImode),
- GET_CODE (operands[1]), i386_compare_op0, i386_compare_op1,
- VOIDmode, 0, 0);
-
- if (!temp)
- FAIL;
-
- operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx);
- break;
-
- default:
- operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
- GET_MODE (i386_compare_op0),
- i386_compare_op0, i386_compare_op1);
- break;
- }
-}")
-
-(define_insn ""
- [(set (match_operand:XF 0 "register_operand" "=f,f,f,f")
- (if_then_else:XF (match_operator 1 "comparison_operator"
- [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
- (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
- (match_operand:XF 4 "register_operand" "f,f,0,0")
- (match_operand:XF 5 "register_operand" "0,0,f,f")))]
- "TARGET_CMOVE
- && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
- && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
- "#")
-
-(define_insn ""
- [(set (match_operand:XF 0 "register_operand" "=f,f,f,f")
- (if_then_else:XF (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "r,m,r,m")
- (match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
- (match_operand:XF 4 "register_operand" "f,f,0,0")
- (match_operand:XF 5 "register_operand" "0,0,f,f")))]
- "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT
- && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
- && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
- "#")
-
-(define_split
- [(set (match_operand:XF 0 "register_operand" "")
- (if_then_else:XF (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "")
- (const_int 0)])
- (match_operand:XF 3 "register_operand" "")
- (match_operand:XF 4 "register_operand" "")))]
- "TARGET_CMOVE && reload_completed"
- [(set (cc0)
- (match_dup 2))
- (set (match_dup 0)
- (if_then_else:XF (match_op_dup 1 [(cc0) (const_int 0)])
- (match_dup 3) (match_dup 4)))]
- "")
-
-(define_split
- [(set (match_operand:XF 0 "register_operand" "")
- (if_then_else:XF (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "")
- (match_operand 3 "general_operand" "")])
- (match_operand:XF 4 "register_operand" "")
- (match_operand:XF 5 "register_operand" "")))]
- "TARGET_CMOVE && reload_completed"
- [(set (cc0) (compare (match_dup 2) (match_dup 3)))
- (set (match_dup 0)
- (if_then_else:XF (match_op_dup 1 [(cc0) (const_int 0)])
- (match_dup 4) (match_dup 5)))]
- "")
+ "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;")
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f,f")
- (if_then_else:XF (match_operator 1 "comparison_operator"
- [(cc0) (const_int 0)])
+ (if_then_else:XF (match_operator 1 "fcmov_comparison_operator"
+ [(reg 17) (const_int 0)])
(match_operand:XF 2 "register_operand" "f,0")
(match_operand:XF 3 "register_operand" "0,f")))]
- "TARGET_CMOVE && reload_completed"
- "* return output_fp_conditional_move (which_alternative, operands);")
-
-(define_expand "movdicc"
- [(set (match_operand:DI 0 "register_operand" "")
- (if_then_else:DI (match_operand 1 "comparison_operator" "")
- (match_operand:DI 2 "nonimmediate_operand" "")
- (match_operand:DI 3 "nonimmediate_operand" "")))]
"TARGET_CMOVE"
- "
-{
- if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
- FAIL;
-
- operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
- GET_MODE (i386_compare_op0),
- i386_compare_op0, i386_compare_op1);
-}")
-
-(define_insn ""
- [(set (match_operand:DI 0 "register_operand" "=&r,&r,&r,&r")
- (if_then_else:DI (match_operator 1 "comparison_operator"
- [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
- (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
- (match_operand:DI 4 "nonimmediate_operand" "ro,ro,0,0")
- (match_operand:DI 5 "nonimmediate_operand" "0,0,ro,ro")))]
- "TARGET_CMOVE"
- "#")
-
-(define_insn ""
- [(set (match_operand:DI 0 "register_operand" "=&r,&r,&r,&r")
- (if_then_else:DI (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "r,m,r,m")
- (match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
- (match_operand:DI 4 "nonimmediate_operand" "ro,ro,0,0")
- (match_operand:DI 5 "nonimmediate_operand" "0,0,ro,ro")))]
- "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT"
- "#")
+ "@
+ fcmov%F1\\t{%2, %0|%0, %2}
+ fcmov%f1\\t{%3, %0|%0, %3}"
+ [(set_attr "type" "fcmov")])
+
+;; Misc patterns (?)
-(define_split
- [(set (match_operand:DI 0 "register_operand" "")
- (if_then_else:DI (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "")
- (const_int 0)])
- (match_operand:DI 3 "nonimmediate_operand" "")
- (match_operand:DI 4 "nonimmediate_operand" "")))]
- "TARGET_CMOVE && reload_completed"
- [(set (cc0)
- (match_dup 2))
- (set (match_dup 5)
- (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)])
- (match_dup 7) (match_dup 9)))
- (set (match_dup 6)
- (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)])
- (match_dup 8) (match_dup 10)))]
- "split_di (&operands[0], 1, &operands[5], &operands[6]);
- split_di (&operands[3], 1, &operands[7], &operands[8]);
- split_di (&operands[4], 1, &operands[9], &operands[10]);")
+;; This pattern exists to put a dependancy on all ebp-based memory accesses.
+;; Otherwise there will be nothing to keep
+;;
+;; [(set (reg ebp) (reg esp))]
+;; [(set (reg esp) (plus (reg esp) (const_int -160000)))
+;; (clobber (eflags)]
+;; [(set (mem (plus (reg ebp) (const_int -160000))) (const_int 0))]
+;;
+;; in proper program order.
-(define_split
- [(set (match_operand:DI 0 "register_operand" "")
- (if_then_else:DI (match_operator 1 "comparison_operator"
- [(match_operand 2 "nonimmediate_operand" "")
- (match_operand 3 "general_operand" "")])
- (match_operand:DI 4 "nonimmediate_operand" "")
- (match_operand:DI 5 "nonimmediate_operand" "")))]
- "TARGET_CMOVE && reload_completed"
- [(set (cc0) (compare (match_dup 2) (match_dup 3)))
- (set (match_dup 6)
- (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)])
- (match_dup 8) (match_dup 10)))
- (set (match_dup 7)
- (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)])
- (match_dup 9) (match_dup 11)))]
- "split_di (&operands[0], 1, &operands[6], &operands[7]);
- split_di (&operands[4], 1, &operands[8], &operands[9]);
- split_di (&operands[5], 1, &operands[10], &operands[11]);")
-
-(define_insn "strlensi_unroll"
- [(set (match_operand:SI 0 "register_operand" "=&r,&r")
- (unspec:SI [(mem:BLK (match_operand:SI 1 "address_operand" "r,r"))
- (match_operand:SI 2 "immediate_operand" "i,i")] 0))
- (clobber (match_scratch:SI 3 "=&q,&r"))]
- "optimize > 1"
- "* return output_strlen_unroll (operands);")
-
-;; the only difference between the following patterns is the register preference
-;; on a pentium using a q-register saves one clock cycle per 4 characters
-
-(define_insn "strlensi_unroll4"
- [(set (match_operand:SI 0 "register_operand" "=r,r")
- (unspec:SI [(mem:BLK (match_operand:SI 3 "register_operand" "0,0"))
- (match_operand:SI 1 "immediate_operand" "i,i")
- (match_operand:SI 2 "register_operand" "+q,!r")] 0))
- (clobber (match_dup 2))]
- "(TARGET_USE_ANY_REG && optimize > 1)"
- "* return output_strlen_unroll (operands);")
+(define_insn "prologue_allocate_stack"
+ [(set (match_operand:SI 0 "register_operand" "r")
+ (plus:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand:SI 2 "nonmemory_operand" "ri")))
+ (set (match_operand:SI 3 "register_operand" "r")
+ (match_dup 3))
+ (clobber (reg:CC 17))]
+ ""
+ "*
+{
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (INTVAL (operands[2]) == 128
+ || (INTVAL (operands[2]) < 0
+ && INTVAL (operands[2]) != -128)))
+ {
+ operands[2] = GEN_INT (-INTVAL (operands[2]));
+ return \"sub{l}\\t{%2, %0|%0, %2}\";
+ }
+ return \"add{l}\\t{%2, %0|%0, %2}\";
+}"
+ [(set_attr "type" "alu")])
-(define_insn "strlensi_unroll5"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (unspec:SI [(mem:BLK (match_operand:SI 3 "register_operand" "0"))
- (match_operand:SI 1 "immediate_operand" "i")
- (match_operand:SI 2 "register_operand" "+q")] 0))
- (clobber (match_dup 2))]
- "(TARGET_USE_Q_REG && optimize > 1)"
- "* return output_strlen_unroll (operands);"
-)
+(define_insn "epilogue_deallocate_stack"
+ [(set (match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "register_operand" "r"))
+ (set (match_dup 1) (match_dup 1))]
+ ""
+ "mov{l}\\t{%1, %0|%0, %1}"
+ [(set_attr "type" "imov")])
(define_insn "allocate_stack_worker"
[(unspec:SI [(match_operand:SI 0 "register_operand" "a")] 3)
(set (reg:SI 7) (minus:SI (reg:SI 7) (match_dup 0)))
- (clobber (match_dup 0))]
+ (clobber (match_dup 0))
+ (clobber (reg:CC 17))]
"TARGET_STACK_PROBE"
- "* return AS1(call,__alloca);"
- [(set_attr "memory" "none")])
+ "call\\t__alloca"
+ [(set_attr "type" "multi")
+ (set_attr "length" "5")])
(define_expand "allocate_stack"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (minus:SI (reg:SI 7) (match_operand:SI 1 "general_operand" "")))
- (set (reg:SI 7) (minus:SI (reg:SI 7) (match_dup 1)))]
- "TARGET_STACK_PROBE"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (reg:SI 7)
+ (match_operand:SI 1 "general_operand" "")))
+ (clobber (reg:CC 17))])
+ (parallel [(set (reg:SI 7)
+ (minus:SI (reg:SI 7) (match_dup 1)))
+ (clobber (reg:CC 17))])]
+ "TARGET_STACK_PROBE"
"
{
#ifdef CHECK_STACK_LIMIT
@@ -8205,3 +7751,355 @@ byte_xor_operation:
load_pic_register (1);
DONE;
}")
+
+;; RTL Peephole optimizations, run before sched2. These primarily look to
+;; transform a complex memory operation into two memory to register operations.
+
+;; Don't push memory operands
+(define_peephole2
+ [(match_scratch:SI 2 "r")
+ (set (match_operand:SI 0 "push_operand" "")
+ (match_operand:SI 1 "memory_operand" ""))]
+ "! optimize_size && ! TARGET_PUSH_MEMORY"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_dup 0) (match_dup 2))]
+ "")
+
+(define_peephole2
+ [(match_scratch:HI 2 "r")
+ (set (match_operand:HI 0 "push_operand" "")
+ (match_operand:HI 1 "memory_operand" ""))]
+ "! optimize_size && ! TARGET_PUSH_MEMORY"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_dup 0) (match_dup 2))]
+ "")
+
+(define_peephole2
+ [(match_scratch:QI 2 "q")
+ (set (match_operand:QI 0 "push_operand" "")
+ (match_operand:QI 1 "memory_operand" ""))]
+ "! optimize_size && ! TARGET_PUSH_MEMORY"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_dup 0) (match_dup 2))]
+ "")
+
+;; Don't move an immediate directly to memory when the instruction
+;; gets too big.
+(define_peephole2
+ [(match_scratch:SI 1 "r")
+ (set (match_operand:SI 0 "memory_operand" "")
+ (const_int 0))]
+ "! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
+ && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
+ && TARGET_SPLIT_LONG_MOVES"
+ [(parallel [(set (match_dup 1) (const_int 0))
+ (clobber (reg:CC 17))])
+ (set (match_dup 0) (match_dup 1))]
+ "")
+
+(define_peephole2
+ [(match_scratch:HI 1 "r")
+ (set (match_operand:HI 0 "memory_operand" "")
+ (const_int 0))]
+ "! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
+ && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
+ && TARGET_SPLIT_LONG_MOVES"
+ [(parallel [(set (match_dup 1) (const_int 0))
+ (clobber (reg:CC 17))])
+ (set (match_dup 0) (match_dup 1))]
+ "")
+
+(define_peephole2
+ [(match_scratch:QI 1 "q")
+ (set (match_operand:QI 0 "memory_operand" "")
+ (const_int 0))]
+ "! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
+ && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
+ && TARGET_SPLIT_LONG_MOVES"
+ [(parallel [(set (match_dup 1) (const_int 0))
+ (clobber (reg:CC 17))])
+ (set (match_dup 0) (match_dup 1))]
+ "")
+
+(define_peephole2
+ [(match_scratch:SI 2 "r")
+ (set (match_operand:SI 0 "memory_operand" "")
+ (match_operand:SI 1 "immediate_operand" ""))]
+ "! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
+ && TARGET_SPLIT_LONG_MOVES"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_dup 0) (match_dup 2))]
+ "")
+
+(define_peephole2
+ [(match_scratch:HI 2 "r")
+ (set (match_operand:HI 0 "memory_operand" "")
+ (match_operand:HI 1 "immediate_operand" ""))]
+ "! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
+ && TARGET_SPLIT_LONG_MOVES"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_dup 0) (match_dup 2))]
+ "")
+
+(define_peephole2
+ [(match_scratch:QI 2 "q")
+ (set (match_operand:QI 0 "memory_operand" "")
+ (match_operand:QI 1 "immediate_operand" ""))]
+ "! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
+ && TARGET_SPLIT_LONG_MOVES"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_dup 0) (match_dup 2))]
+ "")
+
+;; Don't compare memory with zero, load and use a test instead.
+(define_peephole2
+ [(match_scratch:SI 3 "r")
+ (set (reg:CCNO 17)
+ (compare:CCNO (match_operand:SI 0 "memory_operand" "")
+ (const_int 0)))]
+ "! optimize_size"
+ [(set (match_dup 3) (match_dup 0))
+ (set (reg:CCNO 17) (compare:CCNO (match_dup 3) (const_int 0)))]
+ "")
+
+;; NOT is not pairable on Pentium, while XOR is, but one byte longer.
+;; Don't split NOTs with a displacement operand, because resulting XOR
+;; will not be pariable anyway.
+;;
+;; On AMD K6, NOT is vector decoded with memory operand that can not be
+;; represented using a modRM byte. The XOR replacement is long decoded,
+;; so this split helps here as well.
+;;
+;; Note: Can't do this as a regular split because reg_dead_p assumes
+;; resource info is live.
+
+(define_peephole2
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
+ "!optimize_size
+ && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
+ && ((TARGET_PENTIUM
+ && (GET_CODE (operands[0]) != MEM
+ || !memory_displacement_operand (operands[0], SImode)))
+ || (TARGET_K6 && long_memory_operand (operands[0], SImode)))"
+ [(parallel [(set (match_dup 0)
+ (xor:SI (match_dup 1) (const_int -1)))
+ (clobber (reg:CC 17))])]
+ "")
+
+(define_peephole2
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (not:HI (match_operand:HI 1 "nonimmediate_operand" "0")))]
+ "!optimize_size
+ && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
+ && ((TARGET_PENTIUM
+ && (GET_CODE (operands[0]) != MEM
+ || !memory_displacement_operand (operands[0], HImode)))
+ || (TARGET_K6 && long_memory_operand (operands[0], HImode)))"
+ [(parallel [(set (match_dup 0)
+ (xor:HI (match_dup 1) (const_int -1)))
+ (clobber (reg:CC 17))])]
+ "")
+
+(define_peephole2
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=rm")
+ (not:QI (match_operand:QI 1 "nonimmediate_operand" "0")))]
+ "!optimize_size
+ && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
+ && ((TARGET_PENTIUM
+ && (GET_CODE (operands[0]) != MEM
+ || !memory_displacement_operand (operands[0], QImode)))
+ || (TARGET_K6 && long_memory_operand (operands[0], QImode)))"
+ [(parallel [(set (match_dup 0)
+ (xor:QI (match_dup 1) (const_int -1)))
+ (clobber (reg:CC 17))])]
+ "")
+
+;; Non pairable "test imm, reg" instructions can be translated to
+;; "and imm, reg" if reg dies. The "and" form is also shorter (one
+;; byte opcode instead of two, have a short form for byte operands),
+;; so do it for other CPUs as well. Given that the value was dead,
+;; this should not create any new dependancies. Pass on the sub-word
+;; versions if we're concerned about partial register stalls.
+
+(define_peephole2
+ [(set (reg:CCNO 17)
+ (compare:CCNO (and:SI (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "immediate_operand" ""))
+ (const_int 0)))]
+ "(true_regnum (operands[0]) != 0
+ || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'K'))
+ && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))"
+ [(parallel
+ [(set (reg:CCNO 17)
+ (compare:CCNO (and:SI (match_dup 0)
+ (match_dup 1))
+ (const_int 0)))
+ (set (match_dup 0)
+ (and:SI (match_dup 0) (match_dup 1)))])]
+ "")
+
+(define_peephole2
+ [(set (reg:CCNO 17)
+ (compare:CCNO (and:HI (match_operand:HI 0 "register_operand" "")
+ (match_operand:HI 1 "immediate_operand" ""))
+ (const_int 0)))]
+ "! TARGET_PARTIAL_REG_STALL
+ && (true_regnum (operands[0]) != 0
+ || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'K'))
+ && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))"
+ [(parallel
+ [(set (reg:CCNO 17)
+ (compare:CCNO (and:HI (match_dup 0)
+ (match_dup 1))
+ (const_int 0)))
+ (set (match_dup 0)
+ (and:HI (match_dup 0) (match_dup 1)))])]
+ "")
+
+(define_peephole2
+ [(set (reg:CCNO 17)
+ (compare:CCNO (and:QI (match_operand:QI 0 "register_operand" "")
+ (match_operand:QI 1 "immediate_operand" ""))
+ (const_int 0)))]
+ "! TARGET_PARTIAL_REG_STALL
+ && true_regnum (operands[0]) != 0
+ && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))"
+ [(parallel
+ [(set (reg:CCNO 17)
+ (compare:CCNO (and:QI (match_dup 0)
+ (match_dup 1))
+ (const_int 0)))
+ (set (match_dup 0)
+ (and:QI (match_dup 0) (match_dup 1)))])]
+ "")
+
+(define_peephole2
+ [(set (reg:CCNO 17)
+ (compare:CCNO
+ (and:SI
+ (zero_extract:SI
+ (match_operand 0 "ext_register_operand" "q")
+ (const_int 8)
+ (const_int 8))
+ (match_operand 1 "const_int_operand" "n"))
+ (const_int 0)))]
+ "! TARGET_PARTIAL_REG_STALL
+ && true_regnum (operands[0]) != 0
+ && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))"
+ [(parallel [(set (reg:CCNO 17)
+ (compare:CCNO
+ (and:SI
+ (zero_extract:SI
+ (match_dup 0)
+ (const_int 8)
+ (const_int 8))
+ (match_dup 1))
+ (const_int 0)))
+ (set (zero_extract:SI (match_dup 0)
+ (const_int 8)
+ (const_int 8))
+ (and:SI
+ (zero_extract:SI
+ (match_dup 0)
+ (const_int 8)
+ (const_int 8))
+ (match_dup 1)))])]
+ "")
+
+;; Don't do logical operations with memory inputs.
+(define_peephole2
+ [(match_scratch:SI 2 "r")
+ (parallel [(set (match_operand:SI 0 "register_operand" "")
+ (match_operator:SI 3 "arith_or_logical_operator"
+ [(match_dup 0)
+ (match_operand:SI 1 "memory_operand" "")]))
+ (clobber (reg:CC 17))])]
+ "! optimize_size && ! TARGET_READ_MODIFY"
+ [(set (match_dup 2) (match_dup 1))
+ (parallel [(set (match_dup 0)
+ (match_op_dup 3 [(match_dup 0) (match_dup 2)]))
+ (clobber (reg:CC 17))])]
+ "")
+
+(define_peephole2
+ [(match_scratch:SI 2 "r")
+ (parallel [(set (match_operand:SI 0 "register_operand" "")
+ (match_operator:SI 3 "arith_or_logical_operator"
+ [(match_operand:SI 1 "memory_operand" "")
+ (match_dup 0)]))
+ (clobber (reg:CC 17))])]
+ "! optimize_size && ! TARGET_READ_MODIFY"
+ [(set (match_dup 2) (match_dup 1))
+ (parallel [(set (match_dup 0)
+ (match_op_dup 3 [(match_dup 2) (match_dup 0)]))
+ (clobber (reg:CC 17))])]
+ "")
+
+; Don't do logical operations with memory outputs
+;
+; These two don't make sense for PPro/PII -- we're expanding a 4-uop
+; instruction into two 1-uop insns plus a 2-uop insn. That last has
+; the same decoder scheduling characteristics as the original.
+
+(define_peephole2
+ [(match_scratch:SI 2 "r")
+ (parallel [(set (match_operand:SI 0 "memory_operand" "")
+ (match_operator:SI 3 "arith_or_logical_operator"
+ [(match_dup 0)
+ (match_operand:SI 1 "nonmemory_operand" "")]))
+ (clobber (reg:CC 17))])]
+ "! optimize_size && ! TARGET_READ_MODIFY_WRITE"
+ [(set (match_dup 2) (match_dup 0))
+ (parallel [(set (match_dup 2)
+ (match_op_dup 3 [(match_dup 2) (match_dup 1)]))
+ (clobber (reg:CC 17))])
+ (set (match_dup 0) (match_dup 2))]
+ "")
+
+(define_peephole2
+ [(match_scratch:SI 2 "r")
+ (parallel [(set (match_operand:SI 0 "memory_operand" "")
+ (match_operator:SI 3 "arith_or_logical_operator"
+ [(match_operand:SI 1 "nonmemory_operand" "")
+ (match_dup 0)]))
+ (clobber (reg:CC 17))])]
+ "! optimize_size && ! TARGET_READ_MODIFY_WRITE"
+ [(set (match_dup 2) (match_dup 0))
+ (parallel [(set (match_dup 2)
+ (match_op_dup 3 [(match_dup 1) (match_dup 2)]))
+ (clobber (reg:CC 17))])
+ (set (match_dup 0) (match_dup 2))]
+ "")
+
+;; Attempt to always use XOR for zeroing registers.
+(define_peephole2
+ [(set (match_operand 0 "register_operand" "")
+ (const_int 0))]
+ "(GET_MODE (operands[0]) == QImode
+ || GET_MODE (operands[0]) == HImode
+ || GET_MODE (operands[0]) == SImode)
+ && (! TARGET_USE_MOV0 || optimize_size)
+ && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
+ [(parallel [(set (match_dup 0) (const_int 0))
+ (clobber (reg:CC 17))])]
+ "")
+
+;; For HI and SI modes, or $-1,reg is smaller than mov $-1,reg.
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand" "")
+ (const_int -1))]
+ "optimize_size && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
+ [(parallel [(set (match_dup 0)
+ (ior:SI (match_dup 0) (const_int -1)))
+ (clobber (reg:CC 17))])]
+ "")
+
+(define_peephole2
+ [(set (match_operand:HI 0 "register_operand" "")
+ (const_int -1))]
+ "optimize_size && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
+ [(parallel [(set (match_dup 0)
+ (ior:HI (match_dup 0) (const_int -1)))
+ (clobber (reg:CC 17))])]
+ "")
diff --git a/gcc/config/i386/unix.h b/gcc/config/i386/unix.h
index 771d802..03095c4 100644
--- a/gcc/config/i386/unix.h
+++ b/gcc/config/i386/unix.h
@@ -22,79 +22,13 @@ Boston, MA 02111-1307, USA. */
that are the same for all the i386 Unix systems
(though they may differ in non-Unix systems). */
-/* Define some concatenation macros to concatenate an opcode
- and one, two or three operands. In other assembler syntaxes
- they may alter the order of ther operands. */
-
-/* Note that the other files fail to use these
- in some of the places where they should. */
-
-#if defined(__STDC__) || defined(ALMOST_STDC)
-#define AS2(a,b,c) #a " " #b "," #c
-#define AS2C(b,c) " " #b "," #c
-#define AS3(a,b,c,d) #a " " #b "," #c "," #d
-#define AS1(a,b) #a " " #b
-#else
-#define AS1(a,b) "a b"
-#define AS2(a,b,c) "a b,c"
-#define AS2C(b,c) " b,c"
-#define AS3(a,b,c,d) "a b,c,d"
-#endif
+#define DEFAULT_ASSEMBLER_DIALECT 0
/* Define macro used to output shift-double opcodes when the shift
count is in %cl. Some assemblers require %cl as an argument;
some don't. This macro controls what to do: by default, don't
print %cl. */
#define SHIFT_DOUBLE_OMITS_COUNT 1
-#define AS3_SHIFT_DOUBLE(a,b,c,d) \
- (SHIFT_DOUBLE_OMITS_COUNT ? AS2 (a,c,d) : AS3 (a,b,c,d))
-
-/* Output the size-letter for an opcode.
- CODE is the letter used in an operand spec (L, B, W, S or Q).
- CH is the corresponding lower case letter
- (except if CODE is `Q' then CH is `l', unless GAS_MNEMONICS). */
-#define PUT_OP_SIZE(CODE,CH,FILE) putc (CH,(FILE))
-
-/* Opcode suffix for fullword insn. */
-#define L_SIZE "l"
-
-/* Prefix for register names in this syntax. */
-#define RP "%"
-
-/* Prefix for immediate operands in this syntax. */
-#define IP "$"
-
-/* Indirect call instructions should use `*'. */
-#define USE_STAR 1
-
-/* Prefix for a memory-operand X. */
-#define PRINT_PTR(X, FILE)
-
-/* Delimiters that surround base reg and index reg. */
-#define ADDR_BEG(FILE) putc('(', (FILE))
-#define ADDR_END(FILE) putc(')', (FILE))
-
-/* Print an index register (whose rtx is IREG). */
-#define PRINT_IREG(FILE,IREG) \
- do \
- { fputs (",", (FILE)); PRINT_REG ((IREG), 0, (FILE)); } \
- while (0)
-
-/* Print an index scale factor SCALE. */
-#define PRINT_SCALE(FILE,SCALE) \
- if ((SCALE) != 1) fprintf ((FILE), ",%d", (SCALE))
-
-/* Print a base/index combination.
- BREG is the base reg rtx, IREG is the index reg rtx,
- and SCALE is the index scale factor (an integer). */
-
-#define PRINT_B_I_S(BREG,IREG,SCALE,FILE) \
- { ADDR_BEG (FILE); \
- if (BREG) PRINT_REG ((BREG), 0, (FILE)); \
- if ((IREG) != 0) \
- { PRINT_IREG ((FILE), (IREG)); \
- PRINT_SCALE ((FILE), (SCALE)); } \
- ADDR_END (FILE); }
/* Define the syntax of pseudo-ops, labels and comments. */
@@ -148,43 +82,48 @@ Boston, MA 02111-1307, USA. */
/* Output code to add DELTA to the first argument, and then jump to FUNCTION.
Used for C++ multiple inheritance. */
-#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
-do { \
- tree parm; \
- \
- if (i386_regparm > 0) \
- parm = TYPE_ARG_TYPES (TREE_TYPE (function)); \
- else \
- parm = NULL_TREE; \
- for (; parm; parm = TREE_CHAIN (parm)) \
- if (TREE_VALUE (parm) == void_type_node) \
- break; \
- fprintf (FILE, "\taddl $%d,%s\n", DELTA, \
- parm ? "%eax" \
- : aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION))) ? "8(%esp)" \
- : "4(%esp)"); \
- \
- if (flag_pic) \
- { \
- rtx xops[2]; \
- xops[0] = pic_offset_table_rtx; \
- xops[1] = (rtx) gen_label_rtx (); \
- \
- if (i386_regparm > 2) \
- abort (); \
- output_asm_insn ("push%L0 %0", xops); \
- output_asm_insn (AS1 (call,%P1), xops); \
- ASM_OUTPUT_INTERNAL_LABEL (FILE, "L", CODE_LABEL_NUMBER (xops[1])); \
- output_asm_insn (AS1 (pop%L0,%0), xops); \
- output_asm_insn ("addl $%__GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops); \
- fprintf (FILE, "\tmovl "); \
- assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \
- fprintf (FILE, "@GOT(%%ebx),%%ecx\n\tpopl %%ebx\n\tjmp *%%ecx\n"); \
- } \
- else \
- { \
- fprintf (FILE, "\tjmp "); \
- assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \
- fprintf (FILE, "\n"); \
- } \
+#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
+do { \
+ tree parm; \
+ rtx xops[2]; \
+ \
+ if (ix86_regparm > 0) \
+ parm = TYPE_ARG_TYPES (TREE_TYPE (function)); \
+ else \
+ parm = NULL_TREE; \
+ for (; parm; parm = TREE_CHAIN (parm)) \
+ if (TREE_VALUE (parm) == void_type_node) \
+ break; \
+ \
+ xops[0] = GEN_INT (DELTA); \
+ if (parm) \
+ xops[1] = gen_rtx_REG (SImode, 0); \
+ else if (aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION)))) \
+ xops[1] = gen_rtx_MEM (SImode, plus_constant (stack_pointer_rtx, 8)); \
+ else \
+ xops[1] = gen_rtx_MEM (SImode, plus_constant (stack_pointer_rtx, 4)); \
+ output_asm_insn ("add{l} {%0, %1|%1, %0}", xops); \
+ \
+ if (flag_pic) \
+ { \
+ xops[0] = pic_offset_table_rtx; \
+ xops[1] = gen_label_rtx (); \
+ \
+ if (ix86_regparm > 2) \
+ abort (); \
+ output_asm_insn ("push{l}\t%0", xops); \
+ output_asm_insn ("call\t%P1", xops); \
+ ASM_OUTPUT_INTERNAL_LABEL (FILE, "L", CODE_LABEL_NUMBER (xops[1])); \
+ output_asm_insn ("pop{l}\t%0", xops); \
+ output_asm_insn ("add{l}\t$_GLOBAL_OFFSET_TABLE_+[.-%P1], %0", xops); \
+ fprintf (FILE, "\tmovl "); \
+ assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \
+ fprintf (FILE, "@GOT(%%ebx),%%ecx\n\tpopl %%ebx\n\tjmp *%%ecx\n"); \
+ } \
+ else \
+ { \
+ fprintf (FILE, "\tjmp "); \
+ assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \
+ fprintf (FILE, "\n"); \
+ } \
} while (0)
diff --git a/gcc/config/i386/win32.h b/gcc/config/i386/win32.h
index 36f3ec7..b97a5c8 100644
--- a/gcc/config/i386/win32.h
+++ b/gcc/config/i386/win32.h
@@ -274,8 +274,5 @@ do { \
rtx xops[1]; \
xops[0] = gen_rtx_MEM (FUNCTION_MODE, \
gen_rtx (SYMBOL_REF, Pmode, "_monstartup")); \
- if (do_rtl) \
- emit_call_insn (gen_rtx (CALL, VOIDmode, xops[0], const0_rtx)); \
- else \
- output_asm_insn (AS1 (call,%P1), xops); \
+ emit_call_insn (gen_rtx (CALL, VOIDmode, xops[0], const0_rtx)); \
}
diff --git a/gcc/config/i386/winnt.c b/gcc/config/i386/winnt.c
index 90cae27..bda9311 100644
--- a/gcc/config/i386/winnt.c
+++ b/gcc/config/i386/winnt.c
@@ -58,7 +58,7 @@ i386_pe_valid_decl_attribute_p (decl, attributes, attr, args)
return 1;
}
- return i386_valid_decl_attribute_p (decl, attributes, attr, args);
+ return ix86_valid_decl_attribute_p (decl, attributes, attr, args);
}
/* Return nonzero if ATTR is a valid attribute for TYPE.
@@ -81,7 +81,7 @@ i386_pe_valid_type_attribute_p (type, attributes, attr, args)
return 1;
}
- return i386_valid_type_attribute_p (type, attributes, attr, args);
+ return ix86_valid_type_attribute_p (type, attributes, attr, args);
}
/* Merge attributes in decls OLD and NEW.
diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c
index 4da5a7a..d9c4048 100644
--- a/gcc/reg-stack.c
+++ b/gcc/reg-stack.c
@@ -160,8 +160,8 @@ Boston, MA 02111-1307, USA. */
#include "hard-reg-set.h"
#include "flags.h"
#include "insn-flags.h"
-#include "recog.h"
#include "toplev.h"
+#include "recog.h"
#include "varray.h"
#ifdef STACK_REGS
@@ -232,26 +232,13 @@ static rtx
/* Get the basic block number of an insn. See note at block_number
definition are validity of this information. */
-static int BLOCK_NUM PROTO((rtx));
-
-#ifdef __GNUC__
-__inline__
-#endif
-static int
-BLOCK_NUM(insn)
- rtx insn;
-{
- int tmp = INSN_UID (insn);
- if (tmp > max_uid)
- abort ();
- tmp = block_number[tmp];
- if (tmp < 0)
- abort ();
- return tmp;
-}
+#define BLOCK_NUM(INSN) \
+ ((INSN_UID (INSN) > max_uid) \
+ ? (abort() , -1) : block_number[INSN_UID (INSN)])
/* Forward declarations */
+static int stack_regs_mentioned_p PROTO((rtx pat));
static void mark_regs_pat PROTO((rtx, HARD_REG_SET *));
static void straighten_stack PROTO((rtx, stack));
static void pop_stack PROTO((stack, int));
@@ -273,7 +260,8 @@ static void delete_insn_for_stacker PROTO((rtx));
static rtx emit_pop_insn PROTO((rtx, stack, rtx, rtx (*) ()));
static void emit_swap_insn PROTO((rtx, stack, rtx));
static void move_for_stack_reg PROTO((rtx, stack, rtx));
-static void swap_rtx_condition PROTO((rtx));
+static int swap_rtx_condition_1 PROTO((rtx));
+static int swap_rtx_condition PROTO((rtx));
static void compare_for_stack_reg PROTO((rtx, stack, rtx));
static void subst_stack_regs_pat PROTO((rtx, stack, rtx));
static void subst_asm_stack_regs PROTO((rtx, stack));
@@ -284,47 +272,96 @@ static void goto_block_pat PROTO((rtx, stack, rtx));
static void convert_regs PROTO((void));
static void print_blocks PROTO((FILE *, rtx, rtx));
static void dump_stack_info PROTO((FILE *));
-static int check_stack_regs_mentioned PROTO((rtx insn));
-/* Initialize stack_regs_mentioned_data for INSN (growing the virtual array
- if needed. Return nonzero if INSN mentions stacked registers. */
+/* Return non-zero if any stack register is mentioned somewhere within PAT. */
static int
-check_stack_regs_mentioned (insn)
- rtx insn;
+stack_regs_mentioned_p (pat)
+ rtx pat;
{
- unsigned int uid = INSN_UID (insn);
- if (uid >= VARRAY_SIZE (stack_regs_mentioned_data))
- /* Allocate some extra size to avoid too many reallocs, but
- do not grow exponentially. */
- VARRAY_GROW (stack_regs_mentioned_data, uid + uid / 20);
- if (stack_regs_mentioned_p (PATTERN (insn)))
+ register const char *fmt;
+ register int i;
+
+ if (STACK_REG_P (pat))
+ return 1;
+
+ fmt = GET_RTX_FORMAT (GET_CODE (pat));
+ for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
{
- VARRAY_CHAR (stack_regs_mentioned_data, uid) = 1;
- return 1;
+ if (fmt[i] == 'E')
+ {
+ register int j;
+
+ for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
+ if (stack_regs_mentioned_p (XVECEXP (pat, i, j)))
+ return 1;
+ }
+ else if (fmt[i] == 'e' && stack_regs_mentioned_p (XEXP (pat, i)))
+ return 1;
}
- else
- VARRAY_CHAR (stack_regs_mentioned_data, uid) = 2;
+
return 0;
}
-/* Return nonzero if INSN mentions stacked registers, else return
- zero. */
+/* Return nonzero if INSN mentions stacked registers, else return zero. */
int
stack_regs_mentioned (insn)
rtx insn;
{
- unsigned int uid;
+ unsigned int uid, max;
+ int test;
+
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
return 0;
+
uid = INSN_UID (insn);
- if (uid >= VARRAY_SIZE (stack_regs_mentioned_data)
- || ! VARRAY_CHAR (stack_regs_mentioned_data, uid))
- return (check_stack_regs_mentioned (insn));
- return VARRAY_CHAR (stack_regs_mentioned_data, uid) == 1;
+ max = VARRAY_SIZE (stack_regs_mentioned_data);
+ if (uid >= max)
+ {
+ /* Allocate some extra size to avoid too many reallocs, but
+ do not grow too quickly. */
+ max = uid + uid / 20;
+ VARRAY_GROW (stack_regs_mentioned_data, max);
+ }
+
+ test = VARRAY_CHAR (stack_regs_mentioned_data, uid);
+ if (test == 0)
+ {
+ /* This insn has yet to be examined. Do so now. */
+ test = stack_regs_mentioned_p (PATTERN (insn)) ? 1 : 2;
+ VARRAY_CHAR (stack_regs_mentioned_data, uid) = test;
+ }
+
+ return test == 1;
}
+
+static rtx ix86_flags_rtx;
+static rtx
+next_flags_user (insn)
+ rtx insn;
+{
+ /* Search forward looking for the first use of this value.
+ Stop at block boundaries. */
+ /* ??? This really cries for BLOCK_END! */
+
+ while (1)
+ {
+ insn = NEXT_INSN (insn);
+ if (!insn)
+ return NULL_RTX;
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && reg_mentioned_p (ix86_flags_rtx, PATTERN (insn)))
+ return insn;
+
+ if (GET_CODE (insn) == JUMP_INSN
+ || GET_CODE (insn) == CODE_LABEL
+ || GET_CODE (insn) == CALL_INSN)
+ return NULL_RTX;
+ }
+}
/* Mark all registers needed for this pattern. */
@@ -338,17 +375,17 @@ mark_regs_pat (pat, set)
register int count;
if (GET_CODE (pat) == SUBREG)
- {
- mode = GET_MODE (pat);
- regno = SUBREG_WORD (pat);
- regno += REGNO (SUBREG_REG (pat));
- }
+ {
+ mode = GET_MODE (pat);
+ regno = SUBREG_WORD (pat);
+ regno += REGNO (SUBREG_REG (pat));
+ }
else
- regno = REGNO (pat), mode = GET_MODE (pat);
+ regno = REGNO (pat), mode = GET_MODE (pat);
for (count = HARD_REGNO_NREGS (regno, mode);
count; count--, regno++)
- SET_HARD_REG_BIT (*set, regno);
+ SET_HARD_REG_BIT (*set, regno);
}
/* Reorganise the stack into ascending numbers,
@@ -372,7 +409,7 @@ straighten_stack (insn, regstack)
temp_stack.reg_set = regstack->reg_set;
for (top = temp_stack.top = regstack->top; top >= 0; top--)
- temp_stack.reg[top] = FIRST_STACK_REG + temp_stack.top - top;
+ temp_stack.reg[top] = FIRST_STACK_REG + temp_stack.top - top;
change_stack (insn, regstack, &temp_stack, emit_insn_after);
}
@@ -403,36 +440,6 @@ pop_stack (regstack, regno)
}
}
-/* Return non-zero if any stack register is mentioned somewhere within PAT. */
-
-int
-stack_regs_mentioned_p (pat)
- rtx pat;
-{
- register const char *fmt;
- register int i;
-
- if (STACK_REG_P (pat))
- return 1;
-
- fmt = GET_RTX_FORMAT (GET_CODE (pat));
- for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'E')
- {
- register int j;
-
- for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
- if (stack_regs_mentioned_p (XVECEXP (pat, i, j)))
- return 1;
- }
- else if (fmt[i] == 'e' && stack_regs_mentioned_p (XEXP (pat, i)))
- return 1;
- }
-
- return 0;
-}
-
/* Convert register usage from "flat" register file usage to a "stack
register file. FIRST is the first insn in the function, FILE is the
dump file, if used.
@@ -454,15 +461,17 @@ reg_to_stack (first, file)
enum machine_mode mode;
HARD_REG_SET stackentry;
+ ix86_flags_rtx = gen_rtx_REG (CCmode, FLAGS_REG);
+
max_uid = get_max_uid ();
VARRAY_CHAR_INIT (stack_regs_mentioned_data, max_uid + 1,
"stack_regs_mentioned cache");
CLEAR_HARD_REG_SET (stackentry);
- {
- static int initialised;
- if (!initialised)
+ {
+ static int initialised;
+ if (!initialised)
{
#if 0
initialised = 1; /* This array can not have been previously
@@ -471,16 +480,16 @@ reg_to_stack (first, file)
functions. */
#endif
for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
- {
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
- mode = GET_MODE_WIDER_MODE (mode))
+ {
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
FP_MODE_REG (i, mode) = gen_rtx_REG (mode, i);
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_FLOAT); mode != VOIDmode;
- mode = GET_MODE_WIDER_MODE (mode))
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_FLOAT); mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
FP_MODE_REG (i, mode) = gen_rtx_REG (mode, i);
- }
+ }
}
- }
+ }
/* Count the basic blocks. Also find maximum insn uid. */
{
@@ -509,7 +518,7 @@ reg_to_stack (first, file)
blocks++;
if (code == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
- before_function_beg = 0;
+ before_function_beg = 0;
/* Remember whether or not this insn mentions an FP regs.
Check JUMP_INSNs too, in case someone creates a funny PARALLEL. */
@@ -518,7 +527,7 @@ reg_to_stack (first, file)
&& stack_regs_mentioned_p (PATTERN (insn)))
{
stack_reg_seen = 1;
- VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 1;
+ VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 1;
/* Note any register passing parameters. */
@@ -565,7 +574,6 @@ reg_to_stack (first, file)
bzero ((char *) block_out_reg_set, blocks * sizeof (HARD_REG_SET));
block_number = (int *) alloca ((max_uid + 1) * sizeof (int));
- memset (block_number, -1, (max_uid + 1) * sizeof (int));
find_blocks (first);
stack_reg_life_analysis (first, &stackentry);
@@ -648,32 +656,30 @@ get_true_reg (pat)
rtx *pat;
{
for (;;)
- switch (GET_CODE (*pat))
+ switch (GET_CODE (*pat))
{
- case SUBREG:
- /* eliminate FP subregister accesses in favour of the
- actual FP register in use. */
- {
- rtx subreg;
- if (FP_REG_P (subreg = SUBREG_REG (*pat)))
+ case SUBREG:
+ /* Eliminate FP subregister accesses in favour of the
+ actual FP register in use. */
+ {
+ rtx subreg;
+ if (FP_REG_P (subreg = SUBREG_REG (*pat)))
{
*pat = FP_MODE_REG (REGNO (subreg) + SUBREG_WORD (*pat),
GET_MODE (subreg));
- default:
+ default:
return pat;
}
- }
- case FLOAT:
- case FIX:
- case FLOAT_EXTEND:
- pat = & XEXP (*pat, 0);
+ }
+ case FLOAT:
+ case FIX:
+ case FLOAT_EXTEND:
+ pat = & XEXP (*pat, 0);
}
}
/* Record the life info of each stack reg in INSN, updating REGSTACK.
N_INPUTS is the number of inputs; N_OUTPUTS the outputs.
- OPERANDS is an array of all operands for the insn, and is assumed to
- contain all output operands, then all inputs operands.
There are many rules that an asm statement for stack-like regs must
follow. Those rules are explained at the top of this file: the rule
@@ -712,7 +718,7 @@ record_asm_reg_life (insn, regstack)
malformed_asm = 1;
/* Avoid further trouble with this insn. */
PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
- VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 2;
+ PUT_MODE (insn, VOIDmode);
return;
}
@@ -917,10 +923,10 @@ record_reg_life_pat (pat, src, dest, douse)
|| (GET_CODE (pat) == SUBREG && STACK_REG_P (SUBREG_REG (pat))))
{
if (src)
- mark_regs_pat (pat, src);
+ mark_regs_pat (pat, src);
if (dest)
- mark_regs_pat (pat, dest);
+ mark_regs_pat (pat, dest);
return;
}
@@ -1022,74 +1028,74 @@ record_reg_life (insn, block, regstack)
return;
}
- {
- HARD_REG_SET src, dest;
- int regno;
-
- CLEAR_HARD_REG_SET (src);
- CLEAR_HARD_REG_SET (dest);
-
- if (GET_CODE (insn) == CALL_INSN)
- for (note = CALL_INSN_FUNCTION_USAGE (insn);
- note;
- note = XEXP (note, 1))
- if (GET_CODE (XEXP (note, 0)) == USE)
- record_reg_life_pat (SET_DEST (XEXP (note, 0)), &src, NULL_PTR, 0);
-
- record_reg_life_pat (PATTERN (insn), &src, &dest, 0);
- for (regno = FIRST_STACK_REG; regno <= LAST_STACK_REG; regno++)
- if (! TEST_HARD_REG_BIT (regstack->reg_set, regno))
- {
- if (TEST_HARD_REG_BIT (src, regno)
- && ! TEST_HARD_REG_BIT (dest, regno))
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD,
- FP_MODE_REG (regno, DFmode),
- REG_NOTES (insn));
- else if (TEST_HARD_REG_BIT (dest, regno))
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_UNUSED,
- FP_MODE_REG (regno, DFmode),
- REG_NOTES (insn));
- }
+ {
+ HARD_REG_SET src, dest;
+ int regno;
+
+ CLEAR_HARD_REG_SET (src);
+ CLEAR_HARD_REG_SET (dest);
+
+ if (GET_CODE (insn) == CALL_INSN)
+ for (note = CALL_INSN_FUNCTION_USAGE (insn);
+ note;
+ note = XEXP (note, 1))
+ if (GET_CODE (XEXP (note, 0)) == USE)
+ record_reg_life_pat (SET_DEST (XEXP (note, 0)), &src, NULL_PTR, 0);
+
+ record_reg_life_pat (PATTERN (insn), &src, &dest, 0);
+ for (regno = FIRST_STACK_REG; regno <= LAST_STACK_REG; regno++)
+ if (! TEST_HARD_REG_BIT (regstack->reg_set, regno))
+ {
+ if (TEST_HARD_REG_BIT (src, regno)
+ && ! TEST_HARD_REG_BIT (dest, regno))
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD,
+ FP_MODE_REG (regno, DFmode),
+ REG_NOTES (insn));
+ else if (TEST_HARD_REG_BIT (dest, regno))
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_UNUSED,
+ FP_MODE_REG (regno, DFmode),
+ REG_NOTES (insn));
+ }
- if (GET_CODE (insn) == CALL_INSN)
- {
- int reg;
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ int reg;
- /* There might be a reg that is live after a function call.
- Initialize it to zero so that the program does not crash. See
- comment towards the end of stack_reg_life_analysis(). */
+ /* There might be a reg that is live after a function call.
+ Initialize it to zero so that the program does not crash. See
+ comment towards the end of stack_reg_life_analysis(). */
- for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; reg++)
- if (! TEST_HARD_REG_BIT (dest, reg)
- && TEST_HARD_REG_BIT (regstack->reg_set, reg))
- {
- rtx init, pat;
+ for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; reg++)
+ if (! TEST_HARD_REG_BIT (dest, reg)
+ && TEST_HARD_REG_BIT (regstack->reg_set, reg))
+ {
+ rtx init, pat;
- /* The insn will use virtual register numbers, and so
- convert_regs is expected to process these. But BLOCK_NUM
- cannot be used on these insns, because they do not appear in
- block_number[]. */
+ /* The insn will use virtual register numbers, and so
+ convert_regs is expected to process these. But BLOCK_NUM
+ cannot be used on these insns, because they do not appear in
+ block_number[]. */
- pat = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, DFmode),
- CONST0_RTX (DFmode));
- init = emit_insn_after (pat, insn);
+ pat = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, DFmode),
+ CONST0_RTX (DFmode));
+ init = emit_insn_after (pat, insn);
- CLEAR_HARD_REG_BIT (regstack->reg_set, reg);
+ CLEAR_HARD_REG_BIT (regstack->reg_set, reg);
- /* If the CALL_INSN was the end of a block, move the
- block_end to point to the new insn. */
+ /* If the CALL_INSN was the end of a block, move the
+ block_end to point to the new insn. */
- if (block_end[block] == insn)
- block_end[block] = init;
- }
+ if (block_end[block] == insn)
+ block_end[block] = init;
+ }
- /* Some regs do not survive a CALL */
- AND_COMPL_HARD_REG_SET (regstack->reg_set, call_used_reg_set);
- }
+ /* Some regs do not survive a CALL */
+ AND_COMPL_HARD_REG_SET (regstack->reg_set, call_used_reg_set);
+ }
- AND_COMPL_HARD_REG_SET (regstack->reg_set, dest);
- IOR_HARD_REG_SET (regstack->reg_set, src);
- }
+ AND_COMPL_HARD_REG_SET (regstack->reg_set, dest);
+ IOR_HARD_REG_SET (regstack->reg_set, src);
+ }
}
/* Find all basic blocks of the function, which starts with FIRST.
@@ -1240,26 +1246,26 @@ stack_reg_life_analysis (first, stackentry)
int reg, block;
struct stack_def regstack;
- {
- rtx retvalue;
+ {
+ rtx retvalue;
- if ((retvalue = stack_result (current_function_decl)))
+ if ((retvalue = stack_result (current_function_decl)))
{
/* Find all RETURN insns and mark them. */
for (block = blocks - 1; --block >= 0;)
- if (GET_CODE (block_end[block]) == JUMP_INSN
- && returnjump_p (block_end[block]))
- mark_regs_pat (retvalue, block_out_reg_set+block);
+ if (GET_CODE (block_end[block]) == JUMP_INSN
+ && returnjump_p (block_end[block]))
+ mark_regs_pat (retvalue, block_out_reg_set+block);
/* Mark off the end of last block if we "fall off" the end of the
function into the epilogue. */
if (GET_CODE (block_end[blocks-1]) != JUMP_INSN
- || returnjump_p (block_end[blocks-1]))
+ || GET_CODE (PATTERN (block_end[blocks-1])) == RETURN)
mark_regs_pat (retvalue, block_out_reg_set+blocks-1);
}
- }
+ }
/* now scan all blocks backward for stack register use */
@@ -1343,10 +1349,10 @@ stack_reg_life_analysis (first, stackentry)
block -= 1;
}
- /* If any reg is live at the start of the first block of a
- function, then we must guarantee that the reg holds some value by
- generating our own "load" of that register. Otherwise a 387 would
- fault trying to access an empty register. */
+ /* If any reg is live at the start of the first block of a
+ function, then we must guarantee that the reg holds some value by
+ generating our own "load" of that register. Otherwise a 387 would
+ fault trying to access an empty register. */
/* Load zero into each live register. The fact that a register
appears live at the function start necessarily implies an error
@@ -1373,10 +1379,10 @@ stack_reg_life_analysis (first, stackentry)
}
}
-/*****************************************************************************
- This section deals with stack register substitution, and forms the second
- pass over the RTL.
- *****************************************************************************/
+/*
+ * This section deals with stack register substitution, and forms the second
+ * pass over the RTL.
+ */
/* Replace REG, which is a pointer to a stack reg RTX, with an RTX for
the desired hard REGNO. */
@@ -1391,11 +1397,11 @@ replace_reg (reg, regno)
abort ();
switch (GET_MODE_CLASS (GET_MODE (*reg)))
- {
- default: abort ();
- case MODE_FLOAT:
- case MODE_COMPLEX_FLOAT:;
- }
+ {
+ default: abort ();
+ case MODE_FLOAT:
+ case MODE_COMPLEX_FLOAT:;
+ }
*reg = FP_MODE_REG (regno, GET_MODE (*reg));
}
@@ -1454,14 +1460,6 @@ static void
delete_insn_for_stacker (insn)
rtx insn;
{
- int i;
-
- /* Ensure that the side effects were clobbers when deleting a PARALLEL. */
- if (GET_CODE (PATTERN (insn)) == PARALLEL)
- for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++)
- if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) != CLOBBER)
- abort ();
-
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
@@ -1469,12 +1467,9 @@ delete_insn_for_stacker (insn)
/* Emit an insn to pop virtual register REG before or after INSN.
REGSTACK is the stack state after INSN and is updated to reflect this
- pop. WHEN is either emit_insn_before, emit_insn_after or NULL.
- in case WHEN is NULL we don't really emit the insn, just modify stack
- information. Caller is expected to emit insn himself.
-
- A pop insn is represented as a SET whose destination is the register to
- be popped and source is the top of stack. A death note for the top of stack
+ pop. WHEN is either emit_insn_before or emit_insn_after. A pop insn
+ is represented as a SET whose destination is the register to be popped
+ and source is the top of stack. A death note for the top of stack
cases the movdf pattern to pop. */
static rtx
@@ -1492,18 +1487,14 @@ emit_pop_insn (insn, regstack, reg, when)
if (hard_regno < FIRST_STACK_REG)
abort ();
- if (when)
- {
- pop_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG (hard_regno, DFmode),
- FP_MODE_REG (FIRST_STACK_REG, DFmode));
+ pop_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG (hard_regno, DFmode),
+ FP_MODE_REG (FIRST_STACK_REG, DFmode));
- pop_insn = (*when) (pop_rtx, insn);
+ pop_insn = (*when) (pop_rtx, insn);
- REG_NOTES (pop_insn) = gen_rtx_EXPR_LIST (REG_DEAD,
- FP_MODE_REG (FIRST_STACK_REG,
- DFmode),
- REG_NOTES (pop_insn));
- }
+ REG_NOTES (pop_insn) = gen_rtx_EXPR_LIST (REG_DEAD,
+ FP_MODE_REG (FIRST_STACK_REG, DFmode),
+ REG_NOTES (pop_insn));
regstack->reg[regstack->top - (hard_regno - FIRST_STACK_REG)]
= regstack->reg[regstack->top];
@@ -1528,7 +1519,6 @@ emit_swap_insn (insn, regstack, reg)
rtx reg;
{
int hard_regno;
- rtx gen_swapdf();
rtx swap_rtx, swap_insn;
int tmp, other_reg; /* swap regno temps */
rtx i1; /* the stack-reg insn prior to INSN */
@@ -1578,15 +1568,8 @@ emit_swap_insn (insn, regstack, reg)
return;
}
- if (GET_RTX_CLASS (GET_CODE (i1)) == 'i' && sets_cc0_p (PATTERN (i1)))
- {
- i1 = next_nonnote_insn (i1);
- if (i1 == insn)
- abort ();
- }
-
- swap_rtx = gen_swapdf (FP_MODE_REG (hard_regno, DFmode),
- FP_MODE_REG (FIRST_STACK_REG, DFmode));
+ swap_rtx = gen_swapxf (FP_MODE_REG (hard_regno, XFmode),
+ FP_MODE_REG (FIRST_STACK_REG, XFmode));
swap_insn = emit_insn_after (swap_rtx, i1);
}
@@ -1732,109 +1715,144 @@ move_for_stack_reg (insn, regstack, pat)
abort ();
}
-static void
-swap_rtx_condition (pat)
+/* Swap the condition on a branch, if there is one. Return true if we
+ found a condition to swap. False if the condition was not used as
+ such. */
+
+static int
+swap_rtx_condition_1 (pat)
rtx pat;
{
register const char *fmt;
- register int i;
+ register int i, r = 0;
if (GET_RTX_CLASS (GET_CODE (pat)) == '<')
{
PUT_CODE (pat, swap_condition (GET_CODE (pat)));
- return;
+ r = 1;
}
-
- fmt = GET_RTX_FORMAT (GET_CODE (pat));
- for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
+ else
{
- if (fmt[i] == 'E')
+ fmt = GET_RTX_FORMAT (GET_CODE (pat));
+ for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
{
- register int j;
+ if (fmt[i] == 'E')
+ {
+ register int j;
- for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
- swap_rtx_condition (XVECEXP (pat, i, j));
+ for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
+ r |= swap_rtx_condition_1 (XVECEXP (pat, i, j));
+ }
+ else if (fmt[i] == 'e')
+ r |= swap_rtx_condition_1 (XEXP (pat, i));
}
- else if (fmt[i] == 'e')
- swap_rtx_condition (XEXP (pat, i));
}
+
+ return r;
+}
+
+static int
+swap_rtx_condition (insn)
+ rtx insn;
+{
+ rtx pat = PATTERN (insn);
+
+ /* We're looking for a single set to cc0 or an HImode temporary. */
+
+ if (GET_CODE (pat) == SET
+ && GET_CODE (SET_DEST (pat)) == REG
+ && REGNO (SET_DEST (pat)) == FLAGS_REG)
+ {
+ insn = next_flags_user (insn);
+ if (insn == NULL_RTX)
+ return 0;
+ pat = PATTERN (insn);
+ }
+
+ /* See if this is, or ends in, a fnstsw, aka unspec 9. If so, we're
+ not doing anything with the cc value right now. We may be able to
+ search for one though. */
+
+ if (GET_CODE (pat) == SET
+ && GET_CODE (SET_SRC (pat)) == UNSPEC
+ && XINT (SET_SRC (pat), 1) == 9)
+ {
+ rtx dest = SET_DEST (pat);
+
+ /* Search forward looking for the first use of this value.
+ Stop at block boundaries. */
+ /* ??? This really cries for BLOCK_END! */
+ while (1)
+ {
+ insn = NEXT_INSN (insn);
+ if (insn == NULL_RTX)
+ return 0;
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && reg_mentioned_p (dest, insn))
+ break;
+ if (GET_CODE (insn) == JUMP_INSN)
+ return 0;
+ if (GET_CODE (insn) == CODE_LABEL)
+ return 0;
+ }
+
+ /* So we've found the insn using this value. If it is anything
+ other than sahf, aka unspec 10, or the value does not die
+ (meaning we'd have to search further), then we must give up. */
+ pat = PATTERN (insn);
+ if (GET_CODE (pat) != SET
+ || GET_CODE (SET_SRC (pat)) != UNSPEC
+ || XINT (SET_SRC (pat), 1) != 10
+ || ! dead_or_set_p (insn, dest))
+ return 0;
+
+ /* Now we are prepared to handle this as a normal cc0 setter. */
+ insn = next_flags_user (insn);
+ if (insn == NULL_RTX)
+ return 0;
+ pat = PATTERN (insn);
+ }
+
+ return swap_rtx_condition_1 (pat);
}
/* Handle a comparison. Special care needs to be taken to avoid
causing comparisons that a 387 cannot do correctly, such as EQ.
- Also, a fstp instruction may need to be emitted. The 387 does have an
+ Also, a pop insn may need to be emitted. The 387 does have an
`fcompp' insn that can pop two regs, but it is sometimes too expensive
to do this - a `fcomp' followed by a `fstpl %st(0)' may be easier to
- set up.
-
- We can not handle this by emiting fpop instruction after compare, because
- it appears between cc0 setter and user. So we emit only
- REG_DEAD note and handle it as a special case in machine description.
-
- This code used trick with delay_slot filling to emit pop insn after
- comparsion but it didn't worked because it caused confusion with cc_status
- in final pass. */
+ set up. */
static void
-compare_for_stack_reg (insn, regstack, pat)
+compare_for_stack_reg (insn, regstack, pat_src)
rtx insn;
stack regstack;
- rtx pat;
+ rtx pat_src;
{
rtx *src1, *src2;
rtx src1_note, src2_note;
- rtx cc0_user;
- int have_cmove;
- int hard_regno;
+ rtx flags_user;
- src1 = get_true_reg (&XEXP (SET_SRC (pat), 0));
- src2 = get_true_reg (&XEXP (SET_SRC (pat), 1));
- cc0_user = next_cc0_user (insn);
-
- /* If the insn that uses cc0 is an FP-conditional move, then the destination
- must be the top of stack */
- if (GET_CODE (PATTERN (cc0_user)) == SET
- && SET_DEST (PATTERN (cc0_user)) != pc_rtx
- && GET_CODE (SET_SRC (PATTERN (cc0_user))) == IF_THEN_ELSE
- && (GET_MODE_CLASS (GET_MODE (SET_DEST (PATTERN (cc0_user))))
- == MODE_FLOAT))
- {
- rtx *dest;
-
- dest = get_true_reg (&SET_DEST (PATTERN (cc0_user)));
-
- have_cmove = 1;
- if (get_hard_regnum (regstack, *dest) >= FIRST_STACK_REG
- && REGNO (*dest) != regstack->reg[regstack->top])
- {
- emit_swap_insn (insn, regstack, *dest);
- }
- }
- else
- have_cmove = 0;
+ src1 = get_true_reg (&XEXP (pat_src, 0));
+ src2 = get_true_reg (&XEXP (pat_src, 1));
+ flags_user = next_flags_user (insn);
/* ??? If fxch turns out to be cheaper than fstp, give priority to
registers that die in this insn - move those to stack top first. */
- if (! STACK_REG_P (*src1)
- || (STACK_REG_P (*src2)
- && get_hard_regnum (regstack, *src2) == FIRST_STACK_REG))
+ if ((! STACK_REG_P (*src1)
+ || (STACK_REG_P (*src2)
+ && get_hard_regnum (regstack, *src2) == FIRST_STACK_REG))
+ && swap_rtx_condition (insn))
{
- rtx temp, next;
-
- temp = XEXP (SET_SRC (pat), 0);
- XEXP (SET_SRC (pat), 0) = XEXP (SET_SRC (pat), 1);
- XEXP (SET_SRC (pat), 1) = temp;
+ rtx temp;
+ temp = XEXP (pat_src, 0);
+ XEXP (pat_src, 0) = XEXP (pat_src, 1);
+ XEXP (pat_src, 1) = temp;
- src1 = get_true_reg (&XEXP (SET_SRC (pat), 0));
- src2 = get_true_reg (&XEXP (SET_SRC (pat), 1));
-
- next = next_cc0_user (insn);
- if (next == NULL_RTX)
- abort ();
+ src1 = get_true_reg (&XEXP (pat_src, 0));
+ src2 = get_true_reg (&XEXP (pat_src, 1));
- swap_rtx_condition (PATTERN (next));
- INSN_CODE (next) = -1;
INSN_CODE (insn) = -1;
}
@@ -1847,16 +1865,12 @@ compare_for_stack_reg (insn, regstack, pat)
else
src2_note = NULL_RTX;
- if (! have_cmove)
- emit_swap_insn (insn, regstack, *src1);
+ emit_swap_insn (insn, regstack, *src1);
replace_reg (src1, FIRST_STACK_REG);
if (STACK_REG_P (*src2))
- {
- hard_regno = get_hard_regnum (regstack, *src2);
- replace_reg (src2, hard_regno);
- }
+ replace_reg (src2, get_hard_regnum (regstack, *src2));
if (src1_note)
{
@@ -1885,11 +1899,16 @@ compare_for_stack_reg (insn, regstack, pat)
}
else
{
- /* Pop of second operand is handled using special REG_DEAD note
- because we can't emit pop insn after cc0 setter. */
+ /* The 386 can only represent death of the first operand in
+ the case handled above. In all other cases, emit a separate
+ pop and remove the death note from here. */
+
+ /* link_cc0_insns (insn); */
- emit_pop_insn (insn, regstack, XEXP (src2_note, 0), NULL);
- replace_reg (&XEXP (src2_note, 0), hard_regno);
+ remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src2_note, 0)));
+
+ emit_pop_insn (insn, regstack, XEXP (src2_note, 0),
+ emit_insn_after);
}
}
}
@@ -1906,12 +1925,14 @@ subst_stack_regs_pat (insn, regstack, pat)
rtx *dest, *src;
rtx *src1 = (rtx *) NULL_PTR, *src2;
rtx src1_note, src2_note;
+ rtx pat_src;
if (GET_CODE (pat) != SET)
return;
dest = get_true_reg (&SET_DEST (pat));
src = get_true_reg (&SET_SRC (pat));
+ pat_src = SET_SRC (pat);
/* See if this is a `movM' pattern, and handle elsewhere if so. */
@@ -1922,22 +1943,22 @@ subst_stack_regs_pat (insn, regstack, pat)
|| GET_CODE (*src) == CONST_DOUBLE))))
move_for_stack_reg (insn, regstack, pat);
else
- switch (GET_CODE (SET_SRC (pat)))
+ switch (GET_CODE (pat_src))
{
case COMPARE:
- compare_for_stack_reg (insn, regstack, pat);
+ compare_for_stack_reg (insn, regstack, pat_src);
break;
case CALL:
- {
- int count;
- for (count = HARD_REGNO_NREGS (REGNO (*dest), GET_MODE (*dest));
- --count >= 0;)
+ {
+ int count;
+ for (count = HARD_REGNO_NREGS (REGNO (*dest), GET_MODE (*dest));
+ --count >= 0;)
{
regstack->reg[++regstack->top] = REGNO (*dest) + count;
SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest) + count);
}
- }
+ }
replace_reg (dest, FIRST_STACK_REG);
break;
@@ -1960,7 +1981,7 @@ subst_stack_regs_pat (insn, regstack, pat)
source. */
if (src1 == 0)
- src1 = get_true_reg (&XEXP (SET_SRC (pat), 0));
+ src1 = get_true_reg (&XEXP (pat_src, 0));
emit_swap_insn (insn, regstack, *src1);
@@ -1992,8 +2013,8 @@ subst_stack_regs_pat (insn, regstack, pat)
source and some other stack register (possibly top of stack)
as a destination. */
- src1 = get_true_reg (&XEXP (SET_SRC (pat), 0));
- src2 = get_true_reg (&XEXP (SET_SRC (pat), 1));
+ src1 = get_true_reg (&XEXP (pat_src, 0));
+ src2 = get_true_reg (&XEXP (pat_src, 1));
/* We will fix any death note later. */
@@ -2095,13 +2116,13 @@ subst_stack_regs_pat (insn, regstack, pat)
break;
case UNSPEC:
- switch (XINT (SET_SRC (pat), 1))
+ switch (XINT (pat_src, 1))
{
case 1: /* sin */
case 2: /* cos */
/* These insns only operate on the top of the stack. */
- src1 = get_true_reg (&XVECEXP (SET_SRC (pat), 0, 0));
+ src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
emit_swap_insn (insn, regstack, *src1);
@@ -2121,16 +2142,35 @@ subst_stack_regs_pat (insn, regstack, pat)
break;
+ case 10:
+ /* (unspec [(unspec [(compare ..)] 9)] 10)
+ Unspec 9 is fnstsw; unspec 10 is sahf. The combination
+ matches the PPRO fcomi instruction. */
+
+ pat_src = XVECEXP (pat_src, 0, 0);
+ if (GET_CODE (pat_src) != UNSPEC
+ || XINT (pat_src, 1) != 9)
+ abort ();
+ /* FALLTHRU */
+
+ case 9:
+ /* (unspec [(compare ..)] 9)
+ Combined fcomp+fnstsw generated for doing well with CSE.
+ When optimizing this would have been broken up before now. */
+
+ pat_src = XVECEXP (pat_src, 0, 0);
+ if (GET_CODE (pat_src) != COMPARE)
+ abort ();
+
+ compare_for_stack_reg (insn, regstack, pat_src);
+ break;
+
default:
abort ();
}
break;
case IF_THEN_ELSE:
- /* dest has to be on stack. */
- if (get_hard_regnum (regstack, *dest) < FIRST_STACK_REG)
- abort ();
-
/* This insn requires the top of stack to be the destination. */
/* If the comparison operator is an FP comparison operator,
@@ -2142,8 +2182,8 @@ subst_stack_regs_pat (insn, regstack, pat)
&& REGNO (*dest) != regstack->reg[regstack->top])
emit_swap_insn (insn, regstack, *dest);
- src1 = get_true_reg (&XEXP (SET_SRC (pat), 1));
- src2 = get_true_reg (&XEXP (SET_SRC (pat), 2));
+ src1 = get_true_reg (&XEXP (pat_src, 1));
+ src2 = get_true_reg (&XEXP (pat_src, 2));
src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2));
@@ -2184,7 +2224,9 @@ subst_stack_regs_pat (insn, regstack, pat)
}
}
- /* Make dest the top of stack. */
+ /* Make dest the top of stack. Add dest to regstack if not present. */
+ if (get_hard_regnum (regstack, *dest) < FIRST_STACK_REG)
+ regstack->reg[++regstack->top] = REGNO (*dest);
SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
replace_reg (dest, FIRST_STACK_REG);
@@ -2500,26 +2542,26 @@ subst_stack_regs (insn, regstack)
register int i;
if (GET_CODE (insn) == CALL_INSN)
- {
- int top = regstack->top;
+ {
+ int top = regstack->top;
- /* If there are any floating point parameters to be passed in
- registers for this call, make sure they are in the right
- order. */
+ /* If there are any floating point parameters to be passed in
+ registers for this call, make sure they are in the right
+ order. */
- if (top >= 0)
- {
- straighten_stack (PREV_INSN (insn), regstack);
+ if (top >= 0)
+ {
+ straighten_stack (PREV_INSN (insn), regstack);
- /* Now mark the arguments as dead after the call. */
+ /* Now mark the arguments as dead after the call. */
- while (regstack->top >= 0)
- {
- CLEAR_HARD_REG_BIT (regstack->reg_set, FIRST_STACK_REG + regstack->top);
- regstack->top--;
- }
- }
- }
+ while (regstack->top >= 0)
+ {
+ CLEAR_HARD_REG_BIT (regstack->reg_set, FIRST_STACK_REG + regstack->top);
+ regstack->top--;
+ }
+ }
+ }
/* Do the actual substitution if any stack regs are mentioned.
Since we only record whether entire insn mentions stack regs, and
@@ -2544,14 +2586,8 @@ subst_stack_regs (insn, regstack)
for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
{
if (stack_regs_mentioned_p (XVECEXP (PATTERN (insn), 0, i)))
- {
- subst_stack_regs_pat (insn, regstack,
- XVECEXP (PATTERN (insn), 0, i));
-
- /* subst_stack_regs_pat may have deleted a no-op insn. */
- if (GET_CODE (insn) == NOTE)
- break;
- }
+ subst_stack_regs_pat (insn, regstack,
+ XVECEXP (PATTERN (insn), 0, i));
}
else
subst_stack_regs_pat (insn, regstack, PATTERN (insn));
@@ -2712,27 +2748,27 @@ goto_block_pat (insn, regstack, pat)
int reg;
switch (GET_CODE (pat))
- {
- case RETURN:
- straighten_stack (PREV_INSN (insn), regstack);
- return;
- default:
- {
- int i, j;
- const char *fmt = GET_RTX_FORMAT (GET_CODE (pat));
-
- for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- goto_block_pat (insn, regstack, XEXP (pat, i));
- if (fmt[i] == 'E')
- for (j = 0; j < XVECLEN (pat, i); j++)
- goto_block_pat (insn, regstack, XVECEXP (pat, i, j));
- }
+ {
+ case RETURN:
+ straighten_stack (PREV_INSN (insn), regstack);
return;
- }
- case LABEL_REF:;
- }
+ default:
+ {
+ int i, j;
+ const char *fmt = GET_RTX_FORMAT (GET_CODE (pat));
+
+ for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ goto_block_pat (insn, regstack, XEXP (pat, i));
+ if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (pat, i); j++)
+ goto_block_pat (insn, regstack, XVECEXP (pat, i, j));
+ }
+ return;
+ }
+ case LABEL_REF:;
+ }
label = XEXP (pat, 0);
if (GET_CODE (label) != CODE_LABEL)
@@ -2896,26 +2932,26 @@ convert_regs ()
regs live at its start, then the last basic block will have regs live
at its end that need to be popped before the function returns. */
- {
- int value_reg_low, value_reg_high;
- value_reg_low = value_reg_high = -1;
- {
- rtx retvalue;
- if ((retvalue = stack_result (current_function_decl)))
- {
- value_reg_low = REGNO (retvalue);
- value_reg_high = value_reg_low +
+ {
+ int value_reg_low, value_reg_high;
+ value_reg_low = value_reg_high = -1;
+ {
+ rtx retvalue;
+ if ((retvalue = stack_result (current_function_decl)))
+ {
+ value_reg_low = REGNO (retvalue);
+ value_reg_high = value_reg_low +
HARD_REGNO_NREGS (value_reg_low, GET_MODE (retvalue)) - 1;
- }
+ }
- }
- for (reg = regstack.top; reg >= 0; reg--)
- if (regstack.reg[reg] < value_reg_low
- || regstack.reg[reg] > value_reg_high)
- insn = emit_pop_insn (insn, &regstack,
- FP_MODE_REG (regstack.reg[reg], DFmode),
- emit_insn_after);
- }
+ }
+ for (reg = regstack.top; reg >= 0; reg--)
+ if (regstack.reg[reg] < value_reg_low
+ || regstack.reg[reg] > value_reg_high)
+ insn = emit_pop_insn (insn, &regstack,
+ FP_MODE_REG (regstack.reg[reg], DFmode),
+ emit_insn_after);
+ }
straighten_stack (insn, &regstack);
}
diff --git a/gcc/rtl.h b/gcc/rtl.h
index ec0b738..59b2706 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1568,7 +1568,6 @@ extern void output_func_start_profiler PROTO ((void));
#ifdef BUFSIZ
extern void reg_to_stack PROTO ((rtx, FILE *));
#endif
-extern int stack_regs_mentioned_p PROTO ((rtx));
/* In fold-const.c */
extern int add_double PROTO ((HOST_WIDE_INT, HOST_WIDE_INT,