Lazarus

Free Pascal => General => Topic started by: Avinash on January 20, 2020, 10:58:56 am

Title: Any traces of «if» statement disappeared
Post by: Avinash on January 20, 2020, 10:58:56 am
I re-saved the file, try recompile with -B and with -O-, but...

Code: Pascal  [Select][+][-]
  1. function SysFindFirst(Path: PChar; Attr: Longint; var F: TOSSearchRec; IsPChar: Boolean): Longint;
  2. begin
  3.   F.ExcludeAttr := Attr;
  4.   F.Handle := FindFirstFile(Path, F.FindData);
  5.   if F.Handle <> invalid_Handle_Value then
  6.     begin
  7.       Result := DoFindFile(F, IsPChar);
  8.       if Result <> 0 then
  9.         begin
  10.           FindClose(F.Handle);
  11.           F.Handle := invalid_Handle_Value;
  12.         end;
  13.     end
  14.   else
  15.     Result := GetLastError;
  16. end;

fpc -Anasmwin32 -al -O- -Mtp -Rintel vpsyslow.pas
oops!

Code: Pascal  [Select][+][-]
  1. SECTION .text
  2.     ALIGN 16
  3.     GLOBAL VPSYSLOW_$$_SYSFINDFIRST$PCHAR$LONGINT$TOSSEARCHREC$BOOLEAN$$LONGINT
  4. VPSYSLOW_$$_SYSFINDFIRST$PCHAR$LONGINT$TOSSEARCHREC$BOOLEAN$$LONGINT:
  5. ; [1038] begin
  6.         push    ebp
  7.         mov ebp,esp
  8.         lea esp,[esp-16]
  9. ; Var Path located at ebp-4, size=OS_32
  10. ; Var Attr located at ebp-8, size=OS_S32
  11. ; Var F located at ebp-12, size=OS_32
  12. ; Var IsPChar located at ebp+8, size=OS_8
  13. ; Var $result located at ebp-16, size=OS_S32
  14.         mov dword [ebp-4],eax
  15.         mov dword [ebp-8],edx
  16.         mov dword [ebp-12],ecx
  17. ; [1039] F.ExcludeAttr := Attr;
  18.         mov eax,dword [ebp-12]
  19.         mov edx,dword [ebp-8]
  20.         mov dword [eax+277],edx
  21. ; [1040] F.Handle := FindFirstFile(Path, F.FindData);
  22.         mov eax,dword [ebp-12]
  23.         lea eax,[eax+281]
  24.         push    eax
  25.         push    dword [ebp-4]
  26.         call    _$dll$kernel32$FindFirstFileA
  27.         mov edx,dword [ebp-12]
  28.         mov dword [edx],eax
  29. ; [1043] Result := DoFindFile(F, IsPChar);
  30.         mov eax,dword [ebp-12]
  31.         mov dl,byte [ebp+8]
  32.         call    VPSYSLOW_$$_DOFINDFILE$TOSSEARCHREC$BOOLEAN$$LONGINT
  33.         mov dword [ebp-16],eax
  34. ; [1044] if Result <> 0 then
  35.         cmp dword [ebp-16],0
  36.         jne ..@j1550
  37.         jmp ..@j1551
  38. ..@j1550:
  39. ; [1046] FindClose(F.Handle);
  40.         mov eax,dword [ebp-12]
  41.         push    dword [eax]
  42.         call    _$dll$kernel32$FindClose
  43. ; [1047] F.Handle := invalid_Handle_Value;
  44.         mov eax,dword [ebp-12]
  45.         mov dword [eax],-1
  46. ..@j1551:
  47. ; [1052] end;
  48.         mov eax,dword [ebp-16]
  49.         leave
  50.         ret 4

Where if F.Handle <> invalid_Handle_Value then / else ?
Title: Re: Any traces of «if» statement disappeared
Post by: marcov on January 20, 2020, 11:05:39 am
Do both sides of the IF have the same type?

This sometimes happen with broken code that compares a variable of an unsigned type to a signed (and negative) constant.

Maybe it finds some VP definition that doesn't typecast the rhs to thandle. Unit Windows is correct and has

Code: Pascal  [Select][+][-]
  1. const   INVALID_HANDLE_VALUE = HANDLE(-1);
  2.  

A unsigned value is of course never negative, so it gets optimized away.
Title: Re: Any traces of «if» statement disappeared
Post by: Avinash on January 20, 2020, 11:23:21 am
TOSSearchRec.Handle: Longint;

Code: Pascal  [Select][+][-]
  1. type
  2.   TOSSearchRec = packed record
  3.     Handle: Longint;
  4.     NameLStr: Pointer;
  5.     Attr: Byte;
  6.     Time: Longint;
  7.     Size: Longint;
  8.     Name: ShortString;
  9.     Filler: array[0..3] of Char;
  10. {$IFDEF WIN32}
  11.     ExcludeAttr: Longint;
  12.     FindData:    TWin32FindData;
  13. {$ENDIF}
  14. {$IFDEF DPMI32}
  15.     attr_must:byte;
  16.     dos_dta:
  17.       record
  18.         Fill: array[1..21] of Byte;
  19.         Attr: Byte;
  20.         Time: Longint;
  21.         Size: Longint;
  22.         Name: array[0..12] of Char;
  23.       end;
  24. {$ENDIF}
  25. {$IFDEF LINUX}
  26.     FindDir:  array[0..255] of Char;
  27.     FindName: ShortString;
  28.     FindAttr: LongInt;
  29. {$ENDIF}
  30.   end;
Title: Re: Any traces of «if» statement disappeared
Post by: marcov on January 20, 2020, 11:33:36 am
Cool! Then FPC can even track that handle is assigned using findfirstfile and propagates the fact that findfirstfile returns an unsigned value, thus .handle can't be negative!

More advanced then I thought!

Try changing handle to unsigned, or maybe typecasting the result of the windows api FIND* functions if you want them to return deviant types.

If that doesn't work, make a small compilable example to test with.
Title: Re: Any traces of «if» statement disappeared
Post by: Avinash on January 20, 2020, 12:02:16 pm
Try changing handle to unsigned, or maybe typecasting the result of the windows api FIND* functions if you want them to return deviant types.

with no success

I attached files, compiled by
fpc -Anasmwin32 -al -O- -Mtp -Rintel -MRESULT vpsyslow.pas
Title: Re: Any traces of «if» statement disappeared
Post by: Avinash on January 20, 2020, 12:23:27 pm
if F.Handle <> LongInt(invalid_Handle_Value)
helps, thanks

but this does not feel like advanced feature
Title: Re: Any traces of «if» statement disappeared
Post by: marcov on January 20, 2020, 01:24:05 pm
Well, Windows handles are unsigned. So logically you'd keep everything unsigned. That you don't introduces the problems.

Note that the optimization doesn't matter. In any Delphi like that has int64, a integer<>cardinal comparison or addition will be upscaled, and this comparison will always fail because   int64(-1) <>  int64(cardinal(4294967295)).

In FPC and Delphi after 4, this generally got cleaned up, but if you are recycling ancient code this might trip you.
Title: Re: Any traces of «if» statement disappeared
Post by: Avinash on January 20, 2020, 03:15:32 pm
Yes you are right. My dissatisfaction was caused by the fact that when I changed the type of TOSSearchRec.Handle to DWord, nothing changed, but this turned out to be because somewhere there was a type definition of DWord = LongInt. And so everything in FPC is correct.
Title: Re: Any traces of «if» statement disappeared
Post by: MarkMLl on January 20, 2020, 03:26:29 pm
Yes you are right. My dissatisfaction was caused by the fact that when I changed the type of TOSSearchRec.Handle to DWord, nothing changed, but this turned out to be because somewhere there was a type definition of DWord = LongInt. And so everything in FPC is correct.

Also note that QWord is defined as signed, so defining large unsigned 64-bit numbers needs a cast. Unfortunate... and in fairness I have to say that when I queried that a year or so ago it was described to me as a compiler design choice. So it's not entirely a library coding issue.

