GCC 2.95.2 for AIX handles 'long long' incorrectly
Franz Sirl
Franz.Sirl-kernel@lauterbach.com
Sat Mar 11 13:44:00 GMT 2000
Am Fri, 10 Mar 2000 schrieb Franz Sirl:
>At 02:38 09.03.00, Geoff Keating wrote:
>
>>Wayne Scott <wscott@ichips.intel.com> writes:
>>
>> > Attached is a simple testcase of a function that returns a 'long long'
>> >
>> > GCC version 2.95.2 produced incorrect results when the optimizer is
>> > enabled.
>> >
>> > # this is a IBM 397 with 1G of memory
>> > $ uname -a
>> > AIX pdxcs566 1 4 000111179400
>>
>>This appears to be fixed in the newppc-branch and so will be fixed in
>>the next release. I'm not sure what patch fixed it or whether it's
>>fixed in the mainline CVS.
>
>The patch that fixed it is Richard Hendersons stupid.c-die-die-die patch. I
>tried parts of the patch on the gcc-2_95-branch and this is the one that
>fixes the testcase:
>
>Index: stmt.c
>===================================================================
>RCS file: /cvs/gcc/egcs/gcc/stmt.c,v
>retrieving revision 1.71.4.4
>diff -u -p -r1.71.4.4 stmt.c
>--- stmt.c 2000/01/07 22:41:20 1.71.4.4
>+++ stmt.c 2000/03/10 11:56:01
>@@ -2521,7 +2521,8 @@ expand_value_return (val)
> #endif
> emit_move_insn (return_reg, val);
> }
>- if (GET_CODE (return_reg) == REG
>+ if (obey_regdecls
>+ && GET_CODE (return_reg) == REG
> && REGNO (return_reg) < FIRST_PSEUDO_REGISTER)
> emit_insn (gen_rtx_USE (VOIDmode, return_reg));
> /* Handle calls that return values in multiple non-contiguous locations.
>
>Somehow the USEs confuse other parts of the compiler, but unfortunately the
>patch breaks the bootstrap of the gcc-2_95-branch :-(, so I'm probably
>something missing here.
>
>The question now is how do we want to proceed here? Should stupid.c die in
>the gcc-2_95-branch too? Or should I try to find another solution, possibly
>based on the above patch and other parts of the stupid.c patch? Any
>ideas/hints?
Ugh, actually the bug is totally different and Richard's stupid.c-diediedie
patch just hides the real problem in emit-rtl.c:operand_subword(). What happens
is that during jump_optimize the compiler gets confused about the high and low
words of a reg:DI if it contains a hardreg. If the generation of USEs is
suppressed as without stupid.c the compiler uses pseudos and just hides the bug.
I removed this optimization:
Index: emit-rtl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/emit-rtl.c,v
retrieving revision 1.59.4.4
diff -u -p -r1.59.4.4 emit-rtl.c
--- emit-rtl.c 1999/08/11 07:28:52 1.59.4.4
+++ emit-rtl.c 2000/03/11 20:47:08
@@ -1256,19 +1256,8 @@ operand_subword (op, i, validate_address
&& (! HARD_REGNO_MODE_OK (REGNO (op), word_mode)
|| ! HARD_REGNO_MODE_OK (REGNO (op) + i, word_mode)))
return 0;
- else if (REGNO (op) >= FIRST_PSEUDO_REGISTER
- || (REG_FUNCTION_VALUE_P (op)
- && rtx_equal_function_value_matters)
- /* We want to keep the stack, frame, and arg pointers
- special. */
- || op == frame_pointer_rtx
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
- || op == arg_pointer_rtx
-#endif
- || op == stack_pointer_rtx)
- return gen_rtx_SUBREG (word_mode, op, i);
else
- return gen_rtx_REG (word_mode, REGNO (op) + i);
+ return gen_rtx_SUBREG (word_mode, op, i);
}
else if (GET_CODE (op) == SUBREG)
return gen_rtx_SUBREG (word_mode, SUBREG_REG (op), i + SUBREG_WORD (op));
and everything is OK afterwards. The compiler bootstraps and passes the
testsuite without regressions on powerpc-linux-gnu.
I used Wayne's example slightly modified:
typedef unsigned long long uint64;
const uint64 bigconst = 1ULL << 34;
int a = 1;
static
uint64 getmask(void)
{
if (a)
return bigconst;
else
return 0;
}
main()
{
uint64 f = getmask();
if (f != bigconst) abort ();
exit (0);
}
Without my patch this was the offending RTL after jump:
(insn 51 53 52 (parallel[
(set (subreg:SI (reg:DI 95) 0)
(and:SI (subreg:SI (reg:DI 89) 0)
(reg:SI 3 r3)))
(clobber (scratch:CC))
] ) -1 (nil)
(expr_list:REG_NO_CONFLICT (reg:DI 89)
(expr_list:REG_NO_CONFLICT (reg/i:DI 3 r3)
(nil))))
(insn 52 51 55 (parallel[
(set (subreg:SI (reg:DI 95) 1)
(and:SI (subreg:SI (reg:DI 89) 1)
(reg:SI 4 r4)))
(clobber (scratch:CC))
] ) -1 (nil)
(expr_list:REG_NO_CONFLICT (reg:DI 89)
(expr_list:REG_NO_CONFLICT (reg/i:DI 3 r3)
(nil))))
(insn 55 52 57 (set (reg:DI 95)
(reg:DI 95)) -1 (nil)
(insn_list:REG_RETVAL 53 (expr_list:REG_EQUAL (and:DI (reg:DI 89)
(reg/i:DI 3 r3))
(nil))))
(insn 57 55 59 (set (reg:DI 89)
(reg:DI 95)) -1 (nil)
(nil))
(insn 59 57 34 (set (reg/i:DI 3 r3)
(reg:DI 89)) -1 (nil)
(nil))
(insn 34 59 0 (use (reg/i:DI 3 r3)) -1 (nil)
(nil))
Note that the subreg index 0 in (and:SI (subreg:SI (reg:DI 89) 0) corresponds
to the index used in calling operand_subword. It seems this index always has
the meaning 0==lowpart and 1==highpart, in contrary to the comment before
operand_subword()... Compared to that the rN+0 is the high part of a hardreg
and rN+1 is the lowpart on PPC.
Now with my patch the RTL looks like this:
(insn 52 54 53 (parallel[
(set (subreg:SI (reg:DI 96) 0)
(and:SI (subreg:SI (reg:DI 88) 0)
(subreg:SI (reg:DI 90) 0)))
(clobber (scratch:CC))
] ) -1 (nil)
(expr_list:REG_NO_CONFLICT (reg:DI 88)
(expr_list:REG_NO_CONFLICT (reg:DI 90)
(nil))))
(insn 53 52 56 (parallel[
(set (subreg:SI (reg:DI 96) 1)
(and:SI (subreg:SI (reg:DI 88) 1)
(subreg:SI (reg:DI 90) 1)))
(clobber (scratch:CC))
] ) -1 (nil)
(expr_list:REG_NO_CONFLICT (reg:DI 88)
(expr_list:REG_NO_CONFLICT (reg:DI 90)
(nil))))
(insn 56 53 58 (set (reg:DI 96)
(reg:DI 96)) -1 (nil)
(insn_list:REG_RETVAL 54 (expr_list:REG_EQUAL (and:DI (reg:DI 88)
(reg:DI 90))
(nil))))
(insn 58 56 0 (set (reg/i:DI 3 r3)
(reg:DI 96)) -1 (nil)
(nil))
I did play with other solutions involving WORDS_BIG_ENDIAN, but I couldn't get
it to work. What happens now is that operand subword returns (subreg:SI
(reg/i:DI 3 r3) 0)/(subreg:SI (reg/i:DI 3 r3) 1) instead of the wrong (reg:SI 3
r3)/(reg:SI 4 r4).
A backtrace:
Breakpoint 2, operand_subword (op=0x1034b0b8, i=0, validate_address=1,
mode=DImode) at ../../../gcc295/gcc/emit-rtl.c:1260
1260 return gen_rtx_SUBREG (word_mode, op, i);
(gdb) p debug_rtx(op)
(reg/i:DI 3 r3)
$19 = void
(gdb) l
1255 if (REGNO (op) < FIRST_PSEUDO_REGISTER
1256 && (! HARD_REGNO_MODE_OK (REGNO (op), word_mode)
1257 || ! HARD_REGNO_MODE_OK (REGNO (op) + i, word_mode)))
1258 return 0;
1259 else
1260 return gen_rtx_SUBREG (word_mode, op, i);
1261 }
1262 else if (GET_CODE (op) == SUBREG)
1263 return gen_rtx_SUBREG (word_mode, SUBREG_REG (op), i + SUBREG_WORD (op));
1264 else if (GET_CODE (op) == CONCAT)
(gdb) bt
#0 operand_subword (op=0x1034b0b8, i=0, validate_address=1, mode=DImode) at ../../../gcc295/gcc/emit-rtl.c:1260
#1 0x100c4500 in operand_subword_force (op=0x1034b0b8, i=0, mode=DImode) at ../../../gcc295/gcc/emit-rtl.c:1525
#2 0x1009da84 in expand_binop (mode=DImode, binoptab=0x10355d10, op0=0x10348de8, op1=0x1034b0b8, target=0x10349160,
unsignedp=0, methods=OPTAB_LIB_WIDEN) at ../../../gcc295/gcc/optabs.c:1002
#3 0x10096114 in expand_and (op0=0x1034b0b8, op1=0x10348de8, target=0x10348de8) at ../../../gcc295/gcc/expmed.c:4051
#4 0x101229c8 in jump_optimize_1 (f=0x1034ae78, cross_jump=0, noop_moves=0, after_regscan=1, mark_labels_only=0)
at ../../../gcc295/gcc/jump.c:1175
#5 0x10120a0c in jump_optimize (f=0x1034ae78, cross_jump=0, noop_moves=0, after_regscan=1)
at ../../../gcc295/gcc/jump.c:143
#6 0x10006bdc in rest_of_compilation (decl=0x1035d620) at ../../../gcc295/gcc/toplev.c:3845
#7 0x1029bc60 in finish_function (nested=0) at ../../../gcc295/gcc/c-decl.c:7269
#8 0x102841d0 in yyparse () at c-parse.y:313
#9 0x10005420 in compile_file (name=0x7ffffdab "ret64.i") at ../../../gcc295/gcc/toplev.c:3267
#10 0x1000a730 in main (argc=11, argv=0x7ffffc74) at ../../../gcc295/gcc/toplev.c:5444
#11 0xff0a7dc in Letext () at ../sysdeps/powerpc/elf/libc-start.c:106
(gdb) fin
Run till exit from #0 operand_subword (op=0x1034b0b8, i=0, validate_address=1, mode=DImode)
at ../../../gcc295/gcc/emit-rtl.c:1260
0x100c4500 in operand_subword_force (op=0x1034b0b8, i=0, mode=DImode) at ../../../gcc295/gcc/emit-rtl.c:1525
1525 rtx result = operand_subword (op, i, 1, mode);
Value returned is $20 = 0x10349190
(gdb) p debug_rtx(0x10349190)
(subreg:SI (reg/i:DI 3 r3) 0)
$21 = void
Does anyone have an idea for an other/better solution?
Franz.
More information about the Gcc-bugs
mailing list