This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

HARD_REGNO_CALL_PART_CLOBBERED and regs_invalidated_by_call


Hi Richard,

As part of implementing the new O32 FPXX ABI I am making use of the
HARD_REGNO_CALL_PART_CLOBBERED macro to allow odd-numbered floating-point 
registers to be considered as 'normally' callee-saved but call clobbered if they 
are being used to hold SImode or SFmode data. The macro is implemented as:

/* Odd numbered single precision registers are not considered call saved
   for O32 FPXX as they will be clobbered when run on an FR=1 FPU.  */
#define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE)                     \
  (TARGET_FLOATXX && ((MODE) == SFmode || (MODE) == SImode)             \
   && FP_REG_P (REGNO) && (REGNO & 1))

IRA and LRA appear to work correctly w.r.t. HARD_REGNO_CALL_PART_CLOBBERED and I 
get the desired O32 FPXX ABI behaviour. However when writing a number of tests 
for this I triggered some optimisations (in particular regcprop) which ignored 
the fact that the odd-numbered single-precision registers are clobbered across 
calls and essentially undid the work IRA/LRA did in treating the register as 
clobbered. The reason for regcprop ignoring the call-clobbered nature of these 
registers is that it simply does not check. The test for call-clobbered 
registers solely relies on regs_invalidated_by_call which is (and cannot be) 
aware of the HARD_REGNO_CALL_PART_CLOBBERED macro as it has no information about
what mode registers are in when it is used. A proposed fix is inline below for
this specific issue.

diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index 101de76..cb2937c 100644
--- a/gcc/regcprop.c
+++ b/gcc/regcprop.c
@@ -1030,8 +1030,10 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd)
                }
            }

-         EXECUTE_IF_SET_IN_HARD_REG_SET (regs_invalidated_by_call, 0, regno, hrsi)
-           if (regno < set_regno || regno >= set_regno + set_nregs)
+         for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+           if ((TEST_HARD_REG_BIT (regs_invalidated_by_call, regno)
+                || HARD_REGNO_CALL_PART_CLOBBERED (regno, vd->e[regno].mode))
+               && (regno < set_regno || regno >= set_regno + set_nregs))
              kill_value_regno (regno, 1, vd);

          /* If SET was seen in CALL_INSN_FUNCTION_USAGE, and SET_SRC

The problem is that there are several other passes that solely rely on 
regs_invalidated_by_call to determine call-clobbered status and will therefore 
make the mistake. Some of these passes simply don't have mode information around 
when handling call-clobbered registers which leaves me a little unsure of the 
best solution in those cases. I would expect that being over-cautious and always 
marking a potentially clobbered register as clobbered seems like one option but 
there is a risk that doing so could lead to legitimate use of a callee-saved 
register (in a mode that is not part clobbered) to be broken.  Essentially I 
would propose introducing another register set 'regs_maybe_invalidated_by_call' 
that includes all reg_invalidated_by_call and anything 
HARD_REGNO_CALL_PART_CLOBBERED reports true for when checking all registers 
against all modes. Wherever call-clobbered information is required but mode 
information is unavailable then regs_maybe_invalidated_by_call would then be 
used.  As I said though there are probably some corner cases to handle too.

I don't quite have the O32 FPXX patches ready to send out yet but this issue is 
relevant to all architectures using HARD_REGNO_CALL_PART_CLOBBERED, presumably 
nobody has hit it yet though.

Regards,
Matthew


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]