i386-protos.h (ix86_setup_incoming_varargs, [...]): Declare.
authorJan Hubicka <jh@suse.cz>
Fri, 28 Sep 2001 17:20:25 +0000 (19:20 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Fri, 28 Sep 2001 17:20:25 +0000 (17:20 +0000)
* i386-protos.h (ix86_setup_incoming_varargs, ix86_va_arg,
ix86_va_start, ix86_build_va_list): Declare.
* i386.c (ix86_setup_incoming_varargs, ix86_va_arg,
ix86_va_start, ix86_build_va_list): New global functions.
* i386.md (sse_prologue_save_insn): New insn.
(sse_prologue_save): New expander.
* i386.h (EXPAND_BUILTIN_VA_ARG, EXPAND_BUILTIN_VA_START,
BUILD_VA_LIST_TYPE, SETUP_INCOMING_VARARGS): New macros.

From-SVN: r45862

gcc/ChangeLog
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/config/i386/i386.md
gcc/doc/invoke.texi

index 91e995a420f97048e69cb7be97cba8c3b43347c0..cfedd181d9412937a28eea4db928f1d130c25c74 100644 (file)
@@ -1,3 +1,14 @@
+Fri Sep 28 19:18:40 CEST 2001  Jan Hubicka  <jh@suse.cz>
+
+       * i386-protos.h (ix86_setup_incoming_varargs, ix86_va_arg,
+       ix86_va_start, ix86_build_va_list): Declare.
+       * i386.c (ix86_setup_incoming_varargs, ix86_va_arg,
+       ix86_va_start, ix86_build_va_list): New global functions.
+       * i386.md (sse_prologue_save_insn): New insn.
+       (sse_prologue_save): New expander.
+       * i386.h (EXPAND_BUILTIN_VA_ARG, EXPAND_BUILTIN_VA_START,
+       BUILD_VA_LIST_TYPE, SETUP_INCOMING_VARARGS): New macros.
+
 2001-09-28  Neil Booth  <neil@daikokuya.demon.co.uk>
 
        * cpplex.c (new_buff, _cpp_get_buff, _cpp_extend_buff):
index f69dd2a54419867d274e21789ba44d995ed3d690..410b84e8de62c2ba8e97bbc0e381e45f4215b684 100644 (file)
@@ -140,6 +140,11 @@ extern bool ix86_function_value_regno_p PARAMS ((int));
 extern bool ix86_function_arg_regno_p PARAMS ((int));
 extern int ix86_function_arg_boundary PARAMS ((enum machine_mode, tree));
 extern int ix86_return_in_memory PARAMS ((tree));
+extern void ix86_va_start PARAMS ((int, tree, rtx));
+extern rtx ix86_va_arg PARAMS ((tree, tree));
+extern void ix86_setup_incoming_varargs PARAMS ((CUMULATIVE_ARGS *,
+                                                enum machine_mode,
+                                                tree, int *, int));
 
 extern rtx ix86_force_to_memory PARAMS ((enum machine_mode, rtx));
 extern void ix86_free_from_memory PARAMS ((enum machine_mode));
@@ -175,6 +180,7 @@ extern rtx ix86_expand_builtin PARAMS ((tree, rtx, rtx, enum machine_mode, int))
 
 #ifdef TREE_CODE
 extern int ix86_return_pops_args PARAMS ((tree, tree, int));
+extern tree ix86_build_va_list PARAMS ((void));
 
 extern int ix86_data_alignment PARAMS ((tree, int));
 extern int ix86_local_alignment PARAMS ((tree, int));
index 76370067b1c1e736e9d55028a765481cabe5152f..889c428bc37cd93916c82d48738c2232c7ad4de3 100644 (file)
@@ -2061,10 +2061,455 @@ ix86_libcall_value (mode)
   else
    return gen_rtx_REG (mode, VALUE_REGNO (mode));
 }
+\f
+/* Create the va_list data type.  */
 
