]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/config/xtensa/xtensa.c
xtensa.c (xtensa_build_va_list): Use lang_hooks.types.make_type instead of make_node...
[gcc.git] / gcc / config / xtensa / xtensa.c
index a791da00fb75c529690b97545e5c5193e4312218..f2cb700e1ba1015d24a06fdaee4ff40627255312 100644 (file)
@@ -42,9 +42,12 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "function.h"
 #include "toplev.h"
 #include "optabs.h"
+#include "output.h"
 #include "libfuncs.h"
+#include "ggc.h"
 #include "target.h"
 #include "target-def.h"
+#include "langhooks.h"
 
 /* Enumeration for all of the relational tests, so that we can build
    arrays indexed by the test type, and not worry about the order
@@ -84,7 +87,7 @@ const char *xtensa_st_opcodes[(int) MAX_MACHINE_MODE];
 #define LARGEST_MOVE_RATIO 15
 
 /* Define the structure for the machine field in struct function.  */
-struct machine_function
+struct machine_function GTY(())
 {
   int accesses_prev_frame;
 };
@@ -185,6 +188,24 @@ enum reg_class xtensa_char_to_class[256] =
   NO_REGS,     NO_REGS,        NO_REGS,        NO_REGS,
 };
 
+static int b4const_or_zero PARAMS ((int));
+static enum internal_test map_test_to_internal_test PARAMS ((enum rtx_code));
+static rtx gen_int_relational PARAMS ((enum rtx_code, rtx, rtx, int *));
+static rtx gen_float_relational PARAMS ((enum rtx_code, rtx, rtx));
+static rtx gen_conditional_move PARAMS ((rtx));
+static rtx fixup_subreg_mem PARAMS ((rtx x));
+static enum machine_mode xtensa_find_mode_for_size PARAMS ((unsigned));
+static struct machine_function * xtensa_init_machine_status PARAMS ((void));
+static void printx PARAMS ((FILE *, signed int));
+static void xtensa_select_rtx_section PARAMS ((enum machine_mode, rtx,
+                                              unsigned HOST_WIDE_INT));
+static void xtensa_encode_section_info PARAMS ((tree, int));
+
+static rtx frame_size_const;
+static int current_function_arg_words;
+static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
+  REG_ALLOC_ORDER;
+\f
 /* 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.
@@ -210,23 +231,13 @@ enum reg_class xtensa_char_to_class[256] =
 #undef TARGET_ASM_ALIGNED_SI_OP
 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
 
-struct gcc_target targetm = TARGET_INITIALIZER;
-
-static int b4const_or_zero PARAMS ((int));
-static enum internal_test map_test_to_internal_test PARAMS ((enum rtx_code));
-static rtx gen_int_relational PARAMS ((enum rtx_code, rtx, rtx, int *));
-static rtx gen_float_relational PARAMS ((enum rtx_code, rtx, rtx));
-static rtx gen_conditional_move PARAMS ((rtx));
-static rtx fixup_subreg_mem PARAMS ((rtx x));
-static enum machine_mode xtensa_find_mode_for_size PARAMS ((unsigned));
-static void xtensa_init_machine_status PARAMS ((struct function *p));
-static void xtensa_free_machine_status PARAMS ((struct function *p));
-static void printx PARAMS ((FILE *, signed int));
-static rtx frame_size_const;
-static int current_function_arg_words;
-static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
-  REG_ALLOC_ORDER;
+#undef TARGET_ASM_SELECT_RTX_SECTION
+#define TARGET_ASM_SELECT_RTX_SECTION  xtensa_select_rtx_section
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO  xtensa_encode_section_info
 
+struct gcc_target targetm = TARGET_INITIALIZER;
+\f
 
 /*
  * Functions to test Xtensa immediate operand validity.
@@ -460,7 +471,7 @@ xtensa_valid_move (mode, operands)
       if (!ACC_REG_P (dst_regnum))
        return true;
     }
-  else if (register_operand (operands[1], mode))
+  if (register_operand (operands[1], mode))
     {
       int src_regnum = xt_true_regnum (operands[1]);
       if (!ACC_REG_P (src_regnum))
@@ -1371,7 +1382,7 @@ xtensa_expand_block_move (operands)
   if (num_pieces >= move_ratio)
     return 0;
 
-   /* make sure the memory addresses are valid */
+  /* make sure the memory addresses are valid */
   operands[0] = validize_mem (dest);
   operands[1] = validize_mem (src);
 
@@ -1539,21 +1550,10 @@ xtensa_expand_nonlocal_goto (operands)
 }
 
 
-static void
-xtensa_init_machine_status (p)
-     struct function *p;
+static struct machine_function *
+xtensa_init_machine_status ()
 {
-  p->machine = (struct machine_function *)
-    xcalloc (1, sizeof (struct machine_function));
-}
-
-
-static void
-xtensa_free_machine_status (p)
-     struct function *p;
-{
-  free (p->machine);
-  p->machine = NULL;
+  return ggc_alloc_cleared (sizeof (struct machine_function));
 }
 
 
@@ -1628,7 +1628,7 @@ xtensa_emit_call (callop, operands)
      int callop;
      rtx *operands;
 {
-  char *result = (char *) malloc (64);
+  static char result[64];
   rtx tgt = operands[callop];
 
   if (GET_CODE (tgt) == CONST_INT)
@@ -1836,7 +1836,6 @@ override_options ()
     }
 
   init_machine_status = xtensa_init_machine_status;
-  free_machine_status = xtensa_free_machine_status;
 
   /* Check PIC settings.  There's no need for -fPIC on Xtensa and
      some targets need to always use PIC.  */
@@ -1926,10 +1925,8 @@ print_operand (file, op, letter)
       }
 
     case MEM:
-        /*
-        * For a volatile memory reference, emit a MEMW before the
-        * load or store.
-        */
+      /* For a volatile memory reference, emit a MEMW before the
+        load or store.  */
        if (letter == 'v')
          {
            if (MEM_VOLATILE_P (op) && TARGET_SERIALIZE_VOLATILE)
@@ -1937,7 +1934,16 @@ print_operand (file, op, letter)
            break;
          }
        else if (letter == 'N')
-         op = adjust_address (op, GET_MODE (op), 4);
+         {
+           enum machine_mode mode;
+           switch (GET_MODE (op))
+             {
+             case DFmode: mode = SFmode; break;
+             case DImode: mode = SImode; break;
+             default: abort ();
+             }
+           op = adjust_address (op, mode, 4);
+         }
 
        output_address (XEXP (op, 0));
        break;
@@ -1989,12 +1995,7 @@ print_operand (file, op, letter)
 
 /* A C compound statement to output to stdio stream STREAM the
    assembler syntax for an instruction operand that is a memory
-   reference whose address is ADDR.  ADDR is an RTL expression.
-
-   On some machines, the syntax for a symbolic address depends on
-   the section that the address refers to.  On these machines,
-   define the macro 'ENCODE_SECTION_INFO' to store the information
-   into the 'symbol_ref', and then check for it here.  */
+   reference whose address is ADDR.  ADDR is an RTL expression.  */
 
 void
 print_operand_address (file, addr)
