Sign in Join

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

Mailing lists / fpc-pascal / 2007-08

About the bug report #9408...

6 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

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

mm

Hello,

I don't want to start a big discuss on the subject (it would presumably lead nowhere) but I would like to answer to both J.M. and P.V. who added notes to the report.

To J.M.
-------
You said "To be compatible with Delphi". With its current behaviour, FPC 2.1.4 is not compatible with Delphi (and no more with FPC 2.0.4).

You quoted the bug #8321. There, I see two problems but none concerns the subtraction of unsigned integers.

1) The problem in the bug report.

    "Edit1.text:=(intToStr(a + b - 256));".
    Calling an overloaded function with a value whose type is not
    clearly defined (a and b are bytes but 256 is not) is, at least,
    dangerous programming.

2) The problem in FPC.
For some reasons, FPC decided to call IntToStr(Int64) (here, Delphi called IntToStr(Longint)). But, instead of extending the parameter as a signed number, it extended it as an unsigned one. This is not coherent. Since FPC selected a signed parameter overload, it should have extended the parameter with

mov eax, param
cdq

not with, as it did,

mov eax, param
mov edx, 0

To P.V.
-------
Compelling FPC 2.1.4 to behave like FPC 2.0.4 is not very difficult. In a program where you have "A := B - C;" (A,B,C being Longwords), it is sufficient to write "A := Longword(Longint(B) - Longint(C));" and all is right. The most difficult is to find which lines of code has to be modified. FPC signals most of them ("Possible loss of data ...") but not all. For instance, "if (A and (A-1)) = ..." is silently converted as a 64-bit operation.

But the problem is not just an efficiency problem, it is also a 'result' problem. For instance, try this with both FPC 2.0.4 and 2.1.4 :

   B := 1111;
   C := 1112;
   D := 311;
   A := (B - C) div D;

You will get two different values for A.
With 2.0.4, you compute ((B - C) mod 2^32) div D; with 2.1.4, you compute (B - C) div D where (B - C) is a 64-bit signed parameter. These are two different operations.

mm

Reply by email

Peter Vreman
to mm
Show quoted text 20 lines
Compelling FPC 2.1.4 to behave like FPC 2.0.4 is not very difficult. In a program where you have "A := B - C;" (A,B,C being Longwords), it is sufficient to write "A := Longword(Longint(B) - Longint(C));" and all is right. The most difficult is to find which lines of code has to be modified. FPC signals most of them ("Possible loss of data ...") but not all. For instance, "if (A and (A-1)) = ..." is silently converted as a 64-bit operation. But the problem is not just an efficiency problem, it is also a 'result' problem. For instance, try this with both FPC 2.0.4 and 2.1.4 : B := 1111; C := 1112; D := 311; A := (B - C) div D; You will get two different values for A. With 2.0.4, you compute ((B - C) mod 2^32) div D; with 2.1.4, you compute (B - C) div D where (B - C) is a 64-bit signed parameter. These are two different operations.

We did a lot of experiments regarding this. There is no clear description how to calculate the longwords.

The current behavior of 2.1.4 is the best effort we could do that is both the same on 32-bit and 64-bit platforms. In 2.0.4 there was a difference between 32-bit and 64-bit platforms and fpc was also not always compatible with delphi.

Reply by email

mm
to Peter Vreman
Peter Vreman wrote 23 lines
> Compelling FPC 2.1.4 to behave like FPC 2.0.4 is not very difficult. > In a program where you have "A := B - C;" (A,B,C being Longwords), it > is sufficient to write "A := Longword(Longint(B) - Longint(C));" and all > is right. The most difficult is to find which lines of code has to be > modified. FPC signals most of them ("Possible loss of data ...") but not > all. For instance, "if (A and (A-1)) = ..." is silently converted as a > 64-bit operation. > > But the problem is not just an efficiency problem, it is also a 'result' > problem. For instance, try this with both FPC 2.0.4 and 2.1.4 : > > B := 1111; > C := 1112; > D := 311; > A := (B - C) div D; > > You will get two different values for A. > With 2.0.4, you compute ((B - C) mod 2^32) div D; with 2.1.4, you > compute (B - C) div D where (B - C) is a 64-bit signed parameter. These > are two different operations. We did a lot of experiments regarding this. There is no clear description how to calculate the longwords.

