Implement call0 ABI for xtensa
authorMax Filippov <jcmvbkbc@gmail.com>
Tue, 3 Mar 2015 17:44:01 +0000 (17:44 +0000)
committerMax Filippov <jcmvbkbc@gcc.gnu.org>
Tue, 3 Mar 2015 17:44:01 +0000 (17:44 +0000)
call0 is an ABI that doesn't use register windows.

2015-03-03  Max Filippov  <jcmvbkbc@gmail.com>

gcc/
* config/xtensa/constraints.md ("a" constraint): Include stack
pointer in case of call0 ABI.
("q" constraint): Make empty in case of call0 ABI.
("D" constraint): Include stack pointer in case of call0 ABI.
* config/xtensa/xtensa-protos.h (xtensa_set_return_address,
xtensa_expand_epilogue, xtensa_regno_to_class): Add new function
prototypes.
* config/xtensa/xtensa.c (xtensa_callee_save_size): New
variable.
(xtensa_regno_to_class): Make it a local variable in the
function xtensa_regno_to_class.
(xtensa_function_epilogue, TARGET_ASM_FUNCTION_EPILOGUE): Remove
macro, function prototype and implementation.
(reg_nonleaf_alloc_order): Make it a local variable in the
function order_regs_for_local_alloc.
(xtensa_conditional_register_usage): New function.
(TARGET_CONDITIONAL_REGISTER_USAGE): Define macro.
(xtensa_valid_move): Allow direct moves to stack pointer
register in call0 ABI.
(xtensa_setup_frame_addresses): Only spill register windows in
windowed ABI.
(xtensa_emit_call): Emit call(x)8 or call(x)0 in windowed and
call0 ABI respectively.
(xtensa_function_arg_1): Only mark a7 register for copying in
windowed ABI.
(xtensa_call_save_reg): New function.
(compute_frame_size): Add space for callee saved register
storage to the frame size in call0 ABI.
(xtensa_expand_prologue): Generate code to set up stack frame
and save callee-saved registers in call0 ABI.
(xtensa_expand_epilogue): New function.
(xtensa_set_return_address): New function.
(xtensa_return_addr): Calculate return address in call0 ABI.
(xtensa_builtin_saveregs): Only mark a7 register for copying and
emit copying code in windowed ABI.
(order_regs_for_local_alloc): Add preferred register allocation
order for non-leaf function in call0 ABI.
(xtensa_static_chain): Add atatic chain passing for call0 ABI.
(xtensa_asm_trampoline_template): Add trampoline generation for
call0 ABI.
(xtensa_trampoline_init): Add trampoline initialization for
call0 ABI.
(xtensa_conditional_register_usage, xtensa_regno_to_class): New
functions.
* config/xtensa/xtensa.h (TARGET_WINDOWED_ABI): New macro.
(TARGET_CPU_CPP_BUILTINS): Add built-in define for call0 ABI.
(CALL_USED_REGISTERS): Modify to encode both windowed and call0
ABI call-used registers.
(HARD_FRAME_POINTER_REGNUM): Add frame pointer for call0 ABI.
(INCOMING_REGNO, OUTGOING_REGNO): Use argument unchanged in
call0 ABI.
(REG_CLASS_CONTENTS): Include all registers into the preferred
reload registers set, adjust the set in the
xtensa_conditional_register_usage.
(xtensa_regno_to_class): Drop variable declaration.
(REGNO_REG_CLASS): Redefine to use xtensa_regno_to_class
function.
(WINDOW_SIZE): Define as 8 or 0 for windowed and call0 ABI
respectively.
(FUNCTION_PROFILER): Add _mcount call for call0 ABI.
(TRAMPOLINE_SIZE): Define trampoline size for call0 ABI.
(RETURN_ADDR_IN_PREVIOUS_FRAME): Define to 0 in call0 ABI.
(ASM_OUTPUT_POOL_PROLOGUE): Always generate literal pool
location in call0 ABI.
(EH_RETURN_STACKADJ_RTX): New definition, use a10 for passing
stack adjustment size when handling exception.
(CRT_CALL_STATIC_FUNCTION): Add definition for call0 ABI.
* config/xtensa/xtensa.md (A9_REG, UNSPECV_BLOCKAGE): New
definitions.
("return" pattern): Generate ret.n/ret in call0 ABI.
("epilogue" pattern): Expand epilogue.
("nonlocal_goto" pattern): Use default in call0 ABI.
("eh_return" pattern): Move implementation to eh_set_a0_windowed,
emit eh_set_a0_* depending on ABI.
("eh_set_a0_windowed" pattern): Former eh_return pattern.
("eh_set_a0_call0", "blockage"): New patterns.

libgcc/
* config/xtensa/lib2funcs.S (__xtensa_libgcc_window_spill,
__xtensa_nonlocal_goto): Don't compile for call0 ABI.
(__xtensa_sync_caches): Only use entry and retw in windowed ABI,
use ret in call0 ABI.
* config/xtensa/t-windowed: New file.
* libgcc/config/xtensa/t-xtensa (LIB2ADDEH): Move to t-windowed.
* libgcc/configure: Regenerated.
* libgcc/configure.ac: Check if xtensa target is configured for
windowed ABI and thus needs to use custom unwind code.

From-SVN: r221158

13 files changed:
gcc/ChangeLog
gcc/config/xtensa/constraints.md
gcc/config/xtensa/xtensa-protos.h
gcc/config/xtensa/xtensa.c
gcc/config/xtensa/xtensa.h
gcc/config/xtensa/xtensa.md
libgcc/ChangeLog
libgcc/config/xtensa/lib2funcs.S
libgcc/config/xtensa/linux-unwind.h
libgcc/config/xtensa/t-windowed [new file with mode: 0644]
libgcc/config/xtensa/t-xtensa
libgcc/configure
libgcc/configure.ac

