Commit 590e2636 by Max Filippov Committed by Max Filippov

Implement call0 ABI for xtensa

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
parent d76b082e
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> 2015-03-03 Martin Liska <mliska@suse.cz>
PR ipa/65287 PR ipa/65287
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
;; Register constraints. ;; 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}, "General-purpose AR registers @code{a0}-@code{a15},
except @code{a1} (@code{sp}).") except @code{a1} (@code{sp}).")
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
"Floating-point registers @code{f0}-@code{f15}; only available if the "Floating-point registers @code{f0}-@code{f15}; only available if the
Xtensa Floating-Pointer Coprocessor is configured.") Xtensa Floating-Pointer Coprocessor is configured.")
(define_register_constraint "q" "SP_REG" (define_register_constraint "q" "TARGET_WINDOWED_ABI ? SP_REG : NO_REGS"
"@internal "@internal
The stack pointer (register @code{a1}).") The stack pointer (register @code{a1}).")
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
General-purpose AR registers, but only if the Xtensa 16-Bit Integer General-purpose AR registers, but only if the Xtensa 16-Bit Integer
Multiply Option is configured.") 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 "@internal
General-purpose AR registers, but only if the Xtensa Code Density General-purpose AR registers, but only if the Xtensa Code Density
Option is configured.") Option is configured.")
......
...@@ -61,6 +61,7 @@ extern void init_cumulative_args (CUMULATIVE_ARGS *, int); ...@@ -61,6 +61,7 @@ extern void init_cumulative_args (CUMULATIVE_ARGS *, int);
extern void print_operand (FILE *, rtx, int); extern void print_operand (FILE *, rtx, int);
extern void print_operand_address (FILE *, rtx); extern void print_operand_address (FILE *, rtx);
extern void xtensa_output_literal (FILE *, rtx, machine_mode, int); 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); extern rtx xtensa_return_addr (int, rtx);
#endif /* RTX_CODE */ #endif /* RTX_CODE */
...@@ -68,6 +69,8 @@ extern void xtensa_setup_frame_addresses (void); ...@@ -68,6 +69,8 @@ extern void xtensa_setup_frame_addresses (void);
extern int xtensa_dbx_register_number (int); extern int xtensa_dbx_register_number (int);
extern long compute_frame_size (int); extern long compute_frame_size (int);
extern void xtensa_expand_prologue (void); extern void xtensa_expand_prologue (void);
extern void xtensa_expand_epilogue (void);
extern void order_regs_for_local_alloc (void); extern void order_regs_for_local_alloc (void);
extern enum reg_class xtensa_regno_to_class (int regno);
#endif /* !__XTENSA_PROTOS_H__ */ #endif /* !__XTENSA_PROTOS_H__ */
...@@ -118,6 +118,8 @@ char xtensa_hard_regno_mode_ok[(int) MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER]; ...@@ -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. */ /* Current frame size calculated by compute_frame_size. */
unsigned xtensa_current_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. */ /* Largest block move to handle in-line. */
#define LARGEST_MOVE_RATIO 15 #define LARGEST_MOVE_RATIO 15
...@@ -144,21 +146,6 @@ const char xtensa_leaf_regs[FIRST_PSEUDO_REGISTER] = ...@@ -144,21 +146,6 @@ const char xtensa_leaf_regs[FIRST_PSEUDO_REGISTER] =
1 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 void xtensa_option_override (void);
static enum internal_test map_test_to_internal_test (enum rtx_code); static enum internal_test map_test_to_internal_test (enum rtx_code);
static rtx gen_int_relational (enum rtx_code, rtx, rtx, int *); static rtx gen_int_relational (enum rtx_code, rtx, rtx, int *);
...@@ -171,7 +158,6 @@ static rtx xtensa_legitimize_address (rtx, rtx, machine_mode); ...@@ -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_mode_dependent_address_p (const_rtx, addr_space_t);
static bool xtensa_return_in_msb (const_tree); static bool xtensa_return_in_msb (const_tree);
static void printx (FILE *, signed int); static void printx (FILE *, signed int);
static void xtensa_function_epilogue (FILE *, HOST_WIDE_INT);
static rtx xtensa_builtin_saveregs (void); static rtx xtensa_builtin_saveregs (void);
static bool xtensa_legitimate_address_p (machine_mode, rtx, bool); static bool xtensa_legitimate_address_p (machine_mode, rtx, bool);
static unsigned int xtensa_multibss_section_type_flags (tree, const char *, 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 *); ...@@ -224,17 +210,9 @@ static const char *xtensa_invalid_within_doloop (const rtx_insn *);
static bool xtensa_member_type_forces_blk (const_tree, static bool xtensa_member_type_forces_blk (const_tree,
machine_mode mode); machine_mode mode);
static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] = static void xtensa_conditional_register_usage (void);
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. */
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE xtensa_function_epilogue
/* These hooks specify assembly directives for creating certain kinds /* These hooks specify assembly directives for creating certain kinds
of integer object. */ of integer object. */
...@@ -355,6 +333,9 @@ static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] = ...@@ -355,6 +333,9 @@ static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
#undef TARGET_INVALID_WITHIN_DOLOOP #undef TARGET_INVALID_WITHIN_DOLOOP
#define TARGET_INVALID_WITHIN_DOLOOP xtensa_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; struct gcc_target targetm = TARGET_INITIALIZER;
...@@ -522,9 +503,10 @@ xtensa_valid_move (machine_mode mode, rtx *operands) ...@@ -522,9 +503,10 @@ xtensa_valid_move (machine_mode mode, rtx *operands)
/* The stack pointer can only be assigned with a MOVSP opcode. */ /* The stack pointer can only be assigned with a MOVSP opcode. */
if (dst_regnum == STACK_POINTER_REGNUM) if (dst_regnum == STACK_POINTER_REGNUM)
return (mode == SImode return !TARGET_WINDOWED_ABI
&& register_operand (operands[1], mode) || (mode == SImode
&& !ACC_REG_P (xt_true_regnum (operands[1]))); && register_operand (operands[1], mode)
&& !ACC_REG_P (xt_true_regnum (operands[1])));
if (!ACC_REG_P (dst_regnum)) if (!ACC_REG_P (dst_regnum))
return true; return true;
...@@ -1665,9 +1647,10 @@ xtensa_setup_frame_addresses (void) ...@@ -1665,9 +1647,10 @@ xtensa_setup_frame_addresses (void)
/* Set flag to cause TARGET_FRAME_POINTER_REQUIRED to return true. */ /* Set flag to cause TARGET_FRAME_POINTER_REQUIRED to return true. */
cfun->machine->accesses_prev_frame = 1; cfun->machine->accesses_prev_frame = 1;
emit_library_call if (TARGET_WINDOWED_ABI)
(gen_rtx_SYMBOL_REF (Pmode, "__xtensa_libgcc_window_spill"), emit_library_call
LCT_NORMAL, VOIDmode, 0); (gen_rtx_SYMBOL_REF (Pmode, "__xtensa_libgcc_window_spill"),
LCT_NORMAL, VOIDmode, 0);
} }
...@@ -1825,11 +1808,11 @@ xtensa_emit_call (int callop, rtx *operands) ...@@ -1825,11 +1808,11 @@ xtensa_emit_call (int callop, rtx *operands)
rtx tgt = operands[callop]; rtx tgt = operands[callop];
if (GET_CODE (tgt) == CONST_INT) 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)) else if (register_operand (tgt, VOIDmode))
sprintf (result, "callx8\t%%%d", callop); sprintf (result, "callx%d\t%%%d", WINDOW_SIZE, callop);
else else
sprintf (result, "call8\t%%%d", callop); sprintf (result, "call%d\t%%%d", WINDOW_SIZE, callop);
return result; return result;
} }
...@@ -2174,7 +2157,7 @@ xtensa_function_arg_1 (cumulative_args_t cum_v, machine_mode mode, ...@@ -2174,7 +2157,7 @@ xtensa_function_arg_1 (cumulative_args_t cum_v, machine_mode mode,
regno = regbase + *arg_words; regno = regbase + *arg_words;
if (cum->incoming && regno <= A7_REG && regno + words > A7_REG) 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); return gen_rtx_REG (mode, regno);
} }
...@@ -2641,6 +2624,22 @@ xtensa_output_literal (FILE *file, rtx x, machine_mode mode, int labelno) ...@@ -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 /* Return the bytes needed to compute the frame pointer from the current
stack pointer. */ stack pointer. */
...@@ -2651,14 +2650,25 @@ xtensa_output_literal (FILE *file, rtx x, machine_mode mode, int labelno) ...@@ -2651,14 +2650,25 @@ xtensa_output_literal (FILE *file, rtx x, machine_mode mode, int labelno)
long long
compute_frame_size (int size) compute_frame_size (int size)
{ {
int regno;
/* Add space for the incoming static chain value. */ /* Add space for the incoming static chain value. */
if (cfun->static_chain_decl != NULL) if (cfun->static_chain_decl != NULL)
size += (1 * UNITS_PER_WORD); 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_current_frame_size =
XTENSA_STACK_ALIGN (size XTENSA_STACK_ALIGN (size
+ xtensa_callee_save_size
+ crtl->outgoing_args_size + crtl->outgoing_args_size
+ (WINDOW_SIZE * UNITS_PER_WORD)); + (WINDOW_SIZE * UNITS_PER_WORD));
xtensa_callee_save_size = XTENSA_STACK_ALIGN (xtensa_callee_save_size);
return xtensa_current_frame_size; return xtensa_current_frame_size;
} }
...@@ -2686,23 +2696,103 @@ void ...@@ -2686,23 +2696,103 @@ void
xtensa_expand_prologue (void) xtensa_expand_prologue (void)
{ {
HOST_WIDE_INT total_size; HOST_WIDE_INT total_size;
rtx size_rtx; rtx_insn *insn = NULL;
rtx_insn *insn;
rtx note_rtx; rtx note_rtx;
total_size = compute_frame_size (get_frame_size ()); total_size = compute_frame_size (get_frame_size ());
size_rtx = GEN_INT (total_size);
if (total_size < (1 << (12+3))) if (TARGET_WINDOWED_ABI)
insn = emit_insn (gen_entry (size_rtx)); {
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 else
{ {
/* Use a8 as a temporary since a0-a7 may be live. */ int regno;
rtx tmp_reg = gen_rtx_REG (Pmode, A8_REG); HOST_WIDE_INT offset = 0;
emit_insn (gen_entry (GEN_INT (MIN_FRAME_SIZE)));
emit_move_insn (tmp_reg, GEN_INT (total_size - MIN_FRAME_SIZE)); /* -128 is a limit of single addi instruction. */
emit_insn (gen_subsi3 (tmp_reg, stack_pointer_rtx, tmp_reg)); if (total_size > 0 && total_size <= 128)
insn = emit_insn (gen_movsi (stack_pointer_rtx, tmp_reg)); {
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) if (frame_pointer_needed)
...@@ -2731,38 +2821,147 @@ xtensa_expand_prologue (void) ...@@ -2731,38 +2821,147 @@ xtensa_expand_prologue (void)
} }
} }
else else
insn = emit_insn (gen_movsi (hard_frame_pointer_rtx, {
stack_pointer_rtx)); insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
} stack_pointer_rtx));
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 note_rtx = gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
each instruction in the prologue. It just takes up space. */ stack_pointer_rtx);
note_rtx = gen_rtx_SET (VOIDmode, (frame_pointer_needed RTX_FRAME_RELATED_P (insn) = 1;
? hard_frame_pointer_rtx add_reg_note (insn, REG_FRAME_RELATED_EXPR, note_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);
}
/* 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 void
xtensa_function_epilogue (FILE *file ATTRIBUTE_UNUSED, xtensa_expand_epilogue (void)
HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{ {
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_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 rtx
xtensa_return_addr (int count, rtx frame) xtensa_return_addr (int count, rtx frame)
{ {
rtx result, retaddr, curaddr, label; 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) if (count == -1)
retaddr = gen_rtx_REG (Pmode, A0_REG); retaddr = gen_rtx_REG (Pmode, A0_REG);
else else
...@@ -2879,14 +3078,14 @@ xtensa_builtin_saveregs (void) ...@@ -2879,14 +3078,14 @@ xtensa_builtin_saveregs (void)
set_mem_alias_set (gp_regs, get_varargs_alias_set ()); set_mem_alias_set (gp_regs, get_varargs_alias_set ());
/* Now store the incoming registers. */ /* Now store the incoming registers. */
cfun->machine->need_a7_copy = true; cfun->machine->need_a7_copy = TARGET_WINDOWED_ABI;
cfun->machine->vararg_a7 = true; cfun->machine->vararg_a7 = true;
move_block_from_reg (GP_ARG_FIRST + arg_words, move_block_from_reg (GP_ARG_FIRST + arg_words,
adjust_address (gp_regs, BLKmode, adjust_address (gp_regs, BLKmode,
arg_words * UNITS_PER_WORD), arg_words * UNITS_PER_WORD),
gp_left); gp_left);
gcc_assert (cfun->machine->vararg_a7_copy != 0); if (cfun->machine->vararg_a7_copy != 0)
emit_insn_before (cfun->machine->vararg_a7_copy, get_insns ()); emit_insn_before (cfun->machine->vararg_a7_copy, get_insns ());
return XEXP (gp_regs, 0); return XEXP (gp_regs, 0);
} }
...@@ -3272,7 +3471,19 @@ order_regs_for_local_alloc (void) ...@@ -3272,7 +3471,19 @@ order_regs_for_local_alloc (void)
{ {
if (!leaf_function_p ()) 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)); FIRST_PSEUDO_REGISTER * sizeof (int));
} }
else else
...@@ -3642,9 +3853,14 @@ xtensa_function_value_regno_p (const unsigned int regno) ...@@ -3642,9 +3853,14 @@ xtensa_function_value_regno_p (const unsigned int regno)
static rtx static rtx
xtensa_static_chain (const_tree ARG_UNUSED (fndecl_or_type), bool incoming_p) xtensa_static_chain (const_tree ARG_UNUSED (fndecl_or_type), bool incoming_p)
{ {
rtx base = incoming_p ? arg_pointer_rtx : stack_pointer_rtx; if (TARGET_WINDOWED_ABI)
return gen_frame_mem (Pmode, plus_constant (Pmode, base, {
-5 * UNITS_PER_WORD)); 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) ...@@ -3662,65 +3878,109 @@ xtensa_asm_trampoline_template (FILE *stream)
bool use_call0 = (TARGET_CONST16 || TARGET_ABSOLUTE_LITERALS); bool use_call0 = (TARGET_CONST16 || TARGET_ABSOLUTE_LITERALS);
fprintf (stream, "\t.begin no-transform\n"); 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, "\tentry\tsp, %d\n", MIN_FRAME_SIZE);
fprintf (stream, "\tmov\ta10, a0\n");
/* Use a CALL0 instruction to skip past the constants and in the if (use_call0)
process get the PC into A0. This allows PC-relative access to {
the constants without relying on L32R. */ /* Save the return address. */
fprintf (stream, "\tcall0\t.Lskipconsts\n"); fprintf (stream, "\tmov\ta10, a0\n");
}
else
fprintf (stream, "\tj\t.Lskipconsts\n");
fprintf (stream, "\t.align\t4\n"); /* Use a CALL0 instruction to skip past the constants and in the
fprintf (stream, ".Lchainval:%s0\n", integer_asm_op (4, TRUE)); process get the PC into A0. This allows PC-relative access to
fprintf (stream, ".Lfnaddr:%s0\n", integer_asm_op (4, TRUE)); the constants without relying on L32R. */
fprintf (stream, ".Lskipconsts:\n"); fprintf (stream, "\tcall0\t.Lskipconsts\n");
}
else
fprintf (stream, "\tj\t.Lskipconsts\n");
/* Load the static chain and function address from the trampoline. */ fprintf (stream, "\t.align\t4\n");
if (use_call0) fprintf (stream, ".Lchainval:%s0\n", integer_asm_op (4, TRUE));
{ fprintf (stream, ".Lfnaddr:%s0\n", integer_asm_op (4, TRUE));
fprintf (stream, "\taddi\ta0, a0, 3\n"); fprintf (stream, ".Lskipconsts:\n");
fprintf (stream, "\tl32i\ta9, a0, 0\n");
fprintf (stream, "\tl32i\ta8, a0, 4\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 else
{ {
fprintf (stream, "\tl32r\ta9, .Lchainval\n"); if (use_call0)
fprintf (stream, "\tl32r\ta8, .Lfnaddr\n"); {
} /* Save the return address. */
fprintf (stream, "\tmov\ta10, a0\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) /* Use a CALL0 instruction to skip past the constants and in the
/* Restore the return address. */ process get the PC into A0. This allows PC-relative access to
fprintf (stream, "\tmov\ta0, a10\n"); 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, "\t.align\t4\n");
fprintf (stream, "\taddi\ta8, a8, 3\n"); fprintf (stream, ".Lchainval:%s0\n", integer_asm_op (4, TRUE));
fprintf (stream, "\tjx\ta8\n"); fprintf (stream, ".Lfnaddr:%s0\n", integer_asm_op (4, TRUE));
fprintf (stream, ".Lskipconsts:\n");
/* Pad size to a multiple of TRAMPOLINE_ALIGNMENT. */ /* Load the static chain and function address from the trampoline. */
if (use_call0) if (use_call0)
fprintf (stream, "\t.byte\t0\n"); {
else fprintf (stream, "\taddi\ta0, a0, 3\n");
fprintf (stream, "\tnop\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"); fprintf (stream, "\t.end no-transform\n");
} }
...@@ -3729,8 +3989,19 @@ xtensa_trampoline_init (rtx m_tramp, tree fndecl, rtx chain) ...@@ -3729,8 +3989,19 @@ xtensa_trampoline_init (rtx m_tramp, tree fndecl, rtx chain)
{ {
rtx func = XEXP (DECL_RTL (fndecl), 0); rtx func = XEXP (DECL_RTL (fndecl), 0);
bool use_call0 = (TARGET_CONST16 || TARGET_ABSOLUTE_LITERALS); bool use_call0 = (TARGET_CONST16 || TARGET_ABSOLUTE_LITERALS);
int chain_off = use_call0 ? 12 : 8; int chain_off;
int func_off = use_call0 ? 16 : 12; 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 (), emit_block_move (m_tramp, assemble_trampoline_template (),
GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
...@@ -3989,4 +4260,50 @@ xtensa_reorg (void) ...@@ -3989,4 +4260,50 @@ xtensa_reorg (void)
xtensa_reorg_loops (); 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" #include "gt-xtensa.h"
...@@ -66,6 +66,7 @@ extern unsigned xtensa_current_frame_size; ...@@ -66,6 +66,7 @@ extern unsigned xtensa_current_frame_size;
#define TARGET_ABSOLUTE_LITERALS XSHAL_USE_ABSOLUTE_LITERALS #define TARGET_ABSOLUTE_LITERALS XSHAL_USE_ABSOLUTE_LITERALS
#define TARGET_THREADPTR XCHAL_HAVE_THREADPTR #define TARGET_THREADPTR XCHAL_HAVE_THREADPTR
#define TARGET_LOOPS XCHAL_HAVE_LOOPS #define TARGET_LOOPS XCHAL_HAVE_LOOPS
#define TARGET_WINDOWED_ABI (XSHAL_ABI == XTHAL_ABI_WINDOWED)
#define TARGET_DEFAULT \ #define TARGET_DEFAULT \
((XCHAL_HAVE_L32R ? 0 : MASK_CONST16) | \ ((XCHAL_HAVE_L32R ? 0 : MASK_CONST16) | \
...@@ -83,7 +84,8 @@ extern unsigned xtensa_current_frame_size; ...@@ -83,7 +84,8 @@ extern unsigned xtensa_current_frame_size;
builtin_assert ("machine=xtensa"); \ builtin_assert ("machine=xtensa"); \
builtin_define ("__xtensa__"); \ builtin_define ("__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__"); \ builtin_define (TARGET_BIG_ENDIAN ? "__XTENSA_EB__" : "__XTENSA_EL__"); \
if (!TARGET_HARD_FLOAT) \ if (!TARGET_HARD_FLOAT) \
builtin_define ("__XTENSA_SOFT_FLOAT__"); \ builtin_define ("__XTENSA_SOFT_FLOAT__"); \
...@@ -238,10 +240,18 @@ extern unsigned xtensa_current_frame_size; ...@@ -238,10 +240,18 @@ extern unsigned xtensa_current_frame_size;
registers that can be used without being saved. registers that can be used without being saved.
The latter must include the registers where values are returned The latter must include the registers where values are returned
and the register where structure-value addresses are passed. 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 \ #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, 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]; ...@@ -341,7 +351,8 @@ extern char xtensa_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER];
#define STACK_POINTER_REGNUM (GP_REG_FIRST + 1) #define STACK_POINTER_REGNUM (GP_REG_FIRST + 1)
/* Base register for access to local variables of the function. */ /* 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 /* The register number of the frame pointer register, which is used to
access automatic variables in the stack frame. For Xtensa, this access automatic variables in the stack frame. For Xtensa, this
...@@ -366,14 +377,16 @@ extern char xtensa_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER]; ...@@ -366,14 +377,16 @@ extern char xtensa_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER];
we use a fixed window size of 8. */ we use a fixed window size of 8. */
#define INCOMING_REGNO(OUT) \ #define INCOMING_REGNO(OUT) \
((GP_REG_P (OUT) && \ (TARGET_WINDOWED_ABI ? \
((unsigned) ((OUT) - GP_REG_FIRST) >= WINDOW_SIZE)) ? \ ((GP_REG_P (OUT) && \
(OUT) - WINDOW_SIZE : (OUT)) ((unsigned) ((OUT) - GP_REG_FIRST) >= WINDOW_SIZE)) ? \
(OUT) - WINDOW_SIZE : (OUT)) : (OUT))
#define OUTGOING_REGNO(IN) \ #define OUTGOING_REGNO(IN) \
((GP_REG_P (IN) && \ (TARGET_WINDOWED_ABI ? \
((unsigned) ((IN) - GP_REG_FIRST) < WINDOW_SIZE)) ? \ ((GP_REG_P (IN) && \
(IN) + WINDOW_SIZE : (IN)) ((unsigned) ((IN) - GP_REG_FIRST) < WINDOW_SIZE)) ? \
(IN) + WINDOW_SIZE : (IN)) : (IN))
/* Define the classes of registers for register constraints in the /* Define the classes of registers for register constraints in the
...@@ -422,7 +435,7 @@ enum reg_class ...@@ -422,7 +435,7 @@ enum reg_class
{ 0xfff80000, 0x00000007 }, /* floating-point registers */ \ { 0xfff80000, 0x00000007 }, /* floating-point registers */ \
{ 0x00000000, 0x00000008 }, /* MAC16 accumulator */ \ { 0x00000000, 0x00000008 }, /* MAC16 accumulator */ \
{ 0x00000002, 0x00000000 }, /* stack pointer register */ \ { 0x00000002, 0x00000000 }, /* stack pointer register */ \
{ 0x0000ff7d, 0x00000000 }, /* preferred reload registers */ \ { 0x0000fffd, 0x00000000 }, /* preferred reload registers */ \
{ 0x0000fffd, 0x00000000 }, /* general-purpose registers */ \ { 0x0000fffd, 0x00000000 }, /* general-purpose registers */ \
{ 0x0003ffff, 0x00000000 }, /* integer registers */ \ { 0x0003ffff, 0x00000000 }, /* integer registers */ \
{ 0xffffffff, 0x0000000f } /* all registers */ \ { 0xffffffff, 0x0000000f } /* all registers */ \
...@@ -432,9 +445,7 @@ enum reg_class ...@@ -432,9 +445,7 @@ enum reg_class
register REGNO. In general there is more that one such class; register REGNO. In general there is more that one such class;
choose a class which is "minimal", meaning that no smaller class choose a class which is "minimal", meaning that no smaller class
also contains the register. */ 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. /* Use the Xtensa AR register file for base registers.
No index registers. */ No index registers. */
...@@ -497,7 +508,7 @@ extern const enum reg_class xtensa_regno_to_class[FIRST_PSEUDO_REGISTER]; ...@@ -497,7 +508,7 @@ extern const enum reg_class xtensa_regno_to_class[FIRST_PSEUDO_REGISTER];
#define STACK_BOUNDARY 128 #define STACK_BOUNDARY 128
/* Use a fixed register window size of 8. */ /* 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 /* Symbolic macros for the registers used to return integer, floating
point, and values of coprocessor and user-defined modes. */ point, and values of coprocessor and user-defined modes. */
...@@ -561,11 +572,11 @@ typedef struct xtensa_args ...@@ -561,11 +572,11 @@ typedef struct xtensa_args
fprintf (FILE, "\t%s\ta10, a0\n", TARGET_DENSITY ? "mov.n" : "mov"); \ fprintf (FILE, "\t%s\ta10, a0\n", TARGET_DENSITY ? "mov.n" : "mov"); \
if (flag_pic) \ if (flag_pic) \
{ \ { \
fprintf (FILE, "\tmovi\ta8, _mcount@PLT\n"); \ fprintf (FILE, "\tmovi\ta%d, _mcount@PLT\n", WINDOW_SIZE); \
fprintf (FILE, "\tcallx8\ta8\n"); \ fprintf (FILE, "\tcallx%d\ta%d\n", WINDOW_SIZE, WINDOW_SIZE); \
} \ } \
else \ else \
fprintf (FILE, "\tcall8\t_mcount\n"); \ fprintf (FILE, "\tcall%d\t_mcount\n", WINDOW_SIZE); \
} while (0) } while (0)
/* Stack pointer value doesn't matter at exit. */ /* Stack pointer value doesn't matter at exit. */
...@@ -573,7 +584,11 @@ typedef struct xtensa_args ...@@ -573,7 +584,11 @@ typedef struct xtensa_args
/* Size in bytes of the trampoline, as an integer. Make sure this is /* Size in bytes of the trampoline, as an integer. Make sure this is
a multiple of TRAMPOLINE_ALIGNMENT to avoid -Wpadded warnings. */ 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. */ /* Alignment required for trampolines, in bits. */
#define TRAMPOLINE_ALIGNMENT 32 #define TRAMPOLINE_ALIGNMENT 32
...@@ -615,7 +630,7 @@ typedef struct xtensa_args ...@@ -615,7 +630,7 @@ typedef struct xtensa_args
/* Define this if the return address of a particular stack frame is /* Define this if the return address of a particular stack frame is
accessed from the frame pointer of the previous stack frame. */ 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 /* A C expression whose value is RTL representing the value of the
return address for the frame COUNT steps up from the current return address for the frame COUNT steps up from the current
...@@ -770,7 +785,7 @@ typedef struct xtensa_args ...@@ -770,7 +785,7 @@ typedef struct xtensa_args
/* Define output to appear before the constant pool. */ /* Define output to appear before the constant pool. */
#define ASM_OUTPUT_POOL_PROLOGUE(FILE, FUNNAME, FUNDECL, SIZE) \ #define ASM_OUTPUT_POOL_PROLOGUE(FILE, FUNNAME, FUNDECL, SIZE) \
do { \ do { \
if ((SIZE) > 0) \ if ((SIZE) > 0 || !TARGET_WINDOWED_ABI) \
{ \ { \
resolve_unique_section ((FUNDECL), 0, flag_function_sections); \ resolve_unique_section ((FUNDECL), 0, flag_function_sections); \
switch_to_section (function_section (FUNDECL)); \ switch_to_section (function_section (FUNDECL)); \
...@@ -805,6 +820,8 @@ typedef struct xtensa_args ...@@ -805,6 +820,8 @@ typedef struct xtensa_args
| DW_EH_PE_pcrel | DW_EH_PE_sdata4) \ | DW_EH_PE_pcrel | DW_EH_PE_sdata4) \
: DW_EH_PE_absptr) : DW_EH_PE_absptr)
#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, GP_REG_FIRST + 10)
/* Emit a PC-relative relocation. */ /* Emit a PC-relative relocation. */
#define ASM_OUTPUT_DWARF_PCREL(FILE, SIZE, LABEL) \ #define ASM_OUTPUT_DWARF_PCREL(FILE, SIZE, LABEL) \
do { \ do { \
...@@ -818,8 +835,16 @@ typedef struct xtensa_args ...@@ -818,8 +835,16 @@ typedef struct xtensa_args
a MOVI and let the assembler relax it -- for the .init and .fini a MOVI and let the assembler relax it -- for the .init and .fini
sections, the assembler knows to put the literal in the right sections, the assembler knows to put the literal in the right
place. */ place. */
#if defined(__XTENSA_WINDOWED_ABI__)
#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \ #define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \
asm (SECTION_OP "\n\ asm (SECTION_OP "\n\
movi\ta8, " USER_LABEL_PREFIX #FUNC "\n\ movi\ta8, " USER_LABEL_PREFIX #FUNC "\n\
callx8\ta8\n" \ callx8\ta8\n" \
TEXT_SECTION_ASM_OP); 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
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
(A1_REG 1) (A1_REG 1)
(A7_REG 7) (A7_REG 7)
(A8_REG 8) (A8_REG 8)
(A9_REG 9)
(UNSPEC_NOP 2) (UNSPEC_NOP 2)
(UNSPEC_PLT 3) (UNSPEC_PLT 3)
...@@ -44,6 +45,7 @@ ...@@ -44,6 +45,7 @@
(UNSPECV_S32C1I 5) (UNSPECV_S32C1I 5)
(UNSPECV_EH_RETURN 6) (UNSPECV_EH_RETURN 6)
(UNSPECV_SET_TP 7) (UNSPECV_SET_TP 7)
(UNSPECV_BLOCKAGE 8)
]) ])
;; This code iterator allows signed and unsigned widening multiplications ;; This code iterator allows signed and unsigned widening multiplications
...@@ -1658,9 +1660,11 @@ ...@@ -1658,9 +1660,11 @@
(define_insn "return" (define_insn "return"
[(return) [(return)
(use (reg:SI A0_REG))] (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 "type" "jump")
(set_attr "mode" "none") (set_attr "mode" "none")
...@@ -1681,7 +1685,7 @@ ...@@ -1681,7 +1685,7 @@
[(return)] [(return)]
"" ""
{ {
emit_jump_insn (gen_return ()); xtensa_expand_epilogue ();
DONE; DONE;
}) })
...@@ -1700,7 +1704,7 @@ ...@@ -1700,7 +1704,7 @@
(match_operand:SI 1 "general_operand" "") (match_operand:SI 1 "general_operand" "")
(match_operand:SI 2 "general_operand" "") (match_operand:SI 2 "general_operand" "")
(match_operand:SI 3 "" "")] (match_operand:SI 3 "" "")]
"" "TARGET_WINDOWED_ABI"
{ {
xtensa_expand_nonlocal_goto (operands); xtensa_expand_nonlocal_goto (operands);
DONE; DONE;
...@@ -1713,7 +1717,18 @@ ...@@ -1713,7 +1717,18 @@
;; already been applied to the handler, but the generic version doesn't ;; already been applied to the handler, but the generic version doesn't
;; allow us to frob it quite enough, so we just frob here. ;; 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) [(set (reg:SI A0_REG)
(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] (unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
UNSPECV_EH_RETURN)) UNSPECV_EH_RETURN))
...@@ -1726,6 +1741,29 @@ ...@@ -1726,6 +1741,29 @@
(set (reg:SI A0_REG) (rotatert:SI (match_dup 1) (const_int 2)))] (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 ;; 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 ;; know if a frame pointer is required until the reload pass, and
;; because there may be an incoming argument value in the hard frame ;; because there may be an incoming argument value in the hard frame
......
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> 2015-02-12 Jonathan Wakely <jwakely@redhat.com>
PR libgcc/64885 PR libgcc/64885
......
...@@ -29,6 +29,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see ...@@ -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 current register window. This is used to set up the stack so that
arbitrary frames can be accessed. */ arbitrary frames can be accessed. */
#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
.align 4 .align 4
.global __xtensa_libgcc_window_spill .global __xtensa_libgcc_window_spill
.type __xtensa_libgcc_window_spill,@function .type __xtensa_libgcc_window_spill,@function
...@@ -38,6 +39,7 @@ __xtensa_libgcc_window_spill: ...@@ -38,6 +39,7 @@ __xtensa_libgcc_window_spill:
syscall syscall
retw retw
.size __xtensa_libgcc_window_spill, .-__xtensa_libgcc_window_spill .size __xtensa_libgcc_window_spill, .-__xtensa_libgcc_window_spill
#endif
/* __xtensa_nonlocal_goto: This code does all the hard work of a /* __xtensa_nonlocal_goto: This code does all the hard work of a
...@@ -51,6 +53,7 @@ __xtensa_libgcc_window_spill: ...@@ -51,6 +53,7 @@ __xtensa_libgcc_window_spill:
This function never returns to its caller but instead goes directly This function never returns to its caller but instead goes directly
to the address of the specified goto handler. */ to the address of the specified goto handler. */
#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
.align 4 .align 4
.global __xtensa_nonlocal_goto .global __xtensa_nonlocal_goto
.type __xtensa_nonlocal_goto,@function .type __xtensa_nonlocal_goto,@function
...@@ -128,6 +131,7 @@ __xtensa_nonlocal_goto: ...@@ -128,6 +131,7 @@ __xtensa_nonlocal_goto:
retw retw
.size __xtensa_nonlocal_goto, .-__xtensa_nonlocal_goto .size __xtensa_nonlocal_goto, .-__xtensa_nonlocal_goto
#endif
/* __xtensa_sync_caches: This function is called after writing a trampoline /* __xtensa_sync_caches: This function is called after writing a trampoline
...@@ -154,7 +158,9 @@ __xtensa_nonlocal_goto: ...@@ -154,7 +158,9 @@ __xtensa_nonlocal_goto:
.global __xtensa_sync_caches .global __xtensa_sync_caches
.type __xtensa_sync_caches,@function .type __xtensa_sync_caches,@function
__xtensa_sync_caches: __xtensa_sync_caches:
#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
entry sp, 32 entry sp, 32
#endif
#if XCHAL_DCACHE_SIZE > 0 #if XCHAL_DCACHE_SIZE > 0
/* Flush the trampoline from the data cache. */ /* Flush the trampoline from the data cache. */
extui a4, a2, 0, XCHAL_DCACHE_LINEWIDTH extui a4, a2, 0, XCHAL_DCACHE_LINEWIDTH
...@@ -182,5 +188,9 @@ __xtensa_sync_caches: ...@@ -182,5 +188,9 @@ __xtensa_sync_caches:
bnez a4, .Licache_loop bnez a4, .Licache_loop
#endif #endif
isync isync
#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
retw retw
#else
ret
#endif
.size __xtensa_sync_caches, .-__xtensa_sync_caches .size __xtensa_sync_caches, .-__xtensa_sync_caches
...@@ -52,6 +52,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see ...@@ -52,6 +52,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define ENTRY_BYTE 0x36 #define ENTRY_BYTE 0x36
#endif #endif
#ifdef __XTENSA_WINDOWED_ABI__
#define MD_FALLBACK_FRAME_STATE_FOR xtensa_fallback_frame_state #define MD_FALLBACK_FRAME_STATE_FOR xtensa_fallback_frame_state
static _Unwind_Reason_Code static _Unwind_Reason_Code
...@@ -94,4 +95,6 @@ xtensa_fallback_frame_state (struct _Unwind_Context *context, ...@@ -94,4 +95,6 @@ xtensa_fallback_frame_state (struct _Unwind_Context *context,
return _URC_NO_REASON; return _URC_NO_REASON;
} }
#endif /* __XTENSA_WINDOWED_ABI__ */
#endif /* ifdef inhibit_libc */ #endif /* ifdef inhibit_libc */
LIB2ADDEH = $(srcdir)/config/xtensa/unwind-dw2-xtensa.c \
$(srcdir)/unwind-dw2-fde.c $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
...@@ -11,6 +11,3 @@ LIB1ASMFUNCS = _mulsi3 _divsi3 _modsi3 _udivsi3 _umodsi3 \ ...@@ -11,6 +11,3 @@ LIB1ASMFUNCS = _mulsi3 _divsi3 _modsi3 _udivsi3 _umodsi3 \
_truncdfsf2 _extendsfdf2 _truncdfsf2 _extendsfdf2
LIB2ADD = $(srcdir)/config/xtensa/lib2funcs.S 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
...@@ -4810,6 +4810,27 @@ EOF ...@@ -4810,6 +4810,27 @@ EOF
;; ;;
esac 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 # Check for visibility support. This is after config.host so that
# we can check for asm_hidden_op. # we can check for asm_hidden_op.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((visibility(\"hidden\")))" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((visibility(\"hidden\")))" >&5
......
...@@ -436,6 +436,22 @@ EOF ...@@ -436,6 +436,22 @@ EOF
;; ;;
esac 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 # Check for visibility support. This is after config.host so that
# we can check for asm_hidden_op. # we can check for asm_hidden_op.
AC_CACHE_CHECK([for __attribute__((visibility("hidden")))], AC_CACHE_CHECK([for __attribute__((visibility("hidden")))],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment