Re: GCC bug?

Georg-Johann Lay <[email protected]> Fri, 4 Aug 2023 17:38:39 +0200
Newsgroups gmane.comp.hardware.avr.gcc
Message-ID <[email protected]>
> Browsing the GCC source, I found this in gcc/config/avr/avr.c
> 
>  if (AVR_HAVE_RAMPZ
>           && TEST_HARD_REG_BIT (set, REG_Z)
>           && TEST_HARD_REG_BIT (set, REG_Z + 1))
>         {
>           emit_push_sfr (rampz_rtx, false /* frame */, AVR_HAVE_RAMPD,
> treg);
>         }
> 
> 
> I wont pretend to fully understand this part of the compiler, but that
> AVR_HAVE_RAMPD looks shady to me?
> 
> Anyone with deeper knowledge want to have a look?
> 
> -Ian

Hi Ian, the code is as intended:

It's during ISR prologue where we determine whether RAMPZ has to be 
saved / restored.  Conditions are that:

1) RAMPZ exists and

2) Z register is used.

The call to emit_push_sfr() to push RAMPZ has argument clr_p = 
HAVE_RAMPD (sic!) because we have two cases when RAMPZ might occur:

A) The hardware has RAMPZ but none of the other RAMP* registers.  This 
is the case on devices with more than 64 KiB of flash and with RAM less 
than 64 KiB.  RAMPZ is only used to augment ELPM.  The rule is that any 
insn may use and clobber RAMPZ as needed *without* the requirement to 
restore the previous value.

B) The hardware has more than 64 KiB of RAM and all RAMP registers are 
present.  The convention is that all RAMP* registers contain a value of 
zero.  If an insn clobbers RAMP*, it has to restore its value. 
Consequently, upon entering an ISR, some RAMPZ might be non-zero, but 
the compiler expects all RAMP registers to contain zero.

As both cases A) and B) have RAMPZ, AVR_HAVE_RAMPZ cannot be used to 
discriminate these cases, but AVR_HAVE_RAMPD *does* discriminate.

There are similar use cases of AVR_HAVE_RAMPD in the startup code or 
after using ELPM, for example at the end of avr.cc::avr_out_lpm():

   if (xop[4] == xstring_e && AVR_HAVE_RAMPD)
     {
       /* Reset RAMPZ to 0 so that EBI devices don't read garbage from 
RAM.  */

       xop[0] = zero_reg_rtx;
       avr_asm_len ("out %i6,%0", xop, plen, 1);
     }

xop[6] is RAMPZ, and xop[4] == xstring_e if ELPM was used.

Johann