Article View: gnu.gcc.bug
Article #6335GCC patch #6
From: buc
Date: Wed, 20 Dec 1995 00:00
Date: Wed, 20 Dec 1995 00:00
190 lines
6693 bytes
6693 bytes
*emit-rtl.c (gen_lowpart_common): Handle lowpart on special hard regs
Dmitry K. Butskoy (buc@stu.spb.su)
GCC: 2.7.2
CPU: big-endians
(Our configuration:
CPU: mc68030/mc68882
Computer: BESTA (similar to `mot3300 delta')
System: SVR3.1 (similar to sysV68)
asm: SGS System V/68 R2V1 syntax )
I have found a better way to fix the problem reported by
`GCC patch v2' for GCC.2.7.0.
There is `gen_lowpart_common' function in emit-rtl.c . This
function does:
****
/* Return a value representing some low-order bits of X, where the number
of low-order bits is given by MODE. Note that no conversion is done
between floating-point and fixed-point values, rather, the bit
representation is returned.
This function handles the cases in common between gen_lowpart, below,
and two variants in cse.c and combine.c. These are the cases that can
be safely handled at all points in the compilation.
If this is not a case we can handle, return 0. */
rtx
gen_lowpart_common (mode, x)
enum machine_mode mode;
register rtx x;
{
****
To make this work `gen_lowpart_common()' computes a offset
of low part in X . To store this offset variable `word' is used.
All is OK, but for cases when X is a COMPLEX_REAL type
represented by hard float-point registers, the value of `word' computes
incorrectly. E.g. (for m68k):
** BIG ENDIAN **
UNITS_PER_WORD = 4 ( o o o o )
example #1 (memory):
.__________complex__double__________.
.____double_____. .____double_____.
. . . o o o o o o o o o o o o o o o o . . .
$0 $4 $8 $12
,__high__part___, ,___low__part___,
^ word = 2 (= sizeof(high part) / UNITS_PER_WORD)
example #2 (data registers):
.__________complex__double__________.
.____double_____. .____double_____.
. . . o-o-o-o o-o-o-o o-o-o-o o-o-o-o . . .
reg0 reg1 reg2 reg3
,__high__part___, ,___low__part___,
^ word = 2 (= sizeof(high part) / UNITS_PER_WORD)
example #3 (float-point registers):
.__________complex__double__________.
.____double_____. .____double_____.
. . . xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx . . .
fp_reg0 fp_reg1
,__high__part___, ,___low__part___,
^ word = 1 (!= sizeof(high part) / UNITS_PER_WORD)
At the last example sizeof(high part) always is `1' in its context,
independent of the used machine mode (SFmode, DFmode or XFmode).
I think there is some reasons to handle last case (example #3)
by `gen_lowpart_common()' . For example, it is actual for passing
complex real arguments by fp registers or returning complex real value
by fp registers.
I tried to return complex reals such way on m68k. For test,
typedef __complex double foo;
foo bar(foo a , foo b ) {
return a+b;
}
instead of evident result,
file "bar.c"
even
global bar
bar:
fmov.d 4(%sp),%fp0
fadd.d 20(%sp),%fp0
fmov.d 12(%sp),%fp1
fadd.d 28(%sp),%fp1
rts
nop
it produce,
file "bar.c"
even
global bar
bar:
fmov.d 4(%sp),%fp0
fadd.d 20(%sp),%fp0
fmov.d 12(%sp),%fp2
fadd.d 28(%sp),%fp2
rts
nop
where instead of fp0/fp1 pair fp0+fp2 are used.
To fix the problem considered, one should recompute the `word' value
for case `X' is a `REG' (register). When REG is not a special hard
register, it must produce the same value as a usual way.
To recompute `word' value I use a `HARD_REGNO_NREGS' macro, which
is defined in all tm-headers:
****
/* Return number of consecutive hard regs needed starting at reg REGNO
to hold something of mode MODE.
This is ordinarily the length in words of a value of mode MODE
but can be less for certain modes in special long registers.
#define HARD_REGNO_NREGS(REGNO, MODE) \
****
Hear is a patch for emit-rtl.c,
`diff -p -c4':
*** emit-rtlO.c Fri Dec 8 19:23:02 1995
--- emit-rtl.c Mon Dec 18 17:43:29 1995
*************** gen_lowpart_common (mode, x)
*** 611,618 ****
--- 611,629 ----
? SUBREG_REG (x)
: gen_rtx (SUBREG, mode, SUBREG_REG (x), SUBREG_WORD (x)));
else if (GET_CODE (x) == REG)
{
+ /* Recomputing `word' value for a case of hard registers.
+ Some special long registers can store modes which are
+ more wide than UNITS_PER_WORD . */
+ /* We check first two conditions below as above, else `word' always
+ has value of 0 . */
+ if (WORDS_BIG_ENDIAN
+ && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
+ && REGNO (x) < FIRST_PSEUDO_REGISTER)
+ word = HARD_REGNO_NREGS (REGNO (x), GET_MODE (x)) -
+ HARD_REGNO_NREGS (REGNO (x), mode) ;
+
/* If the register is not valid for MODE, return 0. If we don't
do this, there is no way to fix up the resulting REG later.
But we do do this if the current REG is not valid for its
mode. This latter is a kludge, but is required due to the
(I use `REGNO(x)' in `HARD_REGNO_NREGS (REGNO (x), mode)' to get
the number of the hard regs the same class as X ).
This variant works on m68k, but I`m not sure about other big-endian
machines.
I think, my previous message about the problem considered
(with subject `GCC patch v2') may be removed.
Dmitry K. Butskoy,
Saint-Petersburg State Technical University,
St. Petersburg, Russia.
<buc@stu.spb.su>
Technical Details
Message-ID:
<AAJq-rmyI0@stu.spb.su>Path:
arc1-ca.pugleaf.net!unknown!not-for-mailShow Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 113d02,785ece42a51bdc8b,start X-Google-Attributes: gid113d02,public From: buc@stu.spb.SU Subject: GCC patch #6 Date: 1995/12/20 Message-ID: <AAJq-rmyI0@stu.spb.su> X-Deja-AN: 122393822 distribution: gnu sender: daemon@cis.ohio-state.edu organization: State Technical University of St. Petersburg newsgroups: gnu.gcc.bug