+2019-04-16 Claudiu Zissulescu <claziss@synopsys.com>
+
+ * config/arc/arc.c (arc_hard_regno_modes): Add two missing modes
+ for last two fake registers.
+ (arc_conditional_register_usage): Make sure fake frame and arg
+ pointer regs are in general regs class.
+ (FRAME_POINTER_MASK): Remove.
+ (RETURN_ADDR_MASK): Remove.
+ (arc_must_save_register): Use hard frame regnum.
+ (frame_restore_reg): Use hard_frame_pointer_rtx.
+ (arc_save_callee_saves): Likewise.
+ (arc_restore_callee_saves): Likewise.
+ (arc_save_callee_enter): Likewise.
+ (arc_restore_callee_leave): Likewise.
+ (arc_save_callee_milli): Likewise.
+ (arc_eh_return_address_location): Likewise.
+ (arc_check_multi): Use hard frame regnum.
+ (arc_can_eliminate): Likewise.
+ * config/arc/arc.h (FIXED_REGISTERS): Make FP register available
+ for register allocator.
+ (REG_CLASS_CONTENTS): Update GENERAL_REGS.
+ (REGNO_OK_FOR_BASE_P): Consider FRAME_POINTER_REGNUM.
+ (FRAME_POINTER_REGNUM): Change it to a fake register.
+ (HARD_FRAME_POINTER_REGNUM): Defined.
+ (ARG_POINTER_REGNUM): Change it to a new fake register.
+ (ELIMINABLE_REGS): Update.
+ (REGISTER_NAMES): Update names.
+ * config/arc/arc.md (LP_START): Remove.
+ (LP_END): Likewise.
+ (shift_si3_loop): Update pattern.
+
2019-04-16 Claudiu Zissulescu <claziss@synopsys.com>
* config/arc/arc.c (arc_expand_prologue): Emit blockage regardless
V_MODES, V_MODES, V_MODES, V_MODES, V_MODES, V_MODES, V_MODES, V_MODES,
S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES,
- S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES
+ S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES,
+ S_MODES, S_MODES
};
static unsigned int arc_mode_class [NUM_MACHINE_MODES];
/* Handle Special Registers. */
arc_regno_reg_class[CC_REG] = NO_REGS; /* CC_REG: must be NO_REGS. */
- arc_regno_reg_class[62] = GENERAL_REGS;
+ arc_regno_reg_class[FRAME_POINTER_REGNUM] = GENERAL_REGS;
+ arc_regno_reg_class[ARG_POINTER_REGNUM] = GENERAL_REGS;
if (TARGET_DPFP)
for (i = R40_REG; i < R44_REG; ++i)
return fun->machine->fn_type = fn_type;
}
-#define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
-#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
+/* Helper function to wrap FRAME_POINTER_NEEDED. We do this as
+ FRAME_POINTER_NEEDED will not be true until the IRA (Integrated
+ Register Allocator) pass, while we want to get the frame size
+ correct earlier than the IRA pass.
+
+ When a function uses eh_return we must ensure that the fp register
+ is saved and then restored so that the unwinder can restore the
+ correct value for the frame we are going to jump to.
+
+ To do this we force all frames that call eh_return to require a
+ frame pointer (see arc_frame_pointer_required), this
+ will ensure that the previous frame pointer is stored on entry to
+ the function, and will then be reloaded at function exit.
+
+ As the frame pointer is handled as a special case in our prologue
+ and epilogue code it must not be saved and restored using the
+ MUST_SAVE_REGISTER mechanism otherwise we run into issues where GCC
+ believes that the function is not using a frame pointer and that
+ the value in the fp register is the frame pointer, while the
+ prologue and epilogue are busy saving and restoring the fp
+ register.
+
+ During compilation of a function the frame size is evaluated
+ multiple times, it is not until the reload pass is complete the the
+ frame size is considered fixed (it is at this point that space for
+ all spills has been allocated). However the frame_pointer_needed
+ variable is not set true until the register allocation pass, as a
+ result in the early stages the frame size does not include space
+ for the frame pointer to be spilled.
+
+ The problem that this causes is that the rtl generated for
+ EH_RETURN_HANDLER_RTX uses the details of the frame size to compute
+ the offset from the frame pointer at which the return address
+ lives. However, in early passes GCC has not yet realised we need a
+ frame pointer, and so has not included space for the frame pointer
+ in the frame size, and so gets the offset of the return address
+ wrong. This should not be an issue as in later passes GCC has
+ realised that the frame pointer needs to be spilled, and has
+ increased the frame size. However, the rtl for the
+ EH_RETURN_HANDLER_RTX is not regenerated to use the newer, larger
+ offset, and the wrong smaller offset is used. */
+
+static bool
+arc_frame_pointer_needed (void)
+{
+ return (frame_pointer_needed || crtl->calls_eh_return);
+}
/* Tell prologue and epilogue if register REGNO should be saved /
restored. The return address, stack pointer and frame pointer are
break;
}
- if ((regno) != RETURN_ADDR_REGNUM
- && (regno) != FRAME_POINTER_REGNUM
- && (regno) != STACK_POINTER_REGNUM
- && df_regs_ever_live_p (regno)
- && (!call_used_regs[regno]
- || ARC_INTERRUPT_P (fn_type))
- /* Do not emit code for auto saved regs. */
- && !irq_auto_save_p
- && !firq_auto_save_p)
- return true;
+ switch (regno)
+ {
+ case RETURN_ADDR_REGNUM:
+ case STACK_POINTER_REGNUM:
+ return false;
+
+ case HARD_FRAME_POINTER_REGNUM:
+ /* If we need FP reg as a frame pointer then don't save it as a
+ regular reg. */
+ if (arc_frame_pointer_needed ())
+ return false;
+
+ /* FALLTHRU */
+ default:
+ if (df_regs_ever_live_p (regno)
+ && (!call_used_regs[regno]
+ || ARC_INTERRUPT_P (fn_type))
+ /* Do not emit code for auto saved regs. */
+ && !irq_auto_save_p
+ && !firq_auto_save_p)
+ return true;
+ }
return false;
}
return false;
}
-/* Helper function to wrap FRAME_POINTER_NEEDED. We do this as
- FRAME_POINTER_NEEDED will not be true until the IRA (Integrated
- Register Allocator) pass, while we want to get the frame size
- correct earlier than the IRA pass.
-
- When a function uses eh_return we must ensure that the fp register
- is saved and then restored so that the unwinder can restore the
- correct value for the frame we are going to jump to.
-
- To do this we force all frames that call eh_return to require a
- frame pointer (see arc_frame_pointer_required), this
- will ensure that the previous frame pointer is stored on entry to
- the function, and will then be reloaded at function exit.
-
- As the frame pointer is handled as a special case in our prologue
- and epilogue code it must not be saved and restored using the
- MUST_SAVE_REGISTER mechanism otherwise we run into issues where GCC
- believes that the function is not using a frame pointer and that
- the value in the fp register is the frame pointer, while the
- prologue and epilogue are busy saving and restoring the fp
- register.
-
- During compilation of a function the frame size is evaluated
- multiple times, it is not until the reload pass is complete the the
- frame size is considered fixed (it is at this point that space for
- all spills has been allocated). However the frame_pointer_needed
- variable is not set true until the register allocation pass, as a
- result in the early stages the frame size does not include space
- for the frame pointer to be spilled.
-
- The problem that this causes is that the rtl generated for
- EH_RETURN_HANDLER_RTX uses the details of the frame size to compute
- the offset from the frame pointer at which the return address
- lives. However, in early passes GCC has not yet realised we need a
- frame pointer, and so has not included space for the frame pointer
- in the frame size, and so gets the offset of the return address
- wrong. This should not be an issue as in later passes GCC has
- realised that the frame pointer needs to be spilled, and has
- increased the frame size. However, the rtl for the
- EH_RETURN_HANDLER_RTX is not regenerated to use the newer, larger
- offset, and the wrong smaller offset is used. */
-
-static bool
-arc_frame_pointer_needed (void)
-{
- return (frame_pointer_needed || crtl->calls_eh_return);
-}
-
/* Return non-zero if there are registers to be saved or loaded using
millicode thunks. We can only use consecutive sequences starting
with r13, and not going beyond r25.
insn = frame_move_inc (reg, addr, stack_pointer_rtx, 0);
add_reg_note (insn, REG_CFA_RESTORE, reg);
- if (reg == frame_pointer_rtx)
+ if (reg == hard_frame_pointer_rtx)
add_reg_note (insn, REG_CFA_DEF_CFA,
plus_constant (Pmode, stack_pointer_rtx,
GET_MODE_SIZE (GET_MODE (reg)) + offset));
registers are saved. */
if (save_fp)
{
- frame_allocated += frame_save_reg (frame_pointer_rtx, offset);
+ frame_allocated += frame_save_reg (hard_frame_pointer_rtx, offset);
offset = 0;
}
/* Emit mov fp,sp. */
if (arc_frame_pointer_needed ())
- frame_move (frame_pointer_rtx, stack_pointer_rtx);
+ frame_move (hard_frame_pointer_rtx, stack_pointer_rtx);
return frame_allocated;
}
/* Emit mov fp,sp. */
if (arc_frame_pointer_needed () && offset)
{
- frame_move (stack_pointer_rtx, frame_pointer_rtx);
+ frame_move (stack_pointer_rtx, hard_frame_pointer_rtx);
frame_deallocated += offset;
offset = 0;
}
{
/* Any offset is taken care by previous if-statement. */
gcc_assert (offset == 0);
- frame_deallocated += frame_restore_reg (frame_pointer_rtx, 0);
+ frame_deallocated += frame_restore_reg (hard_frame_pointer_rtx, 0);
}
if (offset)
mem = gen_frame_mem (Pmode, plus_constant (Pmode,
stack_pointer_rtx,
off));
- XVECEXP (insn, 0, indx) = gen_rtx_SET (mem, frame_pointer_rtx);
+ XVECEXP (insn, 0, indx) = gen_rtx_SET (mem, hard_frame_pointer_rtx);
RTX_FRAME_RELATED_P (XVECEXP (insn, 0, indx++)) = 1;
off -= UNITS_PER_WORD;
- XVECEXP (insn, 0, indx) = gen_rtx_SET (frame_pointer_rtx,
+ XVECEXP (insn, 0, indx) = gen_rtx_SET (hard_frame_pointer_rtx,
stack_pointer_rtx);
RTX_FRAME_RELATED_P (XVECEXP (insn, 0, indx++)) = 1;
save_fp = false;
mem = gen_frame_mem (Pmode, plus_constant (Pmode,
stack_pointer_rtx,
off));
- XVECEXP (insn, 0, indx) = gen_rtx_SET (frame_pointer_rtx, mem);
+ XVECEXP (insn, 0, indx) = gen_rtx_SET (hard_frame_pointer_rtx, mem);
RTX_FRAME_RELATED_P (XVECEXP (insn, 0, indx++)) = 1;
off -= UNITS_PER_WORD;
}
/* Dwarf related info. */
if (restore_fp)
{
- add_reg_note (insn, REG_CFA_RESTORE, frame_pointer_rtx);
+ add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx);
add_reg_note (insn, REG_CFA_DEF_CFA,
plus_constant (Pmode, stack_pointer_rtx,
offset + nregs * UNITS_PER_WORD));
above loop to save fp because our ABI states fp goes aftert all
registers are saved. */
if (save_fp)
- frame_allocated += frame_save_reg (frame_pointer_rtx, offset);
+ frame_allocated += frame_save_reg (hard_frame_pointer_rtx, offset);
/* Emit mov fp,sp. */
if (arc_frame_pointer_needed ())
- frame_move (frame_pointer_rtx, stack_pointer_rtx);
+ frame_move (hard_frame_pointer_rtx, stack_pointer_rtx);
return frame_allocated;
}
/* Emit mov fp,sp. */
if (arc_frame_pointer_needed () && offset)
{
- frame_move (stack_pointer_rtx, frame_pointer_rtx);
+ frame_move (stack_pointer_rtx, hard_frame_pointer_rtx);
frame_allocated = offset;
offset = 0;
}
if (restore_fp)
- frame_allocated += frame_restore_reg (frame_pointer_rtx, 0);
+ frame_allocated += frame_restore_reg (hard_frame_pointer_rtx, 0);
if (offset)
{
if (REGNO (reg) == RETURN_ADDR_REGNUM
&& i == start)
regno = 12;
- else if (REGNO (reg) == FRAME_POINTER_REGNUM)
+ else if (REGNO (reg) == HARD_FRAME_POINTER_REGNUM)
++i;
else if (REGNO (reg) != regno)
return false;
included in the 'extra_size' field. */
offset = afi->reg_size + afi->extra_size - 4;
mem = gen_frame_mem (Pmode,
- plus_constant (Pmode, frame_pointer_rtx, offset));
+ plus_constant (Pmode, hard_frame_pointer_rtx, offset));
/* The following should not be needed, and is, really a hack. The
issue being worked around here is that the DSE (Dead Store
static bool
arc_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
{
- return ((to == FRAME_POINTER_REGNUM) || !arc_frame_pointer_needed ());
+ return ((to == HARD_FRAME_POINTER_REGNUM) || (to == STACK_POINTER_REGNUM));
}
/* Define the offset between two registers, one to be eliminated, and
if (!cfun->machine->frame_info.initialized)
arc_compute_frame_size ();
- if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
+ if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
{
return (cfun->machine->frame_info.extra_size
+ cfun->machine->frame_info.reg_size);
+ cfun->machine->frame_info.extra_size
+ cfun->machine->frame_info.reg_size));
}
+ if ((from == FRAME_POINTER_REGNUM) && (to == HARD_FRAME_POINTER_REGNUM))
+ return 0;
gcc_unreachable ();
}
frame pointer value for this frame (if the use of the frame pointer
had not been removed). We really do want the raw frame pointer
register value. */
- return gen_raw_REG (Pmode, FRAME_POINTER_REGNUM);
+ return gen_raw_REG (Pmode, HARD_FRAME_POINTER_REGNUM);
}
/* Return nonzero if a jli call should be generated for a call from
argument pointer. */
/* r63 is pc, r64-r127 = simd vregs, r128-r143 = simd dma config regs
- r144, r145 = lp_start, lp_end
+ r144, r145 = ARG_POINTER, FRAME_POINTER
and therefore the pseudo registers start from r146. */
#define FIRST_PSEUDO_REGISTER 146
{ 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 1, 1, 1, 1, 1, 1, \
+ 0, 0, 1, 0, 1, 1, 1, 1, \
\
1, 1, 1, 1, 1, 1, 1, 1, \
0, 0, 0, 0, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 1, 1, 1, 1, 1, 1, \
+ 0, 0, 1, 0, 1, 1, 1, 1, \
\
1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, \
{0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rsd'. */ \
{0x0000000f, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rcd'. */ \
{0x0000f00f, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'q'. */ \
- {0x1c001fff, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rsc'. */ \
+ {0x00001fff, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'Rsc'. */ \
{0x9fffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, /* 'h'. */ \
{0x00000000, 0x00000f00, 0x00000000, 0x00000000, 0x00000000}, /* 'D'. */ \
- {0xffffffff, 0x8fffffff, 0x00000000, 0x00000000, 0x00000000}, /* 'r'. */ \
+ {0xffffffff, 0x8fffffff, 0x00000000, 0x00000000, 0x00030000}, /* 'r'. */ \
{0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000}, /* 'v'. */ \
{0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000ffff}, /* 'd'. */ \
{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0003ffff} /* ALL_REGS. */\
Since they use reg_renumber, they are safe only once reg_renumber
has been allocated, which happens in local-alloc.c. */
#define REGNO_OK_FOR_BASE_P(REGNO) \
- ((REGNO) < 29 || ((REGNO) == ARG_POINTER_REGNUM) || ((REGNO) == 63) \
+ ((REGNO) < 29 \
+ || ((REGNO) == ARG_POINTER_REGNUM) \
+ || ((REGNO) == FRAME_POINTER_REGNUM) \
+ || ((REGNO) == PCL_REG) \
|| ((unsigned) reg_renumber[REGNO] < 29) \
|| ((unsigned) (REGNO) == (unsigned) arc_tp_regno) \
|| (fixed_regs[REGNO] == 0 && IN_RANGE (REGNO, 32, 59)) \
- || ((REGNO) == 30 && fixed_regs[REGNO] == 0))
+ || (fixed_regs[REGNO] == 0 && (REGNO) == R30_REG))
#define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_BASE_P(REGNO)
#define STACK_POINTER_REGNUM 28
/* Base register for access to local variables of the function. */
-#define FRAME_POINTER_REGNUM 27
+#define FRAME_POINTER_REGNUM 145
+#define HARD_FRAME_POINTER_REGNUM 27
/* Base register for access to arguments of the function. This register
will be eliminated into either fp or sp. */
-#define ARG_POINTER_REGNUM 62
+#define ARG_POINTER_REGNUM 144
#define RETURN_ADDR_REGNUM 31
#define ELIMINABLE_REGS \
{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
- {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
- {FRAME_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}}
/* Define the offset between two registers, one to be eliminated, and the other
its replacement, at the start of a routine. */
"r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39", \
"d1", "d1", "d2", "d2", "r44", "r45", "r46", "r47", \
"r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55", \
- rname56,rname57,rname58,rname59,"lp_count", "cc", "ap", "pcl", \
+ rname56,rname57,rname58,rname59,"lp_count", "cc", "limm", "pcl", \
"vr0", "vr1", "vr2", "vr3", "vr4", "vr5", "vr6", "vr7", \
"vr8", "vr9", "vr10", "vr11", "vr12", "vr13", "vr14", "vr15", \
"vr16", "vr17", "vr18", "vr19", "vr20", "vr21", "vr22", "vr23", \
"vr56", "vr57", "vr58", "vr59", "vr60", "vr61", "vr62", "vr63", \
"dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7", \
"dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7", \
- "lp_start", "lp_end" \
+ "arg", "frame" \
}
#define ADDITIONAL_REGISTER_NAMES \
(LP_COUNT 60)
(CC_REG 61)
(PCL_REG 63)
- (LP_START 144)
- (LP_END 145)
]
)
(match_operand:SI 2 "nonmemory_operand" "rn,Cal")]))
(clobber (match_scratch:SI 4 "=X,X"))
(clobber (reg:SI LP_COUNT))
- (clobber (reg:SI LP_START))
- (clobber (reg:SI LP_END))
(clobber (reg:CC CC_REG))
]
"!TARGET_BARREL_SHIFTER"
{
int len = XVECLEN (operands[0], 0);
rtx tmp = XVECEXP (operands[0], 0, len - 1);
- if (XEXP (tmp, 0) != frame_pointer_rtx)
+ if (XEXP (tmp, 0) != hard_frame_pointer_rtx)
{
operands[3] = XEXP (tmp, 0);
gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));
{
int len = XVECLEN (operands[0], 0);
rtx tmp = XVECEXP (operands[0], 0, len - 1);
- if (XEXP (tmp, 0) != frame_pointer_rtx)
+ if (XEXP (tmp, 0) != hard_frame_pointer_rtx)
{
operands[3] = XEXP (tmp, 0);
gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));
{
int len = XVECLEN (operands[0], 0);
rtx tmp = XVECEXP (operands[0], 0, len - 1);
- if (XEXP (tmp, 0) != frame_pointer_rtx)
+ if (XEXP (tmp, 0) != hard_frame_pointer_rtx)
{
operands[3] = XEXP (tmp, 0);
gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));
{
int len = XVECLEN (operands[0], 0);
rtx tmp = XVECEXP (operands[0], 0, len - 1);
- if (XEXP (tmp, 0) != frame_pointer_rtx)
+ if (XEXP (tmp, 0) != hard_frame_pointer_rtx)
{
operands[3] = XEXP (tmp, 0);
gcc_assert (INTVAL (operands[1]) == INTVAL (operands[2]));