* RFA/RFC: GCC has an incorrect length for the ldc1 instruction
@ 2007-08-07 8:07 Nick Clifton
2007-08-07 9:54 ` Richard Sandiford
0 siblings, 1 reply; 6+ messages in thread
From: Nick Clifton @ 2007-08-07 8:07 UTC (permalink / raw)
To: echristo, richard; +Cc: gcc-patches
[-- Attachment #1: Type: text/plain, Size: 2368 bytes --]
Hi Eric, Hi Richard,
Another customer bug report has pointed out a problem with the MIPS
compiler. Compile the attached test case with:
mips64vrel-elf-gcc -mgp32 -mlong64 -march=vr5000 -O2 128195.c -S -dp
(I presume that this problem exists with other MIPS targets apart
from the mips64vrel-elf. It just so happens that this is the
toolchain that the customer is using).
Look at the assembler output. In particular:
ldc1 $f2,0($4) # 6 *movdf_hardfloat_32bit/3 [length = 8]
Note the assumed length of the ldc1 instruction. In the original
bug report this was a problem because the ldc1 instruction was
between an mfhi and a mult instruction, and gcc thought that this
was sufficient to act as a hilo interlock. This does not appear to
happen with the current mainline gcc sources, but I still think that
the incorrect length is a bug.
Tracking the problem through the code, I found that
mips_address_insns() was saying that it takes 2 instructions to
implement this rtl:
(mem:DF (reg:SI $4))
when in fact it only takes one. The patch below fixes this, in what
I hope is the correct way. I checked the patch by recompiling a
mips64vrel-elf toolchain and running a gcc testsuite regression test
for the default multilib and the vr5000/long64/gp32 multilib.
- There were no regressions. I am not sure if this covers all
eventualities though.
What do you think, should I apply the patch ?
Cheers
Nick
gcc/ChangeLog
2007-08-06 Nick Clifton <nickc@redhat.com>
* config/mips/mips.c (mips_address_insns): DFmode loads and
stores only take one instruction when hardware doubles are
supported.
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c (revision 127178)
+++ gcc/config/mips/mips.c (working copy)
@@ -1963,6 +1963,9 @@ mips_address_insns (rtx x, enum machine_
if (mode == BLKmode)
/* BLKmode is used for single unaligned loads and stores. */
factor = 1;
+ else if (mode == DFmode && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT)
+ /* Doubles can be accessed by a single instruction when the hardware supports it. */
+ factor = 1;
else
/* Each word of a multi-word value will be accessed individually. */
factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
[-- Attachment #2: 128195.c --]
[-- Type: application/octet-stream, Size: 276 bytes --]
#include <stdio.h>
extern void func (int, int, int);
int
main (void)
{
static long long1;
long long3;
static long long4;
static double * pd2;
static double * pd4;
func (1, (((! *pd2) >= *pd4) * ((long3 * long1) && long4)), 0);
return 0;
}
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: RFA/RFC: GCC has an incorrect length for the ldc1 instruction
2007-08-07 8:07 RFA/RFC: GCC has an incorrect length for the ldc1 instruction Nick Clifton
@ 2007-08-07 9:54 ` Richard Sandiford
2007-08-07 15:03 ` Nick Clifton
2007-08-10 7:15 ` Nick Clifton
0 siblings, 2 replies; 6+ messages in thread
From: Richard Sandiford @ 2007-08-07 9:54 UTC (permalink / raw)
To: Nick Clifton; +Cc: echristo, gcc-patches
Nick Clifton <nickc@redhat.com> writes:
> Hi Eric, Hi Richard,
>
> Another customer bug report has pointed out a problem with the MIPS
> compiler. Compile the attached test case with:
>
> mips64vrel-elf-gcc -mgp32 -mlong64 -march=vr5000 -O2 128195.c -S -dp
>
> (I presume that this problem exists with other MIPS targets apart
> from the mips64vrel-elf. It just so happens that this is the
> toolchain that the customer is using).
>
> Look at the assembler output. In particular:
>
> ldc1 $f2,0($4) # 6 *movdf_hardfloat_32bit/3 [length = 8]
>
> Note the assumed length of the ldc1 instruction. In the original
> bug report this was a problem because the ldc1 instruction was
> between an mfhi and a mult instruction, and gcc thought that this
> was sufficient to act as a hilo interlock. This does not appear to
> happen with the current mainline gcc sources, but I still think that
> the incorrect length is a bug.
>
> Tracking the problem through the code, I found that
> mips_address_insns() was saying that it takes 2 instructions to
> implement this rtl:
>
> (mem:DF (reg:SI $4))
>
> when in fact it only takes one. The patch below fixes this, in what
> I hope is the correct way. I checked the patch by recompiling a
> mips64vrel-elf toolchain and running a gcc testsuite regression test
> for the default multilib and the vr5000/long64/gp32 multilib.
> - There were no regressions. I am not sure if this covers all
> eventualities though.
>[...]
> Index: gcc/config/mips/mips.c
> ===================================================================
> --- gcc/config/mips/mips.c (revision 127178)
> +++ gcc/config/mips/mips.c (working copy)
> @@ -1963,6 +1963,9 @@ mips_address_insns (rtx x, enum machine_
> if (mode == BLKmode)
> /* BLKmode is used for single unaligned loads and stores. */
> factor = 1;
> + else if (mode == DFmode && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT)
> + /* Doubles can be accessed by a single instruction when the hardware supports it. */
> + factor = 1;
> else
> /* Each word of a multi-word value will be accessed individually. */
> factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
Unfortunately, this isn't quite right. DFmode moves still take
2 instructions when the target is a GPR. For MIPS I, they will
also take 2 instructions when the target is an FPR.
I think instead that mips_fetch_insns should try to prove that
the move does not need to be split, and tell mips_address_insns
about it. Does the patch below work for you?
(I think the 'R' thing is a bug fix. 'R' is only used in user asms
and is provided for compatibility with older compilers. I don't think
users will expect us to second-guess whether two separate loads or stores
are being used.)
I admit this isn't pretty, but I can't think of a prettier way off-hand.
Richard
gcc/
* config/mips/mips-protos.h (mips_address_insns): Add a boolean
argument.
(mips_fetch_insns): Delete in favor of...
(mips_load_store_insns): ...this new function.
* config/mips/mips.c (mips_address_insns): Add a boolean argument
to say whether multiword moves _might_ be split.
(mips_fetch_insns): Delete in favor of...
(mips_load_store_insns): ...this new function.
(mips_rtx_costs): Update the call to mips_address_insns.
(mips_address_cost): Likewise.
* config/mips/mips.md (length): Use mips_load_store_insns instead
of mips_fetch_insns.
* config/mips/constraints.md (R): Use mips_address_insns rather
than mips_fetch_insns. Assume that the move never needs to be split.
Index: gcc/config/mips/mips-protos.h
===================================================================
--- gcc/config/mips/mips-protos.h 2007-08-07 09:52:19.000000000 +0100
+++ gcc/config/mips/mips-protos.h 2007-08-07 10:41:24.000000000 +0100
@@ -140,9 +140,9 @@ struct mips16e_save_restore_info;
extern bool mips_symbolic_constant_p (rtx, enum mips_symbol_type *);
extern int mips_regno_mode_ok_for_base_p (int, enum machine_mode, int);
extern bool mips_stack_address_p (rtx, enum machine_mode);
-extern int mips_address_insns (rtx, enum machine_mode);
+extern int mips_address_insns (rtx, enum machine_mode, bool);
extern int mips_const_insns (rtx);
-extern int mips_fetch_insns (rtx);
+extern int mips_load_store_insns (rtx, rtx);
extern int mips_idiv_insns (void);
extern int fp_register_operand (rtx, enum machine_mode);
extern int lo_operand (rtx, enum machine_mode);
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c 2007-08-07 09:39:37.000000000 +0100
+++ gcc/config/mips/mips.c 2007-08-07 10:45:29.000000000 +0100
@@ -1950,22 +1950,26 @@ mips16_unextended_reference_p (enum mach
/* Return the number of instructions needed to load or store a value
- of mode MODE at X. Return 0 if X isn't valid for MODE.
+ of mode MODE at X. Return 0 if X isn't valid for MODE. Assume that
+ multiword moves may need to be split into word moves if MIGHT_SPLIT_P,
+ otherwise assume that a single load or store is enough.
For mips16 code, count extended instructions as two instructions. */
int
-mips_address_insns (rtx x, enum machine_mode mode)
+mips_address_insns (rtx x, enum machine_mode mode, bool might_split_p)
{
struct mips_address_info addr;
int factor;
- if (mode == BLKmode)
- /* BLKmode is used for single unaligned loads and stores. */
- factor = 1;
- else
- /* Each word of a multi-word value will be accessed individually. */
+ /* BLKmode is used for single unaligned loads and stores and should
+ not count as a multiword mode. (GET_MODE_SIZE (BLKmode) is pretty
+ meaningless, so we have to single it out as a special case one way
+ or the other.) */
+ if (mode != BLKmode && might_split_p)
factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ else
+ factor = 1;
if (mips_classify_address (&addr, x, mode, false))
switch (addr.type)
@@ -2061,14 +2065,30 @@ mips_const_insns (rtx x)
}
-/* Return the number of instructions needed for memory reference X.
- Count extended mips16 instructions as two instructions. */
+/* Return the number of instructions needed to implement INSN,
+ given that it loads from or stores to MEM. Count extended
+ mips16 instructions as two instructions. */
int
-mips_fetch_insns (rtx x)
+mips_load_store_insns (rtx mem, rtx insn)
{
- gcc_assert (MEM_P (x));
- return mips_address_insns (XEXP (x, 0), GET_MODE (x));
+ enum machine_mode mode;
+ bool might_split_p;
+ rtx set;
+
+ gcc_assert (MEM_P (mem));
+ mode = GET_MODE (mem);
+
+ /* Try to prove that INSN does not need to be split. */
+ might_split_p = true;
+ if (GET_MODE_BITSIZE (mode) == 64)
+ {
+ set = single_set (insn);
+ if (set && !mips_split_64bit_move_p (SET_DEST (set), SET_SRC (set)))
+ might_split_p = false;
+ }
+
+ return mips_address_insns (XEXP (mem, 0), mode, might_split_p);
}
@@ -2818,7 +2838,7 @@ mips_rtx_costs (rtx x, int code, int out
/* If the address is legitimate, return the number of
instructions it needs. */
rtx addr = XEXP (x, 0);
- int n = mips_address_insns (addr, GET_MODE (x));
+ int n = mips_address_insns (addr, GET_MODE (x), true);
if (n > 0)
{
*total = COSTS_N_INSNS (n + 1);
@@ -2973,7 +2993,7 @@ mips_rtx_costs (rtx x, int code, int out
static int
mips_address_cost (rtx addr)
{
- return mips_address_insns (addr, SImode);
+ return mips_address_insns (addr, SImode, false);
}
\f
/* Return one word of double-word value OP, taking into account the fixed
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md 2007-08-07 09:53:28.000000000 +0100
+++ gcc/config/mips/mips.md 2007-08-07 10:28:12.000000000 +0100
@@ -360,9 +360,9 @@ (define_attr "length" ""
(eq_attr "type" "const")
(symbol_ref "mips_const_insns (operands[1]) * 4")
(eq_attr "type" "load,fpload")
- (symbol_ref "mips_fetch_insns (operands[1]) * 4")
+ (symbol_ref "mips_load_store_insns (operands[1], insn) * 4")
(eq_attr "type" "store,fpstore")
- (symbol_ref "mips_fetch_insns (operands[0]) * 4")
+ (symbol_ref "mips_load_store_insns (operands[0], insn) * 4")
;; In the worst case, a call macro will take 8 instructions:
;;
Index: gcc/config/mips/constraints.md
===================================================================
--- gcc/config/mips/constraints.md 2007-08-07 09:52:55.000000000 +0100
+++ gcc/config/mips/constraints.md 2007-08-07 09:53:14.000000000 +0100
@@ -151,7 +151,7 @@ (define_constraint "Q"
(define_memory_constraint "R"
"An address that can be used in a non-macro load or store."
(and (match_code "mem")
- (match_test "mips_fetch_insns (op) == 1")))
+ (match_test "mips_address_insns (XEXP (op, 0), mode, false) == 1")))
(define_constraint "S"
"@internal
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: RFA/RFC: GCC has an incorrect length for the ldc1 instruction
2007-08-07 9:54 ` Richard Sandiford
@ 2007-08-07 15:03 ` Nick Clifton
2007-08-10 7:15 ` Nick Clifton
1 sibling, 0 replies; 6+ messages in thread
From: Nick Clifton @ 2007-08-07 15:03 UTC (permalink / raw)
To: Nick Clifton, echristo, gcc-patches, richard
Hi Richard,
> Unfortunately, this isn't quite right. DFmode moves still take
> 2 instructions when the target is a GPR. For MIPS I, they will
> also take 2 instructions when the target is an FPR.
Darn, I was afraid that there might be a case like that.
> I think instead that mips_fetch_insns should try to prove that
> the move does not need to be split, and tell mips_address_insns
> about it. Does the patch below work for you?
It does. I also tested the patch on the slightly older sources that make up
the toolchain that was sent to our customer (which compiles the test case with
only one ldc1 instruction between a mfhi and a mult instruction) and it fixes
that toolchain as well.
Cheers
Nick
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: RFA/RFC: GCC has an incorrect length for the ldc1 instruction
2007-08-07 9:54 ` Richard Sandiford
2007-08-07 15:03 ` Nick Clifton
@ 2007-08-10 7:15 ` Nick Clifton
2007-08-10 7:58 ` Richard Sandiford
1 sibling, 1 reply; 6+ messages in thread
From: Nick Clifton @ 2007-08-10 7:15 UTC (permalink / raw)
To: Nick Clifton, echristo, gcc-patches, richard
Hi Richard,
> I think instead that mips_fetch_insns should try to prove that
> the move does not need to be split, and tell mips_address_insns
> about it. Does the patch below work for you?
Yes.
> gcc/
> * config/mips/mips-protos.h (mips_address_insns): Add a boolean
> argument.
> (mips_fetch_insns): Delete in favor of...
> (mips_load_store_insns): ...this new function.
> * config/mips/mips.c (mips_address_insns): Add a boolean argument
> to say whether multiword moves _might_ be split.
> (mips_fetch_insns): Delete in favor of...
> (mips_load_store_insns): ...this new function.
> (mips_rtx_costs): Update the call to mips_address_insns.
> (mips_address_cost): Likewise.
> * config/mips/mips.md (length): Use mips_load_store_insns instead
> of mips_fetch_insns.
> * config/mips/constraints.md (R): Use mips_address_insns rather
> than mips_fetch_insns. Assume that the move never needs to be split.
Are you going to apply this version of the patch, or may I do it on your behalf ?
Cheers
Nick
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: RFA/RFC: GCC has an incorrect length for the ldc1 instruction
2007-08-10 7:15 ` Nick Clifton
@ 2007-08-10 7:58 ` Richard Sandiford
2007-08-10 15:41 ` Richard Sandiford
0 siblings, 1 reply; 6+ messages in thread
From: Richard Sandiford @ 2007-08-10 7:58 UTC (permalink / raw)
To: Nick Clifton; +Cc: echristo, gcc-patches
Nick Clifton <nickc@redhat.com> writes:
> Hi Richard,
>> gcc/
>> * config/mips/mips-protos.h (mips_address_insns): Add a boolean
>> argument.
>> (mips_fetch_insns): Delete in favor of...
>> (mips_load_store_insns): ...this new function.
>> * config/mips/mips.c (mips_address_insns): Add a boolean argument
>> to say whether multiword moves _might_ be split.
>> (mips_fetch_insns): Delete in favor of...
>> (mips_load_store_insns): ...this new function.
>> (mips_rtx_costs): Update the call to mips_address_insns.
>> (mips_address_cost): Likewise.
>> * config/mips/mips.md (length): Use mips_load_store_insns instead
>> of mips_fetch_insns.
>> * config/mips/constraints.md (R): Use mips_address_insns rather
>> than mips_fetch_insns. Assume that the move never needs to be split.
>
> Are you going to apply this version of the patch, or may I do it on
> your behalf ?
Sorry for the delay. I've been really busy recently, and only started
running tests for the patch yesterday. I'll commit it today or tomorrow
if the results are OK.
Richard
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: RFA/RFC: GCC has an incorrect length for the ldc1 instruction
2007-08-10 7:58 ` Richard Sandiford
@ 2007-08-10 15:41 ` Richard Sandiford
0 siblings, 0 replies; 6+ messages in thread
From: Richard Sandiford @ 2007-08-10 15:41 UTC (permalink / raw)
To: Nick Clifton; +Cc: echristo, gcc-patches
Richard Sandiford <richard@codesourcery.com> writes:
> Nick Clifton <nickc@redhat.com> writes:
>> Hi Richard,
>>> gcc/
>>> * config/mips/mips-protos.h (mips_address_insns): Add a boolean
>>> argument.
>>> (mips_fetch_insns): Delete in favor of...
>>> (mips_load_store_insns): ...this new function.
>>> * config/mips/mips.c (mips_address_insns): Add a boolean argument
>>> to say whether multiword moves _might_ be split.
>>> (mips_fetch_insns): Delete in favor of...
>>> (mips_load_store_insns): ...this new function.
>>> (mips_rtx_costs): Update the call to mips_address_insns.
>>> (mips_address_cost): Likewise.
>>> * config/mips/mips.md (length): Use mips_load_store_insns instead
>>> of mips_fetch_insns.
>>> * config/mips/constraints.md (R): Use mips_address_insns rather
>>> than mips_fetch_insns. Assume that the move never needs to be split.
>>
>> Are you going to apply this version of the patch, or may I do it on
>> your behalf ?
>
> Sorry for the delay. I've been really busy recently, and only started
> running tests for the patch yesterday. I'll commit it today or tomorrow
> if the results are OK.
Now committed after testing on mipsisa32r2-elfoabi.
Richard
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2007-08-10 15:41 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-08-07 8:07 RFA/RFC: GCC has an incorrect length for the ldc1 instruction Nick Clifton
2007-08-07 9:54 ` Richard Sandiford
2007-08-07 15:03 ` Nick Clifton
2007-08-10 7:15 ` Nick Clifton
2007-08-10 7:58 ` Richard Sandiford
2007-08-10 15:41 ` Richard Sandiford
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).