mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-27 05:44:15 +08:00
Add an assertion: the zeroed_hardregs set is a subset of all call used regs.
We should make sure that the hard register set that is actually cleared by the target hook zero_call_used_regs should be a subset of all call used registers. At the same time, update documentation for the target hook TARGET_ZERO_CALL_USED_REGS. This new assertion identified a bug in the i386 implemenation, which incorrectly set the zeroed_hardregs for stack registers. Fixed this bug in i386 implementation. gcc/ChangeLog: 2022-04-01 Qing Zhao <qing.zhao@oracle.com> * config/i386/i386.cc (zero_all_st_registers): Return the value of num_of_st. (ix86_zero_call_used_regs): Update zeroed_hardregs set according to the return value of zero_all_st_registers. * doc/tm.texi: Update the documentation of TARGET_ZERO_CALL_USED_REGS. * function.cc (gen_call_used_regs_seq): Add an assertion. * target.def: Update the documentation of TARGET_ZERO_CALL_USED_REGS.
This commit is contained in:
parent
413187b0b3
commit
31933f4f78
@ -3753,16 +3753,17 @@ zero_all_vector_registers (HARD_REG_SET need_zeroed_hardregs)
|
||||
needs to be cleared, the whole stack should be cleared. However,
|
||||
x87 stack registers that hold the return value should be excluded.
|
||||
x87 returns in the top (two for complex values) register, so
|
||||
num_of_st should be 7/6 when x87 returns, otherwise it will be 8. */
|
||||
num_of_st should be 7/6 when x87 returns, otherwise it will be 8.
|
||||
return the value of num_of_st. */
|
||||
|
||||
|
||||
static bool
|
||||
static int
|
||||
zero_all_st_registers (HARD_REG_SET need_zeroed_hardregs)
|
||||
{
|
||||
|
||||
/* If the FPU is disabled, no need to zero all st registers. */
|
||||
if (! (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387))
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
unsigned int num_of_st = 0;
|
||||
for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
|
||||
@ -3774,7 +3775,7 @@ zero_all_st_registers (HARD_REG_SET need_zeroed_hardregs)
|
||||
}
|
||||
|
||||
if (num_of_st == 0)
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
bool return_with_x87 = false;
|
||||
return_with_x87 = (crtl->return_rtx
|
||||
@ -3802,7 +3803,7 @@ zero_all_st_registers (HARD_REG_SET need_zeroed_hardregs)
|
||||
insn = emit_insn (gen_rtx_SET (st_reg, st_reg));
|
||||
add_reg_note (insn, REG_DEAD, st_reg);
|
||||
}
|
||||
return true;
|
||||
return num_of_st;
|
||||
}
|
||||
|
||||
|
||||
@ -3851,7 +3852,7 @@ ix86_zero_call_used_regs (HARD_REG_SET need_zeroed_hardregs)
|
||||
{
|
||||
HARD_REG_SET zeroed_hardregs;
|
||||
bool all_sse_zeroed = false;
|
||||
bool all_st_zeroed = false;
|
||||
int all_st_zeroed_num = 0;
|
||||
bool all_mm_zeroed = false;
|
||||
|
||||
CLEAR_HARD_REG_SET (zeroed_hardregs);
|
||||
@ -3881,9 +3882,17 @@ ix86_zero_call_used_regs (HARD_REG_SET need_zeroed_hardregs)
|
||||
if (!exit_with_mmx_mode)
|
||||
/* x87 exit mode, we should zero all st registers together. */
|
||||
{
|
||||
all_st_zeroed = zero_all_st_registers (need_zeroed_hardregs);
|
||||
if (all_st_zeroed)
|
||||
SET_HARD_REG_BIT (zeroed_hardregs, FIRST_STACK_REG);
|
||||
all_st_zeroed_num = zero_all_st_registers (need_zeroed_hardregs);
|
||||
|
||||
if (all_st_zeroed_num > 0)
|
||||
for (unsigned int regno = FIRST_STACK_REG; regno <= LAST_STACK_REG; regno++)
|
||||
/* x87 stack registers that hold the return value should be excluded.
|
||||
x87 returns in the top (two for complex values) register. */
|
||||
if (all_st_zeroed_num == 8
|
||||
|| !((all_st_zeroed_num >= 6 && regno == REGNO (crtl->return_rtx))
|
||||
|| (all_st_zeroed_num == 6
|
||||
&& (regno == (REGNO (crtl->return_rtx) + 1)))))
|
||||
SET_HARD_REG_BIT (zeroed_hardregs, regno);
|
||||
}
|
||||
else
|
||||
/* MMX exit mode, check whether we can zero all mm registers. */
|
||||
|
@ -12330,6 +12330,13 @@ This target hook emits instructions to zero the subset of @var{selected_regs}
|
||||
that could conceivably contain values that are useful to an attacker.
|
||||
Return the set of registers that were actually cleared.
|
||||
|
||||
For most targets, the returned set of registers is a subset of
|
||||
@var{selected_regs}, however, for some of the targets (for example MIPS),
|
||||
clearing some registers that are in the @var{selected_regs} requires
|
||||
clearing other call used registers that are not in the @var{selected_regs},
|
||||
under such situation, the returned set of registers must be a subset of all
|
||||
call used registers.
|
||||
|
||||
The default implementation uses normal move instructions to zero
|
||||
all the registers in @var{selected_regs}. Define this hook if the
|
||||
target has more efficient ways of zeroing certain registers,
|
||||
|
@ -5892,7 +5892,9 @@ gen_call_used_regs_seq (rtx_insn *ret, unsigned int zero_regs_type)
|
||||
df_simulate_one_insn_backwards (bb, ret, live_out);
|
||||
|
||||
HARD_REG_SET selected_hardregs;
|
||||
HARD_REG_SET all_call_used_regs;
|
||||
CLEAR_HARD_REG_SET (selected_hardregs);
|
||||
CLEAR_HARD_REG_SET (all_call_used_regs);
|
||||
for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
|
||||
{
|
||||
if (!crtl->abi->clobbers_full_reg_p (regno))
|
||||
@ -5901,6 +5903,13 @@ gen_call_used_regs_seq (rtx_insn *ret, unsigned int zero_regs_type)
|
||||
continue;
|
||||
if (REGNO_REG_SET_P (live_out, regno))
|
||||
continue;
|
||||
#ifdef LEAF_REG_REMAP
|
||||
if (crtl->uses_only_leaf_regs && LEAF_REG_REMAP (regno) < 0)
|
||||
continue;
|
||||
#endif
|
||||
/* This is a call used register that is dead at return. */
|
||||
SET_HARD_REG_BIT (all_call_used_regs, regno);
|
||||
|
||||
if (only_gpr
|
||||
&& !TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], regno))
|
||||
continue;
|
||||
@ -5908,10 +5917,6 @@ gen_call_used_regs_seq (rtx_insn *ret, unsigned int zero_regs_type)
|
||||
continue;
|
||||
if (only_arg && !FUNCTION_ARG_REGNO_P (regno))
|
||||
continue;
|
||||
#ifdef LEAF_REG_REMAP
|
||||
if (crtl->uses_only_leaf_regs && LEAF_REG_REMAP (regno) < 0)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* Now this is a register that we might want to zero. */
|
||||
SET_HARD_REG_BIT (selected_hardregs, regno);
|
||||
@ -5925,6 +5930,15 @@ gen_call_used_regs_seq (rtx_insn *ret, unsigned int zero_regs_type)
|
||||
HARD_REG_SET zeroed_hardregs;
|
||||
start_sequence ();
|
||||
zeroed_hardregs = targetm.calls.zero_call_used_regs (selected_hardregs);
|
||||
|
||||
/* For most targets, the returned set of registers is a subset of
|
||||
selected_hardregs, however, for some of the targets (for example MIPS),
|
||||
clearing some registers that are in selected_hardregs requires clearing
|
||||
other call used registers that are not in the selected_hardregs, under
|
||||
such situation, the returned set of registers must be a subset of
|
||||
all call used registers. */
|
||||
gcc_assert (hard_reg_set_subset_p (zeroed_hardregs, all_call_used_regs));
|
||||
|
||||
rtx_insn *seq = get_insns ();
|
||||
end_sequence ();
|
||||
if (seq)
|
||||
|
@ -5122,6 +5122,13 @@ DEFHOOK
|
||||
that could conceivably contain values that are useful to an attacker.\n\
|
||||
Return the set of registers that were actually cleared.\n\
|
||||
\n\
|
||||
For most targets, the returned set of registers is a subset of\n\
|
||||
@var{selected_regs}, however, for some of the targets (for example MIPS),\n\
|
||||
clearing some registers that are in the @var{selected_regs} requires\n\
|
||||
clearing other call used registers that are not in the @var{selected_regs},\n\
|
||||
under such situation, the returned set of registers must be a subset of all\n\
|
||||
call used registers.\n\
|
||||
\n\
|
||||
The default implementation uses normal move instructions to zero\n\
|
||||
all the registers in @var{selected_regs}. Define this hook if the\n\
|
||||
target has more efficient ways of zeroing certain registers,\n\
|
||||
|
Loading…
Reference in New Issue
Block a user