summaryrefslogtreecommitdiff
path: root/gcc/config/s390/s390.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/s390/s390.c')
-rw-r--r--gcc/config/s390/s390.c45
1 files changed, 27 insertions, 18 deletions
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 9de035051e2..4ebfbb3fc8c 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -1038,7 +1038,7 @@ const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
- ADDR_REGS, NO_REGS, ADDR_REGS
+ ADDR_REGS, NO_REGS, ADDR_REGS, ADDR_REGS
};
/* Return attribute type of insn. */
@@ -1613,9 +1613,6 @@ load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
else
return 0;
- if (src_addr == frame_pointer_rtx || src_addr == arg_pointer_rtx)
- return 0;
-
for (i = 1; i < count; i++)
{
rtx elt = XVECEXP (op, 0, i);
@@ -1676,9 +1673,6 @@ store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
else
return 0;
- if (dest_addr == frame_pointer_rtx || dest_addr == arg_pointer_rtx)
- return 0;
-
for (i = 1; i < count; i++)
{
rtx elt = XVECEXP (op, 0, i);
@@ -2258,15 +2252,19 @@ s390_decompose_address (register rtx addr, struct s390_address *out)
/* Validate displacement. */
if (!disp)
{
- /* If the argument pointer is involved, the displacement will change
- later anyway as the argument pointer gets eliminated. This could
- make a valid displacement invalid, but it is more likely to make
- an invalid displacement valid, because we sometimes access the
- register save area via negative offsets to the arg pointer.
+ /* If the argument pointer or the return address pointer are involved,
+ the displacement will change later anyway as the virtual registers get
+ eliminated. This could make a valid displacement invalid, but it is
+ more likely to make an invalid displacement valid, because we sometimes
+ access the register save area via negative offsets to one of those
+ registers.
Thus we don't check the displacement for validity here. If after
elimination the displacement turns out to be invalid after all,
this is fixed up by reload in any case. */
- if (base != arg_pointer_rtx && indx != arg_pointer_rtx)
+ if (base != arg_pointer_rtx
+ && indx != arg_pointer_rtx
+ && base != return_address_pointer_rtx
+ && indx != return_address_pointer_rtx)
if (!DISP_IN_RANGE (offset))
return FALSE;
}
@@ -5499,7 +5497,7 @@ s390_reorg (void)
frame pointer of that frame. */
rtx
-s390_return_addr_rtx (int count, rtx frame)
+s390_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
{
rtx addr;
@@ -5512,10 +5510,10 @@ s390_return_addr_rtx (int count, rtx frame)
value of RETURN_REGNUM is actually saved. */
if (count == 0)
- cfun->machine->save_return_addr_p = true;
-
- /* To retrieve the return address we read the stack slot where the
- corresponding RETURN_REGNUM value was saved. */
+ {
+ cfun->machine->save_return_addr_p = true;
+ return gen_rtx_MEM (Pmode, return_address_pointer_rtx);
+ }
addr = plus_constant (frame, RETURN_REGNUM * UNITS_PER_WORD);
addr = memory_address (Pmode, addr);
@@ -5642,6 +5640,17 @@ s390_arg_frame_offset (void)
return cfun->machine->frame_size + STACK_POINTER_OFFSET;
}
+/* Return offset between return address pointer (location of r14
+ on the stack) and frame pointer initially after prologue. */
+
+HOST_WIDE_INT
+s390_return_address_offset (void)
+{
+ s390_frame_info (1, 1);
+
+ return cfun->machine->frame_size + RETURN_REGNUM * UNITS_PER_WORD;
+}
+
/* Emit insn to save fpr REGNUM at offset OFFSET relative
to register BASE. Return generated insn. */