The only thing that is clear in all that stuff, this is the situation : we inherit the mess initiated by Borland in the 80's. If, at that time, someone at Borland decided to follow some standard (the ADA one, for instance), today things would certainly be a little less lame.

The current behavior of 2.1.4 is the best effort we could do that is both the same on 32-bit and 64-bit platforms. In 2.0.4 there was a difference between 32-bit and 64-bit platforms and fpc was also not always compatible with delphi.

I understand that your work is not easy, there is no good solution. Either you follow Borland, i.e., you go on with the current mess, or you try to rationalize things but, in this case, you can no more be fully compatible with what was previously done.

mm

Reply by email

Jonas Maebe
to mm: I don't want to start a big discuss on the subject (it would presumably lead nowhere) but…
mm wrote
To J.M. ------- You said "To be compatible with Delphi". With its current behaviour, FPC 2.1.4 is not compatible with Delphi (and no more with FPC 2.0.4).

It is at least more compatible with Delphi than 2.1.4

You quoted the bug #8321. There, I see two problems but none concerns the subtraction of unsigned integers.

The a, b and 256 below are all unsigned integers. a+b gets a result type of cardinal.

Show quoted text 5 lines
1) The problem in the bug report. "Edit1.text:=(intToStr(a + b - 256));". Calling an overloaded function with a value whose type is not clearly defined (a and b are bytes but 256 is not) is, at least, dangerous programming.

Not necessarily.

Show quoted text 15 lines
2) The problem in FPC. For some reasons, FPC decided to call IntToStr(Int64) (here, Delphi called IntToStr(Longint)). But, instead of extending the parameter as a signed number, it extended it as an unsigned one. This is not coherent. Since FPC selected a signed parameter overload, it should have extended the parameter with mov eax, param cdq not with, as it did, mov eax, param mov edx, 0

No. Whether you sign or zero extend depends on the "signdness" of the source type, not of the target type. The whole point of using int64 rather than longint or dword is that it can represent all values from low(longint) till high(cardinal) without any problem. If you "sign extend" a cardinal into an int64, all values between high(longint)+1 and high(cardinal) are going to become negative, which is wrong.

Jonas

Reply by email

mm
to Jonas Maebe
Jonas Maebe wrote 9 lines
On 15 Aug 2007, at 03:51, mm wrote: > To J.M. > ------- > You said "To be compatible with Delphi". With its current behaviour, > FPC 2.1.4 is not compatible with Delphi (and no more with FPC 2.0.4). It is at least more compatible with Delphi than 2.1.4

Which Delphi? :-)

Show quoted text 5 lines
> You quoted the bug #8321. There, I see two problems but none concerns > the subtraction of unsigned integers. The a, b and 256 below are all unsigned integers. a+b gets a result type of cardinal.

I don't agree. If you don't explicitly write Longword(256), by default, it is a Longint.

Show quoted text 7 lines
> 1) The problem in the bug report. > "Edit1.text:=(intToStr(a + b - 256));". > Calling an overloaded function with a value whose type is not > clearly defined (a and b are bytes but 256 is not) is, at least, > dangerous programming. Not necessarily.

Such behaviour is totally confusing. And not only for the compiler but also for the programmers. At first glance what is the type of "a + b - 256"? It should be a Longint but, in fact, I don't know what it is. When I see things like this, I don't know what the programmer wanted to do. The only thing I can do is to suppose.

Show quoted text 17 lines
> 2) The problem in FPC. > For some reasons, FPC decided to call IntToStr(Int64) (here, Delphi > called IntToStr(Longint)). But, instead of extending the parameter as > a signed number, it extended it as an unsigned one. This is not > coherent. Since FPC selected a signed parameter overload, it should > have extended the parameter with > > mov eax, param > cdq > > not with, as it did, > > mov eax, param > mov edx, 0 No. Whether you sign or zero extend depends on the "signdness" of the source type, not of the target type.

That's not what I said. Where does the target type comes from? This is the compiler choice. Why did the compiler select the signed parameter overloaded function? Because it regarded the parameter as being a signed integer [*]. What is this parameter if it is not what you call the 'source type'?

