Path: meolyon!mwhh!news.Hanse.DE!news.rrz.uni-hamburg.de!news.dkrz.de!news.tu-harburg.de!news.dfn.de!gina.zfn.uni-bremen.de!marvin.pc-labor.uni-bremen.de!news.uni-stuttgart.de!news.belwue.de!fu-berlin.de!news.mathworks.com!newsfeed.internetmci.com!news.sprintlink.net!cs.utexas.edu!math.ohio-state.edu!cis.ohio-state.edu!ida.liu.se!mpe From: mpe@ida.liu.se (Mikael Pettersson) Newsgroups: gnu.gcc.bug Subject: gcc 2.7.0 bug PowerPC Date: 10 Aug 1995 18:27:43 -0400 Organization: GNUs Not Usenet Lines: 132 Sender: daemon@cis.ohio-state.edu Approved: bug-gcc@prep.ai.mit.edu Distribution: gnu Message-ID: <9508102226.AA11314@sen14.ida.liu.se> GCC 2.7.0, configured for "powerpc-parsytec-parix", generates incorrect code for the BUG function below. This happens both with and without -O. The problem is that the first word of array "tmp118" has been given the same address in the activation record as the last word of array "tmp117". /* bug.c */ #include <stdio.h> extern void gc(void*), print(void*); char *sp_low, *sp_high; void BUG(void) { { char mySP; if( &mySP < sp_low ) { void *tmp119[5]; gc(tmp119); return; } } { void *tmp115[2]; tmp115[0] = (void*)256; tmp115[1] = (void*)64; { void *tmp116[2]; tmp116[0] = (void*)257; tmp116[1] = tmp115; { void *tmp117[3]; tmp117[0] = (void*)515; tmp117[1] = (void*)2; tmp117[2] = tmp116; { void *tmp118[2]; tmp118[0] = (void*)260; /* overwrites tmp117[2] */ tmp118[1] = tmp117; print(tmp118); } } } } } void gc(void *ignore) {} void print(void *x) { if( (char*)x < sp_low || (char*)x > sp_high ) { printf("%u", x); } else { unsigned hdr = *(unsigned*)x; unsigned slots; void **xx; printf("%u(", hdr & 63); slots = hdr >> 8; xx = (void**)x + 1; if( slots > 0 ) while( print(*xx++), --slots > 0 ) printf(", "); printf(")"); } } int main(void) { char mySP; sp_high = &mySP; sp_low = &mySP - 4096; BUG(); printf("\n"); return 0; } The program outputs: 4(3(2, 260)) while it _should_ output: 4(3(2, 1(0(64)))) This is what gcc -O -S generates for function BUG: .align 2 .globl BUG .globl .BUG .csect BUG[DS] BUG: .long .BUG, TOC[tc0], 0 .csect .text[PR] .BUG: mflr 0 stw 0,8(1) stwu 1,-96(1) lwz 9,LC..4(2) lwz 9,0(9) addi 0,1,56 cmplw 1,0,9 bc 4,4,L..14 addi 3,1,64 bl .gc cror 31,31,31 b L..13 L..14: li 0,256 stw 0,64(1) /* tmp115[0] = 256 */ li 0,64 stw 0,68(1) /* tmp115[1] = 64 */ li 0,257 stw 0,72(1) /* tmp116[0] = 257 */ addi 0,1,64 stw 0,76(1) /* tmp116[1] = &tmp115 */ li 0,515 stw 0,80(1) /* tmp117[0] = 515 */ li 0,2 stw 0,84(1) /* tmp117[1] = 2 */ li 0,260 /* no asignment to tmp117[2] ?? */ stw 0,88(1) /* tmp118[0] = 260 OVERWRITES tmp117[2] */ addi 0,1,80 stw 0,92(1) /* tmp118[1] = &tmp117 */ addi 3,1,88 bl .print /* print(&tmp118) */ cror 31,31,31 L..13: addi 1,1,96 lwz 0,8(1) mtlr 0 blr Path: meolyon!mwhh!news.Hanse.DE!news.rrz.uni-hamburg.de!news.dkrz.de!news.tu-harburg.de!news.dfn.de!Germany.EU.net!howland.reston.ans.net!math.ohio-state.edu!magnus.acs.ohio-state.edu!cis.ohio-state.edu!meolyon.hanse.DE!amylaar From: amylaar@meolyon.hanse.DE (Joern Rennecke) Newsgroups: gnu.gcc.bug Subject: Re: gcc 2.7.0 bug HP-PA (bug fix) Date: 9 Sep 1995 15:37:05 -0400 Organization: GNUs Not Usenet Lines: 343 Sender: daemon@cis.ohio-state.edu Approved: bug-gcc@prep.ai.mit.edu Distribution: gnu Message-ID: <m0srTmG-000DkHC@meolyon> ~Newsgroups: gnu.gcc.bug Path: amylaar ~From: amylaar@meolyon.hanse.de (Joern Rennecke) ~Subject: Re: gcc 2.7.0 bug HP-PA (bug fix) Distribution: gnu Organization: Private site running Linux Message-ID: <1995Sep9.173310.4622@meolyon.hanse.de> ~References: <9508101742.AA11105@sen14.ida.liu.se> ~Date: Sat, 9 Sep 1995 17:33:10 GMT mpe@ida.liu.se (Mikael Pettersson) writes: >GCC 2.7.0, configured with --build=hppa1.1-hp-hpux9.05 >and --with-gnu-as (from gnu binutils 2.5.2), miscompiles >the following program (when not optimizing, -O0): >/* bug.c */ >#include <stdio.h> >void rml_gc(void) {} >char *rmlSPLIM; >static void sclam826(unsigned *tmp1509) >{ > char mySP; > if( &mySP > rmlSPLIM ) { > void *tmp1527[3]; > rml_gc(); > } > { > unsigned tmp796 = *tmp1509; > unsigned tmp1510[5]; > printf("0x%x\n", tmp796); > tmp1510[4] = 0x55555555; > printf("0x%x\n", tmp796); /* tmp796 is wrong here */ > } >} >int main(void) >{ > unsigned tmp1509; > rmlSPLIM = (char*)&tmp1509 + 4096; > tmp1509 = 0xaaaaaaaa; > sclam826(&tmp1509); > return 0; >} >The (incorrect) output of the program is: >0xaaaaaaaa >0x55555555 >The assembly code for sclam826() is: > .align 4 > .PARAM sclam826,ARGW0=GR >sclam826 > .PROC > .CALLINFO FRAME=192,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3 > .ENTRY > stw %r2,-20(0,%r30) > copy %r3,%r1 > copy %r30,%r3 > stwm %r1,192(0,%r30) > stw %r26,-36(0,%r3) > addil LR'rmlSPLIM-$global$,%r27 > ldo RR'rmlSPLIM-$global$(%r1),%r19 > ldw 0(0,%r19),%r20 > ldo 8(%r3),%r19 > comb,>>=,n %r20,%r19,L$0003 > .CALL > bl rml_gc,%r2 > nop >L$0003 > ldw -36(0,%r3),%r19 > ldw 0(0,%r19),%r20 > stw %r20,32(0,%r3) /* ok */ > ldil LR'L$C0000,%r19 > ldo RR'L$C0000(%r19),%r26 > ldw 32(0,%r3),%r25 /* ok */ > .CALL ARGW0=GR,ARGW1=GR > bl printf,%r2 > nop > ldil L'1431655765,%r20 > ldo R'1431655765(%r20),%r19 > stw %r19,32(0,%r3) /* BUG HERE */ > ldil LR'L$C0000,%r19 > ldo RR'L$C0000(%r19),%r26 > ldw 32(0,%r3),%r25 /* wrong value now */ > .CALL ARGW0=GR,ARGW1=GR > bl printf,%r2 > nop >L$0002 > ldw -20(0,%r3),%r2 > ldo 64(%r3),%r30 > ldwm -64(0,%r30),%r3 > bv,n 0(%r2) > .EXIT > .PROCEND >As one can see from the lines marked /* ok */ and /* BUG HERE */, >GCC has placed "tmp796" and "tmp1510[4]" in the same location >in the activation record. The underlying problem seems to be present for all targets with FRAME_GROWS_DOWNWARD un#defined. Fix appended. Joern Rennecke *** gcc-2.7.0/function.c Sat Jul 8 01:56:26 1995 --- gcc-2.7.0-x/function.c Sat Sep 9 19:26:59 1995 *************** static tree blocks_nreverse PROTO((tree) *** 439,444 **** --- 439,445 ---- static int all_blocks PROTO((tree, tree *)); static int *record_insns PROTO((rtx)); static int contains PROTO((rtx, int *)); + static rtx assign_stack_local2 PROTO((enum machine_mode, int, int, int *)); /* Pointer to chain of `struct function' for containing functions. */ struct function *outer_function_chain; *************** get_frame_size () *** 638,643 **** --- 639,646 ---- #endif } + int dummy_slotsize; + /* Allocate a stack slot of SIZE bytes and return a MEM rtx for it with machine mode MODE. *************** assign_stack_local (mode, size, align) *** 654,662 **** --- 657,676 ---- int size; int align; { + return assign_stack_local2(mode, size, align, &dummy_slotsize); + } + + rtx + assign_stack_local2 (mode, size, align, sizep) + enum machine_mode mode; + int size; + int align; + int *sizep; + { register rtx x, addr; int bigend_correction = 0; int alignment; + int frame_offset_old; if (align == 0) { *************** assign_stack_local (mode, size, align) *** 672,677 **** --- 686,697 ---- else alignment = align / BITS_PER_UNIT; + /* All space allocated on the frame has to be accounted for in the + allocated slots sizes, combine_temp_slots won't think that adjacent + slots really are adjacent. OTOH, having stack slots start before their + address calls for trouble, thus the alignment padding is added to the + size of the slot the padding is aligned with. */ + frame_offset_old = frame_offset; /* Round frame offset to that alignment. We must be careful here, since FRAME_OFFSET might be negative and division with a negative dividend isn't as well defined as we might *************** assign_stack_local (mode, size, align) *** 681,686 **** --- 701,714 ---- frame_offset = FLOOR_ROUND (frame_offset, alignment); #else frame_offset = CEIL_ROUND (frame_offset, alignment); + { + static int *last_sizep = &dummy_slotsize; + /* when reload rounds the stacksize, last_sizep gets reset to + &dummy_slotsize */ + *last_sizep += frame_offset - frame_offset_old; + last_sizep = sizep; + *sizep = size; + } #endif /* On a big-endian machine, if we are allocating more space than we will use, *************** assign_stack_local (mode, size, align) *** 690,695 **** --- 718,724 ---- #ifdef FRAME_GROWS_DOWNWARD frame_offset -= size; + *sizep = frame_offset_old - frame_offset; #endif /* If we have already instantiated virtual registers, return the actual *************** assign_stack_temp (mode, size, keep) *** 832,837 **** --- 861,883 ---- if (best_p->size - rounded_size >= alignment) { p = (struct temp_slot *) oballoc (sizeof (struct temp_slot)); + /* make sure that a size increase from assign_stack_local2 + to p->size will end up in the appropriate block. Also + keeps temp_slots ordered so that combine_temp_slots might + be simplified. */ + #ifdef FRAME_GROWS_DOWNWARD + p->next = best_p->next; + best_p->next = p; + #else + { + struct temp_slot *q; + *p = *best_p; + best_p->next = p; + q = p; + p = best_p; + best_p = q; + } + #endif p->in_use = p->addr_taken = 0; p->size = best_p->size - rounded_size; p->slot = gen_rtx (MEM, BLKmode, *************** assign_stack_temp (mode, size, keep) *** 839,846 **** rounded_size)); p->address = 0; p->rtl_expr = 0; - p->next = temp_slots; - temp_slots = p; stack_slot_list = gen_rtx (EXPR_LIST, VOIDmode, p->slot, stack_slot_list); --- 885,890 ---- *************** assign_stack_temp (mode, size, keep) *** 855,875 **** /* If we still didn't find one, make a new temporary. */ if (p == 0) { - int frame_offset_old = frame_offset; p = (struct temp_slot *) oballoc (sizeof (struct temp_slot)); /* If the temp slot mode doesn't indicate the alignment, use the largest possible, so no one will be disappointed. */ ! p->slot = assign_stack_local (mode, size, mode == BLKmode ? -1 : 0); ! /* The following slot size computation is necessary because we don't ! know the actual size of the temporary slot until assign_stack_local ! has performed all the frame alignment and size rounding for the ! requested temporary. Otherwise combine_temp_slots won't think that ! adjacent slots really are adjacent. */ ! #ifdef FRAME_GROWS_DOWNWARD ! p->size = frame_offset_old - frame_offset; ! #else ! p->size = frame_offset - frame_offset_old; ! #endif p->address = 0; p->next = temp_slots; temp_slots = p; --- 899,909 ---- /* If we still didn't find one, make a new temporary. */ if (p == 0) { p = (struct temp_slot *) oballoc (sizeof (struct temp_slot)); /* If the temp slot mode doesn't indicate the alignment, use the largest possible, so no one will be disappointed. */ ! p->slot = assign_stack_local2 (mode, size, mode == BLKmode ? -1 : 0, ! &p->size); p->address = 0; p->next = temp_slots; temp_slots = p; *************** combine_temp_slots () *** 927,933 **** --- 961,983 ---- { /* P comes after Q; combine P into Q. */ q->size += p->size; + #ifdef STACK_GROWS_DOWNWARD delete_p = 1; + #else + /* If we'd miss a size increase from assign_stack_local2 + because it goes into the discarded slot instead of the + combined one, subsequent calls would be unable to + combine it with a following slot. */ + { + struct temp_slot *tmp = p->next; + *p = *q; + q->next = tmp; + tmp = p; + p = q; + q = tmp; + delete_q = 1; + } + #endif break; } } *** gcc-2.7.0/ChangeLog Sat Jul 8 01:54:05 1995 --- gcc-2.7.0-x/ChangeLog Sat Sep 9 19:15:42 1995 *************** *** 1,3 **** --- 1,42 ---- + Sat Sep 9 17:54:02 MET DST 1995 J"orn Rennecke (amylaar@meolyon.hanse.de) + * function.c (assign_stack_local2): new function. Like + assign_local_stack, but takes an additional parameter to store + the size of an allocated slot. + When FRAME_GROWS_DOWNWARD is not #defined, add the stack alignment + to the size of the last allocated slot. + (assign_stack_local): redefined as a call to assign_stack_local2. + assign_stack_temp(): use assign_stack_local2. Take special care + when splitting a block where last_sizep will point to. + (combine_temp_slots): When combining for !STACK_GROWS_DOWNWARD, + make sure the size increase gets into the combined slot. + + Tue Aug 29 19:10:53 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + * c-common.c (decl_attribute, case A_PACKED): Check is_type first. + (decl_attribute, case A_T_UNION): Likewise. + Don't access TYPE_FIELDS if DECL is zero. + * c-decl.c (finish_struct): If transparent_union attribute + specified, validate it once we finish laying the union out. + + Thu Aug 17 21:02:09 1995 J"orn Rennecke (amylaar@meolyon.hanse.de) + * i386.c (arithmetic_comparison_operator): New function. + (print_operand) : take into account that overflow flag is not + set like after a compare instruction. + * i386.md (decrement_and_branch_until_zero): use + arithmetic_comparison_operator to decide if there is an comparison + that is suitable to be expressed by the condition code from an + arithmetic operation. + + Fri Jul 14 07:34:21 1995 J"orn Rennecke (amylaar@meolyon.hanse.de) + * c-decl.c(finish_struct): wait with decl_attributes() till + TYPE_FIELDS (t) is valid. + + Thu Jul 13 22:53:04 1995 J"orn Rennecke (amylaar@meolyon.hanse.de) + * c-common.c(decl_attributes): bug fix for A_ALIGNED + + Sat Jul 8 10:33:59 1995 J"orn Rennecke (amylaar@meolyon.hanse.de) + * New optimization option -fomit-default-branch . Most of it + is in expand_end_case(). Doc in gcc.1 + Fri Jun 16 06:54:03 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu) * alpha.c (alpha_builtin_saveregs): Use ptr_mode and conversions