Handles are a very real problem, since at least in unix-derived OSes there's a convention that a -ve handle represents an error. Unfortunately a handle might also represent a memory address, even though it should be treated as an opaque type about which an application programmer should assume nothing. There quite simply isn't an answer which can satisfy everybody across all platforms.

MarkMLl
Title: Re: Any traces of «if» statement disappeared
Post by: PascalDragon on January 20, 2020, 10:50:03 pm
Yes you are right. My dissatisfaction was caused by the fact that when I changed the type of TOSSearchRec.Handle to DWord, nothing changed, but this turned out to be because somewhere there was a type definition of DWord = LongInt. And so everything in FPC is correct.

Also note that QWord is defined as signed, so defining large unsigned 64-bit numbers needs a cast. Unfortunate... and in fairness I have to say that when I queried that a year or so ago it was described to me as a compiler design choice. So it's not entirely a library coding issue.
This is incorrect. QWord is an unsigned type. However untyped 64-bit constants are always considered signed unless they are cast to QWord.
Title: Re: Any traces of «if» statement disappeared
Post by: MarkMLl on January 20, 2020, 11:04:43 pm
Also note that QWord is defined as signed, so defining large unsigned 64-bit numbers needs a cast. Unfortunate... and in fairness I have to say that when I queried that a year or so ago it was described to me as a compiler design choice. So it's not entirely a library coding issue.
This is incorrect. QWord is an unsigned type. However untyped 64-bit constants are always considered signed unless they are cast to QWord.

My apologies. I meant to say that QWord is implemented internally as a signed 64-bit.

MarkMLl
Title: Re: Any traces of «if» statement disappeared
Post by: jamie on January 21, 2020, 12:13:45 am
In 3.0.2 64, QWORD is a intrinsic type and Uint64 = QWORD

I am sure it's the same for the 32 bit verison/.
That looks correct to me.
Title: Re: Any traces of «if» statement disappeared
Post by: MarkMLl on January 21, 2020, 09:23:04 am
In 3.0.2 64, QWORD is a intrinsic type and Uint64 = QWORD

I am sure it's the same for the 32 bit verison/.
That looks correct to me.

Code: [Select]
0 1>markMLl@desktop:~$ cat test.pas
program test;

var
  x, y, z: qword;

begin
  x := $7fffffffffffffff;
  y := $ffffffffffffffff;
  z := $8000000000000000
end.

0 1>markMLl@desktop:~$ fpc test
Free Pascal Compiler version 3.0.4 [2018/07/03] for x86_64
Copyright (c) 1993-2017 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling test.pas
test.pas(8,8) Warning: range check error while evaluating constants (-1 must be between 0 and 18446744073709551615)
test.pas(9,8) Warning: range check error while evaluating constants (-9223372036854775808 must be between 0 and 18446744073709551615)
test.pas(4,3) Note: Local variable "x" is assigned but never used
test.pas(4,6) Note: Local variable "y" is assigned but never used
test.pas(4,9) Note: Local variable "z" is assigned but never used
Linking test
/usr/bin/ld: warning: link.res contains output sections; did you forget -T?
11 lines compiled, 0.1 sec
2 warning(s) issued
3 note(s) issued

Note warnings in line 8 & 9.

MarkMLl
Title: Re: Any traces of «if» statement disappeared
Post by: PascalDragon on January 21, 2020, 10:00:41 am
Also note that QWord is defined as signed, so defining large unsigned 64-bit numbers needs a cast. Unfortunate... and in fairness I have to say that when I queried that a year or so ago it was described to me as a compiler design choice. So it's not entirely a library coding issue.
This is incorrect. QWord is an unsigned type. However untyped 64-bit constants are always considered signed unless they are cast to QWord.

My apologies. I meant to say that QWord is implemented internally as a signed 64-bit.
That is also not true. Where did you get that idea?
Title: Re: Any traces of «if» statement disappeared
Post by: MarkMLl on January 21, 2020, 10:15:54 am
That is also not true. Where did you get that idea?

Jonas, although since it was on the ML I'd rather not try to find out how I'm misquoting him :-)

