From mboxrd@z Thu Jan 1 00:00:00 1970 From: hjl@lucon.org (H.J. Lu) To: wilson@cygnus.com (Jim Wilson) Cc: hjl@lucon.org, wilson@cygnus.com, law@cygnus.com, scox@cygnus.com, crux@pool.informatik.rwth-aachen.de, egcs@cygnus.com Subject: Re: More fp bug in egcs Date: Sat, 02 May 1998 18:56:00 -0000 Message-id: References: <199805010234.TAA02560@ada.cygnus.com.cygnus.com> X-SW-Source: 1998-05/msg00048.html > > I believe this is another bug in the same i386 code as my last patch. > > The problem is that the only FP->DImode converstion instruction pops the > FP stack. Normally we have both popping and non-popping versions of > instructions. The x86 code handles this by aborting if we need to emit > the non-existent non-popping instruction. However, this can't work all > of the time, because it assumes the optimizer always generates optimal > code. That isn't safe. And it is obviously not safe if we are compiling > without optimization. > > In order to fix this, we need to emulate the missing instruction if gcc > needs to emit it. The following patch does this. If there is a better way > to do this, then let me know. > > Thu Apr 30 19:28:16 1998 Jim Wilson > > * i386.c (output_fix_trunc): Add code to emulate non-popping DImode > case. > > *** i386.c Sun Feb 15 11:54:11 1998 > --- /home/wilson/tmp/i386.c Thu Apr 30 19:26:54 1998 > *************** output_fix_trunc (insn, operands) > *** 3731,3738 **** > int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; > rtx xops[2]; > > ! if (! STACK_TOP_P (operands[1]) || > ! (GET_MODE (operands[0]) == DImode && ! stack_top_dies)) > abort (); > > xops[0] = GEN_INT (12); > --- 3731,3737 ---- > int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; > rtx xops[2]; > > ! if (! STACK_TOP_P (operands[1])) > abort (); > > xops[0] = GEN_INT (12); > *************** output_fix_trunc (insn, operands) > *** 3750,3755 **** > --- 3749,3765 ---- > { > if (stack_top_dies) > output_asm_insn (AS1 (fistp%z0,%0), operands); > + else if (GET_MODE (operands[0]) == DImode && ! stack_top_dies) > + { > + /* There is no DImode version of this without a stack pop, so > + we must emulate it. It doesn't matter much what the second > + instruction is, because the value being pushed on the FP stack > + is not used except for the following stack popping store. > + This case can only happen without optimization, so it doesn't > + matter that it is inefficient. */ > + output_asm_insn (AS1 (fistp%z0,%0), operands); > + output_asm_insn (AS1 (fild%z0,%0), operands); > + } > else > output_asm_insn (AS1 (fist%z0,%0), operands); > } > Here is the trimmed down test case. I am not sure if your patch is correct. If you take look at the stack RTL dump, you will see SF 1 in (define_insn "" [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "+f")))) (clobber (match_dup 1)) (clobber (match_operand:SI 2 "memory_operand" "m")) (clobber (match_operand:DI 3 "memory_operand" "m")) (clobber (match_scratch:SI 4 "=&q"))] "TARGET_80387" "* return output_fix_trunc (insn, operands);") is used as the input for the next insn: ;; Insn is not within a basic block (insn:QI 104 269 272 (parallel[ (set (mem:DI (plus:SI (reg:SI 6 %ebp) (const_int -144))) (fix:DI (fix:SF (reg:SF 8 %st(0))))) (clobber (reg:SF 8 %st(0))) (clobber (mem:SI (plus:SI (reg:SI 6 %ebp) (const_int -4)))) (clobber (mem:DI (plus:SI (reg:SI 6 %ebp) (const_int -12)))) (clobber (reg:SI 1 %edx)) ] ) 117 {fix_truncxfsi2-1} (nil) (nil)) ;; Insn is not within a basic block (insn:QI 272 104 275 (set (mem:SF (plus:SI (reg:SI 6 %ebp) (const_int -148))) (reg:SF 8 %st(0))) -1 (nil) (expr_list:REG_DEAD (reg:DF 8 %st(0)) (nil))) I don't know if it is correct. Did gcc know %st(0) was not the same %st(0) before? Thanks. -- H.J. Lu (hjl@gnu.org) --- typedef struct _geom_elem { double coeffs[6]; } pGeomDefRec, *pGeomDefPtr; typedef struct _mpgeombanddef { int yOut; int in_width; } mpGeometryBandRec, *mpGeometryBandPtr; typedef void *pointer; typedef unsigned char CARD8; typedef CARD8 BytePixel; void BiGL_B (OUTP,srcimg,width,sline,pedpvt,pvtband) pointer OUTP; pointer *srcimg; register int width; int sline; pGeomDefPtr pedpvt; mpGeometryBandPtr pvtband; { register float s, t, st; register int isrcline,isrcpix; register int srcwidth = pvtband->in_width - 1; register BytePixel val; register BytePixel *ptrIn, *ptrJn; register double a = pedpvt->coeffs[0]; register double c = pedpvt->coeffs[2]; register double srcpix = a * ((double)(0.0000)) + pedpvt->coeffs[1] * (pvtband->yOut + ((double)(0.0000)) ) + pedpvt->coeffs[4]; register double srcline = c * ((double)(0.0000)) + pedpvt->coeffs[3] * (pvtband->yOut + ((double)(0.0000)) ) + pedpvt->coeffs[5]; if ( (isrcpix >= 0) && (isrcpix < srcwidth) ) val = ptrIn[isrcpix] * ((float)1. - s - t + st) + ptrIn[isrcpix+1] * (s - st) + ptrJn[isrcpix] * (t - st) + ptrJn[isrcpix+1] * (st) + (float)0.5 ; }