+tree
+ix86_build_va_list ()
+{
+  tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl;
 
-\f
+  /* For i386 we use plain pointer to argument area.  */
+  if (!TARGET_64BIT)
+    return build_pointer_type (char_type_node);
+
+  record = make_lang_type (RECORD_TYPE);
+  type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
+
+  f_gpr = build_decl (FIELD_DECL, get_identifier ("gp_offset"), 
+                     unsigned_type_node);
+  f_fpr = build_decl (FIELD_DECL, get_identifier ("fp_offset"), 
+                     unsigned_type_node);
+  f_ovf = build_decl (FIELD_DECL, get_identifier ("overflow_arg_area"),
+                     ptr_type_node);
+  f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"),
+                     ptr_type_node);
+
+  DECL_FIELD_CONTEXT (f_gpr) = record;
+  DECL_FIELD_CONTEXT (f_fpr) = record;
+  DECL_FIELD_CONTEXT (f_ovf) = record;
+  DECL_FIELD_CONTEXT (f_sav) = record;
+
+  TREE_CHAIN (record) = type_decl;
+  TYPE_NAME (record) = type_decl;
+  TYPE_FIELDS (record) = f_gpr;
+  TREE_CHAIN (f_gpr) = f_fpr;
+  TREE_CHAIN (f_fpr) = f_ovf;
+  TREE_CHAIN (f_ovf) = f_sav;
+
+  layout_type (record);
+
+  /* The correct type is an array type of one element.  */
+  return build_array_type (record, build_index_type (size_zero_node));
+}
+
+/* Perform any needed actions needed for a function that is receiving a
+   variable number of arguments. 
+
+   CUM is as above.
+
+   MODE and TYPE are the mode and type of the current parameter.
+
+   PRETEND_SIZE is a variable that should be set to the amount of stack
+   that must be pushed by the prolog to pretend that our caller pushed
+   it.
+
+   Normally, this macro will push all remaining incoming registers on the
+   stack and set PRETEND_SIZE to the length of the registers pushed.  */
+
+void
+ix86_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
+     CUMULATIVE_ARGS *cum;
+     enum machine_mode mode;
+     tree type;
+     int *pretend_size ATTRIBUTE_UNUSED;
+     int no_rtl;
+
+{
+  CUMULATIVE_ARGS next_cum;
+  rtx save_area = NULL_RTX, mem;
+  rtx label;
+  rtx label_ref;
+  rtx tmp_reg;
+  rtx nsse_reg;
+  int set;
+  tree fntype;
+  int stdarg_p;
+  int i;
+
+  if (!TARGET_64BIT)
+    return;
+
+  /* Indicate to allocate space on the stack for varargs save area.  */
+  ix86_save_varrargs_registers = 1;
+
+  fntype = TREE_TYPE (current_function_decl);
+  stdarg_p = (TYPE_ARG_TYPES (fntype) != 0
+             && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
+                 != void_type_node));
+
+  /* For varargs, we do not want to skip the dummy va_dcl argument.
+     For stdargs, we do want to skip the last named argument.  */
+  next_cum = *cum;
+  if (stdarg_p)
+    function_arg_advance (&next_cum, mode, type, 1);
+
+  if (!no_rtl)
+    save_area = frame_pointer_rtx;
+
+  set = get_varargs_alias_set ();
+
+  for (i = next_cum.regno; i < ix86_regparm; i++)
+    {
+      mem = gen_rtx_MEM (Pmode,
+                        plus_constant (save_area, i * UNITS_PER_WORD));
+      MEM_ALIAS_SET (mem) = set;
+      emit_move_insn (mem, gen_rtx_REG (Pmode,
+                                       x86_64_int_parameter_registers[i]));
+    }
+
+  if (next_cum.sse_nregs)
+    {
+      /* Now emit code to save SSE registers.  The AX parameter contains number
+        of SSE parameter regsiters used to call this function.  We use
+        sse_prologue_save insn template that produces computed jump across
+        SSE saves.  We need some preparation work to get this working.  */
+
+      label = gen_label_rtx ();
+      label_ref = gen_rtx_LABEL_REF (Pmode, label);
+
+      /* Compute address to jump to :
+         label - 5*eax + nnamed_sse_arguments*5  */
+      tmp_reg = gen_reg_rtx (Pmode);
+      nsse_reg = gen_reg_rtx (Pmode);
+      emit_insn (gen_zero_extendqidi2 (nsse_reg, gen_rtx_REG (QImode, 0)));
+      emit_insn (gen_rtx_SET (VOIDmode, tmp_reg,
+                             gen_rtx_MULT (VOIDmode, nsse_reg,
+                                           GEN_INT (4))));
+      if (next_cum.sse_regno)
+       emit_move_insn
+         (nsse_reg,
+          gen_rtx_CONST (DImode,
+                         gen_rtx_PLUS (DImode,
+                                       label_ref,
+                                       GEN_INT (next_cum.sse_regno * 4))));
+      else
+       emit_move_insn (nsse_reg, label_ref);
+      emit_insn (gen_subdi3 (nsse_reg, nsse_reg, tmp_reg));
+
+      /* Compute address of memory block we save into.  We always use pointer
+        pointing 127 bytes after first byte to store - this is needed to keep
+        instruction size limited by 4 bytes.  */
+      tmp_reg = gen_reg_rtx (Pmode);
+      emit_insn (gen_rtx_SET(VOIDmode, tmp_reg,
+                            plus_constant (save_area, 8 * REGPARM_MAX + 127)));
+      mem = gen_rtx_MEM (BLKmode, plus_constant (tmp_reg, -127));
+      MEM_ALIAS_SET (mem) = set;
+
+      /* And finally do the dirty job!  */
+      emit_insn (gen_sse_prologue_save (mem, nsse_reg, GEN_INT (next_cum.sse_regno),
+                label));
+    }
+
+}
+
+/* Implement va_start.  */
+
+void
+ix86_va_start (stdarg_p, valist, nextarg)
+     int stdarg_p;
+     tree valist;
+     rtx nextarg;
+{
+  HOST_WIDE_INT words, n_gpr, n_fpr;
+  tree f_gpr, f_fpr, f_ovf, f_sav;
+  tree gpr, fpr, ovf, sav, t;
+
+  /* Only 64bit target needs something special.  */
+  if (!TARGET_64BIT)
+    {
+      std_expand_builtin_va_start (stdarg_p, valist, nextarg);
+      return;
+    }
+
+  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
+  f_fpr = TREE_CHAIN (f_gpr);
+  f_ovf = TREE_CHAIN (f_fpr);
+  f_sav = TREE_CHAIN (f_ovf);
+
+  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
+  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
+  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+
+  /* Count number of gp and fp argument registers used.  */
+  words = current_function_args_info.words;
+  n_gpr = current_function_args_info.regno;
+  n_fpr = current_function_args_info.sse_regno;
+
+  if (TARGET_DEBUG_ARG)
+    fprintf (stderr, "va_start: words = %d, n_gpr = %d, n_fpr = %d\n",
+            words, n_gpr, n_fpr);
+
+  t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr,
+            build_int_2 (n_gpr * 8, 0));
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr,
+            build_int_2 (n_fpr * 16 + 8*REGPARM_MAX, 0));
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  /* Find the overflow area.  */
+  t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
+  if (words != 0)
+    t = build (PLUS_EXPR, TREE_TYPE (ovf), t,
+              build_int_2 (words * UNITS_PER_WORD, 0));
+  t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  /* Find the register save area.
+     Prologue of the function save it right above stack frame.  */
+  t = make_tree (TREE_TYPE (sav), frame_pointer_rtx);
+  t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+}
+
+/* Implement va_arg.  */
+rtx
+ix86_va_arg (valist, type)
+     tree valist, type;
+{
+  static int intreg[6] = { 0, 1, 2, 3, 4, 5 };
+  tree f_gpr, f_fpr, f_ovf, f_sav;
+  tree gpr, fpr, ovf, sav, t;
+  int indirect_p = 0, size, rsize;
+  rtx lab_false, lab_over = NULL_RTX;
+  rtx addr_rtx, r;
+  rtx container;
+
+  /* Only 64bit target needs something special.  */
+  if (!TARGET_64BIT)
+    {
+      return std_expand_builtin_va_arg (valist, type);
+    }
+
+  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
+  f_fpr = TREE_CHAIN (f_gpr);
+  f_ovf = TREE_CHAIN (f_fpr);
+  f_sav = TREE_CHAIN (f_ovf);
+
+  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
+  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
+  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+
+  size = int_size_in_bytes (type);
+  rsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+
+  container = construct_container (TYPE_MODE (type), type, 0,
+                                  REGPARM_MAX, SSE_REGPARM_MAX, intreg, 0);
+  /*
+   * Pull the value out of the saved registers ...
+   */
 
+  addr_rtx = gen_reg_rtx (Pmode);
+
+  if (container)
+    {
+      rtx int_addr_rtx, sse_addr_rtx;
+      int needed_intregs, needed_sseregs;
+      int need_temp;
+
+      lab_over = gen_label_rtx ();
+      lab_false = gen_label_rtx ();
+
+      examine_argument (TYPE_MODE (type), type, 0,
+                       &needed_intregs, &needed_sseregs);
+
+
+      need_temp = ((needed_intregs && TYPE_ALIGN (type) > 64)
+                  || TYPE_ALIGN (type) > 128);
+
+      /* In case we are passing structure, verify that it is consetuctive block
+         on the register save area.  If not we need to do moves.  */
+      if (!need_temp && !REG_P (container))
+       {
+         /* Verify that all registers are strictly consetuctive  */
+         if (SSE_REGNO_P (REGNO (XEXP (XVECEXP (container, 0, 0), 0))))
+           {
+             int i;
+
+             for (i = 0; i < XVECLEN (container, 0) && !need_temp; i++)
+               {
+                 rtx slot = XVECEXP (container, 0, i);
+                 if (REGNO (XEXP (slot, 0)) != FIRST_SSE_REG + (unsigned int)i
+                     || INTVAL (XEXP (slot, 1)) != i * 16)
+                   need_temp = 1;
+               }
+           }
+         else
+           {
+             int i;
+
+             for (i = 0; i < XVECLEN (container, 0) && !need_temp; i++)
+               {
+                 rtx slot = XVECEXP (container, 0, i);
+                 if (REGNO (XEXP (slot, 0)) != (unsigned int)i
+                     || INTVAL (XEXP (slot, 1)) != i * 8)
+                   need_temp = 1;
+               }
+           }
+       }
+      if (!need_temp)
+       {
+         int_addr_rtx = addr_rtx;
+         sse_addr_rtx = addr_rtx;
+       }
+      else
+       {
+         int_addr_rtx = gen_reg_rtx (Pmode);
+         sse_addr_rtx = gen_reg_rtx (Pmode);
+       }
+      /* First ensure that we fit completely in registers.  */
+      if (needed_intregs)
+       {
+         emit_cmp_and_jump_insns (expand_expr
+                                  (gpr, NULL_RTX, SImode, EXPAND_NORMAL),
+                                  GEN_INT ((REGPARM_MAX - needed_intregs +
+                                            1) * 8), GE, const1_rtx, SImode,
+                                  1, 1, lab_false);
+       }
+      if (needed_sseregs)
+       {
+         emit_cmp_and_jump_insns (expand_expr
+                                  (fpr, NULL_RTX, SImode, EXPAND_NORMAL),
+                                  GEN_INT ((SSE_REGPARM_MAX -
+                                            needed_sseregs + 1) * 16 +
+                                           REGPARM_MAX * 8), GE, const1_rtx,
+                                  SImode, 1, 1, lab_false);
+       }
+
+      /* Compute index to start of area used for integer regs.  */
+      if (needed_intregs)
+       {
+         t = build (PLUS_EXPR, ptr_type_node, sav, gpr);
+         r = expand_expr (t, int_addr_rtx, Pmode, EXPAND_NORMAL);
+         if (r != int_addr_rtx)
+           emit_move_insn (int_addr_rtx, r);
+       }
+      if (needed_sseregs)
+       {
+         t = build (PLUS_EXPR, ptr_type_node, sav, fpr);
+         r = expand_expr (t, sse_addr_rtx, Pmode, EXPAND_NORMAL);
+         if (r != sse_addr_rtx)
+           emit_move_insn (sse_addr_rtx, r);
+       }
+      if (need_temp)
+       {
+         int i;
+         rtx mem;
+
+         mem = assign_temp (type, 0, 1, 0);
+         MEM_ALIAS_SET (mem) = get_varargs_alias_set ();
+         addr_rtx = XEXP (mem, 0);
+         for (i = 0; i < XVECLEN (container, 0); i++)
+           {
+             rtx slot = XVECEXP (container, 0, i);
+             rtx reg = XEXP (slot, 0);
+             enum machine_mode mode = GET_MODE (reg);
+             rtx src_addr;
+             rtx src_mem;
+             int src_offset;
+             rtx dest_mem;
+
+             if (SSE_REGNO_P (REGNO (reg)))
+               {
+                 src_addr = sse_addr_rtx;
+                 src_offset = (REGNO (reg) - FIRST_SSE_REG) * 16;
+               }
+             else
+               {
+                 src_addr = int_addr_rtx;
+                 src_offset = REGNO (reg) * 8;
+               }
+             src_mem = gen_rtx_MEM (mode, src_addr);
+             MEM_ALIAS_SET (src_mem) = get_varargs_alias_set ();
+             src_mem = adjust_address (src_mem, mode, src_offset);
+             dest_mem = adjust_address (mem, mode, INTVAL (XEXP (slot, 1)));
+             PUT_MODE (dest_mem, mode);
+             /* ??? Break out TImode moves from integer registers?  */
+             emit_move_insn (dest_mem, src_mem);
+           }
+       }
+
+      if (needed_intregs)
+       {
+         t =
+           build (PLUS_EXPR, TREE_TYPE (gpr), gpr,
+                  build_int_2 (needed_intregs * 8, 0));
+         t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t);
+         TREE_SIDE_EFFECTS (t) = 1;
+         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+       }
+      if (needed_sseregs)
+       {
+         t =
+           build (PLUS_EXPR, TREE_TYPE (fpr), fpr,
+                  build_int_2 (needed_sseregs * 16, 0));
+         t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, t);
+         TREE_SIDE_EFFECTS (t) = 1;
+         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+       }
+
+      emit_jump_insn (gen_jump (lab_over));
+      emit_barrier ();
+      emit_label (lab_false);
+    }
+
+  /* ... otherwise out of the overflow area.  */
+
+  /* Care for on-stack alignment if needed.  */
+  if (FUNCTION_ARG_BOUNDARY (VOIDmode, type) <= 64)
+    t = ovf;
+  else
+    {
+      HOST_WIDE_INT align = FUNCTION_ARG_BOUNDARY (VOIDmode, type) / 8;
+      t = build (PLUS_EXPR, TREE_TYPE (ovf), ovf, build_int_2 (align - 1, 0));
+      t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
+    }
+  t = save_expr (t);
+
+  r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+  if (r != addr_rtx)
+    emit_move_insn (addr_rtx, r);
+
+  t =
+    build (PLUS_EXPR, TREE_TYPE (t), t,
+          build_int_2 (rsize * UNITS_PER_WORD, 0));
+  t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  if (container)
+    emit_label (lab_over);
+
+  if (indirect_p)
+    {
+      abort ();
+      r = gen_rtx_MEM (Pmode, addr_rtx);
+      MEM_ALIAS_SET (r) = get_varargs_alias_set ();
+      emit_move_insn (addr_rtx, r);
+    }
+
+  return addr_rtx;
+}
+\f
 /* Return nonzero if OP is general operand representable on x86_64.  */
 
 int