MarkMLl
Title: Re: Any traces of «if» statement disappeared
Post by: PascalDragon on January 21, 2020, 02:51:22 pm
In 3.0.2 64, QWORD is a intrinsic type and Uint64 = QWORD

I am sure it's the same for the 32 bit verison/.
That looks correct to me.

Code: [Select]
0 1>markMLl@desktop:~$ cat test.pas
program test;

var
  x, y, z: qword;

begin
  x := $7fffffffffffffff;
  y := $ffffffffffffffff;
  z := $8000000000000000
end.

0 1>markMLl@desktop:~$ fpc test
Free Pascal Compiler version 3.0.4 [2018/07/03] for x86_64
Copyright (c) 1993-2017 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling test.pas
test.pas(8,8) Warning: range check error while evaluating constants (-1 must be between 0 and 18446744073709551615)
test.pas(9,8) Warning: range check error while evaluating constants (-9223372036854775808 must be between 0 and 18446744073709551615)
test.pas(4,3) Note: Local variable "x" is assigned but never used
test.pas(4,6) Note: Local variable "y" is assigned but never used
test.pas(4,9) Note: Local variable "z" is assigned but never used
Linking test
/usr/bin/ld: warning: link.res contains output sections; did you forget -T?
11 lines compiled, 0.1 sec
2 warning(s) issued
3 note(s) issued

Note warnings in line 8 & 9.
As I have written above 64-bit constants are always signed. In Pascal the result of an expression also does not depend on what it is assigned to (with a few exceptions like overloaded function/method pointers). And Pascal has signed as the main type. Thus you need to explicitly cast the constant to QWord. This does in no way mean that QWord is signed.
Title: Re: Any traces of «if» statement disappeared
Post by: Avinash on January 23, 2020, 08:41:17 pm
Where if F.Handle <> invalid_Handle_Value then / else ?

It was the tip of the iceberg. In old Pascal programs LongInt is widely used in comparing file signatures, identifiers, and also in bit fields. Four ASCII characters can easily be more than $7FFFFFFF.
In {$MODE TP} the Integer becomes SmallInt, but the functioning of LongInt remains unchanged, while in Turbo Pascal it is different. Similar to how Int64 works now:

Code: Pascal  [Select][+][-]
  1. var
  2.   L: LongInt;
  3.   I: Int64;
  4. begin
  5.   L := $FFFFFFFF;
  6.   WriteLn(L = $FFFFFFFF);           { = FALSE   (Turbo Pascal gives TRUE) }
  7.  
  8.   I := $FFFFFFFFFFFFFFFF;
  9.   WriteLn(I = $FFFFFFFFFFFFFFFF);   { = TRUE  }
  10. end.

As a result, only about half of the comparisons remain working when compiling this FPC. Need I say what will happen to the code if you cross out half the lines?
I tried to overload the comparison operator, but I got a message that this is «impossible»

Code: Pascal  [Select][+][-]
  1. operator = (D: DWord; L: LongInt) B: Boolean; Inline;
  2. begin
  3.   B := (D = DWord(L));
  4. end;

Is there a solution other than manually editing a iceberg of code?
Title: Re: Any traces of «if» statement disappeared
Post by: PascalDragon on January 24, 2020, 04:10:25 pm
It was the tip of the iceberg. In old Pascal programs LongInt is widely used in comparing file signatures, identifiers, and also in bit fields. Four ASCII characters can easily be more than $7FFFFFFF.
In {$MODE TP} the Integer becomes SmallInt, but the functioning of LongInt remains unchanged, while in Turbo Pascal it is different.

Integer is defined as a type that changes its meaning with the mode (TP, FPC vs. ObjFPC, Delphi) while LongInt is always 32-bit.

Similar to how Int64 works now:

Code: Pascal  [Select][+][-]
  1. var
  2.   L: LongInt;
  3.   I: Int64;
  4. begin
  5.   L := $FFFFFFFF;
  6.   WriteLn(L = $FFFFFFFF);           { = FALSE   (Turbo Pascal gives TRUE) }
  7.  
  8.   I := $FFFFFFFFFFFFFFFF;
  9.   WriteLn(I = $FFFFFFFFFFFFFFFF);   { = TRUE  }
  10. end.

