diff --git a/gcc/config/xtensa/constraints.md b/gcc/config/xtensa/constraints.md
index 74aca6c..30f4c1f 100644
--- a/gcc/config/xtensa/constraints.md
+++ b/gcc/config/xtensa/constraints.md
@@ -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.")
diff --git a/gcc/config/xtensa/xtensa-protos.h b/gcc/config/xtensa/xtensa-protos.h
index ad95db0..6a53625 100644
--- a/gcc/config/xtensa/xtensa-protos.h
+++ b/gcc/config/xtensa/xtensa-protos.h
@@ -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__ */
diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c
index 6c289e5..eb039ba 100644
--- a/gcc/config/xtensa/xtensa.c
+++ b/gcc/config/xtensa/xtensa.c
@@ -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;
-
-
-/* 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
+
 
 /* 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;
 
 
@@ -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"
diff --git a/gcc/config/xtensa/xtensa.h b/gcc/config/xtensa/xtensa.h
index 14fe4bb..011411c 100644
--- a/gcc/config/xtensa/xtensa.h
+++ b/gcc/config/xtensa/xtensa.h
@@ -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
diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md
index ccaa2b2..6d84384 100644
--- a/gcc/config/xtensa/xtensa.md
+++ b/gcc/config/xtensa/xtensa.md
@@ -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
@@ -1658,9 +1660,11 @@
 (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")
@@ -1681,7 +1685,7 @@
   [(return)]
   ""
 {
-  emit_jump_insn (gen_return ());
+  xtensa_expand_epilogue ();
   DONE;
 })
 
@@ -1700,7 +1704,7 @@
    (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;
@@ -1713,7 +1717,18 @@
 ;; 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))
@@ -1726,6 +1741,29 @@
    (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
diff --git a/libgcc/config/xtensa/lib2funcs.S b/libgcc/config/xtensa/lib2funcs.S
index 1014a19..4d451c8 100644
--- a/libgcc/config/xtensa/lib2funcs.S
+++ b/libgcc/config/xtensa/lib2funcs.S
@@ -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
diff --git a/libgcc/config/xtensa/linux-unwind.h b/libgcc/config/xtensa/linux-unwind.h
index eed3be5..9daf738 100644
--- a/libgcc/config/xtensa/linux-unwind.h
+++ b/libgcc/config/xtensa/linux-unwind.h
@@ -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
index 0000000..7d9e9db
--- /dev/null
+++ b/libgcc/config/xtensa/t-windowed
@@ -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
diff --git a/libgcc/config/xtensa/t-xtensa b/libgcc/config/xtensa/t-xtensa
index 27399e6..ed3eb84 100644
--- a/libgcc/config/xtensa/t-xtensa
+++ b/libgcc/config/xtensa/t-xtensa
@@ -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
diff --git a/libgcc/configure b/libgcc/configure
index a88259d..9d567f9 100644
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -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
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 5edcbde..1c405e8 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -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")))],