index 4d76ac67b29b4ccc065eaf136c9fcd19b3f346b4..654d8fbdac0da6afadea979e12a6253c411086fa 100644 (file)
@@ -1604,6 +1604,35 @@ typedef struct ix86_args {
        || ! FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (TREE_TYPE (DECL)))) \
        || FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (TREE_TYPE (cfun->decl))))))
 
+/* Perform any needed actions needed for a function that is receiving a
+   variable number of arguments.
+
+   CUM is as above.
+
+   MODE and TYPE are the mode and type of the current parameter.
+
+   PRETEND_SIZE is a variable that should be set to the amount of stack
+   that must be pushed by the prolog to pretend that our caller pushed
+   it.
+
+   Normally, this macro will push all remaining incoming registers on the
+   stack and set PRETEND_SIZE to the length of the registers pushed.  */
+
+#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
+  ix86_setup_incoming_varargs (&CUM, MODE, TYPE, &PRETEND_SIZE, NO_RTL)
+
+/* Define the `__builtin_va_list' type for the ABI.  */
+#define BUILD_VA_LIST_TYPE(VALIST) \
+  (VALIST) = ix86_build_va_list ()
+
+/* Implement `va_start' for varargs and stdarg.  */
+#define EXPAND_BUILTIN_VA_START(stdarg, valist, nextarg) \
+  ix86_va_start (stdarg, valist, nextarg)
+
+/* Implement `va_arg'.  */
+#define EXPAND_BUILTIN_VA_ARG(valist, type) \
+  ix86_va_arg (valist, type)
+
 /* This macro is invoked at the end of compilation.  It is used here to
    output code for -fpic that will load the return address into %ebx.  */
 