index 6cbeb89a0ce15adc35496aa44fa28b2cbf7d99a5..5c1bb2701934e059503a9db5ca41b3db6c63a1d7 100644 (file)
@@ -1,3 +1,83 @@
+2015-03-03  Max Filippov  <jcmvbkbc@gmail.com>
+
+       Implement call0 ABI for xtensa
+       * config/xtensa/constraints.md ("a" constraint): Include stack
+       pointer in case of call0 ABI.
+       ("q" constraint): Make empty in case of call0 ABI.
+       ("D" constraint): Include stack pointer in case of call0 ABI.
+       * config/xtensa/xtensa-protos.h (xtensa_set_return_address,
+       xtensa_expand_epilogue, xtensa_regno_to_class): Add new function
+       prototypes.
+       * config/xtensa/xtensa.c (xtensa_callee_save_size): New
+       variable.
+       (xtensa_regno_to_class): Make it a local variable in the
+       function xtensa_regno_to_class.
+       (xtensa_function_epilogue, TARGET_ASM_FUNCTION_EPILOGUE): Remove
+       macro, function prototype and implementation.
+       (reg_nonleaf_alloc_order): Make it a local variable in the
+       function order_regs_for_local_alloc.
+       (xtensa_conditional_register_usage): New function.
+       (TARGET_CONDITIONAL_REGISTER_USAGE): Define macro.
+       (xtensa_valid_move): Allow direct moves to stack pointer
+       register in call0 ABI.
+       (xtensa_setup_frame_addresses): Only spill register windows in
+       windowed ABI.
+       (xtensa_emit_call): Emit call(x)8 or call(x)0 in windowed and
+       call0 ABI respectively.
+       (xtensa_function_arg_1): Only mark a7 register for copying in
+       windowed ABI.
+       (xtensa_call_save_reg): New function.
+       (compute_frame_size): Add space for callee saved register
+       storage to the frame size in call0 ABI.
+       (xtensa_expand_prologue): Generate code to set up stack frame
+       and save callee-saved registers in call0 ABI.
+       (xtensa_expand_epilogue): New function.
+       (xtensa_set_return_address): New function.
+       (xtensa_return_addr): Calculate return address in call0 ABI.
+       (xtensa_builtin_saveregs): Only mark a7 register for copying and
+       emit copying code in windowed ABI.
+       (order_regs_for_local_alloc): Add preferred register allocation
+       order for non-leaf function in call0 ABI.
+       (xtensa_static_chain): Add atatic chain passing for call0 ABI.
+       (xtensa_asm_trampoline_template): Add trampoline generation for
+       call0 ABI.
+       (xtensa_trampoline_init): Add trampoline initialization for
+       call0 ABI.
+       (xtensa_conditional_register_usage, xtensa_regno_to_class): New
+       functions.
+       * config/xtensa/xtensa.h (TARGET_WINDOWED_ABI): New macro.
+       (TARGET_CPU_CPP_BUILTINS): Add built-in define for call0 ABI.
+       (CALL_USED_REGISTERS): Modify to encode both windowed and call0
+       ABI call-used registers.
+       (HARD_FRAME_POINTER_REGNUM): Add frame pointer for call0 ABI.
+       (INCOMING_REGNO, OUTGOING_REGNO): Use argument unchanged in
+       call0 ABI.
+       (REG_CLASS_CONTENTS): Include all registers into the preferred
+       reload registers set, adjust the set in the
+       xtensa_conditional_register_usage.
+       (xtensa_regno_to_class): Drop variable declaration.
+       (REGNO_REG_CLASS): Redefine to use xtensa_regno_to_class
+       function.
+       (WINDOW_SIZE): Define as 8 or 0 for windowed and call0 ABI
+       respectively.
+       (FUNCTION_PROFILER): Add _mcount call for call0 ABI.
+       (TRAMPOLINE_SIZE): Define trampoline size for call0 ABI.
+       (RETURN_ADDR_IN_PREVIOUS_FRAME): Define to 0 in call0 ABI.
+       (ASM_OUTPUT_POOL_PROLOGUE): Always generate literal pool
+       location in call0 ABI.
+       (EH_RETURN_STACKADJ_RTX): New definition, use a10 for passing
+       stack adjustment size when handling exception.
+       (CRT_CALL_STATIC_FUNCTION): Add definition for call0 ABI.
+       * config/xtensa/xtensa.md (A9_REG, UNSPECV_BLOCKAGE): New
+       definitions.
+       ("return" pattern): Generate ret.n/ret in call0 ABI.
+       ("epilogue" pattern): Expand epilogue.
+       ("nonlocal_goto" pattern): Use default in call0 ABI.
+       ("eh_return" pattern): Move implementation to eh_set_a0_windowed,
+       emit eh_set_a0_* depending on ABI.
+       ("eh_set_a0_windowed" pattern): Former eh_return pattern.
+       ("eh_set_a0_call0", "blockage"): New patterns.
+
 2015-03-03  Martin Liska  <mliska@suse.cz>
 
        PR ipa/65287
index 74aca6c2edfa2edcec0ad5b4268c6529aa465172..30f4c1f696de6cf0d1acfc9e341ee2fc67c37b69 100644 (file)
@@ -19,7 +19,7 @@
 
 ;; Register constraints.
 
