Patch pending review
Franz Sirl
Franz.Sirl-kernel@lauterbach.com
Tue Dec 12 12:50:00 GMT 2000
On Tuesday 12 December 2000 20:46, Geoff Keating wrote:
> Franz Sirl <Franz.Sirl-kernel@lauterbach.com> writes:
> > Hi,
> >
> > this patch
> >
> > < http://gcc.gnu.org/ml/gcc-patches/2000-11/msg00202.html >
> >
> > hasn't been reviewed yet. It works fine and enables successful RTL
> > checking bootstraps on powerpc-linux-gnu.
>
> Thank you!
>
> I was trying to work out why my patch, which changed it to:
>
> ;; Length (in bytes).
> (define_attr "length" ""
> (if_then_else (eq_attr "type" "branch")
> (if_then_else (and (ge (minus (pc) (match_dup 0))
> (const_int -32768))
> (lt (minus (pc) (match_dup 0))
> (const_int 32764)))
> (const_int 4)
> (const_int 8))
>
> wasn't working.
>
> I believe the correct change is to make it
>
> ;; Length (in bytes).
> ; According to insn_current_reference_address, '(pc)' in the following
> means: ; for a forward branch, the reference address is the end address
> of ; the branch as known from the previous branch shortening pass,
> ; minus a value to account for possible size increase due to
> ; alignment. For a backward branch, it is the start address of the
> ; branch as known from the current pass, plus a value to account for
> ; possible size increase due to alignment.
> ; so for forward branches, we need to subtract the size of the branch
> ; (which will be 4 if the branch is being shortened) from (pc), to get
> ; the start of the branch from which the branch offset will be
> ; relative. This is accomplished by using 32764 rather than 32768 below.
> (define_attr "length" ""
> (if_then_else (eq_attr "type" "branch")
> (if_then_else (and (ge (minus (match_dup 0) (pc))
> (const_int -32768))
> (lt (minus (match_dup 0) (pc))
> (const_int 32764)))
> (const_int 4)
> (const_int 8))
>
> and drop the generic change. (The generic change would break many
> other ports.) I'll test this and see how it goes.
Well, I guess it still may fail and I strongly believe
insn_current_reference_address() should be changed too. The code in question
as I understand it
if (INSN_SHUID (branch) < INSN_SHUID (dest))
{
/* Forward branch. */
return (insn_last_address + insn_lengths[seq_uid]
- align_fuzz (seq, dest, length_unit_log, ~0));
}
else
{
/* Backward branch. */
return (insn_current_address
+ align_fuzz (dest, seq, length_unit_log, ~0));
}
tries to provide a threshold so we don't enter an endless loop trying to
shorten the branches. But this will only work as expected if
insn_last_address < insn_current_address. But the branch shortening can
happily end up with insn_last_address >= insn_current_address and thus the
branch maybe miscalculated depending on the compiled code, cause the
calculated forward branch distance is too small then.
If my original solution seems to strict, I would suggest this variation,
which should accomplish the intention:
if (INSN_SHUID (branch) < INSN_SHUID (dest))
{
/* Forward branch. */
return (insn_current_address - insn_default_length (branch)
- align_fuzz (seq, dest, length_unit_log, ~0));
}
else
{
/* Backward branch. */
return (insn_current_address
+ align_fuzz (dest, seq, length_unit_log, ~0));
}
This should provide the threshold in a reliable manner due to the subtraction
of insn_default_length(branch).
Franz.
More information about the Gcc-patches
mailing list