View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0017710 | FPC | Compiler | public | 2010-10-25 11:37 | 2011-05-17 21:54 |
Reporter | Adriaan van Os | Assigned To | Florian | ||
Priority | normal | Severity | minor | Reproducibility | always |
Status | resolved | Resolution | fixed | ||
Platform | Darwin i386 | OS | Mac OS X | ||
Product Version | 2.5.1 | ||||
Fixed in Version | 2.6.0 | ||||
Summary | 0017710: 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 Information | Also see <http://www2.gnu-pascal.de/crystal/gpc/en/mail15011.html>. | ||||
Tags | No tags attached. | ||||
Fixed in Revision | 17489 | ||||
FPCOldBugId | |||||
FPCTarget | |||||
Attached Files |
|
|
Delphi XE prints 2147483647. |
|
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. |
|
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... |
|
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. |
|
I think, for negative numbers, an arithmetic shift right makes more sense than a logical shift right. |
|
I received a report that Delphi 2006 prints 2147483647 for writeln( -2 shr 1). |
|
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. |
|
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 |
|
I suggest to change the compiler to use arithmetic shift right for signed integer types, except in delphi and tp modes. |
|
> 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. |
|
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". |
|
> 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. |
|
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... |
|
> 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. |
|
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"? |
|
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. |
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 |