-(define_register_constraint "a" "GR_REGS"
+(define_register_constraint "a" "TARGET_WINDOWED_ABI ? GR_REGS : AR_REGS"
  "General-purpose AR registers @code{a0}-@code{a15},
   except @code{a1} (@code{sp}).")
 
@@ -36,7 +36,7 @@
  "Floating-point registers @code{f0}-@code{f15}; only available if the
   Xtensa Floating-Pointer Coprocessor is configured.")
 
-(define_register_constraint "q" "SP_REG"
+(define_register_constraint "q" "TARGET_WINDOWED_ABI ? SP_REG : NO_REGS"
  "@internal
   The stack pointer (register @code{a1}).")
 
@@ -53,7 +53,7 @@
   General-purpose AR registers, but only if the Xtensa 16-Bit Integer
   Multiply Option is configured.")
 
-(define_register_constraint "D" "TARGET_DENSITY ? GR_REGS: NO_REGS"
+(define_register_constraint "D" "TARGET_DENSITY ? (TARGET_WINDOWED_ABI ? GR_REGS : AR_REGS) : NO_REGS"
  "@internal
   General-purpose AR registers, but only if the Xtensa Code Density
   Option is configured.")
index ad95db047d8d4339ef4bae7e0de21a822504f0b0..6a5362547d50d0b597b162cbe8f3c04c16519fa1 100644 (file)
@@ -61,6 +61,7 @@ extern void init_cumulative_args (CUMULATIVE_ARGS *, int);
 extern void print_operand (FILE *, rtx, int);
 extern void print_operand_address (FILE *, rtx);
 extern void xtensa_output_literal (FILE *, rtx, machine_mode, int);
+extern void xtensa_set_return_address (rtx, rtx);
 extern rtx xtensa_return_addr (int, rtx);
 #endif /* RTX_CODE */
 
@@ -68,6 +69,8 @@ extern void xtensa_setup_frame_addresses (void);
 extern int xtensa_dbx_register_number (int);
 extern long compute_frame_size (int);
 extern void xtensa_expand_prologue (void);
+extern void xtensa_expand_epilogue (void);
 extern void order_regs_for_local_alloc (void);
+extern enum reg_class xtensa_regno_to_class (int regno);
 
 #endif /* !__XTENSA_PROTOS_H__ */
index 6c289e537193e54da96bb734b1b1a2347d9b2551..eb039bac56a2eaa5e83a0d3dbd5ce2a71dfba185 100644 (file)
@@ -118,6 +118,8 @@ char xtensa_hard_regno_mode_ok[(int) MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER];
 
 /* Current frame size calculated by compute_frame_size.  */
 unsigned xtensa_current_frame_size;
+/* Callee-save area size in the current frame calculated by compute_frame_size. */
+int xtensa_callee_save_size;
 
 /* Largest block move to handle in-line.  */
 #define LARGEST_MOVE_RATIO 15
@@ -144,21 +146,6 @@ const char xtensa_leaf_regs[FIRST_PSEUDO_REGISTER] =
   1
 };
 
-/* Map hard register number to register class */
-const enum reg_class xtensa_regno_to_class[FIRST_PSEUDO_REGISTER] =
-{
-  RL_REGS,     SP_REG,         RL_REGS,        RL_REGS,
-  RL_REGS,     RL_REGS,        RL_REGS,        GR_REGS,
-  RL_REGS,     RL_REGS,        RL_REGS,        RL_REGS,
-  RL_REGS,     RL_REGS,        RL_REGS,        RL_REGS,
-  AR_REGS,     AR_REGS,        BR_REGS,
-  FP_REGS,     FP_REGS,        FP_REGS,        FP_REGS,
-  FP_REGS,     FP_REGS,        FP_REGS,        FP_REGS,
-  FP_REGS,     FP_REGS,        FP_REGS,        FP_REGS,
-  FP_REGS,     FP_REGS,        FP_REGS,        FP_REGS,
-  ACC_REG,
-};
-
 static void xtensa_option_override (void);
 static enum internal_test map_test_to_internal_test (enum rtx_code);
 static rtx gen_int_relational (enum rtx_code, rtx, rtx, int *);
@@ -171,7 +158,6 @@ static rtx xtensa_legitimize_address (rtx, rtx, machine_mode);
 static bool xtensa_mode_dependent_address_p (const_rtx, addr_space_t);
 static bool xtensa_return_in_msb (const_tree);
 static void printx (FILE *, signed int);
-static void xtensa_function_epilogue (FILE *, HOST_WIDE_INT);
 static rtx xtensa_builtin_saveregs (void);
 static bool xtensa_legitimate_address_p (machine_mode, rtx, bool);
 static unsigned int xtensa_multibss_section_type_flags (tree, const char *,
@@ -224,17 +210,9 @@ static const char *xtensa_invalid_within_doloop (const rtx_insn *);
 static bool xtensa_member_type_forces_blk (const_tree,
                                           machine_mode mode);
 
-static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
-  REG_ALLOC_ORDER;
-\f
-
-/* 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.  */
+static void xtensa_conditional_register_usage (void);
 
-#undef TARGET_ASM_FUNCTION_EPILOGUE
-#define TARGET_ASM_FUNCTION_EPILOGUE xtensa_function_epilogue
+\f
 
 /* These hooks specify assembly directives for creating certain kinds
    of integer object.  */
@@ -355,6 +333,9 @@ static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
 #undef TARGET_INVALID_WITHIN_DOLOOP
 #define TARGET_INVALID_WITHIN_DOLOOP xtensa_invalid_within_doloop
 
+#undef TARGET_CONDITIONAL_REGISTER_USAGE
+#define TARGET_CONDITIONAL_REGISTER_USAGE xtensa_conditional_register_usage
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 \f
@@ -522,9 +503,10 @@ xtensa_valid_move (machine_mode mode, rtx *operands)
 
       /* The stack pointer can only be assigned with a MOVSP opcode.  */
       if (dst_regnum == STACK_POINTER_REGNUM)
-       return (mode == SImode
-               && register_operand (operands[1], mode)
-               && !ACC_REG_P (xt_true_regnum (operands[1])));
+       return !TARGET_WINDOWED_ABI
+         || (mode == SImode
+             && register_operand (operands[1], mode)
+             && !ACC_REG_P (xt_true_regnum (operands[1])));
 
       if (!ACC_REG_P (dst_regnum))
        return true;
@@ -1665,9 +1647,10 @@ xtensa_setup_frame_addresses (void)
   /* Set flag to cause TARGET_FRAME_POINTER_REQUIRED to return true.  */
   cfun->machine->accesses_prev_frame = 1;
 
-  emit_library_call
-    (gen_rtx_SYMBOL_REF (Pmode, "__xtensa_libgcc_window_spill"),
-     LCT_NORMAL, VOIDmode, 0);
+  if (TARGET_WINDOWED_ABI)
+    emit_library_call
+      (gen_rtx_SYMBOL_REF (Pmode, "__xtensa_libgcc_window_spill"),
+       LCT_NORMAL, VOIDmode, 0);
 }
 
 
@@ -1825,11 +1808,11 @@ xtensa_emit_call (int callop, rtx *operands)
   rtx tgt = operands[callop];
 
   if (GET_CODE (tgt) == CONST_INT)
-    sprintf (result, "call8\t0x%lx", INTVAL (tgt));
+    sprintf (result, "call%d\t0x%lx", WINDOW_SIZE, INTVAL (tgt));
   else if (register_operand (tgt, VOIDmode))
-    sprintf (result, "callx8\t%%%d", callop);
+    sprintf (result, "callx%d\t%%%d", WINDOW_SIZE, callop);
   else
-    sprintf (result, "call8\t%%%d", callop);
+    sprintf (result, "call%d\t%%%d", WINDOW_SIZE, callop);
 
   return result;
 }
@@ -2174,7 +2157,7 @@ xtensa_function_arg_1 (cumulative_args_t cum_v, machine_mode mode,
   regno = regbase + *arg_words;
 
   if (cum->incoming && regno <= A7_REG && regno + words > A7_REG)
-    cfun->machine->need_a7_copy = true;
+    cfun->machine->need_a7_copy = TARGET_WINDOWED_ABI;
 
   return gen_rtx_REG (mode, regno);
 }
@@ -2641,6 +2624,22 @@ xtensa_output_literal (FILE *file, rtx x, machine_mode mode, int labelno)
     }
 }
 
+static bool
+xtensa_call_save_reg(int regno)
+{
+  if (TARGET_WINDOWED_ABI)
+    return false;
+
+  if (regno == A0_REG)
+    return crtl->profile || !crtl->is_leaf || crtl->calls_eh_return ||
+      df_regs_ever_live_p (regno);
+
+  if (crtl->calls_eh_return && regno >= 2 && regno < 4)
+    return true;
+
+  return !fixed_regs[regno] && !call_used_regs[regno] &&
+    df_regs_ever_live_p (regno);
+}
 
 /* Return the bytes needed to compute the frame pointer from the current
    stack pointer.  */
@@ -2651,14 +2650,25 @@ xtensa_output_literal (FILE *file, rtx x, machine_mode mode, int labelno)
 long
 compute_frame_size (int size)
 {
+  int regno;
+
   /* Add space for the incoming static chain value.  */
   if (cfun->static_chain_decl != NULL)
     size += (1 * UNITS_PER_WORD);
 
+  xtensa_callee_save_size = 0;
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
+    {
+      if (xtensa_call_save_reg(regno))
+       xtensa_callee_save_size += UNITS_PER_WORD;
+    }
+
   xtensa_current_frame_size =
     XTENSA_STACK_ALIGN (size
+                       + xtensa_callee_save_size
                        + crtl->outgoing_args_size
                        + (WINDOW_SIZE * UNITS_PER_WORD));
+  xtensa_callee_save_size = XTENSA_STACK_ALIGN (xtensa_callee_save_size);
   return xtensa_current_frame_size;
 }
 
@@ -2686,23 +2696,103 @@ void
 xtensa_expand_prologue (void)
 {
   HOST_WIDE_INT total_size;
-  rtx size_rtx;
-  rtx_insn *insn;
+  rtx_insn *insn = NULL;
   rtx note_rtx;
 
+
   total_size = compute_frame_size (get_frame_size ());
-  size_rtx = GEN_INT (total_size);
 
-  if (total_size < (1 << (12+3)))
-    insn = emit_insn (gen_entry (size_rtx));
+  if (TARGET_WINDOWED_ABI)
+    {
+      if (total_size < (1 << (12+3)))
+       insn = emit_insn (gen_entry (GEN_INT (total_size)));
+      else
+       {
+         /* Use a8 as a temporary since a0-a7 may be live.  */
+         rtx tmp_reg = gen_rtx_REG (Pmode, A8_REG);
+         emit_insn (gen_entry (GEN_INT (MIN_FRAME_SIZE)));
+         emit_move_insn (tmp_reg, GEN_INT (total_size - MIN_FRAME_SIZE));
+         emit_insn (gen_subsi3 (tmp_reg, stack_pointer_rtx, tmp_reg));
+         insn = emit_insn (gen_movsi (stack_pointer_rtx, tmp_reg));
+       }
+    }
   else
     {
-      /* Use a8 as a temporary since a0-a7 may be live.  */
-      rtx tmp_reg = gen_rtx_REG (Pmode, A8_REG);
-      emit_insn (gen_entry (GEN_INT (MIN_FRAME_SIZE)));
-      emit_move_insn (tmp_reg, GEN_INT (total_size - MIN_FRAME_SIZE));
-      emit_insn (gen_subsi3 (tmp_reg, stack_pointer_rtx, tmp_reg));
-      insn = emit_insn (gen_movsi (stack_pointer_rtx, tmp_reg));
+      int regno;
+      HOST_WIDE_INT offset = 0;
+
+      /* -128 is a limit of single addi instruction. */
+      if (total_size > 0 && total_size <= 128)
+       {
+         insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+                                       GEN_INT (-total_size)));
+         RTX_FRAME_RELATED_P (insn) = 1;
+         note_rtx = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                                 plus_constant (Pmode, stack_pointer_rtx,
+                                                -total_size));
+         add_reg_note (insn, REG_FRAME_RELATED_EXPR, note_rtx);
+         offset = total_size - UNITS_PER_WORD;
+       }
+      else if (xtensa_callee_save_size)
+       {
+         /* 1020 is maximal s32i offset, if the frame is bigger than that
+          * we move sp to the end of callee-saved save area, save and then
+          * move it to its final location. */
+         if (total_size > 1024)
+           {
+             insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+                                           GEN_INT (-xtensa_callee_save_size)));
+             RTX_FRAME_RELATED_P (insn) = 1;
+             note_rtx = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                                     plus_constant (Pmode, stack_pointer_rtx,
+                                                    -xtensa_callee_save_size));
+             add_reg_note (insn, REG_FRAME_RELATED_EXPR, note_rtx);
+             offset = xtensa_callee_save_size - UNITS_PER_WORD;
+           }
+         else
+           {
+             rtx tmp_reg = gen_rtx_REG (Pmode, A9_REG);
+             emit_move_insn (tmp_reg, GEN_INT (total_size));
+             insn = emit_insn (gen_subsi3 (stack_pointer_rtx,
+                                           stack_pointer_rtx, tmp_reg));
+             RTX_FRAME_RELATED_P (insn) = 1;
+             note_rtx = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                                     plus_constant (Pmode, stack_pointer_rtx,
+                                                    -total_size));
+             add_reg_note (insn, REG_FRAME_RELATED_EXPR, note_rtx);
+             offset = total_size - UNITS_PER_WORD;
+           }
+       }
+
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
+       {
+         if (xtensa_call_save_reg(regno))
+           {
+             rtx x = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
+             rtx mem = gen_frame_mem (SImode, x);
+             rtx reg = gen_rtx_REG (SImode, regno);
+
+             offset -= UNITS_PER_WORD;
+             insn = emit_move_insn (mem, reg);
+             RTX_FRAME_RELATED_P (insn) = 1;
+             add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+                           gen_rtx_SET (VOIDmode, mem, reg));
+           }
+       }
+      if (total_size > 1024)
+       {
+         rtx tmp_reg = gen_rtx_REG (Pmode, A9_REG);
+         emit_move_insn (tmp_reg, GEN_INT (total_size -
+                                           xtensa_callee_save_size));
+         insn = emit_insn (gen_subsi3 (stack_pointer_rtx,
+                                       stack_pointer_rtx, tmp_reg));
+         RTX_FRAME_RELATED_P (insn) = 1;
+         note_rtx = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                                 plus_constant (Pmode, stack_pointer_rtx,
+                                                xtensa_callee_save_size -
+                                                total_size));
+         add_reg_note (insn, REG_FRAME_RELATED_EXPR, note_rtx);
+       }
     }
 
   if (frame_pointer_needed)
@@ -2731,38 +2821,147 @@ xtensa_expand_prologue (void)
            }
        }
       else
-       insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
-                                    stack_pointer_rtx));
-    }
-
-  /* Create a note to describe the CFA.  Because this is only used to set
-     DW_AT_frame_base for debug info, don't bother tracking changes through
-     each instruction in the prologue.  It just takes up space.  */
-  note_rtx = gen_rtx_SET (VOIDmode, (frame_pointer_needed
-                                    ? hard_frame_pointer_rtx
-                                    : stack_pointer_rtx),
-                         plus_constant (Pmode, stack_pointer_rtx,
-                                        -total_size));
-  RTX_FRAME_RELATED_P (insn) = 1;
-  add_reg_note (insn, REG_FRAME_RELATED_EXPR, note_rtx);
-}
-
+        {
+         insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
+                                      stack_pointer_rtx));
+         if (!TARGET_WINDOWED_ABI)
+           {
+             note_rtx = gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
+                                     stack_pointer_rtx);
+             RTX_FRAME_RELATED_P (insn) = 1;
+             add_reg_note (insn, REG_FRAME_RELATED_EXPR, note_rtx);
+           }
+       }
+    }
 
-/* Clear variables at function end.  */
+  if (TARGET_WINDOWED_ABI)
+    {
+      /* Create a note to describe the CFA.  Because this is only used to set
+        DW_AT_frame_base for debug info, don't bother tracking changes through
+        each instruction in the prologue.  It just takes up space.  */
+      note_rtx = gen_rtx_SET (VOIDmode, (frame_pointer_needed
+                                        ? hard_frame_pointer_rtx
+                                        : stack_pointer_rtx),
+                             plus_constant (Pmode, stack_pointer_rtx,
+                                            -total_size));
+      RTX_FRAME_RELATED_P (insn) = 1;
+      add_reg_note (insn, REG_FRAME_RELATED_EXPR, note_rtx);
+    }
+}
 
 void
-xtensa_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
-                         HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+xtensa_expand_epilogue (void)
 {
+  if (!TARGET_WINDOWED_ABI)
+    {
+      int regno;
+      HOST_WIDE_INT offset;
+
+      if (xtensa_current_frame_size > (frame_pointer_needed ? 127 : 1024))
+       {
+         rtx tmp_reg = gen_rtx_REG (Pmode, A9_REG);
+         emit_move_insn (tmp_reg, GEN_INT (xtensa_current_frame_size -
+                                           xtensa_callee_save_size));
+         emit_insn (gen_addsi3 (stack_pointer_rtx, frame_pointer_needed ?
+                                hard_frame_pointer_rtx : stack_pointer_rtx,
+                                tmp_reg));
+         offset = xtensa_callee_save_size - UNITS_PER_WORD;
+       }
+      else
+       {
+         if (frame_pointer_needed)
+           emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
+         offset = xtensa_current_frame_size - UNITS_PER_WORD;
+       }
+
+      /* Prevent reordering of saved a0 update and loading it back from
+        the save area.  */
+      if (crtl->calls_eh_return)
+       emit_insn (gen_blockage ());
+
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
+       {
+         if (xtensa_call_save_reg(regno))
+           {
+             rtx x = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
+
+             offset -= UNITS_PER_WORD;
+             emit_move_insn (gen_rtx_REG (SImode, regno),
+                             gen_frame_mem (SImode, x));
+           }
+       }
+
+      if (xtensa_current_frame_size > 0)
+       {
+         if (frame_pointer_needed || /* always reachable with addi */
+             xtensa_current_frame_size > 1024 ||
+             xtensa_current_frame_size <= 127)
+           {
+             if (xtensa_current_frame_size <= 127)
+               offset = xtensa_current_frame_size;
+             else
+               offset = xtensa_callee_save_size;
+
+             emit_insn (gen_addsi3 (stack_pointer_rtx,
+                                    stack_pointer_rtx,
+                                    GEN_INT (offset)));
+           }
+         else
+           {
+             rtx tmp_reg = gen_rtx_REG (Pmode, A9_REG);
+             emit_move_insn (tmp_reg, GEN_INT (xtensa_current_frame_size));
+             emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+                                    tmp_reg));
+           }
+       }
+
+      if (crtl->calls_eh_return)
+       emit_insn (gen_add3_insn (stack_pointer_rtx,
+                                 stack_pointer_rtx,
+                                 EH_RETURN_STACKADJ_RTX));
+    }
   xtensa_current_frame_size = 0;
+  xtensa_callee_save_size = 0;
+  emit_jump_insn (gen_return ());
 }
 
+void
+xtensa_set_return_address (rtx address, rtx scratch)
+{
+  HOST_WIDE_INT total_size = compute_frame_size (get_frame_size ());
+  rtx frame = frame_pointer_needed ?
+    hard_frame_pointer_rtx : stack_pointer_rtx;
+  rtx a0_addr = plus_constant (Pmode, frame,
+                              total_size - UNITS_PER_WORD);
+  rtx note = gen_rtx_SET (VOIDmode,
+                         gen_frame_mem (SImode, a0_addr),
+                         gen_rtx_REG (SImode, A0_REG));
+  rtx insn;
+
+  if (total_size > 1024) {
+    emit_move_insn (scratch, GEN_INT (total_size - UNITS_PER_WORD));
+    emit_insn (gen_addsi3 (scratch, frame, scratch));
+    a0_addr = scratch;
+  }
+
+  insn = emit_move_insn (gen_frame_mem (SImode, a0_addr), address);
+  RTX_FRAME_RELATED_P (insn) = 1;
+  add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
+}
 
 rtx
 xtensa_return_addr (int count, rtx frame)
 {
   rtx result, retaddr, curaddr, label;
 
+  if (!TARGET_WINDOWED_ABI)
+    {
+      if (count != 0)
+       return const0_rtx;
+
+      return get_hard_reg_initial_val (Pmode, A0_REG);
+    }
+
   if (count == -1)
     retaddr = gen_rtx_REG (Pmode, A0_REG);
   else
@@ -2879,14 +3078,14 @@ xtensa_builtin_saveregs (void)
   set_mem_alias_set (gp_regs, get_varargs_alias_set ());
 
   /* Now store the incoming registers.  */
-  cfun->machine->need_a7_copy = true;
+  cfun->machine->need_a7_copy = TARGET_WINDOWED_ABI;
   cfun->machine->vararg_a7 = true;
   move_block_from_reg (GP_ARG_FIRST + arg_words,
                       adjust_address (gp_regs, BLKmode,
                                       arg_words * UNITS_PER_WORD),
                       gp_left);
-  gcc_assert (cfun->machine->vararg_a7_copy != 0);
-  emit_insn_before (cfun->machine->vararg_a7_copy, get_insns ());
+  if (cfun->machine->vararg_a7_copy != 0)
+    emit_insn_before (cfun->machine->vararg_a7_copy, get_insns ());
 
   return XEXP (gp_regs, 0);
 }
