mirror of git://gcc.gnu.org/git/gcc.git
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
This commit is contained in:
parent
d76b082e8a
commit
590e26360c
|
|
@ -1,3 +1,83 @@
|
||||||
|
2015-03-03 Max Filippov <jcmvbkbc@gmail.com>
|
||||||
|
|
||||||
|
Implement call0 ABI for xtensa
|
||||||
|
* config/xtensa/constraints.md ("a" constraint): Include stack
|
||||||
|
pointer in case of call0 ABI.
|
||||||
|
("q" constraint): Make empty in case of call0 ABI.
|
||||||
|
("D" constraint): Include stack pointer in case of call0 ABI.
|
||||||
|
* config/xtensa/xtensa-protos.h (xtensa_set_return_address,
|
||||||
|
xtensa_expand_epilogue, xtensa_regno_to_class): Add new function
|
||||||
|
prototypes.
|
||||||
|
* config/xtensa/xtensa.c (xtensa_callee_save_size): New
|
||||||
|
variable.
|
||||||
|
(xtensa_regno_to_class): Make it a local variable in the
|
||||||
|
function xtensa_regno_to_class.
|
||||||
|
(xtensa_function_epilogue, TARGET_ASM_FUNCTION_EPILOGUE): Remove
|
||||||
|
macro, function prototype and implementation.
|
||||||
|
(reg_nonleaf_alloc_order): Make it a local variable in the
|
||||||
|
function order_regs_for_local_alloc.
|
||||||
|
(xtensa_conditional_register_usage): New function.
|
||||||
|
(TARGET_CONDITIONAL_REGISTER_USAGE): Define macro.
|
||||||
|
(xtensa_valid_move): Allow direct moves to stack pointer
|
||||||
|
register in call0 ABI.
|
||||||
|
(xtensa_setup_frame_addresses): Only spill register windows in
|
||||||
|
windowed ABI.
|
||||||
|
(xtensa_emit_call): Emit call(x)8 or call(x)0 in windowed and
|
||||||
|
call0 ABI respectively.
|
||||||
|
(xtensa_function_arg_1): Only mark a7 register for copying in
|
||||||
|
windowed ABI.
|
||||||
|
(xtensa_call_save_reg): New function.
|
||||||
|
(compute_frame_size): Add space for callee saved register
|
||||||
|
storage to the frame size in call0 ABI.
|
||||||
|
(xtensa_expand_prologue): Generate code to set up stack frame
|
||||||
|
and save callee-saved registers in call0 ABI.
|
||||||
|
(xtensa_expand_epilogue): New function.
|
||||||
|
(xtensa_set_return_address): New function.
|
||||||
|
(xtensa_return_addr): Calculate return address in call0 ABI.
|
||||||
|
(xtensa_builtin_saveregs): Only mark a7 register for copying and
|
||||||
|
emit copying code in windowed ABI.
|
||||||
|
(order_regs_for_local_alloc): Add preferred register allocation
|
||||||
|
order for non-leaf function in call0 ABI.
|
||||||
|
(xtensa_static_chain): Add atatic chain passing for call0 ABI.
|
||||||
|
(xtensa_asm_trampoline_template): Add trampoline generation for
|
||||||
|
call0 ABI.
|
||||||
|
(xtensa_trampoline_init): Add trampoline initialization for
|
||||||
|
call0 ABI.
|
||||||
|
(xtensa_conditional_register_usage, xtensa_regno_to_class): New
|
||||||
|
functions.
|
||||||
|
* config/xtensa/xtensa.h (TARGET_WINDOWED_ABI): New macro.
|
||||||
|
(TARGET_CPU_CPP_BUILTINS): Add built-in define for call0 ABI.
|
||||||
|
(CALL_USED_REGISTERS): Modify to encode both windowed and call0
|
||||||
|
ABI call-used registers.
|
||||||
|
(HARD_FRAME_POINTER_REGNUM): Add frame pointer for call0 ABI.
|
||||||
|
(INCOMING_REGNO, OUTGOING_REGNO): Use argument unchanged in
|
||||||
|
call0 ABI.
|
||||||
|
(REG_CLASS_CONTENTS): Include all registers into the preferred
|
||||||
|
reload registers set, adjust the set in the
|
||||||
|
xtensa_conditional_register_usage.
|
||||||
|
(xtensa_regno_to_class): Drop variable declaration.
|
||||||
|
(REGNO_REG_CLASS): Redefine to use xtensa_regno_to_class
|
||||||
|
function.
|
||||||
|
(WINDOW_SIZE): Define as 8 or 0 for windowed and call0 ABI
|
||||||
|
respectively.
|
||||||
|
(FUNCTION_PROFILER): Add _mcount call for call0 ABI.
|
||||||
|
(TRAMPOLINE_SIZE): Define trampoline size for call0 ABI.
|
||||||
|
(RETURN_ADDR_IN_PREVIOUS_FRAME): Define to 0 in call0 ABI.
|
||||||
|
(ASM_OUTPUT_POOL_PROLOGUE): Always generate literal pool
|
||||||
|
location in call0 ABI.
|
||||||
|
(EH_RETURN_STACKADJ_RTX): New definition, use a10 for passing
|
||||||
|
stack adjustment size when handling exception.
|
||||||
|
(CRT_CALL_STATIC_FUNCTION): Add definition for call0 ABI.
|
||||||
|
* config/xtensa/xtensa.md (A9_REG, UNSPECV_BLOCKAGE): New
|
||||||
|
definitions.
|
||||||
|
("return" pattern): Generate ret.n/ret in call0 ABI.
|
||||||
|
("epilogue" pattern): Expand epilogue.
|
||||||
|
("nonlocal_goto" pattern): Use default in call0 ABI.
|
||||||
|
("eh_return" pattern): Move implementation to eh_set_a0_windowed,
|
||||||
|
emit eh_set_a0_* depending on ABI.
|
||||||
|
("eh_set_a0_windowed" pattern): Former eh_return pattern.
|
||||||
|
("eh_set_a0_call0", "blockage"): New patterns.
|
||||||
|
|
||||||
2015-03-03 Martin Liska <mliska@suse.cz>
|
2015-03-03 Martin Liska <mliska@suse.cz>
|
||||||
|
|
||||||
PR ipa/65287
|
PR ipa/65287
|
||||||
|
|
|
||||||
|
|
@ -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 @@
|
||||||
"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 @@
|
||||||
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);
|
||||||
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);
|
||||||
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];
|
||||||
|
|
||||||
/* 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] =
|
||||||
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);
|
||||||
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,18 +210,10 @@ 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] =
|
||||||
#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)
|
||||||
|
|
||||||
/* 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)
|
||||||
/* 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)
|
||||||
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,
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
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
|
||||||
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 ());
|
|
||||||
size_rtx = GEN_INT (total_size);
|
|
||||||
|
|
||||||
if (total_size < (1 << (12+3)))
|
total_size = compute_frame_size (get_frame_size ());
|
||||||
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
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a note to describe the CFA. Because this is only used to set
|
if (TARGET_WINDOWED_ABI)
|
||||||
DW_AT_frame_base for debug info, don't bother tracking changes through
|
{
|
||||||
each instruction in the prologue. It just takes up space. */
|
/* Create a note to describe the CFA. Because this is only used to set
|
||||||
note_rtx = gen_rtx_SET (VOIDmode, (frame_pointer_needed
|
DW_AT_frame_base for debug info, don't bother tracking changes through
|
||||||
? 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
|
||||||
plus_constant (Pmode, stack_pointer_rtx,
|
? hard_frame_pointer_rtx
|
||||||
-total_size));
|
: stack_pointer_rtx),
|
||||||
RTX_FRAME_RELATED_P (insn) = 1;
|
plus_constant (Pmode, stack_pointer_rtx,
|
||||||
add_reg_note (insn, REG_FRAME_RELATED_EXPR, note_rtx);
|
-total_size));
|
||||||
|
RTX_FRAME_RELATED_P (insn) = 1;
|
||||||
|
add_reg_note (insn, REG_FRAME_RELATED_EXPR, note_rtx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Clear variables at function end. */
|
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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)
|
||||||
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");
|
||||||
|
|
||||||
|
/* 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");
|
||||||
|
|
||||||
|
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\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");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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");
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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;
|
||||||
#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;
|
||||||
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;
|
||||||
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];
|
||||||
#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];
|
||||||
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
|
||||||
{ 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
|
||||||
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];
|
||||||
#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
|
||||||
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
|
||||||
|
|
||||||
/* 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
|
||||||
|
|
||||||
/* 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
|
||||||
/* 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
|
||||||
| 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
|
||||||
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 @@
|
||||||
(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 @@
|
||||||
(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 @@
|
||||||
(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 @@
|
||||||
[(return)]
|
[(return)]
|
||||||
""
|
""
|
||||||
{
|
{
|
||||||
emit_jump_insn (gen_return ());
|
xtensa_expand_epilogue ();
|
||||||
DONE;
|
DONE;
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -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 @@
|
||||||
;; 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 @@
|
||||||
(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
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,16 @@
|
||||||
|
2015-03-03 Max Filippov <jcmvbkbc@gmail.com>
|
||||||
|
|
||||||
|
Implement call0 ABI for xtensa
|
||||||
|
* config/xtensa/lib2funcs.S (__xtensa_libgcc_window_spill,
|
||||||
|
__xtensa_nonlocal_goto): Don't compile for call0 ABI.
|
||||||
|
(__xtensa_sync_caches): Only use entry and retw in windowed ABI,
|
||||||
|
use ret in call0 ABI.
|
||||||
|
* config/xtensa/t-windowed: New file.
|
||||||
|
* libgcc/config/xtensa/t-xtensa (LIB2ADDEH): Move to t-windowed.
|
||||||
|
* libgcc/configure: Regenerated.
|
||||||
|
* libgcc/configure.ac: Check if xtensa target is configured for
|
||||||
|
windowed ABI and thus needs to use custom unwind code.
|
||||||
|
|
||||||
2015-02-12 Jonathan Wakely <jwakely@redhat.com>
|
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
|
||||||
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:
|
||||||
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:
|
||||||
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:
|
||||||
|
|
||||||
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:
|
||||||
.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:
|
||||||
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
|
||||||
#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,
|
||||||
return _URC_NO_REASON;
|
return _URC_NO_REASON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* __XTENSA_WINDOWED_ABI__ */
|
||||||
|
|
||||||
#endif /* ifdef inhibit_libc */
|
#endif /* ifdef inhibit_libc */
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
;;
|
;;
|
||||||
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
|
||||||
;;
|
;;
|
||||||
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")))],
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue