This is the mail archive of the gcc-patches@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]

Re: RFA: return_in_msb and complex-mode structures


Richard Henderson <rth@redhat.com> writes:
> On Thu, Nov 18, 2004 at 03:58:36PM +0000, Richard Sandiford wrote:
>> !   /* Use ashr rather than lshr for right shifts.  This is for the benefit
>> !      of the MIPS port, which requires SImode values to be sign-extended
>> !      when stored in 64-bit registers.  */
>
> This is the only part that worries me.  This implies that the shift
> is happening after the PROMOTE_MODE stuff, which means that we aren't
> necessarily generating the correct code for some future target that
> wants to use return_in_msb.
>
> Seems to me that this shift should either happen before promote_mode
> and promote_function_return are applied, or it should re-apply them
> to choose lshr vs ashr.

FWIW, the shift is happening before the PROMOTE_MODE stuff.
That's true both before and after the patch.

The MIPS problem referred to above isn't really related to PROMOTE_MODE
as such.  Even on 64-bit MIPS targets, PROMOTE_MODE only promotes to
SImode if pointers are SImode.  Overpromoting to DImode leads to much
worse code because truncation isn't a no-op.

The case we're dealing with is something like:

    struct s { int i; }
    void foo (struct s) { bar (s.i + 1); }

With big-endian n32, the structure is passed in the upper 32 bits of
argument register $4, so we need to shift it right first.  This shifted
argument will be stored in an SImode pseudo.

So suppose we use a sequence like:

        dsrl32  $4,$4,0         # logical shift by 32
        addiu   $4,$4,1         # $4 isn't sign-extended before this insn
        jal     bar

addiu requires sign-extended input operands, so this sequence invokes
undefined behaviour for negative s.i.  We really need an arithmetic
shift instead.

Now the way the old code dealt with this was to use convert_to_mode()
after the shift:

	  /* Shift the value into the low part of the register.  */
	  *value = expand_binop (GET_MODE (*value), lshr_optab, *value,
				 GEN_INT (shift), 0, 1, OPTAB_WIDEN);

	  /* Truncate it to the type's mode, or its integer equivalent.
	     This is subject to TRULY_NOOP_TRUNCATION.  */
	  *value = convert_to_mode (int_mode_for_mode (TYPE_MODE (type)),
				    *value, 0);

	  /* Now convert it to the final form.  */
	  *value = gen_lowpart (TYPE_MODE (type), *value);
	  return true;

The second statement introduced an explicit truncation for MIPS and
would have been a no-op and most other targets.  Combine would later
merge this truncation with the logical shift to produce a single
arithmetic shift.

Although that all worked fine when shifting pseudos, I wasn't sure
whether we could rely on combine to do that when the original
logical-shift/truncation sequence applies to hard registers.

I thought about various alternatives to select between arithmetic and
logical shifts, but they all needed more code than the patch I posted.
At the end of the day, we have to pick one sort of shift, and:

  (1) The only current user of this code wants arithmetic shifts.
  (2) Hopefully no new architectures will have the same daft
      instruction restrictions that MIPS does.

so it seemed better to use arithmetic shifts unconditionally for now.
We can always revisit this later if another target wants to use
return_in_msb and really does need logical shifts.  Hopefully then
it will be clearer what the right conditions are.

Richard


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