@@ -2303,9 +2304,10 @@ xtensa_function_epilogue (file, size)
 tree
 xtensa_build_va_list (void)
 {
-  tree f_stk, f_reg, f_ndx, record;
+  tree f_stk, f_reg, f_ndx, record, type_decl;
 
-  record = make_node (RECORD_TYPE);
+  record = (*lang_hooks.types.make_type) (RECORD_TYPE);
+  type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
 
   f_stk = build_decl (FIELD_DECL, get_identifier ("__va_stk"),
                      ptr_type_node);
@@ -2318,6 +2320,8 @@ xtensa_build_va_list (void)
   DECL_FIELD_CONTEXT (f_reg) = record;
   DECL_FIELD_CONTEXT (f_ndx) = record;
 
+  TREE_CHAIN (record) = type_decl;
+  TYPE_NAME (record) = type_decl;
   TYPE_FIELDS (record) = f_stk;
   TREE_CHAIN (f_stk) = f_reg;
   TREE_CHAIN (f_reg) = f_ndx;
@@ -2344,9 +2348,7 @@ xtensa_builtin_saveregs ()
   /* allocate the general-purpose register space */
   gp_regs = assign_stack_local
     (BLKmode, MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD, -1);
-  MEM_IN_STRUCT_P (gp_regs) = 1;
-  RTX_UNCHANGING_P (gp_regs) = 1;
-  RTX_UNCHANGING_P (XEXP (gp_regs, 0)) = 1;
+  set_mem_alias_set (gp_regs, get_varargs_alias_set ());
 
   /* Now store the incoming registers.  */
   dest = change_address (gp_regs, SImode,
@@ -2424,14 +2426,10 @@ xtensa_va_arg (valist, type)
   tree f_stk, stk;
   tree f_reg, reg;
   tree f_ndx, ndx;
-  tree tmp, addr_tree;
-  rtx array, orig_ndx, r, addr;
-  HOST_WIDE_INT size, va_size;
+  tree tmp, addr_tree, type_size;
+  rtx array, orig_ndx, r, addr, size, va_size;
   rtx lab_false, lab_over, lab_false2;
 
-  size = int_size_in_bytes (type);
-  va_size = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
-
   f_stk = TYPE_FIELDS (va_list_type_node);
   f_reg = TREE_CHAIN (f_stk);
   f_ndx = TREE_CHAIN (f_reg);
@@ -2440,6 +2438,20 @@ xtensa_va_arg (valist, type)
   reg = build (COMPONENT_REF, TREE_TYPE (f_reg), valist, f_reg);
   ndx = build (COMPONENT_REF, TREE_TYPE (f_ndx), valist, f_ndx);
 
+  type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type));
+
+  va_size = gen_reg_rtx (SImode);
+  tmp = fold (build (MULT_EXPR, sizetype,
+                    fold (build (TRUNC_DIV_EXPR, sizetype,
+                                 fold (build (PLUS_EXPR, sizetype,
+                                              type_size,
+                                              size_int (UNITS_PER_WORD - 1))),
+                                 size_int (UNITS_PER_WORD))),
+                    size_int (UNITS_PER_WORD)));
+  r = expand_expr (tmp, va_size, SImode, EXPAND_NORMAL);
+  if (r != va_size)
+    emit_move_insn (va_size, r);
+
 
   /* First align __va_ndx to a double word boundary if necessary for this arg:
 
@@ -2470,7 +2482,8 @@ xtensa_va_arg (valist, type)
   if (r != orig_ndx)
     emit_move_insn (orig_ndx, r);
 
-  tmp = build (PLUS_EXPR, integer_type_node, ndx, build_int_2 (va_size, 0));
+  tmp = build (PLUS_EXPR, integer_type_node, ndx,
+              make_tree (intSI_type_node, va_size));
   tmp = build (MODIFY_EXPR, integer_type_node, ndx, tmp);
   TREE_SIDE_EFFECTS (tmp) = 1;
   expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -2478,26 +2491,33 @@ xtensa_va_arg (valist, type)
 
   /* Check if the argument is in registers:
 
-     if ((AP).__va_ndx <= __MAX_ARGS_IN_REGISTERS * 4)
+     if ((AP).__va_ndx <= __MAX_ARGS_IN_REGISTERS * 4
+         && !MUST_PASS_IN_STACK (type))
         __array = (AP).__va_reg;
   */
 
-  lab_false = gen_label_rtx ();
-  lab_over = gen_label_rtx ();
   array = gen_reg_rtx (Pmode);
 