As a result, only about half of the comparisons remain working when compiling this FPC. Need I say what will happen to the code if you cross out half the lines?

Please pay attention to the warnings that FPC generates. When I compile that code I get the following output:

Code: [Select]
Compiling .\fpctests\ttest.pp
ttest.pp(7,8) Warning: Range check error while evaluating constants (4294967295 must be between -2147483648 and 2147483647)
ttest.pp(8,13) Warning: Comparison might be always false due to range of constant and expression
Linking testoutput\ttest.exe
12 lines compiled, 0.0 sec, 28512 bytes code, 1300 bytes data
2 warning(s) issued

The first warning explicitly tells you why that comparison is wrong. FPC supports 64-bit values, this is why $FFFFFFFF is interpreted as signed 64-bit value. And that is not equal to LongInt($FFFFFFFF).

You can compile with -Sew so that all warnings are handled as errors. Please note that this really means all warnings. Using {$warn XXX error} (where XXX is the error number you can get when compiling with -vq) you can also selectively treat some warnings as errors. My suggestion would be to put these into an include file and to include that at the top of all of your units.

I tried to overload the comparison operator, but I got a message that this is «impossible»

Code: Pascal  [Select][+][-]
  1. operator = (D: DWord; L: LongInt) B: Boolean; Inline;
  2. begin
  3.   B := (D = DWord(L));
  4. end;

Only operators that don't have an internal operator can be overloaded.
Title: Re: Any traces of «if» statement disappeared
Post by: ASerge on January 24, 2020, 04:37:59 pm
Code: Pascal  [Select][+][-]
  1. var
  2.   L: LongInt;
  3.   I: Int64;
  4. begin
  5.   L := $FFFFFFFF;
  6.   WriteLn(L = $FFFFFFFF);           { = FALSE   (Turbo Pascal gives TRUE) }
  7.  
  8.   I := $FFFFFFFFFFFFFFFF;
  9.   WriteLn(I = $FFFFFFFFFFFFFFFF);   { = TRUE  }
  10. end.
By the way in Delphi False not only in the first case, but also in the second. Delphi believes that the signed Int64 can never be equal to the maximum unsigned.
Title: Re: Any traces of «if» statement disappeared
Post by: marcov on January 24, 2020, 04:39:52 pm
It was the tip of the iceberg. In old Pascal programs LongInt is widely used in comparing file signatures, identifiers, and also in bit fields. Four ASCII characters can easily be more than $7FFFFFFF.

Yes, probably.

Is there a solution other than manually editing a iceberg of code?

No, hackish solutions like the overload are not wise since not very transparent. You never know if they fix everything adequately in all cases, and worse they can mask warnings.

Delphi 4 is from 1998, so this change is already 22 years old. (though to be fair, FPC only has it since 1.9.x precursor series in late 2003). Time to kill the beast.


Title: Re: Any traces of «if» statement disappeared
Post by: lucamar on January 24, 2020, 05:02:19 pm
Four ASCII characters can easily be more than $7FFFFFFF.

Yes, probably.

If we're really talking of ASCII characters then no, it can never be: ASCII only defines characters $00..$7F. Unless one defines ASCII as "not quite just ASCII".

Yes, I know: "nitpicking" ... but let's use correct terminology ;)
Title: Re: Any traces of «if» statement disappeared
Post by: Avinash on January 26, 2020, 05:11:33 pm
Using {$warn XXX error} (where XXX is the error number you can get when compiling with -vq) you can also selectively treat some warnings as errors. My suggestion would be to put these into an include file and to include that at the top of all of your units.

Thanks, very good advice. I fixed a lot of undetected bugs in this way (also those with asm reg32, Word). This message filtering is very useful since the original 500 warnings were untreatable, even with redirection to the file using -Fe.

