View Issue Details

IDProjectCategoryView StatusLast Update
0017710FPCCompilerpublic2011-05-17 21:54
ReporterAdriaan van Os Assigned ToFlorian  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
PlatformDarwin i386OSMac OS X 
Product Version2.5.1 
Fixed in Version2.6.0 
Summary0017710: The minus sign as unary operator
Description{$mode macpas}
program unary;
begin
  writeln( - 2 shr 1)
end.

CodeWarrior prints -1, FPC prints 9223372036854775807. I am not sure about Turbo Pascal and Delphi.
Additional InformationAlso see <http://www2.gnu-pascal.de/crystal/gpc/en/mail15011.html>.
TagsNo tags attached.
Fixed in Revision17489
FPCOldBugId
FPCTarget
Attached Files

Activities

Marco van de Voort

2010-10-25 11:57

manager   ~0042094

Delphi XE prints 2147483647.

Jasper Neumann

2010-10-25 12:19

reporter   ~0042096

Last edited: 2010-10-25 12:22

Indeed -2 shr 1 is identical to (-2) shr 1 whereas -(2 shr 1) = -1.
The shr operator (at least in TP and Delphi) is defined as being unsigned, i.e. shifting in zero bits. Therefore any negative number shifted right by <>0 will result in a non-negative number. -2 shr 1 will result in maxint = high(integer) since -2 is representable as integer.
Please correct me if I'm wrong.

Jonas Maebe

2010-10-25 13:08

manager   ~0042099

And this is what Kylix prints:


$ cat > tw17710.pp
program unary;
begin
writeln( -1 ); {-1}
writeln( 2 shr 1 ); { 1}
writeln((-2)shr 1 ); {GPC: -1 FPC: 9223372036854775807}
writeln(-(2 shr 1)); {-1}
writeln( -2 shr 1 ); {GPC: -1 FPC: 9223372036854775807}
writeln( -2 div 2 ); {-1}
end.

$ dcc tw17710.pp
Borland Delphi for Linux Version 14.5
Copyright (c) 1983,2002 Borland Software Corporation
tw17710.pp(10)
11 lines, 0.00 seconds, 22236 bytes code, 3088 bytes data.

$ ./tw17710
-1
1
-1
-1
-1
-1

It doesn't seem like there's too much agreement on the correct result around...

Adriaan van Os

2010-10-25 14:46

developer   ~0042103

The point seems to be that Delphi, Kylix, GPC and CodeWarrior perform an arithmetic shift, whereas Borland/Turbo Pascal and FPC perform a logical shift. See <http://www2.gnu-pascal.de/crystal/gpc/en/mail15016.html> and <http://en.wikipedia.org/wiki/Arithmetic_shift>.

The other issue is the operator precedence of '-'. GPC follows the Pascal standard. FPC follows Borland/Turbo Pascal.

program arithmeticshift;
begin
  writeln( -(1 shr 1));
  writeln( -1 shr 1);
  writeln( (-1) shr 1)
end.

Adriaan van Os

2010-10-25 15:54

developer   ~0042108

I think, for negative numbers, an arithmetic shift right makes more sense than a logical shift right.

Adriaan van Os

2010-10-25 15:56

developer   ~0042109

I received a report that Delphi 2006 prints 2147483647 for writeln( -2 shr 1).

Jasper Neumann

2010-10-25 16:48

reporter   ~0042110

Last edited: 2010-10-25 17:04

It seems that FPC and Delphi are differently buggy when shifting right negative constants.
It might be that D6 internally uses int64 and D2006 a larger type (128 bit?) for constants.

For non-constants FPC, Delphi-6, and Delphi-2006 work as expected.

program unary;
begin
  writeln( sizeof(integer) ); { must be 4 for compatibility to Delphi }
  writeln( -1 ); {-1}
  writeln( 2 shr 1 ); { 1}
  writeln((-2)shr 1 ); {GPC: -1, FPC: 9223372036854775807, D6: -1, D2006: 2147483647}
  writeln(-(2 shr 1)); {-1}
  writeln( -2 shr 1 ); {GPC: -1, FPC: 9223372036854775807, D6: -1, D2006: 2147483647}
  writeln( -2 div 2 ); {-1}
  writeln( integer(-2) shr 1 ); {GPC: ?, FPC: 9223372036854775807, D6: -1, D2006: 2147483647}
  writeln( integer(-2 shr 1) ); {GPC: ?, FPC: -1, D6: -1, D2006: 2147483647}
  writeln( int64(-2) shr 1 ); {GPC: ?, FPC: 9223372036854775807, D6: 9223372036854775807, D2006: -1}
end.

Of course it would make sense to perform an arithmetic shift for negative left arguments and a logical one for unsigned. I think Borland made (1983, Turbo Pascal 1.0) the wrong decision when they defined shr to always shift logical.

Quintessence: Don't shr negative constants.

Marco van de Voort

2010-10-25 20:11

manager   ~0042115

I ran Jasper's test for Delphi XE, and the results are much like D2006:

4
-1
1
2147483647
-1
2147483647
-1
2147483647
2147483647
9223372036854775807

Adriaan van Os

2010-10-27 10:30

developer   ~0042194

I suggest to change the compiler to use arithmetic shift right for signed integer types, except in delphi and tp modes.

Jonas Maebe

2010-10-27 11:08

manager   ~0042196

> I suggest to change the compiler to use arithmetic shift right
> for signed integer types, except in delphi and tp modes.

That will definitely not happen. To be really compatible with the behaviour described, it would make the behaviour different between operations on a variable (logical shift right) and on a constant (arithmetic shift right). Performing an arithmetic shift right in all cases would break backward compatibility in a horrible way for no real gain.

Note that FPC trunk supports arithmetic shift right at the Pascal leven via the following routines:

  function SarShortint(Const AValue : Shortint): Shortint;
  function SarShortint(Const AValue : Shortint;Shift : Byte): Shortint;
  function SarSmallint(Const AValue : Smallint): Smallint;
  function SarSmallint(Const AValue : Smallint;Shift : Byte): Smallint;
  function SarLongint(Const AValue : Longint): Longint;
  function SarLongint(Const AValue : Longint;Shift : Byte): Longint;
  function SarInt64(Const AValue : Int64): Int64;
  function SarInt64(Const AValue : Int64;Shift : Byte): Int64;

They are handled as compiler intrinsics (to the extent that the hardware supports the operations with the relevant sizes) and hence do not cause any function call overhead unless necessary. The only limitation is that unlike shl/shr, you cannot use them in definitions of formal constants.

Adriaan van Os

2010-10-27 11:48

developer   ~0042197

Last edited: 2010-10-27 11:49

There need be no conflict between the behaviour for constants and variables. Constant have an implicit type, or at least an implicit type behaviour.

A find the argument about "breaking backward compatibility in a horrible way" rather amusing. All bug fixing does that. And the current behaviour for mode macpas does "break backward compatibility in a horrible way".

Jonas Maebe

2010-10-27 12:58

manager   ~0042200

> There need be no conflict between the behaviour for constants
> and variables. Constant have an implicit type, or at least an
> implicit type behaviour.

I didn't say that there has to be a conflict, I said there is a conflict if we implement the behaviour described above and in the messages on GPC mailing list. Looking closer, that's only the case if we implement the Delphi behaviour though (for one Delphi version or another).

> A find the argument about "breaking backward compatibility in a
> horrible way" rather amusing. All bug fixing does that.

It does not. Changing the semantics, which may be required to fix a bug, does, of course.

> And the current behaviour for mode macpas does "break backward
> compatibility in a horrible way".

It can be changed for MacPas mode. It won't be changed for FPC and ObjFPC modes.

Jasper Neumann

2010-10-27 15:25

reporter   ~0042204

Last edited: 2010-10-27 15:26

As far as I can see and understand: If you do not shr negative constants there is no problem. The issue arises because constants normally have no definitive implicit type; a constant only gets typed when used together with a non-const, e.g. assignment or addition to a variable.
I'm not sure about "integer(-2) shr 1" whether it should result in 2**31-1 because the -2 is explicitely typed to a 32 bit signed entity.

BTW: Isn't there an operator SAR? If not, why not introduce it and make it available for manifest const expressions (i.e. formal constants)?

For the similar rotate operators there *must* be a definitive type to work upon...

Jonas Maebe

2010-10-27 15:51

manager   ~0042206

> The issue arises because constants normally have no
> definitive implicit type

It's not just about implicit types, because when shifting a variable (even a longint with a negative value) TP/Delphi always use a logical shift right, even though the type is perfectly known there.

> BTW: Isn't there an operator SAR?

No.

> If not, why not introduce it

Because we have decided not to complicate the parser by introducing more and more operators, and instead have opted to extend the compiler via intrinsics, such as the ones mentioned in my comment 0042196 above.

> For the similar rotate operators there *must* be a definitive
> type to work upon...

That's why they are also defined as intrinsics with the type name encoded in the intrinsic itself.

Jasper Neumann

2010-10-28 13:38

reporter   ~0042246

Last edited: 2010-10-28 14:04

JM> It's not just about implicit types,
JM> because when shifting a variable (even a longint with a negative value)
JM> TP/Delphi always use a logical shift right,
JM> even though the type is perfectly known there.

If it's not just about constants having no implicit type, how do you
interpret the results of integer(-2) shr 1?
FPC: c:int64:=integer(-2); result:int64:=c shr 1
D6: c:int64:=integer(-2); result:integer:=c shr 1
D2006: c:integer:=integer(-2); result:integer:=c shr 1
Which implementation is "correct"? Which is "best"?

See above in my test:
writeln( integer(-2) shr 1 ); {GPC: ?, FPC: 9223372036854775807, D6: -1,
D2006: 2147483647}

Which proc will be used in FPC for swap($fedc) or swap(word($fedc)) or swap(integer($fedc))?
The (incompatible to Delphi) one for int64 swapping two dwords?
All versions of TP/BP/Delphi will result probably in $dcfe for these cases.
Here too: Which implementation is "correct"? Which is "best"?

Florian

2011-05-17 21:54

administrator   ~0048364

The precedence is fixed. If shr should behave differently as it is now, please open a separate issue report with some examples how it is supposed to work.

Issue History

Date Modified Username Field Change
2010-10-25 11:37 Adriaan van Os New Issue
2010-10-25 11:57 Marco van de Voort Note Added: 0042094
2010-10-25 12:19 Jasper Neumann Note Added: 0042096
2010-10-25 12:22 Jasper Neumann Note Edited: 0042096
2010-10-25 13:08 Jonas Maebe Note Added: 0042099
2010-10-25 14:46 Adriaan van Os Note Added: 0042103
2010-10-25 15:54 Adriaan van Os Note Added: 0042108
2010-10-25 15:56 Adriaan van Os Note Added: 0042109
2010-10-25 16:48 Jasper Neumann Note Added: 0042110
2010-10-25 16:52 Jasper Neumann Note Edited: 0042110
2010-10-25 16:53 Jasper Neumann Note Edited: 0042110
2010-10-25 17:04 Jasper Neumann Note Edited: 0042110
2010-10-25 20:11 Marco van de Voort Note Added: 0042115
2010-10-27 10:30 Adriaan van Os Note Added: 0042194
2010-10-27 11:08 Jonas Maebe Note Added: 0042196
2010-10-27 11:48 Adriaan van Os Note Added: 0042197
2010-10-27 11:49 Adriaan van Os Note Edited: 0042197
2010-10-27 12:58 Jonas Maebe Note Added: 0042200
2010-10-27 15:25 Jasper Neumann Note Added: 0042204
2010-10-27 15:26 Jasper Neumann Note Edited: 0042204
2010-10-27 15:51 Jonas Maebe Note Added: 0042206
2010-10-28 13:38 Jasper Neumann Note Added: 0042246
2010-10-28 14:04 Jasper Neumann Note Edited: 0042246
2011-05-17 21:54 Florian Fixed in Revision => 17489
2011-05-17 21:54 Florian Status new => resolved
2011-05-17 21:54 Florian Fixed in Version => 2.5.1
2011-05-17 21:54 Florian Resolution open => fixed
2011-05-17 21:54 Florian Assigned To => Florian
2011-05-17 21:54 Florian Note Added: 0048364