Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2001-03

Double-precision recursion

32 messages · 14 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Rich Pasco

My Pascal implementation of recursive floating-point algorithm fails, but a line-by-line C translation of the same program works fine.

I stripped the program down to "just the bug" and posted the minimized code at http://home.earthlink.net/~richpasco/pasbug.html

I would deeply appreciate anyone telling me just why the Pascal version fails. Trivial suggestions like "avoid floating point" or "restructure it to avoid recursion" or "use the C version instead" are not helpful.

- Rich

Jeff Wormsley
to Rich Pasco
AM Rich Pasco wrote
My Pascal implementation of recursive floating-point algorithm fails, but a line-by-line C translation of the same program works fine.

Perhaps you need to increase the stack size to support the recursion?

Jeff.

Rich Pasco
Jeff Wormsley wrote
Perhaps you need to increase the stack size to support the recursion?

I tried that. The floating point error always happens at the same depth (N=8) regardless of the stack size. But if I make the stack small enough, I get a stack overflow error (which is different).

- Rich

Rich Pasco
Sebastian G�nther wrote
Looks like a FPU stack overflow...?

You may be onto something here.

I didn't know there a separate stack in the FPU. How can I learn more about how Free Pascal utilizes it?

If you reduce the line "p := get+cof(n);" just to "p := cof(n);", then the program works. (ehmm, it doesn't crash anymore...)

Yes, but in the "real" program from which this trivial example was derived, this is not an option.

But I'm somewhat surprised that BP sufferes from the same problem.

Apparently both BP and FP use the FPU stack (if there is one) the same way. In this case, I'm surprised that the C version is not also subject to the same bug.

- Rich

Marco van de Voort
to Rich Pasco
Show quoted text 6 lines
> Looks like a FPU stack overflow...? You may be onto something here. I didn't know there a separate stack in the FPU. How can I learn more about how Free Pascal utilizes it?

Try to compile using -al, and check the generated assembler.

Show quoted text 5 lines
> If you reduce the line "p := get+cof(n);" just to "p := cof(n);", then > the program works. (ehmm, it doesn't crash anymore...) Yes, but in the "real" program from which this trivial example was derived, this is not an option.

The problem is that if you kill this behaviour, you loose a lot of speed.

One could try to detect simple recursion in the compiler, but this would only detect a -> a -> a recursion, and not a -> b -> a -> b -> a

Show quoted text 5 lines
> But I'm somewhat surprised that BP sufferes from the same problem. Apparently both BP and FP use the FPU stack (if there is one) the same way. In this case, I'm surprised that the C version is not also subject to the same bug.

If BP behaves the same way, we are compatible, and then it is not a bug :-)

Rich Pasco

Apparently the problem is that neither Borland Pascal (BP) nor Free Pascal (FP) appropriately handle the Floating Point Unit (FPU) hardware stack during procedure calls, although apparently Microsoft Visual C (MSVC) does, as demonstrated by successful operation of the C version of my example.

The stack should either be extended into RAM or saved and restored, but apparently BP and FP do neither.

Here are some relevant quotes from Intel's "Guidelines for Writing FPU Exception Handlers" at
http://www.intel.nl/design/intarch/techinfo/Pentium/fpuhandl.htm

"In some operating systems supporting the FPU, the numeric register stack is extended to memory. To extend the FPU stack to memory, the invalid exception is unmasked."

"In order to support multi-tasking, each thread in the system needs a save area for the general purpose registers, and each task that is allowed to use floating point needs an FPU save area large enough to hold the entire FPU stack and associated FPU state such as the control word and status word. (See "Saving the FPU's State", for a complete description of the FPU save image.)"

A relevant application note of further interest, "AP-578: Software and Hardware Considerations for FPU Exception Handlers for Intel Architecture Processors" may be obtained from http://developer.intel.com/design/pro/applnots/243291.htm

Whew.

- Rich

Sebastian Günther
to Rich Pasco: You may be onto something here. I didn't know there a separate stack in the FPU. How can…
Rich Pasco wrote
I didn't know there a separate stack in the FPU. How can I learn more about how Free Pascal utilizes it?

AFAIK, FPC works this way:

If you have a FPU operation which uses function results as arguments, such as

  a := b + c(...);    (c is a function)

then FPC will push 'b' on the FPU stack, call c() (which returns the result in the top-most FPU stack element), and add the both top-most elements.
In the case of a recursion, you will get serious problems with this approach, of course.

Show quoted text 5 lines
> If you reduce the line "p := get+cof(n);" just to "p := cof(n);", then > the program works. (ehmm, it doesn't crash anymore...) Yes, but in the "real" program from which this trivial example was derived, this is not an option.

Of course.... :)

Show quoted text 5 lines
> But I'm somewhat surprised that BP sufferes from the same problem. Apparently both BP and FP use the FPU stack (if there is one) the same way. In this case, I'm surprised that the C version is not also subject to the same bug.

I think most other compilers (including Delphi?) just don't push operands on the stack if there are still functions to be executed, before the operation is finished. As Marco pointed out, this results in much slower code - but on the other hand, this is the only solution to get code which works correctly in all cases.

A workaround for  a := b + c(...);  is this: (might not work with
optimizations enabled)
  var
    d: Double;
  begin
    ...
    d := c(...);
    a := b + d;
  end;

- Sebastian

Rich Pasco

Johan Blok wrote,

In that case it should give runtime error 202, I checked that with stack

checking

on. It gives runtime error 207 (Invalid Floating Point operation).

The key concept is that there are two separate stacks here. Runtime error 202 is overflow of the normal subroutine call stack. Runtime error 207 a catch-all for various FPU exceptions, such as divide-by-zero, numerical overflow, and FPU stack overflow.

Show quoted text 5 lines
Besides this I compiled it using the GNU Pascal Compiler. Now it works, as I expected, because gpc shares almost all important compiler stuff with gcc. Isn't it a bug of fpc?

Yes, I think so.

Marco van de Voort wrote,

If BP behaves the same way, we are compatible, and then it is not a bug :-)

I hope you were joking. To emulate bugs of obsolete systems is not a good way to create the new.

It seems that FPC follows BP in failing to handle the FPU stack. This failure should be fixed in FPC.

- Rich

Rich Pasco
Sebastian G�nther wrote 10 lines
AFAIK, FPC works this way: If you have a FPU operation which uses function results as arguments, such as a := b + c(...); (c is a function) then FPC will push 'b' on the FPU stack, call c() (which returns the result in the top-most FPU stack element), and add the both top-most elements. In the case of a recursion, you will get serious problems with this approach, of course.

I think you understand the problem perfectly.

Show quoted text 10 lines
A workaround for a := b + c(...); is this: (might not work with optimizations enabled) var d: Double; begin ... d := c(...); a := b + d; end;

Indeed, that is how I have repaired my real application program, and it seems to work correctly. While that makes me happy, for now, I still think that FPC should be fixed to avoid the problem with the original source code.

I have updated my web page at
http://home.earthlink.net/~richpasco/pasbug.html
to reflect the state of this discussion so far.

- Rich

Marco van de Voort
to Rich Pasco: checking The key concept is that there are two separate stacks here. Runtime error 202 is…
Show quoted text 5 lines
> If BP behaves the same way, we are compatible, and then it is not a bug :-) I hope you were joking. To emulate bugs of obsolete systems is not a good way to create the new.

Only partially. BP and Delphi are the reference designs, not GPC, GCC or C++.

It seems that FPC follows BP in failing to handle the FPU stack.

Are you certain that GPC does it this way? Or does it just forget about optimalisations, and just generates slow code?

This failure should be fixed in FPC.

How? My main concerns are:

- Disabling it all together results in severe loss of speed in FPU apps, sacrificed for the rare recursion-with FP case.

- Recursion is not flagged as being recursive. Auto recursion can be checked (calling itself), but a perfect solution is hard.

- Extending FPU stacks might not be possible from user mode under most OSes. Did you actually check that GCC does this?

Rich Pasco
Marco van de Voort wrote
Are you certain that GPC does it this way? Or does it just forget about optimalisations, and just generates slow code?

I know nothing of GPC. It was Johan Blok who mentioned GPC.

Show quoted text 10 lines
How? My main concerns are: - Disabling it all together results in severe loss of speed in FPU apps, sacrificed for the rare recursion-with FP case. - Recursion is not flagged as being recursive. Auto recursion can be checked (calling itself), but a perfect solution is hard. - Extending FPU stacks might not be possible from user mode under most OSes. Did you actually check that GCC does this?

No, again I know nothing of GPC.

To me, correct operation on all programs is better than fast operation on some but total failure on others. How about a compiler option switch so we can choose what we want?

You guys are the implementers, I'm an end-user. If you can't extend the FPU stack in RAM, then you should save and restore its contents on every procedure call. Yes, I know it's slow, but it may be the only way to correctly handle recursion.

Note: It might be possible for the compiler to look for a function that directly calls itself, but in the example I provided where there are a pair of function calling each other alternately, this test would fail to detect the recursion.

At the very least, a different Run Time Error code should be reported for FPU stack overflow than for other arithmetic faults (divide-by-zero, etc.) To lump everything into 207 makes it very hard to diagnose the problem--it took me three days and a post to this list to figure this one out with only a "floating point exception" to go on. If it had said *which* floating point exception (e.g. FPU hardware stack overflow) then I would have been much sooner on my way to solve the problem.

- Rich

Unknown author

This is a well documented limitation of Borland Pascal. I have lost the original reference to this but the solution from Borland was to use an expression that would create a temporary variable. Using parentheses can force the creation of a temporary variable.

This is more a design limitation than a bug. All the versions of Borland (Turbo) Pascal that used the FPU have this limitation. Once you know it is there it is easy to avoid.

Rolf Grunsky

----------------------------------------------------------- Remember, what you see coming at you is coming from you. "Jungle" Jack Flanders -----------------------------------------------------------
Jonas
Rich Pasco wrote 12 lines
> var > d: Double; > begin > ... > d := c(...); > a := b + d; > end; Indeed, that is how I have repaired my real application program, and it seems to work correctly. While that makes me happy, for now, I still think that FPC should be fixed to avoid the problem with the original source code.

W already have a bug report about this (<http://www.freepascal.org/bugs/showrec.php3?ID=1269>). We discussed it and while it will seriously slow down any FPU calculations involving function calls, the only solution is to save everything on the FPU stack to memory before calling any procedure. We will fix it this way, but until now no-one has gotten around doing it.

BP has the FPU stack overflow bug (it even contains a demo program to show it, indicating that back then they thought the programmer was responsible to work around this silly implementation of the 80x87 FPU), Delphi has it fixed (and uses the same technique as described above).

Jonas

Jonas
Rich Pasco wrote
You guys are the implementers, I'm an end-user. If you can't extend the FPU stack in RAM, then you should save and restore its contents on every procedure call. Yes, I know it's slow, but it may be the only way to correctly handle recursion.

I think the text you forwarded seemed to be geared at OS designers, not compiler designers.

At the very least, a different Run Time Error code should be reported for FPU stack overflow than for other arithmetic faults (divide-by-zero, etc.) To lump everything into 207 makes it very hard to diagnose the

We do differentiate between different FPU errors. However, RTE 202 refers to a regular stack overflow, not to an FPU stack overflow (afaik there is no separate RTE defined for an FPU stack overflow in Delphi nor in TP). That's because they are two completely different beasts: the FPU stack are 8 hardware registers accessible as a stack inside the 80x87 FPU. The normal stack is in regular RAM and is like a stack which you would implement in Pascal as an array on the heap (but starting at the end of the heap and growing downwards)r.

The stack and the heap reside in the same memory space, with the stack starting on top and growing down and the heap starting at the bottom and growing up. If the stack grows into the heap, you get a stack overflow. In most modern OS'es this is impossible nowadays, because they detect this somehow and grow the available stack space (this last paragraph is not 100% correct I think, but it should give you a general idea of the issues at hand).

Jonas

Thomas Schatzl
to Jonas
Show quoted text 8 lines
On Friday, March 30, 2001, at 03:16 AM, Rich Pasco wrote: > At the very least, a different Run Time Error code should be reported > for FPU stack overflow than for other arithmetic faults (divide-by-zero, > etc.) To lump everything into 207 makes it very hard to diagnose the We do differentiate between different FPU errors. However, RTE 202 refers to a regular stack overflow, not to an FPU stack overflow (afaik there is no

separate

RTE defined for an FPU stack overflow in Delphi nor in TP). That's because they are two completely different

Delphi does differ between several types of FPU exceptions by triggering different types of exceptions.

Regards,
Thomas

Jonas
Rich Pasco wrote
Runtime error 207 a catch-all for various FPU exceptions, such as divide-by-zero, numerical overflow, and FPU stack overflow.

That is incorrect (from the unix system unit):

         if (FpuState and $7f)  0 then
            begin
              { first check the more precise options }
              if (FpuState and FPU_DivisionByZero)0 then
                res:=200
              else if (FpuState and FPU_Overflow)0 then
                res:=205
              else if (FpuState and FPU_Underflow)0 then
                res:=206
              else if (FpuState and FPU_Denormal)0 then
                res:=216
              else if (FpuState and (FPU_StackOverflow or FPU_StackUnderflow))<
                res:=207
              else if (FpuState and FPU_Invalid)0 then
                res:=216
              else
                res:=207;  {'Coprocessor Error'}
            end;

Jonas

Jonas
Thomas Schatzl wrote 8 lines
> We do differentiate between different FPU errors. However, RTE 202 refers to a >regular stack overflow, not to an FPU stack overflow (afaik there is no >separate >RTE defined for an FPU stack overflow in Delphi nor in TP). That's because they >are two completely different Delphi does differ between several types of FPU exceptions by triggering different types of exceptions.

We also do (see my other mail), but not for FPU stack over/underflow, those are simple 207's.

Jonas

Rich Pasco
to Jonas: W already have a bug report about this (<http://www.freepascal.org/bugs/showrec.php3?ID=12…
Jonas wrote
We already have a bug report about this (<http://www.freepascal.org/bugs/showrec.php3?ID=1269>). We discussed it and while it will seriously slow down any FPU calculations involving function calls, the only solution is to save everything on the FPU stack to memory before calling any procedure. We will fix it this way, but until now no-one has gotten around doing it.

Thanks for this. Please allow my request to increment the priority level a notch. :-)

BP has the FPU stack overflow bug (it even contains a demo program to show it, indicating that back then they thought the programmer was responsible to work around this silly implementation of the 80x87 FPU)

Indeed, thanks to this comment, I found the demo (with the default BP installation path) at C:\BP\EXAMPLES\DOS\FIB8087.PAS

I think the text you forwarded seemed to be geared at OS designers, not compiler designers.

Perhaps, but if the OS doesn't fix it, then the compiler should include a work-around when the target platform is vulnerable.

We do differentiate between different FPU errors.

Thank you for this information. I stand corrected, with due apologies.

However, RTE 202 refers to a regular stack overflow, not to an FPU stack overflow (afaik there is no separate RTE defined for an FPU stack overflow in Delphi nor in TP). That's because they are two completely different beasts: the FPU stack are 8 hardware registers accessible as a stack inside the 80x87 FPU. The normal stack is in regular RAM and is like a stack which you would implement in Pascal as an array on the heap (but starting at the end of the heap and growing downwards).

I understand this. I believe that it was Johan Blok who was confused on this point.

- Rich

Ramon Bosque
to Rich Pasco

----- Original Message -----
"Rich Pasco" wrote
To:

Jonas wrote: > We already have a bug report about this

(<http://www.freepascal.org/bugs/showrec.php3?ID=1269>). We discussed it and while it will seriously slow down any FPU calculations involving function calls, the only solution is to save everything on the FPU stack to memory before calling any procedure. We will fix it this way, but until now no-one has gotten around doing it.

Could this be done using an option in the compiler? I think that it would be a pity to lose speed in a normal situation in order to prevent a crash in a specific program.

Best regards

Ramon Bosque

Unknown author
Could this be done using an option in the compiler? I think that it would be a pity to lose speed in a normal situation in order to prevent a crash in a specific program.

FWIW, I agree...

Jim

Lee, John

We seem to have had similar discussion re fp before in the contecyt of fpu optimisation- or was it different? My 0.001 euro then (& now) was why can't we fix is as described (IMO this should be done ASAP because it is a REAL (tho' obscure) bug!). My concern is that if it impacts performance (& this is quite a big fpc plus point) could we disable it somehow for those who want max performance & can take a chance on errors... Regards John

Earlier message 49 lines
-----Original Message----- From: Rich Pasco Sent: Friday, March 30, 2001 03:59 To: Subject: Re: [fpc-pascal]Double-precision recursion Jonas wrote: > We already have a bug report about this (<http://www.freepascal.org/bugs/showrec.php3?ID=1269>). We discussed it and while it will seriously slow down any FPU calculations involving function calls, the only solution is to save everything on the FPU stack to memory before calling any procedure. We will fix it this way, but until now no-one has gotten around doing it. Thanks for this. Please allow my request to increment the priority level a notch. :-) > BP has the FPU stack overflow bug (it even contains a demo program to show it, indicating that back then they thought the programmer was responsible to work around this silly implementation of the 80x87 FPU) Indeed, thanks to this comment, I found the demo (with the default BP installation path) at C:\BP\EXAMPLES\DOS\FIB8087.PAS > I think the text you forwarded seemed to be geared at OS designers, not compiler designers. Perhaps, but if the OS doesn't fix it, then the compiler should include a work-around when the target platform is vulnerable. > We do differentiate between different FPU errors. Thank you for this information. I stand corrected, with due apologies. > However, RTE 202 refers to a regular stack overflow, not to an FPU stack overflow (afaik there is no separate RTE defined for an FPU stack overflow in Delphi nor in TP). That's because they are two completely different beasts: the FPU stack are 8 hardware registers accessible as a stack inside the 80x87 FPU. The normal stack is in regular RAM and is like a stack which you would implement in Pascal as an array on the heap (but starting at the end of the heap and growing downwards). I understand this. I believe that it was Johan Blok who was confused on this point. - Rich
Johan Blok
to Sebastian Günther: Looks like a FPU stack overflow...? If you reduce the line "p := get+cof(n);" just to "p…
Sebastian Günther wrote 7 lines
Rich Pasco wrote: > > I would deeply appreciate anyone telling me just why the Pascal version > fails. Looks like a FPU stack overflow...?

In that case it should give runtime error 202, I checked that with stack checking
on. It gives runtime error 207 (Invalid Floating Point operation).

I also tried to start with different n. It allways crashes at the starting n + 8.

I did this on linux.

If you reduce the line "p := get+cof(n);" just to "p := cof(n);", then the program works. (ehmm, it doesn't crash anymore...)

I also tried different things with this: allways when you are doing some calculation it
crashes.

Besides this I compiled it using the GNU Pascal Compiler. Now it works, as I expected, because
gpc shares almost all important compiler stuff with gcc.

Isn't it a bug of fpc?

Johan Blok

Jonas Maebe
to Peter Beisel
Peter Beisel wrote
does anybody know where to get Graphix for FreePascal 4.05?

As you may know, Michael Knapp (the author) abandoned it :( Does anyone still have a copy?

Jonas

Dirk Verwiebe
to Jonas Maebe

My last version ist 4.02 from 12.3.2001.

Dirk

Show quoted text 12 lines
On maandag, april 8, 2002, at 04:55 , Peter Beisel wrote: > does anybody know where to get Graphix for FreePascal 4.05? As you may know, Michael Knapp (the author) abandoned it :( Does anyone still have a copy? Jonas _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Jean-Pierre PLANAS
to Jonas Maebe: As you may know, Michael Knapp (the author) abandoned it :( Does anyone still have a copy?

Hello

You can find Graphix on sourceforge (http://www.sourceforge.net) in the kernel module of mosdev project.
We use Graphix for this project...

Jean-Pierre

you wrote 9 lines
On maandag, april 8, 2002, at 04:55 , Peter Beisel wrote: >does anybody know where to get Graphix for FreePascal 4.05? As you may know, Michael Knapp (the author) abandoned it :( Does anyone still have a copy? Jonas
Dirk Verwiebe
to Dirk Verwiebe

My version is from 8.9.2001. Which version is it ? 4.04 ? There are no version information in the zip archive.

Dirk

Show quoted text 24 lines
I have just found it.Should i send it via email ? Dirk Peter Beisel schrieb: > Thank you, but I'm searching for the last version. > At 27.Sept.2001 Michael Knapp released GraphiX 4.0.5 > Peter > > Dirk Verwiebe wrote: > > > My last version ist 4.02 from 12.3.2001. > > > > Dirk > > > > _______________________________________________ > fpc-pascal maillist - > http://lists.freepascal.org/mailman/listinfo/fpc-pascal _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Lee, John

Please send latest version to me & I'll put it on thre freepascal.org ftp server. J

Earlier message 29 lines
-----Original Message----- From: Dirk Verwiebe Sent: Tuesday, April 09, 2002 16:16 To: Subject: Re: [fpc-pascal]Graphix I have just found it.Should i send it via email ? Dirk Peter Beisel schrieb: > Thank you, but I'm searching for the last version. > At 27.Sept.2001 Michael Knapp released GraphiX 4.0.5 > Peter > > Dirk Verwiebe wrote: > > > My last version ist 4.02 from 12.3.2001. > > > > Dirk > > > > _______________________________________________ > fpc-pascal maillist - > http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Peter Beisel
to Dirk Verwiebe: I have just found it.Should i send it via email ? Dirk

Please send it to John Lee. I think it's a good idea to put it on the freepascal.org ftp server.
Peter

Show quoted text 24 lines
I have just found it.Should i send it via email ? Dirk Peter Beisel schrieb: > Thank you, but I'm searching for the last version. > At 27.Sept.2001 Michael Knapp released GraphiX 4.0.5 > Peter > > Dirk Verwiebe wrote: > > > My last version ist 4.02 from 12.3.2001. > > > > Dirk > > > > _______________________________________________ > fpc-pascal maillist - > http://lists.freepascal.org/mailman/listinfo/fpc-pascal _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal