Sign in Join

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

Mailing lists / fpc-devel / 2005-07

Not really a bug...

45 messages · 11 people · –

Reply by email Subscribe to this list Your subscription

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

Marcel Martin

Hello,

I am using FPC 2.0.0, Win32.

When subtracting a longword from a longword, FPC codes the operation as if it were a 64-bit operation. This is not really a bug since the code is correct but this uselessly increases the running times and the sizes of the executables.

(I found no bug report about that)

For instance, with u, v and w Longwords, the following subtraction

   u := v - w;

is coded as

movl U_P$TEST2_V,%eax
movl $0,%ebx
movl U_P$TEST2_W,%ecx
movl $0,%edx
subl %ecx,%eax
sbbl %edx,%ebx
movl %eax,U_P$TEST2_U

Here, not only 2 movl's and 1 sbbl are useless but FPC also wastes time to save/use/restore extra register(s).

At the moment, the only work around I found to make a subtraction with Longwords is to write the operation this way:

   u := Longword(Longint(v) - Longint(w));

coded as

movl U_P$TEST2_V,%eax
subl U_P$TEST2_W,%eax
movl %eax,U_P$TEST2_U

notice that

   u := v;
   Dec(u,w);
   movl  U_P$TEST2_V,%eax
   movl  %eax,U_P$TEST2_U
   movl  U_P$TEST2_W,%eax
   subl  %eax,U_P$TEST2_U

shows there is no problem with Dec (the same with Pred(), if u is a Longword, writing "u-1" is not ok but writing "Pred(u)" is ok).

mm

Reply by email

Peter Vreman
to Marcel Martin
Show quoted text 10 lines
Hello, I am using FPC 2.0.0, Win32. When subtracting a longword from a longword, FPC codes the operation as if it were a 64-bit operation. This is not really a bug since the code is correct but this uselessly increases the running times and the sizes of the executables. (I found no bug report about that)

There were a couple of bug reports about this issue. It is already fixed in current svn.

Reply by email

Gerhard Scholz
to Peter Vreman

I've tried to submit this as a bug report, but after pressing on "Submit bug" nothing happens on http://www.freepascal.org/bugs/add.php3

Inc ( v, i ) and Dec ( v, i ) produce rangecheck or overflow check with {$r+,q+}

Without checks the program runs corrctly.

The values and results are in range; the errors shold not occur.

Example program:

{$r+,q+,s+}
{ $r-,q-,s-}
program incdec ;
  uses
    sysutils ;
  var
    pre : 0..132 ;
    fra : -132..132 ;
  procedure init ; begin pre := 1 ; fra := -1 ; end ;
  begin
    init ; pre := pre + fra ;                       writeln ( pre ) ;
    init ; pre := pre - fra ;                       writeln ( pre ) ;
    init ; inc ( pre, fra ) ;   {Dec/Inc error? }   writeln ( pre ) ;
    init ; Dec ( pre, fra ) ;   {Dec/Inc error? }   writeln ( pre ) ;
   end.

The assembler code shows that Inc/Dec assumes that the second parameter has the same type as the first. This is not true in this case.

Assembler code (shortened):

#...
# [18] init ; pre := pre + fra ; writeln ( pre ) ; call P$INCDEC_INIT
movzbl U_P$INCDEC_PRE,%eax
movswl U_P$INCDEC_FRA,%edx
addl %eax,%edx
jno .L18
call FPC_OVERFLOW
.L18:
movl %edx,%eax
cmpl $132,%eax
jbe .L19
call FPC_RANGEERROR
.L19:
movb %dl,U_P$INCDEC_PRE
#...
# [19] init ; pre := pre - fra ; writeln ( pre ) ; call P$INCDEC_INIT
movzbl U_P$INCDEC_PRE,%edx
movswl U_P$INCDEC_FRA,%eax
subl %eax,%edx
jno .L32
call FPC_OVERFLOW
.L32:
movl %edx,%eax
cmpl $132,%eax
jbe .L33
call FPC_RANGEERROR
.L33:
movb %dl,U_P$INCDEC_PRE
#...
# [20] init ; inc ( pre, fra ) ; {Dec/Inc error? } writeln ( pre ) ; call P$INCDEC_INIT
movzbl U_P$INCDEC_PRE,%eax
movzbl U_P$INCDEC_FRA,%edx
addl %eax,%edx
jae .L46
call FPC_OVERFLOW
.L46:
movl %edx,%eax
cmpl $132,%eax
jbe .L47
call FPC_RANGEERROR
.L47:
#...
movb %dl,U_P$INCDEC_PRE
# [21] init ; Dec ( pre, fra ) ; {Dec/Inc error? } writeln ( pre ) ; call P$INCDEC_INIT
movzbl U_P$INCDEC_PRE,%edx
movzbl U_P$INCDEC_FRA,%eax
subl %eax,%edx
jae .L60
call FPC_OVERFLOW
.L60:
movl %edx,%eax
cmpl $132,%eax
jbe .L61
call FPC_RANGEERROR
.L61:
#...

Reply by email

Marcel Martin
to Peter Vreman: There were a couple of bug reports about this issue. It is already fixed in current svn.
Peter Vreman wrote 14 lines
>Hello, > >I am using FPC 2.0.0, Win32. > >When subtracting a longword from a longword, FPC codes the >operation as if it were a 64-bit operation. This is not really >a bug since the code is correct but this uselessly increases >the running times and the sizes of the executables. > >(I found no bug report about that) There were a couple of bug reports about this issue. It is already fixed in current svn.

I am using FPC 2.0.0 with some files overwritten by the ones downloaded from
ftp://ftp.freepascal.org/pub/fpc/snapshot/v21/i386-win32/ (file base.i386-win32.zip)
and the problem is still there.

base.i386-win32.zip doesn't contain updated files?

mm

Reply by email

Colin Western
to Gerhard Scholz: I've tried to submit this as a bug report, but after pressing on "Submit bug" nothing…
Gerhard Scholz wrote 11 lines
I've tried to submit this as a bug report, but after pressing on "Submit bug" nothing happens on http://www.freepascal.org/bugs/add.php3 Inc ( v, i ) and Dec ( v, i ) produce rangecheck or overflow check with {$r+,q+} Without checks the program runs corrctly.

<snip>
This looks similar to bug 4152 that I submitted recently. Colin

Reply by email

Peter Vreman
to Marcel Martin: I am using FPC 2.0.0 with some files overwritten by the ones downloaded from…
Show quoted text 23 lines
Peter Vreman a écrit : >>Hello, >> >>I am using FPC 2.0.0, Win32. >> >>When subtracting a longword from a longword, FPC codes the >>operation as if it were a 64-bit operation. This is not really >>a bug since the code is correct but this uselessly increases >>the running times and the sizes of the executables. >> >>(I found no bug report about that) > > > There were a couple of bug reports about this issue. It is already fixed > in current svn. I am using FPC 2.0.0 with some files overwritten by the ones downloaded from ftp://ftp.freepascal.org/pub/fpc/snapshot/v21/i386-win32/ (file base.i386-win32.zip) and the problem is still there. base.i386-win32.zip doesn't contain updated files?

Use the svn trunk to be sure to get the latest sources. The binary snapshots sometimes fail to build.

Current svn generates the following code:

# [4] u := v - w;
movl U_P$PROGRAM_V,%eax
subl U_P$PROGRAM_W,%eax
movl %eax,U_P$PROGRAM_U

Reply by email

Marco van de Voort
to Marcel Martin: I am using FPC 2.0.0 with some files overwritten by the ones downloaded from…
Show quoted text 12 lines
> > > There were a couple of bug reports about this issue. It is already fixed > in current svn. I am using FPC 2.0.0 with some files overwritten by the ones downloaded from ftp://ftp.freepascal.org/pub/fpc/snapshot/v21/i386-win32/ (file base.i386-win32.zip) and the problem is still there. base.i386-win32.zip doesn't contain updated files?

check the compiler version and fpc.cfg to make sure you really use the new files.

Reply by email

Peter Vreman
to Colin Western: <snip> This looks similar to bug 4152 that I submitted recently. Colin
Show quoted text 12 lines
Gerhard Scholz wrote: >I've tried to submit this as a bug report, but after pressing on "Submit > bug" >nothing happens on http://www.freepascal.org/bugs/add.php3 > > > >Inc ( v, i ) and Dec ( v, i ) produce rangecheck or overflow check with > {$r+,q+} > >Without checks the program runs corrctly.

Fixed

<snip> This looks similar to bug 4152 that I submitted recently.

Bug 4152 is partly fixed. The compiletime error is removed. Only the runtime overflow is left. That still needs to be decided how to handle it. The following code also fails with an overflow

{$Q+}
var
  v : cardinal;
begin
  v:=100;
  inc(v,-1);
end.

The reason is that -1 is in fact an addition of $ffffffff resulting in the carry flag being set and therefor an overflow.

Reply by email

Marco van de Voort
to Peter Vreman: Fixed Bug 4152 is partly fixed. The compiletime error is removed. Only the runtime…
Show quoted text 27 lines
> Gerhard Scholz wrote: > >> >>Inc ( v, i ) and Dec ( v, i ) produce rangecheck or overflow check with >> {$r+,q+} >> >>Without checks the program runs corrctly. Fixed > <snip> > This looks similar to bug 4152 that I submitted recently. Bug 4152 is partly fixed. The compiletime error is removed. Only the runtime overflow is left. That still needs to be decided how to handle it. The following code also fails with an overflow {$Q+} var v : cardinal; begin v:=100; inc(v,-1); end. The reason is that -1 is in fact an addition of $ffffffff resulting in the carry flag being set and therefor an overflow.

For cardinal IMHO not-a-bug?

Reply by email

Gerhard Scholz
to Peter Vreman: Fixed Bug 4152 is partly fixed. The compiletime error is removed. Only the runtime…

...

Show quoted text 14 lines
Bug 4152 is partly fixed. The compiletime error is removed. Only the runtime overflow is left. That still needs to be decided how to handle it. The following code also fails with an overflow {$Q+} var v : cardinal; begin v:=100; inc(v,-1); end. The reason is that -1 is in fact an addition of $ffffffff resulting in the carry flag being set and therefor an overflow.
Maybe the cleanest way is (in the $r+ $q+ mode) to handle
    inc ( v, d ) ;
the same as
   v := v + d ;

I replaced my code like this when I found the bug, and now my code works.

Gerhard

Reply by email

Gerhard Scholz
to Marco van de Voort: For cardinal IMHO not-a-bug?

...

Show quoted text 11 lines
> var > v : cardinal; > begin > v:=100; > inc(v,-1); > end. > > The reason is that -1 is in fact an addition of $ffffffff resulting in the > carry flag being set and therefor an overflow. For cardinal IMHO not-a-bug?

I think it's a bug for cardinals and other unsigned ints also (as long as the result is in the range of the result variable)

Reply by email

Marco van de Voort
to Gerhard Scholz
Show quoted text 14 lines
> > var > > v : cardinal; > > begin > > v:=100; > > inc(v,-1); > > end. > > > > The reason is that -1 is in fact an addition of $ffffffff resulting in the > > carry flag being set and therefor an overflow. > > For cardinal IMHO not-a-bug? I think it's a bug for cardinals and other unsigned ints also (as long as the result is in the range of the result variable)

-1 is not a valid cardinal -> out of range -> rangecheck error.

Reply by email

C Western
to Marco van de Voort
Marco van de Voort wrote 18 lines
>>>var >>> v : cardinal; >>>begin >>> v:=100; >>> inc(v,-1); >>>end. >>> >>>The reason is that -1 is in fact an addition of $ffffffff resulting in the >>>carry flag being set and therefor an overflow. >> >>For cardinal IMHO not-a-bug? > >I think it's a bug for cardinals and other unsigned ints also (as long as the >result is in the range of the result variable) -1 is not a valid cardinal -> out of range -> rangecheck error.

But on the other hand Dec(v,1) is fine, so Inc(v,-1) should also work. Colin

Reply by email

Marcel Martin
to C Western
C Western wrote 26 lines
Marco van de Voort wrote: >>>> var >>>> v : cardinal; >>>> begin >>>> v:=100; >>>> inc(v,-1); >>>> end. >>>> >>>> The reason is that -1 is in fact an addition of $ffffffff resulting >>>> in the >>>> carry flag being set and therefor an overflow. >>> >>> >>> For cardinal IMHO not-a-bug? >> >> >> I think it's a bug for cardinals and other unsigned ints also (as >> long as the >> result is in the range of the result variable) > > > > -1 is not a valid cardinal -> out of range -> rangecheck error. > But on the other hand Dec(v,1) is fine, so Inc(v,-1) should also work.

And if Dec(v,1) raises an overflow? Should Inc(v,-1) also do? If v = 0 (v is a longword), Dec(v,1) = overflow. So, Inc(v,-1), i.e., 0 + $ffffffff = overflow?

I think Marco is right. Basically, when the compiler has to code Inc(x,SomeConstant), the only sensible behaviour it is expected to have is to regard the constant as being of the type of x. So, if x is a Longword and if SomeConstant equals -1, either it adds $ffffffff (and there will be an overflow if x > 0) or it stops at compile time saying that -1 is not a Longword.

mm

Reply by email

peter green
to Marcel Martin
shouldn't it implement inv(v,-1) in exactly the same way it implements
v:=v-1?
Show quoted text 54 lines
-----Original Message----- From: Behalf Of Marcel Martin Sent: 06 July 2005 23:36 To: FPC developers' list Subject: Re: [fpc-devel] bug: Inc(v,i)/Dec(v,i) C Western a écrit : > Marco van de Voort wrote: > >>>>> var >>>>> v : cardinal; >>>>> begin >>>>> v:=100; >>>>> inc(v,-1); >>>>> end. >>>>> >>>>> The reason is that -1 is in fact an addition of $ffffffff resulting >>>>> in the >>>>> carry flag being set and therefor an overflow. >>>> >>>> >>>> For cardinal IMHO not-a-bug? >>> >>> >>> I think it's a bug for cardinals and other unsigned ints also (as >>> long as the >>> result is in the range of the result variable) >> >> >> >> -1 is not a valid cardinal -> out of range -> rangecheck error. >> > But on the other hand Dec(v,1) is fine, so Inc(v,-1) should also work. And if Dec(v,1) raises an overflow? Should Inc(v,-1) also do? If v = 0 (v is a longword), Dec(v,1) = overflow. So, Inc(v,-1), i.e., 0 + $ffffffff = overflow? I think Marco is right. Basically, when the compiler has to code Inc(x,SomeConstant), the only sensible behaviour it is expected to have is to regard the constant as being of the type of x. So, if x is a Longword and if SomeConstant equals -1, either it adds $ffffffff (and there will be an overflow if x > 0) or it stops at compile time saying that -1 is not a Longword. mm _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email

Marcel Martin
to peter green
peter green wrote
shouldn't it implement inv(v,-1) in exactly the same way it implements v:=v-1?

Well, I am far to be an expert in compilers but I think no, it shouldn't.
v := v + Longword(-1) is different from v := v - Longword(1). The resulting value v is the same but not the way to get it. If, as a programmer, I write 'Inc', the compiler should code an addition and not a subtraction.

mm

Reply by email

Peter Vreman
to peter green: shouldn't it implement inv(v,-1) in exactly the same way it implements v:=v-1?
shouldn't it implement inv(v,-1) in exactly the same way it implements v:=v-1?

The problem is what type do you give to -1. In the old situation the -1 was converted to the same type as v -> longword. Resulting in $ffffffff. Adding the $ffffffff gives an overflow.

Note that the compiler doesn't know that -1 is a negative value. Because it can also be a variable:

d:=-1;
inc(v,d);

If you translate inc(v,-1) to v:=v+(-1) then the operation is done in 64bit mode. It is the only way to garauntee that there is no overflow but still a rangecheck for the result value.

It should be solved now in the current svn trunk.

Reply by email

Vinzent Hoefler
to Peter Vreman
Peter Vreman wrote 5 lines
> shouldn't it implement inv(v,-1) in exactly the same way it > implements v:=v-1? The problem is what type do you give to -1. In the old situation the -1 was converted to the same type as v -> longword.

Which should trigger a range check already, because -1 can't be represented as valid longword.

Personal note: Maybe there was a reason why Borland Pascal didn't do range checks on Inc/Dec. The only time I ever used it was a checksum calculation which was modulo anyway. Any other time I use the usual operators. So especially with the "added" overflow check I think, Inc and Dec are pretty useless functions, because the don't do anything you can't accomplish by using "+" or "-" unless you have very_long_and_complex_variable_names and want to save some typing work.

Vinzent.

Reply by email

Hans-Peter Diettrich
to Marcel Martin: And if Dec(v,1) raises an overflow? Should Inc(v,-1) also do? If v = 0 (v is a longword),…
Marcel Martin wrote 7 lines
I think Marco is right. Basically, when the compiler has to code Inc(x,SomeConstant), the only sensible behaviour it is expected to have is to regard the constant as being of the type of x. So, if x is a Longword and if SomeConstant equals -1, either it adds $ffffffff (and there will be an overflow if x > 0) or it stops at compile time saying that -1 is not a Longword.

IMO the compiler can convert between Inc and Dec, for negative constants, so that the value always is positive, compatible with signed and unsigned data types.

DoDi

Reply by email

Marcel Martin
to Vinzent Hoefler: Which should trigger a range check already, because -1 can't be represented as valid…
Vinzent Hoefler wrote 15 lines
On Thursday 07 July 2005 05:39, Peter Vreman wrote: >>shouldn't it implement inv(v,-1) in exactly the same way it >>implements v:=v-1? > >The problem is what type do you give to -1. In the old situation the >-1 was converted to the same type as v -> longword. Which should trigger a range check already, because -1 can't be represented as valid longword. Personal note: Maybe there was a reason why Borland Pascal didn't do range checks on Inc/Dec.

Yes, there is always a good reason for a bug :-)

To the FPC team.
If ever you changed that, i.e., if you suppressed the overflows with Inc and Dec, thanks to let us know explicitely (here, for instance). Personally, I would have to rewrite a few lines of code, like, for instance, in

procedure XDiv2(X: PBigFloat);
begin
   with X^ do if not IEqu0(Mantissa) then {$Q+} Dec(Exponent); {$Q-}
end;
Show quoted text 6 lines
The only time I ever used it was a checksum calculation which was modulo anyway. Any other time I use the usual operators. So especially with the "added" overflow check I think, Inc and Dec are pretty useless functions, because the don't do anything you can't accomplish by using "+" or "-" unless you have very_long_and_complex_variable_names and want to save some typing work.

That's a matter of habit. Not sure but I believe that with TP3, the compiled code was better with "Inc" than with "+".

mm

Reply by email

Marco van de Voort
to Hans-Peter Diettrich: IMO the compiler can convert between Inc and Dec, for negative constants, so that the…
Show quoted text 13 lines
Marcel Martin wrote: > I think Marco is right. Basically, when the compiler has to > code Inc(x,SomeConstant), the only sensible behaviour it is > expected to have is to regard the constant as being of the > type of x. So, if x is a Longword and if SomeConstant equals > -1, either it adds $ffffffff (and there will be an overflow > if x > 0) or it stops at compile time saying that -1 is not > a Longword. IMO the compiler can convert between Inc and Dec, for negative constants, so that the value always is positive, compatible with signed and unsigned data types.

It's not a matter of what can, but what should.

Reply by email

Vinzent Hoefler
to Marcel Martin: Yes, there is always a good reason for a bug :-) To the FPC team. If ever you changed…
Marcel Martin wrote 6 lines
Vinzent Hoefler a écrit : > Personal note: Maybe there was a reason why Borland Pascal didn't > do range checks on Inc/Dec. Yes, there is always a good reason for a bug :-)

Any sufficiently advanced bug cannot be distinguished from a feature. :-)

If ever you changed that, i.e., if you suppressed the overflows with Inc and Dec, thanks to let us know explicitely (here, for instance).

Full ACK. They have to document it either way (and in the past they did).

Show quoted text 7 lines
Personally, I would have to rewrite a few lines of code, like, for instance, in procedure XDiv2(X: PBigFloat); begin with X^ do if not IEqu0(Mantissa) then {$Q+} Dec(Exponent); {$Q-} end;

Yeah. Sure. Same reason I had to rewrite:

|   for i := 0 to Buf_Len - 1 do
|   begin
|      b := tByteArray (Buf)[i];
|      Inc (C_Sum, b); { work around range check error RRG/VH 161100 }
|      ComOut (P_Nr, b);

because after we decided to port the whole stuff to Linux, FPC broke the code again. :-)

Show quoted text 10 lines
> The only time I ever used it was a checksum > calculation which was modulo anyway. Any other time I use the usual > operators. So especially with the "added" overflow check I think, > Inc and Dec are pretty useless functions, because the don't do > anything you can't accomplish by using "+" or "-" unless you have > very_long_and_complex_variable_names and want to save some typing > work. That's a matter of habit. Not sure but I believe that with TP3, the compiled code was better with "Inc" than with "+".

Yes, it used a direct memory increment which was better on the processors we used back then. Interestingly with the introduction of the Pentium 10 years ago which (in most cases) could execute the mem-store/reg-inc/mem-store faster than the direct in-memory-addition this optimization fired back. Of course then it didn't matter that much anymore, 'coz the processor was too fast already. ;-)

Vinzent.

Reply by email

Gerhard Scholz
to Vinzent Hoefler: Which should trigger a range check already, because -1 can't be represented as valid…

----- Original Message -----

Earlier message 58 lines
From: "Vinzent Hoefler" To: "FPC developers' list" Sent: Thursday, July 07, 2005 9:47 AM Subject: Re: [fpc-devel] bug: Inc(v,i)/Dec(v,i) > On Thursday 07 July 2005 05:39, Peter Vreman wrote: > > > > shouldn't it implement inv(v,-1) in exactly the same way it > > > implements v:=v-1? > > > > The problem is what type do you give to -1. In the old situation the > > -1 was converted to the same type as v -> longword. > > Which should trigger a range check already, because -1 can't be > represented as valid longword. > > Personal note: Maybe there was a reason why Borland Pascal didn't do > range checks on Inc/Dec. The only time I ever used it was a checksum > calculation which was modulo anyway. Any other time I use the usual > operators. So especially with the "added" overflow check I think, Inc > and Dec are pretty useless functions, because the don't do anything you > can't accomplish by using "+" or "-" unless you have > very_long_and_complex_variable_names and want to save some typing work. > > > Vinzent. I assume that was exactly the reason why they were introduced: as a shorthand and as a hint for optimization. The original Pascal only had the forms inc(v) and dec(v) so the operation could be done directly on the memory location of the variable (if the machine code had a possibility for that). inc(v,d) and dec(v,d) came later; I think Borland introduced them. The problem is not really a constant param2 (that can be avoided by myself), but a variable param2 (and both can occur: positive and negative deltas!): inc ( v, delta ) ; Solution 1 of course would be: if delta < 0 then dec ( v, -delta ) else inc ( v, delta ) ; but that looks like a joke and not very optimal. Solution 2 would be the safe way (as I'm forced to do it now): v := v + delta ; I think the easiest solution to the whole problem would be to internally translate a "inc(v,d)" to "v := v + d", at least in {$r+,q+} checked code. Gerhard

Reply by email

Marco van de Voort
to Gerhard Scholz
Show quoted text 5 lines
Solution 1 of course would be: if delta < 0 then dec ( v, -delta ) else inc ( v, delta ) ;
inc(longint(v),delta);
Show quoted text 8 lines
but that looks like a joke and not very optimal. Solution 2 would be the safe way (as I'm forced to do it now): v := v + delta ; I think the easiest solution to the whole problem would be to internally translate a "inc(v,d)" to "v := v + d", at least in {$r+,q+} checked code.
This doesn't fix the problem that you are mixing types. v:=v+d is flawed from
that perspective too, the compiler even complains
smbg.pp(9,7) Warning: Mixing signed expressions and longwords gives a 64bit result

on a line like

  v:=v+-5;

Reply by email

Gerhard Scholz
to Marco van de Voort

----- Original Message -----

Earlier message 51 lines
From: "Marco van de Voort" To: "FPC developers' list" Sent: Friday, July 08, 2005 11:52 AM Subject: Re: [fpc-devel] bug: Inc(v,i)/Dec(v,i) > > Solution 1 of course would be: > > > > if delta < 0 > > then dec ( v, -delta ) > > else inc ( v, delta ) ; > > inc(longint(v),delta); Interesting, I didn't know typecasts on the left side of assignment yet. Doesn't look very portable. Beside, v is word or byte, depending on a compiler-$if elsewhere, so I would have to write: inc ( {$ifdef big} smallint {$else} shortint {$endif }v, delta ) ; Not very clear readable. ... > This doesn't fix the problem that you are mixing types. v:=v+d is flawed from > that perspective too, the compiler even complains > > smbg.pp(9,7) Warning: Mixing signed expressions and longwords gives a 64bit result > > on a line like > > v:=v+-5; I'm sorry, v IS unsigned, delta IS signed, and the computation has to be done. Besides, v and d are 8-bit or 16-bit, and the result WILL fit in v (that is checked before for other reasons). Of course, I could convert both v and d to some signed int first, do the computation, and store it back to v, but that just elongates the code and should produce the same result. And I prefer to develop programs with $r+,q+,etc.-checks on and with ranges (I seldom declare "v : integer"; more often I declare "v : 0..99" or similar) [this was one of the major benefits of Pascal against other languages when it was invented] and this saves a good part of testing time. And while testing I do not mind speed as a major factor, but stability. Gerhard

Reply by email

Vinzent Hoefler
to Gerhard Scholz
Gerhard Scholz wrote 6 lines
Beside, v is word or byte, depending on a compiler-$if elsewhere, so I would have to write: inc ( {$ifdef big} smallint {$else} shortint {$endif }v, delta ) ; Not very clear readable.

Agreed. It's not don't do that, instead

{$IFDEF BIG}
type My_Type = SmallInt;
{$ELSE}
type My_Type = ShortInt;
{$ENDIF}

and then

|Inc (My_Type(v), Delta);

should do the trick.

OTOH, to be honest: I don't see the point in using Inc/Dec here at all, especially if "v := v + Delta;" would work perfect already. I even think the "standard" way of doing the addition would be much more readable in that context.

Vinzent.

Reply by email

Gerhard Scholz
to Vinzent Hoefler

----- Original Message -----

Earlier message 43 lines
From: "Vinzent Hoefler" To: "FPC developers' list" Sent: Friday, July 08, 2005 1:24 PM Subject: Re: [fpc-devel] bug: Inc(v,i)/Dec(v,i) ... > Agreed. It's not don't do that, instead > > {$IFDEF BIG} > type My_Type = SmallInt; > {$ELSE} > type My_Type = ShortInt; > {$ENDIF} > > and then > > |Inc (My_Type(v), Delta); > > should do the trick. It's not so easy because v is of subrange x..y where x and y are more complex constant expressions. So I would have to check that with a lot of {$if } to decide between short and small. Makes it also unreadable. > OTOH, ... new abbreviation? what's that? > ... to be honest: I don't see the point in using Inc/Dec here at all, > especially if "v := v + Delta;" would work perfect already. I even > think the "standard" way of doing the addition would be much more > readable in that context. I'm already doing that (now). With some accustomization, "inc(..." and "v := v + ..." is both good readable, and normally (at least with checks off) it was assumed to produce compacter and faster code. Especially when v is not a simple variable, but a more complex one, e.g.: Inc ( v[j]^[k].a[l], delta ) ; And in such a case it's also better readable. Gerhard

Reply by email

Tom Verhoeff
to Vinzent Hoefler: Which should trigger a range check already, because -1 can't be represented as valid…
Vinzent Hoefler wrote 5 lines
operators. So especially with the "added" overflow check I think, Inc and Dec are pretty useless functions, because the don't do anything you can't accomplish by using "+" or "-" unless you have very_long_and_complex_variable_names and want to save some typing work.

You suggest that it saves only typing, but it also simplifies optimization in cases where the variable is compositite, because the address needs to be calculated only once. E.g. in one piece of code, I have a 13-dimensional array of integers, and I do

Inc ( A[e1, e2, ..., e13] )

I don't know if modern compilers will properly optimize

  A[e1, e2, ..., e13] := Succ ( A[e1, e2, ..., e13] )

Recalculation of the index expressions e1 through e13 can be avoided by introducing auxiliary variables, but it is less straightforward to avoid the recalculation of the address given the index values.

In fact, it would be nice to have a Self for arrays as well (as for objects), where you could write

  with A[e1, e2, ..., e13] do
    Self := Succ ( Self )

because that would allow more general expressions to benefit from the one-time address calculation. (Of course, this is just a let/where clause from functional programming). For example,

  with A[e1, e2, ..., e13] do
    Self := Self * ( Self * ( Self + 1 ) + 2 ) + 3

What I sometimes resort to is

  var A: array [ ... ] of record Self: Integer end;
  with A[e1, e2, ..., e13] do
    Self := Self * ( Self * ( Self + 1 ) + 2 ) + 3

But it is a pain to introduce such wrapping records explicitly, because you need to change not only the variable's type, but also all using occurrences of the variable.

Tom

E-MAIL: T.Verhoeff @ TUE.NL | Fac. of Math. & Computing Science PHONE: +31 40 247 41 25 | Eindhoven University of Technology FAX: +31 40 247 54 04 | PO Box 513, NL-5600 MB Eindhoven http://www.win.tue.nl/~wstomv/ | The Netherlands

Reply by email

Vinzent Hoefler
to Gerhard Scholz: ----- Original Message ----- From: "Vinzent Hoefler" To: "FPC developers' list" Sent:…
Gerhard Scholz wrote 9 lines
----- Original Message ----- From: "Vinzent Hoefler" To: "FPC developers' list" Sent: Friday, July 08, 2005 1:24 PM Subject: Re: [fpc-devel] bug: Inc(v,i)/Dec(v,i) > OTOH, ... new abbreviation? what's that?

http://www.acronymfinder.com/af-query.asp?String=exact&Acronym=otoh

;-)

Show quoted text 6 lines
With some accustomization, "inc(..." and "v := v + ..." is both good readable, and normally (at least with checks off) it was assumed to produce compacter and faster code. Especially when v is not a simple variable, but a more complex one, e.g.: Inc ( v[j]^[k].a[l], delta ) ; And in such a case it's also better readable.

Yes, if you really need to do such complex expressions. I tend to write smaller subroutines which take arguments.

Vinzent.

Reply by email

Vinzent Hoefler
to Tom Verhoeff: You suggest that it saves only typing, but it also simplifies optimization in cases where…
Tom Verhoeff wrote 8 lines
On Thu, Jul 07, 2005 at 07:47:03AM +0000, Vinzent Hoefler wrote: > operators. So especially with the "added" overflow check I think, > Inc and Dec are pretty useless functions, because the don't do > anything you can't accomplish by using "+" or "-" unless you have > very_long_and_complex_variable_names and want to save some typing > work. You suggest that it saves only typing,

No, I just tried to ignore that point and hoped nobody would notice. :)

but it also simplifies optimization in cases where the variable is compositite, because the address needs to be calculated only once.

Yes, but in the same way it endorses using functions with side-effects. Consider

|Int_Ptr^ := Int_Ptr^ + 1;

vs.

|Inc (Int_Ptr^);

where Int_Ptr is a function returning a pointer to a different Integer each time it is called.

Show quoted text 8 lines
E.g. in one piece of code, I have a 13-dimensional array of integers, and I do Inc ( A[e1, e2, ..., e13] ) I don't know if modern compilers will properly optimize A[e1, e2, ..., e13] := Succ ( A[e1, e2, ..., e13] )

They should, unless the index expressions are functions - which may have side-effects. See above.

Show quoted text 5 lines
In fact, it would be nice to have a Self for arrays as well (as for objects), where you could write with A[e1, e2, ..., e13] do Self := Succ ( Self )

It could be more generic, if you'd allow renaming declaration like Ada does:

declare
   X : Integer renames A(e1, e2, ..., e13);
begin
   X := X + 1;
end;

Well, the problem with possible side-effects would remain then. Perhaps we should introduce the notion of a pure function (like in VHDL) to give the compiler a hint that it doesn't need to recalculate all that stuff.

Vinzent.

Reply by email

Peter Vreman
to Hans-Peter Diettrich: IMO the compiler can convert between Inc and Dec, for negative constants, so that the…
Show quoted text 13 lines
Marcel Martin wrote: > I think Marco is right. Basically, when the compiler has to > code Inc(x,SomeConstant), the only sensible behaviour it is > expected to have is to regard the constant as being of the > type of x. So, if x is a Longword and if SomeConstant equals > -1, either it adds $ffffffff (and there will be an overflow > if x > 0) or it stops at compile time saying that -1 is not > a Longword. IMO the compiler can convert between Inc and Dec, for negative constants, so that the value always is positive, compatible with signed and unsigned data types.

That means different behaviour between the use of a variable or constant. That is something you never want.

Reply by email

Peter Vreman
to Gerhard Scholz: ----- Original Message ----- From: "Marco van de Voort" To: "FPC developers' list" Sent:…
Show quoted text 5 lines
> v:=v+-5; I'm sorry, v IS unsigned, delta IS signed, and the computation has to be done. Besides, v and d are 8-bit or 16-bit, and the result WILL fit in v (that is checked before for other reasons).

Range check errors are inserted the expression
at the right side the value can be bigger/smaller than what is allowed. The compiler even doesn't know the type of the final destination at that time. And in pascal the rule is to do the calculations in the native integer type. That means 32 bit (or 64 bit for amd64).

Reply by email

Gerhard Scholz
to Peter Vreman

----- Original Message -----

Earlier message 24 lines
From: "Peter Vreman" To: "FPC developers' list" Sent: Friday, July 08, 2005 6:31 PM Subject: Re: [fpc-devel] bug: Inc(v,i)/Dec(v,i) > >> v:=v+-5; > > > > I'm sorry, v IS unsigned, delta IS signed, and the computation has to be > > done. Besides, v and d are 8-bit or 16-bit, and the result WILL fit in v > > (that is checked before for other reasons). > > Range check errors are inserted the expression > at the right side the value can be bigger/smaller than what is allowed. > The compiler even doesn't know the type of the final destination at that > time. And in pascal the rule is to do the calculations in the native > integer type. That means 32 bit (or 64 bit for amd64). inc ( v, d ) gives an overflow, not a rangecheck, when v is unsigned and i is signed. V is byte or word, D is shortint or smallint, the result is positive and in the range of V, and the whole thing produces an overflow, that's the problem.

Reply by email

Hans-Peter Diettrich
to Peter Vreman: That means different behaviour between the use of a variable or constant. That is…
Peter Vreman wrote 6 lines
> IMO the compiler can convert between Inc and Dec, for negative > constants, so that the value always is positive, compatible with > signed and unsigned data types. That means different behaviour between the use of a variable or constant. That is something you never want.

Why not? I expect that the compiler evaluates constant expressions, and creates the best code for the resulting values.

>> So, if x is a Longword and if SomeConstant equals >> -1, either it adds $ffffffff (and there will be an overflow >> if x > 0) or it stops at compile time saying that -1 is not >> a Longword.

In the case of Inc(x, SomeConstant) the value of the named constant can be changed, with arbitrary positive or negative values. Would you then want to find all uses of "someconst" in your code, to find out where your code deserves a modification?

IMO every calculation, that can result in illegal results in *normal* operation, has to be handled appropriately in the code. If no problems are predicted, expected, and handled, in explicit code, the compiler only has to care about coding errors, that result in *unexpected* overflows. I don't think that a calculation should produce or not produce an overflow, depending only on the sign of the given value. From the mathematical viewpoint +(+1) and -(-1) is perfectly equivalent, as is +(-1) and -(+1). When there exist reasons why such expressions should be handled differently, the user is responsible for indicating such an exceptional situation.

DoDi

Reply by email

Marcel Martin
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote 13 lines
Peter Vreman wrote: >>IMO the compiler can convert between Inc and Dec, for negative >>constants, so that the value always is positive, compatible with >>signed and unsigned data types. > >That means different behaviour between the use of a variable or constant. >That is something you never want. Why not? I expect that the compiler evaluates constant expressions, and creates the best code for the resulting values.

The best code is, before all, the correct code.

Show quoted text 10 lines
>>>So, if x is a Longword and if SomeConstant equals >>>-1, either it adds $ffffffff (and there will be an overflow >>>if x > 0) or it stops at compile time saying that -1 is not >>>a Longword. In the case of Inc(x, SomeConstant) the value of the named constant can be changed, with arbitrary positive or negative values. Would you then want to find all uses of "someconst" in your code, to find out where your code deserves a modification?

If I declare a constant as an unsigned integer, if I wrote my code assuming it is an unsigned integer and if, suddenly, I decide to change that, of course, I may expect some problems.

Note: I have the feeling that you are confusing signed/unsigned and negative/positive. When I talk of unsigned integers, I am not talking about signed ones that may be positive. No, I am talking about integers that can never be negative.

Show quoted text 6 lines
IMO every calculation, that can result in illegal results in *normal* operation, has to be handled appropriately in the code. If no problems are predicted, expected, and handled, in explicit code, the compiler only has to care about coding errors, that result in *unexpected* overflows. I don't think that a calculation should produce or not produce an overflow, depending only on the sign of the given value.

Unexpected overflows? The overflows occur or not according to simple rules, perfectly defined, which ones depend on the types of the operands.
If A is a Longword (this is an unsigned type, no instance can be negative). So if A = 2^32-1 and if I compute A + 1, there is an overflow because the resulting value should be 2^32 and this value doesn't exist for the Longword type.

From the mathematical viewpoint +(+1) and -(-1) is perfectly equivalent, as is +(-1) and -(+1).

Computationally, this is not equivalent.
+(-1) -> add eax, $ffffffff
-(+1) -> sub eax, $00000001
And at this point, even if we know the content of eax before the operation, we cannot know if there is or not an overflow without knowing the type of the integer contained in eax.

Moreover, when programming, mathematical considerations have to be handled with care. Mathematically, (x = -x) -> (x = 0). Computationally, this is wrong (because the computer doesn't work over the ring Z but over a ring Z/2^kZ). If x is a Longint and if x = -x, either x = 0 or x = -2^31.
Try this

   x : Longint;
   ...
   x := Longint($80000000); // x := -2^31
   WriteLn(IntToStr(x));
   x := -x;
   WriteLn(IntToStr(x));

(And this is not a bug. This is a consequence of the 2-complement representation of signed integers.)

When there exist reasons why such expressions should be handled differently, the user is responsible for indicating such an exceptional situation.

If the situation is such that I want no overflows, I always can tell the compiler: {$Q-}.

mm

Reply by email

Hans-Peter Diettrich
to Marcel Martin
Marcel Martin wrote
> Why not? I expect that the compiler evaluates constant expressions, and > creates the best code for the resulting values. The best code is, before all, the correct code.

So we have to find out what is *correct*.

Show quoted text 8 lines
> In the case of Inc(x, SomeConstant) the value of the named constant can > be changed, with arbitrary positive or negative values. Would you then > want to find all uses of "someconst" in your code, to find out where > your code deserves a modification? If I declare a constant as an unsigned integer, if I wrote my code assuming it is an unsigned integer and if, suddenly, I decide to change that, of course, I may expect some problems.

Why should one expect problems when incrementing or decrementing an value, maybe signed or unsigned?

Note: I have the feeling that you are confusing signed/unsigned and negative/positive. When I talk of unsigned integers, I am not talking about signed ones that may be positive. No, I am talking about integers that can never be negative.

I do not confuse anything like that.

Show quoted text 10 lines
> IMO every calculation, that can result in illegal results in *normal* > operation, has to be handled appropriately in the code. If no problems > are predicted, expected, and handled, in explicit code, the compiler > only has to care about coding errors, that result in *unexpected* > overflows. I don't think that a calculation should produce or not > produce an overflow, depending only on the sign of the given value. Unexpected overflows? The overflows occur or not according to simple rules, perfectly defined, which ones depend on the types of the operands.

Unexpected as depending on the values, not on the types. When the ranges of the possible operands are known, it's also known whether an overflow can occur in computations with these operands.

If A is a Longword (this is an unsigned type, no instance can be negative). So if A = 2^32-1 and if I compute A + 1, there is an overflow because the resulting value should be 2^32 and this value doesn't exist for the Longword type.

No doubt, when the compiler doesn't extend the range of the arguments (see below).

Show quoted text 10 lines
> From > the mathematical viewpoint +(+1) and -(-1) is perfectly equivalent, as > is +(-1) and -(+1). Computationally, this is not equivalent. +(-1) -> add eax, $ffffffff -(+1) -> sub eax, $00000001 And at this point, even if we know the content of eax before the operation, we cannot know if there is or not an overflow without knowing the type of the integer contained in eax.

Since the hardware cannot know whether $ffffffff is a huge unsigned number, or a small signed number, a possibly thrown or indicated overflow from above instructions is meaningless. This is why a proper and unoptimized implementation must extend values of different signedness to the next bigger type, so that the calculation cannot produce an overflow.

When you consult Wirth and the design of Pascal and his following languages, you'll find out that unsigned data types always are subranges of bigger signed data types. This is why we cannot have an proper UInt64 type without an proper Int128 type, unless one wants to break all sane design rules.

Show quoted text 5 lines
Moreover, when programming, mathematical considerations have to be handled with care. Mathematically, (x = -x) -> (x = 0). Computationally, this is wrong (because the computer doesn't work over the ring Z but over a ring Z/2^kZ). If x is a Longint and if x = -x, either x = 0 or x = -2^31.

Bad example. In 2's complement both 0 and -2^31 have no counterpart of the opposite sign, whereas in 2-1 complement (sorry, don't know the English term) the negative values are represented by the bitwise complement of the positive values. When there exists no representation of -(-2^31), you cannot perform an comparison with that value.

Show quoted text 11 lines
Try this x : Longint; ... x := Longint($80000000); // x := -2^31 WriteLn(IntToStr(x)); x := -x; WriteLn(IntToStr(x)); (And this is not a bug. This is a consequence of the 2-complement representation of signed integers.)

It is a bug. As outlined before, the above assignment of x:=-x should raise an range check error. A comparison of x=-x will return False, in the Int64 range.

The expression Longint($80000000) is questionable because, in the strict sense, it forces the compiler to perform an illegal operation, which only happens to produce an in-range value on specific machines.

I know that unsigned values frequrently are not appropriately handled by many compilers, for *performance* reasons. I also know that many external routines use unsigned values in an inappropriate way, only because it's easier to define an "unsigned int" instead of an proper subrange, and because many languages do not support subrange types at all. I agree that we must live with such weird declarations, but there exists no need, besides performance, for handling such datatypes in an inappropriate way. When you rethink all your arguments and examples, based on an compiler that maps unsigned data types into subranges of the next higher signed type, you'll find out that all problems go away. Every "optimization", violating that rule, will cause selfmade trouble :-(

DoDi

Reply by email

Marcel Martin
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote
So we have to find out what is *correct*.

When I wrote "correct code", I meant "not only the code that gives the correct result but also the code that correctly computes it".

Show quoted text 7 lines
>If I declare a constant as an unsigned integer, if I wrote my >code assuming it is an unsigned integer and if, suddenly, >I decide to change that, of course, I may expect some problems. Why should one expect problems when incrementing or decrementing an value, maybe signed or unsigned?

We are talking about overflows. If I wrote some code that depends on the possible overflows of an instance of type Longword and if I change the type of the variable to Longint without changing the code, I may expect problems.

Show quoted text 8 lines
>Unexpected overflows? The overflows occur or not according to >simple rules, perfectly defined, which ones depend on the types >of the operands. Unexpected as depending on the values, not on the types. When the ranges of the possible operands are known, it's also known whether an overflow can occur in computations with these operands.

But overflows cannot be unexpected. If x is a Longword and if x > 0, Inc(x,-1) will raise an overflow. And this is not unexpected.

Show quoted text 19 lines
> > From > >>the mathematical viewpoint +(+1) and -(-1) is perfectly equivalent, as >>is +(-1) and -(+1). > >Computationally, this is not equivalent. >+(-1) -> add eax, $ffffffff >-(+1) -> sub eax, $00000001 >And at this point, even if we know the content of eax before the >operation, we cannot know if there is or not an overflow without >knowing the type of the integer contained in eax. Since the hardware cannot know whether $ffffffff is a huge unsigned number, or a small signed number, a possibly thrown or indicated overflow from above instructions is meaningless. This is why a proper and unoptimized implementation must extend values of different signedness to the next bigger type, so that the calculation cannot produce an overflow.

That's what FPC does when such a bigger type exists. But are we talking about that?
This thread is about "since the resulting x, after Inc(x,-1), is in the range of x, the compiler should code Dec(x,1)". No, it shouldn't. When a programmer writes "Inc", he explicitely asks the compiler to code an addition and not a subtraction. If, in "Inc(x,-1)", x is a Longword, the compiler should regard "-1" as a Longword or signals a problem. In no case, the compiler should decide not to raise an overflow because the result of an operation is in the range of the destination variable. Overflows depend on operations not on results.

Show quoted text 8 lines
>Moreover, when programming, mathematical considerations have to >be handled with care. Mathematically, (x = -x) -> (x = 0). >Computationally, this is wrong (because the computer doesn't work >over the ring Z but over a ring Z/2^kZ). If x is a Longint and >if x = -x, either x = 0 or x = -2^31. Bad example.

Indeed? :-)

Show quoted text 21 lines
In 2's complement both 0 and -2^31 have no counterpart of the opposite sign, whereas in 2-1 complement (sorry, don't know the English term) the negative values are represented by the bitwise complement of the positive values. When there exists no representation of -(-2^31), you cannot perform an comparison with that value. >Try this > > x : Longint; > ... > x := Longint($80000000); // x := -2^31 > WriteLn(IntToStr(x)); > x := -x; > WriteLn(IntToStr(x)); > >(And this is not a bug. This is a consequence of the 2-complement >representation of signed integers.) It is a bug.

We have a big, BIG, communication problem. When I write, 2^31 = -2^31 is a consequence of the representation and not a bug and when you wrote it is a bug since it should raise a range check error, are we talking of the same thing? ;-)

Moreover, since you use mathematical viewpoints, I don't see where is the problem for you : mathematically, it is true that 2^(k-1) = -2^(k-1) (mod 2^k).

As outlined before, the above assignment of x:=-x should raise an range check error. A comparison of x=-x will return False, in the Int64 range.
Not with FPC. (Moreover, I didn't make comparisons, I only
used ":=" and "-".)
The expression Longint($80000000) is questionable because, in the strict sense, it forces the compiler to perform an illegal operation, which only happens to produce an in-range value on specific machines.
Use this "x := -(1 shl 31);" if you prefer. What does it change
for the purpose of the example?

mm

Reply by email

Marcel Martin
to Marcel Martin
Marcel Martin wrote 8 lines
Hans-Peter Diettrich a écrit : > As outlined before, the above assignment of x:=-x should > raise an range check error. A comparison of x=-x will return False, in > the Int64 range. Not with FPC. (Moreover, I didn't make comparisons, I only used ":=" and "-".)

But, if X is a Longint equal to -2^31, with {$Q+}, the instruction "x := -x;" should raise an overflow and it would seem it doesn't (I just checked it with FPC v2.0). This, this is a bug.

mm

Reply by email

Hans-Peter Diettrich
to Marcel Martin: When I wrote "correct code", I meant "not only the code that gives the correct result but…
Marcel Martin wrote 12 lines
>>Unexpected overflows? The overflows occur or not according to >>simple rules, perfectly defined, which ones depend on the types >>of the operands. > > > Unexpected as depending on the values, not on the types. When the ranges > of the possible operands are known, it's also known whether an overflow > can occur in computations with these operands. But overflows cannot be unexpected. If x is a Longword and if x > 0, Inc(x,-1) will raise an overflow. And this is not unexpected.

It is unexpected, for multiple reasons:

1) From online help in D4:

>

Inc(X) corresponds to the statement X := X + 1, and Inc(X, N) corresponds to the statement X := X + N.
<<
I cannot see any correspondence, when one form produces overflows, whereas the other form doesn't.

2) The overflow only occurs for special, machine specific conditions. The writer of high level language code IMO can expect that no machine specific details will influence the behaviour of his code, else the compiler at least must issue appropriate warnings.

Since I don't have the current FPC compiler, I refer to D4 in this (hopefully) last example:

type
  TCard = 0..1000; //or 0..$FFFFFFFF or 0..$8000
var
  x: TCard;
const
  c = -1;
begin
  x := 5;
  x := x + c;
  Inc(x, c);
end;

Here no overflow occurs, at least not in D4. An overflow occurs only in the special case where the upper bound of the type is $FFFFFFFF, in general when the highest bit in the highest byte of the memory representation is part of the type. Would you call this an expected behaviour?

IMO the inconsistent behaviour of the above code is a bug. I can accept such behaviour only with respect to *full* Delphi compatibility, where every bug must be reproduced also by the FPC compiler. Otherwise I expect a consistent and machine independent compilation and execution of all high level language code.

We have a big, BIG, communication problem...

I realized already that we are talking about different things :-( I'm talking about computation in general, you're talking about machine specific number representations and calculations.

Please check your arguments with regards to unsigned types in general, i.e. any zero-based integer type.

DoDi

Reply by email

Marcel Martin
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote 26 lines
Marcel Martin wrote: >>>Unexpected overflows? The overflows occur or not according to >>>simple rules, perfectly defined, which ones depend on the types >>>of the operands. >> >> >>Unexpected as depending on the values, not on the types. When the ranges >>of the possible operands are known, it's also known whether an overflow >>can occur in computations with these operands. > >But overflows cannot be unexpected. If x is a Longword and >if x > 0, Inc(x,-1) will raise an overflow. And this is not >unexpected. It is unexpected, for multiple reasons: 1) From online help in D4: Inc(X) corresponds to the statement X := X + 1, and Inc(X, N) corresponds to the statement X := X + N. << I cannot see any correspondence, when one form produces overflows, whereas the other form doesn't.

It shouldn't. Under the same circumstances, both have to raise overflows. Here, it's not the overflow rules that are inconsistent but the way they are implemented by such or such compiler.

2) The overflow only occurs for special, machine specific conditions. The writer of high level language code IMO can expect that no machine specific details will influence the behaviour of his code, else the compiler at least must issue appropriate warnings.

I agree. But what is the link with the fact that in no case the compiler should code a "Inc(x,-1)" as a "Dec(x,1)"?

Since I don't have the current FPC compiler, I refer to D4 in this (hopefully) last example:

This list is named "fpc-devel" ;-)

Show quoted text 13 lines
type TCard = 0..1000; //or 0..$FFFFFFFF or 0..$8000 var x: TCard; const c = -1; begin x := 5; x := x + c; Inc(x, c); end; Here no overflow occurs, at least not in D4.

No more with FPC. But with {$R+}, FPC will raise a range check error if the resulting x is not in 0..1000. (For Delphi, I don't know, it's too boring to get the generated assembler code.)

Show quoted text 5 lines
An overflow occurs only in the special case where the upper bound of the type is $FFFFFFFF, in general when the highest bit in the highest byte of the memory representation is part of the type. Would you call this an expected behaviour?

Yes. Because I know that overflows only occur with 'native' types :-)

IMO the inconsistent behaviour of the above code is a bug. I can accept such behaviour only with respect to *full* Delphi compatibility,

This is the last reason for which I would accept. FPC has not to follow Delphi and still less to be compatible with Delphi bugs. (The future of Pascal is not Delphi, this is FPC ;-)

where every bug must be reproduced also by the FPC compiler. Otherwise I expect a consistent and machine independent compilation and execution of all high level language code.

From that point of view, FPC is incomparably better than Delphi. Now, yes, maybe FPC developpers could add some code to check overflows even for 'exotic' types. If you really need it, ask them.

Show quoted text 7 lines
>We have a big, BIG, communication problem... I realized already that we are talking about different things :-( I'm talking about computation in general, you're talking about machine specific number representations and calculations.

We are talking about "Should the compiler replace "Inc(x,-1)" by "Dec(x,1)?" The answer is no. And that's not because perfectly defined overflow rules are not correctly implemented in Delphi that this answer should change.

Please check your arguments with regards to unsigned types in general, i.e. any zero-based integer type.

With your example? If the same rules would apply for both user defined types and native types, in "x := x + c", the compiler should regard c = -1 as c = 1000 (since the range 0..1000 is the one of the residues modulo 1001). So "x := x + c" should be coded as x := x + 1000 (or an error should be raised because -1 is not in 0..1000) and if x > 0, with {$Q+}, the operation should raise an overflow. The same for "Inc(x,c)". (Notice that with "Dec(x,1)", an overflow should occur only if x = 0 whereas with "Inc(x,-1)" it should occur only if x 0. These two instructions yield the same result but they don't get it the same way and, thus, are not equivalent.)

mm

Reply by email

Hans-Peter Diettrich
to Marcel Martin
Marcel Martin wrote 7 lines
> I cannot see any correspondence, when one form produces overflows, > whereas the other form doesn't. It shouldn't. Under the same circumstances, both have to raise overflows. Here, it's not the overflow rules that are inconsistent but the way they are implemented by such or such compiler.

Yes, and no compiler should raise an overflow, IMO.

Show quoted text 7 lines
> 2) The overflow only occurs for special, machine specific conditions. > The writer of high level language code IMO can expect that no machine > specific details will influence the behaviour of his code, else the > compiler at least must issue appropriate warnings. I agree. But what is the link with the fact that in no case the compiler should code a "Inc(x,-1)" as a "Dec(x,1)"?

As already mentioned, a compiler has to produce correct code, and a correct implementation will either reject an increment of -1 for unsigned variables, or will produce correct code that does not raise an overflow.

Show quoted text 5 lines
> Since I don't have the current FPC compiler, I refer to D4 in this > (hopefully) last example: This list is named "fpc-devel" ;-)

Yes, I know, but I could not get the latest version already (small bandwidth).

Show quoted text 18 lines
> type > TCard = 0..1000; //or 0..$FFFFFFFF or 0..$8000 > var > x: TCard; > const > c = -1; > begin > x := 5; > x := x + c; > Inc(x, c); > end; > > Here no overflow occurs, at least not in D4. No more with FPC. But with {$R+}, FPC will raise a range check error if the resulting x is not in 0..1000. (For Delphi, I don't know, it's too boring to get the generated assembler code.)

The range check is okay, it was never under question ;-)

Show quoted text 8 lines
> An overflow occurs only in > the special case where the upper bound of the type is $FFFFFFFF, in > general when the highest bit in the highest byte of the memory > representation is part of the type. Would you call this an expected > behaviour? Yes. Because I know that overflows only occur with 'native' types :-)

Okay, that's somewhat reasonable ;-)

Show quoted text 9 lines
>>We have a big, BIG, communication problem... > > > I realized already that we are talking about different things :-( > I'm talking about computation in general, you're talking about machine > specific number representations and calculations. We are talking about "Should the compiler replace "Inc(x,-1)" by "Dec(x,1)?" The answer is no.

Even if *your* answer is no, my answer still is yes.

Show quoted text 10 lines
> Please check your arguments with regards to unsigned types in general, > i.e. any zero-based integer type. With your example? If the same rules would apply for both user defined types and native types, in "x := x + c", the compiler should regard c = -1 as c = 1000 (since the range 0..1000 is the one of the residues modulo 1001). So "x := x + c" should be coded as x := x + 1000 (or an error should be raised because -1 is not in 0..1000) and if x > 0, with {$Q+}, the operation should raise an overflow.

That's a bit weird, isn't it? If you argue with modulo arithmetic, you should know that overflows or range errors cannot occur then. But Pascal doesn't use modulo arithmetic, so your arguments simply don't apply.

DoDi

Reply by email

Gerhard Scholz
to Hans-Peter Diettrich: It is unexpected, for multiple reasons: 1) From online help in D4: Inc(X) corresponds to…

I have seen, that the Julian-Routines in dateutils are a little bit incomplete.

Since I have a working Julian (and the other way round: nailuJ) -function, I could integrate them, or deliver the functions so somebody else who wants to integrate them.

For integrating I would need more information about the parameters, especially the meaning of the double,
and: which day has a julian value of 1 (in my routines 1.1.1600 is the base)

What is JulianDate vs. ModifiedJulianDate?

Function DateTimeToJulianDate(const AValue: TDateTime): Double;
Function JulianDateToDateTime(const AValue: Double): TDateTime;
Function TryJulianDateToDateTime(const AValue: Double; var ADateTime:
TDateTime): Boolean;
Function DateTimeToModifiedJulianDate(const AValue: TDateTime): Double;
Function ModifiedJulianDateToDateTime(const AValue: Double): TDateTime;
Function TryModifiedJulianDateToDateTime(const AValue: Double; var
ADateTime: TDateTime): Boolean;

Gerhard

Reply by email