[*] Yes, this is logical. What is not logical is to believe that it calls the signed parameter overload whereas it regards the parameter as an unsigned one (and, if I understand you well, that exactly what FPC does).

Show quoted text 5 lines
The whole point of using int64 rather than longint or dword is that it can represent all values from low(longint) till high(cardinal) without any problem. If you "sign extend" a cardinal into an int64, all values between high(longint)+1 and high(cardinal) are going to become negative, which is wrong.

But you are saying this as if it was ok to regard "a + b - 256" as a Longword. It is should regard "a + b - 256" as a
Longint, not as a Longword. Moreover, assuming FPC regards "a + b - 256" as a Longword, then it should call IntToStr(Qword), not IntToStr(Int64).

mm
http://www.ellipsa.net/

Reply by email

Jonas Maebe
to mm
mm wrote 10 lines
Jonas Maebe a écrit : > On 15 Aug 2007, at 03:51, mm wrote: >> To J.M. >> ------- >> You said "To be compatible with Delphi". With its current behaviour, >> FPC 2.1.4 is not compatible with Delphi (and no more with FPC >> 2.0.4). > It is at least more compatible with Delphi than 2.1.4 Which Delphi? :-)

Mostly whichever Delphi the people who submit those bugs are using, although most things are usually verified against Delphi 6.5 and/or 7.

Show quoted text 6 lines
> The a, b and 256 below are all unsigned integers. a+b gets a > result type of cardinal. I don't agree. If you don't explicitly write Longword(256), by default, it is a Longint.

It is, but in case of an expression with only unsigned types and positive constants., we convert everything to dword rather than longint (because of Delphi).

Show quoted text 21 lines
>> 2) The problem in FPC. >> For some reasons, FPC decided to call IntToStr(Int64) (here, >> Delphi >> called IntToStr(Longint)). But, instead of extending the >> parameter as >> a signed number, it extended it as an unsigned one. This is not >> coherent. Since FPC selected a signed parameter overload, it >> should >> have extended the parameter with >> >> mov eax, param >> cdq >> >> not with, as it did, >> >> mov eax, param >> mov edx, 0 > No. Whether you sign or zero extend depends on the "signdness" of > the source type, not of the target type. That's not what I said.

It is what you said, but apparently not what you meant.

Show quoted text 5 lines
Where does the target type comes from? This is the compiler choice. Why did the compiler select the signed parameter overloaded function? Because it regarded the parameter as being a signed integer [*].

No, because if you have to choose between these overloads:

sysstrh.inc:function IntToStr(Value: integer): string;
sysstrh.inc:function IntToStr(Value: Int64): string;
sysstrh.inc:function IntToStr(Value: QWord): string;

(this is compiled in objpas mode, so integer = longint), and someone passes an expression which has been evaluated as cardinal, then you prefer the int64 to the longint version because an int64 can represent all cardinal versions, while a longint cannot. And the compiler prefers an int64 to a qword because in general it prefers signed over unsigned types (except when Delphi says otherwise).

What is this parameter if it is not what you call the 'source type'?

The source type is the type of the value/expression you pass to a function. Based on all the source types of the parameter values/ expressions, we select the overloaded function to be called (the "closest" match which preferably can handle all possibly passed values). After this selection, all parameter values/expressions are converted to the actual parameter types of this function.

Show quoted text 9 lines
> The whole point of using int64 rather than longint or dword is > that it can represent all values from low(longint) till high > (cardinal) without any problem. If you "sign extend" a cardinal > into an int64, all values between high(longint)+1 and high > (cardinal) are going to become negative, which is wrong. But you are saying this as if it was ok to regard "a + b - 256" as a Longword. It is should regard "a + b - 256" as a Longint, not as a Longword.

Delphi says otherwise. We used to regard that as longint, and then the bug report came. We could of course implement umpteen different kind of type evaluation rules depending on people's taste, but that would be a lot of work both as far as implementation, maintenance and testing is concerned (and it would make it even more difficult to asses which type will be used based on looking at some source code).

Moreover, assuming FPC regards "a + b - 256" as a Longword, then it should call IntToStr(Qword), not IntToStr (Int64).

That may possibly happen if int128 ever becomes common place, because in general the highest supported signed type is usually treated in a special way.

Jonas

Reply by email