static bool xtensa_hard_regno_mode_ok (unsigned int, machine_mode);
static bool xtensa_modes_tieable_p (machine_mode, machine_mode);
static HOST_WIDE_INT xtensa_constant_alignment (const_tree, HOST_WIDE_INT);
+static bool xtensa_can_eliminate (const int from ATTRIBUTE_UNUSED,
+ const int to);
static HOST_WIDE_INT xtensa_starting_frame_offset (void);
static unsigned HOST_WIDE_INT xtensa_asan_shadow_offset (void);
#undef TARGET_CONSTANT_ALIGNMENT
#define TARGET_CONSTANT_ALIGNMENT xtensa_constant_alignment
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE xtensa_can_eliminate
+
#undef TARGET_STARTING_FRAME_OFFSET
#define TARGET_STARTING_FRAME_OFFSET xtensa_starting_frame_offset
return align;
}
+static bool
+xtensa_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
+{
+ gcc_assert (from == ARG_POINTER_REGNUM || from == FRAME_POINTER_REGNUM);
+
+ /* If we need a frame pointer, ARG_POINTER_REGNUM and FRAME_POINTER_REGNUM
+ can only eliminate to HARD_FRAME_POINTER_REGNUM. */
+ return to == HARD_FRAME_POINTER_REGNUM
+ || (!frame_pointer_needed && to == STACK_POINTER_REGNUM);
+}
+
/* Implement TARGET_STARTING_FRAME_OFFSET. */
static HOST_WIDE_INT
#define STACK_POINTER_REGNUM (GP_REG_FIRST + 1)
/* Base register for access to local variables of the function. */
-#define HARD_FRAME_POINTER_REGNUM (GP_REG_FIRST + \
- (TARGET_WINDOWED_ABI ? 7 : 15))
+#define HARD_FRAME_POINTER_REGNUM \
+ (TARGET_WINDOWED_ABI \
+ ? XTENSA_WINDOWED_HARD_FRAME_POINTER_REGNUM \
+ : XTENSA_CALL0_HARD_FRAME_POINTER_REGNUM)
+
+#define XTENSA_WINDOWED_HARD_FRAME_POINTER_REGNUM (GP_REG_FIRST + 7)
+#define XTENSA_CALL0_HARD_FRAME_POINTER_REGNUM (GP_REG_FIRST + 15)
/* The register number of the frame pointer register, which is used to
access automatic variables in the stack frame. For Xtensa, this
|| (flag_sanitize & SANITIZE_ADDRESS) != 0)
/* The ARG_POINTER and FRAME_POINTER are not real Xtensa registers, so
- they are eliminated to either the stack pointer or hard frame pointer. */
-#define ELIMINABLE_REGS \
-{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
- { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
- { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
- { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
+ they are eliminated to either the stack pointer or hard frame pointer.
+ Since hard frame pointer is different register in windowed and call0
+ ABIs list them both and only allow real HARD_FRAME_POINTER_REGNUM in
+ TARGET_CAN_ELIMINATE. */
+#define ELIMINABLE_REGS \
+{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { ARG_POINTER_REGNUM, XTENSA_WINDOWED_HARD_FRAME_POINTER_REGNUM}, \
+ { ARG_POINTER_REGNUM, XTENSA_CALL0_HARD_FRAME_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, XTENSA_WINDOWED_HARD_FRAME_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, XTENSA_CALL0_HARD_FRAME_POINTER_REGNUM}}
/* Specify the initial difference between the specified pair of registers. */
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \