This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
flow patch for building ia64
- To: gcc-bugs at gcc dot gnu dot org, gcc-patches at gcc dot gnu dot org
- Subject: flow patch for building ia64
- From: amacleod at cygnus dot com
- Date: Thu, 26 Jul 2001 14:30:52 -0700 (PDT)
I was looking at why the trunk cannot build libgcc for ia64 today.
It bombs out in propagate_one_insn when trying to compile __fixdfti
in libgcc2.c. The function isn't very big, and simply reduces down to:
typedef int TItype __attribute__ ((mode (TI)));
typedef float DFtype __attribute__ ((mode (DF)));
TItype
__fixdfti (DFtype a)
{
if (a < 0)
return - __fixunsdfti (-a);
return __fixunsdfti (a);
}
It turns out the only thing the prologue saves is the value of b0
into register r33. This value is then restored in the epilogue.
The processing in propagate_one_insn goes through the entire list of
registers which are invalidated by a call, and removes them from
the live list. What it doesn't take into acocunt is that there
are a few registers which are 'symbolic' in nature, but may map back to
hardware registers. the important ones are
mapped right in gen_rtx_REG (), and MAY consist of:
frame_pointer_rtx
hard_frame_pointer_rtx
arg_pointer_rtx
return_address_pointer_rtx
stack_pointer_rtx
In the ia64 case, after the copy of b0 into r33, we updated
return_address_pointer_rtx to be r33. Then during propagate_one_insn,
the symbolic register RETURN_ADDRESS_POINTER_REGNUM (reg #329)
is marked as killed by a call, so propagate_one_insn clears
register #329 from the reg_live list, but the call to gen_rtx_REG
maps register 329 back to r33, and so r33 is removed from the list
instead.
So... there are 2 solutions. Since this doesn't seem to be
affecting anything except ia64, the simple thing is to
not mark the return_address_register as call-killed. b0 is
marked, so I dont think this will have any undesired side effects.
The other option would be to look at the register generated by the
call to gen_rtx_REG and test whether it is call clobbered or not.
This seem like a more general solution, but I dont know if that
might have other unexpected side effects.... Either one
solves the problem for ia64.
Which is the preferable solution? (Or maybe both? :-) I'm
working on bootstrapping the general one right now.
simple ia64 one:
* config/ia64/ia64.h (CALL_USED_REGISTERS): Unset RA register, b0
already handles this.
Index: config/ia64/ia64.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/ia64/ia64.h,v
retrieving revision 1.78
diff -c -p -r1.78 ia64.h
*** ia64.h 2001/07/25 13:21:49 1.78
--- ia64.h 2001/07/26 21:24:24
*************** while (0)
*** 630,636 ****
/* Branch registers. */ \
1, 0, 0, 0, 0, 0, 1, 1, \
/*FP RA CCV UNAT PFS LC EC */ \
! 1, 1, 1, 1, 1, 0, 1 \
}
/* Define this macro if the target machine has register windows. This C
--- 630,636 ----
/* Branch registers. */ \
1, 0, 0, 0, 0, 0, 1, 1, \
/*FP RA CCV UNAT PFS LC EC */ \
! 1, 0, 1, 1, 1, 0, 1 \
}
/* Define this macro if the target machine has register windows. This C
or the more general one:
* flow.c (propagate_one_insn): Ensure that the register we are
invalidating doesn't point to a different register which is valid.
Index: flow.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/flow.c,v
retrieving revision 1.442
diff -c -p -r1.442 flow.c
*** flow.c 2001/07/25 20:51:24 1.442
--- flow.c 2001/07/26 21:08:19
*************** propagate_one_insn (pbi, insn)
*** 5090,5097 ****
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
{
/* We do not want REG_UNUSED notes for these registers. */
! mark_set_1 (pbi, CLOBBER, gen_rtx_REG (reg_raw_mode[i], i),
cond, insn,
pbi->flags & ~(PROP_DEATH_NOTES | PROP_REG_INFO));
}
--- 5090,5104 ----
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
{
+ rtx reg = gen_rtx_REG (reg_raw_mode[i], i);
+ /* If this register maps to a different one, make
+ sure this one is invalidated by the call. */
+ if (REGNO (reg) != i
+ && !TEST_HARD_REG_BIT (regs_invalidated_by_call,
+ REGNO (reg)))
+ continue;
/* We do not want REG_UNUSED notes for these registers. */
! mark_set_1 (pbi, CLOBBER, reg,
cond, insn,
pbi->flags & ~(PROP_DEATH_NOTES | PROP_REG_INFO));
}