@@ -3272,7 +3471,19 @@ order_regs_for_local_alloc (void)
 {
   if (!leaf_function_p ())
     {
-      memcpy (reg_alloc_order, reg_nonleaf_alloc_order,
+      static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
+       REG_ALLOC_ORDER;
+      static const int reg_nonleaf_alloc_order_call0[FIRST_PSEUDO_REGISTER] =
+       {
+         11, 10,  9,  8,  7,  6,  5,  4,  3,  2, 12, 13, 14, 15,
+         18,
+         19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+         0,  1, 16, 17,
+         35,
+       };
+
+      memcpy (reg_alloc_order, TARGET_WINDOWED_ABI ?
+             reg_nonleaf_alloc_order : reg_nonleaf_alloc_order_call0,
              FIRST_PSEUDO_REGISTER * sizeof (int));
     }
   else
@@ -3642,9 +3853,14 @@ xtensa_function_value_regno_p (const unsigned int regno)
 static rtx
 xtensa_static_chain (const_tree ARG_UNUSED (fndecl_or_type), bool incoming_p)
 {
-  rtx base = incoming_p ? arg_pointer_rtx : stack_pointer_rtx;
-  return gen_frame_mem (Pmode, plus_constant (Pmode, base,
-                                             -5 * UNITS_PER_WORD));
+  if (TARGET_WINDOWED_ABI)
+    {
+      rtx base = incoming_p ? arg_pointer_rtx : stack_pointer_rtx;
+      return gen_frame_mem (Pmode, plus_constant (Pmode, base,
+                                                 -5 * UNITS_PER_WORD));
+    }
+  else
+    return gen_rtx_REG (Pmode, A8_REG);
 }
 
 
@@ -3662,65 +3878,109 @@ xtensa_asm_trampoline_template (FILE *stream)
   bool use_call0 = (TARGET_CONST16 || TARGET_ABSOLUTE_LITERALS);
 
   fprintf (stream, "\t.begin no-transform\n");
-  fprintf (stream, "\tentry\tsp, %d\n", MIN_FRAME_SIZE);
 
-  if (use_call0)
+  if (TARGET_WINDOWED_ABI)
     {
-      /* Save the return address.  */
-      fprintf (stream, "\tmov\ta10, a0\n");
+      fprintf (stream, "\tentry\tsp, %d\n", MIN_FRAME_SIZE);
 
-      /* Use a CALL0 instruction to skip past the constants and in the
-        process get the PC into A0.  This allows PC-relative access to
-        the constants without relying on L32R.  */
-      fprintf (stream, "\tcall0\t.Lskipconsts\n");
-    }
-  else
-    fprintf (stream, "\tj\t.Lskipconsts\n");
+      if (use_call0)
+       {
+         /* Save the return address.  */
+         fprintf (stream, "\tmov\ta10, a0\n");
 
-  fprintf (stream, "\t.align\t4\n");
-  fprintf (stream, ".Lchainval:%s0\n", integer_asm_op (4, TRUE));
-  fprintf (stream, ".Lfnaddr:%s0\n", integer_asm_op (4, TRUE));
-  fprintf (stream, ".Lskipconsts:\n");
+         /* Use a CALL0 instruction to skip past the constants and in the
+            process get the PC into A0.  This allows PC-relative access to
+            the constants without relying on L32R.  */
+         fprintf (stream, "\tcall0\t.Lskipconsts\n");
+       }
+      else
+       fprintf (stream, "\tj\t.Lskipconsts\n");
 
-  /* Load the static chain and function address from the trampoline.  */
-  if (use_call0)
-    {
-      fprintf (stream, "\taddi\ta0, a0, 3\n");
-      fprintf (stream, "\tl32i\ta9, a0, 0\n");
-      fprintf (stream, "\tl32i\ta8, a0, 4\n");
+      fprintf (stream, "\t.align\t4\n");
+      fprintf (stream, ".Lchainval:%s0\n", integer_asm_op (4, TRUE));
+      fprintf (stream, ".Lfnaddr:%s0\n", integer_asm_op (4, TRUE));
+      fprintf (stream, ".Lskipconsts:\n");
+
+      /* Load the static chain and function address from the trampoline.  */
+      if (use_call0)
+       {
+         fprintf (stream, "\taddi\ta0, a0, 3\n");
+         fprintf (stream, "\tl32i\ta9, a0, 0\n");
+         fprintf (stream, "\tl32i\ta8, a0, 4\n");
+       }
+      else
+       {
+         fprintf (stream, "\tl32r\ta9, .Lchainval\n");
+         fprintf (stream, "\tl32r\ta8, .Lfnaddr\n");
+       }
+
+      /* Store the static chain.  */
+      fprintf (stream, "\ts32i\ta9, sp, %d\n", MIN_FRAME_SIZE - 20);
+
+      /* Set the proper stack pointer value.  */
+      fprintf (stream, "\tl32i\ta9, a8, 0\n");
+      fprintf (stream, "\textui\ta9, a9, %d, 12\n",
+              TARGET_BIG_ENDIAN ? 8 : 12);
+      fprintf (stream, "\tslli\ta9, a9, 3\n");
+      fprintf (stream, "\taddi\ta9, a9, %d\n", -MIN_FRAME_SIZE);
+      fprintf (stream, "\tsub\ta9, sp, a9\n");
+      fprintf (stream, "\tmovsp\tsp, a9\n");
+
+      if (use_call0)
+       /* Restore the return address.  */
+       fprintf (stream, "\tmov\ta0, a10\n");
+
+      /* Jump to the instruction following the ENTRY.  */
+      fprintf (stream, "\taddi\ta8, a8, 3\n");
+      fprintf (stream, "\tjx\ta8\n");
+
+      /* Pad size to a multiple of TRAMPOLINE_ALIGNMENT.  */
+      if (use_call0)
+       fprintf (stream, "\t.byte\t0\n");
+      else
+       fprintf (stream, "\tnop\n");
     }
   else
     {
-      fprintf (stream, "\tl32r\ta9, .Lchainval\n");
-      fprintf (stream, "\tl32r\ta8, .Lfnaddr\n");
-    }
-
-  /* Store the static chain.  */
-  fprintf (stream, "\ts32i\ta9, sp, %d\n", MIN_FRAME_SIZE - 20);
-
-  /* Set the proper stack pointer value.  */
-  fprintf (stream, "\tl32i\ta9, a8, 0\n");
-  fprintf (stream, "\textui\ta9, a9, %d, 12\n",
-          TARGET_BIG_ENDIAN ? 8 : 12);
-  fprintf (stream, "\tslli\ta9, a9, 3\n");
-  fprintf (stream, "\taddi\ta9, a9, %d\n", -MIN_FRAME_SIZE);
-  fprintf (stream, "\tsub\ta9, sp, a9\n");
-  fprintf (stream, "\tmovsp\tsp, a9\n");
+      if (use_call0)
+       {
+         /* Save the return address.  */
+         fprintf (stream, "\tmov\ta10, a0\n");
 
-  if (use_call0)
-    /* Restore the return address.  */
-    fprintf (stream, "\tmov\ta0, a10\n");
+         /* Use a CALL0 instruction to skip past the constants and in the
+            process get the PC into A0.  This allows PC-relative access to
+            the constants without relying on L32R.  */
+         fprintf (stream, "\tcall0\t.Lskipconsts\n");
+       }
+      else
+       fprintf (stream, "\tj\t.Lskipconsts\n");
 
-  /* Jump to the instruction following the ENTRY.  */
-  fprintf (stream, "\taddi\ta8, a8, 3\n");
-  fprintf (stream, "\tjx\ta8\n");
+      fprintf (stream, "\t.align\t4\n");
+      fprintf (stream, ".Lchainval:%s0\n", integer_asm_op (4, TRUE));
+      fprintf (stream, ".Lfnaddr:%s0\n", integer_asm_op (4, TRUE));
+      fprintf (stream, ".Lskipconsts:\n");
 
-  /* Pad size to a multiple of TRAMPOLINE_ALIGNMENT.  */
-  if (use_call0)
-    fprintf (stream, "\t.byte\t0\n");
-  else
-    fprintf (stream, "\tnop\n");
+      /* Load the static chain and function address from the trampoline.  */
+      if (use_call0)
+       {
+         fprintf (stream, "\taddi\ta0, a0, 3\n");
+         fprintf (stream, "\tl32i\ta8, a0, 0\n");
+         fprintf (stream, "\tl32i\ta9, a0, 4\n");
+         fprintf (stream, "\tmov\ta0, a10\n");
+       }
+      else
+       {
+         fprintf (stream, "\tl32r\ta8, .Lchainval\n");
+         fprintf (stream, "\tl32r\ta9, .Lfnaddr\n");
+       }
+      fprintf (stream, "\tjx\ta9\n");
 
+      /* Pad size to a multiple of TRAMPOLINE_ALIGNMENT.  */
+      if (use_call0)
+       fprintf (stream, "\t.byte\t0\n");
+      else
+       fprintf (stream, "\tnop\n");
+    }
   fprintf (stream, "\t.end no-transform\n");
 }
 
@@ -3729,8 +3989,19 @@ xtensa_trampoline_init (rtx m_tramp, tree fndecl, rtx chain)
 {
   rtx func = XEXP (DECL_RTL (fndecl), 0);
   bool use_call0 = (TARGET_CONST16 || TARGET_ABSOLUTE_LITERALS);
-  int chain_off = use_call0 ? 12 : 8;
-  int func_off = use_call0 ? 16 : 12;
+  int chain_off;
+  int func_off;
+
+  if (TARGET_WINDOWED_ABI)
+    {
+      chain_off = use_call0 ? 12 : 8;
+      func_off = use_call0 ? 16 : 12;
+    }
+  else
+    {
+      chain_off = use_call0 ? 8 : 4;
+      func_off = use_call0 ? 12 : 8;
+    }
 
   emit_block_move (m_tramp, assemble_trampoline_template (),
                   GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
@@ -3989,4 +4260,50 @@ xtensa_reorg (void)
   xtensa_reorg_loops ();
 }
 
+/* Update register usage after having seen the compiler flags.  */
+
+static void
+xtensa_conditional_register_usage (void)
+{
+  unsigned i, c_mask;
+
+  c_mask = TARGET_WINDOWED_ABI ? (1 << 1) : (1 << 2);
+
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      /* Set/reset conditionally defined registers from
+        CALL_USED_REGISTERS initializer.  */
+      if (call_used_regs[i] > 1)
+       call_used_regs[i] = !!(call_used_regs[i] & c_mask);
+    }
+
+  /* Remove hard FP register from the preferred reload registers set.  */
+  CLEAR_HARD_REG_BIT (reg_class_contents[(int)RL_REGS],
+                     HARD_FRAME_POINTER_REGNUM);
+}
+
+/* Map hard register number to register class */
+
+enum reg_class xtensa_regno_to_class (int regno)
+{
+  static const enum reg_class regno_to_class[FIRST_PSEUDO_REGISTER] =
+    {
+      RL_REGS, SP_REG,         RL_REGS,        RL_REGS,
+      RL_REGS, RL_REGS,        RL_REGS,        RL_REGS,
+      RL_REGS, RL_REGS,        RL_REGS,        RL_REGS,
+      RL_REGS, RL_REGS,        RL_REGS,        RL_REGS,
+      AR_REGS, AR_REGS,        BR_REGS,
+      FP_REGS, FP_REGS,        FP_REGS,        FP_REGS,
+      FP_REGS, FP_REGS,        FP_REGS,        FP_REGS,
+      FP_REGS, FP_REGS,        FP_REGS,        FP_REGS,
+      FP_REGS, FP_REGS,        FP_REGS,        FP_REGS,
+      ACC_REG,
+    };
+
+  if (regno == HARD_FRAME_POINTER_REGNUM)
+    return GR_REGS;
+  else
+    return regno_to_class[regno];
+}
+
 #include "gt-xtensa.h"
index 14fe4bb56ea42ee5919ed135acb86981d0f5f967..011411c09bf66fd6af232eb72605354b1d425b06 100644 (file)
@@ -66,6 +66,7 @@ extern unsigned xtensa_current_frame_size;
 #define TARGET_ABSOLUTE_LITERALS XSHAL_USE_ABSOLUTE_LITERALS
 #define TARGET_THREADPTR       XCHAL_HAVE_THREADPTR
 #define TARGET_LOOPS           XCHAL_HAVE_LOOPS
+#define TARGET_WINDOWED_ABI    (XSHAL_ABI == XTHAL_ABI_WINDOWED)
 
 #define TARGET_DEFAULT \
   ((XCHAL_HAVE_L32R    ? 0 : MASK_CONST16) |                           \
@@ -83,7 +84,8 @@ extern unsigned xtensa_current_frame_size;
     builtin_assert ("machine=xtensa");                                 \
     builtin_define ("__xtensa__");                                     \
     builtin_define ("__XTENSA__");                                     \
-    builtin_define ("__XTENSA_WINDOWED_ABI__");                                \
+    builtin_define (TARGET_WINDOWED_ABI ?                              \
+                   "__XTENSA_WINDOWED_ABI__" : "__XTENSA_CALL0_ABI__");\
     builtin_define (TARGET_BIG_ENDIAN ? "__XTENSA_EB__" : "__XTENSA_EL__"); \
     if (!TARGET_HARD_FLOAT)                                            \
       builtin_define ("__XTENSA_SOFT_FLOAT__");                                \
@@ -238,10 +240,18 @@ extern unsigned xtensa_current_frame_size;
    registers that can be used without being saved.
    The latter must include the registers where values are returned
    and the register where structure-value addresses are passed.
-   Aside from that, you can include as many other registers as you like.  */
+   Aside from that, you can include as many other registers as you like.
+
+   The value encoding is the following:
+   1: register is used by all ABIs;
+   bit 1 is set: register is used by windowed ABI;
+   bit 2 is set: register is used by call0 ABI.
+
+   Proper values are computed in TARGET_CONDITIONAL_REGISTER_USAGE.  */
+
 #define CALL_USED_REGISTERS                                            \
 {                                                                      \
-  1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,                      \
+  1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 2, 2, 2, 2,                      \
   1, 1, 1,                                                             \
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,                      \
   1,                                                                   \
@@ -341,7 +351,8 @@ extern char xtensa_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER];
 #define STACK_POINTER_REGNUM (GP_REG_FIRST + 1)
 
 /* Base register for access to local variables of the function.  */
-#define HARD_FRAME_POINTER_REGNUM (GP_REG_FIRST + 7)
+#define HARD_FRAME_POINTER_REGNUM (GP_REG_FIRST + \
+                                  (TARGET_WINDOWED_ABI ? 7 : 15))
 
 /* The register number of the frame pointer register, which is used to
    access automatic variables in the stack frame.  For Xtensa, this
@@ -366,14 +377,16 @@ extern char xtensa_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER];
    we use a fixed window size of 8.  */
 
 #define INCOMING_REGNO(OUT)                                            \
-  ((GP_REG_P (OUT) &&                                                  \
-    ((unsigned) ((OUT) - GP_REG_FIRST) >= WINDOW_SIZE)) ?              \
-   (OUT) - WINDOW_SIZE : (OUT))
+  (TARGET_WINDOWED_ABI ?                                               \
+   ((GP_REG_P (OUT) &&                                                 \
+     ((unsigned) ((OUT) - GP_REG_FIRST) >= WINDOW_SIZE)) ?             \
+    (OUT) - WINDOW_SIZE : (OUT)) : (OUT))
 
 #define OUTGOING_REGNO(IN)                                             \
-  ((GP_REG_P (IN) &&                                                   \
-    ((unsigned) ((IN) - GP_REG_FIRST) < WINDOW_SIZE)) ?                        \
-   (IN) + WINDOW_SIZE : (IN))
+  (TARGET_WINDOWED_ABI ?                                               \
+   ((GP_REG_P (IN) &&                                                  \
+     ((unsigned) ((IN) - GP_REG_FIRST) < WINDOW_SIZE)) ?               \
+    (IN) + WINDOW_SIZE : (IN)) : (IN))
 
 
 /* Define the classes of registers for register constraints in the
@@ -422,7 +435,7 @@ enum reg_class
   { 0xfff80000, 0x00000007 }, /* floating-point registers */ \
   { 0x00000000, 0x00000008 }, /* MAC16 accumulator */ \
   { 0x00000002, 0x00000000 }, /* stack pointer register */ \
-  { 0x0000ff7d, 0x00000000 }, /* preferred reload registers */ \
+  { 0x0000fffd, 0x00000000 }, /* preferred reload registers */ \
   { 0x0000fffd, 0x00000000 }, /* general-purpose registers */ \
   { 0x0003ffff, 0x00000000 }, /* integer registers */ \
   { 0xffffffff, 0x0000000f }  /* all registers */ \
@@ -432,9 +445,7 @@ enum reg_class
    register REGNO.  In general there is more that one such class;
    choose a class which is "minimal", meaning that no smaller class
    also contains the register.  */
-extern const enum reg_class xtensa_regno_to_class[FIRST_PSEUDO_REGISTER];
-
-#define REGNO_REG_CLASS(REGNO) xtensa_regno_to_class[ (REGNO) ]
+#define REGNO_REG_CLASS(REGNO) xtensa_regno_to_class (REGNO)
 
 /* Use the Xtensa AR register file for base registers.
    No index registers.  */
@@ -497,7 +508,7 @@ extern const enum reg_class xtensa_regno_to_class[FIRST_PSEUDO_REGISTER];
 #define STACK_BOUNDARY 128
 
 /* Use a fixed register window size of 8.  */
-#define WINDOW_SIZE 8
+#define WINDOW_SIZE (TARGET_WINDOWED_ABI ? 8 : 0)
 
 /* Symbolic macros for the registers used to return integer, floating
    point, and values of coprocessor and user-defined modes.  */
@@ -561,11 +572,11 @@ typedef struct xtensa_args
     fprintf (FILE, "\t%s\ta10, a0\n", TARGET_DENSITY ? "mov.n" : "mov"); \
     if (flag_pic)                                                      \
       {                                                                        \
-       fprintf (FILE, "\tmovi\ta8, _mcount@PLT\n");                    \
-       fprintf (FILE, "\tcallx8\ta8\n");                               \
+       fprintf (FILE, "\tmovi\ta%d, _mcount@PLT\n", WINDOW_SIZE);      \
+       fprintf (FILE, "\tcallx%d\ta%d\n", WINDOW_SIZE, WINDOW_SIZE);   \
       }                                                                        \
     else                                                               \
-      fprintf (FILE, "\tcall8\t_mcount\n");                            \
+      fprintf (FILE, "\tcall%d\t_mcount\n", WINDOW_SIZE);              \
   } while (0)
 
 /* Stack pointer value doesn't matter at exit.  */
@@ -573,7 +584,11 @@ typedef struct xtensa_args
 
 /* Size in bytes of the trampoline, as an integer.  Make sure this is
    a multiple of TRAMPOLINE_ALIGNMENT to avoid -Wpadded warnings.  */
-#define TRAMPOLINE_SIZE (TARGET_CONST16 || TARGET_ABSOLUTE_LITERALS ? 60 : 52)
+#define TRAMPOLINE_SIZE (TARGET_WINDOWED_ABI ? \
+                        (TARGET_CONST16 || TARGET_ABSOLUTE_LITERALS ? \
+                         60 : 52) : \
+                        (TARGET_CONST16 || TARGET_ABSOLUTE_LITERALS ? \
+                         32 : 24))
 
 /* Alignment required for trampolines, in bits.  */
 #define TRAMPOLINE_ALIGNMENT 32
@@ -615,7 +630,7 @@ typedef struct xtensa_args
 
 /* Define this if the return address of a particular stack frame is
    accessed from the frame pointer of the previous stack frame.  */
-#define RETURN_ADDR_IN_PREVIOUS_FRAME 1
+#define RETURN_ADDR_IN_PREVIOUS_FRAME TARGET_WINDOWED_ABI
 
 /* A C expression whose value is RTL representing the value of the
    return address for the frame COUNT steps up from the current
@@ -770,7 +785,7 @@ typedef struct xtensa_args
 /* Define output to appear before the constant pool.  */
 #define ASM_OUTPUT_POOL_PROLOGUE(FILE, FUNNAME, FUNDECL, SIZE)          \
   do {                                                                 \
-    if ((SIZE) > 0)                                                    \
+    if ((SIZE) > 0 || !TARGET_WINDOWED_ABI)                            \
       {                                                                        \
        resolve_unique_section ((FUNDECL), 0, flag_function_sections);  \
        switch_to_section (function_section (FUNDECL));                 \
@@ -805,6 +820,8 @@ typedef struct xtensa_args
       | DW_EH_PE_pcrel | DW_EH_PE_sdata4)                              \
    : DW_EH_PE_absptr)
 
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, GP_REG_FIRST + 10)
+
 /* Emit a PC-relative relocation.  */
 #define ASM_OUTPUT_DWARF_PCREL(FILE, SIZE, LABEL)                      \
   do {                                                                 \
@@ -818,8 +835,16 @@ typedef struct xtensa_args
    a MOVI and let the assembler relax it -- for the .init and .fini
    sections, the assembler knows to put the literal in the right
    place.  */
+#if defined(__XTENSA_WINDOWED_ABI__)
 #define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \
     asm (SECTION_OP "\n\
        movi\ta8, " USER_LABEL_PREFIX #FUNC "\n\
        callx8\ta8\n" \
        TEXT_SECTION_ASM_OP);
+#elif defined(__XTENSA_CALL0_ABI__)
+#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \
+    asm (SECTION_OP "\n\
+       movi\ta0, " USER_LABEL_PREFIX #FUNC "\n\
+       callx0\ta0\n" \
+       TEXT_SECTION_ASM_OP);
+#endif
index ccaa2b2f560ad3831b66d2ff4a31f38e3c575282..6d84384c950266a65be15786b4ba7bd9c7d73b65 100644 (file)
@@ -24,6 +24,7 @@
   (A1_REG              1)
   (A7_REG              7)
   (A8_REG              8)
+  (A9_REG              9)
 
   (UNSPEC_NOP          2)
   (UNSPEC_PLT          3)
@@ -44,6 +45,7 @@
   (UNSPECV_S32C1I      5)
   (UNSPECV_EH_RETURN   6)
   (UNSPECV_SET_TP      7)
+  (UNSPECV_BLOCKAGE    8)
 ])
 
 ;; This code iterator allows signed and unsigned widening multiplications
 (define_insn "return"
   [(return)
    (use (reg:SI A0_REG))]
-  "reload_completed"
+  "(TARGET_WINDOWED_ABI || !xtensa_current_frame_size) && reload_completed"
 {
-  return (TARGET_DENSITY ? "retw.n" : "retw");
+  return TARGET_WINDOWED_ABI ?
+      (TARGET_DENSITY ? "retw.n" : "retw") :
+      (TARGET_DENSITY ? "ret.n" : "ret");
 }
   [(set_attr "type"    "jump")
    (set_attr "mode"    "none")
   [(return)]
   ""
 {
-  emit_jump_insn (gen_return ());
+  xtensa_expand_epilogue ();
   DONE;
 })
 
    (match_operand:SI 1 "general_operand" "")
    (match_operand:SI 2 "general_operand" "")
    (match_operand:SI 3 "" "")]
-  ""
+  "TARGET_WINDOWED_ABI"
 {
   xtensa_expand_nonlocal_goto (operands);
   DONE;
 ;; already been applied to the handler, but the generic version doesn't
 ;; allow us to frob it quite enough, so we just frob here.
 
-(define_insn_and_split "eh_return"
+(define_expand "eh_return"
+  [(use (match_operand 0 "general_operand"))]
+  ""
+{
+  if (TARGET_WINDOWED_ABI)
+    emit_insn (gen_eh_set_a0_windowed (operands[0]));
+  else
+    emit_insn (gen_eh_set_a0_call0 (operands[0]));
+  DONE;
+})
+
+(define_insn_and_split "eh_set_a0_windowed"
   [(set (reg:SI A0_REG)
        (unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
                            UNSPECV_EH_RETURN))
    (set (reg:SI A0_REG) (rotatert:SI (match_dup 1) (const_int 2)))]
   "")
 
+(define_insn_and_split "eh_set_a0_call0"
+  [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")]
+                   UNSPECV_EH_RETURN)
+   (clobber (match_scratch:SI 1 "=r"))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  xtensa_set_return_address (operands[0], operands[1]);
+  DONE;
+})
+
+;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
+;; all of memory.  This blocks insns from being moved across this point.
+
+(define_insn "blockage"
+  [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
+  ""
+  ""
+  [(set_attr "length" "0")
+   (set_attr "type" "nop")])
+
 ;; Setting up a frame pointer is tricky for Xtensa because GCC doesn't
 ;; know if a frame pointer is required until the reload pass, and
 ;; because there may be an incoming argument value in the hard frame
index 35e8f858f9b940861ef9f0b29983c4241432ab53..49eee7a24a43fe3cb88a156875468ce5fc92dc30 100644 (file)
@@ -1,3 +1,16 @@
+2015-03-03  Max Filippov  <jcmvbkbc@gmail.com>
+       
+       Implement call0 ABI for xtensa
+       * config/xtensa/lib2funcs.S (__xtensa_libgcc_window_spill,
+       __xtensa_nonlocal_goto): Don't compile for call0 ABI.
+       (__xtensa_sync_caches): Only use entry and retw in windowed ABI,
+       use ret in call0 ABI.
+       * config/xtensa/t-windowed: New file.
+       * libgcc/config/xtensa/t-xtensa (LIB2ADDEH): Move to t-windowed.
+       * libgcc/configure: Regenerated.
+       * libgcc/configure.ac: Check if xtensa target is configured for
+       windowed ABI and thus needs to use custom unwind code.
+
 2015-02-12  Jonathan Wakely  <jwakely@redhat.com>
 
        PR libgcc/64885
index 1014a19732af145e5c0687c16bdbddbc550f7d8c..4d451c8c71c8952e54baa0107a77252e5a18ac4a 100644 (file)
@@ -29,6 +29,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    current register window.  This is used to set up the stack so that
    arbitrary frames can be accessed.  */
 
+#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
        .align  4
        .global __xtensa_libgcc_window_spill
        .type   __xtensa_libgcc_window_spill,@function
@@ -38,6 +39,7 @@ __xtensa_libgcc_window_spill:
        syscall
        retw
        .size   __xtensa_libgcc_window_spill, .-__xtensa_libgcc_window_spill
+#endif
 
 
 /* __xtensa_nonlocal_goto: This code does all the hard work of a
@@ -51,6 +53,7 @@ __xtensa_libgcc_window_spill:
   This function never returns to its caller but instead goes directly
   to the address of the specified goto handler.  */
 
+#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
        .align  4
        .global __xtensa_nonlocal_goto
        .type   __xtensa_nonlocal_goto,@function
@@ -128,6 +131,7 @@ __xtensa_nonlocal_goto:
 
        retw
        .size   __xtensa_nonlocal_goto, .-__xtensa_nonlocal_goto
+#endif
 
 
 /* __xtensa_sync_caches: This function is called after writing a trampoline
@@ -154,7 +158,9 @@ __xtensa_nonlocal_goto:
        .global __xtensa_sync_caches
        .type   __xtensa_sync_caches,@function
 __xtensa_sync_caches:
+#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
        entry   sp, 32
+#endif
 #if XCHAL_DCACHE_SIZE > 0
        /* Flush the trampoline from the data cache.  */
        extui   a4, a2, 0, XCHAL_DCACHE_LINEWIDTH
@@ -182,5 +188,9 @@ __xtensa_sync_caches:
        bnez    a4, .Licache_loop
 #endif
        isync
+#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
        retw
+#else
+       ret
+#endif
        .size   __xtensa_sync_caches, .-__xtensa_sync_caches
index eed3be5cdce547e7c37f154b1893645b51fcf41c..9daf738ff57a96dde0d2e64dcf8909901e2f2088 100644 (file)
@@ -52,6 +52,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define ENTRY_BYTE 0x36
 #endif
 
+#ifdef __XTENSA_WINDOWED_ABI__
 #define MD_FALLBACK_FRAME_STATE_FOR xtensa_fallback_frame_state
 
 static _Unwind_Reason_Code
@@ -94,4 +95,6 @@ xtensa_fallback_frame_state (struct _Unwind_Context *context,
   return _URC_NO_REASON;
 }
 
+#endif /* __XTENSA_WINDOWED_ABI__ */
+
 #endif /* ifdef inhibit_libc  */
diff --git a/libgcc/config/xtensa/t-windowed b/libgcc/config/xtensa/t-windowed
new file mode 100644 (file)
index 0000000..7d9e9db
--- /dev/null
@@ -0,0 +1,2 @@
+LIB2ADDEH = $(srcdir)/config/xtensa/unwind-dw2-xtensa.c \
+   $(srcdir)/unwind-dw2-fde.c $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
index 27399e67fa0d632b58a53d85d8564e802c2db597..ed3eb84a71b884183599352c9d3449c835b2faf6 100644 (file)
@@ -11,6 +11,3 @@ LIB1ASMFUNCS = _mulsi3 _divsi3 _modsi3 _udivsi3 _umodsi3 \
        _truncdfsf2 _extendsfdf2
 
 LIB2ADD = $(srcdir)/config/xtensa/lib2funcs.S
-
-LIB2ADDEH = $(srcdir)/config/xtensa/unwind-dw2-xtensa.c \
-   $(srcdir)/unwind-dw2-fde.c $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
index a88259da325b2f9a559ee69d32cf80ca61761af5..9d567f9d48c4ad0db74c0066d2ef2ac8f2f392fb 100644 (file)
@@ -4810,6 +4810,27 @@ EOF
   ;;
 esac
 
+# Check if xtensa target is configured for windowed ABI and thus needs to use
+# custom unwind code.
+# This is after config.host so we can augment tmake_file.
+case ${host} in
+xtensa*-*)
+  cat > conftest.c <<EOF
+       #ifdef __XTENSA_CALL0_ABI__
+       #error
+       #endif
+EOF
+  if { ac_try='${CC-cc} -E -o conftest.i conftest.c 1>&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+      tmake_file="${tmake_file} xtensa/t-windowed"
+  fi
+  ;;
+esac
+
 # Check for visibility support.  This is after config.host so that
 # we can check for asm_hidden_op.
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((visibility(\"hidden\")))" >&5
index 5edcbde69ddcc7d1b28dca46107c4df684a498a6..1c405e8dfe5a298967dc74fafd8dae43e83a6f11 100644 (file)
@@ -436,6 +436,22 @@ EOF
   ;;
 esac
 
+# Check if xtensa target is configured for windowed ABI and thus needs to use
+# custom unwind code.
+# This is after config.host so we can augment tmake_file.
+case ${host} in
+xtensa*-*)
+  cat > conftest.c <<EOF
+       #ifdef __XTENSA_CALL0_ABI__
+       #error
+       #endif
+EOF
+  if AC_TRY_COMMAND(${CC-cc} -E -o conftest.i conftest.c 1>&AS_MESSAGE_LOG_FD); then
+      tmake_file="${tmake_file} xtensa/t-windowed"
+  fi
+  ;;
+esac
+
 # Check for visibility support.  This is after config.host so that
 # we can check for asm_hidden_op.
 AC_CACHE_CHECK([for __attribute__((visibility("hidden")))],