-  emit_cmp_and_jump_insns (expand_expr (ndx, NULL_RTX, SImode, EXPAND_NORMAL),
-                          GEN_INT (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD),
-                          GT, const1_rtx, SImode, 0, lab_false);
-
-  r = expand_expr (reg, array, Pmode, EXPAND_NORMAL);
-  if (r != array)
-    emit_move_insn (array, r);
-
-  emit_jump_insn (gen_jump (lab_over));
-  emit_barrier ();
-  emit_label (lab_false);
-
+  lab_over = NULL_RTX;
+  if (!MUST_PASS_IN_STACK (VOIDmode, type))
+    {
+      lab_false = gen_label_rtx ();
+      lab_over = gen_label_rtx ();
+
+      emit_cmp_and_jump_insns (expand_expr (ndx, NULL_RTX, SImode,
+                                           EXPAND_NORMAL),
+                              GEN_INT (MAX_ARGS_IN_REGISTERS
+                                       * UNITS_PER_WORD),
+                              GT, const1_rtx, SImode, 0, lab_false);
+
+      r = expand_expr (reg, array, Pmode, EXPAND_NORMAL);
+      if (r != array)
+       emit_move_insn (array, r);
+
+      emit_jump_insn (gen_jump (lab_over));
+      emit_barrier ();
+      emit_label (lab_false);
+    }
 
   /* ...otherwise, the argument is on the stack (never split between
      registers and the stack -- change __va_ndx if necessary):
@@ -2515,7 +2535,8 @@ xtensa_va_arg (valist, type)
                           GEN_INT (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD),
                           GE, const1_rtx, SImode, 0, lab_false2);
 
-  tmp = build_int_2 ((MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD) + va_size, 0);
+  tmp = build (PLUS_EXPR, sizetype, make_tree (intSI_type_node, va_size),
+              build_int_2 (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD, 0));
   tmp = build (MODIFY_EXPR, integer_type_node, ndx, tmp);
   TREE_SIDE_EFFECTS (tmp) = 1;
   expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -2526,31 +2547,45 @@ xtensa_va_arg (valist, type)
   if (r != array)
     emit_move_insn (array, r);
 
+  if (lab_over != NULL_RTX)
+    emit_label (lab_over);
+
 
   /* Given the base array pointer (__array) and index to the subsequent
      argument (__va_ndx), find the address:
 
-     Big-endian:
-     __array + (AP).__va_ndx - sizeof (TYPE)
-
-     Little-endian:
-     __array + (AP).__va_ndx - __va_size (TYPE)
+     __array + (AP).__va_ndx - (BYTES_BIG_ENDIAN && sizeof (TYPE) < 4
+                               ? sizeof (TYPE)
+                               : __va_size (TYPE))
 
      The results are endian-dependent because values smaller than one word
      are aligned differently.
   */
 
-  emit_label (lab_over);
+  size = gen_reg_rtx (SImode);
+  emit_move_insn (size, va_size);
+  
+  if (BYTES_BIG_ENDIAN)
+    {
+      rtx lab_use_va_size = gen_label_rtx ();
+
+      emit_cmp_and_jump_insns (expand_expr (type_size, NULL_RTX, SImode,
+                                           EXPAND_NORMAL),
+                              GEN_INT (PARM_BOUNDARY / BITS_PER_UNIT),
+                              GE, const1_rtx, SImode, 0, lab_use_va_size);
+
+      r = expand_expr (type_size, size, SImode, EXPAND_NORMAL);
+      if (r != size)
+       emit_move_insn (size, r);
+
+      emit_label (lab_use_va_size);
+    }
 
   addr_tree = build (PLUS_EXPR, ptr_type_node,
                     make_tree (ptr_type_node, array),
                     ndx);
-  addr_tree = build (PLUS_EXPR, ptr_type_node,
-                    addr_tree,
-                    build_int_2 (BYTES_BIG_ENDIAN
-                                 && size < (PARM_BOUNDARY / BITS_PER_UNIT)
-                                 ? -size
-                                 : -va_size, -1));
+  addr_tree = build (MINUS_EXPR, ptr_type_node, addr_tree,
+                    make_tree (intSI_type_node, size));
   addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
   addr = copy_to_reg (addr);
   return addr;
@@ -2691,3 +2726,28 @@ a7_overlap_mentioned_p (x)
 
   return 0;
 }
+
+/* The literal pool stays with the function.  */
+
+static void
+xtensa_select_rtx_section (mode, x, align)
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+     rtx x ATTRIBUTE_UNUSED;
+     unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
+{
+  function_section (current_function_decl);
+}
+
+/* If we are referencing a function that is static, make the SYMBOL_REF
+   special so that we can generate direct calls to it even with -fpic.  */
+
+static void
+xtensa_encode_section_info (decl, first)
+     tree decl;
+     int first ATTRIBUTE_UNUSED;
+{
+  if (TREE_CODE (decl) == FUNCTION_DECL && ! TREE_PUBLIC (decl))
+    SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
+}
+
+#include "gt-xtensa.h"
This page took 0.038179 seconds and 5 git commands to generate.