I note that something doesn’t work in FPC with directive parsing, and outside of simple pieces, the $WARN directive works with message numbers is somehow inconsistently, or maybe some of the directives are skipped (and with +/- instead of ON/OFF it doesn't seem to parse at all). Using the -vm keys here is a much more reliable way (if I remember correctly, I had the same problem with $ASMMODE, and I was forced to use the -Rintel switch instead of the directive).
Title: Re: Any traces of «if» statement disappeared
Post by: PascalDragon on January 27, 2020, 09:22:25 am
I note that something doesn’t work in FPC with directive parsing, and outside of simple pieces, the $WARN directive works with message numbers is somehow inconsistently, or maybe some of the directives are skipped (and with +/- instead of ON/OFF it doesn't seem to parse at all). Using the -vm keys here is a much more reliable way (if I remember correctly, I had the same problem with $ASMMODE, and I was forced to use the -Rintel switch instead of the directive).

According to the docs (https://www.freepascal.org/docs-html/current/prog/progsu80.html#x87-860001.2.80) +/- should work for $WARN. Could either be a bug in the compiler or in the documentation. Can you provide a reproducible, self contained example?

Also you need to add these to each unit (that's why I said include file). Only adding them e.g. in the main program file will not work.
Title: Re: Any traces of «if» statement disappeared
Post by: Thaddy on January 27, 2020, 09:26:42 am
I can't reproduce it, e.g. {$warn 5026-} etc works. Maybe you used a space before - ? That indeed does not work.
[edit]
Not anymore, may be regression?
Title: Re: Any traces of «if» statement disappeared
Post by: PascalDragon on January 27, 2020, 09:32:06 am
Then that would be a bug in the documentation (https://www.freepascal.org/docs-html/current/prog/progsu80.html#x87-860001.2.80) that has a space there.
Title: Re: Any traces of «if» statement disappeared
Post by: Avinash on January 27, 2020, 09:53:10 am
I can't reproduce it, e.g. {$warn 5026-} etc works. Maybe you used a space before - ? That indeed does not work.

It does not work for me

Code: Pascal  [Select][+][-]
  1. {$WARN 5026-}
  2. begin
  3. end.

fpc test.pas

Code: Pascal  [Select][+][-]
  1. Target OS: Win32 for i386                                          
  2. Compiling test.pas                                                
  3. test.pas(1,2) Error: Illegal state "" for $WARN directive          
  4. test.pas(3,4) Fatal: There were 1 errors compiling module, stopping
  5. Fatal: Compilation aborted                                        
  6. Error: D:\FPC\bin\i386-Win32\ppc386.exe returned an error exitcode

fpc -n test.pas

Code: Pascal  [Select][+][-]
  1. test.pas(1,2) Error: Illegal state "" for $WARN directive        
  2. Fatal: Can't find unit system used by Program                    
  3. Fatal: Compilation aborted                                        
  4. Error: D:\FPC\bin\i386-Win32\ppc386.exe returned an error exitcode

Also you need to add these to each unit (that's why I said include file). Only adding them e.g. in the main program file will not work.

Yes, I did so, such a file exists. It is not included in absolutely all units, but part of the warnings did not turn off in the unit where it was included.
Title: Re: Any traces of «if» statement disappeared
Post by: Thaddy on January 27, 2020, 10:22:21 am
I believe it used to work, but a workaround is {$warn 5024 off}. It still works from the commandline, though: fpc -vw5024-
Title: Re: Any traces of «if» statement disappeared
Post by: marcov on January 27, 2020, 10:39:17 am
And please file a bug since this is a documentation discrepancy
Title: Re: Any traces of «if» statement disappeared
Post by: Thaddy on January 27, 2020, 12:09:29 pm
And please file a bug since this is a documentation discrepancy
Yes, but I think the underlying issue is the inconsistency in the parser, so what way should it be resolved?
Documenting away issues is something I do not really like....

I can submit one, but in what direction? Parser or Doc? Your opinion is valuable and appreciated.
Title: Re: Any traces of «if» statement disappeared
Post by: marcov on January 27, 2020, 12:21:04 pm
Put it in compiler bug to indicate that is your prefered fix, with a suggestion that if they won't at least the docs should be changed.

TinyPortal © 2005-2018