@@ -2775,6 +2804,7 @@ extern int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER];
 #define EH_RETURN_DATA_REGNO(N)        ((N) < 2 ? (N) : INVALID_REGNUM)
 #define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, 2)
 
+
 /* Select a format to encode pointers in exception handling data.  CODE
    is 0 for data, 1 for code labels, 2 for function pointers.  GLOBAL is
    true if the symbol may be affected by dynamic relocations.
index 8021f39b33f2f0be624a5f9e65318efd19bab95c..5119db6615b0db83b67c00ff0e876095fd1e8f4a 100644 (file)
 }
   [(set_attr "type" "sse")])
 
+(define_expand "sse_prologue_save"
+  [(parallel [(set (match_operand:BLK 0 "" "")
+                  (unspec:BLK [(reg:DI 21)
+                               (reg:DI 22)
+                               (reg:DI 23)
+                               (reg:DI 24)
+                               (reg:DI 25)
+                               (reg:DI 26)
+                               (reg:DI 27)
+                               (reg:DI 28)] 13))
+             (use (match_operand:DI 1 "register_operand" ""))
+             (use (match_operand:DI 2 "immediate_operand" ""))
+             (use (label_ref:DI (match_operand 3 "" "")))])]
+  "TARGET_64BIT"
+  "")
+
+(define_insn "*sse_prologue_save_insn"
+  [(set (mem:BLK (plus:DI (match_operand:DI 0 "register_operand" "R")
+                         (match_operand:DI 4 "const_int_operand" "n")))
+       (unspec:BLK [(reg:DI 21)
+                    (reg:DI 22)
+                    (reg:DI 23)
+                    (reg:DI 24)
+                    (reg:DI 25)
+                    (reg:DI 26)
+                    (reg:DI 27)
+                    (reg:DI 28)] 13))
+   (use (match_operand:DI 1 "register_operand" "r"))
+   (use (match_operand:DI 2 "const_int_operand" "i"))
+   (use (label_ref:DI (match_operand 3 "" "X")))]
+  "TARGET_64BIT
+   && INTVAL (operands[4]) + SSE_REGPARM_MAX * 16 - 16 < 128
+   && INTVAL (operands[4]) + INTVAL (operands[2]) * 16 >= -128"
+  "*
+{
+  int i;
+  operands[0] = gen_rtx_MEM (Pmode,
+                            gen_rtx_PLUS (Pmode, operands[0], operands[4]));
+  output_asm_insn (\"jmp\\t%A1\", operands);
+  for (i = SSE_REGPARM_MAX - 1; i >= INTVAL (operands[2]); i--)
+    {
+      operands[4] = adjust_address (operands[0], DImode, i*16);
+      operands[5] = gen_rtx_REG (TImode, SSE_REGNO (i));
+      PUT_MODE (operands[4], TImode);
+      if (GET_CODE (XEXP (operands[0], 0)) != PLUS)
+        output_asm_insn (\"rex\", operands);
+      output_asm_insn (\"movaps\\t{%5, %4|%4, %5}\", operands);
+    }
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
+                            CODE_LABEL_NUMBER (operands[3]));
+  RET;
+}
+  "
+  [(set_attr "type" "other")
+   (set_attr "length_immediate" "0")
+   (set_attr "length_address" "0")
+   (set_attr "length" "135")
+   (set_attr "memory" "store")
+   (set_attr "modrm" "0")
+   (set_attr "mode" "DI")])
index d2b2afc8a8065b81042ffe3fb467c053c75fc501..58c4d0390bb10df009d33463e7f456eb20d1b875 100644 (file)
@@ -274,7 +274,7 @@ in the following sections.
 -fschedule-insns  -fschedule-insns2 @gol
 -fsingle-precision-constant  -fssa -fssa-ccp -fssa-dce @gol
 -fstrength-reduce  -fstrict-aliasing  -fthread-jumps  -ftrapv @gol
--funroll-all-loops  -funroll-loops  @gol
+-funroll-all-loops  -funroll-loops -fmessy-debugging @gol
 --param @var{name}=@var{value}
 -O  -O0  -O1  -O2  -O3  -Os}
 
@@ -3414,6 +3414,18 @@ of optimizations to be performed is desired.
 Not all of the optimizations performed by GCC have @option{-f} options
 to control them.
 
+@table @gcctabopt
+@item -fmessy-debugging
+@opindex fmessy-debugging
+Some optimizations can be stronger if compiler give up ability to generate
+at least approximately usefull debug information for optimized programs.
+These transformation are not done when @option{-g} switch is not specified,
+as politics is to get the code with @option{-g} and without equivalent,
+except for debugging section.
+
+This optimization enables such transformations.  It is still compatible with
+@option{-g}, but debugging resulting programs will be even higher challenge.
+
 @table @gcctabopt
 @item -fstrength-reduce
 @opindex fstrength-reduce